############################################################################# ## ## 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;
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 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)>2then
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=0then
c:=6; else if nf>lf then
lf:=nf/lf; else
lf:=lf/nf; fi; if lf<2then
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;
# 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]=0do
Unbind(p[d]);
d:=d-1;
od;
v:=p[1]; if v=0then
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<0then # 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=0then
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>=3then # 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);
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)>0then
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)>0then
fac:=fac*Gcd(d); fi;
return 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; while0 < 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;
# 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);
# 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 if0 = 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;
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; elif0 = 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);
# 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<>0then
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;
# if <f> is zero return it if0 = 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);
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 := []; while0 < 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);
# compute conversion for standard associate
q := (1/Last(s)) mod p;
# convert <s> and <x> back into polynomials if0 = 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)>1then
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>1then if rb=0then
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>1then # 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.
############################################################################# ## #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=0then # Special case (that has to return 0)
a:=b[1]; else
a:=b[a]; fi; if0=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);
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); if0 = 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;
# 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; if0 < 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;
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 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)=1then
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);
# if we have found a true factor update everything if0 < 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)>0then
Add(fcn.irrFactors,f);
Add(res.irrFactors,f);
f:=f^0; fi;
# if <f> is trivial return if DegreeOfLaurentPolynomial(f) < 1then
Info(InfoPoly,2,"found non-trivial factorization");
return res; fi;
# 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;
############################################################################# ## #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 = 4then 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)));
Info(InfoPoly,2,"finishing factorization mod p: ",Runtime());
# if <fp> is irreducible so is <f> if1 = 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); if1 = i then
deg:=tmp; else
deg:=Intersection(deg,tmp); fi;
# if there is only one possible degree != 0 then <f> is irreducible if2 = 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 if0 < 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 if0 < 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 if0 < 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()); if0 = 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])=1then
s:=List([1..fc[2]],i->x);
s[1]:=s[1]*LeadingCoefficient(f);
return s; fi;
# if <f> is almost linear return if1 = 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) > 20then
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) < 2then
Info(InfoPoly,2,"<f> is a linear power");
s:=[ q ]; else # treat zeroes (only one possible)
s:=CoefficientsOfLaurentPolynomial(q)[2]; if s>0then
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 if0 < DegreeOfLaurentPolynomial(g)
and DegreeOfLaurentPolynomial(g) >= DegreeOfLaurentPolynomial(r) then
q:=Quotient(R,g,r); while0 < 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<>0then
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) < 2then
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)>0then # 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<>0do
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]>0then
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)=0then # 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]];
for loop in [1..MAXTRYGCDHEU] do if LogInt(AbsInt(Int(xi)),10)*Maximum(xd)>5000then
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/2then
g:=g-xi; # symmetric rep. fi;
gamma:=(gamma-g)/xi; if i=0then
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/2then
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<>1then
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)=0then
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;
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);
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.116Bemerkung:
(vorverarbeitet am 2026-10-12)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.