Annotation of OpenXM_contrib/pari-2.2/src/modules/subfield.c, Revision 1.2
1.2 ! noro 1: /* $Id: subfield.c,v 1.55 2002/09/07 19:15:13 karim Exp $
1.1 noro 2:
3: Copyright (C) 2000 The PARI group.
4:
5: This file is part of the PARI/GP package.
6:
7: PARI/GP is free software; you can redistribute it and/or modify it under the
8: terms of the GNU General Public License as published by the Free Software
9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
10: ANY WARRANTY WHATSOEVER.
11:
12: Check the License for details. You should have received a copy of it, along
13: with the package; see the file 'COPYING'. If not, write to the Free Software
14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
15:
16: /*******************************************************************/
17: /* */
18: /* SUBFIELDS OF A NUMBER FIELD */
19: /* J. Klueners and M. Pohst, J. Symb. Comp. (1996), vol. 11 */
20: /* */
21: /*******************************************************************/
22: #include "pari.h"
23: extern GEN matrixpow(long n, long m, GEN y, GEN P,GEN l);
24: extern GEN Fp_factor_irred(GEN P,GEN l, GEN Q);
25: extern GEN FpX_rand(long d1, long v, GEN p);
26: extern GEN hensel_lift_fact(GEN pol, GEN Q, GEN T, GEN p, GEN pe, long e);
1.2 ! noro 27: extern GEN ZX_disc_all(GEN x, ulong bound);
! 28: extern GEN indexpartial(GEN P, GEN DP);
! 29: extern GEN initgaloisborne(GEN T, GEN dn, long prec, GEN *ptL, GEN *ptprep, GEN *ptdis);
! 30: extern long ZX_get_prec(GEN x);
1.1 noro 31:
32: static GEN print_block_system(long N,GEN Y,long d,GEN vbs,long maxl);
33:
34: /* Computation of potential block systems of given size d associated to a
35: * rational prime p: give a row vector of row vectors containing the
36: * potential block systems of imprimitivity; a potential block system is a
37: * vector of row vectors (enumeration of the roots).
38: */
39: #define BIL 32 /* for 64bit machines also */
40: static GEN
41: calc_block(long N,GEN Z,long d,GEN Y,GEN vbs,ulong maxl)
42: {
43: long r,lK,i,j,t,tp,T,lpn,u,nn,lnon,lY;
44: GEN K,n,non,pn,pnon,e,Yp,Zp,Zpp;
45:
46: if (DEBUGLEVEL>3)
47: {
48: long l = vbs? lg(vbs): 0;
49: fprintferr("avma = %ld, lg(Z) = %ld, lg(Y) = %ld, lg(vbs) = %ld\n",
50: avma,lg(Z),lg(Y),l);
51: if (DEBUGLEVEL > 5)
52: {
53: fprintferr("Z = %Z\n",Z);
54: fprintferr("Y = %Z\n",Y);
55: if (DEBUGLEVEL > 7) fprintferr("vbs = %Z\n",vbs);
56: }
57: }
58: r=lg(Z); lnon = min(BIL, r);
59: e = new_chunk(BIL);
60: n = new_chunk(r);
61: non = new_chunk(lnon);
62: pnon = new_chunk(lnon);
63: pn = new_chunk(lnon);
64: Zp = cgetg(lnon,t_VEC);
65: Zpp = cgetg(lnon,t_VEC);
66: for (i=1; i<r; i++) n[i] = lg(Z[i])-1;
67:
68: K=divisors(stoi(n[1])); lK=lg(K);
69: for (i=1; i<lK; i++)
70: {
71: long ngcd = n[1], k = itos((GEN)K[i]), dk = d*k;
72: lpn=0;
73: for (j=2; j<r; j++)
74: if (n[j]%k == 0)
75: {
76: if (++lpn >= BIL) err(talker,"overflow in calc_block");
77: pn[lpn] = n[j]; pnon[lpn] = j;
78: ngcd = cgcd(ngcd, n[j]);
79: }
80: if (dk % ngcd) continue;
81: T = 1<<lpn; if (!lpn) lpn = 1;
82: for (t=0; t<T; t++)
83: {
84: for (nn=n[1],tp=t, u=1; u<=lpn; u++,tp>>=1)
85: {
86: if (tp&1) { nn += pn[u]; e[u]=1; } else e[u]=0;
87: }
88: if (dk == nn)
89: {
1.2 ! noro 90: gpmem_t av=avma;
1.1 noro 91: int Z_equal_Zp = 1;
92:
93: for (j=1; j<lnon; j++) non[j]=0;
94: Zp[1]=Z[1];
95: for (u=2,j=1; j<=lpn; j++)
96: if (e[j])
97: {
98: Zp[u]=Z[pnon[j]]; non[pnon[j]]=1;
99: if (Zp[u] != Z[u]) Z_equal_Zp = 0;
100: u++;
101: }
102: setlg(Zp, u);
103: lY=lg(Y); Yp = cgetg(lY+1,t_VEC);
104: for (j=1; j<lY; j++) Yp[j]=Y[j];
105: Yp[lY]=(long)Zp;
106: if (r == u && Z_equal_Zp)
107: vbs = print_block_system(N,Yp,d,vbs,maxl);
108: else
109: {
110: for (u=1,j=2; j<r; j++)
111: if (!non[j]) Zpp[u++] = Z[j];
112: setlg(Zpp, u);
113: vbs = calc_block(N,Zpp,d,Yp,vbs,maxl);
114: }
1.2 ! noro 115: if (vbs && (ulong)lg(vbs) > maxl) return vbs;
1.1 noro 116: avma=av;
117: }
118: }
119: }
120: return vbs;
121: }
122:
123: static GEN
124: potential_block_systems(long N, long d, GEN n, ulong maxl)
125: {
1.2 ! noro 126: long r, i, j, k;
! 127: gpmem_t av=avma;
1.1 noro 128: GEN p1,vbs,Z;
129:
130: r=lg(n); Z=cgetg(r,t_VEC);
131: for (k=0,i=1; i<r; i++)
132: {
133: p1=cgetg(n[i]+1,t_VECSMALL); Z[i]=(long)p1;
134: for (j=1; j<=n[i]; j++) p1[j]= ++k;
135: }
136: vbs=calc_block(N,Z,d, cgetg(1,t_VEC), NULL, maxl);
137: avma=av; return vbs;
138: }
139:
140: /* product of permutations. Put the result in perm1. */
141: static void
1.2 ! noro 142: perm_mul_i(GEN perm1,GEN perm2)
1.1 noro 143: {
1.2 ! noro 144: long i, N = lg(perm1);
! 145: gpmem_t av = avma;
1.1 noro 146: GEN perm=new_chunk(N);
147: for (i=1; i<N; i++) perm[i]=perm1[perm2[i]];
148: for (i=1; i<N; i++) perm1[i]=perm[i];
149: avma=av;
150: }
151:
152: /* cy is a cycle; compute cy^l as a permutation */
153: static GEN
154: cycle_power_to_perm(GEN perm,GEN cy,long l)
155: {
156: long lp,i,j,b, N = lg(perm), lcy = lg(cy)-1;
157:
158: lp = l % lcy;
159: for (i=1; i<N; i++) perm[i] = i;
160: if (lp)
161: {
1.2 ! noro 162: gpmem_t av = avma;
1.1 noro 163: GEN p1 = new_chunk(N);
164: b = cy[1];
165: for (i=1; i<lcy; i++) b = (perm[b] = cy[i+1]);
166: perm[b] = cy[1];
167: for (i=1; i<N; i++) p1[i] = perm[i];
168:
1.2 ! noro 169: for (j=2; j<=lp; j++) perm_mul_i(perm,p1);
1.1 noro 170: avma = av;
171: }
172: return perm;
173: }
174:
175: /* image du block system D par la permutation perm */
176: static GEN
177: im_block_by_perm(GEN D,GEN perm)
178: {
179: long i,j,lb,lcy;
180: GEN Dn,cy,p1;
181:
182: lb=lg(D); Dn=cgetg(lb,t_VEC);
183: for (i=1; i<lb; i++)
184: {
185: cy=(GEN)D[i]; lcy=lg(cy);
186: Dn[i]=lgetg(lcy,t_VECSMALL); p1=(GEN)Dn[i];
187: for (j=1; j<lcy; j++) p1[j] = perm[cy[j]];
188: }
189: return Dn;
190: }
191:
192: /* cy is a cycle; recturn cy(a) */
193: static long
194: im_by_cy(long a,GEN cy)
195: {
196: long k, l = lg(cy);
197:
198: k=1; while (k<l && cy[k] != a) k++;
199: if (k == l) return a;
200: k++; if (k == l) k = 1;
201: return cy[k];
202: }
203:
204: /* vbs[0] = current cardinality+1, vbs[1] = max number of elts */
205: static GEN
206: append_vbs(GEN vbs, GEN D)
207: {
208: long l,maxl,i,j,n, lD = lg(D);
209: GEN Dn, last;
210:
211: n = 0; for (i=1; i<lD; i++) n += lg(D[i]);
212: Dn = (GEN)gpmalloc((lD + n) * sizeof(long));
213: last = Dn + lD; Dn[0] = D[0];
214: for (i=1; i<lD; i++)
215: {
216: GEN cy = (GEN)D[i], cn = last;
217: for (j=0; j<lg(cy); j++) cn[j] = cy[j];
218: Dn[i] = (long)cn; last = cn + j;
219: }
220:
221: if (!vbs)
222: {
223: maxl = 1024;
224: vbs = (GEN)gpmalloc((2 + maxl)*sizeof(GEN));
225: *vbs = maxl; vbs++; setlg(vbs, 1);
226: }
227: l = lg(vbs); maxl = vbs[-1];
228: if (l == maxl)
229: {
1.2 ! noro 230: vbs = (GEN)gprealloc((void*)(vbs-1), (2 + (maxl<<1))*sizeof(GEN));
1.1 noro 231: *vbs = maxl<<1; vbs++; setlg(vbs, 1);
232: }
233: if (DEBUGLEVEL>5) fprintferr("appending D = %Z\n",D);
234: vbs[l] = (long)Dn; setlg(vbs, l+1); return vbs;
235: }
236:
237: GEN
238: myconcat(GEN D, long a)
239: {
240: long i,l = lg(D);
241: GEN x = cgetg(l+1,t_VECSMALL);
242: for (i=1; i<l; i++) x[i]=D[i];
243: x[l] = a; return x;
244: }
245:
246: void
247: myconcat2(GEN D, GEN a)
248: {
249: long i,l = lg(D), m = lg(a);
250: GEN x = D + (l-1);
251: for (i=1; i<m; i++) x[i]=a[i];
252: setlg(D, l+m-1);
253: }
254:
255: static GEN
256: print_block_system(long N,GEN Y,long d,GEN vbs,long maxl)
257: {
258: long a,i,j,l,ll,*k,*n,lp,**e,u,v,*t,ns, r = lg(Y);
259: GEN D,De,Z,cyperm,perm,p1,empty;
260:
261: if (DEBUGLEVEL>5) fprintferr("Y = %Z\n",Y);
262: empty = cgetg(1,t_VEC);
263: n = new_chunk(N+1);
1.2 ! noro 264: D = cget1(N+1, t_VEC);
1.1 noro 265: t=new_chunk(r+1); k=new_chunk(r+1); Z=cgetg(r+1,t_VEC);
266: for (ns=0,i=1; i<r; i++)
267: {
268: GEN Yi = (GEN)Y[i], cy;
269: long ki = 0, si = lg(Yi)-1;
270:
271: for (j=1; j<=si; j++) { n[j]=lg(Yi[j])-1; ki += n[j]; }
272: ki /= d;
273: De=cgetg(ki+1,t_VEC);
274: for (j=1; j<=ki; j++) De[j]=(long)empty;
275: for (j=1; j<=si; j++)
276: {
277: cy = (GEN)Yi[j]; a = cy[1];
278: for (l=1,lp=0; l<=n[j]; l++)
279: {
280: lp++; if (lp>ki) lp = 1;
281: a = im_by_cy(a, cy);
282: De[lp] = (long)myconcat((GEN)De[lp], a);
283: }
284: }
285: if (si>1 && ki>1)
286: {
287: ns++; t[ns]=si-1; k[ns]=ki;
288: Z[ns]=lgetg(si,t_VEC); p1=(GEN)Z[ns];
289: for (j=2; j<=si; j++) p1[j-1]=Yi[j];
290: }
291: myconcat2(D,De);
292: }
293: if (DEBUGLEVEL>2) { fprintferr("\nns = %ld\n",ns); flusherr(); }
294: if (!ns) return append_vbs(vbs,D);
295:
296: setlg(Z, ns+1);
297: e=(long**)new_chunk(ns+1);
298: for (i=1; i<=ns; i++)
299: {
300: e[i]=new_chunk(t[i]+1);
301: for (j=1; j<=t[i]; j++) e[i][j]=0;
302: }
303: cyperm = cgetg(N+1,t_VEC);
304: perm = cgetg(N+1,t_VEC); i=ns;
305: do
306: {
1.2 ! noro 307: gpmem_t av = avma;
1.1 noro 308: if (DEBUGLEVEL>5)
309: {
310: for (l=1; l<=ns; l++)
311: {
312: for (ll=1; ll<=t[l]; ll++)
313: fprintferr("e[%ld][%ld] = %ld, ",l,ll,e[l][ll]);
314: fprintferr("\n");
315: }
316: fprintferr("\n"); flusherr();
317: }
318: for (u=1; u<=N; u++) perm[u]=u;
319: for (u=1; u<=ns; u++)
320: for (v=1; v<=t[u]; v++)
1.2 ! noro 321: perm_mul_i(perm, cycle_power_to_perm(cyperm,gmael(Z,u,v),e[u][v]));
1.1 noro 322: vbs = append_vbs(vbs, im_block_by_perm(D,perm));
323: if (lg(vbs) > maxl) return vbs;
324: avma = av;
325:
326: e[ns][t[ns]]++;
327: if (e[ns][t[ns]] >= k[ns])
328: {
329: j=t[ns]-1;
330: while (j>=1 && e[ns][j] == k[ns]-1) j--;
331: if (j>=1) { e[ns][j]++; for (l=j+1; l<=t[ns]; l++) e[ns][l]=0; }
332: else
333: {
334: i=ns-1;
335: while (i>=1)
336: {
337: j=t[i];
338: while (j>=1 && e[i][j] == k[i]-1) j--;
339: if (j<1) i--;
340: else
341: {
342: e[i][j]++;
343: for (l=j+1; l<=t[i]; l++) e[i][l]=0;
344: for (ll=i+1; ll<=ns; ll++)
345: for (l=1; l<=t[ll]; l++) e[ll][l]=0;
346: break;
347: }
348: }
349: }
350: }
351: }
352: while (i>0);
353: return vbs;
354: }
355:
356: static GEN
357: polsimplify(GEN x)
358: {
359: long i,lx = lgef(x);
360: for (i=2; i<lx; i++)
361: if (typ(x[i]) == t_POL) x[i] = (long)constant_term(x[i]);
362: return x;
363: }
364:
365: /* return 0 if |g[i]| > M[i] for some i; 1 otherwise */
366: static long
367: ok_coeffs(GEN g,GEN M)
368: {
369: long i, lg = lgef(g)-1; /* g is monic, and cst term is ok */
370: for (i=3; i<lg; i++)
371: if (absi_cmp((GEN)g[i], (GEN)M[i]) > 0) return 0;
372: return 1;
373: }
374:
375: /* Return a polynomial g defining a potential subfield, or
376: * 0: if p | d(g)
377: * 1: if coeffs of g are too large
378: * 2: same, detected by cheap d-1 test */
379: static GEN
380: cand_for_subfields(GEN A,GEN DATA,GEN *ptlistdelta)
381: {
382: long N,m,i,j,d,lf;
383: GEN M,T,pe,p,pol,fhk,g;
1.2 ! noro 384: GEN d_1_term,delta,listdelta,whichdelta,firstroot;
1.1 noro 385:
386: pol=(GEN)DATA[1];
387: p = (GEN)DATA[2];
388: pe= (GEN)DATA[3];
389: T = (GEN)DATA[4];
390: fhk=(GEN)DATA[5];
391: M = (GEN)DATA[8]; N=degpol(pol); m=lg(A)-1; d=N/m; /* m | M */
392: firstroot = (GEN)DATA[13];
393:
394: delta = cgetg(m+1,t_VEC);
395: lf = lg(firstroot);
396: listdelta = cgetg(lf, t_VEC);
397: whichdelta = cgetg(N+1, t_VECSMALL);
1.2 ! noro 398: d_1_term = gzero;
1.1 noro 399: for (i=1; i<=m; i++)
400: {
401: GEN Ai = (GEN)A[i], p1 = gun;
402: for (j=1; j<=d; j++)
1.2 ! noro 403: p1 = Fq_mul(p1, (GEN)fhk[Ai[j]], T,pe);
1.1 noro 404: delta[i] = (long)p1;
405: if (DEBUGLEVEL>2) fprintferr("delta[%ld] = %Z\n",i,p1);
406: /* g = prod (X - delta[i])
407: * if g o h = 0 (pol), we'll have h(Ai[j]) = delta[i] for all j */
408: /* fk[k] belongs to block number whichdelta[k] */
409: for (j=1; j<=d; j++) whichdelta[Ai[j]] = i;
410: if (typ(p1) == t_POL) p1 = constant_term(p1);
1.2 ! noro 411: d_1_term = addii(d_1_term, p1);
1.1 noro 412: }
1.2 ! noro 413: d_1_term = centermod(d_1_term, pe); /* Tr(g) */
! 414: if (absi_cmp(d_1_term, (GEN)M[3]) > 0) return gdeux; /* d-1 test */
1.1 noro 415: g = FqV_roots_to_pol(delta, T, pe, 0);
416: g = centermod(polsimplify(g), pe); /* assume g in Z[X] */
417: if (DEBUGLEVEL>2) fprintferr("pol. found = %Z\n",g);
418: if (!ok_coeffs(g,M)) return gun;
419: if (!FpX_is_squarefree(g, p)) return gzero;
420:
421: for (i=1; i<lf; i++) listdelta[i] = delta[whichdelta[firstroot[i]]];
422: *ptlistdelta = listdelta; return g;
423: }
424:
425: /* return U list of polynomials s.t U[i] = 1 mod fk[i] and 0 mod fk[j] for all
426: * other j */
427: static GEN
428: get_bezout(GEN pol, GEN fk, GEN p)
429: {
430: GEN A,B,d,u,v,bezout_coeff;
431: long i, l = lg(fk);
432:
433: pol = FpX_red(pol, p);
434: bezout_coeff = cgetg(l, t_VEC);
435: for (i=1; i<l; i++)
436: {
437: A = (GEN)fk[i];
438: B = FpX_div(pol, A, p);
439: d = FpX_extgcd(A,B,p, &u, &v);
440: if (degpol(d) > 0) err(talker, "relatively prime polynomials expected");
441: d = constant_term(d);
442: if (!gcmp1(d))
443: {
444: d = mpinvmod(d, p);
445: v = FpX_Fp_mul(v,d, p);
446: }
447: bezout_coeff[i] = (long)FpX_mul(B,v, p);
448: }
449: return bezout_coeff;
450: }
451:
452: /* assume x in Fq, return Tr_{Fq/Fp}(x) as a t_INT */
453: static GEN
454: trace(GEN x, GEN Trq, GEN p)
455: {
456: long i, l;
457: GEN s;
458: if (typ(x) == t_INT) return modii(mulii(x, (GEN)Trq[1]), p);
459: l = lgef(x)-1; if (l == 1) return gzero;
460: x++; s = mulii((GEN)x[1], (GEN)Trq[1]);
461: for (i=2; i<l; i++)
462: s = addii(s, mulii((GEN)x[i], (GEN)Trq[i]));
463: return modii(s, p);
464: }
465:
466: /* assume x in Fq[X], return Tr_{Fq[X]/Fp[X]}(x), varn(X) = 0 */
467: static GEN
468: poltrace(GEN x, GEN Trq, GEN p)
469: {
470: long i,l;
471: GEN y;
472: if (typ(x) == t_INT || varn(x) != 0) return trace(x, Trq, p);
473: l = lgef(x); y = cgetg(l,t_POL); y[1]=x[1];
474: for (i=2; i<l; i++) y[i] = (long)trace((GEN)x[i],Trq,p);
475: return y;
476: }
477:
478: /* Find h in Fp[X] such that h(a[i]) = listdelta[i] for all modular factors
479: * ff[i], where a[i] is a fixed root of ff[i] in Fq = Z[Y]/(p,T) [namely the
480: * first one in Fp_factor_irred output]. Let f = ff[i], A the given root, then
481: * h mod f is Tr_Fq/Fp ( h(A) f(X)/(X-A)f'(A) ), most of the expression being
482: * precomputed. The complete h is recovered via chinese remaindering */
483: static GEN
484: chinese_retrieve_pol(GEN DATA, GEN listdelta)
485: {
486: GEN interp,Trk,bezoutC,T,p, S,p1;
487: long i,l;
488: p = (GEN)DATA[2];
489: T = (GEN)DATA[4];
490: interp = (GEN)DATA[10];
491: Trk = (GEN)DATA[11];
492: bezoutC = (GEN)DATA[12];
493:
494: S = NULL; l = lg(interp);
495: for (i=1; i<l; i++)
496: { /* h(firstroot[i]) = listdelta[i] */
497: p1 = FpXQX_FpXQ_mul((GEN)interp[i], (GEN)listdelta[i], T,p);
498: p1 = poltrace(p1, (GEN)Trk[i], p);
499: p1 = gmul(p1, (GEN)bezoutC[i]);
500: S = S? gadd(S,p1): p1;
501: }
502: return FpX_res(FpX_red(S, p), FpX_red((GEN)DATA[1],p), p);
503: }
504:
1.2 ! noro 505: /* return P(X + c) using destructive Horner */
! 506: static GEN
! 507: TR_pol(GEN P, GEN c)
! 508: {
! 509: GEN Q = dummycopy(P), *R;
! 510: long i,k,n;
! 511:
! 512: if (!signe(P)) return Q;
! 513: R = (GEN*)(Q+2); n = degpol(P);
! 514: if (gcmp1(c))
! 515: {
! 516: for (i=1; i<=n; i++)
! 517: for (k=n-i; k<n; k++)
! 518: R[k] = gadd(R[k], R[k+1]);
! 519: }
! 520: else if (gcmp_1(c))
! 521: {
! 522: for (i=1; i<=n; i++)
! 523: for (k=n-i; k<n; k++)
! 524: R[k] = gsub(R[k], R[k+1]);
! 525: }
! 526: else
! 527: {
! 528: for (i=1; i<=n; i++)
! 529: for (k=n-i; k<n; k++)
! 530: R[k] = gadd(R[k], gmul(c, R[k+1]));
! 531: }
! 532: return Q;
! 533: }
! 534:
1.1 noro 535: /* g in Z[X] potentially defines a subfield of Q[X]/f. It is a subfield iff A
536: * (cf cand_for_subfields) was a block system; then there
537: * exists h in Q[X] such that f | g o h. listdelta determines h s.t f | g o h
538: * in Fp[X] (cf chinese_retrieve_pol). We try to lift it. */
539: static GEN
540: embedding_of_potential_subfields(GEN g,GEN DATA,GEN listdelta)
541: {
542: GEN TR,w0_Q,w0,w1_Q,w1,wpow,h0,gp,T,q2,q,p,ind,maxp,a;
543: long rt;
1.2 ! noro 544: gpmem_t av;
1.1 noro 545:
546: T = (GEN)DATA[1]; rt = brent_kung_optpow(degpol(T), 2);
547: p = (GEN)DATA[2];
548: maxp = (GEN)DATA[7];
549: ind = (GEN)DATA[9];
550: gp = derivpol(g); av = avma;
551: w0 = chinese_retrieve_pol(DATA,listdelta);
552: w0_Q = centermod(gmul(w0,ind), p);
553: h0 = FpXQ_inv(FpX_FpXQ_compo(gp,w0, T,p), T,p); /* = 1/g'(w0) mod (T,p) */
554: wpow = NULL; q = sqri(p);
555: for(;;)
556: {/* Given g,w0,h0 in Z[x], s.t. h0.g'(w0) = 1 and g(w0) = 0 mod (T,p), find
557: * [w1,h1] satisfying the same conditions mod p^2, [w1,h1] = [w0,h0] (mod p)
558: * (cf. Dixon: J. Austral. Math. Soc., Series A, vol.49, 1990, p.445) */
559: if (DEBUGLEVEL>1) fprintferr("lifting embedding mod p = %Z\n",q);
560:
561: /* w1 := w0 - h0 g(w0) mod (T,q) */
562: if (wpow)
563: a = FpX_FpXQV_compo(g,wpow, T,q);
564: else
565: a = FpX_FpXQ_compo(g,w0, T,q); /* first time */
566: /* now, a = 0 (p) */
567: a = gmul(gneg(h0), gdivexact(a, p));
568: w1 = gadd(w0, gmul(p, FpX_res(a, T,p)));
569:
570: w1_Q = centermod(gmul(w1, resii(ind,q)), q);
571: if (gegal(w1_Q, w0_Q) || cmpii(q,maxp) > 0)
572: {
1.2 ! noro 573: GEN G = gcmp1(ind)? g: rescale_pol(g,ind);
1.1 noro 574: if (gcmp0(poleval(G, gmodulcp(w1_Q,T)))) break;
575: }
576: if (cmpii(q, maxp) > 0)
577: {
578: if (DEBUGLEVEL) fprintferr("coeff too big for embedding\n");
579: return NULL;
580: }
581: {
582: GEN *gptr[5]; gptr[0]=&w1; gptr[1]=&h0; gptr[2]=&w1_Q;
583: gptr[3]=&q; gptr[4]=&p;
584: gerepilemany(av,gptr,5);
585: }
586:
587: q2 = sqri(q);
588: wpow = FpXQ_powers(w1, rt, T, q2);
589: /* h0 := h0 * (2 - h0 g'(w1)) mod (T,q)
590: * = h0 + h0 * (1 - h0 g'(w1)) */
591: a = gmul(gneg(h0), FpX_FpXQV_compo(gp, FpXV_red(wpow,q),T,q));
592: a = ZX_s_add(FpX_res(a, T,q), 1); /* 1 - h0 g'(w1) = 0 (p) */
593: a = gmul(h0, gdivexact(a, p));
594: h0 = gadd(h0, gmul(p, FpX_res(a, T,p)));
595: w0 = w1; w0_Q = w1_Q; p = q; q = q2;
596: }
597: TR = (GEN)DATA[14];
1.2 ! noro 598: if (!gcmp0(TR)) w1_Q = TR_pol(w1_Q, TR);
1.1 noro 599: return gdiv(w1_Q,ind);
600: }
601:
602: static GEN
603: choose_prime(GEN pol,GEN dpol,long d,GEN *ptff,GEN *ptlistpotbl, long *ptlcm)
604: {
1.2 ! noro 605: gpmem_t av;
! 606: byteptr di=diffptr;
! 607: long j,k,oldllist,llist,r,lcm,oldlcm,pp,minp, N = degpol(pol), m = N/d;
1.1 noro 608: GEN p,listpotbl,oldlistpotbl,ff,oldff,n,oldn;
1.2 ! noro 609:
! 610: minp = N*(m-1)/2;
! 611: if (DEBUGLEVEL) (void)timer2();
! 612: di++; p = stoi(2);
! 613: while (p[2]<=minp)
! 614: NEXT_PRIME_VIADIFF(p[2], di);
1.1 noro 615: oldllist = 100000;
616: oldlcm = 0;
617: oldlistpotbl = oldff = oldn = NULL; pp = 0; /* gcc -Wall */
618: av = avma;
1.2 ! noro 619: for(k=1; k<11 || !oldn; k++,avma = av)
1.1 noro 620: {
1.2 ! noro 621: while (!smodis(dpol,p[2]))
! 622: NEXT_PRIME_VIADIFF(p[2], di);
1.1 noro 623: if (k > 50) err(talker,"sorry, too many block systems in nfsubfields");
1.2 ! noro 624: ff=(GEN)factmod0(pol,p)[1]; r=lg(ff)-1;
! 625: if (r == 1 || r == N) goto repeat;
1.1 noro 626:
627: n = cgetg(r+1, t_VECSMALL);
628: lcm = n[1] = degpol(ff[1]);
629: for (j=2; j<=r; j++) { n[j] = degpol(ff[j]); lcm = clcm(lcm,n[j]); }
1.2 ! noro 630: if (lcm < oldlcm) goto repeat; /* false when oldlcm = 0 */
! 631: if (r >= BIL) { err(warner,"subfields: overflow in calc_block"); goto repeat; }
1.1 noro 632: if (DEBUGLEVEL) fprintferr("p = %ld,\tlcm = %ld,\torbits: %Z\n",p[2],lcm,n);
1.2 ! noro 633: if (oldn && gegal(n,oldn)) goto repeat;
1.1 noro 634:
635: listpotbl = potential_block_systems(N,d,n, oldllist);
636: if (!listpotbl) { oldlistpotbl = NULL; pp = p[2]; break; }
637: llist = lg(listpotbl)-1;
638: if (llist >= oldllist)
639: {
640: if (DEBUGLEVEL) msgtimer("#pbs >= %ld [aborted]",oldllist);
641: for (j=1; j<llist; j++) free((void*)listpotbl[j]);
1.2 ! noro 642: free((void*)(listpotbl-1)); goto repeat;
1.1 noro 643: }
644: oldllist = llist; oldlistpotbl = listpotbl;
645: pp = p[2]; oldff = ff; oldlcm = lcm; oldn = n;
646: if (DEBUGLEVEL) msgtimer("#pbs = %ld",llist);
647: av = avma;
1.2 ! noro 648: repeat:
! 649: NEXT_PRIME_VIADIFF(p[2], di);
1.1 noro 650: }
1.2 ! noro 651: if (DEBUGLEVEL) fprintferr("Chosen prime: p = %ld\n",pp);
1.1 noro 652: *ptlistpotbl=oldlistpotbl; *ptff=oldff; *ptlcm=oldlcm; return stoi(pp);
653: }
654:
655: static GEN
656: bound_for_coeff(long m,GEN rr, GEN *maxroot)
657: {
658: long i,r1, lrr=lg(rr);
659: GEN p1,b1,b2,B,M, C = matpascal(m-1);
660:
1.2 ! noro 661: for (r1=1; r1 < lrr; r1++)
! 662: if (typ(rr[r1]) != t_REAL) break;
! 663: r1--;
1.1 noro 664:
665: rr = gabs(rr,0); *maxroot = vecmax(rr);
666: for (i=1; i<lrr; i++)
667: if (gcmp((GEN)rr[i], gun) < 0) rr[i] = un;
668: for (b1=gun,i=1; i<=r1; i++) b1 = gmul(b1, (GEN)rr[i]);
669: for (b2=gun ; i<lrr; i++) b2 = gmul(b2, (GEN)rr[i]);
670: B = gmul(b1, gsqr(b2)); /* Mahler measure */
671: M = cgetg(m+2, t_VEC); M[1]=M[2]=zero; /* unused */
672: for (i=1; i<m; i++)
673: {
674: p1 = gadd(gmul(gcoeff(C, m, i+1), B),/* binom(m-1, i) */
675: gcoeff(C, m, i)); /* binom(m-1, i-1) */
676: M[i+2] = (long)ceil_safe(p1);
677: }
678: return M;
679: }
680:
681: static GEN
682: init_traces(GEN ff, GEN T, GEN p)
683: {
684: long N = degpol(T),i,j,k, r = lg(ff);
685: GEN Frob = matrixpow(N,N, FpXQ_pow(polx[varn(T)],p, T,p), T,p);
686: GEN y,p1,p2,Trk,pow,pow1;
687:
688: k = degpol(ff[r-1]); /* largest degree in modular factorization */
689: pow = cgetg(k+1, t_VEC);
690: pow[1] = (long)zero; /* dummy */
691: pow[2] = (long)Frob;
692: pow1= cgetg(k+1, t_VEC); /* 1st line */
693: for (i=3; i<=k; i++)
694: pow[i] = (long)FpM_mul((GEN)pow[i-1], Frob, p);
695: pow1[1] = (long)zero; /* dummy */
696: for (i=2; i<=k; i++)
697: {
698: p1 = cgetg(N+1, t_VEC);
699: pow1[i] = (long)p1; p2 = (GEN)pow[i];
700: for (j=1; j<=N; j++) p1[j] = coeff(p2,1,j);
701: }
702: p1 = cgetg(N+1,t_VEC); p1[1] = un;
703: for (i=2; i<=N; i++) p1[i] = zero;
704: /* Trk[i] = line 1 of x -> x + x^p + ... + x^{p^(i-1)} */
705: Trk = pow; /* re-use (destroy) pow */
706: Trk[1] = (long)p1;
707: for (i=2; i<=k; i++)
708: Trk[i] = ladd((GEN)Trk[i-1], (GEN)pow1[i]);
709: y = cgetg(r, t_VEC);
710: for (i=1; i<r; i++) y[i] = Trk[degpol(ff[i])];
711: return y;
712: }
713:
714: /* return C in Z[X]/(p,T), C[ D[1] ] = 1, C[ D[i] ] = 0 otherwise. H is the
715: * list of degree 1 polynomials X - D[i] (come directly from factorization) */
716: static GEN
717: interpol(GEN H, GEN T, GEN p)
718: {
719: long i, m = lg(H);
720: GEN X = polx[0],d,p1,p2,a;
721:
722: p1=polun[0]; p2=gun; a = gneg(constant_term(H[1])); /* = D[1] */
723: for (i=2; i<m; i++)
724: {
725: d = constant_term(H[i]); /* -D[i] */
726: p1 = FpXQX_mul(p1,gadd(X,d), T,p);
1.2 ! noro 727: p2 = Fq_mul(p2, gadd(a,d), T,p);
1.1 noro 728: }
729: p2 = FpXQ_inv(p2, T,p);
730: return FpXQX_FpXQ_mul(p1,p2, T,p);
731: }
732:
733: static GEN
734: roots_from_deg1(GEN x)
735: {
736: long i,l = lg(x);
737: GEN r = cgetg(l,t_VEC);
738: for (i=1; i<l; i++) r[i] = lneg(constant_term(x[i]));
739: return r;
740: }
741:
742: struct poldata
743: {
744: GEN pol;
745: GEN dis; /* |disc(pol)| */
746: GEN roo; /* roots(pol) */
747: GEN den; /* multiple of index(pol) */
748: };
749:
750: /* ff = factmod(nf[1], p), d = requested degree for subfield. Return DATA,
751: * valid for given nf, p and d
752: * 1: polynomial nf[1],
753: * 2: prime p,
754: * 3: exponent e (for Hensel lifts) such that p^e > max(M),
755: * 4: polynomial defining the field F_(p^nn),
756: * 5: Hensel lift to precision p^e of DATA[6]
757: * 6: roots of nf[1] in F_(p^nn),
758: * 7: Hadamard bound for coefficients of h(x) such that g o h = 0 mod nf[1].
759: * 8: bound M for polynomials defining subfields x DATA[9]
760: * 9: multiple of index of nf
761: *10: *[i] = interpolation polynomial for ff[i] [= 1 on the first root
762: firstroot[i], 0 on the others]
763: *11: Trk used to compute traces (cf poltrace)
764: *12: Bezout coefficients associated to the ff[i]
765: *13: *[i] = index of first root of ff[i] (in DATA[6])
766: *14: number of polynomial changes (translations) */
767: static GEN
768: compute_data(GEN DATA, struct poldata PD, long d, GEN ff, GEN T,GEN p)
769: {
1.2 ! noro 770: long i,j,l,e,N, lff = lg(ff);
! 771: GEN ffL,den,roo,pe,p1,p2,fk,fhk,MM,maxroot,pol,interp,bezoutC;
1.1 noro 772:
773: if (DEBUGLEVEL>1) { fprintferr("Entering compute_data()\n\n"); flusherr(); }
774: pol = PD.pol; N = degpol(pol);
775: roo = PD.roo;
776: den = PD.den;
777: if (DATA) /* update (translate) an existing DATA */
778: {
779: GEN Xm1 = gsub(polx[varn(pol)], gun);
780: GEN TR = addis((GEN)DATA[14],1);
1.2 ! noro 781: GEN mTR = negi(TR), mun = negi(gun);
1.1 noro 782: DATA[14] = (long)TR;
1.2 ! noro 783: pol = TR_pol(pol, mTR);
1.1 noro 784: p1 = dummycopy(roo); l = lg(p1);
785: for (i=1; i<l; i++) p1[i] = ladd(TR, (GEN)p1[i]);
786: roo = p1;
787:
788: fk = (GEN)DATA[6]; l=lg(fk);
789: for (i=1; i<l; i++) fk[i] = lsub(Xm1, (GEN)fk[i]);
790:
791: interp = (GEN)DATA[10];
792: bezoutC = (GEN)DATA[12]; l = lg(interp);
793: for (i=1; i<l; i++)
794: {
795: if (degpol(interp[i]) > 0) /* do not turn polun[0] into gun */
796: {
1.2 ! noro 797: p1 = TR_pol((GEN)interp[i], mun);
1.1 noro 798: interp[i] = (long)FpXQX_red(p1, NULL,p);
799: }
800: if (degpol(bezoutC[i]) > 0)
801: {
1.2 ! noro 802: p1 = TR_pol((GEN)bezoutC[i], mun);
1.1 noro 803: bezoutC[i] = (long)FpXQX_red(p1, NULL,p);
804: }
805: }
1.2 ! noro 806: p1 = cgetg(lff, t_VEC);
! 807: for (i=1; i<lff; i++)
! 808: p1[i] = (long)FpX_red(TR_pol((GEN)ff[i], mTR), p);
! 809: ff = p1;
1.1 noro 810: }
811: else
812: {
1.2 ! noro 813: GEN firstroot = cgetg(lff, t_VECSMALL);
1.1 noro 814: DATA = cgetg(15,t_VEC);
815: DATA[2] = (long)p;
816: DATA[4] = (long)T;
1.2 ! noro 817: interp = cgetg(lff, t_VEC);
1.1 noro 818: fk = cgetg(N+1,t_VEC);
1.2 ! noro 819: for (l=1,j=1; j<lff; j++)
1.1 noro 820: { /* compute roots and fix ordering (Frobenius cycles) */
1.2 ! noro 821: p1 = Fp_factor_irred((GEN)ff[j], p,T);
1.1 noro 822: interp[j] = (long)interpol(p1,T,p);
823: firstroot[j] = l;
824: for (i=1; i<lg(p1); i++,l++) fk[l] = p1[i];
825: }
826: DATA[9] = (long)PD.den;
827: DATA[10]= (long)interp;
828: DATA[11]= (long)init_traces(ff, T,p);
829: DATA[12]= (long)get_bezout(pol,ff,p);
830: DATA[13]= (long)firstroot;
831: DATA[14]= zero;
832: }
833: DATA[1] = (long)pol;
834: MM = bound_for_coeff(d, roo, &maxroot);
835: MM = gmul2n(MM,1);
836: DATA[8] = (long)MM;
837: e = logint(shifti(vecmax(MM),20), p, &pe); /* overlift 2^20 [for d-1 test] */
838: DATA[3] = (long)pe;
839: DATA[6] = (long)roots_from_deg1(fk);
1.2 ! noro 840:
! 841: #if 0
1.1 noro 842: fhk = hensel_lift_fact(pol,fk,(GEN)DATA[4],p,pe,e);
1.2 ! noro 843: #else
! 844: /* first lift in Zp to precision p^e */
! 845: ffL = hensel_lift_fact(pol,ff, NULL,p,pe,e);
! 846: fhk = NULL;
! 847: for (l=i=1; i<lff; i++)
! 848: { /* lift factorization of ff[i] in Qp[X] / T */
! 849: GEN L = (GEN)ffL[i];
! 850: long di = degpol(L);
! 851: p2 = cgetg(di+1, t_VEC);
! 852: for (j=1; j<=di; j++) p2[j] = fk[l++];
! 853: p1 = hensel_lift_fact(L,p2,T,p,pe,e);
! 854: fhk = fhk? concatsp(fhk, p1): p1;
! 855: }
! 856: #endif
1.1 noro 857: DATA[5] = (long)roots_from_deg1(fhk);
858:
859: p1 = gmul(stoi(N), gsqrt(gpuigs(stoi(N-1),N-1),DEFAULTPREC));
860: p2 = gpuigs(maxroot, N/d + N*(N-1)/2);
861: p1 = gdiv(gmul(p1,p2), gsqrt(PD.dis,DEFAULTPREC));
862: p1 = shifti(ceil_safe(p1), 1);
863: DATA[7] = lmulii(p1, PD.den);
864:
865: if (DEBUGLEVEL>1) {
866: fprintferr("f = %Z\n",DATA[1]);
867: fprintferr("p = %Z, lift to p^%ld\n",DATA[2], e);
868: fprintferr("Fq defined by %Z\n",DATA[4]);
869: fprintferr("2 * Hadamard bound * ind = %Z\n",DATA[7]);
870: fprintferr("2 * M = %Z\n",DATA[8]);
871: }
872: return DATA;
873: }
874:
875: /* g = polynomial, h = embedding. Return [[g,h]] */
876: static GEN
877: _subfield(GEN g, GEN h)
878: {
879: GEN x = cgetg(3,t_VEC);
880: x[1] = (long)g;
881: x[2] = (long)h; return _vec(x);
882: }
883:
884: /* subfields of degree d */
885: static GEN
886: subfields_of_given_degree(struct poldata PD,long d)
887: {
1.2 ! noro 888: gpmem_t av, av2;
! 889: long llist,i,nn,v;
1.1 noro 890: GEN listpotbl,ff,A,CSF,ESF,LSB,p,T,DATA,listdelta;
891: GEN pol = PD.pol, dpol = PD.dis;
892:
893: if (DEBUGLEVEL) fprintferr("\n*** Look for subfields of degree %ld\n\n", d);
894: av = avma;
895: p = choose_prime(pol,dpol,degpol(pol)/d,&ff,&listpotbl,&nn);
896: if (!listpotbl) { avma=av; return cgetg(1,t_VEC); }
1.2 ! noro 897: v = fetch_var(); name_var(v,"y");
! 898: T = lift_intern(ffinit(p,nn, v));
1.1 noro 899: DATA = NULL; LSB = cgetg(1,t_VEC);
900: i = 1; llist = lg(listpotbl);
901: CHANGE:
902: DATA = compute_data(DATA,PD,d, ff,T,p);
903: for (; i<llist; i++)
904: {
905: av2 = avma; A = (GEN)listpotbl[i];
906: if (DEBUGLEVEL > 1) fprintferr("\n* Potential block # %ld: %Z\n",i,A);
907: CSF = cand_for_subfields(A,DATA,&listdelta);
908: if (typ(CSF)==t_INT)
909: {
910: avma = av2;
911: if (DEBUGLEVEL > 1) switch(itos(CSF))
912: {
913: case 0: fprintferr("changing f(x): p divides disc(g(x))\n"); break;
914: case 1: fprintferr("coeff too big for pol g(x)\n"); break;
915: case 2: fprintferr("d-1 test failed\n"); break;
916: }
917: if (CSF==gzero) goto CHANGE;
918: }
919: else
920: {
921: if (DEBUGLEVEL) fprintferr("candidate = %Z\n",CSF);
922: ESF = embedding_of_potential_subfields(CSF,DATA,listdelta);
923: if (!ESF) { avma = av2; continue; }
924:
925: if (DEBUGLEVEL) fprintferr("embedding = %Z\n",ESF);
926: LSB = gerepileupto(av2, concat(LSB, _subfield(CSF,ESF)));
927: }
928: }
1.2 ! noro 929: (void)delete_var();
1.1 noro 930: for (i=1; i<llist; i++) free((void*)listpotbl[i]);
931: free((void*)(listpotbl-1));
932: if (DEBUGLEVEL) fprintferr("\nSubfields of degree %ld: %Z\n",d, LSB);
933: return gerepilecopy(av, LSB);
934: }
935:
936: static GEN
937: fix_var(GEN x, long v)
938: {
939: long i, l = lg(x);
940: x = gcopy(x); if (!v) return x;
941: for (i=1; i<l; i++) { GEN t = (GEN)x[i]; setvarn(t[1],v); setvarn(t[2],v); }
942: return x;
943: }
944:
945: void
946: subfields_poldata(GEN T, struct poldata *PD)
947: {
1.2 ! noro 948: GEN nf,L,dis;
1.1 noro 949:
950: T = get_nfpol(T, &nf);
951: PD->pol = dummycopy(T); /* may change variable number later */
952: if (nf)
953: {
1.2 ! noro 954: PD->den = Q_denom((GEN)nf[7]);
1.1 noro 955: PD->roo = (GEN)nf[6];
956: PD->dis = mulii(absi((GEN)nf[3]), sqri((GEN)nf[4]));
957: }
1.2 ! noro 958: else
! 959: {
! 960: PD->den = initgaloisborne(T,NULL,ZX_get_prec(T), &L,NULL,&dis);
! 961: PD->roo = L;
! 962: PD->dis = absi(dis);
! 963: }
1.1 noro 964: }
965:
966: GEN
967: subfields(GEN nf,GEN d)
968: {
1.2 ! noro 969: gpmem_t av = avma;
! 970: long di, N, v0;
! 971: GEN LSB, pol, G;
1.1 noro 972: struct poldata PD;
973:
974: pol = get_nfpol(nf, &nf); /* in order to treat trivial cases */
975: v0=varn(pol); N=degpol(pol); di=itos(d);
976: if (di==N) return gerepilecopy(av, _subfield(pol, polx[v0]));
977: if (di==1) return gerepilecopy(av, _subfield(polx[v0], pol));
978: if (di < 1 || di > N || N % di) return cgetg(1,t_VEC);
979:
1.2 ! noro 980: /* much easier if nf is Galois (WSS) */
! 981: G = galoisconj4(nf? nf: pol, NULL, 1, 0);
! 982: if (typ(G) != t_INT)
! 983: { /* Bingo */
! 984: GEN L = galoissubgroups(G), F;
! 985: long k,i, l = lg(L), o = N/di;
! 986: F = cgetg(l, t_VEC);
! 987: k = 1;
! 988: for (i=1; i<l; i++)
! 989: {
! 990: GEN H = (GEN)L[i];
! 991: if (group_order(H) == o)
! 992: F[k++] = (long) lift_intern(galoisfixedfield(G, (GEN)H[1], 0, v0));
! 993: }
! 994: setlg(F, k);
! 995: return gerepilecopy(av, F);
! 996: }
! 997:
! 998: subfields_poldata(nf? nf:pol, &PD);
1.1 noro 999: pol = PD.pol;
1000: setvarn(pol, 0);
1001: LSB = subfields_of_given_degree(PD, di);
1002: return gerepileupto(av, fix_var(LSB,v0));
1003: }
1004:
1005: static GEN
1006: subfieldsall(GEN nf)
1007: {
1.2 ! noro 1008: gpmem_t av = avma;
! 1009: long N, ld, i, v0;
! 1010: GEN G, pol, dg, LSB, NLSB;
1.1 noro 1011: struct poldata PD;
1012:
1.2 ! noro 1013: /* much easier if nf is Galois (WSS) */
! 1014: G = galoisconj4(nf, NULL, 1, 0);
! 1015: if (typ(G) != t_INT)
! 1016: {
! 1017: pol = get_nfpol(nf, &nf);
! 1018: return gerepilecopy(av, lift_intern( galoissubfields(G, 0, varn(pol)) ));
! 1019: }
! 1020:
1.1 noro 1021: subfields_poldata(nf, &PD);
1022: pol = PD.pol;
1023:
1024: v0 = varn(pol); N = degpol(pol);
1025: dg = divisors(stoi(N)); ld = lg(dg)-1;
1026: if (DEBUGLEVEL) fprintferr("\n***** Entering subfields\n\npol = %Z\n",pol);
1027:
1028: LSB = _subfield(pol,polx[0]);
1029: if (ld > 2)
1030: {
1031: setvarn(pol, 0);
1032: for (i=2; i<ld; i++)
1033: {
1.2 ! noro 1034: gpmem_t av1 = avma;
1.1 noro 1035: NLSB = subfields_of_given_degree(PD, N / itos((GEN)dg[i]));
1036: if (lg(NLSB) > 1) LSB = concatsp(LSB,NLSB); else avma = av1;
1037: }
1038: }
1039: LSB = concatsp(LSB, _subfield(polx[0],pol));
1040: if (DEBUGLEVEL) fprintferr("\n***** Leaving subfields\n\n");
1041: return gerepileupto(av, fix_var(LSB,v0));
1042: }
1043:
1044: GEN
1045: subfields0(GEN nf,GEN d)
1046: {
1047: return d? subfields(nf,d): subfieldsall(nf);
1048: }
1049:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>