Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314/**************************************************************/15/* */16/* NUMBER FIELDS */17/* */18/**************************************************************/19#include "pari.h"20#include "paripriv.h"2122#define DEBUGLEVEL DEBUGLEVEL_nf2324int new_galois_format = 0;2526/* v a t_VEC, lg(v) = 13, sanity check for true rnf */27static int28v13checkrnf(GEN v)29{ return typ(gel(v,6)) == t_VEC; }30static int31rawcheckbnf(GEN v) { return typ(v)==t_VEC && lg(v)==11; }32static int33rawchecknf(GEN v) { return typ(v)==t_VEC && lg(v)==10; }34/* v a t_VEC, lg(v) = 11, sanity check for true bnf */35static int36v11checkbnf(GEN v) { return rawchecknf(bnf_get_nf(v)); }37/* v a t_VEC, lg(v) = 10, sanity check for true nf */38static int39v10checknf(GEN v) { return typ(gel(v,1))==t_POL; }40/* v a t_VEC, lg(v) = 9, sanity check for true gal */41static int42v9checkgal(GEN v)43{ GEN x = gel(v,2); return typ(x) == t_VEC && lg(x) == 4; }4445int46checkrnf_i(GEN rnf)47{ return (typ(rnf)==t_VEC && lg(rnf)==13 && v13checkrnf(rnf)); }4849void50checkrnf(GEN rnf)51{ if (!checkrnf_i(rnf)) pari_err_TYPE("checkrnf",rnf); }5253GEN54checkbnf_i(GEN X)55{56if (typ(X) == t_VEC)57switch (lg(X))58{59case 11:60if (typ(gel(X,6)) != t_INT) return NULL; /* pre-2.2.4 format */61if (lg(gel(X,10)) != 4) return NULL; /* pre-2.8.1 format */62return X;63case 7: return checkbnf_i(bnr_get_bnf(X));64}65return NULL;66}6768GEN69checknf_i(GEN X)70{71if (typ(X)==t_VEC)72switch(lg(X))73{74case 10: return X;75case 11: return checknf_i(bnf_get_nf(X));76case 7: return checknf_i(bnr_get_bnf(X));77case 3: if (typ(gel(X,2)) == t_POLMOD) return checknf_i(gel(X,1));78}79return NULL;80}8182GEN83checkbnf(GEN x)84{85GEN bnf = checkbnf_i(x);86if (!bnf) pari_err_TYPE("checkbnf [please apply bnfinit()]",x);87return bnf;88}8990GEN91checknf(GEN x)92{93GEN nf = checknf_i(x);94if (!nf) pari_err_TYPE("checknf [please apply nfinit()]",x);95return nf;96}9798GEN99checkbnr_i(GEN bnr)100{101if (typ(bnr)!=t_VEC || lg(bnr)!=7 || !checkbnf_i(bnr_get_bnf(bnr)))102return NULL;103return bnr;104}105void106checkbnr(GEN bnr)107{108if (!checkbnr_i(bnr))109pari_err_TYPE("checkbnr [please apply bnrinit()]",bnr);110}111112void113checksqmat(GEN x, long N)114{115if (typ(x)!=t_MAT) pari_err_TYPE("checksqmat",x);116if (lg(x) == 1 || lgcols(x) != N+1) pari_err_DIM("checksqmat");117}118119GEN120checkbid_i(GEN bid)121{122GEN f;123if (typ(bid)!=t_VEC || lg(bid)!=6 || typ(bid_get_U(bid)) != t_VEC)124return NULL;125f = bid_get_mod(bid);126if (typ(f)!=t_VEC || lg(f)!=3) return NULL;127return bid;128}129void130checkbid(GEN bid)131{132if (!checkbid_i(bid)) pari_err_TYPE("checkbid",bid);133}134void135checkabgrp(GEN v)136{137if (typ(v) == t_VEC) switch(lg(v))138{139case 4: if (typ(gel(v,3)) != t_VEC) break;140case 3: if (typ(gel(v,2)) != t_VEC) break;141if (typ(gel(v,1)) != t_INT) break;142return;/*OK*/143default: break;144}145pari_err_TYPE("checkabgrp",v);146}147148GEN149checknfelt_mod(GEN nf, GEN x, const char *s)150{151GEN T = gel(x,1), a = gel(x,2), Tnf = nf_get_pol(nf);152if (!RgX_equal_var(T, Tnf)) pari_err_MODULUS(s, T, Tnf);153return a;154}155156void157check_ZKmodule(GEN x, const char *s)158{159if (typ(x) != t_VEC || lg(x) < 3) pari_err_TYPE(s,x);160if (typ(gel(x,1)) != t_MAT) pari_err_TYPE(s,gel(x,1));161if (typ(gel(x,2)) != t_VEC) pari_err_TYPE(s,gel(x,2));162if (lg(gel(x,2)) != lgcols(x)) pari_err_DIM(s);163}164165static long166typv6(GEN x)167{168if (typ(gel(x,1)) == t_VEC && lg(gel(x,3)) == 3)169{170GEN t = gel(x,3);171if (typ(t) != t_VEC) return typ_NULL;172t = gel(x,5);173switch(typ(gel(x,5)))174{175case t_VEC: return typ_BID;176case t_MAT: return typ_BIDZ;177default: return typ_NULL;178}179}180if (typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT) return typ_PRID;181return typ_NULL;182}183184GEN185get_bnf(GEN x, long *t)186{187switch(typ(x))188{189case t_POL: *t = typ_POL; return NULL;190case t_QUAD: *t = typ_Q ; return NULL;191case t_VEC:192switch(lg(x))193{194case 5: if (typ(gel(x,1)) != t_INT) break;195*t = typ_QUA; return NULL;196case 6: *t = typv6(x); return NULL;197case 7: *t = typ_BNR;198x = bnr_get_bnf(x);199if (!rawcheckbnf(x)) break;200return x;201case 9:202if (!v9checkgal(x)) break;203*t = typ_GAL; return NULL;204case 10:205if (!v10checknf(x)) break;206*t = typ_NF; return NULL;207case 11:208if (!v11checkbnf(x)) break;209*t = typ_BNF; return x;210case 13:211if (!v13checkrnf(x)) break;212*t = typ_RNF; return NULL;213case 17: *t = typ_ELL; return NULL;214}215break;216case t_COL:217if (get_prid(x)) { *t = typ_MODPR; return NULL; }218break;219}220*t = typ_NULL; return NULL;221}222223GEN224get_nf(GEN x, long *t)225{226switch(typ(x))227{228case t_POL : *t = typ_POL; return NULL;229case t_QUAD: *t = typ_Q ; return NULL;230case t_VEC:231switch(lg(x))232{233case 3:234if (typ(gel(x,2)) != t_POLMOD) break;235return get_nf(gel(x,1),t);236case 5:237if (typ(gel(x,1)) != t_INT) break;238*t = typ_QUA; return NULL;239case 6: *t = typv6(x); return NULL;240case 7:241x = bnr_get_bnf(x);242if (!rawcheckbnf(x) || !rawchecknf(x = bnf_get_nf(x))) break;243*t = typ_BNR; return x;244case 9:245if (!v9checkgal(x)) break;246*t = typ_GAL; return NULL;247case 10:248if (!v10checknf(x)) break;249*t = typ_NF; return x;250case 11:251if (!rawchecknf(x = bnf_get_nf(x))) break;252*t = typ_BNF; return x;253case 13:254if (!v13checkrnf(x)) break;255*t = typ_RNF; return NULL;256case 17: *t = typ_ELL; return NULL;257}258break;259case t_QFB: *t = typ_QFB; return NULL;260case t_COL:261if (get_prid(x)) { *t = typ_MODPR; return NULL; }262break;263}264*t = typ_NULL; return NULL;265}266267long268nftyp(GEN x)269{270switch(typ(x))271{272case t_POL : return typ_POL;273case t_QUAD: return typ_Q;274case t_VEC:275switch(lg(x))276{277case 13:278if (!v13checkrnf(x)) break;279return typ_RNF;280case 10:281if (!v10checknf(x)) break;282return typ_NF;283case 11:284if (!v11checkbnf(x)) break;285return typ_BNF;286case 7:287x = bnr_get_bnf(x);288if (!rawcheckbnf(x) || !v11checkbnf(x)) break;289return typ_BNR;290case 6:291return typv6(x);292case 9:293if (!v9checkgal(x)) break;294return typ_GAL;295case 17: return typ_ELL;296}297}298return typ_NULL;299}300301/*************************************************************************/302/** **/303/** GALOIS GROUP **/304/** **/305/*************************************************************************/306307GEN308tschirnhaus(GEN x)309{310pari_sp av = avma, av2;311long a, v = varn(x);312GEN u, y = cgetg(5,t_POL);313314if (typ(x)!=t_POL) pari_err_TYPE("tschirnhaus",x);315if (lg(x) < 4) pari_err_CONSTPOL("tschirnhaus");316if (v) { u = leafcopy(x); setvarn(u,0); x=u; }317y[1] = evalsigne(1)|evalvarn(0);318do319{320a = random_bits(2); if (a==0) a = 1; gel(y,4) = stoi(a);321a = random_bits(3); if (a>=4) a -= 8; gel(y,3) = stoi(a);322a = random_bits(3); if (a>=4) a -= 8; gel(y,2) = stoi(a);323u = RgXQ_charpoly(y,x,v); av2 = avma;324}325while (degpol(RgX_gcd(u,RgX_deriv(u)))); /* while u not separable */326if (DEBUGLEVEL>1)327err_printf("Tschirnhaus transform. New pol: %Ps",u);328set_avma(av2); return gerepileupto(av,u);329}330331/* Assume pol in Z[X], monic of degree n. Find L in Z such that332* POL = L^(-n) pol(L x) is monic in Z[X]. Return POL and set *ptk = L.333* No GC. */334GEN335ZX_Z_normalize(GEN pol, GEN *ptk)336{337long i,j, sk, n = degpol(pol); /* > 0 */338GEN k, fa, P, E, a, POL;339340if (ptk) *ptk = gen_1;341if (!n) return pol;342a = pol + 2; k = gel(a,n-1); /* a[i] = coeff of degree i */343for (i = n-2; i >= 0; i--)344{345k = gcdii(k, gel(a,i));346if (is_pm1(k)) return pol;347}348sk = signe(k);349if (!sk) return pol; /* monomial! */350fa = absZ_factor_limit(k, 0); k = gen_1;351P = gel(fa,1);352E = gel(fa,2);353POL = leafcopy(pol); a = POL+2;354for (i = lg(P)-1; i > 0; i--)355{356GEN p = gel(P,i), pv, pvj;357long vmin = itos(gel(E,i));358/* find v_p(k) = min floor( v_p(a[i]) / (n-i)) */359for (j=n-1; j>=0; j--)360{361long v;362if (!signe(gel(a,j))) continue;363v = Z_pval(gel(a,j), p) / (n - j);364if (v < vmin) vmin = v;365}366if (!vmin) continue;367pvj = pv = powiu(p,vmin); k = mulii(k, pv);368/* a[j] /= p^(v*(n-j)) */369for (j=n-1; j>=0; j--)370{371if (j < n-1) pvj = mulii(pvj, pv);372gel(a,j) = diviiexact(gel(a,j), pvj);373}374}375if (ptk) *ptk = k;376return POL;377}378379/* Assume pol != 0 in Z[X]. Find C in Q, L in Z such that POL = C pol(x/L) monic380* in Z[X]. Return POL and set *pL = L. Wasteful (but correct) if pol is not381* primitive: better if caller used Q_primpart already. No GC. */382GEN383ZX_primitive_to_monic(GEN pol, GEN *pL)384{385long i,j, n = degpol(pol);386GEN lc = leading_coeff(pol), L, fa, P, E, a, POL;387388if (is_pm1(lc))389{390if (pL) *pL = gen_1;391return signe(lc) < 0? ZX_neg(pol): pol;392}393if (signe(lc) < 0)394POL = ZX_neg(pol);395else396POL = leafcopy(pol);397a = POL+2; lc = gel(a,n);398fa = absZ_factor_limit(lc,0); L = gen_1;399P = gel(fa,1);400E = gel(fa,2);401for (i = lg(P)-1; i > 0; i--)402{403GEN p = gel(P,i), pk, pku;404long v, j0, e = itos(gel(E,i)), k = e/n, d = k*n - e;405406if (d < 0) { k++; d += n; }407/* k = ceil(e[i] / n); find d, k such that p^d pol(x / p^k) monic */408for (j=n-1; j>0; j--)409{410if (!signe(gel(a,j))) continue;411v = Z_pval(gel(a,j), p);412while (v + d < k * j) { k++; d += n; }413}414pk = powiu(p,k); j0 = d/k;415L = mulii(L, pk);416417pku = powiu(p,d - k*j0);418/* a[j] *= p^(d - kj) */419for (j=j0; j>=0; j--)420{421if (j < j0) pku = mulii(pku, pk);422gel(a,j) = mulii(gel(a,j), pku);423}424j0++;425pku = powiu(p,k*j0 - d);426/* a[j] /= p^(kj - d) */427for (j=j0; j<=n; j++)428{429if (j > j0) pku = mulii(pku, pk);430gel(a,j) = diviiexact(gel(a,j), pku);431}432}433if (pL) *pL = L;434return POL;435}436/* Assume pol != 0 in Z[X]. Find C,L in Q such that POL = C pol(x/L)437* monic in Z[X]. Return POL and set *pL = L.438* Wasteful (but correct) if pol is not primitive: better if caller used439* Q_primpart already. No GC. */440GEN441ZX_Q_normalize(GEN pol, GEN *pL)442{443GEN lc, POL = ZX_primitive_to_monic(pol, &lc);444POL = ZX_Z_normalize(POL, pL);445if (pL) *pL = gdiv(lc, *pL);446return POL;447}448449GEN450ZX_Q_mul(GEN A, GEN z)451{452pari_sp av = avma;453long i, l = lg(A);454GEN d, n, Ad, B, u;455if (typ(z)==t_INT) return ZX_Z_mul(A,z);456n = gel(z, 1); d = gel(z, 2);457Ad = RgX_to_RgC(FpX_red(A, d), l-2);458u = gcdii(d, FpV_factorback(Ad, NULL, d));459B = cgetg(l, t_POL);460B[1] = A[1];461if (equali1(u))462{463for(i=2; i<l; i++)464gel(B, i) = mkfrac(mulii(n, gel(A,i)), d);465} else466{467for(i=2; i<l; i++)468{469GEN di = gcdii(gel(Ad, i-1), u);470GEN ni = mulii(n, diviiexact(gel(A,i), di));471if (equalii(d, di))472gel(B, i) = ni;473else474gel(B, i) = mkfrac(ni, diviiexact(d, di));475}476}477return gerepilecopy(av, B);478}479480/* pol != 0 in Z[x], returns a monic polynomial POL in Z[x] generating the481* same field: there exist C in Q, L in Z such that POL(x) = C pol(x/L).482* Set *L = NULL if L = 1, and to L otherwise. No garbage collecting. */483GEN484ZX_to_monic(GEN pol, GEN *L)485{486long n = lg(pol)-1;487GEN lc = gel(pol,n);488if (is_pm1(lc)) { *L = gen_1; return signe(lc) > 0? pol: ZX_neg(pol); }489return ZX_primitive_to_monic(Q_primpart(pol), L);490}491492GEN493ZXX_Q_mul(GEN A, GEN z)494{495long i, l;496GEN B;497if (typ(z)==t_INT) return ZXX_Z_mul(A,z);498B = cgetg_copy(A, &l);499B[1] = A[1];500for (i=2; i<l; i++)501{502GEN Ai = gel(A,i);503gel(B,i) = typ(Ai)==t_POL ? ZX_Q_mul(Ai, z): gmul(Ai, z);504}505return B;506}507508/* Evaluate pol in s using nfelt arithmetic and Horner rule */509GEN510nfpoleval(GEN nf, GEN pol, GEN s)511{512pari_sp av=avma;513long i=lg(pol)-1;514GEN res;515if (i==1) return gen_0;516res = nf_to_scalar_or_basis(nf, gel(pol,i));517for (i-- ; i>=2; i--)518res = nfadd(nf, nfmul(nf, s, res), gel(pol,i));519return gerepileupto(av, res);520}521522static GEN523QX_table_nfpoleval(GEN nf, GEN pol, GEN m)524{525pari_sp av = avma;526long i = lg(pol)-1;527GEN res, den;528if (i==1) return gen_0;529pol = Q_remove_denom(pol, &den);530res = scalarcol_shallow(gel(pol,i), nf_get_degree(nf));531for (i-- ; i>=2; i--)532res = ZC_Z_add(ZM_ZC_mul(m, res), gel(pol,i));533if (den) res = RgC_Rg_div(res, den);534return gerepileupto(av, res);535}536537GEN538FpX_FpC_nfpoleval(GEN nf, GEN pol, GEN a, GEN p)539{540pari_sp av=avma;541long i=lg(pol)-1, n=nf_get_degree(nf);542GEN res, Ma;543if (i==1) return zerocol(n);544Ma = FpM_red(zk_multable(nf, a), p);545res = scalarcol(gel(pol,i),n);546for (i-- ; i>=2; i--)547{548res = FpM_FpC_mul(Ma, res, p);549gel(res,1) = Fp_add(gel(res,1), gel(pol,i), p);550}551return gerepileupto(av, res);552}553554/* compute s(x), not stack clean */555static GEN556ZC_galoisapply(GEN nf, GEN s, GEN x)557{558x = nf_to_scalar_or_alg(nf, x);559if (typ(x) != t_POL) return scalarcol(x, nf_get_degree(nf));560return QX_table_nfpoleval(nf, x, zk_multable(nf, s));561}562563/* true nf; S = automorphism in basis form, return an FpC = S(z) mod p */564GEN565zk_galoisapplymod(GEN nf, GEN z, GEN S, GEN p)566{567GEN den, pe, pe1, denpe, R;568569z = nf_to_scalar_or_alg(nf, z);570if (typ(z) != t_POL) return z;571if (gequalX(z)) return FpC_red(S, p); /* common, e.g. modpr_genFq */572z = Q_remove_denom(z,&den);573denpe = pe = NULL;574pe1 = p;575if (den)576{577ulong e = Z_pvalrem(den, p, &den);578if (e) { pe = powiu(p, e); pe1 = mulii(pe, p); }579denpe = Fp_inv(den, pe1);580}581R = FpX_FpC_nfpoleval(nf, FpX_red(z, pe1), FpC_red(S, pe1), pe1);582if (denpe) R = FpC_Fp_mul(R, denpe, pe1);583if (pe) R = gdivexact(R, pe);584return R;585}586587/* true nf */588static GEN589pr_make(GEN nf, GEN p, GEN u, GEN e, GEN f)590{591GEN t = FpM_deplin(zk_multable(nf, u), p);592t = zk_scalar_or_multable(nf, t);593return mkvec5(p, u, e, f, t);594}595static GEN596pr_galoisapply(GEN nf, GEN pr, GEN aut)597{598GEN p = pr_get_p(pr), u = zk_galoisapplymod(nf, pr_get_gen(pr), aut, p);599return pr_make(nf, p, u, gel(pr,3), gel(pr,4));600}601static GEN602pr_galoismatrixapply(GEN nf, GEN pr, GEN M)603{604GEN p = pr_get_p(pr), u = FpC_red(ZM_ZC_mul(M, pr_get_gen(pr)), p);605return pr_make(nf, p, u, gel(pr,3), gel(pr,4));606}607608static GEN609vecgaloisapply(GEN nf, GEN aut, GEN x)610{ pari_APPLY_same(galoisapply(nf, aut, gel(x,i))); }611static GEN612vecgaloismatrixapply(GEN nf, GEN aut, GEN x)613{ pari_APPLY_same(nfgaloismatrixapply(nf, aut, gel(x,i))); }614615/* x: famat or standard algebraic number, aut automorphism in ZC form616* simplified from general galoisapply */617static GEN618elt_galoisapply(GEN nf, GEN aut, GEN x)619{620pari_sp av = avma;621switch(typ(x))622{623case t_INT: return icopy(x);624case t_FRAC: return gcopy(x);625case t_POLMOD: x = gel(x,2); /* fall through */626case t_POL: {627GEN y = basistoalg(nf, ZC_galoisapply(nf, aut, x));628return gerepileupto(av,y);629}630case t_COL:631return gerepileupto(av, ZC_galoisapply(nf, aut, x));632case t_MAT:633switch(lg(x)) {634case 1: return cgetg(1, t_MAT);635case 3: retmkmat2(vecgaloisapply(nf,aut,gel(x,1)), ZC_copy(gel(x,2)));636}637}638pari_err_TYPE("galoisapply",x);639return NULL; /* LCOV_EXCL_LINE */640}641/* M automorphism in matrix form */642static GEN643elt_galoismatrixapply(GEN nf, GEN M, GEN x)644{645if (typ(x) == t_MAT)646switch(lg(x)) {647case 1: return cgetg(1, t_MAT);648case 3: retmkmat2(vecgaloismatrixapply(nf,M,gel(x,1)), ZC_copy(gel(x,2)));649}650return nfgaloismatrixapply(nf, M, x);651}652653GEN654galoisapply(GEN nf, GEN aut, GEN x)655{656pari_sp av = avma;657long lx;658GEN y;659660nf = checknf(nf);661switch(typ(x))662{663case t_INT: return icopy(x);664case t_FRAC: return gcopy(x);665666case t_POLMOD: x = gel(x,2); /* fall through */667case t_POL:668aut = algtobasis(nf, aut);669y = basistoalg(nf, ZC_galoisapply(nf, aut, x));670return gerepileupto(av,y);671672case t_VEC:673aut = algtobasis(nf, aut);674switch(lg(x))675{676case 6:677if (pr_is_inert(x)) { set_avma(av); return gcopy(x); }678return gerepilecopy(av, pr_galoisapply(nf, x, aut));679case 3: y = cgetg(3,t_VEC);680gel(y,1) = galoisapply(nf, aut, gel(x,1));681gel(y,2) = elt_galoisapply(nf, aut, gel(x,2));682return gerepileupto(av, y);683}684break;685686case t_COL:687aut = algtobasis(nf, aut);688return gerepileupto(av, ZC_galoisapply(nf, aut, x));689690case t_MAT: /* ideal */691lx = lg(x); if (lx==1) return cgetg(1,t_MAT);692if (nbrows(x) != nf_get_degree(nf)) break;693y = RgM_mul(nfgaloismatrix(nf,aut), x);694return gerepileupto(av, idealhnf_shallow(nf,y));695}696pari_err_TYPE("galoisapply",x);697return NULL; /* LCOV_EXCL_LINE */698}699700/* M automorphism in galoismatrix form */701GEN702nfgaloismatrixapply(GEN nf, GEN M, GEN x)703{704pari_sp av = avma;705long lx;706GEN y;707708nf = checknf(nf);709switch(typ(x))710{711case t_INT: return icopy(x);712case t_FRAC: return gcopy(x);713714case t_POLMOD: x = gel(x,2); /* fall through */715case t_POL:716x = algtobasis(nf, x);717return gerepileupto(av, basistoalg(nf, RgM_RgC_mul(M, x)));718719case t_VEC:720switch(lg(x))721{722case 6:723if (pr_is_inert(x)) { set_avma(av); return gcopy(x); }724return gerepilecopy(av, pr_galoismatrixapply(nf, x, M));725case 3: y = cgetg(3,t_VEC);726gel(y,1) = nfgaloismatrixapply(nf, M, gel(x,1));727gel(y,2) = elt_galoismatrixapply(nf, M, gel(x,2));728return gerepileupto(av, y);729}730break;731732case t_COL: return RgM_RgC_mul(M, x);733734case t_MAT: /* ideal */735lx = lg(x); if (lx==1) return cgetg(1,t_MAT);736if (nbrows(x) != nf_get_degree(nf)) break;737return gerepileupto(av, idealhnf_shallow(nf,RgM_mul(M, x)));738}739pari_err_TYPE("galoisapply",x);740return NULL; /* LCOV_EXCL_LINE */741}742743/* compute action of automorphism s on nf.zk */744GEN745nfgaloismatrix(GEN nf, GEN s)746{747pari_sp av2, av = avma;748GEN zk, D, M, H, m;749long k, n;750751nf = checknf(nf);752zk = nf_get_zkprimpart(nf); n = lg(zk)-1;753M = cgetg(n+1, t_MAT);754gel(M,1) = col_ei(n, 1); /* s(1) = 1 */755if (n == 1) return M;756av2 = avma;757if (typ(s) != t_COL) s = algtobasis(nf, s);758D = nf_get_zkden(nf);759H = RgV_to_RgM(zk, n);760if (n == 2)761{762GEN t = gel(H,2); /* D * s(w_2) */763t = ZC_Z_add(ZC_Z_mul(s, gel(t,2)), gel(t,1));764gel(M,2) = gerepileupto(av2, gdiv(t, D));765return M;766}767m = zk_multable(nf, s);768gel(M,2) = s; /* M[,k] = s(x^(k-1)) */769for (k = 3; k <= n; k++) gel(M,k) = ZM_ZC_mul(m, gel(M,k-1));770M = ZM_mul(M, H);771if (!equali1(D)) M = ZM_Z_divexact(M, D);772return gerepileupto(av, M);773}774775static GEN776get_aut(GEN nf, GEN gal, GEN aut, GEN g)777{778return aut ? gel(aut, g[1]): poltobasis(nf, galoispermtopol(gal, g));779}780781static GEN782idealquasifrob(GEN nf, GEN gal, GEN grp, GEN pr, GEN subg, GEN *S, GEN aut)783{784pari_sp av = avma;785long i, n = nf_get_degree(nf), f = pr_get_f(pr);786GEN pi = pr_get_gen(pr);787for (i=1; i<=n; i++)788{789GEN g = gel(grp,i);790if ((!subg && perm_orderu(g) == (ulong)f)791|| (subg && perm_relorder(g, subg)==f))792{793*S = get_aut(nf, gal, aut, g);794if (ZC_prdvd(ZC_galoisapply(nf, *S, pi), pr)) return g;795set_avma(av);796}797}798pari_err_BUG("idealquasifrob [Frobenius not found]");799return NULL;/*LCOV_EXCL_LINE*/800}801802GEN803nfgaloispermtobasis(GEN nf, GEN gal)804{805GEN grp = gal_get_group(gal);806long i, n = lg(grp)-1;807GEN aut = cgetg(n+1, t_VEC);808for(i=1; i<=n; i++)809{810pari_sp av = avma;811GEN g = gel(grp, i);812GEN vec = poltobasis(nf, galoispermtopol(gal, g));813gel(aut, g[1]) = gerepileupto(av, vec);814}815return aut;816}817818static void819gal_check_pol(const char *f, GEN x, GEN y)820{ if (!RgX_equal_var(x,y)) pari_err_MODULUS(f,x,y); }821822/* true nf */823GEN824idealfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN aut)825{826pari_sp av = avma;827GEN S=NULL, g=NULL; /*-Wall*/828GEN T, p, a, b, modpr;829long f, n, s;830f = pr_get_f(pr); n = nf_get_degree(nf);831if (f==1) { set_avma(av); return identity_perm(n); }832g = idealquasifrob(nf, gal, gal_get_group(gal), pr, NULL, &S, aut);833if (f==2) return gerepileuptoleaf(av, g);834modpr = zk_to_Fq_init(nf,&pr,&T,&p);835a = pol_x(nf_get_varn(nf));836b = nf_to_Fq(nf, zk_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr);837for (s = 1; s < f-1; s++)838{839a = Fq_pow(a, p, T, p);840if (ZX_equal(a, b)) break;841}842g = perm_powu(g, Fl_inv(s, f));843return gerepileupto(av, g);844}845846GEN847idealfrobenius(GEN nf, GEN gal, GEN pr)848{849nf = checknf(nf);850checkgal(gal);851checkprid(pr);852gal_check_pol("idealfrobenius",nf_get_pol(nf),gal_get_pol(gal));853if (pr_get_e(pr)>1) pari_err_DOMAIN("idealfrobenius","pr.e", ">", gen_1,pr);854return idealfrobenius_aut(nf, gal, pr, NULL);855}856857/* true nf */858GEN859idealramfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN ram, GEN aut)860{861pari_sp av = avma;862GEN S=NULL, g=NULL; /*-Wall*/863GEN T, p, a, b, modpr;864GEN isog, deco;865long f, n, s;866f = pr_get_f(pr); n = nf_get_degree(nf);867if (f==1) { set_avma(av); return identity_perm(n); }868modpr = zk_to_Fq_init(nf,&pr,&T,&p);869deco = group_elts(gel(ram,1), nf_get_degree(nf));870isog = group_set(gel(ram,2), nf_get_degree(nf));871g = idealquasifrob(nf, gal, deco, pr, isog, &S, aut);872a = pol_x(nf_get_varn(nf));873b = nf_to_Fq(nf, zk_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr);874for (s=0; !ZX_equal(a, b); s++)875a = Fq_pow(a, p, T, p);876g = perm_powu(g, Fl_inv(s, f));877return gerepileupto(av, g);878}879880GEN881idealramfrobenius(GEN nf, GEN gal, GEN pr, GEN ram)882{883return idealramfrobenius_aut(nf, gal, pr, ram, NULL);884}885886static GEN887idealinertiagroup(GEN nf, GEN gal, GEN aut, GEN pr)888{889long i, n = nf_get_degree(nf);890GEN p, T, modpr = zk_to_Fq_init(nf,&pr,&T,&p);891GEN b = modpr_genFq(modpr);892long e = pr_get_e(pr), coprime = ugcd(e, pr_get_f(pr)) == 1;893GEN grp = gal_get_group(gal), pi = pr_get_gen(pr);894pari_sp ltop = avma;895for (i=1; i<=n; i++)896{897GEN iso = gel(grp,i);898if (perm_orderu(iso) == (ulong)e)899{900GEN S = get_aut(nf, gal, aut, iso);901if (ZC_prdvd(ZC_galoisapply(nf, S, pi), pr)902&& (coprime || gequalX(nf_to_Fq(nf, galoisapply(nf,S,b), modpr))))903return iso;904set_avma(ltop);905}906}907pari_err_BUG("idealinertiagroup [no isotropic element]");908return NULL;/*LCOV_EXCL_LINE*/909}910911static GEN912idealramgroupstame(GEN nf, GEN gal, GEN aut, GEN pr)913{914pari_sp av = avma;915GEN iso, frob, giso, isog, S, res;916long e = pr_get_e(pr), f = pr_get_f(pr);917GEN grp = gal_get_group(gal);918if (e == 1)919{920if (f==1)921return cgetg(1,t_VEC);922frob = idealquasifrob(nf, gal, grp, pr, NULL, &S, aut);923set_avma(av);924res = cgetg(2, t_VEC);925gel(res, 1) = cyclicgroup(frob, f);926return res;927}928res = cgetg(3, t_VEC);929av = avma;930iso = idealinertiagroup(nf, gal, aut, pr);931set_avma(av);932giso = cyclicgroup(iso, e);933gel(res, 2) = giso;934if (f==1)935{936gel(res, 1) = giso;937return res;938}939av = avma;940isog = group_set(giso, nf_get_degree(nf));941frob = idealquasifrob(nf, gal, grp, pr, isog, &S, aut);942set_avma(av);943gel(res, 1) = dicyclicgroup(iso,frob,e,f);944return res;945}946947/* true nf, p | e */948static GEN949idealramgroupswild(GEN nf, GEN gal, GEN aut, GEN pr)950{951pari_sp av2, av = avma;952GEN p, T, idx, g, gbas, pi, pibas, Dpi, modpr = zk_to_Fq_init(nf,&pr,&T,&p);953long bound, i, vDpi, vDg, n = nf_get_degree(nf);954long e = pr_get_e(pr);955long f = pr_get_f(pr);956ulong nt,rorder;957GEN pg, ppi, grp = gal_get_group(gal);958959/* G_i = {s: v(s(pi) - pi) > i} trivial for i > bound;960* v_pr(Diff) = sum_{i = 0}^{bound} (#G_i - 1) >= e-1 + bound*(p-1)*/961bound = (idealval(nf, nf_get_diff(nf), pr) - (e-1)) / (itou(p)-1);962(void) u_pvalrem(n,p,&nt);963rorder = e*f*(n/nt);964idx = const_vecsmall(n,-1);965pg = NULL;966vDg = 0;967if (f == 1)968g = gbas = NULL;969else970{971GEN Dg;972g = nf_to_scalar_or_alg(nf, modpr_genFq(modpr));973if (!gequalX(g)) /* p | nf.index */974{975g = Q_remove_denom(g, &Dg);976vDg = Z_pval(Dg,p);977pg = powiu(p, vDg + 1);978g = FpX_red(g, pg);979}980gbas = nf_to_scalar_or_basis(nf, g);981}982pi = nf_to_scalar_or_alg(nf, pr_get_gen(pr));983pi = Q_remove_denom(pi, &Dpi);984vDpi = Dpi ? Z_pval(Dpi, p): 0;985ppi = powiu(p, vDpi + (bound + e)/e);986pi = FpX_red(pi, ppi);987pibas = nf_to_scalar_or_basis(nf, pi);988av2 = avma;989for (i = 2; i <= n; i++)990{991GEN S, Spi, piso, iso = gel(grp, i);992long j, o, ix = iso[1];993if (idx[ix] >= 0 || rorder % (o = (long)perm_orderu(iso))) continue;994995piso = iso;996S = get_aut(nf, gal, aut, iso);997Spi = FpX_FpC_nfpoleval(nf, pi, FpC_red(S, ppi), ppi);998/* Computation made knowing that the valuation is <= bound + 1. Correct999* to maximal value if reduction mod ppi altered this */1000idx[ix] = minss(bound+1, idealval(nf, gsub(Spi,pibas), pr) - e*vDpi);1001if (idx[ix] == 0) idx[ix] = -1;1002else if (g)1003{1004GEN Sg = pg? FpX_FpC_nfpoleval(nf, g, FpC_red(S, pg), pg): S;1005if (vDg)1006{ if (nfval(nf, gsub(Sg, gbas), pr) - e*vDg <= 0) idx[ix] = 0; }1007else /* same, more efficient */1008{ if (!ZC_prdvd(gsub(Sg, gbas), pr)) idx[ix] = 0; }1009}1010for (j = 2; j < o; j++)1011{1012piso = perm_mul(piso,iso);1013if (ugcd(j,o)==1) idx[ piso[1] ] = idx[ix];1014}1015set_avma(av2);1016}1017return gerepileuptoleaf(av, idx);1018}10191020GEN1021idealramgroups_aut(GEN nf, GEN gal, GEN pr, GEN aut)1022{1023pari_sp av = avma;1024GEN tbl, idx, res, set, sub;1025long i, j, e, n, maxm, p;1026ulong et;1027nf = checknf(nf);1028checkgal(gal);1029checkprid(pr);1030gal_check_pol("idealramgroups",nf_get_pol(nf),gal_get_pol(gal));1031e = pr_get_e(pr); n = nf_get_degree(nf);1032p = itos(pr_get_p(pr));1033if (e%p) return idealramgroupstame(nf, gal, aut, pr);1034(void) u_lvalrem(e,p,&et);1035idx = idealramgroupswild(nf, gal, aut, pr);1036sub = group_subgroups(galois_group(gal));1037tbl = subgroups_tableset(sub, n);1038maxm = vecsmall_max(idx)+1;1039res = cgetg(maxm+1,t_VEC);1040set = zero_F2v(n); F2v_set(set,1);1041for(i=maxm; i>0; i--)1042{1043long ix;1044for(j=1;j<=n;j++)1045if (idx[j]==i-1)1046F2v_set(set,j);1047ix = tableset_find_index(tbl, set);1048if (ix==0) pari_err_BUG("idealramgroups");1049gel(res,i) = gel(sub, ix);1050}1051return gerepilecopy(av, res);1052}10531054GEN1055idealramgroups(GEN nf, GEN gal, GEN pr)1056{1057return idealramgroups_aut(nf, gal, pr, NULL);1058}10591060/* x = relative polynomial nf = absolute nf, bnf = absolute bnf */1061GEN1062get_bnfpol(GEN x, GEN *bnf, GEN *nf)1063{1064*bnf = checkbnf_i(x);1065*nf = checknf_i(x);1066if (*nf) x = nf_get_pol(*nf);1067if (typ(x) != t_POL) pari_err_TYPE("get_bnfpol",x);1068return x;1069}10701071GEN1072get_nfpol(GEN x, GEN *nf)1073{1074if (typ(x) == t_POL) { *nf = NULL; return x; }1075*nf = checknf(x); return nf_get_pol(*nf);1076}10771078static GEN1079incl_disc(GEN nfa, GEN a, int nolocal)1080{1081GEN d;1082if (nfa) return nf_get_disc(nfa);1083if (nolocal) return NULL;1084d = ZX_disc(a);1085if (!signe(d)) pari_err_IRREDPOL("nfisincl",a);1086return d;1087}10881089static int1090badp(GEN fa, GEN db, long q)1091{1092GEN P = gel(fa,1), E = gel(fa,2);1093long i, l = lg(P);1094for (i = 1; i < l; i++)1095if (mod2(gel(E,i)) && !dvdii(db, powiu(gel(P,i),q))) return 1;1096return 0;1097}10981099/* is isomorphism / inclusion (a \subset b) compatible with what we know about1100* basic invariants ? (degree, signature, discriminant); test for isomorphism1101* if fliso is set and for inclusion otherwise */1102static int1103tests_OK(GEN a, GEN nfa, GEN b, GEN nfb, long fliso)1104{1105GEN da2, da, db, fa, P, U;1106long i, l, q, m = degpol(a), n = degpol(b);11071108if (m <= 0) pari_err_IRREDPOL("nfisincl",a);1109if (n <= 0) pari_err_IRREDPOL("nfisincl",b);1110q = n / m; /* relative degree */1111if (fliso) { if (n != m) return 0; } else { if (n % m) return 0; }1112if (m == 1) return 1;11131114/*local test expensive if n^2 >> m^4 <=> q = n/m >> m */1115db = incl_disc(nfb, b, q > m);1116da = db? incl_disc(nfa, a, 0): NULL;1117if (nfa && nfb) /* both nf structures available */1118{1119long r1a = nf_get_r1(nfa), r1b = nf_get_r1(nfb);1120return fliso ? (r1a == r1b && equalii(da, db))1121: (r1b <= r1a * q && dvdii(db, powiu(da, q)));1122}1123if (!db) return 1;1124if (fliso) return issquare(gdiv(da,db));11251126if (nfa)1127{1128P = nf_get_ramified_primes(nfa); l = lg(P);1129for (i = 1; i < l; i++)1130if (Z_pval(db, gel(P,i)) < q * Z_pval(da, gel(P,i))) return 0;1131return 1;1132}1133else if (nfb)1134{1135P = nf_get_ramified_primes(nfb); l = lg(P);1136for (i = 1; i < l; i++)1137{1138GEN p = gel(P,i);1139long va = Z_pval(nfdisc(mkvec2(a, mkvec(p))), p);1140if (va && Z_pval(db, gel(P,i)) < va * q) return 0;1141}1142return 1;1143}1144/* da = dK A^2, db = dL B^2, dL = dK^q * N(D)1145* da = da1 * da2, da2 maximal s.t. (da2, db) = 1: let p a prime divisor of1146* da2 then p \nmid da1 * dK and p | A => v_p(da) = v_p(da2) is even */1147da2 = Z_ppo(da, db);1148if (!is_pm1(da2))1149{ /* replace da by da1 all of whose prime divisors divide db */1150da2 = absi_shallow(da2);1151if (!Z_issquare(da2)) return 0;1152da = diviiexact(da, da2);1153}1154if (is_pm1(da)) return 1;1155fa = absZ_factor_limit_strict(da, 0, &U);1156if (badp(fa, db, q)) return 0;1157if (U && mod2(gel(U,2)) && expi(gel(U,1)) < 150)1158{ /* cofactor is small, finish */1159fa = absZ_factor(gel(U,1));1160if (badp(fa, db, q)) return 0;1161}1162return 1;1163}11641165GEN1166nfisisom(GEN a, GEN b)1167{1168pari_sp av = avma;1169long i, va, vb, lx;1170GEN nfa, nfb, y, la, lb;1171int newvar, sw = 0;11721173a = get_nfpol(a, &nfa);1174b = get_nfpol(b, &nfb);1175if (!nfa) { a = Q_primpart(a); RgX_check_ZX(a, "nfisisom"); }1176if (!nfb) { b = Q_primpart(b); RgX_check_ZX(b, "nfisisom"); }1177if (nfa && !nfb) { swap(a,b); nfb = nfa; nfa = NULL; sw = 1; }1178if (!tests_OK(a, nfa, b, nfb, 1)) { set_avma(av); return gen_0; }11791180if (nfb) lb = gen_1; else nfb = b = ZX_Q_normalize(b,&lb);1181if (nfa) la = gen_1; else nfa = a = ZX_Q_normalize(a,&la);1182va = varn(a); vb = varn(b); newvar = (varncmp(vb,va) <= 0);1183if (newvar) { a = leafcopy(a); setvarn(a, fetch_var_higher()); }1184y = lift_shallow(nfroots(nfb,a));1185if (newvar) (void)delete_var();1186lx = lg(y); if (lx==1) { set_avma(av); return gen_0; }1187if (sw) { vb = va; b = leafcopy(b); setvarn(b, vb); }1188for (i=1; i<lx; i++)1189{1190GEN t = gel(y,i);1191if (typ(t) == t_POL) setvarn(t, vb); else t = scalarpol(t, vb);1192if (lb != gen_1) t = RgX_unscale(t, lb);1193if (la != gen_1) t = RgX_Rg_div(t, la);1194gel(y,i) = sw? RgXQ_reverse(t, b): t;1195}1196return gerepilecopy(av,y);1197}11981199static GEN1200partmap_reverse(GEN a, GEN b, GEN t, GEN la, GEN lb, long v)1201{1202pari_sp av = avma;1203GEN rnf = rnfequation2(a, t), z;1204if (!RgX_equal(b, gel(rnf,1)))1205{ setvarn(b,v); pari_err_IRREDPOL("nfisincl", b); }1206z = liftpol_shallow(gel(rnf, 2));1207setvarn(z, v);1208if (!isint1(lb)) z = RgX_unscale(z, lb);1209if (!isint1(la)) z = RgX_Rg_div(z, la);1210return gerepilecopy(av, z);1211}12121213static GEN1214partmap_reverse_frac(GEN a, GEN b, GEN t, GEN la, GEN lb, long v)1215{1216pari_sp av = avma;1217long k = 0;1218GEN N, D, G, L, de;1219GEN C = ZX_ZXY_resultant_all(a, Q_remove_denom(t,&de), &k, &L);1220if (k || degpol(b) != degpol(C))1221{ setvarn(b,v); pari_err_IRREDPOL("nfisincl", b); }1222N = RgX_neg(gel(L,1)); D = gel(L,2);1223setvarn(N, v); setvarn(D, v);1224G = QX_gcd(N,D);1225if (degpol(G))1226{1227N = RgX_div(N,G); D = RgX_div(D,G);1228}1229if (!isint1(lb)) { N = RgX_unscale(N, lb); D = RgX_unscale(D, lb); }1230if (!isint1(la)) D = RgX_Rg_mul(D, la);1231return gerepilecopy(av, mkrfrac(N,D));1232}12331234static GEN1235nfisincl_from_fact(GEN a, long da, GEN b, GEN la, GEN lb, long vb, GEN y, long flag)1236{1237long i, k, lx = lg(y);1238long db = degpol(b), d = db/da;1239GEN x = cgetg(lx, t_VEC);1240for (i=1, k=1; i<lx; i++)1241{1242GEN t = gel(y,i);1243if (degpol(t)!=d) continue;1244gel(x, k++) = partmap_reverse(a, b, t, la, lb, vb);1245if (flag==1) return gel(x,1);1246}1247if (k==1) return gen_0;1248setlg(x, k);1249gen_sort_inplace(x, (void*)&cmp_RgX, &cmp_nodata, NULL);1250return x;1251}12521253static GEN1254nfisincl_from_fact_frac(GEN a, GEN b, GEN la, GEN lb, long vb, GEN y)1255{1256long i, k, lx = lg(y);1257long da = degpol(a), db = degpol(b), d = db/da;1258GEN x = cgetg(lx, t_VEC);1259for (i=1, k=1; i<lx; i++)1260{1261GEN t = gel(y,i);1262if (degpol(t)!=d) continue;1263gel(x, k++) = partmap_reverse_frac(a, b, t, la, lb, vb);1264}1265if (k==1) return gen_0;1266setlg(x, k);1267return x;1268}12691270GEN1271nfisincl0(GEN fa, GEN fb, long flag)1272{1273pari_sp av = avma;1274long vb;1275GEN a, b, nfa, nfb, x, y, la, lb;1276int newvar;1277if (flag < 0 || flag > 3) pari_err_FLAG("nfisincl");12781279a = get_nfpol(fa, &nfa);1280b = get_nfpol(fb, &nfb);1281if (!nfa) { a = Q_primpart(a); RgX_check_ZX(a, "nsisincl"); }1282if (!nfb) { b = Q_primpart(b); RgX_check_ZX(b, "nsisincl"); }1283if (ZX_equal(a, b) && flag<=1)1284{1285if (flag==1)1286{1287x = pol_x(varn(b));1288return degpol(b) > 1 ? x: RgX_rem(x,b);1289}1290x = galoisconj(fb, NULL); settyp(x, t_VEC);1291return gerepilecopy(av,x);1292}1293if (flag==0 && !tests_OK(a, nfa, b, nfb, 0)) { set_avma(av); return gen_0; }12941295if (nfb) lb = gen_1; else nfb = b = ZX_Q_normalize(b,&lb);1296if (nfa) la = gen_1; else nfa = a = ZX_Q_normalize(a,&la);1297vb = varn(b); newvar = (varncmp(varn(a),vb) <= 0);1298if (newvar) { b = leafcopy(b); setvarn(b, fetch_var_higher()); }1299y = lift_shallow(gel(nffactor(nfa,b),1));1300if (flag>=2)1301x = nfisincl_from_fact_frac(a, b, la, lb, vb, y);1302else1303x = nfisincl_from_fact(nfa, degpol(a), b, la, lb, vb, y, flag);1304if (newvar) (void)delete_var();1305return gerepilecopy(av,x);1306}13071308GEN1309nfisincl(GEN fa, GEN fb) { return nfisincl0(fa, fb, 0); }13101311static GEN1312lastel(GEN x) { return gel(x, lg(x)-1); }13131314static GEN1315RgF_to_Flxq(GEN F, GEN T, ulong p)1316{1317return typ(F)==t_POL ? RgX_to_Flx(F, p)1318: Flxq_div(RgX_to_Flx(gel(F,1), p), RgX_to_Flx(gel(F,2), p), T, p);1319}13201321static GEN1322RgFV_to_FlxqV(GEN x, GEN T, ulong p)1323{ pari_APPLY_same(RgF_to_Flxq(gel(x,i), T, p)) }13241325static GEN1326nfsplitting_auto(GEN g, GEN R)1327{1328forprime_t T;1329long i, d = degpol(g);1330ulong p;1331GEN P, K, N, G, q, den = Q_denom(R), Rp, Gp;1332u_forprime_init(&T, d*maxss(expu(d)-3, 2), ULONG_MAX);1333for(;;)1334{1335p = u_forprime_next(&T);1336if (dvdiu(den,p)) continue;1337Gp = ZX_to_Flx(g, p);1338if (Flx_is_totally_split(Gp, p)) break;1339}1340P = Flx_roots(Gp, p);1341Rp = RgFV_to_FlxqV(R, Gp, p);1342K = Flm_Flc_invimage(FlxV_to_Flm(Rp, d), vecsmall_ei(d, 2), p);1343N = Flm_transpose(FlxV_Flv_multieval(Rp, P, p));1344q = perm_inv(vecsmall_indexsort(gel(N,1)));1345G = cgetg(d+1, t_COL);1346for (i=1; i<=d; i++)1347{1348GEN r = perm_mul(vecsmall_indexsort(gel(N,i)), q);1349gel(G,i) = FlxV_Flc_mul(Rp, vecpermute(K, r), p);1350}1351return mkvec3(g, G, utoi(p));1352}13531354static GEN1355nfsplitting_composite(GEN P)1356{1357GEN F = gel(ZX_factor(P), 1), Q = NULL;1358long i, n = lg(F)-1;1359for (i = 1; i <= n; i++)1360{1361GEN Fi = gel(F, i);1362if (degpol(Fi) == 1) continue;1363Q = Q ? lastel(compositum(Q, Fi)): Fi;1364}1365return Q ? Q: pol_x(varn(P));1366}1367GEN1368nfsplitting0(GEN T0, GEN D, long flag)1369{1370pari_sp av = avma;1371long d, Ds, v;1372GEN T, F, K, N = NULL;1373T = T0 = get_nfpol(T0, &K);1374if (!K)1375{1376if (typ(T) != t_POL) pari_err_TYPE("nfsplitting",T);1377T = Q_primpart(T);1378RgX_check_ZX(T,"nfsplitting");1379}1380T = nfsplitting_composite(T);1381d = degpol(T); v = varn(T);1382if (d <= 1 && flag==0)1383{ set_avma(av); return pol_x(v); }1384if (!K) {1385if (!isint1(leading_coeff(T))) K = T = polredbest(T,0);1386K = T;1387}1388if (flag==1 && !ZX_equal(T, T0))1389pari_err_FLAG("nfsplitting");1390if (D)1391{1392if (typ(D) != t_INT || signe(D) < 1) pari_err_TYPE("nfsplitting",D);1393}1394else1395{1396char *data = stack_strcat(pari_datadir, "/galdata");1397long dmax = pari_is_dir(data)? 11: 7;1398D = (d <= dmax)? gel(polgalois(T,DEFAULTPREC), 1): mpfact(d);1399}1400Ds = itos_or_0(D);1401T = leafcopy(T); setvarn(T, fetch_var_higher());1402for(F = T;;)1403{1404GEN P = gel(nffactor(K, F), 1), Q = gel(P,lg(P)-1);1405if (degpol(gel(P,1)) == degpol(Q))1406{1407if (flag==1 && ZX_equal(T, T0))1408N = nfisincl_from_fact(K, d, F, gen_1, gen_1, v, liftall(P), flag);1409else if (flag>1 && ZX_equal(T, T0))1410N = nfisincl_from_fact_frac(T0, F, gen_1, gen_1, v, liftall(P));1411break;1412}1413F = rnfequation(K,Q);1414if (degpol(F) == Ds && flag==0)1415break;1416}1417if (umodiu(D,degpol(F)))1418{1419char *sD = itostr(D);1420pari_warn(warner,stack_strcat("ignoring incorrect degree bound ",sD));1421}1422setvarn(F, v);1423(void)delete_var();1424if (flag==2) return gerepilecopy(av, nfsplitting_auto(F, N));1425return gerepilecopy(av, odd(flag) ? mkvec2(F,N): F);1426}14271428GEN1429nfsplitting(GEN T, GEN D) { return nfsplitting0(T, D, 0); }14301431GEN1432nfsplitting_gp(GEN T, GEN D, long flag)1433{1434if (flag < 0 || flag > 1)1435pari_err_FLAG("nfsplitting");1436return nfsplitting0(T, D, flag);1437}14381439/*************************************************************************/1440/** **/1441/** INITALG **/1442/** **/1443/*************************************************************************/1444typedef struct {1445GEN T;1446GEN ro; /* roots of T */1447long r1;1448GEN basden;1449long prec;1450long extraprec; /* possibly -1 = irrelevant or not computed */1451GEN M, G; /* possibly NULL = irrelevant or not computed */1452} nffp_t;14531454static GEN1455get_roots(GEN x, long r1, long prec)1456{1457long i, ru;1458GEN z;1459if (typ(x) != t_POL)1460{1461z = leafcopy(x);1462ru = (lg(z)-1 + r1) >> 1;1463}1464else1465{1466long n = degpol(x);1467z = (r1 == n)? ZX_realroots_irred(x, prec): QX_complex_roots(x,prec);1468ru = (n+r1)>>1;1469}1470for (i=r1+1; i<=ru; i++) gel(z,i) = gel(z, (i<<1)-r1);1471z[0]=evaltyp(t_VEC)|evallg(ru+1); return z;1472}14731474GEN1475nf_get_allroots(GEN nf)1476{1477return embed_roots(nf_get_roots(nf), nf_get_r1(nf));1478}14791480/* For internal use. compute trace(x mod pol), sym=polsym(pol,deg(pol)-1) */1481static GEN1482quicktrace(GEN x, GEN sym)1483{1484GEN p1 = gen_0;1485long i;14861487if (typ(x) != t_POL) return gmul(x, gel(sym,1));1488if (signe(x))1489{1490sym--;1491for (i=lg(x)-1; i>1; i--)1492p1 = gadd(p1, gmul(gel(x,i),gel(sym,i)));1493}1494return p1;1495}14961497static GEN1498get_Tr(GEN mul, GEN x, GEN basden)1499{1500GEN t, bas = gel(basden,1), den = gel(basden,2);1501long i, j, n = lg(bas)-1;1502GEN T = cgetg(n+1,t_MAT), TW = cgetg(n+1,t_COL), sym = polsym(x, n-1);15031504gel(TW,1) = utoipos(n);1505for (i=2; i<=n; i++)1506{1507t = quicktrace(gel(bas,i), sym);1508if (den && gel(den,i)) t = diviiexact(t,gel(den,i));1509gel(TW,i) = t; /* tr(w[i]) */1510}1511gel(T,1) = TW;1512for (i=2; i<=n; i++)1513{1514gel(T,i) = cgetg(n+1,t_COL); gcoeff(T,1,i) = gel(TW,i);1515for (j=2; j<=i; j++) /* Tr(W[i]W[j]) */1516gcoeff(T,i,j) = gcoeff(T,j,i) = ZV_dotproduct(gel(mul,j+(i-1)*n), TW);1517}1518return T;1519}15201521/* return [bas[i]*denom(bas[i]), denom(bas[i])], denom 1 is given as NULL */1522static GEN1523get_bas_den(GEN bas)1524{1525GEN b,d,den, dbas = leafcopy(bas);1526long i, l = lg(bas);1527int power = 1;1528den = cgetg(l,t_VEC);1529for (i=1; i<l; i++)1530{1531b = Q_remove_denom(gel(bas,i), &d);1532gel(dbas,i) = b;1533gel(den,i) = d; if (d) power = 0;1534}1535if (power) den = NULL; /* power basis */1536return mkvec2(dbas, den);1537}15381539/* return multiplication table for S->basis */1540static GEN1541nf_multable(nfmaxord_t *S, GEN invbas)1542{1543GEN T = S->T, w = gel(S->basden,1), den = gel(S->basden,2);1544long i,j, n = degpol(T);1545GEN mul = cgetg(n*n+1,t_MAT);15461547/* i = 1 split for efficiency, assume w[1] = 1 */1548for (j=1; j<=n; j++)1549gel(mul,j) = gel(mul,1+(j-1)*n) = col_ei(n, j);1550for (i=2; i<=n; i++)1551for (j=i; j<=n; j++)1552{1553pari_sp av = avma;1554GEN z = (i == j)? ZXQ_sqr(gel(w,i), T): ZXQ_mul(gel(w,i),gel(w,j), T);1555z = ZM_ZX_mul(invbas, z); /* integral column */1556if (den)1557{1558GEN d = mul_denom(gel(den,i), gel(den,j));1559if (d) z = ZC_Z_divexact(z, d);1560}1561gel(mul,j+(i-1)*n) = gel(mul,i+(j-1)*n) = gerepileupto(av,z);1562}1563return mul;1564}15651566/* as get_Tr, mul_table not precomputed */1567static GEN1568make_Tr(nfmaxord_t *S)1569{1570GEN T = S->T, w = gel(S->basden,1), den = gel(S->basden,2);1571long i,j, n = degpol(T);1572GEN c, t, d, M = cgetg(n+1,t_MAT), sym = polsym(T, n-1);15731574/* W[i] = w[i]/den[i]; assume W[1] = 1, case i = 1 split for efficiency */1575c = cgetg(n+1,t_COL); gel(M,1) = c;1576gel(c, 1) = utoipos(n);1577for (j=2; j<=n; j++)1578{1579pari_sp av = avma;1580t = quicktrace(gel(w,j), sym);1581if (den)1582{1583d = gel(den,j);1584if (d) t = diviiexact(t, d);1585}1586gel(c,j) = gerepileuptoint(av, t);1587}1588for (i=2; i<=n; i++)1589{1590c = cgetg(n+1,t_COL); gel(M,i) = c;1591for (j=1; j<i ; j++) gel(c,j) = gcoeff(M,i,j);1592for ( ; j<=n; j++)1593{1594pari_sp av = avma;1595t = (i == j)? ZXQ_sqr(gel(w,i), T): ZXQ_mul(gel(w,i),gel(w,j), T);1596t = quicktrace(t, sym);1597if (den)1598{1599d = mul_denom(gel(den,i),gel(den,j));1600if (d) t = diviiexact(t, d);1601}1602gel(c,j) = gerepileuptoint(av, t); /* Tr (W[i]W[j]) */1603}1604}1605return M;1606}16071608/* [bas[i]/den[i]]= integer basis. roo = real part of the roots */1609static void1610make_M(nffp_t *F, int trunc)1611{1612GEN bas = gel(F->basden,1), den = gel(F->basden,2), ro = F->ro;1613GEN m, d, M;1614long i, j, l = lg(ro), n = lg(bas);1615M = cgetg(n,t_MAT);1616gel(M,1) = const_col(l-1, gen_1); /* bas[1] = 1 */1617for (j=2; j<n; j++) gel(M,j) = cgetg(l,t_COL);1618for (i=1; i<l; i++)1619{1620GEN r = gel(ro,i), ri;1621ri = (gexpo(r) > 1)? ginv(r): NULL;1622for (j=2; j<n; j++) gcoeff(M,i,j) = RgX_cxeval(gel(bas,j), r, ri);1623}1624if (den)1625for (j=2; j<n; j++)1626{1627d = gel(den,j); if (!d) continue;1628m = gel(M,j);1629for (i=1; i<l; i++) gel(m,i) = gdiv(gel(m,i), d);1630}16311632if (trunc && gprecision(M) > F->prec)1633{1634M = gprec_w(M, F->prec);1635F->ro = gprec_w(ro,F->prec);1636}1637F->M = M;1638}16391640/* return G real such that G~ * G = T_2 */1641static void1642make_G(nffp_t *F)1643{1644GEN G, M = F->M;1645long i, j, k, r1 = F->r1, l = lg(M);16461647if (r1 == l-1) { F->G = M; return; }1648G = cgetg(l, t_MAT);1649for (j = 1; j < l; j++)1650{1651GEN g, m = gel(M,j);1652gel(G,j) = g = cgetg(l, t_COL);1653for (k = i = 1; i <= r1; i++) gel(g,k++) = gel(m,i);1654for ( ; k < l; i++)1655{1656GEN r = gel(m,i);1657if (typ(r) == t_COMPLEX)1658{1659GEN a = gel(r,1), b = gel(r,2);1660gel(g,k++) = mpadd(a, b);1661gel(g,k++) = mpsub(a, b);1662}1663else1664{1665gel(g,k++) = r;1666gel(g,k++) = r;1667}1668}1669}1670F->G = G;1671}16721673static long1674prec_fix(long prec)1675{1676#ifndef LONG_IS_64BIT1677/* make sure that default accuracy is the same on 32/64bit */1678if (odd(prec)) prec += EXTRAPRECWORD;1679#endif1680return prec;1681}1682static void1683make_M_G(nffp_t *F, int trunc)1684{1685long n, eBD, prec;1686if (F->extraprec < 0)1687{ /* not initialized yet; compute roots so that absolute accuracy1688* of M & G >= prec */1689double er;1690n = degpol(F->T);1691eBD = 1 + gexpo(gel(F->basden,1));1692er = F->ro? (1+gexpo(F->ro)): fujiwara_bound(F->T);1693if (er < 0) er = 0;1694F->extraprec = nbits2extraprec(n*er + eBD + log2(n));1695}1696prec = prec_fix(F->prec + F->extraprec);1697if (!F->ro || gprecision(gel(F->ro,1)) < prec)1698F->ro = get_roots(F->T, F->r1, prec);16991700make_M(F, trunc);1701make_G(F);1702}17031704static void1705nffp_init(nffp_t *F, nfmaxord_t *S, long prec)1706{1707F->T = S->T;1708F->r1 = S->r1;1709F->basden = S->basden;1710F->ro = NULL;1711F->extraprec = -1;1712F->prec = prec;1713}17141715/* let bas a t_VEC of QX giving a Z-basis of O_K. Return the index of the1716* basis. Assume bas[1] = 1 and that the leading coefficient of elements1717* of bas are of the form 1/b for a t_INT b */1718static GEN1719get_nfindex(GEN bas)1720{1721pari_sp av = avma;1722long n = lg(bas)-1, i;1723GEN D, d, mat;17241725/* assume bas[1] = 1 */1726D = gel(bas,1);1727if (! is_pm1(simplify_shallow(D))) pari_err_TYPE("get_nfindex", D);1728D = gen_1;1729for (i = 2; i <= n; i++)1730{ /* after nfbasis, basis is upper triangular! */1731GEN B = gel(bas,i), lc;1732if (degpol(B) != i-1) break;1733lc = gel(B, i+1);1734switch (typ(lc))1735{1736case t_INT: continue;1737case t_FRAC: if (is_pm1(gel(lc,1)) ) {D = mulii(D, gel(lc,2)); continue;}1738default: pari_err_TYPE("get_nfindex", B);1739}1740}1741if (i <= n)1742{ /* not triangular after all */1743bas = vecslice(bas,i,n);1744bas = Q_remove_denom(bas, &d);1745if (!d) return D;1746mat = RgV_to_RgM(bas, n);1747mat = rowslice(mat, i,n);1748D = mulii(D, diviiexact(powiu(d, n-i+1), absi_shallow(ZM_det(mat))));1749}1750return gerepileuptoint(av, D);1751}1752/* make sure all components of S are initialized */1753static void1754nfmaxord_complete(nfmaxord_t *S)1755{1756if (!S->dT) S->dT = ZX_disc(S->T);1757if (!S->index)1758{1759if (S->dK) /* fast */1760S->index = sqrti( diviiexact(S->dT, S->dK) );1761else1762S->index = get_nfindex(S->basis);1763}1764if (!S->dK) S->dK = diviiexact(S->dT, sqri(S->index));1765if (S->r1 < 0) S->r1 = ZX_sturm_irred(S->T);1766if (!S->basden) S->basden = get_bas_den(S->basis);1767}17681769GEN1770nfmaxord_to_nf(nfmaxord_t *S, GEN ro, long prec)1771{1772GEN nf = cgetg(10,t_VEC);1773GEN T = S->T, Tr, D, w, A, dA, MDI, mat = cgetg(9,t_VEC);1774long n = degpol(T);1775nffp_t F;1776nfmaxord_complete(S);1777nffp_init(&F,S,prec);1778F.ro = ro;1779make_M_G(&F, 0);17801781gel(nf,1) = S->T;1782gel(nf,2) = mkvec2s(S->r1, (n - S->r1)>>1);1783gel(nf,3) = S->dK;1784gel(nf,4) = S->index;1785gel(nf,5) = mat;1786if (gprecision(gel(F.ro,1)) > prec) F.ro = gprec_wtrunc(F.ro, prec);1787gel(nf,6) = F.ro;1788w = S->basis;1789if (!is_pm1(S->index)) w = Q_remove_denom(w, NULL);1790gel(nf,7) = w;1791gel(nf,8) = ZM_inv(RgV_to_RgM(w,n), NULL);1792gel(nf,9) = nf_multable(S, nf_get_invzk(nf));1793gel(mat,1) = F.M;1794gel(mat,2) = F.G;17951796Tr = get_Tr(gel(nf,9), T, S->basden);1797gel(mat,6) = A = ZM_inv(Tr, &dA); /* dA T^-1, primitive */1798A = ZM_hnfmodid(A, dA);1799/* CAVEAT: nf is not complete yet, but the fields needed for1800* idealtwoelt, zk_scalar_or_multable and idealinv are present ! */1801MDI = idealtwoelt(nf, A);1802gel(MDI,2) = zk_scalar_or_multable(nf, gel(MDI,2));1803gel(mat,7) = MDI;1804if (is_pm1(S->index))1805{ /* principal ideal (T'), whose norm is |dK| */1806D = zk_scalar_or_multable(nf, ZX_deriv(T));1807if (typ(D) == t_MAT) D = ZM_hnfmod(D, absi_shallow(S->dK));1808}1809else1810{1811GEN c = diviiexact(dA, gcoeff(A,1,1));1812D = idealHNF_inv_Z(nf, A); /* (A\cap Z) / A */1813if (!is_pm1(c)) D = ZM_Z_mul(D, c);1814}1815gel(mat,3) = RM_round_maxrank(F.G);1816gel(mat,4) = Tr;1817gel(mat,5) = D;1818gel(mat,8) = shallowtrans(S->dKP? S->dKP: gel(absZ_factor(S->dK), 1));1819return nf;1820}18211822static GEN1823primes_certify(GEN dK, GEN dKP)1824{1825long i, l = lg(dKP);1826GEN v, w, D = dK;1827v = vectrunc_init(l);1828w = vectrunc_init(l);1829for (i = 1; i < l; i++)1830{1831GEN p = gel(dKP,i);1832vectrunc_append(isprime(p)? w: v, p);1833(void)Z_pvalrem(D, p, &D);1834}1835if (!is_pm1(D))1836{1837if (signe(D) < 0) D = negi(D);1838vectrunc_append(isprime(D)? w: v, D);1839}1840return mkvec2(v,w);1841}1842GEN1843nfcertify(GEN nf)1844{1845pari_sp av = avma;1846GEN vw;1847nf = checknf(nf);1848vw = primes_certify(nf_get_disc(nf), nf_get_ramified_primes(nf));1849return gerepilecopy(av, gel(vw,1));1850}18511852/* set *pro to roots of S->T */1853static GEN1854get_red_G(nfmaxord_t *S, GEN *pro)1855{1856GEN G, u, u0 = NULL;1857pari_sp av;1858long i, prec, n = degpol(S->T);1859nffp_t F;18601861prec = nbits2prec(n+32);1862nffp_init(&F, S, prec);1863av = avma;1864for (i=1; ; i++)1865{1866F.prec = prec; make_M_G(&F, 0); G = F.G;1867if (u0) G = RgM_mul(G, u0);1868if (DEBUGLEVEL)1869err_printf("get_red_G: starting LLL, prec = %ld (%ld + %ld)\n",1870prec + F.extraprec, prec, F.extraprec);1871if ((u = lllfp(G, 0.99, LLL_KEEP_FIRST)))1872{1873if (lg(u)-1 == n) break;1874/* singular ==> loss of accuracy */1875if (u0) u0 = gerepileupto(av, RgM_mul(u0,u));1876else u0 = gerepilecopy(av, u);1877}1878prec = precdbl(prec) + nbits2extraprec(gexpo(u0));1879F.ro = NULL;1880if (DEBUGLEVEL) pari_warn(warnprec,"get_red_G", prec);1881}1882if (u0) u = RgM_mul(u0,u);1883*pro = F.ro; return u;1884}18851886/* Compute an LLL-reduced basis for the integer basis of nf(T).1887* set *pro = roots of x if computed [NULL if not computed] */1888static void1889set_LLL_basis(nfmaxord_t *S, GEN *pro, double DELTA)1890{1891GEN B = S->basis;1892long N = degpol(S->T);1893if (S->r1 < 0)1894{1895S->r1 = ZX_sturm_irred(S->T);1896if (odd(N - S->r1)) pari_err_IRREDPOL("set_LLL_basis", S->T);1897}1898if (!S->basden) S->basden = get_bas_den(B);1899if (S->r1 == N) {1900pari_sp av = avma;1901GEN u = ZM_lll(make_Tr(S), DELTA, LLL_GRAM|LLL_KEEP_FIRST|LLL_IM);1902B = gerepileupto(av, RgV_RgM_mul(B, u));1903*pro = NULL;1904}1905else1906B = RgV_RgM_mul(B, get_red_G(S, pro));1907S->basis = B;1908S->basden = get_bas_den(B);1909}19101911/* = 1 iff |a| > |b| or equality and a > 0 */1912static int1913cmpii_polred(GEN a, GEN b)1914{1915int fl = abscmpii(a, b);1916long sa, sb;1917if (fl) return fl;1918sa = signe(a);1919sb = signe(b);1920if (sa == sb) return 0;1921return sa == 1? 1: -1;1922}1923static int1924ZX_cmp(GEN x, GEN y)1925{ return gen_cmp_RgX((void*)cmpii_polred, x, y); }1926/* current best: ZX x of discriminant *dx, is ZX y better than x ?1927* (if so update *dx); both x and y are monic */1928static int1929ZX_is_better(GEN y, GEN x, GEN *dx)1930{1931GEN d = ZX_disc(y);1932int cmp;1933if (!*dx) *dx = ZX_disc(x);1934cmp = abscmpii(d, *dx);1935if (cmp < 0) { *dx = d; return 1; }1936return cmp? 0: (ZX_cmp(y, x) < 0);1937}19381939static void polredbest_aux(nfmaxord_t *S, GEN *pro, GEN *px, GEN *pdx, GEN *pa);1940/* Seek a simpler, polynomial pol defining the same number field as1941* x (assumed to be monic at this point) */1942static GEN1943nfpolred(nfmaxord_t *S, GEN *pro)1944{1945GEN x = S->T, dx, b, rev;1946long n = degpol(x), v = varn(x);19471948if (n == 1) {1949S->T = pol_x(v);1950*pro = NULL;1951return scalarpol_shallow(negi(gel(x,2)), v);1952}1953polredbest_aux(S, pro, &x, &dx, &b);1954if (x == S->T) return NULL; /* no improvement */1955if (DEBUGLEVEL>1) err_printf("xbest = %Ps\n",x);19561957/* update T */1958rev = QXQ_reverse(b, S->T);1959S->basis = QXV_QXQ_eval(S->basis, rev, x);1960S->index = sqrti( diviiexact(dx,S->dK) );1961S->basden = get_bas_den(S->basis);1962S->dT = dx;1963S->T = x;1964*pro = NULL; /* reset */1965return rev;1966}19671968/* Either nf type or ZX or [monic ZX, data], where data is either an integral1969* basis (deprecated), or listP data (nfbasis input format) to specify1970* a set of primes at with the basis order must be maximal.1971* 1) nf type (or unrecognized): return t_VEC1972* 2) ZX or [ZX, listP]: return t_POL1973* 3) [ZX, order basis]: return 0 (deprecated)1974* incorrect: return -1 */1975static long1976nf_input_type(GEN x)1977{1978GEN T, V, DKP = NULL;1979long i, d, v;1980switch(typ(x))1981{1982case t_POL: return t_POL;1983case t_VEC:1984switch(lg(x))1985{1986case 4: DKP = gel(x,3);1987case 3: break;1988default: return t_VEC; /* nf or incorrect */1989}1990T = gel(x,1); V = gel(x,2);1991if (typ(T) != t_POL) return -1;1992switch(typ(V))1993{1994case t_INT: case t_MAT: return t_POL;1995case t_VEC: case t_COL:1996if (RgV_is_ZV(V)) return t_POL;1997break;1998default: return -1;1999}2000d = degpol(T); v = varn(T);2001if (d<1 || !RgX_is_ZX(T) || !isint1(gel(T,d+2)) || lg(V)-1!=d) return -1;2002for (i = 1; i <= d; i++)2003{ /* check integer basis */2004GEN c = gel(V,i);2005switch(typ(c))2006{2007case t_INT: break;2008case t_POL: if (varn(c) == v && RgX_is_QX(c) && degpol(c) < d) break;2009/* fall through */2010default: return -1;2011}2012}2013if (DKP && (typ(DKP) != t_VEC || !RgV_is_ZV(DKP))) return -1;2014return 0;2015}2016return t_VEC; /* nf or incorrect */2017}20182019/* cater for obsolete nf_PARTIALFACT flag */2020static void2021nfinit_basic_partial(nfmaxord_t *S, GEN T)2022{2023if (typ(T) == t_POL) { nfmaxord(S, mkvec2(T,utoipos(500000)), 0); }2024else nfinit_basic(S, T);2025}2026/* true nf */2027static GEN2028nf_basden(GEN nf)2029{2030GEN zkD = nf_get_zkprimpart(nf), D = nf_get_zkden(nf);2031D = equali1(D)? NULL: const_vec(lg(zkD)-1, D);2032return mkvec2(zkD, D);2033}2034void2035nfinit_basic(nfmaxord_t *S, GEN T)2036{2037switch (nf_input_type(T))2038{2039case t_POL: nfmaxord(S, T, 0); return;2040case t_VEC:2041{ /* nf, bnf, bnr */2042GEN nf = checknf(T);2043S->T = S->T0 = nf_get_pol(nf);2044S->basis = nf_get_zk(nf); /* probably useless */2045S->basden = nf_basden(nf);2046S->index = nf_get_index(nf);2047S->dK = nf_get_disc(nf);2048S->dKP = nf_get_ramified_primes(nf);2049S->dT = mulii(S->dK, sqri(S->index));2050S->r1 = nf_get_r1(nf); break;2051}2052case 0: /* monic integral polynomial + integer basis (+ ramified primes)*/2053S->T = S->T0 = gel(T,1);2054S->basis = gel(T,2);2055S->basden = NULL;2056S->index = NULL;2057S->dK = NULL;2058S->dKP = lg(T) == 4? gel(T,3): NULL;2059S->dT = NULL;2060S->r1 = -1; break;2061default: /* -1 */2062pari_err_TYPE("nfinit_basic", T);2063}2064S->dTP = S->dTE = S->dKE = NULL;2065S->unscale = gen_1;2066}20672068GEN2069nfinit_complete(nfmaxord_t *S, long flag, long prec)2070{2071GEN nf, unscale;20722073if (!ZX_is_irred(S->T)) pari_err_IRREDPOL("nfinit",S->T);2074if (!(flag & nf_RED) && !ZX_is_monic(S->T0))2075{2076pari_warn(warner,"nonmonic polynomial. Result of the form [nf,c]");2077flag |= nf_RED | nf_ORIG;2078}2079unscale = S->unscale;2080if (!(flag & nf_RED) && !isint1(unscale))2081{ /* implies lc(x0) = 1 and L := 1/unscale is integral */2082long d = degpol(S->T0);2083GEN L = ginv(unscale); /* x = L^(-deg(x)) x0(L X) */2084GEN f= powiu(L, (d*(d-1)) >> 1);2085S->T = S->T0; /* restore original user-supplied x0, unscale data */2086S->unscale = gen_1;2087S->dT = gmul(S->dT, sqri(f));2088S->basis = RgXV_unscale(S->basis, unscale);2089S->index = gmul(S->index, f);2090}2091nfmaxord_complete(S); /* more expensive after set_LLL_basis */2092if (flag & nf_RED)2093{2094GEN ro, rev;2095/* lie to polred: more efficient to update *after* modreverse, than to2096* unscale in the polred subsystem */2097S->unscale = gen_1;2098rev = nfpolred(S, &ro);2099nf = nfmaxord_to_nf(S, ro, prec);2100if (flag & nf_ORIG)2101{2102if (!rev) rev = pol_x(varn(S->T)); /* no improvement */2103if (!isint1(unscale)) rev = RgX_Rg_div(rev, unscale);2104nf = mkvec2(nf, mkpolmod(rev, S->T));2105}2106S->unscale = unscale; /* restore */2107} else {2108GEN ro; set_LLL_basis(S, &ro, 0.99);2109nf = nfmaxord_to_nf(S, ro, prec);2110}2111return nf;2112}2113/* Initialize the number field defined by the polynomial x (in variable v)2114* flag & nf_RED: try a polred first.2115* flag & nf_ORIG2116* do a polred and return [nfinit(x), Mod(a,red)], where2117* Mod(a,red) = Mod(v,x) (i.e return the base change). */2118GEN2119nfinitall(GEN x, long flag, long prec)2120{2121const pari_sp av = avma;2122nfmaxord_t S;2123GEN nf;21242125if (checkrnf_i(x)) return rnf_build_nfabs(x, prec);2126nfinit_basic(&S, x);2127nf = nfinit_complete(&S, flag, prec);2128return gerepilecopy(av, nf);2129}21302131GEN2132nfinitred(GEN x, long prec) { return nfinitall(x, nf_RED, prec); }2133GEN2134nfinitred2(GEN x, long prec) { return nfinitall(x, nf_RED|nf_ORIG, prec); }2135GEN2136nfinit(GEN x, long prec) { return nfinitall(x, 0, prec); }21372138GEN2139nfinit0(GEN x, long flag,long prec)2140{2141switch(flag)2142{2143case 0:2144case 1: return nfinitall(x,0,prec);2145case 2: case 4: return nfinitall(x,nf_RED,prec);2146case 3: case 5: return nfinitall(x,nf_RED|nf_ORIG,prec);2147default: pari_err_FLAG("nfinit");2148}2149return NULL; /* LCOV_EXCL_LINE */2150}21512152/* assume x a bnr/bnf/nf */2153long2154nf_get_prec(GEN x)2155{2156GEN nf = checknf(x), ro = nf_get_roots(nf);2157return (typ(ro)==t_VEC)? precision(gel(ro,1)): DEFAULTPREC;2158}21592160/* true nf */2161GEN2162nfnewprec_shallow(GEN nf, long prec)2163{2164GEN m, NF = leafcopy(nf);2165nffp_t F;21662167F.T = nf_get_pol(nf);2168F.ro = NULL;2169F.r1 = nf_get_r1(nf);2170F.basden = nf_basden(nf);2171F.extraprec = -1;2172F.prec = prec; make_M_G(&F, 0);2173gel(NF,5) = m = leafcopy(gel(NF,5));2174gel(m,1) = F.M;2175gel(m,2) = F.G;2176gel(NF,6) = F.ro; return NF;2177}21782179GEN2180nfnewprec(GEN nf, long prec)2181{2182GEN z;2183switch(nftyp(nf))2184{2185default: pari_err_TYPE("nfnewprec", nf);2186case typ_BNF: z = bnfnewprec(nf,prec); break;2187case typ_BNR: z = bnrnewprec(nf,prec); break;2188case typ_NF: {2189pari_sp av = avma;2190z = gerepilecopy(av, nfnewprec_shallow(checknf(nf), prec));2191break;2192}2193}2194return z;2195}21962197/********************************************************************/2198/** **/2199/** POLRED **/2200/** **/2201/********************************************************************/2202GEN2203embednorm_T2(GEN x, long r1)2204{2205pari_sp av = avma;2206GEN p = RgV_sumpart(x, r1);2207GEN q = RgV_sumpart2(x,r1+1, lg(x)-1);2208if (q != gen_0) p = gadd(p, gmul2n(q,1));2209return avma == av? gcopy(p): gerepileupto(av, p);2210}22112212/* simplified version of gnorm for scalar, noncomplex inputs, without GC */2213static GEN2214real_norm(GEN x)2215{2216switch(typ(x))2217{2218case t_INT: return sqri(x);2219case t_REAL: return sqrr(x);2220case t_FRAC: return sqrfrac(x);2221}2222pari_err_TYPE("real_norm", x);2223return NULL;/*LCOV_EXCL_LINE*/2224}2225/* simplified version of gnorm, without GC */2226static GEN2227complex_norm(GEN x)2228{2229return typ(x) == t_COMPLEX? cxnorm(x): real_norm(x);2230}2231/* return T2(x), argument r1 needed in case x has components whose type2232* is unexpected, e.g. all of them t_INT for embed(gen_1) */2233GEN2234embed_T2(GEN x, long r1)2235{2236pari_sp av = avma;2237long i, l = lg(x);2238GEN c, s = NULL, t = NULL;2239if (typ(gel(x,1)) == t_INT) return muliu(gel(x,1), 2*(l-1)-r1);2240for (i = 1; i <= r1; i++)2241{2242c = real_norm(gel(x,i));2243s = s? gadd(s, c): c;2244}2245for (; i < l; i++)2246{2247c = complex_norm(gel(x,i));2248t = t? gadd(t, c): c;2249}2250if (t) { t = gmul2n(t,1); s = s? gadd(s,t): t; }2251return gerepileupto(av, s);2252}2253/* return N(x) */2254GEN2255embed_norm(GEN x, long r1)2256{2257pari_sp av = avma;2258long i, l = lg(x);2259GEN c, s = NULL, t = NULL;2260if (typ(gel(x,1)) == t_INT) return powiu(gel(x,1), 2*(l-1)-r1);2261for (i = 1; i <= r1; i++)2262{2263c = gel(x,i);2264s = s? gmul(s, c): c;2265}2266for (; i < l; i++)2267{2268c = complex_norm(gel(x,i));2269t = t? gmul(t, c): c;2270}2271if (t) s = s? gmul(s,t): t;2272return gerepileupto(av, s);2273}22742275typedef struct {2276long r1, v, prec;2277GEN ZKembed; /* embeddings of fincke-pohst-reduced Zk basis */2278GEN u; /* matrix giving fincke-pohst-reduced Zk basis */2279GEN M; /* embeddings of initial (LLL-reduced) Zk basis */2280GEN bound; /* T2 norm of the polynomial defining nf */2281long expo_best_disc; /* expo(disc(x)), best generator so far */2282} CG_data;22832284/* characteristic pol of x (given by embeddings) */2285static GEN2286get_pol(CG_data *d, GEN x)2287{2288long e;2289GEN g = grndtoi(roots_to_pol_r1(x, d->v, d->r1), &e);2290return (e > -5)? NULL: g;2291}22922293/* characteristic pol of x (given as vector on (w_i)) */2294static GEN2295get_polchar(CG_data *d, GEN x)2296{ return get_pol(d, RgM_RgC_mul(d->ZKembed,x)); }22972298/* Choose a canonical polynomial in the pair { Pmin_a, Pmin_{-a} }, i.e.2299* { z(X), (-1)^(deg z) z(-Z) } and keeping the smallest wrt cmpii_polred2300* Either leave z alone (return 1) or set z <- (-1)^n z(-X). In place. */2301static int2302ZX_canon_neg(GEN z)2303{2304long i, s;2305for (i = lg(z)-2; i >= 2; i -= 2)2306{ /* examine the odd (resp. even) part of z if deg(z) even (resp. odd). */2307s = signe(gel(z,i));2308if (!s) continue;2309/* non trivial */2310if (s < 0) break; /* z(X) < (-1)^n z(-X) */23112312for (; i>=2; i-=2) gel(z,i) = negi(gel(z,i));2313return 1;2314}2315return 0;2316}2317/* return a defining polynomial for Q(alpha), v = embeddings of alpha.2318* Return NULL on failure: discriminant too large or non primitive */2319static GEN2320try_polmin(CG_data *d, nfmaxord_t *S, GEN v, long flag, GEN *ai)2321{2322const long best = flag & nf_ABSOLUTE;2323long ed;2324pari_sp av = avma;2325GEN g;2326if (best)2327{2328ed = expo(embed_disc(v, d->r1, LOWDEFAULTPREC));2329set_avma(av); if (d->expo_best_disc < ed) return NULL;2330}2331else2332ed = 0;2333g = get_pol(d, v);2334/* accuracy too low, compute algebraically */2335if (!g) { set_avma(av); g = ZXQ_charpoly(*ai, S->T, varn(S->T)); }2336g = ZX_radical(g);2337if (best && degpol(g) != degpol(S->T)) return gc_NULL(av);2338g = gerepilecopy(av, g);2339d->expo_best_disc = ed;2340if (flag & nf_ORIG)2341{2342if (ZX_canon_neg(g)) *ai = RgX_neg(*ai);2343if (!isint1(S->unscale)) *ai = RgX_unscale(*ai, S->unscale);2344}2345else2346(void)ZX_canon_neg(g);2347if (DEBUGLEVEL>3) err_printf("polred: generator %Ps\n", g);2348return g;2349}23502351/* does x generate the correct field ? */2352static GEN2353chk_gen(void *data, GEN x)2354{2355pari_sp av = avma, av1;2356GEN h, g = get_polchar((CG_data*)data,x);2357if (!g) pari_err_PREC("chk_gen");2358av1 = avma;2359h = ZX_gcd(g, ZX_deriv(g));2360if (degpol(h)) return gc_NULL(av);2361if (DEBUGLEVEL>3) err_printf(" generator: %Ps\n",g);2362set_avma(av1); return gerepileupto(av, g);2363}23642365static long2366chk_gen_prec(long N, long bit)2367{ return prec_fix(nbits2prec(10 + (long)log2((double)N) + bit)); }23682369/* v = [P,A] two vectors (of ZX and ZV resp.) of same length; remove duplicate2370* polynomials in P, updating A, in place. Among elements having the same2371* characteristic pol, choose the smallest according to ZV_abscmp */2372static void2373remove_duplicates(GEN v)2374{2375GEN x, a, P = gel(v,1), A = gel(v,2);2376long k, i, l = lg(P);2377pari_sp av = avma;23782379if (l < 2) return;2380(void)sort_factor_pol(mkvec2(P, A), cmpii);2381x = gel(P,1); a = gel(A,1);2382for (k=1,i=2; i<l; i++)2383if (ZX_equal(gel(P,i), x))2384{2385if (ZV_abscmp(gel(A,i), a) < 0) a = gel(A,i);2386}2387else2388{2389gel(A,k) = a;2390gel(P,k) = x;2391k++;2392x = gel(P,i); a = gel(A,i);2393}2394l = k+1;2395gel(A,k) = a; setlg(A,l);2396gel(P,k) = x; setlg(P,l); set_avma(av);2397}23982399static void2400polred_init(nfmaxord_t *S, nffp_t *F, CG_data *d)2401{2402long e, prec, n = degpol(S->T);2403double log2rho;2404GEN ro;2405set_LLL_basis(S, &ro, 0.9999);2406/* || polchar ||_oo < 2^e ~ 2 (n * rho)^n, rho = max modulus of root */2407log2rho = ro ? (double)gexpo(ro): fujiwara_bound(S->T);2408e = n * (long)(log2rho + log2((double)n)) + 1;2409if (e < 0) e = 0; /* can occur if n = 1 */2410prec = chk_gen_prec(n, e);2411nffp_init(F,S,prec);2412F->ro = ro;2413make_M_G(F, 1);24142415d->v = varn(S->T);2416d->expo_best_disc = -1;2417d->ZKembed = NULL;2418d->M = NULL;2419d->u = NULL;2420d->r1= S->r1;2421}2422static GEN2423findmindisc(GEN y)2424{2425GEN x = gel(y,1), dx = NULL;2426long i, l = lg(y);2427for (i = 2; i < l; i++)2428{2429GEN yi = gel(y,i);2430if (ZX_is_better(yi,x,&dx)) x = yi;2431}2432return x;2433}2434/* filter [y,b] from polred_aux: keep a single polynomial of degree n in y2435* [ the best wrt discriminant ordering ], but keep all imprimitive2436* polynomials */2437static void2438filter(GEN y, GEN b, long n)2439{2440GEN x, a, dx;2441long i, k = 1, l = lg(y);2442a = x = dx = NULL;2443for (i = 1; i < l; i++)2444{2445GEN yi = gel(y,i), ai = gel(b,i);2446if (degpol(yi) == n)2447{2448pari_sp av = avma;2449if (!dx) dx = ZX_disc(yi);2450else if (!ZX_is_better(yi,x,&dx)) { set_avma(av); continue; }2451x = yi; a = ai; continue;2452}2453gel(y,k) = yi;2454gel(b,k) = ai; k++;2455}2456if (dx)2457{2458gel(y,k) = x;2459gel(b,k) = a; k++;2460}2461setlg(y, k);2462setlg(b, k);2463}24642465static GEN2466polred_aux(nfmaxord_t *S, GEN *pro, long flag)2467{ /* only keep polynomials of max degree and best discriminant */2468const long best = flag & nf_ABSOLUTE;2469const long orig = flag & nf_ORIG;2470GEN M, b, y, x = S->T;2471long maxi, i, j, k, v = varn(x), n = lg(S->basis)-1;2472nffp_t F;2473CG_data d;24742475if (n == 1)2476{2477if (!best)2478{2479GEN X = pol_x(v);2480return orig? mkmat2(mkcol(X),mkcol(gen_1)): mkvec(X);2481}2482else2483return orig? trivial_fact(): cgetg(1,t_VEC);2484}24852486polred_init(S, &F, &d);2487if (pro) *pro = F.ro;2488M = F.M;2489if (best)2490{2491if (!S->dT) S->dT = ZX_disc(S->T);2492d.expo_best_disc = expi(S->dT);2493}24942495/* n + 2 sum_{1 <= i <= n} n-i = n + n(n-1) = n*n */2496y = cgetg(n*n + 1, t_VEC);2497b = cgetg(n*n + 1, t_COL);2498k = 1;2499if (!best) { gel(y,1) = pol_x(v); gel(b,1) = gen_0; k++; }2500for (i = 2; i <= n; i++)2501{2502GEN ch, ai;2503ai = gel(S->basis,i);2504ch = try_polmin(&d, S, gel(M,i), flag, &ai);2505if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }2506}2507maxi = minss(n, 3);2508for (i = 1; i <= maxi; i++)2509for (j = i+1; j <= n; j++)2510{2511GEN ch, ai, v;2512ai = gadd(gel(S->basis,i), gel(S->basis,j));2513v = RgV_add(gel(M,i), gel(M,j));2514/* defining polynomial for Q(w_i+w_j) */2515ch = try_polmin(&d, S, v, flag, &ai);2516if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }25172518ai = gsub(gel(S->basis,i), gel(S->basis,j));2519v = RgV_sub(gel(M,i), gel(M,j));2520/* defining polynomial for Q(w_i-w_j) */2521ch = try_polmin(&d, S, v, flag, &ai);2522if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }2523}2524setlg(y, k);2525setlg(b, k); filter(y, b, n);2526if (!orig) return gen_sort_uniq(y, (void*)cmpii, &gen_cmp_RgX);2527settyp(y, t_COL);2528(void)sort_factor_pol(mkmat2(y, b), cmpii);2529return mkmat2(b, y);2530}25312532/* FIXME: obsolete */2533static GEN2534Polred(GEN x, long flag, GEN fa)2535{2536pari_sp av = avma;2537nfmaxord_t S;2538if (fa)2539nfinit_basic(&S, mkvec2(x,fa));2540else if (flag & nf_PARTIALFACT)2541nfinit_basic_partial(&S, x);2542else2543nfinit_basic(&S, x);2544return gerepilecopy(av, polred_aux(&S, NULL, flag));2545}25462547/* finds "best" polynomial in polred_aux list, defaulting to S->T if none of2548* them is primitive. *px is the ZX, characteristic polynomial of Mod(*pb,S->T),2549* *pdx its discriminant if pdx != NULL. Set *pro = polroots(S->T) */2550static void2551polredbest_aux(nfmaxord_t *S, GEN *pro, GEN *px, GEN *pdx, GEN *pb)2552{2553GEN y, dx, x = S->T; /* default value */2554long i, l;2555y = polred_aux(S, pro, pb? nf_ORIG|nf_ABSOLUTE: nf_ABSOLUTE);2556dx = S->dT;2557if (pb)2558{2559GEN a, b = deg1pol_shallow(S->unscale, gen_0, varn(x));2560a = gel(y,1); l = lg(a);2561y = gel(y,2);2562for (i=1; i<l; i++)2563{2564GEN yi = gel(y,i);2565pari_sp av = avma;2566if (ZX_is_better(yi,x,&dx)) { x = yi; b = gel(a,i); } else set_avma(av);2567}2568*pb = b;2569}2570else2571{2572l = lg(y);2573for (i=1; i<l; i++)2574{2575GEN yi = gel(y,i);2576pari_sp av = avma;2577if (ZX_is_better(yi,x,&dx)) x = yi; else set_avma(av);2578}2579}2580if (pdx) { if (!dx) dx = ZX_disc(x); *pdx = dx; }2581*px = x;2582}2583static GEN2584polredbest_i(GEN T0, long flag)2585{2586GEN T = T0, a;2587nfmaxord_t S;2588nfinit_basic_partial(&S, T);2589polredbest_aux(&S, NULL, &T, NULL, flag? &a: NULL);2590if (flag == 2)2591T = mkvec2(T, a);2592else if (flag == 1)2593{2594GEN b = (T0 == T)? pol_x(varn(T)): QXQ_reverse(a, T0);2595/* charpoly(Mod(a,T0)) = T; charpoly(Mod(b,T)) = S.x */2596if (degpol(T) == 1) b = grem(b,T);2597T = mkvec2(T, mkpolmod(b,T));2598}2599return T;2600}2601GEN2602polredbest(GEN T, long flag)2603{2604pari_sp av = avma;2605if (flag < 0 || flag > 1) pari_err_FLAG("polredbest");2606return gerepilecopy(av, polredbest_i(T, flag));2607}2608/* DEPRECATED: backward compatibility */2609GEN2610polred0(GEN x, long flag, GEN fa)2611{2612long fl = 0;2613if (flag & 1) fl |= nf_PARTIALFACT;2614if (flag & 2) fl |= nf_ORIG;2615return Polred(x, fl, fa);2616}26172618GEN2619polredord(GEN x)2620{2621pari_sp av = avma;2622GEN v, lt;2623long i, n, vx;26242625if (typ(x) != t_POL) pari_err_TYPE("polredord",x);2626x = Q_primpart(x); RgX_check_ZX(x,"polredord");2627n = degpol(x); if (n <= 0) pari_err_CONSTPOL("polredord");2628if (n == 1) return gerepilecopy(av, mkvec(x));2629lt = leading_coeff(x); vx = varn(x);2630if (is_pm1(lt))2631{2632if (signe(lt) < 0) x = ZX_neg(x);2633v = pol_x_powers(n, vx);2634}2635else2636{ GEN L;2637/* basis for Dedekind order */2638v = cgetg(n+1, t_VEC);2639gel(v,1) = scalarpol_shallow(lt, vx);2640for (i = 2; i <= n; i++)2641gel(v,i) = RgX_Rg_add(RgX_mulXn(gel(v,i-1), 1), gel(x,n+3-i));2642gel(v,1) = pol_1(vx);2643x = ZX_Q_normalize(x, &L);2644v = gsubst(v, vx, monomial(ginv(L),1,vx));2645for (i=2; i <= n; i++)2646if (Q_denom(gel(v,i)) == gen_1) gel(v,i) = pol_xn(i-1, vx);2647}2648return gerepileupto(av, polred(mkvec2(x, v)));2649}26502651GEN2652polred(GEN x) { return Polred(x, 0, NULL); }2653GEN2654smallpolred(GEN x) { return Polred(x, nf_PARTIALFACT, NULL); }2655GEN2656factoredpolred(GEN x, GEN fa) { return Polred(x, 0, fa); }2657GEN2658polred2(GEN x) { return Polred(x, nf_ORIG, NULL); }2659GEN2660smallpolred2(GEN x) { return Polred(x, nf_PARTIALFACT|nf_ORIG, NULL); }2661GEN2662factoredpolred2(GEN x, GEN fa) { return Polred(x, nf_PARTIALFACT, fa); }26632664/********************************************************************/2665/** **/2666/** POLREDABS **/2667/** **/2668/********************************************************************/2669/* set V[k] := matrix of multiplication by nk.zk[k] */2670static GEN2671set_mulid(GEN V, GEN M, GEN Mi, long r1, long r2, long N, long k)2672{2673GEN v, Mk = cgetg(N+1, t_MAT);2674long i, e;2675for (i = 1; i < k; i++) gel(Mk,i) = gmael(V, i, k);2676for ( ; i <=N; i++)2677{2678v = vecmul(gel(M,k), gel(M,i));2679v = RgM_RgC_mul(Mi, split_realimag(v, r1, r2));2680gel(Mk,i) = grndtoi(v, &e);2681if (e > -5) return NULL;2682}2683gel(V,k) = Mk; return Mk;2684}26852686static GEN2687ZM_image_shallow(GEN M, long *pr)2688{2689long j, k, r;2690GEN y, d = ZM_pivots(M, &k);2691r = lg(M)-1 - k;2692y = cgetg(r+1,t_MAT);2693for (j=k=1; j<=r; k++)2694if (d[k]) gel(y,j++) = gel(M,k);2695*pr = r; return y;2696}26972698/* U = base change matrix, R = Cholesky form of the quadratic form [matrix2699* Q from algo 2.7.6] */2700static GEN2701chk_gen_init(FP_chk_fun *chk, GEN R, GEN U)2702{2703CG_data *d = (CG_data*)chk->data;2704GEN P, V, D, inv, bound, S, M;2705long N = lg(U)-1, r1 = d->r1, r2 = (N-r1)>>1;2706long i, j, prec, firstprim = 0, skipfirst = 0;2707pari_sp av;27082709d->u = U;2710d->ZKembed = M = RgM_mul(d->M, U);27112712av = avma; bound = d->bound;2713D = cgetg(N+1, t_VECSMALL);2714for (i = 1; i <= N; i++)2715{2716pari_sp av2 = avma;2717P = get_pol(d, gel(M,i));2718if (!P) pari_err_PREC("chk_gen_init");2719P = gerepilecopy(av2, ZX_radical(P));2720D[i] = degpol(P);2721if (D[i] == N)2722{ /* primitive element */2723GEN B = embed_T2(gel(M,i), r1);2724if (!firstprim) firstprim = i; /* index of first primitive element */2725if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P);2726if (gcmp(B,bound) < 0) bound = gerepileuptoleaf(av2, B);2727}2728else2729{2730if (DEBUGLEVEL>2) err_printf("chk_gen_init: subfield %Ps\n",P);2731if (firstprim)2732{ /* cycle basis vectors so that primitive elements come last */2733GEN u = d->u, e = M;2734GEN te = gel(e,i), tu = gel(u,i), tR = gel(R,i);2735long tS = D[i];2736for (j = i; j > firstprim; j--)2737{2738u[j] = u[j-1];2739e[j] = e[j-1];2740R[j] = R[j-1];2741D[j] = D[j-1];2742}2743gel(u,firstprim) = tu;2744gel(e,firstprim) = te;2745gel(R,firstprim) = tR;2746D[firstprim] = tS; firstprim++;2747}2748}2749}2750if (!firstprim)2751{ /* try (a little) to find primitive elements to improve bound */2752GEN x = cgetg(N+1, t_VECSMALL);2753if (DEBUGLEVEL>1)2754err_printf("chk_gen_init: difficult field, trying random elements\n");2755for (i = 0; i < 10; i++)2756{2757GEN e, B;2758for (j = 1; j <= N; j++) x[j] = (long)random_Fl(7) - 3;2759e = RgM_zc_mul(M, x);2760B = embed_T2(e, r1);2761if (gcmp(B,bound) >= 0) continue;2762P = get_pol(d, e); if (!P) pari_err_PREC( "chk_gen_init");2763if (!ZX_is_squarefree(P)) continue;2764if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P);2765bound = B ;2766}2767}27682769if (firstprim != 1)2770{2771inv = ginv( split_realimag(M, r1, r2) ); /*TODO: use QR?*/2772V = gel(inv,1);2773for (i = 2; i <= r1+r2; i++) V = gadd(V, gel(inv,i));2774/* V corresponds to 1_Z */2775V = grndtoi(V, &j);2776if (j > -5) pari_err_BUG("precision too low in chk_gen_init");2777S = mkmat(V); /* 1 */27782779V = cgetg(N+1, t_VEC);2780for (i = 1; i <= N; i++,skipfirst++)2781{ /* S = Q-basis of subfield generated by nf.zk[1..i-1] */2782GEN Mx, M2;2783long j, k, h, rkM, dP = D[i];27842785if (dP == N) break; /* primitive */2786Mx = set_mulid(V, M, inv, r1, r2, N, i);2787if (!Mx) break; /* prec. problem. Stop */2788if (dP == 1) continue;2789rkM = lg(S)-1;2790M2 = cgetg(N+1, t_MAT); /* we will add to S the elts of M2 */2791gel(M2,1) = col_ei(N, i); /* nf.zk[i] */2792k = 2;2793for (h = 1; h < dP; h++)2794{2795long r; /* add to M2 the elts of S * nf.zk[i] */2796for (j = 1; j <= rkM; j++) gel(M2,k++) = ZM_ZC_mul(Mx, gel(S,j));2797setlg(M2, k); k = 1;2798S = ZM_image_shallow(shallowconcat(S,M2), &r);2799if (r == rkM) break;2800if (r > rkM)2801{2802rkM = r;2803if (rkM == N) break;2804}2805}2806if (rkM == N) break;2807/* Q(w[1],...,w[i-1]) is a strict subfield of nf */2808}2809}2810/* x_1,...,x_skipfirst generate a strict subfield [unless N=skipfirst=1] */2811chk->skipfirst = skipfirst;2812if (DEBUGLEVEL>2) err_printf("chk_gen_init: skipfirst = %ld\n",skipfirst);28132814/* should be DEF + gexpo( max_k C^n_k (bound/k)^(k/2) ) */2815bound = gerepileuptoleaf(av, bound);2816prec = chk_gen_prec(N, (gexpo(bound)*N)/2);2817if (DEBUGLEVEL)2818err_printf("chk_gen_init: new prec = %ld (initially %ld)\n", prec, d->prec);2819if (prec > d->prec) pari_err_BUG("polredabs (precision problem)");2820if (prec < d->prec) d->ZKembed = gprec_w(M, prec);2821return bound;2822}28232824static GEN2825polredabs_i(GEN x, nfmaxord_t *S, GEN *u, long flag)2826{2827FP_chk_fun chk = { &chk_gen, &chk_gen_init, NULL, NULL, 0 };2828nffp_t F;2829CG_data d;2830GEN v, y, a;2831long i, l;28322833nfinit_basic_partial(S, x);2834x = S->T0;2835if (degpol(x) == 1)2836{2837long vx = varn(x);2838*u = NULL;2839return mkvec2(mkvec( pol_x(vx) ),2840mkvec( deg1pol_shallow(gen_1, negi(gel(S->T,2)), vx) ));2841}2842if (!(flag & nf_PARTIALFACT) && S->dK && S->dKP)2843{2844GEN vw = primes_certify(S->dK, S->dKP);2845v = gel(vw,1); l = lg(v);2846if (l != 1)2847{ /* fix integral basis */2848GEN w = gel(vw,2);2849for (i = 1; i < l; i++)2850w = ZV_union_shallow(w, gel(Z_factor(gel(v,i)),1));2851nfinit_basic(S, mkvec2(S->T0,w));2852}2853}28542855chk.data = (void*)&d;2856polred_init(S, &F, &d);2857d.bound = embed_T2(F.ro, d.r1);2858if (realprec(d.bound) > F.prec) d.bound = rtor(d.bound, F.prec);2859for (;;)2860{2861GEN R = R_from_QR(F.G, F.prec);2862if (R)2863{2864d.prec = F.prec;2865d.M = F.M;2866v = fincke_pohst(mkvec(R),NULL,-1, 0, &chk);2867if (v) break;2868}2869F.prec = precdbl(F.prec);2870F.ro = NULL;2871make_M_G(&F, 1);2872if (DEBUGLEVEL) pari_warn(warnprec,"polredabs0",F.prec);2873}2874y = gel(v,1);2875a = gel(v,2); l = lg(a);2876for (i = 1; i < l; i++) /* normalize wrt z -> -z */2877if (ZX_canon_neg(gel(y,i)) && (flag & (nf_ORIG|nf_RAW)))2878gel(a,i) = ZC_neg(gel(a,i));2879*u = d.u; return v;2880}28812882GEN2883polredabs0(GEN x, long flag)2884{2885pari_sp av = avma;2886GEN Y, A, u, v;2887nfmaxord_t S;2888long i, l;28892890v = polredabs_i(x, &S, &u, flag);2891remove_duplicates(v);2892Y = gel(v,1);2893A = gel(v,2);2894l = lg(A); if (l == 1) pari_err_BUG("polredabs (missing vector)");2895if (DEBUGLEVEL) err_printf("Found %ld minimal polynomials.\n",l-1);2896if (!(flag & nf_ALL))2897{2898GEN y = findmindisc(Y);2899for (i = 1; i < l; i++)2900if (ZX_equal(gel(Y,i), y)) break;2901Y = mkvec(gel(Y,i));2902A = mkvec(gel(A,i)); l = 2;2903}2904if (flag & (nf_RAW|nf_ORIG)) for (i = 1; i < l; i++)2905{2906GEN y = gel(Y,i), a = gel(A,i);2907if (u) a = RgV_RgC_mul(S.basis, ZM_ZC_mul(u, a));2908if (flag & nf_ORIG)2909{2910a = QXQ_reverse(a, S.T);2911if (!isint1(S.unscale)) a = gdiv(a, S.unscale); /* not RgX_Rg_div */2912a = mkpolmod(a,y);2913}2914gel(Y,i) = mkvec2(y, a);2915}2916return gerepilecopy(av, (flag & nf_ALL)? Y: gel(Y,1));2917}29182919GEN2920polredabsall(GEN x, long flun) { return polredabs0(x, flun | nf_ALL); }2921GEN2922polredabs(GEN x) { return polredabs0(x,0); }2923GEN2924polredabs2(GEN x) { return polredabs0(x,nf_ORIG); }29252926/* relative polredabs/best. Returns relative polynomial by default (flag = 0)2927* flag & nf_ORIG: + element (base change)2928* flag & nf_ABSOLUTE: absolute polynomial */2929static GEN2930rnfpolred_i(GEN nf, GEN R, long flag, long best)2931{2932const char *f = best? "rnfpolredbest": "rnfpolredabs";2933const long abs = ((flag & nf_ORIG) && (flag & nf_ABSOLUTE));2934GEN listP = NULL, red, pol, A, P, T, rnfeq;2935pari_sp av = avma;29362937if (typ(R) == t_VEC) {2938if (lg(R) != 3) pari_err_TYPE(f,R);2939listP = gel(R,2);2940R = gel(R,1);2941}2942if (typ(R) != t_POL) pari_err_TYPE(f,R);2943nf = checknf(nf);2944T = nf_get_pol(nf);2945R = RgX_nffix(f, T, R, 0);2946if (best || (flag & nf_PARTIALFACT))2947{2948rnfeq = abs? nf_rnfeq(nf, R): nf_rnfeqsimple(nf, R);2949pol = gel(rnfeq,1);2950if (listP) pol = mkvec2(pol, listP);2951red = best? polredbest_i(pol, abs? 1: 2)2952: polredabs0(pol, (abs? nf_ORIG: nf_RAW)|nf_PARTIALFACT);2953P = gel(red,1);2954A = gel(red,2);2955}2956else2957{2958nfmaxord_t S;2959GEN rnf, u, v, y, a;2960long i, j, l;2961pari_timer ti;2962if (DEBUGLEVEL>1) timer_start(&ti);2963rnf = rnfinit(nf, R);2964rnfeq = rnf_get_map(rnf);2965pol = rnf_zkabs(rnf);2966if (DEBUGLEVEL>1) timer_printf(&ti, "absolute basis");2967v = polredabs_i(pol, &S, &u, nf_ORIG);2968pol = gel(pol,1);2969y = gel(v,1); P = findmindisc(y);2970a = gel(v,2);2971l = lg(y); A = cgetg(l, t_VEC);2972for (i = j = 1; i < l; i++)2973if (ZX_equal(gel(y,i),P))2974{2975GEN t = gel(a,i);2976if (u) t = RgV_RgC_mul(S.basis, ZM_ZC_mul(u,t));2977gel(A,j++) = t;2978}2979setlg(A,j); /* mod(A[i], pol) are all roots of P in Q[X]/(pol) */2980}2981if (DEBUGLEVEL>1) err_printf("reduced absolute generator: %Ps\n",P);2982if (flag & nf_ABSOLUTE)2983{2984if (flag & nf_ORIG)2985{2986GEN a = gel(rnfeq,2); /* Mod(a,pol) root of T */2987GEN k = gel(rnfeq,3); /* Mod(variable(R),R) + k*a root of pol */2988if (typ(A) == t_VEC) A = gel(A,1); /* any root will do */2989a = RgX_RgXQ_eval(a, lift_shallow(A), P); /* Mod(a, P) root of T */2990P = mkvec3(P, mkpolmod(a,P), gsub(A, gmul(k,a)));2991}2992return gerepilecopy(av, P);2993}2994if (typ(A) != t_VEC)2995{2996A = eltabstorel_lift(rnfeq, A);2997P = lift_if_rational( RgXQ_charpoly(A, R, varn(R)) );2998}2999else3000{ /* canonical factor */3001long i, l = lg(A), v = varn(R);3002GEN besta = NULL;3003for (i = 1; i < l; i++)3004{3005GEN a = eltabstorel_lift(rnfeq, gel(A,i));3006GEN p = lift_if_rational( RgXQ_charpoly(a, R, v) );3007if (i == 1 || cmp_universal(p, P) < 0) { P = p; besta = a; }3008}3009A = besta;3010}3011if (flag & nf_ORIG) P = mkvec2(P, mkpolmod(RgXQ_reverse(A,R),P));3012return gerepilecopy(av, P);3013}3014GEN3015rnfpolredabs(GEN nf, GEN R, long flag)3016{ return rnfpolred_i(nf,R,flag, 0); }3017GEN3018rnfpolredbest(GEN nf, GEN R, long flag)3019{3020if (flag < 0 || flag > 3) pari_err_FLAG("rnfpolredbest");3021return rnfpolred_i(nf,R,flag, 1);3022}302330243025