[BACK]Return to galconj.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / src / basemath

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, &gt);
                   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, &gt);
                   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, &gt, 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>