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

  1. #############################################################################
  2. ##
  3. #A  ring.g                      GAP library                  Martin Schoenert
  4. ##
  5. #A  @(#)$Id: ring.g,v 3.13 1992/12/16 19:47:27 martin Rel $
  6. ##
  7. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  8. ##
  9. ##  This file  contains  those  functions  that  are  dispatcher  for  rings.
  10. ##
  11. #H  $Log: ring.g,v $
  12. #H  Revision 3.13  1992/12/16  19:47:27  martin
  13. #H  replaced quoted record names with escaped ones
  14. #H
  15. #H  Revision 3.12  1992/12/07  07:38:55  fceller
  16. #H  replaced another 1,0 with R.one,R.zero
  17. #H
  18. #H  Revision 3.11  1992/11/16  12:23:47  fceller
  19. #H  added Laurent polynomials
  20. #H
  21. #H  Revision 3.10  1992/08/13  13:11:09  fceller
  22. #H  add 'Indeterminate'
  23. #H
  24. #H  Revision 3.9  1992/06/17  07:06:04  fceller
  25. #H  moved '<somedomain>.operations.Polynomial' function to "<somedomain>.g"
  26. #H
  27. #H  Revision 3.8  1992/04/21  10:28:53  fceller
  28. #H  changed '0' and '1' into 'R.zero' and 'R.one' in 'Gcd'
  29. #H
  30. #H  Revision 3.7  1992/04/05  15:04:04  martin
  31. #H  improved 'RingOps.Units' to return a group, not a set
  32. #H
  33. #H  Revision 3.6  1992/04/05  14:57:27  martin
  34. #H  added 'RingOps.Print'
  35. #H
  36. #H  Revision 3.5  1992/04/05  14:50:49  martin
  37. #H  changed 'Ring' slightly
  38. #H
  39. #H  Revision 3.4  1992/04/05  14:16:44  martin
  40. #H  added 'RingOps.Elements'
  41. #H
  42. #H  Revision 3.3  1992/02/06  11:47:31  martin
  43. #H  removed 'InverseMod' and added 'QuotientMod'
  44. #H
  45. #H  Revision 3.2  1991/12/04  09:01:29  martin
  46. #H  changed 'Ring' and 'DefaultRing' to use 'Domain', removed 'RingDomain'
  47. #H
  48. #H  Revision 3.1  1991/10/24  11:33:29  martin
  49. #H  changed package for new domain concept with inheritance
  50. #H
  51. #H  Revision 3.0  1991/08/08  15:34:42  martin
  52. #H  initial revision under RCS
  53. #H
  54. ##
  55.  
  56.  
  57. #############################################################################
  58. ##
  59. #F  IsRing( <domain> )  . . . . . . . . . . . . .  test if a domain is a ring
  60. ##
  61. IsRing := function ( D )
  62.     return IsRec( D )
  63.        and IsBound( D.isRing )
  64.        and D.isRing;
  65. end;
  66.  
  67.  
  68. ############################################################################
  69. ##
  70. #V  RingOps . . . . . . . . . . . . . . .  operation record for ring category
  71. ##
  72. RingOps := Copy( DomainOps );
  73.  
  74.  
  75. #############################################################################
  76. ##
  77. #F  RingOps.Elements( <R> ) . . . . . . . . . . . . . . .  elements of a ring
  78. ##
  79. RingOps.Elements := function ( R )
  80.     local   elms,       # elements of <R>, result
  81.             set,        # set corresponding to <elms>
  82.             elm,        # one element of <elms>
  83.             gen,        # one generator of <R>
  84.             new;        # product or sum of <elm> and <gen>
  85.  
  86.     # check that we can handle this ring
  87.     if IsBound( R.isFinite ) and not R.isFinite  then
  88.         Error("the ring <R> must be finite to compute its elements");
  89.     elif not IsBound( R.generators )  then
  90.         Error("sorry, do not know how to compute the elements of <R>");
  91.  
  92.     # otherwise use an orbit like algorithm
  93.     else
  94.         elms := [ R.zero ];
  95.         set  := Set( elms );
  96.         for elm  in elms  do
  97.             for gen  in R.generators  do
  98.                 new := elm + gen;
  99.                 if not new in set  then
  100.                     Add( elms, new );
  101.                     AddSet( set, new );
  102.                 fi;
  103.                 new := elm * gen;
  104.                 if not new in set  then
  105.                     Add( elms, new );
  106.                     AddSet( set, new );
  107.                 fi;
  108.             od;
  109.         od;
  110.     fi;
  111.     return set;
  112. end;
  113.  
  114.  
  115. #############################################################################
  116. ##
  117. #F  RingOps.\=( <R>, <S> ) . . . . . . . . . . . test if two rings are equal
  118. ##
  119. RingOps.\= := function ( R, S )
  120.     local   isEql;
  121.     if IsRing( R ) and IsFinite( R )  then
  122.         if IsRing( S ) and IsFinite( S )  then
  123.             if IsBound( R.generators )  and IsBound( S.generators )  then
  124.                 isEql :=     (Size( R ) = Size( S ))
  125.                          and ForAll( R.generators, r -> r in S )
  126.                          and ForAll( S.generators, s -> s in R );
  127.             else
  128.                 isEql := DomainOps.\=( R, S );
  129.             fi;
  130.         elif IsRing( S )  then
  131.             isEql := false;
  132.     else
  133.             isEql := DomainOps.\=( R, S );
  134.         fi;
  135.     elif IsRing( R )  then
  136.         if IsRing( S )  and IsFinite( S )  then
  137.             isEql := false;
  138.         elif IsRing( S )  then
  139.             if IsBound( R.generators )  and IsBound( S.generators )  then
  140.                 isEql :=     ForAll( R.generators, g -> g in S )
  141.                          and ForAll( S.generators, g -> g in R );
  142.             else
  143.                 isEql := DomainOps.\=( R, S );
  144.             fi;
  145.     else
  146.             isEql := DomainOps.\=( R, S );
  147.         fi;
  148.     else
  149.         isEql := DomainOps.\=( R, S );
  150.     fi;
  151.     return isEql;
  152.  
  153. end;
  154.  
  155.  
  156. #############################################################################
  157. ##
  158. #F  RingOps.Print(<R>)  . . . . . . . . . . . . . . . . . . . .  print a ring
  159. ##
  160. RingOps.Print := function ( R )
  161.     local   i;
  162.  
  163.     # if the ring has a name we use this
  164.     if IsBound( R.name )  then
  165.         Print( R.name );
  166.  
  167.     # otherwise we print the generators
  168.     elif IsBound( R.generators )  then
  169.  
  170.         # if the ring is not trivial the identity need not be printed
  171.         if R.generators <> []  then
  172.             Print( "Ring( ");
  173.             for i  in [ 1 .. Length(R.generators)-1 ]  do
  174.                 Print( R.generators[i], ", " );
  175.             od;
  176.             Print( R.generators[Length(R.generators)], " )" );
  177.  
  178.         # if the group is trivial print it as 'Ring( <id> )'
  179.         else
  180.             Print( "Ring( ", R.identity, " )" );
  181.         fi;
  182.  
  183.     # else print the record
  184.     else
  185.         PrintRec( R );
  186.     fi;
  187. end;
  188.  
  189.  
  190. #############################################################################
  191. ##
  192. #F  RingOps.Polynomial( <R>, <coeffs>, <val> )    .  polynomial over a ring <R>
  193. ##
  194. RingOps.Polynomial := function( R, coeffs, val )
  195.     local  i,  k,  l,  c;
  196.  
  197.     # remove leading zeros
  198.     k := Length( coeffs );
  199.     while 0 < k and coeffs[k] = R.zero  do
  200.         k := k - 1;
  201.     od;
  202.  
  203.     # remove trailing zeros
  204.     i := 0;
  205.     while i < k and coeffs[i+1] = R.zero  do
  206.     i := i + 1;
  207.     od;
  208.  
  209.     # now really remove zeros
  210.     c := [];
  211.     for l  in [ i+1 .. k ]  do
  212.     c[l-i] := coeffs[l];
  213.     od;
  214.     if i < k  then
  215.         val := val + i;
  216.     else
  217.         val := 0;
  218.     fi;
  219.  
  220.     # is vector might fail, but we ignore this
  221.     IsVector(c);
  222.  
  223.     # return polynomial
  224.     if val < 0  then
  225.         return rec( coefficients := c,
  226.                     baseRing     := R,
  227.                     isPolynomial := true,
  228.             valuation    := val,
  229.                     domain       := LaurentPolynomials,
  230.                     operations   := PolynomialOps );
  231.     else
  232.         return rec( coefficients := c,
  233.                     baseRing     := R,
  234.                     isPolynomial := true,
  235.             valuation    := val,
  236.                     domain       := Polynomials,
  237.                     operations   := PolynomialOps );
  238.     fi;
  239.  
  240. end;
  241.  
  242.  
  243. #############################################################################
  244. ##
  245. #F  RingOps.PolynomialRing( <R> ) . . . . . . . . . . .  full polynomial ring
  246. ##
  247. RingOps.PolynomialRing := function( R )
  248.     local   P;
  249.  
  250.     # construct a new ring domain
  251.     P := rec();
  252.     P.isDomain := true;
  253.     P.isRing   := true;
  254.  
  255.     # show that this a polynomial ring
  256.     P.isPolynomialRing := true;
  257.  
  258.     # set known properties
  259.     P.isFinite := false;
  260.     P.size     := "infinity";
  261.  
  262.     # add known properties of polynom ring
  263.     if IsBound(R.isCommutativeRing)  then
  264.         P.isCommutativeRing := R.isCommutativeRing;
  265.     fi;
  266.  
  267.     # add known units
  268.     if IsBound(R.units)  then
  269.         P.units := Copy(R.units);
  270.     fi;
  271.  
  272.     # set one and zero
  273.     P.one  := Polynomial( R, [ R.one ] );
  274.     P.zero := Polynomial( R, [] );
  275.  
  276.     # 'P.baseRing' contains <R>
  277.     P.baseRing := R;
  278.  
  279.     # set operations record and return
  280.     P.operations := PolynomialRingOps;
  281.     return P;
  282.  
  283. end;
  284.  
  285.  
  286. #############################################################################
  287. ##
  288. #F  RingOps.LaurentPolynomialRing( <R> )  . . .  full Laurent polynomial ring
  289. ##
  290. RingOps.LaurentPolynomialRing := function( R )
  291.     local   P;
  292.  
  293.     # construct a new ring domain
  294.     P := rec();
  295.     P.isDomain := true;
  296.     P.isRing   := true;
  297.  
  298.     # show that this a Laurent polynomial ring
  299.     P.isLaurentPolynomialRing := true;
  300.  
  301.     # set known properties
  302.     P.isFinite := false;
  303.     P.size     := "infinity";
  304.  
  305.     # add known properties of polynom ring
  306.     if IsBound(R.isCommutativeRing)  then
  307.         P.isCommutativeRing := R.isCommutativeRing;
  308.     fi;
  309.  
  310.     # set one and zero
  311.     P.one  := Polynomial( R, [ R.one ] );
  312.     P.zero := Polynomial( R, [] );
  313.  
  314.     # 'P.baseRing' contains <R>
  315.     P.baseRing := R;
  316.  
  317.     # set operations record and return
  318.     P.operations := LaurentPolynomialRingOps;
  319.     return P;
  320.  
  321. end;
  322.  
  323.  
  324. #############################################################################
  325. ##
  326. #F  RingOps.Indeterminate( <R> )  . . . . . . . . . indeterminate over a ring
  327. ##
  328. RingOps.Indeterminate := function( R )
  329.     return Polynomial( R, [ R.zero, R.one ] );
  330. end;
  331.  
  332.  
  333. #############################################################################
  334. ##
  335. #F  IsCommutativeRing( <D> )  . . . . .  test if a domain is commutative ring
  336. ##
  337. IsCommutativeRing := function ( R )
  338.  
  339.     if not IsRing( R )  then
  340.         Error("<R> must be a ring");
  341.     fi;
  342.  
  343.     if not IsBound( R.isCommutativeRing )  then
  344.         R.isCommutativeRing := R.operations.IsCommutativeRing( R );
  345.     fi;
  346.  
  347.     return R.isCommutativeRing;
  348. end;
  349.  
  350. RingOps.IsCommutativeRing := function ( R )
  351.     local    elms, i, k;
  352.  
  353.     if IsBound( R.generators )  then
  354.         for i  in [1..Length(R.generators)]  do
  355.             for k  in [i+1..Length(R.generators)]  do
  356.                 if   R.generators[i] * R.generators[k]
  357.                   <> R.generators[k] * R.generators[i]
  358.                 then
  359.                     return false;
  360.                 fi;
  361.             od;
  362.         od;
  363.         return true;
  364.  
  365.     elif IsFinite( R )  then
  366.         elms := Elements( R );
  367.         for i  in [1..Length(elms)]  do
  368.             for k  in [i+1..Length(elms)]  do
  369.                 if elms[i] * elms[k] <> elms[k] * elms[i]  then
  370.                     return false;
  371.                 fi;
  372.             od;
  373.         od;
  374.         return true;
  375.  
  376.     else
  377.         Error("sorry, can not test if the infinite ring <R> is commutative");
  378.     fi;
  379. end;
  380.  
  381.  
  382. #############################################################################
  383. ##
  384. #F  IsIntegralRing( <D> ) . . . . . . . test if a domain is a integral domain
  385. ##
  386. IsIntegralRing := function ( R )
  387.  
  388.     if not IsRing( R )  then
  389.         Error("<R> must be a ring");
  390.     fi;
  391.  
  392.     if not IsBound( R.isIntegralRing )  then
  393.         R.isIntegralRing := R.operations.IsIntegralRing( R );
  394.     fi;
  395.  
  396.     return R.isIntegralRing;
  397. end;
  398.  
  399. RingOps.IsIntegralRing := function ( R )
  400.     local   elms, i, k;
  401.  
  402.     if IsFinite( R )  then
  403.         if not IsCommutativeRing( R )  then
  404.             return false;
  405.         fi;
  406.         elms := Elements( R );
  407.         for i  in [1..Length(elms)]  do
  408.             for k  in [i+1..Length(elms)]  do
  409.                 if elms[i] * elms[k] = R.zero  then
  410.                     return false;
  411.                 fi;
  412.             od;
  413.         od;
  414.         return true;
  415.  
  416.     else
  417.         Error("sorry, can not test if the infinte ring <R> is integral");
  418.     fi;
  419. end;
  420.  
  421.  
  422. #############################################################################
  423. ##
  424. #F  IsUniqueFactorizationRing( <D> )  . . . . . . . test if a domain is a UFD
  425. ##
  426. IsUniqueFactorizationRing := function ( R )
  427.  
  428.     if not IsRing( R )  then
  429.         Error("<R> must be a ring");
  430.     fi;
  431.  
  432.     if not IsBound( R.isUniqueFactorizationRing )  then
  433.         R.isUniqueFactorizationRing :=
  434.             R.operations.IsUniqueFactorizationRing( R );
  435.     fi;
  436.  
  437.     return R.isUniqueFactorizationRing;
  438. end;
  439.  
  440. RingOps.IsUniqueFactorizationRing := function ( R )
  441.     Error("sorry, can not test if the ring <R> has unique factorization");
  442. end;
  443.  
  444.  
  445. #############################################################################
  446. ##
  447. #F  IsEuclideanRing( <D> )  . . . . . .  test if a domain is a Euclidean ring
  448. ##
  449. IsEuclideanRing := function ( R )
  450.  
  451.     if not IsRing( R )  then
  452.         Error("<R> must be a ring");
  453.     fi;
  454.  
  455.     if not IsBound( R.isEuclideanRing )  then
  456.         R.isEuclideanRing := R.operations.IsEuclideanRing( R );
  457.     fi;
  458.  
  459.     return R.isEuclideanRing;
  460. end;
  461.  
  462. RingOps.IsEuclideanRing := function ( R )
  463.     Error("sorry, can not test if the ring <R> is an Euclidean ring");
  464. end;
  465.  
  466.  
  467. #############################################################################
  468. ##
  469. #F  Quotient( [<R>,] <r>, <s> ) . . . . . . . . quotient of two ring elements
  470. ##
  471. Quotient := function ( arg )
  472.     local   R, r, s;
  473.  
  474.     # get and check the arguments
  475.     if   Length(arg) = 2  then
  476.         R := DefaultRing( arg[1], arg[2] );
  477.         r := arg[1];
  478.         s := arg[2];
  479.     elif Length(arg) = 3  then
  480.         R := arg[1];
  481.         if not IsRing( R )  then
  482.             Error("<R> must be a ring");
  483.         fi;
  484.         r := arg[2];
  485.         if not r in R  then
  486.             Error("<r> must be an element of <R>");
  487.         fi;
  488.         s := arg[3];
  489.         if not s in R  then
  490.             Error("<s> must be an element of <R>");
  491.         fi;
  492.     else
  493.         Error("usage: Quotient( [<R>,] <r>, <s> )");
  494.     fi;
  495.  
  496.     # there must be an operation to compute the quotient
  497.     return R.operations.Quotient( R, r, s );
  498. end;
  499.  
  500. RingOps.Quotient := function ( R, r, s )
  501.     Error("sorry, can not divide in the ring <R>");
  502. end;
  503.  
  504.  
  505. #############################################################################
  506. ##
  507. #F  IsUnit( [<R>,] <r> )  . . . . . . . . . . .  test if an element is a unit
  508. ##
  509. IsUnit := function ( arg )
  510.     local   R, r;
  511.  
  512.     # get and check the arguments
  513.     if    Length(arg) = 1  then
  514.         R := DefaultRing( arg[1] );
  515.         r := arg[1];
  516.     elif  Length(arg) = 2  then
  517.         R := arg[1];
  518.         if not IsRing( R )  then
  519.             Error("<R> must be a ring");
  520.         fi;
  521.         r := arg[2];
  522.         if not r in R  then
  523.             Error("<r> must be an element of <R>");
  524.         fi;
  525.     else
  526.         Error("usage: IsUnit( [<R>,] <r> )");
  527.     fi;
  528.  
  529.     # perform the test
  530.     return R.operations.IsUnit( R, r );
  531. end;
  532.  
  533. RingOps.IsUnit := function ( R, r )
  534.     local   isUnit;
  535.  
  536.     # if a list of units is already known, use it
  537.     if IsBound( R.units )  then
  538.         isUnit := r in R.units;
  539.  
  540.     # otherwise simply try to compute the inverse
  541.     else
  542.         isUnit := r <> R.zero
  543.                   and R.operations.Quotient( R, R.one, r ) <> false;
  544.     fi;
  545.  
  546.     # return the result
  547.     return isUnit;
  548. end;
  549.  
  550.  
  551. #############################################################################
  552. ##
  553. #F  Units( <R> )  . . . . . . . . . . . . . . . . . . . . . . units of a ring
  554. ##
  555. Units := function ( R )
  556.  
  557.     # check the argument
  558.     if not IsRing( R )  then
  559.         Error("<R> must be a ring");
  560.     fi;
  561.  
  562.     # compute the units if necessary
  563.     if not IsBound( R.units )  then
  564.         R.units := R.operations.Units( R );
  565.     fi;
  566.  
  567.     # return the units
  568.     return ShallowCopy( R.units );
  569. end;
  570.  
  571. RingOps.Units := function ( R )
  572.     local   units,
  573.             elm;
  574.  
  575.     if IsFinite( R )  then
  576.         units := Group( R.one );
  577.         for elm  in Elements( R )  do
  578.             if IsUnit( R, elm )  and not elm in units  then
  579.                 units := Group( Concatenation( units.generators, [ elm ] ),
  580.                                 units.identity );
  581.             fi;
  582.         od;
  583.     else
  584.         Error("sorry, can not compute the units of the infinite ring <R>");
  585.     fi;
  586.  
  587.     return units;
  588. end;
  589.  
  590.  
  591. #############################################################################
  592. ##
  593. #F  IsAssociated( [<R>,] <r>, <s> )  test if two ring elements are associated
  594. ##
  595. IsAssociated := function ( arg )
  596.     local   R, r, s;
  597.  
  598.     # get and check the arguments
  599.     if    Length(arg) = 2  then
  600.         R := DefaultRing( arg[1], arg[2] );
  601.         r := arg[1];
  602.         s := arg[2];
  603.     elif  Length(arg) = 3  then
  604.         R := arg[1];
  605.         if not IsRing( R )  then
  606.             Error("<R> must be a ring");
  607.         fi;
  608.         r := arg[2];
  609.         if not r in R  then
  610.             Error("<r> must be an element of <R>");
  611.         fi;
  612.         s := arg[3];
  613.         if not s in R  then
  614.             Error("<s> must be an element of <R>");
  615.         fi;
  616.     else
  617.         Error("usage: IsAssociated( [<R>,] <r>, <s> )");
  618.     fi;
  619.  
  620.     # return the result of the test
  621.     return R.operations.IsAssociated( R, r, s );
  622. end;
  623.  
  624. RingOps.IsAssociated := function ( R, r, s )
  625.     local   isAss, q;
  626.  
  627.     # if a list of the units is already known, use it
  628.     if IsBound( R.units )  then
  629.         isAss := r in R.units * s;
  630.  
  631.     # or check if the quotient is a unit
  632.     else
  633.         if s = R.zero  then
  634.             isAss := r = R.zero;
  635.         else
  636.             q := R.operations.Quotient( R, r, s );
  637.             isAss := q <> false  and R.operations.IsUnit( R, q );
  638.         fi;
  639.     fi;
  640.  
  641.     # return the result
  642.     return isAss;
  643. end;
  644.  
  645.  
  646. #############################################################################
  647. ##
  648. #F  StandardAssociate( [<R>,] <r> ) . .  standard associate of a ring element
  649. ##
  650. StandardAssociate := function ( arg )
  651.     local   R, r;
  652.  
  653.     # get and check the arguments
  654.     if   Length(arg) = 1  then
  655.         R := DefaultRing( arg[1] );
  656.         r := arg[1];
  657.     elif Length(arg) = 2  then
  658.         R := arg[1];
  659.         if not IsRing( R )  then
  660.             Error("<R> must be a ring");
  661.         fi;
  662.         r := arg[2];
  663.         if not r in R  then
  664.             Error("<r> must be an element of <R>");
  665.         fi;
  666.     else
  667.         Error("usage: StandardAssociate( [<R>,] <r> )");
  668.     fi;
  669.  
  670.     # return the standard associate
  671.     return R.operations.StandardAssociate( R, r );
  672. end;
  673.  
  674. RingOps.StandardAssociate := function ( R, r )
  675.     Error("sorry, can not compute the standard associate of <r> in <R>");
  676. end;
  677.  
  678.  
  679. #############################################################################
  680. ##
  681. #F  Associates( [<R>,] <r> )  . . . . . . . . .  associates of a ring element
  682. ##
  683. Associates := function ( arg )
  684.     local   R, r;
  685.  
  686.     # get and check the arguments
  687.     if   Length(arg) = 1  then
  688.         R := DefaultRing( arg[1] );
  689.         r := arg[1];
  690.     elif Length(arg) = 2  then
  691.         R := arg[1];
  692.         if not IsRing( R )  then
  693.             Error("<R> must be a ring");
  694.         fi;
  695.         r := arg[2];
  696.         if not r in R  then
  697.             Error("<r> must be an element of <R>");
  698.         fi;
  699.     else
  700.         Error("usage: Associates( [<R>,] <r> )");
  701.     fi;
  702.  
  703.     # compute the associates of <r>
  704.     return R.operations.Associates( R, r );
  705. end;
  706.  
  707. RingOps.Associates := function ( R, r )
  708.     return Set( Elements( Units( R ) ) * r );
  709. end;
  710.  
  711.  
  712. #############################################################################
  713. ##
  714. #F  IsIrreducible( [<R>,] <r> )  . . .  test if a ring element is irreducible
  715. ##
  716. IsIrreducible := function ( arg )
  717.     local   R, r;
  718.  
  719.     # get and check the arguments
  720.     if    Length(arg) = 1  then
  721.         R := DefaultRing( arg[1] );
  722.         r := arg[1];
  723.     elif  Length(arg) = 2  then
  724.         R := arg[1];
  725.         if not IsRing( R )  then
  726.             Error("<R> must be a ring");
  727.         fi;
  728.         r := arg[2];
  729.         if not r in R  then
  730.             Error("<r> must be an element of <R>");
  731.         fi;
  732.     else
  733.         Error("usage: IsIrreducible( [<R>,] <r> )");
  734.     fi;
  735.  
  736.     # permform the test
  737.     return R.operations.IsIrreducible( R, r );
  738. end;
  739.  
  740. RingOps.IsIrreducible := function ( R, r )
  741.     Error("sorry, can not test if <r> is irreducible in the ring <R>");
  742. end;
  743.  
  744.  
  745. #############################################################################
  746. ##
  747. #F  IsPrime( [<R>,] <r> ) . . . . . . . . . test if a ring element is a prime
  748. ##
  749. ##  every prime is irreducible
  750. ##
  751. IsPrime := function ( arg )
  752.     local   R, r;
  753.  
  754.     # get and check the arguments
  755.     if    Length(arg) = 1  then
  756.         R := DefaultRing( arg[1] );
  757.         r := arg[1];
  758.     elif  Length(arg) = 2  then
  759.         R := arg[1];
  760.         if not IsRing( R )  then
  761.             Error("<R> must be a ring");
  762.         fi;
  763.         r := arg[2];
  764.         if not r in R  then
  765.             Error("<r> must be an element of <R>");
  766.         fi;
  767.     else
  768.         Error("usage: IsPrime( [<R>,] <r> )");
  769.     fi;
  770.  
  771.     # perform the test
  772.     return R.operations.IsPrime( R, r );
  773. end;
  774.  
  775. RingOps.IsPrime := function ( R, r )
  776.     Error("sorry, can not test if <r> is prime in the ring <R>");
  777. end;
  778.  
  779.  
  780. #############################################################################
  781. ##
  782. #F  Factors( [<R>,] <r> ) . . . . . . . . . . factorization of a ring element
  783. ##
  784. Factors := function ( arg )
  785.     local   R, r;
  786.  
  787.     # get and check the arguments
  788.     if   Length(arg) = 1  then
  789.         r := arg[1];
  790.         R := DefaultRing( r );
  791.         if not IsRing( R )  then
  792.             Error("<R> must be a ring");
  793.         fi;
  794.     elif Length(arg) = 2  then
  795.         R := arg[1];
  796.         if not IsRing( R )  then
  797.             Error("<R> must be a ring");
  798.         fi;
  799.         r := arg[2];
  800.         if not r in R  then
  801.             Error("<r> must be an element of <R>");
  802.         fi;
  803.     else
  804.         Error("usage: Factors( [<R>,] <r> )");
  805.     fi;
  806.  
  807.     # factor the number
  808.     return R.operations.Factors( R, r );
  809. end;
  810.  
  811. RingOps.Factors := function ( R, r )
  812.     Error("sorry, can not factor <r> in the ring <R>");
  813. end;
  814.  
  815.  
  816. #############################################################################
  817. ##
  818. #F  EuclideanDegree( [<R>,] <r> )  . . . . euclidean degree of a ring element
  819. ##
  820. EuclideanDegree := function ( arg )
  821.     local   R, r;
  822.  
  823.     # get and check the arguments
  824.     if   Length(arg) = 1  then
  825.         r := arg[1];
  826.         R := DefaultRing( r );
  827.         if IsEuclideanRing( R ) <> true  then
  828.             Error("<R> must be a Euclidean ring");
  829.         fi;
  830.     elif Length(arg) = 2  then
  831.         R := arg[1];
  832.         if IsEuclideanRing( R ) <> true  then
  833.             Error("<R> must be a Euclidean ring");
  834.         fi;
  835.         r := arg[2];
  836.         if not r in R  then
  837.             Error("<r> must be an element of <R>");
  838.         fi;
  839.     else
  840.         Error("usage: EuclideanDegree( [<R>,] <r> )");
  841.     fi;
  842.  
  843.     # compute the Euclidean degree
  844.     return R.operations.EuclideanDegree( R, r );
  845. end;
  846.  
  847. RingOps.EuclideanDegree := function ( R, r )
  848.     Error("sorry, can not compute the Euclidean degree of <r> in <R>");
  849. end;
  850.  
  851.  
  852. #############################################################################
  853. ##
  854. #F  Mod( [<R>,], <r>, <m> ) . . . . .  remainder of a ring element by another
  855. ##
  856. Mod := function ( arg )
  857.     local   R, r, m;
  858.  
  859.     # get and check the arguments
  860.     if   Length(arg) = 2  then
  861.         R := DefaultRing( arg[1], arg[2] );
  862.         if not IsEuclideanRing( R )  then
  863.             Error("<R> must be a Euclidean ring");
  864.         fi;
  865.         r := arg[1];
  866.         m := arg[2];
  867.     elif Length(arg) = 3  then
  868.         R := arg[1];
  869.         if not IsEuclideanRing( R )  then
  870.             Error("<R> must be a Euclidean ring");
  871.         fi;
  872.         r := arg[2];
  873.         if not r in R  then
  874.             Error("<r> must be an element of <R>");
  875.         fi;
  876.         m := arg[3];
  877.         if not m in R  then
  878.             Error("<m> must be an element of <R>");
  879.         fi;
  880.     else
  881.         Error("usage: Mod( [<R>,] <r>, <m> )");
  882.     fi;
  883.  
  884.     # compute the remainder
  885.     return R.operations.Mod( R, r, m );
  886. end;
  887.  
  888. RingOps.Mod := function ( R, r, m )
  889.     Error("sorry, can not compute the remainder of <r> by <m> in <R>");
  890. end;
  891.  
  892.  
  893. #############################################################################
  894. ##
  895. #F  QuotientMod( [<R>,] <r>, <s>, <m> ) . . . . quotient of two ring elements
  896. #F                                                             modulo another
  897. ##
  898. QuotientMod := function ( arg )
  899.     local   R, r, s, m;
  900.  
  901.     # get and check the arguments
  902.     if   Length(arg) = 3  then
  903.         R := DefaultRing( arg[1], arg[2], arg[3] );
  904.         if not IsEuclideanRing( R )  then
  905.             Error("<R> must be a Euclidean ring");
  906.         fi;
  907.         r := arg[1];
  908.         s := arg[2];
  909.         m := arg[3];
  910.     elif Length(arg) = 4  then
  911.         R := arg[1];
  912.         if not IsEuclideanRing( R )  then
  913.             Error("<R> must be a Euclidean ring");
  914.         fi;
  915.         r := arg[2];
  916.         if not r in R  then
  917.             Error("<r> must be an element of <R>");
  918.         fi;
  919.         s := arg[3];
  920.         if not s in R  then
  921.             Error("<s> must be an element of <R>");
  922.         fi;
  923.         m := arg[4];
  924.         if not m in R  then
  925.             Error("<m> must be an element of <R>");
  926.         fi;
  927.     else
  928.         Error("usage: QuotientMod( [<R>,] <r>, <s>, <m> )");
  929.     fi;
  930.  
  931.     # compute the quotient
  932.     return R.operations.QuotientMod( R, r, s, m );
  933. end;
  934.  
  935. RingOps.QuotientMod := function ( R, r, s, m )
  936.     local  f, g, h, fs, gs, hs, q;
  937.     f := s;  fs := 1;
  938.     g := m;  gs := 0;
  939.     while g <> R.zero  do
  940.         q := R.operations.Quotient( R, f - R.operations.Mod( R, f, g ), g );
  941.         h := g;          hs := gs;
  942.         g := f - q * g;  gs := fs - q * gs;
  943.         f := h;          fs := hs;
  944.     od;
  945.     q := R.operations.Quotient( R, r, f );
  946.     if q = false  then
  947.         return false;
  948.     else
  949.         return R.operations.Mod( R, fs * q, m );
  950.     fi;
  951. end;
  952.  
  953.  
  954. #############################################################################
  955. ##
  956. #F  PowerMod( [<R>,] <r>, <e>, <m> )  . . power of a ring element mod another
  957. ##
  958. PowerMod := function ( arg )
  959.     local   R, r, e, m;
  960.  
  961.     # get and check the arguments
  962.     if   Length(arg) = 3  then
  963.         R := DefaultRing( arg[1], arg[3] );
  964.         if not IsEuclideanRing( R )  then
  965.             Error("<R> must be a Euclidean ring");
  966.         fi;
  967.         r := arg[1];
  968.         e := arg[2];
  969.         if not IsInt( e )  then
  970.             Error("<e> must be an integer");
  971.         fi;
  972.         m := arg[3];
  973.     elif Length(arg) = 4  then
  974.         R := arg[1];
  975.         if not IsEuclideanRing( R )  then
  976.             Error("<R> must be a Euclidean ring");
  977.         fi;
  978.         r := arg[2];
  979.         if not r in R  then
  980.             Error("<r> must be an element of <R>");
  981.         fi;
  982.         e := arg[3];
  983.         if not IsInt( e )  then
  984.             Error("<e> must be an integer");
  985.         fi;
  986.         m := arg[4];
  987.         if not m in R  then
  988.             Error("<m> must be an element of <R>");
  989.         fi;
  990.     else
  991.         Error("usage: PowerMod( [<R>,] <r>, <e>, <m> )");
  992.     fi;
  993.  
  994.     # compute the power
  995.     return R.operations.PowerMod( R, r, e, m );
  996. end;
  997.  
  998. RingOps.PowerMod := function ( R, r, e, m )
  999.     local   pow, f;
  1000.  
  1001.     # reduce r initially
  1002.     r := R.operations.Mod( R, r, m );
  1003.  
  1004.     # handle special case
  1005.     if e = 0  then
  1006.         return R.one;
  1007.     fi;
  1008.  
  1009.     # if e is negative then invert n modulo m with Euclids algorithm
  1010.     if e < 0  then
  1011.         r := R.operations.QuotientMod( R, R.one, r, m );
  1012.         if r = false  then
  1013.             Error("<r> must be invertable modulo <m>");
  1014.         fi;
  1015.         e := -e;
  1016.     fi;
  1017.  
  1018.     # now use the repeated squaring method (right-to-left)
  1019.     pow := R.one;
  1020.     f := 2 ^ (LogInt( e, 2 ) + 1);
  1021.     while 1 < f  do
  1022.         pow := R.operations.Mod( R, pow * pow, m );
  1023.         f := QuoInt( f, 2 );
  1024.         if f <= e  then
  1025.             pow := R.operations.Mod( R, pow * r, m );
  1026.             e := e - f;
  1027.         fi;
  1028.     od;
  1029.  
  1030.     # return the power
  1031.     return pow;
  1032. end;
  1033.  
  1034.  
  1035. #############################################################################
  1036. ##
  1037. #F  Gcd( [<R>,] <r1>, <r2>... ) . .  greatest common divisor of ring elements
  1038. ##
  1039. Gcd := function ( arg )
  1040.     local   R, ns, i, gcd;
  1041.  
  1042.     # get and check the arguments (what a pain)
  1043.     if   Length(arg) = 0  then
  1044.         Error("usage: Gcd( [<R>,] <r1>, <r2>... )");
  1045.     elif Length(arg) = 1  then
  1046.         ns := arg[1];
  1047.     elif Length(arg) = 2 and IsRing(arg[1])  then
  1048.         R := arg[1];
  1049.         ns := arg[2];
  1050.     elif  IsRing(arg[1])  then
  1051.         R := arg[1];
  1052.         ns := Sublist( arg, [2..Length(arg)] );        
  1053.     else
  1054.         R := DefaultRing( arg );
  1055.         ns := arg;
  1056.     fi;
  1057.     if not IsList( ns )  or Length(ns) = 0  then
  1058.         Error("usage: Gcd( [<R>,] <r1>, <r2>... )");
  1059.     fi;
  1060.     if not IsBound( R )  then
  1061.         R := DefaultRing( ns );
  1062.     else
  1063.         if not ForAll( ns, n -> n in R )  then
  1064.             Error("<r> must be an element of <R>");
  1065.         fi;
  1066.     fi;
  1067.     if not IsEuclideanRing( R )  then
  1068.         Error("<R> must be a Euclidean ring");
  1069.     fi;
  1070.  
  1071.     # compute the gcd by iterating
  1072.     gcd := ns[1];
  1073.     for i  in [2..Length(ns)]  do
  1074.         gcd := R.operations.Gcd( R, gcd, ns[i] );
  1075.     od;
  1076.  
  1077.     # return the gcd
  1078.     return gcd;
  1079. end;
  1080.  
  1081. RingOps.Gcd := function ( R, r, s )
  1082.     local   gcd, u, v, w;
  1083.  
  1084.     # perform a Euclidean algorithm
  1085.     u := r;
  1086.     v := s;
  1087.     while v <> R.zero  do
  1088.         w := v;
  1089.         v := R.operations.Mod( R, u, v );
  1090.         u := w;
  1091.     od;
  1092.     gcd := u;
  1093.  
  1094.     # norm the element
  1095.     gcd := R.operations.StandardAssociate( R, gcd );
  1096.  
  1097.     # return the gcd
  1098.     return gcd;
  1099. end;
  1100.  
  1101.  
  1102. #############################################################################
  1103. ##
  1104. #F  GcdRepresentation( [<R>,] <r>, <s> )  . . . . . representation of the gcd
  1105. ##
  1106. GcdRepresentation := function ( arg )
  1107.     local   R, ns, i, gcd, rep, tmp;
  1108.  
  1109.     # get and check the arguments (what a pain)
  1110.     if   Length(arg) = 0  then
  1111.         Error("usage: Gcd( [<R>,] <r1>, <r2>... )");
  1112.     elif Length(arg) = 1  then
  1113.         ns := arg[1];
  1114.     elif Length(arg) = 2 and IsRing(arg[1])  then
  1115.         R := arg[1];
  1116.         ns := arg[2];
  1117.     elif  IsRing(arg[1])  then
  1118.         R := arg[1];
  1119.         ns := Sublist( arg, [2..Length(arg)] );        
  1120.     else
  1121.         R := DefaultRing( arg );
  1122.         ns := arg;
  1123.     fi;
  1124.     if not IsList( ns )  or Length(ns) = 0  then
  1125.         Error("usage: GcdRepresentation( [<R>,] <r1>, <r2>... )");
  1126.     fi;
  1127.     if not IsBound( R )  then
  1128.         R := DefaultRing( ns );
  1129.     else
  1130.         if not ForAll( ns, n -> n in R )  then
  1131.             Error("<r> must be an element of <R>");
  1132.         fi;
  1133.     fi;
  1134.     if not IsEuclideanRing( R )  then
  1135.         Error("<R> must be a Euclidean ring");
  1136.     fi;
  1137.  
  1138.     # compute the gcd by iterating
  1139.     gcd := ns[1];
  1140.     rep := [ R.one ];
  1141.     for i  in [2..Length(ns)]  do
  1142.         tmp := R.operations.GcdRepresentation( R, gcd, ns[i] );
  1143.         gcd := tmp[1] * gcd + tmp[2] * ns[i];
  1144.         rep := List( rep, x -> x * tmp[1] );
  1145.         Add( rep, tmp[2] );
  1146.     od;
  1147.  
  1148.     # return the gcd representation
  1149.     return rep;
  1150. end;
  1151.  
  1152. RingOps.GcdRepresentation := function ( R, x, y )
  1153.     local  f, g, h, fx, gx, hx, q;
  1154.     f := x;  fx := R.one;
  1155.     g := y;  gx := R.zero;
  1156.     while g <> R.zero  do
  1157.         q := R.operations.Quotient( R, f - R.operations.Mod( R, f, g ), g );
  1158.         h := g;          hx := gx;
  1159.         g := f - q * g;  gx := fx - q * gx;
  1160.         f := h;          fx := hx;
  1161.     od;
  1162.     q := R.operations.Quotient(R, R.operations.StandardAssociate(R, f), f);
  1163.     if y = R.zero  then
  1164.         return [ q * fx, 0 ];
  1165.     else
  1166.         return [ q * fx, R.operations.Quotient( R, q * (f - fx * x), y ) ];
  1167.     fi;
  1168. end;
  1169.  
  1170.  
  1171. #############################################################################
  1172. ##
  1173. #F  Lcm( [<R>,] <r1>, <r2>,.. ) .  least common multiple of two ring elements
  1174. ##
  1175. Lcm := function ( arg )
  1176.     local   R, ns, n, gcd, lcm, i, h;
  1177.  
  1178.     # get and check the arguments (what a pain)
  1179.     if   Length(arg) = 0  then
  1180.         Error("usage: Lcm( [<R>,] <r1>, <r2>... )");
  1181.     elif Length(arg) = 1  then
  1182.         ns := arg[1];
  1183.     elif Length(arg) = 2 and IsRing(arg[1])  then
  1184.         R := arg[1];
  1185.         ns := arg[2];
  1186.     elif  IsRing(arg[1])  then
  1187.         R := arg[1];
  1188.         ns := Sublist( arg, [2..Length(arg)] );        
  1189.     else
  1190.         R := DefaultRing( arg );
  1191.         ns := arg;
  1192.     fi;
  1193.     if not IsList( ns )  or Length(ns) = 0  then
  1194.         Error("usage: Lcm( [<R>,] <r1>, <r2>... )");
  1195.     fi;
  1196.     if not IsBound( R )  then
  1197.         R := DefaultRing( ns );
  1198.     else
  1199.         if not ForAll( ns, n -> n in R )  then
  1200.             Error("<r> must be an element of <R>");
  1201.         fi;
  1202.     fi;
  1203.     if not IsEuclideanRing( R )  then
  1204.         Error("<R> must be a Euclidean ring");
  1205.     fi;
  1206.  
  1207.     # compute the least common multiple
  1208.     lcm := ns[1];
  1209.     for i  in [2..Length(ns)]  do
  1210.         lcm := R.operations.Lcm( R, lcm, ns[i] );
  1211.     od;
  1212.  
  1213.     # return the lcm
  1214.     return lcm;
  1215. end;
  1216.  
  1217. RingOps.Lcm := function ( R, r, s )
  1218.     local   lcm;
  1219.  
  1220.     # compute the least common multiple
  1221.     if r = R.zero  and s = R.zero  then
  1222.         lcm := R.zero;
  1223.     else
  1224.         lcm := R.operations.StandardAssociate( R,
  1225.                     R.operations.Quotient( R, r, R.operations.Gcd( R, r, s ) )
  1226.                     * s );
  1227.     fi;
  1228.  
  1229.     # return the lcm
  1230.     return lcm;
  1231. end;
  1232.  
  1233.  
  1234. #############################################################################
  1235. ##
  1236. #F  RingOps.AsGroup(<R>)  . . . . . . . view a ring as a multiplicative group
  1237. ##
  1238. RingOps.AsGroup := function ( R )
  1239.     Error("sorry, can not view the ring <R> as a group");
  1240. end;
  1241.  
  1242.  
  1243. #############################################################################
  1244. ##
  1245. #F  RingOps.AsAdditiveGroup(<R>)  . . . . .  view a ring as an additive group
  1246. ##
  1247. RingOps.AsAdditiveGroup := function ( R )
  1248.     Error("sorry, can not view the ring <R> as an additive group");
  1249. end;
  1250.  
  1251.  
  1252. #############################################################################
  1253. ##
  1254. #V  RingElements  . . . . . . . . . . . . . . . . domain of all Ring elements
  1255. #V  RingElementsOps . .  operations record of the domain of all ring elements
  1256. ##
  1257. ##  'RingElements' is  the domain of    all  ring elements,  i.e.,  integers,
  1258. ##  cyclotomic  integers, field  elements,  and records  that  implement ring
  1259. ##  elements.  Note that 'RingElements' is not a ring.
  1260. ##
  1261. ##  'RingElementsOps'  is   the  operations record   for  the  'RingElements'
  1262. ##  domain.  The  operations  record  of other ring  domains like  'Integers'
  1263. ##  inherit default methods from this record.
  1264. ##
  1265. ##  Those domains are  known  to 'Domain',   and they know  how to  create  a
  1266. ##  ring that contains a given list of elements.
  1267. ##
  1268. RingElementsOps         := Copy( DomainOps );
  1269.  
  1270. RingElementsOps.\in    := function ( z, RingElements )
  1271.     return IsInt( z )
  1272.         or IsCycInt( z )
  1273.         or IsRec( z )  and IsBound(z.isRingElement)  and z.isRingElement;
  1274. end;
  1275.  
  1276. RingElementsOps.Order   := function ( F, z )
  1277.     local   ord, elm;
  1278.     if z = F.zero  then
  1279.         ord := 0;
  1280.     else
  1281.         elm := z;
  1282.         ord := 1;
  1283.         while elm <> F.one  do
  1284.             elm := elm * z;
  1285.             ord := ord + 1;
  1286.         od;
  1287.     fi;
  1288.     return ord;
  1289. end;
  1290.  
  1291.  
  1292. RingElements            := rec();
  1293. RingElements.isDomain   := true;
  1294.  
  1295. RingElements.name       := "RingElements";
  1296.  
  1297. RingElements.isFinite   := false;
  1298. RingElements.size       := "infinity";
  1299.  
  1300. RingElements.operations := RingElementsOps;
  1301.  
  1302.  
  1303. #############################################################################
  1304. ##
  1305. #F  Ring(<z>,...) . . . . . . . . . . . .  ring containing a list of elements
  1306. ##
  1307. Ring := function ( arg )
  1308.     local   R,          # ring containing the elements of <arg>, result
  1309.             D;          # domain containing the elements of <arg>
  1310.  
  1311.     # if called with one domain argument look in the operations record
  1312.     if Length(arg) = 1  and IsDomain(arg[1])  then
  1313.         R := arg[1].operations.Ring( arg[1] );
  1314.  
  1315.     # special case for one square matrix
  1316.     elif    Length(arg) = 1
  1317.         and IsMat(arg[1])  and Length(arg[1]) = Length(arg[1][1])
  1318.     then
  1319.         D := Domain( arg );
  1320.         R := D.operations.Ring( arg );
  1321.  
  1322.     # special case for list of elements
  1323.     elif Length(arg) = 1  and IsList(arg[1])  then
  1324.         D := Domain( arg[1] );
  1325.         R := D.operations.Ring( arg[1] );
  1326.  
  1327.     # other cases
  1328.     else
  1329.         D := Domain( arg );
  1330.         R := D.operations.Ring( arg );
  1331.     fi;
  1332.  
  1333.     # return the ring
  1334.     return R;
  1335. end;
  1336.  
  1337. RingElementsOps.Ring := function ( arg )
  1338.     Error("sorry, there is no default way to construct a ring");
  1339. end;
  1340.  
  1341.  
  1342. #############################################################################
  1343. ##
  1344. #F  DefaultRing(<z>,...)  . . . .  default ring containing a list of elements
  1345. ##
  1346. DefaultRing := function ( arg )
  1347.     local   R,          # ring containing the elements of <arg>, result
  1348.             D;          # domain containing the elements of <arg>
  1349.  
  1350.     # special case for one square matrix
  1351.     if    Length(arg) = 1
  1352.         and IsMat(arg[1])  and Length(arg[1]) = Length(arg[1][1])
  1353.     then
  1354.         D := Domain( arg );
  1355.         R := D.operations.DefaultRing( arg );
  1356.  
  1357.     # special case for list of elements
  1358.     elif Length(arg) = 1  and IsList(arg[1])  then
  1359.         D := Domain( arg[1] );
  1360.         R := D.operations.DefaultRing( arg[1] );
  1361.  
  1362.     # other cases
  1363.     else
  1364.         D := Domain( arg );
  1365.         R := D.operations.DefaultRing( arg );
  1366.     fi;
  1367.  
  1368.     # return the default ring
  1369.     return R;
  1370. end;
  1371.  
  1372. RingElementsOps.DefaultRing := function ( arg )
  1373.     Error("sorry, there is no default way to construct a default ring");
  1374. end;
  1375.  
  1376.  
  1377. #############################################################################
  1378. ##
  1379. #F  AsRing(<D>) . . . . . . . . . . . . . . . . . . . view a domain to a ring
  1380. ##
  1381. AsRing := function ( D )
  1382.     if not IsBound( D.asRing )  then
  1383.         D.asRing := D.operations.AsRing( D );
  1384.     fi;
  1385.     return D.asRing;
  1386. end;
  1387.  
  1388. RingOps.AsRing := function ( R )
  1389.     return R;
  1390. end;
  1391.  
  1392.  
  1393. #############################################################################
  1394. ##
  1395. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  1396. ##
  1397. ##  Local Variables:
  1398. ##  mode:               outline
  1399. ##  outline-regexp:     "#F\\|#V\\|#E"
  1400. ##  fill-column:        73
  1401. ##  fill-prefix:        "##  "
  1402. ##  eval:               (hide-body)
  1403. ##  End:
  1404. ##
  1405.  
  1406.  
  1407.  
  1408.