/* $Id: buch4.c,v 1.36 2002/09/10 14:47:04 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. */ /*******************************************************************/ /* */ /* S-CLASS GROUP AND NORM SYMBOLS */ /* (Denis Simon, desimon@math.u-bordeaux.fr) */ /* */ /*******************************************************************/ #include "pari.h" #include "parinf.h" extern GEN to_polmod(GEN x, GEN mod); extern GEN hnfall0(GEN A, long remove); extern GEN get_theta_abstorel(GEN T, GEN pol, GEN k); extern GEN _rnfequation(GEN A, GEN B, long *pk, GEN *pLPRS); static long psquare(GEN a,GEN p) { long v; GEN ap; if (gcmp0(a) || gcmp1(a)) return 1; if (!cmpis(p,2)) { v=vali(a); if (v&1) return 0; return (smodis(shifti(a,-v),8)==1); } ap=stoi(1); v=pvaluation(a,p,&ap); if (v&1) return 0; return (kronecker(ap,p)==1); } static long lemma6(GEN pol,GEN p,long nu,GEN x) { long i, lambda, mu; gpmem_t ltop=avma; GEN gx,gpx; for (i=lgef(pol)-2,gx=(GEN) pol[i+1]; i>1; i--) gx=addii(mulii(gx,x),(GEN) pol[i]); if (psquare(gx,p)) return 1; for (i=lgef(pol)-2,gpx=mulis((GEN) pol[i+1],i-1); i>2; i--) gpx=addii(mulii(gpx,x),mulis((GEN) pol[i],i-2)); lambda=pvaluation(gx,p,&gx); if (gcmp0(gpx)) mu=BIGINT; else mu=pvaluation(gpx,p,&gpx); avma=ltop; if (lambda>(mu<<1)) return 1; if (lambda>=(nu<<1) && mu>=nu) return 0; return -1; } static long lemma7(GEN pol,long nu,GEN x) { long i,odd4,lambda,mu,mnl; gpmem_t ltop=avma; GEN gx,gpx,oddgx; for (i=lgef(pol)-2,gx=(GEN) pol[i+1]; i>1; i--) gx=addii(mulii(gx,x),(GEN) pol[i]); if (psquare(gx,gdeux)) return 1; for (i=lgef(pol)-2,gpx=gmulgs((GEN) pol[i+1],i-1); i>2; i--) gpx=gadd(gmul(gpx,x),gmulgs((GEN) pol[i],i-2)); lambda=vali(gx); if (gcmp0(gpx)) mu=BIGINT; else mu=vali(gpx); oddgx=shifti(gx,-lambda); mnl=mu+nu-lambda; odd4=smodis(oddgx,4); avma=ltop; if (lambda>(mu<<1)) return 1; if (nu > mu) { if (mnl==1 && (lambda&1) == 0) return 1; if (mnl==2 && (lambda&1) == 0 && odd4==1) return 1; } else { if (lambda>=(nu<<1)) return 0; if (lambda==((nu-1)<<1) && odd4==1) return 0; } return -1; } static long zpsol(GEN pol,GEN p,long nu,GEN pnu,GEN x0) { long i, result; gpmem_t ltop=avma; GEN x,pnup; result = (cmpis(p,2)) ? lemma6(pol,p,nu,x0) : lemma7(pol,nu,x0); if (result==+1) return 1; if (result==-1) return 0; x=gcopy(x0); pnup=mulii(pnu,p); for (i=0; i0); } static long check2(GEN nf, GEN a, GEN zinit) { GEN zlog=zideallog(nf,a,zinit), p1 = gmael(zinit,2,2); long i; for (i=1; i1; i--) gx = gadd(gmul(gx,x),(GEN) pol[i]); if (psquarenf(nf,gx,p)) { avma=ltop; return 1; } lambda = idealval(nf,gx,p); for (i=lgef(pol)-2,gpx=gmulgs((GEN) pol[i+1],i-1); i>2; i--) gpx=gadd(gmul(gpx,x),gmulgs((GEN) pol[i],i-2)); mu = gcmp0(gpx)? BIGINT: idealval(nf,gpx,p); avma=ltop; if (lambda > mu<<1) return 1; if (lambda >= nu<<1 && mu >= nu) return 0; return -1; } static long lemma7nf(GEN nf,GEN pol,GEN p,long nu,GEN x,GEN zinit) { long res, i, lambda, mu, q; gpmem_t ltop=avma; GEN gx,gpx,p1; for (i=lgef(pol)-2, gx=(GEN) pol[i+1]; i>1; i--) gx=gadd(gmul(gx,x),(GEN) pol[i]); if (psquare2nf(nf,gx,p,zinit)) { avma=ltop; return 1; } lambda=idealval(nf,gx,p); for (i=lgef(pol)-2,gpx=gmulgs((GEN) pol[i+1],i-1); i>2; i--) gpx=gadd(gmul(gpx,x),gmulgs((GEN) pol[i],i-2)); if (!gcmp0(gpx)) mu=idealval(nf,gpx,p); else mu=BIGINT; if (lambda>(mu<<1)) { avma=ltop; return 1; } if (nu > mu) { if (lambda&1) { avma=ltop; return -1; } q=mu+nu-lambda; res=1; } else { if (lambda>=(nu<<1)) { avma=ltop; return 0; } if (lambda&1) { avma=ltop; return -1; } q=(nu<<1)-lambda; res=0; } if (q > itos((GEN) p[3])<<1) { avma=ltop; return -1; } p1 = gmodulcp(gpowgs(gmul((GEN)nf[7],(GEN)p[2]), lambda), (GEN)nf[1]); if (!psquare2qnf(nf,gdiv(gx,p1), p,q)) res = -1; avma=ltop; return res; } static long zpsolnf(GEN nf,GEN pol,GEN p,long nu,GEN pnu,GEN x0,GEN repr,GEN zinit) { long i, result; gpmem_t ltop=avma; GEN pnup; nf=checknf(nf); if (cmpis((GEN) p[1],2)) result=lemma6nf(nf,pol,p,nu,x0); else result=lemma7nf(nf,pol,p,nu,x0,zinit); if (result== 1) return 1; if (result==-1) return 0; pnup = gmul(pnu, basistoalg(nf,(GEN)p[2])); nu++; for (i=1; i=4) fprintferr("nfhilbert not soluble at real place %ld\n",i); avma = av; return -1; } /* local solutions in finite completions ? (pr | 2ab) * primes above 2 are toughest. Try the others first */ S = (GEN) idealfactor(nf,gmul(gmulsg(2,a),b))[1]; /* product of all hilbertp is 1 ==> remove one prime (above 2!) */ for (i=lg(S)-1; i>1; i--) if (nfhilbertp(nf,a,b,(GEN) S[i]) < 0) { if (DEBUGLEVEL >=4) fprintferr("nfhilbert not soluble at finite place: %Z\n",S[i]); avma = av; return -1; } avma = av; return 1; } long nfhilbert0(GEN nf,GEN a,GEN b,GEN p) { if (p) return nfhilbertp(nf,a,b,p); return nfhilbert(nf,a,b); } extern GEN isprincipalfact(GEN bnf,GEN P, GEN e, GEN C, long flag); extern GEN vconcat(GEN Q1, GEN Q2); extern GEN mathnfspec(GEN x, GEN *ptperm, GEN *ptdep, GEN *ptB, GEN *ptC); extern GEN factorback_i(GEN fa, GEN e, GEN nf, int red); extern GEN detcyc(GEN cyc); /* S a list of prime ideal in primedec format. Return res: * res[1] = generators of (S-units / units), as polynomials * res[2] = [perm, HB, den], for bnfissunit * res[3] = [] (was: log. embeddings of res[1]) * res[4] = S-regulator ( = R * det(res[2]) * \prod log(Norm(S[i]))) * res[5] = S class group * res[6] = S */ GEN bnfsunit(GEN bnf,GEN S,long prec) { gpmem_t ltop = avma; long i,j,ls; GEN p1,nf,classgp,gen,M,U,H; GEN sunit,card,sreg,res,pow; if (typ(S) != t_VEC) err(typeer,"bnfsunit"); bnf = checkbnf(bnf); nf=(GEN)bnf[7]; classgp=gmael(bnf,8,1); gen = (GEN)classgp[3]; sreg = gmael(bnf,8,2); res=cgetg(7,t_VEC); res[1]=res[2]=res[3]=lgetg(1,t_VEC); res[4]=(long)sreg; res[5]=(long)classgp; res[6]=(long)S; ls=lg(S); /* M = relation matrix for the S class group (in terms of the class group * generators given by gen) * 1) ideals in S */ M = cgetg(ls,t_MAT); for (i=1; i 1) { /* non trivial (rare!) */ GEN D,U, ClS = cgetg(4,t_VEC); D = smithall(H, &U, NULL); for(i=1; i1) { GEN den, Sperm, perm, dep, B, U1 = U; long lH, lB, fl = nf_GEN|nf_FORCE; /* U1 = upper left corner of U, invertible. S * U1 = principal ideals * whose generators generate the S-units */ setlg(U1,ls); p1 = cgetg(ls, t_MAT); /* p1 is junk for mathnfspec */ for (i=1; i 1 && lg(dep[1]) > 1) err(bugparier,"bnfsunit"); /* [ H B ] [ H^-1 - H^-1 B ] * perm o HNF(U1) = [ 0 Id ], inverse = [ 0 Id ] * (permute the rows) * S * HNF(U1) = _integral_ generators for S-units = sunit */ Sperm = cgetg(ls, t_VEC); sunit = cgetg(ls, t_VEC); for (i=1; i 0) xp = gmul(xp, gpowgs(p1, k)); else xm = gmul(xm, gpowgs(p1,-k)); } if (xp != gun) *px = gmul(*px,xp); if (xm != gun) *px = gdiv(*px,xm); return v; } /* cette fonction est l'equivalent de isunit, sauf qu'elle donne le resultat * avec des s-unites: si x n'est pas une s-unite alors issunit=[]~; * si x est une s-unite alors * x=\prod_{i=0}^r {e_i^issunit[i]}*prod{i=r+1}^{r+s} {s_i^issunit[i]} * ou les e_i sont les unites du corps (comme dans isunit) * et les s_i sont les s-unites calculees par sunit (dans le meme ordre). */ GEN bnfissunit(GEN bnf,GEN suni,GEN x) { gpmem_t av = avma; GEN v, w; bnf = checkbnf(bnf); if (typ(suni)!=t_VEC || lg(suni)!=7) err(typeer,"bnfissunit"); switch (typ(x)) { case t_INT: case t_FRAC: case t_FRACN: case t_POL: case t_COL: x = basistoalg(bnf,x); break; case t_POLMOD: break; default: err(typeer,"bnfissunit"); } v = NULL; if ( (w = make_unit(bnf, suni, &x)) ) v = isunit(bnf, x); if (!v || lg(v) == 1) { avma = av; return cgetg(1,t_COL); } return gerepileupto(av, concat(v, w)); } static void pr_append(GEN nf, GEN rel, GEN p, GEN *prod, GEN *S1, GEN *S2) { if (divise(*prod, p)) return; *prod = mulii(*prod, p); *S1 = concatsp(*S1, primedec(nf,p)); *S2 = concatsp(*S2, primedec(rel,p)); } static void fa_pr_append(GEN nf,GEN rel,GEN N,GEN *prod,GEN *S1,GEN *S2) { if (!is_pm1(N)) { GEN v = (GEN)factor(N)[1]; long i, l = lg(v); for (i=1; i 2) { /* needs reltoabs */ rnfeq = rnfequation2(bnf, relpol); polabs = (GEN)rnfeq[1]; k = (GEN)rnfeq[3]; } else { long sk; polabs = _rnfequation(bnf, relpol, &sk, NULL); k = stoi(sk); } } if (!rel || !gcmp0(k)) rel = bnfinit0(polabs, 1, NULL, nfgetprec(nf)); if (!nfrel) nfrel = checknf(rel); if (galois < 0 || galois > 2) err(flagerr, "rnfisnorminit"); if (galois == 2) { GEN P = rnfeq? pol_up(rnfeq, relpol): relpol; galois = nfisgalois(gsubst(nfrel, varn(P), polx[varn(T)]), P); } prod = gun; S1 = S2 = cgetg(1, t_VEC); res = gmael(rel,8,1); cyc = (GEN)res[2]; gen = (GEN)res[3]; l = lg(cyc); for(i=1; i answer is unconditional) * if flag>0 add to S all primes dividing p <= flag * if flag<0 add to S all primes dividing abs(flag) * answer is a vector v = [a,b] such that * x = N(a)*b and x is a norm iff b = 1 [assuming S large enough] */ GEN rnfisnorm(GEN T, GEN x, long flag) { gpmem_t av = avma; GEN bnf = (GEN)T[1], rel = (GEN)T[2], relpol = (GEN)T[3], theta = (GEN)T[4]; GEN nf, aux, H, Y, M, A, suni, sunitrel, futu, tu, w; GEN prod, S1, S2; GEN res = cgetg(3,t_VEC); long L, i, drel, itu; if (typ(T) != t_VEC || lg(T) != 9) err(talker,"please apply rnfisnorminit first"); bnf = checkbnf(bnf); rel = checkbnf(rel); nf = checknf(bnf); x = basistoalg(nf,x); if (typ(x) != t_POLMOD) err(typeer, "rnfisnorm"); drel = degpol(relpol); if (gcmp0(x) || gcmp1(x) || (gcmp_1(x) && odd(drel))) { res[1] = (long)x; res[2] = un; return res; } /* build set T of ideals involved in the solutions */ prod = (GEN)T[5]; S1 = (GEN)T[6]; S2 = (GEN)T[7]; if (flag && !gcmp0((GEN)T[8])) err(warner,"useless flag in rnfisnorm: the extension is Galois"); if (flag > 0) { byteptr d = diffptr; long p = 0; if (maxprime() < flag) err(primer1); for(;;) { NEXT_PRIME_VIADIFF(p, d); if (p > flag) break; pr_append(nf,rel,stoi(p),&prod,&S1,&S2); } } else if (flag < 0) fa_pr_append(nf,rel,stoi(-flag),&prod,&S1,&S2); /* overkill: prime ideals dividing x would be enough */ fa_pr_append(nf,rel,idealnorm(nf,x), &prod,&S1,&S2); /* computation on T-units */ w = gmael3(rel,8,4,1); tu = gmael3(rel,8,4,2); futu = concatsp(check_units(rel,"rnfisnorm"), tu); suni = bnfsunit(bnf,S1,3); sunitrel = (GEN)bnfsunit(rel,S2,3)[1]; if (lg(sunitrel) > 1) sunitrel = lift_intern(basistoalg(rel,sunitrel)); sunitrel = concatsp(futu, sunitrel); A = lift(bnfissunit(bnf,suni,x)); L = lg(sunitrel); itu = lg(nf[6])-1; /* index of torsion unit in bnfsunit(nf) output */ M = cgetg(L+1,t_MAT); for (i=1; i