Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2009 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"1617#define DEBUGLEVEL DEBUGLEVEL_padicfields1819/************************************************************/20/* Computation of all the extensions of a given */21/* degree of a p-adic field */22/* Xavier Roblot */23/************************************************************/24/* cf. Math. Comp, vol. 70, No. 236, pp. 1641-1659 for more details.25Note that n is now e (since the e from the paper is always = 1) and l26is now f */27/* Structure for a given type of extension */28typedef struct {29GEN p;30long e, f, j;31long a, b, c;32long v; /* auxiliary variable */33long r; /* pr = p^r */34GEN pr; /* p-adic precision for poly. reduction */35GEN q, qm1; /* p^f, q - 1 */36GEN T; /* polynomial defining K^ur */37GEN frob; /* Frobenius acting of the root of T (mod pr) */38GEN u; /* suitable root of unity (expressed in terms of the root of T) */39GEN nbext; /* number of extensions */40GEN roottable; /* table of roots of polynomials over the residue field */41GEN pk; /* powers of p: [p^1, p^2, ..., p^c] */42} KRASNER_t;4344/* Structure containing the field data (constructed with FieldData) */45typedef struct {46GEN p;47GEN top; /* absolute polynomial of a = z + pi (mod pr) */48GEN topr; /* top mod p */49GEN z; /* root of T in terms of a (mod pr) */50GEN eis; /* relative polynomial of pi in terms of z (mod pr) */51GEN pi; /* prime element in terms of a */52GEN ipi; /* p/pi in terms of a (mod pr) (used to divide by pi) */53GEN pik; /* [1, pi, ..., pi^(e-1), pi^e/p] in terms of a (mod pr).54Note the last one is different! */55long cj; /* number of conjugate fields */56} FAD_t;5758#undef CHECK5960/* Eval P(x) assuming P has positive coefficients and the result is a long */61static ulong62ZX_z_eval(GEN P, ulong x)63{64long i, l = lg(P);65ulong z;6667if (typ(P) == t_INT) return itou(P);68if (l == 2) return 0;69z = itou(gel(P, l-1));70for (i = l-2; i > 1; i--) z = z*x + itou(gel(P,i));71return z;72}7374/* Eval P(x, y) assuming P has positive coefficients and the result is a long */75static ulong76ZXY_z_eval(GEN P, ulong x, ulong y)77{78long i, l = lg(P);79ulong z;8081if (l == 2) return 0;82z = ZX_z_eval(gel(P, l-1), y);83for (i = l-2; i > 1; i--) z = z*x + ZX_z_eval(gel(P, i), y);84return z;85}8687/* P an Fq[X], where Fq = Fp[Y]/(T(Y)), a an FpX representing the automorphism88* y -> a(y). Return a(P), applying a() coefficientwise. */89static GEN90FqX_FpXQ_eval(GEN P, GEN a, GEN T, GEN p)91{92long i, l;93GEN Q = cgetg_copy(P, &l);9495Q[1] = P[1];96for (i = 2; i < l; i++)97{98GEN cf = gel(P, i);99if (typ(cf) == t_POL) {100switch(degpol(cf))101{102case -1: cf = gen_0; break;103case 0: cf = gel(cf,2); break;104default:105cf = FpX_FpXQ_eval(cf, a, T, p);106cf = simplify_shallow(cf);107break;108}109}110gel(Q, i) = cf;111}112113return Q;114}115116/* Sieving routines */117static GEN118InitSieve(long l) { return zero_F2v(l); }119static long120NextZeroValue(GEN sv, long i)121{122for(; i <= sv[1]; i++)123if (!F2v_coeff(sv, i)) return i;124return 0; /* sieve is full or out of the sieve! */125}126static void127SetSieveValue(GEN sv, long i)128{ if (i >= 1 && i <= sv[1]) F2v_set(sv, i); }129130/* return 1 if the data verify Ore condition and 0 otherwise */131static long132VerifyOre(GEN p, long e, long j)133{134long nv, b, vb, nb;135136if (j < 0) return 0;137nv = e * u_pval(e, p);138b = j%e;139if (b == 0) return (j == nv);140if (j > nv) return 0;141/* j < nv */142vb = u_pval(b, p);143nb = vb*e;144return (nb <= j);145}146147/* Given [K:Q_p] = m and disc(K/Q_p) = p^d, return all decompositions K/K^ur/Q_p148* as [e, f, j] with149* K^ur/Q_p unramified of degree f,150* K/K^ur totally ramified of degree e and discriminant p^(e+j-1);151* thus d = f*(e+j-1) and j > 0 iff ramification is wild */152static GEN153possible_efj_by_d(GEN p, long m, long d)154{155GEN rep, div;156long i, ctr, l;157158if (d == 0) return mkvec(mkvecsmall3(1, m, 0)); /* unramified */159div = divisorsu(ugcd(m, d));160l = lg(div); ctr = 1;161rep = cgetg(l, t_VEC);162for (i = 1; i < l; i++)163{164long f = div[i], e = m/f, j = d/f - e + 1;165if (VerifyOre(p, e, j)) gel(rep, ctr++) = mkvecsmall3(e, f, j);166}167setlg(rep, ctr); return rep;168}169170/* return the number of extensions corresponding to (e,f,j) */171static GEN172NumberExtensions(KRASNER_t *data)173{174ulong pp, pa;175long e, a, b;176GEN p, q, s0, p1;177178e = data->e;179p = data->p;180q = data->q;181a = data->a; /* floor(j/e) <= v_p(e), hence p^a | e */182b = data->b; /* j % e */183if (is_bigint(p)) /* implies a = 0 */184return b == 0? utoipos(e): mulsi(e, data->qm1);185186pp = p[2];187switch(a)188{189case 0: pa = 1; s0 = utoipos(e); break;190case 1: pa = pp; s0 = mului(e, powiu(q, e / pa)); break;191default:192pa = upowuu(pp, a); /* p^a */193s0 = mulsi(e, powiu(q, (e / pa) * ((pa - 1) / (pp - 1))));194}195/* s0 = e * q^(e*sum(p^-i, i=1...a)) */196if (b == 0) return s0;197198/* q^floor((b-1)/p^(a+1)) */199p1 = powiu(q, sdivsi(b-1, muluu(pa, pp)));200return mulii(mulii(data->qm1, s0), p1);201}202203static GEN204get_topx(KRASNER_t *data, GEN eis)205{206GEN p1, p2, rpl, c;207pari_sp av;208long j;209/* top poly. is the minimal polynomial of root(T) + root(eis) */210if (data->f == 1) return eis;211c = FpX_neg(pol_x(data->v),data->pr);212rpl = FqX_translate(eis, c, data->T, data->pr);213p1 = p2 = rpl; av = avma;214for (j = 1; j < data->f; j++)215{216/* compute conjugate polynomials using the Frobenius */217p1 = FqX_FpXQ_eval(p1, data->frob, data->T, data->pr);218p2 = FqX_mul(p2, p1, data->T, data->pr);219if (gc_needed(av,2)) gerepileall(av, 2, &p1,&p2);220}221return simplify_shallow(p2); /* ZX */222}223224/* eis (ZXY): Eisenstein polynomial over the field defined by T.225* topx (ZX): absolute equation of root(T) + root(eis).226* Return the struct FAD corresponding to the field it defines (GENs created227* as clones). Assume e > 1. */228static void229FieldData(KRASNER_t *data, FAD_t *fdata, GEN eis, GEN topx)230{231GEN p1, p2, p3, z, ipi, cipi, dipi, t, Q;232233fdata->p = data->p;234t = leafcopy(topx); setvarn(t, data->v);235fdata->top = t;236fdata->topr = FpX_red(t, data->pr);237238if (data->f == 1) z = gen_0;239else240{ /* Compute a root of T in K(top) using Hensel's lift */241z = pol_x(data->v);242p1 = FpX_deriv(data->T, data->p);243/* First lift to a root mod p */244for (;;) {245p2 = FpX_FpXQ_eval(data->T, z, fdata->top, data->p);246if (gequal0(p2)) break;247p3 = FpX_FpXQ_eval(p1, z, fdata->top, data->p);248z = FpX_sub(z, FpXQ_div(p2, p3, fdata->top, data->p), data->p);249}250/* Then a root mod p^r */251z = ZpX_ZpXQ_liftroot(data->T, z, fdata->top, data->p, data->r);252}253254fdata->z = z;255fdata->eis = eis;256fdata->pi = Fq_sub(pol_x(data->v), fdata->z,257FpX_red(fdata->top, data->p), data->p);258ipi = RgXQ_inv(fdata->pi, fdata->top);259ipi = Q_remove_denom(ipi, &dipi);260Q = mulii(data->pr, data->p);261cipi = Fp_inv(diviiexact(dipi, data->p), Q);262fdata->ipi = FpX_Fp_mul(ipi, cipi, Q); /* p/pi mod p^(pr+1) */263264/* Last one is set to pi^e/p (so we compute pi^e with one extra precision) */265p2 = mulii(data->pr, data->p);266p1 = FpXQ_powers(fdata->pi, data->e, fdata->topr, p2);267gel(p1, data->e+1) = ZX_Z_divexact(gel(p1, data->e+1), data->p);268fdata->pik = p1;269}270271/* return pol*ipi/p (mod top, pp) if it has integral coefficient, NULL272otherwise. The result is reduced mod top, pp */273static GEN274DivideByPi(FAD_t *fdata, GEN pp, GEN ppp, GEN pol)275{276GEN P;277long i, l;278pari_sp av = avma;279280/* "pol" is a t_INT or an FpX: signe() works for both */281if (!signe(pol)) return pol;282283P = Fq_mul(pol, fdata->ipi, fdata->top, ppp); /* FpX */284l = lg(P);285for (i = 2; i < l; i++)286{287GEN r;288gel(P,i) = dvmdii(gel(P,i), fdata->p, &r);289if (r != gen_0) return gc_NULL(av);290}291return FpX_red(P, pp);292}293294/* return pol# = pol~/pi^vpi(pol~) mod pp where pol~(x) = pol(pi.x + beta)295* has coefficients in the field defined by top and pi is a prime element */296static GEN297GetSharp(FAD_t *fdata, GEN pp, GEN ppp, GEN pol, GEN beta, long *pl)298{299GEN p1, p2;300long i, v, l, d = degpol(pol);301pari_sp av = avma;302303if (!gequal0(beta))304p1 = FqX_translate(pol, beta, fdata->topr, pp);305else306p1 = shallowcopy(pol);307p2 = p1;308for (v = 0;; v++)309{310for (i = 0; i <= v; i++)311{312GEN c = gel(p2, i+2);313c = DivideByPi(fdata, pp, ppp, c);314if (!c) break;315gel(p2, i+2) = c;316}317if (i <= v) break;318p1 = shallowcopy(p2);319}320if (!v) pari_err_BUG("GetSharp [no division]");321322for (l = v; l >= 0; l--)323{324GEN c = gel(p1, l+2);325c = DivideByPi(fdata, pp, ppp, c);326if (!c) { break; }327}328329*pl = l; if (l < 2) return NULL;330331/* adjust powers */332for (i = v+1; i <= d; i++)333gel(p1, i+2) = Fq_mul(gel(p1, i+2),334gel(fdata->pik, i-v+1), fdata->topr, pp);335336return gerepilecopy(av, normalizepol(p1));337}338339/* Compute roots of pol in the residue field. Use table look-up if possible */340static GEN341Quick_FqX_roots(KRASNER_t *data, GEN pol)342{343GEN rts;344ulong ind = 0;345346if (data->f == 1)347pol = FpXY_evalx(pol, gen_0, data->p);348else349pol = FqX_red(pol, data->T, data->p);350if (data->roottable)351{352ind = ZXY_z_eval(pol, data->q[2], data->p[2]);353if (gel(data->roottable, ind)) return gel(data->roottable, ind);354}355rts = FqX_roots(pol, data->T, data->p);356if (ind) gel(data->roottable, ind) = gclone(rts);357return rts;358}359360static void361FreeRootTable(GEN T)362{363if (T)364{365long j, l = lg(T);366for (j = 1; j < l; j++) guncloneNULL(gel(T,j));367}368}369370/* Return the number of roots of pol congruent to alpha modulo pi working371modulo pp (all roots if alpha is NULL); if flag is nonzero, return 1372as soon as a root is found. (Note: ppp = pp*p for DivideByPi) */373static long374RootCongruents(KRASNER_t *data, FAD_t *fdata, GEN pol, GEN alpha, GEN pp, GEN ppp, long sl, long flag)375{376GEN R;377long s, i;378379if (alpha)380{381long l;382pol = GetSharp(fdata, pp, ppp, pol, alpha, &l);383if (l <= 1) return l;384/* decrease precision if sl gets bigger than a multiple of e */385sl += l;386if (sl >= data->e)387{388sl -= data->e;389ppp = pp;390pp = diviiexact(pp, data->p);391}392}393394R = Quick_FqX_roots(data, pol);395for (s = 0, i = 1; i < lg(R); i++)396{397s += RootCongruents(data, fdata, pol, gel(R, i), pp, ppp, sl, flag);398if (flag && s) return 1;399}400return s;401}402403/* pol is a ZXY defining a polynomial over the field defined by fdata404If flag != 0, return 1 as soon as a root is found. Computations are done with405a precision of pr. */406static long407RootCountingAlgorithm(KRASNER_t *data, FAD_t *fdata, GEN pol, long flag)408{409long j, l, d;410GEN P = cgetg_copy(pol, &l);411412P[1] = pol[1];413d = l-3;414for (j = 0; j < d; j++)415{416GEN cf = gel(pol, j+2);417if (typ(cf) == t_INT)418cf = diviiexact(cf, data->p);419else420cf = ZX_Z_divexact(cf, data->p);421gel(P, j+2) = Fq_mul(cf, gel(fdata->pik, j+1), fdata->topr, data->pr);422}423gel(P, d+2) = gel(fdata->pik, d+1); /* pik[d] = pi^d/p */424425return RootCongruents(data, fdata, P, NULL, diviiexact(data->pr, data->p), data->pr, 0, flag);426}427428/* Return nonzero if the field given by fdata defines a field isomorphic to429* the one defined by pol */430static long431IsIsomorphic(KRASNER_t *data, FAD_t *fdata, GEN pol)432{433long j, nb;434pari_sp av = avma;435436if (RgX_is_ZX(pol)) return RootCountingAlgorithm(data, fdata, pol, 1);437438for (j = 1; j <= data->f; j++)439{440GEN p1 = FqX_FpXQ_eval(pol, fdata->z, fdata->top, data->pr);441nb = RootCountingAlgorithm(data, fdata, p1, 1);442if (nb) return gc_long(av, nb);443if (j < data->f)444pol = FqX_FpXQ_eval(pol, data->frob, data->T, data->pr);445}446return gc_long(av,0);447}448449/* Compute the number of conjugates fields of the field given by fdata */450static void451NbConjugateFields(KRASNER_t *data, FAD_t *fdata)452{453GEN pol = fdata->eis;454long j, nb;455pari_sp av = avma;456457if (RgX_is_ZX(pol)) { /* split for efficiency; contains the case f = 1 */458fdata->cj = data->e / RootCountingAlgorithm(data, fdata, pol, 0);459set_avma(av); return;460}461462nb = 0;463for (j = 1; j <= data->f; j++)464{ /* Transform to pol. in z to pol. in a */465GEN p1 = FqX_FpXQ_eval(pol, fdata->z, fdata->top, data->pr);466nb += RootCountingAlgorithm(data, fdata, p1, 0);467/* Look at the roots of conjugates polynomials */468if (j < data->f)469pol = FqX_FpXQ_eval(pol, data->frob, data->T, data->pr);470}471set_avma(av);472fdata->cj = data->e * data->f / nb;473return;474}475476/* return a minimal list of polynomials generating all the totally477ramified extensions of K^ur of degree e and discriminant478p^{e + j - 1} in the tamely ramified case */479static GEN480TamelyRamifiedCase(KRASNER_t *data)481{482long av = avma;483long g = ugcdui(data->e, data->qm1); /* (e, q-1) */484GEN rep, eis, Xe = gpowgs(pol_x(0), data->e), m = stoi(data->e / g);485486rep = zerovec(g);487eis = gadd(Xe, data->p);488gel(rep, 1) = mkvec2(get_topx(data,eis), m);489if (g > 1)490{491ulong pmodg = umodiu(data->p, g);492long r = 1, ct = 1;493GEN sv = InitSieve(g-1);494/* let Frobenius act to get a minimal set of polynomials over Q_p */495while (r)496{497long gr;498GEN p1 = (typ(data->u) == t_INT)?499mulii(Fp_powu(data->u, r, data->p), data->p):500ZX_Z_mul(FpXQ_powu(data->u, r, data->T, data->p), data->p);501eis = gadd(Xe, p1); /* add cst coef */502ct++;503gel(rep, ct) = mkvec2(get_topx(data,eis), m);504gr = r;505do { SetSieveValue(sv, gr); gr = Fl_mul(gr, pmodg, g); } while (gr != r);506r = NextZeroValue(sv, r);507}508setlg(rep, ct+1);509}510return gerepilecopy(av, rep);511}512513static long514function_l(GEN p, long a, long b, long i)515{516long l = 1 + a - z_pval(i, p);517if (i < b) l++;518return (l < 1)? 1: l;519}520521/* Structure of the coefficients set Omega. Each coefficient is [start, zr]522* meaning all the numbers of the form:523* zeta_0 * p^start + ... + zeta_s * p^c (s = c - start)524* with zeta_i roots of unity (powers of zq + zero), zeta_0 = 0 is525* possible iff zr = 1 */526static GEN527StructureOmega(KRASNER_t *data, GEN *pnbpol)528{529GEN nbpol, O = cgetg(data->e + 1, t_VEC);530long i;531532/* i = 0 */533gel(O, 1) = mkvecsmall2(1, 0);534nbpol = mulii(data->qm1, powiu(data->q, data->c - 1));535for (i = 1; i < data->e; i++)536{537long v_start, zero = 0;538GEN nbcf, p1;539v_start = function_l(data->p, data->a, data->b, i);540p1 = powiu(data->q, data->c - v_start);541if (i == data->b)542nbcf = mulii(p1, data->qm1);543else544{545nbcf = mulii(p1, data->q);546zero = 1;547}548gel(O, i+1) = mkvecsmall2(v_start, zero);549nbpol = mulii(nbpol, nbcf);550}551*pnbpol = nbpol; return O;552}553554/* a random element of the finite field */555static GEN556RandomFF(KRASNER_t *data)557{558long i, l = data->f + 2, p = itou(data->p);559GEN c = cgetg(l, t_POL);560c[1] = evalvarn(data->v);561for (i = 2; i < l; i++) gel(c, i) = utoi(random_Fl(p));562return ZX_renormalize(c, l);563}564static GEN565RandomPol(KRASNER_t *data, GEN Omega)566{567long i, j, l = data->e + 3, end = data->c;568GEN pol = cgetg(l, t_POL);569pol[1] = evalsigne(1) | evalvarn(0);570for (i = 1; i <= data->e; i++)571{572GEN c, cf = gel(Omega, i);573long st = cf[1], zr = cf[2];574/* c = sum_{st <= j <= end} x_j p^j, where x_j are random Fq mod (p,upl)575* If (!zr), insist on x_st != 0 */576for (;;) {577c = RandomFF(data);578if (zr || signe(c)) break;579}580for (j = 1; j <= end-st; j++)581c = ZX_add(c, ZX_Z_mul(RandomFF(data), gel(data->pk, j)));582c = ZX_Z_mul(c, gel(data->pk, st));583c = FpX_red(c, data->pr);584switch(degpol(c))585{586case -1: c = gen_0; break;587case 0: c = gel(c,2); break;588}589gel(pol, i+1) = c;590}591gel(pol, i+1) = gen_1; /* monic */592return pol;593}594595static void596CloneFieldData(FAD_t *fdata)597{598fdata->top = gclone(fdata->top);599fdata->topr= gclone(fdata->topr);600fdata->z = gclone(fdata->z);601fdata->eis = gclone(fdata->eis);602fdata->pi = gclone(fdata->pi);603fdata->ipi = gclone(fdata->ipi);604fdata->pik = gclone(fdata->pik);605}606static void607FreeFieldData(FAD_t *fdata)608{609gunclone(fdata->top);610gunclone(fdata->topr);611gunclone(fdata->z);612gunclone(fdata->eis);613gunclone(fdata->pi);614gunclone(fdata->ipi);615gunclone(fdata->pik);616}617618static GEN619WildlyRamifiedCase(KRASNER_t *data)620{621long nbext, ct, fd, nb = 0, j;622GEN nbpol, rpl, rep, Omega;623FAD_t **vfd;624pari_timer T;625pari_sp av = avma, av2;626627/* Omega = vector giving the structure of the set Omega */628/* nbpol = number of polynomials to consider = |Omega| */629Omega = StructureOmega(data, &nbpol);630nbext = itos_or_0(data->nbext);631if (!nbext || (nbext & ~LGBITS))632pari_err_OVERFLOW("padicfields [too many extensions]");633634if (DEBUGLEVEL>0) {635err_printf("There are %ld extensions to find and %Ps polynomials to consider\n", nbext, nbpol);636timer_start(&T);637}638639vfd = (FAD_t**)new_chunk(nbext);640for (j = 0; j < nbext; j++) vfd[j] = (FAD_t*)new_chunk(sizeof(FAD_t));641642ct = 0;643fd = 0;644av2 = avma;645646while (fd < nbext)647{ /* Jump randomly among the polynomials : seems best... */648rpl = RandomPol(data, Omega);649if (DEBUGLEVEL>3) err_printf("considering polynomial %Ps\n", rpl);650for (j = 0; j < ct; j++)651{652nb = IsIsomorphic(data, vfd[j], rpl);653if (nb) break;654}655if (!nb)656{657GEN topx = get_topx(data, rpl);658FAD_t *f = (FAD_t*)vfd[ct];659FieldData(data, f, rpl, topx);660CloneFieldData(f);661NbConjugateFields(data, f);662nb = f->cj;663fd += nb;664ct++;665if (DEBUGLEVEL>1)666err_printf("%ld more extension%s\t(%ld/%ld, %ldms)\n",667nb, (nb == 1)? "": "s", fd, nbext, timer_delay(&T));668}669set_avma(av2);670}671672rep = cgetg(ct+1, t_VEC);673for (j = 0; j < ct; j++)674{675FAD_t *f = (FAD_t*)vfd[j];676GEN topx = ZX_copy(f->top);677setvarn(topx, 0);678gel(rep, j+1) = mkvec2(topx, stoi(f->cj));679FreeFieldData(f);680}681FreeRootTable(data->roottable);682return gerepileupto(av, rep);683}684685/* return the minimal polynomial T of a generator of K^ur and the expression (mod pr)686* in terms of T of a root of unity u such that u is l-maximal for all primes l687* dividing g = (e,q-1). */688static void689setUnramData(KRASNER_t *d)690{691if (d->f == 1)692{693d->T = pol_x(d->v);694d->u = pgener_Fp(d->p);695d->frob = pol_x(d->v);696}697else698{699GEN L, z, T, p = d->p;700d->T = T = init_Fq(p, d->f, d->v);701L = gel(factoru(ugcdui(d->e, d->qm1)), 1);702z = gener_FpXQ_local(T, p, zv_to_ZV(L));703d->u = ZpXQ_sqrtnlift(pol_1(d->v), d->qm1, z, T, p, d->r);704d->frob = ZpX_ZpXQ_liftroot(T, FpXQ_pow(pol_x(d->v), p, T, p), T, p, d->r);705}706}707708/* return [ p^1, p^2, ..., p^c ] */709static GEN710get_pk(KRASNER_t *data)711{712long i, l = data->c + 1;713GEN pk = cgetg(l, t_VEC), p = data->p;714gel(pk, 1) = p;715for (i = 2; i <= data->c; i++) gel(pk, i) = mulii(gel(pk, i-1), p);716return pk;717}718719/* Compute an absolute polynomial for all the totally ramified720extensions of Q_p(z) of degree e and discriminant p^{e + j - 1}721where z is a root of upl defining an unramified extension of Q_p */722/* See padicfields for the meaning of flag */723static GEN724GetRamifiedPol(GEN p, GEN efj, long flag)725{726long e = efj[1], f = efj[2], j = efj[3], i, l;727const long v = 1;728GEN L, pols;729KRASNER_t data;730pari_sp av = avma;731732if (DEBUGLEVEL>1)733err_printf(" Computing extensions with decomposition [e, f, j] = [%ld, %ld, %ld]\n", e,f,j);734data.p = p;735data.e = e;736data.f = f;737data.j = j;738data.a = j/e;739data.b = j%e;740data.c = (e+2*j)/e+1;741data.q = powiu(p, f);742data.qm1 = subiu(data.q, 1);743data.v = v;744data.r = 1 + (long)ceildivuu(2*j + 3, e); /* enough precision */745data.pr = powiu(p, data.r);746data.nbext = NumberExtensions(&data);747748if (flag == 2) return data.nbext;749750setUnramData(&data);751if (DEBUGLEVEL>1)752err_printf(" Unramified part %Ps\n", data.T);753data.roottable = NULL;754if (j)755{756if (lgefint(data.q) == 3)757{758ulong npol = upowuu(data.q[2], e+1);759if (npol && npol < (1<<19)) data.roottable = const_vec(npol, NULL);760}761data.pk = get_pk(&data);762L = WildlyRamifiedCase(&data);763}764else765L = TamelyRamifiedCase(&data);766767pols = cgetg_copy(L, &l);768if (flag == 1)769{770GEN E = utoipos(e), F = utoipos(f), D = utoi(f*(e+j-1));771for (i = 1; i < l; i++)772{773GEN T = gel(L,i);774gel(pols, i) = mkvec5(ZX_copy(gel(T, 1)), E,F,D, icopy(gel(T, 2)));775}776}777else778{779for (i = 1; i < l; i++)780{781GEN T = gel(L,i);782gel(pols, i) = ZX_copy(gel(T,1));783}784}785return gerepileupto(av, pols);786}787788static GEN789possible_efj(GEN p, long m)790{ /* maximal possible discriminant valuation d <= m * (1+v_p(m)) - 1 */791/* 1) [j = 0, tame] d = m - f with f | m and v_p(f) = v_p(m), or792* 2) [j > 0, wild] d >= m, j <= v_p(e)*e */793ulong m1, pve, pp = p[2]; /* pp used only if v > 0 */794long ve, v = u_pvalrem(m, p, &m1);795GEN L, D = divisorsu(m1);796long i, taum1 = lg(D)-1, nb = 0;797798if (v) {799for (pve = 1,ve = 1; ve <= v; ve++) { pve *= pp; nb += pve * ve; }800nb = itos_or_0(muluu(nb, zv_sum(D)));801if (!nb || is_bigint( mului(pve, sqru(v)) ) )802pari_err_OVERFLOW("padicfields [too many ramification possibilities]");803}804nb += taum1; /* upper bound for the number of possible triples [e,f,j] */805806L = cgetg(nb + 1, t_VEC);807/* 1) tame */808for (nb=1, i=1; i < lg(D); i++)809{810long e = D[i], f = m / e;811gel(L, nb++) = mkvecsmall3(e, f, 0);812}813/* 2) wild */814/* Ore's condition: either815* 1) j = v_p(e) * e, or816* 2) j = a e + b, with 0 < b < e and v_p(b) <= a < v_p(e) */817for (pve = 1, ve = 1; ve <= v; ve++)818{819pve *= pp; /* = p^ve */820for (i = 1; i < lg(D); i++)821{822long a,b, e = D[i] * pve, f = m / e;823for (b = 1; b < e; b++)824for (a = u_lval(b, pp); a < ve; a++)825gel(L, nb++) = mkvecsmall3(e, f, a*e + b);826gel(L, nb++) = mkvecsmall3(e, f, ve*e);827}828}829setlg(L, nb); return L;830}831832#ifdef CHECK833static void834checkpols(GEN p, GEN EFJ, GEN pols)835{836GEN pol, p1, p2;837long c1, c2, e, f, j, i, l = lg(pols);838839if (typ(pols) == t_INT) return;840841e = EFJ[1];842f = EFJ[2];843j = EFJ[3];844845for (i = 1; i < l; i++)846{847pol = gel(pols, i);848if (typ(pol) == t_VEC) pol = gel(pol, 1);849if (!polisirreducible(pol)) pari_err_BUG("Polynomial is reducible");850p1 = poldisc0(pol, -1);851if (gvaluation(p1, p) != f*(e+j-1)) pari_err_BUG("Discriminant is incorrect");852/* only compute a p-maximal order */853p1 = nfinitall(mkvec2(pol, mkvec(p)), 0, DEFAULTPREC);854p2 = idealprimedec(p1, p);855if(lg(p2) > 2) pari_err_BUG("Prime p is split");856p2 = gel(p2, 1);857if (cmpis(gel(p2, 3), e)) pari_err_BUG("Ramification index is incorrect");858if (cmpis(gel(p2, 4), f)) pari_err_BUG("inertia degree is incorrect");859}860861if (l == 2) return;862if (e*f > 20) return;863864/* TODO: check that (random) distinct polynomials give nonisomorphic extensions */865for (i = 1; i < 3*l; i++)866{867c1 = random_Fl(l-1)+1;868c2 = random_Fl(l-1)+1;869if (c1 == c2) continue;870p1 = gel(pols, c1);871if (typ(p1) == t_VEC) p1 = gel(p1, 1);872p2 = gel(pols, c2);873if (typ(p2) == t_VEC) p2 = gel(p2, 1);874pol = polcompositum0(p1, p2, 0);875pol = gel(pol, 1);876if (poldegree(pol, -1) > 100) continue;877p1 = factorpadic(pol, p, 2);878p1 = gmael(p1, 1, 1);879if (poldegree(p1, -1) == e*f) pari_err_BUG("fields are isomorphic");880/*881p1 = nfinitall(mkvec2(pol, mkvec(p)), 0, DEFAULTPREC);882p2 = idealprimedec_galois(p1, p);883if (!cmpis(mulii(gel(p2, 3), gel(p2, 4)), e*f)) pari_err_BUG("fields are isomorphic");884*/885}886}887#endif888889static GEN890pols_from_efj(pari_sp av, GEN EFJ, GEN p, long flag)891{892long i, l;893GEN L = cgetg_copy(EFJ, &l);894if (l == 1) { set_avma(av); return flag == 2? gen_0: cgetg(1, t_VEC); }895for (i = 1; i < l; i++)896{897gel(L,i) = GetRamifiedPol(p, gel(EFJ,i), flag);898#ifdef CHECK899checkpols(p, gel(EFJ, i), gel(L, i));900#endif901}902if (flag == 2) return gerepileuptoint(av, ZV_sum(L));903return gerepilecopy(av, shallowconcat1(L));904}905906/* return a minimal list of polynomials generating all the extensions of907Q_p of given degree N; if N is a t_VEC [n,d], return extensions of degree n908and discriminant p^d. */909/* Return only the polynomials if flag = 0 (default), also the ramification910degree, the residual degree and the discriminant if flag = 1 and only the911number of extensions if flag = 2 */912GEN913padicfields0(GEN p, GEN N, long flag)914{915pari_sp av = avma;916long m = 0, d = -1;917GEN L;918919if (typ(p) != t_INT) pari_err_TYPE("padicfields",p);920/* be nice to silly users */921if (!BPSW_psp(p)) pari_err_PRIME("padicfields",p);922switch(typ(N))923{924case t_VEC:925if (lg(N) != 3) pari_err_TYPE("padicfields",N);926d = gtos(gel(N,2));927N = gel(N,1); /* fall through */928case t_INT:929m = itos(N);930if (m <= 0) pari_err_DOMAIN("padicfields", "degree", "<=", gen_0,N);931break;932default:933pari_err_TYPE("padicfields",N);934}935if (d >= 0) return padicfields(p, m, d, flag);936L = possible_efj(p, m);937return pols_from_efj(av, L, p, flag);938}939940GEN941padicfields(GEN p, long m, long d, long flag)942{943long av = avma;944GEN L = possible_efj_by_d(p, m, d);945return pols_from_efj(av, L, p, flag);946}947948949