for 
Linux and Mac OSX 
32 bit and 64 bit versions 
Robert H. Lewis 
© 1992, 1995  2011 by Robert H. Lewis. all rights reserved. 
http://home.bway.net/lewis/ 
July 25, 2011 v3.9.99, 4.19 (64 bit) 
Introduction  1 
1. Interpreter Commands  6 
2. Builtin Functions  15 
3. Names  26 
4. Variables and Arrays  27 
5. Expressions and Assignment  29 
6. Array Expressions  31 
7. The Array of Arrays  34 
8. Functions  35 
9. Arithmetic Modes (Ground Rings)  42 
10. Polynomials  44 
11. Quolynomials  49 
12. Polymods  50 
13. Laurent Polynomials  52 
14. Character Strings  53 
15. More Builtin Functions  55 
16. The Dangerous Commands  57 
17. Errors and Warnings  61 
18. Popping, Pushing, Debugging, and Panic Stops  63 
19. Initializing with Ferstartup  65 
20. Hints and Observations  66 
Appendix One  69 
Appendix Two  69 
Appendix Three  70 
Appendix Four  79 
Appendix Five  92 
Appendix Six  93 
Index  96 
Fermat User's Guide 
Robert H. Lewis 
© 1992, 1995  2011. all rights reserved 
* This is the Fermat manual for Linux and OSX, 32 or 64 bit * 

























Symbol  Keystroke  Meaning  Use  Apply to arrays? 
\  \  divide and truncate  x \y, [x]\y  yes 
  shift\  modulo  x  y, [x]  y  yes 
…  shift\  absolute value  (x+y)  no 
< >  < >  not equal to  x < > y  no 
> =  > =  greater than or equal  x > = y  no 
< =  < =  less than or equal  x < = y  no 
$  shift4  greatest integer  $x  yes 
^{∧}  shift6  raise to power  x^{∧}n, [x]^{∧}n  yes 
_  shift   suppress modular  _9087  no 
:  shift ;  suppress display; terminal only  10^{∧}9999 :  no 
'  '  start, end quote  ' … '  no 
"  shift'  derivative of poly, quoly  x"  no 
!  shift1  factorial  x!  no 
!  shift1  display  !(x,y,z), !!x, ![z  yes 
?  shift/  get from terminal  ?s, ?[x]  yes 
<  shift,  previous value  x := <  yes 
#  shift3  polynomial evaluation  x # y , x #(u=y), x # [y]  yes 
@  shift2  panic stop  &@  no 
@  shift2  cancel  @[x], @F, @ < [x] >  yes 
_  shift   concatenate arrays  [x] _ [y]  yes 
J  shiftj  add (drop) poly. var.  &J  no 
{  shift[  start comment  { …}  no 
}  shift]  end comment  { …}  no 
}  shift]  exit function  &}  no 
>  shift.  exit loop  & >  no 
]  ]  cycle (in loop)  &]  no 
^{ ∼ }  shift`  ellipsis  x[2^{ ∼ } ,4 ^{ ∼ } ]  yes 
`  `  line continuation  only from terminal  no 
< F  shift, shiftf  system function  only from terminal  no 
%  shift5  array of arrays  %[1] := [x]  yes 
; This set of functions was used in November 1990 by Robert H. Lewis to ; answer an unsolved question in group theory. A certain property of some ; groups called the Gkj groups was checked by counting the number of ; homomorphisms from Gkj > SL(2, Z/4). It turns out that for certain k and ; j, this number can vary from the expected number. Gilbert Baumslag ; presented the question in this form. Gkj is a one relator group with two ; generators; the relation involves the two generators raised to powers k ; and j. To find a homomorphism from Gkj into a group it is necessary and ; sufficient to find 2 elements of that group that satisfy the same relation. ; SL(2, Z/4) is picked because it is finite, 2x2 matrices are easy to ; compute with, and it has an appropriate lower central series. ; Fermat note: Fermat reads the first six statements and does them. Then ; it reads the function definitions. Then it executes the last 11 statements. ; There is no reason to have this particular order of statements in this file. ; In particular, the function definitions can be in any order. &(t = 1); &(m = 0); ;; Turn off the user interrupt capability.&(Jx); &(Jy); &(Jz); &(Jw); ;; Adjoin 4 polynomial variables.
;; Find [p] among the list of 2x2 matrices representing SL(2,Z/4). Function Find(i,size,j,ans) = ans := 0; for j = i, size do if p[1] <> e[j] then &] fi; if p[2] <> f[j] then &] fi; if p[3] <> g[j] then &] fi; if p[4] = h[j] then ans := &_m(j); & > fi od; ans.; ;; Find where each element [p]'s inverse transpose is in SL(2,Z/4). Function SetInvTr(i) = for i = 1, invs do [p] := [(e[i],f[i],g[i],h[i])]; { ith element of SL(2,Z/4) } STrans[p]; [p] := [(p[4],p[2],p[3],p[1])]; { fast inverse } it[i] := Find(1, &_m(invs)) od.; ;; Insert is used by DelConj. Function Insert(x1,i,k) = i := 1; while i <= j do if x1 > conjs[i] then for k = j + 1, i + 1,  1 do conjs[k] := conjs[k1] od; conjs[i] := x1; &_m(j :+ ); &} else if x1 = conjs[i] then &} else &_m(i :+ ) fi fi od; conjs[i] := x1; &_m(j :+ ).; ; Compute the conjugacy classes in SL(2,Z/4). Look at each element of ; SL(2,Z/4). Delete from the list of SL(2,Z/4) all of its conjugates. ; When finished, one representative is left in each class. Function DelConj(i,j,k,n,spot) = Array conjs[invs\2]; Array a1[2,2]; Array count[2]; [count] := 0; &_m(size := invs); i := 1; while i <= size do [a1] := [(e[i],f[i],g[i],h[i])]; j := 0; { Fill the array conjs to tell where the conjugates of [a1] are. } for k = 1, invs do [p] := [(e1[k],f1[k],g1[k],h1[k])]; [q] := [(p[4],p[2],p[3],p[1])]; [p] := [q]*[a1]*[p]; spot := Find(i, size); if spot = 0 then !!'spot is 0' fi; if spot <> i then Insert(spot) fi od; !!('number of conjugates is ', &_m(j + 1)); [count] := [count] \_ &_m(j + 1); { Delete the conjugates of [a1]. Change [it] accordingly. } for k = 1, j do &_m(size:); for n = 1, conjs[k]  1 do if it[n] = conjs[k] then it[n] := i fi; if it[n] > conjs[k] then &_m(it[n] := it[n]  1) fi od; for n = conjs[k], size do e[n] := e[n+1]; f[n] := f[n+1]; g[n] := g[n+1]; h[n] := h[n+1]; it[n] := it[n+1]; if it[n] = conjs[k] then it[n] := i fi; if it[n] > conjs[k] then &_m(it[n]:) fi od od; &_m(i :+ ) od; [count] := [count[3~]]; @([conjs], [a1]).; ;; OneDet tests every possible 2x2 matrix over Z/4 and saves the ;; invertible ones. j1 is owned by CreateData. Function OneDet(i,j,k,l) = for i = 0, dim  1 do for j = 0, dim  1 do for k = 0, dim  1 do for l = 0, dim  1 do if i*l  k*j = 1 then &_m(j1 := j1 + 1); e[j1] := i; f[j1] := j; g[j1] := k; h[j1] := l fi od od od od.; ;; Count the number of all 2x2 matrices over Z/4 that have determinant 1. Function CountInv(i,j,k,l,j1) = for i = 0, dim  1 do for j = 0, dim  1 do for k = 0, dim  1 do for l = 0, dim  1 do if i*l  k*j = 1 then &_m(j1 :+ ) fi od od od od; j1.; Function CreateData(j1) = Array e[invs]; Array f[invs]; Array g[invs]; Array h[invs]; OneDet; [e1] := [e]; [f1] := [f]; [g1] := [g]; [h1] := [h].; ; Main tries one pair of exponents, exp1 and exp2. It counts the number ; of homomorphisms from the group they define into the 2x2 matrix group. ; The basic word that defines the group has been massaged to minimize ; the amount of work within the innermost loop. That is also the reason ; for using the polynomials  part of the word can be evaluated in advance ; "once and for all". Function Main(exp1,exp2,i,j,k,l,yes) = time := &T; hits := 0; for i = 1, size do [c] := [(e[i],f[i],g[i],h[i])]; [ci] := [c]^exp1; [cj] := [c]^exp2; [prod1] := [cj]*[b]; [prod2] := [b]*[cj]; { If [c] is in the center, so that count[i] = 1, the answer is easy. Increment and cycle. } if count[i] = 1 then &_m(hits := hits + invs); &] fi; for j = 1, invs do &(m = 1); { Allow mouse interrupts. } [a] := [(e1[j],f1[j],g1[j],h1[j])]; [p] := [ci]*[a]; &(m = 0); { Turn off mouse interrupts. } [a1] := [(p[4],p[2],p[3],p[1])]; [test] := [a1]*[a]*[p]; [test] := [prod1]  [prod2]*[test]; for k = 1, invs do yes := 1; for l = 1, 4 do if test[l]#(h1[k], g1[k], f1[k], e1[k]) <> 0 then yes := 0; & > fi od; if yes = 1 then &_m(hits := hits + count[i]) fi od od od; !!('time is ', &_m((&T  time)/60), 'seconds.'); !!('i, j, hits are ', exp1:3, exp2:3, hits).; ; Driver is the 'main program'. It first counts the number of invertible ; 2x2 matrices over Z/dim, using CountInv. (dim = 4 is the right choice, ; for which invs is 48). CreateData then actually creates the 48 matrices. ; Matrices are stored in 4 arrays [e], [f], [g], [h],one for the upper ; left coordinates, one for the lower left, etc. (This is inelegant and ; could be done better with Fermat's array of arrays.) These are ; duplicated into [e1], [f1], etc. Then SetInvTr finds where each matrix's ; inverse transpose is. This data is stored in array [it]. DelConj breaks ; the group into conjugacy classes. (This is done because the basic defining ; word is invariant under conjugation, so we save some time this way.) ; When it's finished, [e], [f], [g], [h] store 1 representative from each ; class, and [it] says where the inverse transpose of each of these ; representatives is. But it turns out that it[j] = j for all j. Had ; this not been true, a further speed up would have been possible. Then a ; loop indexed on i tests the exponents from the arrays [try1] and [try2] ; thereby looking for maps from the group Gkj,where k = try1[i] and j = ; try2[i]. Main counts the number of homomorphisms from the Gkj group into ; SL(2,Z/4). Function Driver(size,time,invs) = time := &T; Array a[2,2]; Array b[2,2]; Array c[2,2]; Array ci[2,2]; Array cj[2,2]; Array p[2,2]; Array a1[2,2]; Array b1[2,2]; Array q[2,2]; Array test[2,2]; [b] := [(x,z,y,w)]; invs := CountInv; !!('order of group is ', invs); Array it[invs]; CreateData; SetInvTr; !!('initial [it]'); ![it; !; DelConj; !!('time is ', &_m((&T  time)/60), ' seconds.'); !!('size is ', size); { size = number of conjugacy classes. } !!('Now [it] is '); ![it[1~size]; !; !!'[count] is '; ![count; !; for i = 1, 100 do Main(try1[i], try2[i]) od.; ?dim; ; Ask user for dim. &(p = dim); ; Go to modular mode mod dim. In converting, dim ; becomes 0. (of course) dim := 1; &_m(dim := dim + 1); ; dim now holds dim, not 0. Array try1[100]; ; Create exponents to try for k and j. Array try2[100]; [try1[1~7]] := 1; [try1[8~14]] := 2; &(a = 0); [try2] := [<i=0,99> ( &_m (i7 + 2) )]; &(a = 1); &x;Example 2.
Function Degree(n,i,j,k,diff,answer) = { Create matrix of degrees of entries in [x]. n = dim. of [x]. } Array y[n,n]; for i = 1, n*n do if x[i] = 0 then y[i] := 10^10 { " infinity" } else y[i] := Deg(x[i]) fi od; answer := 0; { This loop simulates row and column manipulations in [x] by working with the degrees in [y]. } for i = 1, n do { Try to factor out as many powers as you can. } Rowscan(n, i); Colscan(n, i); { Find spot with lowest degree >= 0. } j := Det_ + ([y[i~,i~]] + 1); if j = 1 then & > fi; { Convert linear to (row, column) coordinates in [y]. } k := (j  1)\(n  i + 1) + i; j := (j  1)(n  i + 1) + i; { If the remaining matrix is all constants, stop now. } if Maxdegree(n, i) = 0 then & > fi; { Simulate row and column manipulations. } Switchrow([y[,i~]], i, j); Switchcol([y[i~,]], i, k); for j = i + 1, n do diff := y[j,i]  y[i,i]; for k = i + 1, n do [y[j,k]] := Max(y[j,k], diff + y[i,k]) od od; answer := answer + y[i,i] od; answer.; Function Rowscan(n,i,r,j,deg) = for r = i, n do { Find position and value of smallest nonnegative entry in rth row in columns >= i. } j := Det_ + ([y[r,i~]] + 1); deg := y[r,j+i1]; { If deg is positive, factor it out, changing answer accordingly. } if deg > 0 then [y[r,i~]] := [y[r,i~]]  deg; answer := answer + deg fi od.; Function Colscan(n,i,r,j,deg) = for r = i, n do { Find position and value of smallest nonnegative entry in rth column in rows >= i. } j := Det_ + ([y[i~,r]] + 1); deg := y[j+i1,r]; { If deg is positive, factor it out, changing answer accordingly. } if deg > 0 then [y[i~,r]] := [y[i~,r]]  deg; answer := answer + deg fi od.; Function Maxdegree(n,i,r,s,deg) = deg := 0; for r = i, n do for s = i, n do if y[r,s] > deg then deg := y[r,s]; &> fi od; if deg > 0 then &> fi od; deg.; Function Max(a,b) = if a > b then a else b fi.; { Assume that t is the polynomial variable. }n := Degree(Cols[x]) \2; { Standard LaGrange interpolation at points n, n+1, ..., n1, n:}
Function CharPoly(a,n,i,pm) = { Assume t is a polynomial variable. } n := Cols[a]; Array c[n]; [q] := [a]; c[1] := Trace[a]; for i = 2, n do [q] := [q] + c[i1]*[1]; [q] := [a]*[q]; c[i] := Trace[q]/i od; { Correct for odd n. } if n2 then pm :=  1 else pm := 1 fi.; Function Invert(a,q,n,i) = { Set [q] = the inverse of [a] } n := Cols[a]; Array c[n]; [p] := [a]; c[1] := Trace[a]; for i = 2, n do [q] := [p] + c[i1]*[1]; [p] := [a]*[q]; c[i] := Trace[p]/i od; [q] := [q]/(c[n]); @([p], [c]).;
BAD: for i = 1, m do if n = i+1 then .... ;; i+1 is NOT 1 more than i (!) GOOD: for i = 1, m do if n = _(i+1) then ... BAD: rc := 1 + Sigma<j=1,n> [ Deg(za,j)*exp[j] ] GOOD: rc := 1 + _Sigma<j=1,n> [ Deg(za,j)*exp[j] ]Technically, over any modular ground ring, one should use the &_m or _(...) as above, but I at least usually use large primes p in Z/p, maybe 44449, so no harm results  usually. But over GF(2^{8}) and GF(2^{16}), one needs constant vigilance. For example, 2 is not 2 (!) Remember that modular is automatically suppressed in forloops, exponents, and array indexes. So these should be OK:
for i = 1, 2n do... x := y^(i+2); s := c[2*n+1];It is fine to attach poly vars on top of these ground fields. However, do not do &P on top of that. I have not thoroughly checked that. Appendix 6. New Features Added Between June 2005 and July 2011
item  page 
absolute value  16 
adjoin variable  79 
adjoint  21, 55, 86 
AES  92 
Altmult  87 
argument  35 
arithmetic modes  42, 1, 16 
selective change  59 
array builtin functions  2025 
array of arrays  34 
array parameter  38 
arrays  14, 16, 20, 28, 3033 
assignment  29, 30, 31 
binomial coefficient  16 
blank  3 
builtin functions  1524 
cancelling, arrays  6, 39 
functions  35 
canonical forms  49 
character strings  53 
characteristic polynomial  21, 56, 86 
Chinese Remainder Theorem  21, 55 
codegree  18, 45, 80 
coefficient (in polynomial)  18, 8081 
Colreduce  23, 88 
Cols  22, 87 
command interrupt  63, 8 
comments  39 
compile  57 
concatenate arrays  22 
conditions  36 
content  19, 82 
continuation character  4, 7 
cycle  37 
dangerous commands  57 
debugging  63 
degree  18, 22, 80, 87 
Denom  80 
derivative  19, 20, 46, 55 
item  page 
determinant  7, 20, 85 
determinant cutoff  7 
diagonal matrix  22, 30 
display  6, 12 
Divides  55, 82 
Dixon resultant  90 
dumb save  9 
early loop termination  37 
efficient use of storage  27 
Equal  18 
errors  61, 7 
evaluation  18, 45 
expression (grammatical)  16 
expressions  2830 
factor (grammatical)  16 
Factor (a polynomial)  47, 83 
factorial  16 
ferstartup  65 
FFLU, FFLUC  24, 90 
field, finite  92 
field, ground  1, 50, 92 
files  8, 9 
forloop  37 
fraction free LU  24, 90 
free an array  28 
function definition  35 
GaussBareiss  85 
GCD  19, 52, 82 
Gershgorn's Theorem  56, 87 
globals  7 
graphics  1 
greatest integer  16 
ground ring  1, 42 
Hamiltonian Path  89 
heap  8 
Hensel's Lemma  55 
Hermite form  24, 89 
Hilbert matrix  32 
if statement  36 
imperative form of switches  11 
implicit multiplication  15 
increment command  15, 29 
item  page 
initializing  65 
input  3, 9, 11 
integer  57 
interpreter commands  614 
interrupt  60 
invert matrix  31, 33, 66 
I/O  9, 12 
Irred(ucible poly)  84 
Isprime  16 
Iszero  23 
Killden  81 
Laurent polynomial  1, 52, 79 
LCM  86 
leading coefficient  19, 81 
leading term  19, 81 
LeverrierFaddeev method  56 
local variables  36 
Log2  18 
LMon  81 
loops  3638 
early termination  37 
Maple format  10 
matrices  3134, 85 ff. 
matrix builtin functions  2024, 30, 32, 5556, 8590 
matrix inverse  31, 33, 66 
Mcoef  81 
Mfact  81 
minimal polynomial  21, 56, 86 
Minors  31, 89 
Minpoly  56, 86 
Modmode  17 
modular arithmetic  1, 42, 59 
modular mode, turning off  42, 43 
and loops  42 
selective change  59 
Modulus  17 
Mono  81, 95 
monomial commands  81 
monomial order  94, 95 
Move  18 
MPowermod  87 
MPW  1 
item  page 
name change, array  28 
names  26 
noise, eliminate  8 
normalizing a matrix  2324, 88 
number  15 
Numer  80 
Numvars  16 
output file  9 
panic stop  63, 11 
parameters  3, 35, 79 
PDivides  55, 82 
pivot strategies  25 
polymods  1, 50 
Poly  83 
polynomial evaluation  18, 45 
polynomial readin  43, 46 
cancelling  44 
polynomial variable, adjoining  44, 11 
polynomials  4447, 1820, 
pop  63, 11 
Powermod  55, 83 
previous result  3, 17 
probably divides  55, 82 
procedures  35 
product, Prod  17 
prompt, change  8 
Prime  17 
PRoot  55, 81 
Pseudet  88 
pseudodivision  45 
purge  6 
push  63, 11 
quit  8 
quolymods  50 
quolynomials  49, 1 
quotient ring  50, 79 
random number  10, 17 
Rat  55 
rational arithmetic  1, 42 
reading (file)  8 
Redrowech  24, 89 
Remquot  18 
rename array  28 
reserved words  37 
item  page 
Return  15, 35, 57 
Reverse  22 
row/column operations  23 
Rowreduce  23, 88 
saving (to a file)  9, 5, 66 
saving space  27, 28, 29 
scalar  15 
SDet  95 
SDivide  83 
Smith normal form  23, 88 
Sort  94 
space saving  27, 28, 29 
sparse access loop  38, 90 
sparse arrays  13, 20, 27, 31, 56, 84 
Splice  81, 83 
Split  81, 83 
Sqfree  47, 83 
Sqrt  16 
startup file  65 
STrans  87, 93 
subarrays  31, 85 
sum, Sigma  17, 87 
Swap  18 
Switchrow, Switchcol  23 
suppress display  8 
suppress modular  42 
system array  22 
system function  40 
system variable  3 
term (grammatical)  16 
Terms  81 
Time  17 
timing  10 
item  page 
Toot  15 
total degree, Totdeg  55 
trace  21, 87 
transpose  22, 87 
ugly display  10 
Var  18, 82 
Vars  82 
variables  27, 36 
verbose display  10 
warnings  61 
whileloops  37 
writing (to a file)  9, 5, 66 
Youngman, Henny  67 