/* $Id: base3.c,v 1.87 2002/09/08 17:09:39 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. */ /*******************************************************************/ /* */ /* BASIC NF OPERATIONS */ /* */ /*******************************************************************/ #include "pari.h" extern GEN u_FpM_deplin(GEN x, ulong p); extern GEN u_FpM_inv(GEN a, ulong p); extern GEN famat_ideallog(GEN nf, GEN g, GEN e, GEN bid); extern GEN famat_to_nf_modidele(GEN nf, GEN g, GEN e, GEN bid); extern GEN vconcat(GEN A, GEN B); /*******************************************************************/ /* */ /* OPERATIONS OVER NUMBER FIELD ELEMENTS. */ /* These are always represented as column vectors over the */ /* integral basis nf[7] */ /* */ /*******************************************************************/ int isnfscalar(GEN x) { long lx=lg(x),i; if (typ(x) != t_COL) return 0; for (i=2; inf, x, D->I), D->p); } static GEN _sqrmod(void *data, GEN x) { eltmod_muldata *D = (eltmod_muldata*)data; return FpV_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) { gpmem_t av = avma; eltmod_muldata D; long s,N; GEN y; if (typ(n)!=t_INT) err(talker,"not an integer exponent in nfpow"); nf=checknf(nf); N=degpol(nf[1]); s=signe(n); if (!s || I == 1) return gscalcol_i(gun,N); y = zerocol(N); y[I] = un; D.nf = nf; D.p = p; D.I = I; y = leftright_pow(y,n, (void*)&D, &_sqrmod, &_mulidmod); if (s < 0) y = FpV_red(element_inv(nf,y), p); return av==avma? gcopy(y): 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 (GEN)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) { gpmem_t av; long j,k,N; GEN s,v,c,p1, tab; if (i==1) return gcopy(x); tab = get_tab(nf, &N); if (typ(x) != t_COL || lg(x) != N+1) err(typeer,"element_mulid"); tab += (i-1)*N; v=cgetg(N+1,t_COL); av=avma; for (k=1; k<=N; k++) { s = gzero; for (j=1; j<=N; j++) if (signe(c = gcoeff(tab,k,j)) && !gcmp0(p1 = (GEN)x[j])) { if (!gcmp1(c)) p1 = gmul(p1,c); s = gadd(s,p1); } v[k]=lpileupto(av,s); av=avma; } 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; 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) { long i, N = degpol(nf[1]); GEN mul = cgetg(N+1,t_MAT); if (typ(x) != t_COL) x = algtobasis(nf,x); mul[1] = (long)x; /* assume w_1 = 1 */ for (i=2; i<=N; i++) mul[i] = (long)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 = dummycopy(x); for(w=0;; w++) { for (i=1; i<=N; i++) { /* compute (x.b)_i */ a = mulii((GEN)x[1], gcoeff(mul,i,1)); for (k=2; k<=N; k++) a = addii(a, mulii((GEN)x[k], gcoeff(mul,i,k))); /* is it divisible by p ? */ y[i] = ldvmdii(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) { gpmem_t av = avma; long N,w,vcx,e; GEN cx,p; if (gcmp0(x)) return VERYBIGINT; nf=checknf(nf); N=degpol(nf[1]); checkprimeid(vp); p=(GEN)vp[1]; e=itos((GEN)vp[3]); switch(typ(x)) { case t_INT: case t_FRAC: case t_FRACN: return ggval(x,p)*e; case t_POLMOD: x = (GEN)x[2]; /* fall through */ case t_POL: x = algtobasis_i(nf,x); break; case t_COL: if (lg(x)==N+1) break; default: err(typeer,"element_val"); } if (isnfscalar(x)) return ggval((GEN)x[1],p)*e; cx = content(x); if (gcmp1(cx)) vcx=0; else { x = gdiv(x,cx); vcx = ggval(cx,p); } w = int_elt_val(nf,x,p,(GEN)vp[5],NULL); avma=av; return w + vcx*e; } /* polegal without comparing variables */ long polegal_spec(GEN x, GEN y) { long i = lgef(x); if (i != lgef(y)) return 0; for (i--; i > 1; i--) if (!gegal((GEN)x[i],(GEN)y[i])) return 0; return 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= N) x = gres(x,P); return mulmat_pol((GEN)nf[8], x); } return gscalcol(x,N); } GEN algtobasis(GEN nf, GEN x) { long tx=typ(x),lx=lg(x),i,N; gpmem_t 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)? _0: _1); return vecsign; } } x = Q_primpart(x); for (j=i=1; i 0)? (long)_0: (long)_1; avma = av; setlg(vecsign,j); return vecsign; } /* 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_VEC); for (i=1; i<=r1; i++) arch[i] = un; 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((GEN)x[i], gcoeff(y,i,i))); if (Q) (*Q)[i] = (long)q; if (signe(q)) x = gadd(x, gmul(q, (GEN)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,arch,gen; long nba,i; if (!sarch) return y; gen = (GEN)sarch[2]; nba = lg(gen); if (nba == 1) return y; arch = (GEN)idele[2]; s = zsigne(nf,y,arch); if (x) s = gadd(s, zsigne(nf,x,arch)); s = lift_intern(gmul((GEN)sarch[3],s)); for (i=1; i gexpo(x))? x: y; } GEN element_powmodideal(GEN nf,GEN x,GEN k,GEN ideal) { GEN y = gscalcol_i(gun,degpol(nf[1])); for(;;) { if (mpodd(k)) y=element_mulmodideal(nf,x,y,ideal); k=shifti(k,-1); if (!signe(k)) return y; x = element_sqrmodideal(nf,x,ideal); } } GEN element_powmodidele(GEN nf,GEN x,GEN k,GEN idele,GEN sarch) { GEN y = element_powmodideal(nf,x,k,idele); 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; } /* H relation matrix among row of generators g. Let URV = D its SNF, newU R * newV = newD its clean SNF (no 1 in Dnew). Return the diagonal of newD, * newU and newUi such that 1/U = (newUi, ?). * Rationale: let (G,0) = g Ui be the new generators then * 0 = G U R --> G D = 0, g = G newU and G = g newUi */ GEN smithrel(GEN H, GEN *newU, GEN *newUi) { GEN U,Ui,D,p1; long l,c; D = smithall(H, &U, NULL); l = lg(D); for (c=1; c= 0) err(talker,"module too large in Fp_shanks"); lbaby=itos(p1)+1; smalltable=cgetg(lbaby+1,t_VEC); g0inv = mpinvmod(g0, p); p1 = x; c = 3 * lgefint(p); for (i=1;;i++) { av1 = avma; if (is_pm1(p1)) { avma=av; return stoi(i-1); } smalltable[i]=(long)p1; if (i==lbaby) break; (void)new_chunk(c); p1 = mulii(p1,g0inv); /* HACK */ avma = av1; p1 = resii(p1, p); } giant = resii(mulii(x, mpinvmod(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 = resii(mulii(p1,giant), p); if (low_stack(lim, stack_lim(av1,2))) { if(DEBUGMEM>1) err(warnmem,"Fp_shanks, k = %ld", k); p1 = gerepileuptoint(av1, p1); } } } /* Pohlig-Hellman */ GEN Fp_PHlog(GEN a, GEN g, GEN p, GEN ord) { gpmem_t av = avma; GEN v,t0,a0,b,q,g_q,n_q,ginv0,qj,ginv; GEN fa, ex; long e,i,j,l; if (!ord) ord = subis(p,1); if (typ(ord) == t_MAT) { fa = ord; ord= factorback(fa,NULL); } else fa = decomp(ord); if (typ(g) == t_INTMOD) g = lift_intern(g); ex = (GEN)fa[2]; fa = (GEN)fa[1]; l = lg(fa); ginv = mpinvmod(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); qj[0] = un; for (j=1; j<=e; j++) qj[j] = lmulii((GEN)qj[j-1], q); t0 = divii(ord, (GEN)qj[e]); a0 = powmodulo(a, t0, p); ginv0 = powmodulo(ginv, t0, p); /* order q^e */ g_q = powmodulo(g, divii(ord,q), p); /* order q */ n_q = gzero; for (j=0; j = Fp^* */ q = divii(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 * q = order of g0 is prime (and != p) */ static GEN ffshanks(GEN x, GEN g0, GEN q, GEN T, GEN p) { gpmem_t 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,q))) return gzero; /* g0 in Fp^*, order q | (p-1) */ if (typ(g0) == t_POL) g0 = constant_term(g0); return Fp_PHlog(x,g0,p,q); } p1 = racine(q); if (cmpis(p1,LGBITS) >= 0) err(talker,"module too large in ffshanks"); lbaby = itos(p1)+1; smalltable = cgetg(lbaby+1,t_VEC); g0inv = FpXQ_inv(g0,T,p); p1 = x; for (i=1;;i++) { if (gcmp1(p1)) { avma = av; return stoi(i-1); } smalltable[i]=(long)p1; if (i==lbaby) break; p1 = FpXQ_mul(p1,g0inv, T,p); } giant = FpXQ_div(x,p1,T,p); perm = gen_sort(smalltable, cmp_IND | cmp_C, cmp_pol); smalltable = vecextract_p(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) err(warnmem,"ffshanks"); p1 = gerepileupto(av1, p1); } } } /* same in Fp[X]/T */ GEN ff_PHlog(GEN a, GEN g, GEN T, GEN p) { gpmem_t 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(gpowgs(p, degpol(T)), 1); fa = factor(ord); ex = (GEN)fa[2]; fa = (GEN)fa[1]; l = lg(fa); ginv = FpXQ_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); qj[0] = un; for (j=1; j<=e; j++) qj[j] = lmulii((GEN)qj[j-1], q); t0 = divii(ord, (GEN)qj[e]); a0 = FpXQ_pow(a, t0, T,p); ginv0 = FpXQ_pow(ginv, t0, T,p); /* order q^e */ g_q = FpXQ_pow(g, divii(ord,q), T,p); /* order q */ n_q = gzero; 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, each with 5 components as follows : * [[clh],[gen1],[gen2],[signat2],U.X^-1]. Each component corresponds to * d_i,g_i,g'_i,s_i. Generators g_i are not necessarily prime to x, the * generators g'_i are. signat2 is the (horizontal) vector made of the * signatures (column vectors) of the g'_i. If x = NULL, the original ideal * was a prime power */ static GEN zprimestar(GEN nf,GEN pr,GEN ep,GEN x,GEN arch) { gpmem_t av = avma, av1, tetpil; long N, f, i, e, a, b; GEN prh,p,pf_1,list,v,p1,p3,p4,prk,uv,g0,newgen,pra,prb; GEN *gptr[2]; if(DEBUGLEVEL>3) { fprintferr("treating pr = %Z ^ %Z\n",pr,ep); flusherr(); } prh = prime_to_ideal(nf,pr); N = degpol(nf[1]); f = itos((GEN)pr[4]); p = (GEN)pr[1]; pf_1 = addis(gpowgs(p,f), -1); if (f==1) { v = zerocol(N); v[1] = gener(p)[2]; } else { GEN T, modpr = zk_to_ff_init(nf, &pr, &T, &p); v = ff_to_nf(FpXQ_gener(T,p), modpr); v = algtobasis(nf, v); } /* v generates (Z_K / pr)^* */ if(DEBUGLEVEL>3) fprintferr("v computed\n"); e = itos(ep); prk=(e==1)? pr: idealpow(nf,pr,ep); if(DEBUGLEVEL>3) fprintferr("prk computed\n"); g0 = v; uv = NULL; /* gcc -Wall */ if (x) { uv = idealaddtoone(nf,prk, idealdivpowprime(nf,x,pr,ep)); g0 = makeprimetoideal(nf,x,uv,v); if(DEBUGLEVEL>3) fprintferr("g0 computed\n"); } p1 = cgetg(6,t_VEC); list = _vec(p1); p1[1] = (long)_vec(pf_1); p1[2] = (long)_vec(v); p1[3] = (long)_vec(g0); p1[4] = (long)_vec(zsigne(nf,g0,arch)); p1[5] = un; if (e==1) return gerepilecopy(av, list); a=1; b=2; av1=avma; pra = prh; prb = (e==2)? prk: idealpow(nf,pr,gdeux); for(;;) { if(DEBUGLEVEL>3) fprintferr(" treating a = %ld, b = %ld\n",a,b); p1 = zidealij(pra,prb); newgen = dummycopy((GEN)p1[2]); p3 = cgetg(lg(newgen),t_VEC); if(DEBUGLEVEL>3) fprintferr("zidealij done\n"); for (i=1; i5) fprintferr("zarchstar: r = %ld\n",r); p1 = gpowgs(stoi(rr),N); limr = (cmpis(p1,BIGINT) >= 0)? BIGINT: p1[2]; limr = (limr-1)>>1; k = zk? rr: 1; /* to avoid 0 */ for ( ; k<=limr; k++) { gpmem_t av1=avma; long kk = k; GEN alpha = vun; for (i=1; i<=N; i++) { lambda[i] = (kk+r)%rr - r; kk/=rr; if (lambda[i]) alpha = gadd(alpha, gmulsg(lambda[i],(GEN)bas[i])); } p1 = (GEN)mat[lgmat]; for (i=1; i<=nba; i++) p1[i] = (gsigne((GEN)alpha[i]) < 0)? 1: 0; if (u_FpM_deplin(mat, 2)) avma = av1; else { /* new vector indep. of previous ones */ avma = av1; alpha = nfun; for (i=1; i<=N; i++) if (lambda[i]) alpha = gadd(alpha, gmulsg(lambda[i],(GEN)x[i])); genarch[lgmat++] = (long)alpha; if (lgmat > nba) { GEN *gptr[2]; mat = small_to_mat( u_FpM_inv(mat, 2) ); gptr[0]=&genarch; gptr[1]=&mat; gerepilemany(av,gptr,2); y[2]=(long)genarch; y[3]=(long)mat; return y; } setlg(mat,lgmat+1); } } } } GEN zinternallog_pk(GEN nf, GEN a0, GEN y, GEN pr, GEN prk, GEN list, GEN *psigne) { GEN a = a0, L,e,p1,cyc,gen; long i,j, llist = lg(list)-1; e = gzero; /* gcc -Wall */ for (j=1; j<=llist; j++) { L = (GEN)list[j]; cyc=(GEN)L[1]; gen=(GEN)L[2]; if (j==1) p1 = nf_PHlog(nf,a,(GEN)gen[1],pr); else { p1 = (GEN)a[1]; a[1] = laddsi(-1,(GEN)a[1]); e = gmul((GEN)L[5],a); a[1] = (long)p1; /* here lg(e) == lg(cyc) */ p1 = (GEN)e[1]; } for (i=1; i5) fprintferr("do element_powmodideal\n"); p1 = element_powmodideal(nf,(GEN)gen[i],p1,prk); a = element_mulmodideal(nf,a,p1,prk); } } return y; } /* Retourne la decomposition de a sur les nbgen generateurs successifs * contenus dans list_set et si index !=0 on ne fait ce calcul que pour * l'ideal premier correspondant a cet index en mettant a 0 les autres * composantes */ static GEN zinternallog(GEN nf,GEN a,GEN list_set,long nbgen,GEN arch,GEN fa,long index) { GEN prlist,ep,y0,y,ainit,list,pr,prk,cyc,psigne,p1,p2; gpmem_t av; long nbp,i,j,k; y0 = y = cgetg(nbgen+1,t_COL); av=avma; prlist=(GEN)fa[1]; ep=(GEN)fa[2]; nbp=lg(ep)-1; i=typ(a); if (is_extscalar_t(i)) a = algtobasis(nf,a); if (DEBUGLEVEL>3) { fprintferr("entering zinternallog, "); flusherr(); if (DEBUGLEVEL>5) fprintferr("with a = %Z\n",a); } ainit = a; psigne = zsigne(nf,ainit,arch); p2 = NULL; /* gcc -Wall */ for (k=1; k<=nbp; k++) { list = (GEN)list_set[k]; if (index && index!=k) { for (j=1; j3) { fprintferr("leaving\n"); flusherr(); } for (i=1; i<=nbgen; i++) y0[i] = licopy((GEN)y0[i]); return y0; } static GEN compute_gen(GEN nf, GEN u1, GEN gen, GEN bid) { long i, c = lg(u1); GEN basecl = cgetg(c,t_VEC); for (i=1; i (long)maxprime()) err(primer1); for (p[2]=0; 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) continue; q2=q; ideal=pr; z2=dummycopy(z); if (do_units) lu2=dummycopy(lu); for (l=2; ;l++) { if (big_id) ideal = zidealstarinitall(nf,ideal,do_gen); if (do_units) embunit = logunitmatrix(nf,funits,racunit,ideal); for (i=q; i<=bound; i+=q) { p1 = (GEN)z[i/q]; lp1 = lg(p1); if (lp1 == 1) continue; p2 = cgetg(lp1,t_VEC); for (k=1; k (ulong)bound) break; ideal = idealpows(nf,pr,l); } z = z2; if (do_units) lu = lu2; } if (low_stack(lim, stack_lim(av,1))) { GEN *gptr[2]; gptr[0]=&z; gptr[1]=&lu; if(DEBUGMEM>1) err(warnmem,"ideallistzstarall"); gerepilemany(av,gptr,do_units?2:1); } } if (!do_units) return gerepilecopy(av0, z); y = cgetg(3,t_VEC); y[1] = lcopy(z); lu2 = cgetg(lg(z),t_VEC); for (i=1; i4) err(flagerr,"ideallist"); return ideallistzstarall(bnf,bound,flag); } GEN ideallistzstar(GEN nf,long bound) { return ideallistzstarall(nf,bound,0); } GEN ideallistzstargen(GEN nf,long bound) { return ideallistzstarall(nf,bound,1); } GEN ideallistunit(GEN nf,long bound) { return ideallistzstarall(nf,bound,2); } GEN ideallistunitgen(GEN nf,long bound) { return ideallistzstarall(nf,bound,3); } GEN ideallist(GEN bnf,long bound) { return ideallistzstarall(bnf,bound,4); } static GEN ideallist_arch(GEN nf,GEN list,GEN arch,long flun) { long nba,i,j,lx,ly; GEN p1,z,p2; if (typ(arch) != t_VEC) err(typeer,"ideallistarch"); nba=0; for (i=1; i3) err(flagerr,"ideallistarch"); return ideallistarchall(nf,list,arch,flag); }