/* $Id: base3.c,v 1.194.2.1 2006/12/11 14:29:52 kb 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. */ /*******************************************************************/ /* */ /* BASIC NF OPERATIONS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /*******************************************************************/ /* */ /* OPERATIONS OVER NUMBER FIELD ELEMENTS. */ /* represented as column vectors over the integral basis nf[7] */ /* */ /*******************************************************************/ int RgV_isscalar(GEN x) { long lx = lg(x),i; for (i=2; inf, x, D->I), D->p); } static GEN _sqrmod(void *data, GEN x) { eltmod_muldata *D = (eltmod_muldata*)data; return FpC_red(element_sqri(D->nf, x), D->p); } /* x = I-th vector of the Z-basis of Z_K, in Z^n, compute lift(x^n mod p) */ GEN element_powid_mod_p(GEN nf, long I, GEN n, GEN p) { pari_sp av = avma; eltmod_muldata D; long s,N; GEN y; if (typ(n) != t_INT) pari_err(talker,"not an integer exponent in nfpow"); nf = checknf(nf); N = degpol(nf[1]); s = signe(n); if (s < 0) pari_err(talker,"negative power in element_powid_mod_p"); if (!s || I == 1) return gscalcol_i(gen_1,N); D.nf = nf; D.p = p; D.I = I; y = leftright_pow(col_ei(N, I), n, (void*)&D, &_sqrmod, &_mulidmod); return gerepileupto(av,y); } GEN element_mulidid(GEN nf, long i, long j) { long N; GEN tab = get_tab(nf, &N); tab += (i-1)*N; return gel(tab,j); } /* Outputs x.w_i, where w_i is the i-th elt of the integral basis */ GEN element_mulid(GEN nf, GEN x, long i) { long j, k, N; GEN v, tab; if (i==1) return gcopy(x); tab = get_tab(nf, &N); if (typ(x) != t_COL || lg(x) != N+1) pari_err(typeer,"element_mulid"); tab += (i-1)*N; v = cgetg(N+1,t_COL); for (k=1; k<=N; k++) { pari_sp av = avma; GEN s = gen_0; for (j=1; j<=N; j++) { GEN c = gcoeff(tab,k,j); if (signe(c)) s = gadd(s, _mulix(c, gel(x,j))); } gel(v,k) = gerepileupto(av,s); } return v; } /* table of multiplication by wi in ZK = Z[w1,..., wN] */ GEN eltmulid_get_table(GEN nf, long i) { long k,N; GEN m, tab = get_tab(nf, &N); tab += (i-1)*N; m = cgetg(N+1,t_COL); for (k=1; k<=N; k++) m[k] = tab[k]; return m; } /* table of multiplication by x in ZK = Z[w1,..., wN] */ GEN eltmul_get_table(GEN nf, GEN x) { if (typ(x) == t_MAT) return x; else { long i, N = degpol(nf[1]); GEN mul = cgetg(N+1,t_MAT); x = algtobasis_i(nf, x); if (RgV_isscalar(x)) return gscalmat(gel(x,1), N); gel(mul,1) = x; /* assume w_1 = 1 */ for (i=2; i<=N; i++) gel(mul,i) = element_mulid(nf,x,i); return mul; } } /* valuation of integer x, with resp. to prime ideal P above p. * p.P^(-1) = b Z_K, v >= val_p(norm(x)), and N = deg(nf) * [b may be given as the 'multiplication by b' matrix] */ long int_elt_val(GEN nf, GEN x, GEN p, GEN b, GEN *newx) { long i,k,w, N = degpol(nf[1]); GEN r,a,y,mul; mul = (typ(b) == t_MAT)? b: eltmul_get_table(nf, b); y = cgetg(N+1, t_COL); /* will hold the new x */ x = shallowcopy(x); for(w=0;; w++) { for (i=1; i<=N; i++) { /* compute (x.b)_i */ a = mulii(gel(x,1), gcoeff(mul,i,1)); for (k=2; k<=N; k++) a = addii(a, mulii(gel(x,k), gcoeff(mul,i,k))); /* is it divisible by p ? */ gel(y,i) = dvmdii(a,p,&r); if (signe(r)) { if (newx) *newx = x; return w; } } r=x; x=y; y=r; } } long element_val(GEN nf, GEN x, GEN vp) { pari_sp av = avma; long w, vcx, e; GEN cx,p; if (gcmp0(x)) return VERYBIGINT; nf = checknf(nf); checkprimeid(vp); p = gel(vp,1); e = itos(gel(vp,3)); switch(typ(x)) { case t_INT: return e*Z_pval(x,p); case t_FRAC:return e*(Z_pval(gel(x,1),p) - Z_pval(gel(x,2),p)); default: x = algtobasis_i(nf,x); break; } if (RgV_isscalar(x)) return e*ggval(gel(x,1),p); cx = content(x); if (gcmp1(cx)) vcx=0; else { x = gdiv(x,cx); vcx = ggval(cx,p); } w = int_elt_val(nf,x,p,gel(vp,5),NULL); avma = av; return w + vcx*e; } /* polegal without comparing variables */ long polegal_spec(GEN x, GEN y) { long i = lg(x); if (i != lg(y)) return 0; for (i--; i > 1; i--) if (!gequal(gel(x,i),gel(y,i))) return 0; return 1; } GEN coltoalg(GEN nf, GEN x) { return mkpolmod( coltoliftalg(nf, x), gel(nf,1) ); } GEN basistoalg(GEN nf, GEN x) { long tx=typ(x),lx=lg(x),i,j,l; GEN z; nf = checknf(nf); switch(tx) { case t_COL: for (i=1; i= degpol(P)) x = RgX_rem(x,P); return mulmat_pol(gel(nf,8), x); } GEN algtobasis(GEN nf, GEN x) { long tx=typ(x),lx=lg(x),i,N; pari_sp av=avma; GEN z; nf = checknf(nf); switch(tx) { case t_VEC: case t_COL: case t_MAT: z=cgetg(lx,tx); for (i=1; i 0)? gen_0: gen_1; avma = av; return V; } /* return the t_COL vector of signs of x; the matrix of such if x is a vector * of nf elements */ GEN zsigns(GEN nf, GEN x) { long r1, i, l; GEN arch, S; nf = checknf(nf); r1 = nf_get_r1(nf); arch = cgetg(r1+1, t_VECSMALL); for (i=1; i<=r1; i++) arch[i] = i; if (typ(x) != t_VEC) return zsigne(nf, x, arch); l = lg(x); S = cgetg(l, t_MAT); for (i=1; i0; i--) { q = negi(diviiround(gel(x,i), gcoeff(y,i,i))); if (Q) gel(*Q, i) = q; if (signe(q)) x = gadd(x, gmul(q, gel(y,i))); } return x; } /* for internal use...Reduce matrix x modulo matrix y */ GEN reducemodmatrix(GEN x, GEN y) { return reducemodHNF(x, hnfmod(y,detint(y)), NULL); } /* x = y Q + R */ GEN reducemodHNF(GEN x, GEN y, GEN *Q) { long lx = lg(x), i; GEN R = cgetg(lx, t_MAT); if (Q) { GEN q = cgetg(lx, t_MAT); *Q = q; for (i=1; i> 0 at sarch */ GEN set_sign_mod_idele(GEN nf, GEN x, GEN y, GEN idele, GEN sarch) { GEN s, archp, gen; long nba,i; if (!sarch) return y; gen = gel(sarch,2); nba = lg(gen); if (nba == 1) return y; archp = arch_to_perm(gel(idele,2)); s = zsigne(nf, y, archp); if (x) s = gadd(s, zsigne(nf, x, archp)); s = gmul(gel(sarch,3), s); for (i=1; i gexpo(x))? x: y; } /* given an element x in Z_K and an integral ideal y with x, y coprime, outputs an element inverse of x modulo y */ GEN element_invmodideal(GEN nf, GEN x, GEN y) { pari_sp av = avma; GEN a, xh, yh; nf = checknf(nf); if (gcmp1(gcoeff(y,1,1))) return zerocol( degpol(nf[1]) ); yh = get_hnfid(nf, y); switch (typ(x)) { case t_POL: case t_POLMOD: case t_COL: xh = idealhermite_aux(nf,x); break; default: pari_err(typeer,"element_invmodideal"); return NULL; /* not reached */ } a = element_div(nf, hnfmerge_get_1(xh, yh), x); return gerepilecopy(av, nfreducemodideal_i(a, yh)); } static GEN element_sqrmodideal(GEN nf, GEN x, GEN id) { return nfreducemodideal_i(element_sqr(nf,x),id); } static GEN element_mulmodideal(GEN nf, GEN x, GEN y, GEN id) { return x? nfreducemodideal_i(element_mul(nf,x,y),id): algtobasis_i(nf, y); } /* assume k >= 0, ideal in HNF */ GEN element_powmodideal(GEN nf,GEN x,GEN k,GEN ideal) { GEN y = NULL; for(;;) { if (mpodd(k)) y = element_mulmodideal(nf,y,x,ideal); k = shifti(k,-1); if (!signe(k)) break; x = element_sqrmodideal(nf,x,ideal); } return y? y: gscalcol_i(gen_1,degpol(nf[1])); } /* assume k >= 0, assume idele = [HNFideal, arch] */ GEN element_powmodidele(GEN nf,GEN x,GEN k,GEN idele,GEN sarch) { GEN y = element_powmodideal(nf,x,k,gel(idele,1)); if (mpodd(k)) { if (!gcmp1(k)) y = set_sign_mod_idele(nf, x, y, idele, sarch); } else { if (!gcmp0(k)) y = set_sign_mod_idele(nf, NULL, y, idele, sarch); } return y; } /* a * g^n mod id */ static GEN elt_mulpow_modideal(GEN nf, GEN a, GEN g, GEN n, GEN id) { return element_mulmodideal(nf, a, element_powmodideal(nf,g,n,id), id); } /* assume (num(g[i]), id) = 1 for all i. Return prod g[i]^e[i] mod id. * EX = multiple of exponent of (O_K/id)^* */ GEN famat_to_nf_modideal_coprime(GEN nf, GEN g, GEN e, GEN id, GEN EX) { GEN dh, h, n, plus = NULL, minus = NULL, idZ = gcoeff(id,1,1); long i, lx = lg(g); GEN EXo2 = (expi(EX) > 10)? shifti(EX,-1): NULL; if (is_pm1(idZ)) lx = 1; /* id = Z_K */ for (i=1; i 0) plus = elt_mulpow_modideal(nf, plus, h, n, id); else /* sn < 0 */ minus = elt_mulpow_modideal(nf, minus, h, negi(n), id); } if (minus) plus = element_mulmodideal(nf, plus, element_invmodideal(nf,minus,id), id); return plus? plus: gscalcol_i(gen_1, lg(id)-1); } /* given 2 integral ideals x, y in HNF s.t x | y | x^2, compute the quotient (1+x)/(1+y) in the form [[cyc],[gen]], if U != NULL, set *U := ux^-1 */ static GEN zidealij(GEN x, GEN y, GEN *U) { GEN G, p1, cyc; long j, N; /* x^(-1) y = relations between the 1 + x_i (HNF) */ cyc = smithrel(hnf_gauss(x, y), U, &G); N = lg(cyc); G = gmul(x,G); settyp(G, t_VEC); /* new generators */ for (j=1; j= 0) pari_err(talker,"module too large in Fp_shanks"); lbaby = itos(p1)+1; smalltable = cgetg(lbaby+1,t_VEC); g0inv = Fp_inv(g0, p); p1 = x; for (i=1;;i++) { av1 = avma; if (is_pm1(p1)) { avma = av; return stoi(i-1); } gel(smalltable,i) = p1; if (i==lbaby) break; p1 = gerepileuptoint(av1, remii(mulii(p1,g0inv), p)); } giant = remii(mulii(x, Fp_inv(p1,p)), p); p1=cgetg(lbaby+1,t_VEC); perm = gen_sort(smalltable, cmp_IND | cmp_C, cmpii); for (i=1; i<=lbaby; i++) p1[i]=smalltable[perm[i]]; smalltable=p1; p1=giant; av1 = avma; lim=stack_lim(av1,2); for (k=1;;k++) { i=tablesearch(smalltable,p1,cmpii); if (i) { v=addis(mulss(lbaby-1,k),perm[i]); return gerepileuptoint(av,addsi(-1,v)); } p1 = remii(mulii(p1,giant), p); if (low_stack(lim, stack_lim(av1,2))) { if(DEBUGMEM>1) pari_warn(warnmem,"Fp_shanks, k = %ld", k); p1 = gerepileuptoint(av1, p1); } } } /* Pohlig-Hellman */ GEN Fp_PHlog(GEN a, GEN g, GEN p, GEN ord) { pari_sp av = avma; GEN v,t0,a0,b,q,g_q,n_q,ginv0,qj,ginv; GEN fa, ex; long e,i,j,l; if (equalii(g, a)) return gen_1; /* frequent special case */ if (!ord) ord = subis(p,1); if (typ(ord) == t_MAT) { fa = ord; ord= factorback(fa,NULL); } else fa = Z_factor(ord); ex = gel(fa,2); fa = gel(fa,1); l = lg(fa); ginv = Fp_inv(g,p); v = cgetg(l, t_VEC); for (i=1; i5) fprintferr("Pohlig-Hellman: DL mod %Z^%ld\n",q,e); qj = new_chunk(e+1); gel(qj,0) = gen_1; for (j=1; j<=e; j++) gel(qj,j) = mulii(gel(qj,j-1), q); t0 = diviiexact(ord, gel(qj,e)); a0 = Fp_pow(a, t0, p); ginv0 = Fp_pow(ginv, t0, p); /* order q^e */ g_q = Fp_pow(g, diviiexact(ord,q), p); /* order q */ n_q = gen_0; for (j=0; j = Fp^* */ q = diviiexact(ord,ordp); g = FpXQ_pow(g,q,T,p); if (typ(g) == t_POL) g = constant_term(g); } n_q = Fp_PHlog(a,g,p,NULL); if (q) n_q = mulii(q, n_q); return gerepileuptoint(av, n_q); } /* smallest n >= 0 such that g0^n=x modulo pr, assume g0 reduced * N = order of g0 is prime (and != p) */ static GEN ffshanks(GEN x, GEN g0, GEN N, GEN T, GEN p) { pari_sp av = avma, av1, lim; long lbaby,i,k; GEN p1,smalltable,giant,perm,v,g0inv; if (!degpol(x)) x = constant_term(x); if (typ(x) == t_INT) { if (!gcmp1(modii(p,N))) return gen_0; /* g0 in Fp^*, order N | (p-1) */ if (typ(g0) == t_POL) g0 = constant_term(g0); return Fp_PHlog(x,g0,p,N); } p1 = sqrti(N); if (cmpiu(p1,LGBITS) >= 0) pari_err(talker,"module too large in ffshanks"); lbaby = itos(p1)+1; smalltable = cgetg(lbaby+1,t_VEC); g0inv = Fq_inv(g0,T,p); p1 = x; for (i=1;;i++) { if (gcmp1(p1)) { avma = av; return stoi(i-1); } gel(smalltable,i) = p1; if (i==lbaby) break; av1 = avma; p1 = gerepileupto(av1, FpXQ_mul(p1,g0inv, T,p)); } giant = FpXQ_div(x,p1,T,p); perm = gen_sort(smalltable, cmp_IND | cmp_C, cmp_pol); smalltable = vecpermute(smalltable, perm); p1 = giant; av1 = avma; lim=stack_lim(av1,2); for (k=1;;k++) { i = tablesearch(smalltable,p1,cmp_pol); if (i) { v = addis(mulss(lbaby-1,k), perm[i]); return gerepileuptoint(av, addsi(-1,v)); } p1 = FpXQ_mul(p1, giant, T,p); if (low_stack(lim, stack_lim(av1,2))) { if(DEBUGMEM>1) pari_warn(warnmem,"ffshanks"); p1 = gerepileupto(av1, p1); } } } /* same in Fp[X]/T */ GEN ff_PHlog(GEN a, GEN g, GEN T, GEN p) { pari_sp av = avma; GEN v,t0,a0,b,q,g_q,n_q,ginv0,qj,ginv,ord,fa,ex; long e,i,j,l; if (typ(a) == t_INT) return gerepileuptoint(av, ff_PHlog_Fp(a,g,T,p)); /* f > 1 ==> T != NULL */ ord = subis(powiu(p, degpol(T)), 1); fa = factor(ord); ex = gel(fa,2); fa = gel(fa,1); l = lg(fa); ginv = Fq_inv(g,T,p); v = cgetg(l, t_VEC); for (i=1; i5) fprintferr("nf_Pohlig-Hellman: DL mod %Z^%ld\n",q,e); qj = new_chunk(e+1); gel(qj,0) = gen_1; for (j=1; j<=e; j++) gel(qj,j) = mulii(gel(qj,j-1), q); t0 = diviiexact(ord, gel(qj,e)); a0 = FpXQ_pow(a, t0, T,p); ginv0 = FpXQ_pow(ginv, t0, T,p); /* order q^e */ g_q = FpXQ_pow(g, diviiexact(ord,q), T,p); /* order q */ n_q = gen_0; for (j=0; j k) return gerepilecopy(av0, g); } } /* Given an ideal pr^ep, and an integral ideal x (in HNF form) compute a list * of vectors,corresponding to the abelian groups (O_K/pr)^*, and * 1 + pr^i/ 1 + pr^min(2i, ep), i = 1,... * Each vector has 5 components as follows : * [[cyc],[g],[g'],[sign],U.X^-1]. * cyc = type as abelian group * g, g' = generators. (g',x) = 1, not necessarily so for g * sign = vector of the sign(g') at arch. * If x = NULL, the original ideal was a prime power */ static GEN zprimestar(GEN nf, GEN pr, GEN ep, GEN x, GEN arch) { pari_sp av = avma; long a, b, e = itos(ep), f = itos(gel(pr,4)); GEN p = gel(pr,1), list, g, g0, y, u,v, prh, prb, pre; if(DEBUGLEVEL>3) fprintferr("treating pr^%ld, pr = %Z\n",e,pr); if (f == 1) g = gscalcol_i(gener_Fp(p), degpol(nf[1])); else { GEN T, modpr = zk_to_ff_init(nf, &pr, &T, &p); g = ff_to_nf(FpXQ_gener(T,p), modpr); g = poltobasis(nf, g); } /* g generates (Z_K / pr)^* */ prh = prime_to_ideal(nf,pr); pre = (e==1)? prh: idealpow(nf,pr,ep); g0 = g; u = v = NULL; /* gcc -Wall */ if (x) { GEN uv = idealaddtoone(nf,pre, idealdivpowprime(nf,x,pr,ep)); u = gel(uv,1); v = gel(uv,2); v = eltmul_get_table(nf, v); g0 = makeprimetoideal(x,u,v,g); } list = cget1(e+1, t_VEC); y = cgetg(6,t_VEC); appendL(list, y); gel(y,1) = mkvec(addis(powiu(p,f), -1)); gel(y,2) = mkvec(g); gel(y,3) = mkvec(g0); gel(y,4) = mkvec(zsigne(nf,g0,arch)); gel(y,5) = gen_1; prb = prh; for (a = b = 1; a < e; a = b) { GEN pra = prb, gen, z, s, U; long i, l; b <<= 1; /* compute 1 + pr^a / 1 + pr^b, 2a <= b */ if(DEBUGLEVEL>3) fprintferr(" treating a = %ld, b = %ld\n",a,b); prb = (b >= e)? pre: idealpows(nf,pr,b); z = zidealij(pra, prb, &U); gen = shallowcopy(gel(z,2)); l = lg(gen); s = cgetg(l, t_VEC); if(DEBUGLEVEL>3) fprintferr("zidealij done\n"); for (i = 1; i < l; i++) { if (x) gel(gen,i) = makeprimetoideal(x,u,v,gel(gen,i)); gel(s,i) = zsigne(nf,gel(gen,i),arch); } y = cgetg(6,t_VEC); appendL(list, y); y[1] = z[1]; y[2] = z[2]; gel(y,3) = gen; gel(y,4) = s; gel(y,5) = U; } return gerepilecopy(av, list); } /* increment y, which runs through [-d,d]^k. Return 0 when done. */ static int increment(GEN y, long k, long d) { long i = 0, j; do { if (++i > k) return 0; y[i]++; } while (y[i] > d); for (j = 1; j < i; j++) y[j] = -d; return 1; } GEN archstar_full_rk(GEN x, GEN bas, GEN v, GEN gen) { long i, r, lgmat, N = lg(bas)-1, nba = lg(v[1]) - 1; GEN lambda = cgetg(N+1, t_VECSMALL), mat = cgetg(nba+1,t_MAT); lgmat = lg(v); setlg(mat, lgmat+1); for (i = 1; i < lgmat; i++) mat[i] = v[i]; for ( ; i <= nba; i++) gel(mat,i) = cgetg(nba+1, t_VECSMALL); if (x) { x = lllint_ip(x,4); bas = gmul(bas, x); } for (r=1;; r++) { /* reset */ (void)vec_setconst(lambda, (GEN)0); if (!x) lambda[1] = r; while (increment(lambda, N, r)) { pari_sp av1 = avma; GEN a = RgM_zc_mul(bas, lambda), c = gel(mat,lgmat); for (i = 1; i <= nba; i++) { GEN t = x? gadd(gel(a,i), gen_1): gel(a,i); c[i] = (gsigne(t) < 0)? 1: 0; } avma = av1; if (Flm_deplin(mat, 2)) continue; /* c independant of previous sign vectors */ if (!x) a = zc_to_ZC(lambda); else { a = ZM_zc_mul(x, lambda); gel(a,1) = addis(gel(a,1), 1); } gel(gen,lgmat) = a; if (lgmat++ == nba) return Flm_to_ZM( Flm_inv(mat,2) ); /* full rank */ setlg(mat,lgmat+1); } } } /* x integral ideal, compute elements in 1+x (in x, if x = zk) whose sign * matrix is invertible */ GEN zarchstar(GEN nf, GEN x, GEN archp) { long i, nba; pari_sp av; GEN p1, y, bas, gen, mat, gZ, v; archp = arch_to_perm(archp); nba = lg(archp) - 1; y = cgetg(4,t_VEC); if (!nba) { gel(y,1) = cgetg(1,t_VEC); gel(y,2) = cgetg(1,t_VEC); gel(y,3) = cgetg(1,t_MAT); return y; } p1 = cgetg(nba+1,t_VEC); for (i=1; i<=nba; i++) gel(p1,i) = gen_2; gel(y,1) = p1; av = avma; if (gcmp1(gcoeff(x,1,1))) x = NULL; /* x = O_K */ gZ = x? subsi(1, gcoeff(x,1,1)): gen_m1; /* gZ << 0, gZ = 1 mod x */ if (nba == 1) { gel(y,2) = mkvec(gZ); gel(y,3) = gscalmat(gen_1,1); return y; } bas = gmael(nf,5,1); if (lg(bas[1]) > lg(archp)) bas = rowpermute(bas, archp); gen = cgetg(nba+1,t_VEC); v = mkmat( const_vecsmall(nba, 1) ); gel(gen,1) = gZ; mat = archstar_full_rk(x, bas, v, gen); gerepileall(av,2,&gen,&mat); gel(y,2) = gen; gel(y,3) = mat; return y; } static GEN zlog_pk(GEN nf, GEN a0, GEN y, GEN pr, GEN prk, GEN list, GEN *psigne) { GEN a = a0, L, e, cyc, gen, s, U; long i,j, llist = lg(list)-1; for (j = 1; j <= llist; j++) { L = gel(list,j); cyc = gel(L,1); gen = gel(L,2); s = gel(L,4); U = gel(L,5); if (j == 1) e = mkcol( nf_PHlog(nf, a, gel(gen,1), pr) ); else if (typ(a) == t_INT) e = gmul(subis(a, 1), gel(U,1)); else { /* t_COL */ GEN t = gel(a,1); gel(a,1) = addsi(-1, gel(a,1)); /* a -= 1 */ e = gmul(U, a); gel(a,1) = t; /* restore */ } /* here lg(e) == lg(cyc) */ for (i = 1; i < lg(cyc); i++) { GEN t = modii(negi(gel(e,i)), gel(cyc,i)); gel(++y,0) = negi(t); if (!signe(t)) continue; if (mod2(t)) *psigne = *psigne? gadd(*psigne, gel(s,i)): gel(s,i); if (j != llist) a = elt_mulpow_modideal(nf, a, gel(gen,i), t, prk); } } return y; } static void zlog_add_sign(GEN y0, GEN sgn, GEN lists) { GEN y, s; long i; if (!sgn) return; y = y0 + lg(y0); s = gmul(gmael(lists, lg(lists)-1, 3), sgn); for (i = lg(s)-1; i > 0; i--) gel(--y,0) = mpodd(gel(s,i))? gen_1: gen_0; } static GEN famat_zlog(GEN nf, GEN g, GEN e, GEN sgn, GEN bid) { GEN vp = gmael(bid, 3,1), ep = gmael(bid, 3,2), arch = gmael(bid,1,2); GEN cyc = gmael(bid,2,2), lists = gel(bid,4), U = gel(bid,5); GEN y0, x, y, EX = gel(cyc,1); long i, l; y0 = y = cgetg(lg(U), t_COL); if (!sgn) sgn = zsigne(nf, to_famat(g,e), arch); l = lg(vp); for (i=1; i < l; i++) { GEN pr = gel(vp,i), prk; prk = (l==2)? gmael(bid,1,1): idealpow(nf, pr, gel(ep,i)); /* FIXME: FIX group exponent (should be mod prk, not f !) */ x = famat_makecoprime(nf, g, e, pr, prk, EX); y = zlog_pk(nf, x, y, pr, prk, gel(lists,i), &sgn); } zlog_add_sign(y0, sgn, lists); return y0; } static GEN get_index(GEN lists) { long t = 0, j, k, l = lg(lists)-1; GEN L, ind = cgetg(l+1, t_VECSMALL); for (k = 1; k < l; k++) { L = gel(lists,k); ind[k] = t; for (j=1; jn = n; S->U = U; S->P = P; S->e = e; S->archp = arch_to_perm(arch); S->lists = lists; S->ind = get_index(lists); } void init_zlog_bid(zlog_S *S, GEN bid) { GEN ideal = gel(bid,1), fa = gel(bid,3), fa2 = gel(bid,4), U = gel(bid,5); GEN arch = (typ(ideal)==t_VEC && lg(ideal)==3)? gel(ideal,2): NULL; init_zlog(S, lg(U)-1, gel(fa,1), gel(fa,2), arch, fa2, U); } /* Return decomposition of a on the S->nf successive generators contained in * S->lists. If index !=0, do the computation for the corresponding prime * ideal and set to 0 the other components. */ static GEN zlog_ind(GEN nf, GEN a, zlog_S *S, GEN sgn, long index) { GEN y0 = zerocol(S->n), y, list, pr, prk; pari_sp av = avma; long i, k, kmin, kmax; if (typ(a) != t_INT) a = algtobasis_i(nf,a); if (DEBUGLEVEL>3) { fprintferr("entering zlog, "); flusherr(); if (DEBUGLEVEL>5) fprintferr("with a = %Z\n",a); } if (index) { kmin = kmax = index; y = y0 + S->ind[index]; } else { kmin = 1; kmax = lg(S->P)-1; y = y0; } if (!sgn) sgn = zsigne(nf, a, S->archp); for (k = kmin; k <= kmax; k++) { list= (GEN)S->lists[k]; pr = (GEN)S->P[k]; prk = idealpow(nf, pr, (GEN)S->e[k]); y = zlog_pk(nf, a, y, pr, prk, list, &sgn); } zlog_add_sign(y0, sgn, S->lists); if (DEBUGLEVEL>3) { fprintferr("leaving\n"); flusherr(); } avma = av; for (i=1; i <= S->n; i++) gel(y0,i) = icopy(gel(y0,i)); return y0; } /* sgn = sign(a, S->arch) or NULL if unknown */ GEN zlog(GEN nf, GEN a, GEN sgn, zlog_S *S) { return zlog_ind(nf, a, S, sgn, 0); } /* Log on bid.gen of generators of P_{1,I pr^{e-1}} / P_{1,I pr^e} (I,pr) = 1, * defined implicitly via CRT. 'index' is the index of pr in modulus * factorization */ GEN log_gen_pr(zlog_S *S, long index, GEN nf, long e) { long i, l, yind = S->ind[index]; GEN y, A, L, L2 = (GEN)S->lists[index]; if (e == 1) { L = gel(L2,1); y = zerocol(S->n); gel(y, yind+1) = gen_1; zlog_add_sign(y, gmael(L,4,1), S->lists); A = mkmat(y); } else { GEN pr = (GEN)S->P[index], prk, g; if (e == 2) L = gel(L2,2); else L = zidealij(idealpows(nf,pr,e-1), idealpows(nf,pr,e), NULL); g = gel(L,2); l = lg(g); A = cgetg(l, t_MAT); prk = idealpow(nf, pr, (GEN)S->e[index]); for (i = 1; i < l; i++) { GEN G = gel(g,i), sgn = NULL; /* positive at f_oo */ y = zerocol(S->n); (void)zlog_pk(nf, G, y + yind, pr, prk, L2, &sgn); zlog_add_sign(y, sgn, S->lists); gel(A,i) = y; } } return gmul(S->U, A); } /* Log on bid.gen of generator of P_{1,f} / P_{1,f v[index]} * v = vector of r1 real places */ GEN log_gen_arch(zlog_S *S, long index) { GEN y = zerocol(S->n); zlog_add_sign(y, col_ei(lg(S->archp)-1, index), S->lists); return gmul(S->U, y); } static GEN compute_gen(GEN nf, GEN u1, GEN gen, GEN bid) { long i, c = lg(u1); GEN L = cgetg(c,t_VEC); for (i=1; i3 && lg(G2)>3)? gen_1: NULL; nbgen = l1+l2-2; cyc = smithrel(diagonal_i(shallowconcat(cyc1,cyc2)), &U, gen? &u1: NULL); if (nbgen) { GEN U1 = gel(bid1,5), U2 = gel(bid2,5); U1 = l1 == 1? zeromat(nbgen,lg(U1)-1): gmul(vecslice(U, 1, l1-1), U1); U2 = l2 == 1? zeromat(nbgen,lg(U2)-1): gmul(vecslice(U, l1, nbgen), U2); U = shallowconcat(U1, U2); } else U = zeromat(0, lx-2); if (gen) { GEN u, v, uv = idealaddtoone(nf,gel(f1,1),gel(f2,1)); u = gel(uv,1); v = gel(uv,2); gen = shallowconcat(makeprimetoidealvec(nf,x,u,v, gel(G1,3)), makeprimetoidealvec(nf,x,v,u, gel(G2,3))); } y = cgetg(6,t_VEC); gel(y,1) = mkvec2(x, gel(f1,2)); gel(y,3) = fa; gel(y,4) = lists; gel(y,5) = U; add_clgp(nf, u1, cyc, gen, y); return gerepilecopy(av,y); } /* bid1 = for module m1 (without arch. part), arch = archimedean part. * Output: bid [[m1,arch],[h,[cyc],[gen]],idealfact,[liste],U] for m1.arch */ static GEN join_bid_arch(GEN nf, GEN bid1, GEN arch) { pari_sp av = avma; long i, lx1; GEN f1, G1, fa1, lists1, U; GEN lists, cyc, y, u1 = NULL, x, sarch, gen; checkbid(bid1); f1 = gel(bid1,1); G1 = gel(bid1,2); fa1 = gel(bid1,3); x = gel(f1,1); sarch = zarchstar(nf, x, arch); lists1 = gel(bid1,4); lx1 = lg(lists1); lists = cgetg(lx1,t_VEC); for (i=1; i3)? gen_1: NULL; cyc = diagonal_i(shallowconcat(gel(G1,2), gel(sarch,1))); cyc = smithrel(cyc, &U, gen? &u1: NULL); if (gen) gen = shallowconcat(gel(G1,3), gel(sarch,2)); y = cgetg(6,t_VEC); gel(y,1) = mkvec2(x, arch); gel(y,3) = fa1; gel(y,4) = lists; gel(y,5) = U; add_clgp(nf, u1, cyc, gen, y); return gerepilecopy(av,y); } #if 0 /* could be useful somewhere else */ /* z <- ( z | f(v[i])_{i=1..#v} )*/ void concatmap(GEN *pz, GEN v, GEN (*f)(void*,GEN), void *data) { long i, nz, lv = lg(v); GEN z, Z, Zt; if (lv == 1) return; z = *pz; nz = lg(z)-1; Z = cgetg(lv + nz, typ(z)); for (i = 1; i <=nz; i++) Z[i] = z[i]; Zt = Z + nz; for (i = 1; i < lv; i++) gel(Zt,i) = f(data, gel(v,i)); *pz = Z; } #endif typedef struct _ideal_data { GEN nf, emb, L, pr, prL, arch, sgnU; } ideal_data; static void concat_join(GEN *pz, GEN v, GEN (*f)(ideal_data*,GEN), ideal_data *data) { long i, nz, lv = lg(v); GEN z, Z, Zt; if (lv == 1) return; z = *pz; nz = lg(z)-1; Z = cgetg(lv + nz, typ(z)); for (i = 1; i <=nz; i++) Z[i] = z[i]; Zt = Z + nz; for (i = 1; i < lv; i++) gel(Zt,i) = f(data, gel(v,i)); *pz = Z; } static GEN join_idealinit(ideal_data *D, GEN x) { return join_bid(D->nf, x, D->prL); } static GEN join_ideal(ideal_data *D, GEN x) { return idealmulpowprime(D->nf, x, D->pr, D->L); } static GEN join_unit(ideal_data *D, GEN x) { return mkvec2(join_idealinit(D, gel(x,1)), vconcat(gel(x,2), D->emb)); } /* compute matrix of zlogs of units */ GEN zlog_units(GEN nf, GEN U, GEN sgnU, GEN bid) { long j, l = lg(U); GEN m = cgetg(l, t_MAT); zlog_S S; init_zlog_bid(&S, bid); for (j = 1; j < l; j++) gel(m,j) = zlog(nf, gel(U,j), vecpermute(gel(sgnU,j), S.archp), &S); return m; } /* compute matrix of zlogs of units, assuming S.archp = [] */ GEN zlog_units_noarch(GEN nf, GEN U, GEN bid) { long j, l = lg(U); GEN m = cgetg(l, t_MAT), empty = cgetg(1, t_COL); zlog_S S; init_zlog_bid(&S, bid); for (j = 1; j < l; j++) gel(m,j) = zlog(nf, gel(U,j), empty, &S); return m; } /* calcule la matrice des zlog des unites */ static GEN zlog_unitsarch(GEN sgnU, GEN bid) { GEN U, liste = gel(bid,4), arch = gmael(bid,1,2); long i; U = gmul(gmael(liste, lg(liste)-1, 3), rowpermute(sgnU, arch_to_perm(arch))); for (i = 1; i < lg(U); i++) (void)F2V_red_ip(gel(U,i)); return U; } /* flag &1 : generators, otherwise no * flag &2 : units, otherwise no * flag &4 : ideals in HNF, otherwise bid */ static GEN Ideallist(GEN bnf, ulong bound, long flag) { const long do_gen = flag & 1, do_units = flag & 2, big_id = !(flag & 4); byteptr ptdif = diffptr; pari_sp lim, av, av0 = avma; long i, j, l; GEN nf, z, p, fa, id, U, empty = cgetg(1,t_VEC); ideal_data ID; GEN (*join_z)(ideal_data*, GEN) = do_units? &join_unit : (big_id? &join_idealinit: &join_ideal); nf = checknf(bnf); if ((long)bound <= 0) return empty; id = matid(degpol(nf[1])); if (big_id) id = Idealstar(nf,id,do_gen); /* z[i] will contain all "objects" of norm i. Depending on flag, this means * an ideal, a bid, or a couple [bid, log(units)]. Such objects are stored * in vectors, computed one primary component at a time; join_z * reconstructs the global object */ z = cgetg(bound+1,t_VEC); if (do_units) { U = init_units(bnf); gel(z,1) = mkvec( mkvec2(id, zlog_units_noarch(nf, U, id)) ); } else { U = NULL; /* -Wall */ gel(z,1) = mkvec(id); } for (i=2; i<=(long)bound; i++) gel(z,i) = empty; ID.nf = nf; p = cgeti(3); p[1] = evalsigne(1) | evallgefint(3); av = avma; lim = stack_lim(av,1); maxprime_check(bound); for (p[2] = 0; (ulong)p[2] <= bound; ) { NEXT_PRIME_VIADIFF(p[2], ptdif); if (DEBUGLEVEL>1) { fprintferr("%ld ",p[2]); flusherr(); } fa = primedec(nf, p); for (j=1; j bound) break; z2 = shallowcopy(z); q = Q; ID.pr = ID.prL = pr; for (l=1; Q <= bound; l++, Q *= q) /* add pr^l */ { ID.L = utoipos(l); if (big_id) { if (l > 1) ID.prL = idealpow(nf,pr,ID.L); ID.prL = Idealstar(nf,ID.prL,do_gen); if (do_units) ID.emb = zlog_units_noarch(nf, U, ID.prL); } for (iQ = Q,i = 1; iQ <= bound; iQ += Q,i++) concat_join(&gel(z,iQ), gel(z2,i), join_z, &ID); } } if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) pari_warn(warnmem,"Ideallist"); z = gerepilecopy(av, z); } } if (do_units) for (i = 1; i < lg(z); i++) { GEN s = gel(z,i); long l = lg(s); for (j = 1; j < l; j++) { GEN v = gel(s,j), bid = gel(v,1); gel(v,2) = gmul(gel(bid,5), gel(v,2)); } } return gerepilecopy(av0, z); } GEN ideallist0(GEN bnf,long bound, long flag) { if (flag<0 || flag>4) pari_err(flagerr,"ideallist"); return Ideallist(bnf,bound,flag); } GEN ideallistzstar(GEN nf,long bound) { return Ideallist(nf,bound,0); } GEN ideallistzstargen(GEN nf,long bound) { return Ideallist(nf,bound,1); } GEN ideallistunit(GEN nf,long bound) { return Ideallist(nf,bound,2); } GEN ideallistunitgen(GEN nf,long bound) { return Ideallist(nf,bound,3); } GEN ideallist(GEN bnf,long bound) { return Ideallist(bnf,bound,4); } static GEN join_arch(ideal_data *D, GEN x) { return join_bid_arch(D->nf, x, D->arch); } static GEN join_archunit(ideal_data *D, GEN x) { GEN bid = join_arch(D, gel(x,1)), U = gel(x,2); U = gmul(gel(bid,5), vconcat(U, zlog_unitsarch(D->sgnU, bid))); return mkvec2(bid, U); } /* L from ideallist, add archimedean part */ GEN ideallistarch(GEN bnf, GEN L, GEN arch) { pari_sp av; long i, j, l = lg(L), lz; GEN v, z, V; ideal_data ID; GEN (*join_z)(ideal_data*, GEN) = &join_arch; if (typ(L) != t_VEC) pari_err(typeer, "ideallistarch"); if (l == 1) return cgetg(1,t_VEC); z = gel(L,1); if (typ(z) != t_VEC) pari_err(typeer, "ideallistarch"); z = gel(z,1); /* either a bid or [bid,U] */ if (lg(z) == 3) { /* the latter: do units */ if (typ(z) != t_VEC) pari_err(typeer,"ideallistarch"); join_z = &join_archunit; ID.sgnU = zsignunits(bnf, NULL, 1); } ID.nf = checknf(bnf); arch = arch_to_perm(arch); av = avma; V = cgetg(l, t_VEC); for (i = 1; i < l; i++) { z = gel(L,i); lz = lg(z); gel(V,i) = v = cgetg(lz,t_VEC); for (j=1; j