Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  polyrat.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Alexander Hulpke.
##
##  Copyright of GAP belongs to its developers, whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-2.0-or-later
##
##  This file contains functions for polynomials over the rationals
##

#############################################################################
##
#F  APolyProd(<a>,<b>,<p>)   . . . . . . . . . . polynomial product a*b mod p
##
##return a*b mod p;
InstallGlobalFunction(APolyProd,function(a,b,p)
local ac,bc,i,j,pc,pv,ci,fam;

  ci:=CIUnivPols(a,b);
  fam:=FamilyObj(a);
  a:=CoefficientsOfLaurentPolynomial(a);
  b:=CoefficientsOfLaurentPolynomial(b);

  pv:=a[2]+b[2];
  #pc:=ProductCoeffs(a.coefficients,b.coefficients);
  ac:=List(a[1],i->i mod p);
  bc:=List(b[1],i->i mod p);
  if Length(ac)>Length(bc) then
    pc:=ac;
    ac:=bc;
    bc:=pc;
  fi;
  # prepare result list
  pc:=[];
  for i in [1..Length(ac)+Length(bc)-1] do
    pc[i]:=0;
  od;
  for i in [1..Length(ac)] do
    #pc:=SumCoeffs(pc,i*bc) mod p;
    for j in [1..Length(bc)] do
      pc[i+j-1]:=(pc[i+j-1]+ac[i]*bc[j]) mod p;
    od;
  od;
  pv:=pv+RemoveOuterCoeffs(pc,fam!.zeroCoefficient);
  return LaurentPolynomialByExtRepNC(fam,pc,pv,ci);
end);

#############################################################################
##
#F  BPolyProd(<a>,<b>,<m>,<p>) . . . . . . polynomial product a*b mod m mod p
##
##  return EuclideanRemainder(PolynomialRing(Rationals),a*b mod p,m) mod p;
InstallGlobalFunction(BPolyProd,function(a,b,m,p)
local ac,bc,mc,i,j,pc,ci,f,fam;


  ci:=CIUnivPols(a,b);
  fam:=FamilyObj(a);
  a:=CoefficientsOfLaurentPolynomial(a);
  b:=CoefficientsOfLaurentPolynomial(b);
  m:=CoefficientsOfLaurentPolynomial(m);
  # we shift as otherwise the mod will mess up valuations (should occur
  # rarely anyhow)
  ac:=List(a[1],i->i mod p);
  ac:=ShiftedCoeffs(ac,a[2]);
  bc:=List(b[1],i->i mod p);
  bc:=ShiftedCoeffs(bc,b[2]);
  mc:=List(m[1],i->i mod p);
  mc:=ShiftedCoeffs(mc,m[2]);
  ReduceCoeffsMod(ac,mc,p);
  ShrinkRowVector(ac);
  ReduceCoeffsMod(bc,mc,p);
  ShrinkRowVector(bc);
  if Length(ac)>Length(bc) then
    pc:=ac;
    ac:=bc;
    bc:=pc;
  fi;
  pc:=[];
  f:=false;
  for i in ac do
    if f then
      # only do it 2nd time (here to avoin doing once too often)
      bc:=ShiftedCoeffs(bc,1);
      ReduceCoeffsMod(bc,mc,p);
      ShrinkRowVector(bc);
    else
      f:=true;
    fi;
    #pc:=SumCoeffs(pc,i*bc) mod p;
    for j in [Length(pc)+1..Length(bc)] do
      pc[j]:=0;
    od;
    for j in [1..Length(bc)] do
      pc[j]:=(pc[j]+i*bc[j] mod p) mod p;
    od;
    ShrinkRowVector(pc);
    ReduceCoeffsMod(pc,mc,p);
    ShrinkRowVector(pc);
  od;
  p:=RemoveOuterCoeffs(pc,fam!.zeroCoefficient);
  return LaurentPolynomialByExtRepNC(fam,pc,p,ci);
end);


#############################################################################
##
#F  ApproxRational:  approximativ k"urzen
##
BindGlobal("ApproxRational",function(r,s)
local n,d,u;
  n:=NumeratorRat(r);
  d:=DenominatorRat(r);
  u:=LogInt(d,10)-s+1;
  if u>0 then
    u:=10^u;
    return QuoInt(n,u)/QuoInt(d,u);
  else
    return r;
  fi;
end);

#############################################################################
##
#F  ApproximateRoot(<num>,<n>[,<digits>]) . . approximate th n-th root of num
##   numerically with a denominator of 'digits' digits.
##
BIND_GLOBAL( "APPROXROOTS", NEW_SORTED_CACHE(false) );

BindGlobal("ApproximateRoot",function(arg)
local r,e,f,store,maker;
  r:=arg[1];
  e:=arg[2];
  if Length(arg)>2 then
    f:=arg[3];
  else
    f:=10;
  fi;

  store:= e<=10 and IsInt(r) and 0<=r and r<=100 and f=10;

  maker := function()
  local x,nf,lf,c,letzt;

  x:=RootInt(NumeratorRat(r),e)/RootInt(DenominatorRat(r),e);
  nf:=r;
  c:=0;
  letzt:=[];
  repeat
    lf:=nf;
    Add(letzt,x);
    x:=ApproxRational(1/e*((e-1)*x+r/(x^(e-1))),f+6);
    nf:=AbsoluteValue(x^e-r);
    if nf=0 then
      c:=6;
    else
      if nf>lf then
        lf:=nf/lf;
      else
        lf:=lf/nf;
      fi;
      if lf<2 then
        c:=c+1;
      else
        c:=0;
      fi;
    fi;
  # until 3 times no improvement
  until c>2 or x in letzt;
  return x;
  end;

  if store then
    return GET_FROM_SORTED_CACHE(APPROXROOTS, [e,r], maker);
  fi;
  return maker();
end);

#############################################################################
##
#F  ApproxRootBound(f) Numerical approximation of RootBound (better, but
##  may fail)
##
BindGlobal("ApproxRootBound",function(f)
local x,p,tp,diff,app,d,scheit,v,nkon;

  x:=IndeterminateNumberOfLaurentPolynomial(f);
  p:=CoefficientsOfLaurentPolynomial(f);
  if p[2]<0 or not ForAll(p[1],IsRat) then
    # avoid complex conjugation etc.
    Error("only yet implemented for rational polynomials");
  fi;

  # eliminate valuation
  f:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,p[1],x);
  x:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,[0,1],x);

  # probably first test, whether polynomial should be inverted. However,
  # we expect roots larger than one.
  d:=DegreeOfLaurentPolynomial(f);
  f:=Value(f,1/x)*x^d;
  app:=1/2;
  diff:=1/4;
  nkon:=true;
  repeat
    # pol, whose roots are the 1/app of the roots of f
    tp:=Value(f,x*app);
    tp:=CoefficientsOfLaurentPolynomial(tp)[1];
    tp:=tp/tp[1];
    tp:=List(tp,i->ApproxRational(i,10));
    # now check, by using the Lehmer/Schur method, whether tp has a root
    # in the unit circle, i.e. f has a root in the app-circle
    repeat
      scheit:=false;
      p:=tp;
      repeat
        d:=Length(p);
        # compute T[p]=\bar a_n p-a_0 p*, everything rational.
        p:=p[1]*p-p[d]*Reversed(p);
        p:=List(p,i->ApproxRational(i,10));
        d:=Length(p);
        while d>1 and p[d]=0 do
          Unbind(p[d]);
          d:=d-1;
        od;
        v:=p[1];
        if v=0 then
          scheit:=nkon;
        fi;
        nkon:=ForAny(p{[2..Length(p)]},i->i<>0);
      until v<=0;
      if scheit then
        # we fail due to rounding errors
        return fail;
      else
        if v<0 then
          # zero in the unit circle, app smaller
          app:=app-diff;
        else
          # no zero in the unit circle, app larger
          app:=app+diff;
        fi;
      fi;
    until not scheit;
    diff:=diff/2;
  # until good circle found, which does not contain roots.
  until v=0 and (1-app/(app+diff))<1/40;

  # revert last enlargement and add accuracy to be secure
  app:=app-2*diff;
  return 1/app+1/20;
end);

#############################################################################
##
#F  RootBound(<f>) . . . . bound for absolute value of (complex) roots of f
##
InstallGlobalFunction(RootBound,function(f)
local a,b,c,d;
  # valuation gives only 0 as zero, this can be neglected
  f:=CoefficientsOfLaurentPolynomial(f)[1];
  # normieren
  f:=f/Last(f);
  f:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,f,1);

  a:=ApproxRootBound(f);
  # did the numerical part fail?
  if a=fail then
    c:=CoefficientsOfLaurentPolynomial(f)[1];
    c:=List(c,AbsInt);
    d:=Length(c);
    a:=Maximum(1,Sum(c{[1..d-1]}));
    b:=1+Maximum(c);
    if b<a then
      a:=b;
    fi;
    b:=Maximum(List([1..d-1],i->RootInt(d*Int(AbsInt(c[d-i])+1/2),i)+1));
    if b<a then
      a:=b;
    fi;
    if ForAll(c,i->i<>0) then
      b:=List([3..d],i->2*AbsInt(c[i-1]/c[i]));
      Add(b,AbsInt(c[1]/c[2]));
      b:=Maximum(b);
      if b<a then
        a:=b;
      fi;
    fi;
    b:=Sum([1..d-1],i->AbsInt(c[i]-c[i+1]))+AbsInt(c[1]);
    if b<a then
      a:=b;
    fi;
    b:=1/20+Maximum(List([1..d-1],
                i->RootInt(Int(AbsInt(c[d-i]/Binomial(d-1,i))+1/2),i)+1))
                   /(ApproximateRoot(2,d-1)-1)+10^(-10);
    if b<a then
      a:=b;
    fi;

  fi;
  return a;
end);

#############################################################################
##
#F  BombieriNorm(<pol>) . . . . . . . . . . . . compute weighted Norm [pol]_2
##
InstallGlobalFunction(BombieriNorm,function(f)
local c,i,n,s;
  c:=CoefficientsOfLaurentPolynomial(f);
  c:=ShiftedCoeffs(c[1],c[2]);
  n:=Length(c)-1;
  s:=0;
  for i in [0..n] do
    s:=s+AbsInt(c[i+1])^2/Binomial(n,i);
  od;
  return ApproximateRoot(s,2);
end);

#############################################################################
##
#F  MinimizedBombieriNorm(<pol>) . . . . . . . minimize weighted Norm [pol]_2
##                                            by shifting roots
##
InstallMethod(MinimizedBombieriNorm,true,
   [IsPolynomial and IsRationalFunctionsFamilyElement],0,
function(f)
local bn,bnf,a,b,c,d,bb,bf,bd,step,x,cnt;

  step:=1;
  bb:=infinity;
  bf:=f;
  bd:=0;
  bn:=[];
  # evaluation of norm, including storing it (avoids expensive double evals)
  bnf := function(dis)
  local p,g;
    p:=Filtered(bn,i->i[1]=dis);
    if p=[] then
      g:=Value(f,x+dis);
      p:=[dis,BombieriNorm(g)];
      Add(bn,p);
      if bb>p[2] then
        # note record
        bf:=g;
        bb:=p[2];
        bd:=dis;
      fi;
      return p[2];
    else
      return p[1][2];
    fi;
  end;

  x:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,[0,1],
       IndeterminateNumberOfLaurentPolynomial(f));
  d:=0;
  cnt:=0;
  repeat
    cnt:=cnt+1;
    Info(InfoPoly,2,"Minimizing BombieriNorm, x->x+(",d,")");
    # local parabola approximation
    a:=bnf(d-step);
    b:=bnf(d);
    c:=bnf(d+step);
    if a<b and c<b then
      if a<c then d:=d-step;
      else d:=d+step;
      fi;
    elif not(a>b and c>b) and (a+c<>2*b) then
      a:=-(c-a)/2/(a+c-2*b)*step;
      # stets aufrunden (wir wollen weg)
      a:=step*Int(AbsInt(a)/step+1)*SignInt(a);
      if a=0 then
        Error("???");
      else
        d:=d+a;
      fi;
    fi;
  until (a>b and c>b) # no better can be reached
        or cnt>6
        or ForAll([d-1,d,d+1],i->Filtered(bn,j->j[1]=i)<>[]); #or loop
  # best value
  return [bf,bd];
end);

#############################################################################
##
#F  BeauzamyBound(<pol>) . . . . . Beauzamy's Bound for Factors Coefficients
##                                 cf. JSC 13 (1992), 463-472
##
BindGlobal("BeauzamyBound",function(f)
local n;
  n:=DegreeOfLaurentPolynomial(f);
  return Int(
  # the strange number in the next line is an (upper) rational approximation
  # for 3^{3/4}/2/\sqrt(\pi)
  643038/1000000*ApproximateRoot(3^n,2)/ApproximateRoot(n,2)*BombieriNorm(f))+1;
end);

#############################################################################
##
#F  OneFactorBound(<pol>) . . . . . . . . . . . . Bound for one factor of pol
##
InstallGlobalFunction(OneFactorBound,function(f)
local d,n;
  n:=DegreeOfLaurentPolynomial(f);
  if n>=3 then
    # Single factor bound of Beauzamy, Trevisan and Wang (1993)
    return Int(10912/10000*(ApproximateRoot(2^n,2)/ApproximateRoot(n^3,8)
           *(ApproximateRoot(BombieriNorm(f),2))))+1;
  else
    # Mignotte's single factor bound
    d:=QuoInt(n,2);
    return
    Binomial(d,QuoInt(d,2))
      *(1+RootInt(Sum(CoefficientsOfLaurentPolynomial(f)[1],
                      i->i^2),2));
  fi;
end);

#############################################################################
##
#F  PrimitivePolynomial(<f>) . . . remove denominator and coefficients gcd
##
InstallMethod(PrimitivePolynomial,"univariate polynomial",true,
  [IsUnivariatePolynomial],0,
function(f)
local lcm, c, fc,fac;

  fc:=CoefficientsOfLaurentPolynomial(f)[1];
  # compute lcm of denominator
  lcm := 1;
  for c  in fc  do
    lcm := LcmInt(lcm,DenominatorRat(c));
  od;

  # remove all denominators
  f := f*lcm;
  fac:=1/lcm;
  fc:=CoefficientsOfLaurentPolynomial(f)[1];

  # remove gcd of coefficients
  if Length(fc)>0 then
    fc:=Gcd(fc);
  else
    fc:=1;
  fi;
  fac:=fac*fc;
  return [f*(1/fc),fac];

end);

BindGlobal("PrimitiveFacExtRepRatPol",function(e)
local d,lcm,i,fac;
  d:=e{[2,4..Length(e)]};
  if not ForAll(d,IsRat) then
    TryNextMethod();
  fi;
  lcm:=1;
  for i in d do
    lcm := LcmInt(lcm,DenominatorRat(i));
  od;
  fac:=1/lcm;
  d:=d*lcm;
  if Length(d)>0 then
    fac:=fac*Gcd(d);
  fi;
  return fac;
end);

InstallMethod(PrimitivePolynomial,"rational polynomial",true,
  [IsPolynomial],0,
function(f)
local e,fac;
  e:=ExtRepPolynomialRatFun(f);
  fac:=PrimitiveFacExtRepRatPol(e);
  return [f/fac,fac];
end);


#############################################################################
##
#F  BeauzamyBoundGcd(<f>,<g>) . . . . . Beauzamy's Bound for Gcd Coefficients
##
##  cf. JSC 13 (1992),463-472
##
BindGlobal("BeauzamyBoundGcd",function(f,g)
local   n, A, B,lf,lg;

  lf:=LeadingCoefficient(f);
  if not IsOne(lf) then
    f:=f/lf;
  fi;

  lg:=LeadingCoefficient(f);
  if not IsOne(lg) then
    g:=g/lg;
  fi;
  n := DegreeOfLaurentPolynomial(f);
  # the   strange   number  in   the   next line  is   an  (upper) rational
  # approximation for 3^{3/4}/2/\sqrt(\pi)
  A := Int(643038/1000000
        * ApproximateRoot(3^n,2)/ApproximateRoot(n,2)
        * BombieriNorm(f))+1;

  # the   strange  number   in  the   next   line is  an   (upper) rational
  # approximation for 3^{3/4}/2/\sqrt(\pi)
  n := DegreeOfLaurentPolynomial(g);
  B := Int(643038/1000000
        * ApproximateRoot(3^n,2)/ApproximateRoot(n,2)
        * BombieriNorm(g))+1;
  B:=Minimum(A,B);
  if not (IsOne(lf) or IsOne(lg)) then
     B:=B*GcdInt(lf,lg);
  fi;
  return B;

end);


#############################################################################
##
#F  RPGcdModPrime(<f>,<g>,<p>,<a>,<brci>)  . . gcd mod <p>
##
BindGlobal("RPGcdModPrime",function(f,g,p,a,brci)
local fam,gcd, u, v, w, val, r, s;

  fam:=CoefficientsFamily(FamilyObj(f));
  f:=CoefficientsOfLaurentPolynomial(f);
  g:=CoefficientsOfLaurentPolynomial(g);
  # compute in the finite field F_<p>
  val := Minimum(f[2], g[2]);
  s   := ShiftedCoeffs(f[1],f[2]-val);
  r   := ShiftedCoeffs(g[1],g[2]-val);
  ReduceCoeffsMod(s,p);  ShrinkRowVector(s);
  ReduceCoeffsMod(r,p);  ShrinkRowVector(r);

  # compute the gcd
  u := r;
  v := s;
  while 0 < Length(v)  do
    w := v;
    ReduceCoeffsMod(u,v,p);
    ShrinkRowVector(u);
    v := u;
    u := w;
  od;
  #gcd := u * (a/Last(u));
  gcd:=u;
  MultVector(gcd,a/Last(u));
  ReduceCoeffsMod(gcd,p);

  # and return the polynomial
  return LaurentPolynomialByCoefficients(fam,gcd,val,brci);

end);


BindGlobal("RPGcdCRT",function(f,p,g,q,ci)
local min, cf, lf, cg, lg, i, P, m, r, fam;

  fam := CoefficientsFamily(FamilyObj(f));
  f:=CoefficientsOfLaurentPolynomial(f);
  g:=CoefficientsOfLaurentPolynomial(g);
  # remove valuation
  min := Minimum(f[2],g[2]);
  if f[2] <> min  then
    cf := ShiftedCoeffs(f[1],f[2] - min);
  else
    cf := ShallowCopy(f[1]);
  fi;
  lf := Length(cf);
  if g[2] <> min  then
    cg := ShiftedCoeffs(g[1],g[2] - min);
  else
    cg := ShallowCopy(g[1]);
  fi;
  lg := Length(cg);

  # use chinese remainder
  r := [ p,q ];
  P := p * q;
  m := P/2;
  for i  in [ 1 .. Minimum(lf,lg) ]  do
    cf[i] := ChineseRem(r,[ cf[i],cg[i] ]);
    if m < cf[i]  then cf[i] := cf[i] - P;  fi;
  od;
  if lf < lg  then
    for i  in [ lf+1 .. lg ]  do
      cf[i] := ChineseRem(r,[ 0,cg[i] ]);
      if m < cf[i]  then cf[i] := cf[i] - P;  fi;
    od;
  elif lg < lf  then
    for i  in [ lg+1 .. lf ]  do
      cf[i] := ChineseRem(r,[ cf[i],0 ]);
      if m < cf[i]  then cf[i] := cf[i] - P;  fi;
    od;
  fi;

  # return the polynomial
  return LaurentPolynomialByCoefficients(fam,cf,min,ci);

end);


BindGlobal("RPGcd1",function(t,a,f,g)
local G, P, l, m, i;

  # <P> will hold the product of primes use so far
  t.modulo := t.prime;

  # <G> will hold the approximation of the gcd
  G := t.gcd;

  # use next prime until we reach the Beauzamy bound
  while t.modulo < t.bound  do
    repeat t.prime := NextPrimeInt(t.prime);  until a mod t.prime <> 0;

    # compute modular gcd
    t.gcd := RPGcdModPrime(f,g,t.prime,a,t.brci);
    Info(InfoPoly,3,"gcd mod ",t.prime," = ",t.gcd);

    # if the degree of <C> is smaller we started with wrong <p>
    if DegreeOfLaurentPolynomial(t.gcd)
       < DegreeOfLaurentPolynomial(G)
    then
      Info(InfoPoly,3,"found lower degree,restarting");
      return false;
    fi;

    # if the degrees of <C> and <G> are equal use chinese remainder
    if DegreeOfLaurentPolynomial(t.gcd)
       = DegreeOfLaurentPolynomial(G)
    then
      P := G;
      G := RPGcdCRT(P,t.modulo,t.gcd,t.prime,t.brci);
      t.modulo := t.modulo * t.prime;
      Info(InfoPoly,3,"gcd mod ",t.modulo," = ",G);
      if G = P  then
        t.correct :=  IsZero(f mod G) and IsZero(g mod G);
        if t.correct  then
          Info(InfoPoly,3,"found correct gcd");
          t.gcd := G;
          return true;
        fi;
      fi;
    fi;
  od;

  # get <G> into the -<t.modulo>/2 to +<t.modulo> range
  G:=CoefficientsOfLaurentPolynomial(G);
  l := [];
  m := t.modulo/2;
  for i  in [ 1 .. Length(G[1]) ]  do
    if m < G[1][i]  then
      l[i] := G[1][i] - t.modulo;
    else
      l[i] := G[1][i];
    fi;
  od;
  G := LaurentPolynomialByExtRepNC(FamilyObj(f),l,G[2],t.brci);
  Info(InfoPoly,3,"gcd mod ",t.modulo," = ",G);

  # check if <G> is correct but return 'true' in any case
  t.correct := IsZero(f mod G) and IsZero(g mod G);
  t.gcd := G;
  return true;

end);


BindGlobal("RPIGcd", function(f,g)
local a,t;

  # special case zero:
  if IsZero(f) then
    return g;
  elif IsZero(g) then
    return f;
  fi;
  # compute the Beauzamy bound for the gcd
  t := rec(prime := 1000);
  t.brci:=CIUnivPols(f,g);

  t.bound := 2 * Int(BeauzamyBoundGcd(f,g)+1);
  Info(InfoPoly,3,"Beauzamy bound = ",t.bound/2);

  # avoid gcd of leading coefficients
  a := GcdInt(LeadingCoefficient(f),LeadingCoefficient(g));
  repeat

    # start with first prime avoiding gcd of leading coefficients
    repeat t.prime := NextPrimeInt(t.prime);  until a mod t.prime <> 0;

    # compute modular gcd with leading coefficient <a>
    t.gcd := RPGcdModPrime(f,g,t.prime,a,t.brci);
    Info(InfoPoly,3,"gcd mod ",t.prime," = ",t.gcd);

    # loop until we have success
    repeat
      if 0 = DegreeOfLaurentPolynomial(t.gcd)  then
        Info(InfoPoly,3,"<f> and <g> are relative prime");
        return One(f);
      fi;
    until RPGcd1(t,a,f,g);
  until t.correct;

  # return the gcd
  return t.gcd;

end);

#############################################################################
##
#F  GcdOp( <R>, <f>, <g> )  . . . . . . . for rational univariate polynomials
##
InstallRingAgnosticGcdMethod("rational univariate polynomials",
  IsCollsElmsElms,IsIdenticalObj,
  [IsRationalsPolynomialRing and IsEuclideanRing,
   IsUnivariatePolynomial,IsUnivariatePolynomial],0,
function(f,g)
local brci,gcd,fam,fc,gc;

  fam:=FamilyObj(f);

  if not (IsIdenticalObj(CoefficientsFamily(fam),CyclotomicsFamily)
     and ForAll(CoefficientsOfLaurentPolynomial(f)[1],IsRat)
     and ForAll(CoefficientsOfLaurentPolynomial(g)[1],IsRat)) then
    TryNextMethod(); # not applicable as not rational
  fi;

  brci:=CIUnivPols(f,g);
  if brci=fail then TryNextMethod();fi;
  # check trivial cases
  if -infinity = DegreeOfLaurentPolynomial(f)  then
    return g;
  elif -infinity = DegreeOfLaurentPolynomial(g)  then
    return f;
  elif 0 = DegreeOfLaurentPolynomial(f)
       or 0 = DegreeOfLaurentPolynomial(g)
  then
    return One(f);
  fi;

  # convert polynomials into integer polynomials
  f := PrimitivePolynomial(f)[1];
  g := PrimitivePolynomial(g)[1];
  Info(InfoPoly,3,"<f> = ",f);
  Info(InfoPoly,3,"<g> = ",g);

  fc:=CoefficientsOfLaurentPolynomial(f);
  gc:=CoefficientsOfLaurentPolynomial(g);

  # try heuristic method:
  gcd:=HeuGcdIntPolsCoeffs(fc[1],gc[1]);
  if gcd=fail then
    # fall back to the original version:
    gcd:=RPIGcd(f,g);
    return StandardAssociate(gcd);

  fi;
  fc:=Minimum(fc[2],gc[2]);
  fc:=fc+RemoveOuterCoeffs(gcd,fam!.zeroCoefficient);
  if Length(gcd)>0 and not IsOne(Last(gcd)) then
    gcd:=gcd/Last(gcd);
  fi;
  return LaurentPolynomialByExtRepNC(fam,gcd,fc,brci);
end);

InstallMethod(\mod,"reduction of univariate rational polynomial at a prime",
  true,[IsUnivariatePolynomial,IsInt],0,
function(f,p)
local c;
  c:=CoefficientsOfLaurentPolynomial(f);
  if Length(c[1])>0 and
      ForAny(c[1],i->not (IsRat(i) or IsAlgebraicElement(i))) then
    TryNextMethod();
  fi;
  return LaurentPolynomialByCoefficients(
      CoefficientsFamily(FamilyObj(f)),List(c[1],i->i mod p),c[2],
      IndeterminateNumberOfLaurentPolynomial(f));
end);

InstallMethod(\mod,"reduction of general rational polynomial at a prime",
  true,[IsPolynomial,IsInt],0,
function(f,p)
local c,d,i,m;
  c:=ExtRepPolynomialRatFun(f);
  d:=[];
  for i in [2,4..Length(c)] do
    if not (IsRat(c[i]) or IsAlgebraicElement(c[i])) then
      TryNextMethod();
    fi;
    m:=c[i] mod p;
    if m<>0 then
      Add(d,c[i-1]);
      Add(d,m);
    fi;
  od;
  return PolynomialByExtRepNC(FamilyObj(f),d);
end);

#############################################################################
##
#F  RPQuotientModPrime(<f>,<g>,<p>) . . .  quotient
##
BindGlobal("RPQuotientModPrime",function(f,g,p)
local   m, n, i, k, c, q, val, fc,gc,brci,fam;

  # get base ring
  brci:=CIUnivPols(f,g);
  fam:=FamilyObj(f);
  # reduce <f> and <g> mod <p>
  f := f mod p;
  g := g mod p;

  fc:=CoefficientsOfLaurentPolynomial(f);
  gc:=CoefficientsOfLaurentPolynomial(g);

  # if <f> is zero return it
  if 0 = Length(fc[1])  then
    return f;
  fi;

  # check the value of the valuation of <f> and <g>
  if fc[2] < gc[2]  then
    return false;
  fi;
  val := fc[2]-gc[2];

  # Try to divide <f> by <g>,compute mod <p>
  q := [];
  n := Length(gc[1]);
  m := Length(fc[1]) - n;
  gc:=gc[1];
  f := ShallowCopy(fc[1]);
  for i  in [0..m]  do
    c := f[m-i+n]/gc[n] mod p;
    for k  in [1..n]  do
      f[m-i+k] := (f[m-i+k] - c*gc[k]) mod p;
    od;
    q[m-i+1] := c;
  od;

  # Did the division work?

  for i  in [ 1 .. m+n ]  do
    if f[i] <> fam!.zeroCoefficient then
      return false;
    fi;
  od;
  val:=val+RemoveOuterCoeffs(q,fam!.zeroCoefficient);
  return LaurentPolynomialByExtRepNC(fam,q,val,brci);

end);


#############################################################################
##
#F  RPGcdRepresentationModPrime(<f>,<g>,<p>)  . gcd
##
BindGlobal("RPGcdRepresentationModPrime",function(f,g,p)

  local   val,     # the minimal valuation of <f> and <g>
      s, sx,    # first line of gcd algorithm
      t, tx,    # second line of gcd algorithm
      h, hx,    # temp for swapping lines
      q,       # quotient
      n,m,r,c,  # used in quotient
      brci,
      i,k;       # loops

  Info(InfoPoly,3,"f=",f,"g=",g);
  # get base ring
  brci:=CIUnivPols(f,g);
  brci:=[CoefficientsFamily(FamilyObj(f)),brci];

  # remove common x^i term
  f:=CoefficientsOfLaurentPolynomial(f);
  g:=CoefficientsOfLaurentPolynomial(g);

  val:=Minimum(f[2],g[2]);
  f  :=ShiftedCoeffs(f[1],f[2]-val);
  g  :=ShiftedCoeffs(g[1],g[2]-val);
  ReduceCoeffsMod(f,p);  ShrinkRowVector(f);
  ReduceCoeffsMod(g,p);  ShrinkRowVector(g);

  # compute the gcd and representation mod <p>
  s := ShallowCopy(f);  sx := [ One(brci[1]) ];
  t := ShallowCopy(g);  tx := [];
  while 0 < Length(t)  do
    Info(InfoPoly,3,"<s> = ",s,", <sx> = ",sx,"\n",
           "#I  <t> = ",t,", <tx> = ",tx);

    # compute the euclidean quotient of <s> by <t>
    q := [];
    n := Length(t);
    m := Length(s) - n;
    r := ShallowCopy(s);
    for i  in [ 0 .. m ]  do
      c := r[m-i+n] / t[n] mod p;
      for k  in [ 1 .. n ]  do
        r[m-i+k] := (r[m-i+k] - c * t[k]) mod p;
      od;
      q[m-i+1] := c;
    od;
    Info(InfoPoly,3,"<q> = ",q);

    # update representation
    h  := t;
    hx := tx;
    t  := s;
    AddCoeffs(t,ProductCoeffs(q,h),-1);
    ReduceCoeffsMod(t,p);
    ShrinkRowVector(t);
    tx := sx;
    AddCoeffs(tx,ProductCoeffs(q,hx),-1);
    ReduceCoeffsMod(tx,p);
    ShrinkRowVector(tx);
    s  := h;
    sx := hx;
  od;
  Info(InfoPoly,3,"<s> = ",s,", <sx> = ",sx);

  # compute conversion for standard associate
  q := (1/Last(s)) mod p;

  # convert <s> and <x> back into polynomials
  if 0 = Length(g)  then
    #sx := q * sx;
    MultVector(sx,q);
    ReduceCoeffsMod(sx,p);
    return [ LaurentPolynomialByCoefficients(brci[1],sx,0,brci[2]),
         Zero(brci[1]) ];
  else
    #hx := q * sx;
    hx:=ShallowCopy(sx);
    MultVector(hx,q);
    ReduceCoeffsMod(hx,p);
    hx := LaurentPolynomialByCoefficients(brci[1],hx,0,brci[2]);
    AddCoeffs(s,ProductCoeffs(sx,f),-1);
    #s := q * s;
    MultVector(s,q);
    ReduceCoeffsMod(s,p);
    s := LaurentPolynomialByCoefficients(brci[1],s,0,brci[2]);
    g := LaurentPolynomialByCoefficients(brci[1],g,0,brci[2]);
    q := RPQuotientModPrime(s,g,p);
    return [ hx,q ];
  fi;

end);


#############################################################################
##
#F  HenselBound(<pol>,[<minpol>,<den>]) . . . Bounds for Factor coefficients
##    if the computation takes place over an algebraic extension, then
##    minpol and denominator must be given
##
InstallGlobalFunction(HenselBound,function(arg)
local pol,n,nalpha,d,dis,rb,bound,a,i,j,k,l,w,bin,lm,bea,polc,ro,rbpow;

  pol:=arg[1];
  if Length(arg)>1 then
    n:=arg[2];
    d:=arg[3];

    dis:=Discriminant(n);
    nalpha:=RootBound(n); # bound for norm of \alpha.

    polc:=CoefficientsOfLaurentPolynomial(pol)[1];
    if not ForAll(polc,IsRat) then
      # now try to bound the roots of f accordingly. As in all estimates by
      # RootBound only the absolute value of the coefficients is used, we will
      # estimate these first, and replace f by the polynomial
      # x^n-b_{n-1}x^(n-1)-...-b_0 whose roots are certainly larger
      a:=[];
      for i in polc do
        # bound for coefficients of pol
        if IsRat(i) then
          Add(a,AbsInt(i));
        else
          Add(a,Sum(ExtRepOfObj(i),AbsInt)*nalpha);
        fi;
      od;
      a:=-a;
      a[Length(a)]:=-a[Length(a)];
      pol:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,a,1);
    else
      pol:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,polc,1);
    fi;
    n:=DegreeOfLaurentPolynomial(n);
  else
    n:=1;
  fi;

  bound:=[];
  rb:=0;
  #BeauzamyBound
  bea:=BeauzamyBound(pol);
  # compute Landau-Mignotte bound for absolute values of
  # coefficients of any factor
  polc:=CoefficientsOfLaurentPolynomial(pol)[1];
  w:=Sum(polc,i->i^2);
  # we want an upper bound of the root, RootInt will give a lower
  # bound. So we compute the root of w-1 (in case w is a perfect square)
  # and add 1. As we nowhere selected a specific galois representative,
  # this bound (which is rational!) will bound all conjugactes as well.
  lm:=(RootInt(Int(w)-1,2)+1);
  for k in [1..DegreeOfLaurentPolynomial(pol)] do

    l:=2^k*lm;
    if l<bea then
      w:=l;
    else
      w:=bea;
    fi;

    #if lb>10^30 or n>1 then
    if bea>10^200 or n>1 then
      if rb=0 then
        rb:=RootBound(pol);
        if rb>1000 and not IsInt(rb) then
          rb:=Int(rb+1);
        fi;
        rbpow:=[rb];
        a:=rb;
      fi;
      # now try factor deg k
      bin:=1;
      for j in [1..k] do
        bin:=bin*(k-j+1)/j;
        if not IsBound(rbpow[j]) then
          rbpow[j]:=rbpow[j-1]*rb;
          if rbpow[j]>10 and not IsInt(rbpow[j]) then
            rbpow[j]:=Int(rbpow[j]+1);
          fi;
        fi;
        w:=bin*rbpow[j];
        if w>a then
          a:=w;
        fi;
      od;

      # select the better bound
      if a<l then
        w:=a;
      else
        w:=l;
      fi;
    fi;

    if n>1 then
      # algebraic Extension case
      # finally we have to bound (again) the coefficients of \alpha when
      # writing the coefficients of the factor as \sum c_i/d\alpha^i.

      ro:=AbsInt(dis);
      ro:=RootInt(NumeratorRat(ro))/(1+RootInt(DenominatorRat(ro)-1));
      w:=Int(d*w*Factorial(n)/ro*nalpha^(n*(n-1)/2))+1;
    fi;

    bound[k]:=Int(w)+1;
  od;
  return bound;
end);

#############################################################################
##
#F  TrialQuotientRPF(<f>,<g>,<b>)  . . . . . . f/g if coeffbounds are given by b
##
InstallGlobalFunction(TrialQuotientRPF,function(f,g,b)
local  fc,gc,a,m, n, i, k, c, q, val, brci,fam;
  brci:=CIUnivPols(f,g);
  a:=DegreeOfLaurentPolynomial(f)-DegreeOfLaurentPolynomial(g);
  fam:=FamilyObj(f);
  fc:=CoefficientsOfLaurentPolynomial(f);
  gc:=CoefficientsOfLaurentPolynomial(g);
  if a=0 then
    # Special case (that has to return 0)
    a:=b[1];
  else
    a:=b[a];
  fi;
  if 0=Length(fc[1]) then
    return f;
  fi;
  if fc[2]<gc[2] then
    return fail;
  fi;
  val:=fc[2]-gc[2];
  q:=[];
  n:=Length(gc[1]);
  m:=Length(fc[1])-n;
  f:=ShallowCopy(ShiftedCoeffs(fc[1],fc[2]));
  gc:=gc[1];
#  if IsField(R) then
    for i in [0..m] do
      c:=f[(m-i+n)]/gc[n];
      if MaxNumeratorCoeffAlgElm(c)>a then
        Info(InfoPoly,3,"early break");
        return fail;
      fi;
      for k in [1..n] do
        f[m-i+k]:=f[m-i+k]-c*gc[k];
      od;
      q[m-i+1]:=c;
    od;
#  else
#    for i in [0..m] do
#      c:=Quotient(R,f[m-i+n],gc[n]);
#      if c=fail then
#        return fail;
#      fi;
#      if MaxNumeratorCoeffAlgElm(c)>a then
#        Info(InfoPoly,3,"early break\n");
#        return fail;
#      fi;
#      for k in [1..n] do
#        f[m-i+k]:=f[m-i+k]-c*g.coefficients[k];
#        if MaxNumeratorCoeffAlgElm(f[m-i+k])>b then
#          Info(InfoPoly,3,"early break\n");
#          return fail;
#        fi;
#      od;
#      q[m-i+1]:=c;
#    od;
#  fi;
  k:=Zero(f[1]);
  for i in [1..m+n] do
    if f[i]<>k then
      return fail;
    fi;
  od;
  val:=val+RemoveOuterCoeffs(q,fam!.zeroCoefficient);
  return LaurentPolynomialByExtRepNC(fam,q,val,brci);
end);


#############################################################################
##
#F  TryCombinations(<f>,...)  . . . . . . . . . . . . . . . .  try factors
##
InstallGlobalFunction(TryCombinations,function(f,lc,l,p,t,bounds,opt,split,useonefacbound)
local  p2, res, j, i,ii,o,d,b,lco,degs, step, cnew, sel, deli,
     degf, good, act, da, prd, cof, q, combi,mind,binoli,alldegs;

  alldegs:=t.degrees;
  # <res> contains the irr/reducible factors and the remaining ones
  res:=rec(irreducibles:=[],
            irrFactors  :=[],
            reducibles  :=[],
            redFactors  :=[],
            remaining   :=[ 1 .. Length(l) ]);

  # coefficients should be in -<p>/2 and <p>/2
  p2  :=p/2;
  deli:=List(l,DegreeOfLaurentPolynomial);

  # sel are the still selected indices
  sel:=[ 1 .. Length(l) ];

  # create List of binomial coefficients to speed up the 'Combinations' process
  binoli:=[];
  for i in [0..Length(l)-1] do
  binoli[i+1]:=List([0..i],j->Binomial(i,j));
  od;

  step:=0;
  act :=1;
  repeat

  # factors of larger than half remaining degree we will find as
  # final cofactor. This cannot be used if we factor only using the one
  # factor bound!

  if not useonefacbound then
    degf:=DegreeOfLaurentPolynomial(f);
    degs:=Filtered(alldegs,i -> 2*i<=degf);
  else
    degs:=alldegs;
  fi;

  if IsBound(opt.onlydegs) then
    degs:=Intersection(degs,opt.onlydegs);
    Info(InfoPoly,3,"degs=",degs);
  fi;

  if act in sel  then

    # search all combinations of Length step+1 containing the act-th
    # factor,that are allowed
    good:=true;
    da:=List(degs,i -> i-deli[act]);

    # check,whether any combination will be of suitable degree

    cnew:=Set(deli{Filtered(sel,i->i>act)});

    if ForAny(da,i->NrRestrictedPartitions(i,cnew,step)>0) then
        # as we have all combinations including < <act>,we can skip them
        Info(InfoPoly,2,"trying length ",step+1," containing ",act);
        cnew:=Filtered(sel,i -> i > act);
    else
        Info(InfoPoly,2,"length ",step+1," containing ",act," not feasible");
        cnew:=[];
    fi;

    mind:=Sum(deli); # the maximum of the possible degrees. We surely
             # will find something smaller

    lco:=Binomial(Length(cnew),step);
    if 0 = lco  then
    # fix mind to make sure,we don't erroneously eliminate the factor
        mind:=0;
    else
      Info(InfoPoly,2,lco," combinations");
      i:=1;
      while good and i<=lco  do

        # try combination number i
        # combi:=CombinationNr(cnew,step,i);

        q:=i;
        d:=Length(cnew); # the remaining Length
        o:=0;
        combi:=[];
        for ii in [step-1,step-2..0] do
        j:=1;
        b:=binoli[d][ii+1];
        while q>b do
          q:=q-b;
          # compute b:=Binomial(d-(j+1),ii);
          b:=b*(d-j-ii)/(d-j);
          j:=j+1;
        od;
        o:=j+o;
        d:=d-j;
        Add(combi,cnew[o]);
        od;

        # check whether this yields a minimal degree
        d:=Sum(deli{combi});
        if d<mind then
          mind:=d;
        fi;

      if d in da then
          AddSet(combi,act); # add the 'always' factor

          # make sure that the quotient has a chance,compute the
          # extremal coefficient of the product:
          q:=(ProductMod(List(l{combi},
              i->CoefficientsOfLaurentPolynomial(i)[1][1]),
                   p) * lc) mod p;
          if p2 < q  then
            q:=q - p;
          fi;

          # As  we  don't  know  yet  the gcd  of  all the products
          # coefficients (to make it  primitive),we do  a slightly
          # weaker test:  (test of  leading   coeffs is  first   in
          # 'TrialQuotientRPF') this just should  reduce the number of
          # 'ProductMod' necessary.   the  absolute  part  of  the
          # product must  divide  the absolute  part of  f  up to a
          # divisor of <lc>
          q:=CoefficientsOfLaurentPolynomial(f)[1][1] / q * lc;
          if not IsInt(q)  then
            Info(InfoPoly,3,"ignoring combination ",combi);
            q:=fail;
          else
            Info(InfoPoly,2,"testing combination ",combi);

            # compute the product and reduce
            prd:=ProductMod(l{combi},p);
            prd:=CoefficientsOfUnivariatePolynomial(prd);
            cof:=[];
            for j  in [ 1 .. Length(prd) ]  do
              cof[j]:=(lc*prd[j]) mod p;
              if p2 < cof[j]  then
                cof[j]:=cof[j] - p;
              fi;
            od;

            # make the product primitive
            cof:=cof * (1/Gcd(cof));
            prd:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,
              cof,t.ind);
            q:=TrialQuotientRPF(f,prd,bounds);
          fi;

          if q <> fail  then
            f:=q;
            Info(InfoPoly,2,"found true factor of degree ",
                 DegreeOfLaurentPolynomial(prd));
            if Length(combi)=1 or split  then
                q:=0;
            else
              q:=2*lc*OneFactorBound(prd);
              if q <= p  then
                Info(InfoPoly,2,"proven irreducible by 'OneFactorBound'");
              fi;
            fi;

            # for some reason,we know,the factor is irred.
            if q <= p  then
              Append(res.irreducibles,combi);
              Add(res.irrFactors,prd);

              if IsBound(opt.stopdegs)
                and DegreeOfLaurentPolynomial(prd) in opt.stopdegs then
                Info(InfoPoly,2,"hit stopdegree");
                Add(res.redFactors,f);
                res.stop:=true;
                return res;
              fi;

            else
              Add(res.reducibles,combi);
              Add(res.redFactors,prd);
            fi;
            SubtractSet(res.remaining,combi);
            good:=false;
            SubtractSet(sel,combi);
          fi;

          fi;
          i:=i+1;

        od;
    fi;

    # we can forget about the actual factor,as any longer combination
    # is too big
    if Length(degs)>1 and deli[act]+mind >= Maximum(degs)  then
        Info(InfoPoly,2,"factor ",act," can be further neglected");
        sel:=Difference(sel,[act]);
    fi;

  fi;

  # consider next factor
  act:=act + 1;
  if 0 < Length(sel) and act>Maximum(sel)  then
    step:=step+1;
    act :=sel[1];
  fi;

  # until nothing is left
  until 0 = Length(sel) or Length(sel)<step;

  # if <split> is true we *must* find a complete factorization.
  if split and 0 < Length(res.remaining) and not IsOne(f) then
#and not(IsBound(opt.onlydegs) or IsBound(opt.stopdegs)) then

    # the remaining f must be an irreducible factor,larger than deg/2
    Append(res.irreducibles,res.remaining);
    res.remaining:=[];
    Add(res.irrFactors,f);
  fi;

  # return the result
  return res;

end);


#############################################################################
##
#F  RPSquareHensel(<f>,<t>,<opt>)
##
BindGlobal("RPSquareHensel",function(f,t,opt)

  local   p,       # prime
      q,       # current modulus
      q1,      # last modulus
      l,       # factorization mod <q>
      lc,      # leading coefficient of <f>
      bounds,    # Bounds for Factor Coefficients
      ofb,     # OneFactorBound
      k,       # Lift boundary
      prd,     # product of <l>
      rep,     # lifted representation of gcd(<lp>)
      fcn,     # index of true factor in <l>
      dis,     # distance of <f> and <l>
      cor,     # correction
      max,     # maximum absolute coefficient of <f>
      res,     # result
      gcd,     # used in gcd representation
      i, j;    # loop

  # get <l> and <p>
  l:=t.factors;
  p:=t.prime;

  # get the leading coefficient of <f>
  lc:=LeadingCoefficient(f);

  # and maximal coefficient
  max:=Maximum(List(CoefficientsOfUnivariatePolynomial(f),AbsInt));

  # compute the factor coefficient bounds
  ofb:=2*AbsInt(lc)*OneFactorBound(f);
  Info(InfoPoly,2,"One factor bound = ",ofb);
  bounds:=2*AbsInt(lc)*HenselBound(f);
  k:=bounds[Maximum(Filtered(t.degrees,
                             i-> 2*i<=DegreeOfLaurentPolynomial(f)))];
  Info(InfoPoly,2,"Hensel bound = ",k);

  # compute a representation of the 1 mod <p>
  Info(InfoPoly,2,"computing gcd representation: ",Runtime());
  prd:=(1/lc * f) mod p;
  gcd:=RPQuotientModPrime(prd,l[1],p);
  rep:=[ One(f) ];
  for i  in [ 2 .. Length(l) ]  do
    dis:=RPQuotientModPrime(prd,l[i],p);
    cor:=RPGcdRepresentationModPrime(gcd,dis,p);
    gcd:=(cor[1] * gcd + cor[2] * dis) mod p;
    rep:=List(rep,z -> z * cor[1] mod p);
    Add(rep,cor[2]);
  od;
  Info(InfoPoly,2,"representation computed:    ",Runtime());

  # <res> will hold our result
  res:=rec(irrFactors:=[], redFactors:=[], remaining:=[],
        bounds:=bounds);

  # start Hensel until <q> is greater than k
  q  :=p^2;
  q1 :=p;
  while q1 < k  do
    Info(InfoPoly,2,"computing mod ",q);

    for i in [ 1 .. Length(l) ]  do
      dis:=List(CoefficientsOfUnivariatePolynomial(f),i->i/lc mod q);
      ReduceCoeffsMod(dis,CoefficientsOfUnivariatePolynomial(l[i]),q);
  #dis:=EuclideanRemainder(PolynomialRing(Rationals),dis,l[i]) mod q;
  #dis:=CoefficientsOfUnivariatePolynomial(dis);
      dis:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,dis,t.ind);
      l[i]:=l[i] + BPolyProd(rep[i],dis,l[i],q);
    od;

    # NOCH: Assert und leading coeff
    #if not ForAll(CoefficientsOfLaurentPolynomial(Product(l)-f)[1],
    #        i->i mod q=0) then
    #  Error("not product modulo q");
    #fi;

    # if this is not the last step update <rep> and check for factors
    if q < k  then

      # correct the inverses
      for i  in [ 1 .. Length(l) ]  do
        if Length(l)=1 then
          dis:=l[1]^0;
        else
          dis:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,
                                                  [1],t.ind);
          for j in  Difference([1..Length(l)],[i])  do
            dis:=BPolyProd(dis,l[j],l[i],q);
          od;
        fi;
        rep[i]:=BPolyProd(rep[i],
                   (2-APolyProd(rep[i],dis,q)),
                   l[i],
                   q);
      od;

      # try to find true factors
      if max <= q then
        Info(InfoPoly,2,"searching for factors: ",Runtime());
        fcn:=TryCombinations(f,lc,l,q,t,bounds,opt,false,false);
      elif ofb < q  then
        Info(InfoPoly,2,"searching for factors: ",Runtime());
        fcn:=TryCombinations(f,lc,l,q,t,bounds,opt,false,true);

        #Info(InfoPoly,2,"finishing search:    ",Runtime());
      else
        fcn:=rec(irreducibles:=[], reducibles:=[]);
      fi;

      # if we have found a true factor update everything
      if 0 < Length(fcn.irreducibles)+Length(fcn.reducibles)  then
        # append irreducible factors to <res>.irrFactors
        Append(res.irrFactors,fcn.irrFactors);

        # append reducible factors to <res>.redFactors
        Append(res.redFactors,fcn.redFactors);

        # compute new <f>
        prd:=Product(fcn.redFactors) * Product(fcn.irrFactors);

        f  :=f/prd;
        if IsBound(fcn.stop) then
          res.stop:=true;
          return res;
        fi;

        lc :=LeadingCoefficient(f);
        ofb:=2*AbsInt(lc)*OneFactorBound(f);
        Info(InfoPoly,2,"new one factor bound = ",ofb);

        # degree arguments or OFB arguments prove f irreducible
        if (ForAll(t.degrees,i->i=0 or 2*i>=DegreeOfLaurentPolynomial(f))
           or ofb<q) and DegreeOfLaurentPolynomial(f)>0 then
          Add(fcn.irrFactors,f);
          Add(res.irrFactors,f);
          f:=f^0;
        fi;

        # if <f> is trivial return
        if DegreeOfLaurentPolynomial(f) < 1  then
          Info(InfoPoly,2,"found non-trivial factorization");
          return res;
        fi;

        # compute the factor coefficient bounds
        k:=HenselBound(f);
        bounds:=List([ 1 .. Length(k) ],
                i -> Minimum(bounds[i],k[i]));
         k:=2 * AbsInt(lc)
             * bounds[Maximum(Filtered(t.degrees,
                         i-> 2*i<=DegreeOfLaurentPolynomial(f)))];
        Info(InfoPoly,2,"new Hensel bound = ",k);

        # remove true factors from <l> and corresponding <rep>
        prd:=(1/LeadingCoefficient(prd)) * prd mod q;
        l  :=l{fcn.remaining};
        rep:=List(rep{fcn.remaining},x -> prd * x);

        # reduce <rep>[i] mod <l>[i]
        for i  in [ 1 .. Length(l) ]  do
          #rep[i]:=rep[i] mod l[i] mod q;
          rep[i]:=CoefficientsOfLaurentPolynomial(rep[i]);
          rep[i]:=ShiftedCoeffs(rep[i][1],rep[i][2]);
          j:=CoefficientsOfLaurentPolynomial(l[i]);
          j:=ReduceCoeffsMod(rep[i],ShiftedCoeffs(j[1],j[2]),q);
          # shrink the list rep[i], according to the 'j' value
          rep[i]:=rep[i]{[1..j]};
          rep[i]:=LaurentPolynomialByCoefficients(
                    CyclotomicsFamily,rep[i],0,t.ind);
        od;

      # if there was a factor,we ought to have found it
      elif ofb < q  then
        Add(res.irrFactors,f);
        Info(InfoPoly,2,"f irreducible,since one factor would ",
               "have been found now");
        return res;
      fi;
    fi;

    # square modulus
    q1:=q;
    q :=q^2;

    # avoid a modulus too big
    if q > k  then
      q:=p^(LogInt(k,p)+1);
    fi;
  od;

  # return the remaining polynomials
  res.remPolynomial:=f;
  res.remaining  :=l;
  res.primePower   :=q1;
  res.lc       :=lc;
  return res;

end);


#############################################################################
##
#F  RPFactorsModPrime(<f>)   find suitable prime and factor
##
##  <f> must be squarefree.  We test 3 "small" and 2 "big" primes.
##
BindGlobal("RPFactorsModPrime",function(f)
local i,     # loops
      fc,    # f's coeffs
      lc,    # leading coefficient of <f>
      p,     # current prime
      PR,    # polynomial ring over F_<p>
      fp,    # <f> in <R>
      lp,    # factors of <fp>
      min,   # minimal number of factors so far
      P,     # best prime so far
      LP,    # factorization of <f> mod <P>
      deg,   # possible degrees of factors
      t,     # return record
      cof,   # new coefficients
      tmp;

  fc:=CoefficientsOfLaurentPolynomial(f)[1];
  # set minimal number of factors to the degree of <f>
  min:=DegreeOfLaurentPolynomial(f)+1;
  lc :=LeadingCoefficient(f);

  # find a suitable prime
  t:=rec(ind:=IndeterminateNumberOfLaurentPolynomial(f));
  p:=1;
  for i  in [ 1 .. 5 ]  do

    # reset <p> to big prime after first 3 test
    if i = 4  then p:=Maximum(p,1000);  fi;

    # find a prime not dividing <lc> and <f>_<p> squarefree
    repeat
      repeat
        p :=NextPrimeInt(p);
      until lc mod p <> 0 and fc[1] mod p <> 0;
      PR:=PolynomialRing(GF(p));
      tmp:=1/lc mod p;
      fp :=UnivariatePolynomialByCoefficients(FamilyObj(Z(p)),
           List(fc,x->((tmp*x) mod p)* Z(p)^0),1);
    until 0 = DegreeOfLaurentPolynomial(Gcd(PR,fp,Derivative(fp)));

    # factorize <f> modulo <p>
    Info(InfoPoly,2,"starting factorization mod p:  ",Runtime());
    lp:=Factors(PR,fp);

    Info(InfoPoly,2,"finishing factorization mod p: ",Runtime());

    # if <fp> is irreducible so is <f>
    if 1 = Length(lp)  then
      Info(InfoPoly,2,"<f> mod ",p," is irreducible");
      t.isIrreducible:=true;
      return t;
    else
      Info(InfoPoly,2,"found ",Length(lp)," factors mod ",p);
      Info(InfoPoly,2,"of degree ",List(lp,DegreeOfLaurentPolynomial));
    fi;

    # choose a maximal prime with minimal number of factors
    if Length(lp) <= min  then
      min:=Length(lp);
      P  :=p;
      LP :=lp;
    fi;

    # compute the possible degrees
    tmp:=Set(Combinations(List(lp,DegreeOfLaurentPolynomial)),Sum);
    if 1 = i  then
      deg:=tmp;
    else
      deg:=Intersection(deg,tmp);
    fi;

    # if there is only one possible degree != 0 then <f> is irreducible
    if 2 = Length(deg)  then
      Info(InfoPoly,2,"<f> must be irreducible,only one degree left");
      t.isIrreducible:=true;
      return t;
    fi;

  od;

  # convert factors <LP> back to the integers
  lp:=ShallowCopy(LP);
  for i  in [ 1 .. Length(LP) ]  do
    cof:=CoefficientsOfUnivariatePolynomial(LP[i]);
    #cof:=IntVecFFE(cof);
    cof:=List(cof,IntFFE);
    LP[i]:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,cof,t.ind);
  od;

  # return the chosen prime
  Info(InfoPoly,2,"choosing prime ",P," with ",Length(LP)," factors");
  Info(InfoPoly,2,"possible degrees: ",deg);
  t.isIrreducible:=false;
  t.prime    :=P;
  t.factors    :=LP;
  t.degrees    :=deg;
  return t;

end);


#############################################################################
##
#M  FactorsSquarefree(<R>,<f>,<opt>) . factors of <f>
##
##  <f> must be square free and must have a constant term.
##
InstallMethod( FactorsSquarefree, "univariate rational poly", true,
  [IsRationalsPolynomialRing,IsUnivariatePolynomial,IsRecord],0,
function(R,f,opt)
local t, h, fac, g, tmp;

  # find a suitable prime,if <f> is irreducible return
  t:=RPFactorsModPrime(f);
  if t.isIrreducible  then return [f];  fi;
  Info(InfoPoly,2,"using prime ",t.prime," for factorization");

  # for easy combining,we want large degree factors first
  Sort(t.factors,
    function(a,b)
      return DegreeOfLaurentPolynomial(a) > DegreeOfLaurentPolynomial(b);
    end);

  # start Hensel
  h:=RPSquareHensel(f,t,opt);

  # combine remaining factors
  fac:=[];

  # first the factors found by hensel
  if 0 < Length(h.remaining)  then
    Info(InfoPoly,2,"found ",Length(h.remaining)," remaining terms");
    tmp:=TryCombinations(
                   h.remPolynomial,
                   h.lc,
                   h.remaining,
                   h.primePower,
                   t,
                   h.bounds,
                   opt,
                   true,false);
    Append(fac,tmp.irrFactors);
    Append(fac,tmp.redFactors);
  else
    tmp:=rec();
  fi;

  # append the irreducible ones
  if 0 < Length(h.irrFactors)  then
    Info(InfoPoly,2,"found ",Length(h.irrFactors)," irreducibles");
    Append(fac,h.irrFactors);
  fi;

  # and try to factorize the (possible) reducible ones
  if 0 < Length(h.redFactors) then
    Info(InfoPoly,2,"found ",Length(h.redFactors)," reducibles");

    if not (IsBound(tmp.stop) or IsBound(h.stop)) then
        # the stopping criterion has not yet been reached
        for g  in h.redFactors  do
          Append(fac,FactorsSquarefree(R,g,opt));
        od;
    else
        Append(fac,h.redFactors);
    fi;
  fi;

  # and return
  return fac;

end);

BindGlobal("RPIFactors",function(R,f,opt)
local   fc,ind, v, g, q, s, r, x,shift;

  fc:=CoefficientsOfLaurentPolynomial(f);
  ind:=IndeterminateNumberOfLaurentPolynomial(f);
  # if <f> is trivial return
  Info(InfoPoly,2,"starting integer factorization: ",Runtime());
  if 0 = Length(fc[1])  then
    Info(InfoPoly,2,"<f> is trivial");
    return [ f ];
  fi;

  # remove a valuation
  v:=fc[2];
  f:=UnivariatePolynomialByCoefficients(CyclotomicsFamily,fc[1],ind);
  x:=LaurentPolynomialByCoefficients(CyclotomicsFamily,[1],1,ind);

  # if <f> is almost constant return
  if Length(fc[1])=1  then
    s:=List([1..fc[2]],i->x);
    s[1]:=s[1]*LeadingCoefficient(f);
    return s;
  fi;

  # if <f> is almost linear return
  if 1 = DegreeOfLaurentPolynomial(f)  then
    Info(InfoPoly,2,"<f> is almost linear");
    s:=List([1..v],f -> x);
    Add(s,f);
    return s;
  fi;

  # shift the zeros of f if appropriate
  if DegreeOfLaurentPolynomial(f) > 20  then
    g:=MinimizedBombieriNorm(f);
    f:=g[1];
    shift:=-g[2];
  else
    shift:=0;
  fi;

  # make <f> integral,primitive and square free
  g:=Gcd(R,f,Derivative(f));
  q:=PrimitivePolynomial(f/g)[1];
  q:=q * SignInt(LeadingCoefficient(q));
  Info(InfoPoly,3,"factorizing polynomial of degree ",
       DegreeOfLaurentPolynomial(q));

  # and factorize <q>
  if DegreeOfLaurentPolynomial(q) < 2  then
    Info(InfoPoly,2,"<f> is a linear power");
    s:=[ q ];
  else
    # treat zeroes (only one possible)
    s:=CoefficientsOfLaurentPolynomial(q)[2];
    if s>0 then
      s:=[x];
      q:=q/x;
    else
      s:=[];
    fi;
    s:=Concatenation(s,FactorsSquarefree(R,q,opt));
  fi;

  # find factors of <g>
  for r  in s  do
    if 0 < DegreeOfLaurentPolynomial(g)
       and DegreeOfLaurentPolynomial(g) >= DegreeOfLaurentPolynomial(r) then
      q:=Quotient(R,g,r);
      while 0 < DegreeOfLaurentPolynomial(g) and q <> fail  do
        Add(s,r);
        g:=q;
        if DegreeOfLaurentPolynomial(g)>=DegreeOfLaurentPolynomial(r) then
          q:=Quotient(R,g,r);
        else
          q:=fail;
        fi;
      od;
    fi;
  od;

  # reshift
  if shift<>0 then
    Info(InfoPoly,2,"shifting zeros back");
    Apply(s,i->Value(i,x+shift));
  fi;

  # sort the factors
  Append(s,List([1..v],f->x));
  Sort(s);

  if not (IsBound(opt.stopdegs) or IsBound(opt.onlydegs)) and Sum(s,DegreeOfLaurentPolynomial)<>DegreeOfLaurentPolynomial(f)+v then
    Error("degree discrepancy!");
  fi;

  # return the (primitive) factors
  return s;

end);


#############################################################################
##
#M  Factors(<R>,<f> ) . .  factors of rational polynomial
##
InstallMethod(Factors,"univariate rational polynomial",IsCollsElms,
  [IsRationalsPolynomialRing,IsUnivariatePolynomial],0,
function(R,f)
local r,cr,opt,irf,i;

  opt:=ValueOption("factoroptions");
  PushOptions(rec(factoroptions:=rec())); # options do not hold for
                                          # subsequent factorizations
  if opt=fail then
    opt:=rec();
  fi;

  cr:=CoefficientsRing(R);
  irf:=IrrFacsPol(f);
  i:=PositionProperty(irf,i->i[1]=cr);
  if i<>fail then
    # if we know the factors,return
    PopOptions();
    return ShallowCopy(irf[i][2]);
  fi;

  # handle trivial case
  if DegreeOfLaurentPolynomial(f) < 2  then
    StoreFactorsPol(cr,f,[f]);
    PopOptions();
    return [f];
  fi;

  # compute the integer factors
  r:=RPIFactors(R,PrimitivePolynomial(f)[1],opt);

  # convert into standard associates and sort
  r:=List(r,x -> StandardAssociate(R,x));
  Sort(r);

  if Length(r)>0 then
    # correct leading term
    r[1]:=r[1]*Quotient(R,f,Product(r));
  fi;

  # and return
  if not IsBound(opt.onlydegs) and not IsBound(opt.stopdegs) then
    StoreFactorsPol(cr,f,r);
    for i in r do
      StoreFactorsPol(cr,i,[i]);
    od;
  fi;
  PopOptions();
  return r;

end);

#############################################################################
##
#F  SymAdic( <x>, <b> ) . . . . . . . . . . symmetric <b>-adic expansion of <x>
#F  (<b> and <x> integers)
##
BindGlobal( "SymAdic", function(x,b)
  local l, b2, r;
  b2:=QuoInt(b,2);
  l:=[];
  while x<>0 do
    r:=x mod b;
    if r>b2 then
      r:=r-b;
    fi;
    Add(l,r);
    x:=(x-r)/b;
  od;
  return l;
end );


#############################################################################
##
#F  HeuGcdIntPolsExtRep(<fam>,<a>,<b>)
##
##  takes two polynomials ext reps, primitivizes them with integer
##  coefficients and tries to
##  compute a Gcd expanding Gcds of specializations.
##  Source: Geddes,Czapor,Labahn: Algorithm 7.4

#V MAXTRYGCDHEU: defines maximal number of attempts to find Gcd heuristically
MAXTRYGCDHEU:=6;

InstallGlobalFunction(HeuGcdIntPolsExtRep,function(fam,d,e)
local x,xd,er,i,j,k,m,p,sel,xi,gamma,G,g,loop,zero,add;

  # find the indeterminates and their degrees:
  x:=[];
  xd:=[[],[]];
  er:=[d,e];
  for k in [1,2] do
    for i in [1,3..Length(er[k])-1] do
      m:=er[k][i];
      for j in [1,3..Length(m)-1] do
        p:=Position(x,m[j]);
        if p=fail then
          Add(x,m[j]);
          p:=Length(x);
          xd[1][p]:=0;
          xd[2][p]:=0;
        fi;
        xd[k][p]:=Maximum(xd[k][p],m[j+1]);
      od;
    od;
  od;

  # discard the indeterminates which occur in only one of the polynomials
  sel:=[];
  for i in [1..Length(x)] do
    if xd[1][i]>0 and xd[2][i]>0 then
      Add(sel,i);
    fi;
  od;
  x:=x{sel};
  xd:=List(xd,i->i{sel});

  # are the variables disjoint or do we have no variables at all?
  if Length(x)=0 then
    # return the gcd of all coefficients involved
    G:=Gcd(Concatenation(d{[2,4..Length(d)]},e{[2,4..Length(e)]}));
    return G;
  fi;

  # pick the first indeterminate
  x:=x[1];
  xd:=[xd[1][1],xd[2][1]];

  xi:=2*Minimum(Maximum(List(d{[2,4..Length(d)]},AbsInt)),
                Maximum(List(e{[2,4..Length(e)]},AbsInt)))+2;

  for loop in [1..MAXTRYGCDHEU] do
    if LogInt(AbsInt(Int(xi)),10)*Maximum(xd)>5000 then
      return fail;
    fi;
    # specialize both polynomials at x=xi
    # and compute their heuristic Gcd
    gamma:=HeuGcdIntPolsExtRep(fam,
              SpecializedExtRepPol(fam,d,x,xi),
              SpecializedExtRepPol(fam,e,x,xi) );

    if gamma<>fail then
      # generate G from xi-adic expansion
      G:=[];
      i:=0;
      if IsInt(gamma) then
        zero:=Zero(gamma);
      else
        zero:=[];
      fi;
      while gamma<>zero do
        if IsInt(gamma) then
          # gamma is an integer value
          g:=gamma mod xi;
          if g>xi/2 then
            g:=g-xi; # symmetric rep.
          fi;
          gamma:=(gamma-g)/xi;
          if i=0 then
            add:=[[],g];
          else
            add:=[[x,i],g];
          fi;
        else
          # gamma is an ext rep
          g:=[];
          for j in [2,4..Length(gamma)] do
            k:=gamma[j] mod xi;
            if k>xi/2 then
              k:=k - xi; #symmetric rep
            fi;
            if k<>0*k then
              Add(g,gamma[j-1]);
              Add(g,k);
            fi;
          od;
          #gamma:=(gamma-g)/xi in ext rep;
          add:=ShallowCopy(g);
          add{[2,4..Length(add)]}:=-add{[2,4..Length(add)]}; #-g
          gamma:=ZippedSum(gamma,add,0,fam!.zippedSum); # gamma-g
          gamma{[2,4..Length(gamma)]}:=gamma{[2,4..Length(gamma)]}/xi; # /xi
          #add:=g*xp^i; in extrep
          add:=ZippedProduct(g,[[x,i],1],0,fam!.zippedProduct);
        fi;
        # G:=G+add in extrep
        G:=ZippedSum(G,add,0,fam!.zippedSum);
        i:=i+1;
      od;

      if Length(G)>0 and Length(G[1])>0 and
         QuotientPolynomialsExtRep(fam,d,G)<>fail and
         QuotientPolynomialsExtRep(fam,e,G)<>fail then
        return G;
      fi;
    fi;
    xi:=QuoInt(xi*73794,27011); #square of golden ratio
  od;
  return fail;
end);

# and the same in univariate
InstallGlobalFunction(HeuGcdIntPolsCoeffs,function(f,g)
local xi, t, h, i, lf, lg, lh,fr,gr;

  if IsEmpty(f) or IsEmpty(g) then
    return fail;
  fi;
  # first test value for heuristic gcd:
  xi:=2+2*Minimum(Maximum(List(f,AbsInt)),Maximum(List(g,AbsInt)));
  i:=0;
  lf:=Last(f);
  lg:=Last(g);

  # and now the tests:
  while i< MAXTRYGCDHEU do

    # xi-adic expansion of Gcd(f(xi),g(xi)) (regarded as coefficient list)
    h:=Gcd(  ValuePol(f,xi),
             ValuePol(g,xi) );
    h:=SymAdic(h,xi);

    # make it primitive:
    t:=Gcd(h);
    if t<>1 then
      h:=h/t;
    fi;
    lh:=Last(h);

    # check if it divides f and g: if yes, ready! if no, try larger xi

    ## this should be done more efficiently !
    if RemInt(lg,lh)=0 and RemInt(lf,lh)=0 then
      fr:=ShallowCopy(f);
      ReduceCoeffs(fr,h);
      gr:=ShallowCopy(g);
      ReduceCoeffs(gr,h);
      t:=Set(Concatenation(fr,gr));
    else
      t:=false;
    fi;
    if t=[0] then
      Info(InfoPoly,4,"GcdHeuPrimitiveList: tried ",i+1," values");
      return h;
    else
      i:=i+1;
      xi:=QuoInt(xi*73794,27011);
    fi;
  od;
  Info(InfoPoly,2,"GcdHeuPrimitiveList: failed after trying ",
             MAXTRYGCDHEU," values");
  return fail;
end);


InstallMethod(HeuristicCancelPolynomialsExtRep,"rationals",true,
  [IsRationalFunctionsFamily,IsList,IsList],0,
function(fam,a,b)
local nf,df,g;
  if not (HasCoefficientsFamily(fam)
     and IsIdenticalObj(CoefficientsFamily(fam),CyclotomicsFamily)
     and ForAll(a{[2,4..Length(a)]},IsRat)
     and ForAll(b{[2,4..Length(b)]},IsRat)) then
    # the coefficients are not all rationals
    TryNextMethod();
  fi;

  # make numerator and denominator primitive with integer coefficients
  nf:=PrimitiveFacExtRepRatPol(a);
  if not IsOne(nf) then
    a:=ShallowCopy(a);
    a{[2,4..Length(a)]}:=a{[2,4..Length(a)]}/nf;
  fi;

  df:=PrimitiveFacExtRepRatPol(b);
  if not IsOne(df) then
    b:=ShallowCopy(b);
    b{[2,4..Length(b)]}:=b{[2,4..Length(b)]}/df;
  fi;

  # the remaining common factor
  nf:=nf/df;
  g:=HeuGcdIntPolsExtRep(fam,a,b);
  if IsList(g) and (Length(g)>2 or (Length(g)=2 and Length(g[1])>0)) then
    # make g primitive
    df:=PrimitiveFacExtRepRatPol(g);
    if not IsOne(df) then
      g:=ShallowCopy(g);
      g{[2,4..Length(g)]}:=g{[2,4..Length(g)]}/df;
    fi;

    Info(InfoPoly,3,"Heuristic integer gcd returns ",g);

    a:=QuotientPolynomialsExtRep(fam,a,g);
    b:=QuotientPolynomialsExtRep(fam,b,g);
    if a<>fail and b<>fail then
      a{[2,4..Length(a)]}:=a{[2,4..Length(a)]}*nf;
      g:=[a,b];
      return g;
    fi;
  fi;
  return fail;
end);

InstallGlobalFunction(PolynomialModP,function(pol,p)
local f, cof;
   f:=GF(p);
   cof:=CoefficientsOfUnivariatePolynomial(pol);
   return UnivariatePolynomial(f,cof*One(f),
             IndeterminateNumberOfUnivariateRationalFunction(pol));
end);

[ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge