Annotation of OpenXM_contrib/pari-2.2/src/basemath/galconj.c, Revision 1.3
1.3 ! noro 1: /* $Id: galconj.c,v 1.106 2002/09/08 10:47:36 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:
1.3 ! noro 16: #include "pari.h"
! 17: extern GEN bezout_lift_fact(GEN T, GEN Tmod, GEN p, long e);
! 18: extern GEN respm(GEN x,GEN y,GEN pm);
! 19: extern GEN ZX_disc_all(GEN,long);
! 20: extern GEN polratlift(GEN P, GEN mod, GEN amax, GEN bmax, GEN denom);
! 21: extern GEN znstar_hnf_elts(GEN Z, GEN H);
! 22: extern long ZX_get_prec(GEN x);
! 23:
1.1 noro 24: /*************************************************************************/
25: /** **/
26: /** GALOIS CONJUGATES **/
27: /** **/
28: /*************************************************************************/
1.3 ! noro 29:
1.1 noro 30: GEN
31: galoisconj(GEN nf)
32: {
33: GEN x, y, z;
1.3 ! noro 34: long i, lz, v;
! 35: gpmem_t av = avma;
1.1 noro 36: nf = checknf(nf);
37: x = (GEN) nf[1];
38: v = varn(x);
39: if (v == 0)
40: nf = gsubst(nf, 0, polx[MAXVARN]);
41: else
42: {
43: x = dummycopy(x);
44: setvarn(x, 0);
45: }
46: z = nfroots(nf, x);
47: lz = lg(z);
48: y = cgetg(lz, t_COL);
49: for (i = 1; i < lz; i++)
50: {
51: GEN p1 = lift((GEN) z[i]);
52: setvarn(p1, v);
53: y[i] = (long) p1;
54: }
55: return gerepileupto(av, y);
56: }
57:
58: /* nbmax: maximum number of possible conjugates */
59: GEN
60: galoisconj2pol(GEN x, long nbmax, long prec)
61: {
1.3 ! noro 62: long i, n, v, nbauto;
! 63: gpmem_t av = avma;
1.1 noro 64: GEN y, w, polr, p1, p2;
65: n = degpol(x);
66: if (n <= 0)
67: return cgetg(1, t_VEC);
68: if (gisirreducible(x) == gzero)
69: err(redpoler, "galoisconj2pol");
70: polr = roots(x, prec);
71: p1 = (GEN) polr[1];
72: nbauto = 1;
73: prec = (long) (bit_accuracy(prec) * L2SL10 * 0.75);
74: w = cgetg(n + 2, t_VEC);
75: w[1] = un;
76: for (i = 2; i <= n; i++)
77: w[i] = lmul(p1, (GEN) w[i - 1]);
78: v = varn(x);
79: y = cgetg(nbmax + 1, t_COL);
80: y[1] = (long) polx[v];
81: for (i = 2; i <= n && nbauto < nbmax; i++)
82: {
83: w[n + 1] = polr[i];
84: p1 = lindep2(w, prec);
85: if (signe(p1[n + 1]))
86: {
87: setlg(p1, n + 1);
88: p2 = gdiv(gtopolyrev(p1, v), negi((GEN) p1[n + 1]));
89: if (gdivise(poleval(x, p2), x))
90: {
91: y[++nbauto] = (long) p2;
92: if (DEBUGLEVEL > 1)
93: fprintferr("conjugate %ld: %Z\n", i, y[nbauto]);
94: }
95: }
96: }
97: setlg(y, 1 + nbauto);
98: return gerepileupto(av, gen_sort(y, 0, cmp_pol));
99: }
100:
101: GEN
102: galoisconj2(GEN nf, long nbmax, long prec)
103: {
1.3 ! noro 104: long i, j, n, r1, ru, nbauto;
! 105: gpmem_t av = avma;
1.1 noro 106: GEN x, y, w, polr, p1, p2;
107: if (typ(nf) == t_POL)
108: return galoisconj2pol(nf, nbmax, prec);
109: nf = checknf(nf);
110: x = (GEN) nf[1];
111: n = degpol(x);
112: if (n <= 0)
113: return cgetg(1, t_VEC);
114: r1 = nf_get_r1(nf);
115: p1 = (GEN) nf[6];
116: prec = precision((GEN) p1[1]);
117: /* accuracy in decimal digits */
118: prec = (long) (bit_accuracy(prec) * L2SL10 * 0.75);
119: ru = (n + r1) >> 1;
120: nbauto = 1;
121: polr = cgetg(n + 1, t_VEC);
122: for (i = 1; i <= r1; i++)
123: polr[i] = p1[i];
124: for (j = i; i <= ru; i++)
125: {
126: polr[j++] = p1[i];
127: polr[j++] = lconj((GEN) p1[i]);
128: }
129: p2 = gmael(nf, 5, 1);
130: w = cgetg(n + 2, t_VEC);
131: for (i = 1; i <= n; i++)
132: w[i] = coeff(p2, 1, i);
133: y = cgetg(nbmax + 1, t_COL);
134: y[1] = (long) polx[varn(x)];
135: for (i = 2; i <= n && nbauto < nbmax; i++)
136: {
137: w[n + 1] = polr[i];
138: p1 = lindep2(w, prec);
139: if (signe(p1[n + 1]))
140: {
141: setlg(p1, n + 1);
142: settyp(p1, t_COL);
143: p2 = gdiv(gmul((GEN) nf[7], p1), negi((GEN) p1[n + 1]));
144: if (gdivise(poleval(x, p2), x))
145: {
146: y[++nbauto] = (long) p2;
147: if (DEBUGLEVEL > 1)
148: fprintferr("conjugate %ld: %Z\n", i, y[nbauto]);
149: }
150: }
151: }
152: setlg(y, 1 + nbauto);
153: return gerepileupto(av, gen_sort(y, 0, cmp_pol));
154: }
155: /*************************************************************************/
156: /** **/
157: /** GALOISCONJ4 **/
158: /** **/
159: /** **/
160: /*************************************************************************/
161: /*DEBUGLEVEL:
162: 1: timing
163: 2: outline
164: 4: complete outline
165: 6: detail
166: 7: memory
167: 9: complete detail
168: */
1.3 ! noro 169:
! 170: /* DP = multiple of disc(P) or NULL
! 171: * Return a multiple of the denominator of an algebraic integer (in Q[X]/(P))
! 172: * when expressed in terms of the power basis */
1.1 noro 173: GEN
1.3 ! noro 174: indexpartial(GEN P, GEN DP)
1.1 noro 175: {
1.3 ! noro 176: gpmem_t av = avma;
! 177: long i, nb;
! 178: GEN fa, p1, res = gun, dP;
! 179: pari_timer T;
1.1 noro 180:
1.3 ! noro 181: dP = derivpol(P);
! 182: if(DEBUGLEVEL>=5) (void)TIMER(&T);
! 183: if(!DP) DP = ZX_disc(P);
! 184: DP = mpabs(DP);
! 185: if(DEBUGLEVEL>=5) msgTIMER(&T,"IndexPartial: discriminant");
! 186: fa = auxdecomp(DP, 0);
! 187: if(DEBUGLEVEL>=5) msgTIMER(&T,"IndexPartial: factorization");
! 188: nb = lg(fa[1]);
! 189: for (i = 1; i < nb; i++)
! 190: {
! 191: GEN p=gmael(fa,1,i);
! 192: GEN e=gmael(fa,2,i);
! 193: p1 = powgi(p,shifti(e,-1));
! 194: if ( i==nb-1 )
! 195: {
! 196: if ( mod2(e) && !isprime(p) )
! 197: p1 = mulii(p1,p);
! 198: }
! 199: else if ( cmpis(e,4)>=0 )
! 200: {
! 201: if(DEBUGLEVEL>=5) fprintferr("IndexPartial: factor %Z ",p1);
! 202: p1 = mppgcd(p1, respm(P,dP,p1));
! 203: if(DEBUGLEVEL>=5)
! 204: {
! 205: fprintferr("--> %Z : ",p1);
! 206: msgTIMER(&T,"");
! 207: }
! 208: }
! 209: res=mulii(res,p1);
! 210: }
! 211: return gerepileupto(av,res);
1.1 noro 212: }
213:
1.3 ! noro 214: GEN
! 215: vandermondeinverseprep(GEN L)
1.1 noro 216: {
217: int i, j, n = lg(L);
218: GEN V;
219: V = cgetg(n, t_VEC);
220: for (i = 1; i < n; i++)
221: {
1.3 ! noro 222: gpmem_t ltop=avma;
1.1 noro 223: GEN W=cgetg(n,t_VEC);
224: for (j = 1; j < n; j++)
225: if (i==j)
226: W[j]=un;
227: else
228: W[j]=lsub((GEN)L[i],(GEN)L[j]);
229: V[i]=lpileupto(ltop,divide_conquer_prod(W,&gmul));
230: }
231: return V;
232: }
233:
234: /* Calcule l'inverse de la matrice de van der Monde de T multiplie par den */
235: GEN
236: vandermondeinverse(GEN L, GEN T, GEN den, GEN prep)
237: {
1.3 ! noro 238: gpmem_t ltop = avma;
! 239: int i, n = lg(L)-1;
1.1 noro 240: long x = varn(T);
241: GEN M, P;
242: if (!prep)
1.3 ! noro 243: prep = vandermondeinverseprep(L);
! 244: M = cgetg(n+1, t_MAT);
! 245: for (i = 1; i <= n; i++)
1.1 noro 246: {
247: P = gdiv(gdeuc(T, gsub(polx[x], (GEN) L[i])), (GEN) prep[i]);
1.3 ! noro 248: M[i] = (long)pol_to_vec(P,n);
1.1 noro 249: }
1.3 ! noro 250: return gerepileupto(ltop, gmul(den, M));
1.1 noro 251: }
252:
253: /* Calcule les bornes sur les coefficients a chercher */
254: struct galois_borne
255: {
256: GEN l;
257: long valsol;
258: long valabs;
259: GEN bornesol;
260: GEN ladicsol;
261: GEN ladicabs;
262: GEN lbornesol;
263: };
264:
265:
266: GEN
1.3 ! noro 267: initgaloisborne(GEN T, GEN dn, long prec, GEN *ptL, GEN *ptprep, GEN *ptdis)
1.1 noro 268: {
1.3 ! noro 269: int i, n = degpol(T);
! 270: GEN L, z, prep, den;
! 271: pari_timer ti;
! 272:
! 273: if (DEBUGLEVEL>=4) (void)TIMER(&ti);
1.1 noro 274: L = roots(T, prec);
1.3 ! noro 275: if (DEBUGLEVEL>=4) msgTIMER(&ti,"roots");
1.1 noro 276: for (i = 1; i <= n; i++)
277: {
278: z = (GEN) L[i];
1.3 ! noro 279: if (signe(z[2])) break;
1.1 noro 280: L[i] = z[1];
281: }
1.3 ! noro 282: if (DEBUGLEVEL>=4) (void)TIMER(&ti);
! 283: prep = vandermondeinverseprep(L);
1.1 noro 284: if (!dn)
285: {
1.3 ! noro 286: GEN dis, res = divide_conquer_prod(gabs(prep,prec), mpmul);
1.1 noro 287: disable_dbg(0);
1.3 ! noro 288: dis = ZX_disc_all(T, 1+logint(res,gdeux,NULL));
1.1 noro 289: disable_dbg(-1);
1.3 ! noro 290: den = indexpartial(T,dis);
! 291: if (ptdis) *ptdis = dis;
1.1 noro 292: }
293: else
1.3 ! noro 294: den = dn;
! 295: if (ptprep) *ptprep = prep;
! 296: *ptL = L; return den;
! 297: }
! 298:
! 299: /* ||| M ||| with respect to || x ||_oo. Assume M square t_MAT */
! 300: GEN
! 301: matrixnorm(GEN M, long prec)
! 302: {
! 303: long i,j, n = lg(M);
! 304: GEN B = realzero(prec);
! 305:
! 306: for (i = 1; i < n; i++)
1.1 noro 307: {
1.3 ! noro 308: GEN z = gabs(gcoeff(M,i,1), prec);
! 309: for (j = 2; j < n; j++)
1.1 noro 310: z = gadd(z, gabs(gcoeff(M,i,j), prec));
1.3 ! noro 311: if (gcmp(z, B) > 0) B = z;
1.1 noro 312: }
1.3 ! noro 313: return B;
! 314: }
! 315:
! 316: /* L a t_VEC/t_COL, return ||L||_oo */
! 317: GEN
! 318: supnorm(GEN L, long prec)
! 319: {
! 320: long i, n = lg(L);
! 321: GEN z, B;
! 322:
! 323: if (n == 1) return realzero(prec);
! 324: B = gabs((GEN)L[1], prec);
! 325: for (i = 2; i < n; i++)
1.1 noro 326: {
1.3 ! noro 327: z = gabs((GEN)L[i], prec);
! 328: if (gcmp(z, B) > 0) B = z;
1.1 noro 329: }
1.3 ! noro 330: return B;
! 331: }
! 332:
! 333: GEN
! 334: galoisborne(GEN T, GEN dn, struct galois_borne *gb, long ppp)
! 335: {
! 336: gpmem_t ltop = avma, av2;
! 337: GEN borne, borneroots, borneabs;
! 338: int n;
! 339: GEN L, M, prep, den;
! 340: long prec;
! 341: pari_timer ti;
! 342:
! 343: prec = ZX_get_prec(T);
! 344: den = initgaloisborne(T,dn,prec, &L,&prep,NULL);
! 345: if (!dn) den = gclone(den);
! 346: if (DEBUGLEVEL>=4) TIMERstart(&ti);
! 347: M = vandermondeinverse(L, gmul(T, realun(prec)), den, prep);
! 348: if (DEBUGLEVEL>=4) msgTIMER(&ti,"vandermondeinverse");
! 349: borne = matrixnorm(M, prec);
! 350: borneroots = supnorm(L, prec);
! 351: n = degpol(T);
1.1 noro 352: borneabs = addsr(1, gmulsg(n, gpowgs(borneroots, n/ppp)));
353: /*if (ppp == 1)
354: borneabs = addsr(1, gmulsg(n, gpowgs(borneabs, 2)));*/
355: borneroots = addsr(1, gmul(borne, borneroots));
356: av2 = avma;
357: /*We use d-1 test, so we must overlift to 2^BITS_IN_LONG*/
1.3 ! noro 358: gb->valsol = logint(gmul2n(borneroots,2+BITS_IN_LONG), gb->l,NULL);
! 359: gb->valabs = logint(gmul2n(borneabs,2), gb->l,NULL);
! 360: gb->valabs = max(gb->valsol, gb->valabs);
1.1 noro 361: if (DEBUGLEVEL >= 4)
362: fprintferr("GaloisConj:val1=%ld val2=%ld\n", gb->valsol, gb->valabs);
363: avma = av2;
1.3 ! noro 364: gb->bornesol = gerepileupto(ltop, ceil_safe(mulrs(borneroots,2)));
1.1 noro 365: if (DEBUGLEVEL >= 9)
366: fprintferr("GaloisConj: Bound %Z\n",borneroots);
367: gb->ladicsol = gpowgs(gb->l, gb->valsol);
368: gb->ladicabs = gpowgs(gb->l, gb->valabs);
369: gb->lbornesol = subii(gb->ladicsol,gb->bornesol);
1.3 ! noro 370: if (!dn) { dn = icopy(den); gunclone(den); }
1.1 noro 371: return dn;
372: }
373:
374: struct galois_lift
375: {
376: GEN T;
377: GEN den;
378: GEN p;
379: GEN L;
380: GEN Lden;
381: long e;
382: GEN Q;
383: GEN TQ;
384: struct galois_borne *gb;
385: };
386: /* Initialise la structure galois_lift */
387: GEN makeLden(GEN L,GEN den, struct galois_borne *gb)
388: {
1.3 ! noro 389: gpmem_t ltop=avma;
1.1 noro 390: long i,l=lg(L);
391: GEN Lden;
392: Lden=cgetg(l,t_VEC);
393: for (i=1;i<l;i++)
394: Lden[i]=lmulii((GEN)L[i],den);
395: for (i=1;i<l;i++)
396: Lden[i]=lmodii((GEN)Lden[i],gb->ladicsol);
397: return gerepileupto(ltop,Lden);
398: }
399: void
400: initlift(GEN T, GEN den, GEN p, GEN L, GEN Lden, struct galois_borne *gb, struct galois_lift *gl)
401: {
1.3 ! noro 402: gpmem_t ltop, lbot;
1.1 noro 403: gl->gb=gb;
404: gl->T = T;
405: gl->den = den;
406: gl->p = p;
407: gl->L = L;
408: gl->Lden = Lden;
409: ltop = avma;
1.3 ! noro 410: gl->e = logint(gmul2n(gb->bornesol, 2+BITS_IN_LONG),p,NULL);
1.1 noro 411: gl->e = max(2,gl->e);
412: lbot = avma;
413: gl->Q = gpowgs(p, gl->e);
414: gl->Q = gerepile(ltop, lbot, gl->Q);
415: gl->TQ = FpX_red(T,gl->Q);
416: }
417:
418: /*
419: * Verifie que f est une solution presque surement et calcule sa permutation
420: */
421: static int
422: poltopermtest(GEN f, struct galois_lift *gl, GEN pf)
423: {
1.3 ! noro 424: gpmem_t ltop;
1.1 noro 425: GEN fx, fp;
426: long i, j,ll;
427: for (i = 2; i< lgef(f); i++)
428: if (cmpii((GEN)f[i],gl->gb->bornesol)>0
429: && cmpii((GEN)f[i],gl->gb->lbornesol)<0)
430: {
431: if (DEBUGLEVEL>=4)
432: fprintferr("GaloisConj: Solution too large, discard it.\n");
1.3 ! noro 433: if (DEBUGLEVEL>=8)
! 434: fprintferr("f=%Z\n borne=%Z\n l-borne=%Z\n",f,gl->gb->bornesol,gl->gb->lbornesol);
1.1 noro 435: return 0;
436: }
437: ll=lg(gl->L);
438: fp = cgetg(ll, t_VECSMALL);
439: ltop = avma;
440: for (i = 1; i < ll; i++)
441: fp[i] = 1;
442: for (i = 1; i < ll; i++)
443: {
444: fx = FpX_eval(f, (GEN) gl->L[i],gl->gb->ladicsol);
445: for (j = 1; j < ll; j++)
446: {
447: if (fp[j] && egalii(fx, (GEN) gl->Lden[j]))
448: {
449: pf[i] = j;
450: fp[j] = 0;
451: break;
452: }
453: }
454: if (j == ll)
455: return 0;
456: avma = ltop;
457: }
458: return 1;
459: }
460:
461: /*
462: * Soit P un polynome de \ZZ[X] , p un nombre premier , S\in\FF_p[X]/(Q) tel
463: * que P(S)=0 [p,Q] Relever S en S_0 tel que P(S_0)=0 [p^e,Q]
464: * Unclean stack.
465: */
466: static long monoratlift(GEN S, GEN q, GEN qm1old,struct galois_lift *gl, GEN frob)
467: {
1.3 ! noro 468: gpmem_t ltop=avma;
1.1 noro 469: GEN tlift = polratlift(S,q,qm1old,qm1old,gl->den);
470: if (tlift)
471: {
472: if(DEBUGLEVEL>=4)
473: fprintferr("MonomorphismLift: trying early solution %Z\n",tlift);
474: /*Rationals coefficients*/
475: tlift=lift(gmul(tlift,gmodulcp(gl->den,gl->gb->ladicsol)));
476: if (poltopermtest(tlift, gl, frob))
477: {
478: if(DEBUGLEVEL>=4)
479: fprintferr("MonomorphismLift: true early solution.\n");
480: avma=ltop;
481: return 1;
482: }
483: if(DEBUGLEVEL>=4)
484: fprintferr("MonomorphismLift: false early solution.\n");
485: }
486: avma=ltop;
487: return 0;
488: }
489: GEN
490: monomorphismratlift(GEN P, GEN S, struct galois_lift *gl, GEN frob)
491: {
1.3 ! noro 492: gpmem_t ltop, lbot;
1.1 noro 493: long rt;
494: GEN Q=gl->T, p=gl->p;
495: long e=gl->e, level=1;
496: long x;
497: GEN q, qold, qm1, qm1old;
498: GEN W, Pr, Qr, Sr, Wr = gzero, Prold, Qrold, Spow;
499: long i,nb,mask;
500: GEN *gptr[2];
1.3 ! noro 501: if (DEBUGLEVEL == 1) (void)timer2();
1.1 noro 502: x = varn(P);
503: rt = brent_kung_optpow(degpol(Q),1);
504: q = p; qm1 = gun; /*during the run, we have p*qm1=q*/
505: nb=hensel_lift_accel(e, &mask);
506: Pr = FpX_red(P,q);
507: Qr = (P==Q)?Pr:FpX_red(Q, q);/*A little speed up for automorphismlift*/
508: W=FpX_FpXQ_compo(deriv(Pr, x),S,Qr,q);
509: W=FpXQ_inv(W,Qr,q);
510: qold = p; qm1old=gun;
511: Prold = Pr;
512: Qrold = Qr;
513: gptr[0] = &S;
514: gptr[1] = &Wr;
515: for (i=0; i<nb;i++)
516: {
517: if (DEBUGLEVEL>=2)
518: {
519: level=(level<<1)-((mask>>i)&1);
1.3 ! noro 520: (void)timer2();
1.1 noro 521: }
522: qm1 = (mask&(1<<i))?sqri(qm1):mulii(qm1, q);
523: q = mulii(qm1, p);
524: Pr = FpX_red(P, q);
525: Qr = (P==Q)?Pr:FpX_red(Q, q);/*A little speed up for automorphismlift*/
526: ltop = avma;
527: Sr = S;
528: Spow = FpXQ_powers(Sr, rt, Qr, q);
529:
530: if (i)
531: {
532: W = FpXQ_mul(Wr, FpX_FpXQV_compo(deriv(Pr,-1),FpXV_red(Spow,qold),Qrold,qold), Qrold, qold);
533: W = FpX_neg(W, qold);
534: W = FpX_Fp_add(W, gdeux, qold);
535: W = FpXQ_mul(Wr, W, Qrold, qold);
536: }
537: Wr = W;
538: S = FpXQ_mul(Wr, FpX_FpXQV_compo(Pr, Spow, Qr, q),Qr,q);
539: S = FpX_sub(Sr, S, NULL);
540: lbot = avma;
541: Wr = gcopy(Wr);
542: S = FpX_red(S, q);
543: gerepilemanysp(ltop, lbot, gptr, 2);
544: if (i && i<nb-1 && frob && monoratlift(S,q,qm1old,gl,frob))
545: return NULL;
546: qold = q; qm1old=qm1; Prold = Pr; Qrold = Qr;
547: if (DEBUGLEVEL >= 2)
548: msgtimer("MonomorphismLift: lift to prec %d",level);
549: }
550: if (DEBUGLEVEL == 1)
551: msgtimer("monomorphismlift()");
552: return S;
553: }
554: /*
555: * Soit T un polynome de \ZZ[X] , p un nombre premier , S\in\FF_p[X]/(T) tel
556: * que T(S)=0 [p,T] Relever S en S_0 tel que T(S_0)=0 [T,p^e]
557: * Unclean stack.
558: */
559: GEN
560: automorphismlift(GEN S, struct galois_lift *gl, GEN frob)
561: {
562: return monomorphismratlift(gl->T, S, gl, frob);
563: }
564: GEN
565: monomorphismlift(GEN P, GEN S, GEN Q, GEN p, long e)
566: {
567: struct galois_lift gl;
568: gl.T=Q;
569: gl.p=p;
570: gl.e=e;
571: return monomorphismratlift(P,S,&gl,NULL);
572: }
573:
574: struct galois_testlift
575: {
576: long n;
577: long f;
578: long g;
579: GEN bezoutcoeff;
580: GEN pauto;
581: GEN C;
582: GEN Cd;
583: };
584: static GEN
585: galoisdolift(struct galois_lift *gl, GEN frob)
586: {
1.3 ! noro 587: gpmem_t ltop=avma;
1.1 noro 588: long v = varn(gl->T);
589: GEN Tp = FpX_red(gl->T, gl->p);
590: GEN S = FpXQ_pow(polx[v],gl->p, Tp,gl->p);
591: GEN plift = automorphismlift(S, gl, frob);
592: return gerepileupto(ltop,plift);
593: }
594:
595: static void
596: inittestlift( GEN plift, GEN Tmod, struct galois_lift *gl,
597: struct galois_testlift *gt)
598: {
599: long v = varn(gl->T);
600: gt->n = lg(gl->L) - 1;
601: gt->g = lg(Tmod) - 1;
602: gt->f = gt->n / gt->g;
603: gt->bezoutcoeff = bezout_lift_fact(gl->T, Tmod, gl->p, gl->e);
604: gt->pauto = cgetg(gt->f + 1, t_VEC);
605: gt->pauto[1] = (long) polx[v];
606: gt->pauto[2] = (long) gcopy(plift);
607: if (gt->f > 2)
608: {
1.3 ! noro 609: gpmem_t ltop=avma;
1.1 noro 610: int i;
611: long nautpow=brent_kung_optpow(gt->n-1,gt->f-2);
612: GEN autpow;
1.3 ! noro 613: if (DEBUGLEVEL >= 1) (void)timer2();
1.1 noro 614: autpow = FpXQ_powers(plift,nautpow,gl->TQ,gl->Q);
615: for (i = 3; i <= gt->f; i++)
616: gt->pauto[i] = (long) FpX_FpXQV_compo((GEN)gt->pauto[i-1],autpow,gl->TQ,gl->Q);
617: /*Somewhat paranoid with memory, but this function use a lot of stack.*/
618: gt->pauto=gerepileupto(ltop, gt->pauto);
619: if (DEBUGLEVEL >= 1) msgtimer("frobenius power");
620: }
621: }
622:
623: long intheadlong(GEN x, GEN mod)
624: {
1.3 ! noro 625: gpmem_t ltop=avma;
1.1 noro 626: GEN r;
627: int s;
628: long res;
629: r=divii(shifti(x,BITS_IN_LONG),mod);
630: s=signe(r);
631: res=s?s>0?r[2]:-r[2]:0;
632: avma=ltop;
633: return res;
634: }
635:
636: GEN matheadlong(GEN W, GEN mod)
637: {
638: long i,j;
639: GEN V=cgetg(lg(W),t_VEC);
640: for(i=1;i<lg(W);i++)
641: {
642: V[i]=lgetg(lg(W[i]),t_VECSMALL);
643: for(j=1;j<lg(W[i]);j++)
644: mael(V,i,j)=intheadlong(gmael(W,i,j),mod);
645: }
646: return V;
647: }
648:
649: long polheadlong(GEN P, long n, GEN mod)
650: {
651: return (lgef(P)>n+2)?intheadlong((GEN)P[n+2],mod):0;
652: }
653: /*
654: *
655: */
656: long
657: frobeniusliftall(GEN sg, long el, GEN *psi, struct galois_lift *gl,
658: struct galois_testlift *gt, GEN frob)
659: {
1.3 ! noro 660: gpmem_t av, ltop2, ltop = avma;
1.1 noro 661: long d, z, m, c, n, ord;
662: int i, j, k;
663: GEN pf, u, v;
1.3 ! noro 664: GEN C, Cd, sgi, cache;
! 665: long Z, c_idx=gt->g-1;
! 666: long stop=0,hop=0;
! 667: GEN NN,NQ,NR;
! 668: long N1,N2,R1,Ni;
1.1 noro 669: m = gt->g;
670: ord = gt->f;
671: n = lg(gl->L) - 1;
672: c = lg(sg) - 1;
673: d = m / c;
674: pf = cgetg(m, t_VECSMALL);
675: *psi = pf;
676: ltop2 = avma;
677: NN = gdiv(mpfact(m), gmul(stoi(c), gpowgs(mpfact(d), c)));
678: if (DEBUGLEVEL >= 4)
679: fprintferr("GaloisConj:I will try %Z permutations\n", NN);
680: N1=10000000;
681: NQ=dvmdis(NN,N1,&NR);
682: if (cmpis(NQ,1000000000)>0)
683: {
1.3 ! noro 684: err(warner,"Combinatorics too hard : would need %Z tests!\n"
! 685: "I will skip it,but it may induce galoisinit to loop",NN);
1.1 noro 686: avma = ltop;
687: *psi = NULL;
688: return 0;
689: }
690: N2=itos(NQ); R1=itos(NR); if(!N2) N1=R1;
691: if (DEBUGLEVEL>=4)
692: {
693: stop=N1/20;
1.3 ! noro 694: (void)timer2();
1.1 noro 695: }
696: avma = ltop2;
697: C=gt->C;
698: Cd=gt->Cd;
699: v = FpX_Fp_mul(FpXQ_mul((GEN)gt->pauto[1+el%ord], (GEN)
700: gt->bezoutcoeff[m],gl->TQ,gl->Q),gl->den,gl->Q);
1.3 ! noro 701: sgi=cgetg(lg(sg),t_VECSMALL);
! 702: for(i=1;i<lg(sgi);i++)
! 703: sgi[i]=(el*sg[i])%ord + 1;
! 704: cache=cgetg(m+1,t_VECSMALL);
! 705: cache[m]=polheadlong(v,1,gl->Q);
! 706: Z=polheadlong(v,2,gl->Q);
1.1 noro 707: for (i = 1; i < m; i++)
708: pf[i] = 1 + i / d;
709: av = avma;
710: for (Ni = 0, i = 0; ;i++)
711: {
1.3 ! noro 712: for (j = c_idx ; j > 0; j--)
1.1 noro 713: {
714: long h;
1.3 ! noro 715: h=sgi[pf[j]];
1.1 noro 716: if (!mael(C,h,j))
717: {
1.3 ! noro 718: gpmem_t av3=avma;
1.1 noro 719: GEN r;
720: r=FpX_Fp_mul(FpXQ_mul((GEN) gt->pauto[h],
721: (GEN) gt->bezoutcoeff[j],gl->TQ,gl->Q),gl->den,gl->Q);
722: mael(C,h,j) = lclone(r);
1.3 ! noro 723: mael(Cd,h,j) = polheadlong(r,1,gl->Q);
1.1 noro 724: avma=av3;
725: }
1.3 ! noro 726: cache[j]=cache[j+1]+mael(Cd,h,j);
1.1 noro 727: }
1.3 ! noro 728: if (labs(cache[1])<=n )
1.1 noro 729: {
1.3 ! noro 730: long ZZ=Z;
1.1 noro 731: for (j = 1; j < m; j++)
1.3 ! noro 732: ZZ += polheadlong(gmael(C,sgi[pf[j]],j),2,gl->Q);
! 733: if (labs(ZZ)<=n )
1.1 noro 734: {
735: u = v;
736: for (j = 1; j < m; j++)
1.3 ! noro 737: u = FpX_add(u, gmael(C,sgi[pf[j]],j),NULL);
1.1 noro 738: u = FpX_center(FpX_red(u, gl->Q), gl->Q);
739: if (poltopermtest(u, gl, frob))
740: {
741: if (DEBUGLEVEL >= 4 )
1.3 ! noro 742: {
1.1 noro 743: msgtimer("");
1.3 ! noro 744: fprintferr("GaloisConj: %d hops on %Z tests\n",hop,addis(mulss(Ni,N1),i));
! 745: }
1.1 noro 746: avma = ltop2;
747: return 1;
748: }
1.3 ! noro 749: else if (DEBUGLEVEL >= 4 )
! 750: fprintferr("M");
1.1 noro 751: }
1.3 ! noro 752: else hop++;
1.1 noro 753: }
754: if (DEBUGLEVEL >= 4 && i==stop)
755: {
756: stop+=N1/20;
757: msgtimer("GaloisConj:Testing %Z", addis(mulss(Ni,N1),i));
758: }
759: avma = av;
760: if (i == N1 - 1)
761: {
762: if (Ni==N2-1)
763: N1=R1;
764: if (Ni==N2)
765: break;
766: Ni++;
767: i=0;
768: if (DEBUGLEVEL>=4)
769: {
770: stop=N1/20;
1.3 ! noro 771: (void)timer2();
1.1 noro 772: }
773: }
774: for (j = 2; j < m && pf[j - 1] >= pf[j]; j++);
775: for (k = 1; k < j - k && pf[k] != pf[j - k]; k++)
776: {
777: z = pf[k];
778: pf[k] = pf[j - k];
779: pf[j - k] = z;
780: }
781: for (k = j - 1; pf[k] >= pf[j]; k--);
782: z = pf[j];
783: pf[j] = pf[k];
784: pf[k] = z;
1.3 ! noro 785: c_idx=j;
1.1 noro 786: }
1.3 ! noro 787: if (DEBUGLEVEL>=4)
! 788: fprintferr("GaloisConj: not found, %d hops \n",hop);
1.1 noro 789: avma = ltop;
790: *psi = NULL;
791: return 0;
792: }
793:
794: /*
795: * alloue une ardoise pour n entiers de longueurs pour les test de
796: * permutation
797: */
798: GEN
799: alloue_ardoise(long n, long s)
800: {
801: GEN ar;
802: long i;
803: ar = cgetg(n + 1, t_VEC);
804: for (i = 1; i <= n; i++)
805: ar[i] = lgetg(s, t_INT);
806: return ar;
807: }
808:
809: /*
810: * structure contenant toutes les données pour le tests des permutations:
811: *
812: * ordre :ordre des tests pour verifie_test ordre[lg(ordre)]: numero du test
813: * principal borne : borne sur les coefficients a trouver ladic: modulo
814: * l-adique des racines lborne:ladic-borne TM:vecteur des ligne de M
815: * PV:vecteur des clones des matrices de test (Vmatrix) (ou NULL si non
816: * calcule) L,M comme d'habitude (voir plus bas)
817: */
818: struct galois_test
819: {
820: GEN ordre;
821: GEN borne, lborne, ladic;
822: GEN PV, TM;
823: GEN L, M;
824: };
825: /* Calcule la matrice de tests correspondant a la n-ieme ligne de V */
826: static GEN
827: Vmatrix(long n, struct galois_test *td)
828: {
1.3 ! noro 829: gpmem_t lbot, ltop = avma;
1.1 noro 830: GEN V;
831: long i;
832: V = cgetg(lg(td->L), t_VEC);
833: for (i = 1; i < lg(V); i++)
834: V[i] = mael(td->M,i,n);
835: V = gmul(td->L, V);
836: lbot = avma;
837: V = gmod(V, td->ladic);
838: return gerepile(ltop, lbot, V);
839: }
840:
841: /*
842: * Initialise la structure galois_test
843: */
844: static void
845: inittest(GEN L, GEN M, GEN borne, GEN ladic, struct galois_test *td)
846: {
1.3 ! noro 847: gpmem_t ltop;
1.1 noro 848: long i;
849: int n = lg(L) - 1;
850: if (DEBUGLEVEL >= 8)
851: fprintferr("GaloisConj:Entree Init Test\n");
852: td->ordre = cgetg(n + 1, t_VECSMALL);
853: for (i = 1; i <= n - 2; i++)
854: td->ordre[i] = i + 2;
855: for (; i <= n; i++)
856: td->ordre[i] = i - n + 2;
857: td->borne = borne;ltop = avma;
858: td->lborne = subii(ladic, borne);
859: td->ladic = ladic;
860: td->L = L;
861: td->M = M;
862: td->PV = cgetg(n + 1, t_VECSMALL); /* peut-etre t_VEC est correct ici */
863: for (i = 1; i <= n; i++)
864: td->PV[i] = 0;
865: ltop = avma;
866: td->PV[td->ordre[n]] = (long) gclone(Vmatrix(td->ordre[n], td));
867: avma = ltop;
1.3 ! noro 868: td->TM = gtrans_i(M);
1.1 noro 869: settyp(td->TM, t_VEC);
870: for (i = 1; i < lg(td->TM); i++)
871: settyp(td->TM[i], t_VEC);
872: if (DEBUGLEVEL >= 8)
873: fprintferr("GaloisConj:Sortie Init Test\n");
874: }
875:
876: /*
877: * liberer les clones de la structure galois_test
878: *
879: * Reservé a l'accreditation ultra-violet:Liberez les clones! Paranoia(tm)
880: */
881: static void
882: freetest(struct galois_test *td)
883: {
884: int i;
885: for (i = 1; i < lg(td->PV); i++)
886: if (td->PV[i])
887: {
888: gunclone((GEN) td->PV[i]);
889: td->PV[i] = 0;
890: }
891: }
892:
893: /*
894: * Test si le nombre padique P est proche d'un entier inferieur a td->borne
895: * en valeur absolue.
896: */
897: static long
898: padicisint(GEN P, struct galois_test *td)
899: {
900: long r;
1.3 ! noro 901: gpmem_t ltop = avma;
1.1 noro 902: GEN U;
903: /*if (typ(P) != t_INT) err(typeer, "padicisint");*/
904: U = modii(P, td->ladic);
905: r = gcmp(U, (GEN) td->borne) <= 0 || gcmp(U, (GEN) td->lborne) >= 0;
906: avma = ltop;
907: return r;
908: }
909:
910: /*
911: * Verifie si pf est une vrai solution et non pas un "hop"
912: */
913: static long
914: verifietest(GEN pf, struct galois_test *td)
915: {
1.3 ! noro 916: gpmem_t av = avma;
1.1 noro 917: GEN P, V;
918: int i, j;
919: int n = lg(td->L) - 1;
920: if (DEBUGLEVEL >= 8)
921: fprintferr("GaloisConj:Entree Verifie Test\n");
1.3 ! noro 922: P = perm_mul(td->L, pf);
1.1 noro 923: for (i = 1; i < n; i++)
924: {
925: long ord;
926: GEN PW;
927: ord = td->ordre[i];
928: PW = (GEN) td->PV[ord];
929: if (PW)
930: {
931: V = ((GEN **) PW)[1][pf[1]];
932: for (j = 2; j <= n; j++)
933: V = addii(V, ((GEN **) PW)[j][pf[j]]);
934: }
935: else
936: V = centermod(gmul((GEN) td->TM[ord], P),td->ladic);
937: if (!padicisint(V, td))
938: break;
939: }
940: if (i == n)
941: {
942: if (DEBUGLEVEL >= 8)
943: fprintferr("GaloisConj:Sortie Verifie Test:1\n");
944: avma = av;
945: return 1;
946: }
947: if (!td->PV[td->ordre[i]])
948: {
949: td->PV[td->ordre[i]] = (long) gclone(Vmatrix(td->ordre[i], td));
950: if (DEBUGLEVEL >= 4)
951: fprintferr("M");
952: }
953: if (DEBUGLEVEL >= 4)
954: fprintferr("%d.", i);
955: if (i > 1)
956: {
957: long z;
958: z = td->ordre[i];
959: for (j = i; j > 1; j--)
960: td->ordre[j] = td->ordre[j - 1];
961: td->ordre[1] = z;
962: if (DEBUGLEVEL >= 8)
963: fprintferr("%Z", td->ordre);
964: }
965: if (DEBUGLEVEL >= 8)
966: fprintferr("GaloisConj:Sortie Verifie Test:0\n");
967: avma = av;
968: return 0;
969: }
970: /*Compute a*b/c when a*b will overflow*/
971: static long muldiv(long a,long b,long c)
972: {
973: return (long)((double)a*(double)b/c);
974: }
975:
976: /*
977: * F est la decomposition en cycle de sigma, B est la decomposition en cycle
978: * de cl(tau) Teste toutes les permutations pf pouvant correspondre a tau tel
979: * que : tau*sigma*tau^-1=sigma^s et tau^d=sigma^t ou d est l'ordre de
980: * cl(tau) --------- x: vecteur des choix y: vecteur des mises a jour G:
981: * vecteur d'acces a F linéaire
982: */
983: GEN
984: testpermutation(GEN F, GEN B, long s, long t, long cut,
985: struct galois_test *td)
986: {
1.3 ! noro 987: gpmem_t av, avm = avma;
1.1 noro 988: int a, b, c, d, n;
989: GEN pf, x, ar, y, *G;
990: int p1, p2, p3, p4, p5, p6;
991: long l1, l2, N1, N2, R1;
992: long i, j, cx, hop = 0, start = 0;
993: GEN W, NN, NQ, NR;
994: long V;
1.3 ! noro 995: if (DEBUGLEVEL >= 1) (void)timer2();
1.1 noro 996: a = lg(F) - 1;
997: b = lg(F[1]) - 1;
998: c = lg(B) - 1;
999: d = lg(B[1]) - 1;
1000: n = a * b;
1001: s = (b + s) % b;
1002: pf = cgetg(n + 1, t_VECSMALL);
1003: av = avma;
1004: ar = cgetg(a + 1, t_VECSMALL);
1005: x = cgetg(a + 1, t_VECSMALL);
1006: y = cgetg(a + 1, t_VECSMALL);
1007: G = (GEN *) cgetg(a + 1, t_VECSMALL); /* Don't worry */
1008: W = matheadlong((GEN) td->PV[td->ordre[n]],td->ladic);
1009: for (cx = 1, i = 1, j = 1; cx <= a; cx++, i++)
1010: {
1011: x[cx] = (i != d) ? 0 : t;
1012: y[cx] = 1;
1013: G[cx] = (GEN) F[((long **) B)[j][i]]; /* Be happy */
1014: if (i == d)
1015: {
1016: i = 0;
1017: j++;
1018: }
1019: } /* Be happy now! */
1020: NN = divis(gpowgs(stoi(b), c * (d - 1)),cut);
1021: if (DEBUGLEVEL >= 4)
1022: fprintferr("GaloisConj:I will try %Z permutations\n", NN);
1023: N1=100000;
1024: NQ=dvmdis(NN,N1,&NR);
1025: if (cmpis(NQ,1000000000)>0)
1026: {
1027: avma=avm;
1028: err(warner,"Combinatorics too hard : would need %Z tests!\n I'll skip it but you will get a partial result...",NN);
1.3 ! noro 1029: return perm_identity(n);
1.1 noro 1030: }
1031: N2=itos(NQ); R1=itos(NR);
1032: for (l2 = 0; l2 <= N2; l2++)
1033: {
1034: long nbiter = (l2<N2) ? N1: R1;
1035: if (DEBUGLEVEL >= 2 && N2)
1036: fprintferr("%d%% ", muldiv(l2,100,N2));
1037: for (l1 = 0; l1 < nbiter; l1++)
1038: {
1039: if (start)
1040: {
1041: for (i = 1, j = d; i < a;)
1042: {
1043: y[i] = 1;
1044: if ((++(x[i])) != b)
1045: break;
1046: x[i++] = 0;
1047: if (i == j)
1048: {
1049: y[i++] = 1;
1050: j += d;
1051: }
1052: }
1053: y[i + 1] = 1;
1054: }
1055: else start=1;
1056: for (p1 = 1, p5 = d; p1 <= a; p1++, p5++)
1057: if (y[p1])
1058: {
1059: if (p5 == d)
1060: {
1061: p5 = 0;
1062: p4 = 0;
1063: }
1064: else
1065: p4 = x[p1 - 1];
1066: if (p5 == d - 1)
1067: p6 = p1 + 1 - d;
1068: else
1069: p6 = p1 + 1;
1070: y[p1] = 0;
1071: V = 0;
1072: for (p2 = 1 + p4, p3 = 1 + x[p1]; p2 <= b; p2++)
1073: {
1074: V += mael(W,G[p6][p3],G[p1][p2]);
1075: p3 += s;
1076: if (p3 > b)
1077: p3 -= b;
1078: }
1079: p3 = 1 + x[p1] - s;
1080: if (p3 <= 0)
1081: p3 += b;
1082: for (p2 = p4; p2 >= 1; p2--)
1083: {
1084: V += mael(W,G[p6][p3],G[p1][p2]);
1085: p3 -= s;
1086: if (p3 <= 0)
1087: p3 += b;
1088: }
1089: ar[p1]=V;
1090: }
1091: V = 0;
1092: for (p1 = 1; p1 <= a; p1++)
1093: V += ar[p1];
1094: if (labs(V)<=n)
1095: {
1096: for (p1 = 1, p5 = d; p1 <= a; p1++, p5++)
1097: {
1098: if (p5 == d)
1099: {
1100: p5 = 0;
1101: p4 = 0;
1102: }
1103: else
1104: p4 = x[p1 - 1];
1105: if (p5 == d - 1)
1106: p6 = p1 + 1 - d;
1107: else
1108: p6 = p1 + 1;
1109: for (p2 = 1 + p4, p3 = 1 + x[p1]; p2 <= b; p2++)
1110: {
1111: pf[G[p1][p2]] = G[p6][p3];
1112: p3 += s;
1113: if (p3 > b)
1114: p3 -= b;
1115: }
1116: p3 = 1 + x[p1] - s;
1117: if (p3 <= 0)
1118: p3 += b;
1119: for (p2 = p4; p2 >= 1; p2--)
1120: {
1121: pf[G[p1][p2]] = G[p6][p3];
1122: p3 -= s;
1123: if (p3 <= 0)
1124: p3 += b;
1125: }
1126: }
1127: if (verifietest(pf, td))
1128: {
1129: if (DEBUGLEVEL >= 1)
1130: {
1131: GEN nb=addis(mulss(l2,N1),l1);
1132: msgtimer("testpermutation(%Z)", nb);
1133: if (DEBUGLEVEL >= 2 && hop)
1134: fprintferr("GaloisConj:%d hop sur %Z iterations\n", hop, nb);
1135: }
1136: avma = av;
1137: return pf;
1138: }
1139: else
1140: hop++;
1141: }
1142: }
1143: }
1144: if (DEBUGLEVEL >= 1)
1145: {
1146: msgtimer("testpermutation(%Z)", NN);
1147: if (DEBUGLEVEL >= 2 && hop)
1148: fprintferr("GaloisConj:%d hop sur %Z iterations\n", hop, NN);
1149: }
1150: avma = avm;
1151: return gzero;
1152: }
1153: int pari_compare_lg(GEN x, GEN y)
1154: {
1155: return lg(x)-lg(y);
1156: }
1157:
1158: /*
1.3 ! noro 1159: * Calcule la liste des sous groupes de (\ZZ/m\ZZ)^* d'ordre divisant p et
1.1 noro 1160: * retourne la liste de leurs elements
1161: */
1162: GEN
1163: listsousgroupes(long m, long p)
1164: {
1.3 ! noro 1165: gpmem_t ltop = avma;
! 1166: GEN zn, zns, lss, sg, res;
1.1 noro 1167: int k, card, i, phi;
1168: if (m == 2)
1169: {
1170: res = cgetg(2, t_VEC);
1171: sg = cgetg(2, t_VECSMALL);
1172: res[1] = (long) sg;
1173: sg[1] = 1;
1174: return res;
1175: }
1.3 ! noro 1176: zn = znstar(stoi(m));
! 1177: phi = itos((GEN) zn[1]);
! 1178: zns = znstar_small(zn);
! 1179: lss = subgrouplist((GEN) zn[2], NULL);
1.1 noro 1180: res = cgetg(lg(lss), t_VEC);
1181: for (k = 1, i = lg(lss) - 1; i >= 1; i--)
1182: {
1.3 ! noro 1183: gpmem_t av;
1.1 noro 1184: av = avma;
1185: card = phi / itos(det((GEN) lss[i]));
1186: avma = av;
1187: if (p % card == 0)
1.3 ! noro 1188: res[k++] = (long) znstar_hnf_elts(zns,(GEN)lss[i]);
1.1 noro 1189: }
1190: setlg(res,k);
1191: res=gen_sort(res,0,&pari_compare_lg);
1192: return gerepileupto(ltop,res);
1193: }
1194:
1195: GEN
1196: fixedfieldpolsigma(GEN sigma, GEN p, GEN Tp, GEN sym, GEN deg, long g)
1197: {
1.3 ! noro 1198: gpmem_t ltop=avma;
1.1 noro 1199: long i, j, npows;
1200: GEN s, f, pows;
1201: sigma=lift(gmul(sigma,gmodulsg(1,p)));
1202: f=polx[varn(sigma)];
1203: s=zeropol(varn(sigma));
1204: for(j=1;j<lg(sym);j++)
1205: if(sym[j])
1206: {
1207: s=FpX_add(s,FpX_Fp_mul(FpXQ_pow(f,stoi(deg[j]),Tp,p),stoi(sym[j]),p),p);
1208: }
1209: npows = brent_kung_optpow(lgef(Tp)-4,g-1);
1210: pows = FpXQ_powers(sigma,npows,Tp,p);
1211: for(i=2; i<=g;i++)
1212: {
1213: f=FpX_FpXQV_compo(f,pows,Tp,p);
1214: for(j=1;j<lg(sym);j++)
1215: if(sym[j])
1216: {
1217: s=FpX_add(s,FpX_Fp_mul(FpXQ_pow(f,stoi(deg[j]),Tp,p),stoi(sym[j]),p),p);
1218: }
1219: }
1220: return gerepileupto(ltop, s);
1221: }
1222:
1223: GEN
1224: fixedfieldfactmod(GEN Sp, GEN p, GEN Tmod)
1225: {
1226: long i;
1227: long l=lg(Tmod);
1228: GEN F=cgetg(l,t_VEC);
1229: for(i=1;i<l;i++)
1.3 ! noro 1230: F[i]=(long)FpXQ_minpoly(FpX_res(Sp,(GEN) Tmod[i],p), (GEN) Tmod[i],p);
1.1 noro 1231: return F;
1232: }
1233:
1234: GEN
1235: fixedfieldnewtonsumaut(GEN sigma, GEN p, GEN Tp, GEN e, long g)
1236: {
1.3 ! noro 1237: gpmem_t ltop=avma;
1.1 noro 1238: long i;
1239: GEN s,f,V;
1240: long rt;
1241: sigma=lift(gmul(sigma,gmodulsg(1,p)));
1242: f=polx[varn(sigma)];
1243: rt=brent_kung_optpow(lgef(Tp)-4,g-1);
1244: V=FpXQ_powers(sigma,rt,Tp,p);
1245: s=FpXQ_pow(f,e,Tp,p);
1246: for(i=2; i<=g;i++)
1247: {
1248: f=FpX_FpXQV_compo(f,V,Tp,p);
1249: s=FpX_add(s,FpXQ_pow(f,e,Tp,p),p);
1250: }
1251: return gerepileupto(ltop, s);
1252: }
1253:
1254: GEN
1255: fixedfieldnewtonsum(GEN O, GEN L, GEN mod, GEN e)
1256: {
1257: long f,g;
1258: long i,j;
1259: GEN PL;
1260: f=lg(O)-1;
1261: g=lg(O[1])-1;
1262: PL=cgetg(lg(O), t_COL);
1263: for(i=1; i<=f; i++)
1264: {
1.3 ! noro 1265: gpmem_t ltop=avma;
1.1 noro 1266: GEN s=gzero;
1267: for(j=1; j<=g; j++)
1268: s=addii(s,powmodulo((GEN)L[mael(O,i,j)],e,mod));
1269: PL[i]=lpileupto(ltop,modii(s,mod));
1270: }
1271: return PL;
1272: }
1273:
1274: GEN
1275: fixedfieldpol(GEN O, GEN L, GEN mod, GEN sym, GEN deg)
1276: {
1.3 ! noro 1277: gpmem_t ltop=avma;
1.1 noro 1278: long i;
1279: GEN S=gzero;
1280: for(i=1;i<lg(sym);i++)
1281: if (sym[i])
1282: S=gadd(S,gmulsg(sym[i],fixedfieldnewtonsum(O, L, mod, stoi(deg[i]))));
1283: S=FpV_red(S,mod);
1284: return gerepileupto(ltop, S);
1285: }
1286:
1287: static long
1288: fixedfieldtests(GEN LN, long n)
1289: {
1290: long i,j,k;
1291: for (i=1;i<lg(LN[1]);i++)
1292: for(j=i+1;j<lg(LN[1]);j++)
1293: {
1294: for(k=1;k<=n;k++)
1295: if (cmpii(gmael(LN,k,j),gmael(LN,k,i)))
1296: break;
1297: if (k>n)
1298: return 0;
1299: }
1300: return 1;
1301: }
1302:
1303: static long
1304: fixedfieldtest(GEN V)
1305: {
1306: long i,j;
1307: for (i=1;i<lg(V);i++)
1308: for(j=i+1;j<lg(V);j++)
1309: if (!cmpii((GEN)V[i],(GEN)V[j]))
1310: return 0;
1311: return 1;
1312: }
1313:
1314: void
1315: debug_surmer(char *s,GEN S, long n)
1316: {
1317: long l=lg(S);
1318: setlg(S,n+1);
1319: fprintferr(s,S);
1320: setlg(S,l);
1321: }
1322:
1323: /*We try hard to find a polynomial R squarefree mod p.
1324: Unfortunately, it may be too much asked.
1325: A less bugprone way would be to only ask it to be squarefree mod p^e
1326: with e not too big. Most of the code is here, but I lack the theoretical
1327: knowledge to make it to work smoothly.B.A.
1328: */
1329: static GEN
1330: fixedfieldsurmer(GEN O, GEN L, GEN mod, GEN l, GEN p, GEN S, GEN deg, long v, GEN LN,long n)
1331: {
1332: long i;
1333: GEN V;
1334: V=(GEN)LN[n];
1335: for (i=1;i<lg(S);i++)
1336: S[i]=0;
1337: S[n]=1;
1338: for (i=0;i<2*n-1;i++)
1339: {
1340: long k;
1341: if (fixedfieldtest(V))
1342: {
1.3 ! noro 1343: gpmem_t av=avma;
1.1 noro 1344: GEN s=fixedfieldpol(O,L,mod,S,deg);
1345: GEN P=FpV_roots_to_pol(s,mod,v);
1346: P=FpX_center(P,mod);
1347: if (p==gun || FpX_is_squarefree(P,p))
1348: {
1349: GEN V;
1350: if (DEBUGLEVEL>=4)
1351: debug_surmer("FixedField: Sym: %Z\n",S,n);
1352: V=cgetg(3,t_VEC);
1353: V[1]=lcopy(s);/*do not swap*/
1354: V[2]=lcopy(P);
1355: return V;
1356: }
1357: else
1358: {
1359: if (DEBUGLEVEL>=6)
1360: debug_surmer("FixedField: bad mod: %Z\n",S,n);
1361: avma=av;
1362: }
1363: }
1364: else
1365: {
1366: if (DEBUGLEVEL>=6)
1367: debug_surmer("FixedField: Tested: %Z\n",S,n);
1368: }
1369: k=1+(i%n);
1370: S[k]++;
1371: V=FpV_red(gadd(V,(GEN)LN[k]),l);
1372: }
1373: return NULL;
1374: }
1375:
1376: GEN
1377: fixedfieldsympol(GEN O, GEN L, GEN mod, GEN l, GEN p, GEN S, GEN deg, long v)
1378: {
1.3 ! noro 1379: gpmem_t ltop=avma;
1.1 noro 1380: GEN V=NULL;
1381: GEN LN=cgetg(lg(L),t_VEC);
1382: GEN Ll=FpV_red(L,l);
1383: long n,i;
1384: for(i=1;i<lg(deg);i++)
1385: deg[i]=0;
1386: for(n=1,i=1;i<lg(L);i++)
1387: {
1388: long j;
1389: LN[n]=(long)fixedfieldnewtonsum(O,Ll,l,stoi(i));
1390: for(j=2;j<lg(LN[n]);j++)
1391: if(cmpii(gmael(LN,n,j),gmael(LN,n,1)))
1392: break;
1393: if(j==lg(LN[n]) && j>2)
1394: continue;
1395: if (DEBUGLEVEL>=6) fprintferr("FixedField: LN[%d]=%Z\n",n,LN[n]);
1396: deg[n]=i;
1397: if (fixedfieldtests(LN,n))
1398: {
1399: V=fixedfieldsurmer(O,L,mod,l,p,S,deg,v,LN,n);
1400: if (V)
1401: break;
1402: }
1403: n++;
1404: }
1405: if (DEBUGLEVEL>=4)
1406: {
1407: long l=lg(deg);
1408: setlg(deg,n);
1409: fprintferr("FixedField: Computed degrees: %Z\n",deg);
1410: setlg(deg,l);
1411: }
1412: if (!V)
1413: err(talker, "prime too small in fixedfield");
1414: return gerepileupto(ltop,V);
1415: }
1416: /*
1417: * Calcule l'inclusion de R dans T i.e. S telque T|R\compo S
1418: * Ne recopie pas PL.
1419: */
1420: GEN
1421: fixedfieldinclusion(GEN O, GEN PL)
1422: {
1423: GEN S;
1424: int i, j;
1425: S = cgetg((lg(O) - 1) * (lg(O[1]) - 1) + 1, t_COL);
1426: for (i = 1; i < lg(O); i++)
1427: for (j = 1; j < lg(O[i]); j++)
1428: S[((GEN *) O)[i][j]] = PL[i];
1429: return S;
1430: }
1431:
1432: /*Usually mod is bigger than than den so there is no need to reduce it.*/
1433: GEN
1434: vandermondeinversemod(GEN L, GEN T, GEN den, GEN mod)
1435: {
1.3 ! noro 1436: gpmem_t av;
1.1 noro 1437: int i, j, n = lg(L);
1438: long x = varn(T);
1439: GEN M, P, Tp;
1440: M = cgetg(n, t_MAT);
1441: av=avma;
1442: Tp = gclone(FpX_red(deriv(T, x),mod)); /*clone*/
1443: avma=av;
1444: for (i = 1; i < n; i++)
1445: {
1446: GEN z;
1447: av = avma;
1448: z = mpinvmod(FpX_eval(Tp, (GEN) L[i],mod),mod);
1449: z = modii(mulii(den,z),mod);
1450: P = FpX_Fp_mul(FpX_div(T, deg1pol(gun,negi((GEN) L[i]),x),mod), z, mod);
1451: M[i] = lgetg(n, t_COL);
1452: for (j = 1; j < n; j++)
1453: mael(M,i,j) = lcopy((GEN) P[1 + j]);
1454: M[i] = lpileupto(av,(GEN)M[i]);
1455: }
1456: gunclone(Tp); /*unclone*/
1457: return M;
1458: }
1459: /* Calcule le polynome associe a un vecteur conjugue v*/
1460: static GEN
1461: vectopol(GEN v, GEN M, GEN den , GEN mod, long x)
1462: {
1.3 ! noro 1463: long n = lg(v), i, k;
! 1464: gpmem_t av;
1.1 noro 1465: GEN z = cgetg(n+1,t_POL),p1,p2,mod2;
1466: av=avma;
1467: mod2=gclone(shifti(mod,-1));/*clone*/
1468: avma=av;
1469: z[1]=evalsigne(1)|evalvarn(x)|evallgef(n+1);
1470: for (i=2; i<=n; i++)
1471: {
1472: p1=gzero; av=avma;
1473: for (k=1; k<n; k++)
1474: {
1475: p2=mulii(gcoeff(M,i-1,k),(GEN)v[k]);
1476: p1=addii(p1,p2);
1477: }
1478: p1=modii(p1,mod);
1479: if (cmpii(p1,mod2)>0) p1=subii(p1,mod);
1480: p1=gdiv(p1,den);
1481: z[i]=lpileupto(av,p1);
1482: }
1483: gunclone(mod2);/*unclone*/
1484: return normalizepol_i(z,n+1);
1485: }
1486: /* Calcule le polynome associe a une permutation des racines*/
1487: static GEN
1488: permtopol(GEN p, GEN L, GEN M, GEN den, GEN mod, long x)
1489: {
1.3 ! noro 1490: long n = lg(L), i, k;
! 1491: gpmem_t av;
1.1 noro 1492: GEN z = cgetg(n+1,t_POL),p1,p2,mod2;
1493: if (lg(p) != n) err(talker,"incorrect permutation in permtopol");
1494: av=avma;
1495: mod2=gclone(shifti(mod,-1)); /*clone*/
1496: avma=av;
1497: z[1]=evalsigne(1)|evalvarn(x)|evallgef(n+1);
1498: for (i=2; i<=n; i++)
1499: {
1500: p1=gzero; av=avma;
1501: for (k=1; k<n; k++)
1502: {
1503: p2=mulii(gcoeff(M,i-1,k),(GEN)L[p[k]]);
1504: p1=addii(p1,p2);
1505: }
1506: p1=modii(p1,mod);
1507: if (cmpii(p1,mod2)>0) p1=subii(p1,mod);
1508: p1=gdiv(p1,den);
1509: z[i]=lpileupto(av,p1);
1510: }
1511: gunclone(mod2); /*unclone*/
1512: return normalizepol_i(z,n+1);
1513: }
1514:
1515: GEN
1516: galoisgrouptopol( GEN res, GEN L, GEN M, GEN den, GEN mod, long v)
1517: {
1518: GEN aut = cgetg(lg(res), t_COL);
1519: long i;
1520: for (i = 1; i < lg(res); i++)
1521: {
1522: if (DEBUGLEVEL>=6)
1523: fprintferr("%d ",i);
1524: aut[i] = (long) permtopol((GEN) res[i], L, M, den, mod, v);
1525: }
1526: return aut;
1527: }
1528:
1529: /*
1530: * Casse l'orbite O en sous-orbite d'ordre premier correspondant a des
1531: * puissance de l'element
1532: */
1533: GEN
1534: splitorbite(GEN O)
1535: {
1.3 ! noro 1536: gpmem_t lbot, ltop = avma;
1.1 noro 1537: int i, n;
1.3 ! noro 1538: GEN fc, res;
1.1 noro 1539: n = lg(O[1]) - 1;
1.3 ! noro 1540: fc = decomp_primary_small(n);
1.1 noro 1541: lbot = avma;
1542: res = cgetg(3, t_VEC);
1543: res[1] = lgetg(lg(fc), t_VEC);
1544: res[2] = lgetg(lg(fc), t_VECSMALL);
1545: for (i = 1; i < lg(fc); i++)
1546: {
1.3 ! noro 1547: mael(res,1,lg(fc) - i) = (long)cyc_powtoperm(O, n / fc[i]);
! 1548: mael(res,2,lg(fc) - i) = fc[i];
1.1 noro 1549: }
1550: if ( DEBUGLEVEL>=4 )
1551: fprintferr("GaloisConj:splitorbite: %Z\n",res);
1552: return gerepile(ltop, lbot, res);
1553: }
1554:
1555: /*
1556: * structure qui contient l'analyse du groupe de Galois par etude des degres
1557: * de Frobenius:
1558: *
1559: * p: nombre premier a relever deg: degre du lift ŕ effectuer pgp: plus grand
1560: * diviseur premier du degre de T.
1561: * l: un nombre premier tel que T est totalement decompose
1562: * modulo l ppp: plus petit diviseur premier du degre de T. primepointer:
1563: * permet de calculer les premiers suivant p.
1564: */
1.3 ! noro 1565: enum ga_code {ga_all_normal=1,ga_ext_2=2,ga_non_wss=4};
1.1 noro 1566: struct galois_analysis
1567: {
1568: long p;
1569: long deg;
1570: long ord;
1571: long l;
1572: long ppp;
1573: long p4;
1.3 ! noro 1574: enum ga_code group;
1.1 noro 1575: byteptr primepointer;
1576: };
1577: void
1578: galoisanalysis(GEN T, struct galois_analysis *ga, long calcul_l, long karma_type)
1579: {
1.3 ! noro 1580: gpmem_t ltop=avma;
1.1 noro 1581: long n,p;
1582: long i;
1.3 ! noro 1583: enum k_code {k_amoeba=0,k_snake=1,k_fish=2,k_bird=4,k_rodent=6,k_dog=8,k_human=9,k_cat=12} karma;
1.1 noro 1584: long group,linf;
1585: /*TODO: complete the table to at least 200*/
1586: const int prim_nonss_orders[]={36,48,56,60,72,75,80,96,108,120,132,0};
1587: GEN F,Fp,Fe,Fpe,O;
1.3 ! noro 1588: long min_prime,np;
1.1 noro 1589: long order,phi_order;
1590: long plift,nbmax,nbtest,deg;
1591: byteptr primepointer,pp;
1.3 ! noro 1592:
! 1593: if (!ZX_is_squarefree(T))
! 1594: err(talker, "Polynomial not squarefree in galoisinit");
! 1595: if (DEBUGLEVEL >= 1) (void)timer2();
1.1 noro 1596: n = degpol(T);
1597: if (!karma_type) karma_type=n;
1598: else err(warner,"entering black magic computation");
1599: O = cgetg(n+1,t_VECSMALL);
1600: for(i=1;i<=n;i++) O[i]=0;
1601: F = factor(stoi(n));
1602: Fp=gtovecsmall((GEN)F[1]);
1603: Fe=gtovecsmall((GEN)F[2]);
1604: np=lg(Fp)-1;
1605: Fpe=cgetg(np+1, t_VECSMALL);
1606: for (i = 1; i < lg(Fpe); i++)
1607: Fpe[i] = itos(powgi(gmael(F,1,i), gmael(F,2,i)));
1608: /*In this part, we study the cardinal of the group to have an information
1609: about the orders, so if we are unlucky we can continue.*/
1610:
1611: /*Are there non WSS groups of this order ?*/
1612: group=0;
1613: for(i=0;prim_nonss_orders[i];i++)
1614: if (n%prim_nonss_orders[i] == 0)
1615: {
1616: group |= ga_non_wss;
1617: break;
1618: }
1619: if ( n>12 && n%12 == 0 )
1620: {
1621: /*We need to know the greatest prime dividing n/12*/
1622: if ( Fp[np] == 3 && Fe[np] == 1 )
1623: group |= ga_ext_2;
1624: }
1625: phi_order = 1;
1626: order = 1;
1627: for (i = np; i > 0; i--)
1628: {
1629: p = Fp[i];
1630: if (phi_order % p != 0)
1631: {
1632: order *= p;
1633: phi_order *= p - 1;
1634: }
1635: else
1636: {
1637: group |= ga_all_normal;
1638: break;
1639: }
1640: if (Fe[i]>1)
1641: break;
1642: }
1643: /*Now, we study the orders of the Frobenius elements*/
1.3 ! noro 1644: min_prime=n*max((long)(BITS_IN_LONG-bfffo(n)-4),2);
1.1 noro 1645: plift = 0;
1646: nbmax = 8+(n>>1);
1647: nbtest = 0; karma = k_amoeba;
1648: deg = Fp[np];
1649: for (p = 0, pp = primepointer = diffptr;
1650: (plift == 0
1651: || (nbtest < nbmax && (nbtest <=8 || order < (n>>1)))
1652: || (n == 24 && O[6] == 0 && O[4] == 0)
1653: || ((group&ga_non_wss) && order == Fp[np]))
1654: && (nbtest < 3 * nbmax || !(group&ga_non_wss)) ;)
1655: {
1.3 ! noro 1656: gpmem_t av;
1.1 noro 1657: GEN ip,FS,p1;
1658: long o,norm_o=1;
1.3 ! noro 1659:
! 1660: NEXT_PRIME_VIADIFF_CHECK(p,primepointer);
1.1 noro 1661: /*discard small primes*/
1.3 ! noro 1662: if (p <= min_prime)
1.1 noro 1663: continue;
1664: ip=stoi(p);
1665: if (!FpX_is_squarefree(T,ip))
1666: continue;
1667: nbtest++;
1668: av=avma;
1669: FS=(GEN)simplefactmod(T,ip)[1];
1670: p1=(GEN)FS[1];
1671: for(i=2;i<lg(FS);i++)
1672: if (cmpii(p1,(GEN)FS[i]))
1673: break;
1674: if (i<lg(FS))
1675: {
1676: avma = ltop;
1677: if (DEBUGLEVEL >= 2)
1678: fprintferr("GaloisAnalysis:non Galois for p=%ld\n", p);
1679: ga->p = p;
1680: ga->deg = 0;
1681: return; /* Not a Galois polynomial */
1682: }
1683: o=n/(lg(FS)-1);
1684: avma=av;
1685: if (!O[o])
1686: O[o]=p;
1687: if (o % deg == 0)
1688: {
1689: /*We try to find a power of the Frobenius which generate
1690: a normal subgroup just by looking at the order.*/
1691: if (o * Fp[1] >= n)
1692: /*Subgroup of smallest index are normal*/
1693: norm_o = o;
1694: else
1695: {
1696: norm_o = 1;
1697: for (i = np; i > 0; i--)
1698: {
1699: if (o % Fpe[i] == 0)
1700: norm_o *= Fpe[i];
1701: else
1702: break;
1703: }
1704: }
1705: if (norm_o != 1)
1706: {
1707: if (!(group&ga_all_normal) || o > order ||
1708: (o == order && (plift == 0 || norm_o > deg
1709: || (norm_o == deg && cgcd(p-1,karma_type)>karma ))))
1710: {
1711: deg = norm_o;
1712: order = o;
1713: plift = p;
1.3 ! noro 1714: karma=(enum k_code)cgcd(p-1,karma_type);
1.1 noro 1715: pp = primepointer;
1716: group |= ga_all_normal;
1717: }
1718: }
1719: else if (!(group&ga_all_normal) && (plift == 0 || o > order
1720: || ( o == order && cgcd(p-1,karma_type)>karma )))
1721: {
1722: order = o;
1723: plift = p;
1.3 ! noro 1724: karma=(enum k_code)cgcd(p-1,karma_type);
1.1 noro 1725: pp = primepointer;
1726: }
1727: }
1728: if (DEBUGLEVEL >= 5)
1729: fprintferr("GaloisAnalysis:Nbtest=%ld,p=%ld,o=%ld,n_o=%d,best p=%ld,ord=%ld,k=%ld\n",
1730: nbtest, p, o, norm_o, plift, order,karma);
1731: }
1732: /* This is to avoid looping on non-wss group.
1733: To be checked for large groups. */
1734: /*Would it be better to disable this check if we are in a good case ?
1735: * (ga_all_normal and !(ga_ext_2) (e.g. 60)) ?*/
1736: if (plift == 0 || ((group&ga_non_wss) && order == Fp[np]))
1737: {
1738: deg = 0;
1739: err(warner, "Galois group almost certainly not weakly super solvable");
1740: }
1741: /*linf=(n*(n-1))>>2;*/
1742: linf=n;
1743: if (calcul_l && O[1]<=linf)
1744: {
1.3 ! noro 1745: gpmem_t av;
1.1 noro 1746: long l=0;
1747: /*we need a totally splited prime l*/
1748: av = avma;
1749: while (l == 0)
1750: {
1751: long nb;
1.3 ! noro 1752:
! 1753: NEXT_PRIME_VIADIFF_CHECK(p,primepointer);
1.1 noro 1754: if (p<=linf) continue;
1755: nb=FpX_nbroots(T,stoi(p));
1756: if (nb == n)
1757: l = p;
1758: else if (nb && FpX_is_squarefree(T,stoi(p)))
1759: {
1760: avma = ltop;
1761: if (DEBUGLEVEL >= 2)
1762: fprintferr("GaloisAnalysis:non Galois for p=%ld\n", p);
1763: ga->p = p;
1764: ga->deg = 0;
1765: return; /* Not a Galois polynomial */
1766: }
1767: avma = av;
1768: }
1769: O[1]=l;
1770: }
1771: ga->p = plift;
1.3 ! noro 1772: ga->group = (enum ga_code)group;
1.1 noro 1773: ga->deg = deg;
1774: ga->ord = order;
1775: ga->l = O[1];
1776: ga->primepointer = pp;
1777: ga->ppp = Fp[1];
1778: ga->p4 = O[4];
1779: if (DEBUGLEVEL >= 4)
1780: fprintferr("GaloisAnalysis:p=%ld l=%ld group=%ld deg=%ld ord=%ld\n",
1781: plift, O[1], group, deg, order);
1782: if (DEBUGLEVEL >= 1)
1783: msgtimer("galoisanalysis()");
1784: avma = ltop;
1785: }
1786:
1787: /* Groupe A4 */
1788: GEN
1789: a4galoisgen(GEN T, struct galois_test *td)
1790: {
1.3 ! noro 1791: gpmem_t ltop = avma, av, av2;
1.1 noro 1792: long i, j, k;
1793: long n;
1794: long N, hop = 0;
1795: long **O;
1796: GEN *ar, **mt; /* tired of casting */
1797: GEN t, u;
1798: GEN res, orb, ry;
1799: GEN pft, pfu, pfv;
1800: n = degpol(T);
1801: res = cgetg(3, t_VEC);
1802: ry = cgetg(4, t_VEC);
1803: res[1] = (long) ry;
1804: pft = cgetg(n + 1, t_VECSMALL);
1805: pfu = cgetg(n + 1, t_VECSMALL);
1806: pfv = cgetg(n + 1, t_VECSMALL);
1807: ry[1] = (long) pft;
1808: ry[2] = (long) pfu;
1809: ry[3] = (long) pfv;
1810: ry = cgetg(4, t_VECSMALL);
1811: ry[1] = 2;
1812: ry[2] = 2;
1813: ry[3] = 3;
1814: res[2] = (long) ry;
1815: av = avma;
1816: ar = (GEN *) alloue_ardoise(n, 1 + lg(td->ladic));
1817: mt = (GEN **) td->PV[td->ordre[n]];
1818: t = cgetg(n + 1, t_VECSMALL) + 1; /* Sorry for this hack */
1819: u = cgetg(n + 1, t_VECSMALL) + 1; /* too lazy to correct */
1820: av2 = avma;
1821: N = itos(gdiv(mpfact(n), mpfact(n >> 1))) >> (n >> 1);
1822: if (DEBUGLEVEL >= 4)
1823: fprintferr("A4GaloisConj:I will test %ld permutations\n", N);
1824: avma = av2;
1825: for (i = 0; i < n; i++)
1826: t[i] = i + 1;
1827: for (i = 0; i < N; i++)
1828: {
1829: GEN g;
1830: int a, x, y;
1831: if (i == 0)
1832: {
1833: gaffect(gzero, ar[(n - 2) >> 1]);
1834: for (k = n - 2; k > 2; k -= 2)
1835: addiiz(ar[k >> 1], addii(mt[k + 1][k + 2], mt[k + 2][k + 1]),
1836: ar[(k >> 1) - 1]);
1837: }
1838: else
1839: {
1840: x = i;
1841: y = 1;
1842: do
1843: {
1844: y += 2;
1845: a = x%y;
1846: x = x/y;
1847: }
1848: while (!a);
1849: switch (y)
1850: {
1851: case 3:
1852: x = t[2];
1853: if (a == 1)
1854: {
1855: t[2] = t[1];
1856: t[1] = x;
1857: }
1858: else
1859: {
1860: t[2] = t[0];
1861: t[0] = x;
1862: }
1863: break;
1864: case 5:
1865: x = t[0];
1866: t[0] = t[2];
1867: t[2] = t[1];
1868: t[1] = x;
1869: x = t[4];
1870: t[4] = t[4 - a];
1871: t[4 - a] = x;
1872: addiiz(ar[2], addii(mt[t[4]][t[5]], mt[t[5]][t[4]]), ar[1]);
1873: break;
1874: case 7:
1875: x = t[0];
1876: t[0] = t[4];
1877: t[4] = t[3];
1878: t[3] = t[1];
1879: t[1] = t[2];
1880: t[2] = x;
1881: x = t[6];
1882: t[6] = t[6 - a];
1883: t[6 - a] = x;
1884: addiiz(ar[3], addii(mt[t[6]][t[7]], mt[t[7]][t[6]]), ar[2]);
1885: addiiz(ar[2], addii(mt[t[4]][t[5]], mt[t[5]][t[4]]), ar[1]);
1886: break;
1887: case 9:
1888: x = t[0];
1889: t[0] = t[6];
1890: t[6] = t[5];
1891: t[5] = t[3];
1892: t[3] = x;
1893: x = t[4];
1894: t[4] = t[1];
1895: t[1] = x;
1896: x = t[8];
1897: t[8] = t[8 - a];
1898: t[8 - a] = x;
1899: addiiz(ar[4], addii(mt[t[8]][t[9]], mt[t[9]][t[8]]), ar[3]);
1900: addiiz(ar[3], addii(mt[t[6]][t[7]], mt[t[7]][t[6]]), ar[2]);
1901: addiiz(ar[2], addii(mt[t[4]][t[5]], mt[t[5]][t[4]]), ar[1]);
1902: break;
1903: default:
1904: y--;
1905: x = t[0];
1906: t[0] = t[2];
1907: t[2] = t[1];
1908: t[1] = x;
1909: for (k = 4; k < y; k += 2)
1910: {
1911: int j;
1912: x = t[k];
1913: for (j = k; j > 0; j--)
1914: t[j] = t[j - 1];
1915: t[0] = x;
1916: }
1917: x = t[y];
1918: t[y] = t[y - a];
1919: t[y - a] = x;
1920: for (k = y; k > 2; k -= 2)
1921: addiiz(ar[k >> 1],
1922: addii(mt[t[k]][t[k + 1]], mt[t[k + 1]][t[k]]),
1923: ar[(k >> 1) - 1]);
1924: }
1925: }
1926: g = addii(ar[1], addii(addii(mt[t[0]][t[1]], mt[t[1]][t[0]]),
1927: addii(mt[t[2]][t[3]], mt[t[3]][t[2]])));
1928: if (padicisint(g, td))
1929: {
1930: for (k = 0; k < n; k += 2)
1931: {
1932: pft[t[k]] = t[k + 1];
1933: pft[t[k + 1]] = t[k];
1934: }
1935: if (verifietest(pft, td))
1936: break;
1937: else
1938: hop++;
1939: }
1940: avma = av2;
1941: }
1942: if (i == N)
1943: {
1944: avma = ltop;
1945: if (DEBUGLEVEL >= 1 && hop)
1946: fprintferr("A4GaloisConj: %ld hop sur %ld iterations\n", hop, N);
1947: return gzero;
1948: }
1949: if (DEBUGLEVEL >= 1 && hop)
1950: fprintferr("A4GaloisConj: %ld hop sur %ld iterations\n", hop, N);
1951: N = itos(gdiv(mpfact(n >> 1), mpfact(n >> 2))) >> 1;
1952: avma = av2;
1953: if (DEBUGLEVEL >= 4)
1954: fprintferr("A4GaloisConj:sigma=%Z \n", pft);
1955: for (i = 0; i < N; i++)
1956: {
1957: GEN g;
1958: int a, x, y;
1959: if (i == 0)
1960: {
1961: for (k = 0; k < n; k += 4)
1962: {
1963: u[k + 3] = t[k + 3];
1964: u[k + 2] = t[k + 1];
1965: u[k + 1] = t[k + 2];
1966: u[k] = t[k];
1967: }
1968: }
1969: else
1970: {
1971: x = i;
1972: y = -2;
1973: do
1974: {
1975: y += 4;
1976: a = x%y;
1977: x = x/y;
1978: }
1979: while (!a);
1980: x = u[2];
1981: u[2] = u[0];
1982: u[0] = x;
1983: switch (y)
1984: {
1985: case 2:
1986: break;
1987: case 6:
1988: x = u[4];
1989: u[4] = u[6];
1990: u[6] = x;
1991: if (!(a & 1))
1992: {
1993: a = 4 - (a >> 1);
1994: x = u[6];
1995: u[6] = u[a];
1996: u[a] = x;
1997: x = u[4];
1998: u[4] = u[a - 2];
1999: u[a - 2] = x;
2000: }
2001: break;
2002: case 10:
2003: x = u[6];
2004: u[6] = u[3];
2005: u[3] = u[2];
2006: u[2] = u[4];
2007: u[4] = u[1];
2008: u[1] = u[0];
2009: u[0] = x;
2010: if (a >= 3)
2011: a += 2;
2012: a = 8 - a;
2013: x = u[10];
2014: u[10] = u[a];
2015: u[a] = x;
2016: x = u[8];
2017: u[8] = u[a - 2];
2018: u[a - 2] = x;
2019: break;
2020: }
2021: }
2022: g = gzero;
2023: for (k = 0; k < n; k += 2)
2024: g = addii(g, addii(mt[u[k]][u[k + 1]], mt[u[k + 1]][u[k]]));
2025: if (padicisint(g, td))
2026: {
2027: for (k = 0; k < n; k += 2)
2028: {
2029: pfu[u[k]] = u[k + 1];
2030: pfu[u[k + 1]] = u[k];
2031: }
2032: if (verifietest(pfu, td))
2033: break;
2034: else
2035: hop++;
2036: }
2037: avma = av2;
2038: }
2039: if (i == N)
2040: {
2041: avma = ltop;
2042: return gzero;
2043: }
2044: if (DEBUGLEVEL >= 1 && hop)
2045: fprintferr("A4GaloisConj: %ld hop sur %ld iterations\n", hop, N);
2046: if (DEBUGLEVEL >= 4)
2047: fprintferr("A4GaloisConj:tau=%Z \n", pfu);
2048: avma = av2;
2049: orb = cgetg(3, t_VEC);
2050: orb[1] = (long) pft;
2051: orb[2] = (long) pfu;
2052: if (DEBUGLEVEL >= 4)
2053: fprintferr("A4GaloisConj:orb=%Z \n", orb);
1.3 ! noro 2054: O = (long**) vecperm_orbits(orb, 12);
1.1 noro 2055: if (DEBUGLEVEL >= 4)
2056: fprintferr("A4GaloisConj:O=%Z \n", O);
2057: av2 = avma;
2058: for (j = 0; j < 2; j++)
2059: {
2060: pfv[O[1][1]] = O[2][1];
2061: pfv[O[1][2]] = O[2][3 + j];
2062: pfv[O[1][3]] = O[2][4 - (j << 1)];
2063: pfv[O[1][4]] = O[2][2 + j];
2064: for (i = 0; i < 4; i++)
2065: {
2066: long x;
2067: GEN g;
2068: switch (i)
2069: {
2070: case 0:
2071: break;
2072: case 1:
2073: x = O[3][1];
2074: O[3][1] = O[3][2];
2075: O[3][2] = x;
2076: x = O[3][3];
2077: O[3][3] = O[3][4];
2078: O[3][4] = x;
2079: break;
2080: case 2:
2081: x = O[3][1];
2082: O[3][1] = O[3][4];
2083: O[3][4] = x;
2084: x = O[3][2];
2085: O[3][2] = O[3][3];
2086: O[3][3] = x;
2087: break;
2088: case 3:
2089: x = O[3][1];
2090: O[3][1] = O[3][2];
2091: O[3][2] = x;
2092: x = O[3][3];
2093: O[3][3] = O[3][4];
2094: O[3][4] = x;
2095: }
2096: pfv[O[2][1]] = O[3][1];
2097: pfv[O[2][3 + j]] = O[3][4 - j];
2098: pfv[O[2][4 - (j << 1)]] = O[3][2 + (j << 1)];
2099: pfv[O[2][2 + j]] = O[3][3 - j];
2100: pfv[O[3][1]] = O[1][1];
2101: pfv[O[3][4 - j]] = O[1][2];
2102: pfv[O[3][2 + (j << 1)]] = O[1][3];
2103: pfv[O[3][3 - j]] = O[1][4];
2104: g = gzero;
2105: for (k = 1; k <= n; k++)
2106: g = addii(g, mt[k][pfv[k]]);
2107: if (padicisint(g, td) && verifietest(pfv, td))
2108: {
2109: avma = av;
2110: if (DEBUGLEVEL >= 1)
2111: fprintferr("A4GaloisConj:%ld hop sur %d iterations max\n",
2112: hop, 10395 + 68);
2113: return res;
2114: }
2115: else
2116: hop++;
2117: avma = av2;
2118: }
2119: }
2120: /* Echec? */
2121: avma = ltop;
2122: return gzero;
2123: }
2124:
2125: /* Groupe S4 */
2126: static void
2127: s4makelift(GEN u, struct galois_lift *gl, GEN liftpow)
2128: {
2129: int i;
2130: liftpow[1] = (long) automorphismlift(u, gl, NULL);
2131: for (i = 2; i < lg(liftpow); i++)
2132: liftpow[i] = (long) FpXQ_mul((GEN) liftpow[i - 1], (GEN) liftpow[1],gl->TQ,gl->Q);
2133: }
2134: static long
2135: s4test(GEN u, GEN liftpow, struct galois_lift *gl, GEN phi)
2136: {
1.3 ! noro 2137: gpmem_t ltop=avma;
1.1 noro 2138: GEN res;
2139: int bl,i,d = lgef(u)-2;
1.3 ! noro 2140: if (DEBUGLEVEL >= 6) (void)timer2();
1.1 noro 2141: if ( !d ) return 0;
2142: res=(GEN)u[2];
2143: for (i = 1; i < d; i++)
2144: {
2145: if (lgef(liftpow[i])>2)
2146: res=addii(res,mulii(gmael(liftpow,i,2), (GEN) u[i + 2]));
2147: }
2148: res=modii(mulii(res,gl->den),gl->Q);
2149: if (cmpii(res,gl->gb->bornesol)>0
2150: && cmpii(res,subii(gl->Q,gl->gb->bornesol))<0)
2151: {
2152: avma=ltop;
2153: return 0;
2154: }
2155: res = (GEN) scalarpol((GEN)u[2],varn(u));
2156: for (i = 1; i < d ; i++)
2157: {
2158: GEN z;
2159: z = FpX_Fp_mul((GEN) liftpow[i], (GEN) u[i + 2],NULL);
2160: res = FpX_add(res,z ,gl->Q);
2161: }
2162: res = FpX_center(FpX_Fp_mul(res,gl->den,gl->Q), gl->Q);
2163: if (DEBUGLEVEL >= 6)
2164: msgtimer("s4test()");
2165: bl = poltopermtest(res, gl, phi);
2166: avma=ltop;
2167: return bl;
2168: }
2169: static GEN
2170: s4releveauto(GEN misom,GEN Tmod,GEN Tp,GEN p,long a1,long a2,long a3,long a4,long a5,long a6)
2171: {
1.3 ! noro 2172: gpmem_t ltop=avma;
1.1 noro 2173: GEN u1,u2,u3,u4,u5;
2174: GEN pu1,pu2,pu3,pu4;
2175: pu1=FpX_mul( (GEN) Tmod[a2], (GEN) Tmod[a1],p);
2176: u1 = FpX_chinese_coprime(gmael(misom,a1,a2),gmael(misom,a2,a1),
2177: (GEN) Tmod[a2], (GEN) Tmod[a1],pu1,p);
2178: pu2=FpX_mul( (GEN) Tmod[a4], (GEN) Tmod[a3],p);
2179: u2 = FpX_chinese_coprime(gmael(misom,a3,a4),gmael(misom,a4,a3),
2180: (GEN) Tmod[a4], (GEN) Tmod[a3],pu2,p);
2181: pu3=FpX_mul( (GEN) Tmod[a6], (GEN) Tmod[a5],p);
2182: u3 = FpX_chinese_coprime(gmael(misom,a5,a6),gmael(misom,a6,a5),
2183: (GEN) Tmod[a6], (GEN) Tmod[a5],pu3,p);
2184: pu4=FpX_mul(pu1,pu2,p);
2185: u4 = FpX_chinese_coprime(u1,u2,pu1,pu2,pu4,p);
2186: u5 = FpX_chinese_coprime(u4,u3,pu4,pu3,Tp,p);
2187: return gerepileupto(ltop,u5);
2188: }
2189: GEN
2190: s4galoisgen(struct galois_lift *gl)
2191: {
2192: struct galois_testlift gt;
1.3 ! noro 2193: gpmem_t av, ltop2, ltop = avma;
1.1 noro 2194: GEN Tmod, isom, isominv, misom;
2195: int i, j;
2196: GEN sg;
2197: GEN sigma, tau, phi;
2198: GEN res, ry;
2199: GEN pj;
2200: GEN p,Q,TQ,Tp;
2201: GEN bezoutcoeff, pauto, liftpow, aut;
2202:
2203: p = gl->p;
2204: Q = gl->Q;
2205: res = cgetg(3, t_VEC);
2206: ry = cgetg(5, t_VEC);
2207: res[1] = (long) ry;
2208: for (i = 1; i < lg(ry); i++)
2209: ry[i] = lgetg(lg(gl->L), t_VECSMALL);
2210: ry = cgetg(5, t_VECSMALL);
2211: res[2] = (long) ry;
2212: ry[1] = 2;
2213: ry[2] = 2;
2214: ry[3] = 3;
2215: ry[4] = 2;
2216: ltop2 = avma;
2217: sg = cgetg(7, t_VECSMALL);
2218: pj = cgetg(7, t_VECSMALL);
2219: sigma = cgetg(lg(gl->L), t_VECSMALL);
2220: tau = cgetg(lg(gl->L), t_VECSMALL);
2221: phi = cgetg(lg(gl->L), t_VECSMALL);
2222: for (i = 1; i < lg(sg); i++)
2223: sg[i] = i;
2224: Tp = FpX_red(gl->T,p);
2225: TQ = gl->TQ;
2226: Tmod = lift((GEN) factmod(gl->T, p)[1]);
2227: isom = cgetg(lg(Tmod), t_VEC);
2228: isominv = cgetg(lg(Tmod), t_VEC);
2229: misom = cgetg(lg(Tmod), t_MAT);
2230: aut=galoisdolift(gl, NULL);
2231: inittestlift(aut,Tmod, gl, >);
2232: bezoutcoeff = gt.bezoutcoeff;
2233: pauto = gt.pauto;
2234: for (i = 1; i < lg(pj); i++)
2235: pj[i] = 0;
2236: for (i = 1; i < lg(isom); i++)
2237: {
2238: misom[i] = lgetg(lg(Tmod), t_COL);
2239: isom[i] = (long) Fp_isom((GEN) Tmod[1], (GEN) Tmod[i], p);
2240: if (DEBUGLEVEL >= 6)
2241: fprintferr("S4GaloisConj:Computing isomorphisms %d:%Z\n", i,
2242: (GEN) isom[i]);
2243: isominv[i] = (long) Fp_inv_isom((GEN) isom[i], (GEN) Tmod[i],p);
2244: }
2245: for (i = 1; i < lg(isom); i++)
2246: for (j = 1; j < lg(isom); j++)
2247: mael(misom,i,j) = (long) FpX_FpXQ_compo((GEN) isominv[i],(GEN) isom[j],
2248: (GEN) Tmod[j],p);
2249: liftpow = cgetg(24, t_VEC);
2250: av = avma;
2251: for (i = 0; i < 3; i++)
2252: {
1.3 ! noro 2253: gpmem_t av2, avm1, avm2;
1.1 noro 2254: GEN u;
2255: int j1, j2, j3;
2256: GEN u1, u2, u3;
2257: if (i)
2258: {
2259: int x;
2260: x = sg[3];
2261: if (i == 1)
2262: {
2263: sg[3] = sg[2];
2264: sg[2] = x;
2265: }
2266: else
2267: {
2268: sg[3] = sg[1];
2269: sg[1] = x;
2270: }
2271: }
2272: u=s4releveauto(misom,Tmod,Tp,p,sg[1],sg[2],sg[3],sg[4],sg[5],sg[6]);
2273: s4makelift(u, gl, liftpow);
2274: av2 = avma;
2275: for (j1 = 0; j1 < 4; j1++)
2276: {
2277: u1 = FpX_add(FpXQ_mul((GEN) bezoutcoeff[sg[5]],
2278: (GEN) pauto[1 + j1],TQ,Q),
2279: FpXQ_mul((GEN) bezoutcoeff[sg[6]],
2280: (GEN) pauto[((-j1) & 3) + 1],TQ,Q),Q);
2281: avm1 = avma;
2282: for (j2 = 0; j2 < 4; j2++)
2283: {
2284: u2 = FpX_add(u1, FpXQ_mul((GEN) bezoutcoeff[sg[3]],
2285: (GEN) pauto[1 + j2],TQ,Q),NULL);
2286: u2 = FpX_add(u2, FpXQ_mul((GEN) bezoutcoeff[sg[4]], (GEN)
2287: pauto[((-j2) & 3) + 1],TQ,Q),Q);
2288: avm2 = avma;
2289: for (j3 = 0; j3 < 4; j3++)
2290: {
2291: u3 = FpX_add(u2, FpXQ_mul((GEN) bezoutcoeff[sg[1]],
2292: (GEN) pauto[1 + j3],TQ,Q),NULL);
2293: u3 = FpX_add(u3, FpXQ_mul((GEN) bezoutcoeff[sg[2]], (GEN)
2294: pauto[((-j3) & 3) + 1],TQ,Q),Q);
2295: if (DEBUGLEVEL >= 4)
2296: fprintferr("S4GaloisConj:Testing %d/3:%d/4:%d/4:%d/4:%Z\n",
2297: i, j1,j2, j3, sg);
2298: if (s4test(u3, liftpow, gl, sigma))
2299: {
2300: pj[1] = j3;
2301: pj[2] = j2;
2302: pj[3] = j1;
2303: goto suites4;
2304: }
2305: avma = avm2;
2306: }
2307: avma = avm1;
2308: }
2309: avma = av2;
2310: }
2311: avma = av;
2312: }
2313: avma = ltop;
2314: return gzero;
2315: suites4:
2316: if (DEBUGLEVEL >= 4)
2317: fprintferr("S4GaloisConj:sigma=%Z\n", sigma);
2318: if (DEBUGLEVEL >= 4)
2319: fprintferr("S4GaloisConj:pj=%Z\n", pj);
2320: avma = av;
2321: for (j = 1; j <= 3; j++)
2322: {
1.3 ! noro 2323: gpmem_t av2;
1.1 noro 2324: GEN u;
2325: int w, l;
2326: int z;
2327: z = sg[1]; sg[1] = sg[3]; sg[3] = sg[5]; sg[5] = z;
2328: z = sg[2]; sg[2] = sg[4]; sg[4] = sg[6]; sg[6] = z;
2329: z = pj[1]; pj[1] = pj[2]; pj[2] = pj[3]; pj[3] = z;
2330: for (l = 0; l < 2; l++)
2331: {
2332: u=s4releveauto(misom,Tmod,Tp,p,sg[1],sg[3],sg[2],sg[4],sg[5],sg[6]);
2333: s4makelift(u, gl, liftpow);
2334: av2 = avma;
2335: for (w = 0; w < 4; w += 2)
2336: {
1.3 ! noro 2337: gpmem_t av3;
1.1 noro 2338: GEN uu;
2339: pj[6] = (w + pj[3]) & 3;
2340: uu =FpX_add(FpXQ_mul((GEN) bezoutcoeff[sg[5]],
2341: (GEN) pauto[(pj[6] & 3) + 1],TQ,Q),
2342: FpXQ_mul((GEN) bezoutcoeff[sg[6]],
2343: (GEN) pauto[((-pj[6]) & 3) + 1],TQ,Q),Q);
2344: av3 = avma;
2345: for (i = 0; i < 4; i++)
2346: {
2347: GEN u;
2348: pj[4] = i;
2349: pj[5] = (i + pj[2] - pj[1]) & 3;
2350: if (DEBUGLEVEL >= 4)
2351: fprintferr("S4GaloisConj:Testing %d/3:%d/2:%d/2:%d/4:%Z:%Z\n",
2352: j - 1, w >> 1, l, i, sg, pj);
2353: u = FpX_add(uu, FpXQ_mul((GEN) pauto[(pj[4] & 3) + 1],
2354: (GEN) bezoutcoeff[sg[1]],TQ,Q),Q);
2355: u = FpX_add(u, FpXQ_mul((GEN) pauto[((-pj[4]) & 3) + 1],
2356: (GEN) bezoutcoeff[sg[3]],TQ,Q),Q);
2357: u = FpX_add(u, FpXQ_mul((GEN) pauto[(pj[5] & 3) + 1],
2358: (GEN) bezoutcoeff[sg[2]],TQ,Q),Q);
2359: u = FpX_add(u, FpXQ_mul((GEN) pauto[((-pj[5]) & 3) + 1],
2360: (GEN) bezoutcoeff[sg[4]],TQ,Q),Q);
2361: if (s4test(u, liftpow, gl, tau))
2362: goto suites4_2;
2363: avma = av3;
2364: }
2365: avma = av2;
2366: }
2367: z = sg[4];
2368: sg[4] = sg[3];
2369: sg[3] = z;
2370: pj[2] = (-pj[2]) & 3;
2371: avma = av;
2372: }
2373: }
2374: avma = ltop;
2375: return gzero;
2376: suites4_2:
2377: avma = av;
2378: {
2379: int abc, abcdef;
2380: GEN u;
1.3 ! noro 2381: gpmem_t av2;
1.1 noro 2382: abc = (pj[1] + pj[2] + pj[3]) & 3;
2383: abcdef = (((abc + pj[4] + pj[5] - pj[6]) & 3) >> 1);
2384: u = s4releveauto(misom,Tmod,Tp,p,sg[1],sg[4],sg[2],sg[5],sg[3],sg[6]);
2385: s4makelift(u, gl, liftpow);
2386: av2 = avma;
2387: for (j = 0; j < 8; j++)
2388: {
2389: int h, g, i;
2390: h = j & 3;
2391: g = abcdef + ((j & 4) >> 1);
2392: i = h + abc - g;
2393: u = FpXQ_mul((GEN) pauto[(g & 3) + 1],
2394: (GEN) bezoutcoeff[sg[1]],TQ,Q);
2395: u = FpX_add(u, FpXQ_mul((GEN) pauto[((-g) & 3) + 1],
2396: (GEN) bezoutcoeff[sg[4]],TQ,Q),NULL);
2397: u = FpX_add(u, FpXQ_mul((GEN) pauto[(h & 3) + 1],
2398: (GEN) bezoutcoeff[sg[2]],TQ,Q),NULL);
2399: u = FpX_add(u, FpXQ_mul((GEN) pauto[((-h) & 3) + 1],
2400: (GEN) bezoutcoeff[sg[5]],TQ,Q),NULL);
2401: u = FpX_add(u, FpXQ_mul((GEN) pauto[(i & 3) + 1],
2402: (GEN) bezoutcoeff[sg[3]],TQ,Q),NULL);
2403: u = FpX_add(u, FpXQ_mul((GEN) pauto[((-i) & 3) + 1],
2404: (GEN) bezoutcoeff[sg[6]],TQ,Q),Q);
2405: if (DEBUGLEVEL >= 4)
2406: fprintferr("S4GaloisConj:Testing %d/8 %d:%d:%d\n",
2407: j, g & 3, h & 3, i & 3);
2408: if (s4test(u, liftpow, gl, phi))
2409: break;
2410: avma = av2;
2411: }
2412: }
2413: if (j == 8)
2414: {
2415: avma = ltop;
2416: return gzero;
2417: }
2418: for (i = 1; i < lg(gl->L); i++)
2419: {
2420: ((GEN **) res)[1][1][i] = sigma[tau[i]];
2421: ((GEN **) res)[1][2][i] = phi[sigma[tau[phi[i]]]];
2422: ((GEN **) res)[1][3][i] = phi[sigma[i]];
2423: ((GEN **) res)[1][4][i] = sigma[i];
2424: }
2425: avma = ltop2;
2426: return res;
2427: }
2428: struct galois_frobenius
2429: {
2430: long p;
2431: long fp;
2432: long deg;
2433: GEN Tmod;
2434: GEN psi;
2435: };
2436:
2437: /*Warning : the output of this function is not gerepileupto
2438: * compatible...*/
2439: static GEN
2440: galoisfindgroups(GEN lo, GEN sg, long f)
2441: {
1.3 ! noro 2442: gpmem_t ltop=avma;
1.1 noro 2443: GEN V,W;
2444: long i,j,k;
2445: V=cgetg(lg(lo),t_VEC);
2446: for(j=1,i=1;i<lg(lo);i++)
2447: {
1.3 ! noro 2448: gpmem_t av=avma;
1.1 noro 2449: GEN U;
2450: W=cgetg(lg(lo[i]),t_VECSMALL);
2451: for(k=1;k<lg(lo[i]);k++)
2452: W[k]=mael(lo,i,k)%f;
1.3 ! noro 2453: vecsmall_sort(W);
! 2454: U=vecsmall_uniq(W);
1.1 noro 2455: if (gegal(U, sg))
2456: {
2457: cgiv(U);
2458: V[j++]=lo[i];
2459: }
2460: else
2461: avma=av;
2462: }
2463: setlg(V,j);
2464: /*warning components of V point to W*/
2465: return gerepileupto(ltop,V);
2466: }
2467:
2468: static long
2469: galoisfrobeniustest(GEN aut, struct galois_lift *gl, GEN frob)
2470: {
1.3 ! noro 2471: gpmem_t ltop = avma;
1.1 noro 2472: GEN tlift = FpX_center(FpX_Fp_mul(aut,gl->den,gl->Q), gl->Q);
1.3 ! noro 2473: long res = poltopermtest(tlift, gl, frob);
! 2474: avma = ltop;
1.1 noro 2475: return res;
2476: }
2477:
2478: static GEN
2479: galoismakepsi(long g, GEN sg, GEN pf)
2480: {
2481: GEN psi=cgetg(g+1,t_VECSMALL);
2482: long i;
2483: for (i = 1; i < g; i++)
2484: psi[i] = sg[pf[i]];
2485: psi[g]=sg[1];
2486: return psi;
2487: }
2488:
2489: static GEN
1.3 ! noro 2490: galoisfrobeniuslift(GEN T, GEN den, GEN L, GEN Lden,
1.1 noro 2491: struct galois_frobenius *gf, struct galois_borne *gb)
2492: {
1.3 ! noro 2493: gpmem_t ltop=avma, av2;
1.1 noro 2494: struct galois_testlift gt;
2495: struct galois_lift gl;
2496: GEN res;
2497: long i,j,k;
2498: long n=lg(L)-1, deg=1, g=lg(gf->Tmod)-1;
2499: GEN F,Fp,Fe;
2500: GEN ip=stoi(gf->p), aut, frob;
2501: if (DEBUGLEVEL >= 4)
2502: fprintferr("GaloisConj:p=%ld deg=%ld fp=%ld\n", gf->p, deg, gf->fp);
2503: res = cgetg(lg(L), t_VECSMALL);
1.3 ! noro 2504: gf->psi = vecsmall_const(g,1);
1.1 noro 2505: av2=avma;
2506: initlift(T, den, ip, L, Lden, gb, &gl);
2507: aut = galoisdolift(&gl, res);
2508: if (!aut || galoisfrobeniustest(aut,&gl,res))
2509: {
2510: avma=av2;
2511: gf->deg = gf->fp;
2512: return res;
2513: }
2514: inittestlift(aut,gf->Tmod, &gl, >);
2515: gt.C=cgetg(gf->fp+1,t_VEC);
2516: for (i = 1; i <= gf->fp; i++)
2517: {
2518: gt.C[i]=lgetg(gt.g+1,t_VECSMALL);
2519: for(j = 1; j <= gt.g; j++)
2520: mael(gt.C,i,j)=0;
2521: }
2522: gt.Cd=gcopy(gt.C);
2523:
2524: F=factor(stoi(gf->fp));
2525: Fp=gtovecsmall((GEN)F[1]);
2526: Fe=gtovecsmall((GEN)F[2]);
2527: frob = cgetg(lg(L), t_VECSMALL);
2528: for(k=lg(Fp)-1;k>=1;k--)
2529: {
1.3 ! noro 2530: gpmem_t btop=avma;
1.1 noro 2531: GEN psi=NULL,fres=NULL,sg;
2532: long el=gf->fp, dg=1, dgf=1;
2533: long e,pr;
1.3 ! noro 2534: sg=perm_identity(1);
1.1 noro 2535: for(e=1;e<=Fe[k];e++)
2536: {
2537: long l;
2538: GEN lo;
2539: GEN pf;
2540: dg *= Fp[k]; el /= Fp[k];
2541: if ( DEBUGLEVEL>=4 )
2542: fprintferr("Trying degre %d.\n",dg);
2543: if (galoisfrobeniustest((GEN)gt.pauto[el+1],&gl,frob))
2544: {
2545: dgf = dg;
1.3 ! noro 2546: psi = vecsmall_const(g,1);
1.1 noro 2547: fres= gcopy(frob);
2548: continue;
2549: }
2550: disable_dbg(0);
2551: lo = listsousgroupes(dg, n / gf->fp);
2552: disable_dbg(-1);
2553: if (e!=1)
2554: lo = galoisfindgroups(lo, sg, dgf);
2555: if (DEBUGLEVEL >= 4)
2556: fprintferr("Galoisconj:Subgroups list:%Z\n", lo);
2557: for (l = 1; l < lg(lo); l++)
2558: if ( lg(lo[l])>2 &&
2559: frobeniusliftall((GEN)lo[l], el, &pf, &gl, >, frob))
2560: {
2561: sg = gcopy((GEN)lo[l]);
2562: psi = galoismakepsi(g,sg,pf);
2563: dgf = dg;
2564: fres=gcopy(frob);
2565: break;
2566: }
2567: if ( l == lg(lo) )
2568: break;
2569: }
2570: if (dgf==1) { avma=btop; continue; }
2571: pr=deg*dgf;
2572: if (deg==1)
2573: {
2574: for(i=1;i<lg(res);i++) res[i]=fres[i];
2575: for(i=1;i<lg(psi);i++) gf->psi[i]=psi[i];
2576: }
2577: else
2578: {
1.3 ! noro 2579: GEN cp=perm_mul(res,fres);
1.1 noro 2580: for(i=1;i<lg(res);i++) res[i]=cp[i];
2581: for(i=1;i<lg(psi);i++) gf->psi[i]=(dgf*gf->psi[i]+deg*psi[i])%pr;
2582: }
2583: deg=pr;
2584: avma=btop;
2585: }
2586: for (i = 1; i <= gf->fp; i++)
2587: for (j = 1; j <= gt.g; j++)
2588: if (mael(gt.C,i,j))
2589: gunclone(gmael(gt.C,i,j));
2590: if (DEBUGLEVEL>=4 && res)
2591: fprintferr("Best lift: %d\n",deg);
2592: if (deg==1)
2593: {
2594: avma=ltop;
2595: return NULL;
2596: }
2597: else
2598: {
2599: /*We need to normalise result so that psi[g]=1*/
2600: long im=itos(mpinvmod(stoi(gf->psi[g]),stoi(gf->fp)));
1.3 ! noro 2601: GEN cp=perm_pow(res, im);
1.1 noro 2602: for(i=1;i<lg(res);i++) res[i]=cp[i];
2603: for(i=1;i<lg(gf->psi);i++) gf->psi[i]=mulssmod(im,gf->psi[i],gf->fp);
2604: avma=av2;
2605: gf->deg=deg;
2606: return res;
2607: }
2608: }
2609:
2610: static GEN
1.3 ! noro 2611: galoisfindfrobenius(GEN T, GEN L, GEN den, struct galois_frobenius *gf,
1.1 noro 2612: struct galois_borne *gb, const struct galois_analysis *ga)
2613: {
1.3 ! noro 2614: gpmem_t lbot, ltop=avma;
! 2615: long Try=0;
1.1 noro 2616: long n = degpol(T), deg, gmask;
2617: byteptr primepointer = ga->primepointer;
2618: GEN Lden,frob;
2619: Lden=makeLden(L,den,gb);
2620: gf->deg=ga->deg;gf->p=ga->p; deg=ga->deg;
2621: gmask=(ga->group&ga_ext_2)?3:1;
2622: for (;;)
2623: {
1.3 ! noro 2624: gpmem_t av = avma;
1.1 noro 2625: long isram;
1.3 ! noro 2626: long i;
1.1 noro 2627: GEN ip,Tmod;
2628: ip = stoi(gf->p);
2629: Tmod = lift((GEN) factmod(T, ip));
2630: isram = 0;
2631: for (i = 1; i < lg(Tmod[2]) && !isram; i++)
2632: if (!gcmp1(gmael(Tmod,2,i)))
2633: isram = 1;
2634: if (isram == 0)
2635: {
2636: gf->fp = degpol(gmael(Tmod,1,1));
2637: for (i = 2; i < lg(Tmod[1]); i++)
2638: if (degpol(gmael(Tmod,1,i)) != gf->fp)
2639: {
2640: avma = ltop;
2641: return NULL; /* Not Galois polynomial */
2642: }
2643: lbot=avma;
2644: gf->Tmod=gcopy((GEN)Tmod[1]);
2645: if ( ((gmask&1) && gf->fp % deg == 0) || ((gmask&2) && gf->fp % 2== 0) )
2646: {
1.3 ! noro 2647: frob=galoisfrobeniuslift(T, den, L, Lden, gf, gb);
1.1 noro 2648: if (frob)
2649: {
2650: GEN *gptr[3];
2651: gptr[0]=&gf->Tmod;
2652: gptr[1]=&gf->psi;
2653: gptr[2]=&frob;
2654: gerepilemanysp(ltop,lbot,gptr,3);
2655: return frob;
2656: }
2657: if ((ga->group&ga_all_normal) && gf->fp % deg == 0)
2658: gmask&=~1;
2659: /*The first prime degree is always divisible by deg, so we don't
2660: * have to worry about ext_2 being used before regular supersolvable*/
2661: if (!gmask)
2662: {
2663: avma = ltop;
2664: return NULL;
2665: }
1.3 ! noro 2666: Try++;
! 2667: if ( (ga->group&ga_non_wss) && Try > n )
1.1 noro 2668: err(warner, "galoisconj _may_ hang up for this polynomial");
2669: }
2670: }
1.3 ! noro 2671: NEXT_PRIME_VIADIFF_CHECK(gf->p, primepointer);
1.1 noro 2672: if (DEBUGLEVEL >= 4)
2673: fprintferr("GaloisConj:next p=%ld\n", gf->p);
2674: avma = av;
2675: }
2676: }
2677:
2678: GEN
2679: galoisgen(GEN T, GEN L, GEN M, GEN den, struct galois_borne *gb,
1.3 ! noro 2680: const struct galois_analysis *ga);
! 2681: static GEN
! 2682: galoisgenfixedfield(GEN Tp, GEN Pmod, GEN V, GEN ip, struct galois_borne *gb, GEN Pg)
! 2683: {
! 2684: gpmem_t ltop=avma;
! 2685: GEN P, PL, Pden, PM, Pp, Pladicabs;
! 2686: GEN tau, PG;
! 2687: long g,gp;
! 2688: long x=varn(Tp);
! 2689: P=(GEN)V[2];
! 2690: PL=(GEN)V[1];
! 2691: gp=lg(Pmod)-1;
! 2692: Pp = FpX_red(P,ip);
! 2693: if (DEBUGLEVEL>=6)
! 2694: fprintferr("GaloisConj: Fixed field %Z\n",P);
! 2695: if (degpol(P)==2)
! 2696: {
! 2697: PG=cgetg(3,t_VEC);
! 2698: PG[1]=lgetg(2,t_VEC);
! 2699: PG[2]=lgetg(2,t_VECSMALL);
! 2700: mael(PG,1,1)=lgetg(3,t_VECSMALL);
! 2701: mael(PG,2,1)=2;
! 2702: mael3(PG,1,1,1)=2;
! 2703: mael3(PG,1,1,2)=1;
! 2704: tau=deg1pol(stoi(-1),negi((GEN)P[3]),x);
! 2705: tau = lift(gmul(tau,gmodulcp(gun,ip)));
! 2706: tau = FpX_FpXQ_compo((GEN) Pmod[gp], tau,Pp,ip);
! 2707: tau = FpX_gcd(Pp, tau,ip);
! 2708: tau = FpX_Fp_mul(tau,mpinvmod((GEN) tau[lgef(tau) - 1],ip),ip);
! 2709: for (g = 1; g <= gp; g++)
! 2710: if (gegal(tau, (GEN) Pmod[g]))
! 2711: break;
! 2712: if (g == lg(Pmod))
! 2713: return NULL;
! 2714: Pg[1]=g;
! 2715: }
! 2716: else
! 2717: {
! 2718: struct galois_analysis Pga;
! 2719: struct galois_borne Pgb;
! 2720: long j;
! 2721: galoisanalysis(P, &Pga, 0, 0);
! 2722: if (Pga.deg == 0)
! 2723: return NULL; /* Avoid computing the discriminant */
! 2724: Pgb.l = gb->l;
! 2725: Pden = galoisborne(P, NULL, &Pgb, Pga.ppp);
! 2726: Pladicabs=Pgb.ladicabs;
! 2727: if (Pgb.valabs > gb->valabs)
! 2728: {
! 2729: if (DEBUGLEVEL>=4)
! 2730: fprintferr("GaloisConj:increase prec of p-adic roots of %ld.\n"
! 2731: ,Pgb.valabs-gb->valabs);
! 2732: PL = rootpadicliftroots(P,PL,gb->l,Pgb.valabs);
! 2733: }
! 2734: PM = vandermondeinversemod(PL, P, Pden, Pgb.ladicabs);
! 2735: PG = galoisgen(P, PL, PM, Pden, &Pgb, &Pga);
! 2736: if (PG == gzero) return NULL;
! 2737: for (j = 1; j < lg(PG[1]); j++)
! 2738: {
! 2739: gpmem_t btop=avma;
! 2740: tau = permtopol(gmael(PG,1,j), PL, PM, Pden, Pladicabs, x);
! 2741: tau = lift(gmul(tau,gmodulcp(gun,ip)));
! 2742: tau = FpX_FpXQ_compo((GEN) Pmod[gp], tau,Pp,ip);
! 2743: tau = FpX_gcd(Pp, tau,ip);
! 2744: tau = FpX_Fp_mul(tau,mpinvmod((GEN) tau[lgef(tau) - 1],ip),ip);
! 2745: for (g = 1; g < lg(Pmod); g++)
! 2746: if (gegal(tau, (GEN) Pmod[g]))
! 2747: break;
! 2748: if (g == lg(Pmod))
! 2749: return NULL;
! 2750: avma=btop;
! 2751: Pg[j]=g;
! 2752: }
! 2753: }
! 2754: return gerepilecopy(ltop,PG);
! 2755: }
! 2756:
! 2757: GEN
! 2758: galoisgen(GEN T, GEN L, GEN M, GEN den, struct galois_borne *gb,
1.1 noro 2759: const struct galois_analysis *ga)
2760: {
2761: struct galois_test td;
2762: struct galois_frobenius gf;
1.3 ! noro 2763: gpmem_t lbot, ltop2, ltop = avma;
1.1 noro 2764: long n, p, deg;
1.3 ! noro 2765: long fp;
1.1 noro 2766: long x;
2767: int i, j;
2768: GEN Lden, sigma;
2769: GEN Tmod, res, pf = gzero, split, ip;
2770: GEN frob;
2771: GEN O;
1.3 ! noro 2772: GEN PG, Pg;
1.1 noro 2773: n = degpol(T);
2774: if (!ga->deg)
2775: return gzero;
2776: x = varn(T);
2777: if (DEBUGLEVEL >= 9)
2778: fprintferr("GaloisConj:denominator:%Z\n", den);
2779: if (n == 12 && ga->ord==3) /* A4 is very probable,so test it first */
2780: {
1.3 ! noro 2781: gpmem_t av = avma;
1.1 noro 2782: if (DEBUGLEVEL >= 4)
2783: fprintferr("GaloisConj:Testing A4 first\n");
2784: inittest(L, M, gb->bornesol, gb->ladicsol, &td);
2785: lbot = avma;
2786: PG = a4galoisgen(T, &td);
2787: freetest(&td);
2788: if (PG != gzero)
2789: return gerepile(ltop, lbot, PG);
2790: avma = av;
2791: }
2792: if (n == 24 && ga->ord==3) /* S4 is very probable,so test it first */
2793: {
1.3 ! noro 2794: gpmem_t av = avma;
1.1 noro 2795: struct galois_lift gl;
2796: if (DEBUGLEVEL >= 4)
2797: fprintferr("GaloisConj:Testing S4 first\n");
2798: lbot = avma;
2799: Lden=makeLden(L,den,gb);
2800: initlift(T, den, stoi(ga->p4), L, Lden, gb, &gl);
2801: PG = s4galoisgen(&gl);
2802: if (PG != gzero)
2803: return gerepile(ltop, lbot, PG);
2804: avma = av;
2805: }
1.3 ! noro 2806: frob=galoisfindfrobenius(T, L, den, &gf, gb, ga);
1.1 noro 2807: if (!frob)
2808: {
2809: ltop=avma;
2810: return gzero;
2811: }
1.3 ! noro 2812: p=gf.p;
1.1 noro 2813: ip=stoi(p);
2814: Tmod=gf.Tmod;
1.3 ! noro 2815: fp=gf.fp;
! 2816: O = perm_cycles(frob);
1.1 noro 2817: split = splitorbite(O);
2818: deg=lg(O[1])-1;
2819: sigma = permtopol(frob, L, M, den, gb->ladicabs, x);
2820: if (DEBUGLEVEL >= 9)
2821: fprintferr("GaloisConj:Orbite:%Z\n", O);
2822: if (deg == n) /* Cyclique */
2823: {
2824: lbot = avma;
2825: res = cgetg(3, t_VEC);
2826: res[1] = lgetg(lg(split[1]), t_VEC);
2827: res[2] = lgetg(lg(split[2]), t_VECSMALL);
2828: for (i = 1; i < lg(split[1]); i++)
2829: {
2830: mael(res,1,i) = lcopy(gmael(split,1,i));
2831: mael(res,2,i) = mael(split,2,i);
2832: }
2833: return gerepile(ltop, lbot, res);
2834: }
2835: if (DEBUGLEVEL >= 9)
2836: fprintferr("GaloisConj:Frobenius:%Z\n", sigma);
1.3 ! noro 2837: Pg=cgetg(lg(O),t_VECSMALL);
1.1 noro 2838: {
1.3 ! noro 2839: gpmem_t btop=avma;
! 2840: GEN V, sym, dg, Tp, Sp, Pmod;
1.1 noro 2841: sym=cgetg(lg(L),t_VECSMALL);
2842: dg=cgetg(lg(L),t_VECSMALL);
2843: V = fixedfieldsympol(O, L, gb->ladicabs, gb->l, ip, sym, dg, x);
2844: Tp = FpX_red(T,ip);
2845: Sp = fixedfieldpolsigma(sigma,ip,Tp,sym,dg,deg);
2846: Pmod = fixedfieldfactmod(Sp,ip,Tmod);
1.3 ! noro 2847: PG=galoisgenfixedfield(Tp, Pmod, V, ip, gb, Pg);
! 2848: if (PG == NULL)
1.1 noro 2849: {
1.3 ! noro 2850: avma = ltop;
! 2851: return gzero;
1.1 noro 2852: }
1.3 ! noro 2853: if (DEBUGLEVEL >= 4)
! 2854: fprintferr("GaloisConj:Back to Earth:%Z\n", PG);
! 2855: PG=gerepileupto(btop, PG);
1.1 noro 2856: }
2857: inittest(L, M, gb->bornesol, gb->ladicsol, &td);
2858: lbot = avma;
2859: res = cgetg(3, t_VEC);
2860: res[1] = lgetg(lg(PG[1]) + lg(split[1]) - 1, t_VEC);
2861: res[2] = lgetg(lg(PG[1]) + lg(split[1]) - 1, t_VECSMALL);
2862: for (i = 1; i < lg(split[1]); i++)
2863: {
2864: ((GEN **) res)[1][i] = gcopy(((GEN **) split)[1][i]);
2865: ((GEN *) res)[2][i] = ((GEN *) split)[2][i];
2866: }
2867: for (i = lg(split[1]); i < lg(res[1]); i++)
2868: ((GEN **) res)[1][i] = cgetg(n + 1, t_VECSMALL);
2869: ltop2 = avma;
2870: for (j = 1; j < lg(PG[1]); j++)
2871: {
1.3 ! noro 2872: GEN B;
! 2873: long t;
1.1 noro 2874: long w, sr, dss;
2875: if (DEBUGLEVEL >= 6)
2876: fprintferr("GaloisConj:G[%d]=%Z d'ordre relatif %d\n", j,
2877: ((GEN **) PG)[1][j], ((long **) PG)[2][j]);
1.3 ! noro 2878: B = perm_cycles(gmael(PG,1,j));
1.1 noro 2879: if (DEBUGLEVEL >= 6)
2880: fprintferr("GaloisConj:B=%Z\n", B);
1.3 ! noro 2881: w = gf.psi[Pg[j]];
1.1 noro 2882: dss = deg / cgcd(deg, w - 1);
2883: sr = 1;
2884: for (i = 1; i < lg(B[1]) - 1; i++)
2885: sr = (1 + sr * w) % deg;
2886: sr = cgcd(sr, deg);
2887: if (DEBUGLEVEL >= 6)
2888: fprintferr("GaloisConj:w=%ld [%ld] sr=%ld dss=%ld\n", w, deg, sr, dss);
2889: for (t = 0; t < sr; t += dss)
2890: {
2891: pf = testpermutation(O, B, w, t, sr, &td);
2892: if (pf != gzero)
2893: break;
2894: }
2895: if (pf == gzero)
2896: {
2897: freetest(&td);
2898: avma = ltop;
2899: return gzero;
2900: }
2901: else
2902: {
2903: int i;
2904: for (i = 1; i <= n; i++)
2905: ((GEN **) res)[1][lg(split[1]) + j - 1][i] = pf[i];
2906: ((GEN *) res)[2][lg(split[1]) + j - 1] = ((GEN *) PG)[2][j];
2907: }
2908: avma = ltop2;
2909: }
2910: if (DEBUGLEVEL >= 4)
2911: fprintferr("GaloisConj:Fini!\n");
2912: freetest(&td);
2913: return gerepile(ltop, lbot, res);
2914: }
2915:
2916: /*
2917: * T: polynome ou nf den optionnel: si présent doit etre un multiple du
2918: * dénominateur commun des solutions Si T est un nf et den n'est pas présent,
2919: * le denominateur de la base d'entiers est pris pour den
2920: */
2921: GEN
2922: galoisconj4(GEN T, GEN den, long flag, long karma)
2923: {
1.3 ! noro 2924: gpmem_t ltop = avma;
1.1 noro 2925: GEN G, L, M, res, aut, grp=NULL;/*keep gcc happy on the wall*/
2926: struct galois_analysis ga;
2927: struct galois_borne gb;
2928: int n, i, j, k;
2929: if (typ(T) != t_POL)
2930: {
2931: T = checknf(T);
1.3 ! noro 2932: if (!den) den = Q_denom((GEN)T[7]);
1.1 noro 2933: T = (GEN) T[1];
2934: }
2935: n = degpol(T);
2936: if (n <= 0)
2937: err(constpoler, "galoisconj4");
2938: for (k = 2; k <= n + 2; k++)
2939: if (typ(T[k]) != t_INT)
2940: err(talker, "polynomial not in Z[X] in galoisconj4");
2941: if (!gcmp1((GEN) T[n + 2]))
2942: err(talker, "non-monic polynomial in galoisconj4");
2943: n = degpol(T);
2944: if (n == 1) /* Too easy! */
2945: {
2946: if (!flag)
2947: {
2948: res = cgetg(2, t_COL);
2949: res[1] = (long) polx[varn(T)];
2950: return res;
2951: }
2952: ga.l = 3;
2953: ga.deg = 1;
2954: ga.ppp = 1;
2955: den = gun;
2956: }
2957: else
2958: galoisanalysis(T, &ga, 1, karma);
2959: if (ga.deg == 0)
2960: {
2961: avma = ltop;
2962: return stoi(ga.p); /* Avoid computing the discriminant */
2963: }
2964: if (den)
2965: {
2966: if (typ(den) != t_INT)
2967: err(talker, "Second arg. must be integer in galoisconj4");
2968: den = absi(den);
2969: }
2970: gb.l = stoi(ga.l);
1.3 ! noro 2971: if (DEBUGLEVEL >= 1) (void)timer2();
1.1 noro 2972: den = galoisborne(T, den, &gb, ga.ppp);
2973: if (DEBUGLEVEL >= 1)
2974: msgtimer("galoisborne()");
2975: L = rootpadicfast(T, gb.l, gb.valabs);
2976: if (DEBUGLEVEL >= 1)
2977: msgtimer("rootpadicfast()");
2978: M = vandermondeinversemod(L, T, den, gb.ladicabs);
2979: if (DEBUGLEVEL >= 1)
2980: msgtimer("vandermondeinversemod()");
2981: if (n == 1)
2982: {
2983: G = cgetg(3, t_VEC);
2984: G[1] = lgetg(1, t_VECSMALL);
2985: G[2] = lgetg(1, t_VECSMALL);
2986: }
2987: else
2988: G = galoisgen(T, L, M, den, &gb, &ga);
2989: if (DEBUGLEVEL >= 6)
2990: fprintferr("GaloisConj:%Z\n", G);
2991: if (G == gzero)
2992: {
2993: avma = ltop;
2994: return gzero;
2995: }
1.3 ! noro 2996: if (DEBUGLEVEL >= 1) (void)timer2();
1.1 noro 2997: if (flag)
2998: {
2999: grp = cgetg(9, t_VEC);
3000: grp[1] = (long) gcopy(T);
3001: grp[2] = lgetg(4,t_VEC); /*Make K.B. happy(8 components)*/
3002: mael(grp,2,1) = lstoi(ga.l);
3003: mael(grp,2,2) = lstoi(gb.valabs);
3004: mael(grp,2,3) = licopy(gb.ladicabs);
3005: grp[3] = (long) gcopy(L);
3006: grp[4] = (long) gcopy(M);
3007: grp[5] = (long) gcopy(den);
3008: grp[7] = (long) gcopy((GEN) G[1]);
3009: grp[8] = (long) gcopy((GEN) G[2]);
3010: }
3011: res = cgetg(n + 1, t_VEC);
1.3 ! noro 3012: res[1] = (long) perm_identity(n);
1.1 noro 3013: k = 1;
3014: for (i = 1; i < lg(G[1]); i++)
3015: {
3016: int c = k * (((long **) G)[2][i] - 1);
3017: for (j = 1; j <= c; j++) /* I like it */
1.3 ! noro 3018: res[++k] = (long) perm_mul((GEN) res[j], ((GEN **) G)[1][i]);
1.1 noro 3019: }
3020: if (flag)
3021: {
3022: grp[6] = (long) res;
3023: return gerepileupto(ltop, grp);
3024: }
3025: aut = galoisgrouptopol(res,L,M,den,gb.ladicsol, varn(T));
3026: if (DEBUGLEVEL >= 1)
3027: msgtimer("Calcul polynomes");
1.3 ! noro 3028: return gerepileupto(ltop, gen_sort(aut, 0, cmp_pol));
1.1 noro 3029: }
3030:
3031: /* Calcule le nombre d'automorphisme de T avec forte probabilité */
3032: /* pdepart premier nombre premier a tester */
3033: long
3034: numberofconjugates(GEN T, long pdepart)
3035: {
1.3 ! noro 3036: gpmem_t ltop2, ltop = avma;
1.1 noro 3037: long n, p, nbmax, nbtest;
3038: long card;
3039: byteptr primepointer;
3040: int i;
3041: GEN L;
3042: n = degpol(T);
3043: card = sturm(T);
3044: card = cgcd(card, n - card);
3045: nbmax = (n<<1) + 1;
3046: if (nbmax < 20) nbmax=20;
3047: nbtest = 0;
3048: L = cgetg(n + 1, t_VECSMALL);
3049: ltop2 = avma;
3050: for (p = 0, primepointer = diffptr; nbtest < nbmax && card > 1;)
3051: {
1.3 ! noro 3052: long s;
1.1 noro 3053: long isram;
3054: GEN S;
1.3 ! noro 3055:
! 3056: NEXT_PRIME_VIADIFF_CHECK(p,primepointer);
1.1 noro 3057: if (p < pdepart)
3058: continue;
3059: S = (GEN) simplefactmod(T, stoi(p));
3060: isram = 0;
3061: for (i = 1; i < lg(S[2]) && !isram; i++)
3062: if (!gcmp1(((GEN **) S)[2][i]))
3063: isram = 1;
3064: if (isram == 0)
3065: {
3066: for (i = 1; i <= n; i++)
3067: L[i] = 0;
3068: for (i = 1; i < lg(S[1]) && !isram; i++)
3069: L[itos(((GEN **) S)[1][i])]++;
3070: s = L[1];
3071: for (i = 2; i <= n; i++)
3072: s = cgcd(s, L[i] * i);
3073: card = cgcd(s, card);
3074: }
3075: if (DEBUGLEVEL >= 6)
3076: fprintferr("NumberOfConjugates:Nbtest=%ld,card=%ld,p=%ld\n", nbtest,
3077: card, p);
3078: nbtest++;
3079: avma = ltop2;
3080: }
3081: if (DEBUGLEVEL >= 2)
3082: fprintferr("NumberOfConjugates:card=%ld,p=%ld\n", card, p);
3083: avma = ltop;
3084: return card;
3085: }
3086:
3087: GEN
3088: galoisconj0(GEN nf, long flag, GEN d, long prec)
3089: {
1.3 ! noro 3090: gpmem_t ltop;
1.1 noro 3091: GEN G, T;
3092: long card;
3093: if (typ(nf) != t_POL)
3094: {
3095: nf = checknf(nf);
3096: T = (GEN) nf[1];
3097: }
3098: else
3099: T = nf;
3100: switch (flag)
3101: {
3102: case 0:
3103: ltop = avma;
3104: G = galoisconj4(nf, d, 0, 0);
3105: if (typ(G) != t_INT) /* Success */
3106: return G;
3107: else
3108: {
3109: card = numberofconjugates(T, G == gzero ? 2 : itos(G));
3110: avma = ltop;
3111: if (card != 1)
3112: {
3113: if (typ(nf) == t_POL)
3114: {
3115: G = galoisconj2pol(nf, card, prec);
3116: if (lg(G) <= card)
3117: err(warner, "conjugates list may be incomplete in nfgaloisconj");
3118: return G;
3119: }
3120: else
3121: return galoisconj(nf);
3122: }
3123: }
3124: break; /* Failure */
3125: case 1:
3126: return galoisconj(nf);
3127: case 2:
3128: return galoisconj2(nf, degpol(T), prec);
3129: case 4:
3130: G = galoisconj4(nf, d, 0, 0);
3131: if (typ(G) != t_INT)
3132: return G;
3133: break; /* Failure */
3134: default:
3135: err(flagerr, "nfgaloisconj");
3136: }
3137: G = cgetg(2, t_COL);
3138: G[1] = (long) polx[varn(T)];
3139: return G; /* Failure */
3140: }
3141:
3142:
3143:
3144: /******************************************************************************/
3145: /* Isomorphism between number fields */
3146: /******************************************************************************/
3147: long
3148: isomborne(GEN P, GEN den, GEN p)
3149: {
1.3 ! noro 3150: gpmem_t ltop=avma;
1.1 noro 3151: struct galois_borne gb;
3152: gb.l=p;
1.3 ! noro 3153: (void)galoisborne(P,den,&gb,degpol(P));
1.1 noro 3154: avma=ltop;
3155: return gb.valsol;
3156: }
3157:
3158:
3159:
3160: /******************************************************************************/
3161: /* Galois theory related algorithms */
3162: /******************************************************************************/
3163: GEN
3164: checkgal(GEN gal)
3165: {
3166: if (typ(gal) == t_POL)
3167: err(talker, "please apply galoisinit first");
3168: if (typ(gal) != t_VEC || lg(gal) != 9)
3169: err(talker, "Not a Galois field in a Galois related function");
3170: return gal;
3171: }
3172:
3173: GEN
3174: galoisinit(GEN nf, GEN den, long karma)
3175: {
3176: GEN G;
3177: G = galoisconj4(nf, den, 1, karma);
3178: if (typ(G) == t_INT)
3179: err(talker,
3180: "galoisinit: field not Galois or Galois group not weakly super solvable");
3181: return G;
3182: }
3183:
3184: GEN
3185: galoispermtopol(GEN gal, GEN perm)
3186: {
3187: GEN v;
3188: long t = typ(perm);
3189: int i;
3190: gal = checkgal(gal);
3191: switch (t)
3192: {
3193: case t_VECSMALL:
3194: return permtopol(perm, (GEN) gal[3], (GEN) gal[4], (GEN) gal[5],
3195: gmael(gal,2,3), varn((GEN) gal[1]));
3196: case t_VEC:
3197: case t_COL:
3198: case t_MAT:
3199: v = cgetg(lg(perm), t);
3200: for (i = 1; i < lg(v); i++)
3201: v[i] = (long) galoispermtopol(gal, (GEN) perm[i]);
3202: return v;
3203: }
3204: err(typeer, "galoispermtopol");
3205: return NULL; /* not reached */
3206: }
3207:
3208:
3209: GEN
3210: galoiscosets(GEN O, GEN perm)
3211: {
3212: long i,j,k,u;
3213: long o = lg(O)-1, f = lg(O[1])-1;
3214: GEN C = cgetg(lg(O),t_VECSMALL);
1.3 ! noro 3215: gpmem_t av=avma;
1.1 noro 3216: GEN RC=cgetg(lg(perm),t_VECSMALL);
3217: for(i=1;i<lg(RC);i++)
3218: RC[i]=0;
3219: u=mael(O,1,1);
3220: for(i=1,j=1;j<=o;i++)
3221: {
3222: if (RC[mael(perm,i,u)])
3223: continue;
3224: for(k=1;k<=f;k++)
3225: RC[mael(perm,i,mael(O,1,k))]=1;
3226: C[j++]=i;
3227: }
3228: avma=av;
3229: return C;
3230: }
3231:
3232: GEN
3233: fixedfieldfactor(GEN L, GEN O, GEN perm, GEN M, GEN den, GEN mod,
3234: long x,long y)
3235: {
1.3 ! noro 3236: gpmem_t ltop=avma;
1.1 noro 3237: GEN F,G,V,res,cosets;
3238: int i, j, k;
3239: F=cgetg(lg(O[1])+1,t_COL);
3240: F[lg(O[1])]=un;
3241: G=cgetg(lg(O),t_VEC);
3242: for (i = 1; i < lg(O); i++)
3243: {
3244: GEN Li = cgetg(lg(O[i]),t_VEC);
3245: for (j = 1; j < lg(O[i]); j++)
3246: Li[j] = L[mael(O,i,j)];
3247: G[i]=(long)FpV_roots_to_pol(Li,mod,x);
3248: }
3249:
3250: cosets=galoiscosets(O,perm);
3251: if (DEBUGLEVEL>=4) fprintferr("GaloisFixedField:cosets=%Z \n",cosets);
3252: V=cgetg(lg(O),t_COL);
3253: if (DEBUGLEVEL>=6) fprintferr("GaloisFixedField:den=%Z mod=%Z \n",den,mod);
3254: res=cgetg(lg(O),t_VEC);
3255: for (i = 1; i < lg(O); i++)
3256: {
1.3 ! noro 3257: gpmem_t av=avma;
1.1 noro 3258: long ii,jj;
3259: GEN G=cgetg(lg(O),t_VEC);
3260: for (ii = 1; ii < lg(O); ii++)
3261: {
3262: GEN Li = cgetg(lg(O[ii]),t_VEC);
3263: for (jj = 1; jj < lg(O[ii]); jj++)
3264: Li[jj] = L[mael(perm,cosets[i],mael(O,ii,jj))];
3265: G[ii]=(long)FpV_roots_to_pol(Li,mod,x);
3266: }
3267: for (j = 1; j < lg(O[1]); j++)
3268: {
3269: for(k = 1; k < lg(O); k++)
3270: V[k]=mael(G,k,j+1);
3271: F[j]=(long) vectopol(V, M, den, mod, y);
3272: }
3273: res[i]=(long)gerepileupto(av,gtopolyrev(F,x));
3274: }
3275: return gerepileupto(ltop,res);
3276: }
3277:
3278: GEN
3279: galoisfixedfield(GEN gal, GEN perm, long flag, long y)
3280: {
1.3 ! noro 3281: gpmem_t lbot, ltop = avma;
1.1 noro 3282: GEN L, P, S, PL, O, res, mod;
3283: long x, n;
3284: int i;
3285: gal = checkgal(gal);
3286: x = varn((GEN) gal[1]);
3287: L = (GEN) gal[3]; n=lg(L)-1;
3288: mod = gmael(gal,2,3);
3289: if (flag<0 || flag>2)
3290: err(flagerr, "galoisfixedfield");
3291: if (typ(perm) == t_VEC)
3292: {
1.3 ! noro 3293: for (i = 1; i < lg(perm); i++)
! 3294: if (typ(perm[i]) != t_VECSMALL || lg(perm[i])!=n+1)
! 3295: err(typeer, "galoisfixedfield");
! 3296: O = vecperm_orbits(perm, n);
1.1 noro 3297: }
3298: else if (typ(perm) != t_VECSMALL || lg(perm)!=n+1 )
1.3 ! noro 3299: {
1.1 noro 3300: err(typeer, "galoisfixedfield");
1.3 ! noro 3301: return NULL; /* not reached */
! 3302: }
! 3303: else
! 3304: O = perm_cycles(perm);
1.1 noro 3305: {
3306: GEN sym=cgetg(lg(L),t_VECSMALL);
3307: GEN dg=cgetg(lg(L),t_VECSMALL);
3308: GEN V;
3309: V = fixedfieldsympol(O, L, mod, gmael(gal,2,1), gun, sym, dg, x);
3310: P=(GEN)V[2];
3311: PL=(GEN)V[1];
3312: }
3313: if (flag==1)
3314: return gerepileupto(ltop,P);
3315: S = fixedfieldinclusion(O, PL);
3316: S = vectopol(S, (GEN) gal[4], (GEN) gal[5], mod, x);
3317: if (flag==0)
3318: {
3319: lbot = avma;
3320: res = cgetg(3, t_VEC);
3321: res[1] = (long) gcopy(P);
3322: res[2] = (long) gmodulcp(S, (GEN) gal[1]);
3323: return gerepile(ltop, lbot, res);
3324: }
3325: else
3326: {
3327: GEN PM,Pden;
3328: {
3329: struct galois_borne Pgb;
3330: long val=itos(gmael(gal,2,2));
3331: Pgb.l = gmael(gal,2,1);
3332: Pden = galoisborne(P, NULL, &Pgb, 1);
3333: if (Pgb.valabs > val)
3334: {
1.3 ! noro 3335: if (DEBUGLEVEL>=4)
! 3336: fprintferr("GaloisConj:increase prec of p-adic roots of %ld.\n"
! 3337: ,Pgb.valabs-val);
! 3338: PL = rootpadicliftroots(P,PL,Pgb.l,Pgb.valabs);
! 3339: L = rootpadicliftroots((GEN) gal[1],L,Pgb.l,Pgb.valabs);
! 3340: mod = Pgb.ladicabs;
1.1 noro 3341: }
3342: }
3343: PM = vandermondeinversemod(PL, P, Pden, mod);
3344: lbot = avma;
3345: if (y==-1)
3346: y = fetch_user_var("y");
3347: if (y<=x)
3348: err(talker,"priority of optional variable too high in galoisfixedfield");
3349: res = cgetg(4, t_VEC);
3350: res[1] = (long) gcopy(P);
3351: res[2] = (long) gmodulcp(S, (GEN) gal[1]);
3352: res[3] = (long) fixedfieldfactor(L,O,(GEN)gal[6],
1.3 ! noro 3353: PM,Pden,mod,x,y);
1.1 noro 3354: return gerepile(ltop, lbot, res);
3355: }
3356: }
3357:
3358: /*return 1 if gal is abelian, else 0*/
3359: long
3360: galoistestabelian(GEN gal)
3361: {
1.3 ! noro 3362: gpmem_t ltop=avma;
! 3363: GEN G;
! 3364: long test;
1.1 noro 3365: gal = checkgal(gal);
1.3 ! noro 3366: G=cgetg(3,t_VEC);
! 3367: G[1]=gal[7];
! 3368: G[2]=gal[8];
! 3369: test=group_isabelian(G);
! 3370: avma=ltop;
! 3371: return test;
1.1 noro 3372: }
3373:
3374: GEN galoisisabelian(GEN gal, long flag)
3375: {
3376: long i, j;
1.3 ! noro 3377: long test, n;
1.1 noro 3378: GEN M;
3379: gal = checkgal(gal);
3380: test=galoistestabelian(gal);
3381: if (!test) return gzero;
3382: if (flag==1) return gun;
3383: if (flag) err(flagerr,"galoisisabelian");
1.3 ! noro 3384: n=lg(gal[7]);
1.1 noro 3385: M=cgetg(n,t_MAT);
3386: for(i=1;i<n;i++)
3387: {
1.3 ! noro 3388: gpmem_t btop;
1.1 noro 3389: GEN P;
3390: long k;
3391: M[i]=lgetg(n,t_COL);
3392: btop=avma;
1.3 ! noro 3393: P=perm_pow(gmael(gal,7,i),mael(gal,8,i));
1.1 noro 3394: for(j=1;j<lg(gal[6]);j++)
3395: if (gegal(P,gmael(gal,6,j)))
3396: break;
3397: avma=btop;
3398: if (j==lg(gal[6])) err(talker,"wrong argument in galoisisabelian");
3399: j--;
3400: for(k=1;k<i;k++)
3401: {
3402: mael(M,i,k)=lstoi(j%mael(gal,8,k));
3403: j/=mael(gal,8,k);
3404: }
3405: mael(M,i,k++)=lstoi(mael(gal,8,i));
3406: for( ;k<n;k++)
3407: mael(M,i,k)=zero;
3408: }
3409: return M;
3410: }
1.3 ! noro 3411: GEN galoissubgroups(GEN G)
1.1 noro 3412: {
1.3 ! noro 3413: gpmem_t ltop=avma;
! 3414: GEN H;
! 3415: G = checkgal(G);
! 3416: H=cgetg(3,t_VEC);
! 3417: H[1]=G[7];
! 3418: H[2]=G[8];
! 3419: return gerepileupto(ltop,group_subgroups(H));
1.1 noro 3420: }
3421:
1.3 ! noro 3422: GEN galoissubfields(GEN G, long flag, long v)
1.1 noro 3423: {
1.3 ! noro 3424: gpmem_t ltop=avma;
1.1 noro 3425: long i;
1.3 ! noro 3426: GEN L = galoissubgroups(G);
! 3427: long l2 = lg(L);
! 3428: GEN p3 = cgetg(l2, t_VEC);
! 3429: for (i = 1; i < l2; ++i)
! 3430: p3[i] = (long) galoisfixedfield(G, gmael(L,i,1), flag, v);
! 3431: return gerepileupto(ltop,p3);
1.1 noro 3432: }
3433:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>