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/*********************************************************************/15/** **/16/** ARITHMETIC FUNCTIONS **/17/** (first part) **/18/** **/19/*********************************************************************/20#include "pari.h"21#include "paripriv.h"2223#define DEBUGLEVEL DEBUGLEVEL_arith2425/******************************************************************/26/* */27/* GENERATOR of (Z/mZ)* */28/* */29/******************************************************************/30static GEN31remove2(GEN q) { long v = vali(q); return v? shifti(q, -v): q; }32static ulong33u_remove2(ulong q) { return q >> vals(q); }34GEN35odd_prime_divisors(GEN q) { return gel(Z_factor(remove2(q)), 1); }36static GEN37u_odd_prime_divisors(ulong q) { return gel(factoru(u_remove2(q)), 1); }38/* p odd prime, q=(p-1)/2; L0 list of (some) divisors of q = (p-1)/2 or NULL39* (all prime divisors of q); return the q/l, l in L0 */40static GEN41is_gener_expo(GEN p, GEN L0)42{43GEN L, q = shifti(p,-1);44long i, l;45if (L0) {46l = lg(L0);47L = cgetg(l, t_VEC);48} else {49L0 = L = odd_prime_divisors(q);50l = lg(L);51}52for (i=1; i<l; i++) gel(L,i) = diviiexact(q, gel(L0,i));53return L;54}55static GEN56u_is_gener_expo(ulong p, GEN L0)57{58const ulong q = p >> 1;59long i;60GEN L;61if (!L0) L0 = u_odd_prime_divisors(q);62L = cgetg_copy(L0,&i);63while (--i) L[i] = q / uel(L0,i);64return L;65}6667int68is_gener_Fl(ulong x, ulong p, ulong p_1, GEN L)69{70long i;71if (krouu(x, p) >= 0) return 0;72for (i=lg(L)-1; i; i--)73{74ulong t = Fl_powu(x, uel(L,i), p);75if (t == p_1 || t == 1) return 0;76}77return 1;78}79/* assume p prime */80ulong81pgener_Fl_local(ulong p, GEN L0)82{83const pari_sp av = avma;84const ulong p_1 = p-1;85long x;86GEN L;87if (p <= 19) switch(p)88{ /* quick trivial cases */89case 2: return 1;90case 7:91case 17: return 3;92default: return 2;93}94L = u_is_gener_expo(p,L0);95for (x = 2;; x++)96if (is_gener_Fl(x,p,p_1,L)) return gc_ulong(av, x);97}98ulong99pgener_Fl(ulong p) { return pgener_Fl_local(p, NULL); }100101/* L[i] = set of (p-1)/2l, l ODD prime divisor of p-1 (l=2 can be included,102* but wasteful) */103int104is_gener_Fp(GEN x, GEN p, GEN p_1, GEN L)105{106long i, t = lgefint(x)==3? kroui(x[2], p): kronecker(x, p);107if (t >= 0) return 0;108for (i = lg(L)-1; i; i--)109{110GEN t = Fp_pow(x, gel(L,i), p);111if (equalii(t, p_1) || equali1(t)) return 0;112}113return 1;114}115116/* assume p prime, return a generator of all L[i]-Sylows in F_p^*. */117GEN118pgener_Fp_local(GEN p, GEN L0)119{120pari_sp av0 = avma;121GEN x, p_1, L;122if (lgefint(p) == 3)123{124ulong z;125if (p[2] == 2) return gen_1;126if (L0) L0 = ZV_to_nv(L0);127z = pgener_Fl_local(uel(p,2), L0);128set_avma(av0); return utoipos(z);129}130p_1 = subiu(p,1); L = is_gener_expo(p, L0);131x = utoipos(2);132for (;; x[2]++) { if (is_gener_Fp(x, p, p_1, L)) break; }133set_avma(av0); return utoipos(uel(x,2));134}135136GEN137pgener_Fp(GEN p) { return pgener_Fp_local(p, NULL); }138139ulong140pgener_Zl(ulong p)141{142if (p == 2) pari_err_DOMAIN("pgener_Zl","p","=",gen_2,gen_2);143/* only p < 2^32 such that znprimroot(p) != znprimroot(p^2) */144if (p == 40487) return 10;145#ifndef LONG_IS_64BIT146return pgener_Fl(p);147#else148if (p < (1UL<<32)) return pgener_Fl(p);149else150{151const pari_sp av = avma;152const ulong p_1 = p-1;153long x ;154GEN p2 = sqru(p), L = u_is_gener_expo(p, NULL);155for (x=2;;x++)156if (is_gener_Fl(x,p,p_1,L) && !is_pm1(Fp_powu(utoipos(x),p_1,p2)))157return gc_ulong(av, x);158}159#endif160}161162/* p prime. Return a primitive root modulo p^e, e > 1 */163GEN164pgener_Zp(GEN p)165{166if (lgefint(p) == 3) return utoipos(pgener_Zl(p[2]));167else168{169const pari_sp av = avma;170GEN p_1 = subiu(p,1), p2 = sqri(p), L = is_gener_expo(p,NULL);171GEN x = utoipos(2);172for (;; x[2]++)173if (is_gener_Fp(x,p,p_1,L) && !equali1(Fp_pow(x,p_1,p2))) break;174set_avma(av); return utoipos(uel(x,2));175}176}177178static GEN179gener_Zp(GEN q, GEN F)180{181GEN p = NULL;182long e = 0;183if (F)184{185GEN P = gel(F,1), E = gel(F,2);186long i, l = lg(P);187for (i = 1; i < l; i++)188{189p = gel(P,i);190if (absequaliu(p, 2)) continue;191if (i < l-1) pari_err_DOMAIN("znprimroot", "argument","=",F,F);192e = itos(gel(E,i));193}194if (!p) pari_err_DOMAIN("znprimroot", "argument","=",F,F);195}196else197e = Z_isanypower(q, &p);198return e > 1? pgener_Zp(p): pgener_Fp(q);199}200201GEN202znprimroot(GEN N)203{204pari_sp av = avma;205GEN x, n, F;206207if ((F = check_arith_non0(N,"znprimroot")))208{209F = clean_Z_factor(F);210N = typ(N) == t_VEC? gel(N,1): factorback(F);211}212N = absi_shallow(N);213if (abscmpiu(N, 4) <= 0) { set_avma(av); return mkintmodu(N[2]-1,N[2]); }214switch(mod4(N))215{216case 0: /* N = 0 mod 4 */217pari_err_DOMAIN("znprimroot", "argument","=",N,N);218x = NULL; break;219case 2: /* N = 2 mod 4 */220n = shifti(N,-1); /* becomes odd */221x = gener_Zp(n,F); if (!mod2(x)) x = addii(x,n);222break;223default: /* N odd */224x = gener_Zp(N,F);225break;226}227return gerepilecopy(av, mkintmod(x, N));228}229230/* n | (p-1), returns a primitive n-th root of 1 in F_p^* */231GEN232rootsof1_Fp(GEN n, GEN p)233{234pari_sp av = avma;235GEN L = odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */236GEN z = pgener_Fp_local(p, L);237z = Fp_pow(z, diviiexact(subiu(p,1), n), p); /* prim. n-th root of 1 */238return gerepileuptoint(av, z);239}240241GEN242rootsof1u_Fp(ulong n, GEN p)243{244pari_sp av = avma;245GEN z, L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */246z = pgener_Fp_local(p, Flv_to_ZV(L));247z = Fp_pow(z, diviuexact(subiu(p,1), n), p); /* prim. n-th root of 1 */248return gerepileuptoint(av, z);249}250251ulong252rootsof1_Fl(ulong n, ulong p)253{254pari_sp av = avma;255GEN L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fl_local */256ulong z = pgener_Fl_local(p, L);257z = Fl_powu(z, (p-1) / n, p); /* prim. n-th root of 1 */258return gc_ulong(av,z);259}260261/*********************************************************************/262/** **/263/** INVERSE TOTIENT FUNCTION **/264/** **/265/*********************************************************************/266/* N t_INT, L a ZV containing all prime divisors of N, and possibly other267* primes. Return factor(N) */268GEN269Z_factor_listP(GEN N, GEN L)270{271long i, k, l = lg(L);272GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL);273for (i = k = 1; i < l; i++)274{275GEN p = gel(L,i);276long v = Z_pvalrem(N, p, &N);277if (v)278{279gel(P,k) = p;280gel(E,k) = utoipos(v);281k++;282}283}284setlg(P, k);285setlg(E, k); return mkmat2(P,E);286}287288/* look for x such that phi(x) = n, p | x => p > m (if m = NULL: no condition).289* L is a list of primes containing all prime divisors of n. */290static long291istotient_i(GEN n, GEN m, GEN L, GEN *px)292{293pari_sp av = avma, av2;294GEN k, D;295long i, v;296if (m && mod2(n))297{298if (!equali1(n)) return 0;299if (px) *px = gen_1;300return 1;301}302D = divisors(Z_factor_listP(shifti(n, -1), L));303/* loop through primes p > m, d = p-1 | n */304av2 = avma;305if (!m)306{ /* special case p = 2, d = 1 */307k = n;308for (v = 1;; v++) {309if (istotient_i(k, gen_2, L, px)) {310if (px) *px = shifti(*px, v);311return 1;312}313if (mod2(k)) break;314k = shifti(k,-1);315}316set_avma(av2);317}318for (i = 1; i < lg(D); ++i)319{320GEN p, d = shifti(gel(D, i), 1); /* even divisors of n */321if (m && cmpii(d, m) < 0) continue;322p = addiu(d, 1);323if (!isprime(p)) continue;324k = diviiexact(n, d);325for (v = 1;; v++) {326GEN r;327if (istotient_i(k, p, L, px)) {328if (px) *px = mulii(*px, powiu(p, v));329return 1;330}331k = dvmdii(k, p, &r);332if (r != gen_0) break;333}334set_avma(av2);335}336return gc_long(av,0);337}338339/* find x such that phi(x) = n */340long341istotient(GEN n, GEN *px)342{343pari_sp av = avma;344if (typ(n) != t_INT) pari_err_TYPE("istotient", n);345if (signe(n) < 1) return 0;346if (mod2(n))347{348if (!equali1(n)) return 0;349if (px) *px = gen_1;350return 1;351}352if (istotient_i(n, NULL, gel(Z_factor(n), 1), px))353{354if (!px) set_avma(av);355else356*px = gerepileuptoint(av, *px);357return 1;358}359return gc_long(av,0);360}361362/*********************************************************************/363/** **/364/** INTEGRAL LOGARITHM **/365/** **/366/*********************************************************************/367368/* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e369* e = floor(log_y B). Set *ptq = y^e if non-NULL */370long371ulogintall(ulong B, ulong y, ulong *ptq)372{373ulong r, r2;374long e;375376if (y == 2)377{378long eB = expu(B); /* 2^eB <= B < 2^(eB + 1) */379if (ptq) *ptq = 1UL << eB;380return eB;381}382r = y, r2 = 1UL;383for (e=1;; e++)384{ /* here, r = y^e, r2 = y^(e-1) */385if (r >= B)386{387if (r != B) { e--; r = r2; }388if (ptq) *ptq = r;389return e;390}391r2 = r;392r = umuluu_or_0(y, r);393if (!r)394{395if (ptq) *ptq = r2;396return e;397}398}399}400401/* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e402* e = floor(log_y B). Set *ptq = y^e if non-NULL */403long404logintall(GEN B, GEN y, GEN *ptq)405{406pari_sp av;407long ey, e, emax, i, eB = expi(B); /* 2^eB <= B < 2^(eB + 1) */408GEN q, pow2;409410if (lgefint(B) == 3)411{412ulong q;413if (lgefint(y) > 3)414{415if (ptq) *ptq = gen_1;416return 0;417}418if (!ptq) return ulogintall(B[2], y[2], NULL);419e = ulogintall(B[2], y[2], &q);420*ptq = utoi(q); return e;421}422if (equaliu(y,2))423{424if (ptq) *ptq = int2n(eB);425return eB;426}427av = avma;428ey = expi(y);429/* eB/(ey+1) - 1 < e <= eB/ey */430emax = eB/ey;431if (emax <= 13) /* e small, be naive */432{433GEN r = y, r2 = gen_1;434for (e=1;; e++)435{ /* here, r = y^e, r2 = y^(e-1) */436long fl = cmpii(r, B);437if (fl >= 0)438{439if (fl) { e--; cgiv(r); r = r2; }440if (ptq) *ptq = gerepileuptoint(av, r); else set_avma(av);441return e;442}443r2 = r; r = mulii(r,y);444}445}446/* e >= 13 ey / (ey+1) >= 6.5 */447448/* binary splitting: compute bits of e one by one */449/* compute pow2[i] = y^(2^i) [i < crude upper bound for log_2 log_y(B)] */450pow2 = new_chunk((long)log2(eB)+2);451gel(pow2,0) = y;452for (i=0, q=y;; )453{454GEN r = gel(pow2,i); /* r = y^2^i */455long fl = cmpii(r,B);456if (!fl)457{458e = 1L<<i;459if (ptq) *ptq = gerepileuptoint(av, r); else set_avma(av);460return e;461}462if (fl > 0) { i--; break; }463q = r;464if (1L<<(i+1) > emax) break;465gel(pow2,++i) = sqri(q);466}467468for (e = 1L<<i;;)469{ /* y^e = q < B < r = q * y^(2^i) */470pari_sp av2 = avma;471long fl;472GEN r;473if (--i < 0) break;474r = mulii(q, gel(pow2,i));475fl = cmpii(r, B);476if (fl > 0) set_avma(av2);477else478{479e += (1L<<i);480q = r;481if (!fl) break; /* B = r */482}483}484if (ptq) *ptq = gerepileuptoint(av, q); else set_avma(av);485return e;486}487488long489logint0(GEN B, GEN y, GEN *ptq)490{491if (typ(B) != t_INT) pari_err_TYPE("logint",B);492if (signe(B) <= 0) pari_err_DOMAIN("logint", "x" ,"<=", gen_0, B);493if (typ(y) != t_INT) pari_err_TYPE("logint",y);494if (cmpis(y, 2) < 0) pari_err_DOMAIN("logint", "b" ,"<=", gen_1, y);495return logintall(B,y,ptq);496}497498/*********************************************************************/499/** **/500/** INTEGRAL SQUARE ROOT **/501/** **/502/*********************************************************************/503GEN504sqrtint(GEN a)505{506if (typ(a) != t_INT) pari_err_TYPE("sqrtint",a);507switch (signe(a))508{509case 1: return sqrti(a);510case 0: return gen_0;511default: pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);512}513return NULL; /* LCOV_EXCL_LINE */514}515GEN516sqrtint0(GEN a, GEN *r)517{518if (!r) return sqrtint(a);519if (typ(a) != t_INT) pari_err_TYPE("sqrtint",a);520switch (signe(a))521{522case 1: return sqrtremi(a, r);523case 0: *r = gen_0; return gen_0;524default: pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);525}526return NULL; /* LCOV_EXCL_LINE */527}528529/*********************************************************************/530/** **/531/** PERFECT SQUARE **/532/** **/533/*********************************************************************/534static int535carremod(ulong A)536{537const int carresmod64[]={5381,1,0,0,1,0,0,0,0,1, 0,0,0,0,0,0,1,1,0,0, 0,0,0,0,0,1,0,0,0,0,5390,0,0,1,0,0,1,0,0,0, 0,1,0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,1,0,0, 0,0,0,0};540const int carresmod63[]={5411,1,0,0,1,0,0,1,0,1, 0,0,0,0,0,0,1,0,1,0, 0,0,1,0,0,1,0,0,1,0,5420,0,0,0,0,0,1,1,0,0, 0,0,0,1,0,0,1,0,0,1, 0,0,0,0,0,0,0,0,1,0, 0,0,0};543const int carresmod65[]={5441,1,0,0,1,0,0,0,0,1, 1,0,0,0,1,0,1,0,0,0, 0,0,0,0,0,1,1,0,0,1,5451,0,0,0,0,1,1,0,0,1, 1,0,0,0,0,0,0,0,0,1, 0,1,0,0,0,1,1,0,0,0, 0,1,0,0,1};546const int carresmod11[]={1,1,0,1,1,1,0,0,0,1, 0};547return (carresmod64[A & 0x3fUL]548&& carresmod63[A % 63UL]549&& carresmod65[A % 65UL]550&& carresmod11[A % 11UL]);551}552553/* emulate Z_issquareall on single-word integers */554long555uissquareall(ulong A, ulong *sqrtA)556{557if (!A) { *sqrtA = 0; return 1; }558if (carremod(A))559{560ulong a = usqrt(A);561if (a * a == A) { *sqrtA = a; return 1; }562}563return 0;564}565long566uissquare(ulong A)567{568if (!A) return 1;569if (carremod(A))570{571ulong a = usqrt(A);572if (a * a == A) return 1;573}574return 0;575}576577long578Z_issquareall(GEN x, GEN *pt)579{580pari_sp av;581GEN y, r;582583switch(signe(x))584{585case -1: return 0;586case 0: if (pt) *pt=gen_0; return 1;587}588if (lgefint(x) == 3)589{590ulong u = uel(x,2), a;591if (!pt) return uissquare(u);592if (!uissquareall(u, &a)) return 0;593*pt = utoipos(a); return 1;594}595if (!carremod(umodiu(x, 64*63*65*11))) return 0;596av = avma; y = sqrtremi(x, &r);597if (r != gen_0) return gc_long(av,0);598if (pt) { *pt = y; set_avma((pari_sp)y); } else set_avma(av);599return 1;600}601602/* a t_INT, p prime */603long604Zp_issquare(GEN a, GEN p)605{606long v;607GEN ap;608609if (!signe(a) || gequal1(a)) return 1;610v = Z_pvalrem(a, p, &ap);611if (v&1) return 0;612return absequaliu(p, 2)? umodiu(ap, 8) == 1613: kronecker(ap,p) == 1;614}615616static long617polissquareall(GEN x, GEN *pt)618{619pari_sp av;620long v;621GEN y, a, b, p;622623if (!signe(x))624{625if (pt) *pt = gcopy(x);626return 1;627}628if (odd(degpol(x))) return 0; /* odd degree */629av = avma;630v = RgX_valrem(x, &x);631if (v & 1) return gc_long(av,0);632a = gel(x,2); /* test constant coeff */633if (!pt)634{ if (!issquare(a)) return gc_long(av,0); }635else636{ if (!issquareall(a,&b)) return gc_long(av,0); }637if (!degpol(x)) { /* constant polynomial */638if (!pt) return gc_long(av,1);639y = scalarpol(b, varn(x)); goto END;640}641p = characteristic(x);642if (signe(p) && !mod2(p))643{644long i, lx;645if (!absequaliu(p,2)) pari_err_IMPL("issquare for even characteristic != 2");646x = gmul(x, mkintmod(gen_1, gen_2));647lx = lg(x);648if ((lx-3) & 1) return gc_long(av,0);649for (i = 3; i < lx; i+=2)650if (!gequal0(gel(x,i))) return gc_long(av,0);651if (pt) {652y = cgetg((lx+3) / 2, t_POL);653for (i = 2; i < lx; i+=2)654if (!issquareall(gel(x,i), &gel(y, (i+2)>>1))) return gc_long(av,0);655y[1] = evalsigne(1) | evalvarn(varn(x));656goto END;657} else {658for (i = 2; i < lx; i+=2)659if (!issquare(gel(x,i))) return gc_long(av,0);660return gc_long(av,1);661}662}663else664{665long m = 1;666x = RgX_Rg_div(x,a);667/* a(x^m) = B^2 => B = b(x^m) provided a(0) != 0 */668if (!signe(p)) x = RgX_deflate_max(x,&m);669y = ser2rfrac_i(gsqrt(RgX_to_ser(x,lg(x)-1),0));670if (!RgX_equal(RgX_sqr(y), x)) return gc_long(av,0);671if (!pt) return gc_long(av,1);672if (!gequal1(a)) y = gmul(b, y);673if (m != 1) y = RgX_inflate(y,m);674}675END:676if (v) y = RgX_shift_shallow(y, v>>1);677*pt = gerepilecopy(av, y); return 1;678}679680/* b unit mod p */681static int682Up_ispower(GEN b, GEN K, GEN p, long d, GEN *pt)683{684if (d == 1)685{ /* mod p: faster */686if (!Fp_ispower(b, K, p)) return 0;687if (pt) *pt = Fp_sqrtn(b, K, p, NULL);688}689else690{ /* mod p^{2 +} */691if (!ispower(cvtop(b, p, d), K, pt)) return 0;692if (pt) *pt = gtrunc(*pt);693}694return 1;695}696697/* We're studying whether a mod (q*p^e) is a K-th power, (q,p) = 1.698* Decide mod p^e, then reduce a mod q unless q = NULL. */699static int700handle_pe(GEN *pa, GEN q, GEN L, GEN K, GEN p, long e)701{702GEN t, A;703long v = Z_pvalrem(*pa, p, &A), d = e - v;704if (d <= 0) t = gen_0;705else706{707ulong r;708v = uabsdivui_rem(v, K, &r);709if (r || !Up_ispower(A, K, p, d, L? &t: NULL)) return 0;710if (L && v) t = mulii(t, powiu(p, v));711}712if (q) *pa = modii(*pa, q);713if (L) vectrunc_append(L, mkintmod(t, powiu(p, e)));714return 1;715}716long717Zn_ispower(GEN a, GEN q, GEN K, GEN *pt)718{719GEN L, N;720pari_sp av;721long e, i, l;722ulong pp;723forprime_t S;724725if (!signe(a))726{727if (pt) {728GEN t = cgetg(3, t_INTMOD);729gel(t,1) = icopy(q); gel(t,2) = gen_0; *pt = t;730}731return 1;732}733/* a != 0 */734av = avma;735736if (typ(q) != t_INT) /* integer factorization */737{738GEN P = gel(q,1), E = gel(q,2);739l = lg(P);740L = pt? vectrunc_init(l): NULL;741for (i = 1; i < l; i++)742{743GEN p = gel(P,i);744long e = itos(gel(E,i));745if (!handle_pe(&a, NULL, L, K, p, e)) return gc_long(av,0);746}747goto END;748}749if (!mod2(K)750&& kronecker(a, shifti(q,-vali(q))) == -1) return gc_long(av,0);751L = pt? vectrunc_init(expi(q)+1): NULL;752u_forprime_init(&S, 2, tridiv_bound(q));753while ((pp = u_forprime_next(&S)))754{755int stop;756e = Z_lvalrem_stop(&q, pp, &stop);757if (!e) continue;758if (!handle_pe(&a, q, L, K, utoipos(pp), e)) return gc_long(av,0);759if (stop)760{761if (!is_pm1(q) && !handle_pe(&a, q, L, K, q, 1)) return gc_long(av,0);762goto END;763}764}765l = lg(primetab);766for (i = 1; i < l; i++)767{768GEN p = gel(primetab,i);769e = Z_pvalrem(q, p, &q);770if (!e) continue;771if (!handle_pe(&a, q, L, K, p, e)) return gc_long(av,0);772if (is_pm1(q)) goto END;773}774N = gcdii(a,q);775if (!is_pm1(N))776{777if (ifac_isprime(N))778{779e = Z_pvalrem(q, N, &q);780if (!handle_pe(&a, q, L, K, N, e)) return gc_long(av,0);781}782else783{784GEN part = ifac_start(N, 0);785for(;;)786{787long e;788GEN p;789if (!ifac_next(&part, &p, &e)) break;790e = Z_pvalrem(q, p, &q);791if (!handle_pe(&a, q, L, K, p, e)) return gc_long(av,0);792}793}794}795if (!is_pm1(q))796{797if (ifac_isprime(q))798{799if (!handle_pe(&a, q, L, K, q, 1)) return gc_long(av,0);800}801else802{803GEN part = ifac_start(q, 0);804for(;;)805{806long e;807GEN p;808if (!ifac_next(&part, &p, &e)) break;809if (!handle_pe(&a, q, L, K, p, e)) return gc_long(av,0);810}811}812}813END:814if (pt) *pt = gerepileupto(av, chinese1_coprime_Z(L));815return 1;816}817818static long819polmodispower(GEN x, GEN K, GEN *pt)820{821pari_sp av = avma;822GEN p = NULL, T = NULL;823if (Rg_is_FpXQ(x, &T,&p) && p)824{825x = liftall_shallow(x);826if (T) T = liftall_shallow(T);827if (!Fq_ispower(x, K, T, p)) return gc_long(av,0);828if (!pt) return gc_long(av,1);829x = Fq_sqrtn(x, K, T,p, NULL);830if (typ(x) == t_INT)831x = Fp_to_mod(x,p);832else833x = mkpolmod(FpX_to_mod(x,p), FpX_to_mod(T,p));834*pt = gerepilecopy(av, x); return 1;835}836pari_err_IMPL("ispower for general t_POLMOD");837return 0;838}839static long840rfracispower(GEN x, GEN K, GEN *pt)841{842pari_sp av = avma;843GEN n = gel(x,1), d = gel(x,2);844long v = -RgX_valrem(d, &d), vx = varn(d);845if (typ(n) == t_POL && varn(n) == vx) v += RgX_valrem(n, &n);846if (!dvdsi(v, K)) return gc_long(av, 0);847if (lg(d) >= 3)848{849GEN a = gel(d,2); /* constant term */850if (!gequal1(a)) { d = RgX_Rg_div(d, a); n = gdiv(n, a); }851}852if (!ispower(d, K, pt? &d: NULL) || !ispower(n, K, pt? &n: NULL))853return gc_long(av, 0);854if (!pt) return gc_long(av, 1);855x = gdiv(n, d);856if (v) x = gmul(x, monomial(gen_1, v / itos(K), vx));857*pt = gerepileupto(av, x); return 1;858}859long860issquareall(GEN x, GEN *pt)861{862long tx = typ(x);863GEN F;864pari_sp av;865866if (!pt) return issquare(x);867switch(tx)868{869case t_INT: return Z_issquareall(x, pt);870case t_FRAC: av = avma;871F = cgetg(3, t_FRAC);872if ( !Z_issquareall(gel(x,1), &gel(F,1))873|| !Z_issquareall(gel(x,2), &gel(F,2))) return gc_long(av,0);874*pt = F; return 1;875876case t_POLMOD:877return polmodispower(x, gen_2, pt);878case t_POL: return polissquareall(x,pt);879case t_RFRAC: return rfracispower(x, gen_2, pt);880881case t_REAL: case t_COMPLEX: case t_PADIC: case t_SER:882if (!issquare(x)) return 0;883*pt = gsqrt(x, DEFAULTPREC); return 1;884885case t_INTMOD:886return Zn_ispower(gel(x,2), gel(x,1), gen_2, pt);887888case t_FFELT: return FF_issquareall(x, pt);889890}891pari_err_TYPE("issquareall",x);892return 0; /* LCOV_EXCL_LINE */893}894895long896issquare(GEN x)897{898GEN a, p;899long v;900901switch(typ(x))902{903case t_INT:904return Z_issquare(x);905906case t_REAL:907return (signe(x)>=0);908909case t_INTMOD:910return Zn_ispower(gel(x,2), gel(x,1), gen_2, NULL);911912case t_FRAC:913return Z_issquare(gel(x,1)) && Z_issquare(gel(x,2));914915case t_FFELT: return FF_issquareall(x, NULL);916917case t_COMPLEX:918return 1;919920case t_PADIC:921a = gel(x,4); if (!signe(a)) return 1;922if (valp(x)&1) return 0;923p = gel(x,2);924if (!absequaliu(p, 2)) return (kronecker(a,p) != -1);925926v = precp(x); /* here p=2, a is odd */927if ((v>=3 && mod8(a) != 1 ) ||928(v==2 && mod4(a) != 1)) return 0;929return 1;930931case t_POLMOD:932return polmodispower(x, gen_2, NULL);933934case t_POL:935return polissquareall(x,NULL);936937case t_SER:938if (!signe(x)) return 1;939if (valp(x)&1) return 0;940return issquare(gel(x,2));941942case t_RFRAC:943return rfracispower(x, gen_2, NULL);944}945pari_err_TYPE("issquare",x);946return 0; /* LCOV_EXCL_LINE */947}948GEN gissquare(GEN x) { return issquare(x)? gen_1: gen_0; }949GEN gissquareall(GEN x, GEN *pt) { return issquareall(x,pt)? gen_1: gen_0; }950951long952ispolygonal(GEN x, GEN S, GEN *N)953{954pari_sp av = avma;955GEN D, d, n;956if (typ(x) != t_INT) pari_err_TYPE("ispolygonal", x);957if (typ(S) != t_INT) pari_err_TYPE("ispolygonal", S);958if (abscmpiu(S,3) < 0) pari_err_DOMAIN("ispolygonal","s","<", utoipos(3),S);959if (signe(x) < 0) return 0;960if (signe(x) == 0) { if (N) *N = gen_0; return 1; }961if (is_pm1(x)) { if (N) *N = gen_1; return 1; }962/* n = (sqrt( (8s - 16) x + (s-4)^2 ) + s - 4) / 2(s - 2) */963if (abscmpiu(S, 1<<16) < 0) /* common case ! */964{965ulong s = S[2], r;966if (s == 4) return Z_issquareall(x, N);967if (s == 3)968D = addiu(shifti(x, 3), 1);969else970D = addiu(mului(8*s - 16, x), (s-4)*(s-4));971if (!Z_issquareall(D, &d)) return gc_long(av,0);972if (s == 3)973d = subiu(d, 1);974else975d = addiu(d, s - 4);976n = absdiviu_rem(d, 2*s - 4, &r);977if (r) return gc_long(av,0);978}979else980{981GEN r, S_2 = subiu(S,2), S_4 = subiu(S,4);982D = addii(mulii(shifti(S_2,3), x), sqri(S_4));983if (!Z_issquareall(D, &d)) return gc_long(av,0);984d = addii(d, S_4);985n = dvmdii(shifti(d,-1), S_2, &r);986if (r != gen_0) return gc_long(av,0);987}988if (N) *N = gerepileuptoint(av, n); else set_avma(av);989return 1;990}991992/*********************************************************************/993/** **/994/** PERFECT POWER **/995/** **/996/*********************************************************************/997static long998polispower(GEN x, GEN K, GEN *pt)999{1000pari_sp av;1001long v, d, k = itos(K);1002GEN y, a, b;1003GEN T = NULL, p = NULL;10041005if (!signe(x))1006{1007if (pt) *pt = gcopy(x);1008return 1;1009}1010d = degpol(x);1011if (d % k) return 0; /* degree not multiple of k */1012av = avma;1013if (RgX_is_FpXQX(x, &T, &p) && p)1014{ /* over Fq */1015if (T && typ(T) == t_FFELT)1016{1017if (!FFX_ispower(x, k, T, pt)) return gc_long(av,0);1018return 1;1019}1020x = RgX_to_FqX(x,T,p);1021if (!FqX_ispower(x, k, T,p, pt)) return gc_long(av,0);1022if (pt) *pt = gerepileupto(av, FqX_to_mod(*pt, T, p));1023return 1;1024}1025v = RgX_valrem(x, &x);1026if (v % k) return 0;1027v /= k;1028a = gel(x,2); b = NULL;1029if (!ispower(a, K, &b)) return gc_long(av,0);1030if (d)1031{1032GEN p = characteristic(x);1033a = leading_coeff(x);1034if (!ispower(a, K, &b)) return gc_long(av,0);1035x = RgX_normalize(x);1036if (signe(p) && cmpii(p,K) <= 0)1037pari_err_IMPL("ispower(general t_POL) in small characteristic");1038y = gtrunc(gsqrtn(RgX_to_ser(x,lg(x)), K, NULL, 0));1039if (!RgX_equal(powgi(y, K), x)) return gc_long(av,0);1040}1041else1042y = pol_1(varn(x));1043if (pt)1044{1045if (!gequal1(a))1046{1047if (!b) b = gsqrtn(a, K, NULL, DEFAULTPREC);1048y = gmul(b,y);1049}1050if (v) y = RgX_shift_shallow(y, v);1051*pt = gerepilecopy(av, y);1052}1053else set_avma(av);1054return 1;1055}10561057long1058Z_ispowerall(GEN x, ulong k, GEN *pt)1059{1060long s = signe(x);1061ulong mask;1062if (!s) { if (pt) *pt = gen_0; return 1; }1063if (s > 0) {1064if (k == 2) return Z_issquareall(x, pt);1065if (k == 3) { mask = 1; return !!is_357_power(x, pt, &mask); }1066if (k == 5) { mask = 2; return !!is_357_power(x, pt, &mask); }1067if (k == 7) { mask = 4; return !!is_357_power(x, pt, &mask); }1068return is_kth_power(x, k, pt);1069}1070if (!odd(k)) return 0;1071if (Z_ispowerall(absi_shallow(x), k, pt))1072{1073if (pt) *pt = negi(*pt);1074return 1;1075};1076return 0;1077}10781079/* is x a K-th power mod p ? Assume p prime. */1080int1081Fp_ispower(GEN x, GEN K, GEN p)1082{1083pari_sp av = avma;1084GEN p_1;1085x = modii(x, p);1086if (!signe(x) || equali1(x)) return gc_bool(av,1);1087/* implies p > 2 */1088p_1 = subiu(p,1);1089K = gcdii(K, p_1);1090if (absequaliu(K, 2)) return gc_bool(av, kronecker(x,p) > 0);1091x = Fp_pow(x, diviiexact(p_1,K), p);1092return gc_bool(av, equali1(x));1093}10941095/* x unit defined modulo 2^e, e > 0, p prime */1096static int1097U2_issquare(GEN x, long e)1098{1099long r = signe(x)>=0?mod8(x):8-mod8(x);1100if (e==1) return 1;1101if (e==2) return (r&3L) == 1;1102return r == 1;1103}1104/* x unit defined modulo p^e, e > 0, p prime */1105static int1106Up_issquare(GEN x, GEN p, long e)1107{ return (absequaliu(p,2))? U2_issquare(x, e): kronecker(x,p)==1; }11081109long1110Zn_issquare(GEN d, GEN fn)1111{1112long j, np;1113if (typ(d) != t_INT) pari_err_TYPE("Zn_issquare",d);1114if (typ(fn) == t_INT) return Zn_ispower(d, fn, gen_2, NULL);1115/* integer factorization */1116np = nbrows(fn);1117for (j = 1; j <= np; ++j)1118{1119GEN r, p = gcoeff(fn, j, 1);1120long e = itos(gcoeff(fn, j, 2));1121long v = Z_pvalrem(d,p,&r);1122if (v < e && (odd(v) || !Up_issquare(r, p, e-v))) return 0;1123}1124return 1;1125}11261127/* return [N',v]; v contains all x mod N' s.t. x^2 + B x + C = 0 modulo N */1128GEN1129Zn_quad_roots(GEN N, GEN B, GEN C)1130{1131pari_sp av = avma;1132GEN fa = NULL, D, w, v, P, E, F0, Q0, F, mF, A, Q, T, R, Np, N4;1133long l, i, j, ct;11341135if ((fa = check_arith_non0(N,"Zn_quad_roots")))1136{1137N = typ(N) == t_VEC? gel(N,1): factorback(N);1138fa = clean_Z_factor(fa);1139}1140N = absi_shallow(N);1141N4 = shifti(N,2);1142D = modii(subii(sqri(B), shifti(C,2)), N4);1143if (!signe(D))1144{ /* (x + B/2)^2 = 0 (mod N), D = B^2-4C = 0 (4N) => B even */1145if (!fa) fa = Z_factor(N);1146P = gel(fa,1);1147E = ZV_to_zv(gel(fa,2));1148l = lg(P);1149for (i = 1; i < l; i++) E[i] = (E[i]+1) >> 1;1150Np = factorback2(P, E); /* x = -B mod N' */1151B = shifti(B,-1);1152return gerepilecopy(av, mkvec2(Np, mkvec(Fp_neg(B,Np))));1153}1154if (!fa)1155fa = Z_factor(N4);1156else /* convert to factorization of N4 = 4*N */1157fa = famat_reduce(famat_mulpows_shallow(fa, gen_2, 2));1158P = gel(fa,1); l = lg(P);1159E = ZV_to_zv(gel(fa,2));1160F = cgetg(l, t_VEC);1161mF= cgetg(l, t_VEC); F0 = gen_0;1162Q = cgetg(l, t_VEC); Q0 = gen_1;1163for (i = j = 1, ct = 0; i < l; i++)1164{1165GEN p = gel(P,i), q, f, mf, D0;1166long t2, s = E[i], t = Z_pvalrem(D, p, &D0), d = s - t;1167if (d <= 0)1168{1169q = powiu(p, (s+1)>>1);1170Q0 = mulii(Q0, q); continue;1171}1172/* d > 0 */1173if (odd(t)) return NULL;1174t2 = t >> 1;1175if (i > 1)1176{ /* p > 2 */1177if (kronecker(D0, p) == -1) return NULL;1178q = powiu(p, s - t2);1179f = Zp_sqrt(D0, p, d);1180if (!f) return NULL; /* p was not actually prime... */1181if (t2) f = mulii(powiu(p,t2), f);1182mf = Fp_neg(f, q);1183}1184else1185{ /* p = 2 */1186if (d <= 3)1187{1188if (d == 3 && Mod8(D0) != 1) return NULL;1189if (d == 2 && Mod4(D0) != 1) return NULL;1190Q0 = int2n(1+t2); F0 = NULL; continue;1191}1192if (Mod8(D0) != 1) return NULL;1193q = int2n(d - 1 + t2);1194f = Z2_sqrt(D0, d);1195if (t2) f = shifti(f, t2);1196mf = Fp_neg(f, q);1197}1198gel(Q,j) = q;1199gel(F,j) = f;1200gel(mF,j)= mf; j++;1201}1202setlg(Q,j);1203setlg(F,j);1204setlg(mF,j);1205if (is_pm1(Q0)) A = leafcopy(F);1206else1207{ /* append the fixed congruence (F0 mod Q0) */1208if (!F0) F0 = shifti(Q0,-1);1209A = shallowconcat(F, F0);1210Q = shallowconcat(Q, Q0);1211}1212ct = 1 << (j-1);1213T = ZV_producttree(Q);1214R = ZV_chinesetree(Q,T);1215Np = gmael(T, lg(T)-1, 1);1216B = modii(B, Np);1217if (!signe(B)) B = NULL;1218Np = shifti(Np, -1); /* N' = (\prod_i Q[i]) / 2 */1219w = cgetg(3, t_VEC);1220gel(w,1) = icopy(Np);1221gel(w,2) = v = cgetg(ct+1, t_VEC);1222l = lg(F);1223for (j = 1; j <= ct; j++)1224{1225pari_sp av2 = avma;1226long m = j - 1;1227GEN u;1228for (i = 1; i < l; i++)1229{1230gel(A,i) = (m&1L)? gel(mF,i): gel(F,i);1231m >>= 1;1232}1233u = ZV_chinese_tree(A,Q,T,R); /* u mod N' st u^2 = B^2-4C modulo 4N */1234if (B) u = subii(u,B);1235gel(v,j) = gerepileuptoint(av2, modii(shifti(u,-1), Np));1236}1237return gerepileupto(av, w);1238}12391240static long1241Qp_ispower(GEN x, GEN K, GEN *pt)1242{1243pari_sp av = avma;1244GEN z = Qp_sqrtn(x, K, NULL);1245if (!z) return gc_long(av,0);1246if (pt) *pt = z;1247return 1;1248}12491250long1251ispower(GEN x, GEN K, GEN *pt)1252{1253GEN z;12541255if (!K) return gisanypower(x, pt);1256if (typ(K) != t_INT) pari_err_TYPE("ispower",K);1257if (signe(K) <= 0) pari_err_DOMAIN("ispower","exponent","<=",gen_0,K);1258if (equali1(K)) { if (pt) *pt = gcopy(x); return 1; }1259switch(typ(x)) {1260case t_INT:1261if (lgefint(K) != 3) return 0;1262return Z_ispowerall(x, itou(K), pt);1263case t_FRAC:1264{1265GEN a = gel(x,1), b = gel(x,2);1266ulong k;1267if (lgefint(K) != 3) return 0;1268k = itou(K);1269if (pt) {1270z = cgetg(3, t_FRAC);1271if (Z_ispowerall(a, k, &a) && Z_ispowerall(b, k, &b)) {1272*pt = z; gel(z,1) = a; gel(z,2) = b; return 1;1273}1274set_avma((pari_sp)(z + 3)); return 0;1275}1276return Z_ispower(a, k) && Z_ispower(b, k);1277}1278case t_INTMOD:1279return Zn_ispower(gel(x,2), gel(x,1), K, pt);1280case t_FFELT:1281return FF_ispower(x, K, pt);12821283case t_PADIC:1284return Qp_ispower(x, K, pt);1285case t_POLMOD:1286return polmodispower(x, K, pt);1287case t_POL:1288return polispower(x, K, pt);1289case t_RFRAC:1290return rfracispower(x, K, pt);1291case t_REAL:1292if (signe(x) < 0 && !mpodd(K)) return 0;1293case t_COMPLEX:1294if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC);1295return 1;12961297case t_SER:1298if (signe(x) && (!dvdsi(valp(x), K) || !ispower(gel(x,2), K, NULL)))1299return 0;1300if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC);1301return 1;1302}1303pari_err_TYPE("ispower",x);1304return 0; /* LCOV_EXCL_LINE */1305}13061307long1308gisanypower(GEN x, GEN *pty)1309{1310long tx = typ(x);1311ulong k, h;1312if (tx == t_INT) return Z_isanypower(x, pty);1313if (tx == t_FRAC)1314{1315pari_sp av = avma;1316GEN fa, P, E, a = gel(x,1), b = gel(x,2);1317long i, j, p, e;1318int sw = (abscmpii(a, b) > 0);13191320if (sw) swap(a, b);1321k = Z_isanypower(a, pty? &a: NULL);1322if (!k)1323{ /* a = -1,1 or not a pure power */1324if (!is_pm1(a)) return gc_long(av,0);1325if (signe(a) < 0) b = negi(b);1326k = Z_isanypower(b, pty? &b: NULL);1327if (!k || !pty) return gc_long(av,k);1328*pty = gerepileupto(av, ginv(b));1329return k;1330}1331fa = factoru(k);1332P = gel(fa,1);1333E = gel(fa,2); h = k;1334for (i = lg(P) - 1; i > 0; i--)1335{1336p = P[i];1337e = E[i];1338for (j = 0; j < e; j++)1339if (!is_kth_power(b, p, &b)) break;1340if (j < e) k /= upowuu(p, e - j);1341}1342if (k == 1) return gc_long(av,0);1343if (!pty) return gc_long(av,k);1344if (k != h) a = powiu(a, h/k);1345*pty = gerepilecopy(av, mkfrac(a, b));1346return k;1347}1348pari_err_TYPE("gisanypower", x);1349return 0; /* LCOV_EXCL_LINE */1350}13511352/* v_p(x) = e != 0 for some p; return ispower(x,,&x), updating x.1353* No need to optimize for 2,3,5,7 powers (done before) */1354static long1355split_exponent(ulong e, GEN *x)1356{1357GEN fa, P, E;1358long i, j, l, k = 1;1359if (e == 1) return 1;1360fa = factoru(e);1361P = gel(fa,1);1362E = gel(fa,2); l = lg(P);1363for (i = 1; i < l; i++)1364{1365ulong p = P[i];1366for (j = 0; j < E[i]; j++)1367{1368GEN y;1369if (!is_kth_power(*x, p, &y)) break;1370k *= p; *x = y;1371}1372}1373return k;1374}13751376static long1377Z_isanypower_nosmalldiv(GEN *px)1378{ /* any prime divisor of x is > 102 */1379const double LOG2_103 = 6.6865; /* lower bound for log_2(103) */1380const double LOG103 = 4.6347; /* lower bound for log(103) */1381forprime_t T;1382ulong mask = 7, e2;1383long k, ex;1384GEN y, x = *px;13851386k = 1;1387while (Z_issquareall(x, &y)) { k <<= 1; x = y; }1388while ( (ex = is_357_power(x, &y, &mask)) ) { k *= ex; x = y; }1389e2 = (ulong)((expi(x) + 1) / LOG2_103); /* >= log_103 (x) */1390if (u_forprime_init(&T, 11, e2))1391{1392GEN logx = NULL;1393const ulong Q = 30011; /* prime */1394ulong p, xmodQ;1395double dlogx = 0;1396/* cut off at x^(1/p) ~ 2^30 bits which seems to be about optimum;1397* for large p the modular checks are no longer competitively fast */1398while ( (ex = is_pth_power(x, &y, &T, 30)) )1399{1400k *= ex; x = y;1401e2 = (ulong)((expi(x) + 1) / LOG2_103);1402u_forprime_restrict(&T, e2);1403}1404if (DEBUGLEVEL>4)1405err_printf("Z_isanypower: now k=%ld, x=%ld-bit\n", k, expi(x)+1);1406xmodQ = umodiu(x, Q);1407/* test Q | x, just in case */1408if (!xmodQ) { *px = x; return k * split_exponent(Z_lval(x,Q), px); }1409/* x^(1/p) < 2^31 */1410p = T.p;1411if (p <= e2)1412{1413logx = logr_abs( itor(x, DEFAULTPREC) );1414dlogx = rtodbl(logx);1415e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */1416}1417while (p && p <= e2)1418{ /* is x a p-th power ? By computing y = round(x^(1/p)).1419* Check whether y^p = x, first mod Q, then exactly. */1420pari_sp av = avma;1421long e;1422GEN logy = divru(logx, p), y = grndtoi(mpexp(logy), &e);1423ulong ymodQ = umodiu(y,Q);1424if (e >= -10 || Fl_powu(ymodQ, p % (Q-1), Q) != xmodQ1425|| !equalii(powiu(y, p), x)) set_avma(av);1426else1427{1428k *= p; x = y; xmodQ = ymodQ; logx = logy; dlogx /= p;1429e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */1430u_forprime_restrict(&T, e2);1431continue; /* if success, retry same p */1432}1433p = u_forprime_next(&T);1434}1435}1436*px = x; return k;1437}14381439static ulong tinyprimes[] = {14402, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,144173, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,1442157, 163, 167, 173, 179, 181, 191, 193, 197, 1991443};14441445/* disregard the sign of x, caller will take care of x < 0 */1446static long1447Z_isanypower_aux(GEN x, GEN *pty)1448{1449long ex, v, i, l, k;1450GEN y, P, E;1451ulong mask, e = 0;14521453if (abscmpii(x, gen_2) < 0) return 0; /* -1,0,1 */14541455if (signe(x) < 0) x = negi(x);1456k = l = 1;1457P = cgetg(26 + 1, t_VECSMALL);1458E = cgetg(26 + 1, t_VECSMALL);1459/* trial division */1460for(i = 0; i < 26; i++)1461{1462ulong p = tinyprimes[i];1463int stop;1464v = Z_lvalrem_stop(&x, p, &stop);1465if (v)1466{1467P[l] = p;1468E[l] = v; l++;1469e = ugcd(e, v); if (e == 1) goto END;1470}1471if (stop) {1472if (is_pm1(x)) k = e;1473goto END;1474}1475}14761477if (e)1478{ /* Bingo. Result divides e */1479long v3, v5, v7;1480ulong e2 = e;1481v = u_lvalrem(e2, 2, &e2);1482if (v)1483{1484for (i = 0; i < v; i++)1485{1486if (!Z_issquareall(x, &y)) break;1487k <<= 1; x = y;1488}1489}1490mask = 0;1491v3 = u_lvalrem(e2, 3, &e2); if (v3) mask = 1;1492v5 = u_lvalrem(e2, 5, &e2); if (v5) mask |= 2;1493v7 = u_lvalrem(e2, 7, &e2); if (v7) mask |= 4;1494while ( (ex = is_357_power(x, &y, &mask)) ) {1495x = y;1496switch(ex)1497{1498case 3: k *= 3; if (--v3 == 0) mask &= ~1; break;1499case 5: k *= 5; if (--v5 == 0) mask &= ~2; break;1500case 7: k *= 7; if (--v7 == 0) mask &= ~4; break;1501}1502}1503k *= split_exponent(e2, &x);1504}1505else1506k = Z_isanypower_nosmalldiv(&x);1507END:1508if (pty && k != 1)1509{1510if (e)1511{ /* add missing small factors */1512y = powuu(P[1], E[1] / k);1513for (i = 2; i < l; i++) y = mulii(y, powuu(P[i], E[i] / k));1514x = equali1(x)? y: mulii(x,y);1515}1516*pty = x;1517}1518return k == 1? 0: k;1519}15201521long1522Z_isanypower(GEN x, GEN *pty)1523{1524pari_sp av = avma;1525long k = Z_isanypower_aux(x, pty);1526if (!k) return gc_long(av,0);1527if (signe(x) < 0)1528{1529long v = vals(k);1530if (v)1531{1532GEN y;1533k >>= v;1534if (k == 1) return gc_long(av,0);1535if (!pty) return gc_long(av,k);1536y = *pty;1537y = powiu(y, 1<<v);1538togglesign(y);1539*pty = gerepileuptoint(av, y);1540return k;1541}1542if (pty) togglesign_safe(pty);1543}1544if (pty) *pty = gerepilecopy(av, *pty); else set_avma(av);1545return k;1546}15471548/* Faster than */1549/* !cmpii(n, int2n(vali(n))) */1550/* !cmpis(shifti(n, -vali(n)), 1) */1551/* expi(n) == vali(n) */1552/* hamming(n) == 1 */1553/* even for single-word values, and much faster for multiword values. */1554/* If all you have is a word, you can just use n & !(n & (n-1)). */1555long1556Z_ispow2(GEN n)1557{1558GEN xp;1559long i, lx;1560ulong u;1561if (signe(n) != 1) return 0;1562xp = int_LSW(n);1563lx = lgefint(n);1564u = *xp;1565for (i = 3; i < lx; ++i)1566{1567if (u) return 0;1568xp = int_nextW(xp);1569u = *xp;1570}1571return !(u & (u-1));1572}15731574static long1575isprimepower_i(GEN n, GEN *pt, long flag)1576{1577pari_sp av = avma;1578long i, v;15791580if (typ(n) != t_INT) pari_err_TYPE("isprimepower", n);1581if (signe(n) <= 0) return 0;15821583if (lgefint(n) == 3)1584{1585ulong p;1586v = uisprimepower(n[2], &p);1587if (v)1588{1589if (pt) *pt = utoipos(p);1590return v;1591}1592return 0;1593}1594for (i = 0; i < 26; i++)1595{1596ulong p = tinyprimes[i];1597v = Z_lvalrem(n, p, &n);1598if (v)1599{1600set_avma(av);1601if (!is_pm1(n)) return 0;1602if (pt) *pt = utoipos(p);1603return v;1604}1605}1606/* p | n => p >= 103 */1607v = Z_isanypower_nosmalldiv(&n); /* expensive */1608if (!(flag? isprime(n): BPSW_psp(n))) return gc_long(av,0);1609if (pt) *pt = gerepilecopy(av, n); else set_avma(av);1610return v;1611}1612long1613isprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,1); }1614long1615ispseudoprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,0); }16161617long1618uisprimepower(ulong n, ulong *pp)1619{ /* We must have CUTOFF^11 >= ULONG_MAX and CUTOFF^3 < ULONG_MAX.1620* Tests suggest that 200-300 is the best range for 64-bit platforms. */1621const ulong CUTOFF = 200UL;1622const long TINYCUTOFF = 46; /* tinyprimes[45] = 199 */1623const ulong CUTOFF3 = CUTOFF*CUTOFF*CUTOFF;1624#ifdef LONG_IS_64BIT1625/* primes preceeding the appropriate root of ULONG_MAX. */1626const ulong ROOT9 = 137;1627const ulong ROOT8 = 251;1628const ulong ROOT7 = 563;1629const ulong ROOT5 = 7129;1630const ulong ROOT4 = 65521;1631#else1632const ulong ROOT9 = 11;1633const ulong ROOT8 = 13;1634const ulong ROOT7 = 23;1635const ulong ROOT5 = 83;1636const ulong ROOT4 = 251;1637#endif1638ulong mask;1639long v, i;1640int e;1641if (n < 2) return 0;1642if (!odd(n)) {1643if (n & (n-1)) return 0;1644*pp = 2; return vals(n);1645}1646if (n < 8) { *pp = n; return 1; } /* 3,5,7 */1647for (i = 1/*skip p=2*/; i < TINYCUTOFF; i++)1648{1649ulong p = tinyprimes[i];1650if (n % p == 0)1651{1652v = u_lvalrem(n, p, &n);1653if (n == 1) { *pp = p; return v; }1654return 0;1655}1656}1657/* p | n => p >= CUTOFF */16581659if (n < CUTOFF3)1660{1661if (n < CUTOFF*CUTOFF || uisprime_101(n)) { *pp = n; return 1; }1662if (uissquareall(n, &n)) { *pp = n; return 2; }1663return 0;1664}16651666/* Check for squares, fourth powers, and eighth powers as appropriate. */1667v = 1;1668if (uissquareall(n, &n)) {1669v <<= 1;1670if (CUTOFF <= ROOT4 && uissquareall(n, &n)) {1671v <<= 1;1672if (CUTOFF <= ROOT8 && uissquareall(n, &n)) v <<= 1;1673}1674}16751676if (CUTOFF > ROOT5) mask = 1;1677else1678{1679const ulong CUTOFF5 = CUTOFF3*CUTOFF*CUTOFF;1680if (n < CUTOFF5) mask = 1; else mask = 3;1681if (CUTOFF <= ROOT7)1682{1683const ulong CUTOFF7 = CUTOFF5*CUTOFF*CUTOFF;1684if (n >= CUTOFF7) mask = 7;1685}1686}16871688if (CUTOFF <= ROOT9 && (e = uis_357_power(n, &n, &mask))) { v *= e; mask=1; }1689if ((e = uis_357_power(n, &n, &mask))) v *= e;16901691if (uisprime_101(n)) { *pp = n; return v; }1692return 0;1693}16941695/*********************************************************************/1696/** **/1697/** KRONECKER SYMBOL **/1698/** **/1699/*********************************************************************/1700/* t = 3,5 mod 8 ? (= 2 not a square mod t) */1701static int1702ome(long t)1703{1704switch(t & 7)1705{1706case 3:1707case 5: return 1;1708default: return 0;1709}1710}1711/* t a t_INT, is t = 3,5 mod 8 ? */1712static int1713gome(GEN t)1714{ return signe(t)? ome( mod2BIL(t) ): 0; }17151716/* assume y odd, return kronecker(x,y) * s */1717static long1718krouu_s(ulong x, ulong y, long s)1719{1720ulong x1 = x, y1 = y, z;1721while (x1)1722{1723long r = vals(x1);1724if (r)1725{1726if (odd(r) && ome(y1)) s = -s;1727x1 >>= r;1728}1729if (x1 & y1 & 2) s = -s;1730z = y1 % x1; y1 = x1; x1 = z;1731}1732return (y1 == 1)? s: 0;1733}17341735long1736kronecker(GEN x, GEN y)1737{1738pari_sp av = avma;1739long s = 1, r;1740ulong xu;17411742if (typ(x) != t_INT) pari_err_TYPE("kronecker",x);1743if (typ(y) != t_INT) pari_err_TYPE("kronecker",y);1744switch (signe(y))1745{1746case -1: y = negi(y); if (signe(x) < 0) s = -1; break;1747case 0: return is_pm1(x);1748}1749r = vali(y);1750if (r)1751{1752if (!mpodd(x)) return gc_long(av,0);1753if (odd(r) && gome(x)) s = -s;1754y = shifti(y,-r);1755}1756x = modii(x,y);1757while (lgefint(x) > 3) /* x < y */1758{1759GEN z;1760r = vali(x);1761if (r)1762{1763if (odd(r) && gome(y)) s = -s;1764x = shifti(x,-r);1765}1766/* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */1767if (mod2BIL(x) & mod2BIL(y) & 2) s = -s;1768z = remii(y,x); y = x; x = z;1769if (gc_needed(av,2))1770{1771if(DEBUGMEM>1) pari_warn(warnmem,"kronecker");1772gerepileall(av, 2, &x, &y);1773}1774}1775xu = itou(x);1776if (!xu) return is_pm1(y)? s: 0;1777r = vals(xu);1778if (r)1779{1780if (odd(r) && gome(y)) s = -s;1781xu >>= r;1782}1783/* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */1784if (xu & mod2BIL(y) & 2) s = -s;1785return gc_long(av, krouu_s(umodiu(y,xu), xu, s));1786}17871788long1789krois(GEN x, long y)1790{1791ulong yu;1792long s = 1;17931794if (y <= 0)1795{1796if (y == 0) return is_pm1(x);1797yu = (ulong)-y; if (signe(x) < 0) s = -1;1798}1799else1800yu = (ulong)y;1801if (!odd(yu))1802{1803long r;1804if (!mpodd(x)) return 0;1805r = vals(yu); yu >>= r;1806if (odd(r) && gome(x)) s = -s;1807}1808return krouu_s(umodiu(x, yu), yu, s);1809}1810/* assume y != 0 */1811long1812kroiu(GEN x, ulong y)1813{1814long r;1815if (odd(y)) return krouu_s(umodiu(x,y), y, 1);1816if (!mpodd(x)) return 0;1817r = vals(y); y >>= r;1818return krouu_s(umodiu(x,y), y, (odd(r) && gome(x))? -1: 1);1819}18201821/* assume y > 0, odd, return s * kronecker(x,y) */1822static long1823krouodd(ulong x, GEN y, long s)1824{1825long r;1826if (lgefint(y) == 3) return krouu_s(x, y[2], s);1827if (!x) return 0; /* y != 1 */1828r = vals(x);1829if (r)1830{1831if (odd(r) && gome(y)) s = -s;1832x >>= r;1833}1834/* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */1835if (x & mod2BIL(y) & 2) s = -s;1836return krouu_s(umodiu(y,x), x, s);1837}18381839long1840krosi(long x, GEN y)1841{1842const pari_sp av = avma;1843long s = 1, r;1844switch (signe(y))1845{1846case -1: y = negi(y); if (x < 0) s = -1; break;1847case 0: return (x==1 || x==-1);1848}1849r = vali(y);1850if (r)1851{1852if (!odd(x)) return gc_long(av,0);1853if (odd(r) && ome(x)) s = -s;1854y = shifti(y,-r);1855}1856if (x < 0) { x = -x; if (mod4(y) == 3) s = -s; }1857return gc_long(av, krouodd((ulong)x, y, s));1858}18591860long1861kroui(ulong x, GEN y)1862{1863const pari_sp av = avma;1864long s = 1, r;1865switch (signe(y))1866{1867case -1: y = negi(y); break;1868case 0: return x==1UL;1869}1870r = vali(y);1871if (r)1872{1873if (!odd(x)) return gc_long(av,0);1874if (odd(r) && ome(x)) s = -s;1875y = shifti(y,-r);1876}1877return gc_long(av, krouodd(x, y, s));1878}18791880long1881kross(long x, long y)1882{1883ulong yu;1884long s = 1;18851886if (y <= 0)1887{1888if (y == 0) return (labs(x)==1);1889yu = (ulong)-y; if (x < 0) s = -1;1890}1891else1892yu = (ulong)y;1893if (!odd(yu))1894{1895long r;1896if (!odd(x)) return 0;1897r = vals(yu); yu >>= r;1898if (odd(r) && ome(x)) s = -s;1899}1900x %= (long)yu; if (x < 0) x += yu;1901return krouu_s((ulong)x, yu, s);1902}19031904long1905krouu(ulong x, ulong y)1906{1907long r;1908if (odd(y)) return krouu_s(x, y, 1);1909if (!odd(x)) return 0;1910r = vals(y); y >>= r;1911return krouu_s(x, y, (odd(r) && ome(x))? -1: 1);1912}19131914/*********************************************************************/1915/** **/1916/** HILBERT SYMBOL **/1917/** **/1918/*********************************************************************/1919/* x,y are t_INT or t_REAL */1920static long1921mphilbertoo(GEN x, GEN y)1922{1923long sx = signe(x), sy = signe(y);1924if (!sx || !sy) return 0;1925return (sx < 0 && sy < 0)? -1: 1;1926}19271928long1929hilbertii(GEN x, GEN y, GEN p)1930{1931pari_sp av;1932long oddvx, oddvy, z;19331934if (!p) return mphilbertoo(x,y);1935if (is_pm1(p) || signe(p) < 0) pari_err_PRIME("hilbertii",p);1936if (!signe(x) || !signe(y)) return 0;1937av = avma;1938oddvx = odd(Z_pvalrem(x,p,&x));1939oddvy = odd(Z_pvalrem(y,p,&y));1940/* x, y are p-units, compute hilbert(x * p^oddvx, y * p^oddvy, p) */1941if (absequaliu(p, 2))1942{1943z = (Mod4(x) == 3 && Mod4(y) == 3)? -1: 1;1944if (oddvx && gome(y)) z = -z;1945if (oddvy && gome(x)) z = -z;1946}1947else1948{1949z = (oddvx && oddvy && mod4(p) == 3)? -1: 1;1950if (oddvx && kronecker(y,p) < 0) z = -z;1951if (oddvy && kronecker(x,p) < 0) z = -z;1952}1953return gc_long(av, z);1954}19551956static void1957err_prec(void) { pari_err_PREC("hilbert"); }1958static void1959err_p(GEN p, GEN q) { pari_err_MODULUS("hilbert", p,q); }1960static void1961err_oo(GEN p) { pari_err_MODULUS("hilbert", p, strtoGENstr("oo")); }19621963/* x t_INTMOD, *pp = prime or NULL [ unset, set it to x.mod ].1964* Return lift(x) provided it's p-adic accuracy is large enough to decide1965* hilbert()'s value [ problem at p = 2 ] */1966static GEN1967lift_intmod(GEN x, GEN *pp)1968{1969GEN p = *pp, N = gel(x,1);1970x = gel(x,2);1971if (!p)1972{1973*pp = p = N;1974switch(itos_or_0(p))1975{1976case 2:1977case 4: err_prec();1978}1979return x;1980}1981if (!signe(p)) err_oo(N);1982if (absequaliu(p,2))1983{ if (vali(N) <= 2) err_prec(); }1984else1985{ if (!dvdii(N,p)) err_p(N,p); }1986if (!signe(x)) err_prec();1987return x;1988}1989/* x t_PADIC, *pp = prime or NULL [ unset, set it to x.p ].1990* Return lift(x)*p^(v(x) mod 2) provided it's p-adic accuracy is large enough1991* to decide hilbert()'s value [ problem at p = 2 ]*/1992static GEN1993lift_padic(GEN x, GEN *pp)1994{1995GEN p = *pp, q = gel(x,2), y = gel(x,4);1996if (!p) *pp = p = q;1997else if (!equalii(p,q)) err_p(p, q);1998if (absequaliu(p,2) && precp(x) <= 2) err_prec();1999if (!signe(y)) err_prec();2000return odd(valp(x))? mulii(p,y): y;2001}20022003long2004hilbert(GEN x, GEN y, GEN p)2005{2006pari_sp av = avma;2007long tx = typ(x), ty = typ(y);20082009if (p && typ(p) != t_INT) pari_err_TYPE("hilbert",p);2010if (tx == t_REAL)2011{2012if (p && signe(p)) err_oo(p);2013switch (ty)2014{2015case t_INT:2016case t_REAL: return mphilbertoo(x,y);2017case t_FRAC: return mphilbertoo(x,gel(y,1));2018default: pari_err_TYPE2("hilbert",x,y);2019}2020}2021if (ty == t_REAL)2022{2023if (p && signe(p)) err_oo(p);2024switch (tx)2025{2026case t_INT:2027case t_REAL: return mphilbertoo(x,y);2028case t_FRAC: return mphilbertoo(gel(x,1),y);2029default: pari_err_TYPE2("hilbert",x,y);2030}2031}2032if (tx == t_INTMOD) { x = lift_intmod(x, &p); tx = t_INT; }2033if (ty == t_INTMOD) { y = lift_intmod(y, &p); ty = t_INT; }20342035if (tx == t_PADIC) { x = lift_padic(x, &p); tx = t_INT; }2036if (ty == t_PADIC) { y = lift_padic(y, &p); ty = t_INT; }20372038if (tx == t_FRAC) { tx = t_INT; x = p? mulii(gel(x,1),gel(x,2)): gel(x,1); }2039if (ty == t_FRAC) { ty = t_INT; y = p? mulii(gel(y,1),gel(y,2)): gel(y,1); }20402041if (tx != t_INT || ty != t_INT) pari_err_TYPE2("hilbert",x,y);2042if (p && !signe(p)) p = NULL;2043return gc_long(av, hilbertii(x,y,p));2044}20452046/*******************************************************************/2047/* */2048/* SQUARE ROOT MODULO p */2049/* */2050/*******************************************************************/2051static void2052checkp(ulong q, ulong p)2053{ if (!q) pari_err_PRIME("Fl_nonsquare",utoipos(p)); }2054/* p = 1 (mod 4) prime, return the first quadratic nonresidue, a prime */2055static ulong2056nonsquare1_Fl(ulong p)2057{2058forprime_t S;2059ulong q;2060if ((p & 7UL) != 1) return 2UL;2061q = p % 3; if (q == 2) return 3UL;2062checkp(q, p);2063q = p % 5; if (q == 2 || q == 3) return 5UL;2064checkp(q, p);2065q = p % 7; if (q != 4 && q >= 3) return 7UL;2066checkp(q, p);2067u_forprime_init(&S, 11, p);2068while ((q = u_forprime_next(&S)))2069{2070long i = krouu(q, p);2071if (i < 0) return q;2072checkp(q, p);2073}2074checkp(0, p);2075return 0; /*LCOV_EXCL_LINE*/2076}2077/* p > 2 a prime */2078ulong2079nonsquare_Fl(ulong p)2080{ return ((p & 3UL) == 3)? p-1: nonsquare1_Fl(p); }20812082ulong2083Fl_2gener_pre(ulong p, ulong pi)2084{2085ulong p1 = p-1;2086long e = vals(p1);2087if (e == 1) return p1;2088return Fl_powu_pre(nonsquare1_Fl(p), p1 >> e, p, pi);2089}20902091/* Tonelli-Shanks. Assume p is prime and (a,p) != -1. */2092ulong2093Fl_sqrt_pre_i(ulong a, ulong y, ulong p, ulong pi)2094{2095long i, e, k;2096ulong p1, q, v, w;20972098if (!a) return 0;2099p1 = p - 1; e = vals(p1);2100if (e == 0) /* p = 2 */2101{2102if (p != 2) pari_err_PRIME("Fl_sqrt [modulus]",utoi(p));2103return ((a & 1) == 0)? 0: 1;2104}2105if (e == 1)2106{2107v = Fl_powu_pre(a, (p+1) >> 2, p, pi);2108if (Fl_sqr_pre(v, p, pi) != a) return ~0UL;2109p1 = p - v; if (v > p1) v = p1;2110return v;2111}2112q = p1 >> e; /* q = (p-1)/2^oo is odd */2113p1 = Fl_powu_pre(a, q >> 1, p, pi); /* a ^ [(q-1)/2] */2114if (!p1) return 0;2115v = Fl_mul_pre(a, p1, p, pi);2116w = Fl_mul_pre(v, p1, p, pi);2117if (!y) y = Fl_powu_pre(nonsquare1_Fl(p), q, p, pi);2118while (w != 1)2119{ /* a*w = v^2, y primitive 2^e-th root of 12120a square --> w even power of y, hence w^(2^(e-1)) = 1 */2121p1 = Fl_sqr_pre(w,p,pi);2122for (k=1; p1 != 1 && k < e; k++) p1 = Fl_sqr_pre(p1,p,pi);2123if (k == e) return ~0UL;2124/* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */2125p1 = y;2126for (i=1; i < e-k; i++) p1 = Fl_sqr_pre(p1, p, pi);2127y = Fl_sqr_pre(p1, p, pi); e = k;2128w = Fl_mul_pre(y, w, p, pi);2129v = Fl_mul_pre(v, p1, p, pi);2130}2131p1 = p - v; if (v > p1) v = p1;2132return v;2133}21342135ulong2136Fl_sqrt(ulong a, ulong p)2137{2138ulong pi = get_Fl_red(p);2139return Fl_sqrt_pre_i(a, 0, p, pi);2140}21412142ulong2143Fl_sqrt_pre(ulong a, ulong p, ulong pi)2144{2145return Fl_sqrt_pre_i(a, 0, p, pi);2146}21472148static ulong2149Fl_lgener_pre_all(ulong l, long e, ulong r, ulong p, ulong pi, ulong *pt_m)2150{2151ulong x, y, m;2152ulong le1 = upowuu(l, e-1);2153for (x = 2; ; x++)2154{2155y = Fl_powu_pre(x, r, p, pi);2156if (y==1) continue;2157m = Fl_powu_pre(y, le1, p, pi);2158if (m != 1) break;2159}2160*pt_m = m;2161return y;2162}21632164/* solve x^l = a , l prime in G of order q.2165*2166* q = (l^e)*r, e >= 1, (r,l) = 12167* y generates the l-Sylow of G2168* m = y^(l^(e-1)) != 1 */2169static ulong2170Fl_sqrtl_raw(ulong a, ulong l, ulong e, ulong r, ulong p, ulong pi, ulong y, ulong m)2171{2172ulong p1, v, w, z, dl;2173ulong u2;2174if (a==0) return a;2175u2 = Fl_inv(l%r, r);2176v = Fl_powu_pre(a, u2, p, pi);2177w = Fl_powu_pre(v, l, p, pi);2178w = Fl_mul_pre(w, Fl_inv(a, p), p, pi);2179if (w==1) return v;2180if (y==0) y = Fl_lgener_pre_all(l, e, r, p, pi, &m);2181while (w!=1)2182{2183ulong k = 0;2184p1 = w;2185do2186{2187z = p1; p1 = Fl_powu_pre(p1, l, p, pi);2188if (++k == e) return ULONG_MAX;2189} while (p1!=1);2190dl = Fl_log_pre(z, m, l, p, pi);2191dl = Fl_neg(dl, l);2192p1 = Fl_powu_pre(y,dl*upowuu(l,e-k-1),p,pi);2193m = Fl_powu_pre(m, dl, p, pi);2194e = k;2195v = Fl_mul_pre(p1,v,p,pi);2196y = Fl_powu_pre(p1,l,p,pi);2197w = Fl_mul_pre(y,w,p,pi);2198}2199return v;2200}22012202static ulong2203Fl_sqrtl_i(ulong a, ulong l, ulong p, ulong pi, ulong y, ulong m)2204{2205ulong r, e = u_lvalrem(p-1, l, &r);2206return Fl_sqrtl_raw(a, l, e, r, p, pi, y, m);2207}22082209ulong2210Fl_sqrtl_pre(ulong a, ulong l, ulong p, ulong pi)2211{2212return Fl_sqrtl_i(a, l, p, pi, 0, 0);2213}22142215ulong2216Fl_sqrtl(ulong a, ulong l, ulong p)2217{2218ulong pi = get_Fl_red(p);2219return Fl_sqrtl_i(a, l, p, pi, 0, 0);2220}22212222ulong2223Fl_sqrtn_pre(ulong a, long n, ulong p, ulong pi, ulong *zetan)2224{2225ulong m, q = p-1, z;2226ulong nn = n >= 0 ? (ulong)n: -(ulong)n;2227if (a==0)2228{2229if (n < 0) pari_err_INV("Fl_sqrtn", mkintmod(gen_0,utoi(p)));2230if (zetan) *zetan = 1UL;2231return 0;2232}2233if (n==1)2234{2235if (zetan) *zetan = 1;2236return n < 0? Fl_inv(a,p): a;2237}2238if (n==2)2239{2240if (zetan) *zetan = p-1;2241return Fl_sqrt_pre_i(a, 0, p, pi);2242}2243if (a == 1 && !zetan) return a;2244m = ugcd(nn, q);2245z = 1;2246if (m!=1)2247{2248GEN F = factoru(m);2249long i, j, e;2250ulong r, zeta, y, l;2251for (i = nbrows(F); i; i--)2252{2253l = ucoeff(F,i,1);2254j = ucoeff(F,i,2);2255e = u_lvalrem(q,l, &r);2256y = Fl_lgener_pre_all(l, e, r, p, pi, &zeta);2257if (zetan)2258z = Fl_mul_pre(z, Fl_powu_pre(y, upowuu(l,e-j), p, pi), p, pi);2259if (a!=1)2260do2261{2262a = Fl_sqrtl_raw(a, l, e, r, p, pi, y, zeta);2263if (a==ULONG_MAX) return ULONG_MAX;2264} while (--j);2265}2266}2267if (m != nn)2268{2269ulong qm = q/m, nm = nn/m;2270a = Fl_powu_pre(a, Fl_inv(nm%qm, qm), p, pi);2271}2272if (n < 0) a = Fl_inv(a, p);2273if (zetan) *zetan = z;2274return a;2275}22762277ulong2278Fl_sqrtn(ulong a, long n, ulong p, ulong *zetan)2279{2280ulong pi = get_Fl_red(p);2281return Fl_sqrtn_pre(a, n, p, pi, zetan);2282}22832284/* Cipolla is better than Tonelli-Shanks when e = v_2(p-1) is "too big".2285* Otherwise, is a constant times worse; for p = 3 (mod 4), is about 3 times worse,2286* and in average is about 2 or 2.5 times worse. But try both algorithms for2287* S(n) = (2^n+3)^2-8 with n = 750, 771, 779, 790, 874, 1176, 1728, 2604, etc.2288*2289* If X^2 := t^2 - a is not a square in F_p (so X is in F_p^2), then2290* (t+X)^(p+1) = (t-X)(t+X) = a, hence sqrt(a) = (t+X)^((p+1)/2) in F_p^2.2291* If (a|p)=1, then sqrt(a) is in F_p.2292* cf: LNCS 2286, pp 430-434 (2002) [Gonzalo Tornaria] */22932294/* compute y^2, y = y[1] + y[2] X */2295static GEN2296sqrt_Cipolla_sqr(void *data, GEN y)2297{2298GEN u = gel(y,1), v = gel(y,2), p = gel(data,2), n = gel(data,3);2299GEN u2 = sqri(u), v2 = sqri(v);2300v = subii(sqri(addii(v,u)), addii(u2,v2));2301u = addii(u2, mulii(v2,n));2302/* NOT mkvec2: must be gerepileupto-able */2303retmkvec2(modii(u,p), modii(v,p));2304}2305/* compute (t+X) y^2 */2306static GEN2307sqrt_Cipolla_msqr(void *data, GEN y)2308{2309GEN u = gel(y,1), v = gel(y,2), a = gel(data,1), p = gel(data,2), gt = gel(data,4);2310ulong t = gt[2];2311GEN d = addii(u, mului(t,v)), d2= sqri(d);2312GEN b = remii(mulii(a,v), p);2313u = subii(mului(t,d2), mulii(b,addii(u,d)));2314v = subii(d2, mulii(b,v));2315/* NOT mkvec2: must be gerepileupto-able */2316retmkvec2(modii(u,p), modii(v,p));2317}2318/* assume a reduced mod p [ otherwise correct but inefficient ] */2319static GEN2320sqrt_Cipolla(GEN a, GEN p)2321{2322pari_sp av1;2323GEN u, v, n, y, pov2;2324ulong t;23252326if (kronecker(a, p) < 0) return NULL;2327pov2 = shifti(p,-1);2328if (cmpii(a,pov2) > 0) a = subii(a,p); /* center: avoid multiplying by huge base*/23292330av1 = avma;2331for(t=1; ; t++)2332{2333n = subsi((long)(t*t), a);2334if (kronecker(n, p) < 0) break;2335set_avma(av1);2336}23372338/* compute (t+X)^((p-1)/2) =: u+vX */2339u = utoipos(t);2340y = gen_pow_fold(mkvec2(u, gen_1), pov2, mkvec4(a,p,n,u),2341sqrt_Cipolla_sqr, sqrt_Cipolla_msqr);2342/* Now u+vX = (t+X)^((p-1)/2); thus2343* (u+vX)(t+X) = sqrt(a) + 0 X2344* Whence,2345* sqrt(a) = (u+vt)t - v*a2346* 0 = (u+vt)2347* Thus a square root is v*a */23482349v = Fp_mul(gel(y, 2), a, p);2350if (cmpii(v,pov2) > 0) v = subii(p,v);2351return v;2352}23532354/* Return NULL if p is found to be composite */2355static GEN2356Fp_2gener_all(long e, GEN p)2357{2358GEN y, m;2359long k;2360GEN q = shifti(subiu(p,1), -e); /* q = (p-1)/2^oo is odd */2361if (e==0 && !equaliu(p,2)) return NULL;2362for (k=2; ; k++)2363{2364long i = krosi(k, p);2365if (i >= 0)2366{2367if (i) continue;2368return NULL;2369}2370y = m = Fp_pow(utoi(k), q, p);2371for (i=1; i<e; i++)2372if (equali1(m = Fp_sqr(m, p))) break;2373if (i == e) break; /* success */2374}2375return y;2376}23772378/* Return NULL if p is found to be composite */2379GEN2380Fp_2gener(GEN p)2381{ return Fp_2gener_all(vali(subis(p,1)),p); }23822383/* smallest square root */2384static GEN2385choose_sqrt(GEN v, GEN p)2386{2387pari_sp av = avma;2388GEN q = subii(p,v);2389if (cmpii(v,q) > 0) v = q; else set_avma(av);2390return v;2391}2392/* Tonelli-Shanks. Assume p is prime and return NULL if (a,p) = -1. */2393GEN2394Fp_sqrt_i(GEN a, GEN y, GEN p)2395{2396pari_sp av = avma;2397long i, k, e;2398GEN p1, q, v, w;23992400if (typ(a) != t_INT) pari_err_TYPE("Fp_sqrt",a);2401if (typ(p) != t_INT) pari_err_TYPE("Fp_sqrt",p);2402if (signe(p) <= 0 || equali1(p)) pari_err_PRIME("Fp_sqrt",p);2403if (lgefint(p) == 3)2404{2405ulong pp = uel(p,2), u = Fl_sqrt(umodiu(a, pp), pp);2406if (u == ~0UL) return NULL;2407return utoi(u);2408}24092410a = modii(a, p); if (!signe(a)) { set_avma(av); return gen_0; }2411p1 = subiu(p,1); e = vali(p1);2412if (e <= 2)2413{ /* direct formulas more efficient */2414pari_sp av2;2415if (e == 0) pari_err_PRIME("Fp_sqrt [modulus]",p); /* p != 2 */2416if (e == 1)2417{2418q = addiu(shifti(p1,-2),1); /* (p+1) / 4 */2419v = Fp_pow(a, q, p);2420}2421else2422{ /* Atkin's formula */2423GEN i, a2 = shifti(a,1);2424if (cmpii(a2,p) >= 0) a2 = subii(a2,p);2425q = shifti(p1, -3); /* (p-5)/8 */2426v = Fp_pow(a2, q, p);2427i = Fp_mul(a2, Fp_sqr(v,p), p); /* i^2 = -1 */2428v = Fp_mul(a, Fp_mul(v, subiu(i,1), p), p);2429}2430av2 = avma;2431/* must check equality in case (a/p) = -1 or p not prime */2432e = equalii(Fp_sqr(v,p), a); set_avma(av2);2433return e? gerepileuptoint(av,choose_sqrt(v,p)): NULL;2434}2435/* On average, Cipolla is better than Tonelli/Shanks if and only if2436* e(e-1) > 8*log2(n)+20, see LNCS 2286 pp 430 [GTL] */2437if (e*(e-1) > 20 + 8 * expi(p))2438{2439v = sqrt_Cipolla(a,p); if (!v) return gc_NULL(av);2440return gerepileuptoint(av,v);2441}2442if (!y)2443{2444y = Fp_2gener_all(e, p);2445if (!y) pari_err_PRIME("Fp_sqrt [modulus]",p);2446}2447q = shifti(p1,-e); /* q = (p-1)/2^oo is odd */2448p1 = Fp_pow(a, shifti(q,-1), p); /* a ^ (q-1)/2 */2449v = Fp_mul(a, p1, p);2450w = Fp_mul(v, p1, p);2451while (!equali1(w))2452{ /* a*w = v^2, y primitive 2^e-th root of 12453a square --> w even power of y, hence w^(2^(e-1)) = 1 */2454p1 = Fp_sqr(w,p);2455for (k=1; !equali1(p1) && k < e; k++) p1 = Fp_sqr(p1,p);2456if (k == e) return gc_NULL(av); /* p composite or (a/p) != 1 */2457/* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */2458p1 = y;2459for (i=1; i < e-k; i++) p1 = Fp_sqr(p1,p);2460y = Fp_sqr(p1, p); e = k;2461w = Fp_mul(y, w, p);2462v = Fp_mul(v, p1, p);2463if (gc_needed(av,1))2464{2465if(DEBUGMEM>1) pari_warn(warnmem,"Fp_sqrt");2466gerepileall(av,3, &y,&w,&v);2467}2468}2469return gerepileuptoint(av, choose_sqrt(v,p));2470}24712472GEN2473Fp_sqrt(GEN a, GEN p)2474{2475return Fp_sqrt_i(a, NULL, p);2476}24772478/*********************************************************************/2479/** **/2480/** GCD & BEZOUT **/2481/** **/2482/*********************************************************************/24832484GEN2485lcmii(GEN x, GEN y)2486{2487pari_sp av;2488GEN a, b;2489if (!signe(x) || !signe(y)) return gen_0;2490av = avma; a = gcdii(x,y);2491if (absequalii(a,y)) { set_avma(av); return absi(x); }2492if (!equali1(a)) y = diviiexact(y,a);2493b = mulii(x,y); setabssign(b); return gerepileuptoint(av, b);2494}24952496/* given x in assume 0 < x < N; return u in (Z/NZ)^* such that u x = gcd(x,N) (mod N);2497* set *pd = gcd(x,N) */2498GEN2499Fp_invgen(GEN x, GEN N, GEN *pd)2500{2501GEN d, d0, e, v;2502if (lgefint(N) == 3)2503{2504ulong dd, NN = N[2], xx = umodiu(x,NN);2505if (!xx) { *pd = N; return gen_0; }2506xx = Fl_invgen(xx, NN, &dd);2507*pd = utoi(dd); return utoi(xx);2508}2509*pd = d = bezout(x, N, &v, NULL);2510if (equali1(d)) return v;2511/* vx = gcd(x,N) (mod N), v coprime to N/d but need not be coprime to N */2512e = diviiexact(N,d);2513d0 = Z_ppo(d, e); /* d = d0 d1, d0 coprime to N/d, rad(d1) | N/d */2514if (equali1(d0)) return v;2515if (!equalii(d,d0)) e = lcmii(e, diviiexact(d,d0));2516return Z_chinese_coprime(v, gen_1, e, d0, mulii(e,d0));2517}25182519/*********************************************************************/2520/** **/2521/** CHINESE REMAINDERS **/2522/** **/2523/*********************************************************************/25242525/* Chinese Remainder Theorem. x and y must have the same type (integermod,2526* polymod, or polynomial/vector/matrix recursively constructed with these2527* as coefficients). Creates (with the same type) a z in the same residue2528* class as x and the same residue class as y, if it is possible.2529*2530* We also allow (during recursion) two identical objects even if they are2531* not integermod or polymod. For example:2532*2533* ? x = [1, Mod(5, 11), Mod(X + Mod(2, 7), X^2 + 1)];2534* ? y = [1, Mod(7, 17), Mod(X + Mod(0, 3), X^2 + 1)];2535* ? chinese(x, y)2536* %3 = [1, Mod(16, 187), Mod(X + mod(9, 21), X^2 + 1)] */25372538static GEN2539gen_chinese(GEN x, GEN(*f)(GEN,GEN))2540{2541GEN z = gassoc_proto(f,x,NULL);2542if (z == gen_1) retmkintmod(gen_0,gen_1);2543return z;2544}25452546/* x t_INTMOD, y t_POLMOD; promote x to t_POLMOD mod Pol(x.mod) then2547* call chinese: makes Mod(0,1) a better "neutral" element */2548static GEN2549chinese_intpol(GEN x,GEN y)2550{2551pari_sp av = avma;2552GEN z = mkpolmod(gel(x,2), scalarpol_shallow(gel(x,1), varn(gel(y,1))));2553return gerepileupto(av, chinese(z, y));2554}25552556GEN2557chinese1(GEN x) { return gen_chinese(x,chinese); }25582559GEN2560chinese(GEN x, GEN y)2561{2562pari_sp av;2563long tx = typ(x), ty;2564GEN z,p1,p2,d,u,v;25652566if (!y) return chinese1(x);2567if (gidentical(x,y)) return gcopy(x);2568ty = typ(y);2569if (tx == ty) switch(tx)2570{2571case t_POLMOD:2572{2573GEN A = gel(x,1), B = gel(y,1);2574GEN a = gel(x,2), b = gel(y,2);2575if (varn(A)!=varn(B)) pari_err_VAR("chinese",A,B);2576if (RgX_equal(A,B)) retmkpolmod(chinese(a,b), gcopy(A)); /*same modulus*/2577av = avma;2578d = RgX_extgcd(A,B,&u,&v);2579p2 = gsub(b, a);2580if (!gequal0(gmod(p2, d))) break;2581p1 = gdiv(A,d);2582p2 = gadd(a, gmul(gmul(u,p1), p2));25832584z = cgetg(3, t_POLMOD);2585gel(z,1) = gmul(p1,B);2586gel(z,2) = gmod(p2,gel(z,1));2587return gerepileupto(av, z);2588}2589case t_INTMOD:2590{2591GEN A = gel(x,1), B = gel(y,1);2592GEN a = gel(x,2), b = gel(y,2), c, d, C, U;2593z = cgetg(3,t_INTMOD);2594Z_chinese_pre(A, B, &C, &U, &d);2595c = Z_chinese_post(a, b, C, U, d);2596if (!c) pari_err_OP("chinese", x,y);2597set_avma((pari_sp)z);2598gel(z,1) = icopy(C);2599gel(z,2) = icopy(c); return z;2600}2601case t_POL:2602{2603long i, lx = lg(x), ly = lg(y);2604if (varn(x) != varn(y)) break;2605if (lx < ly) { swap(x,y); lswap(lx,ly); }2606z = cgetg(lx, t_POL); z[1] = x[1];2607for (i=2; i<ly; i++) gel(z,i) = chinese(gel(x,i),gel(y,i));2608for ( ; i<lx; i++) gel(z,i) = gcopy(gel(x,i));2609return z;2610}26112612case t_VEC: case t_COL: case t_MAT:2613{2614long i, lx;2615z = cgetg_copy(x, &lx); if (lx!=lg(y)) break;2616for (i=1; i<lx; i++) gel(z,i) = chinese(gel(x,i),gel(y,i));2617return z;2618}2619}2620if (tx == t_POLMOD && ty == t_INTMOD) return chinese_intpol(y,x);2621if (ty == t_POLMOD && tx == t_INTMOD) return chinese_intpol(x,y);2622pari_err_OP("chinese",x,y);2623return NULL; /* LCOV_EXCL_LINE */2624}26252626/* init chinese(Mod(.,A), Mod(.,B)) */2627void2628Z_chinese_pre(GEN A, GEN B, GEN *pC, GEN *pU, GEN *pd)2629{2630GEN u, d = bezout(A,B,&u,NULL); /* U = u(A/d), u(A/d) + v(B/d) = 1 */2631GEN t = diviiexact(A,d);2632*pU = mulii(u, t);2633*pC = mulii(t, B);2634if (pd) *pd = d;2635}2636/* Assume C = lcm(A, B), U = 0 mod (A/d), U = 1 mod (B/d), a = b mod d,2637* where d = gcd(A,B) or NULL, return x = a (mod A), b (mod B).2638* If d not NULL, check whether a = b mod d. */2639GEN2640Z_chinese_post(GEN a, GEN b, GEN C, GEN U, GEN d)2641{2642GEN b_a;2643if (!signe(a))2644{2645if (d && !dvdii(b, d)) return NULL;2646return Fp_mul(b, U, C);2647}2648b_a = subii(b,a);2649if (d && !dvdii(b_a, d)) return NULL;2650return modii(addii(a, mulii(U, b_a)), C);2651}2652static ulong2653u_chinese_post(ulong a, ulong b, ulong C, ulong U)2654{2655if (!a) return Fl_mul(b, U, C);2656return Fl_add(a, Fl_mul(U, Fl_sub(b,a,C), C), C);2657}26582659GEN2660Z_chinese(GEN a, GEN b, GEN A, GEN B)2661{2662pari_sp av = avma;2663GEN C, U; Z_chinese_pre(A, B, &C, &U, NULL);2664return gerepileuptoint(av, Z_chinese_post(a,b, C, U, NULL));2665}2666GEN2667Z_chinese_all(GEN a, GEN b, GEN A, GEN B, GEN *pC)2668{2669GEN U; Z_chinese_pre(A, B, pC, &U, NULL);2670return Z_chinese_post(a,b, *pC, U, NULL);2671}26722673/* return lift(chinese(a mod A, b mod B))2674* assume(A,B)=1, a,b,A,B integers and C = A*B */2675GEN2676Z_chinese_coprime(GEN a, GEN b, GEN A, GEN B, GEN C)2677{2678pari_sp av = avma;2679GEN U = mulii(Fp_inv(A,B), A);2680return gerepileuptoint(av, Z_chinese_post(a,b,C,U, NULL));2681}2682ulong2683u_chinese_coprime(ulong a, ulong b, ulong A, ulong B, ulong C)2684{ return u_chinese_post(a,b,C, A * Fl_inv(A % B,B)); }26852686/* chinese1 for coprime moduli in Z */2687static GEN2688chinese1_coprime_Z_aux(GEN x, GEN y)2689{2690GEN z = cgetg(3, t_INTMOD);2691GEN A = gel(x,1), a = gel(x, 2);2692GEN B = gel(y,1), b = gel(y, 2), C = mulii(A,B);2693pari_sp av = avma;2694GEN U = mulii(Fp_inv(A,B), A);2695gel(z,2) = gerepileuptoint(av, Z_chinese_post(a,b,C,U, NULL));2696gel(z,1) = C; return z;2697}2698GEN2699chinese1_coprime_Z(GEN x) {return gen_chinese(x,chinese1_coprime_Z_aux);}27002701/*********************************************************************/2702/** **/2703/** MODULAR EXPONENTIATION **/2704/** **/2705/*********************************************************************/27062707/* xa, ya = t_VECSMALL */2708GEN2709ZV_producttree(GEN xa)2710{2711long n = lg(xa)-1;2712long m = n==1 ? 1: expu(n-1)+1;2713GEN T = cgetg(m+1, t_VEC), t;2714long i, j, k;2715t = cgetg(((n+1)>>1)+1, t_VEC);2716if (typ(xa)==t_VECSMALL)2717{2718for (j=1, k=1; k<n; j++, k+=2)2719gel(t, j) = muluu(xa[k], xa[k+1]);2720if (k==n) gel(t, j) = utoi(xa[k]);2721} else {2722for (j=1, k=1; k<n; j++, k+=2)2723gel(t, j) = mulii(gel(xa,k), gel(xa,k+1));2724if (k==n) gel(t, j) = icopy(gel(xa,k));2725}2726gel(T,1) = t;2727for (i=2; i<=m; i++)2728{2729GEN u = gel(T, i-1);2730long n = lg(u)-1;2731t = cgetg(((n+1)>>1)+1, t_VEC);2732for (j=1, k=1; k<n; j++, k+=2)2733gel(t, j) = mulii(gel(u, k), gel(u, k+1));2734if (k==n) gel(t, j) = gel(u, k);2735gel(T, i) = t;2736}2737return T;2738}27392740/* return [A mod P[i], i=1..#P], T = ZV_producttree(P) */2741GEN2742Z_ZV_mod_tree(GEN A, GEN P, GEN T)2743{2744long i,j,k;2745long m = lg(T)-1, n = lg(P)-1;2746GEN t;2747GEN Tp = cgetg(m+1, t_VEC);2748gel(Tp, m) = mkvec(modii(A, gmael(T,m,1)));2749for (i=m-1; i>=1; i--)2750{2751GEN u = gel(T, i);2752GEN v = gel(Tp, i+1);2753long n = lg(u)-1;2754t = cgetg(n+1, t_VEC);2755for (j=1, k=1; k<n; j++, k+=2)2756{2757gel(t, k) = modii(gel(v, j), gel(u, k));2758gel(t, k+1) = modii(gel(v, j), gel(u, k+1));2759}2760if (k==n) gel(t, k) = gel(v, j);2761gel(Tp, i) = t;2762}2763{2764GEN u = gel(T, i+1);2765GEN v = gel(Tp, i+1);2766long l = lg(u)-1;2767if (typ(P)==t_VECSMALL)2768{2769GEN R = cgetg(n+1, t_VECSMALL);2770for (j=1, k=1; j<=l; j++, k+=2)2771{2772uel(R,k) = umodiu(gel(v, j), P[k]);2773if (k < n)2774uel(R,k+1) = umodiu(gel(v, j), P[k+1]);2775}2776return R;2777}2778else2779{2780GEN R = cgetg(n+1, t_VEC);2781for (j=1, k=1; j<=l; j++, k+=2)2782{2783gel(R,k) = modii(gel(v, j), gel(P,k));2784if (k < n)2785gel(R,k+1) = modii(gel(v, j), gel(P,k+1));2786}2787return R;2788}2789}2790}27912792/* T = ZV_producttree(P), R = ZV_chinesetree(P,T) */2793GEN2794ZV_chinese_tree(GEN A, GEN P, GEN T, GEN R)2795{2796long m = lg(T)-1, n = lg(A)-1;2797long i,j,k;2798GEN Tp = cgetg(m+1, t_VEC);2799GEN M = gel(T, 1);2800GEN t = cgetg(lg(M), t_VEC);2801if (typ(P)==t_VECSMALL)2802{2803for (j=1, k=1; k<n; j++, k+=2)2804{2805pari_sp av = avma;2806GEN a = mului(A[k], gel(R,k)), b = mului(A[k+1], gel(R,k+1));2807GEN tj = modii(addii(mului(P[k],b), mului(P[k+1],a)), gel(M,j));2808gel(t, j) = gerepileuptoint(av, tj);2809}2810if (k==n) gel(t, j) = modii(mului(A[k], gel(R,k)), gel(M, j));2811} else2812{2813for (j=1, k=1; k<n; j++, k+=2)2814{2815pari_sp av = avma;2816GEN a = mulii(gel(A,k), gel(R,k)), b = mulii(gel(A,k+1), gel(R,k+1));2817GEN tj = modii(addii(mulii(gel(P,k),b), mulii(gel(P,k+1),a)), gel(M,j));2818gel(t, j) = gerepileuptoint(av, tj);2819}2820if (k==n) gel(t, j) = modii(mulii(gel(A,k), gel(R,k)), gel(M, j));2821}2822gel(Tp, 1) = t;2823for (i=2; i<=m; i++)2824{2825GEN u = gel(T, i-1), M = gel(T, i);2826GEN t = cgetg(lg(M), t_VEC);2827GEN v = gel(Tp, i-1);2828long n = lg(v)-1;2829for (j=1, k=1; k<n; j++, k+=2)2830{2831pari_sp av = avma;2832gel(t, j) = gerepileuptoint(av, modii(addii(mulii(gel(u, k), gel(v, k+1)),2833mulii(gel(u, k+1), gel(v, k))), gel(M, j)));2834}2835if (k==n) gel(t, j) = gel(v, k);2836gel(Tp, i) = t;2837}2838return gmael(Tp,m,1);2839}28402841static GEN2842ncV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)2843{2844long i, l = lg(gel(vA,1)), n = lg(P);2845GEN mod = gmael(T, lg(T)-1, 1), V = cgetg(l, t_COL);2846for (i=1; i < l; i++)2847{2848pari_sp av = avma;2849GEN c, A = cgetg(n, typ(P));2850long j;2851for (j=1; j < n; j++) A[j] = mael(vA,j,i);2852c = Fp_center(ZV_chinese_tree(A, P, T, R), mod, m2);2853gel(V,i) = gerepileuptoint(av, c);2854}2855return V;2856}28572858static GEN2859nxV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)2860{2861long i, j, l, n = lg(P);2862GEN mod = gmael(T, lg(T)-1, 1), V, w;2863w = cgetg(n, t_VECSMALL);2864for(j=1; j<n; j++) w[j] = lg(gel(vA,j));2865l = vecsmall_max(w);2866V = cgetg(l, t_POL);2867V[1] = mael(vA,1,1);2868for (i=2; i < l; i++)2869{2870pari_sp av = avma;2871GEN c, A = cgetg(n, typ(P));2872if (typ(P)==t_VECSMALL)2873for (j=1; j < n; j++) A[j] = i < w[j] ? mael(vA,j,i): 0;2874else2875for (j=1; j < n; j++) gel(A,j) = i < w[j] ? gmael(vA,j,i): gen_0;2876c = Fp_center(ZV_chinese_tree(A, P, T, R), mod, m2);2877gel(V,i) = gerepileuptoint(av, c);2878}2879return ZX_renormalize(V, l);2880}28812882static GEN2883nxCV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)2884{2885long i, j, l = lg(gel(vA,1)), n = lg(P);2886GEN A = cgetg(n, t_VEC);2887GEN V = cgetg(l, t_COL);2888for (i=1; i < l; i++)2889{2890for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);2891gel(V,i) = nxV_polint_center_tree(A, P, T, R, m2);2892}2893return V;2894}28952896static GEN2897polint_chinese(GEN worker, GEN mA, GEN P)2898{2899long cnt, pending, n, i, j, l = lg(gel(mA,1));2900struct pari_mt pt;2901GEN done, va, M, A;2902pari_timer ti;29032904if (l == 1) return cgetg(1, t_MAT);2905cnt = pending = 0;2906n = lg(P);2907A = cgetg(n, t_VEC);2908va = mkvec(A);2909M = cgetg(l, t_MAT);2910if (DEBUGLEVEL>4) timer_start(&ti);2911if (DEBUGLEVEL>5) err_printf("Start parallel Chinese remainder: ");2912mt_queue_start_lim(&pt, worker, l-1);2913for (i=1; i<l || pending; i++)2914{2915long workid;2916for(j=1; j < n; j++) gel(A,j) = gmael(mA,j,i);2917mt_queue_submit(&pt, i, i<l? va: NULL);2918done = mt_queue_get(&pt, &workid, &pending);2919if (done)2920{2921gel(M,workid) = done;2922if (DEBUGLEVEL>5) err_printf("%ld%% ",(++cnt)*100/(l-1));2923}2924}2925if (DEBUGLEVEL>5) err_printf("\n");2926if (DEBUGLEVEL>4) timer_printf(&ti, "nmV_chinese_center");2927mt_queue_end(&pt);2928return M;2929}29302931GEN2932nxMV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2)2933{2934return nxCV_polint_center_tree(vA, P, T, R, m2);2935}29362937static GEN2938nxMV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2)2939{2940long i, j, l = lg(gel(vA,1)), n = lg(P);2941GEN A = cgetg(n, t_VEC);2942GEN V = cgetg(l, t_MAT);2943for (i=1; i < l; i++)2944{2945for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);2946gel(V,i) = nxCV_polint_center_tree(A, P, T, R, m2);2947}2948return V;2949}29502951static GEN2952nxMV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2)2953{2954GEN worker = snm_closure(is_entry("_nxMV_polint_worker"), mkvec4(T, R, P, m2));2955return polint_chinese(worker, mA, P);2956}29572958static GEN2959nmV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2)2960{2961long i, j, l = lg(gel(vA,1)), n = lg(P);2962GEN A = cgetg(n, t_VEC);2963GEN V = cgetg(l, t_MAT);2964for (i=1; i < l; i++)2965{2966for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);2967gel(V,i) = ncV_polint_center_tree(A, P, T, R, m2);2968}2969return V;2970}29712972GEN2973nmV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2)2974{2975return ncV_polint_center_tree(vA, P, T, R, m2);2976}29772978static GEN2979nmV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2)2980{2981GEN worker = snm_closure(is_entry("_polint_worker"), mkvec4(T, R, P, m2));2982return polint_chinese(worker, mA, P);2983}29842985/* return [A mod P[i], i=1..#P] */2986GEN2987Z_ZV_mod(GEN A, GEN P)2988{2989pari_sp av = avma;2990return gerepilecopy(av, Z_ZV_mod_tree(A, P, ZV_producttree(P)));2991}2992/* P a t_VECSMALL */2993GEN2994Z_nv_mod(GEN A, GEN P)2995{2996pari_sp av = avma;2997return gerepileuptoleaf(av, Z_ZV_mod_tree(A, P, ZV_producttree(P)));2998}2999/* B a ZX, T = ZV_producttree(P) */3000GEN3001ZX_nv_mod_tree(GEN B, GEN A, GEN T)3002{3003pari_sp av;3004long i, j, l = lg(B), n = lg(A)-1;3005GEN V = cgetg(n+1, t_VEC);3006for (j=1; j <= n; j++)3007{3008gel(V, j) = cgetg(l, t_VECSMALL);3009mael(V, j, 1) = B[1]&VARNBITS;3010}3011av = avma;3012for (i=2; i < l; i++)3013{3014GEN v = Z_ZV_mod_tree(gel(B, i), A, T);3015for (j=1; j <= n; j++)3016mael(V, j, i) = v[j];3017set_avma(av);3018}3019for (j=1; j <= n; j++)3020(void) Flx_renormalize(gel(V, j), l);3021return V;3022}30233024static GEN3025to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; }30263027GEN3028ZXX_nv_mod_tree(GEN P, GEN xa, GEN T, long w)3029{3030pari_sp av = avma;3031long i, j, l = lg(P), n = lg(xa)-1;3032GEN V = cgetg(n+1, t_VEC);3033for (j=1; j <= n; j++)3034{3035gel(V, j) = cgetg(l, t_POL);3036mael(V, j, 1) = P[1]&VARNBITS;3037}3038for (i=2; i < l; i++)3039{3040GEN v = ZX_nv_mod_tree(to_ZX(gel(P, i), w), xa, T);3041for (j=1; j <= n; j++)3042gmael(V, j, i) = gel(v,j);3043}3044for (j=1; j <= n; j++)3045(void) FlxX_renormalize(gel(V, j), l);3046return gerepilecopy(av, V);3047}30483049GEN3050ZXC_nv_mod_tree(GEN C, GEN xa, GEN T, long w)3051{3052pari_sp av = avma;3053long i, j, l = lg(C), n = lg(xa)-1;3054GEN V = cgetg(n+1, t_VEC);3055for (j = 1; j <= n; j++)3056gel(V, j) = cgetg(l, t_COL);3057for (i = 1; i < l; i++)3058{3059GEN v = ZX_nv_mod_tree(to_ZX(gel(C, i), w), xa, T);3060for (j = 1; j <= n; j++)3061gmael(V, j, i) = gel(v,j);3062}3063return gerepilecopy(av, V);3064}30653066GEN3067ZXM_nv_mod_tree(GEN M, GEN xa, GEN T, long w)3068{3069pari_sp av = avma;3070long i, j, l = lg(M), n = lg(xa)-1;3071GEN V = cgetg(n+1, t_VEC);3072for (j=1; j <= n; j++)3073gel(V, j) = cgetg(l, t_MAT);3074for (i=1; i < l; i++)3075{3076GEN v = ZXC_nv_mod_tree(gel(M, i), xa, T, w);3077for (j=1; j <= n; j++)3078gmael(V, j, i) = gel(v,j);3079}3080return gerepilecopy(av, V);3081}30823083GEN3084ZV_nv_mod_tree(GEN B, GEN A, GEN T)3085{3086pari_sp av;3087long i, j, l = lg(B), n = lg(A)-1;3088GEN V = cgetg(n+1, t_VEC);3089for (j=1; j <= n; j++)3090gel(V, j) = cgetg(l, t_VECSMALL);3091av = avma;3092for (i=1; i < l; i++)3093{3094GEN v = Z_ZV_mod_tree(gel(B, i), A, T);3095for (j=1; j <= n; j++)3096mael(V, j, i) = v[j];3097set_avma(av);3098}3099return V;3100}31013102GEN3103ZM_nv_mod_tree(GEN M, GEN xa, GEN T)3104{3105pari_sp av = avma;3106long i, j, l = lg(M), n = lg(xa)-1;3107GEN V = cgetg(n+1, t_VEC);3108for (j=1; j <= n; j++)3109gel(V, j) = cgetg(l, t_MAT);3110for (i=1; i < l; i++)3111{3112GEN v = ZV_nv_mod_tree(gel(M, i), xa, T);3113for (j=1; j <= n; j++)3114gmael(V, j, i) = gel(v,j);3115}3116return gerepilecopy(av, V);3117}31183119static GEN3120ZV_sqr(GEN z)3121{3122long i,l = lg(z);3123GEN x = cgetg(l, t_VEC);3124if (typ(z)==t_VECSMALL)3125for (i=1; i<l; i++) gel(x,i) = sqru(z[i]);3126else3127for (i=1; i<l; i++) gel(x,i) = sqri(gel(z,i));3128return x;3129}31303131static GEN3132ZT_sqr(GEN x)3133{3134if (typ(x) == t_INT)3135return sqri(x);3136pari_APPLY_type(t_VEC, ZT_sqr(gel(x,i)))3137}31383139static GEN3140ZV_invdivexact(GEN y, GEN x)3141{3142long i, l = lg(y);3143GEN z = cgetg(l,t_VEC);3144if (typ(x)==t_VECSMALL)3145for (i=1; i<l; i++)3146{3147pari_sp av = avma;3148ulong a = Fl_inv(umodiu(diviuexact(gel(y,i),x[i]), x[i]), x[i]);3149set_avma(av);3150gel(z,i) = utoi(a);3151}3152else3153for (i=1; i<l; i++)3154gel(z,i) = Fp_inv(diviiexact(gel(y,i), gel(x,i)), gel(x,i));3155return z;3156}31573158/* P t_VECSMALL or t_VEC of t_INT */3159GEN3160ZV_chinesetree(GEN P, GEN T)3161{3162GEN T2 = ZT_sqr(T), P2 = ZV_sqr(P);3163GEN mod = gmael(T,lg(T)-1,1);3164return ZV_invdivexact(Z_ZV_mod_tree(mod, P2, T2), P);3165}31663167static GEN3168gc_chinese(pari_sp av, GEN T, GEN a, GEN *pt_mod)3169{3170if (!pt_mod)3171return gerepileupto(av, a);3172else3173{3174GEN mod = gmael(T, lg(T)-1, 1);3175gerepileall(av, 2, &a, &mod);3176*pt_mod = mod;3177return a;3178}3179}31803181GEN3182ZV_chinese_center(GEN A, GEN P, GEN *pt_mod)3183{3184pari_sp av = avma;3185GEN T = ZV_producttree(P);3186GEN R = ZV_chinesetree(P, T);3187GEN a = ZV_chinese_tree(A, P, T, R);3188GEN mod = gmael(T, lg(T)-1, 1);3189GEN ca = Fp_center(a, mod, shifti(mod,-1));3190return gc_chinese(av, T, ca, pt_mod);3191}31923193GEN3194ZV_chinese(GEN A, GEN P, GEN *pt_mod)3195{3196pari_sp av = avma;3197GEN T = ZV_producttree(P);3198GEN R = ZV_chinesetree(P, T);3199GEN a = ZV_chinese_tree(A, P, T, R);3200return gc_chinese(av, T, a, pt_mod);3201}32023203GEN3204nxV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)3205{3206pari_sp av = avma;3207GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3208GEN a = nxV_polint_center_tree(A, P, T, R, m2);3209return gerepileupto(av, a);3210}32113212GEN3213nxV_chinese_center(GEN A, GEN P, GEN *pt_mod)3214{3215pari_sp av = avma;3216GEN T = ZV_producttree(P);3217GEN R = ZV_chinesetree(P, T);3218GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3219GEN a = nxV_polint_center_tree(A, P, T, R, m2);3220return gc_chinese(av, T, a, pt_mod);3221}32223223GEN3224ncV_chinese_center(GEN A, GEN P, GEN *pt_mod)3225{3226pari_sp av = avma;3227GEN T = ZV_producttree(P);3228GEN R = ZV_chinesetree(P, T);3229GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3230GEN a = ncV_polint_center_tree(A, P, T, R, m2);3231return gc_chinese(av, T, a, pt_mod);3232}32333234GEN3235ncV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)3236{3237pari_sp av = avma;3238GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3239GEN a = ncV_polint_center_tree(A, P, T, R, m2);3240return gerepileupto(av, a);3241}32423243GEN3244nmV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)3245{3246pari_sp av = avma;3247GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3248GEN a = nmV_polint_center_tree(A, P, T, R, m2);3249return gerepileupto(av, a);3250}32513252GEN3253nmV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R)3254{3255pari_sp av = avma;3256GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3257GEN a = nmV_polint_center_tree_seq(A, P, T, R, m2);3258return gerepileupto(av, a);3259}32603261GEN3262nmV_chinese_center(GEN A, GEN P, GEN *pt_mod)3263{3264pari_sp av = avma;3265GEN T = ZV_producttree(P);3266GEN R = ZV_chinesetree(P, T);3267GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3268GEN a = nmV_polint_center_tree(A, P, T, R, m2);3269return gc_chinese(av, T, a, pt_mod);3270}32713272GEN3273nxCV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)3274{3275pari_sp av = avma;3276GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3277GEN a = nxCV_polint_center_tree(A, P, T, R, m2);3278return gerepileupto(av, a);3279}32803281GEN3282nxCV_chinese_center(GEN A, GEN P, GEN *pt_mod)3283{3284pari_sp av = avma;3285GEN T = ZV_producttree(P);3286GEN R = ZV_chinesetree(P, T);3287GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3288GEN a = nxCV_polint_center_tree(A, P, T, R, m2);3289return gc_chinese(av, T, a, pt_mod);3290}32913292GEN3293nxMV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R)3294{3295pari_sp av = avma;3296GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3297GEN a = nxMV_polint_center_tree_seq(A, P, T, R, m2);3298return gerepileupto(av, a);3299}33003301GEN3302nxMV_chinese_center(GEN A, GEN P, GEN *pt_mod)3303{3304pari_sp av = avma;3305GEN T = ZV_producttree(P);3306GEN R = ZV_chinesetree(P, T);3307GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);3308GEN a = nxMV_polint_center_tree(A, P, T, R, m2);3309return gc_chinese(av, T, a, pt_mod);3310}33113312/**********************************************************************3313** **3314** Powering over (Z/NZ)^*, small N **3315** **3316**********************************************************************/33173318/* 2^n mod p; assume n > 1 */3319static ulong3320Fl_2powu_pre(ulong n, ulong p, ulong pi)3321{3322ulong y = 2;3323int j = 1+bfffo(n);3324/* normalize, i.e set highest bit to 1 (we know n != 0) */3325n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */3326for (; j; n<<=1,j--)3327{3328y = Fl_sqr_pre(y,p,pi);3329if (n & HIGHBIT) y = Fl_double(y, p);3330}3331return y;3332}33333334/* 2^n mod p; assume n > 1 and !(p & HIGHMASK) */3335static ulong3336Fl_2powu(ulong n, ulong p)3337{3338ulong y = 2;3339int j = 1+bfffo(n);3340/* normalize, i.e set highest bit to 1 (we know n != 0) */3341n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */3342for (; j; n<<=1,j--)3343{3344y = (y*y) % p;3345if (n & HIGHBIT) y = Fl_double(y, p);3346}3347return y;3348}33493350ulong3351Fl_powu_pre(ulong x, ulong n0, ulong p, ulong pi)3352{3353ulong y, z, n;3354if (n0 <= 1)3355{ /* frequent special cases */3356if (n0 == 1) return x;3357if (n0 == 0) return 1;3358}3359if (x <= 2)3360{3361if (x == 2) return Fl_2powu_pre(n0, p, pi);3362return x; /* 0 or 1 */3363}3364y = 1; z = x; n = n0;3365for(;;)3366{3367if (n&1) y = Fl_mul_pre(y,z,p,pi);3368n>>=1; if (!n) return y;3369z = Fl_sqr_pre(z,p,pi);3370}3371}33723373ulong3374Fl_powu(ulong x, ulong n0, ulong p)3375{3376ulong y, z, n;3377if (n0 <= 2)3378{ /* frequent special cases */3379if (n0 == 2) return Fl_sqr(x,p);3380if (n0 == 1) return x;3381if (n0 == 0) return 1;3382}3383if (x <= 1) return x; /* 0 or 1 */3384if (p & HIGHMASK)3385return Fl_powu_pre(x, n0, p, get_Fl_red(p));3386if (x == 2) return Fl_2powu(n0, p);3387y = 1; z = x; n = n0;3388for(;;)3389{3390if (n&1) y = (y*z) % p;3391n>>=1; if (!n) return y;3392z = (z*z) % p;3393}3394}33953396/* Reduce data dependency to maximize internal parallelism */3397GEN3398Fl_powers_pre(ulong x, long n, ulong p, ulong pi)3399{3400long i, k;3401GEN powers = cgetg(n + 2, t_VECSMALL);3402powers[1] = 1; if (n == 0) return powers;3403powers[2] = x;3404for (i = 3, k=2; i <= n; i+=2, k++)3405{3406powers[i] = Fl_sqr_pre(powers[k], p, pi);3407powers[i+1] = Fl_mul_pre(powers[k], powers[k+1], p, pi);3408}3409if (i==n+1)3410powers[i] = Fl_sqr_pre(powers[k], p, pi);3411return powers;3412}34133414GEN3415Fl_powers(ulong x, long n, ulong p)3416{3417return Fl_powers_pre(x, n, p, get_Fl_red(p));3418}34193420/**********************************************************************3421** **3422** Powering over (Z/NZ)^*, large N **3423** **3424**********************************************************************/34253426static GEN3427Fp_dblsqr(GEN x, GEN N)3428{3429GEN z = shifti(Fp_sqr(x, N), 1);3430return cmpii(z, N) >= 0? subii(z, N): z;3431}34323433typedef struct muldata {3434GEN (*sqr)(void * E, GEN x);3435GEN (*mul)(void * E, GEN x, GEN y);3436GEN (*mul2)(void * E, GEN x);3437} muldata;34383439/* modified Barrett reduction with one fold */3440/* See Fast Modular Reduction, W. Hasenplaugh, G. Gaubatz, V. Gopal, ARITH 18 */34413442static GEN3443Fp_invmBarrett(GEN p, long s)3444{3445GEN R, Q = dvmdii(int2n(3*s),p,&R);3446return mkvec2(Q,R);3447}34483449/* a <= (N-1)^2, 2^(2s-2) <= N < 2^(2s). Return 0 <= r < N such that3450* a = r (mod N) */3451static GEN3452Fp_rem_mBarrett(GEN a, GEN B, long s, GEN N)3453{3454pari_sp av = avma;3455GEN P = gel(B, 1), Q = gel(B, 2); /* 2^(3s) = P N + Q, 0 <= Q < N */3456long t = expi(P)+1; /* 2^(t-1) <= P < 2^t */3457GEN u = shifti(a, -3*s), v = remi2n(a, 3*s); /* a = 2^(3s)u + v */3458GEN A = addii(v, mulii(Q,u)); /* 0 <= A < 2^(3s+1) */3459GEN q = shifti(mulii(shifti(A, t-3*s), P), -t); /* A/N - 4 < q <= A/N */3460GEN r = subii(A, mulii(q, N));3461GEN sr= subii(r,N); /* 0 <= r < 4*N */3462if (signe(sr)<0) return gerepileuptoint(av, r);3463r=sr; sr = subii(r,N); /* 0 <= r < 3*N */3464if (signe(sr)<0) return gerepileuptoint(av, r);3465r=sr; sr = subii(r,N); /* 0 <= r < 2*N */3466return gerepileuptoint(av, signe(sr)>=0 ? sr:r);3467}34683469/* Montgomery reduction */34703471INLINE ulong3472init_montdata(GEN N) { return (ulong) -invmod2BIL(mod2BIL(N)); }34733474struct montred3475{3476GEN N;3477ulong inv;3478};34793480/* Montgomery reduction */3481static GEN3482_sqr_montred(void * E, GEN x)3483{3484struct montred * D = (struct montred *) E;3485return red_montgomery(sqri(x), D->N, D->inv);3486}34873488/* Montgomery reduction */3489static GEN3490_mul_montred(void * E, GEN x, GEN y)3491{3492struct montred * D = (struct montred *) E;3493return red_montgomery(mulii(x, y), D->N, D->inv);3494}34953496static GEN3497_mul2_montred(void * E, GEN x)3498{3499struct montred * D = (struct montred *) E;3500GEN z = shifti(_sqr_montred(E, x), 1);3501long l = lgefint(D->N);3502while (lgefint(z) > l) z = subii(z, D->N);3503return z;3504}35053506static GEN3507_sqr_remii(void* N, GEN x)3508{ return remii(sqri(x), (GEN) N); }35093510static GEN3511_mul_remii(void* N, GEN x, GEN y)3512{ return remii(mulii(x, y), (GEN) N); }35133514static GEN3515_mul2_remii(void* N, GEN x)3516{ return Fp_dblsqr(x, (GEN) N); }35173518struct redbarrett3519{3520GEN iM, N;3521long s;3522};35233524static GEN3525_sqr_remiibar(void *E, GEN x)3526{3527struct redbarrett * D = (struct redbarrett *) E;3528return Fp_rem_mBarrett(sqri(x), D->iM, D->s, D->N);3529}35303531static GEN3532_mul_remiibar(void *E, GEN x, GEN y)3533{3534struct redbarrett * D = (struct redbarrett *) E;3535return Fp_rem_mBarrett(mulii(x, y), D->iM, D->s, D->N);3536}35373538static GEN3539_mul2_remiibar(void *E, GEN x)3540{3541struct redbarrett * D = (struct redbarrett *) E;3542return Fp_dblsqr(x, D->N);3543}35443545static long3546Fp_select_red(GEN *y, ulong k, GEN N, long lN, muldata *D, void **pt_E)3547{3548if (lN >= Fp_POW_BARRETT_LIMIT && (k==0 || ((double)k)*expi(*y) > 2 + expi(N)))3549{3550struct redbarrett * E = (struct redbarrett *) stack_malloc(sizeof(struct redbarrett));3551D->sqr = &_sqr_remiibar;3552D->mul = &_mul_remiibar;3553D->mul2 = &_mul2_remiibar;3554E->N = N;3555E->s = 1+(expi(N)>>1);3556E->iM = Fp_invmBarrett(N, E->s);3557*pt_E = (void*) E;3558return 0;3559}3560else if (mod2(N) && lN < Fp_POW_REDC_LIMIT)3561{3562struct montred * E = (struct montred *) stack_malloc(sizeof(struct montred));3563*y = remii(shifti(*y, bit_accuracy(lN)), N);3564D->sqr = &_sqr_montred;3565D->mul = &_mul_montred;3566D->mul2 = &_mul2_montred;3567E->N = N;3568E->inv = init_montdata(N);3569*pt_E = (void*) E;3570return 1;3571}3572else3573{3574D->sqr = &_sqr_remii;3575D->mul = &_mul_remii;3576D->mul2 = &_mul2_remii;3577*pt_E = (void*) N;3578return 0;3579}3580}35813582GEN3583Fp_powu(GEN A, ulong k, GEN N)3584{3585long lN = lgefint(N);3586int base_is_2, use_montgomery;3587muldata D;3588void *E;3589pari_sp av;35903591if (lN == 3) {3592ulong n = uel(N,2);3593return utoi( Fl_powu(umodiu(A, n), k, n) );3594}3595if (k <= 2)3596{ /* frequent special cases */3597if (k == 2) return Fp_sqr(A,N);3598if (k == 1) return A;3599if (k == 0) return gen_1;3600}3601av = avma; A = modii(A,N);3602base_is_2 = 0;3603if (lgefint(A) == 3) switch(A[2])3604{3605case 1: set_avma(av); return gen_1;3606case 2: base_is_2 = 1; break;3607}36083609/* TODO: Move this out of here and use for general modular computations */3610use_montgomery = Fp_select_red(&A, k, N, lN, &D, &E);3611if (base_is_2)3612A = gen_powu_fold_i(A, k, E, D.sqr, D.mul2);3613else3614A = gen_powu_i(A, k, E, D.sqr, D.mul);3615if (use_montgomery)3616{3617A = red_montgomery(A, N, ((struct montred *) E)->inv);3618if (cmpii(A, N) >= 0) A = subii(A,N);3619}3620return gerepileuptoint(av, A);3621}36223623GEN3624Fp_pows(GEN A, long k, GEN N)3625{3626if (lgefint(N) == 3) {3627ulong n = N[2];3628ulong a = umodiu(A, n);3629if (k < 0) {3630a = Fl_inv(a, n);3631k = -k;3632}3633return utoi( Fl_powu(a, (ulong)k, n) );3634}3635if (k < 0) { A = Fp_inv(A, N); k = -k; };3636return Fp_powu(A, (ulong)k, N);3637}36383639/* A^K mod N */3640GEN3641Fp_pow(GEN A, GEN K, GEN N)3642{3643pari_sp av;3644long s, lN = lgefint(N), sA, sy;3645int base_is_2, use_montgomery;3646GEN y;3647muldata D;3648void *E;36493650s = signe(K);3651if (!s) return dvdii(A,N)? gen_0: gen_1;3652if (lN == 3 && lgefint(K) == 3)3653{3654ulong n = N[2], a = umodiu(A, n);3655if (s < 0) a = Fl_inv(a, n);3656if (a <= 1) return utoi(a); /* 0 or 1 */3657return utoi(Fl_powu(a, uel(K,2), n));3658}36593660av = avma;3661if (s < 0) y = Fp_inv(A,N);3662else3663{3664y = modii(A,N);3665if (!signe(y)) { set_avma(av); return gen_0; }3666}3667if (lgefint(K) == 3) return gerepileuptoint(av, Fp_powu(y, K[2], N));36683669base_is_2 = 0;3670sy = abscmpii(y, shifti(N,-1)) > 0;3671if (sy) y = subii(N,y);3672sA = sy && mod2(K);3673if (lgefint(y) == 3) switch(y[2])3674{3675case 1: set_avma(av); return sA ? subis(N,1): gen_1;3676case 2: base_is_2 = 1; break;3677}36783679/* TODO: Move this out of here and use for general modular computations */3680use_montgomery = Fp_select_red(&y, 0UL, N, lN, &D, &E);3681if (base_is_2)3682y = gen_pow_fold_i(y, K, E, D.sqr, D.mul2);3683else3684y = gen_pow_i(y, K, E, D.sqr, D.mul);3685if (use_montgomery)3686{3687y = red_montgomery(y, N, ((struct montred *) E)->inv);3688if (cmpii(y,N) >= 0) y = subii(y,N);3689}3690if (sA) y = subii(N, y);3691return gerepileuptoint(av,y);3692}36933694static GEN3695_Fp_mul(void *E, GEN x, GEN y) { return Fp_mul(x,y,(GEN)E); }36963697static GEN3698_Fp_sqr(void *E, GEN x) { return Fp_sqr(x,(GEN)E); }36993700static GEN3701_Fp_one(void *E) { (void) E; return gen_1; }37023703GEN3704Fp_pow_init(GEN x, GEN n, long k, GEN p)3705{3706return gen_pow_init(x, n, k, (void*)p, &_Fp_sqr, &_Fp_mul);3707}37083709GEN3710Fp_pow_table(GEN R, GEN n, GEN p)3711{3712return gen_pow_table(R, n, (void*)p, &_Fp_one, &_Fp_mul);3713}37143715GEN3716Fp_powers(GEN x, long n, GEN p)3717{3718if (lgefint(p) == 3)3719return Flv_to_ZV(Fl_powers(umodiu(x, uel(p, 2)), n, uel(p, 2)));3720return gen_powers(x, n, 1, (void*)p, _Fp_sqr, _Fp_mul, _Fp_one);3721}37223723GEN3724FpV_prod(GEN V, GEN p)3725{3726return gen_product(V, (void *)p, &_Fp_mul);3727}37283729static GEN3730_Fp_pow(void *E, GEN x, GEN n) { return Fp_pow(x,n,(GEN)E); }37313732static GEN3733_Fp_rand(void *E) { return addiu(randomi(subiu((GEN)E,1)),1); }37343735static GEN Fp_easylog(void *E, GEN a, GEN g, GEN ord);37363737static const struct bb_group Fp_star={_Fp_mul,_Fp_pow,_Fp_rand,hash_GEN,3738equalii,equali1,Fp_easylog};37393740static GEN3741_Fp_red(void *E, GEN x) { return Fp_red(x, (GEN)E); }37423743static GEN3744_Fp_add(void *E, GEN x, GEN y) { (void) E; return addii(x,y); }37453746static GEN3747_Fp_neg(void *E, GEN x) { (void) E; return negi(x); }37483749static GEN3750_Fp_rmul(void *E, GEN x, GEN y) { (void) E; return mulii(x,y); }37513752static GEN3753_Fp_inv(void *E, GEN x) { return Fp_inv(x,(GEN)E); }37543755static int3756_Fp_equal0(GEN x) { return signe(x)==0; }37573758static GEN3759_Fp_s(void *E, long x) { (void) E; return stoi(x); }37603761static const struct bb_field Fp_field={_Fp_red,_Fp_add,_Fp_rmul,_Fp_neg,3762_Fp_inv,_Fp_equal0,_Fp_s};37633764const struct bb_field *get_Fp_field(void **E, GEN p)3765{3766*E = (void*)p; return &Fp_field;3767}37683769/*********************************************************************/3770/** **/3771/** ORDER of INTEGERMOD x in (Z/nZ)* **/3772/** **/3773/*********************************************************************/3774ulong3775Fl_order(ulong a, ulong o, ulong p)3776{3777pari_sp av = avma;3778GEN m, P, E;3779long i;3780if (a==1) return 1;3781if (!o) o = p-1;3782m = factoru(o);3783P = gel(m,1);3784E = gel(m,2);3785for (i = lg(P)-1; i; i--)3786{3787ulong j, l = P[i], e = E[i], t = o / upowuu(l,e), y = Fl_powu(a, t, p);3788if (y == 1) o = t;3789else for (j = 1; j < e; j++)3790{3791y = Fl_powu(y, l, p);3792if (y == 1) { o = t * upowuu(l, j); break; }3793}3794}3795return gc_ulong(av, o);3796}37973798/*Find the exact order of a assuming a^o==1*/3799GEN3800Fp_order(GEN a, GEN o, GEN p) {3801if (lgefint(p) == 3 && (!o || typ(o) == t_INT))3802{3803ulong pp = p[2], oo = (o && lgefint(o)==3)? uel(o,2): pp-1;3804return utoi( Fl_order(umodiu(a, pp), oo, pp) );3805}3806return gen_order(a, o, (void*)p, &Fp_star);3807}3808GEN3809Fp_factored_order(GEN a, GEN o, GEN p)3810{ return gen_factored_order(a, o, (void*)p, &Fp_star); }38113812/* return order of a mod p^e, e > 0, pe = p^e */3813static GEN3814Zp_order(GEN a, GEN p, long e, GEN pe)3815{3816GEN ap, op;3817if (absequaliu(p, 2))3818{3819if (e == 1) return gen_1;3820if (e == 2) return mod4(a) == 1? gen_1: gen_2;3821if (mod4(a) == 1)3822op = gen_1;3823else {3824op = gen_2;3825a = Fp_sqr(a, pe);3826}3827} else {3828ap = (e == 1)? a: remii(a,p);3829op = Fp_order(ap, subiu(p,1), p);3830if (e == 1) return op;3831a = Fp_pow(a, op, pe); /* 1 mod p */3832}3833if (equali1(a)) return op;3834return mulii(op, powiu(p, e - Z_pval(subiu(a,1), p)));3835}38363837GEN3838znorder(GEN x, GEN o)3839{3840pari_sp av = avma;3841GEN b, a;38423843if (typ(x) != t_INTMOD) pari_err_TYPE("znorder [t_INTMOD expected]",x);3844b = gel(x,1); a = gel(x,2);3845if (!equali1(gcdii(a,b))) pari_err_COPRIME("znorder", a,b);3846if (!o)3847{3848GEN fa = Z_factor(b), P = gel(fa,1), E = gel(fa,2);3849long i, l = lg(P);3850o = gen_1;3851for (i = 1; i < l; i++)3852{3853GEN p = gel(P,i);3854long e = itos(gel(E,i));38553856if (l == 2)3857o = Zp_order(a, p, e, b);3858else {3859GEN pe = powiu(p,e);3860o = lcmii(o, Zp_order(remii(a,pe), p, e, pe));3861}3862}3863return gerepileuptoint(av, o);3864}3865return Fp_order(a, o, b);3866}3867GEN3868order(GEN x) { return znorder(x, NULL); }38693870/*********************************************************************/3871/** **/3872/** DISCRETE LOGARITHM in (Z/nZ)* **/3873/** **/3874/*********************************************************************/3875static GEN3876Fp_log_halfgcd(ulong bnd, GEN C, GEN g, GEN p)3877{3878pari_sp av = avma;3879GEN h1, h2, F, G;3880if (!Fp_ratlift(g,p,C,shifti(C,-1),&h1,&h2)) return gc_NULL(av);3881if ((F = Z_issmooth_fact(h1, bnd)) && (G = Z_issmooth_fact(h2, bnd)))3882{3883GEN M = cgetg(3, t_MAT);3884gel(M,1) = vecsmall_concat(gel(F, 1),gel(G, 1));3885gel(M,2) = vecsmall_concat(gel(F, 2),zv_neg_inplace(gel(G, 2)));3886return gerepileupto(av, M);3887}3888return gc_NULL(av);3889}38903891static GEN3892Fp_log_find_rel(GEN b, ulong bnd, GEN C, GEN p, GEN *g, long *e)3893{3894GEN rel;3895do3896{3897(*e)++; *g = Fp_mul(*g, b, p);3898rel = Fp_log_halfgcd(bnd, C, *g, p);3899} while (!rel);3900return rel;3901}39023903struct Fp_log_rel3904{3905GEN rel;3906ulong prmax;3907long nbrel, nbmax, nbgen;3908};39093910/* add u^e */3911static void3912addifsmooth1(struct Fp_log_rel *r, GEN z, long u, long e)3913{3914pari_sp av = avma;3915long off = r->prmax+1;3916GEN F = cgetg(3, t_MAT);3917gel(F,1) = vecsmall_append(gel(z,1), off+u);3918gel(F,2) = vecsmall_append(gel(z,2), e);3919gel(r->rel,++r->nbrel) = gerepileupto(av, F);3920}39213922/* add u^-1 v^-1 */3923static void3924addifsmooth2(struct Fp_log_rel *r, GEN z, long u, long v)3925{3926pari_sp av = avma;3927long off = r->prmax+1;3928GEN P = mkvecsmall2(off+u,off+v), E = mkvecsmall2(-1,-1);3929GEN F = cgetg(3, t_MAT);3930gel(F,1) = vecsmall_concat(gel(z,1), P);3931gel(F,2) = vecsmall_concat(gel(z,2), E);3932gel(r->rel,++r->nbrel) = gerepileupto(av, F);3933}39343935/*3936Let p=C^2+c3937Solve h = (C+x)*(C+a)-p = 0 [mod l]3938h= -c+x*(C+a)+C*a = 0 [mod l]3939x = (c-C*a)/(C+a) [mod l]3940h = -c+C*(x+a)+a*x3941*/39423943GEN3944Fp_log_sieve_worker(long a, long prmax, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz)3945{3946pari_sp ltop = avma;3947long th, n = lg(pi)-1;3948long i, j;3949GEN sieve = zero_zv(a+2)+1;3950GEN L = cgetg(1+a+2, t_VEC);3951pari_sp av = avma;3952long rel = 1;3953GEN z, h;3954h = addis(C,a);3955if ((z = Z_issmooth_fact(h, prmax)))3956{3957gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -1));3958av = avma;3959}3960for (i=1; i<=n; i++)3961{3962ulong li = pi[i], s = sz[i], al = a % li;3963ulong u, iv = Fl_invsafe(Fl_add(Ci[i],al,li),li);3964if (!iv) continue;3965u = Fl_mul(Fl_sub(ci[i],Fl_mul(Ci[i],al,li),li), iv ,li);3966for(j = u; j<=a; j+=li)3967sieve[j] += s;3968}3969if (a)3970{3971long e = expi(mulis(C,a));3972th = e - expu(e) - 1;3973} else th = -1;3974for (j=0; j<a; j++)3975if (sieve[j]>=th)3976{3977GEN h = addiu(subii(muliu(C,a+j),c), a*j);3978if ((z = Z_issmooth_fact(h, prmax)))3979{3980gel(L, rel++) = mkvec2(z, mkvecsmall3(2, a, j));3981av = avma;3982} else set_avma(av);3983}3984/* j = a */3985if (sieve[a]>=th)3986{3987GEN h = addiu(subii(muliu(C,2*a),c), a*a);3988if ((z = Z_issmooth_fact(h, prmax)))3989gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -2));3990}3991setlg(L, rel);3992return gerepilecopy(ltop, L);3993}39943995static long3996Fp_log_sieve(struct Fp_log_rel *r, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz)3997{3998struct pari_mt pt;3999long i, j, nb = 0;4000GEN worker = snm_closure(is_entry("_Fp_log_sieve_worker"),4001mkvecn(7, utoi(r->prmax), C, c, Ci, ci, pi, sz));4002long running, pending = 0;4003GEN W = zerovec(r->nbgen);4004mt_queue_start_lim(&pt, worker, r->nbgen);4005for (i = 0; (running = (i < r->nbgen)) || pending; i++)4006{4007GEN done;4008long idx;4009mt_queue_submit(&pt, i, running ? mkvec(stoi(i)): NULL);4010done = mt_queue_get(&pt, &idx, &pending);4011if (!done || lg(done)==1) continue;4012gel(W, idx+1) = done;4013nb += lg(done)-1;4014if (DEBUGLEVEL && (i&127)==0)4015err_printf("%ld%% ",100*nb/r->nbmax);4016}4017mt_queue_end(&pt);4018for(j = 1; j <= r->nbgen && r->nbrel < r->nbmax; j++)4019{4020long ll, m;4021GEN L = gel(W,j);4022if (isintzero(L)) continue;4023ll = lg(L);4024for (m=1; m<ll && r->nbrel < r->nbmax ; m++)4025{4026GEN Lm = gel(L,m), h = gel(Lm, 1), v = gel(Lm, 2);4027if (v[1] == 1)4028addifsmooth1(r, h, v[2], v[3]);4029else4030addifsmooth2(r, h, v[2], v[3]);4031}4032}4033return j;4034}40354036static GEN4037ECP_psi(GEN x, GEN y)4038{4039long prec = realprec(x);4040GEN lx = glog(x, prec), ly = glog(y, prec);4041GEN u = gdiv(lx, ly);4042return gpow(u, gneg(u),prec);4043}40444045struct computeG4046{4047GEN C;4048long bnd, nbi;4049};40504051static GEN4052_computeG(void *E, GEN gen)4053{4054struct computeG * d = (struct computeG *) E;4055GEN ps = ECP_psi(gmul(gen,d->C), stoi(d->bnd));4056return gsub(gmul(gsqr(gen),ps),gmul2n(gaddgs(gen,d->nbi),2));4057}40584059static long4060compute_nbgen(GEN C, long bnd, long nbi)4061{4062struct computeG d;4063d.C = shifti(C, 1);4064d.bnd = bnd;4065d.nbi = nbi;4066return itos(ground(zbrent((void*)&d, _computeG, gen_2, stoi(bnd), DEFAULTPREC)));4067}40684069static GEN4070_psi(void*E, GEN y)4071{4072GEN lx = (GEN) E;4073long prec = realprec(lx);4074GEN ly = glog(y, prec);4075GEN u = gdiv(lx, ly);4076return gsub(gdiv(y ,ly), gpow(u, u, prec));4077}40784079static GEN4080opt_param(GEN x, long prec)4081{4082return zbrent((void*)glog(x,prec), _psi, gen_2, x, prec);4083}40844085static GEN4086check_kernel(long nbg, long N, long prmax, GEN C, GEN M, GEN p, GEN m)4087{4088pari_sp av = avma;4089long lM = lg(M)-1, nbcol = lM;4090long tbs = maxss(1, expu(nbg/expi(m)));4091for (;;)4092{4093GEN K = FpMs_leftkernel_elt_col(M, nbcol, N, m);4094GEN tab;4095long i, f=0;4096long l = lg(K), lm = lgefint(m);4097GEN idx = diviiexact(subiu(p,1),m), g;4098pari_timer ti;4099if (DEBUGLEVEL) timer_start(&ti);4100for(i=1; i<l; i++)4101if (signe(gel(K,i)))4102break;4103g = Fp_pow(utoi(i), idx, p);4104tab = Fp_pow_init(g, p, tbs, p);4105K = FpC_Fp_mul(K, Fp_inv(gel(K,i), m), m);4106for(i=1; i<l; i++)4107{4108GEN k = gel(K,i);4109GEN j = i<=prmax ? utoi(i): addis(C,i-(prmax+1));4110if (signe(k)==0 || !equalii(Fp_pow_table(tab, k, p), Fp_pow(j, idx, p)))4111gel(K,i) = cgetineg(lm);4112else4113f++;4114}4115if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbg);4116if(f > (nbg>>1)) return gerepileupto(av, K);4117for(i=1; i<=nbcol; i++)4118{4119long a = 1+random_Fl(lM);4120swap(gel(M,a),gel(M,i));4121}4122if (4*nbcol>5*nbg) nbcol = nbcol*9/10;4123}4124}41254126static GEN4127Fp_log_find_ind(GEN a, GEN K, long prmax, GEN C, GEN p, GEN m)4128{4129pari_sp av=avma;4130GEN aa = gen_1;4131long AV = 0;4132for(;;)4133{4134GEN A = Fp_log_find_rel(a, prmax, C, p, &aa, &AV);4135GEN F = gel(A,1), E = gel(A,2);4136GEN Ao = gen_0;4137long i, l = lg(F);4138for(i=1; i<l; i++)4139{4140GEN Ki = gel(K,F[i]);4141if (signe(Ki)<0) break;4142Ao = addii(Ao, mulis(Ki, E[i]));4143}4144if (i==l) return Fp_divu(Ao, AV, m);4145aa = gerepileuptoint(av, aa);4146}4147}41484149static GEN4150Fp_log_index(GEN a, GEN b, GEN m, GEN p)4151{4152pari_sp av = avma, av2;4153long i, j, nbi, nbr = 0, nbrow, nbg;4154GEN C, c, Ci, ci, pi, pr, sz, l, Ao, Bo, K, d, p_1;4155pari_timer ti;4156struct Fp_log_rel r;4157ulong bnds = itou(roundr_safe(opt_param(sqrti(p),DEFAULTPREC)));4158ulong bnd = 4*bnds;4159if (!bnds || cmpii(sqru(bnds),m)>=0) return NULL;41604161p_1 = subiu(p,1);4162if (!is_pm1(gcdii(m,diviiexact(p_1,m))))4163m = diviiexact(p_1, Z_ppo(p_1, m));4164pr = primes_upto_zv(bnd);4165nbi = lg(pr)-1;4166C = sqrtremi(p, &c);4167av2 = avma;4168for (i = 1; i <= nbi; ++i)4169{4170ulong lp = pr[i];4171while (lp <= bnd)4172{4173nbr++;4174lp *= pr[i];4175}4176}4177pi = cgetg(nbr+1,t_VECSMALL);4178Ci = cgetg(nbr+1,t_VECSMALL);4179ci = cgetg(nbr+1,t_VECSMALL);4180sz = cgetg(nbr+1,t_VECSMALL);4181for (i = 1, j = 1; i <= nbi; ++i)4182{4183ulong lp = pr[i], sp = expu(2*lp-1);4184while (lp <= bnd)4185{4186pi[j] = lp;4187Ci[j] = umodiu(C, lp);4188ci[j] = umodiu(c, lp);4189sz[j] = sp;4190lp *= pr[i];4191j++;4192}4193}4194r.nbrel = 0;4195r.nbgen = compute_nbgen(C, bnd, nbi);4196r.nbmax = 2*(nbi+r.nbgen);4197r.rel = cgetg(r.nbmax+1,t_VEC);4198r.prmax = pr[nbi];4199if (DEBUGLEVEL)4200{4201err_printf("bnd=%lu Size FB=%ld extra gen=%ld \n", bnd, nbi, r.nbgen);4202timer_start(&ti);4203}4204nbg = Fp_log_sieve(&r, C, c, Ci, ci, pi, sz);4205nbrow = r.prmax + nbg;4206if (DEBUGLEVEL)4207{4208err_printf("\n");4209timer_printf(&ti," %ld relations, %ld generators", r.nbrel, nbi+nbg);4210}4211setlg(r.rel,r.nbrel+1);4212r.rel = gerepilecopy(av2, r.rel);4213K = check_kernel(nbi+nbrow-r.prmax, nbrow, r.prmax, C, r.rel, p, m);4214if (DEBUGLEVEL) timer_start(&ti);4215Ao = Fp_log_find_ind(a, K, r.prmax, C, p, m);4216if (DEBUGLEVEL) timer_printf(&ti," log element");4217Bo = Fp_log_find_ind(b, K, r.prmax, C, p, m);4218if (DEBUGLEVEL) timer_printf(&ti," log generator");4219d = gcdii(Ao,Bo);4220l = Fp_div(diviiexact(Ao, d) ,diviiexact(Bo, d), m);4221if (!equalii(a,Fp_pow(b,l,p))) pari_err_BUG("Fp_log_index");4222return gerepileuptoint(av, l);4223}42244225static int4226Fp_log_use_index(long e, long p)4227{4228return (e >= 27 && 20*(p+6)<=e*e);4229}42304231/* Trivial cases a = 1, -1. Return x s.t. g^x = a or [] if no such x exist */4232static GEN4233Fp_easylog(void *E, GEN a, GEN g, GEN ord)4234{4235pari_sp av = avma;4236GEN p = (GEN)E;4237/* assume a reduced mod p, p not necessarily prime */4238if (equali1(a)) return gen_0;4239/* p > 2 */4240if (equalii(subiu(p,1), a)) /* -1 */4241{4242pari_sp av2;4243GEN t;4244ord = get_arith_Z(ord);4245if (mpodd(ord)) { set_avma(av); return cgetg(1, t_VEC); } /* no solution */4246t = shifti(ord,-1); /* only possible solution */4247av2 = avma;4248if (!equalii(Fp_pow(g, t, p), a)) { set_avma(av); return cgetg(1, t_VEC); }4249set_avma(av2); return gerepileuptoint(av, t);4250}4251if (typ(ord)==t_INT && BPSW_psp(p) && Fp_log_use_index(expi(ord),expi(p)))4252return Fp_log_index(a, g, ord, p);4253return gc_NULL(av); /* not easy */4254}42554256GEN4257Fp_log(GEN a, GEN g, GEN ord, GEN p)4258{4259GEN v = get_arith_ZZM(ord);4260GEN F = gmael(v,2,1);4261long lF = lg(F)-1, lmax;4262if (lF == 0) return equali1(a)? gen_0: cgetg(1, t_VEC);4263lmax = expi(gel(F,lF));4264if (BPSW_psp(p) && Fp_log_use_index(lmax,expi(p)))4265v = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(27)));4266return gen_PH_log(a,g,v,(void*)p,&Fp_star);4267}42684269static ulong4270Fl_log_naive(ulong a, ulong g, ulong ord, ulong p)4271{4272ulong i, h=1;4273for(i=0; i<ord; i++, h = Fl_mul(h, g, p))4274if(a==h) return i;4275return ~0UL;4276}42774278static ulong4279Fl_log_naive_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi)4280{4281ulong i, h=1;4282for(i=0; i<ord; i++, h = Fl_mul_pre(h, g, p, pi))4283if(a==h) return i;4284return ~0UL;4285}42864287static ulong4288Fl_log_Fp(ulong a, ulong g, ulong ord, ulong p)4289{4290pari_sp av = avma;4291GEN r = Fp_log(utoi(a),utoi(g),utoi(ord),utoi(p));4292return gc_ulong(av, typ(r)==t_INT ? itou(r): ~0UL);4293}42944295ulong4296Fl_log_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi)4297{4298if (ord <= 200) return Fl_log_naive_pre(a, g, ord, p, pi);4299return Fl_log_Fp(a, g, ord, p);4300}43014302ulong4303Fl_log(ulong a, ulong g, ulong ord, ulong p)4304{4305if (ord <= 200)4306return (p&HIGHMASK) ? Fl_log_naive_pre(a, g, ord, p, get_Fl_red(p))4307: Fl_log_naive(a, g, ord, p);4308return Fl_log_Fp(a, g, ord, p);4309}43104311/* find x such that h = g^x mod N > 1, N = prod_{i <= l} P[i]^E[i], P[i] prime.4312* PHI[l] = eulerphi(N / P[l]^E[l]). Destroys P/E */4313static GEN4314znlog_rec(GEN h, GEN g, GEN N, GEN P, GEN E, GEN PHI)4315{4316long l = lg(P) - 1, e = E[l];4317GEN p = gel(P, l), phi = gel(PHI,l), pe = e == 1? p: powiu(p, e);4318GEN a,b, hp,gp, hpe,gpe, ogpe; /* = order(g mod p^e) | p^(e-1)(p-1) */43194320if (l == 1) {4321hpe = h;4322gpe = g;4323} else {4324hpe = modii(h, pe);4325gpe = modii(g, pe);4326}4327if (e == 1) {4328hp = hpe;4329gp = gpe;4330} else {4331hp = remii(hpe, p);4332gp = remii(gpe, p);4333}4334if (hp == gen_0 || gp == gen_0) return NULL;4335if (absequaliu(p, 2))4336{4337GEN n = int2n(e);4338ogpe = Zp_order(gpe, gen_2, e, n);4339a = Fp_log(hpe, gpe, ogpe, n);4340if (typ(a) != t_INT) return NULL;4341}4342else4343{ /* Avoid black box groups: (Z/p^2)^* / (Z/p)^* ~ (Z/pZ, +), where DL4344is trivial */4345/* [order(gp), factor(order(gp))] */4346GEN v = Fp_factored_order(gp, subiu(p,1), p);4347GEN ogp = gel(v,1);4348if (!equali1(Fp_pow(hp, ogp, p))) return NULL;4349a = Fp_log(hp, gp, v, p);4350if (typ(a) != t_INT) return NULL;4351if (e == 1) ogpe = ogp;4352else4353{ /* find a s.t. g^a = h (mod p^e), p odd prime, e > 0, (h,p) = 1 */4354/* use p-adic log: O(log p + e) mul*/4355long vpogpe, vpohpe;43564357hpe = Fp_mul(hpe, Fp_pow(gpe, negi(a), pe), pe);4358gpe = Fp_pow(gpe, ogp, pe);4359/* g,h = 1 mod p; compute b s.t. h = g^b */43604361/* v_p(order g mod pe) */4362vpogpe = equali1(gpe)? 0: e - Z_pval(subiu(gpe,1), p);4363/* v_p(order h mod pe) */4364vpohpe = equali1(hpe)? 0: e - Z_pval(subiu(hpe,1), p);4365if (vpohpe > vpogpe) return NULL;43664367ogpe = mulii(ogp, powiu(p, vpogpe)); /* order g mod p^e */4368if (is_pm1(gpe)) return is_pm1(hpe)? a: NULL;4369b = gdiv(Qp_log(cvtop(hpe, p, e)), Qp_log(cvtop(gpe, p, e)));4370a = addii(a, mulii(ogp, padic_to_Q(b)));4371}4372}4373/* gp^a = hp => x = a mod ogpe => generalized Pohlig-Hellman strategy */4374if (l == 1) return a;43754376N = diviiexact(N, pe); /* make N coprime to p */4377h = Fp_mul(h, Fp_pow(g, modii(negi(a), phi), N), N);4378g = Fp_pow(g, modii(ogpe, phi), N);4379setlg(P, l); /* remove last element */4380setlg(E, l);4381b = znlog_rec(h, g, N, P, E, PHI);4382if (!b) return NULL;4383return addmulii(a, b, ogpe);4384}43854386static GEN4387get_PHI(GEN P, GEN E)4388{4389long i, l = lg(P);4390GEN PHI = cgetg(l, t_VEC);4391gel(PHI,1) = gen_1;4392for (i=1; i<l-1; i++)4393{4394GEN t, p = gel(P,i);4395long e = E[i];4396t = mulii(powiu(p, e-1), subiu(p,1));4397if (i > 1) t = mulii(t, gel(PHI,i));4398gel(PHI,i+1) = t;4399}4400return PHI;4401}44024403GEN4404znlog(GEN h, GEN g, GEN o)4405{4406pari_sp av = avma;4407GEN N, fa, P, E, x;4408switch (typ(g))4409{4410case t_PADIC:4411{4412GEN p = gel(g,2);4413long v = valp(g);4414if (v < 0) pari_err_DIM("znlog");4415if (v > 0) {4416long k = gvaluation(h, p);4417if (k % v) return cgetg(1,t_VEC);4418k /= v;4419if (!gequal(h, gpowgs(g,k))) { set_avma(av); return cgetg(1,t_VEC); }4420set_avma(av); return stoi(k);4421}4422N = gel(g,3);4423g = Rg_to_Fp(g, N);4424break;4425}4426case t_INTMOD:4427N = gel(g,1);4428g = gel(g,2); break;4429default: pari_err_TYPE("znlog", g);4430return NULL; /* LCOV_EXCL_LINE */4431}4432if (equali1(N)) { set_avma(av); return gen_0; }4433h = Rg_to_Fp(h, N);4434if (o) return gerepileupto(av, Fp_log(h, g, o, N));4435fa = Z_factor(N);4436P = gel(fa,1);4437E = vec_to_vecsmall(gel(fa,2));4438x = znlog_rec(h, g, N, P, E, get_PHI(P,E));4439if (!x) { set_avma(av); return cgetg(1,t_VEC); }4440return gerepileuptoint(av, x);4441}44424443GEN4444Fp_sqrtn(GEN a, GEN n, GEN p, GEN *zeta)4445{4446if (lgefint(p)==3)4447{4448long nn = itos_or_0(n);4449if (nn)4450{4451ulong pp = p[2];4452ulong uz;4453ulong r = Fl_sqrtn(umodiu(a,pp),nn,pp, zeta ? &uz:NULL);4454if (r==ULONG_MAX) return NULL;4455if (zeta) *zeta = utoi(uz);4456return utoi(r);4457}4458}4459a = modii(a,p);4460if (!signe(a))4461{4462if (zeta) *zeta = gen_1;4463if (signe(n) < 0) pari_err_INV("Fp_sqrtn", mkintmod(gen_0,p));4464return gen_0;4465}4466if (absequaliu(n,2))4467{4468if (zeta) *zeta = subiu(p,1);4469return signe(n) > 0 ? Fp_sqrt(a,p): Fp_sqrt(Fp_inv(a, p),p);4470}4471return gen_Shanks_sqrtn(a,n,subiu(p,1),zeta,(void*)p,&Fp_star);4472}44734474/*********************************************************************/4475/** **/4476/** FUNDAMENTAL DISCRIMINANTS **/4477/** **/4478/*********************************************************************/4479static long4480fa_isfundamental(GEN F)4481{4482GEN P = gel(F,1), E = gel(F,2);4483long i, s, l = lg(P);44844485if (l == 1) return 1;4486s = signe(gel(P,1)); /* = signe(x) */4487if (!s) return 0;4488if (s < 0) { l--; P = vecslice(P,2,l); E = vecslice(E,2,l); }4489if (l == 1) return 0;4490if (!absequaliu(gel(P,1), 2))4491i = 1; /* need x = 1 mod 4 */4492else4493{4494i = 2;4495switch(itou(gel(E,1)))4496{4497case 2: s = -s; break; /* need x/4 = 3 mod 4 */4498case 3: s = 0; break; /* no condition mod 4 */4499default: return 0;4500}4501}4502for(; i < l; i++)4503{4504if (!equali1(gel(E,i))) return 0;4505if (s && Mod4(gel(P,i)) == 3) s = -s;4506}4507return s >= 0;4508}4509long4510isfundamental(GEN x)4511{4512if (typ(x) != t_INT)4513{4514pari_sp av = avma;4515long v = fa_isfundamental(check_arith_all(x,"isfundamental"));4516return gc_long(av,v);4517}4518return Z_isfundamental(x);4519}45204521/* x fundamental ? */4522long4523uposisfundamental(ulong x)4524{4525ulong r = x & 15; /* x mod 16 */4526if (!r) return 0;4527switch(r & 3)4528{ /* x mod 4 */4529case 0: return (r == 4)? 0: uissquarefree(x >> 2);4530case 1: return uissquarefree(x);4531default: return 0;4532}4533}4534/* -x fundamental ? */4535long4536unegisfundamental(ulong x)4537{4538ulong r = x & 15; /* x mod 16 */4539if (!r) return 0;4540switch(r & 3)4541{ /* x mod 4 */4542case 0: return (r == 12)? 0: uissquarefree(x >> 2);4543case 3: return uissquarefree(x);4544default: return 0;4545}4546}4547long4548sisfundamental(long x)4549{ return x < 0? unegisfundamental((ulong)(-x)): uposisfundamental(x); }45504551long4552Z_isfundamental(GEN x)4553{4554long r;4555switch(lgefint(x))4556{4557case 2: return 0;4558case 3: return signe(x) < 0? unegisfundamental(x[2])4559: uposisfundamental(x[2]);4560}4561r = mod16(x);4562if (!r) return 0;4563if ((r & 3) == 0)4564{4565pari_sp av;4566r >>= 2; /* |x|/4 mod 4 */4567if (signe(x) < 0) r = 4-r;4568if (r == 1) return 0;4569av = avma;4570r = Z_issquarefree( shifti(x,-2) );4571return gc_long(av, r);4572}4573r &= 3; /* |x| mod 4 */4574if (signe(x) < 0) r = 4-r;4575return (r==1) ? Z_issquarefree(x) : 0;4576}45774578static GEN4579fa_quaddisc(GEN f)4580{4581GEN P = gel(f,1), E = gel(f,2), s = gen_1;4582long i, l = lg(P);4583for (i = 1; i < l; i++) /* possibly including -1 */4584if (mpodd(gel(E,i))) s = mulii(s, gel(P,i));4585if (Mod4(s) > 1) s = shifti(s,2);4586return s;4587}45884589GEN4590quaddisc(GEN x)4591{4592const pari_sp av = avma;4593if (is_rational_t(typ(x))) x = factor(x);4594else x = check_arith_all(x,"quaddisc");4595return gerepileuptoint(av, fa_quaddisc(x));4596}45974598/*********************************************************************/4599/** **/4600/** FACTORIAL **/4601/** **/4602/*********************************************************************/4603GEN4604mulu_interval_step(ulong a, ulong b, ulong step)4605{4606pari_sp av = avma;4607ulong k, l, N, n;4608long lx;4609GEN x;46104611if (!a) return gen_0;4612if (step == 1) return mulu_interval(a, b);4613n = 1 + (b-a) / step;4614b -= (b-a) % step;4615if (n < 61)4616{4617if (n == 1) return utoipos(a);4618x = muluu(a,a+step); if (n == 2) return x;4619for (k=a+2*step; k<=b; k+=step) x = mului(k,x);4620return gerepileuptoint(av, x);4621}4622/* step | b-a */4623lx = 1; x = cgetg(2 + n/2, t_VEC);4624N = b + a;4625for (k = a;; k += step)4626{4627l = N - k; if (l <= k) break;4628gel(x,lx++) = muluu(k,l);4629}4630if (l == k) gel(x,lx++) = utoipos(k);4631setlg(x, lx);4632return gerepileuptoint(av, ZV_prod(x));4633}4634/* return a * (a+1) * ... * b. Assume a <= b [ note: factoring out powers of 24635* first is slower ... ] */4636GEN4637mulu_interval(ulong a, ulong b)4638{4639pari_sp av = avma;4640ulong k, l, N, n;4641long lx;4642GEN x;46434644if (!a) return gen_0;4645n = b - a + 1;4646if (n < 61)4647{4648if (n == 1) return utoipos(a);4649x = muluu(a,a+1); if (n == 2) return x;4650for (k=a+2; k<=b; k++) x = mului(k,x);4651return gerepileuptoint(av, x);4652}4653lx = 1; x = cgetg(2 + n/2, t_VEC);4654N = b + a;4655for (k = a;; k++)4656{4657l = N - k; if (l <= k) break;4658gel(x,lx++) = muluu(k,l);4659}4660if (l == k) gel(x,lx++) = utoipos(k);4661setlg(x, lx);4662return gerepileuptoint(av, ZV_prod(x));4663}4664GEN4665muls_interval(long a, long b)4666{4667pari_sp av = avma;4668long lx, k, l, N, n = b - a + 1;4669GEN x;46704671if (a <= 0 && b >= 0) return gen_0;4672if (n < 61)4673{4674x = stoi(a);4675for (k=a+1; k<=b; k++) x = mulsi(k,x);4676return gerepileuptoint(av, x);4677}4678lx = 1; x = cgetg(2 + n/2, t_VEC);4679N = b + a;4680for (k = a;; k++)4681{4682l = N - k; if (l <= k) break;4683gel(x,lx++) = mulss(k,l);4684}4685if (l == k) gel(x,lx++) = stoi(k);4686setlg(x, lx);4687return gerepileuptoint(av, ZV_prod(x));4688}46894690GEN4691mpfact(long n)4692{4693pari_sp av = avma;4694GEN a, v;4695long k;4696if (n <= 12) switch(n)4697{4698case 0: case 1: return gen_1;4699case 2: return gen_2;4700case 3: return utoipos(6);4701case 4: return utoipos(24);4702case 5: return utoipos(120);4703case 6: return utoipos(720);4704case 7: return utoipos(5040);4705case 8: return utoipos(40320);4706case 9: return utoipos(362880);4707case 10:return utoipos(3628800);4708case 11:return utoipos(39916800);4709case 12:return utoipos(479001600);4710default: pari_err_DOMAIN("factorial", "argument","<",gen_0,stoi(n));4711}4712v = cgetg(expu(n) + 2, t_VEC);4713for (k = 1;; k++)4714{4715long m = n >> (k-1), l;4716if (m <= 2) break;4717l = (1 + (n >> k)) | 1;4718/* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */4719a = mulu_interval_step(l, m, 2);4720gel(v,k) = k == 1? a: powiu(a, k);4721}4722a = gel(v,--k); while (--k) a = mulii(a, gel(v,k));4723a = shifti(a, factorial_lval(n, 2));4724return gerepileuptoint(av, a);4725}47264727ulong4728factorial_Fl(long n, ulong p)4729{4730long k;4731ulong v;4732if (p <= (ulong)n) return 0;4733v = Fl_powu(2, factorial_lval(n, 2), p);4734for (k = 1;; k++)4735{4736long m = n >> (k-1), l, i;4737ulong a = 1;4738if (m <= 2) break;4739l = (1 + (n >> k)) | 1;4740/* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */4741for (i=l; i<=m; i+=2)4742a = Fl_mul(a, i, p);4743v = Fl_mul(v, k == 1? a: Fl_powu(a, k, p), p);4744}4745return v;4746}47474748GEN4749factorial_Fp(long n, GEN p)4750{4751pari_sp av = avma;4752long k;4753GEN v = Fp_powu(gen_2, factorial_lval(n, 2), p);4754for (k = 1;; k++)4755{4756long m = n >> (k-1), l, i;4757GEN a = gen_1;4758if (m <= 2) break;4759l = (1 + (n >> k)) | 1;4760/* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */4761for (i=l; i<=m; i+=2)4762a = Fp_mulu(a, i, p);4763v = Fp_mul(v, k == 1? a: Fp_powu(a, k, p), p);4764v = gerepileuptoint(av, v);4765}4766return v;4767}47684769/*******************************************************************/4770/** **/4771/** LUCAS & FIBONACCI **/4772/** **/4773/*******************************************************************/4774static void4775lucas(ulong n, GEN *a, GEN *b)4776{4777GEN z, t, zt;4778if (!n) { *a = gen_2; *b = gen_1; return; }4779lucas(n >> 1, &z, &t); zt = mulii(z, t);4780switch(n & 3) {4781case 0: *a = subiu(sqri(z),2); *b = subiu(zt,1); break;4782case 1: *a = subiu(zt,1); *b = addiu(sqri(t),2); break;4783case 2: *a = addiu(sqri(z),2); *b = addiu(zt,1); break;4784case 3: *a = addiu(zt,1); *b = subiu(sqri(t),2);4785}4786}47874788GEN4789fibo(long n)4790{4791pari_sp av = avma;4792GEN a, b;4793if (!n) return gen_0;4794lucas((ulong)(labs(n)-1), &a, &b);4795a = diviuexact(addii(shifti(a,1),b), 5);4796if (n < 0 && !odd(n)) setsigne(a, -1);4797return gerepileuptoint(av, a);4798}47994800/*******************************************************************/4801/* */4802/* CONTINUED FRACTIONS */4803/* */4804/*******************************************************************/4805static GEN4806icopy_lg(GEN x, long l)4807{4808long lx = lgefint(x);4809GEN y;48104811if (lx >= l) return icopy(x);4812y = cgeti(l); affii(x, y); return y;4813}48144815/* continued fraction of a/b. If y != NULL, stop when partial quotients4816* differ from y */4817static GEN4818Qsfcont(GEN a, GEN b, GEN y, ulong k)4819{4820GEN z, c;4821ulong i, l, ly = lgefint(b);48224823/* times 1 / log2( (1+sqrt(5)) / 2 ) */4824l = (ulong)(3 + bit_accuracy_mul(ly, 1.44042009041256));4825if (k > 0 && k+1 > 0 && l > k+1) l = k+1; /* beware overflow */4826if (l > LGBITS) l = LGBITS;48274828z = cgetg(l,t_VEC);4829l--;4830if (y) {4831pari_sp av = avma;4832if (l >= (ulong)lg(y)) l = lg(y)-1;4833for (i = 1; i <= l; i++)4834{4835GEN q = gel(y,i);4836gel(z,i) = q;4837c = b; if (!gequal1(q)) c = mulii(q, b);4838c = subii(a, c);4839if (signe(c) < 0)4840{ /* partial quotient too large */4841c = addii(c, b);4842if (signe(c) >= 0) i++; /* by 1 */4843break;4844}4845if (cmpii(c, b) >= 0)4846{ /* partial quotient too small */4847c = subii(c, b);4848if (cmpii(c, b) < 0) {4849/* by 1. If next quotient is 1 in y, add 1 */4850if (i < l && equali1(gel(y,i+1))) gel(z,i) = addiu(q,1);4851i++;4852}4853break;4854}4855if ((i & 0xff) == 0) gerepileall(av, 2, &b, &c);4856a = b; b = c;4857}4858} else {4859a = icopy_lg(a, ly);4860b = icopy(b);4861for (i = 1; i <= l; i++)4862{4863gel(z,i) = truedvmdii(a,b,&c);4864if (c == gen_0) { i++; break; }4865affii(c, a); cgiv(c); c = a;4866a = b; b = c;4867}4868}4869i--;4870if (i > 1 && gequal1(gel(z,i)))4871{4872cgiv(gel(z,i)); --i;4873gel(z,i) = addui(1, gel(z,i)); /* unclean: leave old z[i] on stack */4874}4875setlg(z,i+1); return z;4876}48774878static GEN4879sersfcont(GEN a, GEN b, long k)4880{4881long i, l = typ(a) == t_POL? lg(a): 3;4882GEN y, c;4883if (lg(b) > l) l = lg(b);4884if (k > 0 && l > k+1) l = k+1;4885y = cgetg(l,t_VEC);4886for (i=1; i<l; i++)4887{4888gel(y,i) = poldivrem(a,b,&c);4889if (gequal0(c)) { i++; break; }4890a = b; b = c;4891}4892setlg(y, i); return y;4893}48944895GEN4896gboundcf(GEN x, long k)4897{4898pari_sp av;4899long tx = typ(x), e;4900GEN y, a, b, c;49014902if (k < 0) pari_err_DOMAIN("gboundcf","nmax","<",gen_0,stoi(k));4903if (is_scalar_t(tx))4904{4905if (gequal0(x)) return mkvec(gen_0);4906switch(tx)4907{4908case t_INT: return mkveccopy(x);4909case t_REAL:4910av = avma;4911c = mantissa_real(x,&e);4912if (e < 0) pari_err_PREC("gboundcf");4913y = int2n(e);4914a = Qsfcont(c,y, NULL, k);4915b = addsi(signe(x), c);4916return gerepilecopy(av, Qsfcont(b,y, a, k));49174918case t_FRAC:4919av = avma;4920return gerepileupto(av, Qsfcont(gel(x,1),gel(x,2), NULL, k));4921}4922pari_err_TYPE("gboundcf",x);4923}49244925switch(tx)4926{4927case t_POL: return mkveccopy(x);4928case t_SER:4929av = avma;4930return gerepileupto(av, gboundcf(ser2rfrac_i(x), k));4931case t_RFRAC:4932av = avma;4933return gerepilecopy(av, sersfcont(gel(x,1), gel(x,2), k));4934}4935pari_err_TYPE("gboundcf",x);4936return NULL; /* LCOV_EXCL_LINE */4937}49384939static GEN4940sfcont2(GEN b, GEN x, long k)4941{4942pari_sp av = avma;4943long lb = lg(b), tx = typ(x), i;4944GEN y,p1;49454946if (k)4947{4948if (k >= lb) pari_err_DIM("contfrac [too few denominators]");4949lb = k+1;4950}4951y = cgetg(lb,t_VEC);4952if (lb==1) return y;4953if (is_scalar_t(tx))4954{4955if (!is_intreal_t(tx) && tx != t_FRAC) pari_err_TYPE("sfcont2",x);4956}4957else if (tx == t_SER) x = ser2rfrac_i(x);49584959if (!gequal1(gel(b,1))) x = gmul(gel(b,1),x);4960for (i = 1;;)4961{4962if (tx == t_REAL)4963{4964long e = expo(x);4965if (e > 0 && nbits2prec(e+1) > realprec(x)) break;4966gel(y,i) = floorr(x);4967p1 = subri(x, gel(y,i));4968}4969else4970{4971gel(y,i) = gfloor(x);4972p1 = gsub(x, gel(y,i));4973}4974if (++i >= lb) break;4975if (gequal0(p1)) break;4976x = gdiv(gel(b,i),p1);4977}4978setlg(y,i);4979return gerepilecopy(av,y);4980}49814982GEN4983gcf(GEN x) { return gboundcf(x,0); }4984GEN4985gcf2(GEN b, GEN x) { return contfrac0(x,b,0); }4986GEN4987contfrac0(GEN x, GEN b, long nmax)4988{4989long tb;49904991if (!b) return gboundcf(x,nmax);4992tb = typ(b);4993if (tb == t_INT) return gboundcf(x,itos(b));4994if (! is_vec_t(tb)) pari_err_TYPE("contfrac0",b);4995if (nmax < 0) pari_err_DOMAIN("contfrac","nmax","<",gen_0,stoi(nmax));4996return sfcont2(b,x,nmax);4997}49984999GEN5000contfracpnqn(GEN x, long n)5001{5002pari_sp av = avma;5003long i, lx = lg(x);5004GEN M,A,B, p0,p1, q0,q1;50055006if (lx == 1)5007{5008if (! is_matvec_t(typ(x))) pari_err_TYPE("pnqn",x);5009if (n >= 0) return cgetg(1,t_MAT);5010return matid(2);5011}5012switch(typ(x))5013{5014case t_VEC: case t_COL: A = x; B = NULL; break;5015case t_MAT:5016switch(lgcols(x))5017{5018case 2: A = row(x,1); B = NULL; break;5019case 3: A = row(x,2); B = row(x,1); break;5020default: pari_err_DIM("pnqn [ nbrows != 1,2 ]");5021return NULL; /*LCOV_EXCL_LINE*/5022}5023break;5024default: pari_err_TYPE("pnqn",x);5025return NULL; /*LCOV_EXCL_LINE*/5026}5027p1 = gel(A,1);5028q1 = B? gel(B,1): gen_1; /* p[0], q[0] */5029if (n >= 0)5030{5031lx = minss(lx, n+2);5032if (lx == 2) return gerepilecopy(av, mkmat(mkcol2(p1,q1)));5033}5034else if (lx == 2)5035return gerepilecopy(av, mkmat2(mkcol2(p1,q1), mkcol2(gen_1,gen_0)));5036/* lx >= 3 */5037p0 = gen_1;5038q0 = gen_0; /* p[-1], q[-1] */5039M = cgetg(lx, t_MAT);5040gel(M,1) = mkcol2(p1,q1);5041for (i=2; i<lx; i++)5042{5043GEN a = gel(A,i), p2,q2;5044if (B) {5045GEN b = gel(B,i);5046p0 = gmul(b,p0);5047q0 = gmul(b,q0);5048}5049p2 = gadd(gmul(a,p1),p0); p0=p1; p1=p2;5050q2 = gadd(gmul(a,q1),q0); q0=q1; q1=q2;5051gel(M,i) = mkcol2(p1,q1);5052}5053if (n < 0) M = mkmat2(gel(M,lx-1), gel(M,lx-2));5054return gerepilecopy(av, M);5055}5056GEN5057pnqn(GEN x) { return contfracpnqn(x,-1); }5058/* x = [a0, ..., an] from gboundcf, n >= 0;5059* return [[p0, ..., pn], [q0,...,qn]] */5060GEN5061ZV_allpnqn(GEN x)5062{5063long i, lx = lg(x);5064GEN p0, p1, q0, q1, p2, q2, P,Q, v = cgetg(3,t_VEC);50655066gel(v,1) = P = cgetg(lx, t_VEC);5067gel(v,2) = Q = cgetg(lx, t_VEC);5068p0 = gen_1; q0 = gen_0;5069gel(P, 1) = p1 = gel(x,1); gel(Q, 1) = q1 = gen_1;5070for (i=2; i<lx; i++)5071{5072GEN a = gel(x,i);5073gel(P, i) = p2 = addmulii(p0, a, p1); p0 = p1; p1 = p2;5074gel(Q, i) = q2 = addmulii(q0, a, q1); q0 = q1; q1 = q2;5075}5076return v;5077}50785079/* write Mod(x,N) as a/b, gcd(a,b) = 1, b <= B (no condition if B = NULL) */5080static GEN5081mod_to_frac(GEN x, GEN N, GEN B)5082{5083GEN a, b, A;5084if (B) A = divii(shifti(N, -1), B);5085else5086{5087A = sqrti(shifti(N, -1));5088B = A;5089}5090if (!Fp_ratlift(x, N, A,B,&a,&b) || !equali1( gcdii(a,b) )) return NULL;5091return equali1(b)? a: mkfrac(a,b);5092}50935094static GEN5095mod_to_rfrac(GEN x, GEN N, long B)5096{5097GEN a, b;5098long A, d = degpol(N);5099if (B >= 0) A = d-1 - B;5100else5101{5102B = d >> 1;5103A = odd(d)? B : B-1;5104}5105if (varn(N) != varn(x)) x = scalarpol(x, varn(N));5106if (!RgXQ_ratlift(x, N, A, B, &a,&b) || degpol(RgX_gcd(a,b)) > 0) return NULL;5107return gdiv(a,b);5108}51095110/* k > 0 t_INT, x a t_FRAC, returns the convergent a/b5111* of the continued fraction of x with b <= k maximal */5112static GEN5113bestappr_frac(GEN x, GEN k)5114{5115pari_sp av;5116GEN p0, p1, p, q0, q1, q, a, y;51175118if (cmpii(gel(x,2),k) <= 0) return gcopy(x);5119av = avma; y = x;5120p1 = gen_1; p0 = truedvmdii(gel(x,1), gel(x,2), &a); /* = floor(x) */5121q1 = gen_0; q0 = gen_1;5122x = mkfrac(a, gel(x,2)); /* = frac(x); now 0<= x < 1 */5123for(;;)5124{5125x = ginv(x); /* > 1 */5126a = typ(x)==t_INT? x: divii(gel(x,1), gel(x,2));5127if (cmpii(a,k) > 0)5128{ /* next partial quotient will overflow limits */5129GEN n, d;5130a = divii(subii(k, q1), q0);5131p = addii(mulii(a,p0), p1); p1=p0; p0=p;5132q = addii(mulii(a,q0), q1); q1=q0; q0=q;5133/* compare |y-p0/q0|, |y-p1/q1| */5134n = gel(y,1);5135d = gel(y,2);5136if (abscmpii(mulii(q1, subii(mulii(q0,n), mulii(d,p0))),5137mulii(q0, subii(mulii(q1,n), mulii(d,p1)))) < 0)5138{ p1 = p0; q1 = q0; }5139break;5140}5141p = addii(mulii(a,p0), p1); p1=p0; p0=p;5142q = addii(mulii(a,q0), q1); q1=q0; q0=q;51435144if (cmpii(q0,k) > 0) break;5145x = gsub(x,a); /* 0 <= x < 1 */5146if (typ(x) == t_INT) { p1 = p0; q1 = q0; break; } /* x = 0 */51475148}5149return gerepileupto(av, gdiv(p1,q1));5150}5151/* k > 0 t_INT, x != 0 a t_REAL, returns the convergent a/b5152* of the continued fraction of x with b <= k maximal */5153static GEN5154bestappr_real(GEN x, GEN k)5155{5156pari_sp av = avma;5157GEN kr, p0, p1, p, q0, q1, q, a, y = x;51585159p1 = gen_1; a = p0 = floorr(x);5160q1 = gen_0; q0 = gen_1;5161x = subri(x,a); /* 0 <= x < 1 */5162if (!signe(x)) { cgiv(x); return a; }5163kr = itor(k, realprec(x));5164for(;;)5165{5166long d;5167x = invr(x); /* > 1 */5168if (cmprr(x,kr) > 0)5169{ /* next partial quotient will overflow limits */5170a = divii(subii(k, q1), q0);5171p = addii(mulii(a,p0), p1); p1=p0; p0=p;5172q = addii(mulii(a,q0), q1); q1=q0; q0=q;5173/* compare |y-p0/q0|, |y-p1/q1| */5174if (abscmprr(mulir(q1, subri(mulir(q0,y), p0)),5175mulir(q0, subri(mulir(q1,y), p1))) < 0)5176{ p1 = p0; q1 = q0; }5177break;5178}5179d = nbits2prec(expo(x) + 1);5180if (d > lg(x)) { p1 = p0; q1 = q0; break; } /* original x was ~ 0 */51815182a = truncr(x); /* truncr(x) will NOT raise e_PREC */5183p = addii(mulii(a,p0), p1); p1=p0; p0=p;5184q = addii(mulii(a,q0), q1); q1=q0; q0=q;51855186if (cmpii(q0,k) > 0) break;5187x = subri(x,a); /* 0 <= x < 1 */5188if (!signe(x)) { p1 = p0; q1 = q0; break; }5189}5190if (signe(q1) < 0) { togglesign_safe(&p1); togglesign_safe(&q1); }5191return gerepilecopy(av, equali1(q1)? p1: mkfrac(p1,q1));5192}51935194/* k t_INT or NULL */5195static GEN5196bestappr_Q(GEN x, GEN k)5197{5198long lx, tx = typ(x), i;5199GEN a, y;52005201switch(tx)5202{5203case t_INT: return icopy(x);5204case t_FRAC: return k? bestappr_frac(x, k): gcopy(x);5205case t_REAL:5206if (!signe(x)) return gen_0;5207/* i <= e iff nbits2lg(e+1) > lg(x) iff floorr(x) fails */5208i = bit_prec(x); if (i <= expo(x)) return NULL;5209return bestappr_real(x, k? k: int2n(i));52105211case t_INTMOD: {5212pari_sp av = avma;5213a = mod_to_frac(gel(x,2), gel(x,1), k); if (!a) return NULL;5214return gerepilecopy(av, a);5215}5216case t_PADIC: {5217pari_sp av = avma;5218long v = valp(x);5219a = mod_to_frac(gel(x,4), gel(x,3), k); if (!a) return NULL;5220if (v) a = gmul(a, powis(gel(x,2), v));5221return gerepilecopy(av, a);5222}52235224case t_COMPLEX: {5225pari_sp av = avma;5226y = cgetg(3, t_COMPLEX);5227gel(y,2) = bestappr(gel(x,2), k);5228gel(y,1) = bestappr(gel(x,1), k);5229if (gequal0(gel(y,2))) return gerepileupto(av, gel(y,1));5230return y;5231}5232case t_SER:5233if (ser_isexactzero(x)) return gcopy(x);5234/* fall through */5235case t_POLMOD: case t_POL: case t_RFRAC:5236case t_VEC: case t_COL: case t_MAT:5237y = cgetg_copy(x, &lx);5238if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }5239for (; i<lx; i++)5240{5241a = bestappr_Q(gel(x,i),k); if (!a) return NULL;5242gel(y,i) = a;5243}5244if (tx == t_POL) return normalizepol(y);5245if (tx == t_SER) return normalize(y);5246return y;5247}5248pari_err_TYPE("bestappr_Q",x);5249return NULL; /* LCOV_EXCL_LINE */5250}52515252static GEN5253bestappr_ser(GEN x, long B)5254{5255long dN, v = valp(x), lx = lg(x);5256GEN t;5257x = normalizepol(ser2pol_i(x, lx));5258dN = lx-2;5259if (v > 0)5260{5261x = RgX_shift_shallow(x, v);5262dN += v;5263}5264else if (v < 0)5265{5266if (B >= 0) B = maxss(B+v, 0);5267}5268t = mod_to_rfrac(x, pol_xn(dN, varn(x)), B);5269if (!t) return NULL;5270if (v < 0)5271{5272GEN a, b;5273long vx;5274if (typ(t) == t_POL) return RgX_mulXn(t, v);5275/* t_RFRAC */5276vx = varn(x);5277a = gel(t,1);5278b = gel(t,2);5279v -= RgX_valrem(b, &b);5280if (typ(a) == t_POL && varn(a) == vx) v += RgX_valrem(a, &a);5281if (v < 0) b = RgX_shift(b, -v);5282else if (v > 0) {5283if (typ(a) != t_POL || varn(a) != vx) a = scalarpol_shallow(a, vx);5284a = RgX_shift(a, v);5285}5286t = mkrfraccopy(a, b);5287}5288return t;5289}5290static GEN bestappr_RgX(GEN x, long B);5291/* x t_POLMOD, B >= 0 or < 0 [omit condition on B].5292* Look for coprime t_POL a,b, deg(b)<=B, such that a/b = x */5293static GEN5294bestappr_RgX(GEN x, long B)5295{5296long i, lx, tx = typ(x);5297GEN y, t;5298switch(tx)5299{5300case t_INT: case t_REAL: case t_INTMOD: case t_FRAC:5301case t_COMPLEX: case t_PADIC: case t_QUAD: case t_POL:5302return gcopy(x);53035304case t_RFRAC: {5305pari_sp av = avma;5306if (B < 0 || degpol(gel(x,2)) <= B) return gcopy(x);5307x = rfrac_to_ser(x, 2*B+1);5308t = bestappr_ser(x, B); if (!t) return NULL;5309return gerepileupto(av, t);5310}5311case t_POLMOD: {5312pari_sp av = avma;5313t = mod_to_rfrac(gel(x,2), gel(x,1), B); if (!t) return NULL;5314return gerepileupto(av, t);5315}5316case t_SER: {5317pari_sp av = avma;5318t = bestappr_ser(x, B); if (!t) return NULL;5319return gerepileupto(av, t);5320}53215322case t_VEC: case t_COL: case t_MAT:5323y = cgetg_copy(x, &lx);5324if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }5325for (; i<lx; i++)5326{5327t = bestappr_RgX(gel(x,i),B); if (!t) return NULL;5328gel(y,i) = t;5329}5330return y;5331}5332pari_err_TYPE("bestappr_RgX",x);5333return NULL; /* LCOV_EXCL_LINE */5334}53355336/* allow k = NULL: maximal accuracy */5337GEN5338bestappr(GEN x, GEN k)5339{5340pari_sp av = avma;5341if (k) { /* replace by floor(k) */5342switch(typ(k))5343{5344case t_INT:5345break;5346case t_REAL: case t_FRAC:5347k = floor_safe(k); /* left on stack for efficiency */5348if (!signe(k)) k = gen_1;5349break;5350default:5351pari_err_TYPE("bestappr [bound type]", k);5352break;5353}5354}5355x = bestappr_Q(x, k);5356if (!x) { set_avma(av); return cgetg(1,t_VEC); }5357return x;5358}5359GEN5360bestapprPade(GEN x, long B)5361{5362pari_sp av = avma;5363GEN t = bestappr_RgX(x, B);5364if (!t) { set_avma(av); return cgetg(1,t_VEC); }5365return t;5366}53675368/***********************************************************************/5369/** **/5370/** FUNDAMENTAL UNIT AND REGULATOR (QUADRATIC FIELDS) **/5371/** **/5372/***********************************************************************/53735374static GEN5375get_quad(GEN f, GEN pol, long r)5376{5377GEN p1 = gcoeff(f,1,2), q1 = gcoeff(f,2,2);5378return mkquad(pol, r? subii(p1,q1): p1, q1);5379}53805381/* replace f by f * [a,1; 1,0] */5382static void5383update_f(GEN f, GEN a)5384{5385GEN p1;5386p1 = gcoeff(f,1,1);5387gcoeff(f,1,1) = addii(mulii(a,p1), gcoeff(f,1,2));5388gcoeff(f,1,2) = p1;53895390p1 = gcoeff(f,2,1);5391gcoeff(f,2,1) = addii(mulii(a,p1), gcoeff(f,2,2));5392gcoeff(f,2,2) = p1;5393}53945395/*5396* fm is a vector of matrices and i an index5397* the bits of i give the non-zero entries5398* the product of the non zero entries is the5399* actual result.5400* if i odd, fm[1] is implicitely [fm[1],1;1,0]5401*/54025403static void5404update_fm(GEN f, GEN a, long i)5405{5406if (!odd(i))5407gel(f,1) = a;5408else5409{5410long v = vals(i+1), k;5411GEN b = gel(f,1);5412GEN u = mkmat22(addiu(mulii(a, b), 1), b, a, gen_1);5413gel(f,1) = gen_0;5414for (k = 1; k < v; k++)5415{5416u = ZM2_mul(gel(f, k+1), u);5417gel(f,k+1) = gen_0; /* for gerepileall */5418}5419gel(f,v+1) = u;5420}5421}54225423static GEN5424prod_fm(GEN f, long i)5425{5426long v = vals(i);5427GEN u;5428long k;5429if (!v) u = mkmat22(gel(f,1),gen_1,gen_1,gen_0);5430else u = gel(f,v+1);5431v++;5432for (i>>=v, k = v+1; i; i>>=1, k++)5433if (odd(i))5434u = ZM2_mul(gel(f,k), u);5435return u;5436}54375438GEN5439quadunit(GEN x)5440{5441pari_sp av = avma, av2;5442GEN pol, y, a, u, v, sqd, f;5443long r, i = 1;54445445check_quaddisc_real(x, &r, "quadunit");5446pol = quadpoly(x);5447sqd = sqrti(x); av2 = avma;5448a = shifti(addui(r,sqd),-1);5449f = zerovec(2+(expi(x)>>1));5450gel(f,1) = a;5451u = stoi(r); v = gen_2;5452for(;;)5453{5454GEN u1, v1;5455u1 = subii(mulii(a,v),u);5456v1 = divii(subii(x,sqri(u1)),v);5457if ( equalii(v,v1) ) {5458f = prod_fm(f,i);5459y = get_quad(f,pol,r);5460update_f(f,a);5461y = gdiv(get_quad(f,pol,r), conj_i(y));5462break;5463}5464a = divii(addii(sqd,u1), v1);5465if ( equalii(u,u1) ) {5466y = get_quad(prod_fm(f,i),pol,r);5467y = gdiv(y, conj_i(y));5468break;5469}5470update_fm(f,a,i++);5471u = u1; v = v1;5472if (gc_needed(av2,2))5473{5474if(DEBUGMEM>1) pari_warn(warnmem,"quadunit (%ld)", i);5475gerepileall(av2,4, &a,&f,&u,&v);5476}5477}5478if (signe(gel(y,3)) < 0) y = gneg(y);5479return gerepileupto(av, y);5480}54815482GEN5483quadunit0(GEN x, long v)5484{5485GEN y = quadunit(x);5486if (v==-1) v = fetch_user_var("w");5487setvarn(gel(y,1), v);5488return y;5489}54905491GEN5492quadregulator(GEN x, long prec)5493{5494pari_sp av = avma, av2;5495GEN R, rsqd, u, v, sqd;5496long r, Rexpo;54975498check_quaddisc_real(x, &r, "quadregulator");5499sqd = sqrti(x);5500rsqd = gsqrt(x,prec);5501Rexpo = 0; R = real2n(1, prec); /* = 2 */5502av2 = avma;5503u = stoi(r); v = gen_2;5504for(;;)5505{5506GEN u1 = subii(mulii(divii(addii(u,sqd),v), v), u);5507GEN v1 = divii(subii(x,sqri(u1)),v);5508if (equalii(v,v1))5509{5510R = sqrr(R); shiftr_inplace(R, -1);5511R = mulrr(R, divri(addir(u1,rsqd),v));5512break;5513}5514if (equalii(u,u1))5515{5516R = sqrr(R); shiftr_inplace(R, -1);5517break;5518}5519R = mulrr(R, divri(addir(u1,rsqd),v));5520Rexpo += expo(R); setexpo(R,0);5521u = u1; v = v1;5522if (Rexpo & ~EXPOBITS) pari_err_OVERFLOW("quadregulator [exponent]");5523if (gc_needed(av2,2))5524{5525if(DEBUGMEM>1) pari_warn(warnmem,"quadregulator");5526gerepileall(av2,3, &R,&u,&v);5527}5528}5529R = logr_abs(divri(R,v));5530if (Rexpo)5531{5532GEN t = mulsr(Rexpo, mplog2(prec));5533shiftr_inplace(t, 1);5534R = addrr(R,t);5535}5536return gerepileuptoleaf(av, R);5537}55385539/*************************************************************************/5540/** **/5541/** CLASS NUMBER **/5542/** **/5543/*************************************************************************/55445545int5546qfb_equal1(GEN f) { return equali1(gel(f,1)); }55475548static GEN qfi_pow(void *E, GEN f, GEN n)5549{ return E? nupow(f,n,(GEN)E): qfbpow_i(f,n); }5550static GEN qfi_comp(void *E, GEN f, GEN g)5551{ return E? nucomp(f,g,(GEN)E): qfbcomp_i(f,g); }5552static const struct bb_group qfi_group={ qfi_comp,qfi_pow,NULL,hash_GEN,5553gidentical,qfb_equal1,NULL};55545555GEN5556qfi_order(GEN q, GEN o)5557{ return gen_order(q, o, NULL, &qfi_group); }55585559GEN5560qfi_log(GEN a, GEN g, GEN o)5561{ return gen_PH_log(a, g, o, NULL, &qfi_group); }55625563GEN5564qfi_Shanks(GEN a, GEN g, long n)5565{5566pari_sp av = avma;5567GEN T, X;5568long rt_n, c;55695570a = qfbred_i(a);5571g = qfbred_i(g);55725573rt_n = sqrt((double)n);5574c = n / rt_n;5575c = (c * rt_n < n + 1) ? c + 1 : c;55765577T = gen_Shanks_init(g, rt_n, NULL, &qfi_group);5578X = gen_Shanks(T, a, c, NULL, &qfi_group);5579return X? gerepileuptoint(av, X): gc_NULL(av);5580}55815582GEN5583qfbclassno0(GEN x,long flag)5584{5585switch(flag)5586{5587case 0: return map_proto_G(classno,x);5588case 1: return map_proto_G(classno2,x);5589default: pari_err_FLAG("qfbclassno");5590}5591return NULL; /* LCOV_EXCL_LINE */5592}55935594/* f^h = 1, return order(f). Set *pfao to its factorization */5595static GEN5596find_order(void *E, GEN f, GEN h, GEN *pfao)5597{5598GEN v = gen_factored_order(f, h, E, &qfi_group);5599*pfao = gel(v,2); return gel(v,1);5600}56015602static int5603ok_q(GEN q, GEN h, GEN d2, long r2)5604{5605if (d2)5606{5607if (r2 <= 2 && !mpodd(q)) return 0;5608return is_pm1(Z_ppo(q,d2));5609}5610else5611{5612if (r2 <= 1 && !mpodd(q)) return 0;5613return is_pm1(Z_ppo(q,h));5614}5615}56165617/* a,b given by their factorizations. Return factorization of lcm(a,b).5618* Set A,B such that A*B = lcm(a, b), (A,B)=1, A|a, B|b */5619static GEN5620split_lcm(GEN a, GEN Fa, GEN b, GEN Fb, GEN *pA, GEN *pB)5621{5622GEN P = ZC_union_shallow(gel(Fa,1), gel(Fb,1));5623GEN A = gen_1, B = gen_1;5624long i, l = lg(P);5625GEN E = cgetg(l, t_COL);5626for (i=1; i<l; i++)5627{5628GEN p = gel(P,i);5629long va = Z_pval(a,p);5630long vb = Z_pval(b,p);5631if (va < vb)5632{5633B = mulii(B,powiu(p,vb));5634gel(E,i) = utoi(vb);5635}5636else5637{5638A = mulii(A,powiu(p,va));5639gel(E,i) = utoi(va);5640}5641}5642*pA = A;5643*pB = B; return mkmat2(P,E);5644}56455646/* g1 has order d1, f has order o, replace g1 by an element of order lcm(d1,o)*/5647static void5648update_g1(GEN *pg1, GEN *pd1, GEN *pfad1, GEN f, GEN o, GEN fao)5649{5650GEN A,B, g1 = *pg1, d1 = *pd1;5651*pfad1 = split_lcm(d1,*pfad1, o,fao, &A,&B);5652*pg1 = gmul(qfbpow_i(g1, diviiexact(d1,A)), qfbpow_i(f, diviiexact(o,B)));5653*pd1 = mulii(A,B); /* g1 has order d1 <- lcm(d1,o) */5654}56555656/* Write x = Df^2, where D = fundamental discriminant,5657* P^E = factorisation of conductor f, with E[i] >= 0 */5658static void5659corediscfact(GEN x, long xmod4, GEN *ptD, GEN *ptP, GEN *ptE)5660{5661long s = signe(x), l, i;5662GEN fa = absZ_factor(x);5663GEN d, P = gel(fa,1), E = gtovecsmall(gel(fa,2));56645665l = lg(P); d = gen_1;5666for (i=1; i<l; i++)5667{5668if (E[i] & 1) d = mulii(d, gel(P,i));5669E[i] >>= 1;5670}5671if (!xmod4 && mod4(d) != ((s < 0)? 3: 1)) { d = shifti(d,2); E[1]--; }5672*ptD = (s < 0)? negi(d): d;5673*ptP = P;5674*ptE = E;5675}56765677static GEN5678conductor_part(GEN x, long xmod4, GEN *ptD, GEN *ptreg)5679{5680long l, i, s = signe(x);5681GEN E, H, D, P, reg;56825683corediscfact(x, xmod4, &D, &P, &E);5684H = gen_1; l = lg(P);5685/* f \prod_{p|f} [ 1 - (D/p) p^-1 ] = \prod_{p^e||f} p^(e-1) [ p - (D/p) ] */5686for (i=1; i<l; i++)5687{5688long e = E[i];5689if (e)5690{5691GEN p = gel(P,i);5692H = mulii(H, subis(p, kronecker(D,p)));5693if (e >= 2) H = mulii(H, powiu(p,e-1));5694}5695}56965697/* divide by [ O_K^* : O^* ] */5698if (s < 0)5699{5700reg = NULL;5701switch(itou_or_0(D))5702{5703case 4: H = shifti(H,-1); break;5704case 3: H = divis(H,3); break;5705}5706} else {5707reg = quadregulator(D,DEFAULTPREC);5708if (!equalii(x,D))5709H = divii(H, roundr(divrr(quadregulator(x,DEFAULTPREC), reg)));5710}5711if (ptreg) *ptreg = reg;5712*ptD = D; return H;5713}57145715static long5716two_rank(GEN x)5717{5718GEN p = gel(absZ_factor(x),1);5719long l = lg(p)-1;5720#if 0 /* positive disc not needed */5721if (signe(x) > 0)5722{5723long i;5724for (i=1; i<=l; i++)5725if (mod4(gel(p,i)) == 3) { l--; break; }5726}5727#endif5728return l-1;5729}57305731static GEN5732sqr_primeform(GEN x, ulong p) { return qfbsqr_i(primeform_u(x, p)); }5733/* return a set of forms hopefully generating Cl(K)^2; set L ~ L(chi_D,1) */5734static GEN5735get_forms(GEN D, GEN *pL)5736{5737const long MAXFORM = 20;5738GEN L, sqrtD = gsqrt(absi_shallow(D),DEFAULTPREC);5739GEN forms = vectrunc_init(MAXFORM+1);5740long s, nforms = 0;5741ulong p;5742forprime_t S;5743L = mulrr(divrr(sqrtD,mppi(DEFAULTPREC)), dbltor(1.005));/*overshoot by 0.5%*/5744s = itos_or_0( truncr(shiftr(sqrtr(sqrtD), 1)) );5745if (!s) pari_err_OVERFLOW("classno [discriminant too large]");5746if (s < 10) s = 200;5747else if (s < 20) s = 1000;5748else if (s < 5000) s = 5000;5749u_forprime_init(&S, 2, s);5750while ( (p = u_forprime_next(&S)) )5751{5752long d, k = kroiu(D,p);5753pari_sp av2;5754if (!k) continue;5755if (k > 0)5756{5757if (++nforms < MAXFORM) vectrunc_append(forms, sqr_primeform(D,p));5758d = p-1;5759}5760else5761d = p+1;5762av2 = avma; affrr(divru(mulur(p,L),d), L); set_avma(av2);5763}5764*pL = L; return forms;5765}57665767/* h ~ #G, return o = order of f, set fao = its factorization */5768static GEN5769Shanks_order(void *E, GEN f, GEN h, GEN *pfao)5770{5771long s = minss(itos(sqrti(h)), 10000);5772GEN T = gen_Shanks_init(f, s, E, &qfi_group);5773GEN v = gen_Shanks(T, ginv(f), ULONG_MAX, E, &qfi_group);5774return find_order(E, f, addiu(v,1), pfao);5775}57765777/* if g = 1 in G/<f> ? */5778static int5779equal1(void *E, GEN T, ulong N, GEN g)5780{ return !!gen_Shanks(T, g, N, E, &qfi_group); }57815782/* Order of 'a' in G/<f>, T = gen_Shanks_init(f,n), order(f) < n*N5783* FIXME: should be gen_order, but equal1 has the wrong prototype */5784static GEN5785relative_order(void *E, GEN a, GEN o, ulong N, GEN T)5786{5787pari_sp av = avma;5788long i, l;5789GEN m;57905791m = get_arith_ZZM(o);5792if (!m) pari_err_TYPE("gen_order [missing order]",a);5793o = gel(m,1);5794m = gel(m,2); l = lgcols(m);5795for (i = l-1; i; i--)5796{5797GEN t, y, p = gcoeff(m,i,1);5798long j, e = itos(gcoeff(m,i,2));5799if (l == 2) {5800t = gen_1;5801y = a;5802} else {5803t = diviiexact(o, powiu(p,e));5804y = powgi(a, t);5805}5806if (equal1(E, T,N,y)) o = t;5807else {5808for (j = 1; j < e; j++)5809{5810y = powgi(y, p);5811if (equal1(E, T,N,y)) break;5812}5813if (j < e) {5814if (j > 1) p = powiu(p, j);5815o = mulii(t, p);5816}5817}5818}5819return gerepilecopy(av, o);5820}58215822/* h(x) for x<0 using Baby Step/Giant Step.5823* Assumes G is not too far from being cyclic.5824*5825* Compute G^2 instead of G so as to kill most of the noncyclicity */5826GEN5827classno(GEN x)5828{5829pari_sp av = avma;5830long r2, k, s, i, l;5831GEN forms, hin, Hf, D, g1, d1, d2, q, L, fad1, order_bound;5832void *E;58335834if (signe(x) >= 0) return classno2(x);58355836check_quaddisc(x, &s, &k, "classno");5837if (abscmpiu(x,12) <= 0) return gen_1;58385839Hf = conductor_part(x, k, &D, NULL);5840if (abscmpiu(D,12) <= 0) return gerepilecopy(av, Hf);5841forms = get_forms(D, &L);5842r2 = two_rank(D);5843hin = roundr(shiftr(L, -r2)); /* rough approximation for #G, G = Cl(K)^2 */58445845l = lg(forms);5846order_bound = const_vec(l-1, NULL);5847E = expi(D) > 60? (void*)sqrtnint(shifti(absi_shallow(D),-2),4): NULL;5848g1 = gel(forms,1);5849gel(order_bound,1) = d1 = Shanks_order(E, g1, hin, &fad1);5850q = diviiround(hin, d1); /* approximate order of G/<g1> */5851d2 = NULL; /* not computed yet */5852if (is_pm1(q)) goto END;5853for (i=2; i < l; i++)5854{5855GEN o, fao, a, F, fd, f = gel(forms,i);5856fd = qfbpow_i(f, d1); if (is_pm1(gel(fd,1))) continue;5857F = qfbpow_i(fd, q);5858a = gel(F,1);5859o = is_pm1(a)? find_order(E, fd, q, &fao): Shanks_order(E, fd, q, &fao);5860/* f^(d1 q) = 1 */5861fao = merge_factor(fad1,fao, (void*)&cmpii, &cmp_nodata);5862o = find_order(E, f, fao, &fao);5863gel(order_bound,i) = o;5864/* o = order of f, fao = factor(o) */5865update_g1(&g1,&d1,&fad1, f,o,fao);5866q = diviiround(hin, d1);5867if (is_pm1(q)) goto END;5868}5869/* very probably d1 = expo(Cl^2(K)), q ~ #Cl^2(K) / d1 */5870if (expi(q) > 3)5871{ /* q large: compute d2, 2nd elt divisor */5872ulong N, n = 2*itou(sqrti(d1));5873GEN D = d1, T = gen_Shanks_init(g1, n, E, &qfi_group);5874d2 = gen_1;5875N = itou( gceil(gdivgs(d1,n)) ); /* order(g1) <= n*N */5876for (i = 1; i < l; i++)5877{5878GEN d, f = gel(forms,i), B = gel(order_bound,i);5879if (!B) B = find_order(E, f, fad1, /*junk*/&d);5880f = qfbpow_i(f,d2);5881if (equal1(E, T,N,f)) continue;5882B = gdiv(B,d2); if (typ(B) == t_FRAC) B = gel(B,1);5883/* f^B = 1 */5884d = relative_order(E, f, B, N,T);5885d2= mulii(d,d2);5886D = mulii(d1,d2);5887q = diviiround(hin,D);5888if (is_pm1(q)) { d1 = D; goto END; }5889}5890/* very probably, d2 is the 2nd elementary divisor */5891d1 = D; /* product of first two elt divisors */5892}5893/* impose q | d2^oo (d1^oo if d2 not computed), and compatible with known5894* 2-rank */5895if (!ok_q(q,d1,d2,r2))5896{5897GEN q0 = q;5898long d;5899if (cmpii(mulii(q,d1), hin) < 0)5900{ /* try q = q0+1,-1,+2,-2 */5901d = 1;5902do { q = addis(q0,d); d = d>0? -d: 1-d; } while(!ok_q(q,d1,d2,r2));5903}5904else5905{ /* q0-1,+1,-2,+2 */5906d = -1;5907do { q = addis(q0,d); d = d<0? -d: -1-d; } while(!ok_q(q,d1,d2,r2));5908}5909}5910d1 = mulii(d1,q);59115912END:5913return gerepileuptoint(av, shifti(mulii(d1,Hf), r2));5914}59155916GEN5917quadclassno(GEN x)5918{5919pari_sp av = avma;5920GEN Hf, D;5921long s, r;5922check_quaddisc(x, &s, &r, "quadclassno");5923if (s < 0 && abscmpiu(x,12) <= 0) return gen_1;5924Hf = conductor_part(x, r, &D, NULL);5925return gerepileuptoint(av, mulii(Hf, gel(quadclassunit0(D,0,NULL,0),1)));5926}59275928/* use Euler products */5929GEN5930classno2(GEN x)5931{5932pari_sp av = avma;5933const long prec = DEFAULTPREC;5934long n, i, r, s;5935GEN p1, p2, S, p4, p5, p7, Hf, Pi, reg, logd, d, dr, D, half;59365937check_quaddisc(x, &s, &r, "classno2");5938if (s < 0 && abscmpiu(x,12) <= 0) return gen_1;59395940Hf = conductor_part(x, r, &D, ®);5941if (s < 0 && abscmpiu(D,12) <= 0) return gerepilecopy(av, Hf); /* |D| < 12*/59425943Pi = mppi(prec);5944d = absi_shallow(D); dr = itor(d, prec);5945logd = logr_abs(dr);5946p1 = sqrtr(divrr(mulir(d,logd), gmul2n(Pi,1)));5947if (s > 0)5948{5949GEN invlogd = invr(logd);5950p2 = subsr(1, shiftr(mulrr(logr_abs(reg),invlogd),1));5951if (cmprr(sqrr(p2), shiftr(invlogd,1)) >= 0) p1 = mulrr(p2,p1);5952}5953n = itos_or_0( mptrunc(p1) );5954if (!n) pari_err_OVERFLOW("classno [discriminant too large]");59555956p4 = divri(Pi,d);5957p7 = invr(sqrtr_abs(Pi));5958half = real2n(-1, prec);5959if (s > 0)5960{ /* i = 1, shortcut */5961p1 = sqrtr_abs(dr);5962p5 = subsr(1, mulrr(p7,incgamc(half,p4,prec)));5963S = addrr(mulrr(p1,p5), eint1(p4,prec));5964for (i=2; i<=n; i++)5965{5966long k = kroiu(D,i); if (!k) continue;5967p2 = mulir(sqru(i), p4);5968p5 = subsr(1, mulrr(p7,incgamc(half,p2,prec)));5969p5 = addrr(divru(mulrr(p1,p5),i), eint1(p2,prec));5970S = (k>0)? addrr(S,p5): subrr(S,p5);5971}5972S = shiftr(divrr(S,reg),-1);5973}5974else5975{ /* i = 1, shortcut */5976p1 = gdiv(sqrtr_abs(dr), Pi);5977p5 = subsr(1, mulrr(p7,incgamc(half,p4,prec)));5978S = addrr(p5, divrr(p1, mpexp(p4)));5979for (i=2; i<=n; i++)5980{5981long k = kroiu(D,i); if (!k) continue;5982p2 = mulir(sqru(i), p4);5983p5 = subsr(1, mulrr(p7,incgamc(half,p2,prec)));5984p5 = addrr(p5, divrr(p1, mulur(i, mpexp(p2))));5985S = (k>0)? addrr(S,p5): subrr(S,p5);5986}5987}5988return gerepileuptoint(av, mulii(Hf, roundr(S)));5989}59905991/* 1 + q + ... + q^v, v > 0 */5992static GEN5993geomsumu(ulong q, long v)5994{5995GEN u = utoipos(1+q);5996for (; v > 1; v--) u = addui(1, mului(q, u));5997return u;5998}5999static GEN6000geomsum(GEN q, long v)6001{6002GEN u;6003if (lgefint(q) == 3) return geomsumu(q[2], v);6004u = addiu(q,1);6005for (; v > 1; v--) u = addui(1, mulii(q, u));6006return u;6007}60086009static GEN6010hclassno6_large(GEN x)6011{6012long i, l, s, xmod4;6013GEN H = NULL, D, P, E;60146015x = negi(x);6016check_quaddisc(x, &s, &xmod4, "hclassno");6017corediscfact(x, xmod4, &D, &P, &E);6018l = lg(P);6019if (l > 1 && lgefint(x) == 3)6020{ /* F != 1, second chance */6021ulong h = hclassno6u_from_cache(x[2]);6022if (h) H = utoipos(h);6023}6024if (!H)6025{6026GEN Q = quadclassunit0(D, 0, NULL, 0);6027H = gel(Q,1);6028switch(itou_or_0(D))6029{6030case 3: H = shifti(H,1);break;6031case 4: H = muliu(H,3); break;6032default:H = muliu(H,6); break;6033}6034}6035/* H \prod_{p^e||f} (1 + (p^e-1)/(p-1))[ p - (D/p) ] */6036for (i = 1; i < l; i++)6037{6038long e = E[i], s;6039GEN p, t;6040if (!e) continue;6041p = gel(P,i); s = kronecker(D,p);6042if (e == 1) t = addiu(p, 1-s);6043else if (s == 1) t = powiu(p, e);6044else t = addui(1, mulii(subis(p, s), geomsum(p, e-1)));6045H = mulii(H,t);6046}6047return H;6048}60496050/* x > 0, x = 0,3 (mod 4). Return 6*hclassno(x), an integer */6051GEN6052hclassno6(GEN x)6053{6054ulong d = itou_or_0(x);6055if (d)6056{ /* create cache if d small */6057ulong h = d < 500000 ? hclassno6u(d): hclassno6u_from_cache(d);6058if (h) return utoipos(h);6059}6060return hclassno6_large(x);6061}60626063GEN6064hclassno(GEN x)6065{6066long a, s;6067if (typ(x) != t_INT) pari_err_TYPE("hclassno",x);6068s = signe(x);6069if (s < 0) return gen_0;6070if (!s) return gdivgs(gen_1, -12);6071a = mod4(x); if (a == 1 || a == 2) return gen_0;6072return gdivgs(hclassno6(x), 6);6073}607460756076