home *** CD-ROM | disk | FTP | other *** search
/ Math Solutions 1995 October / Math_Solutions_CD-ROM_Walnut_Creek_October_1995.iso / pc / mac / discrete / lib / finfield.g < prev    next >
Encoding:
Text File  |  1993-05-05  |  31.9 KB  |  1,100 lines

  1. #############################################################################
  2. ##
  3. #A  finfield.g                  GAP library                     Werner Nickel
  4. #A                                                         & Martin Schoenert
  5. ##
  6. #A  @(#)$Id: finfield.g,v 3.12 1992/12/16 19:47:27 martin Rel $
  7. ##
  8. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  9. ##
  10. ##  This file contains those functions that deal with finite field  elements.
  11. ##
  12. #H  $Log: finfield.g,v $
  13. #H  Revision 3.12  1992/12/16  19:47:27  martin
  14. #H  replaced quoted record names with escaped ones
  15. #H
  16. #H  Revision 3.11  1992/11/16  12:22:59  fceller
  17. #H  added Laurent polynomials
  18. #H
  19. #H  Revision 3.10  1992/07/30  15:22:56  fceller
  20. #H  fixed some minor bugs in 'GaloisField'
  21. #H
  22. #H  Revision 3.9  1992/06/17  07:06:04  fceller
  23. #H  moved '<somedomain>.operations.Polynomial' function to "<somedomain>.g"
  24. #H
  25. #H  Revision 3.8  1992/04/29  14:10:17  martin
  26. #H  added 'FinFieldOps.Coefficients'
  27. #H
  28. #H  Revision 3.7  1992/04/23  07:25:37  fceller
  29. #H  read in "polyfin.g" which contains functions for polynomials
  30. #H  over finite fields.
  31. #H
  32. #H  Revision 3.6  1992/03/27  11:14:51  martin
  33. #H  changed mapping to general mapping and function to mapping
  34. #H
  35. #H  Revision 3.5  1992/02/11  14:16:36  martin
  36. #H  added 'GaloisGroup'
  37. #H
  38. #H  Revision 3.4  1992/01/29  11:07:59  martin
  39. #H  improved 'IntFFE'
  40. #H
  41. #H  Revision 3.3  1992/01/02  16:29:27  martin
  42. #H  made a temporary fix to 'GF'
  43. #H
  44. #H  Revision 3.2  1991/10/10  12:40:31  martin
  45. #H  changed everything for new domain concept
  46. #H
  47. #H  Revision 3.1  1991/08/04  12:00:00  martin
  48. #H  changed the finite field package for domains
  49. #H
  50. #H  Revision 3.0  1991/01/06  12:00:00  martin
  51. #H  initial revision under RCS
  52. #H
  53. ##
  54.  
  55.  
  56. #############################################################################
  57. ##
  58. #F  IsFiniteField( <obj> )  . . .  test if an object is a finite field record
  59. ##
  60. IsFiniteField := function ( obj )
  61.     return IsRec( obj )
  62.        and IsBound( obj.isField  )  and obj.isField
  63.        and IsBound( obj.isFinite )  and obj.isFinite;
  64. end;
  65.  
  66.  
  67. #############################################################################
  68. ##
  69. #V  FiniteFieldOps  . . . . . . . . . . . operations record for finite fields
  70. ##
  71. FiniteFieldOps := Copy( FieldOps );
  72.  
  73.  
  74. #############################################################################
  75. ##
  76. #F  FiniteFieldOps.Elements(<F>)  . . . . . . . .  elements of a finite field
  77. ##
  78. FiniteFieldOps.Elements := function ( F )
  79.     local   elms, elms2, i, k;
  80.  
  81.     # contruct the elements of the field
  82.     elms := [ F.zero ];
  83.     for i  in [1..Length(F.generators)]  do
  84.         elms2 := [];
  85.         for k  in [0..F.char-1]  do
  86.             Append( elms2, elms + k * F.generators[i] );
  87.         od;
  88.         elms := elms2;
  89.     od;
  90.  
  91.     # return the set of elements
  92.     elms := Set( elms );
  93.     return elms;
  94. end;
  95.  
  96.  
  97. #############################################################################
  98. ##
  99. #F  FiniteFieldOps.\in( z, F ) . .  test if an object lies in a finite field
  100. ##
  101. FiniteFieldOps.\in := function ( z, F )
  102.     return IsFFE( z )
  103.        and CharFFE( z ) = F.char
  104.        and F.degree mod DegreeFFE( z ) = 0;
  105. end;
  106.  
  107.  
  108. #############################################################################
  109. ##
  110. #F  FiniteFieldOps.Intersection(<F>,<G>)  . intersection of two finite fields
  111. ##
  112. FiniteFieldOps.Intersection := function ( F, G )
  113.     local   I;
  114.     if     IsField( F )  and IsFinite( F )
  115.        and IsField( G )  and IsFinite( G )  then
  116.         if F.char = G.char  then
  117.             I := GF( F.char ^ GcdInt( F.degree, G.degree ) );
  118.         else
  119.             I := [];
  120.         fi;
  121.     else
  122.         I := FieldOps.Intersection( F, G );
  123.     fi;
  124.     return I;
  125. end;
  126.  
  127.  
  128. #############################################################################
  129. ##
  130. #F  FiniteFieldOps.Random(<F>)  . . . . .  random element from a finite field
  131. ##
  132. FiniteFieldOps.Random := function ( F )
  133.     local   rnd;
  134.     if IsBound(F.elements)  then
  135.         rnd := RandomList( F.elements );
  136.     elif IsBound(F.root)  then
  137.         rnd := RandomList( [0..F.size-1] );
  138.         if rnd = 0  then
  139.             rnd := F.zero;
  140.         else
  141.             rnd := F.root^rnd;
  142.         fi;
  143.     else
  144.         rnd := FieldOps.Random( F );
  145.     fi;
  146.     return rnd;
  147. end;
  148.  
  149.  
  150. #############################################################################
  151. ##
  152. #F  FiniteFieldOps.Print(<F>) . . . . . . . . . . . . .  print a finite field
  153. ##
  154. FiniteFieldOps.Print := function ( F )
  155.     if IsBound( F.name )  then
  156.         Print( F.name );
  157.     else
  158.         if F.degree = 1  then
  159.             Print( "GF(",F.char,")" );
  160.         else
  161.             Print( "GF(",F.char,"^",F.degree,")" );
  162.         fi;
  163.         if not IsInt( F.field )  then
  164.             Print( "/",F.field );
  165.         fi;
  166.     fi;
  167. end;
  168.  
  169.  
  170. #############################################################################
  171. ##
  172. #F  FiniteFieldOps.\/(<F>,<G>) . .. . . . . .  quotient of two finite fields
  173. ##
  174. FiniteFieldOps.\/ := function ( F, G )
  175.     local   Q;
  176.  
  177.     # let others do the main work
  178.     Q := FieldOps.\/( F, G );
  179.  
  180.     # enter further knowledge
  181.     if IsBound(F.root)  then Q.root := F.root;  fi;
  182.     Q.base := List( [0..F.degree/G.degree-1], i->Z(F.size)^i );
  183.  
  184.     # return the quotient
  185.     return Q;
  186. end;
  187.  
  188.  
  189. #############################################################################
  190. ##
  191. #F  FiniteFieldOps.GaloisGroup(<F>) . . . . .  Galois group of a finite field
  192. ##
  193. FiniteFieldOps.GaloisGroup := function ( F )
  194.     if IsInt( F.field )  then
  195.         return Group( FrobeniusAutomorphismI( F, F.field ) );
  196.     else
  197.         return Group( FrobeniusAutomorphismI( F, Size( F.field ) ) );
  198.     fi;
  199. end;
  200.  
  201.  
  202. #############################################################################
  203. ##
  204. #F  FiniteFieldOps.Conjugates(<F>,<z>) . conjugates of a finite field element
  205. ##
  206. FiniteFieldOps.Conjugates := function ( F, z )
  207.     local   cnjs,       # conjugates of <z> in <F>, result
  208.             ord,        # order of the subfield of <F>
  209.             deg,        # degree of <F> over its subfield
  210.             i;          # loop variable
  211.  
  212.     # get the order of the subfield and the degree
  213.     if IsInt(F.field)  then
  214.         ord := F.char;
  215.         deg := F.degree;
  216.     else
  217.         ord := F.field.char ^ F.field.degree;
  218.         deg := F.degree / F.field.degree;
  219.     fi;
  220.     if F.char <> CharFFE(z)  or F.degree mod DegreeFFE(z) <> 0  then
  221.         Error("<z> must lie in <F>");
  222.     fi;
  223.  
  224.     # compute the conjugates $\set_{i=0}^{d-1}{z^(q^i)}$
  225.     cnjs := [];
  226.     for i  in [0..deg-1]  do
  227.         Add( cnjs, z );
  228.         z := z^ord;
  229.     od;
  230.  
  231.     # return the conjugates
  232.     return cnjs;
  233. end;
  234.  
  235.  
  236. #############################################################################
  237. ##
  238. #F  FiniteFieldOps.Norm(<F>,<z>)  . . . . . .. norm of a finite field element
  239. ##
  240. FiniteFieldOps.Norm := function ( F, z )
  241.     local   nrm,        # norm of <z> in <F>, result
  242.             ord,        # order of the subfield of <F>
  243.             deg;        # degree of <F> over its subfield
  244.  
  245.     # get the order of the subfield and the degree
  246.     if IsInt(F.field)  then
  247.         ord := F.char;
  248.         deg := F.degree;
  249.     else
  250.         ord := F.field.char ^ F.field.degree;
  251.         deg := F.degree / F.field.degree;
  252.     fi;
  253.     if F.char <> CharFFE(z)  or F.degree mod DegreeFFE(z) <> 0  then
  254.         Error("<z> must lie in <F>");
  255.     fi;
  256.  
  257.     # $nrm = \prod_{i=0}^{deg-1}{ z^(ord^i) }
  258.     #      = z ^ {1 + ord + ord^2 + .. + ord^{deg-1}}
  259.     #      = z ^ {(ord^deg-1)/(ord-1)} $
  260.     nrm := z ^ ((ord^deg-1)/(ord-1));
  261.  
  262.     # return the norm
  263.     return nrm;
  264. end;
  265.  
  266.  
  267. #############################################################################
  268. ##
  269. #F  FiniteFieldOps.Trace(<F>,<z>) . . . . . . trace of a finite field element
  270. ##
  271. FiniteFieldOps.Trace := function ( F, z )
  272.     local   trc,        # trace of <z> in <F>, result
  273.             ord,        # order of the subfield of <F>
  274.             deg,        # degree of <F> over its subfield
  275.             i;          # loop variable
  276.  
  277.     # get the order of the subfield and the degree
  278.     if IsInt(F.field)  then
  279.         ord := F.char;
  280.         deg := F.degree;
  281.     else
  282.         ord := F.field.char ^ F.field.degree;
  283.         deg := F.degree / F.field.degree;
  284.     fi;
  285.     if F.char <> CharFFE(z)  or F.degree mod DegreeFFE(z) <> 0  then
  286.         Error("<z> must lie in <F>");
  287.     fi;
  288.  
  289.     # $trc = \sum_{i=0}^{deg-1}{ z^(ord^i) }$
  290.     trc := 0;
  291.     for i  in [0..deg-1]  do
  292.         trc := trc + z;
  293.         z := z^ord;
  294.     od;
  295.  
  296.     # return the trace
  297.     return trc;
  298. end;
  299.  
  300.  
  301. #############################################################################
  302. ##
  303. #F  FiniteFieldOps.Order(<F>,<z>) . . . . . . order of a finite field element
  304. ##
  305. OrderFFE := function ( z )
  306.     local   ord,        # order of <z>, result
  307.             chr,        # characteristic of <F> (and <z>)
  308.             deg;        # degree of <z> over the primefield
  309.  
  310.     # compute the order
  311.     if z = 0 * z   then
  312.         ord := 0;
  313.     else
  314.         chr := CharFFE( z );
  315.         deg := DegreeFFE( z );
  316.         ord := (chr^deg-1) / GcdInt( chr^deg-1, LogFFE( z, Z(chr^deg) ) );
  317.     fi;
  318.  
  319.     # return the order
  320.     return ord;
  321. end;
  322.  
  323. FiniteFieldOps.Order := function ( F, z )
  324.     return OrderFFE( z );
  325. end;
  326.  
  327.  
  328. #############################################################################
  329. ##
  330. #F  FiniteFieldOps.Coefficents(<F>,<z>)  coefficients of finite field element
  331. ##
  332. FiniteFieldOps.Coefficients := function ( F, z )
  333.     local   q, d, mat, b, cnjs, k, zz;
  334.  
  335.     # get the size of the subfield and the degree of the extension
  336.     if IsInt( F.field )  then
  337.         q := F.field;
  338.     else
  339.         q := Size( F.field );
  340.     fi;
  341.     d := Length( F.base );
  342.  
  343.     # if the inverse matrix of the base is not already known compute it
  344.     if not IsBound( F.inverseBase )  then
  345.  
  346.         # build the matrix M[i,k] = base[i]^(q^k)
  347.         mat := [];
  348.         for b  in F.base  do
  349.             cnjs := [];
  350.             for k  in [0..d-1]  do
  351.                 Add( cnjs, b^(q^k) );
  352.             od;
  353.             Add( mat, cnjs );
  354.         od;
  355.  
  356.         # add the inverse matrix to the field record
  357.         F.inverseBase := mat ^ -1;
  358.  
  359.     fi;
  360.  
  361.     # compute the vector of conjugates of z
  362.     zz := [];
  363.     for k  in [0..d-1]  do
  364.         Add( zz, z^(q^k) );
  365.     od;
  366.     return zz * F.inverseBase;
  367. end;
  368.  
  369.  
  370. #############################################################################
  371. ##
  372. #F  FiniteFieldOps.Polynomial( <R>, <coeffs>, <val> ) . . polynomial over <R>
  373. ##
  374. FiniteFieldOps.Polynomial := function( R, coeffs, val )
  375.     local  i,  k,  l,  c;
  376.  
  377.     # remove leading zeros
  378.     k := Length( coeffs );
  379.     while 0 < k and LogVecFFE(coeffs,k) = false  do
  380.         k := k - 1;
  381.     od;
  382.  
  383.     # remove trailing zeros
  384.     i := 0;
  385.     while i < k and LogVecFFE(coeffs,i+1) = false  do
  386.     i := i + 1;
  387.     od;
  388.  
  389.     # now really remove zeros
  390.     c := ShiftedCoeffs( coeffs, -i );
  391.     l := Length(coeffs);
  392.     while k < l  do
  393.     Unbind(c[l-i]);
  394.     l := l - 1;
  395.     od;
  396.     if i < k  then
  397.         val := val + i;
  398.     else
  399.         val := 0;
  400.     fi;
  401.  
  402.     # convert it into a vector
  403.     IsVector(c);
  404.  
  405.     # return polynomial
  406.     if val < 0  then
  407.         return rec( coefficients := c,
  408.                     baseRing     := R,
  409.                     isPolynomial := true,
  410.             valuation    := val,
  411.                     domain       := FiniteFieldLaurentPolynomials,
  412.                     operations   := FiniteFieldPolynomialOps );
  413.     else
  414.         return rec( coefficients := c,
  415.                     baseRing     := R,
  416.                     isPolynomial := true,
  417.             valuation    := val,
  418.                     domain       := FiniteFieldPolynomials,
  419.                     operations   := FiniteFieldPolynomialOps );
  420.     fi;
  421.  
  422. end;
  423.  
  424.  
  425. #############################################################################
  426. ##
  427. #F  FiniteFieldOps.PolynomialRing( <R> )  . . . . . . .  full polynomial ring
  428. ##
  429. FiniteFieldOps.PolynomialRing := function( R )
  430.     local   P;
  431.  
  432.     # construct a new ring domain
  433.     P := rec();
  434.     P.isDomain := true;
  435.     P.isRing   := true;
  436.  
  437.     # set known properties
  438.     P.isFinite := false;
  439.     P.size     := "infinity";
  440.  
  441.     # add properties of polynom ring over finite field
  442.     P.isCommutativeRing         := true;
  443.     P.isIntegralRing            := true;
  444.     P.isUniqueFactorizationRing := true;
  445.     P.isEuclideanRing           := true;
  446.     P.isPolynomialRing          := true;
  447.  
  448.     # set one and zero
  449.     P.one  := Polynomial( R, [ R.one ] );
  450.     P.zero := Polynomial( R, [] );
  451.  
  452.     # generate the field and a poly of degree 1
  453.     if 1 < R.degree  then
  454.         P.generators := [ Polynomial( R, [ R.zero, R.one ] ),
  455.                           Polynomial( R, [ R.root ] ) ];
  456.     else
  457.         P.generators := [ Polynomial( R, [ R.zero, R.one ] ) ];
  458.     fi;
  459.                           
  460.  
  461.     # 'P.baseRing' contains <R>
  462.     P.baseRing := R;
  463.  
  464.     # set operations record and return
  465.     P.operations := FiniteFieldPolynomialRingOps;
  466.     return P;
  467.  
  468. end;
  469.  
  470.  
  471. #############################################################################
  472. ##
  473. #F  FiniteFieldOps.LaurentPolynomialRing( <F> )  full Laurent polynomial ring
  474. ##
  475. FiniteFieldOps.LaurentPolynomialRing := function( F )
  476.     local   P;
  477.  
  478.     # construct a new ring domain
  479.     P := rec();
  480.     P.isDomain := true;
  481.     P.isRing   := true;
  482.  
  483.     # show that this a Laurent polynomial ring
  484.     P.isLaurentPolynomialRing := true;
  485.  
  486.     # set known properties
  487.     P.isFinite := false;
  488.     P.size     := "infinity";
  489.  
  490.     # add properties of laurent polynom ring over field
  491.     P.isCommutativeRing         := true;
  492.     P.isIntegralRing            := true;
  493.     P.isUniqueFactorizationRing := true;
  494.     P.isEuclideanRing           := true;
  495.  
  496.     # set one and zero
  497.     P.one  := Polynomial( F, [ F.one ] );
  498.     P.zero := Polynomial( F, [] );
  499.  
  500.     # 'P.baseRing' contains <F>
  501.     P.baseRing := F;
  502.  
  503.     # set operations record and return
  504.     P.operations := FieldLaurentPolynomialRingOps;
  505.     return P;
  506.  
  507. end;
  508.  
  509.  
  510. #############################################################################
  511. ##
  512. #F  FiniteFieldOps.Int(<F>,<z>)  convert a finite field element to an integer
  513. ##
  514. IntFFE := function ( z )
  515.     local   int, p, r, zero, one, y, row, cnv, i;
  516.  
  517.     # check that the element lies in the prime field
  518.     if 1 < DegreeFFE(z)  then
  519.         Error("<z> must lie in the prime field");
  520.     fi;
  521.     p := CharFFE( z );
  522.     r := PrimitiveRootMod( p );
  523.     zero := 0 * Z(p);
  524.     one  := Z(p) ^ 0;
  525.  
  526.     # convert a finite field element
  527.     if IsFFE( z )  then
  528.         if   z = zero  then int := 0;
  529.         elif z = one   then int := 1;
  530.         else  int := PowerMod( r, LogFFE( z, Z(p) ), p );
  531.         fi;
  532.  
  533.     # convert a finite field vector
  534.     elif IsVector( z )  then
  535.  
  536.         # handle small vectors directly
  537.         if Length( z ) < p  then
  538.             int := [];
  539.             for i  in [ 1 .. Length(z) ]  do
  540.                 if   z[i] = zero then int[i] := 0;
  541.                 elif z[i] = one  then int[i] := 1;
  542.                 else int[i] := PowerMod( r, LogFFE( z[i], Z(p) ), p );
  543.                 fi;
  544.             od;
  545.  
  546.         # handle large vectors with a lookup table
  547.         else
  548.             cnv := [ r ];
  549.             for i  in [2..p-2]  do
  550.                 cnv[i] := (cnv[i-1] * r) mod p;
  551.             od;
  552.             int := [];
  553.             for i  in [ 1 .. Length(z) ]  do
  554.                 if   z[i] = zero then int[i] := 0;
  555.                 elif z[i] = one  then int[i] := 1;
  556.                 else int[i] := cnv[ LogFFE( z[i], Z(p) ) ];
  557.                 fi;
  558.             od;
  559.  
  560.         fi;
  561.  
  562.     # convert a finite field matrix
  563.     elif IsMat( z )  then
  564.  
  565.         # handle small matrices directly
  566.         if Length( z )^2 < p  then
  567.             int := [];
  568.             for y  in z  do
  569.                 row := [];
  570.                 for i  in [ 1 .. Length( y ) ]  do
  571.                     if   y[i] = zero  then row[i] := 0;
  572.                     elif y[i] = one   then row[i] := 1;
  573.                     else row[i] := PowerMod( r, LogFFE( y[i], Z(p) ), p );
  574.                     fi;
  575.                 od;
  576.                 Add( int, row );
  577.             od;
  578.  
  579.         # handle large matrices with a lookup table
  580.         else
  581.             cnv := [ r ];
  582.             for i  in [2..p-2]  do
  583.                 cnv[i] := (cnv[i-1] * r) mod p;
  584.             od;
  585.             int := [];
  586.             for y  in z  do
  587.                 row := [];
  588.                 for i  in [ 1 .. Length( y ) ]  do
  589.                     if   y[i] = zero  then row[i] := 0;
  590.                     elif y[i] = one   then row[i] := 1;
  591.                     else row[i] := cnv[ LogFFE( y[i], Z(p) ) ];
  592.                     fi;
  593.                 od;
  594.                 Add( int, row );
  595.             od;
  596.  
  597.         fi;
  598.  
  599.     else
  600.         Error("<z> must be an element, a vector, or a matrix");
  601.     fi;
  602.  
  603.     # return the integer
  604.     return int;
  605. end;
  606.  
  607. FiniteFieldOps.Int := function ( F, z )
  608.     return IntFFE( z );
  609. end;
  610.  
  611.  
  612. #############################################################################
  613. ##
  614. #F  GaloisField( <p>^<n> )  . . . . . . . . . .  create a finite field record
  615. ##
  616. GF := function ( arg )
  617.     local   F,  p, d,  i, r;
  618.  
  619.     # if necessary split the arguments
  620.     if Length(arg) = 1  then
  621.         p := SmallestRootInt( arg[1] );
  622.         d := LogInt( arg[1], p );
  623.     elif Length(arg) = 2  then
  624.         p := arg[1];
  625.         d := arg[2];
  626.     else
  627.         Error("usage: GF( <subfield>, <extension> )");
  628.     fi;
  629.  
  630.     # if the subfield is given by a prime denoting the prime field
  631.     if IsInt( p )  and IsPrime( p )  then
  632.  
  633.         # if the degree of the extension is given
  634.         if   IsInt( d )  then
  635.  
  636.             F := rec(
  637.                 isDomain                := true,
  638.                 isField                 := true,
  639.  
  640.                 char                    := p,
  641.                 degree                  := d,
  642.                 generators              := List( [0..d-1], i->Z(p^d)^i ),
  643.                 zero                    := 0 * Z(p^d),
  644.                 one                     := Z(p^d) ^ 0,
  645.  
  646.                 size                    := p^d,
  647.                 isFinite                := true,
  648.                 root                    := Z(p^d),
  649.  
  650.                 field                   := p,
  651.                 dimension               := d,
  652.                 base                    := List( [0..d-1], i->Z(p^d)^i ),
  653.  
  654.                 operations              := FiniteFieldOps );
  655.  
  656.         # if a base for the extension is given
  657.         elif IsVector( d )  and IsBaseFF( p, d )  then
  658.  
  659.             F := rec(
  660.                 isDomain                := true,
  661.                 isField                 := true,
  662.  
  663.                 char                    := p,
  664.                 degree                  := Length( d ),
  665.                 generators              := Copy( d ),
  666.                 zero                    := 0 * Z(p),
  667.                 one                     := Z(p) ^ 0,
  668.  
  669.                 size                    := p^Length(d),
  670.                 isFinite                := true,
  671.  
  672.                 field                   := p,
  673.                 dimension               := Length( d ),
  674.                 base                    := Copy( d ),
  675.  
  676.                 operations              := FiniteFieldOps );
  677.  
  678.         # if the extension is given by an irreducible polynomial
  679.         elif IsVector( d )  and DegreeFFE( d ) = 1  then
  680.  
  681.             r := Z(p^(Length(d)-1));
  682.             while r <> r^0 and ValuePol( d, r ) <> 0 * r  do
  683.                 r := r * Z(p^(Length(d)-1));
  684.             od;
  685.             if DegreeFFE( r ) < Length( d ) - 1  then
  686.                 Error("<polynomial> must be irreducible");
  687.             fi;
  688.  
  689.             F := rec(
  690.                 isDomain                := true,
  691.                 isField                 := true,
  692.  
  693.                 char                    := p,
  694.                 degree                  := Length( d ) - 1,
  695.                 generators              := List( [0..Length(d)-2], i->r^i ),
  696.                 zero                    := 0 * Z(p),
  697.                 one                     := Z(p) ^ 0,
  698.  
  699.                 size                    := p^(Length(d)-1),
  700.                 isFinite                := true,
  701.                 polynomial              := Copy( d ),
  702.  
  703.                 field                   := p,
  704.                 dimension               := Length( d ),
  705.                 base                    := List( [0..Length(d)-2], i->r^i ),
  706.  
  707.                 operations              := FiniteFieldOps );
  708.  
  709.             if FiniteFieldOps.Order(F,r) = F.char^F.degree - 1  then
  710.                 F.root := r;
  711.             fi;
  712.  
  713.         fi;
  714.  
  715.     # if the subfield is given by a finite field record
  716.     elif IsRec( p )  then
  717.  
  718.         # if the degree of the extension is given
  719.         if   IsInt( d )  then
  720.  
  721.             F := rec(
  722.                 isDomain                := true,
  723.                 isField                 := true,
  724.  
  725.                 char                    := p.char,
  726.                 degree                  := p.degree * d,
  727.                 generators              := List( [0..p.degree*d-1],
  728.                                              i->Z(p.char^(p.degree*d))^i
  729.                                            ),
  730.                 zero                    := 0 * Z(p.char^(p.degree*d)),
  731.                 one                     := Z(p.char^(p.degree*d)) ^ 0,
  732.  
  733.                 size                    := p.char ^ (p.degree * d),
  734.                 isFinite                := true,
  735.                 root                    := Z(p.char^(p.degree*d)),
  736.  
  737.                 field                   := p,
  738.                 dimension               := d,
  739.                 base                    := List( [0..d-1],
  740.                                              i->Z(p.char^(p.degree*d))^i
  741.                                            ),
  742.  
  743.                 operations              := FiniteFieldOps );
  744.  
  745.         # if a base for the extension is given
  746.         elif IsVector( d )  and IsBaseFF( p, d )  then
  747.  
  748.             F := rec(
  749.                 isDomain                := true,
  750.                 isField                 := true,
  751.  
  752.                 char                    := p.char,
  753.                 degree                  := p.degree * Length(d),
  754.                 generators              := List( [0..p.degree*Length(d)-1],
  755.                                           i->Z(p.char^(p.degree*Length(d)))^i
  756.                                            ),
  757.                 zero                    := 0 * Z(p.char),
  758.                 one                     := Z(p.char) ^ 0,
  759.  
  760.                 size                    := p.char^(p.degree*Length(d)),
  761.                 isFinite                := true,
  762.  
  763.                 field                   := p,
  764.                 dimension               := Length( d ),
  765.                 base                    := Copy( d ),
  766.  
  767.                 operations              := FiniteFieldOps );
  768.  
  769.         # if the extension is given by an irreducible polynomial
  770.         elif IsVector( d )  and p.degree mod DegreeFFE( d ) = 0  then
  771.  
  772.             r := Z(p.char^(Length(d)-1));
  773.             while r <> r^0 and ValuePol( d, r ) <> 0 * r  do
  774.                 r := r * Z(p.char^(Length(d)-1));
  775.             od;
  776.             if DegreeFFE( r ) < Length( d ) - 1  then
  777.                 Error("<pol> must be irreducible");
  778.             fi;
  779.  
  780.             F := rec(
  781.                 isDomain   := true,
  782.                 isField    := true,
  783.  
  784.                 char       := p.char,
  785.                 degree     := p.degree * (Length(d)-1),
  786.                 generators := List( [0..p.degree*(Length(d)-1)-1],
  787.                                 i->Z(p.char^(p.degree*(Length(d)-1)))^i
  788.                                            ),
  789.                 zero       := 0 * Z(p.char),
  790.                 one        := Z(p.char) ^ 0,
  791.  
  792.                 size       := p.char^(p.degree*(Length(d)-1)),
  793.                 isFinite   := true,
  794.  
  795.                 field      := p,
  796.                 dimension  := Length( d ) - 1,
  797.                 base       := List( [0..Length(d)-2], i->r^i ),
  798.                 polynomial := Copy( d ),
  799.  
  800.                 operations := FiniteFieldOps );
  801.  
  802.             if FiniteFieldOps.Order(F,r) = F.char^F.degree - 1  then
  803.                 F.root := r;
  804.             fi;
  805.  
  806.         # otherwise we dont know how to handle the extension
  807.         else
  808.             Error("<extension> must be a <deg>, <bas>, or <pol>");
  809.         fi;
  810.  
  811.     # otherwise we dont know how to handle the subfield
  812.     else
  813.         Error("<subfield> must be a prime or a finite field");
  814.     fi;
  815.  
  816.     # return the finite field record
  817.     return F;
  818. end;
  819.  
  820. FiniteField := GF;
  821. GaloisField := GF;
  822.  
  823.  
  824. #############################################################################
  825. ##
  826. #V  FiniteFieldElements . . . . . . . . . domain of all finite field elements
  827. #V  FiniteFieldElementsOps  . .  operations record for the domain of all ffes
  828. ##
  829. FiniteFieldElementsOps          := Copy( FieldElementsOps );
  830.  
  831. FiniteFieldElementsOps.\in     := function ( z, F )
  832.     return IsFFE( z );
  833. end;
  834.  
  835. FiniteFieldElementsOps.Order    := FiniteFieldOps.Order;
  836.  
  837. FiniteFieldElementsOps.Int      := FiniteFieldOps.Int;
  838.  
  839.  
  840. FiniteFieldElements             := rec();
  841. FiniteFieldElements.isDomain    := true;
  842.  
  843. FiniteFieldElements.name        := "FiniteFieldElements";
  844.  
  845. FiniteFieldElements.isFinite    := false;
  846. FiniteFieldElements.size        := "infinity";
  847.  
  848. FiniteFieldElements.operations  := FiniteFieldElementsOps;
  849.  
  850.  
  851. #############################################################################
  852. ##
  853. #F  FiniteFieldElementsOps.Field(<v>) . . . . field of a finite field element
  854. ##
  855. FiniteFieldElementsOps.Field := function ( z )
  856.     local   F,          # field containing <z>, result
  857.             chr,        # characteristic of <z>
  858.             deg;        # degree of <z> over the primefield
  859.  
  860.     # get characteristic and degree
  861.     chr := CharFFE( z );
  862.     deg := DegreeFFE( z );
  863.  
  864.     # make the finite field record
  865.     F := rec(
  866.  
  867.         isDomain                := true,                # type of domain
  868.         isField                 := true,
  869.  
  870.         char                    := chr,                 # identity
  871.         degree                  := deg,
  872.         generators              := List( [0..deg-1], i->Z(chr^deg)^i ),
  873.         zero                    := 0 * Z(chr),
  874.         one                     := Z(chr) ^ 0,
  875.  
  876.         size                    := chr^deg,             # properties
  877.         isFinite                := true,
  878.         root                    := Z(chr^deg),
  879.  
  880.         field                   := chr,                 # subfield
  881.         dimension               := deg,
  882.         base                    := List( [0..deg-1], i->Z(chr^deg)^i ),
  883.  
  884.         operations              := FiniteFieldOps
  885.  
  886.     );
  887.  
  888.     # return the finite field
  889.     return F;
  890. end;
  891.  
  892.  
  893. #############################################################################
  894. ##
  895. #F  FiniteFieldElementsOps.DefaultField(<z>)  . default field containing ffes
  896. ##
  897. FiniteFieldElementsOps.DefaultField := FiniteFieldElementsOps.Field;
  898.  
  899.  
  900. #############################################################################
  901. ##
  902. #F  IsBaseFF( <F>, <base> ) . . . . . . . . . . test for linear indenpendence
  903. ##
  904. IsBaseFF := function ( F, base )
  905.     local   q, d, mat, b, cnjs, k;
  906.  
  907.     # get the order of the subfield and the degree of the extension
  908.     if IsInt(F)  then
  909.         q := F;
  910.         d := DegreeFFE( base );
  911.     else
  912.         q := F.char ^ F.degree;
  913.         d := DegreeFFE( base ) / F.degree;
  914.     fi;
  915.  
  916.     # test that the elements of base lie in the finite field of degree d
  917.     if d <> Length(base)  then
  918.         return false;
  919.     fi;
  920.  
  921.     # build the matrix M[i,k] = base[i]^(q^k)
  922.     mat := [];
  923.     for b  in base  do
  924.         cnjs := [];
  925.         for k  in [0..d-1]  do
  926.             Add( cnjs, b^(q^k) );
  927.         od;
  928.         Add( mat, cnjs );
  929.     od;
  930.  
  931.     # it is a base if and only if mat is invertable
  932.     return DeterminantMat( mat ) <> 0;
  933. end;
  934.  
  935.  
  936. #############################################################################
  937. ##
  938. #F  IsFrobeniusAutomorphism(<obj>)  . . test if an object is a Frobenius aut.
  939. ##
  940. IsFrobeniusAutomorphism := function ( obj )
  941.     return IsRec( obj )
  942.        and IsBound( obj.isFrobeniusAutomorphism )
  943.        and obj.isFrobeniusAutomorphism;
  944. end;
  945.  
  946.  
  947. #############################################################################
  948. ##
  949. #F  FrobeniusAutomorphism(<F>)  . .  Frobenius automorphism of a finite field
  950. #V  FrobeniusAutomorphismOps  . . . . . operations record for Frobenius auts.
  951. ##
  952. FrobeniusAutomorphism := function ( F )
  953.  
  954.     # check the arguments
  955.     if not IsField( F )  or not IsPrime( F.char )  then
  956.         Error("<F> must be a finite field");
  957.     fi;
  958.  
  959.     # return the automorphism
  960.     return FrobeniusAutomorphismI( F, F.char );
  961. end;
  962.  
  963. FrobeniusAutomorphismI := function ( F, i )
  964.  
  965.     # make the mapping record
  966.     return rec(
  967.         isGeneralMapping        := true,
  968.         domain                  := Mappings,
  969.  
  970.         isFrobeniusAutomorphism := true,
  971.         power                   := i mod (Size( F ) - 1),
  972.         source                  := F,
  973.         range                   := F,
  974.  
  975.         isMapping               := true,
  976.         isHomomorphism          := true,
  977.         isSurjective            := true,
  978.         isInjective             := true,
  979.  
  980.         operations              := FrobeniusAutomorphismOps );
  981.  
  982. end;
  983.  
  984. FrobeniusAutomorphismOps := Copy( FieldHomomorphismOps );
  985.  
  986. FrobeniusAutomorphismOps.\= := function ( aut1, aut2 )
  987.     if IsFrobeniusAutomorphism( aut1 )  then
  988.         if IsFrobeniusAutomorphism( aut2 )  then
  989.             return aut1.source = aut2.source
  990.                and aut1.power  = aut2.power;
  991.         else
  992.             return false;
  993.         fi;
  994.     else
  995.         if IsFrobeniusAutomorphism( aut2 )  then
  996.             return false;
  997.         else
  998.             Error("panic: neither <aut1> nor <aut2> is a Frobenius aut.");
  999.         fi;
  1000.     fi;
  1001. end;
  1002.  
  1003. FrobeniusAutomorphismOps.ImageElm := function ( aut, elm )
  1004.     return elm ^ aut.power;
  1005. end;
  1006.  
  1007. FrobeniusAutomorphismOps.ImagesElm := function ( aut, elm )
  1008.     return [ elm ^ aut.power ];
  1009. end;
  1010.  
  1011. FrobeniusAutomorphismOps.ImagesSet := function ( aut, elms )
  1012.     if IsField( elms )  and  IsSubset( aut.source, elms )  then
  1013.         return elms;
  1014.     else
  1015.         return FieldHomomorphismOps.ImagesSet( aut, elms );
  1016.     fi;
  1017. end;
  1018.  
  1019. FrobeniusAutomorphismOps.ImagesRepresentative := function ( aut, elm )
  1020.     return elm ^ aut.power;
  1021. end;
  1022.  
  1023. FrobeniusAutomorphismOps.CompositionMapping := function ( aut1, aut2 )
  1024.     if IsFrobeniusAutomorphism( aut1 )  then
  1025.         if IsFrobeniusAutomorphism( aut2 )  then
  1026.             return FrobeniusAutomorphismI( aut1.source,
  1027.                                            aut1.power * aut2.power );
  1028.         else
  1029.             return FieldHomomorphismOps.CompositionMapping( aut1, aut2 );
  1030.         fi;
  1031.     else
  1032.         return FieldHomomorphismOps.CompositionMapping( aut1, aut2 );
  1033.     fi;
  1034. end;
  1035.  
  1036. FrobeniusAutomorphismOps.InverseMapping := function ( aut )
  1037.     return FrobeniusAutomorphismI( aut.source,
  1038.                                    Size(aut.source)/aut.power );
  1039. end;
  1040.  
  1041. FrobeniusAutomorphismOps.PowerMapping := function ( aut, i )
  1042.     return FrobeniusAutomorphismI( aut.source,
  1043.                                    PowerMod(aut.power,i,Size(aut.source)-1));
  1044. end;
  1045.  
  1046. FrobeniusAutomorphismOps.\< := function ( aut1, aut2 )
  1047.     local   p, d;       # characteristic and degree
  1048.     if IsFrobeniusAutomorphism( aut1 )  then
  1049.         if IsFrobeniusAutomorphism( aut2 )  then
  1050.             if aut1.source <> aut2.source  then
  1051.                 return aut1.source < aut2.source;
  1052.             else
  1053.                 p := aut1.source.char;
  1054.                 for d  in DivisorsInt( LogInt( Size(aut1.source), p ) )  do
  1055.                     if Z(p^d) ^ aut1.power <> Z(p^d) ^ aut2.power  then
  1056.                         return Z(p^d) ^ aut1.power < Z(p^d) ^ aut2.power;
  1057.                     fi;
  1058.                 od;
  1059.                 return false;
  1060.             fi;
  1061.         else
  1062.             return FieldHomomorphismOps.\<( aut1, aut2 );
  1063.         fi;
  1064.     else
  1065.         return FieldHomomorphismOps.\<( aut1, aut2 );
  1066.     fi;
  1067. end;
  1068.  
  1069. FrobeniusAutomorphismOps.Print := function ( aut )
  1070.     if aut.power = aut.source.char  then
  1071.         Print( "FrobeniusAutomorphism( ", aut.source, " )" );
  1072.     elif aut.power = 1  then
  1073.         Print( "IdentityMapping( ", aut.source, " )" );
  1074.     else
  1075.         Print( "FrobeniusAutomorphism( ", aut.source, " )^",
  1076.                LogInt( aut.power, aut.source.char ) );
  1077.     fi;
  1078. end;
  1079.  
  1080. FiniteFieldOps.IdentityMapping := function ( F )
  1081.     return FrobeniusAutomorphismI( F, 1 );
  1082. end;
  1083.  
  1084.  
  1085. #############################################################################
  1086. ##
  1087. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  1088. ##
  1089. ##  Local Variables:
  1090. ##  mode:               outline
  1091. ##  outline-regexp:     "#F\\|#V\\|#E"
  1092. ##  fill-column:        73
  1093. ##  fill-prefix:        "##  "
  1094. ##  eval:               (hide-body)
  1095. ##  End:
  1096. ##
  1097.  
  1098.  
  1099.  
  1100.