Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 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/** SPECIAL POLYNOMIALS **/20/** **/21/*******************************************************************/22/* Tchebichev polynomial: T0=1; T1=X; T(n)=2*X*T(n-1)-T(n-2)23* T(n) = (n/2) sum_{k=0}^{n/2} a_k x^(n-2k)24* where a_k = (-1)^k 2^(n-2k) (n-k-1)! / k!(n-2k)! is an integer25* and a_0 = 2^(n-1), a_k / a_{k-1} = - (n-2k+2)(n-2k+1) / 4k(n-k) */26GEN27polchebyshev1(long n, long v) /* Assume 4*n < LONG_MAX */28{29long k, l;30pari_sp av;31GEN q,a,r;3233if (v<0) v = 0;34/* polchebyshev(-n,1) = polchebyshev(n,1) */35if (n < 0) n = -n;36if (n==0) return pol_1(v);37if (n==1) return pol_x(v);3839q = cgetg(n+3, t_POL); r = q + n+2;40a = int2n(n-1);41gel(r--,0) = a;42gel(r--,0) = gen_0;43for (k=1,l=n; l>1; k++,l-=2)44{45av = avma;46a = diviuuexact(muluui(l, l-1, a), 4*k, n-k);47togglesign(a); a = gerepileuptoint(av, a);48gel(r--,0) = a;49gel(r--,0) = gen_0;50}51q[1] = evalsigne(1) | evalvarn(v);52return q;53}54static void55polchebyshev1_eval_aux(long n, GEN x, GEN *pt1, GEN *pt2)56{57GEN t1, t2, b;58if (n == 1) { *pt1 = gen_1; *pt2 = x; return; }59if (n == 0) { *pt1 = x; *pt2 = gen_1; return; }60polchebyshev1_eval_aux((n+1) >> 1, x, &t1, &t2);61b = gsub(gmul(gmul2n(t1,1), t2), x);62if (odd(n)) { *pt1 = gadd(gmul2n(gsqr(t1), 1), gen_m1); *pt2 = b; }63else { *pt1 = b; *pt2 = gadd(gmul2n(gsqr(t2), 1), gen_m1); }64}65static GEN66polchebyshev1_eval(long n, GEN x)67{68GEN t1, t2;69long i, v;70pari_sp av;7172if (n < 0) n = -n;73if (n==0) return gen_1;74if (n==1) return gcopy(x);75av = avma;76v = u_lvalrem(n, 2, (ulong*)&n);77polchebyshev1_eval_aux((n+1)>>1, x, &t1, &t2);78if (n != 1) t2 = gsub(gmul(gmul2n(t1,1), t2), x);79for (i = 1; i <= v; i++) t2 = gadd(gmul2n(gsqr(t2), 1), gen_m1);80return gerepileupto(av, t2);81}8283/* Chebychev polynomial of the second kind U(n,x): the coefficient in front of84* x^(n-2*m) is (-1)^m * 2^(n-2m)*(n-m)!/m!/(n-2m)! for m=0,1,...,n/2 */85GEN86polchebyshev2(long n, long v)87{88pari_sp av;89GEN q, a, r;90long m;91int neg = 0;9293if (v<0) v = 0;94/* polchebyshev(-n,2) = -polchebyshev(n-2,2) */95if (n < 0) {96if (n == -1) return zeropol(v);97neg = 1; n = -n-2;98}99if (n==0) return neg ? scalar_ZX_shallow(gen_m1, v): pol_1(v);100101q = cgetg(n+3, t_POL); r = q + n+2;102a = int2n(n);103if (neg) togglesign(a);104gel(r--,0) = a;105gel(r--,0) = gen_0;106for (m=1; 2*m<= n; m++)107{108av = avma;109a = diviuuexact(muluui(n-2*m+2, n-2*m+1, a), 4*m, n-m+1);110togglesign(a); a = gerepileuptoint(av, a);111gel(r--,0) = a;112gel(r--,0) = gen_0;113}114q[1] = evalsigne(1) | evalvarn(v);115return q;116}117static void118polchebyshev2_eval_aux(long n, GEN x, GEN *pu1, GEN *pu2)119{120GEN u1, u2, u, mu1;121if (n == 1) { *pu1 = gen_1; *pu2 = gmul2n(x,1); return; }122if (n == 0) { *pu1 = gen_0; *pu2 = gen_1; return; }123polchebyshev2_eval_aux(n >> 1, x, &u1, &u2);124mu1 = gneg(u1);125u = gmul(gadd(u2,u1), gadd(u2,mu1));126if (odd(n)) { *pu1 = u; *pu2 = gmul(gmul2n(u2,1), gadd(gmul(x,u2), mu1)); }127else { *pu2 = u; *pu1 = gmul(gmul2n(u1,1), gadd(u2, gmul(x,mu1))); }128}129static GEN130polchebyshev2_eval(long n, GEN x)131{132GEN u1, u2, mu1;133long neg = 0;134pari_sp av;135136if (n < 0) {137if (n == -1) return gen_0;138neg = 1; n = -n-2;139}140if (n==0) return neg ? gen_m1: gen_1;141av = avma;142polchebyshev2_eval_aux(n>>1, x, &u1, &u2);143mu1 = gneg(u1);144if (odd(n)) u2 = gmul(gmul2n(u2,1), gadd(gmul(x,u2), mu1));145else u2 = gmul(gadd(u2,u1), gadd(u2,mu1));146if (neg) u2 = gneg(u2);147return gerepileupto(av, u2);148}149150GEN151polchebyshev(long n, long kind, long v)152{153switch (kind)154{155case 1: return polchebyshev1(n, v);156case 2: return polchebyshev2(n, v);157default: pari_err_FLAG("polchebyshev");158}159return NULL; /* LCOV_EXCL_LINE */160}161GEN162polchebyshev_eval(long n, long kind, GEN x)163{164if (!x) return polchebyshev(n, kind, 0);165if (gequalX(x)) return polchebyshev(n, kind, varn(x));166switch (kind)167{168case 1: return polchebyshev1_eval(n, x);169case 2: return polchebyshev2_eval(n, x);170default: pari_err_FLAG("polchebyshev");171}172return NULL; /* LCOV_EXCL_LINE */173}174175/* Hermite polynomial H(n,x): H(n+1) = 2x H(n) - 2n H(n-1)176* The coefficient in front of x^(n-2*m) is177* (-1)^m * n! * 2^(n-2m)/m!/(n-2m)! for m=0,1,...,n/2.. */178GEN179polhermite(long n, long v)180{181long m;182pari_sp av;183GEN q,a,r;184185if (v<0) v = 0;186if (n==0) return pol_1(v);187188q = cgetg(n+3, t_POL); r = q + n+2;189a = int2n(n);190gel(r--,0) = a;191gel(r--,0) = gen_0;192for (m=1; 2*m<= n; m++)193{194av = avma;195a = diviuexact(muluui(n-2*m+2, n-2*m+1, a), 4*m);196togglesign(a);197gel(r--,0) = a = gerepileuptoint(av, a);198gel(r--,0) = gen_0;199}200q[1] = evalsigne(1) | evalvarn(v);201return q;202}203static void204err_hermite(long n)205{ pari_err_DOMAIN("polhermite", "degree", "<", gen_0, stoi(n)); }206GEN207polhermite_eval0(long n, GEN x, long flag)208{209long i;210pari_sp av, av2;211GEN x2, u, v;212213if (n < 0) err_hermite(n);214if (!x || gequalX(x))215{216long v = x? varn(x): 0;217if (flag)218{219if (!n) err_hermite(-1);220retmkvec2(polhermite(n-1,v),polhermite(n,v));221}222return polhermite(n, v);223}224if (n==0)225{226if (flag) err_hermite(-1);227return gen_1;228}229if (n==1)230{231if (flag) retmkvec2(gen_1, gmul2n(x,1));232return gmul2n(x,1);233}234av = avma; x2 = gmul2n(x,1); v = gen_1; u = x2;235av2= avma;236for (i=1; i<n; i++)237{ /* u = H_i(x), v = H_{i-1}(x), compute t = H_{i+1}(x) */238GEN t;239if ((i & 0xff) == 0) gerepileall(av2,2,&u, &v);240t = gsub(gmul(x2, u), gmulsg(2*i,v));241v = u; u = t;242}243if (flag) return gerepilecopy(av, mkvec2(v, u));244return gerepileupto(av, u);245}246GEN247polhermite_eval(long n, GEN x) { return polhermite_eval0(n, x, 0); }248249/* Legendre polynomial250* L0=1; L1=X; (n+1)*L(n+1)=(2*n+1)*X*L(n)-n*L(n-1)251* L(n) = 2^-n sum_{k=0}^{n/2} a_k x^(n-2k)252* where a_k = (-1)^k (2n-2k)! / k! (n-k)! (n-2k)! is an integer253* and a_0 = binom(2n,n), a_k / a_{k-1} = - (n-2k+1)(n-2k+2) / 2k (2n-2k+1) */254GEN255pollegendre(long n, long v)256{257long k, l;258pari_sp av;259GEN a, r, q;260261if (v<0) v = 0;262/* pollegendre(-n) = pollegendre(n-1) */263if (n < 0) n = -n-1;264if (n==0) return pol_1(v);265if (n==1) return pol_x(v);266267av = avma;268q = cgetg(n+3, t_POL); r = q + n+2;269gel(r--,0) = a = binomialuu(n<<1,n);270gel(r--,0) = gen_0;271for (k=1,l=n; l>1; k++,l-=2)272{ /* l = n-2*k+2 */273av = avma;274a = diviuuexact(muluui(l, l-1, a), 2*k, n+l-1);275togglesign(a); a = gerepileuptoint(av, a);276gel(r--,0) = a;277gel(r--,0) = gen_0;278}279q[1] = evalsigne(1) | evalvarn(v);280return gerepileupto(av, gmul2n(q,-n));281}282/* q such that Ln * 2^n = q(x^2) [n even] or x q(x^2) [n odd] */283GEN284pollegendre_reduced(long n, long v)285{286long k, l, N;287pari_sp av;288GEN a, r, q;289290if (v<0) v = 0;291/* pollegendre(-n) = pollegendre(n-1) */292if (n < 0) n = -n-1;293if (n<=1) return n? scalarpol_shallow(gen_2,v): pol_1(v);294295N = n >> 1;296q = cgetg(N+3, t_POL); r = q + N+2;297gel(r--,0) = a = binomialuu(n<<1,n);298for (k=1,l=n; l>1; k++,l-=2)299{ /* l = n-2*k+2 */300av = avma;301a = diviuuexact(muluui(l, l-1, a), 2*k, n+l-1);302togglesign(a);303gel(r--,0) = a = gerepileuptoint(av, a);304}305q[1] = evalsigne(1) | evalvarn(v);306return q;307}308309GEN310pollegendre_eval0(long n, GEN x, long flag)311{312pari_sp av;313GEN u, v;314long i;315316if (n < 0) n = -n-1; /* L(-n) = L(n-1) */317/* n >= 0 */318if (flag && flag != 1) pari_err_FLAG("pollegendre");319if (!x || gequalX(x))320{321long v = x? varn(x): 0;322if (flag) retmkvec2(pollegendre(n-1,v), pollegendre(n,v));323return pollegendre(n, v);324}325if (n==0)326{327if (flag) retmkvec2(gen_1, gcopy(x));328return gen_1;329}330if (n==1)331{332if (flag) retmkvec2(gcopy(x), gen_1);333return gcopy(x);334}335av = avma; v = gen_1; u = x;336for (i=1; i<n; i++)337{ /* u = P_i(x), v = P_{i-1}(x), compute t = P_{i+1}(x) */338GEN t;339if ((i & 0xff) == 0) gerepileall(av,2,&u, &v);340t = gdivgs(gsub(gmul(gmulsg(2*i+1,x), u), gmulsg(i,v)), i+1);341v = u; u = t;342}343if (flag) return gerepilecopy(av, mkvec2(v, u));344return gerepileupto(av, u);345}346GEN347pollegendre_eval(long n, GEN x) { return pollegendre_eval0(n, x, 0); }348349/* Laguerre polynomial350* L0^a = 1; L1^a = -X+a+1;351* (n+1)*L^a(n+1) = (-X+(2*n+a+1))*L^a(n) - (n+a)*L^a(n-1)352* L^a(n) = sum_{k=0}^n (-1)^k * binom(n+a,n-k) * x^k/k! */353GEN354pollaguerre(long n, GEN a, long v)355{356pari_sp av = avma;357GEN L = cgetg(n+3, t_POL), c1 = gen_1, c2 = mpfact(n);358long i;359360L[1] = evalsigne(1) | evalvarn(v);361if (odd(n)) togglesign_safe(&c2);362for (i = n; i >= 0; i--)363{364gel(L, i+2) = gdiv(c1, c2);365if (i)366{367c2 = divis(c2,-i);368c1 = gdivgs(gmul(c1, gaddsg(i,a)), n+1-i);369}370}371return gerepilecopy(av, L);372}373static void374err_lag(long n)375{ pari_err_DOMAIN("pollaguerre", "degree", "<", gen_0, stoi(n)); }376GEN377pollaguerre_eval0(long n, GEN a, GEN x, long flag)378{379pari_sp av = avma;380long i;381GEN v, u;382383if (n < 0) err_lag(n);384if (flag && flag != 1) pari_err_FLAG("pollaguerre");385if (!a) a = gen_0;386if (!x || gequalX(x))387{388long v = x? varn(x): 0;389if (flag)390{391if (!n) err_lag(-1);392retmkvec2(pollaguerre(n-1,a,v), pollaguerre(n,a,v));393}394return pollaguerre(n,a,v);395}396if (n==0)397{398if (flag) err_lag(-1);399return gen_1;400}401if (n==1)402{403if (flag) retmkvec2(gsub(gaddgs(a,1),x), gen_1);404return gsub(gaddgs(a,1),x);405}406av = avma; v = gen_1; u = gsub(gaddgs(a,1),x);407for (i=1; i<n; i++)408{ /* u = P_i(x), v = P_{i-1}(x), compute t = P_{i+1}(x) */409GEN t;410if ((i & 0xff) == 0) gerepileall(av,2,&u, &v);411t = gdivgs(gsub(gmul(gsub(gaddsg(2*i+1,a),x), u), gmul(gaddsg(i,a),v)), i+1);412v = u; u = t;413}414if (flag) return gerepilecopy(av, mkvec2(v, u));415return gerepileupto(av, u);416}417GEN418pollaguerre_eval(long n, GEN x, GEN a) { return pollaguerre_eval0(n, x, a, 0); }419420/* polcyclo(p) = X^(p-1) + ... + 1 */421static GEN422polcyclo_prime(long p, long v)423{424GEN T = cgetg(p+2, t_POL);425long i;426T[1] = evalsigne(1) | evalvarn(v);427for (i = 2; i < p+2; i++) gel(T,i) = gen_1;428return T;429}430431/* cyclotomic polynomial */432GEN433polcyclo(long n, long v)434{435long s, q, i, l;436pari_sp av=avma;437GEN T, P;438439if (v<0) v = 0;440if (n < 3)441switch(n)442{443case 1: return deg1pol_shallow(gen_1, gen_m1, v);444case 2: return deg1pol_shallow(gen_1, gen_1, v);445default: pari_err_DOMAIN("polcyclo", "index", "<=", gen_0, stoi(n));446}447P = gel(factoru(n), 1); l = lg(P);448s = P[1]; T = polcyclo_prime(s, v);449for (i = 2; i < l; i++)450{ /* Phi_{np}(X) = Phi_n(X^p) / Phi_n(X) */451s *= P[i];452T = RgX_div(RgX_inflate(T, P[i]), T);453}454/* s = squarefree part of n */455q = n / s;456if (q == 1) return gerepileupto(av, T);457return gerepilecopy(av, RgX_inflate(T,q));458}459460/* cyclotomic polynomial */461GEN462polcyclo_eval(long n, GEN x)463{464pari_sp av= avma;465GEN P, md, xd, yneg, ypos;466long l, s, i, j, q, tx;467long root_of_1 = 0;468469if (!x) return polcyclo(n, 0);470tx = typ(x);471if (gequalX(x)) return polcyclo(n, varn(x));472if (n <= 0) pari_err_DOMAIN("polcyclo", "index", "<=", gen_0, stoi(n));473if (n == 1) return gsubgs(x, 1);474if (tx == t_INT && !signe(x)) return gen_1;475while ((n & 3) == 0) { n >>= 1; x = gsqr(x); } /* Phi_4n(x) = Phi_2n(x^2) */476/* n not divisible by 4 */477if (n == 2) return gerepileupto(av, gaddgs(x,1));478if (!odd(n)) { n >>= 1; x = gneg(x); } /* Phi_2n(x) = Phi_n(-x) for n>1 odd */479/* n odd > 2. s largest squarefree divisor of n */480P = gel(factoru(n), 1); s = zv_prod(P);481/* replace n by largest squarefree divisor */482q = n/s; if (q != 1) { x = gpowgs(x, q); n = s; }483l = lg(P)-1;484/* n squarefree odd > 2, l distinct prime divisors. Now handle x = 1 or -1 */485if (tx == t_INT) { /* shortcut */486if (is_pm1(x))487{488set_avma(av);489if (signe(x) > 0 && l == 1) return utoipos(P[1]);490return gen_1;491}492} else {493if (gequal1(x))494{ /* n is prime, return n; multiply by x to keep the type */495if (l == 1) return gerepileupto(av, gmulgs(x,n));496return gerepilecopy(av, x); /* else 1 */497}498if (gequalm1(x)) return gerepileupto(av, gneg(x)); /* -1 */499}500/* Heuristic: evaluation will probably not improve things */501if (tx == t_POL || tx == t_MAT || lg(x) > n)502return gerepileupto(av, poleval(polcyclo(n,0), x));503504xd = cgetg((1L<<l) + 1, t_VEC); /* the x^d, where d | n */505md = cgetg((1L<<l) + 1, t_VECSMALL); /* the mu(d), where d | n */506gel(xd, 1) = x;507md[1] = 1;508/* Use Phi_n(x) = Prod_{d|n} (x^d-1)^mu(n/d).509* If x has exact order D, n = Dq, then the result is 0 if q = 1. Otherwise510* the factors with x^d-1, D|d are omitted and we multiply at the end by511* prod_{d | q} d^mu(q/d) = q if prime, 1 otherwise */512/* We store the factors with mu(d)= 1 (resp.-1) in ypos (resp yneg).513* At the end we return ypos/yneg if mu(n)=1 and yneg/ypos if mu(n)=-1 */514ypos = gsubgs(x,1);515yneg = gen_1;516for (i = 1; i <= l; i++)517{518long ti = 1L<<(i-1), p = P[i];519for (j = 1; j <= ti; j++) {520GEN X = gpowgs(gel(xd,j), p), t = gsubgs(X,1);521gel(xd,ti+j) = X;522md[ti+j] = -md[j];523if (gequal0(t))524{ /* x^d = 1; root_of_1 := the smallest index ti+j such that X == 1525* (whose bits code d: bit i-1 is set iff P[i] | d). If no such index526* exists, then root_of_1 remains 0. Do not multiply with X-1 if X = 1,527* we handle these factors at the end */528if (!root_of_1) root_of_1 = ti+j;529}530else531{532if (md[ti+j] == 1) ypos = gmul(ypos, t);533else yneg = gmul(yneg, t);534}535}536}537ypos = odd(l)? gdiv(yneg,ypos): gdiv(ypos,yneg);538if (root_of_1)539{540GEN X = gel(xd,(1<<l)); /* = x^n = 1 */541long bitmask_q = (1<<l) - root_of_1;542/* bitmask_q encodes q = n/d: bit (i-1) is 1 iff P[i] | q */543544/* x is a root of unity. If bitmask_q = 0, then x was a primitive n-th545* root of 1 and the result is zero. Return X - 1 to preserve type. */546if (!bitmask_q) return gerepileupto(av, gsubgs(X, 1));547/* x is a primitive d-th root of unity, where d|n and d<n: we548* must multiply ypos by if(isprime(n/d), n/d, 1) */549ypos = gmul(ypos, X); /* multiply by X = 1 to preserve type */550/* If bitmask_q = 1<<(i-1) for some i <= l, then q == P[i] and we multiply551* by P[i]; otherwise q is composite and nothing more needs to be done */552if (!(bitmask_q & (bitmask_q-1))) /* detects power of 2, since bitmask!=0 */553{554i = vals(bitmask_q)+1; /* q = P[i] */555ypos = gmulgs(ypos, P[i]);556}557}558return gerepileupto(av, ypos);559}560/********************************************************************/561/** **/562/** HILBERT & PASCAL MATRICES **/563/** **/564/********************************************************************/565GEN566mathilbert(long n) /* Hilbert matrix of order n */567{568long i,j;569GEN p;570571if (n < 0) pari_err_DOMAIN("mathilbert", "dimension", "<", gen_0, stoi(n));572p = cgetg(n+1,t_MAT);573for (j=1; j<=n; j++)574{575gel(p,j) = cgetg(n+1,t_COL);576for (i=1+(j==1); i<=n; i++)577gcoeff(p,i,j) = mkfrac(gen_1, utoipos(i+j-1));578}579if (n) gcoeff(p,1,1) = gen_1;580return p;581}582583/* q-Pascal triangle = (choose(i,j)_q) (ordinary binomial if q = NULL) */584GEN585matqpascal(long n, GEN q)586{587long i, j, I;588pari_sp av = avma;589GEN m, qpow = NULL; /* gcc -Wall */590591if (n < -1) pari_err_DOMAIN("matpascal", "n", "<", gen_m1, stoi(n));592n++; m = cgetg(n+1,t_MAT);593for (j=1; j<=n; j++) gel(m,j) = cgetg(n+1,t_COL);594if (q)595{596I = (n+1)/2;597if (I > 1) { qpow = new_chunk(I+1); gel(qpow,2)=q; }598for (j=3; j<=I; j++) gel(qpow,j) = gmul(q, gel(qpow,j-1));599}600for (i=1; i<=n; i++)601{602I = (i+1)/2; gcoeff(m,i,1)= gen_1;603if (q)604{605for (j=2; j<=I; j++)606gcoeff(m,i,j) = gadd(gmul(gel(qpow,j),gcoeff(m,i-1,j)),607gcoeff(m,i-1,j-1));608}609else610{611for (j=2; j<=I; j++)612gcoeff(m,i,j) = addii(gcoeff(m,i-1,j), gcoeff(m,i-1,j-1));613}614for ( ; j<=i; j++) gcoeff(m,i,j) = gcoeff(m,i,i+1-j);615for ( ; j<=n; j++) gcoeff(m,i,j) = gen_0;616}617return gerepilecopy(av, m);618}619620GEN621eulerianpol(long N, long v)622{623pari_sp av = avma;624long n, n2, k = 0;625GEN A;626if (v < 0) v = 0;627if (N <= 0) pari_err_DOMAIN("eulerianpol", "index", "<=", gen_0, stoi(N));628if (N == 1) return pol_1(v);629if (N == 2) return deg1pol_shallow(gen_1, gen_1, v);630A = cgetg(N+1, t_VEC);631gel(A,1) = gen_1; gel(A,2) = gen_1; /* A_2 = x+1 */632for (n = 3; n <= N; n++)633{ /* A(n,k) = (n-k)A(n-1,k-1) + (k+1)A(n-1,k) */634n2 = n >> 1;635if (odd(n)) gel(A,n2+1) = mului(n+1, gel(A,n2));636for (k = n2-1; k; k--)637gel(A,k+1) = addii(mului(n-k, gel(A,k)), mului(k+1, gel(A,k+1)));638if (gc_needed(av,1))639{640if (DEBUGMEM>1) pari_warn(warnmem,"eulerianpol, %ld/%ld",n,N);641for (k = odd(n)? n2+1: n2; k < N; k++) gel(A,k+1) = gen_0;642A = gerepilecopy(av, A);643}644}645k = N >> 1; if (odd(N)) k++;646for (; k < N; k++) gel(A,k+1) = gel(A, N-k);647return gerepilecopy(av, RgV_to_RgX(A, v));648}649650/******************************************************************/651/** **/652/** PRECISION CHANGES **/653/** **/654/******************************************************************/655656GEN657gprec(GEN x, long d)658{659pari_sp av = avma;660if (d <= 0) pari_err_DOMAIN("gprec", "precision", "<=", gen_0, stoi(d));661return gerepilecopy(av, gprec_w(x, ndec2prec(d)));662}663664/* not GC-safe; precision given in word length (including codewords) */665GEN666gprec_w(GEN x, long pr)667{668long lx, i;669GEN y;670671switch(typ(x))672{673case t_REAL:674if (signe(x)) return realprec(x) != pr? rtor(x,pr): x;675i = -prec2nbits(pr);676if (i < expo(x)) return real_0_bit(i);677y = cgetr(2); y[1] = x[1]; return y;678case t_COMPLEX:679y = cgetg(3, t_COMPLEX);680gel(y,1) = gprec_w(gel(x,1),pr);681gel(y,2) = gprec_w(gel(x,2),pr);682break;683case t_POL: case t_SER:684y = cgetg_copy(x, &lx); y[1] = x[1];685for (i=2; i<lx; i++) gel(y,i) = gprec_w(gel(x,i),pr);686break;687case t_POLMOD: case t_RFRAC: case t_VEC: case t_COL: case t_MAT:688y = cgetg_copy(x, &lx);689for (i=1; i<lx; i++) gel(y,i) = gprec_w(gel(x,i),pr);690break;691default: return x;692}693return y;694}695/* not GC-safe; precision given in word length (including codewords) */696GEN697gprec_wensure(GEN x, long pr)698{699long lx, i;700GEN y;701702switch(typ(x))703{704case t_REAL:705if (signe(x)) return realprec(x) < pr? rtor(x,pr): x;706i = -prec2nbits(pr);707if (i < expo(x)) return real_0_bit(i);708y = cgetr(2); y[1] = x[1]; return y;709case t_COMPLEX:710y = cgetg(3, t_COMPLEX);711gel(y,1) = gprec_wensure(gel(x,1),pr);712gel(y,2) = gprec_wensure(gel(x,2),pr);713break;714case t_POL: case t_SER:715y = cgetg_copy(x, &lx); y[1] = x[1];716for (i=2; i<lx; i++) gel(y,i) = gprec_wensure(gel(x,i),pr);717break;718case t_POLMOD: case t_RFRAC: case t_VEC: case t_COL: case t_MAT:719y = cgetg_copy(x, &lx);720for (i=1; i<lx; i++) gel(y,i) = gprec_wensure(gel(x,i),pr);721break;722default: return x;723}724return y;725}726727/* not GC-safe; precision given in word length (including codewords),728* truncate mantissa to precision 'pr' but never increase it */729GEN730gprec_wtrunc(GEN x, long pr)731{732long lx, i;733GEN y;734735switch(typ(x))736{737case t_REAL:738return (signe(x) && realprec(x) > pr)? rtor(x,pr): x;739case t_COMPLEX:740y = cgetg(3, t_COMPLEX);741gel(y,1) = gprec_wtrunc(gel(x,1),pr);742gel(y,2) = gprec_wtrunc(gel(x,2),pr);743break;744case t_POL:745case t_SER:746y = cgetg_copy(x, &lx); y[1] = x[1];747for (i=2; i<lx; i++) gel(y,i) = gprec_wtrunc(gel(x,i),pr);748break;749case t_POLMOD: case t_RFRAC: case t_VEC: case t_COL: case t_MAT:750y = cgetg_copy(x, &lx);751for (i=1; i<lx; i++) gel(y,i) = gprec_wtrunc(gel(x,i),pr);752break;753default: return x;754}755return y;756}757758/********************************************************************/759/** **/760/** SERIES TRANSFORMS **/761/** **/762/********************************************************************/763/** LAPLACE TRANSFORM (OF A SERIES) **/764/********************************************************************/765static GEN766serlaplace(GEN x)767{768long i, l = lg(x), e = valp(x);769GEN t, y = cgetg(l,t_SER);770if (e < 0) pari_err_DOMAIN("laplace","valuation","<",gen_0,stoi(e));771t = mpfact(e); y[1] = x[1];772for (i=2; i<l; i++)773{774gel(y,i) = gmul(t, gel(x,i));775e++; t = mului(e,t);776}777return y;778}779static GEN780pollaplace(GEN x)781{782long i, e = 0, l = lg(x);783GEN t = gen_1, y = cgetg(l,t_POL);784y[1] = x[1];785for (i=2; i<l; i++)786{787gel(y,i) = gmul(t, gel(x,i));788e++; t = mului(e,t);789}790return y;791}792GEN793laplace(GEN x)794{795pari_sp av = avma;796switch(typ(x))797{798case t_POL: x = pollaplace(x); break;799case t_SER: x = serlaplace(x); break;800default: if (is_scalar_t(typ(x))) return gcopy(x);801pari_err_TYPE("laplace",x);802}803return gerepilecopy(av, x);804}805806/********************************************************************/807/** CONVOLUTION PRODUCT (OF TWO SERIES) **/808/********************************************************************/809GEN810convol(GEN x, GEN y)811{812long j, lx, ly, ex, ey, vx = varn(x);813GEN z;814815if (typ(x) != t_SER) pari_err_TYPE("convol",x);816if (typ(y) != t_SER) pari_err_TYPE("convol",y);817if (varn(y) != vx) pari_err_VAR("convol", x,y);818ex = valp(x);819ey = valp(y);820if (ser_isexactzero(x))821return scalarser(gadd(Rg_get_0(x), Rg_get_0(y)), varn(x), maxss(ex,ey));822lx = lg(x) + ex; x -= ex;823ly = lg(y) + ey; y -= ey;824/* inputs shifted: x[i] and y[i] now correspond to monomials of same degree */825if (ly < lx) lx = ly; /* min length */826if (ex < ey) ex = ey; /* max valuation */827if (lx - ex < 3) return zeroser(vx, lx-2);828829z = cgetg(lx - ex, t_SER);830z[1] = evalvalp(ex) | evalvarn(vx);831for (j = ex+2; j<lx; j++) gel(z,j-ex) = gmul(gel(x,j),gel(y,j));832return normalize(z);833}834835/***********************************************************************/836/* OPERATIONS ON DIRICHLET SERIES: *, / */837/* (+, -, scalar multiplication are done on the corresponding vectors) */838/***********************************************************************/839static long840dirval(GEN x)841{842long i = 1, lx = lg(x);843while (i < lx && gequal0(gel(x,i))) i++;844return i;845}846847GEN848dirmul(GEN x, GEN y)849{850pari_sp av = avma, av2;851long nx, ny, nz, dx, dy, i, j, k;852GEN z;853854if (typ(x)!=t_VEC) pari_err_TYPE("dirmul",x);855if (typ(y)!=t_VEC) pari_err_TYPE("dirmul",y);856dx = dirval(x); nx = lg(x)-1;857dy = dirval(y); ny = lg(y)-1;858if (ny-dy < nx-dx) { swap(x,y); lswap(nx,ny); lswap(dx,dy); }859nz = minss(nx*dy,ny*dx);860y = RgV_kill0(y);861av2 = avma;862z = zerovec(nz);863for (j=dx; j<=nx; j++)864{865GEN c = gel(x,j);866if (gequal0(c)) continue;867if (gequal1(c))868{869for (k=dy,i=j*dy; i<=nz; i+=j,k++)870if (gel(y,k)) gel(z,i) = gadd(gel(z,i),gel(y,k));871}872else if (gequalm1(c))873{874for (k=dy,i=j*dy; i<=nz; i+=j,k++)875if (gel(y,k)) gel(z,i) = gsub(gel(z,i),gel(y,k));876}877else878{879for (k=dy,i=j*dy; i<=nz; i+=j,k++)880if (gel(y,k)) gel(z,i) = gadd(gel(z,i),gmul(c,gel(y,k)));881}882if (gc_needed(av2,3))883{884if (DEBUGMEM>1) pari_warn(warnmem,"dirmul, %ld/%ld",j,nx);885z = gerepilecopy(av2,z);886}887}888return gerepilecopy(av,z);889}890891GEN892dirdiv(GEN x, GEN y)893{894pari_sp av = avma, av2;895long nx,ny,nz, dx,dy, i,j,k;896GEN p1;897898if (typ(x)!=t_VEC) pari_err_TYPE("dirdiv",x);899if (typ(y)!=t_VEC) pari_err_TYPE("dirdiv",y);900dx = dirval(x); nx = lg(x)-1;901dy = dirval(y); ny = lg(y)-1;902if (dy != 1 || !ny) pari_err_INV("dirdiv",y);903nz = minss(nx,ny*dx);904p1 = gel(y,1);905if (gequal1(p1)) p1 = NULL; else y = gdiv(y,p1);906y = RgV_kill0(y);907av2 = avma;908x = p1 ? gdiv(x,p1): leafcopy(x);909for (j=1; j<dx; j++) gel(x,j) = gen_0;910setlg(x,nz+1);911for (j=dx; j<=nz; j++)912{913GEN c = gel(x,j);914if (gequal0(c)) continue;915if (gequal1(c))916{917for (i=j+j,k=2; i<=nz; i+=j,k++)918if (gel(y,k)) gel(x,i) = gsub(gel(x,i),gel(y,k));919}920else if (gequalm1(c))921{922for (i=j+j,k=2; i<=nz; i+=j,k++)923if (gel(y,k)) gel(x,i) = gadd(gel(x,i),gel(y,k));924}925else926{927for (i=j+j,k=2; i<=nz; i+=j,k++)928if (gel(y,k)) gel(x,i) = gsub(gel(x,i),gmul(c,gel(y,k)));929}930if (gc_needed(av2,3))931{932if (DEBUGMEM>1) pari_warn(warnmem,"dirdiv, %ld/%ld",j,nz);933x = gerepilecopy(av2,x);934}935}936return gerepilecopy(av,x);937}938939/*******************************************************************/940/** **/941/** COMBINATORICS **/942/** **/943/*******************************************************************/944/** BINOMIAL COEFFICIENTS **/945/*******************************************************************/946GEN947binomialuu(ulong n, ulong k)948{949pari_sp ltop = avma;950GEN z;951if (k > n) return gen_0;952k = minuu(k,n-k);953if (!k) return gen_1;954if (k == 1) return utoipos(n);955z = diviiexact(mulu_interval(n-k+1, n), mulu_interval(2UL, k));956return gerepileuptoint(ltop,z);957}958959GEN960binomial(GEN n, long k)961{962long i, prec;963pari_sp av;964GEN y;965966if (k <= 1)967{968if (is_noncalc_t(typ(n))) pari_err_TYPE("binomial",n);969if (k < 0) return gen_0;970if (k == 0) return gen_1;971return gcopy(n);972}973av = avma;974if (typ(n) == t_INT)975{976if (signe(n) > 0)977{978GEN z = subiu(n,k);979if (cmpis(z,k) < 0)980{981k = itos(z); set_avma(av);982if (k <= 1)983{984if (k < 0) return gen_0;985if (k == 0) return gen_1;986return icopy(n);987}988}989}990/* k > 1 */991if (lgefint(n) == 3 && signe(n) > 0)992{993y = binomialuu(itou(n),(ulong)k);994return gerepileupto(av, y);995}996else997{998y = cgetg(k+1,t_VEC);999for (i=1; i<=k; i++) gel(y,i) = subiu(n,i-1);1000y = ZV_prod(y);1001}1002y = diviiexact(y, mpfact(k));1003return gerepileuptoint(av, y);1004}10051006prec = precision(n);1007if (prec && k > 200 + 0.8*prec2nbits(prec)) {1008GEN A = mpfactr(k, prec), B = ggamma(gsubgs(n,k-1), prec);1009return gerepileupto(av, gdiv(ggamma(gaddgs(n,1), prec), gmul(A,B)));1010}10111012y = cgetg(k+1,t_VEC);1013for (i=1; i<=k; i++) gel(y,i) = gsubgs(n,i-1);1014return gerepileupto(av, gdiv(RgV_prod(y), mpfact(k)));1015}10161017GEN1018binomial0(GEN x, GEN k)1019{1020if (!k)1021{1022if (typ(x) != t_INT || signe(x) < 0) pari_err_TYPE("binomial", x);1023return vecbinomial(itos(x));1024}1025if (typ(k) != t_INT) pari_err_TYPE("binomial", k);1026return binomial(x, itos(k));1027}10281029/* Assume n >= 0, return bin, bin[k+1] = binomial(n, k) */1030GEN1031vecbinomial(long n)1032{1033long d, k;1034GEN C;1035if (!n) return mkvec(gen_1);1036C = cgetg(n+2, t_VEC) + 1; /* C[k] = binomial(n, k) */1037gel(C,0) = gen_1;1038gel(C,1) = utoipos(n); d = (n + 1) >> 1;1039for (k=2; k <= d; k++)1040{1041pari_sp av = avma;1042gel(C,k) = gerepileuptoint(av, diviuexact(mului(n-k+1, gel(C,k-1)), k));1043}1044for ( ; k <= n; k++) gel(C,k) = gel(C,n-k);1045return C - 1;1046}10471048/********************************************************************/1049/** STIRLING NUMBERS **/1050/********************************************************************/1051/* Stirling number of the 2nd kind. The number of ways of partitioning1052a set of n elements into m nonempty subsets. */1053GEN1054stirling2(ulong n, ulong m)1055{1056pari_sp av = avma;1057GEN s, bmk;1058ulong k;1059if (n==0) return (m == 0)? gen_1: gen_0;1060if (m > n || m == 0) return gen_0;1061if (m==n) return gen_1;1062/* k = 0 */1063bmk = gen_1; s = powuu(m, n);1064for (k = 1; k <= ((m-1)>>1); ++k)1065{ /* bmk = binomial(m, k) */1066GEN c, kn, mkn;1067bmk = diviuexact(mului(m-k+1, bmk), k);1068kn = powuu(k, n); mkn = powuu(m-k, n);1069c = odd(m)? subii(mkn,kn): addii(mkn,kn);1070c = mulii(bmk, c);1071s = odd(k)? subii(s, c): addii(s, c);1072if (gc_needed(av,2))1073{1074if(DEBUGMEM>1) pari_warn(warnmem,"stirling2");1075gerepileall(av, 2, &s, &bmk);1076}1077}1078/* k = m/2 */1079if (!odd(m))1080{1081GEN c;1082bmk = diviuexact(mului(k+1, bmk), k);1083c = mulii(bmk, powuu(k,n));1084s = odd(k)? subii(s, c): addii(s, c);1085}1086return gerepileuptoint(av, diviiexact(s, mpfact(m)));1087}10881089/* Stirling number of the first kind. Up to the sign, the number of1090permutations of n symbols which have exactly m cycles. */1091GEN1092stirling1(ulong n, ulong m)1093{1094pari_sp ltop=avma;1095ulong k;1096GEN s, t;1097if (n < m) return gen_0;1098else if (n==m) return gen_1;1099/* t = binomial(n-1+k, m-1) * binomial(2n-m, n-m-k) */1100/* k = n-m > 0 */1101t = binomialuu(2*n-m-1, m-1);1102s = mulii(t, stirling2(2*(n-m), n-m));1103if (odd(n-m)) togglesign(s);1104for (k = n-m-1; k > 0; --k)1105{1106GEN c;1107t = diviuuexact(muluui(n-m+k+1, n+k+1, t), n+k, n-m-k);1108c = mulii(t, stirling2(n-m+k, k));1109s = odd(k)? subii(s, c): addii(s, c);1110if ((k & 0x1f) == 0) {1111t = gerepileuptoint(ltop, t);1112s = gerepileuptoint(avma, s);1113}1114}1115return gerepileuptoint(ltop, s);1116}11171118GEN1119stirling(long n, long m, long flag)1120{1121if (n < 0) pari_err_DOMAIN("stirling", "n", "<", gen_0, stoi(n));1122if (m < 0) pari_err_DOMAIN("stirling", "m", "<", gen_0, stoi(m));1123switch (flag)1124{1125case 1: return stirling1((ulong)n,(ulong)m);1126case 2: return stirling2((ulong)n,(ulong)m);1127default: pari_err_FLAG("stirling");1128}1129return NULL; /*LCOV_EXCL_LINE*/1130}11311132/*******************************************************************/1133/** **/1134/** RECIPROCAL POLYNOMIAL **/1135/** **/1136/*******************************************************************/1137/* return coefficients s.t x = x_0 X^n + ... + x_n */1138GEN1139polrecip(GEN x)1140{1141long tx = typ(x);1142if (is_scalar_t(tx)) return gcopy(x);1143if (tx != t_POL) pari_err_TYPE("polrecip",x);1144return RgX_recip(x);1145}11461147/********************************************************************/1148/** **/1149/** POLYNOMIAL INTERPOLATION **/1150/** **/1151/********************************************************************/1152/* given complex roots L[i], i <= n of some monic T in C[X], return1153* the T'(L[i]), computed stably via products of differences */1154GEN1155vandermondeinverseinit(GEN L)1156{1157long i, j, l = lg(L);1158GEN V = cgetg(l, t_VEC);1159for (i = 1; i < l; i++)1160{1161pari_sp av = avma;1162GEN W = cgetg(l-1,t_VEC);1163long k = 1;1164for (j = 1; j < l; j++)1165if (i != j) gel(W, k++) = gsub(gel(L,i), gel(L,j));1166gel(V,i) = gerepileupto(av, RgV_prod(W));1167}1168return V;1169}11701171/* Compute the inverse of the van der Monde matrix of T multiplied by den */1172GEN1173vandermondeinverse(GEN L, GEN T, GEN den, GEN prep)1174{1175pari_sp av = avma;1176long i, n = lg(L)-1;1177GEN M = cgetg(n+1, t_MAT);11781179if (!prep) prep = vandermondeinverseinit(L);1180if (den && equali1(den)) den = NULL;1181for (i = 1; i <= n; i++)1182{1183GEN d = gel(prep,i);1184GEN P = RgX_Rg_mul(RgX_div_by_X_x(T, gel(L,i), NULL),1185den? gdiv(den,d): ginv(d));1186gel(M,i) = RgX_to_RgC(P,n);1187}1188return gerepilecopy(av, M);1189}11901191static GEN1192RgV_polint_fast(GEN X, GEN Y, long v)1193{1194GEN p, pol;1195long t, pa;1196if (X) t = RgV_type2(X,Y, &p, &pol, &pa);1197else t = Rg_type(Y, &p, &pol, &pa);1198if (t != t_INTMOD) return NULL;1199Y = RgC_to_FpC(Y, p);1200X = X? RgC_to_FpC(X, p): identity_ZV(lg(Y)-1);1201return FpX_to_mod(FpV_polint(X, Y, p, v), p);1202}1203/* allow X = NULL for [1,...,n] */1204GEN1205RgV_polint(GEN X, GEN Y, long v)1206{1207pari_sp av0 = avma, av;1208GEN Q, L, P = NULL;1209long i, l = lg(Y);1210if ((Q = RgV_polint_fast(X,Y,v))) return Q;1211if (!X) X = identity_ZV(l-1);1212L = vandermondeinverseinit(X);1213Q = roots_to_pol(X, v); av = avma;1214for (i=1; i<l; i++)1215{1216GEN T, dP;1217if (gequal0(gel(Y,i))) continue;1218T = RgX_div_by_X_x(Q, gel(X,i), NULL);1219dP = RgX_Rg_mul(T, gmul(gel(Y,i), ginv(gel(L,i))));1220P = P? RgX_add(P, dP): dP;1221if (gc_needed(av,2))1222{1223if (DEBUGMEM>1) pari_warn(warnmem,"RgV_polint i = %ld/%ld", i, l-1);1224P = gerepileupto(av, P);1225}1226}1227if (!P) { set_avma(av); return zeropol(v); }1228return gerepileupto(av0, P);1229}1230static int1231inC(GEN x)1232{1233switch(typ(x)) {1234case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: case t_QUAD: return 1;1235default: return 0;1236}1237}1238static long1239check_dy(GEN X, GEN x, long n)1240{1241GEN D = NULL;1242long i, ns = 0;1243if (!inC(x)) return -1;1244for (i = 0; i < n; i++)1245{1246GEN t = gsub(x, gel(X,i));1247if (!inC(t)) return -1;1248t = gabs(t, DEFAULTPREC);1249if (!D || gcmp(t,D) < 0) { ns = i; D = t; }1250}1251/* X[ns] is closest to x */1252return ns;1253}1254/* X,Y are "spec" GEN vectors with n > 0 components ( at X[0], ... X[n-1] ) */1255GEN1256polintspec(GEN X, GEN Y, GEN x, long n, long *pe)1257{1258long i, m, ns;1259pari_sp av = avma, av2;1260GEN y, c, d, dy = NULL; /* gcc -Wall */12611262if (pe) *pe = -HIGHEXPOBIT;1263if (n == 1) return gmul(gel(Y,0), Rg_get_1(x));1264if (!X) X = identity_ZV(n) + 1;1265av2 = avma;1266ns = check_dy(X, x, n); if (ns < 0) { pe = NULL; ns = 0; }1267c = cgetg(n+1, t_VEC);1268d = cgetg(n+1, t_VEC); for (i=0; i<n; i++) gel(c,i+1) = gel(d,i+1) = gel(Y,i);1269y = gel(d,ns+1);1270/* divided differences */1271for (m = 1; m < n; m++)1272{1273for (i = 0; i < n-m; i++)1274{1275GEN ho = gsub(gel(X,i),x), hp = gsub(gel(X,i+m),x), den = gsub(ho,hp);1276if (gequal0(den))1277{1278char *x1 = stack_sprintf("X[%ld]", i+1);1279char *x2 = stack_sprintf("X[%ld]", i+m+1);1280pari_err_DOMAIN("polinterpolate",x1,"=",strtoGENstr(x2), X);1281}1282den = gdiv(gsub(gel(c,i+2),gel(d,i+1)), den);1283gel(c,i+1) = gmul(ho,den);1284gel(d,i+1) = gmul(hp,den);1285}1286dy = (2*ns < n-m)? gel(c,ns+1): gel(d,ns--);1287y = gadd(y,dy);1288if (gc_needed(av2,2))1289{1290if (DEBUGMEM>1) pari_warn(warnmem,"polint, %ld/%ld",m,n-1);1291gerepileall(av2, 4, &y, &c, &d, &dy);1292}1293}1294if (pe && inC(dy)) *pe = gexpo(dy);1295return gerepileupto(av, y);1296}12971298GEN1299polint_i(GEN X, GEN Y, GEN t, long *pe)1300{1301long lx = lg(X), vt;13021303if (! is_vec_t(typ(X))) pari_err_TYPE("polinterpolate",X);1304if (Y)1305{1306if (! is_vec_t(typ(Y))) pari_err_TYPE("polinterpolate",Y);1307if (lx != lg(Y)) pari_err_DIM("polinterpolate");1308}1309else1310{1311Y = X;1312X = NULL;1313}1314if (pe) *pe = -HIGHEXPOBIT;1315vt = t? gvar(t): 0;1316if (vt != NO_VARIABLE)1317{ /* formal interpolation */1318pari_sp av;1319long v0, vY = gvar(Y);1320GEN P;1321if (X) vY = varnmax(vY, gvar(X));1322/* shortcut */1323if (varncmp(vY, vt) > 0 && (!t || gequalX(t))) return RgV_polint(X, Y, vt);1324av = avma;1325/* first interpolate in high priority variable, then substitute t */1326v0 = fetch_var_higher();1327P = RgV_polint(X, Y, v0);1328P = gsubst(P, v0, t? t: pol_x(0));1329(void)delete_var();1330return gerepileupto(av, P);1331}1332/* numerical interpolation */1333if (lx == 1) return Rg_get_0(t);1334return polintspec(X? X+1: NULL,Y+1,t,lx-1, pe);1335}1336GEN1337polint(GEN X, GEN Y, GEN t, GEN *pe)1338{1339long e;1340GEN p = polint_i(X, Y, t, &e);1341if (pe) *pe = stoi(e);1342return p;1343}13441345/********************************************************************/1346/** **/1347/** MODREVERSE **/1348/** **/1349/********************************************************************/1350static void1351err_reverse(GEN x, GEN T)1352{1353pari_err_DOMAIN("modreverse","deg(minpoly(z))", "<", stoi(degpol(T)),1354mkpolmod(x,T));1355}13561357/* return y such that Mod(y, charpoly(Mod(a,T)) = Mod(a,T) */1358GEN1359RgXQ_reverse(GEN a, GEN T)1360{1361pari_sp av = avma;1362long n = degpol(T);1363GEN y;13641365if (n <= 1) {1366if (n <= 0) return gcopy(a);1367return gerepileupto(av, gneg(gdiv(gel(T,2), gel(T,3))));1368}1369if (typ(a) != t_POL || !signe(a)) err_reverse(a,T);1370y = RgXV_to_RgM(RgXQ_powers(a,n-1,T), n);1371y = RgM_solve(y, col_ei(n, 2));1372if (!y) err_reverse(a,T);1373return gerepilecopy(av, RgV_to_RgX(y, varn(T)));1374}1375GEN1376QXQ_reverse(GEN a, GEN T)1377{1378pari_sp av = avma;1379long n = degpol(T);1380GEN y;13811382if (n <= 1) {1383if (n <= 0) return gcopy(a);1384return gerepileupto(av, gneg(gdiv(gel(T,2), gel(T,3))));1385}1386if (typ(a) != t_POL || !signe(a)) err_reverse(a,T);1387if (gequalX(a)) return gcopy(a);1388y = RgXV_to_RgM(QXQ_powers(a,n-1,T), n);1389y = QM_gauss(y, col_ei(n, 2));1390if (!y) err_reverse(a,T);1391return gerepilecopy(av, RgV_to_RgX(y, varn(T)));1392}13931394GEN1395modreverse(GEN x)1396{1397long v, n;1398GEN T, a;13991400if (typ(x)!=t_POLMOD) pari_err_TYPE("modreverse",x);1401T = gel(x,1); n = degpol(T); if (n <= 0) return gcopy(x);1402a = gel(x,2);1403v = varn(T);1404retmkpolmod(RgXQ_reverse(a, T),1405(n==1)? gsub(pol_x(v), a): RgXQ_charpoly(a, T, v));1406}14071408/********************************************************************/1409/** **/1410/** MERGESORT **/1411/** **/1412/********************************************************************/1413static int1414cmp_small(GEN x, GEN y) {1415long a = (long)x, b = (long)y;1416return a>b? 1: (a<b? -1: 0);1417}14181419static int1420veccmp(void *data, GEN x, GEN y)1421{1422GEN k = (GEN)data;1423long i, s, lk = lg(k), lx = minss(lg(x), lg(y));14241425if (!is_vec_t(typ(x))) pari_err_TYPE("lexicographic vecsort",x);1426if (!is_vec_t(typ(y))) pari_err_TYPE("lexicographic vecsort",y);1427for (i=1; i<lk; i++)1428{1429long c = k[i];1430if (c >= lx)1431pari_err_TYPE("lexicographic vecsort, index too large", stoi(c));1432s = lexcmp(gel(x,c), gel(y,c));1433if (s) return s;1434}1435return 0;1436}14371438/* return permutation sorting v[1..n], removing duplicates. Assume n > 0 */1439static GEN1440gen_sortspec_uniq(GEN v, long n, void *E, int (*cmp)(void*,GEN,GEN))1441{1442pari_sp av;1443long NX, nx, ny, m, ix, iy, i;1444GEN x, y, w, W;1445int s;1446switch(n)1447{1448case 1: return mkvecsmall(1);1449case 2:1450s = cmp(E,gel(v,1),gel(v,2));1451if (s < 0) return mkvecsmall2(1,2);1452else if (s > 0) return mkvecsmall2(2,1);1453return mkvecsmall(1);1454case 3:1455s = cmp(E,gel(v,1),gel(v,2));1456if (s < 0) {1457s = cmp(E,gel(v,2),gel(v,3));1458if (s < 0) return mkvecsmall3(1,2,3);1459else if (s == 0) return mkvecsmall2(1,2);1460s = cmp(E,gel(v,1),gel(v,3));1461if (s < 0) return mkvecsmall3(1,3,2);1462else if (s > 0) return mkvecsmall3(3,1,2);1463return mkvecsmall2(1,2);1464} else if (s > 0) {1465s = cmp(E,gel(v,1),gel(v,3));1466if (s < 0) return mkvecsmall3(2,1,3);1467else if (s == 0) return mkvecsmall2(2,1);1468s = cmp(E,gel(v,2),gel(v,3));1469if (s < 0) return mkvecsmall3(2,3,1);1470else if (s > 0) return mkvecsmall3(3,2,1);1471return mkvecsmall2(2,1);1472} else {1473s = cmp(E,gel(v,1),gel(v,3));1474if (s < 0) return mkvecsmall2(1,3);1475else if (s == 0) return mkvecsmall(1);1476return mkvecsmall2(3,1);1477}1478}1479NX = nx = n>>1; ny = n-nx;1480av = avma;1481x = gen_sortspec_uniq(v, nx,E,cmp); nx = lg(x)-1;1482y = gen_sortspec_uniq(v+NX,ny,E,cmp); ny = lg(y)-1;1483w = cgetg(n+1, t_VECSMALL);1484m = ix = iy = 1;1485while (ix<=nx && iy<=ny)1486{1487s = cmp(E, gel(v,x[ix]), gel(v,y[iy]+NX));1488if (s < 0)1489w[m++] = x[ix++];1490else if (s > 0)1491w[m++] = y[iy++]+NX;1492else {1493w[m++] = x[ix++];1494iy++;1495}1496}1497while (ix<=nx) w[m++] = x[ix++];1498while (iy<=ny) w[m++] = y[iy++]+NX;1499set_avma(av);1500W = cgetg(m, t_VECSMALL);1501for (i = 1; i < m; i++) W[i] = w[i];1502return W;1503}15041505/* return permutation sorting v[1..n]. Assume n > 0 */1506static GEN1507gen_sortspec(GEN v, long n, void *E, int (*cmp)(void*,GEN,GEN))1508{1509long nx, ny, m, ix, iy;1510GEN x, y, w;1511switch(n)1512{1513case 1:1514(void)cmp(E,gel(v,1),gel(v,1)); /* check for type error */1515return mkvecsmall(1);1516case 2:1517return cmp(E,gel(v,1),gel(v,2)) <= 0? mkvecsmall2(1,2)1518: mkvecsmall2(2,1);1519case 3:1520if (cmp(E,gel(v,1),gel(v,2)) <= 0) {1521if (cmp(E,gel(v,2),gel(v,3)) <= 0) return mkvecsmall3(1,2,3);1522return (cmp(E,gel(v,1),gel(v,3)) <= 0)? mkvecsmall3(1,3,2)1523: mkvecsmall3(3,1,2);1524} else {1525if (cmp(E,gel(v,1),gel(v,3)) <= 0) return mkvecsmall3(2,1,3);1526return (cmp(E,gel(v,2),gel(v,3)) <= 0)? mkvecsmall3(2,3,1)1527: mkvecsmall3(3,2,1);1528}1529}1530nx = n>>1; ny = n-nx;1531w = cgetg(n+1,t_VECSMALL);1532x = gen_sortspec(v, nx,E,cmp);1533y = gen_sortspec(v+nx,ny,E,cmp);1534m = ix = iy = 1;1535while (ix<=nx && iy<=ny)1536if (cmp(E, gel(v,x[ix]), gel(v,y[iy]+nx))<=0)1537w[m++] = x[ix++];1538else1539w[m++] = y[iy++]+nx;1540while (ix<=nx) w[m++] = x[ix++];1541while (iy<=ny) w[m++] = y[iy++]+nx;1542set_avma((pari_sp)w); return w;1543}15441545static void1546init_sort(GEN *x, long *tx, long *lx)1547{1548*tx = typ(*x);1549if (*tx == t_LIST)1550{1551if (list_typ(*x)!=t_LIST_RAW) pari_err_TYPE("sort",*x);1552*x = list_data(*x);1553*lx = *x? lg(*x): 1;1554} else {1555if (!is_matvec_t(*tx) && *tx != t_VECSMALL) pari_err_TYPE("gen_sort",*x);1556*lx = lg(*x);1557}1558}15591560/* (x o y)[1..lx-1], destroy y */1561INLINE GEN1562sort_extract(GEN x, GEN y, long tx, long lx)1563{1564long i;1565switch(tx)1566{1567case t_VECSMALL:1568for (i=1; i<lx; i++) y[i] = x[y[i]];1569break;1570case t_LIST:1571settyp(y,t_VEC);1572for (i=1; i<lx; i++) gel(y,i) = gel(x,y[i]);1573return gtolist(y);1574default:1575settyp(y,tx);1576for (i=1; i<lx; i++) gel(y,i) = gcopy(gel(x,y[i]));1577}1578return y;1579}15801581static GEN1582triv_sort(long tx) { return tx == t_LIST? mklist(): cgetg(1, tx); }1583/* Sort the vector x, using cmp to compare entries. */1584GEN1585gen_sort_uniq(GEN x, void *E, int (*cmp)(void*,GEN,GEN))1586{1587long tx, lx;1588GEN y;15891590init_sort(&x, &tx, &lx);1591if (lx==1) return triv_sort(tx);1592y = gen_sortspec_uniq(x,lx-1,E,cmp);1593return sort_extract(x, y, tx, lg(y)); /* lg(y) <= lx */1594}1595/* Sort the vector x, using cmp to compare entries. */1596GEN1597gen_sort(GEN x, void *E, int (*cmp)(void*,GEN,GEN))1598{1599long tx, lx;1600GEN y;16011602init_sort(&x, &tx, &lx);1603if (lx==1) return triv_sort(tx);1604y = gen_sortspec(x,lx-1,E,cmp);1605return sort_extract(x, y, tx, lx);1606}1607/* indirect sort: return the permutation that would sort x */1608GEN1609gen_indexsort_uniq(GEN x, void *E, int (*cmp)(void*,GEN,GEN))1610{1611long tx, lx;1612init_sort(&x, &tx, &lx);1613if (lx==1) return cgetg(1, t_VECSMALL);1614return gen_sortspec_uniq(x,lx-1,E,cmp);1615}1616/* indirect sort: return the permutation that would sort x */1617GEN1618gen_indexsort(GEN x, void *E, int (*cmp)(void*,GEN,GEN))1619{1620long tx, lx;1621init_sort(&x, &tx, &lx);1622if (lx==1) return cgetg(1, t_VECSMALL);1623return gen_sortspec(x,lx-1,E,cmp);1624}16251626/* Sort the vector x in place, using cmp to compare entries */1627void1628gen_sort_inplace(GEN x, void *E, int (*cmp)(void*,GEN,GEN), GEN *perm)1629{1630long tx, lx, i;1631pari_sp av = avma;1632GEN y;16331634init_sort(&x, &tx, &lx);1635if (lx<=2)1636{1637if (perm) *perm = lx == 1? cgetg(1, t_VECSMALL): mkvecsmall(1);1638return;1639}1640y = gen_sortspec(x,lx-1, E, cmp);1641if (perm)1642{1643GEN z = new_chunk(lx);1644for (i=1; i<lx; i++) gel(z,i) = gel(x,y[i]);1645for (i=1; i<lx; i++) gel(x,i) = gel(z,i);1646*perm = y;1647set_avma((pari_sp)y);1648} else {1649for (i=1; i<lx; i++) gel(y,i) = gel(x,y[i]);1650for (i=1; i<lx; i++) gel(x,i) = gel(y,i);1651set_avma(av);1652}1653}1654GEN1655gen_sort_shallow(GEN x, void *E, int (*cmp)(void*,GEN,GEN))1656{1657long tx, lx, i;1658pari_sp av;1659GEN y, z;16601661init_sort(&x, &tx, &lx);1662if (lx<=2) return x;1663z = cgetg(lx, tx); av = avma;1664y = gen_sortspec(x,lx-1, E, cmp);1665for (i=1; i<lx; i++) gel(z,i) = gel(x,y[i]);1666return gc_const(av, z);1667}16681669static int1670closurecmp(void *data, GEN x, GEN y)1671{1672pari_sp av = avma;1673long s = gsigne(closure_callgen2((GEN)data, x,y));1674set_avma(av); return s;1675}1676static void1677check_positive_entries(GEN k)1678{1679long i, l = lg(k);1680for (i=1; i<l; i++)1681if (k[i] <= 0) pari_err_DOMAIN("sort_function", "index", "<", gen_0, stoi(k[i]));1682}16831684typedef int (*CMP_FUN)(void*,GEN,GEN);1685/* return NULL if t_CLOSURE k is a "key" (arity 1) and not a sorting func */1686static CMP_FUN1687sort_function(void **E, GEN x, GEN k)1688{1689int (*cmp)(GEN,GEN) = &lexcmp;1690long tx = typ(x);1691if (!k)1692{1693*E = (void*)((typ(x) == t_VECSMALL)? cmp_small: cmp);1694return &cmp_nodata;1695}1696if (tx == t_VECSMALL) pari_err_TYPE("sort_function", x);1697switch(typ(k))1698{1699case t_INT: k = mkvecsmall(itos(k)); break;1700case t_VEC: case t_COL: k = ZV_to_zv(k); break;1701case t_VECSMALL: break;1702case t_CLOSURE:1703if (closure_is_variadic(k))1704pari_err_TYPE("sort_function, variadic cmpf",k);1705*E = (void*)k;1706switch(closure_arity(k))1707{1708case 1: return NULL; /* wrt key */1709case 2: return &closurecmp;1710default: pari_err_TYPE("sort_function, cmpf arity != 1, 2",k);1711}1712default: pari_err_TYPE("sort_function",k);1713}1714check_positive_entries(k);1715*E = (void*)k; return &veccmp;1716}17171718#define cmp_IND 11719#define cmp_LEX 2 /* FIXME: backward compatibility, ignored */1720#define cmp_REV 41721#define cmp_UNIQ 81722GEN1723vecsort0(GEN x, GEN k, long flag)1724{1725void *E;1726int (*CMP)(void*,GEN,GEN) = sort_function(&E, x, k);17271728if (flag < 0 || flag > (cmp_REV|cmp_LEX|cmp_IND|cmp_UNIQ))1729pari_err_FLAG("vecsort");1730if (!CMP)1731{ /* wrt key: precompute all values, O(n) calls instead of O(n log n) */1732pari_sp av = avma;1733GEN v, y;1734long i, tx, lx;1735init_sort(&x, &tx, &lx);1736if (lx == 1) return flag&cmp_IND? cgetg(1,t_VECSMALL): triv_sort(tx);1737v = cgetg(lx, t_VEC);1738for (i = 1; i < lx; i++) gel(v,i) = closure_callgen1(k, gel(x,i));1739y = vecsort0(v, NULL, flag | cmp_IND);1740y = flag&cmp_IND? y: sort_extract(x, y, tx, lg(y));1741return gerepileupto(av, y);1742}1743if (flag&cmp_UNIQ)1744x = flag&cmp_IND? gen_indexsort_uniq(x, E, CMP): gen_sort_uniq(x, E, CMP);1745else1746x = flag&cmp_IND? gen_indexsort(x, E, CMP): gen_sort(x, E, CMP);1747if (flag & cmp_REV)1748{ /* reverse order */1749GEN y = x;1750if (typ(x)==t_LIST) { y = list_data(x); if (!y) return x; }1751vecreverse_inplace(y);1752}1753return x;1754}17551756GEN1757indexsort(GEN x) { return gen_indexsort(x, (void*)&gcmp, cmp_nodata); }1758GEN1759indexlexsort(GEN x) { return gen_indexsort(x, (void*)&lexcmp, cmp_nodata); }1760GEN1761indexvecsort(GEN x, GEN k)1762{1763if (typ(k) != t_VECSMALL) pari_err_TYPE("vecsort",k);1764return gen_indexsort(x, (void*)k, &veccmp);1765}17661767GEN1768sort(GEN x) { return gen_sort(x, (void*)gcmp, cmp_nodata); }1769GEN1770lexsort(GEN x) { return gen_sort(x, (void*)lexcmp, cmp_nodata); }1771GEN1772vecsort(GEN x, GEN k)1773{1774if (typ(k) != t_VECSMALL) pari_err_TYPE("vecsort",k);1775return gen_sort(x, (void*)k, &veccmp);1776}1777/* adapted from gen_search; don't export: keys of T[i] should be precomputed */1778static long1779key_search(GEN T, GEN x, GEN code)1780{1781long u = lg(T)-1, i, l, s;17821783if (!u) return 0;1784l = 1; x = closure_callgen1(code, x);1785do1786{1787i = (l+u)>>1; s = lexcmp(x, closure_callgen1(code, gel(T,i)));1788if (!s) return i;1789if (s<0) u=i-1; else l=i+1;1790} while (u>=l);1791return 0;1792}1793long1794vecsearch(GEN v, GEN x, GEN k)1795{1796pari_sp av = avma;1797void *E;1798int (*CMP)(void*,GEN,GEN) = sort_function(&E, v, k);1799long r, tv = typ(v);1800if (tv == t_VECSMALL)1801x = (GEN)itos(x);1802else if (!is_matvec_t(tv)) pari_err_TYPE("vecsearch", v);1803r = CMP? gen_search(v, x, E, CMP): key_search(v, x, k);1804return gc_long(av, r < 0? 0: r);1805}18061807GEN1808ZV_indexsort(GEN L) { return gen_indexsort(L, (void*)&cmpii, &cmp_nodata); }1809GEN1810ZV_sort(GEN L) { return gen_sort(L, (void*)&cmpii, &cmp_nodata); }1811GEN1812ZV_sort_uniq(GEN L) { return gen_sort_uniq(L, (void*)&cmpii, &cmp_nodata); }1813void1814ZV_sort_inplace(GEN L) { gen_sort_inplace(L, (void*)&cmpii, &cmp_nodata,NULL); }18151816GEN1817vec_equiv(GEN F)1818{1819pari_sp av = avma;1820long j, k, L = lg(F);1821GEN w = cgetg(L, t_VEC);1822GEN perm = gen_indexsort(F, (void*)&cmp_universal, cmp_nodata);1823for (j = k = 1; j < L;)1824{1825GEN v = cgetg(L, t_VECSMALL);1826long l = 1, o = perm[j];1827v[l++] = o;1828for (j++; j < L; v[l++] = perm[j++])1829if (!gequal(gel(F,o), gel(F, perm[j]))) break;1830setlg(v, l); gel(w, k++) = v;1831}1832setlg(w, k); return gerepilecopy(av,w);1833}18341835GEN1836vec_reduce(GEN v, GEN *pE)1837{1838GEN E, F, P = gen_indexsort(v, (void*)cmp_universal, cmp_nodata);1839long i, m, l;1840F = cgetg_copy(v, &l);1841*pE = E = cgetg(l, t_VECSMALL);1842for (i = m = 1; i < l;)1843{1844GEN u = gel(v, P[i]);1845long k;1846for(k = i + 1; k < l; k++)1847if (cmp_universal(gel(v, P[k]), u)) break;1848E[m] = k - i; gel(F, m) = u; i = k; m++;1849}1850setlg(F, m);1851setlg(E, m); return F;1852}18531854/********************************************************************/1855/** SEARCH IN SORTED VECTOR **/1856/********************************************************************/1857/* index of x in table T, 0 otherwise */1858long1859tablesearch(GEN T, GEN x, int (*cmp)(GEN,GEN))1860{1861long l = 1, u = lg(T)-1, i, s;18621863while (u>=l)1864{1865i = (l+u)>>1; s = cmp(x, gel(T,i));1866if (!s) return i;1867if (s<0) u=i-1; else l=i+1;1868}1869return 0;1870}18711872/* looks if x belongs to the set T and returns the index if yes, 0 if no */1873long1874gen_search(GEN T, GEN x, void *data, int (*cmp)(void*,GEN,GEN))1875{1876long u = lg(T)-1, i, l, s;18771878if (!u) return -1;1879l = 1;1880do1881{1882i = (l+u) >> 1; s = cmp(data, x, gel(T,i));1883if (!s) return i;1884if (s < 0) u = i-1; else l = i+1;1885} while (u >= l);1886return -((s < 0)? i: i+1);1887}18881889long1890ZV_search(GEN x, GEN y) { return tablesearch(x, y, cmpii); }18911892long1893zv_search(GEN T, long x)1894{1895long l = 1, u = lg(T)-1;1896while (u>=l)1897{1898long i = (l+u)>>1;1899if (x < T[i]) u = i-1;1900else if (x > T[i]) l = i+1;1901else return i;1902}1903return 0;1904}19051906/********************************************************************/1907/** COMPARISON FUNCTIONS **/1908/********************************************************************/1909int1910cmp_nodata(void *data, GEN x, GEN y)1911{1912int (*cmp)(GEN,GEN)=(int (*)(GEN,GEN)) data;1913return cmp(x,y);1914}19151916/* assume x and y come from the same idealprimedec call (uniformizer unique) */1917int1918cmp_prime_over_p(GEN x, GEN y)1919{1920long k = pr_get_f(x) - pr_get_f(y); /* diff. between residue degree */1921return k? ((k > 0)? 1: -1)1922: ZV_cmp(pr_get_gen(x), pr_get_gen(y));1923}19241925int1926cmp_prime_ideal(GEN x, GEN y)1927{1928int k = cmpii(pr_get_p(x), pr_get_p(y));1929return k? k: cmp_prime_over_p(x,y);1930}19311932/* assume x and y are t_POL in the same variable whose coeffs can be1933* compared (used to sort polynomial factorizations) */1934int1935gen_cmp_RgX(void *data, GEN x, GEN y)1936{1937int (*coeff_cmp)(GEN,GEN)=(int(*)(GEN,GEN))data;1938long i, lx = lg(x), ly = lg(y);1939int fl;1940if (lx > ly) return 1;1941if (lx < ly) return -1;1942for (i=lx-1; i>1; i--)1943if ((fl = coeff_cmp(gel(x,i), gel(y,i)))) return fl;1944return 0;1945}19461947static int1948cmp_RgX_Rg(GEN x, GEN y)1949{1950long lx = lgpol(x), ly;1951if (lx > 1) return 1;1952ly = gequal0(y) ? 0:1;1953if (lx > ly) return 1;1954if (lx < ly) return -1;1955if (lx==0) return 0;1956return gcmp(gel(x,2), y);1957}1958int1959cmp_RgX(GEN x, GEN y)1960{1961if (typ(x) == t_POLMOD) x = gel(x,2);1962if (typ(y) == t_POLMOD) y = gel(y,2);1963if (typ(x) == t_POL) {1964if (typ(y) != t_POL) return cmp_RgX_Rg(x, y);1965} else {1966if (typ(y) != t_POL) return gcmp(x,y);1967return - cmp_RgX_Rg(y,x);1968}1969return gen_cmp_RgX((void*)&gcmp,x,y);1970}19711972int1973cmp_Flx(GEN x, GEN y)1974{1975long i, lx = lg(x), ly = lg(y);1976if (lx > ly) return 1;1977if (lx < ly) return -1;1978for (i=lx-1; i>1; i--)1979if (uel(x,i) != uel(y,i)) return uel(x,i)<uel(y,i)? -1: 1;1980return 0;1981}1982/********************************************************************/1983/** MERGE & SORT FACTORIZATIONS **/1984/********************************************************************/1985/* merge fx, fy two factorizations, whose 1st column is sorted in strictly1986* increasing order wrt cmp */1987GEN1988merge_factor(GEN fx, GEN fy, void *data, int (*cmp)(void *,GEN,GEN))1989{1990GEN x = gel(fx,1), e = gel(fx,2), M, E;1991GEN y = gel(fy,1), f = gel(fy,2);1992long ix, iy, m, lx = lg(x), ly = lg(y), l = lx+ly-1;19931994M = cgetg(l, t_COL);1995E = cgetg(l, t_COL);19961997m = ix = iy = 1;1998while (ix<lx && iy<ly)1999{2000int s = cmp(data, gel(x,ix), gel(y,iy));2001if (s < 0)2002{ gel(M,m) = gel(x,ix); gel(E,m) = gel(e,ix); ix++; }2003else if (s == 0)2004{2005GEN z = gel(x,ix), g = addii(gel(e,ix), gel(f,iy));2006iy++; ix++; if (!signe(g)) continue;2007gel(M,m) = z; gel(E,m) = g;2008}2009else2010{ gel(M,m) = gel(y,iy); gel(E,m) = gel(f,iy); iy++; }2011m++;2012}2013while (ix<lx) { gel(M,m) = gel(x,ix); gel(E,m) = gel(e,ix); ix++; m++; }2014while (iy<ly) { gel(M,m) = gel(y,iy); gel(E,m) = gel(f,iy); iy++; m++; }2015setlg(M, m);2016setlg(E, m); return mkmat2(M, E);2017}2018/* merge two sorted vectors, removing duplicates. Shallow */2019GEN2020merge_sort_uniq(GEN x, GEN y, void *data, int (*cmp)(void *,GEN,GEN))2021{2022long i, j, k, lx = lg(x), ly = lg(y);2023GEN z = cgetg(lx + ly - 1, typ(x));2024i = j = k = 1;2025while (i<lx && j<ly)2026{2027int s = cmp(data, gel(x,i), gel(y,j));2028if (s < 0)2029gel(z,k++) = gel(x,i++);2030else if (s > 0)2031gel(z,k++) = gel(y,j++);2032else2033{ gel(z,k++) = gel(x,i++); j++; }2034}2035while (i<lx) gel(z,k++) = gel(x,i++);2036while (j<ly) gel(z,k++) = gel(y,j++);2037setlg(z, k); return z;2038}2039/* in case of equal keys in x,y, take the key from x */2040static GEN2041ZV_union_shallow_t(GEN x, GEN y, long t)2042{2043long i, j, k, lx = lg(x), ly = lg(y);2044GEN z = cgetg(lx + ly - 1, t);2045i = j = k = 1;2046while (i<lx && j<ly)2047{2048int s = cmpii(gel(x,i), gel(y,j));2049if (s < 0)2050gel(z,k++) = gel(x,i++);2051else if (s > 0)2052gel(z,k++) = gel(y,j++);2053else2054{ gel(z,k++) = gel(x,i++); j++; }2055}2056while (i < lx) gel(z,k++) = gel(x,i++);2057while (j < ly) gel(z,k++) = gel(y,j++);2058setlg(z, k); return z;2059}2060GEN2061ZV_union_shallow(GEN x, GEN y)2062{ return ZV_union_shallow_t(x, y, t_VEC); }2063GEN2064ZC_union_shallow(GEN x, GEN y)2065{ return ZV_union_shallow_t(x, y, t_COL); }20662067/* sort generic factorization, in place */2068GEN2069sort_factor(GEN y, void *data, int (*cmp)(void *,GEN,GEN))2070{2071GEN a, b, A, B, w;2072pari_sp av;2073long n, i;20742075a = gel(y,1); n = lg(a); if (n == 1) return y;2076b = gel(y,2); av = avma;2077A = new_chunk(n);2078B = new_chunk(n);2079w = gen_sortspec(a, n-1, data, cmp);2080for (i=1; i<n; i++) { long k=w[i]; gel(A,i) = gel(a,k); gel(B,i) = gel(b,k); }2081for (i=1; i<n; i++) { gel(a,i) = gel(A,i); gel(b,i) = gel(B,i); }2082set_avma(av); return y;2083}2084/* sort polynomial factorization, in place */2085GEN2086sort_factor_pol(GEN y,int (*cmp)(GEN,GEN))2087{2088(void)sort_factor(y,(void*)cmp, &gen_cmp_RgX);2089return y;2090}20912092/***********************************************************************/2093/* */2094/* SET OPERATIONS */2095/* */2096/***********************************************************************/2097GEN2098gtoset(GEN x)2099{2100long lx;2101if (!x) return cgetg(1, t_VEC);2102switch(typ(x))2103{2104case t_VEC:2105case t_COL: lx = lg(x); break;2106case t_LIST:2107if (list_typ(x)==t_LIST_MAP) return mapdomain(x);2108x = list_data(x); lx = x? lg(x): 1; break;2109case t_VECSMALL: lx = lg(x); x = zv_to_ZV(x); break;2110default: return mkveccopy(x);2111}2112if (lx==1) return cgetg(1,t_VEC);2113x = gen_sort_uniq(x, (void*)&cmp_universal, cmp_nodata);2114settyp(x, t_VEC); /* it may be t_COL */2115return x;2116}21172118long2119setisset(GEN x)2120{2121long i, lx = lg(x);21222123if (typ(x) != t_VEC) return 0;2124if (lx == 1) return 1;2125for (i=1; i<lx-1; i++)2126if (cmp_universal(gel(x,i+1), gel(x,i)) <= 0) return 0;2127return 1;2128}21292130long2131setsearch(GEN T, GEN y, long flag)2132{2133long i, lx;2134switch(typ(T))2135{2136case t_VEC: lx = lg(T); break;2137case t_LIST:2138if (list_typ(T) != t_LIST_RAW) pari_err_TYPE("setsearch",T);2139T = list_data(T); lx = T? lg(T): 1; break;2140default: pari_err_TYPE("setsearch",T);2141return 0; /*LCOV_EXCL_LINE*/2142}2143if (lx==1) return flag? 1: 0;2144i = gen_search(T,y,(void*)cmp_universal,cmp_nodata);2145if (i > 0) return flag? 0: i;2146return flag ? -i: 0;2147}21482149GEN2150setunion_i(GEN x, GEN y)2151{ return merge_sort_uniq(x,y, (void*)cmp_universal, cmp_nodata); }21522153GEN2154setunion(GEN x, GEN y)2155{2156pari_sp av = avma;2157if (typ(x) != t_VEC) pari_err_TYPE("setunion",x);2158if (typ(y) != t_VEC) pari_err_TYPE("setunion",y);2159return gerepilecopy(av, setunion_i(x, y));2160}21612162GEN2163setintersect(GEN x, GEN y)2164{2165long ix = 1, iy = 1, iz = 1, lx = lg(x), ly = lg(y);2166pari_sp av = avma;2167GEN z = cgetg(lx,t_VEC);2168if (typ(x) != t_VEC) pari_err_TYPE("setintersect",x);2169if (typ(y) != t_VEC) pari_err_TYPE("setintersect",y);2170while (ix < lx && iy < ly)2171{2172int c = cmp_universal(gel(x,ix), gel(y,iy));2173if (c < 0) ix++;2174else if (c > 0) iy++;2175else { gel(z, iz++) = gel(x,ix); ix++; iy++; }2176}2177setlg(z,iz); return gerepilecopy(av,z);2178}21792180GEN2181gen_setminus(GEN A, GEN B, int (*cmp)(GEN,GEN))2182{2183pari_sp ltop = avma;2184long i = 1, j = 1, k = 1, lx = lg(A), ly = lg(B);2185GEN diff = cgetg(lx,t_VEC);2186while (i < lx && j < ly)2187switch ( cmp(gel(A,i),gel(B,j)) )2188{2189case -1: gel(diff,k++) = gel(A,i++); break;2190case 1: j++; break;2191case 0: i++; break;2192}2193while (i < lx) gel(diff,k++) = gel(A,i++);2194setlg(diff,k);2195return gerepilecopy(ltop,diff);2196}21972198GEN2199setminus(GEN x, GEN y)2200{2201if (typ(x) != t_VEC) pari_err_TYPE("setminus",x);2202if (typ(y) != t_VEC) pari_err_TYPE("setminus",y);2203return gen_setminus(x,y,cmp_universal);2204}22052206GEN2207setbinop(GEN f, GEN x, GEN y)2208{2209pari_sp av = avma;2210long i, j, lx, ly, k = 1;2211GEN z;2212if (typ(f) != t_CLOSURE || closure_arity(f) != 2 || closure_is_variadic(f))2213pari_err_TYPE("setbinop [function needs exactly 2 arguments]",f);2214lx = lg(x);2215if (typ(x) != t_VEC) pari_err_TYPE("setbinop", x);2216if (y == NULL) { /* assume x = y and f symmetric */2217z = cgetg((((lx-1)*lx) >> 1) + 1, t_VEC);2218for (i = 1; i < lx; i++)2219for (j = i; j < lx; j++)2220gel(z, k++) = closure_callgen2(f, gel(x,i),gel(x,j));2221} else {2222ly = lg(y);2223if (typ(y) != t_VEC) pari_err_TYPE("setbinop", y);2224z = cgetg((lx-1)*(ly-1) + 1, t_VEC);2225for (i = 1; i < lx; i++)2226for (j = 1; j < ly; j++)2227gel(z, k++) = closure_callgen2(f, gel(x,i),gel(y,j));2228}2229return gerepileupto(av, gtoset(z));2230}223122322233