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

Annotation of OpenXM_contrib/pari-2.2/src/basemath/base2.c, Revision 1.2

1.2     ! noro        1: /* $Id: base2.c,v 1.181 2002/09/11 02:31:22 karim Exp $
1.1       noro        2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /*******************************************************************/
                     17: /*                                                                 */
                     18: /*                       MAXIMAL ORDERS                            */
                     19: /*                                                                 */
                     20: /*******************************************************************/
                     21: #include "pari.h"
1.2     ! noro       22: #include "parinf.h"
1.1       noro       23:
1.2     ! noro       24: #define RXQX_rem(x,y,T) RXQX_divrem((x),(y),(T),ONLY_REM)
        !            25: #define FpX_rem(x,y,p) FpX_divres((x),(y),(p),ONLY_REM)
        !            26: extern GEN addone_aux2(GEN x, GEN y);
        !            27: extern GEN addshiftw(GEN x, GEN y, long d);
        !            28: extern GEN gmul_mat_smallvec(GEN x, GEN y);
        !            29: extern GEN hnf_invimage(GEN A, GEN b);
        !            30: extern GEN norm_by_embed(long r1, GEN x);
        !            31: extern GEN ZX_resultant_all(GEN A, GEN B, GEN dB, ulong bound);
        !            32: extern GEN polsym_gen(GEN P, GEN y0, long n, GEN T, GEN N);
        !            33: extern GEN FqX_gcd(GEN P, GEN Q, GEN T, GEN p);
        !            34: extern GEN FqX_factor(GEN x, GEN T, GEN p);
        !            35: extern GEN DDF2(GEN x, long hint);
        !            36: extern GEN eltabstorel(GEN x, GEN T, GEN pol, GEN k);
        !            37: extern GEN element_powid_mod_p(GEN nf, long I, GEN n, GEN p);
        !            38: extern GEN FpVQX_red(GEN z, GEN T, GEN p);
        !            39: extern GEN Fp_factor_irred(GEN P,GEN l, GEN Q);
        !            40: extern GEN RXQX_divrem(GEN x, GEN y, GEN T, GEN *pr);
        !            41: extern GEN RXQX_mul(GEN x, GEN y, GEN T);
        !            42: extern GEN ZY_ZXY_resultant_all(GEN A, GEN B0, long *lambda, GEN *LPRS);
        !            43: extern GEN _ei(long n, long i);
        !            44: extern GEN col_to_ff(GEN x, long v);
        !            45: extern GEN element_mulidid(GEN nf, long i, long j);
        !            46: extern GEN eltmulid_get_table(GEN nf, long i);
        !            47: extern GEN idealaddtoone_i(GEN nf, GEN x, GEN y);
1.1       noro       48: extern GEN mat_to_vecpol(GEN x, long v);
1.2     ! noro       49: extern GEN merge_factor_i(GEN f, GEN g);
        !            50: extern GEN mulmat_pol(GEN A, GEN x);
        !            51: extern GEN nfgcd(GEN P, GEN Q, GEN nf, GEN den);
        !            52: extern GEN pidealprimeinv(GEN nf, GEN x);
1.1       noro       53: extern GEN pol_to_monic(GEN pol, GEN *lead);
                     54: extern GEN quicktrace(GEN x, GEN sym);
1.2     ! noro       55: extern GEN sqr_by_tab(GEN tab, GEN x);
        !            56: extern GEN to_polmod(GEN x, GEN mod);
        !            57: extern GEN unnf_minus_x(GEN x);
        !            58: extern int isrational(GEN x);
        !            59: extern long int_elt_val(GEN nf, GEN x, GEN p, GEN bp, GEN *t);
        !            60:
        !            61: /* FIXME: backward compatibility. Should use the proper nf_* equivalents */
        !            62: #define compat_PARTIAL 1
        !            63: #define compat_ROUND2  2
1.1       noro       64:
                     65: static void
1.2     ! noro       66: allbase_check_args(GEN f, long flag, GEN *dx, GEN *ptw)
1.1       noro       67: {
1.2     ! noro       68:   GEN w = *ptw;
        !            69:
        !            70:   if (DEBUGLEVEL) (void)timer2();
1.1       noro       71:   if (typ(f)!=t_POL) err(notpoler,"allbase");
                     72:   if (degpol(f) <= 0) err(constpoler,"allbase");
1.2     ! noro       73:
        !            74:   *dx = w? factorback(w, NULL): ZX_disc(f);
        !            75:   if (!signe(*dx)) err(talker,"reducible polynomial in allbase");
        !            76:   if (!w) *ptw = auxdecomp(absi(*dx), (flag & nf_PARTIALFACT)? 0: 1);
1.1       noro       77:   if (DEBUGLEVEL) msgtimer("disc. factorisation");
                     78: }
                     79:
                     80: /*******************************************************************/
                     81: /*                                                                 */
                     82: /*                            ROUND 2                              */
                     83: /*                                                                 */
                     84: /*******************************************************************/
                     85: /* companion matrix of unitary polynomial x */
                     86: static GEN
                     87: companion(GEN x) /* cf assmat */
                     88: {
                     89:   long i,j,l;
                     90:   GEN y;
                     91:
                     92:   l=degpol(x)+1; y=cgetg(l,t_MAT);
                     93:   for (j=1; j<l; j++)
                     94:   {
                     95:     y[j] = lgetg(l,t_COL);
                     96:     for (i=1; i<l-1; i++)
                     97:       coeff(y,i,j)=(i+1==j)? un: zero;
                     98:     coeff(y,i,j) = lneg((GEN)x[j+1]);
                     99:   }
                    100:   return y;
                    101: }
                    102:
                    103: /* assume x, y are square integer matrices of same dim. Multiply them */
                    104: static GEN
                    105: mulmati(GEN x, GEN y)
                    106: {
1.2     ! noro      107:   gpmem_t av;
        !           108:   long n = lg(x),i,j,k;
1.1       noro      109:   GEN z = cgetg(n,t_MAT),p1,p2;
                    110:
                    111:   for (j=1; j<n; j++)
                    112:   {
                    113:     z[j] = lgetg(n,t_COL);
                    114:     for (i=1; i<n; i++)
                    115:     {
                    116:       p1=gzero; av=avma;
                    117:       for (k=1; k<n; k++)
                    118:       {
                    119:         p2=mulii(gcoeff(x,i,k),gcoeff(y,k,j));
                    120:         if (p2 != gzero) p1=addii(p1,p2);
                    121:       }
                    122:       coeff(z,i,j)=lpileupto(av,p1);
                    123:     }
                    124:   }
                    125:   return z;
                    126: }
                    127:
                    128: static GEN
1.2     ! noro      129: _mulmati(void *data /*ignored*/, GEN x, GEN y) {
        !           130:   (void)data; return mulmati(x,y);
        !           131: }
        !           132: static GEN
        !           133: _sqrmati(void *data /*ignored*/, GEN x) {
        !           134:   (void)data; return mulmati(x,x);
        !           135: }
        !           136:
        !           137: static GEN
        !           138: powmati(GEN x, GEN n)
1.1       noro      139: {
1.2     ! noro      140:   gpmem_t av = avma;
        !           141:   GEN y = leftright_pow(x, n, NULL, &_sqrmati, &_mulmati);
1.1       noro      142:   return gerepileupto(av,y);
                    143: }
                    144:
                    145: static GEN
                    146: rtran(GEN v, GEN w, GEN q)
                    147: {
1.2     ! noro      148:   gpmem_t av,tetpil;
1.1       noro      149:   GEN p1;
                    150:
                    151:   if (signe(q))
                    152:   {
                    153:     av=avma; p1=gneg(gmul(q,w)); tetpil=avma;
                    154:     return gerepile(av,tetpil,gadd(v,p1));
                    155:   }
                    156:   return v;
                    157: }
                    158:
                    159: /* return (v - qw) mod m (only compute entries k0,..,n)
                    160:  * v and w are expected to have entries smaller than m */
                    161: static GEN
1.2     ! noro      162: mtran(GEN v, GEN w, GEN q, GEN m, GEN mo2, long k0)
1.1       noro      163: {
1.2     ! noro      164:   long k;
1.1       noro      165:   GEN p1;
                    166:
                    167:   if (signe(q))
1.2     ! noro      168:     for (k=lg(v)-1; k >= k0; k--)
1.1       noro      169:     {
1.2     ! noro      170:       gpmem_t av = avma;
1.1       noro      171:       p1 = subii((GEN)v[k], mulii(q,(GEN)w[k]));
1.2     ! noro      172:       p1 = centermodii(p1, m, mo2);
        !           173:       v[k] = lpileuptoint(av, p1);
1.1       noro      174:     }
                    175:   return v;
                    176: }
                    177:
                    178: /* entries of v and w are C small integers */
                    179: static GEN
                    180: mtran_long(GEN v, GEN w, long q, long m, long k0)
                    181: {
                    182:   long k, p1;
                    183:
                    184:   if (q)
                    185:   {
                    186:     for (k=lg(v)-1; k>= k0; k--)
                    187:     {
                    188:       p1 = v[k] - q * w[k];
                    189:       v[k] = p1 % m;
                    190:     }
                    191:   }
                    192:   return v;
                    193: }
                    194:
                    195: /* coeffs of a are C-long integers */
                    196: static void
                    197: rowred_long(GEN a, long rmod)
                    198: {
                    199:   long q,j,k,pro, c = lg(a), r = lg(a[1]);
                    200:
                    201:   for (j=1; j<r; j++)
                    202:   {
                    203:     for (k=j+1; k<c; k++)
                    204:       while (coeff(a,j,k))
                    205:       {
                    206:        q = coeff(a,j,j) / coeff(a,j,k);
                    207:        pro=(long)mtran_long((GEN)a[j],(GEN)a[k],q,rmod, j);
                    208:        a[j]=a[k]; a[k]=pro;
                    209:       }
                    210:     if (coeff(a,j,j) < 0)
                    211:       for (k=j; k<r; k++) coeff(a,k,j)=-coeff(a,k,j);
                    212:     for (k=1; k<j; k++)
                    213:     {
                    214:       q = coeff(a,j,k) / coeff(a,j,j);
                    215:       a[k]=(long)mtran_long((GEN)a[k],(GEN)a[j],q,rmod, k);
                    216:     }
                    217:   }
                    218:   /* don't update the 0s in the last columns */
                    219:   for (j=1; j<r; j++)
                    220:     for (k=1; k<r; k++) coeff(a,j,k) = lstoi(coeff(a,j,k));
                    221: }
                    222:
                    223: static void
                    224: rowred(GEN a, GEN rmod)
                    225: {
                    226:   long j,k,pro, c = lg(a), r = lg(a[1]);
1.2     ! noro      227:   gpmem_t av=avma, lim=stack_lim(av,1);
        !           228:   GEN q, rmodo2 = shifti(rmod,-1);
1.1       noro      229:
                    230:   for (j=1; j<r; j++)
                    231:   {
                    232:     for (k=j+1; k<c; k++)
                    233:       while (signe(gcoeff(a,j,k)))
                    234:       {
1.2     ! noro      235:        q=diviiround(gcoeff(a,j,j),gcoeff(a,j,k));
        !           236:        pro=(long)mtran((GEN)a[j],(GEN)a[k],q,rmod,rmodo2, j);
1.1       noro      237:        a[j]=a[k]; a[k]=pro;
                    238:       }
                    239:     if (signe(gcoeff(a,j,j)) < 0)
                    240:       for (k=j; k<r; k++) coeff(a,k,j)=lnegi(gcoeff(a,k,j));
                    241:     for (k=1; k<j; k++)
                    242:     {
1.2     ! noro      243:       q=diviiround(gcoeff(a,j,k),gcoeff(a,j,j));
        !           244:       a[k]=(long)mtran((GEN)a[k],(GEN)a[j],q,rmod,rmodo2, k);
1.1       noro      245:     }
                    246:     if (low_stack(lim, stack_lim(av,1)))
                    247:     {
                    248:       long j1,k1;
                    249:       GEN p1 = a;
                    250:       if(DEBUGMEM>1) err(warnmem,"rowred j=%ld", j);
                    251:       p1 = gerepilecopy(av,a);
                    252:       for (j1=1; j1<r; j1++)
                    253:         for (k1=1; k1<c; k1++) coeff(a,j1,k1) = coeff(p1,j1,k1);
                    254:     }
                    255:   }
                    256: }
                    257:
                    258: /* Calcule d/x  ou  d est entier et x matrice triangulaire inferieure
1.2     ! noro      259:  * entiere dont les coeff diagonaux divisent d (resultat entier). */
1.1       noro      260: static GEN
1.2     ! noro      261: matinv(GEN x, GEN d)
1.1       noro      262: {
1.2     ! noro      263:   gpmem_t av,av1;
        !           264:   long i,j,k, n = lg(x[1]); /* Warning: lg(x) from ordmax is bogus */
1.1       noro      265:   GEN y,h;
                    266:
1.2     ! noro      267:   y = idmat(n-1);
        !           268:   for (i=1; i<n; i++)
        !           269:     coeff(y,i,i) = (long)diviiexact(d,gcoeff(x,i,i));
1.1       noro      270:   av=avma;
1.2     ! noro      271:   for (i=2; i<n; i++)
1.1       noro      272:     for (j=i-1; j; j--)
                    273:     {
                    274:       for (h=gzero,k=j+1; k<=i; k++)
                    275:       {
                    276:         GEN p1 = mulii(gcoeff(y,i,k),gcoeff(x,k,j));
                    277:         if (p1 != gzero) h=addii(h,p1);
                    278:       }
                    279:       setsigne(h,-signe(h)); av1=avma;
                    280:       coeff(y,i,j) = lpile(av,av1,divii(h,gcoeff(x,j,j)));
                    281:       av = avma;
                    282:     }
                    283:   return y;
                    284: }
                    285:
                    286: static GEN
                    287: ordmax(GEN *cf, GEN p, long epsilon, GEN *ptdelta)
                    288: {
1.2     ! noro      289:   long sp,i,n=lg(cf)-1;
        !           290:   gpmem_t av=avma, av2,limit;
        !           291:   GEN T,T2,Tn,m,v,delta,hard_case_exponent, *w;
1.1       noro      292:   const GEN pp = sqri(p);
1.2     ! noro      293:   const GEN ppo2 = shifti(pp,-1);
1.1       noro      294:   const long pps = (2*expi(pp)+2<BITS_IN_LONG)? pp[2]: 0;
                    295:
                    296:   if (cmpis(p,n) > 0)
                    297:   {
1.2     ! noro      298:     hard_case_exponent = NULL;
1.1       noro      299:     sp = 0; /* gcc -Wall */
                    300:   }
                    301:   else
                    302:   {
                    303:     long k;
                    304:     k = sp = itos(p);
                    305:     i=1; while (k < n) { k *= sp; i++; }
1.2     ! noro      306:     hard_case_exponent = stoi(i);
1.1       noro      307:   }
                    308:   T=cgetg(n+1,t_MAT); for (i=1; i<=n; i++) T[i]=lgetg(n+1,t_COL);
                    309:   T2=cgetg(2*n+1,t_MAT); for (i=1; i<=2*n; i++) T2[i]=lgetg(n+1,t_COL);
                    310:   Tn=cgetg(n*n+1,t_MAT); for (i=1; i<=n*n; i++) Tn[i]=lgetg(n+1,t_COL);
                    311:   v = new_chunk(n+1);
1.2     ! noro      312:   w = (GEN*)new_chunk(n+1);
1.1       noro      313:
                    314:   av2 = avma; limit = stack_lim(av2,1);
                    315:   delta=gun; m=idmat(n);
                    316:
                    317:   for(;;)
                    318:   {
1.2     ! noro      319:     long j, k, h;
        !           320:     gpmem_t av0 = avma;
1.1       noro      321:     GEN t,b,jp,hh,index,p1, dd = sqri(delta), ppdd = mulii(dd,pp);
1.2     ! noro      322:     GEN ppddo2 = shifti(ppdd,-1);
1.1       noro      323:
                    324:     if (DEBUGLEVEL > 3)
                    325:       fprintferr("ROUND2: epsilon = %ld\tavma = %ld\n",epsilon,avma);
                    326:
1.2     ! noro      327:     b=matinv(m,delta);
1.1       noro      328:     for (i=1; i<=n; i++)
                    329:     {
                    330:       for (j=1; j<=n; j++)
                    331:         for (k=1; k<=n; k++)
                    332:         {
                    333:           p1 = j==k? gcoeff(m,i,1): gzero;
                    334:           for (h=2; h<=n; h++)
                    335:           {
                    336:            GEN p2 = mulii(gcoeff(m,i,h),gcoeff(cf[h],j,k));
                    337:             if (p2!=gzero) p1 = addii(p1,p2);
                    338:           }
1.2     ! noro      339:           coeff(T,j,k) = (long)centermodii(p1, ppdd, ppddo2);
1.1       noro      340:         }
                    341:       p1 = mulmati(m, mulmati(T,b));
                    342:       for (j=1; j<=n; j++)
                    343:        for (k=1; k<=n; k++)
1.2     ! noro      344:          coeff(p1,j,k)=(long)centermodii(divii(gcoeff(p1,j,k),dd),pp,ppo2);
1.1       noro      345:       w[i] = p1;
                    346:     }
                    347:
                    348:     if (hard_case_exponent)
                    349:     {
                    350:       for (j=1; j<=n; j++)
                    351:       {
                    352:        for (i=1; i<=n; i++) coeff(T,i,j) = coeff(w[j],1,i);
                    353:        /* ici la boucle en k calcule la puissance p mod p de w[j] */
                    354:        for (k=1; k<sp; k++)
                    355:        {
                    356:          for (i=1; i<=n; i++)
                    357:          {
                    358:            p1 = gzero;
                    359:            for (h=1; h<=n; h++)
                    360:             {
                    361:               GEN p2=mulii(gcoeff(T,h,j),gcoeff(w[j],h,i));
                    362:              if (p2!=gzero) p1 = addii(p1,p2);
                    363:             }
                    364:             v[i] = lmodii(p1, p);
                    365:          }
                    366:          for (i=1; i<=n; i++) coeff(T,i,j)=v[i];
                    367:        }
                    368:       }
                    369:       t = powmati(T, hard_case_exponent);
                    370:     }
                    371:     else
                    372:     {
                    373:       for (i=1; i<=n; i++)
                    374:        for (j=1; j<=n; j++)
                    375:        {
1.2     ! noro      376:           gpmem_t av1 = avma;
1.1       noro      377:           p1 = gzero;
                    378:          for (k=1; k<=n; k++)
                    379:            for (h=1; h<=n; h++)
                    380:            {
                    381:              const GEN r=modii(gcoeff(w[i],k,h),p);
                    382:              const GEN s=modii(gcoeff(w[j],h,k),p);
1.2     ! noro      383:               const GEN p2 = mulii(r,s);
1.1       noro      384:              if (p2!=gzero) p1 = addii(p1,p2);
                    385:            }
                    386:          coeff(T,i,j) = lpileupto(av1,p1);
                    387:        }
                    388:       t = T;
                    389:     }
                    390:
                    391:     if (pps)
                    392:     {
                    393:       long ps = p[2];
                    394:       for (i=1; i<=n; i++)
                    395:         for (j=1; j<=n; j++)
                    396:         {
                    397:           coeff(T2,j,i)=(i==j)? ps: 0;
                    398:           coeff(T2,j,n+i)=smodis(gcoeff(t,i,j),ps);
                    399:         }
1.2     ! noro      400:       rowred_long(T2,pps);
1.1       noro      401:     }
                    402:     else
                    403:     {
                    404:       for (i=1; i<=n; i++)
                    405:         for (j=1; j<=n; j++)
                    406:         {
                    407:           coeff(T2,j,i)=(i==j)? (long)p: zero;
                    408:           coeff(T2,j,n+i)=lmodii(gcoeff(t,i,j),p);
                    409:         }
                    410:       rowred(T2,pp);
                    411:     }
1.2     ! noro      412:     jp=matinv(T2,p);
1.1       noro      413:     if (pps)
                    414:     {
                    415:       for (k=1; k<=n; k++)
                    416:       {
1.2     ! noro      417:         gpmem_t av1=avma;
1.1       noro      418:         t = mulmati(mulmati(jp,w[k]), T2);
                    419:         for (h=i=1; i<=n; i++)
                    420:           for (j=1; j<=n; j++)
                    421:             { coeff(Tn,k,h) = itos(divii(gcoeff(t,i,j), p)) % pps; h++; }
                    422:         avma=av1;
                    423:       }
                    424:       avma = av0;
                    425:       rowred_long(Tn,pps);
                    426:     }
                    427:     else
                    428:     {
                    429:       for (k=1; k<=n; k++)
                    430:       {
                    431:         t = mulmati(mulmati(jp,w[k]), T2);
                    432:         for (h=i=1; i<=n; i++)
                    433:           for (j=1; j<=n; j++)
                    434:             { coeff(Tn,k,h) = ldivii(gcoeff(t,i,j), p); h++; }
                    435:       }
                    436:       rowred(Tn,pp);
                    437:     }
                    438:     for (index=gun,i=1; i<=n; i++)
                    439:       index = mulii(index,gcoeff(Tn,i,i));
                    440:     if (gcmp1(index)) break;
                    441:
1.2     ! noro      442:     m = mulmati(matinv(Tn,index), m);
1.1       noro      443:     hh = delta = mulii(index,delta);
                    444:     for (i=1; i<=n; i++)
                    445:       for (j=1; j<=n; j++)
                    446:         hh = mppgcd(gcoeff(m,i,j),hh);
                    447:     if (!is_pm1(hh))
                    448:     {
                    449:       m = gdiv(m,hh);
                    450:       delta = divii(delta,hh);
                    451:     }
                    452:     epsilon -= 2 * ggval(index,p);
                    453:     if (epsilon < 2) break;
                    454:     if (low_stack(limit,stack_lim(av2,1)))
                    455:     {
                    456:       GEN *gptr[3]; gptr[0]=&m; gptr[1]=&delta;
                    457:       if(DEBUGMEM>1) err(warnmem,"ordmax");
                    458:       gerepilemany(av2, gptr,2);
                    459:     }
                    460:   }
                    461:   {
                    462:     GEN *gptr[2]; gptr[0]=&m; gptr[1]=&delta;
                    463:     gerepilemany(av,gptr,2);
                    464:   }
                    465:   *ptdelta=delta; return m;
                    466: }
                    467:
                    468: /* Input:
                    469:  *  x normalized integral polynomial of degree n, defining K=Q(theta).
                    470:  *
                    471:  *  code 0, 1 or (long)p if we want base, smallbase ou factoredbase (resp.).
                    472:  *  y is GEN *, which will receive the discriminant of K.
                    473:  *
                    474:  * Output
                    475:  *  1) A t_COL whose n components are rationnal polynomials (with degree
                    476:  *     0,1...n-1) : integral basis for K (putting x=theta).
                    477:  *     Rem: common denominator is in da.
                    478:  *
                    479:  *  2) discriminant of K (in *y).
                    480:  */
1.2     ! noro      481: static GEN
        !           482: allbase2(GEN f, int flag, GEN *dx, GEN *dK, GEN *ptw)
1.1       noro      483: {
1.2     ! noro      484:   GEN w,w1,w2,a,pro,at,bt,b,da,db,q, *cf,*gptr[2];
        !           485:   gpmem_t av=avma,tetpil;
        !           486:   long n,h,j,i,k,r,s,t,v,mf;
        !           487:
        !           488:   w = ptw? *ptw: NULL;
        !           489:   allbase_check_args(f,flag,dx, &w);
        !           490:   w1 = (GEN)w[1];
        !           491:   w2 = (GEN)w[2];
1.1       noro      492:   v = varn(f); n = degpol(f); h = lg(w1)-1;
                    493:   cf = (GEN*)cgetg(n+1,t_VEC);
                    494:   cf[2]=companion(f);
                    495:   for (i=3; i<=n; i++) cf[i]=mulmati(cf[2],cf[i-1]);
                    496:
                    497:   a=idmat(n); da=gun;
                    498:   for (i=1; i<=h; i++)
                    499:   {
1.2     ! noro      500:     gpmem_t av1 = avma;
1.1       noro      501:     mf=itos((GEN)w2[i]); if (mf==1) continue;
                    502:     if (DEBUGLEVEL) fprintferr("Treating p^k = %Z^%ld\n",w1[i],mf);
                    503:
                    504:     b=ordmax(cf,(GEN)w1[i],mf,&db);
                    505:     a=gmul(db,a); b=gmul(da,b);
                    506:     da=mulii(db,da);
                    507:     at=gtrans(a); bt=gtrans(b);
                    508:     for (r=n; r; r--)
                    509:       for (s=r; s; s--)
                    510:         while (signe(gcoeff(bt,s,r)))
                    511:         {
1.2     ! noro      512:           q=diviiround(gcoeff(at,s,s),gcoeff(bt,s,r));
1.1       noro      513:           pro=rtran((GEN)at[s],(GEN)bt[r],q);
                    514:           for (t=s-1; t; t--)
                    515:           {
1.2     ! noro      516:             q=diviiround(gcoeff(at,t,s),gcoeff(at,t,t));
1.1       noro      517:             pro=rtran(pro,(GEN)at[t],q);
                    518:           }
                    519:           at[s]=bt[r]; bt[r]=(long)pro;
                    520:         }
                    521:     for (j=n; j; j--)
                    522:     {
                    523:       for (k=1; k<j; k++)
                    524:       {
                    525:         while (signe(gcoeff(at,j,k)))
                    526:         {
1.2     ! noro      527:           q=diviiround(gcoeff(at,j,j),gcoeff(at,j,k));
1.1       noro      528:           pro=rtran((GEN)at[j],(GEN)at[k],q);
                    529:           at[j]=at[k]; at[k]=(long)pro;
                    530:         }
                    531:       }
                    532:       if (signe(gcoeff(at,j,j))<0)
                    533:         for (k=1; k<=j; k++) coeff(at,k,j)=lnegi(gcoeff(at,k,j));
                    534:       for (k=j+1; k<=n; k++)
                    535:       {
1.2     ! noro      536:         q=diviiround(gcoeff(at,j,k),gcoeff(at,j,j));
1.1       noro      537:         at[k]=(long)rtran((GEN)at[k],(GEN)at[j],q);
                    538:       }
                    539:     }
                    540:     for (j=2; j<=n; j++)
                    541:       if (egalii(gcoeff(at,j,j), gcoeff(at,j-1,j-1)))
                    542:       {
                    543:         coeff(at,1,j)=zero;
                    544:         for (k=2; k<=j; k++) coeff(at,k,j)=coeff(at,k-1,j-1);
                    545:       }
                    546:     tetpil=avma; a=gtrans(at);
                    547:     {
1.2     ! noro      548:       GEN *gptr[2];
1.1       noro      549:       da = icopy(da); gptr[0]=&a; gptr[1]=&da;
                    550:       gerepilemanysp(av1,tetpil,gptr,2);
                    551:     }
                    552:   }
1.2     ! noro      553:   *dK = *dx;
1.1       noro      554:   for (j=1; j<=n; j++)
1.2     ! noro      555:     *dK = diviiexact(mulii(*dK,sqri(gcoeff(a,j,j))), sqri(da));
        !           556:   tetpil=avma; *dK = icopy(*dK);
1.1       noro      557:   at=cgetg(n+1,t_VEC); v=varn(f);
                    558:   for (k=1; k<=n; k++)
                    559:   {
                    560:     q=cgetg(k+2,t_POL); at[k]=(long)q;
                    561:     q[1] = evalsigne(1) | evallgef(2+k) | evalvarn(v);
1.2     ! noro      562:     for (j=1; j<=k; j++) q[j+1] = ldiv(gcoeff(a,k,j),da);
1.1       noro      563:   }
1.2     ! noro      564:   gptr[0] = &at; gptr[1] = dK;
1.1       noro      565:   gerepilemanysp(av,tetpil,gptr,2);
                    566:   return at;
                    567: }
                    568:
                    569: GEN
1.2     ! noro      570: base2(GEN x, GEN *pdK) { return nfbasis(x, pdK, compat_ROUND2, NULL); }
1.1       noro      571:
                    572: GEN
1.2     ! noro      573: discf2(GEN x) { return nfdiscf0(x, compat_ROUND2, NULL); }
1.1       noro      574:
                    575: /*******************************************************************/
                    576: /*                                                                 */
                    577: /*                            ROUND 4                              */
                    578: /*                                                                 */
                    579: /*******************************************************************/
                    580:
                    581: GEN nilord(GEN p,GEN fx,long mf,GEN gx,long flag);
                    582: GEN Decomp(GEN p,GEN f,long mf,GEN theta,GEN chi,GEN nu,long r);
                    583: static GEN dbasis(GEN p, GEN f, long mf, GEN alpha, GEN U);
                    584: static GEN maxord(GEN p,GEN f,long mf);
                    585: static GEN testb2(GEN p,GEN fa,long Fa,GEN theta,GEN pmf,long Ft,GEN ns);
                    586: static GEN testc2(GEN p,GEN fa,GEN pmr,GEN pmf,GEN alph2,
                    587:                  long Ea,GEN thet2,long Et,GEN ns);
                    588:
                    589: static int
                    590: fnz(GEN x,long j)
                    591: {
                    592:   long i;
                    593:   for (i=1; i<j; i++)
                    594:     if (signe(x[i])) return 0;
                    595:   return 1;
                    596: }
                    597:
1.2     ! noro      598: /* return list u[i], 2 by 2 coprime with the same prime divisors as ab */
        !           599: static GEN
        !           600: get_coprimes(GEN a, GEN b)
1.1       noro      601: {
1.2     ! noro      602:   long i, k = 1;
        !           603:   GEN u = cgetg(3, t_VEC);
        !           604:   u[1] = (long)a;
        !           605:   u[2] = (long)b;
        !           606:   /* u1,..., uk 2 by 2 coprime */
        !           607:   while (k+1 < lg(u))
        !           608:   {
        !           609:     GEN d, c = (GEN)u[k+1];
        !           610:     if (is_pm1(c)) { k++; continue; }
        !           611:     for (i=1; i<=k; i++)
        !           612:     {
        !           613:       if (is_pm1(u[i])) continue;
        !           614:       d = mppgcd(c, (GEN)u[i]);
        !           615:       if (d == gun) continue;
        !           616:       c = diviiexact(c, d);
        !           617:       u[i] = (long)diviiexact((GEN)u[i], d);
        !           618:       u = concatsp(u, d);
        !           619:     }
        !           620:     u[++k] = (long)c;
        !           621:   }
        !           622:   for (i = k = 1; i < lg(u); i++)
        !           623:     if (!is_pm1(u[i])) u[k++] = u[i];
        !           624:   setlg(u, k); return u;
        !           625: }
        !           626:
        !           627: /* return integer basis. Set dK = disc(K), dx = disc(f), w (possibly partial)
        !           628:  * factorization of dK. *ptw can be set by the caller, in which case it is
        !           629:  * taken to be the factorization of disc(f), then overwritten
        !           630:  * [no consistency check] */
        !           631: GEN
        !           632: allbase(GEN f, int flag, GEN *dx, GEN *dK, GEN *index, GEN *ptw)
        !           633: {
        !           634:   GEN w, w1, w2, a, da, p1, ordmax;
        !           635:   long n, lw, i, j, k, l;
        !           636:
        !           637:   if (flag & nf_ROUND2) return allbase2(f,flag,dx,dK,ptw);
        !           638:   w = ptw? *ptw: NULL;
        !           639:   allbase_check_args(f, flag, dx, &w);
        !           640:   w1 = (GEN)w[1];
        !           641:   w2 = (GEN)w[2];
        !           642:   n = degpol(f); lw = lg(w1);
        !           643:   ordmax = cgetg(1, t_VEC);
        !           644:   /* "complete" factorization first */
        !           645:   for (i=1; i<lw; i++)
        !           646:   {
        !           647:     long mf = itos((GEN)w2[i]);
        !           648:     if (mf == 1) { ordmax = concatsp(ordmax, gun); continue; }
        !           649:
        !           650:     CATCH(invmoder) { /* caught false prime, update factorization */
        !           651:       GEN x = (GEN)global_err_data;
        !           652:       GEN p = mppgcd((GEN)x[1], (GEN)x[2]);
        !           653:       GEN N, u;
        !           654:       if (DEBUGLEVEL) err(warner,"impossible inverse: %Z", x);
        !           655:
        !           656:       u = get_coprimes(p, diviiexact((GEN)x[1],p));
        !           657:       l = lg(u);
        !           658:       /* no small factors, but often a prime power */
        !           659:       for (k = 1; k < l; k++) u[k] = coeff(auxdecomp((GEN)u[k], 2),1,1);
        !           660:
        !           661:       w1[i] = u[1];
        !           662:       w1 = concatsp(w1, vecextract_i(u, 2, l-1));
        !           663:       N = *dx;
        !           664:       w2[i] = lstoi(pvaluation(N, (GEN)w1[i], &N));
        !           665:       k  = lw;
        !           666:       lw = lg(w1);
        !           667:       for ( ; k < lw; k++) w2[k] = lstoi(pvaluation(N, (GEN)w1[k], &N));
        !           668:     } RETRY {
        !           669:       if (DEBUGLEVEL) fprintferr("Treating p^k = %Z^%ld\n",w1[i],mf);
        !           670:       ordmax = concatsp(ordmax, _vec( maxord((GEN)w1[i],f,mf) ));
        !           671:     } ENDCATCH;
        !           672:   }
1.1       noro      673:
                    674:   a = NULL; /* gcc -Wall */
1.2     ! noro      675:   da = NULL;
        !           676:   for (i=1; i<lw; i++)
1.1       noro      677:   {
1.2     ! noro      678:     GEN db, b = (GEN)ordmax[i];
        !           679:     if (b == gun) continue;
        !           680:     db = gun;
1.1       noro      681:     for (j=1; j<=n; j++)
                    682:     {
                    683:       p1 = denom(gcoeff(b,j,j));
                    684:       if (cmpii(p1,db) > 0) db = p1;
                    685:     }
1.2     ! noro      686:     if (db == gun) continue;
        !           687:
        !           688:     /* db = denom(diag(b)), (da,db) = 1 */
        !           689:     b = Q_muli_to_int(b,db);
        !           690:     if (!da) { da = db; a = b; }
        !           691:     else
        !           692:     {
        !           693:       j=1; while (j<=n && fnz((GEN)a[j],j) && fnz((GEN)b[j],j)) j++;
        !           694:       b = gmul(da,b);
        !           695:       a = gmul(db,a); da = mulii(da,db);
        !           696:       k = j-1; p1 = cgetg(2*n-k+1,t_MAT);
        !           697:       for (j=1; j<=k; j++)
        !           698:       {
        !           699:         p1[j] = a[j];
        !           700:         coeff(p1,j,j) = lmppgcd(gcoeff(a,j,j),gcoeff(b,j,j));
        !           701:       }
        !           702:       for (  ; j<=n;     j++) p1[j] = a[j];
        !           703:       for (  ; j<=2*n-k; j++) p1[j] = b[j+k-n];
        !           704:       a = hnfmodid(p1, da);
1.1       noro      705:     }
1.2     ! noro      706:     if (DEBUGLEVEL>5) fprintferr("Result for prime %Z is:\n%Z\n",w1[i],b);
1.1       noro      707:   }
1.2     ! noro      708:   *dK = *dx;
1.1       noro      709:   if (da)
                    710:   {
1.2     ! noro      711:     *index = diviiexact(da, gcoeff(a,1,1));
        !           712:     for (j=2; j<=n; j++) *index = mulii(*index, diviiexact(da, gcoeff(a,j,j)));
        !           713:     *dK = diviiexact(*dK, sqri(*index));
1.1       noro      714:     for (j=n-1; j; j--)
                    715:       if (cmpis(gcoeff(a,j,j),2) > 0)
                    716:       {
1.2     ! noro      717:         p1 = shifti(gcoeff(a,j,j),-1);
1.1       noro      718:         for (k=j+1; k<=n; k++)
                    719:           if (cmpii(gcoeff(a,j,k),p1) > 0)
                    720:             for (l=1; l<=j; l++)
1.2     ! noro      721:               coeff(a,l,k) = lsubii(gcoeff(a,l,k),gcoeff(a,l,j));
1.1       noro      722:       }
1.2     ! noro      723:     a = gdiv(a, da);
1.1       noro      724:   }
1.2     ! noro      725:   else
1.1       noro      726:   {
1.2     ! noro      727:     *index = gun;
        !           728:     a = idmat(n);
1.1       noro      729:   }
1.2     ! noro      730:
        !           731:   if (ptw)
1.1       noro      732:   {
1.2     ! noro      733:     long lfa = 1;
        !           734:     GEN W1, W2, D = *dK;
        !           735:
        !           736:     w = cgetg(3,t_MAT);
        !           737:     W1 = cgetg(lw, t_COL); w[1] = (long)W1;
        !           738:     W2 = cgetg(lw, t_COL); w[2] = (long)W2;
        !           739:     for (j=1; j<lw; j++)
1.1       noro      740:     {
1.2     ! noro      741:       k = pvaluation(D, (GEN)w1[j], &D);
        !           742:       if (k) { W1[lfa] = w1[j]; W2[lfa] = lstoi(k); lfa++; }
1.1       noro      743:     }
1.2     ! noro      744:     setlg(W1, lfa);
        !           745:     setlg(W2, lfa); *ptw = w;
1.1       noro      746:   }
1.2     ! noro      747:   return mat_to_vecpol(a, varn(f));
1.1       noro      748: }
                    749:
                    750: static GEN
                    751: update_fact(GEN x, GEN f)
                    752: {
                    753:   GEN e,q,d = ZX_disc(x), g = cgetg(3, t_MAT), p = (GEN)f[1];
                    754:   long iq,i,k,l;
                    755:   if (typ(f)!=t_MAT || lg(f)!=3)
                    756:     err(talker,"not a factorisation in nfbasis");
                    757:   l = lg(p);
                    758:   q = cgetg(l,t_COL); g[1]=(long)q;
                    759:   e = cgetg(l,t_COL); g[2]=(long)e; iq = 1;
                    760:   for (i=1; i<l; i++)
                    761:   {
                    762:     k = pvaluation(d, (GEN)p[i], &d);
1.2     ! noro      763:     if (k) { q[iq] = p[i]; e[iq] = lstoi(k); iq++; }
1.1       noro      764:   }
                    765:   setlg(q,iq); setlg(e,iq);
                    766:   return merge_factor_i(decomp(d), g);
                    767: }
                    768:
                    769: static GEN
1.2     ! noro      770: unscale_vecpol(GEN v, GEN h)
1.1       noro      771: {
1.2     ! noro      772:   long i, l;
        !           773:   GEN w;
        !           774:   if (!h) return v;
        !           775:   l = lg(v); w = cgetg(l, typ(v));
        !           776:   for (i=1; i<l; i++) w[i] = (long)unscale_pol((GEN)v[i], h);
        !           777:   return w;
        !           778: }
1.1       noro      779:
1.2     ! noro      780: /* FIXME: have to deal with compatibility flags */
        !           781: static void
        !           782: _nfbasis(GEN x0, long flag, GEN fa, GEN *pbas, GEN *pdK)
        !           783: {
        !           784:   GEN x, dx, dK, basis, lead, index;
        !           785:   long fl = 0;
1.1       noro      786:
1.2     ! noro      787:   if (typ(x0)!=t_POL) err(typeer,"nfbasis");
        !           788:   if (!degpol(x0)) err(zeropoler,"nfbasis");
        !           789:   check_pol_int(x0, "nfbasis");
1.1       noro      790:
1.2     ! noro      791:   x = pol_to_monic(x0, &lead);
        !           792:   if (fa && gcmp0(fa)) fa = NULL; /* compatibility. NULL is the proper arg */
        !           793:   if (fa && lead) fa = update_fact(x, fa);
        !           794:   if (flag & compat_PARTIAL) fl |= nf_PARTIALFACT;
        !           795:   if (flag & compat_ROUND2)  fl |= nf_ROUND2;
        !           796:   basis = allbase(x, fl, &dx, &dK, &index, &fa);
        !           797:   if (pbas) *pbas = unscale_vecpol(basis, lead);
        !           798:   if (pdK)  *pdK = dK;
1.1       noro      799: }
                    800:
                    801: GEN
1.2     ! noro      802: nfbasis(GEN x, GEN *pdK, long flag, GEN fa)
1.1       noro      803: {
1.2     ! noro      804:   gpmem_t av = avma;
        !           805:   GEN bas; _nfbasis(x, flag, fa, &bas, pdK);
        !           806:   gerepileall(av, 2, &bas, pdK); return bas;
1.1       noro      807: }
                    808:
                    809: GEN
1.2     ! noro      810: nfbasis0(GEN x, long flag, GEN fa)
1.1       noro      811: {
1.2     ! noro      812:   gpmem_t av = avma;
        !           813:   GEN bas; _nfbasis(x, flag, fa, &bas, NULL);
        !           814:   return gerepilecopy(av, bas);
1.1       noro      815: }
                    816:
                    817: GEN
1.2     ! noro      818: nfdiscf0(GEN x, long flag, GEN fa)
1.1       noro      819: {
1.2     ! noro      820:   gpmem_t av = avma;
        !           821:   GEN dK; _nfbasis(x, flag, fa, NULL, &dK);
        !           822:   return gerepilecopy(av, dK);
1.1       noro      823: }
                    824:
                    825: GEN
1.2     ! noro      826: base(GEN x, GEN *pdK) { return nfbasis(x, pdK, 0, NULL); }
1.1       noro      827:
                    828: GEN
1.2     ! noro      829: smallbase(GEN x, GEN *pdK) { return nfbasis(x, pdK, compat_PARTIAL, NULL); }
1.1       noro      830:
                    831: GEN
1.2     ! noro      832: factoredbase(GEN x, GEN fa, GEN *pdK) { return nfbasis(x, pdK, 0, fa); }
1.1       noro      833:
                    834: GEN
1.2     ! noro      835: discf(GEN x) { return nfdiscf0(x, 0, NULL); }
1.1       noro      836:
                    837: GEN
1.2     ! noro      838: smalldiscf(GEN x) { return nfdiscf0(x, nf_PARTIALFACT, NULL); }
1.1       noro      839:
                    840: GEN
1.2     ! noro      841: factoreddiscf(GEN x, GEN fa) { return nfdiscf0(x, 0, fa); }
1.1       noro      842:
                    843:
                    844: /* return U if Z[alpha] is not maximal or 2*dU < m-1; else return NULL */
                    845: static GEN
                    846: dedek(GEN f, long mf, GEN p,GEN g)
                    847: {
                    848:   GEN k,h;
                    849:   long dk;
                    850:
                    851:   h = FpX_div(f,g,p);
                    852:   k = gdivexact(gadd(f, gneg_i(gmul(g,h))), p);
                    853:   k = FpX_gcd(k, FpX_gcd(g,h, p), p);
                    854:
                    855:   dk = degpol(k);
1.2     ! noro      856:   if (DEBUGLEVEL>2)
        !           857:   {
        !           858:     fprintferr("  dedek: gcd has degree %ld\n", dk);
        !           859:     if (DEBUGLEVEL>5) fprintferr("initial parameters p=%Z,\n  f=%Z\n",p,f);
        !           860:   }
1.1       noro      861:   if (2*dk >= mf-1) return FpX_div(f,k,p);
                    862:   return dk? (GEN)NULL: f;
                    863: }
                    864:
                    865: /* p-maximal order of Af; mf = v_p(Disc(f)) */
                    866: static GEN
                    867: maxord(GEN p,GEN f,long mf)
                    868: {
1.2     ! noro      869:   const gpmem_t av = avma;
        !           870:   long j,r, flw = (cmpsi(degpol(f),p) < 0);
1.1       noro      871:   GEN w,g,h,res;
                    872:
                    873:   if (flw)
                    874:   {
                    875:     h = NULL; r = 0; /* gcc -Wall */
                    876:     g = FpX_div(f, FpX_gcd(f,derivpol(f), p), p);
                    877:   }
                    878:   else
                    879:   {
                    880:     w=(GEN)factmod(f,p)[1]; r=lg(w)-1;
                    881:     g = h = lift_intern((GEN)w[r]); /* largest factor */
                    882:     for (j=1; j<r; j++) g = FpX_red(gmul(g, lift_intern((GEN)w[j])), p);
                    883:   }
                    884:   res = dedek(f,mf,p,g);
                    885:   if (res)
                    886:     res = dbasis(p,f,mf,polx[varn(f)],res);
                    887:   else
                    888:   {
                    889:     if (flw) { w=(GEN)factmod(f,p)[1]; r=lg(w)-1; h=lift_intern((GEN)w[r]); }
                    890:     res = (r==1)? nilord(p,f,mf,h,0): Decomp(p,f,mf,polx[varn(f)],f,h,0);
                    891:   }
                    892:   return gerepileupto(av,res);
                    893: }
                    894:
                    895: /* do a centermod on integer or rational number */
                    896: static GEN
                    897: polmodiaux(GEN x, GEN y, GEN ys2)
                    898: {
1.2     ! noro      899:   if (typ(x)!=t_INT) x = mulii((GEN)x[1], mpinvmod((GEN)x[2],y));
        !           900:   return centermodii(x,y,ys2);
1.1       noro      901: }
                    902:
                    903: /* x polynomial with integer or rational coeff. Reduce them mod y IN PLACE */
                    904: GEN
                    905: polmodi(GEN x, GEN y)
                    906: {
                    907:   long lx=lgef(x), i;
                    908:   GEN ys2 = shifti(y,-1);
                    909:   for (i=2; i<lx; i++) x[i]=(long)polmodiaux((GEN)x[i],y,ys2);
                    910:   return normalizepol_i(x, lx);
                    911: }
                    912:
                    913: /* same but not in place */
                    914: GEN
                    915: polmodi_keep(GEN x, GEN y)
                    916: {
                    917:   long lx=lgef(x), i;
                    918:   GEN ys2 = shifti(y,-1);
                    919:   GEN z = cgetg(lx,t_POL);
                    920:   for (i=2; i<lx; i++) z[i]=(long)polmodiaux((GEN)x[i],y,ys2);
                    921:   z[1]=x[1]; return normalizepol_i(z, lx);
                    922: }
                    923:
                    924: static GEN
1.2     ! noro      925: shiftpol(GEN x, long v)
        !           926: {
        !           927:   x = addshiftw(x, zeropol(v), 1);
        !           928:   setvarn(x,v); return x;
        !           929: }
        !           930:
        !           931: /* Sylvester's matrix, mod p^m (assumes f1 monic) */
        !           932: static GEN
        !           933: sylpm(GEN f1,GEN f2,GEN pm)
        !           934: {
        !           935:   long n,j,v=varn(f1);
        !           936:   GEN a,h;
        !           937:
        !           938:   n=degpol(f1); a=cgetg(n+1,t_MAT);
        !           939:   h = FpX_res(f2,f1,pm);
        !           940:   for (j=1;; j++)
        !           941:   {
        !           942:     a[j] = (long)pol_to_vec(h,n);
        !           943:     if (j == n) break;
        !           944:     h = FpX_res(shiftpol(h,v),f1,pm);
        !           945:   }
        !           946:   return hnfmodid(a,pm);
        !           947: }
        !           948:
        !           949: /* polynomial gcd mod p^m (assumes f1 monic) */
        !           950: GEN
        !           951: gcdpm(GEN f1,GEN f2,GEN pm)
        !           952: {
        !           953:   gpmem_t av=avma,tetpil;
        !           954:   long n,c,v=varn(f1);
        !           955:   GEN a,col;
        !           956:
        !           957:   n=degpol(f1); a=sylpm(f1,f2,pm);
        !           958:   for (c=1; c<=n; c++)
        !           959:     if (signe(resii(gcoeff(a,c,c),pm))) break;
        !           960:   if (c > n) { avma=av; return zeropol(v); }
        !           961:
        !           962:   col = gdiv((GEN)a[c], gcoeff(a,c,c)); tetpil=avma;
        !           963:   return gerepile(av,tetpil, gtopolyrev(col,v));
        !           964: }
        !           965:
        !           966: /* reduced resultant mod p^m (assumes x monic) */
        !           967: GEN
        !           968: respm(GEN x,GEN y,GEN pm)
        !           969: {
        !           970:   gpmem_t av = avma;
        !           971:   GEN p1 = sylpm(x,y,pm);
        !           972:
        !           973:   p1 = gcoeff(p1,1,1);
        !           974:   if (egalii(p1,pm)) { avma = av; return gzero; }
        !           975:   return gerepileuptoint(av, icopy(p1));
        !           976: }
        !           977:
        !           978: static GEN
1.1       noro      979: dbasis(GEN p, GEN f, long mf, GEN alpha, GEN U)
                    980: {
1.2     ! noro      981:   long n=degpol(f),dU,i;
1.1       noro      982:   GEN b,ha,pd,pdp;
                    983:
                    984:   if (n == 1) return gscalmat(gun, 1);
1.2     ! noro      985:   if (DEBUGLEVEL>5)
1.1       noro      986:   {
1.2     ! noro      987:     fprintferr("  entering Dedekind Basis with parameters p=%Z\n",p);
        !           988:     fprintferr("  f = %Z,\n  alpha = %Z\n",f,alpha);
1.1       noro      989:   }
1.2     ! noro      990:   ha = pd = gpowgs(p,mf/2); pdp = mulii(pd,p);
1.1       noro      991:   dU = typ(U)==t_POL? degpol(U): 0;
                    992:   b = cgetg(n,t_MAT); /* Z[a] + U/p Z[a] is maximal */
                    993:   /* skip first column = gscalcol(pd,n) */
1.2     ! noro      994:   for (i=1; i<n; i++)
1.1       noro      995:   {
1.2     ! noro      996:     if (i == dU)
1.1       noro      997:     {
1.2     ! noro      998:       ha = gdiv(gmul(pd,RX_RXQ_compo(U,alpha,f)),p);
1.1       noro      999:       ha = polmodi(ha,pdp);
                   1000:     }
                   1001:     else
                   1002:     {
1.2     ! noro     1003:       GEN d, mod;
1.1       noro     1004:       ha = gmul(ha,alpha);
1.2     ! noro     1005:       ha = Q_remove_denom(ha, &d);
        !          1006:       mod = d? mulii(pdp,d): pdp;
1.1       noro     1007:       ha = FpX_res(ha, f, mod);
1.2     ! noro     1008:       if (d) ha = gdivexact(ha,d);
1.1       noro     1009:     }
1.2     ! noro     1010:     b[i] = (long)pol_to_vec(ha,n);
1.1       noro     1011:   }
                   1012:   b = hnfmodid(b,pd);
                   1013:   if (DEBUGLEVEL>5) fprintferr("  new order: %Z\n",b);
1.2     ! noro     1014:   return gdiv(b, pd);
1.1       noro     1015: }
                   1016:
                   1017: static GEN
                   1018: get_partial_order_as_pols(GEN p, GEN f)
                   1019: {
1.2     ! noro     1020:   GEN b = maxord(p,f, ggval(ZX_disc(f),p));
        !          1021:   return mat_to_vecpol(b, varn(f));
        !          1022: }
        !          1023:
        !          1024: long
        !          1025: FpX_val(GEN x0, GEN t, GEN p, GEN *py)
        !          1026: {
        !          1027:   long k;
        !          1028:   GEN r, y, x = x0;
1.1       noro     1029:
1.2     ! noro     1030:   for (k=0; ; k++)
        !          1031:   {
        !          1032:     y = FpX_divres(x, t, p, &r);
        !          1033:     if (signe(r)) break;
        !          1034:     x = y;
1.1       noro     1035:   }
1.2     ! noro     1036:   *py = x; return k;
        !          1037: }
        !          1038:
        !          1039: /* e in Qp, f i Zp. Return r = e mod (f, pk) */
        !          1040: static GEN
        !          1041: QpX_mod(GEN e, GEN f, GEN pk)
        !          1042: {
        !          1043:   GEN mod, d;
        !          1044:   e = Q_remove_denom(e, &d);
        !          1045:   mod = d? mulii(pk,d): pk;
        !          1046:   e = FpX_res(e, centermod(f, mod), mod);
        !          1047:   e = FpX_center(e, mod);
        !          1048:   if (d) e = gdiv(e, d);
        !          1049:   return e;
1.1       noro     1050: }
                   1051:
                   1052: /* if flag != 0, factorization to precision r (maximal order otherwise) */
                   1053: GEN
                   1054: Decomp(GEN p,GEN f,long mf,GEN theta,GEN chi,GEN nu,long flag)
                   1055: {
1.2     ! noro     1056:   GEN fred,res,pr,pk,ph,pdr,b1,b2,a,e,f1,f2;
1.1       noro     1057:
                   1058:   if (DEBUGLEVEL>2)
                   1059:   {
                   1060:     fprintferr("  entering Decomp ");
                   1061:     if (DEBUGLEVEL>5)
                   1062:     {
                   1063:       fprintferr("with parameters: p=%Z, expo=%ld\n",p,mf);
                   1064:       if (flag) fprintferr("precision = %ld\n",flag);
                   1065:       fprintferr("  f=%Z",f);
                   1066:     }
                   1067:     fprintferr("\n");
                   1068:   }
1.2     ! noro     1069:
        !          1070:   (void)FpX_val(chi, nu, p, &b1); /* nu irreducible mod p */
        !          1071:   b2 = FpX_div(chi, b1, p);
        !          1072:   a = FpX_mul(FpXQ_inv(b2, b1, p), b2, p);
        !          1073:   pdr = respm(f, derivpol(f), gpowgs(p,mf+1));
        !          1074:   e = RX_RXQ_compo(a, theta, f);
1.1       noro     1075:   e = gdiv(polmodi(gmul(pdr,e), mulii(pdr,p)),pdr);
                   1076:
                   1077:   pr = flag? gpowgs(p,flag): mulii(p,sqri(pdr));
1.2     ! noro     1078:   pk = p; ph = mulii(pdr,pr);
1.1       noro     1079:   /* E(t) - e(t) belongs to p^k Op, which is contained in p^(k-df)*Zp[xi] */
                   1080:   while (cmpii(pk,ph) < 0)
1.2     ! noro     1081:   { /* e <-- e^2(3-2e) mod p^2k */
        !          1082:     pk = sqri(pk);
1.1       noro     1083:     e = gmul(gsqr(e), gsubsg(3,gmul2n(e,1)));
1.2     ! noro     1084:     e = QpX_mod(e, f, pk);
1.1       noro     1085:   }
1.2     ! noro     1086:   fred = centermod(f, ph);
        !          1087:   f1 = gcdpm(fred, gmul(pdr,gsubsg(1,e)), ph);
        !          1088:   fred = centermod(fred, pr); /* pr | ph */
        !          1089:   f1 = centermod(f1, pr);
        !          1090:   f2 = FpX_div(fred,f1, pr);
        !          1091:   f2 = FpX_center(f2, pr);
1.1       noro     1092:
1.2     ! noro     1093:   if (DEBUGLEVEL>5)
1.1       noro     1094:   {
                   1095:     fprintferr("  leaving Decomp");
1.2     ! noro     1096:     fprintferr(" with parameters: f1 = %Z\nf2 = %Z\ne = %Z\n\n", f1,f2,e);
1.1       noro     1097:   }
                   1098:
                   1099:   if (flag)
                   1100:   {
1.2     ! noro     1101:     b1 = factorpadic4(f1,p,flag);
        !          1102:     b2 = factorpadic4(f2,p,flag); res = cgetg(3,t_MAT);
        !          1103:     res[1] = (long)concatsp((GEN)b1[1],(GEN)b2[1]);
        !          1104:     res[2] = (long)concatsp((GEN)b1[2],(GEN)b2[2]); return res;
1.1       noro     1105:   }
                   1106:   else
                   1107:   {
1.2     ! noro     1108:     GEN ib1, ib2;
        !          1109:     long n, n1, n2, i;
        !          1110:     ib1 = get_partial_order_as_pols(p,f1); n1 = lg(ib1)-1;
        !          1111:     ib2 = get_partial_order_as_pols(p,f2); n2 = lg(ib2)-1;
        !          1112:     n = n1+n2;
        !          1113:     res = cgetg(n+1, t_VEC);
1.1       noro     1114:     for (i=1; i<=n1; i++)
1.2     ! noro     1115:       res[i] = (long)QpX_mod(gmul(gmul(pdr,(GEN)ib1[i]),e), f, pdr);
        !          1116:     e = gsubsg(1,e); ib2 -= n1;
        !          1117:     for (   ; i<=n; i++)
        !          1118:       res[i] = (long)QpX_mod(gmul(gmul(pdr,(GEN)ib2[i]),e), f, pdr);
        !          1119:     res = vecpol_to_mat(res, n);
        !          1120:     return gdiv(hnfmodid(res,pdr), pdr); /* normalized integral basis */
1.1       noro     1121:   }
                   1122: }
                   1123:
                   1124: /* minimum extension valuation: res[0]/res[1] (both are longs) */
1.2     ! noro     1125: static void
        !          1126: vstar(GEN p,GEN h, long *L, long *E)
1.1       noro     1127: {
                   1128:   long m,first,j,k,v,w;
                   1129:
                   1130:   m=degpol(h); first=1; k=1; v=0;
                   1131:   for (j=1; j<=m; j++)
                   1132:     if (! gcmp0((GEN)h[m-j+2]))
                   1133:     {
                   1134:       w = ggval((GEN)h[m-j+2],p);
                   1135:       if (first || w*k < v*j) { v=w; k=j; }
                   1136:       first=0;
                   1137:     }
                   1138:   m = cgcd(v,k);
1.2     ! noro     1139:   *L = v/m;
        !          1140:   *E = k/m;
1.1       noro     1141: }
                   1142:
                   1143: /* reduce the element elt modulo rd, taking first care of the denominators */
                   1144: static GEN
                   1145: redelt(GEN elt, GEN rd, GEN pd)
                   1146: {
                   1147:   GEN den, nelt, nrd, relt;
                   1148:
1.2     ! noro     1149:   den  = ggcd(Q_denom(elt), pd);
1.1       noro     1150:   nelt = gmul(den, elt);
                   1151:   nrd  = gmul(den, rd);
                   1152:
                   1153:   if (typ(elt) == t_POL)
                   1154:     relt = polmodi(nelt, nrd);
                   1155:   else
                   1156:     relt = centermod(nelt, nrd);
                   1157:
                   1158:   return gdiv(relt, den);
                   1159: }
                   1160:
                   1161: /* compute the Newton sums of g(x) mod pp from its coefficients */
                   1162: GEN
                   1163: polsymmodpp(GEN g, GEN pp)
                   1164: {
1.2     ! noro     1165:   gpmem_t av1, av2;
        !          1166:   long d = degpol(g), i, k;
1.1       noro     1167:   GEN s , y;
                   1168:
1.2     ! noro     1169:   y = cgetg(d + 1, t_COL);
1.1       noro     1170:   y[1] = lstoi(d);
                   1171:   for (k = 1; k < d; k++)
                   1172:   {
1.2     ! noro     1173:     av1 = avma;
1.1       noro     1174:     s = centermod(gmulsg(k, polcoeff0(g,d-k,-1)), pp);
                   1175:     for (i = 1; i < k; i++)
                   1176:       s = gadd(s, gmul((GEN)y[k-i+1], polcoeff0(g,d-i,-1)));
1.2     ! noro     1177:     av2 = avma;
1.1       noro     1178:     y[k + 1] = lpile(av1, av2, centermod(gneg(s), pp));
                   1179:   }
                   1180:
                   1181:   return y;
                   1182: }
                   1183:
                   1184: /* no GC */
                   1185: static GEN
                   1186: manage_cache(GEN chi, GEN pp, GEN ns)
                   1187: {
                   1188:   long j, n = degpol(chi);
                   1189:   GEN ns2, npp = (GEN)ns[n+1];
                   1190:
                   1191:   if (gcmp(pp, npp) > 0)
                   1192:   {
                   1193:     if (DEBUGLEVEL > 4)
                   1194:       fprintferr("newtonsums: result too large to fit in cache\n");
1.2     ! noro     1195:     return polsymmodpp(chi, pp);
1.1       noro     1196:   }
                   1197:
                   1198:   if (!signe((GEN)ns[1]))
                   1199:   {
1.2     ! noro     1200:     ns2 = polsymmodpp(chi, pp);
        !          1201:     for (j = 1; j <= n; j++)
1.1       noro     1202:       affii((GEN)ns2[j], (GEN)ns[j]);
                   1203:   }
1.2     ! noro     1204:
1.1       noro     1205:   return ns;
                   1206: }
                   1207:
1.2     ! noro     1208: /* compute the Newton sums modulo pp of the characteristic
1.1       noro     1209:    polynomial of a(x) mod g(x) */
                   1210: static GEN
                   1211: newtonsums(GEN a, GEN chi, GEN pp, GEN ns)
                   1212: {
                   1213:   GEN va, pa, s, ns2;
1.2     ! noro     1214:   long j, k, n = degpol(chi);
        !          1215:   gpmem_t av2, lim;
1.1       noro     1216:
                   1217:   ns2 = manage_cache(chi, pp, ns);
                   1218:
                   1219:   av2 = avma;
                   1220:   lim = stack_lim(av2, 1);
                   1221:
                   1222:   pa = gun;
                   1223:   va = zerovec(n);
                   1224:
                   1225:   for (j = 1; j <= n; j++)
                   1226:   {
                   1227:     pa = gmul(pa, a);
1.2     ! noro     1228:     pa = polmodi(pa, pp);
1.1       noro     1229:     pa = gmod(pa, chi);
1.2     ! noro     1230:     pa = polmodi(pa, pp);
1.1       noro     1231:
                   1232:     s  = gzero;
                   1233:
                   1234:     for (k = 0; k <= n-1; k++)
                   1235:       s = addii(s, mulii(polcoeff0(pa, k, -1), (GEN)ns2[k+1]));
1.2     ! noro     1236:
        !          1237:     va[j] = (long)centermod(s, pp);
        !          1238:
1.1       noro     1239:     if (low_stack(lim, stack_lim(av2, 1)))
                   1240:     {
                   1241:       GEN *gptr[2];
                   1242:       gptr[0]=&pa; gptr[1]=&va;
                   1243:       if(DEBUGMEM>1) err(warnmem, "newtonsums");
                   1244:       gerepilemany(av2, gptr, 2);
                   1245:     }
                   1246:   }
                   1247:
                   1248:   return va;
                   1249: }
                   1250:
                   1251: /* compute the characteristic polynomial of a mod g
                   1252:    to a precision of pp using Newton sums */
                   1253: static GEN
                   1254: newtoncharpoly(GEN a, GEN chi, GEN pp, GEN ns)
                   1255: {
                   1256:   GEN v, c, s, t;
1.2     ! noro     1257:   long n = degpol(chi), j, k, vn = varn(chi);
        !          1258:   gpmem_t av = avma, av2, lim;
1.1       noro     1259:
                   1260:   v = newtonsums(a, chi, pp, ns);
                   1261:   av2 = avma;
                   1262:   lim = stack_lim(av2, 1);
                   1263:   c = cgetg(n + 2, t_VEC);
                   1264:   c[1] = un;
                   1265:   if (n%2) c[1] = lneg((GEN)c[1]);
                   1266:   for (k = 2; k <= n+1; k++) c[k] = zero;
                   1267:
                   1268:   for (k = 2; k <= n+1; k++)
                   1269:   {
                   1270:     s = gzero;
                   1271:     for (j = 1; j < k; j++)
                   1272:     {
                   1273:       t = gmul((GEN)v[j], (GEN)c[k-j]);
                   1274:       if (!(j%2)) t = gneg(t);
                   1275:       s = gadd(s, t);
                   1276:     }
                   1277:     c[k] = ldiv(s, stoi(k - 1));
                   1278:
                   1279:     if (low_stack(lim, stack_lim(av2, 1)))
                   1280:     {
                   1281:       if(DEBUGMEM>1) err(warnmem, "newtoncharpoly");
                   1282:       c = gerepilecopy(av2, c);
                   1283:     }
                   1284:   }
1.2     ! noro     1285:
1.1       noro     1286:   k = (n%2)? 1: 2;
1.2     ! noro     1287:   for (  ; k <= n+1; k += 2)
1.1       noro     1288:     c[k] = lneg((GEN)c[k]);
                   1289:
                   1290:   return gerepileupto(av, gtopoly(c, vn));
                   1291: }
                   1292:
1.2     ! noro     1293: /* return v_p(n!) */
        !          1294: static long
        !          1295: val_fact(long n, GEN pp)
        !          1296: {
        !          1297:   long p, q, v;
        !          1298:   if (is_bigint(pp)) return 0;
        !          1299:   q = p = itos(pp); v = 0;
        !          1300:   do { v += n/q; q *= p; } while (n >= q);
        !          1301:   return v;
        !          1302: }
        !          1303:
        !          1304: static GEN
1.1       noro     1305: mycaract(GEN f, GEN beta, GEN p, GEN pp, GEN ns)
                   1306: {
1.2     ! noro     1307:   GEN p1, chi, npp;
        !          1308:   long v = varn(f), n = degpol(f);
1.1       noro     1309:
                   1310:   if (gcmp0(beta)) return zeropol(v);
                   1311:
1.2     ! noro     1312:   beta = Q_primitive_part(beta,&p1);
1.1       noro     1313:   if (!pp)
1.2     ! noro     1314:     chi = ZX_caract(f, beta, v);
1.1       noro     1315:   else
                   1316:   {
1.2     ! noro     1317:     npp = mulii(pp, gpowgs(p, val_fact(n, p)));
        !          1318:     if (p1) npp = mulii(npp, gpowgs(denom(p1), n));
1.1       noro     1319:
                   1320:     chi = newtoncharpoly(beta, f, npp, ns);
                   1321:   }
                   1322:
1.2     ! noro     1323:   if (p1) chi = rescale_pol(chi,p1);
        !          1324:
        !          1325:   if (!pp) return chi;
1.1       noro     1326:
                   1327:   /* this can happen only if gamma is incorrect (not an integer) */
1.2     ! noro     1328:   if (divise(Q_denom(chi), p)) return NULL;
        !          1329:
        !          1330:   return redelt(chi, pp, pp);
1.1       noro     1331: }
                   1332:
                   1333: /* Factor characteristic polynomial of beta mod p */
                   1334: static GEN
                   1335: factcp(GEN p, GEN f, GEN beta, GEN pp, GEN ns)
                   1336: {
1.2     ! noro     1337:   gpmem_t av;
1.1       noro     1338:   GEN chi,nu, b = cgetg(4,t_VEC);
1.2     ! noro     1339:   long l;
1.1       noro     1340:
                   1341:   chi=mycaract(f,beta,p,pp,ns);
                   1342:   av=avma; nu=(GEN)factmod(chi,p)[1]; l=lg(nu)-1;
                   1343:   nu=lift_intern((GEN)nu[1]);
                   1344:   b[1]=(long)chi;
                   1345:   b[2]=lpilecopy(av,nu);
                   1346:   b[3]=lstoi(l); return b;
                   1347: }
                   1348:
                   1349: /* return the prime element in Zp[phi] */
                   1350: static GEN
                   1351: getprime(GEN p, GEN chi, GEN phi, GEN chip, GEN nup, long *Lp, long *Ep)
                   1352: {
1.2     ! noro     1353:   long v = varn(chi), L, E, r, s;
        !          1354:   GEN chin, pip, pp;
1.1       noro     1355:
                   1356:   if (gegal(nup, polx[v]))
                   1357:     chin = chip;
                   1358:   else
                   1359:     chin = mycaract(chip, nup, p, NULL, NULL);
                   1360:
1.2     ! noro     1361:   vstar(p, chin, &L, &E);
        !          1362:   (void)cbezout(L, -E, &r, &s);
        !          1363:   if (r <= 0)
        !          1364:   {
        !          1365:     long q = 1 + ((-r) / E);
        !          1366:     r += q*E;
        !          1367:     s += q*L;
1.1       noro     1368:   }
                   1369:
1.2     ! noro     1370:   pip = RX_RXQ_compo(nup, phi, chi);
        !          1371:   pip = lift_intern(gpowgs(gmodulcp(pip, chi), r));
        !          1372:   pp  = gpowgs(p, s);
1.1       noro     1373:
1.2     ! noro     1374:   *Lp = L;
        !          1375:   *Ep = E; return gdiv(pip, pp);
1.1       noro     1376: }
                   1377:
                   1378: static GEN
1.2     ! noro     1379: update_alpha(GEN p, GEN fx, GEN alph, GEN chi, GEN pmr, GEN pmf, long mf,
1.1       noro     1380:             GEN ns)
                   1381: {
                   1382:   long l, v = varn(fx);
                   1383:   GEN nalph = NULL, nchi, w, nnu, pdr, npmr, rep;
                   1384:
                   1385:   affii(gzero, (GEN)ns[1]); /* kill cache */
                   1386:
                   1387:   if (!chi)
                   1388:     nchi = mycaract(fx, alph, p, pmf, ns);
                   1389:   else
                   1390:   {
                   1391:     nchi  = chi;
                   1392:     nalph = alph;
                   1393:   }
                   1394:
                   1395:   pdr = respm(nchi, derivpol(nchi), pmr);
                   1396:   for (;;)
                   1397:   {
                   1398:     if (signe(pdr)) break;
1.2     ! noro     1399:     if (!nalph) nalph = gadd(alph, gmul(p, polx[v]));
        !          1400:     /* nchi was too reduced at this point; try a larger precision */
        !          1401:     pmf  = sqri(pmf);
        !          1402:     nchi = mycaract(fx, nalph, p, pmf, ns);
        !          1403:     pdr  = respm(nchi, derivpol(nchi), pmf);
1.1       noro     1404:     if (signe(pdr)) break;
                   1405:     if (DEBUGLEVEL >= 6)
                   1406:       fprintferr("  non separable polynomial in update_alpha!\n");
1.2     ! noro     1407:     /* at this point, we assume that chi is not square-free */
1.1       noro     1408:     nalph = gadd(nalph, gmul(p, polx[v]));
                   1409:     w = factcp(p, fx, nalph, NULL, ns);
1.2     ! noro     1410:     nchi = (GEN)w[1];
        !          1411:     nnu  = (GEN)w[2];
1.1       noro     1412:     l    = itos((GEN)w[3]);
                   1413:     if (l > 1) return Decomp(p, fx, mf, nalph, nchi, nnu, 0);
                   1414:     pdr = respm(nchi, derivpol(nchi), pmr);
                   1415:   }
                   1416:
                   1417:   if (is_pm1(pdr))
                   1418:     npmr = gun;
                   1419:   else
                   1420:   {
                   1421:     npmr  = mulii(sqri(pdr), p);
                   1422:     nchi  = polmodi(nchi, npmr);
1.2     ! noro     1423:     nalph = redelt(nalph? nalph: alph, npmr, pmf);
1.1       noro     1424:   }
                   1425:
                   1426:   affii(gzero, (GEN)ns[1]); /* kill cache again (contains data for fx) */
                   1427:
                   1428:   rep = cgetg(5, t_VEC);
                   1429:   rep[1] = (long)nalph;
                   1430:   rep[2] = (long)nchi;
                   1431:   rep[3] = (long)npmr;
                   1432:   rep[4] = lmulii(p, pdr);
                   1433:
                   1434:   return rep;
                   1435: }
                   1436:
1.2     ! noro     1437: /* flag != 0 iff we're looking for the p-adic factorization,
1.1       noro     1438:    in which case it is the p-adic precision we want */
                   1439: GEN
                   1440: nilord(GEN p, GEN fx, long mf, GEN gx, long flag)
                   1441: {
1.2     ! noro     1442:   long L, E, Fa, La, Ea, oE, Fg, eq, er, v = varn(fx), i, nv, Le, Ee, N, l, vn;
1.1       noro     1443:   GEN p1, alph, chi, nu, w, phi, pmf, pdr, pmr, kapp, pie, chib, ns;
1.2     ! noro     1444:   GEN gamm, chig, nug, delt, beta, eta, chie, nue, pia, opa;
1.1       noro     1445:
1.2     ! noro     1446:   if (DEBUGLEVEL>2)
1.1       noro     1447:   {
1.2     ! noro     1448:     fprintferr("  entering Nilord");
        !          1449:     if (DEBUGLEVEL>4)
1.1       noro     1450:     {
                   1451:       fprintferr(" with parameters: p = %Z, expo = %ld\n", p, mf);
                   1452:       fprintferr("  fx = %Z, gx = %Z", fx, gx);
                   1453:     }
                   1454:     fprintferr("\n");
                   1455:   }
1.2     ! noro     1456:
1.1       noro     1457:   pmf = gpowgs(p, mf + 1);
                   1458:   pdr = respm(fx, derivpol(fx), pmf);
                   1459:   pmr = mulii(sqri(pdr), p);
                   1460:   pdr = mulii(p, pdr);
                   1461:   chi = polmodi_keep(fx, pmr);
                   1462:
                   1463:   alph = polx[v];
1.2     ! noro     1464:   nu = gx;
1.1       noro     1465:   N  = degpol(fx);
                   1466:   oE = 0;
                   1467:   opa = NULL;
                   1468:
                   1469:   /* used to cache the newton sums of chi */
                   1470:   ns = cgetg(N + 2, t_COL);
                   1471:   p1 = powgi(p, gceil(gdivsg(N, mulii(p, subis(p, 1))))); /* p^(N/(p(p-1))) */
                   1472:   p1 = mulii(p1, mulii(pmf, gpowgs(pmr, N)));
                   1473:   l  = lg(p1); /* enough in general... */
                   1474:   for (i = 1; i <= N + 1; i++) ns[i] = lgeti(l);
                   1475:   ns[N+1] = (long)p1;
                   1476:   affii(gzero, (GEN)ns[1]); /* zero means: need to be computed */
                   1477:
                   1478:   for(;;)
                   1479:   {
1.2     ! noro     1480:     /* kappa needs to be recomputed */
1.1       noro     1481:     kapp = NULL;
                   1482:     Fa   = degpol(nu);
                   1483:     /* the prime element in Zp[alpha] */
                   1484:     pia  = getprime(p, chi, polx[v], chi, nu, &La, &Ea);
                   1485:     pia  = redelt(pia, pmr, pmf);
                   1486:
                   1487:     if (Ea < oE)
                   1488:     {
                   1489:       alph = gadd(alph, opa);
                   1490:       w = update_alpha(p, fx, alph, NULL, pmr, pmf, mf, ns);
                   1491:       alph = (GEN)w[1];
                   1492:       chi  = (GEN)w[2];
                   1493:       pmr  = (GEN)w[3];
                   1494:       pdr  = (GEN)w[4];
                   1495:       kapp = NULL;
                   1496:       pia  = getprime(p, chi, polx[v], chi, nu, &La, &Ea);
                   1497:       pia  = redelt(pia, pmr, pmf);
                   1498:     }
1.2     ! noro     1499:
        !          1500:     oE = Ea; opa = RX_RXQ_compo(pia, alph, fx);
1.1       noro     1501:
                   1502:     if (DEBUGLEVEL >= 5)
                   1503:       fprintferr("  Fa = %ld and Ea = %ld \n", Fa, Ea);
1.2     ! noro     1504:
1.1       noro     1505:     /* we change alpha such that nu = pia */
                   1506:     if (La > 1)
                   1507:     {
1.2     ! noro     1508:       alph = gadd(alph, RX_RXQ_compo(pia, alph, fx));
1.1       noro     1509:
                   1510:       w = update_alpha(p, fx, alph, NULL, pmr, pmf, mf, ns);
                   1511:       alph = (GEN)w[1];
                   1512:       chi  = (GEN)w[2];
                   1513:       pmr  = (GEN)w[3];
                   1514:       pdr  = (GEN)w[4];
                   1515:     }
                   1516:
                   1517:     /* if Ea*Fa == N then O = Zp[alpha] */
1.2     ! noro     1518:     if (Ea*Fa == N)
1.1       noro     1519:     {
                   1520:       if (flag) return NULL;
                   1521:
                   1522:       alph = redelt(alph, sqri(p), pmf);
                   1523:       return dbasis(p, fx, mf, alph, p);
                   1524:     }
                   1525:
                   1526:     /* during the process beta tends to a factor of chi */
                   1527:     beta  = lift_intern(gpowgs(gmodulcp(nu, chi), Ea));
                   1528:
                   1529:     for (;;)
                   1530:     {
                   1531:       if (DEBUGLEVEL >= 5)
                   1532:        fprintferr("  beta = %Z\n", beta);
                   1533:
                   1534:       /* if pmf divides norm(beta) then it's useless */
                   1535:       p1 = gmod(gnorm(gmodulcp(beta, chi)), pmf);
                   1536:       if (signe(p1))
                   1537:       {
                   1538:        chib = NULL;
                   1539:        vn = ggval(p1, p);
                   1540:        eq = (long)(vn / N);
                   1541:        er = (long)(vn*Ea/N - eq*Ea);
                   1542:       }
1.2     ! noro     1543:       else
1.1       noro     1544:       {
                   1545:        chib = mycaract(chi, beta, NULL, NULL, ns);
1.2     ! noro     1546:        vstar(p, chib, &L, &E);
        !          1547:        eq = (long)(L / E);
        !          1548:        er = (long)(L*Ea / E - eq*Ea);
1.1       noro     1549:       }
1.2     ! noro     1550:
        !          1551:       /* eq and er are such that gamma = beta.p^-eq.nu^-er is a unit */
1.1       noro     1552:       if (eq) gamm = gdiv(beta, gpowgs(p, eq));
                   1553:       else gamm = beta;
                   1554:
                   1555:       if (er)
                   1556:       {
                   1557:        /* kappa = nu^-1 in Zp[alpha] */
                   1558:        if (!kapp)
                   1559:        {
1.2     ! noro     1560:          kapp = QX_invmod(nu, chi);
1.1       noro     1561:          kapp = redelt(kapp, pmr, pmf);
                   1562:          kapp = gmodulcp(kapp, chi);
                   1563:        }
                   1564:        gamm = lift(gmul(gamm, gpowgs(kapp, er)));
                   1565:        gamm = redelt(gamm, p, pmf);
                   1566:       }
                   1567:
                   1568:       if (DEBUGLEVEL >= 6)
                   1569:        fprintferr("  gamma = %Z\n", gamm);
                   1570:
                   1571:       if (er || !chib)
1.2     ! noro     1572:        chig = mycaract(chi, gamm, p, pmf, ns);
1.1       noro     1573:       else
                   1574:       {
                   1575:        chig = poleval(chib, gmul(polx[v], gpowgs(p, eq)));
                   1576:        chig = gdiv(chig, gpowgs(p, N*eq));
                   1577:        chig = polmodi(chig, pmf);
                   1578:       }
                   1579:
1.2     ! noro     1580:       if (!chig || !gcmp1(Q_denom(chig)))
1.1       noro     1581:       {
1.2     ! noro     1582:        /* Valuation of beta was wrong. This means that
        !          1583:           gamma fails the v*-test */
        !          1584:        chib = mycaract(chi, beta, p, NULL, ns);
        !          1585:        vstar(p, chib, &L, &E);
        !          1586:        eq = (long)(-L / E);
        !          1587:        er = (long)(-L*Ea / E - eq*Ea);
        !          1588:
        !          1589:        if (eq) gamm = gmul(beta, gpowgs(p, eq));
        !          1590:        else gamm = beta;
        !          1591:        if (er)
1.1       noro     1592:        {
                   1593:          gamm = gmul(gamm, gpowgs(nu, er));
                   1594:          gamm = gmod(gamm, chi);
                   1595:          gamm = redelt(gamm, p, pmr);
                   1596:        }
1.2     ! noro     1597:        chig = mycaract(chi, gamm, p, pmf, ns);
1.1       noro     1598:       }
                   1599:
                   1600:       nug  = (GEN)factmod(chig, p)[1];
                   1601:       l    = lg(nug) - 1;
                   1602:       nug  = lift((GEN)nug[l]);
                   1603:
                   1604:       if (l > 1)
                   1605:       {
                   1606:        /* there are at least 2 factors mod. p => chi can be split */
1.2     ! noro     1607:        phi  = RX_RXQ_compo(gamm, alph, fx);
1.1       noro     1608:        phi  = redelt(phi, p, pmf);
                   1609:        if (flag) mf += 3;
                   1610:         return Decomp(p, fx, mf, phi, chig, nug, flag);
                   1611:       }
                   1612:
                   1613:       Fg = degpol(nug);
                   1614:       if (Fa%Fg)
                   1615:       {
                   1616:        if (DEBUGLEVEL >= 5)
                   1617:          fprintferr("  Increasing Fa\n");
                   1618:        /* we compute a new element such F = lcm(Fa, Fg) */
                   1619:        w = testb2(p, chi, Fa, gamm, pmf, Fg, ns);
                   1620:        if (gcmp1((GEN)w[1]))
                   1621:        {
                   1622:          /* there are at least 2 factors mod. p => chi can be split */
1.2     ! noro     1623:          phi = RX_RXQ_compo((GEN)w[2], alph, fx);
1.1       noro     1624:          phi = redelt(phi, p, pmf);
                   1625:           if (flag) mf += 3;
                   1626:           return Decomp(p, fx, mf, phi, (GEN)w[3], (GEN)w[4], flag);
                   1627:        }
                   1628:        break;
                   1629:       }
                   1630:
                   1631:       /* we look for a root delta of nug in Fp[alpha] such that
                   1632:         vp(gamma - delta) > 0. This root can then be used to
                   1633:         improved the approximation given by beta */
                   1634:       nv = fetch_var();
                   1635:       w = Fp_factor_irred(nug, p, gsubst(nu, varn(nu), polx[nv]));
                   1636:       if (degpol(w[1]) != 1)
                   1637:         err(talker,"bug in nilord (no root). Is p a prime ?");
                   1638:
                   1639:       for (i = 1;; i++)
                   1640:       {
                   1641:        if (i >= lg(w))
1.2     ! noro     1642:           err(talker, "bug in nilord (no suitable root), is p = %Z a prime?",
1.1       noro     1643:              (long)p);
                   1644:         delt = gneg_i(gsubst(gcoeff(w, 2, i), nv, polx[v]));
1.2     ! noro     1645:         eta  = gsub(gamm, delt);
1.1       noro     1646:         if (typ(delt) == t_INT)
                   1647:         {
                   1648:           chie = poleval(chig, gadd(polx[v], delt));
                   1649:           nue  = (GEN)factmod(chie, p)[1];
                   1650:           l    = lg(nue) - 1;
                   1651:           nue  = lift((GEN)nue[l]);
                   1652:         }
                   1653:         else
1.2     ! noro     1654:         {
1.1       noro     1655:           p1   = factcp(p, chi, eta, pmf, ns);
                   1656:           chie = (GEN)p1[1];
1.2     ! noro     1657:           nue  = (GEN)p1[2];
1.1       noro     1658:           l    = itos((GEN)p1[3]);
                   1659:         }
                   1660:         if (l > 1)
                   1661:         {
                   1662:           /* there are at least 2 factors mod. p => chi can be split */
1.2     ! noro     1663:           (void)delete_var();
        !          1664:           phi = RX_RXQ_compo(eta, alph, fx);
1.1       noro     1665:           phi = redelt(phi, p, pmf);
                   1666:           if (flag) mf += 3;
                   1667:           return Decomp(p, fx, mf, phi, chie, nue, flag);
                   1668:         }
1.2     ! noro     1669:
1.1       noro     1670:         /* if vp(eta) = vp(gamma - delta) > 0 */
                   1671:         if (gegal(nue, polx[v])) break;
                   1672:       }
1.2     ! noro     1673:       (void)delete_var();
1.1       noro     1674:
1.2     ! noro     1675:       if (!signe(modii(constant_term(chie), pmr)))
1.1       noro     1676:        chie = mycaract(chi, eta, p, pmf, ns);
                   1677:
                   1678:       pie = getprime(p, chi, eta, chie, nue, &Le, &Ee);
                   1679:       if (Ea%Ee)
                   1680:       {
                   1681:        if (DEBUGLEVEL >= 5)
                   1682:          fprintferr("  Increasing Ea\n");
                   1683:        pie = redelt(pie, p, pmf);
                   1684:        /* we compute a new element such E = lcm(Ea, Ee) */
                   1685:        w = testc2(p, chi, pmr, pmf, nu, Ea, pie, Ee, ns);
                   1686:        if (gcmp1((GEN)w[1]))
                   1687:        {
                   1688:          /* there are at least 2 factors mod. p => chi can be split */
1.2     ! noro     1689:          phi = RX_RXQ_compo((GEN)w[2], alph, fx);
1.1       noro     1690:          phi = redelt(phi, p, pmf);
                   1691:           if (flag) mf += 3;
                   1692:           return Decomp(p, fx, mf, phi, (GEN)w[3], (GEN)w[4], flag);
                   1693:        }
                   1694:        break;
                   1695:       }
1.2     ! noro     1696:
1.1       noro     1697:       if (eq) delt = gmul(delt, gpowgs(p, eq));
                   1698:       if (er) delt = gmul(delt, gpowgs(nu, er));
                   1699:       beta = gsub(beta, delt);
                   1700:     }
                   1701:
                   1702:     /* we replace alpha by a new alpha with a larger F or E */
1.2     ! noro     1703:     alph = RX_RXQ_compo((GEN)w[2], alph, fx);
1.1       noro     1704:     chi  = (GEN)w[3];
                   1705:     nu   = (GEN)w[4];
                   1706:
                   1707:     w = update_alpha(p, fx, alph, chi, pmr, pmf, mf, ns);
                   1708:     alph = (GEN)w[1];
                   1709:     chi  = (GEN)w[2];
                   1710:     pmr  = (GEN)w[3];
                   1711:     pdr  = (GEN)w[4];
                   1712:
                   1713:     /* that can happen if p does not divide the field discriminant! */
                   1714:     if (is_pm1(pmr))
                   1715:     {
                   1716:       if (flag)
                   1717:       {
                   1718:        p1 = lift((GEN)factmod(chi, p)[1]);
                   1719:        l  = lg(p1) - 1;
                   1720:        if (l == 1) return NULL;
                   1721:        phi = redelt(alph, p, pmf);
                   1722:        return Decomp(p, fx, ggval(pmf, p), phi, chi, (GEN)p1[l], flag);
                   1723:       }
                   1724:       else
                   1725:        return dbasis(p, fx, mf, alph, chi);
                   1726:     }
                   1727:   }
                   1728: }
                   1729:
                   1730: /* Returns [1,phi,chi,nu] if phi non-primary
1.2     ! noro     1731:  *         [2,phi,chi,nu] with F_phi = lcm (F_alpha, F_theta)
        !          1732:  *                         and E_phi = E_alpha
1.1       noro     1733:  */
                   1734: static GEN
                   1735: testb2(GEN p, GEN fa, long Fa, GEN theta, GEN pmf, long Ft, GEN ns)
                   1736: {
                   1737:   long m, Dat, t, v = varn(fa);
                   1738:   GEN b, w, phi, h;
                   1739:
1.2     ! noro     1740:   Dat = clcm(Fa, Ft) + 3;
1.1       noro     1741:   b = cgetg(5, t_VEC);
1.2     ! noro     1742:   m = p[2];
1.1       noro     1743:   if (degpol(p) > 0 || m < 0) m = 0;
                   1744:
                   1745:   for (t = 1;; t++)
                   1746:   {
                   1747:     h = m? stopoly(t, m, v): scalarpol(stoi(t), v);
                   1748:     phi = gadd(theta, gmod(h, fa));
                   1749:     w = factcp(p, fa, phi, pmf, ns);
                   1750:     h = (GEN)w[3];
                   1751:     if (h[2] > 1) { b[1] = un; break; }
                   1752:     if (lgef(w[2]) == Dat) { b[1] = deux; break; }
                   1753:   }
1.2     ! noro     1754:
        !          1755:   b[2] = (long)phi;
        !          1756:   b[3] = w[1];
        !          1757:   b[4] = w[2];
1.1       noro     1758:   return b;
                   1759: }
                   1760:
                   1761: /* Returns [1, phi, chi, nu] if phi non-primary
                   1762:  *         [2, phi, chi, nu] if E_phi = lcm (E_alpha, E_theta)
                   1763:  */
                   1764: static GEN
1.2     ! noro     1765: testc2(GEN p, GEN fa, GEN pmr, GEN pmf, GEN alph2, long Ea, GEN thet2,
1.1       noro     1766:        long Et, GEN ns)
                   1767: {
                   1768:   GEN b, c1, c2, c3, psi, phi, w, h;
                   1769:   long r, s, t, v = varn(fa);
                   1770:
                   1771:   b=cgetg(5, t_VEC);
                   1772:
1.2     ! noro     1773:   (void)cbezout(Ea, Et, &r, &s); t = 0;
1.1       noro     1774:   while (r < 0) { r = r + Et; t++; }
                   1775:   while (s < 0) { s = s + Ea; t++; }
                   1776:
1.2     ! noro     1777:   c1 = lift_intern(gpowgs(gmodulcp(alph2, fa), s));
        !          1778:   c2 = lift_intern(gpowgs(gmodulcp(thet2, fa), r));
        !          1779:   c3 = gdiv(gmod(gmul(c1, c2), fa), gpowgs(p, t));
1.1       noro     1780:
                   1781:   psi = redelt(c3, pmr, pmr);
                   1782:   phi = gadd(polx[v], psi);
                   1783:
                   1784:   w = factcp(p, fa, phi, pmf, ns);
                   1785:   h = (GEN)w[3];
                   1786:   b[1] = (h[2] > 1)? un: deux;
1.2     ! noro     1787:   b[2] = (long)phi;
        !          1788:   b[3] = w[1];
        !          1789:   b[4] = w[2];
1.1       noro     1790:   return b;
                   1791: }
                   1792:
1.2     ! noro     1793: /*******************************************************************/
        !          1794: /*                                                                 */
        !          1795: /*    2-ELT REPRESENTATION FOR PRIME IDEALS (dividing index)       */
        !          1796: /*                                                                 */
        !          1797: /*******************************************************************/
        !          1798: /* beta = generators of prime ideal (vectors). Return "small" random elt in P */
        !          1799: static GEN
        !          1800: random_elt_in_P(GEN beta, long small)
1.1       noro     1801: {
1.2     ! noro     1802:   long z, i, j, la, lbeta = lg(beta);
        !          1803:   GEN a = NULL, B;
1.1       noro     1804:
1.2     ! noro     1805:   /* compute sum random(-7..8) * beta[i] */
        !          1806:   if (small)
1.1       noro     1807:   {
1.2     ! noro     1808:     la = lg(beta[1]);
        !          1809:     if (small > 7) small = 0;
        !          1810:     for (i=1; i<lbeta; i++)
        !          1811:     { /* Warning: change definition of 'small' if you change this */
        !          1812:       z = mymyrand() >> (BITS_IN_RANDOM-5); /* in [0,15] */
        !          1813:       if (z >= 9) z -= 7;
        !          1814:       if (small) z %= small;
        !          1815:       if (!z) continue;
        !          1816:       B = (GEN)beta[i];
        !          1817:       if (a)
        !          1818:         for (j = 1; j < la; j++) a[j] += z * B[j];
        !          1819:       else {
        !          1820:         a = cgetg(la, t_VECSMALL);
        !          1821:         for (j = 1; j <la; j++) a[j] = z * B[j];
        !          1822:       }
        !          1823:     }
1.1       noro     1824:   }
1.2     ! noro     1825:   else
        !          1826:     for (i=1; i<lbeta; i++)
        !          1827:     {
        !          1828:       z = mymyrand() >> (BITS_IN_RANDOM-5);
        !          1829:       if (z >= 9) z -= 7;
        !          1830:       if (!z) continue;
        !          1831:       B = gmulsg(z, (GEN)beta[i]);
        !          1832:       a = a? gadd(a, B): B;
        !          1833:     }
        !          1834:   return a;
1.1       noro     1835: }
                   1836:
1.2     ! noro     1837: /* routines to check uniformizer algebraically (as t_POL) */
        !          1838:
        !          1839: /* a t_POL, D t_INT (or NULL if 1), q = p^(f+1). a/D in pr | p, norm(pr) = pf.
        !          1840:  * Return 1 if (a/D,p) = pr, and 0 otherwise */
        !          1841: static int
        !          1842: is_uniformizer(GEN D, GEN a, GEN T, GEN q)
        !          1843: {
        !          1844:   GEN N = ZX_resultant_all(T, a, D, 0); /* norm(a) */
        !          1845:   return (resii(N, q) != gzero);
        !          1846: }
1.1       noro     1847:
1.2     ! noro     1848: /* a/D or a/D + p uniformizer ? */
1.1       noro     1849: static GEN
1.2     ! noro     1850: prime_check_elt(GEN D, GEN Dp, GEN a, GEN T, GEN q, int ramif)
        !          1851: {
        !          1852:   if (is_uniformizer(D,a,T,q)) return a;
        !          1853:   /* can't succeed if e > 1 */
        !          1854:   if (!ramif && is_uniformizer(D,gadd(a,Dp),T,q)) return a;
        !          1855:   return NULL;
        !          1856: }
        !          1857:
        !          1858: /* P given by an Fp basis */
        !          1859: static GEN
        !          1860: compute_pr2(GEN nf, GEN P, GEN p, int *ramif)
        !          1861: {
        !          1862:   long i, j, m = lg(P)-1;
        !          1863:   GEN mul, P2 = gmul(p, P);
        !          1864:   for (i=1; i<=m; i++)
        !          1865:   {
        !          1866:     mul = eltmul_get_table(nf, (GEN)P[i]);
        !          1867:     for (j=1; j<=i; j++)
        !          1868:       P2 = concatsp(P2, gmul(mul, (GEN)P[j]));
        !          1869:   }
        !          1870:   P2 = hnfmodid(P2, sqri(p)); /* HNF of pr^2 */
        !          1871:   *ramif = egalii(gcoeff(P2,1,1), p); /* pr/p ramified ? */
        !          1872:   return P2;
        !          1873: }
        !          1874:
        !          1875: static GEN
        !          1876: random_unif_loop_pol(GEN nf, GEN P, GEN D, GEN Dp, GEN beta, GEN pol,
        !          1877:                      GEN p, GEN q)
        !          1878: {
        !          1879:   long small, i, c = 0, m = lg(P)-1, N = degpol(nf[1]), keep = getrand();
        !          1880:   int ramif;
        !          1881:   GEN a, P2;
        !          1882:   gpmem_t av;
        !          1883:
        !          1884:   for(i=1; i<=m; i++)
        !          1885:     if ((a = prime_check_elt(D,Dp,(GEN)beta[i],pol,q,0))) return a;
        !          1886:
        !          1887:   (void)setrand(1);
        !          1888:   if (DEBUGLEVEL) fprintferr("uniformizer_loop, hard case: ");
        !          1889:   P2 = compute_pr2(nf, P, p, &ramif);
        !          1890:
        !          1891:   a = mulis(Dp, 8*degpol(nf[1]));
        !          1892:   if (is_bigint(a)) small = 0;
        !          1893:   else
        !          1894:   {
        !          1895:     ulong mod = itou(Dp);
        !          1896:     small = itos(p);
        !          1897:     for (i=1; i<=m; i++)
        !          1898:       beta[i] = (long)u_Fp_FpV(pol_to_vec((GEN)beta[i], N), mod);
        !          1899:   }
        !          1900:
        !          1901:   for(av = avma; ;avma = av)
        !          1902:   {
        !          1903:     if (DEBUGLEVEL && (++c & 0x3f) == 0) fprintferr("%d ", c);
        !          1904:     a = random_elt_in_P(beta, small);
        !          1905:     if (!a) continue;
        !          1906:     if (small) a = vec_to_pol(small_to_vec(a), varn(pol));
        !          1907:     a = centermod(a, Dp);
        !          1908:     if ((a = prime_check_elt(D,Dp,a,pol,q,ramif)))
        !          1909:     {
        !          1910:       if (DEBUGLEVEL) fprintferr("\n");
        !          1911:       (void)setrand(keep); return a;
        !          1912:     }
        !          1913:   }
        !          1914: }
        !          1915:
        !          1916: /* routines to check uniformizer numerically (as t_COL) */
        !          1917:
        !          1918: static int
        !          1919: vec_is_uniformizer(GEN a, GEN q, long r1)
        !          1920: {
        !          1921:   long e;
        !          1922:   GEN N = grndtoi( norm_by_embed(r1, a), &e );
        !          1923:   if (e > -5) err(precer, "vec_is_uniformizer");
        !          1924:   return (resii(N, q) != gzero);
        !          1925: }
        !          1926:
        !          1927: static GEN
        !          1928: prime_check_eltvec(GEN a, GEN M, GEN p, GEN q, long r1, long small, int ramif)
1.1       noro     1929: {
1.2     ! noro     1930:   GEN ar;
        !          1931:   long i,l;
        !          1932:   a = centermod(a, p);
        !          1933:   if (small) ar = gmul_mat_smallvec(M, a);
        !          1934:   else       ar = gmul(M, a);
        !          1935:
        !          1936:   if (vec_is_uniformizer(ar, q, r1)) return small? small_to_col(a): a;
        !          1937:   /* can't succeed if e > 1 */
        !          1938:   if (ramif) return NULL;
        !          1939:   l = lg(ar);
        !          1940:   for (i=1; i<l; i++) ar[i] = ladd((GEN)ar[i], p);
        !          1941:   if (!vec_is_uniformizer(ar, q, r1)) return NULL;
        !          1942:   if (small) a = small_to_col(a);
        !          1943:   a[1] = laddii((GEN)a[1],p); return a;
1.1       noro     1944: }
                   1945:
                   1946: static GEN
1.2     ! noro     1947: random_unif_loop_vec(GEN nf, GEN P, GEN p, GEN q)
1.1       noro     1948: {
1.2     ! noro     1949:   long small, r1, i, c = 0, m = lg(P)-1, keep = getrand();
        !          1950:   int ramif;
        !          1951:   GEN a, P2, beta, M = gmael(nf,5,1);
        !          1952:   gpmem_t av;
        !          1953:
        !          1954:   r1 = nf_get_r1(nf);
        !          1955:   a = mulis(p, 8*degpol(nf[1]));
        !          1956:   if (is_bigint(a)) { small = 0; beta = P; }
        !          1957:   else
        !          1958:   {
        !          1959:     small = itos(p); beta = cgetg(m+1, t_MAT);
        !          1960:     for (i=1; i<=m; i++)
        !          1961:       beta[i] = (long)u_Fp_FpV((GEN)P[i], itou(p));
        !          1962:   }
        !          1963:   for(i=1; i<=m; i++)
        !          1964:     if ((a = prime_check_eltvec((GEN)beta[i],M,p,q,r1,small,0))) return a;
        !          1965:
        !          1966:   (void)setrand(1);
        !          1967:   if (DEBUGLEVEL) fprintferr("uniformizer_loop, hard case: ");
        !          1968:   P2 = compute_pr2(nf, P, p, &ramif);
1.1       noro     1969:
1.2     ! noro     1970:   for(av = avma; ;avma = av)
1.1       noro     1971:   {
1.2     ! noro     1972:     if (DEBUGLEVEL && (++c & 0x3f) == 0) fprintferr("%d ", c);
        !          1973:     a = random_elt_in_P(beta, small);
        !          1974:     if (!a) continue;
        !          1975:     if ((a = prime_check_eltvec(a,M,p,q,r1,small,0)))
        !          1976:     {
        !          1977:       if (DEBUGLEVEL) fprintferr("\n");
        !          1978:       (void)setrand(keep); return a;
        !          1979:     }
1.1       noro     1980:   }
                   1981: }
                   1982:
1.2     ! noro     1983: /* L = Fp-bases for prime ideals of O_K/p. Return a p-uniformizer for
        !          1984:  * L[i] using the approximation theorem */
        !          1985: static GEN
        !          1986: uniformizer_appr(GEN nf, GEN L, long i, GEN p)
1.1       noro     1987: {
1.2     ! noro     1988:   long j, l;
        !          1989:   GEN inter = NULL, P = (GEN)L[i], P2, Q, u, v, pi;
        !          1990:   int ramif;
1.1       noro     1991:
1.2     ! noro     1992:   l = lg(L)-1;
        !          1993:   for (j=l; j; j--)
        !          1994:   {
        !          1995:     if (j == i) continue;
        !          1996:     Q = (GEN)L[j]; if (typ(Q) != t_MAT) break;
        !          1997:     inter = inter? FpM_intersect(inter, Q, p): Q;
        !          1998:   }
        !          1999:   if (!inter)
        !          2000:   {
        !          2001:     setlg(L, l);
        !          2002:     inter = idealprodprime(nf, L);
        !          2003:   }
        !          2004:   else
        !          2005:   {
        !          2006:     inter = hnfmodid(inter, p);
        !          2007:     for (   ; j; j--)
        !          2008:     {
        !          2009:       Q = (GEN)L[j];
        !          2010:       inter = idealmul(nf, inter, Q);
        !          2011:     }
        !          2012:   }
1.1       noro     2013:
1.2     ! noro     2014:   /* inter = prod L[j], j != i */
        !          2015:   P2 = compute_pr2(nf, P, p, &ramif);
        !          2016:   u = addone_aux2(P2, inter);
        !          2017:   v = unnf_minus_x(u);
        !          2018:   if (!ramif) pi = gmul(p, v);
        !          2019:   else
        !          2020:   {
        !          2021:     l = lg(P)-1;
        !          2022:     for (j=l; j; j--)
        !          2023:       if (!hnf_invimage(P2, (GEN)P[j])) break;
        !          2024:     pi = element_muli(nf,(GEN)P[j],v);
        !          2025:   }
        !          2026:   pi = gadd(pi, u);
        !          2027:   pi =  centermod(pi, p);
        !          2028:   if (!ramif && hnf_invimage(P2, pi)) pi[1] = laddii((GEN)pi[1], p);
        !          2029:   return pi;
1.1       noro     2030: }
                   2031:
1.2     ! noro     2032: /* Input: an ideal mod p, P != Z_K (Fp-basis, in matrix form)
        !          2033:  * Output: x such that P = (p,x) */
        !          2034: static GEN
        !          2035: uniformizer(GEN nf, GEN P, GEN p)
1.1       noro     2036: {
1.2     ! noro     2037:   GEN q, D, Dp, w, beta, a, T = (GEN)nf[1];
        !          2038:   long i, f, N = degpol(T), m = lg(P)-1;
        !          2039:
        !          2040:   if (!m) return gscalcol_i(p,N);
1.1       noro     2041:
1.2     ! noro     2042:   /* we want v_p(Norm(beta)) = p^f, f = N-m */
        !          2043:   f = N-m;
        !          2044:   P = centermod(P, p);
        !          2045:   q = mulii(gpowgs(p,f), p);
        !          2046:
        !          2047:   if (typ(nf[5]) == t_VEC) /* dummy nf from padicff */
        !          2048:   {
        !          2049:     GEN M = gmael(nf,5,1);
        !          2050:     long ex, prec = gprecision(M);
        !          2051:     ex = gexpo(M) + gexpo(mulsi(8 * N, p));
        !          2052:     /* enough prec to use norm_by_embed */
        !          2053:     if (N * ex <= bit_accuracy(prec))
        !          2054:       return random_unif_loop_vec(nf, P, p, q);
        !          2055:   }
        !          2056:
        !          2057:   w = Q_remove_denom((GEN)nf[7], &D);
        !          2058:   if (D)
        !          2059:   {
        !          2060:     long v = pvaluation(D, p, &a);
        !          2061:     D = gpowgs(p, v);
        !          2062:     Dp = mulii(D, p);
        !          2063:   } else {
        !          2064:     w = dummycopy(w);
        !          2065:     Dp = p;
        !          2066:   }
        !          2067:   for (i=1; i<=N; i++)
        !          2068:     w[i] = (long)FpX_red((GEN)w[i], Dp); /* w[i] / D defined mod p */
        !          2069:   beta = gmul(w, P);
        !          2070:   a = random_unif_loop_pol(nf,P,D,Dp,beta,T,p,q);
        !          2071:   a = algtobasis_i(nf,a);
        !          2072:   if (D) a = gdivexact(a,D);
        !          2073:   a = centermod(a, p);
        !          2074:   if (!is_uniformizer(D,gmul(w,a), T,q)) a[1] = laddii((GEN)a[1],p);
        !          2075:   return a;
1.1       noro     2076: }
                   2077:
1.2     ! noro     2078: /* Assuming P = (p,u) prime, return tau such that p Z + tau Z = p P^(-1)*/
1.1       noro     2079: static GEN
1.2     ! noro     2080: anti_uniformizer(GEN nf, GEN p, GEN u)
1.1       noro     2081: {
1.2     ! noro     2082:   gpmem_t av = avma;
        !          2083:   GEN mat = eltmul_get_table(nf, u);
        !          2084:   return gerepileupto(av, FpM_deplin(mat,p));
1.1       noro     2085: }
                   2086:
                   2087: /*******************************************************************/
                   2088: /*                                                                 */
                   2089: /*                   BUCHMANN-LENSTRA ALGORITHM                    */
                   2090: /*                                                                 */
                   2091: /*******************************************************************/
                   2092:
1.2     ! noro     2093: /* pr = (p,u) of ramification index e */
        !          2094: GEN
        !          2095: apply_kummer(GEN nf,GEN u,GEN e,GEN p)
        !          2096: {
        !          2097:   GEN t, T = (GEN)nf[1], pr = cgetg(6,t_VEC);
        !          2098:   long f = degpol(u), N = degpol(T);
        !          2099:
        !          2100:   pr[1] = (long)p;
        !          2101:   pr[3] = (long)e;
        !          2102:   pr[4] = lstoi(f);
        !          2103:   if (f == N) /* inert */
        !          2104:   {
        !          2105:     pr[2] = (long)gscalcol_i(p,N);
        !          2106:     pr[5] = (long)gscalcol_i(gun,N);
        !          2107:   }
        !          2108:   else
        !          2109:   { /* make sure v_pr(u) = 1 (automatic if e>1) */
        !          2110:     if (is_pm1(e) && !is_uniformizer(NULL,u, T, gpowgs(p,f+1)))
        !          2111:       u[2] = laddii((GEN)u[2], p);
        !          2112:     t = algtobasis_i(nf, FpX_div(T,u,p));
        !          2113:     pr[2] = (long)algtobasis_i(nf,u);
        !          2114:     pr[5] = (long)centermod(t, p);
        !          2115:   }
        !          2116:   return pr;
        !          2117: }
        !          2118:
        !          2119: /* return a Z basis of Z_K's p-radical, phi = x--> x^p-x */
1.1       noro     2120: static GEN
1.2     ! noro     2121: pradical(GEN nf, GEN p, GEN *phi)
1.1       noro     2122: {
                   2123:   long i,N = degpol(nf[1]);
1.2     ! noro     2124:   GEN q,m,frob,rad;
1.1       noro     2125:
1.2     ! noro     2126:   /* matrix of Frob: x->x^p over Z_K/p */
1.1       noro     2127:   frob = cgetg(N+1,t_MAT);
                   2128:   for (i=1; i<=N; i++)
1.2     ! noro     2129:     frob[i] = (long)element_powid_mod_p(nf,i,p, p);
1.1       noro     2130:
1.2     ! noro     2131:   m = frob; q = p;
        !          2132:   while (cmpis(q,N) < 0) { q = mulii(q,p); m = FpM_mul(m, frob, p); }
        !          2133:   rad = FpM_ker(m, p); /* m = Frob^k, s.t p^k >= N */
        !          2134:   for (i=1; i<=N; i++)
        !          2135:     coeff(frob,i,i) = lsubis(gcoeff(frob,i,i), 1);
        !          2136:   *phi = frob; return rad;
        !          2137: }
        !          2138:
        !          2139: /* return powers of a: a^0, ... , a^d,  d = dim A */
        !          2140: static GEN
        !          2141: get_powers(GEN mul, GEN p)
        !          2142: {
        !          2143:   long i, d = lg(mul[1]);
        !          2144:   GEN z, pow = cgetg(d+2,t_MAT), P = pow+1;
        !          2145:
        !          2146:   P[0] = (long)gscalcol_i(gun, d-1);
        !          2147:   z = (GEN)mul[1];
        !          2148:   for (i=1; i<=d; i++)
1.1       noro     2149:   {
1.2     ! noro     2150:     P[i] = (long)z; /* a^i */
        !          2151:     if (i!=d) z = FpM_FpV_mul(mul, z, p);
1.1       noro     2152:   }
1.2     ! noro     2153:   return pow;
1.1       noro     2154: }
                   2155:
1.2     ! noro     2156: /* minimal polynomial of a in A (dim A = d).
        !          2157:  * mul = multiplication table by a in A */
1.1       noro     2158: static GEN
1.2     ! noro     2159: pol_min(GEN mul, GEN p)
1.1       noro     2160: {
1.2     ! noro     2161:   gpmem_t av = avma;
        !          2162:   GEN z, pow = get_powers(mul, p);
        !          2163:   z = FpM_deplin(pow, p);
        !          2164:   return gerepileupto(av, gtopolyrev(z,0));
1.1       noro     2165: }
                   2166:
                   2167: static GEN
1.2     ! noro     2168: get_pr(GEN nf, GEN L, long i, GEN p, int appr)
1.1       noro     2169: {
1.2     ! noro     2170:   GEN pr, u, t, P = (GEN)L[i];
        !          2171:   long e, f;
        !          2172:   gpmem_t av;
1.1       noro     2173:
1.2     ! noro     2174:   if (typ(P) == t_VEC) return P; /* already done (Kummer) */
        !          2175:
        !          2176:   av = avma;
        !          2177:   if (appr) u = uniformizer_appr(nf, L, i, p);
        !          2178:   else      u = uniformizer(nf, P, p);
        !          2179:   u = gerepilecopy(av, u);
        !          2180:   t = anti_uniformizer(nf,p,u);
        !          2181:   av = avma;
        !          2182:   e = 1 + int_elt_val(nf,t,p,t,NULL);
        !          2183:   f = degpol(nf[1]) - (lg(P)-1);
        !          2184:   avma = av;
        !          2185:   pr = cgetg(6,t_VEC);
        !          2186:   pr[1] = (long)p;
        !          2187:   pr[2] = (long)u;
        !          2188:   pr[3] = lstoi(e);
        !          2189:   pr[4] = lstoi(f);
        !          2190:   pr[5] = (long)t; return pr;
1.1       noro     2191: }
                   2192:
1.2     ! noro     2193: static int
        !          2194: use_appr(GEN L, GEN pp, long N)
1.1       noro     2195: {
1.2     ! noro     2196:   long i, f, l = lg(L);
        !          2197:   double prod = 1., NP;
        !          2198:   GEN P;
        !          2199:   gpmem_t av = avma;
1.1       noro     2200:
1.2     ! noro     2201:   for (i=1; i<l; i++)
1.1       noro     2202:   {
1.2     ! noro     2203:     P = (GEN)L[i];
        !          2204:     f = typ(P)==t_VEC? itos((GEN)P[4]): N - (lg(P)-1);
        !          2205:     NP = gtodouble(gpowgs(pp, f));
        !          2206:     prod *= (1 - 1./NP);
1.1       noro     2207:   }
1.2     ! noro     2208:   avma = av;
        !          2209:   return (prod * N * 10 < 1);
1.1       noro     2210: }
                   2211:
1.2     ! noro     2212: /* prime ideal decomposition of p */
1.1       noro     2213: static GEN
1.2     ! noro     2214: _primedec(GEN nf, GEN p)
1.1       noro     2215: {
1.2     ! noro     2216:   long i,k,c,iL,N;
        !          2217:   GEN ex,F,L,Lpr,Ip,H,phi,mat1,T,f,g,h,p1,UN;
        !          2218:   int appr;
        !          2219:
        !          2220:   if (DEBUGLEVEL>2) (void)timer2();
        !          2221:   nf = checknf(nf); T = (GEN)nf[1];
        !          2222:   F = factmod(T,p);
        !          2223:   ex = (GEN)F[2];
        !          2224:   F  = (GEN)F[1]; F = centerlift(F);
        !          2225:   if (DEBUGLEVEL>5) msgtimer("factmod");
1.1       noro     2226:
1.2     ! noro     2227:   k = lg(F);
        !          2228:   if (signe(modii((GEN)nf[4],p))) /* p doesn't divide index */
1.1       noro     2229:   {
1.2     ! noro     2230:     L = cgetg(k,t_VEC);
        !          2231:     for (i=1; i<k; i++)
        !          2232:       L[i] = (long)apply_kummer(nf,(GEN)F[i],(GEN)ex[i],p);
        !          2233:     if (DEBUGLEVEL>5) msgtimer("simple primedec");
        !          2234:     return L;
        !          2235:   }
        !          2236:
        !          2237:   g = (GEN)F[1];
        !          2238:   for (i=2; i<k; i++) g = FpX_mul(g,(GEN)F[i], p);
        !          2239:   h = FpX_div(T,g,p);
        !          2240:   f = FpX_red(gdivexact(gsub(gmul(g,h), T), p), p);
        !          2241:
        !          2242:   N = degpol(T);
        !          2243:   L = cgetg(N+1,t_VEC); iL = 1;
        !          2244:   for (i=1; i<k; i++)
        !          2245:     if (is_pm1(ex[i]) || signe(FpX_res(f,(GEN)F[i],p)))
        !          2246:       L[iL++] = (long)apply_kummer(nf,(GEN)F[i],(GEN)ex[i],p);
        !          2247:     else /* F[i] | (f,g,h), happens at least once by Dedekind criterion */
        !          2248:       ex[i] = 0;
        !          2249:   if (DEBUGLEVEL>2) msgtimer("%ld Kummer factors", iL-1);
        !          2250:
        !          2251:   /* phi matrix of x -> x^p - x in algebra Z_K/p */
        !          2252:   Ip = pradical(nf,p,&phi);
        !          2253:   if (DEBUGLEVEL>2) msgtimer("pradical");
        !          2254:
        !          2255:   /* split etale algebra Z_K / (p,Ip) */
        !          2256:   h = cgetg(N+1,t_VEC);
        !          2257:   if (iL > 1)
        !          2258:   { /* split off Kummer factors */
        !          2259:     GEN mulbeta, beta = NULL;
        !          2260:     for (i=1; i<k; i++)
        !          2261:       if (!ex[i]) beta = beta? FpX_mul(beta, (GEN)F[i], p): (GEN)F[i];
        !          2262:     beta = FpV_red(algtobasis_i(nf,beta), p);
        !          2263:
        !          2264:     mulbeta = FpM_red(eltmul_get_table(nf, beta), p);
        !          2265:     p1 = concatsp(mulbeta, Ip);
        !          2266:     /* Fp-base of ideal (Ip, beta) in ZK/p */
        !          2267:     h[1] = (long)FpM_image(p1, p);
1.1       noro     2268:   }
1.2     ! noro     2269:   else
        !          2270:     h[1] = (long)Ip;
        !          2271:
        !          2272:   UN = gscalcol(gun, N);
        !          2273:   for (c=1; c; c--)
        !          2274:   { /* Let A:= (Z_K/p) / Ip; try to split A2 := A / Im H ~ Im M2
        !          2275:        H * ? + M2 * Mi2 = Id_N ==> M2 * Mi2 projector A --> A2 */
        !          2276:     GEN M, Mi, M2, Mi2, phi2;
        !          2277:     long dim;
        !          2278:
        !          2279:     H = (GEN)h[c]; k = lg(H)-1;
        !          2280:     M   = FpM_suppl(concatsp(H,UN), p);
        !          2281:     Mi  = FpM_inv(M, p);
        !          2282:     M2  = vecextract_i(M, k+1,N); /* M = (H|M2) invertible */
        !          2283:     Mi2 = rowextract_i(Mi,k+1,N);
        !          2284:     /* FIXME: FpM_mul(,M2) could be done with vecextract_p */
        !          2285:     phi2 = FpM_mul(Mi2, FpM_mul(phi,M2, p), p);
        !          2286:     mat1 = FpM_ker(phi2, p);
        !          2287:     dim = lg(mat1)-1; /* A2 product of 'dim' fields */
        !          2288:     if (dim > 1)
        !          2289:     { /* phi2 v = 0 <==> a = M2 v in Ker phi */
        !          2290:       GEN I,R,r,a,mula,mul2, v = (GEN)mat1[2];
        !          2291:       long n;
        !          2292:
        !          2293:       a = FpM_FpV_mul(M2,v, p);
        !          2294:       mula = FpM_red(eltmul_get_table(nf, a), p);
        !          2295:       mul2 = FpM_mul(Mi2, FpM_mul(mula,M2, p), p);
        !          2296:       R = rootmod(pol_min(mul2,p), p); /* totally split mod p */
        !          2297:
        !          2298:       n = lg(R)-1;
        !          2299:       for (i=1; i<=n; i++)
        !          2300:       {
        !          2301:         r = lift_intern((GEN)R[i]);
        !          2302:         I = gaddmat_i(negi(r), mula);
        !          2303:        h[c++] = (long)FpM_image(concatsp(H, I), p);
        !          2304:       }
        !          2305:       if (n == dim)
        !          2306:         for (i=1; i<=n; i++) { H = (GEN)h[--c]; L[iL++] = (long)H; }
        !          2307:     }
        !          2308:     else /* A2 field ==> H maximal, f = N-k = dim(A2) */
        !          2309:       L[iL++] = (long)H;
        !          2310:   }
        !          2311:   setlg(L, iL);
        !          2312:   Lpr = cgetg(iL, t_VEC);
        !          2313:   if (DEBUGLEVEL>2) msgtimer("splitting %ld factors",iL-1);
        !          2314:   appr = use_appr(L,p,N);
        !          2315:   if (DEBUGLEVEL>2 && appr) fprintferr("using the approximation theorem\n");
        !          2316:   for (i=1; i<iL; i++) Lpr[i] = (long)get_pr(nf, L, i, p, appr);
        !          2317:   if (DEBUGLEVEL>2) msgtimer("finding uniformizers");
        !          2318:   return Lpr;
        !          2319: }
        !          2320:
        !          2321: GEN
        !          2322: primedec(GEN nf, GEN p)
        !          2323: {
        !          2324:   gpmem_t av = avma;
        !          2325:   return gerepileupto(av, gen_sort(_primedec(nf,p), 0, cmp_prime_over_p));
1.1       noro     2326: }
                   2327:
1.2     ! noro     2328: /* return [Fp[x]: Fp] */
        !          2329: static long
        !          2330: ffdegree(GEN x, GEN frob, GEN p)
1.1       noro     2331: {
1.2     ! noro     2332:   gpmem_t av = avma;
        !          2333:   long d, f = lg(frob)-1;
        !          2334:   GEN y = x;
1.1       noro     2335:
1.2     ! noro     2336:   for (d=1; d < f; d++)
1.1       noro     2337:   {
1.2     ! noro     2338:     y = FpM_FpV_mul(frob, y, p);
        !          2339:     if (gegal(y, x)) break;
1.1       noro     2340:   }
1.2     ! noro     2341:   avma = av; return d;
1.1       noro     2342: }
                   2343:
                   2344: static GEN
1.2     ! noro     2345: lift_to_zk(GEN v, GEN c, long N)
1.1       noro     2346: {
1.2     ! noro     2347:   GEN w = zerocol(N);
        !          2348:   long i, l = lg(c);
        !          2349:   for (i=1; i<l; i++) w[c[i]] = v[i];
        !          2350:   return w;
1.1       noro     2351: }
                   2352:
1.2     ! noro     2353: /* return integral x = 0 mod p/pr^e, (x,pr) = 1.
        !          2354:  * Don't reduce mod p here: caller may need result mod pr^k */
        !          2355: GEN
        !          2356: special_anti_uniformizer(GEN nf, GEN pr)
        !          2357: {
        !          2358:   GEN p = (GEN)pr[1], e = (GEN)pr[3];
        !          2359:   return gdivexact(element_pow(nf,(GEN)pr[5],e), gpowgs(p,itos(e)-1));
        !          2360: }
1.1       noro     2361:
1.2     ! noro     2362: /* return t = 1 mod pr, t = 0 mod p / pr^e(pr/p) */
1.1       noro     2363: static GEN
1.2     ! noro     2364: anti_uniformizer2(GEN nf, GEN pr)
1.1       noro     2365: {
1.2     ! noro     2366:   GEN p = (GEN)pr[1], z;
        !          2367:   z = gmod(special_anti_uniformizer(nf, pr), p);
        !          2368:   z = eltmul_get_table(nf, z);
        !          2369:   z = hnfmodid(z, p);
        !          2370:   z = idealaddtoone_i(nf,pr,z);
        !          2371:   return unnf_minus_x(z);
        !          2372: }
1.1       noro     2373:
1.2     ! noro     2374: #define mpr_TAU 1
        !          2375: #define mpr_FFP 2
        !          2376: #define mpr_PR  3
        !          2377: #define mpr_T   4
        !          2378: #define mpr_NFP 5
        !          2379: #define SMALLMODPR 4
        !          2380: #define LARGEMODPR 6
        !          2381: static GEN
        !          2382: modpr_TAU(GEN modpr)
        !          2383: {
        !          2384:   GEN tau = (GEN)modpr[mpr_TAU];
        !          2385:   if (typ(tau) == t_INT && signe(tau) == 0) tau = NULL;
        !          2386:   return tau;
        !          2387: }
1.1       noro     2388:
1.2     ! noro     2389: /* prh = HNF matrix, which is identity but for the first line. Return a
        !          2390:  * projector to ZK / prh ~ Z/prh[1,1] */
        !          2391: GEN
        !          2392: dim1proj(GEN prh)
        !          2393: {
        !          2394:   long i, N = lg(prh)-1;
        !          2395:   GEN ffproj = cgetg(N+1, t_VEC);
        !          2396:   GEN x, q = gcoeff(prh,1,1);
        !          2397:   ffproj[1] = un;
        !          2398:   for (i=2; i<=N; i++)
1.1       noro     2399:   {
1.2     ! noro     2400:     x = gcoeff(prh,1,i);
        !          2401:     if (signe(x)) x = subii(q,x);
        !          2402:     ffproj[i] = (long)x;
1.1       noro     2403:   }
1.2     ! noro     2404:   return ffproj;
1.1       noro     2405: }
1.2     ! noro     2406:
1.1       noro     2407: static GEN
1.2     ! noro     2408: modprinit(GEN nf, GEN pr, int zk)
1.1       noro     2409: {
1.2     ! noro     2410:   gpmem_t av = avma;
        !          2411:   GEN res, tau, mul, x, p, T, pow, ffproj, nfproj, prh, c, gf;
        !          2412:   long N, i, k, f;
        !          2413:
        !          2414:   nf = checknf(nf); checkprimeid(pr);
        !          2415:   gf = (GEN)pr[4];
        !          2416:   f = itos(gf);
        !          2417:   N = degpol(nf[1]);
        !          2418:   prh = prime_to_ideal(nf, pr);
        !          2419:   tau = zk? gzero: anti_uniformizer2(nf, pr);
        !          2420:   p = (GEN)pr[1];
1.1       noro     2421:
1.2     ! noro     2422:   if (f == 1)
        !          2423:   {
        !          2424:     res = cgetg(SMALLMODPR, t_COL);
        !          2425:     res[mpr_TAU] = (long)tau;
        !          2426:     res[mpr_FFP] = (long)dim1proj(prh);
        !          2427:     res[mpr_PR ] = (long)pr; return gerepilecopy(av, res);
        !          2428:   }
1.1       noro     2429:
1.2     ! noro     2430:   c = cgetg(f+1, t_VECSMALL);
        !          2431:   ffproj = cgetg(N+1, t_MAT);
        !          2432:   for (k=i=1; i<=N; i++)
        !          2433:   {
        !          2434:     x = gcoeff(prh, i,i);
        !          2435:     if (!is_pm1(x)) { c[k] = i; ffproj[i] = (long)_ei(N, i); k++; }
        !          2436:     else
        !          2437:       ffproj[i] = lneg((GEN)prh[i]);
        !          2438:   }
        !          2439:   ffproj = rowextract_p(ffproj, c);
        !          2440:   if (! divise((GEN)nf[4], p))
        !          2441:   {
        !          2442:     GEN basis, proj_modT;
        !          2443:     if (N == f) T = (GEN)nf[1]; /* pr inert */
        !          2444:     else
        !          2445:       T = primpart(gmul((GEN)nf[7], (GEN)pr[2]));
1.1       noro     2446:
1.2     ! noro     2447:     basis = (GEN)nf[7];
        !          2448:     proj_modT = cgetg(f+1, t_MAT);
        !          2449:     for (i=1; i<=f; i++)
        !          2450:     {
        !          2451:       GEN cx, w = Q_primitive_part((GEN)basis[c[i]], &cx);
        !          2452:       w = FpX_rem(w, T, p);
        !          2453:       if (cx)
1.1       noro     2454:       {
1.2     ! noro     2455:         cx = gmod(cx, p);
        !          2456:         w = FpX_Fp_mul(w, cx, p);
        !          2457:       }
        !          2458:       proj_modT[i] = (long)pol_to_vec(w, f); /* w_i mod (T,p) */
1.1       noro     2459:     }
1.2     ! noro     2460:     ffproj = FpM_mul(proj_modT,ffproj,p);
        !          2461:
        !          2462:     res = cgetg(SMALLMODPR+1, t_COL);
        !          2463:     res[mpr_TAU] = (long)tau;
        !          2464:     res[mpr_FFP] = (long)ffproj;
        !          2465:     res[mpr_PR ] = (long)pr;
        !          2466:     res[mpr_T  ] = (long)T; return gerepilecopy(av, res);
1.1       noro     2467:   }
                   2468:
1.2     ! noro     2469:   if (isprime(gf))
        !          2470:   {
        !          2471:     mul = eltmulid_get_table(nf, c[2]);
        !          2472:     mul = vecextract_p(mul, c);
        !          2473:   }
        !          2474:   else
        !          2475:   {
        !          2476:     GEN v, u, u2, frob;
        !          2477:     long deg,deg1,deg2;
1.1       noro     2478:
1.2     ! noro     2479:     /* matrix of Frob: x->x^p over Z_K/pr = < w[c1], ..., w[cf] > over Fp */
        !          2480:     frob = cgetg(f+1, t_MAT);
        !          2481:     for (i=1; i<=f; i++)
1.1       noro     2482:     {
1.2     ! noro     2483:       x = element_powid_mod_p(nf,c[i],p, p);
        !          2484:       frob[i] = (long)FpM_FpV_mul(ffproj, x, p);
1.1       noro     2485:     }
1.2     ! noro     2486:     u = _ei(f,2); k = 2;
        !          2487:     deg1 = ffdegree(u, frob, p);
        !          2488:     while (deg1 < f)
1.1       noro     2489:     {
1.2     ! noro     2490:       k++; u2 = _ei(f, k);
        !          2491:       deg2 = ffdegree(u2, frob, p);
        !          2492:       deg = clcm(deg1,deg2);
        !          2493:       if (deg == deg1) continue;
        !          2494:       if (deg == deg2) { deg1 = deg2; u = u2; continue; }
        !          2495:       u = gadd(u, u2);
        !          2496:       while (ffdegree(u, frob, p) < deg) u = gadd(u, u2);
        !          2497:       deg1 = deg;
1.1       noro     2498:     }
1.2     ! noro     2499:     v = lift_to_zk(u,c,N);
        !          2500:
        !          2501:     mul = cgetg(f+1,t_MAT);
        !          2502:     mul[1] = (long)v; /* assume w_1 = 1 */
        !          2503:     for (i=2; i<=f; i++) mul[i] = (long)element_mulid(nf,v,c[i]);
1.1       noro     2504:   }
                   2505:
1.2     ! noro     2506:   /* Z_K/pr = Fp(v), mul = mul by v */
        !          2507:   mul = FpM_red(mul, p);
        !          2508:   mul = FpM_mul(ffproj, mul, p);
        !          2509:
        !          2510:   pow = get_powers(mul, p);
        !          2511:   T = gtopolyrev(FpM_deplin(pow, p), varn(nf[1]));
        !          2512:   nfproj = cgetg(f+1, t_MAT);
        !          2513:   for (i=1; i<=f; i++) nfproj[i] = (long)lift_to_zk((GEN)pow[i], c, N);
        !          2514:   nfproj = gmul((GEN)nf[7], nfproj);
1.1       noro     2515:
1.2     ! noro     2516:   setlg(pow, f+1);
        !          2517:   ffproj = FpM_mul(FpM_inv(pow, p), ffproj, p);
1.1       noro     2518:
1.2     ! noro     2519:   res = cgetg(LARGEMODPR, t_COL);
        !          2520:   res[mpr_TAU] = (long)tau;
        !          2521:   res[mpr_FFP] = (long)ffproj;
        !          2522:   res[mpr_PR ] = (long)pr;
        !          2523:   res[mpr_T  ] = (long)T;
        !          2524:   res[mpr_NFP] = (long)nfproj; return gerepilecopy(av, res);
        !          2525: }
1.1       noro     2526:
1.2     ! noro     2527: GEN
        !          2528: nfmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 0); }
        !          2529: GEN
        !          2530: zkmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 1); }
1.1       noro     2531:
1.2     ! noro     2532: void
        !          2533: checkmodpr(GEN modpr)
        !          2534: {
        !          2535:   if (typ(modpr) != t_COL || lg(modpr) < SMALLMODPR)
        !          2536:     err(talker,"incorrect modpr format");
        !          2537:   checkprimeid((GEN)modpr[mpr_PR]);
1.1       noro     2538: }
                   2539:
1.2     ! noro     2540:
1.1       noro     2541: static GEN
1.2     ! noro     2542: to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p, int zk)
1.1       noro     2543: {
1.2     ! noro     2544:   GEN modpr = (typ(*pr) == t_COL)? *pr: modprinit(nf, *pr, zk);
        !          2545:   *T = lg(modpr)==SMALLMODPR? NULL: (GEN)modpr[mpr_T];
        !          2546:   *pr = (GEN)modpr[mpr_PR];
        !          2547:   *p = (GEN)(*pr)[1]; return modpr;
        !          2548: }
        !          2549: GEN
        !          2550: nf_to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p) {
        !          2551:   GEN modpr = to_ff_init(nf,pr,T,p,0);
        !          2552:   GEN tau = modpr_TAU(modpr);
        !          2553:   if (!tau) modpr[mpr_TAU] = (long)anti_uniformizer2(nf, *pr);
        !          2554:   return modpr;
        !          2555: }
        !          2556: GEN
        !          2557: zk_to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p) {
        !          2558:   return to_ff_init(nf,pr,T,p,1);
1.1       noro     2559: }
                   2560:
1.2     ! noro     2561: /* assume x in 'basis' form (t_COL) */
1.1       noro     2562: GEN
1.2     ! noro     2563: zk_to_ff(GEN x, GEN modpr)
1.1       noro     2564: {
1.2     ! noro     2565:   GEN pr = (GEN)modpr[mpr_PR];
        !          2566:   GEN p = (GEN)pr[1];
        !          2567:   GEN y = gmul((GEN)modpr[mpr_FFP], x);
        !          2568:   if (lg(modpr) == SMALLMODPR) return modii(y,p);
        !          2569:   y = FpV_red(y, p);
        !          2570:   return col_to_ff(y, varn(modpr[mpr_T]));
        !          2571: }
        !          2572:
        !          2573: /* REDUCTION Modulo a prime ideal */
1.1       noro     2574:
1.2     ! noro     2575: /* assume x in t_COL form, v_pr(x) >= 0 */
        !          2576: static GEN
        !          2577: kill_denom(GEN x, GEN nf, GEN p, GEN modpr)
        !          2578: {
        !          2579:   GEN cx, den = denom(x);
        !          2580:   long v;
        !          2581:   if (gcmp1(den)) return x;
1.1       noro     2582:
1.2     ! noro     2583:   v = ggval(den,p);
        !          2584:   if (v)
1.1       noro     2585:   {
1.2     ! noro     2586:     GEN tau = modpr_TAU(modpr);
        !          2587:     if (!tau) err(talker,"modpr initialized for integers only!");
        !          2588:     x = element_mul(nf,x, element_pow(nf,tau,stoi(v)));
1.1       noro     2589:   }
1.2     ! noro     2590:   x = Q_primitive_part(x, &cx);
        !          2591:   x = FpV_red(x, p);
        !          2592:   if (cx) x = FpV_red(gmul(gmod(cx, p), x), p);
        !          2593:   return x;
1.1       noro     2594: }
                   2595:
                   2596: /* x integral, reduce mod prh in HNF */
                   2597: GEN
                   2598: nfreducemodpr_i(GEN x, GEN prh)
                   2599: {
                   2600:   GEN p = gcoeff(prh,1,1);
                   2601:   long i,j;
                   2602:
                   2603:   x = dummycopy(x);
                   2604:   for (i=lg(x)-1; i>=2; i--)
                   2605:   {
                   2606:     GEN t = (GEN)prh[i], p1 = resii((GEN)x[i], p);
                   2607:     x[i] = (long)p1;
                   2608:     if (signe(p1) && is_pm1(t[i]))
                   2609:     {
                   2610:       for (j=1; j<i; j++)
                   2611:         x[j] = lsubii((GEN)x[j], mulii(p1, (GEN)t[j]));
                   2612:       x[i] = zero;
                   2613:     }
                   2614:   }
                   2615:   x[1] = lresii((GEN)x[1], p); return x;
                   2616: }
                   2617:
                   2618: GEN
1.2     ! noro     2619: nfreducemodpr(GEN nf, GEN x, GEN modpr)
1.1       noro     2620: {
1.2     ! noro     2621:   gpmem_t av = avma;
        !          2622:   long i;
        !          2623:   GEN pr, p;
1.1       noro     2624:
1.2     ! noro     2625:   checkmodpr(modpr);
        !          2626:   pr = (GEN)modpr[mpr_PR];
        !          2627:   p = (GEN)pr[1];
        !          2628:   if (typ(x) != t_COL) x = algtobasis(nf,x);
1.1       noro     2629:   for (i=lg(x)-1; i>0; i--)
1.2     ! noro     2630:     if (typ(x[i]) == t_INTMOD) { x = lift(x); break; }
        !          2631:   x = kill_denom(x, nf, p, modpr);
        !          2632:   x = ff_to_nf(zk_to_ff(x,modpr), modpr);
        !          2633:   if (typ(x) != t_COL) x = algtobasis(nf, x);
        !          2634:   return gerepileupto(av, FpV(x, p));
        !          2635: }
        !          2636:
        !          2637: GEN
        !          2638: nf_to_ff(GEN nf, GEN x, GEN modpr)
        !          2639: {
        !          2640:   gpmem_t av = avma;
        !          2641:   GEN pr = (GEN)modpr[mpr_PR];
        !          2642:   GEN p = (GEN)pr[1];
        !          2643:   long t = typ(x);
        !          2644:
        !          2645:   if (t == t_POLMOD) { x = (GEN)x[2]; t = typ(x); }
        !          2646:   switch(t)
        !          2647:   {
        !          2648:     case t_INT: return modii(x, p);
        !          2649:     case t_FRAC: return gmod(x, p);
        !          2650:     case t_POL: x = algtobasis(nf, x); break;
        !          2651:     case t_COL: break;
        !          2652:     default: err(typeer,"nf_to_ff");
        !          2653:   }
        !          2654:   x = kill_denom(x, nf, p, modpr);
        !          2655:   return gerepilecopy(av, zk_to_ff(x, modpr));
        !          2656: }
        !          2657:
        !          2658: GEN
        !          2659: ff_to_nf(GEN x, GEN modpr)
        !          2660: {
        !          2661:   if (lg(modpr) < LARGEMODPR) return x;
        !          2662:   return mulmat_pol((GEN)modpr[mpr_NFP], x);
        !          2663: }
        !          2664: GEN
        !          2665: modprM_lift(GEN x, GEN modpr)
        !          2666: {
        !          2667:   long i,j,h,l = lg(x);
        !          2668:   GEN y = cgetg(l, t_MAT);
        !          2669:   if (l == 1) return y;
        !          2670:
        !          2671:   h = lg(x[1]);
        !          2672:   for (j=1; j<l; j++)
1.1       noro     2673:   {
1.2     ! noro     2674:     GEN p1 = cgetg(h,t_COL); y[j] = (long)p1;
        !          2675:     for (i=1; i<h; i++) p1[i]=(long)ff_to_nf(gcoeff(x,i,j), modpr);
1.1       noro     2676:   }
1.2     ! noro     2677:   return y;
1.1       noro     2678: }
1.2     ! noro     2679: GEN
        !          2680: modprX_lift(GEN x, GEN modpr)
        !          2681: {
        !          2682:   long i, l;
        !          2683:   GEN z;
        !          2684:
        !          2685:   if (typ(x)!=t_POL) return gcopy(x); /* scalar */
        !          2686:   l = lgef(x);
        !          2687:   z = cgetg(l, t_POL); z[1] = x[1];
        !          2688:   for (i=2; i<l; i++) z[i] = (long)ff_to_nf((GEN)x[i], modpr);
        !          2689:   return z;
        !          2690: }
        !          2691:
        !          2692: /* reduce the coefficients of pol modulo modpr */
        !          2693: GEN
        !          2694: modprX(GEN x, GEN nf,GEN modpr)
        !          2695: {
        !          2696:   long i, l;
        !          2697:   GEN z;
1.1       noro     2698:
1.2     ! noro     2699:   if (typ(x)!=t_POL) return nf_to_ff(nf,x,modpr);
        !          2700:   l = lgef(x);
        !          2701:   z = cgetg(l,t_POL); z[1] = x[1];
        !          2702:   for (i=2; i<l; i++) z[i] = (long)nf_to_ff(nf,(GEN)x[i],modpr);
        !          2703:   return normalizepol(z);
        !          2704: }
        !          2705: GEN
        !          2706: modprV(GEN z, GEN nf,GEN modpr)
        !          2707: {
        !          2708:   long i,l = lg(z);
        !          2709:   GEN x;
        !          2710:   x = cgetg(l,typ(z));
        !          2711:   for (i=1; i<l; i++) x[i] = (long)nf_to_ff(nf,(GEN)z[i], modpr);
        !          2712:   return x;
        !          2713: }
        !          2714: /* assume z a t_VEC/t_COL/t_MAT */
1.1       noro     2715: GEN
1.2     ! noro     2716: modprM(GEN z, GEN nf,GEN modpr)
1.1       noro     2717: {
1.2     ! noro     2718:   long i,l = lg(z), m;
        !          2719:   GEN x;
        !          2720:
        !          2721:   if (typ(z) != t_MAT) return modprV(z,nf,modpr);
        !          2722:   x = cgetg(l,t_MAT); if (l==1) return x;
        !          2723:   m = lg((GEN)z[1]);
        !          2724:   for (i=1; i<l; i++) x[i] = (long)modprV((GEN)z[i],nf,modpr);
        !          2725:   return x;
1.1       noro     2726: }
                   2727:
                   2728: /*                        relative ROUND 2
                   2729:  *
                   2730:  * input: nf = base field K
                   2731:  *   x monic polynomial, coefficients in Z_K, degree n defining a relative
                   2732:  *   extension L=K(theta).
                   2733:  *   One MUST have varn(x) < varn(nf[1]).
                   2734:  * output: a pseudo-basis [A,I] of Z_L, where A is in M_n(K) in HNF form and
                   2735:  *   I a vector of n ideals.
                   2736:  */
                   2737:
                   2738: /* given MODULES x and y by their pseudo-bases in HNF, gives a
1.2     ! noro     2739:  * pseudo-basis of the module generated by x and y. */
1.1       noro     2740: static GEN
                   2741: rnfjoinmodules(GEN nf, GEN x, GEN y)
                   2742: {
                   2743:   long i,lx,ly;
                   2744:   GEN p1,p2,z,Hx,Hy,Ix,Iy;
                   2745:
                   2746:   if (x == NULL) return y;
1.2     ! noro     2747:   Hx = (GEN)x[1]; lx = lg(Hx); Ix = (GEN)x[2];
        !          2748:   Hy = (GEN)y[1]; ly = lg(Hy); Iy = (GEN)y[2];
1.1       noro     2749:   i = lx+ly-1;
                   2750:   z = (GEN)gpmalloc(sizeof(long*)*(3+2*i));
                   2751:   *z = evaltyp(t_VEC)|evallg(3);
                   2752:   p1 =  z+3; z[1]=(long)p1; *p1 = evaltyp(t_MAT)|evallg(i);
                   2753:   p2 = p1+i; z[2]=(long)p2; *p2 = evaltyp(t_VEC)|evallg(i);
                   2754:
1.2     ! noro     2755:   for (i=1; i<lx; i++) { p1[i] = Hx[i]; p2[i] = Ix[i]; }
        !          2756:   p1 += lx-1;
        !          2757:   p2 += lx-1;
        !          2758:   for (i=1; i<ly; i++) { p1[i] = Hy[i]; p2[i] = Iy[i]; }
1.1       noro     2759:   x = nfhermite(nf,z); free(z); return x;
                   2760: }
                   2761:
1.2     ! noro     2762: typedef struct {
        !          2763:   GEN nf, multab, modpr,T,p;
        !          2764:   long h;
        !          2765: } rnfeltmod_muldata;
        !          2766:
1.1       noro     2767: static GEN
1.2     ! noro     2768: _mul(void *data, GEN x, GEN y/* base; ignored */)
1.1       noro     2769: {
1.2     ! noro     2770:   rnfeltmod_muldata *D = (rnfeltmod_muldata *) data;
        !          2771:   GEN z = x? element_mulid(D->multab,x,D->h)
        !          2772:            : element_mulidid(D->multab,D->h,D->h);
        !          2773:   (void)y;
        !          2774:   return FpVQX_red(z,D->T,D->p);
1.1       noro     2775: }
                   2776: static GEN
1.2     ! noro     2777: _sqr(void *data, GEN x)
1.1       noro     2778: {
1.2     ! noro     2779:   rnfeltmod_muldata *D = (rnfeltmod_muldata *) data;
        !          2780:   GEN z = x? sqr_by_tab(D->multab,x)
        !          2781:            : element_mulidid(D->multab,D->h,D->h);
        !          2782:   return FpVQX_red(z,D->T,D->p);
1.1       noro     2783: }
                   2784:
1.2     ! noro     2785: /* Compute x^n mod pr in the extension, assume n >= 0 */
1.1       noro     2786: static GEN
1.2     ! noro     2787: rnfelementid_powmod(GEN multab, long h, GEN n, GEN T, GEN p)
1.1       noro     2788: {
1.2     ! noro     2789:   gpmem_t av = avma;
        !          2790:   GEN y;
        !          2791:   rnfeltmod_muldata D;
        !          2792:
        !          2793:   if (!signe(n)) return gun;
1.1       noro     2794:
1.2     ! noro     2795:   D.multab = multab;
        !          2796:   D.h = h;
        !          2797:   D.T = T;
        !          2798:   D.p = p;
        !          2799:   y = leftright_pow(NULL, n, (void*)&D, &_sqr, &_mul);
1.1       noro     2800:   return gerepilecopy(av, y);
                   2801: }
                   2802:
1.2     ! noro     2803: #if 0
1.1       noro     2804: GEN
                   2805: mymod(GEN x, GEN p)
                   2806: {
                   2807:   long i,lx, tx = typ(x);
                   2808:   GEN y,p1;
                   2809:
                   2810:   if (tx == t_INT) return resii(x,p);
                   2811:   if (tx == t_FRAC)
                   2812:   {
                   2813:     p1 = resii((GEN)x[2], p);
                   2814:     if (p1 != gzero) { cgiv(p1); return gmod(x,p); }
                   2815:     return x;
                   2816:   }
                   2817:   if (!is_matvec_t(tx))
                   2818:     err(bugparier, "mymod (missing type)");
                   2819:   lx = lg(x); y = cgetg(lx,tx);
                   2820:   for (i=1; i<lx; i++) y[i] = (long)mymod((GEN)x[i],p);
                   2821:   return y;
                   2822: }
1.2     ! noro     2823: #endif
        !          2824:
        !          2825: #define FqX_div(x,y,T,p) FpXQX_divres((x),(y),(T),(p),NULL)
        !          2826: #define FqX_mul FpXQX_mul
        !          2827:
        !          2828: /* relative Dedekind criterion over nf, applied to the order defined by a
        !          2829:  * root of irreducible polynomial P, modulo the prime ideal pr. Returns
        !          2830:  * [flag,basis,val], where basis is a pseudo-basis of the enlarged order,
        !          2831:  * flag is 1 iff this order is pr-maximal, and val is the valuation at pr of
        !          2832:  * the order discriminant */
        !          2833: static GEN
        !          2834: rnfdedekind_i(GEN nf,GEN P,GEN pr, GEN disc)
        !          2835: {
        !          2836:   long vt, r, d, n, m, i, j;
        !          2837:   gpmem_t av = avma;
        !          2838:   GEN Prd,p1,p2,p,tau,g,matid;
        !          2839:   GEN modpr,res,h,k,base,nfT,T,gzk,hzk;
        !          2840:
        !          2841:   if (!disc) disc = discsr(P);
        !          2842:   P = lift(P);
        !          2843:   nf = checknf(nf); nfT = (GEN)nf[1];
        !          2844:   res = cgetg(4,t_VEC);
        !          2845:   modpr = nf_to_ff_init(nf,&pr, &T, &p);
        !          2846:   tau = gmul((GEN)nf[7], (GEN)pr[5]);
        !          2847:   n = degpol(nfT);
        !          2848:   m = degpol(P);
        !          2849:
        !          2850:   Prd = modprX(P, nf, modpr);
        !          2851:   p1 = (GEN)FqX_factor(Prd,T,p)[1];
        !          2852:   r = lg(p1); if (r < 2) err(constpoler,"rnfdedekind");
        !          2853:   g = (GEN)p1[1];
        !          2854:   for (i=2; i<r; i++) g = FqX_mul(g, (GEN)p1[i], T, p);
        !          2855:   h = FqX_div(Prd,g, T, p);
        !          2856:   gzk = modprX_lift(g, modpr);
        !          2857:   hzk = modprX_lift(h, modpr);
        !          2858:
        !          2859:   k = gsub(P, RXQX_mul(gzk,hzk, nfT));
        !          2860:   k = gdiv(RXQX_mul(tau,k,nfT), p);
        !          2861:   k = modprX(k, nf, modpr);
        !          2862:
        !          2863:   p2 = FqX_gcd(g,h,  T,p);
        !          2864:   k  = FqX_gcd(p2,k, T,p); d = degpol(k);  /* <= m */
        !          2865:
        !          2866:   vt = idealval(nf,disc,pr) - 2*d;
        !          2867:   res[3] = lstoi(vt);
        !          2868:   res[1] = (!d || vt<=1)? un: zero;
        !          2869:
        !          2870:   base = cgetg(3,t_VEC);
        !          2871:   p1 = cgetg(m+d+1,t_MAT); base[1] = (long)p1;
        !          2872:   p2 = cgetg(m+d+1,t_VEC); base[2] = (long)p2;
        !          2873:  /* if d > 0, base[2] temporarily multiplied by p, for the final nfhermitemod
        !          2874:   * [ which requires integral ideals ] */
        !          2875:   matid = gscalmat(d? p: gun, n);
        !          2876:   for (j=1; j<=m; j++)
        !          2877:   {
        !          2878:     p1[j] = (long)_ei(m, j);
        !          2879:     p2[j] = (long)matid;
        !          2880:   }
        !          2881:   if (d)
        !          2882:   {
        !          2883:     GEN prinvp = pidealprimeinv(nf,pr); /* again multiplied by p */
        !          2884:     GEN X = polx[varn(P)], pal;
        !          2885:
        !          2886:     pal = FqX_div(Prd,k, T,p);
        !          2887:     pal = modprX_lift(pal, modpr);
        !          2888:     for (   ; j<=m+d; j++)
        !          2889:     {
        !          2890:       p1[j] = (long)pol_to_vec(pal,m);
        !          2891:       p2[j] = (long)prinvp;
        !          2892:       pal = RXQX_rem(RXQX_mul(pal,X,nfT),P,nfT);
        !          2893:     }
        !          2894:     /* the modulus is integral */
        !          2895:     base = nfhermitemod(nf,base, gmul(gpowgs(p, m-d),
        !          2896:                                      idealpows(nf, prinvp, d)));
        !          2897:     base[2] = ldiv((GEN)base[2], p); /* cancel the factor p */
        !          2898:   }
        !          2899:   res[2] = (long)base; return gerepilecopy(av, res);
        !          2900: }
        !          2901:
        !          2902: GEN
        !          2903: rnfdedekind(GEN nf,GEN P0,GEN pr)
        !          2904: {
        !          2905:   return rnfdedekind_i(nf,P0,pr,NULL);
        !          2906: }
1.1       noro     2907:
                   2908: static GEN
1.2     ! noro     2909: rnfordmax(GEN nf, GEN pol, GEN pr, GEN disc)
1.1       noro     2910: {
1.2     ! noro     2911:   gpmem_t av=avma,av1,lim;
        !          2912:   long i,j,k,n,v1,v2,vpol,m,cmpt,sep;
        !          2913:   GEN p,T,q,q1,modpr,A,Aa,Aaa,A1,I,R,p1,p2,p3,multab,multabmod,Aainv;
1.1       noro     2914:   GEN pip,baseIp,baseOp,alpha,matprod,alphainv,matC,matG,vecpro,matH;
1.2     ! noro     2915:   GEN neworder,H,Hid,alphalistinv,alphalist,prhinv,nfT,id,rnfId;
1.1       noro     2916:
                   2917:   if (DEBUGLEVEL>1) fprintferr(" treating %Z\n",pr);
1.2     ! noro     2918:   modpr = nf_to_ff_init(nf,&pr,&T,&p);
        !          2919:   p1 = rnfdedekind_i(nf,pol,modpr,disc);
1.1       noro     2920:   if (gcmp1((GEN)p1[1])) return gerepilecopy(av,(GEN)p1[2]);
                   2921:
1.2     ! noro     2922:   sep = itos((GEN)p1[3]);
        !          2923:   A = gmael(p1,2,1);
        !          2924:   I = gmael(p1,2,2);
        !          2925:
        !          2926:   pip = basistoalg(nf, (GEN)pr[2]);
        !          2927:   nfT = (GEN)nf[1];
        !          2928:   n = degpol(pol); vpol = varn(pol);
        !          2929:   q = T? gpowgs(p,degpol(T)): p;
        !          2930:   q1 = q; while (cmpis(q1,n) < 0) q1 = mulii(q1,q);
        !          2931:   rnfId = idmat(degpol(pol));
        !          2932:   id    = idmat(degpol(nfT));
        !          2933:
        !          2934:   multab = cgetg(n*n+1,t_MAT);
        !          2935:   for (j=1; j<=n*n; j++) multab[j] = lgetg(n+1,t_COL);
        !          2936:   prhinv = idealinv(nf, pr);
        !          2937:   alphalistinv = cgetg(n+1,t_VEC);
        !          2938:   alphalist    = cgetg(n+1,t_VEC);
        !          2939:   A1 = cgetg(n+1,t_MAT);
        !          2940:   av1 = avma; lim = stack_lim(av1,1);
1.1       noro     2941:   for(cmpt=1; ; cmpt++)
                   2942:   {
1.2     ! noro     2943:     if (DEBUGLEVEL>1) fprintferr("    %ld%s pass\n",cmpt,eng_ord(cmpt));
        !          2944:     for (j=1; j<=n; j++)
1.1       noro     2945:     {
1.2     ! noro     2946:       if (gegal((GEN)I[j],id))
        !          2947:       {
        !          2948:         alphalist[j] = alphalistinv[j] = un;
        !          2949:         A1[j] = A[j]; continue;
        !          2950:       }
        !          2951:
        !          2952:       p1 = ideal_two_elt(nf,(GEN)I[j]);
        !          2953:       if (gcmp0((GEN)p1[1]))
        !          2954:         alpha = (GEN)p1[2];
1.1       noro     2955:       else
                   2956:       {
1.2     ! noro     2957:         v1 = element_val(nf,(GEN)p1[1],pr);
        !          2958:         v2 = element_val(nf,(GEN)p1[2],pr);
        !          2959:         alpha = (v1>v2)? (GEN)p1[2]: (GEN)p1[1];
1.1       noro     2960:       }
1.2     ! noro     2961:       alphalist[j]    = (long)alpha;
        !          2962:       alphalistinv[j] = (long)element_inv(nf,alpha);
        !          2963:
        !          2964:       p1 = cgetg(n+1,t_COL); A1[j] = (long)p1;
1.1       noro     2965:       for (i=1; i<=n; i++)
1.2     ! noro     2966:         p1[i] = (long)element_mul(nf,gcoeff(A,i,j),alpha);
1.1       noro     2967:     }
1.2     ! noro     2968:     Aa = basistoalg(nf,A1);
        !          2969:     Aainv = lift_intern(ginv(Aa));
        !          2970:     Aaa = lift_intern(mat_to_vecpol(Aa,vpol));
        !          2971:     for (i=1; i<=n; i++)
        !          2972:       for (j=i; j<=n; j++)
1.1       noro     2973:       {
1.2     ! noro     2974:         long tp;
        !          2975:         p1 = RXQX_rem(gmul((GEN)Aaa[i],(GEN)Aaa[j]), pol, nfT);
        !          2976:         tp = typ(p1);
        !          2977:         if (is_scalar_t(tp) || (tp==t_POL && varn(p1)>vpol))
        !          2978:           p2 = gmul(p1, (GEN)Aainv[1]);
        !          2979:         else
        !          2980:           p2 = mulmat_pol(Aainv, p1);
        !          2981:         for (k=1; k<=n; k++)
        !          2982:         {
        !          2983:           GEN c = gres((GEN)p2[k], nfT);
        !          2984:           coeff(multab,k,(i-1)*n+j) = (long)c;
        !          2985:           coeff(multab,k,(j-1)*n+i) = (long)c;
        !          2986:         }
1.1       noro     2987:       }
1.2     ! noro     2988:     multabmod = modprM(multab,nf,modpr);
        !          2989:     R = cgetg(n+1,t_MAT);
        !          2990:     R[1] = rnfId[1];
        !          2991:     for (j=2; j<=n; j++)
        !          2992:       R[j] = (long) rnfelementid_powmod(multabmod,j,q1,T,p);
        !          2993:     baseIp = FqM_ker(R,T,p);
        !          2994:     baseOp = lg(baseIp)==1? rnfId: FqM_suppl(baseIp,T,p);
        !          2995:     alpha = modprM_lift(baseOp, modpr);
        !          2996:     for (j=1; j<lg(baseIp); j++)
        !          2997:     {
        !          2998:       p1 = (GEN)alpha[j];
        !          2999:       for (i=1; i<=n; i++) p1[i] = (long)to_polmod((GEN)p1[i], nfT);
1.1       noro     3000:     }
                   3001:     for (   ; j<=n; j++)
                   3002:     {
1.2     ! noro     3003:       p1 = (GEN)alpha[j];
        !          3004:       for (i=1; i<=n; i++) p1[i] = lmul(pip, (GEN)p1[i]);
1.1       noro     3005:     }
1.2     ! noro     3006:     alphainv = lift_intern(ginv(alpha));
        !          3007:     alpha = lift_intern(alpha);
        !          3008:
        !          3009:     matprod = cgetg(n+1,t_MAT);
1.1       noro     3010:     for (j=1; j<=n; j++)
                   3011:     {
1.2     ! noro     3012:       p1 = cgetg(n+1,t_COL); matprod[j] = (long)p1;
1.1       noro     3013:       for (i=1; i<=n; i++)
1.2     ! noro     3014:         p1[i] = (long)gmod(element_mulid(multab, (GEN)alpha[i],j), nfT);
1.1       noro     3015:     }
                   3016:     matC = cgetg(n+1,t_MAT);
                   3017:     for (j=1; j<=n; j++)
                   3018:     {
1.2     ! noro     3019:       p1 = cgetg(n*n+1,t_COL); matC[j] = (long)p1;
1.1       noro     3020:       for (i=1; i<=n; i++)
                   3021:       {
                   3022:        p2 = gmul(alphainv, gcoeff(matprod,i,j));
                   3023:        for (k=1; k<=n; k++)
1.2     ! noro     3024:         {
        !          3025:           GEN c = gres((GEN)p2[k], nfT);
        !          3026:           p1[(i-1)*n+k] = (long)nf_to_ff(nf,c,modpr);
        !          3027:         }
1.1       noro     3028:       }
                   3029:     }
1.2     ! noro     3030:     matG = FqM_ker(matC,T,p); m = lg(matG)-1;
        !          3031:     matG = modprM_lift(matG, modpr);
        !          3032:     vecpro = cgetg(3,t_VEC);
        !          3033:     vecpro[1] = (long)concatsp(matG,rnfId);
        !          3034:
        !          3035:     p2 = cgetg(n+m+1,t_VEC);
        !          3036:     vecpro[2] = (long)p2;
        !          3037:     for (j=1; j<=m; j++) p2[j] = (long)prhinv;
1.1       noro     3038:     p2 += m;
                   3039:     for (j=1; j<=n; j++)
                   3040:       p2[j] = (long)idealmul(nf,(GEN)I[j],(GEN)alphalistinv[j]);
                   3041:
1.2     ! noro     3042:     matH = nfhermite(nf,vecpro);
        !          3043:     p1 = algtobasis(nf, gmul(Aa, basistoalg(nf,(GEN)matH[1])));
        !          3044:     p2 = (GEN)matH[2];
        !          3045:
        !          3046:     neworder = cgetg(3,t_VEC);
        !          3047:     H   = cgetg(n+1,t_MAT);
        !          3048:     Hid = cgetg(n+1,t_VEC);
1.1       noro     3049:     for (j=1; j<=n; j++)
                   3050:     {
1.2     ! noro     3051:       alphainv = (GEN)alphalistinv[j];
        !          3052:       if (alphainv == gun) { H[j] = p1[j]; Hid[j] = p2[j]; continue; }
        !          3053:
1.1       noro     3054:       p3=cgetg(n+1,t_COL); H[j]=(long)p3;
                   3055:       for (i=1; i<=n; i++)
1.2     ! noro     3056:        p3[i] = (long)element_mul(nf,gcoeff(p1,i,j),alphainv);
        !          3057:       Hid[j] = (long)idealmul(nf,(GEN)p2[j],(GEN)alphalist[j]);
1.1       noro     3058:     }
1.2     ! noro     3059:     if (DEBUGLEVEL>3) { fprintferr(" new order:\n"); outerr(H); outerr(Hid); }
1.1       noro     3060:     if (sep == 2 || gegal(I,Hid))
                   3061:     {
1.2     ! noro     3062:       neworder[1] = (long)H;
        !          3063:       neworder[2] = (long)Hid;
        !          3064:       return gerepilecopy(av, neworder);
1.1       noro     3065:     }
                   3066:
1.2     ! noro     3067:     A = H; I = Hid;
1.1       noro     3068:     if (low_stack(lim, stack_lim(av1,1)) || (cmpt & 3) == 0)
                   3069:     {
                   3070:       GEN *gptr[2]; gptr[0]=&A; gptr[1]=&I;
                   3071:       if(DEBUGMEM>1) err(warnmem,"rnfordmax");
                   3072:       gerepilemany(av1,gptr,2);
                   3073:     }
                   3074:   }
                   3075: }
                   3076:
                   3077: static void
                   3078: check_pol(GEN x, long v)
                   3079: {
1.2     ! noro     3080:   long i,tx, lx = lgef(x);
1.1       noro     3081:   if (varn(x) != v)
                   3082:     err(talker,"incorrect variable in rnf function");
                   3083:   for (i=2; i<lx; i++)
                   3084:   {
                   3085:     tx = typ(x[i]);
                   3086:     if (!is_scalar_t(tx) || tx == t_POLMOD)
                   3087:       err(talker,"incorrect polcoeff in rnf function");
                   3088:   }
                   3089: }
                   3090:
                   3091: GEN
                   3092: fix_relative_pol(GEN nf, GEN x, int chk_lead)
                   3093: {
                   3094:   GEN xnf = (typ(nf) == t_POL)? nf: (GEN)nf[1];
1.2     ! noro     3095:   long i, vnf = varn(xnf), lx = lgef(x);
1.1       noro     3096:   if (typ(x) != t_POL || varn(x) >= vnf)
                   3097:     err(talker,"incorrect polynomial in rnf function");
                   3098:   x = dummycopy(x);
                   3099:   for (i=2; i<lx; i++)
                   3100:     switch(typ(x[i]))
                   3101:     {
                   3102:       case t_POL:
                   3103:         check_pol((GEN)x[i], vnf);
                   3104:         x[i] = lmodulcp((GEN)x[i], xnf); break;
                   3105:       case t_POLMOD:
                   3106:         if (!gegal(gmael(x,i,1), xnf)) err(consister,"rnf function");
                   3107:         break;
                   3108:     }
                   3109:
                   3110:   if (chk_lead && !gcmp1(leading_term(x)))
                   3111:     err(impl,"non-monic relative polynomials");
                   3112:   return x;
                   3113: }
                   3114:
                   3115: static GEN
                   3116: rnfround2all(GEN nf, GEN pol, long all)
                   3117: {
1.2     ! noro     3118:   gpmem_t av = avma;
        !          3119:   long i,j,n,N,nbidp,vpol,*ep;
        !          3120:   GEN A,p1,p2,nfT,list,id,I,W,pseudo,y,d,D,sym,unnf,disc;
1.1       noro     3121:
1.2     ! noro     3122:   nf=checknf(nf); nfT=(GEN)nf[1]; vpol=varn(pol);
1.1       noro     3123:   pol = fix_relative_pol(nf,pol,1);
1.2     ! noro     3124:   N = degpol(nfT);
        !          3125:   n = degpol(pol);
        !          3126:   disc = discsr(pol); pol = lift(pol);
        !          3127:   list = idealfactor(nf, disc);
        !          3128:   ep  = (long*)list[2];
        !          3129:   list= (GEN)  list[1];
        !          3130:   nbidp=lg(list)-1; for(i=1;i<=nbidp;i++) ep[i] = itos((GEN)ep[i]);
1.1       noro     3131:   if (DEBUGLEVEL>1)
                   3132:   {
                   3133:     fprintferr("Ideals to consider:\n");
                   3134:     for (i=1; i<=nbidp; i++)
                   3135:       if (ep[i]>1) fprintferr("%Z^%ld\n",list[i],ep[i]);
                   3136:     flusherr();
                   3137:   }
1.2     ! noro     3138:   id = idmat(N); unnf = (GEN)id[1];
1.1       noro     3139:   pseudo = NULL;
                   3140:   for (i=1; i<=nbidp; i++)
                   3141:     if (ep[i] > 1)
                   3142:     {
1.2     ! noro     3143:       y = rnfordmax(nf, pol, (GEN)list[i], disc);
1.1       noro     3144:       pseudo = rnfjoinmodules(nf,pseudo,y);
                   3145:     }
1.2     ! noro     3146:   if (pseudo)
        !          3147:   {
        !          3148:     A = (GEN)pseudo[1];
        !          3149:     I = (GEN)pseudo[2];
        !          3150:   }
        !          3151:   else
1.1       noro     3152:   {
1.2     ! noro     3153:     I = cgetg(n+1,t_VEC); for (i=1; i<=n; i++) I[i] = (long)id;
        !          3154:     A = idmat_intern(n, unnf, zerocol(N));
1.1       noro     3155:   }
1.2     ! noro     3156:   W = mat_to_vecpol(lift_intern(basistoalg(nf,A)), vpol);
        !          3157:   sym = polsym_gen(pol, NULL, n-1, nfT, NULL);
        !          3158:   p2 = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) p2[j] = lgetg(n+1,t_COL);
1.1       noro     3159:   for (j=1; j<=n; j++)
                   3160:     for (i=j; i<=n; i++)
                   3161:     {
1.2     ! noro     3162:       p1 = RXQX_mul((GEN)W[i],(GEN)W[j], nfT);
        !          3163:       p1 = RXQX_rem(p1, pol, nfT);
        !          3164:       p1 = simplify_i(quicktrace(p1,sym));
        !          3165:       coeff(p2,j,i)=coeff(p2,i,j) = (long)p1;
1.1       noro     3166:     }
1.2     ! noro     3167:   d = algtobasis_i(nf, det(p2));
1.1       noro     3168:
1.2     ! noro     3169:   i=1; while (i<=n && gegal((GEN)I[i], id)) i++;
        !          3170:   if (i > n) D = id;
1.1       noro     3171:   else
                   3172:   {
                   3173:     D = (GEN)I[i];
                   3174:     for (i++; i<=n; i++)
1.2     ! noro     3175:       if (!gegal((GEN)I[i], id)) D = idealmul(nf,D,(GEN)I[i]);
1.1       noro     3176:     D = idealpow(nf,D,gdeux);
                   3177:   }
1.2     ! noro     3178:   p2 = core2partial(content(d));
        !          3179:   p2 = sqri((GEN)p2[2]);
        !          3180:
1.1       noro     3181:   i = all? 2: 0;
1.2     ! noro     3182:   p1=cgetg(3 + i, t_VEC);
        !          3183:   if (i) { p1[1] = lcopy(A); p1[2] = lcopy(I); }
1.1       noro     3184:   p1[1+i] = (long)idealmul(nf,D,d);
1.2     ! noro     3185:   p1[2+i] = (long)gdiv(d, p2);
        !          3186:   return gerepileupto(av,p1);
1.1       noro     3187: }
                   3188:
                   3189: GEN
                   3190: rnfpseudobasis(GEN nf, GEN pol)
                   3191: {
                   3192:   return rnfround2all(nf,pol,1);
                   3193: }
                   3194:
                   3195: GEN
                   3196: rnfdiscf(GEN nf, GEN pol)
                   3197: {
                   3198:   return rnfround2all(nf,pol,0);
                   3199: }
                   3200:
1.2     ! noro     3201: GEN
        !          3202: gen_if_principal(GEN bnf, GEN x)
        !          3203: {
        !          3204:   gpmem_t av = avma;
        !          3205:   GEN z = isprincipalall(bnf,x, nf_GEN_IF_PRINCIPAL | nf_FORCE);
        !          3206:   if (typ(z) == t_INT) { avma = av; return NULL; }
        !          3207:   return z;
        !          3208: }
        !          3209:
        !          3210: /* given bnf and a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d] it
        !          3211:  * does not matter), tries to simplify the HNF as much as possible. The
        !          3212:  * resulting matrix will be upper triangular but the diagonal coefficients
        !          3213:  * will not be equal to 1. The ideals are guaranteed to be integral and
        !          3214:  * primitive. */
1.1       noro     3215: GEN
                   3216: rnfsimplifybasis(GEN bnf, GEN order)
                   3217: {
1.2     ! noro     3218:   gpmem_t av = avma;
        !          3219:   long j, n, l;
1.1       noro     3220:   GEN p1,id,Az,Iz,nf,A,I;
                   3221:
1.2     ! noro     3222:   bnf = checkbnf(bnf); nf = (GEN)bnf[7];
1.1       noro     3223:   if (typ(order)!=t_VEC || lg(order)<3)
                   3224:     err(talker,"not a pseudo-basis in nfsimplifybasis");
1.2     ! noro     3225:   A = (GEN)order[1];
        !          3226:   I = (GEN)order[2]; n = lg(A)-1;
        !          3227:   id = idmat(degpol(nf[1]));
        !          3228:   Iz = cgetg(n+1,t_VEC);
        !          3229:   Az = cgetg(n+1,t_MAT);
1.1       noro     3230:   for (j=1; j<=n; j++)
                   3231:   {
1.2     ! noro     3232:     if (gegal((GEN)I[j],id)) { Iz[j]=(long)id; Az[j]=A[j]; continue; }
        !          3233:
        !          3234:     Iz[j] = (long)Q_primitive_part((GEN)I[j], &p1);
        !          3235:     Az[j] = p1? lmul((GEN)A[j],p1): A[j];
        !          3236:     if (p1 && gegal((GEN)Iz[j], id)) continue;
        !          3237:
        !          3238:     p1 = gen_if_principal(bnf, (GEN)Iz[j]);
        !          3239:     if (p1)
1.1       noro     3240:     {
1.2     ! noro     3241:       Iz[j] = (long)id;
        !          3242:       Az[j] = (long)element_mulvec(nf,p1,(GEN)Az[j]);
1.1       noro     3243:     }
                   3244:   }
1.2     ! noro     3245:   l = lg(order); p1 = cgetg(l, t_VEC);
        !          3246:   p1[1] = (long)Az;
        !          3247:   p1[2] = (long)Iz; for (j=3; j<l; j++) p1[j] = order[j];
        !          3248:   return gerepilecopy(av, p1);
1.1       noro     3249: }
                   3250:
                   3251: GEN
                   3252: rnfdet2(GEN nf, GEN A, GEN I)
                   3253: {
1.2     ! noro     3254:   gpmem_t av,tetpil;
        !          3255:   long i;
1.1       noro     3256:   GEN p1;
                   3257:
                   3258:   nf=checknf(nf); av = tetpil = avma;
                   3259:   p1=idealhermite(nf,det(matbasistoalg(nf,A)));
                   3260:   for(i=1;i<lg(I);i++) { tetpil=avma; p1=idealmul(nf,p1,(GEN)I[i]); }
                   3261:   tetpil=avma; return gerepile(av,tetpil,p1);
                   3262: }
                   3263:
                   3264: GEN
                   3265: rnfdet(GEN nf, GEN order)
                   3266: {
                   3267:   if (typ(order)!=t_VEC || lg(order)<3)
                   3268:     err(talker,"not a pseudo-matrix in rnfdet");
                   3269:   return rnfdet2(nf,(GEN)order[1],(GEN)order[2]);
                   3270: }
                   3271:
                   3272: GEN
                   3273: rnfdet0(GEN nf, GEN x, GEN y)
                   3274: {
                   3275:   return y? rnfdet2(nf,x,y): rnfdet(nf,x);
                   3276: }
                   3277:
1.2     ! noro     3278: /* Given two fractional ideals a and b, gives x in a, y in b, z in b^-1,
        !          3279:    t in a^-1 such that xt-yz=1. In the present version, z is in Z. */
        !          3280: static GEN
        !          3281: nfidealdet1(GEN nf, GEN a, GEN b)
        !          3282: {
        !          3283:   gpmem_t av = avma;
        !          3284:   GEN x,p1,res,u,v,da,db;
        !          3285:
        !          3286:   a = idealinv(nf,a);
        !          3287:   da = denom(a); if (!gcmp1(da)) a = gmul(da,a);
        !          3288:   db = denom(b); if (!gcmp1(db)) b = gmul(db,b);
        !          3289:   x = idealcoprime(nf,a,b);
        !          3290:   p1 = idealaddtoone(nf, idealmul(nf,x,a), b);
        !          3291:   u = (GEN)p1[1];
        !          3292:   v = (GEN)p1[2];
        !          3293:
        !          3294:   res = cgetg(5,t_VEC);
        !          3295:   res[1] = (long)gmul(x,da);
        !          3296:   res[2] = (long)gdiv(v,db);
        !          3297:   res[3] = lnegi(db);
        !          3298:   res[4] = (long)element_div(nf, u, (GEN)res[1]);
        !          3299:   return gerepilecopy(av,res);
        !          3300: }
        !          3301:
        !          3302: static GEN
        !          3303: get_order(GEN nf, GEN O, char *s)
        !          3304: {
        !          3305:   if (typ(O) == t_POL)
        !          3306:     return rnfpseudobasis(nf, O);
        !          3307:   if (typ(O)!=t_VEC || lg(O) < 3)
        !          3308:     err(talker,"not a pseudo-matrix in %s", s);
        !          3309:   return O;
        !          3310: }
        !          3311:
        !          3312: /* given a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d]), gives an
        !          3313:  * n x n matrix (not in HNF) of a pseudo-basis and an ideal vector
        !          3314:  * [id,id,...,id,I] such that order = nf[7]^(n-1) x I.
        !          3315:  * Uses the approximation theorem ==> slow. */
1.1       noro     3316: GEN
                   3317: rnfsteinitz(GEN nf, GEN order)
                   3318: {
1.2     ! noro     3319:   gpmem_t av = avma;
        !          3320:   long i,n,l;
1.1       noro     3321:   GEN Id,A,I,p1,a,b;
                   3322:
                   3323:   nf = checknf(nf);
                   3324:   Id = idmat(degpol(nf[1]));
1.2     ! noro     3325:   order = get_order(nf, order, "rnfsteinitz");
        !          3326:   A = matalgtobasis(nf, (GEN)order[1]);
        !          3327:   I = dummycopy((GEN)order[2]); n=lg(A)-1;
1.1       noro     3328:   if (typ(A) != t_MAT || typ(I) != t_VEC || lg(I) != n+1)
                   3329:     err(typeer,"rnfsteinitz");
                   3330:   for (i=1; i<n; i++)
                   3331:   {
1.2     ! noro     3332:     GEN c1,c2;
        !          3333:     a = (GEN)I[i]; if (gegal(a,Id)) continue;
        !          3334:
        !          3335:     c1 = (GEN)A[i];
        !          3336:     c2 = (GEN)A[i+1];
        !          3337:     b = (GEN)I[i+1];
        !          3338:     if (gegal(b,Id))
        !          3339:     {
        !          3340:       A[i]  = (long)c2;
        !          3341:       A[i+1]= lneg(c1);
        !          3342:       I[i]  = (long)b;
        !          3343:       I[i+1]= (long)a;
        !          3344:     }
        !          3345:     else
1.1       noro     3346:     {
1.2     ! noro     3347:       p1 = nfidealdet1(nf,a,b);
        !          3348:       A[i]  = ladd(element_mulvec(nf, (GEN)p1[1], c1),
        !          3349:                    element_mulvec(nf, (GEN)p1[2], c2));
        !          3350:       A[i+1]= ladd(element_mulvec(nf, (GEN)p1[3], c1),
        !          3351:                    element_mulvec(nf, (GEN)p1[4], c2));
        !          3352:       I[i]  = (long)Id;
        !          3353:       I[i+1]= (long)Q_primitive_part(idealmul(nf,a,b), &p1);
        !          3354:       if (p1) A[i+1] = (long)element_mulvec(nf, p1,(GEN)A[i+1]);
        !          3355:     }
        !          3356:   }
        !          3357:   l = lg(order);
        !          3358:   p1 = cgetg(l,t_VEC);
        !          3359:   p1[1]=(long)A;
        !          3360:   p1[2]=(long)I; for (i=3; i<l; i++) p1[i]=order[i];
        !          3361:   return gerepilecopy(av, p1);
1.1       noro     3362: }
                   3363:
1.2     ! noro     3364: /* Given bnf and either an order as output by rnfpseudobasis or a polynomial,
        !          3365:  * and outputs a basis if it is free, an n+1-generating set if it is not */
1.1       noro     3366: GEN
                   3367: rnfbasis(GEN bnf, GEN order)
                   3368: {
1.2     ! noro     3369:   gpmem_t av = avma;
        !          3370:   long j, n;
        !          3371:   GEN nf, A, I, cl, col, a, id;
        !          3372:
        !          3373:   bnf = checkbnf(bnf); nf = (GEN)bnf[7];
        !          3374:   id = idmat(degpol(nf[1]));
        !          3375:   order = get_order(nf, order, "rnfbasis");
        !          3376:   I = (GEN)order[2]; n = lg(I)-1;
1.1       noro     3377:   j=1; while (j<n && gegal((GEN)I[j],id)) j++;
1.2     ! noro     3378:   if (j<n)
1.1       noro     3379:   {
1.2     ! noro     3380:     order = rnfsteinitz(nf,order);
        !          3381:     I = (GEN)order[2];
1.1       noro     3382:   }
1.2     ! noro     3383:   A = (GEN)order[1];
        !          3384:   col= (GEN)A[n]; A = vecextract_i(A, 1, n-1);
        !          3385:   cl = (GEN)I[n];
        !          3386:   a = gen_if_principal(bnf, cl);
        !          3387:   if (!a)
1.1       noro     3388:   {
1.2     ! noro     3389:     GEN p1 = ideal_two_elt(nf, cl);
        !          3390:     A = concatsp(A, gmul((GEN)p1[1], col));
        !          3391:     a = (GEN)p1[2];
1.1       noro     3392:   }
1.2     ! noro     3393:   A = concatsp(A, element_mulvec(nf, a, col));
        !          3394:   return gerepilecopy(av, A);
1.1       noro     3395: }
                   3396:
1.2     ! noro     3397: /* Given bnf and either an order as output by rnfpseudobasis or a polynomial,
        !          3398:  * and outputs a basis (not pseudo) in Hermite Normal Form if it exists, zero
        !          3399:  * if not
1.1       noro     3400:  */
                   3401: GEN
                   3402: rnfhermitebasis(GEN bnf, GEN order)
                   3403: {
1.2     ! noro     3404:   gpmem_t av = avma;
        !          3405:   long j, n;
        !          3406:   GEN nf, A, I, a, id;
        !          3407:
        !          3408:   bnf = checkbnf(bnf); nf = (GEN)bnf[7];
        !          3409:   id = idmat(degpol(nf[1]));
        !          3410:   order = get_order(nf, order, "rnfbasis");
        !          3411:   A = (GEN)order[1]; A = dummycopy(A);
        !          3412:   I = (GEN)order[2]; n = lg(A)-1;
1.1       noro     3413:   for (j=1; j<=n; j++)
                   3414:   {
1.2     ! noro     3415:     if (gegal((GEN)I[j],id)) continue;
        !          3416:
        !          3417:     a = gen_if_principal(bnf, (GEN)I[j]);
        !          3418:     if (!a) { avma = av; return gzero; }
        !          3419:     A[j] = (long)element_mulvec(nf, a, (GEN)A[j]);
1.1       noro     3420:   }
                   3421:   return gerepilecopy(av,A);
                   3422: }
                   3423:
1.2     ! noro     3424: static long
        !          3425: _rnfisfree(GEN bnf, GEN order)
1.1       noro     3426: {
1.2     ! noro     3427:   long n, j;
        !          3428:   GEN nf, p1, id, I;
1.1       noro     3429:
                   3430:   bnf = checkbnf(bnf);
                   3431:   if (gcmp1(gmael3(bnf,8,1,1))) return 1;
                   3432:
1.2     ! noro     3433:   nf = (GEN)bnf[7]; id = idmat(degpol(nf[1]));
        !          3434:   order = get_order(nf, order, "rnfisfree");
        !          3435:   I = (GEN)order[2]; n = lg(I)-1;
1.1       noro     3436:   j=1; while (j<=n && gegal((GEN)I[j],id)) j++;
1.2     ! noro     3437:   if (j>n) return 1;
1.1       noro     3438:
1.2     ! noro     3439:   p1 = (GEN)I[j];
1.1       noro     3440:   for (j++; j<=n; j++)
1.2     ! noro     3441:     if (!gegal((GEN)I[j],id)) p1 = idealmul(nf,p1,(GEN)I[j]);
        !          3442:   return gcmp0( isprincipal(bnf,p1) );
        !          3443: }
        !          3444:
        !          3445: long
        !          3446: rnfisfree(GEN bnf, GEN order)
        !          3447: {
        !          3448:   gpmem_t av = avma;
        !          3449:   long n = _rnfisfree(bnf, order);
        !          3450:   avma = av; return n;
1.1       noro     3451: }
                   3452:
                   3453: /**********************************************************************/
                   3454: /**                                                                 **/
                   3455: /**                  COMPOSITUM OF TWO NUMBER FIELDS                **/
                   3456: /**                                                                 **/
                   3457: /**********************************************************************/
1.2     ! noro     3458: /* modular version */
1.1       noro     3459: GEN
                   3460: polcompositum0(GEN A, GEN B, long flall)
                   3461: {
1.2     ! noro     3462:   gpmem_t av = avma;
        !          3463:   long v, k;
1.1       noro     3464:   GEN C, LPRS;
                   3465:
                   3466:   if (typ(A)!=t_POL || typ(B)!=t_POL) err(typeer,"polcompositum0");
                   3467:   if (degpol(A)<=0 || degpol(B)<=0) err(constpoler,"compositum");
                   3468:   v = varn(A);
                   3469:   if (varn(B) != v) err(talker,"not the same variable in compositum");
                   3470:   C = content(A); if (!gcmp1(C)) A = gdiv(A, C);
                   3471:   C = content(B); if (!gcmp1(C)) B = gdiv(B, C);
                   3472:   check_pol_int(A,"compositum");
                   3473:   check_pol_int(B,"compositum");
                   3474:   if (!ZX_is_squarefree(A)) err(talker,"compositum: %Z not separable", A);
                   3475:   if (!ZX_is_squarefree(B)) err(talker,"compositum: %Z not separable", B);
                   3476:
                   3477:   k = 1; C = ZY_ZXY_resultant_all(A, B, &k, flall? &LPRS: NULL);
1.2     ! noro     3478:   C = DDF2(C, 0); /* C = Res_Y (A, B(X + kY)) guaranteed squarefree */
        !          3479:   C = sort_vecpol(C);
1.1       noro     3480:   if (flall)
                   3481:   {
                   3482:     long i,l = lg(C);
                   3483:     GEN w,a,b; /* a,b,c root of A,B,C = compositum, c = b - k a */
                   3484:     for (i=1; i<l; i++)
                   3485:     { /* invmod possibly very costly */
1.2     ! noro     3486:       a = gmul((GEN)LPRS[1], QX_invmod((GEN)LPRS[2], (GEN)C[i]));
1.1       noro     3487:       a = gneg_i(gmod(a, (GEN)C[i]));
                   3488:       b = gadd(polx[v], gmulsg(k,a));
                   3489:       w = cgetg(5,t_VEC); /* [C, a, b, n ] */
1.2     ! noro     3490:       w[1] = C[i];
1.1       noro     3491:       w[2] = (long)to_polmod(a, (GEN)w[1]);
                   3492:       w[3] = (long)to_polmod(b, (GEN)w[1]);
                   3493:       w[4] = lstoi(-k); C[i] = (long)w;
                   3494:     }
                   3495:   }
                   3496:   settyp(C, t_VEC); return gerepilecopy(av, C);
                   3497: }
                   3498:
                   3499: GEN
                   3500: compositum(GEN pol1,GEN pol2)
                   3501: {
                   3502:   return polcompositum0(pol1,pol2,0);
                   3503: }
                   3504:
                   3505: GEN
                   3506: compositum2(GEN pol1,GEN pol2)
                   3507: {
                   3508:   return polcompositum0(pol1,pol2,1);
                   3509: }
                   3510:
                   3511: int
                   3512: nfissquarefree(GEN nf, GEN x)
                   3513: {
1.2     ! noro     3514:   gpmem_t av = avma;
1.1       noro     3515:   GEN g, y = derivpol(x);
                   3516:   if (isrational(x))
                   3517:     g = modulargcd(x, y);
                   3518:   else
                   3519:     g = nfgcd(x, y, nf, NULL);
                   3520:   avma = av; return (degpol(g) == 0);
                   3521: }
                   3522:
                   3523: GEN
1.2     ! noro     3524: _rnfequation(GEN A, GEN B, long *pk, GEN *pLPRS)
1.1       noro     3525: {
1.2     ! noro     3526:   long k, lA, lB;
        !          3527:   GEN nf, C;
        !          3528:
        !          3529:   A = get_nfpol(A, &nf);
        !          3530:   B = fix_relative_pol(A,B,1);
        !          3531:   lA = lgef(A);
        !          3532:   lB = lgef(B);
1.1       noro     3533:   if (lA<=3 || lB<=3) err(constpoler,"rnfequation");
                   3534:
                   3535:   check_pol_int(A,"rnfequation");
1.2     ! noro     3536:   B = primpart(lift_intern(B));
1.1       noro     3537:   for (k=2; k<lB; k++)
                   3538:     if (lgef(B[k]) >= lA) B[k] = lres((GEN)B[k],A);
                   3539:
                   3540:   if (!nfissquarefree(A,B))
                   3541:     err(talker,"not k separable relative equation in rnfequation");
                   3542:
1.2     ! noro     3543:   *pk = 0; C = ZY_ZXY_resultant_all(A, B, pk, pLPRS);
1.1       noro     3544:   if (gsigne(leadingcoeff(C)) < 0) C = gneg_i(C);
1.2     ! noro     3545:   *pk = -*pk; return primpart(C);
        !          3546: }
        !          3547:
        !          3548: GEN
        !          3549: rnfequation0(GEN A, GEN B, long flall)
        !          3550: {
        !          3551:   gpmem_t av = avma;
        !          3552:   long k;
        !          3553:   GEN LPRS, nf, C;
        !          3554:
        !          3555:   A = get_nfpol(A, &nf);
        !          3556:   C = _rnfequation(A, B, &k, flall? &LPRS: NULL);
1.1       noro     3557:   if (flall)
                   3558:   {
1.2     ! noro     3559:     GEN w,a,b; /* a,b,c root of A,B,C = compositum, c = b + k a */
1.1       noro     3560:     /* invmod possibly very costly */
1.2     ! noro     3561:     a = gmul((GEN)LPRS[1], QX_invmod((GEN)LPRS[2], C));
1.1       noro     3562:     a = gneg_i(gmod(a, C));
1.2     ! noro     3563:     b = gadd(polx[varn(A)], gmulsg(k,a));
1.1       noro     3564:     w = cgetg(4,t_VEC); /* [C, a, n ] */
1.2     ! noro     3565:     w[1] = (long)C;
1.1       noro     3566:     w[2] = (long)to_polmod(a, (GEN)w[1]);
1.2     ! noro     3567:     w[3] = lstoi(k); C = w;
1.1       noro     3568:   }
                   3569:   return gerepilecopy(av, C);
                   3570: }
                   3571:
                   3572: GEN
                   3573: rnfequation(GEN nf,GEN pol2)
                   3574: {
                   3575:   return rnfequation0(nf,pol2,0);
                   3576: }
                   3577:
                   3578: GEN
                   3579: rnfequation2(GEN nf,GEN pol2)
                   3580: {
                   3581:   return rnfequation0(nf,pol2,1);
                   3582: }
                   3583:
                   3584: static GEN
                   3585: nftau(long r1, GEN x)
                   3586: {
                   3587:   long i, ru = lg(x);
                   3588:   GEN s;
                   3589:
                   3590:   s = r1 ? (GEN)x[1] : gmul2n(greal((GEN)x[1]),1);
                   3591:   for (i=2; i<=r1; i++) s=gadd(s,(GEN)x[i]);
                   3592:   for ( ; i<ru; i++) s=gadd(s,gmul2n(greal((GEN)x[i]),1));
                   3593:   return s;
                   3594: }
                   3595:
                   3596: static GEN
                   3597: nftocomplex(GEN nf, GEN x)
                   3598: {
                   3599:   long ru,vnf,k;
                   3600:   GEN p2,p3,ronf;
                   3601:
                   3602:   p2 = (typ(x)==t_POLMOD)? (GEN)x[2]: gmul((GEN)nf[7],x);
                   3603:   vnf=varn(nf[1]);
                   3604:   ronf=(GEN)nf[6]; ru=lg(ronf); p3=cgetg(ru,t_COL);
                   3605:   for (k=1; k<ru; k++) p3[k]=lsubst(p2,vnf,(GEN)ronf[k]);
                   3606:   return p3;
                   3607: }
                   3608:
                   3609: static GEN
                   3610: rnfscal(GEN mth, GEN xth, GEN yth)
                   3611: {
                   3612:   long n,ru,i,j,kk;
                   3613:   GEN x,y,m,res,p1,p2;
                   3614:
                   3615:   n=lg(mth)-1; ru=lg(gcoeff(mth,1,1));
                   3616:   res=cgetg(ru,t_COL);
                   3617:   for (kk=1; kk<ru; kk++)
                   3618:   {
                   3619:     m=cgetg(n+1,t_MAT);
                   3620:     for (j=1; j<=n; j++)
                   3621:     {
                   3622:       p1=cgetg(n+1,t_COL); m[j]=(long)p1;
                   3623:       for (i=1; i<=n; i++) { p2=gcoeff(mth,i,j); p1[i]=p2[kk]; }
                   3624:     }
                   3625:     x=cgetg(n+1,t_VEC);
                   3626:     for (j=1; j<=n; j++) x[j]=(long)gconj((GEN)((GEN)xth[j])[kk]);
                   3627:     y=cgetg(n+1,t_COL);
                   3628:     for (j=1; j<=n; j++) y[j]=((GEN)yth[j])[kk];
                   3629:     res[kk]=(long)gmul(x,gmul(m,y));
                   3630:   }
                   3631:   return res;
                   3632: }
                   3633:
                   3634: static GEN
                   3635: rnfdiv(GEN x, GEN y)
                   3636: {
                   3637:   long i, ru = lg(x);
1.2     ! noro     3638:   GEN z = cgetg(ru,t_COL);
1.1       noro     3639:
                   3640:   for (i=1; i<ru; i++) z[i]=(long)gdiv((GEN)x[i],(GEN)y[i]);
                   3641:   return z;
                   3642: }
                   3643:
                   3644: static GEN
                   3645: rnfmul(GEN x, GEN y)
                   3646: {
                   3647:   long i, ru = lg(x);
1.2     ! noro     3648:   GEN z = cgetg(ru,t_COL);
1.1       noro     3649:
                   3650:   for (i=1; i<ru; i++) z[i]=(long)gmul((GEN)x[i],(GEN)y[i]);
                   3651:   return z;
                   3652: }
                   3653:
                   3654: static GEN
                   3655: rnfvecmul(GEN x, GEN v)
                   3656: {
                   3657:   long i, lx = lg(v);
1.2     ! noro     3658:   GEN y = cgetg(lx,typ(v));
1.1       noro     3659:
                   3660:   for (i=1; i<lx; i++) y[i]=(long)rnfmul(x,(GEN)v[i]);
                   3661:   return y;
                   3662: }
                   3663:
                   3664: static GEN
1.2     ! noro     3665: allonge(GEN v, long l)
1.1       noro     3666: {
1.2     ! noro     3667:   long r, r2, i;
        !          3668:   GEN y = cgetg(l,t_COL);
1.1       noro     3669:
1.2     ! noro     3670:   r = lg(v); r2 = l-r;
        !          3671:   for (i=1; i < r; i++) y[i] = v[i];
        !          3672:   for (   ; i < l; i++) y[i] = lconj((GEN)v[i-r2]);
1.1       noro     3673:   return y;
                   3674: }
                   3675:
                   3676: static GEN
                   3677: findmin(GEN nf, GEN ideal, GEN muf,long prec)
                   3678: {
1.2     ! noro     3679:   gpmem_t av = avma;
        !          3680:   long i, l;
        !          3681:   GEN m,y, G = gmael(nf,5,2);
1.1       noro     3682:
1.2     ! noro     3683:   m = gmul(G, ideal);
        !          3684:   m = lllintern(m,4,1,prec);
1.1       noro     3685:   if (!m)
                   3686:   {
1.2     ! noro     3687:     ideal = lllint_ip(ideal,4);
        !          3688:     m = gmul(G, ideal);
        !          3689:     m = lllintern(m,4,1,prec);
1.1       noro     3690:     if (!m) err(precer,"rnflllgram");
                   3691:   }
1.2     ! noro     3692:   ideal = gmul(ideal,m);
        !          3693:   l = lg(ideal); y = cgetg(l,t_MAT);
        !          3694:   for (i=1; i<l; i++)
        !          3695:     y[i] = (long)allonge(nftocomplex(nf,(GEN)ideal[i]),l);
        !          3696:   m = ground(greal(gauss(y, allonge(muf,l))));
        !          3697:   return gerepileupto(av, gmul(ideal,m));
1.1       noro     3698: }
                   3699:
                   3700: #define swap(x,y) { long _t=x; x=y; y=_t; }
                   3701:
                   3702: /* given a base field nf (e.g main variable y), a polynomial pol with
                   3703:  * coefficients in nf    (e.g main variable x), and an order as output
                   3704:  * by rnfpseudobasis, outputs a reduced order.
                   3705:  */
                   3706: GEN
                   3707: rnflllgram(GEN nf, GEN pol, GEN order,long prec)
                   3708: {
1.2     ! noro     3709:   gpmem_t av=avma,tetpil;
        !          3710:   long i,j,k,l,kk,kmax,r1,ru,lx,vnf;
1.1       noro     3711:   GEN p1,p2,M,I,U,ronf,poll,unro,roorder,powreorder,mth,s,MC,MPOL,MCS;
                   3712:   GEN B,mu,Bf,temp,ideal,x,xc,xpol,muf,mufc,muno,y,z,Ikk_inv;
                   3713:
                   3714: /* Initializations and verifications */
                   3715:
                   3716:   nf=checknf(nf);
                   3717:   if (typ(order)!=t_VEC || lg(order)<3)
                   3718:     err(talker,"not a pseudo-matrix in rnflllgram");
                   3719:   M=(GEN)order[1]; I=(GEN)order[2]; lx=lg(I);
                   3720:   if (lx < 3) return gcopy(order);
                   3721:   if (lx-1 != degpol(pol)) err(consister,"rnflllgram");
                   3722:   U=idmat(lx-1); I = dummycopy(I);
                   3723:
                   3724: /* Compute the relative T2 matrix of powers of theta */
                   3725:
                   3726:   vnf=varn(nf[1]); ronf=(GEN)nf[6]; ru=lg(ronf); poll=lift(pol);
                   3727:   r1 = nf_get_r1(nf);
                   3728:   unro=cgetg(lx,t_COL); for (i=1; i<lx; i++) unro[i]=un;
                   3729:   roorder=cgetg(ru,t_VEC);
                   3730:   for (i=1; i<ru; i++)
                   3731:     roorder[i]=lroots(gsubst(poll,vnf,(GEN)ronf[i]),prec);
                   3732:   powreorder=cgetg(lx,t_MAT);
                   3733:   p1=cgetg(ru,t_COL); powreorder[1]=(long)p1;
                   3734:   for (i=1; i<ru; i++) p1[i]=(long)unro;
                   3735:   for (k=2; k<lx; k++)
                   3736:   {
                   3737:     p1=cgetg(ru,t_COL); powreorder[k]=(long)p1;
                   3738:     for (i=1; i<ru; i++)
                   3739:     {
                   3740:       p2=cgetg(lx,t_COL); p1[i]=(long)p2;
                   3741:       for (j=1; j<lx; j++)
                   3742:        p2[j] = lmul(gmael(roorder,i,j),gmael3(powreorder,k-1,i,j));
                   3743:     }
                   3744:   }
                   3745:   mth=cgetg(lx,t_MAT);
                   3746:   for (l=1; l<lx; l++)
                   3747:   {
                   3748:     p1=cgetg(lx,t_COL); mth[l]=(long)p1;
                   3749:     for (k=1; k<lx; k++)
                   3750:     {
                   3751:       p2=cgetg(ru,t_COL); p1[k]=(long)p2;
                   3752:       for (i=1; i<ru; i++)
                   3753:       {
                   3754:        s=gzero;
                   3755:        for (j=1; j<lx; j++)
                   3756:          s = gadd(s,gmul(gconj(gmael3(powreorder,k,i,j)),
                   3757:                          gmael3(powreorder,l,i,j)));
                   3758:        p2[i]=(long)s;
                   3759:       }
                   3760:     }
                   3761:   }
                   3762:
                   3763: /* Transform the matrix M into a matrix with coefficients in K and also
                   3764:    with coefficients polymod */
                   3765:
                   3766:   MC=cgetg(lx,t_MAT); MPOL=cgetg(lx,t_MAT);
                   3767:   for (j=1; j<lx; j++)
                   3768:   {
                   3769:     p1=cgetg(lx,t_COL); MC[j]=(long)p1;
                   3770:     p2=cgetg(lx,t_COL); MPOL[j]=(long)p2;
                   3771:     for (i=1; i<lx; i++)
                   3772:     {
                   3773:       p2[i]=(long)basistoalg(nf,gcoeff(M,i,j));
                   3774:       p1[i]=(long)nftocomplex(nf,(GEN)p2[i]);
                   3775:     }
                   3776:   }
                   3777:   MCS=cgetg(lx,t_MAT);
                   3778:
                   3779: /* Start LLL algorithm */
                   3780:
                   3781:   mu=cgetg(lx,t_MAT); B=cgetg(lx,t_COL);
                   3782:   for (j=1; j<lx; j++)
                   3783:   {
                   3784:     p1=cgetg(lx,t_COL); mu[j]=(long)p1; for (i=1; i<lx; i++) p1[i]=zero;
                   3785:     B[j]=zero;
                   3786:   }
                   3787:   kk=2; if (DEBUGLEVEL) fprintferr("kk = %ld ",kk);
                   3788:   kmax=1; B[1]=lreal(rnfscal(mth,(GEN)MC[1],(GEN)MC[1]));
                   3789:   MCS[1]=lcopy((GEN)MC[1]);
                   3790:   do
                   3791:   {
                   3792:     if (kk>kmax)
                   3793:     {
                   3794: /* Incremental Gram-Schmidt */
                   3795:       kmax=kk; MCS[kk]=lcopy((GEN)MC[kk]);
                   3796:       for (j=1; j<kk; j++)
                   3797:       {
                   3798:        coeff(mu,kk,j) = (long) rnfdiv(rnfscal(mth,(GEN)MCS[j],(GEN)MC[kk]),
                   3799:                                      (GEN) B[j]);
                   3800:        MCS[kk] = lsub((GEN) MCS[kk], rnfvecmul(gcoeff(mu,kk,j),(GEN)MCS[j]));
                   3801:       }
                   3802:       B[kk] = lreal(rnfscal(mth,(GEN)MCS[kk],(GEN)MCS[kk]));
                   3803:       if (gcmp0((GEN)B[kk])) err(lllger3);
                   3804:     }
                   3805:
                   3806: /* RED(k,k-1) */
                   3807:     l=kk-1; Ikk_inv=idealinv(nf, (GEN)I[kk]);
                   3808:     ideal=idealmul(nf,(GEN)I[l],Ikk_inv);
                   3809:     x=findmin(nf,ideal,gcoeff(mu,kk,l),2*prec-2);
                   3810:     if (!gcmp0(x))
                   3811:     {
                   3812:       xpol=basistoalg(nf,x); xc=nftocomplex(nf,xpol);
                   3813:       MC[kk]=lsub((GEN)MC[kk],rnfvecmul(xc,(GEN)MC[l]));
                   3814:       U[kk]=lsub((GEN)U[kk],gmul(xpol,(GEN)U[l]));
                   3815:       coeff(mu,kk,l)=lsub(gcoeff(mu,kk,l),xc);
                   3816:       for (i=1; i<l; i++)
                   3817:        coeff(mu,kk,i)=lsub(gcoeff(mu,kk,i),rnfmul(xc,gcoeff(mu,l,i)));
                   3818:     }
                   3819: /* Test LLL condition */
                   3820:     p1=nftau(r1,gadd((GEN) B[kk],
                   3821:                      gmul(gnorml2(gcoeff(mu,kk,kk-1)),(GEN)B[kk-1])));
                   3822:     p2=gdivgs(gmulsg(9,nftau(r1,(GEN)B[kk-1])),10);
                   3823:     if (gcmp(p1,p2)<=0)
                   3824:     {
                   3825: /* Execute SWAP(k) */
                   3826:       k=kk;
                   3827:       swap(MC[k-1],MC[k]);
                   3828:       swap(U[k-1],U[k]);
                   3829:       swap(I[k-1],I[k]);
                   3830:       for (j=1; j<=k-2; j++) swap(coeff(mu,k-1,j),coeff(mu,k,j));
                   3831:       muf=gcoeff(mu,k,k-1);
                   3832:       mufc=gconj(muf); muno=greal(rnfmul(muf,mufc));
                   3833:       Bf=gadd((GEN)B[k],rnfmul(muno,(GEN)B[k-1]));
                   3834:       p1=rnfdiv((GEN)B[k-1],Bf);
                   3835:       coeff(mu,k,k-1)=(long)rnfmul(mufc,p1);
                   3836:       temp=(GEN)MCS[k-1];
                   3837:       MCS[k-1]=ladd((GEN)MCS[k],rnfvecmul(muf,(GEN)MCS[k-1]));
                   3838:       MCS[k]=lsub(rnfvecmul(rnfdiv((GEN)B[k],Bf),temp),
                   3839:                  rnfvecmul(gcoeff(mu,k,k-1),(GEN)MCS[k]));
                   3840:       B[k]=(long)rnfmul((GEN)B[k],p1); B[k-1]=(long)Bf;
                   3841:       for (i=k+1; i<=kmax; i++)
                   3842:       {
                   3843:        temp=gcoeff(mu,i,k);
                   3844:        coeff(mu,i,k)=lsub(gcoeff(mu,i,k-1),rnfmul(muf,gcoeff(mu,i,k)));
                   3845:        coeff(mu,i,k-1) = ladd(temp, rnfmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k)));
                   3846:       }
                   3847:       if (kk>2) { kk--; if (DEBUGLEVEL) fprintferr("%ld ",kk); }
                   3848:     }
                   3849:     else
                   3850:     {
                   3851:       for (l=kk-2; l; l--)
                   3852:       {
                   3853: /* RED(k,l) */
                   3854:        ideal=idealmul(nf,(GEN)I[l],Ikk_inv);
                   3855:        x=findmin(nf,ideal,gcoeff(mu,kk,l),2*prec-2);
                   3856:        if (!gcmp0(x))
                   3857:        {
                   3858:           xpol=basistoalg(nf,x); xc=nftocomplex(nf,xpol);
                   3859:          MC[kk]=(long)gsub((GEN)MC[kk],rnfvecmul(xc,(GEN)MC[l]));
                   3860:          U[kk]=(long)gsub((GEN)U[kk],gmul(xpol,(GEN)U[l]));
                   3861:          coeff(mu,kk,l)=lsub(gcoeff(mu,kk,l),xc);
                   3862:          for (i=1; i<l; i++)
                   3863:            coeff(mu,kk,i) = lsub(gcoeff(mu,kk,i), rnfmul(xc,gcoeff(mu,l,i)));
                   3864:        }
                   3865:       }
                   3866:       kk++; if (DEBUGLEVEL) fprintferr("%ld ",kk);
                   3867:     }
                   3868:   }
                   3869:   while (kk<lx);
                   3870:   if (DEBUGLEVEL) fprintferr("\n");
                   3871:   p1=gmul(MPOL,U); tetpil=avma;
                   3872:   y=cgetg(3,t_VEC); z=cgetg(3,t_VEC); y[1]=(long)z;
                   3873:   z[2]=lcopy(I); z[1]=(long)algtobasis(nf,p1);
                   3874:   y[2]=(long)algtobasis(nf,U);
                   3875:   return gerepile(av,tetpil,y);
                   3876: }
                   3877:
                   3878: GEN
                   3879: rnfpolred(GEN nf, GEN pol, long prec)
                   3880: {
1.2     ! noro     3881:   gpmem_t av = avma;
        !          3882:   long i, j, n, v = varn(pol);
        !          3883:   GEN id, al, w, I, O, bnf;
1.1       noro     3884:
                   3885:   if (typ(pol)!=t_POL) err(typeer,"rnfpolred");
1.2     ! noro     3886:   bnf = nf; nf = checknf(bnf);
        !          3887:   bnf = (nf == bnf)? NULL: checkbnf(bnf);
        !          3888:   if (degpol(pol) <= 1) return _vec(polx[v]);
        !          3889:
        !          3890:   id = rnfpseudobasis(nf,pol);
1.1       noro     3891:   if (bnf && gcmp1(gmael3(bnf,8,1,1))) /* if bnf is principal */
                   3892:   {
1.2     ! noro     3893:     GEN newI, newO, zk = idmat(degpol(nf[1]));
        !          3894:     O = (GEN)id[1];
        !          3895:     I = (GEN)id[2]; n = lg(I)-1;
        !          3896:     newI = cgetg(n+1,t_VEC);
        !          3897:     newO = cgetg(n+1,t_MAT);
1.1       noro     3898:     for (j=1; j<=n; j++)
                   3899:     {
1.2     ! noro     3900:       newI[j] = (long)zk; al = gen_if_principal(bnf,(GEN)I[j]);
        !          3901:       newO[j] = (long)element_mulvec(nf, al, (GEN)O[j]);
1.1       noro     3902:     }
1.2     ! noro     3903:     id = cgetg(3,t_VEC);
        !          3904:     id[1] = (long)newO;
        !          3905:     id[2] = (long)newI;
1.1       noro     3906:   }
1.2     ! noro     3907:
        !          3908:   id = (GEN)rnflllgram(nf,pol,id,prec)[1];
        !          3909:   O = (GEN)id[1];
        !          3910:   I = (GEN)id[2]; n = lg(I)-1;
        !          3911:   w = cgetg(n+1,t_VEC);
        !          3912:   pol = lift(pol);
1.1       noro     3913:   for (j=1; j<=n; j++)
                   3914:   {
1.2     ! noro     3915:     GEN p1, newpol;
        !          3916:
        !          3917:     p1 = (GEN)I[j]; al = gmul(gcoeff(p1,1,1),(GEN)O[j]);
        !          3918:     p1 = basistoalg(nf,(GEN)al[n]);
1.1       noro     3919:     for (i=n-1; i; i--)
1.2     ! noro     3920:       p1 = gadd(basistoalg(nf,(GEN)al[i]), gmul(polx[v],p1));
        !          3921:     p1 = gmodulcp(gtovec(caract2(pol,lift(p1),v)), (GEN)nf[1]);
        !          3922:     newpol = gtopoly(p1, v);
        !          3923:
1.1       noro     3924:     p1 = ggcd(newpol, derivpol(newpol));
1.2     ! noro     3925:     if (degpol(p1) > 0)
1.1       noro     3926:     {
1.2     ! noro     3927:       newpol = gdiv(newpol, p1);
        !          3928:       newpol = gdiv(newpol, leading_term(newpol));
1.1       noro     3929:     }
1.2     ! noro     3930:     w[j] = (long)newpol;
1.1       noro     3931:   }
                   3932:   return gerepilecopy(av,w);
                   3933: }
                   3934:
                   3935: /* given a relative polynomial pol over nf, compute a pseudo-basis for the
                   3936:  * extension, then an absolute basis */
1.2     ! noro     3937: static GEN
        !          3938: makebasis(GEN nf, GEN pol, GEN rnfeq)
1.1       noro     3939: {
1.2     ! noro     3940:   GEN elts,ids,polabs,plg,plg0,B,bs,p1,den,vbs,d,vpro;
        !          3941:   gpmem_t av = avma;
        !          3942:   long n,N,m,i,j,k, v = varn(pol);
        !          3943:
        !          3944:   polabs= (GEN)rnfeq[1];
        !          3945:   plg   = (GEN)rnfeq[2]; plg = lift_intern(plg);
        !          3946:   p1 = rnfpseudobasis(nf,pol);
1.1       noro     3947:   elts= (GEN)p1[1];
                   3948:   ids = (GEN)p1[2];
1.2     ! noro     3949:   if (DEBUGLEVEL>1) fprintferr("relative basis computed\n");
        !          3950:   N = degpol(pol);
        !          3951:   n = degpol(nf[1]); m = n*N;
        !          3952:
        !          3953:   plg0= Q_remove_denom(plg, &den); /* plg = plg0/den */
        !          3954:   /* nf = K = Q(a), vbs[i+1] = a^i as an elt of L = Q[X] / polabs */
        !          3955:   vbs = RXQ_powers(plg0, polabs, n-1);
        !          3956:   if (den)
        !          3957:   { /* restore denominators */
        !          3958:     vbs[2] = (long)plg; d = den;
        !          3959:     for (i=3; i<=n; i++) { d = mulii(d,den); vbs[i] = ldiv((GEN)vbs[i], d); }
        !          3960:   }
        !          3961:
        !          3962:   /* bs = integer basis of K, as elements of L */
1.1       noro     3963:   bs = gmul(vbs, vecpol_to_mat((GEN)nf[7],n));
                   3964:
1.2     ! noro     3965:   vpro = cgetg(N+1,t_VEC);
        !          3966:   for (i=1; i<=N; i++) vpro[i] = lpowgs(polx[v], i-1);
        !          3967:   vpro = gmul(vpro, elts);
        !          3968:   B = cgetg(m+1, t_MAT);
        !          3969:   for(i=k=1; i<=N; i++)
        !          3970:   {
        !          3971:     GEN w = element_mulvec(nf, (GEN)vpro[i], (GEN)ids[i]);
        !          3972:     for(j=1; j<=n; j++)
        !          3973:     {
        !          3974:       p1 = gres(gmul(bs, (GEN)w[j]), polabs);
        !          3975:       B[k++] = (long)pol_to_vec(p1, m);
        !          3976:     }
        !          3977:   }
        !          3978:   B = Q_remove_denom(B, &den);
        !          3979:   if (den) { B = hnfmodid(B, den); B = gdiv(B, den); } else B = idmat(m);
        !          3980:   p1 = cgetg(3,t_VEC);
        !          3981:   p1[1] = (long)polabs;
        !          3982:   p1[2] = (long)B; return gerepilecopy(av, p1);
        !          3983: }
        !          3984:
        !          3985: /* relative polredabs. Returns relative polynomial by default (flag = 0)
        !          3986:  * flag & nf_ORIG: + element (base change)
        !          3987:  * flag & nf_ADDZK: + integer basis
        !          3988:  * flag & nf_ABSOLUTE: absolute polynomial */
        !          3989: GEN
        !          3990: rnfpolredabs(GEN nf, GEN relpol, long flag)
        !          3991: {
        !          3992:   GEN red, bas, z, elt, POL, pol, T, a;
        !          3993:   long v, fl;
        !          3994:   gpmem_t av = avma;
        !          3995:
        !          3996:   if (typ(relpol)!=t_POL) err(typeer,"rnfpolredabs");
        !          3997:   nf = checknf(nf); v = varn(relpol);
        !          3998:   if (DEBUGLEVEL>1) (void)timer2();
        !          3999:   relpol = unifpol(nf,relpol,1);
        !          4000:   T = (GEN)nf[1];
        !          4001:   if ((flag & nf_ADDZK) && (flag != (nf_ADDZK|nf_ABSOLUTE)))
        !          4002:     err(impl,"this combination of flags in rnfpolredabs");
        !          4003:   fl = (flag & nf_ADDZK)? nf_ORIG: nf_RAW;
        !          4004:   if (flag & nf_PARTIALFACT)
        !          4005:   {
        !          4006:     long sa;
        !          4007:     bas = NULL; /* -Wall */
        !          4008:     POL = _rnfequation(nf, relpol, &sa, NULL);
        !          4009:     red = polredabs0(POL, fl | nf_PARTIALFACT);
        !          4010:     a = stoi(sa);
        !          4011:   }
        !          4012:   else
        !          4013:   {
        !          4014:     GEN rel, eq = rnfequation2(nf,relpol);
        !          4015:     POL = (GEN)eq[1];
        !          4016:     a   = (GEN)eq[3];
        !          4017:     rel = poleval(relpol, gsub(polx[v],
        !          4018:                                gmul(a, gmodulcp(polx[varn(T)],T))));
        !          4019:     bas = makebasis(nf, rel, eq);
        !          4020:     if (DEBUGLEVEL>1)
        !          4021:     {
        !          4022:       msgtimer("absolute basis");
        !          4023:       fprintferr("original absolute generator: %Z\n", POL);
        !          4024:     }
        !          4025:     red = polredabs0(bas, fl);
        !          4026:   }
        !          4027:   pol = (GEN)red[1];
        !          4028:   if (DEBUGLEVEL>1) fprintferr("reduced absolute generator: %Z\n",pol);
        !          4029:   if (flag & nf_ABSOLUTE)
1.1       noro     4030:   {
1.2     ! noro     4031:     if (flag & nf_ADDZK)
        !          4032:     {
        !          4033:       GEN t = (GEN)red[2], B = (GEN)bas[2];
        !          4034:       GEN v = RXQ_powers(lift_intern(t), pol, degpol(pol)-1);
        !          4035:       z = cgetg(3, t_VEC);
        !          4036:       z[1] = (long)pol;
        !          4037:       z[2] = lmul(v, B);
        !          4038:       return gerepilecopy(av, z);
        !          4039:     }
        !          4040:     return gerepilecopy(av, pol);
        !          4041:   }
        !          4042:
        !          4043:   elt = eltabstorel((GEN)red[2], T, relpol, a);
        !          4044:
        !          4045:   pol = rnfcharpoly(nf,relpol,elt,v);
        !          4046:   if (!(flag & nf_ORIG)) return gerepileupto(av, pol);
        !          4047:   z = cgetg(3,t_VEC);
        !          4048:   z[1] = (long)pol;
        !          4049:   z[2] = (long)to_polmod(modreverse_i((GEN)elt[2],(GEN)elt[1]), pol);
        !          4050:   return gerepilecopy(av, z);
1.1       noro     4051: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>