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

  1. #############################################################################
  2. ##
  3. #A  polyrat.g                   GAP library                      Frank Celler
  4. ##
  5. #A  @(#)$Id: polyrat.g,v 3.19 1993/02/19 15:50:51 fceller Exp $
  6. ##
  7. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  8. ##
  9. ##  This file contains functions for polynomials over finite fields.
  10. ##
  11. #H  $Log: polyrat.g,v $
  12. #H  Revision 3.19  1993/02/19  15:50:51  fceller
  13. #H  fixed a bug in '-'
  14. #H
  15. #H  Revision 3.18  1993/02/12  12:00:08  martin
  16. #H  multiplication must check for zero before using 'FastPolynomial'
  17. #H
  18. #H  Revision 3.17  1993/02/11  16:47:56  fceller
  19. #H  added <list> + <polynomial>
  20. #H
  21. #H  Revision 3.16  1993/02/09  14:25:55  martin
  22. #H  made undefined globals local
  23. #H
  24. #H  Revision 3.15  1993/02/08  11:57:07  fceller
  25. #H  some speed ups in polynomial arithmetic
  26. #H
  27. #H  Revision 3.14  1993/01/22  12:03:48  fceller
  28. #H  added missing 'isPolynomialRing' in 'RationalsPolynomials'
  29. #H
  30. #H  Revision 3.13  1993/01/08  09:13:08  fceller
  31. #H  added Hensel 'Factors' for polynomials over the rationals
  32. #H
  33. #H  Revision 3.12  1993/01/04  11:19:14  fceller
  34. #H  added 'Gcd'
  35. #H
  36. #H  Revision 3.11  1992/12/16  19:47:27  martin
  37. #H  replaced quoted record names with escaped ones
  38. #H
  39. #H  Revision 3.10  1992/12/07  07:40:04  fceller
  40. #H  added <f> mod <n>
  41. #H
  42. #H  Revision 3.9  1992/11/25  12:34:54  fceller
  43. #H  added 'Degree'
  44. #H
  45. #H  Revision 3.8  1992/11/16  17:48:31  fceller
  46. #H  added 'String' support
  47. #H
  48. #H  Revision 3.7  92/11/16  12:23:40  fceller
  49. #H  added Laurent polynomials
  50. #H  
  51. #H  Revision 3.6  92/10/28  09:15:08  fceller
  52. #H  fixed 'mod' for zero polynomial
  53. #H  
  54. #H  Revision 3.5  1992/07/24  07:08:07  fceller
  55. #H  improved '*' to allow <nullpoly> * <int>
  56. #H
  57. #H  Revision 3.4  1992/07/23  09:20:48  fceller
  58. #H  improved '*' to allow <list> * <polynomial>
  59. #H
  60. #H  Revision 3.3  1992/06/17  07:06:04  fceller
  61. #H  moved '<somedomain>.operations.Polynomial' function to "<somedomain>.g"
  62. #H
  63. #H  Revision 3.2  1992/06/01  07:32:24  fceller
  64. #H  Initial GAP 3.2 release
  65. ##
  66.  
  67.  
  68. #############################################################################
  69. ##
  70. #F  InfoPoly1(...)  . . . . . . . . . . . infomation function for polynomials
  71. #F  InfoPoly2(...)  . . . . . . . . . . . . .  debug function for polynomials
  72. ##
  73. if not IsBound(InfoPoly1)    then InfoPoly1   := Ignore;  fi;
  74. if not IsBound(InfoPoly2)    then InfoPoly2   := Ignore;  fi;
  75. if not IsBound(InfoPoly3)    then InfoPoly3   := Ignore;  fi;
  76.  
  77.  
  78. #############################################################################
  79. ##
  80.  
  81. #V  RationalsPolynomialOps  . . . . . . . . . . polynomial over the rationals
  82. ##
  83. RationalsPolynomialOps := Copy( PolynomialOps );
  84. RationalsPolynomialOps.name := "RationalsPolynomialOps";
  85.  
  86.  
  87. #############################################################################
  88. ##
  89. #F  RationalsPolynomialOps.\+ . . . . . . . . . . . .  sum of two polynomials
  90. ##
  91. RationalsPolynomialOps.\+ := function( l, r )
  92.     local   sum,  val,  vdf;
  93.  
  94.     # handle the case that one argument is a list
  95.     if IsList(l)  then
  96.         return List( l, x -> x+r );
  97.     elif IsList(r)  then
  98.         return List( r, x -> l+x );
  99.     fi;
  100.  
  101.     # handle the case <scalar> + <polynomial>
  102.     if not (IsRec(l) and IsBound(l.isPolynomial) and l.isPolynomial)  then
  103.  
  104.         # <r> must have the rationals as base ring
  105.         if Rationals <> r.baseRing  then
  106.             Error( "<r> must have the rationals as base ring" );
  107.         fi;
  108.  
  109.         # <l> must lie in the base ring of <r>
  110.         if not IsRat(l)  then
  111.             Error( "<l> must lie in the base ring of <r>" );
  112.         fi;
  113.  
  114.     # if <l> is trivial return <r>
  115.     if l = 0  then
  116.         return r;
  117.     fi;
  118.  
  119.     # otherwise convert <l> into a polynomial
  120.         l := RationalsOps.FastPolynomial( Rationals, [l], 0 );
  121.     fi;
  122.  
  123.     # handle the case <polynomial> + <scalar>
  124.     if not (IsRec(r) and IsBound(r.isPolynomial) and r.isPolynomial)  then
  125.  
  126.         # <l> must have the rationals as base ring
  127.         if Rationals <> l.baseRing  then
  128.             Error( "<l> must have the rationals as base ring" );
  129.         fi;
  130.  
  131.         # <r> must lie in the base ring of <l>
  132.         if not IsRat(r)  then
  133.             Error( "<r> must lie in the base ring of <l>" );
  134.         fi;
  135.  
  136.     # if <r> is trivial return <l>
  137.     if r = 0  then
  138.         return l;
  139.     fi;
  140.  
  141.     # otherwise convert <r> into a polynomial
  142.     r := RationalsOps.FastPolynomial( Rationals, [r], 0 );
  143.     fi;
  144.  
  145.     # depth greater than one are handle by our superclass
  146.     if 1 <> l.operations.Depth(l) or 1 <> r.operations.Depth(r)  then
  147.     return PolynomialOps.\+( l, r );
  148.  
  149.     # give up if we have rings other then the rationals
  150.     elif Rationals <> l.baseRing  then
  151.         Error( "<l> must have the rationals as base ring" );
  152.     elif Rationals <> r.baseRing  then
  153.         Error( "<r> must have the rationals as base ring" );
  154.  
  155.     # if <l> is the null polynomial return <r>
  156.     elif Length(l.coefficients) = 0  then
  157.     return r;
  158.  
  159.     # if <r> is the null polynomial return <l>
  160.     elif Length(r.coefficients) = 0  then
  161.         return l;
  162.  
  163.     # sum of two polynomials
  164.     else
  165.  
  166.         # get a common ring and the valuation minimum;
  167.         vdf := r.valuation - l.valuation;
  168.  
  169.         # if <r>.valuation is the minimum shift <l>
  170.         if r.valuation < l.valuation  then
  171.             val := r.valuation;
  172.             sum := ShiftedCoeffs( l.coefficients, -vdf );
  173.  
  174.             # the rationals are commutative
  175.             AddCoeffs( sum, r.coefficients );
  176.  
  177.         # if <l>.valuation is the minimum shift <r>
  178.         elif l.valuation < r.valuation  then
  179.             val := l.valuation;
  180.             sum := ShiftedCoeffs( r.coefficients, vdf );
  181.  
  182.             # the rationals are commutative
  183.             AddCoeffs( sum, l.coefficients );
  184.  
  185.         # otherwise they are equal
  186.         else
  187.             sum := SumCoeffs( l.coefficients, r.coefficients );
  188.             val := l.valuation;
  189.         fi;
  190.  
  191.         # return the sum
  192.     if 0 < Length(sum) and 0 <> sum[1]  then
  193.             return RationalsOps.FastPolynomial( Rationals, sum, val );
  194.     else
  195.             return RationalsOps.Polynomial( Rationals, sum, val );
  196.     fi;
  197.  
  198.     fi;
  199.  
  200. end;
  201.  
  202.  
  203. #############################################################################
  204. ##
  205. #F  RationalsPolynomialOps.\- . . . . . . . . . . . . diff of two polynomials
  206. ##
  207. RationalsPolynomialOps.\- := function( l, r )
  208.     local   dif,  val,  vdf;
  209.  
  210.     # handle the case that one argument is a list
  211.     if IsList(l)  then
  212.         return List( l, x -> x-r );
  213.     elif IsList(r)  then
  214.         return List( r, x -> l-x );
  215.     fi;
  216.  
  217.     # handle the case <scalar> - <polynomial>
  218.     if not (IsRec(l) and IsBound(l.isPolynomial) and l.isPolynomial)  then
  219.  
  220.         # <r> must have the rationals as base ring
  221.         if Rationals <> r.baseRing  then
  222.             Error( "<r> must have the rationals as base ring" );
  223.         fi;
  224.  
  225.         # <l> must lie in the base ring of <r>
  226.         if not IsRat(l)  then
  227.             Error( "<l> must lie in the base ring of <r>" );
  228.         fi;
  229.  
  230.     # if <l> is trivial return -<r>
  231.     if l = 0  then
  232.             return RationalsOps.FastPolynomial(
  233.                Rationals,
  234.                (-1) * r.coefficients,
  235.                r.valuation );
  236.     fi;
  237.  
  238.     # otherwise convert <l> into a polynomial
  239.         l := RationalsOps.FastPolynomial( Rationals, [l], 0 );
  240.     fi;
  241.  
  242.     # handle the case <polynomial> - <scalar>
  243.     if not (IsRec(r) and IsBound(r.isPolynomial) and r.isPolynomial)  then
  244.  
  245.         # <l> must have the rationals as base ring
  246.         if Rationals <> l.baseRing  then
  247.             Error( "<l> must have the rationals as base ring" );
  248.         fi;
  249.  
  250.         # <r> must lie in the base ring of <l>
  251.         if not IsRat(r)  then
  252.             Error( "<r> must lie in the base ring of <l>" );
  253.         fi;
  254.  
  255.     # if <r> is trivial return <l>
  256.     if r = 0  then
  257.         return l;
  258.     fi;
  259.  
  260.     # otherwise convert <r> into a polynomial
  261.     r := RationalsOps.FastPolynomial( Rationals, [r], 0 );
  262.     fi;
  263.  
  264.     # depth greater than one are handle by our superclass
  265.     if 1 <> l.operations.Depth(l) or 1 <> r.operations.Depth(r)  then
  266.     return PolynomialOps.\-( l, r );
  267.  
  268.     # give up if we have rings other then the rationals
  269.     elif Rationals <> l.baseRing  then
  270.         Error( "<l> must have the rationals as base ring" );
  271.     elif Rationals <> r.baseRing  then
  272.         Error( "<r> must have the rationals as base ring" );
  273.  
  274.     # if <l> is the null polynomial return <r>
  275.     elif Length(l.coefficients) = 0  then
  276.     return -r;
  277.  
  278.     # if <r> is the null polynomial return <l>
  279.     elif Length(r.coefficients) = 0  then
  280.         return l;
  281.  
  282.     # difference of two polynomials
  283.     else
  284.  
  285.         # get a common ring and the valuation minimum;
  286.         vdf := r.valuation - l.valuation;
  287.  
  288.         # if <r>.valuation is the minimum shift <l>
  289.         if r.valuation < l.valuation  then
  290.             val := r.valuation;
  291.             dif := ShiftedCoeffs( l.coefficients, -vdf );
  292.  
  293.             # the rationals are commutative
  294.             AddCoeffs( dif, r.coefficients, -1 );
  295.  
  296.         # if <l>.valuation is the minimum shift <r>
  297.         elif l.valuation < r.valuation  then
  298.             val := l.valuation;
  299.             dif := (-1)*ShiftedCoeffs( r.coefficients, vdf );
  300.  
  301.             # the rationals are commutative
  302.             AddCoeffs( dif, l.coefficients );
  303.  
  304.         # otherwise they are equal
  305.         else
  306.             dif := Copy(l.coefficients);
  307.             AddCoeffs( dif, r.coefficients, -1 );
  308.             val := l.valuation;
  309.         fi;
  310.  
  311.         # return the difference
  312.     if 0 < Length(dif) and 0 <> dif[1]  then
  313.             return RationalsOps.FastPolynomial( Rationals, dif, val );
  314.     else
  315.             return RationalsOps.Polynomial( Rationals, dif, val );
  316.     fi;
  317.  
  318.     fi;
  319.  
  320. end;
  321.  
  322.  
  323. #############################################################################
  324. ##
  325. #F  RationalsPolynomialOps.\*  . . . . . . . . .  product of two polynomials
  326. ##
  327. RationalsPolynomialOps.\* := function( l, r )
  328.     local   R,  prd,  val;
  329.  
  330.     # handle the case that one argument is a list
  331.     if IsList(l)  then
  332.         return List( l, x -> x*r );
  333.     elif IsList(r)  then
  334.         return List( r, x -> l*x );
  335.  
  336.     # handle the case <scalar> * <polynomial>
  337.     elif not (IsRec(l) and IsBound(l.isPolynomial) and l.isPolynomial)  then
  338.  
  339.         # <r> must have the rationals as base ring
  340.         if Rationals <> r.baseRing  then
  341.             Error( "<r> must have the rationals as base ring" );
  342.         fi;
  343.  
  344.         # <l> must lie in the base ring of <r>
  345.         if not IsRat(l)  then
  346.         Error( "<l> must lie in the base ring of <r>" );
  347.     fi;
  348.     if l = 0 or r.coefficients = []  then
  349.         prd := [];
  350.         val := 0;
  351.         else
  352.         prd := l * r.coefficients;
  353.         val := r.valuation;
  354.     fi;
  355.  
  356.         # compute the product
  357.         prd            := RationalsOps.FastPolynomial( Rationals, prd, val );
  358.         prd.depth      := 1;
  359.         prd.groundRing := Rationals;
  360.  
  361.         # and return
  362.         return prd;
  363.  
  364.     # handle the case <polynomial> * <scalar>
  365.     elif not (IsRec(r) and IsBound(r.isPolynomial) and r.isPolynomial)  then
  366.  
  367.         # <l> must have the rationals as base ring
  368.         if Rationals <> l.baseRing  then
  369.             Error( "<l> must have the rationals as base ring" );
  370.         fi;
  371.  
  372.         # <r> must lie in the base ring of <r>
  373.     if not IsRat(r)  then
  374.         Error( "<r> must lie in the base ring of <l>" );
  375.     fi;
  376.     if r = l.baseRing.zero or l.coefficients = []  then
  377.         prd := [];
  378.         val := 0;
  379.         else
  380.         prd := l.coefficients * r;
  381.         val := l.valuation;
  382.     fi;
  383.  
  384.         # compute the product
  385.         prd            := RationalsOps.FastPolynomial( Rationals, prd, val );
  386.         prd.depth      := 1;
  387.         prd.groundRing := Rationals;
  388.  
  389.         # and return
  390.         return prd;
  391.  
  392.     # our superclass will handle different depth
  393.     elif 1 <> l.operations.Depth(l) or 1 <> r.operations.Depth(r) then
  394.         return PolynomialOps.\*( l, r );
  395.  
  396.     # give up if we have rings other then the rationals
  397.     elif Rationals <> l.baseRing  then
  398.         Error( "<l> must have the rationals as base ring" );
  399.     elif Rationals <> r.baseRing  then
  400.         Error( "<r> must have the rationals as base ring" );
  401.  
  402.     # if <l> is the null polynomial return <l>
  403.     elif Length(l.coefficients) = 0  then
  404.     return l;
  405.  
  406.     # if <r> is the null polynomial return <r>
  407.     elif Length(r.coefficients) = 0  then
  408.         return r;
  409.  
  410.     # multiply two polynomials
  411.     else
  412.  
  413.         # get a common ring
  414.         R := l.baseRing;
  415.  
  416.         # use 'ProductCoeffs' in order to fold product
  417.         prd := ProductCoeffs( l.coefficients, r.coefficients );
  418.     val := l.valuation + r.valuation;
  419.  
  420.         # compute the product
  421.         prd            := R.operations.FastPolynomial( R, prd, val );
  422.         prd.depth      := 1;
  423.         prd.groundRing := Rationals;
  424.  
  425.         # and return
  426.         return prd;
  427.  
  428.     fi;
  429.  
  430. end;
  431.  
  432.  
  433. #############################################################################
  434. ##
  435. #F  RationalsPolynomialOps.\mod  . . . . . . .  remainder of two polynomials
  436. ##
  437. RationalsPolynomialOps.\mod := function( l, r )
  438.     local   R,  rem,  val,  vdf;
  439.  
  440.     # <l> must be a polynomial
  441.     if not IsPolynomial(l)  then
  442.         Error( "<l> must be a polynomial" );
  443.     fi;
  444.  
  445.     # if <r> is a integer reduce the coefficients of <l>
  446.     if IsInt(r)  then
  447.     rem := List( l.coefficients, x -> x mod r );
  448.     return Polynomial( l.baseRing, rem, l.valuation );
  449.     fi;
  450.  
  451.  
  452.     # otherwise <r> must be a non-zero polynomial
  453.     if not IsPolynomial(r)  then
  454.         Error( "<r> must be a polynomial" );
  455.     fi;
  456.     if Length(r.coefficients) = 0  then
  457.         Error( "<r> must be non zero" );
  458.     fi;
  459.  
  460.     # our superclass will handle different depth
  461.     if l.operations.Depth(l) <> r.operations.Depth(r)  then
  462.         return PolynomialOps.\mod( l, r );
  463.  
  464.     # give up if we have different rings
  465.     elif l.baseRing <> r.baseRing  then
  466.         Error( "polynomials must have the same ring" );    
  467.  
  468.     # multiply two polynomials
  469.     else
  470.  
  471.         # if one is a Laurent polynomial use 'Mod'
  472.         if l.valuation < 0 or r.valuation < 0  then
  473.             return Mod( DefaultRing(l,r), l, r );
  474.         fi;
  475.  
  476.         # get a common ring and the value difference
  477.         R   := l.baseRing;
  478.         vdf := r.valuation - l.valuation;
  479.  
  480.         # if <r>.valuation is the minimum shift <l>
  481.         if r.valuation < l.valuation  then
  482.             val := r.valuation;
  483.             rem := ShiftedCoeffs( l.coefficients, -vdf );
  484.             ReduceCoeffs( rem, r.coefficients );
  485.  
  486.         # if <l>.valuation is the minimum shift <r>
  487.         elif l.valuation < r.valuation  then
  488.             r   := ShiftedCoeffs( r.coefficients, vdf );
  489.             rem := RemainderCoeffs( l.coefficients, r );
  490.             val := l.valuation;
  491.  
  492.         # otherwise they are equal
  493.         else
  494.             rem := RemainderCoeffs( l.coefficients, r.coefficients );
  495.             val := l.valuation;
  496.         fi;
  497.     fi;
  498.  
  499.     # return the remainder
  500.     return R.operations.Polynomial( R, rem, val );
  501.  
  502. end;
  503.  
  504.  
  505. #############################################################################
  506. ##
  507. #F  RationalsPolynomialOps.\^  . . . . . . . . . . .  power of a polynomials
  508. ##
  509. RationalsPolynomialOps.\^ := function( l, r )
  510.     local   R,  pow, val;
  511.  
  512.     # <l> must be a polynomial over the rationals and <r> an integer
  513.     if not IsPolynomial(l) or l.baseRing <> Rationals  then
  514.         Error( "<l> must be a polynomial over the rationals" );
  515.     fi;
  516.     if not IsInt(r)  then
  517.         Error( "<r> must be an integer" );
  518.     fi;
  519.  
  520.     # invert <l> if necessary
  521.     if r < 0  then
  522.         R := LaurentPolynomialRing( l.baseRing );
  523.         l := R.operations.Quotient( R, R.one, l );
  524.         r := -r;
  525.     fi;
  526.     R := l.baseRing;
  527.  
  528.     # if <r> is zero, return x^0
  529.     if r = 0  then
  530.         return RationalsOps.FastPolynomial( Rationals, [R.one], 0 );
  531.  
  532.     # if <r> is one return <l>
  533.     elif r = 1  then
  534.         return l;
  535.     fi;
  536.  
  537.     # if <l> is trivial return
  538.     if Length(l.coefficients) = 0  then
  539.         return l;
  540.  
  541.     # if <l> is of degree less than 2, return
  542.     elif Length(l.coefficients) = 1  then
  543.         return RationalsOps.FastPolynomial(
  544.                    Rationals,
  545.                    [l.coefficients[1]^r],
  546.                    l.valuation*r );
  547.     fi;
  548.  
  549.     # use repeated squaring
  550.     val := l.valuation * r;
  551.     l   := l.coefficients;
  552.     pow := [ R.one ];
  553.     while 0 < r  do
  554.         if r mod 2 = 1  then
  555.         pow := ProductCoeffs( pow, l );
  556.             r   := r - 1;
  557.         fi; 
  558.         if 1 < r  then
  559.         l := ProductCoeffs( l, l );
  560.             r := r / 2;
  561.         fi;
  562.     od;
  563.  
  564.     # return the power
  565.     return RationalsOps.FastPolynomial( Rationals, pow, val );
  566.  
  567. end;
  568.  
  569.  
  570. #############################################################################
  571. ##
  572. #F  RationalsPolynomialOps.String( <f> )  . . . . . construct a pretty string
  573. ##
  574. RationalsPolynomialOps.String := function( f )
  575.     local   x,  i,  d,  v,  s,  l;
  576.  
  577.     # find a name for the indeterminate
  578.     x := Indeterminate(f.baseRing);
  579.     if IsBound(x.name)  then x := x.name;  else x := "x";  fi;
  580.  
  581.     # run through the coefficients of <f>
  582.     v := f.valuation-1;
  583.     l := Length(f.coefficients);
  584.     for i  in Reversed([ 1 .. l ])  do
  585.         d := f.coefficients[i];
  586.         if 0 <> d  then
  587.             if i = l and d = 1 and i+v <> 0  then
  588.                 s := "";
  589.             elif i = l and d = 1  then
  590.                 s := "1";
  591.             elif i = l and d = -1 and i+v <> 0  then
  592.                 s := "-";
  593.             elif i = l and d = -1  then
  594.                 s := "-1";
  595.             elif i = l  then
  596.                 s := String(d);
  597.             elif d = 1 and i+v <> 0  then
  598.                 s := ConcatenationString( s, "+" );
  599.             elif d = 1  then
  600.                 s := ConcatenationString( s, "+1" );
  601.             elif d = -1 and i+v <> 0  then
  602.                 s := ConcatenationString( s, "-" );
  603.             elif d = -1  then
  604.                 s := ConcatenationString( s, "-1" );
  605.             elif d < 0  then
  606.                 s := ConcatenationString( s, String(d) );
  607.             elif 0 < d  then
  608.                 s := ConcatenationString( s, "+", String(d) );
  609.             else
  610.                 Error( "internal error in 'RationalsPolynomialOps.String'" );
  611.             fi;
  612.             if i+v < 0 or 1 < i+v then
  613.                 s := ConcatenationString( s, x, "^", String(i+v) );
  614.             elif i+v = 1  then
  615.                 s := ConcatenationString( s, x );
  616.             fi;
  617.     fi;
  618.     od;
  619.  
  620.     # catch a special case
  621.     if l = 0  then s := "0";  fi;
  622.     return s;
  623.  
  624. end;
  625.  
  626.  
  627.  
  628. #############################################################################
  629. ##
  630.  
  631. #V  RationalsPolynomials  . . . . .  domain of polynomials over the rationals
  632. ##
  633. RationalsPolynomials             := Copy( Polynomials );
  634. RationalsPolynomials.name        := "RationalsPolynomials";
  635. RationalsPolynomials.operations  := Copy( FieldPolynomialRingOps );
  636. RationalsPolynomialsOps          := RationalsPolynomials.operations;
  637.  
  638. # show that this a polynomial ring
  639. RationalsPolynomials.isPolynomialRing := true;
  640.  
  641. # rationals polynomials form a ring
  642. RationalsPolynomials.isDomain := true;
  643. RationalsPolynomials.isRing   := true;
  644.  
  645. # set known properties
  646. RationalsPolynomials.isFinite := false;
  647. RationalsPolynomials.size     := "infinity";
  648.  
  649. # add properties of polynom ring over a field
  650. RationalsPolynomials.isCommutativeRing         := true;
  651. RationalsPolynomials.isIntegralRing            := true;
  652. RationalsPolynomials.isUniqueFactorizationRing := true;
  653. RationalsPolynomials.isEuclideanRing           := true;
  654.  
  655. # set one, zero and base ring
  656. RationalsPolynomials.one  := Polynomial( Rationals, [ 1 ] );
  657. RationalsPolynomials.zero := Polynomial( Rationals, [] );
  658. RationalsPolynomials.baseRing := Rationals;
  659.  
  660.  
  661. #############################################################################
  662. ##
  663. #F  RationalsPolynomialsOps.\in  . . . . . . . . . . . . . . membership test
  664. ##
  665. RationalsPolynomialsOps.\in := function( p, RationalsPolynomials )
  666.     return     IsRec( p )
  667.            and IsBound( p.isPolynomial )
  668.            and p.isPolynomial
  669.            and IsField( p.baseRing )
  670.        and 0 <= p.valuation
  671.            and p.baseRing = Rationals;
  672. end;
  673.  
  674.  
  675. #############################################################################
  676. ##
  677. #F  RationalsPolynomialsOps.DefaultRing( <L> )    . . . . . . . .  default ring
  678. ##
  679. RationalsPolynomialsOps.DefaultRing := PolynomialsOps.DefaultRing;
  680.  
  681.  
  682. #############################################################################
  683. ##
  684. #F  RationalsPolynomialsOps.PowerMod( <R>, <g>, <e>, <m> )  . . . . . . power
  685. ##
  686. RationalsPolynomialsOps.PowerMod := function( R, g, e, m )
  687.  
  688.     # if <m> is of degree one return the zero polynomial
  689.     if Degree(m) = 1  then
  690.     return R.zero;
  691.  
  692.     # if <e> is zero return one
  693.     elif e = 0  then
  694.     return R.one;
  695.     fi;
  696.  
  697.     # reduce polynomial
  698.     g := R.operations.Mod( R, g, m );
  699.  
  700.     # and invert if necessary
  701.     if e < 0  then
  702.     g := R.operations.QuotientMod( R, R.one, g, m );
  703.         if g = false  then
  704.         Error( "<g> must be invertable module <m>" );
  705.         fi;
  706.         e := -e;
  707.     fi;
  708.  
  709.     # use 'PowerModCoeffs' to power polynomial
  710.     g := ShiftedCoeffs( g.coefficients, g.valuation );
  711.     m := ShiftedCoeffs( m.coefficients, m.valuation );
  712.     return Polynomial( R.baseRing, PowerModCoeffs( g, e, m ) );
  713.  
  714. end;
  715.  
  716.  
  717. #############################################################################
  718. ##
  719. #F  RationalsPolynomialsOps.IntegerPolynomial( <R>, <f> ) . . . . convert <f>
  720. ##
  721. RationalsPolynomialsOps.IntegerPolynomial := function( R, f )
  722.     local   lcm,  c;
  723.  
  724.     # compute lcm of denominator
  725.     lcm := 1;
  726.     for c  in f.coefficients  do
  727.     lcm := LcmInt( lcm, Denominator(c) );
  728.     od;
  729.  
  730.     # remove all denominators
  731.     f := f * lcm;
  732.  
  733.     # remove gcd of coefficients
  734.     return f * (1/Gcd(f.coefficients));
  735.  
  736. end;
  737.  
  738.  
  739. #############################################################################
  740. ##
  741.  
  742. #F  LandauMignotteBoundGcd( <f>, <g> )    . . . .  bound for gcd of <f> and <g>
  743. ##
  744. LandauMignotteBoundGcd := function( f, g )
  745.     local  A,  B,  sum,  srt;
  746.  
  747.     # compute norm of <f>
  748.     sum := Sum( f.coefficients, x -> x^2 );
  749.     srt := RootInt( sum, 2 );
  750.     if srt*srt < sum  then srt := srt+1;  fi;
  751.     A := srt / AbsInt(LeadingCoefficient(f));
  752.  
  753.     # compte norm of <g>
  754.     sum := Sum( g.coefficients, x -> x^2 );
  755.     srt := RootInt( sum, 2 );
  756.     if srt*srt < sum  then srt := srt+1;  fi;
  757.     B := srt / AbsInt(LeadingCoefficient(g));
  758.  
  759.     # return the bound
  760.     return   2^Minimum( Degree(f), Degree(g) )
  761.            * GcdInt( LeadingCoefficient(f), LeadingCoefficient(g) )
  762.            * Minimum( A, B );
  763.  
  764. end;
  765.  
  766.  
  767. #############################################################################
  768. ##
  769. #F  RationalsPolynomialsOps.GcdModPrime( <f>, <g>, <p>, <a> ) . . gcd mod <p>
  770. ##
  771. RationalsPolynomialsOps.GcdModPrime := function( f, g, p, a )
  772.     local   F,  c,  tab,  cof,  log,  x;
  773.  
  774.     # compute in the finite field F_<p>
  775.     f := f mod p;
  776.     g := g mod p;
  777.     F := GF(p);
  778.     c := Gcd( Polynomial( F, f.coefficients*F.one, f.valuation ),
  779.               Polynomial( F, g.coefficients*F.one, g.valuation ) );
  780.  
  781.     # convert back to integers
  782.     tab := IntegerTable(F);
  783.     cof := [];
  784.     for x  in [ 1 .. Length(c.coefficients) ]  do
  785.         log := LogVecFFE(c.coefficients,x);
  786.         if log = false  then
  787.             Add( cof, 0 );
  788.         else
  789.             Add( cof, (tab[log+1]*a) mod p );
  790.         fi;
  791.     od;
  792.     return Polynomial( f.baseRing, cof, c.valuation );
  793.  
  794. end;
  795.  
  796.  
  797. #############################################################################
  798. ##
  799. #F  RationalsPolynomialsOps.Gcd( <R>, <f>, <g> )  . . . . gcd of <f> and <g>
  800. ##
  801. RationalsPolynomialsOps.Gcd := function( R, f, g )
  802.  
  803.     # check trivial cases
  804.     if -1 = Degree(f)  then
  805.         return g;
  806.     elif -1 = Degree(g)  then
  807.         return f;
  808.     elif 0 = Degree(f) or 0 = Degree(g)  then
  809.         return R.one;
  810.     fi;
  811.  
  812.     # convert polynomials into integer polynomials
  813.     f := R.operations.IntegerPolynomial( R, f );
  814.     g := R.operations.IntegerPolynomial( R, g );
  815.     InfoPoly2( "#I  <f> = ", f, "\n" );
  816.     InfoPoly2( "#I  <g> = ", g, "\n" );
  817.  
  818.     # return the standard associate
  819.     return StandardAssociate( R, R.operations.IGcd( R, f, g ) );
  820.  
  821. end;
  822.  
  823. RationalsPolynomialsOps.IGcd := function( R, f, g )
  824.     local   a,  t;
  825.  
  826.     # compute the Landau Mignotte bound for the gcd
  827.     t := rec( prime := 1 );
  828.     t.bound := 2 * Int(LandauMignotteBoundGcd( f, g )+1);
  829.     InfoPoly2( "#I  Landau-Mignotte bound = ", t.bound/2, "\n" );
  830.  
  831.     # avoid gcd of leading coefficients
  832.     a := GcdInt( LeadingCoefficient(f), LeadingCoefficient(g) );
  833.     repeat
  834.  
  835.         # start with first prime avoiding gcd of leading coefficients
  836.         repeat t.prime := NextPrimeInt(t.prime);  until a mod t.prime <> 0;
  837.  
  838.         # compute modular gcd with leading coefficient <a>
  839.         t.gcd := RationalsPolynomialsOps.GcdModPrime( f, g, t.prime, a );
  840.         InfoPoly2( "#I  gcd mod ", t.prime, " = ", t.gcd, "\n" );
  841.  
  842.         # loop until we have success
  843.         repeat
  844.             if 0 = Degree(t.gcd)  then
  845.                 InfoPoly2( "#I  <f> and <g> are relative prime\n" );
  846.                 return R.one;
  847.             fi;
  848.         until RationalsPolynomialsOps.Gcd1( R, t, a, f, g );
  849.     until t.correct;
  850.  
  851.     # return the gcd
  852.     return t.gcd;
  853.  
  854. end;
  855.  
  856. RationalsPolynomialsOps.Gcd1 := function( R, t, a, f, g )
  857.     local   G,  P;
  858.  
  859.     # <P> will hold the product of primes use so far
  860.     t.modulo := t.prime;
  861.  
  862.     # <G> will hold the approximation of the gcd
  863.     G := t.gcd;
  864.  
  865.     # use next prime until we reach the Landau-Mignotte bound
  866.     while t.modulo < t.bound  do
  867.         repeat t.prime := NextPrimeInt(t.prime);  until a mod t.prime <> 0;
  868.  
  869.         # compute modular gcd
  870.         t.gcd := RationalsPolynomialsOps.GcdModPrime( f, g, t.prime, a );
  871.         InfoPoly2( "#I  gcd mod ", t.prime, " = ", t.gcd, "\n" );
  872.  
  873.         # if the degree of <C> is smaller we started with wrong <p>
  874.         if Degree(t.gcd) < Degree(G)  then
  875.             InfoPoly2( "#I  found lower degree, restarting\n" );
  876.             return false;
  877.         fi;
  878.  
  879.         # if the degrees of <C> and <G> are equal use chinese remainder
  880.         if Degree(t.gcd) = Degree(G)  then
  881.             P := G;
  882.             G := RationalsPolynomialsOps.GcdCRT(G,t.modulo,t.gcd,t.prime);
  883.             t.modulo := t.modulo * t.prime;
  884.             InfoPoly2( "#I  gcd mod ", t.modulo, " = ", G, "\n" );
  885.             if G = P  then
  886.                 t.correct :=     Quotient(R,f,G)<>false
  887.                              and Quotient(R,g,G)<>false;
  888.                 if t.correct  then
  889.                     InfoPoly2( "#I  found correct gcd\n" );
  890.                     t.gcd := G;
  891.                     return true;
  892.                 fi;
  893.             fi;
  894.         fi;
  895.     od;
  896.  
  897.     # check if <G> is correct but return 'true' in any case
  898.     t.correct := Quotient(R,f,G)<>false and Quotient(R,g,G)<>false;
  899.     t.gcd := G;
  900.     return true;
  901.  
  902. end;
  903.  
  904. RationalsPolynomialsOps.GcdCRT := function( f, p, g, q )
  905.     local   min,  cf,  lf,  cg,  lg,  i,  P,  m,  r;
  906.  
  907.     # remove valuation
  908.     min := Minimum( f.valuation, g.valuation );
  909.     if f.valuation <> min  then    
  910.         cf := ShiftedCoeffs( f.coefficients, f.valuation - min );
  911.     else
  912.         cf := ShallowCopy(f.coefficients);
  913.     fi;
  914.     lf := Length(cf);
  915.     if g.valuation <> min  then    
  916.         cg := ShiftedCoeffs( g.coefficients, g.valuation - min );
  917.     else
  918.         cg := ShallowCopy(g.coefficients);
  919.     fi;
  920.     lg := Length(cg);
  921.  
  922.     # use chinese remainder
  923.     r := [ p, q ];
  924.     P := p * q;
  925.     m := P/2;
  926.     for i  in [ 1 .. Minimum(lf,lg) ]  do
  927.         cf[i] := ChineseRem( r, [ cf[i], cg[i] ] );
  928.         if m < cf[i]  then cf[i] := cf[i] - P;  fi;
  929.     od;
  930.     if lf < lg  then
  931.         for i  in [ lf+1 .. lg ]  do
  932.             cf[i] := ChineseRem( r, [ 0, cg[i] ] );
  933.             if m < cf[i]  then cf[i] := cf[i] - P;  fi;
  934.         od;
  935.     elif lg < lf  then
  936.         for i  in [ lg+1 .. lf ]  do
  937.             cf[i] := ChineseRem( r, [ cf[i], 0 ] );
  938.             if m < cf[i]  then cf[i] := cf[i] - P;  fi;
  939.         od;
  940.     fi;
  941.  
  942.     # return the polynomial
  943.     return Polynomial( f.baseRing, cf, min );
  944.  
  945. end;
  946.  
  947.  
  948. #############################################################################
  949. ##
  950.  
  951. #F  RationalsPolynomialsOps.QuotientModPrime(<R>,<f>,<g>,<p>) . . .  quotient
  952. ##
  953. RationalsPolynomialsOps.QuotientModPrime := function( R, f, g, p )
  954.     local   m,  n,  i,  k,  c,  q,  R,  val;
  955.  
  956.     # get base ring
  957.     R := R.baseRing;
  958.  
  959.     # reduce <f> and <g> mod <p>
  960.     f := f mod p;
  961.     g := g mod p;
  962.  
  963.     # if <f> is zero return it
  964.     if 0 = Length(f.coefficients)  then
  965.     return f;
  966.     fi;
  967.  
  968.     # check the value of the valuation of <f> and <g>
  969.     if f.valuation < g.valuation  then
  970.         return false;
  971.     fi;
  972.     val := f.valuation - g.valuation;
  973.  
  974.     # Try to divide <f> by <g>, compute mod <p>
  975.     q := [];
  976.     n := Length( g.coefficients );
  977.     m := Length( f.coefficients ) - n;
  978.     f := ShallowCopy( f.coefficients );
  979.     for i  in [0 .. m ]  do
  980.         c := f[m-i+n] / g.coefficients[n] mod p;
  981.         for k  in [ 1 .. n ]  do
  982.             f[m-i+k] := ( f[m-i+k] - c * g.coefficients[k] ) mod p;
  983.         od;
  984.         q[m-i+1] := c;
  985.     od;
  986.  
  987.     # Did the division work?
  988.     for i  in [ 1 .. m+n ]  do
  989.         if f[i] <> R.zero  then
  990.             return false;
  991.         fi;
  992.     od;
  993.     return Polynomial( R, q, val );
  994.  
  995. end;
  996.  
  997.  
  998. #############################################################################
  999. ##
  1000. #F  LandauMignotteBound( <f> )  . . . . . . . . . . bound for factors of <f>
  1001. ##
  1002. LandauMignotteBound := function( f )
  1003.     local   sum,  srt;
  1004.  
  1005.     sum := Sum( f.coefficients, x -> x^2 );
  1006.     srt := RootInt( sum, 2 );
  1007.     if srt*srt < sum  then srt := srt + 1;  fi;
  1008.     return 2^Degree(f) * srt;
  1009. end;
  1010.     
  1011.  
  1012. #############################################################################
  1013. ##
  1014. #F  RationalsPolynomialsOps.SquareHensel( <R>, <f>, <lp> )
  1015. ##
  1016. RationalsPolynomialsOps.SquareHensel := function( R, f, lp )
  1017.  
  1018.     local   p,              # prime of <lp>
  1019.             q,              # current modulus
  1020.             q1,             # last modulus
  1021.             q2,             # <q> / 2
  1022.             lc,             # leading coefficient of <f>
  1023.             k,              # Landau-Mignotte bound
  1024.             prd,            # product of <lp> or <l>
  1025.             pd2,            # product of <l>
  1026.             rp,             # representation of gcd(<lp>)
  1027.             tab,            # integer table of <fp>
  1028.             rep,            # lifted representation of gcd(<lp>)
  1029.             fac,            # true factor found so far
  1030.             fcn,            # index of true factor in <l>
  1031.             dis,            # distance of <f> and <l>
  1032.             cor,            # correction
  1033.             rcr,            # inverse corrections
  1034.             quo,            # quotient
  1035.             sum,            # temp
  1036.             aa, bb,         # left and right subproducts
  1037.             l,              # factors mod <q>
  1038.             lq1,            # factors mod <q1>
  1039.             g, cof, log,    # temps
  1040.             i, j,  x;       # loop
  1041.  
  1042.     # get the leading coefficient of <f>
  1043.     lc := LeadingCoefficient(f);
  1044.  
  1045.     # compute the Landau-Mignotte bound
  1046.     k := 2 * AbsInt(lc) * LandauMignotteBound(f);
  1047.     InfoPoly2( "#I  Landau-Mignotte bound = ", k/2/AbsInt(lc), "\n" );
  1048.  
  1049.     # get the prime <p>
  1050.     p := lp[1].baseRing.char;
  1051.  
  1052.     # compute the representation of 1 mod <p>
  1053.     prd := Product(lp);
  1054.     rp  := GcdRepresentation( List( lp, x -> Quotient( prd, x ) ) );
  1055.  
  1056.     # convert representation <rp> back to the integers
  1057.     tab := IntegerTable( lp[1].baseRing );
  1058.     rep := [];
  1059.     for g  in rp  do
  1060.         cof := [];
  1061.         for x  in [ 1 .. Length(g.coefficients) ]  do
  1062.             log := LogVecFFE(g.coefficients,x);
  1063.             if log = false  then
  1064.                 Add( cof, 0 );
  1065.             else
  1066.                 Add( cof, tab[log+1] );
  1067.             fi;
  1068.         od;
  1069.         Add( rep, Polynomial( Rationals, cof, g.valuation ) );
  1070.     od;
  1071.  
  1072.     # convert factors <lp> back to the integers
  1073.     l := [];
  1074.     for g  in lp  do
  1075.         cof := [];
  1076.         for x  in [ 1 .. Length(g.coefficients) ]  do
  1077.             log := LogVecFFE(g.coefficients,x);
  1078.             if log = false  then
  1079.                 Add( cof, 0 );
  1080.             else
  1081.                 Add( cof, tab[log+1] );
  1082.             fi;
  1083.         od;
  1084.         Add( l, Polynomial( Rationals, cof, g.valuation ) );
  1085.     od;
  1086.  
  1087.     # and check it
  1088.     InfoPoly3( "#C  difference mod ", p, " = ",
  1089.                ((1/lc mod p)*f-Product(l)) mod p, " (should be 0)\n" );
  1090.  
  1091.     # start Hensel until <q> is greater than k
  1092.     q   := p^2;
  1093.     q1  := p;
  1094.     fac := [];
  1095.     while q1 < k  do
  1096.         InfoPoly2( "#I  computing mod ", q, "\n" );
  1097.  
  1098.         # compute discrepancies for factors
  1099.         dis := ( ( ( 1/lc mod q ) * f - Product(l) ) mod q ) * (1/q1);
  1100.         InfoPoly2( "#I  discrepancy = ", dis, "\n" );
  1101.  
  1102.         # compute corrections for factors
  1103.         lq1 := ShallowCopy(l);
  1104.         cor := [];
  1105.         for i  in [ 1 .. Length(l) ]  do
  1106.             cor[i] := rep[i] * dis mod l[i] mod q1;
  1107.             InfoPoly2( "#I  ", i, ".th correction = ", cor[i], "\n" );
  1108.             if 0 < Length(cor[i].coefficients)  then
  1109.                 l[i] := l[i] + q1 * cor[i];
  1110.             fi;
  1111.             InfoPoly2( "#I  ", i, ".th factor = ", l[i], "\n" );
  1112.         od;
  1113.  
  1114.         # if this is not the last step update <rep>
  1115.         if q < k  then
  1116.  
  1117.             # compute the products Product(<lq1>)/<lq1>[i]
  1118.             aa := [ R.one ];
  1119.             for i  in [ 1 .. Length(l)-1 ]  do
  1120.                 aa[i+1] := aa[i] * lq1[i] mod q;
  1121.             od;
  1122.             bb := [ R.one ];
  1123.             for i  in [ 1 .. Length(l)-1 ]  do
  1124.                 bb[i+1] := bb[i] * lq1[Length(l)+1-i] mod q;
  1125.             od;
  1126.             bb := Reversed(bb);
  1127.  
  1128.             # compute discrepancies for inverses
  1129.             rcr := [];
  1130.             for i  in [ 1 .. Length(l) ]  do
  1131.                 prd := aa[i] * bb[i] mod q;
  1132.                 dis := ( ( 1 - rep[i] * prd ) mod l[i] mod q ) * (1/q1);
  1133.                 InfoPoly2( "#I  ", i, ".th rep discrepancy = ", dis, "\n" );
  1134.                 sum := 0 * dis;
  1135.                 prd := prd mod q1;
  1136.                 for j  in [ 1 .. Length(l) ]  do
  1137.                     if j <> i  then
  1138.                       quo := R.operations.QuotientModPrime(R,prd,lq1[j],q1);
  1139.                        sum := sum + quo * cor[j];
  1140.                     fi;
  1141.                 od;
  1142.                 rcr[i] := (rep[i]*(dis-rep[i]*sum)) mod lq1[i] mod q1;
  1143.                 InfoPoly2("#I  ", i, ".th rep correction = ", rcr[i], "\n");
  1144.             od;
  1145.  
  1146.             # correct the inverses
  1147.             for i  in [ 1 .. Length(l) ]  do
  1148.                 rep[i] := ( rep[i] + q1 * rcr[i] ) mod q;
  1149.                 InfoPoly2( "#I  ", i, ".th representation = ", rep[i], "\n" );
  1150.             od;
  1151.         fi;
  1152.  
  1153.         # check for true factors
  1154.         fcn := [];
  1155.         q2  := q/2;
  1156.         for i  in [ 1 .. Length(l) ]  do
  1157.             if 0 = Length(cor[i].coefficients)  then
  1158.                 g := [];
  1159.                 for j  in [ 1 .. Length(l[i].coefficients) ]  do
  1160.                     g[j] := ( l[i].coefficients[j] * lc ) mod q;
  1161.                     if q2 < g[j]  then
  1162.                         g[j] := g[j] - q;
  1163.                     fi;
  1164.                 od;
  1165.                 g := Polynomial( Rationals, g * (1/Gcd(g)), l[i].valuation );
  1166.                 if f.coefficients[1] mod g.coefficients[1] = 0
  1167.                    and LeadingCoefficient(f)
  1168.                        mod LeadingCoefficient(g) = 0
  1169.                 then
  1170.                     quo := Quotient( R, f, g );
  1171.                     if quo <> false  then
  1172.                         InfoPoly2( "#I  found true factor = ", l[i], "\n" );
  1173.                         Add( fcn, i );
  1174.                         f := quo;
  1175.                     fi;
  1176.                 fi;
  1177.             fi;
  1178.         od;
  1179.  
  1180.         # if we have found a true factor update everything
  1181.         if 0 < Length(fcn)  then
  1182.  
  1183.             # append factors to <fac>
  1184.             Append( fac, Sublist( l, fcn ) );
  1185.  
  1186.             # compute new Landau-Mignotte bound
  1187.             lc := LeadingCoefficient(f);
  1188.             k  := 2 * AbsInt(lc) * LandauMignotteBound(f);
  1189.             InfoPoly2( "#I  new L-M bound = ", k/2/AbsInt(lc), "\n" );
  1190.  
  1191.             # remove true factors from <l> and corresponding <rep>
  1192.             prd := Product( Sublist( l, fcn ) ) mod q;
  1193.             fcn := Filtered( [ 1 .. Length(l) ], x -> not x in fcn );
  1194.             l   := Sublist( l, fcn );
  1195.             rep := List( Sublist( rep, fcn ), x -> prd * x );
  1196.  
  1197.             # reduce <rep>[i] mod <l>[i]
  1198.             for i  in [ 1 .. Length(l) ]  do
  1199.                 rep[i] := rep[i] mod l[i] mod q;
  1200.             od;
  1201.         fi;
  1202.  
  1203.         # and check it
  1204.         if q < k and InfoPoly3 <> Ignore  then
  1205.             prd := Product(l);
  1206.             for i  in [ 1 .. Length(l) ]  do
  1207.                 InfoPoly3( "#C  rep[", i, "] * P[", i, "] = ",
  1208.                            (rep[i]*Quotient(R,prd,l[i])) mod l[i] mod q,
  1209.                            " (should be 1)\n" );
  1210.             od;
  1211.         fi;
  1212.         InfoPoly3( "#C  difference mod ", q, " = ",
  1213.                    ((1/lc mod q)*f-Product(l)) mod q,
  1214.                    " (should be 0)\n" );
  1215.  
  1216.         # square modulus
  1217.         q1 := q;
  1218.         q  := q^2;
  1219.     od;
  1220.  
  1221.     # convert the coefficients c_i such that |c_i| <= k/2
  1222.     rep := [];
  1223.     q2  := q1 / 2;
  1224.     for g  in l  do
  1225.         cof := ShallowCopy(g.coefficients);
  1226.         for x  in [ 1 .. Length(cof) ]  do
  1227.             cof[x] := cof[x]*lc mod q1;
  1228.             if q2 < cof[x]  then
  1229.                 cof[x] := cof[x] - q1;
  1230.             fi;
  1231.         od;
  1232.  
  1233.         # make polynomial primitive
  1234.         g := Polynomial( Rationals, cof * (1/Gcd(cof)), g.valuation );
  1235.  
  1236.         # check if <cof> is a true factor
  1237.         if f.coefficients[1] mod g.coefficients[1] = 0
  1238.            and LeadingCoefficient(f) mod LeadingCoefficient(g) = 0
  1239.         then
  1240.             quo := Quotient( R, f, g );
  1241.             if quo <> false  then     
  1242.                 InfoPoly2( "#I  found a true factor = ", g, "\n" );
  1243.                 Add( fac, g );
  1244.                 f  := quo;
  1245.                 lc := LeadingCoefficient(f);
  1246.             else
  1247.                 Add( rep, g );
  1248.             fi;
  1249.         else
  1250.             Add( rep, g );
  1251.         fi;
  1252.     od;
  1253.  
  1254.     # return the result
  1255.     return rec( polynomial     := f,
  1256.                 factors        := fac,
  1257.                 remaining      := rep,
  1258.                 landauMignotte := LandauMignotteBound(f) * AbsInt(lc),
  1259.                 primePower     := q1,
  1260.                 primePower2    := q1/2 );
  1261.  
  1262. end;
  1263.  
  1264.  
  1265. #############################################################################
  1266. ##
  1267. #F  RationalsPolynomialsOps.FactorsModPrime( <R>, <f> )      find suitable prime
  1268. ##
  1269. ##  <f> must be squarefree.  We test 3 "small" and 2 "big" primes.
  1270. ##
  1271. RationalsPolynomialsOps.FactorsModPrime := function( R, f )
  1272.  
  1273.     local   i,          # loop
  1274.             lc,         # leading coefficient of <f>
  1275.             p,          # current prime
  1276.             PR,         # polynomial ring over F_<p>
  1277.             fp,         # <f> in <R>
  1278.             lp,         # factors of <fp>
  1279.             min,        # minimal number of factors so far
  1280.             P,          # best prime so far
  1281.             LP,         # factorization of <f> mod <P>
  1282.             deg,        # possible degrees of factors
  1283.             t,          # return record
  1284.             tmp;
  1285.  
  1286.     # set minimal number of factors to the degree of <f>
  1287.     min := Degree(f)+1;
  1288.     lc  := LeadingCoefficient(f);
  1289.  
  1290.     # find a suitable prime
  1291.     t := rec();
  1292.     p := 1;
  1293.     for i  in [ 1 .. 5 ]  do
  1294.  
  1295.         # reset <p> to big prime after first 3 test
  1296.         if i = 4  then p := Maximum( p, 1000 );  fi;
  1297.  
  1298.         # find a prime not dividing <lc> and <f>_<p> squarefree
  1299.         repeat
  1300.             repeat
  1301.                 p  := NextPrimeInt(p);
  1302.             until lc mod p <> 0;
  1303.             PR  := PolynomialRing(GF(p));
  1304.             tmp := 1/lc mod p;
  1305.             fp  := List( f.coefficients, x->(tmp*x mod p)*PR.baseRing.one );
  1306.             fp  := Polynomial( PR.baseRing, fp, f.valuation );
  1307.         until 0 = Degree(Gcd(fp,Derivative(fp)));
  1308.  
  1309.         # factorise <f> modulo <p>
  1310.         lp := PR.operations.Factors( PR, fp );
  1311.  
  1312.         # if <fp> is irreducible so is <f>
  1313.         if 1 = Length(lp)  then
  1314.             InfoPoly2( "#I  <f> mod ", p, " is irreducible\n" );
  1315.             t.isIrreducible := true;
  1316.             return t;
  1317.         else
  1318.             InfoPoly2( "#I  found ", Length(lp), " factors mod ", p, "\n" );
  1319.         fi;
  1320.  
  1321.         # choose a minimal prime with minimal number of factors
  1322.         if Length(lp) <= min  then
  1323.             min := Length(lp);
  1324.             P   := p;
  1325.             LP  := lp;
  1326.         fi;
  1327.  
  1328.         # compute the possible degrees
  1329.         tmp := Set( List( Combinations( List( lp, Degree ) ), g -> Sum(g) ) );
  1330.         if 1 = i  then
  1331.             deg := tmp;
  1332.         else
  1333.             deg := Intersection( deg, tmp );
  1334.         fi;
  1335.  
  1336.         # if there is only one possible degree != 0 then <f> is irreducible
  1337.         if 2 = Length(deg)  then
  1338.             InfoPoly2( "#I  <f> must be irreducible, only one degree left\n" );
  1339.             t.isIrreducible := true;
  1340.             return t;
  1341.         fi;
  1342.         
  1343.     od;
  1344.  
  1345.     # return the chosen prime
  1346.     InfoPoly2( "#I  choosing prime ", P, " with ", Length(LP), " factors\n" );
  1347.     t.isIrreducible := false;
  1348.     t.prime         := P;
  1349.     t.factors       := LP;
  1350.     t.degrees       := deg;
  1351.     return t;
  1352.  
  1353. end;
  1354.  
  1355.  
  1356. #############################################################################
  1357. ##
  1358. #F  RationalsPolynomialsOps.FactorsSquarefree( <R>, <f> ) . .  factors of <f>
  1359. ##
  1360. ##  <f> must be square free and must have a constant term.
  1361. ##
  1362. RationalsPolynomialsOps.FactorsSquarefree := function( R, f )
  1363.     local   t,  h,  fac,  rem,  c,  cbs,  i,  j,  sl,  prd,  cof,  q;
  1364.  
  1365.     # find a suitable prime, if <f> is irreducible return
  1366.     t := R.operations.FactorsModPrime( R, f );
  1367.     if t.isIrreducible  then return [f];  fi;
  1368.     InfoPoly2( "#I  using prime ", t.prime, " for factorization\n" );
  1369.  
  1370.     # start Hensel
  1371.     h := R.operations.SquareHensel( R, f, t.factors );
  1372.  
  1373.     # check for any direct factors
  1374.     f   := h.polynomial;
  1375.     fac := h.factors;
  1376.     rem := h.remaining;
  1377.     InfoPoly2( "#I  found ", Length(fac), " true factors, ",
  1378.                Length(rem), " remaining\n" );
  1379.  
  1380.     # try all combinations
  1381.     c := 2;
  1382.     while 2*c <= Length(rem)  do
  1383.         cbs := Combinations( [ 1 .. Length(rem) ], c );
  1384.         j   := 0;
  1385.         repeat
  1386.             j  := j + 1;
  1387.             sl := Sublist( rem, cbs[j] );
  1388.  
  1389.             # the degree of the combination must be possible
  1390.             if Sum(List(sl,Degree)) in t.degrees  then
  1391.  
  1392.                 # compute the product and reduce
  1393.                 prd := Product( sl );
  1394.                 cof := [];
  1395.                 for i  in [ 1 .. Length(prd.coefficients) ]  do
  1396.                     cof[i] := prd.coefficients[i] mod h.primePower;
  1397.                     if h.primePower2 < cof[i]  then
  1398.                         cof[i] := cof[i] - h.primePower;
  1399.                     fi;
  1400.                 od;
  1401.  
  1402.                 # make the product primitive
  1403.                 cof := cof * (1/Gcd(cof));
  1404.                 prd := Polynomial( Rationals, cof, prd.valuation );
  1405.  
  1406.                 # make sure that the quotient has a chance
  1407.                 if f.coefficients[1] mod prd.coefficients[1] <> 0
  1408.                    or LeadingCoefficient(f)
  1409.                       mod LeadingCoefficient(prd) <> 0
  1410.                 then
  1411.                     InfoPoly2( "#I  ignoring combination ", cbs[j], "\n" );
  1412.                     q := false;
  1413.                 else
  1414.                     InfoPoly2( "#I  testing combination ", cbs[j], "\n" );
  1415.                     q := Quotient( f, prd );
  1416.                 fi;
  1417.             else
  1418.                 InfoPoly2( "#I  skipping combination ", cbs[j], "\n" );
  1419.                 q := false;
  1420.             fi;
  1421.         until q <> false or j = Length(cbs);
  1422.  
  1423.         # if the quotient is ok, remove the factors, set <f> and <fac>
  1424.         if q <> false  then
  1425.             f := q;
  1426.             InfoPoly2( "#I  found true factor = ", prd, "\n" );
  1427.             Add( fac, prd );
  1428.             rem := List( Filtered( [ 1 .. Length(rem) ],
  1429.                              x -> not x in cbs[j] ),
  1430.                          y -> rem[y] );
  1431.         else
  1432.             c := c + 1;
  1433.         fi;
  1434.     od;
  1435.  
  1436.     # the product of the remaing one is a true factor
  1437.     if 0 < Length(rem)  then
  1438.         prd := Product(rem);
  1439.         cof := [];
  1440.         for i  in [ 1 .. Length(prd.coefficients) ]  do
  1441.             cof[i] := prd.coefficients[i] mod h.primePower;
  1442.             if h.primePower2 < cof[i]  then
  1443.                 cof[i] := cof[i] - h.primePower;
  1444.             fi;
  1445.         od;
  1446.         cof := cof * (1/Gcd(cof));
  1447.         Add( fac, Polynomial( Rationals, cof, prd.valuation ) );
  1448.     fi;
  1449.         
  1450.     # return the factors
  1451.     return fac;
  1452.  
  1453. end;
  1454.  
  1455.  
  1456. #############################################################################
  1457. ##
  1458. #F  RationalsPolynomialsOps.IFactors( <R>, <f> )  . . . . . .  factors of <f>
  1459. ##
  1460. RationalsPolynomialsOps.IFactors := function( R, f )
  1461.     local   l,  v,  g,  q,  s,  r,  x;
  1462.  
  1463.     # if <f> is trivial return
  1464.     if 0 = Length( f.coefficients )  then
  1465.         InfoPoly2( "#I  <f> is trivial\n" );
  1466.         return [ f ];
  1467.     fi;
  1468.  
  1469.     # remove a valuation
  1470.     v := f.valuation;
  1471.     f := Polynomial( R.baseRing, f.coefficients );
  1472.     x := Indeterminate(R.baseRing);
  1473.  
  1474.     # if <f> is constant return
  1475.     if 0 = Degree(f)  then
  1476.         InfoPoly2( "#I  <f> is a power of x\n" );
  1477.         s    := List( [ 1 .. v ], f -> x );
  1478.         s[1] := s[1] * f.coefficients[1];
  1479.         return s;
  1480.     fi;
  1481.  
  1482.     # if <f> linear return
  1483.     if 1 = Degree(f)  then
  1484.         InfoPoly2( "#I  <f> is a linear\n" );
  1485.         s := List( [ 1 .. v ], f -> x );
  1486.         Add( s, f );
  1487.         return s;
  1488.     fi;
  1489.  
  1490.     # make <f> integral, primitive and square free
  1491.     g := R.operations.IGcd( R, f, Derivative(f) );
  1492.     q := R.operations.IntegerPolynomial( R, Quotient( R, f, g ) );
  1493.     q := q * SignInt(LeadingCoefficient(q));
  1494.     InfoPoly2( "#I  factorizing ", q, "\n" );
  1495.  
  1496.     # and factorize <q>
  1497.     if Degree(q) < 2  then
  1498.         InfoPoly2( "#I  <f> is a linear power\n" );
  1499.         s := [ q ];
  1500.     else
  1501.         s := R.operations.FactorsSquarefree( R, q );
  1502.     fi;
  1503.  
  1504.     # find factors of <g>
  1505.     for r  in s  do
  1506.         if 0 < Degree(g) and Degree(g) mod Degree(r) = 0  then
  1507.             q := Quotient( R, g, r );
  1508.             while 0 < Degree(g) and q <> false  do
  1509.                 Add( s, r );
  1510.                 g := q;
  1511.                 if Degree(g) mod Degree(r) = 0  then
  1512.                     q := Quotient( R, g, r );
  1513.                 else
  1514.                     q := false;
  1515.                 fi;
  1516.             od;
  1517.         fi;
  1518.     od;
  1519.  
  1520.     # sort the factors
  1521.     Append( s, List( [ 1 .. v ],  f -> x ) );
  1522.     Sort(s);
  1523.  
  1524.     # return the (primitive) factors
  1525.     return s;
  1526.  
  1527. end;
  1528.  
  1529.  
  1530. #############################################################################
  1531. ##
  1532. #F  RationalsPolynomialsOps.Factors( <R>, <f> )    . . . . . . .  factors of <f>
  1533. ##
  1534. RationalsPolynomialsOps.Factors := function ( R, f )
  1535.     local   r;
  1536.  
  1537.     # handle trivial case
  1538.     if Degree(f) < 2  then
  1539.     f.factors := [ f ];
  1540.     elif Length(f.coefficients) = 1  then
  1541.     r := List( [ 1 .. f.valuation ], x -> Indeterminate(f.baseRing) );
  1542.     r[1] := r[1] * f.coefficients[1];
  1543.     f.factors := r;
  1544.     fi;
  1545.  
  1546.     # do we know the factors
  1547.     if IsBound(f.factors) and R.baseRing = f.baseRing  then
  1548.         return f.factors;
  1549.     fi;
  1550.  
  1551.     # compute the integer factors
  1552.     r := R.operations.IFactors( R, f );
  1553.  
  1554.     # convert into standard associates and sort
  1555.     r := List( r, x -> StandardAssociate(R,x) );
  1556.     Sort(r);
  1557.  
  1558.     # correct leading term
  1559.     r[1] := LeadingCoefficient(f) * r[1];
  1560.  
  1561.     # and return
  1562.     if f.baseRing = R.baseRing  then
  1563.     f.factors := r;
  1564.     fi;
  1565.     return r;
  1566.  
  1567. end;
  1568.  
  1569.     
  1570. #############################################################################
  1571. ##
  1572.  
  1573. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  1574. ##
  1575. ##  Local Variables:
  1576. ##  mode:               outline
  1577. ##  outline-regexp:     "#F\\|#V\\|#E"
  1578. ##  eval:               (local-set-key "\t" 'indent-for-tab-command)
  1579. ##  eval:               (hide-body)
  1580. ##  End:
  1581. ##
  1582.