/***********************************************************************/ /** **/ /** ARITHMETIC OPERATIONS ON POLYNOMIALS **/ /** (second part) **/ /** **/ /***********************************************************************/ /* $Id: polarit2.c,v 1.2 1999/09/20 13:30:05 karim Exp $ */ #include "pari.h" GEN polsym(GEN x, long n) { long av1,av2,dx=lgef(x)-3,i,k; GEN s,y,x_lead; if (n<0) err(impl,"polsym of a negative n"); if (typ(x) != t_POL) err(typeer,"polsym"); if (!signe(x)) err(zeropoler,"polsym"); y=cgetg(n+2,t_COL); y[1]=lstoi(dx); x_lead=(GEN)x[dx+2]; if (gcmp1(x_lead)) x_lead=NULL; for (k=1; k<=n; k++) { av1=avma; s = (dx>=k)? gmulsg(k,(GEN)x[dx+2-k]): gzero; for (i=1; i ly) return 1; if (lx < ly) return -1; for (i=lx-1; i>1; i--) if ((fl = polcmp_coeff_cmp((GEN)x[i], (GEN)y[i]))) return fl; return 0; } /* sort factorization so that factors appear by decreasing degree, in place */ GEN sort_factor(GEN y, int (*cmp)(GEN,GEN)) { GEN w,c1,c2, p1 = (GEN)y[1], p2 = (GEN)y[2]; long av=avma, n=lg(p1), i; int (*old)(GEN,GEN) = polcmp_coeff_cmp; c1 = new_chunk(n); c2 = new_chunk(n); polcmp_coeff_cmp = cmp; w = gen_sort(p1, cmp_IND | cmp_C, polcmp); for (i=1; i0) return subii(y,p); return y; case t_POL: lx=lgef(x); y=cgetg(lx,t_POL); y[1]=x[1]; for (i=2; i0) p1=subii(p1,p); y[i]=lpileupto(av,p1); } return y; case t_COL: lx=lg(x); y=cgetg(lx,t_COL); for (i=1; i0) p1=subii(p1,p); y[i]=(long)p1; } return y; } return x; } static GEN decpol(GEN x, long klim) { short int pos[200]; long av=avma,av1,tete,k,kin,i,j,i1,i2,fl,d,nbfact; GEN res,p1,p2; kin=1; res=cgetg(lgef(x)-2,t_VEC); nbfact=0; p1=roots(x,DEFAULTPREC); d=lg(p1)-1; if (!klim) klim=d; do { fl=1; for (k=kin; k+k <= d && k<=klim; k++) { for (i=0; i<=k; i++) pos[i]=i; do { av1=avma; p2=gzero; j=0; for (i1=1; i1<=k; i1++) p2=gadd(p2,(GEN)p1[pos[i1]]); if (gexpo(gimag(p2))<-20 && gexpo(gsub(p2,ground(p2)))<-20) { p2=gun; for (i1=1; i1<=k; i1++) p2=gmul(p2,gsub(polx[0],(GEN)p1[pos[i1]])); p2 = ground(p2); if (gcmp0(gimag(p2)) && gcmp0(gmod(x,p2))) { res[++nbfact]=(long)p2; x=gdiv(x,p2); kin=k; p2=cgetg(d-k+1,t_COL); for (i=i1=i2=1; i<=d; i++) { if (i1<=k && i==pos[i1]) i1++; else p2[i2++]=p1[i]; } p1=p2; d-=k; fl=0; break; } } avma=av1; pos[k]++; while (pos[k-j] > d-j) { j++; pos[k-j]++; } for (i=k-j+1; i<=k; i++) pos[i]=i+pos[k-j]-k+j; } while (j3) res[++nbfact]=(long)x; setlg(res,nbfact+1); tete=avma; return gerepile(av,tete,greal(res)); } /* This code originally by Richard Schroeppel */ /* Note that PARI's idea of the maximum possible coefficient involves the * limit on the degree (klim). Consider revising this. If I don't respect * the degree limit when testing potential factors, there's the possibility * that I might identify a high degree factor that isn't irreducible, because * it's lower degree divisors were missed because they had a coefficient * outside the Borne limit for klim, but the higher degree factor had it's * coefficients within Borne. This would still have the property that any * factors of degree <= klim were guaranteed irr, but higher degrees * (> 2*klim) might not be irr. * * The subroutine: * fxn points at the first unconsidered factor for the current combination * psf is the product-so-far, or 0 for a null product * dlim is the degree limit remaining for unconsidered divisors * other arguments are "global" and must already be setup * as factors are found, they are put in cmbf_fax; the count is kept in * cmbf_faxn; and they are divided out of cmbf_target; the degree and * leading coefficient are updated; and the constituent modular factors * are deleted from cmbf_modfax. * exit value is 1 if any factors are found. * If psf is 0, all factors made up from pieces at or after fxn will be * found & removed. If psf is not 0, only the factor which is a * continuation of psf will be found. */ /* setup for calling cmbf = combine_factors */ static GEN cmbf_target; /* target poly. Assume content removed */ static GEN cmbf_lc; /* leading coefficient */ static GEN cmbf_abslc; /* |lc| */ static GEN cmbf_abslcxtarget;/* abslc * target */ static GEN cmbf_mod; /* modulus */ static GEN cmbf_fax; /* result array + one cell for leftover cst. */ static GEN cmbf_modfax; /* array of modular factors. Each has LC 1.1 based indexing. Product should be congruent to a/lc(a). */ static long cmbf_degree; /* degree(target) */ static long cmbf_modfaxn; /* number of modular factors */ static long cmbf_faxn; /* last used cell in fax. # of factors found */ static GEN cmbf_modhalf; /* assume same variables, y normalized, non constant */ static GEN polidivis(GEN x, GEN y, GEN bound) { long dx,dy,dz,i,j,av, vx = varn(x); GEN z,p1,y_lead; dy=lgef(y)-3; dx=lgef(x)-3; dz=dx-dy; if (dz<0) return NULL; z=cgetg(dz+3,t_POL); x += 2; y += 2; z += 2; y_lead = (GEN)y[dy]; if (gcmp1(y_lead)) y_lead = NULL; p1 = (GEN)x[dx]; z[dz]=y_lead? ldivii(p1,y_lead): licopy(p1); for (i=dx-1; i>=dy; i--) { av=avma; p1=(GEN)x[i]; for (j=i-dy+1; j<=i && j<=dz; j++) p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j])); if (y_lead) { p1 = gdiv(p1,y_lead); if (typ(p1)!=t_INT) return NULL; } if (absi_cmp(p1, bound) > 0) return NULL; p1 = gerepileupto(av,p1); z[i-dy] = (long)p1; } av = avma; for (;; i--) { p1 = (GEN)x[i]; /* we always enter this loop at least once */ for (j=0; j<=i && j<=dz; j++) p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j])); if (!gcmp0(p1)) return NULL; avma = av; if (!i) break; } z -= 2; z[1]=evalsigne(1) | evallgef(dz+3) | evalvarn(vx); return z; } static int try_div(GEN x, GEN y, GEN *q) { if (resii((GEN)x[2], (GEN)y[2]) != gzero) { if (DEBUGLEVEL>6) fprintferr("."); return 0; } *q = polidivis(x,y,cmbf_modhalf); if (*q) return 1; if (DEBUGLEVEL>6) fprintferr("*"); return 0; } static int cmbf(long fxn, GEN psf, long dlim, long hint) { long newd,av,val2,val=0; /* assume failure */ GEN newf,newpsf,quo,cont; if (dlim <= 0 || fxn > cmbf_modfaxn) return 0; /* first, try deeper factors without considering the current one */ if (fxn < cmbf_modfaxn) { val = cmbf(fxn+1,psf,dlim,hint); if (val && psf) return val; } /* second, try including the current modular factor in the product */ newf = (GEN)cmbf_modfax[fxn]; if (!newf) return val; /* modular factor already used */ newd = lgef(newf)-3; if (newd > dlim) return val; av = avma; if (!(newd%hint)) { if (!psf) psf = cmbf_abslc; newpsf = centermod(gmul(psf,newf),cmbf_mod); /* try out the new combination */ if (try_div(cmbf_abslcxtarget, newpsf, &quo)) { /* found a factor */ cont = content(newpsf); if (signe(leading_term(newpsf)) < 0) cont = negi(cont); newpsf = gdiv(newpsf,cont); cmbf_fax[++cmbf_faxn] = (long)newpsf; /* store factor */ cmbf_modfax[fxn] = 0; /* remove used modular factor */ if (DEBUGLEVEL > 2) { fprintferr("\n"); msgtimer("to find factor %Z",newpsf); } /* fix up target */ cmbf_target = gdiv(quo,leading_term(newpsf)); cmbf_degree = lgef(cmbf_target)-3; cmbf_lc = (GEN)cmbf_target[cmbf_degree+2]; cmbf_abslc = absi(cmbf_lc); cmbf_abslcxtarget = gmul(cmbf_abslc,cmbf_target); return 1; } } /* degree too large, or no more modular factors? */ if (newd == dlim || fxn == cmbf_modfaxn) return val; /* include more factors */ val2 = cmbf(fxn+1,newpsf,dlim-newd,hint); if (val2) cmbf_modfax[fxn] = 0; /* remove used modular factor */ else avma = av; return val || val2; } static long min_deg(long jmax,ulong tabbit[]) { long j,k=1,j1=2; for (j=jmax; j>=0; j--) { for ( ; k<=15; k++) { if (tabbit[j]&j1) return ((jmax-j)<<4)+k; j1<<=1; } k=0; j1=1; } return (jmax<<4)+15; } static void dotab(long d,long jmax,ulong *tabkbit,ulong *tmp) { ulong rem,pro; long j,d1,d2; d1=d>>4; d2=d&15; rem=0; for (j=jmax-d1; j>=0; j--) { pro = tabkbit[j+d1]<>16; } for (j=jmax-d1; j>=0; j--) tabkbit[j] |= tmp[j]; } /* lift factorisation mod p to mod p^e = pev */ GEN hensel_lift_fact(GEN pol, GEN fact, GEN p, GEN pev, long e) { long ev,i, nf = lg(fact); GEN aprov = pol, res = cgetg(nf, t_VEC); for (i=nf-1; i; i--) { GEN ae,be,u,v,ae2,be2,s,t,pe,pe2,z,g; long ltop = avma; ae = (GEN)fact[i]; /* lead coeff(ae) = 1 */ be = Fp_poldivres(aprov,ae,p, NULL); g = (GEN)Fp_pol_extgcd(ae,be,p,&u,&v)[2]; /* deg g = 0 */ if (!gcmp1(g)) { g = mpinvmod(g, p); u = gmul(u, g); v = gmul(v, g); } for(pe=p,ev=1;;) { ev<<=1; pe2=(ev>=e)? pev: sqri(pe); g = gadd(aprov, gneg_i(gmul(ae,be))); g = Fp_pol_red(g, pe2); g = gdivexact(g, pe); z = Fp_pol_red(gmul(v,g), pe); t = Fp_poldivres(z,ae,pe, &s); t = gadd(gmul(u,g), gmul(t,be)); t = Fp_pol_red(t, pe); be2 = gadd(be, gmul(t,pe)); ae2 = gadd(ae, gmul(s,pe)); /* already reduced mod pe2 */ if (ev>=e) break; g = gadd(gun, gneg_i(gadd(gmul(u,ae2),gmul(v,be2)))); g = Fp_pol_red(g, pe2); g = gdivexact(g, pe); z = Fp_pol_red(gmul(v,g), pe); t = Fp_poldivres(z,ae,pe, &s); t = gadd(gmul(u,g), gmul(t,be)); t = Fp_pol_red(t, pe); u = gadd(u, gmul(t,pe)); v = gadd(v, gmul(s,pe)); pe=pe2; ae=ae2; be=be2; } ae = gerepileupto(ltop, ae2); aprov = Fp_poldivres(aprov,ae,pev, NULL); ltop = avma; res[i] = (long)ae; if (DEBUGLEVEL > 4) fprintferr("...lifting factor of degree %3ld. Time = %ld\n", lgef(ae)-3,timer2()); } return res; } long split_berlekamp(GEN Q, GEN *t, GEN pp, GEN pps2); /* assume degree(a) > 0, a(0) != 0, and a squarefree */ static GEN squff(GEN a, long klim, long hint) { GEN Q,prime,primes2,factorsmodp,p1,p2,y,g,z,w,pe,*tabd,*tabdnew; long av=avma,tetpil,va=varn(a),da=lgef(a)-3; long chosenp,p,nfacp,lbit,i,j,d,e,np,nmax,lgg,nf,nft; ulong *tabbit, *tabkbit, *tmp; byteptr pt=diffptr; const int NOMBDEP = 5; if (hint < 0) return decpol(a,klim); if (DEBUGLEVEL > 2) timer2(); lbit=(da>>4)+1; nmax=da+1; i=da>>1; if (!klim || klim>i) klim=i; tabdnew = (GEN*)new_chunk(nmax); tabbit = (ulong*)new_chunk(lbit); tabkbit = (ulong*)new_chunk(lbit); tmp = (ulong*)new_chunk(lbit); p = np = 0; prime = icopy(gun); while (np < NOMBDEP) { GEN minuspolx; p += *pt++; if (!*pt) err(primer1); if (!smodis((GEN)a[da+2],p)) continue; prime[2] = p; z = Fp_pol(a, prime); if (gcmp0(discsr(z))) continue; z = lift_intern(z); for (j=0; j>1)) { d++; w = Fp_pow_mod_pol(w, prime, z, prime); g = Fp_pol_gcd(z, gadd(w, minuspolx), prime); tabdnew[d]=g; lgg=lgef(g)-3; if (lgg>0) { z = Fp_poldivres(z, g, prime, NULL); e = lgef(z)-3; w = Fp_poldivres(w, z, prime, ONLY_REM); lgg /= d; nfacp += lgg; if (DEBUGLEVEL>5) fprintferr(" %3ld %s of degree %3ld\n", lgg, lgg==1?"factor": "factors",d); for (j=1; j<=lgg; j++) dotab(d,lbit-1,tabkbit,tmp); } } if (e>0) { if (DEBUGLEVEL>5) fprintferr(" %3ld factor of degree %3ld\n",1,e); tabdnew[e]=z; nfacp++; dotab(e,lbit-1,tabkbit,tmp); } if (np) for (j=0; j 4) fprintferr("...tried prime %3ld (%-3ld %s). Time = %ld\n", p,nfacp,nfacp==1?"factor": "factors",timer2()); if (min_deg(lbit-1,tabbit) > klim) { avma=av; y=cgetg(2,t_COL); y[1]=lcopy(a); return y; } if (nfacp 4) msgtimer("splitting mod p = %ld",chosenp); p1=gzero; for (i=2; i<=da+2; i++) p1=addii(p1,sqri((GEN)a[i])); p2=absi((GEN)a[da+2]); p1=addii(p2,addsi(1,racine(p1))); p1=mulii(p1,binome(stoi(da-1),klim)); p1=shifti(mulii(p2,p1),1); for (e=1,pe=gun; ; e++) { pe = mulis(pe,chosenp); if (cmpii(pe,p1) >= 0) break; } if (DEBUGLEVEL > 4) fprintferr("coeff bound: %Z\n",p1); cmbf_target = a; cmbf_degree = lgef(a)-3; cmbf_lc = (GEN)a[lgef(a)-1]; cmbf_abslc = absi(cmbf_lc); cmbf_abslcxtarget = gmul(cmbf_abslc,a); cmbf_mod = pe; cmbf_modhalf = shifti(pe,-1); cmbf_modfax = hensel_lift_fact(a,factorsmodp,prime,pe,e); cmbf_modfaxn = nf; cmbf_fax = cgetg(nf+2,t_COL); cmbf_faxn = 0; /* sorting factors decreasing by degree helps if klim is used * If not, can start with first arg of 2 instead of 1, saving some time. * Should be sending tabbit through for more efficiency ??? */ cmbf(1,NULL,klim,hint); /* The Call */ if (cmbf_degree) { if (signe(cmbf_lc)<0) cmbf_target = gneg_i(cmbf_target); cmbf_fax[++cmbf_faxn] = (long)cmbf_target; /* leftover factor */ } if (DEBUGLEVEL>6) fprintferr("\n"); tetpil=avma; y=cgetg(cmbf_faxn+1,t_COL); for (i=1; i<=cmbf_faxn; i++) y[i]=lcopy((GEN)cmbf_fax[i]); return gerepile(av,tetpil,y); } /* klim=0 habituellement, sauf si l'on ne veut chercher que les facteurs * de degre <= klim */ GEN factpol(GEN x, long klim, long hint) { GEN fa,p1,d,t,v,w, y = cgetg(3,t_MAT); long av=avma,av2,lx,vx,i,j,k,ex,nbfac,zval; if (typ(x)!=t_POL) err(notpoler,"factpol"); if (!signe(x)) err(zeropoler,"factpol"); ex = nbfac = 0; p1 = x+2; while (gcmp0((GEN)*p1)) p1++; zval = p1 - (x + 2); lx = lgef(x) - zval; vx = varn(x); if (zval) { x = cgetg(lx, t_POL); p1 -= 2; for (i=2; i 3) { fa[ex] = (long)squff(t,klim,hint); nbfac += lg(fa[ex])-1; } } END: av2=avma; v=cgetg(nbfac+1,t_COL); y[1]=(long)v; w=cgetg(nbfac+1,t_COL); y[2]=(long)w; if (zval) { v[1]=lpolx[vx]; w[1]=lstoi(zval); k=1; } else k=0; for (i=1; i<=ex; i++) for (j=1; j> tsh) #define typ2(x) (x & ((1<0) t[10]=1; else t[12]=1; break; case t_INTMOD: assign_or_fail((GEN)p2[1],p); assign_or_fail((GEN)p1[1],pol); t[11]=1; break; case t_PADIC: s = precp(p2) + valp(p2); if (s < pa) pa = s; assign_or_fail((GEN)p2[2],p); assign_or_fail((GEN)p1[1],pol); t[13]=1; break; default: return 0; } } break; case t_POLMOD: assign_or_fail((GEN)p1[1],pol); for (j=1; j<=2; j++) { GEN pbis = NULL, polbis = NULL; long pabis; switch(poltype((GEN)p1[j],&pbis,&polbis,&pabis)) { case t_INT: t[14]=1; break; case t_INTMOD: t[15]=1; break; case t_PADIC: t[16]=1; if (pabis>1; p2=cgetg(lx,t_COL); for(i=1; i 2) { if (DEBUGLEVEL>7) fprintferr("prod: remaining objects %ld\n",k-1); lx = k; k = 1; for (i=1; ity) { p1=x; x=y; y=p1; l=tx; tx=ty; ty=l; } if (is_matvec_t(ty)) { l=lg(y); z=cgetg(l,ty); for (i=1; i3) { tetpil=avma; p1=gerepile(av,tetpil,ggcd(p1,(GEN)y[2])); } z[2]=(long)p1; } return z; case t_POL: z=cgetg(3,t_POLMOD); copyifstack(x[1],z[1]); av=avma; p1=ggcd((GEN)x[1],(GEN)x[2]); if (lgef(p1)>3) { tetpil=avma; p1=gerepile(av,tetpil,ggcd(y,p1)); } z[2]=(long)p1; return z; case t_RFRAC: av=avma; p1=ggcd((GEN)x[1],(GEN)y[2]); tetpil=avma; if (!gcmp1(p1)) err(talker,"non invertible fraction in a gcd with POLMOD"); return gerepile(av,tetpil,ggcd((GEN)y[1],x)); case t_RFRACN: av=avma; p1=gred_rfrac(y); tetpil=avma; return gerepile(av,tetpil,ggcd(p1,x)); } break; case t_POL: switch(ty) { case t_POL: return srgcd(x,y); case t_SER: return gpuigs(polx[vx],min(valp(y),gval(x,vx))); case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(3,ty); z[1]=lgcd(x,(GEN)y[1]); z[2]=lcopy((GEN)y[2]); return z; } break; case t_SER: switch(ty) { case t_SER: return gpuigs(polx[vx],min(valp(x),valp(y))); case t_RFRAC: case t_RFRACN: return gpuigs(polx[vx],min(valp(x),gval(y,vx))); } break; case t_RFRAC: case t_RFRACN: z=cgetg(3,ty); if (!is_rfrac_t(ty)) err(talker,"forbidden gcd rational function with vector/matrix"); p1 = gdiv((GEN)y[2], ggcd((GEN)x[2], (GEN)y[2])); tetpil = avma; z[2] = lpile((long)z,tetpil,gmul(p1, (GEN)x[2])); z[1] = lgcd((GEN)x[1], (GEN)y[1]); return z; } err(talker,"gcd vector/matrix with a forbidden type"); return NULL; /* not reached */ } GEN glcm(GEN x, GEN y) { long av=avma,tx,ty=typ(y),i,l; GEN p1,p2,z; if (is_matvec_t(ty)) { l=lg(y); z=cgetg(l,ty); for (i=1; i1) err(warnmem,"polgcdnun"); gerepilemanysp(av,av1,gptr,2); } } } /* return 1 if coeff explosion is not possible */ static int issimplefield(GEN x) { long lx,i; switch(typ(x)) { case t_REAL: case t_INTMOD: case t_PADIC: case t_SER: return 1; case t_POL: lx=lgef(x); for (i=2; i1; i--) switch(typ(x[i])) { case t_INT: case t_FRAC: break; default: return 0; } return 1; } static int isinexactfield(GEN x) { long lx,i; switch(typ(x)) { case t_REAL: case t_PADIC: case t_SER: return 1; case t_POL: lx=lgef(x); for (i=2; i vy) { d=cgetg(3,t_RFRAC); d[1]=(long)polun[vx]; d[2]=lcopy(x); return d; } if (lgef(x)!=3) err(talker,"non-invertible polynomial in polinvmod"); x=(GEN)x[2]; vx=gvar(x); } tx=typ(x); if (tx==t_POL) { if (isinexactfield(x) || isinexactfield(y)) return polinvinexact(x,y); av=avma; d=subresext(x,y,&u,&v); if (gcmp0(d)) err(talker,"non-invertible polynomial in polinvmod"); if (typ(d)==t_POL && varn(d)==vx) { if (lgef(d)>3) err(talker,"non-invertible polynomial in polinvmod"); d=(GEN)d[2]; } av1=avma; return gerepile(av,av1,gdiv(u,d)); } if (!is_rfrac_t(tx)) err(typeer,"polinvmod"); av=avma; p1=gmul((GEN)x[1],polinvmod((GEN)x[2],y)); av1=avma; return gerepile(av,av1,gmod(p1,y)); } GEN gbezout(GEN x, GEN y, GEN *u, GEN *v) { long tx=typ(x),ty=typ(y); if (tx==t_INT && ty==t_INT) return bezout(x,y,u,v); if (!is_extscalar_t(tx) || !is_extscalar_t(ty)) err(typeer,"gbezout"); return bezoutpol(x,y,u,v); } GEN vecbezout(GEN x, GEN y) { GEN z=cgetg(4,t_VEC); z[3]=(long)gbezout(x,y,(GEN*)(z+1),(GEN*)(z+2)); return z; } GEN vecbezoutres(GEN x, GEN y) { GEN z=cgetg(4,t_VEC); z[3]=(long)subresext(x,y,(GEN*)(z+1),(GEN*)(z+2)); return z; } /*******************************************************************/ /* */ /* CONTENU ET PARTIE PRIMITIVE */ /* */ /*******************************************************************/ GEN content(GEN x) { long av,tetpil,lx,i,tx=typ(x); GEN p1,p2; if (is_scalar_t(tx)) return tx==t_POLMOD? content((GEN)x[2]): gcopy(x); av = avma; switch(tx) { case t_RFRAC: case t_RFRACN: p1=content((GEN)x[1]); p2=content((GEN)x[2]); tetpil=avma; return gerepile(av,tetpil,gdiv(p1,p2)); case t_VEC: case t_COL: case t_MAT: lx = lg(x); if (lx==1) return gun; p1=content((GEN)x[1]); for (i=2; i lx) { /* integer coeffs */ while (lx>lontyp[tx]) { lx--; p1=mppgcd(p1,(GEN)x[lx]); if (is_pm1(p1)) { avma=av; return gun; } } } else { while (lx>lontyp[tx]) { lx--; p1=ggcd(p1,(GEN)x[lx]); } if (isinexactreal(p1)) { avma=av; return gun; } } return av==avma? gcopy(p1): gerepileupto(av,p1); } /*******************************************************************/ /* */ /* SOUS RESULTANT */ /* */ /*******************************************************************/ GEN gdivexact(GEN x, GEN y) { long i,lx; GEN z; if (gcmp1(y)) return x; switch(typ(x)) { case t_INT: if (typ(y)==t_INT) return divii(x,y); if (!signe(x)) return gzero; break; case t_INTMOD: case t_POLMOD: return gmul(x,ginv(y)); case t_POL: switch(typ(y)) { case t_INTMOD: case t_POLMOD: return gmul(x,ginv(y)); case t_POL: if (varn(x)==varn(y)) return poldivres(x,y, ONLY_DIVIDES_EXACT); } lx = lgef(x); z = cgetg(lx,t_POL); for (i=2; i= dy, y non constant */ GEN pseudorem(GEN x, GEN y) { long av = avma, av2,lim, vx = varn(x),dx,dy,dz,i,lx, p; if (!signe(y)) err(talker,"euclidean division by zero (pseudorem)"); (void)new_chunk(2); dx=lgef(x)-3; x = revpol(x); dy=lgef(y)-3; y = revpol(y); dz=dx-dy; p = dz+1; av2 = avma; lim = stack_lim(av2,1); for (;;) { x[0] = lneg((GEN)x[0]); p--; for (i=1; i<=dy; i++) x[i] = ladd(gmul((GEN)y[0], (GEN)x[i]), gmul((GEN)x[0],(GEN)y[i])); for ( ; i<=dx; i++) x[i] = lmul((GEN)y[0], (GEN)x[i]); do { x++; dx--; } while (dx >= 0 && gcmp0((GEN)x[0])); if (dx < dy) break; if (low_stack(lim,stack_lim(av2,1))) { if(DEBUGMEM>1) err(warnmem,"pseudorem dx = %ld >= %ld",dx,dy); gerepilemanycoeffs(av2,x,dx+1); } } if (dx < 0) return zeropol(vx); lx = dx+3; x -= 2; x[0]=evaltyp(t_POL) | evallg(lx); x[1]=evalsigne(1) | evalvarn(vx) | evallgef(lx); x = revpol(x) - 2; return gerepileupto(av, gmul(x, gpowgs((GEN)y[0], p))); } /* Si sol != NULL: * met dans *sol le dernier polynome non nul de la polynomial remainder * sequence si elle a ete effectuee, 0 sinon */ GEN subresall(GEN u, GEN v, GEN *sol) { long degq,av,av2,lim,tetpil,dx,dy,du,dv,dr,signh; GEN g,h,r,p1,p2,p3,p4; if (sol) *sol=gzero; if ((r = init_resultant(u,v))) return r; if (isinexactfield(u) || isinexactfield(v)) return resultant2(u,v); dx=lgef(u); dy=lgef(v); signh=1; if (dx1) err(warnmem,"subresall, dr = %ld",dr); gerepilemany(av2,gptr,4); } } if (dv==4) { tetpil=avma; p2=gcopy((GEN)v[2]); } else { if (dv == 3) err(bugparier,"subres"); p1=gpuigs((GEN)v[2],dv-3); p2=gpuigs(h,dv-4); tetpil=avma; p2=gdiv(p1,p2); } if (p3) { p1=gpuigs(p3,dy-3); tetpil=avma; p2=gmul(p2,p1); } if (p4) { p1=gpuigs(p4,dx-3); tetpil=avma; p2=gmul(p2,p1); } if (signh<0) { tetpil=avma; p2=gneg(p2); } { GEN *gptr[2]; gptr[0]=&p2; if (sol) { *sol=gcopy(u); gptr[1]=sol; } gerepilemanysp(av,tetpil,gptr,sol?2:1); return p2; } } static GEN scalar_res(GEN x, GEN y, GEN *U, GEN *V) { long dx=lgef(x)-4; *V=gpuigs(y,dx); *U=gzero; return gmul(y,*V); } /* calcule U et V tel que Ux+By=resultant(x,y) */ GEN subresext(GEN x, GEN y, GEN *U, GEN *V) { long degq,av,tetpil,tx,ty,dx,dy,du,dv,dr,signh; GEN z,g,h,r,p1,p2,p3,p4,u,v,lpu,um1,uze, *gptr[2]; if (gcmp0(x) || gcmp0(y)) { *U = *V = gzero; return gzero; } tx=typ(x); ty=typ(y); if (is_scalar_t(tx) || is_scalar_t(ty)) { if (tx==t_POL) return scalar_res(x,y,U,V); if (ty==t_POL) return scalar_res(y,x,V,U); *U=ginv(x); *V=gzero; return gun; } if (tx!=t_POL || ty!=t_POL) err(typeer,"subresext"); if (varn(x)!=varn(y)) return (varn(x)= (b=a+a)) a=b; c=x; n-=a; while (a>1) { a>>=1; c=gdivexact(gsqr(c),y); if (n>=a) { c=gdivexact(gmul(c,x),y); n -= a; } } return c; } static GEN Lazard2(GEN F, GEN x, GEN y, long n) { if (n<=1) return F; x = Lazard(x,y,n-1); return gdivexact(gmul(x,F),y); } static GEN addshift(GEN x, GEN y) { long v = varn(x); if (!signe(x)) return y; x = addshiftw(x,y,1); setvarn(x,v); return x; } static GEN nextSousResultant(GEN P, GEN Q, GEN Z, GEN s) { GEN p0, q0, z0, H, A; long p, q, j, av, lim, v = varn(P); z0 = leading_term(Z); p = degree(P); p0 = leading_term(P); P = reductum(P); q = degree(Q); q0 = leading_term(Q); Q = reductum(Q); av = avma; lim = stack_lim(av,1); H = gneg(reductum(Z)); A = gmul((GEN)P[q+2],H); for (j = q+1; j < p; j++) { H = (degree(H) == q-1) ? addshift(reductum(H), gdivexact(gmul(gneg((GEN)H[q+1]),Q), q0)) : addshift(H, zeropol(v)); A = gadd(A,gmul((GEN)P[j+2],H)); if (low_stack(lim,stack_lim(av,1))) { GEN *gptr[2]; gptr[0]=&A; gptr[1]=&H; if(DEBUGMEM>1) err(warnmem,"nextSousResultant j = %ld/%ld",j,p); gerepilemany(av,gptr,2); } } P = normalizepol_i(P, q+2); A = gdivexact(gadd(A,gmul(z0,P)), p0); A = (degree(H) == q-1) ? gadd(gmul(q0,addshift(reductum(H),A)), gmul(gneg((GEN)H[q+1]),Q)) : gmul(q0, addshift(H,A)); return gdivexact(A, ((p-q)&1)? s: gneg(s)); } GEN resultantducos(GEN P, GEN Q) { long delta, av=avma, tetpil, lim = stack_lim(av,1); GEN Z, s; if ((Z = init_resultant(P,Q))) return Z; delta = degree(P) - degree(Q); if (delta < 0) { Z = ((degree(P)&1) && (degree(Q)&1)) ? gneg(Q) : Q; Q = P; P = Z; delta = -delta; } s = gun; if (degree(Q) > 0) { s = gpuigs(leading_term(Q),delta); Z = Q; Q = pseudorem(P, gneg(Q)); P = Z; while(degree(Q) > 0) { if (low_stack(lim,stack_lim(av,1))) { GEN *gptr[2]; gptr[0]=&P; gptr[1]=&Q; if(DEBUGMEM>1) err(warnmem,"resultantducos, deg Q = %ld",degree(Q)); gerepilemany(av,gptr,2); s = leading_term(P); } delta = degree(P) - degree(Q); Z = Lazard2(Q, leading_term(Q), s, delta); Q = nextSousResultant(P, Q, Z, s); P = Z; s = leading_term(P); } } if (!signe(Q)) { avma = av; return gzero; } s = Lazard(leading_term(Q), s, degree(P)); tetpil = avma; return gerepile(av,tetpil,gcopy(s)); } /*******************************************************************/ /* */ /* RESULTANT PAR MATRICE DE SYLVESTER */ /* */ /*******************************************************************/ GEN sylvestermatrix_i(GEN x, GEN y) { long d,dx,dy,i,j; GEN p1,p2; dx=lgef(x)-3; dy=lgef(y)-3; d=dx+dy; p1=cgetg(d+1,t_MAT); for (j=1; j<=dy; j++) { p2=cgetg(d+1,t_COL); p1[j]=(long)p2; for (i=1; i=vx) return gsubst(x,v,polx[0]); p1 = cgetg(3,t_POL); p1[1] = evalvarn(0)|evalsigne(signe(x))|evallgef(3); p1[2] = (long)x; return p1; } if (v) { *mx = 1; return gsubst(gsubst(x,0,polx[MAXVARN]),v,polx[0]); } } return x; } /* resultant of x and y with respect to variable v, or with respect to their * main variable if v < 0. */ GEN polresultant0(GEN x, GEN y, long v, long flag) { long av = avma, m = 0; if (v >= 0) { x = fix_pol(x,v, &m); y = fix_pol(y,v, &m); } switch(flag) { case 0: x=subresall(x,y,NULL); break; case 1: x=resultant2(x,y); break; case 2: x=resultantducos(x,y); break; default: err(flagerr,"polresultant"); } if (m) x = gsubst(x,MAXVARN,polx[0]); return gerepileupto(av,x); } /*******************************************************************/ /* */ /* P.G.C.D PAR L'ALGORITHME DU SOUS RESULTANT */ /* */ /*******************************************************************/ GEN srgcd(GEN x, GEN y) { long av,av1,tetpil,tx=typ(x),ty=typ(y),dx,dy,vx,lim; GEN d,g,h,p1,p2,u,v; if (!signe(y)) return gcopy(x); if (!signe(x)) return gcopy(y); if (is_scalar_t(tx) || is_scalar_t(ty)) return gun; if (tx!=t_POL || ty!=t_POL) err(typeer,"srgcd"); vx=varn(x); if (vx!=varn(y)) return gun; if (ismonome(x)) return gcdmonome(x,y); if (ismonome(y)) return gcdmonome(y,x); if (isrational(x) && isrational(y)) return modulargcd(x,y); av=avma; if (issimplefield(x) || issimplefield(y)) x = polgcdnun(x,y); else { dx=lgef(x); dy=lgef(y); if (dx 9) fprintferr("srgcd: dr = %ld\n", dr); du=lgef(u); dv=lgef(v); degq=du-dv; u=v; switch(degq) { case 0: v = gdiv(r,g); g = leading_term(u); break; case 1: v = gdiv(r,gmul(h,g)); h = g = leading_term(u); break; default: v = gdiv(r,gmul(gpuigs(h,degq),g)); g = leading_term(u); h = gdiv(gpuigs(g,degq), gpuigs(h,degq-1)); } if (low_stack(lim, stack_lim(av1,1))) { GEN *gptr[4]; gptr[0]=&u; gptr[1]=&v; gptr[2]=&g; gptr[3]=&h; if(DEBUGMEM>1) err(warnmem,"srgcd"); gerepilemany(av1,gptr,4); } } p1 = content(v); if (!gcmp1(p1)) v = gdiv(v,p1); x = gmul(d,v); } if (typ(x)!=t_POL) x = gmul(polun[vx],x); else { p1=leading_term(x); ty=typ(p1); if ((is_frac_t(ty) || is_intreal_t(ty)) && gsigne(p1)<0) x = gneg(x); } return gerepileupto(av,x); } GEN qf_disc(GEN x, GEN y, GEN z); GEN poldisc0(GEN x, long v) { long av,tx=typ(x),i; GEN z,p1,p2; switch(tx) { case t_POL: if (gcmp0(x)) return gzero; av = avma; i = 0; if (v >= 0 && v != varn(x)) x = fix_pol(x,v, &i); p1 = subres(x, derivpol(x)); p2 = leading_term(x); if (!gcmp1(p2)) p1 = gdiv(p1,p2); if ((lgef(x)-3) & 2) p1 = gneg(p1); if (i) p1 = gsubst(p1, MAXVARN, polx[0]); return gerepileupto(av,p1); case t_COMPLEX: return stoi(-4); case t_QUAD: case t_POLMOD: return poldisc0((GEN)x[1], v); case t_QFR: case t_QFI: av = avma; return gerepileuptoint(av, qf_disc(x,NULL,NULL)); case t_VEC: case t_COL: case t_MAT: i=lg(x); z=cgetg(i,tx); for (i--; i; i--) z[i]=(long)poldisc0((GEN)x[i], v); return z; } err(typeer,"discsr"); return NULL; /* not reached */ } GEN discsr(GEN x) { return poldisc0(x, -1); } GEN reduceddiscsmith(GEN pol) { long av=avma,tetpil,i,j,n; GEN polp,alpha,p1,m; if (typ(pol)!=t_POL) err(typeer,"reduceddiscsmith"); n=lgef(pol)-3; if (n<=0) err(constpoler,"reduceddiscsmith"); check_pol_int(pol); if (!gcmp1((GEN)pol[n+2])) err(talker,"non-monic polynomial in poldiscreduced"); polp = derivpol(pol); alpha = polx[varn(pol)]; m=cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { p1=cgetg(n+1,t_COL); m[j]=(long)p1; for (i=1; i<=n; i++) p1[i]=(long)truecoeff(polp,i-1); if (j 0 || degq&1) r=gneg_i(r); sl = gsigne((GEN) r[dr-1]); sr = b? gsigne(poleval(r,b)): sl; if (sr) { if (!s) s=sr; else if (sr!=s) { s= -s; r1--; } } sr = a? gsigne(poleval(r,a)): ((dr&1)? sl: -sl); if (sr) { if (!t) t=sr; else if (sr!=t) { t= -t; r1++; } } if (dr==3) { avma=av; return r1; } u=v; p1 = g; g = gabs(leading_term(u),DEFAULTPREC); switch(degq) { case 0: break; case 1: p1 = gmul(h,p1); h = g; break; default: p1 = gmul(gpuigs(h,degq),p1); h = gdiv(gpuigs(g,degq), gpuigs(h,degq-1)); } v = gdiv(r,p1); } } /*******************************************************************/ /* */ /* POLYNOME QUADRATIQUE ASSOCIE A UN DISCRIMINANT */ /* */ /*******************************************************************/ GEN quadpoly0(GEN x, long v) { long res,l,tetpil,i,sx, tx = typ(x); GEN y,p1; if (is_matvec_t(tx)) { l=lg(x); y=cgetg(l,tx); for (i=1; i1) err(funder2,"quadpoly"); l=avma; p1=shifti(x,-2); setsigne(p1,-signe(p1)); y[2] = (long) p1; if (!res) y[3] = zero; else { if (sx<0) { tetpil=avma; y[2] = lpile(l,tetpil,addsi(1,p1)); } y[3] = lnegi(gun); } return y; } GEN quadpoly(GEN x) { return quadpoly0(x,-1); } GEN quadgen(GEN x) { GEN y=cgetg(4,t_QUAD); y[1]=lquadpoly(x); y[2]=zero; y[3]=un; return y; } /*******************************************************************/ /* */ /* INVERSE MODULO GENERAL */ /* */ /*******************************************************************/ GEN ginvmod(GEN x, GEN y) { long tx=typ(x); switch(typ(y)) { case t_POL: if (tx==t_POL) return polinvmod(x,y); if (is_scalar_t(tx)) return ginv(x); break; case t_INT: if (tx==t_INT) return mpinvmod(x,y); if (tx==t_POL) return gzero; } err(typeer,"ginvmod"); return NULL; /* not reached */ } /***********************************************************************/ /** **/ /** NEWTON POLYGON **/ /** **/ /***********************************************************************/ /* assume leading coeff of x is non-zero */ GEN newtonpoly(GEN x, GEN p) { GEN y; long n,ind,a,b,c,u1,u2,r1,r2; long *vval, num[] = {evaltyp(t_INT) | m_evallg(3), 0, 0}; if (typ(x)!=t_POL) err(typeer,"newtonpoly"); n=lgef(x)-3; if (n<=0) { y=cgetg(1,t_VEC); return y; } y = cgetg(n+1,t_VEC); x += 2; /* now x[i] = term of degree i */ vval = (long *) gpmalloc(sizeof(long)*(n+1)); for (a=0; a<=n; a++) vval[a] = ggval((GEN)x[a],p); for (a=0, ind=1; a