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. Built-in 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 Built-in 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 |
$ | shift-4 | greatest integer | $x | yes |
∧ | shift-6 | 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 |
! | shift-1 | factorial | x! | no |
! | shift-1 | display | !(x,y,z), !!x, ![z | yes |
? | shift-/ | get from terminal | ?s, ?[x] | yes |
< | shift-, | previous value | x := < | yes |
# | shift-3 | polynomial evaluation | x # y , x #(u=y), x # [y] | yes |
@ | shift-2 | panic stop | &@ | no |
@ | shift-2 | cancel | @[x], @F, @ < [x] > | yes |
_ | shift- - | concatenate arrays | [x] _ [y] | yes |
J | shift-j | 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-, shift-f | system function | only from terminal | no |
% | shift-5 | 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[k-1] 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 (i|7 + 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+i-1]; { 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+i-1,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, ..., n-1, 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[i-1]*[1]; [q] := [a]*[q]; c[i] := -Trace[q]/i od; { Correct for odd n. } if n|2 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[i-1]*[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(28) and GF(216), one needs constant vigilance. For example, 2 is not 2 (!) Remember that modular is automatically suppressed in for-loops, 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 built-in functions | 20-25 |
array of arrays | 34 |
array parameter | 38 |
arrays | 14, 16, 20, 28, 30-33 |
assignment | 29, 30, 31 |
binomial coefficient | 16 |
blank | 3 |
built-in functions | 15-24 |
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, 80-81 |
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 | 28-30 |
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 |
for-loop | 37 |
fraction free LU | 24, 90 |
free an array | 28 |
function definition | 35 |
Gauss-Bareiss | 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 | 6-14 |
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 |
Leverrier-Faddeev method | 56 |
local variables | 36 |
Log2 | 18 |
LMon | 81 |
loops | 36-38 |
early termination | 37 |
Maple format | 10 |
matrices | 31-34, 85 ff. |
matrix built-in functions | 20-24, 30, 32, 55-56, 85-90 |
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 | 23-24, 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 read-in | 43, 46 |
cancelling | 44 |
polynomial variable, adjoining | 44, 11 |
polynomials | 44-47, 18-20, |
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 |
pseudo-division | 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 |
while-loops | 37 |
writing (to a file) | 9, 5, 66 |
Youngman, Henny | 67 |