/*******************************************************************/ /* */ /* Factorisation dans un corps de nombres */ /* et modulo un ideal premier */ /* */ /*******************************************************************/ /* $Id: nffactor.c,v 1.5 1999/09/23 18:48:42 xavier Exp $ */ #include "pari.h" GEN hensel_lift(GEN pol,GEN fk,GEN fkk,GEN p,long e); GEN hensel_lift_fact(GEN pol, GEN fact, GEN p, GEN pev, long e); GEN nf_get_T2(GEN base, GEN polr); GEN nfreducemodpr_i(GEN x, GEN prh); GEN sort_factor(GEN y, int (*cmp)(GEN,GEN)); static GEN nf_pol_mul(GEN nf,GEN pol1,GEN pol2); static GEN nf_pol_sqr(GEN nf,GEN pol1); static GEN nf_pol_divres(GEN nf,GEN pol1,GEN pol2, GEN *pr); static GEN nf_pol_subres(GEN nf,GEN pol1,GEN pol2); static GEN nfmod_pol_reduce(GEN nf,GEN prhall,GEN pol); static GEN nfmod_pol_mul(GEN nf,GEN prhall,GEN pol1,GEN pol2); static GEN nfmod_pol_sqr(GEN nf,GEN prhall,GEN pol1); static GEN nfmod_pol_divres(GEN nf,GEN prhall,GEN pol1,GEN pol2, GEN *pr); static GEN nfmod_split2(GEN nf,GEN prhall,GEN pmod,GEN pol,GEN exp); static GEN nfmod_pol_gcd(GEN nf,GEN prhall,GEN pol1,GEN pol2); static GEN nfmod_pol_pow(GEN nf,GEN prhall,GEN pmod,GEN pol,GEN exp); static GEN nf_bestlift(GEN id,GEN idinv,GEN den,GEN elt); static GEN nf_pol_lift(GEN id,GEN idinv,GEN den,GEN pol); static GEN nfsqff(GEN nf,GEN pol,long fl); static int nf_combine_factors(GEN nf,long fxn,GEN psf,long dlim,long hint); typedef struct Nfcmbf /* for use in nfsqff */ { GEN pol, h, hinv, fact, res, lt, den; long nfact, nfactmod; } Nfcmbf; static Nfcmbf nfcmbf; static GEN unifpol0(GEN nf,GEN pol,long flag) { static long n = 0; static GEN vun = NULL; GEN f = (GEN) nf[1]; long i = lgef(f)-3, av; if (i != n) { n=i; if (vun) free(vun); vun = (GEN) gpmalloc((n+1)*sizeof(long)); vun[0] = evaltyp(t_COL) | evallg(n+1); vun[1]=un; for ( ; i>=2; i--) vun[i]=zero; } av = avma; switch(typ(pol)) { case t_INT: case t_FRAC: case t_RFRAC: pol = gmul(pol,vun); break; case t_POL: pol = gmodulcp(pol,f); /* fall through */ case t_POLMOD: pol = algtobasis(nf,pol); } if (flag) pol = basistoalg(nf, lift(pol)); return gerepileupto(av,pol); } /* Pour pol un polynome a coefficients dans Z, nf ou l'algebre correspondant * renvoie le meme polynome avec pour coefficients: * si flag=0: des vecteurs sur la base d'entiers. * si flag=1: des polymods. */ GEN unifpol(GEN nf,GEN pol,long flag) { if (typ(pol)==t_POL && varn(pol) < varn(nf[1])) { long i, d = lgef(pol); GEN p1 = pol; pol=cgetg(d,t_POL); pol[1]=p1[1]; for (i=2; i=2; i--) p1[i] = (long) nfreducemodpr(nf,(GEN)pol[i],prhall); return gerepile(av,tetpil, normalizepol(p1)); } /* x^2 modulo prhall ds nf (x elt accepte) */ static GEN nfmod_pol_sqr(GEN nf,GEN prhall,GEN x) { long av=avma,tetpil; GEN px; px = nfmod_pol_reduce(nf,prhall,x); px = unifpol(nf,lift(px),1); px = unifpol(nf,nf_pol_sqr(nf,px),0); tetpil=avma; return gerepile(av,tetpil,nfmod_pol_reduce(nf,prhall,px)); } /* multiplication des polynomes x et y modulo prhall ds nf (x elt accepte) */ static GEN nfmod_pol_mul(GEN nf,GEN prhall,GEN x,GEN y) { long av=avma,tetpil; GEN px,py; px = nfmod_pol_reduce(nf,prhall,x); px = unifpol(nf,lift(px),1); py = nfmod_pol_reduce(nf,prhall,y); py = unifpol(nf,lift(py),1); px = unifpol(nf,nf_pol_mul(nf,px,py),0); tetpil=avma; return gerepile(av,tetpil,nfmod_pol_reduce(nf,prhall,px)); } /* division euclidienne du polynome x par le polynome y */ static GEN nf_pol_divres(GEN nf,GEN x,GEN y,GEN *pr) { long av = avma,tetpil; GEN nq = poldivres(unifpol(nf,x,1),unifpol(nf,y,1),pr); GEN *gptr[2]; tetpil=avma; nq=unifpol(nf,nq,0); if (pr) *pr = unifpol(nf,*pr,0); gptr[0]=&nq; gptr[1]=pr; gerepilemanysp(av,tetpil,gptr,pr ? 2:1); return nq; } /* division euclidienne du polynome x par le polynome y modulo prhall */ static GEN nfmod_pol_divres(GEN nf,GEN prhall,GEN x,GEN y, GEN *pr) { long av=avma,dx,dy,dz,i,j,k,l,n,tetpil; GEN z,p1,p2,p3,px,py; py = nfmod_pol_reduce(nf,prhall,y); if (gcmp0(py)) err(talker, "division by zero in nfmod_pol_divres"); tetpil=avma; px=nfmod_pol_reduce(nf,prhall,x); dx=lgef(px)-3; dy=lgef(py)-3; dz=dx-dy; if (dx=dy; --i) { l=avma; p1=nfreducemodpr(nf,(GEN)px[i+2],prhall); for (j=i-dy+1; j<=i && j<=dz; j++) { p2=element_mul(nf,(GEN)z[j+2],(GEN)py[i-j+2]); p2=nfreducemodpr(nf,p2,prhall); p1=gsub(p1,p2); } tetpil=avma; p3=element_divmodpr(nf,p1,(GEN)py[dy+2],prhall); z[i-dy+2]=lpile(l,tetpil,p3); z[i-dy+2]=(long)nfreducemodpr(nf,(GEN)z[i-dy+2],prhall); } l=avma; for (i=dy-1; i>=0; --i) { l=avma; p1=((GEN)px[i+2]); for (j=0; j<=i && j<=dz; j++) { p2=element_mul(nf,(GEN)z[j+2],(GEN)py[i-j+2]); p2=nfreducemodpr(nf,p2,prhall); tetpil=avma; p1=gsub(p1,p2); } p1=gerepile(l,tetpil,p1); if (!gcmp0(nfreducemodpr(nf,p1,prhall))) break; } if (!pr) { avma = l; return z; } if (i<0) { avma=l; p3 = cgetg(3,t_POL); p3[2]=zero; p3[1] = evallgef(2) | evalvarn(varn(px)); *pr=p3; return z; } p3=cgetg(i+3,t_POL); p3[1]=evalsigne(1) | evallgef(i+3) | evalvarn(varn(px)); p3[i+2]=(long)nfreducemodpr(nf,p1,prhall); for (k=i-1; k>=0; --k) { l=avma; p1=((GEN)px[k+2]); for (j=0; j<=k && j<=dz; j++) { p2=element_mul(nf,(GEN)z[j+2],(GEN)py[k-j+2]); p2=nfreducemodpr(nf,p2,prhall); tetpil=avma; p1=gsub(p1,p2); } p3[k+2]=lpile(l,tetpil,nfreducemodpr(nf,p1,prhall)); } *pr=p3; return z; } /* PGCD des polynomes x et y, par l'algorithme du sub-resultant */ static GEN nf_pol_subres(GEN nf,GEN x,GEN y) { long av=avma,tetpil; GEN s = srgcd(unifpol(nf,x,1), unifpol(nf,y,1)); tetpil=avma; return gerepile(av,tetpil,unifpol(nf,s,1)); } /* PGCD des polynomes x et y modulo prhall */ static GEN nfmod_pol_gcd(GEN nf,GEN prhall,GEN x,GEN y) { long av=avma; GEN p1,p2; if (lgef(x)= varn(nf[1])) err(talker,"polynomial variable must have highest priority in nffactormod"); prhall=nfmodprinit(nf,pr); n=lgef(nf[1])-3; vun = gscalcol_i(gun, n); vzero = gscalcol_i(gzero, n); f=unifpol(nf,pol,0); f=nfmod_pol_reduce(nf,prhall,f); d=lgef(f)-3; vf=varn(f); t = (GEN*)new_chunk(d+1); ex= new_chunk(d+1); x=gcopy(polx[vf]); x[3]=(long)vun; x[2]=(long)vzero; if (d<=1) { nbfact=2; t[1] = f; ex[1]=1; } else { q = (GEN)pr[1]; psim = VERYBIGINT; if (!is_bigint(q)) psim = itos(q); /* psim has an effect only when p is small. If too big, set it to a huge * number (i.e ignore it) to avoid an error in itos on next line. */ q=gpuigs(q, itos((GEN)pr[4])); f1=f; e=1; nbfact=1; while (lgef(f1)>3) { df1=deriv(f1,vf); f2=nfmod_pol_gcd(nf,prhall,f1,df1); g1=nfmod_pol_divres(nf,prhall,f1,f2,NULL); k=0; while (lgef(g1)>3) { k++; if (k%psim == 0) { k++; f2=nfmod_pol_divres(nf,prhall,f2,g1,NULL); } f3=nfmod_pol_gcd(nf,prhall,f2,g1); u = nfmod_pol_divres(nf,prhall,g1,f3,NULL); f2= nfmod_pol_divres(nf,prhall,f2,f3,NULL); g1=f3; if (lgef(u)>3) { N=lgef(u)-3; Q=cgetg(N+1,t_MAT); v3=cgetg(N+1,t_COL); Q[1]=(long)v3; v3[1]=(long)vun; for (i=2; i<=N; i++) v3[i]=(long)vzero; v2 = v = nfmod_pol_pow(nf,prhall,u,x,q); for (j=2; j<=N; j++) { v3=cgetg(N+1,t_COL); Q[j]=(long)v3; for (i=1; i<=lgef(v2)-2; i++) v3[i]=v2[i+1]; for (; i<=N; i++) v3[i]=(long)vzero; if (j1) { vker=cgetg(r+1,t_COL); for (i=1; i<=r; i++) { v3=cgetg(N+2,t_POL); v3[1]=evalsigne(1)+evallgef(2+N); setvarn(v3,vf); vker[i]=(long)v3; for (j=1; j<=N; j++) v3[j+1]=coeff(v2,j,i); normalizepol(v3); } } while (kk>8, q); vz=nfreducemodpr(nf,vz,prhall); v=gadd(v,nfmod_pol_mul(nf,prhall,vz,(GEN)vker[i])); } for (i=1; i<=kk && kk4) { if(psim==2) polu=nfmod_split2(nf,prhall,polb,v,q); else { polu=nfmod_pol_pow(nf,prhall,polb,v,shifti(q,-1)); polu=gsub(polu,vun); } pold=nfmod_pol_gcd(nf,prhall,polb,polu); if (lgef(pold)>3 && lgef(pold)=4) fprintferr("Premier choisi pour decomposition: %Z\n", pr); return pr; } } avma = av; return NULL; } static GEN choose_prime(GEN nf, GEN dk, GEN lim) { GEN p, pr; p = nextprime(lim); for (;;) { if ((pr = p_ok(nf,p,dk))) break; p = nextprime(addis(p,2)); } return pr; } /* Renvoie les racines de pol contenues dans nf */ GEN nfroots(GEN nf,GEN pol) { long av=avma,tetpil,i,d=lgef(pol); GEN p1,p2,polbase,polmod,den; nf=checknf(nf); if (typ(pol)!=t_POL) err(talker,"not a polynomial in nfroots"); if (varn(pol) >= varn(nf[1])) err(talker,"polynomial variable must have highest priority in nfroots"); polbase=unifpol(nf,pol,0); if (d==3) { tetpil=avma; p1=cgetg(1,t_VEC); return gerepile(av,tetpil,p1); } if (d==4) { tetpil=avma; p1=cgetg(2,t_VEC); p1[1] = (long)basistoalg(nf,gneg_i( element_div(nf,(GEN)polbase[2],(GEN)polbase[3]))); return gerepile(av,tetpil,p1); } p1=element_inv(nf,leading_term(polbase)); polbase=nf_pol_mul(nf,p1,polbase); den=gun; for (i=2; i=4) fprintferr("On teste si le polynome est square-free\n"); p1=derivpol(polmod); p2=nf_pol_subres(nf,polmod,p1); if (degree(p2) > 0) { p1=element_inv(nf,leading_term(p2)); p2=nf_pol_mul(nf,p1,p2); polmod=nf_pol_divres(nf,polmod,p2,NULL); p1=element_inv(nf,leading_term(polmod)); polmod=nf_pol_mul(nf,p1,polmod); d=lgef(polmod); den=gun; for (i=2; i=3; i--) p1=element_mul(nf,elt,gadd((GEN)pol[i],p1)); tetpil=avma; return gerepile(av,tetpil,gadd(p1,(GEN)pol[2])); } #endif /* Calcule la factorisation du polynome x dans nf */ GEN nffactor(GEN nf,GEN pol) { GEN y,p1,p2,den,p3,p4,quot, rep = cgetg(3,t_MAT); long av = avma,tetpil,i,d; if (DEBUGLEVEL >= 4) timer2(); nf=checknf(nf); if (typ(pol)!=t_POL) err(typeer,"nffactor"); if (varn(pol) >= varn(nf[1])) err(talker,"polynomial variable must have highest priority in nffactor"); d=lgef(pol); if (d==3) { rep[1]=lgetg(1,t_COL); rep[2]=lgetg(1,t_COL); return rep; } if (d==4) { p1=cgetg(2,t_COL); rep[1]=(long)p1; p1[1]=lcopy(pol); p1=cgetg(2,t_COL); rep[2]=(long)p1; p1[1]=un; return rep; } p1=element_inv(nf,leading_term(pol)); pol=nf_pol_mul(nf,p1,pol); p1=unifpol(nf,pol,0); den=gun; for (i=2; i=4) fprintferr("On teste si le polynome est square-free\n"); p2=derivpol(p1); p3=nf_pol_subres(nf,p1,p2); if (degree(p3) > 0) { p4=element_inv(nf,leading_term(p3)); p3=nf_pol_mul(nf,p4,p3); p2=nf_pol_divres(nf,p1,p3,NULL); p4=element_inv(nf,leading_term(p2)); p2=nf_pol_mul(nf,p4,p2); d=lgef(p2); den=gun; for (i=2; i=1; i--) { GEN fact=(GEN)y[i], quo = quot, rem; long e = 0; do { quo = nf_pol_divres(nf,quo,fact,&rem); e++; } while (gcmp0(rem)); p3[i]=lstoi(e); } avma = (long)y; y = gerepile(av, tetpil, y); p2=cgetg(i+1, t_COL); for (; i>=1; i--) p2[i]=lstoi(p3[i]); free(p3); } else { tetpil=avma; y = gerepile(av,tetpil,nfsqff(nf,p1,0)); i = nfcmbf.nfact; p2=cgetg(i+1, t_COL); for (; i>=1; i--) p2[i]=un; } if (DEBUGLEVEL>=4) fprintferr("Nombre de facteur(s) trouve(s) : %ld\n", nfcmbf.nfact); rep[1]=(long)y; rep[2]=(long)p2; return sort_factor(rep, cmp_pol); } /* teste si la matrice M est suffisament orthogonale */ static long test_mat(GEN M, GEN p, GEN C2, long k) { long av = avma, i, N = lg(M); GEN min, prod, L2, R; min = prod = gcoeff(M,1,1); for (i = 2; i < N; i++) { L2 = gcoeff(M,i,i); prod = mpmul(prod,L2); if (mpcmp(L2,min) < 0) min = L2; } R = mpmul(min, gpowgs(p, k<<1)); i = mpcmp(mpmul(C2,prod), R); avma = av; return (i < 0); } /* calcule la matrice correspondant a pr^e jusqu'a ce que R(pr^e) > C */ static GEN T2_matrix_pow(GEN nf, GEN pre, GEN p, GEN C, long *kmax, long prec) { long av=avma,av1,lim, k = *kmax, N = lgef((GEN)nf[1])-3; int tot_real = !signe(gmael(nf,2,2)); GEN p1,p2,p3,u,C2,T2, x = (GEN)nf[1]; C2 = gdiv(gmul2n(C,2), absi((GEN)nf[3])); p1 = gmul(pre,lllintpartial(pre)); av1 = avma; T2 = tot_real? gmael(nf,5,4) : nf_get_T2((GEN) nf[7], roots(x,prec)); p3 = qf_base_change(T2,p1,1); if (N <= 6 && test_mat(p3,p,C2,k)) { avma = av1; return gerepileupto(av,p1); } av1=avma; lim = stack_lim(av1,2); for (;;) { if (DEBUGLEVEL>2) fprintferr("exponent: %ld\n",k); for(;;) { u = tot_real? lllgramint(p3): lllgramintern(p3,100,1,prec); if (u) break; prec=(prec<<1)-2; if (DEBUGLEVEL > 1) err(warnprec,"nffactor[1]",prec); T2 = nf_get_T2((GEN) nf[7], roots(x,prec)); p3 = qf_base_change(T2,p1,1); } if (DEBUGLEVEL>2) msgtimer("lllgram + base change"); p3 = qf_base_change(p3,u,1); if (test_mat(p3,p,C2,k)) { *kmax = k; return gerepileupto(av,gmul(p1,u)); } /* il faut augmenter la precision en meme temps */ p2=shifti(gceil(mulsr(k, glog(p,DEFAULTPREC))),-1); prec += (long)(itos(p2)*pariK1); if (DEBUGLEVEL > 1) err(warnprec,"nffactor[2]",prec); k = k<<1; p1 = idealmullll(nf,p1,p1); if (low_stack(lim, stack_lim(av1,2))) { if (DEBUGMEM>1) err(warnmem,"T2_matrix_pow"); p1 = gerepileupto(av1,p1); } if (!tot_real) T2 = nf_get_T2((GEN) nf[7], roots(x,prec)); p3 = qf_base_change(T2,p1,1); } } /* Calcule la factorisation du polynome x qui est sans facteurs carres dans nf, Le polynome est a coefficients dans Z_k et son terme dominant est un entier rationnel, si fl=1 renvoie seulement les racines du polynome contenues dans le corps */ static GEN nfsqff(GEN nf,GEN pol, long fl) { long d=lgef(pol),i,k,m,n,av=avma,tetpil,newprec,prec; GEN p1,pr,p2,rep,k2,C,h,dk,dki,p,prh,p3,T2,polbase,fact,pk; GEN polmod,polred,hinv,lt,minp,den,maxp=shifti(gun,32),run; dk=absi((GEN)nf[3]); dki=mulii(dk,(GEN)nf[4]); n=lgef(nf[1])-3; polbase = unifpol(nf,pol,0); polmod = unifpol(nf,pol,1); dki=mulii(dki,gnorm((GEN)polmod[d-1])); prec = DEFAULTPREC; for (;;) { if (prec <= gprecision(nf)) T2 = gprec_w(gmael(nf,5,3), prec); else T2 = nf_get_T2((GEN)nf[7], roots((GEN)nf[1], prec)); run=realun(prec); p1=realzero(prec); for (i=2; i 0) break; prec = (prec<<1)-2; if (DEBUGLEVEL > 1) err(warnprec, "nfsqff", prec); } if (DEBUGLEVEL>=4) fprintferr("La norme de ce polynome est : %Z\n", p1); lt=(GEN)leading_term(polbase)[1]; p2=mulis(sqri(lt),n); C=mpadd(p1,p2); C=mpadd(C,gsqrt(gmul(p1,p2),prec)); if (!fl) C=mpmul(C,sqri(binome(shifti(stoi(n-1),-1),(n-1)>>2))); C=gmul(C,sqri(lt)); if (DEBUGLEVEL>=4) fprintferr("La borne de la norme des coeff du diviseur est : %Z\n", C); k2=gmul2n(gmulgs(glog(gdivgs(gmul2n(C,2),n),DEFAULTPREC),n),-1); if (!fl) k2=mulrr(k2,dbltor(1.1)); minp=gmin(gexp(gmul2n(k2,-6),BIGDEFAULTPREC), maxp); minp=gceil(minp); if (DEBUGLEVEL>=4) { fprintferr("borne inf. sur les nombres premiers : %Z\n", minp); msgtimer("Calcul des bornes"); } for (;;) { pr=choose_prime(nf,dki,minp); p=(GEN)pr[1]; prh=prime_to_ideal(nf,pr); polred=gcopy(polbase); lt=(GEN)leading_term(polbase)[1]; lt=mpinvmod(lt,p); for (i=2; i=4) { msgtimer("Choix de l'ideal premier"); fprintferr("Nombre de facteurs irreductibles modulo pr = %ld\n", lg(rep)-1); } if (lg(rep)==2) { if (fl) { avma=av; return cgetg(1,t_VEC); } rep=cgetg(2,t_VEC); rep[1]=lcopy(polmod); nfcmbf.nfact=1; return gerepileupto(av, rep); } p2=cgetr(DEFAULTPREC); affir(mulii(absi(dk),gpowgs(p,k)),p2); p2=shifti(gceil(mplog(p2)),-1); newprec = MEDDEFAULTPREC + (long)(itos(p2)*pariK1); if (DEBUGLEVEL>=4) fprintferr("nouvelle precision : %ld\n",newprec); prh = idealpows(nf,pr,k); m = k; h = T2_matrix_pow(nf,prh,p,C, &k, newprec); if (m != k) prh=idealpows(nf,pr,k); if (DEBUGLEVEL>=4) { fprintferr("un exposant convenable est : %ld\n",(long)k); msgtimer("Calcul de H"); } pk = gcoeff(prh,1,1); lt=(GEN)leading_term(polbase)[1]; lt=mpinvmod(lt,pk); polred[1] = polbase[1]; for (i=2; i= 4) msgtimer("Calcul de la factorisation pr-adique"); den=ginv(det(h)); hinv=adj(h); lt=(GEN)leading_term(polbase)[1]; if (fl) { long x_a[] = { evaltyp(t_POL)|m_evallg(4), 0,0,0 }; GEN mlt = negi(lt), rem; x_a[1] = polbase[1]; setlgef(x_a, 4); x_a[3] = un; p1=cgetg(lg(rep)+1,t_VEC); polbase = unifpol(nf,polbase,1); for (m=1,i=1; i= 4) msgtimer("Reconnaissance des facteurs"); i = nfcmbf.nfact; if (lgef(nfcmbf.pol)>3) { nfcmbf.res[++i] = (long) nf_pol_divres(nf,nfcmbf.pol,nfcmbf.lt,NULL); nfcmbf.nfact = i; } tetpil=avma; rep=cgetg(i+1,t_VEC); for ( ; i>=1; i--) rep[i]=(long)unifpol(nf,(GEN)nfcmbf.res[i],1); return gerepile(av,tetpil,rep); } static int nf_combine_factors(GEN nf,long fxn,GEN psf,long dlim,long hint) { int val=0; /* assume failure */ GEN newf, newpsf = NULL; long newd,ltop,i; if (dlim<=0) return 0; if (fxn > nfcmbf.nfactmod) return 0; /* first, try deeper factors without considering the current one */ if (fxn != nfcmbf.nfactmod) { val=nf_combine_factors(nf,fxn+1,psf,dlim,hint); if (val && psf) return 1; } /* second, try including the current modular factor in the product */ newf=(GEN)nfcmbf.fact[fxn]; if (!newf) return val; /* modular factor already used */ newd=lgef(newf)-3; if (newd>dlim) return val; /* degree of new factor is too large */ if (newd%hint == 0) { GEN p, quot,rem; newpsf = nf_pol_mul(nf, (psf)? psf: nfcmbf.lt, newf); newpsf = nf_pol_lift(nfcmbf.h,nfcmbf.hinv,nfcmbf.den,newpsf); /* try out the new combination */ ltop=avma; quot=nf_pol_divres(nf,nfcmbf.pol,newpsf,&rem); if (gcmp0(rem)) /* found a factor */ { p = nf_pol_mul(nf,element_inv(nf,leading_term(newpsf)),newpsf); nfcmbf.res[++nfcmbf.nfact] = (long) p; /* store factor */ nfcmbf.fact[fxn]=0; /* remove used modular factor */ /* fix up target */ p=gun; quot=unifpol(nf,quot,0); for (i=2; i