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) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31041-bd73e9fcdd) Lines: 95.5 % 711 679
Test Date: 2026-07-22 22:45:42 Functions: 92.9 % 56 52
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      3471516 : 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      6130078 : init_form(struct buch_quad *B, GEN ex,
     135              :           GEN (*comp)(GEN,GEN,struct qfr_data *S))
     136              : {
     137      6130078 :   long i, l = lg(B->powsubFB);
     138      6130078 :   GEN F = NULL;
     139     32212916 :   for (i=1; i<l; i++)
     140     26108832 :     if (ex[i])
     141              :     {
     142     24480317 :       GEN t = gmael(B->powsubFB,i,ex[i]);
     143     24480317 :       F = F? comp(F, t, B->q): t;
     144              :     }
     145      6104084 :   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     16471798 : QFI_comp(GEN x, GEN y, struct qfr_data *S) { (void)S; return qfbcomp_i(x,y); }
     152              : 
     153              : static GEN
     154       264078 : qfi_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFI_comp); }
     155              : 
     156              : static GEN
     157      5668174 : random_form(struct buch_quad *B, GEN ex,
     158              :             GEN (*comp)(GEN,GEN, struct qfr_data *S))
     159              : {
     160      5668174 :   long i, l = lg(ex);
     161      5668174 :   pari_sp av = avma;
     162              :   GEN F;
     163              :   for(;;)
     164              :   {
     165     29459159 :     for (i=1; i<l; i++) ex[i] = random_bits(RANDOM_BITS);
     166      5668797 :     if ((F = init_form(B, ex, comp))) return F;
     167          753 :     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      5506585 : qfi_random(struct buch_quad *B,GEN ex) { return random_form(B, ex, &QFI_comp); }
     174              : 
     175              : /*******************************************************************/
     176              : /*                                                                 */
     177              : /*                     Common subroutines                          */
     178              : /*                                                                 */
     179              : /*******************************************************************/
     180              : /* Prime ideals of norm < D = 4 log^2(disc K) generate Cl(K) under GRH
     181              :  * (Grenie-Molteni). Failure with a factor base of primes with norm < LIMC.
     182              :  * Suggest new value.
     183              :  *
     184              :  * A value of c * log^2(disc K) in [0.3, 1] is OK for most fields and no
     185              :  * example is known where c >= 2 is necessary to generate the class group.
     186              :  * Nevertheless, when the bound (hence the factorbase) is small, the index
     187              :  * calculus algorithm may fail even if the class group is generated. We allow a
     188              :  * return value > D for this reason [#2653] */
     189              : ulong
     190         2357 : bnf_increase_LIMC(ulong LIMC, ulong D)
     191              : {
     192         2357 :   if (LIMC <= D / 13.333) /* c <= 0.3 */
     193          232 :     LIMC *= 2; /* tiny c, roughly double it */
     194              :   else
     195         2125 :     LIMC += maxuu(1, D / 20); /* large c, add 0.2 to it */
     196         2357 :   return LIMC;
     197              : }
     198              : 
     199              : /* Is |q| <= p ? */
     200              : static int
     201        10416 : isless_iu(GEN q, ulong p) {
     202        10416 :   long l = lgefint(q);
     203        10416 :   return l==2 || (l == 3 && uel(q,2) <= p);
     204              : }
     205              : 
     206              : static GEN
     207      7093744 : Z_isquasismooth_prod(GEN N, GEN P)
     208              : {
     209      7093744 :   P = gcdii(P,N);
     210     13730097 :   while (!is_pm1(P))
     211              :   {
     212      6620119 :     N = diviiexact(N, P);
     213      6642417 :     P = gcdii(N, P);
     214              :   }
     215      7080893 :   return N;
     216              : }
     217              : 
     218              : static long
     219      7100591 : factorquad(struct buch_quad *B, GEN f, long nFB, ulong limp)
     220              : {
     221              :   ulong X;
     222      7100591 :   long i, lo = 0;
     223      7100591 :   GEN F, x = gel(f,1), FB = B->FB, P = B->primfact, E = B->exprimfact;
     224      7100591 :   if (B->badprim && !is_pm1(gcdii(x, B->badprim))) return 0;
     225      7093388 :   F =  Z_isquasismooth_prod(x, B->prodFB);
     226      7080495 :   if (cmpiu(F, B->limhash) > 0) return 0;
     227      6455926 :   for (i=1; lgefint(x) > 3; i++)
     228              :   {
     229        10416 :     ulong p = uel(FB,i), r;
     230        10416 :     GEN q = absdiviu_rem(x, p, &r);
     231        10416 :     if (!r)
     232              :     {
     233         1530 :       long k = 0;
     234         2633 :       do { k++; x = q; q = absdiviu_rem(x, p, &r); } while (!r);
     235         1530 :       lo++; P[lo] = p; E[lo] = k;
     236              :     }
     237        10416 :     if (isless_iu(q,p)) {
     238            1 :       if (lgefint(x) == 3) { X = uel(x,2); goto END; }
     239           34 :       return 0;
     240              :     }
     241        10415 :     if (i == nFB) return 0;
     242              :   }
     243      6445510 :   X = uel(x,2);
     244      6445510 :   if (X == 1) { P[0] = 0; return 1; }
     245     74785463 :   for (;; i++)
     246     74785463 :   { /* single precision affair, split for efficiency */
     247     81205347 :     ulong p = uel(FB,i);
     248     81205347 :     ulong q = X / p, r = X % p; /* gcc makes a single div */
     249     81205347 :     if (!r)
     250              :     {
     251      7109950 :       long k = 0;
     252      8557124 :       do { k++; X = q; q = X / p; r = X % p; } while (!r);
     253      7109950 :       lo++; P[lo] = p; E[lo] = k;
     254              :     }
     255     81205347 :     if (q <= p) break;
     256     74810459 :     if (i == nFB) return 0;
     257              :   }
     258      6394889 : END:
     259      6394889 :   if (X > B->limhash) return 0;
     260      6394889 :   if (X != 1 && X <= limp) { lo++; P[lo] = X; E[lo] = 1; X = 1; }
     261      6394889 :   P[0] = lo; return X;
     262              : }
     263              : 
     264              : /* Check for a "large prime relation" involving q; q may not be prime */
     265              : static long *
     266      3471460 : largeprime(struct buch_quad *B, long q, GEN ex, long np, long nrho)
     267              : {
     268      3471460 :   const long hashv = hash(q);
     269      3471525 :   long *pt, i, l = lg(B->subFB);
     270              : 
     271      3694788 :   for (pt = B->hashtab[hashv]; ; pt = (long*) pt[0])
     272              :   {
     273      3694788 :     if (!pt)
     274              :     {
     275      3168595 :       pt = (long*) pari_malloc((l+3) * sizeof(long));
     276      3169205 :       *pt++ = nrho; /* nrho = pt[-3] */
     277      3169205 :       *pt++ = np;   /* np   = pt[-2] */
     278      3169205 :       *pt++ = q;    /* q    = pt[-1] */
     279      3169205 :       pt[0] = (long)B->hashtab[hashv];
     280     18624396 :       for (i=1; i<l; i++) pt[i]=ex[i];
     281      3169205 :       B->hashtab[hashv]=pt; return NULL;
     282              :     }
     283       526193 :     if (pt[-1] == q) break;
     284              :   }
     285       348861 :   for(i=1; i<l; i++)
     286       345474 :     if (pt[i] != ex[i]) return pt;
     287         3387 :   return (pt[-2]==np)? NULL: pt;
     288              : }
     289              : 
     290              : static void
     291       294539 : clearhash(long **hash)
     292              : {
     293              :   long *pt;
     294              :   long i;
     295    301816331 :   for (i=0; i<HASHT; i++) {
     296    304691085 :     for (pt = hash[i]; pt; ) {
     297      3169293 :       void *z = (void*)(pt - 3);
     298      3169293 :       pt = (long*) pt[0]; pari_free(z);
     299              :     }
     300    301521792 :     hash[i] = NULL;
     301              :   }
     302       294909 : }
     303              : 
     304              : /* last prime stored */
     305              : ulong
     306            0 : GRH_last_prime(GRHcheck_t *S) { return (S->primes + S->nprimes-1)->p; }
     307              : /* ensure that S->primes can hold at least nb primes */
     308              : void
     309       454948 : GRH_ensure(GRHcheck_t *S, long nb)
     310              : {
     311       454948 :   if (S->maxprimes <= nb)
     312              :   {
     313            0 :     do S->maxprimes *= 2; while (S->maxprimes <= nb);
     314            0 :     pari_realloc_ip((void**)&S->primes, S->maxprimes*sizeof(*S->primes));
     315              :   }
     316       454948 : }
     317              : /* cache data for all primes up to the LIM */
     318              : static void
     319      2053814 : cache_prime_quad(GRHcheck_t *S, ulong LIM, GEN D)
     320              : {
     321              :   GRHprime_t *pr;
     322              :   long nb;
     323              : 
     324      2053814 :   if (S->limp >= LIM) return;
     325       124993 :   nb = (long)primepi_upper_bound((double)LIM); /* #{p <= LIM} <= nb */
     326       125012 :   GRH_ensure(S, nb+1); /* room for one extra prime */
     327       125012 :   for (pr = S->primes + S->nprimes;;)
     328     22472382 :   {
     329     22597394 :     ulong p = u_forprime_next(&(S->P));
     330     22596638 :     pr->p = p;
     331     22596638 :     pr->logp = log((double)p);
     332     22596638 :     pr->dec = (GEN)kroiu(D,p);
     333     22597397 :     S->nprimes++;
     334     22597397 :     pr++;
     335              :     /* store up to nextprime(LIM) included */
     336     22597397 :     if (p >= LIM) { S->limp = p; break; }
     337              :   }
     338              : }
     339              : 
     340              : static GEN
     341       122390 : compute_invresquad(GRHcheck_t *S, long LIMC)
     342              : {
     343       122390 :   pari_sp av = avma;
     344       122390 :   GEN invres = real_1(DEFAULTPREC);
     345       122389 :   double limp = log((double)LIMC) / 2;
     346              :   GRHprime_t *pr;
     347              :   long i;
     348     22460165 :   for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--)
     349              :   {
     350     22347251 :     long s = (long)pr->dec;
     351     22347251 :     if (s)
     352              :     {
     353     22147852 :       ulong p = pr->p;
     354     22147852 :       if (s > 0 || pr->logp <= limp)
     355              :         /* Both p and P contribute */
     356     11230035 :         invres = mulur(p - s, divru(invres, p));
     357     10917817 :       else if (s<0)
     358              :         /* Only p contributes */
     359     10917820 :         invres = mulur(p, divru(invres, p - 1));
     360              :     }
     361              :   }
     362       112914 :   return gc_leaf(av, invres);
     363              : }
     364              : 
     365              : /* p | conductor of order of disc D ? */
     366              : static int
     367       689066 : is_bad(GEN D, ulong p)
     368              : {
     369       689066 :   pari_sp av = avma;
     370       689066 :   if (p == 2)
     371              :   {
     372       155896 :     long r = mod16(D) >> 1;
     373       155896 :     if (r && signe(D) < 0) r = 8-r;
     374       155896 :     return (r < 4);
     375              :   }
     376       533170 :   return gc_bool(av, dvdii(D, sqru(p))); /* p^2 | D ? */
     377              : }
     378              : 
     379              : /* returns the n-th suitable ideal for the factorbase */
     380              : static long
     381       122378 : nthidealquad(GEN D, long n)
     382              : {
     383       122378 :   pari_sp av = avma;
     384              :   forprime_t S;
     385              :   ulong p;
     386       122378 :   (void)u_forprime_init(&S, 2, ULONG_MAX);
     387       628178 :   while ((p = u_forprime_next(&S)) && n > 0)
     388       505832 :     if (!is_bad(D, p) && kroiu(D, p) >= 0) n--;
     389       122356 :   return gc_long(av, p);
     390              : }
     391              : 
     392              : static int
     393      1808974 : quadGRHchk(GEN D, GRHcheck_t *S, ulong LIMC)
     394              : {
     395      1808974 :   double logC = log((double)LIMC), SA = 0, SB = 0;
     396              :   long i;
     397              : 
     398      1808974 :   cache_prime_quad(S, LIMC, D);
     399      1808975 :   for (i = 0;; i++)
     400     47080019 :   {
     401     48888994 :     GRHprime_t *pr = S->primes+i;
     402     48888994 :     ulong p = pr->p;
     403              :     long M;
     404              :     double logNP, q, A, B;
     405     48888994 :     if (p > LIMC) break;
     406     47233666 :     if ((long)pr->dec < 0)
     407              :     {
     408     23628067 :       logNP = 2 * pr->logp;
     409     23628067 :       q = 1/(double)p;
     410              :     }
     411              :     else
     412              :     {
     413     23605599 :       logNP = pr->logp;
     414     23605599 :       q = 1/sqrt((double)p);
     415              :     }
     416     47233666 :     A = logNP * q; B = logNP * A; M = (long)(logC/logNP);
     417     47233666 :     if (M > 1)
     418              :     {
     419      4267803 :       double inv1_q = 1 / (1-q);
     420      4267803 :       A *= (1 - pow(q, (double) M)) * inv1_q;
     421      4267803 :       B *= (1 - pow(q, (double) M)*(M+1 - M*q)) * inv1_q * inv1_q;
     422              :     }
     423     47233666 :     if ((long)pr->dec>0) { SA += 2*A;SB += 2*B; } else { SA += A; SB += B; }
     424     47233666 :     if (p == LIMC) break;
     425              :   }
     426      1808975 :   return GRHok(S, logC, SA, SB);
     427              : }
     428              : 
     429              : /* C2 >= C1; create B->FB, B->numFB; set B->badprim. Return L(kro_D, 1) */
     430              : static void
     431       122487 : FBquad(struct buch_quad *B, ulong C2, ulong C1, GRHcheck_t *S)
     432              : {
     433       122487 :   GEN D = B->q->D;
     434              :   long i;
     435              :   pari_sp av;
     436              :   GRHprime_t *pr;
     437              : 
     438       122487 :   cache_prime_quad(S, C2, D);
     439       122487 :   pr = S->primes;
     440       122487 :   B->numFB = cgetg(C2+1, t_VECSMALL);
     441       122487 :   B->FB    = cgetg(C2+1, t_VECSMALL);
     442       122481 :   av = avma;
     443       122481 :   B->KC = 0; i = 0;
     444       122481 :   B->badprim = gen_1;
     445      4578005 :   for (;; pr++) /* p <= C2 */
     446      4578005 :   {
     447      4700486 :     ulong p = pr->p;
     448      4700486 :     if (!B->KC && p > C1) B->KC = i;
     449      4700486 :     if (p > C2) break;
     450      4591463 :     switch ((long)pr->dec)
     451              :     {
     452      2263868 :       case -1: break; /* inert */
     453       183241 :       case  0: /* ramified */
     454       183241 :         if (is_bad(D, p)) { B->badprim = muliu(B->badprim, p); break; }
     455              :         /* fall through */
     456              :       default:  /* split */
     457      2327446 :         i++; B->numFB[p] = i; B->FB[i] = p; break;
     458              :     }
     459      4591468 :     if (p == C2)
     460              :     {
     461        13463 :       if (!B->KC) B->KC = i;
     462        13463 :       break;
     463              :     }
     464              :   }
     465       122486 :   B->KC2 = i;
     466       122486 :   setlg(B->FB, B->KC2+1);
     467       122487 :   if (B->badprim != gen_1)
     468          126 :     B->badprim = gc_INT(av, B->badprim);
     469              :   else
     470              :   {
     471       122361 :     B->badprim = NULL; set_avma(av);
     472              :   }
     473       122487 :   B->prodFB = zv_prod_Z(B->FB);
     474       122484 : }
     475              : 
     476              : /* create B->vperm, return B->subFB */
     477              : static GEN
     478       122484 : subFBquad(struct buch_quad *B, GEN D, double PROD, long minSFB)
     479              : {
     480       122484 :   long i, j, lgsub = 1, ino = 1, lv = B->KC+1;
     481       122484 :   double prod = 1.;
     482              :   pari_sp av;
     483              :   GEN no;
     484              : 
     485       122484 :   B->vperm = cgetg(lv, t_VECSMALL);
     486       122485 :   av = avma;
     487       122485 :   no    = cgetg(lv, t_VECSMALL);
     488       577088 :   for (j = 1; j < lv; j++)
     489              :   {
     490       576980 :     ulong p = uel(B->FB,j);
     491       576980 :     if (!umodiu(D, p)) no[ino++] = j; /* ramified */
     492              :     else
     493              :     {
     494       437247 :       B->vperm[lgsub++] = j;
     495       437247 :       prod *= p;
     496       437247 :       if (lgsub > minSFB && prod > PROD) break;
     497              :     }
     498              :   }
     499              :   /* lgsub >= 1 otherwise quadGRHchk is false */
     500       122485 :   i = lgsub;
     501       262217 :   for (j = 1; j < ino;i++,j++) B->vperm[i] = no[j];
     502      1872606 :   for (     ; i < lv; i++)     B->vperm[i] = i;
     503       122485 :   no = gclone(vecslice(B->vperm, 1, lgsub-1));
     504       122487 :   set_avma(av); return no;
     505              : }
     506              : 
     507              : /* assume n >= 1, x[i][j] = B->subFB[i]^j, for j = 1..n */
     508              : static GEN
     509       172082 : powsubFBquad(struct buch_quad *B, long n)
     510              : {
     511       172082 :   pari_sp av = avma;
     512       172082 :   long i,j, l = lg(B->subFB);
     513       172082 :   GEN F, y, x = cgetg(l, t_VEC), D = B->q->D;
     514              : 
     515       172081 :   if (B->PRECREG) /* real */
     516              :   {
     517        39627 :     for (i=1; i<l; i++)
     518              :     {
     519        34510 :       F = qfr5_pf(B->q, B->FB[B->subFB[i]], B->PRECREG);
     520        34510 :       y = cgetg(n+1, t_VEC); gel(x,i) = y;
     521        34510 :       gel(y,1) = F;
     522       552160 :       for (j=2; j<=n; j++) gel(y,j) = QFR5_comp(gel(y,j-1), F, B->q);
     523              :     }
     524              :   }
     525              :   else /* imaginary */
     526              :   {
     527       753793 :     for (i=1; i<l; i++)
     528              :     {
     529       586867 :       F = qfi_pf(D, B->FB[B->subFB[i]]);
     530       586809 :       y = cgetg(n+1, t_VEC); gel(x,i) = y;
     531       589225 :       gel(y,1) = F;
     532      9367042 :       for (j=2; j<=n; j++) gel(y,j) = qfbcomp_i(gel(y,j-1), F);
     533              :     }
     534              :   }
     535       172043 :   x = gclone(x); set_avma(av); return x;
     536              : }
     537              : 
     538              : static void
     539       149964 : sub_fact(struct buch_quad *B, GEN col, GEN F)
     540              : {
     541       149964 :   GEN b = gel(F,2);
     542              :   long i;
     543       280986 :   for (i=1; i<=B->primfact[0]; i++)
     544              :   {
     545       131022 :     ulong p = B->primfact[i], k = B->numFB[p];
     546       131022 :     long e = B->exprimfact[i];
     547       131022 :     if (umodiu(b, p<<1) > p) e = -e;
     548       131022 :     col[k] -= e;
     549              :   }
     550       149964 : }
     551              : 
     552              : #if 0
     553              : static void
     554              : dbg_fact(struct buch_quad *B)
     555              : {
     556              :   long i;
     557              :   for (i=1; i<=B->primfact[0]; i++)
     558              :   {
     559              :     ulong p = B->primfact[i];
     560              :     long e = B->exprimfact[i];
     561              :     err_printf("%lu^%ld ",p,e);
     562              :   }
     563              : }
     564              : 
     565              : static void
     566              : chk_fact(struct buch_quad *B, GEN col)
     567              : {
     568              :   long i, l = lg(col);
     569              :   GEN Q = qfi_pf(B->q->D, 1);
     570              :   for (i=1; i< l; i++)
     571              :   {
     572              :     ulong p = B->FB[i];
     573              :     long k = col[i];
     574              :     Q = qfbcomp(qfbpowraw(qfi_pf(B->q->D, p),k),Q);
     575              :   }
     576              :   if (!gequal1(gel(Q,1))) pari_err_BUG("chk_fact");
     577              : }
     578              : #endif
     579              : 
     580              : static void
     581      3105896 : add_fact(struct buch_quad *B, GEN col, GEN F)
     582              : {
     583      3105896 :   GEN b = gel(F,2);
     584              :   long i;
     585      9318772 :   for (i=1; i<=B->primfact[0]; i++)
     586              :   {
     587      6212578 :     ulong p = B->primfact[i], k = B->numFB[p];
     588      6212578 :     long e = B->exprimfact[i];
     589      6212578 :     if (umodiu(b, p<<1) > p) e = -e;
     590      6212876 :     col[k] += e;
     591              :   }
     592      3106194 : }
     593              : 
     594              : static GEN
     595       122378 : get_clgp(struct buch_quad *B, GEN W, GEN *ptD)
     596              : {
     597       122378 :   GEN res, init, u1, D = ZM_snf_group(W,NULL,&u1);
     598       122375 :   long i, j, l = lg(W), c = lg(D);
     599              : 
     600       122375 :   res=cgetg(c,t_VEC); init = cgetg(l,t_VEC);
     601       379043 :   for (i=1; i<l; i++) gel(init,i) = primeform_u(B->q->D, B->FB[B->vperm[i]]);
     602       342549 :   for (j=1; j<c; j++)
     603              :   {
     604       220173 :     GEN g = NULL;
     605       220173 :     if (signe(B->q->D) > 0)
     606              :     {
     607        13328 :       for (i=1; i<l; i++)
     608              :       {
     609         9618 :         GEN t, u = gcoeff(u1,i,j);
     610         9618 :         if (!signe(u)) continue;
     611         4543 :         t = qfr3_pow(gel(init,i), u, B->q);
     612         4543 :         g = g? qfr3_comp(g, t, B->q): t;
     613              :       }
     614         3710 :       g = qfr3_to_qfr(qfr3_canon_safe(qfr3_red(g, B->q), B->q), B->q->D);
     615              :     }
     616              :     else
     617              :     {
     618       752691 :       for (i=1; i<l; i++)
     619              :       {
     620       536228 :         GEN t, u = gcoeff(u1,i,j);
     621       536228 :         if (!signe(u)) continue;
     622       362274 :         t = powgi(gel(init,i), u);
     623       362281 :         g = g? qfbcomp_i(g, t): t;
     624              :       }
     625              :     }
     626       220172 :     gel(res,j) = g;
     627              :   }
     628       122376 :   *ptD = D; return res;
     629              : }
     630              : 
     631              : static long
     632       122392 : trivial_relations(struct buch_quad *B, GEN mat, GEN C)
     633              : {
     634       122392 :   long i, j = 0;
     635       122392 :   GEN col, D = B->q->D;
     636      2449099 :   for (i = 1; i <= B->KC; i++)
     637              :   { /* ramified prime ==> trivial relation */
     638      2326695 :     if (umodiu(D, B->FB[i])) continue;
     639       182838 :     col = zero_zv(B->KC);
     640       182851 :     col[i] = 2; j++;
     641       182851 :     gel(mat,j) = col;
     642       182851 :     gel(C,j) = gen_0;
     643              :   }
     644       122404 :   return j;
     645              : }
     646              : 
     647              : static void
     648            0 : dbg_all(pari_timer *T, const char *phase, long s, long n)
     649              : {
     650            0 :   err_printf("\n");
     651            0 :   timer_printf(T, "%s rel [#rel/#test = %ld/%ld]", phase,s,n);
     652            0 : }
     653              : 
     654              : /* Imaginary Quadratic fields */
     655              : 
     656              : static void
     657         8813 : rel_to_col(struct buch_quad *B, GEN col, GEN rel, GEN b)
     658              : {
     659         8813 :   GEN P = gel(rel, 1), E = gel(rel, 2);
     660         8813 :   long i, lP = lg(P);
     661       105784 :   for (i=1; i<lP; i++)
     662              :   {
     663        96971 :     ulong p = uel(P, i), e = uel(E, i);
     664        96971 :     col[B->numFB[p]] += umodiu(b, p<<1) > p ? -e :e;
     665              :   }
     666         8813 : }
     667              : 
     668              : static void
     669       175936 : imag_relations(struct buch_quad *B, long need, long *pc, ulong LIMC, GEN mat)
     670              : {
     671              :   pari_timer T;
     672       175936 :   long lgsub = lg(B->subFB), current = *pc, nbtest = 0, s = 0;
     673              :   long i, fpc;
     674              :   pari_sp av;
     675       175936 :   GEN col, form, ex = cgetg(lgsub, t_VECSMALL);
     676              : 
     677       175936 :   if (!current) current = 1;
     678       175936 :   if (DEBUGLEVEL>2) timer_start(&T);
     679       175936 :   av = avma;
     680              :   for(;;)
     681              :   {
     682      5682346 :     if (s >= need) break;
     683      5506417 :     set_avma(av);
     684      5506188 :     form = qfi_random(B,ex);
     685      5500401 :     form = qfbcomp_i(form, qfi_pf(B->q->D, B->FB[current]));
     686      5499816 :     nbtest++; fpc = factorquad(B,form,B->KC,LIMC);
     687      5504678 :     if (!fpc)
     688              :     {
     689       291830 :       if (DEBUGLEVEL>3) err_printf(".");
     690       291830 :       if ((nbtest & 0xff) == 0 && ++current > B->KC) current = 1;
     691       291830 :       continue;
     692              :     }
     693      5212848 :     if (fpc > 1)
     694              :     {
     695      2706120 :       long *fpd = largeprime(B,fpc,ex,current,0);
     696              :       ulong b1, b2, p;
     697              :       GEN form2;
     698      2707252 :       if (!fpd)
     699              :       {
     700      2443272 :         if (DEBUGLEVEL>3) err_printf(".");
     701      2443256 :         continue;
     702              :       }
     703       263980 :       form2 = qfbcomp_i(qfi_factorback(B,fpd), qfi_pf(B->q->D, B->FB[fpd[-2]]));
     704       264076 :       p = fpc << 1;
     705       264076 :       b1 = umodiu(gel(form2,2), p);
     706       264077 :       b2 = umodiu(gel(form,2),  p);
     707       264078 :       if (b1 != b2 && b1+b2 != p) continue;
     708              : 
     709       264078 :       col = gel(mat,++s);
     710       264078 :       add_fact(B,col, form);
     711       264082 :       (void)factorquad(B,form2,B->KC,LIMC);
     712       264093 :       if (b1==b2)
     713              :       {
     714       643895 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += fpd[i]-ex[i];
     715       132335 :         sub_fact(B, col, form2); col[fpd[-2]]++;
     716              :       }
     717              :       else
     718              :       {
     719       640257 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += -fpd[i]-ex[i];
     720       131758 :         add_fact(B, col, form2); col[fpd[-2]]--;
     721              :       }
     722       264100 :       if (DEBUGLEVEL>2) err_printf(" %ldP",s);
     723              :     }
     724              :     else
     725              :     {
     726      2506728 :       col = gel(mat,++s);
     727     11732934 :       for (i=1; i<lgsub; i++) col[B->subFB[i]] = -ex[i];
     728      2506728 :       add_fact(B, col, form);
     729      2507674 :       if (DEBUGLEVEL>2) err_printf(" %ld",s);
     730              :     }
     731      2771324 :     col[current]--;
     732      2771324 :     if (++current > B->KC) current = 1;
     733              :   }
     734       175929 :   if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest);
     735       175929 :   *pc = current;
     736       175929 : }
     737              : 
     738              : static void
     739          336 : mpqs_relations(struct buch_quad *B, long need, long *pc, ulong LIMC, GEN mat, mpqs_handle_t *H, GEN missing_primes)
     740              : {
     741              :   pari_timer T;
     742              :   long i, lV;
     743              :   GEN V;
     744          336 :   if (DEBUGLEVEL>2) timer_start(&T);
     745          336 :   V = mpqs_class_rels(H, need, missing_primes);
     746          336 :   if (!V) { imag_relations(B, need, pc, LIMC, mat); return; }
     747          336 :   lV = lg(V);
     748         9149 :   for (i = 1; i < lV && i <= need; i++)
     749              :   {
     750         8813 :     GEN formA = gel(V,i), rel = gel(formA,2), b = gel(formA,1);
     751         8813 :     GEN col = gel(mat,i);
     752         8813 :     rel_to_col(B, col, rel, b);
     753              :   }
     754          336 :   if (DEBUGLEVEL>2) timer_printf(&T, "MPQS rel [#rel = %ld]", i-1);
     755              : }
     756              : 
     757              : static int
     758            7 : imag_be_honest(struct buch_quad *B)
     759              : {
     760            7 :   long p, fpc, s = B->KC, nbtest = 0;
     761            7 :   GEN F, ex = cgetg(lg(B->subFB), t_VECSMALL);
     762            7 :   pari_sp av = avma;
     763              : 
     764          525 :   while (s<B->KC2)
     765              :   {
     766          518 :     p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p);
     767          518 :     F = qfbcomp_i(qfi_pf(B->q->D, p), qfi_random(B, ex));
     768          518 :     fpc = factorquad(B,F,s,p-1);
     769          518 :     if (fpc == 1) { nbtest=0; s++; }
     770              :     else
     771          392 :       if (++nbtest > 40) return 0;
     772          518 :     set_avma(av);
     773              :   }
     774            7 :   return 1;
     775              : }
     776              : 
     777              : static GEN
     778       184688 : dist(GEN e, GEN d, long prec) { return mkvec2(qfr5_dist(e, d, prec), d); }
     779              : /* z a pre-allocated pair [t_REAL, t_INT], D = [t,d] from dist() */
     780              : static void
     781       184688 : dist_set(GEN z, GEN D)
     782              : {
     783       184688 :   affrr(gel(D,1), gel(z,1));
     784       184688 :   affsi(signe(gel(D,2)) < 0? 1: 0, gel(z,2));
     785       184688 : }
     786              : 
     787              : /* Real Quadratic fields */
     788              : 
     789              : static void
     790         5145 : real_relations(struct buch_quad *B, long need, long *pc, long lim, ulong LIMC, GEN mat, GEN C)
     791              : {
     792              :   pari_timer T;
     793         5145 :   long lgsub = lg(B->subFB), prec = B->PRECREG, current = *pc, nbtest=0, s=0;
     794              :   long i, fpc, endcycle, rhoacc, rho;
     795              :   /* in a 2nd phase, don't include FB[current] but run along the cyle
     796              :    * ==> get more units */
     797         5145 :   int first = (current == 0);
     798              :   pari_sp av, av1;
     799         5145 :   GEN d, col, form, form0, form1, ex = cgetg(lgsub, t_VECSMALL);
     800              : 
     801         5145 :   if (DEBUGLEVEL>2) timer_start(&T);
     802         5145 :   if (!current) current = 1;
     803         5145 :   if (lim > need) lim = need;
     804         5145 :   av = avma;
     805              :   for(;;)
     806              :   {
     807       166691 :     if (s >= need) break;
     808       161546 :     if (first && s >= lim) {
     809         2142 :       first = 0;
     810         2142 :       if (DEBUGLEVEL>2) dbg_all(&T, "initial", s, nbtest);
     811              :     }
     812       161546 :     set_avma(av); form = qfr3_random(B, ex);
     813       161546 :     if (!first)
     814       159369 :       form = QFR3_comp(form, qfr3_pf(B->q, B->FB[current]), B->q);
     815       161546 :     av1 = avma;
     816       161546 :     form0 = form; form1 = NULL;
     817       161546 :     endcycle = rhoacc = 0;
     818       161546 :     rho = -1;
     819              : 
     820      1300964 : CYCLE:
     821      1300964 :     if (endcycle || rho > 5000)
     822              :     {
     823           21 :       if (++current > B->KC) current = 1;
     824           21 :       continue;
     825              :     }
     826      1300943 :     if (gc_needed(av,1))
     827              :     {
     828            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"real_relations");
     829            0 :       (void)gc_all(av1, form1? 2: 1, &form, &form1);
     830              :     }
     831      1300943 :     if (rho < 0) rho = 0; /* first time in */
     832              :     else
     833              :     {
     834      1139397 :       form = qfr3_rho(form, B->q); rho++;
     835      1139397 :       rhoacc++;
     836      1139397 :       if (first)
     837       442526 :         endcycle = (absequalii(gel(form,1),gel(form0,1))
     838       221263 :              && equalii(gel(form,2),gel(form0,2)));
     839              :       else
     840              :       {
     841       918134 :         if (absequalii(gel(form,1), gel(form,3))) /* a = -c */
     842              :         {
     843            0 :           if (absequalii(gel(form,1),gel(form0,1)) &&
     844            0 :                   equalii(gel(form,2),gel(form0,2))) continue;
     845            0 :           form = qfr3_rho(form, B->q); rho++;
     846            0 :           rhoacc++;
     847              :         }
     848              :         else
     849       918134 :           { setsigne(form[1],1); setsigne(form[3],-1); }
     850       918176 :         if (equalii(gel(form,1),gel(form0,1)) &&
     851           42 :             equalii(gel(form,2),gel(form0,2))) continue;
     852              :       }
     853              :     }
     854      1300943 :     nbtest++; fpc = factorquad(B,form,B->KC,LIMC);
     855      1300943 :     if (!fpc)
     856              :     {
     857       386778 :       if (DEBUGLEVEL>3) err_printf(".");
     858       386778 :       goto CYCLE;
     859              :     }
     860       914165 :     if (fpc > 1)
     861              :     { /* look for Large Prime relation */
     862       764946 :       long *fpd = largeprime(B,fpc,ex,first? 0: current,rhoacc);
     863              :       ulong b1, b2, p;
     864              :       GEN form2;
     865       764946 :       if (!fpd)
     866              :       {
     867       729477 :         if (DEBUGLEVEL>3) err_printf(".");
     868       729477 :         goto CYCLE;
     869              :       }
     870        35469 :       if (!form1)
     871              :       {
     872        35469 :         form1 = qfr5_factorback(B,ex);
     873        35469 :         if (!first)
     874        35469 :           form1 = QFR5_comp(form1, qfr5_pf(B->q, B->FB[current], prec), B->q);
     875              :       }
     876        35469 :       form1 = qfr5_rho_pow(form1, rho, B->q);
     877        35469 :       rho = 0;
     878              : 
     879        35469 :       form2 = qfr5_factorback(B,fpd);
     880        35469 :       if (fpd[-2])
     881        23709 :         form2 = QFR5_comp(form2, qfr5_pf(B->q, B->FB[fpd[-2]], prec), B->q);
     882        35469 :       form2 = qfr5_rho_pow(form2, fpd[-3], B->q);
     883        35469 :       if (!absequalii(gel(form2,1),gel(form2,3)))
     884              :       {
     885        35469 :         setsigne(form2[1], 1);
     886        35469 :         setsigne(form2[3],-1);
     887              :       }
     888        35469 :       p = fpc << 1;
     889        35469 :       b1 = umodiu(gel(form2,2), p);
     890        35469 :       b2 = umodiu(gel(form1,2), p);
     891        35469 :       if (b1 != b2 && b1+b2 != p) goto CYCLE;
     892              : 
     893        35469 :       col = gel(mat,++s);
     894        35469 :       add_fact(B, col, form1);
     895        35469 :       (void)factorquad(B,form2,B->KC,LIMC);
     896        35469 :       if (b1==b2)
     897              :       {
     898       135100 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += fpd[i]-ex[i];
     899        17626 :         sub_fact(B,col, form2);
     900        17626 :         if (fpd[-2]) col[fpd[-2]]++;
     901        17626 :         d = dist(subii(gel(form1,4),gel(form2,4)),
     902        17626 :                  divrr(gel(form1,5),gel(form2,5)), prec);
     903              :       }
     904              :       else
     905              :       {
     906       136780 :         for (i=1; i<lgsub; i++) col[B->subFB[i]] += -fpd[i]-ex[i];
     907        17843 :         add_fact(B, col, form2);
     908        17843 :         if (fpd[-2]) col[fpd[-2]]--;
     909        17843 :         d = dist(addii(gel(form1,4),gel(form2,4)),
     910        17843 :                  mulrr(gel(form1,5),gel(form2,5)), prec);
     911              :       }
     912        35469 :       if (DEBUGLEVEL>2) err_printf(" %ldP",s);
     913              :     }
     914              :     else
     915              :     { /* standard relation */
     916       149219 :       if (!form1)
     917              :       {
     918       126077 :         form1 = qfr5_factorback(B, ex);
     919       126077 :         if (!first)
     920       123900 :           form1 = QFR5_comp(form1, qfr5_pf(B->q, B->FB[current], prec), B->q);
     921              :       }
     922       149219 :       form1 = qfr5_rho_pow(form1, rho, B->q);
     923       149219 :       rho = 0;
     924              : 
     925       149219 :       col = gel(mat,++s);
     926      1147489 :       for (i=1; i<lgsub; i++) col[B->subFB[i]] = -ex[i];
     927       149219 :       add_fact(B, col, form1);
     928       149219 :       d = dist(gel(form1,4), gel(form1,5), prec);
     929       149219 :       if (DEBUGLEVEL>2) err_printf(" %ld",s);
     930              :     }
     931       184688 :     dist_set(gel(C,s), d);
     932       184688 :     if (first)
     933              :     {
     934        25319 :       if (s >= lim) continue;
     935        23163 :       goto CYCLE;
     936              :     }
     937              :     else
     938              :     {
     939       159369 :       col[current]--;
     940       159369 :       if (++current > B->KC) current = 1;
     941              :     }
     942              :   }
     943         5145 :   if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest);
     944         5145 :   *pc = current;
     945         5145 : }
     946              : 
     947              : static int
     948            7 : real_be_honest(struct buch_quad *B)
     949              : {
     950            7 :   long p, fpc, s = B->KC, nbtest = 0;
     951            7 :   GEN F,F0, ex = cgetg(lg(B->subFB), t_VECSMALL);
     952            7 :   pari_sp av = avma;
     953              : 
     954           28 :   while (s<B->KC2)
     955              :   {
     956           21 :     p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p);
     957           21 :     F = QFR3_comp(qfr3_random(B, ex), qfr3_pf(B->q, p), B->q);
     958           21 :     for (F0 = F;;)
     959              :     {
     960           49 :       fpc = factorquad(B,F,s,p-1);
     961           49 :       if (fpc == 1) { nbtest=0; s++; break; }
     962           28 :       if (++nbtest > 40) return 0;
     963           28 :       F = qfr3_canon(qfr3_rho(F, B->q), B->q);
     964           28 :       if (equalii(gel(F,1),gel(F0,1))
     965            0 :        && equalii(gel(F,2),gel(F0,2))) break;
     966              :     }
     967           21 :     set_avma(av);
     968              :   }
     969            7 :   return 1;
     970              : }
     971              : 
     972              : static GEN
     973        55146 : crabs(GEN a)
     974              : {
     975        55146 :   return signe(real_i(a)) < 0 ? gneg(a): a;
     976              : }
     977              : 
     978              : static GEN
     979        33978 : gcdreal(GEN a,GEN b)
     980              : {
     981        33978 :   if (!signe(real_i(a))) return crabs(b);
     982        33012 :   if (!signe(real_i(b))) return crabs(a);
     983        32897 :   if (expo(real_i(a))<-5) return crabs(b);
     984        12040 :   if (expo(real_i(b))<-5) return crabs(a);
     985         9093 :   a = crabs(a); b = crabs(b);
     986        20019 :   while (expo(real_i(b)) >= -5  && signe(real_i(b)))
     987              :   {
     988              :     long e;
     989        10926 :     GEN r, q = gcvtoi(divrr(real_i(a),real_i(b)),&e);
     990        10926 :     if (e > 0) return NULL;
     991        10926 :     r = gsub(a, gmul(q,b)); a = b; b = r;
     992              :   }
     993         9093 :   return crabs(a);
     994              : }
     995              : 
     996              : static int
     997       159985 : get_R(struct buch_quad *B, GEN C, long sreg, GEN z, GEN *ptR)
     998              : {
     999       159985 :   GEN R = gen_1;
    1000              :   double c;
    1001              :   long i;
    1002       159985 :   if (B->PRECREG)
    1003              :   {
    1004         2982 :     R = crabs(gel(C,1));
    1005        36960 :     for (i=2; i<=sreg; i++)
    1006              :     {
    1007        33978 :       R = gcdreal(gel(C,i), R);
    1008        33978 :       if (!R) return fupb_PRECI;
    1009              :     }
    1010         2982 :     if (gexpo(real_i(R)) <= -3)
    1011              :     {
    1012            0 :       if (DEBUGLEVEL>2) err_printf("regulator is zero.\n");
    1013            0 :       return fupb_RELAT;
    1014              :     }
    1015         2982 :     if (DEBUGLEVEL>2) err_printf("#### Tentative regulator: %Ps\n",R);
    1016              :   }
    1017       159985 :   c = gtodouble(gmul(z, real_i(R)));
    1018       159987 :   if (c < 0.8 || c > 1.3) return fupb_RELAT;
    1019       122365 :   *ptR = R; return fupb_NONE;
    1020              : }
    1021              : 
    1022              : static int
    1023       122364 : quad_be_honest(struct buch_quad *B)
    1024              : {
    1025              :   int r;
    1026       122364 :   if (B->KC2 <= B->KC) return 1;
    1027           14 :   if (DEBUGLEVEL>2)
    1028            0 :     err_printf("be honest for primes from %ld to %ld\n", B->FB[B->KC+1],B->FB[B->KC2]);
    1029           14 :   r = B->PRECREG? real_be_honest(B): imag_be_honest(B);
    1030           14 :   if (DEBUGLEVEL>2) err_printf("\n");
    1031           14 :   return r;
    1032              : }
    1033              : 
    1034              : static GEN
    1035       122592 : Buchquad_i(GEN D, double cbach, double cbach2, long prec)
    1036              : {
    1037       122592 :   const long MAXRELSUP = 20, SFB_MAX = 3, MPQS_THRESHOLD = 60;
    1038              :   pari_timer T;
    1039              :   pari_sp av, av2;
    1040       122592 :   const long RELSUP = 5;
    1041              :   long i, s, current, triv, sfb_trials, nrelsup, nreldep, need, nsubFB, minSFB;
    1042              :   ulong low, high, LIMC0, LIMC, LIMC2, LIMCMAX, cp;
    1043       122592 :   GEN W, cyc, gen, dep, mat, C, extraC, B, R, invhr, h = NULL; /*-Wall*/
    1044              :   double drc, sdrc, lim, LOGD, LOGD2;
    1045              :   GRHcheck_t GRHcheck;
    1046              :   struct qfr_data q;
    1047              :   struct buch_quad BQ;
    1048       122592 :   int FIRST = 1, use_mpqs = 0;
    1049              :   mpqs_handle_t H;
    1050              :   GEN missing_primes;
    1051              : 
    1052       122592 :   check_quaddisc(D, &s, /*junk*/&i, "Buchquad");
    1053       122594 :   R = NULL; /* -Wall */
    1054       122594 :   BQ.q = &q;
    1055       122594 :   q.D = D;
    1056       122594 :   if (s < 0)
    1057              :   {
    1058       120438 :     if (abscmpiu(q.D,4) <= 0)
    1059          217 :       retmkvec4(gen_1, cgetg(1,t_VEC), cgetg(1,t_VEC), gen_1);
    1060       120220 :     prec = BQ.PRECREG = 0;
    1061       120220 :     if (expi(D) >= MPQS_THRESHOLD)
    1062           28 :       use_mpqs = 1;
    1063              :   } else {
    1064         2156 :     BQ.PRECREG = maxss(prec+EXTRAPREC64, nbits2prec(2*expi(q.D) + 128));
    1065              :   }
    1066       122376 :   if (DEBUGLEVEL>2) timer_start(&T);
    1067       122376 :   BQ.primfact   = new_chunk(100);
    1068       122375 :   BQ.exprimfact = new_chunk(100);
    1069       122373 :   BQ.hashtab = (long**) new_chunk(HASHT);
    1070    125418013 :   for (i=0; i<HASHT; i++) BQ.hashtab[i] = NULL;
    1071              : 
    1072       122377 :   drc = fabs(gtodouble(q.D));
    1073       122373 :   LOGD = log(drc);
    1074       122373 :   LOGD2 = LOGD * LOGD;
    1075              : 
    1076       122373 :   sdrc = lim = sqrt(drc);
    1077       122373 :   if (!BQ.PRECREG) lim /= sqrt(3.);
    1078       122373 :   cp = (ulong)exp(sqrt(LOGD*log(LOGD)/8.0));
    1079       122373 :   if (cp < 20) cp = 20;
    1080       122373 :   if (cbach > 6.) {
    1081            0 :     if (cbach2 < cbach) cbach2 = cbach;
    1082            0 :     cbach = 6.;
    1083              :   }
    1084       122373 :   if (cbach < 0.)
    1085            0 :     pari_err_DOMAIN("Buchquad","Bach constant","<",gen_0,dbltor(cbach));
    1086       122373 :   av = avma;
    1087       122373 :   BQ.powsubFB = BQ.subFB = NULL;
    1088       122373 :   minSFB = (expi(D) > 15)? 3: 2;
    1089       122373 :   init_GRHcheck(&GRHcheck, 2, BQ.PRECREG? 2: 0, LOGD);
    1090       122375 :   high = low = LIMC0 = maxss((long)(cbach2*LOGD2), 1);
    1091       122375 :   LIMCMAX = (long)(4.*LOGD2);
    1092              :   /* 97/1223 below to ensure a good enough approximation of residue */
    1093       122375 :   cache_prime_quad(&GRHcheck, expi(D) < 16 ? 97: 1223, D);
    1094      1026863 :   while (!quadGRHchk(D, &GRHcheck, high))
    1095              :   {
    1096       904485 :     low = high;
    1097       904485 :     high *= 2;
    1098              :   }
    1099       904539 :   while (high - low > 1)
    1100              :   {
    1101       782184 :     long test = (low+high)/2;
    1102       782184 :     if (quadGRHchk(D, &GRHcheck, test))
    1103       409522 :       high = test;
    1104              :     else
    1105       372651 :       low = test;
    1106              :   }
    1107       122355 :   if (high == LIMC0+1 && quadGRHchk(D, &GRHcheck, LIMC0))
    1108            0 :     LIMC2 = LIMC0;
    1109              :   else
    1110       122355 :     LIMC2 = high;
    1111       122355 :   if (LIMC2 > LIMCMAX) LIMC2 = LIMCMAX;
    1112       122355 :   LIMC0 = (long)(cbach*LOGD2);
    1113       122355 :   LIMC = cbach ? LIMC0 : LIMC2;
    1114       122355 :   LIMC = maxss(LIMC, nthidealquad(D, 2));
    1115              : 
    1116              : /* LIMC = Max(cbach*(log D)^2, exp(sqrt(log D loglog D) / 8)) */
    1117       122388 : START:
    1118       122388 :   missing_primes = NULL;
    1119              :   do
    1120              :   {
    1121       122483 :     if (!FIRST) LIMC = bnf_increase_LIMC(LIMC,LIMCMAX);
    1122       122483 :     if (DEBUGLEVEL>2 && LIMC > LIMC0)
    1123            0 :       err_printf("%s*** Bach constant: %f\n", FIRST?"":"\n", LIMC/LOGD2);
    1124       122483 :     FIRST = 0; set_avma(av);
    1125       122483 :     guncloneNULL(BQ.subFB);
    1126       122483 :     guncloneNULL(BQ.powsubFB);
    1127       122482 :     clearhash(BQ.hashtab);
    1128       122487 :     if (LIMC < cp) LIMC = cp;
    1129       122487 :     if (LIMC2 < LIMC) LIMC2 = LIMC;
    1130       122487 :     if (BQ.PRECREG) qfr_data_init(q.D, BQ.PRECREG, &q);
    1131              : 
    1132       122487 :     FBquad(&BQ, LIMC2, LIMC, &GRHcheck);
    1133       122484 :     if (DEBUGLEVEL>2) timer_printf(&T, "factor base");
    1134       122484 :     BQ.subFB = subFBquad(&BQ, q.D, lim + 0.5, minSFB);
    1135       122487 :     if (DEBUGLEVEL>2) timer_printf(&T, "subFBquad = %Ps",
    1136              :                                  vecpermute(BQ.FB, BQ.subFB));
    1137       122487 :     nsubFB = lg(BQ.subFB) - 1;
    1138              :   }
    1139       122487 :   while (nsubFB < (expi(D) > 15 ? 3 : 2));
    1140              :   /* invhr = 2^r1 (2pi)^r2 / sqrt(D) w ~ L(chi,1) / hR */
    1141       122390 :   invhr = gmul(dbltor((BQ.PRECREG?2.:M_PI)/sdrc),
    1142              :                compute_invresquad(&GRHcheck, LIMC));
    1143       122383 :   BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1);
    1144       122392 :   if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad");
    1145       122392 :   BQ.limhash = (LIMC & HIGHMASK)? (HIGHBIT>>1): LIMC*LIMC;
    1146              : 
    1147       122392 :   need = BQ.KC + RELSUP - 2;
    1148       122392 :   current = 0;
    1149       122392 :   W = NULL;
    1150       122392 :   sfb_trials = nreldep = nrelsup = 0;
    1151       122392 :   s = nsubFB + RELSUP;
    1152       122392 :   if (use_mpqs)
    1153           28 :     use_mpqs = mpqs_class_init(&H, D, BQ.KC);
    1154       122392 :   av2 = avma;
    1155              : 
    1156              :   do
    1157              :   {
    1158       181416 :     if ((nreldep & 3) == 1 || (nrelsup & 7) == 1) {
    1159        49696 :       if (DEBUGLEVEL>2) err_printf("*** Changing sub factor base\n");
    1160        49696 :       gunclone(BQ.subFB);
    1161        49696 :       gunclone(BQ.powsubFB);
    1162        49696 :       BQ.subFB = gclone(vecslice(BQ.vperm, 1, nsubFB));
    1163        49696 :       BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1);
    1164        49696 :       if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad");
    1165        49696 :       clearhash(BQ.hashtab);
    1166              :     }
    1167       181416 :     if (!use_mpqs) need += 2;
    1168       181416 :     mat    = cgetg(need+1, t_MAT);
    1169       181417 :     extraC = cgetg(need+1, t_VEC);
    1170       181418 :     if (!W) { /* first time */
    1171       122392 :       C = extraC;
    1172       122392 :       triv = trivial_relations(&BQ, mat, C);
    1173       122390 :       if (DEBUGLEVEL>2) err_printf("KC = %ld, need %ld relations\n", BQ.KC, need);
    1174              :     } else {
    1175        59026 :       triv = 0;
    1176        59026 :       if (DEBUGLEVEL>2) err_printf("...need %ld more relations\n", need);
    1177              :     }
    1178       181416 :     if (BQ.PRECREG) {
    1179       189833 :       for (i = triv+1; i<=need; i++) {
    1180       184688 :         gel(mat,i) = zero_zv(BQ.KC);
    1181       184688 :         gel(extraC,i) = mkcomplex(cgetr(BQ.PRECREG), cgeti(3));
    1182              :       }
    1183         5145 :       real_relations(&BQ, need - triv, &current, s,LIMC,mat + triv,extraC + triv);
    1184              :     } else {
    1185      2957510 :       for (i = triv+1; i<=need; i++) {
    1186      2781270 :         gel(mat,i) = zero_zv(BQ.KC);
    1187      2781239 :         gel(extraC,i) = gen_0;
    1188              :       }
    1189       176240 :       if (use_mpqs)
    1190          336 :         mpqs_relations(&BQ, need - triv, &current, LIMC,mat + triv, &H, missing_primes);
    1191              :       else
    1192       175904 :         imag_relations(&BQ, need - triv, &current, LIMC,mat + triv);
    1193              :     }
    1194       181408 :     if (DEBUGLEVEL>2) timer_start(&T);
    1195       181415 :     if (!W)
    1196       122389 :       W = hnfspec_i(mat,BQ.vperm,&dep,&B,&C,nsubFB);
    1197              :     else
    1198        59026 :       W = hnfadd_i(W,BQ.vperm,&dep,&B,&C, mat,extraC);
    1199       181417 :     if (DEBUGLEVEL>2) timer_printf(&T, "hnfadd");
    1200       181417 :     need = BQ.KC - (lg(W)-1) - (lg(B)-1);
    1201       181417 :     (void)gc_all(av2, 4, &W,&C,&B,&dep);
    1202       181419 :     missing_primes = vecslice(BQ.vperm,1,need);
    1203       181419 :     if (need)
    1204              :     {
    1205        21419 :       if (++nreldep > 15 && cbach < 1) goto START;
    1206        21419 :       continue;
    1207              :     }
    1208              : 
    1209       160000 :     h = ZM_det_triangular(W);
    1210       159988 :     if (DEBUGLEVEL>2) err_printf("\n#### Tentative class number: %Ps\n", h);
    1211              : 
    1212       159988 :     switch(get_R(&BQ, C, (lg(C)-1) - (lg(B)-1) - (lg(W)-1), mulir(h,invhr), &R))
    1213              :     {
    1214            0 :       case fupb_PRECI:
    1215            0 :         BQ.PRECREG = precdbl(BQ.PRECREG);
    1216            0 :         FIRST = 1; goto START;
    1217              : 
    1218        37622 :       case fupb_RELAT:
    1219        37622 :         if (++nrelsup > MAXRELSUP)
    1220              :         {
    1221           63 :           if (++sfb_trials > SFB_MAX && cbach <= 1) goto START;
    1222           49 :           if (nsubFB < minss(10,BQ.KC)) nsubFB++;
    1223              :         }
    1224        37608 :         need = minss(BQ.KC, nrelsup);
    1225              :     }
    1226              :   }
    1227       181389 :   while (need);
    1228              :   /* DONE */
    1229       122365 :   if (!quad_be_honest(&BQ)) goto START;
    1230       122364 :   if (DEBUGLEVEL>2) timer_printf(&T, "be honest");
    1231       122364 :   clearhash(BQ.hashtab);
    1232       122378 :   free_GRHcheck(&GRHcheck);
    1233              : 
    1234       122378 :   gen = get_clgp(&BQ,W,&cyc);
    1235       122375 :   gunclone(BQ.subFB);
    1236       122378 :   gunclone(BQ.powsubFB);
    1237       122378 :   if (BQ.PRECREG)
    1238         2156 :     return mkvec5(h, cyc, gen, real_i(R), mpodd(imag_i(R)) ? gen_m1:gen_1);
    1239              :   else
    1240       120222 :     return mkvec4(h, cyc, gen, real_i(R));
    1241              : }
    1242              : GEN
    1243         4424 : Buchquad(GEN D, double c, double c2, long prec)
    1244              : {
    1245         4424 :   pari_sp av = avma;
    1246         4424 :   GEN z = Buchquad_i(D, c, c2, prec);
    1247         4424 :   return gc_GEN(av, z);
    1248              : }
    1249              : 
    1250              : GEN
    1251            0 : buchimag(GEN D, GEN c, GEN c2, GEN REL)
    1252            0 : { (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),0); }
    1253              : 
    1254              : GEN
    1255            0 : buchreal(GEN D, GEN flag, GEN c, GEN c2, GEN REL, long prec) {
    1256            0 :   if (signe(flag)) pari_err_IMPL("narrow class group");
    1257            0 :   (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),prec);
    1258              : }
    1259              : 
    1260              : GEN
    1261         4424 : quadclassunit0(GEN x, long flag, GEN data, long prec)
    1262              : {
    1263              :   long lx;
    1264         4424 :   double c1 = 0.0, c2 = 0.0;
    1265              : 
    1266         4424 :   if (!data) lx=1;
    1267              :   else
    1268              :   {
    1269           28 :     lx = lg(data);
    1270           28 :     if (typ(data)!=t_VEC) pari_err_TYPE("quadclassunit", data);
    1271           28 :     if (lx > 7) pari_err_DIM("quadclassunit [tech vector]");
    1272           28 :     if (lx > 3) lx = 3;
    1273              :   }
    1274         4424 :   switch(lx)
    1275              :   {
    1276           21 :     case 3: c2 = gtodouble(gel(data,2));
    1277           28 :     case 2: c1 = gtodouble(gel(data,1));
    1278              :   }
    1279         4424 :   if (flag) pari_err_IMPL("narrow class group");
    1280         4424 :   return Buchquad(x,c1,c2,prec);
    1281              : }
    1282              : GEN
    1283       113132 : quadclassno(GEN D)
    1284              : {
    1285       113132 :   pari_sp av = avma;
    1286       113132 :   GEN h = abgrp_get_no(Buchquad_i(D, 0, 0, 0));
    1287       113139 :   return icopy_avma(h, av);
    1288              : }
    1289              : long
    1290         5032 : quadclassnos(long D)
    1291              : {
    1292         5032 :   pari_sp av = avma;
    1293         5032 :   long h = itos(abgrp_get_no(Buchquad_i(stoi(D), 0, 0, 0)));
    1294         5032 :   return gc_long(av, h);
    1295              : }
        

Generated by: LCOV version 2.0-1