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

  1. #############################################################################
  2. ##
  3. #A  polynom.g                   GAP library                      Frank Celler
  4. ##
  5. #A  @(#)$Id: polynom.g,v 3.23 1993/02/11 16:47:56 fceller Rel $
  6. ##
  7. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  8. ##
  9. ##  This file  contains those functions that  are  dispatchers for polynomial
  10. ##  functions  and  the  polynomial   arithmetic.    The  idea  to  represent
  11. ##  polynomials as records containing '.baseRing'  and '.coefficients' is due
  12. ##  to S.Linton.
  13. ##
  14. #H  $Log: polynom.g,v $
  15. #H  Revision 3.23  1993/02/11  16:47:56  fceller
  16. #H  added <list> + <polynomial>
  17. #H
  18. #H  Revision 3.22  1993/02/08  11:56:05  fceller
  19. #H  ground ring is now stored in polynomial record
  20. #H
  21. #H  Revision 3.21  1993/02/04  13:47:12  fceller
  22. #H  added '/' and 'EuclideanQuotient'
  23. #H
  24. #H  Revision 3.20  1993/02/03  12:36:06  fceller
  25. #H  fixed undeclared local variables
  26. #H
  27. #H  Revision 3.19  1993/01/25  13:18:26  fceller
  28. #H  fixed '=' and '<' to handle iterated polynomials
  29. #H
  30. #H  Revision 3.18  1993/01/20  11:09:02  fceller
  31. #H  changed 'DisplayPolynomial' again (in order to display
  32. #H  polynomials over the cyclotmics)
  33. #H
  34. #H  Revision 3.17  1993/01/06  15:44:35  fceller
  35. #H  changed 'LeadingCoefficient' to handle the trivial polynomial
  36. #H
  37. #H  Revision 3.16  1993/01/04  11:18:50  fceller
  38. #H  added 'LeadingCoefficient'
  39. #H
  40. #H  Revision 3.15  1992/12/16  19:47:27  martin
  41. #H  replaced quoted record names with escaped ones
  42. #H
  43. #H  Revision 3.14  1992/12/07  07:41:08  fceller
  44. #H  fixed 'Quotient( 0, f )'
  45. #H
  46. #H  Revision 3.13  92/11/25  12:34:28  fceller
  47. #H  added 'Degree'
  48. #H  
  49. #H  Revision 3.12  1992/11/19  14:12:23  fceller
  50. #H  changed 'DisplayPolynomial'
  51. #H
  52. #H  Revision 3.11  92/11/16  12:23:24  fceller
  53. #H  added Laurent polynomials
  54. #H  
  55. #H  Revision 3.10  1992/08/13  13:11:09  fceller
  56. #H  added 'Indeterminate'
  57. #H
  58. #H  Revision 3.9  1992/07/24  07:08:07  fceller
  59. #H  improved '*' to allow <nullpoly> * <int>
  60. #H
  61. #H  Revision 3.8  1992/07/23  09:04:18  fceller
  62. #H  improved '*' to allow <int> * <polynomial>
  63. #H
  64. #H  Revision 3.7  1992/06/17  07:06:04  fceller
  65. #H  moved '<somedomain>.operations.Polynomial' function to "<somedomain>.g"
  66. #H
  67. #H  Revision 3.6  1992/06/05  09:58:04  fceller
  68. #H  improved 'Derivative'
  69. #H
  70. #H  Revision 3.5  1992/06/01  07:33:55  fceller
  71. #H  added 'Value'
  72. #H
  73. #H  Revision 3.4  1992/05/25  09:10:05  fceller
  74. #H  added 'EmbeddedPolynomial', fixed a bug
  75. #H
  76. #H  Revision 3.3  1992/05/07  10:29:16  fceller
  77. #H  added 'CompanionMatrix', better pretty printing in 'DisplayPolynomial'
  78. #H
  79. #H  Revision 3.2  1992/04/21  10:37:47  fceller
  80. #H  Initial GAP 3.2 release
  81. ##
  82.  
  83.  
  84. #############################################################################
  85. ##
  86. #F  InfoPoly1(...)  . . . . . . . . . . . infomation function for polynomials
  87. #F  InfoPoly2(...)  . . . . . . . . . . . . .  debug function for polynomials
  88. ##
  89. if not IsBound(InfoPoly1)    then InfoPoly1   := Ignore;  fi;
  90. if not IsBound(InfoPoly2)    then InfoPoly2   := Ignore;  fi;
  91.  
  92.  
  93. #############################################################################
  94. ##
  95.  
  96. #F  Polynomial( <R>, <coeffs>, <val> )  . . . . . . . . . polynomial over <R>
  97. ##
  98. Polynomial := function( arg )
  99.     local   R,  coeffs,  val;
  100.  
  101.     # check the argument list
  102.     if 2 = Length(arg)  then
  103.         R := arg[1];
  104.         coeffs := arg[2];
  105.         val := 0;
  106.     elif 3 = Length(arg)  then
  107.         R := arg[1];
  108.         coeffs := arg[2];
  109.         val := arg[3];
  110.     else
  111.         Error( "usage: Polynomial( <R>, <coeffs>, <val> )",
  112.                "or Polynomial( <R>, <coeffs> )" );
  113.     fi;
  114.  
  115.     # <R> must be a ring with one or a field
  116.     if not IsField(R) and not IsRing(R)  then
  117.         Error("<R> must be a field or ring");
  118.     elif IsRing(R) and not IsBound(R.one)  then
  119.         Error("<R> must be a ring with one");
  120.     fi;
  121.  
  122.     # construct the polynomial
  123.     return R.operations.Polynomial( R, coeffs, val );
  124.  
  125. end;
  126.  
  127.  
  128. #############################################################################
  129. ##
  130. #F  IsPolynomial( <obj> ) . . . . . . . . . . . . . . . is <obj> a polynomial
  131. ##
  132. IsPolynomial := function( obj )
  133.     return IsRec(obj) and IsBound(obj.isPolynomial) and obj.isPolynomial;
  134. end;
  135.  
  136.  
  137. #############################################################################
  138. ##
  139. #F  CompanionMatrix( <R>, <f> ) . . . . . . . . . . . . . .  companion matrix
  140. ##
  141. CompanionMatrix := function( R, f )
  142.  
  143.     # check <R> and <f>
  144.     if not IsPolynomial( f )  then
  145.         Error( "<f> must be a polynomial" );
  146.     elif f.valuation < 0  then
  147.         Error( "<f> must not be a Laurent polynomial" );
  148.     fi;
  149.  
  150.     # check that the coefficients of <f> are in the base ring of <R>
  151.     if not ForAll( f.coefficients, x -> x in R.baseRing )  then
  152.         Error( "cannot write <f> over <R>.baseRing" );
  153.     fi;
  154.  
  155.     # return the companion matrix of <f>
  156.     return R.operations.CompanionMatrix( R, f );
  157.  
  158. end;
  159.  
  160.  
  161. #############################################################################
  162. ##
  163. #F  EmbeddedPolynomial( <R>, <f> )  . . . . . . . embed polynomial <f> in <R>
  164. ##
  165. EmbeddedPolynomial := function( R, f )
  166.  
  167.     # check <R> and <f>
  168.     if not IsPolynomial( f )  then
  169.         Error( "<f> must be a polynomial" );
  170.     fi;
  171.  
  172.     # check that the coefficients of <f> are in the base ring of <R>
  173.     if not ForAll( f.coefficients, x -> x in R.baseRing )  then
  174.         Error( "cannot write <f> over <R>.baseRing" );
  175.     fi;
  176.  
  177.     # convert
  178.     return R.operations.EmbeddedPolynomial( R, f );
  179.  
  180. end;
  181.  
  182.  
  183. #############################################################################
  184. ##
  185. #F  RandomPol( <R>, <deg> ) . . . . . . . . . . . . . . . . random polynomial
  186. ##
  187. ##  'RandomPol' returns a  random polynomial of  degree less than or equal to
  188. ##  <deg>,  which must be a nonnegativ integer,  whose coefficients come from
  189. ##  a ring <R>.
  190. ##
  191. RandomPol := function ( R, deg )
  192.     local  rand,  i;
  193.  
  194.     rand := [];
  195.     for i  in [ 1 .. deg+1 ]  do
  196.         rand[i] := Random( R );
  197.     od;
  198.     return Polynomial( R, rand );
  199.  
  200. end;
  201.  
  202.  
  203. #############################################################################
  204. ##
  205. #F  Value( <f>, <x> ) . . . . . . . . . . . . . . . . . . . . return <f>(<x>)
  206. ##
  207. Value := function( f, x )
  208.     return f.operations.Value( f, x );
  209. end;
  210.  
  211.  
  212. #############################################################################
  213. ##
  214. #F  Indeterminate( <R> )  . . . . . . . . . . . . . . indeterminate of a ring
  215. ##
  216. Indeterminate := function( R )
  217.     if not IsBound( R.indeterminate )  then
  218.         R.indeterminate := R.operations.Indeterminate( R );
  219.     fi;
  220.     return R.indeterminate;
  221. end;
  222.  
  223. X := Indeterminate;
  224.  
  225.  
  226. #############################################################################
  227. ##
  228.  
  229. #F  LaurentPolynomialRing( <R> )  . . . .  full Laurent polynom ring over <R>
  230. ##
  231. LaurentPolynomialRing := function( R )
  232.     local   i,  B;
  233.  
  234.     # <R> must be a ring with one
  235.     if not IsRing(R) and not IsField(R)  then
  236.         Error( "<R> must be a ring or field" );
  237.     elif IsRing(R) and not IsBound(R.one)  then
  238.         Error( "<R> must be a ring with one" );
  239.     fi;
  240.  
  241.     # check if the polynom ring is already known
  242.     if not IsBound(R.laurentPolynomialRing)  then
  243.         R.laurentPolynomialRing := R.operations.LaurentPolynomialRing(R);
  244.         if IsBound(R.laurentPolynomialRing.generators)  then
  245.             B := R.laurentPolynomialRing.generators;
  246.             for i  in [ 1 .. Length(B) ]  do
  247.                 R.laurentPolynomialRing.(i) := B[i];
  248.             od;
  249.         fi;
  250.     fi;
  251.     return R.laurentPolynomialRing;
  252.  
  253. end;
  254.  
  255.  
  256. #############################################################################
  257. ##
  258. #F  IsLaurentPolynomialRing( <obj> )  . . . . . is <R> a Laurent polynom ring
  259. ##
  260. IsLaurentPolynomialRing := function( obj )
  261.     return     IsRec(obj)
  262.            and IsBound(obj.isLaurentPolynomialRing)
  263.            and obj.isLaurentPolynomialRing;
  264. end;
  265.  
  266.  
  267. #############################################################################
  268. ##
  269. #V  LaurentPolynomialRingOps  . . . . . . . . . full Laurent polynom ring ops
  270. ##
  271. LaurentPolynomialRingOps := Copy( RingOps );
  272. LaurentPolynomialRingOps.name := "LaurentPolynomialRingOps";
  273.  
  274.  
  275. #############################################################################
  276. ##
  277. #F  LaurentPolynomialRingOps.\in . . . . . . . . . . . . . . membership test
  278. ##
  279. LaurentPolynomialRingOps.\in := function( p, P )
  280.     return     IsRec( p )
  281.            and IsBound( p.isPolynomial )
  282.            and p.isPolynomial
  283.            and p.baseRing = P.baseRing;
  284. end;
  285.  
  286.  
  287. #############################################################################
  288. ##
  289. #F  LaurentPolynomialRingOps.Factors( <R>, <f> )  . . . . . .  factors of <f>
  290. ##
  291. LaurentPolynomialRingOps.Factors := function( R, f )
  292.     local   g,  r;
  293.  
  294.     # factorize the standard associate of <f>
  295.     g := StandardAssociate( R, f );
  296.     r := Factors( PolynomialRing(R.baseRing), g );
  297.     if 0 < Length(r)  then
  298.     r[1] := Quotient(R,f,g) * r[1];
  299.     fi;
  300.     return r;
  301.  
  302. end;
  303.  
  304.  
  305. #############################################################################
  306. ##
  307. #F  LaurentPolynomialRingOps.Quotient( <R>, <l>, <r> )  . . . . . . <l> / <r>
  308. ##
  309. LaurentPolynomialRingOps.Quotient := function ( R, f, g )
  310.     local   m,  n,  i,  k,  c,  q,  R,  val;
  311.  
  312.     # get the base ring
  313.     R := R.baseRing;
  314.  
  315.     # if <f> is zero return it
  316.     if 0 = Length(f.coefficients)  then
  317.     return f;
  318.     fi;
  319.  
  320.     # get the value of the valuation of <f> / <g>
  321.     val := f.valuation - g.valuation;
  322.  
  323.     # Try to divide <f> by <g>
  324.     q := [];
  325.     n := Length( g.coefficients );
  326.     m := Length( f.coefficients ) - n;
  327.     f := ShallowCopy( f.coefficients );
  328.     if IsField(R)  then
  329.         for i  in [0 .. m ]  do
  330.             c := f[m-i+n] / g.coefficients[n];
  331.             for k  in [ 1 .. n ]  do
  332.                 f[m-i+k] := f[m-i+k] - c * g.coefficients[k];
  333.             od;
  334.             q[m-i+1] := c;
  335.         od;
  336.     else
  337.         for i  in [0 .. m ]  do
  338.             c := Quotient( R, f[m-i+n], g.coefficients[n] );
  339.             if c = false  then return false;  fi;
  340.             for k  in [ 1 .. n ]  do
  341.                 f[m-i+k] := f[m-i+k] - c * g.coefficients[k];
  342.             od;
  343.             q[m-i+1] := c;
  344.         od;
  345.     fi;
  346.  
  347.     # Did the division work?
  348.     for i  in [ 1 .. m+n ]  do
  349.         if f[i] <> R.zero  then
  350.             return false;
  351.         fi;
  352.     od;
  353.     return Polynomial( R, q, val );
  354.  
  355. end;
  356.  
  357.  
  358. #############################################################################
  359. ##
  360. #F  LaurentPolynomialRingOps.Derivative( <R>, <f> ) . . . . . . .  derivative
  361. ##
  362. Derivative := function( arg )
  363.     local   R,  f;
  364.  
  365.     if Length(arg) = 2  then
  366.         R := arg[1];
  367.         f := arg[2];
  368.     else
  369.         f := arg[1];
  370.         R := DefaultRing(f);
  371.     fi;
  372.     return R.operations.Derivative( R, f );
  373.  
  374. end;
  375.  
  376. LaurentPolynomialRingOps.Derivative := function( R, f )
  377.     local  d,  i;
  378.  
  379.     d := [];
  380.     for i  in [ 1 .. Length(f.coefficients) ]  do
  381.         d[i] := (i+f.valuation-1) * f.coefficients[i];
  382.     od;
  383.     return Polynomial( R.baseRing, d, f.valuation-1 );
  384.  
  385. end;
  386.  
  387.  
  388. #############################################################################
  389. ##
  390. #F  LaurentPolynomialRingOps.EuclideanDegree( <R>, <f> )  . . . degree of <f>
  391. ##
  392. LaurentPolynomialRingOps.EuclideanDegree := function( R, f )
  393.     return Length(f.coefficients)-1;
  394. end;
  395.  
  396.  
  397. #############################################################################
  398. ##
  399. #F  LaurentPolynomialRingOps.StandardAssociate( <R>, <f> ) standard associate
  400. ##
  401. LaurentPolynomialRingOps.StandardAssociate := function( R, f )
  402.     local   l,  a;
  403.  
  404.     # <f> should be nontrivial
  405.     if 0 < Length(f.coefficients)  then
  406.  
  407.         # get standard associate of leading term
  408.         l := f.coefficients[Length(f.coefficients)];
  409.         a := Quotient( R.baseRing, StandardAssociate( R.baseRing, l ), l );
  410.         f := Polynomial(R.baseRing,List(f.coefficients,x->a*x),0);
  411.         f.valuation := 0;
  412.     fi;
  413.     return f;
  414.  
  415. end;
  416.  
  417.  
  418. #############################################################################
  419. ##
  420. #F  LaurentPolynomialRingOps.EmbeddedPolynomial( <R>, <f> )  embed polynomial
  421. ##
  422. LaurentPolynomialRingOps.EmbeddedPolynomial := function( R, f )
  423.     return Polynomial( R.baseRing, f.coefficients, f.valuation );
  424. end;
  425.  
  426.  
  427. #############################################################################
  428. ##
  429. #F  LaurentPolynomialRingOps.Print( <P> ) . . . . . . . . . . pretty printing
  430. ##
  431. LaurentPolynomialRingOps.Print := function( P )
  432.     if IsBound( P.name )  then
  433.         Print( P.name );
  434.     else
  435.         Print( "LaurentPolynomialRing( ", P.baseRing, " )" );
  436.     fi;
  437. end;
  438.  
  439.  
  440. #############################################################################
  441. ##
  442.  
  443. #F  PolynomialRing( <R> ) . . . . . . . . . . . .  full polynom ring over <R>
  444. ##
  445. PolynomialRing := function( R )
  446.     local   i;
  447.  
  448.     # <R> must be a ring with one
  449.     if not IsRing(R) and not IsField(R)  then
  450.         Error( "<R> must be a ring or field" );
  451.     elif IsRing(R) and not IsBound(R.one)  then
  452.         Error( "<R> must be a ring with one" );
  453.     fi;
  454.  
  455.     # check if the polynom ring is already known
  456.     if not IsBound(R.polynomialRing)  then
  457.         R.polynomialRing := R.operations.PolynomialRing(R);
  458.         if IsBound(R.polynomialRing.generators)  then
  459.             for i  in [ 1 .. Length(R.polynomialRing.generators) ]  do
  460.                 R.polynomialRing.(i) := R.polynomialRing.generators[i];
  461.             od;
  462.         fi;
  463.     fi;
  464.     return R.polynomialRing;
  465.  
  466. end;
  467.  
  468.  
  469. #############################################################################
  470. ##
  471. #F  IsPolynomialRing( <obj> ) . . . . . . . . . . . . . is <R> a polynom ring
  472. ##
  473. IsPolynomialRing := function( obj )
  474.     return     IsRec(obj)
  475.            and IsBound(obj.isPolynomialRing)
  476.            and obj.isPolynomialRing;
  477. end;
  478.  
  479.  
  480. #############################################################################
  481. ##
  482. #V  PolynomialRingOps . . . . . . . . . . . . . . . . . full polynom ring ops
  483. ##
  484. PolynomialRingOps := Copy( RingOps );
  485. PolynomialRingOps.name := "PolynomialRingOps";
  486.  
  487.  
  488. #############################################################################
  489. ##
  490. #F  PolynomialRingOps.\in  . . . . . . membership test for full polynom ring
  491. ##
  492. PolynomialRingOps.\in := function( p, P )
  493.     return     IsRec( p )
  494.            and IsBound( p.isPolynomial )
  495.            and p.isPolynomial
  496.            and 0 <= p.valuation
  497.            and p.baseRing = P.baseRing;
  498. end;
  499.  
  500.  
  501. #############################################################################
  502. ##
  503. #F  PolynomialRingOps.Quotient( <R>, <f>, <g> ) . . . . . . . . . . <l> / <r>
  504. ##
  505. PolynomialRingOps.Quotient := function ( R, f, g )
  506.     local   m,  n,  i,  k,  c,  q,  R,  val;
  507.  
  508.     # <f> and <g> must have the same field
  509.     if f.baseRing <> g.baseRing  then
  510.         Error( "<f> and <g> must have the same base ring" );
  511.     fi;
  512.     R := f.baseRing;
  513.  
  514.     # if <f> is zero return it
  515.     if 0 = Length(f.coefficients)  then
  516.     return f;
  517.     fi;
  518.  
  519.     # check the value of the valuation of <f> and <g>
  520.     if f.valuation < g.valuation  then
  521.         return false;
  522.     fi;
  523.     val := f.valuation - g.valuation;
  524.  
  525.     # Try to divide <f> by <g>
  526.     q := [];
  527.     n := Length( g.coefficients );
  528.     m := Length( f.coefficients ) - n;
  529.     f := ShallowCopy( f.coefficients );
  530.     if IsField(R)  then
  531.         for i  in [0 .. m ]  do
  532.             c := f[m-i+n] / g.coefficients[n];
  533.             for k  in [ 1 .. n ]  do
  534.                 f[m-i+k] := f[m-i+k] - c * g.coefficients[k];
  535.             od;
  536.             q[m-i+1] := c;
  537.         od;
  538.     else
  539.         for i  in [0 .. m ]  do
  540.             c := Quotient( R, f[m-i+n], g.coefficients[n] );
  541.             if c = false  then return false;  fi;
  542.             for k  in [ 1 .. n ]  do
  543.                 f[m-i+k] := f[m-i+k] - c * g.coefficients[k];
  544.             od;
  545.             q[m-i+1] := c;
  546.         od;
  547.     fi;
  548.  
  549.     # Did the division work?
  550.     for i  in [ 1 .. m+n ]  do
  551.         if f[i] <> R.zero  then
  552.             return false;
  553.         fi;
  554.     od;
  555.     return Polynomial( R, q, val );
  556.  
  557. end;
  558.  
  559.  
  560. #############################################################################
  561. ##
  562. #F  PolynomialRingOps.Derivative( <R>, <f> )  . .  derivative of a polynomial
  563. ##
  564. PolynomialRingOps.Derivative := function( R, f )
  565.     local  d,  i;
  566.  
  567.     if f.valuation+Length(f.coefficients) < 2  then
  568.         return R.zero;
  569.     else
  570.         d := [];
  571.         for i  in [ 1 .. Length(f.coefficients) ]  do
  572.             d[i] := (i+f.valuation-1) * f.coefficients[i];
  573.         od;
  574.         return Polynomial( R.baseRing, d, f.valuation-1 );
  575.     fi;
  576.  
  577. end;
  578.  
  579.  
  580. #############################################################################
  581. ##
  582. #F  PolynomialRingOps.EuclideanDegree( <R>, <f> ) . . . . . . . degree of <f>
  583. ##
  584. PolynomialRingOps.EuclideanDegree := function( R, f )
  585.     return ( Length(f.coefficients)-1 ) + f.valuation;
  586. end;
  587.  
  588.  
  589. #############################################################################
  590. ##
  591. #F  PolynomialRingOps.CompanionMatrix( <R>, <f> ) . . companion matrix of <f>
  592. ##
  593. ##  Returns the companion matrix A of <f>.  If <f> has leading coefficient 1
  594. ##  the companion matrix has characteristic polynomial <f>.
  595. ##
  596. PolynomialRingOps.CompanionMatrix := function( R, f )
  597.     local   d,  C,  i;
  598.  
  599.     d := (Length(f.coefficients)-1) + f.valuation;
  600.     C := NullMat( d, d, R.baseRing.zero );
  601.     for i  in [ 1 .. d-1 ]  do
  602.         C[i][i+1] := R.baseRing.one;
  603.     od;
  604.     for i  in [ f.valuation+1 .. d ]  do
  605.         C[d][i] := -f.coefficients[i];
  606.     od;
  607.     return C;
  608.  
  609. end;
  610.  
  611.  
  612. #############################################################################
  613. ##
  614. #F  PolynomialRingOps.StandardAssociate( <R>, <f> ) standard associate of <f>
  615. ##
  616. PolynomialRingOps.StandardAssociate := function( R, f )
  617.     local   l,  a;
  618.  
  619.     # <f> should be nontrivial
  620.     if 0 < Length(f.coefficients)  then
  621.  
  622.         # get standard associate of leading term
  623.         l := f.coefficients[Length(f.coefficients)];
  624.         a := Quotient( R.baseRing, StandardAssociate( R.baseRing, l ), l );
  625.         f := Polynomial(R.baseRing,List(f.coefficients,x->a*x),f.valuation);
  626.     fi;
  627.     return f;
  628.  
  629. end;
  630.  
  631.  
  632. #############################################################################
  633. ##
  634. #F  PolynomialRingOps.EmbeddedPolynomial( <R>, <f> )  . . .  embed polynomial
  635. ##
  636. PolynomialRingOps.EmbeddedPolynomial := function( R, f )
  637.     return Polynomial( R.baseRing, f.coefficients, f.valuation );
  638. end;
  639.  
  640.  
  641. #############################################################################
  642. ##
  643. #F  PolynomialRingOps.Print( <P> )  . . . . . . . . . . . . . pretty printing
  644. ##
  645. PolynomialRingOps.Print := function( P )
  646.     if IsBound( P.name )  then
  647.         Print( P.name );
  648.     else
  649.         Print( "PolynomialRing( ", P.baseRing, " )" );
  650.     fi;
  651. end;
  652.  
  653.  
  654. #############################################################################
  655. ##
  656.  
  657. #V  LaurentPolynomials  . . . . . . . . . . domain of all Laurent polynomials
  658. ##
  659. LaurentPolynomials            := rec();
  660.  
  661. LaurentPolynomials.isDomain   := "true";
  662.  
  663. LaurentPolynomials.name       := "LaurentPolynomials";
  664.  
  665. LaurentPolynomials.isFinite   := false;
  666. LaurentPolynomials.size       := "infinity";
  667.  
  668. LaurentPolynomials.operations := Copy( DomainOps );
  669. LaurentPolynomialsOps         := LaurentPolynomials.operations;
  670.  
  671. LaurentPolynomialsOps.\in := function( p, Polynomials )
  672.     return     IsRec( p )
  673.            and IsBound( p.isPolynomial )
  674.            and p.isPolynomial;
  675. end;
  676.  
  677.  
  678. #############################################################################
  679. ##
  680. #F  LaurentPolynomialsOps.DefaultRing( <L> )  . . . . . . default ring of <L>
  681. ##
  682. LaurentPolynomialsOps.DefaultRing := function( L )
  683.     local   R,  l,  v;
  684.  
  685.     # get the ring
  686.     R := L[1].baseRing;
  687.     v := L[1].valuation;
  688.     for l  in L  do
  689.         if R <> l.baseRing  then
  690.             Error( "sorry, all elements must have the same base ring" );
  691.         fi;
  692.         if l.valuation < v  then
  693.             v := l.valuation;
  694.         fi;
  695.     od;
  696.  
  697.     # return the full (Laurent) polynom ring over <R>
  698.     if v < 0  then
  699.         return LaurentPolynomialRing(R);
  700.     else
  701.         return PolynomialRing(R);
  702.     fi;
  703.  
  704. end;
  705.  
  706.  
  707. #############################################################################
  708. ##
  709.  
  710. #V  Polynomials . . . . . . . . . . . . . . . . . . domain of all polynomials
  711. ##
  712. Polynomials            := rec();
  713.  
  714. Polynomials.isDomain   := "true";
  715.  
  716. Polynomials.name       := "Polynomials";
  717.  
  718. Polynomials.isFinite   := false;
  719. Polynomials.size       := "infinity";
  720.  
  721. Polynomials.operations := Copy( DomainOps );
  722. PolynomialsOps         := Polynomials.operations;
  723.  
  724. PolynomialsOps.\in := function( p, Polynomials )
  725.     return     IsRec( p )
  726.            and IsBound( p.isPolynomial )
  727.            and p.isPolynomial
  728.            and 0 <= p.valuation;
  729. end;
  730.  
  731.  
  732. #############################################################################
  733. ##
  734. #F  PolynomialsOps.DefaultRing( <L> ) . . . . . . . . . . default ring of <L>
  735. ##
  736. PolynomialsOps.DefaultRing := LaurentPolynomialsOps.DefaultRing;
  737.  
  738.  
  739. #############################################################################
  740. ##
  741.  
  742. #V  PolynomialOps   . . . . . . . . . . . . . . . operations for a polynomial
  743. ##
  744. PolynomialOps := rec();
  745. PolynomialOps.name := "PolynomialOps";
  746.  
  747.  
  748. #############################################################################
  749. ##
  750. #F  PolynomialOps.Print( <f> )  . . . . . .  print a polynomial in a nice way
  751. ##
  752. PolynomialOps.Print := function( pol )
  753.     local   R;
  754.  
  755.     R := pol.baseRing;
  756.     if IsBound(R.indeterminate) and IsBound(R.indeterminate.name)  then
  757.         DisplayPolynomial( pol, [R.indeterminate.name], false );
  758.     else
  759.     DisplayPolynomial( pol, ["X(",R,")"], false );
  760.     fi;
  761. end;
  762.  
  763.  
  764. #############################################################################
  765. ##
  766. #F  PolynomialOps.Value( <f>, <x> ) . . . . . . . . . . evaluate a polynomial
  767. ##
  768. PolynomialOps.Value := function( f, x )
  769.     local  val, i, id;
  770.  
  771.     id  := x ^ 0;
  772.     val := 0 * id;
  773.     i := Length(f.coefficients);
  774.     while 0 < i  do
  775.         val := val*x + id*f.coefficients[i];
  776.         i := i-1;
  777.     od;
  778.     if 0 <> f.valuation  then
  779.         val := val * x^f.valuation;
  780.     fi;
  781.     return val;
  782.  
  783. end;
  784.  
  785.  
  786. #############################################################################
  787. ##
  788. #F  PolynomialOps.Depth( <f> )  . . . . . . . . . ((R[x_1])[x_2])..)[x_depth]
  789. ##
  790. PolynomialOps.Depth := function( f )
  791.     local    R,  d;
  792.  
  793.     if not IsBound(f.depth)  then
  794.         R := f.baseRing;
  795.         d := 1;
  796.         while IsPolynomialRing(R) or IsLaurentPolynomialRing(R)  do
  797.             R := R.baseRing;
  798.             d := d + 1;
  799.         od;
  800.         f.depth := d;
  801.     fi;
  802.     return f.depth;
  803.  
  804. end;
  805.  
  806.  
  807. #############################################################################
  808. ##
  809. #F  PolynomialOps.GroundRing( <f> ) . . . . . . . . . . .  ground ring of <f>
  810. ##
  811. PolynomialOps.GroundRing := function( f )
  812.     local    R;
  813.  
  814.     if not IsBound(f.groundRing)  then
  815.         R := f.baseRing;
  816.         while IsPolynomialRing(R) or IsLaurentPolynomialRing(R)  do
  817.             R := R.baseRing;
  818.         od;
  819.         f.groundRing := R;
  820.     fi;
  821.     return f.groundRing;
  822. end;
  823.  
  824.  
  825. #############################################################################
  826. ##
  827. #F  PolynomialOps.Degree( <f> ) . . . . . . . . . . .  degree of a polynomial
  828. ##
  829. Degree := function( obj )
  830.     if not IsBound(obj.degree)  then
  831.     obj.degree := obj.operations.Degree(obj);
  832.     fi;
  833.     return obj.degree;
  834. end;
  835.  
  836. PolynomialOps.Degree := function( f )
  837.     return ( Length(f.coefficients)-1 ) + f.valuation;
  838. end;
  839.  
  840.  
  841. #############################################################################
  842. ##
  843. #F  PolynomialOps.LeadingCoefficient( <f> ) . . .  leading coefficient of <f>
  844. ##
  845. LeadingCoefficient := function( f )
  846.     if not IsBound(f.leadingCoefficient)  then
  847.     f.leadingCoefficient := f.operations.LeadingCoefficient(f);
  848.     fi;
  849.     return f.leadingCoefficient;
  850. end;
  851.  
  852. PolynomialOps.LeadingCoefficient := function( f )
  853.     if 0 < Length(f.coefficients)  then
  854.         return f.coefficients[Length(f.coefficients)];
  855.     else
  856.         return f.baseRing.zero;
  857.     fi;
  858. end;
  859.  
  860.  
  861. #############################################################################
  862. ##
  863. #F  PolynomialOps.\= . . . . . . . . . . . .  equaltity test for polynomials
  864. ##
  865. PolynomialOps.\= := function( l, r )
  866.     local   R,  sum,  i;
  867.  
  868.     # handle the case <something> = <polynomial>
  869.     if not IsPolynomial( l )  then
  870.         return false;
  871.  
  872.     # handle the case <polynomial> = <something>
  873.     elif not IsPolynomial( r )  then
  874.         return false;
  875.  
  876.     # handle special case of iterated polynomials
  877.     elif l.operations.Depth(l) <> r.operations.Depth(r)  then
  878.         return false;
  879.  
  880.     # return 'false' if <l> and <r> have different rings
  881.     elif l.operations.GroundRing(l) <> r.operations.GroundRing(r)  then
  882.         return false;
  883.  
  884.     # compare valuation
  885.     elif l.valuation <> r.valuation  then
  886.         return false;
  887.  
  888.     # compare coefficients
  889.     else
  890.         return l.coefficients = r.coefficients;
  891.     fi;
  892.  
  893. end;
  894.  
  895.  
  896. #############################################################################
  897. ##
  898. #F  PolynomialOps.\< . . . . . . . . . . . . . . . comparison of polynomials
  899. ##
  900. PolynomialOps.\< := function( l, r )
  901.  
  902.     if not IsPolynomial( l )  then
  903.         return l < r.coefficients;
  904.     elif not IsPolynomial( r )  then
  905.         return l.coefficients < r;
  906.     elif l.operations.Depth(l) <> r.operations.Depth(r)  then
  907.         return l.operations.Depth(l) < r.operations.Depth(r);
  908.     elif l.valuation <> r.valuation  then
  909.         return l.valuation < r.valuation;
  910.     elif Length( l.coefficients ) = Length( r.coefficients )  then
  911.         return l.coefficients < r.coefficients;
  912.     else
  913.         return Length( l.coefficients ) < Length( r.coefficients );
  914.     fi;
  915.  
  916. end;
  917.  
  918.  
  919. #############################################################################
  920. ##
  921. #F  PolynomialOps.\+ . . . . . . . . . . . . . . . .  sum of two polynomials
  922. ##
  923. PolynomialOps.\+ := function( l, r )
  924.     local   R,  sum,  val,  vdf,  i;
  925.  
  926.     # handle the case that one argument is a list
  927.     if IsList(l)  then
  928.         return List( l, x -> x+r );
  929.     elif IsList(r)  then
  930.         return List( r, x -> l+x );
  931.     fi;
  932.  
  933.     # handle the case <scalar> + <polynomial>
  934.     if not IsPolynomial(l)  then
  935.         if IsInt(l)  then
  936.             l := l * r.baseRing.one;
  937.         elif not l in r.baseRing  then
  938.             Error( "<l> must lie in the base ring of <r>" );
  939.         fi;
  940.         R := r.baseRing;
  941.         l := R.operations.Polynomial( R, [l], 0 );
  942.     fi;
  943.  
  944.     # handle the case <polynomial> + <scalar>
  945.     if not IsPolynomial(r)  then
  946.         if IsInt(r)  then
  947.             r := r * l.baseRing.one;
  948.         elif not r in l.baseRing  then
  949.             Error( "<r> must lie in the base ring of <l>" );
  950.         fi;
  951.         R := l.baseRing;
  952.     r := R.operations.Polynomial( R, [r], 0 );
  953.     fi;
  954.  
  955.     # handle special case of iterated polynomials
  956.     if l.operations.Depth(l) < r.operations.Depth(r)  then
  957.         R := DefaultRing(r);
  958.         l := l * R.one;
  959.     elif r.operations.Depth(r) < l.operations.Depth(l)  then
  960.         R := DefaultRing(l);
  961.         r := R.one * r;
  962.     fi;
  963.  
  964.     # give up if we have different rings
  965.     if l.operations.GroundRing(l) <> r.operations.GroundRing(r)  then
  966.         Error( "polynomials must have the same ring" ); 
  967.  
  968.     # if <l> is the null polynomial return <r>
  969.     elif Length(l.coefficients) = 0  then
  970.     return r;
  971.  
  972.     # if <r> is the null polynomial return <l>
  973.     elif Length(r.coefficients) = 0  then
  974.         return l;
  975.  
  976.     # sum of two polynomials
  977.     else
  978.  
  979.         # get a common ring
  980.         R := l.baseRing;
  981.  
  982.         # add both coefficients lists
  983.         if l.valuation < r.valuation  then
  984.         val := l.valuation;
  985.             sum := Copy( l.coefficients );
  986.             vdf := r.valuation - l.valuation;
  987.             for i  in [ Length(sum)+1 .. Length(r.coefficients)+vdf ] do
  988.             sum[i] := R.zero;
  989.             od;
  990.             for i  in [ 1 .. Length(r.coefficients) ]  do
  991.             sum[i+vdf] := sum[i+vdf] + r.coefficients[i];
  992.             od;
  993.         else
  994.         val := r.valuation;
  995.             sum := Copy( r.coefficients );
  996.             vdf := l.valuation - r.valuation;
  997.             for i  in [ Length(sum)+1 .. Length(l.coefficients)+vdf ] do
  998.             sum[i] := R.zero;
  999.             od;
  1000.             for i  in [ 1 .. Length(l.coefficients) ]  do
  1001.             sum[i+vdf] := l.coefficients[i] + sum[i+vdf];
  1002.             od;
  1003.         fi;
  1004.     fi;
  1005.  
  1006.     # return the sum
  1007.     return R.operations.Polynomial( R, sum, val );
  1008.  
  1009. end;
  1010.  
  1011.  
  1012. #############################################################################
  1013. ##
  1014. #F  PolynomialOps.\- . . . . . . . . . . . . . difference of two polynomials
  1015. ##
  1016. PolynomialOps.\- := function( l, r )
  1017.     local   R,  dif,  val,  vdf,  i;
  1018.  
  1019.     # handle the case that one argument is a list
  1020.     if IsList(l)  then
  1021.         return List( l, x -> x-r );
  1022.     elif IsList(r)  then
  1023.         return List( r, x -> l-x );
  1024.     fi;
  1025.  
  1026.     # handle the case <scalar> - <polynomial>
  1027.     if not IsPolynomial(l)  then
  1028.         if IsInt(l)  then
  1029.             l := l * r.baseRing.one;
  1030.         elif not l in r.baseRing  then
  1031.             Error( "<l> must lie in the base ring of <r>" );
  1032.         fi;
  1033.         R := r.baseRing;
  1034.         l := R.operations.Polynomial( R, [l], 0 );
  1035.     fi;
  1036.  
  1037.     # handle the case <polynomial> - <scalar>
  1038.     if not IsPolynomial(r)  then
  1039.         if IsInt(r)  then
  1040.             r := r * l.baseRing.one;
  1041.         elif not r in l.baseRing  then
  1042.             Error( "<r> must lie in the base ring of <l>" );
  1043.         fi;
  1044.         R := l.baseRing;
  1045.     r := R.operations.Polynomial( R, [r], 0 );
  1046.     fi;
  1047.  
  1048.     # handle special case of iterated polynomials
  1049.     if l.operations.Depth(l) < r.operations.Depth(r)  then
  1050.         R := DefaultRing(r);
  1051.         l := l * R.one;
  1052.     elif r.operations.Depth(r) < l.operations.Depth(l)  then
  1053.         R := DefaultRing(l);
  1054.         r := R.one * r;
  1055.     fi;
  1056.  
  1057.     # give up if we have different rings
  1058.     if l.operations.GroundRing(l) <> r.operations.GroundRing(r)  then
  1059.         Error( "polynomials must have the same ring" ); 
  1060.  
  1061.     # if <l> is the null polynomial return -<r>
  1062.     elif Length(l.coefficients) = 0  then
  1063.     return -r;
  1064.  
  1065.     # if <r> is the null polynomial return <l>
  1066.     elif Length(r.coefficients) = 0  then
  1067.         return l;
  1068.  
  1069.     # difference of two polynomials
  1070.     else
  1071.  
  1072.         # get a common ring
  1073.         R := l.baseRing;
  1074.  
  1075.         # add both coefficients lists
  1076.         if l.valuation < r.valuation  then
  1077.         val := l.valuation;
  1078.             dif := Copy( l.coefficients );
  1079.             vdf := r.valuation - l.valuation;
  1080.             for i  in [ Length(dif)+1 .. Length(r.coefficients)+vdf ] do
  1081.             dif[i] := R.zero;
  1082.             od;
  1083.             for i  in [ 1 .. Length(r.coefficients) ]  do
  1084.             dif[i+vdf] := dif[i+vdf] - r.coefficients[i];
  1085.             od;
  1086.         else
  1087.         val := r.valuation;
  1088.             dif := Copy( r.coefficients ) * (R.zero-R.one);
  1089.             vdf := l.valuation - r.valuation;
  1090.             for i  in [ Length(dif)+1 .. Length(l.coefficients)+vdf ] do
  1091.             dif[i] := R.zero;
  1092.             od;
  1093.             for i  in [ 1 .. Length(l.coefficients) ]  do
  1094.             dif[i+vdf] := l.coefficients[i] + dif[i+vdf];
  1095.             od;
  1096.         fi;
  1097.     fi;
  1098.  
  1099.     # return the dif
  1100.     return R.operations.Polynomial( R, dif, val );
  1101.  
  1102. end;
  1103.  
  1104.  
  1105. #############################################################################
  1106. ##
  1107. #F  PolynomialOps.\* . . . . . . . . . . . . . .  product of two polynomials
  1108. ##
  1109. PolynomialOps.\* := function( l, r )
  1110.     local   R,  prd,  z,  m,  n,  i,  j,  val;
  1111.  
  1112.     # handle the case that one argument is a list
  1113.     if IsList(l)  then
  1114.         return List(l, x -> x*r);
  1115.     elif IsList(r)  then
  1116.         return List(r, x -> l*x);
  1117.  
  1118.     # handle the case <scalar> * <polynomial>
  1119.     elif not IsPolynomial(l)  then
  1120.         if IsInt(l) and IsBound(r.baseRing.one)  then
  1121.             l := l * r.baseRing.one;
  1122.         elif not l in r.baseRing  then
  1123.         Error("<l> must lie in the base ring of <r>");
  1124.     fi;
  1125.     R := r.baseRing;
  1126.     if l = r.baseRing.zero or r.coefficients = []  then
  1127.         prd := [];
  1128.             val := 0;
  1129.         else
  1130.         prd := l * r.coefficients;
  1131.             val := r.valuation;
  1132.     fi;
  1133.  
  1134.     # handle the case <polynomial> * <scalar>
  1135.     elif not IsPolynomial(r)  then
  1136.         if IsInt(r) and IsBound(l.baseRing.one)  then
  1137.             r := l.baseRing.one * r;
  1138.     elif not r in l.baseRing  then
  1139.         Error("<r> must lie in the base ring of <l>");
  1140.     fi;
  1141.     R := l.baseRing;
  1142.     if r = l.baseRing.zero or l.coefficients = []  then
  1143.         prd := [];
  1144.             val := 0;
  1145.         else
  1146.         prd := l.coefficients * r;
  1147.             val := l.valuation;
  1148.     fi;
  1149.  
  1150.     # the ground fields must be equal
  1151.     elif l.operations.GroundRing(l) <> r.operations.GroundRing(r)  then
  1152.         Error( "polynomials must have the same ring" );
  1153.  
  1154.     # handle special case of iterated polynomials
  1155.     elif l.operations.Depth(l) <> r.operations.Depth(r)  then
  1156.         if l.operations.Depth(l) < r.operations.Depth(r)  then
  1157.             prd := List( r.coefficients, x -> l*x );
  1158.             val := r.valuation;
  1159.             R   := r.baseRing;
  1160.         else
  1161.             prd := List( l.coefficients, x -> x*r );
  1162.             val := l.valuation;
  1163.             R   := l.baseRing;
  1164.         fi;
  1165.  
  1166.     # multiply two polynomials
  1167.     else
  1168.  
  1169.         # get a common ring
  1170.         R := l.baseRing;
  1171.  
  1172.         # fold the product
  1173.         m := Length(l.coefficients);
  1174.         n := Length(r.coefficients);
  1175.         prd := [];
  1176.         for i  in [ 1 .. m+n-1 ]  do
  1177.             z := R.zero;
  1178.             for j  in [ Maximum(i+1-n,1) .. Minimum(m,i) ]  do
  1179.                 z := z + l.coefficients[j]*r.coefficients[i+1-j];
  1180.             od;
  1181.             prd[i] := z;
  1182.         od;
  1183.         val := l.valuation + r.valuation;
  1184.     fi;
  1185.  
  1186.     # return the product
  1187.     return R.operations.Polynomial( R, prd, val );
  1188.  
  1189. end;
  1190.  
  1191.  
  1192. #############################################################################
  1193. ##
  1194. #F  PolynomialOps.\/ . . . . . . . . . . . . . . quotient of two polynomials
  1195. ##
  1196. PolynomialOps.\/ := function( l, r )
  1197.     local   R,  quo,  z,  m,  n,  i,  j,  val;
  1198.  
  1199.     # handle the case that <l> argument is a list
  1200.     if IsList(l)  then
  1201.         return List(l, x -> x/r);
  1202.  
  1203.     # handle the case <scalar> / <polynomial>
  1204.     elif not IsPolynomial(l)  then
  1205.         if IsInt(l) and IsBound(r.baseRing.one)  then
  1206.             l := l * r.baseRing.one;
  1207.         elif not l in r.baseRing  then
  1208.         Error("<l> must lie in the base ring of <r>");
  1209.     fi;
  1210.         r := r^-1;
  1211.     R := r.baseRing;
  1212.     if l = r.baseRing.zero or r.coefficients = []  then
  1213.         quo := [];
  1214.             val := 0;
  1215.         else
  1216.         quo := l * r.coefficients;
  1217.             val := r.valuation;
  1218.     fi;
  1219.  
  1220.     # handle the case <polynomial> / <scalar>
  1221.     elif not IsPolynomial(r)  then
  1222.         if IsInt(r) and IsBound(l.baseRing.one)  then
  1223.             r := l.baseRing.one * r;
  1224.     elif not r in l.baseRing  then
  1225.         Error("<r> must lie in the base ring of <l>");
  1226.     fi;
  1227.     R := l.baseRing;
  1228.     if r = l.baseRing.zero or l.coefficients = []  then
  1229.             Error( "<r> must be non-zero" );
  1230.         else
  1231.         quo := l.coefficients * (1/r);
  1232.             val := l.valuation;
  1233.     fi;
  1234.  
  1235.     # the ground fields must be equal
  1236.     elif l.operations.GroundRing(l) <> r.operations.GroundRing(r)  then
  1237.         Error( "polynomials must have the same ring" );
  1238.  
  1239.     # handle special case of iterated polynomials
  1240.     elif l.operations.Depth(l) <> r.operations.Depth(r)  then
  1241.         if l.operations.Depth(l) < r.operations.Depth(r)  then
  1242.             quo := List( r.coefficients, x -> l/x );
  1243.             val := r.valuation;
  1244.             R   := r.baseRing;
  1245.         else
  1246.             quo := List( l.coefficients, x -> x/r );
  1247.             val := l.valuation;
  1248.             R   := l.baseRing;
  1249.         fi;
  1250.  
  1251.     # compute the quotient and return in this case
  1252.     else
  1253.         quo := Quotient( l, r );
  1254.         if quo = false  then
  1255.             Error( "cannot divide <l> by <r>" );
  1256.         fi;
  1257.         return quo;
  1258.     fi;
  1259.  
  1260.     # return the product
  1261.     return R.operations.Polynomial( R, quo, val );
  1262.  
  1263. end;
  1264.  
  1265.  
  1266. #############################################################################
  1267. ##
  1268. #F  PolynomialOps.\^ . . . . . . . . . . . . . . . . . power of a polynomial
  1269. ##
  1270. PolynomialOps.\^ := function( l, r )
  1271.     local   R,  pow;
  1272.  
  1273.     # <l> must be a polynomial and <r> a non-negative integer
  1274.     if not IsPolynomial(l)  then
  1275.         Error("<l> must be a polynomial");
  1276.     fi;
  1277.     if not IsInt(r)  then
  1278.         Error("<r> must be an integer");
  1279.     fi;
  1280.  
  1281.     # invert <l> if necessary and possible
  1282.     if r < 0  then
  1283.         R := LaurentPolynomialRing( l.baseRing );
  1284.         l := R.operations.Quotient( R, R.one, l );
  1285.         if l = false  then
  1286.             Error( "cannot invert <l> in the laurent polynomial ring" );
  1287.         fi;
  1288.         r := -r;
  1289.     fi;
  1290.  
  1291.     # if <r> is zero, return x^0, if <r> is one return <l>
  1292.     R := l.baseRing;
  1293.     if r = 0  then
  1294.         return Polynomial( R, [ R.one ] );
  1295.     elif r = 1  then
  1296.         return l;
  1297.     fi;
  1298.  
  1299.     # if <l> is of degree less than 2, return
  1300.     if Length(l.coefficients) = 0  then
  1301.         return l;
  1302.     elif Length(l.coefficients) = 1  then
  1303.         return Polynomial( R, [ l.coefficients[1]^r ], l.valuation*r );
  1304.     fi;
  1305.  
  1306.     # use repeated squaring
  1307.     pow := Polynomial( R, [ R.one ] );
  1308.     while 0 < r  do
  1309.         if r mod 2 = 1  then
  1310.         pow := pow * l;
  1311.             r   := r - 1;
  1312.         fi; 
  1313.         if 1 < r  then
  1314.         l := l * l;
  1315.             r := r / 2;
  1316.         fi;
  1317.     od;
  1318.  
  1319.     # return the power
  1320.     return pow;
  1321.  
  1322. end;
  1323.  
  1324.  
  1325. #############################################################################
  1326. ##
  1327.  
  1328. #F  DisplayPolynomial( <p>, <str> ) . . . . . . . . . .  display a polynomial
  1329. ##
  1330. DisplayPolynomial := function( arg )
  1331.  
  1332.     local   i,            # loop variable
  1333.         p,              # the polynomial
  1334.             wantNl,         # try if we want a newline at the end
  1335.         str,            # string list for indeterminate
  1336.         nam,            # loop variable for <str>
  1337.             cof,            # coefficients of <p>
  1338.             len,            # length of coefficients of <p>
  1339.             isMinus,        # if 'true' print "x^2 - x"
  1340.             isPrimeField;   # if 'true' print "Z(3)*(2*x^2+1)"
  1341.  
  1342.     # get arguments, <wantNl> is 'false' by default
  1343.     p := arg[1];
  1344.     str := arg[2];
  1345.     if IsString(str)  then str := [ str ];  fi;
  1346.     wantNl := 3 = Length(arg) and arg[3];
  1347.  
  1348.     # check if the base ring of <p> is a finite prime field
  1349.     isPrimeField := IsFiniteField(p.baseRing) and (p.baseRing.degree = 1);
  1350.  
  1351.     # if the polynomial is of length one, ignore <isPrimeField>
  1352.     if  Length(p.coefficients) < 2  then isPrimeField := false;  fi;
  1353.  
  1354.     # check if can print a minus sign
  1355.     isMinus := IsInt(p.baseRing.zero);
  1356.  
  1357.     # catch some trivial cases
  1358.     if p.valuation = 0 and Length(p.coefficients) < 2  then
  1359.     if Length(p.coefficients) = 0  then
  1360.         Print("0*");
  1361.         for nam  in str  do
  1362.         Print( nam );
  1363.         od;
  1364.         Print("^0");
  1365.     elif p.coefficients[1] = p.baseRing.one  then
  1366.         for nam  in str  do
  1367.         Print( nam );
  1368.         od;
  1369.         Print("^0");
  1370.     elif isMinus and p.coefficients[1] = -p.baseRing.one  then
  1371.         Print("-");
  1372.         for nam  in str  do
  1373.         Print( nam );
  1374.         od;
  1375.         Print("^0");
  1376.     else
  1377.         Print( p.coefficients[1], "*" );
  1378.         for  nam  in str  do
  1379.         Print( nam );
  1380.         od;
  1381.         Print("^0");
  1382.     fi;
  1383.     return;
  1384.     fi;
  1385.  
  1386.     # if <isPrimeField> is 'true' print the one in Zp
  1387.     if isPrimeField  then  Print( p.baseRing.one, "*(" );  fi;
  1388.  
  1389.     # print the polynomial
  1390.     len := Length(p.coefficients);
  1391.     for i  in Reversed([ 1 .. len ])  do
  1392.         cof := p.coefficients[i];
  1393.         if cof <> p.baseRing.zero  then
  1394.             if i < len and isMinus and IsInt(cof) and cof < 0  then
  1395.                 Print(" - ");
  1396.                 cof := -cof;
  1397.             elif i = len and isMinus and cof = -p.baseRing.one  then
  1398.                 Print("-");
  1399.                 cof := -cof;
  1400.             elif i < len  then
  1401.                 Print(" + ");
  1402.             fi;
  1403.             if 1 = i + p.valuation  then
  1404.                 if isPrimeField  then
  1405.                     Print(Int(cof));
  1406.                 elif IsFFE(cof) or IsInt(cof) then
  1407.                     Print(cof);
  1408.         else
  1409.             Print( "(", cof, ")" );
  1410.                 fi;
  1411.             elif 2 = i + p.valuation  then
  1412.                 if cof <> p.baseRing.one  then
  1413.                        if isPrimeField  then
  1414.                         Print( Int(cof), "*" );
  1415.             for nam in str  do
  1416.                 Print( nam );
  1417.             od;
  1418.             elif IsFFE(cof) or IsInt(cof)  then
  1419.                         Print( cof, "*" );
  1420.             for nam in str  do
  1421.                 Print( nam );
  1422.             od;
  1423.                     else
  1424.                         Print( "(", cof, ")*" );
  1425.             for nam in str  do
  1426.                 Print( nam );
  1427.             od;
  1428.                     fi;
  1429.                 else
  1430.             for nam in str  do
  1431.             Print( nam );
  1432.             od;
  1433.                 fi;
  1434.             else
  1435.                 if cof <> p.baseRing.one  then
  1436.                     if isPrimeField  then
  1437.                         Print( Int(cof), "*" );
  1438.             for nam in str  do
  1439.                 Print( nam );
  1440.             od;
  1441.             elif IsFFE(cof) or IsInt(cof)  then
  1442.                         Print( cof, "*" );
  1443.             for nam in str  do
  1444.                 Print( nam );
  1445.             od;
  1446.                     else
  1447.                         Print( "(", cof, ")*" );
  1448.             for nam in str  do
  1449.                 Print( nam );
  1450.             od;
  1451.                     fi;
  1452.                 else
  1453.             for nam in str  do
  1454.             Print( nam );
  1455.             od;
  1456.                 fi;
  1457.             if i+p.valuation-1 < 0  then
  1458.             Print( "^(", i+p.valuation-1, ")" );
  1459.         else
  1460.                     Print( "^", i+p.valuation-1 );
  1461.         fi;
  1462.             fi;
  1463.         fi;
  1464.     od;
  1465.     if isPrimeField  then Print(")");  fi;
  1466.     if wantNl  then Print("\n");  fi;
  1467.  
  1468. end;
  1469.  
  1470.  
  1471. #############################################################################
  1472. ##
  1473.  
  1474. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  1475. ##
  1476. ##  Local Variables:
  1477. ##  mode:               outline
  1478. ##  outline-regexp:     "#F\\|#V\\|#E"
  1479. ##  eval:               (local-set-key "\t" 'tab-to-tab-stop)
  1480. ##  eval:               (hide-body)
  1481. ##  End:
  1482. ##
  1483.