Annotation of OpenXM_contrib/pari-2.2/src/basemath/buch1.c, Revision 1.2
1.2 ! noro 1: /* $Id: buch1.c,v 1.51 2002/09/05 10:55:35 karim Exp $
1.1 noro 2:
3: Copyright (C) 2000 The PARI group.
4:
5: This file is part of the PARI/GP package.
6:
7: PARI/GP is free software; you can redistribute it and/or modify it under the
8: terms of the GNU General Public License as published by the Free Software
9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
10: ANY WARRANTY WHATSOEVER.
11:
12: Check the License for details. You should have received a copy of it, along
13: with the package; see the file 'COPYING'. If not, write to the Free Software
14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
15:
16: /*******************************************************************/
17: /* */
18: /* CLASS GROUP AND REGULATOR (McCURLEY, BUCHMANN) */
19: /* QUADRATIC FIELDS */
20: /* */
21: /*******************************************************************/
22: #include "pari.h"
23:
24: const int narrow = 0; /* should set narrow = flag in buchquad, but buggy */
25:
1.2 ! noro 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: const int HASHT = 1 << HASHBITS;
! 31:
! 32: static long
! 33: hash(long q) { return (q & ((1 << (HASHBITS+1)) - 1)) >> 1; }
! 34: #undef HASHBITS
! 35:
1.1 noro 36: /* See buch2.c:
37: * precision en digits decimaux=2*(#digits decimaux de Disc)+50
1.2 ! noro 38: * on prendra les p decomposes tels que prod(p)>lim dans la subFB
1.1 noro 39: * LIMC=Max(c.(log(Disc))^2,exp((1/8).sqrt(log(Disc).loglog(Disc))))
40: * LIMC2=Max(6.(log(Disc))^2,exp((1/8).sqrt(log(Disc).loglog(Disc))))
1.2 ! noro 41: * subFB contient les indices des p decomposes tels que prod(p) > sqrt(Disc)
! 42: * powsubFB est la table des puissances des formes dans subFB
1.1 noro 43: */
1.2 ! noro 44:
! 45: #define RANDOM_BITS 4
! 46: static const long CBUCH = (1<<RANDOM_BITS)-1;
! 47: static const long randshift=BITS_IN_RANDOM-1 - RANDOM_BITS;
! 48: #undef RANDOM_BITS
! 49:
! 50: static long KC,KC2,limhash,RELSUP,PRECREG;
! 51: static long *primfact,*exprimfact,*badprim;
! 52: static long *FB,*numFB, **hashtab;
! 53: static GEN powsubFB,vperm,subFB,Disc,sqrtD,isqrtD;
1.1 noro 54:
55: GEN buchquad(GEN D, double c, double c2, long RELSUP0, long flag, long prec);
56: extern GEN roots_to_pol_intern(GEN L, GEN a, long v, int plus);
1.2 ! noro 57: extern GEN colreducemodHNF(GEN x, GEN y, GEN *Q);
! 58: extern GEN quadhilbertreal(GEN D, GEN flag, long prec);
! 59: extern void comp_gen(GEN z,GEN x,GEN y);
! 60: extern GEN codeform5(GEN x, long prec);
! 61: extern GEN comprealform5(GEN x, GEN y, GEN D, GEN sqrtD, GEN isqrtD);
! 62: extern GEN redrealform5(GEN x, GEN D, GEN sqrtD, GEN isqrtD);
! 63: extern GEN rhoreal_aux(GEN x, GEN D, GEN sqrtD, GEN isqrtD);
! 64: extern GEN cgetalloc(GEN x, size_t l, long t);
1.1 noro 65:
66: GEN
67: quadclassunit0(GEN x, long flag, GEN data, long prec)
68: {
69: long lx,RELSUP0;
70: double cbach, cbach2;
71:
72: if (!data) lx=1;
73: else
74: {
75: lx = lg(data);
76: if (typ(data)!=t_VEC || lx > 7)
77: err(talker,"incorrect parameters in quadclassunit");
78: if (lx > 4) lx = 4;
79: }
80: cbach = cbach2 = 0.1; RELSUP0 = 5;
81: switch(lx)
82: {
83: case 4: RELSUP0 = itos((GEN)data[3]);
84: case 3: cbach2 = gtodouble((GEN)data[2]);
85: case 2: cbach = gtodouble((GEN)data[1]);
86: }
87: return buchquad(x,cbach,cbach2,RELSUP0,flag,prec);
88: }
89:
90: /*******************************************************************/
91: /* */
92: /* Hilbert and Ray Class field using CM (Schertz) */
93: /* */
94: /*******************************************************************/
95:
96: int
97: isoforder2(GEN form)
98: {
99: GEN a=(GEN)form[1],b=(GEN)form[2],c=(GEN)form[3];
100: return !signe(b) || absi_equal(a,b) || egalii(a,c);
101: }
102:
103: GEN
104: getallforms(GEN D, long *pth, GEN *ptz)
105: {
106: long d = itos(D), t, b2, a, b, c, h, dover3 = labs(d)/3;
107: GEN z, L=cgetg(labs(d), t_VEC);
108: b2 = b = (d&1); h = 0; z=gun;
109: while (b2 <= dover3)
110: {
111: t = (b2-d)/4;
112: for (a=b?b:1; a*a<=t; a++)
113: if (t%a == 0)
114: {
115: c = t/a; z = mulsi(a,z);
116: L[++h] = (long)qfi(stoi(a),stoi(b),stoi(c));
117: if (b && a != b && a*a != t)
118: L[++h] = (long)qfi(stoi(a),stoi(-b),stoi(c));
119: }
120: b+=2; b2=b*b;
121: }
122: *pth = h; *ptz = z; setlg(L,h+1); return L;
123: }
124:
125: #define MOD4(x) ((((GEN)x)[2])&3)
126: #define MAXL 300
1.2 ! noro 127: /* find P and Q two non principal prime ideals (above p,q) such that
1.1 noro 128: * (pq, z) = 1 [coprime to all class group representatives]
129: * cl(P) = cl(Q) if P has order 2 in Cl(K)
130: * Try to have e = 24 / gcd(24, (p-1)(q-1)) as small as possible */
131: void
132: get_pq(GEN D, GEN z, GEN flag, GEN *ptp, GEN *ptq)
133: {
134: GEN wp=cgetg(MAXL,t_VEC), wlf=cgetg(MAXL,t_VEC), court=icopy(gun);
135: GEN p, form;
136: long i, ell, l = 1, d = itos(D);
137: byteptr diffell = diffptr + 2;
138:
139: if (typ(flag)==t_VEC)
140: { /* assume flag = [p,q]. Check nevertheless */
141: for (i=1; i<lg(flag); i++)
142: {
143: ell = itos((GEN)flag[i]);
144: if (smodis(z,ell) && kross(d,ell) > 0)
145: {
146: form = redimag(primeform(D,(GEN)flag[i],0));
147: if (!gcmp1((GEN)form[1])) {
148: wp[l] = flag[i];
149: l++; if (l == 3) break;
150: }
151: }
152: }
153: if (l<3) err(talker,"[quadhilbert] incorrect values in flag: %Z", flag);
154: *ptp = (GEN)wp[1];
155: *ptq = (GEN)wp[2]; return;
156: }
157:
158: ell = 3;
159: while (l < 3 || ell<=MAXL)
160: {
1.2 ! noro 161: NEXT_PRIME_VIADIFF_CHECK(ell, diffell);
1.1 noro 162: if (smodis(z,ell) && kross(d,ell) > 0)
163: {
164: court[2]=ell; form = redimag(primeform(D,court,0));
165: if (!gcmp1((GEN)form[1])) {
166: wp[l] = licopy(court);
167: wlf[l] = (long)form; l++;
168: }
169: }
170: }
171: setlg(wp,l); setlg(wlf,l);
172:
173: for (i=1; i<l; i++)
174: if (smodis((GEN)wp[i],3) == 1) break;
175: if (i==l) i = 1;
176: p = (GEN)wp[i]; form = (GEN)wlf[i];
177: i = l;
178: if (isoforder2(form))
179: {
180: long oki = 0;
181: for (i=1; i<l; i++)
182: if (gegal((GEN)wlf[i],form))
183: {
184: if (MOD4(p) == 1 || MOD4(wp[i]) == 1) break;
185: if (!oki) oki = i; /* not too bad, still e = 2 */
186: }
187: if (i==l) i = oki;
188: if (!i) err(bugparier,"quadhilbertimag (can't find p,q)");
189: }
190: else
191: {
192: if (MOD4(p) == 3)
193: {
194: for (i=1; i<l; i++)
195: if (MOD4(wp[i]) == 1) break;
196: }
197: if (i==l) i = 1;
198: }
199: *ptp = p;
200: *ptq = (GEN)wp[i];
201: }
202: #undef MAXL
203:
204: static GEN
205: gpq(GEN form, GEN p, GEN q, long e, GEN sqd, GEN u, long prec)
206: {
207: GEN a2 = shifti((GEN)form[1], 1);
208: GEN b = (GEN)form[2], p1,p2,p3,p4;
209: GEN w = lift(chinois(gmodulcp(negi(b),a2), u));
210: GEN al = cgetg(3,t_COMPLEX);
211: al[1] = lneg(gdiv(w,a2));
212: al[2] = ldiv(sqd,a2);
213: p1 = trueeta(gdiv(al,p),prec);
214: p2 = egalii(p,q)? p1: trueeta(gdiv(al,q),prec);
215: p3 = trueeta(gdiv(al,mulii(p,q)),prec);
216: p4 = trueeta(al,prec);
217: return gpowgs(gdiv(gmul(p1,p2),gmul(p3,p4)), e);
218: }
219:
220: /* returns an equation for the Hilbert class field of the imaginary
221: * quadratic field of discriminant D if flag=0, a vector of
222: * two-component vectors [form,g(form)] where g() is the root of the equation
223: * if flag is non-zero.
224: */
225: static GEN
226: quadhilbertimag(GEN D, GEN flag)
227: {
1.2 ! noro 228: long h, i, e, prec;
! 229: gpmem_t av=avma;
1.1 noro 230: GEN z,L,P,p,q,qfp,qfq,up,uq,u;
231: int raw = ((typ(flag)==t_INT && signe(flag)));
232:
1.2 ! noro 233: if (DEBUGLEVEL>=2) (void)timer2();
1.1 noro 234: if (gcmpgs(D,-11) >= 0) return polx[0];
235: L = getallforms(D,&h,&z);
236: if (DEBUGLEVEL>=2) msgtimer("class number = %ld",h);
237: if (h == 1) { avma=av; return polx[0]; }
238:
239: get_pq(D, z, flag, &p, &q);
240: e = 24 / cgcd((smodis(p,24)-1) * (smodis(q,24)-1), 24);
241: if(DEBUGLEVEL>=2) fprintferr("p = %Z, q = %Z, e = %ld\n",p,q,e);
242: qfp = primeform(D,p,0); up = gmodulcp((GEN)qfp[2],shifti(p,1));
243: if (egalii(p,q))
244: {
245: u = (GEN)compimagraw(qfp,qfp)[2];
246: u = gmodulcp(u, shifti(mulii(p,q),1));
247: }
248: else
249: {
250: qfq = primeform(D,q,0); uq = gmodulcp((GEN)qfq[2],shifti(q,1));
251: u = chinois(up,uq);
252: }
253: prec = raw? DEFAULTPREC: 3;
254: for(;;)
255: {
1.2 ! noro 256: long ex, exmax = 0;
! 257: gpmem_t av0 = avma;
1.1 noro 258: GEN lead, sqd = gsqrt(negi(D),prec);
1.2 ! noro 259: P = cgetg(h+1,t_VEC);
1.1 noro 260: for (i=1; i<=h; i++)
261: {
262: GEN v, s = gpq((GEN)L[i], p, q, e, sqd, u, prec);
263: if (raw)
264: {
265: v = cgetg(3,t_VEC); P[i] = (long)v;
266: v[1] = L[i];
267: v[2] = (long)s;
268: }
269: else P[i] = (long)s;
1.2 ! noro 270: ex = gexpo(s); if (ex > 0) exmax += ex;
1.1 noro 271: }
272: if (DEBUGLEVEL>=2) msgtimer("roots");
273: if (raw) { P = gcopy(P); break; }
274: /* to avoid integer overflow (1 + 0.) */
275: lead = (exmax < bit_accuracy(prec))? gun: realun(prec);
276:
277: P = greal(roots_to_pol_intern(lead,P,0,0));
278: P = grndtoi(P,&exmax);
279: if (DEBUGLEVEL>=2) msgtimer("product, error bits = %ld",exmax);
280: if (exmax <= -10)
281: {
282: if (typ(flag)==t_VEC && !issquarefree(P)) { avma=av; return gzero; }
283: break;
284: }
285: avma = av0; prec += (DEFAULTPREC-2) + (1 + (exmax >> TWOPOTBITS_IN_LONG));
286: if (DEBUGLEVEL) err(warnprec,"quadhilbertimag",prec);
287: }
288: return gerepileupto(av,P);
289: }
290:
291: GEN
292: quadhilbert(GEN D, GEN flag, long prec)
293: {
294: if (!flag) flag = gzero;
295: if (typ(D)!=t_INT)
296: {
297: D = checkbnf(D);
298: if (degpol(gmael(D,7,1)) != 2)
299: err(talker,"not a polynomial of degree 2 in quadhilbert");
300: D=gmael(D,7,3);
301: }
302: else
303: {
304: if (!isfundamental(D))
305: err(talker,"quadhilbert needs a fundamental discriminant");
306: }
307: return (signe(D)>0)? quadhilbertreal(D,flag,prec)
308: : quadhilbertimag(D,flag);
309: }
310:
311: /* AUXILLIARY ROUTINES FOR QUADRAYIMAGWEI */
312: #define to_approx(nf,a) ((GEN)gmul(gmael((nf),5,1), (a))[1])
313:
314: /* Z-basis for a (over C) */
315: static GEN
316: get_om(GEN nf, GEN a)
317: {
318: GEN om = cgetg(3,t_VEC);
319: om[1] = (long)to_approx(nf,(GEN)a[2]);
320: om[2] = (long)to_approx(nf,(GEN)a[1]);
321: return om;
322: }
323:
324: /* Compute all elts in class group G = [|G|,c,g], c=cyclic factors, g=gens.
325: * Set list[j + 1] = g1^e1...gk^ek where j is the integer
326: * ek + ck [ e(k-1) + c(k-1) [... + c2 [e1]]...] */
327: static GEN
1.2 ! noro 328: getallelts(GEN bnr)
1.1 noro 329: {
1.2 ! noro 330: GEN nf,G,C,c,g, *list, **pows, *gk;
1.1 noro 331: long lc,i,j,k,no;
332:
1.2 ! noro 333: nf = checknf(bnr);
! 334: G = (GEN)bnr[5];
! 335:
1.1 noro 336: no = itos((GEN)G[1]);
337: c = (GEN)G[2];
338: g = (GEN)G[3]; lc = lg(c)-1;
339: list = (GEN*) cgetg(no+1,t_VEC);
340: if (!lc)
341: {
342: list[1] = idealhermite(nf,gun);
343: return (GEN)list;
344: }
345: pows = (GEN**)cgetg(lc+1,t_VEC);
346: c = dummycopy(c); settyp(c, t_VECSMALL);
347: for (i=1; i<=lc; i++)
348: {
349: c[i] = k = itos((GEN)c[i]);
350: gk = (GEN*)cgetg(k, t_VEC); gk[1] = (GEN)g[i];
1.2 ! noro 351: for (j=2; j<k; j++)
! 352: gk[j] = idealmodidele(bnr, idealmul(nf, gk[j-1], gk[1]));
1.1 noro 353: pows[i] = gk; /* powers of g[i] */
354: }
355:
1.2 ! noro 356: C = cgetg(lc+1, t_VECSMALL); C[1] = c[lc];
1.1 noro 357: for (i=2; i<=lc; i++) C[i] = C[i-1] * c[lc-i+1];
358: /* C[i] = c(k-i+1) * ... * ck */
359: /* j < C[i+1] <==> j only involves g(k-i)...gk */
360: i = 1; list[1] = 0; /* dummy */
361: for (j=1; j < C[1]; j++)
362: list[j + 1] = pows[lc][j];
363: for ( ; j<no; j++)
364: {
365: GEN p1,p2;
366: if (j == C[i+1]) i++;
1.2 ! noro 367: p2 = pows[lc-i][j/C[i]];
! 368: p1 = list[j%C[i] + 1];
! 369: if (p1) p2 = idealmodidele(bnr, idealmul(nf,p2,p1));
1.1 noro 370: list[j + 1] = p2;
371: }
372: list[1] = idealhermite(nf,gun);
373: return (GEN)list;
374: }
375:
376: /* x quadratic integer (approximate), recognize it. If error return NULL */
377: static GEN
378: findbezk(GEN nf, GEN x)
379: {
380: GEN a,b, M = gmael(nf,5,1), y = cgetg(3, t_COL), u = gcoeff(M,1,2);
381: long ea,eb;
382:
383: b = grndtoi(gdiv(gimag(x), gimag(u)), &eb);
384: a = grndtoi(greal(gsub(x, gmul(b,u))),&ea);
385: if (ea>-20 || eb>-20) return NULL;
386: if (!signe(b)) return a;
387: y[1] = (long)a;
388: y[2] = (long)b; return basistoalg(nf,y);
389: }
390:
391: static GEN
392: findbezk_pol(GEN nf, GEN x)
393: {
394: long i, lx = lgef(x);
395: GEN y = cgetg(lx,t_POL);
396: for (i=2; i<lx; i++)
397: if (! (y[i] = (long)findbezk(nf,(GEN)x[i])) ) return NULL;
398: y[1] = x[1]; return y;
399: }
400:
401: GEN
402: form_to_ideal(GEN x)
403: {
404: long tx = typ(x);
405: GEN b,c, y = cgetg(3, t_MAT);
406: if (tx != t_QFR && tx != t_QFI) err(typeer,"form_to_ideal");
407: c = cgetg(3,t_COL); y[1] = (long)c;
408: c[1] = x[1]; c[2] = zero;
409: c = cgetg(3,t_COL); y[2] = (long)c;
410: b = negi((GEN)x[2]);
411: if (mpodd(b)) b = addis(b,1);
412: c[1] = lshifti(b,-1); c[2] = un; return y;
413: }
414:
415: /* P as output by quadhilbertimag, convert forms to ideals */
416: static void
417: convert_to_id(GEN P)
418: {
419: long i,l = lg(P);
420: for (i=1; i<l; i++)
421: {
422: GEN p1 = (GEN)P[i];
423: p1[1] = (long)form_to_ideal((GEN)p1[1]);
424: }
425: }
426:
427: /* P approximation computed at initial precision prec. Compute needed prec
428: * to know P with 1 word worth of trailing decimals */
429: static long
430: get_prec(GEN P, long prec)
431: {
432: long k = gprecision(P);
433: if (k == 3) return (prec<<1)-2; /* approximation not trustworthy */
434: k = prec - k; /* lost precision when computing P */
435: if (k < 0) k = 0;
436: k += MEDDEFAULTPREC + (gexpo(P) >> TWOPOTBITS_IN_LONG);
437: if (k <= prec) k = (prec<<1)-2; /* dubious: old prec should have worked */
438: return k;
439: }
440:
441: /* AUXILLIARY ROUTINES FOR QUADRAYSIGMA */
442:
443: /* Compute data for ellphist */
444: static GEN
445: ellphistinit(GEN om, long prec)
446: {
447: GEN p1,res,om1b,om2b, om1 = (GEN)om[1], om2 = (GEN)om[2];
448:
449: if (gsigne(gimag(gdiv(om1,om2))) < 0)
450: {
1.2 ! noro 451: p1 = om1; om1 = om2; om2 = p1;
! 452: om = cgetg(3,t_VEC);
! 453: om[1] = (long)om1;
! 454: om[2] = (long)om2;
1.1 noro 455: }
456: om1b = gconj(om1);
457: om2b = gconj(om2); res = cgetg(4,t_VEC);
458: res[1] = ldivgs(elleisnum(om,2,0,prec),12);
459: res[2] = ldiv(PiI2(prec), gmul(om2, gimag(gmul(om1b,om2))));
460: res[3] = (long)om2b; return res;
461: }
462:
463: /* Computes log(phi^*(z,om)), using res computed by ellphistinit */
464: static GEN
465: ellphist(GEN om, GEN res, GEN z, long prec)
466: {
467: GEN u = gimag(gmul(z, (GEN)res[3]));
468: GEN zst = gsub(gmul(u, (GEN)res[2]), gmul(z,(GEN)res[1]));
469: return gsub(ellsigma(om,z,1,prec),gmul2n(gmul(z,zst),-1));
470: }
471:
472: /* Computes phi^*(la,om)/phi^*(1,om) where (1,om) is an oriented basis of the
473: ideal gf*gc^{-1} */
474: static GEN
475: computeth2(GEN om, GEN la, long prec)
476: {
477: GEN p1,p2,res = ellphistinit(om,prec);
478:
479: p1 = gsub(ellphist(om,res,la,prec), ellphist(om,res,gun,prec));
480: p2 = gimag(p1);
481: if (gexpo(greal(p1))>20 || gexpo(p2)> bit_accuracy(min(prec,lg(p2)))-10)
482: return NULL;
483: return gexp(p1,prec);
484: }
485:
486: /* Computes P_2(X)=polynomial in Z_K[X] closest to prod_gc(X-th2(gc)) where
487: the product is over the ray class group bnr.*/
488: static GEN
489: computeP2(GEN bnr, GEN la, int raw, long prec)
490: {
1.2 ! noro 491: long clrayno, i, first = 1;
! 492: gpmem_t av=avma, av2;
1.1 noro 493: GEN listray,P0,P,f,lanum, nf = checknf(bnr);
1.2 ! noro 494:
1.1 noro 495: f = gmael3(bnr,2,1,1);
496: if (typ(la) != t_COL) la = algtobasis(nf,la);
1.2 ! noro 497: listray = getallelts(bnr);
1.1 noro 498: clrayno = lg(listray)-1; av2 = avma;
499: PRECPB:
500: if (!first)
501: {
502: if (DEBUGLEVEL) err(warnprec,"computeP2",prec);
503: nf = gerepileupto(av2, nfnewprec(checknf(bnr),prec));
504: }
505: first = 0; lanum = to_approx(nf,la);
506: P = cgetg(clrayno+1,t_VEC);
507: for (i=1; i<=clrayno; i++)
508: {
509: GEN om = get_om(nf, idealdiv(nf,f,(GEN)listray[i]));
510: GEN v, s = computeth2(om,lanum,prec);
511: if (!s) { prec = (prec<<1)-2; goto PRECPB; }
512: if (raw)
513: {
514: v = cgetg(3,t_VEC); P[i] = (long)v;
515: v[1] = (long)listray[i];
516: v[2] = (long)s;
517: }
518: else P[i] = (long)s;
519: }
520: if (!raw)
521: {
522: P0 = roots_to_pol(P, 0);
523: P = findbezk_pol(nf, P0);
524: if (!P) { prec = get_prec(P0, prec); goto PRECPB; }
525: }
526: return gerepilecopy(av, P);
527: }
528:
529: #define nexta(a) (a>0 ? -a : 1-a)
530: static GEN
531: do_compo(GEN x, GEN y)
532: {
533: long a, ph = degpol(y);
534: GEN z;
1.2 ! noro 535: y = gmul(gpowgs(polx[0],ph), gsubst(y,0,gdiv(polx[MAXVARN],polx[0])));
1.1 noro 536: for (a = 0;; a = nexta(a))
537: {
538: if (a) x = gsubst(x, 0, gaddsg(a, polx[0]));
539: z = subres(x,y);
540: z = gsubst(z, MAXVARN, polx[0]);
541: if (issquarefree(z)) return z;
542: }
543: }
544: #undef nexta
545:
546: static GEN
547: galoisapplypol(GEN nf, GEN s, GEN x)
548: {
549: long i, lx = lg(x);
550: GEN y = cgetg(lx,t_POL);
551:
552: for (i=2; i<lx; i++) y[i] = (long)galoisapply(nf,s,(GEN)x[i]);
553: y[1] = x[1]; return y;
554: }
555:
556: /* x quadratic, write it as ua + v, u,v rational */
557: static GEN
558: findquad(GEN a, GEN x, GEN p)
559: {
1.2 ! noro 560: long tu, tv;
! 561: gpmem_t av = avma;
1.1 noro 562: GEN u,v;
563: if (typ(x) == t_POLMOD) x = (GEN)x[2];
564: if (typ(a) == t_POLMOD) a = (GEN)a[2];
565: u = poldivres(x, a, &v);
566: u = simplify(u); tu = typ(u);
567: v = simplify(v); tv = typ(v);
568: if (!is_scalar_t(tu) || !is_scalar_t(tv))
569: err(talker, "incorrect data in findquad");
570: x = v;
571: if (!gcmp0(u)) x = gadd(gmul(u, polx[varn(a)]), x);
572: if (typ(x) == t_POL) x = gmodulcp(x,p);
573: return gerepileupto(av, x);
574: }
575:
576: static GEN
577: findquad_pol(GEN nf, GEN a, GEN x)
578: {
579: long i, lx = lg(x);
580: GEN p = (GEN)nf[1], y = cgetg(lx,t_POL);
581: for (i=2; i<lx; i++) y[i] = (long)findquad(a, (GEN)x[i], p);
582: y[1] = x[1]; return y;
583: }
584:
585: static GEN
586: compocyclo(GEN nf, long m, long d, long prec)
587: {
588: GEN sb,a,b,s,p1,p2,p3,res,polL,polLK,nfL, D = (GEN)nf[3];
589: long ell,vx;
590:
591: p1 = quadhilbertimag(D, gzero);
592: p2 = cyclo(m,0);
593: if (d==1) return do_compo(p1,p2);
594:
595: ell = m&1 ? m : (m>>2);
596: if (!cmpsi(-ell,D)) /* ell = |D| */
597: {
598: p2 = gcoeff(nffactor(nf,p2),1,1);
599: return do_compo(p1,p2);
600: }
601: if (ell%4 == 3) ell = -ell;
602: /* nf = K = Q(a), L = K(b) quadratic extension = Q(t) */
603: polLK = quadpoly(stoi(ell)); /* relative polynomial */
604: res = rnfequation2(nf, polLK);
605: vx = varn(nf[1]);
606: polL = gsubst((GEN)res[1],0,polx[vx]); /* = charpoly(t) */
607: a = gsubst(lift((GEN)res[2]), 0,polx[vx]);
608: b = gsub(polx[vx], gmul((GEN)res[3], a));
609: nfL = initalg(polL,prec);
610: p1 = gcoeff(nffactor(nfL,p1),1,1);
611: p2 = gcoeff(nffactor(nfL,p2),1,1);
612: p3 = do_compo(p1,p2); /* relative equation over L */
613: /* compute non trivial s in Gal(L / K) */
614: sb= gneg(gadd(b, truecoeff(polLK,1))); /* s(b) = Tr(b) - b */
615: s = gadd(polx[vx], gsub(sb, b)); /* s(t) = t + s(b) - b */
616: p3 = gmul(p3, galoisapplypol(nfL, s, p3));
617: return findquad_pol(nf, a, p3);
618: }
619:
620: /* I integral ideal in HNF. (x) = I, x small in Z ? */
621: static long
622: isZ(GEN I)
623: {
624: GEN x = gcoeff(I,1,1);
625: if (signe(gcoeff(I,1,2)) || !egalii(x, gcoeff(I,2,2))) return 0;
626: return is_bigint(x)? -1: itos(x);
627: }
628:
629: /* Treat special cases directly. return NULL if not special case */
630: static GEN
631: treatspecialsigma(GEN nf, GEN gf, int raw, long prec)
632: {
633: GEN p1,p2,tryf, D = (GEN)nf[3];
634: long Ds,fl,i;
635:
636: if (raw)
637: err(talker,"special case in Schertz's theorem. Odd flag meaningless");
638: i = isZ(gf);
639: if (cmpis(D,-3)==0)
640: {
641: if (i == 4 || i == 5 || i == 7) return cyclo(i,0);
642: if (cmpis(gcoeff(gf,1,1), 9) || cmpis(content(gf),3)) return NULL;
643: p1 = (GEN)nfroots(nf,cyclo(3,0))[1]; /* f = P_3^3 */
644: return gadd(gpowgs(polx[0],3), p1); /* x^3+j */
645: }
646: if (cmpis(D,-4)==0)
647: {
648: if (i == 3 || i == 5) return cyclo(i,0);
649: if (i != 4) return NULL;
650: p1 = (GEN)nfroots(nf,cyclo(4,0))[1];
651: return gadd(gpowgs(polx[0],2), p1); /* x^2+i */
652: }
653: Ds = smodis(D,48);
654: if (i)
655: {
656: if (i==2 && Ds%16== 8) return compocyclo(nf, 4,1,prec);
657: if (i==3 && Ds% 3== 1) return compocyclo(nf, 3,1,prec);
658: if (i==4 && Ds% 8== 1) return compocyclo(nf, 4,1,prec);
659: if (i==6 && Ds ==40) return compocyclo(nf,12,1,prec);
660: return NULL;
661: }
662:
1.2 ! noro 663: p1 = gcoeff(gf,1,1); /* integer > 0 */
1.1 noro 664: p2 = gcoeff(gf,2,2);
665: if (gcmp1(p2)) { fl = 0; tryf = p1; }
666: else {
667: if (Ds % 16 != 8 || !egalii(content(gf),gdeux)) return NULL;
668: fl = 1; tryf = shifti(p1,-1);
669: }
1.2 ! noro 670: /* tryf integer > 0 */
! 671: if (cmpis(tryf, 3) <= 0 || signe(resii(D, tryf)) || !isprime(tryf))
1.1 noro 672: return NULL;
673:
674: i = itos(tryf); if (fl) i *= 4;
675: return compocyclo(nf,i,2,prec);
676: }
677:
678: static GEN
679: getallrootsof1(GEN bnf)
680: {
681: GEN z, u, nf = checknf(bnf), racunit = gmael3(bnf,8,4,2);
682: long i, n = itos(gmael3(bnf,8,4,1));
683:
684: u = cgetg(n+1, t_VEC);
685: z = basistoalg(nf, racunit);
686: for (i=1; ; i++)
687: {
688: u[i] = (long)algtobasis(nf,z);
689: if (i == n) return u;
690: z = gmul(z, racunit);
691: }
692: }
693:
694: /* Compute ray class field polynomial using sigma; if raw=1, pairs
695: [ideals,roots] are given instead so that congruence subgroups can be used */
696: static GEN
697: quadrayimagsigma(GEN bnr, int raw, long prec)
698: {
699: GEN allf,bnf,nf,pol,w,f,la,P,labas,lamodf,u;
700: long a,b,f2,i,lu;
701:
702: allf = conductor(bnr,gzero,2); bnr = (GEN)allf[2];
703: f = gmael(allf,1,1);
704: bnf= (GEN)bnr[1];
705: nf = (GEN)bnf[7];
706: pol= (GEN)nf[1];
707: if (gcmp1(gcoeff(f,1,1))) /* f = 1 ? */
708: {
709: P = quadhilbertimag((GEN)nf[3], stoi(raw));
710: if (raw) convert_to_id(P);
711: return gcopy(P);
712: }
713: P = treatspecialsigma(nf,f,raw,prec);
714: if (P) return P;
715:
716: w = gmodulcp(polx[varn(pol)], pol);
717: f2 = 2 * itos(gcoeff(f,1,1));
718: u = getallrootsof1(bnf); lu = lg(u);
719: for (i=1; i<lu; i++)
1.2 ! noro 720: u[i] = (long)colreducemodHNF((GEN)u[i], f, NULL); /* roots of 1, mod f */
1.1 noro 721: if (DEBUGLEVEL>1)
722: fprintferr("quadray: looking for [a,b] != unit mod 2f\n[a,b] = ");
723: for (a=0; a<f2; a++)
724: for (b=0; b<f2; b++)
725: {
726: la = gaddgs(gmulsg(a,w),b);
727: if (smodis(gnorm(la), f2) != 1) continue;
728: if (DEBUGLEVEL>1) fprintferr("[%ld,%ld] ",a,b);
729:
730: labas = algtobasis(nf, la);
1.2 ! noro 731: lamodf = colreducemodHNF(labas, f, NULL);
1.1 noro 732: for (i=1; i<lu; i++)
733: if (gegal(lamodf, (GEN)u[i])) break;
734: if (i < lu) continue; /* la = unit mod f */
735: if (DEBUGLEVEL)
736: {
737: if (DEBUGLEVEL>1) fprintferr("\n");
738: fprintferr("lambda = %Z\n",la);
739: }
740: return computeP2(bnr,labas,raw,prec);
741: }
742: err(bugparier,"quadrayimagsigma");
743: return NULL;
744: }
745:
746: GEN
747: quadray(GEN D, GEN f, GEN flag, long prec)
748: {
749: GEN bnr,y,p1,pol,bnf,lambda;
1.2 ! noro 750: long raw;
! 751: gpmem_t av = avma;
1.1 noro 752:
753: if (!flag) flag = gzero;
754: if (typ(flag)==t_INT) lambda = NULL;
755: else
756: {
757: if (typ(flag)!=t_VEC || lg(flag)!=3) err(flagerr,"quadray");
758: lambda = (GEN)flag[1]; flag = (GEN)flag[2];
759: if (typ(flag)!=t_INT) err(flagerr,"quadray");
760: }
761: if (typ(D)!=t_INT)
762: {
763: bnf = checkbnf(D);
764: if (degpol(gmael(bnf,7,1)) != 2)
765: err(talker,"not a polynomial of degree 2 in quadray");
766: D=gmael(bnf,7,3);
767: }
768: else
769: {
770: if (!isfundamental(D))
771: err(talker,"quadray needs a fundamental discriminant");
772: pol = quadpoly(D); setvarn(pol, fetch_user_var("y"));
773: bnf = bnfinit0(pol,signe(D)>0?1:0,NULL,prec);
774: }
775: raw = (mpodd(flag) && signe(D) < 0);
776: bnr = bnrinit0(bnf,f,1);
777: if (gcmp1(gmael(bnr,5,1)))
778: {
779: avma = av; if (!raw) return polx[0];
780: y = cgetg(2,t_VEC); p1 = cgetg(3,t_VEC); y[1] = (long)p1;
781: p1[1]=(long)idmat(2);
782: p1[2]=(long)polx[0]; return y;
783: }
784: if (signe(D) > 0)
785: y = bnrstark(bnr,gzero, gcmp0(flag)?1:5, prec);
786: else
787: {
788: if (lambda)
789: y = computeP2(bnr,lambda,raw,prec);
790: else
791: y = quadrayimagsigma(bnr,raw,prec);
792: }
793: return gerepileupto(av, y);
794: }
795:
796: /*******************************************************************/
797: /* */
798: /* Routines related to binary quadratic forms (for internal use) */
799: /* */
800: /*******************************************************************/
801: #define rhorealform(x) rhoreal_aux(x,Disc,sqrtD,isqrtD)
802: #define redrealform(x) gcopy(fix_signs(redrealform5(x,Disc,sqrtD,isqrtD)))
1.2 ! noro 803:
! 804: static GEN
! 805: fix_signs(GEN x)
! 806: {
! 807: GEN a = (GEN)x[1];
! 808: GEN c = (GEN)x[3];
! 809: if (signe(a) < 0)
! 810: {
! 811: if (narrow || absi_equal(a,c)) return rhorealform(x);
! 812: setsigne(a,1); setsigne(c,-1);
! 813: }
! 814: return x;
! 815: }
! 816:
! 817: static GEN
! 818: comprealform(GEN x,GEN y) {
! 819: return fix_signs( comprealform5(x,y,Disc,sqrtD,isqrtD) );
! 820: }
1.1 noro 821:
822: /* compute rho^n(x) */
1.2 ! noro 823: static GEN
1.1 noro 824: rhoreal_pow(GEN x, long n)
825: {
1.2 ! noro 826: long i;
! 827: gpmem_t av = avma, lim = stack_lim(av, 1);
1.1 noro 828: for (i=1; i<=n; i++)
829: {
830: x = rhorealform(x);
831: if (low_stack(lim, stack_lim(av,1)))
832: {
1.2 ! noro 833: if(DEBUGMEM>1) err(warnmem,"rhoreal_pow");
1.1 noro 834: x = gerepilecopy(av, x);
835: }
836: }
837: return gerepilecopy(av, x);
838: }
839:
840: static GEN
1.2 ! noro 841: realpf5(GEN D, long p)
1.1 noro 842: {
1.2 ! noro 843: gpmem_t av = avma;
! 844: GEN y = primeform(D,stoi(p),PRECREG);
! 845: y = codeform5(y,PRECREG);
! 846: return gerepileupto(av, redrealform(y));
1.1 noro 847: }
848:
849: static GEN
1.2 ! noro 850: realpf(GEN D, long p)
1.1 noro 851: {
1.2 ! noro 852: gpmem_t av = avma;
! 853: GEN y = primeform(D,stoi(p),PRECREG);
1.1 noro 854: return gerepileupto(av, redrealform(y));
855: }
856:
857: static GEN
1.2 ! noro 858: imagpf(GEN D, long p) { return primeform(D,stoi(p),0); }
1.1 noro 859:
860: static GEN
861: comprealform3(GEN x, GEN y)
862: {
1.2 ! noro 863: gpmem_t av = avma;
1.1 noro 864: GEN z = cgetg(4,t_VEC); comp_gen(z,x,y);
865: return gerepileupto(av, redrealform(z));
866: }
867:
1.2 ! noro 868: /* Warning: ex[0] not set */
1.1 noro 869: static GEN
1.2 ! noro 870: init_form(long *ex, GEN (*comp)(GEN,GEN))
1.1 noro 871: {
1.2 ! noro 872: long i, l = lg(powsubFB);
! 873: GEN F = NULL;
! 874: for (i=1; i<l; i++)
! 875: if (ex[i])
! 876: {
! 877: GEN t = gmael(powsubFB,i,ex[i]);
! 878: F = F? comp(F,t): t;
! 879: }
! 880: return F;
! 881: }
! 882: static GEN
! 883: initrealform5(long *ex) { return init_form(ex, &comprealform); }
! 884: static GEN
! 885: initimagform(long *ex) { return init_form(ex, &compimag); }
1.1 noro 886:
1.2 ! noro 887: static GEN
! 888: random_form(GEN ex, GEN (*comp)(GEN,GEN))
! 889: {
! 890: long i, l = lg(ex);
! 891: gpmem_t av = avma;
! 892: GEN F;
! 893: for(;;)
! 894: {
! 895: for (i=1; i<l; i++) ex[i] = mymyrand()>>randshift;
! 896: if ((F = init_form(ex, comp))) return F;
! 897: avma = av;
! 898: }
1.1 noro 899: }
900:
1.2 ! noro 901: static GEN
! 902: real_random_form(GEN ex) { return random_form(ex, &comprealform3); }
! 903: static GEN
! 904: imag_random_form(GEN ex) { return random_form(ex, &compimag); }
! 905:
1.1 noro 906: /*******************************************************************/
907: /* */
908: /* Common subroutines */
909: /* */
910: /*******************************************************************/
911: static void
912: buch_init(void)
913: {
1.2 ! noro 914: if (DEBUGLEVEL) (void)timer2();
1.1 noro 915: primfact = new_chunk(100);
916: exprimfact = new_chunk(100);
917: badprim = new_chunk(100);
918: hashtab = (long**) new_chunk(HASHT);
919: }
920:
921: double
922: check_bach(double cbach, double B)
923: {
924: if (cbach >= B)
925: err(talker,"sorry, buchxxx couldn't deal with this field PLEASE REPORT!");
926: cbach *= 2; if (cbach > B) cbach = B;
927: if (DEBUGLEVEL) fprintferr("\n*** Bach constant: %f\n", cbach);
928: return cbach;
929: }
930:
931: static long
1.2 ! noro 932: factorquad(GEN f, long kcz, long limp)
1.1 noro 933: {
1.2 ! noro 934: long i, p, k, lo;
! 935: gpmem_t av;
1.1 noro 936: GEN q,r, x = (GEN)f[1];
937:
938: if (is_pm1(x)) { primfact[0]=0; return 1; }
939: av=avma; lo=0;
940: if (signe(x) < 0) x = absi(x);
941: for (i=1; ; i++)
942: {
1.2 ! noro 943: p=FB[i]; q=dvmdis(x,p,&r);
1.1 noro 944: if (!signe(r))
945: {
1.2 ! noro 946: for (k=0; !signe(r); k++) { x=q; q=dvmdis(x,p,&r); }
! 947: primfact[++lo]=p; exprimfact[lo]=k;
1.1 noro 948: }
949: if (cmpis(q,p)<=0) break;
950: if (i==kcz) { avma=av; return 0; }
951: }
1.2 ! noro 952: avma=av;
! 953: if (lgefint(x)!=3 || (p=x[2]) > limhash) return 0;
1.1 noro 954:
955: if (p != 1 && p <= limp)
956: {
957: for (i=1; i<=badprim[0]; i++)
958: if (p % badprim[i] == 0) return 0;
1.2 ! noro 959: primfact[++lo]=p; exprimfact[lo]=1;
1.1 noro 960: p = 1;
961: }
962: primfact[0]=lo; return p;
963: }
964:
965: /* q may not be prime, but check for a "large prime relation" involving q */
966: static long *
967: largeprime(long q, long *ex, long np, long nrho)
968: {
1.2 ! noro 969: const long hashv = hash(q);
! 970: long *pt, i, l = lg(subFB);
1.1 noro 971:
972: for (pt = hashtab[hashv]; ; pt = (long*) pt[0])
973: {
974: if (!pt)
975: {
1.2 ! noro 976: pt = (long*) gpmalloc((l+3)<<TWOPOTBYTES_IN_LONG);
1.1 noro 977: *pt++ = nrho; /* nrho = pt[-3] */
978: *pt++ = np; /* np = pt[-2] */
979: *pt++ = q; /* q = pt[-1] */
980: pt[0] = (long)hashtab[hashv];
1.2 ! noro 981: for (i=1; i<l; i++) pt[i]=ex[i];
1.1 noro 982: hashtab[hashv]=pt; return NULL;
983: }
984: if (pt[-1] == q) break;
985: }
1.2 ! noro 986: for(i=1; i<l; i++)
1.1 noro 987: if (pt[i] != ex[i]) return pt;
988: return (pt[-2]==np)? (GEN)NULL: pt;
989: }
990:
1.2 ! noro 991: /* p | conductor of order of disc D ? */
! 992: static int
! 993: is_bad(GEN D, ulong p)
1.1 noro 994: {
1.2 ! noro 995: gpmem_t av = avma;
! 996: int r;
! 997: if (p == 2)
! 998: {
! 999: r = mod16(D) >> 1;
! 1000: if (r && signe(D) < 0) r = 8-r;
! 1001: return (r < 4);
! 1002: }
! 1003: r = (resii(D, muluu(p,p)) == gzero); /* p^2 | D ? */
! 1004: avma = av; return r;
1.1 noro 1005: }
1006:
1.2 ! noro 1007: /* create FB, numFB; fill badprim. Return L(kro_D, 1) */
! 1008: static GEN
! 1009: FBquad(GEN Disc, long n2, long n)
1.1 noro 1010: {
1.2 ! noro 1011: GEN Res = realun(DEFAULTPREC);
! 1012: long i, p, bad, s;
! 1013: gpmem_t av;
! 1014: byteptr d = diffptr;
1.1 noro 1015:
1.2 ! noro 1016: numFB = cgetg(n2+1, t_VECSMALL);
! 1017: FB = cgetg(n2+1, t_VECSMALL);
! 1018: av = avma;
! 1019: KC = 0; bad = 0; i = 0;
! 1020: if (maxprime() < n2) err(primer1);
! 1021: for (p = 0;;) /* p <= n2 */
! 1022: {
! 1023: NEXT_PRIME_VIADIFF(p, d);
! 1024: if (!KC && p > n) KC = i;
! 1025: if (p > n2) break;
! 1026: s = krogs(Disc,p);
! 1027: switch (s)
1.1 noro 1028: {
1029: case -1: break; /* inert */
1030: case 0: /* ramified */
1.2 ! noro 1031: if (is_bad(Disc, (ulong)p)) { badprim[++bad]=p; break; }
! 1032: /* fall through */
1.1 noro 1033: default: /* split */
1.2 ! noro 1034: i++; numFB[p]=i; FB[i] = p; break;
1.1 noro 1035: }
1.2 ! noro 1036: Res = mulsr(p, divrs(Res, p - s));
1.1 noro 1037: }
1.2 ! noro 1038: if (!KC) return NULL;
! 1039: Res = gerepileupto(av, Res);
1.1 noro 1040: KC2 = i;
1.2 ! noro 1041: setlg(FB, KC2+1);
1.1 noro 1042: if (DEBUGLEVEL)
1043: {
1044: msgtimer("factor base");
1045: if (DEBUGLEVEL>7)
1046: {
1.2 ! noro 1047: fprintferr("FB:\n");
! 1048: for (i=1; i<=KC; i++) fprintferr("%ld ", FB[i]);
! 1049: fprintferr("\n");
1.1 noro 1050: }
1051: }
1.2 ! noro 1052: badprim[0] = bad; return Res;
1.1 noro 1053: }
1054:
1.2 ! noro 1055: /* create vperm, return subFB */
! 1056: static GEN
! 1057: subFBquad(GEN D, double PROD, long KC)
1.1 noro 1058: {
1.2 ! noro 1059: long i, j, lgsub, ino, lv = KC+1;
! 1060: double prod = 1.;
! 1061: gpmem_t av;
! 1062: GEN no;
1.1 noro 1063:
1.2 ! noro 1064: vperm = cgetg(lv, t_VECSMALL);
! 1065: av = avma;
! 1066: no = cgetg(lv, t_VECSMALL); ino = 1;
! 1067: for (i=j=1; j < lv; j++)
1.1 noro 1068: {
1.2 ! noro 1069: long p = FB[j];
! 1070: if (smodis(D, p) == 0) no[ino++] = j; /* ramified */
! 1071: else
! 1072: {
! 1073: vperm[i] = j; i++;
! 1074: prod *= p;
! 1075: if (prod > PROD) break;
! 1076: }
1.1 noro 1077: }
1.2 ! noro 1078: if (j == lv) return NULL;
! 1079: lgsub = i;
! 1080: for (j = 1; j <ino; i++,j++) vperm[i] = no[j];
! 1081: for ( ; i < lv; i++) vperm[i] = i;
! 1082: avma = av;
! 1083: if (DEBUGLEVEL) msgtimer("subFBquad (%ld elt.)", lgsub-1);
! 1084: return vecextract_i(vperm, 1, lgsub-1);
1.1 noro 1085: }
1086:
1.2 ! noro 1087: /* assume n >= 1, x[i][j] = subFB[i]^j, for j = 1..n */
! 1088: static GEN
! 1089: powsubFBquad(long n)
1.1 noro 1090: {
1.2 ! noro 1091: long i,j, l = lg(subFB);
! 1092: GEN F, y, x = cgetg(l, t_VEC);
1.1 noro 1093:
1094: if (PRECREG) /* real */
1095: {
1.2 ! noro 1096: for (i=1; i<l; i++)
! 1097: {
! 1098: F = realpf5(Disc, FB[subFB[i]]);
! 1099: y = cgetg(n+1, t_VEC); x[i] = (long)y;
! 1100: y[1] = (long)F;
! 1101: for (j=2; j<=n; j++) y[j] = (long)comprealform((GEN)y[j-1], F);
1.1 noro 1102: }
1103: }
1104: else /* imaginary */
1105: {
1.2 ! noro 1106: for (i=1; i<l; i++)
1.1 noro 1107: {
1.2 ! noro 1108: F = imagpf(Disc, FB[subFB[i]]);
! 1109: y = cgetg(n+1, t_VEC); x[i] = (long)y;
! 1110: y[1] = (long)F;
! 1111: for (j=2; j<=n; j++) y[j] = (long)compimag((GEN)y[j-1], F);
1.1 noro 1112: }
1113: }
1.2 ! noro 1114: if (DEBUGLEVEL) msgtimer("powsubFBquad");
! 1115: return x;
1.1 noro 1116: }
1117:
1118: static void
1119: desalloc(long **mat)
1120: {
1121: long i,*p,*q;
1.2 ! noro 1122: for (i=1; i<lg(mat); i++) free(mat[i]);
! 1123: free(mat);
! 1124: for (i=1; i<HASHT; i++)
! 1125: for (p = hashtab[i]; p; p = q) { q=(long*)p[0]; free(p-3); }
! 1126: }
1.1 noro 1127:
1.2 ! noro 1128: static void
! 1129: sub_fact(GEN col, GEN F)
! 1130: {
! 1131: GEN b = (GEN)F[2];
! 1132: long i, p, e;
! 1133: for (i=1; i<=primfact[0]; i++)
! 1134: {
! 1135: p = primfact[i]; e = exprimfact[i];
! 1136: if (smodis(b, p<<1) > p) e = -e;
! 1137: col[numFB[p]] -= e;
1.1 noro 1138: }
1139: }
1.2 ! noro 1140: static void
! 1141: add_fact(GEN col, GEN F)
1.1 noro 1142: {
1.2 ! noro 1143: GEN b = (GEN)F[2];
! 1144: long i, p, e;
! 1145: for (i=1; i<=primfact[0]; i++)
! 1146: {
! 1147: p = primfact[i]; e = exprimfact[i];
! 1148: if (smodis(b, p<<1) > p) e = -e;
! 1149: col[numFB[p]] += e;
1.1 noro 1150: }
1151: }
1152:
1153: #define comp(x,y) x? (PRECREG? compreal(x,y): compimag(x,y)): y
1154: static GEN
1155: get_clgp(GEN Disc, GEN W, GEN *ptmet, long prec)
1156: {
1.2 ! noro 1157: GEN res,*init, u1, met = smithrel(W,NULL,&u1);
! 1158: long c,i,j, l = lg(W);
1.1 noro 1159:
1.2 ! noro 1160: c = lg(met);
1.1 noro 1161: if (DEBUGLEVEL) msgtimer("smith/class group");
1162: res=cgetg(c,t_VEC); init = (GEN*)cgetg(l,t_VEC);
1163: for (i=1; i<l; i++)
1.2 ! noro 1164: init[i] = primeform(Disc,stoi(FB[vperm[i]]),prec);
1.1 noro 1165: for (j=1; j<c; j++)
1166: {
1.2 ! noro 1167: GEN p1 = NULL;
1.1 noro 1168: for (i=1; i<l; i++)
1.2 ! noro 1169: p1 = comp(p1, powgi(init[i], gcoeff(u1,i,j)));
1.1 noro 1170: res[j] = (long)p1;
1171: }
1172: if (DEBUGLEVEL) msgtimer("generators");
1173: *ptmet = met; return res;
1174: }
1175:
1176: static GEN
1.2 ! noro 1177: extra_relations(long LIMC, long nlze, GEN *ptextraC)
1.1 noro 1178: {
1.2 ! noro 1179: long fpc, i, k, nlze2;
! 1180: long s = 0, extrarel = nlze+2, lgsub = lg(subFB);
! 1181: gpmem_t av;
1.1 noro 1182: long MAXRELSUP = min(50,4*KC);
1.2 ! noro 1183: GEN p1, form, ex, extramat, extraC, col;
1.1 noro 1184:
1.2 ! noro 1185: extramat = cgetg(extrarel+1, t_MAT);
! 1186: extraC = cgetg(extrarel+1, t_VEC);
! 1187: for (i=1; i<=extrarel; i++) extramat[i] = lgetg(KC+1,t_VECSMALL);
! 1188: if (!PRECREG)
! 1189: for (i=1; i<=extrarel; i++) extraC[i] = lgetg(1,t_COL);
! 1190:
! 1191: if (DEBUGLEVEL) fprintferr("looking for %ld extra relations\n",extrarel);
! 1192: nlze2 = PRECREG? max(nlze,lgsub-1): min(nlze+1,KC);
1.1 noro 1193: if (nlze2 < 3 && KC > 2) nlze2 = 3;
1.2 ! noro 1194: ex = cgetg(nlze2+1, t_VECSMALL);
1.1 noro 1195: av = avma;
1196: while (s<extrarel)
1197: {
1198: form = NULL;
1199: for (i=1; i<=nlze2; i++)
1200: {
1.2 ! noro 1201: ex[i] = mymyrand()>>randshift;
1.1 noro 1202: if (ex[i])
1203: {
1.2 ! noro 1204: p1 = primeform(Disc,stoi(FB[vperm[i]]),PRECREG);
! 1205: p1 = gpowgs(p1,ex[i]); form = comp(form,p1);
1.1 noro 1206: }
1207: }
1208: if (!form) continue;
1209:
1.2 ! noro 1210: fpc = factorquad(form,KC,LIMC);
1.1 noro 1211: if (fpc==1)
1212: {
1213: s++; col = (GEN)extramat[s];
1214: for (i=1; i<=nlze2; i++) col[vperm[i]] = -ex[i];
1.2 ! noro 1215: for ( ; i<=KC; i++) col[vperm[i]] = 0;
! 1216: add_fact(col, form);
1.1 noro 1217: for (i=1; i<=KC; i++)
1218: if (col[i]) break;
1219: if (i>KC)
1220: {
1221: s--; avma = av;
1222: if (--MAXRELSUP == 0) return NULL;
1223: }
1.2 ! noro 1224: else { av = avma; if (PRECREG) extraC[s] = form[4]; }
1.1 noro 1225: }
1226: else avma = av;
1227: if (DEBUGLEVEL)
1228: {
1229: if (fpc == 1) fprintferr(" %ld",s);
1230: else if (DEBUGLEVEL>1) fprintferr(".");
1231: }
1232: }
1.2 ! noro 1233:
! 1234: for (i=1; i<=extrarel; i++)
1.1 noro 1235: {
1.2 ! noro 1236: GEN colg = cgetg(KC+1,t_COL);
! 1237: col = (GEN)extramat[i];
! 1238: extramat[i] = (long)colg;
! 1239: for (k=1; k<=KC; k++) colg[k] = lstoi(col[vperm[k]]);
1.1 noro 1240: }
1.2 ! noro 1241: if (DEBUGLEVEL) { fprintferr("\n"); msgtimer("extra relations"); }
! 1242: *ptextraC = extraC; return extramat;
! 1243: }
! 1244: #undef comp
! 1245:
! 1246: static long
! 1247: trivial_relations(long **mat, GEN C)
! 1248: {
! 1249: long i, s = 0;
! 1250: GEN col;
! 1251: for (i=1; i<=KC; i++)
! 1252: {
! 1253: if (smodis(Disc, FB[i])) continue;
! 1254: /* ramified prime ==> trivial relation */
! 1255: col = mat[++s];
! 1256: col[i] = 2;
! 1257: if (C) affsr(0, (GEN)C[s]);
1.1 noro 1258: }
1.2 ! noro 1259: return s;
! 1260: }
! 1261:
! 1262: static void
! 1263: dbg_all(long phase, long s, long n)
! 1264: {
! 1265: if (DEBUGLEVEL>1) fprintferr("\n");
! 1266: msgtimer("%s rel [#rel/#test = %ld/%ld]", phase? "random": "initial", s, n);
! 1267: }
! 1268:
! 1269: void
! 1270: wr_rel(GEN col)
! 1271: {
! 1272: long i, l = lg(col);
! 1273: fprintferr("\nrel = ");
! 1274: for (i=1; i<l; i++)
! 1275: if (col[i]) fprintferr("%ld^%ld ",i,col[i]);
! 1276: fprintferr("\n");
1.1 noro 1277: }
1278:
1.2 ! noro 1279: void
! 1280: dbg_rel(long s, GEN col)
! 1281: {
! 1282: if (DEBUGLEVEL == 1) fprintferr("%4ld",s);
! 1283: else { fprintferr("cglob = %ld. ", s); wr_rel(col); }
! 1284: flusherr();
! 1285: }
1.1 noro 1286: /*******************************************************************/
1287: /* */
1288: /* Imaginary Quadratic fields */
1289: /* */
1290: /*******************************************************************/
1291:
1.2 ! noro 1292: /* Strategy 1 until lim relation found, then Strategy 2 until LIM. */
1.1 noro 1293: static GEN
1.2 ! noro 1294: imag_relations(long LIM, long lim, long LIMC, long **mat)
1.1 noro 1295: {
1.2 ! noro 1296: long lgsub = lg(subFB), i, s, fpc, current, nbtest = 0;
! 1297: int first = 1;
! 1298: gpmem_t av;
! 1299: GEN C, col, form, ex = cgetg(lgsub, t_VECSMALL);
! 1300: GEN dummy = cgetg(1,t_COL);
1.1 noro 1301:
1.2 ! noro 1302: C = cgetg(LIM+1, t_VEC);
! 1303: for (i=1; i<=LIM; i++) C[i] = (long)dummy;
! 1304: av = avma;
! 1305: s = trivial_relations(mat, NULL);
! 1306: lim += s; if (lim > LIM) lim = LIM;
1.1 noro 1307: for(;;)
1308: {
1.2 ! noro 1309: if (s >= lim) {
! 1310: if (s >= LIM) break;
! 1311: lim = LIM; first = 0;
! 1312: if (DEBUGLEVEL) dbg_all(0, s, nbtest);
! 1313: }
! 1314: avma = av; current = first? 1+(s%KC): 1+s-RELSUP;
! 1315: form = imagpf(Disc, FB[current]);
! 1316: form = compimag(form, imag_random_form(ex));
! 1317: nbtest++; fpc = factorquad(form,KC,LIMC);
1.1 noro 1318: if (!fpc)
1319: {
1.2 ! noro 1320: if (DEBUGLEVEL>1) fprintferr(".");
1.1 noro 1321: continue;
1322: }
1323: if (fpc > 1)
1324: {
1.2 ! noro 1325: long *fpd = largeprime(fpc,ex,current,0);
! 1326: long b1, b2, p;
! 1327: GEN form2;
1.1 noro 1328: if (!fpd)
1329: {
1.2 ! noro 1330: if (DEBUGLEVEL>1) fprintferr(".");
1.1 noro 1331: continue;
1332: }
1.2 ! noro 1333: form2 = initimagform(fpd);
! 1334: form2 = compimag(form2, imagpf(Disc, FB[fpd[-2]]));
! 1335: p = fpc << 1;
! 1336: b1 = smodis((GEN)form2[2], p);
! 1337: b2 = smodis((GEN)form[2], p);
! 1338: if (b1 != b2 && b1+b2 != p) continue;
! 1339:
! 1340: col = mat[++s];
! 1341: add_fact(col, form);
! 1342: (void)factorquad(form2,KC,LIMC);
1.1 noro 1343: if (b1==b2)
1344: {
1.2 ! noro 1345: for (i=1; i<lgsub; i++) col[subFB[i]] += fpd[i]-ex[i];
! 1346: sub_fact(col, form2); col[fpd[-2]]++;
1.1 noro 1347: }
1348: else
1349: {
1.2 ! noro 1350: for (i=1; i<lgsub; i++) col[subFB[i]] += -fpd[i]-ex[i];
! 1351: add_fact(col, form2); col[fpd[-2]]--;
1.1 noro 1352: }
1.2 ! noro 1353: }
1.1 noro 1354: else
1355: {
1.2 ! noro 1356: col = mat[++s];
! 1357: for (i=1; i<lgsub; i++) col[subFB[i]] = -ex[i];
! 1358: add_fact(col, form);
1.1 noro 1359: }
1360: col[current]--;
1.2 ! noro 1361: if (DEBUGLEVEL) dbg_rel(s, col);
1.1 noro 1362: if (!first && fpc == 1 && col[current] == 0)
1363: {
1364: s--; for (i=1; i<=KC; i++) col[i]=0;
1365: }
1366: }
1.2 ! noro 1367: if (DEBUGLEVEL) dbg_all(1, s, nbtest);
! 1368: return C;
1.1 noro 1369: }
1370:
1371: static int
1.2 ! noro 1372: imag_be_honest()
1.1 noro 1373: {
1.2 ! noro 1374: long p, fpc, s = KC, nbtest = 0;
! 1375: gpmem_t av = avma;
! 1376: GEN F, ex = cgetg(lg(subFB), t_VECSMALL);
1.1 noro 1377:
1378: while (s<KC2)
1379: {
1.2 ! noro 1380: p = FB[s+1]; if (DEBUGLEVEL) fprintferr(" %ld",p);
! 1381: F = compimag(imagpf(Disc, p), imag_random_form(ex));
! 1382: fpc = factorquad(F,s,p-1);
1.1 noro 1383: if (fpc == 1) { nbtest=0; s++; }
1384: else
1385: if (++nbtest > 20) return 0;
1386: avma = av;
1387: }
1388: return 1;
1389: }
1390:
1391: /*******************************************************************/
1392: /* */
1393: /* Real Quadratic fields */
1394: /* */
1395: /*******************************************************************/
1396:
1.2 ! noro 1397: /* (1/2) log (d * 2^{e * EXP220}) */
! 1398: GEN
! 1399: get_dist(GEN e, GEN d, long prec)
! 1400: {
! 1401: GEN t = mplog(absr(d));
! 1402: if (signe(e)) t = addrr(t, mulir(mulsi(EXP220,e), mplog2(prec)));
! 1403: return shiftr(t, -1);
! 1404: }
! 1405:
1.1 noro 1406: static GEN
1.2 ! noro 1407: real_relations(long LIM, long lim, long LIMC, long **mat)
1.1 noro 1408: {
1.2 ! noro 1409: long lgsub = lg(subFB), i, s, fpc, current, nbtest = 0, endcycle, rhoacc, rho;
! 1410: int first = 1;
! 1411: gpmem_t av, av1, limstack;
! 1412: GEN C, d, col, form, form0, form1, ex = cgetg(lgsub, t_VECSMALL);
1.1 noro 1413:
1.2 ! noro 1414: C = cgetg(LIM+1, t_VEC);
! 1415: for (i=1; i<=LIM; i++) C[i] = lgetr(PRECREG);
! 1416:
! 1417: current = 0;
! 1418: av = avma; limstack = stack_lim(av,1);
! 1419: s = trivial_relations(mat, C);
! 1420: lim += s; if (lim > LIM) lim = LIM;
! 1421: NEW:
1.1 noro 1422: for(;;)
1423: {
1.2 ! noro 1424: if (s >= lim) {
! 1425: if (lim == LIM) break;
! 1426: lim = LIM; first = 0;
! 1427: if (DEBUGLEVEL) dbg_all(0, s, nbtest);
1.1 noro 1428: }
1429: avma = av;
1430: form = real_random_form(ex);
1431: if (!first)
1432: {
1433: current = 1+s-RELSUP;
1.2 ! noro 1434: form = comprealform3(form, realpf(Disc, FB[current]));
1.1 noro 1435: }
1.2 ! noro 1436: av1 = avma;
1.1 noro 1437: form0 = form; form1 = NULL;
1.2 ! noro 1438: endcycle = rhoacc = 0;
! 1439: rho = -1;
! 1440:
! 1441: CYCLE:
! 1442: if (endcycle) goto NEW;
! 1443: if (low_stack(limstack, stack_lim(av,1)))
! 1444: {
! 1445: if(DEBUGMEM>1) err(warnmem,"real_relations");
! 1446: gerepileall(av1, form1? 2: 1, &form, &form1);
! 1447: }
! 1448: if (rho < 0) rho = 0; /* first time in */
! 1449: else
1.1 noro 1450: {
1.2 ! noro 1451: form = rhorealform(form); rho++;
! 1452: rhoacc++;
! 1453: if (first)
! 1454: endcycle = (absi_equal((GEN)form[1],(GEN)form0[1])
! 1455: && egalii((GEN)form[2],(GEN)form0[2])
! 1456: && (!narrow || signe(form0[1])==signe(form[1])));
1.1 noro 1457: else
1458: {
1.2 ! noro 1459: if (narrow)
! 1460: { form = rhorealform(form); rho++; }
! 1461: else if (absi_equal((GEN)form[1], (GEN)form[3])) /* a = -c */
1.1 noro 1462: {
1.2 ! noro 1463: if (absi_equal((GEN)form[1],(GEN)form0[1]) &&
! 1464: egalii((GEN)form[2],(GEN)form0[2])) goto NEW;
! 1465: form = rhorealform(form); rho++;
1.1 noro 1466: }
1467: else
1.2 ! noro 1468: { setsigne(form[1],1); setsigne(form[3],-1); }
! 1469: if (egalii((GEN)form[1],(GEN)form0[1]) &&
! 1470: egalii((GEN)form[2],(GEN)form0[2])) goto NEW;
1.1 noro 1471: }
1.2 ! noro 1472: }
! 1473: nbtest++; fpc = factorquad(form,KC,LIMC);
! 1474: if (!fpc)
! 1475: {
! 1476: if (DEBUGLEVEL>1) fprintferr(".");
! 1477: goto CYCLE;
! 1478: }
! 1479: if (fpc > 1)
! 1480: { /* look for Large Prime relation */
! 1481: long *fpd = largeprime(fpc,ex,current,rhoacc);
! 1482: long b1, b2, p;
! 1483: GEN form2;
! 1484: if (!fpd)
1.1 noro 1485: {
1.2 ! noro 1486: if (DEBUGLEVEL>1) fprintferr(".");
! 1487: goto CYCLE;
1.1 noro 1488: }
1.2 ! noro 1489: if (!form1) form1 = initrealform5(ex);
! 1490: if (!first) form1 = comprealform(form1, realpf5(Disc, FB[current]));
! 1491: form1 = rhoreal_pow(form1, rho);
! 1492: rho = 0;
! 1493:
! 1494: form2 = initrealform5(fpd);
! 1495: if (fpd[-2]) form2 = comprealform(form2, realpf5(Disc, FB[fpd[-2]]));
! 1496: form2 = rhoreal_pow(form2, fpd[-3]);
! 1497: if (!narrow && !absi_equal((GEN)form2[1],(GEN)form2[3]))
! 1498: {
! 1499: setsigne(form2[1],1);
! 1500: setsigne(form2[3],-1);
! 1501: }
! 1502: p = fpc << 1;
! 1503: b1 = smodis((GEN)form2[2], p);
! 1504: b2 = smodis((GEN)form1[2], p);
! 1505: if (b1 != b2 && b1+b2 != p) goto CYCLE;
! 1506:
! 1507: col = mat[++s];
! 1508: add_fact(col, form1);
! 1509: (void)factorquad(form2,KC,LIMC);
! 1510: if (b1==b2)
1.1 noro 1511: {
1.2 ! noro 1512: for (i=1; i<lgsub; i++) col[subFB[i]] += fpd[i]-ex[i];
! 1513: sub_fact(col, form2);
! 1514: if (fpd[-2]) col[fpd[-2]]++; /* implies !first */
! 1515: d = get_dist(subii((GEN)form1[4],(GEN)form2[4]),
! 1516: divrr((GEN)form1[5],(GEN)form2[5]), PRECREG);
1.1 noro 1517: }
1518: else
1519: {
1.2 ! noro 1520: for (i=1; i<lgsub; i++) col[subFB[i]] += -fpd[i]-ex[i];
! 1521: add_fact(col, form2);
! 1522: if (fpd[-2]) col[fpd[-2]]--;
! 1523: d = get_dist(addii((GEN)form1[4],(GEN)form2[4]),
! 1524: mulrr((GEN)form1[5],(GEN)form2[5]), PRECREG);
1.1 noro 1525: }
1.2 ! noro 1526: }
! 1527: else
! 1528: { /* standard relation */
! 1529: if (!form1) form1 = initrealform5(ex);
! 1530: if (!first) form1 = comprealform(form1, realpf5(Disc, FB[current]));
! 1531: form1 = rhoreal_pow(form1,rho);
! 1532: rho = 0;
! 1533:
! 1534: col = mat[++s];
! 1535: for (i=1; i<lgsub; i++) col[subFB[i]] = -ex[i];
! 1536: add_fact(col, form1);
! 1537: d = get_dist((GEN)form1[4], (GEN)form1[5], PRECREG);
! 1538: }
! 1539: if (DEBUGLEVEL) fprintferr(" %ld",s);
! 1540: affrr(d, (GEN)C[s]);
! 1541: if (first)
! 1542: {
! 1543: if (s >= lim) goto NEW;
! 1544: goto CYCLE;
! 1545: }
! 1546: else
! 1547: {
! 1548: col[current]--;
! 1549: if (fpc == 1 && col[current] == 0)
1.1 noro 1550: {
1.2 ! noro 1551: s--; for (i=1; i<=KC; i++) col[i]=0;
1.1 noro 1552: }
1553: }
1554: }
1.2 ! noro 1555: if (DEBUGLEVEL) dbg_all(1, s, nbtest);
! 1556: return C;
1.1 noro 1557: }
1558:
1559: static int
1.2 ! noro 1560: real_be_honest()
1.1 noro 1561: {
1.2 ! noro 1562: long p, fpc, s = KC, nbtest = 0;
! 1563: gpmem_t av = avma;
! 1564: GEN F,F0, ex = cgetg(lg(subFB), t_VECSMALL);
1.1 noro 1565:
1566: while (s<KC2)
1567: {
1.2 ! noro 1568: p = FB[s+1]; if (DEBUGLEVEL) fprintferr(" %ld",p);
! 1569: F = comprealform3(realpf(Disc, p), real_random_form(ex));
! 1570: for (F0 = F;;)
1.1 noro 1571: {
1.2 ! noro 1572: fpc = factorquad(F,s,p-1);
1.1 noro 1573: if (fpc == 1) { nbtest=0; s++; break; }
1574: if (++nbtest > 20) return 0;
1.2 ! noro 1575: F = fix_signs( rhorealform(F) );
! 1576: if (egalii((GEN)F[1],(GEN)F0[1])
! 1577: && egalii((GEN)F[2],(GEN)F0[2])) break;
1.1 noro 1578: }
1579: avma = av;
1580: }
1581: return 1;
1582: }
1583:
1584: static GEN
1.2 ! noro 1585: gcdreal(GEN a,GEN b)
1.1 noro 1586: {
1587: long e;
1588: GEN k1,r;
1589:
1.2 ! noro 1590: if (!signe(a)) return mpabs(b);
! 1591: if (!signe(b)) return mpabs(a);
! 1592:
1.1 noro 1593: if (typ(a)==t_INT)
1594: {
1595: if (typ(b)==t_INT) return mppgcd(a,b);
1.2 ! noro 1596: a = itor(a, lg(b));
1.1 noro 1597: }
1598: else if (typ(b)==t_INT)
1.2 ! noro 1599: {
! 1600: b = itor(b, lg(a));
! 1601: }
1.1 noro 1602: if (expo(a)<-5) return absr(b);
1603: if (expo(b)<-5) return absr(a);
1604: a=absr(a); b=absr(b);
1605: while (expo(b) >= -5 && signe(b))
1606: {
1.2 ! noro 1607: k1 = gcvtoi(divrr(a,b),&e);
1.1 noro 1608: if (e > 0) return NULL;
1609: r=subrr(a,mulir(k1,b)); a=b; b=r;
1610: }
1.2 ! noro 1611: return absr(a);
1.1 noro 1612: }
1613:
1.2 ! noro 1614: enum { RELAT, LARGE, PRECI };
! 1615:
! 1616: static int
! 1617: get_R(GEN C, long sreg, GEN z, GEN *ptR)
1.1 noro 1618: {
1.2 ! noro 1619: GEN R = gun;
! 1620: double c;
! 1621: long i;
1.1 noro 1622:
1.2 ! noro 1623: if (PRECREG)
1.1 noro 1624: {
1.2 ! noro 1625: R = mpabs((GEN)C[1]);
! 1626: for (i=2; i<=sreg; i++)
! 1627: {
! 1628: R = gcdreal((GEN)C[i], R);
! 1629: if (!R) return PRECI;
! 1630: }
! 1631: if (DEBUGLEVEL)
! 1632: {
! 1633: if (DEBUGLEVEL>7) fprintferr("R = %Z",R);
! 1634: msgtimer("regulator");
! 1635: }
! 1636: if (gexpo(R) <= -3)
! 1637: {
! 1638: if (DEBUGLEVEL) fprintferr("regulator is zero.\n");
! 1639: return RELAT;
! 1640: }
1.1 noro 1641: }
1.2 ! noro 1642: c = gtodouble(gmul(z, R));
! 1643: if (c < 0.75 || c > 1.5) return RELAT;
! 1644: *ptR = R; return LARGE;
! 1645: }
! 1646:
! 1647: static int
! 1648: quad_be_honest()
! 1649: {
! 1650: int r;
! 1651: if (KC2 <= KC) return 1;
1.1 noro 1652: if (DEBUGLEVEL)
1.2 ! noro 1653: fprintferr("be honest for primes from %ld to %ld\n", FB[KC+1],FB[KC2]);
! 1654: r = PRECREG? real_be_honest(): imag_be_honest();
! 1655: if (DEBUGLEVEL) { fprintferr("\n"); msgtimer("be honest"); }
! 1656: return r;
1.1 noro 1657: }
1658:
1659: GEN
1660: buchquad(GEN D, double cbach, double cbach2, long RELSUP0, long flag, long prec)
1661: {
1.2 ! noro 1662: gpmem_t av0 = avma, av;
! 1663: long KCCO, i, j, s, **mat;
! 1664: long nrelsup, nreldep, LIMC, LIMC2, cp, nlze;
! 1665: GEN h, W, cyc, res, gen, dep, C, B, extramat, extraC;
! 1666: GEN R, resc, Res, z;
! 1667: double drc, lim, LOGD, LOGD2;
! 1668: const long MAXRELSUP = 7;
1.1 noro 1669:
1670: Disc = D; if (typ(Disc)!=t_INT) err(typeer,"buchquad");
1.2 ! noro 1671: s = mod4(Disc);
1.1 noro 1672: switch(signe(Disc))
1673: {
1674: case -1:
1675: if (cmpis(Disc,-4) >= 0)
1676: {
1.2 ! noro 1677: GEN p1=cgetg(6,t_VEC); p1[1]=p1[4]=p1[5]=un;
1.1 noro 1678: p1[2]=p1[3]=lgetg(1,t_VEC); return p1;
1679: }
1680: if (s==2 || s==1) err(funder2,"buchquad");
1681: PRECREG=0; break;
1682:
1683: case 1:
1684: if (s==2 || s==3) err(funder2,"buchquad");
1685: if (flag)
1686: err(talker,"sorry, narrow class group not implemented. Use bnfnarrow");
1687: PRECREG=1; break;
1688:
1689: default: err(talker,"zero discriminant in quadclassunit");
1690: }
1691: if (carreparfait(Disc)) err(talker,"square argument in quadclassunit");
1692: if (!isfundamental(Disc))
1693: err(warner,"not a fundamental discriminant in quadclassunit");
1694: buch_init(); RELSUP = RELSUP0;
1.2 ! noro 1695: drc = fabs(gtodouble(Disc));
! 1696: LOGD = log(drc);
! 1697: LOGD2 = LOGD * LOGD;
! 1698:
! 1699: lim = sqrt(drc);
! 1700: /* resc = sqrt(D) w / 2^r1 (2pi)^r2 ~ hR / L(chi,1) */
! 1701: if (PRECREG) resc = dbltor(lim / 2.);
! 1702: else resc = dbltor(lim / PI);
1.1 noro 1703: if (!PRECREG) lim /= sqrt(3.);
1.2 ! noro 1704: R = gun;
1.1 noro 1705: cp = (long)exp(sqrt(LOGD*log(LOGD)/8.0));
1706: if (cp < 13) cp = 13;
1707: av = avma; cbach /= 2;
1.2 ! noro 1708: mat = NULL;
1.1 noro 1709:
1.2 ! noro 1710: START: avma = av; cbach = check_bach(cbach,6.);
! 1711: if (mat) { desalloc(mat); mat = NULL; }
1.1 noro 1712: nreldep = nrelsup = 0;
1.2 ! noro 1713: LIMC = (long)(cbach*LOGD2);
! 1714: if (LIMC < cp) { LIMC = cp; cbach = LIMC / LOGD2; }
! 1715: LIMC2 = (long)(max(cbach,cbach2)*LOGD2);
1.1 noro 1716: if (LIMC2 < LIMC) LIMC2 = LIMC;
1717: if (PRECREG)
1718: {
1719: PRECREG = max(prec+1, MEDDEFAULTPREC + 2*(expi(Disc)>>TWOPOTBITS_IN_LONG));
1720: sqrtD = gsqrt(Disc,PRECREG);
1721: isqrtD = gfloor(sqrtD);
1722: }
1723:
1.2 ! noro 1724: Res = FBquad(Disc,LIMC2,LIMC);
! 1725: if (!Res) goto START;
! 1726: subFB = subFBquad(Disc, lim + 0.5, KC);
! 1727: if (!subFB) goto START;
! 1728: powsubFB = powsubFBquad(CBUCH+1);
! 1729: limhash = ((ulong)LIMC < (MAXHALFULONG>>1))? LIMC*LIMC: HIGHBIT>>1;
! 1730: for (i=0; i<HASHT; i++) hashtab[i]=NULL;
! 1731:
1.1 noro 1732: KCCO = KC + RELSUP;
1.2 ! noro 1733: if (DEBUGLEVEL) fprintferr("KC = %ld, KCCO = %ld\n",KC,KCCO);
! 1734: mat = (long**)cgetalloc(NULL, KCCO+1, t_VEC);
1.1 noro 1735: for (i=1; i<=KCCO; i++)
1736: {
1.2 ! noro 1737: GEN t = cgetalloc(NULL, KC+1, t_VECSMALL);
! 1738: for (j=1; j<=KC; j++) t[j]=0;
! 1739: mat[i] = t;
1.1 noro 1740: }
1741:
1.2 ! noro 1742: s = lg(subFB)-1 + RELSUP;
! 1743: C = PRECREG? real_relations(KCCO,s,LIMC,mat)
! 1744: : imag_relations(KCCO,s,LIMC,mat);
! 1745: W = hnfspec(mat,vperm,&dep,&B,&C,lg(subFB)-1);
! 1746: nlze = lg(dep)>1? lg(dep[1])-1: lg(B[1])-1;
1.1 noro 1747:
1748: if (nlze)
1749: {
1.2 ! noro 1750: MORE:
! 1751: extramat = extra_relations(LIMC,nlze, &extraC);
! 1752: if (!extramat) { goto START; }
! 1753: W = hnfadd(W,vperm,&dep,&B,&C, extramat,extraC);
! 1754: nlze = lg(dep)>1? lg(dep[1])-1: lg(B[1])-1;
! 1755: KCCO += lg(extramat)-1;
1.1 noro 1756: if (nlze)
1757: {
1.2 ! noro 1758: if (++nreldep > 5) goto START;
! 1759: goto MORE;
1.1 noro 1760: }
1761: }
1.2 ! noro 1762:
! 1763: h = dethnf_i(W);
! 1764: if (DEBUGLEVEL) fprintferr("\n#### Tentative class number: %Z\n", h);
! 1765:
! 1766: z = mulrr(Res, resc); /* ~ hR if enough relations, a multiple otherwise */
! 1767: switch(get_R(C, KCCO - (lg(B)-1) - (lg(W)-1), divir(h,z), &R))
1.1 noro 1768: {
1.2 ! noro 1769: case PRECI:
! 1770: prec = (PRECREG<<1)-2;
! 1771: goto START;
! 1772:
! 1773: case RELAT:
! 1774: if (++nrelsup <= MAXRELSUP) { nlze = min(KC, nrelsup); goto MORE; }
! 1775: goto START;
1.1 noro 1776: }
1.2 ! noro 1777: /* DONE */
! 1778: if (!quad_be_honest()) goto START;
1.1 noro 1779:
1.2 ! noro 1780: gen = get_clgp(Disc,W,&cyc,PRECREG);
! 1781: desalloc(mat);
1.1 noro 1782:
1783: res=cgetg(6,t_VEC);
1.2 ! noro 1784: res[1]=(long)h;
! 1785: res[2]=(long)cyc;
! 1786: res[3]=(long)gen;
! 1787: res[4]=(long)R;
! 1788: res[5]=ldiv(mpmul(R,h), z); return gerepilecopy(av0,res);
1.1 noro 1789: }
1790:
1791: GEN
1792: buchimag(GEN D, GEN c, GEN c2, GEN REL)
1793: {
1794: return buchquad(D,gtodouble(c),gtodouble(c2),itos(REL), 0,0);
1795: }
1796:
1797: GEN
1798: buchreal(GEN D, GEN sens0, GEN c, GEN c2, GEN REL, long prec)
1799: {
1800: return buchquad(D,gtodouble(c),gtodouble(c2),itos(REL), itos(sens0),prec);
1801: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>