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

Generated by: LCOV version 2.0-1