Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */13#include "pari.h"14#include "paripriv.h"1516#define DEBUGLEVEL DEBUGLEVEL_quadclassunit1718/*******************************************************************/19/* */20/* CLASS GROUP AND REGULATOR (McCURLEY, BUCHMANN) */21/* QUADRATIC FIELDS */22/* */23/*******************************************************************/24/* For largeprime() hashtable. Note that hashed pseudoprimes are odd (unless25* 2 | index), hence the low order bit is not useful. So we hash26* HASHBITS bits starting at bit 1, not bit 0 */27#define HASHBITS 1028static const long HASHT = 1L << HASHBITS;2930static long31hash(long q) { return (q & ((1L << (HASHBITS+1)) - 1)) >> 1; }32#undef HASHBITS3334/* See buch2.c:35* B->subFB contains split p such that \prod p > sqrt(B->Disc)36* B->powsubFB contains powers of forms in B->subFB */37#define RANDOM_BITS 438static const long CBUCH = (1L<<RANDOM_BITS)-1;3940struct buch_quad41{42ulong limhash;43long KC, KC2, PRECREG;44long *primfact, *exprimfact, **hashtab;45GEN FB, numFB;46GEN powsubFB, vperm, subFB, badprim;47struct qfr_data *q;48};4950/*******************************************************************/51/* */52/* Routines related to binary quadratic forms (for internal use) */53/* */54/*******************************************************************/55/* output canonical representative wrt projection Cl^+ --> Cl (a > 0) */56static GEN57qfr3_canon(GEN x, struct qfr_data *S)58{59GEN a = gel(x,1), c = gel(x,3);60if (signe(a) < 0) {61if (absequalii(a,c)) return qfr3_rho(x, S);62setsigne(a, 1);63setsigne(c,-1);64}65return x;66}67static GEN68qfr3_canon_safe(GEN x, struct qfr_data *S)69{70GEN a = gel(x,1), c = gel(x,3);71if (signe(a) < 0) {72if (absequalii(a,c)) return qfr3_rho(x, S);73gel(x,1) = negi(a);74gel(x,3) = negi(c);75}76return x;77}78static GEN79qfr5_canon(GEN x, struct qfr_data *S)80{81GEN a = gel(x,1), c = gel(x,3);82if (signe(a) < 0) {83if (absequalii(a,c)) return qfr5_rho(x, S);84setsigne(a, 1);85setsigne(c,-1);86}87return x;88}89static GEN90QFR5_comp(GEN x,GEN y, struct qfr_data *S)91{ return qfr5_canon(qfr5_comp(x,y,S), S); }92static GEN93QFR3_comp(GEN x, GEN y, struct qfr_data *S)94{ return qfr3_canon(qfr3_comp(x,y,S), S); }9596/* compute rho^n(x) */97static GEN98qfr5_rho_pow(GEN x, long n, struct qfr_data *S)99{100long i;101pari_sp av = avma;102for (i=1; i<=n; i++)103{104x = qfr5_rho(x,S);105if (gc_needed(av,1))106{107if(DEBUGMEM>1) pari_warn(warnmem,"qfr5_rho_pow");108x = gerepilecopy(av, x);109}110}111return gerepilecopy(av, x);112}113114static GEN115qfr5_pf(struct qfr_data *S, long p, long prec)116{117GEN y = primeform_u(S->D,p);118return qfr5_canon(qfr5_red(qfr_to_qfr5(y,prec), S), S);119}120121static GEN122qfr3_pf(struct qfr_data *S, long p)123{124GEN y = primeform_u(S->D,p);125return qfr3_canon(qfr3_red(y, S), S);126}127128#define qfi_pf primeform_u129130/* Warning: ex[0] not set in general */131static GEN132init_form(struct buch_quad *B, GEN ex,133GEN (*comp)(GEN,GEN,struct qfr_data *S))134{135long i, l = lg(B->powsubFB);136GEN F = NULL;137for (i=1; i<l; i++)138if (ex[i])139{140GEN t = gmael(B->powsubFB,i,ex[i]);141F = F? comp(F, t, B->q): t;142}143return F;144}145static GEN146qfr5_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFR5_comp); }147148static GEN149QFI_comp(GEN x, GEN y, struct qfr_data *S) { (void)S; return qfbcomp_i(x,y); }150151static GEN152qfi_factorback(struct buch_quad *B, GEN ex) { return init_form(B, ex, &QFI_comp); }153154static GEN155random_form(struct buch_quad *B, GEN ex,156GEN (*comp)(GEN,GEN, struct qfr_data *S))157{158long i, l = lg(ex);159pari_sp av = avma;160GEN F;161for(;;)162{163for (i=1; i<l; i++) ex[i] = random_bits(RANDOM_BITS);164if ((F = init_form(B, ex, comp))) return F;165set_avma(av);166}167}168static GEN169qfr3_random(struct buch_quad *B,GEN ex){ return random_form(B, ex, &QFR3_comp); }170static GEN171qfi_random(struct buch_quad *B,GEN ex) { return random_form(B, ex, &QFI_comp); }172173/*******************************************************************/174/* */175/* Common subroutines */176/* */177/*******************************************************************/178long179bnf_increase_LIMC(long LIMC, long LIMCMAX)180{181if (LIMC >= LIMCMAX) pari_err_BUG("Buchmann's algorithm");182if (LIMC <= LIMCMAX/40) /* cbach <= 0.3 */183LIMC *= 2;184else if (LIMCMAX < 60) /* \Delta_K <= 9 */185LIMC++;186else187LIMC += LIMCMAX / 60; /* cbach += 0.2 */188if (LIMC > LIMCMAX) LIMC = LIMCMAX;189return LIMC;190}191192/* Is |q| <= p ? */193static int194isless_iu(GEN q, ulong p) {195long l = lgefint(q);196return l==2 || (l == 3 && uel(q,2) <= p);197}198199static long200factorquad(struct buch_quad *B, GEN f, long nFB, ulong limp)201{202ulong X;203long i, lo = 0;204GEN x = gel(f,1), FB = B->FB, P = B->primfact, E = B->exprimfact;205206for (i=1; lgefint(x) > 3; i++)207{208ulong p = uel(FB,i), r;209GEN q = absdiviu_rem(x, p, &r);210if (!r)211{212long k = 0;213do { k++; x = q; q = absdiviu_rem(x, p, &r); } while (!r);214lo++; P[lo] = p; E[lo] = k;215}216if (isless_iu(q,p)) {217if (lgefint(x) == 3) { X = uel(x,2); goto END; }218return 0;219}220if (i == nFB) return 0;221}222X = uel(x,2);223if (X == 1) { P[0] = 0; return 1; }224for (;; i++)225{ /* single precision affair, split for efficiency */226ulong p = uel(FB,i);227ulong q = X / p, r = X % p; /* gcc makes a single div */228if (!r)229{230long k = 0;231do { k++; X = q; q = X / p; r = X % p; } while (!r);232lo++; P[lo] = p; E[lo] = k;233}234if (q <= p) break;235if (i == nFB) return 0;236}237END:238if (X > B->limhash) return 0;239if (X != 1 && X <= limp)240{241if (B->badprim && ugcdui(X, B->badprim) > 1) return 0;242lo++; P[lo] = X; E[lo] = 1;243X = 1;244}245P[0] = lo; return X;246}247248/* Check for a "large prime relation" involving q; q may not be prime */249static long *250largeprime(struct buch_quad *B, long q, GEN ex, long np, long nrho)251{252const long hashv = hash(q);253long *pt, i, l = lg(B->subFB);254255for (pt = B->hashtab[hashv]; ; pt = (long*) pt[0])256{257if (!pt)258{259pt = (long*) pari_malloc((l+3) * sizeof(long));260*pt++ = nrho; /* nrho = pt[-3] */261*pt++ = np; /* np = pt[-2] */262*pt++ = q; /* q = pt[-1] */263pt[0] = (long)B->hashtab[hashv];264for (i=1; i<l; i++) pt[i]=ex[i];265B->hashtab[hashv]=pt; return NULL;266}267if (pt[-1] == q) break;268}269for(i=1; i<l; i++)270if (pt[i] != ex[i]) return pt;271return (pt[-2]==np)? NULL: pt;272}273274static void275clearhash(long **hash)276{277long *pt;278long i;279for (i=0; i<HASHT; i++) {280for (pt = hash[i]; pt; ) {281void *z = (void*)(pt - 3);282pt = (long*) pt[0]; pari_free(z);283}284hash[i] = NULL;285}286}287288/* last prime stored */289ulong290GRH_last_prime(GRHcheck_t *S) { return (S->primes + S->nprimes-1)->p; }291/* ensure that S->primes can hold at least nb primes */292void293GRH_ensure(GRHcheck_t *S, long nb)294{295if (S->maxprimes <= nb)296{297do S->maxprimes *= 2; while (S->maxprimes <= nb);298pari_realloc_ip((void**)&S->primes, S->maxprimes*sizeof(*S->primes));299}300}301/* cache data for all primes up to the LIM */302static void303cache_prime_quad(GRHcheck_t *S, ulong LIM, GEN D)304{305GRHprime_t *pr;306long nb;307308if (S->limp >= LIM) return;309nb = (long)primepi_upper_bound((double)LIM); /* #{p <= LIM} <= nb */310GRH_ensure(S, nb+1); /* room for one extra prime */311for (pr = S->primes + S->nprimes;;)312{313ulong p = u_forprime_next(&(S->P));314pr->p = p;315pr->logp = log((double)p);316pr->dec = (GEN)kroiu(D,p);317S->nprimes++;318pr++;319/* store up to nextprime(LIM) included */320if (p >= LIM) { S->limp = p; break; }321}322}323324static GEN325compute_invresquad(GRHcheck_t *S, long LIMC)326{327pari_sp av = avma;328GEN invres = real_1(DEFAULTPREC);329double limp = log((double)LIMC) / 2;330GRHprime_t *pr;331long i;332for (pr = S->primes, i = S->nprimes; i > 0; pr++, i--)333{334long s = (long)pr->dec;335if (s)336{337ulong p = pr->p;338if (s > 0 || pr->logp <= limp)339/* Both p and P contribute */340invres = mulur(p - s, divru(invres, p));341else if (s<0)342/* Only p contributes */343invres = mulur(p, divru(invres, p - 1));344}345}346return gerepileuptoleaf(av, invres);347}348349/* p | conductor of order of disc D ? */350static int351is_bad(GEN D, ulong p)352{353pari_sp av = avma;354if (p == 2)355{356long r = mod16(D) >> 1;357if (r && signe(D) < 0) r = 8-r;358return (r < 4);359}360return gc_bool(av, dvdii(D, sqru(p))); /* p^2 | D ? */361}362363/* returns the n-th suitable ideal for the factorbase */364static long365nthidealquad(GEN D, long n)366{367pari_sp av = avma;368forprime_t S;369ulong p;370(void)u_forprime_init(&S, 2, ULONG_MAX);371while ((p = u_forprime_next(&S)) && n > 0)372if (!is_bad(D, p) && kroiu(D, p) >= 0) n--;373return gc_long(av, p);374}375376static int377quadGRHchk(GEN D, GRHcheck_t *S, ulong LIMC)378{379double logC = log((double)LIMC), SA = 0, SB = 0;380long i;381382cache_prime_quad(S, LIMC, D);383for (i = 0;; i++)384{385GRHprime_t *pr = S->primes+i;386ulong p = pr->p;387long M;388double logNP, q, A, B;389if (p > LIMC) break;390if ((long)pr->dec < 0)391{392logNP = 2 * pr->logp;393q = 1/(double)p;394}395else396{397logNP = pr->logp;398q = 1/sqrt((double)p);399}400A = logNP * q; B = logNP * A; M = (long)(logC/logNP);401if (M > 1)402{403double inv1_q = 1 / (1-q);404A *= (1 - pow(q, (double) M)) * inv1_q;405B *= (1 - pow(q, (double) M)*(M+1 - M*q)) * inv1_q * inv1_q;406}407if ((long)pr->dec>0) { SA += 2*A;SB += 2*B; } else { SA += A; SB += B; }408if (p == LIMC) break;409}410return GRHok(S, logC, SA, SB);411}412413/* C2 >= C1; create B->FB, B->numFB; set B->badprim. Return L(kro_D, 1) */414static void415FBquad(struct buch_quad *B, ulong C2, ulong C1, GRHcheck_t *S)416{417GEN D = B->q->D;418long i;419pari_sp av;420GRHprime_t *pr;421422cache_prime_quad(S, C2, D);423pr = S->primes;424B->numFB = cgetg(C2+1, t_VECSMALL);425B->FB = cgetg(C2+1, t_VECSMALL);426av = avma;427B->KC = 0; i = 0;428B->badprim = gen_1;429for (;; pr++) /* p <= C2 */430{431ulong p = pr->p;432if (!B->KC && p > C1) B->KC = i;433if (p > C2) break;434switch ((long)pr->dec)435{436case -1: break; /* inert */437case 0: /* ramified */438if (is_bad(D, p)) { B->badprim = muliu(B->badprim, p); break; }439/* fall through */440default: /* split */441i++; B->numFB[p] = i; B->FB[i] = p; break;442}443if (p == C2)444{445if (!B->KC) B->KC = i;446break;447}448}449B->KC2 = i;450setlg(B->FB, B->KC2+1);451if (B->badprim != gen_1)452B->badprim = gerepileuptoint(av, B->badprim);453else454{455B->badprim = NULL; set_avma(av);456}457}458459/* create B->vperm, return B->subFB */460static GEN461subFBquad(struct buch_quad *B, GEN D, double PROD, long minSFB)462{463long i, j, lgsub = 1, ino = 1, lv = B->KC+1;464double prod = 1.;465pari_sp av;466GEN no;467468B->vperm = cgetg(lv, t_VECSMALL);469av = avma;470no = cgetg(lv, t_VECSMALL);471for (j = 1; j < lv; j++)472{473ulong p = uel(B->FB,j);474if (!umodiu(D, p)) no[ino++] = j; /* ramified */475else476{477B->vperm[lgsub++] = j;478prod *= p;479if (lgsub > minSFB && prod > PROD) break;480}481}482/* lgsub >= 1 otherwise quadGRHchk is false */483i = lgsub;484for (j = 1; j < ino;i++,j++) B->vperm[i] = no[j];485for ( ; i < lv; i++) B->vperm[i] = i;486no = gclone(vecslice(B->vperm, 1, lgsub-1));487set_avma(av); return no;488}489490/* assume n >= 1, x[i][j] = B->subFB[i]^j, for j = 1..n */491static GEN492powsubFBquad(struct buch_quad *B, long n)493{494pari_sp av = avma;495long i,j, l = lg(B->subFB);496GEN F, y, x = cgetg(l, t_VEC), D = B->q->D;497498if (B->PRECREG) /* real */499{500for (i=1; i<l; i++)501{502F = qfr5_pf(B->q, B->FB[B->subFB[i]], B->PRECREG);503y = cgetg(n+1, t_VEC); gel(x,i) = y;504gel(y,1) = F;505for (j=2; j<=n; j++) gel(y,j) = QFR5_comp(gel(y,j-1), F, B->q);506}507}508else /* imaginary */509{510for (i=1; i<l; i++)511{512F = qfi_pf(D, B->FB[B->subFB[i]]);513y = cgetg(n+1, t_VEC); gel(x,i) = y;514gel(y,1) = F;515for (j=2; j<=n; j++) gel(y,j) = qfbcomp_i(gel(y,j-1), F);516}517}518x = gclone(x); set_avma(av); return x;519}520521static void522sub_fact(struct buch_quad *B, GEN col, GEN F)523{524GEN b = gel(F,2);525long i;526for (i=1; i<=B->primfact[0]; i++)527{528ulong p = B->primfact[i], k = B->numFB[p];529long e = B->exprimfact[i];530if (umodiu(b, p<<1) > p) e = -e;531col[k] -= e;532}533}534static void535add_fact(struct buch_quad *B, GEN col, GEN F)536{537GEN b = gel(F,2);538long i;539for (i=1; i<=B->primfact[0]; i++)540{541ulong p = B->primfact[i], k = B->numFB[p];542long e = B->exprimfact[i];543if (umodiu(b, p<<1) > p) e = -e;544col[k] += e;545}546}547548static GEN549get_clgp(struct buch_quad *B, GEN W, GEN *ptD)550{551GEN res, init, u1, D = ZM_snf_group(W,NULL,&u1);552long i, j, l = lg(W), c = lg(D);553554res=cgetg(c,t_VEC); init = cgetg(l,t_VEC);555for (i=1; i<l; i++) gel(init,i) = primeform_u(B->q->D, B->FB[B->vperm[i]]);556for (j=1; j<c; j++)557{558GEN g = NULL;559if (signe(B->q->D) > 0)560{561for (i=1; i<l; i++)562{563GEN t, u = gcoeff(u1,i,j);564if (!signe(u)) continue;565t = qfr3_pow(gel(init,i), u, B->q);566g = g? qfr3_comp(g, t, B->q): t;567}568g = qfr3_to_qfr(qfr3_canon_safe(qfr3_red(g, B->q), B->q), B->q->D);569}570else571{572for (i=1; i<l; i++)573{574GEN t, u = gcoeff(u1,i,j);575if (!signe(u)) continue;576t = powgi(gel(init,i), u);577g = g? qfbcomp_i(g, t): t;578}579}580gel(res,j) = g;581}582*ptD = D; return res;583}584585static long586trivial_relations(struct buch_quad *B, GEN mat, GEN C)587{588long i, j = 0;589GEN col, D = B->q->D;590for (i = 1; i <= B->KC; i++)591{ /* ramified prime ==> trivial relation */592if (umodiu(D, B->FB[i])) continue;593col = zero_zv(B->KC);594col[i] = 2; j++;595gel(mat,j) = col;596gel(C,j) = gen_0;597}598return j;599}600601static void602dbg_all(pari_timer *T, const char *phase, long s, long n)603{604err_printf("\n");605timer_printf(T, "%s rel [#rel/#test = %ld/%ld]", phase,s,n);606}607608/* Imaginary Quadratic fields */609610static void611imag_relations(struct buch_quad *B, long need, long *pc, ulong LIMC, GEN mat)612{613pari_timer T;614long lgsub = lg(B->subFB), current = *pc, nbtest = 0, s = 0;615long i, fpc;616pari_sp av;617GEN col, form, ex = cgetg(lgsub, t_VECSMALL);618619if (!current) current = 1;620if (DEBUGLEVEL>2) timer_start(&T);621av = avma;622for(;;)623{624if (s >= need) break;625set_avma(av);626form = qfi_random(B,ex);627form = qfbcomp_i(form, qfi_pf(B->q->D, B->FB[current]));628nbtest++; fpc = factorquad(B,form,B->KC,LIMC);629if (!fpc)630{631if (DEBUGLEVEL>3) err_printf(".");632if ((nbtest & 0xff) == 0 && ++current > B->KC) current = 1;633continue;634}635if (fpc > 1)636{637long *fpd = largeprime(B,fpc,ex,current,0);638ulong b1, b2, p;639GEN form2;640if (!fpd)641{642if (DEBUGLEVEL>3) err_printf(".");643continue;644}645form2 = qfbcomp_i(qfi_factorback(B,fpd), qfi_pf(B->q->D, B->FB[fpd[-2]]));646p = fpc << 1;647b1 = umodiu(gel(form2,2), p);648b2 = umodiu(gel(form,2), p);649if (b1 != b2 && b1+b2 != p) continue;650651col = gel(mat,++s);652add_fact(B,col, form);653(void)factorquad(B,form2,B->KC,LIMC);654if (b1==b2)655{656for (i=1; i<lgsub; i++) col[B->subFB[i]] += fpd[i]-ex[i];657sub_fact(B, col, form2); col[fpd[-2]]++;658}659else660{661for (i=1; i<lgsub; i++) col[B->subFB[i]] += -fpd[i]-ex[i];662add_fact(B, col, form2); col[fpd[-2]]--;663}664if (DEBUGLEVEL>2) err_printf(" %ldP",s);665}666else667{668col = gel(mat,++s);669for (i=1; i<lgsub; i++) col[B->subFB[i]] = -ex[i];670add_fact(B, col, form);671if (DEBUGLEVEL>2) err_printf(" %ld",s);672}673col[current]--;674if (++current > B->KC) current = 1;675}676if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest);677*pc = current;678}679680static int681imag_be_honest(struct buch_quad *B)682{683long p, fpc, s = B->KC, nbtest = 0;684GEN F, ex = cgetg(lg(B->subFB), t_VECSMALL);685pari_sp av = avma;686687while (s<B->KC2)688{689p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p);690F = qfbcomp_i(qfi_pf(B->q->D, p), qfi_random(B, ex));691fpc = factorquad(B,F,s,p-1);692if (fpc == 1) { nbtest=0; s++; }693else694if (++nbtest > 40) return 0;695set_avma(av);696}697return 1;698}699700/* Real Quadratic fields */701702static void703real_relations(struct buch_quad *B, long need, long *pc, long lim, ulong LIMC, GEN mat, GEN C)704{705pari_timer T;706long lgsub = lg(B->subFB), prec = B->PRECREG, current = *pc, nbtest=0, s=0;707long i, fpc, endcycle, rhoacc, rho;708/* in a 2nd phase, don't include FB[current] but run along the cyle709* ==> get more units */710int first = (current == 0);711pari_sp av, av1;712GEN d, col, form, form0, form1, ex = cgetg(lgsub, t_VECSMALL);713714if (DEBUGLEVEL>2) timer_start(&T);715if (!current) current = 1;716if (lim > need) lim = need;717av = avma;718for(;;)719{720if (s >= need) break;721if (first && s >= lim) {722first = 0;723if (DEBUGLEVEL>2) dbg_all(&T, "initial", s, nbtest);724}725set_avma(av); form = qfr3_random(B, ex);726if (!first)727form = QFR3_comp(form, qfr3_pf(B->q, B->FB[current]), B->q);728av1 = avma;729form0 = form; form1 = NULL;730endcycle = rhoacc = 0;731rho = -1;732733CYCLE:734if (endcycle || rho > 5000)735{736if (++current > B->KC) current = 1;737continue;738}739if (gc_needed(av,1))740{741if(DEBUGMEM>1) pari_warn(warnmem,"real_relations");742gerepileall(av1, form1? 2: 1, &form, &form1);743}744if (rho < 0) rho = 0; /* first time in */745else746{747form = qfr3_rho(form, B->q); rho++;748rhoacc++;749if (first)750endcycle = (absequalii(gel(form,1),gel(form0,1))751&& equalii(gel(form,2),gel(form0,2)));752else753{754if (absequalii(gel(form,1), gel(form,3))) /* a = -c */755{756if (absequalii(gel(form,1),gel(form0,1)) &&757equalii(gel(form,2),gel(form0,2))) continue;758form = qfr3_rho(form, B->q); rho++;759rhoacc++;760}761else762{ setsigne(form[1],1); setsigne(form[3],-1); }763if (equalii(gel(form,1),gel(form0,1)) &&764equalii(gel(form,2),gel(form0,2))) continue;765}766}767nbtest++; fpc = factorquad(B,form,B->KC,LIMC);768if (!fpc)769{770if (DEBUGLEVEL>3) err_printf(".");771goto CYCLE;772}773if (fpc > 1)774{ /* look for Large Prime relation */775long *fpd = largeprime(B,fpc,ex,first? 0: current,rhoacc);776ulong b1, b2, p;777GEN form2;778if (!fpd)779{780if (DEBUGLEVEL>3) err_printf(".");781goto CYCLE;782}783if (!form1)784{785form1 = qfr5_factorback(B,ex);786if (!first)787form1 = QFR5_comp(form1, qfr5_pf(B->q, B->FB[current], prec), B->q);788}789form1 = qfr5_rho_pow(form1, rho, B->q);790rho = 0;791792form2 = qfr5_factorback(B,fpd);793if (fpd[-2])794form2 = QFR5_comp(form2, qfr5_pf(B->q, B->FB[fpd[-2]], prec), B->q);795form2 = qfr5_rho_pow(form2, fpd[-3], B->q);796if (!absequalii(gel(form2,1),gel(form2,3)))797{798setsigne(form2[1], 1);799setsigne(form2[3],-1);800}801p = fpc << 1;802b1 = umodiu(gel(form2,2), p);803b2 = umodiu(gel(form1,2), p);804if (b1 != b2 && b1+b2 != p) goto CYCLE;805806col = gel(mat,++s);807add_fact(B, col, form1);808(void)factorquad(B,form2,B->KC,LIMC);809if (b1==b2)810{811for (i=1; i<lgsub; i++) col[B->subFB[i]] += fpd[i]-ex[i];812sub_fact(B,col, form2);813if (fpd[-2]) col[fpd[-2]]++;814d = qfr5_dist(subii(gel(form1,4),gel(form2,4)),815divrr(gel(form1,5),gel(form2,5)), prec);816}817else818{819for (i=1; i<lgsub; i++) col[B->subFB[i]] += -fpd[i]-ex[i];820add_fact(B, col, form2);821if (fpd[-2]) col[fpd[-2]]--;822d = qfr5_dist(addii(gel(form1,4),gel(form2,4)),823mulrr(gel(form1,5),gel(form2,5)), prec);824}825if (DEBUGLEVEL>2) err_printf(" %ldP",s);826}827else828{ /* standard relation */829if (!form1)830{831form1 = qfr5_factorback(B, ex);832if (!first)833form1 = QFR5_comp(form1, qfr5_pf(B->q, B->FB[current], prec), B->q);834}835form1 = qfr5_rho_pow(form1, rho, B->q);836rho = 0;837838col = gel(mat,++s);839for (i=1; i<lgsub; i++) col[B->subFB[i]] = -ex[i];840add_fact(B, col, form1);841d = qfr5_dist(gel(form1,4), gel(form1,5), prec);842if (DEBUGLEVEL>2) err_printf(" %ld",s);843}844affrr(d, gel(C,s));845if (first)846{847if (s >= lim) continue;848goto CYCLE;849}850else851{852col[current]--;853if (++current > B->KC) current = 1;854}855}856if (DEBUGLEVEL>2) dbg_all(&T, "random", s, nbtest);857*pc = current;858}859860static int861real_be_honest(struct buch_quad *B)862{863long p, fpc, s = B->KC, nbtest = 0;864GEN F,F0, ex = cgetg(lg(B->subFB), t_VECSMALL);865pari_sp av = avma;866867while (s<B->KC2)868{869p = B->FB[s+1]; if (DEBUGLEVEL>2) err_printf(" %ld",p);870F = QFR3_comp(qfr3_random(B, ex), qfr3_pf(B->q, p), B->q);871for (F0 = F;;)872{873fpc = factorquad(B,F,s,p-1);874if (fpc == 1) { nbtest=0; s++; break; }875if (++nbtest > 40) return 0;876F = qfr3_canon(qfr3_rho(F, B->q), B->q);877if (equalii(gel(F,1),gel(F0,1))878&& equalii(gel(F,2),gel(F0,2))) break;879}880set_avma(av);881}882return 1;883}884885static GEN886gcdreal(GEN a,GEN b)887{888if (!signe(a)) return mpabs_shallow(b);889if (!signe(b)) return mpabs_shallow(a);890if (typ(a)==t_INT)891{892if (typ(b)==t_INT) return gcdii(a,b);893a = itor(a, lg(b));894}895else if (typ(b)==t_INT)896b = itor(b, lg(a));897if (expo(a)<-5) return absr(b);898if (expo(b)<-5) return absr(a);899a = absr(a); b = absr(b);900while (expo(b) >= -5 && signe(b))901{902long e;903GEN r, q = gcvtoi(divrr(a,b),&e);904if (e > 0) return NULL;905r = subrr(a, mulir(q,b)); a = b; b = r;906}907return mpabs_shallow(a);908}909910static int911get_R(struct buch_quad *B, GEN C, long sreg, GEN z, GEN *ptR)912{913GEN R = gen_1;914double c;915long i;916917if (B->PRECREG)918{919R = mpabs_shallow(gel(C,1));920for (i=2; i<=sreg; i++)921{922R = gcdreal(gel(C,i), R);923if (!R) return fupb_PRECI;924}925if (gexpo(R) <= -3)926{927if (DEBUGLEVEL>2) err_printf("regulator is zero.\n");928return fupb_RELAT;929}930if (DEBUGLEVEL>2) err_printf("#### Tentative regulator: %Ps\n",R);931}932c = gtodouble(gmul(z, R));933if (c < 0.8 || c > 1.3) return fupb_RELAT;934*ptR = R; return fupb_NONE;935}936937static int938quad_be_honest(struct buch_quad *B)939{940int r;941if (B->KC2 <= B->KC) return 1;942if (DEBUGLEVEL>2)943err_printf("be honest for primes from %ld to %ld\n", B->FB[B->KC+1],B->FB[B->KC2]);944r = B->PRECREG? real_be_honest(B): imag_be_honest(B);945if (DEBUGLEVEL>2) err_printf("\n");946return r;947}948949GEN950Buchquad(GEN D, double cbach, double cbach2, long prec)951{952const long MAXRELSUP = 7, SFB_MAX = 3;953pari_timer T;954pari_sp av0 = avma, av, av2;955const long RELSUP = 5;956long i, s, current, triv, sfb_trials, nrelsup, nreldep, need, nsubFB, minSFB;957ulong low, high, LIMC0, LIMC, LIMC2, LIMCMAX, cp;958GEN W, cyc, res, gen, dep, mat, C, extraC, B, R, invhr, h = NULL; /*-Wall*/959double drc, sdrc, lim, LOGD, LOGD2;960GRHcheck_t GRHcheck;961struct qfr_data q;962struct buch_quad BQ;963int FIRST = 1;964965check_quaddisc(D, &s, /*junk*/&i, "Buchquad");966R = NULL; /* -Wall */967BQ.q = &q;968q.D = D;969if (s < 0)970{971if (abscmpiu(q.D,4) <= 0)972{973GEN z = cgetg(5,t_VEC);974gel(z,1) = gel(z,4) = gen_1; gel(z,2) = gel(z,3) = cgetg(1,t_VEC);975return z;976}977prec = BQ.PRECREG = 0;978} else {979BQ.PRECREG = maxss(prec+EXTRAPRECWORD, nbits2prec(2*expi(q.D) + 128));980}981if (DEBUGLEVEL>2) timer_start(&T);982BQ.primfact = new_chunk(100);983BQ.exprimfact = new_chunk(100);984BQ.hashtab = (long**) new_chunk(HASHT);985for (i=0; i<HASHT; i++) BQ.hashtab[i] = NULL;986987drc = fabs(gtodouble(q.D));988LOGD = log(drc);989LOGD2 = LOGD * LOGD;990991sdrc = lim = sqrt(drc);992if (!BQ.PRECREG) lim /= sqrt(3.);993cp = (ulong)exp(sqrt(LOGD*log(LOGD)/8.0));994if (cp < 20) cp = 20;995if (cbach > 6.) {996if (cbach2 < cbach) cbach2 = cbach;997cbach = 6.;998}999if (cbach < 0.)1000pari_err_DOMAIN("Buchquad","Bach constant","<",gen_0,dbltor(cbach));1001av = avma;1002BQ.powsubFB = BQ.subFB = NULL;1003minSFB = (expi(D) > 15)? 3: 2;1004init_GRHcheck(&GRHcheck, 2, BQ.PRECREG? 2: 0, LOGD);1005high = low = LIMC0 = maxss((long)(cbach2*LOGD2), 1);1006LIMCMAX = (long)(6.*LOGD2);1007/* 97/1223 below to ensure a good enough approximation of residue */1008cache_prime_quad(&GRHcheck, expi(D) < 16 ? 97: 1223, D);1009while (!quadGRHchk(D, &GRHcheck, high))1010{1011low = high;1012high *= 2;1013}1014while (high - low > 1)1015{1016long test = (low+high)/2;1017if (quadGRHchk(D, &GRHcheck, test))1018high = test;1019else1020low = test;1021}1022if (high == LIMC0+1 && quadGRHchk(D, &GRHcheck, LIMC0))1023LIMC2 = LIMC0;1024else1025LIMC2 = high;1026if (LIMC2 > LIMCMAX) LIMC2 = LIMCMAX;1027LIMC0 = (long)(cbach*LOGD2);1028LIMC = cbach ? LIMC0 : LIMC2;1029LIMC = maxss(LIMC, nthidealquad(D, 2));10301031/* LIMC = Max(cbach*(log D)^2, exp(sqrt(log D loglog D) / 8)) */1032START:1033do1034{1035if (!FIRST) LIMC = bnf_increase_LIMC(LIMC,LIMCMAX);1036if (DEBUGLEVEL>2 && LIMC > LIMC0)1037err_printf("%s*** Bach constant: %f\n", FIRST?"":"\n", LIMC/LOGD2);1038FIRST = 0; set_avma(av);1039guncloneNULL(BQ.subFB);1040guncloneNULL(BQ.powsubFB);1041clearhash(BQ.hashtab);1042if (LIMC < cp) LIMC = cp;1043if (LIMC2 < LIMC) LIMC2 = LIMC;1044if (BQ.PRECREG) qfr_data_init(q.D, BQ.PRECREG, &q);10451046FBquad(&BQ, LIMC2, LIMC, &GRHcheck);1047if (DEBUGLEVEL>2) timer_printf(&T, "factor base");1048BQ.subFB = subFBquad(&BQ, q.D, lim + 0.5, minSFB);1049if (DEBUGLEVEL>2) timer_printf(&T, "subFBquad = %Ps",1050vecpermute(BQ.FB, BQ.subFB));1051nsubFB = lg(BQ.subFB) - 1;1052}1053while (nsubFB < (expi(D) > 15 ? 3 : 2));1054/* invhr = 2^r1 (2pi)^r2 / sqrt(D) w ~ L(chi,1) / hR */1055invhr = gmul(dbltor((BQ.PRECREG?2.:M_PI)/sdrc),1056compute_invresquad(&GRHcheck, LIMC));1057BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1);1058if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad");1059BQ.limhash = (LIMC & HIGHMASK)? (HIGHBIT>>1): LIMC*LIMC;10601061need = BQ.KC + RELSUP - 2;1062current = 0;1063W = NULL;1064sfb_trials = nreldep = nrelsup = 0;1065s = nsubFB + RELSUP;1066av2 = avma;10671068do1069{1070if ((nreldep & 3) == 1 || (nrelsup & 7) == 1) {1071if (DEBUGLEVEL>2) err_printf("*** Changing sub factor base\n");1072gunclone(BQ.subFB);1073gunclone(BQ.powsubFB);1074BQ.subFB = gclone(vecslice(BQ.vperm, 1, nsubFB));1075BQ.powsubFB = powsubFBquad(&BQ,CBUCH+1);1076if (DEBUGLEVEL>2) timer_printf(&T, "powsubFBquad");1077clearhash(BQ.hashtab);1078}1079need += 2;1080mat = cgetg(need+1, t_MAT);1081extraC = cgetg(need+1, t_VEC);1082if (!W) { /* first time */1083C = extraC;1084triv = trivial_relations(&BQ, mat, C);1085if (DEBUGLEVEL>2) err_printf("KC = %ld, need %ld relations\n", BQ.KC, need);1086} else {1087triv = 0;1088if (DEBUGLEVEL>2) err_printf("...need %ld more relations\n", need);1089}1090if (BQ.PRECREG) {1091for (i = triv+1; i<=need; i++) {1092gel(mat,i) = zero_zv(BQ.KC);1093gel(extraC,i) = cgetr(BQ.PRECREG);1094}1095real_relations(&BQ, need - triv, ¤t, s,LIMC,mat + triv,extraC + triv);1096} else {1097for (i = triv+1; i<=need; i++) {1098gel(mat,i) = zero_zv(BQ.KC);1099gel(extraC,i) = gen_0;1100}1101imag_relations(&BQ, need - triv, ¤t, LIMC,mat + triv);1102}11031104if (!W)1105W = hnfspec_i(mat,BQ.vperm,&dep,&B,&C,nsubFB);1106else1107W = hnfadd_i(W,BQ.vperm,&dep,&B,&C, mat,extraC);1108gerepileall(av2, 4, &W,&C,&B,&dep);1109need = BQ.KC - (lg(W)-1) - (lg(B)-1);1110if (need)1111{1112if (++nreldep > 15 && cbach < 1) goto START;1113continue;1114}11151116h = ZM_det_triangular(W);1117if (DEBUGLEVEL>2) err_printf("\n#### Tentative class number: %Ps\n", h);11181119switch(get_R(&BQ, C, (lg(C)-1) - (lg(B)-1) - (lg(W)-1), mulir(h,invhr), &R))1120{1121case fupb_PRECI:1122BQ.PRECREG = precdbl(BQ.PRECREG);1123FIRST = 1; goto START;11241125case fupb_RELAT:1126if (++nrelsup > MAXRELSUP)1127{1128if (++sfb_trials > SFB_MAX && cbach <= 1) goto START;1129if (nsubFB < minss(10,BQ.KC)) nsubFB++;1130}1131need = minss(BQ.KC, nrelsup);1132}1133}1134while (need);1135/* DONE */1136if (!quad_be_honest(&BQ)) goto START;1137if (DEBUGLEVEL>2) timer_printf(&T, "be honest");1138clearhash(BQ.hashtab);1139free_GRHcheck(&GRHcheck);11401141gen = get_clgp(&BQ,W,&cyc);1142gunclone(BQ.subFB);1143gunclone(BQ.powsubFB);1144res = cgetg(5,t_VEC);1145gel(res,1) = h;1146gel(res,2) = cyc;1147gel(res,3) = gen;1148gel(res,4) = R; return gerepilecopy(av0,res);1149}11501151GEN1152buchimag(GEN D, GEN c, GEN c2, GEN REL)1153{ (void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),0); }11541155GEN1156buchreal(GEN D, GEN flag, GEN c, GEN c2, GEN REL, long prec) {1157if (signe(flag)) pari_err_IMPL("narrow class group");1158(void)REL; return Buchquad(D,gtodouble(c),gtodouble(c2),prec);1159}11601161GEN1162quadclassunit0(GEN x, long flag, GEN data, long prec)1163{1164long lx;1165double c1 = 0.0, c2 = 0.0;11661167if (!data) lx=1;1168else1169{1170lx = lg(data);1171if (typ(data)!=t_VEC) pari_err_TYPE("quadclassunit", data);1172if (lx > 7) pari_err_DIM("quadclassunit [tech vector]");1173if (lx > 3) lx = 3;1174}1175switch(lx)1176{1177case 3: c2 = gtodouble(gel(data,2));1178case 2: c1 = gtodouble(gel(data,1));1179}1180if (flag) pari_err_IMPL("narrow class group");1181return Buchquad(x,c1,c2,prec);1182}118311841185