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 - basemath - buch1.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30256-57c6c2b57f) Lines: 681 713 95.5 %
Date: 2025-05-07 09:19:00 Functions: 52 56 92.9 %
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             : #include "pari.h"
      15             : #include "paripriv.h"
      16             : #include "mpqs.h"
      17             : 
      18             : #define DEBUGLEVEL DEBUGLEVEL_quadclassunit
      19             : 
      20             : /*******************************************************************/
      21             : /*                                                                 */
      22             : /*         CLASS GROUP AND REGULATOR (McCURLEY, BUCHMANN)          */
      23             : /*                   QUADRATIC FIELDS                              */
      24             : /*                                                                 */
      25             : /*******************************************************************/
      26             : /* For largeprime() hashtable. Note that hashed pseudoprimes are odd (unless
      27             :  * 2 | index), hence the low order bit is not useful. So we hash
      28             :  * HASHBITS bits starting at bit 1, not bit 0 */
      29             : #define HASHBITS 10
      30             : static const long HASHT = 1L << HASHBITS;
      31             : 
      32             : static long
      33     2565641 : hash(long q) { return (q & ((1L << (HASHBITS+1)) - 1)) >> 1; }
      34             : #undef HASHBITS
      35             : 
      36             : /* See buch2.c:
      37             :  * B->subFB contains split p such that \prod p > sqrt(B->Disc)
      38             :  * B->powsubFB contains powers of forms in B->subFB */
      39             : #define RANDOM_BITS 4
      40             : static const long CBUCH = (1L<<RANDOM_BITS)-1;
      41             : 
      42             : struct buch_quad
      43             : {
      44             :   ulong limhash;
      45             :   long KC, KC2, PRECREG;
      46             :   long *primfact, *exprimfact, **hashtab;
      47             :   GEN FB, numFB, prodFB;
      48             :   GEN powsubFB, vperm, subFB, badprim;
      49             :   struct qfr_data *q;
      50             : };
      51             : 
      52             : /*******************************************************************/
      53             : /*                                                                 */
      54             : /*  Routines related to binary quadratic forms (for internal use)  */
      55             : /*                                                                 */
      56             : /*******************************************************************/
      57             : /* output canonical representative wrt projection Cl^+ --> Cl (a > 0) */
      58             : static GEN
      59     1166963 : qfr3_canon(GEN x, struct qfr_data *S)
      60             : {
      61     1166963 :   GEN a = gel(x,1), c = gel(x,3);
      62     1166963 :   if (signe(a) < 0) {
      63      403298 :     if (absequalii(a,c)) return qfr3_rho(x, S);
      64      403284 :     setsigne(a, 1);
      65      403284 :     setsigne(c,-1);
      66             :   }
      67     1166949 :   return x;
      68             : }
      69             : static GEN
      70        3710 : qfr3_canon_safe(GEN x, struct qfr_data *S)
      71             : {
      72        3710 :   GEN a = gel(x,1), c = gel(x,3);
      73        3710 :   if (signe(a) < 0) {
      74         224 :     if (absequalii(a,c)) return qfr3_rho(x, S);
      75         224 :     gel(x,1) = negi(a);
      76         224 :     gel(x,3) = negi(c);
      77             :   }
      78        3710 :   return x;
      79             : }
      80             : static GEN
      81     1952748 : qfr5_canon(GEN x, struct qfr_data *S)
      82             : {
      83     1952748 :   GEN a = gel(x,1), c = gel(x,3);
      84     1952748 :   if (signe(a) < 0) {
      85      723268 :     if (absequalii(a,c)) return qfr5_rho(x, S);
      86      723254 :     setsigne(a, 1);
      87      723254 :     setsigne(c,-1);
      88             :   }
      89     1952734 :   return x;
      90             : }
      91             : static GEN
      92     1735160 : QFR5_comp(GEN x,GEN y, struct qfr_data *S)
      93     1735160 : { return qfr5_canon(qfr5_comp(x,y,S), S); }
      94             : static GEN
      95     1007545 : QFR3_comp(GEN x, GEN y, struct qfr_data *S)
      96     1007545 : { return qfr3_canon(qfr3_comp(x,y,S), S); }
      97             : 
      98             : /* compute rho^n(x) */
      99             : static GEN
     100      220157 : qfr5_rho_pow(GEN x, long n, struct qfr_data *S)
     101             : {
     102             :   long i;
     103      220157 :   pari_sp av = avma;
     104     2194360 :   for (i=1; i<=n; i++)
     105             :   {
     106     1974203 :     x = qfr5_rho(x,S);
     107     1974203 :     if (gc_needed(av,1))
     108             :     {
     109           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"qfr5_rho_pow");
     110           0 :       x = gc_GEN(av, x);
     111             :     }
     112             :   }
     113      220157 :   return gc_GEN(av, x);
     114             : }
     115             : 
     116             : static GEN
     117      217588 : qfr5_pf(struct qfr_data *S, long p, long prec)
     118             : {
     119      217588 :   GEN y = primeform_u(S->D,p);
     120      217588 :   return qfr5_canon(qfr5_red(qfr_to_qfr5(y,prec), S), S);
     121             : }
     122             : 
     123             : static GEN
     124      159390 : qfr3_pf(struct qfr_data *S, long p)
     125             : {
     126      159390 :   GEN y = primeform_u(S->D,p);
     127      159390 :   return qfr3_canon(qfr3_red(y, S), S);
     128             : }
     129             : 
     130             : #define qfi_pf primeform_u
     131             : 
     132             : /* Warning: ex[0] not set in general */
     133             : static GEN
     134     4061403 : init_form(struct buch_quad *B, GEN ex,
     135             :           GEN (*comp)(GEN,GEN,struct qfr_data *S))
     136             : {
     137     4061403 :   long i, l = lg(B->powsubFB);
     138     4061403 :   GEN F = NULL;
     139    22912005 :   for (i=1; i<l; i++)
     140    18859962 :     if (ex[i])
     141             :     {
     142    17682815 :       GEN t = gmael(B->powsubFB,i,ex[i]);
     143    17682815 :       F = F? comp(F, t, B->q): t;
     144             :     }
     145     4052043 :   return F;
     146             : }
     147             : static GEN
     148      197015 : qfr5_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFR5_comp); }
     149             : 
     150             : static GEN
     151    11740371 : QFI_comp(GEN x, GEN y, struct qfr_data *S) { (void)S; return qfbcomp_i(x,y); }
     152             : 
     153             : static GEN
     154      160889 : qfi_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFI_comp); }
     155             : 
     156             : static GEN
     157     3703010 : random_form(struct buch_quad *B, GEN ex,
     158             :             GEN (*comp)(GEN,GEN, struct qfr_data *S))
     159             : {
     160     3703010 :   long i, l = lg(ex);
     161     3703010 :   pari_sp av = avma;
     162             :   GEN F;
     163             :   for(;;)
     164             :   {
     165    20589696 :     for (i=1; i<l; i++) ex[i] = random_bits(RANDOM_BITS);
     166     3703246 :     if ((F = init_form(B, ex, comp))) return F;
     167         464 :     set_avma(av);
     168             :   }
     169             : }
     170             : static GEN
     171      161567 : qfr3_random(struct buch_quad *B,GEN ex){ return random_form(B, ex, &QFR3_comp); }
     172             : static GEN
     173     3541364 : qfi_random(struct buch_quad *B,GEN ex) { return random_form(B, ex, &QFI_comp); }
     174             : 
     175             : /*******************************************************************/
     176             : /*                                                                 */
     177             : /*                     Common subroutines                          */
     178             : /*                                                                 */
     179             : /*******************************************************************/
     180             : /* We assume prime ideals of norm < D generate Cl(K); failure with
     181             :  * a factor base of primes with norm < LIMC <= D. Suggest new value.
     182             :  * All values of the form c * log^2 (disc K) [where D has c = 4
     183             :  * (Grenie-Molteni, under GRH)]. A value of c in [0.3, 1] should be OK for most
     184             :  * fields. No example is known where c >= 2 is necessary. */
     185             : ulong
     186        2333 : bnf_increase_LIMC(ulong LIMC, ulong D)
     187             : {
     188        2333 :   if (LIMC >= D) pari_err_BUG("Buchmann's algorithm");
     189        2333 :   if (LIMC <= D / 13.333)
     190         240 :     LIMC *= 2; /* tiny c <= 0.3 : double it */
     191             :   else
     192        2093 :     LIMC += maxuu(1, D / 20); /* large c, add 0.2 to it */
     193        2333 :   if (LIMC > D) LIMC = D;
     194        2333 :   return LIMC;
     195             : }
     196             : 
     197             : /* Is |q| <= p ? */
     198             : static int
     199       10416 : isless_iu(GEN q, ulong p) {
     200       10416 :   long l = lgefint(q);
     201       10416 :   return l==2 || (l == 3 && uel(q,2) <= p);
     202             : }
     203             : 
     204             : static GEN
     205     5029383 : Z_isquasismooth_prod(GEN N, GEN P)
     206             : {
     207     5029383 :   P = gcdii(P,N);
     208    10031364 :   while (!is_pm1(P))
     209             :   {
     210     4996923 :     N = diviiexact(N, P);
     211     5004600 :     P = gcdii(N, P);
     212             :   }
     213     5025479 :   return N;
     214             : }
     215             : 
     216             : static long
     217     5036417 : factorquad(struct buch_quad *B, GEN f, long nFB, ulong limp)
     218             : {
     219             :   ulong X;
     220     5036417 :   long i, lo = 0;
     221     5036417 :   GEN F, x = gel(f,1), FB = B->FB, P = B->primfact, E = B->exprimfact;
     222     5036417 :   if (B->badprim && !is_pm1(gcdii(x, B->badprim))) return 0;
     223     5029480 :   F =  Z_isquasismooth_prod(x, B->prodFB);
     224     5025295 :   if (cmpiu(F, B->limhash) > 0) return 0;
     225     4401465 :   for (i=1; lgefint(x) > 3; i++)
     226             :   {
     227       10416 :     ulong p = uel(FB,i), r;
     228       10416 :     GEN q = absdiviu_rem(x, p, &r);
     229       10416 :     if (!r)
     230             :     {
     231        1530 :       long k = 0;
     232        2633 :       do { k++; x = q; q = absdiviu_rem(x, p, &r); } while (!r);
     233        1530 :       lo++; P[lo] = p; E[lo] = k;
     234             :     }
     235       10416 :     if (isless_iu(q,p)) {
     236           1 :       if (lgefint(x) == 3) { X = uel(x,2); goto END; }
     237          34 :       return 0;
     238             :     }
     239       10415 :     if (i == nFB) return 0;
     240             :   }
     241     4391049 :   X = uel(x,2);
     242     4391049 :   if (X == 1) { P[0] = 0; return 1; }
     243    68606810 :   for (;; i++)
     244    68606810 :   { /* single precision affair, split for efficiency */
     245    72979141 :     ulong p = uel(FB,i);
     246    72979141 :     ulong q = X / p, r = X % p; /* gcc makes a single div */
     247    72979141 :     if (!r)
     248             :     {
     249     5620279 :       long k = 0;
     250     6787171 :       do { k++; X = q; q = X / p; r = X % p; } while (!r);
     251     5620279 :       lo++; P[lo] = p; E[lo] = k;
     252             :     }
     253    72979141 :     if (q <= p) break;
     254    68640338 :     if (i == nFB) return 0;
     255             :   }
     256     4338804 : END:
     257     4338804 :   if (X > B->limhash) return 0;
     258     4338804 :   if (X != 1 && X <= limp) { lo++; P[lo] = X; E[lo] = 1; X = 1; }
     259     4338804 :   P[0] = lo; return X;
     260             : }
     261             : 
     262             : /* Check for a "large prime relation" involving q; q may not be prime */
     263             : static long *
     264     2565639 : largeprime(struct buch_quad *B, long q, GEN ex, long np, long nrho)
     265             : {
     266     2565639 :   const long hashv = hash(q);
     267     2565638 :   long *pt, i, l = lg(B->subFB);
     268             : 
     269     2787411 :   for (pt = B->hashtab[hashv]; ; pt = (long*) pt[0])
     270             :   {
     271     2787411 :     if (!pt)
     272             :     {
     273     2366008 :       pt = (long*) pari_malloc((l+3) * sizeof(long));
     274     2366305 :       *pt++ = nrho; /* nrho = pt[-3] */
     275     2366305 :       *pt++ = np;   /* np   = pt[-2] */
     276     2366305 :       *pt++ = q;    /* q    = pt[-1] */
     277     2366305 :       pt[0] = (long)B->hashtab[hashv];
     278    14988831 :       for (i=1; i<l; i++) pt[i]=ex[i];
     279     2366305 :       B->hashtab[hashv]=pt; return NULL;
     280             :     }
     281      421403 :     if (pt[-1] == q) break;
     282             :   }
     283      238200 :   for(i=1; i<l; i++)
     284      234919 :     if (pt[i] != ex[i]) return pt;
     285        3281 :   return (pt[-2]==np)? NULL: pt;
     286             : }
     287             : 
     288             : static void
     289      169561 : clearhash(long **hash)
     290             : {
     291             :   long *pt;
     292             :   long i;
     293   173769079 :   for (i=0; i<HASHT; i++) {
     294   175965870 :     for (pt = hash[i]; pt; ) {
     295     2366352 :       void *z = (void*)(pt - 3);
     296     2366352 :       pt = (long*) pt[0]; pari_free(z);
     297             :     }
     298   173599518 :     hash[i] = NULL;
     299             :   }
     300      169510 : }
     301             : 
     302             : /* last prime stored */
     303             : ulong
     304           0 : GRH_last_prime(GRHcheck_t *S) { return (S->primes + S->nprimes-1)->p; }
     305             : /* ensure that S->primes can hold at least nb primes */
     306             : void
     307      400844 : GRH_ensure(GRHcheck_t *S, long nb)
     308             : {
     309      400844 :   if (S->maxprimes <= nb)
     310             :   {
     311           0 :     do S->maxprimes *= 2; while (S->maxprimes <= nb);
     312           0 :     pari_realloc_ip((void**)&S->primes, S->maxprimes*sizeof(*S->primes));
     313             :   }
     314      400844 : }
     315             : /* cache data for all primes up to the LIM */
     316             : static void
     317     1174115 : cache_prime_quad(GRHcheck_t *S, ulong LIM, GEN D)
     318             : {
     319             :   GRHprime_t *pr;
     320             :   long nb;
     321             : 
     322     1174115 :   if (S->limp >= LIM) return;
     323       72435 :   nb = (long)primepi_upper_bound((double)LIM); /* #{p <= LIM} <= nb */
     324       72436 :   GRH_ensure(S, nb+1); /* room for one extra prime */
     325       72436 :   for (pr = S->primes + S->nprimes;;)
     326    12668420 :   {
     327    12740856 :     ulong p = u_forprime_next(&(S->P));
     328    12740528 :     pr->p = p;
     329    12740528 :     pr->logp = log((double)p);
     330    12740528 :     pr->dec = (GEN)kroiu(D,p);
     331    12740856 :     S->nprimes++;
     332    12740856 :     pr++;
     333             :     /* store up to nextprime(LIM) included */
     334    12740856 :     if (p >= LIM) { S->limp = p; break; }
     335             :   }
     336             : }
     337             : 
     338             : static GEN
     339       70311 : compute_invresquad(GRHcheck_t *S, long LIMC)
     340             : {
     341       70311 :   pari_sp av = avma;
     342       70311 :   GEN invres = real_1(DEFAULTPREC);
     343       70311 :   double limp = log((double)LIMC) / 2;
     344             :   GRHprime_t *pr;
     345             :   long i;
     346    12745491 :   for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--)
     347             :   {
     348    12677128 :     long s = (long)pr->dec;
     349    12677128 :     if (s)
     350             :     {
     351    12561182 :       ulong p = pr->p;
     352    12561182 :       if (s > 0 || pr->logp <= limp)
     353             :         /* Both p and P contribute */
     354     6391456 :         invres = mulur(p - s, divru(invres, p));
     355     6169726 :       else if (s<0)
     356             :         /* Only p contributes */
     357     6169685 :         invres = mulur(p, divru(invres, p - 1));
     358             :     }
     359             :   }
     360       68363 :   return gc_uptoleaf(av, invres);
     361             : }
     362             : 
     363             : /* p | conductor of order of disc D ? */
     364             : static int
     365      391710 : is_bad(GEN D, ulong p)
     366             : {
     367      391710 :   pari_sp av = avma;
     368      391710 :   if (p == 2)
     369             :   {
     370       89535 :     long r = mod16(D) >> 1;
     371       89535 :     if (r && signe(D) < 0) r = 8-r;
     372       89535 :     return (r < 4);
     373             :   }
     374      302175 :   return gc_bool(av, dvdii(D, sqru(p))); /* p^2 | D ? */
     375             : }
     376             : 
     377             : /* returns the n-th suitable ideal for the factorbase */
     378             : static long
     379       70299 : nthidealquad(GEN D, long n)
     380             : {
     381       70299 :   pari_sp av = avma;
     382             :   forprime_t S;
     383             :   ulong p;
     384       70299 :   (void)u_forprime_init(&S, 2, ULONG_MAX);
     385      357428 :   while ((p = u_forprime_next(&S)) && n > 0)
     386      287141 :     if (!is_bad(D, p) && kroiu(D, p) >= 0) n--;
     387       70290 :   return gc_long(av, p);
     388             : }
     389             : 
     390             : static int
     391     1033440 : quadGRHchk(GEN D, GRHcheck_t *S, ulong LIMC)
     392             : {
     393     1033440 :   double logC = log((double)LIMC), SA = 0, SB = 0;
     394             :   long i;
     395             : 
     396     1033440 :   cache_prime_quad(S, LIMC, D);
     397     1033431 :   for (i = 0;; i++)
     398    29526844 :   {
     399    30560275 :     GRHprime_t *pr = S->primes+i;
     400    30560275 :     ulong p = pr->p;
     401             :     long M;
     402             :     double logNP, q, A, B;
     403    30560275 :     if (p > LIMC) break;
     404    29616075 :     if ((long)pr->dec < 0)
     405             :     {
     406    14787195 :       logNP = 2 * pr->logp;
     407    14787195 :       q = 1/(double)p;
     408             :     }
     409             :     else
     410             :     {
     411    14828880 :       logNP = pr->logp;
     412    14828880 :       q = 1/sqrt((double)p);
     413             :     }
     414    29616075 :     A = logNP * q; B = logNP * A; M = (long)(logC/logNP);
     415    29616075 :     if (M > 1)
     416             :     {
     417     2502073 :       double inv1_q = 1 / (1-q);
     418     2502073 :       A *= (1 - pow(q, (double) M)) * inv1_q;
     419     2502073 :       B *= (1 - pow(q, (double) M)*(M+1 - M*q)) * inv1_q * inv1_q;
     420             :     }
     421    29616075 :     if ((long)pr->dec>0) { SA += 2*A;SB += 2*B; } else { SA += A; SB += B; }
     422    29616075 :     if (p == LIMC) break;
     423             :   }
     424     1033431 :   return GRHok(S, logC, SA, SB);
     425             : }
     426             : 
     427             : /* C2 >= C1; create B->FB, B->numFB; set B->badprim. Return L(kro_D, 1) */
     428             : static void
     429       70383 : FBquad(struct buch_quad *B, ulong C2, ulong C1, GRHcheck_t *S)
     430             : {
     431       70383 :   GEN D = B->q->D;
     432             :   long i;
     433             :   pari_sp av;
     434             :   GRHprime_t *pr;
     435             : 
     436       70383 :   cache_prime_quad(S, C2, D);
     437       70383 :   pr = S->primes;
     438       70383 :   B->numFB = cgetg(C2+1, t_VECSMALL);
     439       70383 :   B->FB    = cgetg(C2+1, t_VECSMALL);
     440       70363 :   av = avma;
     441       70363 :   B->KC = 0; i = 0;
     442       70363 :   B->badprim = gen_1;
     443     2812443 :   for (;; pr++) /* p <= C2 */
     444     2812443 :   {
     445     2882806 :     ulong p = pr->p;
     446     2882806 :     if (!B->KC && p > C1) B->KC = i;
     447     2882806 :     if (p > C2) break;
     448     2819919 :     switch ((long)pr->dec)
     449             :     {
     450     1389661 :       case -1: break; /* inert */
     451      104571 :       case  0: /* ramified */
     452      104571 :         if (is_bad(D, p)) { B->badprim = muliu(B->badprim, p); break; }
     453             :         /* fall through */
     454             :       default:  /* split */
     455     1430215 :         i++; B->numFB[p] = i; B->FB[i] = p; break;
     456             :     }
     457     2819939 :     if (p == C2)
     458             :     {
     459        7496 :       if (!B->KC) B->KC = i;
     460        7496 :       break;
     461             :     }
     462             :   }
     463       70383 :   B->KC2 = i;
     464       70383 :   setlg(B->FB, B->KC2+1);
     465       70383 :   if (B->badprim != gen_1)
     466          42 :     B->badprim = gc_INT(av, B->badprim);
     467             :   else
     468             :   {
     469       70341 :     B->badprim = NULL; set_avma(av);
     470             :   }
     471       70383 :   B->prodFB = zv_prod_Z(B->FB);
     472       70380 : }
     473             : 
     474             : /* create B->vperm, return B->subFB */
     475             : static GEN
     476       70380 : subFBquad(struct buch_quad *B, GEN D, double PROD, long minSFB)
     477             : {
     478       70380 :   long i, j, lgsub = 1, ino = 1, lv = B->KC+1;
     479       70380 :   double prod = 1.;
     480             :   pari_sp av;
     481             :   GEN no;
     482             : 
     483       70380 :   B->vperm = cgetg(lv, t_VECSMALL);
     484       70381 :   av = avma;
     485       70381 :   no    = cgetg(lv, t_VECSMALL);
     486      334582 :   for (j = 1; j < lv; j++)
     487             :   {
     488      334505 :     ulong p = uel(B->FB,j);
     489      334505 :     if (!umodiu(D, p)) no[ino++] = j; /* ramified */
     490             :     else
     491             :     {
     492      254840 :       B->vperm[lgsub++] = j;
     493      254840 :       prod *= p;
     494      254840 :       if (lgsub > minSFB && prod > PROD) break;
     495             :     }
     496             :   }
     497             :   /* lgsub >= 1 otherwise quadGRHchk is false */
     498       70381 :   i = lgsub;
     499      150045 :   for (j = 1; j < ino;i++,j++) B->vperm[i] = no[j];
     500     1165608 :   for (     ; i < lv; i++)     B->vperm[i] = i;
     501       70381 :   no = gclone(vecslice(B->vperm, 1, lgsub-1));
     502       70383 :   set_avma(av); return no;
     503             : }
     504             : 
     505             : /* assume n >= 1, x[i][j] = B->subFB[i]^j, for j = 1..n */
     506             : static GEN
     507       99198 : powsubFBquad(struct buch_quad *B, long n)
     508             : {
     509       99198 :   pari_sp av = avma;
     510       99198 :   long i,j, l = lg(B->subFB);
     511       99198 :   GEN F, y, x = cgetg(l, t_VEC), D = B->q->D;
     512             : 
     513       99197 :   if (B->PRECREG) /* real */
     514             :   {
     515       39627 :     for (i=1; i<l; i++)
     516             :     {
     517       34510 :       F = qfr5_pf(B->q, B->FB[B->subFB[i]], B->PRECREG);
     518       34510 :       y = cgetg(n+1, t_VEC); gel(x,i) = y;
     519       34510 :       gel(y,1) = F;
     520      552160 :       for (j=2; j<=n; j++) gel(y,j) = QFR5_comp(gel(y,j-1), F, B->q);
     521             :     }
     522             :   }
     523             :   else /* imaginary */
     524             :   {
     525      427045 :     for (i=1; i<l; i++)
     526             :     {
     527      332981 :       F = qfi_pf(D, B->FB[B->subFB[i]]);
     528      332953 :       y = cgetg(n+1, t_VEC); gel(x,i) = y;
     529      333857 :       gel(y,1) = F;
     530     5318632 :       for (j=2; j<=n; j++) gel(y,j) = qfbcomp_i(gel(y,j-1), F);
     531             :     }
     532             :   }
     533       99181 :   x = gclone(x); set_avma(av); return x;
     534             : }
     535             : 
     536             : static void
     537       98387 : sub_fact(struct buch_quad *B, GEN col, GEN F)
     538             : {
     539       98387 :   GEN b = gel(F,2);
     540             :   long i;
     541      208128 :   for (i=1; i<=B->primfact[0]; i++)
     542             :   {
     543      109741 :     ulong p = B->primfact[i], k = B->numFB[p];
     544      109741 :     long e = B->exprimfact[i];
     545      109741 :     if (umodiu(b, p<<1) > p) e = -e;
     546      109741 :     col[k] -= e;
     547             :   }
     548       98387 : }
     549             : 
     550             : #if 0
     551             : static void
     552             : dbg_fact(struct buch_quad *B)
     553             : {
     554             :   long i;
     555             :   for (i=1; i<=B->primfact[0]; i++)
     556             :   {
     557             :     ulong p = B->primfact[i];
     558             :     long e = B->exprimfact[i];
     559             :     err_printf("%lu^%ld ",p,e);
     560             :   }
     561             : }
     562             : 
     563             : static void
     564             : chk_fact(struct buch_quad *B, GEN col)
     565             : {
     566             :   long i, l = lg(col);
     567             :   GEN Q = qfi_pf(B->q->D, 1);
     568             :   for (i=1; i< l; i++)
     569             :   {
     570             :     ulong p = B->FB[i];
     571             :     long k = col[i];
     572             :     Q = qfbcomp(qfbpowraw(qfi_pf(B->q->D, p),k),Q);
     573             :   }
     574             :   if (!gequal1(gel(Q,1))) pari_err_BUG("chk_fact");
     575             : }
     576             : #endif
     577             : 
     578             : static void
     579     1892109 : add_fact(struct buch_quad *B, GEN col, GEN F)
     580             : {
     581     1892109 :   GEN b = gel(F,2);
     582             :   long i;
     583     5929440 :   for (i=1; i<=B->primfact[0]; i++)
     584             :   {
     585     4037176 :     ulong p = B->primfact[i], k = B->numFB[p];
     586     4037176 :     long e = B->exprimfact[i];
     587     4037176 :     if (umodiu(b, p<<1) > p) e = -e;
     588     4037331 :     col[k] += e;
     589             :   }
     590     1892264 : }
     591             : 
     592             : static GEN
     593       70299 : get_clgp(struct buch_quad *B, GEN W, GEN *ptD)
     594             : {
     595       70299 :   GEN res, init, u1, D = ZM_snf_group(W,NULL,&u1);
     596       70296 :   long i, j, l = lg(W), c = lg(D);
     597             : 
     598       70296 :   res=cgetg(c,t_VEC); init = cgetg(l,t_VEC);
     599      216094 :   for (i=1; i<l; i++) gel(init,i) = primeform_u(B->q->D, B->FB[B->vperm[i]]);
     600      195705 :   for (j=1; j<c; j++)
     601             :   {
     602      125406 :     GEN g = NULL;
     603      125406 :     if (signe(B->q->D) > 0)
     604             :     {
     605       13328 :       for (i=1; i<l; i++)
     606             :       {
     607        9618 :         GEN t, u = gcoeff(u1,i,j);
     608        9618 :         if (!signe(u)) continue;
     609        4543 :         t = qfr3_pow(gel(init,i), u, B->q);
     610        4543 :         g = g? qfr3_comp(g, t, B->q): t;
     611             :       }
     612        3710 :       g = qfr3_to_qfr(qfr3_canon_safe(qfr3_red(g, B->q), B->q), B->q->D);
     613             :     }
     614             :     else
     615             :     {
     616      423646 :       for (i=1; i<l; i++)
     617             :       {
     618      301945 :         GEN t, u = gcoeff(u1,i,j);
     619      301945 :         if (!signe(u)) continue;
     620      203547 :         t = powgi(gel(init,i), u);
     621      203556 :         g = g? qfbcomp_i(g, t): t;
     622             :       }
     623             :     }
     624      125409 :     gel(res,j) = g;
     625             :   }
     626       70299 :   *ptD = D; return res;
     627             : }
     628             : 
     629             : static long
     630       70313 : trivial_relations(struct buch_quad *B, GEN mat, GEN C)
     631             : {
     632       70313 :   long i, j = 0;
     633       70313 :   GEN col, D = B->q->D;
     634     1499799 :   for (i = 1; i <= B->KC; i++)
     635             :   { /* ramified prime ==> trivial relation */
     636     1429477 :     if (umodiu(D, B->FB[i])) continue;
     637      104303 :     col = zero_zv(B->KC);
     638      104311 :     col[i] = 2; j++;
     639      104311 :     gel(mat,j) = col;
     640      104311 :     gel(C,j) = gen_0;
     641             :   }
     642       70322 :   return j;
     643             : }
     644             : 
     645             : static void
     646           0 : dbg_all(pari_timer *T, const char *phase, long s, long n)
     647             : {
     648           0 :   err_printf("\n");
     649           0 :   timer_printf(T, "%s rel [#rel/#test = %ld/%ld]", phase,s,n);
     650           0 : }
     651             : 
     652             : /* Imaginary Quadratic fields */
     653             : 
     654             : static void
     655        8813 : rel_to_col(struct buch_quad *B, GEN col, GEN rel, GEN b)
     656             : {
     657        8813 :   GEN P = gel(rel, 1), E = gel(rel, 2);
     658        8813 :   long i, lP = lg(P);
     659      105784 :   for (i=1; i<lP; i++)
     660             :   {
     661       96971 :     ulong p = uel(P, i), e = uel(E, i);
     662       96971 :     col[B->numFB[p]] += umodiu(b, p<<1) > p ? -e :e;
     663             :   }
     664        8813 : }
     665             : 
     666             : static void
     667       99046 : imag_relations(struct buch_quad *B, long need, long *pc, ulong LIMC, GEN mat)
     668             : {
     669             :   pari_timer T;
     670       99046 :   long lgsub = lg(B->subFB), current = *pc, nbtest = 0, s = 0;
     671             :   long i, fpc;
     672             :   pari_sp av;
     673       99046 :   GEN col, form, ex = cgetg(lgsub, t_VECSMALL);
     674             : 
     675       99046 :   if (!current) current = 1;
     676       99046 :   if (DEBUGLEVEL>2) timer_start(&T);
     677       99046 :   av = avma;
     678             :   for(;;)
     679             :   {
     680     3640152 :     if (s >= need) break;
     681     3541105 :     set_avma(av);
     682     3541010 :     form = qfi_random(B,ex);
     683     3538520 :     form = qfbcomp_i(form, qfi_pf(B->q->D, B->FB[current]));
     684     3538759 :     nbtest++; fpc = factorquad(B,form,B->KC,LIMC);
     685     3540283 :     if (!fpc)
     686             :     {
     687      291564 :       if (DEBUGLEVEL>3) err_printf(".");
     688      291564 :       if ((nbtest & 0xff) == 0 && ++current > B->KC) current = 1;
     689      291564 :       continue;
     690             :     }
     691     3248719 :     if (fpc > 1)
     692             :     {
     693     1800531 :       long *fpd = largeprime(B,fpc,ex,current,0);
     694             :       ulong b1, b2, p;
     695             :       GEN form2;
     696     1801005 :       if (!fpd)
     697             :       {
     698     1640155 :         if (DEBUGLEVEL>3) err_printf(".");
     699     1640156 :         continue;
     700             :       }
     701      160850 :       form2 = qfbcomp_i(qfi_factorback(B,fpd), qfi_pf(B->q->D, B->FB[fpd[-2]]));
     702      160888 :       p = fpc << 1;
     703      160888 :       b1 = umodiu(gel(form2,2), p);
     704      160888 :       b2 = umodiu(gel(form,2),  p);
     705      160890 :       if (b1 != b2 && b1+b2 != p) continue;
     706             : 
     707      160890 :       col = gel(mat,++s);
     708      160890 :       add_fact(B,col, form);
     709      160891 :       (void)factorquad(B,form2,B->KC,LIMC);
     710      160893 :       if (b1==b2)
     711             :       {
     712      415397 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += fpd[i]-ex[i];
     713       80760 :         sub_fact(B, col, form2); col[fpd[-2]]++;
     714             :       }
     715             :       else
     716             :       {
     717      411103 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += -fpd[i]-ex[i];
     718       80133 :         add_fact(B, col, form2); col[fpd[-2]]--;
     719             :       }
     720      160895 :       if (DEBUGLEVEL>2) err_printf(" %ldP",s);
     721             :     }
     722             :     else
     723             :     {
     724     1448188 :       col = gel(mat,++s);
     725     6956499 :       for (i=1; i<lgsub; i++) col[B->subFB[i]] = -ex[i];
     726     1448188 :       add_fact(B, col, form);
     727     1448636 :       if (DEBUGLEVEL>2) err_printf(" %ld",s);
     728             :     }
     729     1609386 :     col[current]--;
     730     1609386 :     if (++current > B->KC) current = 1;
     731             :   }
     732       99047 :   if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest);
     733       99047 :   *pc = current;
     734       99047 : }
     735             : 
     736             : static void
     737         336 : mpqs_relations(struct buch_quad *B, long need, long *pc, ulong LIMC, GEN mat, mpqs_handle_t *H, GEN missing_primes)
     738             : {
     739             :   pari_timer T;
     740             :   long i, lV;
     741             :   GEN V;
     742         336 :   if (DEBUGLEVEL>2) timer_start(&T);
     743         336 :   V = mpqs_class_rels(H, need, missing_primes);
     744         336 :   if (!V) { imag_relations(B, need, pc, LIMC, mat); return; }
     745         336 :   lV = lg(V);
     746        9149 :   for (i = 1; i < lV && i <= need; i++)
     747             :   {
     748        8813 :     GEN formA = gel(V,i), rel = gel(formA,2), b = gel(formA,1);
     749        8813 :     GEN col = gel(mat,i);
     750        8813 :     rel_to_col(B, col, rel, b);
     751             :   }
     752         336 :   if (DEBUGLEVEL>2) timer_printf(&T, "MPQS rel [#rel = %ld]", i-1);
     753             : }
     754             : 
     755             : static int
     756           7 : imag_be_honest(struct buch_quad *B)
     757             : {
     758           7 :   long p, fpc, s = B->KC, nbtest = 0;
     759           7 :   GEN F, ex = cgetg(lg(B->subFB), t_VECSMALL);
     760           7 :   pari_sp av = avma;
     761             : 
     762         525 :   while (s<B->KC2)
     763             :   {
     764         518 :     p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p);
     765         518 :     F = qfbcomp_i(qfi_pf(B->q->D, p), qfi_random(B, ex));
     766         518 :     fpc = factorquad(B,F,s,p-1);
     767         518 :     if (fpc == 1) { nbtest=0; s++; }
     768             :     else
     769         392 :       if (++nbtest > 40) return 0;
     770         518 :     set_avma(av);
     771             :   }
     772           7 :   return 1;
     773             : }
     774             : 
     775             : static GEN
     776      184688 : dist(GEN e, GEN d, long prec) { return mkvec2(qfr5_dist(e, d, prec), d); }
     777             : /* z a pre-allocated pair [t_REAL, t_INT], D = [t,d] from dist() */
     778             : static void
     779      184688 : dist_set(GEN z, GEN D)
     780             : {
     781      184688 :   affrr(gel(D,1), gel(z,1));
     782      184688 :   affsi(signe(gel(D,2)) < 0? 1: 0, gel(z,2));
     783      184688 : }
     784             : 
     785             : /* Real Quadratic fields */
     786             : 
     787             : static void
     788        5145 : real_relations(struct buch_quad *B, long need, long *pc, long lim, ulong LIMC, GEN mat, GEN C)
     789             : {
     790             :   pari_timer T;
     791        5145 :   long lgsub = lg(B->subFB), prec = B->PRECREG, current = *pc, nbtest=0, s=0;
     792             :   long i, fpc, endcycle, rhoacc, rho;
     793             :   /* in a 2nd phase, don't include FB[current] but run along the cyle
     794             :    * ==> get more units */
     795        5145 :   int first = (current == 0);
     796             :   pari_sp av, av1;
     797        5145 :   GEN d, col, form, form0, form1, ex = cgetg(lgsub, t_VECSMALL);
     798             : 
     799        5145 :   if (DEBUGLEVEL>2) timer_start(&T);
     800        5145 :   if (!current) current = 1;
     801        5145 :   if (lim > need) lim = need;
     802        5145 :   av = avma;
     803             :   for(;;)
     804             :   {
     805      166691 :     if (s >= need) break;
     806      161546 :     if (first && s >= lim) {
     807        2142 :       first = 0;
     808        2142 :       if (DEBUGLEVEL>2) dbg_all(&T, "initial", s, nbtest);
     809             :     }
     810      161546 :     set_avma(av); form = qfr3_random(B, ex);
     811      161546 :     if (!first)
     812      159369 :       form = QFR3_comp(form, qfr3_pf(B->q, B->FB[current]), B->q);
     813      161546 :     av1 = avma;
     814      161546 :     form0 = form; form1 = NULL;
     815      161546 :     endcycle = rhoacc = 0;
     816      161546 :     rho = -1;
     817             : 
     818     1300964 : CYCLE:
     819     1300964 :     if (endcycle || rho > 5000)
     820             :     {
     821          21 :       if (++current > B->KC) current = 1;
     822          21 :       continue;
     823             :     }
     824     1300943 :     if (gc_needed(av,1))
     825             :     {
     826           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"real_relations");
     827           0 :       (void)gc_all(av1, form1? 2: 1, &form, &form1);
     828             :     }
     829     1300943 :     if (rho < 0) rho = 0; /* first time in */
     830             :     else
     831             :     {
     832     1139397 :       form = qfr3_rho(form, B->q); rho++;
     833     1139397 :       rhoacc++;
     834     1139397 :       if (first)
     835      442526 :         endcycle = (absequalii(gel(form,1),gel(form0,1))
     836      221263 :              && equalii(gel(form,2),gel(form0,2)));
     837             :       else
     838             :       {
     839      918134 :         if (absequalii(gel(form,1), gel(form,3))) /* a = -c */
     840             :         {
     841           0 :           if (absequalii(gel(form,1),gel(form0,1)) &&
     842           0 :                   equalii(gel(form,2),gel(form0,2))) continue;
     843           0 :           form = qfr3_rho(form, B->q); rho++;
     844           0 :           rhoacc++;
     845             :         }
     846             :         else
     847      918134 :           { setsigne(form[1],1); setsigne(form[3],-1); }
     848      918176 :         if (equalii(gel(form,1),gel(form0,1)) &&
     849          42 :             equalii(gel(form,2),gel(form0,2))) continue;
     850             :       }
     851             :     }
     852     1300943 :     nbtest++; fpc = factorquad(B,form,B->KC,LIMC);
     853     1300943 :     if (!fpc)
     854             :     {
     855      386778 :       if (DEBUGLEVEL>3) err_printf(".");
     856      386778 :       goto CYCLE;
     857             :     }
     858      914165 :     if (fpc > 1)
     859             :     { /* look for Large Prime relation */
     860      764946 :       long *fpd = largeprime(B,fpc,ex,first? 0: current,rhoacc);
     861             :       ulong b1, b2, p;
     862             :       GEN form2;
     863      764946 :       if (!fpd)
     864             :       {
     865      729477 :         if (DEBUGLEVEL>3) err_printf(".");
     866      729477 :         goto CYCLE;
     867             :       }
     868       35469 :       if (!form1)
     869             :       {
     870       35469 :         form1 = qfr5_factorback(B,ex);
     871       35469 :         if (!first)
     872       35469 :           form1 = QFR5_comp(form1, qfr5_pf(B->q, B->FB[current], prec), B->q);
     873             :       }
     874       35469 :       form1 = qfr5_rho_pow(form1, rho, B->q);
     875       35469 :       rho = 0;
     876             : 
     877       35469 :       form2 = qfr5_factorback(B,fpd);
     878       35469 :       if (fpd[-2])
     879       23709 :         form2 = QFR5_comp(form2, qfr5_pf(B->q, B->FB[fpd[-2]], prec), B->q);
     880       35469 :       form2 = qfr5_rho_pow(form2, fpd[-3], B->q);
     881       35469 :       if (!absequalii(gel(form2,1),gel(form2,3)))
     882             :       {
     883       35469 :         setsigne(form2[1], 1);
     884       35469 :         setsigne(form2[3],-1);
     885             :       }
     886       35469 :       p = fpc << 1;
     887       35469 :       b1 = umodiu(gel(form2,2), p);
     888       35469 :       b2 = umodiu(gel(form1,2), p);
     889       35469 :       if (b1 != b2 && b1+b2 != p) goto CYCLE;
     890             : 
     891       35469 :       col = gel(mat,++s);
     892       35469 :       add_fact(B, col, form1);
     893       35469 :       (void)factorquad(B,form2,B->KC,LIMC);
     894       35469 :       if (b1==b2)
     895             :       {
     896      135100 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += fpd[i]-ex[i];
     897       17626 :         sub_fact(B,col, form2);
     898       17626 :         if (fpd[-2]) col[fpd[-2]]++;
     899       17626 :         d = dist(subii(gel(form1,4),gel(form2,4)),
     900       17626 :                  divrr(gel(form1,5),gel(form2,5)), prec);
     901             :       }
     902             :       else
     903             :       {
     904      136780 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += -fpd[i]-ex[i];
     905       17843 :         add_fact(B, col, form2);
     906       17843 :         if (fpd[-2]) col[fpd[-2]]--;
     907       17843 :         d = dist(addii(gel(form1,4),gel(form2,4)),
     908       17843 :                  mulrr(gel(form1,5),gel(form2,5)), prec);
     909             :       }
     910       35469 :       if (DEBUGLEVEL>2) err_printf(" %ldP",s);
     911             :     }
     912             :     else
     913             :     { /* standard relation */
     914      149219 :       if (!form1)
     915             :       {
     916      126077 :         form1 = qfr5_factorback(B, ex);
     917      126077 :         if (!first)
     918      123900 :           form1 = QFR5_comp(form1, qfr5_pf(B->q, B->FB[current], prec), B->q);
     919             :       }
     920      149219 :       form1 = qfr5_rho_pow(form1, rho, B->q);
     921      149219 :       rho = 0;
     922             : 
     923      149219 :       col = gel(mat,++s);
     924     1147489 :       for (i=1; i<lgsub; i++) col[B->subFB[i]] = -ex[i];
     925      149219 :       add_fact(B, col, form1);
     926      149219 :       d = dist(gel(form1,4), gel(form1,5), prec);
     927      149219 :       if (DEBUGLEVEL>2) err_printf(" %ld",s);
     928             :     }
     929      184688 :     dist_set(gel(C,s), d);
     930      184688 :     if (first)
     931             :     {
     932       25319 :       if (s >= lim) continue;
     933       23163 :       goto CYCLE;
     934             :     }
     935             :     else
     936             :     {
     937      159369 :       col[current]--;
     938      159369 :       if (++current > B->KC) current = 1;
     939             :     }
     940             :   }
     941        5145 :   if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest);
     942        5145 :   *pc = current;
     943        5145 : }
     944             : 
     945             : static int
     946           7 : real_be_honest(struct buch_quad *B)
     947             : {
     948           7 :   long p, fpc, s = B->KC, nbtest = 0;
     949           7 :   GEN F,F0, ex = cgetg(lg(B->subFB), t_VECSMALL);
     950           7 :   pari_sp av = avma;
     951             : 
     952          28 :   while (s<B->KC2)
     953             :   {
     954          21 :     p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p);
     955          21 :     F = QFR3_comp(qfr3_random(B, ex), qfr3_pf(B->q, p), B->q);
     956          21 :     for (F0 = F;;)
     957             :     {
     958          49 :       fpc = factorquad(B,F,s,p-1);
     959          49 :       if (fpc == 1) { nbtest=0; s++; break; }
     960          28 :       if (++nbtest > 40) return 0;
     961          28 :       F = qfr3_canon(qfr3_rho(F, B->q), B->q);
     962          28 :       if (equalii(gel(F,1),gel(F0,1))
     963           0 :        && equalii(gel(F,2),gel(F0,2))) break;
     964             :     }
     965          21 :     set_avma(av);
     966             :   }
     967           7 :   return 1;
     968             : }
     969             : 
     970             : static GEN
     971       55146 : crabs(GEN a)
     972             : {
     973       55146 :   return signe(real_i(a)) < 0 ? gneg(a): a;
     974             : }
     975             : 
     976             : static GEN
     977       33978 : gcdreal(GEN a,GEN b)
     978             : {
     979       33978 :   if (!signe(real_i(a))) return crabs(b);
     980       33012 :   if (!signe(real_i(b))) return crabs(a);
     981       32897 :   if (expo(real_i(a))<-5) return crabs(b);
     982       12040 :   if (expo(real_i(b))<-5) return crabs(a);
     983        9093 :   a = crabs(a); b = crabs(b);
     984       20019 :   while (expo(real_i(b)) >= -5  && signe(real_i(b)))
     985             :   {
     986             :     long e;
     987       10926 :     GEN r, q = gcvtoi(divrr(real_i(a),real_i(b)),&e);
     988       10926 :     if (e > 0) return NULL;
     989       10926 :     r = gsub(a, gmul(q,b)); a = b; b = r;
     990             :   }
     991        9093 :   return crabs(a);
     992             : }
     993             : 
     994             : static int
     995       91589 : get_R(struct buch_quad *B, GEN C, long sreg, GEN z, GEN *ptR)
     996             : {
     997       91589 :   GEN R = gen_1;
     998             :   double c;
     999             :   long i;
    1000       91589 :   if (B->PRECREG)
    1001             :   {
    1002        2982 :     R = crabs(gel(C,1));
    1003       36960 :     for (i=2; i<=sreg; i++)
    1004             :     {
    1005       33978 :       R = gcdreal(gel(C,i), R);
    1006       33978 :       if (!R) return fupb_PRECI;
    1007             :     }
    1008        2982 :     if (gexpo(real_i(R)) <= -3)
    1009             :     {
    1010           0 :       if (DEBUGLEVEL>2) err_printf("regulator is zero.\n");
    1011           0 :       return fupb_RELAT;
    1012             :     }
    1013        2982 :     if (DEBUGLEVEL>2) err_printf("#### Tentative regulator: %Ps\n",R);
    1014             :   }
    1015       91589 :   c = gtodouble(gmul(z, real_i(R)));
    1016       91591 :   if (c < 0.8 || c > 1.3) return fupb_RELAT;
    1017       70295 :   *ptR = R; return fupb_NONE;
    1018             : }
    1019             : 
    1020             : static int
    1021       70295 : quad_be_honest(struct buch_quad *B)
    1022             : {
    1023             :   int r;
    1024       70295 :   if (B->KC2 <= B->KC) return 1;
    1025          14 :   if (DEBUGLEVEL>2)
    1026           0 :     err_printf("be honest for primes from %ld to %ld\n", B->FB[B->KC+1],B->FB[B->KC2]);
    1027          14 :   r = B->PRECREG? real_be_honest(B): imag_be_honest(B);
    1028          14 :   if (DEBUGLEVEL>2) err_printf("\n");
    1029          14 :   return r;
    1030             : }
    1031             : 
    1032             : static GEN
    1033       70473 : Buchquad_i(GEN D, double cbach, double cbach2, long prec)
    1034             : {
    1035       70473 :   const long MAXRELSUP = 20, SFB_MAX = 3, MPQS_THRESHOLD = 60;
    1036             :   pari_timer T;
    1037             :   pari_sp av, av2;
    1038       70473 :   const long RELSUP = 5;
    1039             :   long i, s, current, triv, sfb_trials, nrelsup, nreldep, need, nsubFB, minSFB;
    1040             :   ulong low, high, LIMC0, LIMC, LIMC2, LIMCMAX, cp;
    1041       70473 :   GEN W, cyc, gen, dep, mat, C, extraC, B, R, invhr, h = NULL; /*-Wall*/
    1042             :   double drc, sdrc, lim, LOGD, LOGD2;
    1043             :   GRHcheck_t GRHcheck;
    1044             :   struct qfr_data q;
    1045             :   struct buch_quad BQ;
    1046       70473 :   int FIRST = 1, use_mpqs = 0;
    1047             :   mpqs_handle_t H;
    1048             :   GEN missing_primes;
    1049             : 
    1050       70473 :   check_quaddisc(D, &s, /*junk*/&i, "Buchquad");
    1051       70473 :   R = NULL; /* -Wall */
    1052       70473 :   BQ.q = &q;
    1053       70473 :   q.D = D;
    1054       70473 :   if (s < 0)
    1055             :   {
    1056       68317 :     if (abscmpiu(q.D,4) <= 0)
    1057         175 :       retmkvec4(gen_1, cgetg(1,t_VEC), cgetg(1,t_VEC), gen_1);
    1058       68142 :     prec = BQ.PRECREG = 0;
    1059       68142 :     if (expi(D) >= MPQS_THRESHOLD)
    1060          28 :       use_mpqs = 1;
    1061             :   } else {
    1062        2156 :     BQ.PRECREG = maxss(prec+EXTRAPREC64, nbits2prec(2*expi(q.D) + 128));
    1063             :   }
    1064       70298 :   if (DEBUGLEVEL>2) timer_start(&T);
    1065       70298 :   BQ.primfact   = new_chunk(100);
    1066       70298 :   BQ.exprimfact = new_chunk(100);
    1067       70298 :   BQ.hashtab = (long**) new_chunk(HASHT);
    1068    72051120 :   for (i=0; i<HASHT; i++) BQ.hashtab[i] = NULL;
    1069             : 
    1070       70299 :   drc = fabs(gtodouble(q.D));
    1071       70298 :   LOGD = log(drc);
    1072       70298 :   LOGD2 = LOGD * LOGD;
    1073             : 
    1074       70298 :   sdrc = lim = sqrt(drc);
    1075       70298 :   if (!BQ.PRECREG) lim /= sqrt(3.);
    1076       70298 :   cp = (ulong)exp(sqrt(LOGD*log(LOGD)/8.0));
    1077       70298 :   if (cp < 20) cp = 20;
    1078       70298 :   if (cbach > 6.) {
    1079           0 :     if (cbach2 < cbach) cbach2 = cbach;
    1080           0 :     cbach = 6.;
    1081             :   }
    1082       70298 :   if (cbach < 0.)
    1083           0 :     pari_err_DOMAIN("Buchquad","Bach constant","<",gen_0,dbltor(cbach));
    1084       70298 :   av = avma;
    1085       70298 :   BQ.powsubFB = BQ.subFB = NULL;
    1086       70298 :   minSFB = (expi(D) > 15)? 3: 2;
    1087       70298 :   init_GRHcheck(&GRHcheck, 2, BQ.PRECREG? 2: 0, LOGD);
    1088       70297 :   high = low = LIMC0 = maxss((long)(cbach2*LOGD2), 1);
    1089       70298 :   LIMCMAX = (long)(4.*LOGD2);
    1090             :   /* 97/1223 below to ensure a good enough approximation of residue */
    1091       70298 :   cache_prime_quad(&GRHcheck, expi(D) < 16 ? 97: 1223, D);
    1092      586995 :   while (!quadGRHchk(D, &GRHcheck, high))
    1093             :   {
    1094      516696 :     low = high;
    1095      516696 :     high *= 2;
    1096             :   }
    1097      516761 :   while (high - low > 1)
    1098             :   {
    1099      446467 :     long test = (low+high)/2;
    1100      446467 :     if (quadGRHchk(D, &GRHcheck, test))
    1101      233929 :       high = test;
    1102             :     else
    1103      212537 :       low = test;
    1104             :   }
    1105       70294 :   if (high == LIMC0+1 && quadGRHchk(D, &GRHcheck, LIMC0))
    1106           0 :     LIMC2 = LIMC0;
    1107             :   else
    1108       70294 :     LIMC2 = high;
    1109       70294 :   if (LIMC2 > LIMCMAX) LIMC2 = LIMCMAX;
    1110       70294 :   LIMC0 = (long)(cbach*LOGD2);
    1111       70294 :   LIMC = cbach ? LIMC0 : LIMC2;
    1112       70294 :   LIMC = maxss(LIMC, nthidealquad(D, 2));
    1113             : 
    1114             : /* LIMC = Max(cbach*(log D)^2, exp(sqrt(log D loglog D) / 8)) */
    1115       70312 : START:
    1116       70312 :   missing_primes = NULL;
    1117             :   do
    1118             :   {
    1119       70382 :     if (!FIRST) LIMC = bnf_increase_LIMC(LIMC,LIMCMAX);
    1120       70382 :     if (DEBUGLEVEL>2 && LIMC > LIMC0)
    1121           0 :       err_printf("%s*** Bach constant: %f\n", FIRST?"":"\n", LIMC/LOGD2);
    1122       70382 :     FIRST = 0; set_avma(av);
    1123       70382 :     guncloneNULL(BQ.subFB);
    1124       70382 :     guncloneNULL(BQ.powsubFB);
    1125       70382 :     clearhash(BQ.hashtab);
    1126       70383 :     if (LIMC < cp) LIMC = cp;
    1127       70383 :     if (LIMC2 < LIMC) LIMC2 = LIMC;
    1128       70383 :     if (BQ.PRECREG) qfr_data_init(q.D, BQ.PRECREG, &q);
    1129             : 
    1130       70383 :     FBquad(&BQ, LIMC2, LIMC, &GRHcheck);
    1131       70380 :     if (DEBUGLEVEL>2) timer_printf(&T, "factor base");
    1132       70380 :     BQ.subFB = subFBquad(&BQ, q.D, lim + 0.5, minSFB);
    1133       70383 :     if (DEBUGLEVEL>2) timer_printf(&T, "subFBquad = %Ps",
    1134             :                                  vecpermute(BQ.FB, BQ.subFB));
    1135       70383 :     nsubFB = lg(BQ.subFB) - 1;
    1136             :   }
    1137       70383 :   while (nsubFB < (expi(D) > 15 ? 3 : 2));
    1138             :   /* invhr = 2^r1 (2pi)^r2 / sqrt(D) w ~ L(chi,1) / hR */
    1139       70311 :   invhr = gmul(dbltor((BQ.PRECREG?2.:M_PI)/sdrc),
    1140             :                compute_invresquad(&GRHcheck, LIMC));
    1141       70313 :   BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1);
    1142       70313 :   if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad");
    1143       70313 :   BQ.limhash = (LIMC & HIGHMASK)? (HIGHBIT>>1): LIMC*LIMC;
    1144             : 
    1145       70313 :   need = BQ.KC + RELSUP - 2;
    1146       70313 :   current = 0;
    1147       70313 :   W = NULL;
    1148       70313 :   sfb_trials = nreldep = nrelsup = 0;
    1149       70313 :   s = nsubFB + RELSUP;
    1150       70313 :   if (use_mpqs)
    1151          28 :     use_mpqs = mpqs_class_init(&H, D, BQ.KC);
    1152       70313 :   av2 = avma;
    1153             : 
    1154             :   do
    1155             :   {
    1156      104528 :     if ((nreldep & 3) == 1 || (nrelsup & 7) == 1) {
    1157       28887 :       if (DEBUGLEVEL>2) err_printf("*** Changing sub factor base\n");
    1158       28887 :       gunclone(BQ.subFB);
    1159       28887 :       gunclone(BQ.powsubFB);
    1160       28887 :       BQ.subFB = gclone(vecslice(BQ.vperm, 1, nsubFB));
    1161       28887 :       BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1);
    1162       28887 :       if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad");
    1163       28887 :       clearhash(BQ.hashtab);
    1164             :     }
    1165      104528 :     if (!use_mpqs) need += 2;
    1166      104528 :     mat    = cgetg(need+1, t_MAT);
    1167      104528 :     extraC = cgetg(need+1, t_VEC);
    1168      104528 :     if (!W) { /* first time */
    1169       70313 :       C = extraC;
    1170       70313 :       triv = trivial_relations(&BQ, mat, C);
    1171       70313 :       if (DEBUGLEVEL>2) err_printf("KC = %ld, need %ld relations\n", BQ.KC, need);
    1172             :     } else {
    1173       34215 :       triv = 0;
    1174       34215 :       if (DEBUGLEVEL>2) err_printf("...need %ld more relations\n", need);
    1175             :     }
    1176      104528 :     if (BQ.PRECREG) {
    1177      189833 :       for (i = triv+1; i<=need; i++) {
    1178      184688 :         gel(mat,i) = zero_zv(BQ.KC);
    1179      184688 :         gel(extraC,i) = mkcomplex(cgetr(BQ.PRECREG), cgeti(3));
    1180             :       }
    1181        5145 :       real_relations(&BQ, need - triv, &current, s,LIMC,mat + triv,extraC + triv);
    1182             :     } else {
    1183     1717986 :       for (i = triv+1; i<=need; i++) {
    1184     1618602 :         gel(mat,i) = zero_zv(BQ.KC);
    1185     1618603 :         gel(extraC,i) = gen_0;
    1186             :       }
    1187       99384 :       if (use_mpqs)
    1188         336 :         mpqs_relations(&BQ, need - triv, &current, LIMC,mat + triv, &H, missing_primes);
    1189             :       else
    1190       99048 :         imag_relations(&BQ, need - triv, &current, LIMC,mat + triv);
    1191             :     }
    1192      104528 :     if (DEBUGLEVEL>2) timer_start(&T);
    1193      104528 :     if (!W)
    1194       70313 :       W = hnfspec_i(mat,BQ.vperm,&dep,&B,&C,nsubFB);
    1195             :     else
    1196       34215 :       W = hnfadd_i(W,BQ.vperm,&dep,&B,&C, mat,extraC);
    1197      104528 :     if (DEBUGLEVEL>2) timer_printf(&T, "hnfadd");
    1198      104528 :     need = BQ.KC - (lg(W)-1) - (lg(B)-1);
    1199      104528 :     (void)gc_all(av2, 4, &W,&C,&B,&dep);
    1200      104527 :     missing_primes = vecslice(BQ.vperm,1,need);
    1201      104527 :     if (need)
    1202             :     {
    1203       12933 :       if (++nreldep > 15 && cbach < 1) goto START;
    1204       12933 :       continue;
    1205             :     }
    1206             : 
    1207       91594 :     h = ZM_det_triangular(W);
    1208       91590 :     if (DEBUGLEVEL>2) err_printf("\n#### Tentative class number: %Ps\n", h);
    1209             : 
    1210       91590 :     switch(get_R(&BQ, C, (lg(C)-1) - (lg(B)-1) - (lg(W)-1), mulir(h,invhr), &R))
    1211             :     {
    1212           0 :       case fupb_PRECI:
    1213           0 :         BQ.PRECREG = precdbl(BQ.PRECREG);
    1214           0 :         FIRST = 1; goto START;
    1215             : 
    1216       21296 :       case fupb_RELAT:
    1217       21296 :         if (++nrelsup > MAXRELSUP)
    1218             :         {
    1219          63 :           if (++sfb_trials > SFB_MAX && cbach <= 1) goto START;
    1220          49 :           if (nsubFB < minss(10,BQ.KC)) nsubFB++;
    1221             :         }
    1222       21282 :         need = minss(BQ.KC, nrelsup);
    1223             :     }
    1224             :   }
    1225      104510 :   while (need);
    1226             :   /* DONE */
    1227       70295 :   if (!quad_be_honest(&BQ)) goto START;
    1228       70295 :   if (DEBUGLEVEL>2) timer_printf(&T, "be honest");
    1229       70295 :   clearhash(BQ.hashtab);
    1230       70299 :   free_GRHcheck(&GRHcheck);
    1231             : 
    1232       70299 :   gen = get_clgp(&BQ,W,&cyc);
    1233       70299 :   gunclone(BQ.subFB);
    1234       70299 :   gunclone(BQ.powsubFB);
    1235       70299 :   if (BQ.PRECREG)
    1236        2156 :     return mkvec5(h, cyc, gen, real_i(R), mpodd(imag_i(R)) ? gen_m1:gen_1);
    1237             :   else
    1238       68143 :     return mkvec4(h, cyc, gen, real_i(R));
    1239             : }
    1240             : GEN
    1241        4424 : Buchquad(GEN D, double c, double c2, long prec)
    1242             : {
    1243        4424 :   pari_sp av = avma;
    1244        4424 :   GEN z = Buchquad_i(D, c, c2, prec);
    1245        4424 :   return gc_GEN(av, z);
    1246             : }
    1247             : 
    1248             : GEN
    1249           0 : buchimag(GEN D, GEN c, GEN c2, GEN REL)
    1250           0 : { (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),0); }
    1251             : 
    1252             : GEN
    1253           0 : buchreal(GEN D, GEN flag, GEN c, GEN c2, GEN REL, long prec) {
    1254           0 :   if (signe(flag)) pari_err_IMPL("narrow class group");
    1255           0 :   (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),prec);
    1256             : }
    1257             : 
    1258             : GEN
    1259        4424 : quadclassunit0(GEN x, long flag, GEN data, long prec)
    1260             : {
    1261             :   long lx;
    1262        4424 :   double c1 = 0.0, c2 = 0.0;
    1263             : 
    1264        4424 :   if (!data) lx=1;
    1265             :   else
    1266             :   {
    1267          28 :     lx = lg(data);
    1268          28 :     if (typ(data)!=t_VEC) pari_err_TYPE("quadclassunit", data);
    1269          28 :     if (lx > 7) pari_err_DIM("quadclassunit [tech vector]");
    1270          28 :     if (lx > 3) lx = 3;
    1271             :   }
    1272        4424 :   switch(lx)
    1273             :   {
    1274          21 :     case 3: c2 = gtodouble(gel(data,2));
    1275          28 :     case 2: c1 = gtodouble(gel(data,1));
    1276             :   }
    1277        4424 :   if (flag) pari_err_IMPL("narrow class group");
    1278        4424 :   return Buchquad(x,c1,c2,prec);
    1279             : }
    1280             : GEN
    1281       61174 : quadclassno(GEN D)
    1282             : {
    1283       61174 :   pari_sp av = avma;
    1284       61174 :   GEN h = abgrp_get_no(Buchquad_i(D, 0, 0, 0));
    1285       61175 :   return icopy_avma(h, av);
    1286             : }
    1287             : long
    1288        4875 : quadclassnos(long D)
    1289             : {
    1290        4875 :   pari_sp av = avma;
    1291        4875 :   long h = itos(abgrp_get_no(Buchquad_i(stoi(D), 0, 0, 0)));
    1292        4875 :   return gc_long(av, h);
    1293             : }

Generated by: LCOV version 1.16