/* $Id: base3.c,v 1.41 2001/10/01 12:11:29 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 int ker_trivial_mod_p(GEN x, GEN p); extern long ideal_is_zk(GEN ideal,long N); 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 hnfall_i(GEN A, GEN *ptB, long remove); 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; for (i=2; i= 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 v) { long i,k,w, N = degpol(nf[1]); GEN r,a,y,mul; if (typ(b) == t_MAT) mul = b; else { mul = cgetg(N+1,t_MAT); for (i=1; i<=N; i++) mul[i] = (long)element_mulid(nf,b,i); } y = cgetg(N+1, t_COL); /* will hold the new x */ x = dummycopy(x); for(w=0; w<=v; 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)) goto END; } r=x; x=y; y=r; } END: if (newx) *newx = x; return w; } long element_val(GEN nf, GEN x, GEN vp) { long av = avma,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_intern(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,VERYBIGINT); avma=av; return w + vcx*e; } /* d = a multiple of norm(x), x integral */ long element_val2(GEN nf, GEN x, GEN d, GEN vp) { GEN p = (GEN)vp[1]; long av, v = ggval(d,p); if (!v) return 0; av=avma; v = int_elt_val(nf,x,p,(GEN)vp[5],NULL,v); avma=av; return v; } /* 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; 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),av=avma,i,N; GEN z; nf=checknf(nf); switch(tx) { case t_VEC: case t_COL: case t_MAT: z=cgetg(lx,tx); for (i=1; i B) err(precer, "zsigne"); vecsign[j++] = (gsigne(y) > 0)? (long)_0: (long)_1; } avma = av; setlg(vecsign,j); return vecsign; } GEN lllreducemodmatrix(GEN x,GEN y) { ulong av = avma; GEN z = gmul(y,lllint(y)); return gerepileupto(av, reducemodinvertible(x, z)); } /* for internal use...reduce x modulo (invertible) y */ GEN reducemodinvertible(GEN x, GEN y) { return gadd(x, gneg(gmul(y, ground(gauss(y,x))))); } /* Reduce column x modulo y in HNF */ GEN colreducemodmat(GEN x, GEN y, GEN *Q) { long i, l = lg(x); GEN q; if (Q) *Q = cgetg(l,t_COL); if (l == 1) return cgetg(1,t_COL); for (i = l-1; i>0; i--) { q = negi(gdivround((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 z,U,Ui,D,p1; long l,c; z = smith2(H); U = (GEN)z[1]; D = (GEN)z[3]; 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; new_chunk(c); p1 = mulii(p1,g0inv); 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) { ulong 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= 0 such that g0^n=x modulo pr, assume g0 reduced * q = order of g0 (Npr - 1 if q = NULL) * TODO: should be done in F_(p^f), not in Z_k mod pr (done for f=1) */ static GEN nfshanks(GEN nf,GEN x,GEN g0,GEN pr,GEN prhall,GEN q) { long av=avma,av1,lim,lbaby,i,k, f = itos((GEN)pr[4]); GEN p1,smalltable,giant,perm,v,g0inv,prh = (GEN)prhall[1]; GEN multab, p = (GEN)pr[1]; x = lift_intern(nfreducemodpr(nf,x,prhall)); p1 = q? q: addsi(-1, gpowgs(p,f)); p1 = racine(p1); if (cmpis(p1,LGBITS) >= 0) err(talker,"module too large in nfshanks"); lbaby=itos(p1)+1; smalltable=cgetg(lbaby+1,t_VEC); g0inv = lift_intern(element_invmodpr(nf,g0,prhall)); p1 = x; multab = get_multab(nf, g0inv); for (i=lg(multab)-1; i; i--) multab[i]=(long)FpV_red((GEN)multab[i], p); for (i=1;;i++) { if (isnfscalar(p1) && gcmp1((GEN)p1[1])) { avma=av; return stoi(i-1); } smalltable[i]=(long)p1; if (i==lbaby) break; p1 = mul_matvec_mod_pr(multab,p1,prh); } giant=lift_intern(element_divmodpr(nf,x,p1,prhall)); p1=cgetg(lbaby+1,t_VEC); perm = gen_sort(smalltable, cmp_IND | cmp_C, cmp_vecint); for (i=1; i<=lbaby; i++) p1[i]=smalltable[perm[i]]; smalltable=p1; p1=giant; multab = get_multab(nf, giant); for (i=lg(multab)-1; i; i--) multab[i]=(long)FpV_red((GEN)multab[i], p); av1 = avma; lim=stack_lim(av1,2); for (k=1;;k++) { i=tablesearch(smalltable,p1,cmp_vecint); if (i) { v=addis(mulss(lbaby-1,k),perm[i]); return gerepileuptoint(av,addsi(-1,v)); } p1 = mul_matvec_mod_pr(multab,p1,prh); if (low_stack(lim, stack_lim(av1,2))) { if(DEBUGMEM>1) err(warnmem,"nfshanks"); p1 = gerepileupto(av1, p1); } } } /* same in nf.zk / pr * TODO: should be done in F_(p^f), not in Z_k mod pr (done for f=1) */ GEN nf_PHlog(GEN nf, GEN a, GEN g, GEN pr, GEN prhall) { ulong av = avma; GEN v,t0,a0,b,q,g_q,n_q,ginv0,qj,ginv,ord,fa,ex; long e,i,j,l; a = lift_intern(nfreducemodpr(nf,a,prhall)); if (isnfscalar(a)) { /* can be done in Fp^* */ GEN p = (GEN)pr[1], ordp = subis(p, 1); a = (GEN)a[1]; if (gcmp1(a) || egalii(p, gdeux)) { avma = av; return gzero; } ord = subis(idealnorm(nf,pr), 1); if (egalii(a, ordp)) /* -1 */ return gerepileuptoint(av, shifti(ord,-1)); if (egalii(ord, ordp)) q = NULL; else /* we want < g > = Fp^* */ { q = divii(ord,ordp); g = element_powmodpr(nf,g,q,prhall); } g = lift_intern((GEN)g[1]); n_q = Fp_PHlog(a,g,p,NULL); if (q) n_q = mulii(q, n_q); return gerepileuptoint(av, n_q); } ord = subis(idealnorm(nf,pr),1); fa = factor(ord); ex = (GEN)fa[2]; fa = (GEN)fa[1]; l = lg(fa); ginv = lift_intern(element_invmodpr(nf, g, prhall)); 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 = element_powmodpr(nf, a, t0, prhall); ginv0 = element_powmodpr(nf, ginv, t0, prhall); /* order q^e */ g_q = element_powmodpr(nf, g, divii(ord,q), prhall); /* order q */ n_q = gzero; for (j=0; j3) { fprintferr("treating pr = %Z ^ %Z\n",pr,ep); flusherr(); } prh=prime_to_ideal(nf,pr); N=lg(prh)-1; f=itos((GEN)pr[4]); p=(GEN)pr[1]; pf_1 = addis(gpowgs(p,f), -1); v = zerocol(N); if (f==1) v[1]=gener(p)[2]; else { GEN prhall = cgetg(3,t_VEC); long psim; if (is_bigint(p)) err(talker,"prime too big in zprimestar"); psim = itos(p); list = (GEN)factor(pf_1)[1]; nbp=lg(list)-1; prhall[1]=(long)prh; prhall[2]=zero; for (n=psim; n>=0; n++) { m=n; for (i=1; i<=N; i++) if (!gcmp1(gcoeff(prh,i,i))) { v[i]=lstoi(m%psim); m/=psim; } for (j=1; j<=nbp; j++) { p1 = divii(pf_1,(GEN)list[j]); p1 = lift_intern(element_powmodpr(nf,v,p1,prhall)); if (isnfscalar(p1) && gcmp1((GEN)p1[1])) break; } if (j>nbp) break; } if (n < 0) err(talker,"prime too big in zprimestar"); } /* v generates (Z_K / pr)^* */ if(DEBUGLEVEL>3) {fprintferr("v computed\n");flusherr();} e = itos(ep); prk=(e==1)? pr: idealpow(nf,pr,ep); if(DEBUGLEVEL>3) {fprintferr("prk computed\n");flusherr();} g0 = v; uv = NULL; /* gcc -Wall */ if (x) { uv = idealaddtoone(nf,prk, idealdivexact(nf,x,prk)); g0 = makeprimetoideal(nf,x,uv,v); if(DEBUGLEVEL>3) {fprintferr("g0 computed\n");flusherr();} } 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); flusherr();} p1 = zidealij(pra,prb); newgen = dummycopy((GEN)p1[2]); p3 = cgetg(lg(newgen),t_VEC); if(DEBUGLEVEL>3) {fprintferr("zidealij done\n"); flusherr();} for (i=1; i5) fprintferr("zarchstar: r = %ld\n",r); p1 = gpowgs(stoi(rr),N); limr = is_bigint(p1)? BIGINT: p1[2]; limr = (limr-1)>>1; k = zk? rr: 1; /* to avoid 0 */ for ( ; k<=limr; k++) { long av1=avma, 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)? zero: un; if (ker_trivial_mod_p(mat, gdeux)) 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 = ginv(mat); 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, nfmodprinit(nf,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; long av,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; ) { 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; nba=0; for (i=1; i3) err(flagerr,"ideallistarch"); return ideallistarchall(nf,list,arch,flag); }