Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - modules - stark.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.16.2 lcov report (development 29115-f22e516b23) Lines: 1651 1786 92.4 %
Date: 2024-03-18 08:03:28 Functions: 127 129 98.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : /*******************************************************************/
      16             : /*                                                                 */
      17             : /*        COMPUTATION OF STARK UNITS OF TOTALLY REAL FIELDS        */
      18             : /*                                                                 */
      19             : /*******************************************************************/
      20             : #include "pari.h"
      21             : #include "paripriv.h"
      22             : 
      23             : #define DEBUGLEVEL DEBUGLEVEL_stark
      24             : 
      25             : /* ComputeCoeff */
      26             : typedef struct {
      27             :   GEN L0, L1, L11, L2; /* VECSMALL of p */
      28             :   GEN L1ray, L11ray; /* precomputed isprincipalray(pr), pr | p */
      29             :   GEN rayZ; /* precomputed isprincipalray(i), i < condZ */
      30             :   long condZ; /* generates cond(bnr) \cap Z, assumed small */
      31             : } LISTray;
      32             : 
      33             : /* Char evaluation */
      34             : typedef struct {
      35             :   long ord;
      36             :   GEN *val, chi;
      37             : } CHI_t;
      38             : 
      39             : /* RecCoeff */
      40             : typedef struct {
      41             :   GEN M, beta, B, U, nB;
      42             :   long v, G, N;
      43             : } RC_data;
      44             : 
      45             : /********************************************************************/
      46             : /*                    Miscellaneous functions                       */
      47             : /********************************************************************/
      48             : static GEN
      49       17815 : chi_get_c(GEN chi) { return gmael(chi,1,2); }
      50             : static long
      51       51352 : chi_get_deg(GEN chi) { return itou(gmael(chi,1,1)); }
      52             : 
      53             : /* Compute the image of logelt by character chi, zeta_ord(chi)^n; return n */
      54             : static ulong
      55       13839 : CharEval_n(GEN chi, GEN logelt)
      56             : {
      57       13839 :   GEN gn = ZV_dotproduct(chi_get_c(chi), logelt);
      58       13839 :   return umodiu(gn, chi_get_deg(chi));
      59             : }
      60             : /* Compute the image of logelt by character chi, as a complex number */
      61             : static GEN
      62       13783 : CharEval(GEN chi, GEN logelt)
      63             : {
      64       13783 :   ulong n = CharEval_n(chi, logelt), d = chi_get_deg(chi);
      65       13783 :   long nn = Fl_center(n,d,d>>1);
      66       13783 :   GEN x = gel(chi,2);
      67       13783 :   x = gpowgs(x, labs(nn));
      68       13783 :   if (nn < 0) x = conj_i(x);
      69       13783 :   return x;
      70             : }
      71             : 
      72             : /* return n such that C(elt) = z^n */
      73             : static ulong
      74      636297 : CHI_eval_n(CHI_t *C, GEN logelt)
      75             : {
      76      636297 :   GEN n = ZV_dotproduct(C->chi, logelt);
      77      636297 :   return umodiu(n, C->ord);
      78             : }
      79             : /* return C(elt) */
      80             : static GEN
      81      634631 : CHI_eval(CHI_t *C, GEN logelt)
      82             : {
      83      634631 :   return C->val[CHI_eval_n(C, logelt)];
      84             : }
      85             : 
      86             : static void
      87        3976 : init_CHI(CHI_t *c, GEN CHI, GEN z)
      88             : {
      89        3976 :   long i, d = chi_get_deg(CHI);
      90        3976 :   GEN *v = (GEN*)new_chunk(d);
      91        3976 :   v[0] = gen_1;
      92        3976 :   if (d != 1)
      93             :   {
      94        3976 :     v[1] = z;
      95       32557 :     for (i=2; i<d; i++) v[i] = gmul(v[i-1], z);
      96             :   }
      97        3976 :   c->chi = chi_get_c(CHI);
      98        3976 :   c->ord = d;
      99        3976 :   c->val = v;
     100        3976 : }
     101             : /* as t_POLMOD */
     102             : static void
     103        2450 : init_CHI_alg(CHI_t *c, GEN CHI) {
     104        2450 :   long d = chi_get_deg(CHI);
     105             :   GEN z;
     106        2450 :   switch(d)
     107             :   {
     108           0 :     case 1: z = gen_1; break;
     109         931 :     case 2: z = gen_m1; break;
     110        1519 :     default: z = mkpolmod(pol_x(0), polcyclo(d,0));
     111             :   }
     112        2450 :   init_CHI(c,CHI, z);
     113        2450 : }
     114             : /* as t_COMPLEX */
     115             : static void
     116        1526 : init_CHI_C(CHI_t *c, GEN CHI) {
     117        1526 :   init_CHI(c,CHI, gel(CHI,2));
     118        1526 : }
     119             : 
     120             : typedef struct {
     121             :   long r; /* rank = lg(gen) */
     122             :   GEN j; /* current elt is gen[1]^j[1] ... gen[r]^j[r] */
     123             :   GEN cyc; /* t_VECSMALL of elementary divisors */
     124             : } GROUP_t;
     125             : 
     126             : static int
     127      680988 : NextElt(GROUP_t *G)
     128             : {
     129      680988 :   long i = 1;
     130      680988 :   if (G->r == 0) return 0; /* no more elt */
     131      752493 :   while (++G->j[i] == G->cyc[i]) /* from 0 to cyc[i]-1 */
     132             :   {
     133       72289 :     G->j[i] = 0;
     134       72289 :     if (++i > G->r) return 0; /* no more elt */
     135             :   }
     136      680204 :   return i; /* we have multiplied by gen[i] */
     137             : }
     138             : 
     139             : /* enumerate all group elements; trivial elt comes last */
     140             : GEN
     141       42399 : cyc2elts(GEN cyc)
     142             : {
     143             :   long i, n;
     144             :   GEN z;
     145             :   GROUP_t G;
     146             : 
     147       42399 :   G.cyc = typ(cyc)==t_VECSMALL? cyc: gtovecsmall(cyc);
     148       42399 :   n = zv_prod(G.cyc);
     149       42399 :   G.r = lg(cyc)-1;
     150       42399 :   G.j = zero_zv(G.r);
     151             : 
     152       42399 :   z = cgetg(n+1, t_VEC);
     153       42399 :   gel(z,n) = leafcopy(G.j); /* trivial elt comes last */
     154      672434 :   for  (i = 1; i < n; i++)
     155             :   {
     156      630035 :     (void)NextElt(&G);
     157      630035 :     gel(z,i) = leafcopy(G.j);
     158             :   }
     159       42399 :   return z;
     160             : }
     161             : 
     162             : /* nchi: a character given by a vector [d, (c_i)], e.g. from char_normalize
     163             :  * such that chi(x) = e((c . log(x)) / d) where log(x) on bnr.gen */
     164             : static GEN
     165        3619 : get_Char(GEN nchi, long prec)
     166        3619 : { return mkvec2(nchi, rootsof1_cx(gel(nchi,1), prec)); }
     167             : 
     168             : /* prime divisors of conductor */
     169             : static GEN
     170         448 : divcond(GEN bnr) {GEN bid = bnr_get_bid(bnr); return gel(bid_get_fact(bid),1);}
     171             : 
     172             : /* vector of prime ideals dividing bnr but not bnrc */
     173             : static GEN
     174         161 : get_prdiff(GEN D, GEN Dc)
     175             : {
     176         161 :   long n, i, l  = lg(D);
     177         161 :   GEN diff = cgetg(l, t_COL);
     178         448 :   for (n = i = 1; i < l; i++)
     179         287 :     if (!tablesearch(Dc, gel(D,i), &cmp_prime_ideal)) gel(diff,n++) = gel(D,i);
     180         161 :   setlg(diff, n); return diff;
     181             : }
     182             : 
     183             : #define ch_prec(x) realprec(gel(x,1))
     184             : #define ch_C(x)    gel(x,1)
     185             : #define ch_bnr(x)  gel(x,2)
     186             : #define ch_3(x)    gel(x,3)
     187             : #define ch_q(x)    gel(x,3)[1]
     188             : #define ch_CHI(x)  gel(x,4)
     189             : #define ch_diff(x) gel(x,5)
     190             : #define ch_CHI0(x) gel(x,6)
     191             : #define ch_small(x) gel(x,7)
     192             : #define ch_comp(x) gel(x,7)[1]
     193             : #define ch_phideg(x) gel(x,7)[2]
     194             : static long
     195        1253 : ch_deg(GEN dtcr) { return chi_get_deg(ch_CHI(dtcr)); }
     196             : 
     197             : /********************************************************************/
     198             : /*                    1rst part: find the field K                   */
     199             : /********************************************************************/
     200             : static GEN AllStark(GEN data, long flag, long prec);
     201             : 
     202             : /* Columns of C [HNF] give the generators of a subgroup of the finite abelian
     203             :  * group A [ in terms of implicit generators ], compute data to work in A/C:
     204             :  * 1) order
     205             :  * 2) structure
     206             :  * 3) the matrix A ->> A/C
     207             :  * 4) the subgroup C */
     208             : static GEN
     209        1302 : InitQuotient(GEN C)
     210             : {
     211        1302 :   GEN U, D = ZM_snfall_i(C, &U, NULL, 1), h = ZV_prod(D);
     212        1302 :   return mkvec5(h, D, U, C, cyc_normalize(D));
     213             : }
     214             : 
     215             : /* lift chi character on A/C [Qt from InitQuotient] to character on A [cyc]*/
     216             : static GEN
     217        3465 : LiftChar(GEN Qt, GEN cyc, GEN chi)
     218             : {
     219        3465 :   GEN ncyc = gel(Qt,5), U = gel(Qt,3), nchi = char_normalize(chi, ncyc);
     220        3465 :   GEN c = ZV_ZM_mul(gel(nchi,2), U), d = gel(nchi,1);
     221        3465 :   return char_denormalize(cyc, d, c);
     222             : }
     223             : 
     224             : /* Let C be a subgroup, system of representatives of the quotient */
     225             : static GEN
     226         322 : subgroup_classes(GEN C)
     227             : {
     228         322 :   GEN U, D = ZM_snfall_i(C, &U, NULL, 1), e = cyc2elts(D);
     229         322 :   long i, l = lg(e);
     230             : 
     231         322 :   if (ZM_isidentity(U))
     232        1946 :     for (i = 1; i < l; i++) (void)vecsmall_to_vec_inplace(gel(e,i));
     233             :   else
     234             :   {
     235          14 :     GEN Ui = ZM_inv(U,NULL);
     236          84 :     for (i = 1; i < l; i++) gel(e,i) = ZM_zc_mul(Ui, gel(e,i));
     237             :   }
     238         322 :   return e;
     239             : }
     240             : 
     241             : /* Let s: A -> B given by [P,cycA,cycB] A and B, compute the kernel of s. */
     242             : GEN
     243         448 : abmap_kernel(GEN S)
     244             : {
     245         448 :   GEN U, P = gel(S,1), cycA = gel(S,2), DB = diagonal_shallow(gel(S,3));
     246         448 :   long nA = lg(cycA)-1, rk;
     247             : 
     248         448 :   rk = nA + lg(DB) - lg(ZM_hnfall_i(shallowconcat(P, DB), &U, 1));
     249         448 :   return ZM_hnfmodid(matslice(U, 1,nA, 1,rk), cycA);
     250             : }
     251             : /* let H be a subgroup of A; return s(H) */
     252             : GEN
     253        1519 : abmap_subgroup_image(GEN S, GEN H)
     254        1519 : { return ZM_hnfmodid(ZM_mul(gel(S,1), H),  gel(S,3)); }
     255             : 
     256             : /* Let m and n be two moduli such that n|m and let C be a congruence
     257             :    group modulo n, compute the corresponding congruence group modulo m
     258             :    ie the kernel of the map Clk(m) ->> Clk(n)/C */
     259             : static GEN
     260         448 : ComputeKernel(GEN bnrm, GEN bnrn, GEN dtQ)
     261             : {
     262         448 :   pari_sp av = avma;
     263         448 :   GEN S = bnrsurjection(bnrm, bnrn);
     264         448 :   GEN P = ZM_mul(gel(dtQ,3), gel(S,1));
     265         448 :   return gerepileupto(av, abmap_kernel(mkvec3(P, gel(S,2), gel(dtQ,2))));
     266             : }
     267             : 
     268             : static long
     269        1169 : cyc_is_cyclic(GEN cyc) { return lg(cyc) <= 2 || equali1(gel(cyc,2)); }
     270             : 
     271             : /* Let H be a subgroup of cl(bnr)/sugbroup, return 1 if
     272             :    cl(bnr)/subgoup/H is cyclic and the signature of the
     273             :    corresponding field is equal to sig and no finite prime
     274             :    dividing cond(bnr) is totally split in this field. Return 0
     275             :    otherwise. */
     276             : static long
     277         518 : IsGoodSubgroup(GEN H, GEN bnr, GEN map)
     278             : {
     279         518 :   pari_sp av = avma;
     280             :   GEN S, mod, modH, p1, U, P, PH, bnrH, iH, qH;
     281             :   long j;
     282             : 
     283         518 :   p1 = InitQuotient(H);
     284             :   /* quotient is non cyclic */
     285         518 :   if (!cyc_is_cyclic(gel(p1,2))) return gc_long(av,0);
     286             : 
     287         252 :   (void)ZM_hnfall_i(shallowconcat(map,H), &U, 0);
     288         252 :   setlg(U, lg(H));
     289         924 :   for (j = 1; j < lg(U); j++) setlg(gel(U,j), lg(H));
     290         252 :   p1 = ZM_hnfmodid(U, bnr_get_cyc(bnr)); /* H as a subgroup of bnr */
     291         252 :   modH = bnrconductor_raw(bnr, p1);
     292         252 :   mod  = bnr_get_mod(bnr);
     293             : 
     294             :   /* is the signature correct? */
     295         252 :   if (!gequal(gel(modH,2), gel(mod,2))) return gc_long(av, 0);
     296             : 
     297             :   /* finite part are the same: OK */
     298         182 :   if (gequal(gel(modH,1), gel(mod,1))) return gc_long(av, 1);
     299             : 
     300             :   /* need to check the splitting of primes dividing mod but not modH */
     301          63 :   bnrH = Buchray(bnr, modH, nf_INIT);
     302          63 :   P = divcond(bnr);
     303          63 :   PH = divcond(bnrH);
     304          63 :   S = bnrsurjection(bnr, bnrH);
     305             :   /* H as a subgroup of bnrH */
     306          63 :   iH = abmap_subgroup_image(S, p1);
     307          63 :   qH = InitQuotient(iH);
     308         203 :   for (j = 1; j < lg(P); j++)
     309             :   {
     310         161 :     GEN pr = gel(P, j), e;
     311             :     /* if pr divides modH, it is ramified, so it's good */
     312         161 :     if (tablesearch(PH, pr, cmp_prime_ideal)) continue;
     313             :     /* inertia degree of pr in bnr(modH)/H is charorder(cycH, e) */
     314          56 :     e = ZM_ZC_mul(gel(qH,3), isprincipalray(bnrH, pr));
     315          56 :     e = ZV_ZV_mod(e, gel(qH,2));
     316          56 :     if (ZV_equal0(e)) return gc_long(av,0); /* f = 1 */
     317             :   }
     318          42 :   return gc_long(av,1);
     319             : }
     320             : 
     321             : /* compute list of nontrivial characters trivial on H, modulo complex
     322             :  * conjugation. If flag is set, impose a nontrivial conductor at infinity */
     323             : static GEN
     324         392 : AllChars(GEN bnr, GEN dtQ, long flag)
     325             : {
     326         392 :   GEN v, vchi, cyc = bnr_get_cyc(bnr);
     327         392 :   long n, i, hD = itos(gel(dtQ,1));
     328             :   hashtable *S;
     329             : 
     330         392 :   v = cgetg(hD+1, t_VEC); /* nonconjugate chars */
     331         392 :   vchi = cyc2elts(gel(dtQ,2));
     332         392 :   S = hash_create(hD, (ulong(*)(void*))&hash_GEN,
     333             :                   (int(*)(void*,void*))&ZV_equal, 1);
     334        3857 :   for (i = n = 1; i < hD; i++) /* remove i = hD: trivial char */
     335             :   { /* lift a character of D in Clk(m) */
     336        3465 :     GEN F, lchi = LiftChar(dtQ, cyc, zv_to_ZV(gel(vchi,i))), cchi = NULL;
     337             : 
     338        3465 :     if (hash_search(S, lchi)) continue;
     339        2653 :     F = bnrconductor_raw(bnr, lchi);
     340        2653 :     if (flag && gequal0(gel(F,2))) continue; /* f_oo(chi) trivial ? */
     341             : 
     342        1267 :     if (abscmpiu(charorder(cyc,lchi), 2) > 0)
     343             :     { /* nonreal chi: add its conjugate character to S */
     344         812 :       cchi = charconj(cyc, lchi);
     345         812 :       hash_insert(S, cchi, (void*)1);
     346             :     }
     347        1267 :     gel(v, n++) = cchi? mkvec3(lchi, F, cchi): mkvec2(lchi, F);
     348             :   }
     349         392 :   setlg(v, n); return v;
     350             : }
     351             : 
     352             : static GEN InitChar(GEN bnr, GEN CR, long flag, long prec);
     353             : static void CharNewPrec(GEN data, long prec);
     354             : 
     355             : /* Given a conductor and a subgroups, return the corresponding complexity and
     356             :  * precision required using quickpol. Fill data[5] with dataCR */
     357             : static long
     358         322 : CplxModulus(GEN data, long *newprec)
     359             : {
     360         322 :   long dprec = DEFAULTPREC;
     361         322 :   pari_sp av = avma;
     362             :   for (;;)
     363           0 :   {
     364         322 :     GEN cpl, pol = AllStark(data, -1, dprec);
     365         322 :     cpl = RgX_fpnorml2(pol, LOWDEFAULTPREC);
     366         322 :     dprec = maxss(dprec, nbits2extraprec(gexpo(pol))) + EXTRAPREC64;
     367         322 :     if (!gequal0(cpl)) { *newprec = dprec; return gexpo(cpl); }
     368           0 :     set_avma(av);
     369           0 :     if (DEBUGLEVEL>1) pari_warn(warnprec, "CplxModulus", dprec);
     370           0 :     CharNewPrec(data, dprec);
     371             :   }
     372             : }
     373             : 
     374             : /* return A \cap B in abelian group defined by cyc. NULL = whole group */
     375             : static GEN
     376         567 : subgp_intersect(GEN cyc, GEN A, GEN B)
     377             : {
     378             :   GEN H, U;
     379             :   long k, lH;
     380         567 :   if (!A) return B;
     381         224 :   if (!B) return A;
     382         224 :   H = ZM_hnfall_i(shallowconcat(A,B), &U, 1);
     383         224 :   setlg(U, lg(A)); lH = lg(H);
     384         798 :   for (k = 1; k < lg(U); k++) setlg(gel(U,k), lH);
     385         224 :   return ZM_hnfmodid(ZM_mul(A,U), cyc);
     386             : }
     387             : 
     388             : static void CharNewPrec(GEN dataCR, long prec);
     389             : /* Let (f,C) be a conductor without infinite part and a congruence group mod f.
     390             :  * Compute (m,D) such that D is a congruence group of conductor m, f | m,
     391             :  * divisible by all the infinite places but one, D is a subgroup of index 2 of
     392             :  * Cm = Ker: Clk(m) -> Clk(f)/C. Consider further the subgroups H of Clk(m)/D
     393             :  * with cyclic quotient Clk(m)/H such that no place dividing m is totally split
     394             :  * in the extension KH corresponding to H: we want their intersection to be
     395             :  * trivial. These H correspond to (the kernels of Galois orbits of) characters
     396             :  * chi of Clk(m)/D such that chi(log_gen_arch(m_oo)) != 1 and for all pr | m
     397             :  * we either have
     398             :  * - chi(log_gen_pr(pr,1)) != 1 [pr | cond(chi) => ramified in KH]
     399             :  * - or [pr \nmid cond(chi)] chi lifted to Clk(m/pr^oo) is not trivial at pr.
     400             :  * We want the map from Clk(m)/D given by the vector of such characters to have
     401             :  * trivial kernel. Return bnr(m), D, Ck(m)/D and Clk(m)/Cm */
     402             : static GEN
     403         322 : FindModulus(GEN bnr, GEN dtQ, long *newprec)
     404             : {
     405         322 :   const long LIMNORM = 400;
     406         322 :   long n, i, maxnorm, minnorm, N, pr, rb, iscyc, olde = LONG_MAX;
     407         322 :   pari_sp av = avma;
     408         322 :   GEN bnf, nf, f, varch, m, rep = NULL;
     409             : 
     410         322 :   bnf = bnr_get_bnf(bnr);
     411         322 :   nf  = bnf_get_nf(bnf);
     412         322 :   N   = nf_get_degree(nf);
     413         322 :   f   = gel(bnr_get_mod(bnr), 1);
     414             : 
     415             :   /* if cpl < rb, it is not necessary to try another modulus */
     416         322 :   rb = expi( powii(mulii(nf_get_disc(nf), ZM_det_triangular(f)),
     417             :                    gmul2n(bnr_get_no(bnr), 3)) );
     418             : 
     419             :   /* Initialization of the possible infinite part */
     420         322 :   varch = cgetg(N+1,t_VEC);
     421        1106 :   for (i = 1; i <= N; i++)
     422             :   {
     423         784 :     GEN a = const_vec(N,gen_1);
     424         784 :     gel(a, N+1-i) = gen_0;
     425         784 :     gel(varch, i) = a;
     426             :   }
     427         322 :   m = cgetg(3, t_VEC);
     428             : 
     429             :   /* Go from minnorm up to maxnorm; if necessary, increase these values.
     430             :    * If the extension is cyclic then a suitable conductor exists and we go on
     431             :    * until we find it. Else, stop at norm LIMNORM. */
     432         322 :   minnorm = 1;
     433         322 :   maxnorm = 50;
     434         322 :   iscyc = cyc_is_cyclic(gel(dtQ,2));
     435             : 
     436         322 :   if (DEBUGLEVEL>1)
     437           0 :     err_printf("Looking for a modulus of norm: ");
     438             : 
     439             :   for(;;)
     440           0 :   {
     441         322 :     GEN listid = ideallist0(nf, maxnorm, 4+8); /* ideals of norm <= maxnorm */
     442         322 :     pari_sp av1 = avma;
     443        1463 :     for (n = minnorm; n <= maxnorm; n++, set_avma(av1))
     444             :     {
     445        1463 :       GEN idnormn = gel(listid,n);
     446        1463 :       long nbidnn  = lg(idnormn) - 1;
     447        1463 :       if (DEBUGLEVEL>1) err_printf(" %ld", n);
     448        2296 :       for (i = 1; i <= nbidnn; i++)
     449             :       { /* finite part of the conductor */
     450             :         long s;
     451             : 
     452        1155 :         gel(m,1) = idealmul(nf, f, gel(idnormn,i));
     453        3213 :         for (s = 1; s <= N; s++)
     454             :         { /* infinite part */
     455             :           GEN candD, Cm, bnrm;
     456             :           long lD, c;
     457             : 
     458        2380 :           gel(m,2) = gel(varch,s);
     459             :           /* compute Clk(m), check if m is a conductor */
     460        2380 :           bnrm = Buchray(bnf, m, nf_INIT);
     461        2380 :           if (!bnrisconductor(bnrm, NULL)) continue;
     462             : 
     463             :           /* compute Im(C) in Clk(m)... */
     464         448 :           Cm = ComputeKernel(bnrm, bnr, dtQ);
     465             :           /* ... and its subgroups of index 2 with conductor m */
     466         448 :           candD = subgrouplist_cond_sub(bnrm, Cm, mkvec(gen_2));
     467         448 :           lD = lg(candD);
     468         455 :           for (c = 1; c < lD; c++)
     469             :           {
     470         329 :             GEN data, CR, D = gel(candD,c), QD = InitQuotient(D);
     471         329 :             GEN ord = gel(QD,1), cyc = gel(QD,2), map = gel(QD,3);
     472             :             long e;
     473             : 
     474         329 :             if (!cyc_is_cyclic(cyc)) /* cyclic => suitable, else test */
     475             :             {
     476          77 :               GEN lH = subgrouplist(cyc, NULL), IK = NULL;
     477          77 :               long j, ok = 0;
     478         574 :               for (j = 1; j < lg(lH); j++)
     479             :               {
     480         567 :                 GEN H = gel(lH, j), IH = subgp_intersect(cyc, IK, H);
     481             :                 /* if H > IK, no need to test H */
     482         567 :                 if (IK && gidentical(IH, IK)) continue;
     483         518 :                 if (IsGoodSubgroup(H, bnrm, map))
     484             :                 {
     485         161 :                   IK = IH; /* intersection of all good subgroups */
     486         161 :                   if (equalii(ord, ZM_det_triangular(IK))) { ok = 1; break; }
     487             :                 }
     488             :               }
     489          77 :               if (!ok) continue;
     490             :             }
     491         322 :             CR = InitChar(bnrm, AllChars(bnrm, QD, 1), 0, DEFAULTPREC);
     492         322 :             data = mkvec4(bnrm, D, subgroup_classes(Cm), CR);
     493         322 :             if (DEBUGLEVEL>1)
     494           0 :               err_printf("\nTrying modulus = %Ps and subgroup = %Ps\n",
     495             :                          bnr_get_mod(bnrm), D);
     496         322 :             e = CplxModulus(data, &pr);
     497         322 :             if (DEBUGLEVEL>1) err_printf("cpl = 2^%ld\n", e);
     498         322 :             if (e < olde)
     499             :             {
     500         322 :               guncloneNULL(rep); rep = gclone(data);
     501         322 :               *newprec = pr; olde = e;
     502             :             }
     503         322 :             if (olde < rb) goto END; /* OK */
     504           0 :             if (DEBUGLEVEL>1) err_printf("Trying to find another modulus...");
     505             :           }
     506             :         }
     507         833 :         if (rep) goto END; /* OK */
     508             :       }
     509             :     }
     510             :     /* if necessary compute more ideals */
     511           0 :     minnorm = maxnorm;
     512           0 :     maxnorm <<= 1;
     513           0 :     if (!iscyc && maxnorm > LIMNORM) return NULL;
     514             :   }
     515         322 : END:
     516         322 :   if (DEBUGLEVEL>1)
     517           0 :     err_printf("No, we're done!\nModulus = %Ps and subgroup = %Ps\n",
     518           0 :                bnr_get_mod(gel(rep,1)), gel(rep,2));
     519         322 :   CharNewPrec(rep, *newprec); return gerepilecopy(av, rep);
     520             : }
     521             : 
     522             : /********************************************************************/
     523             : /*                      2nd part: compute W(X)                      */
     524             : /********************************************************************/
     525             : 
     526             : /* find ilambda s.t. Diff*f*ilambda integral and coprime to f
     527             :    and ilambda >> 0 at foo, fa = factorization of f */
     528             : static GEN
     529         784 : get_ilambda(GEN nf, GEN fa, GEN foo)
     530             : {
     531         784 :   GEN x, w, E2, P = gel(fa,1), E = gel(fa,2), D = nf_get_diff(nf);
     532         784 :   long i, l = lg(P);
     533         784 :   if (l == 1) return gen_1;
     534         651 :   w = cgetg(l, t_VEC);
     535         651 :   E2 = cgetg(l, t_COL);
     536        1428 :   for (i = 1; i < l; i++)
     537             :   {
     538         777 :     GEN pr = gel(P,i), t = pr_get_tau(pr);
     539         777 :     long e = itou(gel(E,i)), v = idealval(nf, D, pr);
     540         777 :     if (v) { D = idealdivpowprime(nf, D, pr, utoipos(v)); e += v; }
     541         777 :     gel(E2,i) = stoi(e+1);
     542         777 :     if (typ(t) == t_MAT) t = gel(t,1);
     543         777 :     gel(w,i) = gdiv(nfpow(nf, t, stoi(e)), powiu(pr_get_p(pr),e));
     544             :   }
     545         651 :   x = mkmat2(P, E2);
     546         651 :   return idealchinese(nf, mkvec2(x, foo), w);
     547             : }
     548             : /* compute the list of W(chi) such that Ld(s,chi) = W(chi) Ld(1 - s, chi*),
     549             :  * for all chi in LCHI. All chi have the same conductor (= cond(bnr)). */
     550             : static GEN
     551         980 : ArtinNumber(GEN bnr, GEN LCHI, long prec)
     552             : {
     553         980 :   long ic, i, j, nz, nChar = lg(LCHI)-1;
     554             :   pari_sp av2;
     555             :   GEN sqrtnc, cond, condZ, cond0, cond1, nf, T, cyc, vN, vB, diff, vt, idh;
     556             :   GEN zid, gen, z, nchi, indW, W, classe, s0, s, den, ilambda, sarch;
     557             :   CHI_t **lC;
     558             :   GROUP_t G;
     559             : 
     560         980 :   lC = (CHI_t**)new_chunk(nChar + 1);
     561         980 :   indW = cgetg(nChar + 1, t_VECSMALL);
     562         980 :   W = cgetg(nChar + 1, t_VEC);
     563        3353 :   for (ic = 0, i = 1; i <= nChar; i++)
     564             :   {
     565        2373 :     GEN CHI = gel(LCHI,i);
     566        2373 :     if (chi_get_deg(CHI) <= 2) { gel(W,i) = gen_1; continue; }
     567        1526 :     ic++; indW[ic] = i;
     568        1526 :     lC[ic] = (CHI_t*)new_chunk(sizeof(CHI_t));
     569        1526 :     init_CHI_C(lC[ic], CHI);
     570             :   }
     571         980 :   if (!ic) return W;
     572         784 :   nChar = ic;
     573             : 
     574         784 :   nf    = bnr_get_nf(bnr);
     575         784 :   diff  = nf_get_diff(nf);
     576         784 :   T     = nf_get_Tr(nf);
     577         784 :   cond  = bnr_get_mod(bnr);
     578         784 :   cond0 = gel(cond,1); condZ = gcoeff(cond0,1,1);
     579         784 :   cond1 = gel(cond,2);
     580             : 
     581         784 :   sqrtnc = gsqrt(idealnorm(nf, cond0), prec);
     582         784 :   ilambda = get_ilambda(nf, bid_get_fact(bnr_get_bid(bnr)), cond1);
     583         784 :   idh = idealmul(nf, ilambda, idealmul(nf, diff, cond0)); /* integral */
     584         784 :   ilambda = Q_remove_denom(ilambda, &den);
     585         784 :   z = den? rootsof1_cx(den, prec): NULL;
     586             : 
     587             :   /* compute a system of generators of (Ok/cond)^*, we'll make them
     588             :    * cond1-positive in the main loop */
     589         784 :   zid = Idealstar(nf, cond0, nf_GEN);
     590         784 :   cyc = abgrp_get_cyc(zid);
     591         784 :   gen = abgrp_get_gen(zid);
     592         784 :   nz = lg(gen) - 1;
     593         784 :   sarch = nfarchstar(nf, cond0, vec01_to_indices(cond1));
     594             : 
     595         784 :   nchi = cgetg(nChar+1, t_VEC);
     596        2310 :   for (ic = 1; ic <= nChar; ic++) gel(nchi,ic) = cgetg(nz + 1, t_VECSMALL);
     597        1603 :   for (i = 1; i <= nz; i++)
     598             :   {
     599         819 :     if (is_bigint(gel(cyc,i)))
     600           0 :       pari_err_OVERFLOW("ArtinNumber [conductor too large]");
     601         819 :     gel(gen,i) = set_sign_mod_divisor(nf, NULL, gel(gen,i), sarch);
     602         819 :     classe = isprincipalray(bnr, gel(gen,i));
     603        2485 :     for (ic = 1; ic <= nChar; ic++) {
     604        1666 :       GEN n = gel(nchi,ic);
     605        1666 :       n[i] = CHI_eval_n(lC[ic], classe);
     606             :     }
     607             :   }
     608             : 
     609             :   /* Sum chi(beta) * exp(2i * Pi * Tr(beta * ilambda) where beta
     610             :      runs through the classes of (Ok/cond0)^* and beta cond1-positive */
     611         784 :   vt = gel(T,1); /* ( Tr(w_i) )_i */
     612         784 :   if (typ(ilambda) == t_COL)
     613         560 :     vt = ZV_ZM_mul(vt, zk_multable(nf, ilambda));
     614             :   else
     615         224 :     vt = ZC_Z_mul(vt, ilambda);
     616             :   /*vt = den . (Tr(w_i * ilambda))_i */
     617         784 :   G.cyc = gtovecsmall(cyc);
     618         784 :   G.r = nz;
     619         784 :   G.j = zero_zv(nz);
     620         784 :   vN = zero_Flm_copy(nz, nChar);
     621             : 
     622         784 :   av2 = avma;
     623         784 :   vB = const_vec(nz, gen_1);
     624         784 :   s0 = z? powgi(z, modii(gel(vt,1), den)): gen_1; /* for beta = 1 */
     625         784 :   s = const_vec(nChar, s0);
     626             : 
     627       50953 :   while ( (i = NextElt(&G)) )
     628             :   {
     629       50169 :     GEN b = gel(vB,i);
     630       50169 :     b = nfmuli(nf, b, gel(gen,i));
     631       50169 :     b = typ(b) == t_COL? FpC_red(b, condZ): modii(b, condZ);
     632      100674 :     for (j=1; j<=i; j++) gel(vB,j) = b;
     633             : 
     634      208607 :     for (ic = 1; ic <= nChar; ic++)
     635             :     {
     636      158438 :       GEN v = gel(vN,ic), n = gel(nchi,ic);
     637      158438 :       v[i] = Fl_add(v[i], n[i], lC[ic]->ord);
     638      158998 :       for (j=1; j<i; j++) v[j] = v[i];
     639             :     }
     640             : 
     641       50169 :     gel(vB,i) = b = set_sign_mod_divisor(nf, NULL, b, sarch);
     642       50169 :     if (!z)
     643           0 :       s0 = gen_1;
     644             :     else
     645             :     {
     646       50169 :       b = typ(b) == t_COL? ZV_dotproduct(vt, b): mulii(gel(vt,1),b);
     647       50169 :       s0 = powgi(z, modii(b,den));
     648             :     }
     649      208607 :     for (ic = 1; ic <= nChar; ic++)
     650             :     {
     651      158438 :       GEN v = gel(vN,ic), val = lC[ic]->val[ v[i] ];
     652      158438 :       gel(s,ic) = gadd(gel(s,ic), gmul(val, s0));
     653             :     }
     654             : 
     655       50169 :     if (gc_needed(av2, 1))
     656             :     {
     657           0 :       if (DEBUGMEM > 1) pari_warn(warnmem,"ArtinNumber");
     658           0 :       gerepileall(av2, 2, &s, &vB);
     659             :     }
     660             :   }
     661             : 
     662         784 :   classe = isprincipalray(bnr, idh);
     663         784 :   z = powIs(- (lg(gel(sarch,1))-1));
     664             : 
     665        2310 :   for (ic = 1; ic <= nChar; ic++)
     666             :   {
     667        1526 :     s0 = gmul(gel(s,ic), CHI_eval(lC[ic], classe));
     668        1526 :     gel(W, indW[ic]) = gmul(gdiv(s0, sqrtnc), z);
     669             :   }
     670         784 :   return W;
     671             : }
     672             : 
     673             : static GEN
     674         707 : AllArtinNumbers(GEN CR, long prec)
     675             : {
     676         707 :   pari_sp av = avma;
     677         707 :   GEN vChar = gel(CR,1), dataCR = gel(CR,2);
     678         707 :   long j, k, cl = lg(dataCR) - 1, J = lg(vChar)-1;
     679         707 :   GEN W = cgetg(cl+1,t_VEC), WbyCond, LCHI;
     680             : 
     681        1610 :   for (j = 1; j <= J; j++)
     682             :   {
     683         903 :     GEN LChar = gel(vChar,j), ldata = vecpermute(dataCR, LChar);
     684         903 :     GEN dtcr = gel(ldata,1), bnr = ch_bnr(dtcr);
     685         903 :     long l = lg(LChar);
     686             : 
     687         903 :     if (DEBUGLEVEL>1)
     688           0 :       err_printf("* Root Number: cond. no %ld/%ld (%ld chars)\n", j, J, l-1);
     689         903 :     LCHI = cgetg(l, t_VEC);
     690        3199 :     for (k = 1; k < l; k++) gel(LCHI,k) = ch_CHI0(gel(ldata,k));
     691         903 :     WbyCond = ArtinNumber(bnr, LCHI, prec);
     692        3199 :     for (k = 1; k < l; k++) gel(W,LChar[k]) = gel(WbyCond,k);
     693             :   }
     694         707 :   return gerepilecopy(av, W);
     695             : }
     696             : 
     697             : /* compute the constant W of the functional equation of
     698             :    Lambda(chi). If flag = 1 then chi is assumed to be primitive */
     699             : GEN
     700          77 : bnrrootnumber(GEN bnr, GEN chi, long flag, long prec)
     701             : {
     702          77 :   pari_sp av = avma;
     703             :   GEN cyc, W;
     704             : 
     705          77 :   if (flag < 0 || flag > 1) pari_err_FLAG("bnrrootnumber");
     706          77 :   checkbnr(bnr);
     707          77 :   if (flag)
     708             :   {
     709           0 :     cyc = bnr_get_cyc(bnr);
     710           0 :     if (!char_check(cyc,chi)) pari_err_TYPE("bnrrootnumber [character]", chi);
     711             :   }
     712             :   else
     713             :   {
     714          77 :     bnr_char_sanitize(&bnr, &chi);
     715          77 :     cyc = bnr_get_cyc(bnr);
     716             :   }
     717          77 :   chi = char_normalize(chi, cyc_normalize(cyc));
     718          77 :   chi = get_Char(chi, prec);
     719          77 :   W = ArtinNumber(bnr, mkvec(chi), prec);
     720          77 :   return gerepilecopy(av, gel(W,1));
     721             : }
     722             : 
     723             : /********************************************************************/
     724             : /*               3rd part: initialize the characters                */
     725             : /********************************************************************/
     726             : 
     727             : /* Let chi be a character, A(chi) corresponding to the primes dividing diff
     728             :  * at s = flag. If s = 0, returns [r, A] where r is the order of vanishing
     729             :  * at s = 0 corresponding to diff. */
     730             : static GEN
     731        2044 : AChi(GEN dtcr, long *r, long flag, long prec)
     732             : {
     733        2044 :   GEN A, diff = ch_diff(dtcr), bnrc = ch_bnr(dtcr), chi  = ch_CHI0(dtcr);
     734        2044 :   long i, l = lg(diff);
     735             : 
     736        2044 :   A = gen_1; *r = 0;
     737        2149 :   for (i = 1; i < l; i++)
     738             :   {
     739         105 :     GEN B, pr = gel(diff,i), z = CharEval(chi, isprincipalray(bnrc, pr));
     740         105 :     if (flag)
     741           0 :       B = gsubsg(1, gdiv(z, pr_norm(pr)));
     742         105 :     else if (gequal1(z))
     743             :     {
     744          21 :       B = glog(pr_norm(pr), prec);
     745          21 :       (*r)++;
     746             :     }
     747             :     else
     748          84 :       B = gsubsg(1, z);
     749         105 :     A = gmul(A, B);
     750             :   }
     751        2044 :   return A;
     752             : }
     753             : /* simplified version of Achi: return 1 if L(0,chi) = 0 */
     754             : static int
     755        1029 : L_vanishes_at_0(GEN D)
     756             : {
     757        1029 :   GEN diff = ch_diff(D), bnrc = ch_bnr(D), chi  = ch_CHI0(D);
     758        1029 :   long i, l = lg(diff);
     759        1071 :   for (i = 1; i < l; i++)
     760             :   {
     761          56 :     GEN pr = gel(diff,i);
     762          56 :     if (!CharEval_n(chi, isprincipalray(bnrc, pr))) return 1;
     763             :   }
     764        1015 :   return 0;
     765             : }
     766             : 
     767             : static GEN
     768         532 : _data3(GEN arch, long r2)
     769             : {
     770         532 :   GEN z = cgetg(4, t_VECSMALL);
     771         532 :   long i, r1 = lg(arch) - 1, q = 0;
     772        1701 :   for (i = 1; i <= r1; i++) if (signe(gel(arch,i))) q++;
     773         532 :   z[1] = q;
     774         532 :   z[2] = r1 - q;
     775         532 :   z[3] = r2; return z;
     776             : }
     777             : static void
     778        1561 : ch_get3(GEN dtcr, long *a, long *b, long *c)
     779        1561 : { GEN v = ch_3(dtcr); *a = v[1]; *b = v[2]; *c = v[3]; }
     780             : static GEN
     781         707 : get_C(GEN nf, long prec)
     782             : {
     783         707 :   long r2 = nf_get_r2(nf), N = nf_get_degree(nf);
     784         707 :   return gmul2n(sqrtr_abs(divir(nf_get_disc(nf), powru(mppi(prec),N))), -r2);
     785             : }
     786             : /* sort chars according to conductor */
     787             : static GEN
     788         385 : sortChars(GEN ch)
     789             : {
     790         385 :   long j, l = lg(ch);
     791         385 :   GEN F = cgetg(l, t_VEC);
     792        1652 :   for (j = 1; j < l; j++) gel(F, j) = gmael(ch,j,2);
     793         385 :   return vec_equiv(F);
     794             : }
     795             : 
     796             : /* Given a list [chi, F = cond(chi)] of characters over Cl(bnr), return
     797             :  * [vChar, dataCR], where vChar contains the equivalence classes of
     798             :  * characters with the same conductor, and dataCR contains for each character:
     799             :  * - bnr(F)
     800             :  * - the constant C(F) [t_REAL]
     801             :  * - [q, r1 - q, r2, rc] where
     802             :  *      q = number of real places in F
     803             :  *      rc = max{r1 + r2 - q + 1, r2 + q}
     804             :  * - diff(chi) primes dividing m but not F
     805             :  * - chi in bnr(m)
     806             :  * - chi in bnr(F).
     807             :  * If all is unset, only compute characters s.t. L(chi,0) != 0 */
     808             : static GEN
     809         385 : InitChar(GEN bnr, GEN ch, long all, long prec)
     810             : {
     811         385 :   GEN bnf = checkbnf(bnr), nf = bnf_get_nf(bnf), mod = bnr_get_mod(bnr);
     812         385 :   GEN C, dataCR, ncyc, vChar = sortChars(ch);
     813         385 :   long n, l, r2 = nf_get_r2(nf), prec2 = precdbl(prec) + EXTRAPREC64;
     814         385 :   long lv = lg(vChar);
     815             : 
     816         385 :   C = get_C(nf, prec2);
     817         385 :   ncyc = cyc_normalize(bnr_get_cyc(bnr));
     818             : 
     819         385 :   dataCR = cgetg_copy(ch, &l);
     820         917 :   for (n = 1; n < lv; n++)
     821             :   {
     822         532 :     GEN D, bnrc, v = gel(vChar, n); /* indices of chars of given conductor */
     823         532 :     long a, i = v[1], lc = lg(v);
     824         532 :     GEN F = gmael(ch,i,2);
     825             : 
     826         532 :     gel(dataCR, i) = D = cgetg(8, t_VEC);
     827         532 :     ch_C(D) = mulrr(C, gsqrt(ZM_det_triangular(gel(F,1)), prec2));
     828         532 :     ch_3(D) = _data3(gel(F,2), r2);
     829         532 :     if (gequal(F, mod))
     830             :     {
     831         371 :       ch_bnr(D) = bnrc = bnr;
     832         371 :       ch_diff(D) = cgetg(1, t_VEC);
     833             :     }
     834             :     else
     835             :     {
     836         161 :       ch_bnr(D) = bnrc = Buchray(bnf, F, nf_INIT);
     837         161 :       ch_diff(D) = get_prdiff(divcond(bnr), divcond(bnrc));
     838             :     }
     839        1799 :     for (a = 1; a < lc; a++)
     840             :     {
     841        1267 :       long i = v[a];
     842        1267 :       GEN chi = gmael(ch,i,1);
     843             : 
     844        1267 :       if (a > 1) gel(dataCR, i) = D = leafcopy(D);
     845        1267 :       chi = char_normalize(chi,ncyc);
     846        1267 :       ch_CHI(D) = get_Char(chi, prec2);
     847        1267 :       if (bnrc == bnr)
     848        1050 :         ch_CHI0(D) = ch_CHI(D);
     849             :       else
     850             :       {
     851         217 :         chi = bnrchar_primitive(bnr, chi, bnrc);
     852         217 :         ch_CHI0(D) = get_Char(chi, prec2);
     853             :       }
     854             :       /* set last */
     855        1267 :       ch_small(D) = mkvecsmall2(all || !L_vanishes_at_0(D),
     856        1267 :                                 eulerphiu(itou(gel(chi,1))));
     857             :     }
     858             :   }
     859         385 :   return mkvec2(vChar, dataCR);
     860             : }
     861             : 
     862             : /* recompute dataCR with the new precision, modify bnr components in place */
     863             : static void
     864         322 : CharNewPrec(GEN data, long prec)
     865             : {
     866         322 :   long j, l, prec2 = precdbl(prec) + EXTRAPREC64;
     867         322 :   GEN C, nf, dataCR = gmael(data,4,2), D = gel(dataCR,1);
     868             : 
     869         322 :   if (ch_prec(D) >= prec2) return;
     870         322 :   nf = bnr_get_nf(ch_bnr(D));
     871         322 :   if (nf_get_prec(nf) < prec) nf = nfnewprec_shallow(nf, prec); /* not prec2 */
     872         322 :   C = get_C(nf, prec2); l = lg(dataCR);
     873        1351 :   for (j = 1; j < l; j++)
     874             :   {
     875             :     GEN f0;
     876        1029 :     D = gel(dataCR,j); f0 = gel(bnr_get_mod(ch_bnr(D)), 1);
     877        1029 :     ch_C(D) = mulrr(C, gsqrt(ZM_det_triangular(f0), prec2));
     878        1029 :     gmael(ch_bnr(D), 1, 7) = nf;
     879        1029 :     ch_CHI(D) = get_Char(gel(ch_CHI(D),1), prec2);
     880        1029 :     ch_CHI0(D)= get_Char(gel(ch_CHI0(D),1), prec2);
     881             :   }
     882             : }
     883             : 
     884             : /********************************************************************/
     885             : /*             4th part: compute the coefficients an(chi)           */
     886             : /*                                                                  */
     887             : /* matan entries are arrays of ints containing the coefficients of  */
     888             : /* an(chi) as a polmod modulo polcyclo(order(chi))                     */
     889             : /********************************************************************/
     890             : 
     891             : static void
     892      979939 : _0toCoeff(int *rep, long deg)
     893             : {
     894             :   long i;
     895     4375600 :   for (i=0; i<deg; i++) rep[i] = 0;
     896      979939 : }
     897             : 
     898             : /* transform a polmod into Coeff */
     899             : static void
     900      392055 : Polmod2Coeff(int *rep, GEN polmod, long deg)
     901             : {
     902             :   long i;
     903      392055 :   if (typ(polmod) == t_POLMOD)
     904             :   {
     905      288273 :     GEN pol = gel(polmod,2);
     906      288273 :     long d = degpol(pol);
     907             : 
     908      288273 :     pol += 2;
     909     1226580 :     for (i=0; i<=d; i++) rep[i] = itos(gel(pol,i));
     910      665185 :     for (   ; i<deg; i++) rep[i] = 0;
     911             :   }
     912             :   else
     913             :   {
     914      103782 :     rep[0] = itos(polmod);
     915      112014 :     for (i=1; i<deg; i++) rep[i] = 0;
     916             :   }
     917      392055 : }
     918             : 
     919             : /* initialize a deg * n matrix of ints */
     920             : static int**
     921        4039 : InitMatAn(long n, long deg, long flag)
     922             : {
     923             :   long i, j;
     924        4039 :   int *a, **A = (int**)pari_malloc((n+1)*sizeof(int*));
     925        4039 :   A[0] = NULL;
     926     6109784 :   for (i = 1; i <= n; i++)
     927             :   {
     928     6105745 :     a = (int*)pari_malloc(deg*sizeof(int));
     929     6105745 :     A[i] = a; a[0] = (i == 1 || flag);
     930    19586973 :     for (j = 1; j < deg; j++) a[j] = 0;
     931             :   }
     932        4039 :   return A;
     933             : }
     934             : 
     935             : static void
     936        6321 : FreeMat(int **A, long n)
     937             : {
     938             :   long i;
     939     6124190 :   for (i = 0; i <= n; i++)
     940     6117869 :     if (A[i]) pari_free((void*)A[i]);
     941        6321 :   pari_free((void*)A);
     942        6321 : }
     943             : 
     944             : /* initialize Coeff reduction */
     945             : static int**
     946        2282 : InitReduction(long d, long deg)
     947             : {
     948             :   long j;
     949        2282 :   pari_sp av = avma;
     950             :   int **A;
     951             :   GEN polmod, pol;
     952             : 
     953        2282 :   A   = (int**)pari_malloc(deg*sizeof(int*));
     954        2282 :   pol = polcyclo(d, 0);
     955       10367 :   for (j = 0; j < deg; j++)
     956             :   {
     957        8085 :     A[j] = (int*)pari_malloc(deg*sizeof(int));
     958        8085 :     polmod = gmodulo(pol_xn(deg+j, 0), pol);
     959        8085 :     Polmod2Coeff(A[j], polmod, deg);
     960             :   }
     961             : 
     962        2282 :   set_avma(av); return A;
     963             : }
     964             : 
     965             : #if 0
     966             : void
     967             : pan(int **an, long n, long deg)
     968             : {
     969             :   long i,j;
     970             :   for (i = 1; i <= n; i++)
     971             :   {
     972             :     err_printf("n = %ld: ",i);
     973             :     for (j = 0; j < deg; j++) err_printf("%d ",an[i][j]);
     974             :     err_printf("\n");
     975             :   }
     976             : }
     977             : #endif
     978             : 
     979             : /* returns 0 if c is zero, 1 otherwise. */
     980             : static int
     981     7613478 : IsZero(int* c, long deg)
     982             : {
     983             :   long i;
     984    25816953 :   for (i = 0; i < deg; i++)
     985    20149424 :     if (c[i]) return 0;
     986     5667529 :   return 1;
     987             : }
     988             : 
     989             : /* set c0 <-- c0 * c1 */
     990             : static void
     991     1485934 : MulCoeff(int *c0, int* c1, int** reduc, long deg)
     992             : {
     993             :   long i,j;
     994             :   int c, *T;
     995             : 
     996     1485934 :   if (IsZero(c0,deg)) return;
     997             : 
     998      797592 :   T = (int*)new_chunk(2*deg);
     999     8317090 :   for (i = 0; i < 2*deg; i++)
    1000             :   {
    1001     7519498 :     c = 0;
    1002    81900933 :     for (j = 0; j <= i; j++)
    1003    74381435 :       if (j < deg && j > i - deg) c += c0[j] * c1[i-j];
    1004     7519498 :     T[i] = c;
    1005             :   }
    1006     4557341 :   for (i = 0; i < deg; i++)
    1007             :   {
    1008     3759749 :     c = T[i];
    1009    39070592 :     for (j = 0; j < deg; j++) c += reduc[j][i] * T[deg+j];
    1010     3759749 :     c0[i] = c;
    1011             :   }
    1012             : }
    1013             : 
    1014             : /* c0 <- c0 + c1 * c2 */
    1015             : static void
    1016     6127544 : AddMulCoeff(int *c0, int *c1, int* c2, int** reduc, long deg)
    1017             : {
    1018             :   long i, j;
    1019             :   pari_sp av;
    1020             :   int c, *t;
    1021             : 
    1022     6127544 :   if (IsZero(c2,deg)) return;
    1023     1148357 :   if (!c1) /* c1 == 1 */
    1024             :   {
    1025      706713 :     for (i = 0; i < deg; i++) c0[i] += c2[i];
    1026      290843 :     return;
    1027             :   }
    1028      857514 :   av = avma;
    1029      857514 :   t = (int*)new_chunk(2*deg); /* = c1 * c2, not reduced */
    1030     6579874 :   for (i = 0; i < 2*deg; i++)
    1031             :   {
    1032     5722360 :     c = 0;
    1033    41566476 :     for (j = 0; j <= i; j++)
    1034    35844116 :       if (j < deg && j > i - deg) c += c1[j] * c2[i-j];
    1035     5722360 :     t[i] = c;
    1036             :   }
    1037     3718694 :   for (i = 0; i < deg; i++)
    1038             :   {
    1039     2861180 :     c = t[i];
    1040    19352648 :     for (j = 0; j < deg; j++) c += reduc[j][i] * t[deg+j];
    1041     2861180 :     c0[i] += c;
    1042             :   }
    1043      857514 :   set_avma(av);
    1044             : }
    1045             : 
    1046             : /* evaluate the Coeff. No Garbage collector */
    1047             : static GEN
    1048     3626440 : EvalCoeff(GEN z, int* c, long deg)
    1049             : {
    1050             :   long i,j;
    1051             :   GEN e, r;
    1052             : 
    1053     3626440 :   if (!c) return gen_0;
    1054             : #if 0
    1055             :   /* standard Horner */
    1056             :   e = stoi(c[deg - 1]);
    1057             :   for (i = deg - 2; i >= 0; i--)
    1058             :     e = gadd(stoi(c[i]), gmul(z, e));
    1059             : #else
    1060             :   /* specific attention to sparse polynomials */
    1061     3626440 :   e = NULL;
    1062     5195014 :   for (i = deg-1; i >=0; i=j-1)
    1063             :   {
    1064    12110551 :     for (j=i; c[j] == 0; j--)
    1065    10541977 :       if (j==0)
    1066             :       {
    1067     2969825 :         if (!e) return NULL;
    1068      304833 :         if (i!=j) z = gpowgs(z,i-j+1);
    1069      304833 :         return gmul(e,z);
    1070             :       }
    1071     1568574 :     if (e)
    1072             :     {
    1073      607126 :       r = (i==j)? z: gpowgs(z,i-j+1);
    1074      607126 :       e = gadd(gmul(e,r), stoi(c[j]));
    1075             :     }
    1076             :     else
    1077      961448 :       e = stoi(c[j]);
    1078             :   }
    1079             : #endif
    1080      656615 :   return e;
    1081             : }
    1082             : 
    1083             : /* a2 <- copy the n x m array */
    1084             : static void
    1085      355040 : CopyCoeff(int** a, int** a2, long n, long m)
    1086             : {
    1087             :   long i,j;
    1088             : 
    1089     5243138 :   for (i = 1; i <= n; i++)
    1090             :   {
    1091     4888098 :     int *b = a[i], *b2 = a2[i];
    1092    19248175 :     for (j = 0; j < m; j++) b2[j] = b[j];
    1093             :   }
    1094      355040 : }
    1095             : 
    1096             : static void
    1097      355040 : an_AddMul(int **an,int **an2, long np, long n, long deg, GEN chi, int **reduc)
    1098             : {
    1099      355040 :   GEN chi2 = chi;
    1100             :   long q, qk, k;
    1101      355040 :   int *c, *c2 = (int*)new_chunk(deg);
    1102             : 
    1103      355040 :   CopyCoeff(an, an2, n/np, deg);
    1104      355040 :   for (q=np;;)
    1105             :   {
    1106      388514 :     if (gequal1(chi2)) c = NULL; else { Polmod2Coeff(c2, chi2, deg); c = c2; }
    1107     6516058 :     for(k = 1, qk = q; qk <= n; k++, qk += q)
    1108     6127544 :       AddMulCoeff(an[qk], c, an2[k], reduc, deg);
    1109      388514 :     if (! (q = umuluu_le(q,np, n)) ) break;
    1110             : 
    1111       33474 :     chi2 = gmul(chi2, chi);
    1112             :   }
    1113      355040 : }
    1114             : 
    1115             : /* correct the coefficients an(chi) according with diff(chi) in place */
    1116             : static void
    1117        2282 : CorrectCoeff(GEN dtcr, int** an, int** reduc, long n, long deg)
    1118             : {
    1119        2282 :   pari_sp av = avma;
    1120             :   long lg, j;
    1121             :   pari_sp av1;
    1122             :   int **an2;
    1123             :   GEN bnrc, diff;
    1124             :   CHI_t C;
    1125             : 
    1126        2282 :   diff = ch_diff(dtcr); lg = lg(diff) - 1;
    1127        2282 :   if (!lg) return;
    1128             : 
    1129         168 :   if (DEBUGLEVEL>2) err_printf("diff(CHI) = %Ps", diff);
    1130         168 :   bnrc = ch_bnr(dtcr);
    1131         168 :   init_CHI_alg(&C, ch_CHI0(dtcr));
    1132             : 
    1133         168 :   an2 = InitMatAn(n, deg, 0);
    1134         168 :   av1 = avma;
    1135         364 :   for (j = 1; j <= lg; j++)
    1136             :   {
    1137         196 :     GEN pr = gel(diff,j);
    1138         196 :     long Np = upr_norm(pr);
    1139         196 :     GEN chi  = CHI_eval(&C, isprincipalray(bnrc, pr));
    1140         196 :     an_AddMul(an,an2,Np,n,deg,chi,reduc);
    1141         196 :     set_avma(av1);
    1142             :   }
    1143         168 :   FreeMat(an2, n); set_avma(av);
    1144             : }
    1145             : 
    1146             : /* compute the coefficients an in the general case */
    1147             : static int**
    1148        1589 : ComputeCoeff(GEN dtcr, LISTray *R, long n, long deg)
    1149             : {
    1150        1589 :   pari_sp av = avma, av2;
    1151             :   long i, l;
    1152             :   int **an, **reduc, **an2;
    1153             :   GEN L;
    1154             :   CHI_t C;
    1155             : 
    1156        1589 :   init_CHI_alg(&C, ch_CHI(dtcr));
    1157        1589 :   an  = InitMatAn(n, deg, 0);
    1158        1589 :   an2 = InitMatAn(n, deg, 0);
    1159        1589 :   reduc  = InitReduction(C.ord, deg);
    1160        1589 :   av2 = avma;
    1161             : 
    1162        1589 :   L = R->L1; l = lg(L);
    1163      356433 :   for (i=1; i<l; i++, set_avma(av2))
    1164             :   {
    1165      354844 :     long np = L[i];
    1166      354844 :     GEN chi  = CHI_eval(&C, gel(R->L1ray,i));
    1167      354844 :     an_AddMul(an,an2,np,n,deg,chi,reduc);
    1168             :   }
    1169        1589 :   FreeMat(an2, n);
    1170             : 
    1171        1589 :   CorrectCoeff(dtcr, an, reduc, n, deg);
    1172        1589 :   FreeMat(reduc, deg-1);
    1173        1589 :   set_avma(av); return an;
    1174             : }
    1175             : 
    1176             : /********************************************************************/
    1177             : /*              5th part: compute L-functions at s=1                */
    1178             : /********************************************************************/
    1179             : static void
    1180         427 : deg11(LISTray *R, long p, GEN bnr, GEN pr) {
    1181         427 :   vecsmalltrunc_append(R->L1, p);
    1182         427 :   vectrunc_append(R->L1ray, isprincipalray(bnr, pr));
    1183         427 : }
    1184             : static void
    1185       24337 : deg12(LISTray *R, long p, GEN bnr, GEN pr) {
    1186       24337 :   vecsmalltrunc_append(R->L11, p);
    1187       24337 :   vectrunc_append(R->L11ray, isprincipalray(bnr, pr));
    1188       24337 : }
    1189             : static void
    1190          35 : deg0(LISTray *R, long p) { vecsmalltrunc_append(R->L0, p); }
    1191             : static void
    1192       26244 : deg2(LISTray *R, long p) { vecsmalltrunc_append(R->L2, p); }
    1193             : 
    1194             : static void
    1195         196 : InitPrimesQuad(GEN bnr, ulong N0, LISTray *R)
    1196             : {
    1197         196 :   pari_sp av = avma;
    1198         196 :   GEN bnf = bnr_get_bnf(bnr), F = gel(bnr_get_mod(bnr), 1);
    1199         196 :   GEN v, N, nf = bnf_get_nf(bnf), dk = nf_get_disc(nf);
    1200         196 :   long l = 1 + primepi_upper_bound(N0);
    1201         196 :   ulong i, p, FZ = itou(gcoeff(F,1,1)), FZ2 = itou(gcoeff(F,2,2));
    1202             :   forprime_t T;
    1203             : 
    1204         196 :   FZ2 = ugcd(FZ, FZ2); /* content(F) */
    1205         196 :   R->L0 = vecsmalltrunc_init(l);
    1206         196 :   R->L2 = vecsmalltrunc_init(l); R->condZ = FZ;
    1207         196 :   R->L1 = vecsmalltrunc_init(l); R->L1ray = vectrunc_init(l);
    1208         196 :   R->L11= vecsmalltrunc_init(l); R->L11ray= vectrunc_init(l);
    1209         196 :   N = utoipos(2);
    1210         196 :   u_forprime_init(&T, 2, N0);
    1211       51239 :   while ( (p = u_forprime_next(&T)) )
    1212             :   {
    1213       51043 :     N[2] = p;
    1214       51043 :     switch (kroiu(dk, p))
    1215             :     {
    1216       26258 :     case -1: /* inert */
    1217       26258 :       if (FZ % p == 0) deg0(R,p); else deg2(R,p);
    1218       26258 :       break;
    1219       24519 :     case 1: /* split */
    1220       24519 :       if (FZ2 % p == 0) deg0(R,p);
    1221             :       else
    1222             :       {
    1223       24519 :         GEN Lpr = idealprimedec(nf, N);
    1224       24519 :         if (FZ % p) deg12(R, p, bnr, gel(Lpr,1));
    1225             :         else
    1226             :         {
    1227         182 :           long t = ZC_prdvd(gel(F,2), gel(Lpr,1))? 2: 1;
    1228         182 :           deg11(R, p, bnr, gel(Lpr,t));
    1229             :         }
    1230             :       }
    1231       24519 :       break;
    1232         266 :     default: /* ramified */
    1233         266 :       if (FZ % p == 0)
    1234          21 :         deg0(R,p);
    1235             :       else
    1236         245 :         deg11(R, p, bnr, idealprimedec_galois(nf, N));
    1237         266 :       break;
    1238             :     }
    1239             :   }
    1240             :   /* precompute isprincipalray(x), x in Z */
    1241         196 :   v = coprimes_zv(FZ);
    1242         196 :   R->rayZ = cgetg(FZ, t_VEC);
    1243        2541 :   for (i = 1; i < FZ; i++)
    1244             :   {
    1245        2345 :     N[2] = i;
    1246        2345 :     gel(R->rayZ,i) = v[i]? isprincipalray(bnr, N): gen_0;
    1247             :   }
    1248         196 :   gerepileall(av, 7, &(R->L0), &(R->L2), &(R->rayZ),
    1249             :               &(R->L1), &(R->L1ray), &(R->L11), &(R->L11ray));
    1250         196 : }
    1251             : 
    1252             : static void
    1253         511 : InitPrimes(GEN bnr, ulong N0, LISTray *R)
    1254             : {
    1255         511 :   GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1);
    1256         511 :   long p, l, condZ, N = lg(cond)-1;
    1257         511 :   GEN DL, prime, BOUND, nf = bnf_get_nf(bnf);
    1258             :   forprime_t T;
    1259             : 
    1260         511 :   R->condZ = condZ = itos(gcoeff(cond,1,1));
    1261         511 :   l = primepi_upper_bound(N0) * N;
    1262         511 :   DL = cgetg(N+1, t_VEC);
    1263         511 :   R->L1 = vecsmalltrunc_init(l);
    1264         511 :   R->L1ray = vectrunc_init(l);
    1265         511 :   u_forprime_init(&T, 2, N0);
    1266         511 :   prime = utoipos(2);
    1267         511 :   BOUND = utoi(N0);
    1268      122752 :   while ( (p = u_forprime_next(&T)) )
    1269             :   {
    1270      122241 :     pari_sp av = avma;
    1271             :     long j, k, lP;
    1272             :     GEN P;
    1273      122241 :     prime[2] = p;
    1274      122241 :     if (DEBUGLEVEL>1 && (p & 2047) == 1) err_printf("%ld ", p);
    1275      122241 :     P = idealprimedec_limit_norm(nf, prime, BOUND); lP = lg(P);
    1276      243943 :     for (j = 1; j < lP; j++)
    1277             :     {
    1278      121702 :       GEN pr  = gel(P,j), dl = NULL;
    1279      121702 :       if (condZ % p || !idealval(nf, cond, pr))
    1280             :       {
    1281      121233 :         dl = gclone( isprincipalray(bnr, pr) );
    1282      121233 :         vecsmalltrunc_append(R->L1, upowuu(p, pr_get_f(pr)));
    1283             :       }
    1284      121702 :       gel(DL,j) = dl;
    1285             :     }
    1286      122241 :     set_avma(av);
    1287      243943 :     for (k = 1; k < j; k++)
    1288             :     {
    1289      121702 :       if (!DL[k]) continue;
    1290      121233 :       vectrunc_append(R->L1ray, ZC_copy(gel(DL,k)));
    1291      121233 :       gunclone(gel(DL,k));
    1292             :     }
    1293             :   }
    1294         511 : }
    1295             : 
    1296             : static GEN /* cf polcoef */
    1297      412236 : _sercoeff(GEN x, long n)
    1298             : {
    1299      412236 :   long i = n - valser(x);
    1300      412236 :   return (i < 0)? gen_0: gel(x,i+2);
    1301             : }
    1302             : 
    1303             : static void
    1304      412236 : affect_coeff(GEN q, long n, GEN y, long t)
    1305             : {
    1306      412236 :   GEN x = _sercoeff(q,-n);
    1307      412236 :   if (x == gen_0) gel(y,n) = NULL;
    1308      210548 :   else { affgr(x, gel(y,n)); shiftr_inplace(gel(y,n), t); }
    1309      412236 : }
    1310             : /* (x-i)(x-(i+1)) */
    1311             : static GEN
    1312      105282 : d2(long i) { return deg2pol_shallow(gen_1, utoineg(2*i+1), muluu(i,i+1), 0); }
    1313             : /* x-i */
    1314             : static GEN
    1315      315902 : d1(long i) { return deg1pol_shallow(gen_1, stoi(-i), 0); }
    1316             : 
    1317             : typedef struct {
    1318             :   GEN c1, aij, bij, cS, cT, powracpi;
    1319             :   long i0, a,b,c, r, rc1, rc2;
    1320             : } ST_t;
    1321             : 
    1322             : /* compute the principal part at the integers s = 0, -1, -2, ..., -i0
    1323             :  * of Gamma((s+1)/2)^a Gamma(s/2)^b Gamma(s)^c / (s - z) with z = 0 and 1 */
    1324             : static void
    1325         308 : ppgamma(ST_t *T, long prec)
    1326             : {
    1327             :   GEN G, G1, G2, A, E, O, x, sqpi, aij, bij;
    1328         308 :   long c = T->c, r = T->r, i0 = T->i0, i, j, s, t, dx;
    1329             :   pari_sp av;
    1330             : 
    1331         308 :   T->aij = aij = cgetg(i0+1, t_VEC);
    1332         308 :   T->bij = bij = cgetg(i0+1, t_VEC);
    1333      105590 :   for (i = 1; i <= i0; i++)
    1334             :   {
    1335             :     GEN p1, p2;
    1336      105282 :     gel(aij,i) = p1 = cgetg(r+1, t_VEC);
    1337      105282 :     gel(bij,i) = p2 = cgetg(r+1, t_VEC);
    1338      311400 :     for (j=1; j<=r; j++) { gel(p1,j) = cgetr(prec); gel(p2,j) = cgetr(prec); }
    1339             :   }
    1340         308 :   av = avma; x = pol_x(0);
    1341         308 :   sqpi = sqrtr_abs(mppi(prec)); /* Gamma(1/2) */
    1342             : 
    1343         308 :   G1 = gexp(integser(psi1series(r-1, 0, prec)), prec); /* Gamma(1 + x) */
    1344         308 :   G = shallowcopy(G1); setvalser(G,-1); /* Gamma(x) */
    1345             : 
    1346             :   /* expansion of log(Gamma(u) / Gamma(1/2)) at u = 1/2 */
    1347         308 :   G2 = cgetg(r+2, t_SER);
    1348         308 :   G2[1] = evalsigne(1) | _evalvalser(1) | evalvarn(0);
    1349         308 :   gel(G2,2) = gneg(gadd(gmul2n(mplog2(prec), 1), mpeuler(prec)));
    1350         644 :   for (i = 1; i < r; i++) gel(G2,i+2) = mulri(gel(G1,i+2), int2um1(i));
    1351         308 :   G2 = gmul(sqpi, gexp(G2, prec)); /* Gamma(1/2 + x) */
    1352             : 
    1353             :  /* We simplify to get one of the following two expressions
    1354             :   * if (b > a) : sqrt(Pi)^a 2^{a-au} Gamma(u)^{a+c} Gamma(  u/2  )^{|b-a|}
    1355             :   * if (b <= a): sqrt(Pi)^b 2^{b-bu} Gamma(u)^{b+c} Gamma((u+1)/2)^{|b-a|} */
    1356         308 :   if (T->b > T->a)
    1357             :   {
    1358          56 :     t = T->a; s = T->b; dx = 1;
    1359          56 :     E = ser_unscale(G, ghalf);
    1360          56 :     O = gmul2n(gdiv(ser_unscale(G2, ghalf), d1(1)), 1); /* Gamma((x-1)/2) */
    1361             :   }
    1362             :   else
    1363             :   {
    1364         252 :     t = T->b; s = T->a; dx = 0;
    1365         252 :     E = ser_unscale(G2, ghalf);
    1366         252 :     O = ser_unscale(G, ghalf);
    1367             :   }
    1368             :   /* (sqrt(Pi) 2^{1-x})^t Gamma(x)^{t+c} */
    1369         308 :   A = gmul(gmul(powru(gmul2n(sqpi,1), t), gpowgs(G, t+c)),
    1370             :            gpow(gen_2, RgX_to_ser(gmulgs(x,-t), r+2), prec));
    1371             :   /* A * Gamma((x - dx + 1)/2)^{s-t} */
    1372         308 :   E = gmul(A, gpowgs(E, s-t));
    1373             :   /* A * Gamma((x - dx)/2)^{s-t} */
    1374         308 :   O = gdiv(gmul(A, gpowgs(O, s-t)), gpowgs(gsubgs(x, 1), t+c));
    1375       52949 :   for (i = 0; i < i0/2; i++)
    1376             :   {
    1377       52641 :     GEN p1, q1, A1 = gel(aij,2*i+1), B1 = gel(bij,2*i+1);
    1378       52641 :     GEN p2, q2, A2 = gel(aij,2*i+2), B2 = gel(bij,2*i+2);
    1379       52641 :     long t1 = i * (s+t), t2 = t1 + t;
    1380             : 
    1381       52641 :     p1 = gdiv(E, d1(2*i));
    1382       52641 :     q1 = gdiv(E, d1(2*i+1));
    1383       52641 :     p2 = gdiv(O, d1(2*i+1));
    1384       52641 :     q2 = gdiv(O, d1(2*i+2));
    1385      155700 :     for (j = 1; j <= r; j++)
    1386             :     {
    1387      103059 :       affect_coeff(p1, j, A1, t1); affect_coeff(q1, j, B1, t1);
    1388      103059 :       affect_coeff(p2, j, A2, t2); affect_coeff(q2, j, B2, t2);
    1389             :     }
    1390       52641 :     E = gdiv(E, gmul(gpowgs(d1(2*i+1+dx), s-t), gpowgs(d2(2*i+1), t+c)));
    1391       52641 :     O = gdiv(O, gmul(gpowgs(d1(2*i+2+dx), s-t), gpowgs(d2(2*i+2), t+c)));
    1392             :   }
    1393         308 :   set_avma(av);
    1394         308 : }
    1395             : 
    1396             : /* chi != 1. Return L(1, chi) if fl & 1, else [r, c] where L(s, chi) ~ c s^r
    1397             :  * at s = 0. */
    1398             : static GEN
    1399        1253 : GetValue(GEN dtcr, GEN W, GEN S, GEN T, long fl, long prec)
    1400             : {
    1401             :   GEN cf, z;
    1402             :   long q, b, c, r;
    1403        1253 :   int isreal = (ch_deg(dtcr) <= 2);
    1404             : 
    1405        1253 :   ch_get3(dtcr, &q, &b, &c);
    1406        1253 :   if (fl & 1)
    1407             :   { /* S(chi) + W(chi).T(chi)) / (C(chi) sqrt(Pi)^{r1 - q}) */
    1408         196 :     cf = gmul(ch_C(dtcr), powruhalf(mppi(prec), b));
    1409             : 
    1410         196 :     z = gadd(S, gmul(W, T));
    1411         196 :     if (isreal) z = real_i(z);
    1412         196 :     z = gdiv(z, cf);
    1413         196 :     if (fl & 2) z = gmul(z, AChi(dtcr, &r, 1, prec));
    1414             :   }
    1415             :   else
    1416             :   { /* (W(chi).S(conj(chi)) + T(chi)) / (sqrt(Pi)^q 2^{r1 - q}) */
    1417        1057 :     cf = gmul2n(powruhalf(mppi(prec), q), b);
    1418             : 
    1419        1057 :     z = gadd(gmul(W, conj_i(S)), conj_i(T));
    1420        1057 :     if (isreal) z = real_i(z);
    1421        1057 :     z = gdiv(z, cf); r = 0;
    1422        1057 :     if (fl & 2) z = gmul(z, AChi(dtcr, &r, 0, prec));
    1423        1057 :     z = mkvec2(utoi(b + c + r), z);
    1424             :   }
    1425        1253 :   return z;
    1426             : }
    1427             : 
    1428             : /* return the order and the first nonzero term of L(s, chi0)
    1429             :    at s = 0. If flag != 0, adjust the value to get L_S(s, chi0). */
    1430             : static GEN
    1431          35 : GetValue1(GEN bnr, long flag, long prec)
    1432             : {
    1433          35 :   GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf);
    1434          35 :   GEN h = bnf_get_no(bnf), R = bnf_get_reg(bnf);
    1435          35 :   GEN c = gdivgs(mpmul(h, R), -bnf_get_tuN(bnf));
    1436          35 :   long r = lg(nf_get_roots(nf)) - 2; /* r1 + r2 - 1 */;
    1437          35 :   if (flag)
    1438             :   {
    1439           0 :     GEN diff = divcond(bnr);
    1440             :     long i, l;
    1441           0 :     l = lg(diff) - 1; r += l;
    1442           0 :     for (i = 1; i <= l; i++) c = gmul(c, glog(pr_norm(gel(diff,i)), prec));
    1443             :   }
    1444          35 :   return mkvec2(utoi(r), c);
    1445             : }
    1446             : 
    1447             : /********************************************************************/
    1448             : /*                6th part: recover the coefficients                */
    1449             : /********************************************************************/
    1450             : static long
    1451        2338 : TestOne(GEN plg, RC_data *d)
    1452             : {
    1453        2338 :   long j, v = d->v;
    1454        2338 :   GEN z = gsub(d->beta, gel(plg,v));
    1455        2338 :   if (expo(z) >= d->G) return 0;
    1456        6412 :   for (j = 1; j < lg(plg); j++)
    1457        4483 :     if (j != v && mpcmp(d->B, mpabs_shallow(gel(plg,j))) < 0) return 0;
    1458        1929 :   return 1;
    1459             : }
    1460             : 
    1461             : static GEN
    1462         361 : chk_reccoeff_init(FP_chk_fun *chk, GEN r, GEN mat)
    1463             : {
    1464         361 :   RC_data *d = (RC_data*)chk->data;
    1465         361 :   (void)r; d->U = mat; return d->nB;
    1466             : }
    1467             : 
    1468             : static GEN
    1469         288 : chk_reccoeff(void *data, GEN x)
    1470             : {
    1471         288 :   RC_data *d = (RC_data*)data;
    1472         288 :   GEN v = gmul(d->U, x), z = gel(v,1);
    1473             : 
    1474         288 :   if (!gequal1(z)) return NULL;
    1475         288 :   *++v = evaltyp(t_COL) | _evallg( lg(d->M) ); /* pop 1st elt */
    1476         288 :   if (TestOne(gmul(d->M, v), d)) return v;
    1477           0 :   return NULL;
    1478             : }
    1479             : 
    1480             : /* Using Cohen's method */
    1481             : static GEN
    1482         361 : RecCoeff3(GEN nf, RC_data *d, long prec)
    1483             : {
    1484             :   GEN A, M, nB, cand, p1, B2, C2, tB, beta2, nf2, Bd;
    1485         361 :   GEN beta = d->beta, B = d->B;
    1486         361 :   long N = d->N, v = d->v, e, BIG;
    1487         361 :   long i, j, k, ct = 0, prec2;
    1488         361 :   FP_chk_fun chk = { &chk_reccoeff, &chk_reccoeff_init, NULL, NULL, 0 };
    1489         361 :   chk.data = (void*)d;
    1490             : 
    1491         361 :   d->G = minss(-10, -prec >> 4);
    1492         361 :   BIG = maxss(32, -2*d->G);
    1493         361 :   tB  = sqrtnr(real2n(BIG-N,DEFAULTPREC), N-1);
    1494         361 :   Bd  = grndtoi(gmin_shallow(B, tB), &e);
    1495         361 :   if (e > 0) return NULL; /* failure */
    1496         361 :   Bd = addiu(Bd, 1);
    1497         361 :   prec2 = nbits2prec( expi(Bd) + 192 );
    1498         361 :   prec2 = maxss(precdbl(prec), prec2);
    1499         361 :   B2 = sqri(Bd);
    1500         361 :   C2 = shifti(B2, BIG<<1);
    1501             : 
    1502         361 : LABrcf: ct++;
    1503         361 :   beta2 = gprec_w(beta, prec2);
    1504         361 :   nf2 = nfnewprec_shallow(nf, prec2);
    1505         361 :   d->M = M = nf_get_M(nf2);
    1506             : 
    1507         361 :   A = cgetg(N+2, t_MAT);
    1508        1493 :   for (i = 1; i <= N+1; i++) gel(A,i) = cgetg(N+2, t_COL);
    1509             : 
    1510         361 :   gcoeff(A, 1, 1) = gadd(gmul(C2, gsqr(beta2)), B2);
    1511        1132 :   for (j = 2; j <= N+1; j++)
    1512             :   {
    1513         771 :     p1 = gmul(C2, gmul(gneg_i(beta2), gcoeff(M, v, j-1)));
    1514         771 :     gcoeff(A, 1, j) = gcoeff(A, j, 1) = p1;
    1515             :   }
    1516        1132 :   for (i = 2; i <= N+1; i++)
    1517        2001 :     for (j = i; j <= N+1; j++)
    1518             :     {
    1519        1230 :       p1 = gen_0;
    1520        3984 :       for (k = 1; k <= N; k++)
    1521             :       {
    1522        2754 :         GEN p2 = gmul(gcoeff(M, k, j-1), gcoeff(M, k, i-1));
    1523        2754 :         if (k == v) p2 = gmul(C2, p2);
    1524        2754 :         p1 = gadd(p1,p2);
    1525             :       }
    1526        1230 :       gcoeff(A, i, j) = gcoeff(A, j, i) = p1;
    1527             :     }
    1528             : 
    1529         361 :   nB = mului(N+1, B2);
    1530         361 :   d->nB = nB;
    1531         361 :   cand = fincke_pohst(A, nB, -1, prec2, &chk);
    1532             : 
    1533         361 :   if (!cand)
    1534             :   {
    1535           0 :     if (ct > 3) return NULL;
    1536           0 :     prec2 = precdbl(prec2);
    1537           0 :     if (DEBUGLEVEL>1) pari_warn(warnprec,"RecCoeff", prec2);
    1538           0 :     goto LABrcf;
    1539             :   }
    1540             : 
    1541         361 :   cand = gel(cand,1);
    1542         361 :   if (lg(cand) == 2) return gel(cand,1);
    1543             : 
    1544         217 :   if (DEBUGLEVEL>1) err_printf("RecCoeff3: no solution found!\n");
    1545         217 :   return NULL;
    1546             : }
    1547             : 
    1548             : /* Using linear dependence relations */
    1549             : static GEN
    1550        2002 : RecCoeff2(GEN nf,  RC_data *d,  long prec)
    1551             : {
    1552             :   pari_sp av;
    1553        2002 :   GEN vec, M = nf_get_M(nf), beta = d->beta;
    1554        2002 :   long bit, min, max, lM = lg(M);
    1555             : 
    1556        2002 :   d->G = minss(-20, -prec >> 4);
    1557             : 
    1558        2002 :   vec  = vec_prepend(row(M, d->v), gneg(beta));
    1559        2002 :   min = (long)prec * 0.75;
    1560        2002 :   max = (long)prec * 0.98;
    1561        2002 :   av = avma;
    1562        2524 :   for (bit = max; bit >= min; bit-=32, set_avma(av))
    1563             :   {
    1564             :     long e;
    1565        2163 :     GEN v = lindep_bit(vec, bit), z = gel(v,1);
    1566        2163 :     if (!signe(z)) continue;
    1567        2050 :     *++v = evaltyp(t_COL) | _evallg(lM); /* pop 1st elt */
    1568        2050 :     v = grndtoi(gdiv(v, z), &e);
    1569        2050 :     if (e > 0) break;
    1570        2050 :     if (TestOne(RgM_RgC_mul(M, v), d)) return v;
    1571             :   }
    1572             :   /* failure */
    1573         361 :   return RecCoeff3(nf,d,prec);
    1574             : }
    1575             : 
    1576             : /* Attempts to find a polynomial with coefficients in nf such that
    1577             :    its coefficients are close to those of pol at the place v and
    1578             :    less than B at all the other places */
    1579             : static GEN
    1580         539 : RecCoeff(GEN nf,  GEN pol,  long v, long prec)
    1581             : {
    1582         539 :   long j, md, cl = degpol(pol);
    1583         539 :   pari_sp av = avma;
    1584             :   RC_data d;
    1585             : 
    1586             :   /* if precision(pol) is too low, abort */
    1587        3542 :   for (j = 2; j <= cl+1; j++)
    1588             :   {
    1589        3003 :     GEN t = gel(pol, j);
    1590        3003 :     if (precision(t) - gexpo(t) < 34) return NULL;
    1591             :   }
    1592             : 
    1593         539 :   md = cl/2;
    1594         539 :   pol = leafcopy(pol);
    1595             : 
    1596         539 :   d.N = nf_get_degree(nf);
    1597         539 :   d.v = v;
    1598             : 
    1599        2324 :   for (j = 1; j <= cl; j++)
    1600             :   { /* start with the coefficients in the middle,
    1601             :        since they are the harder to recognize! */
    1602        2002 :     long cf = md + (j%2? j/2: -j/2);
    1603        2002 :     GEN t, bound = shifti(binomial(utoipos(cl), cf), cl-cf);
    1604             : 
    1605        2002 :     if (DEBUGLEVEL>1) err_printf("RecCoeff (cf = %ld, B = %Ps)\n", cf, bound);
    1606        2002 :     d.beta = real_i( gel(pol,cf+2) );
    1607        2002 :     d.B    = bound;
    1608        2002 :     if (! (t = RecCoeff2(nf, &d, prec)) ) return NULL;
    1609        1785 :     gel(pol, cf+2) = coltoalg(nf,t);
    1610             :   }
    1611         322 :   gel(pol,cl+2) = gen_1;
    1612         322 :   return gerepilecopy(av, pol);
    1613             : }
    1614             : 
    1615             : /* an[q * i] *= chi for all (i,p)=1 */
    1616             : static void
    1617      108531 : an_mul(int **an, long p, long q, long n, long deg, GEN chi, int **reduc)
    1618             : {
    1619             :   pari_sp av;
    1620             :   long c,i;
    1621             :   int *T;
    1622             : 
    1623      108531 :   if (gequal1(chi)) return;
    1624       99833 :   av = avma;
    1625       99833 :   T = (int*)new_chunk(deg); Polmod2Coeff(T,chi, deg);
    1626     2117218 :   for (c = 1, i = q; i <= n; i += q, c++)
    1627     2017385 :     if (c == p) c = 0; else MulCoeff(an[i], T, reduc, deg);
    1628       99833 :   set_avma(av);
    1629             : }
    1630             : /* an[q * i] = 0 for all (i,p)=1 */
    1631             : static void
    1632       98351 : an_set0_coprime(int **an, long p, long q, long n, long deg)
    1633             : {
    1634             :   long c,i;
    1635     1187425 :   for (c = 1, i = q; i <= n; i += q, c++)
    1636     1089074 :     if (c == p) c = 0; else _0toCoeff(an[i], deg);
    1637       98351 : }
    1638             : /* an[q * i] = 0 for all i */
    1639             : static void
    1640         105 : an_set0(int **an, long p, long n, long deg)
    1641             : {
    1642             :   long i;
    1643       60020 :   for (i = p; i <= n; i += p) _0toCoeff(an[i], deg);
    1644         105 : }
    1645             : 
    1646             : /* compute the coefficients an for the quadratic case */
    1647             : static int**
    1648         693 : computean(GEN dtcr, LISTray *R, long n, long deg)
    1649             : {
    1650         693 :   pari_sp av = avma, av2;
    1651             :   long i, p, q, condZ, l;
    1652             :   int **an, **reduc;
    1653             :   GEN L, chi, chi1;
    1654             :   CHI_t C;
    1655             : 
    1656         693 :   init_CHI_alg(&C, ch_CHI(dtcr));
    1657         693 :   condZ= R->condZ;
    1658             : 
    1659         693 :   an = InitMatAn(n, deg, 1);
    1660         693 :   reduc = InitReduction(C.ord, deg);
    1661         693 :   av2 = avma;
    1662             : 
    1663             :   /* all pr | p divide cond */
    1664         693 :   L = R->L0; l = lg(L);
    1665         798 :   for (i=1; i<l; i++) an_set0(an,L[i],n,deg);
    1666             : 
    1667             :   /* 1 prime of degree 2 */
    1668         693 :   L = R->L2; l = lg(L);
    1669       97712 :   for (i=1; i<l; i++, set_avma(av2))
    1670             :   {
    1671       97019 :     p = L[i];
    1672       97019 :     if (condZ == 1) chi = C.val[0]; /* 1 */
    1673       96865 :     else            chi = CHI_eval(&C, gel(R->rayZ, p%condZ));
    1674       97019 :     chi1 = chi;
    1675       97019 :     for (q=p;;)
    1676             :     {
    1677       98351 :       an_set0_coprime(an, p,q,n,deg); /* v_p(q) odd */
    1678       98351 :       if (! (q = umuluu_le(q,p, n)) ) break;
    1679             : 
    1680        4362 :       an_mul(an,p,q,n,deg,chi,reduc);
    1681        4362 :       if (! (q = umuluu_le(q,p, n)) ) break;
    1682        1332 :       chi = gmul(chi, chi1);
    1683             :     }
    1684             :   }
    1685             : 
    1686             :   /* 1 prime of degree 1 */
    1687         693 :   L = R->L1; l = lg(L);
    1688        2289 :   for (i=1; i<l; i++, set_avma(av2))
    1689             :   {
    1690        1596 :     p = L[i];
    1691        1596 :     chi = CHI_eval(&C, gel(R->L1ray,i));
    1692        1596 :     chi1 = chi;
    1693        1596 :     for(q=p;;)
    1694             :     {
    1695        7340 :       an_mul(an,p,q,n,deg,chi,reduc);
    1696        7340 :       if (! (q = umuluu_le(q,p, n)) ) break;
    1697        5744 :       chi = gmul(chi, chi1);
    1698             :     }
    1699             :   }
    1700             : 
    1701             :   /* 2 primes of degree 1 */
    1702         693 :   L = R->L11; l = lg(L);
    1703       90495 :   for (i=1; i<l; i++, set_avma(av2))
    1704             :   {
    1705             :     GEN ray1, ray2, chi11, chi12, chi2;
    1706             : 
    1707       89802 :     p = L[i]; ray1 = gel(R->L11ray,i); /* use pr1 pr2 = (p) */
    1708       89802 :     if (condZ == 1)
    1709         112 :       ray2 = ZC_neg(ray1);
    1710             :     else
    1711       89690 :       ray2 = ZC_sub(gel(R->rayZ, p%condZ),  ray1);
    1712       89802 :     chi11 = CHI_eval(&C, ray1);
    1713       89802 :     chi12 = CHI_eval(&C, ray2);
    1714             : 
    1715       89802 :     chi1 = gadd(chi11, chi12);
    1716       89802 :     chi2 = chi12;
    1717       89802 :     for(q=p;;)
    1718             :     {
    1719       96829 :       an_mul(an,p,q,n,deg,chi1,reduc);
    1720       96829 :       if (! (q = umuluu_le(q,p, n)) ) break;
    1721        7027 :       chi2 = gmul(chi2, chi12);
    1722        7027 :       chi1 = gadd(chi2, gmul(chi1, chi11));
    1723             :     }
    1724             :   }
    1725             : 
    1726         693 :   CorrectCoeff(dtcr, an, reduc, n, deg);
    1727         693 :   FreeMat(reduc, deg-1);
    1728         693 :   set_avma(av); return an;
    1729             : }
    1730             : 
    1731             : /* return the vector of A^i/i for i = 1...n */
    1732             : static GEN
    1733         224 : mpvecpowdiv(GEN A, long n)
    1734             : {
    1735         224 :   pari_sp av = avma;
    1736             :   long i;
    1737         224 :   GEN v = powersr(A, n);
    1738         224 :   GEN w = cgetg(n+1, t_VEC);
    1739         224 :   gel(w,1) = rcopy(gel(v,2));
    1740      364392 :   for (i=2; i<=n; i++) gel(w,i) = divru(gel(v,i+1), i);
    1741         224 :   return gerepileupto(av, w);
    1742             : }
    1743             : 
    1744             : static void GetST0(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec);
    1745             : /* allocate memory for GetST answer */
    1746             : static void
    1747         420 : ST_alloc(GEN *pS, GEN *pT, long l, long prec)
    1748             : {
    1749             :   long j;
    1750         420 :   *pS = cgetg(l, t_VEC);
    1751         420 :   *pT = cgetg(l, t_VEC);
    1752        1883 :   for (j = 1; j < l; j++)
    1753             :   {
    1754        1463 :     gel(*pS,j) = cgetc(prec);
    1755        1463 :     gel(*pT,j) = cgetc(prec);
    1756             :   }
    1757         420 : }
    1758             : 
    1759             : /* compute S and T for the quadratic case. The following cases are:
    1760             :  * 1) bnr complex;
    1761             :  * 2) bnr real and no infinite place divide cond_chi (TODO);
    1762             :  * 3) bnr real and one infinite place divide cond_chi;
    1763             :  * 4) bnr real and both infinite places divide cond_chi (TODO) */
    1764             : static void
    1765         231 : QuadGetST(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec)
    1766             : {
    1767             :   pari_sp av, av1, av2;
    1768             :   long ncond, n, j, k, n0;
    1769         231 :   GEN vChar = gel(CR,1), dataCR = gel(CR,2), S, T, an, cs, N0, C;
    1770             :   LISTray LIST;
    1771             : 
    1772             :   /* initializations */
    1773         231 :   ST_alloc(pS, pT, lg(dataCR), prec); T = *pT; S = *pS;
    1774         231 :   av = avma;
    1775         231 :   ncond = lg(vChar)-1;
    1776         231 :   C    = cgetg(ncond+1, t_VEC);
    1777         231 :   N0   = cgetg(ncond+1, t_VECSMALL);
    1778         231 :   cs   = cgetg(ncond+1, t_VECSMALL);
    1779         231 :   n0 = 0;
    1780         455 :   for (j = 1; j <= ncond; j++)
    1781             :   {
    1782         259 :     GEN dtcr = gel(dataCR, mael(vChar,j,1)), c = ch_C(dtcr);
    1783             :     long r1, r2;
    1784             : 
    1785         259 :     gel(C,j) = c;
    1786         259 :     nf_get_sign(bnr_get_nf(ch_bnr(dtcr)), &r1, &r2);
    1787         259 :     if (r1 == 2) /* real quadratic */
    1788             :     {
    1789         245 :       cs[j] = 2 + ch_q(dtcr);
    1790         245 :       if (cs[j] == 2 || cs[j] == 4)
    1791             :       { /* NOT IMPLEMENTED YET */
    1792          35 :         GetST0(bnr, pS, pT, CR, prec);
    1793          35 :         return;
    1794             :       }
    1795             :       /* FIXME: is this value of N0 correct for the general case ? */
    1796         210 :       N0[j] = (long)prec * 0.35 * gtodouble(c);
    1797             :     }
    1798             :     else /* complex quadratic */
    1799             :     {
    1800          14 :       cs[j] = 1;
    1801          14 :       N0[j] = (long)prec * 0.7 * gtodouble(c);
    1802             :     }
    1803         224 :     if (n0 < N0[j]) n0 = N0[j];
    1804             :   }
    1805         196 :   if (DEBUGLEVEL>1) err_printf("N0 = %ld\n", n0);
    1806         196 :   InitPrimesQuad(bnr, n0, &LIST);
    1807             : 
    1808         196 :   av1 = avma;
    1809             :   /* loop over conductors */
    1810         420 :   for (j = 1; j <= ncond; j++)
    1811             :   {
    1812         224 :     GEN c0 = gel(C,j), c1 = divur(1, c0), c2 = divur(2, c0);
    1813         224 :     GEN ec1 = mpexp(c1), ec2 = mpexp(c2), LChar = gel(vChar,j);
    1814             :     GEN vf0, vf1, cf0, cf1;
    1815         224 :     const long nChar = lg(LChar)-1, NN = N0[j];
    1816             : 
    1817         224 :     if (DEBUGLEVEL>1)
    1818           0 :       err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", j,ncond,NN);
    1819         224 :     if (realprec(ec1) > prec) ec1 = rtor(ec1, prec);
    1820         224 :     if (realprec(ec2) > prec) ec2 = rtor(ec2, prec);
    1821         224 :     switch(cs[j])
    1822             :     {
    1823          14 :     case 1:
    1824          14 :       cf0 = gen_1;
    1825          14 :       cf1 = c0;
    1826          14 :       vf0 = mpveceint1(rtor(c1, prec), ec1, NN);
    1827          14 :       vf1 = mpvecpowdiv(invr(ec1), NN); break;
    1828             : 
    1829         210 :     case 3:
    1830         210 :       cf0 = sqrtr(mppi(prec));
    1831         210 :       cf1 = gmul2n(cf0, 1);
    1832         210 :       cf0 = gmul(cf0, c0);
    1833         210 :       vf0 = mpvecpowdiv(invr(ec2), NN);
    1834         210 :       vf1 = mpveceint1(rtor(c2, prec), ec2, NN); break;
    1835             : 
    1836           0 :     default:
    1837           0 :       cf0 = cf1 = NULL; /* FIXME: not implemented */
    1838           0 :       vf0 = vf1 = NULL;
    1839             :     }
    1840         924 :     for (k = 1; k <= nChar; k++)
    1841             :     {
    1842         700 :       long u = LChar[k], d, c;
    1843         700 :       GEN dtcr = gel(dataCR, u), z, s, t;
    1844             :       int **matan;
    1845             : 
    1846         700 :       if (!ch_comp(dtcr)) continue;
    1847         693 :       if (DEBUGLEVEL>1) err_printf("\tchar no: %ld (%ld/%ld)\n", u,k,nChar);
    1848         693 :       d = ch_phideg(dtcr);
    1849         693 :       z = gel(ch_CHI(dtcr), 2); s = t = gen_0; av2 = avma;
    1850         693 :       matan = computean(gel(dataCR,u), &LIST, NN, d);
    1851     1231476 :       for (n = 1, c = 0; n <= NN; n++)
    1852     1230783 :         if ((an = EvalCoeff(z, matan[n], d)))
    1853             :         {
    1854      323342 :           s = gadd(s, gmul(an, gel(vf0,n)));
    1855      323342 :           t = gadd(t, gmul(an, gel(vf1,n)));
    1856      323342 :           if (++c == 256) { gerepileall(av2,2, &s,&t); c = 0; }
    1857             :         }
    1858         693 :       gaffect(gmul(cf0, s), gel(S,u));
    1859         693 :       gaffect(gmul(cf1, conj_i(t)), gel(T,u));
    1860         693 :       FreeMat(matan,NN); set_avma(av2);
    1861             :     }
    1862         224 :     if (DEBUGLEVEL>1) err_printf("\n");
    1863         224 :     set_avma(av1);
    1864             :   }
    1865         196 :   set_avma(av);
    1866             : }
    1867             : 
    1868             : /* s += t*u. All 3 of them t_REAL, except we allow s or u = NULL (for 0) */
    1869             : static GEN
    1870    51886310 : _addmulrr(GEN s, GEN t, GEN u)
    1871             : {
    1872    51886310 :   if (u)
    1873             :   {
    1874    51618378 :     GEN v = mulrr(t, u);
    1875    51618378 :     return s? addrr(s, v): v;
    1876             :   }
    1877      267932 :   return s;
    1878             : }
    1879             : /* s += t. Both real, except we allow s or t = NULL (for exact 0) */
    1880             : static GEN
    1881   105518127 : _addrr(GEN s, GEN t)
    1882   105518127 : { return t? (s? addrr(s, t): t) : s; }
    1883             : 
    1884             : /* S & T for the general case. This is time-critical: optimize */
    1885             : static void
    1886      521409 : get_cS_cT(ST_t *T, long n)
    1887             : {
    1888             :   pari_sp av;
    1889             :   GEN csurn, nsurc, lncsurn, A, B, s, t, Z, aij, bij;
    1890             :   long i, j, r, i0;
    1891             : 
    1892      521409 :   if (gel(T->cS,n)) return;
    1893             : 
    1894      244167 :   av = avma;
    1895      244167 :   aij = T->aij; i0= T->i0;
    1896      244167 :   bij = T->bij; r = T->r;
    1897      244167 :   Z = cgetg(r+1, t_VEC);
    1898      244167 :   gel(Z,1) = NULL; /* unused */
    1899             : 
    1900      244167 :   csurn = divru(T->c1, n);
    1901      244167 :   nsurc = invr(csurn);
    1902      244167 :   lncsurn = logr_abs(csurn);
    1903             : 
    1904      244167 :   if (r > 1)
    1905             :   {
    1906      243992 :     gel(Z,2) = lncsurn; /* r >= 2 */
    1907      248087 :     for (i = 3; i <= r; i++)
    1908        4095 :       gel(Z,i) = divru(mulrr(gel(Z,i-1), lncsurn), i-1);
    1909             :     /* Z[i] = ln^(i-1)(c1/n) / (i-1)! */
    1910             :   }
    1911             : 
    1912             :   /* i = i0 */
    1913      244167 :     A = gel(aij,i0); t = _addrr(NULL, gel(A,1));
    1914      244167 :     B = gel(bij,i0); s = _addrr(NULL, gel(B,1));
    1915      492254 :     for (j = 2; j <= r; j++)
    1916             :     {
    1917      248087 :       s = _addmulrr(s, gel(Z,j),gel(B,j));
    1918      248087 :       t = _addmulrr(t, gel(Z,j),gel(A,j));
    1919             :     }
    1920    52392813 :   for (i = i0 - 1; i > 1; i--)
    1921             :   {
    1922    52148646 :     A = gel(aij,i); if (t) t = mulrr(t, nsurc);
    1923    52148646 :     B = gel(bij,i); if (s) s = mulrr(s, nsurc);
    1924    77595627 :     for (j = odd(i)? T->rc2: T->rc1; j > 1; j--)
    1925             :     {
    1926    25446981 :       s = _addmulrr(s, gel(Z,j),gel(B,j));
    1927    25446981 :       t = _addmulrr(t, gel(Z,j),gel(A,j));
    1928             :     }
    1929    52148646 :     s = _addrr(s, gel(B,1));
    1930    52148646 :     t = _addrr(t, gel(A,1));
    1931             :   }
    1932             :   /* i = 1 */
    1933      244167 :     A = gel(aij,1); if (t) t = mulrr(t, nsurc);
    1934      244167 :     B = gel(bij,1); if (s) s = mulrr(s, nsurc);
    1935      244167 :     s = _addrr(s, gel(B,1));
    1936      244167 :     t = _addrr(t, gel(A,1));
    1937      492254 :     for (j = 2; j <= r; j++)
    1938             :     {
    1939      248087 :       s = _addmulrr(s, gel(Z,j),gel(B,j));
    1940      248087 :       t = _addmulrr(t, gel(Z,j),gel(A,j));
    1941             :     }
    1942      244167 :   s = _addrr(s, T->b? mulrr(csurn, gel(T->powracpi,T->b+1)): csurn);
    1943      244167 :   if (!s) s = gen_0;
    1944      244167 :   if (!t) t = gen_0;
    1945      244167 :   gel(T->cS,n) = gclone(s);
    1946      244167 :   gel(T->cT,n) = gclone(t); set_avma(av);
    1947             : }
    1948             : 
    1949             : static void
    1950         497 : clear_cScT(ST_t *T, long N)
    1951             : {
    1952         497 :   GEN cS = T->cS, cT = T->cT;
    1953             :   long i;
    1954     1643058 :   for (i=1; i<=N; i++)
    1955     1642561 :     if (cS[i]) {
    1956      244167 :       gunclone(gel(cS,i));
    1957      244167 :       gunclone(gel(cT,i)); gel(cS,i) = gel(cT,i) = NULL;
    1958             :     }
    1959         497 : }
    1960             : 
    1961             : static void
    1962         308 : init_cScT(ST_t *T, GEN dtcr, long N, long prec)
    1963             : {
    1964         308 :   ch_get3(dtcr, &T->a, &T->b, &T->c);
    1965         308 :   T->rc1 = T->a + T->c;
    1966         308 :   T->rc2 = T->b + T->c;
    1967         308 :   T->r   = maxss(T->rc2+1, T->rc1); /* >= 2 */
    1968         308 :   ppgamma(T, prec);
    1969         308 :   clear_cScT(T, N);
    1970         308 : }
    1971             : 
    1972             : /* return a t_REAL */
    1973             : static GEN
    1974         511 : zeta_get_limx(long r1, long r2, long bit)
    1975             : {
    1976         511 :   pari_sp av = avma;
    1977             :   GEN p1, p2, c0, c1, A0;
    1978         511 :   long r = r1 + r2, N = r + r2;
    1979             : 
    1980             :   /* c1 = N 2^(-2r2 / N) */
    1981         511 :   c1 = mulrs(powrfrac(real2n(1, DEFAULTPREC), -2*r2, N), N);
    1982             : 
    1983         511 :   p1 = powru(Pi2n(1, DEFAULTPREC), r - 1);
    1984         511 :   p2 = mulir(powuu(N,r), p1); shiftr_inplace(p2, -r2);
    1985         511 :   c0 = sqrtr( divrr(p2, powru(c1, r+1)) );
    1986             : 
    1987         511 :   A0 = logr_abs( gmul2n(c0, bit) ); p2 = divrr(A0, c1);
    1988         511 :   p1 = divrr(mulur(N*(r+1), logr_abs(p2)), addsr(2*(r+1), gmul2n(A0,2)));
    1989         511 :   return gerepileuptoleaf(av, divrr(addrs(p1, 1), powruhalf(p2, N)));
    1990             : }
    1991             : /* N_0 = floor( C_K / limx ). Large */
    1992             : static long
    1993         630 : zeta_get_N0(GEN C,  GEN limx)
    1994             : {
    1995             :   long e;
    1996         630 :   pari_sp av = avma;
    1997         630 :   GEN z = gcvtoi(gdiv(C, limx), &e); /* avoid truncation error */
    1998         630 :   if (e >= 0 || is_bigint(z))
    1999           0 :     pari_err_OVERFLOW("zeta_get_N0 [need too many primes]");
    2000         630 :   return gc_long(av, itos(z));
    2001             : }
    2002             : 
    2003             : static GEN
    2004        1897 : eval_i(long r1, long r2, GEN limx, long i)
    2005             : {
    2006        1897 :   GEN t = powru(limx, i);
    2007        1897 :   if (!r1)      t = mulrr(t, powru(mpfactr(i  , DEFAULTPREC), r2));
    2008        1897 :   else if (!r2) t = mulrr(t, powru(mpfactr(i/2, DEFAULTPREC), r1));
    2009             :   else {
    2010           0 :     GEN u1 = mpfactr(i/2, DEFAULTPREC);
    2011           0 :     GEN u2 = mpfactr(i,   DEFAULTPREC);
    2012           0 :     if (r1 == r2) t = mulrr(t, powru(mulrr(u1,u2), r1));
    2013           0 :     else t = mulrr(t, mulrr(powru(u1,r1), powru(u2,r2)));
    2014             :   }
    2015        1897 :   return t;
    2016             : }
    2017             : 
    2018             : /* "small" even i such that limx^i ( (i\2)! )^r1 ( i! )^r2 > B. */
    2019             : static long
    2020         189 : get_i0(long r1, long r2, GEN B, GEN limx)
    2021             : {
    2022         189 :   long imin = 1, imax = 1400;
    2023         196 :   while (mpcmp(eval_i(r1,r2,limx, imax), B) < 0) { imin = imax; imax *= 2; }
    2024        1890 :   while(imax - imin >= 4)
    2025             :   {
    2026        1701 :     long m = (imax + imin) >> 1;
    2027        1701 :     if (mpcmp(eval_i(r1,r2,limx, m), B) >= 0) imax = m; else imin = m;
    2028             :   }
    2029         189 :   return imax & ~1; /* make it even */
    2030             : }
    2031             : /* limx = zeta_get_limx(r1, r2, bit), a t_REAL */
    2032             : static long
    2033         189 : zeta_get_i0(long r1, long r2, long bit, GEN limx)
    2034             : {
    2035         189 :   pari_sp av = avma;
    2036         189 :   GEN B = gmul(sqrtr( divrr(powrs(mppi(DEFAULTPREC), r2-3), limx) ),
    2037             :                gmul2n(powuu(5, r1), bit + r2));
    2038         189 :   return gc_long(av, get_i0(r1, r2, B, limx));
    2039             : }
    2040             : 
    2041             : static void
    2042         189 : GetST0(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec)
    2043             : {
    2044             :   pari_sp av, av1, av2;
    2045             :   long n, j, k, jc, n0, prec2, i0, r1, r2, ncond;
    2046         189 :   GEN nf = bnr_get_nf(bnr);
    2047         189 :   GEN vChar = gel(CR,1), dataCR = gel(CR,2), N0, C, an, limx, S, T;
    2048             :   LISTray LIST;
    2049             :   ST_t cScT;
    2050             : 
    2051         189 :   ST_alloc(pS, pT, lg(dataCR), prec); T = *pT; S = *pS;
    2052         189 :   av = avma;
    2053         189 :   nf_get_sign(nf,&r1,&r2);
    2054         189 :   ncond = lg(vChar)-1;
    2055         189 :   C  = cgetg(ncond+1, t_VEC);
    2056         189 :   N0 = cgetg(ncond+1, t_VECSMALL);
    2057         189 :   n0 = 0;
    2058         189 :   limx = zeta_get_limx(r1, r2, prec);
    2059         497 :   for (j = 1; j <= ncond; j++)
    2060             :   {
    2061         308 :     GEN dtcr = gel(dataCR, mael(vChar,j,1)), c = ch_C(dtcr);
    2062         308 :     gel(C,j) = c;
    2063         308 :     N0[j] = zeta_get_N0(c, limx);
    2064         308 :     if (n0 < N0[j]) n0  = N0[j];
    2065             :   }
    2066         189 :   cScT.i0 = i0 = zeta_get_i0(r1, r2, prec, limx);
    2067         189 :   if (DEBUGLEVEL>1) err_printf("i0 = %ld, N0 = %ld\n",i0, n0);
    2068         189 :   InitPrimes(bnr, n0, &LIST);
    2069         189 :   prec2 = precdbl(prec) + EXTRAPREC64;
    2070         189 :   cScT.powracpi = powersr(sqrtr(mppi(prec2)), r1);
    2071         189 :   cScT.cS = cgetg(n0+1, t_VEC);
    2072         189 :   cScT.cT = cgetg(n0+1, t_VEC);
    2073      794107 :   for (j=1; j<=n0; j++) gel(cScT.cS,j) = gel(cScT.cT,j) = NULL;
    2074             : 
    2075         189 :   av1 = avma;
    2076         497 :   for (jc = 1; jc <= ncond; jc++)
    2077             :   {
    2078         308 :     GEN LChar = gel(vChar,jc);
    2079         308 :     long nChar = lg(LChar)-1, N = N0[jc];
    2080             : 
    2081             :     /* Can discard completely a conductor if all chars satisfy L(0,chi) = 0
    2082             :      * Not sure whether this is possible. */
    2083         308 :     if (DEBUGLEVEL>1)
    2084           0 :       err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", jc,ncond,N);
    2085             : 
    2086         308 :     cScT.c1 = gel(C,jc);
    2087         308 :     init_cScT(&cScT, gel(dataCR, LChar[1]), N, prec2);
    2088         308 :     av2 = avma;
    2089         875 :     for (k = 1; k <= nChar; k++)
    2090             :     {
    2091         567 :       long d, c, u = LChar[k];
    2092         567 :       GEN dtcr = gel(dataCR, u), z, s, t;
    2093             :       int **matan;
    2094             : 
    2095         567 :       if (!ch_comp(dtcr)) continue;
    2096         560 :       if (DEBUGLEVEL>1) err_printf("\tchar no: %ld (%ld/%ld)\n", u,k,nChar);
    2097         560 :       z = gel(ch_CHI(dtcr), 2);
    2098         560 :       d = ch_phideg(dtcr); s = t = gen_0;
    2099         560 :       matan = ComputeCoeff(dtcr, &LIST, N, d);
    2100     2094167 :       for (n = 1, c = 0; n <= N; n++)
    2101     2093607 :         if ((an = EvalCoeff(z, matan[n], d)))
    2102             :         {
    2103      521409 :           get_cS_cT(&cScT, n);
    2104      521409 :           s = gadd(s, gmul(an, gel(cScT.cS,n)));
    2105      521409 :           t = gadd(t, gmul(an, gel(cScT.cT,n)));
    2106      521409 :           if (++c == 256) { gerepileall(av2,2, &s,&t); c = 0; }
    2107             :         }
    2108         560 :       gaffect(s,         gel(S,u));
    2109         560 :       gaffect(conj_i(t), gel(T,u));
    2110         560 :       FreeMat(matan, N); set_avma(av2);
    2111             :     }
    2112         308 :     if (DEBUGLEVEL>1) err_printf("\n");
    2113         308 :     set_avma(av1);
    2114             :   }
    2115         189 :   clear_cScT(&cScT, n0);
    2116         189 :   set_avma(av);
    2117         189 : }
    2118             : 
    2119             : static void
    2120         385 : GetST(GEN bnr, GEN *pS, GEN *pT, GEN CR, long prec)
    2121             : {
    2122         385 :   if (nf_get_degree(bnr_get_nf(bnr)) == 2)
    2123         231 :     QuadGetST(bnr, pS, pT, CR, prec);
    2124             :   else
    2125         154 :     GetST0(bnr, pS, pT, CR, prec);
    2126         385 : }
    2127             : 
    2128             : /*******************************************************************/
    2129             : /*                                                                 */
    2130             : /*     Class fields of real quadratic fields using Stark units     */
    2131             : /*                                                                 */
    2132             : /*******************************************************************/
    2133             : /* compute the Hilbert class field using genus class field theory when
    2134             :    the exponent of the class group is exactly 2 (trivial group not covered) */
    2135             : /* Cf Herz, Construction of class fields, LNM 21, Theorem 1 (VII-6) */
    2136             : static GEN
    2137          14 : GenusFieldQuadReal(GEN disc)
    2138             : {
    2139          14 :   GEN T = NULL, p0 = NULL, P = gel(Z_factor(disc), 1);
    2140          14 :   long i, i0 = 0, l = lg(P);
    2141             : 
    2142          42 :   for (i = 1; i < l; i++)
    2143             :   {
    2144          35 :     GEN p = gel(P,i);
    2145          35 :     if (mod4(p) == 3) { p0 = p; i0 = i; break; }
    2146             :   }
    2147          14 :   l--; /* remove last prime */
    2148          14 :   if (i0 == l) l--; /* ... remove p0 and last prime */
    2149          49 :   for (i = 1; i < l; i++)
    2150             :   {
    2151          35 :     GEN p = gel(P,i), d, t;
    2152          35 :     if (i == i0) continue;
    2153          28 :     if (absequaliu(p, 2))
    2154          14 :       switch (mod32(disc))
    2155             :       {
    2156          14 :         case  8: d = gen_2; break;
    2157           0 :         case 24: d = shifti(p0, 1); break;
    2158           0 :         default: d = p0; break;
    2159             :       }
    2160             :     else
    2161          14 :       d = (mod4(p) == 1)? p: mulii(p0, p);
    2162          28 :     t = mkpoln(3, gen_1, gen_0, negi(d)); /* x^2 - d */
    2163          28 :     T = T? ZX_composedsum(T, t): t;
    2164             :   }
    2165          14 :   return polredbest(T, 0);
    2166             : }
    2167             : static GEN
    2168         406 : GenusFieldQuadImag(GEN disc)
    2169             : {
    2170         406 :   GEN T = NULL, P = gel(absZ_factor(disc), 1);
    2171         406 :   long i, n = lg(P)-1;
    2172        1183 :   for (i = 1; i < n; i++) /* remove last prime */
    2173             :   {
    2174         777 :     GEN p = gel(P,i), d, t;
    2175         777 :     if (absequaliu(p, 2))
    2176         231 :       switch (mod32(disc))
    2177             :       {
    2178          56 :         case 24: d = gen_2; break;  /* disc = 8 mod 32 */
    2179          42 :         case  8: d = gen_m2; break; /* disc =-8 mod 32 */
    2180         133 :         default: d = gen_m1; break;
    2181             :       }
    2182             :     else
    2183         546 :       d = (mod4(p) == 1)? p: negi(p);
    2184         777 :     t = mkpoln(3, gen_1, gen_0, negi(d)); /* x^2 - d */
    2185         777 :     T = T? ZX_composedsum(T, t): t;
    2186             :   }
    2187         406 :   return polredbest(T, 0);
    2188             : }
    2189             : 
    2190             : /* if flag != 0, computes a fast and crude approximation of the result */
    2191             : static GEN
    2192         644 : AllStark(GEN data, long flag, long newprec)
    2193             : {
    2194         644 :   const long BND = 300;
    2195         644 :   long cl, i, j, cpt = 0, N, h, v, n, r1, r2, den;
    2196             :   pari_sp av, av2;
    2197             :   int **matan;
    2198         644 :   GEN bnr = gel(data,1), nf = bnr_get_nf(bnr), p1, p2, S, T;
    2199         644 :   GEN CR = gel(data,4), dataCR = gel(CR,2);
    2200             :   GEN polrelnum, polrel, Lp, W, vzeta, C, cond1, L1, an;
    2201             :   LISTray LIST;
    2202             :   pari_timer ti;
    2203             : 
    2204         644 :   nf_get_sign(nf, &r1,&r2);
    2205         644 :   N     = nf_get_degree(nf);
    2206         644 :   cond1 = gel(bnr_get_mod(bnr), 2);
    2207             : 
    2208         644 :   v = 1;
    2209        1344 :   while (gequal1(gel(cond1,v))) v++;
    2210         644 :   cl = lg(dataCR)-1;
    2211         644 :   h  = itos(ZM_det_triangular(gel(data,2))) >> 1;
    2212             : 
    2213         644 : LABDOUB:
    2214         644 :   if (DEBUGLEVEL) timer_start(&ti);
    2215         644 :   av = avma;
    2216         644 :   W = AllArtinNumbers(CR, newprec);
    2217         644 :   if (DEBUGLEVEL) timer_printf(&ti,"Compute W");
    2218         644 :   Lp = cgetg(cl + 1, t_VEC);
    2219         644 :   if (!flag)
    2220             :   {
    2221         322 :     GetST(bnr, &S, &T, CR, newprec);
    2222         322 :     if (DEBUGLEVEL) timer_printf(&ti, "S&T");
    2223        1351 :     for (i = 1; i <= cl; i++)
    2224             :     {
    2225        1029 :       GEN chi = gel(dataCR, i), v = gen_0;
    2226        1029 :       if (ch_comp(chi))
    2227        1015 :         v = gel(GetValue(chi, gel(W,i), gel(S,i), gel(T,i), 2, newprec), 2);
    2228        1029 :       gel(Lp, i) = v;
    2229             :     }
    2230             :   }
    2231             :   else
    2232             :   { /* compute a crude approximation of the result */
    2233         322 :     C = cgetg(cl + 1, t_VEC);
    2234        1351 :     for (i = 1; i <= cl; i++) gel(C,i) = ch_C(gel(dataCR, i));
    2235         322 :     n = zeta_get_N0(vecmax(C), zeta_get_limx(r1, r2, newprec));
    2236         322 :     if (n > BND) n = BND;
    2237         322 :     if (DEBUGLEVEL) err_printf("N0 in QuickPol: %ld \n", n);
    2238         322 :     InitPrimes(bnr, n, &LIST);
    2239             : 
    2240         322 :     L1 = cgetg(cl+1, t_VEC);
    2241             :     /* use L(1) = sum (an / n) */
    2242        1351 :     for (i = 1; i <= cl; i++)
    2243             :     {
    2244        1029 :       GEN dtcr = gel(dataCR,i);
    2245        1029 :       long d = ch_phideg(dtcr);
    2246        1029 :       matan = ComputeCoeff(dtcr, &LIST, n, d);
    2247        1029 :       av2 = avma;
    2248        1029 :       p1 = real_0(newprec); p2 = gel(ch_CHI(dtcr), 2);
    2249      303079 :       for (j = 1; j <= n; j++)
    2250      302050 :         if ( (an = EvalCoeff(p2, matan[j], d)) )
    2251      116697 :           p1 = gadd(p1, gdivgu(an, j));
    2252        1029 :       gel(L1,i) = gerepileupto(av2, p1);
    2253        1029 :       FreeMat(matan, n);
    2254             :     }
    2255         322 :     p1 = gmul2n(powruhalf(mppi(newprec), N-2), 1);
    2256             : 
    2257        1351 :     for (i = 1; i <= cl; i++)
    2258             :     {
    2259             :       long r;
    2260        1029 :       GEN WW, A = AChi(gel(dataCR,i), &r, 0, newprec);
    2261        1029 :       WW = gmul(gel(C,i), gmul(A, gel(W,i)));
    2262        1029 :       gel(Lp,i) = gdiv(gmul(WW, conj_i(gel(L1,i))), p1);
    2263             :     }
    2264             :   }
    2265             : 
    2266         644 :   p1 = gel(data,3);
    2267         644 :   den = flag ? h: 2*h;
    2268         644 :   vzeta = cgetg(h + 1, t_VEC);
    2269        4060 :   for (i = 1; i <= h; i++)
    2270             :   {
    2271        3416 :     GEN z = gen_0, sig = gel(p1,i);
    2272       17094 :     for (j = 1; j <= cl; j++)
    2273             :     {
    2274       13678 :       GEN dtcr = gel(dataCR,j), CHI = ch_CHI(dtcr);
    2275       13678 :       GEN t = mulreal(gel(Lp,j), CharEval(CHI, sig));
    2276       13678 :       if (chi_get_deg(CHI) != 2) t = gmul2n(t, 1); /* character not real */
    2277       13678 :       z = gadd(z, t);
    2278             :     }
    2279        3416 :     gel(vzeta,i) = gmul2n(gcosh(gdivgu(z,den), newprec), 1);
    2280             :   }
    2281         644 :   polrelnum = roots_to_pol(vzeta, 0);
    2282         644 :   if (DEBUGLEVEL)
    2283             :   {
    2284           0 :     if (DEBUGLEVEL>1) {
    2285           0 :       err_printf("polrelnum = %Ps\n", polrelnum);
    2286           0 :       err_printf("zetavalues = %Ps\n", vzeta);
    2287           0 :       if (!flag)
    2288           0 :         err_printf("Checking the square-root of the Stark unit...\n");
    2289             :     }
    2290           0 :     timer_printf(&ti, "Compute %s", flag? "quickpol": "polrelnum");
    2291             :   }
    2292         644 :   if (flag) return gerepilecopy(av, polrelnum);
    2293             : 
    2294             :   /* try to recognize this polynomial */
    2295         322 :   polrel = RecCoeff(nf, polrelnum, v, newprec);
    2296         322 :   if (!polrel)
    2297             :   {
    2298        1512 :     for (j = 1; j <= h; j++)
    2299        1295 :       gel(vzeta,j) = gsubgs(gsqr(gel(vzeta,j)), 2);
    2300         217 :     polrelnum = roots_to_pol(vzeta, 0);
    2301         217 :     if (DEBUGLEVEL)
    2302             :     {
    2303           0 :       if (DEBUGLEVEL>1) {
    2304           0 :         err_printf("It's not a square...\n");
    2305           0 :         err_printf("polrelnum = %Ps\n", polrelnum);
    2306             :       }
    2307           0 :       timer_printf(&ti, "Compute polrelnum");
    2308             :     }
    2309         217 :     polrel = RecCoeff(nf, polrelnum, v, newprec);
    2310             :   }
    2311         322 :   if (!polrel) /* FAILED */
    2312             :   {
    2313           0 :     const long EXTRA_BITS = 64;
    2314             :     long incr_pr;
    2315           0 :     if (++cpt >= 3) pari_err_PREC( "stark (computation impossible)");
    2316             :     /* estimate needed precision */
    2317           0 :     incr_pr = gprecision(polrelnum) - gexpo(polrelnum);
    2318           0 :     if (incr_pr < 0) incr_pr = -incr_pr + EXTRA_BITS;
    2319           0 :     newprec += nbits2extraprec(maxss(3*EXTRA_BITS, cpt*incr_pr));
    2320           0 :     if (DEBUGLEVEL) pari_warn(warnprec, "AllStark", newprec);
    2321           0 :     CharNewPrec(data, newprec);
    2322           0 :     nf = bnr_get_nf(ch_bnr(gel(dataCR,1)));
    2323           0 :     goto LABDOUB;
    2324             :   }
    2325             : 
    2326         322 :   if (DEBUGLEVEL) {
    2327           0 :     if (DEBUGLEVEL>1) err_printf("polrel = %Ps\n", polrel);
    2328           0 :     timer_printf(&ti, "Recpolnum");
    2329             :   }
    2330         322 :   return gerepilecopy(av, polrel);
    2331             : }
    2332             : 
    2333             : /********************************************************************/
    2334             : /*                        Main functions                            */
    2335             : /********************************************************************/
    2336             : static GEN
    2337           0 : bnrstark_cyclic(GEN bnr, GEN dtQ, long prec)
    2338             : {
    2339           0 :   GEN v, vH, cyc = gel(dtQ,2), U = gel(dtQ,3), M = ZM_inv(U, NULL);
    2340           0 :   long i, j, l = lg(M);
    2341             : 
    2342             :   /* M = indep. generators of Cl_f/subgp, restrict to cyclic components */
    2343           0 :   vH = cgetg(l, t_VEC);
    2344           0 :   for (i = j = 1; i < l; i++)
    2345             :   {
    2346           0 :     if (is_pm1(gel(cyc,i))) break;
    2347           0 :     gel(vH, j++) = ZM_hnfmodid(vecsplice(M,i), cyc);
    2348             :   }
    2349           0 :   setlg(vH, j); v = cgetg(l, t_VEC);
    2350           0 :   for (i = 1; i < j; i++) gel(v,i) = bnrstark(bnr, gel(vH,i), prec);
    2351           0 :   return v;
    2352             : }
    2353             : GEN
    2354         203 : bnrstark(GEN bnr, GEN subgrp, long prec)
    2355             : {
    2356             :   long newprec;
    2357         203 :   pari_sp av = avma;
    2358             :   GEN nf, data, dtQ;
    2359             : 
    2360             :   /* check the bnr */
    2361         203 :   checkbnr(bnr); nf  = bnr_get_nf(bnr);
    2362         203 :   if (nf_get_degree(nf) == 1) return galoissubcyclo(bnr, subgrp, 0, 0);
    2363         203 :   if (!nf_get_varn(nf))
    2364           0 :     pari_err_PRIORITY("bnrstark", nf_get_pol(nf), "=", 0);
    2365         203 :   if (nf_get_r2(nf)) pari_err_DOMAIN("bnrstark", "r2", "!=", gen_0, nf);
    2366             : 
    2367             :   /* compute bnr(conductor) */
    2368         196 :   bnr_subgroup_sanitize(&bnr, &subgrp);
    2369         196 :   if (gequal1(ZM_det_triangular(subgrp))) { set_avma(av); return pol_x(0); }
    2370             : 
    2371             :   /* check the class field */
    2372         196 :   if (!gequal0(gel(bnr_get_mod(bnr), 2)))
    2373           7 :     pari_err_DOMAIN("bnrstark", "r2(class field)", "!=", gen_0, bnr);
    2374             : 
    2375             :   /* find a suitable extension N */
    2376         189 :   dtQ = InitQuotient(subgrp);
    2377         189 :   data  = FindModulus(bnr, dtQ, &newprec);
    2378         189 :   if (!data) return gerepileupto(av, bnrstark_cyclic(bnr, dtQ, prec));
    2379         189 :   if (DEBUGLEVEL>1 && newprec > prec)
    2380           0 :     err_printf("new precision: %ld\n", newprec);
    2381         189 :   return gerepileupto(av, AllStark(data, 0, newprec));
    2382             : }
    2383             : 
    2384             : /* For each character of Cl(bnr)/subgp, compute L(1, chi) (or equivalently
    2385             :  * the first nonzero term c(chi) of the expansion at s = 0).
    2386             :  * If flag & 1: compute the value at s = 1 (for nontrivial characters),
    2387             :  * else compute the term c(chi) and return [r(chi), c(chi)] where r(chi) is
    2388             :  *   the order of L(s, chi) at s = 0.
    2389             :  * If flag & 2: compute the value of the L-function L_S(s, chi) where S is the
    2390             :  *   set of places dividing the modulus of bnr (and the infinite places),
    2391             :  * else
    2392             :  *   compute the value of the primitive L-function attached to chi,
    2393             :  * If flag & 4: return also the character */
    2394             : GEN
    2395          70 : bnrL1(GEN bnr, GEN subgp, long flag, long prec)
    2396             : {
    2397             :   GEN L1, ch, Qt, z;
    2398             :   long l, h;
    2399          70 :   pari_sp av = avma;
    2400             : 
    2401          70 :   checkbnr(bnr);
    2402          70 :   if (flag < 0 || flag > 8) pari_err_FLAG("bnrL1");
    2403             : 
    2404          70 :   subgp = bnr_subgroup_check(bnr, subgp, NULL);
    2405          70 :   if (!subgp) subgp = diagonal_shallow(bnr_get_cyc(bnr));
    2406             : 
    2407          70 :   Qt = InitQuotient(subgp);
    2408          70 :   ch = AllChars(bnr, Qt, 0); l = lg(ch);
    2409          70 :   h = itou(gel(Qt,1));
    2410          70 :   L1 = cgetg((flag&1)? h: h+1, t_VEC);
    2411          70 :   if (l > 1)
    2412             :   {
    2413          63 :     GEN W, S, T, CR = InitChar(bnr, ch, 1, prec), dataCR = gel(CR,2);
    2414             :     long i, j;
    2415             : 
    2416          63 :     GetST(bnr, &S, &T, CR, prec);
    2417          63 :     W = AllArtinNumbers(CR, prec);
    2418         301 :     for (i = j = 1; i < l; i++)
    2419             :     {
    2420         238 :       GEN chi = gel(ch,i);
    2421         238 :       z = GetValue(gel(dataCR,i), gel(W,i), gel(S,i), gel(T,i), flag, prec);
    2422         238 :       gel(L1,j++) = (flag & 4)? mkvec2(gel(chi,1), z): z;
    2423         238 :       if (lg(chi) == 4)
    2424             :       { /* nonreal */
    2425         133 :         z = conj_i(z);
    2426         133 :         gel(L1, j++) = (flag & 4)? mkvec2(gel(chi,3), z): z;
    2427             :       }
    2428             :     }
    2429             :   }
    2430          70 :   if (!(flag & 1))
    2431             :   { /* trivial character */
    2432          35 :     z = GetValue1(bnr, flag & 2, prec);
    2433          35 :     if (flag & 4)
    2434             :     {
    2435           0 :       GEN chi = zerovec(lg(bnr_get_cyc(bnr))-1);
    2436           0 :       z = mkvec2(chi, z);
    2437             :     }
    2438          35 :     gel(L1,h) = z;
    2439             :   }
    2440          70 :   return gerepilecopy(av, L1);
    2441             : }
    2442             : 
    2443             : /*******************************************************************/
    2444             : /*                                                                 */
    2445             : /*       Hilbert and Ray Class field using Stark                   */
    2446             : /*                                                                 */
    2447             : /*******************************************************************/
    2448             : /* P in A[x,y], deg_y P < 2, return P0 and P1 in A[x] such that P = P0 + P1 y */
    2449             : static void
    2450         133 : split_pol_quad(GEN P, GEN *gP0, GEN *gP1)
    2451             : {
    2452         133 :   long i, l = lg(P);
    2453         133 :   GEN P0 = cgetg(l, t_POL), P1 = cgetg(l, t_POL);
    2454         133 :   P0[1] = P1[1] = P[1];
    2455        1211 :   for (i = 2; i < l; i++)
    2456             :   {
    2457        1078 :     GEN c = gel(P,i), c0 = c, c1 = gen_0;
    2458        1078 :     if (typ(c) == t_POL) /* write c = c1 y + c0 */
    2459         945 :       switch(degpol(c))
    2460             :       {
    2461           0 :         case -1: c0 = gen_0; break;
    2462         945 :         default: c1 = gel(c,3); /* fall through */
    2463         945 :         case  0: c0 = gel(c,2); break;
    2464             :       }
    2465        1078 :     gel(P0,i) = c0; gel(P1,i) = c1;
    2466             :   }
    2467         133 :   *gP0 = normalizepol_lg(P0, l);
    2468         133 :   *gP1 = normalizepol_lg(P1, l);
    2469         133 : }
    2470             : 
    2471             : /* k = nf quadratic field, P relative equation of H_k (Hilbert class field)
    2472             :  * return T in Z[X], such that H_k / Q is the compositum of Q[X]/(T) and k */
    2473             : static GEN
    2474         133 : makescind(GEN nf, GEN P)
    2475             : {
    2476         133 :   GEN Pp, p, pol, G, L, a, roo, P0,P1, Ny,Try, nfpol = nf_get_pol(nf);
    2477             :   long i, is_P;
    2478             : 
    2479         133 :   P = lift_shallow(P);
    2480         133 :   split_pol_quad(P, &P0, &P1);
    2481             :   /* P = P0 + y P1, Norm_{k/Q}(P) = P0^2 + Tr y P0P1 + Ny P1^2, irreducible/Q */
    2482         133 :   Ny = gel(nfpol, 2);
    2483         133 :   Try = negi(gel(nfpol, 3));
    2484         133 :   pol = RgX_add(RgX_sqr(P0), RgX_Rg_mul(RgX_sqr(P1), Ny));
    2485         133 :   if (signe(Try)) pol = RgX_add(pol, RgX_Rg_mul(RgX_mul(P0,P1), Try));
    2486             :   /* pol = rnfequation(nf, P); */
    2487         133 :   G = galoisinit(pol, NULL);
    2488         133 :   L = gal_get_group(G);
    2489         133 :   p = gal_get_p(G);
    2490         133 :   a = FpX_oneroot(nfpol, p);
    2491             :   /* P mod a prime \wp above p (which splits) */
    2492         133 :   Pp = FpXY_evalx(P, a, p);
    2493         133 :   roo = gal_get_roots(G);
    2494         133 :   is_P = gequal0( FpX_eval(Pp, remii(gel(roo,1),p), p) );
    2495             :   /* each roo[i] mod p is a root of P or (exclusive) tau(P) mod \wp */
    2496             :   /* record whether roo[1] is a root of P or tau(P) */
    2497             : 
    2498        1022 :   for (i = 1; i < lg(L); i++)
    2499             :   {
    2500        1022 :     GEN perm = gel(L,i);
    2501        1022 :     long k = perm[1]; if (k == 1) continue;
    2502         889 :     k = gequal0( FpX_eval(Pp, remii(gel(roo,k),p), p) );
    2503             :     /* roo[k] is a root of the other polynomial */
    2504         889 :     if (k != is_P)
    2505             :     {
    2506         133 :       ulong o = perm_orderu(perm);
    2507         133 :       if (o != 2) perm = perm_powu(perm, o >> 1);
    2508             :       /* perm has order two and doesn't belong to Gal(H_k/k) */
    2509         133 :       return polredbest(galoisfixedfield(G, perm, 1, varn(P)), 0);
    2510             :     }
    2511             :   }
    2512           0 :   pari_err_BUG("makescind");
    2513             :   return NULL; /*LCOV_EXCL_LINE*/
    2514             : }
    2515             : 
    2516             : /* pbnf = NULL if no bnf is needed, f = NULL may be passed for a trivial
    2517             :  * conductor */
    2518             : static void
    2519         847 : quadray_init(GEN *pD, GEN *pbnf, long prec)
    2520             : {
    2521         847 :   GEN D = *pD, nf, bnf = NULL;
    2522         847 :   if (typ(D) == t_INT)
    2523             :   {
    2524             :     int isfund;
    2525         812 :     if (pbnf) {
    2526         252 :       bnf = Buchall(quadpoly0(D, 1), nf_FORCE, prec);
    2527         252 :       nf = bnf_get_nf(bnf);
    2528         252 :       isfund = equalii(D, nf_get_disc(nf));
    2529             :     }
    2530             :     else
    2531         560 :       isfund = Z_isfundamental(D);
    2532         812 :     if (!isfund) pari_err_DOMAIN("quadray", "isfundamental(D)", "=",gen_0, D);
    2533             :   }
    2534             :   else
    2535             :   {
    2536          35 :     bnf = checkbnf(D);
    2537          35 :     nf = bnf_get_nf(bnf);
    2538          35 :     if (nf_get_degree(nf) != 2)
    2539           7 :       pari_err_DOMAIN("quadray", "degree", "!=", gen_2, nf_get_pol(nf));
    2540          28 :     D = nf_get_disc(nf);
    2541             :   }
    2542         833 :   if (pbnf) *pbnf = bnf;
    2543         833 :   *pD = D;
    2544         833 : }
    2545             : 
    2546             : /* compute the polynomial over Q of the Hilbert class field of
    2547             :    Q(sqrt(D)) where D is a positive fundamental discriminant */
    2548             : static GEN
    2549         147 : quadhilbertreal(GEN D, long prec)
    2550             : {
    2551             :   GEN bnf, bnr, dtQ, data, M;
    2552             :   long newprec;
    2553             :   pari_timer T;
    2554             : 
    2555         147 :   quadray_init(&D, &bnf, prec);
    2556         147 :   switch(itou_or_0(cyc_get_expo(bnf_get_cyc(bnf))))
    2557             :   {
    2558           0 :     case 1: return pol_x(0);
    2559          14 :     case 2: return GenusFieldQuadReal(D);
    2560             :   }
    2561         133 :   bnr  = Buchray(bnf, gen_1, nf_INIT);
    2562         133 :   M = diagonal_shallow(bnr_get_cyc(bnr));
    2563         133 :   dtQ = InitQuotient(M);
    2564             : 
    2565         133 :   if (DEBUGLEVEL) timer_start(&T);
    2566         133 :   data = FindModulus(bnr, dtQ, &newprec);
    2567         133 :   if (DEBUGLEVEL) timer_printf(&T,"FindModulus");
    2568         133 :   if (!data) return bnrstark_cyclic(bnr, dtQ, prec);
    2569         133 :   return makescind(bnf_get_nf(bnf), AllStark(data, 0, newprec));
    2570             : }
    2571             : 
    2572             : /*******************************************************************/
    2573             : /*                                                                 */
    2574             : /*       Hilbert and Ray Class field using CM (Schertz)            */
    2575             : /*                                                                 */
    2576             : /*******************************************************************/
    2577             : /* form^2 = 1 ? */
    2578             : static int
    2579         813 : hasexp2(GEN form)
    2580             : {
    2581         813 :   GEN a = gel(form,1), b = gel(form,2), c = gel(form,3);
    2582         813 :   return !signe(b) || absequalii(a,b) || equalii(a,c);
    2583             : }
    2584             : static int
    2585        1323 : uhasexp2(GEN form)
    2586             : {
    2587        1323 :   long a = form[1], b = form[2], c = form[3];
    2588        1323 :   return !b || a == labs(b) || a == c;
    2589             : }
    2590             : 
    2591             : GEN
    2592         455 : qfbforms(GEN D)
    2593             : {
    2594         455 :   ulong d = itou(D), dover3 = d/3, t, b2, a, b, c, h;
    2595         455 :   GEN L = cgetg((long)(sqrt((double)d) * log2(d)), t_VEC);
    2596         455 :   b2 = b = (d&1); h = 0;
    2597         455 :   if (!b) /* b = 0 treated separately to avoid special cases */
    2598             :   {
    2599         252 :     t = d >> 2; /* (b^2 - D) / 4*/
    2600        2954 :     for (a=1; a*a<=t; a++)
    2601        2702 :       if (c = t/a, t == c*a) gel(L,++h) = mkvecsmall3(a,0,c);
    2602         252 :     b = 2; b2 = 4;
    2603             :   }
    2604             :   /* now b > 0, b = D (mod 2) */
    2605        8078 :   for ( ; b2 <= dover3; b += 2, b2 = b*b)
    2606             :   {
    2607        7623 :     t = (b2 + d) >> 2; /* (b^2 - D) / 4*/
    2608             :     /* b = a */
    2609        7623 :     if (c = t/b, t == c*b) gel(L,++h) = mkvecsmall3(b,b,c);
    2610             :     /* b < a < c */
    2611     1912029 :     for (a = b+1; a*a < t; a++)
    2612     1904406 :       if (c = t/a, t == c*a)
    2613             :       {
    2614        1057 :         gel(L,++h) = mkvecsmall3(a, b,c);
    2615        1057 :         gel(L,++h) = mkvecsmall3(a,-b,c);
    2616             :       }
    2617             :     /* a = c */
    2618        7623 :     if (a * a == t) gel(L,++h) = mkvecsmall3(a,b,a);
    2619             :   }
    2620         455 :   setlg(L,h+1); return L;
    2621             : }
    2622             : 
    2623             : /* gcd(n, 24) */
    2624             : static long
    2625         813 : GCD24(long n)
    2626             : {
    2627         813 :   switch(n % 24)
    2628             :   {
    2629          35 :     case 0: return 24;
    2630          35 :     case 1: return 1;
    2631          28 :     case 2: return 2;
    2632           0 :     case 3: return 3;
    2633         119 :     case 4: return 4;
    2634           0 :     case 5: return 1;
    2635         105 :     case 6: return 6;
    2636           0 :     case 7: return 1;
    2637           0 :     case 8: return 8;
    2638           0 :     case 9: return 3;
    2639          91 :     case 10: return 2;
    2640           0 :     case 11: return 1;
    2641         119 :     case 12: return 12;
    2642           0 :     case 13: return 1;
    2643           0 :     case 14: return 2;
    2644           0 :     case 15: return 3;
    2645          91 :     case 16: return 8;
    2646           0 :     case 17: return 1;
    2647          92 :     case 18: return 6;
    2648           0 :     case 19: return 1;
    2649           0 :     case 20: return 4;
    2650           0 :     case 21: return 3;
    2651          98 :     case 22: return 2;
    2652           0 :     case 23: return 1;
    2653           0 :     default: return 0;
    2654             :   }
    2655             : }
    2656             : 
    2657             : struct gpq_data {
    2658             :   long p, q;
    2659             :   GEN sqd; /* sqrt(D), t_REAL */
    2660             :   GEN u, D;
    2661             :   GEN pq, pq2; /* p*q, 2*p*q */
    2662             :   GEN qfpq ; /* class of \P * \Q */
    2663             : };
    2664             : 
    2665             : /* find P and Q two non principal prime ideals (above p <= q) such that
    2666             :  *   cl(P) = cl(Q) if P,Q have order 2 in Cl(K).
    2667             :  *   Ensure that e = 24 / gcd(24, (p-1)(q-1)) = 1 */
    2668             : /* D t_INT, discriminant */
    2669             : static void
    2670          49 : init_pq(GEN D, struct gpq_data *T)
    2671             : {
    2672          49 :   const long Np = 6547; /* N.B. primepi(50000) = 5133 */
    2673          49 :   const ulong maxq = 50000;
    2674          49 :   GEN listp = cgetg(Np + 1, t_VECSMALL); /* primes p */
    2675          49 :   GEN listP = cgetg(Np + 1, t_VEC); /* primeform(p) if of order 2, else NULL */
    2676          49 :   GEN gcd24 = cgetg(Np + 1, t_VECSMALL); /* gcd(p-1, 24) */
    2677             :   forprime_t S;
    2678          49 :   long l = 1;
    2679          49 :   double best = 0.;
    2680             :   ulong q;
    2681             : 
    2682          49 :   u_forprime_init(&S, 2, ULONG_MAX);
    2683          49 :   T->D = D;
    2684          49 :   T->p = T->q = 0;
    2685             :   for(;;)
    2686        1777 :   {
    2687             :     GEN Q;
    2688             :     long i, gcdq, mod;
    2689             :     int order2, store;
    2690             :     double t;
    2691             : 
    2692        1826 :     q = u_forprime_next(&S);
    2693        1826 :     if (best > 0 && q >= maxq)
    2694             :     {
    2695           0 :       if (DEBUGLEVEL)
    2696           0 :         pari_warn(warner,"possibly suboptimal (p,q) for D = %Ps", D);
    2697           0 :       break;
    2698             :     }
    2699        1826 :     if (kroiu(D, q) < 0) continue; /* inert */
    2700         890 :     Q = qfbred_i(primeform_u(D, q));
    2701         890 :     if (is_pm1(gel(Q,1))) continue; /* Q | q is principal */
    2702             : 
    2703         813 :     store = 1;
    2704         813 :     order2 = hasexp2(Q);
    2705         813 :     gcd24[l] = gcdq = GCD24(q-1);
    2706         813 :     mod = 24 / gcdq; /* mod must divide p-1 otherwise e > 1 */
    2707         813 :     listp[l] = q;
    2708         813 :     gel(listP,l) = order2 ? Q : NULL;
    2709         813 :     t = (q+1)/(double)(q-1);
    2710        2129 :     for (i = 1; i < l; i++) /* try all (p, q), p < q in listp */
    2711             :     {
    2712        1660 :       long p = listp[i], gcdp = gcd24[i];
    2713             :       double b;
    2714             :       /* P,Q order 2 => cl(Q) = cl(P) */
    2715        1660 :       if (order2 && gel(listP,i) && !gequal(gel(listP,i), Q)) continue;
    2716        1653 :       if (gcdp % gcdq == 0) store = 0; /* already a better one in the list */
    2717        1653 :       if ((p-1) % mod) continue;
    2718             : 
    2719         344 :       b = (t*(p+1)) / (p-1); /* (p+1)(q+1) / (p-1)(q-1) */
    2720         344 :       if (b > best) {
    2721          98 :         store = 0; /* (p,q) always better than (q,r) for r >= q */
    2722          98 :         best = b; T->q = q; T->p = p;
    2723          98 :         if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", p, q);
    2724             :       }
    2725             :       /* won't improve with this q as largest member */
    2726         344 :       if (best > 0) break;
    2727             :     }
    2728             :     /* if !store or (q,r) won't improve on current best pair, forget that q */
    2729         813 :     if (store && t*t > best)
    2730         119 :       if (++l >= Np) pari_err_BUG("quadhilbert (not enough primes)");
    2731         813 :     if (!best) /* (p,q) with p < q always better than (q,q) */
    2732             :     { /* try (q,q) */
    2733         140 :       if (gcdq >= 12 && umodiu(D, q)) /* e = 1 and unramified */
    2734             :       {
    2735           7 :         double b = (t*q) / (q-1); /* q(q+1) / (q-1)^2 */
    2736           7 :         if (b > best) {
    2737           7 :           best = b; T->q = T->p = q;
    2738           7 :           if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", q, q);
    2739             :         }
    2740             :       }
    2741             :     }
    2742             :     /* If (p1+1)(q+1) / (p1-1)(q-1) <= best, we can no longer improve
    2743             :      * even with best p : stop */
    2744         813 :     if ((listp[1]+1)*t <= (listp[1]-1)*best) break;
    2745             :   }
    2746          49 :   if (DEBUGLEVEL>1)
    2747           0 :     err_printf("(p, q) = %ld, %ld; gain = %f\n", T->p, T->q, 12*best);
    2748          49 : }
    2749             : 
    2750             : static GEN
    2751        4102 : gpq(GEN form, struct gpq_data *T)
    2752             : {
    2753        4102 :   pari_sp av = avma;
    2754        4102 :   long a = form[1], b = form[2], c = form[3], p = T->p, q = T->q;
    2755             :   GEN form2, w, z;
    2756        4102 :   int fl, real = 0;
    2757             : 
    2758        4102 :   form2 = qfbcomp_i(T->qfpq, mkqfb(stoi(a), stoi(-b), stoi(c), T->D));
    2759             :   /* form2 and form yield complex conjugate roots : only compute for the
    2760             :    * lexicographically smallest of the 2 */
    2761        4102 :   fl = cmpis(gel(form2,1), a);
    2762        4102 :   if (fl <= 0)
    2763             :   {
    2764        2156 :     if (fl < 0) return NULL;
    2765         210 :     fl = cmpis(gel(form2,2), b);
    2766         210 :     if (fl <= 0)
    2767             :     {
    2768         147 :       if (fl < 0) return NULL;
    2769             :       /* form == form2 : real root */
    2770          84 :       real = 1;
    2771             :     }
    2772             :   }
    2773             : 
    2774        2093 :   if (p == 2) { /* (a,b,c) = (1,1,0) mod 2 ? */
    2775         203 :     if (a % q == 0 && (a & b & 1) && !(c & 1))
    2776             :     { /* apply S : make sure that (a,b,c) represents odd values */
    2777           0 :       lswap(a,c); b = -b;
    2778             :     }
    2779             :   }
    2780        2093 :   if (a % p == 0 || a % q == 0)
    2781             :   { /* apply T^k, look for c' = a k^2 + b k + c coprime to N */
    2782         595 :     while (c % p == 0 || c % q == 0)
    2783             :     {
    2784          98 :       c += a + b;
    2785          98 :       b += a << 1;
    2786             :     }
    2787         497 :     lswap(a, c); b = -b; /* apply S */
    2788             :   }
    2789             :   /* now (a,b,c) ~ form and (a,pq) = 1 */
    2790             : 
    2791             :   /* gcd(2a, u) = 2,  w = u mod 2pq, -b mod 2a */
    2792        2093 :   w = Z_chinese(T->u, stoi(-b), T->pq2, utoipos(a << 1));
    2793        2093 :   z = double_eta_quotient(utoipos(a), w, T->D, T->p, T->q, T->pq, T->sqd);
    2794        2093 :   if (real && typ(z) == t_COMPLEX) z = gcopy(gel(z, 1));
    2795        2093 :   return gerepileupto(av, z);
    2796             : }
    2797             : 
    2798             : /* returns an equation for the Hilbert class field of Q(sqrt(D)), D < 0
    2799             :  * fundamental discriminant */
    2800             : static GEN
    2801         462 : quadhilbertimag(GEN D)
    2802             : {
    2803             :   GEN L, P, Pi, Pr, qfp, u;
    2804             :   long h, i, prec;
    2805             :   struct gpq_data T;
    2806             :   pari_timer ti;
    2807             : 
    2808         462 :   if (DEBUGLEVEL>1) timer_start(&ti);
    2809         462 :   if (lgefint(D) == 3)
    2810         462 :     switch (D[2]) { /* = |D|; special cases where e > 1 */
    2811           7 :       case 3:
    2812             :       case 4:
    2813             :       case 7:
    2814             :       case 8:
    2815             :       case 11:
    2816             :       case 19:
    2817             :       case 43:
    2818             :       case 67:
    2819           7 :       case 163: return pol_x(0);
    2820             :     }
    2821         455 :   L = qfbforms(D);
    2822         455 :   h = lg(L)-1;
    2823         455 :   if (! (h & (h - 1))) /* power of 2 */
    2824             :   { /* check whether > |Cl|/2 elements have order <= 2 ==> 2-elementary */
    2825         413 :     long lim = (h>>1) + 1;
    2826        1729 :     for (i=1; i <= lim; i++)
    2827        1323 :       if (!uhasexp2(gel(L,i))) break;
    2828         413 :     if (i > lim) return GenusFieldQuadImag(D);
    2829             :   }
    2830          49 :   if (DEBUGLEVEL>1) timer_printf(&ti,"class number = %ld",h);
    2831          49 :   init_pq(D, &T);
    2832          49 :   qfp = primeform_u(D, T.p);
    2833          49 :   T.pq =  muluu(T.p, T.q);
    2834          49 :   T.pq2 = shifti(T.pq,1);
    2835          49 :   if (T.p == T.q)
    2836             :   {
    2837           0 :     GEN qfbp2 = qfbcompraw(qfp, qfp);
    2838           0 :     u = gel(qfbp2,2);
    2839           0 :     T.u = modii(u, T.pq2);
    2840           0 :     T.qfpq = qfbred_i(qfbp2);
    2841             :   }
    2842             :   else
    2843             :   {
    2844          49 :     GEN qfq = primeform_u(D, T.q), bp = gel(qfp,2), bq = gel(qfq,2);
    2845          49 :     T.u = Z_chinese(bp, bq, utoipos(T.p << 1), utoipos(T.q << 1));
    2846             :     /* T.u = bp (mod 2p), T.u = bq (mod 2q) */
    2847          49 :     T.qfpq = qfbcomp_i(qfp, qfq);
    2848             :   }
    2849             :   /* u modulo 2pq */
    2850          49 :   prec = LOWDEFAULTPREC;
    2851          49 :   Pr = cgetg(h+1,t_VEC);
    2852          49 :   Pi = cgetg(h+1,t_VEC);
    2853             :   for(;;)
    2854          14 :   {
    2855          63 :     long ex, exmax = 0, r1 = 0, r2 = 0;
    2856          63 :     pari_sp av0 = avma;
    2857          63 :     T.sqd = sqrtr_abs(itor(D, prec));
    2858        4165 :     for (i=1; i<=h; i++)
    2859             :     {
    2860        4102 :       GEN s = gpq(gel(L,i), &T);
    2861        4102 :       if (DEBUGLEVEL>3) err_printf("%ld ", i);
    2862        4102 :       if (!s) continue;
    2863        2093 :       if (typ(s) != t_COMPLEX) gel(Pr, ++r1) = s; /* real root */
    2864        2009 :       else                     gel(Pi, ++r2) = s;
    2865        2093 :       ex = gexpo(s); if (ex > 0) exmax += ex;
    2866             :     }
    2867          63 :     if (DEBUGLEVEL>1) timer_printf(&ti,"roots");
    2868          63 :     setlg(Pr, r1+1);
    2869          63 :     setlg(Pi, r2+1);
    2870          63 :     P = roots_to_pol_r1(shallowconcat(Pr,Pi), 0, r1);
    2871          63 :     P = grndtoi(P,&exmax);
    2872          63 :     if (DEBUGLEVEL>1) timer_printf(&ti,"product, error bits = %ld",exmax);
    2873          63 :     if (exmax <= -10) break;
    2874          14 :     set_avma(av0); prec += nbits2extraprec(DEFAULTPREC + exmax);
    2875          14 :     if (DEBUGLEVEL) pari_warn(warnprec,"quadhilbertimag",prec);
    2876             :   }
    2877          49 :   return P;
    2878             : }
    2879             : 
    2880             : GEN
    2881         574 : quadhilbert(GEN D, long prec)
    2882             : {
    2883         574 :   pari_sp av = avma;
    2884         574 :   GEN d = D;
    2885         574 :   quadray_init(&d, NULL, 0);
    2886         973 :   return gerepileupto(av, signe(d)>0? quadhilbertreal(D,prec)
    2887         413 :                                     : quadhilbertimag(d));
    2888             : }
    2889             : 
    2890             : /* return a vector of all roots of 1 in bnf [not necessarily quadratic] */
    2891             : static GEN
    2892          70 : getallrootsof1(GEN bnf)
    2893             : {
    2894          70 :   GEN T, u, nf = bnf_get_nf(bnf), tu;
    2895          70 :   long i, n = bnf_get_tuN(bnf);
    2896             : 
    2897          70 :   if (n == 2) {
    2898          56 :     long N = nf_get_degree(nf);
    2899          56 :     return mkvec2(scalarcol_shallow(gen_m1, N),
    2900             :                   scalarcol_shallow(gen_1, N));
    2901             :   }
    2902          14 :   tu = poltobasis(nf, bnf_get_tuU(bnf));
    2903          14 :   T = zk_multable(nf, tu);
    2904          14 :   u = cgetg(n+1, t_VEC); gel(u,1) = tu;
    2905          56 :   for (i=2; i <= n; i++) gel(u,i) = ZM_ZC_mul(T, gel(u,i-1));
    2906          14 :   return u;
    2907             : }
    2908             : /* assume bnr has the right conductor */
    2909             : static GEN
    2910          70 : get_lambda(GEN bnr)
    2911             : {
    2912          70 :   GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf), pol = nf_get_pol(nf);
    2913          70 :   GEN f = gel(bnr_get_mod(bnr), 1), labas, lamodf, u;
    2914          70 :   long a, b, f2, i, lu, v = varn(pol);
    2915             : 
    2916          70 :   f2 = 2 * itos(gcoeff(f,1,1));
    2917          70 :   u = getallrootsof1(bnf); lu = lg(u);
    2918         238 :   for (i=1; i<lu; i++)
    2919         168 :     gel(u,i) = ZC_hnfrem(gel(u,i), f); /* roots of 1, mod f */
    2920          70 :   if (DEBUGLEVEL>1)
    2921           0 :     err_printf("quadray: looking for [a,b] != unit mod 2f\n[a,b] = ");
    2922         168 :   for (a=0; a<f2; a++)
    2923        2576 :     for (b=0; b<f2; b++)
    2924             :     {
    2925        2478 :       GEN la = deg1pol_shallow(stoi(a), stoi(b), v); /* ax + b */
    2926        2478 :       if (umodiu(gnorm(mkpolmod(la, pol)), f2) != 1) continue;
    2927         224 :       if (DEBUGLEVEL>1) err_printf("[%ld,%ld] ",a,b);
    2928             : 
    2929         224 :       labas = poltobasis(nf, la);
    2930         224 :       lamodf = ZC_hnfrem(labas, f);
    2931         469 :       for (i=1; i<lu; i++)
    2932         399 :         if (ZV_equal(lamodf, gel(u,i))) break;
    2933         224 :       if (i < lu) continue; /* la = unit mod f */
    2934          70 :       if (DEBUGLEVEL)
    2935             :       {
    2936           0 :         if (DEBUGLEVEL>1) err_printf("\n");
    2937           0 :         err_printf("lambda = %Ps\n",la);
    2938             :       }
    2939          70 :       return labas;
    2940             :     }
    2941           0 :   pari_err_BUG("get_lambda");
    2942             :   return NULL;/*LCOV_EXCL_LINE*/
    2943             : }
    2944             : 
    2945             : static GEN
    2946        8778 : to_approx(GEN nf, GEN a)
    2947             : {
    2948        8778 :   GEN M = nf_get_M(nf);
    2949        8778 :   return gadd(gel(a,1), gmul(gcoeff(M,1,2),gel(a,2)));
    2950             : }
    2951             : /* Z-basis for a (over C) */
    2952             : static GEN
    2953        4354 : get_om(GEN nf, GEN a) {
    2954        4354 :   return mkvec2(to_approx(nf,gel(a,2)),
    2955        4354 :                 to_approx(nf,gel(a,1)));
    2956             : }
    2957             : 
    2958             : /* Compute all elts in class group G = [|G|,c,g], c=cyclic factors, g=gens.
    2959             :  * Set list[j + 1] = g1^e1...gk^ek where j is the integer
    2960             :  *   ek + ck [ e(k-1) + c(k-1) [... + c2 [e1]]...] */
    2961             : static GEN
    2962          70 : getallelts(GEN bnr)
    2963             : {
    2964             :   GEN nf, C, c, g, list, pows, gk;
    2965             :   long lc, i, j, no;
    2966             : 
    2967          70 :   nf = bnr_get_nf(bnr);
    2968          70 :   no = itos( bnr_get_no(bnr) );
    2969          70 :   c = bnr_get_cyc(bnr);
    2970          70 :   g = bnr_get_gen_nocheck(bnr); lc = lg(c)-1;
    2971          70 :   list = cgetg(no+1,t_VEC);
    2972          70 :   gel(list,1) = matid(nf_get_degree(nf)); /* (1) */
    2973          70 :   if (!no) return list;
    2974             : 
    2975          70 :   pows = cgetg(lc+1,t_VEC);
    2976          70 :   c = leafcopy(c); settyp(c, t_VECSMALL);
    2977         140 :   for (i=1; i<=lc; i++)
    2978             :   {
    2979          70 :     long k = itos(gel(c,i));
    2980          70 :     c[i] = k;
    2981          70 :     gk = cgetg(k, t_VEC); gel(gk,1) = gel(g,i);
    2982        4284 :     for (j=2; j<k; j++)
    2983        4214 :       gel(gk,j) = idealmoddivisor(bnr, idealmul(nf, gel(gk,j-1), gel(gk,1)));
    2984          70 :     gel(pows,i) = gk; /* powers of g[i] */
    2985             :   }
    2986             : 
    2987          70 :   C = cgetg(lc+1, t_VECSMALL); C[1] = c[lc];
    2988          70 :   for (i=2; i<=lc; i++) C[i] = C[i-1] * c[lc-i+1];
    2989             :   /* C[i] = c(k-i+1) * ... * ck */
    2990             :   /* j < C[i+1] <==> j only involves g(k-i)...gk */
    2991          70 :   i = 1;
    2992        4354 :   for (j=1; j < C[1]; j++)
    2993        4284 :     gel(list, j+1) = gmael(pows,lc,j);
    2994          70 :   while(j<no)
    2995             :   {
    2996             :     long k;
    2997             :     GEN a;
    2998           0 :     if (j == C[i+1]) i++;
    2999           0 :     a = gmael(pows,lc-i,j/C[i]);
    3000           0 :     k = j%C[i] + 1;
    3001           0 :     if (k > 1) a = idealmoddivisor(bnr, idealmul(nf, a, gel(list,k)));
    3002           0 :     gel(list, ++j) = a;
    3003             :   }
    3004          70 :   return list;
    3005             : }
    3006             : 
    3007             : /* x quadratic integer (approximate), recognize it. If error return NULL */
    3008             : static GEN
    3009        4424 : findbezk(GEN nf, GEN x)
    3010             : {
    3011        4424 :   GEN a,b, M = nf_get_M(nf), u = gcoeff(M,1,2);
    3012             :   long ea, eb;
    3013             : 
    3014             :   /* u t_COMPLEX generator of nf.zk, write x ~ a + b u, a,b in Z */
    3015        4424 :   b = grndtoi(mpdiv(imag_i(x), gel(u,2)), &eb);
    3016        4424 :   if (eb > -20) return NULL;
    3017        4424 :   a = grndtoi(mpsub(real_i(x), mpmul(b,gel(u,1))), &ea);
    3018        4424 :   if (ea > -20) return NULL;
    3019        4424 :   return signe(b)? coltoalg(nf, mkcol2(a,b)): a;
    3020             : }
    3021             : 
    3022             : static GEN
    3023          70 : findbezk_pol(GEN nf, GEN x)
    3024             : {
    3025          70 :   long i, lx = lg(x);
    3026          70 :   GEN y = cgetg(lx,t_POL);
    3027        4494 :   for (i=2; i<lx; i++)
    3028        4424 :     if (! (gel(y,i) = findbezk(nf,gel(x,i))) ) return NULL;
    3029          70 :   y[1] = x[1]; return y;
    3030             : }
    3031             : 
    3032             : /* P approximation computed at initial precision prec. Compute needed prec
    3033             :  * to know P with 1 word worth of trailing decimals */
    3034             : static long
    3035           0 : get_prec(GEN P, long prec)
    3036             : {
    3037           0 :   long k = gprecision(P);
    3038           0 :   if (k == 3) return precdbl(prec); /* approximation not trustworthy */
    3039           0 :   k = prec - k; /* lost precision when computing P */
    3040           0 :   if (k < 0) k = 0;
    3041           0 :   k += nbits2prec(gexpo(P) + 128);
    3042           0 :   if (k <= prec) k = precdbl(prec); /* dubious: old prec should have worked */
    3043           0 :   return k;
    3044             : }
    3045             : 
    3046             : /* Compute data for ellphist */
    3047             : static GEN
    3048        4354 : ellphistinit(GEN om, long prec)
    3049             : {
    3050        4354 :   GEN res,om1b,om2b, om1 = gel(om,1), om2 = gel(om,2);
    3051             : 
    3052        4354 :   if (gsigne(imag_i(gdiv(om1,om2))) < 0) { swap(om1,om2); om = mkvec2(om1,om2); }
    3053        4354 :   om1b = conj_i(om1);
    3054        4354 :   om2b = conj_i(om2); res = cgetg(4,t_VEC);
    3055        4354 :   gel(res,1) = gdivgu(elleisnum(om,2,0,prec),12);
    3056        4354 :   gel(res,2) = gdiv(PiI2(prec), gmul(om2, imag_i(gmul(om1b,om2))));
    3057        4354 :   gel(res,3) = om2b; return res;
    3058             : }
    3059             : 
    3060             : /* Computes log(phi^*(z,om)), using res computed by ellphistinit */
    3061             : static GEN
    3062        8708 : ellphist(GEN om, GEN res, GEN z, long prec)
    3063             : {
    3064        8708 :   GEN u = imag_i(gmul(z, gel(res,3)));
    3065        8708 :   GEN zst = gsub(gmul(u, gel(res,2)), gmul(z,gel(res,1)));
    3066        8708 :   return gsub(ellsigma(om,z,1,prec),gmul2n(gmul(z,zst),-1));
    3067             : }
    3068             : 
    3069             : /* Computes phi^*(la,om)/phi^*(1,om) where (1,om) is an oriented basis of the
    3070             :    ideal gf*gc^{-1} */
    3071             : static GEN
    3072        4354 : computeth2(GEN om, GEN la, long prec)
    3073             : {
    3074        4354 :   GEN p1,p2,res = ellphistinit(om,prec);
    3075             : 
    3076        4354 :   p1 = gsub(ellphist(om,res,la,prec), ellphist(om,res,gen_1,prec));
    3077        4354 :   p2 = imag_i(p1);
    3078        4354 :   if (gexpo(real_i(p1)) > 20 || gexpo(p2) > minss(prec,realprec(p2)) - 10)
    3079           0 :     return NULL;
    3080        4354 :   return gexp(p1,prec);
    3081             : }
    3082             : 
    3083             : /* Computes P_2(X)=polynomial in Z_K[X] closest to prod_gc(X-th2(gc)) where
    3084             :    the product is over the ray class group bnr.*/
    3085             : static GEN
    3086          70 : computeP2(GEN bnr, long prec)
    3087             : {
    3088          70 :   long clrayno, i, first = 1;
    3089          70 :   pari_sp av=avma, av2;
    3090          70 :   GEN listray, P0, P, lanum, la = get_lambda(bnr);
    3091          70 :   GEN nf = bnr_get_nf(bnr), f = gel(bnr_get_mod(bnr), 1);
    3092          70 :   listray = getallelts(bnr);
    3093          70 :   clrayno = lg(listray)-1; av2 = avma;
    3094          70 : PRECPB:
    3095          70 :   if (!first)
    3096             :   {
    3097           0 :     if (DEBUGLEVEL) pari_warn(warnprec,"computeP2",prec);
    3098           0 :     nf = gerepilecopy(av2, nfnewprec_shallow(bnr_get_nf(bnr),prec));
    3099             :   }
    3100          70 :   first = 0; lanum = to_approx(nf,la);
    3101          70 :   P = cgetg(clrayno+1,t_VEC);
    3102        4424 :   for (i=1; i<=clrayno; i++)
    3103             :   {
    3104        4354 :     GEN om = get_om(nf, idealdiv(nf,f,gel(listray,i)));
    3105        4354 :     GEN s = computeth2(om,lanum,prec);
    3106        4354 :     if (!s) { prec = precdbl(prec); goto PRECPB; }
    3107        4354 :     gel(P,i) = s;
    3108             :   }
    3109          70 :   P0 = roots_to_pol(P, 0);
    3110          70 :   P = findbezk_pol(nf, P0);
    3111          70 :   if (!P) { prec = get_prec(P0, prec); goto PRECPB; }
    3112          70 :   return gerepilecopy(av, P);
    3113             : }
    3114             : 
    3115             : #define nexta(a) (a>0 ? -a : 1-a)
    3116             : static GEN
    3117          49 : do_compo(GEN A0, GEN B)
    3118             : {
    3119          49 :   long a, i, l = lg(B), v = fetch_var_higher();
    3120             :   GEN A, z;
    3121             :   /* now v > x = pol_x(0) > nf variable */
    3122          49 :   B = leafcopy(B); setvarn(B, v);
    3123         210 :   for (i = 2; i < l; i++) gel(B,i) = monomial(gel(B,i), l-i-1, 0);
    3124             :   /* B := x^deg(B) B(v/x) */
    3125          49 :   A = A0 = leafcopy(A0); setvarn(A0, v);
    3126          56 :   for  (a = 0;; a = nexta(a))
    3127             :   {
    3128          56 :     if (a) A = RgX_translate(A0, stoi(a));
    3129          56 :     z = resultant(A,B); /* in variable 0 */
    3130          56 :     if (issquarefree(z)) break;
    3131             :   }
    3132          49 :   (void)delete_var(); return z;
    3133             : }
    3134             : #undef nexta
    3135             : 
    3136             : static GEN
    3137          14 : galoisapplypol(GEN nf, GEN s, GEN x)
    3138             : {
    3139          14 :   long i, lx = lg(x);
    3140          14 :   GEN y = cgetg(lx,t_POL);
    3141             : 
    3142          56 :   for (i=2; i<lx; i++) gel(y,i) = galoisapply(nf,s,gel(x,i));
    3143          14 :   y[1] = x[1]; return y;
    3144             : }
    3145             : /* x quadratic, write it as ua + v, u,v rational */
    3146             : static GEN
    3147          70 : findquad(GEN a, GEN x, GEN p)
    3148             : {
    3149             :   long tu, tv;
    3150          70 :   pari_sp av = avma;
    3151             :   GEN u,v;
    3152          70 :   if (typ(x) == t_POLMOD) x = gel(x,2);
    3153          70 :   if (typ(a) == t_POLMOD) a = gel(a,2);
    3154          70 :   u = poldivrem(x, a, &v);
    3155          70 :   u = simplify_shallow(u); tu = typ(u);
    3156          70 :   v = simplify_shallow(v); tv = typ(v);
    3157          70 :   if (!is_scalar_t(tu)) pari_err_TYPE("findquad", u);
    3158          70 :   if (!is_scalar_t(tv)) pari_err_TYPE("findquad", v);
    3159          70 :   x = deg1pol(u, v, varn(a));
    3160          70 :   if (typ(x) == t_POL) x = gmodulo(x,p);
    3161          70 :   return gerepileupto(av, x);
    3162             : }
    3163             : static GEN
    3164          14 : findquad_pol(GEN p, GEN a, GEN x)
    3165             : {
    3166          14 :   long i, lx = lg(x);
    3167          14 :   GEN y = cgetg(lx,t_POL);
    3168          84 :   for (i=2; i<lx; i++) gel(y,i) = findquad(a, gel(x,i), p);
    3169          14 :   y[1] = x[1]; return y;
    3170             : }
    3171             : /* m is 3, 4 or 12 */
    3172             : static GEN
    3173          35 : compocyclo(GEN D, long m)
    3174          35 : { return do_compo(quadhilbertimag(D), polcyclo(m,0)); }
    3175             : /* m is prime or 4 * prime */
    3176             : static GEN
    3177          14 : compocyclop(GEN nf, long m)
    3178             : {
    3179          14 :   GEN sb,a,b,s,p1,p2,p3,res,polL,polLK,nfL, D = nf_get_disc(nf);
    3180             :   long ell,vx;
    3181             : 
    3182          14 :   p1 = quadhilbertimag(D);
    3183          14 :   p2 = polcyclo(m,0);
    3184          14 :   ell = odd(m)? m: (m>>2); /* prime */
    3185          14 :   if (absequalui(ell,D)) /* ell = |D| */
    3186             :   {
    3187           0 :     p2 = gcoeff(nffactor(nf,p2),1,1);
    3188           0 :     return do_compo(p1,p2);
    3189             :   }
    3190          14 :   if (ell%4 == 3) ell = -ell;
    3191             :   /* nf = K = Q(a), L = K(b) quadratic extension = Q(t) */
    3192          14 :   polLK = quadpoly_i(stoi(ell)); /* relative polynomial */
    3193          14 :   res = rnfequation2(nf, polLK);
    3194          14 :   vx = nf_get_varn(nf);
    3195          14 :   polL = gsubst(gel(res,1),0,pol_x(vx)); /* = charpoly(t) */
    3196          14 :   a = gsubst(lift_shallow(gel(res,2)), 0,pol_x(vx));
    3197          14 :   b = gsub(pol_x(vx), gmul(gel(res,3), a));
    3198          14 :   nfL = nfinit(polL, DEFAULTPREC);
    3199          14 :   p1 = gcoeff(nffactor(nfL,p1),1,1);
    3200          14 :   p2 = gcoeff(nffactor(nfL,p2),1,1);
    3201          14 :   p3 = do_compo(p1,p2); /* relative equation over L */
    3202             :   /* compute non trivial s in Gal(L / K) */
    3203          14 :   sb= gneg(gadd(b, RgX_coeff(polLK,1))); /* s(b) = Tr(b) - b */
    3204          14 :   s = gadd(pol_x(vx), gsub(sb, b)); /* s(t) = t + s(b) - b */
    3205          14 :   p3 = gmul(p3, galoisapplypol(nfL, s, p3));
    3206          14 :   return findquad_pol(nf_get_pol(nf), a, p3);
    3207             : }
    3208             : 
    3209             : /* I integral ideal in HNF. (x) = I, x small in Z ? */
    3210             : static long
    3211         119 : isZ(GEN I)
    3212             : {
    3213         119 :   GEN x = gcoeff(I,1,1);
    3214         119 :   if (signe(gcoeff(I,1,2)) || !equalii(x, gcoeff(I,2,2))) return 0;
    3215         105 :   return is_bigint(x)? -1: itos(x);
    3216             : }
    3217             : 
    3218             : /* Treat special cases directly. return NULL if not special case */
    3219             : static GEN
    3220         119 : treatspecialsigma(GEN bnr)
    3221             : {
    3222         119 :   GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf);
    3223         119 :   GEN f = gel(bnr_get_mod(bnr), 1),  D = nf_get_disc(nf);
    3224             :   GEN p1, p2;
    3225         119 :   long Ds, fl, tryf, i = isZ(f);
    3226             : 
    3227         119 :   if (i == 1) return quadhilbertimag(D); /* f = 1 */
    3228             : 
    3229         119 :   if (absequaliu(D,3)) /* Q(j) */
    3230             :   {
    3231           0 :     if (i == 4 || i == 5 || i == 7) return polcyclo(i,0);
    3232           0 :     if (!absequaliu(gcoeff(f,1,1),9) || !absequaliu(Z_content(f),3)) return NULL;
    3233             :     /* f = P_3^3 */
    3234           0 :     p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf));
    3235           0 :     return gadd(pol_xn(3,0), p1); /* x^3+j */
    3236             :   }
    3237         119 :   if (absequaliu(D,4)) /* Q(i) */
    3238             :   {
    3239          14 :     if (i == 3 || i == 5) return polcyclo(i,0);
    3240          14 :     if (i != 4) return NULL;
    3241           0 :     p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf));
    3242           0 :     return gadd(pol_xn(2,0), p1); /* x^2+i */
    3243             :   }
    3244         105 :   Ds = smodis(D,48);
    3245         105 :   if (i)
    3246             :   {
    3247          91 :     if (i==2 && Ds%16== 8) return compocyclo(D, 4);
    3248          84 :     if (i==3 && Ds% 3== 1) return compocyclo(D, 3);
    3249          70 :     if (i==4 && Ds% 8== 1) return compocyclo(D, 4);
    3250          63 :     if (i==6 && Ds   ==40) return compocyclo(D,12);
    3251          56 :     return NULL;
    3252             :   }
    3253             : 
    3254          14 :   p1 = gcoeff(f,1,1); /* integer > 0 */
    3255          14 :   tryf = itou_or_0(p1); if (!tryf) return NULL;
    3256          14 :   p2 = gcoeff(f,2,2); /* integer > 0 */
    3257          14 :   if (is_pm1(p2)) fl = 0;
    3258             :   else {
    3259           0 :     if (Ds % 16 != 8 || !absequaliu(Z_content(f),2)) return NULL;
    3260           0 :     fl = 1; tryf >>= 1;
    3261             :   }
    3262          14 :   if (tryf <= 3 || umodiu(D, tryf) || !uisprime(tryf)) return NULL;
    3263          14 :   if (fl) tryf <<= 2;
    3264          14 :   return compocyclop(nf, tryf);
    3265             : }
    3266             : 
    3267             : GEN
    3268         161 : quadray(GEN D, GEN f, long prec)
    3269             : {
    3270         161 :   GEN bnr, y, bnf, H = NULL;
    3271         161 :   pari_sp av = avma;
    3272             : 
    3273         161 :   if (isint1(f)) return quadhilbert(D, prec);
    3274         126 :   if (typ(D) == t_INT && typ(f) != t_INT)
    3275           0 :     pari_err_TYPE("quadray [conductor]", f);
    3276         126 :   quadray_init(&D, &bnf, prec);
    3277         126 :   bnr = Buchray(bnf, f, nf_INIT|nf_GEN);
    3278         126 :   if (is_pm1(bnr_get_no(bnr))) { set_avma(av); return pol_x(0); }
    3279         126 :   if (signe(D) > 0)
    3280           7 :     y = bnrstark(bnr, H, prec);
    3281             :   else
    3282             :   {
    3283         119 :     bnr_subgroup_sanitize(&bnr, &H);
    3284         119 :     y = treatspecialsigma(bnr);
    3285         119 :     if (!y) y = computeP2(bnr, prec);
    3286             :   }
    3287         126 :   return gerepileupto(av, y);
    3288             : }

Generated by: LCOV version 1.14