Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2007 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 Fp */1819static GEN20get_FpX_red(GEN T, GEN *B)21{22if (typ(T)!=t_VEC) { *B=NULL; return T; }23*B = gel(T,1); return gel(T,2);24}2526/***********************************************************************/27/** **/28/** FpX **/29/** **/30/***********************************************************************/3132/* FpX are polynomials over Z/pZ represented as t_POL with33* t_INT coefficients.34* 1) Coefficients should belong to {0,...,p-1}, though nonreduced35* coefficients should work but be slower.36*37* 2) p is not assumed to be prime, but it is assumed that impossible divisions38* will not happen.39* 3) Theses functions let some garbage on the stack, but are gerepileupto40* compatible.41*/4243static ulong44to_Flx(GEN *P, GEN *Q, GEN p)45{46ulong pp = uel(p,2);47*P = ZX_to_Flx(*P, pp);48if(Q) *Q = ZX_to_Flx(*Q, pp);49return pp;50}5152static ulong53to_Flxq(GEN *P, GEN *T, GEN p)54{55ulong pp = uel(p,2);56if (P) *P = ZX_to_Flx(*P, pp);57*T = ZXT_to_FlxT(*T, pp); return pp;58}5960GEN61Z_to_FpX(GEN a, GEN p, long v)62{63pari_sp av = avma;64GEN z = cgetg(3, t_POL);65GEN x = modii(a, p);66if (!signe(x)) { set_avma(av); return pol_0(v); }67z[1] = evalsigne(1) | evalvarn(v);68gel(z,2) = x; return z;69}7071/* z in Z[X], return lift(z * Mod(1,p)), normalized*/72GEN73FpX_red(GEN z, GEN p)74{75long i, l = lg(z);76GEN x = cgetg(l, t_POL);77for (i=2; i<l; i++) gel(x,i) = modii(gel(z,i),p);78x[1] = z[1]; return FpX_renormalize(x,l);79}8081GEN82FpXV_red(GEN x, GEN p)83{ pari_APPLY_type(t_VEC, FpX_red(gel(x,i), p)) }8485GEN86FpXT_red(GEN x, GEN p)87{88if (typ(x) == t_POL)89return FpX_red(x, p);90else91pari_APPLY_type(t_VEC, FpXT_red(gel(x,i), p))92}9394GEN95FpX_normalize(GEN z, GEN p)96{97GEN p1 = leading_coeff(z);98if (lg(z) == 2 || equali1(p1)) return z;99return FpX_Fp_mul_to_monic(z, Fp_inv(p1,p), p);100}101102GEN103FpX_center(GEN T, GEN p, GEN pov2)104{105long i, l = lg(T);106GEN P = cgetg(l,t_POL);107for(i=2; i<l; i++) gel(P,i) = Fp_center(gel(T,i), p, pov2);108P[1] = T[1]; return P;109}110GEN111FpX_center_i(GEN T, GEN p, GEN pov2)112{113long i, l = lg(T);114GEN P = cgetg(l,t_POL);115for(i=2; i<l; i++) gel(P,i) = Fp_center_i(gel(T,i), p, pov2);116P[1] = T[1]; return P;117}118119GEN120FpX_add(GEN x,GEN y,GEN p)121{122long lx = lg(x), ly = lg(y), i;123GEN z;124if (lx < ly) swapspec(x,y, lx,ly);125z = cgetg(lx,t_POL); z[1] = x[1];126for (i=2; i<ly; i++) gel(z,i) = Fp_add(gel(x,i),gel(y,i), p);127for ( ; i<lx; i++) gel(z,i) = modii(gel(x,i), p);128z = ZX_renormalize(z, lx);129if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }130return z;131}132133static GEN134Fp_red_FpX(GEN x, GEN p, long v)135{136GEN z;137if (!signe(x)) return pol_0(v);138z = cgetg(3, t_POL);139gel(z,2) = Fp_red(x,p);140z[1] = evalvarn(v);141return FpX_renormalize(z, 3);142}143144static GEN145Fp_neg_FpX(GEN x, GEN p, long v)146{147GEN z;148if (!signe(x)) return pol_0(v);149z = cgetg(3, t_POL);150gel(z,2) = Fp_neg(x,p);151z[1] = evalvarn(v);152return FpX_renormalize(z, 3);153}154155GEN156FpX_Fp_add(GEN y,GEN x,GEN p)157{158long i, lz = lg(y);159GEN z;160if (lz == 2) return Fp_red_FpX(x,p,varn(y));161z = cgetg(lz,t_POL); z[1] = y[1];162gel(z,2) = Fp_add(gel(y,2),x, p);163if (lz == 3) z = FpX_renormalize(z,lz);164else165for(i=3;i<lz;i++) gel(z,i) = icopy(gel(y,i));166return z;167}168GEN169FpX_Fp_add_shallow(GEN y,GEN x,GEN p)170{171long i, lz = lg(y);172GEN z;173if (lz == 2) return scalar_ZX_shallow(x,varn(y));174z = cgetg(lz,t_POL); z[1] = y[1];175gel(z,2) = Fp_add(gel(y,2),x, p);176if (lz == 3) z = FpX_renormalize(z,lz);177else178for(i=3;i<lz;i++) gel(z,i) = gel(y,i);179return z;180}181GEN182FpX_Fp_sub(GEN y,GEN x,GEN p)183{184long i, lz = lg(y);185GEN z;186if (lz == 2) return Fp_neg_FpX(x,p,varn(y));187z = cgetg(lz,t_POL); z[1] = y[1];188gel(z,2) = Fp_sub(gel(y,2),x, p);189if (lz == 3) z = FpX_renormalize(z,lz);190else191for(i=3;i<lz;i++) gel(z,i) = icopy(gel(y,i));192return z;193}194GEN195FpX_Fp_sub_shallow(GEN y,GEN x,GEN p)196{197long i, lz = lg(y);198GEN z;199if (lz == 2) return Fp_neg_FpX(x,p,varn(y));200z = cgetg(lz,t_POL); z[1] = y[1];201gel(z,2) = Fp_sub(gel(y,2),x, p);202if (lz == 3) z = FpX_renormalize(z,lz);203else204for(i=3;i<lz;i++) gel(z,i) = gel(y,i);205return z;206}207208GEN209FpX_neg(GEN x,GEN p)210{211long i, lx = lg(x);212GEN y = cgetg(lx,t_POL);213y[1] = x[1];214for(i=2; i<lx; i++) gel(y,i) = Fp_neg(gel(x,i), p);215return ZX_renormalize(y, lx);216}217218static GEN219FpX_subspec(GEN x,GEN y,GEN p, long nx, long ny)220{221long i, lz;222GEN z;223if (nx >= ny)224{225lz = nx+2;226z = cgetg(lz,t_POL); z[1] = 0; z += 2;227for (i=0; i<ny; i++) gel(z,i) = Fp_sub(gel(x,i),gel(y,i), p);228for ( ; i<nx; i++) gel(z,i) = modii(gel(x,i), p);229}230else231{232lz = ny+2;233z = cgetg(lz,t_POL); z[1] = 0; z += 2;234for (i=0; i<nx; i++) gel(z,i) = Fp_sub(gel(x,i),gel(y,i), p);235for ( ; i<ny; i++) gel(z,i) = Fp_neg(gel(y,i), p);236}237z = FpX_renormalize(z-2, lz);238if (!lgpol(z)) { set_avma((pari_sp)(z + lz)); return pol_0(0); }239return z;240}241242GEN243FpX_sub(GEN x,GEN y,GEN p)244{245GEN z = FpX_subspec(x+2,y+2,p,lgpol(x),lgpol(y));246setvarn(z, varn(x));247return z;248}249250GEN251Fp_FpX_sub(GEN x, GEN y, GEN p)252{253long ly = lg(y), i;254GEN z;255if (ly <= 3) {256z = cgetg(3, t_POL);257x = (ly == 3)? Fp_sub(x, gel(y,2), p): modii(x, p);258if (!signe(x)) { set_avma((pari_sp)(z + 3)); return pol_0(varn(y)); }259z[1] = evalsigne(1)|y[1]; gel(z,2) = x; return z;260}261z = cgetg(ly,t_POL);262gel(z,2) = Fp_sub(x, gel(y,2), p);263for (i = 3; i < ly; i++) gel(z,i) = Fp_neg(gel(y,i), p);264z = ZX_renormalize(z, ly);265if (!lgpol(z)) { set_avma((pari_sp)(z + ly)); return pol_0(varn(x)); }266z[1] = y[1]; return z;267}268269GEN270FpX_convol(GEN x, GEN y, GEN p)271{272long lx = lg(x), ly = lg(y), i;273GEN z;274if (lx < ly) swapspec(x,y, lx,ly);275z = cgetg(lx,t_POL); z[1] = x[1];276for (i=2; i<ly; i++) gel(z,i) = Fp_mul(gel(x,i),gel(y,i), p);277for ( ; i<lx; i++) gel(z,i) = modii(gel(x,i), p);278z = ZX_renormalize(z, lx);279if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }280return z;281}282283GEN284FpX_mul(GEN x,GEN y,GEN p)285{286if (lgefint(p) == 3)287{288ulong pp = to_Flx(&x, &y, p);289return Flx_to_ZX(Flx_mul(x, y, pp));290}291return FpX_red(ZX_mul(x, y), p);292}293294GEN295FpX_mulspec(GEN a, GEN b, GEN p, long na, long nb)296{ return FpX_red(ZX_mulspec(a, b, na, nb), p); }297298GEN299FpX_sqr(GEN x,GEN p)300{301if (lgefint(p) == 3)302{303ulong pp = to_Flx(&x, NULL, p);304return Flx_to_ZX(Flx_sqr(x, pp));305}306return FpX_red(ZX_sqr(x), p);307}308309GEN310FpX_mulu(GEN y, ulong x,GEN p)311{312GEN z;313long i, l;314x = umodui(x, p);315if (!x) return zeropol(varn(y));316z = cgetg_copy(y, &l); z[1] = y[1];317for(i=2; i<l; i++) gel(z,i) = Fp_mulu(gel(y,i), x, p);318return z;319}320321GEN322FpX_divu(GEN y, ulong x, GEN p)323{324return FpX_Fp_div(y, utoi(umodui(x, p)), p);325}326327GEN328FpX_Fp_mulspec(GEN y,GEN x,GEN p,long ly)329{330GEN z;331long i;332if (!signe(x)) return pol_0(0);333z = cgetg(ly+2,t_POL); z[1] = evalsigne(1);334for(i=0; i<ly; i++) gel(z,i+2) = Fp_mul(gel(y,i), x, p);335return ZX_renormalize(z, ly+2);336}337338GEN339FpX_Fp_mul(GEN y,GEN x,GEN p)340{341GEN z = FpX_Fp_mulspec(y+2,x,p,lgpol(y));342setvarn(z, varn(y)); return z;343}344345GEN346FpX_Fp_div(GEN y, GEN x, GEN p)347{348return FpX_Fp_mul(y, Fp_inv(x, p), p);349}350351GEN352FpX_Fp_mul_to_monic(GEN y,GEN x,GEN p)353{354GEN z;355long i, l;356z = cgetg_copy(y, &l); z[1] = y[1];357for(i=2; i<l-1; i++) gel(z,i) = Fp_mul(gel(y,i), x, p);358gel(z,l-1) = gen_1; return z;359}360361struct _FpXQ {362GEN T, p, aut;363};364365struct _FpX366{367GEN p;368long v;369};370371static GEN372_FpX_mul(void* E, GEN x, GEN y)373{ struct _FpX *D = (struct _FpX *)E; return FpX_mul(x, y, D->p); }374static GEN375_FpX_sqr(void *E, GEN x)376{ struct _FpX *D = (struct _FpX *)E; return FpX_sqr(x, D->p); }377378GEN379FpX_powu(GEN x, ulong n, GEN p)380{381struct _FpX D;382if (n==0) return pol_1(varn(x));383D.p = p;384return gen_powu(x, n, (void *)&D, _FpX_sqr, _FpX_mul);385}386387GEN388FpXV_prod(GEN V, GEN p)389{390struct _FpX D;391D.p = p;392return gen_product(V, (void *)&D, &_FpX_mul);393}394395static GEN396_FpX_pow(void* E, GEN x, GEN y)397{ struct _FpX *D = (struct _FpX *)E; return FpX_powu(x, itou(y), D->p); }398static GEN399_FpX_one(void *E)400{ struct _FpX *D = (struct _FpX *)E; return pol_1(D->v); }401402GEN403FpXV_factorback(GEN f, GEN e, GEN p, long v)404{405struct _FpX D;406D.p = p; D.v = v;407return gen_factorback(f, e, (void *)&D, &_FpX_mul, &_FpX_pow, &_FpX_one);408}409410GEN411FpX_halve(GEN y, GEN p)412{413GEN z;414long i, l;415z = cgetg_copy(y, &l); z[1] = y[1];416for(i=2; i<l; i++) gel(z,i) = Fp_halve(gel(y,i), p);417return z;418}419420static GEN421FpX_divrem_basecase(GEN x, GEN y, GEN p, GEN *pr)422{423long vx, dx, dy, dy1, dz, i, j, sx, lr;424pari_sp av0, av;425GEN z,p1,rem,lead;426427if (!signe(y)) pari_err_INV("FpX_divrem",y);428vx = varn(x);429dy = degpol(y);430dx = degpol(x);431if (dx < dy)432{433if (pr)434{435av0 = avma; x = FpX_red(x, p);436if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }437if (pr == ONLY_REM) return x;438*pr = x;439}440return pol_0(vx);441}442lead = leading_coeff(y);443if (!dy) /* y is constant */444{445if (pr && pr != ONLY_DIVIDES)446{447if (pr == ONLY_REM) return pol_0(vx);448*pr = pol_0(vx);449}450av0 = avma;451if (equali1(lead)) return FpX_red(x, p);452else return gerepileupto(av0, FpX_Fp_div(x, lead, p));453}454av0 = avma; dz = dx-dy;455if (lgefint(p) == 3)456{ /* assume ab != 0 mod p */457ulong pp = to_Flx(&x, &y, p);458z = Flx_divrem(x, y, pp, pr);459set_avma(av0); /* HACK: assume pr last on stack, then z */460if (!z) return NULL;461z = leafcopy(z);462if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)463{464*pr = leafcopy(*pr);465*pr = Flx_to_ZX_inplace(*pr);466}467return Flx_to_ZX_inplace(z);468}469lead = equali1(lead)? NULL: gclone(Fp_inv(lead,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? gerepileuptoint(av, Fp_mul(p1,lead, p)): icopy(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 = subii(p1, mulii(gel(z,j),gel(y,i-j)));482if (lead) p1 = mulii(p1,lead);483gel(z,i-dy) = gerepileuptoint(av,modii(p1, 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 = subii(p1, mulii(gel(z,j),gel(y,i-j)));493p1 = modii(p1,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 = gerepileuptoint((pari_sp)rem, 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 = subii(p1, mulii(gel(z,j),gel(y,i-j)));513gel(rem,i) = gerepileuptoint(av, modii(p1,p));514}515rem -= 2;516guncloneNULL(lead);517if (!sx) (void)FpX_renormalize(rem, lr);518if (pr == ONLY_REM) return gerepileupto(av0,rem);519*pr = rem; return z-2;520}521522GEN523FpX_div_by_X_x(GEN a, GEN x, GEN p, GEN *r)524{525long l = lg(a), i;526GEN z;527if (l <= 3)528{529if (r) *r = l == 2? gen_0: icopy(gel(a,2));530return pol_0(0);531}532l--; z = cgetg(l, t_POL); z[1] = evalsigne(1) | evalvarn(0);533gel(z, l-1) = gel(a,l);534for (i = l-2; i > 1; i--) /* z[i] = a[i+1] + x*z[i+1] */535gel(z,i) = Fp_addmul(gel(a,i+1), x, gel(z,i+1), p);536if (r) *r = Fp_addmul(gel(a,2), x, gel(z,2), p);537return z;538}539540static GEN541_FpX_divrem(void * E, GEN x, GEN y, GEN *r)542{543struct _FpX *D = (struct _FpX*) E;544return FpX_divrem(x, y, D->p, r);545}546static GEN547_FpX_add(void * E, GEN x, GEN y) {548struct _FpX *D = (struct _FpX*) E;549return FpX_add(x, y, D->p);550}551552static struct bb_ring FpX_ring = { _FpX_add,_FpX_mul,_FpX_sqr };553554GEN555FpX_digits(GEN x, GEN T, GEN p)556{557pari_sp av = avma;558struct _FpX D;559long d = degpol(T), n = (lgpol(x)+d-1)/d;560GEN z;561D.p = p;562z = gen_digits(x,T,n,(void *)&D, &FpX_ring, _FpX_divrem);563return gerepileupto(av, z);564}565566GEN567FpXV_FpX_fromdigits(GEN x, GEN T, GEN p)568{569pari_sp av = avma;570struct _FpX D;571GEN z;572D.p = p;573z = gen_fromdigits(x,T,(void *)&D, &FpX_ring);574return gerepileupto(av, z);575}576577long578FpX_valrem(GEN x, GEN t, GEN p, GEN *py)579{580pari_sp av=avma;581long k;582GEN r, y;583584for (k=0; ; k++)585{586y = FpX_divrem(x, t, p, &r);587if (signe(r)) break;588x = y;589}590*py = gerepilecopy(av,x);591return k;592}593594static GEN595FpX_halfgcd_basecase(GEN a, GEN b, GEN p)596{597pari_sp av=avma;598GEN u,u1,v,v1;599long vx = varn(a);600long n = lgpol(a)>>1;601u1 = v = pol_0(vx);602u = v1 = pol_1(vx);603while (lgpol(b)>n)604{605GEN r, q = FpX_divrem(a,b,p, &r);606a = b; b = r; swap(u,u1); swap(v,v1);607u1 = FpX_sub(u1, FpX_mul(u, q, p), p);608v1 = FpX_sub(v1, FpX_mul(v, q ,p), p);609if (gc_needed(av,2))610{611if (DEBUGMEM>1) pari_warn(warnmem,"FpX_halfgcd (d = %ld)",degpol(b));612gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);613}614}615return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));616}617static GEN618FpX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN p)619{620return FpX_add(FpX_mul(u, x, p),FpX_mul(v, y, p), p);621}622623static GEN624FpXM_FpX_mul2(GEN M, GEN x, GEN y, GEN p)625{626GEN res = cgetg(3, t_COL);627gel(res, 1) = FpX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p);628gel(res, 2) = FpX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p);629return res;630}631632static GEN633FpXM_mul2(GEN A, GEN B, GEN p)634{635GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);636GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);637GEN M1 = FpX_mul(FpX_add(A11,A22, p), FpX_add(B11,B22, p), p);638GEN M2 = FpX_mul(FpX_add(A21,A22, p), B11, p);639GEN M3 = FpX_mul(A11, FpX_sub(B12,B22, p), p);640GEN M4 = FpX_mul(A22, FpX_sub(B21,B11, p), p);641GEN M5 = FpX_mul(FpX_add(A11,A12, p), B22, p);642GEN M6 = FpX_mul(FpX_sub(A21,A11, p), FpX_add(B11,B12, p), p);643GEN M7 = FpX_mul(FpX_sub(A12,A22, p), FpX_add(B21,B22, p), p);644GEN T1 = FpX_add(M1,M4, p), T2 = FpX_sub(M7,M5, p);645GEN T3 = FpX_sub(M1,M2, p), T4 = FpX_add(M3,M6, p);646retmkmat2(mkcol2(FpX_add(T1,T2, p), FpX_add(M2,M4, p)),647mkcol2(FpX_add(M3,M5, p), FpX_add(T3,T4, p)));648}649650/* Return [0,1;1,-q]*M */651static GEN652FpX_FpXM_qmul(GEN q, GEN M, GEN p)653{654GEN u, v, res = cgetg(3, t_MAT);655u = FpX_sub(gcoeff(M,1,1), FpX_mul(gcoeff(M,2,1), q, p), p);656gel(res,1) = mkcol2(gcoeff(M,2,1), u);657v = FpX_sub(gcoeff(M,1,2), FpX_mul(gcoeff(M,2,2), q, p), p);658gel(res,2) = mkcol2(gcoeff(M,2,2), v);659return res;660}661662static GEN663matid2_FpXM(long v)664{665retmkmat2(mkcol2(pol_1(v),pol_0(v)),666mkcol2(pol_0(v),pol_1(v)));667}668669static GEN670FpX_shift(GEN a, long n) { return RgX_shift_shallow(a, n); }671672static GEN673FpX_halfgcd_split(GEN x, GEN y, GEN p)674{675pari_sp av=avma;676GEN R, S, V;677GEN y1, r, q;678long l = lgpol(x), n = l>>1, k;679if (lgpol(y)<=n) return matid2_FpXM(varn(x));680R = FpX_halfgcd(FpX_shift(x,-n), FpX_shift(y,-n), p);681V = FpXM_FpX_mul2(R,x,y,p); y1 = gel(V,2);682if (lgpol(y1)<=n) return gerepilecopy(av, R);683q = FpX_divrem(gel(V,1), y1, p, &r);684k = 2*n-degpol(y1);685S = FpX_halfgcd(FpX_shift(y1,-k), FpX_shift(r,-k), p);686return gerepileupto(av, FpXM_mul2(S,FpX_FpXM_qmul(q,R,p),p));687}688689/* Return M in GL_2(Fp[X]) such that:690if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')691*/692693static GEN694FpX_halfgcd_i(GEN x, GEN y, GEN p)695{696if (lg(x)<=FpX_HALFGCD_LIMIT) return FpX_halfgcd_basecase(x,y,p);697return FpX_halfgcd_split(x,y,p);698}699700GEN701FpX_halfgcd(GEN x, GEN y, GEN p)702{703pari_sp av = avma;704GEN M,q,r;705if (lgefint(p)==3)706{707ulong pp = to_Flx(&x, &y, p);708M = FlxM_to_ZXM(Flx_halfgcd(x, y, pp));709}710else711{712if (!signe(x))713{714long v = varn(x);715retmkmat2(mkcol2(pol_0(v),pol_1(v)),716mkcol2(pol_1(v),pol_0(v)));717}718if (degpol(y)<degpol(x)) return FpX_halfgcd_i(x,y,p);719q = FpX_divrem(y,x,p,&r);720M = FpX_halfgcd_i(x,r,p);721gcoeff(M,1,1) = FpX_sub(gcoeff(M,1,1), FpX_mul(q, gcoeff(M,1,2), p), p);722gcoeff(M,2,1) = FpX_sub(gcoeff(M,2,1), FpX_mul(q, gcoeff(M,2,2), p), p);723}724return gerepilecopy(av, M);725}726727static GEN728FpX_gcd_basecase(GEN a, GEN b, GEN p)729{730pari_sp av = avma, av0=avma;731while (signe(b))732{733GEN c;734if (gc_needed(av0,2))735{736if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd (d = %ld)",degpol(b));737gerepileall(av0,2, &a,&b);738}739av = avma; c = FpX_rem(a,b,p); a=b; b=c;740}741return gc_const(av, a);742}743744GEN745FpX_gcd(GEN x, GEN y, GEN p)746{747pari_sp av = avma;748if (lgefint(p)==3)749{750ulong pp;751(void)new_chunk((lg(x) + lg(y)) << 2); /* scratch space */752pp = to_Flx(&x, &y, p);753x = Flx_gcd(x, y, pp);754set_avma(av); return Flx_to_ZX(x);755}756x = FpX_red(x, p);757y = FpX_red(y, p);758if (!signe(x)) return gerepileupto(av, y);759while (lg(y)>FpX_GCD_LIMIT)760{761GEN c;762if (lgpol(y)<=(lgpol(x)>>1))763{764GEN r = FpX_rem(x, y, p);765x = y; y = r;766}767c = FpXM_FpX_mul2(FpX_halfgcd(x,y, p), x, y, p);768x = gel(c,1); y = gel(c,2);769gerepileall(av,2,&x,&y);770}771return gerepileupto(av, FpX_gcd_basecase(x,y,p));772}773774/* Return NULL if gcd can be computed else return a factor of p */775GEN776FpX_gcd_check(GEN x, GEN y, GEN p)777{778pari_sp av = avma;779GEN a,b,c;780781a = FpX_red(x, p);782b = FpX_red(y, p);783while (signe(b))784{785GEN g;786if (!invmod(leading_coeff(b), p, &g)) return gerepileuptoint(av,g);787b = FpX_Fp_mul_to_monic(b, g, p);788c = FpX_rem(a, b, p); a = b; b = c;789if (gc_needed(av,1))790{791if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd_check (d = %ld)",degpol(b));792gerepileall(av,2,&a,&b);793}794}795return gc_NULL(av);796}797798static GEN799FpX_extgcd_basecase(GEN a, GEN b, GEN p, GEN *ptu, GEN *ptv)800{801pari_sp av=avma;802GEN u,v,d,d1,v1;803long vx = varn(a);804d = a; d1 = b;805v = pol_0(vx); v1 = pol_1(vx);806while (signe(d1))807{808GEN r, q = FpX_divrem(d,d1,p, &r);809v = FpX_sub(v,FpX_mul(q,v1,p),p);810u=v; v=v1; v1=u;811u=r; d=d1; d1=u;812if (gc_needed(av,2))813{814if (DEBUGMEM>1) pari_warn(warnmem,"FpX_extgcd (d = %ld)",degpol(d));815gerepileall(av,5, &d,&d1,&u,&v,&v1);816}817}818if (ptu) *ptu = FpX_div(FpX_sub(d,FpX_mul(b,v,p),p),a,p);819*ptv = v; return d;820}821822static GEN823FpX_extgcd_halfgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)824{825pari_sp av=avma;826GEN u,v,R = matid2_FpXM(varn(x));827while (lg(y)>FpX_EXTGCD_LIMIT)828{829GEN M, c;830if (lgpol(y)<=(lgpol(x)>>1))831{832GEN r, q = FpX_divrem(x, y, p, &r);833x = y; y = r;834R = FpX_FpXM_qmul(q, R, p);835}836M = FpX_halfgcd(x,y, p);837c = FpXM_FpX_mul2(M, x,y, p);838R = FpXM_mul2(M, R, p);839x = gel(c,1); y = gel(c,2);840gerepileall(av,3,&x,&y,&R);841}842y = FpX_extgcd_basecase(x,y,p,&u,&v);843if (ptu) *ptu = FpX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1),p);844*ptv = FpX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2),p);845return y;846}847848/* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st849* ux + vy = gcd (mod p) */850GEN851FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)852{853GEN d;854pari_sp ltop=avma;855if (lgefint(p)==3)856{857ulong pp = to_Flx(&x, &y, p);858d = Flx_extgcd(x,y, pp, ptu,ptv);859d = Flx_to_ZX(d);860if (ptu) *ptu=Flx_to_ZX(*ptu);861*ptv=Flx_to_ZX(*ptv);862}863else864{865x = FpX_red(x, p);866y = FpX_red(y, p);867if (lg(y)>FpX_EXTGCD_LIMIT)868d = FpX_extgcd_halfgcd(x, y, p, ptu, ptv);869else870d = FpX_extgcd_basecase(x, y, p, ptu, ptv);871}872gerepileall(ltop,ptu?3:2,&d,ptv,ptu);873return d;874}875876GEN877FpX_rescale(GEN P, GEN h, GEN p)878{879long i, l = lg(P);880GEN Q = cgetg(l,t_POL), hi = h;881gel(Q,l-1) = gel(P,l-1);882for (i=l-2; i>=2; i--)883{884gel(Q,i) = Fp_mul(gel(P,i), hi, p);885if (i == 2) break;886hi = Fp_mul(hi,h, p);887}888Q[1] = P[1]; return Q;889}890891GEN892FpX_deriv(GEN x, GEN p) { return FpX_red(ZX_deriv(x), p); }893894/* Compute intformal(x^n*S)/x^(n+1) */895static GEN896FpX_integXn(GEN x, long n, GEN p)897{898long i, lx = lg(x);899GEN y;900if (lx == 2) return ZX_copy(x);901y = cgetg(lx, t_POL); y[1] = x[1];902for (i=2; i<lx; i++)903{904GEN xi = gel(x,i);905if (!signe(xi))906gel(y,i) = gen_0;907else908{909ulong j = n+i-1;910ulong d = ugcd(j, umodiu(xi, j));911if (d==1)912gel(y,i) = Fp_divu(xi, j, p);913else914gel(y,i) = Fp_divu(diviuexact(xi, d), j/d, p);915}916}917return ZX_renormalize(y, lx);;918}919920GEN921FpX_integ(GEN x, GEN p)922{923long i, lx = lg(x);924GEN y;925if (lx == 2) return ZX_copy(x);926y = cgetg(lx+1, t_POL); y[1] = x[1];927gel(y,2) = gen_0;928for (i=3; i<=lx; i++)929gel(y,i) = signe(gel(x,i-1))? Fp_divu(gel(x,i-1), i-2, p): gen_0;930return ZX_renormalize(y, lx+1);;931}932933INLINE GEN934FpXn_recip(GEN P, long n)935{ return RgXn_recip_shallow(P, n); }936937GEN938FpX_Newton(GEN P, long n, GEN p)939{940pari_sp av = avma;941GEN dP = FpX_deriv(P, p);942GEN Q = FpXn_recip(FpX_div(FpX_shift(dP,n), P, p), n);943return gerepilecopy(av, Q);944}945946GEN947FpX_fromNewton(GEN P, GEN p)948{949pari_sp av = avma;950if (lgefint(p)==3)951{952ulong pp = p[2];953GEN Q = Flx_fromNewton(ZX_to_Flx(P, pp), pp);954return gerepileupto(av, Flx_to_ZX(Q));955} else956{957long n = itos(modii(constant_coeff(P), p))+1;958GEN z = FpX_neg(FpX_shift(P,-1),p);959GEN Q = FpXn_recip(FpXn_expint(z, n, p), n);960return gerepilecopy(av, Q);961}962}963964GEN965FpX_invLaplace(GEN x, GEN p)966{967pari_sp av = avma;968long i, d = degpol(x);969GEN t, y;970if (d <= 1) return gcopy(x);971t = Fp_inv(factorial_Fp(d, p), p);972y = cgetg(d+3, t_POL);973y[1] = x[1];974for (i=d; i>=2; i--)975{976gel(y,i+2) = Fp_mul(gel(x,i+2), t, p);977t = Fp_mulu(t, i, p);978}979gel(y,3) = gel(x,3);980gel(y,2) = gel(x,2);981return gerepilecopy(av, y);982}983984GEN985FpX_Laplace(GEN x, GEN p)986{987pari_sp av = avma;988long i, d = degpol(x);989GEN t = gen_1;990GEN y;991if (d <= 1) return gcopy(x);992y = cgetg(d+3, t_POL);993y[1] = x[1];994gel(y,2) = gel(x,2);995gel(y,3) = gel(x,3);996for (i=2; i<=d; i++)997{998t = Fp_mulu(t, i, p);999gel(y,i+2) = Fp_mul(gel(x,i+2), t, p);1000}1001return gerepilecopy(av, y);1002}10031004int1005FpX_is_squarefree(GEN f, GEN p)1006{1007pari_sp av = avma;1008GEN z = FpX_gcd(f,FpX_deriv(f,p),p);1009set_avma(av);1010return degpol(z)==0;1011}10121013GEN1014random_FpX(long d1, long v, GEN p)1015{1016long i, d = d1+2;1017GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);1018for (i=2; i<d; i++) gel(y,i) = randomi(p);1019return FpX_renormalize(y,d);1020}10211022GEN1023FpX_dotproduct(GEN x, GEN y, GEN p)1024{1025long i, l = minss(lg(x), lg(y));1026pari_sp av;1027GEN c;1028if (l == 2) return gen_0;1029av = avma; c = mulii(gel(x,2),gel(y,2));1030for (i=3; i<l; i++) c = addii(c, mulii(gel(x,i),gel(y,i)));1031return gerepileuptoint(av, modii(c,p));1032}10331034/* Evaluation in Fp1035* x a ZX and y an Fp, return x(y) mod p1036*1037* If p is very large (several longs) and x has small coefficients(<<p),1038* then Brent & Kung algorithm is faster. */1039GEN1040FpX_eval(GEN x,GEN y,GEN p)1041{1042pari_sp av;1043GEN p1,r,res;1044long j, i=lg(x)-1;1045if (i<=2 || !signe(y))1046return (i==1)? gen_0: modii(gel(x,2),p);1047res=cgeti(lgefint(p));1048av=avma; p1=gel(x,i);1049/* specific attention to sparse polynomials (see poleval)*/1050/*You've guessed it! It's a copy-paste(tm)*/1051for (i--; i>=2; i=j-1)1052{1053for (j=i; !signe(gel(x,j)); j--)1054if (j==2)1055{1056if (i!=j) y = Fp_powu(y,i-j+1,p);1057p1=mulii(p1,y);1058goto fppoleval;/*sorry break(2) no implemented*/1059}1060r = (i==j)? y: Fp_powu(y,i-j+1,p);1061p1 = Fp_addmul(gel(x,j), p1, r, p);1062if ((i & 7) == 0) { affii(p1, res); p1 = res; set_avma(av); }1063}1064fppoleval:1065modiiz(p1,p,res); return gc_const(av, res);1066}10671068/* Tz=Tx*Ty where Tx and Ty coprime1069* return lift(chinese(Mod(x*Mod(1,p),Tx*Mod(1,p)),Mod(y*Mod(1,p),Ty*Mod(1,p))))1070* if Tz is NULL it is computed1071* As we do not return it, and the caller will frequently need it,1072* it must compute it and pass it.1073*/1074GEN1075FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p)1076{1077pari_sp av = avma;1078GEN ax,p1;1079ax = FpX_mul(FpXQ_inv(Tx,Ty,p), Tx,p);1080p1 = FpX_mul(ax, FpX_sub(y,x,p),p);1081p1 = FpX_add(x,p1,p);1082if (!Tz) Tz=FpX_mul(Tx,Ty,p);1083p1 = FpX_rem(p1,Tz,p);1084return gerepileupto(av,p1);1085}10861087/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/1088GEN1089FpX_resultant(GEN a, GEN b, GEN p)1090{1091long da,db,dc;1092pari_sp av;1093GEN c,lb, res = gen_1;10941095if (!signe(a) || !signe(b)) return gen_0;1096if (lgefint(p) == 3)1097{1098pari_sp av = avma;1099ulong pp = to_Flx(&a, &b, p);1100long r = Flx_resultant(a, b, pp);1101set_avma(av);1102return utoi(r);1103}11041105da = degpol(a);1106db = degpol(b);1107if (db > da)1108{1109swapspec(a,b, da,db);1110if (both_odd(da,db)) res = subii(p, res);1111}1112if (!da) return gen_1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */1113av = avma;1114while (db)1115{1116lb = gel(b,db+2);1117c = FpX_rem(a,b, p);1118a = b; b = c; dc = degpol(c);1119if (dc < 0) return gc_const(av, gen_0);11201121if (both_odd(da,db)) res = subii(p, res);1122if (!equali1(lb)) res = Fp_mul(res, Fp_powu(lb, da - dc, p), p);1123if (gc_needed(av,2))1124{1125if (DEBUGMEM>1) pari_warn(warnmem,"FpX_resultant (da = %ld)",da);1126gerepileall(av,3, &a,&b,&res);1127}1128da = db; /* = degpol(a) */1129db = dc; /* = degpol(b) */1130}1131res = Fp_mul(res, Fp_powu(gel(b,2), da, p), p);1132return gerepileuptoint(av, res);1133}11341135/* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */1136GEN1137FpX_disc(GEN P, GEN p)1138{1139pari_sp av = avma;1140GEN L, dP = FpX_deriv(P,p), D = FpX_resultant(P, dP, p);1141long dd;1142if (!signe(D)) return gen_0;1143dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */1144L = leading_coeff(P);1145if (dd && !equali1(L))1146D = (dd == -1)? Fp_div(D,L,p): Fp_mul(D, Fp_powu(L, dd, p), p);1147if (degpol(P) & 2) D = Fp_neg(D ,p);1148return gerepileuptoint(av, D);1149}11501151GEN1152FpV_roots_to_pol(GEN V, GEN p, long v)1153{1154pari_sp ltop=avma;1155long i;1156GEN g=cgetg(lg(V),t_VEC);1157for(i=1;i<lg(V);i++)1158gel(g,i) = deg1pol_shallow(gen_1,modii(negi(gel(V,i)),p),v);1159return gerepileupto(ltop,FpXV_prod(g,p));1160}11611162/* invert all elements of x mod p using Montgomery's multi-inverse trick.1163* Not stack-clean. */1164GEN1165FpV_inv(GEN x, GEN p)1166{1167long i, lx = lg(x);1168GEN u, y = cgetg(lx, t_VEC);11691170gel(y,1) = gel(x,1);1171for (i=2; i<lx; i++) gel(y,i) = Fp_mul(gel(y,i-1), gel(x,i), p);11721173u = Fp_inv(gel(y,--i), p);1174for ( ; i > 1; i--)1175{1176gel(y,i) = Fp_mul(u, gel(y,i-1), p);1177u = Fp_mul(u, gel(x,i), p); /* u = 1 / (x[1] ... x[i-1]) */1178}1179gel(y,1) = u; return y;1180}1181GEN1182FqV_inv(GEN x, GEN T, GEN p)1183{1184long i, lx = lg(x);1185GEN u, y = cgetg(lx, t_VEC);11861187gel(y,1) = gel(x,1);1188for (i=2; i<lx; i++) gel(y,i) = Fq_mul(gel(y,i-1), gel(x,i), T,p);11891190u = Fq_inv(gel(y,--i), T,p);1191for ( ; i > 1; i--)1192{1193gel(y,i) = Fq_mul(u, gel(y,i-1), T,p);1194u = Fq_mul(u, gel(x,i), T,p); /* u = 1 / (x[1] ... x[i-1]) */1195}1196gel(y,1) = u; return y;1197}11981199/***********************************************************************/1200/** **/1201/** Barrett reduction **/1202/** **/1203/***********************************************************************/12041205static GEN1206FpX_invBarrett_basecase(GEN T, GEN p)1207{1208long i, l=lg(T)-1, lr = l-1, k;1209GEN r=cgetg(lr, t_POL); r[1]=T[1];1210gel(r,2) = gen_1;1211for (i=3; i<lr; i++)1212{1213pari_sp av = avma;1214GEN u = gel(T,l-i+2);1215for (k=3; k<i; k++)1216u = addii(u, mulii(gel(T,l-i+k), gel(r,k)));1217gel(r,i) = gerepileupto(av, modii(negi(u), p));1218}1219return FpX_renormalize(r,lr);1220}12211222/* Return new lgpol */1223static long1224ZX_lgrenormalizespec(GEN x, long lx)1225{1226long i;1227for (i = lx-1; i>=0; i--)1228if (signe(gel(x,i))) break;1229return i+1;1230}12311232INLINE GEN1233FpX_recipspec(GEN x, long l, long n)1234{1235return RgX_recipspec_shallow(x, l, n);1236}12371238static GEN1239FpX_invBarrett_Newton(GEN T, GEN p)1240{1241pari_sp av = avma;1242long nold, lx, lz, lq, l = degpol(T), i, lQ;1243GEN q, y, z, x = cgetg(l+2, t_POL) + 2;1244ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */1245for (i=0;i<l;i++) gel(x,i) = gen_0;1246q = FpX_recipspec(T+2,l+1,l+1); lQ = lgpol(q); q+=2;1247/* We work on _spec_ FpX's, all the l[xzq] below are lgpol's */12481249/* initialize */1250gel(x,0) = Fp_inv(gel(q,0), p);1251if (lQ>1) gel(q,1) = Fp_red(gel(q,1), p);1252if (lQ>1 && signe(gel(q,1)))1253{1254GEN u = gel(q, 1);1255if (!equali1(gel(x,0))) u = Fp_mul(u, Fp_sqr(gel(x,0), p), p);1256gel(x,1) = Fp_neg(u, p); lx = 2;1257}1258else1259lx = 1;1260nold = 1;1261for (; mask > 1; )1262{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */1263long i, lnew, nnew = nold << 1;12641265if (mask & 1) nnew--;1266mask >>= 1;12671268lnew = nnew + 1;1269lq = ZX_lgrenormalizespec(q, minss(lQ,lnew));1270z = FpX_mulspec(x, q, p, lx, lq); /* FIXME: high product */1271lz = lgpol(z); if (lz > lnew) lz = lnew;1272z += 2;1273/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */1274for (i = nold; i < lz; i++) if (signe(gel(z,i))) break;1275nold = nnew;1276if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */12771278/* z + i represents (x*q - 1) / t^i */1279lz = ZX_lgrenormalizespec (z+i, lz-i);1280z = FpX_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */1281lz = lgpol(z); z += 2;1282if (lz > lnew-i) lz = ZX_lgrenormalizespec(z, lnew-i);12831284lx = lz+ i;1285y = x + i; /* x -= z * t^i, in place */1286for (i = 0; i < lz; i++) gel(y,i) = Fp_neg(gel(z,i), p);1287}1288x -= 2; setlg(x, lx + 2); x[1] = T[1];1289return gerepilecopy(av, x);1290}12911292/* 1/polrecip(T)+O(x^(deg(T)-1)) */1293GEN1294FpX_invBarrett(GEN T, GEN p)1295{1296pari_sp ltop = avma;1297long l = lg(T);1298GEN r;1299if (l<5) return pol_0(varn(T));1300if (l<=FpX_INVBARRETT_LIMIT)1301{1302GEN c = gel(T,l-1), ci=gen_1;1303if (!equali1(c))1304{1305ci = Fp_inv(c, p);1306T = FpX_Fp_mul(T, ci, p);1307r = FpX_invBarrett_basecase(T, p);1308r = FpX_Fp_mul(r, ci, p);1309} else1310r = FpX_invBarrett_basecase(T, p);1311}1312else1313r = FpX_invBarrett_Newton(T, p);1314return gerepileupto(ltop, r);1315}13161317GEN1318FpX_get_red(GEN T, GEN p)1319{1320if (typ(T)==t_POL && lg(T)>FpX_BARRETT_LIMIT)1321retmkvec2(FpX_invBarrett(T,p),T);1322return T;1323}13241325/* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1)1326* and mg is the Barrett inverse of T. */1327static GEN1328FpX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, GEN p, GEN *pr)1329{1330GEN q, r;1331long lt = degpol(T); /*We discard the leading term*/1332long ld, lm, lT, lmg;1333ld = l-lt;1334lm = minss(ld, lgpol(mg));1335lT = ZX_lgrenormalizespec(T+2,lt);1336lmg = ZX_lgrenormalizespec(mg+2,lm);1337q = FpX_recipspec(x+lt,ld,ld); /* q = rec(x) lq<=ld*/1338q = FpX_mulspec(q+2,mg+2,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/1339q = FpX_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lq<=ld*/1340if (!pr) return q;1341r = FpX_mulspec(q+2,T+2,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/1342r = FpX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */1343if (pr == ONLY_REM) return r;1344*pr = r; return q;1345}13461347static GEN1348FpX_divrem_Barrett(GEN x, GEN mg, GEN T, GEN p, GEN *pr)1349{1350GEN q = NULL, r = FpX_red(x, p);1351long l = lgpol(r), lt = degpol(T), lm = 2*lt-1, v = varn(T);1352long i;1353if (l <= lt)1354{1355if (pr == ONLY_REM) return r;1356if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);1357if (pr) *pr = r;1358return pol_0(v);1359}1360if (lt <= 1)1361return FpX_divrem_basecase(r,T,p,pr);1362if (pr != ONLY_REM && l>lm)1363{1364q = cgetg(l-lt+2, t_POL); q[1] = T[1];1365for (i=0;i<l-lt;i++) gel(q+2,i) = gen_0;1366}1367while (l>lm)1368{1369GEN zr, zq = FpX_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr);1370long lz = lgpol(zr);1371if (pr != ONLY_REM)1372{1373long lq = lgpol(zq);1374for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);1375}1376for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);1377l = l-lm+lz;1378}1379if (pr == ONLY_REM)1380{1381if (l > lt)1382r = FpX_divrem_Barrettspec(r+2, l, mg, T, p, ONLY_REM);1383else1384r = FpX_renormalize(r, l+2);1385setvarn(r, v); return r;1386}1387if (l > lt)1388{1389GEN zq = FpX_divrem_Barrettspec(r+2,l,mg,T,p, pr? &r: NULL);1390if (!q) q = zq;1391else1392{1393long lq = lgpol(zq);1394for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);1395}1396}1397else if (pr)1398r = FpX_renormalize(r, l+2);1399setvarn(q, v); q = FpX_renormalize(q, lg(q));1400if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;1401if (pr) { setvarn(r, v); *pr = r; }1402return q;1403}14041405GEN1406FpX_divrem(GEN x, GEN T, GEN p, GEN *pr)1407{1408GEN B, y;1409long dy, dx, d;1410if (pr==ONLY_REM) return FpX_rem(x, T, p);1411y = get_FpX_red(T, &B);1412dy = degpol(y); dx = degpol(x); d = dx-dy;1413if (!B && d+3 < FpX_DIVREM_BARRETT_LIMIT)1414return FpX_divrem_basecase(x,y,p,pr);1415else if (lgefint(p)==3)1416{1417pari_sp av = avma;1418ulong pp = to_Flxq(&x, &T, p);1419GEN z = Flx_divrem(x, T, pp, pr);1420if (!z) return NULL;1421if (!pr || pr == ONLY_DIVIDES)1422return Flx_to_ZX_inplace(gerepileuptoleaf(av, z));1423z = Flx_to_ZX(z);1424*pr = Flx_to_ZX(*pr);1425gerepileall(av, 2, &z, pr);1426return z;1427} else1428{1429pari_sp av=avma;1430GEN mg = B? B: FpX_invBarrett(y, p);1431GEN q1 = FpX_divrem_Barrett(x,mg,y,p,pr);1432if (!q1) return gc_NULL(av);1433if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q1);1434gerepileall(av,2,&q1,pr);1435return q1;1436}1437}14381439GEN1440FpX_rem(GEN x, GEN T, GEN p)1441{1442GEN B, y = get_FpX_red(T, &B);1443long dy = degpol(y), dx = degpol(x), d = dx-dy;1444if (d < 0) return FpX_red(x,p);1445if (!B && d+3 < FpX_REM_BARRETT_LIMIT)1446return FpX_divrem_basecase(x,y,p,ONLY_REM);1447else if (lgefint(p)==3)1448{1449pari_sp av = avma;1450ulong pp = to_Flxq(&x, &T, p);1451return Flx_to_ZX_inplace(gerepileuptoleaf(av, Flx_rem(x, T, pp)));1452} else1453{1454pari_sp av = avma;1455GEN mg = B? B: FpX_invBarrett(y, p);1456return gerepileupto(av, FpX_divrem_Barrett(x, mg, y, p, ONLY_REM));1457}1458}14591460static GEN1461FpXV_producttree_dbl(GEN t, long n, GEN p)1462{1463long i, j, k, m = n==1 ? 1: expu(n-1)+1;1464GEN T = cgetg(m+1, t_VEC);1465gel(T,1) = t;1466for (i=2; i<=m; i++)1467{1468GEN u = gel(T, i-1);1469long n = lg(u)-1;1470GEN t = cgetg(((n+1)>>1)+1, t_VEC);1471for (j=1, k=1; k<n; j++, k+=2)1472gel(t, j) = FpX_mul(gel(u, k), gel(u, k+1), p);1473gel(T, i) = t;1474}1475return T;1476}14771478static GEN1479FpV_producttree(GEN xa, GEN s, GEN p, long vs)1480{1481long n = lg(xa)-1;1482long j, k, ls = lg(s);1483GEN t = cgetg(ls, t_VEC);1484for (j=1, k=1; j<ls; k+=s[j++])1485gel(t, j) = s[j] == 1 ?1486deg1pol_shallow(gen_1, Fp_neg(gel(xa,k), p), vs):1487deg2pol_shallow(gen_1,1488Fp_neg(Fp_add(gel(xa,k), gel(xa,k+1), p), p),1489Fp_mul(gel(xa,k), gel(xa,k+1), p), vs);1490return FpXV_producttree_dbl(t, n, p);1491}14921493static GEN1494FpX_FpXV_multirem_dbl_tree(GEN P, GEN T, GEN p)1495{1496long i,j,k;1497long m = lg(T)-1;1498GEN t;1499GEN Tp = cgetg(m+1, t_VEC);1500gel(Tp, m) = mkvec(P);1501for (i=m-1; i>=1; i--)1502{1503GEN u = gel(T, i);1504GEN v = gel(Tp, i+1);1505long n = lg(u)-1;1506t = cgetg(n+1, t_VEC);1507for (j=1, k=1; k<n; j++, k+=2)1508{1509gel(t, k) = FpX_rem(gel(v, j), gel(u, k), p);1510gel(t, k+1) = FpX_rem(gel(v, j), gel(u, k+1), p);1511}1512gel(Tp, i) = t;1513}1514return Tp;1515}15161517static GEN1518FpX_FpV_multieval_tree(GEN P, GEN xa, GEN T, GEN p)1519{1520pari_sp av = avma;1521long j,k;1522GEN Tp = FpX_FpXV_multirem_dbl_tree(P, T, p);1523GEN R = cgetg(lg(xa), t_VEC);1524GEN u = gel(T, 1);1525GEN v = gel(Tp, 1);1526long n = lg(u)-1;1527for (j=1, k=1; j<=n; j++)1528{1529long c, d = degpol(gel(u,j));1530for (c=1; c<=d; c++, k++)1531gel(R,k) = FpX_eval(gel(v, j), gel(xa,k), p);1532}1533return gerepileupto(av, R);1534}15351536static GEN1537FpVV_polint_tree(GEN T, GEN R, GEN s, GEN xa, GEN ya, GEN p, long vs)1538{1539pari_sp av = avma;1540long m = lg(T)-1;1541long i, j, k, ls = lg(s);1542GEN Tp = cgetg(m+1, t_VEC);1543GEN t = cgetg(ls, t_VEC);1544for (j=1, k=1; j<ls; k+=s[j++])1545if (s[j]==2)1546{1547GEN a = Fp_mul(gel(ya,k), gel(R,k), p);1548GEN b = Fp_mul(gel(ya,k+1), gel(R,k+1), p);1549gel(t, j) = deg1pol_shallow(Fp_add(a, b, p),1550Fp_neg(Fp_add(Fp_mul(gel(xa,k), b, p ),1551Fp_mul(gel(xa,k+1), a, p), p), p), vs);1552}1553else1554gel(t, j) = scalarpol(Fp_mul(gel(ya,k), gel(R,k), p), vs);1555gel(Tp, 1) = t;1556for (i=2; i<=m; i++)1557{1558GEN u = gel(T, i-1);1559GEN t = cgetg(lg(gel(T,i)), t_VEC);1560GEN v = gel(Tp, i-1);1561long n = lg(v)-1;1562for (j=1, k=1; k<n; j++, k+=2)1563gel(t, j) = FpX_add(ZX_mul(gel(u, k), gel(v, k+1)),1564ZX_mul(gel(u, k+1), gel(v, k)), p);1565gel(Tp, i) = t;1566}1567return gerepilecopy(av, gmael(Tp,m,1));1568}15691570GEN1571FpX_FpV_multieval(GEN P, GEN xa, GEN p)1572{1573pari_sp av = avma;1574GEN s = producttree_scheme(lg(xa)-1);1575GEN T = FpV_producttree(xa, s, p, varn(P));1576return gerepileupto(av, FpX_FpV_multieval_tree(P, xa, T, p));1577}15781579GEN1580FpV_polint(GEN xa, GEN ya, GEN p, long vs)1581{1582pari_sp av = avma;1583GEN s, T, P, R;1584long m;1585if (lgefint(p) == 3)1586{1587ulong pp = p[2];1588P = Flv_polint(ZV_to_Flv(xa, pp), ZV_to_Flv(ya, pp), pp, evalvarn(vs));1589return gerepileupto(av, Flx_to_ZX(P));1590}1591s = producttree_scheme(lg(xa)-1);1592T = FpV_producttree(xa, s, p, vs);1593m = lg(T)-1;1594P = FpX_deriv(gmael(T, m, 1), p);1595R = FpV_inv(FpX_FpV_multieval_tree(P, xa, T, p), p);1596return gerepileupto(av, FpVV_polint_tree(T, R, s, xa, ya, p, vs));1597}15981599GEN1600FpV_FpM_polint(GEN xa, GEN ya, GEN p, long vs)1601{1602pari_sp av = avma;1603GEN s = producttree_scheme(lg(xa)-1);1604GEN T = FpV_producttree(xa, s, p, vs);1605long i, m = lg(T)-1, l = lg(ya)-1;1606GEN P = FpX_deriv(gmael(T, m, 1), p);1607GEN R = FpV_inv(FpX_FpV_multieval_tree(P, xa, T, p), p);1608GEN M = cgetg(l+1, t_VEC);1609for (i=1; i<=l; i++)1610gel(M,i) = FpVV_polint_tree(T, R, s, xa, gel(ya,i), p, vs);1611return gerepileupto(av, M);1612}16131614GEN1615FpV_invVandermonde(GEN L, GEN den, GEN p)1616{1617pari_sp av = avma;1618long i, n = lg(L);1619GEN M, R;1620GEN s = producttree_scheme(n-1);1621GEN tree = FpV_producttree(L, s, p, 0);1622long m = lg(tree)-1;1623GEN T = gmael(tree, m, 1);1624R = FpV_inv(FpX_FpV_multieval_tree(FpX_deriv(T, p), L, tree, p), p);1625if (den) R = FpC_Fp_mul(R, den, p);1626M = cgetg(n, t_MAT);1627for (i = 1; i < n; i++)1628{1629GEN P = FpX_Fp_mul(FpX_div_by_X_x(T, gel(L,i), p, NULL), gel(R,i), p);1630gel(M,i) = RgX_to_RgC(P, n-1);1631}1632return gerepilecopy(av, M);1633}16341635static GEN1636FpXV_producttree(GEN xa, GEN s, GEN p)1637{1638long n = lg(xa)-1;1639long j, k, ls = lg(s);1640GEN t = cgetg(ls, t_VEC);1641for (j=1, k=1; j<ls; k+=s[j++])1642gel(t, j) = s[j] == 1 ?1643gel(xa,k): FpX_mul(gel(xa,k),gel(xa,k+1),p);1644return FpXV_producttree_dbl(t, n, p);1645}16461647static GEN1648FpX_FpXV_multirem_tree(GEN P, GEN xa, GEN T, GEN s, GEN p)1649{1650pari_sp av = avma;1651long j, k, ls = lg(s);1652GEN Tp = FpX_FpXV_multirem_dbl_tree(P, T, p);1653GEN R = cgetg(lg(xa), t_VEC);1654GEN v = gel(Tp, 1);1655for (j=1, k=1; j<ls; k+=s[j++])1656{1657gel(R,k) = FpX_rem(gel(v, j), gel(xa,k), p);1658if (s[j] == 2)1659gel(R,k+1) = FpX_rem(gel(v, j), gel(xa,k+1), p);1660}1661return gerepileupto(av, R);1662}16631664GEN1665FpX_FpXV_multirem(GEN P, GEN xa, GEN p)1666{1667pari_sp av = avma;1668GEN s = producttree_scheme(lg(xa)-1);1669GEN T = FpXV_producttree(xa, s, p);1670return gerepileupto(av, FpX_FpXV_multirem_tree(P, xa, T, s, p));1671}16721673/* T = ZV_producttree(P), R = ZV_chinesetree(P,T) */1674static GEN1675FpXV_chinese_tree(GEN A, GEN P, GEN T, GEN R, GEN s, GEN p)1676{1677long m = lg(T)-1, ls = lg(s);1678long i,j,k;1679GEN Tp = cgetg(m+1, t_VEC);1680GEN M = gel(T, 1);1681GEN t = cgetg(lg(M), t_VEC);1682for (j=1, k=1; j<ls; k+=s[j++])1683if (s[j] == 2)1684{1685pari_sp av = avma;1686GEN a = FpX_mul(gel(A,k), gel(R,k), p), b = FpX_mul(gel(A,k+1), gel(R,k+1), p);1687GEN tj = FpX_rem(FpX_add(FpX_mul(gel(P,k), b, p),1688FpX_mul(gel(P,k+1), a, p), p), gel(M,j), p);1689gel(t, j) = gerepileupto(av, tj);1690}1691else1692gel(t, j) = FpX_rem(FpX_mul(gel(A,k), gel(R,k), p), gel(M, j), p);1693gel(Tp, 1) = t;1694for (i=2; i<=m; i++)1695{1696GEN u = gel(T, i-1), M = gel(T, i);1697GEN t = cgetg(lg(M), t_VEC);1698GEN v = gel(Tp, i-1);1699long n = lg(v)-1;1700for (j=1, k=1; k<n; j++, k+=2)1701{1702pari_sp av = avma;1703gel(t, j) = gerepileupto(av, FpX_rem(FpX_add(FpX_mul(gel(u, k), gel(v, k+1), p),1704FpX_mul(gel(u, k+1), gel(v, k), p), p), gel(M, j), p));1705}1706if (k==n) gel(t, j) = gel(v, k);1707gel(Tp, i) = t;1708}1709return gmael(Tp,m,1);1710}17111712static GEN1713FpXV_sqr(GEN x, GEN p)1714{ pari_APPLY_type(t_VEC, FpX_sqr(gel(x,i), p)) }17151716static GEN1717FpXT_sqr(GEN x, GEN p)1718{1719if (typ(x) == t_POL)1720return FpX_sqr(x, p);1721pari_APPLY_type(t_VEC, FpXT_sqr(gel(x,i), p))1722}17231724static GEN1725FpXV_invdivexact(GEN x, GEN y, GEN p)1726{ pari_APPLY_type(t_VEC, FpXQ_inv(FpX_div(gel(x,i), gel(y,i),p), gel(y,i),p)) }17271728static GEN1729FpXV_chinesetree(GEN P, GEN T, GEN s, GEN p)1730{1731GEN T2 = FpXT_sqr(T, p), P2 = FpXV_sqr(P, p);1732GEN mod = gmael(T,lg(T)-1,1);1733return FpXV_invdivexact(FpX_FpXV_multirem_tree(mod, P2, T2, s, p), P, p);1734}17351736static GEN1737gc_chinese(pari_sp av, GEN T, GEN a, GEN *pt_mod)1738{1739if (!pt_mod)1740return gerepileupto(av, a);1741else1742{1743GEN mod = gmael(T, lg(T)-1, 1);1744gerepileall(av, 2, &a, &mod);1745*pt_mod = mod;1746return a;1747}1748}17491750GEN1751FpXV_chinese(GEN A, GEN P, GEN p, GEN *pt_mod)1752{1753pari_sp av = avma;1754GEN s = producttree_scheme(lg(P)-1);1755GEN T = FpXV_producttree(P, s, p);1756GEN R = FpXV_chinesetree(P, T, s, p);1757GEN a = FpXV_chinese_tree(A, P, T, R, s, p);1758return gc_chinese(av, T, a, pt_mod);1759}17601761/***********************************************************************/1762/** **/1763/** FpXQ **/1764/** **/1765/***********************************************************************/17661767/* FpXQ are elements of Fp[X]/(T), represented by FpX*/17681769GEN1770FpXQ_red(GEN x, GEN T, GEN p)1771{1772GEN z = FpX_red(x,p);1773return FpX_rem(z, T,p);1774}17751776GEN1777FpXQ_mul(GEN x,GEN y,GEN T,GEN p)1778{1779GEN z = FpX_mul(x,y,p);1780return FpX_rem(z, T, p);1781}17821783GEN1784FpXQ_sqr(GEN x, GEN T, GEN p)1785{1786GEN z = FpX_sqr(x,p);1787return FpX_rem(z, T, p);1788}17891790/* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist1791* return lift(1 / (x mod (p,pol))) */1792GEN1793FpXQ_invsafe(GEN x, GEN y, GEN p)1794{1795GEN V, z = FpX_extgcd(get_FpX_mod(y), x, p, NULL, &V);1796if (degpol(z)) return NULL;1797z = Fp_invsafe(gel(z,2), p);1798if (!z) return NULL;1799return FpX_Fp_mul(V, z, p);1800}18011802GEN1803FpXQ_inv(GEN x,GEN T,GEN p)1804{1805pari_sp av = avma;1806GEN U = FpXQ_invsafe(x, T, p);1807if (!U) pari_err_INV("FpXQ_inv",x);1808return gerepileupto(av, U);1809}18101811GEN1812FpXQ_div(GEN x,GEN y,GEN T,GEN p)1813{1814pari_sp av = avma;1815return gerepileupto(av, FpXQ_mul(x,FpXQ_inv(y,T,p),T,p));1816}18171818static GEN1819_FpXQ_add(void *data, GEN x, GEN y)1820{1821(void) data;1822return ZX_add(x, y);1823}1824static GEN1825_FpXQ_sub(void *data, GEN x, GEN y)1826{1827(void) data;1828return ZX_sub(x, y);1829}1830static GEN1831_FpXQ_cmul(void *data, GEN P, long a, GEN x)1832{1833(void) data;1834return ZX_Z_mul(x, gel(P,a+2));1835}1836static GEN1837_FpXQ_sqr(void *data, GEN x)1838{1839struct _FpXQ *D = (struct _FpXQ*)data;1840return FpXQ_sqr(x, D->T, D->p);1841}1842static GEN1843_FpXQ_mul(void *data, GEN x, GEN y)1844{1845struct _FpXQ *D = (struct _FpXQ*)data;1846return FpXQ_mul(x,y, D->T, D->p);1847}1848static GEN1849_FpXQ_zero(void *data)1850{1851struct _FpXQ *D = (struct _FpXQ*)data;1852return pol_0(get_FpX_var(D->T));1853}1854static GEN1855_FpXQ_one(void *data)1856{1857struct _FpXQ *D = (struct _FpXQ*)data;1858return pol_1(get_FpX_var(D->T));1859}1860static GEN1861_FpXQ_red(void *data, GEN x)1862{1863struct _FpXQ *D = (struct _FpXQ*)data;1864return FpX_red(x,D->p);1865}18661867static struct bb_algebra FpXQ_algebra = { _FpXQ_red, _FpXQ_add, _FpXQ_sub,1868_FpXQ_mul, _FpXQ_sqr, _FpXQ_one, _FpXQ_zero };18691870const struct bb_algebra *1871get_FpXQ_algebra(void **E, GEN T, GEN p)1872{1873GEN z = new_chunk(sizeof(struct _FpXQ));1874struct _FpXQ *e = (struct _FpXQ *) z;1875e->T = FpX_get_red(T, p);1876e->p = p; *E = (void*)e;1877return &FpXQ_algebra;1878}18791880static GEN1881_FpX_red(void *E, GEN x)1882{ struct _FpX *D = (struct _FpX*)E; return FpX_red(x,D->p); }18831884static GEN1885_FpX_zero(void *E)1886{ struct _FpX *D = (struct _FpX *)E; return pol_0(D->v); }188718881889static struct bb_algebra FpX_algebra = { _FpX_red, _FpXQ_add, _FpXQ_sub,1890_FpX_mul, _FpX_sqr, _FpX_one, _FpX_zero };18911892const struct bb_algebra *1893get_FpX_algebra(void **E, GEN p, long v)1894{1895GEN z = new_chunk(sizeof(struct _FpX));1896struct _FpX *e = (struct _FpX *) z;1897e->p = p; e->v = v; *E = (void*)e;1898return &FpX_algebra;1899}19001901/* x,pol in Z[X], p in Z, n in Z, compute lift(x^n mod (p, pol)) */1902GEN1903FpXQ_pow(GEN x, GEN n, GEN T, GEN p)1904{1905struct _FpXQ D;1906pari_sp av;1907long s = signe(n);1908GEN y;1909if (!s) return pol_1(varn(x));1910if (is_pm1(n)) /* +/- 1 */1911return (s < 0)? FpXQ_inv(x,T,p): FpXQ_red(x,T,p);1912av = avma;1913if (!is_bigint(p))1914{1915ulong pp = to_Flxq(&x, &T, p);1916y = Flxq_pow(x, n, T, pp);1917return Flx_to_ZX_inplace(gerepileuptoleaf(av, y));1918}1919if (s < 0) x = FpXQ_inv(x,T,p);1920D.p = p; D.T = FpX_get_red(T,p);1921y = gen_pow_i(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul);1922return gerepilecopy(av, y);1923}19241925GEN /*Assume n is very small*/1926FpXQ_powu(GEN x, ulong n, GEN T, GEN p)1927{1928struct _FpXQ D;1929pari_sp av;1930GEN y;1931if (!n) return pol_1(varn(x));1932if (n==1) return FpXQ_red(x,T,p);1933av = avma;1934if (!is_bigint(p))1935{1936ulong pp = to_Flxq(&x, &T, p);1937y = Flxq_powu(x, n, T, pp);1938return Flx_to_ZX_inplace(gerepileuptoleaf(av, y));1939}1940D.T = FpX_get_red(T, p); D.p = p;1941y = gen_powu_i(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul);1942return gerepilecopy(av, y);1943}19441945/* generates the list of powers of x of degree 0,1,2,...,l*/1946GEN1947FpXQ_powers(GEN x, long l, GEN T, GEN p)1948{1949struct _FpXQ D;1950int use_sqr;1951if (l>2 && lgefint(p) == 3) {1952pari_sp av = avma;1953ulong pp = to_Flxq(&x, &T, p);1954GEN z = FlxV_to_ZXV(Flxq_powers(x, l, T, pp));1955return gerepileupto(av, z);1956}1957use_sqr = 2*degpol(x)>=get_FpX_degree(T);1958D.T = FpX_get_red(T,p); D.p = p;1959return gen_powers(x, l, use_sqr, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul,&_FpXQ_one);1960}19611962GEN1963FpXQ_matrix_pow(GEN y, long n, long m, GEN P, GEN l)1964{1965return RgXV_to_RgM(FpXQ_powers(y,m-1,P,l),n);1966}19671968GEN1969FpX_Frobenius(GEN T, GEN p)1970{1971return FpXQ_pow(pol_x(get_FpX_var(T)), p, T, p);1972}19731974GEN1975FpX_matFrobenius(GEN T, GEN p)1976{1977long n = get_FpX_degree(T);1978return FpXQ_matrix_pow(FpX_Frobenius(T, p), n, n, T, p);1979}19801981GEN1982FpX_FpXQV_eval(GEN Q, GEN x, GEN T, GEN p)1983{1984struct _FpXQ D;1985D.T = FpX_get_red(T,p); D.p = p;1986return gen_bkeval_powers(Q,degpol(Q),x,(void*)&D,&FpXQ_algebra,_FpXQ_cmul);1987}19881989GEN1990FpX_FpXQ_eval(GEN Q, GEN x, GEN T, GEN p)1991{1992struct _FpXQ D;1993int use_sqr;1994if (lgefint(p) == 3)1995{1996pari_sp av = avma;1997ulong pp = to_Flxq(&x, &T, p);1998GEN z = Flx_Flxq_eval(ZX_to_Flx(Q, pp), x, T, pp);1999return Flx_to_ZX_inplace(gerepileuptoleaf(av, z));2000}2001use_sqr = 2*degpol(x) >= get_FpX_degree(T);2002D.T = FpX_get_red(T,p); D.p = p;2003return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&D,&FpXQ_algebra,_FpXQ_cmul);2004}20052006GEN2007FpXC_FpXQV_eval(GEN x, GEN v, GEN T, GEN p)2008{ pari_APPLY_type(t_COL, FpX_FpXQV_eval(gel(x,i), v, T, p)) }20092010GEN2011FpXM_FpXQV_eval(GEN x, GEN v, GEN T, GEN p)2012{ pari_APPLY_same(FpXC_FpXQV_eval(gel(x,i), v, T, p)) }20132014GEN2015FpXC_FpXQ_eval(GEN x, GEN F, GEN T, GEN p)2016{2017long d = brent_kung_optpow(RgXV_maxdegree(x), lg(x)-1, 1);2018GEN Fp = FpXQ_powers(F, d, T, p);2019return FpXC_FpXQV_eval(x, Fp, T, p);2020}20212022GEN2023FpXQ_autpowers(GEN aut, long f, GEN T, GEN p)2024{2025pari_sp av = avma;2026long n = get_FpX_degree(T);2027long i, nautpow = brent_kung_optpow(n-1,f-2,1);2028long v = get_FpX_var(T);2029GEN autpow, V;2030T = FpX_get_red(T, p);2031autpow = FpXQ_powers(aut, nautpow,T,p);2032V = cgetg(f + 2, t_VEC);2033gel(V,1) = pol_x(v); if (f==0) return gerepileupto(av, V);2034gel(V,2) = gcopy(aut);2035for (i = 3; i <= f+1; i++)2036gel(V,i) = FpX_FpXQV_eval(gel(V,i-1),autpow,T,p);2037return gerepileupto(av, V);2038}20392040static GEN2041FpXQ_autpow_sqr(void *E, GEN x)2042{2043struct _FpXQ *D = (struct _FpXQ*)E;2044return FpX_FpXQ_eval(x, x, D->T, D->p);2045}20462047static GEN2048FpXQ_autpow_msqr(void *E, GEN x)2049{2050struct _FpXQ *D = (struct _FpXQ*)E;2051return FpX_FpXQV_eval(FpXQ_autpow_sqr(E, x), D->aut, D->T, D->p);2052}20532054GEN2055FpXQ_autpow(GEN x, ulong n, GEN T, GEN p)2056{2057pari_sp av = avma;2058struct _FpXQ D;2059long d;2060if (n==0) return FpX_rem(pol_x(varn(x)), T, p);2061if (n==1) return FpX_rem(x, T, p);2062D.T = FpX_get_red(T, p); D.p = p;2063d = brent_kung_optpow(degpol(T), hammingl(n)-1, 1);2064D.aut = FpXQ_powers(x, d, T, p);2065x = gen_powu_fold(x,n,(void*)&D,FpXQ_autpow_sqr,FpXQ_autpow_msqr);2066return gerepilecopy(av, x);2067}20682069static GEN2070FpXQ_auttrace_mul(void *E, GEN x, GEN y)2071{2072struct _FpXQ *D = (struct _FpXQ*)E;2073GEN T = D->T, p = D->p;2074GEN phi1 = gel(x,1), a1 = gel(x,2);2075GEN phi2 = gel(y,1), a2 = gel(y,2);2076ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1);2077GEN V1 = FpXQ_powers(phi1, d, T, p);2078GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);2079GEN aphi = FpX_FpXQV_eval(a2, V1, T, p);2080GEN a3 = FpX_add(a1, aphi, p);2081return mkvec2(phi3, a3);2082}20832084static GEN2085FpXQ_auttrace_sqr(void *E, GEN x)2086{ return FpXQ_auttrace_mul(E, x, x); }20872088GEN2089FpXQ_auttrace(GEN x, ulong n, GEN T, GEN p)2090{2091pari_sp av = avma;2092struct _FpXQ D;2093D.T = FpX_get_red(T, p); D.p = p;2094x = gen_powu_i(x,n,(void*)&D,FpXQ_auttrace_sqr,FpXQ_auttrace_mul);2095return gerepilecopy(av, x);2096}20972098static GEN2099FpXQ_autsum_mul(void *E, GEN x, GEN y)2100{2101struct _FpXQ *D = (struct _FpXQ*)E;2102GEN T = D->T, p = D->p;2103GEN phi1 = gel(x,1), a1 = gel(x,2);2104GEN phi2 = gel(y,1), a2 = gel(y,2);2105ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1);2106GEN V1 = FpXQ_powers(phi1, d, T, p);2107GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);2108GEN aphi = FpX_FpXQV_eval(a2, V1, T, p);2109GEN a3 = FpXQ_mul(a1, aphi, T, p);2110return mkvec2(phi3, a3);2111}2112static GEN2113FpXQ_autsum_sqr(void *E, GEN x)2114{ return FpXQ_autsum_mul(E, x, x); }21152116GEN2117FpXQ_autsum(GEN x, ulong n, GEN T, GEN p)2118{2119pari_sp av = avma;2120struct _FpXQ D;2121D.T = FpX_get_red(T, p); D.p = p;2122x = gen_powu_i(x,n,(void*)&D,FpXQ_autsum_sqr,FpXQ_autsum_mul);2123return gerepilecopy(av, x);2124}21252126static GEN2127FpXQM_autsum_mul(void *E, GEN x, GEN y)2128{2129struct _FpXQ *D = (struct _FpXQ*)E;2130GEN T = D->T, p = D->p;2131GEN phi1 = gel(x,1), a1 = gel(x,2);2132GEN phi2 = gel(y,1), a2 = gel(y,2);2133long g = lg(a2)-1, dT = get_FpX_degree(T);2134ulong d = brent_kung_optpow(dT-1, g*g+1, 1);2135GEN V1 = FpXQ_powers(phi1, d, T, p);2136GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);2137GEN aphi = FpXM_FpXQV_eval(a2, V1, T, p);2138GEN a3 = FqM_mul(a1, aphi, T, p);2139return mkvec2(phi3, a3);2140}2141static GEN2142FpXQM_autsum_sqr(void *E, GEN x)2143{ return FpXQM_autsum_mul(E, x, x); }21442145GEN2146FpXQM_autsum(GEN x, ulong n, GEN T, GEN p)2147{2148pari_sp av = avma;2149struct _FpXQ D;2150D.T = FpX_get_red(T, p); D.p = p;2151x = gen_powu_i(x, n, (void*)&D, FpXQM_autsum_sqr, FpXQM_autsum_mul);2152return gerepilecopy(av, x);2153}21542155static long2156bounded_order(GEN p, GEN b, long k)2157{2158long i;2159GEN a=modii(p,b);2160for(i=1;i<k;i++)2161{2162if (equali1(a))2163return i;2164a = Fp_mul(a,p,b);2165}2166return 0;2167}21682169/*2170n = (p^d-a)\b2171b = bb*p^vb2172p^k = 1 [bb]2173d = m*k+r+vb2174u = (p^k-1)/bb;2175v = (p^(r+vb)-a)/b;2176w = (p^(m*k)-1)/(p^k-1)2177n = p^r*w*u+v2178w*u = p^vb*(p^(m*k)-1)/b2179n = p^(r+vb)*(p^(m*k)-1)/b+(p^(r+vb)-a)/b2180*/21812182static GEN2183FpXQ_pow_Frobenius(GEN x, GEN n, GEN aut, GEN T, GEN p)2184{2185pari_sp av=avma;2186long d = get_FpX_degree(T);2187GEN an = absi_shallow(n), z, q;2188if (cmpii(an,p)<0 || cmpis(an,d)<=0) return FpXQ_pow(x, n, T, p);2189q = powiu(p, d);2190if (dvdii(q, n))2191{2192long vn = logint(an,p);2193GEN autvn = vn==1 ? aut: FpXQ_autpow(aut,vn,T,p);2194z = FpX_FpXQ_eval(x,autvn,T,p);2195} else2196{2197GEN b = diviiround(q, an), a = subii(q, mulii(an,b));2198GEN bb, u, v, autk;2199long vb = Z_pvalrem(b,p,&bb);2200long m, r, k = is_pm1(bb) ? 1 : bounded_order(p,bb,d);2201if (!k || d-vb<k) return FpXQ_pow(x,n, T, p);2202m = (d-vb)/k; r = (d-vb)%k;2203u = diviiexact(subiu(powiu(p,k),1),bb);2204v = diviiexact(subii(powiu(p,r+vb),a),b);2205autk = k==1 ? aut: FpXQ_autpow(aut,k,T,p);2206if (r)2207{2208GEN autr = r==1 ? aut: FpXQ_autpow(aut,r,T,p);2209z = FpX_FpXQ_eval(x,autr,T,p);2210} else z = x;2211if (m > 1) z = gel(FpXQ_autsum(mkvec2(autk, z), m, T, p), 2);2212if (!is_pm1(u)) z = FpXQ_pow(z, u, T, p);2213if (signe(v)) z = FpXQ_mul(z, FpXQ_pow(x, v, T, p), T, p);2214}2215return gerepileupto(av,signe(n)>0 ? z : FpXQ_inv(z,T,p));2216}22172218/* assume T irreducible mod p */2219int2220FpXQ_issquare(GEN x, GEN T, GEN p)2221{2222pari_sp av;2223if (lg(x) == 2 || absequalui(2, p)) return 1;2224if (lg(x) == 3) return Fq_issquare(gel(x,2), T, p);2225av = avma; /* Ng = g^((q-1)/(p-1)) */2226return gc_bool(av, kronecker(FpXQ_norm(x,T,p), p) == 1);2227}2228int2229Fp_issquare(GEN x, GEN p)2230{2231if (absequalui(2, p)) return 1;2232return kronecker(x, p) == 1;2233}2234/* assume T irreducible mod p */2235int2236Fq_issquare(GEN x, GEN T, GEN p)2237{2238if (typ(x) != t_INT) return FpXQ_issquare(x, T, p);2239return (T && ! odd(get_FpX_degree(T))) || Fp_issquare(x, p);2240}22412242long2243Fq_ispower(GEN x, GEN K, GEN T, GEN p)2244{2245pari_sp av = avma;2246long d;2247GEN Q;2248if (equaliu(K,2)) return Fq_issquare(x, T, p);2249if (!T) return Fp_ispower(x, K, p);2250d = get_FpX_degree(T);2251if (typ(x) == t_INT && !umodui(d, K)) return 1;2252Q = subiu(powiu(p,d), 1);2253Q = diviiexact(Q, gcdii(Q, K));2254d = gequal1(Fq_pow(x, Q, T,p));2255return gc_long(av, d);2256}22572258/* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */2259GEN2260Fp_FpXQ_log(GEN a, GEN g, GEN o, GEN T, GEN p)2261{2262pari_sp av = avma;2263GEN q,n_q,ord,ordp, op;22642265if (equali1(a)) return gen_0;2266/* p > 2 */22672268ordp = subiu(p, 1); /* even */2269ord = get_arith_Z(o);2270if (!ord) ord = T? subiu(powiu(p, get_FpX_degree(T)), 1): ordp;2271if (equalii(a, ordp)) /* -1 */2272return gerepileuptoint(av, shifti(ord,-1));2273ordp = gcdii(ordp,ord);2274op = typ(o)==t_MAT ? famat_Z_gcd(o,ordp) : ordp;22752276q = NULL;2277if (T)2278{ /* we want < g > = Fp^* */2279if (!equalii(ord,ordp)) {2280q = diviiexact(ord,ordp);2281g = FpXQ_pow(g,q,T,p);2282}2283g = constant_coeff(g);2284}2285n_q = Fp_log(a,g,op,p);2286if (lg(n_q)==1) return gerepileuptoleaf(av, n_q);2287if (q) n_q = mulii(q, n_q);2288return gerepileuptoint(av, n_q);2289}22902291static GEN2292_FpXQ_pow(void *data, GEN x, GEN n)2293{2294struct _FpXQ *D = (struct _FpXQ*)data;2295return FpXQ_pow_Frobenius(x,n, D->aut, D->T, D->p);2296}22972298static GEN2299_FpXQ_rand(void *data)2300{2301pari_sp av=avma;2302struct _FpXQ *D = (struct _FpXQ*)data;2303GEN z;2304do2305{2306set_avma(av);2307z=random_FpX(get_FpX_degree(D->T),get_FpX_var(D->T),D->p);2308} while (!signe(z));2309return z;2310}23112312static GEN2313_FpXQ_easylog(void *E, GEN a, GEN g, GEN ord)2314{2315struct _FpXQ *s=(struct _FpXQ*) E;2316if (degpol(a)) return NULL;2317return Fp_FpXQ_log(constant_coeff(a),g,ord,s->T,s->p);2318}23192320static const struct bb_group FpXQ_star={_FpXQ_mul,_FpXQ_pow,_FpXQ_rand,hash_GEN,ZX_equal,ZX_equal1,_FpXQ_easylog};23212322const struct bb_group *2323get_FpXQ_star(void **E, GEN T, GEN p)2324{2325struct _FpXQ *e = (struct _FpXQ *) stack_malloc(sizeof(struct _FpXQ));2326e->T = T; e->p = p; e->aut = FpX_Frobenius(T, p);2327*E = (void*)e; return &FpXQ_star;2328}23292330GEN2331FpXQ_order(GEN a, GEN ord, GEN T, GEN p)2332{2333if (lgefint(p)==3)2334{2335pari_sp av=avma;2336ulong pp = to_Flxq(&a, &T, p);2337GEN z = Flxq_order(a, ord, T, pp);2338return gerepileuptoint(av,z);2339}2340else2341{2342void *E;2343const struct bb_group *S = get_FpXQ_star(&E,T,p);2344return gen_order(a,ord,E,S);2345}2346}23472348GEN2349FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p)2350{2351pari_sp av=avma;2352if (lgefint(p)==3)2353{2354if (uel(p,2) == 2)2355{2356GEN z = F2xq_log(ZX_to_F2x(a), ZX_to_F2x(g), ord,2357ZX_to_F2x(get_FpX_mod(T)));2358return gerepileuptoleaf(av, z);2359}2360else2361{2362ulong pp = to_Flxq(&a, &T, p);2363GEN z = Flxq_log(a, ZX_to_Flx(g, pp), ord, T, pp);2364return gerepileuptoleaf(av, z);2365}2366}2367else2368{2369void *E;2370const struct bb_group *S = get_FpXQ_star(&E,T,p);2371GEN z = gen_PH_log(a,g,ord,E,S);2372return gerepileuptoleaf(av, z);2373}2374}23752376GEN2377Fq_log(GEN a, GEN g, GEN ord, GEN T, GEN p)2378{2379if (!T) return Fp_log(a,g,ord,p);2380if (typ(g) == t_INT)2381{2382if (typ(a) == t_POL)2383{2384if (degpol(a)) return cgetg(1,t_VEC);2385a = gel(a,2);2386}2387return Fp_log(a,g,ord,p);2388}2389return typ(a) == t_INT? Fp_FpXQ_log(a,g,ord,T,p): FpXQ_log(a,g,ord,T,p);2390}23912392GEN2393FpXQ_sqrtn(GEN a, GEN n, GEN T, GEN p, GEN *zeta)2394{2395pari_sp av = avma;2396GEN z;2397if (!signe(a))2398{2399long v=varn(a);2400if (signe(n) < 0) pari_err_INV("FpXQ_sqrtn",a);2401if (zeta) *zeta=pol_1(v);2402return pol_0(v);2403}2404if (lgefint(p)==3)2405{2406if (uel(p,2) == 2)2407{2408z = F2xq_sqrtn(ZX_to_F2x(a), n, ZX_to_F2x(get_FpX_mod(T)), zeta);2409if (!z) return NULL;2410z = F2x_to_ZX(z);2411if (!zeta) return gerepileuptoleaf(av, z);2412*zeta=F2x_to_ZX(*zeta);2413} else2414{2415ulong pp = to_Flxq(&a, &T, p);2416z = Flxq_sqrtn(a, n, T, pp, zeta);2417if (!z) return NULL;2418if (!zeta) return Flx_to_ZX_inplace(gerepileuptoleaf(av, z));2419z = Flx_to_ZX(z);2420*zeta=Flx_to_ZX(*zeta);2421}2422}2423else2424{2425void *E;2426const struct bb_group *S = get_FpXQ_star(&E,T,p);2427GEN o = subiu(powiu(p,get_FpX_degree(T)),1);2428z = gen_Shanks_sqrtn(a,n,o,zeta,E,S);2429if (!z) return NULL;2430if (!zeta) return gerepileupto(av, z);2431}2432gerepileall(av, 2, &z,zeta);2433return z;2434}24352436GEN2437FpXQ_sqrt(GEN a, GEN T, GEN p)2438{2439return FpXQ_sqrtn(a, gen_2, T, p, NULL);2440}24412442GEN2443FpXQ_norm(GEN x, GEN TB, GEN p)2444{2445pari_sp av = avma;2446GEN T = get_FpX_mod(TB);2447GEN y = FpX_resultant(T, x, p);2448GEN L = leading_coeff(T);2449if (gequal1(L) || signe(x)==0) return y;2450return gerepileupto(av, Fp_div(y, Fp_pows(L, degpol(x), p), p));2451}24522453GEN2454FpXQ_trace(GEN x, GEN TB, GEN p)2455{2456pari_sp av = avma;2457GEN T = get_FpX_mod(TB);2458GEN dT = FpX_deriv(T,p);2459long n = degpol(dT);2460GEN z = FpXQ_mul(x, dT, TB, p);2461if (degpol(z)<n) return gc_const(av, gen_0);2462return gerepileuptoint(av, Fp_div(gel(z,2+n), gel(T,3+n),p));2463}24642465GEN2466FpXQ_charpoly(GEN x, GEN T, GEN p)2467{2468pari_sp ltop=avma;2469long vT, v = fetch_var();2470GEN R;2471T = leafcopy(get_FpX_mod(T));2472vT = varn(T); setvarn(T, v);2473x = leafcopy(x); setvarn(x, v);2474R = FpX_FpXY_resultant(T, deg1pol_shallow(gen_1,FpX_neg(x,p),vT),p);2475(void)delete_var(); return gerepileupto(ltop,R);2476}24772478/* Computing minimal polynomial : */2479/* cf Shoup 'Efficient Computation of Minimal Polynomials */2480/* in Algebraic Extensions of Finite Fields' */24812482/* Let v a linear form, return the linear form z->v(tau*z)2483that is, v*(M_tau) */24842485static GEN2486FpXQ_transmul_init(GEN tau, GEN T, GEN p)2487{2488GEN bht;2489GEN h, Tp = get_FpX_red(T, &h);2490long n = degpol(Tp), vT = varn(Tp);2491GEN ft = FpX_recipspec(Tp+2, n+1, n+1);2492GEN bt = FpX_recipspec(tau+2, lgpol(tau), n);2493setvarn(ft, vT); setvarn(bt, vT);2494if (h)2495bht = FpXn_mul(bt, h, n-1, p);2496else2497{2498GEN bh = FpX_div(FpX_shift(tau, n-1), T, p);2499bht = FpX_recipspec(bh+2, lgpol(bh), n-1);2500setvarn(bht, vT);2501}2502return mkvec3(bt, bht, ft);2503}25042505static GEN2506FpXQ_transmul(GEN tau, GEN a, long n, GEN p)2507{2508pari_sp ltop = avma;2509GEN t1, t2, t3, vec;2510GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);2511if (signe(a)==0) return pol_0(varn(a));2512t2 = FpX_shift(FpX_mul(bt, a, p),1-n);2513if (signe(bht)==0) return gerepilecopy(ltop, t2);2514t1 = FpX_shift(FpX_mul(ft, a, p),-n);2515t3 = FpXn_mul(t1, bht, n-1, p);2516vec = FpX_sub(t2, FpX_shift(t3, 1), p);2517return gerepileupto(ltop, vec);2518}25192520GEN2521FpXQ_minpoly(GEN x, GEN T, GEN p)2522{2523pari_sp ltop = avma;2524long vT, n;2525GEN v_x, g, tau;2526if (lgefint(p)==3)2527{2528ulong pp = to_Flxq(&x, &T, p);2529GEN g = Flxq_minpoly(x, T, pp);2530return gerepileupto(ltop, Flx_to_ZX(g));2531}2532vT = get_FpX_var(T);2533n = get_FpX_degree(T);2534g = pol_1(vT);2535tau = pol_1(vT);2536T = FpX_get_red(T, p);2537x = FpXQ_red(x, T, p);2538v_x = FpXQ_powers(x, usqrt(2*n), T, p);2539while(signe(tau) != 0)2540{2541long i, j, m, k1;2542GEN M, v, tr;2543GEN g_prime, c;2544if (degpol(g) == n) { tau = pol_1(vT); g = pol_1(vT); }2545v = random_FpX(n, vT, p);2546tr = FpXQ_transmul_init(tau, T, p);2547v = FpXQ_transmul(tr, v, n, p);2548m = 2*(n-degpol(g));2549k1 = usqrt(m);2550tr = FpXQ_transmul_init(gel(v_x,k1+1), T, p);2551c = cgetg(m+2,t_POL);2552c[1] = evalsigne(1)|evalvarn(vT);2553for (i=0; i<m; i+=k1)2554{2555long mj = minss(m-i, k1);2556for (j=0; j<mj; j++)2557gel(c,m+1-(i+j)) = FpX_dotproduct(v, gel(v_x,j+1), p);2558v = FpXQ_transmul(tr, v, n, p);2559}2560c = FpX_renormalize(c, m+2);2561/* now c contains <v,x^i> , i = 0..m-1 */2562M = FpX_halfgcd(pol_xn(m, vT), c, p);2563g_prime = gmael(M, 2, 2);2564if (degpol(g_prime) < 1) continue;2565g = FpX_mul(g, g_prime, p);2566tau = FpXQ_mul(tau, FpX_FpXQV_eval(g_prime, v_x, T, p), T, p);2567}2568g = FpX_normalize(g,p);2569return gerepilecopy(ltop,g);2570}25712572GEN2573FpXQ_conjvec(GEN x, GEN T, GEN p)2574{2575pari_sp av=avma;2576long i;2577long n = get_FpX_degree(T), v = varn(x);2578GEN M = FpX_matFrobenius(T, p);2579GEN z = cgetg(n+1,t_COL);2580gel(z,1) = RgX_to_RgC(x,n);2581for (i=2; i<=n; i++) gel(z,i) = FpM_FpC_mul(M,gel(z,i-1),p);2582gel(z,1) = x;2583for (i=2; i<=n; i++) gel(z,i) = RgV_to_RgX(gel(z,i),v);2584return gerepilecopy(av,z);2585}25862587/* p prime, p_1 = p-1, q = p^deg T, Lp = cofactors of some prime divisors2588* l_p of p-1, Lq = cofactors of some prime divisors l_q of q-1, return a2589* g in Fq such that2590* - Ng generates all l_p-Sylows of Fp^*2591* - g generates all l_q-Sylows of Fq^* */2592static GEN2593gener_FpXQ_i(GEN T, GEN p, GEN p_1, GEN Lp, GEN Lq)2594{2595pari_sp av;2596long vT = varn(T), f = degpol(T), l = lg(Lq);2597GEN F = FpX_Frobenius(T, p);2598int p_is_2 = is_pm1(p_1);2599for (av = avma;; set_avma(av))2600{2601GEN t, g = random_FpX(f, vT, p);2602long i;2603if (degpol(g) < 1) continue;2604if (p_is_2)2605t = g;2606else2607{2608t = FpX_resultant(T, g, p); /* Ng = g^((q-1)/(p-1)), assuming T monic */2609if (kronecker(t, p) == 1) continue;2610if (lg(Lp) > 1 && !is_gener_Fp(t, p, p_1, Lp)) continue;2611t = FpXQ_pow(g, shifti(p_1,-1), T, p);2612}2613for (i = 1; i < l; i++)2614{2615GEN a = FpXQ_pow_Frobenius(t, gel(Lq,i), F, T, p);2616if (!degpol(a) && equalii(gel(a,2), p_1)) break;2617}2618if (i == l) return g;2619}2620}26212622GEN2623gener_FpXQ(GEN T, GEN p, GEN *po)2624{2625long i, j, f = get_FpX_degree(T);2626GEN g, Lp, Lq, p_1, q_1, N, o;2627pari_sp av = avma;26282629p_1 = subiu(p,1);2630if (f == 1) {2631GEN Lp, fa;2632o = p_1;2633fa = Z_factor(o);2634Lp = gel(fa,1);2635Lp = vecslice(Lp, 2, lg(Lp)-1); /* remove 2 for efficiency */26362637g = cgetg(3, t_POL);2638g[1] = evalsigne(1) | evalvarn(get_FpX_var(T));2639gel(g,2) = pgener_Fp_local(p, Lp);2640if (po) *po = mkvec2(o, fa);2641return g;2642}2643if (lgefint(p) == 3)2644{2645ulong pp = to_Flxq(NULL, &T, p);2646g = gener_Flxq(T, pp, po);2647if (!po) return Flx_to_ZX_inplace(gerepileuptoleaf(av, g));2648g = Flx_to_ZX(g);2649gerepileall(av, 2, &g, po);2650return g;2651}2652/* p now odd */2653q_1 = subiu(powiu(p,f), 1);2654N = diviiexact(q_1, p_1);2655Lp = odd_prime_divisors(p_1);2656for (i=lg(Lp)-1; i; i--) gel(Lp,i) = diviiexact(p_1, gel(Lp,i));2657o = factor_pn_1(p,f);2658Lq = leafcopy( gel(o, 1) );2659for (i = j = 1; i < lg(Lq); i++)2660{2661if (dvdii(p_1, gel(Lq,i))) continue;2662gel(Lq,j++) = diviiexact(N, gel(Lq,i));2663}2664setlg(Lq, j);2665g = gener_FpXQ_i(get_FpX_mod(T), p, p_1, Lp, Lq);2666if (!po) g = gerepilecopy(av, g);2667else {2668*po = mkvec2(q_1, o);2669gerepileall(av, 2, &g, po);2670}2671return g;2672}26732674GEN2675gener_FpXQ_local(GEN T, GEN p, GEN L)2676{2677GEN Lp, Lq, p_1 = subiu(p,1), q_1, N, Q;2678long f, i, ip, iq, l = lg(L);2679T = get_FpX_mod(T);2680f = degpol(T);2681q_1 = subiu(powiu(p,f), 1);2682N = diviiexact(q_1, p_1);26832684Q = is_pm1(p_1)? gen_1: shifti(p_1,-1);2685Lp = cgetg(l, t_VEC); ip = 1;2686Lq = cgetg(l, t_VEC); iq = 1;2687for (i=1; i < l; i++)2688{2689GEN a, b, ell = gel(L,i);2690if (absequaliu(ell,2)) continue;2691a = dvmdii(Q, ell, &b);2692if (b == gen_0)2693gel(Lp,ip++) = a;2694else2695gel(Lq,iq++) = diviiexact(N,ell);2696}2697setlg(Lp, ip);2698setlg(Lq, iq);2699return gener_FpXQ_i(T, p, p_1, Lp, Lq);2700}27012702/***********************************************************************/2703/** **/2704/** FpXn **/2705/** **/2706/***********************************************************************/27072708INLINE GEN2709FpXn_red(GEN a, long n)2710{ return RgXn_red_shallow(a, n); }27112712GEN2713FpXn_mul(GEN a, GEN b, long n, GEN p)2714{2715return FpX_red(ZXn_mul(a, b, n), p);2716}27172718GEN2719FpXn_sqr(GEN a, long n, GEN p)2720{2721return FpX_red(ZXn_sqr(a, n), p);2722}27232724/* (f*g) \/ x^n */2725static GEN2726FpX_mulhigh_i(GEN f, GEN g, long n, GEN p)2727{2728return FpX_shift(FpX_mul(f,g, p),-n);2729}27302731static GEN2732FpXn_mulhigh(GEN f, GEN g, long n2, long n, GEN p)2733{2734GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2);2735return FpX_add(FpX_mulhigh_i(fl, g, n2, p), FpXn_mul(fh, g, n - n2, p), p);2736}27372738GEN2739FpXn_inv(GEN f, long e, GEN p)2740{2741pari_sp av = avma, av2;2742ulong mask;2743GEN W, a;2744long v = varn(f), n = 1;27452746if (!signe(f)) pari_err_INV("FpXn_inv",f);2747a = Fp_inv(gel(f,2), p);2748if (e == 1) return scalarpol(a, v);2749else if (e == 2)2750{2751GEN b;2752if (degpol(f) <= 0) return scalarpol(a, v);2753b = Fp_neg(gel(f,3),p);2754if (signe(b)==0) return scalarpol(a, v);2755if (!is_pm1(a)) b = Fp_mul(b, Fp_sqr(a, p), p);2756W = deg1pol_shallow(b, a, v);2757return gerepilecopy(av, W);2758}2759W = scalarpol_shallow(Fp_inv(gel(f,2), p),v);2760mask = quadratic_prec_mask(e);2761av2 = avma;2762for (;mask>1;)2763{2764GEN u, fr;2765long n2 = n;2766n<<=1; if (mask & 1) n--;2767mask >>= 1;2768fr = FpXn_red(f, n);2769u = FpXn_mul(W, FpXn_mulhigh(fr, W, n2, n, p), n-n2, p);2770W = FpX_sub(W, FpX_shift(u, n2), p);2771if (gc_needed(av2,2))2772{2773if(DEBUGMEM>1) pari_warn(warnmem,"FpXn_inv, e = %ld", n);2774W = gerepileupto(av2, W);2775}2776}2777return gerepileupto(av, W);2778}27792780GEN2781FpXn_expint(GEN h, long e, GEN p)2782{2783pari_sp av = avma, av2;2784long v = varn(h), n=1;2785GEN f = pol_1(v), g = pol_1(v);2786ulong mask = quadratic_prec_mask(e);2787av2 = avma;2788for (;mask>1;)2789{2790GEN u, w;2791long n2 = n;2792n<<=1; if (mask & 1) n--;2793mask >>= 1;2794u = FpXn_mul(g, FpX_mulhigh_i(f, FpXn_red(h, n2-1), n2-1, p), n-n2, p);2795u = FpX_add(u, FpX_shift(FpXn_red(h, n-1), 1-n2), p);2796w = FpXn_mul(f, FpX_integXn(u, n2-1, p), n-n2, p);2797f = FpX_add(f, FpX_shift(w, n2), p);2798if (mask<=1) break;2799u = FpXn_mul(g, FpXn_mulhigh(f, g, n2, n, p), n-n2, p);2800g = FpX_sub(g, FpX_shift(u, n2), p);2801if (gc_needed(av2,2))2802{2803if (DEBUGMEM>1) pari_warn(warnmem,"FpXn_exp, e = %ld", n);2804gerepileall(av2, 2, &f, &g);2805}2806}2807return gerepileupto(av, f);2808}28092810GEN2811FpXn_exp(GEN h, long e, GEN p)2812{2813if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2)))2814pari_err_DOMAIN("FpXn_exp","valuation", "<", gen_1, h);2815return FpXn_expint(FpX_deriv(h, p), e, p);2816}281728182819