Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2004 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 with small coefficients. */1819static GEN20get_Flx_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/** Flx **/29/** **/30/***********************************************************************/31/* Flx objects are defined as follows:32Let l an ulong. An Flx is a t_VECSMALL:33x[0] = codeword34x[1] = evalvarn(variable number) (signe is not stored).35x[2] = a_0 x[3] = a_1, etc.36With 0 <= a_i < l3738signe(x) is not valid. Use degpol(x)>=0 instead.39*/40/***********************************************************************/41/** **/42/** Conversion from Flx **/43/** **/44/***********************************************************************/4546GEN47Flx_to_ZX(GEN z)48{49long i, l = lg(z);50GEN x = cgetg(l,t_POL);51for (i=2; i<l; i++) gel(x,i) = utoi(z[i]);52x[1] = evalsigne(l-2!=0)| z[1]; return x;53}5455GEN56Flx_to_FlxX(GEN z, long sv)57{58long i, l = lg(z);59GEN x = cgetg(l,t_POL);60for (i=2; i<l; i++) gel(x,i) = Fl_to_Flx(z[i], sv);61x[1] = evalsigne(l-2!=0)| z[1]; return x;62}6364/* same as Flx_to_ZX, in place */65GEN66Flx_to_ZX_inplace(GEN z)67{68long i, l = lg(z);69for (i=2; i<l; i++) gel(z,i) = utoi(z[i]);70settyp(z, t_POL); z[1]=evalsigne(l-2!=0)|z[1]; return z;71}7273/*Flx_to_Flv=zx_to_zv*/74GEN75Flx_to_Flv(GEN x, long N)76{77long i, l;78GEN z = cgetg(N+1,t_VECSMALL);79if (typ(x) != t_VECSMALL) pari_err_TYPE("Flx_to_Flv",x);80l = lg(x)-1; x++;81for (i=1; i<l ; i++) z[i]=x[i];82for ( ; i<=N; i++) z[i]=0;83return z;84}8586/*Flv_to_Flx=zv_to_zx*/87GEN88Flv_to_Flx(GEN x, long sv)89{90long i, l=lg(x)+1;91GEN z = cgetg(l,t_VECSMALL); z[1]=sv;92x--;93for (i=2; i<l ; i++) z[i]=x[i];94return Flx_renormalize(z,l);95}9697/*Flm_to_FlxV=zm_to_zxV*/98GEN99Flm_to_FlxV(GEN x, long sv)100{ pari_APPLY_type(t_VEC, Flv_to_Flx(gel(x,i), sv)) }101102/*FlxC_to_ZXC=zxC_to_ZXC*/103GEN104FlxC_to_ZXC(GEN x)105{ pari_APPLY_type(t_COL, Flx_to_ZX(gel(x,i))) }106107/*FlxC_to_ZXC=zxV_to_ZXV*/108GEN109FlxV_to_ZXV(GEN x)110{ pari_APPLY_type(t_VEC, Flx_to_ZX(gel(x,i))) }111112void113FlxV_to_ZXV_inplace(GEN v)114{115long i;116for(i=1;i<lg(v);i++) gel(v,i)= Flx_to_ZX(gel(v,i));117}118119/*FlxM_to_ZXM=zxM_to_ZXM*/120GEN121FlxM_to_ZXM(GEN x)122{ pari_APPLY_same(FlxC_to_ZXC(gel(x,i))) }123124GEN125FlxV_to_FlxX(GEN x, long v)126{127long i, l = lg(x)+1;128GEN z = cgetg(l,t_POL); z[1] = evalvarn(v);129x--;130for (i=2; i<l ; i++) gel(z,i) = gel(x,i);131return FlxX_renormalize(z,l);132}133134GEN135FlxM_Flx_add_shallow(GEN x, GEN y, ulong p)136{137long l = lg(x), i, j;138GEN z = cgetg(l,t_MAT);139140if (l==1) return z;141if (l != lgcols(x)) pari_err_OP( "+", x, y);142for (i=1; i<l; i++)143{144GEN zi = cgetg(l,t_COL), xi = gel(x,i);145gel(z,i) = zi;146for (j=1; j<l; j++) gel(zi,j) = gel(xi,j);147gel(zi,i) = Flx_add(gel(zi,i), y, p);148}149return z;150}151152/***********************************************************************/153/** **/154/** Conversion to Flx **/155/** **/156/***********************************************************************/157/* Take an integer and return a scalar polynomial mod p, with evalvarn=vs */158GEN159Fl_to_Flx(ulong x, long sv)160{161return x? mkvecsmall2(sv, x): pol0_Flx(sv);162}163164/* a X^d */165GEN166monomial_Flx(ulong a, long d, long vs)167{168GEN P;169if (a==0) return pol0_Flx(vs);170P = const_vecsmall(d+2, 0);171P[1] = vs; P[d+2] = a;172return P;173}174175GEN176Z_to_Flx(GEN x, ulong p, long sv)177{178long u = umodiu(x,p);179return u? mkvecsmall2(sv, u): pol0_Flx(sv);180}181182/* return x[0 .. dx] mod p as t_VECSMALL. Assume x a t_POL*/183GEN184ZX_to_Flx(GEN x, ulong p)185{186long i, lx = lg(x);187GEN a = cgetg(lx, t_VECSMALL);188a[1]=((ulong)x[1])&VARNBITS;189for (i=2; i<lx; i++) a[i] = umodiu(gel(x,i), p);190return Flx_renormalize(a,lx);191}192193/* return x[0 .. dx] mod p as t_VECSMALL. Assume x a t_POL*/194GEN195zx_to_Flx(GEN x, ulong p)196{197long i, lx = lg(x);198GEN a = cgetg(lx, t_VECSMALL);199a[1] = x[1];200for (i=2; i<lx; i++) uel(a,i) = umodsu(x[i], p);201return Flx_renormalize(a,lx);202}203204ulong205Rg_to_Fl(GEN x, ulong p)206{207switch(typ(x))208{209case t_INT: return umodiu(x, p);210case t_FRAC: {211ulong z = umodiu(gel(x,1), p);212if (!z) return 0;213return Fl_div(z, umodiu(gel(x,2), p), p);214}215case t_PADIC: return padic_to_Fl(x, p);216case t_INTMOD: {217GEN q = gel(x,1), a = gel(x,2);218if (absequaliu(q, p)) return itou(a);219if (!dvdiu(q,p)) pari_err_MODULUS("Rg_to_Fl", q, utoipos(p));220return umodiu(a, p);221}222default: pari_err_TYPE("Rg_to_Fl",x);223return 0; /* LCOV_EXCL_LINE */224}225}226227ulong228Rg_to_F2(GEN x)229{230switch(typ(x))231{232case t_INT: return mpodd(x);233case t_FRAC:234if (!mpodd(gel(x,2))) (void)Fl_inv(0,2); /* error */235return mpodd(gel(x,1));236case t_PADIC:237if (!absequaliu(gel(x,2),2)) pari_err_OP("",x, mkintmodu(1,2));238if (valp(x) < 0) (void)Fl_inv(0,2);239return valp(x) & 1;240case t_INTMOD: {241GEN q = gel(x,1), a = gel(x,2);242if (mpodd(q)) pari_err_MODULUS("Rg_to_F2", q, gen_2);243return mpodd(a);244}245default: pari_err_TYPE("Rg_to_F2",x);246return 0; /* LCOV_EXCL_LINE */247}248}249250GEN251RgX_to_Flx(GEN x, ulong p)252{253long i, lx = lg(x);254GEN a = cgetg(lx, t_VECSMALL);255a[1]=((ulong)x[1])&VARNBITS;256for (i=2; i<lx; i++) a[i] = Rg_to_Fl(gel(x,i), p);257return Flx_renormalize(a,lx);258}259260GEN261RgXV_to_FlxV(GEN x, ulong p)262{ pari_APPLY_type(t_VEC, RgX_to_Flx(gel(x,i), p)) }263264/* If x is a POLMOD, assume modulus is a multiple of T. */265GEN266Rg_to_Flxq(GEN x, GEN T, ulong p)267{268long ta, tx = typ(x), v = get_Flx_var(T);269GEN a, b;270if (is_const_t(tx))271{272if (tx == t_FFELT) return FF_to_Flxq(x);273return Fl_to_Flx(Rg_to_Fl(x, p), v);274}275switch(tx)276{277case t_POLMOD:278b = gel(x,1);279a = gel(x,2); ta = typ(a);280if (is_const_t(ta)) return Fl_to_Flx(Rg_to_Fl(a, p), v);281b = RgX_to_Flx(b, p); if (b[1] != v) break;282a = RgX_to_Flx(a, p); if (Flx_equal(b,T)) return a;283if (lgpol(Flx_rem(b,T,p))==0) return Flx_rem(a, T, p);284break;285case t_POL:286x = RgX_to_Flx(x,p);287if (x[1] != v) break;288return Flx_rem(x, T, p);289case t_RFRAC:290a = Rg_to_Flxq(gel(x,1), T,p);291b = Rg_to_Flxq(gel(x,2), T,p);292return Flxq_div(a,b, T,p);293}294pari_err_TYPE("Rg_to_Flxq",x);295return NULL; /* LCOV_EXCL_LINE */296}297298/***********************************************************************/299/** **/300/** Basic operation on Flx **/301/** **/302/***********************************************************************/303/* = zx_renormalize. Similar to normalizepol, in place */304GEN305Flx_renormalize(GEN /*in place*/ x, long lx)306{307long i;308for (i = lx-1; i>1; i--)309if (x[i]) break;310stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1));311setlg(x, i+1); return x;312}313314GEN315Flx_red(GEN z, ulong p)316{317long i, l = lg(z);318GEN x = cgetg(l, t_VECSMALL);319x[1] = z[1];320for (i=2; i<l; i++) x[i] = uel(z,i)%p;321return Flx_renormalize(x,l);322}323324int325Flx_equal(GEN V, GEN W)326{327long l = lg(V);328if (lg(W) != l) return 0;329while (--l > 1) /* do not compare variables, V[1] */330if (V[l] != W[l]) return 0;331return 1;332}333334GEN335random_Flx(long d1, long vs, ulong p)336{337long i, d = d1+2;338GEN y = cgetg(d,t_VECSMALL); y[1] = vs;339for (i=2; i<d; i++) y[i] = random_Fl(p);340return Flx_renormalize(y,d);341}342343static GEN344Flx_addspec(GEN x, GEN y, ulong p, long lx, long ly)345{346long i,lz;347GEN z;348349if (ly>lx) swapspec(x,y, lx,ly);350lz = lx+2; z = cgetg(lz, t_VECSMALL);351for (i=0; i<ly; i++) z[i+2] = Fl_add(x[i], y[i], p);352for ( ; i<lx; i++) z[i+2] = x[i];353z[1] = 0; return Flx_renormalize(z, lz);354}355356GEN357Flx_add(GEN x, GEN y, ulong p)358{359long i,lz;360GEN z;361long lx=lg(x);362long ly=lg(y);363if (ly>lx) swapspec(x,y, lx,ly);364lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1];365for (i=2; i<ly; i++) z[i] = Fl_add(x[i], y[i], p);366for ( ; i<lx; i++) z[i] = x[i];367return Flx_renormalize(z, lz);368}369370GEN371Flx_Fl_add(GEN y, ulong x, ulong p)372{373GEN z;374long lz, i;375if (!lgpol(y))376return Fl_to_Flx(x,y[1]);377lz=lg(y);378z=cgetg(lz,t_VECSMALL);379z[1]=y[1];380z[2] = Fl_add(y[2],x,p);381for(i=3;i<lz;i++)382z[i] = y[i];383if (lz==3) z = Flx_renormalize(z,lz);384return z;385}386387static GEN388Flx_subspec(GEN x, GEN y, ulong p, long lx, long ly)389{390long i,lz;391GEN z;392393if (ly <= lx)394{395lz = lx+2; z = cgetg(lz, t_VECSMALL);396for (i=0; i<ly; i++) z[i+2] = Fl_sub(x[i],y[i],p);397for ( ; i<lx; i++) z[i+2] = x[i];398}399else400{401lz = ly+2; z = cgetg(lz, t_VECSMALL);402for (i=0; i<lx; i++) z[i+2] = Fl_sub(x[i],y[i],p);403for ( ; i<ly; i++) z[i+2] = Fl_neg(y[i],p);404}405z[1] = 0; return Flx_renormalize(z, lz);406}407408GEN409Flx_sub(GEN x, GEN y, ulong p)410{411long i,lz,lx = lg(x), ly = lg(y);412GEN z;413414if (ly <= lx)415{416lz = lx; z = cgetg(lz, t_VECSMALL);417for (i=2; i<ly; i++) z[i] = Fl_sub(x[i],y[i],p);418for ( ; i<lx; i++) z[i] = x[i];419}420else421{422lz = ly; z = cgetg(lz, t_VECSMALL);423for (i=2; i<lx; i++) z[i] = Fl_sub(x[i],y[i],p);424for ( ; i<ly; i++) z[i] = y[i]? (long)(p - y[i]): y[i];425}426z[1]=x[1]; return Flx_renormalize(z, lz);427}428429GEN430Flx_Fl_sub(GEN y, ulong x, ulong p)431{432GEN z;433long lz = lg(y), i;434if (lz==2)435return Fl_to_Flx(Fl_neg(x, p),y[1]);436z = cgetg(lz, t_VECSMALL);437z[1] = y[1];438z[2] = Fl_sub(uel(y,2), x, p);439for(i=3; i<lz; i++)440z[i] = y[i];441if (lz==3) z = Flx_renormalize(z,lz);442return z;443}444445static GEN446Flx_negspec(GEN x, ulong p, long l)447{448long i;449GEN z = cgetg(l+2, t_VECSMALL) + 2;450for (i=0; i<l; i++) z[i] = Fl_neg(x[i], p);451return z-2;452}453454GEN455Flx_neg(GEN x, ulong p)456{457GEN z = Flx_negspec(x+2, p, lgpol(x));458z[1] = x[1];459return z;460}461462GEN463Flx_neg_inplace(GEN x, ulong p)464{465long i, l = lg(x);466for (i=2; i<l; i++)467if (x[i]) x[i] = p - x[i];468return x;469}470471GEN472Flx_double(GEN y, ulong p)473{474long i, l;475GEN z = cgetg_copy(y, &l); z[1] = y[1];476for(i=2; i<l; i++) z[i] = Fl_double(y[i], p);477return Flx_renormalize(z, l);478}479GEN480Flx_triple(GEN y, ulong p)481{482long i, l;483GEN z = cgetg_copy(y, &l); z[1] = y[1];484for(i=2; i<l; i++) z[i] = Fl_triple(y[i], p);485return Flx_renormalize(z, l);486}487GEN488Flx_Fl_mul(GEN y, ulong x, ulong p)489{490GEN z;491long i, l;492if (!x) return pol0_Flx(y[1]);493z = cgetg_copy(y, &l); z[1] = y[1];494if (HIGHWORD(x | p))495for(i=2; i<l; i++) z[i] = Fl_mul(y[i], x, p);496else497for(i=2; i<l; i++) z[i] = (y[i] * x) % p;498return Flx_renormalize(z, l);499}500GEN501Flx_Fl_mul_to_monic(GEN y, ulong x, ulong p)502{503GEN z;504long i, l;505z = cgetg_copy(y, &l); z[1] = y[1];506if (HIGHWORD(x | p))507for(i=2; i<l-1; i++) z[i] = Fl_mul(y[i], x, p);508else509for(i=2; i<l-1; i++) z[i] = (y[i] * x) % p;510z[l-1] = 1; return z;511}512513/* Return a*x^n if n>=0 and a\x^(-n) if n<0 */514GEN515Flx_shift(GEN a, long n)516{517long i, l = lg(a);518GEN b;519if (l==2 || !n) return Flx_copy(a);520if (l+n<=2) return pol0_Flx(a[1]);521b = cgetg(l+n, t_VECSMALL);522b[1] = a[1];523if (n < 0)524for (i=2-n; i<l; i++) b[i+n] = a[i];525else526{527for (i=0; i<n; i++) b[2+i] = 0;528for (i=2; i<l; i++) b[i+n] = a[i];529}530return b;531}532533GEN534Flx_normalize(GEN z, ulong p)535{536long l = lg(z)-1;537ulong p1 = z[l]; /* leading term */538if (p1 == 1) return z;539return Flx_Fl_mul_to_monic(z, Fl_inv(p1,p), p);540}541542/* return (x * X^d) + y. Assume d > 0, shallow if x == 0*/543static GEN544Flx_addshift(GEN x, GEN y, ulong p, long d)545{546GEN xd,yd,zd = (GEN)avma;547long a,lz,ny = lgpol(y), nx = lgpol(x);548long vs = x[1];549if (nx == 0) return y;550x += 2; y += 2; a = ny-d;551if (a <= 0)552{553lz = (a>nx)? ny+2: nx+d+2;554(void)new_chunk(lz); xd = x+nx; yd = y+ny;555while (xd > x) *--zd = *--xd;556x = zd + a;557while (zd > x) *--zd = 0;558}559else560{561xd = new_chunk(d); yd = y+d;562x = Flx_addspec(x,yd,p, nx,a);563lz = (a>nx)? ny+2: lg(x)+d;564x += 2; while (xd > x) *--zd = *--xd;565}566while (yd > y) *--zd = *--yd;567*--zd = vs;568*--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;569}570571/* shift polynomial + gerepile */572/* Do not set evalvarn*/573static GEN574Flx_shiftip(pari_sp av, GEN x, long v)575{576long i, lx = lg(x), ly;577GEN y;578if (!v || lx==2) return gerepileuptoleaf(av, x);579ly = lx + v; /* result length */580(void)new_chunk(ly); /* check that result fits */581x += lx; y = (GEN)av;582for (i = 2; i<lx; i++) *--y = *--x;583for (i = 0; i< v; i++) *--y = 0;584y -= 2; y[0] = evaltyp(t_VECSMALL) | evallg(ly);585return gc_const((pari_sp)y, y);586}587588static long589get_Fl_threshold(ulong p, long mul, long mul2)590{591return SMALL_ULONG(p) ? mul: mul2;592}593594#define BITS_IN_QUARTULONG (BITS_IN_HALFULONG >> 1)595#define QUARTMASK ((1UL<<BITS_IN_QUARTULONG)-1UL)596#define LLQUARTWORD(x) ((x) & QUARTMASK)597#define HLQUARTWORD(x) (((x) >> BITS_IN_QUARTULONG) & QUARTMASK)598#define LHQUARTWORD(x) (((x) >> (2*BITS_IN_QUARTULONG)) & QUARTMASK)599#define HHQUARTWORD(x) (((x) >> (3*BITS_IN_QUARTULONG)) & QUARTMASK)600INLINE long601maxbitcoeffpol(ulong p, long n)602{603GEN z = muliu(sqru(p - 1), n);604long b = expi(z) + 1;605/* only do expensive bit-packing if it saves at least 1 limb */606if (b <= BITS_IN_QUARTULONG)607{608if (nbits2nlong(n*b) == (n + 3)>>2)609b = BITS_IN_QUARTULONG;610}611else if (b <= BITS_IN_HALFULONG)612{613if (nbits2nlong(n*b) == (n + 1)>>1)614b = BITS_IN_HALFULONG;615}616else617{618long l = lgefint(z) - 2;619if (nbits2nlong(n*b) == n*l)620b = l*BITS_IN_LONG;621}622return b;623}624625INLINE ulong626Flx_mullimb_ok(GEN x, GEN y, ulong p, long a, long b)627{ /* Assume OK_ULONG*/628ulong p1 = 0;629long i;630for (i=a; i<b; i++)631if (y[i])632{633p1 += y[i] * x[-i];634if (p1 & HIGHBIT) p1 %= p;635}636return p1 % p;637}638639INLINE ulong640Flx_mullimb(GEN x, GEN y, ulong p, ulong pi, long a, long b)641{642ulong p1 = 0;643long i;644for (i=a; i<b; i++)645if (y[i])646p1 = Fl_addmul_pre(p1, y[i], x[-i], p, pi);647return p1;648}649650/* assume nx >= ny > 0 */651static GEN652Flx_mulspec_basecase(GEN x, GEN y, ulong p, long nx, long ny)653{654long i,lz,nz;655GEN z;656657lz = nx+ny+1; nz = lz-2;658z = cgetg(lz, t_VECSMALL) + 2; /* x:y:z [i] = term of degree i */659if (SMALL_ULONG(p))660{661for (i=0; i<ny; i++)z[i] = Flx_mullimb_ok(x+i,y,p,0,i+1);662for ( ; i<nx; i++) z[i] = Flx_mullimb_ok(x+i,y,p,0,ny);663for ( ; i<nz; i++) z[i] = Flx_mullimb_ok(x+i,y,p,i-nx+1,ny);664}665else666{667ulong pi = get_Fl_red(p);668for (i=0; i<ny; i++)z[i] = Flx_mullimb(x+i,y,p,pi,0,i+1);669for ( ; i<nx; i++) z[i] = Flx_mullimb(x+i,y,p,pi,0,ny);670for ( ; i<nz; i++) z[i] = Flx_mullimb(x+i,y,p,pi,i-nx+1,ny);671}672z -= 2; return Flx_renormalize(z, lz);673}674675static GEN676int_to_Flx(GEN z, ulong p)677{678long i, l = lgefint(z);679GEN x = cgetg(l, t_VECSMALL);680for (i=2; i<l; i++) x[i] = uel(z,i)%p;681return Flx_renormalize(x, l);682}683684INLINE GEN685Flx_mulspec_mulii(GEN a, GEN b, ulong p, long na, long nb)686{687GEN z=muliispec(a,b,na,nb);688return int_to_Flx(z,p);689}690691static GEN692Flx_to_int_halfspec(GEN a, long na)693{694long j;695long n = (na+1)>>1UL;696GEN V = cgetipos(2+n);697GEN w;698for (w = int_LSW(V), j=0; j+1<na; j+=2, w=int_nextW(w))699*w = a[j]|(a[j+1]<<BITS_IN_HALFULONG);700if (j<na)701*w = a[j];702return V;703}704705static GEN706int_to_Flx_half(GEN z, ulong p)707{708long i;709long lx = (lgefint(z)-2)*2+2;710GEN w, x = cgetg(lx, t_VECSMALL);711for (w = int_LSW(z), i=2; i<lx; i+=2, w=int_nextW(w))712{713x[i] = LOWWORD((ulong)*w)%p;714x[i+1] = HIGHWORD((ulong)*w)%p;715}716return Flx_renormalize(x, lx);717}718719static GEN720Flx_mulspec_halfmulii(GEN a, GEN b, ulong p, long na, long nb)721{722GEN A = Flx_to_int_halfspec(a,na);723GEN B = Flx_to_int_halfspec(b,nb);724GEN z = mulii(A,B);725return int_to_Flx_half(z,p);726}727728static GEN729Flx_to_int_quartspec(GEN a, long na)730{731long j;732long n = (na+3)>>2UL;733GEN V = cgetipos(2+n);734GEN w;735for (w = int_LSW(V), j=0; j+3<na; j+=4, w=int_nextW(w))736*w = a[j]|(a[j+1]<<BITS_IN_QUARTULONG)|(a[j+2]<<(2*BITS_IN_QUARTULONG))|(a[j+3]<<(3*BITS_IN_QUARTULONG));737switch (na-j)738{739case 3:740*w = a[j]|(a[j+1]<<BITS_IN_QUARTULONG)|(a[j+2]<<(2*BITS_IN_QUARTULONG));741break;742case 2:743*w = a[j]|(a[j+1]<<BITS_IN_QUARTULONG);744break;745case 1:746*w = a[j];747break;748case 0:749break;750}751return V;752}753754static GEN755int_to_Flx_quart(GEN z, ulong p)756{757long i;758long lx = (lgefint(z)-2)*4+2;759GEN w, x = cgetg(lx, t_VECSMALL);760for (w = int_LSW(z), i=2; i<lx; i+=4, w=int_nextW(w))761{762x[i] = LLQUARTWORD((ulong)*w)%p;763x[i+1] = HLQUARTWORD((ulong)*w)%p;764x[i+2] = LHQUARTWORD((ulong)*w)%p;765x[i+3] = HHQUARTWORD((ulong)*w)%p;766}767return Flx_renormalize(x, lx);768}769770static GEN771Flx_mulspec_quartmulii(GEN a, GEN b, ulong p, long na, long nb)772{773GEN A = Flx_to_int_quartspec(a,na);774GEN B = Flx_to_int_quartspec(b,nb);775GEN z = mulii(A,B);776return int_to_Flx_quart(z,p);777}778779/*Eval x in 2^(k*BIL) in linear time, k==2 or 3*/780static GEN781Flx_eval2BILspec(GEN x, long k, long l)782{783long i, lz = k*l, ki;784GEN pz = cgetipos(2+lz);785for (i=0; i < lz; i++)786*int_W(pz,i) = 0UL;787for (i=0, ki=0; i<l; i++, ki+=k)788*int_W(pz,ki) = x[i];789return int_normalize(pz,0);790}791792static GEN793Z_mod2BIL_Flx_2(GEN x, long d, ulong p)794{795long i, offset, lm = lgefint(x)-2, l = d+3;796ulong pi = get_Fl_red(p);797GEN pol = cgetg(l, t_VECSMALL);798pol[1] = 0;799for (i=0, offset=0; offset+1 < lm; i++, offset += 2)800pol[i+2] = remll_pre(*int_W(x,offset+1), *int_W(x,offset), p, pi);801if (offset < lm)802pol[i+2] = (*int_W(x,offset)) % p;803return Flx_renormalize(pol,l);804}805806static GEN807Z_mod2BIL_Flx_3(GEN x, long d, ulong p)808{809long i, offset, lm = lgefint(x)-2, l = d+3;810ulong pi = get_Fl_red(p);811GEN pol = cgetg(l, t_VECSMALL);812pol[1] = 0;813for (i=0, offset=0; offset+2 < lm; i++, offset += 3)814pol[i+2] = remlll_pre(*int_W(x,offset+2), *int_W(x,offset+1),815*int_W(x,offset), p, pi);816if (offset+1 < lm)817pol[i+2] = remll_pre(*int_W(x,offset+1), *int_W(x,offset), p, pi);818else if (offset < lm)819pol[i+2] = (*int_W(x,offset)) % p;820return Flx_renormalize(pol,l);821}822823static GEN824Z_mod2BIL_Flx(GEN x, long bs, long d, ulong p)825{826return bs==2 ? Z_mod2BIL_Flx_2(x, d, p): Z_mod2BIL_Flx_3(x, d, p);827}828829static GEN830Flx_mulspec_mulii_inflate(GEN x, GEN y, long N, ulong p, long nx, long ny)831{832pari_sp av = avma;833GEN z = mulii(Flx_eval2BILspec(x,N,nx), Flx_eval2BILspec(y,N,ny));834return gerepileupto(av, Z_mod2BIL_Flx(z, N, nx+ny-2, p));835}836837static GEN838kron_pack_Flx_spec_bits(GEN x, long b, long l) {839GEN y;840long i;841if (l == 0)842return gen_0;843y = cgetg(l + 1, t_VECSMALL);844for(i = 1; i <= l; i++)845y[i] = x[l - i];846return nv_fromdigits_2k(y, b);847}848849/* assume b < BITS_IN_LONG */850static GEN851kron_unpack_Flx_bits_narrow(GEN z, long b, ulong p) {852GEN v = binary_2k_nv(z, b), x;853long i, l = lg(v) + 1;854x = cgetg(l, t_VECSMALL);855for (i = 2; i < l; i++)856x[i] = v[l - i] % p;857return Flx_renormalize(x, l);858}859860static GEN861kron_unpack_Flx_bits_wide(GEN z, long b, ulong p, ulong pi) {862GEN v = binary_2k(z, b), x, y;863long i, l = lg(v) + 1, ly;864x = cgetg(l, t_VECSMALL);865for (i = 2; i < l; i++) {866y = gel(v, l - i);867ly = lgefint(y);868switch (ly) {869case 2: x[i] = 0; break;870case 3: x[i] = *int_W_lg(y, 0, ly) % p; break;871case 4: x[i] = remll_pre(*int_W_lg(y, 1, ly), *int_W_lg(y, 0, ly), p, pi); break;872case 5: x[i] = remlll_pre(*int_W_lg(y, 2, ly), *int_W_lg(y, 1, ly),873*int_W_lg(y, 0, ly), p, pi); break;874default: x[i] = umodiu(gel(v, l - i), p);875}876}877return Flx_renormalize(x, l);878}879880static GEN881Flx_mulspec_Kronecker(GEN A, GEN B, long b, ulong p, long lA, long lB)882{883GEN C, D;884pari_sp av = avma;885A = kron_pack_Flx_spec_bits(A, b, lA);886B = kron_pack_Flx_spec_bits(B, b, lB);887C = gerepileuptoint(av, mulii(A, B));888if (b < BITS_IN_LONG)889D = kron_unpack_Flx_bits_narrow(C, b, p);890else891{892ulong pi = get_Fl_red(p);893D = kron_unpack_Flx_bits_wide(C, b, p, pi);894}895return D;896}897898static GEN899Flx_sqrspec_Kronecker(GEN A, long b, ulong p, long lA)900{901GEN C, D;902A = kron_pack_Flx_spec_bits(A, b, lA);903C = sqri(A);904if (b < BITS_IN_LONG)905D = kron_unpack_Flx_bits_narrow(C, b, p);906else907{908ulong pi = get_Fl_red(p);909D = kron_unpack_Flx_bits_wide(C, b, p, pi);910}911return D;912}913914/* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,915* b+2 were sent instead. na, nb = number of terms of a, b.916* Only c, c0, c1, c2 are genuine GEN.917*/918static GEN919Flx_mulspec(GEN a, GEN b, ulong p, long na, long nb)920{921GEN a0,c,c0;922long n0, n0a, i, v = 0;923pari_sp av;924925while (na && !a[0]) { a++; na--; v++; }926while (nb && !b[0]) { b++; nb--; v++; }927if (na < nb) swapspec(a,b, na,nb);928if (!nb) return pol0_Flx(0);929930av = avma;931if (nb >= get_Fl_threshold(p, Flx_MUL_MULII_LIMIT, Flx_MUL2_MULII_LIMIT))932{933long m = maxbitcoeffpol(p,nb);934switch (m)935{936case BITS_IN_QUARTULONG:937return Flx_shiftip(av,Flx_mulspec_quartmulii(a,b,p,na,nb), v);938case BITS_IN_HALFULONG:939return Flx_shiftip(av,Flx_mulspec_halfmulii(a,b,p,na,nb), v);940case BITS_IN_LONG:941return Flx_shiftip(av,Flx_mulspec_mulii(a,b,p,na,nb), v);942case 2*BITS_IN_LONG:943return Flx_shiftip(av,Flx_mulspec_mulii_inflate(a,b,2,p,na,nb), v);944case 3*BITS_IN_LONG:945return Flx_shiftip(av,Flx_mulspec_mulii_inflate(a,b,3,p,na,nb), v);946default:947return Flx_shiftip(av,Flx_mulspec_Kronecker(a,b,m,p,na,nb), v);948}949}950if (nb < get_Fl_threshold(p, Flx_MUL_KARATSUBA_LIMIT, Flx_MUL2_KARATSUBA_LIMIT))951return Flx_shiftip(av,Flx_mulspec_basecase(a,b,p,na,nb), v);952i=(na>>1); n0=na-i; na=i;953a0=a+n0; n0a=n0;954while (n0a && !a[n0a-1]) n0a--;955956if (nb > n0)957{958GEN b0,c1,c2;959long n0b;960961nb -= n0; b0 = b+n0; n0b = n0;962while (n0b && !b[n0b-1]) n0b--;963c = Flx_mulspec(a,b,p,n0a,n0b);964c0 = Flx_mulspec(a0,b0,p,na,nb);965966c2 = Flx_addspec(a0,a,p,na,n0a);967c1 = Flx_addspec(b0,b,p,nb,n0b);968969c1 = Flx_mul(c1,c2,p);970c2 = Flx_add(c0,c,p);971972c2 = Flx_neg_inplace(c2,p);973c2 = Flx_add(c1,c2,p);974c0 = Flx_addshift(c0,c2 ,p, n0);975}976else977{978c = Flx_mulspec(a,b,p,n0a,nb);979c0 = Flx_mulspec(a0,b,p,na,nb);980}981c0 = Flx_addshift(c0,c,p,n0);982return Flx_shiftip(av,c0, v);983}984985GEN986Flx_mul(GEN x, GEN y, ulong p)987{988GEN z = Flx_mulspec(x+2,y+2,p, lgpol(x),lgpol(y));989z[1] = x[1]; return z;990}991992static GEN993Flx_sqrspec_basecase(GEN x, ulong p, long nx)994{995long i, lz, nz;996ulong p1;997GEN z;998999if (!nx) return pol0_Flx(0);1000lz = (nx << 1) + 1, nz = lz-2;1001z = cgetg(lz, t_VECSMALL) + 2;1002if (SMALL_ULONG(p))1003{1004z[0] = x[0]*x[0]%p;1005for (i=1; i<nx; i++)1006{1007p1 = Flx_mullimb_ok(x+i,x,p,0, (i+1)>>1);1008p1 <<= 1;1009if ((i&1) == 0) p1 += x[i>>1] * x[i>>1];1010z[i] = p1 % p;1011}1012for ( ; i<nz; i++)1013{1014p1 = Flx_mullimb_ok(x+i,x,p,i-nx+1, (i+1)>>1);1015p1 <<= 1;1016if ((i&1) == 0) p1 += x[i>>1] * x[i>>1];1017z[i] = p1 % p;1018}1019}1020else1021{1022ulong pi = get_Fl_red(p);1023z[0] = Fl_sqr_pre(x[0], p, pi);1024for (i=1; i<nx; i++)1025{1026p1 = Flx_mullimb(x+i,x,p,pi,0, (i+1)>>1);1027p1 = Fl_add(p1, p1, p);1028if ((i&1) == 0) p1 = Fl_add(p1, Fl_sqr_pre(x[i>>1], p, pi), p);1029z[i] = p1;1030}1031for ( ; i<nz; i++)1032{1033p1 = Flx_mullimb(x+i,x,p,pi,i-nx+1, (i+1)>>1);1034p1 = Fl_add(p1, p1, p);1035if ((i&1) == 0) p1 = Fl_add(p1, Fl_sqr_pre(x[i>>1], p, pi), p);1036z[i] = p1;1037}1038}1039z -= 2; return Flx_renormalize(z, lz);1040}10411042static GEN1043Flx_sqrspec_sqri(GEN a, ulong p, long na)1044{1045GEN z=sqrispec(a,na);1046return int_to_Flx(z,p);1047}10481049static GEN1050Flx_sqrspec_halfsqri(GEN a, ulong p, long na)1051{1052GEN z = sqri(Flx_to_int_halfspec(a,na));1053return int_to_Flx_half(z,p);1054}10551056static GEN1057Flx_sqrspec_quartsqri(GEN a, ulong p, long na)1058{1059GEN z = sqri(Flx_to_int_quartspec(a,na));1060return int_to_Flx_quart(z,p);1061}10621063static GEN1064Flx_sqrspec_sqri_inflate(GEN x, long N, ulong p, long nx)1065{1066pari_sp av = avma;1067GEN z = sqri(Flx_eval2BILspec(x,N,nx));1068return gerepileupto(av, Z_mod2BIL_Flx(z, N, (nx-1)*2, p));1069}10701071static GEN1072Flx_sqrspec(GEN a, ulong p, long na)1073{1074GEN a0, c, c0;1075long n0, n0a, i, v = 0, m;1076pari_sp av;10771078while (na && !a[0]) { a++; na--; v += 2; }1079if (!na) return pol0_Flx(0);10801081av = avma;1082if (na >= get_Fl_threshold(p, Flx_SQR_SQRI_LIMIT, Flx_SQR2_SQRI_LIMIT))1083{1084m = maxbitcoeffpol(p,na);1085switch(m)1086{1087case BITS_IN_QUARTULONG:1088return Flx_shiftip(av, Flx_sqrspec_quartsqri(a,p,na), v);1089case BITS_IN_HALFULONG:1090return Flx_shiftip(av, Flx_sqrspec_halfsqri(a,p,na), v);1091case BITS_IN_LONG:1092return Flx_shiftip(av, Flx_sqrspec_sqri(a,p,na), v);1093case 2*BITS_IN_LONG:1094return Flx_shiftip(av, Flx_sqrspec_sqri_inflate(a,2,p,na), v);1095case 3*BITS_IN_LONG:1096return Flx_shiftip(av, Flx_sqrspec_sqri_inflate(a,3,p,na), v);1097default:1098return Flx_shiftip(av, Flx_sqrspec_Kronecker(a,m,p,na), v);1099}1100}1101if (na < get_Fl_threshold(p, Flx_SQR_KARATSUBA_LIMIT, Flx_SQR2_KARATSUBA_LIMIT))1102return Flx_shiftip(av, Flx_sqrspec_basecase(a,p,na), v);1103i=(na>>1); n0=na-i; na=i;1104a0=a+n0; n0a=n0;1105while (n0a && !a[n0a-1]) n0a--;11061107c = Flx_sqrspec(a,p,n0a);1108c0= Flx_sqrspec(a0,p,na);1109if (p == 2) n0 *= 2;1110else1111{1112GEN c1, t = Flx_addspec(a0,a,p,na,n0a);1113t = Flx_sqr(t,p);1114c1= Flx_add(c0,c, p);1115c1= Flx_sub(t, c1, p);1116c0 = Flx_addshift(c0,c1,p,n0);1117}1118c0 = Flx_addshift(c0,c,p,n0);1119return Flx_shiftip(av,c0,v);1120}11211122GEN1123Flx_sqr(GEN x, ulong p)1124{1125GEN z = Flx_sqrspec(x+2,p, lgpol(x));1126z[1] = x[1]; return z;1127}11281129GEN1130Flx_powu(GEN x, ulong n, ulong p)1131{1132GEN y = pol1_Flx(x[1]), z;1133ulong m;1134if (n == 0) return y;1135m = n; z = x;1136for (;;)1137{1138if (m&1UL) y = Flx_mul(y,z, p);1139m >>= 1; if (!m) return y;1140z = Flx_sqr(z, p);1141}1142}11431144GEN1145Flx_halve(GEN y, ulong p)1146{1147GEN z;1148long i, l;1149z = cgetg_copy(y, &l); z[1] = y[1];1150for(i=2; i<l; i++) uel(z,i) = Fl_halve(uel(y,i), p);1151return z;1152}11531154static GEN1155Flx_recipspec(GEN x, long l, long n)1156{1157long i;1158GEN z=cgetg(n+2,t_VECSMALL)+2;1159for(i=0; i<l; i++)1160z[n-i-1] = x[i];1161for( ; i<n; i++)1162z[n-i-1] = 0;1163return Flx_renormalize(z-2,n+2);1164}11651166GEN1167Flx_recip(GEN x)1168{1169GEN z=Flx_recipspec(x+2,lgpol(x),lgpol(x));1170z[1]=x[1];1171return z;1172}11731174/* Return h^degpol(P) P(x / h) */1175GEN1176Flx_rescale(GEN P, ulong h, ulong p)1177{1178long i, l = lg(P);1179GEN Q = cgetg(l,t_VECSMALL);1180ulong hi = h;1181Q[l-1] = P[l-1];1182for (i=l-2; i>=2; i--)1183{1184Q[i] = Fl_mul(P[i], hi, p);1185if (i == 2) break;1186hi = Fl_mul(hi,h, p);1187}1188Q[1] = P[1]; return Q;1189}11901191/*1192* x/polrecip(P)+O(x^n)1193*/1194static GEN1195Flx_invBarrett_basecase(GEN T, ulong p)1196{1197long i, l=lg(T)-1, lr=l-1, k;1198GEN r=cgetg(lr,t_VECSMALL); r[1] = T[1];1199r[2] = 1;1200if (SMALL_ULONG(p))1201for (i=3;i<lr;i++)1202{1203ulong u = uel(T, l-i+2);1204for (k=3; k<i; k++)1205{ u += uel(T,l-i+k) * uel(r, k); if (u & HIGHBIT) u %= p; }1206r[i] = Fl_neg(u % p, p);1207}1208else1209for (i=3;i<lr;i++)1210{1211ulong u = Fl_neg(uel(T,l-i+2), p);1212for (k=3; k<i; k++)1213u = Fl_sub(u, Fl_mul(uel(T,l-i+k), uel(r,k), p), p);1214r[i] = u;1215}1216return Flx_renormalize(r,lr);1217}12181219/* Return new lgpol */1220static long1221Flx_lgrenormalizespec(GEN x, long lx)1222{1223long i;1224for (i = lx-1; i>=0; i--)1225if (x[i]) break;1226return i+1;1227}1228static GEN1229Flx_invBarrett_Newton(GEN T, ulong p)1230{1231long nold, lx, lz, lq, l = degpol(T), lQ;1232GEN q, y, z, x = zero_zv(l+1) + 2;1233ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */1234pari_sp av;12351236y = T+2;1237q = Flx_recipspec(y,l+1,l+1); lQ = lgpol(q); q+=2;1238av = avma;1239/* We work on _spec_ Flx's, all the l[xzq12] below are lgpol's */12401241/* initialize */1242x[0] = Fl_inv(q[0], p);1243if (lQ>1 && q[1])1244{1245ulong u = q[1];1246if (x[0] != 1) u = Fl_mul(u, Fl_sqr(x[0],p), p);1247x[1] = p - u; lx = 2;1248}1249else1250lx = 1;1251nold = 1;1252for (; mask > 1; set_avma(av))1253{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */1254long i, lnew, nnew = nold << 1;12551256if (mask & 1) nnew--;1257mask >>= 1;12581259lnew = nnew + 1;1260lq = Flx_lgrenormalizespec(q, minss(lQ, lnew));1261z = Flx_mulspec(x, q, p, lx, lq); /* FIXME: high product */1262lz = lgpol(z); if (lz > lnew) lz = lnew;1263z += 2;1264/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */1265for (i = nold; i < lz; i++) if (z[i]) break;1266nold = nnew;1267if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */12681269/* z + i represents (x*q - 1) / t^i */1270lz = Flx_lgrenormalizespec (z+i, lz-i);1271z = Flx_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */1272lz = lgpol(z); z += 2;1273if (lz > lnew-i) lz = Flx_lgrenormalizespec(z, lnew-i);12741275lx = lz+ i;1276y = x + i; /* x -= z * t^i, in place */1277for (i = 0; i < lz; i++) y[i] = Fl_neg(z[i], p);1278}1279x -= 2; setlg(x, lx + 2); x[1] = T[1];1280return x;1281}12821283GEN1284Flx_invBarrett(GEN T, ulong p)1285{1286pari_sp ltop = avma;1287long l = lgpol(T);1288GEN r;1289if (l < 3) return pol0_Flx(T[1]);1290if (l < get_Fl_threshold(p, Flx_INVBARRETT_LIMIT, Flx_INVBARRETT2_LIMIT))1291{1292ulong c = T[l+1];1293if (c!=1)1294{1295ulong ci = Fl_inv(c,p);1296T=Flx_Fl_mul(T, ci, p);1297r=Flx_invBarrett_basecase(T,p);1298r=Flx_Fl_mul(r,ci,p);1299}1300else1301r=Flx_invBarrett_basecase(T,p);1302}1303else1304r = Flx_invBarrett_Newton(T,p);1305return gerepileuptoleaf(ltop, r);1306}13071308GEN1309Flx_get_red(GEN T, ulong p)1310{1311if (typ(T)!=t_VECSMALL1312|| lgpol(T) < get_Fl_threshold(p, Flx_BARRETT_LIMIT,1313Flx_BARRETT2_LIMIT))1314return T;1315retmkvec2(Flx_invBarrett(T,p),T);1316}13171318/* separate from Flx_divrem for maximal speed. */1319static GEN1320Flx_rem_basecase(GEN x, GEN y, ulong p)1321{1322pari_sp av;1323GEN z, c;1324long dx,dy,dy1,dz,i,j;1325ulong p1,inv;1326long vs=x[1];13271328dy = degpol(y); if (!dy) return pol0_Flx(x[1]);1329dx = degpol(x);1330dz = dx-dy; if (dz < 0) return Flx_copy(x);1331x += 2; y += 2;1332inv = y[dy];1333if (inv != 1UL) inv = Fl_inv(inv,p);1334for (dy1=dy-1; dy1>=0 && !y[dy1]; dy1--);13351336c = cgetg(dy+3, t_VECSMALL); c[1]=vs; c += 2; av=avma;1337z = cgetg(dz+3, t_VECSMALL); z[1]=vs; z += 2;13381339if (SMALL_ULONG(p))1340{1341z[dz] = (inv*x[dx]) % p;1342for (i=dx-1; i>=dy; --i)1343{1344p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */1345for (j=i-dy1; j<=i && j<=dz; j++)1346{1347p1 += z[j]*y[i-j];1348if (p1 & HIGHBIT) p1 %= p;1349}1350p1 %= p;1351z[i-dy] = p1? ((p - p1)*inv) % p: 0;1352}1353for (i=0; i<dy; i++)1354{1355p1 = z[0]*y[i];1356for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)1357{1358p1 += z[j]*y[i-j];1359if (p1 & HIGHBIT) p1 %= p;1360}1361c[i] = Fl_sub(x[i], p1%p, p);1362}1363}1364else1365{1366ulong pi = get_Fl_red(p);1367z[dz] = Fl_mul_pre(inv, x[dx], p, pi);1368for (i=dx-1; i>=dy; --i)1369{1370p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */1371for (j=i-dy1; j<=i && j<=dz; j++)1372p1 = Fl_addmul_pre(p1, z[j], y[i - j], p, pi);1373z[i-dy] = p1? Fl_mul_pre(p - p1, inv, p, pi): 0;1374}1375for (i=0; i<dy; i++)1376{1377p1 = Fl_mul_pre(z[0],y[i],p,pi);1378for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)1379p1 = Fl_addmul_pre(p1, z[j], y[i - j], p, pi);1380c[i] = Fl_sub(x[i], p1, p);1381}1382}1383i = dy-1; while (i>=0 && !c[i]) i--;1384set_avma(av); return Flx_renormalize(c-2, i+3);1385}13861387/* as FpX_divrem but working only on ulong types.1388* if relevant, *pr is the last object on stack */1389static GEN1390Flx_divrem_basecase(GEN x, GEN y, ulong p, GEN *pr)1391{1392GEN z,q,c;1393long dx,dy,dy1,dz,i,j;1394ulong p1,inv;1395long sv=x[1];13961397dy = degpol(y);1398if (dy<0) pari_err_INV("Flx_divrem",y);1399if (pr == ONLY_REM) return Flx_rem_basecase(x, y, p);1400if (!dy)1401{1402if (pr && pr != ONLY_DIVIDES) *pr = pol0_Flx(sv);1403if (y[2] == 1UL) return Flx_copy(x);1404return Flx_Fl_mul(x, Fl_inv(y[2], p), p);1405}1406dx = degpol(x);1407dz = dx-dy;1408if (dz < 0)1409{1410q = pol0_Flx(sv);1411if (pr && pr != ONLY_DIVIDES) *pr = Flx_copy(x);1412return q;1413}1414x += 2;1415y += 2;1416z = cgetg(dz + 3, t_VECSMALL); z[1] = sv; z += 2;1417inv = uel(y, dy);1418if (inv != 1UL) inv = Fl_inv(inv,p);1419for (dy1=dy-1; dy1>=0 && !y[dy1]; dy1--);14201421if (SMALL_ULONG(p))1422{1423z[dz] = (inv*x[dx]) % p;1424for (i=dx-1; i>=dy; --i)1425{1426p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */1427for (j=i-dy1; j<=i && j<=dz; j++)1428{1429p1 += z[j]*y[i-j];1430if (p1 & HIGHBIT) p1 %= p;1431}1432p1 %= p;1433z[i-dy] = p1? (long) ((p - p1)*inv) % p: 0;1434}1435}1436else1437{1438z[dz] = Fl_mul(inv, x[dx], p);1439for (i=dx-1; i>=dy; --i)1440{ /* compute -p1 instead of p1 (pb with ulongs otherwise) */1441p1 = p - uel(x,i);1442for (j=i-dy1; j<=i && j<=dz; j++)1443p1 = Fl_add(p1, Fl_mul(z[j],y[i-j],p), p);1444z[i-dy] = p1? Fl_mul(p - p1, inv, p): 0;1445}1446}1447q = Flx_renormalize(z-2, dz+3);1448if (!pr) return q;14491450c = cgetg(dy + 3, t_VECSMALL); c[1] = sv; c += 2;1451if (SMALL_ULONG(p))1452{1453for (i=0; i<dy; i++)1454{1455p1 = (ulong)z[0]*y[i];1456for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)1457{1458p1 += (ulong)z[j]*y[i-j];1459if (p1 & HIGHBIT) p1 %= p;1460}1461c[i] = Fl_sub(x[i], p1%p, p);1462}1463}1464else1465{1466for (i=0; i<dy; i++)1467{1468p1 = Fl_mul(z[0],y[i],p);1469for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)1470p1 = Fl_add(p1, Fl_mul(z[j],y[i-j],p), p);1471c[i] = Fl_sub(x[i], p1, p);1472}1473}1474i=dy-1; while (i>=0 && !c[i]) i--;1475c = Flx_renormalize(c-2, i+3);1476if (pr == ONLY_DIVIDES)1477{ if (lg(c) != 2) return NULL; }1478else1479*pr = c;1480return q;1481}14821483/* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1)1484* and mg is the Barrett inverse of T. */1485static GEN1486Flx_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, ulong p, GEN *pr)1487{1488GEN q, r;1489long lt = degpol(T); /*We discard the leading term*/1490long ld, lm, lT, lmg;1491ld = l-lt;1492lm = minss(ld, lgpol(mg));1493lT = Flx_lgrenormalizespec(T+2,lt);1494lmg = Flx_lgrenormalizespec(mg+2,lm);1495q = Flx_recipspec(x+lt,ld,ld); /* q = rec(x) lz<=ld*/1496q = Flx_mulspec(q+2,mg+2,p,lgpol(q),lmg); /* q = rec(x) * mg lz<=ld+lm*/1497q = Flx_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lz<=ld*/1498if (!pr) return q;1499r = Flx_mulspec(q+2,T+2,p,lgpol(q),lT); /* r = q*pol lz<=ld+lt*/1500r = Flx_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - q*pol lz<=lt */1501if (pr == ONLY_REM) return r;1502*pr = r; return q;1503}15041505static GEN1506Flx_divrem_Barrett(GEN x, GEN mg, GEN T, ulong p, GEN *pr)1507{1508GEN q = NULL, r = Flx_copy(x);1509long l = lgpol(x), lt = degpol(T), lm = 2*lt-1, v = T[1];1510long i;1511if (l <= lt)1512{1513if (pr == ONLY_REM) return Flx_copy(x);1514if (pr == ONLY_DIVIDES) return lgpol(x)? NULL: pol0_Flx(v);1515if (pr) *pr = Flx_copy(x);1516return pol0_Flx(v);1517}1518if (lt <= 1)1519return Flx_divrem_basecase(x,T,p,pr);1520if (pr != ONLY_REM && l>lm)1521{ q = zero_zv(l-lt+1); q[1] = T[1]; }1522while (l>lm)1523{1524GEN zr, zq = Flx_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr);1525long lz = lgpol(zr);1526if (pr != ONLY_REM)1527{1528long lq = lgpol(zq);1529for(i=0; i<lq; i++) q[2+l-lm+i] = zq[2+i];1530}1531for(i=0; i<lz; i++) r[2+l-lm+i] = zr[2+i];1532l = l-lm+lz;1533}1534if (pr == ONLY_REM)1535{1536if (l > lt)1537r = Flx_divrem_Barrettspec(r+2,l,mg,T,p,ONLY_REM);1538else1539r = Flx_renormalize(r, l+2);1540r[1] = v; return r;1541}1542if (l > lt)1543{1544GEN zq = Flx_divrem_Barrettspec(r+2,l,mg,T,p, pr ? &r: NULL);1545if (!q) q = zq;1546else1547{1548long lq = lgpol(zq);1549for(i=0; i<lq; i++) q[2+i] = zq[2+i];1550}1551}1552else if (pr)1553r = Flx_renormalize(r, l+2);1554q[1] = v; q = Flx_renormalize(q, lg(q));1555if (pr == ONLY_DIVIDES) return lgpol(r)? NULL: q;1556if (pr) { r[1] = v; *pr = r; }1557return q;1558}15591560GEN1561Flx_divrem(GEN x, GEN T, ulong p, GEN *pr)1562{1563GEN B, y;1564long dy, dx, d;1565if (pr==ONLY_REM) return Flx_rem(x, T, p);1566y = get_Flx_red(T, &B);1567dy = degpol(y); dx = degpol(x); d = dx-dy;1568if (!B && d+3 < get_Fl_threshold(p, Flx_DIVREM_BARRETT_LIMIT,Flx_DIVREM2_BARRETT_LIMIT))1569return Flx_divrem_basecase(x,y,p,pr);1570else1571{1572pari_sp av = avma;1573GEN mg = B? B: Flx_invBarrett(y, p);1574GEN q1 = Flx_divrem_Barrett(x,mg,y,p,pr);1575if (!q1) return gc_NULL(av);1576if (!pr || pr==ONLY_DIVIDES) return gerepileuptoleaf(av, q1);1577gerepileall(av,2,&q1,pr);1578return q1;1579}1580}15811582GEN1583Flx_rem(GEN x, GEN T, ulong p)1584{1585GEN B, y = get_Flx_red(T, &B);1586long dy = degpol(y), dx = degpol(x), d = dx-dy;1587if (d < 0) return Flx_copy(x);1588if (!B && d+3 < get_Fl_threshold(p, Flx_REM_BARRETT_LIMIT,Flx_REM2_BARRETT_LIMIT))1589return Flx_rem_basecase(x,y,p);1590else1591{1592pari_sp av=avma;1593GEN mg = B ? B: Flx_invBarrett(y, p);1594GEN r = Flx_divrem_Barrett(x, mg, y, p, ONLY_REM);1595return gerepileuptoleaf(av, r);1596}1597}15981599/* reduce T mod (X^n - 1, p). Shallow function */1600GEN1601Flx_mod_Xnm1(GEN T, ulong n, ulong p)1602{1603long i, j, L = lg(T), l = n+2;1604GEN S;1605if (L <= l || n & ~LGBITS) return T;1606S = cgetg(l, t_VECSMALL);1607S[1] = T[1];1608for (i = 2; i < l; i++) S[i] = T[i];1609for (j = 2; i < L; i++) {1610S[j] = Fl_add(S[j], T[i], p);1611if (++j == l) j = 2;1612}1613return Flx_renormalize(S, l);1614}1615/* reduce T mod (X^n + 1, p). Shallow function */1616GEN1617Flx_mod_Xn1(GEN T, ulong n, ulong p)1618{1619long i, j, L = lg(T), l = n+2;1620GEN S;1621if (L <= l || n & ~LGBITS) return T;1622S = cgetg(l, t_VECSMALL);1623S[1] = T[1];1624for (i = 2; i < l; i++) S[i] = T[i];1625for (j = 2; i < L; i++) {1626S[j] = Fl_sub(S[j], T[i], p);1627if (++j == l) j = 2;1628}1629return Flx_renormalize(S, l);1630}16311632struct _Flxq {1633GEN aut;1634GEN T;1635ulong p;1636};16371638static GEN1639_Flx_divrem(void * E, GEN x, GEN y, GEN *r)1640{1641struct _Flxq *D = (struct _Flxq*) E;1642return Flx_divrem(x, y, D->p, r);1643}1644static GEN1645_Flx_add(void * E, GEN x, GEN y) {1646struct _Flxq *D = (struct _Flxq*) E;1647return Flx_add(x, y, D->p);1648}1649static GEN1650_Flx_mul(void *E, GEN x, GEN y) {1651struct _Flxq *D = (struct _Flxq*) E;1652return Flx_mul(x, y, D->p);1653}1654static GEN1655_Flx_sqr(void *E, GEN x) {1656struct _Flxq *D = (struct _Flxq*) E;1657return Flx_sqr(x, D->p);1658}16591660static struct bb_ring Flx_ring = { _Flx_add,_Flx_mul,_Flx_sqr };16611662GEN1663Flx_digits(GEN x, GEN T, ulong p)1664{1665pari_sp av = avma;1666struct _Flxq D;1667long d = degpol(T), n = (lgpol(x)+d-1)/d;1668GEN z;1669D.p = p;1670z = gen_digits(x,T,n,(void *)&D, &Flx_ring, _Flx_divrem);1671return gerepileupto(av, z);1672}16731674GEN1675FlxV_Flx_fromdigits(GEN x, GEN T, ulong p)1676{1677pari_sp av = avma;1678struct _Flxq D;1679GEN z;1680D.p = p;1681z = gen_fromdigits(x,T,(void *)&D, &Flx_ring);1682return gerepileupto(av, z);1683}16841685long1686Flx_val(GEN x)1687{1688long i, l=lg(x);1689if (l==2) return LONG_MAX;1690for (i=2; i<l && x[i]==0; i++) /*empty*/;1691return i-2;1692}1693long1694Flx_valrem(GEN x, GEN *Z)1695{1696long v, i, l=lg(x);1697GEN y;1698if (l==2) { *Z = Flx_copy(x); return LONG_MAX; }1699for (i=2; i<l && x[i]==0; i++) /*empty*/;1700v = i-2;1701if (v == 0) { *Z = x; return 0; }1702l -= v;1703y = cgetg(l, t_VECSMALL); y[1] = x[1];1704for (i=2; i<l; i++) y[i] = x[i+v];1705*Z = y; return v;1706}17071708GEN1709Flx_deriv(GEN z, ulong p)1710{1711long i,l = lg(z)-1;1712GEN x;1713if (l < 2) l = 2;1714x = cgetg(l, t_VECSMALL); x[1] = z[1]; z++;1715if (HIGHWORD(l | p))1716for (i=2; i<l; i++) x[i] = Fl_mul((ulong)i-1, z[i], p);1717else1718for (i=2; i<l; i++) x[i] = ((i-1) * z[i]) % p;1719return Flx_renormalize(x,l);1720}17211722static GEN1723Flx_integXn(GEN x, long n, ulong p)1724{1725long i, lx = lg(x);1726GEN y;1727if (lx == 2) return Flx_copy(x);1728y = cgetg(lx, t_VECSMALL); y[1] = x[1];1729for (i=2; i<lx; i++)1730{1731ulong xi = uel(x,i);1732if (xi == 0)1733uel(y,i) = 0;1734else1735{1736ulong j = n+i-1;1737ulong d = ugcd(j, xi);1738if (d==1)1739uel(y,i) = Fl_div(xi, j, p);1740else1741uel(y,i) = Fl_div(xi/d, j/d, p);1742}1743}1744return Flx_renormalize(y, lx);;1745}17461747GEN1748Flx_integ(GEN x, ulong p)1749{1750long i, lx = lg(x);1751GEN y;1752if (lx == 2) return Flx_copy(x);1753y = cgetg(lx+1, t_VECSMALL); y[1] = x[1];1754uel(y,2) = 0;1755for (i=3; i<=lx; i++)1756uel(y,i) = uel(x,i-1) ? Fl_div(uel(x,i-1), (i-2)%p, p): 0UL;1757return Flx_renormalize(y, lx+1);;1758}17591760/* assume p prime */1761GEN1762Flx_diff1(GEN P, ulong p)1763{1764return Flx_sub(Flx_translate1(P, p), P, p);1765}17661767GEN1768Flx_deflate(GEN x0, long d)1769{1770GEN z, y, x;1771long i,id, dy, dx = degpol(x0);1772if (d == 1 || dx <= 0) return Flx_copy(x0);1773dy = dx/d;1774y = cgetg(dy+3, t_VECSMALL); y[1] = x0[1];1775z = y + 2;1776x = x0+ 2;1777for (i=id=0; i<=dy; i++,id+=d) z[i] = x[id];1778return y;1779}17801781GEN1782Flx_inflate(GEN x0, long d)1783{1784long i, id, dy, dx = degpol(x0);1785GEN x = x0 + 2, z, y;1786if (dx <= 0) return Flx_copy(x0);1787dy = dx*d;1788y = cgetg(dy+3, t_VECSMALL); y[1] = x0[1];1789z = y + 2;1790for (i=0; i<=dy; i++) z[i] = 0;1791for (i=id=0; i<=dx; i++,id+=d) z[id] = x[i];1792return y;1793}17941795/* write p(X) = a_0(X^k) + X*a_1(X^k) + ... + X^(k-1)*a_{k-1}(X^k) */1796GEN1797Flx_splitting(GEN p, long k)1798{1799long n = degpol(p), v = p[1], m, i, j, l;1800GEN r;18011802m = n/k;1803r = cgetg(k+1,t_VEC);1804for(i=1; i<=k; i++)1805{1806gel(r,i) = cgetg(m+3, t_VECSMALL);1807mael(r,i,1) = v;1808}1809for (j=1, i=0, l=2; i<=n; i++)1810{1811mael(r,j,l) = p[2+i];1812if (j==k) { j=1; l++; } else j++;1813}1814for(i=1; i<=k; i++)1815gel(r,i) = Flx_renormalize(gel(r,i),i<j?l+1:l);1816return r;1817}1818static GEN1819Flx_halfgcd_basecase(GEN a, GEN b, ulong p)1820{1821pari_sp av=avma;1822GEN u,u1,v,v1;1823long vx = a[1];1824long n = lgpol(a)>>1;1825u1 = v = pol0_Flx(vx);1826u = v1 = pol1_Flx(vx);1827while (lgpol(b)>n)1828{1829GEN r, q = Flx_divrem(a,b,p, &r);1830a = b; b = r; swap(u,u1); swap(v,v1);1831u1 = Flx_sub(u1, Flx_mul(u, q, p), p);1832v1 = Flx_sub(v1, Flx_mul(v, q ,p), p);1833if (gc_needed(av,2))1834{1835if (DEBUGMEM>1) pari_warn(warnmem,"Flx_halfgcd (d = %ld)",degpol(b));1836gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);1837}1838}1839return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));1840}1841/* ux + vy */1842static GEN1843Flx_addmulmul(GEN u, GEN v, GEN x, GEN y, ulong p)1844{ return Flx_add(Flx_mul(u,x, p), Flx_mul(v,y, p), p); }18451846static GEN1847FlxM_Flx_mul2(GEN M, GEN x, GEN y, ulong p)1848{1849GEN res = cgetg(3, t_COL);1850gel(res, 1) = Flx_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p);1851gel(res, 2) = Flx_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p);1852return res;1853}18541855#if 01856static GEN1857FlxM_mul2_old(GEN M, GEN N, ulong p)1858{1859GEN res = cgetg(3, t_MAT);1860gel(res, 1) = FlxM_Flx_mul2(M,gcoeff(N,1,1),gcoeff(N,2,1),p);1861gel(res, 2) = FlxM_Flx_mul2(M,gcoeff(N,1,2),gcoeff(N,2,2),p);1862return res;1863}1864#endif1865/* A,B are 2x2 matrices, Flx entries. Return A x B using Strassen 7M formula */1866static GEN1867FlxM_mul2(GEN A, GEN B, ulong p)1868{1869GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);1870GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);1871GEN M1 = Flx_mul(Flx_add(A11,A22, p), Flx_add(B11,B22, p), p);1872GEN M2 = Flx_mul(Flx_add(A21,A22, p), B11, p);1873GEN M3 = Flx_mul(A11, Flx_sub(B12,B22, p), p);1874GEN M4 = Flx_mul(A22, Flx_sub(B21,B11, p), p);1875GEN M5 = Flx_mul(Flx_add(A11,A12, p), B22, p);1876GEN M6 = Flx_mul(Flx_sub(A21,A11, p), Flx_add(B11,B12, p), p);1877GEN M7 = Flx_mul(Flx_sub(A12,A22, p), Flx_add(B21,B22, p), p);1878GEN T1 = Flx_add(M1,M4, p), T2 = Flx_sub(M7,M5, p);1879GEN T3 = Flx_sub(M1,M2, p), T4 = Flx_add(M3,M6, p);1880retmkmat2(mkcol2(Flx_add(T1,T2, p), Flx_add(M2,M4, p)),1881mkcol2(Flx_add(M3,M5, p), Flx_add(T3,T4, p)));1882}18831884/* Return [0,1;1,-q]*M */1885static GEN1886Flx_FlxM_qmul(GEN q, GEN M, ulong p)1887{1888GEN u, v, res = cgetg(3, t_MAT);1889u = Flx_sub(gcoeff(M,1,1), Flx_mul(gcoeff(M,2,1), q, p), p);1890gel(res,1) = mkcol2(gcoeff(M,2,1), u);1891v = Flx_sub(gcoeff(M,1,2), Flx_mul(gcoeff(M,2,2), q, p), p);1892gel(res,2) = mkcol2(gcoeff(M,2,2), v);1893return res;1894}18951896static GEN1897matid2_FlxM(long v)1898{1899return mkmat2(mkcol2(pol1_Flx(v),pol0_Flx(v)),1900mkcol2(pol0_Flx(v),pol1_Flx(v)));1901}19021903static GEN1904Flx_halfgcd_split(GEN x, GEN y, ulong p)1905{1906pari_sp av=avma;1907GEN R, S, V;1908GEN y1, r, q;1909long l = lgpol(x), n = l>>1, k;1910if (lgpol(y)<=n) return matid2_FlxM(x[1]);1911R = Flx_halfgcd(Flx_shift(x,-n),Flx_shift(y,-n),p);1912V = FlxM_Flx_mul2(R,x,y,p); y1 = gel(V,2);1913if (lgpol(y1)<=n) return gerepilecopy(av, R);1914q = Flx_divrem(gel(V,1), y1, p, &r);1915k = 2*n-degpol(y1);1916S = Flx_halfgcd(Flx_shift(y1,-k), Flx_shift(r,-k),p);1917return gerepileupto(av, FlxM_mul2(S,Flx_FlxM_qmul(q,R,p),p));1918}19191920/* Return M in GL_2(Fl[X]) such that:1921if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')1922*/19231924static GEN1925Flx_halfgcd_i(GEN x, GEN y, ulong p)1926{1927if (lgpol(x) < get_Fl_threshold(p, Flx_HALFGCD_LIMIT, Flx_HALFGCD2_LIMIT))1928return Flx_halfgcd_basecase(x,y,p);1929return Flx_halfgcd_split(x,y,p);1930}19311932GEN1933Flx_halfgcd(GEN x, GEN y, ulong p)1934{1935pari_sp av;1936GEN M,q,r;1937long lx=lgpol(x), ly=lgpol(y);1938if (!lx)1939{1940long v = x[1];1941retmkmat2(mkcol2(pol0_Flx(v),pol1_Flx(v)),1942mkcol2(pol1_Flx(v),pol0_Flx(v)));1943}1944if (ly < lx) return Flx_halfgcd_i(x,y,p);1945av = avma;1946q = Flx_divrem(y,x,p,&r);1947M = Flx_halfgcd_i(x,r,p);1948gcoeff(M,1,1) = Flx_sub(gcoeff(M,1,1), Flx_mul(q, gcoeff(M,1,2), p), p);1949gcoeff(M,2,1) = Flx_sub(gcoeff(M,2,1), Flx_mul(q, gcoeff(M,2,2), p), p);1950return gerepilecopy(av, M);1951}19521953/*Do not garbage collect*/1954static GEN1955Flx_gcd_basecase(GEN a, GEN b, ulong p)1956{1957pari_sp av = avma;1958ulong iter = 0;1959if (lg(b) > lg(a)) swap(a, b);1960while (lgpol(b))1961{1962GEN c = Flx_rem(a,b,p);1963iter++; a = b; b = c;1964if (gc_needed(av,2))1965{1966if (DEBUGMEM>1) pari_warn(warnmem,"Flx_gcd (d = %ld)",degpol(c));1967gerepileall(av,2, &a,&b);1968}1969}1970return iter < 2 ? Flx_copy(a) : a;1971}19721973GEN1974Flx_gcd(GEN x, GEN y, ulong p)1975{1976pari_sp av = avma;1977long lim;1978if (!lgpol(x)) return Flx_copy(y);1979lim = get_Fl_threshold(p, Flx_GCD_LIMIT, Flx_GCD2_LIMIT);1980while (lgpol(y) >= lim)1981{1982GEN c;1983if (lgpol(y)<=(lgpol(x)>>1))1984{1985GEN r = Flx_rem(x, y, p);1986x = y; y = r;1987}1988c = FlxM_Flx_mul2(Flx_halfgcd(x,y, p), x, y, p);1989x = gel(c,1); y = gel(c,2);1990if (gc_needed(av,2))1991{1992if (DEBUGMEM>1) pari_warn(warnmem,"Flx_gcd (y = %ld)",degpol(y));1993gerepileall(av,2,&x,&y);1994}1995}1996return gerepileuptoleaf(av, Flx_gcd_basecase(x,y,p));1997}19981999int2000Flx_is_squarefree(GEN z, ulong p)2001{2002pari_sp av = avma;2003GEN d = Flx_gcd(z, Flx_deriv(z,p) , p);2004return gc_bool(av, degpol(d) == 0);2005}20062007static long2008Flx_is_smooth_squarefree(GEN f, long r, ulong p)2009{2010pari_sp av = avma;2011long i;2012GEN sx = polx_Flx(f[1]), a = sx;2013for(i=1;;i++)2014{2015if (degpol(f)<=r) return gc_long(av,1);2016a = Flxq_powu(Flx_rem(a,f,p), p, f, p);2017if (Flx_equal(a, sx)) return gc_long(av,1);2018if (i==r) return gc_long(av,0);2019f = Flx_div(f, Flx_gcd(Flx_sub(a,sx,p),f,p),p);2020}2021}20222023static long2024Flx_is_l_pow(GEN x, ulong p)2025{2026ulong i, lx = lgpol(x);2027for (i=1; i<lx; i++)2028if (x[i+2] && i%p) return 0;2029return 1;2030}20312032int2033Flx_is_smooth(GEN g, long r, ulong p)2034{2035while (1)2036{2037GEN f = Flx_gcd(g, Flx_deriv(g, p), p);2038if (!Flx_is_smooth_squarefree(Flx_div(g, f, p), r, p))2039return 0;2040if (degpol(f)==0) return 1;2041g = Flx_is_l_pow(f,p) ? Flx_deflate(f, p): f;2042}2043}20442045static GEN2046Flx_extgcd_basecase(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv)2047{2048pari_sp av=avma;2049GEN u,v,d,d1,v1;2050long vx = a[1];2051d = a; d1 = b;2052v = pol0_Flx(vx); v1 = pol1_Flx(vx);2053while (lgpol(d1))2054{2055GEN r, q = Flx_divrem(d,d1,p, &r);2056v = Flx_sub(v,Flx_mul(q,v1,p),p);2057u=v; v=v1; v1=u;2058u=r; d=d1; d1=u;2059if (gc_needed(av,2))2060{2061if (DEBUGMEM>1) pari_warn(warnmem,"Flx_extgcd (d = %ld)",degpol(d));2062gerepileall(av,5, &d,&d1,&u,&v,&v1);2063}2064}2065if (ptu) *ptu = Flx_div(Flx_sub(d, Flx_mul(b,v,p), p), a, p);2066*ptv = v; return d;2067}20682069static GEN2070Flx_extgcd_halfgcd(GEN x, GEN y, ulong p, GEN *ptu, GEN *ptv)2071{2072pari_sp av=avma;2073GEN u,v,R = matid2_FlxM(x[1]);2074long lim = get_Fl_threshold(p, Flx_EXTGCD_LIMIT, Flx_EXTGCD2_LIMIT);2075while (lgpol(y) >= lim)2076{2077GEN M, c;2078if (lgpol(y)<=(lgpol(x)>>1))2079{2080GEN r, q = Flx_divrem(x, y, p, &r);2081x = y; y = r;2082R = Flx_FlxM_qmul(q, R, p);2083}2084M = Flx_halfgcd(x,y, p);2085c = FlxM_Flx_mul2(M, x,y, p);2086R = FlxM_mul2(M, R, p);2087x = gel(c,1); y = gel(c,2);2088gerepileall(av,3,&x,&y,&R);2089}2090y = Flx_extgcd_basecase(x,y,p,&u,&v);2091if (ptu) *ptu = Flx_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1),p);2092*ptv = Flx_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2),p);2093return y;2094}20952096/* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st2097* ux + vy = gcd (mod p) */2098GEN2099Flx_extgcd(GEN x, GEN y, ulong p, GEN *ptu, GEN *ptv)2100{2101GEN d;2102pari_sp ltop=avma;2103long lim = get_Fl_threshold(p, Flx_EXTGCD_LIMIT, Flx_EXTGCD2_LIMIT);2104if (lgpol(y) >= lim)2105d = Flx_extgcd_halfgcd(x, y, p, ptu, ptv);2106else2107d = Flx_extgcd_basecase(x, y, p, ptu, ptv);2108gerepileall(ltop,ptu?3:2,&d,ptv,ptu);2109return d;2110}21112112ulong2113Flx_resultant(GEN a, GEN b, ulong p)2114{2115long da,db,dc,cnt;2116ulong lb, res = 1UL;2117pari_sp av;2118GEN c;21192120if (lgpol(a)==0 || lgpol(b)==0) return 0;2121da = degpol(a);2122db = degpol(b);2123if (db > da)2124{2125swapspec(a,b, da,db);2126if (both_odd(da,db)) res = p-res;2127}2128else if (!da) return 1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */2129cnt = 0; av = avma;2130while (db)2131{2132lb = b[db+2];2133c = Flx_rem(a,b, p);2134a = b; b = c; dc = degpol(c);2135if (dc < 0) return gc_long(av,0);21362137if (both_odd(da,db)) res = p - res;2138if (lb != 1) res = Fl_mul(res, Fl_powu(lb, da - dc, p), p);2139if (++cnt == 100) { cnt = 0; gerepileall(av, 2, &a, &b); }2140da = db; /* = degpol(a) */2141db = dc; /* = degpol(b) */2142}2143return gc_ulong(av, Fl_mul(res, Fl_powu(b[2], da, p), p));2144}21452146/* If resultant is 0, *ptU and *ptV are not set */2147ulong2148Flx_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV)2149{2150GEN z,q,u,v, x = a, y = b;2151ulong lb, res = 1UL;2152pari_sp av = avma;2153long dx, dy, dz;2154long vs=a[1];21552156dx = degpol(x);2157dy = degpol(y);2158if (dy > dx)2159{2160swap(x,y); lswap(dx,dy); pswap(ptU, ptV);2161a = x; b = y;2162if (both_odd(dx,dy)) res = p-res;2163}2164/* dy <= dx */2165if (dy < 0) return 0;21662167u = pol0_Flx(vs);2168v = pol1_Flx(vs); /* v = 1 */2169while (dy)2170{ /* b u = x (a), b v = y (a) */2171lb = y[dy+2];2172q = Flx_divrem(x,y, p, &z);2173x = y; y = z; /* (x,y) = (y, x - q y) */2174dz = degpol(z); if (dz < 0) return gc_ulong(av,0);2175z = Flx_sub(u, Flx_mul(q,v, p), p);2176u = v; v = z; /* (u,v) = (v, u - q v) */21772178if (both_odd(dx,dy)) res = p - res;2179if (lb != 1) res = Fl_mul(res, Fl_powu(lb, dx-dz, p), p);2180dx = dy; /* = degpol(x) */2181dy = dz; /* = degpol(y) */2182}2183res = Fl_mul(res, Fl_powu(y[2], dx, p), p);2184lb = Fl_mul(res, Fl_inv(y[2],p), p);2185v = gerepileuptoleaf(av, Flx_Fl_mul(v, lb, p));2186av = avma;2187u = Flx_sub(Fl_to_Flx(res,vs), Flx_mul(b,v,p), p);2188u = gerepileuptoleaf(av, Flx_div(u,a,p)); /* = (res - b v) / a */2189*ptU = u;2190*ptV = v; return res;2191}21922193ulong2194Flx_eval_powers_pre(GEN x, GEN y, ulong p, ulong pi)2195{2196ulong l0, l1, h0, h1, v1, i = 1, lx = lg(x)-1;2197LOCAL_OVERFLOW;2198LOCAL_HIREMAINDER;2199x++;22002201if (lx == 1)2202return 0;2203l1 = mulll(uel(x,i), uel(y,i)); h1 = hiremainder; v1 = 0;2204while (++i < lx) {2205l0 = mulll(uel(x,i), uel(y,i)); h0 = hiremainder;2206l1 = addll(l0, l1); h1 = addllx(h0, h1); v1 += overflow;2207}2208if (v1 == 0) return remll_pre(h1, l1, p, pi);2209else return remlll_pre(v1, h1, l1, p, pi);2210}22112212INLINE ulong2213Flx_eval_pre_i(GEN x, ulong y, ulong p, ulong pi)2214{2215ulong p1;2216long i=lg(x)-1;2217if (i<=2)2218return (i==2)? x[2]: 0;2219p1 = x[i];2220for (i--; i>=2; i--)2221p1 = Fl_addmul_pre(uel(x, i), p1, y, p, pi);2222return p1;2223}22242225ulong2226Flx_eval_pre(GEN x, ulong y, ulong p, ulong pi)2227{2228if (degpol(x) > 15)2229{2230pari_sp av = avma;2231GEN v = Fl_powers_pre(y, degpol(x), p, pi);2232ulong r = Flx_eval_powers_pre(x, v, p, pi);2233return gc_ulong(av,r);2234}2235else2236return Flx_eval_pre_i(x, y, p, pi);2237}22382239ulong2240Flx_eval(GEN x, ulong y, ulong p)2241{2242return Flx_eval_pre(x, y, p, get_Fl_red(p));2243}22442245ulong2246Flv_prod_pre(GEN x, ulong p, ulong pi)2247{2248pari_sp ltop = avma;2249GEN v;2250long i,k,lx = lg(x);2251if (lx == 1) return 1UL;2252if (lx == 2) return uel(x,1);2253v = cgetg(1+(lx << 1), t_VECSMALL);2254k = 1;2255for (i=1; i<lx-1; i+=2)2256uel(v,k++) = Fl_mul_pre(uel(x,i), uel(x,i+1), p, pi);2257if (i < lx) uel(v,k++) = uel(x,i);2258while (k > 2)2259{2260lx = k; k = 1;2261for (i=1; i<lx-1; i+=2)2262uel(v,k++) = Fl_mul_pre(uel(v,i), uel(v,i+1), p, pi);2263if (i < lx) uel(v,k++) = uel(v,i);2264}2265return gc_ulong(ltop, uel(v,1));2266}22672268ulong2269Flv_prod(GEN v, ulong p)2270{2271return Flv_prod_pre(v, p, get_Fl_red(p));2272}22732274GEN2275FlxV_prod(GEN V, ulong p)2276{2277struct _Flxq D;2278D.T = NULL; D.aut = NULL; D.p = p;2279return gen_product(V, (void *)&D, &_Flx_mul);2280}22812282/* compute prod (x - a[i]) */2283GEN2284Flv_roots_to_pol(GEN a, ulong p, long vs)2285{2286struct _Flxq D;2287long i,k,lx = lg(a);2288GEN p1;2289if (lx == 1) return pol1_Flx(vs);2290p1 = cgetg(lx, t_VEC);2291for (k=1,i=1; i<lx-1; i+=2)2292gel(p1,k++) = mkvecsmall4(vs, Fl_mul(a[i], a[i+1], p),2293Fl_neg(Fl_add(a[i],a[i+1],p),p), 1);2294if (i < lx)2295gel(p1,k++) = mkvecsmall3(vs, Fl_neg(a[i],p), 1);2296D.T = NULL; D.aut = NULL; D.p = p;2297setlg(p1, k); return gen_product(p1, (void *)&D, _Flx_mul);2298}22992300/* set v[i] = w[i]^{-1}; may be called with w = v, suitable for "large" p */2301INLINE void2302Flv_inv_pre_indir(GEN w, GEN v, ulong p, ulong pi)2303{2304pari_sp av = avma;2305long n = lg(w), i;2306ulong u;2307GEN c;23082309if (n == 1) return;2310c = cgetg(n, t_VECSMALL); c[1] = w[1];2311for (i = 2; i < n; ++i) c[i] = Fl_mul_pre(w[i], c[i-1], p, pi);2312i = n-1; u = Fl_inv(c[i], p);2313for ( ; i > 1; --i)2314{2315ulong t = Fl_mul_pre(u, c[i-1], p, pi);2316u = Fl_mul_pre(u, w[i], p, pi); v[i] = t;2317}2318v[1] = u; set_avma(av);2319}23202321void2322Flv_inv_pre_inplace(GEN v, ulong p, ulong pi) { Flv_inv_pre_indir(v,v, p, pi); }23232324GEN2325Flv_inv_pre(GEN w, ulong p, ulong pi)2326{ GEN v = cgetg(lg(w), t_VECSMALL); Flv_inv_pre_indir(w, v, p, pi); return v; }23272328/* set v[i] = w[i]^{-1}; may be called with w = v, suitable for SMALL_ULONG p */2329INLINE void2330Flv_inv_indir(GEN w, GEN v, ulong p)2331{2332pari_sp av = avma;2333long n = lg(w), i;2334ulong u;2335GEN c;23362337if (n == 1) return;2338c = cgetg(n, t_VECSMALL); c[1] = w[1];2339for (i = 2; i < n; ++i) c[i] = Fl_mul(w[i], c[i-1], p);2340i = n-1; u = Fl_inv(c[i], p);2341for ( ; i > 1; --i)2342{2343ulong t = Fl_mul(u, c[i-1], p);2344u = Fl_mul(u, w[i], p); v[i] = t;2345}2346v[1] = u; set_avma(av);2347}2348static void2349Flv_inv_i(GEN v, GEN w, ulong p)2350{2351if (SMALL_ULONG(p)) Flv_inv_indir(w, v, p);2352else Flv_inv_pre_indir(w, v, p, get_Fl_red(p));2353}2354void2355Flv_inv_inplace(GEN v, ulong p) { Flv_inv_i(v, v, p); }2356GEN2357Flv_inv(GEN w, ulong p)2358{ GEN v = cgetg(lg(w), t_VECSMALL); Flv_inv_i(v, w, p); return v; }23592360GEN2361Flx_div_by_X_x(GEN a, ulong x, ulong p, ulong *rem)2362{2363long l = lg(a), i;2364GEN a0, z0, z;2365if (l <= 3)2366{2367if (rem) *rem = l == 2? 0: a[2];2368return zero_Flx(a[1]);2369}2370z = cgetg(l-1,t_VECSMALL); z[1] = a[1];2371a0 = a + l-1;2372z0 = z + l-2; *z0 = *a0--;2373if (SMALL_ULONG(p))2374{2375for (i=l-3; i>1; i--) /* z[i] = (a[i+1] + x*z[i+1]) % p */2376{2377ulong t = (*a0-- + x * *z0--) % p;2378*z0 = (long)t;2379}2380if (rem) *rem = (*a0 + x * *z0) % p;2381}2382else2383{2384for (i=l-3; i>1; i--)2385{2386ulong t = Fl_add((ulong)*a0--, Fl_mul(x, *z0--, p), p);2387*z0 = (long)t;2388}2389if (rem) *rem = Fl_add((ulong)*a0, Fl_mul(x, *z0, p), p);2390}2391return z;2392}23932394/* xa, ya = t_VECSMALL */2395static GEN2396Flv_producttree(GEN xa, GEN s, ulong p, long vs)2397{2398long n = lg(xa)-1;2399long m = n==1 ? 1: expu(n-1)+1;2400long i, j, k, ls = lg(s);2401GEN T = cgetg(m+1, t_VEC);2402GEN t = cgetg(ls, t_VEC);2403for (j=1, k=1; j<ls; k+=s[j++])2404gel(t, j) = s[j] == 1 ?2405mkvecsmall3(vs, Fl_neg(xa[k], p), 1):2406mkvecsmall4(vs, Fl_mul(xa[k], xa[k+1], p),2407Fl_neg(Fl_add(xa[k],xa[k+1],p),p), 1);2408gel(T,1) = t;2409for (i=2; i<=m; i++)2410{2411GEN u = gel(T, i-1);2412long n = lg(u)-1;2413GEN t = cgetg(((n+1)>>1)+1, t_VEC);2414for (j=1, k=1; k<n; j++, k+=2)2415gel(t, j) = Flx_mul(gel(u, k), gel(u, k+1), p);2416gel(T, i) = t;2417}2418return T;2419}24202421static GEN2422Flx_Flv_multieval_tree(GEN P, GEN xa, GEN T, ulong p)2423{2424long i,j,k;2425long m = lg(T)-1;2426GEN R = cgetg(lg(xa), t_VECSMALL);2427GEN Tp = cgetg(m+1, t_VEC), t;2428gel(Tp, m) = mkvec(P);2429for (i=m-1; i>=1; i--)2430{2431GEN u = gel(T, i), v = gel(Tp, i+1);2432long n = lg(u)-1;2433t = cgetg(n+1, t_VEC);2434for (j=1, k=1; k<n; j++, k+=2)2435{2436gel(t, k) = Flx_rem(gel(v, j), gel(u, k), p);2437gel(t, k+1) = Flx_rem(gel(v, j), gel(u, k+1), p);2438}2439gel(Tp, i) = t;2440}2441{2442GEN u = gel(T, i+1), v = gel(Tp, i+1);2443long n = lg(u)-1;2444for (j=1, k=1; j<=n; j++)2445{2446long c, d = degpol(gel(u,j));2447for (c=1; c<=d; c++, k++) R[k] = Flx_eval(gel(v, j), xa[k], p);2448}2449return gc_const((pari_sp)R, R);2450}2451}24522453static GEN2454FlvV_polint_tree(GEN T, GEN R, GEN s, GEN xa, GEN ya, ulong p, long vs)2455{2456pari_sp av = avma;2457long m = lg(T)-1;2458long i, j, k, ls = lg(s);2459GEN Tp = cgetg(m+1, t_VEC);2460GEN t = cgetg(ls, t_VEC);2461for (j=1, k=1; j<ls; k+=s[j++])2462if (s[j]==2)2463{2464ulong a = Fl_mul(ya[k], R[k], p);2465ulong b = Fl_mul(ya[k+1], R[k+1], p);2466gel(t, j) = mkvecsmall3(vs, Fl_neg(Fl_add(Fl_mul(xa[k], b, p ),2467Fl_mul(xa[k+1], a, p), p), p), Fl_add(a, b, p));2468gel(t, j) = Flx_renormalize(gel(t, j), 4);2469}2470else2471gel(t, j) = Fl_to_Flx(Fl_mul(ya[k], R[k], p), vs);2472gel(Tp, 1) = t;2473for (i=2; i<=m; i++)2474{2475GEN u = gel(T, i-1);2476GEN t = cgetg(lg(gel(T,i)), t_VEC);2477GEN v = gel(Tp, i-1);2478long n = lg(v)-1;2479for (j=1, k=1; k<n; j++, k+=2)2480gel(t, j) = Flx_add(Flx_mul(gel(u, k), gel(v, k+1), p),2481Flx_mul(gel(u, k+1), gel(v, k), p), p);2482gel(Tp, i) = t;2483}2484return gerepileuptoleaf(av, gmael(Tp,m,1));2485}24862487GEN2488Flx_Flv_multieval(GEN P, GEN xa, ulong p)2489{2490pari_sp av = avma;2491GEN s = producttree_scheme(lg(xa)-1);2492GEN T = Flv_producttree(xa, s, p, P[1]);2493return gerepileuptoleaf(av, Flx_Flv_multieval_tree(P, xa, T, p));2494}24952496static GEN2497FlxV_Flv_multieval_tree(GEN x, GEN xa, GEN T, ulong p)2498{ pari_APPLY_same(Flx_Flv_multieval_tree(gel(x,i), xa, T, p)) }24992500GEN2501FlxV_Flv_multieval(GEN P, GEN xa, ulong p)2502{2503pari_sp av = avma;2504GEN s = producttree_scheme(lg(xa)-1);2505GEN T = Flv_producttree(xa, s, p, P[1]);2506return gerepileupto(av, FlxV_Flv_multieval_tree(P, xa, T, p));2507}25082509GEN2510Flv_polint(GEN xa, GEN ya, ulong p, long vs)2511{2512pari_sp av = avma;2513GEN s = producttree_scheme(lg(xa)-1);2514GEN T = Flv_producttree(xa, s, p, vs);2515long m = lg(T)-1;2516GEN P = Flx_deriv(gmael(T, m, 1), p);2517GEN R = Flv_inv(Flx_Flv_multieval_tree(P, xa, T, p), p);2518return gerepileuptoleaf(av, FlvV_polint_tree(T, R, s, xa, ya, p, vs));2519}25202521GEN2522Flv_Flm_polint(GEN xa, GEN ya, ulong p, long vs)2523{2524pari_sp av = avma;2525GEN s = producttree_scheme(lg(xa)-1);2526GEN T = Flv_producttree(xa, s, p, vs);2527long i, m = lg(T)-1, l = lg(ya)-1;2528GEN P = Flx_deriv(gmael(T, m, 1), p);2529GEN R = Flv_inv(Flx_Flv_multieval_tree(P, xa, T, p), p);2530GEN M = cgetg(l+1, t_VEC);2531for (i=1; i<=l; i++)2532gel(M,i) = FlvV_polint_tree(T, R, s, xa, gel(ya,i), p, vs);2533return gerepileupto(av, M);2534}25352536GEN2537Flv_invVandermonde(GEN L, ulong den, ulong p)2538{2539pari_sp av = avma;2540long i, n = lg(L);2541GEN M, R;2542GEN s = producttree_scheme(n-1);2543GEN tree = Flv_producttree(L, s, p, 0);2544long m = lg(tree)-1;2545GEN T = gmael(tree, m, 1);2546R = Flv_inv(Flx_Flv_multieval_tree(Flx_deriv(T, p), L, tree, p), p);2547if (den!=1) R = Flv_Fl_mul(R, den, p);2548M = cgetg(n, t_MAT);2549for (i = 1; i < n; i++)2550{2551GEN P = Flx_Fl_mul(Flx_div_by_X_x(T, uel(L,i), p, NULL), uel(R,i), p);2552gel(M,i) = Flx_to_Flv(P, n-1);2553}2554return gerepilecopy(av, M);2555}25562557/***********************************************************************/2558/** **/2559/** Flxq **/2560/** **/2561/***********************************************************************/2562/* Flxq objects are defined as follows:2563They are Flx modulo another Flx called q.2564*/25652566/* Product of y and x in Z/pZ[X]/(T), as t_VECSMALL. */2567GEN2568Flxq_mul(GEN x,GEN y,GEN T,ulong p)2569{2570return Flx_rem(Flx_mul(x,y,p),T,p);2571}25722573/* Square of y in Z/pZ[X]/(T), as t_VECSMALL. */2574GEN2575Flxq_sqr(GEN x,GEN T,ulong p)2576{2577return Flx_rem(Flx_sqr(x,p),T,p);2578}25792580static GEN2581_Flxq_red(void *E, GEN x)2582{ struct _Flxq *s = (struct _Flxq *)E;2583return Flx_rem(x, s->T, s->p); }2584#if 02585static GEN2586_Flx_sub(void *E, GEN x, GEN y)2587{ struct _Flxq *s = (struct _Flxq *)E;2588return Flx_sub(x,y,s->p); }2589#endif2590static GEN2591_Flxq_sqr(void *data, GEN x)2592{2593struct _Flxq *D = (struct _Flxq*)data;2594return Flxq_sqr(x, D->T, D->p);2595}2596static GEN2597_Flxq_mul(void *data, GEN x, GEN y)2598{2599struct _Flxq *D = (struct _Flxq*)data;2600return Flxq_mul(x,y, D->T, D->p);2601}2602static GEN2603_Flxq_one(void *data)2604{2605struct _Flxq *D = (struct _Flxq*)data;2606return pol1_Flx(get_Flx_var(D->T));2607}2608#if 02609static GEN2610_Flxq_zero(void *data)2611{2612struct _Flxq *D = (struct _Flxq*)data;2613return pol0_Flx(get_Flx_var(D->T));2614}2615static GEN2616_Flxq_cmul(void *data, GEN P, long a, GEN x)2617{2618struct _Flxq *D = (struct _Flxq*)data;2619return Flx_Fl_mul(x, P[a+2], D->p);2620}2621#endif26222623/* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */2624GEN2625Flxq_powu(GEN x, ulong n, GEN T, ulong p)2626{2627pari_sp av = avma;2628struct _Flxq D;2629GEN y;2630switch(n)2631{2632case 0: return pol1_Flx(get_Flx_var(T));2633case 1: return Flx_copy(x);2634case 2: return Flxq_sqr(x, T, p);2635}2636D.T = Flx_get_red(T, p); D.p = p;2637y = gen_powu_i(x, n, (void*)&D, &_Flxq_sqr, &_Flxq_mul);2638return gerepileuptoleaf(av, y);2639}26402641/* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */2642GEN2643Flxq_pow(GEN x, GEN n, GEN T, ulong p)2644{2645pari_sp av = avma;2646struct _Flxq D;2647GEN y;2648long s = signe(n);2649if (!s) return pol1_Flx(get_Flx_var(T));2650if (s < 0)2651x = Flxq_inv(x,T,p);2652if (is_pm1(n)) return s < 0 ? x : Flx_copy(x);2653D.T = Flx_get_red(T, p); D.p = p;2654y = gen_pow_i(x, n, (void*)&D, &_Flxq_sqr, &_Flxq_mul);2655return gerepileuptoleaf(av, y);2656}26572658GEN2659Flxq_pow_init(GEN x, GEN n, long k, GEN T, ulong p)2660{2661struct _Flxq D;2662D.T = Flx_get_red(T, p); D.p = p;2663return gen_pow_init(x, n, k, (void*)&D, &_Flxq_sqr, &_Flxq_mul);2664}26652666GEN2667Flxq_pow_table(GEN R, GEN n, GEN T, ulong p)2668{2669struct _Flxq D;2670D.T = Flx_get_red(T, p); D.p = p;2671return gen_pow_table(R, n, (void*)&D, &_Flxq_one, &_Flxq_mul);2672}26732674/* Inverse of x in Z/lZ[X]/(T) or NULL if inverse doesn't exist2675* not stack clean.2676*/2677GEN2678Flxq_invsafe(GEN x, GEN T, ulong p)2679{2680GEN V, z = Flx_extgcd(get_Flx_mod(T), x, p, NULL, &V);2681ulong iz;2682if (degpol(z)) return NULL;2683iz = Fl_inv (uel(z,2), p);2684return Flx_Fl_mul(V, iz, p);2685}26862687GEN2688Flxq_inv(GEN x,GEN T,ulong p)2689{2690pari_sp av=avma;2691GEN U = Flxq_invsafe(x, T, p);2692if (!U) pari_err_INV("Flxq_inv",Flx_to_ZX(x));2693return gerepileuptoleaf(av, U);2694}26952696GEN2697Flxq_div(GEN x,GEN y,GEN T,ulong p)2698{2699pari_sp av = avma;2700return gerepileuptoleaf(av, Flxq_mul(x,Flxq_inv(y,T,p),T,p));2701}27022703GEN2704Flxq_powers(GEN x, long l, GEN T, ulong p)2705{2706struct _Flxq D;2707int use_sqr = 2*degpol(x) >= get_Flx_degree(T);2708D.T = Flx_get_red(T, p); D.p = p;2709return gen_powers(x, l, use_sqr, (void*)&D, &_Flxq_sqr, &_Flxq_mul, &_Flxq_one);2710}27112712GEN2713Flxq_matrix_pow(GEN y, long n, long m, GEN P, ulong l)2714{2715return FlxV_to_Flm(Flxq_powers(y,m-1,P,l),n);2716}27172718GEN2719Flx_Frobenius(GEN T, ulong p)2720{2721return Flxq_powu(polx_Flx(get_Flx_var(T)), p, T, p);2722}27232724GEN2725Flx_matFrobenius(GEN T, ulong p)2726{2727long n = get_Flx_degree(T);2728return Flxq_matrix_pow(Flx_Frobenius(T, p), n, n, T, p);2729}27302731static GEN2732Flx_blocks_Flm(GEN P, long n, long m)2733{2734GEN z = cgetg(m+1,t_MAT);2735long i,j, k=2, l = lg(P);2736for(i=1; i<=m; i++)2737{2738GEN zi = cgetg(n+1,t_VECSMALL);2739gel(z,i) = zi;2740for(j=1; j<=n; j++)2741uel(zi, j) = k==l ? 0 : uel(P,k++);2742}2743return z;2744}27452746GEN2747Flx_blocks(GEN P, long n, long m)2748{2749GEN z = cgetg(m+1,t_VEC);2750long i,j, k=2, l = lg(P);2751for(i=1; i<=m; i++)2752{2753GEN zi = cgetg(n+2,t_VECSMALL);2754zi[1] = P[1];2755gel(z,i) = zi;2756for(j=2; j<n+2; j++)2757uel(zi, j) = k==l ? 0 : uel(P,k++);2758zi = Flx_renormalize(zi, n+2);2759}2760return z;2761}27622763static GEN2764FlxV_to_Flm_lg(GEN x, long m, long n)2765{2766long i;2767GEN y = cgetg(n+1, t_MAT);2768for (i=1; i<=n; i++) gel(y,i) = Flx_to_Flv(gel(x,i), m);2769return y;2770}27712772GEN2773Flx_FlxqV_eval(GEN Q, GEN x, GEN T, ulong p)2774{2775pari_sp btop, av = avma;2776long sv = get_Flx_var(T), m = get_Flx_degree(T);2777long i, l = lg(x)-1, lQ = lgpol(Q), n, d;2778GEN A, B, C, S, g;2779if (lQ == 0) return pol0_Flx(sv);2780if (lQ <= l)2781{2782n = l;2783d = 1;2784}2785else2786{2787n = l-1;2788d = (lQ+n-1)/n;2789}2790A = FlxV_to_Flm_lg(x, m, n);2791B = Flx_blocks_Flm(Q, n, d);2792C = gerepileupto(av, Flm_mul(A, B, p));2793g = gel(x, l);2794T = Flx_get_red(T, p);2795btop = avma;2796S = Flv_to_Flx(gel(C, d), sv);2797for (i = d-1; i>0; i--)2798{2799S = Flx_add(Flxq_mul(S, g, T, p), Flv_to_Flx(gel(C,i), sv), p);2800if (gc_needed(btop,1))2801S = gerepileuptoleaf(btop, S);2802}2803return gerepileuptoleaf(av, S);2804}28052806GEN2807Flx_Flxq_eval(GEN Q, GEN x, GEN T, ulong p)2808{2809pari_sp av = avma;2810GEN z, V;2811long d = degpol(Q), rtd;2812if (d < 0) return pol0_Flx(get_Flx_var(T));2813rtd = (long) sqrt((double)d);2814T = Flx_get_red(T, p);2815V = Flxq_powers(x, rtd, T, p);2816z = Flx_FlxqV_eval(Q, V, T, p);2817return gerepileupto(av, z);2818}28192820GEN2821FlxC_FlxqV_eval(GEN x, GEN v, GEN T, ulong p)2822{ pari_APPLY_type(t_COL, Flx_FlxqV_eval(gel(x,i), v, T, p))2823}28242825GEN2826FlxC_Flxq_eval(GEN x, GEN F, GEN T, ulong p)2827{2828long d = brent_kung_optpow(degpol(T)-1,lg(x)-1,1);2829GEN Fp = Flxq_powers(F, d, T, p);2830return FlxC_FlxqV_eval(x, Fp, T, p);2831}28322833#if 02834static struct bb_algebra Flxq_algebra = { _Flxq_red, _Flx_add, _Flx_sub,2835_Flxq_mul, _Flxq_sqr, _Flxq_one, _Flxq_zero};2836#endif28372838static GEN2839Flxq_autpow_sqr(void *E, GEN x)2840{2841struct _Flxq *D = (struct _Flxq*)E;2842return Flx_Flxq_eval(x, x, D->T, D->p);2843}2844static GEN2845Flxq_autpow_msqr(void *E, GEN x)2846{2847struct _Flxq *D = (struct _Flxq*)E;2848return Flx_FlxqV_eval(Flxq_autpow_sqr(E, x), D->aut, D->T, D->p);2849}28502851GEN2852Flxq_autpow(GEN x, ulong n, GEN T, ulong p)2853{2854pari_sp av = avma;2855struct _Flxq D;2856long d;2857if (n==0) return Flx_rem(polx_Flx(x[1]), T, p);2858if (n==1) return Flx_rem(x, T, p);2859D.T = Flx_get_red(T, p); D.p = p;2860d = brent_kung_optpow(get_Flx_degree(T), hammingl(n)-1, 1);2861D.aut = Flxq_powers(x, d, T, p);2862x = gen_powu_fold_i(x,n,(void*)&D,Flxq_autpow_sqr,Flxq_autpow_msqr);2863return gerepilecopy(av, x);2864}28652866GEN2867Flxq_autpowers(GEN x, ulong l, GEN T, ulong p)2868{2869long d, vT = get_Flx_var(T), dT = get_Flx_degree(T);2870ulong i;2871pari_sp av = avma;2872GEN xp, V = cgetg(l+2,t_VEC);2873gel(V,1) = polx_Flx(vT); if (l==0) return V;2874gel(V,2) = gcopy(x); if (l==1) return V;2875T = Flx_get_red(T, p);2876d = brent_kung_optpow(dT-1, l-1, 1);2877xp = Flxq_powers(x, d, T, p);2878for(i = 3; i < l+2; i++)2879gel(V,i) = Flx_FlxqV_eval(gel(V,i-1), xp, T, p);2880return gerepilecopy(av, V);2881}28822883static GEN2884Flxq_autsum_mul(void *E, GEN x, GEN y)2885{2886struct _Flxq *D = (struct _Flxq*)E;2887GEN T = D->T;2888ulong p = D->p;2889GEN phi1 = gel(x,1), a1 = gel(x,2);2890GEN phi2 = gel(y,1), a2 = gel(y,2);2891ulong d = brent_kung_optpow(maxss(degpol(phi1),degpol(a1)),2,1);2892GEN V2 = Flxq_powers(phi2, d, T, p);2893GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p);2894GEN aphi = Flx_FlxqV_eval(a1, V2, T, p);2895GEN a3 = Flxq_mul(aphi, a2, T, p);2896return mkvec2(phi3, a3);2897}2898static GEN2899Flxq_autsum_sqr(void *E, GEN x)2900{ return Flxq_autsum_mul(E, x, x); }29012902GEN2903Flxq_autsum(GEN x, ulong n, GEN T, ulong p)2904{2905pari_sp av = avma;2906struct _Flxq D;2907D.T = Flx_get_red(T, p); D.p = p;2908x = gen_powu_i(x,n,(void*)&D,Flxq_autsum_sqr,Flxq_autsum_mul);2909return gerepilecopy(av, x);2910}29112912static GEN2913Flxq_auttrace_mul(void *E, GEN x, GEN y)2914{2915struct _Flxq *D = (struct _Flxq*)E;2916GEN T = D->T;2917ulong p = D->p;2918GEN phi1 = gel(x,1), a1 = gel(x,2);2919GEN phi2 = gel(y,1), a2 = gel(y,2);2920ulong d = brent_kung_optpow(maxss(degpol(phi1),degpol(a1)),2,1);2921GEN V1 = Flxq_powers(phi1, d, T, p);2922GEN phi3 = Flx_FlxqV_eval(phi2, V1, T, p);2923GEN aphi = Flx_FlxqV_eval(a2, V1, T, p);2924GEN a3 = Flx_add(a1, aphi, p);2925return mkvec2(phi3, a3);2926}29272928static GEN2929Flxq_auttrace_sqr(void *E, GEN x)2930{ return Flxq_auttrace_mul(E, x, x); }29312932GEN2933Flxq_auttrace(GEN x, ulong n, GEN T, ulong p)2934{2935pari_sp av = avma;2936struct _Flxq D;2937D.T = Flx_get_red(T, p); D.p = p;2938x = gen_powu_i(x,n,(void*)&D,Flxq_auttrace_sqr,Flxq_auttrace_mul);2939return gerepilecopy(av, x);2940}29412942static long2943bounded_order(ulong p, GEN b, long k)2944{2945GEN a = modii(utoipos(p), b);2946long i;2947for(i = 1; i < k; i++)2948{2949if (equali1(a)) return i;2950a = modii(muliu(a,p),b);2951}2952return 0;2953}29542955/*2956n = (p^d-a)\b2957b = bb*p^vb2958p^k = 1 [bb]2959d = m*k+r+vb2960u = (p^k-1)/bb;2961v = (p^(r+vb)-a)/b;2962w = (p^(m*k)-1)/(p^k-1)2963n = p^r*w*u+v2964w*u = p^vb*(p^(m*k)-1)/b2965n = p^(r+vb)*(p^(m*k)-1)/b+(p^(r+vb)-a)/b2966*/29672968static GEN2969Flxq_pow_Frobenius(GEN x, GEN n, GEN aut, GEN T, ulong p)2970{2971pari_sp av=avma;2972long d = get_Flx_degree(T);2973GEN an = absi_shallow(n), z, q;2974if (abscmpiu(an,p)<0 || cmpis(an,d)<=0) return Flxq_pow(x, n, T, p);2975q = powuu(p, d);2976if (dvdii(q, n))2977{2978long vn = logint(an, utoipos(p));2979GEN autvn = vn==1 ? aut: Flxq_autpow(aut,vn,T,p);2980z = Flx_Flxq_eval(x,autvn,T,p);2981} else2982{2983GEN b = diviiround(q, an), a = subii(q, mulii(an,b));2984GEN bb, u, v, autk;2985long vb = Z_lvalrem(b,p,&bb);2986long m, r, k = is_pm1(bb)? 1: bounded_order(p,bb,d);2987if (!k || d-vb < k) return Flxq_pow(x,n, T, p);2988m = (d-vb)/k; r = (d-vb)%k;2989u = diviiexact(subiu(powuu(p,k),1),bb);2990v = diviiexact(subii(powuu(p,r+vb),a),b);2991autk = k==1 ? aut: Flxq_autpow(aut,k,T,p);2992if (r)2993{2994GEN autr = r==1 ? aut: Flxq_autpow(aut,r,T,p);2995z = Flx_Flxq_eval(x,autr,T,p);2996} else z = x;2997if (m > 1) z = gel(Flxq_autsum(mkvec2(autk, z), m, T, p), 2);2998if (!is_pm1(u)) z = Flxq_pow(z, u, T, p);2999if (signe(v)) z = Flxq_mul(z, Flxq_pow(x, v, T, p), T, p);3000}3001return gerepileupto(av,signe(n)>0 ? z : Flxq_inv(z,T,p));3002}30033004static GEN3005_Flxq_pow(void *data, GEN x, GEN n)3006{3007struct _Flxq *D = (struct _Flxq*)data;3008return Flxq_pow_Frobenius(x, n, D->aut, D->T, D->p);3009}30103011static GEN3012_Flxq_rand(void *data)3013{3014pari_sp av=avma;3015struct _Flxq *D = (struct _Flxq*)data;3016GEN z;3017do3018{3019set_avma(av);3020z = random_Flx(get_Flx_degree(D->T),get_Flx_var(D->T),D->p);3021} while (lgpol(z)==0);3022return z;3023}30243025/* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */3026static GEN3027Fl_Flxq_log(ulong a, GEN g, GEN o, GEN T, ulong p)3028{3029pari_sp av = avma;3030GEN q,n_q,ord,ordp, op;30313032if (a == 1UL) return gen_0;3033/* p > 2 */30343035ordp = utoi(p - 1);3036ord = get_arith_Z(o);3037if (!ord) ord = T? subiu(powuu(p, get_FpX_degree(T)), 1): ordp;3038if (a == p - 1) /* -1 */3039return gerepileuptoint(av, shifti(ord,-1));3040ordp = gcdii(ordp, ord);3041op = typ(o)==t_MAT ? famat_Z_gcd(o, ordp) : ordp;30423043q = NULL;3044if (T)3045{ /* we want < g > = Fp^* */3046if (!equalii(ord,ordp)) {3047q = diviiexact(ord,ordp);3048g = Flxq_pow(g,q,T,p);3049}3050}3051n_q = Fp_log(utoi(a), utoipos(uel(g,2)), op, utoipos(p));3052if (lg(n_q)==1) return gerepileuptoleaf(av, n_q);3053if (q) n_q = mulii(q, n_q);3054return gerepileuptoint(av, n_q);3055}30563057static GEN3058Flxq_easylog(void* E, GEN a, GEN g, GEN ord)3059{3060struct _Flxq *f = (struct _Flxq *)E;3061GEN T = f->T;3062ulong p = f->p;3063long d = get_Flx_degree(T);3064if (Flx_equal1(a)) return gen_0;3065if (Flx_equal(a,g)) return gen_1;3066if (!degpol(a))3067return Fl_Flxq_log(uel(a,2), g, ord, T, p);3068if (typ(ord)!=t_INT || d <= 4 || d == 6 || abscmpiu(ord,1UL<<27)<0)3069return NULL;3070return Flxq_log_index(a, g, ord, T, p);3071}30723073static const struct bb_group Flxq_star={_Flxq_mul,_Flxq_pow,_Flxq_rand,hash_GEN,Flx_equal,Flx_equal1,Flxq_easylog};30743075const struct bb_group *3076get_Flxq_star(void **E, GEN T, ulong p)3077{3078struct _Flxq *e = (struct _Flxq *) stack_malloc(sizeof(struct _Flxq));3079e->T = T; e->p = p; e->aut = Flx_Frobenius(T, p);3080*E = (void*)e; return &Flxq_star;3081}30823083GEN3084Flxq_order(GEN a, GEN ord, GEN T, ulong p)3085{3086void *E;3087const struct bb_group *S = get_Flxq_star(&E,T,p);3088return gen_order(a,ord,E,S);3089}30903091GEN3092Flxq_log(GEN a, GEN g, GEN ord, GEN T, ulong p)3093{3094void *E;3095pari_sp av = avma;3096const struct bb_group *S = get_Flxq_star(&E,T,p);3097GEN v = get_arith_ZZM(ord), F = gmael(v,2,1);3098if (Flxq_log_use_index(gel(F,lg(F)-1), T, p))3099v = mkvec2(gel(v, 1), ZM_famat_limit(gel(v, 2), int2n(27)));3100return gerepileuptoleaf(av, gen_PH_log(a, g, v, E, S));3101}31023103GEN3104Flxq_sqrtn(GEN a, GEN n, GEN T, ulong p, GEN *zeta)3105{3106if (!lgpol(a))3107{3108if (signe(n) < 0) pari_err_INV("Flxq_sqrtn",a);3109if (zeta)3110*zeta=pol1_Flx(get_Flx_var(T));3111return pol0_Flx(get_Flx_var(T));3112}3113else3114{3115void *E;3116pari_sp av = avma;3117const struct bb_group *S = get_Flxq_star(&E,T,p);3118GEN o = subiu(powuu(p,get_Flx_degree(T)), 1);3119GEN s = gen_Shanks_sqrtn(a,n,o,zeta,E,S);3120if (s) gerepileall(av, zeta?2:1, &s, zeta);3121return s;3122}3123}31243125GEN3126Flxq_sqrt(GEN a, GEN T, ulong p)3127{3128return Flxq_sqrtn(a, gen_2, T, p, NULL);3129}31303131/* assume T irreducible mod p */3132int3133Flxq_issquare(GEN x, GEN T, ulong p)3134{3135if (lgpol(x) == 0 || p == 2) return 1;3136return krouu(Flxq_norm(x,T,p), p) == 1;3137}31383139/* assume T irreducible mod p */3140int3141Flxq_is2npower(GEN x, long n, GEN T, ulong p)3142{3143pari_sp av;3144GEN m;3145if (n==1) return Flxq_issquare(x, T, p);3146if (lgpol(x) == 0 || p == 2) return 1;3147av = avma;3148m = shifti(subiu(powuu(p, get_Flx_degree(T)), 1), -n);3149return gc_bool(av, Flx_equal1(Flxq_pow(x, m, T, p)));3150}31513152GEN3153Flxq_lroot_fast(GEN a, GEN sqx, GEN T, long p)3154{3155pari_sp av=avma;3156GEN A = Flx_splitting(a,p);3157return gerepileuptoleaf(av, FlxqV_dotproduct(A,sqx,T,p));3158}31593160GEN3161Flxq_lroot(GEN a, GEN T, long p)3162{3163pari_sp av=avma;3164long n = get_Flx_degree(T), d = degpol(a);3165GEN sqx, V;3166if (n==1) return leafcopy(a);3167if (n==2) return Flxq_powu(a, p, T, p);3168sqx = Flxq_autpow(Flx_Frobenius(T, p), n-1, T, p);3169if (d==1 && a[2]==0 && a[3]==1) return gerepileuptoleaf(av, sqx);3170if (d>=p)3171{3172V = Flxq_powers(sqx,p-1,T,p);3173return gerepileuptoleaf(av, Flxq_lroot_fast(a,V,T,p));3174} else3175return gerepileuptoleaf(av, Flx_Flxq_eval(a,sqx,T,p));3176}31773178ulong3179Flxq_norm(GEN x, GEN TB, ulong p)3180{3181GEN T = get_Flx_mod(TB);3182ulong y = Flx_resultant(T, x, p);3183ulong L = Flx_lead(T);3184if ( L==1 || lgpol(x)==0) return y;3185return Fl_div(y, Fl_powu(L, (ulong)degpol(x), p), p);3186}31873188ulong3189Flxq_trace(GEN x, GEN TB, ulong p)3190{3191pari_sp av = avma;3192ulong t;3193GEN T = get_Flx_mod(TB);3194long n = degpol(T)-1;3195GEN z = Flxq_mul(x, Flx_deriv(T, p), TB, p);3196t = degpol(z)<n ? 0 : Fl_div(z[2+n],T[3+n],p);3197return gc_ulong(av, t);3198}31993200/*x must be reduced*/3201GEN3202Flxq_charpoly(GEN x, GEN TB, ulong p)3203{3204pari_sp ltop=avma;3205GEN T = get_Flx_mod(TB);3206long vs = evalvarn(fetch_var());3207GEN xm1 = deg1pol_shallow(pol1_Flx(x[1]),Flx_neg(x,p),vs);3208GEN r = Flx_FlxY_resultant(T, xm1, p);3209r[1] = x[1];3210(void)delete_var(); return gerepileupto(ltop, r);3211}32123213/* Computing minimal polynomial : */3214/* cf Shoup 'Efficient Computation of Minimal Polynomials */3215/* in Algebraic Extensions of Finite Fields' */32163217/* Let v a linear form, return the linear form z->v(tau*z)3218that is, v*(M_tau) */32193220static GEN3221Flxq_transmul_init(GEN tau, GEN T, ulong p)3222{3223GEN bht;3224GEN h, Tp = get_Flx_red(T, &h);3225long n = degpol(Tp), vT = Tp[1];3226GEN ft = Flx_recipspec(Tp+2, n+1, n+1);3227GEN bt = Flx_recipspec(tau+2, lgpol(tau), n);3228ft[1] = vT; bt[1] = vT;3229if (h)3230bht = Flxn_mul(bt, h, n-1, p);3231else3232{3233GEN bh = Flx_div(Flx_shift(tau, n-1), T, p);3234bht = Flx_recipspec(bh+2, lgpol(bh), n-1);3235bht[1] = vT;3236}3237return mkvec3(bt, bht, ft);3238}32393240static GEN3241Flxq_transmul(GEN tau, GEN a, long n, ulong p)3242{3243pari_sp ltop = avma;3244GEN t1, t2, t3, vec;3245GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);3246if (lgpol(a)==0) return pol0_Flx(a[1]);3247t2 = Flx_shift(Flx_mul(bt, a, p),1-n);3248if (lgpol(bht)==0) return gerepileuptoleaf(ltop, t2);3249t1 = Flx_shift(Flx_mul(ft, a, p),-n);3250t3 = Flxn_mul(t1, bht, n-1, p);3251vec = Flx_sub(t2, Flx_shift(t3, 1), p);3252return gerepileuptoleaf(ltop, vec);3253}32543255GEN3256Flxq_minpoly(GEN x, GEN T, ulong p)3257{3258pari_sp ltop = avma;3259long vT = get_Flx_var(T), n = get_Flx_degree(T);3260GEN v_x;3261GEN g = pol1_Flx(vT), tau = pol1_Flx(vT);3262T = Flx_get_red(T, p);3263v_x = Flxq_powers(x, usqrt(2*n), T, p);3264while (lgpol(tau) != 0)3265{3266long i, j, m, k1;3267GEN M, v, tr;3268GEN g_prime, c;3269if (degpol(g) == n) { tau = pol1_Flx(vT); g = pol1_Flx(vT); }3270v = random_Flx(n, vT, p);3271tr = Flxq_transmul_init(tau, T, p);3272v = Flxq_transmul(tr, v, n, p);3273m = 2*(n-degpol(g));3274k1 = usqrt(m);3275tr = Flxq_transmul_init(gel(v_x,k1+1), T, p);3276c = cgetg(m+2,t_VECSMALL);3277c[1] = vT;3278for (i=0; i<m; i+=k1)3279{3280long mj = minss(m-i, k1);3281for (j=0; j<mj; j++)3282uel(c,m+1-(i+j)) = Flx_dotproduct(v, gel(v_x,j+1), p);3283v = Flxq_transmul(tr, v, n, p);3284}3285c = Flx_renormalize(c, m+2);3286/* now c contains <v,x^i> , i = 0..m-1 */3287M = Flx_halfgcd(monomial_Flx(1, m, vT), c, p);3288g_prime = gmael(M, 2, 2);3289if (degpol(g_prime) < 1) continue;3290g = Flx_mul(g, g_prime, p);3291tau = Flxq_mul(tau, Flx_FlxqV_eval(g_prime, v_x, T, p), T, p);3292}3293g = Flx_normalize(g,p);3294return gerepileuptoleaf(ltop,g);3295}32963297GEN3298Flxq_conjvec(GEN x, GEN T, ulong p)3299{3300long i, l = 1+get_Flx_degree(T);3301GEN z = cgetg(l,t_COL);3302T = Flx_get_red(T,p);3303gel(z,1) = Flx_copy(x);3304for (i=2; i<l; i++) gel(z,i) = Flxq_powu(gel(z,i-1), p, T, p);3305return z;3306}33073308GEN3309gener_Flxq(GEN T, ulong p, GEN *po)3310{3311long i, j, vT = get_Flx_var(T), f = get_Flx_degree(T);3312ulong p_1;3313GEN g, L, L2, o, q, F;3314pari_sp av0, av;33153316if (f == 1) {3317GEN fa;3318o = utoipos(p-1);3319fa = Z_factor(o);3320L = gel(fa,1);3321L = vecslice(L, 2, lg(L)-1); /* remove 2 for efficiency */3322g = Fl_to_Flx(pgener_Fl_local(p, vec_to_vecsmall(L)), vT);3323if (po) *po = mkvec2(o, fa);3324return g;3325}33263327av0 = avma; p_1 = p - 1;3328q = diviuexact(subiu(powuu(p,f), 1), p_1);33293330L = cgetg(1, t_VECSMALL);3331if (p > 3)3332{3333ulong t = p_1 >> vals(p_1);3334GEN P = gel(factoru(t), 1);3335L = cgetg_copy(P, &i);3336while (--i) L[i] = p_1 / P[i];3337}3338o = factor_pn_1(utoipos(p),f);3339L2 = leafcopy( gel(o, 1) );3340for (i = j = 1; i < lg(L2); i++)3341{3342if (umodui(p_1, gel(L2,i)) == 0) continue;3343gel(L2,j++) = diviiexact(q, gel(L2,i));3344}3345setlg(L2, j);3346F = Flx_Frobenius(T, p);3347for (av = avma;; set_avma(av))3348{3349GEN tt;3350g = random_Flx(f, vT, p);3351if (degpol(g) < 1) continue;3352if (p == 2) tt = g;3353else3354{3355ulong t = Flxq_norm(g, T, p);3356if (t == 1 || !is_gener_Fl(t, p, p_1, L)) continue;3357tt = Flxq_powu(g, p_1>>1, T, p);3358}3359for (i = 1; i < j; i++)3360{3361GEN a = Flxq_pow_Frobenius(tt, gel(L2,i), F, T, p);3362if (!degpol(a) && uel(a,2) == p_1) break;3363}3364if (i == j) break;3365}3366if (!po)3367{3368set_avma((pari_sp)g);3369g = gerepileuptoleaf(av0, g);3370}3371else {3372*po = mkvec2(subiu(powuu(p,f), 1), o);3373gerepileall(av0, 2, &g, po);3374}3375return g;3376}33773378static GEN3379_Flxq_neg(void *E, GEN x)3380{ struct _Flxq *s = (struct _Flxq *)E;3381return Flx_neg(x,s->p); }33823383static GEN3384_Flxq_rmul(void *E, GEN x, GEN y)3385{ struct _Flxq *s = (struct _Flxq *)E;3386return Flx_mul(x,y,s->p); }33873388static GEN3389_Flxq_inv(void *E, GEN x)3390{ struct _Flxq *s = (struct _Flxq *)E;3391return Flxq_inv(x,s->T,s->p); }33923393static int3394_Flxq_equal0(GEN x) { return lgpol(x)==0; }33953396static GEN3397_Flxq_s(void *E, long x)3398{ struct _Flxq *s = (struct _Flxq *)E;3399ulong u = x<0 ? s->p+x: (ulong)x;3400return Fl_to_Flx(u, get_Flx_var(s->T));3401}34023403static const struct bb_field Flxq_field={_Flxq_red,_Flx_add,_Flxq_rmul,_Flxq_neg,3404_Flxq_inv,_Flxq_equal0,_Flxq_s};34053406const struct bb_field *get_Flxq_field(void **E, GEN T, ulong p)3407{3408GEN z = new_chunk(sizeof(struct _Flxq));3409struct _Flxq *e = (struct _Flxq *) z;3410e->T = Flx_get_red(T, p); e->p = p; *E = (void*)e;3411return &Flxq_field;3412}34133414/***********************************************************************/3415/** **/3416/** Flxn **/3417/** **/3418/***********************************************************************/34193420GEN3421Flx_invLaplace(GEN x, ulong p)3422{3423long i, d = degpol(x);3424ulong t;3425GEN y;3426if (d <= 1) return Flx_copy(x);3427t = Fl_inv(factorial_Fl(d, p), p);3428y = cgetg(d+3, t_VECSMALL);3429y[1] = x[1];3430for (i=d; i>=2; i--)3431{3432uel(y,i+2) = Fl_mul(uel(x,i+2), t, p);3433t = Fl_mul(t, i, p);3434}3435uel(y,3) = uel(x,3);3436uel(y,2) = uel(x,2);3437return y;3438}34393440GEN3441Flx_Laplace(GEN x, ulong p)3442{3443long i, d = degpol(x);3444ulong t = 1;3445GEN y;3446if (d <= 1) return Flx_copy(x);3447y = cgetg(d+3, t_VECSMALL);3448y[1] = x[1];3449uel(y,2) = uel(x,2);3450uel(y,3) = uel(x,3);3451for (i=2; i<=d; i++)3452{3453t = Fl_mul(t, i%p, p);3454uel(y,i+2) = Fl_mul(uel(x,i+2), t, p);3455}3456return y;3457}34583459GEN3460Flxn_red(GEN a, long n)3461{3462long i, L, l = lg(a);3463GEN b;3464if (l == 2 || !n) return zero_Flx(a[1]);3465L = n+2; if (L > l) L = l;3466b = cgetg(L, t_VECSMALL); b[1] = a[1];3467for (i=2; i<L; i++) b[i] = a[i];3468return Flx_renormalize(b,L);3469}34703471GEN3472Flxn_mul(GEN a, GEN b, long n, ulong p)3473{ return Flxn_red(Flx_mul(a, b, p), n); }34743475GEN3476Flxn_sqr(GEN a, long n, ulong p)3477{ return Flxn_red(Flx_sqr(a, p), n); }34783479/* (f*g) \/ x^n */3480static GEN3481Flx_mulhigh_i(GEN f, GEN g, long n, ulong p)3482{3483return Flx_shift(Flx_mul(f,g, p),-n);3484}34853486static GEN3487Flxn_mulhigh(GEN f, GEN g, long n2, long n, ulong p)3488{3489GEN F = Flx_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2);3490return Flx_add(Flx_mulhigh_i(fl, g, n2, p), Flxn_mul(fh, g, n - n2, p), p);3491}34923493GEN3494Flxn_inv(GEN f, long e, ulong p)3495{3496pari_sp av = avma, av2;3497ulong mask;3498GEN W;3499long n=1;3500if (lg(f)==2) pari_err_INV("Flxn_inv",f);3501W = Fl_to_Flx(Fl_inv(uel(f,2),p), f[1]);3502mask = quadratic_prec_mask(e);3503av2 = avma;3504for (;mask>1;)3505{3506GEN u, fr;3507long n2 = n;3508n<<=1; if (mask & 1) n--;3509mask >>= 1;3510fr = Flxn_red(f, n);3511u = Flxn_mul(W, Flxn_mulhigh(fr, W, n2, n, p), n-n2, p);3512W = Flx_sub(W, Flx_shift(u, n2), p);3513if (gc_needed(av2,2))3514{3515if(DEBUGMEM>1) pari_warn(warnmem,"Flxn_inv, e = %ld", n);3516W = gerepileupto(av2, W);3517}3518}3519return gerepileupto(av, W);3520}35213522GEN3523Flxn_expint(GEN h, long e, ulong p)3524{3525pari_sp av = avma, av2;3526long v = h[1], n=1;3527GEN f = pol1_Flx(v), g = pol1_Flx(v);3528ulong mask = quadratic_prec_mask(e);3529av2 = avma;3530for (;mask>1;)3531{3532GEN u, w;3533long n2 = n;3534n<<=1; if (mask & 1) n--;3535mask >>= 1;3536u = Flxn_mul(g, Flx_mulhigh_i(f, Flxn_red(h, n2-1), n2-1, p), n-n2, p);3537u = Flx_add(u, Flx_shift(Flxn_red(h, n-1), 1-n2), p);3538w = Flxn_mul(f, Flx_integXn(u, n2-1, p), n-n2, p);3539f = Flx_add(f, Flx_shift(w, n2), p);3540if (mask<=1) break;3541u = Flxn_mul(g, Flxn_mulhigh(f, g, n2, n, p), n-n2, p);3542g = Flx_sub(g, Flx_shift(u, n2), p);3543if (gc_needed(av2,2))3544{3545if (DEBUGMEM>1) pari_warn(warnmem,"Flxn_exp, e = %ld", n);3546gerepileall(av2, 2, &f, &g);3547}3548}3549return gerepileupto(av, f);3550}35513552GEN3553Flxn_exp(GEN h, long e, ulong p)3554{3555if (degpol(h)<1 || uel(h,2)!=0)3556pari_err_DOMAIN("Flxn_exp","valuation", "<", gen_1, h);3557return Flxn_expint(Flx_deriv(h, p), e, p);3558}35593560INLINE GEN3561Flxn_recip(GEN x, long n)3562{3563GEN z=Flx_recipspec(x+2,lgpol(x),n);3564z[1]=x[1];3565return z;3566}35673568GEN3569Flx_Newton(GEN P, long n, ulong p)3570{3571pari_sp av = avma;3572long d = degpol(P);3573GEN dP = Flxn_recip(Flx_deriv(P, p), d);3574GEN Q = Flxn_mul(Flxn_inv(Flxn_recip(P, d+1), n, p), dP, n, p);3575return gerepileuptoleaf(av, Q);3576}35773578GEN3579Flx_fromNewton(GEN P, ulong p)3580{3581pari_sp av = avma;3582ulong n = Flx_constant(P)+1;3583GEN z = Flx_neg(Flx_shift(P, -1), p);3584GEN Q = Flxn_recip(Flxn_expint(z, n, p), n);3585return gerepileuptoleaf(av, Q);3586}35873588static long3589newtonlogint(ulong n, ulong pp)3590{3591long s = 0;3592while (n > pp)3593{3594s += ulogint(n, pp);3595n = (n+1)>>1;3596}3597return s;3598}35993600static void3601init_invlaplace(long d, ulong p, GEN *pt_P, GEN *pt_V)3602{3603long i;3604ulong e;3605GEN P = cgetg(d+1, t_VECSMALL);3606GEN V = cgetg(d+1, t_VECSMALL);3607for (i=1, e=1; i<=d; i++, e++)3608{3609if (e==p)3610{3611e = 0;3612V[i] = u_lvalrem(i, p, &uel(P,i));3613} else3614{3615V[i] = 0; uel(P,i) = i;3616}3617}3618*pt_P = P; *pt_V = V;3619}36203621/* return p^val * FpX_invLaplace(1+x+...x^(n-1), q), with q a power of p and3622* val large enough to compensate for the power of p in the factorials */36233624static GEN3625ZpX_invLaplace_init(long n, GEN q, ulong p, long v, long sv)3626{3627pari_sp av = avma;3628long i, d = n-1, w;3629GEN y, W, E, t;3630init_invlaplace(d, p, &E, &W);3631t = Fp_inv(FpV_prod(Flv_to_ZV(E), q), q);3632w = zv_sum(W);3633if (v > w) t = Fp_mul(t, powuu(p, v-w), q);3634y = cgetg(d+3,t_POL);3635y[1] = evalsigne(1) | sv;3636for (i=d; i>=1; i--)3637{3638gel(y,i+2) = t;3639t = Fp_mulu(t, uel(E,i), q);3640if (uel(W,i)) t = Fp_mul(t, powuu(p, uel(W,i)), q);3641}3642gel(y,2) = t;3643return gerepilecopy(av, ZX_renormalize(y, d+3));3644}36453646static GEN3647Flx_composedsum(GEN P, GEN Q, ulong p)3648{3649long n = 1 + degpol(P)*degpol(Q);3650ulong lead = Fl_mul(Fl_powu(Flx_lead(P), degpol(Q), p),3651Fl_powu(Flx_lead(Q), degpol(P), p), p);3652GEN R;3653if (p >= (ulong)n)3654{3655GEN Pl = Flx_invLaplace(Flx_Newton(P,n,p), p);3656GEN Ql = Flx_invLaplace(Flx_Newton(Q,n,p), p);3657GEN L = Flx_Laplace(Flxn_mul(Pl, Ql, n, p), p);3658R = Flx_fromNewton(L, p);3659} else3660{3661long v = factorial_lval(n-1, p);3662long w = 1 + newtonlogint(n-1, p);3663GEN pv = powuu(p, v);3664GEN qf = powuu(p, w), q = mulii(pv, qf), q2 = mulii(q, pv);3665GEN iL = ZpX_invLaplace_init(n, q, p, v, P[1]);3666GEN Pl = FpX_convol(iL, FpX_Newton(Flx_to_ZX(P), n, qf), q);3667GEN Ql = FpX_convol(iL, FpX_Newton(Flx_to_ZX(Q), n, qf), q);3668GEN Ln = ZX_Z_divexact(FpXn_mul(Pl, Ql, n, q2), pv);3669GEN L = ZX_Z_divexact(FpX_Laplace(Ln, q), pv);3670R = ZX_to_Flx(FpX_fromNewton(L, qf), p);3671}3672return Flx_Fl_mul(R, lead, p);3673}36743675GEN3676Flx_direct_compositum(GEN a, GEN b, ulong p)3677{3678return Flx_composedsum(a, b, p);3679}36803681static GEN3682_Flx_direct_compositum(void *E, GEN a, GEN b)3683{ return Flx_direct_compositum(a, b, (ulong)E); }36843685GEN3686FlxV_direct_compositum(GEN V, ulong p)3687{3688return gen_product(V, (void *)p, &_Flx_direct_compositum);3689}36903691/* (x+1)^n mod p; assume 2 <= n < 2p prime */3692static GEN3693Fl_Xp1_powu(ulong n, ulong p, long v)3694{3695ulong k, d = (n + 1) >> 1;3696GEN C, V = identity_zv(d);36973698Flv_inv_inplace(V, p); /* could restrict to odd integers in [3,d] */3699C = cgetg(n+3, t_VECSMALL);3700C[1] = v;3701uel(C,2) = 1UL;3702uel(C,3) = n%p;3703uel(C,4) = Fl_mul(odd(n)? n: n-1, n >> 1, p);3704/* binom(n,k) = binom(n,k-1) * (n-k+1) / k */3705if (SMALL_ULONG(p))3706for (k = 3; k <= d; k++)3707uel(C,k+2) = Fl_mul(Fl_mul(n-k+1, uel(C,k+1), p), uel(V,k), p);3708else3709{3710ulong pi = get_Fl_red(p);3711for (k = 3; k <= d; k++)3712uel(C,k+2) = Fl_mul_pre(Fl_mul(n-k+1, uel(C,k+1), p), uel(V,k), p, pi);3713}3714for ( ; k <= n; k++) uel(C,2+k) = uel(C,2+n-k);3715return C; /* normalized */3716}37173718/* p arbitrary */3719GEN3720Flx_translate1_basecase(GEN P, ulong p)3721{3722GEN R = Flx_copy(P);3723long i, k, n = degpol(P);3724for (i = 1; i <= n; i++)3725for (k = n-i; k < n; k++) uel(R,k+2) = Fl_add(uel(R,k+2), uel(R,k+3), p);3726return R;3727}37283729static int3730translate_basecase(long n, ulong p)3731{3732#ifdef LONG_IS_64BIT3733if (p <= 19) return n < 40;3734if (p < 1UL<<30) return n < 58;3735if (p < 1UL<<59) return n < 100;3736if (p < 1UL<<62) return n < 120;3737if (p < 1UL<<63) return n < 240;3738return n < 250;3739#else3740if (p <= 13) return n < 18;3741if (p <= 17) return n < 22;3742if (p <= 29) return n < 39;3743if (p <= 67) return n < 69;3744if (p < 1UL<< 15) return n < 80;3745if (p < 1UL<< 16) return n < 100;3746if (p < 1UL<< 28) return n < 300;3747return n < 650;3748#endif3749}3750/* assume p prime */3751GEN3752Flx_translate1(GEN P, ulong p)3753{3754long d, n = degpol(P);3755GEN R, Q, S;3756if (translate_basecase(n, p)) return Flx_translate1_basecase(P, p);3757/* n > 0 */3758d = n >> 1;3759if ((ulong)n < p)3760{3761R = Flx_translate1(Flxn_red(P, d), p);3762Q = Flx_translate1(Flx_shift(P, -d), p);3763S = Fl_Xp1_powu(d, p, P[1]);3764return Flx_add(Flx_mul(Q, S, p), R, p);3765}3766else3767{3768ulong q;3769if ((ulong)d > p) (void)ulogintall(d, p, &q); else q = p;3770R = Flx_translate1(Flxn_red(P, q), p);3771Q = Flx_translate1(Flx_shift(P, -q), p);3772S = Flx_add(Flx_shift(Q, q), Q, p);3773return Flx_add(S, R, p); /* P(x+1) = Q(x+1) (x^q+1) + R(x+1) */3774}3775}37763777static GEN3778zl_Xp1_powu(ulong n, ulong p, ulong q, long e, long vs)3779{3780ulong k, d = n >> 1, c, v = 0;3781GEN C, V, W, U = upowers(p, e-1);3782init_invlaplace(d, p, &V, &W);3783Flv_inv_inplace(V, q);3784C = cgetg(n+3, t_VECSMALL);3785C[1] = vs;3786uel(C,2) = 1UL;3787uel(C,3) = n%q;3788v = u_lvalrem(n, p, &c);3789for (k = 2; k <= d; k++)3790{3791ulong w;3792v += u_lvalrem(n-k+1, p, &w) - W[k];3793c = Fl_mul(Fl_mul(w%q, c, q), uel(V,k), q);3794uel(C,2+k) = v >= (ulong)e ? 0: v==0 ? c : Fl_mul(c, uel(U, v+1), q);3795}3796for ( ; k <= n; k++) uel(C,2+k) = uel(C,2+n-k);3797return C; /* normalized */3798}37993800GEN3801zlx_translate1(GEN P, ulong p, long e)3802{3803ulong d, q = upowuu(p,e), n = degpol(P);3804GEN R, Q, S;3805if (translate_basecase(n, q)) return Flx_translate1_basecase(P, q);3806/* n > 0 */3807d = n >> 1;3808R = zlx_translate1(Flxn_red(P, d), p, e);3809Q = zlx_translate1(Flx_shift(P, -d), p, e);3810S = zl_Xp1_powu(d, p, q, e, P[1]);3811return Flx_add(Flx_mul(Q, S, q), R, q);3812}38133814/***********************************************************************/3815/** **/3816/** Fl2 **/3817/** **/3818/***********************************************************************/3819/* Fl2 objects are Flv of length 2 [a,b] representing a+bsqrt(D) for3820* a nonsquare D. */38213822INLINE GEN3823mkF2(ulong a, ulong b) { return mkvecsmall2(a,b); }38243825GEN3826Fl2_mul_pre(GEN x, GEN y, ulong D, ulong p, ulong pi)3827{3828ulong xaya, xbyb, Db2, mid;3829ulong z1, z2;3830ulong x1 = x[1], x2 = x[2], y1 = y[1], y2 = y[2];3831xaya = Fl_mul_pre(x1,y1,p,pi);3832if (x2==0 && y2==0) return mkF2(xaya,0);3833if (x2==0) return mkF2(xaya,Fl_mul_pre(x1,y2,p,pi));3834if (y2==0) return mkF2(xaya,Fl_mul_pre(x2,y1,p,pi));3835xbyb = Fl_mul_pre(x2,y2,p,pi);3836mid = Fl_mul_pre(Fl_add(x1,x2,p), Fl_add(y1,y2,p),p,pi);3837Db2 = Fl_mul_pre(D, xbyb, p,pi);3838z1 = Fl_add(xaya,Db2,p);3839z2 = Fl_sub(mid,Fl_add(xaya,xbyb,p),p);3840return mkF2(z1,z2);3841}38423843GEN3844Fl2_sqr_pre(GEN x, ulong D, ulong p, ulong pi)3845{3846ulong a = x[1], b = x[2];3847ulong a2, Db2, ab;3848a2 = Fl_sqr_pre(a,p,pi);3849if (b==0) return mkF2(a2,0);3850Db2= Fl_mul_pre(D, Fl_sqr_pre(b,p,pi), p,pi);3851ab = Fl_mul_pre(a,b,p,pi);3852return mkF2(Fl_add(a2,Db2,p), Fl_double(ab,p));3853}38543855ulong3856Fl2_norm_pre(GEN x, ulong D, ulong p, ulong pi)3857{3858ulong a2 = Fl_sqr_pre(x[1],p,pi);3859return x[2]? Fl_sub(a2, Fl_mul_pre(D, Fl_sqr_pre(x[2], p,pi), p,pi), p): a2;3860}38613862GEN3863Fl2_inv_pre(GEN x, ulong D, ulong p, ulong pi)3864{3865ulong n, ni;3866if (x[2] == 0) return mkF2(Fl_inv(x[1],p),0);3867n = Fl_sub(Fl_sqr_pre(x[1], p,pi),3868Fl_mul_pre(D, Fl_sqr_pre(x[2], p,pi), p,pi), p);3869ni = Fl_inv(n,p);3870return mkF2(Fl_mul_pre(x[1], ni, p,pi),3871Fl_neg(Fl_mul_pre(x[2], ni, p,pi), p));3872}38733874int3875Fl2_equal1(GEN x) { return x[1]==1 && x[2]==0; }38763877struct _Fl2 {3878ulong p, pi, D;3879};38803881static GEN3882_Fl2_sqr(void *data, GEN x)3883{3884struct _Fl2 *D = (struct _Fl2*)data;3885return Fl2_sqr_pre(x, D->D, D->p, D->pi);3886}3887static GEN3888_Fl2_mul(void *data, GEN x, GEN y)3889{3890struct _Fl2 *D = (struct _Fl2*)data;3891return Fl2_mul_pre(x,y, D->D, D->p, D->pi);3892}38933894/* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */3895GEN3896Fl2_pow_pre(GEN x, GEN n, ulong D, ulong p, ulong pi)3897{3898pari_sp av = avma;3899struct _Fl2 d;3900GEN y;3901long s = signe(n);3902if (!s) return mkF2(1,0);3903if (s < 0)3904x = Fl2_inv_pre(x,D,p,pi);3905if (is_pm1(n)) return s < 0 ? x : zv_copy(x);3906d.p = p; d.pi = pi; d.D=D;3907y = gen_pow_i(x, n, (void*)&d, &_Fl2_sqr, &_Fl2_mul);3908return gerepileuptoleaf(av, y);3909}39103911static GEN3912_Fl2_pow(void *data, GEN x, GEN n)3913{3914struct _Fl2 *D = (struct _Fl2*)data;3915return Fl2_pow_pre(x, n, D->D, D->p, D->pi);3916}39173918static GEN3919_Fl2_rand(void *data)3920{3921struct _Fl2 *D = (struct _Fl2*)data;3922ulong a = random_Fl(D->p), b=random_Fl(D->p-1)+1;3923return mkF2(a,b);3924}39253926static const struct bb_group Fl2_star={_Fl2_mul, _Fl2_pow, _Fl2_rand,3927hash_GEN, zv_equal, Fl2_equal1, NULL};39283929GEN3930Fl2_sqrtn_pre(GEN a, GEN n, ulong D, ulong p, ulong pi, GEN *zeta)3931{3932struct _Fl2 E;3933GEN o;3934if (a[1]==0 && a[2]==0)3935{3936if (signe(n) < 0) pari_err_INV("Flxq_sqrtn",a);3937if (zeta) *zeta=mkF2(1,0);3938return zv_copy(a);3939}3940E.p=p; E.pi = pi; E.D = D;3941o = subiu(powuu(p,2), 1);3942return gen_Shanks_sqrtn(a,n,o,zeta,(void*)&E,&Fl2_star);3943}39443945GEN3946Flx_Fl2_eval_pre(GEN x, GEN y, ulong D, ulong p, ulong pi)3947{3948GEN p1;3949long i = lg(x)-1;3950if (i <= 2)3951return mkF2(i == 2? x[2]: 0, 0);3952p1 = mkF2(x[i], 0);3953for (i--; i>=2; i--)3954{3955p1 = Fl2_mul_pre(p1, y, D, p, pi);3956uel(p1,1) = Fl_add(uel(p1,1), uel(x,i), p);3957}3958return p1;3959}39603961/***********************************************************************/3962/** **/3963/** FlxV **/3964/** **/3965/***********************************************************************/3966/* FlxV are t_VEC with Flx coefficients. */39673968GEN3969FlxV_Flc_mul(GEN V, GEN W, ulong p)3970{3971pari_sp ltop=avma;3972long i;3973GEN z = Flx_Fl_mul(gel(V,1),W[1],p);3974for(i=2;i<lg(V);i++)3975z=Flx_add(z,Flx_Fl_mul(gel(V,i),W[i],p),p);3976return gerepileuptoleaf(ltop,z);3977}39783979GEN3980ZXV_to_FlxV(GEN x, ulong p)3981{ pari_APPLY_type(t_VEC, ZX_to_Flx(gel(x,i), p)) }39823983GEN3984ZXT_to_FlxT(GEN x, ulong p)3985{3986if (typ(x) == t_POL)3987return ZX_to_Flx(x, p);3988else3989pari_APPLY_type(t_VEC, ZXT_to_FlxT(gel(x,i), p))3990}39913992GEN3993FlxV_to_Flm(GEN x, long n)3994{ pari_APPLY_type(t_MAT, Flx_to_Flv(gel(x,i), n)) }39953996GEN3997FlxV_red(GEN x, ulong p)3998{ pari_APPLY_type(t_VEC, Flx_red(gel(x,i), p)) }39994000GEN4001FlxT_red(GEN x, ulong p)4002{4003if (typ(x) == t_VECSMALL)4004return Flx_red(x, p);4005else4006pari_APPLY_type(t_VEC, FlxT_red(gel(x,i), p))4007}40084009GEN4010FlxqV_dotproduct(GEN x, GEN y, GEN T, ulong p)4011{4012long i, lx = lg(x);4013pari_sp av;4014GEN c;4015if (lx == 1) return pol0_Flx(get_Flx_var(T));4016av = avma; c = Flx_mul(gel(x,1),gel(y,1), p);4017for (i=2; i<lx; i++) c = Flx_add(c, Flx_mul(gel(x,i),gel(y,i), p), p);4018return gerepileuptoleaf(av, Flx_rem(c,T,p));4019}40204021GEN4022FlxqX_dotproduct(GEN x, GEN y, GEN T, ulong p)4023{4024long i, l = minss(lg(x), lg(y));4025pari_sp av;4026GEN c;4027if (l == 2) return pol0_Flx(get_Flx_var(T));4028av = avma; c = Flx_mul(gel(x,2),gel(y,2), p);4029for (i=3; i<l; i++) c = Flx_add(c, Flx_mul(gel(x,i),gel(y,i), p), p);4030return gerepileuptoleaf(av, Flx_rem(c,T,p));4031}40324033GEN4034FlxC_eval_powers_pre(GEN z, GEN x, ulong p, ulong pi)4035{4036long i, l = lg(z);4037GEN y = cgetg(l, t_VECSMALL);4038for (i=1; i<l; i++)4039uel(y,i) = Flx_eval_powers_pre(gel(z,i), x, p, pi);4040return y;4041}40424043/***********************************************************************/4044/** **/4045/** FlxM **/4046/** **/4047/***********************************************************************/40484049GEN4050FlxM_eval_powers_pre(GEN z, GEN x, ulong p, ulong pi)4051{4052long i, l = lg(z);4053GEN y = cgetg(l, t_MAT);4054for (i=1; i<l; i++)4055gel(y,i) = FlxC_eval_powers_pre(gel(z,i), x, p, pi);4056return y;4057}40584059GEN4060zero_FlxC(long n, long sv)4061{4062long i;4063GEN x = cgetg(n + 1, t_COL);4064GEN z = zero_Flx(sv);4065for (i = 1; i <= n; i++)4066gel(x, i) = z;4067return x;4068}40694070GEN4071FlxC_neg(GEN x, ulong p)4072{ pari_APPLY_type(t_COL, Flx_neg(gel(x, i), p)) }40734074GEN4075FlxC_sub(GEN x, GEN y, ulong p)4076{ pari_APPLY_type(t_COL, Flx_sub(gel(x, i), gel(y, i), p)) }40774078GEN4079zero_FlxM(long r, long c, long sv)4080{4081long j;4082GEN x = cgetg(c + 1, t_MAT);4083GEN z = zero_FlxC(r, sv);4084for (j = 1; j <= c; j++)4085gel(x, j) = z;4086return x;4087}40884089GEN4090FlxM_neg(GEN x, ulong p)4091{ pari_APPLY_same(FlxC_neg(gel(x, i), p)) }40924093GEN4094FlxM_sub(GEN x, GEN y, ulong p)4095{ pari_APPLY_same(FlxC_sub(gel(x, i), gel(y,i), p)) }40964097GEN4098FlxqC_Flxq_mul(GEN x, GEN y, GEN T, ulong p)4099{ pari_APPLY_type(t_COL, Flxq_mul(gel(x, i), y, T, p)) }41004101GEN4102FlxqM_Flxq_mul(GEN x, GEN y, GEN T, ulong p)4103{ pari_APPLY_same(FlxqC_Flxq_mul(gel(x, i), y, T, p)) }41044105static GEN4106FlxM_pack_ZM(GEN M, GEN (*pack)(GEN, long)) {4107long i, j, l, lc;4108GEN N = cgetg_copy(M, &l), x;4109if (l == 1)4110return N;4111lc = lgcols(M);4112for (j = 1; j < l; j++) {4113gel(N, j) = cgetg(lc, t_COL);4114for (i = 1; i < lc; i++) {4115x = gcoeff(M, i, j);4116gcoeff(N, i, j) = pack(x + 2, lgpol(x));4117}4118}4119return N;4120}41214122static GEN4123kron_pack_Flx_spec_half(GEN x, long l) {4124if (l == 0)4125return gen_0;4126return Flx_to_int_halfspec(x, l);4127}41284129static GEN4130kron_pack_Flx_spec(GEN x, long l) {4131long i;4132GEN w, y;4133if (l == 0)4134return gen_0;4135y = cgetipos(l + 2);4136for (i = 0, w = int_LSW(y); i < l; i++, w = int_nextW(w))4137*w = x[i];4138return y;4139}41404141static GEN4142kron_pack_Flx_spec_2(GEN x, long l) {4143return Flx_eval2BILspec(x, 2, l);4144}41454146static GEN4147kron_pack_Flx_spec_3(GEN x, long l) {4148return Flx_eval2BILspec(x, 3, l);4149}41504151static GEN4152kron_unpack_Flx(GEN z, ulong p)4153{4154long i, l = lgefint(z);4155GEN x = cgetg(l, t_VECSMALL), w;4156for (w = int_LSW(z), i = 2; i < l; w = int_nextW(w), i++)4157x[i] = ((ulong) *w) % p;4158return Flx_renormalize(x, l);4159}41604161static GEN4162kron_unpack_Flx_2(GEN x, ulong p) {4163long d = (lgefint(x)-1)/2 - 1;4164return Z_mod2BIL_Flx_2(x, d, p);4165}41664167static GEN4168kron_unpack_Flx_3(GEN x, ulong p) {4169long d = lgefint(x)/3 - 1;4170return Z_mod2BIL_Flx_3(x, d, p);4171}41724173static GEN4174FlxM_pack_ZM_bits(GEN M, long b)4175{4176long i, j, l, lc;4177GEN N = cgetg_copy(M, &l), x;4178if (l == 1)4179return N;4180lc = lgcols(M);4181for (j = 1; j < l; j++) {4182gel(N, j) = cgetg(lc, t_COL);4183for (i = 1; i < lc; i++) {4184x = gcoeff(M, i, j);4185gcoeff(N, i, j) = kron_pack_Flx_spec_bits(x + 2, b, lgpol(x));4186}4187}4188return N;4189}41904191static GEN4192ZM_unpack_FlxqM(GEN M, GEN T, ulong p, GEN (*unpack)(GEN, ulong))4193{4194long i, j, l, lc, sv = get_Flx_var(T);4195GEN N = cgetg_copy(M, &l), x;4196if (l == 1)4197return N;4198lc = lgcols(M);4199for (j = 1; j < l; j++) {4200gel(N, j) = cgetg(lc, t_COL);4201for (i = 1; i < lc; i++) {4202x = unpack(gcoeff(M, i, j), p);4203x[1] = sv;4204gcoeff(N, i, j) = Flx_rem(x, T, p);4205}4206}4207return N;4208}42094210static GEN4211ZM_unpack_FlxqM_bits(GEN M, long b, GEN T, ulong p)4212{4213long i, j, l, lc, sv = get_Flx_var(T);4214GEN N = cgetg_copy(M, &l), x;4215if (l == 1)4216return N;4217lc = lgcols(M);4218if (b < BITS_IN_LONG) {4219for (j = 1; j < l; j++) {4220gel(N, j) = cgetg(lc, t_COL);4221for (i = 1; i < lc; i++) {4222x = kron_unpack_Flx_bits_narrow(gcoeff(M, i, j), b, p);4223x[1] = sv;4224gcoeff(N, i, j) = Flx_rem(x, T, p);4225}4226}4227} else {4228ulong pi = get_Fl_red(p);4229for (j = 1; j < l; j++) {4230gel(N, j) = cgetg(lc, t_COL);4231for (i = 1; i < lc; i++) {4232x = kron_unpack_Flx_bits_wide(gcoeff(M, i, j), b, p, pi);4233x[1] = sv;4234gcoeff(N, i, j) = Flx_rem(x, T, p);4235}4236}4237}4238return N;4239}42404241GEN4242FlxqM_mul_Kronecker(GEN A, GEN B, GEN T, ulong p)4243{4244pari_sp av = avma;4245long b, d = get_Flx_degree(T), n = lg(A) - 1;4246GEN C, D, z;4247GEN (*pack)(GEN, long), (*unpack)(GEN, ulong);4248int is_sqr = A==B;42494250z = muliu(muliu(sqru(p - 1), d), n);4251b = expi(z) + 1;4252/* only do expensive bit-packing if it saves at least 1 limb */4253if (b <= BITS_IN_HALFULONG) {4254if (nbits2nlong(d*b) == (d + 1)/2)4255b = BITS_IN_HALFULONG;4256} else {4257long l = lgefint(z) - 2;4258if (nbits2nlong(d*b) == d*l)4259b = l*BITS_IN_LONG;4260}4261set_avma(av);42624263switch (b) {4264case BITS_IN_HALFULONG:4265pack = kron_pack_Flx_spec_half;4266unpack = int_to_Flx_half;4267break;4268case BITS_IN_LONG:4269pack = kron_pack_Flx_spec;4270unpack = kron_unpack_Flx;4271break;4272case 2*BITS_IN_LONG:4273pack = kron_pack_Flx_spec_2;4274unpack = kron_unpack_Flx_2;4275break;4276case 3*BITS_IN_LONG:4277pack = kron_pack_Flx_spec_3;4278unpack = kron_unpack_Flx_3;4279break;4280default:4281A = FlxM_pack_ZM_bits(A, b);4282B = is_sqr? A: FlxM_pack_ZM_bits(B, b);4283C = ZM_mul(A, B);4284D = ZM_unpack_FlxqM_bits(C, b, T, p);4285return gerepilecopy(av, D);4286}4287A = FlxM_pack_ZM(A, pack);4288B = is_sqr? A: FlxM_pack_ZM(B, pack);4289C = ZM_mul(A, B);4290D = ZM_unpack_FlxqM(C, T, p, unpack);4291return gerepilecopy(av, D);4292}429342944295