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