| 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 |