/* $Id: buch4.c 7838 2006-04-08 12:11:17Z kb $ 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 "paripriv.h" static int psquare(GEN a,GEN p) { long v; GEN ap; if (!signe(a) || gcmp1(a)) return 1; v = Z_pvalrem(a, p, &ap); if (v&1) return 0; return equaliu(p, 2)? umodiu(ap, 8) == 1 : kronecker(ap,p) == 1; } static long lemma6(GEN pol,GEN p,long nu,GEN x) { long lambda, mu; pari_sp ltop=avma; GEN gx, gpx; gx = poleval(pol, x); if (psquare(gx,p)) return 1; gpx = poleval(derivpol(pol), x); lambda = Z_pval(gx, p); mu = gcmp0(gpx)? BIGINT: Z_pval(gpx,p); 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 odd4, lambda, mu, mnl; pari_sp ltop = avma; GEN gx, gpx, oddgx; gx = poleval(pol, x); if (psquare(gx,gen_2)) return 1; gpx = poleval(derivpol(pol), x); lambda = Z_lvalrem(gx, 2, &oddgx); mu = gcmp0(gpx)? BIGINT: vali(gpx); mnl = mu+nu-lambda; odd4 = umodiu(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; pari_sp ltop=avma; GEN x,pnup; result = equaliu(p,2)? lemma7(pol,nu,x0): lemma6(pol,p,nu,x0); if (result== 1) return 1; if (result==-1) return 0; x = gcopy(x0); pnup = mulii(pnu,p); for (i=0; i < itos(p); i++) { x = addii(x,pnu); if (zpsol(pol,p,nu+1,pnup,x)) { avma=ltop; return 1; } } avma=ltop; return 0; } /* vaut 1 si l'equation y^2=Pol(x) a une solution p-adique entiere * 0 sinon. Les coefficients sont entiers. */ long zpsoluble(GEN pol,GEN p) { if ((typ(pol)!=t_POL && typ(pol)!=t_INT) || typ(p)!=t_INT ) pari_err(typeer,"zpsoluble"); return zpsol(pol,p,0,gen_1,gen_0); } /* vaut 1 si l'equation y^2=Pol(x) a une solution p-adique rationnelle * (eventuellement infinie), 0 sinon. Les coefficients sont entiers. */ long qpsoluble(GEN pol,GEN p) { if ((typ(pol)!=t_POL && typ(pol)!=t_INT) || typ(p)!=t_INT ) pari_err(typeer,"qpsoluble"); if (zpsol(pol,p,0,gen_1,gen_0)) return 1; return zpsol(polrecip(pol),p,1,p,gen_0); } /* is t a square in (O_K/pr), assume v_pr(t) >= 0 ? */ static long quad_char(GEN nf, GEN t, GEN pr) { GEN ord, ordp, T, p, modpr = nf_to_ff_init(nf, &pr,&T,&p); t = nf_to_ff(nf,t,modpr); if (T) { ord = subis( pr_norm(pr), 1 ); /* |(O_K / pr)^*| */ ordp= subis( p, 1); /* |F_p^*| */ t = Fq_pow(t, diviiexact(ord, ordp), T,p); /* in F_p^* */ if (typ(t) == t_POL) { if (degpol(t)) pari_err(bugparier,"nfhilbertp"); t = constant_term(t); } } return kronecker(t, p); } /* (pr,2) = 1. return 1 if a square in (ZK / pr), 0 otherwise */ static long psquarenf(GEN nf,GEN a,GEN pr) { pari_sp av = avma; long v; if (gcmp0(a)) return 1; v = idealval(nf,a,pr); if (v&1) return 0; if (v) a = gdiv(a, gpowgs(coltoalg(nf, gel(pr,2)), v)); v = quad_char(nf, a, pr); avma = av; return v; } static long check2(GEN nf, GEN a, GEN zinit) { GEN zlog = zideallog(nf,a,zinit), cyc = gmael(zinit,2,2); long i, l = lg(cyc); for (i=1; i mu<<1) return 1; if (lambda >= nu<<1 && mu >= nu) return 0; return -1; } static long lemma7nf(GEN nf,GEN pol,GEN pr,long nu,GEN x,GEN zinit) { long res, lambda, mu, q; GEN gx, gpx, p1; gx = poleval(pol, x); if (psquare2nf(nf,gx,pr,zinit)) return 1; lambda = element_val(nf,gx,pr); gpx = poleval(derivpol(pol), x); mu = gcmp0(gpx)? BIGINT: idealval(nf,gpx,pr); if (lambda > (mu<<1)) return 1; if (nu > mu) { if (lambda&1) return -1; q=mu+nu-lambda; res=1; } else { if (lambda>=(nu<<1)) return 0; if (lambda&1) return -1; q=(nu<<1)-lambda; res=0; } if (q > itos(gel(pr,3))<<1) return -1; p1 = gpowgs(coltoalg(nf, gel(pr,2)), lambda); zinit = zidealstarinit(nf, idealpows(nf,pr,q)); if (!check2(nf,gdiv(gx,p1),zinit)) res = -1; return res; } static long zpsolnf(GEN nf,GEN pol,GEN pr,long nu,GEN pnu,GEN x0,GEN repr,GEN zinit) { long i, result; pari_sp ltop=avma; GEN pnup; result = zinit? lemma7nf(nf,pol,pr,nu,x0,zinit) : lemma6nf(nf,pol,pr,nu,x0); avma = ltop; if (result== 1) return 1; if (result==-1) return 0; pnup = gmul(pnu, coltoalg(nf,gel(pr,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,gel(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); } /* 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) { pari_sp 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) pari_err(typeer,"bnfsunit"); bnf = checkbnf(bnf); nf=gel(bnf,7); classgp=gmael(bnf,8,1); gen = gel(classgp,3); sreg = gmael(bnf,8,2); res=cgetg(7,t_VEC); gel(res,1) = gel(res,2) = gel(res,3) = cgetg(1,t_VEC); gel(res,4) = sreg; gel(res,5) = classgp; gel(res,6) = 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 U, D = smithall(H, &U, NULL); D = mattodiagonal_i(D); card = detcyc(D, &i); setlg(D,i); p1=cgetg(i,t_VEC); pow=ZM_inv(U,gen_1); for(i--; i; i--) gel(p1,i) = factorback_i(gen, gel(pow,i), nf, 1); gel(res,5) = mkvec3(card,D,p1); } /* S-units */ if (ls>1) { GEN den, Sperm, perm, dep, B, A, 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) pari_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 1) *px = famat_mul(xp, to_famat_all(xb, gen_1)); return v; } /* Analog to isunit, for S-units. Let v the result * If x not an S-unit, v = []~, else * x = \prod_{i=0}^r e_i^v[i] * prod{i=r+1}^{r+s} s_i^v[i] * where the e_i are the field units (cf isunit), and the s_i are * the S-units computed by bnfsunit (in the same order) */ GEN bnfissunit(GEN bnf,GEN bnfS,GEN x) { pari_sp av = avma; GEN v, w, nf; bnf = checkbnf(bnf); nf = checknf(bnf); if (typ(bnfS)!=t_VEC || lg(bnfS)!=7) pari_err(typeer,"bnfissunit"); switch (typ(x)) { case t_INT: case t_FRAC: case t_POL: case t_COL: x = basistoalg(nf,x); break; case t_POLMOD: break; default: pari_err(typeer,"bnfissunit"); } v = NULL; if ( (w = make_unit(nf, bnfS, &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 (dvdii(*prod, p)) return; *prod = mulii(*prod, p); *S1 = shallowconcat(*S1, primedec(nf,p)); *S2 = shallowconcat(*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= 0) pari_err(talker,"main variable must be of higher priority in rnfisnorminit"); rnfeq = NULL; /* no reltoabs needed */ if (degpol(nf[1]) == 1) { /* over Q */ polabs = lift(relpol); k = gen_0; } else { if (galois == 2 && drel > 2) { /* needs reltoabs */ rnfeq = rnfequation2(bnf, relpol); polabs = gel(rnfeq,1); gel(rnfeq,2) = lift_intern(gel(rnfeq,2)); k = gel(rnfeq,3); } else { long sk; polabs = rnfequation_i(bnf, relpol, &sk, NULL); k = stoi(sk); } } if (!bnfabs || !gcmp0(k)) bnfabs = bnfinit0(polabs, 1, NULL, nfgetprec(nf)); if (!nfabs) nfabs = checknf(bnfabs); if (galois < 0 || galois > 2) pari_err(flagerr, "rnfisnorminit"); if (galois == 2) { GEN P = rnfeq? pol_up(rnfeq, relpol, vbas): relpol; galois = nfisgalois(gsubst(nfabs, varn(nfabs[1]), pol_x[vbas]), P); } prod = gen_1; S1 = S2 = cgetg(1, t_VEC); res = gmael(bnfabs,8,1); cyc = gel(res,2); gen = gel(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) { pari_sp av = avma; GEN bnf = gel(T,1), rel = gel(T,2), relpol = gel(T,3), theta = gel(T,4); GEN nf, aux, H, U, Y, M, A, bnfS, sunitrel, futu, tu, w, prod, S1, S2; long L, i, drel, itu; if (typ(T) != t_VEC || lg(T) != 9) pari_err(talker,"please apply rnfisnorminit first"); bnf = checkbnf(bnf); rel = checkbnf(rel); nf = checknf(bnf); x = basistoalg(nf,x); if (typ(x) != t_POLMOD) pari_err(typeer, "rnfisnorm"); drel = degpol(relpol); if (gcmp0(x) || gcmp1(x) || (gcmp_1(x) && odd(drel))) { GEN res = cgetg(3, t_VEC); gel(res,1) = simplify(gel(x,2)); gel(res,2) = gen_1; return res; } /* build set T of ideals involved in the solutions */ prod = gel(T,5); S1 = gel(T,6); S2 = gel(T,7); if (flag && !gcmp0(gel(T,8))) pari_warn(warner,"useless flag in rnfisnorm: the extension is Galois"); if (flag > 0) { byteptr d = diffptr; long p = 0; maxprime_check((ulong)flag); for(;;) { NEXT_PRIME_VIADIFF(p, d); if (p > flag) break; pr_append(nf,rel, utoipos(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 = shallowconcat(check_units(rel,"rnfisnorm"), tu); bnfS = bnfsunit(bnf,S1,3); sunitrel = gel(bnfsunit(rel,S2,3), 1); if (lg(sunitrel) > 1) sunitrel = lift_intern(basistoalg(rel, sunitrel)); sunitrel = shallowconcat(futu, sunitrel); A = lift(bnfissunit(bnf,bnfS,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