/* $Id: subfield.c,v 1.55 2002/09/07 19:15:13 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. */ /*******************************************************************/ /* */ /* SUBFIELDS OF A NUMBER FIELD */ /* J. Klueners and M. Pohst, J. Symb. Comp. (1996), vol. 11 */ /* */ /*******************************************************************/ #include "pari.h" extern GEN matrixpow(long n, long m, GEN y, GEN P,GEN l); extern GEN Fp_factor_irred(GEN P,GEN l, GEN Q); extern GEN FpX_rand(long d1, long v, GEN p); extern GEN hensel_lift_fact(GEN pol, GEN Q, GEN T, GEN p, GEN pe, long e); extern GEN ZX_disc_all(GEN x, ulong bound); extern GEN indexpartial(GEN P, GEN DP); extern GEN initgaloisborne(GEN T, GEN dn, long prec, GEN *ptL, GEN *ptprep, GEN *ptdis); extern long ZX_get_prec(GEN x); static GEN print_block_system(long N,GEN Y,long d,GEN vbs,long maxl); /* Computation of potential block systems of given size d associated to a * rational prime p: give a row vector of row vectors containing the * potential block systems of imprimitivity; a potential block system is a * vector of row vectors (enumeration of the roots). */ #define BIL 32 /* for 64bit machines also */ static GEN calc_block(long N,GEN Z,long d,GEN Y,GEN vbs,ulong maxl) { long r,lK,i,j,t,tp,T,lpn,u,nn,lnon,lY; GEN K,n,non,pn,pnon,e,Yp,Zp,Zpp; if (DEBUGLEVEL>3) { long l = vbs? lg(vbs): 0; fprintferr("avma = %ld, lg(Z) = %ld, lg(Y) = %ld, lg(vbs) = %ld\n", avma,lg(Z),lg(Y),l); if (DEBUGLEVEL > 5) { fprintferr("Z = %Z\n",Z); fprintferr("Y = %Z\n",Y); if (DEBUGLEVEL > 7) fprintferr("vbs = %Z\n",vbs); } } r=lg(Z); lnon = min(BIL, r); e = new_chunk(BIL); n = new_chunk(r); non = new_chunk(lnon); pnon = new_chunk(lnon); pn = new_chunk(lnon); Zp = cgetg(lnon,t_VEC); Zpp = cgetg(lnon,t_VEC); for (i=1; i= BIL) err(talker,"overflow in calc_block"); pn[lpn] = n[j]; pnon[lpn] = j; ngcd = cgcd(ngcd, n[j]); } if (dk % ngcd) continue; T = 1<>=1) { if (tp&1) { nn += pn[u]; e[u]=1; } else e[u]=0; } if (dk == nn) { gpmem_t av=avma; int Z_equal_Zp = 1; for (j=1; j maxl) return vbs; avma=av; } } } return vbs; } static GEN potential_block_systems(long N, long d, GEN n, ulong maxl) { long r, i, j, k; gpmem_t av=avma; GEN p1,vbs,Z; r=lg(n); Z=cgetg(r,t_VEC); for (k=0,i=1; i5) fprintferr("appending D = %Z\n",D); vbs[l] = (long)Dn; setlg(vbs, l+1); return vbs; } GEN myconcat(GEN D, long a) { long i,l = lg(D); GEN x = cgetg(l+1,t_VECSMALL); for (i=1; i5) fprintferr("Y = %Z\n",Y); empty = cgetg(1,t_VEC); n = new_chunk(N+1); D = cget1(N+1, t_VEC); t=new_chunk(r+1); k=new_chunk(r+1); Z=cgetg(r+1,t_VEC); for (ns=0,i=1; iki) lp = 1; a = im_by_cy(a, cy); De[lp] = (long)myconcat((GEN)De[lp], a); } } if (si>1 && ki>1) { ns++; t[ns]=si-1; k[ns]=ki; Z[ns]=lgetg(si,t_VEC); p1=(GEN)Z[ns]; for (j=2; j<=si; j++) p1[j-1]=Yi[j]; } myconcat2(D,De); } if (DEBUGLEVEL>2) { fprintferr("\nns = %ld\n",ns); flusherr(); } if (!ns) return append_vbs(vbs,D); setlg(Z, ns+1); e=(long**)new_chunk(ns+1); for (i=1; i<=ns; i++) { e[i]=new_chunk(t[i]+1); for (j=1; j<=t[i]; j++) e[i][j]=0; } cyperm = cgetg(N+1,t_VEC); perm = cgetg(N+1,t_VEC); i=ns; do { gpmem_t av = avma; if (DEBUGLEVEL>5) { for (l=1; l<=ns; l++) { for (ll=1; ll<=t[l]; ll++) fprintferr("e[%ld][%ld] = %ld, ",l,ll,e[l][ll]); fprintferr("\n"); } fprintferr("\n"); flusherr(); } for (u=1; u<=N; u++) perm[u]=u; for (u=1; u<=ns; u++) for (v=1; v<=t[u]; v++) perm_mul_i(perm, cycle_power_to_perm(cyperm,gmael(Z,u,v),e[u][v])); vbs = append_vbs(vbs, im_block_by_perm(D,perm)); if (lg(vbs) > maxl) return vbs; avma = av; e[ns][t[ns]]++; if (e[ns][t[ns]] >= k[ns]) { j=t[ns]-1; while (j>=1 && e[ns][j] == k[ns]-1) j--; if (j>=1) { e[ns][j]++; for (l=j+1; l<=t[ns]; l++) e[ns][l]=0; } else { i=ns-1; while (i>=1) { j=t[i]; while (j>=1 && e[i][j] == k[i]-1) j--; if (j<1) i--; else { e[i][j]++; for (l=j+1; l<=t[i]; l++) e[i][l]=0; for (ll=i+1; ll<=ns; ll++) for (l=1; l<=t[ll]; l++) e[ll][l]=0; break; } } } } } while (i>0); return vbs; } static GEN polsimplify(GEN x) { long i,lx = lgef(x); for (i=2; i M[i] for some i; 1 otherwise */ static long ok_coeffs(GEN g,GEN M) { long i, lg = lgef(g)-1; /* g is monic, and cst term is ok */ for (i=3; i 0) return 0; return 1; } /* Return a polynomial g defining a potential subfield, or * 0: if p | d(g) * 1: if coeffs of g are too large * 2: same, detected by cheap d-1 test */ static GEN cand_for_subfields(GEN A,GEN DATA,GEN *ptlistdelta) { long N,m,i,j,d,lf; GEN M,T,pe,p,pol,fhk,g; GEN d_1_term,delta,listdelta,whichdelta,firstroot; pol=(GEN)DATA[1]; p = (GEN)DATA[2]; pe= (GEN)DATA[3]; T = (GEN)DATA[4]; fhk=(GEN)DATA[5]; M = (GEN)DATA[8]; N=degpol(pol); m=lg(A)-1; d=N/m; /* m | M */ firstroot = (GEN)DATA[13]; delta = cgetg(m+1,t_VEC); lf = lg(firstroot); listdelta = cgetg(lf, t_VEC); whichdelta = cgetg(N+1, t_VECSMALL); d_1_term = gzero; for (i=1; i<=m; i++) { GEN Ai = (GEN)A[i], p1 = gun; for (j=1; j<=d; j++) p1 = Fq_mul(p1, (GEN)fhk[Ai[j]], T,pe); delta[i] = (long)p1; if (DEBUGLEVEL>2) fprintferr("delta[%ld] = %Z\n",i,p1); /* g = prod (X - delta[i]) * if g o h = 0 (pol), we'll have h(Ai[j]) = delta[i] for all j */ /* fk[k] belongs to block number whichdelta[k] */ for (j=1; j<=d; j++) whichdelta[Ai[j]] = i; if (typ(p1) == t_POL) p1 = constant_term(p1); d_1_term = addii(d_1_term, p1); } d_1_term = centermod(d_1_term, pe); /* Tr(g) */ if (absi_cmp(d_1_term, (GEN)M[3]) > 0) return gdeux; /* d-1 test */ g = FqV_roots_to_pol(delta, T, pe, 0); g = centermod(polsimplify(g), pe); /* assume g in Z[X] */ if (DEBUGLEVEL>2) fprintferr("pol. found = %Z\n",g); if (!ok_coeffs(g,M)) return gun; if (!FpX_is_squarefree(g, p)) return gzero; for (i=1; i 0) err(talker, "relatively prime polynomials expected"); d = constant_term(d); if (!gcmp1(d)) { d = mpinvmod(d, p); v = FpX_Fp_mul(v,d, p); } bezout_coeff[i] = (long)FpX_mul(B,v, p); } return bezout_coeff; } /* assume x in Fq, return Tr_{Fq/Fp}(x) as a t_INT */ static GEN trace(GEN x, GEN Trq, GEN p) { long i, l; GEN s; if (typ(x) == t_INT) return modii(mulii(x, (GEN)Trq[1]), p); l = lgef(x)-1; if (l == 1) return gzero; x++; s = mulii((GEN)x[1], (GEN)Trq[1]); for (i=2; i1) fprintferr("lifting embedding mod p = %Z\n",q); /* w1 := w0 - h0 g(w0) mod (T,q) */ if (wpow) a = FpX_FpXQV_compo(g,wpow, T,q); else a = FpX_FpXQ_compo(g,w0, T,q); /* first time */ /* now, a = 0 (p) */ a = gmul(gneg(h0), gdivexact(a, p)); w1 = gadd(w0, gmul(p, FpX_res(a, T,p))); w1_Q = centermod(gmul(w1, resii(ind,q)), q); if (gegal(w1_Q, w0_Q) || cmpii(q,maxp) > 0) { GEN G = gcmp1(ind)? g: rescale_pol(g,ind); if (gcmp0(poleval(G, gmodulcp(w1_Q,T)))) break; } if (cmpii(q, maxp) > 0) { if (DEBUGLEVEL) fprintferr("coeff too big for embedding\n"); return NULL; } { GEN *gptr[5]; gptr[0]=&w1; gptr[1]=&h0; gptr[2]=&w1_Q; gptr[3]=&q; gptr[4]=&p; gerepilemany(av,gptr,5); } q2 = sqri(q); wpow = FpXQ_powers(w1, rt, T, q2); /* h0 := h0 * (2 - h0 g'(w1)) mod (T,q) * = h0 + h0 * (1 - h0 g'(w1)) */ a = gmul(gneg(h0), FpX_FpXQV_compo(gp, FpXV_red(wpow,q),T,q)); a = ZX_s_add(FpX_res(a, T,q), 1); /* 1 - h0 g'(w1) = 0 (p) */ a = gmul(h0, gdivexact(a, p)); h0 = gadd(h0, gmul(p, FpX_res(a, T,p))); w0 = w1; w0_Q = w1_Q; p = q; q = q2; } TR = (GEN)DATA[14]; if (!gcmp0(TR)) w1_Q = TR_pol(w1_Q, TR); return gdiv(w1_Q,ind); } static GEN choose_prime(GEN pol,GEN dpol,long d,GEN *ptff,GEN *ptlistpotbl, long *ptlcm) { gpmem_t av; byteptr di=diffptr; long j,k,oldllist,llist,r,lcm,oldlcm,pp,minp, N = degpol(pol), m = N/d; GEN p,listpotbl,oldlistpotbl,ff,oldff,n,oldn; minp = N*(m-1)/2; if (DEBUGLEVEL) (void)timer2(); di++; p = stoi(2); while (p[2]<=minp) NEXT_PRIME_VIADIFF(p[2], di); oldllist = 100000; oldlcm = 0; oldlistpotbl = oldff = oldn = NULL; pp = 0; /* gcc -Wall */ av = avma; for(k=1; k<11 || !oldn; k++,avma = av) { while (!smodis(dpol,p[2])) NEXT_PRIME_VIADIFF(p[2], di); if (k > 50) err(talker,"sorry, too many block systems in nfsubfields"); ff=(GEN)factmod0(pol,p)[1]; r=lg(ff)-1; if (r == 1 || r == N) goto repeat; n = cgetg(r+1, t_VECSMALL); lcm = n[1] = degpol(ff[1]); for (j=2; j<=r; j++) { n[j] = degpol(ff[j]); lcm = clcm(lcm,n[j]); } if (lcm < oldlcm) goto repeat; /* false when oldlcm = 0 */ if (r >= BIL) { err(warner,"subfields: overflow in calc_block"); goto repeat; } if (DEBUGLEVEL) fprintferr("p = %ld,\tlcm = %ld,\torbits: %Z\n",p[2],lcm,n); if (oldn && gegal(n,oldn)) goto repeat; listpotbl = potential_block_systems(N,d,n, oldllist); if (!listpotbl) { oldlistpotbl = NULL; pp = p[2]; break; } llist = lg(listpotbl)-1; if (llist >= oldllist) { if (DEBUGLEVEL) msgtimer("#pbs >= %ld [aborted]",oldllist); for (j=1; j x + x^p + ... + x^{p^(i-1)} */ Trk = pow; /* re-use (destroy) pow */ Trk[1] = (long)p1; for (i=2; i<=k; i++) Trk[i] = ladd((GEN)Trk[i-1], (GEN)pow1[i]); y = cgetg(r, t_VEC); for (i=1; i max(M), * 4: polynomial defining the field F_(p^nn), * 5: Hensel lift to precision p^e of DATA[6] * 6: roots of nf[1] in F_(p^nn), * 7: Hadamard bound for coefficients of h(x) such that g o h = 0 mod nf[1]. * 8: bound M for polynomials defining subfields x DATA[9] * 9: multiple of index of nf *10: *[i] = interpolation polynomial for ff[i] [= 1 on the first root firstroot[i], 0 on the others] *11: Trk used to compute traces (cf poltrace) *12: Bezout coefficients associated to the ff[i] *13: *[i] = index of first root of ff[i] (in DATA[6]) *14: number of polynomial changes (translations) */ static GEN compute_data(GEN DATA, struct poldata PD, long d, GEN ff, GEN T,GEN p) { long i,j,l,e,N, lff = lg(ff); GEN ffL,den,roo,pe,p1,p2,fk,fhk,MM,maxroot,pol,interp,bezoutC; if (DEBUGLEVEL>1) { fprintferr("Entering compute_data()\n\n"); flusherr(); } pol = PD.pol; N = degpol(pol); roo = PD.roo; den = PD.den; if (DATA) /* update (translate) an existing DATA */ { GEN Xm1 = gsub(polx[varn(pol)], gun); GEN TR = addis((GEN)DATA[14],1); GEN mTR = negi(TR), mun = negi(gun); DATA[14] = (long)TR; pol = TR_pol(pol, mTR); p1 = dummycopy(roo); l = lg(p1); for (i=1; i 0) /* do not turn polun[0] into gun */ { p1 = TR_pol((GEN)interp[i], mun); interp[i] = (long)FpXQX_red(p1, NULL,p); } if (degpol(bezoutC[i]) > 0) { p1 = TR_pol((GEN)bezoutC[i], mun); bezoutC[i] = (long)FpXQX_red(p1, NULL,p); } } p1 = cgetg(lff, t_VEC); for (i=1; i1) { fprintferr("f = %Z\n",DATA[1]); fprintferr("p = %Z, lift to p^%ld\n",DATA[2], e); fprintferr("Fq defined by %Z\n",DATA[4]); fprintferr("2 * Hadamard bound * ind = %Z\n",DATA[7]); fprintferr("2 * M = %Z\n",DATA[8]); } return DATA; } /* g = polynomial, h = embedding. Return [[g,h]] */ static GEN _subfield(GEN g, GEN h) { GEN x = cgetg(3,t_VEC); x[1] = (long)g; x[2] = (long)h; return _vec(x); } /* subfields of degree d */ static GEN subfields_of_given_degree(struct poldata PD,long d) { gpmem_t av, av2; long llist,i,nn,v; GEN listpotbl,ff,A,CSF,ESF,LSB,p,T,DATA,listdelta; GEN pol = PD.pol, dpol = PD.dis; if (DEBUGLEVEL) fprintferr("\n*** Look for subfields of degree %ld\n\n", d); av = avma; p = choose_prime(pol,dpol,degpol(pol)/d,&ff,&listpotbl,&nn); if (!listpotbl) { avma=av; return cgetg(1,t_VEC); } v = fetch_var(); name_var(v,"y"); T = lift_intern(ffinit(p,nn, v)); DATA = NULL; LSB = cgetg(1,t_VEC); i = 1; llist = lg(listpotbl); CHANGE: DATA = compute_data(DATA,PD,d, ff,T,p); for (; i 1) fprintferr("\n* Potential block # %ld: %Z\n",i,A); CSF = cand_for_subfields(A,DATA,&listdelta); if (typ(CSF)==t_INT) { avma = av2; if (DEBUGLEVEL > 1) switch(itos(CSF)) { case 0: fprintferr("changing f(x): p divides disc(g(x))\n"); break; case 1: fprintferr("coeff too big for pol g(x)\n"); break; case 2: fprintferr("d-1 test failed\n"); break; } if (CSF==gzero) goto CHANGE; } else { if (DEBUGLEVEL) fprintferr("candidate = %Z\n",CSF); ESF = embedding_of_potential_subfields(CSF,DATA,listdelta); if (!ESF) { avma = av2; continue; } if (DEBUGLEVEL) fprintferr("embedding = %Z\n",ESF); LSB = gerepileupto(av2, concat(LSB, _subfield(CSF,ESF))); } } (void)delete_var(); for (i=1; ipol = dummycopy(T); /* may change variable number later */ if (nf) { PD->den = Q_denom((GEN)nf[7]); PD->roo = (GEN)nf[6]; PD->dis = mulii(absi((GEN)nf[3]), sqri((GEN)nf[4])); } else { PD->den = initgaloisborne(T,NULL,ZX_get_prec(T), &L,NULL,&dis); PD->roo = L; PD->dis = absi(dis); } } GEN subfields(GEN nf,GEN d) { gpmem_t av = avma; long di, N, v0; GEN LSB, pol, G; struct poldata PD; pol = get_nfpol(nf, &nf); /* in order to treat trivial cases */ v0=varn(pol); N=degpol(pol); di=itos(d); if (di==N) return gerepilecopy(av, _subfield(pol, polx[v0])); if (di==1) return gerepilecopy(av, _subfield(polx[v0], pol)); if (di < 1 || di > N || N % di) return cgetg(1,t_VEC); /* much easier if nf is Galois (WSS) */ G = galoisconj4(nf? nf: pol, NULL, 1, 0); if (typ(G) != t_INT) { /* Bingo */ GEN L = galoissubgroups(G), F; long k,i, l = lg(L), o = N/di; F = cgetg(l, t_VEC); k = 1; for (i=1; i 2) { setvarn(pol, 0); for (i=2; i 1) LSB = concatsp(LSB,NLSB); else avma = av1; } } LSB = concatsp(LSB, _subfield(polx[0],pol)); if (DEBUGLEVEL) fprintferr("\n***** Leaving subfields\n\n"); return gerepileupto(av, fix_var(LSB,v0)); } GEN subfields0(GEN nf,GEN d) { return d? subfields(nf,d): subfieldsall(nf); }