// -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c -Wall modfactor.cc" -*- #include "giacPCH.h" /* * Copyright (C) 2000,7 B. Parisse, Institut Fourier, 38402 St Martin d'Heres * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using namespace std; #include "sym2poly.h" #include "modpoly.h" #include "modfactor.h" #include "giacintl.h" #include #include #include "pari.h" #include "gen.h" // uncomment to remove NTL factorization // #undef HAVE_LIBNTL // #undef HAVE_LIBPARI #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC static int debuglevel=0; // ****************************************************************** // Modular factorization for univariate polynomial factorization in Z // assumes q is univariate, square-free in Z/modulo*Z // assumes modulo is prime !=2 // ****************************************************************** // find modular roots and linear factors bool roots(const modpoly & q,environment * env, vecteur & v,vector & w){ modpoly ddfactor(q); modpoly x(xpower1()); gen pn=env->pn; normalize_env(env); // try modulars from -modulo/2 to modulo/2 int moduloover2=env->pn.val/2; if (env->complexe){ for (int i=-moduloover2;i<=moduloover2;i++){ for (int j=-moduloover2;j<=moduloover2;j++){ gen tmp(i,j); if ( is_zero(horner(ddfactor,tmp,env)) ){ modpoly linearfact(x); linearfact=linearfact-tmp*one(); v.push_back(tmp); w.push_back(linearfact); ddfactor=operator_div(ddfactor,linearfact,env); } } } return true; } modpoly xtop(xpowerpn(env)); if (is_undef(xtop)) return false; if (ddfactor.size()-1){ for (int i=0;icoeff.makegen(i); gen evaluation=horner(ddfactor,gi,env); // CERR << gi << ":" << evaluation << endl; if ( is_zero(evaluation) ){ modpoly linearfact(x); linearfact=linearfact-gi*one(); v.push_back(gi); w.push_back(linearfact); ddfactor=operator_div(ddfactor,linearfact,env); } } } return true; } // v[i]=x^(pn*i) mod q // matrix of the v[i] for i=0..jstart or i=0..degree(q) if jstart=0 void qmatrix(const modpoly & q,environment * env,vector & v,int jstart){ v.clear(); int dim; if (jstart) dim=jstart; else dim=int(q.size())-1; normalize_env(env); v.reserve(dim); modpoly temp(one()),temp2,temp3; v.push_back(temp); if ( env->pn.type==_INT_ && env->pn.valpn.val; for (int i=1;ipn,q,env)); for (int i=1;i & v, environment * env,int qsize,modpoly & s){ s.clear(); if (r.empty()) return true; normalize_env(env); int rs=int(r.size()); if ((rs-1)*env->pn.valpn.val); return !is_undef(s); } int d=int(v.size()); if (rs-1>=d) return false; // setsizeerr(); int maxdeg(1); // maximal degree+1 // make an array of iterator pointing to the cst coeff of v[] // and find maximal degree of v #if 1 // def VISUALC modpoly::const_iterator *itv = new modpoly::const_iterator[d],*itvptr; #else modpoly::const_iterator itv[d],*itvptr; #endif vector::const_iterator vitend=v.end(),vit=v.begin(); for (itvptr=itv;vit!=vitend;++vit,++itvptr){ * itvptr=vit->end(); maxdeg=giacmax(maxdeg,int(vit->size())); } #if 1 // def VISUALC gen * res = new gen[maxdeg]; #else gen res[maxdeg]; #endif gen * resptr=res; modpoly::const_iterator itend=r.end(),itbeg=r.begin(); --itend; --itbeg; if ( env->moduloon && is_zero(env->coeff) && env->pn.type==_INT_ && env->pn.valbegin()){ --(*itvptr); // decreases iterator to increase power of x to x^i res += (it->val)*((*itvptr)->val); } else * (int *) &(*itvptr)=0; // mark that v[] has no coeff of order >=i } } *resptr=gen(res); } } else { for (int i=0;ibegin()){ --(*itvptr); // decreases iterator to increase power of x to x^i *resptr=*resptr+(*it)*(*(*itvptr)); } else * (int *) &(*itvptr)=0; // mark that v[] has no coeff of order >=i } } } } // trim the result into a modpoly --resptr; // here resptr points to the highest coeff of x^i in the array res[maxdeg] if (env->moduloon){ for (;resptr!=res-1;--resptr){ // COUT << *resptr << " " << env->modulo << endl; if (!is_zero(smod(*resptr,env->modulo))) break; } for (;resptr!=res-1;--resptr){ s.push_back(smod(*resptr,env->modulo)); } } else { for (;resptr!=res-1;--resptr){ if (!is_zero(*resptr)) break; } for (;resptr!=res-1;--resptr){ s.push_back(*resptr); } } #if 1 // def VISUALC delete [] itv; delete [] res; #endif return true; } static gen lastnonzero(const dense_POLY1 & q) { int d=int(q.size()); gen n( 0),n0( 0); for (;d;--d){ n=q[d-1]; if (!is_zero(n)) return n; } return 0; } // distinct degree factorization bool ddf(const modpoly & q,const vector & qmat,environment * env,vector< facteur >& v){ modpoly xtop(powmod(xpower1(),env->pn,q,env)); modpoly ddfactor; gcdmodpoly(operator_minus(xtop,xpower1(),env),q,env,ddfactor); if (is_undef(ddfactor)) return false; modpoly qrem(operator_div(q,ddfactor,env)); if (ddfactor.size()-1) v.push_back( facteur(ddfactor,1) ); int k=1; modpoly xpi=xtop ; for (int i=2;;i++){ int qremdeg=int(qrem.size())-1; if (!qremdeg) return true; if (qremdeg<2*i){ v.push_back( facteur(qrem,qremdeg) ); return true; } // compute x^(pn^i) mod qrem then gcd(x^pn^i-x,qrem) // since X^(pn^i)-X is divisible by // any irreductible of degre dividing i // COUT << modulo << " " << qmat << endl; if (qmat.empty()) xpi=powmod(xpower1(),pow(env->pn,i),qrem,env); else { if (!xtoxpowerpn(operator_mod(xpi,qrem,env),qmat,env,0,xpi)) return false; } gcdmodpoly(operator_minus(xpi,xpower1(),env),qrem,env,ddfactor); if (is_undef(ddfactor)) return false; k=int(ddfactor.size())-1; if (k) v.push_back(facteur(ddfactor,i)); if (k==qremdeg) return true; if (k) qrem=operator_div(qrem,ddfactor,env); } return true; } bool cantor_zassenhaus(const modpoly & ddfactor,int i,const vector & qmat,environment * env,vector & v){ if (debuglevel) COUT << "Factoring [" << i << "] " << ddfactor << endl // << " " << qmat << endl ; int k=int(ddfactor.size())-1; if (k==i){ v.push_back(ddfactor); return true; } if (i==1){ // compute roots if (!env || is_strictly_greater(10000,env->pn,context0)){ vecteur vtmp; if (!roots(ddfactor,env,vtmp,v)) return false; return true; } } // compute qmat modulo ddfactor vector thisqmat; if (qmat.empty()) qmatrix(ddfactor,env,thisqmat,0); else { vector::const_iterator it=qmat.begin(),itend=qmat.end(); for (int j=0;(it!=itend) && (jmodulo.val==2 ){ modpoly somme(pp); unsigned m=int(std::log(double(env->pn.val))/std::log(2.)); m *= i; for (unsigned ii=1;iipn-1)/2,ddfactor,env); pp=operator_minus(pp,one(),env); } gcdmodpoly(pp,ddfactor,env,fact1); if (is_undef(fact1)) return false; // hopefully it will split ddfactor deg=int(fact1.size())-1; } // COUT << "cz:" << i << fact1 << ddfactor/fact1 << endl; // recursive calls if (!cantor_zassenhaus(fact1,i,thisqmat,env,v) || !cantor_zassenhaus(operator_div(ddfactor,fact1,env),i,thisqmat,env,v)) return false; return true; } bool cantor_zassenhaus(const vector< facteur > & v_in,const vector & qmat, environment * env,vector & v){ // split elements of v_in // COUT << v_in << endl; vector< facteur >::const_iterator it=v_in.begin(),itend=v_in.end(); for (;it!=itend;++it){ if (!cantor_zassenhaus(it->fact,it->mult,qmat,env,v)) return false; } return true; } /* * From Z/pZ -> Z */ // lift modular roots (quadratic lift) static void liftroots(const dense_POLY1 &q,environment * env,vecteur & v){ // env->moduloon=false; dense_POLY1 qprime=derivative(q); // env->moduloon=true; gen lcoeff(q.front()); gen tcoeff(lastnonzero(q)); gen bound=gen( 2)*abs(lcoeff*tcoeff,context0); gen modulo_orig(env->modulo),moduloi(env->modulo),modulonext(env->modulo); // COUT << modulo << endl; while (is_greater(bound,moduloi,context0)) { // (moduloi<=bound){ modulonext=moduloi*moduloi; vecteur::iterator it=v.begin(),itend=v.end(); for (;it!=itend;++it){ env->modulo=modulonext; if (debug_infolevel>=20) CERR << "liftroot old root value " << *it << endl; gen temp1(iquo(horner(q,*it,env),moduloi)); if (debug_infolevel>=20) CERR << "liftroot num " << temp1 << endl; env->modulo=moduloi; gen temp2(horner(qprime,*it,env)); if (debug_infolevel>=20) CERR << "liftroot den " << temp2 << " mod " << env->modulo << endl; *it=smod(*it - moduloi* temp1 * invmod(temp2,env->modulo),modulonext) ; if (debug_infolevel>=20) CERR << "liftroot new root value " << *it << endl; } moduloi=modulonext; env->modulo=moduloi; } } // number of factors and possible degrees int nfact(const vector< facteur > & v, vector & possible_degrees , int maxdeg){ int k=int(v.size()); possible_degrees[0]=true; for (int i=1;i-1;k--){ if (possible_degrees[k]){ for (int l=mult;l;l--) possible_degrees[k+l*deg]=true; } } } return i; } // set tab to tab && othertab void intersect(vector::iterator tab, vector::iterator othertab,int size) { vector::iterator end = tab+size; for (;tab!=end;++tab,++othertab) *tab = (*tab) && (*othertab); } static void print_possible_degrees(const vector & possible_degrees,int qdeg){ for (int tmp=0;tmp<=qdeg;tmp++) if (possible_degrees[tmp]) COUT << tmp << " "; COUT << endl; } // number of true elements int sigma(const vector & deg){ int res=0; vector::const_iterator it=deg.begin(),itend=deg.end(); for (;it!=itend;++it) res += *it; return res; } // Landau-Mignotte bound gen mignotte_bound(const dense_POLY1 & p){ int d=int(p.size())-1; gen n( d+1); if (d%2) n=n+n; n=(isqrt(n)+gen( 1)); n=n*abs(norm(p,context0),context0).re(context0); n=n*pow(gen( 2),1+(d/2)); return n; } gen mignotte_bound(const polynome & p){ int d=p.lexsorted_degree(); gen n( d+1); if (d%2) n=n+n; n=(isqrt(n)+gen( 1)); n=n*abs(p.norm(),context0).re(context0); n=n*pow(gen( 2),1+(d/2)); return n; } static bool extracttruefactors(dense_POLY1 & q, environment * env,vector & v_in, vector & v_orig, vectpoly & v_out, int & n,const gen & modulo_orig, const gen & moduloi, gen & bound, vector & u){ int totaldegreefound=0; modpoly quo,rem; gen lcoeff=q.front(); vector::const_iterator it=v_in.begin(),itend=v_in.end(); vector::const_iterator orig_it=v_orig.begin(); vector w_in,w_orig; for (;it!=itend;++it,++orig_it){ modpoly test(*it); mulmodpoly(test,lcoeff,env,test); gen z=_lgcd(test,context0); divmodpoly(test,z,0,test); // COUT << "Trying " << q << "/" << *it << endl; if (DenseDivRem(q,test,quo,rem,true) && (rem.empty())){ // COUT << "Found early factor " << *it << endl; polynome temp=unmodularize(test); q=quo; v_out.push_back(temp); totaldegreefound += int(it->size())-1; n--; if (n==1){ v_in.clear(); v_out.push_back(unmodularize(q)); q=one(); n--; return true; } } else { // COUT << "No luck for this one!" << endl; w_in.push_back(*it); w_orig.push_back(*orig_it); } } if (totaldegreefound){ v_in=w_in; v_orig=w_orig; env->modulo=modulo_orig; if (!egcd(v_orig,env,u)) return false; env->modulo=moduloi; bound=iquo(bound,pow(gen(2),totaldegreefound/2)); } return true; } // lift factorization from Z/pZ to Z/p^kZ for a sufficiently large k // using quadratic Hensel lift // modulo is modified to modulo^k // returns -1 on error static int liftq(environment * env,dense_POLY1 & q,gen &bound,vector & v_in,vectpoly & v_out,vector & possible_degrees){ if (debuglevel) COUT << "Big data -> using quadratic Hensel lift." << v_in.size() << endl; gen lcoeff(q.front()); bool notunit=(!is_one(lcoeff)); bool testfortruefs; gen modulo_orig(env->modulo),moduloi(env->modulo),modulonext(env->modulo*env->modulo); vector v_orig(v_in),u; if (!egcd(v_in,env,u)) return -1; if (debuglevel){ COUT << "Lifting v_in:" << v_in << endl << "u:" << u << endl; COUT << "Modulo:" << env->modulo << " Bound:" << bound << endl; } int n=int(v_in.size()); int nfact_to_find = n; vector truefactor(n),hasbeentested(n); for (int i=0;imodulo = modulonext; modpoly pi; // initialize pi with the product of v_in vector::iterator it=v_in.begin(),itend=v_in.end(); mulmodpoly(it,itend,env,pi); for (int count=0;;count++){ // update Q at modulonext, modulonext=moduloi*modulo_orig; env->modulo=modulonext; env->pn=env->modulo; env->moduloon=false; Q=q-lcoeff*pi; divmodpoly(Q,moduloi,Q); Q=modularize(Q,modulo_orig,env); if (is_undef(Q)) return -1; env->moduloon=true; // _VECTute Q such that q=lcoeff*(pi+p^k*Q) // modulo=modulonext; // work in Z/p^(2), done by modularize below // COUT << "Q:" << Q << endl; // _VECTute new v_in if (Q.empty()) env->modulo=modulonext; else { if (notunit) mulmodpoly(Q,invmod(lcoeff,modulo_orig),env,Q); // Q=Q*invmod(lcoeff); vector::iterator itv=v_in.begin(),itvend=v_in.end(); vector::iterator itu=u.begin(); vector::iterator itv0=v_orig.begin(); for (int i=0;itv!=itvend;++itv,++itu,++itv0,++i){ if (!truefactor[i]){ env->modulo=modulo_orig; modpoly vadd,tmp1,tmp2,truefact; mulmodpoly(Q,*itu,env,tmp1); DivRem(tmp1,*itv0,env,tmp2,vadd); // modpoly vadd((Q*(*itu)) % (*itv0)); env->modulo=modulonext; // back in Z/p^2k if (vadd.empty()){ testfortruefs=true; mulmodpoly(*itv,lcoeff,env,truefact); ppz(truefact); } else { hasbeentested[i]=false; env->moduloon =false ; mulmodpoly(vadd,moduloi,vadd); env->moduloon = true ; addmodpoly(*itv,vadd,env,*itv); // (*itv)=(*itv)+moduloi*vadd; testfortruefs = false; } int debut_time=CLOCK(); if (debuglevel) COUT << debut_time << "Searching true factor" << endl; // test if *itv divides q in Z if ( testfortruefs && !hasbeentested[i] && DenseDivRem(newq,truefact,tmp1,tmp2,true) && (tmp2.empty()) ){ int fin_time=CLOCK(); if (debuglevel) COUT << fin_time << "Found true factor " << *itv << endl << "New bound:"<< bound << endl; // yes! _VECTute new q and bound truefactor[i]=true; nfact_to_find--; v_out.push_back(unmodularize(truefact)); if (nfact_to_find==1){ v_out.push_back(unmodularize(tmp1)); q=one(); return 0; } newq=tmp1; bound=mignotte_bound(newq); int truefactdeg=int(truefact.size())-1; for (int j=0;jbound) ) break; v_orig=v_in; if (is_strictly_greater(modulonext*moduloi,bound,context0)){ // modulonext*moduloi>bound) // need a last *linear* lift, modulo_orig and u unchanged, moduloi = modulonext ; modulonext=moduloi*modulo_orig; // update pi env->modulo = modulonext ; it=v_in.begin(); itend=v_in.end(); mulmodpoly(it,itend,env,pi); } else { // compute new u at modulonext and new pi at modulonext^2 // pidown[l]=Pi_{j>n-2-l} v_in[j], piup[l]=Pi_{j piup,pidown; env->modulo=modulonext*modulonext; // modulonext^2 for pi at next iteration pidown.push_back(v_in[n-1]); modpoly tmp(v_in[n-1]); // initialization needed if n=2 for (int k=1;k<=n-2;k++){ mulmodpoly(pidown[k-1],v_in[n-k-1],env,tmp); pidown.push_back(tmp); } mulmodpoly(tmp,v_in[0],env,pi); env->modulo = modulonext ; piup.push_back(v_in[0]); for (int k=1;k<=n-2;k++){ mulmodpoly(piup[k-1],v_in[k],env,tmp); piup.push_back(tmp); } // update u and v u[0] = operator_minus( operator_times(plus_two,u[0],env) , operator_mod( operator_times( operator_mod(pidown[n-2] , v_in[0],env),operator_times(u[0], u[0],env),env) , v_in[0],env) , env); for (int k=1;k w; for (int i=0;i & v_in,vectpoly & v_out){ gen lcoeff(q.front()); bool notunit=(!is_one(lcoeff)); gen modulo_orig(env->modulo),moduloi(env->modulo),modulonext(env->modulo); vector v_orig(v_in),u; if (!egcd(v_orig,env,u)) return false; if (debuglevel){ COUT << "Lifting v_in:" << v_in << endl << "u:" << u << endl; COUT << "Modulo:" << env->modulo << "Bound" << bound << endl; } int n=int(v_in.size()); int d=int(q.size())-1; // at bound/2^d/2, we will look for factors of q1 in v_in, // if true add factors to v_out and reduce the bound // modulo_orig^tryfactors=bound/2^d/2 int tryfactors=(bound.bindigits()-d/2)/modulo_orig.bindigits(); for (int count=1;is_greater(bound,moduloi,context0);count++){ // moduloi<=bound if ((count==tryfactors/4) || (count==tryfactors)){ if (!extracttruefactors(q,env,v_in,v_orig,v_out,n,modulo_orig,moduloi,bound,u)) return false; } if (!n) return true; modulonext=moduloi*modulo_orig; env->moduloon=false; // product of v_in in Z/p^k Z vector::iterator it=v_in.begin(),itend=v_in.end(); dense_POLY1 pi; mulmodpoly(it,itend,env,pi); lcoeff=q.front(); // compute Q such that q=lcoeff*(pi+p^k*Q) // modulo=modulonext; // work in Z/p^(k+1), done by modularize below modpoly Q((q-lcoeff*pi)/moduloi); Q=modularize(Q,modulo_orig,env); if (is_undef(Q)) return false; if (notunit) mulmodpoly(Q,invmod(lcoeff,env->modulo),env,Q); // Q=Q*invmod(lcoeff); // COUT << "Q:" << Q << endl; // compute new v_in if (Q.empty()){ env->modulo=modulonext; moduloi=modulonext; } else { it=v_in.begin(); vector::const_iterator itu=u.begin(),itorig=v_orig.begin(); for (;it!=itend;++it,++itu,++itorig){ env->modulo=modulo_orig; // work in Z/p or Z/p^k modpoly vadd,tmp1,tmp2; mulmodpoly(Q,*itu,env,tmp1); DivRem(tmp1,*itorig,env,tmp2,vadd); // modpoly vadd(Q*(*itu) % (*itorig)); env->modulo=modulonext; // back in Z/p^(k+1) or Z/p^2k (*it)=operator_plus(*it,operator_times(moduloi,vadd,env),env); } moduloi=modulonext; } if (debuglevel) COUT << "Lifted to " << modulonext << endl; } return true; } // given a factorization v_in of q in Z/p^kZ find a factorization v_out // over Z, k is the minimal # of factors of v_in to be combined void combine(const dense_POLY1 & q, const vector & v_in,environment * env,vectpoly & v_out,vector & possible_degrees, int k){ if (v_in.empty()) return; // nothing to do int n=int(v_in.size()); if (debuglevel) COUT << CLOCK() << "Starting combining with " << n << " factors" << endl; gen lcoeff(smod(q.front(),env->modulo)); bool notunit=(!is_one(lcoeff)); if (n==1){ polynome temp(unmodularize(lcoeff*v_in.front())); if (notunit) ppz(temp); v_out.push_back(temp); return; } #if 1 // def VISUALC vector::const_iterator * it=new vector::const_iterator[n+1],itend=v_in.end(),itbegin=v_in.begin(), current; #else vector::const_iterator it[n+1],itend=v_in.end(),itbegin=v_in.begin(), current; #endif vector degrees(n); // records degrees of v_in polynomials for (int j=0;j d1tab(n); // records coeff of degree d-1*2^32/modulo for (int j=0;jmodulo)).to_int(); gen dminus1bound((norm(q,0)+1)*gen((int)q.size()-1)*lcoeff); gen dminus1bound_=iquo(dminus1bound*twoto32,env->modulo); int d1=dminus1bound_.to_int()+1; // maxvalue of d-1 coeff for a product // COUT << dminus1bound << endl; for (;kmodulo); picstcoeff.push_back(lastpi); lastdeg += int(it[j]->size())-1; totaldeg.push_back(lastdeg); lastdminus1 = lastdminus1 + (*it[j])[1]; dminus1.push_back(lastdminus1); } // look if the next possible degree is > degree(q)/2 -> q is irreducible int tmp=lastdeg+int(it[k]->size())-1; for (;2*tmp<=signed(q.size());++tmp) if (possible_degrees[tmp]) break; if (2*tmp>signed(q.size())-1){ v_out.push_back(unmodularize(q)); #if 1 // def VISUALC delete [] it; #endif return ; } current=it[k]; int _VECTteur=0; int * position=°rees[current-itbegin]; int lastd1=(iquo(lastdminus1*twoto32,env->modulo)).to_int(); int * d1tabposition=&d1tab[current-itbegin]; for (;;){ // combination of k factors // first test that the degree is admissible, // then do the d-1 test: coeff multiplied by lcoeff mod modulo < bound // and that the product of cst_coeff divides the polynomial if ( possible_degrees[lastdeg+(*position)] && is_greater(dminus1bound,abs(smod((lastdminus1+(*current)[1])*lcoeff,env->modulo)),0) //&& ( absint(lastd1+(*d1tabposition))< d1 ) ){ gen check=smod(lastpi*cstcoeff(*current)*lcoeff,env->modulo); check=check/gcd(check,lcoeff); if ( is_zero(cstcoeff(q)%check) ){ it[k]=current; // modpoly pi(*it[1]); // for (int j=2;j<=k;j++) // pi=pi*(*it[j]); modpoly pi; mulmodpoly(it,1,k,env,pi); if (notunit) mulmodpoly(pi,lcoeff,env,pi); dense_POLY1 quo(1),rem(1); // COUT << pi << " " << combination << endl; if (notunit) ppz(pi); if ( // (gen(2)*abs(pi[2]) v_new; vector::const_iterator itnew=v_in.begin(); for (int j=1;j<=k;j++){ for (;itnew!=it[j];++itnew) v_new.push_back(*itnew); ++itnew; } for (;itnew!=itend;++itnew) v_new.push_back(*itnew); // if v_new.size is large it might be more efficient // to compute the factorization of newq // else call combine with q <- quo if (v_new.size()>24){ int j=3; factorunivsqff(unmodularize(quo),env,v_out,j,debuglevel,int(v_new.size())); } else { // re_VECTute possible_degrees int founddeg=found.lexsorted_degree(); int newqdeg=int(q.size())-1-founddeg; vector new_possible_degrees(newqdeg+1); for (int j=0;j<=newqdeg;j++) new_possible_degrees[j]=possible_degrees[j+founddeg]; if (debuglevel) print_possible_degrees(new_possible_degrees,newqdeg); combine(quo,v_new,env,v_out,new_possible_degrees,k); } #if 1 // def VISUALC delete [] it; #endif return; } } } ++position; ++_VECTteur; ++current; ++d1tabposition; if (current==itend){ // increment the predecessor until not = max int j=k-1; for (;j>0;j--){ ++it[j]; if (it[j]!=itend+j-k) break; } if (debuglevel && (jmodulo); picstcoeff[j]=lastpi; lastdeg += int(it[j]->size())-1; totaldeg[j]=lastdeg; lastdminus1 = lastdminus1 + (*it[j])[1]; dminus1[j]=lastdminus1; it[j+1]=it[j]+1; } current=it[k]; position=°rees[current-itbegin]; lastd1=(iquo(lastdminus1*twoto32,env->modulo)).to_int(); d1tabposition=&d1tab[current-itbegin]; if (2*(lastdeg+current->size()-1)>q.size()-1){ current=itend-1; continue; } } else break; } } } // k==n v_out.push_back(unmodularize(q)); #if 1 // def VISUALC delete [] it; #endif } const char idivis23[][6]={ {0,0,0,0,0,0}, {1,0,0,0,0,0}, {1,2,0,0,0,0}, {1,3,0,0,0,0}, {1,2,4,0,0,0}, {1,5,0,0,0,0}, {1,2,3,6,0,0}, {1,7,0,0,0,0}, {1,2,4,8,0,0}, {1,3,9,0,0,0}, {1,2,5,10,0,0}, {1,11,0,0,0,0}, {1,2,3,4,6,12}, {1,13,0,0,0,0}, {1,2,7,14,0,0}, {1,3,5,15,0,0}, {1,2,4,8,16,0}, {1,17,0,0,0,0}, {1,2,3,6,9,18}, {1,19,0,0,0,0}, {1,2,4,5,10,20}, {1,3,7,21,0,0}, {1,2,11,22,0,0}, {1,23,0,0,0,0}, }; // Find linear factors of q int do_linearfind(const polynome & q,environment * env,polynome & qrem,vectpoly & v,vecteur & croots,int & i){ int pn; if (normalize_env(env)) pn=env->pn.val; else pn=-1; if (q.coord.empty()){ qrem=q; return 4; } if (q.dim!=1) return 0; // setsizeerr(gettext("modfactor.cc/linearfind")); int qdeg=q.lexsorted_degree(); if (!qdeg) return 4; if (qdeg==1){ v.push_back(q); if (q.coord.size()==1) croots.push_back(0); else croots.push_back(-q.coord.back().value/q.coord.front().value); qrem=polynome(gen( 1),1); return 4; } if (!env->complexe && q.coord.size()>1 && q.coord.front().value.type==_INT_ && q.coord.back().value.type==_INT_){ int qn=absint(q.coord.front().value.val),q0=absint(q.coord.back().value.val); if (qn<24 && q0<24){ // check all rationals divisors of q0/divisor of qn env->moduloon=false; polynome Qtest(1),Qquo,Qrem; Qtest.coord.reserve(2); Qtest.coord.push_back(monomial(1,1,1)); if (q.coord.back().index[0]>0){ croots.push_back(0); v.push_back(Qtest); qrem=q.shift(index_t(1,-1)); } else qrem=q; Qtest.coord.push_back(monomial(1,0,1)); const char * qndiv=idivis23[qn]; const char * q0div=idivis23[q0]; for (int i=0;i<6;i++){ int num=q0div[i]; if (!num) break; for (int j=0;j<6;j++){ int den=qndiv[j]; if (!den) break; Qtest.coord.front().value=den; if (gcd(num,den)==1){ Qtest.coord.back().value=-num; if (qrem.TDivRem(Qtest,Qquo,Qrem,false) && Qrem.coord.empty()){ croots.push_back(gen(num)/gen(den)); v.push_back(Qtest); swap(qrem.coord,Qquo.coord); } Qtest.coord.back().value=num; if (qrem.TDivRem(Qtest,Qquo,Qrem,false) && Qrem.coord.empty()){ croots.push_back(gen(-num)/gen(den)); v.push_back(Qtest); swap(qrem.coord,Qquo.coord); } if (qrem.lexsorted_degree()==0) return 4; if (qrem.lexsorted_degree()<=1){ v.push_back(qrem); if (qrem.coord.size()==1) croots.push_back(0); else croots.push_back(-qrem.coord.back().value/qrem.coord.front().value); qrem.coord.clear(); return 4; } } } } return 4; } // end qn<20 and q0<20 } modpoly Q; // find a prime such that q remains sqff gen m; gen lcoeff=q.coord.front().value; // REMOVED .re(0) bool notunit=(!is_one(lcoeff)); for (;i<100;i++){ if (env->complexe && primes[i]%4!=3) // insure that -1 is not a square mod primes[i] continue; m=gen(primes[i]); if (!is_zero(smod(lcoeff,m))){ // insure that degree remains constant Q=modularize(q,m,env); if (is_undef(Q)) return 0; mulmodpoly(Q,invmod(lcoeff,env->modulo),env,Q); // Q=Q*invmod(lcoeff) Q is now unitary if (debug_infolevel>=20) CERR << "linearfind: trying with prime " << m << " for " << Q << endl; if (is_one(gcd(Q,derivative(Q,env),env))) break; } } if (i==100) return 0; // setsizeerr(gettext("modfactor.cc/linearfind")); if (debug_infolevel>=20) CERR << "linearfind: using prime " << m << endl; vecteur w,xpuipn(xpowerpn(env)); vector wtmp; if (is_undef(xpuipn)) return 0; if (!roots((pn>0 && signed(Q.size())>pn)?gcd(Q,operator_minus(xpuipn,xpower1(),env),env):Q,env,w,wtmp)) return 0; if (debug_infolevel>=20) CERR << "linearfind modular roots " << w << endl; dense_POLY1 q1(modularize(q,gen(0),env)); if (is_undef(q1)) return 0; liftroots(q1,env,w); if (debug_infolevel>=20) CERR << "linearfind lifted modular roots " << w << endl; // try each element of w vecteur::const_iterator it=w.begin(),itend=w.end(); for (;it!=itend;++it){ dense_POLY1 combination,quo,rem; if (notunit){ // COUT << *it << " " << lcoeff << " " << env->modulo << endl; gen s( smod((*it)*lcoeff,env->modulo) ); gen g(gcd(s,lcoeff,context0)); combination.push_back(iquo(lcoeff,g)); combination.push_back(iquo(-s,g)); // COUT << combination << endl; } else { combination.push_back(gen( 1)); combination.push_back(smod(-(*it),env->modulo)); } if (debug_infolevel>=20) CERR << "checking " << combination << endl; if (DenseDivRem(q1,combination,quo,rem,true) && (rem.empty())){ // push factor found v.push_back(unmodularize(combination)); croots.push_back(-combination.back()/combination.front()); q1=quo; } } qrem=unmodularize(q1); env->moduloon=false; return 4; } bool do_factorunivsqff(const polynome & q,environment * env,vectpoly & v,int & i,int debug,int modfactor_primes){ // we do not require q to have 1 as leading coefficient anymore if (0 && !q.coord.empty() && q.coord.front().value!=1){ polynome unitaryp(1), an(0); unitarize(q,unitaryp,an); if (!do_factorunivsqff(unitaryp,env,v,i,debug,modfactor_primes)) return false; for (unsigned i=0;i=2) COUT << "Bound " << bound << " log:" << logbound_d << endl; modpoly Qtry(1); int bestprime=0,bestnumberoffactors=0; gen bestliftsteps; vector< facteur > wf; vector bestqmat; vector possible_degrees(qdeg+1); for (int essai=0;essaimodulo),Qtry,env); // -> Q is now unitary // COUT << "Trying with " << m << Q << endl; if (is_one(gcd(Qtry,derivative(Qtry,env),env))){ vector< facteur > wftry; // distinct degree factorization of Qtry mod env->modulo vector qmat; qmatrix(Qtry,env,qmat,0); if (!ddf(Qtry,qmat,env,wftry)) return false; if (debuglevel) COUT << "Trying prime " << env->modulo << endl; vector new_degrees(qdeg+1); int numberoffactors; if (essai){ numberoffactors=nfact(wftry,new_degrees,qdeg+1); intersect(possible_degrees.begin(),new_degrees.begin(),qdeg+1); } else numberoffactors=nfact(wftry,possible_degrees,qdeg+1); if (debuglevel){ COUT << "Possible degrees after intersection:"; print_possible_degrees(possible_degrees,qdeg); } if ( (numberoffactors==1) || (sigma(possible_degrees)<3) ){ v.push_back(q); env->moduloon=false; return true; } int ilifta=int(giac_ceil(giac_log(logbound_d/giac_log((double) primes[i]))/giac_log(2.0))); int iliftb=giacmax(1,int(giac_ceil(giac_log(2./3.*logbound_d/giac_log((double) primes[i]))/giac_log(2.)))); if (debuglevel) COUT << "Would use min " << ilifta << "," << iliftb << " steps modulo " << currentprime << endl; gen qlifta(pow(currentprime,(long unsigned int) pow(gen(2),ilifta).to_int())); gen qliftb(pow(currentprime,(long unsigned int) 3*pow(gen(2),iliftb-1).to_int())); if (debuglevel>=2) COUT << "Would use min " << qlifta << "," << endl << qliftb << " modulo " << currentprime << endl; gen liftsteps; if (is_strictly_greater(qliftb,qlifta,context0)) // (qliftamodulo=gen(bestprime); if (debuglevel){ COUT << "Using prime " << env->modulo << endl; if (debuglevel>=2){ COUT << " for " ; dbgprint(q); } } vector w; if (!cantor_zassenhaus(wf,bestqmat,env,w)) return false; // COUT << "Starting lift" << endl; // lift and combine dense_POLY1 q1(modularize(q,gen(0),env)); if (is_undef(q1)) return false; #ifdef HAVE_LIBPARI // use PARI LLL+knapsack recombination if (w.size()>12){ vector res; if (pari_lift_combine(q1,w,env->modulo,res)){ vector::const_iterator it=res.begin(),itend=res.end(); for (;it!=itend;++it) v.push_back(unmodularize(*it)); env->moduloon=false; return true; } } #endif // HAVE_LIBPARI // quadratic lift commented until bug is fixed for factor(poly2symb([2052661997653969,0,-28627701862508750,0,2045357156640625],x)); if (0 && is_strictly_greater(bound,pow(env->modulo,(long unsigned int) HENSEL_QUADRATIC_POWER),context0)) { // bound>pow(...) int res=liftq(env,q1,bound,w,v,possible_degrees); if (res==-1) return false; if (res) combine(q1,w,env,v,possible_degrees,res); } else { if (!liftl(env,q1,bound,w,v)) return false; combine(q1,w,env,v,possible_degrees); } env->moduloon=false; if (debuglevel) COUT << CLOCK() << "End combine" << endl; return true; } #ifdef HAVE_LIBNTL typedef gen inttype; int ntlfactor(inttype *p, int pdeg,inttype ** result,int * resultdeg,int debug=0){ if (debug_infolevel) CERR << CLOCK()*1e-6 << " NTL factor begin" << endl; NTL::ZZX f(tab2ZZX(p,pdeg)); // COUT << "Factoring " << f << endl; NTL::vec_pair_ZZX_long factors; NTL::ZZ c; factor(c, factors, f,debug); // c will be 0 since q has content 1 // convert factors to arrays, multiplicity is always 1 // COUT << factors << endl; int s=factors.length(); for (int i=0;imodulo bool factorunivsqff(const polynome & q,environment * env,vectpoly & v,int & i,int debug,int modfactor_primes){ return do_factorunivsqff(q,env,v,i,debug,modfactor_primes); } #endif // ndef HAVE_LIBNTL #ifndef NO_NAMESPACE_GIAC } // namespace giac #endif // ndef NO_NAMESPACE_GIAC