Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2019 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/***********************************************************************/18/** **/19/** FlxX **/20/** **/21/***********************************************************************/2223/* FlxX are t_POL with Flx coefficients.24* Normally the variable ordering should be respected.*/2526/*Similar to normalizepol, in place*/27/*FlxX_renormalize=zxX_renormalize */28GEN29FlxX_renormalize(GEN /*in place*/ x, long lx)30{31long i;32for (i = lx-1; i>1; i--)33if (lgpol(gel(x,i))) break;34stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1));35setlg(x, i+1); setsigne(x, i!=1); return x;36}3738GEN39pol1_FlxX(long v, long sv)40{41GEN z = cgetg(3, t_POL);42z[1] = evalsigne(1) | evalvarn(v);43gel(z,2) = pol1_Flx(sv); return z;44}4546GEN47polx_FlxX(long v, long sv)48{49GEN z = cgetg(4, t_POL);50z[1] = evalsigne(1) | evalvarn(v);51gel(z,2) = pol0_Flx(sv);52gel(z,3) = pol1_Flx(sv); return z;53}5455long56FlxY_degreex(GEN b)57{58long deg = 0, i;59if (!signe(b)) return -1;60for (i = 2; i < lg(b); ++i)61deg = maxss(deg, degpol(gel(b, i)));62return deg;63}6465/*Lift coefficient of B to constant Flx, to give a FlxY*/66GEN67Fly_to_FlxY(GEN B, long sv)68{69long lb=lg(B);70long i;71GEN b=cgetg(lb,t_POL);72b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);73for (i=2; i<lb; i++)74gel(b,i) = Fl_to_Flx(B[i], sv);75return FlxX_renormalize(b, lb);76}7778GEN79zxX_to_FlxX(GEN B, ulong p)80{81long i, lb = lg(B);82GEN b = cgetg(lb,t_POL);83for (i=2; i<lb; i++)84gel(b,i) = zx_to_Flx(gel(B,i), p);85b[1] = B[1]; return FlxX_renormalize(b, lb);86}8788GEN89FlxX_to_ZXX(GEN B)90{91long i, lb = lg(B);92GEN b = cgetg(lb,t_POL);93for (i=2; i<lb; i++)94{95GEN c = gel(B,i);96switch(lgpol(c))97{98case 0: c = gen_0; break;99case 1: c = utoi(c[2]); break;100default: c = Flx_to_ZX(c); break;101}102gel(b,i) = c;103}104b[1] = B[1]; return b;105}106107GEN108FlxXC_to_ZXXC(GEN x)109{ pari_APPLY_type(t_COL, FlxX_to_ZXX(gel(x,i))) }110111GEN112FlxXM_to_ZXXM(GEN x)113{ pari_APPLY_same(FlxXC_to_ZXXC(gel(x,i))) }114115/* Note: v is used _only_ for the t_INT. It must match116* the variable of any t_POL coefficients. */117GEN118ZXX_to_FlxX(GEN B, ulong p, long v)119{120long lb=lg(B);121long i;122GEN b=cgetg(lb,t_POL);123b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);124for (i=2; i<lb; i++)125switch (typ(gel(B,i)))126{127case t_INT:128gel(b,i) = Z_to_Flx(gel(B,i), p, evalvarn(v));129break;130case t_POL:131gel(b,i) = ZX_to_Flx(gel(B,i), p);132break;133}134return FlxX_renormalize(b, lb);135}136137GEN138ZXXV_to_FlxXV(GEN x, ulong p, long v)139{ pari_APPLY_type(t_VEC, ZXX_to_FlxX(gel(x,i), p, v)) }140141GEN142ZXXT_to_FlxXT(GEN x, ulong p, long v)143{144if (typ(x) == t_POL)145return ZXX_to_FlxX(x, p, v);146else147pari_APPLY_type(t_VEC, ZXXT_to_FlxXT(gel(x,i), p, v))148}149150GEN151FlxX_to_FlxC(GEN x, long N, long sv)152{153long i, l;154GEN z;155l = lg(x)-1; x++;156if (l > N+1) l = N+1; /* truncate higher degree terms */157z = cgetg(N+1,t_COL);158for (i=1; i<l ; i++) gel(z,i) = gel(x,i);159for ( ; i<=N; i++) gel(z,i) = pol0_Flx(sv);160return z;161}162163static GEN164FlxXV_to_FlxM_lg(GEN x, long m, long n, long sv)165{166long i;167GEN y = cgetg(n+1, t_MAT);168for (i=1; i<=n; i++) gel(y,i) = FlxX_to_FlxC(gel(x,i), m, sv);169return y;170}171172GEN173FlxXV_to_FlxM(GEN v, long n, long sv)174{ return FlxXV_to_FlxM_lg(v, n, lg(v)-1, sv); }175176/* matrix whose entries are given by the coeffs of the polynomial v in177* two variables (considered as degree n polynomials) */178GEN179FlxX_to_Flm(GEN v, long n)180{181long j, N = lg(v)-1;182GEN y = cgetg(N, t_MAT);183v++;184for (j=1; j<N; j++) gel(y,j) = Flx_to_Flv(gel(v,j), n);185return y;186}187188GEN189FlxX_to_Flx(GEN f)190{191long i, l = lg(f);192GEN V = cgetg(l, t_VECSMALL);193V[1] = ((ulong)f[1])&VARNBITS;194for(i=2; i<l; i++)195V[i] = lgpol(gel(f,i)) ? mael(f,i,2): 0L;196return V;197}198199GEN200Flm_to_FlxX(GEN x, long v,long w)201{202long j, lx = lg(x);203GEN y = cgetg(lx+1, t_POL);204y[1]=evalsigne(1) | v;205y++;206for (j=1; j<lx; j++) gel(y,j) = Flv_to_Flx(gel(x,j), w);207return FlxX_renormalize(--y, lx+1);208}209210/* P(X,Y) --> P(Y,X), n is the degree in Y */211GEN212FlxX_swap(GEN x, long n, long ws)213{214long j, lx = lg(x), ly = n+3;215GEN y = cgetg(ly, t_POL);216y[1] = x[1];217for (j=2; j<ly; j++)218{219long k;220GEN p1 = cgetg(lx, t_VECSMALL);221p1[1] = ws;222for (k=2; k<lx; k++)223if (j<lg(gel(x,k)))224p1[k] = mael(x,k,j);225else226p1[k] = 0;227gel(y,j) = Flx_renormalize(p1,lx);228}229return FlxX_renormalize(y,ly);230}231232static GEN233zxX_to_Kronecker_spec(GEN P, long lp, long n)234{ /* P(X) = sum Pi(Y) * X^i, return P( Y^(2n-1) ) */235long i, j, k, l, N = (n<<1) + 1;236GEN y = cgetg((N-2)*lp + 2, t_VECSMALL) + 2;237for (k=i=0; i<lp; i++)238{239GEN c = gel(P,i);240l = lg(c);241if (l-3 >= n)242pari_err_BUG("zxX_to_Kronecker, P is not reduced mod Q");243for (j=2; j < l; j++) y[k++] = c[j];244if (i == lp-1) break;245for ( ; j < N; j++) y[k++] = 0;246}247y -= 2;248y[1] = 0; setlg(y, k+2); return y;249}250251GEN252zxX_to_Kronecker(GEN P, GEN Q)253{254GEN z = zxX_to_Kronecker_spec(P+2, lg(P)-2, degpol(Q));255z[1] = P[1]; return z;256}257258GEN259FlxX_add(GEN x, GEN y, ulong p)260{261long i,lz;262GEN z;263long lx=lg(x);264long ly=lg(y);265if (ly>lx) swapspec(x,y, lx,ly);266lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];267for (i=2; i<ly; i++) gel(z,i) = Flx_add(gel(x,i), gel(y,i), p);268for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));269return FlxX_renormalize(z, lz);270}271272GEN273FlxX_Flx_add(GEN y, GEN x, ulong p)274{275long i, lz = lg(y);276GEN z;277if (signe(y) == 0) return scalarpol(x, varn(y));278z = cgetg(lz,t_POL); z[1] = y[1];279gel(z,2) = Flx_add(gel(y,2), x, p);280if (lz == 3) z = FlxX_renormalize(z,lz);281else282for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));283return z;284}285286GEN287FlxX_Flx_sub(GEN y, GEN x, ulong p)288{289long i, lz = lg(y);290GEN z;291if (signe(y) == 0) return scalarpol(x, varn(y));292z = cgetg(lz,t_POL); z[1] = y[1];293gel(z,2) = Flx_sub(gel(y,2), x, p);294if (lz == 3) z = FlxX_renormalize(z,lz);295else296for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));297return z;298}299300GEN301FlxX_neg(GEN x, ulong p)302{303long i, lx=lg(x);304GEN z = cgetg(lx, t_POL);305z[1]=x[1];306for (i=2; i<lx; i++) gel(z,i) = Flx_neg(gel(x,i), p);307return z;308}309310GEN311FlxX_Fl_mul(GEN x, ulong y, ulong p)312{313long i, lx=lg(x);314GEN z = cgetg(lx, t_POL);315z[1]=x[1];316for (i=2; i<lx; i++) gel(z,i) = Flx_Fl_mul(gel(x,i), y, p);317return FlxX_renormalize(z, lx);318}319320GEN321FlxX_triple(GEN x, ulong p)322{323long i, lx=lg(x);324GEN z = cgetg(lx, t_POL);325z[1]=x[1];326for (i=2; i<lx; i++) gel(z,i) = Flx_triple(gel(x,i), p);327return FlxX_renormalize(z, lx);328}329330GEN331FlxX_double(GEN x, ulong p)332{333long i, lx=lg(x);334GEN z = cgetg(lx, t_POL);335z[1]=x[1];336for (i=2; i<lx; i++) gel(z,i) = Flx_double(gel(x,i), p);337return FlxX_renormalize(z, lx);338}339340GEN341FlxX_deriv(GEN z, ulong p)342{343long i,l = lg(z)-1;344GEN x;345if (l < 2) l = 2;346x = cgetg(l, t_POL); x[1] = z[1];347for (i=2; i<l; i++) gel(x,i) = Flx_mulu(gel(z,i+1), (ulong) i-1, p);348return FlxX_renormalize(x,l);349}350351GEN352FlxX_translate1(GEN P, long p, long n)353{354GEN Q;355long i, l, ws, lP = lgpol(P);356if (!lP) return gcopy(P);357ws = mael(P,2,1);358Q = FlxX_swap(P, n, ws);359l = lg(Q);360for (i=2; i<l; i++) gel(Q, i) = Flx_translate1(gel(Q, i), p);361return FlxX_swap(Q, lP, ws);362}363364GEN365zlxX_translate1(GEN P, long p, long e, long n)366{367GEN Q;368long i, l, ws, lP = lgpol(P);369if (!lP) return gcopy(P);370ws = mael(P,2,1);371Q = FlxX_swap(P, n, ws);372l = lg(Q);373for (i=2; i<l; i++) gel(Q, i) = zlx_translate1(gel(Q, i), p, e);374return FlxX_swap(Q, lP, ws);375}376377static GEN378FlxX_subspec(GEN x, GEN y, ulong p, long lx, long ly)379{380long i,lz;381GEN z;382383if (ly <= lx)384{385lz = lx+2; z = cgetg(lz, t_POL);386for (i=0; i<ly; i++) gel(z,i+2) = Flx_sub(gel(x,i),gel(y,i),p);387for ( ; i<lx; i++) gel(z,i+2) = Flx_copy(gel(x,i));388}389else390{391lz = ly+2; z = cgetg(lz, t_POL);392for (i=0; i<lx; i++) gel(z,i+2) = Flx_sub(gel(x,i),gel(y,i),p);393for ( ; i<ly; i++) gel(z,i+2) = Flx_neg(gel(y,i),p);394}395z[1] = 0; return FlxX_renormalize(z, lz);396}397398GEN399FlxX_sub(GEN x, GEN y, ulong p)400{401long lx,ly,i,lz;402GEN z;403lx = lg(x); ly = lg(y);404lz=maxss(lx,ly);405z = cgetg(lz,t_POL);406if (lx >= ly)407{408z[1] = x[1];409for (i=2; i<ly; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);410for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));411if (lx==ly) z = FlxX_renormalize(z, lz);412}413else414{415z[1] = y[1];416for (i=2; i<lx; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);417for ( ; i<ly; i++) gel(z,i) = Flx_neg(gel(y,i),p);418}419if (!lgpol(z)) { set_avma((pari_sp)(z + lz)); z = pol_0(varn(x)); }420return z;421}422423GEN424FlxX_Flx_mul(GEN P, GEN U, ulong p)425{426long i, lP = lg(P);427GEN res = cgetg(lP,t_POL);428res[1] = P[1];429for(i=2; i<lP; i++)430gel(res,i) = Flx_mul(U,gel(P,i), p);431return FlxX_renormalize(res, lP);432}433434GEN435FlxY_evalx(GEN Q, ulong x, ulong p)436{437GEN z;438long i, lb = lg(Q);439z = cgetg(lb,t_VECSMALL); z[1] = evalvarn(varn(Q));440for (i=2; i<lb; i++) z[i] = Flx_eval(gel(Q,i), x, p);441return Flx_renormalize(z, lb);442}443444GEN445FlxY_Flx_translate(GEN P, GEN c, ulong p)446{447pari_sp av = avma;448GEN Q;449long i, k, n;450451if (!signe(P) || gequal0(c)) return RgX_copy(P);452Q = leafcopy(P); n = degpol(P);453for (i=1; i<=n; i++)454{455for (k=n-i; k<n; k++)456gel(Q,2+k) = Flx_add(gel(Q,2+k), Flx_mul(gel(Q,2+k+1), c, p), p);457if (gc_needed(av,2))458{459if(DEBUGMEM>1)460pari_warn(warnmem,"FlxY_Flx_translate, i = %ld/%ld", i,n);461Q = gerepilecopy(av, Q);462}463}464return gerepilecopy(av, Q);465}466467GEN468FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi)469{470long i, len = lg(pol);471GEN res = cgetg(len, t_VECSMALL);472res[1] = pol[1] & VARNBITS;473for (i = 2; i < len; ++i)474res[i] = Flx_eval_powers_pre(gel(pol, i), ypowers, p, pi);475return Flx_renormalize(res, len);476}477478ulong479FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi)480{481pari_sp av = avma;482GEN t = FlxY_evalx_powers_pre(pol, ypowers, p, pi);483return gc_ulong(av, Flx_eval_powers_pre(t, xpowers, p, pi));484}485486GEN487FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p)488{489long i, lP = lg(P);490GEN res = cgetg(lP,t_POL);491res[1] = P[1];492for(i=2; i<lP; i++)493gel(res,i) = Flx_FlxqV_eval(gel(P,i), x, T, p);494return FlxX_renormalize(res, lP);495}496497GEN498FlxY_Flxq_evalx(GEN P, GEN x, GEN T, ulong p)499{500pari_sp av = avma;501long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(P),1);502GEN xp = Flxq_powers(x, n, T, p);503return gerepileupto(av, FlxY_FlxqV_evalx(P, xp, T, p));504}505506GEN507FlxY_Flx_div(GEN x, GEN y, ulong p)508{509long i, l;510GEN z;511if (degpol(y) == 0)512{513ulong t = uel(y,2);514if (t == 1) return x;515t = Fl_inv(t, p);516z = cgetg_copy(x, &l); z[1] = x[1];517for (i=2; i<l; i++) gel(z,i) = Flx_Fl_mul(gel(x,i),t,p);518}519else520{521z = cgetg_copy(x, &l); z[1] = x[1];522for (i=2; i<l; i++) gel(z,i) = Flx_div(gel(x,i),y,p);523}524return z;525}526527GEN528FlxX_shift(GEN a, long n, long vs)529{530long i, l = lg(a);531GEN b;532if (l == 2 || !n) return a;533l += n;534if (n < 0)535{536if (l <= 2) return pol_0(varn(a));537b = cgetg(l, t_POL); b[1] = a[1];538a -= n;539for (i=2; i<l; i++) gel(b,i) = gel(a,i);540} else {541b = cgetg(l, t_POL); b[1] = a[1];542a -= n; n += 2;543for (i=2; i<n; i++) gel(b,i) = pol0_Flx(vs);544for ( ; i<l; i++) gel(b,i) = gel(a,i);545}546return b;547}548549GEN550FlxX_blocks(GEN P, long n, long m, long vs)551{552GEN z = cgetg(m+1,t_VEC);553long i,j, k=2, l = lg(P);554for(i=1; i<=m; i++)555{556GEN zi = cgetg(n+2,t_POL);557zi[1] = P[1];558gel(z,i) = zi;559for(j=2; j<n+2; j++)560gel(zi, j) = k==l ? pol0_Flx(vs) : gel(P,k++);561zi = FlxX_renormalize(zi, n+2);562}563return z;564}565566static GEN567FlxX_recipspec(GEN x, long l, long n, long vs)568{569long i;570GEN z = cgetg(n+2,t_POL);571z[1] = 0; z += 2;572for(i=0; i<l; i++)573gel(z,n-i-1) = Flx_copy(gel(x,i));574for( ; i<n; i++)575gel(z,n-i-1) = pol0_Flx(vs);576return FlxX_renormalize(z-2,n+2);577}578579GEN580FlxX_invLaplace(GEN x, ulong p)581{582long i, d = degpol(x);583GEN y;584ulong t;585if (d <= 1) return gcopy(x);586t = Fl_inv(factorial_Fl(d, p), p);587y = cgetg(d+3, t_POL);588y[1] = x[1];589for (i=d; i>=2; i--)590{591gel(y,i+2) = Flx_Fl_mul(gel(x,i+2), t, p);592t = Fl_mul(t, i, p);593}594gel(y,3) = Flx_copy(gel(x,3));595gel(y,2) = Flx_copy(gel(x,2));596return FlxX_renormalize(y, d+3);597}598599GEN600FlxX_Laplace(GEN x, ulong p)601{602long i, d = degpol(x);603ulong t = 1;604GEN y;605if (d <= 1) return gcopy(x);606y = cgetg(d+3, t_POL);607y[1] = x[1];608gel(y,2) = Flx_copy(gel(x,2));609gel(y,3) = Flx_copy(gel(x,3));610for (i=2; i<=d; i++)611{612t = Fl_mul(t, i%p, p);613gel(y,i+2) = Flx_Fl_mul(gel(x,i+2), t, p);614}615return FlxX_renormalize(y, d+3);616}617618/***********************************************************************/619/** **/620/** FlxqX **/621/** **/622/***********************************************************************/623624static GEN625get_FlxqX_red(GEN T, GEN *B)626{627if (typ(T)!=t_VEC) { *B=NULL; return T; }628*B = gel(T,1); return gel(T,2);629}630631GEN632RgX_to_FlxqX(GEN x, GEN T, ulong p)633{634long i, l = lg(x);635GEN z = cgetg(l, t_POL); z[1] = x[1];636for (i = 2; i < l; i++)637gel(z,i) = Rg_to_Flxq(gel(x,i), T, p);638return FlxX_renormalize(z, l);639}640641/* FlxqX are t_POL with Flxq coefficients.642* Normally the variable ordering should be respected.*/643644GEN645random_FlxqX(long d1, long v, GEN T, ulong p)646{647long dT = get_Flx_degree(T), vT = get_Flx_var(T);648long i, d = d1+2;649GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);650for (i=2; i<d; i++) gel(y,i) = random_Flx(dT, vT, p);651return FlxX_renormalize(y,d);652}653654/*Not stack clean*/655GEN656Kronecker_to_FlxqX(GEN z, GEN T, ulong p)657{658long i,j,lx,l, N = (get_Flx_degree(T)<<1) + 1;659GEN x, t = cgetg(N,t_VECSMALL);660t[1] = get_Flx_var(T);661l = lg(z); lx = (l-2) / (N-2);662x = cgetg(lx+3,t_POL);663x[1] = z[1];664for (i=2; i<lx+2; i++)665{666for (j=2; j<N; j++) t[j] = z[j];667z += (N-2);668gel(x,i) = Flx_rem(Flx_renormalize(t,N), T,p);669}670N = (l-2) % (N-2) + 2;671for (j=2; j<N; j++) t[j] = z[j];672gel(x,i) = Flx_rem(Flx_renormalize(t,N), T,p);673return FlxX_renormalize(x, i+1);674}675676GEN677FlxqX_red(GEN z, GEN T, ulong p)678{679GEN res;680long i, l = lg(z);681res = cgetg(l,t_POL); res[1] = z[1];682for(i=2;i<l;i++) gel(res,i) = Flx_rem(gel(z,i),T,p);683return FlxX_renormalize(res,l);684}685686static GEN687FlxqX_mulspec(GEN x, GEN y, GEN T, ulong p, long lx, long ly)688{689pari_sp ltop=avma;690GEN z,kx,ky;691long dT = get_Flx_degree(T);692kx= zxX_to_Kronecker_spec(x,lx,dT);693ky= zxX_to_Kronecker_spec(y,ly,dT);694z = Flx_mul(ky, kx, p);695z = Kronecker_to_FlxqX(z,T,p);696return gerepileupto(ltop,z);697}698699GEN700FlxqX_mul(GEN x, GEN y, GEN T, ulong p)701{702pari_sp ltop=avma;703GEN z, kx, ky, Tm = get_Flx_mod(T);704kx= zxX_to_Kronecker(x, Tm);705ky= zxX_to_Kronecker(y, Tm);706z = Flx_mul(ky, kx, p);707z = Kronecker_to_FlxqX(z, T, p);708return gerepileupto(ltop, z);709}710711GEN712FlxqX_sqr(GEN x, GEN T, ulong p)713{714pari_sp ltop=avma;715GEN z,kx;716kx= zxX_to_Kronecker(x,get_Flx_mod(T));717z = Flx_sqr(kx, p);718z = Kronecker_to_FlxqX(z,T,p);719return gerepileupto(ltop,z);720}721722GEN723FlxqX_Flxq_mul(GEN P, GEN U, GEN T, ulong p)724{725long i, lP = lg(P);726GEN res = cgetg(lP,t_POL);727res[1] = P[1];728for(i=2; i<lP; i++)729gel(res,i) = Flxq_mul(U,gel(P,i), T,p);730return FlxX_renormalize(res, lP);731}732GEN733FlxqX_Flxq_mul_to_monic(GEN P, GEN U, GEN T, ulong p)734{735long i, lP = lg(P);736GEN res = cgetg(lP,t_POL);737res[1] = P[1];738for(i=2; i<lP-1; i++) gel(res,i) = Flxq_mul(U,gel(P,i), T,p);739gel(res,lP-1) = pol1_Flx(get_Flx_var(T));740return FlxX_renormalize(res, lP);741}742743GEN744FlxqX_normalize(GEN z, GEN T, ulong p)745{746GEN p1 = leading_coeff(z);747if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;748return FlxqX_Flxq_mul_to_monic(z, Flxq_inv(p1,T,p), T,p);749}750751/* x and y in Z[Y][X]. Assume T irreducible mod p */752static GEN753FlxqX_divrem_basecase(GEN x, GEN y, GEN T, ulong p, GEN *pr)754{755long vx, dx, dy, dz, i, j, sx, lr;756pari_sp av0, av, tetpil;757GEN z,p1,rem,lead;758759if (!signe(y)) pari_err_INV("FlxqX_divrem",y);760vx=varn(x); dy=degpol(y); dx=degpol(x);761if (dx < dy)762{763if (pr)764{765av0 = avma; x = FlxqX_red(x, T, p);766if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }767if (pr == ONLY_REM) return x;768*pr = x;769}770return pol_0(vx);771}772lead = leading_coeff(y);773if (!dy) /* y is constant */774{775if (pr && pr != ONLY_DIVIDES)776{777if (pr == ONLY_REM) return pol_0(vx);778*pr = pol_0(vx);779}780if (Flx_equal1(lead)) return gcopy(x);781av0 = avma; x = FlxqX_Flxq_mul(x,Flxq_inv(lead,T,p),T,p);782return gerepileupto(av0,x);783}784av0 = avma; dz = dx-dy;785lead = Flx_equal1(lead)? NULL: gclone(Flxq_inv(lead,T,p));786set_avma(av0);787z = cgetg(dz+3,t_POL); z[1] = x[1];788x += 2; y += 2; z += 2;789790p1 = gel(x,dx); av = avma;791gel(z,dz) = lead? gerepileupto(av, Flxq_mul(p1,lead, T, p)): gcopy(p1);792for (i=dx-1; i>=dy; i--)793{794av=avma; p1=gel(x,i);795for (j=i-dy+1; j<=i && j<=dz; j++)796p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p);797if (lead) p1 = Flx_mul(p1, lead,p);798tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,Flx_rem(p1,T,p));799}800if (!pr) { guncloneNULL(lead); return z-2; }801802rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);803for (sx=0; ; i--)804{805p1 = gel(x,i);806for (j=0; j<=i && j<=dz; j++)807p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p);808tetpil=avma; p1 = Flx_rem(p1, T, p); if (lgpol(p1)) { sx = 1; break; }809if (!i) break;810set_avma(av);811}812if (pr == ONLY_DIVIDES)813{814guncloneNULL(lead);815if (sx) return gc_NULL(av0);816return gc_const((pari_sp)rem, z-2);817}818lr=i+3; rem -= lr;819rem[0] = evaltyp(t_POL) | evallg(lr);820rem[1] = z[-1];821p1 = gerepile((pari_sp)rem,tetpil,p1);822rem += 2; gel(rem,i) = p1;823for (i--; i>=0; i--)824{825av=avma; p1 = gel(x,i);826for (j=0; j<=i && j<=dz; j++)827p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p), p);828tetpil=avma; gel(rem,i) = gerepile(av,tetpil, Flx_rem(p1, T, p));829}830rem -= 2;831guncloneNULL(lead);832if (!sx) (void)FlxX_renormalize(rem, lr);833if (pr == ONLY_REM) return gerepileupto(av0,rem);834*pr = rem; return z-2;835}836837static GEN838FlxqX_invBarrett_basecase(GEN T, GEN Q, ulong p)839{840long i, l=lg(T)-1, lr = l-1, k;841long sv=Q[1];842GEN r=cgetg(lr,t_POL); r[1]=T[1];843gel(r,2) = pol1_Flx(sv);844for (i=3;i<lr;i++)845{846pari_sp ltop=avma;847GEN u = Flx_neg(gel(T,l-i+2),p);848for (k=3;k<i;k++)849u = Flx_sub(u, Flxq_mul(gel(T,l-i+k),gel(r,k),Q,p),p);850gel(r,i) = gerepileupto(ltop, u);851}852r = FlxX_renormalize(r,lr);853return r;854}855856/* Return new lgpol */857static long858FlxX_lgrenormalizespec(GEN x, long lx)859{860long i;861for (i = lx-1; i>=0; i--)862if (lgpol(gel(x,i))) break;863return i+1;864}865866static GEN867FlxqX_invBarrett_Newton(GEN S, GEN T, ulong p)868{869pari_sp av = avma;870long nold, lx, lz, lq, l = degpol(S), i, lQ;871GEN q, y, z, x = cgetg(l+2, t_POL) + 2;872long dT = get_Flx_degree(T), vT = get_Flx_var(T);873ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */874for (i=0;i<l;i++) gel(x,i) = pol0_Flx(vT);875q = FlxX_recipspec(S+2,l+1,l+1,dT);876lQ = lgpol(q); q+=2;877/* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */878879/* initialize */880gel(x,0) = Flxq_inv(gel(q,0),T, p);881if (lQ>1 && degpol(gel(q,1)) >= dT)882gel(q,1) = Flx_rem(gel(q,1), T, p);883if (lQ>1 && lgpol(gel(q,1)))884{885GEN u = gel(q, 1);886if (!Flx_equal1(gel(x,0))) u = Flxq_mul(u, Flxq_sqr(gel(x,0), T,p), T,p);887gel(x,1) = Flx_neg(u, p); lx = 2;888}889else890lx = 1;891nold = 1;892for (; mask > 1; )893{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */894long i, lnew, nnew = nold << 1;895896if (mask & 1) nnew--;897mask >>= 1;898899lnew = nnew + 1;900lq = FlxX_lgrenormalizespec(q, minss(lQ,lnew));901z = FlxqX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */902lz = lgpol(z); if (lz > lnew) lz = lnew;903z += 2;904/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */905for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;906nold = nnew;907if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */908909/* z + i represents (x*q - 1) / t^i */910lz = FlxX_lgrenormalizespec (z+i, lz-i);911z = FlxqX_mulspec(x, z+i, T,p, lx, lz); /* FIXME: low product */912lz = lgpol(z); z += 2;913if (lz > lnew-i) lz = FlxX_lgrenormalizespec(z, lnew-i);914915lx = lz+ i;916y = x + i; /* x -= z * t^i, in place */917for (i = 0; i < lz; i++) gel(y,i) = Flx_neg(gel(z,i), p);918}919x -= 2; setlg(x, lx + 2); x[1] = S[1];920return gerepilecopy(av, x);921}922923GEN924FlxqX_invBarrett(GEN T, GEN Q, ulong p)925{926pari_sp ltop=avma;927long l=lg(T), v = varn(T);928GEN r;929GEN c = gel(T,l-1);930if (l<5) return pol_0(v);931if (l<=FlxqX_INVBARRETT_LIMIT)932{933if (!Flx_equal1(c))934{935GEN ci = Flxq_inv(c,Q,p);936T = FlxqX_Flxq_mul(T, ci, Q, p);937r = FlxqX_invBarrett_basecase(T,Q,p);938r = FlxqX_Flxq_mul(r,ci,Q,p);939} else940r = FlxqX_invBarrett_basecase(T,Q,p);941} else942r = FlxqX_invBarrett_Newton(T,Q,p);943return gerepileupto(ltop, r);944}945946GEN947FlxqX_get_red(GEN S, GEN T, ulong p)948{949if (typ(S)==t_POL && lg(S)>FlxqX_BARRETT_LIMIT)950retmkvec2(FlxqX_invBarrett(S, T, p), S);951return S;952}953954/* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)955* * and mg is the Barrett inverse of S. */956static GEN957FlxqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, ulong p, GEN *pr)958{959GEN q, r;960long lt = degpol(S); /*We discard the leading term*/961long ld, lm, lT, lmg;962ld = l-lt;963lm = minss(ld, lgpol(mg));964lT = FlxX_lgrenormalizespec(S+2,lt);965lmg = FlxX_lgrenormalizespec(mg+2,lm);966q = FlxX_recipspec(x+lt,ld,ld,0); /* q = rec(x) lq<=ld*/967q = FlxqX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/968q = FlxX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/969if (!pr) return q;970r = FlxqX_mulspec(q+2,S+2,T,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/971r = FlxX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */972if (pr == ONLY_REM) return r;973*pr = r; return q;974}975976static GEN977FlxqX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, ulong p, GEN *pr)978{979GEN q = NULL, r = FlxqX_red(x, T, p);980long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);981long i;982if (l <= lt)983{984if (pr == ONLY_REM) return r;985if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);986if (pr) *pr = r;987return pol_0(v);988}989if (lt <= 1)990return FlxqX_divrem_basecase(x,S,T,p,pr);991if (pr != ONLY_REM && l>lm)992{993long vT = get_Flx_var(T);994q = cgetg(l-lt+2, t_POL); q[1] = S[1];995for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_Flx(vT);996}997while (l>lm)998{999GEN zr, zq = FlxqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr);1000long lz = lgpol(zr);1001if (pr != ONLY_REM)1002{1003long lq = lgpol(zq);1004for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);1005}1006for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);1007l = l-lm+lz;1008}1009if (pr == ONLY_REM)1010{1011if (l > lt)1012r = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,ONLY_REM);1013else1014r = FlxX_renormalize(r, l+2);1015setvarn(r, v); return r;1016}1017if (l > lt)1018{1019GEN zq = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,pr? &r: NULL);1020if (!q) q = zq;1021else1022{1023long lq = lgpol(zq);1024for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);1025}1026}1027else if (pr)1028r = FlxX_renormalize(r, l+2);1029setvarn(q, v); q = FlxX_renormalize(q, lg(q));1030if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;1031if (pr) { setvarn(r, v); *pr = r; }1032return q;1033}10341035GEN1036FlxqX_divrem(GEN x, GEN S, GEN T, ulong p, GEN *pr)1037{1038GEN B, y;1039long dy, dx, d;1040if (pr==ONLY_REM) return FlxqX_rem(x, S, T, p);1041y = get_FlxqX_red(S, &B);1042dy = degpol(y); dx = degpol(x); d = dx-dy;1043if (!B && d+3 < FlxqX_DIVREM_BARRETT_LIMIT)1044return FlxqX_divrem_basecase(x,y,T,p,pr);1045else1046{1047pari_sp av = avma;1048GEN mg = B? B: FlxqX_invBarrett(y, T, p);1049GEN q = FlxqX_divrem_Barrett(x,mg,y,T,p,pr);1050if (!q) return gc_NULL(av);1051if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q);1052gerepileall(av,2,&q,pr);1053return q;1054}1055}10561057GEN1058FlxqX_rem(GEN x, GEN S, GEN T, ulong p)1059{1060GEN B, y = get_FlxqX_red(S, &B);1061long dy = degpol(y), dx = degpol(x), d = dx-dy;1062if (d < 0) return FlxqX_red(x, T, p);1063if (!B && d+3 < FlxqX_REM_BARRETT_LIMIT)1064return FlxqX_divrem_basecase(x,y, T, p, ONLY_REM);1065else1066{1067pari_sp av=avma;1068GEN mg = B? B: FlxqX_invBarrett(y, T, p);1069GEN r = FlxqX_divrem_Barrett(x, mg, y, T, p, ONLY_REM);1070return gerepileupto(av, r);1071}1072}10731074static GEN1075FlxqX_halfgcd_basecase(GEN a, GEN b, GEN T, ulong p)1076{1077pari_sp av=avma;1078GEN u,u1,v,v1;1079long vx = varn(a);1080long n = lgpol(a)>>1;1081u1 = v = pol_0(vx);1082u = v1 = pol1_FlxX(vx, get_Flx_var(T));1083while (lgpol(b)>n)1084{1085GEN r, q = FlxqX_divrem(a,b, T, p, &r);1086a = b; b = r; swap(u,u1); swap(v,v1);1087u1 = FlxX_sub(u1, FlxqX_mul(u, q, T, p), p);1088v1 = FlxX_sub(v1, FlxqX_mul(v, q ,T, p), p);1089if (gc_needed(av,2))1090{1091if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_halfgcd (d = %ld)",degpol(b));1092gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);1093}1094}1095return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));1096}1097static GEN1098FlxqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, ulong p)1099{1100return FlxX_add(FlxqX_mul(u, x, T, p),FlxqX_mul(v, y, T, p), p);1101}11021103static GEN1104FlxqXM_FlxqX_mul2(GEN M, GEN x, GEN y, GEN T, ulong p)1105{1106GEN res = cgetg(3, t_COL);1107gel(res, 1) = FlxqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p);1108gel(res, 2) = FlxqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p);1109return res;1110}11111112static GEN1113FlxqXM_mul2(GEN A, GEN B, GEN T, ulong p)1114{1115GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);1116GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);1117GEN M1 = FlxqX_mul(FlxX_add(A11,A22, p), FlxX_add(B11,B22, p), T, p);1118GEN M2 = FlxqX_mul(FlxX_add(A21,A22, p), B11, T, p);1119GEN M3 = FlxqX_mul(A11, FlxX_sub(B12,B22, p), T, p);1120GEN M4 = FlxqX_mul(A22, FlxX_sub(B21,B11, p), T, p);1121GEN M5 = FlxqX_mul(FlxX_add(A11,A12, p), B22, T, p);1122GEN M6 = FlxqX_mul(FlxX_sub(A21,A11, p), FlxX_add(B11,B12, p), T, p);1123GEN M7 = FlxqX_mul(FlxX_sub(A12,A22, p), FlxX_add(B21,B22, p), T, p);1124GEN T1 = FlxX_add(M1,M4, p), T2 = FlxX_sub(M7,M5, p);1125GEN T3 = FlxX_sub(M1,M2, p), T4 = FlxX_add(M3,M6, p);1126retmkmat2(mkcol2(FlxX_add(T1,T2, p), FlxX_add(M2,M4, p)),1127mkcol2(FlxX_add(M3,M5, p), FlxX_add(T3,T4, p)));1128}11291130/* Return [0,1;1,-q]*M */1131static GEN1132FlxqX_FlxqXM_qmul(GEN q, GEN M, GEN T, ulong p)1133{1134GEN u, v, res = cgetg(3, t_MAT);1135u = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(gcoeff(M,2,1), q, T, p), p);1136gel(res,1) = mkcol2(gcoeff(M,2,1), u);1137v = FlxX_sub(gcoeff(M,1,2), FlxqX_mul(gcoeff(M,2,2), q, T, p), p);1138gel(res,2) = mkcol2(gcoeff(M,2,2), v);1139return res;1140}11411142static GEN1143matid2_FlxXM(long v, long sv)1144{1145retmkmat2(mkcol2(pol1_FlxX(v, sv),pol_0(v)),1146mkcol2(pol_0(v),pol1_FlxX(v, sv)));1147}11481149static GEN1150FlxqX_halfgcd_split(GEN x, GEN y, GEN T, ulong p)1151{1152pari_sp av=avma;1153GEN R, S, V;1154GEN y1, r, q;1155long l = lgpol(x), n = l>>1, k;1156long vT = get_Flx_var(T);1157if (lgpol(y)<=n) return matid2_FlxXM(varn(x),vT);1158R = FlxqX_halfgcd(FlxX_shift(x,-n,vT),FlxX_shift(y,-n,vT), T, p);1159V = FlxqXM_FlxqX_mul2(R,x,y, T, p); y1 = gel(V,2);1160if (lgpol(y1)<=n) return gerepilecopy(av, R);1161q = FlxqX_divrem(gel(V,1), y1, T, p, &r);1162k = 2*n-degpol(y1);1163S = FlxqX_halfgcd(FlxX_shift(y1,-k,vT), FlxX_shift(r,-k,vT), T, p);1164return gerepileupto(av, FlxqXM_mul2(S,FlxqX_FlxqXM_qmul(q,R, T, p), T, p));1165}11661167/* Return M in GL_2(Fp[X]) such that:1168if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')1169*/11701171static GEN1172FlxqX_halfgcd_i(GEN x, GEN y, GEN T, ulong p)1173{1174if (lg(x)<=FlxqX_HALFGCD_LIMIT) return FlxqX_halfgcd_basecase(x, y, T, p);1175return FlxqX_halfgcd_split(x, y, T, p);1176}11771178GEN1179FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p)1180{1181pari_sp av = avma;1182GEN M,q,r;1183if (!signe(x))1184{1185long v = varn(x), vT = get_Flx_var(T);1186retmkmat2(mkcol2(pol_0(v),pol1_FlxX(v,vT)),1187mkcol2(pol1_FlxX(v,vT),pol_0(v)));1188}1189if (degpol(y)<degpol(x)) return FlxqX_halfgcd_i(x, y, T, p);1190q = FlxqX_divrem(y, x, T, p, &r);1191M = FlxqX_halfgcd_i(x, r, T, p);1192gcoeff(M,1,1) = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(q, gcoeff(M,1,2), T, p), p);1193gcoeff(M,2,1) = FlxX_sub(gcoeff(M,2,1), FlxqX_mul(q, gcoeff(M,2,2), T, p), p);1194return gerepilecopy(av, M);1195}11961197static GEN1198FlxqX_gcd_basecase(GEN a, GEN b, GEN T, ulong p)1199{1200pari_sp av = avma, av0=avma;1201while (signe(b))1202{1203GEN c;1204if (gc_needed(av0,2))1205{1206if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_gcd (d = %ld)",degpol(b));1207gerepileall(av0,2, &a,&b);1208}1209av = avma; c = FlxqX_rem(a, b, T, p); a=b; b=c;1210}1211return gc_const(av, a);1212}12131214GEN1215FlxqX_gcd(GEN x, GEN y, GEN T, ulong p)1216{1217pari_sp av = avma;1218x = FlxqX_red(x, T, p);1219y = FlxqX_red(y, T, p);1220if (!signe(x)) return gerepileupto(av, y);1221while (lg(y)>FlxqX_GCD_LIMIT)1222{1223GEN c;1224if (lgpol(y)<=(lgpol(x)>>1))1225{1226GEN r = FlxqX_rem(x, y, T, p);1227x = y; y = r;1228}1229c = FlxqXM_FlxqX_mul2(FlxqX_halfgcd(x,y, T, p), x, y, T, p);1230x = gel(c,1); y = gel(c,2);1231gerepileall(av,2,&x,&y);1232}1233return gerepileupto(av, FlxqX_gcd_basecase(x, y, T, p));1234}12351236static GEN1237FlxqX_extgcd_basecase(GEN a, GEN b, GEN T, ulong p, GEN *ptu, GEN *ptv)1238{1239pari_sp av=avma;1240GEN u,v,d,d1,v1;1241long vx = varn(a);1242d = a; d1 = b;1243v = pol_0(vx); v1 = pol1_FlxX(vx, get_Flx_var(T));1244while (signe(d1))1245{1246GEN r, q = FlxqX_divrem(d, d1, T, p, &r);1247v = FlxX_sub(v,FlxqX_mul(q,v1,T, p),p);1248u=v; v=v1; v1=u;1249u=r; d=d1; d1=u;1250if (gc_needed(av,2))1251{1252if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_extgcd (d = %ld)",degpol(d));1253gerepileall(av,5, &d,&d1,&u,&v,&v1);1254}1255}1256if (ptu) *ptu = FlxqX_div(FlxX_sub(d,FlxqX_mul(b,v, T, p), p), a, T, p);1257*ptv = v; return d;1258}12591260static GEN1261FlxqX_extgcd_halfgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)1262{1263pari_sp av=avma;1264GEN u,v,R = matid2_FlxXM(varn(x), get_Flx_var(T));1265while (lg(y)>FlxqX_EXTGCD_LIMIT)1266{1267GEN M, c;1268if (lgpol(y)<=(lgpol(x)>>1))1269{1270GEN r, q = FlxqX_divrem(x, y, T, p, &r);1271x = y; y = r;1272R = FlxqX_FlxqXM_qmul(q, R, T, p);1273}1274M = FlxqX_halfgcd(x,y, T, p);1275c = FlxqXM_FlxqX_mul2(M, x,y, T, p);1276R = FlxqXM_mul2(M, R, T, p);1277x = gel(c,1); y = gel(c,2);1278gerepileall(av,3,&x,&y,&R);1279}1280y = FlxqX_extgcd_basecase(x,y, T, p, &u,&v);1281if (ptu) *ptu = FlxqX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T, p);1282*ptv = FlxqX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T, p);1283return y;1284}12851286/* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st1287* ux + vy = gcd (mod T,p) */1288GEN1289FlxqX_extgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)1290{1291GEN d;1292pari_sp ltop=avma;1293x = FlxqX_red(x, T, p);1294y = FlxqX_red(y, T, p);1295if (lg(y)>FlxqX_EXTGCD_LIMIT)1296d = FlxqX_extgcd_halfgcd(x, y, T, p, ptu, ptv);1297else1298d = FlxqX_extgcd_basecase(x, y, T, p, ptu, ptv);1299gerepileall(ltop,ptu?3:2,&d,ptv,ptu);1300return d;1301}13021303static GEN1304FlxqX_saferem(GEN P, GEN Q, GEN T, ulong p)1305{1306GEN U = Flxq_invsafe(leading_coeff(Q), T, p);1307if (!U) return NULL;1308Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p);1309return FlxqX_rem(P,Q,T,p);1310}13111312GEN1313FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p)1314{1315pari_sp av = avma;1316GEN U;1317if (!signe(P)) return gcopy(Q);1318if (!signe(Q)) return gcopy(P);1319T = Flx_get_red(T,p);1320for(;;)1321{1322P = FlxqX_saferem(P,Q,T,p);1323if (!P) return gc_NULL(av);1324if (!signe(P)) break;1325if (gc_needed(av, 1))1326{1327if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_safegcd");1328gerepileall(av, 2, &P,&Q);1329}1330swap(P, Q);1331}1332U = Flxq_invsafe(leading_coeff(Q), T, p);1333if (!U) return gc_NULL(av);1334Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p);1335return gerepileupto(av, Q);1336}13371338struct _FlxqX {ulong p; GEN T;};1339static GEN _FlxqX_mul(void *data,GEN a,GEN b)1340{1341struct _FlxqX *d=(struct _FlxqX*)data;1342return FlxqX_mul(a,b,d->T,d->p);1343}1344static GEN _FlxqX_sqr(void *data,GEN a)1345{1346struct _FlxqX *d=(struct _FlxqX*)data;1347return FlxqX_sqr(a,d->T,d->p);1348}13491350GEN1351FlxqX_powu(GEN V, ulong n, GEN T, ulong p)1352{1353struct _FlxqX d; d.p=p; d.T=T;1354return gen_powu(V, n, (void*)&d, &_FlxqX_sqr, &_FlxqX_mul);1355}13561357/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/1358GEN1359FlxqX_saferesultant(GEN a, GEN b, GEN T, ulong p)1360{1361long vT = get_Flx_var(T);1362long da,db,dc;1363pari_sp av;1364GEN c,lb, res = pol1_Flx(vT);13651366if (!signe(a) || !signe(b)) return pol0_Flx(vT);13671368da = degpol(a);1369db = degpol(b);1370if (db > da)1371{1372swapspec(a,b, da,db);1373if (both_odd(da,db)) res = Flx_neg(res, p);1374}1375if (!da) return pol1_Flx(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */1376av = avma;1377while (db)1378{1379lb = gel(b,db+2);1380c = FlxqX_saferem(a,b, T,p);1381if (!c) return gc_NULL(av);1382a = b; b = c; dc = degpol(c);1383if (dc < 0) { set_avma(av); return pol0_Flx(vT); }13841385if (both_odd(da,db)) res = Flx_neg(res, p);1386if (!equali1(lb)) res = Flxq_mul(res, Flxq_powu(lb, da - dc, T, p), T, p);1387if (gc_needed(av,2))1388{1389if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (da = %ld)",da);1390gerepileall(av,3, &a,&b,&res);1391}1392da = db; /* = degpol(a) */1393db = dc; /* = degpol(b) */1394}1395res = Flxq_mul(res, Flxq_powu(gel(b,2), da, T, p), T, p);1396return gerepileupto(av, res);1397}13981399/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/1400GEN1401FlxqX_resultant(GEN a, GEN b, GEN T, ulong p)1402{1403long vT = get_Flx_var(T);1404long da,db,dc;1405pari_sp av;1406GEN c,lb, res = pol1_Flx(vT);14071408if (!signe(a) || !signe(b)) return pol0_Flx(vT);14091410da = degpol(a);1411db = degpol(b);1412if (db > da)1413{1414swapspec(a,b, da,db);1415if (both_odd(da,db)) res = Flx_neg(res, p);1416}1417if (!da) return pol1_Flx(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */1418av = avma;1419while (db)1420{1421lb = gel(b,db+2);1422c = FlxqX_rem(a,b, T,p);1423a = b; b = c; dc = degpol(c);1424if (dc < 0) { set_avma(av); return pol0_Flx(vT); }14251426if (both_odd(da,db)) res = Flx_neg(res, p);1427if (!equali1(lb)) res = Flxq_mul(res, Flxq_powu(lb, da - dc, T, p), T, p);1428if (gc_needed(av,2))1429{1430if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (da = %ld)",da);1431gerepileall(av,3, &a,&b,&res);1432}1433da = db; /* = degpol(a) */1434db = dc; /* = degpol(b) */1435}1436res = Flxq_mul(res, Flxq_powu(gel(b,2), da, T, p), T, p);1437return gerepileupto(av, res);1438}14391440/* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */1441GEN1442FlxqX_disc(GEN P, GEN T, ulong p)1443{1444pari_sp av = avma;1445GEN L, dP = FlxX_deriv(P, p), D = FlxqX_resultant(P, dP, T, p);1446long dd;1447if (!lgpol(D)) return pol0_Flx(get_Flx_var(T));1448dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */1449L = leading_coeff(P);1450if (dd && !Flx_equal1(L))1451D = (dd == -1)? Flxq_div(D,L,T,p): Flxq_mul(D, Flxq_powu(L, dd, T, p), T, p);1452if (degpol(P) & 2) D = Flx_neg(D, p);1453return gerepileupto(av, D);1454}14551456INLINE GEN1457FlxXn_recip(GEN x, long n, long v)1458{1459return FlxX_recipspec(x+2, minss(lgpol(x), n), n, v);1460}14611462GEN1463FlxqX_Newton(GEN P, long n, GEN T, ulong p)1464{1465pari_sp av = avma;1466long d = degpol(P), vT = get_Flx_var(T);1467GEN dP = FlxXn_recip(FlxX_deriv(P, p), d, vT);1468GEN Q = FlxqXn_mul(FlxqXn_inv(FlxXn_recip(P, d+1, vT), n, T, p), dP, n, T, p);1469return gerepilecopy(av, Q);1470}14711472GEN1473FlxqX_fromNewton(GEN P, GEN T, ulong p)1474{1475pari_sp av = avma;1476long vT = get_Flx_var(T);1477long n = Flx_constant(constant_coeff(P))+1;1478GEN z = FlxX_neg(FlxX_shift(P, -1, vT), p);1479GEN Q = FlxXn_recip(FlxqXn_expint(z, n, T, p), n, vT);1480return gerepilecopy(av, Q);1481}14821483static GEN1484FlxqX_composedsum(GEN P, GEN Q, GEN T, ulong p)1485{1486long n = 1+ degpol(P)*degpol(Q);1487GEN Pl = FlxX_invLaplace(FlxqX_Newton(P,n, T,p), p);1488GEN Ql = FlxX_invLaplace(FlxqX_Newton(Q,n, T,p), p);1489GEN L = FlxX_Laplace(FlxqXn_mul(Pl, Ql, n, T,p), p);1490GEN R = FlxqX_fromNewton(L, T, p);1491GEN lead = Flxq_mul(Flxq_powu(leading_coeff(P),degpol(Q), T, p),1492Flxq_powu(leading_coeff(Q),degpol(P), T, p), T, p);1493return FlxqX_Flxq_mul(R, lead, T, p);1494}14951496GEN1497FlxqX_direct_compositum(GEN P, GEN Q, GEN T, ulong p)1498{1499return FlxqX_composedsum(P, Q, T, p);1500}15011502GEN1503FlxqXV_prod(GEN V, GEN T, ulong p)1504{1505struct _FlxqX d; d.p=p; d.T=T;1506return gen_product(V, (void*)&d, &_FlxqX_mul);1507}15081509static GEN1510FlxqV_roots_to_deg1(GEN x, GEN T, ulong p, long v)1511{1512long sv = get_Flx_var(T);1513pari_APPLY_same(deg1pol_shallow(pol1_Flx(sv),Flx_neg(gel(x,i),p),v))1514}15151516GEN1517FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v)1518{1519pari_sp ltop = avma;1520GEN W = FlxqV_roots_to_deg1(V, T, p, v);1521return gerepileupto(ltop, FlxqXV_prod(W, T, p));1522}15231524/*******************************************************************/1525/* */1526/* (Fl[X]/T(X))[Y] / S(Y) */1527/* */1528/*******************************************************************/15291530GEN1531FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p) {1532return FlxqX_rem(FlxqX_mul(x,y,T,p),S,T,p);1533}15341535GEN1536FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p) {1537return FlxqX_rem(FlxqX_sqr(x,T,p),S,T,p);1538}15391540GEN1541FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p)1542{1543GEN V, z = FlxqX_extgcd(get_FlxqX_mod(S), x, T, p, NULL, &V);1544if (degpol(z)) return NULL;1545z = Flxq_invsafe(gel(z,2),T,p);1546if (!z) return NULL;1547return FlxqX_Flxq_mul(V, z, T, p);1548}15491550GEN1551FlxqXQ_inv(GEN x, GEN S, GEN T,ulong p)1552{1553pari_sp av = avma;1554GEN U = FlxqXQ_invsafe(x, S, T, p);1555if (!U) pari_err_INV("FlxqXQ_inv",x);1556return gerepileupto(av, U);1557}15581559GEN1560FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p) {1561return FlxqXQ_mul(x, FlxqXQ_inv(y,S,T,p),S,T,p);1562}15631564struct _FlxqXQ {1565GEN T, S;1566ulong p;1567};1568static GEN1569_FlxqXQ_add(void *data, GEN x, GEN y) {1570struct _FlxqXQ *d = (struct _FlxqXQ*) data;1571return FlxX_add(x,y, d->p);1572}1573static GEN1574_FlxqXQ_sub(void *data, GEN x, GEN y) {1575struct _FlxqXQ *d = (struct _FlxqXQ*) data;1576return FlxX_sub(x,y, d->p);1577}1578#if 01579static GEN1580_FlxqXQ_cmul(void *data, GEN P, long a, GEN x) {1581struct _FlxqXQ *d = (struct _FlxqXQ*) data;1582return FlxX_Flx_mul(x,gel(P,a+2), d->p);1583}1584#endif1585static GEN1586_FlxqXQ_red(void *data, GEN x) {1587struct _FlxqXQ *d = (struct _FlxqXQ*) data;1588return FlxqX_red(x, d->T, d->p);1589}1590static GEN1591_FlxqXQ_mul(void *data, GEN x, GEN y) {1592struct _FlxqXQ *d = (struct _FlxqXQ*) data;1593return FlxqXQ_mul(x,y, d->S,d->T, d->p);1594}1595static GEN1596_FlxqXQ_sqr(void *data, GEN x) {1597struct _FlxqXQ *d = (struct _FlxqXQ*) data;1598return FlxqXQ_sqr(x, d->S,d->T, d->p);1599}16001601static GEN1602_FlxqXQ_one(void *data) {1603struct _FlxqXQ *d = (struct _FlxqXQ*) data;1604return pol1_FlxX(get_FlxqX_var(d->S),get_Flx_var(d->T));1605}16061607static GEN1608_FlxqXQ_zero(void *data) {1609struct _FlxqXQ *d = (struct _FlxqXQ*) data;1610return pol_0(get_FlxqX_var(d->S));1611}16121613static struct bb_algebra FlxqXQ_algebra = { _FlxqXQ_red, _FlxqXQ_add,1614_FlxqXQ_sub, _FlxqXQ_mul, _FlxqXQ_sqr, _FlxqXQ_one, _FlxqXQ_zero };16151616const struct bb_algebra *1617get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p)1618{1619GEN z = new_chunk(sizeof(struct _FlxqXQ));1620struct _FlxqXQ *e = (struct _FlxqXQ *) z;1621e->T = Flx_get_red(T, p);1622e->S = FlxqX_get_red(S, e->T, p);1623e->p = p; *E = (void*)e;1624return &FlxqXQ_algebra;1625}16261627/* x over Fq, return lift(x^n) mod S */1628GEN1629FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p)1630{1631pari_sp av = avma;1632struct _FlxqXQ D;1633long s = signe(n);1634if (!s) return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));1635if (s < 0) x = FlxqXQ_inv(x,S,T,p);1636if (is_pm1(n)) return s < 0 ? x : gcopy(x);1637if (degpol(x) >= get_FlxqX_degree(S)) x = FlxqX_rem(x,S,T,p);1638T = Flx_get_red(T, p);1639S = FlxqX_get_red(S, T, p);1640D.S = S;1641D.T = T;1642D.p = p;1643x = gen_pow_i(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);1644return gerepilecopy(av, x);1645}16461647/* x over Fq, return lift(x^n) mod S */1648GEN1649FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p)1650{1651pari_sp av = avma;1652struct _FlxqXQ D;1653switch(n)1654{1655case 0: return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));1656case 1: return gcopy(x);1657case 2: return FlxqXQ_sqr(x, S, T, p);1658}1659T = Flx_get_red(T, p);1660S = FlxqX_get_red(S, T, p);1661D.S = S; D.T = T; D.p = p;1662x = gen_powu_i(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);1663return gerepilecopy(av, x);1664}16651666GEN1667FlxqXQ_powers(GEN x, long l, GEN S, GEN T, ulong p)1668{1669struct _FlxqXQ D;1670int use_sqr = 2*degpol(x) >= get_FlxqX_degree(S);1671T = Flx_get_red(T, p);1672S = FlxqX_get_red(S, T, p);1673D.S = S; D.T = T; D.p = p;1674return gen_powers(x, l, use_sqr, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul,&_FlxqXQ_one);1675}16761677/* Let v a linear form, return the linear form z->v(tau*z)1678that is, v*(M_tau) */16791680static GEN1681FlxqXQ_transmul_init(GEN tau, GEN S, GEN T, ulong p)1682{1683GEN bht;1684GEN h, Sp = get_FlxqX_red(S, &h);1685long n = degpol(Sp), vS = varn(Sp), vT = get_Flx_var(T);1686GEN ft = FlxX_recipspec(Sp+2, n+1, n+1, vT);1687GEN bt = FlxX_recipspec(tau+2, lgpol(tau), n, vT);1688setvarn(ft, vS); setvarn(bt, vS);1689if (h)1690bht = FlxqXn_mul(bt, h, n-1, T, p);1691else1692{1693GEN bh = FlxqX_div(FlxX_shift(tau, n-1, vT), S, T, p);1694bht = FlxX_recipspec(bh+2, lgpol(bh), n-1, vT);1695setvarn(bht, vS);1696}1697return mkvec3(bt, bht, ft);1698}16991700static GEN1701FlxqXQ_transmul(GEN tau, GEN a, long n, GEN T, ulong p)1702{1703pari_sp ltop = avma;1704GEN t1, t2, t3, vec;1705GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);1706long vT = get_Flx_var(T);1707if (signe(a)==0) return pol_0(varn(a));1708t2 = FlxX_shift(FlxqX_mul(bt, a, T, p),1-n,vT);1709if (signe(bht)==0) return gerepilecopy(ltop, t2);1710t1 = FlxX_shift(FlxqX_mul(ft, a, T, p),-n,vT);1711t3 = FlxqXn_mul(t1, bht, n-1, T, p);1712vec = FlxX_sub(t2, FlxX_shift(t3, 1, vT), p);1713return gerepileupto(ltop, vec);1714}17151716static GEN1717polxn_FlxX(long n, long v, long vT)1718{1719long i, a = n+2;1720GEN p = cgetg(a+1, t_POL);1721p[1] = evalsigne(1)|evalvarn(v);1722for (i = 2; i < a; i++) gel(p,i) = pol0_Flx(vT);1723gel(p,a) = pol1_Flx(vT); return p;1724}17251726GEN1727FlxqXQ_minpoly(GEN x, GEN S, GEN T, ulong p)1728{1729pari_sp ltop = avma;1730long vS, vT, n;1731GEN v_x, g, tau;1732vS = get_FlxqX_var(S);1733vT = get_Flx_var(T);1734n = get_FlxqX_degree(S);1735g = pol1_FlxX(vS,vT);1736tau = pol1_FlxX(vS,vT);1737S = FlxqX_get_red(S, T, p);1738v_x = FlxqXQ_powers(x, usqrt(2*n), S, T, p);1739while(signe(tau) != 0)1740{1741long i, j, m, k1;1742GEN M, v, tr;1743GEN g_prime, c;1744if (degpol(g) == n) { tau = pol1_FlxX(vS, vT); g = pol1_FlxX(vS, vT); }1745v = random_FlxqX(n, vS, T, p);1746tr = FlxqXQ_transmul_init(tau, S, T, p);1747v = FlxqXQ_transmul(tr, v, n, T, p);1748m = 2*(n-degpol(g));1749k1 = usqrt(m);1750tr = FlxqXQ_transmul_init(gel(v_x,k1+1), S, T, p);1751c = cgetg(m+2,t_POL);1752c[1] = evalsigne(1)|evalvarn(vS);1753for (i=0; i<m; i+=k1)1754{1755long mj = minss(m-i, k1);1756for (j=0; j<mj; j++)1757gel(c,m+1-(i+j)) = FlxqX_dotproduct(v, gel(v_x,j+1), T, p);1758v = FlxqXQ_transmul(tr, v, n, T, p);1759}1760c = FlxX_renormalize(c, m+2);1761/* now c contains <v,x^i> , i = 0..m-1 */1762M = FlxqX_halfgcd(polxn_FlxX(m, vS, vT), c, T, p);1763g_prime = gmael(M, 2, 2);1764if (degpol(g_prime) < 1) continue;1765g = FlxqX_mul(g, g_prime, T, p);1766tau = FlxqXQ_mul(tau, FlxqX_FlxqXQV_eval(g_prime, v_x, S, T, p), S, T, p);1767}1768g = FlxqX_normalize(g,T, p);1769return gerepilecopy(ltop,g);1770}17711772GEN1773FlxqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, ulong p)1774{1775return FlxXV_to_FlxM(FlxqXQ_powers(y,m-1,S,T,p), n, get_Flx_var(T));1776}17771778static GEN1779FlxX_blocks_FlxM(GEN P, long n, long m, long v)1780{1781GEN z = cgetg(m+1,t_MAT);1782long i,j, k=2, l = lg(P);1783for(i=1; i<=m; i++)1784{1785GEN zi = cgetg(n+1,t_COL);1786gel(z,i) = zi;1787for(j=1; j<=n; j++)1788gel(zi, j) = k==l ? pol0_Flx(v) : gel(P,k++);1789}1790return z;1791}17921793GEN1794FlxqX_FlxqXQV_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)1795{1796pari_sp btop, av = avma;1797long v = get_FlxqX_var(S), m = get_FlxqX_degree(S);1798long vT = get_Flx_var(T);1799long i, l = lg(x)-1, lQ = lgpol(Q), n, d;1800GEN A, B, C, R, g;1801if (lQ == 0) return pol_0(v);1802if (lQ <= l)1803{1804n = l;1805d = 1;1806}1807else1808{1809n = l-1;1810d = (lQ+n-1)/n;1811}1812A = FlxXV_to_FlxM_lg(x, m, n, vT);1813B = FlxX_blocks_FlxM(Q, n, d, vT);1814C = gerepileupto(av, FlxqM_mul(A, B, T, p));1815g = gel(x, l);1816T = Flx_get_red(T, p);1817S = FlxqX_get_red(S, T, p);1818btop = avma;1819R = FlxV_to_FlxX(gel(C, d), v);1820for (i = d-1; i>0; i--)1821{1822R = FlxX_add(FlxqXQ_mul(R, g, S, T, p), FlxV_to_FlxX(gel(C,i), v), p);1823if (gc_needed(btop,1))1824R = gerepileupto(btop, R);1825}1826return gerepilecopy(av, R);1827}18281829GEN1830FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)1831{1832pari_sp av = avma;1833GEN z, V;1834long d = degpol(Q), rtd;1835if (d < 0) return pol_0(get_FlxqX_var(S));1836rtd = (long) sqrt((double)d);1837T = Flx_get_red(T, p);1838S = FlxqX_get_red(S, T, p);1839V = FlxqXQ_powers(x, rtd, S, T, p);1840z = FlxqX_FlxqXQV_eval(Q, V, S, T, p);1841return gerepileupto(av, z);1842}18431844static GEN1845FlxqXQ_autpow_sqr(void * E, GEN x)1846{1847struct _FlxqXQ *D = (struct _FlxqXQ *)E;1848GEN S = D->S, T = D->T;1849ulong p = D->p;1850GEN phi = gel(x,1), S1 = gel(x,2);1851long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);1852GEN V = Flxq_powers(phi, n, T, p);1853GEN phi2 = Flx_FlxqV_eval(phi, V, T, p);1854GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p);1855GEN S2 = FlxqX_FlxqXQ_eval(Sphi, S1, S, T, p);1856return mkvec2(phi2, S2);1857}18581859static GEN1860FlxqXQ_autpow_mul(void * E, GEN x, GEN y)1861{1862struct _FlxqXQ *D = (struct _FlxqXQ *)E;1863GEN S = D->S, T = D->T;1864ulong p = D->p;1865GEN phi1 = gel(x,1), S1 = gel(x,2);1866GEN phi2 = gel(y,1), S2 = gel(y,2);1867long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);1868GEN V = Flxq_powers(phi2, n, T, p);1869GEN phi3 = Flx_FlxqV_eval(phi1, V, T, p);1870GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p);1871GEN S3 = FlxqX_FlxqXQ_eval(Sphi, S2, S, T, p);1872return mkvec2(phi3, S3);1873}18741875GEN1876FlxqXQ_autpow(GEN aut, long n, GEN S, GEN T, ulong p)1877{1878pari_sp av = avma;1879struct _FlxqXQ D;1880T = Flx_get_red(T, p);1881S = FlxqX_get_red(S, T, p);1882D.S=S; D.T=T; D.p=p;1883aut = gen_powu_i(aut,n,&D,FlxqXQ_autpow_sqr,FlxqXQ_autpow_mul);1884return gerepilecopy(av, aut);1885}18861887static GEN1888FlxqXQ_autsum_mul(void *E, GEN x, GEN y)1889{1890struct _FlxqXQ *D = (struct _FlxqXQ *)E;1891GEN S = D->S, T = D->T;1892ulong p = D->p;1893GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);1894GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);1895long n2 = brent_kung_optpow(get_Flx_degree(T)-1, lgpol(S1)+lgpol(a1)+1,1);1896GEN V2 = Flxq_powers(phi2, n2, T, p);1897GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p);1898GEN Sphi = FlxY_FlxqV_evalx(S1, V2, T, p);1899GEN aphi = FlxY_FlxqV_evalx(a1, V2, T, p);1900long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);1901GEN V = FlxqXQ_powers(S2, n, S, T, p);1902GEN S3 = FlxqX_FlxqXQV_eval(Sphi, V, S, T, p);1903GEN aS = FlxqX_FlxqXQV_eval(aphi, V, S, T, p);1904GEN a3 = FlxqXQ_mul(aS, a2, S, T, p);1905return mkvec3(phi3, S3, a3);1906}19071908static GEN1909FlxqXQ_autsum_sqr(void * T, GEN x)1910{ return FlxqXQ_autsum_mul(T, x, x); }19111912GEN1913FlxqXQ_autsum(GEN aut, long n, GEN S, GEN T, ulong p)1914{1915pari_sp av = avma;1916struct _FlxqXQ D;1917T = Flx_get_red(T, p);1918S = FlxqX_get_red(S, T, p);1919D.S=S; D.T=T; D.p=p;1920aut = gen_powu_i(aut,n,&D,FlxqXQ_autsum_sqr,FlxqXQ_autsum_mul);1921return gerepilecopy(av, aut);1922}19231924static GEN1925FlxqXQ_auttrace_mul(void *E, GEN x, GEN y)1926{1927struct _FlxqXQ *D = (struct _FlxqXQ *)E;1928GEN S = D->S, T = D->T;1929ulong p = D->p;1930GEN S1 = gel(x,1), a1 = gel(x,2);1931GEN S2 = gel(y,1), a2 = gel(y,2);1932long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1);1933GEN V = FlxqXQ_powers(S2, n, S, T, p);1934GEN S3 = FlxqX_FlxqXQV_eval(S1, V, S, T, p);1935GEN aS = FlxqX_FlxqXQV_eval(a1, V, S, T, p);1936GEN a3 = FlxX_add(aS, a2, p);1937return mkvec2(S3, a3);1938}19391940static GEN1941FlxqXQ_auttrace_sqr(void *E, GEN x)1942{ return FlxqXQ_auttrace_mul(E, x, x); }19431944GEN1945FlxqXQ_auttrace(GEN x, ulong n, GEN S, GEN T, ulong p)1946{1947pari_sp av = avma;1948struct _FlxqXQ D;1949T = Flx_get_red(T, p);1950S = FlxqX_get_red(S, T, p);1951D.S=S; D.T=T; D.p=p;1952x = gen_powu_i(x,n,(void*)&D,FlxqXQ_auttrace_sqr,FlxqXQ_auttrace_mul);1953return gerepilecopy(av, x);1954}19551956/*******************************************************************/1957/* */1958/* FlxYqQ */1959/* */1960/*******************************************************************/19611962/*Preliminary implementation to speed up FpX_ffisom*/1963typedef struct {1964GEN S, T;1965ulong p;1966} FlxYqq_muldata;19671968/* reduce x in Fl[X, Y] in the algebra Fl[X, Y]/ (P(X),Q(Y)) */1969static GEN1970FlxYqq_redswap(GEN x, GEN S, GEN T, ulong p)1971{1972pari_sp ltop=avma;1973long n = get_Flx_degree(S);1974long m = get_Flx_degree(T);1975long w = get_Flx_var(T);1976GEN V = FlxX_swap(x,m,w);1977V = FlxqX_red(V,S,p);1978V = FlxX_swap(V,n,w);1979return gerepilecopy(ltop,V);1980}1981static GEN1982FlxYqq_sqr(void *data, GEN x)1983{1984FlxYqq_muldata *D = (FlxYqq_muldata*)data;1985return FlxYqq_redswap(FlxqX_sqr(x, D->T, D->p),D->S,D->T,D->p);1986}19871988static GEN1989FlxYqq_mul(void *data, GEN x, GEN y)1990{1991FlxYqq_muldata *D = (FlxYqq_muldata*)data;1992return FlxYqq_redswap(FlxqX_mul(x,y, D->T, D->p),D->S,D->T,D->p);1993}19941995/* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */1996GEN1997FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p)1998{1999FlxYqq_muldata D;2000D.S = S;2001D.T = T;2002D.p = p;2003return gen_pow(x, n, (void*)&D, &FlxYqq_sqr, &FlxYqq_mul);2004}20052006/*******************************************************************/2007/* */2008/* FlxqXn */2009/* */2010/*******************************************************************/20112012GEN2013FlxXn_red(GEN a, long n)2014{2015long i, L = n+2, l = lg(a);2016GEN b;2017if (L >= l) return a; /* deg(x) < n */2018b = cgetg(L, t_POL); b[1] = a[1];2019for (i=2; i<L; i++) gel(b,i) = gel(a,i);2020return FlxX_renormalize(b,L);2021}20222023GEN2024FlxqXn_mul(GEN a, GEN b, long n, GEN T, ulong p)2025{ return FlxXn_red(FlxqX_mul(a, b, T, p), n); }20262027GEN2028FlxqXn_sqr(GEN a, long n, GEN T, ulong p)2029{ return FlxXn_red(FlxqX_sqr(a, T, p), n); }20302031/* (f*g) \/ x^n */2032static GEN2033FlxqX_mulhigh_i(GEN f, GEN g, long n, GEN T, ulong p)2034{2035return FlxX_shift(FlxqX_mul(f, g, T, p), -n , get_Flx_var(T));2036}20372038static GEN2039FlxqXn_mulhigh(GEN f, GEN g, long n2, long n, GEN T, ulong p)2040{2041long vT = get_Flx_var(T);2042GEN F = FlxX_blocks(f, n2, 2, vT), fl = gel(F,1), fh = gel(F,2);2043return FlxX_add(FlxqX_mulhigh_i(fl, g, n2, T, p),2044FlxqXn_mul(fh, g, n - n2, T, p), p);2045}20462047GEN2048FlxqXn_inv(GEN f, long e, GEN T, ulong p)2049{2050pari_sp av = avma, av2;2051ulong mask;2052GEN W, a;2053long v = varn(f), n = 1, vT = get_Flx_var(T);20542055if (!signe(f)) pari_err_INV("FlxqXn_inv",f);2056a = Flxq_inv(gel(f,2), T, p);2057if (e == 1) return scalarpol(a, v);2058else if (e == 2)2059{2060GEN b;2061if (degpol(f) <= 0) return scalarpol(a, v);2062b = Flx_neg(gel(f,3), p);2063if (lgpol(b)==0) return scalarpol(a, v);2064b = Flxq_mul(b, Flxq_sqr(a, T, p), T, p);2065W = deg1pol_shallow(b, a, v);2066return gerepilecopy(av, W);2067}2068W = scalarpol_shallow(Flxq_inv(gel(f,2), T, p),v);2069mask = quadratic_prec_mask(e);2070av2 = avma;2071for (;mask>1;)2072{2073GEN u, fr;2074long n2 = n;2075n<<=1; if (mask & 1) n--;2076mask >>= 1;2077fr = FlxXn_red(f, n);2078u = FlxqXn_mul(W, FlxqXn_mulhigh(fr, W, n2, n, T, p), n-n2, T, p);2079W = FlxX_sub(W, FlxX_shift(u, n2, vT), p);2080if (gc_needed(av2,2))2081{2082if(DEBUGMEM>1) pari_warn(warnmem,"FlxqXn_inv, e = %ld", n);2083W = gerepileupto(av2, W);2084}2085}2086return gerepileupto(av, W);2087}20882089/* Compute intformal(x^n*S)/x^(n+1) */2090static GEN2091FlxX_integXn(GEN x, long n, ulong p)2092{2093long i, lx = lg(x);2094GEN y;2095if (lx == 2) return gcopy(x);2096y = cgetg(lx, t_POL); y[1] = x[1];2097for (i=2; i<lx; i++)2098{2099GEN xi = gel(x,i);2100gel(y,i) = Flx_Fl_mul(xi, Fl_inv((n+i-1)%p, p), p);2101}2102return FlxX_renormalize(y, lx);;2103}21042105GEN2106FlxqXn_expint(GEN h, long e, GEN T, ulong p)2107{2108pari_sp av = avma, av2;2109long v = varn(h), n = 1, vT = get_Flx_var(T);2110GEN f = pol1_FlxX(v, vT), g = pol1_FlxX(v, vT);2111ulong mask = quadratic_prec_mask(e);2112av2 = avma;2113for (;mask>1;)2114{2115GEN u, w;2116long n2 = n;2117n<<=1; if (mask & 1) n--;2118mask >>= 1;2119u = FlxqXn_mul(g, FlxqX_mulhigh_i(f, FlxXn_red(h, n2-1), n2-1, T, p), n-n2, T, p);2120u = FlxX_add(u, FlxX_shift(FlxXn_red(h, n-1), 1-n2, vT), p);2121w = FlxqXn_mul(f, FlxX_integXn(u, n2-1, p), n-n2, T, p);2122f = FlxX_add(f, FlxX_shift(w, n2, vT), p);2123if (mask<=1) break;2124u = FlxqXn_mul(g, FlxqXn_mulhigh(f, g, n2, n, T, p), n-n2, T, p);2125g = FlxX_sub(g, FlxX_shift(u, n2, vT), p);2126if (gc_needed(av2,2))2127{2128if (DEBUGMEM>1) pari_warn(warnmem,"FlxqXn_exp, e = %ld", n);2129gerepileall(av2, 2, &f, &g);2130}2131}2132return gerepileupto(av, f);2133}213421352136