Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314/*******************************************************************/15/* */16/* COMPUTATION OF STARK UNITS OF TOTALLY REAL FIELDS */17/* */18/*******************************************************************/19#include "pari.h"20#include "paripriv.h"2122#define DEBUGLEVEL DEBUGLEVEL_stark2324/* ComputeCoeff */25typedef struct {26GEN L0, L1, L11, L2; /* VECSMALL of p */27GEN L1ray, L11ray; /* precomputed isprincipalray(pr), pr | p */28GEN rayZ; /* precomputed isprincipalray(i), i < condZ */29long condZ; /* generates cond(bnr) \cap Z, assumed small */30} LISTray;3132/* Char evaluation */33typedef struct {34long ord;35GEN *val, chi;36} CHI_t;3738/* RecCoeff */39typedef struct {40GEN M, beta, B, U, nB;41long v, G, N;42} RC_data;4344/********************************************************************/45/* Miscellaneous functions */46/********************************************************************/47static GEN48chi_get_c(GEN chi) { return gmael(chi,1,2); }49static long50chi_get_deg(GEN chi) { return itou(gmael(chi,1,1)); }5152/* Compute the image of logelt by character chi, zeta_ord(chi)^n; return n */53static ulong54CharEval_n(GEN chi, GEN logelt)55{56GEN gn = ZV_dotproduct(chi_get_c(chi), logelt);57return umodiu(gn, chi_get_deg(chi));58}59/* Compute the image of logelt by character chi, as a complex number */60static GEN61CharEval(GEN chi, GEN logelt)62{63ulong n = CharEval_n(chi, logelt), d = chi_get_deg(chi);64long nn = Fl_center(n,d,d>>1);65GEN x = gel(chi,2);66x = gpowgs(x, labs(nn));67if (nn < 0) x = conj_i(x);68return x;69}7071/* return n such that C(elt) = z^n */72static ulong73CHI_eval_n(CHI_t *C, GEN logelt)74{75GEN n = ZV_dotproduct(C->chi, logelt);76return umodiu(n, C->ord);77}78/* return C(elt) */79static GEN80CHI_eval(CHI_t *C, GEN logelt)81{82return C->val[CHI_eval_n(C, logelt)];83}8485static void86init_CHI(CHI_t *c, GEN CHI, GEN z)87{88long i, d = chi_get_deg(CHI);89GEN *v = (GEN*)new_chunk(d);90v[0] = gen_1;91if (d != 1)92{93v[1] = z;94for (i=2; i<d; i++) v[i] = gmul(v[i-1], z);95}96c->chi = chi_get_c(CHI);97c->ord = d;98c->val = v;99}100/* as t_POLMOD */101static void102init_CHI_alg(CHI_t *c, GEN CHI) {103long d = chi_get_deg(CHI);104GEN z;105switch(d)106{107case 1: z = gen_1; break;108case 2: z = gen_m1; break;109default: z = mkpolmod(pol_x(0), polcyclo(d,0));110}111init_CHI(c,CHI, z);112}113/* as t_COMPLEX */114static void115init_CHI_C(CHI_t *c, GEN CHI) {116init_CHI(c,CHI, gel(CHI,2));117}118119typedef struct {120long r; /* rank = lg(gen) */121GEN j; /* current elt is gen[1]^j[1] ... gen[r]^j[r] */122GEN cyc; /* t_VECSMALL of elementary divisors */123} GROUP_t;124125static int126NextElt(GROUP_t *G)127{128long i = 1;129if (G->r == 0) return 0; /* no more elt */130while (++G->j[i] == G->cyc[i]) /* from 0 to cyc[i]-1 */131{132G->j[i] = 0;133if (++i > G->r) return 0; /* no more elt */134}135return i; /* we have multiplied by gen[i] */136}137138/* enumerate all group elements; trivial elt comes last */139GEN140cyc2elts(GEN cyc)141{142long i, n;143GEN z;144GROUP_t G;145146G.cyc = typ(cyc)==t_VECSMALL? cyc: gtovecsmall(cyc);147n = zv_prod(G.cyc);148G.r = lg(cyc)-1;149G.j = zero_zv(G.r);150151z = cgetg(n+1, t_VEC);152gel(z,n) = leafcopy(G.j); /* trivial elt comes last */153for (i = 1; i < n; i++)154{155(void)NextElt(&G);156gel(z,i) = leafcopy(G.j);157}158return z;159}160161/* nchi: a character given by a vector [d, (c_i)], e.g. from char_normalize162* such that chi(x) = e((c . log(x)) / d) where log(x) on bnr.gen */163static GEN164get_Char(GEN nchi, long prec)165{ return mkvec2(nchi, rootsof1_cx(gel(nchi,1), prec)); }166167/* prime divisors of conductor */168static GEN169divcond(GEN bnr) {GEN bid = bnr_get_bid(bnr); return gel(bid_get_fact(bid),1);}170171/* vector of prime ideals dividing bnr but not bnrc */172static GEN173get_prdiff(GEN D, GEN Dc)174{175long n, i, l = lg(D);176GEN diff = cgetg(l, t_COL);177for (n = i = 1; i < l; i++)178if (!tablesearch(Dc, gel(D,i), &cmp_prime_ideal)) gel(diff,n++) = gel(D,i);179setlg(diff, n); return diff;180}181182#define ch_prec(x) realprec(gel(x,1))183#define ch_C(x) gel(x,1)184#define ch_bnr(x) gel(x,2)185#define ch_3(x) gel(x,3)186#define ch_q(x) gel(x,3)[1]187#define ch_CHI(x) gel(x,4)188#define ch_diff(x) gel(x,5)189#define ch_CHI0(x) gel(x,6)190#define ch_small(x) gel(x,7)191#define ch_comp(x) gel(x,7)[1]192#define ch_phideg(x) gel(x,7)[2]193static long194ch_deg(GEN dtcr) { return chi_get_deg(ch_CHI(dtcr)); }195196/********************************************************************/197/* 1rst part: find the field K */198/********************************************************************/199static GEN AllStark(GEN data, long flag, long prec);200201/* Columns of C [HNF] give the generators of a subgroup of the finite abelian202* group A [ in terms of implicit generators ], compute data to work in A/C:203* 1) order204* 2) structure205* 3) the matrix A ->> A/C206* 4) the subgroup C */207static GEN208InitQuotient(GEN C)209{210GEN U, D = ZM_snfall_i(C, &U, NULL, 1), h = ZV_prod(D);211return mkvec5(h, D, U, C, cyc_normalize(D));212}213214/* lift chi character on A/C [Qt from InitQuotient] to character on A [cyc]*/215static GEN216LiftChar(GEN Qt, GEN cyc, GEN chi)217{218GEN ncyc = gel(Qt,5), U = gel(Qt,3), nchi = char_normalize(chi, ncyc);219GEN c = ZV_ZM_mul(gel(nchi,2), U), d = gel(nchi,1);220return char_denormalize(cyc, d, c);221}222223/* Let C be a subgroup, system of representatives of the quotient */224static GEN225ag_subgroup_classes(GEN C)226{227GEN U, D = ZM_snfall_i(C, &U, NULL, 1), e = cyc2elts(D);228long i, l = lg(e);229230if (ZM_isidentity(U))231for (i = 1; i < l; i++) (void)vecsmall_to_vec_inplace(gel(e,i));232else233{234GEN Ui = ZM_inv(U,NULL);235for (i = 1; i < l; i++) gel(e,i) = ZM_zc_mul(Ui, gel(e,i));236}237return e;238}239240/* Let s: A -> B given by [P,cycA,cycB] A and B, compute the kernel of s. */241GEN242ag_kernel(GEN S)243{244GEN U, P = gel(S,1), cycA = gel(S,2), DB = diagonal_shallow(gel(S,3));245long nA = lg(cycA)-1, rk;246247rk = nA + lg(DB) - lg(ZM_hnfall_i(shallowconcat(P, DB), &U, 1));248return ZM_hnfmodid(matslice(U, 1,nA, 1,rk), cycA);249}250/* let H be a subgroup of A; return s(H) */251GEN252ag_subgroup_image(GEN S, GEN H)253{ return ZM_hnfmodid(ZM_mul(gel(S,1), H), gel(S,3)); }254255/* Let m and n be two moduli such that n|m and let C be a congruence256group modulo n, compute the corresponding congruence group modulo m257ie the kernel of the map Clk(m) ->> Clk(n)/C */258static GEN259ComputeKernel(GEN bnrm, GEN bnrn, GEN dtQ)260{261pari_sp av = avma;262GEN S = bnrsurjection(bnrm, bnrn);263GEN P = ZM_mul(gel(dtQ,3), gel(S,1));264return gerepileupto(av, ag_kernel(mkvec3(P, gel(S,2), gel(dtQ,2))));265}266267static long268cyc_is_cyclic(GEN cyc) { return lg(cyc) <= 2 || equali1(gel(cyc,2)); }269270/* Let H be a subgroup of cl(bnr)/sugbroup, return 1 if271cl(bnr)/subgoup/H is cyclic and the signature of the272corresponding field is equal to sig and no finite prime273dividing cond(bnr) is totally split in this field. Return 0274otherwise. */275static long276IsGoodSubgroup(GEN H, GEN bnr, GEN map)277{278pari_sp av = avma;279GEN S, mod, modH, p1, U, P, PH, bnrH, iH, qH;280long j;281282p1 = InitQuotient(H);283/* quotient is non cyclic */284if (!cyc_is_cyclic(gel(p1,2))) return gc_long(av,0);285286(void)ZM_hnfall_i(shallowconcat(map,H), &U, 0);287setlg(U, lg(H));288for (j = 1; j < lg(U); j++) setlg(gel(U,j), lg(H));289p1 = ZM_hnfmodid(U, bnr_get_cyc(bnr)); /* H as a subgroup of bnr */290modH = bnrconductor_raw(bnr, p1);291mod = bnr_get_mod(bnr);292293/* is the signature correct? */294if (!gequal(gel(modH,2), gel(mod,2))) return gc_long(av, 0);295296/* finite part are the same: OK */297if (gequal(gel(modH,1), gel(mod,1))) return gc_long(av, 1);298299/* need to check the splitting of primes dividing mod but not modH */300bnrH = Buchray(bnr, modH, nf_INIT);301P = divcond(bnr);302PH = divcond(bnrH);303S = bnrsurjection(bnr, bnrH);304/* H as a subgroup of bnrH */305iH = ag_subgroup_image(S, p1);306qH = InitQuotient(iH);307for (j = 1; j < lg(P); j++)308{309GEN pr = gel(P, j), e;310/* if pr divides modH, it is ramified, so it's good */311if (tablesearch(PH, pr, cmp_prime_ideal)) continue;312/* inertia degree of pr in bnr(modH)/H is charorder(e, cycH) */313e = ZM_ZC_mul(gel(qH,3), isprincipalray(bnrH, pr));314e = vecmodii(e, gel(qH,2));315if (ZV_equal0(e)) return gc_long(av,0); /* f = 1 */316}317return gc_long(av,1);318}319320/* compute list of nontrivial characters trivial on H, modulo complex321* conjugation. If flag is set, impose a nontrivial conductor at infinity */322static GEN323AllChars(GEN bnr, GEN dtQ, long flag)324{325GEN v, vchi, cyc = bnr_get_cyc(bnr);326long n, i, hD = itos(gel(dtQ,1));327hashtable *S;328329v = cgetg(hD+1, t_VEC); /* nonconjugate chars */330vchi = cyc2elts(gel(dtQ,2));331S = hash_create(hD, (ulong(*)(void*))&hash_GEN,332(int(*)(void*,void*))&ZV_equal, 1);333for (i = n = 1; i < hD; i++) /* remove i = hD: trivial char */334{ /* lift a character of D in Clk(m) */335GEN F, lchi = LiftChar(dtQ, cyc, zv_to_ZV(gel(vchi,i))), cchi = NULL;336337if (hash_search(S, lchi)) continue;338F = bnrconductor_raw(bnr, lchi);339if (flag && gequal0(gel(F,2))) continue; /* f_oo(chi) trivial ? */340341if (abscmpiu(charorder(cyc,lchi), 2) > 0)342{ /* nonreal chi: add its conjugate character to S */343cchi = charconj(cyc, lchi);344hash_insert(S, cchi, (void*)1);345}346gel(v, n++) = cchi? mkvec3(lchi, F, cchi): mkvec2(lchi, F);347}348setlg(v, n); return v;349}350351static GEN InitChar(GEN bnr, GEN CR, long flag, long prec);352static void CharNewPrec(GEN data, long prec);353354/* Given a conductor and a subgroups, return the corresponding complexity and355* precision required using quickpol. Fill data[5] with dataCR */356static long357CplxModulus(GEN data, long *newprec)358{359long dprec = DEFAULTPREC;360pari_sp av = avma;361for (;;)362{363GEN cpl, pol = AllStark(data, -1, dprec);364cpl = RgX_fpnorml2(pol, LOWDEFAULTPREC);365dprec = maxss(dprec, nbits2extraprec(gexpo(pol))) + EXTRAPREC64;366if (!gequal0(cpl)) { *newprec = dprec; return gexpo(cpl); }367set_avma(av);368if (DEBUGLEVEL>1) pari_warn(warnprec, "CplxModulus", dprec);369CharNewPrec(data, dprec);370}371}372373/* return A \cap B in abelian group defined by cyc. NULL = whole group */374static GEN375subgp_intersect(GEN cyc, GEN A, GEN B)376{377GEN H, U;378long k, lH;379if (!A) return B;380if (!B) return A;381H = ZM_hnfall_i(shallowconcat(A,B), &U, 1);382setlg(U, lg(A)); lH = lg(H);383for (k = 1; k < lg(U); k++) setlg(gel(U,k), lH);384return ZM_hnfmodid(ZM_mul(A,U), cyc);385}386387static void CharNewPrec(GEN dataCR, long prec);388/* Let (f,C) be a conductor without infinite part and a congruence group mod f.389* Compute (m,D) such that D is a congruence group of conductor m, f | m,390* divisible by all the infinite places but one, D is a subgroup of index 2 of391* Cm = Ker: Clk(m) -> Clk(f)/C. Consider further the subgroups H of Clk(m)/D392* with cyclic quotient Clk(m)/H such that no place dividing m is totally split393* in the extension KH corresponding to H: we want their intersection to be394* trivial. These H correspond to (the kernels of Galois orbits of) characters395* chi of Clk(m)/D such that chi(log_gen_arch(m_oo)) != 1 and for all pr | m396* we either have397* - chi(log_gen_pr(pr,1)) != 1 [pr | cond(chi) => ramified in KH]398* - or [pr \nmid cond(chi)] chi lifted to Clk(m/pr^oo) is not trivial at pr.399* We want the map from Clk(m)/D given by the vector of such caracters to have400* trivial kernel. Return bnr(m), D, Ck(m)/D and Clk(m)/Cm */401static GEN402FindModulus(GEN bnr, GEN dtQ, long *newprec)403{404const long LIMNORM = 400;405long n, i, maxnorm, minnorm, N, pr, rb, iscyc, olde = LONG_MAX;406pari_sp av = avma;407GEN bnf, nf, f, varch, m, rep = NULL;408409bnf = bnr_get_bnf(bnr);410nf = bnf_get_nf(bnf);411N = nf_get_degree(nf);412f = gel(bnr_get_mod(bnr), 1);413414/* if cpl < rb, it is not necessary to try another modulus */415rb = expi( powii(mulii(nf_get_disc(nf), ZM_det_triangular(f)),416gmul2n(bnr_get_no(bnr), 3)) );417418/* Initialization of the possible infinite part */419varch = cgetg(N+1,t_VEC);420for (i = 1; i <= N; i++)421{422GEN a = const_vec(N,gen_1);423gel(a, N+1-i) = gen_0;424gel(varch, i) = a;425}426m = cgetg(3, t_VEC);427428/* Go from minnorm up to maxnorm; if necessary, increase these values.429* If the extension is cyclic then a suitable conductor exists and we go on430* until we find it. Else, stop at norm LIMNORM. */431minnorm = 1;432maxnorm = 50;433iscyc = cyc_is_cyclic(gel(dtQ,2));434435if (DEBUGLEVEL>1)436err_printf("Looking for a modulus of norm: ");437438for(;;)439{440GEN listid = ideallist0(nf, maxnorm, 4+8); /* ideals of norm <= maxnorm */441pari_sp av1 = avma;442for (n = minnorm; n <= maxnorm; n++, set_avma(av1))443{444GEN idnormn = gel(listid,n);445long nbidnn = lg(idnormn) - 1;446if (DEBUGLEVEL>1) err_printf(" %ld", n);447for (i = 1; i <= nbidnn; i++)448{ /* finite part of the conductor */449long s;450451gel(m,1) = idealmul(nf, f, gel(idnormn,i));452for (s = 1; s <= N; s++)453{ /* infinite part */454GEN candD, Cm, bnrm;455long lD, c;456457gel(m,2) = gel(varch,s);458/* compute Clk(m), check if m is a conductor */459bnrm = Buchray(bnf, m, nf_INIT);460if (!bnrisconductor(bnrm, NULL)) continue;461462/* compute Im(C) in Clk(m)... */463Cm = ComputeKernel(bnrm, bnr, dtQ);464/* ... and its subgroups of index 2 with conductor m */465candD = subgrouplist_cond_sub(bnrm, Cm, mkvec(gen_2));466lD = lg(candD);467for (c = 1; c < lD; c++)468{469GEN data, CR, D = gel(candD,c), QD = InitQuotient(D);470GEN ord = gel(QD,1), cyc = gel(QD,2), map = gel(QD,3);471long e;472473if (!cyc_is_cyclic(cyc)) /* cyclic => suitable, else test */474{475GEN lH = subgrouplist(cyc, NULL), IK = NULL;476long j, ok = 0;477for (j = 1; j < lg(lH); j++)478{479GEN H = gel(lH, j), IH = subgp_intersect(cyc, IK, H);480/* if H > IK, no need to test H */481if (IK && gidentical(IH, IK)) continue;482if (IsGoodSubgroup(H, bnrm, map))483{484IK = IH; /* intersection of all good subgroups */485if (equalii(ord, ZM_det_triangular(IK))) { ok = 1; break; }486}487}488if (!ok) continue;489}490CR = InitChar(bnrm, AllChars(bnrm, QD, 1), 0, DEFAULTPREC);491data = mkvec4(bnrm, D, ag_subgroup_classes(Cm), CR);492if (DEBUGLEVEL>1)493err_printf("\nTrying modulus = %Ps and subgroup = %Ps\n",494bnr_get_mod(bnrm), D);495e = CplxModulus(data, &pr);496if (DEBUGLEVEL>1) err_printf("cpl = 2^%ld\n", e);497if (e < olde)498{499guncloneNULL(rep); rep = gclone(data);500*newprec = pr; olde = e;501}502if (olde < rb) goto END; /* OK */503if (DEBUGLEVEL>1) err_printf("Trying to find another modulus...");504}505}506if (rep) goto END; /* OK */507}508}509/* if necessary compute more ideals */510minnorm = maxnorm;511maxnorm <<= 1;512if (!iscyc && maxnorm > LIMNORM) return NULL;513}514END:515if (DEBUGLEVEL>1)516err_printf("No, we're done!\nModulus = %Ps and subgroup = %Ps\n",517bnr_get_mod(gel(rep,1)), gel(rep,2));518CharNewPrec(rep, *newprec); return gerepilecopy(av, rep);519}520521/********************************************************************/522/* 2nd part: compute W(X) */523/********************************************************************/524525/* find ilambda s.t. Diff*f*ilambda integral and coprime to f526and ilambda >> 0 at foo, fa = factorization of f */527static GEN528get_ilambda(GEN nf, GEN fa, GEN foo)529{530GEN x, w, E2, P = gel(fa,1), E = gel(fa,2), D = nf_get_diff(nf);531long i, l = lg(P);532if (l == 1) return gen_1;533w = cgetg(l, t_VEC);534E2 = cgetg(l, t_COL);535for (i = 1; i < l; i++)536{537GEN pr = gel(P,i), t = pr_get_tau(pr);538long e = itou(gel(E,i)), v = idealval(nf, D, pr);539if (v) { D = idealdivpowprime(nf, D, pr, utoipos(v)); e += v; }540gel(E2,i) = stoi(e+1);541if (typ(t) == t_MAT) t = gel(t,1);542gel(w,i) = gdiv(nfpow(nf, t, stoi(e)), powiu(pr_get_p(pr),e));543}544x = mkmat2(P, E2);545return idealchinese(nf, mkvec2(x, foo), w);546}547/* compute the list of W(chi) such that Ld(s,chi) = W(chi) Ld(1 - s, chi*),548* for all chi in LCHI. All chi have the same conductor (= cond(bnr)). */549static GEN550ArtinNumber(GEN bnr, GEN LCHI, long prec)551{552long ic, i, j, nz, nChar = lg(LCHI)-1;553pari_sp av2;554GEN sqrtnc, cond, condZ, cond0, cond1, nf, T, cyc, vN, vB, diff, vt, idh;555GEN zid, gen, z, nchi, indW, W, classe, s0, s, den, ilambda, sarch;556CHI_t **lC;557GROUP_t G;558559lC = (CHI_t**)new_chunk(nChar + 1);560indW = cgetg(nChar + 1, t_VECSMALL);561W = cgetg(nChar + 1, t_VEC);562for (ic = 0, i = 1; i <= nChar; i++)563{564GEN CHI = gel(LCHI,i);565if (chi_get_deg(CHI) <= 2) { gel(W,i) = gen_1; continue; }566ic++; indW[ic] = i;567lC[ic] = (CHI_t*)new_chunk(sizeof(CHI_t));568init_CHI_C(lC[ic], CHI);569}570if (!ic) return W;571nChar = ic;572573nf = bnr_get_nf(bnr);574diff = nf_get_diff(nf);575T = nf_get_Tr(nf);576cond = bnr_get_mod(bnr);577cond0 = gel(cond,1); condZ = gcoeff(cond0,1,1);578cond1 = gel(cond,2);579580sqrtnc = gsqrt(idealnorm(nf, cond0), prec);581ilambda = get_ilambda(nf, bid_get_fact(bnr_get_bid(bnr)), cond1);582idh = idealmul(nf, ilambda, idealmul(nf, diff, cond0)); /* integral */583ilambda = Q_remove_denom(ilambda, &den);584z = den? rootsof1_cx(den, prec): NULL;585586/* compute a system of generators of (Ok/cond)^*, we'll make them587* cond1-positive in the main loop */588zid = Idealstar(nf, cond0, nf_GEN);589cyc = abgrp_get_cyc(zid);590gen = abgrp_get_gen(zid);591nz = lg(gen) - 1;592sarch = nfarchstar(nf, cond0, vec01_to_indices(cond1));593594nchi = cgetg(nChar+1, t_VEC);595for (ic = 1; ic <= nChar; ic++) gel(nchi,ic) = cgetg(nz + 1, t_VECSMALL);596for (i = 1; i <= nz; i++)597{598if (is_bigint(gel(cyc,i)))599pari_err_OVERFLOW("ArtinNumber [conductor too large]");600gel(gen,i) = set_sign_mod_divisor(nf, NULL, gel(gen,i), sarch);601classe = isprincipalray(bnr, gel(gen,i));602for (ic = 1; ic <= nChar; ic++) {603GEN n = gel(nchi,ic);604n[i] = CHI_eval_n(lC[ic], classe);605}606}607608/* Sum chi(beta) * exp(2i * Pi * Tr(beta * ilambda) where beta609runs through the classes of (Ok/cond0)^* and beta cond1-positive */610vt = gel(T,1); /* ( Tr(w_i) )_i */611if (typ(ilambda) == t_COL)612vt = ZV_ZM_mul(vt, zk_multable(nf, ilambda));613else614vt = ZC_Z_mul(vt, ilambda);615/*vt = den . (Tr(w_i * ilambda))_i */616G.cyc = gtovecsmall(cyc);617G.r = nz;618G.j = zero_zv(nz);619vN = zero_Flm_copy(nz, nChar);620621av2 = avma;622vB = const_vec(nz, gen_1);623s0 = z? powgi(z, modii(gel(vt,1), den)): gen_1; /* for beta = 1 */624s = const_vec(nChar, s0);625626while ( (i = NextElt(&G)) )627{628GEN b = gel(vB,i);629b = nfmuli(nf, b, gel(gen,i));630b = typ(b) == t_COL? FpC_red(b, condZ): modii(b, condZ);631for (j=1; j<=i; j++) gel(vB,j) = b;632633for (ic = 1; ic <= nChar; ic++)634{635GEN v = gel(vN,ic), n = gel(nchi,ic);636v[i] = Fl_add(v[i], n[i], lC[ic]->ord);637for (j=1; j<i; j++) v[j] = v[i];638}639640gel(vB,i) = b = set_sign_mod_divisor(nf, NULL, b, sarch);641if (!z)642s0 = gen_1;643else644{645b = typ(b) == t_COL? ZV_dotproduct(vt, b): mulii(gel(vt,1),b);646s0 = powgi(z, modii(b,den));647}648for (ic = 1; ic <= nChar; ic++)649{650GEN v = gel(vN,ic), val = lC[ic]->val[ v[i] ];651gel(s,ic) = gadd(gel(s,ic), gmul(val, s0));652}653654if (gc_needed(av2, 1))655{656if (DEBUGMEM > 1) pari_warn(warnmem,"ArtinNumber");657gerepileall(av2, 2, &s, &vB);658}659}660661classe = isprincipalray(bnr, idh);662z = powIs(- (lg(gel(sarch,1))-1));663664for (ic = 1; ic <= nChar; ic++)665{666s0 = gmul(gel(s,ic), CHI_eval(lC[ic], classe));667gel(W, indW[ic]) = gmul(gdiv(s0, sqrtnc), z);668}669return W;670}671672static GEN673AllArtinNumbers(GEN CR, long prec)674{675pari_sp av = avma;676GEN vChar = gel(CR,1), dataCR = gel(CR,2);677long j, k, cl = lg(dataCR) - 1, J = lg(vChar)-1;678GEN W = cgetg(cl+1,t_VEC), WbyCond, LCHI;679680for (j = 1; j <= J; j++)681{682GEN LChar = gel(vChar,j), ldata = vecpermute(dataCR, LChar);683GEN dtcr = gel(ldata,1), bnr = ch_bnr(dtcr);684long l = lg(LChar);685686if (DEBUGLEVEL>1)687err_printf("* Root Number: cond. no %ld/%ld (%ld chars)\n", j, J, l-1);688LCHI = cgetg(l, t_VEC);689for (k = 1; k < l; k++) gel(LCHI,k) = ch_CHI0(gel(ldata,k));690WbyCond = ArtinNumber(bnr, LCHI, prec);691for (k = 1; k < l; k++) gel(W,LChar[k]) = gel(WbyCond,k);692}693return gerepilecopy(av, W);694}695696/* compute the constant W of the functional equation of697Lambda(chi). If flag = 1 then chi is assumed to be primitive */698GEN699bnrrootnumber(GEN bnr, GEN chi, long flag, long prec)700{701pari_sp av = avma;702GEN cyc, W;703704if (flag < 0 || flag > 1) pari_err_FLAG("bnrrootnumber");705checkbnr(bnr);706if (flag)707{708cyc = bnr_get_cyc(bnr);709if (!char_check(cyc,chi)) pari_err_TYPE("bnrrootnumber [character]", chi);710}711else712{713bnr_char_sanitize(&bnr, &chi);714cyc = bnr_get_cyc(bnr);715}716chi = char_normalize(chi, cyc_normalize(cyc));717chi = get_Char(chi, prec);718W = ArtinNumber(bnr, mkvec(chi), prec);719return gerepilecopy(av, gel(W,1));720}721722/********************************************************************/723/* 3rd part: initialize the characters */724/********************************************************************/725726/* Let chi be a character, A(chi) corresponding to the primes dividing diff727* at s = flag. If s = 0, returns [r, A] where r is the order of vanishing728* at s = 0 corresponding to diff. */729static GEN730AChi(GEN dtcr, long *r, long flag, long prec)731{732GEN A, diff = ch_diff(dtcr), bnrc = ch_bnr(dtcr), chi = ch_CHI0(dtcr);733long i, l = lg(diff);734735A = gen_1; *r = 0;736for (i = 1; i < l; i++)737{738GEN B, pr = gel(diff,i), z = CharEval(chi, isprincipalray(bnrc, pr));739if (flag)740B = gsubsg(1, gdiv(z, pr_norm(pr)));741else if (gequal1(z))742{743B = glog(pr_norm(pr), prec);744(*r)++;745}746else747B = gsubsg(1, z);748A = gmul(A, B);749}750return A;751}752/* simplified version of Achi: return 1 if L(0,chi) = 0 */753static int754L_vanishes_at_0(GEN D)755{756GEN diff = ch_diff(D), bnrc = ch_bnr(D), chi = ch_CHI0(D);757long i, l = lg(diff);758for (i = 1; i < l; i++)759{760GEN pr = gel(diff,i);761if (!CharEval_n(chi, isprincipalray(bnrc, pr))) return 1;762}763return 0;764}765766static GEN767_data3(GEN arch, long r2)768{769GEN z = cgetg(4, t_VECSMALL);770long i, r1 = lg(arch) - 1, q = 0;771for (i = 1; i <= r1; i++) if (signe(gel(arch,i))) q++;772z[1] = q;773z[2] = r1 - q;774z[3] = r2; return z;775}776static void777ch_get3(GEN dtcr, long *a, long *b, long *c)778{ GEN v = ch_3(dtcr); *a = v[1]; *b = v[2]; *c = v[3]; }779static GEN780get_C(GEN nf, long prec)781{782long r2 = nf_get_r2(nf), N = nf_get_degree(nf);783return gmul2n(sqrtr_abs(divir(nf_get_disc(nf), powru(mppi(prec),N))), -r2);784}785/* sort chars according to conductor */786static GEN787sortChars(GEN ch)788{789long j, l = lg(ch);790GEN F = cgetg(l, t_VEC);791for (j = 1; j < l; j++) gel(F, j) = gmael(ch,j,2);792return vec_equiv(F);793}794795/* Given a list [chi, F = cond(chi)] of characters over Cl(bnr), return796* [vChar, dataCR], where vChar containes the equivalence classes of797* characters with the same conductor, and dataCR contains for each character:798* - bnr(F)799* - the constant C(F) [t_REAL]800* - [q, r1 - q, r2, rc] where801* q = number of real places in F802* rc = max{r1 + r2 - q + 1, r2 + q}803* - diff(chi) primes dividing m but not F804* - chi in bnr(m)805* - chi in bnr(F).806* If all is unset, only compute characters s.t. L(chi,0) != 0 */807static GEN808InitChar(GEN bnr, GEN ch, long all, long prec)809{810GEN bnf = checkbnf(bnr), nf = bnf_get_nf(bnf), mod = bnr_get_mod(bnr);811GEN C, dataCR, ncyc, vChar = sortChars(ch);812long n, l, r2 = nf_get_r2(nf), prec2 = precdbl(prec) + EXTRAPREC64;813long lv = lg(vChar);814815C = get_C(nf, prec2);816ncyc = cyc_normalize(bnr_get_cyc(bnr));817818dataCR = cgetg_copy(ch, &l);819for (n = 1; n < lv; n++)820{821GEN D, bnrc, v = gel(vChar, n); /* indices of chars of given conductor */822long a, i = v[1], lc = lg(v);823GEN F = gmael(ch,i,2);824825gel(dataCR, i) = D = cgetg(8, t_VEC);826ch_C(D) = mulrr(C, gsqrt(ZM_det_triangular(gel(F,1)), prec2));827ch_3(D) = _data3(gel(F,2), r2);828if (gequal(F, mod))829{830ch_bnr(D) = bnrc = bnr;831ch_diff(D) = cgetg(1, t_VEC);832}833else834{835ch_bnr(D) = bnrc = Buchray(bnf, F, nf_INIT);836ch_diff(D) = get_prdiff(divcond(bnr), divcond(bnrc));837}838for (a = 1; a < lc; a++)839{840long i = v[a];841GEN chi = gmael(ch,i,1);842843if (a > 1) gel(dataCR, i) = D = leafcopy(D);844chi = char_normalize(chi,ncyc);845ch_CHI(D) = get_Char(chi, prec2);846if (bnrc == bnr)847ch_CHI0(D) = ch_CHI(D);848else849{850chi = bnrchar_primitive(bnr, chi, bnrc);851ch_CHI0(D) = get_Char(chi, prec2);852}853/* set last */854ch_small(D) = mkvecsmall2(all || !L_vanishes_at_0(D),855eulerphiu(itou(gel(chi,1))));856}857}858return mkvec2(vChar, dataCR);859}860861/* recompute dataCR with the new precision, modify bnr components in place */862static void863CharNewPrec(GEN data, long prec)864{865long j, l, prec2 = precdbl(prec) + EXTRAPREC64;866GEN C, nf, dataCR = gmael(data,4,2), D = gel(dataCR,1);867868if (ch_prec(D) >= prec2) return;869nf = bnr_get_nf(ch_bnr(D));870if (nf_get_prec(nf) < prec) nf = nfnewprec_shallow(nf, prec); /* not prec2 */871C = get_C(nf, prec2); l = lg(dataCR);872for (j = 1; j < l; j++)873{874GEN f0;875D = gel(dataCR,j); f0 = gel(bnr_get_mod(ch_bnr(D)), 1);876ch_C(D) = mulrr(C, gsqrt(ZM_det_triangular(f0), prec2));877gmael(ch_bnr(D), 1, 7) = nf;878ch_CHI(D) = get_Char(gel(ch_CHI(D),1), prec2);879ch_CHI0(D)= get_Char(gel(ch_CHI0(D),1), prec2);880}881}882883/********************************************************************/884/* 4th part: compute the coefficients an(chi) */885/* */886/* matan entries are arrays of ints containing the coefficients of */887/* an(chi) as a polmod modulo polcyclo(order(chi)) */888/********************************************************************/889890static void891_0toCoeff(int *rep, long deg)892{893long i;894for (i=0; i<deg; i++) rep[i] = 0;895}896897/* transform a polmod into Coeff */898static void899Polmod2Coeff(int *rep, GEN polmod, long deg)900{901long i;902if (typ(polmod) == t_POLMOD)903{904GEN pol = gel(polmod,2);905long d = degpol(pol);906907pol += 2;908for (i=0; i<=d; i++) rep[i] = itos(gel(pol,i));909for ( ; i<deg; i++) rep[i] = 0;910}911else912{913rep[0] = itos(polmod);914for (i=1; i<deg; i++) rep[i] = 0;915}916}917918/* initialize a deg * n matrix of ints */919static int**920InitMatAn(long n, long deg, long flag)921{922long i, j;923int *a, **A = (int**)pari_malloc((n+1)*sizeof(int*));924A[0] = NULL;925for (i = 1; i <= n; i++)926{927a = (int*)pari_malloc(deg*sizeof(int));928A[i] = a; a[0] = (i == 1 || flag);929for (j = 1; j < deg; j++) a[j] = 0;930}931return A;932}933934static void935FreeMat(int **A, long n)936{937long i;938for (i = 0; i <= n; i++)939if (A[i]) pari_free((void*)A[i]);940pari_free((void*)A);941}942943/* initialize Coeff reduction */944static int**945InitReduction(long d, long deg)946{947long j;948pari_sp av = avma;949int **A;950GEN polmod, pol;951952A = (int**)pari_malloc(deg*sizeof(int*));953pol = polcyclo(d, 0);954for (j = 0; j < deg; j++)955{956A[j] = (int*)pari_malloc(deg*sizeof(int));957polmod = gmodulo(pol_xn(deg+j, 0), pol);958Polmod2Coeff(A[j], polmod, deg);959}960961set_avma(av); return A;962}963964#if 0965void966pan(int **an, long n, long deg)967{968long i,j;969for (i = 1; i <= n; i++)970{971err_printf("n = %ld: ",i);972for (j = 0; j < deg; j++) err_printf("%d ",an[i][j]);973err_printf("\n");974}975}976#endif977978/* returns 0 if c is zero, 1 otherwise. */979static int980IsZero(int* c, long deg)981{982long i;983for (i = 0; i < deg; i++)984if (c[i]) return 0;985return 1;986}987988/* set c0 <-- c0 * c1 */989static void990MulCoeff(int *c0, int* c1, int** reduc, long deg)991{992long i,j;993int c, *T;994995if (IsZero(c0,deg)) return;996997T = (int*)new_chunk(2*deg);998for (i = 0; i < 2*deg; i++)999{1000c = 0;1001for (j = 0; j <= i; j++)1002if (j < deg && j > i - deg) c += c0[j] * c1[i-j];1003T[i] = c;1004}1005for (i = 0; i < deg; i++)1006{1007c = T[i];1008for (j = 0; j < deg; j++) c += reduc[j][i] * T[deg+j];1009c0[i] = c;1010}1011}10121013/* c0 <- c0 + c1 * c2 */1014static void1015AddMulCoeff(int *c0, int *c1, int* c2, int** reduc, long deg)1016{1017long i, j;1018pari_sp av;1019int c, *t;10201021if (IsZero(c2,deg)) return;1022if (!c1) /* c1 == 1 */1023{1024for (i = 0; i < deg; i++) c0[i] += c2[i];1025return;1026}1027av = avma;1028t = (int*)new_chunk(2*deg); /* = c1 * c2, not reduced */1029for (i = 0; i < 2*deg; i++)1030{1031c = 0;1032for (j = 0; j <= i; j++)1033if (j < deg && j > i - deg) c += c1[j] * c2[i-j];1034t[i] = c;1035}1036for (i = 0; i < deg; i++)1037{1038c = t[i];1039for (j = 0; j < deg; j++) c += reduc[j][i] * t[deg+j];1040c0[i] += c;1041}1042set_avma(av);1043}10441045/* evaluate the Coeff. No Garbage collector */1046static GEN1047EvalCoeff(GEN z, int* c, long deg)1048{1049long i,j;1050GEN e, r;10511052if (!c) return gen_0;1053#if 01054/* standard Horner */1055e = stoi(c[deg - 1]);1056for (i = deg - 2; i >= 0; i--)1057e = gadd(stoi(c[i]), gmul(z, e));1058#else1059/* specific attention to sparse polynomials */1060e = NULL;1061for (i = deg-1; i >=0; i=j-1)1062{1063for (j=i; c[j] == 0; j--)1064if (j==0)1065{1066if (!e) return NULL;1067if (i!=j) z = gpowgs(z,i-j+1);1068return gmul(e,z);1069}1070if (e)1071{1072r = (i==j)? z: gpowgs(z,i-j+1);1073e = gadd(gmul(e,r), stoi(c[j]));1074}1075else1076e = stoi(c[j]);1077}1078#endif1079return e;1080}10811082/* copy the n * (m+1) array matan */1083static void1084CopyCoeff(int** a, int** a2, long n, long m)1085{1086long i,j;10871088for (i = 1; i <= n; i++)1089{1090int *b = a[i], *b2 = a2[i];1091for (j = 0; j < m; j++) b2[j] = b[j];1092}1093}10941095static void1096an_AddMul(int **an,int **an2, long np, long n, long deg, GEN chi, int **reduc)1097{1098GEN chi2 = chi;1099long q, qk, k;1100int *c, *c2 = (int*)new_chunk(deg);11011102CopyCoeff(an, an2, n/np, deg);1103for (q=np;;)1104{1105if (gequal1(chi2)) c = NULL; else { Polmod2Coeff(c2, chi2, deg); c = c2; }1106for(k = 1, qk = q; qk <= n; k++, qk += q)1107AddMulCoeff(an[qk], c, an2[k], reduc, deg);1108if (! (q = umuluu_le(q,np, n)) ) break;11091110chi2 = gmul(chi2, chi);1111}1112}11131114/* correct the coefficients an(chi) according with diff(chi) in place */1115static void1116CorrectCoeff(GEN dtcr, int** an, int** reduc, long n, long deg)1117{1118pari_sp av = avma;1119long lg, j;1120pari_sp av1;1121int **an2;1122GEN bnrc, diff;1123CHI_t C;11241125diff = ch_diff(dtcr); lg = lg(diff) - 1;1126if (!lg) return;11271128if (DEBUGLEVEL>2) err_printf("diff(CHI) = %Ps", diff);1129bnrc = ch_bnr(dtcr);1130init_CHI_alg(&C, ch_CHI0(dtcr));11311132an2 = InitMatAn(n, deg, 0);1133av1 = avma;1134for (j = 1; j <= lg; j++)1135{1136GEN pr = gel(diff,j);1137long Np = upr_norm(pr);1138GEN chi = CHI_eval(&C, isprincipalray(bnrc, pr));1139an_AddMul(an,an2,Np,n,deg,chi,reduc);1140set_avma(av1);1141}1142FreeMat(an2, n); set_avma(av);1143}11441145/* compute the coefficients an in the general case */1146static int**1147ComputeCoeff(GEN dtcr, LISTray *R, long n, long deg)1148{1149pari_sp av = avma, av2;1150long i, l;1151int **an, **reduc, **an2;1152GEN L;1153CHI_t C;11541155init_CHI_alg(&C, ch_CHI(dtcr));1156an = InitMatAn(n, deg, 0);1157an2 = InitMatAn(n, deg, 0);1158reduc = InitReduction(C.ord, deg);1159av2 = avma;11601161L = R->L1; l = lg(L);1162for (i=1; i<l; i++, set_avma(av2))1163{1164long np = L[i];1165GEN chi = CHI_eval(&C, gel(R->L1ray,i));1166an_AddMul(an,an2,np,n,deg,chi,reduc);1167}1168FreeMat(an2, n);11691170CorrectCoeff(dtcr, an, reduc, n, deg);1171FreeMat(reduc, deg-1);1172set_avma(av); return an;1173}11741175/********************************************************************/1176/* 5th part: compute L-functions at s=1 */1177/********************************************************************/1178static void1179deg11(LISTray *R, long p, GEN bnr, GEN pr) {1180GEN z = isprincipalray(bnr, pr);1181vecsmalltrunc_append(R->L1, p);1182vectrunc_append(R->L1ray, z);1183}1184static void1185deg12(LISTray *R, long p, GEN bnr, GEN Lpr) {1186GEN z = isprincipalray(bnr, gel(Lpr,1));1187vecsmalltrunc_append(R->L11, p);1188vectrunc_append(R->L11ray, z);1189}1190static void1191deg0(LISTray *R, long p) { vecsmalltrunc_append(R->L0, p); }1192static void1193deg2(LISTray *R, long p) { vecsmalltrunc_append(R->L2, p); }11941195static void1196InitPrimesQuad(GEN bnr, ulong N0, LISTray *R)1197{1198pari_sp av = avma;1199GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1);1200long p,i,l, condZ = itos(gcoeff(cond,1,1)), contZ = itos(content(cond));1201GEN prime, Lpr, nf = bnf_get_nf(bnf), dk = nf_get_disc(nf);1202forprime_t T;12031204l = 1 + primepi_upper_bound(N0);1205R->L0 = vecsmalltrunc_init(l);1206R->L2 = vecsmalltrunc_init(l); R->condZ = condZ;1207R->L1 = vecsmalltrunc_init(l); R->L1ray = vectrunc_init(l);1208R->L11= vecsmalltrunc_init(l); R->L11ray= vectrunc_init(l);1209prime = utoipos(2);1210u_forprime_init(&T, 2, N0);1211while ( (p = u_forprime_next(&T)) )1212{1213prime[2] = p;1214switch (kroiu(dk, p))1215{1216case -1: /* inert */1217if (condZ % p == 0) deg0(R,p); else deg2(R,p);1218break;1219case 1: /* split */1220Lpr = idealprimedec(nf, prime);1221if (condZ % p != 0) deg12(R, p, bnr, Lpr);1222else if (contZ % p == 0) deg0(R,p);1223else1224{1225GEN pr = idealval(nf, cond, gel(Lpr,1))? gel(Lpr,2): gel(Lpr,1);1226deg11(R, p, bnr, pr);1227}1228break;1229default: /* ramified */1230if (condZ % p == 0)1231deg0(R,p);1232else1233deg11(R, p, bnr, idealprimedec_galois(nf,prime));1234break;1235}1236}1237/* precompute isprincipalray(x), x in Z */1238R->rayZ = cgetg(condZ, t_VEC);1239for (i=1; i<condZ; i++)1240gel(R->rayZ,i) = (ugcd(i,condZ) == 1)? isprincipalray(bnr, utoipos(i)): gen_0;1241gerepileall(av, 7, &(R->L0), &(R->L2), &(R->rayZ),1242&(R->L1), &(R->L1ray), &(R->L11), &(R->L11ray) );1243}12441245static void1246InitPrimes(GEN bnr, ulong N0, LISTray *R)1247{1248GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1);1249long p, l, condZ, N = lg(cond)-1;1250GEN DL, prime, BOUND, nf = bnf_get_nf(bnf);1251forprime_t T;12521253R->condZ = condZ = itos(gcoeff(cond,1,1));1254l = primepi_upper_bound(N0) * N;1255DL = cgetg(N+1, t_VEC);1256R->L1 = vecsmalltrunc_init(l);1257R->L1ray = vectrunc_init(l);1258u_forprime_init(&T, 2, N0);1259prime = utoipos(2);1260BOUND = utoi(N0);1261while ( (p = u_forprime_next(&T)) )1262{1263pari_sp av = avma;1264long j, k, lP;1265GEN P;1266prime[2] = p;1267if (DEBUGLEVEL>1 && (p & 2047) == 1) err_printf("%ld ", p);1268P = idealprimedec_limit_norm(nf, prime, BOUND); lP = lg(P);1269for (j = 1; j < lP; j++)1270{1271GEN pr = gel(P,j), dl = NULL;1272if (condZ % p || !idealval(nf, cond, pr))1273{1274dl = gclone( isprincipalray(bnr, pr) );1275vecsmalltrunc_append(R->L1, upowuu(p, pr_get_f(pr)));1276}1277gel(DL,j) = dl;1278}1279set_avma(av);1280for (k = 1; k < j; k++)1281{1282if (!DL[k]) continue;1283vectrunc_append(R->L1ray, ZC_copy(gel(DL,k)));1284gunclone(gel(DL,k));1285}1286}1287}12881289static GEN /* cf polcoef */1290_sercoeff(GEN x, long n)1291{1292long i = n - valp(x);1293return (i < 0)? gen_0: gel(x,i+2);1294}12951296static void1297affect_coeff(GEN q, long n, GEN y, long t)1298{1299GEN x = _sercoeff(q,-n);1300if (x == gen_0) gel(y,n) = NULL;1301else { affgr(x, gel(y,n)); shiftr_inplace(gel(y,n), t); }1302}1303/* (x-i)(x-(i+1)) */1304static GEN1305d2(long i) { return deg2pol_shallow(gen_1, utoineg(2*i+1), muluu(i,i+1), 0); }1306/* x-i */1307static GEN1308d1(long i) { return deg1pol_shallow(gen_1, stoi(-i), 0); }13091310typedef struct {1311GEN c1, aij, bij, cS, cT, powracpi;1312long i0, a,b,c, r, rc1, rc2;1313} ST_t;13141315/* compute the principal part at the integers s = 0, -1, -2, ..., -i01316* of Gamma((s+1)/2)^a Gamma(s/2)^b Gamma(s)^c / (s - z) with z = 0 and 1 */1317static void1318ppgamma(ST_t *T, long prec)1319{1320GEN G, G1, G2, A, E, O, x, sqpi, aij, bij;1321long c = T->c, r = T->r, i0 = T->i0, i, j, s, t, dx;1322pari_sp av;13231324T->aij = aij = cgetg(i0+1, t_VEC);1325T->bij = bij = cgetg(i0+1, t_VEC);1326for (i = 1; i <= i0; i++)1327{1328GEN p1, p2;1329gel(aij,i) = p1 = cgetg(r+1, t_VEC);1330gel(bij,i) = p2 = cgetg(r+1, t_VEC);1331for (j=1; j<=r; j++) { gel(p1,j) = cgetr(prec); gel(p2,j) = cgetr(prec); }1332}1333av = avma; x = pol_x(0);1334sqpi = sqrtr_abs(mppi(prec)); /* Gamma(1/2) */13351336G1 = gexp(integser(psi1series(r-1, 0, prec)), prec); /* Gamma(1 + x) */1337G = shallowcopy(G1); setvalp(G,-1); /* Gamma(x) */13381339/* expansion of log(Gamma(u) / Gamma(1/2)) at u = 1/2 */1340G2 = cgetg(r+2, t_SER);1341G2[1] = evalsigne(1) | _evalvalp(1) | evalvarn(0);1342gel(G2,2) = gneg(gadd(gmul2n(mplog2(prec), 1), mpeuler(prec)));1343for (i = 1; i < r; i++) gel(G2,i+2) = mulri(gel(G1,i+2), int2um1(i));1344G2 = gmul(sqpi, gexp(G2, prec)); /* Gamma(1/2 + x) */13451346/* We simplify to get one of the following two expressions1347* if (b > a) : sqrt(Pi)^a 2^{a-au} Gamma(u)^{a+c} Gamma( u/2 )^{|b-a|}1348* if (b <= a): sqrt(Pi)^b 2^{b-bu} Gamma(u)^{b+c} Gamma((u+1)/2)^{|b-a|} */1349if (T->b > T->a)1350{1351t = T->a; s = T->b; dx = 1;1352E = ser_unscale(G, ghalf);1353O = gmul2n(gdiv(ser_unscale(G2, ghalf), d1(1)), 1); /* Gamma((x-1)/2) */1354}1355else1356{1357t = T->b; s = T->a; dx = 0;1358E = ser_unscale(G2, ghalf);1359O = ser_unscale(G, ghalf);1360}1361/* (sqrt(Pi) 2^{1-x})^t Gamma(x)^{t+c} */1362A = gmul(gmul(powru(gmul2n(sqpi,1), t), gpowgs(G, t+c)),1363gpow(gen_2, RgX_to_ser(gmulgs(x,-t), r+2), prec));1364/* A * Gamma((x - dx + 1)/2)^{s-t} */1365E = gmul(A, gpowgs(E, s-t));1366/* A * Gamma((x - dx)/2)^{s-t} */1367O = gdiv(gmul(A, gpowgs(O, s-t)), gpowgs(gsubgs(x, 1), t+c));1368for (i = 0; i < i0/2; i++)1369{1370GEN p1, q1, A1 = gel(aij,2*i+1), B1 = gel(bij,2*i+1);1371GEN p2, q2, A2 = gel(aij,2*i+2), B2 = gel(bij,2*i+2);1372long t1 = i * (s+t), t2 = t1 + t;13731374p1 = gdiv(E, d1(2*i));1375q1 = gdiv(E, d1(2*i+1));1376p2 = gdiv(O, d1(2*i+1));1377q2 = gdiv(O, d1(2*i+2));1378for (j = 1; j <= r; j++)1379{1380affect_coeff(p1, j, A1, t1); affect_coeff(q1, j, B1, t1);1381affect_coeff(p2, j, A2, t2); affect_coeff(q2, j, B2, t2);1382}1383E = gdiv(E, gmul(gpowgs(d1(2*i+1+dx), s-t), gpowgs(d2(2*i+1), t+c)));1384O = gdiv(O, gmul(gpowgs(d1(2*i+2+dx), s-t), gpowgs(d2(2*i+2), t+c)));1385}1386set_avma(av);1387}13881389/* chi != 1. Return L(1, chi) if fl & 1, else [r, c] where L(s, chi) ~ c s^r1390* at s = 0. */1391static GEN1392GetValue(GEN dtcr, GEN W, GEN S, GEN T, long fl, long prec)1393{1394GEN cf, z;1395long q, b, c, r;1396int isreal = (ch_deg(dtcr) <= 2);13971398ch_get3(dtcr, &q, &b, &c);1399if (fl & 1)1400{ /* S(chi) + W(chi).T(chi)) / (C(chi) sqrt(Pi)^{r1 - q}) */1401cf = gmul(ch_C(dtcr), powruhalf(mppi(prec), b));14021403z = gadd(S, gmul(W, T));1404if (isreal) z = real_i(z);1405z = gdiv(z, cf);1406if (fl & 2) z = gmul(z, AChi(dtcr, &r, 1, prec));1407}1408else1409{ /* (W(chi).S(conj(chi)) + T(chi)) / (sqrt(Pi)^q 2^{r1 - q}) */1410cf = gmul2n(powruhalf(mppi(prec), q), b);14111412z = gadd(gmul(W, conj_i(S)), conj_i(T));1413if (isreal) z = real_i(z);1414z = gdiv(z, cf); r = 0;1415if (fl & 2) z = gmul(z, AChi(dtcr, &r, 0, prec));1416z = mkvec2(utoi(b + c + r), z);1417}1418return z;1419}14201421/* return the order and the first nonzero term of L(s, chi0)1422at s = 0. If flag != 0, adjust the value to get L_S(s, chi0). */1423static GEN1424GetValue1(GEN bnr, long flag, long prec)1425{1426GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf);1427GEN h = bnf_get_no(bnf), R = bnf_get_reg(bnf);1428GEN c = gdivgs(mpmul(h, R), -bnf_get_tuN(bnf));1429long r = lg(nf_get_roots(nf)) - 2; /* r1 + r2 - 1 */;1430if (flag)1431{1432GEN diff = divcond(bnr);1433long i, l;1434l = lg(diff) - 1; r += l;1435for (i = 1; i <= l; i++) c = gmul(c, glog(pr_norm(gel(diff,i)), prec));1436}1437return mkvec2(utoi(r), c);1438}14391440/********************************************************************/1441/* 6th part: recover the coefficients */1442/********************************************************************/1443static long1444TestOne(GEN plg, RC_data *d)1445{1446long j, v = d->v;1447GEN z = gsub(d->beta, gel(plg,v));1448if (expo(z) >= d->G) return 0;1449for (j = 1; j < lg(plg); j++)1450if (j != v && mpcmp(d->B, mpabs_shallow(gel(plg,j))) < 0) return 0;1451return 1;1452}14531454static GEN1455chk_reccoeff_init(FP_chk_fun *chk, GEN r, GEN mat)1456{1457RC_data *d = (RC_data*)chk->data;1458(void)r; d->U = mat; return d->nB;1459}14601461static GEN1462chk_reccoeff(void *data, GEN x)1463{1464RC_data *d = (RC_data*)data;1465GEN v = gmul(d->U, x), z = gel(v,1);14661467if (!gequal1(z)) return NULL;1468*++v = evaltyp(t_COL) | evallg( lg(d->M) );1469if (TestOne(gmul(d->M, v), d)) return v;1470return NULL;1471}14721473/* Using Cohen's method */1474static GEN1475RecCoeff3(GEN nf, RC_data *d, long prec)1476{1477GEN A, M, nB, cand, p1, B2, C2, tB, beta2, nf2, Bd;1478GEN beta = d->beta, B = d->B;1479long N = d->N, v = d->v, e, BIG;1480long i, j, k, ct = 0, prec2;1481FP_chk_fun chk = { &chk_reccoeff, &chk_reccoeff_init, NULL, NULL, 0 };1482chk.data = (void*)d;14831484d->G = minss(-10, -prec2nbits(prec) >> 4);1485BIG = maxss(32, -2*d->G);1486tB = sqrtnr(real2n(BIG-N,DEFAULTPREC), N-1);1487Bd = grndtoi(gmin_shallow(B, tB), &e);1488if (e > 0) return NULL; /* failure */1489Bd = addiu(Bd, 1);1490prec2 = nbits2prec( expi(Bd) + 192 );1491prec2 = maxss(precdbl(prec), prec2);1492B2 = sqri(Bd);1493C2 = shifti(B2, BIG<<1);14941495LABrcf: ct++;1496beta2 = gprec_w(beta, prec2);1497nf2 = nfnewprec_shallow(nf, prec2);1498d->M = M = nf_get_M(nf2);14991500A = cgetg(N+2, t_MAT);1501for (i = 1; i <= N+1; i++) gel(A,i) = cgetg(N+2, t_COL);15021503gcoeff(A, 1, 1) = gadd(gmul(C2, gsqr(beta2)), B2);1504for (j = 2; j <= N+1; j++)1505{1506p1 = gmul(C2, gmul(gneg_i(beta2), gcoeff(M, v, j-1)));1507gcoeff(A, 1, j) = gcoeff(A, j, 1) = p1;1508}1509for (i = 2; i <= N+1; i++)1510for (j = i; j <= N+1; j++)1511{1512p1 = gen_0;1513for (k = 1; k <= N; k++)1514{1515GEN p2 = gmul(gcoeff(M, k, j-1), gcoeff(M, k, i-1));1516if (k == v) p2 = gmul(C2, p2);1517p1 = gadd(p1,p2);1518}1519gcoeff(A, i, j) = gcoeff(A, j, i) = p1;1520}15211522nB = mului(N+1, B2);1523d->nB = nB;1524cand = fincke_pohst(A, nB, -1, prec2, &chk);15251526if (!cand)1527{1528if (ct > 3) return NULL;1529prec2 = precdbl(prec2);1530if (DEBUGLEVEL>1) pari_warn(warnprec,"RecCoeff", prec2);1531goto LABrcf;1532}15331534cand = gel(cand,1);1535if (lg(cand) == 2) return gel(cand,1);15361537if (DEBUGLEVEL>1) err_printf("RecCoeff3: no solution found!\n");1538return NULL;1539}15401541/* Using linear dependance relations */1542static GEN1543RecCoeff2(GEN nf, RC_data *d, long prec)1544{1545pari_sp av;1546GEN vec, M = nf_get_M(nf), beta = d->beta;1547long bit, min, max, lM = lg(M);15481549d->G = minss(-20, -prec2nbits(prec) >> 4);15501551vec = vec_prepend(row(M, d->v), gneg(beta));1552min = (long)prec2nbits_mul(prec, 0.75);1553max = (long)prec2nbits_mul(prec, 0.98);1554av = avma;1555for (bit = max; bit >= min; bit-=32, set_avma(av))1556{1557long e;1558GEN v = lindep_bit(vec, bit), z = gel(v,1);1559if (!signe(z)) continue;1560*++v = evaltyp(t_COL) | evallg(lM);1561v = grndtoi(gdiv(v, z), &e);1562if (e > 0) break;1563if (TestOne(RgM_RgC_mul(M, v), d)) return v;1564}1565/* failure */1566return RecCoeff3(nf,d,prec);1567}15681569/* Attempts to find a polynomial with coefficients in nf such that1570its coefficients are close to those of pol at the place v and1571less than B at all the other places */1572static GEN1573RecCoeff(GEN nf, GEN pol, long v, long prec)1574{1575long j, md, cl = degpol(pol);1576pari_sp av = avma;1577RC_data d;15781579/* if precision(pol) is too low, abort */1580for (j = 2; j <= cl+1; j++)1581{1582GEN t = gel(pol, j);1583if (prec2nbits(precision(t)) - gexpo(t) < 34) return NULL;1584}15851586md = cl/2;1587pol = leafcopy(pol);15881589d.N = nf_get_degree(nf);1590d.v = v;15911592for (j = 1; j <= cl; j++)1593{ /* start with the coefficients in the middle,1594since they are the harder to recognize! */1595long cf = md + (j%2? j/2: -j/2);1596GEN t, bound = shifti(binomial(utoipos(cl), cf), cl-cf);15971598if (DEBUGLEVEL>1) err_printf("RecCoeff (cf = %ld, B = %Ps)\n", cf, bound);1599d.beta = real_i( gel(pol,cf+2) );1600d.B = bound;1601if (! (t = RecCoeff2(nf, &d, prec)) ) return NULL;1602gel(pol, cf+2) = coltoalg(nf,t);1603}1604gel(pol,cl+2) = gen_1;1605return gerepilecopy(av, pol);1606}16071608/* an[q * i] *= chi for all (i,p)=1 */1609static void1610an_mul(int **an, long p, long q, long n, long deg, GEN chi, int **reduc)1611{1612pari_sp av;1613long c,i;1614int *T;16151616if (gequal1(chi)) return;1617av = avma;1618T = (int*)new_chunk(deg); Polmod2Coeff(T,chi, deg);1619for (c = 1, i = q; i <= n; i += q, c++)1620if (c == p) c = 0; else MulCoeff(an[i], T, reduc, deg);1621set_avma(av);1622}1623/* an[q * i] = 0 for all (i,p)=1 */1624static void1625an_set0_coprime(int **an, long p, long q, long n, long deg)1626{1627long c,i;1628for (c = 1, i = q; i <= n; i += q, c++)1629if (c == p) c = 0; else _0toCoeff(an[i], deg);1630}1631/* an[q * i] = 0 for all i */1632static void1633an_set0(int **an, long p, long n, long deg)1634{1635long i;1636for (i = p; i <= n; i += p) _0toCoeff(an[i], deg);1637}16381639/* compute the coefficients an for the quadratic case */1640static int**1641computean(GEN dtcr, LISTray *R, long n, long deg)1642{1643pari_sp av = avma, av2;1644long i, p, q, condZ, l;1645int **an, **reduc;1646GEN L, chi, chi1;1647CHI_t C;16481649init_CHI_alg(&C, ch_CHI(dtcr));1650condZ= R->condZ;16511652an = InitMatAn(n, deg, 1);1653reduc = InitReduction(C.ord, deg);1654av2 = avma;16551656/* all pr | p divide cond */1657L = R->L0; l = lg(L);1658for (i=1; i<l; i++) an_set0(an,L[i],n,deg);16591660/* 1 prime of degree 2 */1661L = R->L2; l = lg(L);1662for (i=1; i<l; i++, set_avma(av2))1663{1664p = L[i];1665if (condZ == 1) chi = C.val[0]; /* 1 */1666else chi = CHI_eval(&C, gel(R->rayZ, p%condZ));1667chi1 = chi;1668for (q=p;;)1669{1670an_set0_coprime(an, p,q,n,deg); /* v_p(q) odd */1671if (! (q = umuluu_le(q,p, n)) ) break;16721673an_mul(an,p,q,n,deg,chi,reduc);1674if (! (q = umuluu_le(q,p, n)) ) break;1675chi = gmul(chi, chi1);1676}1677}16781679/* 1 prime of degree 1 */1680L = R->L1; l = lg(L);1681for (i=1; i<l; i++, set_avma(av2))1682{1683p = L[i];1684chi = CHI_eval(&C, gel(R->L1ray,i));1685chi1 = chi;1686for(q=p;;)1687{1688an_mul(an,p,q,n,deg,chi,reduc);1689if (! (q = umuluu_le(q,p, n)) ) break;1690chi = gmul(chi, chi1);1691}1692}16931694/* 2 primes of degree 1 */1695L = R->L11; l = lg(L);1696for (i=1; i<l; i++, set_avma(av2))1697{1698GEN ray1, ray2, chi11, chi12, chi2;16991700p = L[i]; ray1 = gel(R->L11ray,i); /* use pr1 pr2 = (p) */1701if (condZ == 1)1702ray2 = ZC_neg(ray1);1703else1704ray2 = ZC_sub(gel(R->rayZ, p%condZ), ray1);1705chi11 = CHI_eval(&C, ray1);1706chi12 = CHI_eval(&C, ray2);17071708chi1 = gadd(chi11, chi12);1709chi2 = chi12;1710for(q=p;;)1711{1712an_mul(an,p,q,n,deg,chi1,reduc);1713if (! (q = umuluu_le(q,p, n)) ) break;1714chi2 = gmul(chi2, chi12);1715chi1 = gadd(chi2, gmul(chi1, chi11));1716}1717}17181719CorrectCoeff(dtcr, an, reduc, n, deg);1720FreeMat(reduc, deg-1);1721set_avma(av); return an;1722}17231724/* return the vector of A^i/i for i = 1...n */1725static GEN1726mpvecpowdiv(GEN A, long n)1727{1728pari_sp av = avma;1729long i;1730GEN v = powersr(A, n);1731GEN w = cgetg(n+1, t_VEC);1732gel(w,1) = rcopy(gel(v,2));1733for (i=2; i<=n; i++) gel(w,i) = divru(gel(v,i+1), i);1734return gerepileupto(av, w);1735}17361737static void GetST0(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec);1738/* allocate memory for GetST answer */1739static void1740ST_alloc(GEN *pS, GEN *pT, long l, long prec)1741{1742long j;1743*pS = cgetg(l, t_VEC);1744*pT = cgetg(l, t_VEC);1745for (j = 1; j < l; j++)1746{1747gel(*pS,j) = cgetc(prec);1748gel(*pT,j) = cgetc(prec);1749}1750}17511752/* compute S and T for the quadratic case. The following cases are:1753* 1) bnr complex;1754* 2) bnr real and no infinite place divide cond_chi (TODO);1755* 3) bnr real and one infinite place divide cond_chi;1756* 4) bnr real and both infinite places divide cond_chi (TODO) */1757static void1758QuadGetST(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec)1759{1760pari_sp av, av1, av2;1761long ncond, n, j, k, n0;1762GEN vChar = gel(CR,1), dataCR = gel(CR,2), S, T, an, cs, N0, C;1763LISTray LIST;17641765/* initializations */1766ST_alloc(pS, pT, lg(dataCR), prec); T = *pT; S = *pS;1767av = avma;1768ncond = lg(vChar)-1;1769C = cgetg(ncond+1, t_VEC);1770N0 = cgetg(ncond+1, t_VECSMALL);1771cs = cgetg(ncond+1, t_VECSMALL);1772n0 = 0;1773for (j = 1; j <= ncond; j++)1774{1775GEN dtcr = gel(dataCR, mael(vChar,j,1)), c = ch_C(dtcr);1776long r1, r2;17771778gel(C,j) = c;1779nf_get_sign(bnr_get_nf(ch_bnr(dtcr)), &r1, &r2);1780if (r1 == 2) /* real quadratic */1781{1782cs[j] = 2 + ch_q(dtcr);1783if (cs[j] == 2 || cs[j] == 4)1784{ /* NOT IMPLEMENTED YET */1785GetST0(bnr, pS, pT, CR, prec);1786return;1787}1788/* FIXME: is this value of N0 correct for the general case ? */1789N0[j] = (long)prec2nbits_mul(prec, 0.35 * gtodouble(c));1790}1791else /* complex quadratic */1792{1793cs[j] = 1;1794N0[j] = (long)prec2nbits_mul(prec, 0.7 * gtodouble(c));1795}1796if (n0 < N0[j]) n0 = N0[j];1797}1798if (DEBUGLEVEL>1) err_printf("N0 = %ld\n", n0);1799InitPrimesQuad(bnr, n0, &LIST);18001801av1 = avma;1802/* loop over conductors */1803for (j = 1; j <= ncond; j++)1804{1805GEN c0 = gel(C,j), c1 = divur(1, c0), c2 = divur(2, c0);1806GEN ec1 = mpexp(c1), ec2 = mpexp(c2), LChar = gel(vChar,j);1807GEN vf0, vf1, cf0, cf1;1808const long nChar = lg(LChar)-1, NN = N0[j];18091810if (DEBUGLEVEL>1)1811err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", j,ncond,NN);1812if (realprec(ec1) > prec) ec1 = rtor(ec1, prec);1813if (realprec(ec2) > prec) ec2 = rtor(ec2, prec);1814switch(cs[j])1815{1816case 1:1817cf0 = gen_1;1818cf1 = c0;1819vf0 = mpveceint1(rtor(c1, prec), ec1, NN);1820vf1 = mpvecpowdiv(invr(ec1), NN); break;18211822case 3:1823cf0 = sqrtr(mppi(prec));1824cf1 = gmul2n(cf0, 1);1825cf0 = gmul(cf0, c0);1826vf0 = mpvecpowdiv(invr(ec2), NN);1827vf1 = mpveceint1(rtor(c2, prec), ec2, NN); break;18281829default:1830cf0 = cf1 = NULL; /* FIXME: not implemented */1831vf0 = vf1 = NULL;1832}1833for (k = 1; k <= nChar; k++)1834{1835long u = LChar[k], d, c;1836GEN dtcr = gel(dataCR, u), z, s, t;1837int **matan;18381839if (!ch_comp(dtcr)) continue;1840if (DEBUGLEVEL>1) err_printf("\tchar no: %ld (%ld/%ld)\n", u,k,nChar);1841d = ch_phideg(dtcr);1842z = gel(ch_CHI(dtcr), 2); s = t = gen_0; av2 = avma;1843matan = computean(gel(dataCR,u), &LIST, NN, d);1844for (n = 1, c = 0; n <= NN; n++)1845if ((an = EvalCoeff(z, matan[n], d)))1846{1847s = gadd(s, gmul(an, gel(vf0,n)));1848t = gadd(t, gmul(an, gel(vf1,n)));1849if (++c == 256) { gerepileall(av2,2, &s,&t); c = 0; }1850}1851gaffect(gmul(cf0, s), gel(S,u));1852gaffect(gmul(cf1, conj_i(t)), gel(T,u));1853FreeMat(matan,NN); set_avma(av2);1854}1855if (DEBUGLEVEL>1) err_printf("\n");1856set_avma(av1);1857}1858set_avma(av);1859}18601861/* s += t*u. All 3 of them t_REAL, except we allow s or u = NULL (for 0) */1862static GEN1863_addmulrr(GEN s, GEN t, GEN u)1864{1865if (u)1866{1867GEN v = mulrr(t, u);1868return s? addrr(s, v): v;1869}1870return s;1871}1872/* s += t. Both real, except we allow s or t = NULL (for exact 0) */1873static GEN1874_addrr(GEN s, GEN t)1875{ return t? (s? addrr(s, t): t) : s; }18761877/* S & T for the general case. This is time-critical: optimize */1878static void1879get_cS_cT(ST_t *T, long n)1880{1881pari_sp av;1882GEN csurn, nsurc, lncsurn, A, B, s, t, Z, aij, bij;1883long i, j, r, i0;18841885if (gel(T->cS,n)) return;18861887av = avma;1888aij = T->aij; i0= T->i0;1889bij = T->bij; r = T->r;1890Z = cgetg(r+1, t_VEC);1891gel(Z,1) = NULL; /* unused */18921893csurn = divru(T->c1, n);1894nsurc = invr(csurn);1895lncsurn = logr_abs(csurn);18961897if (r > 1)1898{1899gel(Z,2) = lncsurn; /* r >= 2 */1900for (i = 3; i <= r; i++)1901gel(Z,i) = divru(mulrr(gel(Z,i-1), lncsurn), i-1);1902/* Z[i] = ln^(i-1)(c1/n) / (i-1)! */1903}19041905/* i = i0 */1906A = gel(aij,i0); t = _addrr(NULL, gel(A,1));1907B = gel(bij,i0); s = _addrr(NULL, gel(B,1));1908for (j = 2; j <= r; j++)1909{1910s = _addmulrr(s, gel(Z,j),gel(B,j));1911t = _addmulrr(t, gel(Z,j),gel(A,j));1912}1913for (i = i0 - 1; i > 1; i--)1914{1915A = gel(aij,i); if (t) t = mulrr(t, nsurc);1916B = gel(bij,i); if (s) s = mulrr(s, nsurc);1917for (j = odd(i)? T->rc2: T->rc1; j > 1; j--)1918{1919s = _addmulrr(s, gel(Z,j),gel(B,j));1920t = _addmulrr(t, gel(Z,j),gel(A,j));1921}1922s = _addrr(s, gel(B,1));1923t = _addrr(t, gel(A,1));1924}1925/* i = 1 */1926A = gel(aij,1); if (t) t = mulrr(t, nsurc);1927B = gel(bij,1); if (s) s = mulrr(s, nsurc);1928s = _addrr(s, gel(B,1));1929t = _addrr(t, gel(A,1));1930for (j = 2; j <= r; j++)1931{1932s = _addmulrr(s, gel(Z,j),gel(B,j));1933t = _addmulrr(t, gel(Z,j),gel(A,j));1934}1935s = _addrr(s, T->b? mulrr(csurn, gel(T->powracpi,T->b+1)): csurn);1936if (!s) s = gen_0;1937if (!t) t = gen_0;1938gel(T->cS,n) = gclone(s);1939gel(T->cT,n) = gclone(t); set_avma(av);1940}19411942static void1943clear_cScT(ST_t *T, long N)1944{1945GEN cS = T->cS, cT = T->cT;1946long i;1947for (i=1; i<=N; i++)1948if (cS[i]) {1949gunclone(gel(cS,i));1950gunclone(gel(cT,i)); gel(cS,i) = gel(cT,i) = NULL;1951}1952}19531954static void1955init_cScT(ST_t *T, GEN dtcr, long N, long prec)1956{1957ch_get3(dtcr, &T->a, &T->b, &T->c);1958T->rc1 = T->a + T->c;1959T->rc2 = T->b + T->c;1960T->r = maxss(T->rc2+1, T->rc1); /* >= 2 */1961ppgamma(T, prec);1962clear_cScT(T, N);1963}19641965/* return a t_REAL */1966static GEN1967zeta_get_limx(long r1, long r2, long bit)1968{1969pari_sp av = avma;1970GEN p1, p2, c0, c1, A0;1971long r = r1 + r2, N = r + r2;19721973/* c1 = N 2^(-2r2 / N) */1974c1 = mulrs(powrfrac(real2n(1, DEFAULTPREC), -2*r2, N), N);19751976p1 = powru(Pi2n(1, DEFAULTPREC), r - 1);1977p2 = mulir(powuu(N,r), p1); shiftr_inplace(p2, -r2);1978c0 = sqrtr( divrr(p2, powru(c1, r+1)) );19791980A0 = logr_abs( gmul2n(c0, bit) ); p2 = divrr(A0, c1);1981p1 = divrr(mulur(N*(r+1), logr_abs(p2)), addsr(2*(r+1), gmul2n(A0,2)));1982return gerepileuptoleaf(av, divrr(addrs(p1, 1), powruhalf(p2, N)));1983}1984/* N_0 = floor( C_K / limx ). Large */1985static long1986zeta_get_N0(GEN C, GEN limx)1987{1988long e;1989pari_sp av = avma;1990GEN z = gcvtoi(gdiv(C, limx), &e); /* avoid truncation error */1991if (e >= 0 || is_bigint(z))1992pari_err_OVERFLOW("zeta_get_N0 [need too many primes]");1993return gc_long(av, itos(z));1994}19951996static GEN1997eval_i(long r1, long r2, GEN limx, long i)1998{1999GEN t = powru(limx, i);2000if (!r1) t = mulrr(t, powru(mpfactr(i , DEFAULTPREC), r2));2001else if (!r2) t = mulrr(t, powru(mpfactr(i/2, DEFAULTPREC), r1));2002else {2003GEN u1 = mpfactr(i/2, DEFAULTPREC);2004GEN u2 = mpfactr(i, DEFAULTPREC);2005if (r1 == r2) t = mulrr(t, powru(mulrr(u1,u2), r1));2006else t = mulrr(t, mulrr(powru(u1,r1), powru(u2,r2)));2007}2008return t;2009}20102011/* "small" even i such that limx^i ( (i\2)! )^r1 ( i! )^r2 > B. */2012static long2013get_i0(long r1, long r2, GEN B, GEN limx)2014{2015long imin = 1, imax = 1400;2016while (mpcmp(eval_i(r1,r2,limx, imax), B) < 0) { imin = imax; imax *= 2; }2017while(imax - imin >= 4)2018{2019long m = (imax + imin) >> 1;2020if (mpcmp(eval_i(r1,r2,limx, m), B) >= 0) imax = m; else imin = m;2021}2022return imax & ~1; /* make it even */2023}2024/* limx = zeta_get_limx(r1, r2, bit), a t_REAL */2025static long2026zeta_get_i0(long r1, long r2, long bit, GEN limx)2027{2028pari_sp av = avma;2029GEN B = gmul(sqrtr( divrr(powrs(mppi(DEFAULTPREC), r2-3), limx) ),2030gmul2n(powuu(5, r1), bit + r2));2031return gc_long(av, get_i0(r1, r2, B, limx));2032}20332034static void2035GetST0(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec)2036{2037pari_sp av, av1, av2;2038long n, j, k, jc, n0, prec2, i0, r1, r2, ncond;2039GEN nf = bnr_get_nf(bnr);2040GEN vChar = gel(CR,1), dataCR = gel(CR,2), N0, C, an, limx, S, T;2041LISTray LIST;2042ST_t cScT;20432044ST_alloc(pS, pT, lg(dataCR), prec); T = *pT; S = *pS;2045av = avma;2046nf_get_sign(nf,&r1,&r2);2047ncond = lg(vChar)-1;2048C = cgetg(ncond+1, t_VEC);2049N0 = cgetg(ncond+1, t_VECSMALL);2050n0 = 0;2051limx = zeta_get_limx(r1, r2, prec2nbits(prec));2052for (j = 1; j <= ncond; j++)2053{2054GEN dtcr = gel(dataCR, mael(vChar,j,1)), c = ch_C(dtcr);2055gel(C,j) = c;2056N0[j] = zeta_get_N0(c, limx);2057if (n0 < N0[j]) n0 = N0[j];2058}2059cScT.i0 = i0 = zeta_get_i0(r1, r2, prec2nbits(prec), limx);2060if (DEBUGLEVEL>1) err_printf("i0 = %ld, N0 = %ld\n",i0, n0);2061InitPrimes(bnr, n0, &LIST);2062prec2 = precdbl(prec) + EXTRAPREC64;2063cScT.powracpi = powersr(sqrtr(mppi(prec2)), r1);2064cScT.cS = cgetg(n0+1, t_VEC);2065cScT.cT = cgetg(n0+1, t_VEC);2066for (j=1; j<=n0; j++) gel(cScT.cS,j) = gel(cScT.cT,j) = NULL;20672068av1 = avma;2069for (jc = 1; jc <= ncond; jc++)2070{2071GEN LChar = gel(vChar,jc);2072long nChar = lg(LChar)-1, N = N0[jc];20732074/* Can discard completely a conductor if all chars satisfy L(0,chi) = 02075* Not sure whether this is possible. */2076if (DEBUGLEVEL>1)2077err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", jc,ncond,N);20782079cScT.c1 = gel(C,jc);2080init_cScT(&cScT, gel(dataCR, LChar[1]), N, prec2);2081av2 = avma;2082for (k = 1; k <= nChar; k++)2083{2084long d, c, u = LChar[k];2085GEN dtcr = gel(dataCR, u), z, s, t;2086int **matan;20872088if (!ch_comp(dtcr)) continue;2089if (DEBUGLEVEL>1) err_printf("\tchar no: %ld (%ld/%ld)\n", u,k,nChar);2090z = gel(ch_CHI(dtcr), 2);2091d = ch_phideg(dtcr); s = t = gen_0;2092matan = ComputeCoeff(dtcr, &LIST, N, d);2093for (n = 1, c = 0; n <= N; n++)2094if ((an = EvalCoeff(z, matan[n], d)))2095{2096get_cS_cT(&cScT, n);2097s = gadd(s, gmul(an, gel(cScT.cS,n)));2098t = gadd(t, gmul(an, gel(cScT.cT,n)));2099if (++c == 256) { gerepileall(av2,2, &s,&t); c = 0; }2100}2101gaffect(s, gel(S,u));2102gaffect(conj_i(t), gel(T,u));2103FreeMat(matan, N); set_avma(av2);2104}2105if (DEBUGLEVEL>1) err_printf("\n");2106set_avma(av1);2107}2108clear_cScT(&cScT, n0);2109set_avma(av);2110}21112112static void2113GetST(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec)2114{2115if (nf_get_degree(bnr_get_nf(bnr)) == 2)2116QuadGetST(bnr, pS, pT, CR, prec);2117else2118GetST0(bnr, pS, pT, CR, prec);2119}21202121/*******************************************************************/2122/* */2123/* Class fields of real quadratic fields using Stark units */2124/* */2125/*******************************************************************/2126/* compute the Hilbert class field using genus class field theory when2127the exponent of the class group is exactly 2 (trivial group not covered) */2128/* Cf Herz, Construction of class fields, LNM 21, Theorem 1 (VII-6) */2129static GEN2130GenusFieldQuadReal(GEN disc)2131{2132long i, i0 = 0, l;2133pari_sp av = avma;2134GEN T = NULL, p0 = NULL, P;21352136P = gel(Z_factor(disc), 1);2137l = lg(P);2138for (i = 1; i < l; i++)2139{2140GEN p = gel(P,i);2141if (mod4(p) == 3) { p0 = p; i0 = i; break; }2142}2143l--; /* remove last prime */2144if (i0 == l) l--; /* ... remove p0 and last prime */2145for (i = 1; i < l; i++)2146{2147GEN p = gel(P,i), d, t;2148if (i == i0) continue;2149if (absequaliu(p, 2))2150switch (mod32(disc))2151{2152case 8: d = gen_2; break;2153case 24: d = shifti(p0, 1); break;2154default: d = p0; break;2155}2156else2157d = (mod4(p) == 1)? p: mulii(p0, p);2158t = mkpoln(3, gen_1, gen_0, negi(d)); /* x^2 - d */2159T = T? ZX_compositum_disjoint(T, t): t;2160}2161return gerepileupto(av, polredbest(T, 0));2162}2163static GEN2164GenusFieldQuadImag(GEN disc)2165{2166long i, l;2167pari_sp av = avma;2168GEN T = NULL, P;21692170P = gel(absZ_factor(disc), 1);2171l = lg(P);2172l--; /* remove last prime */2173for (i = 1; i < l; i++)2174{2175GEN p = gel(P,i), d, t;2176if (absequaliu(p, 2))2177switch (mod32(disc))2178{2179case 24: d = gen_2; break; /* disc = 8 mod 32 */2180case 8: d = gen_m2; break; /* disc =-8 mod 32 */2181default: d = gen_m1; break;2182}2183else2184d = (mod4(p) == 1)? p: negi(p);2185t = mkpoln(3, gen_1, gen_0, negi(d)); /* x^2 - d */2186T = T? ZX_compositum_disjoint(T, t): t;2187}2188return gerepileupto(av, polredbest(T, 0));2189}21902191/* if flag != 0, computes a fast and crude approximation of the result */2192static GEN2193AllStark(GEN data, long flag, long newprec)2194{2195const long BND = 300;2196long cl, i, j, cpt = 0, N, h, v, n, r1, r2, den;2197pari_sp av, av2;2198int **matan;2199GEN bnr = gel(data,1), nf = bnr_get_nf(bnr), p1, p2, S, T;2200GEN CR = gel(data,4), dataCR = gel(CR,2);2201GEN polrelnum, polrel, Lp, W, vzeta, C, cond1, L1, an;2202LISTray LIST;2203pari_timer ti;22042205nf_get_sign(nf, &r1,&r2);2206N = nf_get_degree(nf);2207cond1 = gel(bnr_get_mod(bnr), 2);22082209v = 1;2210while (gequal1(gel(cond1,v))) v++;2211cl = lg(dataCR)-1;2212h = itos(ZM_det_triangular(gel(data,2))) >> 1;22132214LABDOUB:2215if (DEBUGLEVEL) timer_start(&ti);2216av = avma;2217W = AllArtinNumbers(CR, newprec);2218if (DEBUGLEVEL) timer_printf(&ti,"Compute W");2219Lp = cgetg(cl + 1, t_VEC);2220if (!flag)2221{2222GetST(bnr, &S, &T, CR, newprec);2223if (DEBUGLEVEL) timer_printf(&ti, "S&T");2224for (i = 1; i <= cl; i++)2225{2226GEN chi = gel(dataCR, i), v = gen_0;2227if (ch_comp(chi))2228v = gel(GetValue(chi, gel(W,i), gel(S,i), gel(T,i), 2, newprec), 2);2229gel(Lp, i) = v;2230}2231}2232else2233{ /* compute a crude approximation of the result */2234C = cgetg(cl + 1, t_VEC);2235for (i = 1; i <= cl; i++) gel(C,i) = ch_C(gel(dataCR, i));2236n = zeta_get_N0(vecmax(C), zeta_get_limx(r1, r2, prec2nbits(newprec)));2237if (n > BND) n = BND;2238if (DEBUGLEVEL) err_printf("N0 in QuickPol: %ld \n", n);2239InitPrimes(bnr, n, &LIST);22402241L1 = cgetg(cl+1, t_VEC);2242/* use L(1) = sum (an / n) */2243for (i = 1; i <= cl; i++)2244{2245GEN dtcr = gel(dataCR,i);2246long d = ch_phideg(dtcr);2247matan = ComputeCoeff(dtcr, &LIST, n, d);2248av2 = avma;2249p1 = real_0(newprec); p2 = gel(ch_CHI(dtcr), 2);2250for (j = 1; j <= n; j++)2251if ( (an = EvalCoeff(p2, matan[j], d)) )2252p1 = gadd(p1, gdivgs(an, j));2253gel(L1,i) = gerepileupto(av2, p1);2254FreeMat(matan, n);2255}2256p1 = gmul2n(powruhalf(mppi(newprec), N-2), 1);22572258for (i = 1; i <= cl; i++)2259{2260long r;2261GEN WW, A = AChi(gel(dataCR,i), &r, 0, newprec);2262WW = gmul(gel(C,i), gmul(A, gel(W,i)));2263gel(Lp,i) = gdiv(gmul(WW, conj_i(gel(L1,i))), p1);2264}2265}22662267p1 = gel(data,3);2268den = flag ? h: 2*h;2269vzeta = cgetg(h + 1, t_VEC);2270for (i = 1; i <= h; i++)2271{2272GEN z = gen_0, sig = gel(p1,i);2273for (j = 1; j <= cl; j++)2274{2275GEN dtcr = gel(dataCR,j), CHI = ch_CHI(dtcr);2276GEN t = mulreal(gel(Lp,j), CharEval(CHI, sig));2277if (chi_get_deg(CHI) != 2) t = gmul2n(t, 1); /* character not real */2278z = gadd(z, t);2279}2280gel(vzeta,i) = gmul2n(gcosh(gdivgs(z,den), newprec), 1);2281}2282polrelnum = roots_to_pol(vzeta, 0);2283if (DEBUGLEVEL)2284{2285if (DEBUGLEVEL>1) {2286err_printf("polrelnum = %Ps\n", polrelnum);2287err_printf("zetavalues = %Ps\n", vzeta);2288if (!flag)2289err_printf("Checking the square-root of the Stark unit...\n");2290}2291timer_printf(&ti, "Compute %s", flag? "quickpol": "polrelnum");2292}2293if (flag) return gerepilecopy(av, polrelnum);22942295/* try to recognize this polynomial */2296polrel = RecCoeff(nf, polrelnum, v, newprec);2297if (!polrel)2298{2299for (j = 1; j <= h; j++)2300gel(vzeta,j) = gsubgs(gsqr(gel(vzeta,j)), 2);2301polrelnum = roots_to_pol(vzeta, 0);2302if (DEBUGLEVEL)2303{2304if (DEBUGLEVEL>1) {2305err_printf("It's not a square...\n");2306err_printf("polrelnum = %Ps\n", polrelnum);2307}2308timer_printf(&ti, "Compute polrelnum");2309}2310polrel = RecCoeff(nf, polrelnum, v, newprec);2311}2312if (!polrel) /* FAILED */2313{2314const long EXTRA_BITS = 64;2315long incr_pr;2316if (++cpt >= 3) pari_err_PREC( "stark (computation impossible)");2317/* estimate needed precision */2318incr_pr = prec2nbits(gprecision(polrelnum))- gexpo(polrelnum);2319if (incr_pr < 0) incr_pr = -incr_pr + EXTRA_BITS;2320newprec += nbits2extraprec(maxss(3*EXTRA_BITS, cpt*incr_pr));2321if (DEBUGLEVEL) pari_warn(warnprec, "AllStark", newprec);2322CharNewPrec(data, newprec);2323nf = bnr_get_nf(ch_bnr(gel(dataCR,1)));2324goto LABDOUB;2325}23262327if (DEBUGLEVEL) {2328if (DEBUGLEVEL>1) err_printf("polrel = %Ps\n", polrel);2329timer_printf(&ti, "Recpolnum");2330}2331return gerepilecopy(av, polrel);2332}23332334/********************************************************************/2335/* Main functions */2336/********************************************************************/2337static GEN2338bnrstark_cyclic(GEN bnr, GEN dtQ, long prec)2339{2340GEN v, vH, cyc = gel(dtQ,2), U = gel(dtQ,3), M = ZM_inv(U, NULL);2341long i, j, l = lg(M);23422343/* M = indep. generators of Cl_f/subgp, restrict to cyclic components */2344vH = cgetg(l, t_VEC);2345for (i = j = 1; i < l; i++)2346{2347if (is_pm1(gel(cyc,i))) break;2348gel(vH, j++) = ZM_hnfmodid(vecsplice(M,i), cyc);2349}2350setlg(vH, j); v = cgetg(l, t_VEC);2351for (i = 1; i < j; i++) gel(v,i) = bnrstark(bnr, gel(vH,i), prec);2352return v;2353}2354GEN2355bnrstark(GEN bnr, GEN subgrp, long prec)2356{2357long newprec;2358pari_sp av = avma;2359GEN nf, data, dtQ;23602361/* check the bnr */2362checkbnr(bnr); nf = bnr_get_nf(bnr);2363if (nf_get_degree(nf) == 1) return galoissubcyclo(bnr, subgrp, 0, 0);2364if (!nf_get_varn(nf))2365pari_err_PRIORITY("bnrstark", nf_get_pol(nf), "=", 0);2366if (nf_get_r2(nf)) pari_err_DOMAIN("bnrstark", "r2", "!=", gen_0, nf);23672368/* compute bnr(conductor) */2369bnr_subgroup_sanitize(&bnr, &subgrp);2370if (gequal1(ZM_det_triangular(subgrp))) { set_avma(av); return pol_x(0); }23712372/* check the class field */2373if (!gequal0(gel(bnr_get_mod(bnr), 2)))2374pari_err_DOMAIN("bnrstark", "r2(class field)", "!=", gen_0, bnr);23752376/* find a suitable extension N */2377dtQ = InitQuotient(subgrp);2378data = FindModulus(bnr, dtQ, &newprec);2379if (!data) return gerepileupto(av, bnrstark_cyclic(bnr, dtQ, prec));2380if (DEBUGLEVEL>1 && newprec > prec)2381err_printf("new precision: %ld\n", newprec);2382return gerepileupto(av, AllStark(data, 0, newprec));2383}23842385/* For each character of Cl(bnr)/subgp, compute L(1, chi) (or equivalently2386* the first nonzero term c(chi) of the expansion at s = 0).2387* If flag & 1: compute the value at s = 1 (for nontrivial characters),2388* else compute the term c(chi) and return [r(chi), c(chi)] where r(chi) is2389* the order of L(s, chi) at s = 0.2390* If flag & 2: compute the value of the L-function L_S(s, chi) where S is the2391* set of places dividing the modulus of bnr (and the infinite places),2392* else2393* compute the value of the primitive L-function attached to chi,2394* If flag & 4: return also the character */2395GEN2396bnrL1(GEN bnr, GEN subgp, long flag, long prec)2397{2398GEN L1, ch, Qt, z;2399long l, h;2400pari_sp av = avma;24012402checkbnr(bnr);2403if (flag < 0 || flag > 8) pari_err_FLAG("bnrL1");24042405subgp = bnr_subgroup_check(bnr, subgp, NULL);2406if (!subgp) subgp = diagonal_shallow(bnr_get_cyc(bnr));24072408Qt = InitQuotient(subgp);2409ch = AllChars(bnr, Qt, 0); l = lg(ch);2410h = itou(gel(Qt,1));2411L1 = cgetg((flag&1)? h: h+1, t_VEC);2412if (l > 1)2413{2414GEN W, S, T, CR = InitChar(bnr, ch, 1, prec), dataCR = gel(CR,2);2415long i, j;24162417GetST(bnr, &S, &T, CR, prec);2418W = AllArtinNumbers(CR, prec);2419for (i = j = 1; i < l; i++)2420{2421GEN chi = gel(ch,i);2422z = GetValue(gel(dataCR,i), gel(W,i), gel(S,i), gel(T,i), flag, prec);2423gel(L1,j++) = (flag & 4)? mkvec2(gel(chi,1), z): z;2424if (lg(chi) == 4)2425{ /* nonreal */2426z = conj_i(z);2427gel(L1, j++) = (flag & 4)? mkvec2(gel(chi,3), z): z;2428}2429}2430}2431if (!(flag & 1))2432{ /* trivial character */2433z = GetValue1(bnr, flag & 2, prec);2434if (flag & 4)2435{2436GEN chi = zerovec(lg(bnr_get_cyc(bnr))-1);2437z = mkvec2(chi, z);2438}2439gel(L1,h) = z;2440}2441return gerepilecopy(av, L1);2442}24432444/*******************************************************************/2445/* */2446/* Hilbert and Ray Class field using Stark */2447/* */2448/*******************************************************************/2449/* P in A[x,y], deg_y P < 2, return P0 and P1 in A[x] such that P = P0 + P1 y */2450static void2451split_pol_quad(GEN P, GEN *gP0, GEN *gP1)2452{2453long i, l = lg(P);2454GEN P0 = cgetg(l, t_POL), P1 = cgetg(l, t_POL);2455P0[1] = P1[1] = P[1];2456for (i = 2; i < l; i++)2457{2458GEN c = gel(P,i), c0 = c, c1 = gen_0;2459if (typ(c) == t_POL) /* write c = c1 y + c0 */2460switch(degpol(c))2461{2462case -1: c0 = gen_0; break;2463default: c1 = gel(c,3); /* fall through */2464case 0: c0 = gel(c,2); break;2465}2466gel(P0,i) = c0; gel(P1,i) = c1;2467}2468*gP0 = normalizepol_lg(P0, l);2469*gP1 = normalizepol_lg(P1, l);2470}24712472/* k = nf quadratic field, P relative equation of H_k (Hilbert class field)2473* return T in Z[X], such that H_k / Q is the compositum of Q[X]/(T) and k */2474static GEN2475makescind(GEN nf, GEN P)2476{2477GEN Pp, p, pol, G, L, a, roo, P0,P1, Ny,Try, nfpol = nf_get_pol(nf);2478long i, is_P;24792480P = lift_shallow(P);2481split_pol_quad(P, &P0, &P1);2482/* P = P0 + y P1, Norm_{k/Q}(P) = P0^2 + Tr y P0P1 + Ny P1^2, irreducible/Q */2483Ny = gel(nfpol, 2);2484Try = negi(gel(nfpol, 3));2485pol = RgX_add(RgX_sqr(P0), RgX_Rg_mul(RgX_sqr(P1), Ny));2486if (signe(Try)) pol = RgX_add(pol, RgX_Rg_mul(RgX_mul(P0,P1), Try));2487/* pol = rnfequation(nf, P); */2488G = galoisinit(pol, NULL);2489L = gal_get_group(G);2490p = gal_get_p(G);2491a = FpX_oneroot(nfpol, p);2492/* P mod a prime \wp above p (which splits) */2493Pp = FpXY_evalx(P, a, p);2494roo = gal_get_roots(G);2495is_P = gequal0( FpX_eval(Pp, remii(gel(roo,1),p), p) );2496/* each roo[i] mod p is a root of P or (exclusive) tau(P) mod \wp */2497/* record whether roo[1] is a root of P or tau(P) */24982499for (i = 1; i < lg(L); i++)2500{2501GEN perm = gel(L,i);2502long k = perm[1]; if (k == 1) continue;2503k = gequal0( FpX_eval(Pp, remii(gel(roo,k),p), p) );2504/* roo[k] is a root of the other polynomial */2505if (k != is_P)2506{2507ulong o = perm_orderu(perm);2508if (o != 2) perm = perm_powu(perm, o >> 1);2509/* perm has order two and doesn't belong to Gal(H_k/k) */2510return galoisfixedfield(G, perm, 1, varn(P));2511}2512}2513pari_err_BUG("makescind");2514return NULL; /*LCOV_EXCL_LINE*/2515}25162517/* pbnf = NULL if no bnf is needed, f = NULL may be passed for a trivial2518* conductor */2519static void2520quadray_init(GEN *pD, GEN f, GEN *pbnf, long prec)2521{2522GEN D = *pD, nf, bnf = NULL;2523if (typ(D) == t_INT)2524{2525int isfund;2526if (pbnf) {2527long v = f? gvar(f): NO_VARIABLE;2528if (v == NO_VARIABLE) v = 1;2529bnf = Buchall(quadpoly0(D, v), nf_FORCE, prec);2530nf = bnf_get_nf(bnf);2531isfund = equalii(D, nf_get_disc(nf));2532}2533else2534isfund = Z_isfundamental(D);2535if (!isfund) pari_err_DOMAIN("quadray", "isfundamental(D)", "=",gen_0, D);2536}2537else2538{2539bnf = checkbnf(D);2540nf = bnf_get_nf(bnf);2541if (nf_get_degree(nf) != 2)2542pari_err_DOMAIN("quadray", "degree", "!=", gen_2, nf_get_pol(nf));2543D = nf_get_disc(nf);2544}2545if (pbnf) *pbnf = bnf;2546*pD = D;2547}25482549/* compute the polynomial over Q of the Hilbert class field of2550Q(sqrt(D)) where D is a positive fundamental discriminant */2551static GEN2552quadhilbertreal(GEN D, long prec)2553{2554pari_sp av = avma;2555GEN bnf, pol, bnr, dtQ, data, M;2556long newprec;2557pari_timer T;25582559quadray_init(&D, NULL, &bnf, prec);2560switch(itou_or_0(cyc_get_expo(bnf_get_cyc(bnf))))2561{2562case 1: set_avma(av); return pol_x(0);2563case 2: return gerepileupto(av, GenusFieldQuadReal(D));2564}2565bnr = Buchray(bnf, gen_1, nf_INIT);2566M = diagonal_shallow(bnr_get_cyc(bnr));2567dtQ = InitQuotient(M);25682569if (DEBUGLEVEL) timer_start(&T);2570data = FindModulus(bnr, dtQ, &newprec);2571if (DEBUGLEVEL) timer_printf(&T,"FindModulus");2572if (!data) return gerepileupto(av, bnrstark_cyclic(bnr, dtQ, prec));2573pol = AllStark(data, 0, newprec);2574pol = makescind(bnf_get_nf(bnf), pol);2575return gerepileupto(av, polredbest(pol, 0));2576}25772578/*******************************************************************/2579/* */2580/* Hilbert and Ray Class field using CM (Schertz) */2581/* */2582/*******************************************************************/2583/* form^2 = 1 ? */2584static int2585hasexp2(GEN form)2586{2587GEN a = gel(form,1), b = gel(form,2), c = gel(form,3);2588return !signe(b) || absequalii(a,b) || equalii(a,c);2589}2590static int2591uhasexp2(GEN form)2592{2593long a = form[1], b = form[2], c = form[3];2594return !b || a == labs(b) || a == c;2595}25962597GEN2598qfbforms(GEN D)2599{2600ulong d = itou(D), dover3 = d/3, t, b2, a, b, c, h;2601GEN L = cgetg((long)(sqrt((double)d) * log2(d)), t_VEC);2602b2 = b = (d&1); h = 0;2603if (!b) /* b = 0 treated separately to avoid special cases */2604{2605t = d >> 2; /* (b^2 - D) / 4*/2606for (a=1; a*a<=t; a++)2607if (c = t/a, t == c*a) gel(L,++h) = mkvecsmall3(a,0,c);2608b = 2; b2 = 4;2609}2610/* now b > 0, b = D (mod 2) */2611for ( ; b2 <= dover3; b += 2, b2 = b*b)2612{2613t = (b2 + d) >> 2; /* (b^2 - D) / 4*/2614/* b = a */2615if (c = t/b, t == c*b) gel(L,++h) = mkvecsmall3(b,b,c);2616/* b < a < c */2617for (a = b+1; a*a < t; a++)2618if (c = t/a, t == c*a)2619{2620gel(L,++h) = mkvecsmall3(a, b,c);2621gel(L,++h) = mkvecsmall3(a,-b,c);2622}2623/* a = c */2624if (a * a == t) gel(L,++h) = mkvecsmall3(a,b,a);2625}2626setlg(L,h+1); return L;2627}26282629/* gcd(n, 24) */2630static long2631GCD24(long n)2632{2633switch(n % 24)2634{2635case 0: return 24;2636case 1: return 1;2637case 2: return 2;2638case 3: return 3;2639case 4: return 4;2640case 5: return 1;2641case 6: return 6;2642case 7: return 1;2643case 8: return 8;2644case 9: return 3;2645case 10: return 2;2646case 11: return 1;2647case 12: return 12;2648case 13: return 1;2649case 14: return 2;2650case 15: return 3;2651case 16: return 8;2652case 17: return 1;2653case 18: return 6;2654case 19: return 1;2655case 20: return 4;2656case 21: return 3;2657case 22: return 2;2658case 23: return 1;2659default: return 0;2660}2661}26622663struct gpq_data {2664long p, q;2665GEN sqd; /* sqrt(D), t_REAL */2666GEN u, D;2667GEN pq, pq2; /* p*q, 2*p*q */2668GEN qfpq ; /* class of \P * \Q */2669};26702671/* find P and Q two non principal prime ideals (above p <= q) such that2672* cl(P) = cl(Q) if P,Q have order 2 in Cl(K).2673* Ensure that e = 24 / gcd(24, (p-1)(q-1)) = 1 */2674/* D t_INT, discriminant */2675static void2676init_pq(GEN D, struct gpq_data *T)2677{2678const long Np = 6547; /* N.B. primepi(50000) = 5133 */2679const ulong maxq = 50000;2680GEN listp = cgetg(Np + 1, t_VECSMALL); /* primes p */2681GEN listP = cgetg(Np + 1, t_VEC); /* primeform(p) if of order 2, else NULL */2682GEN gcd24 = cgetg(Np + 1, t_VECSMALL); /* gcd(p-1, 24) */2683forprime_t S;2684long l = 1;2685double best = 0.;2686ulong q;26872688u_forprime_init(&S, 2, ULONG_MAX);2689T->D = D;2690T->p = T->q = 0;2691for(;;)2692{2693GEN Q;2694long i, gcdq, mod;2695int order2, store;2696double t;26972698q = u_forprime_next(&S);2699if (best > 0 && q >= maxq)2700{2701if (DEBUGLEVEL)2702pari_warn(warner,"possibly suboptimal (p,q) for D = %Ps", D);2703break;2704}2705if (kroiu(D, q) < 0) continue; /* inert */2706Q = qfbred_i(primeform_u(D, q));2707if (is_pm1(gel(Q,1))) continue; /* Q | q is principal */27082709store = 1;2710order2 = hasexp2(Q);2711gcd24[l] = gcdq = GCD24(q-1);2712mod = 24 / gcdq; /* mod must divide p-1 otherwise e > 1 */2713listp[l] = q;2714gel(listP,l) = order2 ? Q : NULL;2715t = (q+1)/(double)(q-1);2716for (i = 1; i < l; i++) /* try all (p, q), p < q in listp */2717{2718long p = listp[i], gcdp = gcd24[i];2719double b;2720/* P,Q order 2 => cl(Q) = cl(P) */2721if (order2 && gel(listP,i) && !gequal(gel(listP,i), Q)) continue;2722if (gcdp % gcdq == 0) store = 0; /* already a better one in the list */2723if ((p-1) % mod) continue;27242725b = (t*(p+1)) / (p-1); /* (p+1)(q+1) / (p-1)(q-1) */2726if (b > best) {2727store = 0; /* (p,q) always better than (q,r) for r >= q */2728best = b; T->q = q; T->p = p;2729if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", p, q);2730}2731/* won't improve with this q as largest member */2732if (best > 0) break;2733}2734/* if !store or (q,r) won't improve on current best pair, forget that q */2735if (store && t*t > best)2736if (++l >= Np) pari_err_BUG("quadhilbert (not enough primes)");2737if (!best) /* (p,q) with p < q always better than (q,q) */2738{ /* try (q,q) */2739if (gcdq >= 12 && umodiu(D, q)) /* e = 1 and unramified */2740{2741double b = (t*q) / (q-1); /* q(q+1) / (q-1)^2 */2742if (b > best) {2743best = b; T->q = T->p = q;2744if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", q, q);2745}2746}2747}2748/* If (p1+1)(q+1) / (p1-1)(q-1) <= best, we can no longer improve2749* even with best p : stop */2750if ((listp[1]+1)*t <= (listp[1]-1)*best) break;2751}2752if (DEBUGLEVEL>1)2753err_printf("(p, q) = %ld, %ld; gain = %f\n", T->p, T->q, 12*best);2754}27552756static GEN2757gpq(GEN form, struct gpq_data *T)2758{2759pari_sp av = avma;2760long a = form[1], b = form[2], c = form[3], p = T->p, q = T->q;2761GEN form2, w, z;2762int fl, real = 0;27632764form2 = qfbcomp_i(T->qfpq, mkqfb(stoi(a), stoi(-b), stoi(c), T->D));2765/* form2 and form yield complex conjugate roots : only compute for the2766* lexicographically smallest of the 2 */2767fl = cmpis(gel(form2,1), a);2768if (fl <= 0)2769{2770if (fl < 0) return NULL;2771fl = cmpis(gel(form2,2), b);2772if (fl <= 0)2773{2774if (fl < 0) return NULL;2775/* form == form2 : real root */2776real = 1;2777}2778}27792780if (p == 2) { /* (a,b,c) = (1,1,0) mod 2 ? */2781if (a % q == 0 && (a & b & 1) && !(c & 1))2782{ /* apply S : make sure that (a,b,c) represents odd values */2783lswap(a,c); b = -b;2784}2785}2786if (a % p == 0 || a % q == 0)2787{ /* apply T^k, look for c' = a k^2 + b k + c coprime to N */2788while (c % p == 0 || c % q == 0)2789{2790c += a + b;2791b += a << 1;2792}2793lswap(a, c); b = -b; /* apply S */2794}2795/* now (a,b,c) ~ form and (a,pq) = 1 */27962797/* gcd(2a, u) = 2, w = u mod 2pq, -b mod 2a */2798w = Z_chinese(T->u, stoi(-b), T->pq2, utoipos(a << 1));2799z = double_eta_quotient(utoipos(a), w, T->D, T->p, T->q, T->pq, T->sqd);2800if (real && typ(z) == t_COMPLEX) z = gcopy(gel(z, 1));2801return gerepileupto(av, z);2802}28032804/* returns an equation for the Hilbert class field of Q(sqrt(D)), D < 02805* fundamental discriminant */2806static GEN2807quadhilbertimag(GEN D)2808{2809GEN L, P, Pi, Pr, qfp, u;2810pari_sp av = avma;2811long h, i, prec;2812struct gpq_data T;2813pari_timer ti;28142815if (DEBUGLEVEL>1) timer_start(&ti);2816if (lgefint(D) == 3)2817switch (D[2]) { /* = |D|; special cases where e > 1 */2818case 3:2819case 4:2820case 7:2821case 8:2822case 11:2823case 19:2824case 43:2825case 67:2826case 163: return pol_x(0);2827}2828L = qfbforms(D);2829h = lg(L)-1;2830if ((1L << vals(h)) == h) /* power of 2 */2831{ /* check whether > |Cl|/2 elements have order <= 2 ==> 2-elementary */2832long lim = (h>>1) + 1;2833for (i=1; i <= lim; i++)2834if (!uhasexp2(gel(L,i))) break;2835if (i > lim) return GenusFieldQuadImag(D);2836}2837if (DEBUGLEVEL>1) timer_printf(&ti,"class number = %ld",h);2838init_pq(D, &T);2839qfp = primeform_u(D, T.p);2840T.pq = muluu(T.p, T.q);2841T.pq2 = shifti(T.pq,1);2842if (T.p == T.q)2843{2844GEN qfbp2 = qfbcompraw(qfp, qfp);2845u = gel(qfbp2,2);2846T.u = modii(u, T.pq2);2847T.qfpq = qfbred_i(qfbp2);2848}2849else2850{2851GEN qfq = primeform_u(D, T.q), bp = gel(qfp,2), bq = gel(qfq,2);2852T.u = Z_chinese(bp, bq, utoipos(T.p << 1), utoipos(T.q << 1));2853/* T.u = bp (mod 2p), T.u = bq (mod 2q) */2854T.qfpq = qfbcomp_i(qfp, qfq);2855}2856/* u modulo 2pq */2857prec = LOWDEFAULTPREC;2858Pr = cgetg(h+1,t_VEC);2859Pi = cgetg(h+1,t_VEC);2860for(;;)2861{2862long ex, exmax = 0, r1 = 0, r2 = 0;2863pari_sp av0 = avma;2864T.sqd = sqrtr_abs(itor(D, prec));2865for (i=1; i<=h; i++)2866{2867GEN s = gpq(gel(L,i), &T);2868if (DEBUGLEVEL>3) err_printf("%ld ", i);2869if (!s) continue;2870if (typ(s) != t_COMPLEX) gel(Pr, ++r1) = s; /* real root */2871else gel(Pi, ++r2) = s;2872ex = gexpo(s); if (ex > 0) exmax += ex;2873}2874if (DEBUGLEVEL>1) timer_printf(&ti,"roots");2875setlg(Pr, r1+1);2876setlg(Pi, r2+1);2877P = roots_to_pol_r1(shallowconcat(Pr,Pi), 0, r1);2878P = grndtoi(P,&exmax);2879if (DEBUGLEVEL>1) timer_printf(&ti,"product, error bits = %ld",exmax);2880if (exmax <= -10) break;2881set_avma(av0); prec += nbits2extraprec(prec2nbits(DEFAULTPREC)+exmax);2882if (DEBUGLEVEL) pari_warn(warnprec,"quadhilbertimag",prec);2883}2884return gerepileupto(av,P);2885}28862887GEN2888quadhilbert(GEN D, long prec)2889{2890GEN d = D;2891quadray_init(&d, NULL, NULL, 0);2892return (signe(d)>0)? quadhilbertreal(D,prec)2893: quadhilbertimag(d);2894}28952896/* return a vector of all roots of 1 in bnf [not necessarily quadratic] */2897static GEN2898getallrootsof1(GEN bnf)2899{2900GEN T, u, nf = bnf_get_nf(bnf), tu;2901long i, n = bnf_get_tuN(bnf);29022903if (n == 2) {2904long N = nf_get_degree(nf);2905return mkvec2(scalarcol_shallow(gen_m1, N),2906scalarcol_shallow(gen_1, N));2907}2908tu = poltobasis(nf, bnf_get_tuU(bnf));2909T = zk_multable(nf, tu);2910u = cgetg(n+1, t_VEC); gel(u,1) = tu;2911for (i=2; i <= n; i++) gel(u,i) = ZM_ZC_mul(T, gel(u,i-1));2912return u;2913}2914/* assume bnr has the right conductor */2915static GEN2916get_lambda(GEN bnr)2917{2918GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf), pol = nf_get_pol(nf);2919GEN f = gel(bnr_get_mod(bnr), 1), labas, lamodf, u;2920long a, b, f2, i, lu, v = varn(pol);29212922f2 = 2 * itos(gcoeff(f,1,1));2923u = getallrootsof1(bnf); lu = lg(u);2924for (i=1; i<lu; i++)2925gel(u,i) = ZC_hnfrem(gel(u,i), f); /* roots of 1, mod f */2926if (DEBUGLEVEL>1)2927err_printf("quadray: looking for [a,b] != unit mod 2f\n[a,b] = ");2928for (a=0; a<f2; a++)2929for (b=0; b<f2; b++)2930{2931GEN la = deg1pol_shallow(stoi(a), stoi(b), v); /* ax + b */2932if (umodiu(gnorm(mkpolmod(la, pol)), f2) != 1) continue;2933if (DEBUGLEVEL>1) err_printf("[%ld,%ld] ",a,b);29342935labas = poltobasis(nf, la);2936lamodf = ZC_hnfrem(labas, f);2937for (i=1; i<lu; i++)2938if (ZV_equal(lamodf, gel(u,i))) break;2939if (i < lu) continue; /* la = unit mod f */2940if (DEBUGLEVEL)2941{2942if (DEBUGLEVEL>1) err_printf("\n");2943err_printf("lambda = %Ps\n",la);2944}2945return labas;2946}2947pari_err_BUG("get_lambda");2948return NULL;/*LCOV_EXCL_LINE*/2949}29502951static GEN2952to_approx(GEN nf, GEN a)2953{2954GEN M = nf_get_M(nf);2955return gadd(gel(a,1), gmul(gcoeff(M,1,2),gel(a,2)));2956}2957/* Z-basis for a (over C) */2958static GEN2959get_om(GEN nf, GEN a) {2960return mkvec2(to_approx(nf,gel(a,2)),2961to_approx(nf,gel(a,1)));2962}29632964/* Compute all elts in class group G = [|G|,c,g], c=cyclic factors, g=gens.2965* Set list[j + 1] = g1^e1...gk^ek where j is the integer2966* ek + ck [ e(k-1) + c(k-1) [... + c2 [e1]]...] */2967static GEN2968getallelts(GEN bnr)2969{2970GEN nf, C, c, g, list, pows, gk;2971long lc, i, j, no;29722973nf = bnr_get_nf(bnr);2974no = itos( bnr_get_no(bnr) );2975c = bnr_get_cyc(bnr);2976g = bnr_get_gen_nocheck(bnr); lc = lg(c)-1;2977list = cgetg(no+1,t_VEC);2978gel(list,1) = matid(nf_get_degree(nf)); /* (1) */2979if (!no) return list;29802981pows = cgetg(lc+1,t_VEC);2982c = leafcopy(c); settyp(c, t_VECSMALL);2983for (i=1; i<=lc; i++)2984{2985long k = itos(gel(c,i));2986c[i] = k;2987gk = cgetg(k, t_VEC); gel(gk,1) = gel(g,i);2988for (j=2; j<k; j++)2989gel(gk,j) = idealmoddivisor(bnr, idealmul(nf, gel(gk,j-1), gel(gk,1)));2990gel(pows,i) = gk; /* powers of g[i] */2991}29922993C = cgetg(lc+1, t_VECSMALL); C[1] = c[lc];2994for (i=2; i<=lc; i++) C[i] = C[i-1] * c[lc-i+1];2995/* C[i] = c(k-i+1) * ... * ck */2996/* j < C[i+1] <==> j only involves g(k-i)...gk */2997i = 1;2998for (j=1; j < C[1]; j++)2999gel(list, j+1) = gmael(pows,lc,j);3000while(j<no)3001{3002long k;3003GEN a;3004if (j == C[i+1]) i++;3005a = gmael(pows,lc-i,j/C[i]);3006k = j%C[i] + 1;3007if (k > 1) a = idealmoddivisor(bnr, idealmul(nf, a, gel(list,k)));3008gel(list, ++j) = a;3009}3010return list;3011}30123013/* x quadratic integer (approximate), recognize it. If error return NULL */3014static GEN3015findbezk(GEN nf, GEN x)3016{3017GEN a,b, M = nf_get_M(nf), u = gcoeff(M,1,2);3018long ea, eb;30193020/* u t_COMPLEX generator of nf.zk, write x ~ a + b u, a,b in Z */3021b = grndtoi(mpdiv(imag_i(x), gel(u,2)), &eb);3022if (eb > -20) return NULL;3023a = grndtoi(mpsub(real_i(x), mpmul(b,gel(u,1))), &ea);3024if (ea > -20) return NULL;3025return signe(b)? coltoalg(nf, mkcol2(a,b)): a;3026}30273028static GEN3029findbezk_pol(GEN nf, GEN x)3030{3031long i, lx = lg(x);3032GEN y = cgetg(lx,t_POL);3033for (i=2; i<lx; i++)3034if (! (gel(y,i) = findbezk(nf,gel(x,i))) ) return NULL;3035y[1] = x[1]; return y;3036}30373038/* P approximation computed at initial precision prec. Compute needed prec3039* to know P with 1 word worth of trailing decimals */3040static long3041get_prec(GEN P, long prec)3042{3043long k = gprecision(P);3044if (k == 3) return precdbl(prec); /* approximation not trustworthy */3045k = prec - k; /* lost precision when computing P */3046if (k < 0) k = 0;3047k += nbits2prec(gexpo(P) + 128);3048if (k <= prec) k = precdbl(prec); /* dubious: old prec should have worked */3049return k;3050}30513052/* Compute data for ellphist */3053static GEN3054ellphistinit(GEN om, long prec)3055{3056GEN res,om1b,om2b, om1 = gel(om,1), om2 = gel(om,2);30573058if (gsigne(imag_i(gdiv(om1,om2))) < 0) { swap(om1,om2); om = mkvec2(om1,om2); }3059om1b = conj_i(om1);3060om2b = conj_i(om2); res = cgetg(4,t_VEC);3061gel(res,1) = gdivgs(elleisnum(om,2,0,prec),12);3062gel(res,2) = gdiv(PiI2(prec), gmul(om2, imag_i(gmul(om1b,om2))));3063gel(res,3) = om2b; return res;3064}30653066/* Computes log(phi^*(z,om)), using res computed by ellphistinit */3067static GEN3068ellphist(GEN om, GEN res, GEN z, long prec)3069{3070GEN u = imag_i(gmul(z, gel(res,3)));3071GEN zst = gsub(gmul(u, gel(res,2)), gmul(z,gel(res,1)));3072return gsub(ellsigma(om,z,1,prec),gmul2n(gmul(z,zst),-1));3073}30743075/* Computes phi^*(la,om)/phi^*(1,om) where (1,om) is an oriented basis of the3076ideal gf*gc^{-1} */3077static GEN3078computeth2(GEN om, GEN la, long prec)3079{3080GEN p1,p2,res = ellphistinit(om,prec);30813082p1 = gsub(ellphist(om,res,la,prec), ellphist(om,res,gen_1,prec));3083p2 = imag_i(p1);3084if (gexpo(real_i(p1))>20 || gexpo(p2)> prec2nbits(minss(prec,realprec(p2)))-10)3085return NULL;3086return gexp(p1,prec);3087}30883089/* Computes P_2(X)=polynomial in Z_K[X] closest to prod_gc(X-th2(gc)) where3090the product is over the ray class group bnr.*/3091static GEN3092computeP2(GEN bnr, long prec)3093{3094long clrayno, i, first = 1;3095pari_sp av=avma, av2;3096GEN listray, P0, P, lanum, la = get_lambda(bnr);3097GEN nf = bnr_get_nf(bnr), f = gel(bnr_get_mod(bnr), 1);3098listray = getallelts(bnr);3099clrayno = lg(listray)-1; av2 = avma;3100PRECPB:3101if (!first)3102{3103if (DEBUGLEVEL) pari_warn(warnprec,"computeP2",prec);3104nf = gerepilecopy(av2, nfnewprec_shallow(checknf(bnr),prec));3105}3106first = 0; lanum = to_approx(nf,la);3107P = cgetg(clrayno+1,t_VEC);3108for (i=1; i<=clrayno; i++)3109{3110GEN om = get_om(nf, idealdiv(nf,f,gel(listray,i)));3111GEN s = computeth2(om,lanum,prec);3112if (!s) { prec = precdbl(prec); goto PRECPB; }3113gel(P,i) = s;3114}3115P0 = roots_to_pol(P, 0);3116P = findbezk_pol(nf, P0);3117if (!P) { prec = get_prec(P0, prec); goto PRECPB; }3118return gerepilecopy(av, P);3119}31203121#define nexta(a) (a>0 ? -a : 1-a)3122static GEN3123do_compo(GEN A0, GEN B)3124{3125long a, i, l = lg(B), v = fetch_var_higher();3126GEN A, z;3127/* now v > x = pol_x(0) > nf variable */3128B = leafcopy(B); setvarn(B, v);3129for (i = 2; i < l; i++) gel(B,i) = monomial(gel(B,i), l-i-1, 0);3130/* B := x^deg(B) B(v/x) */3131A = A0 = leafcopy(A0); setvarn(A0, v);3132for (a = 0;; a = nexta(a))3133{3134if (a) A = RgX_translate(A0, stoi(a));3135z = resultant(A,B); /* in variable 0 */3136if (issquarefree(z)) break;3137}3138(void)delete_var(); return z;3139}3140#undef nexta31413142static GEN3143galoisapplypol(GEN nf, GEN s, GEN x)3144{3145long i, lx = lg(x);3146GEN y = cgetg(lx,t_POL);31473148for (i=2; i<lx; i++) gel(y,i) = galoisapply(nf,s,gel(x,i));3149y[1] = x[1]; return y;3150}3151/* x quadratic, write it as ua + v, u,v rational */3152static GEN3153findquad(GEN a, GEN x, GEN p)3154{3155long tu, tv;3156pari_sp av = avma;3157GEN u,v;3158if (typ(x) == t_POLMOD) x = gel(x,2);3159if (typ(a) == t_POLMOD) a = gel(a,2);3160u = poldivrem(x, a, &v);3161u = simplify_shallow(u); tu = typ(u);3162v = simplify_shallow(v); tv = typ(v);3163if (!is_scalar_t(tu)) pari_err_TYPE("findquad", u);3164if (!is_scalar_t(tv)) pari_err_TYPE("findquad", v);3165x = deg1pol(u, v, varn(a));3166if (typ(x) == t_POL) x = gmodulo(x,p);3167return gerepileupto(av, x);3168}3169static GEN3170findquad_pol(GEN p, GEN a, GEN x)3171{3172long i, lx = lg(x);3173GEN y = cgetg(lx,t_POL);3174for (i=2; i<lx; i++) gel(y,i) = findquad(a, gel(x,i), p);3175y[1] = x[1]; return y;3176}3177static GEN3178compocyclo(GEN nf, long m, long d)3179{3180GEN sb,a,b,s,p1,p2,p3,res,polL,polLK,nfL, D = nf_get_disc(nf);3181long ell,vx;31823183p1 = quadhilbertimag(D);3184p2 = polcyclo(m,0);3185if (d==1) return do_compo(p1,p2);31863187ell = m&1 ? m : (m>>2);3188if (absequalui(ell,D)) /* ell = |D| */3189{3190p2 = gcoeff(nffactor(nf,p2),1,1);3191return do_compo(p1,p2);3192}3193if (ell%4 == 3) ell = -ell;3194/* nf = K = Q(a), L = K(b) quadratic extension = Q(t) */3195polLK = quadpoly(stoi(ell)); /* relative polynomial */3196res = rnfequation2(nf, polLK);3197vx = nf_get_varn(nf);3198polL = gsubst(gel(res,1),0,pol_x(vx)); /* = charpoly(t) */3199a = gsubst(lift_shallow(gel(res,2)), 0,pol_x(vx));3200b = gsub(pol_x(vx), gmul(gel(res,3), a));3201nfL = nfinit(polL, DEFAULTPREC);3202p1 = gcoeff(nffactor(nfL,p1),1,1);3203p2 = gcoeff(nffactor(nfL,p2),1,1);3204p3 = do_compo(p1,p2); /* relative equation over L */3205/* compute non trivial s in Gal(L / K) */3206sb= gneg(gadd(b, RgX_coeff(polLK,1))); /* s(b) = Tr(b) - b */3207s = gadd(pol_x(vx), gsub(sb, b)); /* s(t) = t + s(b) - b */3208p3 = gmul(p3, galoisapplypol(nfL, s, p3));3209return findquad_pol(nf_get_pol(nf), a, p3);3210}32113212/* I integral ideal in HNF. (x) = I, x small in Z ? */3213static long3214isZ(GEN I)3215{3216GEN x = gcoeff(I,1,1);3217if (signe(gcoeff(I,1,2)) || !equalii(x, gcoeff(I,2,2))) return 0;3218return is_bigint(x)? -1: itos(x);3219}32203221/* Treat special cases directly. return NULL if not special case */3222static GEN3223treatspecialsigma(GEN bnr)3224{3225GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf);3226GEN f = gel(bnr_get_mod(bnr), 1), D = nf_get_disc(nf);3227GEN p1, p2;3228long Ds, fl, tryf, i = isZ(f);32293230if (i == 1) return quadhilbertimag(D); /* f = 1 */32313232if (absequaliu(D,3)) /* Q(j) */3233{3234if (i == 4 || i == 5 || i == 7) return polcyclo(i,0);3235if (!absequaliu(gcoeff(f,1,1),9) || !absequaliu(Z_content(f),3)) return NULL;3236/* f = P_3^3 */3237p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf));3238return gadd(pol_xn(3,0), p1); /* x^3+j */3239}3240if (absequaliu(D,4)) /* Q(i) */3241{3242if (i == 3 || i == 5) return polcyclo(i,0);3243if (i != 4) return NULL;3244p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf));3245return gadd(pol_xn(2,0), p1); /* x^2+i */3246}3247Ds = smodis(D,48);3248if (i)3249{3250if (i==2 && Ds%16== 8) return compocyclo(nf, 4,1);3251if (i==3 && Ds% 3== 1) return compocyclo(nf, 3,1);3252if (i==4 && Ds% 8== 1) return compocyclo(nf, 4,1);3253if (i==6 && Ds ==40) return compocyclo(nf,12,1);3254return NULL;3255}32563257p1 = gcoeff(f,1,1); /* integer > 0 */3258tryf = itou_or_0(p1); if (!tryf) return NULL;3259p2 = gcoeff(f,2,2); /* integer > 0 */3260if (is_pm1(p2)) fl = 0;3261else {3262if (Ds % 16 != 8 || !absequaliu(Z_content(f),2)) return NULL;3263fl = 1; tryf >>= 1;3264}3265if (tryf <= 3 || umodiu(D, tryf) || !uisprime(tryf)) return NULL;3266if (fl) tryf <<= 2;3267return compocyclo(nf,tryf,2);3268}32693270GEN3271quadray(GEN D, GEN f, long prec)3272{3273GEN bnr, y, bnf, H = NULL;3274pari_sp av = avma;32753276if (isint1(f)) return quadhilbert(D, prec);3277quadray_init(&D, f, &bnf, prec);3278bnr = Buchray(bnf, f, nf_INIT|nf_GEN);3279if (is_pm1(bnr_get_no(bnr))) { set_avma(av); return pol_x(0); }3280if (signe(D) > 0)3281y = bnrstark(bnr, H, prec);3282else3283{3284bnr_subgroup_sanitize(&bnr, &H);3285y = treatspecialsigma(bnr);3286if (!y) y = computeP2(bnr, prec);3287}3288return gerepileupto(av, y);3289}329032913292