Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2012 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"1617/* Not so fast arithmetic with polynomials over FpX */1819/*******************************************************************/20/* */21/* FpXX */22/* */23/*******************************************************************/24/*Polynomials whose coefficients are either polynomials or integers*/2526static ulong27to_FlxqX(GEN P, GEN Q, GEN T, GEN p, GEN *pt_P, GEN *pt_Q, GEN *pt_T)28{29ulong pp = uel(p,2);30long v = get_FpX_var(T);31*pt_P = ZXX_to_FlxX(P, pp, v);32if (pt_Q) *pt_Q = ZXX_to_FlxX(Q, pp, v);33*pt_T = ZXT_to_FlxT(T, pp);34return pp;35}3637static GEN38ZXX_copy(GEN a) { return gcopy(a); }3940GEN41FpXX_red(GEN z, GEN p)42{43GEN res;44long i, l = lg(z);45res = cgetg(l,t_POL); res[1] = z[1];46for (i=2; i<l; i++)47{48GEN zi = gel(z,i), c;49if (typ(zi)==t_INT)50c = modii(zi,p);51else52{53pari_sp av = avma;54c = FpX_red(zi,p);55switch(lg(c)) {56case 2: set_avma(av); c = gen_0; break;57case 3: c = gerepilecopy(av, gel(c,2)); break;58}59}60gel(res,i) = c;61}62return FpXX_renormalize(res,lg(res));63}64GEN65FpXX_add(GEN x, GEN y, GEN p)66{67long i,lz;68GEN z;69long lx=lg(x);70long ly=lg(y);71if (ly>lx) swapspec(x,y, lx,ly);72lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];73for (i=2; i<ly; i++) gel(z,i) = Fq_add(gel(x,i), gel(y,i), NULL, p);74for ( ; i<lx; i++) gel(z,i) = gcopy(gel(x,i));75return FpXX_renormalize(z, lz);76}77GEN78FpXX_sub(GEN x, GEN y, GEN p)79{80long i,lz;81GEN z;82long lx=lg(x);83long ly=lg(y);84if (ly <= lx)85{86lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];87for (i=2; i<ly; i++) gel(z,i) = Fq_sub(gel(x,i), gel(y,i), NULL, p);88for ( ; i<lx; i++) gel(z,i) = gcopy(gel(x,i));89}90else91{92lz = ly; z = cgetg(lz, t_POL); z[1]=x[1];93for (i=2; i<lx; i++) gel(z,i) = Fq_sub(gel(x,i), gel(y,i), NULL, p);94for ( ; i<ly; i++) gel(z,i) = Fq_neg(gel(y,i), NULL, p);95}96return FpXX_renormalize(z, lz);97}9899static GEN100FpXX_subspec(GEN x, GEN y, GEN p, long nx, long ny)101{102long i,lz;103GEN z;104if (ny <= nx)105{106lz = nx+2; z = cgetg(lz, t_POL);107for (i=0; i<ny; i++) gel(z,i+2) = Fq_sub(gel(x,i), gel(y,i), NULL, p);108for ( ; i<nx; i++) gel(z,i+2) = gcopy(gel(x,i));109}110else111{112lz = ny+2; z = cgetg(lz, t_POL);113for (i=0; i<nx; i++) gel(z,i+2) = Fq_sub(gel(x,i), gel(y,i), NULL, p);114for ( ; i<ny; i++) gel(z,i+2) = Fq_neg(gel(y,i), NULL, p);115}116z[1] = 0; return FpXX_renormalize(z, lz);117}118119GEN120FpXX_neg(GEN x, GEN p)121{122long i, lx = lg(x);123GEN y = cgetg(lx,t_POL);124y[1] = x[1];125for(i=2; i<lx; i++) gel(y,i) = Fq_neg(gel(x,i), NULL, p);126return FpXX_renormalize(y, lx);127}128129GEN130FpXX_Fp_mul(GEN P, GEN u, GEN p)131{132long i, lP;133GEN res = cgetg_copy(P, &lP); res[1] = P[1];134for(i=2; i<lP; i++)135{136GEN x = gel(P,i);137gel(res,i) = typ(x)==t_INT? Fp_mul(x,u,p): FpX_Fp_mul(x,u,p);138}139return FpXX_renormalize(res,lP);140}141142GEN143FpXX_mulu(GEN P, ulong u, GEN p)144{145long i, lP;146GEN res = cgetg_copy(P, &lP); res[1] = P[1];147for(i=2; i<lP; i++)148{149GEN x = gel(P,i);150gel(res,i) = typ(x)==t_INT? Fp_mulu(x,u,p): FpX_mulu(x,u,p);151}152return FpXX_renormalize(res,lP);153}154155GEN156FpXX_halve(GEN P, GEN p)157{158long i, lP;159GEN res = cgetg_copy(P, &lP); res[1] = P[1];160for(i=2; i<lP; i++)161{162GEN x = gel(P,i);163gel(res,i) = typ(x)==t_INT? Fp_halve(x,p): FpX_halve(x,p);164}165return FpXX_renormalize(res,lP);166}167168GEN169FpXX_deriv(GEN P, GEN p)170{171long i, l = lg(P)-1;172GEN res;173174if (l < 3) return pol_0(varn(P));175res = cgetg(l, t_POL);176res[1] = P[1];177for (i=2; i<l ; i++)178{179GEN x = gel(P,i+1);180gel(res,i) = typ(x)==t_INT? Fp_mulu(x,i-1,p): FpX_mulu(x,i-1,p);181}182return FpXX_renormalize(res, l);183}184185GEN186FpXX_integ(GEN P, GEN p)187{188long i, l = lg(P);189GEN res;190191if (l == 2) return pol_0(varn(P));192res = cgetg(l+1, t_POL);193res[1] = P[1];194gel(res,2) = gen_0;195for (i=3; i<=l ; i++)196{197GEN x = gel(P,i-1);198if (signe(x))199{200GEN i1 = Fp_inv(utoi(i-2), p);201gel(res,i) = typ(x)==t_INT? Fp_mul(x,i1,p): FpX_Fp_mul(x,i1,p);202} else203gel(res,i) = gen_0;204}205return FpXX_renormalize(res, l+1);206}207208/*******************************************************************/209/* */210/* (Fp[X]/(Q))[Y] */211/* */212/*******************************************************************/213214static GEN215get_FpXQX_red(GEN T, GEN *B)216{217if (typ(T)!=t_VEC) { *B=NULL; return T; }218*B = gel(T,1); return gel(T,2);219}220221GEN222random_FpXQX(long d1, long v, GEN T, GEN p)223{224long dT = get_FpX_degree(T), vT = get_FpX_var(T);225long i, d = d1+2;226GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);227for (i=2; i<d; i++) gel(y,i) = random_FpX(dT, vT, p);228return FpXQX_renormalize(y,d);229}230231/*Not stack clean*/232GEN233Kronecker_to_FpXQX(GEN Z, GEN T, GEN p)234{235long i,j,lx,l, N = (get_FpX_degree(T)<<1) + 1;236GEN x, t = cgetg(N,t_POL), z = FpX_red(Z, p);237t[1] = evalvarn(get_FpX_var(T));238l = lg(z); lx = (l-2) / (N-2);239x = cgetg(lx+3,t_POL);240x[1] = z[1];241for (i=2; i<lx+2; i++)242{243for (j=2; j<N; j++) gel(t,j) = gel(z,j);244z += (N-2);245gel(x,i) = FpX_rem(FpX_renormalize(t,N), T,p);246}247N = (l-2) % (N-2) + 2;248for (j=2; j<N; j++) gel(t,j) = gel(z,j);249gel(x,i) = FpX_rem(FpX_renormalize(t,N), T,p);250return FpXQX_renormalize(x, i+1);251}252253GEN254FpXQX_red(GEN z, GEN T, GEN p)255{256long i, l = lg(z);257GEN res = cgetg(l,t_POL); res[1] = z[1];258for(i=2;i<l;i++)259if (typ(gel(z,i)) == t_INT)260gel(res,i) = modii(gel(z,i),p);261else262gel(res,i) = FpXQ_red(gel(z,i),T,p);263return FpXQX_renormalize(res,l);264}265266static GEN267to_intmod(GEN x, GEN p) { retmkintmod(modii(x, p), p); }268269GEN270FpXQX_to_mod(GEN z, GEN T, GEN p)271{272long i,l = lg(z);273GEN x = cgetg(l, t_POL);274x[1] = z[1];275if (l == 2) return x;276p = icopy(p);277T = FpX_to_mod_raw(T, p);278for (i=2; i<l; i++)279{280GEN zi = gel(z,i);281gel(x,i) = typ(zi) == t_POL? mkpolmod(FpX_to_mod_raw(zi, p), T)282: to_intmod(zi, p);283}284return normalizepol_lg(x,l);285}286287static GEN288FpXQX_to_mod_raw(GEN z, GEN T, GEN p)289{290long i,l = lg(z);291GEN x = cgetg(l, t_POL);292x[1] = z[1];293if (l == 2) return x;294for (i=2; i<l; i++)295{296GEN zi = gel(z,i);297gel(x,i) = typ(zi) == t_POL? mkpolmod(FpX_to_mod_raw(zi, p), T)298: to_intmod(zi, p);299}300return normalizepol_lg(x,l);301}302303INLINE GEN304FqX_to_mod_raw(GEN f, GEN T, GEN p)305{ return T?FpXQX_to_mod_raw(f, T, p): FpX_to_mod_raw(f, p); }306307static GEN308FqXC_to_mod_raw(GEN x, GEN T, GEN p)309{ pari_APPLY_type(t_COL, FqX_to_mod_raw(gel(x,i), T, p)) }310311GEN312FqXC_to_mod(GEN z, GEN T, GEN p)313{314GEN x;315long i,l = lg(z);316if (!T) return FpXC_to_mod(z, p);317x = cgetg(l, t_COL);318if (l == 1) return x;319p = icopy(p);320T = FpX_to_mod_raw(T, p);321for (i=1; i<l; i++)322gel(x,i) = FqX_to_mod_raw(gel(z, i), T, p);323return x;324}325326GEN327FqXM_to_mod(GEN z, GEN T, GEN p)328{329GEN x;330long i,l = lg(z);331if (!T) return FpXM_to_mod(z, p);332x = cgetg(l, t_MAT);333if (l == 1) return x;334p = icopy(p);335T = FpX_to_mod_raw(T, p);336for (i=1; i<l; i++)337gel(x,i) = FqXC_to_mod_raw(gel(z, i), T, p);338return x;339}340341static int342ZXX_is_ZX_spec(GEN a,long na)343{344long i;345for(i=0;i<na;i++)346if(typ(gel(a,i))!=t_INT) return 0;347return 1;348}349350static int351ZXX_is_ZX(GEN a) { return ZXX_is_ZX_spec(a+2,lgpol(a)); }352353static GEN354FpXX_FpX_mulspec(GEN P, GEN U, GEN p, long v, long lU)355{356long i, lP =lg(P);357GEN res;358res = cgetg(lP, t_POL); res[1] = P[1];359for(i=2; i<lP; i++)360{361GEN Pi = gel(P,i);362gel(res,i) = typ(Pi)==t_INT? FpX_Fp_mulspec(U, Pi, p, lU):363FpX_mulspec(U, Pi+2, p, lU, lgpol(Pi));364setvarn(gel(res,i),v);365}366return FpXQX_renormalize(res,lP);367}368369GEN370FpXX_FpX_mul(GEN P, GEN U, GEN p)371{ return FpXX_FpX_mulspec(P,U+2,p,varn(U),lgpol(U)); }372373static GEN374FpXY_FpY_mulspec(GEN x, GEN y, GEN T, GEN p, long lx, long ly)375{376pari_sp av = avma;377long v = fetch_var();378GEN z = RgXY_swapspec(x,get_FpX_degree(T)-1,v,lx);379z = FpXX_FpX_mulspec(z,y,p,v,ly);380z = RgXY_swapspec(z+2,lx+ly+3,get_FpX_var(T),lgpol(z));381(void)delete_var(); return gerepilecopy(av,z);382}383384static GEN385FpXQX_mulspec(GEN x, GEN y, GEN T, GEN p, long lx, long ly)386{387pari_sp av = avma;388GEN z, kx, ky;389long n;390if (ZXX_is_ZX_spec(y,ly))391{392if (ZXX_is_ZX_spec(x,lx))393return FpX_mulspec(x,y,p,lx,ly);394else395return FpXY_FpY_mulspec(x,y,T,p,lx,ly);396} else if (ZXX_is_ZX_spec(x,lx))397return FpXY_FpY_mulspec(y,x,T,p,ly,lx);398n = get_FpX_degree(T);399kx = RgXX_to_Kronecker_spec(x, lx, n);400ky = RgXX_to_Kronecker_spec(y, ly, n);401z = Kronecker_to_FpXQX(ZX_mul(ky,kx), T, p);402return gerepileupto(av, z);403}404405GEN406FpXQX_mul(GEN x, GEN y, GEN T, GEN p)407{408GEN z = FpXQX_mulspec(x+2,y+2,T,p,lgpol(x),lgpol(y));409setvarn(z,varn(x)); return z;410}411412GEN413FpXQX_sqr(GEN x, GEN T, GEN p)414{415pari_sp av = avma;416GEN z, kx;417if (ZXX_is_ZX(x)) return ZX_sqr(x);418kx= RgXX_to_Kronecker(x, get_FpX_degree(T));419z = Kronecker_to_FpXQX(ZX_sqr(kx), T, p);420return gerepileupto(av, z);421}422423GEN424FpXQX_FpXQ_mul(GEN P, GEN U, GEN T, GEN p)425{426long i, lP;427GEN res;428res = cgetg_copy(P, &lP); res[1] = P[1];429for(i=2; i<lP; i++)430gel(res,i) = typ(gel(P,i))==t_INT? FpX_Fp_mul(U, gel(P,i), p):431FpXQ_mul(U, gel(P,i), T,p);432return FpXQX_renormalize(res,lP);433}434435/* x and y in Z[Y][X]. Assume T irreducible mod p */436static GEN437FpXQX_divrem_basecase(GEN x, GEN y, GEN T, GEN p, GEN *pr)438{439long vx, dx, dy, dy1, dz, i, j, sx, lr;440pari_sp av0, av, tetpil;441GEN z,p1,rem,lead;442443if (!signe(y)) pari_err_INV("FpX_divrem",y);444vx=varn(x); dy=degpol(y); dx=degpol(x);445if (dx < dy)446{447if (pr)448{449av0 = avma; x = FpXQX_red(x, T, p);450if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }451if (pr == ONLY_REM) return x;452*pr = x;453}454return pol_0(vx);455}456lead = leading_coeff(y);457if (!dy) /* y is constant */458{459if (pr && pr != ONLY_DIVIDES)460{461if (pr == ONLY_REM) return pol_0(vx);462*pr = pol_0(vx);463}464if (gequal1(lead)) return FpXQX_red(x,T,p);465av0 = avma; x = FqX_Fq_mul(x, Fq_inv(lead, T,p), T,p);466return gerepileupto(av0,x);467}468av0 = avma; dz = dx-dy;469lead = gequal1(lead)? NULL: gclone(Fq_inv(lead,T,p));470set_avma(av0);471z = cgetg(dz+3,t_POL); z[1] = x[1];472x += 2; y += 2; z += 2;473for (dy1=dy-1; dy1>=0 && !signe(gel(y, dy1)); dy1--);474475p1 = gel(x,dx); av = avma;476gel(z,dz) = lead? gerepileupto(av, Fq_mul(p1,lead, T, p)): gcopy(p1);477for (i=dx-1; i>=dy; i--)478{479av=avma; p1=gel(x,i);480for (j=i-dy1; j<=i && j<=dz; j++)481p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j),NULL,p),NULL,p);482if (lead) p1 = Fq_mul(p1, lead, NULL,p);483tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,Fq_red(p1,T,p));484}485if (!pr) { guncloneNULL(lead); return z-2; }486487rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);488for (sx=0; ; i--)489{490p1 = gel(x,i);491for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)492p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j),NULL,p),NULL,p);493tetpil=avma; p1 = Fq_red(p1, T, p); if (signe(p1)) { sx = 1; break; }494if (!i) break;495set_avma(av);496}497if (pr == ONLY_DIVIDES)498{499guncloneNULL(lead);500if (sx) return gc_NULL(av0);501return gc_const((pari_sp)rem, z-2);502}503lr=i+3; rem -= lr;504rem[0] = evaltyp(t_POL) | evallg(lr);505rem[1] = z[-1];506p1 = gerepile((pari_sp)rem,tetpil,p1);507rem += 2; gel(rem,i) = p1;508for (i--; i>=0; i--)509{510av=avma; p1 = gel(x,i);511for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)512p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j), NULL,p), NULL,p);513tetpil=avma; gel(rem,i) = gerepile(av,tetpil, Fq_red(p1, T, p));514}515rem -= 2;516guncloneNULL(lead);517if (!sx) (void)FpXQX_renormalize(rem, lr);518if (pr == ONLY_REM) return gerepileupto(av0,rem);519*pr = rem; return z-2;520}521522static GEN523FpXQX_halfgcd_basecase(GEN a, GEN b, GEN T, GEN p)524{525pari_sp av=avma;526GEN u,u1,v,v1;527long vx = varn(a);528long n = lgpol(a)>>1;529u1 = v = pol_0(vx);530u = v1 = pol_1(vx);531while (lgpol(b)>n)532{533GEN r, q = FpXQX_divrem(a,b, T, p, &r);534a = b; b = r; swap(u,u1); swap(v,v1);535u1 = FpXX_sub(u1, FpXQX_mul(u, q, T, p), p);536v1 = FpXX_sub(v1, FpXQX_mul(v, q ,T, p), p);537if (gc_needed(av,2))538{539if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_halfgcd (d = %ld)",degpol(b));540gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);541}542}543return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));544}545static GEN546FpXQX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, GEN p)547{548return FpXX_add(FpXQX_mul(u, x, T, p),FpXQX_mul(v, y, T, p), p);549}550551static GEN552FpXQXM_FpXQX_mul2(GEN M, GEN x, GEN y, GEN T, GEN p)553{554GEN res = cgetg(3, t_COL);555gel(res, 1) = FpXQX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p);556gel(res, 2) = FpXQX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p);557return res;558}559560static GEN561FpXQXM_mul2(GEN A, GEN B, GEN T, GEN p)562{563GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);564GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);565GEN M1 = FpXQX_mul(FpXX_add(A11,A22, p), FpXX_add(B11,B22, p), T, p);566GEN M2 = FpXQX_mul(FpXX_add(A21,A22, p), B11, T, p);567GEN M3 = FpXQX_mul(A11, FpXX_sub(B12,B22, p), T, p);568GEN M4 = FpXQX_mul(A22, FpXX_sub(B21,B11, p), T, p);569GEN M5 = FpXQX_mul(FpXX_add(A11,A12, p), B22, T, p);570GEN M6 = FpXQX_mul(FpXX_sub(A21,A11, p), FpXX_add(B11,B12, p), T, p);571GEN M7 = FpXQX_mul(FpXX_sub(A12,A22, p), FpXX_add(B21,B22, p), T, p);572GEN T1 = FpXX_add(M1,M4, p), T2 = FpXX_sub(M7,M5, p);573GEN T3 = FpXX_sub(M1,M2, p), T4 = FpXX_add(M3,M6, p);574retmkmat2(mkcol2(FpXX_add(T1,T2, p), FpXX_add(M2,M4, p)),575mkcol2(FpXX_add(M3,M5, p), FpXX_add(T3,T4, p)));576}577/* Return [0,1;1,-q]*M */578static GEN579FpXQX_FpXQXM_qmul(GEN q, GEN M, GEN T, GEN p)580{581GEN u, v, res = cgetg(3, t_MAT);582u = FpXX_sub(gcoeff(M,1,1), FpXQX_mul(gcoeff(M,2,1), q, T, p), p);583gel(res,1) = mkcol2(gcoeff(M,2,1), u);584v = FpXX_sub(gcoeff(M,1,2), FpXQX_mul(gcoeff(M,2,2), q, T, p), p);585gel(res,2) = mkcol2(gcoeff(M,2,2), v);586return res;587}588589static GEN590matid2_FpXQXM(long v)591{592retmkmat2(mkcol2(pol_1(v),pol_0(v)),593mkcol2(pol_0(v),pol_1(v)));594}595596static GEN597FpXX_shift(GEN a, long n) { return RgX_shift_shallow(a, n); }598599static GEN600FpXQX_halfgcd_split(GEN x, GEN y, GEN T, GEN p)601{602pari_sp av=avma;603GEN R, S, V;604GEN y1, r, q;605long l = lgpol(x), n = l>>1, k;606if (lgpol(y)<=n) return matid2_FpXQXM(varn(x));607R = FpXQX_halfgcd(FpXX_shift(x,-n),FpXX_shift(y,-n), T, p);608V = FpXQXM_FpXQX_mul2(R,x,y, T, p); y1 = gel(V,2);609if (lgpol(y1)<=n) return gerepilecopy(av, R);610q = FpXQX_divrem(gel(V,1), y1, T, p, &r);611k = 2*n-degpol(y1);612S = FpXQX_halfgcd(FpXX_shift(y1,-k), FpXX_shift(r,-k), T, p);613return gerepileupto(av, FpXQXM_mul2(S,FpXQX_FpXQXM_qmul(q,R, T, p), T, p));614}615616/* Return M in GL_2(Fp[X]) such that:617if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')618*/619620static GEN621FpXQX_halfgcd_i(GEN x, GEN y, GEN T, GEN p)622{623if (lg(x)<=FpXQX_HALFGCD_LIMIT) return FpXQX_halfgcd_basecase(x, y, T, p);624return FpXQX_halfgcd_split(x, y, T, p);625}626627GEN628FpXQX_halfgcd(GEN x, GEN y, GEN T, GEN p)629{630pari_sp av = avma;631GEN M,q,r;632if (lgefint(p)==3)633{634ulong pp = to_FlxqX(x, y, T, p, &x, &y, &T);635M = FlxXM_to_ZXXM(FlxqX_halfgcd(x, y, T, pp));636}637else638{639if (!signe(x))640{641long v = varn(x);642retmkmat2(mkcol2(pol_0(v),pol_1(v)),643mkcol2(pol_1(v),pol_0(v)));644}645if (degpol(y)<degpol(x)) return FpXQX_halfgcd_i(x, y, T, p);646q = FpXQX_divrem(y, x, T, p, &r);647M = FpXQX_halfgcd_i(x, r, T, p);648gcoeff(M,1,1) = FpXX_sub(gcoeff(M,1,1), FpXQX_mul(q, gcoeff(M,1,2), T, p), p);649gcoeff(M,2,1) = FpXX_sub(gcoeff(M,2,1), FpXQX_mul(q, gcoeff(M,2,2), T, p), p);650}651return gerepilecopy(av, M);652}653654static GEN655FpXQX_gcd_basecase(GEN a, GEN b, GEN T, GEN p)656{657pari_sp av = avma, av0=avma;658while (signe(b))659{660GEN c;661if (gc_needed(av0,2))662{663if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_gcd (d = %ld)",degpol(b));664gerepileall(av0,2, &a,&b);665}666av = avma; c = FpXQX_rem(a, b, T, p); a=b; b=c;667}668return gc_const(av, a);669}670671GEN672FpXQX_gcd(GEN x, GEN y, GEN T, GEN p)673{674pari_sp av = avma;675if (lgefint(p) == 3)676{677GEN Pl, Ql, Tl, U;678ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl);679U = FlxqX_gcd(Pl, Ql, Tl, pp);680return gerepileupto(av, FlxX_to_ZXX(U));681}682x = FpXQX_red(x, T, p);683y = FpXQX_red(y, T, p);684if (!signe(x)) return gerepileupto(av, y);685while (lg(y)>FpXQX_GCD_LIMIT)686{687GEN c;688if (lgpol(y)<=(lgpol(x)>>1))689{690GEN r = FpXQX_rem(x, y, T, p);691x = y; y = r;692}693c = FpXQXM_FpXQX_mul2(FpXQX_halfgcd(x,y, T, p), x, y, T, p);694x = gel(c,1); y = gel(c,2);695gerepileall(av,2,&x,&y);696}697return gerepileupto(av, FpXQX_gcd_basecase(x, y, T, p));698}699700static GEN701FpXQX_extgcd_basecase(GEN a, GEN b, GEN T, GEN p, GEN *ptu, GEN *ptv)702{703pari_sp av=avma;704GEN u,v,d,d1,v1;705long vx = varn(a);706d = a; d1 = b;707v = pol_0(vx); v1 = pol_1(vx);708while (signe(d1))709{710GEN r, q = FpXQX_divrem(d, d1, T, p, &r);711v = FpXX_sub(v,FpXQX_mul(q,v1,T, p),p);712u=v; v=v1; v1=u;713u=r; d=d1; d1=u;714if (gc_needed(av,2))715{716if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_extgcd (d = %ld)",degpol(d));717gerepileall(av,5, &d,&d1,&u,&v,&v1);718}719}720if (ptu) *ptu = FpXQX_div(FpXX_sub(d,FpXQX_mul(b,v, T, p), p), a, T, p);721*ptv = v; return d;722}723724static GEN725FpXQX_extgcd_halfgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)726{727pari_sp av=avma;728GEN u,v,R = matid2_FpXQXM(varn(x));729while (lg(y)>FpXQX_EXTGCD_LIMIT)730{731GEN M, c;732if (lgpol(y)<=(lgpol(x)>>1))733{734GEN r, q = FpXQX_divrem(x, y, T, p, &r);735x = y; y = r;736R = FpXQX_FpXQXM_qmul(q, R, T, p);737}738M = FpXQX_halfgcd(x,y, T, p);739c = FpXQXM_FpXQX_mul2(M, x,y, T, p);740R = FpXQXM_mul2(M, R, T, p);741x = gel(c,1); y = gel(c,2);742gerepileall(av,3,&x,&y,&R);743}744y = FpXQX_extgcd_basecase(x,y, T, p, &u,&v);745if (ptu) *ptu = FpXQX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T, p);746*ptv = FpXQX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T, p);747return y;748}749750/* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st751* ux + vy = gcd (mod T,p) */752GEN753FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)754{755GEN d;756pari_sp ltop=avma;757if (lgefint(p) == 3)758{759GEN Pl, Ql, Tl, Dl;760ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl);761Dl = FlxqX_extgcd(Pl, Ql, Tl, pp, ptu, ptv);762if (ptu) *ptu = FlxX_to_ZXX(*ptu);763*ptv = FlxX_to_ZXX(*ptv);764d = FlxX_to_ZXX(Dl);765}766else767{768x = FpXQX_red(x, T, p);769y = FpXQX_red(y, T, p);770if (lg(y)>FpXQX_EXTGCD_LIMIT)771d = FpXQX_extgcd_halfgcd(x, y, T, p, ptu, ptv);772else773d = FpXQX_extgcd_basecase(x, y, T, p, ptu, ptv);774}775gerepileall(ltop,ptu?3:2,&d,ptv,ptu);776return d;777}778779GEN780FpXQX_dotproduct(GEN x, GEN y, GEN T, GEN p)781{782long i, l = minss(lg(x), lg(y));783pari_sp av;784GEN c;785if (l == 2) return gen_0;786av = avma; c = gmul(gel(x,2),gel(y,2));787for (i=3; i<l; i++) c = gadd(c, gmul(gel(x,i),gel(y,i)));788return gerepileupto(av, Fq_red(c,T,p));789}790791/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/792GEN793FpXQX_resultant(GEN a, GEN b, GEN T, GEN p)794{795long da,db,dc;796pari_sp av;797long vT = get_FpX_var(T);798GEN c,lb, res = pol_1(vT);799800if (!signe(a) || !signe(b)) return pol_0(vT);801if (lgefint(p) == 3)802{803pari_sp av = avma;804GEN Pl, Ql, Tl, R;805ulong pp = to_FlxqX(a, b, T, p, &Pl, &Ql, &Tl);806R = FlxqX_resultant(Pl, Ql, Tl, pp);807return gerepileupto(av, Flx_to_ZX(R));808}809810da = degpol(a);811db = degpol(b);812if (db > da)813{814swapspec(a,b, da,db);815if (both_odd(da,db)) res = FpX_neg(res, p);816}817if (!da) return pol_1(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */818av = avma;819while (db)820{821lb = gel(b,db+2);822c = FpXQX_rem(a,b, T,p);823a = b; b = c; dc = degpol(c);824if (dc < 0) { set_avma(av); return pol_0(vT); }825826if (both_odd(da,db)) res = FpX_neg(res, p);827if (!equali1(lb)) res = FpXQ_mul(res, FpXQ_powu(lb, da - dc, T, p), T, p);828if (gc_needed(av,2))829{830if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_resultant (da = %ld)",da);831gerepileall(av,3, &a,&b,&res);832}833da = db; /* = degpol(a) */834db = dc; /* = degpol(b) */835}836res = FpXQ_mul(res, FpXQ_powu(gel(b,2), da, T, p), T, p);837return gerepileupto(av, res);838}839840/* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */841GEN842FpXQX_disc(GEN P, GEN T, GEN p)843{844pari_sp av = avma;845GEN L, dP = FpXX_deriv(P, p), D = FpXQX_resultant(P, dP, T, p);846long dd;847if (!signe(D)) return pol_0(get_FpX_var(T));848dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */849L = leading_coeff(P);850if (dd && !gequal1(L))851D = (dd == -1)? FpXQ_div(D,L,T,p): FpXQ_mul(D, FpXQ_powu(L, dd, T, p), T, p);852if (degpol(P) & 2) D = FpX_neg(D, p);853return gerepileupto(av, D);854}855856/***********************************************************************/857/** **/858/** Barrett reduction **/859/** **/860/***********************************************************************/861862/* Return new lgpol */863static long864ZXX_lgrenormalizespec(GEN x, long lx)865{866long i;867for (i = lx-1; i>=0; i--)868if (signe(gel(x,i))) break;869return i+1;870}871872static GEN873FpXQX_invBarrett_basecase(GEN S, GEN T, GEN p)874{875long i, l=lg(S)-1, lr = l-1, k;876GEN r=cgetg(lr, t_POL); r[1]=S[1];877gel(r,2) = gen_1;878for (i=3; i<lr; i++)879{880pari_sp av = avma;881GEN u = gel(S,l-i+2);882for (k=3; k<i; k++)883u = Fq_add(u, Fq_mul(gel(S,l-i+k), gel(r,k), NULL, p), NULL, p);884gel(r,i) = gerepileupto(av, Fq_red(Fq_neg(u, NULL, p), T, p));885}886return FpXQX_renormalize(r,lr);887}888889INLINE GEN890FpXX_recipspec(GEN x, long l, long n)891{892return RgX_recipspec_shallow(x, l, n);893}894895static GEN896FpXQX_invBarrett_Newton(GEN S, GEN T, GEN p)897{898pari_sp av = avma;899long nold, lx, lz, lq, l = degpol(S), i, lQ;900GEN q, y, z, x = cgetg(l+2, t_POL) + 2;901ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */902for (i=0;i<l;i++) gel(x,i) = gen_0;903q = RgX_recipspec_shallow(S+2,l+1,l+1); lQ = lgpol(q); q+=2;904/* We work on _spec_ FpX's, all the l[xzq] below are lgpol's */905906/* initialize */907gel(x,0) = Fq_inv(gel(q,0), T, p);908if (lQ>1) gel(q,1) = Fq_red(gel(q,1), T, p);909if (lQ>1 && signe(gel(q,1)))910{911GEN u = gel(q, 1);912if (!gequal1(gel(x,0))) u = Fq_mul(u, Fq_sqr(gel(x,0), T, p), T, p);913gel(x,1) = Fq_neg(u, T, p); lx = 2;914}915else916lx = 1;917nold = 1;918for (; mask > 1; )919{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */920long i, lnew, nnew = nold << 1;921922if (mask & 1) nnew--;923mask >>= 1;924925lnew = nnew + 1;926lq = ZXX_lgrenormalizespec(q, minss(lQ,lnew));927z = FpXQX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */928lz = lgpol(z); if (lz > lnew) lz = lnew;929z += 2;930/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */931for (i = nold; i < lz; i++) if (signe(gel(z,i))) break;932nold = nnew;933if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */934935/* z + i represents (x*q - 1) / t^i */936lz = ZXX_lgrenormalizespec (z+i, lz-i);937z = FpXQX_mulspec(x, z+i, T, p, lx, lz); /* FIXME: low product */938lz = lgpol(z); z += 2;939if (lz > lnew-i) lz = ZXX_lgrenormalizespec(z, lnew-i);940941lx = lz+ i;942y = x + i; /* x -= z * t^i, in place */943for (i = 0; i < lz; i++) gel(y,i) = Fq_neg(gel(z,i), T, p);944}945x -= 2; setlg(x, lx + 2); x[1] = S[1];946return gerepilecopy(av, x);947}948949GEN950FpXQX_invBarrett(GEN S, GEN T, GEN p)951{952pari_sp ltop = avma;953long l = lg(S);954GEN r;955if (l<5) return pol_0(varn(S));956if (l<=FpXQX_INVBARRETT_LIMIT)957{958GEN c = gel(S,l-1), ci=gen_1;959if (!gequal1(c))960{961ci = Fq_inv(c, T, p);962S = FqX_Fq_mul(S, ci, T, p);963r = FpXQX_invBarrett_basecase(S, T, p);964r = FqX_Fq_mul(r, ci, T, p);965} else966r = FpXQX_invBarrett_basecase(S, T, p);967}968else969r = FpXQX_invBarrett_Newton(S, T, p);970return gerepileupto(ltop, r);971}972973GEN974FpXQX_get_red(GEN S, GEN T, GEN p)975{976if (typ(S)==t_POL && lg(S)>FpXQX_BARRETT_LIMIT)977retmkvec2(FpXQX_invBarrett(S,T,p),S);978return S;979}980981/* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)982* and mg is the Barrett inverse of S. */983static GEN984FpXQX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN p, GEN *pr)985{986GEN q, r;987long lt = degpol(S); /*We discard the leading term*/988long ld, lm, lT, lmg;989ld = l-lt;990lm = minss(ld, lgpol(mg));991lT = ZXX_lgrenormalizespec(S+2,lt);992lmg = ZXX_lgrenormalizespec(mg+2,lm);993q = FpXX_recipspec(x+lt,ld,ld); /* q = rec(x) lq<=ld*/994q = FpXQX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/995q = FpXX_recipspec(q+2,minss(ld,lgpol(q)),ld); /* q = rec (rec(x) * mg) lq<=ld*/996if (!pr) return q;997r = FpXQX_mulspec(q+2,S+2,T,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/998r = FpXX_subspec(x,r+2,p,lt,minss(lt,lgpol(r))); /* r = x - r lr<=lt */999if (pr == ONLY_REM) return r;1000*pr = r; return q;1001}10021003static GEN1004FpXQX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, GEN p, GEN *pr)1005{1006GEN q = NULL, r = FpXQX_red(x, T, p);1007long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);1008long i;1009if (l <= lt)1010{1011if (pr == ONLY_REM) return r;1012if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);1013if (pr) *pr = r;1014return pol_0(v);1015}1016if (lt <= 1)1017return FpXQX_divrem_basecase(r,S,T,p,pr);1018if (pr != ONLY_REM && l>lm)1019{1020q = cgetg(l-lt+2, t_POL); q[1] = S[1];1021for (i=0;i<l-lt;i++) gel(q+2,i) = gen_0;1022}1023while (l>lm)1024{1025GEN zr, zq = FpXQX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr);1026long lz = lgpol(zr);1027if (pr != ONLY_REM)1028{1029long lq = lgpol(zq);1030for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);1031}1032for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);1033l = l-lm+lz;1034}1035if (pr == ONLY_REM)1036{1037if (l > lt)1038r = FpXQX_divrem_Barrettspec(r+2,l,mg,S,T,p,ONLY_REM);1039else1040r = FpXQX_renormalize(r, l+2);1041setvarn(r, v); return r;1042}1043if (l > lt)1044{1045GEN zq = FpXQX_divrem_Barrettspec(r+2,l,mg,S,T,p,pr ? &r: NULL);1046if (!q) q = zq;1047else1048{1049long lq = lgpol(zq);1050for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);1051}1052}1053else if (pr)1054r = FpX_renormalize(r, l+2);1055setvarn(q, v); q = FpXQX_renormalize(q, lg(q));1056if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;1057if (pr) { setvarn(r, v); *pr = r; }1058return q;1059}10601061GEN1062FpXQX_divrem(GEN x, GEN S, GEN T, GEN p, GEN *pr)1063{1064GEN B, y;1065long dy, dx, d;1066if (pr==ONLY_REM) return FpXQX_rem(x, S, T, p);1067y = get_FpXQX_red(S, &B);1068dy = degpol(y); dx = degpol(x); d = dx-dy;1069if (lgefint(p) == 3)1070{1071GEN a, b, t, z;1072pari_sp tetpil, av = avma;1073ulong pp = to_FlxqX(x, y, T, p, &a, &b, &t);1074z = FlxqX_divrem(a, b, t, pp, pr);1075if (pr == ONLY_DIVIDES && !z) return gc_NULL(av);1076tetpil=avma;1077z = FlxX_to_ZXX(z);1078if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)1079*pr = FlxX_to_ZXX(*pr);1080else return gerepile(av, tetpil, z);1081gerepileallsp(av,tetpil,2, pr, &z);1082return z;1083}1084if (!B && d+3 < FpXQX_DIVREM_BARRETT_LIMIT)1085return FpXQX_divrem_basecase(x,y,T,p,pr);1086else1087{1088pari_sp av=avma;1089GEN mg = B? B: FpXQX_invBarrett(y, T, p);1090GEN q = FpXQX_divrem_Barrett(x,mg,y,T,p,pr);1091if (!q) return gc_NULL(av);1092if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q);1093gerepileall(av,2,&q,pr);1094return q;1095}1096}10971098GEN1099FpXQX_rem(GEN x, GEN S, GEN T, GEN p)1100{1101GEN B, y = get_FpXQX_red(S, &B);1102long dy = degpol(y), dx = degpol(x), d = dx-dy;1103if (d < 0) return FpXQX_red(x, T, p);1104if (lgefint(p) == 3)1105{1106pari_sp av = avma;1107GEN a, b, t, z;1108ulong pp = to_FlxqX(x, y, T, p, &a, &b, &t);1109z = FlxqX_rem(a, b, t, pp);1110z = FlxX_to_ZXX(z);1111return gerepileupto(av, z);1112}1113if (!B && d+3 < FpXQX_REM_BARRETT_LIMIT)1114return FpXQX_divrem_basecase(x,y, T, p, ONLY_REM);1115else1116{1117pari_sp av=avma;1118GEN mg = B? B: FpXQX_invBarrett(y, T, p);1119GEN r = FpXQX_divrem_Barrett(x, mg, y, T, p, ONLY_REM);1120return gerepileupto(av, r);1121}1122}11231124/* x + y*z mod p */1125INLINE GEN1126Fq_addmul(GEN x, GEN y, GEN z, GEN T, GEN p)1127{1128pari_sp av;1129if (!signe(y) || !signe(z)) return Fq_red(x, T, p);1130if (!signe(x)) return Fq_mul(z,y, T, p);1131av = avma;1132return gerepileupto(av, Fq_add(x, Fq_mul(y, z, T, p), T, p));1133}11341135GEN1136FpXQX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *r)1137{1138long l = lg(a), i;1139GEN z;1140if (l <= 3)1141{1142if (r) *r = l == 2? gen_0: gcopy(gel(a,2));1143return pol_0(0);1144}1145l--; z = cgetg(l, t_POL); z[1] = evalsigne(1) | evalvarn(0);1146gel(z, l-1) = gel(a,l);1147for (i=l-2; i>1; i--) /* z[i] = a[i+1] + x*z[i+1] */1148gel(z, i) = Fq_addmul(gel(a,i+1), x, gel(z,i+1), T, p);1149if (r) *r = Fq_addmul(gel(a,2), x, gel(z,2), T, p);1150return z;1151}11521153struct _FpXQXQ {1154GEN T, S;1155GEN p;1156};11571158static GEN _FpXQX_mul(void *data, GEN a,GEN b)1159{1160struct _FpXQXQ *d=(struct _FpXQXQ*)data;1161return FpXQX_mul(a,b,d->T,d->p);1162}11631164static GEN _FpXQX_sqr(void *data, GEN a)1165{1166struct _FpXQXQ *d=(struct _FpXQXQ*)data;1167return FpXQX_sqr(a, d->T, d->p);1168}11691170GEN1171FpXQX_powu(GEN x, ulong n, GEN T, GEN p)1172{1173struct _FpXQXQ D;1174if (n==0) return pol_1(varn(x));1175D.T = T; D.p = p;1176return gen_powu(x, n, (void *)&D, _FpXQX_sqr, _FpXQX_mul);1177}11781179GEN1180FpXQXV_prod(GEN V, GEN T, GEN p)1181{1182if (lgefint(p) == 3)1183{1184pari_sp av = avma;1185ulong pp = p[2];1186GEN Tl = ZXT_to_FlxT(T, pp);1187GEN Vl = ZXXV_to_FlxXV(V, pp, get_FpX_var(T));1188Tl = FlxqXV_prod(Vl, Tl, pp);1189return gerepileupto(av, FlxX_to_ZXX(Tl));1190}1191else1192{1193struct _FpXQXQ d;1194d.T=T; d.p=p;1195return gen_product(V, (void*)&d, &_FpXQX_mul);1196}1197}11981199static GEN1200_FpXQX_divrem(void * E, GEN x, GEN y, GEN *r)1201{1202struct _FpXQXQ *d = (struct _FpXQXQ *) E;1203return FpXQX_divrem(x, y, d->T, d->p, r);1204}12051206static GEN1207_FpXQX_add(void * E, GEN x, GEN y)1208{1209struct _FpXQXQ *d = (struct _FpXQXQ *) E;1210return FpXX_add(x, y, d->p);1211}12121213static GEN1214_FpXQX_sub(void * E, GEN x, GEN y) {1215struct _FpXQXQ *d = (struct _FpXQXQ*) E;1216return FpXX_sub(x,y, d->p);1217}12181219static struct bb_ring FpXQX_ring = { _FpXQX_add, _FpXQX_mul, _FpXQX_sqr };12201221GEN1222FpXQX_digits(GEN x, GEN B, GEN T, GEN p)1223{1224pari_sp av = avma;1225long d = degpol(B), n = (lgpol(x)+d-1)/d;1226GEN z;1227struct _FpXQXQ D;1228D.T = T; D.p = p;1229z = gen_digits(x, B, n, (void *)&D, &FpXQX_ring, _FpXQX_divrem);1230return gerepileupto(av, z);1231}12321233GEN1234FpXQXV_FpXQX_fromdigits(GEN x, GEN B, GEN T, GEN p)1235{1236pari_sp av = avma;1237struct _FpXQXQ D;1238GEN z;1239D.T = T; D.p = p;1240z = gen_fromdigits(x,B,(void *)&D, &FpXQX_ring);1241return gerepileupto(av, z);1242}12431244/* Q an FpXY (t_POL with FpX coeffs), evaluate at X = x */1245GEN1246FpXY_evalx(GEN Q, GEN x, GEN p)1247{1248long i, lb = lg(Q);1249GEN z;1250z = cgetg(lb, t_POL); z[1] = Q[1];1251for (i=2; i<lb; i++)1252{1253GEN q = gel(Q,i);1254gel(z,i) = typ(q) == t_INT? modii(q,p): FpX_eval(q, x, p);1255}1256return FpX_renormalize(z, lb);1257}1258/* Q an FpXY, evaluate at Y = y */1259GEN1260FpXY_evaly(GEN Q, GEN y, GEN p, long vx)1261{1262pari_sp av = avma;1263long i, lb = lg(Q);1264GEN z;1265if (!signe(Q)) return pol_0(vx);1266if (lb == 3 || !signe(y)) {1267z = gel(Q, 2);1268return typ(z)==t_INT? scalar_ZX(z, vx): ZX_copy(z);1269}1270z = gel(Q, lb-1);1271if (typ(z) == t_INT) z = scalar_ZX_shallow(z, vx);1272for (i=lb-2; i>=2; i--) z = Fq_add(gel(Q,i), FpX_Fp_mul(z, y, p), NULL, p);1273return gerepileupto(av, z);1274}1275/* Q an FpXY, evaluate at (X,Y) = (x,y) */1276GEN1277FpXY_eval(GEN Q, GEN y, GEN x, GEN p)1278{1279pari_sp av = avma;1280return gerepileuptoint(av, FpX_eval(FpXY_evalx(Q, x, p), y, p));1281}12821283GEN1284FpXY_FpXQV_evalx(GEN P, GEN x, GEN T, GEN p)1285{1286long i, lP = lg(P);1287GEN res = cgetg(lP,t_POL);1288res[1] = P[1];1289for(i=2; i<lP; i++)1290gel(res,i) = typ(gel(P,i))==t_INT? icopy(gel(P,i)):1291FpX_FpXQV_eval(gel(P,i), x, T, p);1292return FlxX_renormalize(res, lP);1293}12941295GEN1296FpXY_FpXQ_evalx(GEN P, GEN x, GEN T, GEN p)1297{1298pari_sp av = avma;1299long n = brent_kung_optpow(get_FpX_degree(T)-1,lgpol(P),1);1300GEN xp = FpXQ_powers(x, n, T, p);1301return gerepileupto(av, FpXY_FpXQV_evalx(P, xp, T, p));1302}13031304/*******************************************************************/1305/* */1306/* (Fp[X]/T(X))[Y] / S(Y) */1307/* */1308/*******************************************************************/13091310/*Preliminary implementation to speed up FpX_ffisom*/1311typedef struct {1312GEN S, T, p;1313} FpXYQQ_muldata;13141315/* reduce x in Fp[X, Y] in the algebra Fp[X,Y]/ (S(X),T(Y)) */1316static GEN1317FpXYQQ_redswap(GEN x, GEN S, GEN T, GEN p)1318{1319pari_sp ltop=avma;1320long n = get_FpX_degree(S);1321long m = get_FpX_degree(T);1322long v = get_FpX_var(T);1323GEN V = RgXY_swap(x,m,v);1324V = FpXQX_red(V,S,p);1325V = RgXY_swap(V,n,v);1326return gerepilecopy(ltop,V);1327}1328static GEN1329FpXYQQ_sqr(void *data, GEN x)1330{1331FpXYQQ_muldata *D = (FpXYQQ_muldata*)data;1332return FpXYQQ_redswap(FpXQX_sqr(x, D->T, D->p),D->S,D->T,D->p);13331334}1335static GEN1336FpXYQQ_mul(void *data, GEN x, GEN y)1337{1338FpXYQQ_muldata *D = (FpXYQQ_muldata*)data;1339return FpXYQQ_redswap(FpXQX_mul(x,y, D->T, D->p),D->S,D->T,D->p);1340}13411342/* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */1343GEN1344FpXYQQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)1345{1346pari_sp av = avma;1347FpXYQQ_muldata D;1348GEN y;1349if (lgefint(p) == 3)1350{1351ulong pp = to_FlxqX(x, NULL, T, p, &x, NULL, &T);1352S = ZX_to_Flx(S, pp);1353y = FlxX_to_ZXX( FlxYqq_pow(x, n, S, T, pp) );1354y = gerepileupto(av, y);1355}1356else1357{1358D.S = S;1359D.T = T;1360D.p = p;1361y = gen_pow(x, n, (void*)&D, &FpXYQQ_sqr, &FpXYQQ_mul);1362}1363return y;1364}13651366GEN1367FpXQXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p) {1368return FpXQX_rem(FpXQX_mul(x, y, T, p), S, T, p);1369}13701371GEN1372FpXQXQ_sqr(GEN x, GEN S, GEN T, GEN p) {1373return FpXQX_rem(FpXQX_sqr(x, T, p), S, T, p);1374}13751376/* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist1377* return lift(1 / (x mod (p,pol))) */1378GEN1379FpXQXQ_invsafe(GEN x, GEN S, GEN T, GEN p)1380{1381GEN V, z = FpXQX_extgcd(get_FpXQX_mod(S), x, T, p, NULL, &V);1382if (degpol(z)) return NULL;1383z = gel(z,2);1384z = typ(z)==t_INT ? Fp_invsafe(z,p) : FpXQ_invsafe(z,T,p);1385if (!z) return NULL;1386return typ(z)==t_INT ? FpXX_Fp_mul(V, z, p): FpXQX_FpXQ_mul(V, z, T, p);1387}13881389GEN1390FpXQXQ_inv(GEN x, GEN S, GEN T,GEN p)1391{1392pari_sp av = avma;1393GEN U = FpXQXQ_invsafe(x, S, T, p);1394if (!U) pari_err_INV("FpXQXQ_inv",x);1395return gerepileupto(av, U);1396}13971398GEN1399FpXQXQ_div(GEN x,GEN y,GEN S, GEN T,GEN p)1400{1401pari_sp av = avma;1402return gerepileupto(av, FpXQXQ_mul(x, FpXQXQ_inv(y,S,T,p),S,T,p));1403}14041405static GEN1406_FpXQXQ_cmul(void *data, GEN P, long a, GEN x) {1407struct _FpXQXQ *d = (struct _FpXQXQ*) data;1408GEN y = gel(P,a+2);1409return typ(y)==t_INT ? FpXX_Fp_mul(x,y, d->p):1410FpXX_FpX_mul(x,y,d->p);1411}1412static GEN1413_FpXQXQ_red(void *data, GEN x) {1414struct _FpXQXQ *d = (struct _FpXQXQ*) data;1415return FpXQX_red(x, d->T, d->p);1416}1417static GEN1418_FpXQXQ_mul(void *data, GEN x, GEN y) {1419struct _FpXQXQ *d = (struct _FpXQXQ*) data;1420return FpXQXQ_mul(x,y, d->S,d->T, d->p);1421}1422static GEN1423_FpXQXQ_sqr(void *data, GEN x) {1424struct _FpXQXQ *d = (struct _FpXQXQ*) data;1425return FpXQXQ_sqr(x, d->S,d->T, d->p);1426}14271428static GEN1429_FpXQXQ_one(void *data) {1430struct _FpXQXQ *d = (struct _FpXQXQ*) data;1431return pol_1(get_FpXQX_var(d->S));1432}14331434static GEN1435_FpXQXQ_zero(void *data) {1436struct _FpXQXQ *d = (struct _FpXQXQ*) data;1437return pol_0(get_FpXQX_var(d->S));1438}14391440static struct bb_algebra FpXQXQ_algebra = { _FpXQXQ_red, _FpXQX_add,1441_FpXQX_sub, _FpXQXQ_mul, _FpXQXQ_sqr, _FpXQXQ_one, _FpXQXQ_zero };14421443const struct bb_algebra *1444get_FpXQXQ_algebra(void **E, GEN S, GEN T, GEN p)1445{1446GEN z = new_chunk(sizeof(struct _FpXQXQ));1447struct _FpXQXQ *e = (struct _FpXQXQ *) z;1448e->T = FpX_get_red(T, p);1449e->S = FpXQX_get_red(S, e->T, p);1450e->p = p; *E = (void*)e;1451return &FpXQXQ_algebra;1452}14531454static struct bb_algebra FpXQX_algebra = { _FpXQXQ_red, _FpXQX_add,1455_FpXQX_sub, _FpXQX_mul, _FpXQX_sqr, _FpXQXQ_one, _FpXQXQ_zero };14561457const struct bb_algebra *1458get_FpXQX_algebra(void **E, GEN T, GEN p, long v)1459{1460GEN z = new_chunk(sizeof(struct _FpXQXQ));1461struct _FpXQXQ *e = (struct _FpXQXQ *) z;1462e->T = FpX_get_red(T, p);1463e->S = pol_x(v);1464e->p = p; *E = (void*)e;1465return &FpXQX_algebra;1466}14671468/* x over Fq, return lift(x^n) mod S */1469GEN1470FpXQXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)1471{1472pari_sp ltop = avma;1473GEN y;1474struct _FpXQXQ D;1475long s = signe(n);1476if (!s) return pol_1(varn(x));1477if (is_pm1(n)) /* +/- 1 */1478return (s < 0)? FpXQXQ_inv(x,S,T,p): ZXX_copy(x);1479if (lgefint(p) == 3)1480{1481ulong pp = to_FlxqX(x, S, T, p, &x, &S, &T);1482GEN z = FlxqXQ_pow(x, n, S, T, pp);1483y = FlxX_to_ZXX(z);1484return gerepileupto(ltop, y);1485}1486else1487{1488T = FpX_get_red(T, p);1489S = FpXQX_get_red(S, T, p);1490D.S = S; D.T = T; D.p = p;1491if (s < 0) x = FpXQXQ_inv(x,S,T,p);1492y = gen_pow_i(x, n, (void*)&D,&_FpXQXQ_sqr,&_FpXQXQ_mul);1493return gerepilecopy(ltop, y);1494}1495}14961497/* generates the list of powers of x of degree 0,1,2,...,l*/1498GEN1499FpXQXQ_powers(GEN x, long l, GEN S, GEN T, GEN p)1500{1501struct _FpXQXQ D;1502int use_sqr = 2*degpol(x) >= get_FpXQX_degree(S);1503T = FpX_get_red(T, p);1504S = FpXQX_get_red(S, T, p);1505D.S = S; D.T = T; D.p = p;1506return gen_powers(x, l, use_sqr, (void*)&D, &_FpXQXQ_sqr, &_FpXQXQ_mul,&_FpXQXQ_one);1507}15081509/* Let v a linear form, return the linear form z->v(tau*z)1510that is, v*(M_tau) */15111512INLINE GEN1513FpXQX_recipspec(GEN x, long l, long n)1514{1515return RgX_recipspec_shallow(x, l, n);1516}15171518static GEN1519FpXQXQ_transmul_init(GEN tau, GEN S, GEN T, GEN p)1520{1521GEN bht;1522GEN h, Sp = get_FpXQX_red(S, &h);1523long n = degpol(Sp), vT = varn(Sp);1524GEN ft = FpXQX_recipspec(Sp+2, n+1, n+1);1525GEN bt = FpXQX_recipspec(tau+2, lgpol(tau), n);1526setvarn(ft, vT); setvarn(bt, vT);1527if (h)1528bht = FpXQXn_mul(bt, h, n-1, T, p);1529else1530{1531GEN bh = FpXQX_div(FpXX_shift(tau, n-1), S, T, p);1532bht = FpXQX_recipspec(bh+2, lgpol(bh), n-1);1533setvarn(bht, vT);1534}1535return mkvec3(bt, bht, ft);1536}15371538static GEN1539FpXQXQ_transmul(GEN tau, GEN a, long n, GEN T, GEN p)1540{1541pari_sp ltop = avma;1542GEN t1, t2, t3, vec;1543GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);1544if (signe(a)==0) return pol_0(varn(a));1545t2 = FpXX_shift(FpXQX_mul(bt, a, T, p),1-n);1546if (signe(bht)==0) return gerepilecopy(ltop, t2);1547t1 = FpXX_shift(FpXQX_mul(ft, a, T, p),-n);1548t3 = FpXQXn_mul(t1, bht, n-1, T, p);1549vec = FpXX_sub(t2, FpXX_shift(t3, 1), p);1550return gerepileupto(ltop, vec);1551}15521553static GEN1554polxn_FpXX(long n, long v, long vT)1555{1556long i, a = n+2;1557GEN p = cgetg(a+1, t_POL);1558p[1] = evalsigne(1)|evalvarn(v);1559for (i = 2; i < a; i++) gel(p,i) = pol_0(vT);1560gel(p,a) = pol_1(vT); return p;1561}15621563GEN1564FpXQXQ_minpoly(GEN x, GEN S, GEN T, GEN p)1565{1566pari_sp ltop = avma;1567long vS, vT, n;1568GEN v_x, g, tau;1569vS = get_FpXQX_var(S);1570vT = get_FpX_var(T);1571n = get_FpXQX_degree(S);1572g = pol_1(vS);1573tau = pol_1(vS);1574S = FpXQX_get_red(S, T, p);1575v_x = FpXQXQ_powers(x, usqrt(2*n), S, T, p);1576while(signe(tau) != 0)1577{1578long i, j, m, k1;1579GEN M, v, tr;1580GEN g_prime, c;1581if (degpol(g) == n) { tau = pol_1(vS); g = pol_1(vS); }1582v = random_FpXQX(n, vS, T, p);1583tr = FpXQXQ_transmul_init(tau, S, T, p);1584v = FpXQXQ_transmul(tr, v, n, T, p);1585m = 2*(n-degpol(g));1586k1 = usqrt(m);1587tr = FpXQXQ_transmul_init(gel(v_x,k1+1), S, T, p);1588c = cgetg(m+2,t_POL);1589c[1] = evalsigne(1)|evalvarn(vS);1590for (i=0; i<m; i+=k1)1591{1592long mj = minss(m-i, k1);1593for (j=0; j<mj; j++)1594gel(c,m+1-(i+j)) = FpXQX_dotproduct(v, gel(v_x,j+1), T, p);1595v = FpXQXQ_transmul(tr, v, n, T, p);1596}1597c = FpXX_renormalize(c, m+2);1598/* now c contains <v,x^i> , i = 0..m-1 */1599M = FpXQX_halfgcd(polxn_FpXX(m, vS, vT), c, T, p);1600g_prime = gmael(M, 2, 2);1601if (degpol(g_prime) < 1) continue;1602g = FpXQX_mul(g, g_prime, T, p);1603tau = FpXQXQ_mul(tau, FpXQX_FpXQXQV_eval(g_prime, v_x, S, T, p), S, T, p);1604}1605g = FpXQX_normalize(g,T, p);1606return gerepilecopy(ltop,g);1607}16081609GEN1610FpXQXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, GEN p)1611{1612return RgXV_to_RgM(FpXQXQ_powers(y,m-1,S,T,p),n);1613}16141615GEN1616FpXQX_FpXQXQV_eval(GEN P, GEN V, GEN S, GEN T, GEN p)1617{1618struct _FpXQXQ D;1619T = FpX_get_red(T, p);1620S = FpXQX_get_red(S, T, p);1621D.S=S; D.T=T; D.p=p;1622return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &FpXQXQ_algebra,1623_FpXQXQ_cmul);1624}16251626GEN1627FpXQX_FpXQXQ_eval(GEN Q, GEN x, GEN S, GEN T, GEN p)1628{1629struct _FpXQXQ D;1630int use_sqr = 2*degpol(x) >= get_FpXQX_degree(S);1631T = FpX_get_red(T, p);1632S = FpXQX_get_red(S, T, p);1633D.S=S; D.T=T; D.p=p;1634return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &FpXQXQ_algebra,1635_FpXQXQ_cmul);1636}16371638static GEN1639FpXQXQ_autpow_sqr(void * E, GEN x)1640{1641struct _FpXQXQ *D = (struct _FpXQXQ *)E;1642GEN S = D->S, T = D->T, p = D->p;1643GEN phi = gel(x,1), S1 = gel(x,2);1644long n = brent_kung_optpow(get_FpX_degree(T)-1,lgpol(S1)+1,1);1645GEN V = FpXQ_powers(phi, n, T, p);1646GEN phi2 = FpX_FpXQV_eval(phi, V, T, p);1647GEN Sphi = FpXY_FpXQV_evalx(S1, V, T, p);1648GEN S2 = FpXQX_FpXQXQ_eval(Sphi, S1, S, T, p);1649return mkvec2(phi2, S2);1650}16511652static GEN1653FpXQXQ_autpow_mul(void * E, GEN x, GEN y)1654{1655struct _FpXQXQ *D = (struct _FpXQXQ *)E;1656GEN S = D->S, T = D->T, p = D->p;1657GEN phi1 = gel(x,1), S1 = gel(x,2);1658GEN phi2 = gel(y,1), S2 = gel(y,2);1659long n = brent_kung_optpow(get_FpX_degree(T)-1, lgpol(S1)+1, 1);1660GEN V = FpXQ_powers(phi2, n, T, p);1661GEN phi3 = FpX_FpXQV_eval(phi1, V, T, p);1662GEN Sphi = FpXY_FpXQV_evalx(S1, V, T, p);1663GEN S3 = FpXQX_FpXQXQ_eval(Sphi, S2, S, T, p);1664return mkvec2(phi3, S3);1665}16661667GEN1668FpXQXQ_autpow(GEN aut, long n, GEN S, GEN T, GEN p)1669{1670pari_sp av = avma;1671struct _FpXQXQ D;1672T = FpX_get_red(T, p);1673S = FpXQX_get_red(S, T, p);1674D.S=S; D.T=T; D.p=p;1675aut = gen_powu_i(aut,n,&D,FpXQXQ_autpow_sqr,FpXQXQ_autpow_mul);1676return gerepilecopy(av, aut);1677}16781679static GEN1680FpXQXQ_auttrace_mul(void *E, GEN x, GEN y)1681{1682struct _FpXQXQ *D = (struct _FpXQXQ *)E;1683GEN S = D->S, T = D->T;1684GEN p = D->p;1685GEN S1 = gel(x,1), a1 = gel(x,2);1686GEN S2 = gel(y,1), a2 = gel(y,2);1687long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1);1688GEN V = FpXQXQ_powers(S2, n, S, T, p);1689GEN S3 = FpXQX_FpXQXQV_eval(S1, V, S, T, p);1690GEN aS = FpXQX_FpXQXQV_eval(a1, V, S, T, p);1691GEN a3 = FpXX_add(aS, a2, p);1692return mkvec2(S3, a3);1693}16941695static GEN1696FpXQXQ_auttrace_sqr(void *E, GEN x)1697{ return FpXQXQ_auttrace_mul(E, x, x); }16981699GEN1700FpXQXQ_auttrace(GEN aut, long n, GEN S, GEN T, GEN p)1701{1702pari_sp av = avma;1703struct _FpXQXQ D;1704T = FpX_get_red(T, p);1705S = FpXQX_get_red(S, T, p);1706D.S=S; D.T=T; D.p=p;1707aut = gen_powu_i(aut,n,&D,FpXQXQ_auttrace_sqr,FpXQXQ_auttrace_mul);1708return gerepilecopy(av, aut);1709}17101711static GEN1712FpXQXQ_autsum_mul(void *E, GEN x, GEN y)1713{1714struct _FpXQXQ *D = (struct _FpXQXQ *) E;1715GEN S = D->S, T = D->T, p = D->p;1716GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);1717GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);1718long n2 = brent_kung_optpow(get_FpX_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1);1719GEN V2 = FpXQ_powers(phi2, n2, T, p);1720GEN phi3 = FpX_FpXQV_eval(phi1, V2, T, p);1721GEN Sphi = FpXY_FpXQV_evalx(S1, V2, T, p);1722GEN aphi = FpXY_FpXQV_evalx(a1, V2, T, p);1723long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);1724GEN V = FpXQXQ_powers(S2, n, S, T, p);1725GEN S3 = FpXQX_FpXQXQV_eval(Sphi, V, S, T, p);1726GEN aS = FpXQX_FpXQXQV_eval(aphi, V, S, T, p);1727GEN a3 = FpXQXQ_mul(aS, a2, S, T, p);1728return mkvec3(phi3, S3, a3);1729}17301731static GEN1732FpXQXQ_autsum_sqr(void * T, GEN x)1733{ return FpXQXQ_autsum_mul(T,x,x); }17341735GEN1736FpXQXQ_autsum(GEN aut, long n, GEN S, GEN T, GEN p)1737{1738pari_sp av = avma;1739struct _FpXQXQ D;1740T = FpX_get_red(T, p);1741S = FpXQX_get_red(S, T, p);1742D.S=S; D.T=T; D.p=p;1743aut = gen_powu_i(aut,n,&D,FpXQXQ_autsum_sqr,FpXQXQ_autsum_mul);1744return gerepilecopy(av, aut);1745}17461747GEN1748FpXQXn_mul(GEN x, GEN y, long n, GEN T, GEN p)1749{1750pari_sp av = avma;1751GEN z, kx, ky;1752long d;1753if (ZXX_is_ZX(y) && ZXX_is_ZX(x))1754return FpXn_mul(x,y,n,p);1755d = get_FpX_degree(T);1756kx = RgXX_to_Kronecker(x, d);1757ky = RgXX_to_Kronecker(y, d);1758z = Kronecker_to_FpXQX(ZXn_mul(ky,kx,(2*d-1)*n), T, p);1759return gerepileupto(av, z);1760}17611762GEN1763FpXQXn_sqr(GEN x, long n, GEN T, GEN p)1764{1765pari_sp av = avma;1766GEN z, kx;1767long d;1768if (ZXX_is_ZX(x)) return ZXn_sqr(x, n);1769d = get_FpX_degree(T);1770kx= RgXX_to_Kronecker(x, d);1771z = Kronecker_to_FpXQX(ZXn_sqr(kx, (2*d-1)*n), T, p);1772return gerepileupto(av, z);1773}17741775INLINE GEN1776FpXXn_red(GEN a, long n)1777{ return RgXn_red_shallow(a, n); }17781779/* (f*g) \/ x^n */1780static GEN1781FpXQX_mulhigh_i(GEN f, GEN g, long n, GEN T, GEN p)1782{1783return FpXX_shift(FpXQX_mul(f,g,T, p),-n);1784}17851786static GEN1787FpXQXn_mulhigh(GEN f, GEN g, long n2, long n, GEN T, GEN p)1788{1789GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2);1790return FpXX_add(FpXQX_mulhigh_i(fl, g, n2, T, p), FpXQXn_mul(fh, g, n - n2, T, p), p);1791}17921793/* Compute intformal(x^n*S)/x^(n+1) */1794static GEN1795FpXX_integXn(GEN x, long n, GEN p)1796{1797long i, lx = lg(x);1798GEN y;1799if (lx == 2) return ZXX_copy(x);1800y = cgetg(lx, t_POL); y[1] = x[1];1801for (i=2; i<lx; i++)1802{1803ulong j = n+i-1;1804GEN xi = gel(x,i);1805if (!signe(xi))1806gel(y,i) = gen_0;1807else1808gel(y,i) = typ(xi)==t_INT ? Fp_divu(xi, j, p)1809: FpX_divu(xi, j, p);1810}1811return ZXX_renormalize(y, lx);;1812}18131814/* Compute intformal(x^n*S)/x^(n+1) */1815static GEN1816ZlXX_integXn(GEN x, long n, GEN p, ulong pp)1817{1818long i, lx = lg(x);1819GEN y;1820if (lx == 2) return ZXX_copy(x);1821if (!pp) return FpXX_integXn(x, n, p);1822y = cgetg(lx, t_POL); y[1] = x[1];1823for (i=2; i<lx; i++)1824{1825GEN xi = gel(x,i);1826if (!signe(xi))1827gel(y,i) = gen_0;1828else1829{1830ulong j;1831long v = u_lvalrem(n+i-1, pp, &j);1832if (typ(xi)==t_INT)1833{1834if (v==0)1835gel(y,i) = Fp_divu(xi, j, p);1836else1837gel(y,i) = Fp_divu(diviuexact(xi, upowuu(pp, v)), j, p);1838} else1839{1840if (v==0)1841gel(y,i) = FpX_divu(xi, j, p);1842else1843gel(y,i) = FpX_divu(ZX_divuexact(xi, upowuu(pp, v)), j, p);1844}1845}1846}1847return ZXX_renormalize(y, lx);;1848}18491850GEN1851ZlXQXn_expint(GEN h, long e, GEN T, GEN p, ulong pp)1852{1853pari_sp av = avma, av2;1854long v = varn(h), n=1;1855GEN f = pol_1(v), g = pol_1(v);1856ulong mask = quadratic_prec_mask(e);1857av2 = avma;1858for (;mask>1;)1859{1860GEN u, w;1861long n2 = n;1862n<<=1; if (mask & 1) n--;1863mask >>= 1;1864u = FpXQXn_mul(g, FpXQX_mulhigh_i(f, FpXXn_red(h, n2-1), n2-1, T, p), n-n2, T, p);1865u = FpXX_add(u, FpXX_shift(FpXXn_red(h, n-1), 1-n2), p);1866w = FpXQXn_mul(f, ZlXX_integXn(u, n2-1, p, pp), n-n2, T, p);1867f = FpXX_add(f, FpXX_shift(w, n2), p);1868if (mask<=1) break;1869u = FpXQXn_mul(g, FpXQXn_mulhigh(f, g, n2, n, T, p), n-n2, T, p);1870g = FpXX_sub(g, FpXX_shift(u, n2), p);1871if (gc_needed(av2,2))1872{1873if (DEBUGMEM>1) pari_warn(warnmem,"FpXQXn_exp, e = %ld", n);1874gerepileall(av2, 2, &f, &g);1875}1876}1877return gerepileupto(av, f);1878}18791880GEN1881FpXQXn_expint(GEN h, long e, GEN T, GEN p)1882{ return ZlXQXn_expint(h, e, T, p, 0); }18831884GEN1885FpXQXn_exp(GEN h, long e, GEN T, GEN p)1886{1887if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2)))1888pari_err_DOMAIN("FpXQXn_exp","valuation", "<", gen_1, h);1889return FpXQXn_expint(FpXX_deriv(h, p), e, T, p);1890}18911892GEN1893FpXQXn_inv(GEN f, long e, GEN T, GEN p)1894{1895pari_sp av = avma, av2;1896ulong mask;1897GEN W, a;1898long v = varn(f), n = 1;18991900if (!signe(f)) pari_err_INV("FpXXn_inv",f);1901a = Fq_inv(gel(f,2), T, p);1902if (e == 1) return scalarpol(a, v);1903else if (e == 2)1904{1905GEN b;1906if (degpol(f) <= 0) return scalarpol(a, v);1907b = Fq_neg(gel(f,3),T,p);1908if (signe(b)==0) return scalarpol(a, v);1909if (!is_pm1(a)) b = Fq_mul(b, Fq_sqr(a, T, p), T, p);1910W = deg1pol_shallow(b, a, v);1911return gerepilecopy(av, W);1912}1913W = scalarpol_shallow(Fq_inv(gel(f,2), T, p),v);1914mask = quadratic_prec_mask(e);1915av2 = avma;1916for (;mask>1;)1917{1918GEN u, fr;1919long n2 = n;1920n<<=1; if (mask & 1) n--;1921mask >>= 1;1922fr = FpXXn_red(f, n);1923u = FpXQXn_mul(W, FpXQXn_mulhigh(fr, W, n2, n, T, p), n-n2, T, p);1924W = FpXX_sub(W, FpXX_shift(u, n2), p);1925if (gc_needed(av2,2))1926{1927if(DEBUGMEM>1) pari_warn(warnmem,"FpXQXn_inv, e = %ld", n);1928W = gerepileupto(av2, W);1929}1930}1931return gerepileupto(av, W);1932}193319341935