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.9Check the License for details. You should have received a copy of it, along10with the package; see the file 'COPYING'. If not, write to the Free Software11Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1213/*******************************************************************/14/* */15/* MAXIMAL ORDERS */16/* */17/*******************************************************************/18#include "pari.h"19#include "paripriv.h"2021#define DEBUGLEVEL DEBUGLEVEL_nf2223/* allow p = -1 from factorizations, avoid oo loop on p = 1 */24static long25safe_Z_pvalrem(GEN x, GEN p, GEN *z)26{27if (is_pm1(p))28{29if (signe(p) > 0) return gvaluation(x,p); /*error*/30*z = absi(x); return 1;31}32return Z_pvalrem(x, p, z);33}34/* D an integer, P a ZV, return a factorization matrix for D over P, removing35* entries with 0 exponent. */36static GEN37fact_from_factors(GEN D, GEN P, long flag)38{39long i, l = lg(P), iq = 1;40GEN Q = cgetg(l+1,t_COL);41GEN E = cgetg(l+1,t_COL);42for (i=1; i<l; i++)43{44GEN p = gel(P,i);45long k;46if (flag && !equalim1(p))47{48p = gcdii(p, D);49if (is_pm1(p)) continue;50}51k = safe_Z_pvalrem(D, p, &D);52if (k) { gel(Q,iq) = p; gel(E,iq) = utoipos(k); iq++; }53}54D = absi_shallow(D);55if (!equali1(D))56{57long k = Z_isanypower(D, &D);58if (!k) k = 1;59gel(Q,iq) = D; gel(E,iq) = utoipos(k); iq++;60}61setlg(Q,iq);62setlg(E,iq); return mkmat2(Q,E);63}6465/* d a t_INT; f a t_MAT factorisation of some t_INT sharing some divisors66* with d, or a prime (t_INT). Return a factorization F of d: "primes"67* entries in f _may_ be composite, and are included as is in d. */68static GEN69update_fact(GEN d, GEN f)70{71GEN P;72switch (typ(f))73{74case t_INT: case t_VEC: case t_COL: return f;75case t_MAT:76if (lg(f) == 3) { P = gel(f,1); break; }77/*fall through*/78default:79pari_err_TYPE("nfbasis [factorization expected]",f);80return NULL;/*LCOV_EXCL_LINE*/81}82return fact_from_factors(d, P, 1);83}8485/* T = C T0(X/L); C = L^d / lt(T0), d = deg(T)86* disc T = C^2(d - 1) L^-(d(d-1)) disc T0 = (L^d / lt(T0)^2)^(d-1) disc T0 */87static GEN88set_disc(nfmaxord_t *S)89{90GEN L, dT;91long d;92if (S->T0 == S->T) return ZX_disc(S->T);93d = degpol(S->T0);94L = S->unscale;95if (typ(L) == t_FRAC && abscmpii(gel(L,1), gel(L,2)) < 0)96dT = ZX_disc(S->T); /* more efficient */97else98{99GEN l0 = leading_coeff(S->T0);100GEN a = gpowgs(gdiv(gpowgs(L, d), sqri(l0)), d-1);101dT = gmul(a, ZX_disc(S->T0)); /* more efficient */102}103return S->dT = dT;104}105106/* dT != 0 */107static GEN108poldiscfactors_i(GEN T, GEN dT, long flag)109{110GEN U, fa, Z, E, P, Tp;111long i, l;112113fa = absZ_factor_limit_strict(dT, minuu(tridiv_bound(dT), maxprime()), &U);114if (!U) return fa;115Z = mkcol(gel(U,1)); P = gel(fa,1); Tp = NULL;116while (lg(Z) != 1)117{ /* pop and handle last element of Z */118GEN p = gel(Z, lg(Z)-1), r;119setlg(Z, lg(Z)-1);120if (!Tp) /* first time: p is composite and not a power */121Tp = ZX_deriv(T);122else123{124(void)Z_isanypower(p, &p);125if ((flag || lgefint(p)==3) && BPSW_psp(p))126{ P = vec_append(P, p); continue; }127}128r = FpX_gcd_check(T, Tp, p);129if (r)130Z = shallowconcat(Z, Z_cba(r, diviiexact(p,r)));131else if (flag)132P = shallowconcat(P, gel(Z_factor(p),1));133else134P = vec_append(P, p);135}136ZV_sort_inplace(P); l = lg(P); E = cgetg(l, t_COL);137for (i = 1; i < l; i++) gel(E,i) = utoipos(Z_pvalrem(dT, gel(P,i), &dT));138return mkmat2(P,E);139}140141GEN142poldiscfactors(GEN T, long flag)143{144pari_sp av = avma;145GEN dT;146if (typ(T) != t_POL || !RgX_is_ZX(T)) pari_err_TYPE("poldiscfactors",T);147if (flag < 0 || flag > 1) pari_err_FLAG("poldiscfactors");148dT = ZX_disc(T);149if (!signe(dT)) retmkvec2(gen_0, Z_factor(gen_0));150return gerepilecopy(av, mkvec2(dT, poldiscfactors_i(T, dT, flag)));151}152153static void154nfmaxord_check_args(nfmaxord_t *S, GEN T, long flag)155{156GEN dT, L, E, P, fa = NULL;157pari_timer t;158long l, ty = typ(T);159160if (DEBUGLEVEL) timer_start(&t);161if (ty == t_VEC) {162if (lg(T) != 3) pari_err_TYPE("nfmaxord",T);163fa = gel(T,2); T = gel(T,1); ty = typ(T);164}165if (ty != t_POL) pari_err_TYPE("nfmaxord",T);166T = Q_primpart(T);167if (degpol(T) <= 0) pari_err_CONSTPOL("nfmaxord");168RgX_check_ZX(T, "nfmaxord");169S->T0 = T;170S->T = T = ZX_Q_normalize(T, &L);171S->unscale = L;172S->dT = dT = set_disc(S);173if (!signe(dT)) pari_err_IRREDPOL("nfmaxord",T);174if (fa)175{176const long MIN = 100; /* include at least all p < 101 */177GEN P0 = NULL, U;178if (!isint1(L)) fa = update_fact(dT, fa);179switch(typ(fa))180{181case t_MAT:182if (!is_Z_factornon0(fa)) pari_err_TYPE("nfmaxord",fa);183P0 = gel(fa,1); /* fall through */184case t_VEC: case t_COL:185if (!P0)186{187if (!RgV_is_ZV(fa)) pari_err_TYPE("nfmaxord",fa);188P0 = fa;189}190P = gel(absZ_factor_limit_strict(dT, MIN, &U), 1);191if (lg(P) != 0) { settyp(P, typ(P0)); P0 = shallowconcat(P0,P); }192P0 = ZV_sort_uniq(P0);193fa = fact_from_factors(dT, P0, 0);194break;195case t_INT:196fa = absZ_factor_limit(dT, (signe(fa) <= 0)? 1: maxuu(itou(fa), MIN));197break;198default:199pari_err_TYPE("nfmaxord",fa);200}201}202else203fa = poldiscfactors_i(T, dT, !(flag & nf_PARTIALFACT));204P = gel(fa,1); l = lg(P);205E = gel(fa,2);206if (l > 1 && is_pm1(gel(P,1)))207{208l--;209P = vecslice(P, 2, l);210E = vecslice(E, 2, l);211}212S->dTP = P;213S->dTE = vec_to_vecsmall(E);214if (DEBUGLEVEL>2) timer_printf(&t, "disc. factorisation");215}216217static int218fnz(GEN x,long j)219{220long i;221for (i=1; i<j; i++)222if (signe(gel(x,i))) return 0;223return 1;224}225/* return list u[i], 2 by 2 coprime with the same prime divisors as ab */226static GEN227get_coprimes(GEN a, GEN b)228{229long i, k = 1;230GEN u = cgetg(3, t_COL);231gel(u,1) = a;232gel(u,2) = b;233/* u1,..., uk 2 by 2 coprime */234while (k+1 < lg(u))235{236GEN d, c = gel(u,k+1);237if (is_pm1(c)) { k++; continue; }238for (i=1; i<=k; i++)239{240GEN ui = gel(u,i);241if (is_pm1(ui)) continue;242d = gcdii(c, ui);243if (d == gen_1) continue;244c = diviiexact(c, d);245gel(u,i) = diviiexact(ui, d);246u = vec_append(u, d);247}248gel(u,++k) = c;249}250for (i = k = 1; i < lg(u); i++)251if (!is_pm1(gel(u,i))) gel(u,k++) = gel(u,i);252setlg(u, k); return u;253}254255/*******************************************************************/256/* */257/* ROUND 4 */258/* */259/*******************************************************************/260typedef struct {261/* constants */262long pisprime; /* -1: unknown, 1: prime, 0: composite */263GEN p, f; /* goal: factor f p-adically */264long df;265GEN pdf; /* p^df = reduced discriminant of f */266long mf; /* */267GEN psf, pmf; /* stability precision for f, wanted precision for f */268long vpsf; /* v_p(p_f) */269/* these are updated along the way */270GEN phi; /* a p-integer, in Q[X] */271GEN phi0; /* a p-integer, in Q[X] from testb2 / testc2, to be composed with272* phi when correct precision is known */273GEN chi; /* characteristic polynomial of phi (mod psc) in Z[X] */274GEN nu; /* irreducible divisor of chi mod p, in Z[X] */275GEN invnu; /* numerator ( 1/ Mod(nu, chi) mod pmr ) */276GEN Dinvnu;/* denominator ( ... ) */277long vDinvnu; /* v_p(Dinvnu) */278GEN prc, psc; /* reduced discriminant of chi, stability precision for chi */279long vpsc; /* v_p(p_c) */280GEN ns, nsf, precns; /* cached Newton sums for nsf and their precision */281} decomp_t;282static GEN maxord_i(decomp_t *S, GEN p, GEN f, long mf, GEN w, long flag);283static GEN dbasis(GEN p, GEN f, long mf, GEN alpha, GEN U);284static GEN maxord(GEN p,GEN f,long mf);285static GEN ZX_Dedekind(GEN F, GEN *pg, GEN p);286287/* Warning: data computed for T = ZX_Q_normalize(T0). If S.unscale !=288* gen_1, caller must take steps to correct the components if it wishes289* to stick to the original T0. Return a vector of p-maximal orders, for290* those p s.t p^2 | disc(T) [ = S->dTP ]*/291static GEN292get_maxord(nfmaxord_t *S, GEN T0, long flag)293{294VOLATILE GEN P, E, O;295VOLATILE long lP, i, k;296297nfmaxord_check_args(S, T0, flag);298P = S->dTP; lP = lg(P);299E = S->dTE;300O = cgetg(1, t_VEC);301for (i=1; i<lP; i++)302{303VOLATILE pari_sp av;304/* includes the silly case where P[i] = -1 */305if (E[i] <= 1) { O = vec_append(O, gen_1); continue; }306av = avma;307pari_CATCH(CATCH_ALL) {308GEN N, u, err = pari_err_last();309long l;310switch(err_get_num(err))311{312case e_INV:313{314GEN p, x = err_get_compo(err, 2);315if (typ(x) == t_INTMOD)316{ /* caught false prime, update factorization */317p = gcdii(gel(x,1), gel(x,2));318u = diviiexact(gel(x,1),p);319if (DEBUGLEVEL) pari_warn(warner,"impossible inverse: %Ps", x);320gerepileall(av, 2, &p, &u);321322u = get_coprimes(p, u); l = lg(u);323/* no small factors, but often a prime power */324for (k = 1; k < l; k++) (void)Z_isanypower(gel(u,k), &gel(u,k));325break;326}327/* fall through */328}329case e_PRIME: case e_IRREDPOL:330{ /* we're here because we failed BPSW_isprime(), no point in331* reporting a possible counter-example to the BPSW test */332GEN p = gel(P,i);333set_avma(av);334if (DEBUGLEVEL)335pari_warn(warner,"large composite in nfmaxord:loop(), %Ps", p);336if (expi(p) < 100) /* factor should require ~20ms for this */337u = gel(Z_factor(p), 1);338else339{ /* give up, probably not maximal */340GEN B, g, k = ZX_Dedekind(S->T, &g, p);341k = FpX_normalize(k, p);342B = dbasis(p, S->T, E[i], NULL, FpX_div(S->T,k,p));343O = vec_append(O, B);344pari_CATCH_reset(); continue;345}346break;347}348default: pari_err(0, err);349return NULL;/*LCOV_EXCL_LINE*/350}351l = lg(u);352gel(P,i) = gel(u,1);353P = shallowconcat(P, vecslice(u, 2, l-1));354av = avma;355N = S->dT; E[i] = Z_pvalrem(N, gel(P,i), &N);356for (k=lP, lP=lg(P); k < lP; k++) E[k] = Z_pvalrem(N, gel(P,k), &N);357} pari_RETRY {358if (DEBUGLEVEL>2) err_printf("Treating p^k = %Ps^%ld\n",P[i],E[i]);359O = vec_append(O, maxord(gel(P,i),S->T,E[i]));360} pari_ENDCATCH;361}362S->dTP = P; return O;363}364365/* M a QM, return denominator of diagonal. All denominators are powers of366* a given integer */367static GEN368diag_denom(GEN M)369{370GEN d = gen_1;371long j, l = lg(M);372for (j=1; j<l; j++)373{374GEN t = gcoeff(M,j,j);375if (typ(t) == t_INT) continue;376t = gel(t,2);377if (abscmpii(t,d) > 0) d = t;378}379return d;380}381static void382setPE(GEN D, GEN P, GEN *pP, GEN *pE)383{384long k, j, l = lg(P);385GEN P2, E2;386*pP = P2 = cgetg(l, t_COL);387*pE = E2 = cgetg(l, t_VECSMALL);388for (k = j = 1; j < l; j++)389{390long v = Z_pvalrem(D, gel(P,j), &D);391if (v) { gel(P2,k) = gel(P,j); E2[k] = v; k++; }392}393setlg(P2, k);394setlg(E2, k);395}396void397nfmaxord(nfmaxord_t *S, GEN T0, long flag)398{399GEN O = get_maxord(S, T0, flag);400GEN f = S->T, P = S->dTP, a = NULL, da = NULL;401long n = degpol(f), lP = lg(P), i, j, k;402int centered = 0;403pari_sp av = avma;404/* r1 & basden not initialized here */405S->r1 = -1;406S->basden = NULL;407for (i=1; i<lP; i++)408{409GEN M, db, b = gel(O,i);410if (b == gen_1) continue;411db = diag_denom(b);412if (db == gen_1) continue;413414/* db = denom(b), (da,db) = 1. Compute da Im(b) + db Im(a) */415b = Q_muli_to_int(b,db);416if (!da) { da = db; a = b; }417else418{ /* optimization: easy as long as both matrix are diagonal */419j=2; while (j<=n && fnz(gel(a,j),j) && fnz(gel(b,j),j)) j++;420k = j-1; M = cgetg(2*n-k+1,t_MAT);421for (j=1; j<=k; j++)422{423gel(M,j) = gel(a,j);424gcoeff(M,j,j) = mulii(gcoeff(a,j,j),gcoeff(b,j,j));425}426/* could reduce mod M(j,j) but not worth it: usually close to da*db */427for ( ; j<=n; j++) gel(M,j) = ZC_Z_mul(gel(a,j), db);428for ( ; j<=2*n-k; j++) gel(M,j) = ZC_Z_mul(gel(b,j+k-n), da);429da = mulii(da,db);430a = ZM_hnfmodall_i(M, da, hnf_MODID|hnf_CENTER);431gerepileall(av, 2, &a, &da);432centered = 1;433}434}435if (da)436{437GEN index = diviiexact(da, gcoeff(a,1,1));438for (j=2; j<=n; j++) index = mulii(index, diviiexact(da, gcoeff(a,j,j)));439if (!centered) a = ZM_hnfcenter(a);440a = RgM_Rg_div(a, da);441S->index = index;442S->dK = diviiexact(S->dT, sqri(index));443}444else445{446S->index = gen_1;447S->dK = S->dT;448a = matid(n);449}450setPE(S->dK, P, &S->dKP, &S->dKE);451S->basis = RgM_to_RgXV(a, varn(f));452}453GEN454nfbasis(GEN x, GEN *pdK)455{456pari_sp av = avma;457nfmaxord_t S;458GEN B;459nfmaxord(&S, x, 0);460B = RgXV_unscale(S.basis, S.unscale);461if (pdK) *pdK = S.dK;462gerepileall(av, pdK? 2: 1, &B, pdK); return B;463}464/* field discriminant: faster than nfmaxord, use local data only */465static GEN466maxord_disc(nfmaxord_t *S, GEN x)467{468GEN O = get_maxord(S, x, 0), I = gen_1;469long n = degpol(S->T), lP = lg(O), i, j;470for (i = 1; i < lP; i++)471{472GEN b = gel(O,i);473if (b == gen_1) continue;474for (j = 1; j <= n; j++)475{476GEN c = gcoeff(b,j,j);477if (typ(c) == t_FRAC) I = mulii(I, gel(c,2)) ;478}479}480return diviiexact(S->dT, sqri(I));481}482GEN483nfdisc(GEN x)484{485pari_sp av = avma;486nfmaxord_t S;487return gerepileuptoint(av, maxord_disc(&S, x));488}489GEN490nfdiscfactors(GEN x)491{492pari_sp av = avma;493GEN E, P, D, nf = checknf_i(x);494if (nf)495{496D = nf_get_disc(nf);497P = nf_get_ramified_primes(nf);498}499else500{501nfmaxord_t S;502D = maxord_disc(&S, x);503P = S.dTP;504}505setPE(D, P, &P, &E); settyp(P, t_COL);506return gerepilecopy(av, mkvec2(D, mkmat2(P, zc_to_ZC(E))));507}508509static ulong510Flx_checkdeflate(GEN x)511{512ulong d = 0, i, lx = (ulong)lg(x);513for (i=3; i<lx; i++)514if (x[i]) { d = ugcd(d,i-2); if (d == 1) break; }515return d;516}517518/* product of (monic) irreducible factors of f over Fp[X]519* Assume f reduced mod p, otherwise valuation at x may be wrong */520static GEN521Flx_radical(GEN f, ulong p)522{523long v0 = Flx_valrem(f, &f);524ulong du, d, e;525GEN u;526527d = Flx_checkdeflate(f);528if (!d) return v0? polx_Flx(f[1]): pol1_Flx(f[1]);529if (u_lvalrem(d,p, &e)) f = Flx_deflate(f, d/e); /* f(x^p^i) -> f(x) */530u = Flx_gcd(f, Flx_deriv(f, p), p); /* (f,f') */531du = degpol(u);532if (du)533{534if (du == (ulong)degpol(f))535f = Flx_radical(Flx_deflate(f,p), p);536else537{538u = Flx_normalize(u, p);539f = Flx_div(f, u, p);540if (p <= du)541{542GEN w = (degpol(f) >= degpol(u))? Flx_rem(f, u, p): f;543w = Flxq_powu(w, du, u, p);544w = Flx_div(u, Flx_gcd(w,u,p), p); /* u / gcd(u, v^(deg u-1)) */545f = Flx_mul(f, Flx_radical(Flx_deflate(w,p), p), p);546}547}548}549if (v0) f = Flx_shift(f, 1);550return f;551}552/* Assume f reduced mod p, otherwise valuation at x may be wrong */553static GEN554FpX_radical(GEN f, GEN p)555{556GEN u;557long v0;558if (lgefint(p) == 3)559{560ulong q = p[2];561return Flx_to_ZX( Flx_radical(ZX_to_Flx(f, q), q) );562}563v0 = ZX_valrem(f, &f);564u = FpX_gcd(f,FpX_deriv(f, p), p);565if (degpol(u)) f = FpX_div(f, u, p);566if (v0) f = RgX_shift(f, 1);567return f;568}569/* f / a */570static GEN571zx_z_div(GEN f, ulong a)572{573long i, l = lg(f);574GEN g = cgetg(l, t_VECSMALL);575g[1] = f[1];576for (i = 2; i < l; i++) g[i] = f[i] / a;577return g;578}579/* Dedekind criterion; return k = gcd(g,h, (f-gh)/p), where580* f = \prod f_i^e_i, g = \prod f_i, h = \prod f_i^{e_i-1}581* k = 1 iff Z[X]/(f) is p-maximal */582static GEN583ZX_Dedekind(GEN F, GEN *pg, GEN p)584{585GEN k, h, g, f, f2;586ulong q = p[2];587if (lgefint(p) == 3 && q < (1UL << BITS_IN_HALFULONG))588{589ulong q2 = q*q;590f2 = ZX_to_Flx(F, q2);591f = Flx_red(f2, q);592g = Flx_radical(f, q);593h = Flx_div(f, g, q);594k = zx_z_div(Flx_sub(f2, Flx_mul(g,h,q2), q2), q);595k = Flx_gcd(k, Flx_gcd(g,h,q), q);596k = Flx_to_ZX(k);597g = Flx_to_ZX(g);598}599else600{601f2 = FpX_red(F, sqri(p));602f = FpX_red(f2, p);603g = FpX_radical(f, p);604h = FpX_div(f, g, p);605k = ZX_Z_divexact(ZX_sub(f2, ZX_mul(g,h)), p);606k = FpX_gcd(FpX_red(k, p), FpX_gcd(g,h,p), p);607}608*pg = g; return k;609}610611/* p-maximal order of Z[x]/f; mf = v_p(Disc(f)) or < 0 [unknown].612* Return gen_1 if p-maximal */613static GEN614maxord(GEN p, GEN f, long mf)615{616const pari_sp av = avma;617GEN res, g, k = ZX_Dedekind(f, &g, p);618long dk = degpol(k);619if (DEBUGLEVEL>2) err_printf(" ZX_Dedekind: gcd has degree %ld\n", dk);620if (!dk) { set_avma(av); return gen_1; }621if (mf < 0) mf = ZpX_disc_val(f, p);622k = FpX_normalize(k, p);623if (2*dk >= mf-1)624res = dbasis(p, f, mf, NULL, FpX_div(f,k,p));625else626{627GEN w, F1, F2;628decomp_t S;629F1 = FpX_factor(k,p);630F2 = FpX_factor(FpX_div(g,k,p),p);631w = merge_sort_uniq(gel(F1,1),gel(F2,1),(void*)cmpii,&gen_cmp_RgX);632res = maxord_i(&S, p, f, mf, w, 0);633}634return gerepilecopy(av,res);635}636/* T monic separable ZX, p prime */637GEN638ZpX_primedec(GEN T, GEN p)639{640const pari_sp av = avma;641GEN w, F1, F2, res, g, k = ZX_Dedekind(T, &g, p);642decomp_t S;643if (!degpol(k)) return zm_to_ZM(FpX_degfact(T, p));644k = FpX_normalize(k, p);645F1 = FpX_factor(k,p);646F2 = FpX_factor(FpX_div(g,k,p),p);647w = merge_sort_uniq(gel(F1,1),gel(F2,1),(void*)cmpii,&gen_cmp_RgX);648res = maxord_i(&S, p, T, ZpX_disc_val(T, p), w, -1);649if (!res)650{651long f = degpol(S.nu), e = degpol(T) / f;652set_avma(av); retmkmat2(mkcols(f), mkcols(e));653}654return gerepilecopy(av,res);655}656657static GEN658Zlx_sylvester_echelon(GEN f1, GEN f2, long early_abort, ulong p, ulong pm)659{660long j, n = degpol(f1);661GEN h, a = cgetg(n+1,t_MAT);662f1 = Flx_get_red(f1, pm);663h = Flx_rem(f2,f1,pm);664for (j=1;; j++)665{666gel(a,j) = Flx_to_Flv(h, n);667if (j == n) break;668h = Flx_rem(Flx_shift(h, 1), f1, pm);669}670return zlm_echelon(a, early_abort, p, pm);671}672/* Sylvester's matrix, mod p^m (assumes f1 monic). If early_abort673* is set, return NULL if one pivot is 0 mod p^m */674static GEN675ZpX_sylvester_echelon(GEN f1, GEN f2, long early_abort, GEN p, GEN pm)676{677long j, n = degpol(f1);678GEN h, a = cgetg(n+1,t_MAT);679h = FpXQ_red(f2,f1,pm);680for (j=1;; j++)681{682gel(a,j) = RgX_to_RgC(h, n);683if (j == n) break;684h = FpX_rem(RgX_shift_shallow(h, 1), f1, pm);685}686return ZpM_echelon(a, early_abort, p, pm);687}688689/* polynomial gcd mod p^m (assumes f1 monic). Return a QpX ! */690static GEN691Zlx_gcd(GEN f1, GEN f2, ulong p, ulong pm)692{693pari_sp av = avma;694GEN a = Zlx_sylvester_echelon(f1,f2,0,p,pm);695long c, l = lg(a), sv = f1[1];696for (c = 1; c < l; c++)697{698ulong t = ucoeff(a,c,c);699if (t)700{701a = Flx_to_ZX(Flv_to_Flx(gel(a,c), sv));702if (t == 1) return gerepilecopy(av, a);703return gerepileupto(av, RgX_Rg_div(a, utoipos(t)));704}705}706set_avma(av);707a = cgetg(2,t_POL); a[1] = sv; return a;708}709GEN710ZpX_gcd(GEN f1, GEN f2, GEN p, GEN pm)711{712pari_sp av = avma;713GEN a;714long c, l, v;715if (lgefint(pm) == 3)716{717ulong q = pm[2];718return Zlx_gcd(ZX_to_Flx(f1, q), ZX_to_Flx(f2,q), p[2], q);719}720a = ZpX_sylvester_echelon(f1,f2,0,p,pm);721l = lg(a); v = varn(f1);722for (c = 1; c < l; c++)723{724GEN t = gcoeff(a,c,c);725if (signe(t))726{727a = RgV_to_RgX(gel(a,c), v);728if (equali1(t)) return gerepilecopy(av, a);729return gerepileupto(av, RgX_Rg_div(a, t));730}731}732set_avma(av); return pol_0(v);733}734735/* Return m > 0, such that p^m ~ 2^16 for initial value of m; p > 1 */736static long737init_m(GEN p)738{739if (lgefint(p) > 3) return 1;740return (long)(16 / log2(p[2]));741}742743/* reduced resultant mod p^m (assumes x monic) */744GEN745ZpX_reduced_resultant(GEN x, GEN y, GEN p, GEN pm)746{747pari_sp av = avma;748GEN z;749if (lgefint(pm) == 3)750{751ulong q = pm[2];752z = Zlx_sylvester_echelon(ZX_to_Flx(x,q), ZX_to_Flx(y,q),0,p[2],q);753if (lg(z) > 1)754{755ulong c = ucoeff(z,1,1);756if (c) { set_avma(av); return utoipos(c); }757}758}759else760{761z = ZpX_sylvester_echelon(x,y,0,p,pm);762if (lg(z) > 1)763{764GEN c = gcoeff(z,1,1);765if (signe(c)) return gerepileuptoint(av, c);766}767}768set_avma(av); return gen_0;769}770/* Assume Res(f,g) divides p^M. Return Res(f, g), using dynamic p-adic771* precision (until result is nonzero or p^M). */772GEN773ZpX_reduced_resultant_fast(GEN f, GEN g, GEN p, long M)774{775GEN R, q = NULL;776long m;777m = init_m(p); if (m < 1) m = 1;778for(;; m <<= 1) {779if (M < 2*m) break;780q = q? sqri(q): powiu(p, m); /* p^m */781R = ZpX_reduced_resultant(f,g, p, q); if (signe(R)) return R;782}783q = powiu(p, M);784R = ZpX_reduced_resultant(f,g, p, q); return signe(R)? R: q;785}786787/* v_p(Res(x,y) mod p^m), assumes (lc(x),p) = 1 */788static long789ZpX_resultant_val_i(GEN x, GEN y, GEN p, GEN pm)790{791pari_sp av = avma;792GEN z;793long i, l, v;794if (lgefint(pm) == 3)795{796ulong q = pm[2], pp = p[2];797z = Zlx_sylvester_echelon(ZX_to_Flx(x,q), ZX_to_Flx(y,q), 1, pp, q);798if (!z) return gc_long(av,-1); /* failure */799v = 0; l = lg(z);800for (i = 1; i < l; i++) v += u_lval(ucoeff(z,i,i), pp);801}802else803{804z = ZpX_sylvester_echelon(x, y, 1, p, pm);805if (!z) return gc_long(av,-1); /* failure */806v = 0; l = lg(z);807for (i = 1; i < l; i++) v += Z_pval(gcoeff(z,i,i), p);808}809return v;810}811812/* assume (lc(f),p) = 1; no assumption on g */813long814ZpX_resultant_val(GEN f, GEN g, GEN p, long M)815{816pari_sp av = avma;817GEN q = NULL;818long v, m;819m = init_m(p); if (m < 2) m = 2;820for(;; m <<= 1) {821if (m > M) m = M;822q = q? sqri(q): powiu(p, m); /* p^m */823v = ZpX_resultant_val_i(f,g, p, q); if (v >= 0) return gc_long(av,v);824if (m == M) return gc_long(av,M);825}826}827828/* assume f separable and (lc(f),p) = 1 */829long830ZpX_disc_val(GEN f, GEN p)831{832pari_sp av = avma;833long v;834if (degpol(f) == 1) return 0;835v = ZpX_resultant_val(f, ZX_deriv(f), p, LONG_MAX);836return gc_long(av,v);837}838839/* *e a ZX, *d, *z in Z, *d = p^(*vd). Simplify e / d by cancelling a840* common factor p^v; if z!=NULL, update it by cancelling the same power of p */841static void842update_den(GEN p, GEN *e, GEN *d, long *vd, GEN *z)843{844GEN newe;845long ve = ZX_pvalrem(*e, p, &newe);846if (ve) {847GEN newd;848long v = minss(*vd, ve);849if (v) {850if (v == *vd)851{ /* rare, denominator cancelled */852if (ve != v) newe = ZX_Z_mul(newe, powiu(p, ve - v));853newd = gen_1;854*vd = 0;855if (z) *z =diviiexact(*z, powiu(p, v));856}857else858{ /* v = ve < vd, generic case */859GEN q = powiu(p, v);860newd = diviiexact(*d, q);861*vd -= v;862if (z) *z = diviiexact(*z, q);863}864*e = newe;865*d = newd;866}867}868}869870/* return denominator, a power of p */871static GEN872QpX_denom(GEN x)873{874long i, l = lg(x);875GEN maxd = gen_1;876for (i=2; i<l; i++)877{878GEN d = gel(x,i);879if (typ(d) == t_FRAC && cmpii(gel(d,2), maxd) > 0) maxd = gel(d,2);880}881return maxd;882}883static GEN884QpXV_denom(GEN x)885{886long l = lg(x), i;887GEN maxd = gen_1;888for (i = 1; i < l; i++)889{890GEN d = QpX_denom(gel(x,i));891if (cmpii(d, maxd) > 0) maxd = d;892}893return maxd;894}895896static GEN897QpX_remove_denom(GEN x, GEN p, GEN *pdx, long *pv)898{899*pdx = QpX_denom(x);900if (*pdx == gen_1) { *pv = 0; *pdx = NULL; }901else {902x = Q_muli_to_int(x,*pdx);903*pv = Z_pval(*pdx, p);904}905return x;906}907908/* p^v * f o g mod (T,q). q = p^vq */909static GEN910compmod(GEN p, GEN f, GEN g, GEN T, GEN q, long v)911{912GEN D = NULL, z, df, dg, qD;913long vD = 0, vdf, vdg;914915f = QpX_remove_denom(f, p, &df, &vdf);916if (typ(g) == t_VEC) /* [num,den,v_p(den)] */917{ vdg = itos(gel(g,3)); dg = gel(g,2); g = gel(g,1); }918else919g = QpX_remove_denom(g, p, &dg, &vdg);920if (df) { D = df; vD = vdf; }921if (dg) {922long degf = degpol(f);923D = mul_content(D, powiu(dg, degf));924vD += degf * vdg;925}926qD = D ? mulii(q, D): q;927if (dg) f = FpX_rescale(f, dg, qD);928z = FpX_FpXQ_eval(f, g, T, qD);929if (!D) {930if (v) {931if (v > 0)932z = ZX_Z_mul(z, powiu(p, v));933else934z = RgX_Rg_div(z, powiu(p, -v));935}936return z;937}938update_den(p, &z, &D, &vD, NULL);939qD = mulii(D,q);940if (v) vD -= v;941z = FpX_center_i(z, qD, shifti(qD,-1));942if (vD > 0)943z = RgX_Rg_div(z, powiu(p, vD));944else if (vD < 0)945z = ZX_Z_mul(z, powiu(p, -vD));946return z;947}948949/* fast implementation of ZM_hnfmodid(M, D) / D, D = p^k */950static GEN951ZpM_hnfmodid(GEN M, GEN p, GEN D)952{953long i, l = lg(M);954M = RgM_Rg_div(ZpM_echelon(M,0,p,D), D);955for (i = 1; i < l; i++)956if (gequal0(gcoeff(M,i,i))) gcoeff(M,i,i) = gen_1;957return M;958}959960/* Return Z-basis for Z[a] + U(a)/p Z[a] in Z[t]/(f), mf = v_p(disc f), U961* a ZX. Special cases: a = t is coded as NULL, U = 0 is coded as NULL */962static GEN963dbasis(GEN p, GEN f, long mf, GEN a, GEN U)964{965long n = degpol(f), i, dU;966GEN b, h;967968if (n == 1) return matid(1);969if (a && gequalX(a)) a = NULL;970if (DEBUGLEVEL>5)971{972err_printf(" entering Dedekind Basis with parameters p=%Ps\n",p);973err_printf(" f = %Ps,\n a = %Ps\n",f, a? a: pol_x(varn(f)));974}975if (a)976{977GEN pd = powiu(p, mf >> 1);978GEN da, pdp = mulii(pd,p), D = pdp;979long vda;980dU = U ? degpol(U): 0;981b = cgetg(n+1, t_MAT);982h = scalarpol(pd, varn(f));983a = QpX_remove_denom(a, p, &da, &vda);984if (da) D = mulii(D, da);985gel(b,1) = scalarcol_shallow(pd, n);986for (i=2; i<=n; i++)987{988if (i == dU+1)989h = compmod(p, U, mkvec3(a,da,stoi(vda)), f, pdp, (mf>>1) - 1);990else991{992h = FpXQ_mul(h, a, f, D);993if (da) h = ZX_Z_divexact(h, da);994}995gel(b,i) = RgX_to_RgC(h,n);996}997return ZpM_hnfmodid(b, p, pd);998}999else1000{1001if (!U) return matid(n);1002dU = degpol(U);1003if (dU == n) return matid(n);1004U = FpX_normalize(U, p);1005b = cgetg(n+1, t_MAT);1006for (i = 1; i <= dU; i++) gel(b,i) = vec_ei(n, i);1007h = RgX_Rg_div(U, p);1008for ( ; i <= n; i++)1009{1010gel(b, i) = RgX_to_RgC(h,n);1011if (i == n) break;1012h = RgX_shift_shallow(h,1);1013}1014return b;1015}1016}10171018static GEN1019get_partial_order_as_pols(GEN p, GEN f)1020{1021GEN O = maxord(p, f, -1);1022long v = varn(f);1023return O == gen_1? pol_x_powers(degpol(f), v): RgM_to_RgXV(O, v);1024}10251026static long1027p_is_prime(decomp_t *S)1028{1029if (S->pisprime < 0) S->pisprime = BPSW_psp(S->p);1030return S->pisprime;1031}1032static GEN ZpX_monic_factor_squarefree(GEN f, GEN p, long prec);10331034/* if flag = 0, maximal order, else factorization to precision r = flag */1035static GEN1036Decomp(decomp_t *S, long flag)1037{1038pari_sp av = avma;1039GEN fred, pr2, pr, pk, ph2, ph, b1, b2, a, e, de, f1, f2, dt, th, chip;1040GEN p = S->p;1041long vde, vdt, k, r = maxss(flag, 2*S->df + 1);10421043if (DEBUGLEVEL>5) err_printf(" entering Decomp: %Ps^%ld\n f = %Ps\n",1044p, r, S->f);1045else if (DEBUGLEVEL>2) err_printf(" entering Decomp\n");1046chip = FpX_red(S->chi, p);1047if (!FpX_valrem(chip, S->nu, p, &b1))1048{1049if (!p_is_prime(S)) pari_err_PRIME("Decomp",p);1050pari_err_BUG("Decomp (not a factor)");1051}1052b2 = FpX_div(chip, b1, p);1053a = FpX_mul(FpXQ_inv(b2, b1, p), b2, p);1054/* E = e / de, e in Z[X], de in Z, E = a(phi) mod (f, p) */1055th = QpX_remove_denom(S->phi, p, &dt, &vdt);1056if (dt)1057{1058long dega = degpol(a);1059vde = dega * vdt;1060de = powiu(dt, dega);1061pr = mulii(p, de);1062a = FpX_rescale(a, dt, pr);1063}1064else1065{1066vde = 0;1067de = gen_1;1068pr = p;1069}1070e = FpX_FpXQ_eval(a, th, S->f, pr);1071update_den(p, &e, &de, &vde, NULL);10721073pk = p; k = 1;1074/* E, (1 - E) tend to orthogonal idempotents in Zp[X]/(f) */1075while (k < r + vde)1076{ /* E <-- E^2(3-2E) mod p^2k, with E = e/de */1077GEN D;1078pk = sqri(pk); k <<= 1;1079e = ZX_mul(ZX_sqr(e), Z_ZX_sub(mului(3,de), gmul2n(e,1)));1080de= mulii(de, sqri(de));1081vde *= 3;1082D = mulii(pk, de);1083e = FpX_rem(e, centermod(S->f, D), D); /* e/de defined mod pk */1084update_den(p, &e, &de, &vde, NULL);1085}1086/* required precision of the factors */1087pr = powiu(p, r); pr2 = shifti(pr, -1);1088ph = mulii(de,pr);ph2 = shifti(ph, -1);1089e = FpX_center_i(FpX_red(e, ph), ph, ph2);1090fred = FpX_red(S->f, ph);10911092f1 = ZpX_gcd(fred, Z_ZX_sub(de, e), p, ph); /* p-adic gcd(f, 1-e) */1093if (!is_pm1(de))1094{1095fred = FpX_red(fred, pr);1096f1 = FpX_red(f1, pr);1097}1098f2 = FpX_div(fred,f1, pr);1099f1 = FpX_center_i(f1, pr, pr2);1100f2 = FpX_center_i(f2, pr, pr2);11011102if (DEBUGLEVEL>5)1103err_printf(" leaving Decomp: f1 = %Ps\nf2 = %Ps\ne = %Ps\nde= %Ps\n", f1,f2,e,de);11041105if (flag < 0)1106{1107GEN m = vconcat(ZpX_primedec(f1, p), ZpX_primedec(f2, p));1108return sort_factor(m, (void*)&cmpii, &cmp_nodata);1109}1110else if (flag)1111{1112gerepileall(av, 2, &f1, &f2);1113return shallowconcat(ZpX_monic_factor_squarefree(f1, p, flag),1114ZpX_monic_factor_squarefree(f2, p, flag));1115} else {1116GEN D, d1, d2, B1, B2, M;1117long n, n1, n2, i;1118gerepileall(av, 4, &f1, &f2, &e, &de);1119D = de;1120B1 = get_partial_order_as_pols(p,f1); n1 = lg(B1)-1;1121B2 = get_partial_order_as_pols(p,f2); n2 = lg(B2)-1; n = n1+n2;1122d1 = QpXV_denom(B1);1123d2 = QpXV_denom(B2); if (cmpii(d1, d2) < 0) d1 = d2;1124if (d1 != gen_1) {1125B1 = Q_muli_to_int(B1, d1);1126B2 = Q_muli_to_int(B2, d1);1127D = mulii(d1, D);1128}1129fred = centermod_i(S->f, D, shifti(D,-1));1130M = cgetg(n+1, t_MAT);1131for (i=1; i<=n1; i++)1132gel(M,i) = RgX_to_RgC(FpX_rem(FpX_mul(gel(B1,i),e,D), fred, D), n);1133e = Z_ZX_sub(de, e); B2 -= n1;1134for ( ; i<=n; i++)1135gel(M,i) = RgX_to_RgC(FpX_rem(FpX_mul(gel(B2,i),e,D), fred, D), n);1136return ZpM_hnfmodid(M, p, D);1137}1138}11391140/* minimum extension valuation: L/E */1141static void1142vstar(GEN p,GEN h, long *L, long *E)1143{1144long first, j, k, v, w, m = degpol(h);11451146first = 1; k = 1; v = 0;1147for (j=1; j<=m; j++)1148{1149GEN c = gel(h, m-j+2);1150if (signe(c))1151{1152w = Z_pval(c,p);1153if (first || w*k < v*j) { v = w; k = j; }1154first = 0;1155}1156}1157/* v/k = min_j ( v_p(h_{m-j}) / j ) */1158w = (long)ugcd(v,k);1159*L = v/w;1160*E = k/w;1161}11621163static GEN1164redelt_i(GEN a, GEN N, GEN p, GEN *pda, long *pvda)1165{1166GEN z;1167a = Q_remove_denom(a, pda);1168*pvda = 0;1169if (*pda)1170{1171long v = Z_pvalrem(*pda, p, &z);1172if (v) {1173*pda = powiu(p, v);1174*pvda = v;1175N = mulii(*pda, N);1176}1177else1178*pda = NULL;1179if (!is_pm1(z)) a = ZX_Z_mul(a, Fp_inv(z, N));1180}1181return centermod(a, N);1182}1183/* reduce the element a modulo N [ a power of p ], taking first care of the1184* denominators */1185static GEN1186redelt(GEN a, GEN N, GEN p)1187{1188GEN da;1189long vda;1190a = redelt_i(a, N, p, &da, &vda);1191if (da) a = RgX_Rg_div(a, da);1192return a;1193}11941195/* compute the c first Newton sums modulo pp of the1196characteristic polynomial of a/d mod chi, d > 0 power of p (NULL = gen_1),1197a, chi in Zp[X], vda = v_p(da)1198ns = Newton sums of chi */1199static GEN1200newtonsums(GEN p, GEN a, GEN da, long vda, GEN chi, long c, GEN pp, GEN ns)1201{1202GEN va, pa, dpa, s;1203long j, k, vdpa, lns = lg(ns);1204pari_sp av;12051206a = centermod(a, pp); av = avma;1207dpa = pa = NULL; /* -Wall */1208vdpa = 0;1209va = zerovec(c);1210for (j = 1; j <= c; j++)1211{ /* pa/dpa = (a/d)^(j-1) mod (chi, pp), dpa = p^vdpa */1212long l;1213pa = j == 1? a: FpXQ_mul(pa, a, chi, pp);1214l = lg(pa); if (l == 2) break;1215if (lns < l) l = lns;12161217if (da) {1218dpa = j == 1? da: mulii(dpa, da);1219vdpa += vda;1220update_den(p, &pa, &dpa, &vdpa, &pp);1221}1222s = mulii(gel(pa,2), gel(ns,2)); /* k = 2 */1223for (k = 3; k < l; k++) s = addii(s, mulii(gel(pa,k), gel(ns,k)));1224if (da) {1225GEN r;1226s = dvmdii(s, dpa, &r);1227if (r != gen_0) return NULL;1228}1229gel(va,j) = centermodii(s, pp, shifti(pp,-1));12301231if (gc_needed(av, 1))1232{1233if(DEBUGMEM>1) pari_warn(warnmem, "newtonsums");1234gerepileall(av, dpa?4:3, &pa, &va, &pp, &dpa);1235}1236}1237for (; j <= c; j++) gel(va,j) = gen_0;1238return va;1239}12401241/* compute the characteristic polynomial of a/da mod chi (a in Z[X]), given1242* by its Newton sums to a precision of pp using Newton sums */1243static GEN1244newtoncharpoly(GEN pp, GEN p, GEN NS)1245{1246long n = lg(NS)-1, j, k;1247GEN c = cgetg(n + 2, t_VEC), pp2 = shifti(pp,-1);12481249gel(c,1) = (n & 1 ? gen_m1: gen_1);1250for (k = 2; k <= n+1; k++)1251{1252pari_sp av2 = avma;1253GEN s = gen_0;1254ulong z;1255long v = u_pvalrem(k - 1, p, &z);1256for (j = 1; j < k; j++)1257{1258GEN t = mulii(gel(NS,j), gel(c,k-j));1259if (!odd(j)) t = negi(t);1260s = addii(s, t);1261}1262if (v) {1263s = gdiv(s, powiu(p, v));1264if (typ(s) != t_INT) return NULL;1265}1266s = mulii(s, Fp_inv(utoipos(z), pp));1267gel(c,k) = gerepileuptoint(av2, Fp_center_i(s, pp, pp2));1268}1269for (k = odd(n)? 1: 2; k <= n+1; k += 2) gel(c,k) = negi(gel(c,k));1270return gtopoly(c, 0);1271}12721273static void1274manage_cache(decomp_t *S, GEN f, GEN pp)1275{1276GEN t = S->precns;12771278if (!t) t = mulii(S->pmf, powiu(S->p, S->df));1279if (cmpii(t, pp) < 0) t = pp;12801281if (!S->precns || !RgX_equal(f, S->nsf) || cmpii(S->precns, t) < 0)1282{1283if (DEBUGLEVEL>4)1284err_printf(" Precision for cached Newton sums for %Ps: %Ps -> %Ps\n",1285f, S->precns? S->precns: gen_0, t);1286S->nsf = f;1287S->ns = FpX_Newton(f, degpol(f), t);1288S->precns = t;1289}1290}12911292/* return NULL if a mod f is not an integer1293* The denominator of any integer in Zp[X]/(f) divides pdr */1294static GEN1295mycaract(decomp_t *S, GEN f, GEN a, GEN pp, GEN pdr)1296{1297pari_sp av;1298GEN d, chi, prec1, prec2, prec3, ns;1299long vd, n = degpol(f);13001301if (gequal0(a)) return pol_0(varn(f));13021303a = QpX_remove_denom(a, S->p, &d, &vd);1304prec1 = pp;1305if (lgefint(S->p) == 3)1306prec1 = mulii(prec1, powiu(S->p, factorial_lval(n, itou(S->p))));1307if (d)1308{1309GEN p1 = powiu(d, n);1310prec2 = mulii(prec1, p1);1311prec3 = mulii(prec1, gmin_shallow(mulii(p1, d), pdr));1312}1313else1314prec2 = prec3 = prec1;1315manage_cache(S, f, prec3);13161317av = avma;1318ns = newtonsums(S->p, a, d, vd, f, n, prec2, S->ns);1319if (!ns) return NULL;1320chi = newtoncharpoly(prec1, S->p, ns);1321if (!chi) return NULL;1322setvarn(chi, varn(f));1323return gerepileupto(av, centermod(chi, pp));1324}13251326static GEN1327get_nu(GEN chi, GEN p, long *ptl)1328{ /* split off powers of x first for efficiency */1329long v = ZX_valrem(FpX_red(chi,p), &chi), n;1330GEN P;1331if (!degpol(chi)) { *ptl = 1; return pol_x(varn(chi)); }1332P = gel(FpX_factor(chi,p), 1); n = lg(P)-1;1333*ptl = v? n+1: n; return gel(P,n);1334}13351336/* Factor characteristic polynomial chi of phi mod p. If it splits, update1337* S->{phi, chi, nu} and return 1. In any case, set *nu to an irreducible1338* factor mod p of chi */1339static int1340split_char(decomp_t *S, GEN chi, GEN phi, GEN phi0, GEN *nu)1341{1342long l;1343*nu = get_nu(chi, S->p, &l);1344if (l == 1) return 0; /* single irreducible factor: doesn't split */1345/* phi o phi0 mod (p, f) */1346S->phi = compmod(S->p, phi, phi0, S->f, S->p, 0);1347S->chi = chi;1348S->nu = *nu; return 1;1349}13501351/* Return the prime element in Zp[phi], a t_INT (iff *Ep = 1) or QX;1352* nup, chip are ZX. phi = NULL codes X1353* If *Ep < oE or Ep divides Ediv (!=0) return NULL (uninteresting) */1354static GEN1355getprime(decomp_t *S, GEN phi, GEN chip, GEN nup, long *Lp, long *Ep,1356long oE, long Ediv)1357{1358GEN z, chin, q, qp;1359long r, s;13601361if (phi && dvdii(constant_coeff(chip), S->psc))1362{1363chip = mycaract(S, S->chi, phi, S->pmf, S->prc);1364if (dvdii(constant_coeff(chip), S->pmf))1365chip = ZXQ_charpoly(phi, S->chi, varn(chip));1366}1367if (degpol(nup) == 1)1368{1369GEN c = gel(nup,2); /* nup = X + c */1370chin = signe(c)? RgX_translate(chip, negi(c)): chip;1371}1372else1373chin = ZXQ_charpoly(nup, chip, varn(chip));13741375vstar(S->p, chin, Lp, Ep);1376if (*Ep < oE || (Ediv && Ediv % *Ep == 0)) return NULL;13771378if (*Ep == 1) return S->p;1379(void)cbezout(*Lp, -*Ep, &r, &s); /* = 1 */1380if (r <= 0)1381{1382long t = 1 + ((-r) / *Ep);1383r += t * *Ep;1384s += t * *Lp;1385}1386/* r > 0 minimal such that r L/E - s = 1/E1387* pi = nu^r / p^s is an element of valuation 1/E,1388* so is pi + O(p) since 1/E < 1. May compute nu^r mod p^(s+1) */1389q = powiu(S->p, s); qp = mulii(q, S->p);1390nup = FpXQ_powu(nup, r, S->chi, qp);1391if (!phi) return RgX_Rg_div(nup, q); /* phi = X : no composition */1392z = compmod(S->p, nup, phi, S->chi, qp, -s);1393return signe(z)? z: NULL;1394}13951396static int1397update_phi(decomp_t *S)1398{1399GEN PHI = NULL, prc, psc, X = pol_x(varn(S->f));1400long k;1401for (k = 1;; k++)1402{1403prc = ZpX_reduced_resultant_fast(S->chi, ZX_deriv(S->chi), S->p, S->vpsc);1404if (!equalii(prc, S->psc)) break;14051406/* increase precision */1407S->vpsc = maxss(S->vpsf, S->vpsc + 1);1408S->psc = (S->vpsc == S->vpsf)? S->psf: mulii(S->psc, S->p);14091410PHI = S->phi;1411if (S->phi0) PHI = compmod(S->p, PHI, S->phi0, S->f, S->psc, 0);1412PHI = gadd(PHI, ZX_Z_mul(X, mului(k, S->p)));1413S->chi = mycaract(S, S->f, PHI, S->psc, S->pdf);1414}1415psc = mulii(sqri(prc), S->p);14161417if (!PHI) /* ok above for k = 1 */1418{1419PHI = S->phi;1420if (S->phi0) PHI = compmod(S->p, PHI, S->phi0, S->f, psc, 0);1421if (S->phi0 || cmpii(psc,S->psc) > 0)1422S->chi = mycaract(S, S->f, PHI, psc, S->pdf);1423}1424S->phi = PHI;1425S->chi = FpX_red(S->chi, psc);14261427/* may happen if p is unramified */1428if (is_pm1(prc)) return 0;1429S->psc = psc;1430S->vpsc = 2*Z_pval(prc, S->p) + 1;1431S->prc = mulii(prc, S->p); return 1;1432}14331434/* return 1 if at least 2 factors mod p ==> chi splits1435* Replace S->phi such that F increases (to D) */1436static int1437testb2(decomp_t *S, long D, GEN theta)1438{1439long v = varn(S->chi), dlim = degpol(S->chi)-1;1440GEN T0 = S->phi, chi, phi, nu;1441if (DEBUGLEVEL>4) err_printf(" Increasing Fa\n");1442for (;;)1443{1444phi = gadd(theta, random_FpX(dlim, v, S->p));1445chi = mycaract(S, S->chi, phi, S->psf, S->prc);1446/* phi nonprimary ? */1447if (split_char(S, chi, phi, T0, &nu)) return 1;1448if (degpol(nu) == D) break;1449}1450/* F_phi=lcm(F_alpha, F_theta)=D and E_phi=E_alpha */1451S->phi0 = T0;1452S->chi = chi;1453S->phi = phi;1454S->nu = nu; return 0;1455}14561457/* return 1 if at least 2 factors mod p ==> chi can be split.1458* compute a new S->phi such that E = lcm(Ea, Et);1459* A a ZX, T a t_INT (iff Et = 1, probably impossible ?) or QX */1460static int1461testc2(decomp_t *S, GEN A, long Ea, GEN T, long Et)1462{1463GEN c, chi, phi, nu, T0 = S->phi;14641465if (DEBUGLEVEL>4) err_printf(" Increasing Ea\n");1466if (Et == 1) /* same as other branch, split for efficiency */1467c = A; /* Et = 1 => s = 1, r = 0, t = 0 */1468else1469{1470long r, s, t;1471(void)cbezout(Ea, Et, &r, &s); t = 0;1472while (r < 0) { r = r + Et; t++; }1473while (s < 0) { s = s + Ea; t++; }14741475/* A^s T^r / p^t */1476c = RgXQ_mul(RgXQ_powu(A, s, S->chi), RgXQ_powu(T, r, S->chi), S->chi);1477c = RgX_Rg_div(c, powiu(S->p, t));1478c = redelt(c, S->psc, S->p);1479}1480phi = RgX_add(c, pol_x(varn(S->chi)));1481chi = mycaract(S, S->chi, phi, S->psf, S->prc);1482if (split_char(S, chi, phi, T0, &nu)) return 1;1483/* E_phi = lcm(E_alpha,E_theta) */1484S->phi0 = T0;1485S->chi = chi;1486S->phi = phi;1487S->nu = nu; return 0;1488}14891490/* Return h^(-degpol(P)) P(x * h) if result is integral, NULL otherwise */1491static GEN1492ZX_rescale_inv(GEN P, GEN h)1493{1494long i, l = lg(P);1495GEN Q = cgetg(l,t_POL), hi = h;1496gel(Q,l-1) = gel(P,l-1);1497for (i=l-2; i>=2; i--)1498{1499GEN r;1500gel(Q,i) = dvmdii(gel(P,i), hi, &r);1501if (signe(r)) return NULL;1502if (i == 2) break;1503hi = mulii(hi,h);1504}1505Q[1] = P[1]; return Q;1506}15071508/* x p^-eq nu^-er mod p */1509static GEN1510get_gamma(decomp_t *S, GEN x, long eq, long er)1511{1512GEN q, g = x, Dg = powiu(S->p, eq);1513long vDg = eq;1514if (er)1515{1516if (!S->invnu)1517{1518while (gdvd(S->chi, S->nu)) S->nu = RgX_Rg_add(S->nu, S->p);1519S->invnu = QXQ_inv(S->nu, S->chi);1520S->invnu = redelt_i(S->invnu, S->psc, S->p, &S->Dinvnu, &S->vDinvnu);1521}1522if (S->Dinvnu) {1523Dg = mulii(Dg, powiu(S->Dinvnu, er));1524vDg += er * S->vDinvnu;1525}1526q = mulii(S->p, Dg);1527g = ZX_mul(g, FpXQ_powu(S->invnu, er, S->chi, q));1528g = FpX_rem(g, S->chi, q);1529update_den(S->p, &g, &Dg, &vDg, NULL);1530g = centermod(g, mulii(S->p, Dg));1531}1532if (!is_pm1(Dg)) g = RgX_Rg_div(g, Dg);1533return g;1534}1535static GEN1536get_g(decomp_t *S, long Ea, long L, long E, GEN beta, GEN *pchig,1537long *peq, long *per)1538{1539long eq, er;1540GEN g, chig, chib = NULL;1541for(;;) /* at most twice */1542{1543if (L < 0)1544{1545chib = ZXQ_charpoly(beta, S->chi, varn(S->chi));1546vstar(S->p, chib, &L, &E);1547}1548eq = L / E; er = L*Ea / E - eq*Ea;1549/* floor(L Ea/E) = eq Ea + er */1550if (er || !chib)1551{ /* g might not be an integer ==> chig = NULL */1552g = get_gamma(S, beta, eq, er);1553chig = mycaract(S, S->chi, g, S->psc, S->prc);1554}1555else1556{ /* g = beta/p^eq, special case of the above */1557GEN h = powiu(S->p, eq);1558g = RgX_Rg_div(beta, h);1559chig = ZX_rescale_inv(chib, h); /* chib(x h) / h^N */1560if (chig) chig = FpX_red(chig, S->pmf);1561}1562/* either success or second consecutive failure */1563if (chig || chib) break;1564/* if g fails the v*-test, v(beta) was wrong. Retry once */1565L = -1;1566}1567*pchig = chig; *peq = eq; *per = er; return g;1568}15691570/* return 1 if at least 2 factors mod p ==> chi can be split */1571static int1572loop(decomp_t *S, long Ea)1573{1574pari_sp av = avma;1575GEN beta = FpXQ_powu(S->nu, Ea, S->chi, S->p);1576long N = degpol(S->f), v = varn(S->f);1577S->invnu = NULL;1578for (;;)1579{ /* beta tends to a factor of chi */1580long L, i, Fg, eq, er;1581GEN chig = NULL, d, g, nug;15821583if (DEBUGLEVEL>4) err_printf(" beta = %Ps\n", beta);1584L = ZpX_resultant_val(S->chi, beta, S->p, S->mf+1);1585if (L > S->mf) L = -1; /* from scratch */1586g = get_g(S, Ea, L, N, beta, &chig, &eq, &er);1587if (DEBUGLEVEL>4) err_printf(" (eq,er) = (%ld,%ld)\n", eq,er);1588/* g = beta p^-eq nu^-er (a unit), chig = charpoly(g) */1589if (split_char(S, chig, g,S->phi, &nug)) return 1;15901591Fg = degpol(nug);1592if (Fg == 1)1593{ /* frequent special case nug = x - d */1594long Le, Ee;1595GEN chie, nue, e, pie;1596d = negi(gel(nug,2));1597chie = RgX_translate(chig, d);1598nue = pol_x(v);1599e = RgX_Rg_sub(g, d);1600pie = getprime(S, e, chie, nue, &Le, &Ee, 0,Ea);1601if (pie) return testc2(S, S->nu, Ea, pie, Ee);1602}1603else1604{1605long Fa = degpol(S->nu), vdeng;1606GEN deng, numg, nume;1607if (Fa % Fg) return testb2(S, ulcm(Fa,Fg), g);1608/* nu & nug irreducible mod p, deg nug | deg nu. To improve beta, look1609* for a root d of nug in Fp[phi] such that v_p(g - d) > 0 */1610if (ZX_equal(nug, S->nu))1611d = pol_x(v);1612else1613{1614if (!p_is_prime(S)) pari_err_PRIME("FpX_ffisom",S->p);1615d = FpX_ffisom(nug, S->nu, S->p);1616}1617/* write g = numg / deng, e = nume / deng */1618numg = QpX_remove_denom(g, S->p, &deng, &vdeng);1619for (i = 1; i <= Fg; i++)1620{1621GEN chie, nue, e;1622if (i != 1) d = FpXQ_pow(d, S->p, S->nu, S->p); /* next root */1623nume = ZX_sub(numg, ZX_Z_mul(d, deng));1624/* test e = nume / deng */1625if (ZpX_resultant_val(S->chi, nume, S->p, vdeng*N+1) <= vdeng*N)1626continue;1627e = RgX_Rg_div(nume, deng);1628chie = mycaract(S, S->chi, e, S->psc, S->prc);1629if (split_char(S, chie, e,S->phi, &nue)) return 1;1630if (RgX_is_monomial(nue))1631{ /* v_p(e) = v_p(g - d) > 0 */1632long Le, Ee;1633GEN pie;1634pie = getprime(S, e, chie, nue, &Le, &Ee, 0,Ea);1635if (pie) return testc2(S, S->nu, Ea, pie, Ee);1636break;1637}1638}1639if (i > Fg)1640{1641if (!p_is_prime(S)) pari_err_PRIME("nilord",S->p);1642pari_err_BUG("nilord (no root)");1643}1644}1645if (eq) d = gmul(d, powiu(S->p, eq));1646if (er) d = gmul(d, gpowgs(S->nu, er));1647beta = gsub(beta, d);16481649if (gc_needed(av,1))1650{1651if (DEBUGMEM > 1) pari_warn(warnmem, "nilord");1652gerepileall(av, S->invnu? 6: 4, &beta, &(S->precns), &(S->ns), &(S->nsf), &(S->invnu), &(S->Dinvnu));1653}1654}1655}16561657/* E and F cannot decrease; return 1 if O = Zp[phi], 2 if we can get a1658* decomposition and 0 otherwise */1659static long1660progress(decomp_t *S, GEN *ppa, long *pE)1661{1662long E = *pE, F;1663GEN pa = *ppa;1664S->phi0 = NULL; /* no delayed composition */1665for(;;)1666{1667long l, La, Ea; /* N.B If E = 0, getprime cannot return NULL */1668GEN pia = getprime(S, NULL, S->chi, S->nu, &La, &Ea, E,0);1669if (pia) { /* success, we break out in THIS loop */1670pa = (typ(pia) == t_POL)? RgX_RgXQ_eval(pia, S->phi, S->f): pia;1671E = Ea;1672if (La == 1) break; /* no need to change phi so that nu = pia */1673}1674/* phi += prime elt */1675S->phi = typ(pa) == t_INT? RgX_Rg_add_shallow(S->phi, pa)1676: RgX_add(S->phi, pa);1677/* recompute char. poly. chi from scratch */1678S->chi = mycaract(S, S->f, S->phi, S->psf, S->pdf);1679S->nu = get_nu(S->chi, S->p, &l);1680if (l > 1) return 2;1681if (!update_phi(S)) return 1; /* unramified */1682if (pia) break;1683}1684*pE = E; *ppa = pa; F = degpol(S->nu);1685if (DEBUGLEVEL>4) err_printf(" (E, F) = (%ld,%ld)\n", E, F);1686if (E * F == degpol(S->f)) return 1;1687if (loop(S, E)) return 2;1688if (!update_phi(S)) return 1;1689return 0;1690}16911692/* flag != 0 iff we're looking for the p-adic factorization,1693in which case it is the p-adic precision we want */1694static GEN1695maxord_i(decomp_t *S, GEN p, GEN f, long mf, GEN w, long flag)1696{1697long oE, n = lg(w)-1; /* factor of largest degree */1698GEN opa, D = ZpX_reduced_resultant_fast(f, ZX_deriv(f), p, mf);1699S->pisprime = -1;1700S->p = p;1701S->mf = mf;1702S->nu = gel(w,n);1703S->df = Z_pval(D, p);1704S->pdf = powiu(p, S->df);1705S->phi = pol_x(varn(f));1706S->chi = S->f = f;1707if (n > 1) return Decomp(S, flag); /* FIXME: use bezout_lift_fact */17081709if (DEBUGLEVEL>4)1710err_printf(" entering Nilord: %Ps^%ld\n f = %Ps, nu = %Ps\n",1711p, S->df, S->f, S->nu);1712else if (DEBUGLEVEL>2) err_printf(" entering Nilord\n");1713S->psf = S->psc = mulii(sqri(D), p);1714S->vpsf = S->vpsc = 2*S->df + 1;1715S->prc = mulii(D, p);1716S->chi = FpX_red(S->f, S->psc);1717S->pmf = powiu(p, S->mf+1);1718S->precns = NULL;1719for(opa = NULL, oE = 0;;)1720{1721long n = progress(S, &opa, &oE);1722if (n == 1) return flag? NULL: dbasis(p, S->f, S->mf, S->phi, S->chi);1723if (n == 2) return Decomp(S, flag);1724}1725}17261727static int1728expo_is_squarefree(GEN e)1729{1730long i, l = lg(e);1731for (i=1; i<l; i++)1732if (e[i] != 1) return 0;1733return 1;1734}1735/* pure round 4 */1736static GEN1737ZpX_round4(GEN f, GEN p, GEN w, long prec)1738{1739decomp_t S;1740GEN L = maxord_i(&S, p, f, ZpX_disc_val(f,p), w, prec);1741return L? L: mkvec(f);1742}1743/* f a squarefree ZX with leading_coeff 1, degree > 0. Return list of1744* irreducible factors in Zp[X] (computed mod p^prec) */1745static GEN1746ZpX_monic_factor_squarefree(GEN f, GEN p, long prec)1747{1748pari_sp av = avma;1749GEN L, fa, w, e;1750long i, l;1751if (degpol(f) == 1) return mkvec(f);1752fa = FpX_factor(f,p); w = gel(fa,1); e = gel(fa,2);1753/* no repeated factors: Hensel lift */1754if (expo_is_squarefree(e)) return ZpX_liftfact(f, w, powiu(p,prec), p, prec);1755l = lg(w);1756if (l == 2)1757{1758L = ZpX_round4(f,p,w,prec);1759if (lg(L) == 2) { set_avma(av); return mkvec(f); }1760}1761else1762{ /* >= 2 factors mod p: partial Hensel lift */1763GEN D = ZpX_reduced_resultant_fast(f, ZX_deriv(f), p, ZpX_disc_val(f,p));1764long r = maxss(2*Z_pval(D,p)+1, prec);1765GEN W = cgetg(l, t_VEC);1766for (i = 1; i < l; i++)1767gel(W,i) = e[i] == 1? gel(w,i): FpX_powu(gel(w,i), e[i], p);1768L = ZpX_liftfact(f, W, powiu(p,r), p, r);1769for (i = 1; i < l; i++)1770gel(L,i) = e[i] == 1? mkvec(gel(L,i))1771: ZpX_round4(gel(L,i), p, mkvec(gel(w,i)), prec);1772L = shallowconcat1(L);1773}1774return gerepilecopy(av, L);1775}17761777/* assume f a ZX with leading_coeff 1, degree > 0 */1778GEN1779ZpX_monic_factor(GEN f, GEN p, long prec)1780{1781GEN poly, ex, P, E;1782long l, i;17831784if (degpol(f) == 1) return mkmat2(mkcol(f), mkcol(gen_1));1785poly = ZX_squff(f,&ex); l = lg(poly);1786P = cgetg(l, t_VEC);1787E = cgetg(l, t_VEC);1788for (i = 1; i < l; i++)1789{1790GEN L = ZpX_monic_factor_squarefree(gel(poly,i), p, prec);1791gel(P,i) = L; settyp(L, t_COL);1792gel(E,i) = const_col(lg(L)-1, utoipos(ex[i]));1793}1794return mkmat2(shallowconcat1(P), shallowconcat1(E));1795}17961797/* DT = multiple of disc(T) or NULL1798* Return a multiple of the denominator of an algebraic integer (in Q[X]/(T))1799* when expressed in terms of the power basis */1800GEN1801indexpartial(GEN T, GEN DT)1802{1803pari_sp av = avma;1804long i, nb;1805GEN fa, E, P, U, res = gen_1, dT = ZX_deriv(T);18061807if (!DT) DT = ZX_disc(T);1808fa = absZ_factor_limit_strict(DT, 0, &U);1809P = gel(fa,1);1810E = gel(fa,2); nb = lg(P)-1;1811for (i = 1; i <= nb; i++)1812{1813long e = itou(gel(E,i)), e2 = e >> 1;1814GEN p = gel(P,i), q = p;1815if (e2 >= 2) q = ZpX_reduced_resultant_fast(T, dT, p, e2);1816res = mulii(res, q);1817}1818if (U)1819{1820long e = itou(gel(U,2)), e2 = e >> 1;1821GEN p = gel(U,1), q = powiu(p, odd(e)? e2+1: e2);1822res = mulii(res, q);1823}1824return gerepileuptoint(av,res);1825}18261827/*******************************************************************/1828/* */1829/* 2-ELT REPRESENTATION FOR PRIME IDEALS (dividing index) */1830/* */1831/*******************************************************************/1832/* to compute norm of elt in basis form */1833typedef struct {1834long r1;1835GEN M; /* via embed_norm */18361837GEN D, w, T; /* via resultant if M = NULL */1838} norm_S;18391840static GEN1841get_norm(norm_S *S, GEN a)1842{1843if (S->M)1844{1845long e;1846GEN N = grndtoi( embed_norm(RgM_RgC_mul(S->M, a), S->r1), &e );1847if (e > -5) pari_err_PREC( "get_norm");1848return N;1849}1850if (S->w) a = RgV_RgC_mul(S->w, a);1851return ZX_resultant_all(S->T, a, S->D, 0);1852}1853static void1854init_norm(norm_S *S, GEN nf, GEN p)1855{1856GEN T = nf_get_pol(nf), M = nf_get_M(nf);1857long N = degpol(T), ex = gexpo(M) + gexpo(mului(8 * N, p));18581859S->r1 = nf_get_r1(nf);1860if (N * ex <= prec2nbits(gprecision(M)) - 20)1861{ /* enough prec to use embed_norm */1862S->M = M;1863S->D = NULL;1864S->w = NULL;1865S->T = NULL;1866}1867else1868{1869GEN w = leafcopy(nf_get_zkprimpart(nf)), D = nf_get_zkden(nf), Dp = sqri(p);1870long i;1871if (!equali1(D))1872{1873GEN w1 = D;1874long v = Z_pval(D, p);1875D = powiu(p, v);1876Dp = mulii(D, Dp);1877gel(w, 1) = remii(w1, Dp);1878}1879for (i=2; i<=N; i++) gel(w,i) = FpX_red(gel(w,i), Dp);1880S->M = NULL;1881S->D = D;1882S->w = w;1883S->T = T;1884}1885}1886/* f = f(pr/p), q = p^(f+1), a in pr.1887* Return 1 if v_pr(a) = 1, and 0 otherwise */1888static int1889is_uniformizer(GEN a, GEN q, norm_S *S) { return !dvdii(get_norm(S,a), q); }18901891/* Return x * y, x, y are t_MAT (Fp-basis of in O_K/p), assume (x,y)=1.1892* Either x or y may be NULL (= O_K), not both */1893static GEN1894mul_intersect(GEN x, GEN y, GEN p)1895{1896if (!x) return y;1897if (!y) return x;1898return FpM_intersect_i(x, y, p);1899}1900/* Fp-basis of (ZK/pr): applied to the primes found in primedec_aux()1901* true nf */1902static GEN1903Fp_basis(GEN nf, GEN pr)1904{1905long i, j, l;1906GEN x, y;1907/* already in basis form (from Buchman-Lenstra) ? */1908if (typ(pr) == t_MAT) return pr;1909/* ordinary prid (from Kummer) */1910x = pr_hnf(nf, pr);1911l = lg(x);1912y = cgetg(l, t_MAT);1913for (i=j=1; i<l; i++)1914if (gequal1(gcoeff(x,i,i))) gel(y,j++) = gel(x,i);1915setlg(y, j); return y;1916}1917/* Let Ip = prod_{ P | p } P be the p-radical. The list L contains the1918* P (mod Ip) seen as sub-Fp-vector spaces of ZK/Ip.1919* Return the list of (Ip / P) (mod Ip).1920* N.B: All ideal multiplications are computed as intersections of Fp-vector1921* spaces. true nf */1922static GEN1923get_LV(GEN nf, GEN L, GEN p, long N)1924{1925long i, l = lg(L)-1;1926GEN LV, LW, A, B;19271928LV = cgetg(l+1, t_VEC);1929if (l == 1) { gel(LV,1) = matid(N); return LV; }1930LW = cgetg(l+1, t_VEC);1931for (i=1; i<=l; i++) gel(LW,i) = Fp_basis(nf, gel(L,i));19321933/* A[i] = L[1]...L[i-1], i = 2..l */1934A = cgetg(l+1, t_VEC); gel(A,1) = NULL;1935for (i=1; i < l; i++) gel(A,i+1) = mul_intersect(gel(A,i), gel(LW,i), p);1936/* B[i] = L[i+1]...L[l], i = 1..(l-1) */1937B = cgetg(l+1, t_VEC); gel(B,l) = NULL;1938for (i=l; i>=2; i--) gel(B,i-1) = mul_intersect(gel(B,i), gel(LW,i), p);1939for (i=1; i<=l; i++) gel(LV,i) = mul_intersect(gel(A,i), gel(B,i), p);1940return LV;1941}19421943static void1944errprime(GEN p) { pari_err_PRIME("idealprimedec",p); }19451946/* P = Fp-basis (over O_K/p) for pr.1947* V = Z-basis for I_p/pr. ramif != 0 iff some pr|p is ramified.1948* Return a p-uniformizer for pr. Assume pr not inert, i.e. m > 0 */1949static GEN1950uniformizer(GEN nf, norm_S *S, GEN P, GEN V, GEN p, int ramif)1951{1952long i, l, f, m = lg(P)-1, N = nf_get_degree(nf);1953GEN u, Mv, x, q;19541955f = N - m; /* we want v_p(Norm(x)) = p^f */1956q = powiu(p,f+1);19571958u = FpM_FpC_invimage(shallowconcat(P, V), col_ei(N,1), p);1959setlg(u, lg(P));1960u = centermod(ZM_ZC_mul(P, u), p);1961if (is_uniformizer(u, q, S)) return u;1962if (signe(gel(u,1)) <= 0) /* make sure u[1] in ]-p,p] */1963gel(u,1) = addii(gel(u,1), p); /* try u + p */1964else1965gel(u,1) = subii(gel(u,1), p); /* try u - p */1966if (!ramif || is_uniformizer(u, q, S)) return u;19671968/* P/p ramified, u in P^2, not in Q for all other Q|p */1969Mv = zk_multable(nf, Z_ZC_sub(gen_1,u));1970l = lg(P);1971for (i=1; i<l; i++)1972{1973x = centermod(ZC_add(u, ZM_ZC_mul(Mv, gel(P,i))), p);1974if (is_uniformizer(x, q, S)) return x;1975}1976errprime(p);1977return NULL; /* LCOV_EXCL_LINE */1978}19791980/*******************************************************************/1981/* */1982/* BUCHMANN-LENSTRA ALGORITHM */1983/* */1984/*******************************************************************/1985static GEN1986mk_pr(GEN p, GEN u, long e, long f, GEN t)1987{ return mkvec5(p, u, utoipos(e), utoipos(f), t); }19881989/* nf a true nf, u in Z[X]/(T); pr = p Z_K + u Z_K of ramification index e */1990GEN1991idealprimedec_kummer(GEN nf,GEN u,long e,GEN p)1992{1993GEN t, T = nf_get_pol(nf);1994long f = degpol(u), N = degpol(T);19951996if (f == N)1997{ /* inert */1998u = scalarcol_shallow(p,N);1999t = gen_1;2000}2001else2002{2003t = centermod(poltobasis(nf, FpX_div(T, u, p)), p);2004u = centermod(poltobasis(nf, u), p);2005if (e == 1)2006{ /* make sure v_pr(u) = 1 (automatic if e>1) */2007GEN cw, w = Q_primitive_part(nf_to_scalar_or_alg(nf, u), &cw);2008long v = cw? f - Q_pval(cw, p) * N: f;2009if (ZpX_resultant_val(T, w, p, v + 1) > v)2010{2011GEN c = gel(u,1);2012gel(u,1) = signe(c) > 0? subii(c, p): addii(c, p);2013}2014}2015t = zk_multable(nf, t);2016}2017return mk_pr(p,u,e,f,t);2018}20192020typedef struct {2021GEN nf, p;2022long I;2023} eltmod_muldata;20242025static GEN2026sqr_mod(void *data, GEN x)2027{2028eltmod_muldata *D = (eltmod_muldata*)data;2029return FpC_red(nfsqri(D->nf, x), D->p);2030}2031static GEN2032ei_msqr_mod(void *data, GEN x)2033{2034GEN x2 = sqr_mod(data, x);2035eltmod_muldata *D = (eltmod_muldata*)data;2036return FpC_red(zk_ei_mul(D->nf, x2, D->I), D->p);2037}2038/* nf a true nf; compute lift(nf.zk[I]^p mod p) */2039static GEN2040pow_ei_mod_p(GEN nf, long I, GEN p)2041{2042pari_sp av = avma;2043eltmod_muldata D;2044long N = nf_get_degree(nf);2045GEN y = col_ei(N,I);2046if (I == 1) return y;2047D.nf = nf;2048D.p = p;2049D.I = I;2050y = gen_pow_fold(y, p, (void*)&D, &sqr_mod, &ei_msqr_mod);2051return gerepileupto(av,y);2052}20532054/* nf a true nf; return a Z basis of Z_K's p-radical, phi = x--> x^p-x */2055static GEN2056pradical(GEN nf, GEN p, GEN *phi)2057{2058long i, N = nf_get_degree(nf);2059GEN q,m,frob,rad;20602061/* matrix of Frob: x->x^p over Z_K/p */2062frob = cgetg(N+1,t_MAT);2063for (i=1; i<=N; i++) gel(frob,i) = pow_ei_mod_p(nf,i,p);20642065m = frob; q = p;2066while (abscmpiu(q,N) < 0) { q = mulii(q,p); m = FpM_mul(m, frob, p); }2067rad = FpM_ker(m, p); /* m = Frob^k, s.t p^k >= N */2068for (i=1; i<=N; i++) gcoeff(frob,i,i) = subiu(gcoeff(frob,i,i), 1);2069*phi = frob; return rad;2070}20712072/* return powers of a: a^0, ... , a^d, d = dim A */2073static GEN2074get_powers(GEN mul, GEN p)2075{2076long i, d = lgcols(mul);2077GEN z, pow = cgetg(d+2,t_MAT), P = pow+1;20782079gel(P,0) = scalarcol_shallow(gen_1, d-1);2080z = gel(mul,1);2081for (i=1; i<=d; i++)2082{2083gel(P,i) = z; /* a^i */2084if (i!=d) z = FpM_FpC_mul(mul, z, p);2085}2086return pow;2087}20882089/* minimal polynomial of a in A (dim A = d).2090* mul = multiplication table by a in A */2091static GEN2092pol_min(GEN mul, GEN p)2093{2094pari_sp av = avma;2095GEN z = FpM_deplin(get_powers(mul, p), p);2096return gerepilecopy(av, RgV_to_RgX(z,0));2097}20982099static GEN2100get_pr(GEN nf, norm_S *S, GEN p, GEN P, GEN V, int ramif, long N, long flim)2101{2102GEN u, t;2103long e, f;21042105if (typ(P) == t_VEC)2106{ /* already done (Kummer) */2107f = pr_get_f(P);2108if (flim > 0 && f > flim) return NULL;2109if (flim == -2) return (GEN)f;2110return P;2111}2112f = N - (lg(P)-1);2113if (flim > 0 && f > flim) return NULL;2114if (flim == -2) return (GEN)f;2115/* P = (p,u) prime. t is an anti-uniformizer: Z_K + t/p Z_K = P^(-1),2116* so that v_P(t) = e(P/p)-1 */2117if (f == N) {2118u = scalarcol_shallow(p,N);2119t = gen_1;2120e = 1;2121} else {2122GEN mt;2123u = uniformizer(nf, S, P, V, p, ramif);2124t = FpM_deplin(zk_multable(nf,u), p);2125mt = zk_multable(nf, t);2126e = ramif? 1 + ZC_nfval(t,mk_pr(p,u,0,0,mt)): 1;2127t = mt;2128}2129return mk_pr(p,u,e,f,t);2130}21312132/* true nf */2133static GEN2134primedec_end(GEN nf, GEN L, GEN p, long flim)2135{2136long i, j, l = lg(L), N = nf_get_degree(nf);2137GEN LV = get_LV(nf, L,p,N);2138int ramif = dvdii(nf_get_disc(nf), p);2139norm_S S; init_norm(&S, nf, p);2140for (i = j = 1; i < l; i++)2141{2142GEN P = get_pr(nf, &S, p, gel(L,i), gel(LV,i), ramif, N, flim);2143if (!P) continue;2144gel(L,j++) = P;2145if (flim == -1) return P;2146}2147setlg(L, j); return L;2148}21492150/* prime ideal decomposition of p; if flim>0, restrict to f(P,p) <= flim2151* if flim = -1 return only the first P2152* if flim = -2 return only the f(P/p) in a t_VECSMALL */2153static GEN2154primedec_aux(GEN nf, GEN p, long flim)2155{2156const long TYP = (flim == -2)? t_VECSMALL: t_VEC;2157GEN E, F, L, Ip, phi, f, g, h, UN, T = nf_get_pol(nf);2158long i, k, c, iL, N;2159int kummer;21602161F = FpX_factor(T, p);2162E = gel(F,2);2163F = gel(F,1);21642165k = lg(F); if (k == 1) errprime(p);2166if ( !dvdii(nf_get_index(nf),p) ) /* p doesn't divide index */2167{2168L = cgetg(k, TYP);2169for (i=1; i<k; i++)2170{2171GEN t = gel(F,i);2172long f = degpol(t);2173if (flim > 0 && f > flim) { setlg(L, i); break; }2174if (flim == -2)2175L[i] = f;2176else2177gel(L,i) = idealprimedec_kummer(nf, t, E[i],p);2178if (flim == -1) return gel(L,1);2179}2180return L;2181}21822183kummer = 0;2184g = FpXV_prod(F, p);2185h = FpX_div(T,g,p);2186f = FpX_red(ZX_Z_divexact(ZX_sub(ZX_mul(g,h), T), p), p);21872188N = degpol(T);2189L = cgetg(N+1,TYP);2190iL = 1;2191for (i=1; i<k; i++)2192if (E[i] == 1 || signe(FpX_rem(f,gel(F,i),p)))2193{2194GEN t = gel(F,i);2195kummer = 1;2196gel(L,iL++) = idealprimedec_kummer(nf, t, E[i],p);2197if (flim == -1) return gel(L,1);2198}2199else /* F[i] | (f,g,h), happens at least once by Dedekind criterion */2200E[i] = 0;22012202/* phi matrix of x -> x^p - x in algebra Z_K/p */2203Ip = pradical(nf,p,&phi);22042205/* split etale algebra Z_K / (p,Ip) */2206h = cgetg(N+1,t_VEC);2207if (kummer)2208{ /* split off Kummer factors */2209GEN mb, b = NULL;2210for (i=1; i<k; i++)2211if (!E[i]) b = b? FpX_mul(b, gel(F,i), p): gel(F,i);2212if (!b) errprime(p);2213b = FpC_red(poltobasis(nf,b), p);2214mb = FpM_red(zk_multable(nf,b), p);2215/* Fp-base of ideal (Ip, b) in ZK/p */2216gel(h,1) = FpM_image(shallowconcat(mb,Ip), p);2217}2218else2219gel(h,1) = Ip;22202221UN = col_ei(N, 1);2222for (c=1; c; c--)2223{ /* Let A:= (Z_K/p) / Ip etale; split A2 := A / Im H ~ Im M22224H * ? + M2 * Mi2 = Id_N ==> M2 * Mi2 projector A --> A2 */2225GEN M, Mi, M2, Mi2, phi2, mat1, H = gel(h,c); /* maximal rank */2226long dim, r = lg(H)-1;22272228M = FpM_suppl(shallowconcat(H,UN), p);2229Mi = FpM_inv(M, p);2230M2 = vecslice(M, r+1,N); /* M = (H|M2) invertible */2231Mi2 = rowslice(Mi,r+1,N);2232/* FIXME: FpM_mul(,M2) could be done with vecpermute */2233phi2 = FpM_mul(Mi2, FpM_mul(phi,M2, p), p);2234mat1 = FpM_ker(phi2, p);2235dim = lg(mat1)-1; /* A2 product of 'dim' fields */2236if (dim > 1)2237{ /* phi2 v = 0 => a = M2 v in Ker phi, a not in Fp.1 + H */2238GEN R, a, mula, mul2, v = gel(mat1,2);2239long n;22402241a = FpM_FpC_mul(M2,v, p); /* not a scalar */2242mula = FpM_red(zk_multable(nf,a), p);2243mul2 = FpM_mul(Mi2, FpM_mul(mula,M2, p), p);2244R = FpX_roots(pol_min(mul2,p), p); /* totally split mod p */2245n = lg(R)-1;2246for (i=1; i<=n; i++)2247{2248GEN I = RgM_Rg_sub_shallow(mula, gel(R,i));2249gel(h,c++) = FpM_image(shallowconcat(H, I), p);2250}2251if (n == dim)2252for (i=1; i<=n; i++) gel(L,iL++) = gel(h,--c);2253}2254else /* A2 field ==> H maximal, f = N-r = dim(A2) */2255gel(L,iL++) = H;2256}2257setlg(L, iL);2258return primedec_end(nf, L, p, flim);2259}22602261GEN2262idealprimedec_limit_f(GEN nf, GEN p, long f)2263{2264pari_sp av = avma;2265GEN v;2266if (typ(p) != t_INT) pari_err_TYPE("idealprimedec",p);2267if (f < 0) pari_err_DOMAIN("idealprimedec", "f", "<", gen_0, stoi(f));2268v = primedec_aux(checknf(nf), p, f);2269v = gen_sort(v, (void*)&cmp_prime_over_p, &cmp_nodata);2270return gerepileupto(av,v);2271}2272GEN2273idealprimedec_galois(GEN nf, GEN p)2274{2275pari_sp av = avma;2276GEN v = primedec_aux(checknf(nf), p, -1);2277return gerepilecopy(av,v);2278}2279GEN2280idealprimedec_degrees(GEN nf, GEN p)2281{2282pari_sp av = avma;2283GEN v = primedec_aux(checknf(nf), p, -2);2284vecsmall_sort(v); return gerepileuptoleaf(av, v);2285}2286GEN2287idealprimedec_limit_norm(GEN nf, GEN p, GEN B)2288{ return idealprimedec_limit_f(nf, p, logint(B,p)); }2289GEN2290idealprimedec(GEN nf, GEN p)2291{ return idealprimedec_limit_f(nf, p, 0); }2292GEN2293nf_pV_to_prV(GEN nf, GEN P)2294{2295long i, l;2296GEN Q = cgetg_copy(P,&l);2297if (l == 1) return Q;2298for (i = 1; i < l; i++) gel(Q,i) = idealprimedec(nf, gel(P,i));2299return shallowconcat1(Q);2300}23012302/* return [Fp[x]: Fp] */2303static long2304ffdegree(GEN x, GEN frob, GEN p)2305{2306pari_sp av = avma;2307long d, f = lg(frob)-1;2308GEN y = x;23092310for (d=1; d < f; d++)2311{2312y = FpM_FpC_mul(frob, y, p);2313if (ZV_equal(y, x)) break;2314}2315return gc_long(av,d);2316}23172318static GEN2319lift_to_zk(GEN v, GEN c, long N)2320{2321GEN w = zerocol(N);2322long i, l = lg(c);2323for (i=1; i<l; i++) gel(w,c[i]) = gel(v,i);2324return w;2325}23262327/* return t = 1 mod pr, t = 0 mod p / pr^e(pr/p) */2328static GEN2329anti_uniformizer(GEN nf, GEN pr)2330{2331long N = nf_get_degree(nf), e = pr_get_e(pr);2332GEN p, b, z;23332334if (e * pr_get_f(pr) == N) return gen_1;2335p = pr_get_p(pr);2336b = pr_get_tau(pr); /* ZM */2337if (e != 1)2338{2339GEN q = powiu(pr_get_p(pr), e-1);2340b = ZM_Z_divexact(ZM_powu(b,e), q);2341}2342/* b = tau^e / p^(e-1), v_pr(b) = 0, v_Q(b) >= e(Q/p) for other Q | p */2343z = ZM_hnfmodid(FpM_red(b,p), p); /* ideal (p) / pr^e, coprime to pr */2344z = idealaddtoone_raw(nf, pr, z);2345return Z_ZC_sub(gen_1, FpC_center(FpC_red(z,p), p, shifti(p,-1)));2346}23472348#define mpr_TAU 12349#define mpr_FFP 22350#define mpr_NFP 52351#define SMALLMODPR 42352#define LARGEMODPR 62353static GEN2354modpr_TAU(GEN modpr)2355{2356GEN tau = gel(modpr,mpr_TAU);2357return isintzero(tau)? NULL: tau;2358}23592360/* prh = HNF matrix, which is identity but for the first line. Return a2361* projector to ZK / prh ~ Z/prh[1,1] */2362GEN2363dim1proj(GEN prh)2364{2365long i, N = lg(prh)-1;2366GEN ffproj = cgetg(N+1, t_VEC);2367GEN x, q = gcoeff(prh,1,1);2368gel(ffproj,1) = gen_1;2369for (i=2; i<=N; i++)2370{2371x = gcoeff(prh,1,i);2372if (signe(x)) x = subii(q,x);2373gel(ffproj,i) = x;2374}2375return ffproj;2376}23772378/* p not necessarily prime, but coprime to denom(basis) */2379GEN2380QXQV_to_FpM(GEN basis, GEN T, GEN p)2381{2382long i, l = lg(basis), f = degpol(T);2383GEN z = cgetg(l, t_MAT);2384for (i = 1; i < l; i++)2385{2386GEN w = gel(basis,i);2387if (typ(w) == t_INT)2388w = scalarcol_shallow(w, f);2389else2390{2391GEN dx;2392w = Q_remove_denom(w, &dx);2393w = FpXQ_red(w, T, p);2394if (dx)2395{2396dx = Fp_inv(dx, p);2397if (!equali1(dx)) w = FpX_Fp_mul(w, dx, p);2398}2399w = RgX_to_RgC(w, f);2400}2401gel(z,i) = w; /* w_i mod (T,p) */2402}2403return z;2404}24052406/* initialize reduction mod pr; if zk = 1, will only init data required to2407* reduce *integral* element. Realize (O_K/pr) as Fp[X] / (T), for a2408* *monic* T; use variable vT for varn(T) */2409static GEN2410modprinit(GEN nf, GEN pr, int zk, long vT)2411{2412pari_sp av = avma;2413GEN res, tau, mul, x, p, T, pow, ffproj, nfproj, prh, c;2414long N, i, k, f;24152416nf = checknf(nf); checkprid(pr);2417if (vT < 0) vT = nf_get_varn(nf);2418f = pr_get_f(pr);2419N = nf_get_degree(nf);2420prh = pr_hnf(nf, pr);2421tau = zk? gen_0: anti_uniformizer(nf, pr);2422p = pr_get_p(pr);24232424if (f == 1)2425{2426res = cgetg(SMALLMODPR, t_COL);2427gel(res,mpr_TAU) = tau;2428gel(res,mpr_FFP) = dim1proj(prh);2429gel(res,3) = pr; return gerepilecopy(av, res);2430}24312432c = cgetg(f+1, t_VECSMALL);2433ffproj = cgetg(N+1, t_MAT);2434for (k=i=1; i<=N; i++)2435{2436x = gcoeff(prh, i,i);2437if (!is_pm1(x)) { c[k] = i; gel(ffproj,i) = col_ei(N, i); k++; }2438else2439gel(ffproj,i) = ZC_neg(gel(prh,i));2440}2441ffproj = rowpermute(ffproj, c);2442if (! dvdii(nf_get_index(nf), p))2443{2444GEN basis = nf_get_zkprimpart(nf), D = nf_get_zkden(nf);2445if (N == f)2446{ /* pr inert */2447T = nf_get_pol(nf);2448T = FpX_red(T,p);2449ffproj = RgV_to_RgM(basis, lg(basis)-1);2450}2451else2452{2453T = RgV_RgC_mul(basis, pr_get_gen(pr));2454T = FpX_normalize(FpX_red(T,p),p);2455basis = FqV_red(vecpermute(basis,c), T, p);2456basis = RgV_to_RgM(basis, lg(basis)-1);2457ffproj = ZM_mul(basis, ffproj);2458}2459setvarn(T, vT);2460ffproj = FpM_red(ffproj, p);2461if (!equali1(D))2462{2463D = modii(D,p);2464if (!equali1(D)) ffproj = FpM_Fp_mul(ffproj, Fp_inv(D,p), p);2465}24662467res = cgetg(SMALLMODPR+1, t_COL);2468gel(res,mpr_TAU) = tau;2469gel(res,mpr_FFP) = ffproj;2470gel(res,3) = pr;2471gel(res,4) = T; return gerepilecopy(av, res);2472}24732474if (uisprime(f))2475{2476mul = ei_multable(nf, c[2]);2477mul = vecpermute(mul, c);2478}2479else2480{2481GEN v, u, u2, frob;2482long deg,deg1,deg2;24832484/* matrix of Frob: x->x^p over Z_K/pr = < w[c1], ..., w[cf] > over Fp */2485frob = cgetg(f+1, t_MAT);2486for (i=1; i<=f; i++)2487{2488x = pow_ei_mod_p(nf,c[i],p);2489gel(frob,i) = FpM_FpC_mul(ffproj, x, p);2490}2491u = col_ei(f,2); k = 2;2492deg1 = ffdegree(u, frob, p);2493while (deg1 < f)2494{2495k++; u2 = col_ei(f, k);2496deg2 = ffdegree(u2, frob, p);2497deg = ulcm(deg1,deg2);2498if (deg == deg1) continue;2499if (deg == deg2) { deg1 = deg2; u = u2; continue; }2500u = ZC_add(u, u2);2501while (ffdegree(u, frob, p) < deg) u = ZC_add(u, u2);2502deg1 = deg;2503}2504v = lift_to_zk(u,c,N);25052506mul = cgetg(f+1,t_MAT);2507gel(mul,1) = v; /* assume w_1 = 1 */2508for (i=2; i<=f; i++) gel(mul,i) = zk_ei_mul(nf,v,c[i]);2509}25102511/* Z_K/pr = Fp(v), mul = mul by v */2512mul = FpM_red(mul, p);2513mul = FpM_mul(ffproj, mul, p);25142515pow = get_powers(mul, p);2516T = RgV_to_RgX(FpM_deplin(pow, p), vT);2517nfproj = cgetg(f+1, t_MAT);2518for (i=1; i<=f; i++) gel(nfproj,i) = lift_to_zk(gel(pow,i), c, N);25192520setlg(pow, f+1);2521ffproj = FpM_mul(FpM_inv(pow, p), ffproj, p);25222523res = cgetg(LARGEMODPR, t_COL);2524gel(res,mpr_TAU) = tau;2525gel(res,mpr_FFP) = ffproj;2526gel(res,3) = pr;2527gel(res,4) = T;2528gel(res,mpr_NFP) = nfproj; return gerepilecopy(av, res);2529}25302531GEN2532nfmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 0, -1); }2533GEN2534zkmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 1, -1); }2535GEN2536nfmodprinit0(GEN nf, GEN pr, long v) { return modprinit(nf, pr, 0, v); }25372538/* x may be a modpr */2539static int2540ok_modpr(GEN x)2541{ return typ(x) == t_COL && lg(x) >= SMALLMODPR && lg(x) <= LARGEMODPR; }2542void2543checkmodpr(GEN x)2544{2545if (!ok_modpr(x)) pari_err_TYPE("checkmodpr [use nfmodprinit]", x);2546checkprid(modpr_get_pr(x));2547}2548GEN2549get_modpr(GEN x)2550{ return ok_modpr(x)? x: NULL; }25512552int2553checkprid_i(GEN x)2554{2555return (typ(x) == t_VEC && lg(x) == 62556&& typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT2557&& typ(gel(x,5)) != t_COL); /* tau changed to t_MAT/t_INT in 2.6 */2558}2559void2560checkprid(GEN x)2561{ if (!checkprid_i(x)) pari_err_TYPE("checkprid",x); }2562GEN2563get_prid(GEN x)2564{2565long lx = lg(x);2566if (lx == 3 && typ(x) == t_VEC) x = gel(x,1);2567if (checkprid_i(x)) return x;2568if (ok_modpr(x)) {2569x = modpr_get_pr(x);2570if (checkprid_i(x)) return x;2571}2572return NULL;2573}25742575static GEN2576to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p, int zk)2577{2578GEN modpr = ok_modpr(*pr)? *pr: modprinit(nf, *pr, zk, -1);2579*T = modpr_get_T(modpr);2580*pr = modpr_get_pr(modpr);2581*p = pr_get_p(*pr); return modpr;2582}25832584/* Return an element of O_K which is set to x Mod T */2585GEN2586modpr_genFq(GEN modpr)2587{2588switch(lg(modpr))2589{2590case SMALLMODPR: /* Fp */2591return gen_1;2592case LARGEMODPR: /* painful case, p \mid index */2593return gmael(modpr,mpr_NFP, 2);2594default: /* trivial case : p \nmid index */2595{2596long v = varn( modpr_get_T(modpr) );2597return pol_x(v);2598}2599}2600}26012602GEN2603nf_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) {2604GEN modpr = to_ff_init(nf,pr,T,p,0);2605GEN tau = modpr_TAU(modpr);2606if (!tau) gel(modpr,mpr_TAU) = anti_uniformizer(nf, *pr);2607return modpr;2608}2609GEN2610zk_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) {2611return to_ff_init(nf,pr,T,p,1);2612}26132614/* assume x in 'basis' form (t_COL) */2615GEN2616zk_to_Fq(GEN x, GEN modpr)2617{2618GEN pr = modpr_get_pr(modpr), p = pr_get_p(pr);2619GEN ffproj = gel(modpr,mpr_FFP);2620GEN T = modpr_get_T(modpr);2621return T? FpM_FpC_mul_FpX(ffproj,x, p, varn(T)): FpV_dotproduct(ffproj,x, p);2622}26232624/* REDUCTION Modulo a prime ideal */26252626/* nf a true nf */2627static GEN2628Rg_to_ff(GEN nf, GEN x0, GEN modpr)2629{2630GEN x = x0, den, pr = modpr_get_pr(modpr), p = pr_get_p(pr);2631long tx = typ(x);26322633if (tx == t_POLMOD) { x = gel(x,2); tx = typ(x); }2634switch(tx)2635{2636case t_INT: return modii(x, p);2637case t_FRAC: return Rg_to_Fp(x, p);2638case t_POL:2639switch(lg(x))2640{2641case 2: return gen_0;2642case 3: return Rg_to_Fp(gel(x,2), p);2643}2644x = Q_remove_denom(x, &den);2645x = poltobasis(nf, x);2646/* content(x) and den may not be coprime */2647break;2648case t_COL:2649x = Q_remove_denom(x, &den);2650/* content(x) and den are coprime */2651if (lg(x)-1 == nf_get_degree(nf)) break;2652default: pari_err_TYPE("Rg_to_ff",x);2653return NULL;/*LCOV_EXCL_LINE*/2654}2655if (den)2656{2657long v = Z_pvalrem(den, p, &den);2658if (v)2659{2660if (tx == t_POL) v -= ZV_pvalrem(x, p, &x);2661/* now v = valuation(true denominator of x) */2662if (v > 0)2663{2664GEN tau = modpr_TAU(modpr);2665if (!tau) pari_err_TYPE("zk_to_ff", x0);2666x = nfmuli(nf,x, nfpow_u(nf, tau, v));2667v -= ZV_pvalrem(x, p, &x);2668}2669if (v > 0) pari_err_INV("Rg_to_ff", mkintmod(gen_0,p));2670if (v) return gen_0;2671if (is_pm1(den)) den = NULL;2672}2673x = FpC_red(x, p);2674}2675x = zk_to_Fq(x, modpr);2676if (den)2677{2678GEN c = Fp_inv(den, p);2679x = typ(x) == t_INT? Fp_mul(x,c,p): FpX_Fp_mul(x,c,p);2680}2681return x;2682}26832684GEN2685nfreducemodpr(GEN nf, GEN x, GEN modpr)2686{2687pari_sp av = avma;2688nf = checknf(nf); checkmodpr(modpr);2689return gerepileupto(av, algtobasis(nf, Fq_to_nf(Rg_to_ff(nf,x,modpr),modpr)));2690}26912692GEN2693nfmodpr(GEN nf, GEN x, GEN pr)2694{2695pari_sp av = avma;2696GEN T, p, modpr;2697nf = checknf(nf);2698modpr = nf_to_Fq_init(nf, &pr, &T, &p);2699if (typ(x) == t_MAT && lg(x) == 3)2700{2701GEN y, v = famat_nfvalrem(nf, x, pr, &y);2702long s = signe(v);2703if (s < 0) pari_err_INV("Rg_to_ff", mkintmod(gen_0,p));2704if (s > 0) return gc_const(av, gen_0);2705x = FqV_factorback(nfV_to_FqV(gel(y,1), nf, modpr), gel(y,2), T, p);2706return gerepileupto(av, x);2707}2708x = Rg_to_ff(nf, x, modpr);2709x = Fq_to_FF(x, Tp_to_FF(T,p));2710return gerepilecopy(av, x);2711}2712GEN2713nfmodprlift(GEN nf, GEN x, GEN pr)2714{2715pari_sp av = avma;2716GEN y, T, p, modpr;2717long i, l, d;2718nf = checknf(nf);2719switch(typ(x))2720{2721case t_INT: return icopy(x);2722case t_FFELT: break;2723case t_VEC: case t_COL: case t_MAT:2724y = cgetg_copy(x,&l);2725for (i = 1; i < l; i++) gel(y,i) = nfmodprlift(nf,gel(x,i),pr);2726return y;2727default: pari_err_TYPE("nfmodprlit",x);2728}2729x = FF_to_FpXQ_i(x);2730d = degpol(x);2731if (d <= 0) { set_avma(av); return d? gen_0: icopy(gel(x,2)); }2732modpr = nf_to_Fq_init(nf, &pr, &T, &p);2733return gerepilecopy(av, Fq_to_nf(x, modpr));2734}27352736/* lift A from residue field to nf */2737GEN2738Fq_to_nf(GEN A, GEN modpr)2739{2740long dA;2741if (typ(A) == t_INT || lg(modpr) < LARGEMODPR) return A;2742dA = degpol(A);2743if (dA <= 0) return dA ? gen_0: gel(A,2);2744return ZM_ZX_mul(gel(modpr,mpr_NFP), A);2745}2746GEN2747FqV_to_nfV(GEN x, GEN modpr)2748{ pari_APPLY_same(Fq_to_nf(gel(x,i), modpr)) }2749GEN2750FqM_to_nfM(GEN A, GEN modpr)2751{2752long i,j,h,l = lg(A);2753GEN B = cgetg(l, t_MAT);27542755if (l == 1) return B;2756h = lgcols(A);2757for (j=1; j<l; j++)2758{2759GEN Aj = gel(A,j), Bj = cgetg(h,t_COL); gel(B,j) = Bj;2760for (i=1; i<h; i++) gel(Bj,i) = Fq_to_nf(gel(Aj,i), modpr);2761}2762return B;2763}2764GEN2765FqX_to_nfX(GEN A, GEN modpr)2766{2767long i, l;2768GEN B;27692770if (typ(A)!=t_POL) return icopy(A); /* scalar */2771B = cgetg_copy(A, &l); B[1] = A[1];2772for (i=2; i<l; i++) gel(B,i) = Fq_to_nf(gel(A,i), modpr);2773return B;2774}27752776/* reduce A to residue field */2777GEN2778nf_to_Fq(GEN nf, GEN A, GEN modpr)2779{2780pari_sp av = avma;2781return gerepileupto(av, Rg_to_ff(checknf(nf), A, modpr));2782}2783/* A t_VEC/t_COL */2784GEN2785nfV_to_FqV(GEN A, GEN nf,GEN modpr)2786{2787long i,l = lg(A);2788GEN B = cgetg(l,typ(A));2789for (i=1; i<l; i++) gel(B,i) = nf_to_Fq(nf,gel(A,i), modpr);2790return B;2791}2792/* A t_MAT */2793GEN2794nfM_to_FqM(GEN A, GEN nf,GEN modpr)2795{2796long i,j,h,l = lg(A);2797GEN B = cgetg(l,t_MAT);27982799if (l == 1) return B;2800h = lgcols(A);2801for (j=1; j<l; j++)2802{2803GEN Aj = gel(A,j), Bj = cgetg(h,t_COL); gel(B,j) = Bj;2804for (i=1; i<h; i++) gel(Bj,i) = nf_to_Fq(nf, gel(Aj,i), modpr);2805}2806return B;2807}2808/* A t_POL */2809GEN2810nfX_to_FqX(GEN A, GEN nf,GEN modpr)2811{2812long i,l = lg(A);2813GEN B = cgetg(l,t_POL); B[1] = A[1];2814for (i=2; i<l; i++) gel(B,i) = nf_to_Fq(nf,gel(A,i),modpr);2815return normalizepol_lg(B, l);2816}28172818/*******************************************************************/2819/* */2820/* RELATIVE ROUND 2 */2821/* */2822/*******************************************************************/2823/* Shallow functions */2824/* FIXME: use a bb_field and export the nfX_* routines */2825static GEN2826nfX_sub(GEN nf, GEN x, GEN y)2827{2828long i, lx = lg(x), ly = lg(y);2829GEN z;2830if (ly <= lx) {2831z = cgetg(lx,t_POL); z[1] = x[1];2832for (i=2; i < ly; i++) gel(z,i) = nfsub(nf,gel(x,i),gel(y,i));2833for ( ; i < lx; i++) gel(z,i) = gel(x,i);2834z = normalizepol_lg(z, lx);2835} else {2836z = cgetg(ly,t_POL); z[1] = y[1];2837for (i=2; i < lx; i++) gel(z,i) = nfsub(nf,gel(x,i),gel(y,i));2838for ( ; i < ly; i++) gel(z,i) = gneg(gel(y,i));2839z = normalizepol_lg(z, ly);2840}2841return z;2842}2843/* FIXME: quadratic multiplication */2844static GEN2845nfX_mul(GEN nf, GEN a, GEN b)2846{2847long da = degpol(a), db = degpol(b), dc, lc, k;2848GEN c;2849if (da < 0 || db < 0) return gen_0;2850dc = da + db;2851if (dc == 0) return nfmul(nf, gel(a,2),gel(b,2));2852lc = dc+3;2853c = cgetg(lc, t_POL); c[1] = a[1];2854for (k = 0; k <= dc; k++)2855{2856long i, I = minss(k, da);2857GEN d = NULL;2858for (i = maxss(k-db, 0); i <= I; i++)2859{2860GEN e = nfmul(nf, gel(a, i+2), gel(b, k-i+2));2861d = d? nfadd(nf, d, e): e;2862}2863gel(c, k+2) = d;2864}2865return normalizepol_lg(c, lc);2866}2867/* assume b monic */2868static GEN2869nfX_rem(GEN nf, GEN a, GEN b)2870{2871long da = degpol(a), db = degpol(b);2872if (da < 0) return gen_0;2873a = leafcopy(a);2874while (da >= db)2875{2876long i, k = da;2877GEN A = gel(a, k+2);2878for (i = db-1, k--; i >= 0; i--, k--)2879gel(a,k+2) = nfsub(nf, gel(a,k+2), nfmul(nf, A, gel(b,i+2)));2880a = normalizepol_lg(a, lg(a)-1);2881da = degpol(a);2882}2883return a;2884}2885static GEN2886nfXQ_mul(GEN nf, GEN a, GEN b, GEN T)2887{2888GEN c = nfX_mul(nf, a, b);2889if (typ(c) != t_POL) return c;2890return nfX_rem(nf, c, T);2891}28922893static void2894fill(long l, GEN H, GEN Hx, GEN I, GEN Ix)2895{2896long i;2897if (typ(Ix) == t_VEC) /* standard */2898for (i=1; i<l; i++) { gel(H,i) = gel(Hx,i); gel(I,i) = gel(Ix,i); }2899else /* constant ideal */2900for (i=1; i<l; i++) { gel(H,i) = gel(Hx,i); gel(I,i) = Ix; }2901}29022903/* given MODULES x and y by their pseudo-bases, returns a pseudo-basis of the2904* module generated by x and y. */2905static GEN2906rnfjoinmodules_i(GEN nf, GEN Hx, GEN Ix, GEN Hy, GEN Iy)2907{2908long lx = lg(Hx), ly = lg(Hy), l = lx+ly-1;2909GEN H = cgetg(l, t_MAT), I = cgetg(l, t_VEC);2910fill(lx, H , Hx, I , Ix);2911fill(ly, H+lx-1, Hy, I+lx-1, Iy); return nfhnf(nf, mkvec2(H, I));2912}2913static GEN2914rnfjoinmodules(GEN nf, GEN x, GEN y)2915{2916if (!x) return y;2917if (!y) return x;2918return rnfjoinmodules_i(nf, gel(x,1), gel(x,2), gel(y,1), gel(y,2));2919}29202921typedef struct {2922GEN multab, T,p;2923long h;2924} rnfeltmod_muldata;29252926static GEN2927_sqr(void *data, GEN x)2928{2929rnfeltmod_muldata *D = (rnfeltmod_muldata *) data;2930GEN z = x? tablesqr(D->multab,x)2931: tablemul_ei_ej(D->multab,D->h,D->h);2932return FqV_red(z,D->T,D->p);2933}2934static GEN2935_msqr(void *data, GEN x)2936{2937GEN x2 = _sqr(data, x), z;2938rnfeltmod_muldata *D = (rnfeltmod_muldata *) data;2939z = tablemul_ei(D->multab, x2, D->h);2940return FqV_red(z,D->T,D->p);2941}29422943/* Compute W[h]^n mod (T,p) in the extension, assume n >= 0. T a ZX */2944static GEN2945rnfeltid_powmod(GEN multab, long h, GEN n, GEN T, GEN p)2946{2947pari_sp av = avma;2948GEN y;2949rnfeltmod_muldata D;29502951if (!signe(n)) return gen_1;29522953D.multab = multab;2954D.h = h;2955D.T = T;2956D.p = p;2957y = gen_pow_fold(NULL, n, (void*)&D, &_sqr, &_msqr);2958return gerepilecopy(av, y);2959}29602961/* P != 0 has at most degpol(P) roots. Look for an element in Fq which is not2962* a root, cf repres() */2963static GEN2964FqX_non_root(GEN P, GEN T, GEN p)2965{2966long dP = degpol(P), f, vT;2967long i, j, k, pi, pp;2968GEN v;29692970if (dP == 0) return gen_1;2971pp = is_bigint(p) ? dP+1: itos(p);2972v = cgetg(dP + 2, t_VEC);2973gel(v,1) = gen_0;2974if (T)2975{ f = degpol(T); vT = varn(T); }2976else2977{ f = 1; vT = 0; }2978for (i=pi=1; i<=f; i++,pi*=pp)2979{2980GEN gi = i == 1? gen_1: pol_xn(i-1, vT), jgi = gi;2981for (j=1; j<pp; j++)2982{2983for (k=1; k<=pi; k++)2984{2985GEN z = Fq_add(gel(v,k), jgi, T,p);2986if (!gequal0(FqX_eval(P, z, T,p))) return z;2987gel(v, j*pi+k) = z;2988}2989if (j < pp-1) jgi = Fq_add(jgi, gi, T,p); /* j*g[i] */2990}2991}2992return NULL;2993}29942995/* Relative Dedekind criterion over (true) nf, applied to the order defined by a2996* root of monic irreducible polynomial P, modulo the prime ideal pr. Assume2997* vdisc = v_pr( disc(P) ).2998* Return NULL if nf[X]/P is pr-maximal. Otherwise, return [flag, O, v]:2999* O = enlarged order, given by a pseudo-basis3000* flag = 1 if O is proven pr-maximal (may be 0 and O nevertheless pr-maximal)3001* v = v_pr(disc(O)). */3002static GEN3003rnfdedekind_i(GEN nf, GEN P, GEN pr, long vdisc, long only_maximal)3004{3005GEN Ppr, A, I, p, tau, g, h, k, base, T, gzk, hzk, prinvp, pal, nfT, modpr;3006long m, vt, r, d, i, j, mpr;30073008if (vdisc < 0) pari_err_TYPE("rnfdedekind [non integral pol]", P);3009if (vdisc == 1) return NULL; /* pr-maximal */3010if (!only_maximal && !gequal1(leading_coeff(P)))3011pari_err_IMPL( "the full Dedekind criterion in the nonmonic case");3012/* either monic OR only_maximal = 1 */3013m = degpol(P);3014nfT = nf_get_pol(nf);3015modpr = nf_to_Fq_init(nf,&pr, &T, &p);3016Ppr = nfX_to_FqX(P, nf, modpr);3017mpr = degpol(Ppr);3018if (mpr < m) /* nonmonic => only_maximal = 1 */3019{3020if (mpr < 0) return NULL;3021if (! RgX_valrem(Ppr, &Ppr))3022{ /* nonzero constant coefficient */3023Ppr = RgX_shift_shallow(RgX_recip_i(Ppr), m - mpr);3024P = RgX_recip_i(P);3025}3026else3027{3028GEN z = FqX_non_root(Ppr, T, p);3029if (!z) pari_err_IMPL( "Dedekind in the difficult case");3030z = Fq_to_nf(z, modpr);3031if (typ(z) == t_INT)3032P = RgX_translate(P, z);3033else3034P = RgXQX_translate(P, z, T);3035P = RgX_recip_i(P);3036Ppr = nfX_to_FqX(P, nf, modpr); /* degpol(P) = degpol(Ppr) = m */3037}3038}3039A = gel(FqX_factor(Ppr,T,p),1);3040r = lg(A); /* > 1 */3041g = gel(A,1);3042for (i=2; i<r; i++) g = FqX_mul(g, gel(A,i), T, p);3043h = FqX_div(Ppr,g, T, p);3044gzk = FqX_to_nfX(g, modpr);3045hzk = FqX_to_nfX(h, modpr);3046k = nfX_sub(nf, P, nfX_mul(nf, gzk,hzk));3047tau = pr_get_tau(pr);3048switch(typ(tau))3049{3050case t_INT: k = gdiv(k, p); break;3051case t_MAT: k = RgX_Rg_div(tablemulvec(NULL,tau, k), p); break;3052}3053k = nfX_to_FqX(k, nf, modpr);3054k = FqX_normalize(FqX_gcd(FqX_gcd(g,h, T,p), k, T,p), T,p);3055d = degpol(k); /* <= m */3056if (!d) return NULL; /* pr-maximal */3057if (only_maximal) return gen_0; /* not maximal */30583059A = cgetg(m+d+1,t_MAT);3060I = cgetg(m+d+1,t_VEC); base = mkvec2(A, I);3061/* base[2] temporarily multiplied by p, for the final nfhnfmod,3062* which requires integral ideals */3063prinvp = pr_inv_p(pr); /* again multiplied by p */3064for (j=1; j<=m; j++)3065{3066gel(A,j) = col_ei(m, j);3067gel(I,j) = p;3068}3069pal = FqX_to_nfX(FqX_div(Ppr,k, T,p), modpr);3070for ( ; j<=m+d; j++)3071{3072gel(A,j) = RgX_to_RgC(pal,m);3073gel(I,j) = prinvp;3074if (j < m+d) pal = RgXQX_rem(RgX_shift_shallow(pal,1),P,nfT);3075}3076/* the modulus is integral */3077base = nfhnfmod(nf,base, idealmulpowprime(nf, powiu(p,m), pr, utoineg(d)));3078gel(base,2) = gdiv(gel(base,2), p); /* cancel the factor p */3079vt = vdisc - 2*d;3080return mkvec3(vt < 2? gen_1: gen_0, base, stoi(vt));3081}30823083/* [L:K] = n */3084static GEN3085triv_order(long n)3086{3087GEN z = cgetg(3, t_VEC);3088gel(z,1) = matid(n);3089gel(z,2) = const_vec(n, gen_1); return z;3090}30913092/* if flag is set, return gen_1 (resp. gen_0) if the order K[X]/(P)3093* is pr-maximal (resp. not pr-maximal). */3094GEN3095rnfdedekind(GEN nf, GEN P, GEN pr, long flag)3096{3097pari_sp av = avma;3098GEN z, dP;3099long v;31003101nf = checknf(nf);3102P = RgX_nffix("rnfdedekind", nf_get_pol(nf), P, 1);3103dP = nfX_disc(nf, P);3104if (!pr)3105{3106GEN fa = idealfactor(nf, dP);3107GEN Q = gel(fa,1), E = gel(fa,2);3108pari_sp av2 = avma;3109long i, l = lg(Q);3110for (i = 1; i < l; i++, set_avma(av2))3111{3112v = itos(gel(E,i));3113if (rnfdedekind_i(nf,P,gel(Q,i),v,1)) { set_avma(av); return gen_0; }3114set_avma(av2);3115}3116set_avma(av); return gen_1;3117}3118else if (typ(pr) == t_VEC)3119{ /* flag = 1 is implicit */3120if (lg(pr) == 1) { set_avma(av); return gen_1; }3121if (typ(gel(pr,1)) == t_VEC)3122{ /* list of primes */3123GEN Q = pr;3124pari_sp av2 = avma;3125long i, l = lg(Q);3126for (i = 1; i < l; i++, set_avma(av2))3127{3128v = nfval(nf, dP, gel(Q,i));3129if (rnfdedekind_i(nf,P,gel(Q,i),v,1)) { set_avma(av); return gen_0; }3130}3131set_avma(av); return gen_1;3132}3133}3134/* single prime */3135v = nfval(nf, dP, pr);3136z = rnfdedekind_i(nf, P, pr, v, flag);3137if (z)3138{3139if (flag) { set_avma(av); return gen_0; }3140z = gerepilecopy(av, z);3141}3142else3143{3144set_avma(av); if (flag) return gen_1;3145z = cgetg(4, t_VEC);3146gel(z,1) = gen_1;3147gel(z,2) = triv_order(degpol(P));3148gel(z,3) = stoi(v);3149}3150return z;3151}31523153static int3154ideal_is1(GEN x) {3155switch(typ(x))3156{3157case t_INT: return is_pm1(x);3158case t_MAT: return RgM_isidentity(x);3159}3160return 0;3161}31623163/* return a in ideal A such that v_pr(a) = v_pr(A) */3164static GEN3165minval(GEN nf, GEN A, GEN pr)3166{3167GEN ab = idealtwoelt(nf,A), a = gel(ab,1), b = gel(ab,2);3168if (nfval(nf,a,pr) > nfval(nf,b,pr)) a = b;3169return a;3170}31713172/* nf a true nf. Return NULL if power order if pr-maximal */3173static GEN3174rnfmaxord(GEN nf, GEN pol, GEN pr, long vdisc)3175{3176pari_sp av = avma, av1;3177long i, j, k, n, nn, vpol, cnt, sep;3178GEN q, q1, p, T, modpr, W, I, p1;3179GEN prhinv, mpi, Id;31803181if (DEBUGLEVEL>1) err_printf(" treating %Ps^%ld\n", pr, vdisc);3182modpr = nf_to_Fq_init(nf,&pr,&T,&p);3183av1 = avma;3184p1 = rnfdedekind_i(nf, pol, modpr, vdisc, 0);3185if (!p1) return gc_NULL(av);3186if (is_pm1(gel(p1,1))) return gerepilecopy(av,gel(p1,2));3187sep = itos(gel(p1,3));3188W = gmael(p1,2,1);3189I = gmael(p1,2,2);3190gerepileall(av1, 2, &W, &I);31913192mpi = zk_multable(nf, pr_get_gen(pr));3193n = degpol(pol); nn = n*n;3194vpol = varn(pol);3195q1 = q = pr_norm(pr);3196while (abscmpiu(q1,n) < 0) q1 = mulii(q1,q);3197Id = matid(n);3198prhinv = pr_inv(pr);3199av1 = avma;3200for(cnt=1;; cnt++)3201{3202GEN I0 = leafcopy(I), W0 = leafcopy(W);3203GEN Wa, Winv, Ip, A, MW, MWmod, F, pseudo, C, G;3204GEN Tauinv = cgetg(n+1, t_VEC), Tau = cgetg(n+1, t_VEC);32053206if (DEBUGLEVEL>1) err_printf(" pass no %ld\n",cnt);3207for (j=1; j<=n; j++)3208{3209GEN tau, tauinv;3210if (ideal_is1(gel(I,j)))3211{3212gel(I,j) = gel(Tau,j) = gel(Tauinv,j) = gen_1;3213continue;3214}3215gel(Tau,j) = tau = minval(nf, gel(I,j), pr);3216gel(Tauinv,j) = tauinv = nfinv(nf, tau);3217gel(W,j) = nfC_nf_mul(nf, gel(W,j), tau);3218gel(I,j) = idealmul(nf, tauinv, gel(I,j)); /* v_pr(I[j]) = 0 */3219}3220/* W = (Z_K/pr)-basis of O/pr. O = (W0,I0) ~ (W, I) */32213222/* compute MW: W_i*W_j = sum MW_k,(i,j) W_k */3223Wa = RgM_to_RgXV(W,vpol);3224Winv = nfM_inv(nf, W);3225MW = cgetg(nn+1, t_MAT);3226/* W_1 = 1 */3227for (j=1; j<=n; j++) gel(MW, j) = gel(MW, (j-1)*n+1) = gel(Id,j);3228for (i=2; i<=n; i++)3229for (j=i; j<=n; j++)3230{3231GEN z = nfXQ_mul(nf, gel(Wa,i), gel(Wa,j), pol);3232if (typ(z) != t_POL)3233z = nfC_nf_mul(nf, gel(Winv,1), z);3234else3235{3236z = RgX_to_RgC(z, lg(Winv)-1);3237z = nfM_nfC_mul(nf, Winv, z);3238}3239gel(MW, (i-1)*n+j) = gel(MW, (j-1)*n+i) = z;3240}32413242/* compute Ip = pr-radical [ could use Ker(trace) if q large ] */3243MWmod = nfM_to_FqM(MW,nf,modpr);3244F = cgetg(n+1, t_MAT); gel(F,1) = gel(Id,1);3245for (j=2; j<=n; j++) gel(F,j) = rnfeltid_powmod(MWmod, j, q1, T,p);3246Ip = FqM_ker(F,T,p);3247if (lg(Ip) == 1) { W = W0; I = I0; break; }32483249/* Fill C: W_k A_j = sum_i C_(i,j),k A_i */3250A = FqM_to_nfM(FqM_suppl(Ip,T,p), modpr);3251for (j = lg(Ip); j<=n; j++) gel(A,j) = nfC_multable_mul(gel(A,j), mpi);3252MW = nfM_mul(nf, nfM_inv(nf,A), MW);3253C = cgetg(n+1, t_MAT);3254for (k=1; k<=n; k++)3255{3256GEN mek = vecslice(MW, (k-1)*n+1, k*n), Ck;3257gel(C,k) = Ck = cgetg(nn+1, t_COL);3258for (j=1; j<=n; j++)3259{3260GEN z = nfM_nfC_mul(nf, mek, gel(A,j));3261for (i=1; i<=n; i++) gel(Ck, (j-1)*n+i) = nf_to_Fq(nf,gel(z,i),modpr);3262}3263}3264G = FqM_to_nfM(FqM_ker(C,T,p), modpr);32653266pseudo = rnfjoinmodules_i(nf, G,prhinv, Id,I);3267/* express W in terms of the power basis */3268W = nfM_mul(nf, W, gel(pseudo,1));3269I = gel(pseudo,2);3270/* restore the HNF property W[i,i] = 1. NB: W upper triangular, with3271* W[i,i] = Tau[i] */3272for (j=1; j<=n; j++)3273if (gel(Tau,j) != gen_1)3274{3275gel(W,j) = nfC_nf_mul(nf, gel(W,j), gel(Tauinv,j));3276gel(I,j) = idealmul(nf, gel(Tau,j), gel(I,j));3277}3278if (DEBUGLEVEL>3) err_printf(" new order:\n%Ps\n%Ps\n", W, I);3279if (sep <= 3 || gequal(I,I0)) break;32803281if (gc_needed(av1,2))3282{3283if(DEBUGMEM>1) pari_warn(warnmem,"rnfmaxord");3284gerepileall(av1,2, &W,&I);3285}3286}3287return gerepilecopy(av, mkvec2(W, I));3288}32893290GEN3291Rg_nffix(const char *f, GEN T, GEN c, int lift)3292{3293switch(typ(c))3294{3295case t_INT: case t_FRAC: return c;3296case t_POL:3297if (lg(c) >= lg(T)) c = RgX_rem(c,T);3298break;3299case t_POLMOD:3300if (!RgX_equal_var(gel(c,1), T)) pari_err_MODULUS(f, gel(c,1),T);3301c = gel(c,2);3302switch(typ(c))3303{3304case t_POL: break;3305case t_INT: case t_FRAC: return c;3306default: pari_err_TYPE(f, c);3307}3308break;3309default: pari_err_TYPE(f,c);3310}3311/* typ(c) = t_POL */3312if (varn(c) != varn(T)) pari_err_VAR(f, c,T);3313switch(lg(c))3314{3315case 2: return gen_0;3316case 3:3317c = gel(c,2); if (is_rational_t(typ(c))) return c;3318pari_err_TYPE(f,c);3319}3320RgX_check_QX(c, f);3321return lift? c: mkpolmod(c, T);3322}3323/* check whether P is a polynomials with coeffs in number field Q[y]/(T) */3324GEN3325RgX_nffix(const char *f, GEN T, GEN P, int lift)3326{3327long i, l, vT = varn(T);3328GEN Q = cgetg_copy(P, &l);3329if (typ(P) != t_POL) pari_err_TYPE(stack_strcat(f," [t_POL expected]"), P);3330if (varncmp(varn(P), vT) >= 0) pari_err_PRIORITY(f, P, ">=", vT);3331Q[1] = P[1];3332for (i=2; i<l; i++) gel(Q,i) = Rg_nffix(f, T, gel(P,i), lift);3333return normalizepol_lg(Q, l);3334}3335GEN3336RgV_nffix(const char *f, GEN T, GEN P, int lift)3337{3338long i, l;3339GEN Q = cgetg_copy(P, &l);3340for (i=1; i<l; i++) gel(Q,i) = Rg_nffix(f, T, gel(P,i), lift);3341return Q;3342}33433344static GEN3345get_d(GEN nf, GEN d)3346{3347GEN b = idealredmodpower(nf, d, 2, 100000);3348return nfmul(nf, d, nfsqr(nf,b));3349}33503351static GEN3352pr_factorback(GEN nf, GEN fa)3353{3354GEN P = gel(fa,1), E = gel(fa,2), z = gen_1;3355long i, l = lg(P);3356for (i = 1; i < l; i++) z = idealmulpowprime(nf, z, gel(P,i), gel(E,i));3357return z;3358}3359static GEN3360pr_factorback_scal(GEN nf, GEN fa)3361{3362GEN D = pr_factorback(nf,fa);3363if (typ(D) == t_MAT && RgM_isscalar(D,NULL)) D = gcoeff(D,1,1);3364return D;3365}33663367/* nf = base field K3368* pol= monic polynomial in Z_K[X] defining a relative extension L = K[X]/(pol).3369* Returns a pseudo-basis [A,I] of Z_L, set *pD to [D,d] and *pf to the3370* index-ideal; rnf is used when lim != 0 and may be NULL */3371GEN3372rnfallbase(GEN nf, GEN pol, GEN lim, GEN rnf, GEN *pD, GEN *pf, GEN *pDKP)3373{3374long i, j, jf, l;3375GEN fa, E, P, Ef, Pf, z, disc;33763377nf = checknf(nf); pol = liftpol_shallow(pol);3378if (!gequal1(leading_coeff(pol)))3379pari_err_IMPL("nonmonic relative polynomials in rnfallbase");3380disc = nf_to_scalar_or_basis(nf, nfX_disc(nf, pol));3381if (lim)3382{3383GEN rnfeq, zknf, dzknf, U, vU, dA, A, MB, dB, BdB, vj, B, Tabs;3384GEN D = idealhnf(nf, disc);3385long rU, m = nf_get_degree(nf), n = degpol(pol), N = n*m;3386nfmaxord_t S;33873388if (typ(lim) == t_INT)3389P = ZV_union_shallow(nf_get_ramified_primes(nf),3390gel(Z_factor_limit(gcoeff(D,1,1), itou(lim)), 1));3391else3392{3393P = cgetg_copy(lim, &l);3394for (i = 1; i < l; i++)3395{3396GEN p = gel(lim,i);3397if (typ(p) != t_INT) p = pr_get_p(p);3398gel(P,i) = p;3399}3400P = ZV_sort_uniq(P);3401}3402if (rnf)3403{3404rnfeq = rnf_get_map(rnf);3405zknf = rnf_get_nfzk(rnf);3406}3407else3408{3409rnfeq = nf_rnfeq(nf, pol);3410zknf = nf_nfzk(nf, rnfeq);3411}3412dzknf = gel(zknf,1);3413if (gequal1(dzknf)) dzknf = NULL;3414Tabs = gel(rnfeq,1);3415nfmaxord(&S, mkvec2(Tabs,P), 0);3416B = RgXV_unscale(S.basis, S.unscale);3417BdB = Q_remove_denom(B, &dB);3418MB = RgXV_to_RgM(BdB, N); /* HNF */34193420vU = cgetg(N+1, t_VEC);3421vj = cgetg(N+1, t_VECSMALL);3422gel(vU,1) = U = cgetg(m+1, t_MAT);3423gel(U,1) = col_ei(N, 1);3424A = dB? (dzknf? gdiv(dB,dzknf): dB): NULL;3425if (A && gequal1(A)) A = NULL;3426for (j = 2; j <= m; j++)3427{3428GEN t = gel(zknf,j);3429if (A) t = ZX_Z_mul(t, A);3430gel(U,j) = hnf_solve(MB, RgX_to_RgC(t, N));3431}3432for (i = 2; i <= N; i++)3433{3434GEN b = gel(BdB,i);3435gel(vU,i) = U = cgetg(m+1, t_MAT);3436gel(U,1) = hnf_solve(MB, RgX_to_RgC(b, N));3437for (j = 2; j <= m; j++)3438{3439GEN t = ZX_rem(ZX_mul(b, gel(zknf,j)), Tabs);3440if (dzknf) t = gdiv(t, dzknf);3441gel(U,j) = hnf_solve(MB, RgX_to_RgC(t, N));3442}3443}3444vj[1] = 1; U = gel(vU,1); rU = m;3445for (i = j = 2; i <= N; i++)3446{3447GEN V = shallowconcat(U, gel(vU,i));3448if (ZM_rank(V) != rU)3449{3450U = V; rU += m; vj[j++] = i;3451if (rU == N) break;3452}3453}3454if (dB) for(;;)3455{3456GEN c = gen_1, H = ZM_hnfmodid(U, dB);3457long ic = 0;3458for (i = 1; i <= N; i++)3459if (cmpii(gcoeff(H,i,i), c) > 0) { c = gcoeff(H,i,i); ic = i; }3460if (!ic) break;3461vj[j++] = ic;3462U = shallowconcat(H, gel(vU, ic));3463}3464setlg(vj, j);3465B = vecpermute(B, vj);34663467l = lg(B);3468A = cgetg(l,t_MAT);3469for (j = 1; j < l; j++)3470{3471GEN t = eltabstorel_lift(rnfeq, gel(B,j));3472gel(A,j) = Rg_to_RgC(t, n);3473}3474A = RgM_to_nfM(nf, A);3475A = Q_remove_denom(A, &dA);3476if (!dA)3477{ /* order is maximal */3478z = triv_order(n);3479if (pf) *pf = gen_1;3480}3481else3482{3483GEN fi;3484/* the first n columns of A are probably in HNF already */3485A = shallowconcat(vecslice(A,n+1,lg(A)-1), vecslice(A,1,n));3486A = mkvec2(A, const_vec(l-1,gen_1));3487if (DEBUGLEVEL > 2) err_printf("rnfallbase: nfhnf in dim %ld\n", l-1);3488z = nfhnfmod(nf, A, nfdetint(nf,A));3489gel(z,2) = gdiv(gel(z,2), dA);3490fi = idealprod(nf,gel(z,2));3491D = idealmul(nf, D, idealsqr(nf, fi));3492if (pf) *pf = idealinv(nf, fi);3493}3494if (RgM_isscalar(D,NULL)) D = gcoeff(D,1,1);3495if (pDKP) { settyp(S.dKP, t_VEC); *pDKP = S.dKP; }3496*pD = mkvec2(D, get_d(nf, disc)); return z;3497}3498fa = idealfactor(nf, disc);3499P = gel(fa,1); l = lg(P); z = NULL;3500E = gel(fa,2);3501Pf = cgetg(l, t_COL);3502Ef = cgetg(l, t_COL);3503for (i = j = jf = 1; i < l; i++)3504{3505GEN pr = gel(P,i);3506long e = itos(gel(E,i));3507if (e > 1)3508{3509GEN vD = rnfmaxord(nf, pol, pr, e);3510if (vD)3511{3512long ef = idealprodval(nf, gel(vD,2), pr);3513z = rnfjoinmodules(nf, z, vD);3514if (ef) { gel(Pf, jf) = pr; gel(Ef, jf++) = stoi(-ef); }3515e += 2 * ef;3516}3517}3518if (e) { gel(P, j) = pr; gel(E, j++) = stoi(e); }3519}3520setlg(P,j);3521setlg(E,j);3522if (pDKP)3523{3524GEN v = cgetg(j, t_VEC);3525for (i = 1; i < j; i++) gel(v,i) = pr_get_p(gel(P,i));3526*pDKP = ZV_sort_uniq(v);3527}3528if (pf)3529{3530setlg(Pf, jf);3531setlg(Ef, jf); *pf = pr_factorback_scal(nf, mkmat2(Pf,Ef));3532}3533*pD = mkvec2(pr_factorback_scal(nf,fa), get_d(nf, disc));3534return z? z: triv_order(degpol(pol));3535}35363537static GEN3538RgX_to_algX(GEN nf, GEN x)3539{3540long i, l;3541GEN y = cgetg_copy(x, &l); y[1] = x[1];3542for (i=2; i<l; i++) gel(y,i) = nf_to_scalar_or_alg(nf, gel(x,i));3543return y;3544}35453546GEN3547nfX_to_monic(GEN nf, GEN T, GEN *pL)3548{3549GEN lT, g, a;3550long i, l = lg(T);3551if (l == 2) return pol_0(varn(T));3552if (l == 3) return pol_1(varn(T));3553nf = checknf(nf);3554T = Q_primpart(RgX_to_nfX(nf, T));3555lT = leading_coeff(T); if (pL) *pL = lT;3556if (isint1(T)) return T;3557g = cgetg_copy(T, &l); g[1] = T[1]; a = lT;3558gel(g, l-1) = gen_1;3559gel(g, l-2) = gel(T,l-2);3560if (l == 4) return g;3561if (typ(lT) == t_INT)3562{3563gel(g, l-3) = gmul(a, gel(T,l-3));3564for (i = l-4; i > 1; i--) { a = mulii(a,lT); gel(g,i) = gmul(a, gel(T,i)); }3565}3566else3567{3568gel(g, l-3) = nfmul(nf, a, gel(T,l-3));3569for (i = l-3; i > 1; i--)3570{3571a = nfmul(nf,a,lT);3572gel(g,i) = nfmul(nf, a, gel(T,i));3573}3574}3575return RgX_to_algX(nf, g);3576}35773578GEN3579rnfdisc_factored(GEN nf, GEN pol, GEN *pd)3580{3581long i, j, l;3582GEN fa, E, P, disc, lim;35833584nf = checknf(nf);3585pol = rnfdisc_get_T(nf, pol, &lim);3586disc = nf_to_scalar_or_basis(nf, nfX_disc(nf, pol));3587pol = nfX_to_monic(nf, pol, NULL);3588fa = idealfactor_partial(nf, disc, lim);3589P = gel(fa,1); l = lg(P);3590E = gel(fa,2);3591for (i = j = 1; i < l; i++)3592{3593long e = itos(gel(E,i));3594GEN pr = gel(P,i);3595if (e > 1)3596{3597GEN vD = rnfmaxord(nf, pol, pr, e);3598if (vD) e += 2*idealprodval(nf, gel(vD,2), pr);3599}3600if (e) { gel(P, j) = pr; gel(E, j++) = stoi(e); }3601}3602if (pd) *pd = get_d(nf, disc);3603setlg(P, j);3604setlg(E, j); return fa;3605}3606GEN3607rnfdiscf(GEN nf, GEN pol)3608{3609pari_sp av = avma;3610GEN d, fa = rnfdisc_factored(nf, pol, &d);3611return gerepilecopy(av, mkvec2(pr_factorback_scal(nf,fa), d));3612}36133614GEN3615gen_if_principal(GEN bnf, GEN x)3616{3617pari_sp av = avma;3618GEN z = bnfisprincipal0(bnf,x, nf_GEN_IF_PRINCIPAL | nf_FORCE);3619return isintzero(z)? gc_NULL(av): z;3620}36213622static int3623is_pseudo_matrix(GEN O)3624{3625return (typ(O) ==t_VEC && lg(O) >= 33626&& typ(gel(O,1)) == t_MAT3627&& typ(gel(O,2)) == t_VEC3628&& lgcols(O) == lg(gel(O,2)));3629}36303631/* given bnf and a pseudo-basis of an order in HNF [A,I], tries to simplify3632* the HNF as much as possible. The resulting matrix will be upper triangular3633* but the diagonal coefficients will not be equal to 1. The ideals are3634* guaranteed to be integral and primitive. */3635GEN3636rnfsimplifybasis(GEN bnf, GEN x)3637{3638pari_sp av = avma;3639long i, l;3640GEN y, Az, Iz, nf, A, I;36413642bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);3643if (!is_pseudo_matrix(x)) pari_err_TYPE("rnfsimplifybasis",x);3644A = gel(x,1);3645I = gel(x,2); l = lg(I);3646y = cgetg(3, t_VEC);3647Az = cgetg(l, t_MAT); gel(y,1) = Az;3648Iz = cgetg(l, t_VEC); gel(y,2) = Iz;3649for (i = 1; i < l; i++)3650{3651GEN c, d;3652if (ideal_is1(gel(I,i))) {3653gel(Iz,i) = gen_1;3654gel(Az,i) = gel(A,i);3655continue;3656}36573658gel(Iz,i) = Q_primitive_part(gel(I,i), &c);3659gel(Az,i) = c? RgC_Rg_mul(gel(A,i),c): gel(A,i);3660if (c && ideal_is1(gel(Iz,i))) continue;36613662d = gen_if_principal(bnf, gel(Iz,i));3663if (d)3664{3665gel(Iz,i) = gen_1;3666gel(Az,i) = nfC_nf_mul(nf, gel(Az,i), d);3667}3668}3669return gerepilecopy(av, y);3670}36713672static GEN3673get_order(GEN nf, GEN O, const char *s)3674{3675if (typ(O) == t_POL)3676return rnfpseudobasis(nf, O);3677if (!is_pseudo_matrix(O)) pari_err_TYPE(s, O);3678return O;3679}36803681GEN3682rnfdet(GEN nf, GEN order)3683{3684pari_sp av = avma;3685GEN A, I, D;3686nf = checknf(nf);3687order = get_order(nf, order, "rnfdet");3688A = gel(order,1);3689I = gel(order,2);3690D = idealmul(nf, nfM_det(nf,A), idealprod(nf,I));3691return gerepileupto(av, D);3692}36933694/* Given two fractional ideals a and b, gives x in a, y in b, z in b^-1,3695t in a^-1 such that xt-yz=1. In the present version, z is in Z. */3696static void3697nfidealdet1(GEN nf, GEN a, GEN b, GEN *px, GEN *py, GEN *pz, GEN *pt)3698{3699GEN x, uv, y, da, db;37003701a = idealinv(nf,a);3702a = Q_remove_denom(a, &da);3703b = Q_remove_denom(b, &db);3704x = idealcoprime(nf,a,b);3705uv = idealaddtoone(nf, idealmul(nf,x,a), b);3706y = gel(uv,2);3707if (da) x = gmul(x,da);3708if (db) y = gdiv(y,db);3709*px = x;3710*py = y;3711*pz = db ? negi(db): gen_m1;3712*pt = nfdiv(nf, gel(uv,1), x);3713}37143715/* given a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d]), gives an3716* n x n matrix (not in HNF) of a pseudo-basis and an ideal vector3717* [1,1,...,1,I] such that order = Z_K^(n-1) x I.3718* Uses the approximation theorem ==> slow. */3719GEN3720rnfsteinitz(GEN nf, GEN order)3721{3722pari_sp av = avma;3723long i, n, l;3724GEN A, I, p1;37253726nf = checknf(nf);3727order = get_order(nf, order, "rnfsteinitz");3728A = RgM_to_nfM(nf, gel(order,1));3729I = leafcopy(gel(order,2)); n=lg(A)-1;3730for (i=1; i<n; i++)3731{3732GEN c1, c2, b, a = gel(I,i);3733gel(I,i) = gen_1;3734if (ideal_is1(a)) continue;37353736c1 = gel(A,i);3737c2 = gel(A,i+1);3738b = gel(I,i+1);3739if (ideal_is1(b))3740{3741gel(A,i) = c2;3742gel(A,i+1) = gneg(c1);3743gel(I,i+1) = a;3744}3745else3746{3747pari_sp av2 = avma;3748GEN x, y, z, t;3749nfidealdet1(nf,a,b, &x,&y,&z,&t);3750x = RgC_add(nfC_nf_mul(nf, c1, x), nfC_nf_mul(nf, c2, y));3751y = RgC_add(nfC_nf_mul(nf, c1, z), nfC_nf_mul(nf, c2, t));3752gerepileall(av2, 2, &x,&y);3753gel(A,i) = x;3754gel(A,i+1) = y;3755gel(I,i+1) = Q_primitive_part(idealmul(nf,a,b), &p1);3756if (p1) gel(A,i+1) = nfC_nf_mul(nf, gel(A,i+1), p1);3757}3758}3759l = lg(order);3760p1 = cgetg(l,t_VEC);3761gel(p1,1) = A;3762gel(p1,2) = I; for (i=3; i<l; i++) gel(p1,i) = gel(order,i);3763return gerepilecopy(av, p1);3764}37653766/* Given bnf and either an order as output by rnfpseudobasis or a polynomial,3767* and outputs a basis if it is free, an n+1-generating set if it is not */3768GEN3769rnfbasis(GEN bnf, GEN order)3770{3771pari_sp av = avma;3772long j, n;3773GEN nf, A, I, cl, col, a;37743775bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);3776order = get_order(nf, order, "rnfbasis");3777I = gel(order,2); n = lg(I)-1;3778j=1; while (j<n && ideal_is1(gel(I,j))) j++;3779if (j<n)3780{3781order = rnfsteinitz(nf,order);3782I = gel(order,2);3783}3784A = gel(order,1);3785col= gel(A,n); A = vecslice(A, 1, n-1);3786cl = gel(I,n);3787a = gen_if_principal(bnf, cl);3788if (!a)3789{3790GEN v = idealtwoelt(nf, cl);3791A = shallowconcat(A, gmul(gel(v,1), col));3792a = gel(v,2);3793}3794A = shallowconcat(A, nfC_nf_mul(nf, col, a));3795return gerepilecopy(av, A);3796}37973798/* Given bnf and either an order as output by rnfpseudobasis or a polynomial,3799* and outputs a basis (not pseudo) in Hermite Normal Form if it exists, zero3800* if not3801*/3802GEN3803rnfhnfbasis(GEN bnf, GEN order)3804{3805pari_sp av = avma;3806long j, n;3807GEN nf, A, I, a;38083809bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);3810order = get_order(nf, order, "rnfbasis");3811A = gel(order,1); A = RgM_shallowcopy(A);3812I = gel(order,2); n = lg(A)-1;3813for (j=1; j<=n; j++)3814{3815if (ideal_is1(gel(I,j))) continue;3816a = gen_if_principal(bnf, gel(I,j));3817if (!a) { set_avma(av); return gen_0; }3818gel(A,j) = nfC_nf_mul(nf, gel(A,j), a);3819}3820return gerepilecopy(av,A);3821}38223823static long3824rnfisfree_aux(GEN bnf, GEN order)3825{3826long n, j;3827GEN nf, P, I;38283829bnf = checkbnf(bnf);3830if (is_pm1( bnf_get_no(bnf) )) return 1;3831nf = bnf_get_nf(bnf);3832order = get_order(nf, order, "rnfisfree");3833I = gel(order,2); n = lg(I)-1;3834j=1; while (j<=n && ideal_is1(gel(I,j))) j++;3835if (j>n) return 1;38363837P = gel(I,j);3838for (j++; j<=n; j++)3839if (!ideal_is1(gel(I,j))) P = idealmul(nf,P,gel(I,j));3840return gequal0( isprincipal(bnf,P) );3841}38423843long3844rnfisfree(GEN bnf, GEN order)3845{ pari_sp av = avma; return gc_long(av, rnfisfree_aux(bnf,order)); }38463847/**********************************************************************/3848/** **/3849/** COMPOSITUM OF TWO NUMBER FIELDS **/3850/** **/3851/**********************************************************************/3852static GEN3853compositum_fix(GEN nf, GEN A)3854{3855int ok;3856if (nf)3857{3858A = Q_primpart(liftpol_shallow(A)); RgX_check_ZXX(A,"polcompositum");3859ok = nfissquarefree(nf,A);3860}3861else3862{3863A = Q_primpart(A); RgX_check_ZX(A,"polcompositum");3864ok = ZX_is_squarefree(A);3865}3866if (!ok) pari_err_DOMAIN("polcompositum","issquarefree(arg)","=",gen_0,A);3867return A;3868}3869#define next_lambda(a) (a>0 ? -a : 1-a)38703871static long3872nfcompositum_lambda(GEN nf, GEN A, GEN B, long lambda)3873{3874pari_sp av = avma;3875forprime_t S;3876GEN T = nf_get_pol(nf);3877long vT = varn(T);3878ulong p;3879init_modular_big(&S);3880p = u_forprime_next(&S);3881while (1)3882{3883GEN Hp, Tp, a;3884if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda);3885a = ZXX_to_FlxX(RgX_rescale(A, stoi(-lambda)), p, vT);3886Tp = ZX_to_Flx(T, p);3887Hp = FlxqX_direct_compositum(a, ZXX_to_FlxX(B, p, vT), Tp, p);3888if (!FlxqX_is_squarefree(Hp, Tp, p))3889{ lambda = next_lambda(lambda); continue; }3890if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda);3891return gc_long(av, lambda);3892}3893}38943895/* modular version */3896GEN3897nfcompositum(GEN nf, GEN A, GEN B, long flag)3898{3899pari_sp av = avma;3900int same;3901long v, k;3902GEN C, D, LPRS;39033904if (typ(A)!=t_POL) pari_err_TYPE("polcompositum",A);3905if (typ(B)!=t_POL) pari_err_TYPE("polcompositum",B);3906if (degpol(A)<=0 || degpol(B)<=0) pari_err_CONSTPOL("polcompositum");3907v = varn(A);3908if (varn(B) != v) pari_err_VAR("polcompositum", A,B);3909if (nf)3910{3911nf = checknf(nf);3912if (varncmp(v,nf_get_varn(nf))>=0) pari_err_PRIORITY("polcompositum", nf, ">=", v);3913}3914same = (A == B || RgX_equal(A,B));3915A = compositum_fix(nf,A);3916B = same ? A: compositum_fix(nf,B);39173918D = LPRS = NULL; /* -Wall */3919k = same? -1: 1;3920if (nf)3921{3922long v0 = fetch_var();3923GEN q, T = nf_get_pol(nf);3924A = liftpol_shallow(A);3925B = liftpol_shallow(B);3926k = nfcompositum_lambda(nf, A, B, k);3927if (flag&1)3928{3929GEN H0, H1;3930GEN chgvar = deg1pol_shallow(stoi(k),pol_x(v0),v);3931GEN B1 = poleval(QXQX_to_mod_shallow(B, T), chgvar);3932C = RgX_resultant_all(QXQX_to_mod_shallow(A, T), B1, &q);3933C = gsubst(C,v0,pol_x(v));3934C = lift_if_rational(C);3935H0 = gsubst(gel(q,2),v0,pol_x(v));3936H1 = gsubst(gel(q,3),v0,pol_x(v));3937if (typ(H0) != t_POL) H0 = scalarpol_shallow(H0,v);3938if (typ(H1) != t_POL) H1 = scalarpol_shallow(H1,v);3939H0 = lift_if_rational(H0);3940H1 = lift_if_rational(H1);3941LPRS = mkvec2(H0,H1);3942}3943else3944{3945C = nf_direct_compositum(nf, RgX_rescale(A,stoi(-k)), B);3946setvarn(C, v); C = QXQX_to_mod_shallow(C, T);3947}3948}3949else3950{3951B = leafcopy(B); setvarn(B,fetch_var_higher());3952C = (flag&1)? ZX_ZXY_resultant_all(A, B, &k, &LPRS)3953: ZX_compositum(A, B, &k);3954setvarn(C, v);3955}3956/* C = Res_Y (A(Y), B(X + kY)) guaranteed squarefree */3957if (flag & 2)3958C = mkvec(C);3959else3960{3961if (same)3962{3963D = RgX_rescale(A, stoi(1 - k));3964if (nf) D = QXQX_to_mod_shallow(D, nf_get_pol(nf));3965C = RgX_div(C, D);3966if (degpol(C) <= 0)3967C = mkvec(D);3968else3969C = shallowconcat(nf? gel(nffactor(nf,C),1): ZX_DDF(C), D);3970}3971else3972C = nf? gel(nffactor(nf,C),1): ZX_DDF(C);3973}3974gen_sort_inplace(C, (void*)(nf?&cmp_RgX: &cmpii), &gen_cmp_RgX, NULL);3975if (flag&1)3976{ /* a,b,c root of A,B,C = compositum, c = b - k a */3977long i, l = lg(C);3978GEN a, b, mH0 = RgX_neg(gel(LPRS,1)), H1 = gel(LPRS,2);3979setvarn(mH0,v);3980setvarn(H1,v);3981for (i=1; i<l; i++)3982{3983GEN D = gel(C,i);3984a = RgXQ_mul(mH0, nf? RgXQ_inv(H1,D): QXQ_inv(H1,D), D);3985b = gadd(pol_x(v), gmulsg(k,a));3986if (degpol(D) == 1) b = RgX_rem(b,D);3987gel(C,i) = mkvec4(D, mkpolmod(a,D), mkpolmod(b,D), stoi(-k));3988}3989}3990(void)delete_var();3991settyp(C, t_VEC);3992if (flag&2) C = gel(C,1);3993return gerepilecopy(av, C);3994}3995GEN3996polcompositum0(GEN A, GEN B, long flag)3997{ return nfcompositum(NULL,A,B,flag); }39983999GEN4000compositum(GEN pol1,GEN pol2) { return polcompositum0(pol1,pol2,0); }4001GEN4002compositum2(GEN pol1,GEN pol2) { return polcompositum0(pol1,pol2,1); }400340044005