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. */13#include "pari.h"14#include "paripriv.h"1516#define DEBUGLEVEL DEBUGLEVEL_bnf1718/*******************************************************************/19/* */20/* CLASS GROUP AND REGULATOR (McCURLEY, BUCHMANN) */21/* GENERAL NUMBER FIELDS */22/* */23/*******************************************************************/24/* get_random_ideal */25static const long RANDOM_BITS = 4;26/* Buchall */27static const long RELSUP = 5;28static const long FAIL_DIVISOR = 32;29static const long MINFAIL = 10;30/* small_norm */31static const long BNF_RELPID = 4;32static const long BMULT = 8;33static const long maxtry_ELEMENT = 1000*1000;34static const long maxtry_DEP = 20;35static const long maxtry_FACT = 500;36/* rnd_rel */37static const long RND_REL_RELPID = 1;38/* random relations */39static const long MINSFB = 3;40static const long SFB_MAX = 3;41static const long DEPSIZESFBMULT = 16;42static const long DEPSFBDIV = 10;43/* add_rel_i */44static const ulong mod_p = 27449UL;45/* be_honest */46static const long maxtry_HONEST = 50;4748typedef struct FACT {49long pr, ex;50} FACT;5152typedef struct subFB_t {53GEN subFB;54struct subFB_t *old;55} subFB_t;5657/* a factor base contains only noninert primes58* KC = # of P in factor base (p <= n, NP <= n2)59* KC2= # of P assumed to generate class group (NP <= n2)60*61* KCZ = # of rational primes under ideals counted by KC62* KCZ2= same for KC2 */6364typedef struct FB_t {65GEN FB; /* FB[i] = i-th rational prime used in factor base */66GEN LP; /* vector of all prime ideals in FB */67GEN LV; /* LV[p] = vector of P|p, NP <= n268* isclone() is set for LV[p] iff all P|p are in FB69* LV[i], i not prime or i > n2, is undefined! */70GEN iLP; /* iLP[p] = i such that LV[p] = [LP[i],...] */71GEN L_jid; /* indexes of "useful" prime ideals for rnd_rel */72long KC, KCZ, KCZ2;73GEN subFB; /* LP o subFB = part of FB used to build random relations */74int sfb_chg; /* need to change subFB ? */75GEN perm; /* permutation of LP used to represent relations [updated by76hnfspec/hnfadd: dense rows come first] */77GEN idealperm; /* permutation of ideals under field automorphisms */78GEN minidx; /* minidx[i] min ideal in orbit of LP[i] under field autom */79subFB_t *allsubFB; /* all subFB's used */80GEN embperm; /* permutations of the complex embeddings */81long MAXDEPSIZESFB; /* # trials before increasing subFB */82long MAXDEPSFB; /* MAXDEPSIZESFB / DEPSFBDIV, # trials befor rotating subFB */83} FB_t;8485enum { sfb_CHANGE = 1, sfb_INCREASE = 2 };8687typedef struct REL_t {88GEN R; /* relation vector as t_VECSMALL; clone */89long nz; /* index of first nonzero elt in R (hash) */90GEN m; /* pseudo-minimum yielding the relation; clone */91long relorig; /* relation this one is an image of */92long relaut; /* automorphim used to compute this relation from the original */93GEN emb; /* archimedean embeddings */94GEN junk[2]; /*make sure sizeof(struct) is a power of two.*/95} REL_t;9697typedef struct RELCACHE_t {98REL_t *chk; /* last checkpoint */99REL_t *base; /* first rel found */100REL_t *last; /* last rel found so far */101REL_t *end; /* target for last relation. base <= last <= end */102size_t len; /* number of rels pre-allocated in base */103long relsup; /* how many linearly dependent relations we allow */104GEN basis; /* mod p basis (generating family actually) */105ulong missing; /* missing vectors in generating family above */106} RELCACHE_t;107108typedef struct FP_t {109double **q;110GEN x;111double *y;112double *z;113double *v;114} FP_t;115116typedef struct RNDREL_t {117long jid;118GEN ex;119} RNDREL_t;120121static void122wr_rel(GEN e)123{124long i, l = lg(e);125for (i = 1; i < l; i++)126if (e[i]) err_printf("%ld^%ld ",i,e[i]);127}128static void129dbg_newrel(RELCACHE_t *cache)130{131if (DEBUGLEVEL > 1)132{133err_printf("\n++++ cglob = %ld\nrel = ", cache->last - cache->base);134wr_rel(cache->last->R);135err_printf("\n");136}137else138err_printf("%ld ", cache->last - cache->base);139}140141static void142delete_cache(RELCACHE_t *M)143{144REL_t *rel;145for (rel = M->base+1; rel <= M->last; rel++)146{147gunclone(rel->R);148if (rel->m) gunclone(rel->m);149}150pari_free((void*)M->base); M->base = NULL;151}152153static void154delete_FB(FB_t *F)155{156subFB_t *s, *sold;157for (s = F->allsubFB; s; s = sold) { sold = s->old; pari_free(s); }158gunclone(F->minidx);159gunclone(F->idealperm);160}161162static void163reallocate(RELCACHE_t *M, long len)164{165REL_t *old = M->base;166M->len = len;167pari_realloc_ip((void**)&M->base, (len+1) * sizeof(REL_t));168if (old)169{170size_t last = M->last - old, chk = M->chk - old, end = M->end - old;171M->last = M->base + last;172M->chk = M->base + chk;173M->end = M->base + end;174}175}176177#define pr_get_smallp(pr) gel(pr,1)[2]178179/* don't take P|p all other Q|p are already there */180static int181bad_subFB(FB_t *F, long t)182{183GEN LP, P = gel(F->LP,t);184long p = pr_get_smallp(P);185LP = gel(F->LV,p);186return (isclone(LP) && t == F->iLP[p] + lg(LP)-1);187}188189static void190assign_subFB(FB_t *F, GEN yes, long iyes)191{192long i, lv = sizeof(subFB_t) + iyes*sizeof(long); /* for struct + GEN */193subFB_t *s = (subFB_t *)pari_malloc(lv);194s->subFB = (GEN)&s[1];195s->old = F->allsubFB; F->allsubFB = s;196for (i = 0; i < iyes; i++) s->subFB[i] = yes[i];197F->subFB = s->subFB;198F->MAXDEPSIZESFB = (iyes-1) * DEPSIZESFBMULT;199F->MAXDEPSFB = F->MAXDEPSIZESFB / DEPSFBDIV;200}201202/* Determine the permutation of the ideals made by each field automorphism */203static GEN204FB_aut_perm(FB_t *F, GEN auts, GEN cyclic)205{206long i, j, m, KC = F->KC, nauts = lg(auts)-1;207GEN minidx, perm = zero_Flm_copy(KC, nauts);208209if (!nauts) { F->minidx = gclone(identity_zv(KC)); return cgetg(1,t_MAT); }210minidx = zero_Flv(KC);211for (m = 1; m < lg(cyclic); m++)212{213GEN thiscyc = gel(cyclic, m);214long k0 = thiscyc[1];215GEN aut = gel(auts, k0), permk0 = gel(perm, k0), ppermk;216i = 1;217while (i <= KC)218{219pari_sp av2 = avma;220GEN seen = zero_Flv(KC), P = gel(F->LP, i);221long imin = i, p, f, l;222p = pr_get_smallp(P);223f = pr_get_f(P);224do225{226if (++i > KC) break;227P = gel(F->LP, i);228}229while (p == pr_get_smallp(P) && f == pr_get_f(P));230for (j = imin; j < i; j++)231{232GEN img = ZM_ZC_mul(aut, pr_get_gen(gel(F->LP, j)));233for (l = imin; l < i; l++)234if (!seen[l] && ZC_prdvd(img, gel(F->LP, l)))235{236seen[l] = 1; permk0[j] = l; break;237}238}239set_avma(av2);240}241for (ppermk = permk0, i = 2; i < lg(thiscyc); i++)242{243GEN permk = gel(perm, thiscyc[i]);244for (j = 1; j <= KC; j++) permk[j] = permk0[ppermk[j]];245ppermk = permk;246}247}248for (j = 1; j <= KC; j++)249{250if (minidx[j]) continue;251minidx[j] = j;252for (i = 1; i <= nauts; i++) minidx[coeff(perm, j, i)] = j;253}254F->minidx = gclone(minidx); return perm;255}256257/* set subFB.258* Fill F->perm (if != NULL): primes ideals sorted by increasing norm (except259* the ones in subFB come first [dense rows for hnfspec]) */260static void261subFBgen(FB_t *F, GEN auts, GEN cyclic, double PROD, long minsFB)262{263GEN y, perm, yes, no;264long i, j, k, iyes, ino, lv = F->KC + 1;265double prod;266pari_sp av;267268F->LP = cgetg(lv, t_VEC);269F->L_jid = F->perm = cgetg(lv, t_VECSMALL);270av = avma;271y = cgetg(lv,t_COL); /* Norm P */272for (k=0, i=1; i <= F->KCZ; i++)273{274GEN LP = gel(F->LV,F->FB[i]);275long l = lg(LP);276for (j = 1; j < l; j++)277{278GEN P = gel(LP,j);279k++;280gel(y,k) = pr_norm(P);281gel(F->LP,k) = P;282}283}284/* perm sorts LP by increasing norm */285perm = indexsort(y);286no = cgetg(lv, t_VECSMALL); ino = 1;287yes = cgetg(lv, t_VECSMALL); iyes = 1;288prod = 1.0;289for (i = 1; i < lv; i++)290{291long t = perm[i];292if (bad_subFB(F, t)) { no[ino++] = t; continue; }293294yes[iyes++] = t;295prod *= (double)itos(gel(y,t));296if (iyes > minsFB && prod > PROD) break;297}298setlg(yes, iyes);299for (j=1; j<iyes; j++) F->perm[j] = yes[j];300for (i=1; i<ino; i++, j++) F->perm[j] = no[i];301for ( ; j<lv; j++) F->perm[j] = perm[j];302F->allsubFB = NULL;303F->idealperm = gclone(FB_aut_perm(F, auts, cyclic));304if (iyes) assign_subFB(F, yes, iyes);305set_avma(av);306}307static int308subFB_change(FB_t *F)309{310long i, iyes, minsFB, lv = F->KC + 1, l = lg(F->subFB)-1;311pari_sp av = avma;312GEN yes, L_jid = F->L_jid, present = zero_zv(lv-1);313314switch (F->sfb_chg)315{316case sfb_INCREASE: minsFB = l + 1; break;317default: minsFB = l; break;318}319320yes = cgetg(minsFB+1, t_VECSMALL); iyes = 1;321if (L_jid)322{323for (i = 1; i < lg(L_jid); i++)324{325long l = L_jid[i];326yes[iyes++] = l;327present[l] = 1;328if (iyes > minsFB) break;329}330}331else i = 1;332if (iyes <= minsFB)333{334for ( ; i < lv; i++)335{336long l = F->perm[i];337if (present[l]) continue;338yes[iyes++] = l;339if (iyes > minsFB) break;340}341if (i == lv) return 0;342}343if (zv_equal(F->subFB, yes))344{345if (DEBUGLEVEL) err_printf("\n*** NOT Changing sub factor base\n");346}347else348{349if (DEBUGLEVEL) err_printf("\n*** Changing sub factor base\n");350assign_subFB(F, yes, iyes);351}352F->sfb_chg = 0; return gc_bool(av, 1);353}354355/* make sure enough room to store n more relations */356static void357pre_allocate(RELCACHE_t *cache, size_t n)358{359size_t len = (cache->last - cache->base) + n;360if (len >= cache->len) reallocate(cache, len << 1);361}362363void364init_GRHcheck(GRHcheck_t *S, long N, long R1, double LOGD)365{366const double c1 = M_PI*M_PI/2;367const double c2 = 3.663862376709;368const double c3 = 3.801387092431; /* Euler + log(8*Pi)*/369S->clone = 0;370S->cN = R1*c2 + N*c1;371S->cD = LOGD - N*c3 - R1*M_PI/2;372S->maxprimes = 16000; /* sufficient for LIMC=176081*/373S->primes = (GRHprime_t*)pari_malloc(S->maxprimes*sizeof(*S->primes));374S->nprimes = 0;375S->limp = 0;376u_forprime_init(&S->P, 2, ULONG_MAX);377}378379void380free_GRHcheck(GRHcheck_t *S)381{382if (S->clone)383{384long i = S->nprimes;385GRHprime_t *pr;386for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--) gunclone(pr->dec);387}388pari_free(S->primes);389}390391int392GRHok(GRHcheck_t *S, double L, double SA, double SB)393{394return (S->cD + (S->cN + 2*SB) / L - 2*SA < -1e-8);395}396397/* Return factorization pattern of p: [f,n], where n[i] primes of398* residue degree f[i] */399static GEN400get_fs(GEN nf, GEN P, GEN index, ulong p)401{402long j, k, f, n, l;403GEN fs, ns;404405if (umodiu(index, p))406{ /* easy case: p does not divide index */407GEN F = Flx_degfact(ZX_to_Flx(P,p), p);408fs = gel(F,1); l = lg(fs);409}410else411{412GEN F = idealprimedec(nf, utoipos(p));413l = lg(F);414fs = cgetg(l, t_VECSMALL);415for (j = 1; j < l; j++) fs[j] = pr_get_f(gel(F,j));416}417ns = cgetg(l, t_VECSMALL);418f = fs[1]; n = 1;419for (j = 2, k = 1; j < l; j++)420if (fs[j] == f)421n++;422else423{424ns[k] = n; fs[k] = f; k++;425f = fs[j]; n = 1;426}427ns[k] = n; fs[k] = f; k++;428setlg(fs, k);429setlg(ns, k); return mkvec2(fs,ns);430}431432/* cache data for all rational primes up to the LIM */433static void434cache_prime_dec(GRHcheck_t *S, ulong LIM, GEN nf)435{436pari_sp av = avma;437GRHprime_t *pr;438GEN index, P;439double nb;440441if (S->limp >= LIM) return;442S->clone = 1;443nb = primepi_upper_bound((double)LIM); /* #{p <= LIM} <= nb */444GRH_ensure(S, nb+1); /* room for one extra prime */445P = nf_get_pol(nf);446index = nf_get_index(nf);447for (pr = S->primes + S->nprimes;;)448{449ulong p = u_forprime_next(&(S->P));450pr->p = p;451pr->logp = log((double)p);452pr->dec = gclone(get_fs(nf, P, index, p));453S->nprimes++;454pr++;455set_avma(av);456/* store up to nextprime(LIM) included */457if (p >= LIM) { S->limp = p; break; }458}459}460461static double462tailresback(long R1, long R2, double rK, long C, double C2, double C3, double r1K, double r2K, double logC, double logC2, double logC3)463{464const double rQ = 1.83787706641;465const double r1Q = 1.98505372441;466const double r2Q = 1.07991541347;467return fabs((R1+R2-1)*(12*logC3+4*logC2-9*logC-6)/(2*C*logC3)468+ (rK-rQ)*(6*logC2 + 5*logC + 2)/(C*logC3)469- R2*(6*logC2+11*logC+6)/(C2*logC2)470- 2*(r1K-r1Q)*(3*logC2 + 4*logC + 2)/(C2*logC3)471+ (R1+R2-1)*(12*logC3+40*logC2+45*logC+18)/(6*C3*logC3)472+ (r2K-r2Q)*(2*logC2 + 3*logC + 2)/(C3*logC3));473}474475static double476tailres(long R1, long R2, double al2K, double rKm, double rKM, double r1Km,477double r1KM, double r2Km, double r2KM, double C, long i)478{479/* C >= 3*2^i, lower bound for eint1(log(C)/2) */480/* for(i=0,30,print(eint1(log(3*2^i)/2))) */481static double tab[] = {4820.50409264803,4830.26205336997,4840.14815491171,4850.08770540561,4860.05347651832,4870.03328934284,4880.02104510690,4890.01346475900,4900.00869778586,4910.00566279855,4920.00371111950,4930.00244567837,4940.00161948049,4950.00107686891,4960.00071868750,4970.00048119961,4980.00032312188,4990.00021753772,5000.00014679818,5019.9272855581E-5,5026.7263969995E-5,5034.5656812967E-5,5043.1041124593E-5,5052.1136011590E-5,5061.4411645381E-5,5079.8393304088E-6,5086.7257395409E-6,5094.6025878272E-6,5103.1529719271E-6,5112.1620490021E-6,5121.4839266071E-6513};514const double logC = log(C), logC2 = logC*logC, logC3 = logC*logC2;515const double C2 = C*C, C3 = C*C2;516double E1 = i >30? 0: tab[i];517return al2K*((33*logC2+22*logC+8)/(8*logC3*sqrt(C))+15*E1/16)518+ maxdd(tailresback(rKm,r1KM,r2Km, C,C2,C3,R1,R2,logC,logC2,logC3),519tailresback(rKM,r1Km,r2KM, C,C2,C3,R1,R2,logC,logC2,logC3))/2520+ ((R1+R2-1)*4*C+R2)*(C2+6*logC)/(4*C2*C2*logC2);521}522523static long524primeneeded(long N, long R1, long R2, double LOGD)525{526const double lim = 0.25; /* should be log(2)/2 == 0.34657... */527const double al2K = 0.3526*LOGD - 0.8212*N + 4.5007;528const double rKm = -1.0155*LOGD + 2.1042*N - 8.3419;529const double rKM = -0.5 *LOGD + 1.2076*N + 1;530const double r1Km = - LOGD + 1.4150*N;531const double r1KM = - LOGD + 1.9851*N;532const double r2Km = - LOGD + 0.9151*N;533const double r2KM = - LOGD + 1.0800*N;534long Cmin = 3, Cmax = 3, i = 0;535while (tailres(R1, R2, al2K, rKm, rKM, r1Km, r1KM, r2Km, r2KM, Cmax, i) > lim)536{537Cmin = Cmax;538Cmax *= 2;539i++;540}541i--;542while (Cmax - Cmin > 1)543{544long t = (Cmin + Cmax)/2;545if (tailres(R1, R2, al2K, rKm, rKM, r1Km, r1KM, r2Km, r2KM, t, i) > lim)546Cmin = t;547else548Cmax = t;549}550return Cmax;551}552553/* ~ 1 / Res(s = 1, zeta_K) */554static GEN555compute_invres(GRHcheck_t *S, long LIMC)556{557pari_sp av = avma;558double loginvres = 0.;559GRHprime_t *pr;560long i;561double logLIMC = log((double)LIMC);562double logLIMC2 = logLIMC*logLIMC, denc;563double c0, c1, c2;564denc = 1/(pow((double)LIMC, 3.) * logLIMC * logLIMC2);565c2 = ( logLIMC2 + 3 * logLIMC / 2 + 1) * denc;566denc *= LIMC;567c1 = (3 * logLIMC2 + 4 * logLIMC + 2) * denc;568denc *= LIMC;569c0 = (3 * logLIMC2 + 5 * logLIMC / 2 + 1) * denc;570for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--)571{572GEN dec, fs, ns;573long addpsi;574double addpsi1, addpsi2;575double logp = pr->logp, NPk;576long j, k, limp = logLIMC/logp;577ulong p = pr->p, p2 = p*p;578if (limp < 1) break;579dec = pr->dec;580fs = gel(dec, 1); ns = gel(dec, 2);581loginvres += 1./p;582/* NB: limp = 1 nearly always and limp > 2 for very few primes */583for (k=2, NPk = p; k <= limp; k++) { NPk *= p; loginvres += 1/(k * NPk); }584addpsi = limp;585addpsi1 = p *(pow((double)p , (double)limp)-1)/(p -1);586addpsi2 = p2*(pow((double)p2, (double)limp)-1)/(p2-1);587j = lg(fs);588while (--j > 0)589{590long f, nb, kmax;591double NP, NP2, addinvres;592f = fs[j]; if (f > limp) continue;593nb = ns[j];594NP = pow((double)p, (double)f);595addinvres = 1/NP;596kmax = limp / f;597for (k=2, NPk = NP; k <= kmax; k++) { NPk *= NP; addinvres += 1/(k*NPk); }598NP2 = NP*NP;599loginvres -= nb * addinvres;600addpsi -= nb * f * kmax;601addpsi1 -= nb*(f*NP *(pow(NP ,(double)kmax)-1)/(NP -1));602addpsi2 -= nb*(f*NP2*(pow(NP2,(double)kmax)-1)/(NP2-1));603}604loginvres -= (addpsi*c0 - addpsi1*c1 + addpsi2*c2)*logp;605}606return gerepileuptoleaf(av, mpexp(dbltor(loginvres)));607}608609static long610nthideal(GRHcheck_t *S, GEN nf, long n)611{612pari_sp av = avma;613GEN P = nf_get_pol(nf);614ulong p = 0, *vecN = (ulong*)const_vecsmall(n, LONG_MAX);615long i, N = poldegree(P, -1);616for (i = 0; ; i++)617{618GRHprime_t *pr;619GEN fs;620cache_prime_dec(S, p+1, nf);621pr = S->primes + i;622fs = gel(pr->dec, 1);623p = pr->p;624if (fs[1] != N)625{626GEN ns = gel(pr->dec, 2);627long k, l, j = lg(fs);628while (--j > 0)629{630ulong NP = upowuu(p, fs[j]);631long nf;632if (!NP) continue;633for (k = 1; k <= n; k++) if (vecN[k] > NP) break;634if (k > n) continue;635/* vecN[k] <= NP */636nf = ns[j]; /*#{primes of norme NP} = nf, insert them here*/637for (l = k+nf; l <= n; l++) vecN[l] = vecN[l-nf];638for (l = 0; l < nf && k+l <= n; l++) vecN[k+l] = NP;639while (l <= k) vecN[l++] = NP;640}641}642if (p > vecN[n]) break;643}644return gc_long(av, vecN[n]);645}646647/* Compute FB, LV, iLP + KC*. Reset perm648* C2: bound for norm of tested prime ideals (includes be_honest())649* C1: bound for p, such that P|p (NP <= C2) used to build relations */650static void651FBgen(FB_t *F, GEN nf, long N, ulong C1, ulong C2, GRHcheck_t *S)652{653GRHprime_t *pr;654long i, ip;655GEN prim;656const double L = log((double)C2 + 0.5);657658cache_prime_dec(S, C2, nf);659pr = S->primes;660F->sfb_chg = 0;661F->FB = cgetg(C2+1, t_VECSMALL);662F->iLP = cgetg(C2+1, t_VECSMALL);663F->LV = zerovec(C2);664665prim = icopy(gen_1);666i = ip = 0;667F->KC = F->KCZ = 0;668for (;; pr++) /* p <= C2 */669{670ulong p = pr->p;671long k, l, m;672GEN LP, nb, f;673674if (!F->KC && p > C1) { F->KCZ = i; F->KC = ip; }675if (p > C2) break;676677if (DEBUGLEVEL>1) err_printf(" %ld",p);678679f = gel(pr->dec, 1); nb = gel(pr->dec, 2);680if (f[1] == N)681{682if (p == C2) break;683continue; /* p inert */684}685l = (long)(L/pr->logp); /* p^f <= C2 <=> f <= l */686for (k=0, m=1; m < lg(f) && f[m]<=l; m++) k += nb[m];687if (!k)688{ /* too inert to appear in FB */689if (p == C2) break;690continue;691}692prim[2] = p; LP = idealprimedec_limit_f(nf,prim, l);693/* keep noninert ideals with Norm <= C2 */694if (m == lg(f)) setisclone(LP); /* flag it: all prime divisors in FB */695F->FB[++i]= p;696gel(F->LV,p) = LP;697F->iLP[p] = ip; ip += k;698if (p == C2) break;699}700if (!F->KC) { F->KCZ = i; F->KC = ip; }701/* Note F->KC > 0 otherwise GRHchk is false */702setlg(F->FB, F->KCZ+1); F->KCZ2 = i;703if (DEBUGLEVEL>1)704{705err_printf("\n");706if (DEBUGLEVEL>6)707{708err_printf("########## FACTORBASE ##########\n\n");709err_printf("KC2=%ld, KC=%ld, KCZ=%ld, KCZ2=%ld\n",710ip, F->KC, F->KCZ, F->KCZ2);711for (i=1; i<=F->KCZ; i++) err_printf("++ LV[%ld] = %Ps",i,gel(F->LV,F->FB[i]));712}713}714F->perm = NULL; F->L_jid = NULL;715}716717static int718GRHchk(GEN nf, GRHcheck_t *S, ulong LIMC)719{720double logC = log((double)LIMC), SA = 0, SB = 0;721GRHprime_t *pr = S->primes;722723cache_prime_dec(S, LIMC, nf);724for (pr = S->primes;; pr++)725{726ulong p = pr->p;727GEN dec, fs, ns;728double logCslogp;729long j;730731if (p > LIMC) break;732dec = pr->dec; fs = gel(dec, 1); ns = gel(dec,2);733logCslogp = logC/pr->logp;734for (j = 1; j < lg(fs); j++)735{736long f = fs[j], M, nb;737double logNP, q, A, B;738if (f > logCslogp) break;739logNP = f * pr->logp;740q = 1/sqrt((double)upowuu(p, f));741A = logNP * q; B = logNP * A; M = (long)(logCslogp/f);742if (M > 1)743{744double inv1_q = 1 / (1-q);745A *= (1 - pow(q, (double)M)) * inv1_q;746B *= (1 - pow(q, (double)M)*(M+1 - M*q)) * inv1_q * inv1_q;747}748nb = ns[j];749SA += nb * A;750SB += nb * B;751}752if (p == LIMC) break;753}754return GRHok(S, logC, SA, SB);755}756757/* SMOOTH IDEALS */758static void759store(long i, long e, FACT *fact)760{761++fact[0].pr;762fact[fact[0].pr].pr = i; /* index */763fact[fact[0].pr].ex = e; /* exponent */764}765766/* divide out x by all P|p, where x as in can_factor(). k = v_p(Nx) */767static int768divide_p_elt(GEN LP, long ip, long k, GEN m, FACT *fact)769{770long j, l = lg(LP);771for (j=1; j<l; j++)772{773GEN P = gel(LP,j);774long v = ZC_nfval(m, P);775if (!v) continue;776store(ip + j, v, fact); /* v = v_P(m) > 0 */777k -= v * pr_get_f(P);778if (!k) return 1;779}780return 0;781}782static int783divide_p_id(GEN LP, long ip, long k, GEN nf, GEN I, FACT *fact)784{785long j, l = lg(LP);786for (j=1; j<l; j++)787{788GEN P = gel(LP,j);789long v = idealval(nf,I, P);790if (!v) continue;791store(ip + j, v, fact); /* v = v_P(I) > 0 */792k -= v * pr_get_f(P);793if (!k) return 1;794}795return 0;796}797static int798divide_p_quo(GEN LP, long ip, long k, GEN nf, GEN I, GEN m, FACT *fact)799{800long j, l = lg(LP);801for (j=1; j<l; j++)802{803GEN P = gel(LP,j);804long v = ZC_nfval(m, P);805if (!v) continue;806v -= idealval(nf,I, P);807if (!v) continue;808store(ip + j, v, fact); /* v = v_P(m / I) > 0 */809k -= v * pr_get_f(P);810if (!k) return 1;811}812return 0;813}814815/* |*N| != 0 is the norm of a primitive ideal, in particular not divisible by816* any inert prime. Is |*N| a smooth rational integer wrt F ? (put the817* exponents in *ex) */818static int819smooth_norm(FB_t *F, GEN *N, GEN *ex)820{821GEN FB = F->FB;822const long KCZ = F->KCZ;823const ulong limp = uel(FB,KCZ); /* last p in FB */824long i;825826*ex = new_chunk(KCZ+1);827for (i=1; ; i++)828{829int stop;830ulong p = uel(FB,i);831long v = Z_lvalrem_stop(N, p, &stop);832(*ex)[i] = v;833if (v)834{835GEN LP = gel(F->LV,p);836if (lg(LP) == 1) return 0;837if (stop) break;838}839if (i == KCZ) return 0;840}841(*ex)[0] = i;842return (abscmpiu(*N,limp) <= 0);843}844845static int846divide_p(FB_t *F, long p, long k, GEN nf, GEN I, GEN m, FACT *fact)847{848GEN LP = gel(F->LV,p);849long ip = F->iLP[p];850if (!m) return divide_p_id (LP,ip,k,nf,I,fact);851if (!I) return divide_p_elt(LP,ip,k,m,fact);852return divide_p_quo(LP,ip,k,nf,I,m,fact);853}854855/* Let x = m if I == NULL,856* I if m == NULL,857* m/I otherwise.858* Can we factor the integral primitive ideal x ? |N| = Norm x > 0 */859static long860can_factor(FB_t *F, GEN nf, GEN I, GEN m, GEN N, FACT *fact)861{862GEN ex;863long i, res = 0;864fact[0].pr = 0;865if (is_pm1(N)) return 1;866if (!smooth_norm(F, &N, &ex)) goto END;867for (i=1; i<=ex[0]; i++)868if (ex[i] && !divide_p(F, F->FB[i], ex[i], nf, I, m, fact)) goto END;869res = is_pm1(N) || divide_p(F, itou(N), 1, nf, I, m, fact);870END:871if (!res && DEBUGLEVEL > 1) err_printf(".");872return res;873}874875/* can we factor m/I ? [m in I from idealpseudomin_nonscalar], NI = norm I */876static long877factorgen(FB_t *F, GEN nf, GEN I, GEN NI, GEN m, FACT *fact)878{879long e, r1 = nf_get_r1(nf);880GEN M = nf_get_M(nf);881GEN N = divri(embed_norm(RgM_RgC_mul(M,m), r1), NI); /* ~ N(m/I) */882N = grndtoi(N, &e);883if (e > -1)884{885if (DEBUGLEVEL > 1) err_printf("+");886return 0;887}888return can_factor(F, nf, I, m, N, fact);889}890891/* FUNDAMENTAL UNITS */892893/* a, m real. Return (Re(x) + a) + I * (Im(x) % m) */894static GEN895addRe_modIm(GEN x, GEN a, GEN m)896{897GEN re, im, z;898if (typ(x) == t_COMPLEX)899{900im = modRr_safe(gel(x,2), m);901if (!im) return NULL;902re = gadd(gel(x,1), a);903z = gequal0(im)? re: mkcomplex(re, im);904}905else906z = gadd(x, a);907return z;908}909910/* clean archimedean components */911static GEN912cleanarch(GEN x, long N, long prec)913{914long i, l, R1, RU;915GEN s, pi2, y = cgetg_copy(x, &l);916917if (typ(x) == t_MAT)918{919for (i = 1; i < l; i++)920if (!(gel(y,i) = cleanarch(gel(x,i), N, prec))) return NULL;921return y;922}923RU = l-1; R1 = (RU<<1) - N; pi2 = Pi2n(1, prec);924s = gdivgs(RgV_sum(real_i(x)), -N); /* -log |norm(x)| / N */925for (i = 1; i <= R1; i++)926if (!(gel(y,i) = addRe_modIm(gel(x,i), s, pi2))) return NULL;927if (i <= RU)928{929GEN pi4 = Pi2n(2, prec), s2 = gmul2n(s, 1);930for ( ; i <= RU; i++)931if (!(gel(y,i) = addRe_modIm(gel(x,i), s2, pi4))) return NULL;932}933return y;934}935GEN936nf_cxlog_normalize(GEN nf, GEN x, long prec)937{938long N = nf_get_degree(checknf(nf));939return cleanarch(x, N, prec);940}941942static GEN943not_given(long reason)944{945if (DEBUGLEVEL)946switch(reason)947{948case fupb_LARGE:949pari_warn(warner,"fundamental units too large, not given");950break;951case fupb_PRECI:952pari_warn(warner,"insufficient precision for fundamental units, not given");953break;954}955return NULL;956}957958/* check whether exp(x) will 1) get too big (real(x) large), 2) require959* large accuracy for argument reduction (imag(x) large) */960static long961expbitprec(GEN x, long *e)962{963GEN re, im;964if (typ(x) != t_COMPLEX) re = x;965else966{967im = gel(x,2); *e = maxss(*e, expo(im) + 5 - bit_prec(im));968re = gel(x,1);969}970return (expo(re) <= 20);971972}973static long974RgC_expbitprec(GEN x)975{976long l = lg(x), i, e = - (long)HIGHEXPOBIT;977for (i = 1; i < l; i++)978if (!expbitprec(gel(x,i), &e)) return LONG_MAX;979return e;980}981static long982RgM_expbitprec(GEN x)983{984long i, j, I, J, e = - (long)HIGHEXPOBIT;985RgM_dimensions(x, &I,&J);986for (j = 1; j <= J; j++)987for (i = 1; i <= I; i++)988if (!expbitprec(gcoeff(x,i,j), &e)) return LONG_MAX;989return e;990}991992static GEN993FlxqX_chinese_unit(GEN X, GEN U, GEN invzk, GEN D, GEN T, ulong p)994{995long i, lU = lg(U), lX = lg(X), d = lg(invzk)-1;996GEN M = cgetg(lU, t_MAT);997if (D)998{999D = Flv_inv(D, p);1000for (i = 1; i < lX; i++)1001if (uel(D, i) != 1)1002gel(X,i) = Flx_Fl_mul(gel(X,i), uel(D,i), p);1003}1004for (i = 1; i < lU; i++)1005{1006GEN H = FlxqV_factorback(X, gel(U, i), T, p);1007gel(M, i) = Flm_Flc_mul(invzk, Flx_to_Flv(H, d), p);1008}1009return M;1010}10111012static GEN1013chinese_unit_slice(GEN A, GEN U, GEN B, GEN D, GEN C, GEN P, GEN *mod)1014{1015pari_sp av = avma;1016long i, n = lg(P)-1, v = varn(C);1017GEN H, T;1018if (n == 1)1019{1020ulong p = uel(P,1);1021GEN a = ZXV_to_FlxV(A, p), b = ZM_to_Flm(B, p), c = ZX_to_Flx(C, p);1022GEN d = D ? ZV_to_Flv(D, p): NULL;1023GEN Hp = FlxqX_chinese_unit(a, U, b, d, c, p);1024H = gerepileupto(av, Flm_to_ZM(Hp));1025*mod = utoi(p);1026return H;1027}1028T = ZV_producttree(P);1029A = ZXC_nv_mod_tree(A, P, T, v);1030B = ZM_nv_mod_tree(B, P, T);1031D = D ? ZV_nv_mod_tree(D, P, T): NULL;1032C = ZX_nv_mod_tree(C, P, T);10331034H = cgetg(n+1, t_VEC);1035for(i=1; i <= n; i++)1036{1037ulong p = P[i];1038GEN a = gel(A,i), b = gel(B,i), c = gel(C,i), d = D ? gel(D,i): NULL;1039gel(H,i) = FlxqX_chinese_unit(a, U, b, d, c, p);1040}1041H = nmV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P, T));1042*mod = gmael(T, lg(T)-1, 1);1043gerepileall(av, 2, &H, mod);1044return H;1045}10461047GEN1048chinese_unit_worker(GEN P, GEN A, GEN U, GEN B, GEN D, GEN C)1049{1050GEN V = cgetg(3, t_VEC);1051gel(V,1) = chinese_unit_slice(A, U, B, isintzero(D) ? NULL: D, C, P, &gel(V,2));1052return V;1053}10541055/* Let x = \prod X[i]^E[i] = u, return u.1056* If dX != NULL, X[i] = nX[i] / dX[i] where nX[i] is a ZX, dX[i] in Z */1057static GEN1058chinese_unit(GEN nf, GEN nX, GEN dX, GEN U, ulong bnd)1059{1060pari_sp av = avma;1061GEN f = nf_get_index(nf), T = nf_get_pol(nf), invzk = nf_get_invzk(nf);1062GEN H, mod;1063forprime_t S;1064GEN worker = snm_closure(is_entry("_chinese_unit_worker"),1065mkcol5(nX, U, invzk, dX? dX: gen_0, T));1066init_modular_big(&S);1067H = gen_crt("chinese_units", worker, &S, f, bnd, 0, &mod, nmV_chinese_center, FpM_center);1068settyp(H, t_VEC); return gerepilecopy(av, H);1069}10701071/* *pE a ZM */1072static void1073ZM_remove_unused(GEN *pE, GEN *pX)1074{1075long j, k, l = lg(*pX);1076GEN E = *pE, v = cgetg(l, t_VECSMALL);1077for (j = k = 1; j < l; j++)1078if (!ZMrow_equal0(E, j)) v[k++] = j;1079if (k < l)1080{1081setlg(v, k);1082*pX = vecpermute(*pX,v);1083*pE = rowpermute(E,v);1084}1085}10861087/* s = -log|norm(x)|/N */1088static GEN1089fixarch(GEN x, GEN s, long R1)1090{1091long i, l;1092GEN y = cgetg_copy(x, &l);1093for (i = 1; i <= R1; i++) gel(y,i) = gadd(s, gel(x,i));1094for ( ; i < l; i++) gel(y,i) = gadd(s, gmul2n(gel(x,i),-1));1095return y;1096}10971098static GEN1099getfu(GEN nf, GEN *ptA, GEN *ptU, long prec)1100{1101GEN U, y, matep, A, T = nf_get_pol(nf), M = nf_get_M(nf);1102long e, j, R1, RU, N = degpol(T);11031104R1 = nf_get_r1(nf); RU = (N+R1) >> 1;1105if (RU == 1) return cgetg(1,t_VEC);11061107A = *ptA;1108matep = cgetg(RU,t_MAT);1109for (j = 1; j < RU; j++)1110{1111GEN Aj = gel(A,j), s = gdivgs(RgV_sum(real_i(Aj)), -N);1112gel(matep,j) = fixarch(Aj, s, R1);1113}1114U = lll(real_i(matep));1115if (lg(U) < RU) return not_given(fupb_PRECI);1116if (ptU) { *ptU = U; *ptA = A = RgM_ZM_mul(A,U); }1117y = RgM_ZM_mul(matep,U);1118e = RgM_expbitprec(y);1119if (e >= 0) return not_given(e == LONG_MAX? fupb_LARGE: fupb_PRECI);1120if (prec <= 0) prec = gprecision(A);1121y = RgM_solve_realimag(M, gexp(y,prec));1122if (!y) return not_given(fupb_PRECI);1123y = grndtoi(y, &e); if (e >= 0) return not_given(fupb_PRECI);1124settyp(y, t_VEC);11251126if (!ptU) *ptA = A = RgM_ZM_mul(A, U);1127for (j = 1; j < RU; j++)1128{ /* y[i] are hopefully unit generators. Normalize: smallest T2 norm */1129GEN u = gel(y,j), v = zk_inv(nf, u);1130if (!v || !is_pm1(Q_denom(v)) || ZV_isscalar(u))1131return not_given(fupb_PRECI);1132if (gcmp(RgC_fpnorml2(v,DEFAULTPREC), RgC_fpnorml2(u,DEFAULTPREC)) < 0)1133{1134gel(A,j) = RgC_neg(gel(A,j));1135if (ptU) gel(U,j) = ZC_neg(gel(U,j));1136u = v;1137}1138gel(y,j) = nf_to_scalar_or_alg(nf, u);1139}1140return y;1141}11421143static void1144err_units() { pari_err_PREC("makeunits [cannot get units, use bnfinit(,1)]"); }11451146/* bound for log2 |sigma(u)|, sigma complex embedding, u fundamental unit1147* attached to bnf_get_logfu */1148static double1149log2fubound(GEN bnf)1150{1151GEN LU = bnf_get_logfu(bnf);1152long i, j, l = lg(LU), r1 = nf_get_r1(bnf_get_nf(bnf));1153double e = 0.0;1154for (j = 1; j < l; j++)1155{1156GEN u = gel(LU,j);1157for (i = 1; i <= r1; i++)1158{1159GEN E = real_i(gel(u,i));1160e = maxdd(e, gtodouble(E));1161}1162for ( ; i <= l; i++)1163{1164GEN E = real_i(gel(u,i));1165e = maxdd(e, gtodouble(E) / 2);1166}1167}1168return e / M_LN2;1169}1170/* bound for log2(|split_real_imag(M, y)|_oo / |y|_oo)*/1171static double1172log2Mbound(GEN nf)1173{1174GEN G = nf_get_G(nf), D = nf_get_disc(nf);1175long r2 = nf_get_r2(nf), l = lg(G), i;1176double e, d = dbllog2(D)/2 - r2 * M_LN2; /* log2 |det(split_real_imag(M))| */1177e = log2(nf_get_degree(nf));1178for (i = 2; i < l; i++) e += dbllog2(gnorml2(gel(G,i))); /* Hadamard bound */1179return e / 2 - d;1180}11811182static GEN1183vec_chinese_unit(GEN bnf)1184{1185GEN nf = bnf_get_nf(bnf), SUnits = bnf_get_sunits(bnf);1186ulong bnd = (ulong)ceil(log2Mbound(nf) + log2fubound(bnf));1187GEN X, dX, Y, U, f = nf_get_index(nf);1188long j, l, v = nf_get_varn(nf);1189if (!SUnits) err_units(); /* no compact units */1190Y = gel(SUnits,1);1191U = gel(SUnits,2);1192ZM_remove_unused(&U, &Y); l = lg(Y); X = cgetg(l, t_VEC);1193if (is_pm1(f)) f = dX = NULL; else dX = cgetg(l, t_VEC);1194for (j = 1; j < l; j++)1195{1196GEN t = nf_to_scalar_or_alg(nf, gel(Y,j));1197if (f)1198{1199GEN den;1200t = Q_remove_denom(t, &den);1201gel(dX,j) = den ? den: gen_1;1202}1203gel(X,j) = typ(t) == t_INT? scalarpol_shallow(t,v): t;1204}1205return chinese_unit(nf, X, dX, U, bnd);1206}12071208static GEN1209makeunits(GEN bnf)1210{1211GEN nf = bnf_get_nf(bnf), fu = bnf_get_fu_nocheck(bnf);1212GEN tu = nf_to_scalar_or_basis(nf, bnf_get_tuU(bnf));1213fu = (typ(fu) == t_MAT)? vec_chinese_unit(bnf): matalgtobasis(nf, fu);1214return vec_prepend(fu, tu);1215}12161217/*******************************************************************/1218/* */1219/* PRINCIPAL IDEAL ALGORITHM (DISCRETE LOG) */1220/* */1221/*******************************************************************/12221223/* G: prime ideals, E: vector of nonnegative exponents.1224* C = possible extra prime (^1) or NULL1225* Return Norm (product) */1226static GEN1227get_norm_fact_primes(GEN G, GEN E, GEN C)1228{1229pari_sp av=avma;1230GEN N = gen_1, P, p;1231long i, c = lg(E);1232for (i=1; i<c; i++)1233{1234GEN ex = gel(E,i);1235long s = signe(ex);1236if (!s) continue;12371238P = gel(G,i); p = pr_get_p(P);1239N = mulii(N, powii(p, mului(pr_get_f(P), ex)));1240}1241if (C) N = mulii(N, pr_norm(C));1242return gerepileuptoint(av, N);1243}12441245/* gen: HNF ideals */1246static GEN1247get_norm_fact(GEN gen, GEN ex, GEN *pd)1248{1249long i, c = lg(ex);1250GEN d,N,I,e,n,ne,de;1251d = N = gen_1;1252for (i=1; i<c; i++)1253if (signe(gel(ex,i)))1254{1255I = gel(gen,i); e = gel(ex,i); n = ZM_det_triangular(I);1256ne = powii(n,e);1257de = equalii(n, gcoeff(I,1,1))? ne: powii(gcoeff(I,1,1), e);1258N = mulii(N, ne);1259d = mulii(d, de);1260}1261*pd = d; return N;1262}12631264static GEN1265get_pr_lists(GEN FB, long N, int list_pr)1266{1267GEN pr, L;1268long i, l = lg(FB), p, pmax;12691270pmax = 0;1271for (i=1; i<l; i++)1272{1273pr = gel(FB,i); p = pr_get_smallp(pr);1274if (p > pmax) pmax = p;1275}1276L = const_vec(pmax, NULL);1277if (list_pr)1278{1279for (i=1; i<l; i++)1280{1281pr = gel(FB,i); p = pr_get_smallp(pr);1282if (!L[p]) gel(L,p) = vectrunc_init(N+1);1283vectrunc_append(gel(L,p), pr);1284}1285for (p=1; p<=pmax; p++)1286if (L[p]) gen_sort_inplace(gel(L,p), (void*)&cmp_prime_over_p,1287&cmp_nodata, NULL);1288}1289else1290{1291for (i=1; i<l; i++)1292{1293pr = gel(FB,i); p = pr_get_smallp(pr);1294if (!L[p]) gel(L,p) = vecsmalltrunc_init(N+1);1295vecsmalltrunc_append(gel(L,p), i);1296}1297}1298return L;1299}13001301/* recover FB, LV, iLP, KCZ from Vbase */1302static GEN1303recover_partFB(FB_t *F, GEN Vbase, long N)1304{1305GEN FB, LV, iLP, L = get_pr_lists(Vbase, N, 0);1306long l = lg(L), p, ip, i;13071308i = ip = 0;1309FB = cgetg(l, t_VECSMALL);1310iLP= cgetg(l, t_VECSMALL);1311LV = cgetg(l, t_VEC);1312for (p = 2; p < l; p++)1313{1314if (!L[p]) continue;1315FB[++i] = p;1316gel(LV,p) = vecpermute(Vbase, gel(L,p));1317iLP[p]= ip; ip += lg(gel(L,p))-1;1318}1319F->KCZ = i;1320F->KC = ip;1321F->FB = FB; setlg(FB, i+1);1322F->LV = LV;1323F->iLP= iLP; return L;1324}13251326/* add v^e to factorization */1327static void1328add_to_fact(long v, long e, FACT *fact)1329{1330long i, l = fact[0].pr;1331for (i=1; i<=l && fact[i].pr < v; i++)/*empty*/;1332if (i <= l && fact[i].pr == v) fact[i].ex += e; else store(v, e, fact);1333}1334static void1335inv_fact(FACT *fact)1336{1337long i, l = fact[0].pr;1338for (i=1; i<=l; i++) fact[i].ex = -fact[i].ex;1339}13401341/* L (small) list of primes above the same p including pr. Return pr index */1342static int1343pr_index(GEN L, GEN pr)1344{1345long j, l = lg(L);1346GEN al = pr_get_gen(pr);1347for (j=1; j<l; j++)1348if (ZV_equal(al, pr_get_gen(gel(L,j)))) return j;1349pari_err_BUG("codeprime");1350return 0; /* LCOV_EXCL_LINE */1351}13521353static long1354Vbase_to_FB(FB_t *F, GEN pr)1355{1356long p = pr_get_smallp(pr);1357return F->iLP[p] + pr_index(gel(F->LV,p), pr);1358}13591360/* x, y 2 extended ideals whose first component is an integral HNF and second1361* a famat */1362static GEN1363idealHNF_mulred(GEN nf, GEN x, GEN y)1364{1365GEN A = idealHNF_mul(nf, gel(x,1), gel(y,1));1366GEN F = famat_mul_shallow(gel(x,2), gel(y,2));1367return idealred(nf, mkvec2(A, F));1368}1369/* idealred(x * pr^n), n > 0 is small, x extended ideal. Reduction in order to1370* avoid prec pb: don't let id become too large as lgsub increases */1371static GEN1372idealmulpowprime2(GEN nf, GEN x, GEN pr, ulong n)1373{1374GEN A = idealmulpowprime(nf, gel(x,1), pr, utoipos(n));1375return mkvec2(A, gel(x,2));1376}1377static GEN1378init_famat(GEN x) { return mkvec2(x, trivial_fact()); }1379/* optimized idealfactorback + reduction; z = init_famat() */1380static GEN1381powred(GEN z, GEN nf, GEN p, GEN e)1382{ gel(z,1) = p; return idealpowred(nf, z, e); }1383static GEN1384genback(GEN z, GEN nf, GEN P, GEN E)1385{1386long i, l = lg(E);1387GEN I = NULL;1388for (i = 1; i < l; i++)1389if (signe(gel(E,i)))1390{1391GEN J = powred(z, nf, gel(P,i), gel(E,i));1392I = I? idealHNF_mulred(nf, I, J): J;1393}1394return I; /* != NULL since a generator */1395}13961397/* return famat y (principal ideal) such that y / x is smooth [wrt Vbase] */1398static GEN1399SPLIT(FB_t *F, GEN nf, GEN x, GEN Vbase, FACT *fact)1400{1401GEN vecG, ex, Ly, y, x0, Nx = ZM_det_triangular(x);1402long nbtest_lim, nbtest, i, j, k, ru, lgsub;1403pari_sp av;14041405/* try without reduction if x is small */1406if (gexpo(gcoeff(x,1,1)) < 100 &&1407can_factor(F, nf, x, NULL, Nx, fact)) return NULL;14081409av = avma;1410Ly = idealpseudominvec(x, nf_get_roundG(nf));1411for(k=1; k<lg(Ly); k++)1412{1413y = gel(Ly,k);1414if (factorgen(F, nf, x, Nx, y, fact)) return y;1415}1416set_avma(av);14171418/* reduce in various directions */1419ru = lg(nf_get_roots(nf));1420vecG = cgetg(ru, t_VEC);1421for (j=1; j<ru; j++)1422{1423gel(vecG,j) = nf_get_Gtwist1(nf, j);1424av = avma;1425Ly = idealpseudominvec(x, gel(vecG,j));1426for(k=1; k<lg(Ly); k++)1427{1428y = gel(Ly,k);1429if (factorgen(F, nf, x, Nx, y, fact)) return y;1430}1431set_avma(av);1432}14331434/* tough case, multiply by random products */1435lgsub = 3;1436ex = cgetg(lgsub, t_VECSMALL);1437x0 = init_famat(x);1438nbtest = 1; nbtest_lim = 4;1439for(;;)1440{1441GEN Ired, I, NI, id = x0;1442av = avma;1443if (DEBUGLEVEL>2) err_printf("# ideals tried = %ld\n",nbtest);1444for (i=1; i<lgsub; i++)1445{1446ex[i] = random_bits(RANDOM_BITS);1447if (ex[i]) id = idealmulpowprime2(nf, id, gel(Vbase,i), ex[i]);1448}1449if (id == x0) continue;1450/* I^(-1) * \prod Vbase[i]^ex[i] = (id[2]) / x */14511452I = gel(id,1); NI = ZM_det_triangular(I);1453if (can_factor(F, nf, I, NULL, NI, fact))1454{1455inv_fact(fact); /* I^(-1) */1456for (i=1; i<lgsub; i++)1457if (ex[i]) add_to_fact(Vbase_to_FB(F,gel(Vbase,i)), ex[i], fact);1458return gel(id,2);1459}1460Ired = ru == 2? I: ZM_lll(I, 0.99, LLL_INPLACE);1461for (j=1; j<ru; j++)1462{1463pari_sp av2 = avma;1464Ly = idealpseudominvec(Ired, gel(vecG,j));1465for (k=1; k < lg(Ly); k++)1466{1467y = gel(Ly,k);1468if (factorgen(F, nf, I, NI, y, fact))1469{1470for (i=1; i<lgsub; i++)1471if (ex[i]) add_to_fact(Vbase_to_FB(F,gel(Vbase,i)), ex[i], fact);1472return famat_mul_shallow(gel(id,2), y);1473}1474}1475set_avma(av2);1476}1477set_avma(av);1478if (++nbtest > nbtest_lim)1479{1480nbtest = 0;1481if (++lgsub < minss(8, lg(Vbase)-1))1482{1483nbtest_lim <<= 1;1484ex = cgetg(lgsub, t_VECSMALL);1485}1486else nbtest_lim = LONG_MAX; /* don't increase further */1487if (DEBUGLEVEL>2) err_printf("SPLIT: increasing factor base [%ld]\n",lgsub);1488}1489}1490}14911492INLINE GEN1493bnf_get_W(GEN bnf) { return gel(bnf,1); }1494INLINE GEN1495bnf_get_B(GEN bnf) { return gel(bnf,2); }1496INLINE GEN1497bnf_get_C(GEN bnf) { return gel(bnf,4); }1498INLINE GEN1499bnf_get_vbase(GEN bnf) { return gel(bnf,5); }1500INLINE GEN1501bnf_get_Ur(GEN bnf) { return gmael(bnf,9,1); }1502INLINE GEN1503bnf_get_ga(GEN bnf) { return gmael(bnf,9,2); }1504INLINE GEN1505bnf_get_GD(GEN bnf) { return gmael(bnf,9,3); }15061507/* Return y (as an elt of K or a t_MAT representing an elt in Z[K])1508* such that x / (y) is smooth and store the exponents of its factorization1509* on g_W and g_B in Wex / Bex; return NULL for y = 1 */1510static GEN1511split_ideal(GEN bnf, GEN x, GEN *pWex, GEN *pBex)1512{1513GEN L, y, Vbase = bnf_get_vbase(bnf);1514GEN Wex, W = bnf_get_W(bnf);1515GEN Bex, B = bnf_get_B(bnf);1516long p, j, i, l, nW, nB;1517FACT *fact;1518FB_t F;15191520L = recover_partFB(&F, Vbase, lg(x)-1);1521fact = (FACT*)stack_malloc((F.KC+1)*sizeof(FACT));1522y = SPLIT(&F, bnf_get_nf(bnf), x, Vbase, fact);1523nW = lg(W)-1; *pWex = Wex = zero_zv(nW);1524nB = lg(B)-1; *pBex = Bex = zero_zv(nB); l = lg(F.FB);1525p = j = 0; /* -Wall */1526for (i = 1; i <= fact[0].pr; i++)1527{ /* decode index C = ip+j --> (p,j) */1528long a, b, t, C = fact[i].pr;1529for (t = 1; t < l; t++)1530{1531long q = F.FB[t], k = C - F.iLP[q];1532if (k <= 0) break;1533p = q;1534j = k;1535}1536a = gel(L, p)[j];1537b = a - nW;1538if (b <= 0) Wex[a] = y? -fact[i].ex: fact[i].ex;1539else Bex[b] = y? -fact[i].ex: fact[i].ex;1540}1541return y;1542}15431544GEN1545init_red_mod_units(GEN bnf, long prec)1546{1547GEN s = gen_0, p1,s1,mat, logfu = bnf_get_logfu(bnf);1548long i,j, RU = lg(logfu);15491550if (RU == 1) return NULL;1551mat = cgetg(RU,t_MAT);1552for (j=1; j<RU; j++)1553{1554p1 = cgetg(RU+1,t_COL); gel(mat,j) = p1;1555s1 = gen_0;1556for (i=1; i<RU; i++)1557{1558gel(p1,i) = real_i(gcoeff(logfu,i,j));1559s1 = mpadd(s1, mpsqr(gel(p1,i)));1560}1561gel(p1,RU) = gen_0; if (mpcmp(s1,s) > 0) s = s1;1562}1563s = gsqrt(gmul2n(s,RU),prec);1564if (expo(s) < 27) s = utoipos(1UL << 27);1565return mkvec2(mat, s);1566}15671568/* z computed above. Return unit exponents that would reduce col (arch) */1569GEN1570red_mod_units(GEN col, GEN z)1571{1572long i,RU;1573GEN x,mat,N2;15741575if (!z) return NULL;1576mat= gel(z,1);1577N2 = gel(z,2);1578RU = lg(mat); x = cgetg(RU+1,t_COL);1579for (i=1; i<RU; i++) gel(x,i) = real_i(gel(col,i));1580gel(x,RU) = N2;1581x = lll(shallowconcat(mat,x));1582if (typ(x) != t_MAT || lg(x) <= RU) return NULL;1583x = gel(x,RU);1584if (signe(gel(x,RU)) < 0) x = gneg_i(x);1585if (!gequal1(gel(x,RU))) pari_err_BUG("red_mod_units");1586setlg(x,RU); return x;1587}15881589static GEN1590add(GEN a, GEN t) { return a = a? RgC_add(a,t): t; }15911592/* [x] archimedian components, A column vector. return [x] A */1593static GEN1594act_arch(GEN A, GEN x)1595{1596GEN a;1597long i,l = lg(A), tA = typ(A);1598if (tA == t_MAT)1599{ /* assume lg(x) >= l */1600a = cgetg(l, t_MAT);1601for (i=1; i<l; i++) gel(a,i) = act_arch(gel(A,i), x);1602return a;1603}1604if (l==1) return cgetg(1, t_COL);1605a = NULL;1606if (tA == t_VECSMALL)1607{1608for (i=1; i<l; i++)1609{1610long c = A[i];1611if (c) a = add(a, gmulsg(c, gel(x,i)));1612}1613}1614else1615{ /* A a t_COL of t_INT. Assume lg(A)==lg(x) */1616for (i=1; i<l; i++)1617{1618GEN c = gel(A,i);1619if (signe(c)) a = add(a, gmul(c, gel(x,i)));1620}1621}1622return a? a: zerocol(lgcols(x)-1);1623}1624/* act_arch(matdiagonal(v), x) */1625static GEN1626diagact_arch(GEN v, GEN x)1627{1628long i, l = lg(v);1629GEN a = cgetg(l, t_MAT);1630for (i = 1; i < l; i++) gel(a,i) = gmul(gel(x,i), gel(v,i));1631return a;1632}16331634static long1635prec_arch(GEN bnf)1636{1637GEN a = bnf_get_C(bnf);1638long i, l = lg(a), prec;16391640for (i=1; i<l; i++)1641if ( (prec = gprecision(gel(a,i))) ) return prec;1642return DEFAULTPREC;1643}16441645static long1646needed_bitprec(GEN x)1647{1648long i, e = 0, l = lg(x);1649for (i = 1; i < l; i++)1650{1651GEN c = gel(x,i);1652long f = gexpo(c) - prec2nbits(gprecision(c));1653if (f > e) e = f;1654}1655return e;1656}16571658/* col = archimedian components of x, Nx its norm, dx a multiple of its1659* denominator. Return x or NULL (fail) */1660GEN1661isprincipalarch(GEN bnf, GEN col, GEN kNx, GEN e, GEN dx, long *pe)1662{1663GEN nf, x, y, logfu, s, M;1664long N, prec = gprecision(col);1665bnf = checkbnf(bnf); nf = bnf_get_nf(bnf); M = nf_get_M(nf);1666if (!prec) prec = prec_arch(bnf);1667*pe = 128;1668logfu = bnf_get_logfu(bnf);1669N = nf_get_degree(nf);1670if (!(col = cleanarch(col,N,prec))) return NULL;1671if (lg(col) > 2)1672{ /* reduce mod units */1673GEN u, z = init_red_mod_units(bnf,prec);1674if (!(u = red_mod_units(col,z))) return NULL;1675col = RgC_add(col, RgM_RgC_mul(logfu, u));1676if (!(col = cleanarch(col,N,prec))) return NULL;1677}1678s = divru(mulir(e, glog(kNx,prec)), N);1679col = fixarch(col, s, nf_get_r1(nf));1680if (RgC_expbitprec(col) >= 0) return NULL;1681col = gexp(col, prec);1682/* d.alpha such that x = alpha \prod gj^ej */1683x = RgM_solve_realimag(M,col); if (!x) return NULL;1684x = RgC_Rg_mul(x, dx);1685y = grndtoi(x, pe);1686if (*pe > -5) { *pe = needed_bitprec(x); return NULL; }1687return RgC_Rg_div(y, dx);1688}16891690/* y = C \prod g[i]^e[i] ? */1691static int1692fact_ok(GEN nf, GEN y, GEN C, GEN g, GEN e)1693{1694pari_sp av = avma;1695long i, c = lg(e);1696GEN z = C? C: gen_1;1697for (i=1; i<c; i++)1698if (signe(gel(e,i))) z = idealmul(nf, z, idealpow(nf, gel(g,i), gel(e,i)));1699if (typ(z) != t_MAT) z = idealhnf_shallow(nf,z);1700if (typ(y) != t_MAT) y = idealhnf_shallow(nf,y);1701return gc_bool(av, ZM_equal(y,z));1702}1703static GEN1704ZV_divrem(GEN A, GEN B, GEN *pR)1705{1706long i, l = lg(A);1707GEN Q = cgetg(l, t_COL), R = cgetg(l, t_COL);1708for (i = 1; i < l; i++) gel(Q,i) = truedvmdii(gel(A,i), gel(B,i), &gel(R,i));1709*pR = R; return Q;1710}17111712static GEN1713Ur_ZC_mul(GEN bnf, GEN v)1714{1715GEN w, U = bnf_get_Ur(bnf);1716long i, l = lg(bnf_get_cyc(bnf)); /* may be < lgcols(U) */17171718w = cgetg(l, t_COL);1719for (i = 1; i < l; i++) gel(w,i) = ZMrow_ZC_mul(U, v, i);1720return w;1721}17221723static GEN1724ZV_mul(GEN x, GEN y)1725{1726long i, l = lg(x);1727GEN z = cgetg(l, t_COL);1728for (i = 1; i < l; i++) gel(z,i) = mulii(gel(x,i), gel(y,i));1729return z;1730}1731static int1732dump_gen(GEN x, long flag)1733{1734GEN d;1735if (!(flag & nf_GENMAT)) return 0;1736x = Q_remove_denom(x, &d);1737return (d && expi(d) > 32) || gexpo(x) > 32;1738}17391740/* assume x in HNF; cf class_group_gen for notations. Return NULL iff1741* flag & nf_FORCE and computation of principal ideal generator fails */1742static GEN1743isprincipalall(GEN bnf, GEN x, long *pprec, long flag)1744{1745GEN xar, Wex, Bex, gen, xc, col, A, Q, R, UA, SUnits;1746GEN C = bnf_get_C(bnf), nf = bnf_get_nf(bnf), cyc = bnf_get_cyc(bnf);1747long nB, nW, e;17481749if (lg(cyc) == 1 && !(flag & (nf_GEN|nf_GENMAT|nf_GEN_IF_PRINCIPAL)))1750return cgetg(1,t_COL);1751if (lg(x) == 2)1752{ /* nf = Q */1753col = gel(x,1);1754if (flag & nf_GENMAT) col = to_famat_shallow(col, gen_1);1755return (flag & nf_GEN_IF_PRINCIPAL)? col: mkvec2(cgetg(1,t_COL), col);1756}17571758x = Q_primitive_part(x, &xc);1759if (equali1(gcoeff(x,1,1))) /* trivial ideal */1760{1761R = zerocol(lg(cyc)-1);1762if (!(flag & (nf_GEN|nf_GENMAT|nf_GEN_IF_PRINCIPAL))) return R;1763if (flag & nf_GEN_IF_PRINCIPAL)1764return scalarcol_shallow(xc? xc: gen_1, nf_get_degree(nf));1765if (flag & nf_GENMAT)1766col = xc? to_famat_shallow(xc, gen_1): trivial_fact();1767else1768col = scalarcol_shallow(xc? xc: gen_1, nf_get_degree(nf));1769return mkvec2(R, col);1770}1771xar = split_ideal(bnf, x, &Wex, &Bex);1772/* x = g_W Wex + g_B Bex + [xar] = g_W (Wex - B*Bex) + [xar] + [C_B]Bex */1773A = zc_to_ZC(Wex); nB = lg(Bex)-1;1774if (nB) A = ZC_sub(A, ZM_zc_mul(bnf_get_B(bnf), Bex));1775UA = Ur_ZC_mul(bnf, A);1776Q = ZV_divrem(UA, cyc, &R);1777/* g_W (Wex - B*Bex) = G Ur A - [ga]A = G R + [GD]Q - [ga]A1778* Finally: x = G R + [xar] + [C_B]Bex + [GD]Q - [ga]A */1779if (!(flag & (nf_GEN|nf_GENMAT|nf_GEN_IF_PRINCIPAL))) return R;1780if ((flag & nf_GEN_IF_PRINCIPAL) && !ZV_equal0(R)) return gen_0;17811782nW = lg(Wex)-1;1783gen = bnf_get_gen(bnf);1784col = NULL;1785SUnits = bnf_get_sunits(bnf);1786if (lg(R) == 11787|| abscmpiu(gel(R,vecindexmax(R)), 4 * bit_accuracy(*pprec)) < 0)1788{ /* q = N (x / prod gj^ej) = N(alpha), denom(alpha) | d */1789GEN d, q = gdiv(ZM_det_triangular(x), get_norm_fact(gen, R, &d));1790col = xar? nf_cxlog(nf, xar, *pprec): NULL;1791if (nB) col = add(col, act_arch(Bex, nW? vecslice(C,nW+1,lg(C)-1): C));1792if (nW) col = add(col, RgC_sub(act_arch(Q, bnf_get_GD(bnf)),1793act_arch(A, bnf_get_ga(bnf))));1794col = isprincipalarch(bnf, col, q, gen_1, d, &e);1795if (col && ((SUnits && dump_gen(col, flag))1796|| !fact_ok(nf,x, col,gen,R))) col = NULL;1797}1798if (!col && (flag & nf_GENMAT))1799{1800if (SUnits)1801{1802GEN X = gel(SUnits,1), U = gel(SUnits,2), C = gel(SUnits,3);1803GEN v = gel(bnf,9), Ge = gel(v,4), M1 = gel(v,5), M2 = gel(v,6);1804GEN z = NULL, F = NULL;1805if (nB)1806{1807GEN C2 = nW? vecslice(C, nW+1, lg(C)-1): C;1808z = ZM_zc_mul(C2, Bex);1809}1810if (nW)1811{ /* [GD]Q - [ga]A = ([X]M1 - [Ge]D) Q - ([X]M2 - [Ge]Ur) A */1812GEN C1 = vecslice(C, 1, nW);1813GEN v = ZC_sub(ZM_ZC_mul(M1,Q), ZM_ZC_mul(M2,A));1814z = add(z, ZM_ZC_mul(C1, v));1815F = famat_reduce(famatV_factorback(Ge, ZC_sub(UA, ZV_mul(cyc,Q))));1816if (lgcols(F) == 1) F = NULL;1817}1818/* reduce modulo units and Q^* */1819if (lg(U) != 1) z = ZC_sub(z, ZM_ZC_mul(U, RgM_Babai(U,z)));1820col = mkmat2(X, z);1821if (F) col = famat_mul_shallow(col, F);1822col = famat_remove_trivial(col);1823if (xar) col = famat_mul_shallow(col, xar);1824}1825else if (!ZV_equal0(R))1826{ /* in case isprincipalfact calls bnfinit() due to prec trouble...*/1827GEN y = isprincipalfact(bnf, x, gen, ZC_neg(R), flag);1828if (typ(y) != t_VEC) return y;1829col = gel(y,2);1830}1831}1832if (col)1833{ /* add back missing content */1834if (xc) col = (typ(col)==t_MAT)? famat_mul_shallow(col,xc)1835: RgC_Rg_mul(col,xc);1836if (typ(col) != t_MAT && lg(col) != 1 && (flag & nf_GENMAT))1837col = to_famat_shallow(col, gen_1);1838}1839else1840{1841if (e < 0) e = 0;1842*pprec += nbits2extraprec(e + 128);1843if (flag & nf_FORCE)1844{1845if (DEBUGLEVEL)1846pari_warn(warner,"precision too low for generators, e = %ld",e);1847return NULL;1848}1849pari_warn(warner,"precision too low for generators, not given");1850col = cgetg(1, t_COL);1851}1852return (flag & nf_GEN_IF_PRINCIPAL)? col: mkvec2(R, col);1853}18541855static GEN1856triv_gen(GEN bnf, GEN x, long flag)1857{1858pari_sp av = avma;1859GEN nf = bnf_get_nf(bnf);1860long c;1861if (flag & nf_GEN_IF_PRINCIPAL)1862{1863if (!(flag & nf_GENMAT)) return algtobasis(nf,x);1864x = nf_to_scalar_or_basis(nf,x);1865if (typ(x) == t_INT && is_pm1(x)) return trivial_fact();1866return gerepilecopy(av, to_famat_shallow(x, gen_1));1867}1868c = lg(bnf_get_cyc(bnf)) - 1;1869if (flag & nf_GENMAT)1870retmkvec2(zerocol(c), to_famat_shallow(algtobasis(nf,x), gen_1));1871if (flag & nf_GEN)1872retmkvec2(zerocol(c), algtobasis(nf,x));1873return zerocol(c);1874}18751876GEN1877bnfisprincipal0(GEN bnf,GEN x,long flag)1878{1879pari_sp av = avma;1880GEN arch, c, nf;1881long pr;18821883bnf = checkbnf(bnf);1884nf = bnf_get_nf(bnf);1885switch( idealtyp(&x, &arch) )1886{1887case id_PRINCIPAL:1888if (gequal0(x)) pari_err_DOMAIN("bnfisprincipal","ideal","=",gen_0,x);1889return triv_gen(bnf, x, flag);1890case id_PRIME:1891if (pr_is_inert(x)) return triv_gen(bnf, pr_get_p(x), flag);1892x = pr_hnf(nf, x);1893break;1894case id_MAT:1895if (lg(x)==1) pari_err_DOMAIN("bnfisprincipal","ideal","=",gen_0,x);1896if (nf_get_degree(nf) != lg(x)-1)1897pari_err_TYPE("idealtyp [dimension != degree]", x);1898}1899pr = prec_arch(bnf); /* precision of unit matrix */1900c = getrand();1901for (;;)1902{1903pari_sp av1 = avma;1904GEN y = isprincipalall(bnf,x,&pr,flag);1905if (y) return gerepilecopy(av, y);19061907if (DEBUGLEVEL) pari_warn(warnprec,"isprincipal",pr);1908set_avma(av1); bnf = bnfnewprec_shallow(bnf,pr); setrand(c);1909}1910}1911GEN1912isprincipal(GEN bnf,GEN x) { return bnfisprincipal0(bnf,x,0); }19131914/* FIXME: OBSOLETE */1915GEN1916isprincipalgen(GEN bnf,GEN x)1917{ return bnfisprincipal0(bnf,x,nf_GEN); }1918GEN1919isprincipalforce(GEN bnf,GEN x)1920{ return bnfisprincipal0(bnf,x,nf_FORCE); }1921GEN1922isprincipalgenforce(GEN bnf,GEN x)1923{ return bnfisprincipal0(bnf,x,nf_GEN | nf_FORCE); }19241925/* lg(u) > 1 */1926static int1927RgV_is1(GEN u) { return isint1(gel(u,1)) && RgV_isscalar(u); }1928static GEN1929add_principal_part(GEN nf, GEN u, GEN v, long flag)1930{1931if (flag & nf_GENMAT)1932return (typ(u) == t_COL && RgV_is1(u))? v: famat_mul_shallow(v,u);1933else1934return nfmul(nf, v, u);1935}19361937#if 01938/* compute C prod P[i]^e[i], e[i] >=0 for all i. C may be NULL (omitted)1939* e destroyed ! */1940static GEN1941expand(GEN nf, GEN C, GEN P, GEN e)1942{1943long i, l = lg(e), done = 1;1944GEN id = C;1945for (i=1; i<l; i++)1946{1947GEN ei = gel(e,i);1948if (signe(ei))1949{1950if (mod2(ei)) id = id? idealmul(nf, id, gel(P,i)): gel(P,i);1951ei = shifti(ei,-1);1952if (signe(ei)) done = 0;1953gel(e,i) = ei;1954}1955}1956if (id != C) id = idealred(nf, id);1957if (done) return id;1958return idealmulred(nf, id, idealsqr(nf, expand(nf,id,P,e)));1959}1960/* C is an extended ideal, possibly with C[1] = NULL */1961static GEN1962expandext(GEN nf, GEN C, GEN P, GEN e)1963{1964long i, l = lg(e), done = 1;1965GEN A = gel(C,1);1966for (i=1; i<l; i++)1967{1968GEN ei = gel(e,i);1969if (signe(ei))1970{1971if (mod2(ei)) A = A? idealmul(nf, A, gel(P,i)): gel(P,i);1972ei = shifti(ei,-1);1973if (signe(ei)) done = 0;1974gel(e,i) = ei;1975}1976}1977if (A == gel(C,1))1978A = C;1979else1980A = idealred(nf, mkvec2(A, gel(C,2)));1981if (done) return A;1982return idealmulred(nf, A, idealsqr(nf, expand(nf,A,P,e)));1983}1984#endif19851986static GEN1987expand(GEN nf, GEN C, GEN P, GEN e)1988{1989long i, l = lg(e);1990GEN B, A = C;1991for (i=1; i<l; i++) /* compute prod P[i]^e[i] */1992if (signe(gel(e,i)))1993{1994B = idealpowred(nf, gel(P,i), gel(e,i));1995A = A? idealmulred(nf,A,B): B;1996}1997return A;1998}1999static GEN2000expandext(GEN nf, GEN C, GEN P, GEN e)2001{2002long i, l = lg(e);2003GEN B, A = gel(C,1), C1 = A;2004for (i=1; i<l; i++) /* compute prod P[i]^e[i] */2005if (signe(gel(e,i)))2006{2007gel(C,1) = gel(P,i);2008B = idealpowred(nf, C, gel(e,i));2009A = A? idealmulred(nf,A,B): B;2010}2011return A == C1? C: A;2012}20132014/* isprincipal for C * \prod P[i]^e[i] (C omitted if NULL) */2015GEN2016isprincipalfact(GEN bnf, GEN C, GEN P, GEN e, long flag)2017{2018const long gen = flag & (nf_GEN|nf_GENMAT|nf_GEN_IF_PRINCIPAL);2019long prec;2020pari_sp av = avma;2021GEN C0, Cext, c, id, nf = checknf(bnf);20222023if (gen)2024{2025Cext = (flag & nf_GENMAT)? trivial_fact()2026: mkpolmod(gen_1,nf_get_pol(nf));2027C0 = mkvec2(C, Cext);2028id = expandext(nf, C0, P, e);2029} else {2030Cext = NULL;2031C0 = C;2032id = expand(nf, C, P, e);2033}2034if (id == C0) /* e = 0 */2035{2036if (!C) return bnfisprincipal0(bnf, gen_1, flag);2037switch(typ(C))2038{2039case t_INT: case t_FRAC: case t_POL: case t_POLMOD: case t_COL:2040return triv_gen(bnf, C, flag);2041}2042C = idealhnf_shallow(nf,C);2043}2044else2045{2046if (gen) { C = gel(id,1); Cext = gel(id,2); } else C = id;2047}2048prec = prec_arch(bnf);2049c = getrand();2050for (;;)2051{2052pari_sp av1 = avma;2053GEN y = isprincipalall(bnf, C, &prec, flag);2054if (y)2055{2056if (flag & nf_GEN_IF_PRINCIPAL)2057{2058if (typ(y) == t_INT) return gc_NULL(av);2059y = add_principal_part(nf, y, Cext, flag);2060}2061else2062{2063GEN u = gel(y,2);2064if (!gen || typ(y) != t_VEC) return gerepileupto(av,y);2065if (lg(u) != 1) gel(y,2) = add_principal_part(nf, u, Cext, flag);2066}2067return gerepilecopy(av, y);2068}2069if (DEBUGLEVEL) pari_warn(warnprec,"isprincipal",prec);2070set_avma(av1); bnf = bnfnewprec_shallow(bnf,prec); setrand(c);2071}2072}2073GEN2074isprincipalfact_or_fail(GEN bnf, GEN C, GEN P, GEN e)2075{2076const long flag = nf_GENMAT|nf_FORCE;2077long prec;2078pari_sp av = avma;2079GEN u, y, id, C0, Cext, nf = bnf_get_nf(bnf);20802081Cext = trivial_fact();2082C0 = mkvec2(C, Cext);2083id = expandext(nf, C0, P, e);2084if (id == C0) /* e = 0 */2085C = idealhnf_shallow(nf,C);2086else {2087C = gel(id,1); Cext = gel(id,2);2088}2089prec = prec_arch(bnf);2090y = isprincipalall(bnf, C, &prec, flag);2091if (!y) { set_avma(av); return utoipos(prec); }2092u = gel(y,2);2093if (lg(u) != 1) gel(y,2) = add_principal_part(nf, u, Cext, flag);2094return gerepilecopy(av, y);2095}20962097GEN2098nfsign_from_logarch(GEN LA, GEN invpi, GEN archp)2099{2100long l = lg(archp), i;2101GEN y = cgetg(l, t_VECSMALL);2102pari_sp av = avma;21032104for (i=1; i<l; i++)2105{2106GEN c = ground( gmul(imag_i(gel(LA,archp[i])), invpi) );2107y[i] = mpodd(c)? 1: 0;2108}2109set_avma(av); return y;2110}21112112GEN2113nfsign_tu(GEN bnf, GEN archp)2114{2115long n;2116if (bnf_get_tuN(bnf) != 2) return cgetg(1, t_VECSMALL);2117n = archp? lg(archp) - 1: nf_get_r1(bnf_get_nf(bnf));2118return const_vecsmall(n, 1);2119}2120GEN2121nfsign_fu(GEN bnf, GEN archp)2122{2123GEN invpi, y, A = bnf_get_logfu(bnf), nf = bnf_get_nf(bnf);2124long j = 1, RU = lg(A);21252126if (!archp) archp = identity_perm( nf_get_r1(nf) );2127invpi = invr( mppi(nf_get_prec(nf)) );2128y = cgetg(RU,t_MAT);2129for (j = 1; j < RU; j++)2130gel(y,j) = nfsign_from_logarch(gel(A,j), invpi, archp);2131return y;2132}2133GEN2134nfsign_units(GEN bnf, GEN archp, int add_zu)2135{2136GEN sfu = nfsign_fu(bnf, archp);2137return add_zu? vec_prepend(sfu, nfsign_tu(bnf, archp)): sfu;2138}21392140/* obsolete */2141GEN2142signunits(GEN bnf)2143{2144pari_sp av;2145GEN S, y, nf;2146long i, j, r1, r2;21472148bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);2149nf_get_sign(nf, &r1,&r2);2150S = zeromatcopy(r1, r1+r2-1); av = avma;2151y = nfsign_fu(bnf, NULL);2152for (j = 1; j < lg(y); j++)2153{2154GEN Sj = gel(S,j), yj = gel(y,j);2155for (i = 1; i <= r1; i++) gel(Sj,i) = yj[i]? gen_m1: gen_1;2156}2157set_avma(av); return S;2158}21592160static GEN2161get_log_embed(REL_t *rel, GEN M, long RU, long R1, long prec)2162{2163GEN arch, C, z = rel->m;2164long i;2165arch = typ(z) == t_COL? RgM_RgC_mul(M, z): const_col(nbrows(M), z);2166C = cgetg(RU+1, t_COL); arch = glog(arch, prec);2167for (i=1; i<=R1; i++) gel(C,i) = gel(arch,i);2168for ( ; i<=RU; i++) gel(C,i) = gmul2n(gel(arch,i), 1);2169return C;2170}2171static GEN2172rel_embed(REL_t *rel, FB_t *F, GEN embs, long ind, GEN M, long RU, long R1,2173long prec)2174{2175GEN C, D, perm;2176long i, n;2177if (!rel->relaut) return get_log_embed(rel, M, RU, R1, prec);2178/* image of another relation by automorphism */2179C = gel(embs, ind - rel->relorig);2180perm = gel(F->embperm, rel->relaut);2181D = cgetg_copy(C, &n);2182for (i = 1; i < n; i++)2183{2184long v = perm[i];2185gel(D,i) = (v > 0)? gel(C,v): conj_i(gel(C,-v));2186}2187return D;2188}2189static GEN2190get_embs(FB_t *F, RELCACHE_t *cache, GEN nf, GEN embs, long PREC)2191{2192long ru, j, k, l = cache->last - cache->chk + 1, r1 = nf_get_r1(nf);2193GEN M = nf_get_M(nf), nembs = cgetg(cache->last - cache->base+1, t_MAT);2194REL_t *rel;21952196for (k = 1; k <= cache->chk - cache->base; k++) gel(nembs,k) = gel(embs,k);2197embs = nembs; ru = nbrows(M);2198for (j=1,rel = cache->chk + 1; j < l; rel++,j++,k++)2199gel(embs,k) = rel_embed(rel, F, embs, k, M, ru, r1, PREC);2200return embs;2201}2202static void2203set_rel_alpha(REL_t *rel, GEN auts, GEN vA, long ind)2204{2205GEN u;2206if (!rel->relaut)2207u = rel->m;2208else2209u = ZM_ZC_mul(gel(auts, rel->relaut), gel(vA, ind - rel->relorig));2210gel(vA, ind) = u;2211}2212static GEN2213set_fact(FB_t *F, FACT *fact, GEN e, long *pnz)2214{2215long n = fact[0].pr;2216GEN c = zero_Flv(F->KC);2217if (!n) /* trivial factorization */2218*pnz = F->KC+1;2219else2220{2221long i, nz = minss(fact[1].pr, fact[n].pr);2222for (i = 1; i <= n; i++) c[fact[i].pr] = fact[i].ex;2223if (e)2224{2225long l = lg(e);2226for (i = 1; i < l; i++)2227if (e[i]) { long v = F->subFB[i]; c[v] += e[i]; if (v < nz) nz = v; }2228}2229*pnz = nz;2230}2231return c;2232}22332234/* Is cols already in the cache ? bs = index of first non zero coeff in cols2235* General check for colinearity useless since exceedingly rare */2236static int2237already_known(RELCACHE_t *cache, long bs, GEN cols)2238{2239REL_t *r;2240long l = lg(cols);2241for (r = cache->last; r > cache->base; r--)2242if (bs == r->nz)2243{2244GEN coll = r->R;2245long b = bs;2246while (b < l && cols[b] == coll[b]) b++;2247if (b == l) return 1;2248}2249return 0;2250}22512252/* Add relation R to cache, nz = index of first non zero coeff in R.2253* If relation is a linear combination of the previous ones, return 0.2254* Otherwise, update basis and return > 0. Compute mod p (much faster)2255* so some kernel vector might not be genuine. */2256static int2257add_rel_i(RELCACHE_t *cache, GEN R, long nz, GEN m, long orig, long aut, REL_t **relp, long in_rnd_rel)2258{2259long i, k, n = lg(R)-1;22602261if (nz == n+1) { k = 0; goto ADD_REL; }2262if (already_known(cache, nz, R)) return -1;2263if (cache->last >= cache->base + cache->len) return 0;2264if (DEBUGLEVEL>6)2265{2266err_printf("adding vector = %Ps\n",R);2267err_printf("generators =\n%Ps\n", cache->basis);2268}2269if (cache->missing)2270{2271GEN a = leafcopy(R), basis = cache->basis;2272k = lg(a);2273do --k; while (!a[k]);2274while (k)2275{2276GEN c = gel(basis, k);2277if (c[k])2278{2279long ak = a[k];2280for (i=1; i < k; i++) if (c[i]) a[i] = (a[i] + ak*(mod_p-c[i])) % mod_p;2281a[k] = 0;2282do --k; while (!a[k]); /* k cannot go below 0: codeword is a sentinel */2283}2284else2285{2286ulong invak = Fl_inv(uel(a,k), mod_p);2287/* Cleanup a */2288for (i = k; i-- > 1; )2289{2290long j, ai = a[i];2291c = gel(basis, i);2292if (!ai || !c[i]) continue;2293ai = mod_p-ai;2294for (j = 1; j < i; j++) if (c[j]) a[j] = (a[j] + ai*c[j]) % mod_p;2295a[i] = 0;2296}2297/* Insert a/a[k] as k-th column */2298c = gel(basis, k);2299for (i = 1; i<k; i++) if (a[i]) c[i] = (a[i] * invak) % mod_p;2300c[k] = 1; a = c;2301/* Cleanup above k */2302for (i = k+1; i<n; i++)2303{2304long j, ck;2305c = gel(basis, i);2306ck = c[k];2307if (!ck) continue;2308ck = mod_p-ck;2309for (j = 1; j < k; j++) if (a[j]) c[j] = (c[j] + ck*a[j]) % mod_p;2310c[k] = 0;2311}2312cache->missing--;2313break;2314}2315}2316}2317else2318k = (cache->last - cache->base) + 1;2319if (k || cache->relsup > 0 || (m && in_rnd_rel))2320{2321REL_t *rel;23222323ADD_REL:2324rel = ++cache->last;2325if (!k && cache->relsup && nz < n+1)2326{2327cache->relsup--;2328k = (rel - cache->base) + cache->missing;2329}2330rel->R = gclone(R);2331rel->m = m ? gclone(m) : NULL;2332rel->nz = nz;2333if (aut)2334{2335rel->relorig = (rel - cache->base) - orig;2336rel->relaut = aut;2337}2338else2339rel->relaut = 0;2340if (relp) *relp = rel;2341if (DEBUGLEVEL) dbg_newrel(cache);2342}2343return k;2344}23452346static int2347add_rel(RELCACHE_t *cache, FB_t *F, GEN R, long nz, GEN m, long in_rnd_rel)2348{2349REL_t *rel;2350long k, l, reln;2351const long lauts = lg(F->idealperm), KC = F->KC;23522353k = add_rel_i(cache, R, nz, m, 0, 0, &rel, in_rnd_rel);2354if (k > 0 && typ(m) != t_INT)2355{2356GEN Rl = cgetg(KC+1, t_VECSMALL);2357reln = rel - cache->base;2358for (l = 1; l < lauts; l++)2359{2360GEN perml = gel(F->idealperm, l);2361long i, nzl = perml[nz];23622363for (i = 1; i <= KC; i++) Rl[i] = 0;2364for (i = nz; i <= KC; i++)2365if (R[i])2366{2367long v = perml[i];23682369if (v < nzl) nzl = v;2370Rl[v] = R[i];2371}2372(void)add_rel_i(cache, Rl, nzl, NULL, reln, l, NULL, in_rnd_rel);2373}2374}2375return k;2376}23772378INLINE void2379step(GEN x, double *y, GEN inc, long k)2380{2381if (!y[k])2382x[k]++; /* leading coeff > 0 */2383else2384{2385long i = inc[k];2386x[k] += i;2387inc[k] = (i > 0)? -1-i: 1-i;2388}2389}23902391INLINE long2392Fincke_Pohst_ideal(RELCACHE_t *cache, FB_t *F, GEN nf, GEN M, GEN I,2393GEN NI, FACT *fact, long Nrelid, FP_t *fp, RNDREL_t *rr, long prec,2394long *Nsmall, long *Nfact)2395{2396pari_sp av;2397const long N = nf_get_degree(nf), R1 = nf_get_r1(nf);2398GEN G = nf_get_G(nf), G0 = nf_get_roundG(nf), r, u, gx, inc, ideal;2399double BOUND, B1, B2;2400long j, k, skipfirst, relid=0, dependent=0, try_elt=0, try_factor=0;24012402inc = const_vecsmall(N, 1);2403u = ZM_lll(ZM_mul(G0, I), 0.99, LLL_IM);2404ideal = ZM_mul(I,u); /* approximate T2-LLL reduction */2405r = gaussred_from_QR(RgM_mul(G, ideal), prec); /* Cholesky for T2 | ideal */2406if (!r) pari_err_BUG("small_norm (precision too low)");24072408for (k=1; k<=N; k++)2409{2410if (!gisdouble(gcoeff(r,k,k),&(fp->v[k]))) return 0;2411for (j=1; j<k; j++) if (!gisdouble(gcoeff(r,j,k),&(fp->q[j][k]))) return 0;2412if (DEBUGLEVEL>3) err_printf("v[%ld]=%.4g ",k,fp->v[k]);2413}2414B1 = fp->v[1]; /* T2(ideal[1]) */2415B2 = fp->v[2] + B1 * fp->q[1][2] * fp->q[1][2]; /* T2(ideal[2]) */2416if (ZV_isscalar(gel(ideal,1))) /* probable */2417{2418skipfirst = 1;2419BOUND = mindd(BMULT * B1, 2 * B2);2420}2421else2422{2423BOUND = mindd(BMULT * B1, 2 * B2);2424skipfirst = 0;2425}2426/* BOUND at most BMULT fp->x smallest known vector */2427if (DEBUGLEVEL>1)2428{2429if (DEBUGLEVEL>3) err_printf("\n");2430err_printf("BOUND = %.4g\n",BOUND);2431}2432BOUND *= 1 + 1e-6;2433k = N; fp->y[N] = fp->z[N] = 0; fp->x[N] = 0;2434for (av = avma;; set_avma(av), step(fp->x,fp->y,inc,k))2435{2436GEN R;2437long nz;2438do2439{ /* look for primitive element of small norm, cf minim00 */2440int fl = 0;2441double p;2442if (k > 1)2443{2444long l = k-1;2445fp->z[l] = 0;2446for (j=k; j<=N; j++) fp->z[l] += fp->q[l][j]*fp->x[j];2447p = (double)fp->x[k] + fp->z[k];2448fp->y[l] = fp->y[k] + p*p*fp->v[k];2449if (l <= skipfirst && !fp->y[1]) fl = 1;2450fp->x[l] = (long)floor(-fp->z[l] + 0.5);2451k = l;2452}2453for(;; step(fp->x,fp->y,inc,k))2454{2455if (++try_elt > maxtry_ELEMENT) return 0;2456if (!fl)2457{2458p = (double)fp->x[k] + fp->z[k];2459if (fp->y[k] + p*p*fp->v[k] <= BOUND) break;24602461step(fp->x,fp->y,inc,k);24622463p = (double)fp->x[k] + fp->z[k];2464if (fp->y[k] + p*p*fp->v[k] <= BOUND) break;2465}2466fl = 0; inc[k] = 1;2467if (++k > N) return 0;2468}2469} while (k > 1);24702471/* element complete */2472if (zv_content(fp->x) !=1) continue; /* not primitive */2473gx = ZM_zc_mul(ideal,fp->x);2474if (ZV_isscalar(gx)) continue;2475if (++try_factor > maxtry_FACT) return 0;24762477if (!Nrelid)2478{2479if (!factorgen(F,nf,I,NI,gx,fact)) continue;2480return 1;2481}2482else if (rr)2483{2484if (!factorgen(F,nf,I,NI,gx,fact)) continue;2485add_to_fact(rr->jid, 1, fact);2486}2487else2488{2489GEN Nx, xembed = RgM_RgC_mul(M, gx);2490long e;2491if (Nsmall) (*Nsmall)++;2492Nx = grndtoi(embed_norm(xembed, R1), &e);2493if (e >= 0) {2494if (DEBUGLEVEL > 1) err_printf("+");2495continue;2496}2497if (!can_factor(F, nf, NULL, gx, Nx, fact)) continue;2498}24992500/* smooth element */2501R = set_fact(F, fact, rr ? rr->ex : NULL, &nz);2502/* make sure we get maximal rank first, then allow all relations */2503if (add_rel(cache, F, R, nz, gx, rr ? 1 : 0) <= 0)2504{ /* probably Q-dependent from previous ones: forget it */2505if (DEBUGLEVEL>1) err_printf("*");2506if (++dependent > maxtry_DEP) break;2507continue;2508}2509dependent = 0;2510if (DEBUGLEVEL && Nfact) (*Nfact)++;2511if (cache->last >= cache->end) return 1; /* we have enough */2512if (++relid == Nrelid) break;2513}2514return 0;2515}25162517static void2518small_norm(RELCACHE_t *cache, FB_t *F, GEN nf, long Nrelid, GEN M,2519FACT *fact, GEN p0)2520{2521const long prec = nf_get_prec(nf);2522FP_t fp;2523pari_sp av;2524GEN L_jid = F->L_jid, Np0;2525long Nsmall, Nfact, n = lg(L_jid);2526pari_timer T;25272528if (DEBUGLEVEL)2529{2530timer_start(&T);2531err_printf("#### Look for %ld relations in %ld ideals (small_norm)\n",2532cache->end - cache->last, lg(L_jid)-1);2533if (p0) err_printf("Look in p0 = %Ps\n", vecslice(p0,1,4));2534}2535Nsmall = Nfact = 0;2536minim_alloc(lg(M), &fp.q, &fp.x, &fp.y, &fp.z, &fp.v);2537Np0 = p0? pr_norm(p0): NULL;2538for (av = avma; --n; set_avma(av))2539{2540long j = L_jid[n];2541GEN id = gel(F->LP, j), Nid;2542if (DEBUGLEVEL>1)2543err_printf("\n*** Ideal no %ld: %Ps\n", j, vecslice(id,1,4));2544if (p0)2545{ Nid = mulii(Np0, pr_norm(id)); id = idealmul(nf, p0, id); }2546else2547{ Nid = pr_norm(id); id = pr_hnf(nf, id);}2548if (Fincke_Pohst_ideal(cache, F, nf, M, id, Nid, fact, Nrelid, &fp,2549NULL, prec, &Nsmall, &Nfact)) break;2550}2551if (DEBUGLEVEL && Nsmall)2552{2553if (DEBUGLEVEL == 1)2554{ if (Nfact) err_printf("\n"); }2555else2556err_printf(" \nnb. fact./nb. small norm = %ld/%ld = %.3f\n",2557Nfact,Nsmall,((double)Nfact)/Nsmall);2558if (timer_get(&T)>1) timer_printf(&T,"small_norm");2559}2560}25612562static GEN2563get_random_ideal(FB_t *F, GEN nf, GEN ex)2564{2565long i, l = lg(ex);2566for (;;)2567{2568GEN I = NULL;2569for (i = 1; i < l; i++)2570if ((ex[i] = random_bits(RANDOM_BITS)))2571{2572GEN pr = gel(F->LP, F->subFB[i]), e = utoipos(ex[i]);2573I = I? idealmulpowprime(nf, I, pr, e): idealpow(nf, pr, e);2574}2575if (I && !ZM_isscalar(I,NULL)) return I; /* != (n)Z_K */2576}2577}25782579static void2580rnd_rel(RELCACHE_t *cache, FB_t *F, GEN nf, FACT *fact)2581{2582pari_timer T;2583GEN L_jid = F->L_jid, M = nf_get_M(nf), R, NR;2584long i, l = lg(L_jid), prec = nf_get_prec(nf);2585RNDREL_t rr;2586FP_t fp;2587pari_sp av;25882589if (DEBUGLEVEL) {2590timer_start(&T);2591err_printf("\n#### Look for %ld relations in %ld ideals (rnd_rel)\n",2592cache->end - cache->last, l-1);2593}2594rr.ex = cgetg(lg(F->subFB), t_VECSMALL);2595R = get_random_ideal(F, nf, rr.ex); /* random product from subFB */2596NR = ZM_det_triangular(R);2597minim_alloc(lg(M), &fp.q, &fp.x, &fp.y, &fp.z, &fp.v);2598for (av = avma, i = 1; i < l; i++, set_avma(av))2599{ /* try P[j] * base */2600long j = L_jid[i];2601GEN P = gel(F->LP, j), Nid = mulii(NR, pr_norm(P));2602if (DEBUGLEVEL>1) err_printf("\n*** Ideal %ld: %Ps\n", j, vecslice(P,1,4));2603rr.jid = j;2604if (Fincke_Pohst_ideal(cache, F, nf, M, idealHNF_mul(nf, R, P), Nid, fact,2605RND_REL_RELPID, &fp, &rr, prec, NULL, NULL)) break;2606}2607if (DEBUGLEVEL)2608{2609err_printf("\n");2610if (timer_get(&T) > 1) timer_printf(&T,"for remaining ideals");2611}2612}26132614static GEN2615automorphism_perms(GEN M, GEN auts, GEN cyclic, long r1, long r2, long N)2616{2617long L = lgcols(M), lauts = lg(auts), lcyc = lg(cyclic), i, j, l, m;2618GEN Mt, perms = cgetg(lauts, t_VEC);2619pari_sp av;26202621for (l = 1; l < lauts; l++) gel(perms, l) = cgetg(L, t_VECSMALL);2622av = avma;2623Mt = shallowtrans(gprec_w(M, LOWDEFAULTPREC));2624Mt = shallowconcat(Mt, conj_i(vecslice(Mt, r1+1, r1+r2)));2625for (l = 1; l < lcyc; l++)2626{2627GEN thiscyc = gel(cyclic, l), thisperm, perm, prev, Nt;2628long k = thiscyc[1];26292630Nt = RgM_mul(shallowtrans(gel(auts, k)), Mt);2631perm = gel(perms, k);2632for (i = 1; i < L; i++)2633{2634GEN v = gel(Nt, i), minD;2635minD = gnorml2(gsub(v, gel(Mt, 1)));2636perm[i] = 1;2637for (j = 2; j <= N; j++)2638{2639GEN D = gnorml2(gsub(v, gel(Mt, j)));2640if (gcmp(D, minD) < 0) { minD = D; perm[i] = j >= L ? r2-j : j; }2641}2642}2643for (prev = perm, m = 2; m < lg(thiscyc); m++, prev = thisperm)2644{2645thisperm = gel(perms, thiscyc[m]);2646for (i = 1; i < L; i++)2647{2648long pp = labs(prev[i]);2649thisperm[i] = prev[i] < 0 ? -perm[pp] : perm[pp];2650}2651}2652}2653set_avma(av); return perms;2654}26552656/* Determine the field automorphisms as matrices on the integral basis */2657static GEN2658automorphism_matrices(GEN nf, GEN *cycp)2659{2660pari_sp av = avma;2661GEN auts = galoisconj(nf, NULL), mats, cyclic, cyclicidx;2662long nauts = lg(auts)-1, i, j, k, l;26632664cyclic = cgetg(nauts+1, t_VEC);2665cyclicidx = zero_Flv(nauts);2666for (l = 1; l <= nauts; l++)2667{2668GEN aut = gel(auts, l);2669if (gequalX(aut)) { swap(gel(auts, l), gel(auts, nauts)); break; }2670}2671/* trivial automorphism is last */2672for (l = 1; l <= nauts; l++) gel(auts, l) = algtobasis(nf, gel(auts, l));2673/* Compute maximal cyclic subgroups */2674for (l = nauts; --l > 0; ) if (!cyclicidx[l])2675{2676GEN elt = gel(auts, l), aut = elt, cyc = cgetg(nauts+1, t_VECSMALL);2677cyc[1] = cyclicidx[l] = l; j = 1;2678do2679{2680elt = galoisapply(nf, elt, aut);2681for (k = 1; k <= nauts; k++) if (gequal(elt, gel(auts, k))) break;2682cyclicidx[k] = l; cyc[++j] = k;2683}2684while (k != nauts);2685setlg(cyc, j);2686gel(cyclic, l) = cyc;2687}2688for (i = j = 1; i < nauts; i++)2689if (cyclicidx[i] == i) cyclic[j++] = cyclic[i];2690setlg(cyclic, j);2691mats = cgetg(nauts, t_VEC);2692while (--j > 0)2693{2694GEN cyc = gel(cyclic, j);2695long id = cyc[1];2696GEN M, Mi, aut = gel(auts, id);26972698gel(mats, id) = Mi = M = nfgaloismatrix(nf, aut);2699for (i = 2; i < lg(cyc); i++) gel(mats, cyc[i]) = Mi = ZM_mul(Mi, M);2700}2701gerepileall(av, 2, &mats, &cyclic);2702if (cycp) *cycp = cyclic;2703return mats;2704}27052706/* vP a list of maximal ideals above the same p from idealprimedec: f(P/p) is2707* increasing; 1 <= j <= #vP; orbit a zc of length <= #vP; auts a vector of2708* automorphisms in ZM form.2709* Set orbit[i] = 1 for all vP[i], i >= j, in the orbit of pr = vP[j] wrt auts.2710* N.B.1 orbit need not be initialized to 0: useful to incrementally run2711* through successive orbits2712* N.B.2 i >= j, so primes with index < j will be missed; run incrementally2713* starting from j = 1 ! */2714static void2715pr_orbit_fill(GEN orbit, GEN auts, GEN vP, long j)2716{2717GEN pr = gel(vP,j), gen = pr_get_gen(pr);2718long i, l = lg(auts), J = lg(orbit), f = pr_get_f(pr);2719orbit[j] = 1;2720for (i = 1; i < l; i++)2721{2722GEN g = ZM_ZC_mul(gel(auts,i), gen);2723long k;2724for (k = j+1; k < J; k++)2725{2726GEN prk = gel(vP,k);2727if (pr_get_f(prk) > f) break; /* f(P[k]) increases with k */2728/* don't check that e matches: (almost) always 1 ! */2729if (!orbit[k] && ZC_prdvd(g, prk)) { orbit[k] = 1; break; }2730}2731}2732}2733/* remark: F->KCZ changes if be_honest() fails */2734static int2735be_honest(FB_t *F, GEN nf, GEN auts, FACT *fact)2736{2737long i, iz, nbtest;2738long lgsub = lg(F->subFB), KCZ0 = F->KCZ;2739long N = nf_get_degree(nf), prec = nf_get_prec(nf);2740GEN M = nf_get_M(nf);2741FP_t fp;2742pari_sp av;27432744if (DEBUGLEVEL) {2745err_printf("Be honest for %ld primes from %ld to %ld\n", F->KCZ2 - F->KCZ,2746F->FB[ F->KCZ+1 ], F->FB[ F->KCZ2 ]);2747}2748minim_alloc(N+1, &fp.q, &fp.x, &fp.y, &fp.z, &fp.v);2749if (lg(auts) == 1) auts = NULL;2750av = avma;2751for (iz=F->KCZ+1; iz<=F->KCZ2; iz++, set_avma(av))2752{2753long p = F->FB[iz];2754GEN pr_orbit, P = gel(F->LV,p);2755long j, J = lg(P); /* > 1 */2756/* the P|p, NP > C2 are assumed in subgroup generated by FB + last P2757* with NP <= C2 is unramified --> check all but last */2758if (pr_get_e(gel(P,J-1)) == 1) J--;2759if (J == 1) continue;2760if (DEBUGLEVEL>1) err_printf("%ld ", p);2761pr_orbit = auts? zero_zv(J-1): NULL;2762for (j = 1; j < J; j++)2763{2764GEN Nid, id, id0;2765if (pr_orbit)2766{2767if (pr_orbit[j]) continue;2768/* discard all primes in automorphism orbit simultaneously */2769pr_orbit_fill(pr_orbit, auts, P, j);2770}2771id = id0 = pr_hnf(nf,gel(P,j));2772Nid = pr_norm(gel(P,j));2773for (nbtest=0;;)2774{2775if (Fincke_Pohst_ideal(NULL, F, nf, M, id, Nid, fact, 0, &fp,2776NULL, prec, NULL, NULL)) break;2777if (++nbtest > maxtry_HONEST)2778{2779if (DEBUGLEVEL)2780pari_warn(warner,"be_honest() failure on prime %Ps\n", gel(P,j));2781return 0;2782}2783/* occurs at most once in the whole function */2784for (i = 1, id = id0; i < lgsub; i++)2785{2786long ex = random_bits(RANDOM_BITS);2787if (ex)2788{2789GEN pr = gel(F->LP, F->subFB[i]);2790id = idealmulpowprime(nf, id, pr, utoipos(ex));2791}2792}2793if (!equali1(gcoeff(id,N,N))) id = Q_primpart(id);2794if (expi(gcoeff(id,1,1)) > 100) id = idealred(nf, id);2795Nid = ZM_det_triangular(id);2796}2797}2798F->KCZ++; /* SUCCESS, "enlarge" factorbase */2799}2800F->KCZ = KCZ0; return gc_bool(av,1);2801}28022803/* all primes with N(P) <= BOUND factor on factorbase ? */2804void2805bnftestprimes(GEN bnf, GEN BOUND)2806{2807pari_sp av0 = avma, av;2808ulong count = 0;2809GEN auts, p, nf = bnf_get_nf(bnf), Vbase = bnf_get_vbase(bnf);2810GEN fb = gen_sort_shallow(Vbase, (void*)&cmp_prime_ideal, cmp_nodata);2811ulong pmax = pr_get_smallp(gel(fb, lg(fb)-1)); /*largest p in factorbase*/2812forprime_t S;2813FACT *fact;2814FB_t F;28152816(void)recover_partFB(&F, Vbase, nf_get_degree(nf));2817fact = (FACT*)stack_malloc((F.KC+1)*sizeof(FACT));2818forprime_init(&S, gen_2, BOUND);2819auts = automorphism_matrices(nf, NULL);2820if (lg(auts) == 1) auts = NULL;2821av = avma;2822while (( p = forprime_next(&S) ))2823{2824GEN pr_orbit, vP;2825long j, J;28262827if (DEBUGLEVEL == 1 && ++count > 1000)2828{2829err_printf("passing p = %Ps / %Ps\n", p, BOUND);2830count = 0;2831}2832set_avma(av);2833vP = idealprimedec_limit_norm(bnf, p, BOUND);2834J = lg(vP);2835/* if last is unramified, all P|p in subgroup generated by FB: skip last */2836if (J > 1 && pr_get_e(gel(vP,J-1)) == 1) J--;2837if (J == 1) continue;2838if (DEBUGLEVEL>1) err_printf("*** p = %Ps\n",p);2839pr_orbit = auts? zero_zv(J-1): NULL;2840for (j = 1; j < J; j++)2841{2842GEN P = gel(vP,j);2843long k = 0;2844if (pr_orbit)2845{2846if (pr_orbit[j]) continue;2847/* discard all primes in automorphism orbit simultaneously */2848pr_orbit_fill(pr_orbit, auts, vP, j);2849}2850if (abscmpiu(p, pmax) > 0 || !(k = tablesearch(fb, P, &cmp_prime_ideal)))2851(void)SPLIT(&F, nf, pr_hnf(nf,P), Vbase, fact);2852if (DEBUGLEVEL>1)2853{2854err_printf(" Testing P = %Ps\n",P);2855if (k) err_printf(" #%ld in factor base\n",k);2856else err_printf(" is %Ps\n", isprincipal(bnf,P));2857}2858}2859}2860set_avma(av0);2861}28622863/* A t_MAT of complex floats, in fact reals. Extract a submatrix B2864* whose columns are definitely nonzero, i.e. gexpo(A[j]) >= -22865*2866* If possible precision problem (t_REAL 0 with large exponent), set2867* *precpb to 1 */2868static GEN2869clean_cols(GEN A, int *precpb)2870{2871long l = lg(A), h, i, j, k;2872GEN B;2873*precpb = 0;2874if (l == 1) return A;2875h = lgcols(A);;2876B = cgetg(l, t_MAT);2877for (i = k = 1; i < l; i++)2878{2879GEN Ai = gel(A,i);2880int non0 = 0;2881for (j = 1; j < h; j++)2882{2883GEN c = gel(Ai,j);2884if (gexpo(c) >= -2)2885{2886if (gequal0(c)) *precpb = 1; else non0 = 1;2887}2888}2889if (non0) gel(B, k++) = Ai;2890}2891setlg(B, k); return B;2892}28932894static long2895compute_multiple_of_R_pivot(GEN X, GEN x0/*unused*/, long ix, GEN c)2896{2897GEN x = gel(X,ix);2898long i, k = 0, ex = - (long)HIGHEXPOBIT, lx = lg(x);2899(void)x0;2900for (i=1; i<lx; i++)2901if (!c[i] && !gequal0(gel(x,i)))2902{2903long e = gexpo(gel(x,i));2904if (e > ex) { ex = e; k = i; }2905}2906return (k && ex > -32)? k: lx;2907}29082909/* Ar = (log |sigma_i(u_j)|) for units (u_j) found so far,2910* RU = R1+R2 = unit rank, N = field degree2911* need = unit rank defect2912* L = NULL (prec problem) or B^(-1) * A with approximate rational entries2913* (as t_REAL), B a submatrix of A, with (probably) maximal rank RU */2914static GEN2915compute_multiple_of_R(GEN Ar, long RU, long N, long *pneed, long *bit, GEN *ptL)2916{2917GEN T, d, mdet, Im_mdet, kR, L;2918long i, j, r, R1 = 2*RU - N;2919int precpb;2920pari_sp av = avma;29212922if (RU == 1) { *ptL = zeromat(0, lg(Ar)-1); return gen_1; }29232924if (DEBUGLEVEL) err_printf("\n#### Computing regulator multiple\n");2925mdet = clean_cols(Ar, &precpb);2926/* will cause precision to increase on later failure, but we may succeed! */2927*ptL = precpb? NULL: gen_1;2928T = cgetg(RU+1,t_COL);2929for (i=1; i<=R1; i++) gel(T,i) = gen_1;2930for ( ; i<=RU; i++) gel(T,i) = gen_2;2931mdet = shallowconcat(T, mdet); /* det(Span(mdet)) = N * R */29322933/* could be using indexrank(), but need custom "get_pivot" function */2934d = RgM_pivots(mdet, NULL, &r, &compute_multiple_of_R_pivot);2935/* # of independent columns == unit rank ? */2936if (lg(mdet)-1 - r != RU)2937{2938if (DEBUGLEVEL)2939err_printf("Unit group rank = %ld < %ld\n",lg(mdet)-1 - r, RU);2940*pneed = RU - (lg(mdet)-1-r); return gc_NULL(av);2941}29422943Im_mdet = cgetg(RU+1, t_MAT); /* extract independent columns */2944/* N.B: d[1] = 1, corresponding to T above */2945gel(Im_mdet, 1) = T;2946for (i = j = 2; i <= RU; j++)2947if (d[j]) gel(Im_mdet, i++) = gel(mdet,j);29482949/* integral multiple of R: the cols we picked form a Q-basis, they have an2950* index in the full lattice. First column is T */2951kR = divru(det2(Im_mdet), N);2952/* R > 0.2 uniformly */2953if (!signe(kR) || expo(kR) < -3)2954{2955if (DEBUGLEVEL) err_printf("Regulator is zero.\n");2956*pneed = 0; return gc_NULL(av);2957}2958d = det2(rowslice(vecslice(Im_mdet, 2, RU), 2, RU));2959setabssign(d); setabssign(kR);2960if (gexpo(gsub(d,kR)) - gexpo(d) > -20) { *ptL = NULL; return gc_NULL(av); }2961L = RgM_inv(Im_mdet);2962/* estimate # of correct bits in result */2963if (!L || (*bit = - gexpo(RgM_Rg_sub(RgM_mul(L,Im_mdet), gen_1))) < 16)2964{ *ptL = NULL; return gc_NULL(av); }29652966L = RgM_mul(rowslice(L,2,RU), Ar); /* approximate rational entries */2967gerepileall(av,2, &L, &kR);2968*ptL = L; return kR;2969}29702971/* leave small integer n as is, convert huge n to t_REAL (for readability) */2972static GEN2973i2print(GEN n)2974{ return lgefint(n) <= DEFAULTPREC? n: itor(n,LOWDEFAULTPREC); }29752976static long2977bad_check(GEN c)2978{2979long ec = gexpo(c);2980if (DEBUGLEVEL) err_printf("\n ***** check = %.28Pg\n",c);2981/* safe check for c < 0.75 : avoid underflow in gtodouble() */2982if (ec < -1 || (ec == -1 && gtodouble(c) < 0.75)) return fupb_PRECI;2983/* safe check for c > 1.3 : avoid overflow */2984if (ec > 0 || (ec == 0 && gtodouble(c) > 1.3)) return fupb_RELAT;2985return fupb_NONE;2986}2987/* Input:2988* lambda = approximate rational entries: coords of units found so far on a2989* sublattice of maximal rank (sublambda)2990* *ptkR = regulator of sublambda = multiple of regulator of lambda2991* Compute R = true regulator of lambda.2992*2993* If c := Rz ~ 1, by Dirichlet's formula, then lambda is the full group of2994* units AND the full set of relations for the class group has been computed.2995*2996* In fact z is a very rough approximation and we only expect 0.75 < Rz < 1.32997* bit is an estimate for the actual accuracy of lambda2998*2999* Output: *ptkR = R, *ptU = basis of fundamental units (in terms lambda) */3000static long3001compute_R(GEN lambda, GEN z, GEN *ptL, GEN *ptkR)3002{3003pari_sp av = avma;3004long bit, r, reason, RU = lg(lambda) == 1? 1: lgcols(lambda);3005GEN L, H, D, den, R, c;30063007*ptL = NULL;3008if (DEBUGLEVEL) err_printf("\n#### Computing check\n");3009if (RU == 1) { *ptkR = gen_1; *ptL = lambda; return bad_check(z); }3010D = gmul2n(mpmul(*ptkR,z), 1); /* bound for denom(lambda) */3011if (expo(D) < 0 && rtodbl(D) < 0.95) return fupb_PRECI;3012L = bestappr(lambda,D);3013if (lg(L) == 1)3014{3015if (DEBUGLEVEL) err_printf("truncation error in bestappr\n");3016return fupb_PRECI;3017}3018den = Q_denom(L);3019if (mpcmp(den,D) > 0)3020{3021if (DEBUGLEVEL) err_printf("D = %Ps\nden = %Ps\n",D, i2print(den));3022return fupb_PRECI;3023}3024bit = -gexpo(gsub(L, lambda)); /* input accuracy */3025L = Q_muli_to_int(L, den);3026if (gexpo(L) + expi(den) > bit - 32)3027{3028if (DEBUGLEVEL) err_printf("dubious bestappr; den = %Ps\n", i2print(den));3029return fupb_PRECI;3030}3031H = ZM_hnf(L); r = lg(H)-1;3032if (!r || r != nbrows(H))3033R = gen_0; /* wrong rank */3034else3035R = gmul(*ptkR, gdiv(ZM_det_triangular(H), powiu(den, r)));3036/* R = tentative regulator; regulator > 0.2 uniformly */3037if (gexpo(R) < -3) {3038if (DEBUGLEVEL) err_printf("\n#### Tentative regulator: %.28Pg\n", R);3039return gc_long(av, fupb_PRECI);3040}3041c = gmul(R,z); /* should be n (= 1 if we are done) */3042if (DEBUGLEVEL) err_printf("\n#### Tentative regulator: %.28Pg\n", R);3043if ((reason = bad_check(c))) return gc_long(av, reason);3044*ptkR = R; *ptL = L; return fupb_NONE;3045}3046static GEN3047get_clg2(GEN cyc, GEN Ga, GEN C, GEN Ur, GEN Ge, GEN M1, GEN M2)3048{3049GEN GD = gsub(act_arch(M1, C), diagact_arch(cyc, Ga));3050GEN ga = gsub(act_arch(M2, C), act_arch(Ur, Ga));3051return mkvecn(6, Ur, ga, GD, Ge, M1, M2);3052}3053/* compute class group (clg1) + data for isprincipal (clg2) */3054static GEN3055class_group_gen(GEN nf,GEN W,GEN C,GEN Vbase,long prec, GEN *pclg2)3056{3057GEN M1, M2, z, G, Ga, Ge, cyc, X, Y, D, U, V, Ur, Ui, Uir;3058long j, l;30593060D = ZM_snfall(W,&U,&V); /* UWV=D, D diagonal, G = g Ui (G=new gens, g=old) */3061Ui = ZM_inv(U, NULL);3062l = lg(D); cyc = cgetg(l, t_VEC); /* elementary divisors */3063for (j = 1; j < l; j++)3064{3065gel(cyc,j) = gcoeff(D,j,j); /* strip useless components */3066if (is_pm1(gel(cyc,j))) break;3067}3068l = j;3069Ur = ZM_hnfdivrem(U, D, &Y);3070Uir = ZM_hnfdivrem(Ui,W, &X);3071/* {x} = logarithmic embedding of x (arch. component)3072* NB: [J,z] = idealred(I) --> I = y J, with {y} = - z3073* G = g Uir - {Ga}, Uir = Ui + WX3074* g = G Ur - {ga}, Ur = U + DY */3075G = cgetg(l,t_VEC);3076Ga= cgetg(l,t_MAT);3077Ge= cgetg(l,t_COL);3078z = init_famat(NULL);3079for (j = 1; j < l; j++)3080{3081GEN I = genback(z, nf, Vbase, gel(Uir,j));3082gel(G,j) = gel(I,1); /* generator, order cyc[j] */3083gel(Ge,j)= gel(I,2);3084gel(Ga,j)= nf_cxlog(nf, gel(I,2), prec);3085if (!gel(Ga,j)) pari_err_PREC("class_group_gen");3086}3087/* {ga} = {GD}Y + G U - g = {GD}Y - {Ga} U + gW X U3088= gW (X Ur + V Y) - {Ga}Ur */3089M2 = ZM_add(ZM_mul(X,Ur), ZM_mul(V,Y));3090setlg(cyc,l); setlg(V,l); setlg(D,l);3091/* G D =: {GD} = g (Ui + W X) D - {Ga}D = g W (V + X D) - {Ga}D3092* NB: Ui D = W V. gW is given by (first l-1 cols of) C */3093M1 = ZM_add(V, ZM_mul(X,D));3094*pclg2 = get_clg2(cyc, Ga, C, Ur, Ge, M1, M2);3095return mkvec3(ZV_prod(cyc), cyc, G);3096}30973098/* compute principal ideals corresponding to (gen[i]^cyc[i]) */3099static GEN3100makecycgen(GEN bnf)3101{3102GEN cyc, gen, h, nf, y, GD;3103long e,i,l;31043105if (DEBUGLEVEL) pari_warn(warner,"completing bnf (building cycgen)");3106nf = bnf_get_nf(bnf);3107cyc = bnf_get_cyc(bnf);3108gen = bnf_get_gen(bnf);3109GD = bnf_get_GD(bnf);3110h = cgetg_copy(gen, &l);3111for (i = 1; i < l; i++)3112{3113GEN gi = gel(gen,i), ci = gel(cyc,i);3114if (abscmpiu(ci, 5) < 0)3115{3116GEN N = ZM_det_triangular(gi);3117y = isprincipalarch(bnf,gel(GD,i), N, ci, gen_1, &e);3118if (y && fact_ok(nf,y,NULL,mkvec(gi),mkvec(ci)))3119{3120gel(h,i) = to_famat_shallow(y,gen_1);3121continue;3122}3123}3124y = isprincipalfact(bnf, NULL, mkvec(gi), mkvec(ci), nf_GENMAT|nf_FORCE);3125gel(h,i) = gel(y,2);3126}3127return h;3128}31293130static GEN3131get_y(GEN bnf, GEN W, GEN B, GEN C, GEN pFB, long j)3132{3133GEN y, nf = bnf_get_nf(bnf);3134long e, lW = lg(W)-1;3135GEN ex = (j<=lW)? gel(W,j): gel(B,j-lW);3136GEN P = (j<=lW)? NULL: gel(pFB,j);3137if (C)3138{ /* archimedean embeddings known: cheap trial */3139GEN Nx = get_norm_fact_primes(pFB, ex, P);3140y = isprincipalarch(bnf,gel(C,j), Nx,gen_1, gen_1, &e);3141if (y && fact_ok(nf,y,P,pFB,ex)) return y;3142}3143y = isprincipalfact_or_fail(bnf, P, pFB, ex);3144return typ(y) == t_INT? y: gel(y,2);3145}3146/* compute principal ideals corresponding to bnf relations */3147static GEN3148makematal(GEN bnf)3149{3150GEN W = bnf_get_W(bnf), B = bnf_get_B(bnf), C = bnf_get_C(bnf);3151GEN pFB, ma, retry;3152long lma, j, prec = 0;31533154if (DEBUGLEVEL) pari_warn(warner,"completing bnf (building matal)");3155lma=lg(W)+lg(B)-1;3156pFB = bnf_get_vbase(bnf);3157ma = cgetg(lma,t_VEC);3158retry = vecsmalltrunc_init(lma);3159for (j=lma-1; j>0; j--)3160{3161pari_sp av = avma;3162GEN y = get_y(bnf, W, B, C, pFB, j);3163if (typ(y) == t_INT)3164{3165long E = itos(y);3166if (DEBUGLEVEL>1) err_printf("\n%ld done later at prec %ld\n",j,E);3167set_avma(av);3168vecsmalltrunc_append(retry, j);3169if (E > prec) prec = E;3170}3171else3172{3173if (DEBUGLEVEL>1) err_printf("%ld ",j);3174gel(ma,j) = gerepileupto(av,y);3175}3176}3177if (prec)3178{3179long k, l = lg(retry);3180GEN y, nf = bnf_get_nf(bnf);3181if (DEBUGLEVEL) pari_warn(warnprec,"makematal",prec);3182nf = nfnewprec_shallow(nf,prec);3183bnf = Buchall(nf, nf_FORCE, prec);3184if (DEBUGLEVEL) err_printf("makematal, adding missing entries:");3185for (k=1; k<l; k++)3186{3187pari_sp av = avma;3188long j = retry[k];3189y = get_y(bnf,W,B,NULL, pFB, j);3190if (typ(y) == t_INT) pari_err_PREC("makematal");3191if (DEBUGLEVEL>1) err_printf("%ld ",j);3192gel(ma,j) = gerepileupto(av,y);3193}3194}3195if (DEBUGLEVEL>1) err_printf("\n");3196return ma;3197}31983199enum { MATAL = 1, CYCGEN, UNITS };3200GEN3201bnf_build_cycgen(GEN bnf)3202{ return obj_checkbuild(bnf, CYCGEN, &makecycgen); }3203GEN3204bnf_build_matalpha(GEN bnf)3205{ return obj_checkbuild(bnf, MATAL, &makematal); }3206GEN3207bnf_build_units(GEN bnf)3208{ return obj_checkbuild(bnf, UNITS, &makeunits); }32093210/* return fu in compact form if available; in terms of a fixed basis3211* of S-units */3212GEN3213bnf_compactfu_mat(GEN bnf)3214{3215GEN X, U, SUnits = bnf_get_sunits(bnf);3216if (!SUnits) return NULL;3217X = gel(SUnits,1);3218U = gel(SUnits,2); ZM_remove_unused(&U, &X);3219return mkvec2(X, U);3220}3221/* return fu in compact form if available; individually as famat */3222GEN3223bnf_compactfu(GEN bnf)3224{3225GEN fu, X, U, SUnits = bnf_get_sunits(bnf);3226long i, l;3227if (!SUnits) return NULL;3228X = gel(SUnits,1);3229U = gel(SUnits,2); l = lg(U); fu = cgetg(l, t_VEC);3230for (i = 1; i < l; i++)3231gel(fu,i) = famat_remove_trivial(mkmat2(X, gel(U,i)));3232return fu;3233}3234/* return expanded fu if available */3235GEN3236bnf_has_fu(GEN bnf)3237{3238GEN fu = obj_check(bnf, UNITS);3239if (fu) return vecsplice(fu, 1);3240fu = bnf_get_fu_nocheck(bnf);3241return (typ(fu) == t_MAT)? NULL: fu;3242}3243/* return expanded fu if available; build if cheap */3244GEN3245bnf_build_cheapfu(GEN bnf)3246{3247GEN fu, SUnits;3248if ((fu = bnf_has_fu(bnf))) return fu;3249if ((SUnits = bnf_get_sunits(bnf)))3250{3251pari_sp av = avma;3252long e = gexpo(real_i(bnf_get_logfu(bnf)));3253set_avma(av); if (e < 13) return vecsplice(bnf_build_units(bnf), 1);3254}3255return NULL;3256}32573258static GEN3259get_regulator(GEN mun)3260{3261pari_sp av = avma;3262GEN R;32633264if (lg(mun) == 1) return gen_1;3265R = det( rowslice(real_i(mun), 1, lgcols(mun)-2) );3266setabssign(R); return gerepileuptoleaf(av, R);3267}32683269/* return corrected archimedian components for elts of x (vector)3270* (= log(sigma_i(x)) - log(|Nx|) / [K:Q]) */3271static GEN3272get_archclean(GEN nf, GEN x, long prec, int units)3273{3274long k, N, l = lg(x);3275GEN M = cgetg(l, t_MAT);32763277if (l == 1) return M;3278N = nf_get_degree(nf);3279for (k = 1; k < l; k++)3280{3281pari_sp av = avma;3282GEN c = nf_cxlog(nf, gel(x,k), prec);3283if (!c || (!units && !(c = cleanarch(c, N, prec)))) return NULL;3284gel(M,k) = gerepilecopy(av, c);3285}3286return M;3287}3288static void3289Sunits_archclean(GEN nf, GEN Sunits, GEN *pmun, GEN *pC, long prec)3290{3291GEN M, X = gel(Sunits,1), U = gel(Sunits,2), G = gel(Sunits,3);3292long k, N = nf_get_degree(nf), l = lg(X);32933294M = cgetg(l, t_MAT);3295for (k = 1; k < l; k++)3296if (!(gel(M,k) = nf_cxlog(nf, gel(X,k), prec))) return;3297*pmun = cleanarch(RgM_ZM_mul(M, U), N, prec);3298if (*pmun) *pC = cleanarch(RgM_ZM_mul(M, G), N, prec);3299}33003301GEN3302bnfnewprec_shallow(GEN bnf, long prec)3303{3304GEN nf0 = bnf_get_nf(bnf), nf, v, fu, matal, y, mun, C;3305GEN Sunits = bnf_get_sunits(bnf), Ur, Ga, Ge, M1, M2;3306long r1, r2, prec0 = prec;33073308nf_get_sign(nf0, &r1, &r2);3309if (Sunits)3310{3311fu = matal = NULL;3312prec += nbits2extraprec(gexpo(Sunits));3313}3314else3315{3316fu = bnf_build_units(bnf);3317fu = vecslice(fu, 2, lg(fu)-1);3318if (r1 + r2 > 1) {3319long e = gexpo(bnf_get_logfu(bnf)) + 1 - TWOPOTBITS_IN_LONG;3320if (e >= 0) prec += nbits2extraprec(e);3321}3322matal = bnf_build_matalpha(bnf);3323}33243325if (DEBUGLEVEL && prec0 != prec) pari_warn(warnprec,"bnfnewprec",prec);3326for(C = NULL;;)3327{3328pari_sp av = avma;3329nf = nfnewprec_shallow(nf0,prec);3330if (Sunits)3331Sunits_archclean(nf, Sunits, &mun, &C, prec);3332else3333{3334mun = get_archclean(nf, fu, prec, 1);3335if (mun) C = get_archclean(nf, matal, prec, 0);3336}3337if (C) break;3338set_avma(av); prec = precdbl(prec);3339if (DEBUGLEVEL) pari_warn(warnprec,"bnfnewprec(extra)",prec);3340}3341y = leafcopy(bnf);3342gel(y,3) = mun;3343gel(y,4) = C;3344gel(y,7) = nf;3345gel(y,8) = v = leafcopy(gel(bnf,8));3346gel(v,2) = get_regulator(mun);3347v = gel(bnf,9);3348if (lg(v) < 7) pari_err_TYPE("bnfnewprec [obsolete bnf format]", bnf);3349Ur = gel(v,1);3350Ge = gel(v,4);3351Ga = nfV_cxlog(nf, Ge, prec);3352M1 = gel(v,5);3353M2 = gel(v,6);3354gel(y,9) = get_clg2(bnf_get_cyc(bnf), Ga, C, Ur, Ge, M1, M2);3355return y;3356}3357GEN3358bnfnewprec(GEN bnf, long prec)3359{3360pari_sp av = avma;3361return gerepilecopy(av, bnfnewprec_shallow(checkbnf(bnf), prec));3362}33633364GEN3365bnrnewprec_shallow(GEN bnr, long prec)3366{3367GEN y = cgetg(7,t_VEC);3368long i;3369gel(y,1) = bnfnewprec_shallow(bnr_get_bnf(bnr), prec);3370for (i=2; i<7; i++) gel(y,i) = gel(bnr,i);3371return y;3372}3373GEN3374bnrnewprec(GEN bnr, long prec)3375{3376GEN y = cgetg(7,t_VEC);3377long i;3378checkbnr(bnr);3379gel(y,1) = bnfnewprec(bnr_get_bnf(bnr), prec);3380for (i=2; i<7; i++) gel(y,i) = gcopy(gel(bnr,i));3381return y;3382}33833384static GEN3385buchall_end(GEN nf,GEN res, GEN clg2, GEN W, GEN B, GEN A, GEN C,GEN Vbase)3386{3387GEN z = obj_init(9, 3);3388gel(z,1) = W;3389gel(z,2) = B;3390gel(z,3) = A;3391gel(z,4) = C;3392gel(z,5) = Vbase;3393gel(z,6) = gen_0;3394gel(z,7) = nf;3395gel(z,8) = res;3396gel(z,9) = clg2;3397return z;3398}33993400GEN3401bnfinit0(GEN P, long flag, GEN data, long prec)3402{3403double c1 = 0., c2 = 0.;3404long fl, relpid = BNF_RELPID;34053406if (data)3407{3408long lx = lg(data);3409if (typ(data) != t_VEC || lx > 5) pari_err_TYPE("bnfinit",data);3410switch(lx)3411{3412case 4: relpid = itos(gel(data,3));3413case 3: c2 = gtodouble(gel(data,2));3414case 2: c1 = gtodouble(gel(data,1));3415}3416}3417switch(flag)3418{3419case 2:3420case 0: fl = 0; break;3421case 1: fl = nf_FORCE; break;3422default: pari_err_FLAG("bnfinit");3423return NULL; /* LCOV_EXCL_LINE */3424}3425return Buchall_param(P, c1, c2, relpid, fl, prec);3426}3427GEN3428Buchall(GEN P, long flag, long prec)3429{ return Buchall_param(P, 0., 0., BNF_RELPID, flag & nf_FORCE, prec); }34303431static GEN3432Buchall_deg1(GEN nf)3433{3434GEN v = cgetg(1,t_VEC), m = cgetg(1,t_MAT);3435GEN res, W, A, B, C, Vbase = cgetg(1,t_COL);3436GEN fu = v, R = gen_1, zu = mkvec2(gen_2, gen_m1);3437GEN clg1 = mkvec3(gen_1,v,v), clg2 = mkvecn(6, m,m,m,v,m,m);34383439W = A = B = C = m; res = mkvec5(clg1, R, gen_1, zu, fu);3440return buchall_end(nf,res,clg2,W,B,A,C,Vbase);3441}34423443/* return (small set of) indices of columns generating the same lattice as x.3444* Assume HNF(x) is inexpensive (few rows, many columns).3445* Dichotomy approach since interesting columns may be at the very end */3446GEN3447extract_full_lattice(GEN x)3448{3449long dj, j, k, l = lg(x);3450GEN h, h2, H, v;34513452if (l < 200) return NULL; /* not worth it */34533454v = vecsmalltrunc_init(l);3455H = ZM_hnf(x);3456h = cgetg(1, t_MAT);3457dj = 1;3458for (j = 1; j < l; )3459{3460pari_sp av = avma;3461long lv = lg(v);34623463for (k = 0; k < dj; k++) v[lv+k] = j+k;3464setlg(v, lv + dj);3465h2 = ZM_hnf(vecpermute(x, v));3466if (ZM_equal(h, h2))3467{ /* these dj columns can be eliminated */3468set_avma(av); setlg(v, lv);3469j += dj;3470if (j >= l) break;3471dj <<= 1;3472if (j + dj >= l) { dj = (l - j) >> 1; if (!dj) dj = 1; }3473}3474else if (dj > 1)3475{ /* at least one interesting column, try with first half of this set */3476set_avma(av); setlg(v, lv);3477dj >>= 1; /* > 0 */3478}3479else3480{ /* this column should be kept */3481if (ZM_equal(h2, H)) break;3482h = h2; j++;3483}3484}3485return v;3486}34873488static void3489init_rel(RELCACHE_t *cache, FB_t *F, long add_need)3490{3491const long n = F->KC + add_need; /* expected # of needed relations */3492long i, j, k, p;3493GEN c, P;3494GEN R;34953496if (DEBUGLEVEL) err_printf("KCZ = %ld, KC = %ld, n = %ld\n", F->KCZ,F->KC,n);3497reallocate(cache, 10*n + 50); /* make room for lots of relations */3498cache->chk = cache->base;3499cache->end = cache->base + n;3500cache->relsup = add_need;3501cache->last = cache->base;3502cache->missing = lg(cache->basis) - 1;3503for (i = 1; i <= F->KCZ; i++)3504{ /* trivial relations (p) = prod P^e */3505p = F->FB[i]; P = gel(F->LV,p);3506if (!isclone(P)) continue;35073508/* all prime divisors in FB */3509c = zero_Flv(F->KC); k = F->iLP[p];3510R = c; c += k;3511for (j = lg(P)-1; j; j--) c[j] = pr_get_e(gel(P,j));3512add_rel(cache, F, R, k+1, pr_get_p(gel(P,1)), 0);3513}3514}35153516/* Let z = \zeta_n in nf. List of not-obviously-dependent generators for3517* cyclotomic units modulo torsion in Q(z) [independent when n a prime power]:3518* - z^a - 1, n/(a,n) not a prime power, a \nmid n unless a=1, 1 <= a < n/23519* - (Z^a - 1)/(Z - 1), p^k || n, Z = z^{n/p^k}, (p,a) = 1, 1 < a <= (p^k-1)/23520*/3521GEN3522nfcyclotomicunits(GEN nf, GEN zu)3523{3524long n = itos(gel(zu, 1)), n2, lP, i, a;3525GEN z, fa, P, E, L, mz, powz;3526if (n <= 6) return cgetg(1, t_VEC);35273528z = algtobasis(nf,gel(zu, 2));3529if ((n & 3) == 2) { n = n >> 1; z = ZC_neg(z); } /* ensure n != 2 (mod 4) */3530n2 = n/2;3531mz = zk_multable(nf, z); /* multiplication by z */3532powz = cgetg(n2, t_VEC); gel(powz,1) = z;3533for (i = 2; i < n2; i++) gel(powz,i) = ZM_ZC_mul(mz, gel(powz,i-1));3534/* powz[i] = z^i */35353536L = vectrunc_init(n);3537fa = factoru(n);3538P = gel(fa,1); lP = lg(P);3539E = gel(fa,2);3540for (i = 1; i < lP; i++)3541{ /* second kind */3542long p = P[i], k = E[i], pk = upowuu(p,k), pk2 = (pk-1) / 2;3543GEN u = gen_1;3544for (a = 2; a <= pk2; a++)3545{3546u = nfadd(nf, u, gel(powz, (n/pk) * (a-1))); /* = (Z^a-1)/(Z-1) */3547if (a % p) vectrunc_append(L, u);3548}3549}3550if (lP > 2) for (a = 1; a < n2; a++)3551{ /* first kind, when n not a prime power */3552ulong p;3553if (a > 1 && (n % a == 0 || uisprimepower(n/ugcd(a,n), &p))) continue;3554vectrunc_append(L, nfadd(nf, gel(powz, a), gen_m1));3555}3556return L;3557}3558static void3559add_cyclotomic_units(GEN nf, GEN zu, RELCACHE_t *cache, FB_t *F)3560{3561pari_sp av = avma;3562GEN L = nfcyclotomicunits(nf, zu);3563long i, l = lg(L);3564if (l > 1)3565{3566GEN R = zero_Flv(F->KC);3567for(i = 1; i < l; i++) add_rel(cache, F, R, F->KC+1, gel(L,i), 0);3568}3569set_avma(av);3570}35713572static GEN3573trim_list(FB_t *F)3574{3575pari_sp av = avma;3576GEN v, L_jid = F->L_jid, minidx = F->minidx, present = zero_Flv(F->KC);3577long i, j, imax = minss(lg(L_jid), F->KC + 1);35783579v = cgetg(imax, t_VECSMALL);3580for (i = j = 1; i < imax; i++)3581{3582long k = minidx[ L_jid[i] ];3583if (!present[k]) { v[j++] = L_jid[i]; present[k] = 1; }3584}3585setlg(v, j); return gerepileuptoleaf(av, v);3586}35873588static void3589try_elt(RELCACHE_t *cache, FB_t *F, GEN nf, GEN x, FACT *fact)3590{3591pari_sp av = avma;3592GEN R, Nx;3593long nz, tx = typ(x);35943595if (tx == t_INT || tx == t_FRAC) return;3596if (tx != t_COL) x = algtobasis(nf, x);3597if (RgV_isscalar(x)) return;3598x = Q_primpart(x);3599Nx = nfnorm(nf, x);3600if (!can_factor(F, nf, NULL, x, Nx, fact)) return;36013602/* smooth element */3603R = set_fact(F, fact, NULL, &nz);3604/* make sure we get maximal rank first, then allow all relations */3605(void) add_rel(cache, F, R, nz, x, 0);3606set_avma(av);3607}36083609static void3610matenlarge(GEN C, long h)3611{3612GEN _0 = zerocol(h);3613long i;3614for (i = lg(C); --i; ) gel(C,i) = shallowconcat(gel(C,i), _0);3615}36163617/* E = floating point embeddings */3618static GEN3619matbotidembs(RELCACHE_t *cache, GEN E)3620{3621long w = cache->last - cache->chk, h = cache->last - cache->base;3622long j, d = h - w, hE = nbrows(E);3623GEN y = cgetg(w+1,t_MAT), _0 = zerocol(h);3624for (j = 1; j <= w; j++)3625{3626GEN c = shallowconcat(gel(E,j), _0);3627if (d + j >= 1) gel(c, d + j + hE) = gen_1;3628gel(y,j) = c;3629}3630return y;3631}3632static GEN3633matbotid(RELCACHE_t *cache)3634{3635long w = cache->last - cache->chk, h = cache->last - cache->base;3636long j, d = h - w;3637GEN y = cgetg(w+1,t_MAT);3638for (j = 1; j <= w; j++)3639{3640GEN c = zerocol(h);3641if (d + j >= 1) gel(c, d + j) = gen_1;3642gel(y,j) = c;3643}3644return y;3645}36463647static long3648myprecdbl(long prec, GEN C)3649{3650long p = prec2nbits(prec) < 1280? precdbl(prec): (long)(prec * 1.5);3651if (C) p = maxss(p, minss(3*p, prec + nbits2extraprec(gexpo(C))));3652return p;3653}36543655static GEN3656_nfnewprec(GEN nf, long prec, long *isclone)3657{3658GEN NF = gclone(nfnewprec_shallow(nf, prec));3659if (*isclone) gunclone(nf);3660*isclone = 1; return NF;3661}36623663/* Nrelid = nb relations per ideal, possibly 0. If flag is set, keep data in3664* algebraic form. */3665GEN3666Buchall_param(GEN P, double cbach, double cbach2, long Nrelid, long flag, long prec)3667{3668pari_timer T;3669pari_sp av0 = avma, av, av2;3670long PREC, N, R1, R2, RU, low, high, LIMC0, LIMC, LIMC2, LIMCMAX, zc, i;3671long LIMres, bit = 0, flag_nfinit = 0;3672long nreldep, sfb_trials, need, old_need, precdouble = 0, TRIES = 0;3673long nfisclone = 0;3674long done_small, small_fail, fail_limit, squash_index, small_norm_prec;3675double LOGD, LOGD2, lim;3676GEN computed = NULL, fu = NULL, zu, nf, M_sn, D, A, W, R, h, Ce, PERM;3677GEN small_multiplier, auts, cyclic, embs, SUnits;3678GEN res, L, invhr, B, C, lambda, dep, clg1, clg2, Vbase;3679const char *precpb = NULL;3680nfmaxord_t nfT;3681RELCACHE_t cache;3682FB_t F;3683GRHcheck_t GRHcheck;3684FACT *fact;36853686if (DEBUGLEVEL) timer_start(&T);3687P = get_nfpol(P, &nf);3688if (nf)3689D = nf_get_disc(nf);3690else3691{3692nfinit_basic(&nfT, P);3693D = nfT.dK;3694if (!ZX_is_monic(nfT.T0))3695{3696pari_warn(warner,"nonmonic polynomial in bnfinit, using polredbest");3697flag_nfinit = nf_RED;3698}3699}3700N = degpol(P);3701if (N <= 1)3702{3703if (!nf) nf = nfinit_complete(&nfT, flag_nfinit, DEFAULTPREC);3704return gerepilecopy(av0, Buchall_deg1(nf));3705}3706D = absi_shallow(D);3707LOGD = dbllog2(D) * M_LN2;3708LOGD2 = LOGD*LOGD;3709LIMCMAX = (long)(12.*LOGD2);3710/* In small_norm, LLL reduction produces v0 in I such that3711* T2(v0) <= (4/3)^((n-1)/2) NI^(2/n) disc(K)^(1/n)3712* We consider v with T2(v) <= BMULT * T2(v0)3713* Hence Nv <= ((4/3)^((n-1)/2) * BMULT / n)^(n/2) NI sqrt(disc(K)).3714* NI <= LIMCMAX^2 */3715PREC = maxss(DEFAULTPREC, prec);3716if (nf) PREC = maxss(PREC, nf_get_prec(nf));3717PREC = maxss(PREC, nbits2prec((long)(LOGD2 * 0.02) + N*N));3718if (DEBUGLEVEL) err_printf("PREC = %ld\n", PREC);3719small_norm_prec = nbits2prec( BITS_IN_LONG +3720(N/2. * ((N-1)/2.*log(4./3) + log(BMULT/(double)N))3721+ 2*log((double) LIMCMAX) + LOGD/2) / M_LN2 ); /*enough to compute norms*/3722if (small_norm_prec > PREC) PREC = small_norm_prec;3723if (!nf)3724nf = nfinit_complete(&nfT, flag_nfinit, PREC);3725else if (nf_get_prec(nf) < PREC)3726nf = nfnewprec_shallow(nf, PREC);3727M_sn = nf_get_M(nf);3728if (PREC > small_norm_prec) M_sn = gprec_w(M_sn, small_norm_prec);37293730zu = nfrootsof1(nf);3731gel(zu,2) = nf_to_scalar_or_alg(nf, gel(zu,2));37323733nf_get_sign(nf, &R1, &R2); RU = R1+R2;3734auts = automorphism_matrices(nf, &cyclic);3735F.embperm = automorphism_perms(nf_get_M(nf), auts, cyclic, R1, R2, N);3736if (DEBUGLEVEL)3737{3738timer_printf(&T, "nfinit & nfrootsof1");3739err_printf("%s bnf: R1 = %ld, R2 = %ld\nD = %Ps\n",3740flag? "Algebraic": "Floating point", R1,R2, D);3741}3742if (LOGD < 20.)3743{ /* tiny disc, Minkowski may be smaller than Bach */3744lim = exp(-N + R2 * log(4/M_PI) + LOGD/2) * sqrt(2*M_PI*N);3745if (lim < 3) lim = 3;3746}3747else /* to be ignored */3748lim = -1;3749if (cbach > 12.) {3750if (cbach2 < cbach) cbach2 = cbach;3751cbach = 12.;3752}3753if (cbach < 0.)3754pari_err_DOMAIN("Buchall","Bach constant","<",gen_0,dbltor(cbach));37553756cache.base = NULL; F.subFB = NULL; F.LP = NULL; SUnits = Ce = NULL;3757init_GRHcheck(&GRHcheck, N, R1, LOGD);3758high = low = LIMC0 = maxss((long)(cbach2*LOGD2), 1);3759while (!GRHchk(nf, &GRHcheck, high)) { low = high; high *= 2; }3760while (high - low > 1)3761{3762long test = (low+high)/2;3763if (GRHchk(nf, &GRHcheck, test)) high = test; else low = test;3764}3765LIMC2 = (high == LIMC0+1 && GRHchk(nf, &GRHcheck, LIMC0))? LIMC0: high;3766if (LIMC2 > LIMCMAX) LIMC2 = LIMCMAX;3767/* Assuming GRH, {P, NP <= LIMC2} generate Cl(K) */3768if (DEBUGLEVEL) err_printf("LIMC2 = %ld\n", LIMC2);3769LIMC0 = (long)(cbach*LOGD2); /* initial value for LIMC */3770LIMC = cbach? LIMC0: LIMC2; /* use {P, NP <= LIMC} as a factorbase */3771LIMC = maxss(LIMC, nthideal(&GRHcheck, nf, N));3772if (DEBUGLEVEL) timer_printf(&T, "computing Bach constant");3773LIMres = primeneeded(N, R1, R2, LOGD);3774cache_prime_dec(&GRHcheck, LIMres, nf);3775/* invhr ~ 2^r1 (2pi)^r2 / sqrt(D) w * Res(zeta_K, s=1) = 1 / hR */3776invhr = gmul(gdiv(gmul2n(powru(mppi(DEFAULTPREC), R2), RU),3777mulri(gsqrt(D,DEFAULTPREC),gel(zu,1))),3778compute_invres(&GRHcheck, LIMres));3779if (DEBUGLEVEL) timer_printf(&T, "computing inverse of hR");3780av = avma;37813782START:3783if (DEBUGLEVEL) timer_start(&T);3784if (TRIES) LIMC = bnf_increase_LIMC(LIMC,LIMCMAX);3785if (DEBUGLEVEL && LIMC > LIMC0)3786err_printf("%s*** Bach constant: %f\n", TRIES?"\n":"", LIMC/LOGD2);3787if (cache.base)3788{3789REL_t *rel;3790for (i = 1, rel = cache.base + 1; rel < cache.last; rel++)3791if (rel->m) i++;3792computed = cgetg(i, t_VEC);3793for (i = 1, rel = cache.base + 1; rel < cache.last; rel++)3794if (rel->m) gel(computed, i++) = rel->m;3795computed = gclone(computed); delete_cache(&cache);3796}3797TRIES++; set_avma(av);3798if (F.LP) delete_FB(&F);3799if (LIMC2 < LIMC) LIMC2 = LIMC;3800if (DEBUGLEVEL) { err_printf("LIMC = %ld, LIMC2 = %ld\n",LIMC,LIMC2); }38013802FBgen(&F, nf, N, LIMC, LIMC2, &GRHcheck);3803if (!F.KC) goto START;3804av = avma;3805subFBgen(&F,auts,cyclic,lim < 0? LIMC2: mindd(lim,LIMC2),MINSFB);3806if (lg(F.subFB) == 1) goto START;3807if (DEBUGLEVEL)3808timer_printf(&T, "factorbase (#subFB = %ld) and ideal permutations",3809lg(F.subFB)-1);38103811fact = (FACT*)stack_malloc((F.KC+1)*sizeof(FACT));3812PERM = leafcopy(F.perm); /* to be restored in case of precision increase */3813cache.basis = zero_Flm_copy(F.KC,F.KC);3814small_multiplier = zero_Flv(F.KC);3815done_small = small_fail = squash_index = zc = sfb_trials = nreldep = 0;3816fail_limit = F.KC + 1;3817W = A = R = NULL;3818av2 = avma;3819init_rel(&cache, &F, RELSUP + RU-1);3820old_need = need = cache.end - cache.last;3821add_cyclotomic_units(nf, zu, &cache, &F);3822if (DEBUGLEVEL) err_printf("\n");3823cache.end = cache.last + need;38243825if (computed)3826{3827for (i = 1; i < lg(computed); i++)3828try_elt(&cache, &F, nf, gel(computed, i), fact);3829gunclone(computed);3830if (DEBUGLEVEL && i > 1)3831timer_printf(&T, "including already computed relations");3832need = 0;3833}38343835do3836{3837GEN Ar, C0;3838do3839{3840pari_sp av4 = avma;3841if (need > 0)3842{3843long oneed = cache.end - cache.last;3844/* Test below can be true if small_norm did not find enough linearly3845* dependent relations */3846if (need < oneed) need = oneed;3847pre_allocate(&cache, need+lg(auts)-1+(R ? lg(W)-1 : 0));3848cache.end = cache.last + need;3849F.L_jid = trim_list(&F);3850}3851if (need > 0 && Nrelid > 0 && (done_small <= F.KC+1 || A) &&3852small_fail <= fail_limit &&3853cache.last < cache.base + 2*F.KC+2*RU+RELSUP /* heuristic */)3854{3855long j, k, LIE = (R && lg(W) > 1 && (done_small % 2));3856REL_t *last = cache.last;3857pari_sp av3 = avma;3858GEN p0;3859if (LIE)3860{ /* We have full rank for class group and unit. The following tries to3861* improve the prime group lattice by looking for relations involving3862* the primes generating the class group. */3863long n = lg(W)-1; /* need n relations to squash the class group */3864F.L_jid = vecslice(F.perm, 1, n);3865cache.end = cache.last + n;3866/* Lie to the add_rel subsystem: pretend we miss relations involving3867* the primes generating the class group (and only those). */3868cache.missing = n;3869for ( ; n > 0; n--) mael(cache.basis, F.perm[n], F.perm[n]) = 0;3870}3871j = done_small % (F.KC+1);3872if (j == 0) p0 = NULL;3873else3874{3875p0 = gel(F.LP, j);3876if (!A)3877{ /* Prevent considering both P_iP_j and P_jP_i in small_norm */3878/* Not all elements end up in F.L_jid (eliminated by hnfspec/add or3879* by trim_list): keep track of which ideals are being considered3880* at each run. */3881long mj = small_multiplier[j];3882for (i = k = 1; i < lg(F.L_jid); i++)3883if (F.L_jid[i] > mj)3884{3885small_multiplier[F.L_jid[i]] = j;3886F.L_jid[k++] = F.L_jid[i];3887}3888setlg(F.L_jid, k);3889}3890}3891if (lg(F.L_jid) > 1)3892small_norm(&cache, &F, nf, Nrelid, M_sn, fact, p0);3893F.L_jid = F.perm; set_avma(av3);3894if (!A && cache.last != last) small_fail = 0; else small_fail++;3895if (LIE)3896{ /* restore add_rel subsystem: undo above lie */3897long n = lg(W) - 1;3898for ( ; n > 0; n--) mael(cache.basis, F.perm[n], F.perm[n]) = 1;3899cache.missing = 0;3900}3901cache.end = cache.last;3902done_small++;3903need = F.sfb_chg = 0;3904}3905if (need > 0)3906{ /* Random relations */3907if (++nreldep > F.MAXDEPSIZESFB) {3908if (++sfb_trials > SFB_MAX && LIMC < LIMCMAX/6) goto START;3909F.sfb_chg = sfb_INCREASE;3910nreldep = 0;3911}3912else if (!(nreldep % F.MAXDEPSFB))3913F.sfb_chg = sfb_CHANGE;3914if (F.sfb_chg && !subFB_change(&F)) goto START;3915rnd_rel(&cache, &F, nf, fact);3916F.L_jid = F.perm;3917}3918if (DEBUGLEVEL) timer_start(&T);3919if (precpb)3920{3921REL_t *rel;3922if (DEBUGLEVEL)3923{3924char str[64]; sprintf(str,"Buchall_param (%s)",precpb);3925pari_warn(warnprec,str,PREC);3926}3927nf = _nfnewprec(nf, PREC, &nfisclone);3928precdouble++; precpb = NULL;39293930if (flag)3931{ /* recompute embs only, no need to redo HNF */3932long j, le = lg(embs), lC = lg(C);3933GEN E, M = nf_get_M(nf);3934set_avma(av4);3935for (rel = cache.base+1, i = 1; i < le; i++,rel++)3936gel(embs,i) = rel_embed(rel, &F, embs, i, M, RU, R1, PREC);3937E = RgM_ZM_mul(embs, rowslice(C, RU+1, nbrows(C)));3938for (j = 1; j < lC; j++)3939for (i = 1; i <= RU; i++) gcoeff(C,i,j) = gcoeff(E,i,j);3940av4 = avma;3941}3942else3943{ /* recompute embs + HNF */3944for(i = 1; i < lg(PERM); i++) F.perm[i] = PERM[i];3945cache.chk = cache.base;3946W = NULL;3947}3948if (DEBUGLEVEL) timer_printf(&T, "increasing accuracy");3949}3950set_avma(av4);3951if (cache.chk != cache.last)3952{ /* Reduce relation matrices */3953long l = cache.last - cache.chk + 1, j;3954GEN mat = cgetg(l, t_MAT);3955REL_t *rel;39563957for (j=1,rel = cache.chk + 1; j < l; rel++,j++) gel(mat,j) = rel->R;3958if (!flag || W)3959{3960embs = get_embs(&F, &cache, nf, embs, PREC);3961if (DEBUGLEVEL && timer_get(&T) > 1)3962timer_printf(&T, "floating point embeddings");3963}3964if (!W)3965{ /* never reduced before */3966C = flag? matbotid(&cache): embs;3967W = hnfspec_i(mat, F.perm, &dep, &B, &C, F.subFB ? lg(F.subFB)-1:0);3968if (DEBUGLEVEL)3969timer_printf(&T, "hnfspec [%ld x %ld]", lg(F.perm)-1, l-1);3970if (flag)3971{3972PREC += nbits2extraprec(gexpo(C));3973if (nf_get_prec(nf) < PREC) nf = _nfnewprec(nf, PREC, &nfisclone);3974embs = get_embs(&F, &cache, nf, embs, PREC);3975C = vconcat(RgM_ZM_mul(embs, C), C);3976}3977if (DEBUGLEVEL)3978timer_printf(&T, "hnfspec floating points");3979}3980else3981{3982long k = lg(embs);3983GEN E = vecslice(embs, k-l+1,k-1);3984if (flag)3985{3986E = matbotidembs(&cache, E);3987matenlarge(C, cache.last - cache.chk);3988}3989W = hnfadd_i(W, F.perm, &dep, &B, &C, mat, E);3990if (DEBUGLEVEL)3991timer_printf(&T, "hnfadd (%ld + %ld)", l-1, lg(dep)-1);3992}3993gerepileall(av2, 5, &W,&C,&B,&dep,&embs);3994cache.chk = cache.last;3995}3996else if (!W)3997{3998need = old_need;3999F.L_jid = vecslice(F.perm, 1, need);4000continue;4001}4002need = F.KC - (lg(W)-1) - (lg(B)-1);4003if (!need && cache.missing)4004{ /* The test above will never be true except if 27449|class number.4005* Ensure that if we have maximal rank for the ideal lattice, then4006* cache.missing == 0. */4007for (i = 1; cache.missing; i++)4008if (!mael(cache.basis, i, i))4009{4010long j;4011cache.missing--; mael(cache.basis, i, i) = 1;4012for (j = i+1; j <= F.KC; j++) mael(cache.basis, j, i) = 0;4013}4014}4015zc = (lg(C)-1) - (lg(B)-1) - (lg(W)-1);4016if (RU-1-zc > 0) need = minss(need + RU-1-zc, F.KC); /* for units */4017if (need)4018{ /* dependent rows */4019F.L_jid = vecslice(F.perm, 1, need);4020vecsmall_sort(F.L_jid);4021if (need != old_need) { nreldep = 0; old_need = need; }4022}4023else4024{ /* If the relation lattice is too small, check will be > 1 and we will4025* do a new run of small_norm/rnd_rel asking for 1 relation. This often4026* gives a relation involving L_jid[1]. We rotate the first element of4027* L_jid in order to increase the probability of finding relations that4028* increases the lattice. */4029long j, n = lg(W) - 1;4030if (n > 1 && squash_index % n)4031{4032F.L_jid = leafcopy(F.perm);4033for (j = 1; j <= n; j++)4034F.L_jid[j] = F.perm[1 + (j + squash_index - 1) % n];4035}4036else4037F.L_jid = F.perm;4038squash_index++;4039}4040}4041while (need);40424043if (!A)4044{4045small_fail = old_need = 0;4046fail_limit = maxss(F.KC / FAIL_DIVISOR, MINFAIL);4047}4048A = vecslice(C, 1, zc); /* cols corresponding to units */4049if (flag) A = rowslice(A, 1, RU);4050Ar = real_i(A);4051R = compute_multiple_of_R(Ar, RU, N, &need, &bit, &lambda);4052if (need < old_need) small_fail = 0;4053#if 0 /* A good idea if we are indeed stuck but needs tuning */4054/* we have computed way more relations than should be necessary */4055if (TRIES < 3 && LIMC < LIMCMAX / 24 &&4056cache.last - cache.base > 10 * F.KC) goto START;4057#endif4058old_need = need;4059if (!lambda)4060{ precpb = "bestappr"; PREC = myprecdbl(PREC, flag? C: NULL); continue; }4061if (!R)4062{ /* not full rank for units */4063if (!need)4064{ precpb = "regulator"; PREC = myprecdbl(PREC, flag? C: NULL); }4065continue;4066}4067h = ZM_det_triangular(W);4068if (DEBUGLEVEL) err_printf("\n#### Tentative class number: %Ps\n", h);4069i = compute_R(lambda, mulir(h,invhr), &L, &R);4070if (DEBUGLEVEL)4071{4072err_printf("\n");4073timer_printf(&T, "computing regulator and check");4074}4075switch(i)4076{4077case fupb_RELAT:4078need = 1; /* not enough relations */4079continue;4080case fupb_PRECI: /* prec problem unless we cheat on Bach constant */4081if ((precdouble&7) == 7 && LIMC<=LIMCMAX/6) goto START;4082precpb = "compute_R"; PREC = myprecdbl(PREC, flag? C: NULL);4083continue;4084}4085/* DONE */40864087if (F.KCZ2 > F.KCZ)4088{4089if (F.sfb_chg && !subFB_change(&F)) goto START;4090if (!be_honest(&F, nf, auts, fact)) goto START;4091if (DEBUGLEVEL) timer_printf(&T, "to be honest");4092}4093F.KCZ2 = 0; /* be honest only once */40944095/* fundamental units */4096{4097GEN AU, CU, U, v = extract_full_lattice(L); /* L may be large */4098CU = NULL;4099if (v) { A = vecpermute(A, v); L = vecpermute(L, v); }4100/* arch. components of fund. units */4101U = ZM_lll(L, 0.99, LLL_IM);4102U = ZM_mul(U, lll(RgM_ZM_mul(real_i(A), U)));4103AU = RgM_ZM_mul(A, U);4104A = cleanarch(AU, N, PREC);4105if (DEBUGLEVEL) timer_printf(&T, "units LLL + cleanarch");4106if (!A || (lg(A) > 1 && gprecision(A) <= 2))4107{4108long add = nbits2extraprec( gexpo(AU) + 64 ) - gprecision(AU);4109precpb = "cleanarch"; PREC += maxss(add, 1); continue;4110}4111if (flag)4112{4113long l = lgcols(C) - RU;4114REL_t *rel;4115SUnits = cgetg(l, t_COL);4116for (rel = cache.base+1, i = 1; i < l; i++,rel++)4117set_rel_alpha(rel, auts, SUnits, i);4118if (RU > 1)4119{4120GEN c = v? vecpermute(C,v): vecslice(C,1,zc);4121CU = ZM_mul(rowslice(c, RU+1, nbrows(c)), U);4122}4123}4124if (DEBUGLEVEL) err_printf("\n#### Computing fundamental units\n");4125fu = getfu(nf, &A, CU? &U: NULL, PREC);4126CU = CU? ZM_mul(CU, U): cgetg(1, t_MAT);4127if (DEBUGLEVEL) timer_printf(&T, "getfu");4128Ce = vecslice(C, zc+1, lg(C)-1);4129if (flag) SUnits = mkvec4(SUnits, CU, rowslice(Ce, RU+1, nbrows(Ce)),4130utoipos(LIMC));4131}4132/* class group generators */4133if (flag) Ce = rowslice(Ce, 1, RU);4134C0 = Ce; Ce = cleanarch(Ce, N, PREC);4135if (!Ce) {4136long add = nbits2extraprec( gexpo(C0) + 64 ) - gprecision(C0);4137precpb = "cleanarch"; PREC += maxss(add, 1);4138}4139if (DEBUGLEVEL) timer_printf(&T, "cleanarch");4140} while (need || precpb);41414142Vbase = vecpermute(F.LP, F.perm);4143if (!fu) fu = cgetg(1, t_MAT);4144if (!SUnits) SUnits = gen_1;4145clg1 = class_group_gen(nf,W,Ce,Vbase,PREC, &clg2);4146res = mkvec5(clg1, R, SUnits, zu, fu);4147res = buchall_end(nf,res,clg2,W,B,A,Ce,Vbase);4148delete_FB(&F);4149res = gerepilecopy(av0, res);4150if (flag) obj_insert_shallow(res, MATAL, cgetg(1,t_VEC));4151if (nfisclone) gunclone(nf);4152delete_cache(&cache);4153free_GRHcheck(&GRHcheck);4154return res;4155}415641574158