factorization.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 

class SET_POLYI_HENSEL

class SET_POLYI_HENSEL is -- Expand DPolyM in Zp[x] to PolyM in Z[x] with PolyM|PolyN -- DpolyMs to Z-coefficient witn Hensel's construction setgL1(g:POLYS_INTI):INTI is l::=0.inti; loop c::=g.arr.elt!; l:=l+c.abs; end; return l; end; setPolyRHensel(prime:INTI,inout PolyN, DpolyM:POLYS_INTI, out factor:POLYS_INTI):BOOL is factor:=#; h,q,r:POLYS_INTI; f:POLYS_INTI:=PolyN.copy; if f.lc.is_neg then f:=-f; end; f_lc::=f.lc; f.monic; -- DpolyMs:=DpolyM.mod_n(prime) g:POLYS_INTI:=DpolyM.mod_n(prime); --g:=g*(lc^(g.degree)*INTI_EXT::inv(prime,g.lc)); --g:=g.substitute(Poly("x")/lc).coeff_to_Zp(prime,false); g.pseudo_monic(f_lc); g:=g.mod_n(prime); f.divmod(g,out q, out r); if r.is_zero then g:=g.substitute(#POLYS_INTI(f_lc,1)); g.remove_gcd; PolyN.divmod(g,out PolyN, out r); factor:=g; return true; end; -- if ! Number.checkDivZ?(f[0],g[0],prime); return false;end f.divmod_Zp(prime, g,out h, out r); --- To bound iteration. -- F= fk x^k +...+f1 x^1+f0, G= gl x^l +...+gx x^1+g0 -- Let fL2= sqrt(|fk|^2+...+|f0|^2)* (gl/fk *2^l), gL1= (|gl|+..+|g0|) -- then gL1<= fL2. -- Iterate until |max coefficient of g| < gL1 <= fL2 < pn/2. -- (Note thet f.lc==1, g.lg==1, pn=prime^n) -- Let fMax=(max coefficient of f). -- Check if divisible when pn^n>fMax, fL2::=1.inti; fMax::=0.inti; loop c::=f.arr.elt!; fL2:=fL2+c*c; if fMax<c.abs then fMax:=c.abs; end; end; fL2:=(fL2*(4.inti)^(g.degree)).sqrt; -- n::=1.inti; pn::=prime; -- pn=prime^n gL1::=setgL1(g); loop while!( (pn<fL2*2.inti)and (gL1<=fL2)); f.constructionHensel(g,h,n,prime,pn,out g, out h); n:=n+1.inti; pn:=pn*prime; if (pn>fMax)and (f-g*h).is_zero then g:=g.substitute(#POLYS_INTI(f_lc,1)); g.remove_gcd; PolyN.divmod(g,out PolyN,out r); factor:=g; return true; end; gL1:=setgL1(g); end; return false; end; end;

class SET_POLYI_PRIM

class SET_POLYI_PRIM is -- Expand DPolyM in Zp[x] to PolyM in Z[x] with PolyM|PolyN -- with simple try&error. -- 1. Make value sa if substitute integer [-PolyN.degree/4..PolyN.degree/4] -- to expected factor. -- 2. And construct the factor. shared TblS:ARRAY{INTI};-- work table shared V0,V1,V1nS:ARRAY{INTI}; shared DpolyMs:POLYS_INTI; shared PolyN:POLYS_INTI; shared PolyF:POLYS_INTI; -- factor -- degD=DpolyM.degree for almost part. setPolyR(degD:CARD,prime:INTI, out polyF:POLYS_INTI):BOOL is -- TRUE if Set set polynomial PolyF[] from TblS[] -- From dPolyM in Zp[x], recover polyF in Z[x]. -- local var: dv,dt,at, deg,diff,i, tbl0, tbl2 tbl0,tbl2:ARRAY{INTI}; polyF:=#; polyF.arr:=#(degD); polyF.clear; -- polyF.array.fill(0,0..degD) tbl0:=TblS.copy; loop deg:CARD:=degD.downto!(1); tbl2:=tbl0.copy; dv:INTI:=1.inti; loop diff::=deg.downto!(1); loop i::=0.upto!(diff-1); tbl2[i]:=tbl2[i+1]- tbl2[i]; end; dv:=dv*diff.inti; end; if ((tbl2[0] % dv) /= 0.inti) then return false; end; at:INTI:=tbl2[0] / dv; polyF[deg]:=DpolyMs[deg]+at*prime; loop i::=0.upto!(deg); dt:INTI:=at; dv:=i.inti-(degD/2).inti; loop deg.times!; dt:=dt*dv; end; tbl0[i]:=tbl0[i] - dt; end; end; polyF[0]:=DpolyMs[0]+tbl0[0]*prime; polyF:=polyF.normalize; return true; end; setV0Tbl(degD:CARD) is -- make table PolyN. -- Elements are non-zero, -- because PolyN has no factor (x-a) in this range V0:=#(degD+1); loop i::=0.upto!(degD); V0[i]:=PolyN.substitute(i.inti-(degD/2).inti).abs; end; end; setV1Tbl(degD:CARD) is -- make table DpolyMs V1:=#(degD+1); loop i::=0.upto!(degD); V1[i]:=DpolyMs.substitute(i.inti-(degD/2).inti); end; end; setVal(ite,degD:CARD, prime:INTI):BOOL is -- "true" if ffind a factor. -- Note that change PolyN and PolyM. v0i:INTI:=V0[ite]; v1i:INTI:=V1[ite]; setFlg:BOOL:=false; -- (v1i+prime*a)|v0i then range of a is -- (-v0i-v1i)/prime..(v0i-v1i)/prime a:INTI:=0.inti; if a<(-v0i-v1i)/prime then a:=(-v0i-v1i)/prime; end; if a>(v0i-v1i)/prime then a:=(v0i-v1i)/prime; end; loop while!( ((-v0i-v1i)/prime<=a)and(a<=(v0i-v1i)/prime)); v1n:INTI:=(v1i+prime*a).abs; if ((v1n /=0.inti) and ((v0i % v1n)=0.inti)) then -- V1nS[ite]:=v1n; TblS[ite]:=a; if (ite>=degD) then polyQ, polyR:POLYS_INTI; setFlg:=setPolyR(degD,prime,out PolyF); if setFlg then PolyN.divmod(PolyF,out polyQ,out polyR); if polyR.is_zero then -- Now, PolyF is factor. -- printf "M=%s F=%s prime=%d\n",DpolyMs.to_s,polyF.to_s,prime PolyN:=polyQ; -- The polynomial is square free, so, -- this is only one factor having DpolyM -- throw(:setValTag,true); return true; end; end; else if setVal(ite+1,degD,prime) then return true; end; end; end; if a<=0.inti then a:=1.inti-a; if a>(v0i-v1i)/prime then a:=-a; end; else a:=-a; if a<(-v0i-v1i)/prime then a:=1.inti-a; end; end; end; return false; end; setPolyRPrimitive(prime:INTI, inout PolyNx, DpolyM:POLYS_INTI, out factor:POLYS_INTI):BOOL is PolyN:=PolyNx; loop i:INTI:=1.inti.upto!(prime); -- adjust leading coefficient. -- This is not needed if PolyN,DpolyM are monic. dpolym::=(DpolyM*i).mod(prime); if INTI_EXT::checkDivZ(PolyN.lc,dpolym.lc,prime)and INTI_EXT::checkDivZ(PolyN[0],dpolym[0],prime) then DpolyMs:=dpolym.mod_n(prime); degD::=DpolyM.degree.card; -- V1nS:=#(degD+1); TblS:=#(degD+1); setV0Tbl(degD); setV1Tbl(degD); if setVal(0,degD,prime) then factor:=PolyF; PolyNx:=PolyN; return true; end; end; end; return false; end; end;

class FACTORIZATION_ALG

class FACTORIZATION_ALG is -- Factorize a polynomial -- Let p:prime. --(1) Let Ap be A in Zp<t>. -- if Ap=1 ; Apd:=1; Resume. --(2) Search A'p s.t. A'p | Apd in Zp[x]. --(3) Check of A' | A in Z[x] -- -- Contain algorithms of -- 2 type of factorization in Zp[x] and -- 2 type of constructing polynomials in Z[x] from Zp[x]. -- as module variables -- shared Factor:ARRAY{POLYS_INTI}; shared FactorP:ARRAY{POLYS_INTI}; -- factors in Z/(prime)Z shared PolyN:POLYS_INTI; -- Normalized shared PolyM:POLYS_INTI; -- PolyN in Zp shared DpolyM:POLYS_INTI; -- divisor in Zp i.e. DpolyM|PolyM shared DpolyMs:POLYS_INTI;-- change each coefficient to little abs init is Factor:=#; FactorP:=#; PolyN:=#; PolyM:=#; DpolyM:=#; DpolyMs:=#; end; checkDivZp(dividend,divisor:POLYS_INTI, prime:INTI):BOOL is -- true if divisible in Zp --if true then -- test -- q,r:POLYS_INTI; -- dividend.divmod_Zp(prime, divisor,out q, out r); return r.is_zero; --end; dq,degR,degD:CARD; q1,topDm:INTI; degR:=dividend.degree.card; degD:=divisor.degree.card; if degR < degD then return false; end; darray::=divisor.arr; rarray::=dividend.array.copy; -- Remainder(dividend) topDm:=prime-INTI_EXT::inv(prime,darray[degD]); -- -1/divisor.lc loop while!(degR>=degD); q1:=(rarray[degR]*topDm)%prime; if q1.is_zero.not then loop i::=0.upto!(degD-1); j::=(degR-degD).up!; rarray[j] := rarray[j]+darray[i]*q1; end; -- rarray[degR]:=0.inti; end; degR:=degR - 1; end; loop i::=0.upto!(degD-1); if (rarray[i] % prime).is_zero.not then return false; end; end; return true; end; -- Expand DPolyM in Zp[x] to PolyM in Z[x] with PolyM|PolyN resume(prime:INTI):BOOL is -- TRUE if find Factors -- #OUT+"resume: prime="+prime.str+", d="+DpolyM.str+"\n"; findFlg::=false; factor:POLYS_INTI; if false then -- for test --#OUT+"PolyN="+PolyN.str+", DpolyM="+DpolyM.str+ -- ", prime="+prime.str+"\n"; findFlg:=SET_POLYI_PRIM::setPolyRPrimitive (prime, inout PolyN, DpolyM, out factor); elsif DpolyM.degree>=5.int then findFlg:=SET_POLYI_HENSEL::setPolyRHensel (prime,inout PolyN, DpolyM, out factor); else findFlg:=SET_POLYI_PRIM::setPolyRPrimitive (prime, inout PolyN, DpolyM, out factor); end; if findFlg then Factor:=Factor.append(|factor|); PolyM:=PolyN.mod(prime); end; return findFlg; end; ----------------following PROCEDUREs work in Zp[t]------------- -- Note that the polynomial PolyN is square free in Zp -- set DpolyM with Berlekamp's algorithm -- -- DpolyM | PolyN over Zp printQ(q:MAT_INTI) is #OUT+"["; loop i::=0.upto!(q.nr-1); loop j::=0.upto!(q.nc-1); #OUT+q[i][j].str+", "; end; #OUT+"\n"; end; #OUT+"]\n"; end; getQ(f:POLYS_INTI,prime:INTI):MAT_INTI is q:MAT_INTI; w1,w2,w3:POLYS_INTI; n::=f.degree.card; w1:=POLYS_INTI::x^prime; w1.divmod_Zp(prime,f, out w3, out w1); w2:=POLYS_INTI::one; q:=#(n,n); a:ARRAY{INTI}; loop i::=0.upto!(q.nr-1); a:=#(n); a.to_val(0.inti); loop j::=w2.arr.ind!; a[j]:=w2.arr[j]; end; q[i]:=a; (w2*w1).divmod_Zp(prime,f,out w3,out w2); end; return q; end; solveQ1(q:MAT_INTI,prime:INTI):ARRAY{POLYS_INTI} is n::=q.nr; q0:MAT_INTI:=q.copy; loop i::=0.upto!(n-1); q[i][i]:=(q[i][i]+prime-1.inti)%prime; end; -- printQ(q); pivot:ARRAY{INT}:=#(n); pivot.to_val(-1); loop i::=0.upto!(n-1); -- set pivot j1:CARD; loop j1:=0.up!; while!((j1<n)and((q[i][j1]=0.inti)or(pivot[j1]/=-1))); end; if j1<n then q.swap_col(i,j1, i,n-1); pivot[i]:=i.int; j::=i; pvr::=INTI_EXT::inv(prime,q[i][j]); loop j1:=0.upto!(n-1); if j1 /= j then d::=((prime-q[i][j1])*pvr)%prime; q.col_plus_scaled_col(j1,j,d); q.col_mod(j1,prime); end; end; end; end; -- printQ(q); solve:ARRAY{POLYS_INTI}:=#; loop i::=0.upto!(n-1);--(n-2); if pivot[i]=-1 then v:ARRAY{INTI}:=#(n); v.to_val(0.inti); v[i]:=1.inti; loop j::=0.upto!(n-1); v[j]:=(v[j]+prime-(q[i][j]*INTI_EXT::inv(prime,q[j][j]))%prime)%prime; end; u::=POLYS_INTI::zero; x::=POLYS_INTI::x; loop j::=0.upto!(n-1); xj::=x^j; loop k::=0.upto!(n-1); u:=u+xj*v[k]*q0[k][j]; end; end; solve:=solve.append(|u.mod(prime)|); end; end; return solve; end; genFactors(f:POLYS_INTI, uList:ARRAY{POLYS_INTI}, prime:INTI):ARRAY{POLYS_INTI} is gcdList1:ARRAY{POLYS_INTI}; loop u:POLYS_INTI:=uList.elt!; loop c::=#INTI(0).upto!(prime-1.inti); g::=f.gcd_Zp(prime, u+c); if g.degree.is_pos then gcdList1:=gcdList1.append(|g|); end; end; end; i::=0; changeFlg::=false; loop while!( i<gcdList1.size-1); gcdList1.sort; -- small is top j::=i+1; changeFlg:=false; loop while!(j<gcdList1.size); r,q:POLYS_INTI; gcdList1[j].divmod_Zp(prime, gcdList1[i],out q, out r); if r.is_zero then changeFlg:=true; if q.degree.is_pos then gcdList1[j]:=q; j:=j+1; else gcdList1:=ARRAY_EXT{POLYS_INTI}::delete_at(j,gcdList1); end; else j:=j+1; end; end; if changeFlg then i:=0; else i:=i+1; end; end; -- printf "gcdList1:\n"; gcdList1.each{|f|printf "%s\n",f} loop i:=0.upto!(gcdList1.size-1); g::=gcdList1[i]; gcdList1[i]:=(g*INTI_EXT::inv(prime,g.lc)).mod(prime); end; return gcdList1; end; setPolyB(depth:CARD, dpoly:POLYS_INTI, prime:INTI):BOOL is -- true if factor is determined if depth<FactorP.size then if setPolyB(depth+1,dpoly,prime) then if dpoly/=POLYS_INTI::one then return true; end; end; if depth=0 then if PolyN.degree.is_pos then Factor:=Factor.append(|PolyN|); PolyN:=POLYS_INTI::one; end; return true; else dpoly:=dpoly*FactorP[depth]; if setPolyB(depth+1,dpoly,prime) then FactorP:=ARRAY_EXT{POLYS_INTI}::delete_at(depth,FactorP);return true; end; return false; end; else if dpoly.degree.is_pos then DpolyM:=dpoly.mod(prime); -- DpolyMs:=dpoly.mod_n(prime); -- #OUT+"setPolyB: prime="+prime.str+", d="+DpolyM.str+"\n"; f_r:BOOL:=resume(prime); return f_r; -- TRUE if find Factors else return false; end; end; end; setPolyBerlekamp(prime:INTI) is f::=PolyM.mod(prime); --#OUT+"PolyM: "+PolyM.str+"\n"; q::=getQ(f,prime); --printQ(q); uList::=solveQ1(q,prime); --#OUT+"uList:"+uList.str+"\n"; factors::=genFactors(f,uList,prime); --#OUT+"factors:"+factors.str+"\n"; FactorP:=factors; --#OUT+"FactorP:"+FactorP.str+"\n"; if setPolyB( 0, POLYS_INTI::one, prime ) then ; end; end; -- set DpolyM with simple try&error -- -- DpolyM | PolyN over Zp checkZp(i:INTI,prime:INTI):BOOL is if PolyN.degree<DpolyM.degree*2 then return true; end; return checkDivZp(PolyM,DpolyM,prime) and resume(prime); end; setPoly2(d:CARD,prime:INTI,degD:CARD):BOOL is -- true if factors are determined. c:INTI:=0.inti; c0:INTI:=(prime/2.inti); loop DpolyM[d]:=c; if (d<=0) then --#OUT+"setPoly2: PolyN="+PolyN.str+", DpolyM="+DpolyM.str+"\n"; if (c>0.inti)and checkZp(c,prime) and (PolyN.degree<degD.int*2) then return true;--throw(:setPolyTag) end; else if setPoly2(d-1,prime,degD) then return true; end; end; if c<=c0 then c:=prime-c-1.inti; if c=c0 then return false; end; else c:=prime-c; end; end; return false; end; setPoly(d:CARD,prime:INTI):BOOL is loop degD::=1.upto!(d); DpolyM[degD]:=1.inti; -- Set DpolyM as monic. if (PolyN.degree<(degD*2).int) then return true;-- throw(:setPolyTag); end; if setPoly2(degD-1,prime,degD) then return true; end; end; return false; end; factorizeSqrFree(p:POLYS_INTI):ARRAY{POLYS_INTI} is --- factorize a square free polynomial Factor:=#; PolyN:=p.remove_gcd; if PolyN[0]=0.inti then PolyN.arr:=ARRAY_EXT{INTI}::delete_at(0,PolyN.arr); Factor:=Factor.append(|POLYS_INTI::x|); end; degN::=PolyN.degree; a::=1.inti; loop while!((a<=degN.inti)and(a<=PolyN[0].abs)); loop while!(((PolyN[0]%a).is_zero)and(PolyN.substitute(a).is_zero)); polyF::=POLYS_INTI::x-a; Factor:=Factor.append(|polyF|); PolyN:=PolyN/polyF; degN:=PolyN.degree; end; if a.is_pos then a:=-a; else a:=1.inti-a; end; end; if degN=1.int then Factor:=Factor.append(|PolyN|); return Factor; elsif degN=0.int then return Factor; end; -- From here, we can assume -- that the polynmial has no factor (x-a), |a|<=degN/4 -- With setPoly and setVal/setPolyR, -- time order for setPoly may be -- ~ k*prime^(degN/2) , k=? -- time order for setVal -- ~ l*(2fp/prime)^(degN/2), l=? -- fp=geometric mean of f(x) (x in (-degN/4..degN/2-degN/4)) -- x=prime, d=degN, -- Assume that O(x)= kx^(d/2)+ l(2fp/x)^(d/2) -- O is minimal at x=(l/k)^{1/d} (2v)^{1/2} fp::=1.inti; loop x::=(-(degN/4)).upto!(degN/2-(degN/4)); fp:=fp*PolyN.substitute(x.inti).abs; end; --#OUT+"fp="+fp.str+"\n"; fp_fltd::=(fp.fltd)^((1.fltd)/(degN.fltd/2.fltd+1.fltd)); --#OUT+"fp="+fp_fltd.str+"\n"; fp_fltd:=(fp_fltd.fltd/30.fltd).sqrt.floor; fp:=fp_fltd.int.inti; --#OUT+"fp="+fp_fltd.str+"\n"; prime:INTI:=INTI_EXT::next_prime(fp-1.inti); --#OUT+"Set prime = "+prime.str+", PolyN="+PolyN.str+"\n"; -- serach prime s.t. -- leading coefficient and bottom coefficient does not vanish, -- and square free over Zp head::=PolyN.lc.abs; tail::=PolyN[0].abs; loop while!((prime<=3.inti)or((head%prime).is_zero) or((tail%prime).is_zero)or(PolyN.is_SqrFree(prime).not)); prime:=INTI_EXT::next_prime(prime); end; --#OUT+"Set prime = "+prime.str+", PolyN="+PolyN.str+"\n"; PolyM:=PolyN.mod(prime); --#OUT+"degN="+degN.str+", PolyN="+PolyN.str+", PolyM="+PolyM.str+"\n"; -- Switch algorithms according to degree of the polynomial. if false then -- test --setPolyBerlekamp(prime); DpolyM:=#; if setPoly(degN.card/2,prime) then ; end; elsif PolyN.degree<11.int then DpolyM:=#; if setPoly(degN.card/2,prime) then ; end; else DpolyM:=#; if setPoly(3,prime) then ; end; if (PolyN.degree<10.int) then DpolyM:=#; if setPoly(PolyN.degree.card/2,prime) then ; end; else ; setPolyBerlekamp(prime); end; end; if (PolyN.degree.is_pos) then Factor:=Factor.append(|PolyN|); end; -- Make leading coefficients positive. loop i::=Factor.ind!; if Factor[i].lc.is_neg then Factor[i]:=-Factor[i]; end; end; Factor.sort; return Factor; end; factorize(poly:POLYS_INTI):ARRAY{POLYS_INTI} is -- factorize a polynomial -- wrapper of factorizeSqrFree(p) init; p::=poly.remove_gcd; sqrF::=p.squareFreeDecomposition; factorA:ARRAY{POLYS_INTI}:=#; loop i::=sqrF.ind!; f::=sqrF[i]; if f.degree.is_pos then ff:ARRAY{POLYS_INTI}:=factorizeSqrFree(f); loop i.times!; loop ffc::=ff.elt!.copy; factorA:=factorA.append(|ffc|); end; end; end; end; -- Make leading coefficients positive. loop i::=factorA.ind!; if factorA[i].lc.is_neg then factorA[i]:=-factorA[i]; end; end; factorA.sort; init; return factorA; end; end;