/* $Id: polarit1.c,v 1.114 2002/09/11 02:29:15 karim Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP 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. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /***********************************************************************/ /** **/ /** ARITHMETIC OPERATIONS ON POLYNOMIALS **/ /** (first part) **/ /** **/ /***********************************************************************/ #include "pari.h" extern GEN get_bas_den(GEN bas); extern GEN get_mul_table(GEN x,GEN bas,GEN invbas); extern GEN pol_to_monic(GEN pol, GEN *lead); #define lswap(x,y) { long _t=x; x=y; y=_t; } #define swap(x,y) { GEN _t=x; x=y; y=_t; } /* see splitgen() for how to use these two */ GEN setloop(GEN a) { a=icopy(a); (void)new_chunk(2); /* dummy to get two cells of extra space */ return a; } /* assume a > 0 */ GEN incpos(GEN a) { long i,l=lgefint(a); for (i=l-1; i>1; i--) if (++a[i]) return a; i=l+1; a--; /* use extra cell */ a[0]=evaltyp(1) | evallg(i); a[1]=evalsigne(1) | evallgefint(i); return a; } GEN incloop(GEN a) { long i,l; switch(signe(a)) { case 0: a--; /* use extra cell */ a[0]=evaltyp(t_INT) | evallg(3); a[1]=evalsigne(1) | evallgefint(3); a[2]=1; return a; case -1: l=lgefint(a); for (i=l-1; i>1; i--) if (a[i]--) break; if (a[2] == 0) { a++; /* save one cell */ a[0] = evaltyp(t_INT) | evallg(2); a[1] = evalsigne(0) | evallgefint(2); } return a; default: return incpos(a); } } /*******************************************************************/ /* */ /* DIVISIBILITE */ /* Return 1 if y | x, 0 otherwise */ /* */ /*******************************************************************/ int gdivise(GEN x, GEN y) { gpmem_t av=avma; x=gmod(x,y); avma=av; return gcmp0(x); } int poldivis(GEN x, GEN y, GEN *z) { gpmem_t av = avma; GEN p1 = poldivres(x,y,ONLY_DIVIDES); if (p1) { *z = p1; return 1; } avma=av; return 0; } /*******************************************************************/ /* */ /* POLYNOMIAL EUCLIDEAN DIVISION */ /* */ /*******************************************************************/ /* Polynomial division x / y: * if z = ONLY_REM return remainder, otherwise return quotient * if z != NULL set *z to remainder * *z is the last object on stack (and thus can be disposed of with cgiv * instead of gerepile) */ GEN poldivres(GEN x, GEN y, GEN *pr) { gpmem_t avy, av, av1; long ty=typ(y),tx,vx,vy,dx,dy,dz,i,j,sx,lrem; GEN z,p1,rem,y_lead,mod; GEN (*f)(GEN,GEN); f = gdiv; if (is_scalar_t(ty)) { if (pr == ONLY_REM) return gzero; if (pr && pr != ONLY_DIVIDES) *pr=gzero; return f(x,y); } tx=typ(x); vy=gvar9(y); if (is_scalar_t(tx) || gvar9(x)>vy) { if (pr == ONLY_REM) return gcopy(x); if (pr == ONLY_DIVIDES) return gcmp0(x)? gzero: NULL; if (pr) *pr=gcopy(x); return gzero; } if (tx!=t_POL || ty!=t_POL) err(typeer,"euclidean division (poldivres)"); vx=varn(x); if (vx=0; dy--) { y_lead = (GEN)y[dy+2]; if (!gcmp0(y_lead)) break; } } if (!dy) /* y is constant */ { if (pr && pr != ONLY_DIVIDES) { if (pr == ONLY_REM) return zeropol(vx); *pr = zeropol(vx); } return f(x, constant_term(y)); } dx = degpol(x); if (vx>vy || dx=dy; i--) { av1=avma; p1=(GEN)x[i]; for (j=i-dy+1; j<=i && j<=dz; j++) if (y[i-j] && z[j] != zero) p1 = gadd(p1, gmul((GEN)z[j],(GEN)y[i-j])); if (y_lead) p1 = f(p1,y_lead); if (isexactzero(p1)) { avma=av1; p1 = gzero; } else p1 = avma==av1? gcopy(p1): gerepileupto(av1,p1); z[i-dy] = (long)p1; } if (!pr) return gerepileupto(av,z-2); rem = (GEN)avma; av1 = (gpmem_t)new_chunk(dx+3); for (sx=0; ; i--) { p1 = (GEN)x[i]; /* we always enter this loop at least once */ for (j=0; j<=i && j<=dz; j++) if (y[i-j] && z[j] != zero) p1 = gadd(p1, gmul((GEN)z[j],(GEN)y[i-j])); if (mod && avma==av1) p1 = gmul(p1,mod); if (!gcmp0(p1)) { sx = 1; break; } /* remainder is non-zero */ if (!isinexactreal(p1) && !isexactzero(p1)) break; if (!i) break; avma=av1; } if (pr == ONLY_DIVIDES) { if (sx) { avma=av; return NULL; } avma = (gpmem_t)rem; return gerepileupto(av,z-2); } lrem=i+3; rem -= lrem; if (avma==av1) { avma = (gpmem_t)rem; p1 = gcopy(p1); } else p1 = gerepileupto((gpmem_t)rem,p1); rem[0]=evaltyp(t_POL) | evallg(lrem); rem[1]=evalsigne(1) | evalvarn(vx) | evallgef(lrem); rem += 2; rem[i]=(long)p1; for (i--; i>=0; i--) { av1=avma; p1 = (GEN)x[i]; for (j=0; j<=i && j<=dz; j++) if (y[i-j] && z[j] != zero) p1 = gadd(p1, gmul((GEN)z[j],(GEN)y[i-j])); if (mod && avma==av1) p1 = gmul(p1,mod); rem[i]=avma==av1? lcopy(p1):lpileupto(av1,p1); } rem -= 2; if (!sx) (void)normalizepol_i(rem, lrem); if (pr == ONLY_REM) return gerepileupto(av,rem); z -= 2; { GEN *gptr[2]; gptr[0]=&z; gptr[1]=&rem; gerepilemanysp(av,avy,gptr,2); *pr = rem; return z; } } /*******************************************************************/ /* */ /* ROOTS MODULO a prime p (no multiplicities) */ /* */ /*******************************************************************/ static GEN mod(GEN x, GEN y) { GEN z = cgetg(3,t_INTMOD); z[1]=(long)y; z[2]=(long)x; return z; } static long factmod_init(GEN *F, GEN pp, long *p) { GEN f = *F; long i,d; if (typ(f)!=t_POL || typ(pp)!=t_INT) err(typeer,"factmod"); if (expi(pp) > BITS_IN_LONG - 3) *p = 0; else { *p = itos(pp); if (*p < 2) err(talker,"not a prime in factmod"); } f = gmul(f, mod(gun,pp)); if (!signe(f)) err(zeropoler,"factmod"); f = lift_intern(f); d = lgef(f); for (i=2; i ss[2]); if (nbrac == 1) { avma=av; return cgetg(1,t_COL); } if (nbrac == d && p != ss[2]) { g = mpinvmod((GEN)f[3], pp); setsigne(g,-1); ss = modis(mulii(g, (GEN)f[2]), p); y[nbrac++]=ss[2]; } avma=av; g=cgetg(nbrac,t_COL); if (isonstack(pp)) pp = icopy(pp); for (i=1; i1) y[1] = (long)gmodulsg(0,p); return y; } y = cgetg(n+j,t_COL); if (j>1) { y[1] = zero; n++; } y[j] = (long)FpX_normalize(b,p); if (la) y[j+lb] = (long)FpX_normalize(a,p); pol = gadd(polx[varn(f)], gun); pol0 = constant_term(pol); while (j<=n) { /* cf FpX_split_berlekamp */ a = (GEN)y[j]; la = degpol(a); if (la==1) y[j++] = lsubii(p, constant_term(a)); else if (la==2) { GEN r = quadsolvemod(a, p, 0); y[j++] = (long)r; y[j++] = (long)otherroot(a,r, p); } else for (pol0[2]=1; ; pol0[2]++) { b = ZX_s_add(FpXQ_pow(pol,q, a,p), -1); /* pol^(p-1)/2 - 1 */ b = FpX_gcd(a,b, p); lb = degpol(b); if (lb && lb < la) { b = FpX_normalize(b, p); y[j+lb] = (long)FpX_div(a,b, p); y[j] = (long)b; break; } if (pol0[2] == 100 && !BSW_psp(p)) err(talker, "not a prime in polrootsmod"); } } tetpil = avma; y = gerepile(av,tetpil,sort(y)); if (isonstack(p)) p = icopy(p); for (i=1; i<=n; i++) y[i] = (long)mod((GEN)y[i], p); return y; } GEN rootmod0(GEN f, GEN p, long flag) { switch(flag) { case 0: return rootmod(f,p); case 1: return rootmod2(f,p); default: err(flagerr,"polrootsmod"); } return NULL; /* not reached */ } /*******************************************************************/ /* */ /* FACTORISATION MODULO p */ /* */ /*******************************************************************/ #define FqX_div(x,y,T,p) FpXQX_divres((x),(y),(T),(p),NULL) #define FqX_rem(x,y,T,p) FpXQX_divres((x),(y),(T),(p),ONLY_REM) #define FqX_red FpXQX_red #define FqX_sqr FpXQX_sqr static GEN spec_FpXQ_pow(GEN x, GEN p, GEN S); extern GEN pol_to_vec(GEN x, long N); extern GEN FqXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p); extern GEN FpXQX_from_Kronecker(GEN z, GEN pol, GEN p); extern GEN FpXQX_safegcd(GEN P, GEN Q, GEN T, GEN p); extern GEN u_normalizepol(GEN x, long lx); extern GEN Fq_pow(GEN x, GEN n, GEN pol, GEN p); /* Functions giving information on the factorisation. */ /* u in Z[X], return kernel of (Frob - Id) over Fp[X] / u */ static GEN FpM_Berlekamp_ker(GEN u, GEN p) { long j,N = degpol(u); GEN vker,v,w,Q,p1; if (DEBUGLEVEL > 7) (void)timer2(); Q = cgetg(N+1,t_MAT); Q[1] = (long)zerocol(N); w = v = FpXQ_pow(polx[varn(u)],p,u,p); for (j=2; j<=N; j++) { p1 = pol_to_vec(w, N); p1[j] = laddis((GEN)p1[j], -1); Q[j] = (long)p1; if (j < N) { gpmem_t av = avma; w = gerepileupto(av, FpX_res(gmul(w,v), u, p)); } } if (DEBUGLEVEL > 7) msgtimer("frobenius"); vker = FpM_ker(Q,p); if (DEBUGLEVEL > 7) msgtimer("kernel"); return vker; } static GEN FqM_Berlekamp_ker(GEN u, GEN T, GEN q, GEN p) { long j,N = degpol(u); GEN vker,v,w,Q,p1; if (DEBUGLEVEL > 7) (void)timer2(); Q = cgetg(N+1,t_MAT); Q[1] = (long)zerocol(N); w = v = FqXQ_pow(polx[varn(u)], q, u, T, p); for (j=2; j<=N; j++) { p1 = pol_to_vec(w, N); p1[j] = laddgs((GEN)p1[j], -1); Q[j] = (long)p1; if (j < N) { gpmem_t av = avma; w = gerepileupto(av, FpXQX_divres(FpXQX_mul(w,v, T,p), u,T,p,ONLY_REM)); } } if (DEBUGLEVEL > 7) msgtimer("frobenius"); vker = FqM_ker(Q,T,p); if (DEBUGLEVEL > 7) msgtimer("kernel"); return vker; } /* f in ZZ[X] and p a prime number. */ long FpX_is_squarefree(GEN f, GEN p) { gpmem_t av = avma; GEN z; z = FpX_gcd(f,derivpol(f),p); avma = av; return lgef(z)==3; } /* idem * leading term of f must be prime to p. */ /* Compute the number of roots in Fp without counting multiplicity * return -1 for 0 polynomial. */ long FpX_nbroots(GEN f, GEN p) { long n=lgef(f); gpmem_t av = avma; GEN z; if (n <= 4) return n-3; f = FpX_red(f, p); z = FpXQ_pow(polx[varn(f)], p, f, p); z = FpX_sub(z,polx[varn(f)],NULL); z = FpX_gcd(z,f,p), avma = av; return degpol(z); } long FpX_is_totally_split(GEN f, GEN p) { long n=degpol(f); gpmem_t av = avma; GEN z; if (n <= 1) return 1; if (!is_bigint(p) && n > p[2]) return 0; f = FpX_red(f, p); z = FpXQ_pow(polx[varn(f)], p, f, p); avma = av; return lgef(z)==4 && gcmp1((GEN)z[3]) && !signe(z[2]); } /* u in ZZ[X] and p a prime number. * u must be squarefree mod p. * leading term of u must be prime to p. */ long FpX_nbfact(GEN u, GEN p) { gpmem_t av = avma; GEN vker = FpM_Berlekamp_ker(u,p); avma = av; return lg(vker)-1; } /* Please use only use this function when you it is false, or that there is a * lot of factors. If you believe f is irreducible or that it has few factors, * then use `FpX_nbfact(f,p)==1' instead (faster). */ static GEN factcantor0(GEN f, GEN pp, long flag); long FpX_is_irred(GEN f, GEN p) { return !!factcantor0(f,p,2); } static GEN modulo; static GEN gsmul(GEN a,GEN b){return FpX_mul(a,b,modulo);} GEN FpV_roots_to_pol(GEN V, GEN p, long v) { gpmem_t ltop=avma; long i; GEN g=cgetg(lg(V),t_VEC); for(i=1;i 0 */ static GEN init_pow_p_mod_pT(GEN p, GEN T) { long i, n = degpol(T), v = varn(T); GEN p1, S = cgetg(n, t_VEC); if (n == 1) return S; S[1] = (long)FpXQ_pow(polx[v], p, T, p); /* use as many squarings as possible */ for (i=2; i < n; i+=2) { p1 = gsqr((GEN)S[i>>1]); S[i] = (long)FpX_res(p1, T, p); if (i == n-1) break; p1 = gmul((GEN)S[i], (GEN)S[1]); S[i+1] = (long)FpX_res(p1, T, p); } return S; } /* compute x^p, S is as above */ static GEN spec_FpXQ_pow(GEN x, GEN p, GEN S) { long i, dx = degpol(x); gpmem_t av = avma, lim = stack_lim(av, 1); GEN x0 = x+2, z; z = (GEN)x0[0]; if (dx < 0) err(talker, "zero polynomial in FpXQ_pow. %Z not prime", p); for (i = 1; i <= dx; i++) { GEN d, c = (GEN)x0[i]; /* assume coeffs in [0, p-1] */ if (!signe(c)) continue; d = (GEN)S[i]; if (!gcmp1(c)) d = gmul(c,d); z = gadd(z, d); if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) err(warnmem,"spec_FpXQ_pow"); z = gerepileupto(av, z); } } z = FpX_red(z, p); return gerepileupto(av, z); } /* factor f mod pp. * If (flag = 1) return the degrees, not the factors * If (flag = 2) return NULL if f is not irreducible */ static GEN factcantor0(GEN f, GEN pp, long flag) { long i, j, k, d, e, vf, p, nbfact; gpmem_t tetpil, av = avma; GEN ex,y,f2,g,g1,u,v,pd,q; GEN *t; if (!(d = factmod_init(&f, pp, &p))) { avma=av; return trivfact(); } /* to hold factors and exponents */ t = (GEN*)cgetg(d+1,t_VEC); ex = new_chunk(d+1); vf=varn(f); e = nbfact = 1; for(;;) { f2 = FpX_gcd(f,derivpol(f), pp); if (flag > 1 && lgef(f2) > 3) return NULL; g1 = FpX_div(f,f2,pp); k = 0; while (lgef(g1)>3) { long du,dg; GEN S; k++; if (p && !(k%p)) { k++; f2 = FpX_div(f2,g1,pp); } u = g1; g1 = FpX_gcd(f2,g1, pp); if (lgef(g1)>3) { u = FpX_div( u,g1,pp); f2= FpX_div(f2,g1,pp); } du = degpol(u); if (du <= 0) continue; /* here u is square-free (product of irred. of multiplicity e * k) */ S = init_pow_p_mod_pT(pp, u); pd=gun; v=polx[vf]; for (d=1; d <= du>>1; d++) { if (!flag) pd = mulii(pd,pp); v = spec_FpXQ_pow(v, pp, S); g = FpX_gcd(gadd(v, gneg(polx[vf])), u, pp); dg = degpol(g); if (dg <= 0) continue; /* Ici g est produit de pol irred ayant tous le meme degre d; */ j=nbfact+dg/d; if (flag) { if (flag > 1) return NULL; for ( ; nbfact X) pour faire pgcd de g avec * w^(p^d-1)/2 jusqu'a casser. p = 2 is treated separately. */ if (p) split(p,t+nbfact,d,pp,q,r,S); else splitgen(pp,t+nbfact,d,pp,q,r); for (; nbfact 1) { avma = av; return gun; } /* irreducible */ tetpil=avma; y=cgetg(3,t_MAT); if (!flag) { y[1]=(long)t; setlg(t, nbfact); y[2]=(long)ex; (void)sort_factor(y,cmpii); } u=cgetg(nbfact,t_COL); y[1]=(long)u; v=cgetg(nbfact,t_COL); y[2]=(long)v; if (flag) for (j=1; j P(Y,X), n-1 is the degree in Y */ GEN swap_polpol(GEN x, long n, long w) { long j, lx = lgef(x), ly = n+3; long v=varn(x); GEN y = cgetg(ly, t_POL); y[1]=evalsigne(1) | evallgef(ly) | evalvarn(v); for (j=2; jir) swap(t[i],t[ir]); ir++;} long FpX_split_berlekamp(GEN *t, GEN p) { GEN u = *t, a,b,po2,vker,pol; long N = degpol(u), d, i, ir, L, la, lb, ps, vu = varn(u); gpmem_t av0 = avma; vker = FpM_Berlekamp_ker(u,p); vker = mat_to_vecpol(vker,vu); d = lg(vker)-1; ps = is_bigint(p)? 0: p[2]; if (ps) { avma = av0; a = cgetg(d+1, t_VEC); /* hack: hidden gerepile */ for (i=1; i<=d; i++) a[i] = (long)pol_to_small((GEN)vker[i]); vker = a; } po2 = shifti(p, -1); /* (p-1) / 2 */ pol = cgetg(N+3,t_POL); ir = 0; /* t[i] irreducible for i <= ir, still to be treated for i < L */ for (L=1; L3) { k++; if (p && !(k%p)) { k++; f2 = FpX_div(f2,g1,pp); } p1 = FpX_gcd(f2,g1, pp); u = g1; g1 = p1; if (degpol(p1)) { u = FpX_div( u,p1,pp); f2= FpX_div(f2,p1,pp); } /* u is square-free (product of irred. of multiplicity e * k) */ N = degpol(u); if (N) { t[nbfact] = FpX_normalize(u,pp); d = (N==1)? 1: FpX_split_berlekamp(t+nbfact, pp); for (j=0; j= precp(x) + v) return invlead? gmul(x, invlead): gcopy(x); sx = !gcmp0(x); p1 = (GEN)x[4]; } else { sx = signe(x); if (!sx) return gzero; v = pvaluation(x,p,&p1); } y = cgetg(5,t_PADIC); if (sx && v < r) { y[4] = lmodii(p1,pr); r -= v; } else { y[4] = zero; v = r; r = 0; } y[3] = (long)pr; y[2] = (long)p; y[1] = evalprecp(r)|evalvalp(v); return invlead? gerepileupto(av, gmul(invlead,y)): y; } /* as above. always return a t_PADIC */ static GEN strict_int_to_padic(GEN x, GEN p, GEN pr, long r, GEN invlead) { GEN y = int_to_padic(x, p, pr, r, invlead); if (y == gzero) y = ggrandocp(p,r); return y; } /* return (x + O(p^r)) normalized (multiply by a unit such that leading coeff * is a power of p), x in Z[X] (or Z_p[X]) */ static GEN pol_to_padic(GEN x, GEN pr, GEN p, long r) { long v = 0,i,lx = lgef(x); GEN z = cgetg(lx,t_POL), lead = leading_term(x); if (gcmp1(lead)) lead = NULL; else { gpmem_t av = avma; v = ggval(lead,p); if (v) lead = gdiv(lead, gpowgs(p,v)); lead = int_to_padic(lead,p,pr,r,NULL); lead = gerepileupto(av, ginv(lead)); } for (i=lx-1; i>1; i--) z[i] = (long)int_to_padic((GEN)x[i],p,pr,r,lead); z[1] = x[1]; return z; } static GEN padic_trivfact(GEN x, GEN p, long r) { GEN y = cgetg(3,t_MAT); p = icopy(p); y[1]=(long)_col(pol_to_padic(x,gpowgs(p,r),p,r)); y[2]=(long)_col(gun); return y; } /* Assume x reduced mod p. q = p^e (simplified version of int_to_padic). * If p = 2, is defined (and reduced) mod 4 [from rootmod] */ GEN Fp_to_Zp(GEN x, GEN p, GEN q, long e) { GEN y = cgetg(5, t_PADIC); if (egalii(p, x)) /* implies p = x = 2 */ { x = gun; q = shifti(q, -1); y[1] = evalprecp(e-1) | evalvalp(1); } else if (!signe(x)) y[1] = evalprecp(0) | evalvalp(e); else y[1] = evalprecp(e) | evalvalp(0); y[2] = (long)p; y[3] = (long)q; y[4] = (long)x; return y; } /* f != 0 in Z[X], primitive, a t_PADIC s.t f(a) = 0 mod p */ static GEN apprgen_i(GEN f, GEN a) { GEN fp,u,p,q,P,res,a0,rac; long prec,i,j,k; prec = gcmp0(a)? valp(a): precp(a); if (prec <= 1) return _vec(a); fp = derivpol(f); u = ggcd(f,fp); if (degpol(u) > 0) { f = gdeuc(f,u); fp = derivpol(f); } p = (GEN)a[2]; P = egalii(p,gdeux)? stoi(4): p; a0= gmod(a, P); #if 0 /* assumption */ if (!gcmp0(FpX_eval(f,a0,P))) err(rootper2); #endif if (!gcmp0(FpX_eval(fp,a0,p))) /* simple zero */ { res = rootpadiclift(f, a0, p, prec); res = strict_int_to_padic(res,p,gpowgs(p,prec),prec,NULL); return _vec(res); } f = poleval(f, gadd(a, gmul(P,polx[varn(f)]))); f = padic_pol_to_int(f); f = gdiv(f, gpowgs(p,ggval(f, p))); res = cgetg(degpol(f)+1,t_VEC); q = gpowgs(p,prec); rac = lift_intern(rootmod(f, P)); for (j=i=1; i 0) { f = gdeuc(f,z); fp = derivpol(f); } rac = rootmod(f, (egalii(p,gdeux) && prec>=2)? stoi(4): p); rac = lift_intern(rac); lx = lg(rac); if (prec==1) { y = cgetg(lx,t_COL); for (i=1; i>1)+(a&1); if (a==1) break; } *pmask=mask>>j; return BITS_IN_LONG-j; } /* SPEC: q is an integer > 1 e>=0 f in ZZ[X], with leading term prime to q. S must be a simple root mod p for all p|q. return roots of f mod q^e, as integers (implicitly mod Q) */ /* STANDARD USE There exists p a prime number and a>0 such that q=p^a f in ZZ[X], with leading term prime to p. S must be a simple root mod p. return p-adics roots of f with prec b, as integers (implicitly mod q^e) */ GEN rootpadiclift(GEN T, GEN S, GEN p, long e) { gpmem_t ltop=avma; long x; GEN qold, q, qm1; GEN W, Tr, Sr, Wr = gzero; long i, nb, mask; x = varn(T); qold = p ; q = p; qm1 = gun; nb=hensel_lift_accel(e, &mask); Tr = FpX_red(T,q); W=FpX_eval(deriv(Tr, x),S,q); W=mpinvmod(W,q); for(i=0;itotally split-->use trace trick */ { gpmem_t av=avma; GEN z; z=(GEN)f[lgef(f)-2];/*-trace(roots)*/ for(i=1; i1; i--) { p1=(GEN)x[i]; if (typ(p1)==t_PADIC) { e=valp(p1); if (signe(p1[4])) e += precp(p1); if (e 0) { f = gdeuc(f,u); fp = derivpol(f); } T = (GEN)a[1]; prec = getprec((GEN)a[2], BIGINT, &p); prec = getprec(T, prec, &p); if (prec==BIGINT) err(rootper1); p1 = poleval(f,a); v = ggval(lift_intern(p1),p); if (v<=0) err(rootper2); fl2 = egalii(p,gdeux); if (fl2 && v==1) err(rootper2); v=ggval(lift_intern(poleval(fp,a)), p); if (!v) { while (!gcmp0(p1)) { a = gsub(a, gdiv(p1,poleval(fp,a))); p1 = poleval(f,a); } tetpil=avma; pro=cgetg(2,t_COL); pro[1]=lcopy(a); return gerepile(av,tetpil,pro); } n=degpol(f); pro=cgetg(n+1,t_COL); if (is_bigint(p)) err(impl,"apprgen9 for p>=2^31"); x=gmodulcp(ggrandocp(p,prec), T); if (fl2) { ps_1=3; x2=ggrandocp(p,2); p=stoi(4); } else { ps_1=itos(p)-1; x2=ggrandocp(p,1); } f = poleval(f,gadd(a,gmul(p,polx[varn(f)]))); f = gdiv(f,gpowgs(p,ggval(f,p))); d=degpol(T); vecg=cgetg(d+1,t_COL); for (i=1; i<=d; i++) vecg[i] = (long)setloop(gzero); va=varn(T); j = 1; for(;;) /* loop through F_q */ { ip=gmodulcp(gtopoly(vecg,va),T); if (gcmp0(poleval(f,gadd(ip,x2)))) { u = apprgen9(f,gadd(ip,x)); for (k=1; k vy) return -1; return cmpii((GEN)x[4], (GEN)y[4]); } /*******************************/ /* Using Buchmann--Lenstra */ /*******************************/ /* factor T = nf[1] in Zp to precision k */ static GEN padicff2(GEN nf,GEN p,long k) { GEN z, mat, D, U,fa, pk, dec_p, Ui, mulx; long i, l; mulx = eltmul_get_table(nf, gmael(nf,8,2)); /* mul by (x mod T) */ dec_p = primedec(nf,p); l = lg(dec_p); fa = cgetg(l,t_COL); D = NULL; /* -Wall */ for (i=1; i 6) (void)timer2(); av = avma; is2 = egalii(p, gdeux); for(cnt = 1;;cnt++) { /* splits *t with probability ~ 1 - 2^(1-r) */ w = w0 = FqX_rand(dt,v, T,p); for (l=1; l 6) fprintferr("[FqX_split] splitting time: %ld (%ld trials)\n",timer2(),cnt); l /= d; t[l] = FqX_div(*t,w, T,p); *t = w; FqX_split(t+l,d,q,S,T,p); FqX_split(t ,d,q,S,T,p); } /* to "compare" (real) scalars and t_INTMODs */ static int cmp_coeff(GEN x, GEN y) { if (typ(x) == t_INTMOD) x = (GEN)x[2]; if (typ(y) == t_INTMOD) y = (GEN)y[2]; return gcmp(x,y); } int cmp_pol(GEN x, GEN y) { long fx[3], fy[3]; long i,lx,ly; int fl; if (typ(x) == t_POLMOD) x = (GEN)x[2]; if (typ(y) == t_POLMOD) y = (GEN)y[2]; if (typ(x) == t_POL) lx = lgef(x); else { lx = 3; fx[2] = (long)x; x = fx; } if (typ(y) == t_POL) ly = lgef(y); else { ly = 3; fy[2] = (long)y; y = fy; } if (lx > ly) return 1; if (lx < ly) return -1; for (i=lx-1; i>1; i--) if ((fl = cmp_coeff((GEN)x[i], (GEN)y[i]))) return fl; return 0; } /* assume n > 1, X over FqX */ /* return S = [ X^q, X^2q, ... X^(n-1)q ] mod u (in Fq[X]) in Kronecker form */ static GEN init_pow_q_mod_pT(GEN X, GEN q, GEN u, GEN T, GEN p) { long i, n = degpol(u); GEN p1, S = cgetg(n, t_VEC); S[1] = (long)FqXQ_pow(X, q, u, T, p); #if 1 /* use as many squarings as possible */ for (i=2; i < n; i+=2) { p1 = gsqr((GEN)S[i>>1]); S[i] = (long)FqX_rem(p1, u, T,p); if (i == n-1) break; p1 = gmul((GEN)S[i], (GEN)S[1]); S[i+1] = (long)FqX_rem(p1, u, T,p); } #else for (i=2; i < n; i++) { p1 = gmul((GEN)S[i-1], (GEN)S[1]); S[i] = (long)FqX_rem(p1, u, T,p); } #endif for (i=1; i < n; i++) S[i] = (long)to_Kronecker((GEN)S[i], T); return S; } /* compute x^q, S is as above */ static GEN spec_Fq_pow_mod_pol(GEN x, GEN S, GEN T, GEN p) { long i, dx = degpol(x); gpmem_t av = avma, lim = stack_lim(av, 1); GEN x0 = x+2, z,c; z = c = (GEN)x0[0]; for (i = 1; i <= dx; i++) { GEN d; c = (GEN)x0[i]; if (gcmp0(c)) continue; d = (GEN)S[i]; if (!gcmp1(c)) d = gmul(c,d); z = gadd(z, d); if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) err(warnmem,"spec_Fq_pow_mod_pol"); z = gerepileupto(av, z); } } z = FpXQX_from_Kronecker(z, T, p); setvarn(z, varn(x)); return gerepileupto(av, z); } static long isabsolutepol(GEN f) { int i, l = lgef(f); for(i=2; i 0) return 0; } return 1; } GEN factmod9(GEN f, GEN p, GEN T) { gpmem_t av = avma; long pg, i, j, k, d, e, N, vf, va, nbfact, nbf, pk; GEN S,ex,f2,f3,df1,df2,g1,u,v,q,unfp,unfq, *t; GEN frobinv,X; if (typ(T)!=t_POL || typ(f)!=t_POL || gcmp0(T)) err(typeer,"factmod9"); vf = varn(f); va = varn(T); if (va <= vf) err(talker,"polynomial variable must have higher priority in factorff"); unfp = gmodulsg(1,p); T = gmul(unfp,T); unfq = gmodulo(gmul(unfp,polun[va]), T); f = gmul(unfq,f); if (!signe(f)) err(zeropoler,"factmod9"); d = degpol(f); if (!d) { avma = av; return trivfact(); } f = simplify(lift_intern(lift_intern(f))); T = lift_intern(T); if (isabsolutepol(f)) { GEN z = Fp_factor_rel0(f, p, T); return to_Fq_fact((GEN)z[1],(GEN)z[2],lg(z[1]), 0, unfq,av); } pg = is_bigint(p)? 0: itos(p); S = df2 = NULL; /* gcc -Wall */ t = (GEN*)cgetg(d+1,t_VEC); ex = new_chunk(d+1); frobinv = gpowgs(p, degpol(T)-1); X = polx[vf]; q = gpowgs(p, degpol(T)); e = nbfact = 1; pk = 1; f3 = NULL; df1 = FqX_deriv(f, T, p); for(;;) { while (gcmp0(df1)) { /* needs d >= p: pg = 0 can't happen */ pk *= pg; e = pk; j = (degpol(f))/pg+3; setlg(f,j); setlgef(f,j); for (i=2; i 1) S = init_pow_q_mod_pT(X, q, u, T, p); for (d=1; d <= N>>1; d++) { qqd = mulii(qqd,q); v = spec_Fq_pow_mod_pol(v, S, T, p); g = FqX_gcd(gsub(v,X),u, T,p); dg = degpol(g); if (dg <= 0) continue; /* all factors of g have degree d */ j = nbfact+dg/d; t[nbfact] = g; FqX_split(t+nbfact,d,q,S,T,p); for (; nbfact0) g=0; } else if (ti != t_INT && ti != t_INTMOD && !is_frac_t(ti)) g=0; } av1=avma; p2=cgetg(3,t_COMPLEX); p2[1]=lmppi(DEFAULTPREC); p2[2]=ldivrs((GEN)p2[1],10); p11=cgetg(4,t_POL); p11[1]=evalsigne(1)+evallgef(4); setvarn(p11,v); p11[3]=un; p12=cgetg(5,t_POL); p12[1]=evalsigne(1)+evallgef(5); setvarn(p12,v); p12[4]=un; for (i=2; i<=deg0+2 && gcmp0((GEN)x[i]); i++) gaffsg(0,(GEN)y[i-1]); k=i-2; if (k!=deg0) { if (k) { j=deg0+3-k; pax=cgetg(j,t_POL); pax[1] = evalsigne(1) | evalvarn(v) | evallgef(j); for (i=2; iemax) emax=e1; } e=emax-e; if (e<0) e=0; avma=av3; if (ps!=pax) xd0=deriv(ps,v); xdabs=cgetg(deg+2,t_POL); xdabs[1]=xd0[1]; for (i=2; i= -20) { p7 = gneg_i(gdiv(p4, poleval(xd,p3))); av3 = avma; if (gcmp0(p5)) exc = -32; else exc = expo(gnorm(p7))-expo(gnorm(p3)); avma = av3; for (j=1; j<=10; j++) { p8=gadd(p3,p7); p9=poleval(xc,p8); p10=gnorm(p9); if (exc < -20 || cmprr(p10,p5) < 0) { GEN *gptr[3]; p3=p8; p4=p9; p5=p10; gptr[0]=&p3; gptr[1]=&p4; gptr[2]=&p5; gerepilemanysp(av2,av3,gptr,3); break; } gshiftz(p7,-2,p7); avma=av3; } if (j > 10) { avma=av; if (DEBUGLEVEL) { fprintferr("too many iterations in rootsold(): "); fprintferr("using roots2()\n"); flusherr(); } return roots2(x,l); } } p1=(GEN)y[k+m*i]; setlg(p1[1],3); setlg(p1[2],3); gaffect(p3,p1); avma=av2; p14=(GEN)p1[1]; p15=(GEN)p1[2]; for (ln=4; ln<=l; ln=(ln<<1)-2) { setlg(p14,ln); setlg(p15,ln); if (gcmp0(p14)) { settyp(p14,t_INT); p14[1]=2; } if (gcmp0(p15)) { settyp(p15,t_INT); p15[1]=2; } p4=poleval(xc,p1); p5=poleval(xd,p1); p6=gneg_i(gdiv(p4,p5)); settyp(p14,t_REAL); settyp(p15,t_REAL); gaffect(gadd(p1,p6),p1); avma=av2; } } setlg(p14,l); setlg(p15,l); p7=gcopy(p1); p14=(GEN)(p7[1]); p15=(GEN)(p7[2]); setlg(p14,l+1); setlg(p15,l+1); if (gcmp0(p14)) { settyp(p14,t_INT); p14[1]=2; } if (gcmp0(p15)) { settyp(p15,t_INT); p15[1]=2; } for (ii=1; ii<=5; ii++) { p4=poleval(ps,p7); p5=poleval(xd0,p7); p6=gneg_i(gdiv(p4,p5)); p7=gadd(p7,p6); p14=(GEN)(p7[1]); p15=(GEN)(p7[2]); if (gcmp0(p14)) { settyp(p14,t_INT); p14[1]=2; } if (gcmp0(p15)) { settyp(p15,t_INT); p15[1]=2; } } gaffect(p7,p1); p4=poleval(ps,p7); p6=gdiv(p4,poleval(xdabs,gabs(p7,l))); if (gexpo(p6)>=expmin) { avma=av; if (DEBUGLEVEL) { fprintferr("internal error in rootsold(): using roots2()\n"); flusherr(); } return roots2(x,l); } avma=av2; if (expo(p1[2])=1; k--) { p2 = (GEN)y[k]; if (gcmp0((GEN)p2[2])) f=0; else f=1; if (f0)? 0 : 1; } } rr=cgetg(N+1,t_COL); for (i=1; i<=N; i++) { p1 = cgetc(PREC); rr[i] = (long)p1; for (j=3; j=1; j--) { x=gzero; flagrealrac=0; if (j==1) x=gneg_i(gdiv((GEN)qolbis[2],(GEN)qolbis[3])); else { x=laguer(qolbis,j,x,EPS,PREC); if (x == NULL) goto RLAB; } if (flagexactpol) { x=gprec(x,(long)((PREC-1)*pariK)); x=laguer(qol,deg,x,gmul2n(EPS,-32),PREC+1); } else x=laguer(qol,deg,x,EPS,PREC); if (x == NULL) goto RLAB; if (typ(x)==t_COMPLEX && gcmp(gabs(gimag(x),PREC),gmul2n(gmul(EPS,gabs(greal(x),PREC)),1))<=0) { x[2]=zero; flagrealrac=1; } else if (j==1 && flagrealpol) { x[2]=zero; flagrealrac=1; } else if (typ(x)!=t_COMPLEX) flagrealrac=1; for (i=1; i<=multiqol; i++) gaffect(x,(GEN)rr[nbroot+i]); nbroot+=multiqol; if (!flagrealpol || flagrealrac) { ad = (GEN*) new_chunk(j+1); for (i=0; i<=j; i++) ad[i]=(GEN)qolbis[i+2]; b=(GEN)ad[j]; for (i=j-1; i>=0; i--) { c=(GEN)ad[i]; ad[i]=b; b=gadd(gmul((GEN)rr[nbroot],b),c); } v=cgetg(j+1,t_VEC); for (i=1; i<=j; i++) v[i]=(long)ad[j-i]; qolbis=gtopoly(v,varn(qolbis)); if (flagrealpol) for (i=2; i<=j+1; i++) if (typ(qolbis[i])==t_COMPLEX) mael(qolbis,i,2)=zero; } else { ad = (GEN*) new_chunk(j-1); ad[j-2]=(GEN)qolbis[j+2]; p1=gmulsg(2,greal((GEN)rr[nbroot])); p2=gnorm((GEN)rr[nbroot]); ad[j-3]=gadd((GEN)qolbis[j+1],gmul(p1,ad[j-2])); for (i=j-2; i>=2; i--) ad[i-2] = gadd((GEN)qolbis[i+2],gsub(gmul(p1,ad[i-1]),gmul(p2,ad[i]))); v=cgetg(j,t_VEC); for (i=1; i<=j-1; i++) v[i]=(long)ad[j-1-i]; qolbis=gtopoly(v,varn(qolbis)); for (i=2; i<=j; i++) if (typ(qolbis[i])==t_COMPLEX) mael(qolbis,i,2)=zero; for (i=1; i<=multiqol; i++) gaffect(gconj((GEN)rr[nbroot]), (GEN)rr[nbroot+i]); nbroot+=multiqol; j--; } } avma=av1; } for (j=2; j<=N; j++) { x=(GEN)rr[j]; if (gcmp0((GEN)x[2])) fr=0; else fr=1; for (i=j-1; i>=1; i--) { if (gcmp0(gmael(rr,i,2))) f=0; else f=1; if (f=0; j--) { f = gadd(gmul(x,f),d); d = gadd(gmul(x,d),b); b = gadd(gmul(x,b), (GEN)pol[j+2]); erre = gadd(QuickNormL1(b,PREC), gmul(abx,erre)); } erre = gmul(erre,EPS); if (gcmp(QuickNormL1(b,PREC),erre)<=0) { gaffect(x,rac); avma = av1; return rac; } g=gdiv(d,b); g2=gsqr(g); h=gsub(g2, gmul2n(gdiv(f,b),1)); sq=gsqrt(gmulsg(N-1,gsub(gmulsg(N,h),g2)),PREC); gp=gadd(g,sq); gm=gsub(g,sq); abp=gnorm(gp); abm=gnorm(gm); if (gcmp(abp,abm)<0) gp=gcopy(gm); if (gsigne(gmax(abp,abm))==1) dx = gdivsg(N,gp); else dx = gmul(gadd(gun,abx),gexp(gmulgs(I,iter),PREC)); x1=gsub(x,dx); if (gcmp(QuickNormL1(gsub(x,x1),PREC),EPS)<0) { gaffect(x,rac); avma = av1; return rac; } if (iter%MT) x=gcopy(x1); else x=gsub(x,gmul(ffrac[iter/MT],dx)); } avma=av; return NULL; } #undef MR #undef MT /***********************************************************************/ /** **/ /** ROOTS of a polynomial with REAL coeffs **/ /** **/ /***********************************************************************/ #define RADIX 1L #define COF 0.95 /* ONLY FOR REAL COEFFICIENTS MATRIX : replace the matrix x with a symmetric matrix a with the same eigenvalues */ static GEN balanc(GEN x) { gpmem_t av = avma; long last,i,j, sqrdx = (RADIX<<1), n = lg(x); GEN r,c,cofgen,a; a = dummycopy(x); last = 0; cofgen = dbltor(COF); while (!last) { last = 1; for (i=1; i 0) {ex--; c=gmul2n(c,-sqrdx);} if (gcmp(gadd(c,r), gmul2n(s,ex)) < 0) { last = 0; for (j=1; j=0.0 ? fabs(a) : -fabs(a)) static GEN hqr(GEN mat) /* find all the eigenvalues of the matrix mat */ { long nn,n,m,l,k,j,its,i,mmin,flj,flk; double **a,p,q,r,s,t,u,v,w,x,y,z,anorm,*wr,*wi; const double eps = 0.000001; GEN eig; n=lg(mat)-1; a=(double**)gpmalloc(sizeof(double*)*(n+1)); for (i=1; i<=n; i++) a[i]=(double*)gpmalloc(sizeof(double)*(n+1)); for (j=1; j<=n; j++) for (i=1; i<=n; i++) a[i][j]=gtodouble((GEN)((GEN)mat[j])[i]); wr=(double*)gpmalloc(sizeof(double)*(n+1)); wi=(double*)gpmalloc(sizeof(double)*(n+1)); anorm=fabs(a[1][1]); for (i=2; i<=n; i++) for (j=(i-1); j<=n; j++) anorm+=fabs(a[i][j]); nn=n; t=0.; if (DEBUGLEVEL>3) { fprintferr("* Finding eigenvalues\n"); flusherr(); } while (nn>=1) { its=0; do { for (l=nn; l>=2; l--) { s=fabs(a[l-1][l-1])+fabs(a[l][l]); if (s==0.) s=anorm; if ((double)(fabs(a[l][l-1])+s)==s) break; } x=a[nn][nn]; if (l==nn){ wr[nn]=x+t; wi[nn--]=0.; } else { y=a[nn-1][nn-1]; w=a[nn][nn-1]*a[nn-1][nn]; if (l == nn-1) { p=0.5*(y-x); q=p*p+w; z=sqrt(fabs(q)); x+=t; if (q>=0. || fabs(q)<=eps) { z=p+SIGN(z,p); wr[nn-1]=wr[nn]=x+z; if (fabs(z)>eps) wr[nn]=x-w/z; wi[nn-1]=wi[nn]=0.; } else{ wr[nn-1]=wr[nn]=x+p; wi[nn-1]=-(wi[nn]=z); } nn-=2; } else { p = q = r = 0.; /* for lint */ if (its==30) err(talker,"too many iterations in hqr"); if (its==10 || its==20) { t+=x; for (i=1; i<=nn; i++) a[i][i]-=x; s = fabs(a[nn][nn-1]) + fabs(a[nn-1][nn-2]); y=x=0.75*s; w=-0.4375*s*s; } its++; for (m=nn-2; m>=l; m--) { z=a[m][m]; r=x-z; s=y-z; p=(r*s-w)/a[m+1][m]+a[m][m+1]; q=a[m+1][m+1]-z-r-s; r=a[m+2][m+1]; s=fabs(p)+fabs(q)+fabs(r); p/=s; q/=s; r/=s; if (m==l) break; u=fabs(a[m][m-1])*(fabs(q)+fabs(r)); v=fabs(p)*(fabs(a[m-1][m-1])+fabs(z)+fabs(a[m+1][m+1])); if ((double)(u+v)==v) break; } for (i=m+2; i<=nn; i++){ a[i][i-2]=0.; if (i!=(m+2)) a[i][i-3]=0.; } for (k=m; k<=nn-1; k++) { if (k!=m) { p=a[k][k-1]; q=a[k+1][k-1]; r = (k != nn-1)? a[k+2][k-1]: 0.; x = fabs(p)+fabs(q)+fabs(r); if (x != 0.) { p/=x; q/=x; r/=x; } } s = SIGN(sqrt(p*p+q*q+r*r),p); if (s == 0.) continue; if (k==m) { if (l!=m) a[k][k-1] = -a[k][k-1]; } else a[k][k-1] = -s*x; p+=s; x=p/s; y=q/s; z=r/s; q/=p; r/=p; for (j=k; j<=nn; j++) { p = a[k][j]+q*a[k+1][j]; if (k != nn-1) { p+=r*a[k+2][j]; a[k+2][j]-=p*z; } a[k+1][j] -= p*y; a[k][j] -= p*x; } mmin = (nn < k+3)? nn: k+3; for (i=l; i<=mmin; i++) { p = x*a[i][k]+y*a[i][k+1]; if (k != nn-1) { p+=z*a[i][k+2]; a[i][k+2]-=p*r; } a[i][k+1] -= p*q; a[i][k] -= p; } } } } } while (l=1; k--) { if (wi[k] != 0.) flk=1; else flk=0; if (flk0) break; wr[k+1]=wr[k]; wi[k+1]=wi[k]; } wr[k+1]=x; wi[k+1]=y; } if (DEBUGLEVEL>3) { fprintferr("* Eigenvalues computed\n"); flusherr(); } for (i=1; i<=n; i++) free(a[i]); free(a); eig=cgetg(n+1,t_COL); for (i=1; i<=n; i++) { if (wi[i] != 0.) { GEN p1 = cgetg(3,t_COMPLEX); eig[i]=(long)p1; p1[1]=(long)dbltor(wr[i]); p1[2]=(long)dbltor(wi[i]); } else eig[i]=(long)dbltor(wr[i]); } free(wr); free(wi); return eig; } /* ONLY FOR POLYNOMIAL WITH REAL COEFFICIENTS : give the roots of the * polynomial a (first, the real roots, then the non real roots) in * increasing order of their real parts MULTIPLE ROOTS ARE FORBIDDEN. */ GEN zrhqr(GEN a,long prec) { gpmem_t av = avma; long i,j,prec2, n = degpol(a), ex = -bit_accuracy(prec); GEN aa,b,p1,rt,rr,hess,x,dx,y,newval,oldval; hess = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { p1 = cgetg(n+1,t_COL); hess[j] = (long)p1; p1[1] = lneg(gdiv((GEN)a[n-j+2],(GEN)a[n+2])); for (i=2; i<=n; i++) p1[i] = (i==(j+1))? un: zero; } rt = hqr(balanc(hess)); prec2 = 2*prec; /* polishing the roots */ aa = gprec_w(a, prec2); b = derivpol(aa); rr = cgetg(n+1,t_COL); for (i=1; i<=n; i++) { x = gprec_w((GEN)rt[i], prec2); for (oldval=NULL;; oldval=newval, x=y) { /* Newton iteration */ dx = poleval(b,x); if (gexpo(dx) < ex) err(talker,"polynomial has probably multiple roots in zrhqr"); y = gsub(x, gdiv(poleval(aa,x),dx)); newval = gabs(poleval(aa,y),prec2); if (gexpo(newval) < ex || (oldval && gcmp(newval,oldval) > 0)) break; } if (DEBUGLEVEL>3) fprintferr("%ld ",i); rr[i] = (long)cgetc(prec); gaffect(y, (GEN)rr[i]); } if (DEBUGLEVEL>3) { fprintferr("\npolished roots = %Z",rr); flusherr(); } return gerepilecopy(av, rr); }