/* $Id: buch3.c,v 1.96 2002/09/08 10:40:52 karim Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************/ /* */ /* RAY CLASS FIELDS */ /* */ /*******************************************************************/ #include "pari.h" #include "parinf.h" extern void testprimes(GEN bnf, long bound); extern GEN Fp_PHlog(GEN a, GEN g, GEN p, GEN ord); extern GEN FqX_factor(GEN x, GEN T, GEN p); extern GEN anti_unif_mod_f(GEN nf, GEN pr, GEN sqf); extern GEN arch_mul(GEN x, GEN y); extern GEN check_and_build_cycgen(GEN bnf); extern GEN colreducemodHNF(GEN x, GEN y, GEN *Q); extern GEN detcyc(GEN cyc); extern GEN famat_reduce(GEN fa); extern GEN famat_to_nf_modideal_coprime(GEN nf, GEN g, GEN e, GEN id); extern GEN famat_to_nf_modidele(GEN nf, GEN g, GEN e, GEN bid); extern GEN gmul_mat_smallvec(GEN x, GEN y); extern GEN idealaddtoone_i(GEN nf, GEN x, GEN y); extern GEN idealprodprime(GEN nf, GEN L); extern GEN ideleaddone_aux(GEN nf,GEN x,GEN ideal); extern GEN isprincipalfact(GEN bnf,GEN P, GEN e, GEN C, long flag); extern GEN logunitmatrix(GEN nf,GEN funits,GEN racunit,GEN bid); extern GEN make_integral(GEN nf, GEN L0, GEN f, GEN *listpr, GEN *ptd1); extern GEN sqred1_from_QR(GEN x, long prec); extern GEN subgroupcondlist(GEN cyc, GEN bound, GEN listKer); extern GEN to_Fp_simple(GEN nf, GEN x, GEN ffproj); extern GEN to_famat_all(GEN x, GEN y); extern GEN trivfact(void); extern GEN unif_mod_f(GEN nf, GEN pr, GEN sqf); extern GEN vconcat(GEN Q1, GEN Q2); extern long FqX_is_squarefree(GEN P, GEN T, GEN p); extern long int_elt_val(GEN nf, GEN x, GEN p, GEN b, GEN *newx); extern void minim_alloc(long n, double ***q, GEN *x, double **y, double **z, double **v); extern void rowselect_p(GEN A, GEN B, GEN p, long init); /* FIXME: obsolete, see zarchstar (which is much slower unfortunately). */ static GEN get_full_rank(GEN nf, GEN v, GEN _0, GEN _1, GEN gen, long ngen, long rankmax) { GEN vecsign,v1,p1,alpha, bas=(GEN)nf[7], rac=(GEN)nf[6]; long rankinit = lg(v)-1, N = degpol(nf[1]), va = varn(nf[1]); long limr,i,k,kk,r,rr; vecsign = cgetg(rankmax+1,t_COL); for (r=1,rr=3; ; r++,rr+=2) { p1 = gpowgs(stoi(rr),N); limr = is_bigint(p1)? BIGINT: p1[2]; limr = (limr-1)>>1; for (k=rr; k<=limr; k++) { gpmem_t av1=avma; alpha = gzero; for (kk=k,i=1; i<=N; i++,kk/=rr) { long lambda = (kk+r)%rr - r; if (lambda) alpha = gadd(alpha,gmulsg(lambda,(GEN)bas[i])); } for (i=1; i<=rankmax; i++) vecsign[i] = (gsigne(gsubst(alpha,va,(GEN)rac[i])) > 0)? (long)_0 : (long)_1; v1 = concatsp(v, vecsign); if (rank(v1) == rankinit) { avma = av1; continue; } v=v1; rankinit++; ngen++; gen[ngen] = (long) alpha; if (rankinit == rankmax) return ginv(v); /* full rank */ vecsign = cgetg(rankmax+1,t_COL); } } } /* FIXME: obsolete. Replace by a call to buchrayall (currently much slower) */ GEN buchnarrow(GEN bnf) { GEN nf,_0,_1,cyc,gen,v,matsign,arch,cycgen,logs; GEN dataunit,p1,p2,h,basecl,met,u1; long r1,R,i,j,ngen,sizeh,t,lo,c; gpmem_t av = avma; bnf = checkbnf(bnf); nf = checknf(bnf); r1 = nf_get_r1(nf); if (!r1) return gcopy(gmael(bnf,8,1)); _1 = gmodulss(1,2); _0 = gmodulss(0,2); cyc = gmael3(bnf,8,1,2); gen = gmael3(bnf,8,1,3); ngen = lg(gen)-1; matsign = signunits(bnf); R = lg(matsign); dataunit = cgetg(R+1,t_MAT); for (j=1; j 0)? (long)_0: (long)_1; } v = cgetg(r1+1,t_COL); for (i=1; i<=r1; i++) v[i] = (long)_1; dataunit[R] = (long)v; v = image(dataunit); t = lg(v)-1; if (t == r1) { avma = av; return gcopy(gmael(bnf,8,1)); } sizeh = ngen+r1-t; p1 = cgetg(sizeh+1,t_COL); for (i=1; i<=ngen; i++) p1[i] = gen[i]; gen = p1; v = get_full_rank(nf,v,_0,_1,gen,ngen,r1); arch = cgetg(r1+1,t_VEC); for (i=1; i<=r1; i++) arch[i]=un; cycgen = check_and_build_cycgen(bnf); logs = cgetg(ngen+1,t_MAT); for (j=1; j<=ngen; j++) { GEN u = lift_intern(gmul(v, zsigne(nf,(GEN)cycgen[j],arch))); logs[j] = (long)vecextract_i(u, t+1, r1); } /* [ cyc 0 ] * [ logs 2 ] = relation matrix for Cl_f */ h = concatsp( vconcat(diagonal(cyc), logs), vconcat(zeromat(ngen, r1-t), gscalmat(gdeux,r1-t)) ); lo = lg(h)-1; met = smithrel(h,NULL,&u1); c = lg(met); if (DEBUGLEVEL>3) msgtimer("smith/class group"); basecl = cgetg(c,t_VEC); for (j=1; j 1 */ basecl = cgetg(l,t_VEC); prec = nfgetprec(nf); G = cgetg(3,t_VEC); G[2] = lgetg(1,t_MAT); for (j=1; j 0) { avma = av; return x; } a = set_sign_mod_idele(nf, NULL, A, idele, sarch); if (a != A && too_big(nf,A) > 0) { avma = av; return x; } return idealmul(nf, a, x); } GEN idealmodidele(GEN bnr, GEN x) { GEN bid = (GEN)bnr[2], fa2 = (GEN)bid[4]; GEN idele = (GEN)bid[1]; GEN sarch = (GEN)fa2[lg(fa2)-1]; return _idealmodidele(checknf(bnr), x, idele, sarch); } /* v_pr(L0 * cx). tau = pr[5] or (more efficient) mult. table for pr[5] */ static long fast_val(GEN nf,GEN L0,GEN cx,GEN pr,GEN tau) { GEN p = (GEN)pr[1]; long v = int_elt_val(nf,L0,p,tau,NULL); if (cx) { long w = ggval(cx, p); if (w) v += w * itos((GEN)pr[3]); } return v; } static GEN compute_raygen(GEN nf, GEN u1, GEN gen, GEN bid) { GEN f, fZ, basecl, module, fa, fa2, *listpr, *listep, *vecinvpi, *vectau; GEN pr, t, sqf, EX, sarch, cyc; long i,j,l,lp; /* basecl = generators in factored form */ basecl = compute_fact(nf,u1,gen); module = (GEN)bid[1]; cyc = gmael(bid,2,2); EX = (GEN)cyc[1]; /* exponent of (O/f)^* */ f = (GEN)module[1]; fZ = gcoeff(f,1,1); fa = (GEN)bid[3]; fa2 = (GEN)bid[4]; sarch = (GEN)fa2[lg(fa2)-1]; listpr = (GEN*)fa[1]; listep = (GEN*)fa[2]; lp = lg(listpr); /* sqf = squarefree kernel of f */ sqf = lp <= 2? NULL: idealprodprime(nf, (GEN)listpr); vecinvpi = (GEN*)cgetg(lp, t_VEC); vectau = (GEN*)cgetg(lp, t_VEC); for (i=1; i != 1 */ p1 = arch_mul(to_famat_all((GEN)vecel[j], (GEN)cyc[j]), p1); logs[j] = (long)zideallog(nf,p1,bid); /* = log(genplus[j]) */ } /* [ cyc 0 ] * [-logs hmat] = relation matrix for Cl_f */ h = concatsp( vconcat(diagonal(cyc), gneg_i(logs)), vconcat(zeromat(ngen, Ri), hmat) ); met = smithrel(hnf(h), &U, add_gen? &u1: NULL); clg = cgetg(add_gen? 4: 3, t_VEC); clg[1] = (long)detcyc(met); clg[2] = (long)met; if (add_gen) clg[3] = (long)compute_raygen(nf,u1,genplus,bid); if (!do_init) return gerepilecopy(av, clg); u2 = cgetg(Ri+1,t_MAT); u1 = cgetg(RU+1,t_MAT); u = (GEN)hmatu[2]; for (j=1; j<=RU; j++) { u1[j]=u[j]; setlg(u[j],RU+1); } u += RU; for (j=1; j<=Ri; j++) { u2[j]=u[j]; setlg(u[j],RU+1); } y = cgetg(7,t_VEC); y[1] = (long)bnf; y[2] = (long)bid; y[3] = (long)vecel; y[4] = (long)U; y[5] = (long)clg; u = cgetg(3,t_VEC); y[6] = (long)u; u[1] = lmul(u2, ginv(hmat)); u[2] = (long)lllint_ip(u1,100); return gerepilecopy(av,y); } GEN buchrayinitgen(GEN bnf, GEN ideal) { return buchrayall(bnf,ideal, nf_INIT | nf_GEN); } GEN buchrayinit(GEN bnf, GEN ideal) { return buchrayall(bnf,ideal, nf_INIT); } GEN buchray(GEN bnf, GEN ideal) { return buchrayall(bnf,ideal, nf_GEN); } GEN bnrclass0(GEN bnf, GEN ideal, long flag) { switch(flag) { case 0: flag = nf_GEN; break; case 1: flag = nf_INIT; break; case 2: flag = nf_INIT | nf_GEN; break; default: err(flagerr,"bnrclass"); } return buchrayall(bnf,ideal,flag); } GEN bnrinit0(GEN bnf, GEN ideal, long flag) { switch(flag) { case 0: flag = nf_INIT; break; case 1: flag = nf_INIT | nf_GEN; break; default: err(flagerr,"bnrinit"); } return buchrayall(bnf,ideal,flag); } GEN rayclassno(GEN bnf,GEN ideal) { GEN nf,h,dataunit,racunit,bigres,bid,cycbid,funits,H; long RU,i; gpmem_t av = avma; bnf = checkbnf(bnf); nf = (GEN)bnf[7]; bigres = (GEN)bnf[8]; h = gmael(bigres,1,1); /* class number */ bid = zidealstarinitall(nf,ideal,0); cycbid = gmael(bid,2,2); if (lg(cycbid) == 1) return gerepileuptoint(av, icopy(h)); funits = check_units(bnf,"rayclassno"); RU = lg(funits); racunit = gmael(bigres,4,2); dataunit = cgetg(RU+1,t_MAT); dataunit[1] = (long)zideallog(nf,racunit,bid); for (i=2; i<=RU; i++) dataunit[i] = (long)zideallog(nf,(GEN)funits[i-1],bid); dataunit = concatsp(dataunit, diagonal(cycbid)); H = hnfmodid(dataunit,(GEN)cycbid[1]); /* (Z_K/f)^* / units ~ Z^n / H */ return gerepileuptoint(av, mulii(h, dethnf_i(H))); } GEN quick_isprincipalgen(GEN bnf, GEN x) { GEN z = cgetg(3, t_VEC), gen = gmael3(bnf,8,1,3); GEN idep, ep = isprincipal(bnf,x); /* x \prod g[i]^(-ep[i]) = factorisation of principal ideal */ idep = isprincipalfact(bnf, gen, gneg(ep), x, nf_GENMAT|nf_FORCE); z[1] = (long)ep; z[2] = idep[2]; return z; } GEN isprincipalrayall(GEN bnr, GEN x, long flag) { long i, j, c; gpmem_t av=avma; GEN bnf,nf,bid,matu,vecel,ep,p1,beta,idep,ex,rayclass; GEN divray,genray,alpha,alphaall,racunit,res,funit; checkbnr(bnr); bnf = (GEN)bnr[1]; nf = (GEN)bnf[7]; bid = (GEN)bnr[2]; vecel=(GEN)bnr[3]; matu =(GEN)bnr[4]; rayclass=(GEN)bnr[5]; divray = (GEN)rayclass[2]; c = lg(divray)-1; ex = cgetg(c+1,t_COL); if (c == 0 && !(flag & nf_GEN)) return ex; if (typ(x) == t_VEC && lg(x) == 3) { idep = (GEN)x[2]; x = (GEN)x[1]; } /* precomputed */ else idep = quick_isprincipalgen(bnf, x); ep = (GEN)idep[1]; beta= (GEN)idep[2]; j = lg(ep); for (i=1; i vecel.gen (coprime to bid) */ if (typ(vecel[i]) != t_INT && signe(ep[i])) /* <==> != 1 */ beta = arch_mul(to_famat_all((GEN)vecel[i], negi((GEN)ep[i])), beta); p1 = gmul(matu, concatsp(ep, zideallog(nf,beta,bid))); for (i=1; i<=c; i++) ex[i] = lmodii((GEN)p1[i],(GEN)divray[i]); if (!(flag & nf_GEN)) return gerepileupto(av, ex); /* compute generator */ if (lg(rayclass)<=3) err(talker,"please apply bnrinit(,,1) and not bnrinit(,,0)"); genray = (GEN)rayclass[3]; /* TODO: should be using nf_GENMAT and function should return a famat */ alphaall = isprincipalfact(bnf, genray, gneg(ex), x, nf_GEN | nf_FORCE); if (!gcmp0((GEN)alphaall[1])) err(bugparier,"isprincipalray (bug1)"); res = (GEN)bnf[8]; funit = check_units(bnf,"isprincipalrayall"); alpha = basistoalg(nf,(GEN)alphaall[2]); p1 = zideallog(nf,(GEN)alphaall[2],bid); if (lg(p1) > 1) { GEN mat = (GEN)bnr[6], pol = (GEN)nf[1]; p1 = gmul((GEN)mat[1],p1); if (!gcmp1(denom(p1))) err(bugparier,"isprincipalray (bug2)"); x = reducemodinvertible(p1,(GEN)mat[2]); racunit = gmael(res,4,2); p1 = powgi(gmodulcp(racunit,pol), (GEN)x[1]); for (j=1; j= p, same is true for [L:K] * d_L = t d_K^[L:K] --> check that some q^p divides d_L */ d = absi((GEN)nf[3]); fa = (GEN)auxdecomp(d,0)[2]; /* list of v_q(d_L). Don't check large primes */ if (mod2(d)) i = 1; else { /* q = 2 */ ep = itos((GEN)fa[1]); if ((ep>>1) >= p) return 0; /* 2 | d_K ==> 4 | d_K */ i = 2; } l = lg(fa); for ( ; i < l; i++) { ep = itos((GEN)fa[i]); if (ep >= p) return 0; } return 1; } static GEN dft_bound() { if (DEBUGLEVEL>1) fprintferr("Default bound for regulator: 0.2\n"); return dbltor(0.2); } static GEN regulatorbound(GEN bnf) { long N, R1, R2, R; GEN nf, dKa, p1, c1; nf = (GEN)bnf[7]; N = degpol(nf[1]); if (!isprimitive(nf)) return dft_bound(); dKa = absi((GEN)nf[3]); nf_get_sign(nf, &R1, &R2); R = R1+R2-1; if (!R2 && N<12) c1 = gpowgs(stoi(4),N>>1); else c1 = gpowgs(stoi(N),N); if (cmpii(dKa,c1) <= 0) return dft_bound(); p1 = gsqr(glog(gdiv(dKa,c1),DEFAULTPREC)); p1 = divrs(gmul2n(gpowgs(divrs(mulrs(p1,3),N*(N*N-1)-6*R2),R),R2), N); p1 = mpsqrt(gdiv(p1, hermiteconstant(R))); if (DEBUGLEVEL>1) fprintferr("Mahler bound for regulator: %Z\n",p1); return gmax(p1, dbltor(0.2)); } /* x given by its embeddings */ GEN norm_by_embed(long r1, GEN x) { long i, ru = lg(x)-1; GEN p = (GEN)x[ru]; if (r1 == ru) { for (i=ru-1; i>0; i--) p = gmul(p, (GEN)x[i]); return p; } p = gnorm(p); for (i=ru-1; i>r1; i--) p = gmul(p, gnorm((GEN)x[i])); for ( ; i>0 ; i--) p = gmul(p, (GEN)x[i]); return p; } static int is_unit(GEN M, long r1, GEN x) { gpmem_t av = avma; GEN Nx = ground( norm_by_embed(r1, gmul_mat_smallvec(M,x)) ); int ok = is_pm1(Nx); avma = av; return ok; } /* FIXME: should use smallvectors */ static GEN minimforunits(GEN nf, long BORNE, GEN w) { const long prec = MEDDEFAULTPREC; long n, i, j, k, s, *x, r1, cnt = 0; gpmem_t av = avma; GEN u,r,a,M; double p, norme, normin, normax; double **q,*v,*y,*z; double eps=0.000001, BOUND = BORNE * 1.00001; if (DEBUGLEVEL>=2) { fprintferr("Searching minimum of T2-form on units:\n"); if (DEBUGLEVEL>2) fprintferr(" BOUND = %ld\n",BOUND); flusherr(); } r1 = nf_get_r1(nf); n = degpol(nf[1]); minim_alloc(n+1, &q, &x, &y, &z, &v); M = gprec_w(gmael(nf,5,1), prec); a = gmul(gmael(nf,5,2), realun(prec)); r = sqred1_from_QR(a, prec); for (j=1; j<=n; j++) { v[j] = rtodbl(gcoeff(r,j,j)); for (i=1; i1) { long l = k-1; z[l] = 0; for (j=k; j<=n; j++) z[l] = z[l]+q[l][j]*x[j]; p = x[k]+z[k]; y[l] = y[k]+p*p*v[k]; x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]); k = l; } for(;;) { p = x[k]+z[k]; if (y[k] + p*p*v[k] <= BOUND) break; k++; x[k]--; } } while (k>1); if (!x[1] && y[1]<=eps) break; if (DEBUGLEVEL>8){ fprintferr("."); flusherr(); } if (++cnt == 5000) return NULL; /* too expensive */ p = x[1]+z[1]; norme = y[1] + p*p*v[1] + eps; if (norme > normax) normax = norme; if (is_unit(M,r1, x) && (norme > 2*n /* exclude roots of unity */ || !isnfscalar(element_pow(nf, small_to_col(x), w)))) { if (norme < normin) normin = norme; if (DEBUGLEVEL>=2) { fprintferr("*"); flusherr(); } } x[k]--; } if (DEBUGLEVEL>=2){ fprintferr("\n"); flusherr(); } avma = av; u = cgetg(4,t_VEC); u[1] = lstoi(s<<1); u[2] = (long)dbltor(normax); u[3] = (long)dbltor(normin); return u; } #undef NBMAX static int is_zero(GEN x, long bitprec) { return (gexpo(x) < -bitprec); } static int is_complex(GEN x, long bitprec) { return (!is_zero(gimag(x), bitprec)); } static GEN compute_M0(GEN M_star,long N) { long m1,m2,n1,n2,n3,k,kk,lr,lr1,lr2,i,j,l,vx,vy,vz,vM,prec; GEN pol,p1,p2,p3,p4,p5,p6,p7,p8,p9,u,v,w,r,r1,r2,M0,M0_pro,S,P,M; GEN f1,f2,f3,g1,g2,g3,pg1,pg2,pg3,pf1,pf2,pf3,X,Y,Z; long bitprec = 24, PREC = gprecision(M_star); if (N==2) return gmul2n(gsqr(gach(gmul2n(M_star,-1),PREC)), -1); vM = fetch_var(); M = polx[vM]; vz = fetch_var(); Z = polx[vz]; vy = fetch_var(); Y = polx[vy]; vx = fetch_var(); X = polx[vx]; PREC = PREC>>1; if (!PREC) PREC = DEFAULTPREC; M0 = NULL; m1 = N/3; for (n1=1; n1<=m1; n1++) { m2 = (N-n1)>>1; for (n2=n1; n2<=m2; n2++) { gpmem_t av = avma; n3=N-n1-n2; prec=PREC; if (n1==n2 && n1==n3) /* n1 = n2 = n3 = m1 = N/3 */ { p1=gdivgs(M_star,m1); p2=gaddsg(1,p1); p3=gsubgs(p1,3); p4=gsqrt(gmul(p2,p3),prec); p5=gsubgs(p1,1); u=gun; v=gmul2n(gadd(p5,p4),-1); w=gmul2n(gsub(p5,p4),-1); M0_pro=gmul2n(gmulsg(m1,gadd(gsqr(glog(v,prec)),gsqr(glog(w,prec)))),-2); if (DEBUGLEVEL>2) { fprintferr("[ %ld, %ld, %ld ]: %Z\n",n1,n2,n3,gprec_w(M0_pro,3)); flusherr(); } if (!M0 || gcmp(M0_pro,M0)<0) M0 = M0_pro; } else if (n1==n2 || n2==n3) { /* n3 > N/3 >= n1 */ k = n2; kk = N-2*k; p2=gsub(M_star,gmulgs(X,k)); p3=gmul(gpowgs(stoi(kk),kk),gpowgs(gsubgs(gmul(M_star,p2),kk*kk),k)); pol=gsub(p3,gmul(gmul(gpowgs(stoi(k),k),gpowgs(X,k)),gpowgs(p2,N-k))); prec=gprecision(pol); if (!prec) prec = MEDDEFAULTPREC; r=roots(pol,prec); lr = lg(r); for (i=1; i2) { fprintferr("[ %ld, %ld, %ld ]: %Z\n",n1,n2,n3,gprec_w(M0_pro,3)); flusherr(); } if (!M0 || gcmp(M0_pro,M0)<0) M0 = M0_pro; } } else { f1 = gsub(gadd(gmulsg(n1,X),gadd(gmulsg(n2,Y),gmulsg(n3,Z))), M); f2 = gmulsg(n1,gmul(Y,Z)); f2 = gadd(f2,gmulsg(n2,gmul(X,Z))); f2 = gadd(f2,gmulsg(n3,gmul(X,Y))); f2 = gsub(f2,gmul(M,gmul(X,gmul(Y,Z)))); f3 = gsub(gmul(gpowgs(X,n1),gmul(gpowgs(Y,n2),gpowgs(Z,n3))), gun); /* f1 = n1 X + n2 Y + n3 Z - M */ /* f2 = n1 YZ + n2 XZ + n3 XY */ /* f3 = X^n1 Y^n2 Z^n3 - 1*/ g1=subres(f1,f2); g1=gdiv(g1,content(g1)); g2=subres(f1,f3); g2=gdiv(g2,content(g2)); g3=subres(g1,g2); g3=gdiv(g3,content(g3)); pf1=gsubst(f1,vM,M_star); pg1=gsubst(g1,vM,M_star); pf2=gsubst(f2,vM,M_star); pg2=gsubst(g2,vM,M_star); pf3=gsubst(f3,vM,M_star); pg3=gsubst(g3,vM,M_star); prec=gprecision(pg3); if (!prec) prec = MEDDEFAULTPREC; r=roots(pg3,prec); lr = lg(r); for (i=1; i2) { fprintferr("[ %ld, %ld, %ld ]: %Z\n",n1,n2,n3,gprec_w(M0_pro,3)); flusherr(); } if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro; } } } } if (!M0) avma = av; else M0 = gerepilecopy(av, M0); } } for (i=1;i<=4;i++) (void)delete_var(); return M0? M0: gzero; } static GEN lowerboundforregulator_i(GEN bnf) { long N,R1,R2,RU,i; GEN nf,M0,M,G,bound,minunit,newminunit; GEN vecminim,p1,pol,y; GEN units = check_units(bnf,"bnfcertify"); nf = (GEN)bnf[7]; N = degpol(nf[1]); nf_get_sign(nf, &R1, &R2); RU = R1+R2-1; if (!RU) return gun; G = gmael(nf,5,2); units = algtobasis(bnf,units); minunit = gnorml2(gmul(G, (GEN)units[1])); /* T2(units[1]) */ for (i=2; i<=RU; i++) { newminunit = gnorml2(gmul(G, (GEN)units[i])); if (gcmp(newminunit,minunit) < 0) minunit = newminunit; } if (gexpo(minunit) > 30) return NULL; vecminim = minimforunits(nf, itos(gceil(minunit)), gmael3(bnf,8,4,1)); if (!vecminim) return NULL; bound = (GEN)vecminim[3]; i = gexpo(gsub(bound,minunit)); if (i > -5) err(bugparier,"lowerboundforregulator"); if (DEBUGLEVEL>1) { fprintferr("M* = %Z\n", bound); if (DEBUGLEVEL>2) { p1=polx[0]; pol=gaddgs(gsub(gpowgs(p1,N),gmul(bound,p1)),N-1); p1 = roots(pol,DEFAULTPREC); if (N&1) y=greal((GEN)p1[3]); else y=greal((GEN)p1[2]); M0 = gmul2n(gmulsg(N*(N-1),gsqr(glog(y,DEFAULTPREC))),-2); fprintferr("pol = %Z\n",pol); fprintferr("old method: y = %Z, M0 = %Z\n",y,gprec_w(M0,3)); } } M0 = compute_M0(bound,N); if (DEBUGLEVEL>1) { fprintferr("M0 = %Z\n",gprec_w(M0,3)); flusherr(); } M = gmul2n(gdivgs(gdiv(gpowgs(M0,RU),hermiteconstant(RU)),N),R2); if (gcmp(M, dbltor(0.04)) < 0) return NULL; M = gsqrt(M,DEFAULTPREC); if (DEBUGLEVEL>1) fprintferr("(lower bound for regulator) M = %Z\n",gprec_w(M,3)); return M; } static GEN lowerboundforregulator(GEN bnf) { gpmem_t av = avma; GEN x = lowerboundforregulator_i(bnf); if (!x) { avma = av; x = regulatorbound(bnf); } return x; } /* Compute a square matrix of rank length(beta) associated to a family * (P_i), 1<=i<=length(beta), of primes s.t. N(P_i) = 1 mod pp, and * (P_i,beta[j]) = 1 for all i,j */ static void primecertify(GEN bnf,GEN beta,long pp,GEN big) { long i,j,qq,nbcol,lb,nbqq,ra,N; GEN nf,mat,mat1,qgen,decqq,newcol,Q,g,ord,modpr; ord = NULL; /* gcc -Wall */ nbcol = 0; nf = (GEN)bnf[7]; N = degpol(nf[1]); lb = lg(beta)-1; mat = cgetg(1,t_MAT); qq = 1; for(;;) { qq += 2*pp; qgen = stoi(qq); if (smodis(big,qq)==0 || !isprime(qgen)) continue; decqq = primedec(bnf,qgen); nbqq = lg(decqq)-1; g = NULL; for (i=1; i<=nbqq; i++) { Q = (GEN)decqq[i]; if (!gcmp1((GEN)Q[4])) break; /* Q has degree 1 */ if (!g) { g = lift_intern(gener(qgen)); /* primitive root */ ord = decomp(stoi(qq-1)); } modpr = zkmodprinit(nf, Q); newcol = cgetg(lb+1,t_COL); for (j=1; j<=lb; j++) { GEN t = to_Fp_simple(nf, (GEN)beta[j], modpr); newcol[j] = (long)Fp_PHlog(t,g,qgen,ord); } if (DEBUGLEVEL>3) { if (i==1) fprintferr(" generator of (Zk/Q)^*: %Z\n", g); fprintferr(" prime ideal Q: %Z\n",Q); fprintferr(" column #%ld of the matrix log(b_j/Q): %Z\n", nbcol, newcol); } mat1 = concatsp(mat,newcol); ra = rank(mat1); if (ra==nbcol) continue; if (DEBUGLEVEL>2) fprintferr(" new rank: %ld\n",ra); if (++nbcol == lb) return; mat = mat1; } } } static void check_prime(long p, GEN bnf, GEN cyc, GEN cycgen, GEN fu, GEN mu, GEN big) { gpmem_t av = avma; long i,b, lc = lg(cyc), w = itos((GEN)mu[1]), lf = lg(fu); GEN beta = cgetg(lf+lc, t_VEC); if (DEBUGLEVEL>1) fprintferr(" *** testing p = %ld\n",p); for (b=1; b2) fprintferr(" p divides h(K)\n"); beta[b] = cycgen[b]; } if (w % p == 0) { if (DEBUGLEVEL>2) fprintferr(" p divides w(K)\n"); beta[b++] = mu[2]; } for (i=1; i3) {fprintferr(" Beta list = %Z\n",beta); flusherr();} primecertify(bnf,beta,p,big); avma = av; } long certifybuchall(GEN bnf) { gpmem_t av = avma; long nbgen,i,j,p,N,R1,R2,R,bound; GEN big,nf,reg,rootsofone,funits,gen,p1,gbound,cycgen,cyc; byteptr delta = diffptr; bnf = checkbnf(bnf); nf = (GEN)bnf[7]; N=degpol(nf[1]); if (N==1) return 1; nf_get_sign(nf, &R1, &R2); R = R1+R2-1; funits = check_units(bnf,"bnfcertify"); testprimes(bnf, zimmertbound(N,R2,absi((GEN)nf[3]))); reg = gmael(bnf,8,2); cyc = gmael3(bnf,8,1,2); nbgen = lg(cyc)-1; gen = gmael3(bnf,8,1,3); rootsofone = gmael(bnf,8,4); gbound = ground(gdiv(reg,lowerboundforregulator(bnf))); if (is_bigint(gbound)) err(talker,"sorry, too many primes to check"); bound = itos(gbound); if ((ulong)bound > maxprime()) err(primer1); if (DEBUGLEVEL>1) { fprintferr("\nPHASE 2: are all primes good ?\n\n"); fprintferr(" Testing primes <= B (= %ld)\n\n",bound); flusherr(); } cycgen = check_and_build_cycgen(bnf); for (big=gun,i=1; i<=nbgen; i++) big = mpppcm(big, gcoeff(gen[i],1,1)); for (i=1; i<=nbgen; i++) { p1 = (GEN)cycgen[i]; if (typ(p1) == t_MAT) { GEN h, g = (GEN)p1[1]; for (j=1; j p | some cycgen[i] */ funits = dummycopy(funits); for (i=1; i1) { fprintferr(" Testing primes | h(K)\n\n"); flusherr(); } for (i=1; i bound) check_prime(p,bnf,cyc,cycgen,funits,rootsofone,big); } } avma=av; return 1; } /*******************************************************************/ /* */ /* RAY CLASS FIELDS: CONDUCTORS AND DISCRIMINANTS */ /* */ /*******************************************************************/ /* s: = Cl_f --> Cl_n --> 0, H subgroup of Cl_f (generators given as * HNF on [gen]). Return subgroup s(H) in Cl_n (associated to bnr) */ static GEN imageofgroup0(GEN gen,GEN bnr,GEN H) { long j,l; GEN E,Delta = diagonal(gmael(bnr,5,2)); /* SNF structure of Cl_n */ if (!H || gcmp0(H)) return Delta; l=lg(gen); E=cgetg(l,t_MAT); for (j=1; j 0, compute * furthermore the corresponding H' and output * if all = 1: [[ideal,arch],[hm,cyc,gen],H'] * if all = 2: [[ideal,arch],newbnr,H'] * if all < 0, answer only 1 is module is the conductor, 0 otherwise. */ GEN conductor(GEN bnr, GEN H, long all) { gpmem_t av = avma; long r1,j,k,ep; GEN bnf,nf,gen,bid,ideal,arch,p1,clhray,clhss,fa,arch2,bnr2,P,ex,mod; checkbnrgen(bnr); bnf = (GEN)bnr[1]; bid = (GEN)bnr[2]; clhray = gmael(bnr,5,1); gen = gmael(bnr,5,3); nf = (GEN)bnf[7]; r1 = nf_get_r1(nf); ideal= gmael(bid,1,1); arch = gmael(bid,1,2); if (H && gcmp0(H)) H = NULL; if (H) { p1 = gauss(H, diagonal(gmael(bnr,5,2))); if (!gcmp1(denom(p1))) err(talker,"incorrect subgroup in conductor"); p1 = absi(det(H)); if (egalii(p1, clhray)) H = NULL; else clhray = p1; } /* H = NULL --> trivial subgroup, else precompute isprincipal(gen) */ if (H || all > 0) gen = getgen(bnf, gen); fa = (GEN)bid[3]; P = (GEN)fa[1]; ex = (GEN)fa[2]; mod = cgetg(3,t_VEC); mod[2] = (long)arch; for (k=1; k=0)? itos((GEN)ex[k]): 1; for (j=1; j<=ep; j++) { mod[1] = (long)idealdivpowprime(nf,ideal,pr,gun); clhss = orderofquotient(bnf,mod,H,gen); if (!egalii(clhss,clhray)) break; if (all < 0) { avma = av; return gzero; } ideal = (GEN)mod[1]; } } mod[1] = (long)ideal; arch2 = dummycopy(arch); mod[2] = (long)arch2; for (k=1; k<=r1; k++) if (signe(arch[k])) { arch2[k] = zero; clhss = orderofquotient(bnf,mod,H,gen); if (!egalii(clhss,clhray)) { arch2[k] = un; continue; } if (all < 0) { avma = av; return gzero; } } if (all < 0) { avma = av; return gun; } if (!all) return gerepilecopy(av, mod); bnr2 = buchrayall(bnf,mod,nf_INIT | nf_GEN); p1 = cgetg(4,t_VEC); p1[3] = (long)imageofgroup(gen,bnr2,H); if (all==1) bnr2 = (GEN)bnr2[5]; p1[2] = lcopy(bnr2); p1[1] = lcopy(mod); return gerepileupto(av, p1); } /* etant donne un bnr et un polynome relatif, trouve le groupe des normes correspondant a l'extension relative en supposant qu'elle est abelienne et que le module donnant bnr est multiple du conducteur. */ GEN rnfnormgroup(GEN bnr, GEN polrel) { long i, j, reldeg, sizemat, p, nfac, k; gpmem_t av = avma; GEN bnf,index,discnf,nf,raycl,group,detgroup,fa,greldeg; GEN famo,ep,fac,col; byteptr d = diffptr; checkbnr(bnr); bnf=(GEN)bnr[1]; raycl=(GEN)bnr[5]; nf=(GEN)bnf[7]; polrel = fix_relative_pol(nf,polrel,1); if (typ(polrel)!=t_POL) err(typeer,"rnfnormgroup"); reldeg = degpol(polrel); /* reldeg-th powers are in norm group */ greldeg = stoi(reldeg); group = diagonal(gmod((GEN)raycl[2], greldeg)); for (i=1; i0) err(bugparier,"rnfnormgroup"); cgiv(detgroup); return gerepileupto(av,group); } static int rnf_is_abelian(GEN nf, GEN pol) { GEN ro, rores, nfL, L, mod, d; long i,j, l; nf = checknf(nf); L = rnfequation(nf,pol); mod = dummycopy(L); setvarn(mod, varn(nf[1])); nfL = _initalg(mod, nf_PARTIALFACT, DEFAULTPREC); ro = nfroots(nfL, L); l = lg(ro)-1; if (l != degpol(pol)) return 0; if (isprime(stoi(l))) return 1; ro = Q_remove_denom(ro, &d); if (!d) rores = ro; else { rores = cgetg(l+1, t_VEC); for (i=1; i<=l; i++) rores[i] = (long)rescale_pol((GEN)ro[i], d); } /* assume roots are sorted by increasing degree */ for (i=1; i trivial subgroup, else precompute isprincipal(gen) */ if (H) gen = getgen(bnf,gen); fa = (GEN)bid[3]; P = (GEN)fa[1]; ex = (GEN)fa[2]; mod = cgetg(3,t_VEC); mod[2] = (long)arch; idealrel = flrel? idmat(degpol(nf[1])): gun; for (k=1; k0) { c++; Lpr[c] = Lpr1[i]; Lex[c] = (long)p1; } } } setlg(Lpr,c+1); setlg(Lex,c+1); return y; } static GEN factorpow(GEN fa,long n) { GEN y; if (!n) return trivfact(); y = cgetg(3,t_MAT); y[1] = fa[1]; y[2] = lmulsg(n, (GEN)fa[2]); return y; } /* Etant donne la liste des zidealstarinit et des matrices d'unites * correspondantes, sort la liste des discrayabs. On ne garde pas les modules * qui ne sont pas des conducteurs */ GEN discrayabslist(GEN bnf,GEN lists) { gpmem_t av = avma; long ii,jj,i,j,k,clhss,ep,clhray,lx,ly,r1,degk,nz; long n,R1,lP; GEN hlist,blist,dlist,nf,dkabs,b,h,d; GEN z,ideal,arch,fa,P,ex,idealrel,mod,pr,dlk,arch2,p3,fac; hlist = rayclassnolist(bnf,lists); blist = (GEN)lists[1]; lx = lg(hlist); dlist = cgetg(lx,t_VEC); nf = (GEN)bnf[7]; r1 = nf_get_r1(nf); degk = degpol(nf[1]); dkabs = absi((GEN)nf[3]); nz = 0; dlk = NULL; /* gcc -Wall */ for (ii=1; ii>SHLGVINT)+1; nbfinal = bound-((nbcext-1)<>SHLGVINT)+1; return gmael(vext, cext, i-((cext-1)<>SHLGVINT)+1; mael(vext, cext, i-((cext-1)<nbgen? zeromat(nbgen, lg(U2)-1): gmul(vecextract_i(U, l1, nbgen), U2) ); } else { c = lg(U1)+lg(U2)-1; U = cgetg(c,t_MAT); for (i=1; i>=1) if (kk&1) rowsel[nba++] = nc + jj; setlg(rowsel, nba); rowselect_p(m, mm, rowsel, nc+1); z2[k+1] = lmulii(h, dethnf_i(hnf(mm))); } z = cgetg(3,t_VEC); Lray[j] = (long)z; z[1] = bid[1]; z[2] = (long)z2; } return Lray; } GEN decodemodule(GEN nf, GEN fa) { long n, k, j, fauxpr; gpmem_t av=avma; GEN g,e,id,pr; nf = checknf(nf); if (typ(fa)!=t_MAT || lg(fa)!=3) err(talker,"incorrect factorisation in decodemodule"); n = degpol(nf[1]); id = idmat(n); g = (GEN)fa[1]; e = (GEN)fa[2]; for (k=1; k2) (void)timer2(); bnf = checkbnf(bnf); flbou=0; nf = (GEN)bnf[7]; r1 = nf_get_r1(nf); degk = degpol(nf[1]); fadkabs = factor(absi((GEN)nf[3])); clh = gmael3(bnf,8,1,1); racunit = gmael3(bnf,8,4,2); funits = check_units(bnf,"discrayabslistarchintern"); if (ramip >= 0) square = 0; else { square = 1; ramip = -ramip; if (ramip==1) ramip=0; } nba = 0; allarch = (arch==NULL); if (allarch) { arch=cgetg(r1+1,t_VEC); for (i=1; i<=r1; i++) arch[i]=un; nba=r1; } else if (gcmp0(arch)) { arch=cgetg(r1+1,t_VEC); for (i=1; i<=r1; i++) arch[i]=zero; } else { if (lg(arch)!=r1+1) err(talker,"incorrect archimedean argument in discrayabslistarchintern"); for (i=1; i<=r1; i++) if (signe(arch[i])) nba++; if (nba) mod = cgetg(3,t_VEC); } p1 = cgetg(3,t_VEC); p1[1] = (long)idmat(degk); p1[2] = (long)arch; bidp = zidealstarinitall(nf,p1,0); if (allarch) { matarchunit = logunitmatrix(nf,funits,racunit,bidp); if (r1>15) err(talker,"r1>15 in discrayabslistarchintern"); } else matarchunit = (GEN)NULL; p = cgeti(3); p[1] = evalsigne(1)|evallgef(3); sqbou = (long)sqrt((double)bound) + 1; av = avma; lim = stack_lim(av,1); z = bigcgetvec(bound); for (i=2;i<=bound;i++) putcompobig(z,i,cgetg(1,t_VEC)); if (allarch) bidp = zidealstarinitall(nf,idmat(degk),0); embunit = logunitmatrix(nf,funits,racunit,bidp); putcompobig(z,1, _vec(zsimp(bidp,embunit))); if (DEBUGLEVEL>1) fprintferr("Starting zidealstarunits computations\n"); if (bound > (long)maxprime()) err(primer1); for (p[2]=0; p[2]<=bound; ) { NEXT_PRIME_VIADIFF(p[2], ptdif); if (!flbou && p[2]>sqbou) { if (DEBUGLEVEL>1) fprintferr("\nStarting rayclassno computations\n"); flbou = 1; z = gerepilecopy(av,z); av1 = avma; raylist = bigcgetvec(bound); for (i=1; i<=bound; i++) { sous = getcompobig(z,i); sousray = rayclassnointernarch(sous,clh,matarchunit); putcompobig(raylist,i,sousray); } raylist = gerepilecopy(av1,raylist); z2 = bigcgetvec(sqbou); for (i=1; i<=sqbou; i++) putcompobig(z2,i, gcopy(getcompobig(z,i))); z = z2; } fa = primedec(nf,p); lfa = lg(fa)-1; for (j=1; j<=lfa; j++) { pr = (GEN)fa[j]; p1 = powgi(p,(GEN)pr[4]); if (DEBUGLEVEL>1) { fprintferr("%ld ",p[2]); flusherr(); } if (is_bigint(p1) || (q = (ulong)itos(p1)) > (ulong)bound) continue; fauxpr = stoi((p[2]*degk + itos((GEN)pr[4])-1)*degk + j-1); p2s = q; ideal = pr; cex = 0; while (q <= (ulong)bound) { cex++; bidp = zidealstarinitall(nf,ideal,0); faussefa = to_famat_all(fauxpr, stoi(cex)); embunit = logunitmatrix(nf,funits,racunit,bidp); for (i=q; i<=bound; i+=q) { p1 = getcompobig(z,i/q); lp1 = lg(p1); if (lp1 == 1) continue; p2 = cgetg(lp1,t_VEC); c=0; for (k=1; k 1) p2 = concatsp(pz,p2); putcompobig(z,i,p2); } else { p2 = rayclassnointernarch(p2,clh,matarchunit); pz = getcompobig(raylist,i); if (lg(pz) > 1) p2 = concatsp(pz,p2); putcompobig(raylist,i,p2); } } if (ramip && ramip % p[2]) break; pz = mulss(q,p2s); if (is_bigint(pz) || (q = (ulong)pz[2]) > (ulong)bound) break; ideal = idealmul(nf,ideal,pr); } } if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) err(warnmem,"[1]: discrayabslistarch"); if (!flbou) { if (DEBUGLEVEL>2) fprintferr("avma = %ld, t(z) = %ld ",avma-bot,taille2(z)); z = gerepilecopy(av, z); } else { if (DEBUGLEVEL>2) fprintferr("avma = %ld, t(r) = %ld ",avma-bot,taille2(raylist)); gptr[0]=&z; gptr[1]=&raylist; gerepilemany(av,gptr,2); } if (DEBUGLEVEL>2) { fprintferr("avma = %ld ",avma-bot); flusherr(); } } } if (!flbou) { if (DEBUGLEVEL>1) fprintferr("\nStarting rayclassno computations\n"); z = gerepilecopy(av, z); av1 = avma; raylist = bigcgetvec(bound); for (i=1; i<=bound; i++) { sous = getcompobig(z,i); sousray = rayclassnointernarch(sous,clh,matarchunit); putcompobig(raylist,i,sousray); } } if (DEBUGLEVEL>2) fprintferr("avma = %ld, t(r) = %ld ",avma-bot,taille2(raylist)); raylist = gerepilecopy(av, raylist); if (DEBUGLEVEL>2) { fprintferr("avma = %ld ",avma-bot); msgtimer("zidealstarlist"); } /* following discrayabslist */ if (DEBUGLEVEL>1) { fprintferr("Starting discrayabs computations\n"); flusherr(); } if (allarch) nbarch = 1<1 && ii%100==0) { fprintferr("%ld ",ii); flusherr(); } sous = getcompobig(raylist,ii); ly = lg(sous); sousdisc = cgetg(ly,t_VEC); putcompobig(disclist, square? ii2: ii,sousdisc); for (jj=1; jj>=1) if (kka & 1) nba++; clhray = itos((GEN)clhrayall[karch+1]); for (k2=1,k=1; k<=r1; k++,k2<<=1) { if (karch&k2 && clhray==itos((GEN)clhrayall[karch-k2+1])) { clhray=0; goto LDISCRAY; } } } idealrel = idealrelinit; for (k=1; k<=lP; k++) { fauxpr = (GEN)P[k]; ep = itos((GEN)ex[k]); ffs = itos(fauxpr); /* Hack for NeXTgcc 2.5.8 -- splitting "resp=fs%degk+1" */ fs = ffs/degk; resp = fs%degk; resp++; gprime = stoi((long)(fs/degk)); if (!allarch && nba) { p1 = (GEN)primedec(nf,gprime)[ffs%degk+1]; ideal = idealmulpowprime(nf,ideal,p1,(GEN)ex[k]); } S=0; clhss=0; normi = ii; normps= itos(gpowgs(gprime,resp)); for (j=1; j<=ep; j++) { GEN fad, fad1, fad2; if (clhss==1) S++; else { if (j < ep) { fac2[k] = lstoi(ep-j); fad = fac; } else { fad = cgetg(3,t_MAT); fad1 = cgetg(lP,t_COL); fad[1] = (long)fad1; fad2 = cgetg(lP,t_COL); fad[2] = (long)fad2; for (i=1; i1) err(warnmem,"[2]: discrayabslistarch"); if (DEBUGLEVEL>2) fprintferr("avma = %ld, t(d) = %ld ",avma-bot,taille2(disclist)); disclist = gerepilecopy(av1, disclist); if (DEBUGLEVEL>2) { fprintferr("avma = %ld ",avma-bot); flusherr(); } } } } if (DEBUGLEVEL>2) msgtimer("discrayabs"); return gerepilecopy(av0, disclist); } GEN discrayabslistarch(GEN bnf, GEN arch, long bound) { return discrayabslistarchintern(bnf,arch,bound, 0); } GEN discrayabslistlong(GEN bnf, long bound) { return discrayabslistarchintern(bnf,gzero,bound, 0); } GEN discrayabslistarchsquare(GEN bnf, GEN arch, long bound) { return discrayabslistarchintern(bnf,arch,bound, -1); } /* Let bnr1, bnr2 be such that mod(bnr2) | mod(bnr1), compute the matrix of the surjective map Cl(bnr1) ->> Cl(bnr2) */ GEN bnrGetSurj(GEN bnr1, GEN bnr2) { long nbg, i; GEN gen, M; gen = gmael(bnr1, 5, 3); nbg = lg(gen) - 1; M = cgetg(nbg + 1, t_MAT); for (i = 1; i <= nbg; i++) M[i] = (long)isprincipalray(bnr2, (GEN)gen[i]); return M; } /* Kernel of the above map */ static GEN bnrGetKer(GEN bnr, GEN mod2) { long i, n; gpmem_t av = avma; GEN P,U, bnr2 = buchrayall(bnr,mod2,nf_INIT); P = bnrGetSurj(bnr, bnr2); n = lg(P); P = concatsp(P, diagonal(gmael(bnr2,5,2))); U = (GEN)hnfall(P)[2]; setlg(U,n); for (i=1; i