Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2007 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"1617/*******************************************************************/18/* */19/* ZX */20/* */21/*******************************************************************/22void23RgX_check_QX(GEN x, const char *s)24{ if (!RgX_is_QX(x)) pari_err_TYPE(stack_strcat(s," [not in Q[X]]"), x); }25void26RgX_check_ZX(GEN x, const char *s)27{ if (!RgX_is_ZX(x)) pari_err_TYPE(stack_strcat(s," [not in Z[X]]"), x); }28long29ZX_max_lg(GEN x)30{31long i, prec = 0, lx = lg(x);3233for (i=2; i<lx; i++) { long l = lgefint(gel(x,i)); if (l > prec) prec = l; }34return prec;35}3637GEN38ZX_add(GEN x, GEN y)39{40long lx,ly,i;41GEN z;42lx = lg(x); ly = lg(y); if (lx < ly) swapspec(x,y, lx,ly);43z = cgetg(lx,t_POL); z[1] = x[1];44for (i=2; i<ly; i++) gel(z,i) = addii(gel(x,i),gel(y,i));45for ( ; i<lx; i++) gel(z,i) = icopy(gel(x,i));46if (lx == ly) z = ZX_renormalize(z, lx);47if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }48return z;49}5051GEN52ZX_sub(GEN x,GEN y)53{54long i, lx = lg(x), ly = lg(y);55GEN z;56if (lx >= ly)57{58z = cgetg(lx,t_POL); z[1] = x[1];59for (i=2; i<ly; i++) gel(z,i) = subii(gel(x,i),gel(y,i));60if (lx == ly)61{62z = ZX_renormalize(z, lx);63if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); z = pol_0(varn(x)); }64}65else66for ( ; i<lx; i++) gel(z,i) = icopy(gel(x,i));67}68else69{70z = cgetg(ly,t_POL); z[1] = y[1];71for (i=2; i<lx; i++) gel(z,i) = subii(gel(x,i),gel(y,i));72for ( ; i<ly; i++) gel(z,i) = negi(gel(y,i));73}74return z;75}7677GEN78ZX_neg(GEN x)79{80long i, l = lg(x);81GEN y = cgetg(l,t_POL);82y[1] = x[1]; for(i=2; i<l; i++) gel(y,i) = negi(gel(x,i));83return y;84}85GEN86ZX_copy(GEN x)87{88long i, l = lg(x);89GEN y = cgetg(l, t_POL);90y[1] = x[1];91for (i=2; i<l; i++)92{93GEN c = gel(x,i);94gel(y,i) = lgefint(c) == 2? gen_0: icopy(c);95}96return y;97}9899GEN100scalar_ZX(GEN x, long v)101{102GEN z;103if (!signe(x)) return pol_0(v);104z = cgetg(3, t_POL);105z[1] = evalsigne(1) | evalvarn(v);106gel(z,2) = icopy(x); return z;107}108109GEN110scalar_ZX_shallow(GEN x, long v)111{112GEN z;113if (!signe(x)) return pol_0(v);114z = cgetg(3, t_POL);115z[1] = evalsigne(1) | evalvarn(v);116gel(z,2) = x; return z;117}118119GEN120ZX_Z_add(GEN y, GEN x)121{122long lz, i;123GEN z = cgetg_copy(y, &lz);124if (lz == 2) { set_avma((pari_sp)(z + 2)); return scalar_ZX(x,varn(y)); }125z[1] = y[1];126gel(z,2) = addii(gel(y,2),x);127for(i=3; i<lz; i++) gel(z,i) = icopy(gel(y,i));128if (lz==3) z = ZX_renormalize(z,lz);129return z;130}131GEN132ZX_Z_add_shallow(GEN y, GEN x)133{134long lz, i;135GEN z = cgetg_copy(y, &lz);136if (lz == 2) { set_avma((pari_sp)(z + 2)); return scalar_ZX_shallow(x,varn(y)); }137z[1] = y[1];138gel(z,2) = addii(gel(y,2),x);139for(i=3; i<lz; i++) gel(z,i) = gel(y,i);140if (lz==3) z = ZX_renormalize(z,lz);141return z;142}143144GEN145ZX_Z_sub(GEN y, GEN x)146{147long lz, i;148GEN z = cgetg_copy(y, &lz);149if (lz == 2)150{ /* scalarpol(negi(x), v) */151long v = varn(y);152set_avma((pari_sp)(z + 2));153if (!signe(x)) return pol_0(v);154z = cgetg(3,t_POL);155z[1] = evalvarn(v) | evalsigne(1);156gel(z,2) = negi(x); return z;157}158z[1] = y[1];159gel(z,2) = subii(gel(y,2),x);160for(i=3; i<lz; i++) gel(z,i) = icopy(gel(y,i));161if (lz==3) z = ZX_renormalize(z,lz);162return z;163}164165GEN166Z_ZX_sub(GEN x, GEN y)167{168long lz, i;169GEN z = cgetg_copy(y, &lz);170if (lz == 2) { set_avma((pari_sp)(z + 2)); return scalar_ZX(x,varn(y)); }171z[1] = y[1];172gel(z,2) = subii(x, gel(y,2));173for(i=3; i<lz; i++) gel(z,i) = negi(gel(y,i));174if (lz==3) z = ZX_renormalize(z,lz);175return z;176}177178GEN179ZX_Z_divexact(GEN y,GEN x)180{181long i, l = lg(y);182GEN z = cgetg(l,t_POL); z[1] = y[1];183for(i=2; i<l; i++) gel(z,i) = diviiexact(gel(y,i),x);184return z;185}186187GEN188ZX_divuexact(GEN y, ulong x)189{190long i, l = lg(y);191GEN z = cgetg(l,t_POL); z[1] = y[1];192for(i=2; i<l; i++) gel(z,i) = diviuexact(gel(y,i),x);193return z;194}195196GEN197zx_z_divexact(GEN y, long x)198{199long i, l = lg(y);200GEN z = cgetg(l,t_VECSMALL); z[1] = y[1];201for (i=2; i<l; i++) z[i] = y[i]/x;202return z;203}204205GEN206ZX_Z_mul(GEN y,GEN x)207{208GEN z;209long i, l;210if (!signe(x)) return pol_0(varn(y));211l = lg(y); z = cgetg(l,t_POL); z[1] = y[1];212for(i=2; i<l; i++) gel(z,i) = mulii(gel(y,i),x);213return z;214}215216GEN217ZX_mulu(GEN y, ulong x)218{219GEN z;220long i, l;221if (!x) return pol_0(varn(y));222l = lg(y); z = cgetg(l,t_POL); z[1] = y[1];223for(i=2; i<l; i++) gel(z,i) = mului(x,gel(y,i));224return z;225}226227GEN228ZX_shifti(GEN y, long n)229{230GEN z;231long i, l;232l = lg(y); z = cgetg(l,t_POL); z[1] = y[1];233for(i=2; i<l; i++) gel(z,i) = shifti(gel(y,i),n);234return ZX_renormalize(z,l);235}236237GEN238ZX_remi2n(GEN y, long n)239{240GEN z;241long i, l;242l = lg(y); z = cgetg(l,t_POL); z[1] = y[1];243for(i=2; i<l; i++) gel(z,i) = remi2n(gel(y,i),n);244return ZX_renormalize(z,l);245}246247GEN248ZXT_remi2n(GEN z, long n)249{250if (typ(z) == t_POL)251return ZX_remi2n(z, n);252else253{254long i,l = lg(z);255GEN x = cgetg(l, t_VEC);256for (i=1; i<l; i++) gel(x,i) = ZXT_remi2n(gel(z,i), n);257return x;258}259}260261GEN262zx_to_ZX(GEN z)263{264long i, l = lg(z);265GEN x = cgetg(l,t_POL);266for (i=2; i<l; i++) gel(x,i) = stoi(z[i]);267x[1] = evalsigne(l-2!=0)| z[1]; return x;268}269270GEN271ZX_deriv(GEN x)272{273long i,lx = lg(x)-1;274GEN y;275276if (lx<3) return pol_0(varn(x));277y = cgetg(lx,t_POL);278for (i=2; i<lx ; i++) gel(y,i) = mului(i-1,gel(x,i+1));279y[1] = x[1]; return y;280}281282int283ZX_equal(GEN V, GEN W)284{285long i, l = lg(V);286if (lg(W) != l) return 0;287for (i = 2; i < l; i++)288if (!equalii(gel(V,i), gel(W,i))) return 0;289return 1;290}291292static long293ZX_valspec(GEN x, long nx)294{295long vx;296for (vx = 0; vx<nx ; vx++)297if (signe(gel(x,vx))) break;298return vx;299}300301long302ZX_val(GEN x)303{304long vx;305if (!signe(x)) return LONG_MAX;306for (vx = 0;; vx++)307if (signe(gel(x,2+vx))) break;308return vx;309}310long311ZX_valrem(GEN x, GEN *Z)312{313long vx;314if (!signe(x)) { *Z = pol_0(varn(x)); return LONG_MAX; }315for (vx = 0;; vx++)316if (signe(gel(x,2+vx))) break;317*Z = RgX_shift_shallow(x, -vx);318return vx;319}320321GEN322ZX_div_by_X_1(GEN a, GEN *r)323{324long l = lg(a), i;325GEN a0, z0, z = cgetg(l-1, t_POL);326z[1] = a[1];327a0 = a + l-1;328z0 = z + l-2; *z0 = *a0--;329for (i=l-3; i>1; i--) /* z[i] = a[i+1] + z[i+1] */330{331GEN t = addii(gel(a0--,0), gel(z0--,0));332gel(z0,0) = t;333}334if (r) *r = addii(gel(a0,0), gel(z0,0));335return z;336}337338/* return P(X + c) using destructive Horner, optimize for c = 1,-1 */339static GEN340ZX_translate_basecase(GEN P, GEN c)341{342pari_sp av = avma;343GEN Q, R;344long i, k, n;345346if (!signe(P) || !signe(c)) return ZX_copy(P);347Q = leafcopy(P);348R = Q+2; n = degpol(P);349if (equali1(c))350{351for (i=1; i<=n; i++)352{353for (k=n-i; k<n; k++) gel(R,k) = addii(gel(R,k), gel(R,k+1));354if (gc_needed(av,2))355{356if(DEBUGMEM>1) pari_warn(warnmem,"ZX_translate(1), i = %ld/%ld", i,n);357Q = gerepilecopy(av, Q); R = Q+2;358}359}360}361else if (equalim1(c))362{363for (i=1; i<=n; i++)364{365for (k=n-i; k<n; k++) gel(R,k) = subii(gel(R,k), gel(R,k+1));366if (gc_needed(av,2))367{368if(DEBUGMEM>1) pari_warn(warnmem,"ZX_translate(-1), i = %ld/%ld", i,n);369Q = gerepilecopy(av, Q); R = Q+2;370}371}372}373else374{375for (i=1; i<=n; i++)376{377for (k=n-i; k<n; k++) gel(R,k) = addmulii_inplace(gel(R,k), c, gel(R,k+1));378if (gc_needed(av,2))379{380if(DEBUGMEM>1) pari_warn(warnmem,"ZX_translate, i = %ld/%ld", i,n);381Q = gerepilecopy(av, Q); R = Q+2;382}383}384}385return gerepilecopy(av, Q);386}387388static GEN389Z_Xpm1_powu(long n, long s, long v)390{391long d, k;392GEN C;393if (!n) return pol_1(v);394d = (n + 1) >> 1;395C = cgetg(n+3, t_POL);396C[1] = evalsigne(1)| evalvarn(v);397gel(C,2) = gen_1;398gel(C,3) = utoipos(n);399for (k=2; k <= d; k++)400gel(C,k+2) = diviuexact(mului(n-k+1, gel(C,k+1)), k);401if (s < 0)402for (k = odd(n)? 0: 1; k <= d; k += 2)403togglesign_safe(&gel(C,k+2));404if (s > 0 || !odd(n))405for (k = d+1; k <= n; k++) gel(C,k+2) = gel(C,n-k+2);406else407for (k = d+1; k <= n; k++) gel(C,k+2) = negi(gel(C,n-k+2));408return C;409}410/* return (x+u)^n */411static GEN412Z_XpN_powu(GEN u, long n, long v)413{414pari_sp av;415long k;416GEN B, C, V;417if (!n) return pol_1(v);418if (is_pm1(u))419return Z_Xpm1_powu(n, signe(u), v);420av = avma;421V = gpowers(u, n);422B = vecbinomial(n);423C = cgetg(n+3, t_POL);424C[1] = evalsigne(1)| evalvarn(v);425for (k=1; k <= n+1; k++)426gel(C,k+1) = mulii(gel(V,n+2-k), gel(B,k));427return gerepileupto(av, C);428}429430GEN431ZX_translate(GEN P, GEN c)432{433pari_sp av = avma;434long n = degpol(P);435if (n < 220)436return ZX_translate_basecase(P, c);437else438{439long d = n >> 1;440GEN Q = ZX_translate(RgX_shift_shallow(P, -d), c);441GEN R = ZX_translate(RgXn_red_shallow(P, d), c);442GEN S = Z_XpN_powu(c, d, varn(P));443return gerepileupto(av, ZX_add(ZX_mul(Q, S), R));444}445}446447GEN448ZX_Z_eval(GEN x, GEN y)449{450long i = lg(x)-1, j;451pari_sp av = avma;452GEN t, r;453454if (i<=2) return (i==2)? icopy(gel(x,2)): gen_0;455if (!signe(y)) return icopy(gel(x,2));456457t = gel(x,i); i--;458#if 0 /* standard Horner's rule */459for ( ; i>=2; i--)460t = addii(mulii(t,y),gel(x,i));461#endif462/* specific attention to sparse polynomials */463for ( ; i>=2; i = j-1)464{465for (j = i; !signe(gel(x,j)); j--)466if (j==2)467{468if (i != j) y = powiu(y, i-j+1);469return gerepileuptoint(av, mulii(t,y));470}471r = (i==j)? y: powiu(y, i-j+1);472t = addii(mulii(t,r), gel(x,j));473if (gc_needed(av,2))474{475if (DEBUGMEM>1) pari_warn(warnmem,"ZX_Z_eval: i = %ld",i);476t = gerepileuptoint(av, t);477}478}479return gerepileuptoint(av, t);480}481482/* Return 2^(n degpol(P)) P(x >> n) */483GEN484ZX_rescale2n(GEN P, long n)485{486long i, l = lg(P), ni = n;487GEN Q;488if (l==2) return pol_0(varn(P));489Q = cgetg(l,t_POL);490gel(Q,l-1) = icopy(gel(P,l-1));491for (i=l-2; i>=2; i--)492{493gel(Q,i) = shifti(gel(P,i), ni);494ni += n;495}496Q[1] = P[1]; return Q;497}498499/* Return h^deg(P) P(x / h), not memory clean. h integer, P ZX */500GEN501ZX_rescale(GEN P, GEN h)502{503long l = lg(P);504GEN Q = cgetg(l,t_POL);505if (l != 2)506{507long i = l-1;508GEN hi = h;509gel(Q,i) = gel(P,i);510if (l != 3) { i--; gel(Q,i) = mulii(gel(P,i), h); }511for (i--; i>=2; i--) { hi = mulii(hi,h); gel(Q,i) = mulii(gel(P,i), hi); }512}513Q[1] = P[1]; return Q;514}515/* Return h^(deg(P)-1) P(x / h), P!=0, h=lt(P), memory unclean; monic result */516GEN517ZX_rescale_lt(GEN P)518{519long l = lg(P);520GEN Q = cgetg(l,t_POL);521gel(Q,l-1) = gen_1;522if (l != 3)523{524long i = l-1;525GEN h = gel(P,i), hi = h;526i--; gel(Q,i) = gel(P,i);527if (l != 4) { i--; gel(Q,i) = mulii(gel(P,i), h); }528for (i--; i>=2; i--) { hi = mulii(hi,h); gel(Q,i) = mulii(gel(P,i), hi); }529}530Q[1] = P[1]; return Q;531}532533/*Eval x in 2^(k*BIL) in linear time*/534static GEN535ZX_eval2BILspec(GEN x, long k, long nx)536{537pari_sp av = avma;538long i,j, lz = k*nx, ki;539GEN pz = cgetipos(2+lz);540GEN nz = cgetipos(2+lz);541for(i=0; i < lz; i++)542{543*int_W(pz,i) = 0UL;544*int_W(nz,i) = 0UL;545}546for(i=0, ki=0; i<nx; i++, ki+=k)547{548GEN c = gel(x,i);549long lc = lgefint(c)-2;550if (signe(c)==0) continue;551if (signe(c) > 0)552for (j=0; j<lc; j++) *int_W(pz,j+ki) = *int_W(c,j);553else554for (j=0; j<lc; j++) *int_W(nz,j+ki) = *int_W(c,j);555}556pz = int_normalize(pz,0);557nz = int_normalize(nz,0); return gerepileuptoint(av, subii(pz,nz));558}559560static long561ZX_expispec(GEN x, long nx)562{563long i, m = 0;564for(i = 0; i < nx; i++)565{566long e = expi(gel(x,i));567if (e > m) m = e;568}569return m;570}571572static GEN573Z_mod2BIL_ZX(GEN x, long bs, long d, long vx)574{575long i, offset, lm = lgefint(x)-2, l = d+vx+3, sx = signe(x);576GEN s1 = int2n(bs*BITS_IN_LONG), pol = cgetg(l, t_POL);577int carry = 0;578pol[1] = evalsigne(1);579for (i=0; i<vx; i++) gel(pol,i+2) = gen_0;580for (offset=0; i <= d+vx; i++, offset += bs)581{582pari_sp av = avma;583long lz = minss(bs, lm-offset);584GEN z = lz > 0 ?adduispec_offset(carry, x, offset, lz): utoi(carry);585if (lgefint(z) == 3+bs) { carry = 1; z = gen_0;}586else587{588carry = (lgefint(z) == 2+bs && (HIGHBIT & *int_W(z,bs-1)));589if (carry)590z = gerepileuptoint(av, (sx==-1)? subii(s1,z): subii(z,s1));591else if (sx==-1) togglesign(z);592}593gel(pol,i+2) = z;594}595return ZX_renormalize(pol,l);596}597598static GEN599ZX_sqrspec_sqri(GEN x, long nx, long ex, long v)600{601long e = 2*ex + expu(nx) + 3;602long N = divsBIL(e)+1;603GEN z = sqri(ZX_eval2BILspec(x,N,nx));604return Z_mod2BIL_ZX(z, N, nx*2-2, v);605}606607static GEN608ZX_mulspec_mulii(GEN x, GEN y, long nx, long ny, long ex, long ey, long v)609{610long e = ex + ey + expu(minss(nx,ny)) + 3;611long N = divsBIL(e)+1;612GEN z = mulii(ZX_eval2BILspec(x,N,nx), ZX_eval2BILspec(y,N,ny));613return Z_mod2BIL_ZX(z, N, nx+ny-2, v);614}615616INLINE GEN617ZX_sqrspec_basecase_limb(GEN x, long a, long i)618{619pari_sp av = avma;620GEN s = gen_0;621long j, l = (i+1)>>1;622for (j=a; j<l; j++)623{624GEN xj = gel(x,j), xx = gel(x,i-j);625if (signe(xj) && signe(xx))626s = addii(s, mulii(xj, xx));627}628s = shifti(s,1);629if ((i&1) == 0)630{631GEN t = gel(x, i>>1);632if (signe(t))633s = addii(s, sqri(t));634}635return gerepileuptoint(av,s);636}637638static GEN639ZX_sqrspec_basecase(GEN x, long nx, long v)640{641long i, lz, nz;642GEN z;643644lz = (nx << 1) + 1; nz = lz-2;645lz += v;646z = cgetg(lz,t_POL); z[1] = evalsigne(1); z += 2;647for (i=0; i<v; i++) gel(z++, 0) = gen_0;648for (i=0; i<nx; i++)649gel(z,i) = ZX_sqrspec_basecase_limb(x, 0, i);650for ( ; i<nz; i++) gel(z,i) = ZX_sqrspec_basecase_limb(x, i-nx+1, i);651z -= v+2; return z;652}653654static GEN655Z_sqrshiftspec_ZX(GEN x, long vx)656{657long i, nz = 2*vx+1;658GEN z = cgetg(2+nz, t_POL);659z[1] = evalsigne(1);660for(i=2;i<nz+1;i++) gel(z,i) = gen_0;661gel(z,nz+1) = sqri(x);662return z;663}664665static GEN666Z_ZX_mulshiftspec(GEN x, GEN y, long ny, long vz)667{668long i, nz = vz+ny;669GEN z = cgetg(2+nz, t_POL);670z[1] = evalsigne(1);671for (i=0; i<vz; i++) gel(z,i+2) = gen_0;672for (i=0; i<ny; i++) gel(z,i+vz+2) = mulii(x, gel(y,i));673return z;674}675676GEN677ZX_sqrspec(GEN x, long nx)678{679#ifdef PARI_KERNEL_GMP680const long low[]={ 17, 32, 96, 112, 160, 128, 128, 160, 160, 160, 160, 160, 176, 192, 192, 192, 192, 192, 224, 224, 224, 240, 240, 240, 272, 288, 288, 240, 288, 304, 304, 304, 304, 304, 304, 352, 352, 368, 352, 352, 352, 368, 368, 432, 432, 496, 432, 496, 496};681const long high[]={ 102860, 70254, 52783, 27086, 24623, 18500, 15289, 13899, 12635, 11487, 10442, 9493, 8630, 7845, 7132, 7132, 6484, 6484, 5894, 5894, 4428, 4428, 3660, 4428, 3660, 3660, 2749, 2499, 2272, 2066, 1282, 1282, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 963, 963, 724, 658, 658, 658, 528, 528, 528, 528};682#else683const long low[]={ 17, 17, 32, 32, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 128, 112, 112, 112, 112, 112, 128, 128, 160, 160, 112, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 176, 160, 160, 176, 160, 160, 176, 176, 208, 176, 176, 176, 192, 192, 176, 176, 224, 176, 224, 224, 176, 224, 224, 224, 176, 176, 176, 176, 176, 176, 176, 176, 224, 176, 176, 224, 224, 224, 224, 224, 224, 224, 240, 288, 240, 288, 288, 240, 288, 288, 240, 240, 304, 304};684const long high[]={ 165657, 85008, 52783, 43622, 32774, 27086, 22385, 15289, 13899, 12635, 11487, 10442, 9493, 7845, 6484, 6484, 5894, 5894, 4871, 4871, 4428, 4026, 3660, 3660, 3660, 3327, 3327, 3024, 2749, 2749, 2272, 2749, 2499, 2499, 2272, 1878, 1878, 1878, 1707, 1552, 1552, 1552, 1552, 1552, 1411, 1411, 1411, 1282, 1282, 1282, 1282, 1282, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1060, 1060, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 876, 876, 876, 876, 796, 658, 724, 658, 724, 658, 658, 658, 658, 658, 658, 658, 658, 658, 658, 658, 658, 336, 658, 658, 592, 336, 336};685#endif686const long nblow = numberof(low);687pari_sp av;688long ex, vx;689GEN z;690if (!nx) return pol_0(0);691vx = ZX_valspec(x,nx); nx-=vx; x+=vx;692if (nx==1) return Z_sqrshiftspec_ZX(gel(x, 0), vx);693av = avma;694ex = ZX_expispec(x,nx);695if (nx-2 < nblow && low[nx-2]<=ex && ex<=high[nx-2])696z = ZX_sqrspec_basecase(x, nx, 2*vx);697else698z = ZX_sqrspec_sqri(x, nx, ex, 2*vx);699return gerepileupto(av, z);700}701702GEN703ZX_sqr(GEN x)704{705GEN z = ZX_sqrspec(x+2, lgpol(x));706z[1] = x[1];707return z;708}709710GEN711ZX_mulspec(GEN x, GEN y, long nx, long ny)712{713pari_sp av;714long ex, ey, vx, vy, v;715if (!nx || !ny) return pol_0(0);716vx = ZX_valspec(x,nx); nx-=vx; x += vx;717vy = ZX_valspec(y,ny); ny-=vy; y += vy;718v = vx + vy;719if (nx==1) return Z_ZX_mulshiftspec(gel(x,0), y, ny, v);720if (ny==1) return Z_ZX_mulshiftspec(gel(y,0), x, nx, v);721if (nx == 2 && ny == 2)722{723GEN a0 = gel(x,0), a1 = gel(x,1), A0, A1, A2;724GEN b0 = gel(y,0), b1 = gel(y,1), z = cgetg(5 + v, t_POL);725long i;726z[1] = evalvarn(0) | evalsigne(1);727A0 = mulii(a0, b0);728A2 = mulii(a1, b1); av = avma;729A1 = gerepileuptoint(av, subii(addii(A0,A2),730mulii(subii(a1,a0), subii(b1,b0))));731i = 4 + v;732gel(z,i--) = A2;733gel(z,i--) = A1;734gel(z,i--) = A0; while (i > 1) gel(z, i--) = gen_0;735return z;736}737#if 0738/* generically slower even when degrees differ a lot; sometimes about twice739* faster when bitsize is moderate */740if (DEBUGVAR)741return RgX_mulspec(x - vx, y - vy, nx + vx, ny + vy);742#endif743av = avma;744ex = ZX_expispec(x, nx);745ey = ZX_expispec(y, ny);746return gerepileupto(av, ZX_mulspec_mulii(x,y,nx,ny,ex,ey,v));747}748GEN749ZX_mul(GEN x, GEN y)750{751GEN z;752if (x == y) return ZX_sqr(x);753z = ZX_mulspec(x+2,y+2,lgpol(x),lgpol(y));754z[1] = x[1];755if (!signe(y)) z[1] &= VARNBITS;756return z;757}758759/* x,y two ZX in the same variable; assume y is monic */760GEN761ZX_rem(GEN x, GEN y)762{763long vx, dx, dy, dz, i, j, sx, lr;764pari_sp av0, av;765GEN z,p1,rem;766767vx = varn(x);768dy = degpol(y);769dx = degpol(x);770if (dx < dy) return ZX_copy(x);771if (!dy) return pol_0(vx); /* y is constant */772av0 = avma; dz = dx-dy;773z=cgetg(dz+3,t_POL); z[1] = x[1];774x += 2; y += 2; z += 2;775776p1 = gel(x,dx);777gel(z,dz) = icopy(p1);778for (i=dx-1; i>=dy; i--)779{780av=avma; p1=gel(x,i);781for (j=i-dy+1; j<=i && j<=dz; j++)782p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));783gel(z,i-dy) = avma == av? icopy(p1): gerepileuptoint(av, p1);784}785rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);786for (sx=0; ; i--)787{788p1 = gel(x,i);789for (j=0; j<=i && j<=dz; j++)790p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));791if (signe(p1)) { sx = 1; break; }792if (!i) break;793set_avma(av);794}795lr=i+3; rem -= lr;796rem[0] = evaltyp(t_POL) | evallg(lr);797rem[1] = z[-1];798p1 = gerepileuptoint((pari_sp)rem, p1);799rem += 2; gel(rem,i) = p1;800for (i--; i>=0; i--)801{802av=avma; p1 = gel(x,i);803for (j=0; j<=i && j<=dz; j++)804p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));805gel(rem,i) = avma == av? icopy(p1): gerepileuptoint(av, p1);806}807rem -= 2;808if (!sx) (void)ZX_renormalize(rem, lr);809return gerepileupto(av0,rem);810}811812/* return x(1) */813GEN814ZX_eval1(GEN x)815{816pari_sp av = avma;817long i = lg(x)-1;818GEN s;819if (i < 2) return gen_0;820s = gel(x,i); i--;821if (i == 1) return icopy(s);822for ( ; i>=2; i--)823{824GEN c = gel(x,i);825if (signe(c)) s = addii(s, c);826}827return gerepileuptoint(av,s);828}829830/* reduce T mod X^n - 1. Shallow function */831GEN832ZX_mod_Xnm1(GEN T, ulong n)833{834long i, j, L = lg(T), l = n+2;835GEN S;836if (L <= l) return T;837S = cgetg(l, t_POL);838S[1] = T[1];839for (i = 2; i < l; i++) gel(S,i) = gel(T,i);840for (j = 2; i < L; i++) {841gel(S,j) = addii(gel(S,j), gel(T,i));842if (++j == l) j = 2;843}844return normalizepol_lg(S, l);845}846847/*******************************************************************/848/* */849/* ZXV */850/* */851/*******************************************************************/852853int854ZXV_equal(GEN V, GEN W)855{856long l = lg(V);857if (l!=lg(W)) return 0;858while (--l > 0)859if (!ZX_equal(gel(V,l), gel(W,l))) return 0;860return 1;861}862863GEN864ZXV_Z_mul(GEN x, GEN y)865{ pari_APPLY_same(ZX_Z_mul(gel(x,i), y)) }866867GEN868ZXV_remi2n(GEN x, long N)869{ pari_APPLY_same(ZX_remi2n(gel(x,i), N)) }870871GEN872ZXV_dotproduct(GEN x, GEN y)873{874pari_sp av = avma;875long i, lx = lg(x);876GEN c;877if (lx == 1) return pol_0(varn(x));878c = ZX_mul(gel(x,1), gel(y,1));879for (i = 2; i < lx; i++)880{881GEN t = ZX_mul(gel(x,i), gel(y,i));882if (signe(t)) c = ZX_add(c, t);883}884return gerepileupto(av, c);885}886887GEN888ZXC_to_FlxC(GEN x, ulong p, long sv)889{ pari_APPLY_type(t_COL,typ(gel(x,i))==t_INT ?890Z_to_Flx(gel(x,i), p, sv): ZX_to_Flx(gel(x,i), p)) }891892GEN893ZXM_to_FlxM(GEN x, ulong p, long sv)894{ pari_APPLY_same(ZXC_to_FlxC(gel(x,i), p, sv)) }895896/*******************************************************************/897/* */898/* ZXQM */899/* */900/*******************************************************************/901902GEN903ZXn_mul(GEN x, GEN y, long n)904{ return RgXn_red_shallow(ZX_mul(x, y), n); }905906GEN907ZXn_sqr(GEN x, long n)908{ return RgXn_red_shallow(ZX_sqr(x), n); }909910/*******************************************************************/911/* */912/* ZXQM */913/* */914/*******************************************************************/915916static long917ZX_expi(GEN x)918{919if (signe(x)==0) return 0;920if (typ(x)==t_INT) return expi(x);921return ZX_expispec(x+2, lgpol(x));922}923924static long925ZXC_expi(GEN x)926{927long i, l = lg(x), m=0;928for(i = 1; i < l; i++)929{930long e = ZX_expi(gel(x,i));931if (e > m) m = e;932}933return m;934}935936static long937ZXM_expi(GEN x)938{939long i, l = lg(x), m=0;940for(i = 1; i < l; i++)941{942long e = ZXC_expi(gel(x,i));943if (e > m) m = e;944}945return m;946}947948static GEN949ZX_eval2BIL(GEN x, long k)950{951if (signe(x)==0) return gen_0;952if (typ(x)==t_INT) return x;953return ZX_eval2BILspec(x+2, k, lgpol(x));954}955956/*Eval x in 2^(k*BIL) in linear time*/957static GEN958ZXC_eval2BIL(GEN x, long k)959{960long i, lx = lg(x);961GEN A = cgetg(lx, t_COL);962for (i=1; i<lx; i++) gel(A,i) = ZX_eval2BIL(gel(x,i), k);963return A;964}965966static GEN967ZXM_eval2BIL(GEN x, long k)968{969long i, lx = lg(x);970GEN A = cgetg(lx, t_MAT);971for (i=1; i<lx; i++) gel(A,i) = ZXC_eval2BIL(gel(x,i), k);972return A;973}974975static GEN976Z_mod2BIL_ZXQ(GEN x, long bs, GEN T)977{978pari_sp av = avma;979long v = varn(T), d = 2*(degpol(T)-1);980GEN z = Z_mod2BIL_ZX(x, bs, d, 0);981setvarn(z, v);982return gerepileupto(av, ZX_rem(z, T));983}984985static GEN986ZC_mod2BIL_ZXQC(GEN x, long bs, GEN T)987{988long i, lx = lg(x);989GEN A = cgetg(lx, t_COL);990for (i=1; i<lx; i++) gel(A,i) = Z_mod2BIL_ZXQ(gel(x,i), bs, T);991return A;992}993994static GEN995ZM_mod2BIL_ZXQM(GEN x, long bs, GEN T)996{997long i, lx = lg(x);998GEN A = cgetg(lx, t_MAT);999for (i=1; i<lx; i++) gel(A,i) = ZC_mod2BIL_ZXQC(gel(x,i), bs, T);1000return A;1001}10021003GEN1004ZXQM_mul(GEN x, GEN y, GEN T)1005{1006long d = degpol(T);1007GEN z;1008pari_sp av = avma;1009if (d == 0)1010z = ZM_mul(simplify_shallow(x),simplify_shallow(y));1011else1012{1013long e, n, N, ex = ZXM_expi(x), ey = ZXM_expi(y);10141015if ((ey && ex > 64 * ey) || (ex && ey > 64 * ex)) return RgM_mul_i(x, y);1016n = lg(x)-1;1017e = ex + ey + expu(d) + expu(n) + 4;1018N = divsBIL(e)+1;1019z = ZM_mul(ZXM_eval2BIL(x,N), ZXM_eval2BIL(y,N));1020z = ZM_mod2BIL_ZXQM(z, N, T);1021}1022return gerepileupto(av, z);1023}10241025GEN1026ZXQM_sqr(GEN x, GEN T)1027{1028long d = degpol(T);1029GEN z;1030pari_sp av = avma;1031if (d == 0)1032z = ZM_sqr(simplify_shallow(x));1033else1034{1035long ex = ZXM_expi(x), d = degpol(T), n = lg(x)-1;1036long e = 2*ex + expu(d) + expu(n) + 4;1037long N = divsBIL(e)+1;1038z = ZM_sqr(ZXM_eval2BIL(x,N));1039z = ZM_mod2BIL_ZXQM(z, N, T);1040}1041return gerepileupto(av, z);1042}10431044GEN1045QXQM_mul(GEN x, GEN y, GEN T)1046{1047GEN dx, nx = Q_primitive_part(x, &dx);1048GEN dy, ny = Q_primitive_part(y, &dy);1049GEN z = ZXQM_mul(nx, ny, T);1050if (dx || dy)1051{1052GEN d = dx ? dy ? gmul(dx, dy): dx : dy;1053if (!gequal1(d)) z = RgM_Rg_mul(z, d);1054}1055return z;1056}10571058GEN1059QXQM_sqr(GEN x, GEN T)1060{1061GEN dx, nx = Q_primitive_part(x, &dx);1062GEN z = ZXQM_sqr(nx, T);1063if (dx) z = RgM_Rg_mul(z, gsqr(dx));1064return z;1065}10661067static GEN1068Z_mod2BIL_Fq(GEN x, long bs, GEN T, GEN p)1069{1070pari_sp av = avma;1071long v = get_FpX_var(T), d = 2*(get_FpX_degree(T)-1);1072GEN z = Z_mod2BIL_ZX(x, bs, d, 0);1073setvarn(z, v);1074return gerepileupto(av, FpX_rem(z, T, p));1075}10761077static GEN1078ZC_mod2BIL_FqC(GEN x, long bs, GEN T, GEN p)1079{1080long i, lx = lg(x);1081GEN A = cgetg(lx, t_COL);1082for (i=1; i<lx; i++) gel(A,i) = Z_mod2BIL_Fq(gel(x,i), bs, T, p);1083return A;1084}10851086static GEN1087ZM_mod2BIL_FqM(GEN x, long bs, GEN T, GEN p)1088{1089long i, lx = lg(x);1090GEN A = cgetg(lx, t_MAT);1091for (i=1; i<lx; i++) gel(A,i) = ZC_mod2BIL_FqC(gel(x,i), bs, T, p);1092return A;1093}10941095GEN1096FqM_mul_Kronecker(GEN x, GEN y, GEN T, GEN p)1097{1098pari_sp av = avma;1099long ex = ZXM_expi(x), ey = ZXM_expi(y), d= degpol(T), n = lg(x)-1;1100long e = ex + ey + expu(d) + expu(n) + 4;1101long N = divsBIL(e)+1;1102GEN z = ZM_mul(ZXM_eval2BIL(x,N), ZXM_eval2BIL(y,N));1103return gerepileupto(av, ZM_mod2BIL_FqM(z, N, T, p));1104}11051106/*******************************************************************/1107/* */1108/* ZXX */1109/* */1110/*******************************************************************/11111112void1113RgX_check_ZXX(GEN x, const char *s)1114{1115long k = lg(x)-1;1116for ( ; k>1; k--) {1117GEN t = gel(x,k);1118switch(typ(t)) {1119case t_INT: break;1120case t_POL: if (RgX_is_ZX(t)) break;1121/* fall through */1122default: pari_err_TYPE(stack_strcat(s, " not in Z[X,Y]"),x);1123}1124}1125}11261127/*Renormalize (in place) polynomial with t_INT or ZX coefficients.*/1128GEN1129ZXX_renormalize(GEN x, long lx)1130{1131long i;1132for (i = lx-1; i>1; i--)1133if (signe(gel(x,i))) break;1134stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + (i+1)));1135setlg(x, i+1); setsigne(x, i!=1); return x;1136}11371138GEN1139ZXX_evalx0(GEN y)1140{1141long i, l = lg(y);1142GEN z = cgetg(l,t_POL); z[1] = y[1];1143for(i=2; i<l; i++)1144{1145GEN yi = gel(y,i);1146gel(z,i) = typ(yi)==t_INT? yi: constant_coeff(yi);1147}1148return ZX_renormalize(z,l);1149}11501151long1152ZXX_max_lg(GEN x)1153{1154long i, prec = 0, lx = lg(x);1155for (i=2; i<lx; i++)1156{1157GEN p = gel(x,i);1158long l = (typ(p) == t_INT)? lgefint(p): ZX_max_lg(p);1159if (l > prec) prec = l;1160}1161return prec;1162}11631164GEN1165ZXX_Z_mul(GEN y, GEN x)1166{1167long i, l = lg(y);1168GEN z = cgetg(l,t_POL); z[1] = y[1];1169for(i=2; i<l; i++)1170if(typ(gel(y,i))==t_INT)1171gel(z,i) = mulii(gel(y,i),x);1172else1173gel(z,i) = ZX_Z_mul(gel(y,i),x);1174return z;1175}11761177GEN1178ZXX_Z_add_shallow(GEN x, GEN y)1179{1180long i, l = lg(x);1181GEN z, a;1182if (signe(x)==0) return scalarpol(y,varn(x));1183z = cgetg(l,t_POL); z[1] = x[1];1184a = gel(x,2);1185gel(z, 2) = typ(a)==t_INT? addii(a,y): ZX_Z_add(a,y);1186for(i=3; i<l; i++)1187gel(z,i) = gel(x,i);1188return z;1189}11901191GEN1192ZXX_Z_divexact(GEN y, GEN x)1193{1194long i, l = lg(y);1195GEN z = cgetg(l,t_POL); z[1] = y[1];1196for(i=2; i<l; i++)1197if(typ(gel(y,i))==t_INT)1198gel(z,i) = diviiexact(gel(y,i),x);1199else1200gel(z,i) = ZX_Z_divexact(gel(y,i),x);1201return z;1202}12031204/* Kronecker substitution, ZXX -> ZX:1205* P(X,Y) = sum_{0<=i<lP} P_i(X) * Y^i, where deg P_i < n.1206* Returns P(X,X^(2n-1)) */1207GEN1208RgXX_to_Kronecker_spec(GEN P, long lP, long n)1209{1210long i, k, N = (n<<1) + 1;1211GEN y;1212if (!lP) return pol_0(0);1213y = cgetg((N-2)*lP + 2, t_POL) + 2;1214for (k=i=0; i<lP; i++)1215{1216long j;1217GEN c = gel(P,i);1218if (typ(c)!=t_POL)1219{1220gel(y,k++) = c;1221j = 3;1222}1223else1224{1225long l = lg(c);1226if (l-3 >= n)1227pari_err_BUG("RgXX_to_Kronecker, P is not reduced mod Q");1228for (j=2; j < l; j++) gel(y,k++) = gel(c,j);1229}1230if (i == lP-1) break;1231for ( ; j < N; j++) gel(y,k++) = gen_0;1232}1233y-=2; setlg(y, k+2); y[1] = evalsigne(1); return y;1234}12351236/* shallow, n = deg(T) */1237GEN1238Kronecker_to_ZXX(GEN z, long n, long v)1239{1240long i,j,lx,l, N = (n<<1)+1;1241GEN x, t;1242l = lg(z); lx = (l-2) / (N-2);1243x = cgetg(lx+3,t_POL);1244x[1] = z[1];1245for (i=2; i<lx+2; i++)1246{1247t = cgetg(N,t_POL); t[1] = evalvarn(v);1248for (j=2; j<N; j++) gel(t,j) = gel(z,j);1249z += (N-2);1250gel(x,i) = ZX_renormalize(t,N);1251}1252N = (l-2) % (N-2) + 2;1253t = cgetg(N,t_POL); t[1] = evalvarn(v);1254for (j=2; j<N; j++) gel(t,j) = gel(z,j);1255gel(x,i) = ZX_renormalize(t,N);1256return ZXX_renormalize(x, i+1);1257}12581259GEN1260RgXX_to_Kronecker(GEN P, long n)1261{1262GEN z = RgXX_to_Kronecker_spec(P+2, lgpol(P), n);1263setvarn(z,varn(P)); return z;1264}1265GEN1266ZXX_mul_Kronecker(GEN x, GEN y, long n)1267{ return ZX_mul(RgXX_to_Kronecker(x,n), RgXX_to_Kronecker(y,n)); }12681269GEN1270ZXX_sqr_Kronecker(GEN x, long n)1271{ return ZX_sqr(RgXX_to_Kronecker(x,n)); }12721273/* shallow, n = deg(T) */1274GEN1275Kronecker_to_ZXQX(GEN z, GEN T)1276{1277long i,j,lx,l, N = (degpol(T)<<1)+1;1278GEN x, t;1279l = lg(z); lx = (l-2) / (N-2);1280x = cgetg(lx+3,t_POL);1281x[1] = z[1];1282for (i=2; i<lx+2; i++)1283{1284t = cgetg(N,t_POL); t[1] = T[1];1285for (j=2; j<N; j++) gel(t,j) = gel(z,j);1286z += (N-2);1287gel(x,i) = ZX_rem(ZX_renormalize(t,N), T);1288}1289N = (l-2) % (N-2) + 2;1290t = cgetg(N,t_POL); t[1] = T[1];1291for (j=2; j<N; j++) gel(t,j) = gel(z,j);1292gel(x,i) = ZX_rem(ZX_renormalize(t,N), T);1293return ZXX_renormalize(x, i+1);1294}12951296GEN1297ZXQX_sqr(GEN x, GEN T)1298{1299pari_sp av = avma;1300long n = degpol(T);1301GEN z = ZXX_sqr_Kronecker(x, n);1302z = Kronecker_to_ZXQX(z, T);1303return gerepilecopy(av, z);1304}13051306GEN1307ZXQX_mul(GEN x, GEN y, GEN T)1308{1309pari_sp av = avma;1310long n = degpol(T);1311GEN z = ZXX_mul_Kronecker(x, y, n);1312z = Kronecker_to_ZXQX(z, T);1313return gerepilecopy(av, z);1314}13151316GEN1317ZXQX_ZXQ_mul(GEN P, GEN U, GEN T)1318{1319long i, lP;1320GEN res;1321res = cgetg_copy(P, &lP); res[1] = P[1];1322for(i=2; i<lP; i++)1323gel(res,i) = typ(gel(P,i))==t_POL? ZXQ_mul(U, gel(P,i), T)1324: gmul(U, gel(P,i));1325return ZXX_renormalize(res,lP);1326}13271328GEN1329QX_mul(GEN x, GEN y)1330{1331GEN dx, nx = Q_primitive_part(x, &dx);1332GEN dy, ny = Q_primitive_part(y, &dy);1333GEN z = ZX_mul(nx, ny);1334if (dx || dy)1335{1336GEN d = dx ? dy ? gmul(dx, dy): dx : dy;1337return ZX_Q_mul(z, d);1338} else1339return z;1340}13411342GEN1343QX_sqr(GEN x)1344{1345GEN dx, nx = Q_primitive_part(x, &dx);1346GEN z = ZX_sqr(nx);1347if (dx)1348return ZX_Q_mul(z, gsqr(dx));1349else1350return z;1351}13521353GEN1354QX_ZX_rem(GEN x, GEN y)1355{1356pari_sp av = avma;1357GEN d, nx = Q_primitive_part(x, &d);1358GEN r = ZX_rem(nx, y);1359if (d) r = ZX_Q_mul(r, d);1360return gerepileupto(av, r);1361}13621363GEN1364QXQX_mul(GEN x, GEN y, GEN T)1365{1366GEN dx, nx = Q_primitive_part(x, &dx);1367GEN dy, ny = Q_primitive_part(y, &dy);1368GEN z = ZXQX_mul(nx, ny, T);1369if (dx || dy)1370{1371GEN d = dx ? dy ? gmul(dx, dy): dx : dy;1372return ZXX_Q_mul(z, d);1373} else1374return z;1375}13761377GEN1378QXQX_sqr(GEN x, GEN T)1379{1380GEN dx, nx = Q_primitive_part(x, &dx);1381GEN z = ZXQX_sqr(nx, T);1382if (dx)1383return ZXX_Q_mul(z, gsqr(dx));1384else1385return z;1386}13871388GEN1389QXQX_powers(GEN P, long n, GEN T)1390{1391GEN v = cgetg(n+2, t_VEC);1392long i;1393gel(v, 1) = pol_1(varn(T));1394if (n==0) return v;1395gel(v, 2) = gcopy(P);1396for (i = 2; i <= n; i++) gel(v,i+1) = QXQX_mul(P, gel(v,i), T);1397return v;1398}13991400GEN1401QXQX_QXQ_mul(GEN P, GEN U, GEN T)1402{1403long i, lP;1404GEN res;1405res = cgetg_copy(P, &lP); res[1] = P[1];1406for(i=2; i<lP; i++)1407gel(res,i) = typ(gel(P,i))==t_POL? QXQ_mul(U, gel(P,i), T)1408: gmul(U, gel(P,i));1409return ZXX_renormalize(res,lP);1410}141114121413