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

Annotation of OpenXM_contrib/pari-2.2/src/basemath/polarit3.c, Revision 1.1.1.1

1.1       noro        1: /* $Id: polarit3.c,v 1.82 2001/10/01 17:19:06 bill Exp $
                      2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /***********************************************************************/
                     17: /**                                                                   **/
                     18: /**               ARITHMETIC OPERATIONS ON POLYNOMIALS                **/
                     19: /**                         (third part)                              **/
                     20: /**                                                                   **/
                     21: /***********************************************************************/
                     22: #include "pari.h"
                     23:
                     24: #define lswap(x,y) {long _z=x; x=y; y=_z;}
                     25: #define pswap(x,y) {GEN *_z=x; x=y; y=_z;}
                     26: #define swap(x,y)  {GEN  _z=x; x=y; y=_z;}
                     27: #define swapspec(x,y, nx,ny) {swap(x,y); lswap(nx,ny);}
                     28: /* 2p^2 < 2^BITS_IN_LONG */
                     29: #ifdef LONG_IS_64BIT
                     30: #  define u_OK_ULONG(p) ((ulong)p <= 3037000493UL)
                     31: #else
                     32: #  define u_OK_ULONG(p) ((ulong)p <= 46337UL)
                     33: #endif
                     34: #define OK_ULONG(p) (lgefint(p) == 3 && u_OK_ULONG(p[2]))
                     35:
                     36: /*******************************************************************/
                     37: /*                                                                 */
                     38: /*                  KARATSUBA (for polynomials)                    */
                     39: /*                                                                 */
                     40: /*******************************************************************/
                     41:
                     42: #if 1 /* for tunings */
                     43: long SQR_LIMIT = 6;
                     44: long MUL_LIMIT = 10;
                     45: long u_SQR_LIMIT = 6;
                     46: long u_MUL_LIMIT = 10;
                     47:
                     48: void
                     49: setsqpol(long a) { SQR_LIMIT=a; u_SQR_LIMIT=a; }
                     50: void
                     51: setmulpol(long a) { MUL_LIMIT=a; u_MUL_LIMIT=a; }
                     52:
                     53: GEN
                     54: u_specpol(GEN x, long nx)
                     55: {
                     56:   GEN z = cgetg(nx+2,t_POL);
                     57:   long i;
                     58:   for (i=0; i<nx; i++) z[i+2] = lstoi(x[i]);
                     59:   z[1]=evalsigne(1)|evallgef(nx+2);
                     60:   return z;
                     61: }
                     62:
                     63: GEN
                     64: specpol(GEN x, long nx)
                     65: {
                     66:   GEN z = cgetg(nx+2,t_POL);
                     67:   long i;
                     68:   for (i=0; i<nx; i++) z[i+2] = x[i];
                     69:   z[1]=evalsigne(1)|evallgef(nx+2);
                     70:   return z;
                     71: }
                     72: #else
                     73: #  define SQR_LIMIT 6
                     74: #  define MUL_LIMIT 10
                     75: #endif
                     76:
                     77: #ifndef HIGHWORD
                     78: #  define HIGHWORD(a) ((a) >> BITS_IN_HALFULONG)
                     79: #endif
                     80:
                     81: /* multiplication in Fp[X], p small */
                     82:
                     83: static GEN
                     84: u_normalizepol(GEN x, long lx)
                     85: {
                     86:   long i;
                     87:   for (i=lx-1; i>1; i--)
                     88:     if (x[i]) break;
                     89:   setlgef(x,i+1);
                     90:   setsigne(x, (i > 1)); return x;
                     91: }
                     92:
                     93: GEN
                     94: u_FpX_deriv(GEN z, ulong p)
                     95: {
                     96:   long i,l = lgef(z)-1;
                     97:   GEN x;
                     98:   if (l < 2) l = 2;
                     99:   x = cgetg(l,t_VECSMALL); x[1] = z[1]; z++;
                    100:   if (HIGHWORD(l | p))
                    101:     for (i=2; i<l; i++) x[i] = mulssmod(i-1, z[i], p);
                    102:   else
                    103:     for (i=2; i<l; i++) x[i] = ((i-1) * z[i]) % p;
                    104:   return u_normalizepol(x,l);
                    105: }
                    106:
                    107: static GEN
                    108: u_FpX_gcd_i(GEN a, GEN b, ulong p)
                    109: {
                    110:   GEN c;
                    111:   if (lgef(b) > lgef(a)) swap(a, b);
                    112:   while (signe(b))
                    113:   {
                    114:     c = u_FpX_rem(a,b,p);
                    115:     a = b; b = c;
                    116:   }
                    117:   return a;
                    118: }
                    119:
                    120: GEN
                    121: u_FpX_gcd(GEN a, GEN b, ulong p)
                    122: {
                    123:   ulong av = avma;
                    124:   return gerepileupto(av, u_FpX_gcd_i(a,b,p));
                    125: }
                    126:
                    127: int
                    128: u_FpX_is_squarefree(GEN z, ulong p)
                    129: {
                    130:   ulong av = avma;
                    131:   GEN d = u_FpX_gcd_i(z, u_FpX_deriv(z,p) , p);
                    132:   avma = av; return (degpol(d) == 0);
                    133: }
                    134:
                    135: static GEN
                    136: u_FpX_addspec(GEN x, GEN y, long p, long lx, long ly)
                    137: {
                    138:   long i,lz;
                    139:   GEN z;
                    140:
                    141:   if (ly>lx) swapspec(x,y, lx,ly);
                    142:   lz = lx+2; z = cgetg(lz,t_VECSMALL) + 2;
                    143:   for (i=0; i<ly; i++) z[i] = addssmod(x[i],y[i],p);
                    144:   for (   ; i<lx; i++) z[i] = x[i];
                    145:   z -= 2; z[1]=0; return u_normalizepol(z, lz);
                    146: }
                    147:
                    148: #ifdef INLINE
                    149: INLINE
                    150: #endif
                    151: ulong
                    152: u_FpX_mullimb(GEN x, GEN y, ulong p, long a, long b)
                    153: {
                    154:   ulong p1 = 0;
                    155:   long i;
                    156:   for (i=a; i<b; i++)
                    157:     if (y[i])
                    158:     {
                    159:       p1 += y[i] * x[-i];
                    160:       if (p1 & HIGHBIT) p1 %= p;
                    161:     }
                    162:   return p1 % p;
                    163: }
                    164:
                    165: ulong
                    166: u_FpX_mullimb_safe(GEN x, GEN y, ulong p, long a, long b)
                    167: {
                    168:   ulong p1 = 0;
                    169:   long i;
                    170:   for (i=a; i<b; i++)
                    171:     if (y[i])
                    172:       p1 = addssmod(p1, mulssmod(y[i],x[-i],p), p);
                    173:   return p1;
                    174: }
                    175:
                    176: /* assume nx >= ny > 0 */
                    177: static GEN
                    178: s_FpX_mulspec(GEN x, GEN y, ulong p, long nx, long ny)
                    179: {
                    180:   long i,lz,nz;
                    181:   GEN z;
                    182:
                    183:   lz = nx+ny+1; nz = lz-2;
                    184:   z = cgetg(lz, t_VECSMALL) + 2; /* x:y:z [i] = term of degree i */
                    185:   if (u_OK_ULONG(p))
                    186:   {
                    187:     for (i=0; i<ny; i++)z[i] = (long)u_FpX_mullimb(x+i,y,p,0,i+1);
                    188:     for (  ; i<nx; i++) z[i] = (long)u_FpX_mullimb(x+i,y,p,0,ny);
                    189:     for (  ; i<nz; i++) z[i] = (long)u_FpX_mullimb(x+i,y,p,i-nx+1,ny);
                    190:   }
                    191:   else
                    192:   {
                    193:     for (i=0; i<ny; i++)z[i] = (long)u_FpX_mullimb_safe(x+i,y,p,0,i+1);
                    194:     for (  ; i<nx; i++) z[i] = (long)u_FpX_mullimb_safe(x+i,y,p,0,ny);
                    195:     for (  ; i<nz; i++) z[i] = (long)u_FpX_mullimb_safe(x+i,y,p,i-nx+1,ny);
                    196:   }
                    197:   z -= 2; z[1]=0; return u_normalizepol(z, lz);
                    198: }
                    199:
                    200: /* return (x * X^d) + y. Assume d > 0, x > 0 and y >= 0 */
                    201: GEN
                    202: u_FpX_addshift(GEN x, GEN y, ulong p, long d)
                    203: {
                    204:   GEN xd,yd,zd = (GEN)avma;
                    205:   long a,lz,ny = lgef(y)-2, nx = lgef(x)-2;
                    206:
                    207:   x += 2; y += 2; a = ny-d;
                    208:   if (a <= 0)
                    209:   {
                    210:     lz = (a>nx)? ny+2: nx+d+2;
                    211:     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
                    212:     while (xd > x) *--zd = *--xd;
                    213:     x = zd + a;
                    214:     while (zd > x) *--zd = 0;
                    215:   }
                    216:   else
                    217:   {
                    218:     xd = new_chunk(d); yd = y+d;
                    219:     x = u_FpX_addspec(x,yd,p, nx,a);
                    220:     lz = (a>nx)? ny+2: lgef(x)+d;
                    221:     x += 2; while (xd > x) *--zd = *--xd;
                    222:   }
                    223:   while (yd > y) *--zd = *--yd;
                    224:   *--zd = evalsigne(1) | evallgef(lz);
                    225:   *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;
                    226: }
                    227:
                    228: #define u_zeropol(malloc) u_allocpol(-1,malloc)
                    229: #define u_FpX_mul(x,y, p) u_FpX_Kmul(x+2,y+2,p, lgef(x)-2,lgef(y)-2)
                    230: #define u_FpX_sqr(x, p) u_FpX_Ksqr(x+2,p, lgef(x)-2)
                    231: #define u_FpX_add(x,y, p) u_FpX_addspec(x+2,y+2,p, lgef(x)-2,lgef(y)-2)
                    232:
                    233: static GEN
                    234: u_allocpol(long d, int malloc)
                    235: {
                    236:   GEN z = malloc? (GEN)gpmalloc((d+3) * sizeof(long)): new_chunk(d+3);
                    237:   z[0] = evaltyp(t_VECSMALL) | evallg(d+3);
                    238:   z[1] = evalsigne((d >= 0)) | evallgef(d+3) | evalvarn(0);
                    239:   return z;
                    240: }
                    241:
                    242: static GEN
                    243: u_scalarpol(ulong x, int malloc)
                    244: {
                    245:   GEN z = u_allocpol(0,malloc);
                    246:   z[2] = x; return z;
                    247: }
                    248:
                    249: static GEN
                    250: u_FpX_neg_i(GEN x, ulong p)
                    251: {
                    252:   long i, l = lgef(x);
                    253:   for (i=2; i<l; i++)
                    254:     if (x[i]) x[i] = p - x[i];
                    255:   return x;
                    256: }
                    257:
                    258: /* shift polynomial + gerepile */
                    259: static GEN
                    260: u_FpX_shiftip(long av, GEN x, long v)
                    261: {
                    262:   long i, lx = lgef(x), ly;
                    263:   GEN y;
                    264:   if (v <= 0 || !signe(x)) return gerepileupto(av, x);
                    265:   avma = av; ly = lx + v;
                    266:   x += lx; y = new_chunk(ly) + ly;
                    267:   for (i = 2; i<lx; i++) *--y = *--x;
                    268:   for (i = 0; i< v; i++) *--y = 0;
                    269:   *--y = evalsigne(1) | evallgef(ly);
                    270:   *--y = evaltyp(t_VECSMALL) | evallg(ly); return y;
                    271: }
                    272:
                    273: /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
                    274:  * b+2 were sent instead. na, nb = number of terms of a, b.
                    275:  * Only c, c0, c1, c2 are genuine GEN.
                    276:  */
                    277: GEN
                    278: u_FpX_Kmul(GEN a, GEN b, ulong p, long na, long nb)
                    279: {
                    280:   GEN a0,c,c0;
                    281:   long av,n0,n0a,i, v = 0;
                    282:
                    283:   while (na && !a[0]) { a++; na--; v++; }
                    284:   while (nb && !b[0]) { b++; nb--; v++; }
                    285:   if (na < nb) swapspec(a,b, na,nb);
                    286:   if (!nb) return u_zeropol(0);
                    287:
                    288:   av = avma;
                    289:   if (nb < u_MUL_LIMIT)
                    290:     return u_FpX_shiftip(av,s_FpX_mulspec(a,b,p,na,nb), v);
                    291:   i=(na>>1); n0=na-i; na=i;
                    292:   a0=a+n0; n0a=n0;
                    293:   while (n0a && !a[n0a-1]) n0a--;
                    294:
                    295:   if (nb > n0)
                    296:   {
                    297:     GEN b0,c1,c2;
                    298:     long n0b;
                    299:
                    300:     nb -= n0; b0 = b+n0; n0b = n0;
                    301:     while (n0b && !b[n0b-1]) n0b--;
                    302:     c =  u_FpX_Kmul(a,b,p,n0a,n0b);
                    303:     c0 = u_FpX_Kmul(a0,b0,p,na,nb);
                    304:
                    305:     c2 = u_FpX_addspec(a0,a,p,na,n0a);
                    306:     c1 = u_FpX_addspec(b0,b,p,nb,n0b);
                    307:
                    308:     c1 = u_FpX_mul(c1,c2,p);
                    309:     c2 = u_FpX_add(c0,c,p);
                    310:
                    311:     c2 = u_FpX_neg_i(c2,p);
                    312:     c2 = u_FpX_add(c1,c2,p);
                    313:     c0 = u_FpX_addshift(c0,c2 ,p, n0);
                    314:   }
                    315:   else
                    316:   {
                    317:     c  = u_FpX_Kmul(a,b,p,n0a,nb);
                    318:     c0 = u_FpX_Kmul(a0,b,p,na,nb);
                    319:   }
                    320:   c0 = u_FpX_addshift(c0,c,p,n0);
                    321:   return u_FpX_shiftip(av,c0, v);
                    322: }
                    323:
                    324: GEN
                    325: u_FpX_sqrpol(GEN x, ulong p, long nx)
                    326: {
                    327:   long i,j,l,lz,nz;
                    328:   ulong p1;
                    329:   GEN z;
                    330:
                    331:   if (!nx) return u_zeropol(0);
                    332:   lz = (nx << 1) + 1, nz = lz-2;
                    333:   z = cgetg(lz,t_VECSMALL) + 2;
                    334:   for (i=0; i<nx; i++)
                    335:   {
                    336:     p1 = 0; l = (i+1)>>1;
                    337:     for (j=0; j<l; j++)
                    338:     {
                    339:       p1 += x[j] * x[i-j];
                    340:       if (p1 & HIGHBIT) p1 %= p;
                    341:     }
                    342:     p1 <<= 1; if (p1 & HIGHBIT) p1 %= p;
                    343:     if ((i&1) == 0)
                    344:       p1 += x[i>>1] * x[i>>1];
                    345:     z[i] = p1 % p;
                    346:   }
                    347:   for (  ; i<nz; i++)
                    348:   {
                    349:     p1 = 0; l = (i+1)>>1;
                    350:     for (j=i-nx+1; j<l; j++)
                    351:     {
                    352:       p1 += x[j] * x[i-j];
                    353:       if (p1 & HIGHBIT) p1 %= p;
                    354:     }
                    355:     p1 <<= 1; if (p1 & HIGHBIT) p1 %= p;
                    356:     if ((i&1) == 0)
                    357:       p1 += x[i>>1] * x[i>>1];
                    358:     z[i] = p1 % p;
                    359:   }
                    360:   z -= 2; z[1]=0; return u_normalizepol(z,lz);
                    361: }
                    362:
                    363: static GEN
                    364: u_Fp_gmul2_1(GEN x, ulong p)
                    365: {
                    366:   long i, l = lgef(x);
                    367:   GEN z = cgetg(l, t_VECSMALL);
                    368:   for (i=2; i<l; i++)
                    369:   {
                    370:     ulong p1 = x[i]<<1;
                    371:     if (p1 > p) p1 -= p;
                    372:     z[i] = p1;
                    373:   }
                    374:   z[1] = x[1]; return z;
                    375: }
                    376:
                    377: GEN
                    378: u_FpX_Ksqr(GEN a, ulong p, long na)
                    379: {
                    380:   GEN a0,c,c0,c1;
                    381:   long av,n0,n0a,i, v = 0;
                    382:
                    383:   while (na && !a[0]) { a++; na--; v += 2; }
                    384:   av = avma;
                    385:   if (na < u_SQR_LIMIT) return u_FpX_shiftip(av, u_FpX_sqrpol(a,p,na), v);
                    386:   i=(na>>1); n0=na-i; na=i;
                    387:   a0=a+n0; n0a=n0;
                    388:   while (n0a && !a[n0a-1]) n0a--;
                    389:
                    390:   c = u_FpX_Ksqr(a,p,n0a);
                    391:   c0= u_FpX_Ksqr(a0,p,na);
                    392:   if (p == 2) n0 *= 2;
                    393:   else
                    394:   {
                    395:     c1 = u_Fp_gmul2_1(u_FpX_Kmul(a0,a,p, na,n0a), p);
                    396:     c0 = u_FpX_addshift(c0,c1,p,n0);
                    397:   }
                    398:   c0 = u_FpX_addshift(c0,c,p,n0);
                    399:   return u_FpX_shiftip(av,c0,v);
                    400: }
                    401:
                    402: /* generic multiplication */
                    403:
                    404: static GEN
                    405: addpol(GEN x, GEN y, long lx, long ly)
                    406: {
                    407:   long i,lz;
                    408:   GEN z;
                    409:
                    410:   if (ly>lx) swapspec(x,y, lx,ly);
                    411:   lz = lx+2; z = cgetg(lz,t_POL) + 2;
                    412:   for (i=0; i<ly; i++) z[i]=ladd((GEN)x[i],(GEN)y[i]);
                    413:   for (   ; i<lx; i++) z[i]=x[i];
                    414:   z -= 2; z[1]=0; return normalizepol_i(z, lz);
                    415: }
                    416:
                    417: static GEN
                    418: addpolcopy(GEN x, GEN y, long lx, long ly)
                    419: {
                    420:   long i,lz;
                    421:   GEN z;
                    422:
                    423:   if (ly>lx) swapspec(x,y, lx,ly);
                    424:   lz = lx+2; z = cgetg(lz,t_POL) + 2;
                    425:   for (i=0; i<ly; i++) z[i]=ladd((GEN)x[i],(GEN)y[i]);
                    426:   for (   ; i<lx; i++) z[i]=lcopy((GEN)x[i]);
                    427:   z -= 2; z[1]=0; return normalizepol_i(z, lz);
                    428: }
                    429:
                    430: #ifdef INLINE
                    431: INLINE
                    432: #endif
                    433: GEN
                    434: mulpol_limb(GEN x, GEN y, char *ynonzero, long a, long b)
                    435: {
                    436:   GEN p1 = NULL;
                    437:   long i,av = avma;
                    438:   for (i=a; i<b; i++)
                    439:     if (ynonzero[i])
                    440:     {
                    441:       GEN p2 = gmul((GEN)y[i],(GEN)x[-i]);
                    442:       p1 = p1 ? gadd(p1, p2): p2;
                    443:     }
                    444:   return p1 ? gerepileupto(av, p1): gzero;
                    445: }
                    446:
                    447: /* assume nx >= ny > 0 */
                    448: static GEN
                    449: mulpol(GEN x, GEN y, long nx, long ny)
                    450: {
                    451:   long i,lz,nz;
                    452:   GEN z;
                    453:   char *p1;
                    454:
                    455:   lz = nx+ny+1; nz = lz-2;
                    456:   z = cgetg(lz, t_POL) + 2; /* x:y:z [i] = term of degree i */
                    457:   p1 = gpmalloc(ny);
                    458:   for (i=0; i<ny; i++)
                    459:   {
                    460:     p1[i] = !isexactzero((GEN)y[i]);
                    461:     z[i] = (long)mulpol_limb(x+i,y,p1,0,i+1);
                    462:   }
                    463:   for (  ; i<nx; i++) z[i] = (long)mulpol_limb(x+i,y,p1,0,ny);
                    464:   for (  ; i<nz; i++) z[i] = (long)mulpol_limb(x+i,y,p1,i-nx+1,ny);
                    465:   free(p1); z -= 2; z[1]=0; return normalizepol_i(z, lz);
                    466: }
                    467:
                    468: /* return (x * X^d) + y. Assume d > 0, x > 0 and y >= 0 */
                    469: GEN
                    470: addshiftw(GEN x, GEN y, long d)
                    471: {
                    472:   GEN xd,yd,zd = (GEN)avma;
                    473:   long a,lz,ny = lgef(y)-2, nx = lgef(x)-2;
                    474:
                    475:   x += 2; y += 2; a = ny-d;
                    476:   if (a <= 0)
                    477:   {
                    478:     lz = (a>nx)? ny+2: nx+d+2;
                    479:     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
                    480:     while (xd > x) *--zd = *--xd;
                    481:     x = zd + a;
                    482:     while (zd > x) *--zd = zero;
                    483:   }
                    484:   else
                    485:   {
                    486:     xd = new_chunk(d); yd = y+d;
                    487:     x = addpol(x,yd, nx,a);
                    488:     lz = (a>nx)? ny+2: lgef(x)+d;
                    489:     x += 2; while (xd > x) *--zd = *--xd;
                    490:   }
                    491:   while (yd > y) *--zd = *--yd;
                    492:   *--zd = evalsigne(1) | evallgef(lz);
                    493:   *--zd = evaltyp(t_POL) | evallg(lz); return zd;
                    494: }
                    495:
                    496: GEN
                    497: addshiftpol(GEN x, GEN y, long d)
                    498: {
                    499:   long v = varn(x);
                    500:   if (!signe(x)) return y;
                    501:   x = addshiftw(x,y,d);
                    502:   setvarn(x,v); return x;
                    503: }
                    504:
                    505: /* as above, producing a clean malloc */
                    506: static GEN
                    507: addshiftwcopy(GEN x, GEN y, long d)
                    508: {
                    509:   GEN xd,yd,zd = (GEN)avma;
                    510:   long a,lz,ny = lgef(y)-2, nx = lgef(x)-2;
                    511:
                    512:   x += 2; y += 2; a = ny-d;
                    513:   if (a <= 0)
                    514:   {
                    515:     lz = nx+d+2;
                    516:     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
                    517:     while (xd > x) *--zd = lcopy((GEN)*--xd);
                    518:     x = zd + a;
                    519:     while (zd > x) *--zd = zero;
                    520:   }
                    521:   else
                    522:   {
                    523:     xd = new_chunk(d); yd = y+d;
                    524:     x = addpolcopy(x,yd, nx,a);
                    525:     lz = (a>nx)? ny+2: lgef(x)+d;
                    526:     x += 2; while (xd > x) *--zd = *--xd;
                    527:   }
                    528:   while (yd > y) *--zd = lcopy((GEN)*--yd);
                    529:   *--zd = evalsigne(1) | evallgef(lz);
                    530:   *--zd = evaltyp(t_POL) | evallg(lz); return zd;
                    531: }
                    532:
                    533: /* shift polynomial in place. assume v free cells have been left before x */
                    534: static GEN
                    535: shiftpol_ip(GEN x, long v)
                    536: {
                    537:   long i, lx;
                    538:   GEN y;
                    539:   if (v <= 0 || !signe(x)) return x;
                    540:   lx = lgef(x);
                    541:   x += 2; y = x + v;
                    542:   for (i = lx-3; i>=0; i--) y[i] = x[i];
                    543:   for (i = 0   ; i< v; i++) x[i] = zero;
                    544:   lx += v;
                    545:   *--x = evalsigne(1) | evallgef(lx);
                    546:   *--x = evaltyp(t_POL) | evallg(lx); return x;
                    547: }
                    548:
                    549: /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
                    550:  * b+2 were sent instead. na, nb = number of terms of a, b.
                    551:  * Only c, c0, c1, c2 are genuine GEN.
                    552:  */
                    553: GEN
                    554: quickmul(GEN a, GEN b, long na, long nb)
                    555: {
                    556:   GEN a0,c,c0;
                    557:   long av,n0,n0a,i, v = 0;
                    558:
                    559:   while (na && isexactzero((GEN)a[0])) { a++; na--; v++; }
                    560:   while (nb && isexactzero((GEN)b[0])) { b++; nb--; v++; }
                    561:   if (na < nb) swapspec(a,b, na,nb);
                    562:   if (!nb) return zeropol(0);
                    563:
                    564:   if (v) (void)cgetg(v,t_STR); /* v gerepile-safe cells for shiftpol_ip */
                    565:   if (nb < MUL_LIMIT)
                    566:     return shiftpol_ip(mulpol(a,b,na,nb), v);
                    567:   i=(na>>1); n0=na-i; na=i;
                    568:   av=avma; a0=a+n0; n0a=n0;
                    569:   while (n0a && isexactzero((GEN)a[n0a-1])) n0a--;
                    570:
                    571:   if (nb > n0)
                    572:   {
                    573:     GEN b0,c1,c2;
                    574:     long n0b;
                    575:
                    576:     nb -= n0; b0 = b+n0; n0b = n0;
                    577:     while (n0b && isexactzero((GEN)b[n0b-1])) n0b--;
                    578:     c = quickmul(a,b,n0a,n0b);
                    579:     c0 = quickmul(a0,b0, na,nb);
                    580:
                    581:     c2 = addpol(a0,a, na,n0a);
                    582:     c1 = addpol(b0,b, nb,n0b);
                    583:
                    584:     c1 = quickmul(c1+2,c2+2, lgef(c1)-2,lgef(c2)-2);
                    585:     c2 = gneg_i(gadd(c0,c));
                    586:     c0 = addshiftw(c0, gadd(c1,c2), n0);
                    587:   }
                    588:   else
                    589:   {
                    590:     c = quickmul(a,b,n0a,nb);
                    591:     c0 = quickmul(a0,b,na,nb);
                    592:   }
                    593:   c0 = addshiftwcopy(c0,c,n0);
                    594:   return shiftpol_ip(gerepileupto(av,c0), v);
                    595: }
                    596:
                    597: GEN
                    598: sqrpol(GEN x, long nx)
                    599: {
                    600:   long av,i,j,l,lz,nz;
                    601:   GEN p1,z;
                    602:   char *p2;
                    603:
                    604:   if (!nx) return zeropol(0);
                    605:   lz = (nx << 1) + 1, nz = lz-2;
                    606:   z = cgetg(lz,t_POL) + 2;
                    607:   p2 = gpmalloc(nx);
                    608:   for (i=0; i<nx; i++)
                    609:   {
                    610:     p2[i] = !isexactzero((GEN)x[i]);
                    611:     p1=gzero; av=avma; l=(i+1)>>1;
                    612:     for (j=0; j<l; j++)
                    613:       if (p2[j] && p2[i-j])
                    614:         p1 = gadd(p1, gmul((GEN)x[j],(GEN)x[i-j]));
                    615:     p1 = gshift(p1,1);
                    616:     if ((i&1) == 0 && p2[i>>1])
                    617:       p1 = gadd(p1, gsqr((GEN)x[i>>1]));
                    618:     z[i] = lpileupto(av,p1);
                    619:   }
                    620:   for (  ; i<nz; i++)
                    621:   {
                    622:     p1=gzero; av=avma; l=(i+1)>>1;
                    623:     for (j=i-nx+1; j<l; j++)
                    624:       if (p2[j] && p2[i-j])
                    625:         p1 = gadd(p1, gmul((GEN)x[j],(GEN)x[i-j]));
                    626:     p1 = gshift(p1,1);
                    627:     if ((i&1) == 0 && p2[i>>1])
                    628:       p1 = gadd(p1, gsqr((GEN)x[i>>1]));
                    629:     z[i] = lpileupto(av,p1);
                    630:   }
                    631:   free(p2); z -= 2; z[1]=0; return normalizepol_i(z,lz);
                    632: }
                    633:
                    634: GEN
                    635: quicksqr(GEN a, long na)
                    636: {
                    637:   GEN a0,c,c0,c1;
                    638:   long av,n0,n0a,i, v = 0;
                    639:
                    640:   while (na && isexactzero((GEN)a[0])) { a++; na--; v += 2; }
                    641:   if (v) (void)new_chunk(v);
                    642:   if (na<SQR_LIMIT) return shiftpol_ip(sqrpol(a,na), v);
                    643:   i=(na>>1); n0=na-i; na=i;
                    644:   av=avma; a0=a+n0; n0a=n0;
                    645:   while (n0a && isexactzero((GEN)a[n0a-1])) n0a--;
                    646:
                    647:   c = quicksqr(a,n0a);
                    648:   c0 = quicksqr(a0,na);
                    649:   c1 = gmul2n(quickmul(a0,a, na,n0a), 1);
                    650:   c0 = addshiftw(c0,c1, n0);
                    651:   c0 = addshiftwcopy(c0,c,n0);
                    652:   return shiftpol_ip(gerepileupto(av,c0), v);
                    653: }
                    654: /*****************************************
                    655:  * Arithmetic in Z/pZ[X]                 *
                    656:  *****************************************/
                    657:
                    658: /*********************************************************************
                    659: This functions supposes polynomials already reduced.
                    660: There are clean and memory efficient.
                    661: **********************************************************************/
                    662:
                    663: GEN
                    664: FpX_center(GEN T,GEN mod)
                    665: {/*OK centermod exists, but is not so clean*/
                    666:   ulong av;
                    667:   long i, l=lg(T);
                    668:   GEN P,mod2;
                    669:   P=cgetg(l,t_POL);
                    670:   P[1]=T[1];
                    671:   av=avma;
                    672:   mod2=gclone(shifti(mod,-1));/*clone*/
                    673:   avma=av;
                    674:   for(i=2;i<l;i++)
                    675:     P[i]=cmpii((GEN)T[i],mod2)<0?licopy((GEN)T[i]):lsubii((GEN)T[i],mod);
                    676:   gunclone(mod2);/*unclone*/
                    677:   return P;
                    678: }
                    679:
                    680: GEN
                    681: FpX_neg(GEN x,GEN p)
                    682: {
                    683:   long i,d=lgef(x);
                    684:   GEN y;
                    685:   y=cgetg(d,t_POL); y[1]=x[1];
                    686:   for(i=2;i<d;i++)
                    687:     if (signe(x[i])) y[i]=lsubii(p,(GEN)x[i]);
                    688:     else y[i]=zero;
                    689:   return y;
                    690: }
                    691: /**********************************************************************
                    692: Unclean functions, do not garbage collect.
                    693: This is a feature: The malloc is corrupted only by the call to FpX_red
                    694: so garbage collecting so often is not desirable.
                    695: FpX_red can sometime be avoided by passing NULL for p.
                    696: In this case the function is usually clean (see below for detail)
                    697: Added to help not using POLMOD of INTMOD which are deadly slow.
                    698: gerepileupto of the result is legible.   Bill.
                    699: I don't like C++.  I am wrong.
                    700: **********************************************************************/
                    701: /*
                    702:  *If p is NULL no reduction is performed and the function is clean.
                    703:  * for FpX_add,FpX_mul,FpX_sqr,FpX_Fp_mul
                    704:  */
                    705: GEN
                    706: FpX_add(GEN x,GEN y,GEN p)
                    707: {
                    708:   long lx,ly,i;
                    709:   GEN z;
                    710:   lx = lgef(x); ly = lgef(y); if (lx < ly) swapspec(x,y, lx,ly);
                    711:   z = cgetg(lx,t_POL); z[1] = x[1];
                    712:   for (i=2; i<ly; i++) z[i]=laddii((GEN)x[i],(GEN)y[i]);
                    713:   for (   ; i<lx; i++) z[i]=licopy((GEN)x[i]);
                    714:   (void)normalizepol_i(z, lx);
                    715:   if (lgef(z) == 2) { avma = (long)(z + lx); z = zeropol(varn(x)); }
                    716:   if (p) z= FpX_red(z, p);
                    717:   return z;
                    718: }
                    719: GEN
                    720: FpX_sub(GEN x,GEN y,GEN p)
                    721: {
                    722:   long lx,ly,i,lz;
                    723:   GEN z;
                    724:   lx = lgef(x); ly = lgef(y);
                    725:   lz=max(lx,ly);
                    726:   z = cgetg(lz,t_POL);
                    727:   if (lx >= ly)
                    728:   {
                    729:     z[1] = x[1];
                    730:     for (i=2; i<ly; i++) z[i]=lsubii((GEN)x[i],(GEN)y[i]);
                    731:     for (   ; i<lx; i++) z[i]=licopy((GEN)x[i]);
                    732:     (void)normalizepol_i(z, lz);
                    733:   }
                    734:   else
                    735:   {
                    736:     z[1] = y[1];
                    737:     for (i=2; i<lx; i++) z[i]=lsubii((GEN)x[i],(GEN)y[i]);
                    738:     for (   ; i<ly; i++) z[i]=lnegi((GEN)y[i]);
                    739:     /*polynomial is always normalized*/
                    740:   }
                    741:   if (lgef(z) == 2) { avma = (long)(z + lz); z = zeropol(varn(x)); }
                    742:   if (p) z= FpX_red(z, p);
                    743:   return z;
                    744: }
                    745: GEN
                    746: FpX_mul(GEN x,GEN y,GEN p)
                    747: {
                    748:   GEN z = quickmul(y+2, x+2, lgef(y)-2, lgef(x)-2);
                    749:   setvarn(z,varn(x));
                    750:   if (!p) return z;
                    751:   return FpX_red(z, p);
                    752: }
                    753: GEN
                    754: FpX_sqr(GEN x,GEN p)
                    755: {
                    756:   GEN z = quicksqr(x+2, lgef(x)-2);
                    757:   setvarn(z,varn(x));
                    758:   if (!p) return z;
                    759:   return FpX_red(z, p);
                    760: }
                    761: #define u_FpX_div(x,y,p) u_FpX_divrem((x),(y),(p),(0),NULL)
                    762:
                    763: /* Product of y and x in Z/pZ[X]/(pol), as t_VECSMALL. Assume OK_ULONG(p) */
                    764: static GEN
                    765: u_FpXQ_mul(GEN y,GEN x,GEN pol,ulong p)
                    766: {
                    767:   GEN z = u_FpX_mul(y,x,p);
                    768:   return u_FpX_rem(z,pol,p);
                    769: }
                    770: /* Square of y in Z/pZ[X]/(pol), as t_VECSMALL. Assume OK_ULONG(p) */
                    771: static GEN
                    772: u_FpXQ_sqr(GEN y,GEN pol,ulong p)
                    773: {
                    774:   GEN z = u_FpX_sqr(y,p);
                    775:   return u_FpX_rem(z,pol,p);
                    776: }
                    777:
                    778: /* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist
                    779:  * return lift(1 / (x mod (p,pol))) */
                    780: GEN
                    781: FpXQ_invsafe(GEN x, GEN T, GEN p)
                    782: {
                    783:   GEN z, U, V;
                    784:
                    785:   if (typ(x) != t_POL) return mpinvmod(x, p);
                    786:   z = FpX_extgcd(x, T, p, &U, &V);
                    787:   if (lgef(z) != 3) return NULL;
                    788:   z = mpinvmod((GEN)z[2], p);
                    789:   return FpX_Fp_mul(U, z, p);
                    790: }
                    791:
                    792: /* Product of y and x in Z/pZ[X]/(T)
                    793:  * return lift(lift(Mod(x*y*Mod(1,p),T*Mod(1,p)))) */
                    794: GEN
                    795: FpXQ_mul(GEN y,GEN x,GEN T,GEN p)
                    796: {
                    797:   GEN z;
                    798:   if (typ(x) == t_INT)
                    799:   {
                    800:     if (typ(y) == t_INT) return modii(mulii(x,y), p);
                    801:     return FpX_Fp_mul(y, x, p);
                    802:   }
                    803:   if (typ(y) == t_INT) return FpX_Fp_mul(x, y, p);
                    804:   z = quickmul(y+2, x+2, lgef(y)-2, lgef(x)-2); setvarn(z,varn(y));
                    805:   z = FpX_red(z, p); return FpX_res(z,T, p);
                    806: }
                    807:
                    808: /* Square of y in Z/pZ[X]/(pol)
                    809:  * return lift(lift(Mod(y^2*Mod(1,p),pol*Mod(1,p)))) */
                    810: GEN
                    811: FpXQ_sqr(GEN y,GEN pol,GEN p)
                    812: {
                    813:   GEN z = quicksqr(y+2,lgef(y)-2); setvarn(z,varn(y));
                    814:   z = FpX_red(z, p); return FpX_res(z,pol, p);
                    815: }
                    816: /*Modify y[2].
                    817:  *No reduction if p is NULL
                    818:  */
                    819: GEN
                    820: FpX_Fp_add(GEN y,GEN x,GEN p)
                    821: {
                    822:   if (!signe(x)) return y;
                    823:   if (!signe(y))
                    824:     return scalarpol(x,varn(y));
                    825:   y[2]=laddii((GEN)y[2],x);
                    826:   if (p) y[2]=lmodii((GEN)y[2],p);
                    827:   if (!signe(y[2]) && degpol(y) == 0) return zeropol(varn(y));
                    828:   return y;
                    829: }
                    830: GEN
                    831: ZX_s_add(GEN y,long x)
                    832: {
                    833:   if (!x) return y;
                    834:   if (!signe(y))
                    835:     return scalarpol(stoi(x),varn(y));
                    836:   y[2] = laddis((GEN)y[2],x);
                    837:   if (!signe(y[2]) && degpol(y) == 0) return zeropol(varn(y));
                    838:   return y;
                    839: }
                    840: /* y is a polynomial in ZZ[X] and x an integer.
                    841:  * If p is NULL, no reduction is perfomed and return x*y
                    842:  *
                    843:  * else the result is lift(y*x*Mod(1,p))
                    844:  */
                    845: GEN
                    846: FpX_Fp_mul(GEN y,GEN x,GEN p)
                    847: {
                    848:   GEN z;
                    849:   int i;
                    850:   if (!signe(x))
                    851:     return zeropol(varn(y));
                    852:   z=cgetg(lg(y),t_POL);
                    853:   z[1]=y[1];
                    854:   for(i=2;i<lgef(y);i++)
                    855:     z[i]=lmulii((GEN)y[i],x);
                    856:   if(!p) return z;
                    857:   return FpX_red(z,p);
                    858: }
                    859: /*****************************************************************
                    860:  *                 End of unclean functions.                     *
                    861:  *                                                               *
                    862:  *****************************************************************/
                    863: /*****************************************************************
                    864:  Clean and with no reduced hypothesis.  Beware that some operations
                    865:  will be much slower with big unreduced coefficient
                    866: *****************************************************************/
                    867: /* Inverse of x in Z[X] / (p,T)
                    868:  * return lift(lift(Mod(x*Mod(1,p), T*Mod(1,p))^-1)); */
                    869: GEN
                    870: FpXQ_inv(GEN x,GEN T,GEN p)
                    871: {
                    872:   ulong av;
                    873:   GEN U;
                    874:
                    875:   if (!T) return mpinvmod(x,p);
                    876:   av = avma;
                    877:   U = FpXQ_invsafe(x, T, p);
                    878:   if (!U) err(talker,"non invertible polynomial in FpXQ_inv");
                    879:   return gerepileupto(av, U);
                    880: }
                    881:
                    882: GEN
                    883: FpXV_FpV_dotproduct(GEN V, GEN W, GEN p)
                    884: {
                    885:   long ltop=avma;
                    886:   long i;
                    887:   GEN z = FpX_Fp_mul((GEN)V[1],(GEN)W[1],NULL);
                    888:   for(i=2;i<lg(V);i++)
                    889:     z=FpX_add(z,FpX_Fp_mul((GEN)V[i],(GEN)W[i],NULL),NULL);
                    890:   return gerepileupto(ltop,FpX_red(z,p));
                    891: }
                    892:
                    893: /* generates the list of powers of x of degree 0,1,2,...,l*/
                    894: GEN
                    895: FpXQ_powers(GEN x, long l, GEN T, GEN p)
                    896: {
                    897:   GEN V=cgetg(l+2,t_VEC);
                    898:   long i;
                    899:   V[1] = (long) scalarpol(gun,varn(T));
                    900:   if (l==0) return V;
                    901:   V[2] = lcopy(x);
                    902:   if (l==1) return V;
                    903:   V[3] = (long) FpXQ_sqr(x,T,p);
                    904:   for(i=4;i<l+2;i++)
                    905:     V[i] = (long) FpXQ_mul((GEN) V[i-1],x,T,p);
                    906: #if 0
                    907:   TODO: Karim proposes to use squaring:
                    908:   V[i] = (long) ((i&1)?FpXQ_sqr((GEN) V[(i+1)>>1],T,p)
                    909:                        :FpXQ_mul((GEN) V[i-1],x,T,p));
                    910:   Please profile it.
                    911: #endif
                    912:   return V;
                    913: }
                    914: #if 0
                    915: static long brent_kung_nbmul(long d, long n, long p)
                    916: {
                    917:   return p+n*((d+p-1)/p);
                    918: }
                    919:   TODO: This the the optimal parameter for the purpose of reducing
                    920:   multiplications, but profiling need to be done to ensure it is not slower
                    921:   than the other option in practice
                    922: /*Return optimal parameter l for the evaluation of n polynomials of degree d*/
                    923: long brent_kung_optpow(long d, long n)
                    924: {
                    925:   double r;
                    926:   long f,c,pr;
                    927:   if (n>=d ) return d;
                    928:   pr=n*d;
                    929:   if (pr<=1) return 1;
                    930:   r=d/sqrt(pr);
                    931:   c=(long)ceil(d/ceil(r));
                    932:   f=(long)floor(d/floor(r));
                    933:   return (brent_kung_nbmul(d, n, c) <= brent_kung_nbmul(d, n, f))?c:f;
                    934: }
                    935: #endif
                    936: /*Return optimal parameter l for the evaluation of n polynomials of degree d*/
                    937: long brent_kung_optpow(long d, long n)
                    938: {
                    939:   double r;
                    940:   long l,pr;
                    941:   if (n>=d ) return d;
                    942:   pr=n*d;
                    943:   if (pr<=1) return 1;
                    944:   r=d/sqrt(pr);
                    945:   l=(long)r;
                    946:   return (d+l-1)/l;
                    947: }
                    948:
                    949: /*Close to FpXV_FpV_dotproduct*/
                    950:
                    951: static GEN
                    952: spec_compo_powers(GEN P, GEN V, long a, long n)
                    953: {
                    954:   long i;
                    955:   GEN z;
                    956:   z = scalarpol((GEN)P[2+a],varn(P));
                    957:   for(i=1;i<=n;i++)
                    958:     z=FpX_add(z,FpX_Fp_mul((GEN)V[i+1],(GEN)P[2+a+i],NULL),NULL);
                    959:   return z;
                    960: }
                    961: /*Try to implement algorithm in Brent & Kung (Fast algorithms for
                    962:  *manipulating formal power series, JACM 25:581-595, 1978)
                    963:
                    964:  V must be as output by FpXQ_powers.
                    965:  For optimal performance, l (of FpXQ_powers) must be as output by
                    966:  brent_kung_optpow
                    967:  */
                    968:
                    969: GEN
                    970: FpX_FpXQV_compo(GEN P, GEN V, GEN T, GEN p)
                    971: {
                    972:   ulong ltop=avma;
                    973:   long l=lg(V)-1;
                    974:   GEN z,u;
                    975:   long d=degpol(P),cnt=0;
                    976:   if (d==-1) return zeropol(varn(T));
                    977:   if (d<l)
                    978:   {
                    979:     z=spec_compo_powers(P,V,0,d);
                    980:     return gerepileupto(ltop,FpX_red(z,p));
                    981:   }
                    982:   if (l<=1)
                    983:     err(talker,"powers is only [] or [1] in FpX_FpXQV_compo");
                    984:   z=spec_compo_powers(P,V,d-l+1,l-1);
                    985:   d-=l;
                    986:   while(d>=l-1)
                    987:   {
                    988:     u=spec_compo_powers(P,V,d-l+2,l-2);
                    989:     z=FpX_add(u,FpXQ_mul(z,(GEN)V[l],T,p),NULL);
                    990:     d-=l-1;
                    991:     cnt++;
                    992:   }
                    993:   u=spec_compo_powers(P,V,0,d);
                    994:   z=FpX_add(u,FpXQ_mul(z,(GEN)V[d+2],T,p),NULL);
                    995:   cnt++;
                    996:   if (DEBUGLEVEL>=8) fprintferr("FpX_FpXQV_compo: %d FpXQ_mul [%d]\n",cnt,l-1);
                    997:   return gerepileupto(ltop,FpX_red(z,p));
                    998: }
                    999:
                   1000: /* T in Z[X] and  x in Z/pZ[X]/(pol)
                   1001:  * return lift(lift(subst(T,variable(T),Mod(x*Mod(1,p),pol*Mod(1,p)))));
                   1002:  */
                   1003: GEN
                   1004: FpX_FpXQ_compo(GEN T,GEN x,GEN pol,GEN p)
                   1005: {
                   1006:   ulong ltop=avma;
                   1007:   GEN z;
                   1008:   long d=degpol(T),rtd;
                   1009:   if (!signe(T)) return zeropol(varn(T));
                   1010:   rtd = (long) sqrt((double)d);
                   1011:   z = FpX_FpXQV_compo(T,FpXQ_powers(x,rtd,pol,p),pol,p);
                   1012:   return gerepileupto(ltop,z);
                   1013: }
                   1014:
                   1015: /* Evaluation in Fp
                   1016:  * x in Z[X] and y in Z return x(y) mod p
                   1017:  *
                   1018:  * If p is very large (several longs) and x has small coefficients(<<p),
                   1019:  * then Brent & Kung algorithm is faster. */
                   1020: GEN
                   1021: FpX_eval(GEN x,GEN y,GEN p)
                   1022: {
                   1023:   ulong av;
                   1024:   GEN p1,r,res;
                   1025:   long i,j;
                   1026:   i=lgef(x)-1;
                   1027:   if (i<=2)
                   1028:     return (i==2)? modii((GEN)x[2],p): gzero;
                   1029:   res=cgetg(lgefint(p),t_INT);
                   1030:   av=avma; p1=(GEN)x[i];
                   1031:   /* specific attention to sparse polynomials (see poleval)*/
                   1032:   /*You've guess it! It's a copy-paste(tm)*/
                   1033:   for (i--; i>=2; i=j-1)
                   1034:   {
                   1035:     for (j=i; !signe((GEN)x[j]); j--)
                   1036:       if (j==2)
                   1037:       {
                   1038:        if (i!=j) y = powmodulo(y,stoi(i-j+1),p);
                   1039:        p1=mulii(p1,y);
                   1040:        goto fppoleval;/*sorry break(2) no implemented*/
                   1041:       }
                   1042:     r = (i==j)? y: powmodulo(y,stoi(i-j+1),p);
                   1043:     p1 = modii(addii(mulii(p1,r), (GEN)x[j]),p);
                   1044:   }
                   1045:  fppoleval:
                   1046:   modiiz(p1,p,res);
                   1047:   avma=av;
                   1048:   return res;
                   1049: }
                   1050: /* Tz=Tx*Ty where Tx and Ty coprime
                   1051:  * return lift(chinese(Mod(x*Mod(1,p),Tx*Mod(1,p)),Mod(y*Mod(1,p),Ty*Mod(1,p))))
                   1052:  * if Tz is NULL it is computed
                   1053:  * As we do not return it, and the caller will frequently need it,
                   1054:  * it must compute it and pass it.
                   1055:  */
                   1056: GEN
                   1057: FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p)
                   1058: {
                   1059:   long av = avma;
                   1060:   GEN ax,p1;
                   1061:   ax = FpX_mul(FpXQ_inv(Tx,Ty,p), Tx,p);
                   1062:   p1=FpX_mul(ax, FpX_sub(y,x,p),p);
                   1063:   p1 = FpX_add(x,p1,p);
                   1064:   if (!Tz) Tz=FpX_mul(Tx,Ty,p);
                   1065:   p1 = FpX_res(p1,Tz,p);
                   1066:   return gerepileupto(av,p1);
                   1067: }
                   1068:
                   1069: /* assume n > 0 */
                   1070: GEN
                   1071: u_FpXQ_pow(GEN x, GEN n, GEN pol, ulong p)
                   1072: {
                   1073:   ulong av = avma;
                   1074:   GEN p1 = n+2, y = x;
                   1075:   long m,i,j;
                   1076:   m = *p1;
                   1077:   j = 1+bfffo(m); m <<= j; j = BITS_IN_LONG-j;
                   1078:   for (i=lgefint(n)-2;;)
                   1079:   {
                   1080:     for (; j; m<<=1,j--)
                   1081:     {
                   1082:       y = u_FpXQ_sqr(y,pol,p);
                   1083:       if (m<0)
                   1084:         y = u_FpXQ_mul(y,x,pol,p);
                   1085:     }
                   1086:     if (--i == 0) break;
                   1087:     m = *++p1, j = BITS_IN_LONG;
                   1088:   }
                   1089:   return gerepileupto(av, y);
                   1090: }
                   1091:
                   1092: /* x,pol in Z[X], p in Z, n in Z, compute lift(x^n mod (p, pol)) */
                   1093: GEN
                   1094: FpXQ_pow(GEN x, GEN n, GEN pol, GEN p)
                   1095: {
                   1096:   ulong av, ltop = avma, lim=stack_lim(avma,1);
                   1097:   long m,i,j, vx = varn(x);
                   1098:   GEN p1 = n+2, y;
                   1099:   if (!signe(n)) return polun[vx];
                   1100:   if (signe(n) < 0)
                   1101:   {
                   1102:     x=FpXQ_inv(x,pol,p);
                   1103:     if (is_pm1(n)) return x; /* n = -1*/
                   1104:   }
                   1105:   else
                   1106:     if (is_pm1(n)) return gcopy(x); /* n = 1 */
                   1107:   if (OK_ULONG(p))
                   1108:   {
                   1109:     ulong pp = p[2];
                   1110:     pol = u_Fp_FpX(pol,0, pp);
                   1111:     x = u_Fp_FpX(x,0, pp);
                   1112:     y = u_FpXQ_pow(x, n, pol, pp);
                   1113:     y = small_to_pol(y,vx);
                   1114:   }
                   1115:   else
                   1116:   {
                   1117:     av = avma;
                   1118:     m = *p1; y = x;
                   1119:     j = 1+bfffo(m); m <<= j; j = BITS_IN_LONG-j;
                   1120:     for (i=lgefint(n)-2;;)
                   1121:     {
                   1122:       for (; j; m<<=1,j--)
                   1123:       {
                   1124:         y = FpXQ_sqr(y,pol,p);
                   1125:         if (low_stack(lim, stack_lim(av,1)))
                   1126:         {
                   1127:           if(DEBUGMEM>1) err(warnmem,"[1]: FpXQ_pow");
                   1128:           y = gerepileupto(av, y);
                   1129:         }
                   1130:         if (m<0)
                   1131:           y = FpXQ_mul(y,x,pol,p);
                   1132:         if (low_stack(lim, stack_lim(av,1)))
                   1133:         {
                   1134:           if(DEBUGMEM>1) err(warnmem,"[2]: FpXQ_pow");
                   1135:           y = gerepileupto(av, y);
                   1136:         }
                   1137:       }
                   1138:       if (--i == 0) break;
                   1139:       m = *++p1, j = BITS_IN_LONG;
                   1140:     }
                   1141:   }
                   1142:   return gerepileupto(ltop,y);
                   1143: }
                   1144:
                   1145: /*******************************************************************/
                   1146: /*                                                                 */
                   1147: /*                             Fp[X][Y]                            */
                   1148: /*                                                                 */
                   1149: /*******************************************************************/
                   1150: /*Polynomials whose coefficients are either polynomials or integers*/
                   1151:
                   1152: GEN
                   1153: FpXX_red(GEN z, GEN p)
                   1154: {
                   1155:     GEN res;
                   1156:     int i;
                   1157:     res=cgetg(lgef(z),t_POL);
                   1158:     res[1] = evalsigne(1) | evalvarn(varn(z)) | evallgef(lgef(z));
                   1159:     for(i=2;i<lgef(res);i++)
                   1160:       if (typ(z[i])!=t_INT)
                   1161:       {
                   1162:        ulong av=avma;
                   1163:         res[i]=(long)FpX_red((GEN)z[i],p);
                   1164:        if (lgef(res[i])<=3)
                   1165:        {
                   1166:          if (lgef(res[i])==2) {avma=av;res[i]=zero;}
                   1167:          else res[i]=lpilecopy(av,gmael(res,i,2));
                   1168:        }
                   1169:       }
                   1170:       else
                   1171:         res[i]=lmodii((GEN)z[i],p);
                   1172:     res=normalizepol_i(res,lgef(res));
                   1173:     return res;
                   1174: }
                   1175:
                   1176: /*******************************************************************/
                   1177: /*                                                                 */
                   1178: /*                             (Fp[X]/(Q))[Y]                      */
                   1179: /*                                                                 */
                   1180: /*******************************************************************/
                   1181:
                   1182: extern GEN to_Kronecker(GEN P, GEN Q);
                   1183: GEN /*Somewhat copy-pasted...*/
                   1184: /*Not malloc nor warn-clean.*/
                   1185: FpXQX_from_Kronecker(GEN z, GEN pol, GEN p)
                   1186: {
                   1187:   long i,j,lx,l = lgef(z), N = (degpol(pol)<<1) + 1;
                   1188:   GEN x, t = cgetg(N,t_POL);
                   1189:   t[1] = pol[1] & VARNBITS;
                   1190:   lx = (l-2) / (N-2); x = cgetg(lx+3,t_POL);
                   1191:   if (isonstack(pol)) pol = gcopy(pol);
                   1192:   for (i=2; i<lx+2; i++)
                   1193:   {
                   1194:     for (j=2; j<N; j++) t[j] = z[j];
                   1195:     z += (N-2);
                   1196:     x[i] = (long)FpX_res(normalizepol_i(t,N), pol, p);
                   1197:   }
                   1198:   N = (l-2) % (N-2) + 2;
                   1199:   for (j=2; j<N; j++) t[j] = z[j];
                   1200:   x[i] = (long)FpX_res(normalizepol_i(t,N), pol, p);
                   1201:   return normalizepol_i(x, i+1);
                   1202: }
                   1203: /*Unused/untested*/
                   1204: GEN
                   1205: FpXQX_red(GEN z, GEN T, GEN p)
                   1206: {
                   1207:   GEN res;
                   1208:   int i;
                   1209:   res=cgetg(lgef(z),t_POL);
                   1210:   res[1] = evalsigne(1) | evalvarn(varn(z)) | evallgef(lgef(z));
                   1211:   for(i=2;i<lgef(res);i++)
                   1212:     if (typ(z[i])!=t_INT)
                   1213:     {
                   1214:       if (T)
                   1215:         res[i]=(long)FpX_res((GEN)z[i],T,p);
                   1216:       else
                   1217:         res[i]=(long)FpX_red((GEN)z[i],p);
                   1218:     }
                   1219:     else
                   1220:       res[i]=lmodii((GEN)z[i],p);
                   1221:   res=normalizepol_i(res,lgef(res));
                   1222:   return res;
                   1223: }
                   1224: /* if T = NULL, call FpX_mul */
                   1225: GEN
                   1226: FpXQX_mul(GEN x, GEN y, GEN T, GEN p)
                   1227: {
                   1228:   ulong ltop;
                   1229:   GEN z,kx,ky;
                   1230:   long vx;
                   1231:   if (!T) return FpX_mul(x,y,p);
                   1232:   ltop = avma;
                   1233:   vx = min(varn(x),varn(y));
                   1234:   kx= to_Kronecker(x,T);
                   1235:   ky= to_Kronecker(y,T);
                   1236:   z = quickmul(ky+2, kx+2, lgef(ky)-2, lgef(kx)-2);
                   1237:   z = FpX_red(z,p);
                   1238:   z = FpXQX_from_Kronecker(z,T,p);
                   1239:   setvarn(z,vx);/*quickmul and Fq_from_Kronecker are not varn-clean*/
                   1240:   return gerepileupto(ltop,z);
                   1241: }
                   1242: GEN/*Unused/untested*/
                   1243: FpXQX_sqr(GEN x, GEN T, GEN p)
                   1244: {
                   1245:   ulong ltop=avma;
                   1246:   GEN z,kx;
                   1247:   long vx=varn(x);
                   1248:   kx= to_Kronecker(x,T);
                   1249:   z = quicksqr(kx+2, lgef(kx)-2);
                   1250:   z = FpX_red(z,p);
                   1251:   z = FpXQX_from_Kronecker(z,T,p);
                   1252:   setvarn(z,vx);/*quickmul and Fq_from_Kronecker are nor varn-clean*/
                   1253:   return gerepileupto(ltop,z);
                   1254: }
                   1255: GEN
                   1256: FpXQX_FpXQ_mul(GEN P, GEN U, GEN T, GEN p)
                   1257: {
                   1258:   int i, lP = lgef(P);
                   1259:   GEN res = cgetg(lP,t_POL);
                   1260:   res[1] = evalsigne(1) | evalvarn(varn(P)) | evallgef(lP);
                   1261:   for(i=2; i<lP; i++)
                   1262:     res[i] = (long)FpXQ_mul(U,(GEN)P[i], T,p);
                   1263:   return normalizepol_i(res,lgef(res));
                   1264: }
                   1265:
                   1266: /* a X^degpol, assume degpol >= 0 */
                   1267: static GEN
                   1268: monomial(GEN a, int degpol, int v)
                   1269: {
                   1270:   long i, lP = degpol+3;
                   1271:   GEN P = cgetg(lP, t_POL);
                   1272:   P[1] = evalsigne(1) | evalvarn(v) | evallgef(lP);
                   1273:   lP--; P[lP] = (long)a;
                   1274:   for (i=2; i<lP; i++) P[i] = zero;
                   1275:   return P;
                   1276: }
                   1277:
                   1278: /* return NULL if Euclidean remainder sequence fails (==> T reducible mod p)
                   1279:  * last non-zero remainder otherwise */
                   1280: GEN
                   1281: FpXQX_safegcd(GEN P, GEN Q, GEN T, GEN p)
                   1282: {
                   1283:   ulong ltop = avma, btop, st_lim;
                   1284:   long dg, vx = varn(P);
                   1285:   GEN U, q;
                   1286:   P = FpXX_red(P, p);
                   1287:   Q = FpXX_red(Q, p);
                   1288:   if (!signe(P)) return gerepileupto(ltop, Q);
                   1289:   if (!signe(Q)) { avma = (ulong)P; return P; }
                   1290:   T = FpX_red(T, p);
                   1291:
                   1292:   btop = avma; st_lim = stack_lim(btop, 1);
                   1293:   dg = lgef(P)-lgef(Q);
                   1294:   if (dg < 0) { swap(P, Q); dg = -dg; }
                   1295:   for(;;)
                   1296:   {
                   1297:     U = FpXQ_invsafe(leading_term(Q), T, p);
                   1298:     if (!U) { avma = ltop; return NULL; }
                   1299:     do /* set P := P % Q */
                   1300:     {
                   1301:       q = FpXQ_mul(U, gneg(leading_term(P)), T, p);
                   1302:       P = gadd(P, FpXQX_mul(monomial(q, dg, vx), Q, T, p));
                   1303:       P = FpXQX_red(P, T, p); /* wasteful, but negligible */
                   1304:       dg = lgef(P)-lgef(Q);
                   1305:     } while (dg >= 0);
                   1306:     if (!signe(P)) break;
                   1307:
                   1308:     if (low_stack(st_lim, stack_lim(btop, 1)))
                   1309:     {
                   1310:       GEN *bptr[2]; bptr[0]=&P; bptr[1]=&Q;
                   1311:       if (DEBUGLEVEL>1) err(warnmem,"FpXQX_safegcd");
                   1312:       gerepilemany(btop, bptr, 2);
                   1313:     }
                   1314:     swap(P, Q); dg = -dg;
                   1315:   }
                   1316:   Q = FpXQX_FpXQ_mul(Q, U, T, p); /* normalize GCD */
                   1317:   return gerepileupto(ltop, Q);
                   1318: }
                   1319:
                   1320: /*******************************************************************/
                   1321: /*                                                                 */
                   1322: /*                             Fq[X]                               */
                   1323: /*                                                                 */
                   1324: /*******************************************************************/
                   1325:
                   1326: /*Well nothing, for now. So we reuse FpXQX*/
                   1327: #define FqX_mul FpXQX_mul
                   1328: #define FqX_sqr FpXQX_sqr
                   1329: #define FqX_red FpXQX_red
                   1330: static GEN
                   1331: Fq_neg(GEN x, GEN T, GEN p)/*T is not used but it is for consistency*/
                   1332: {
                   1333:   switch(typ(x)==t_POL)
                   1334:   {
                   1335:     case 0: return signe(x)?subii(p,x):gzero;
                   1336:     case 1: return FpX_neg(x,p);
                   1337:   }
                   1338:   return NULL;
                   1339: }
                   1340: static GEN modulo,Tmodulo;
                   1341: static GEN fgmul(GEN a,GEN b){return FqX_mul(a,b,Tmodulo,modulo);}
                   1342: GEN
                   1343: FqV_roots_to_pol(GEN V, GEN Tp, GEN p, long v)
                   1344: {
                   1345:   ulong ltop=avma;
                   1346:   long k;
                   1347:   GEN W=cgetg(lg(V),t_VEC);
                   1348:   for(k=1;k<lg(V);k++)
                   1349:     W[k]=(long)deg1pol(gun,Fq_neg((GEN)V[k],Tp,p),v);
                   1350:   modulo=p;Tmodulo=Tp;
                   1351:   W=divide_conquer_prod(W,&fgmul);
                   1352:   return gerepileupto(ltop,W);
                   1353: }
                   1354:
                   1355: /*******************************************************************/
                   1356: /*                                                                 */
                   1357: /*                       n-th ROOT in Fq                           */
                   1358: /*                                                                 */
                   1359: /*******************************************************************/
                   1360: /*NO clean malloc*/
                   1361: static GEN fflgen(GEN l, long e, GEN r, GEN T ,GEN p, GEN *zeta)
                   1362: {
                   1363:   ulong av1;
                   1364:   GEN z,m,m1;
                   1365:   long x=varn(T),k,u,v,pp,i;
                   1366:   if (is_bigint(p))
                   1367:     pp=VERYBIGINT;
                   1368:   else
                   1369:     pp=itos(p);
                   1370:   z=(lgef(T)==4)?polun[x]:polx[x];
                   1371:
                   1372:   av1 = avma;
                   1373:   for (k=1; ; k++)
                   1374:   {
                   1375:     u=k;v=0;
                   1376:     while (u%pp==0){u/=pp;v++;}
                   1377:     if(!v)
                   1378:       z=gadd(z,gun);
                   1379:     else
                   1380:     {
                   1381:       z=gadd(z,gpowgs(polx[x],v));
                   1382:       if (DEBUGLEVEL>=6)
                   1383:        fprintferr("FF l-Gen:next %Z",z);
                   1384:     }
                   1385:     m1 = m = FpXQ_pow(z,r,T,p);
                   1386:     for (i=1; i<e; i++)
                   1387:       if (gcmp1(m=FpXQ_pow(m,l,T,p))) break;
                   1388:     if (i==e) break;
                   1389:     avma = av1;
                   1390:   }
                   1391:   *zeta=m;
                   1392:   return m1;
                   1393: }
                   1394: /* resoud x^l=a mod (p,T)
                   1395:  * l doit etre premier
                   1396:  * q=p^degpol(T)-1
                   1397:  * q=(l^e)*r
                   1398:  * e>=1
                   1399:  * pgcd(r,l)=1
                   1400:  * m=y^(q/l)
                   1401:  * y n'est pas une puissance l-ieme
                   1402:  * m!=1
                   1403:  * ouf!
                   1404:  */
                   1405: GEN
                   1406: ffsqrtlmod(GEN a, GEN l, GEN T ,GEN p , GEN q, long e, GEN r, GEN y, GEN m)
                   1407: {
                   1408:   ulong av = avma,lim;
                   1409:   long i,k;
                   1410:   GEN p1,p2,u1,u2,v,w,z;
                   1411:
                   1412:   bezout(r,l,&u1,&u2);
                   1413:   v=FpXQ_pow(a,u2,T,p);
                   1414:   w=FpXQ_pow(a,modii(mulii(negi(u1),r),q),T,p);
                   1415:   lim = stack_lim(av,1);
                   1416:   while (!gcmp1(w))
                   1417:   {
                   1418:     /* if p is not prime, next loop will not end */
                   1419:     k=0;
                   1420:     p1=w;
                   1421:     do
                   1422:     {
                   1423:       z=p1;
                   1424:       p1=FpXQ_pow(p1,l,T,p);
                   1425:       k++;
                   1426:     }while(!gcmp1(p1));
                   1427:     if (k==e) { avma=av; return NULL; }
                   1428:     p2 = FpXQ_mul(z,m,T,p);
                   1429:     for(i=1; !gcmp1(p2); i++) p2 = FpXQ_mul(p2,m,T,p);/*should be a baby step
                   1430:                                                              giant step instead*/
                   1431:     p1= FpXQ_pow(y,modii(mulsi(i,gpowgs(l,e-k-1)),q),T,p);
                   1432:     m = FpXQ_pow(m,stoi(i),T,p);
                   1433:     e = k;
                   1434:     v = FpXQ_mul(p1,v,T,p);
                   1435:     y = FpXQ_pow(p1,l,T,p);
                   1436:     w = FpXQ_mul(y,w,T,p);
                   1437:     if (low_stack(lim, stack_lim(av,1)))
                   1438:     {
                   1439:       GEN *gptr[4];
                   1440:       if(DEBUGMEM>1) err(warnmem,"ffsqrtlmod");
                   1441:       gptr[0]=&y; gptr[1]=&v; gptr[2]=&w; gptr[3]=&m;
                   1442:       gerepilemany(av,gptr,4);
                   1443:     }
                   1444:   }
                   1445:   return gerepilecopy(av,v);
                   1446: }
                   1447: /*  n is an integer, a is in Fp[X]/(T), p is prime, T is irreducible mod p
                   1448:
                   1449: return a solution of
                   1450:
                   1451: x^n=a mod p
                   1452:
                   1453: 1)If there is no solution return NULL and if zetan is not NULL set zetan to gzero.
                   1454:
                   1455: 2) If there is solution there are exactly  m=gcd(p-1,n) of them.
                   1456:
                   1457: If zetan is not NULL, zetan is set to a primitive mth root of unity so that
                   1458: the set of solutions is {x*zetan^k;k=0 to m-1}
                   1459:
                   1460: If a=0 ,return 0 and if zetan is not NULL zetan is set to gun
                   1461: */
                   1462: GEN ffsqrtnmod(GEN a, GEN n, GEN T, GEN p, GEN *zetan)
                   1463: {
                   1464:   ulong ltop=avma,lbot=0,av1,lim;
                   1465:   long i,j,e;
                   1466:   GEN m,u1,u2;
                   1467:   GEN q,r,zeta,y,l,z;
                   1468:   GEN *gptr[2];
                   1469:   if (typ(a) != t_POL || typ(n) != t_INT || typ(T) != t_POL || typ(p)!=t_INT)
                   1470:     err(typeer,"ffsqrtnmod");
                   1471:   if (lgef(T)==3)
                   1472:     err(constpoler,"ffsqrtnmod");
                   1473:   if(!signe(n))
                   1474:     err(talker,"1/0 exponent in ffsqrtnmod");
                   1475:   if(gcmp1(n)) {if (zetan) *zetan=gun;return gcopy(a);}
                   1476:   if(gcmp0(a)) {if (zetan) *zetan=gun;return gzero;}
                   1477:   q=addsi(-1,gpowgs(p,degpol(T)));
                   1478:   m=bezout(n,q,&u1,&u2);
                   1479:   if (gcmp(m,n))
                   1480:   {
                   1481:     GEN b=modii(u1,q);
                   1482:     lbot=avma;
                   1483:     a=FpXQ_pow(a,b,T,p);
                   1484:   }
                   1485:   if (zetan) z=polun[varn(T)];
                   1486:   lim=stack_lim(ltop,1);
                   1487:   if (!gcmp1(m))
                   1488:   {
                   1489:     m=decomp(m);
                   1490:     av1=avma;
                   1491:     for (i = lg(m[1])-1; i; i--)
                   1492:     {
                   1493:       l=gcoeff(m,i,1); j=itos(gcoeff(m,i,2));
                   1494:       e=pvaluation(q,l,&r);
                   1495:       y=fflgen(l,e,r,T,p,&zeta);
                   1496:       if (zetan) z=FpXQ_mul(z,FpXQ_pow(y,gpowgs(l,e-j),T,p),T,p);
                   1497:       do
                   1498:       {
                   1499:        lbot=avma;
                   1500:        a=ffsqrtlmod(a,l,T,p,q,e,r,y,zeta);
                   1501:        if (!a){avma=ltop;return NULL;}
                   1502:        j--;
                   1503:       }while (j);
                   1504:       if (low_stack(lim, stack_lim(ltop,1)))
                   1505:          /* n can have lots of prime factors*/
                   1506:       {
                   1507:        if(DEBUGMEM>1) err(warnmem,"ffsqrtnmod");
                   1508:        if (zetan)
                   1509:        {
                   1510:          z=gcopy(z);
                   1511:          gptr[0]=&a;gptr[1]=&z;
                   1512:          gerepilemanysp(av1,lbot,gptr,2);
                   1513:        }
                   1514:        else
                   1515:          a=gerepileupto(av1,a);
                   1516:        lbot=av1;
                   1517:       }
                   1518:     }
                   1519:   }
                   1520:   if (zetan)
                   1521:   {
                   1522:     *zetan=gcopy(z);
                   1523:     gptr[0]=&a;gptr[1]=zetan;
                   1524:     gerepilemanysp(ltop,lbot,gptr,2);
                   1525:   }
                   1526:   else
                   1527:     a=gerepileupto(ltop,a);
                   1528:   return a;
                   1529: }
                   1530: /*******************************************************************/
                   1531: /*  Isomorphisms between finite fields                             */
                   1532: /*                                                                 */
                   1533: /*******************************************************************/
                   1534: GEN
                   1535: matrixpow(long n, long m, GEN y, GEN P,GEN l)
                   1536: {
                   1537:   return vecpol_to_mat(FpXQ_powers(y,m-1,P,l),n);
                   1538: }
                   1539: /* compute the reciprocical isomorphism of S mod T,p, i.e. V such that
                   1540:    V(S)=X  mod T,p*/
                   1541: GEN
                   1542: Fp_inv_isom(GEN S,GEN T, GEN p)
                   1543: {
                   1544:   ulong   ltop = avma, lbot;
                   1545:   GEN     M, V;
                   1546:   int     n, i;
                   1547:   long    x;
                   1548:   x = varn(T);
                   1549:   n = degpol(T);
                   1550:   M = matrixpow(n,n,S,T,p);
                   1551:   V = cgetg(n + 1, t_COL);
                   1552:   for (i = 1; i <= n; i++)
                   1553:     V[i] = zero;
                   1554:   V[2] = un;
                   1555:   V = FpM_invimage(M,V,p);
                   1556:   lbot = avma;
                   1557:   V = gtopolyrev(V, x);
                   1558:   return gerepile(ltop, lbot, V);
                   1559: }
                   1560: #if 0
                   1561: /*Old, trivial, implementation*/
                   1562: GEN
                   1563: intersect_ker(GEN P, GEN MA, GEN l, GEN U, GEN lU)
                   1564: {
                   1565:   ulong ltop=avma;
                   1566:   long vp=varn(P), np=degpol(P);
                   1567:   GEN A;
                   1568:   A=FqM_ker(gaddmat(gneg(polx[MAXVARN]), *MA),lU,l);
                   1569:   if (lg(A)!=2)
                   1570:     err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1571:        ,l,polx[vp],P);
                   1572:   A=gmul((GEN)A[1],gmodulcp(gmodulcp(gun,l),U));
                   1573:   return gerepileupto(ltop,gtopolyrev(A,vp));
                   1574: }
                   1575: #endif
                   1576: /* Let P a polynomial != 0 and M the matrix of the x^p Frobenius automorphism in
                   1577:  * FFp[X]/T. Compute P(M)
                   1578:  * not stack clean
                   1579:  */
                   1580: static GEN
                   1581: polfrobenius(GEN M, GEN p, long r, long v)
                   1582: {
                   1583:   GEN V,W;
                   1584:   long i;
                   1585:   V = cgetg(r+2,t_VEC);
                   1586:   V[1] = (long) polx[v];
                   1587:   if (r == 0) return V;
                   1588:   V[2] = (long) gtopolyrev((GEN)M[2],v);
                   1589:   W = (GEN) M[2];
                   1590:   for (i = 3; i <= r+1; ++i)
                   1591:   {
                   1592:     W = FpM_FpV_mul(M,W,p);
                   1593:     V[i] = (long) gtopolyrev(W,v);
                   1594:   }
                   1595:   return V;
                   1596: }
                   1597:
                   1598: static GEN
                   1599: matpolfrobenius(GEN V, GEN P, GEN T, GEN p)
                   1600: {
                   1601:   long i;
                   1602:   long l=degpol(T);
                   1603:   long v=varn(T);
                   1604:   GEN M,W;
                   1605:   GEN PV=gtovec(P);
                   1606:   PV=cgetg(degpol(P)+2,t_VEC);
                   1607:   for(i=1;i<lg(PV);i++)
                   1608:     PV[i]=P[1+i];
                   1609:   M=cgetg(l+1,t_VEC);
                   1610:   M[1]=(long)scalarpol(poleval(P,gun),v);
                   1611:   M[2]=(long)FpXV_FpV_dotproduct(V,PV,p);
                   1612:   W=cgetg(lg(V),t_VEC);
                   1613:   for(i=1;i<lg(W);i++)
                   1614:      W[i]=V[i];
                   1615:   for(i=3;i<=l;i++)
                   1616:   {
                   1617:     long j;
                   1618:     for(j=1;j<lg(W);j++)
                   1619:       W[j]=(long)FpXQ_mul((GEN)W[j],(GEN)V[j],T,p);
                   1620:     M[i]=(long)FpXV_FpV_dotproduct(W,PV,p);
                   1621:   }
                   1622:   return vecpol_to_mat(M,l);
                   1623: }
                   1624:
                   1625: /* Essentially we want to compute
                   1626:  * FqM_ker(MA-polx[MAXVARN],lU,l)
                   1627:  * To avoid use of matrix in Fq we procede as follows:
                   1628:  * We compute FpM_ker(U(MA)) and then we recover
                   1629:  * the eigen value by Galois action, see formula.
                   1630:  */
                   1631: static GEN
                   1632: intersect_ker(GEN P, GEN MA, GEN l, GEN U, GEN lU)
                   1633: {
                   1634:   ulong ltop=avma;
                   1635:   long vp=varn(P);
                   1636:   long vu=varn(lU), r=degpol(lU);
                   1637:   long i;
                   1638:   GEN A, R, M, ib0, V;
                   1639:   if (DEBUGLEVEL>=4) timer2();
                   1640:   V=polfrobenius(MA,l,r,varn(U));
                   1641:   if (DEBUGLEVEL>=4) msgtimer("pol[frobenius]");
                   1642:   M=matpolfrobenius(V,lU,P,l);
                   1643:   if (DEBUGLEVEL>=4) msgtimer("matrix cyclo");
                   1644:   A=FpM_ker(M,l);
                   1645:   if (DEBUGLEVEL>=4) msgtimer("kernel");
                   1646:   A=gerepileupto(ltop,A);
                   1647:   if (lg(A)!=r+1)
                   1648:     err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1649:        ,l,polx[vp],P);
                   1650:   /*The formula is
                   1651:    * a_{r-1}=-\phi(a_0)/b_0
                   1652:    * a_{i-1}=\phi(a_i)+b_ia_{r-1}  i=r-1 to 1
                   1653:    * Where a_0=A[1] and b_i=U[i+2]
                   1654:    */
                   1655:   ib0=negi(mpinvmod((GEN)lU[2],l));
                   1656:   R=cgetg(r+1,t_MAT);
                   1657:   R[1]=A[1];
                   1658:   R[r]=(long)FpM_FpV_mul(MA,gmul((GEN)A[1],ib0),l);
                   1659:   for(i=r-1;i>1;i--)
                   1660:     R[i]=(long)FpV_red(gadd(FpM_FpV_mul(MA,(GEN)R[i+1],l),
                   1661:          gmul((GEN)lU[i+2],(GEN)R[r])),l);
                   1662:   R=gtrans_i(R);
                   1663:   for(i=1;i<lg(R);i++)
                   1664:     R[i]=(long)gtopolyrev((GEN)R[i],vu);
                   1665:   A=gtopolyrev(R,vp);
                   1666:   A=gmul(A,gmodulcp(gmodulcp(gun,l),U));
                   1667:   return gerepileupto(ltop,A);
                   1668: }
                   1669:
                   1670: /* n must divide both the degree of P and Q.  Compute SP and SQ such
                   1671:   that the subfield of FF_l[X]/(P) generated by SP and the subfield of
                   1672:   FF_l[X]/(Q) generated by SQ are isomorphic of degree n.  P and Q do
                   1673:   not need to be of the same variable.  if MA (resp. MB) is not NULL,
                   1674:   must be the matrix of the frobenius map in FF_l[X]/(P) (resp.
                   1675:   FF_l[X]/(Q) ).  */
                   1676: /* Note on the implementation choice:
                   1677:  * We assume the prime p is very large
                   1678:  * so we handle Frobenius as matrices.
                   1679:  */
                   1680: void
                   1681: Fp_intersect(long n, GEN P, GEN Q, GEN l,GEN *SP, GEN *SQ, GEN MA, GEN MB)
                   1682: {
                   1683:   ulong ltop=avma,lbot;
                   1684:   long vp,vq,np,nq,e,pg;
                   1685:   GEN q;
                   1686:   GEN A,B,Ap,Bp;
                   1687:   GEN *gptr[2];
                   1688:   vp=varn(P);vq=varn(Q);
                   1689:   np=degpol(P);nq=degpol(Q);
                   1690:   if (np<=0 || nq<=0 || n<=0 || np%n!=0 || nq%n!=0)
                   1691:     err(talker,"bad degrees in Fp_intersect: %d,%d,%d",n,degpol(P),degpol(Q));
                   1692:   e=pvaluation(stoi(n),l,&q);
                   1693:   pg=itos(q);
                   1694:   avma=ltop;
                   1695:   if (DEBUGLEVEL>=4) timer2();
                   1696:   if(!MA) MA=matrixpow(np,np,FpXQ_pow(polx[vp],l,P,l),P,l);
                   1697:   if(!MB) MB=matrixpow(nq,nq,FpXQ_pow(polx[vq],l,Q,l),Q,l);
                   1698:   if (DEBUGLEVEL>=4) msgtimer("matrixpow");
                   1699:   A=Ap=zeropol(vp);
                   1700:   B=Bp=zeropol(vq);
                   1701:   if (pg>1)
                   1702:   {
                   1703:     if (gcmp0(modis(addis(l,-1),pg)))
                   1704:       /*We do not need to use relative extension in this setting, so
                   1705:         we don't. (Well,now that we don't in the other case also, it is more
                   1706:        dubious to treat cases apart...)*/
                   1707:     {
                   1708:       GEN L,An,Bn,ipg,z;
                   1709:       z=rootmod(cyclo(pg,-1),l);
                   1710:       if (lg(z)<2) err(talker,"%Z is not a prime in Fp_intersect",l);
                   1711:       z=negi(lift((GEN)z[1]));
                   1712:       ipg=stoi(pg);
                   1713:       if (DEBUGLEVEL>=4) timer2();
                   1714:       A=FpM_ker(gaddmat(z, MA),l);
                   1715:       if (lg(A)!=2)
                   1716:        err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1717:            ,l,polx[vp],P);
                   1718:       A=gtopolyrev((GEN)A[1],vp);
                   1719:       B=FpM_ker(gaddmat(z, MB),l);
                   1720:       if (lg(B)!=2)
                   1721:        err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1722:            ,l,polx[vq],Q);
                   1723:       B=gtopolyrev((GEN)B[1],vq);
                   1724:       if (DEBUGLEVEL>=4) msgtimer("FpM_ker");
                   1725:       An=(GEN) FpXQ_pow(A,ipg,P,l)[2];
                   1726:       Bn=(GEN) FpXQ_pow(B,ipg,Q,l)[2];
                   1727:       z=modii(mulii(An,mpinvmod(Bn,l)),l);
                   1728:       L=mpsqrtnmod(z,ipg,l,NULL);
                   1729:       if ( !L )
                   1730:         err(talker,"Polynomials not irreducible in Fp_intersect");
                   1731:       if (DEBUGLEVEL>=4) msgtimer("mpsqrtnmod");
                   1732:       B=FpX_Fp_mul(B,L,l);
                   1733:     }
                   1734:     else
                   1735:     {
                   1736:       GEN L,An,Bn,ipg,U,lU,z;
                   1737:       U=gmael(factmod(cyclo(pg,MAXVARN),l),1,1);
                   1738:       lU=lift(U);
                   1739:       ipg=stoi(pg);
                   1740:       A=intersect_ker(P, MA, l, U, lU);
                   1741:       B=intersect_ker(Q, MB, l, U, lU);
                   1742:       /*Somewhat ugly, but it is a proof that POLYMOD are useful and
                   1743:         powerful.*/
                   1744:       if (DEBUGLEVEL>=4) timer2();
                   1745:       An=lift(lift((GEN)lift(gpowgs(gmodulcp(A,P),pg))[2]));
                   1746:       Bn=lift(lift((GEN)lift(gpowgs(gmodulcp(B,Q),pg))[2]));
                   1747:       if (DEBUGLEVEL>=4) msgtimer("pows [P,Q]");
                   1748:       z=FpXQ_inv(Bn,lU,l);
                   1749:       z=FpXQ_mul(An,z,lU,l);
                   1750:       L=ffsqrtnmod(z,ipg,lU,l,NULL);
                   1751:       if (DEBUGLEVEL>=4) msgtimer("ffsqrtn");
                   1752:       if ( !L )
                   1753:         err(talker,"Polynomials not irreducible in Fp_intersect");
                   1754:       B=gsubst(lift(lift(gmul(B,L))),MAXVARN,gzero);
                   1755:       A=gsubst(lift(lift(A)),MAXVARN,gzero);
                   1756:     }
                   1757:   }
                   1758:   if (e!=0)
                   1759:   {
                   1760:     GEN VP,VQ,moinsun,Ay,By,lmun;
                   1761:     int i,j;
                   1762:     moinsun=stoi(-1);
                   1763:     lmun=addis(l,-1);
                   1764:     MA=gaddmat(moinsun,MA);
                   1765:     MB=gaddmat(moinsun,MB);
                   1766:     Ay=polun[vp];
                   1767:     By=polun[vq];
                   1768:     VP=cgetg(np+1,t_COL);
                   1769:     VP[1]=un;
                   1770:     for(i=2;i<=np;i++) VP[i]=zero;
                   1771:     if (np==nq) VQ=VP;/*save memory*/
                   1772:     else
                   1773:     {
                   1774:       VQ=cgetg(nq+1,t_COL);
                   1775:       VQ[1]=un;
                   1776:       for(i=2;i<=nq;i++) VQ[i]=zero;
                   1777:     }
                   1778:     for(j=0;j<e;j++)
                   1779:     {
                   1780:       if (j)
                   1781:       {
                   1782:        Ay=FpXQ_mul(Ay,FpXQ_pow(Ap,lmun,P,l),P,l);
                   1783:        for(i=1;i<lgef(Ay)-1;i++) VP[i]=Ay[i+1];
                   1784:        for(;i<=np;i++) VP[i]=zero;
                   1785:       }
                   1786:       Ap=FpM_invimage(MA,VP,l);
                   1787:       Ap=gtopolyrev(Ap,vp);
                   1788:       if (j)
                   1789:       {
                   1790:        By=FpXQ_mul(By,FpXQ_pow(Bp,lmun,Q,l),Q,l);
                   1791:        for(i=1;i<lgef(By)-1;i++) VQ[i]=By[i+1];
                   1792:        for(;i<=nq;i++) VQ[i]=zero;
                   1793:       }
                   1794:       Bp=FpM_invimage(MB,VQ,l);
                   1795:       Bp=gtopolyrev(Bp,vq);
                   1796:       if (DEBUGLEVEL>=4) msgtimer("FpM_invimage");
                   1797:     }
                   1798:   }/*FpX_add is not clean, so we must do it *before* lbot=avma*/
                   1799:   A=FpX_add(A,Ap,NULL);
                   1800:   B=FpX_add(B,Bp,NULL);
                   1801:   lbot=avma;
                   1802:   *SP=FpX_red(A,l);
                   1803:   *SQ=FpX_red(B,l);
                   1804:   gptr[0]=SP;gptr[1]=SQ;
                   1805:   gerepilemanysp(ltop,lbot,gptr,2);
                   1806: }
                   1807: /* Let l be a prime number, P, Q in ZZ[X].  P and Q are both
                   1808:  * irreducible modulo l and degree(P) divides degree(Q).  Output a
                   1809:  * monomorphism between FF_l[X]/(P) and FF_l[X]/(Q) as a polynomial R such
                   1810:  * that Q | P(R) mod l.  If P and Q have the same degree, it is of course an
                   1811:  * isomorphism.  */
                   1812: GEN Fp_isom(GEN P,GEN Q,GEN l)
                   1813: {
                   1814:   ulong ltop=avma;
                   1815:   GEN SP,SQ,R;
                   1816:   Fp_intersect(degpol(P),P,Q,l,&SP,&SQ,NULL,NULL);
                   1817:   R=Fp_inv_isom(SP,P,l);
                   1818:   R=FpX_FpXQ_compo(R,SQ,Q,l);
                   1819:   return gerepileupto(ltop,R);
                   1820: }
                   1821: GEN
                   1822: Fp_factorgalois(GEN P,GEN l, long d, long w)
                   1823: {
                   1824:   ulong ltop=avma;
                   1825:   GEN R,V,ld,Tl;
                   1826:   long n,k,m;
                   1827:   long v;
                   1828:   v=varn(P);
                   1829:   n=degpol(P);
                   1830:   m=n/d;
                   1831:   ld=gpowgs(l,d);
                   1832:   Tl=gcopy(P); setvarn(Tl,w);
                   1833:   V=cgetg(m+1,t_VEC);
                   1834:   V[1]=lpolx[w];
                   1835:   for(k=2;k<=m;k++)
                   1836:     V[k]=(long)FpXQ_pow((GEN)V[k-1],ld,Tl,l);
                   1837:   R=FqV_roots_to_pol(V,Tl,l,v);
                   1838:   return gerepileupto(ltop,R);
                   1839: }
                   1840: extern GEN mat_to_polpol(GEN x, long v,long w);
                   1841: extern GEN polpol_to_mat(GEN v, long n);
                   1842: /* P,Q irreducible over F_l. Factor P over FF_l[X] / Q  [factors are ordered as
                   1843:  * a Frobenius cycle] */
                   1844: GEN
                   1845: Fp_factor_irred(GEN P,GEN l, GEN Q)
                   1846: {
                   1847:   ulong ltop=avma,av;
                   1848:   GEN SP,SQ,MP,MQ,M,MF,E,V,IR,res;
                   1849:   long np=degpol(P),nq=degpol(Q);
                   1850:   long i,d=cgcd(np,nq);
                   1851:   long vp=varn(P),vq=varn(Q);
                   1852:   if (d==1)
                   1853:   {
                   1854:     res=cgetg(2,t_COL);
                   1855:     res[1]=lcopy(P);
                   1856:     return res;
                   1857:   }
                   1858:   MF=matrixpow(nq,nq,FpXQ_pow(polx[vq],l,Q,l),Q,l);
                   1859:   Fp_intersect(d,P,Q,l,&SP,&SQ,NULL,MF);
                   1860:   av=avma;
                   1861:   E=Fp_factorgalois(P,l,d,vq);
                   1862:   E=polpol_to_mat(E,np);
                   1863:   MP = matrixpow(np,d,SP,P,l);
                   1864:   IR = (GEN)FpM_sindexrank(MP,l)[1];
                   1865:   E = rowextract_p(E, IR);
                   1866:   M = rowextract_p(MP,IR);
                   1867:   M = FpM_inv(M,l);
                   1868:   MQ = matrixpow(nq,d,SQ,Q,l);
                   1869:   M = FpM_mul(MQ,M,l);
                   1870:   M = FpM_mul(M,E,l);
                   1871:   M = gerepileupto(av,M);
                   1872:   V = cgetg(d+1,t_VEC);
                   1873:   V[1]=(long)M;
                   1874:   for(i=2;i<=d;i++)
                   1875:     V[i]=(long)FpM_mul(MF,(GEN)V[i-1],l);
                   1876:   res=cgetg(d+1,t_COL);
                   1877:   for(i=1;i<=d;i++)
                   1878:     res[i]=(long)mat_to_polpol((GEN)V[i],vp,vq);
                   1879:   return gerepilecopy(ltop,res);
                   1880: }
                   1881: GEN Fp_factor_rel0(GEN P,GEN l, GEN Q)
                   1882: {
                   1883:   ulong ltop=avma,tetpil;
                   1884:   GEN V,ex,F,y,R;
                   1885:   long n,nbfact=0,nmax=lgef(P)-2;
                   1886:   long i;
                   1887:   F=factmod0(P,l);
                   1888:   n=lg((GEN)F[1]);
                   1889:   V=cgetg(nmax,t_VEC);
                   1890:   ex=cgetg(nmax,t_VECSMALL);
                   1891:   for(i=1;i<n;i++)
                   1892:   {
                   1893:     int j,r;
                   1894:     R=Fp_factor_irred(gmael(F,1,i),l,Q);
                   1895:     r=lg(R);
                   1896:     for (j=1;j<r;j++)
                   1897:     {
                   1898:       V[++nbfact]=R[j];
                   1899:       ex[nbfact]=mael(F,2,i);
                   1900:     }
                   1901:   }
                   1902:   setlg(V,nbfact+1);
                   1903:   setlg(ex,nbfact+1);
                   1904:   tetpil=avma; y=cgetg(3,t_VEC);
                   1905:   y[1]=lcopy(V);
                   1906:   y[2]=lcopy(ex);
                   1907:   (void)sort_factor(y,cmp_pol);
                   1908:   return gerepile(ltop,tetpil,y);
                   1909: }
                   1910: GEN Fp_factor_rel(GEN P, GEN l, GEN Q)
                   1911: {
                   1912:   long tetpil,av=avma;
                   1913:   long nbfact;
                   1914:   long j;
                   1915:   GEN y,u,v;
                   1916:   GEN z=Fp_factor_rel0(P,l,Q),t = (GEN) z[1],ex = (GEN) z[2];
                   1917:   nbfact=lg(t);
                   1918:   tetpil=avma; y=cgetg(3,t_MAT);
                   1919:   u=cgetg(nbfact,t_COL); y[1]=(long)u;
                   1920:   v=cgetg(nbfact,t_COL); y[2]=(long)v;
                   1921:   for (j=1; j<nbfact; j++)
                   1922:   {
                   1923:     u[j] = lcopy((GEN)t[j]);
                   1924:     v[j] = lstoi(ex[j]);
                   1925:   }
                   1926:   return gerepile(av,tetpil,y);
                   1927: }
                   1928:
                   1929: /*******************************************************************/
                   1930: extern int ff_poltype(GEN *x, GEN *p, GEN *pol);
                   1931:
                   1932: static GEN
                   1933: to_intmod(GEN x, GEN p)
                   1934: {
                   1935:   GEN a = cgetg(3,t_INTMOD);
                   1936:   a[1] = (long)p;
                   1937:   a[2] = lmodii(x,p); return a;
                   1938: }
                   1939:
                   1940: /* z in Z[X], return z * Mod(1,p), normalized*/
                   1941: GEN
                   1942: FpX(GEN z, GEN p)
                   1943: {
                   1944:   long i,l = lgef(z);
                   1945:   GEN x = cgetg(l,t_POL);
                   1946:   if (isonstack(p)) p = icopy(p);
                   1947:   for (i=2; i<l; i++) x[i] = (long)to_intmod((GEN)z[i], p);
                   1948:   x[1] = z[1]; return normalizepol_i(x,l);
                   1949: }
                   1950:
                   1951: /* z in Z^n, return z * Mod(1,p), normalized*/
                   1952: GEN
                   1953: FpV(GEN z, GEN p)
                   1954: {
                   1955:   long i,l = lg(z);
                   1956:   GEN x = cgetg(l,typ(z));
                   1957:   if (isonstack(p)) p = icopy(p);
                   1958:   for (i=1; i<l; i++) x[i] = (long)to_intmod((GEN)z[i], p);
                   1959:   return x;
                   1960: }
                   1961: /* z in Mat m,n(Z), return z * Mod(1,p), normalized*/
                   1962: GEN
                   1963: FpM(GEN z, GEN p)
                   1964: {
                   1965:   long i,j,l = lg(z), m = lg((GEN)z[1]);
                   1966:   GEN x,y,zi;
                   1967:   if (isonstack(p)) p = icopy(p);
                   1968:   x = cgetg(l,t_MAT);
                   1969:   for (i=1; i<l; i++)
                   1970:   {
                   1971:     x[i] = lgetg(m,t_COL);
                   1972:     y = (GEN)x[i];
                   1973:     zi= (GEN)z[i];
                   1974:     for (j=1; j<m; j++) y[j] = (long)to_intmod((GEN)zi[j], p);
                   1975:   }
                   1976:   return x;
                   1977: }
                   1978: /* z in Z[X] or Z, return lift(z * Mod(1,p)), normalized*/
                   1979: GEN
                   1980: FpX_red(GEN z, GEN p)
                   1981: {
                   1982:   long i,l;
                   1983:   GEN x;
                   1984:   if (typ(z) == t_INT) return modii(z,p);
                   1985:   l = lgef(z);
                   1986:   x = cgetg(l,t_POL);
                   1987:   for (i=2; i<l; i++) x[i] = lmodii((GEN)z[i],p);
                   1988:   x[1] = z[1]; return normalizepol_i(x,l);
                   1989: }
                   1990:
                   1991: GEN
                   1992: FpXV_red(GEN z, GEN p)
                   1993: {
                   1994:   long i,l = lg(z);
                   1995:   GEN x = cgetg(l, t_VEC);
                   1996:   for (i=1; i<l; i++) x[i] = (long)FpX_red((GEN)z[i], p);
                   1997:   return x;
                   1998: }
                   1999:
                   2000: /* z in Z^n, return lift(z * Mod(1,p)) */
                   2001: GEN
                   2002: FpV_red(GEN z, GEN p)
                   2003: {
                   2004:   long i,l = lg(z);
                   2005:   GEN x = cgetg(l,typ(z));
                   2006:   for (i=1; i<l; i++) x[i] = lmodii((GEN)z[i],p);
                   2007:   return x;
                   2008: }
                   2009:
                   2010: /* z in Mat m,n(Z), return lift(z * Mod(1,p)) */
                   2011: GEN
                   2012: FpM_red(GEN z, GEN p)
                   2013: {
                   2014:   long i,j,l = lg(z), m = lg((GEN)z[1]);
                   2015:   GEN x,y;
                   2016:   x = cgetg(l,t_MAT);
                   2017:   for (i=1; i<l; i++)
                   2018:   {
                   2019:     x[i]=lgetg(m,t_MAT);y=(GEN)x[i];
                   2020:     for(j=1; j<m ; j++)
                   2021:       y[j] = lmodii(gmael(z,i,j),p);
                   2022:   }
                   2023:   return x;
                   2024: }
                   2025:
                   2026: /* no garbage collection, divide by leading coeff, mod p */
                   2027: GEN
                   2028: FpX_normalize(GEN z, GEN p)
                   2029: {
                   2030:   GEN p1 = leading_term(z);
                   2031:   if (gcmp1(p1)) return z;
                   2032:   return FpX_Fp_mul(z, mpinvmod(p1,p), p);
                   2033: }
                   2034:
                   2035: GEN
                   2036: FpXQX_normalize(GEN z, GEN T, GEN p)
                   2037: {
                   2038:   GEN p1 = leading_term(z);
                   2039:   if (gcmp1(p1)) return z;
                   2040:   if (!T) return FpX_normalize(z,p);
                   2041:   return FpXQX_FpXQ_mul(z, FpXQ_inv(p1,T,p), T,p);
                   2042: }
                   2043:
                   2044: GEN
                   2045: small_to_mat(GEN z)
                   2046: {
                   2047:   long i, l = lg(z);
                   2048:   GEN x = cgetg(l,t_MAT);
                   2049:   for (i=1; i<l; i++) { x[i] = (long)gtovec((GEN)z[i]); settyp(x[i], t_COL); }
                   2050:   return x;
                   2051: }
                   2052:
                   2053: GEN
                   2054: small_to_pol_i(GEN z, long l)
                   2055: {
                   2056:   long i;
                   2057:   GEN x = cgetg(l,t_POL);
                   2058:   for (i=2; i<l; i++) x[i] = lstoi(z[i]);
                   2059:   x[1] = z[1]; return x;
                   2060: }
                   2061:
                   2062: /* assume z[i] % p has been done */
                   2063: GEN
                   2064: small_to_pol(GEN z, long v)
                   2065: {
                   2066:   GEN x = small_to_pol_i(z, lgef(z));
                   2067:   setvarn(x,v); return x;
                   2068: }
                   2069:
                   2070: GEN
                   2071: pol_to_small(GEN x)
                   2072: {
                   2073:   long i, lx = lgef(x);
                   2074:   GEN a = u_allocpol(lx-3, 0);
                   2075:   for (i=2; i<lx; i++) a[i] = itos((GEN)x[i]);
                   2076:   return a;
                   2077: }
                   2078:
                   2079: /* z in Z[X,Y] representing an elt in F_p[X,Y] mod pol(Y) i.e F_q[X])
                   2080:  * in Kronecker form. Recover the "real" z, normalized
                   2081:  * If p = NULL, use generic functions and the coeff. ring implied by the
                   2082:  * coefficients of z */
                   2083: GEN
                   2084: FqX_from_Kronecker(GEN z, GEN pol, GEN p)
                   2085: {
                   2086:   long i,j,lx,l = lgef(z), N = (degpol(pol)<<1) + 1;
                   2087:   GEN a,x, t = cgetg(N,t_POL);
                   2088:   t[1] = pol[1] & VARNBITS;
                   2089:   lx = (l-2) / (N-2); x = cgetg(lx+3,t_POL);
                   2090:   if (isonstack(pol)) pol = gcopy(pol);
                   2091:   for (i=2; i<lx+2; i++)
                   2092:   {
                   2093:     a = cgetg(3,t_POLMOD); x[i] = (long)a;
                   2094:     a[1] = (long)pol;
                   2095:     for (j=2; j<N; j++) t[j] = z[j];
                   2096:     z += (N-2);
                   2097:     a[2] = (long)FpX_res(normalizepol_i(t,N), pol,p);
                   2098:   }
                   2099:   a = cgetg(3,t_POLMOD); x[i] = (long)a;
                   2100:   a[1] = (long)pol;
                   2101:   N = (l-2) % (N-2) + 2;
                   2102:   for (j=2; j<N; j++) t[j] = z[j];
                   2103:   a[2] = (long)FpX_res(normalizepol_i(t,N), pol,p);
                   2104:   return normalizepol_i(x, i+1);
                   2105: }
                   2106:
                   2107: /* z in ?[X,Y] mod Q(Y) in Kronecker form ((subst(lift(z), x, y^(2deg(z)-1)))
                   2108:  * Recover the "real" z, normalized */
                   2109: GEN
                   2110: from_Kronecker(GEN z, GEN pol)
                   2111: {
                   2112:   return FqX_from_Kronecker(z,pol,NULL);
                   2113: }
                   2114:
                   2115: /*******************************************************************/
                   2116: /*                                                                 */
                   2117: /*                          MODULAR GCD                            */
                   2118: /*                                                                 */
                   2119: /*******************************************************************/
                   2120: ulong xgcduu(ulong d, ulong d1, int f, ulong* v, ulong* v1, long *s);
                   2121: /* 1 / Mod(x,p) , or 0 if inverse doesn't exist */
                   2122: ulong
                   2123: u_invmod(ulong x, ulong p)
                   2124: {
                   2125:   long s;
                   2126:   ulong xv, xv1, g = xgcduu(p, x, 1, &xv, &xv1, &s);
                   2127:   if (g != 1UL) return 0UL;
                   2128:   xv = xv1 % p; if (s < 0) xv = p - xv;
                   2129:   return xv;
                   2130: }
                   2131:
                   2132: #if 0
                   2133: static ulong
                   2134: umodratu(GEN a, ulong p)
                   2135: {
                   2136:   if (typ(a) == t_INT)
                   2137:     return umodiu(a,p);
                   2138:   else { /* assume a a t_FRAC */
                   2139:     ulong num = umodiu((GEN)a[1],p);
                   2140:     ulong den = umodiu((GEN)a[2],p);
                   2141:     return (ulong)mulssmod(num, u_invmod(den,p), p);
                   2142:   }
                   2143: }
                   2144: #endif
                   2145:
                   2146: /* return x[0 .. dx] mod p as t_VECSMALL. Assume x a t_POL/VECSMALL/INT */
                   2147: GEN
                   2148: u_Fp_FpX(GEN x, int malloc, ulong p)
                   2149: {
                   2150:   long i, lx;
                   2151:   GEN a;
                   2152:
                   2153:   switch (typ(x))
                   2154:   {
                   2155:     case t_VECSMALL: return x;
                   2156:     case t_INT: a = u_allocpol(0, malloc);
                   2157:       a[2] = umodiu(x, p); return a;
                   2158:   }
                   2159:   lx = lgef(x); a = u_allocpol(lx-3, malloc);
                   2160:   for (i=2; i<lx; i++) a[i] = (long)umodiu((GEN)x[i], p);
                   2161:   return u_normalizepol(a,lx);
                   2162: }
                   2163:
                   2164: GEN
                   2165: u_Fp_FpM(GEN x, ulong p)
                   2166: {
                   2167:   long i,j,m,n = lg(x);
                   2168:   GEN y = cgetg(n,t_MAT);
                   2169:   if (n == 1) return y;
                   2170:   m = lg(x[1]);
                   2171:   for (j=1; j<n; j++)
                   2172:   {
                   2173:     y[j] = (long)cgetg(m,t_VECSMALL);
                   2174:     for (i=1; i<m; i++) coeff(y,i,j) = (long)umodiu(gcoeff(x,i,j), p);
                   2175:   }
                   2176:   return y;
                   2177: }
                   2178:
                   2179: static GEN
                   2180: u_FpX_Fp_mul(GEN y, ulong x,ulong p, int malloc)
                   2181: {
                   2182:   GEN z;
                   2183:   int i, l;
                   2184:   if (!x) return u_zeropol(malloc);
                   2185:   l = lgef(y); z = u_allocpol(l-3, malloc);
                   2186:   if (HIGHWORD(x | p))
                   2187:     for(i=2; i<l; i++) z[i] = mulssmod(y[i], x, p);
                   2188:   else
                   2189:     for(i=2; i<l; i++) z[i] = (y[i] * x) % p;
                   2190:   return z;
                   2191: }
                   2192:
                   2193: GEN
                   2194: u_FpX_normalize(GEN z, ulong p)
                   2195: {
                   2196:   long l = lgef(z)-1;
                   2197:   ulong p1 = z[l]; /* leading term */
                   2198:   if (p1 == 1) return z;
                   2199:   return u_FpX_Fp_mul(z, u_invmod(p1,p), p, 0);
                   2200: }
                   2201:
                   2202: static GEN
                   2203: u_copy(GEN x, int malloc)
                   2204: {
                   2205:   long i, l = lgef(x);
                   2206:   GEN z = u_allocpol(l-3, malloc);
                   2207:   for (i=2; i<l; i++) z[i] = x[i];
                   2208:   return z;
                   2209: }
                   2210:
                   2211: /* as FpX_divres but working only on ulong types. ASSUME pr != ONLY_DIVIDES */
                   2212: GEN
                   2213: u_FpX_divrem(GEN x, GEN y, ulong p, int malloc, GEN *pr)
                   2214: {
                   2215:   GEN z,q,c;
                   2216:   long dx,dy,dz,i,j;
                   2217:   ulong p1,inv;
                   2218:
                   2219:   dy = degpol(y);
                   2220:   if (!dy)
                   2221:   {
                   2222:     if (pr)
                   2223:     {
                   2224:       if (pr == ONLY_REM) return u_zeropol(malloc);
                   2225:       *pr = u_zeropol(malloc);
                   2226:     }
                   2227:     if (y[2] == 1UL) return u_copy(x,malloc);
                   2228:     return u_FpX_Fp_mul(x, u_invmod(y[2], p), p, malloc);
                   2229:   }
                   2230:   dx = degpol(x);
                   2231:   dz = dx-dy;
                   2232:   if (dz < 0)
                   2233:   {
                   2234:     if (pr)
                   2235:     {
                   2236:       c = u_copy(x, malloc);
                   2237:       if (pr == ONLY_REM) return c;
                   2238:       *pr = c;
                   2239:     }
                   2240:     return u_zeropol(malloc);
                   2241:   }
                   2242:   x += 2;
                   2243:   y += 2;
                   2244:   z = u_allocpol(dz, malloc || (pr == ONLY_REM)) + 2;
                   2245:   inv = y[dy];
                   2246:   if (inv != 1UL) inv = u_invmod(inv,p);
                   2247:
                   2248:   if (u_OK_ULONG(p))
                   2249:   {
                   2250:     z[dz] = (inv*x[dx]) % p;
                   2251:     for (i=dx-1; i>=dy; --i)
                   2252:     {
                   2253:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   2254:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   2255:       {
                   2256:         p1 += z[j]*y[i-j];
                   2257:         if (p1 & HIGHBIT) p1 = p1 % p;
                   2258:       }
                   2259:       p1 %= p;
                   2260:       z[i-dy] = p1? ((p - p1)*inv) % p: 0;
                   2261:     }
                   2262:   }
                   2263:   else
                   2264:   {
                   2265:     z[dz] = mulssmod(inv, x[dx], p);
                   2266:     for (i=dx-1; i>=dy; --i)
                   2267:     {
                   2268:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   2269:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   2270:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   2271:       z[i-dy] = p1? mulssmod(p - p1, inv, p): 0;
                   2272:     }
                   2273:   }
                   2274:   q = u_normalizepol(z-2, dz+3);
                   2275:   if (!pr) return q;
                   2276:
                   2277:   c = u_allocpol(dy,malloc) + 2;
                   2278:   if (u_OK_ULONG(p))
                   2279:   {
                   2280:     for (i=0; i<dy; i++)
                   2281:     {
                   2282:       p1 = z[0]*y[i];
                   2283:       for (j=1; j<=i && j<=dz; j++)
                   2284:       {
                   2285:         p1 += z[j]*y[i-j];
                   2286:         if (p1 & HIGHBIT) p1 = p1 % p;
                   2287:       }
                   2288:       c[i] = subssmod(x[i], p1%p, p);
                   2289:     }
                   2290:   }
                   2291:   else
                   2292:   {
                   2293:     for (i=0; i<dy; i++)
                   2294:     {
                   2295:       p1 = mulssmod(z[0],y[i],p);
                   2296:       for (j=1; j<=i && j<=dz; j++)
                   2297:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   2298:       c[i] = subssmod(x[i], p1, p);
                   2299:     }
                   2300:   }
                   2301:   i=dy-1; while (i>=0 && !c[i]) i--;
                   2302:   c = u_normalizepol(c-2, i+3);
                   2303:   if (pr == ONLY_REM) { free(q); return c; }
                   2304:   *pr = c; return q;
                   2305: }
                   2306:
                   2307: /* x and y in Z[X]. Possibly x in Z */
                   2308: GEN
                   2309: FpX_divres(GEN x, GEN y, GEN p, GEN *pr)
                   2310: {
                   2311:   long vx,dx,dy,dz,i,j,av0,av,tetpil,sx,lrem;
                   2312:   GEN z,p1,rem,lead;
                   2313:
                   2314:   if (!p) return poldivres(x,y,pr);
                   2315:   if (!signe(y)) err(talker,"division by zero in FpX_divres");
                   2316:   vx=varn(x); dy=degpol(y); dx=(typ(x)==t_INT)? 0: degpol(x);
                   2317:   if (dx < dy)
                   2318:   {
                   2319:     if (pr)
                   2320:     {
                   2321:       av0 = avma; x = FpX_red(x, p);
                   2322:       if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: gzero; }
                   2323:       if (pr == ONLY_REM) return x;
                   2324:       *pr = x;
                   2325:     }
                   2326:     return zeropol(vx);
                   2327:   }
                   2328:   lead = leading_term(y);
                   2329:   if (!dy) /* y is constant */
                   2330:   {
                   2331:     if (pr && pr != ONLY_DIVIDES)
                   2332:     {
                   2333:       if (pr == ONLY_REM) return zeropol(vx);
                   2334:       *pr = zeropol(vx);
                   2335:     }
                   2336:     if (gcmp1(lead)) return gcopy(x);
                   2337:     av0 = avma; x = gmul(x, mpinvmod(lead,p)); tetpil = avma;
                   2338:     return gerepile(av0,tetpil,FpX_red(x,p));
                   2339:   }
                   2340:   av0 = avma; dz = dx-dy;
                   2341:   if (OK_ULONG(p))
                   2342:   { /* assume ab != 0 mod p */
                   2343:     ulong pp = (ulong)p[2];
                   2344:     GEN a = u_Fp_FpX(x,1, pp);
                   2345:     GEN b = u_Fp_FpX(y,1, pp);
                   2346:     GEN zz= u_FpX_divrem(a,b,pp,1, pr);
                   2347:     if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)
                   2348:     {
                   2349:       rem = small_to_pol(*pr,vx);
                   2350:       free(*pr); *pr = rem;
                   2351:     }
                   2352:     z = small_to_pol(zz,vx);
                   2353:     free(zz); free(a); free(b); return z;
                   2354:   }
                   2355:   lead = gcmp1(lead)? NULL: gclone(mpinvmod(lead,p));
                   2356:   avma = av0;
                   2357:   z=cgetg(dz+3,t_POL);
                   2358:   z[1]=evalsigne(1) | evallgef(dz+3) | evalvarn(vx);
                   2359:   x += 2; y += 2; z += 2;
                   2360:
                   2361:   p1 = (GEN)x[dx]; av = avma;
                   2362:   z[dz] = lead? lpileupto(av, modii(mulii(p1,lead), p)): licopy(p1);
                   2363:   for (i=dx-1; i>=dy; i--)
                   2364:   {
                   2365:     av=avma; p1=(GEN)x[i];
                   2366:     for (j=i-dy+1; j<=i && j<=dz; j++)
                   2367:       p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j]));
                   2368:     if (lead) p1 = mulii(p1,lead);
                   2369:     tetpil=avma; z[i-dy] = lpile(av,tetpil,modii(p1, p));
                   2370:   }
                   2371:   if (!pr) { if (lead) gunclone(lead); return z-2; }
                   2372:
                   2373:   rem = (GEN)avma; av = (long)new_chunk(dx+3);
                   2374:   for (sx=0; ; i--)
                   2375:   {
                   2376:     p1 = (GEN)x[i];
                   2377:     for (j=0; j<=i && j<=dz; j++)
                   2378:       p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j]));
                   2379:     tetpil=avma; p1 = modii(p1,p); if (signe(p1)) { sx = 1; break; }
                   2380:     if (!i) break;
                   2381:     avma=av;
                   2382:   }
                   2383:   if (pr == ONLY_DIVIDES)
                   2384:   {
                   2385:     if (lead) gunclone(lead);
                   2386:     if (sx) { avma=av0; return NULL; }
                   2387:     avma = (long)rem; return z-2;
                   2388:   }
                   2389:   lrem=i+3; rem -= lrem;
                   2390:   rem[0]=evaltyp(t_POL) | evallg(lrem);
                   2391:   rem[1]=evalsigne(1) | evalvarn(vx) | evallgef(lrem);
                   2392:   p1 = gerepile((long)rem,tetpil,p1);
                   2393:   rem += 2; rem[i]=(long)p1;
                   2394:   for (i--; i>=0; i--)
                   2395:   {
                   2396:     av=avma; p1 = (GEN)x[i];
                   2397:     for (j=0; j<=i && j<=dz; j++)
                   2398:       p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j]));
                   2399:     tetpil=avma; rem[i]=lpile(av,tetpil, modii(p1,p));
                   2400:   }
                   2401:   rem -= 2;
                   2402:   if (lead) gunclone(lead);
                   2403:   if (!sx) normalizepol_i(rem, lrem);
                   2404:   if (pr == ONLY_REM) return gerepileupto(av0,rem);
                   2405:   *pr = rem; return z-2;
                   2406: }
                   2407:
                   2408: /* x and y in Z[Y][X]. Assume T irreducible mod p */
                   2409: GEN
                   2410: FpXQX_divres(GEN x, GEN y, GEN T, GEN p, GEN *pr)
                   2411: {
                   2412:   long vx,dx,dy,dz,i,j,av0,av,tetpil,sx,lrem;
                   2413:   GEN z,p1,rem,lead;
                   2414:
                   2415:   if (!p) return poldivres(x,y,pr);
                   2416:   if (!T) return FpX_divres(x,y,p,pr);
                   2417:   if (!signe(y)) err(talker,"division by zero in FpX_divres");
                   2418:   vx=varn(x); dy=degpol(y); dx=degpol(x);
                   2419:   if (dx < dy)
                   2420:   {
                   2421:     if (pr)
                   2422:     {
                   2423:       av0 = avma; x = FpXQX_red(x, T, p);
                   2424:       if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: gzero; }
                   2425:       if (pr == ONLY_REM) return x;
                   2426:       *pr = x;
                   2427:     }
                   2428:     return zeropol(vx);
                   2429:   }
                   2430:   lead = leading_term(y);
                   2431:   if (!dy) /* y is constant */
                   2432:   {
                   2433:     if (pr && pr != ONLY_DIVIDES)
                   2434:     {
                   2435:       if (pr == ONLY_REM) return zeropol(vx);
                   2436:       *pr = zeropol(vx);
                   2437:     }
                   2438:     if (gcmp1(lead)) return gcopy(x);
                   2439:     av0 = avma; x = gmul(x, FpXQ_inv(lead,T,p)); tetpil = avma;
                   2440:     return gerepile(av0,tetpil,FpXQX_red(x,T,p));
                   2441:   }
                   2442:   av0 = avma; dz = dx-dy;
                   2443: #if 0 /* FIXME: to be done */
                   2444:   if (OK_ULONG(p))
                   2445:   { /* assume ab != 0 mod p */
                   2446:     ulong pp = (ulong)p[2];
                   2447:     GEN a = u_Fp_FpX(x,1, pp);
                   2448:     GEN b = u_Fp_FpX(y,1, pp);
                   2449:     GEN zz= u_FpX_divrem(a,b,pp,1, pr);
                   2450:     if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)
                   2451:     {
                   2452:       rem = small_to_pol(*pr,vx);
                   2453:       free(*pr); *pr = rem;
                   2454:     }
                   2455:     z = small_to_pol(zz,vx);
                   2456:     free(zz); free(a); free(b); return z;
                   2457:   }
                   2458: #endif
                   2459:   lead = gcmp1(lead)? NULL: gclone(FpXQ_inv(lead,T,p));
                   2460:   avma = av0;
                   2461:   z=cgetg(dz+3,t_POL);
                   2462:   z[1]=evalsigne(1) | evallgef(dz+3) | evalvarn(vx);
                   2463:   x += 2; y += 2; z += 2;
                   2464:
                   2465:   p1 = (GEN)x[dx]; av = avma;
                   2466:   z[dz] = lead? lpileupto(av, FpX_res(gmul(p1,lead), T, p)): lcopy(p1);
                   2467:   for (i=dx-1; i>=dy; i--)
                   2468:   {
                   2469:     av=avma; p1=(GEN)x[i];
                   2470:     for (j=i-dy+1; j<=i && j<=dz; j++)
                   2471:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
                   2472:     if (lead) p1 = gmul(FpX_res(p1, T, p), lead);
                   2473:     tetpil=avma; z[i-dy] = lpile(av,tetpil,FpX_res(p1, T, p));
                   2474:   }
                   2475:   if (!pr) { if (lead) gunclone(lead); return z-2; }
                   2476:
                   2477:   rem = (GEN)avma; av = (long)new_chunk(dx+3);
                   2478:   for (sx=0; ; i--)
                   2479:   {
                   2480:     p1 = (GEN)x[i];
                   2481:     for (j=0; j<=i && j<=dz; j++)
                   2482:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
                   2483:     tetpil=avma; p1 = FpX_res(p1, T, p); if (signe(p1)) { sx = 1; break; }
                   2484:     if (!i) break;
                   2485:     avma=av;
                   2486:   }
                   2487:   if (pr == ONLY_DIVIDES)
                   2488:   {
                   2489:     if (lead) gunclone(lead);
                   2490:     if (sx) { avma=av0; return NULL; }
                   2491:     avma = (long)rem; return z-2;
                   2492:   }
                   2493:   lrem=i+3; rem -= lrem;
                   2494:   rem[0]=evaltyp(t_POL) | evallg(lrem);
                   2495:   rem[1]=evalsigne(1) | evalvarn(vx) | evallgef(lrem);
                   2496:   p1 = gerepile((long)rem,tetpil,p1);
                   2497:   rem += 2; rem[i]=(long)p1;
                   2498:   for (i--; i>=0; i--)
                   2499:   {
                   2500:     av=avma; p1 = (GEN)x[i];
                   2501:     for (j=0; j<=i && j<=dz; j++)
                   2502:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
                   2503:     tetpil=avma; rem[i]=lpile(av,tetpil, FpX_res(p1, T, p));
                   2504:   }
                   2505:   rem -= 2;
                   2506:   if (lead) gunclone(lead);
                   2507:   if (!sx) normalizepol_i(rem, lrem);
                   2508:   if (pr == ONLY_REM) return gerepileupto(av0,rem);
                   2509:   *pr = rem; return z-2;
                   2510: }
                   2511:
                   2512: static GEN
                   2513: FpX_gcd_long(GEN x, GEN y, GEN p)
                   2514: {
                   2515:   ulong pp = (ulong)p[2], av = avma;
                   2516:   GEN a,b;
                   2517:
                   2518:   (void)new_chunk((lgef(x) + lgef(y)) << 2); /* scratch space */
                   2519:   a = u_Fp_FpX(x,0, pp);
                   2520:   if (!signe(a)) { avma = av; return FpX_red(y,p); }
                   2521:   b = u_Fp_FpX(y,0, pp);
                   2522:   a = u_FpX_gcd_i(a,b, pp);
                   2523:   avma = av; return small_to_pol(a, varn(x));
                   2524: }
                   2525:
                   2526: /* x and y in Z[X], return lift(gcd(x mod p, y mod p)) */
                   2527: GEN
                   2528: FpX_gcd(GEN x, GEN y, GEN p)
                   2529: {
                   2530:   GEN a,b,c;
                   2531:   long av0,av;
                   2532:
                   2533:   if (OK_ULONG(p)) return FpX_gcd_long(x,y,p);
                   2534:   av0=avma;
                   2535:   a = FpX_red(x, p); av = avma;
                   2536:   b = FpX_red(y, p);
                   2537:   while (signe(b))
                   2538:   {
                   2539:     av = avma; c = FpX_res(a,b,p); a=b; b=c;
                   2540:   }
                   2541:   avma = av; return gerepileupto(av0, a);
                   2542: }
                   2543:
                   2544: GEN
                   2545: u_FpX_sub(GEN x, GEN y, ulong p)
                   2546: {
                   2547:   long i,lz,lx = lgef(x), ly = lgef(y);
                   2548:   GEN z;
                   2549:
                   2550:   if (ly <= lx)
                   2551:   {
                   2552:     lz = lx; z = cgetg(lz,t_VECSMALL);
                   2553:     for (i=2; i<ly; i++) z[i] = subssmod(x[i],y[i],p);
                   2554:     for (   ; i<lx; i++) z[i] = x[i];
                   2555:   }
                   2556:   else
                   2557:   {
                   2558:     lz = ly; z = cgetg(lz,t_VECSMALL);
                   2559:     for (i=2; i<lx; i++) z[i] = subssmod(x[i],y[i],p);
                   2560:     for (   ; i<ly; i++) z[i] = y[i]? p - y[i]: y[i];
                   2561:   }
                   2562:   z[1]=0; return u_normalizepol(z, lz);
                   2563: }
                   2564:
                   2565: /* list of u_FpX in gptr, return then as GEN */
                   2566: static void
                   2567: u_gerepilemany(long av, GEN* gptr[], long n, long v)
                   2568: {
                   2569:   GEN *l = (GEN*)gpmalloc(n*sizeof(GEN));
                   2570:   long i;
                   2571:
                   2572:   /* copy objects */
                   2573:   for (i=0; i<n; i++) l[i] = gclone(*(gptr[i]));
                   2574:   avma = av;
                   2575:   /* copy them back, kill clones */
                   2576:   for (--i; i>=0; i--)
                   2577:   {
                   2578:     *(gptr[i]) = small_to_pol(l[i],v);
                   2579:     gunclone(l[i]);
                   2580:   }
                   2581:   free(l);
                   2582: }
                   2583:
                   2584: static GEN
                   2585: u_FpX_extgcd(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv)
                   2586: {
                   2587:   GEN q,z,u,v, x = a, y = b;
                   2588:
                   2589:   u = u_zeropol(0);
                   2590:   v= u_scalarpol(1, 0); /* v = 1 */
                   2591:   while (signe(y))
                   2592:   {
                   2593:     q = u_FpX_divrem(x,y,p, 0,&z);
                   2594:     x = y; y = z; /* (x,y) = (y, x - q y) */
                   2595:     z = u_FpX_sub(u, u_FpX_mul(q,v, p), p);
                   2596:     u = v; v = z; /* (u,v) = (v, u - q v) */
                   2597:   }
                   2598:   z = u_FpX_sub(x, u_FpX_mul(b,u,p), p);
                   2599:   z = u_FpX_div(z,a,p);
                   2600:   *ptu = z;
                   2601:   *ptv = u; return x;
                   2602: }
                   2603:
                   2604: static GEN
                   2605: FpX_extgcd_long(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
                   2606: {
                   2607:   ulong pp = (ulong)p[2];
                   2608:   long av = avma;
                   2609:   GEN a, b, d;
                   2610:
                   2611:   a = u_Fp_FpX(x,0, pp);
                   2612:   b = u_Fp_FpX(y,0, pp);
                   2613:   d = u_FpX_extgcd(a,b, pp, ptu,ptv);
                   2614:   {
                   2615:     GEN *gptr[3]; gptr[0] = &d; gptr[1] = ptu; gptr[2] = ptv;
                   2616:     u_gerepilemany(av, gptr, 3, varn(x));
                   2617:   }
                   2618:   return d;
                   2619: }
                   2620:
                   2621: /* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st
                   2622:  * ux + vy = gcd (mod p) */
                   2623: GEN
                   2624: FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
                   2625: {
                   2626:   GEN a,b,q,r,u,v,d,d1,v1;
                   2627:   long ltop,lbot;
                   2628:
                   2629:   if (OK_ULONG(p)) return FpX_extgcd_long(x,y,p,ptu,ptv);
                   2630:   ltop=avma;
                   2631:   a = FpX_red(x, p);
                   2632:   b = FpX_red(y, p);
                   2633:   d = a; d1 = b; v = gzero; v1 = gun;
                   2634:   while (signe(d1))
                   2635:   {
                   2636:     q = FpX_divres(d,d1,p, &r);
                   2637:     v = gadd(v, gneg_i(gmul(q,v1)));
                   2638:     v = FpX_red(v,p);
                   2639:     u=v; v=v1; v1=u;
                   2640:     u=r; d=d1; d1=u;
                   2641:   }
                   2642:   u = gadd(d, gneg_i(gmul(b,v)));
                   2643:   u = FpX_red(u, p);
                   2644:   lbot = avma;
                   2645:   u = FpX_div(u,a,p);
                   2646:   d = gcopy(d);
                   2647:   v = gcopy(v);
                   2648:   {
                   2649:     GEN *gptr[3]; gptr[0] = &d; gptr[1] = &u; gptr[2] = &v;
                   2650:     gerepilemanysp(ltop,lbot,gptr,3);
                   2651:   }
                   2652:   *ptu = u; *ptv = v; return d;
                   2653: }
                   2654:
                   2655: /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
                   2656:  * ux + vy = gcd (mod T,p) */
                   2657: GEN
                   2658: FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)
                   2659: {
                   2660:   GEN a,b,q,r,u,v,d,d1,v1;
                   2661:   long ltop,lbot;
                   2662:
                   2663: #if 0 /* FIXME To be done...*/
                   2664:   if (OK_ULONG(p)) return FpXQX_extgcd_long(x,y,T,p,ptu,ptv);
                   2665: #endif
                   2666:   if (!T) return FpX_extgcd(x,y,p,ptu,ptv);
                   2667:   ltop=avma;
                   2668:   a = FpXQX_red(x, T, p);
                   2669:   b = FpXQX_red(y, T, p);
                   2670:   d = a; d1 = b; v = gzero; v1 = gun;
                   2671:   while (signe(d1))
                   2672:   {
                   2673:     q = FpXQX_divres(d,d1,T,p, &r);
                   2674:     v = gadd(v, gneg_i(gmul(q,v1)));
                   2675:     v = FpXQX_red(v,T,p);
                   2676:     u=v; v=v1; v1=u;
                   2677:     u=r; d=d1; d1=u;
                   2678:   }
                   2679:   u = gadd(d, gneg_i(gmul(b,v)));
                   2680:   u = FpXQX_red(u,T, p);
                   2681:   lbot = avma;
                   2682:   u = FpXQX_divres(u,a,T,p,NULL);
                   2683:   d = gcopy(d);
                   2684:   v = gcopy(v);
                   2685:   {
                   2686:     GEN *gptr[3]; gptr[0] = &d; gptr[1] = &u; gptr[2] = &v;
                   2687:     gerepilemanysp(ltop,lbot,gptr,3);
                   2688:   }
                   2689:   *ptu = u; *ptv = v; return d;
                   2690: }
                   2691:
                   2692: extern GEN caractducos(GEN p, GEN x, int v);
                   2693:
                   2694: GEN
                   2695: FpXQ_charpoly(GEN x, GEN T, GEN p)
                   2696: {
                   2697:   ulong ltop=avma;
                   2698:   GEN R=lift(caractducos(FpX(T,p),FpX(x,p),varn(T)));
                   2699:   return gerepileupto(ltop,R);
                   2700: }
                   2701:
                   2702: GEN
                   2703: FpXQ_minpoly(GEN x, GEN T, GEN p)
                   2704: {
                   2705:   ulong ltop=avma;
                   2706:   GEN R=FpXQ_charpoly(x, T, p);
                   2707:   GEN G=FpX_gcd(R,derivpol(R),p);
                   2708:   G=FpX_normalize(G,p);
                   2709:   G=FpX_div(R,G,p);
                   2710:   return gerepileupto(ltop,G);
                   2711: }
                   2712:
                   2713: /* return z = a mod q, b mod p (p,q) = 1. qinv = 1/q mod p */
                   2714: static GEN
                   2715: u_chrem_coprime(GEN a, ulong b, GEN q, ulong p, ulong qinv, GEN pq)
                   2716: {
                   2717:   ulong av = avma, d, amod = umodiu(a,p);
                   2718:   GEN ax;
                   2719:
                   2720:   if (b == amod) return NULL;
                   2721:   d = (b > amod)? b - amod: p - (amod - b); /* (b - a) mod p */
                   2722:   (void)new_chunk(lgefint(pq)<<1); /* HACK */
                   2723:   ax = mului(mulssmod(d,qinv,p), q); /* d mod p, 0 mod q */
                   2724:   avma = av; return addii(a, ax); /* in ]-q, pq[ assuming a in -]-q,q[ */
                   2725: }
                   2726:
                   2727: /* centerlift(u mod p) */
                   2728: GEN
                   2729: u_center(ulong u, ulong p, ulong ps2)
                   2730: {
                   2731:   return stoi((long) (u > ps2)? u - p: u);
                   2732: }
                   2733:
                   2734: GEN
                   2735: ZX_init_CRT(GEN Hp, ulong p, long v)
                   2736: {
                   2737:   long i, l = lgef(Hp), lim = (long)(p>>1);
                   2738:   GEN H = cgetg(l, t_POL);
                   2739:   H[1] = evalsigne(1)|evallgef(l)|evalvarn(v);
                   2740:   for (i=2; i<l; i++)
                   2741:     H[i] = (long)u_center(Hp[i], p, lim);
                   2742:   return H;
                   2743: }
                   2744:
                   2745: /* assume lg(Hp) > 1 */
                   2746: GEN
                   2747: ZM_init_CRT(GEN Hp, ulong p)
                   2748: {
                   2749:   long i,j, m = lg(Hp[1]), l = lg(Hp), lim = (long)(p>>1);
                   2750:   GEN c,cp,H = cgetg(l, t_MAT);
                   2751:   for (j=1; j<l; j++)
                   2752:   {
                   2753:     cp = (GEN)Hp[j];
                   2754:     c = cgetg(m, t_COL);
                   2755:     H[j] = (long)c;
                   2756:     for (i=1; i<l; i++) c[i] = (long)u_center(cp[i],p, lim);
                   2757:   }
                   2758:   return H;
                   2759: }
                   2760:
                   2761: int
                   2762: Z_incremental_CRT(GEN *H, ulong Hp, GEN q, GEN qp, ulong p)
                   2763: {
                   2764:   GEN h, lim = shifti(qp,-1);
                   2765:   ulong qinv = u_invmod(umodiu(q,p), p);
                   2766:   int stable = 1;
                   2767:   h = u_chrem_coprime(*H,Hp,q,p,qinv,qp);
                   2768:   if (h)
                   2769:   {
                   2770:     if (cmpii(h,lim) > 0) h = subii(h,qp);
                   2771:     *H = h; stable = 0;
                   2772:   }
                   2773:   return stable;
                   2774: }
                   2775:
                   2776: int
                   2777: ZX_incremental_CRT(GEN H, GEN Hp, GEN q, GEN qp, ulong p)
                   2778: {
                   2779:   GEN h, lim = shifti(qp,-1);
                   2780:   ulong qinv = u_invmod(umodiu(q,p), p);
                   2781:   long i, l = lgef(H), lp = lgef(Hp);
                   2782:   int stable = 1;
                   2783:   for (i=2; i<lp; i++)
                   2784:   {
                   2785:     h = u_chrem_coprime((GEN)H[i],Hp[i],q,p,qinv,qp);
                   2786:     if (h)
                   2787:     {
                   2788:       if (cmpii(h,lim) > 0) h = subii(h,qp);
                   2789:       H[i] = (long)h; stable = 0;
                   2790:     }
                   2791:   }
                   2792:   for (   ; i<l; i++)
                   2793:   {
                   2794:     h = u_chrem_coprime((GEN)H[i],   0,q,p,qinv,qp);
                   2795:     if (h)
                   2796:     {
                   2797:       if (cmpii(h,lim) > 0) h = subii(h,qp);
                   2798:       H[i] = (long)h; stable = 0;
                   2799:     }
                   2800:   }
                   2801:   return stable;
                   2802: }
                   2803:
                   2804: int
                   2805: ZM_incremental_CRT(GEN H, GEN Hp, GEN q, GEN qp, ulong p)
                   2806: {
                   2807:   GEN h, lim = shifti(qp,-1);
                   2808:   ulong qinv = u_invmod(umodiu(q,p), p);
                   2809:   long i,j, l = lg(H), m = lg(H[1]);
                   2810:   int stable = 1;
                   2811:   for (j=1; j<l; j++)
                   2812:     for (i=1; i<m; i++)
                   2813:     {
                   2814:       h = u_chrem_coprime(gcoeff(H,i,j), coeff(Hp,i,j),q,p,qinv,qp);
                   2815:       if (h)
                   2816:       {
                   2817:         if (cmpii(h,lim) > 0) h = subii(h,qp);
                   2818:         coeff(H,i,j) = (long)h; stable = 0;
                   2819:       }
                   2820:     }
                   2821:   return stable;
                   2822: }
                   2823:
                   2824: /* returns a polynomial in variable v, whose coeffs correspond to the digits
                   2825:  * of m (in base p) */
                   2826: GEN
                   2827: stopoly(long m, long p, long v)
                   2828: {
                   2829:   GEN y = cgetg(BITS_IN_LONG + 2, t_POL);
                   2830:   long l=2;
                   2831:
                   2832:   do { y[l++] = lstoi(m%p); m=m/p; } while (m);
                   2833:   y[1] = evalsigne(1)|evallgef(l)|evalvarn(v);
                   2834:   return y;
                   2835: }
                   2836:
                   2837: GEN
                   2838: stopoly_gen(GEN m, GEN p, long v)
                   2839: {
                   2840:   GEN y = cgetg(bit_accuracy(lgefint(m))+2, t_POL);
                   2841:   long l=2;
                   2842:
                   2843:   do { y[l++] = lmodii(m,p); m=divii(m,p); } while (signe(m));
                   2844:   y[1] = evalsigne(1)|evallgef(l)|evalvarn(v);
                   2845:   return y;
                   2846: }
                   2847:
                   2848: /* modular power */
                   2849: ulong
                   2850: powuumod(ulong x, ulong n0, ulong p)
                   2851: {
                   2852:   ulong y, z, n;
                   2853:   if (n0 <= 2)
                   2854:   { /* frequent special cases */
                   2855:     if (n0 == 2) return mulssmod(x,x,p);
                   2856:     if (n0 == 1) return x;
                   2857:     if (n0 == 0) return 1;
                   2858:   }
                   2859:   y = 1; z = x; n = n0;
                   2860:   for(;;)
                   2861:   {
                   2862:     if (n&1) y = mulssmod(y,z,p);
                   2863:     n>>=1; if (!n) return y;
                   2864:     z = mulssmod(z,z,p);
                   2865:   }
                   2866: }
                   2867:
                   2868: /* separate from u_FpX_divrem for maximal speed. Implicitly malloc = 0  */
                   2869: GEN
                   2870: u_FpX_rem(GEN x, GEN y, ulong p)
                   2871: {
                   2872:   GEN z, c;
                   2873:   long dx,dy,dz,i,j;
                   2874:   ulong p1,inv;
                   2875:
                   2876:   dy = degpol(y); if (!dy) return u_zeropol(0);
                   2877:   dx = degpol(x);
                   2878:   dz = dx-dy; if (dz < 0) return u_copy(x, 0);
                   2879:   x += 2;
                   2880:   y += 2;
                   2881:   z = u_allocpol(dz, 1) + 2;
                   2882:   inv = y[dy];
                   2883:   if (inv != 1UL) inv = u_invmod(inv,p);
                   2884:
                   2885:   c = u_allocpol(dy,0) + 2;
                   2886:   if (u_OK_ULONG(p))
                   2887:   {
                   2888:     z[dz] = (inv*x[dx]) % p;
                   2889:     for (i=dx-1; i>=dy; --i)
                   2890:     {
                   2891:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   2892:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   2893:       {
                   2894:         p1 += z[j]*y[i-j];
                   2895:         if (p1 & HIGHBIT) p1 = p1 % p;
                   2896:       }
                   2897:       p1 %= p;
                   2898:       z[i-dy] = p1? ((p - p1)*inv) % p: 0;
                   2899:     }
                   2900:     for (i=0; i<dy; i++)
                   2901:     {
                   2902:       p1 = z[0]*y[i];
                   2903:       for (j=1; j<=i && j<=dz; j++)
                   2904:       {
                   2905:         p1 += z[j]*y[i-j];
                   2906:         if (p1 & HIGHBIT) p1 = p1 % p;
                   2907:       }
                   2908:       c[i] = subssmod(x[i], p1%p, p);
                   2909:     }
                   2910:   }
                   2911:   else
                   2912:   {
                   2913:     z[dz] = mulssmod(inv, x[dx], p);
                   2914:     for (i=dx-1; i>=dy; --i)
                   2915:     {
                   2916:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   2917:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   2918:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   2919:       z[i-dy] = p1? mulssmod(p - p1, inv, p): 0;
                   2920:     }
                   2921:     for (i=0; i<dy; i++)
                   2922:     {
                   2923:       p1 = mulssmod(z[0],y[i],p);
                   2924:       for (j=1; j<=i && j<=dz; j++)
                   2925:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   2926:       c[i] = subssmod(x[i], p1, p);
                   2927:     }
                   2928:   }
                   2929:   i = dy-1; while (i>=0 && !c[i]) i--;
                   2930:   free(z-2); return u_normalizepol(c-2, i+3);
                   2931: }
                   2932:
                   2933: ulong
                   2934: u_FpX_resultant(GEN a, GEN b, ulong p)
                   2935: {
                   2936:   long da,db,dc,cnt;
                   2937:   ulong lb,av, res = 1UL;
                   2938:   GEN c;
                   2939:
                   2940:   if (!signe(a) || !signe(b)) return 0;
                   2941:   da = degpol(a);
                   2942:   db = degpol(b);
                   2943:   if (db > da)
                   2944:   {
                   2945:     swapspec(a,b, da,db);
                   2946:     if (da & db & 1) res = p-res;
                   2947:   }
                   2948:   if (!da) return 1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
                   2949:   cnt = 0; av = avma;
                   2950:   while (db)
                   2951:   {
                   2952:     lb = b[db+2];
                   2953:     c = u_FpX_rem(a,b, p);
                   2954:     a = b; b = c; dc = degpol(c);
                   2955:     if (dc < 0) { avma = av; return 0; }
                   2956:
                   2957:     if (da & db & 1) res = p - res;
                   2958:     if (lb != 1) res = mulssmod(res, powuumod(lb, da - dc, p), p);
                   2959:     if (++cnt == 4) { cnt = 0; avma = av; }
                   2960:     da = db; /* = degpol(a) */
                   2961:     db = dc; /* = degpol(b) */
                   2962:   }
                   2963:   avma = av; return mulssmod(res, powuumod(b[2], da, p), p);
                   2964: }
                   2965:
                   2966: /* If resultant is 0, *ptU and *ptU are not set */
                   2967: ulong
                   2968: u_FpX_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV)
                   2969: {
                   2970:   GEN z,q,u,v, x = a, y = b;
                   2971:   ulong lb, av = avma, res = 1UL;
                   2972:   long dx,dy,dz;
                   2973:
                   2974:   if (!signe(x) || !signe(y)) return 0;
                   2975:   dx = degpol(x);
                   2976:   dy = degpol(y);
                   2977:   if (dy > dx)
                   2978:   {
                   2979:     swap(x,y); lswap(dx,dy); pswap(ptU, ptV);
                   2980:     a = x; b = y;
                   2981:     if (dx & dy & 1) res = p-res;
                   2982:   }
                   2983:   u = u_zeropol(0);
                   2984:   v = u_scalarpol(1, 0); /* v = 1 */
                   2985:   while (dy)
                   2986:   { /* b u = x (a), b v = y (a) */
                   2987:     lb = y[dy+2];
                   2988:     q = u_FpX_divrem(x,y, p, 0, &z);
                   2989:     x = y; y = z; /* (x,y) = (y, x - q y) */
                   2990:     dz = degpol(z); if (dz < 0) { avma = av; return 0; }
                   2991:     z = u_FpX_sub(u, u_FpX_mul(q,v, p), p);
                   2992:     u = v; v = z; /* (u,v) = (v, u - q v) */
                   2993:
                   2994:     if (dx & dy & 1) res = p - res;
                   2995:     if (lb != 1) res = mulssmod(res, powuumod(lb, dx-dz, p), p);
                   2996:     dx = dy; /* = degpol(x) */
                   2997:     dy = dz; /* = degpol(y) */
                   2998:   }
                   2999:   res = mulssmod(res, powuumod(y[2], dx, p), p);
                   3000:   lb = mulssmod(res, u_invmod(y[2],p), p);
                   3001:   v = gerepileupto(av, u_FpX_Fp_mul(v, lb, p, 0));
                   3002:   av = avma;
                   3003:   u = u_FpX_sub(u_scalarpol(res,0), u_FpX_mul(b,v,p), p);
                   3004:   u = gerepileupto(av, u_FpX_div(u,a,p)); /* = (res - b v) / a */
                   3005:   *ptU = u;
                   3006:   *ptV = v; return res;
                   3007: }
                   3008:
                   3009: /* assuming the PRS finishes on a degree 1 polynomial C0 + C1X, with "generic"
                   3010:  * degree sequence as given by dglist, set *Ci and return resultant(a,b) */
                   3011: ulong
                   3012: u_FpX_resultant_all(GEN a, GEN b, long *C0, long *C1, GEN dglist, ulong p)
                   3013: {
                   3014:   long da,db,dc,cnt,ind;
                   3015:   ulong lb,av,cx = 1, res = 1UL;
                   3016:   GEN c;
                   3017:
                   3018:   if (C0) { *C0 = 1; *C1 = 0; }
                   3019:   if (!signe(a) || !signe(b)) return 0;
                   3020:   da = degpol(a);
                   3021:   db = degpol(b);
                   3022:   if (db > da)
                   3023:   {
                   3024:     swapspec(a,b, da,db);
                   3025:     if (da & db & 1) res = p-res;
                   3026:   }
                   3027:   /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
                   3028:   if (!da) return 1;
                   3029:   cnt = ind = 0; av = avma;
                   3030:   while (db)
                   3031:   {
                   3032:     lb = b[db+2];
                   3033:     c = u_FpX_rem(a,b, p);
                   3034:     a = b; b = c; dc = degpol(c);
                   3035:     if (dc < 0) { avma = av; return 0; }
                   3036:
                   3037:     ind++;
                   3038:     if (C0)
                   3039:     { /* check that Euclidean remainder sequence doesn't degenerate */
                   3040:       if (dc != dglist[ind]) { avma = av; return 0; }
                   3041:       /* update resultant */
                   3042:       if (da & db & 1) res = p-res;
                   3043:       if (lb != 1)
                   3044:       {
                   3045:         ulong t = powuumod(lb, da - dc, p);
                   3046:         res = mulssmod(res, t, p);
                   3047:         if (dc) cx = mulssmod(cx, t, p);
                   3048:       }
                   3049:     }
                   3050:     else
                   3051:     {
                   3052:       if (dc > dglist[ind]) dglist[ind] = dc;
                   3053:     }
                   3054:     if (++cnt == 4) { cnt = 0; avma = av; }
                   3055:     da = db; /* = degpol(a) */
                   3056:     db = dc; /* = degpol(b) */
                   3057:   }
                   3058:   if (!C0)
                   3059:   {
                   3060:     if (ind+1 > lg(dglist)) setlg(dglist,ind+1);
                   3061:     return 0;
                   3062:   }
                   3063:
                   3064:   if (da == 1) /* last non-constant polynomial has degree 1 */
                   3065:   {
                   3066:     *C0 = mulssmod(cx, a[2], p);
                   3067:     *C1 = mulssmod(cx, a[3], p);
                   3068:     lb = b[2];
                   3069:   } else lb = powuumod(b[2], da, p);
                   3070:   avma = av; return mulssmod(res, lb, p);
                   3071: }
                   3072:
                   3073: static ulong global_pp;
                   3074: static GEN
                   3075: _u_FpX_mul(GEN a, GEN b)
                   3076: {
                   3077:   return u_FpX_mul(a,b, global_pp);
                   3078: }
                   3079:
                   3080: /* compute prod (x - a[i]) */
                   3081: GEN
                   3082: u_FpV_roots_to_pol(GEN a, ulong p)
                   3083: {
                   3084:   long i,k,lx = lg(a);
                   3085:   GEN p1,p2;
                   3086:   if (lx == 1) return polun[0];
                   3087:   p1 = cgetg(lx, t_VEC); global_pp = p;
                   3088:   for (k=1,i=1; i<lx-1; i+=2)
                   3089:   {
                   3090:     p2 = cgetg(5,t_VECSMALL); p1[k++] = (long)p2;
                   3091:     p2[2] = mulssmod(a[i], a[i+1], p);
                   3092:     p2[3] = (p<<1) - (a[i] + a[i+1]);
                   3093:     p2[4] = 1; p2[1] = evallgef(5);
                   3094:   }
                   3095:   if (i < lx)
                   3096:   {
                   3097:     p2 = cgetg(4,t_POL); p1[k++] = (long)p2;
                   3098:     p2[1] = evallgef(4);
                   3099:     p2[2] = p - a[i];
                   3100:     p2[3] = 1;
                   3101:   }
                   3102:   setlg(p1, k); return divide_conquer_prod(p1, _u_FpX_mul);
                   3103: }
                   3104:
                   3105:
                   3106: /* u P(X) + v P(-X) */
                   3107: static GEN
                   3108: pol_comp(GEN P, GEN u, GEN v)
                   3109: {
                   3110:   long i, l = lgef(P);
                   3111:   GEN y = cgetg(l, t_POL);
                   3112:   for (i=2; i<l; i++)
                   3113:   {
                   3114:     GEN t = (GEN)P[i];
                   3115:     y[i] = gcmp0(t)? zero:
                   3116:                      (i&1)? lmul(t, gsub(u,v)) /*  odd degree */
                   3117:                           : lmul(t, gadd(u,v));/* even degree */
                   3118:   }
                   3119:   y[1] = P[1]; return normalizepol_i(y,l);
                   3120: }
                   3121:
                   3122: static GEN
                   3123: u_pol_comp(GEN P, ulong u, ulong v, ulong p)
                   3124: {
                   3125:   long i, l = lgef(P);
                   3126:   GEN y = u_allocpol(l-3, 0);
                   3127:   for (i=2; i<l; i++)
                   3128:   {
                   3129:     ulong t = P[i];
                   3130:     y[i] = (t == 0)? 0:
                   3131:                      (i&1)? mulssmod(t, u + (p - v), p)
                   3132:                           : mulssmod(t, u + v, p);
                   3133:   }
                   3134:   return u_normalizepol(y,l);
                   3135: }
                   3136:
                   3137: GEN roots_to_pol(GEN a, long v);
                   3138:
                   3139: GEN
                   3140: polint_triv(GEN xa, GEN ya)
                   3141: {
                   3142:   GEN P = NULL, Q = roots_to_pol(xa,0);
                   3143:   long i, n = lg(xa), av = avma, lim = stack_lim(av,2);
                   3144:   for (i=1; i<n; i++)
                   3145:   {
                   3146:     GEN T,dP;
                   3147:     if (gcmp0((GEN)ya[i])) continue;
                   3148:     T = gdeuc(Q, gsub(polx[0], (GEN)xa[i]));
                   3149:     if (i < n-1 && absi_equal((GEN)xa[i], (GEN)xa[i+1]))
                   3150:     { /* x_i = -x_{i+1} */
                   3151:       T = gdiv(T, poleval(T, (GEN)xa[i]));
                   3152:       dP = pol_comp(T, (GEN)ya[i], (GEN)ya[i+1]);
                   3153:       i++;
                   3154:     }
                   3155:     else
                   3156:     {
                   3157:       dP = gmul((GEN)ya[i], T);
                   3158:       dP = gdiv(dP, poleval(T,(GEN)xa[i]));
                   3159:     }
                   3160:     P = P? gadd(P, dP): dP;
                   3161:     if (low_stack(lim,stack_lim(av,2)))
                   3162:     {
                   3163:       if (DEBUGMEM>1) err(warnmem,"polint_triv2 (i = %ld)",i);
                   3164:       P = gerepileupto(av, P);
                   3165:     }
                   3166:   }
                   3167:   return P? P: zeropol(0);
                   3168: }
                   3169:
                   3170: ulong
                   3171: u_FpX_eval(GEN x, ulong y, ulong p)
                   3172: {
                   3173:   ulong p1,r;
                   3174:   long i,j;
                   3175:   i=lgef(x)-1;
                   3176:   if (i<=2)
                   3177:     return (i==2)? x[2]: 0;
                   3178:   p1 = x[i];
                   3179:   /* specific attention to sparse polynomials (see poleval)*/
                   3180:   if (u_OK_ULONG(p))
                   3181:   {
                   3182:     for (i--; i>=2; i=j-1)
                   3183:     {
                   3184:       for (j=i; !x[j]; j--)
                   3185:         if (j==2)
                   3186:         {
                   3187:           if (i != j) y = powuumod(y, i-j+1, p);
                   3188:           return (p1 * y) % p;
                   3189:         }
                   3190:       r = (i==j)? y: powuumod(y, i-j+1, p);
                   3191:       p1 = ((p1*r) + x[j]) % p;
                   3192:     }
                   3193:   }
                   3194:   else
                   3195:   {
                   3196:     for (i--; i>=2; i=j-1)
                   3197:     {
                   3198:       for (j=i; !x[j]; j--)
                   3199:         if (j==2)
                   3200:         {
                   3201:           if (i != j) y = powuumod(y, i-j+1, p);
                   3202:           return mulssmod(p1, y, p);
                   3203:         }
                   3204:       r = (i==j)? y: powuumod(y, i-j+1, p);
                   3205:       p1 = addssmod(x[j], mulssmod(p1,r,p), p);
                   3206:     }
                   3207:   }
                   3208:   return p1;
                   3209: }
                   3210:
                   3211: static GEN
                   3212: u_FpX_div_by_X_x(GEN a, ulong x, ulong p)
                   3213: {
                   3214:   long l = lgef(a), i;
                   3215:   GEN z = u_allocpol(l-4, 0), a0, z0;
                   3216:   a0 = a + l-1;
                   3217:   z0 = z + l-2; *z0 = *a0--;
                   3218:   if (u_OK_ULONG(p))
                   3219:   {
                   3220:     for (i=l-3; i>1; i--) /* z[i] = (a[i+1] + x*z[i+1]) % p */
                   3221:     {
                   3222:       ulong t = (*a0-- + x *  *z0--) % p;
                   3223:       *z0 = t;
                   3224:     }
                   3225:   }
                   3226:   else
                   3227:   {
                   3228:     for (i=l-3; i>1; i--)
                   3229:     {
                   3230:       ulong t = addssmod(*a0--, mulssmod(x, *z0--, p), p);
                   3231:       *z0 = t;
                   3232:     }
                   3233:   }
                   3234:   return z;
                   3235: }
                   3236:
                   3237: /* xa, ya = t_VECSMALL */
                   3238: GEN
                   3239: u_FpV_polint(GEN xa, GEN ya, ulong p)
                   3240: {
                   3241:   GEN T,dP, P = NULL, Q = u_FpV_roots_to_pol(xa, p);
                   3242:   long i, n = lg(xa);
                   3243:   ulong av, inv;
                   3244:   av = avma; (void)new_chunk(n+3); /* storage space for P */
                   3245:   for (i=1; i<n; i++)
                   3246:   {
                   3247:     if (!ya[i]) continue;
                   3248:     T = u_FpX_div_by_X_x(Q, xa[i], p);
                   3249:     inv = u_invmod(u_FpX_eval(T,xa[i], p), p);
                   3250:     if (i < n-1 && (ulong)(xa[i] + xa[i+1]) == p)
                   3251:     {
                   3252:       dP = u_pol_comp(T, mulssmod(ya[i],inv,p), mulssmod(ya[i+1],inv,p), p);
                   3253:       i++; /* x_i = -x_{i+1} */
                   3254:     }
                   3255:     else
                   3256:       dP = u_FpX_Fp_mul(T, mulssmod(ya[i],inv,p), p, 0);
                   3257:     if (P) avma = av;
                   3258:     P = P? u_FpX_add(P, dP, p): dP;
                   3259:   }
                   3260:   return P? P: u_zeropol(0);
                   3261: }
                   3262:
                   3263: static void
                   3264: u_FpV_polint_all(GEN xa, GEN ya, GEN C0, GEN C1, ulong p)
                   3265: {
                   3266:   GEN T,Q = u_FpV_roots_to_pol(xa, p);
                   3267:   GEN dP  = NULL,  P = NULL;
                   3268:   GEN dP0 = NULL, P0= NULL;
                   3269:   GEN dP1 = NULL, P1= NULL;
                   3270:   long i, n = lg(xa);
                   3271:   ulong inv;
                   3272:   for (i=1; i<n; i++)
                   3273:   {
                   3274:     T = u_FpX_div_by_X_x(Q, xa[i], p);
                   3275:     inv = u_invmod(u_FpX_eval(T,xa[i], p), p);
                   3276:
                   3277: #if 0
                   3278:     if (i < n-1 && (ulong)(xa[i] + xa[i+1]) == p)
                   3279:     {
                   3280:       if (ya[i])
                   3281:         dP = u_pol_comp(T, mulssmod(ya[i],inv,p), mulssmod(ya[i+1],inv,p), p);
                   3282:       if (C0[i])
                   3283:         dP0= u_pol_comp(T, mulssmod(C0[i],inv,p), mulssmod(C0[i+1],inv,p), p);
                   3284:       if (C1[i])
                   3285:         dP1= u_pol_comp(T, mulssmod(C1[i],inv,p), mulssmod(C1[i+1],inv,p), p);
                   3286:       i++; /* x_i = -x_{i+1} */
                   3287:     }
                   3288:     else
                   3289: #endif
                   3290:     {
                   3291:       if (ya[i])
                   3292:       {
                   3293:         dP = u_FpX_Fp_mul(T, mulssmod(ya[i],inv,p), p, 0);
                   3294:         P = P ? u_FpX_add(P , dP , p): dP;
                   3295:       }
                   3296:       if (C0[i])
                   3297:       {
                   3298:         dP0= u_FpX_Fp_mul(T, mulssmod(C0[i],inv,p), p, 0);
                   3299:         P0= P0? u_FpX_add(P0, dP0, p): dP0;
                   3300:       }
                   3301:       if (C1[i])
                   3302:       {
                   3303:         dP1= u_FpX_Fp_mul(T, mulssmod(C1[i],inv,p), p, 0);
                   3304:         P1= P1? u_FpX_add(P1, dP1, p): dP1;
                   3305:       }
                   3306:     }
                   3307:   }
                   3308:   ya[1] = (long) (P ? P : u_zeropol(0));
                   3309:   C0[1] = (long) (P0? P0: u_zeropol(0));
                   3310:   C1[1] = (long) (P1? P1: u_zeropol(0));
                   3311: }
                   3312:
                   3313: /* b a vector of polynomials representing B in Fp[X][Y], evaluate at X = x,
                   3314:  * Return 0 in case of degree drop. */
                   3315: static GEN
                   3316: vec_u_FpX_eval(GEN b, ulong x, ulong p)
                   3317: {
                   3318:   GEN z;
                   3319:   long i, lb = lgef(b);
                   3320:   ulong leadz = u_FpX_eval((GEN)b[lb-1], x, p);
                   3321:   if (!leadz) return u_zeropol(0);
                   3322:
                   3323:   z = u_allocpol(lb-3, 0);
                   3324:   for (i=2; i<lb-1; i++)
                   3325:     z[i] = u_FpX_eval((GEN)b[i], x, p);
                   3326:   z[i] = leadz; return z;
                   3327: }
                   3328:
                   3329: /* as above, but don't care about degree drop */
                   3330: static GEN
                   3331: vec_u_FpX_eval_gen(GEN b, ulong x, ulong p, int *drop)
                   3332: {
                   3333:   GEN z;
                   3334:   long i, lb = lgef(b);
                   3335:   z = u_allocpol(lb-3, 0);
                   3336:   for (i=2; i<lb; i++)
                   3337:     z[i] = u_FpX_eval((GEN)b[i], x, p);
                   3338:   z = u_normalizepol(z, lb);
                   3339:   *drop = lb - lgef(z);
                   3340:   return z;
                   3341: }
                   3342:
                   3343: /* Interpolate at roots of 1 and use Hadamard bound for univariate resultant:
                   3344:  *   bound = N_2(A)^degpol B N_2(B)^degpol(A),  where  N_2(A) = sqrt(sum (N_1(Ai))^2)
                   3345:  * Return B such that bound < 2^B */
                   3346: ulong
                   3347: ZY_ZXY_ResBound(GEN A, GEN B)
                   3348: {
                   3349:   ulong av = avma;
                   3350:   GEN a = gzero, b = gzero, run = realun(DEFAULTPREC);
                   3351:   long i , lA = lgef(A), lB = lgef(B);
                   3352:   for (i=2; i<lA; i++) a = addii(a, sqri((GEN)A[i]));
                   3353:   for (i=2; i<lB; i++)
                   3354:   {
                   3355:     GEN t = (GEN)B[i];
                   3356:     if (typ(t) == t_POL) t = gnorml1(t, 0);
                   3357:     b = addii(b, sqri(t));
                   3358:   }
                   3359:   b = gmul(gpowgs(mulir(a,run), degpol(B)), gpowgs(mulir(b,run), degpol(A)));
                   3360:   avma = av; return 1 + (gexpo(b)>>1);
                   3361: }
                   3362:
                   3363: /* 0, 1, -1, 2, -2, ... */
                   3364: #define next_lambda(a) (a>0 ? -a : 1-a)
                   3365:
                   3366: /* If lambda = NULL, assume A in Z[Y], B in Q[Y][X], return Res_Y(A,B)
                   3367:  * Otherwise, find a small lambda (start from *lambda, use the sequence above)
                   3368:  * such that R(X) = Res_Y(A, B(X + lambda Y)) is squarefree, reset *lambda to
                   3369:  * the chosen value and return R
                   3370:  *
                   3371:  * If LERS is non-NULL, set it to the last non-constant polynomial in the PRS */
                   3372: GEN
                   3373: ZY_ZXY_resultant_all(GEN A, GEN B0, long *lambda, GEN *LERS)
                   3374: {
                   3375:   int checksqfree = lambda? 1: 0, delete = 0, first = 1, stable;
                   3376:   ulong av = avma, av2, lim, bound;
                   3377:   long i,n, lb, dres = degpol(A)*degpol(B0), nmax = (dres+1)>>1;
                   3378:   long vX = varn(B0), vY = varn(A); /* assume vX < vY */
                   3379:   GEN x,y,dglist,cB,B,q,a,b,ev,H,H0,H1,Hp,H0p,H1p,C0,C1;
                   3380:   byteptr d = diffptr + 3000;
                   3381:   ulong p = 27449; /* p = prime(3000) */
                   3382:
                   3383:   dglist = Hp = H0p = H1p = C0 = C1 = NULL; /* gcc -Wall */
                   3384:   if (LERS)
                   3385:   {
                   3386:     if (!lambda) err(talker,"ZY_ZXY_resultant_all: LERS needs lambda");
                   3387:     C0 = cgetg(dres+2, t_VECSMALL);
                   3388:     C1 = cgetg(dres+2, t_VECSMALL);
                   3389:     dglist = cgetg(dres+1, t_VECSMALL);
                   3390:   }
                   3391:   x = cgetg(dres+2, t_VECSMALL);
                   3392:   y = cgetg(dres+2, t_VECSMALL);
                   3393:   if (vY == MAXVARN)
                   3394:   {
                   3395:     vY = fetch_var(); delete = 1;
                   3396:     B0 = gsubst(B0, MAXVARN, polx[vY]);
                   3397:     A = dummycopy(A); setvarn(A, vY);
                   3398:   }
                   3399:   cB = content(B0);
                   3400:   if (typ(cB) == t_POL) cB = content(cB);
                   3401:   if (gcmp1(cB)) cB = NULL; else B0 = gdiv(B0, cB);
                   3402:
                   3403:   if (lambda)
                   3404:     B = poleval(B0, gadd(polx[MAXVARN], gmulsg(*lambda, polx[vY])));
                   3405:   else
                   3406:     B = poleval(B0, polx[MAXVARN]);
                   3407:   av2 = avma; lim = stack_lim(av,2);
                   3408:
                   3409: INIT:
                   3410:   if (first) first = 0;
                   3411:   else
                   3412:   { /* lambda != NULL */
                   3413:     avma = av2; *lambda = next_lambda(*lambda);
                   3414:     if (DEBUGLEVEL>4) fprintferr("Starting with lambda = %ld\n",*lambda);
                   3415:     B = poleval(B0, gadd(polx[MAXVARN], gmulsg(*lambda, polx[vY])));
                   3416:     av2 = avma;
                   3417:   }
                   3418:
                   3419:   if (degpol(A) <= 3)
                   3420:   { /* sub-resultant faster for small degrees */
                   3421:     if (LERS)
                   3422:     {
                   3423:       H = subresall(A,B,&q);
                   3424:       if (typ(q) != t_POL || degpol(q)!=1 || !ZX_is_squarefree(H)) goto INIT;
                   3425:       H0 = (GEN)q[2]; if (typ(H0) == t_POL) setvarn(H0,vX);
                   3426:       H1 = (GEN)q[3]; if (typ(H1) == t_POL) setvarn(H1,vX);
                   3427:     }
                   3428:     else
                   3429:     {
                   3430:       H = subres(A,B);
                   3431:       if (checksqfree && !ZX_is_squarefree(H)) goto INIT;
                   3432:     }
                   3433:     goto END;
                   3434:   }
                   3435:
                   3436:   H = H0 = H1 = NULL;
                   3437:   lb = lgef(B); b = u_allocpol(degpol(B), 0);
                   3438:   bound = ZY_ZXY_ResBound(A,B);
                   3439:   if (DEBUGLEVEL>4) fprintferr("bound for resultant coeffs: 2^%ld\n",bound);
                   3440:
                   3441:   for(;;)
                   3442:   {
                   3443:     p += *d++; if (!*d) err(primer1);
                   3444:
                   3445:     a = u_Fp_FpX(A, 0, p);
                   3446:     for (i=2; i<lb; i++)
                   3447:       b[i] = (long)u_Fp_FpX((GEN)B[i], 0, p);
                   3448:     if (LERS)
                   3449:     {
                   3450:       if (!b[lb-1] || degpol(a) < degpol(A)) continue; /* p | lc(A)lc(B) */
                   3451:       if (checksqfree)
                   3452:       { /* find degree list for generic Euclidean Remainder Sequence */
                   3453:         int goal = min(degpol(a), degpol(b)); /* longest possible */
                   3454:         for (n=1; n <= goal; n++) dglist[n] = 0;
                   3455:         setlg(dglist, 1);
                   3456:         for (n=0; n <= dres; n++)
                   3457:         {
                   3458:           ev = vec_u_FpX_eval(b, n, p);
                   3459:           (void)u_FpX_resultant_all(a, ev, NULL, NULL, dglist, p);
                   3460:           if (lg(dglist)-1 == goal) break;
                   3461:         }
                   3462:         /* last pol in ERS has degree > 1 ? */
                   3463:         goal = lg(dglist)-1;
                   3464:         if (degpol(B) == 1) { if (!goal) goto INIT; }
                   3465:         else
                   3466:         {
                   3467:           if (goal <= 1) goto INIT;
                   3468:           if (dglist[goal] != 0 || dglist[goal-1] != 1) goto INIT;
                   3469:         }
                   3470:         if (DEBUGLEVEL>4)
                   3471:           fprintferr("Degree list for ERS (trials: %ld) = %Z\n",n+1,dglist);
                   3472:       }
                   3473:
                   3474:       for (i=0,n = 0; i <= dres; n++)
                   3475:       {
                   3476:         i++; ev = vec_u_FpX_eval(b, n, p);
                   3477:         x[i] = n;
                   3478:         y[i] = u_FpX_resultant_all(a, ev, C0+i, C1+i, dglist, p);
                   3479:         if (!C1[i]) i--; /* C1(i) = 0. No way to recover C0(i) */
                   3480:       }
                   3481:       u_FpV_polint_all(x,y,C0,C1, p);
                   3482:       Hp = (GEN)y[1];
                   3483:       H0p= (GEN)C0[1];
                   3484:       H1p= (GEN)C1[1];
                   3485:     }
                   3486:     else
                   3487:     {
                   3488:       ulong la = (ulong)leading_term(a);
                   3489:       int drop;
                   3490:      /* Evaluate at 0 (if dres even) and +/- n, so that P_n(X) = P_{-n}(-X),
                   3491:       * where P_i is Lagrange polynomial: P_i(j) = 1 if i=j, 0 otherwise */
                   3492:       for (i=0,n = 1; n <= nmax; n++)
                   3493:       {
                   3494:         ev = vec_u_FpX_eval_gen(b, n, p, &drop);
                   3495:         i++; x[i] = n;   y[i] = u_FpX_resultant(a, ev, p);
                   3496:         if (drop && la != 1) y[i] = mulssmod(y[i], powuumod(la, drop,p),p);
                   3497:         ev = vec_u_FpX_eval_gen(b, p-n, p, &drop);
                   3498:         i++; x[i] = p-n; y[i] = u_FpX_resultant(a, ev, p);
                   3499:         if (drop && la != 1) y[i] = mulssmod(y[i], powuumod(la, drop,p),p);
                   3500:       }
                   3501:       if (i == dres)
                   3502:       {
                   3503:         ev = vec_u_FpX_eval_gen(b, 0, p, &drop);
                   3504:         i++; x[i] = 0;   y[i] = u_FpX_resultant(a, ev, p);
                   3505:         if (drop && la != 1) y[i] = mulssmod(y[i], powuumod(la, drop,p),p);
                   3506:       }
                   3507:       Hp = u_FpV_polint(x,y, p);
                   3508:     }
                   3509:     if (!H && degpol(Hp) != dres) continue;
                   3510:     if (checksqfree) {
                   3511:       if (!u_FpX_is_squarefree(Hp, p)) goto INIT;
                   3512:       if (DEBUGLEVEL>4) fprintferr("Final lambda = %ld\n",*lambda);
                   3513:       checksqfree = 0;
                   3514:     }
                   3515:
                   3516:     if (!H)
                   3517:     { /* initialize */
                   3518:       q = utoi(p); stable = 0;
                   3519:       H = ZX_init_CRT(Hp, p,vX);
                   3520:       if (LERS) {
                   3521:         H0= ZX_init_CRT(H0p, p,vX);
                   3522:         H1= ZX_init_CRT(H1p, p,vX);
                   3523:       }
                   3524:     }
                   3525:     else
                   3526:     {
                   3527:       GEN qp = muliu(q,p);
                   3528:       stable = ZX_incremental_CRT(H, Hp, q,qp, p);
                   3529:       if (LERS) {
                   3530:         stable &= ZX_incremental_CRT(H0,H0p, q,qp, p);
                   3531:         stable &= ZX_incremental_CRT(H1,H1p, q,qp, p);
                   3532:       }
                   3533:       q = qp;
                   3534:     }
                   3535:     /* could make it probabilistic for H ? [e.g if stable twice, etc]
                   3536:      * Probabilistic anyway for H0, H1 */
                   3537:     if (DEBUGLEVEL>5)
                   3538:       msgtimer("resultant mod %ld (bound 2^%ld, stable=%ld)", p,expi(q),stable);
                   3539:     if (stable && (ulong)expi(q) >= bound) break; /* DONE */
                   3540:     if (low_stack(lim, stack_lim(av,2)))
                   3541:     {
                   3542:       GEN *gptr[4]; gptr[0] = &H; gptr[1] = &q; gptr[2] = &H0; gptr[3] = &H1;
                   3543:       if (DEBUGMEM>1) err(warnmem,"ZY_ZXY_resultant");
                   3544:       gerepilemany(av2,gptr,LERS? 4: 2); b = u_allocpol(degpol(B), 0);
                   3545:     }
                   3546:   }
                   3547: END:
                   3548:   setvarn(H, vX); if (delete) delete_var();
                   3549:   if (cB) H = gmul(H, gpowgs(cB, degpol(A)));
                   3550:   if (LERS)
                   3551:   {
                   3552:     GEN *gptr[2];
                   3553:     GEN z = cgetg(3, t_VEC);
                   3554:     z[1] = (long)H0;
                   3555:     z[2] = (long)H1; *LERS = z;
                   3556:     gptr[0]=&H; gptr[1]=LERS;
                   3557:     gerepilemany(av, gptr, 2);
                   3558:     return H;
                   3559:   }
                   3560:   if (!cB) H = gcopy(H);
                   3561:   return gerepileupto(av, H);
                   3562: }
                   3563:
                   3564: GEN
                   3565: ZY_ZXY_resultant(GEN A, GEN B0, long *lambda)
                   3566: {
                   3567:   return ZY_ZXY_resultant_all(A, B0, lambda, NULL);
                   3568: }
                   3569:
                   3570: /* If lambda = NULL, return caract(Mod(B, A)), A,B in Z[X].
                   3571:  * Otherwise find a small lambda such that caract (Mod(B + lambda X, A)) is
                   3572:  * squarefree */
                   3573: GEN
                   3574: ZX_caract_sqf(GEN A, GEN B, long *lambda, long v)
                   3575: {
                   3576:   ulong av = avma;
                   3577:   GEN B0, R, a;
                   3578:   long dB;
                   3579:   int delete;
                   3580:
                   3581:   if (v < 0) v = 0;
                   3582:   switch (typ(B))
                   3583:   {
                   3584:     case t_POL: dB = degpol(B); if (dB > 0) break;
                   3585:       B = dB? (GEN)B[2]: gzero; /* fall through */
                   3586:     default:
                   3587:       if (lambda) { B = scalarpol(B,varn(A)); dB = 0; break;}
                   3588:       return gerepileupto(av, gpowgs(gsub(polx[v], B), degpol(A)));
                   3589:   }
                   3590:   delete = 0;
                   3591:   if (varn(A) == 0)
                   3592:   {
                   3593:     long v0 = fetch_var(); delete = 1;
                   3594:     A = dummycopy(A); setvarn(A,v0);
                   3595:     B = dummycopy(B); setvarn(B,v0);
                   3596:   }
                   3597:   B0 = cgetg(4, t_POL); B0[1] = evalsigne(1)|evalvarn(0)|evallgef(4);
                   3598:   B0[2] = (long)gneg_i(B);
                   3599:   B0[3] = un;
                   3600:   R = ZY_ZXY_resultant(A, B0, lambda);
                   3601:   if (delete) delete_var();
                   3602:   setvarn(R, v); a = leading_term(A);
                   3603:   if (!gcmp1(a)) R = gdiv(R, gpowgs(a, dB));
                   3604:   return gerepileupto(av, R);
                   3605: }
                   3606:
                   3607: GEN
                   3608: ZX_caract(GEN A, GEN B, long v)
                   3609: {
                   3610:   return ZX_caract_sqf(A, B, NULL, v);
                   3611: }
                   3612:
                   3613: static GEN
                   3614: trivial_case(GEN A, GEN B)
                   3615: {
                   3616:   if (typ(A) == t_INT) return gpowgs(A, degpol(B));
                   3617:   if (degpol(A) == 0) return trivial_case((GEN)A[2],B);
                   3618:   return NULL;
                   3619: }
                   3620:
                   3621: GEN
                   3622: ZX_resultant_all(GEN A, GEN B, ulong bound)
                   3623: {
                   3624:   ulong av = avma, av2, lim, Hp;
                   3625:   int stable;
                   3626:   GEN q, a, b, H;
                   3627:   byteptr d = diffptr + 3000;
                   3628:   ulong p = 27449; /* p = prime(3000) */
                   3629:
                   3630:   if ((H = trivial_case(A,B)) || (H = trivial_case(B,A))) return H;
                   3631:   q = H = NULL;
                   3632:   av2 = avma; lim = stack_lim(av,2);
                   3633:   if (!bound) bound = ZY_ZXY_ResBound(A,B);
                   3634:   if (DEBUGLEVEL>4) fprintferr("bound for resultant: 2^%ld\n",bound);
                   3635:
                   3636:   for(;;)
                   3637:   {
                   3638:     p += *d++; if (!*d) err(primer1);
                   3639:     a = u_Fp_FpX(A, 0, p);
                   3640:     b = u_Fp_FpX(B, 0, p);
                   3641:     Hp= u_FpX_resultant(a, b, p);
                   3642:     if (!H)
                   3643:     {
                   3644:       stable = 0; q = utoi(p);
                   3645:       H = u_center(Hp, p, p>>1);
                   3646:     }
                   3647:     else /* could make it probabilistic ??? [e.g if stable twice, etc] */
                   3648:     {
                   3649:       GEN qp = muliu(q,p);
                   3650:       stable = Z_incremental_CRT(&H, Hp, q,qp, p);
                   3651:       q = qp;
                   3652:     }
                   3653:     if (DEBUGLEVEL>5)
                   3654:       msgtimer("resultant mod %ld (bound 2^%ld, stable = %d)",p,expi(q),stable);
                   3655:     if (stable && (ulong)expi(q) >= bound) break; /* DONE */
                   3656:     if (low_stack(lim, stack_lim(av,2)))
                   3657:     {
                   3658:       GEN *gptr[2]; gptr[0] = &H; gptr[1] = &q;
                   3659:       if (DEBUGMEM>1) err(warnmem,"ZX_resultant");
                   3660:       gerepilemany(av2,gptr, 2);
                   3661:     }
                   3662:   }
                   3663:   return gerepileuptoint(av, icopy(H));
                   3664: }
                   3665:
                   3666: GEN
                   3667: ZX_resultant(GEN A, GEN B) { return ZX_resultant_all(A,B,0); }
                   3668:
                   3669: /* assume x has integral coefficients */
                   3670: GEN
                   3671: ZX_disc_all(GEN x, ulong bound)
                   3672: {
                   3673:   ulong av = avma;
                   3674:   GEN l, d = ZX_resultant_all(x, derivpol(x), bound);
                   3675:   l = leading_term(x); if (!gcmp1(l)) d = divii(d,l);
                   3676:   if (degpol(x) & 2) d = negi(d);
                   3677:   return gerepileuptoint(av,d);
                   3678: }
                   3679: GEN ZX_disc(GEN x) { return ZX_disc_all(x,0); }
                   3680:
                   3681: int
                   3682: ZX_is_squarefree(GEN x)
                   3683: {
                   3684:   ulong av = avma;
                   3685:   int d = (lgef(modulargcd(x,derivpol(x))) == 3);
                   3686:   avma = av; return d;
                   3687: }
                   3688:
                   3689: /* h integer, P in Z[X]. Return h^degpol(P) P(x / h) */
                   3690: GEN
                   3691: ZX_rescale_pol(GEN P, GEN h)
                   3692: {
                   3693:   long i, l = lgef(P);
                   3694:   GEN Q = cgetg(l,t_POL), hi = gun;
                   3695:   Q[l-1] = P[l-1];
                   3696:   for (i=l-2; i>=2; i--)
                   3697:   {
                   3698:     hi = gmul(hi,h); Q[i] = lmul((GEN)P[i], hi);
                   3699:   }
                   3700:   Q[1] = P[1]; return Q;
                   3701: }
                   3702:
                   3703: /* A0 and B0 in Q[X] */
                   3704: GEN
                   3705: modulargcd(GEN A0, GEN B0)
                   3706: {
                   3707:   GEN a,b,Hp,D,A,B,q,qp,H,g,p1;
                   3708:   long m,n;
                   3709:   ulong p, av2, av = avma, avlim = stack_lim(av,1);
                   3710:   byteptr d = diffptr;
                   3711:
                   3712:   if ((typ(A0) | typ(B0)) !=t_POL) err(notpoler,"modulargcd");
                   3713:   if (!signe(A0)) return gcopy(B0);
                   3714:   if (!signe(B0)) return gcopy(A0);
                   3715:   A = content(A0);
                   3716:   B = content(B0); D = ggcd(A,B);
                   3717:   A = gcmp1(A)? A0: gdiv(A0,A);
                   3718:   B = gcmp1(B)? B0: gdiv(B0,B);
                   3719:   /* A, B in Z[X] */
                   3720:   g = mppgcd(leading_term(A), leading_term(B)); /* multiple of lead(gcd) */
                   3721:   if (degpol(A) < degpol(B)) swap(A, B);
                   3722:   n = 1 + degpol(B); /* > degree(gcd) */
                   3723:
                   3724:   av2 = avma; H = NULL;
                   3725:   d += 3000; /* 27449 = prime(3000) */
                   3726:   for(p = 27449; ; p+= *d++)
                   3727:   {
                   3728:     if (!*d) err(primer1);
                   3729:     if (!umodiu(g,p)) continue;
                   3730:
                   3731:     a = u_Fp_FpX(A, 0, p);
                   3732:     b = u_Fp_FpX(B, 0, p); Hp = u_FpX_gcd_i(a,b, p);
                   3733:     m = degpol(Hp);
                   3734:     if (m == 0) { H = polun[varn(A0)]; break; } /* coprime. DONE */
                   3735:     if (m > n) continue; /* p | Res(A/G, B/G). Discard */
                   3736:
                   3737:     if (is_pm1(g)) /* make sure lead(H) = g mod p */
                   3738:       Hp = u_FpX_normalize(Hp, p);
                   3739:     else
                   3740:     {
                   3741:       ulong t = mulssmod(umodiu(g, p), u_invmod(Hp[m+2],p), p);
                   3742:       Hp = u_FpX_Fp_mul(Hp, t, p, 0);
                   3743:     }
                   3744:     if (m < n)
                   3745:     { /* First time or degree drop [all previous p were as above; restart]. */
                   3746:       H = ZX_init_CRT(Hp,p,varn(A0));
                   3747:       q = utoi(p); n = m; continue;
                   3748:     }
                   3749:
                   3750:     qp = muliu(q,p);
                   3751:     if (ZX_incremental_CRT(H, Hp, q, qp, p))
                   3752:     { /* H stable: check divisibility */
                   3753:       if (!is_pm1(g)) { p1 = content(H); if (!is_pm1(p1)) H = gdiv(H,p1); }
                   3754:       if (!signe(gres(A,H)) && !signe(gres(B,H))) break; /* DONE */
                   3755:
                   3756:       if (DEBUGLEVEL) fprintferr("modulargcd: trial division failed");
                   3757:     }
                   3758:     q = qp;
                   3759:     if (low_stack(avlim, stack_lim(av,1)))
                   3760:     {
                   3761:       GEN *gptr[2]; gptr[0]=&H; gptr[1]=&q;
                   3762:       if (DEBUGMEM>1) err(warnmem,"modulargcd");
                   3763:       gerepilemany(av2,gptr,2);
                   3764:     }
                   3765:   }
                   3766:   return gerepileupto(av, gmul(D,H));
                   3767: }
                   3768:
                   3769: /* lift(1 / Mod(A,B)) */
                   3770: GEN
                   3771: ZX_invmod(GEN A0, GEN B0)
                   3772: {
                   3773:   GEN a,b,D,A,B,q,qp,Up,Vp,U,V,res;
                   3774:   long stable;
                   3775:   ulong p, av2, av = avma, avlim = stack_lim(av,1);
                   3776:   byteptr d = diffptr;
                   3777:
                   3778:   if (typ(B0) != t_POL) err(notpoler,"ZX_invmod");
                   3779:   if (typ(A0) != t_POL)
                   3780:   {
                   3781:     if (is_scalar_t(typ(A0))) return ginv(A0);
                   3782:     err(notpoler,"ZX_invmod");
                   3783:   }
                   3784:   A = content(A0); D = A;
                   3785:   B = content(B0);
                   3786:   A = gcmp1(A)? A0: gdiv(A0,A);
                   3787:   B = gcmp1(B)? B0: gdiv(B0,B);
                   3788:   /* A, B in Z[X] */
                   3789:   av2 = avma; U = NULL;
                   3790:   d += 3000; /* 27449 = prime(3000) */
                   3791:   for(p = 27449; ; p+= *d++)
                   3792:   {
                   3793:     if (!*d) err(primer1);
                   3794:     a = u_Fp_FpX(A, 0, p);
                   3795:     b = u_Fp_FpX(B, 0, p);
                   3796:     /* if p | Res(A/G, B/G), discard */
                   3797:     if (!u_FpX_extresultant(b,a,p, &Vp,&Up)) continue;
                   3798:
                   3799:     if (!U)
                   3800:     { /* First time */
                   3801:       U = ZX_init_CRT(Up,p,varn(A0));
                   3802:       V = ZX_init_CRT(Vp,p,varn(A0));
                   3803:       q = utoi(p); continue;
                   3804:     }
                   3805:     if (DEBUGLEVEL>5) msgtimer("ZX_invmod: mod %ld (bound 2^%ld)", p,expi(q));
                   3806:     qp = muliu(q,p);
                   3807:     stable  = ZX_incremental_CRT(U, Up, q,qp, p);
                   3808:     stable &= ZX_incremental_CRT(V, Vp, q,qp, p);
                   3809:     if (stable)
                   3810:     { /* all stable: check divisibility */
                   3811:       res = gadd(gmul(A,U), gmul(B,V));
                   3812:       if (degpol(res) == 0) break; /* DONE */
                   3813:       if (DEBUGLEVEL) fprintferr("ZX_invmod: char 0 check failed");
                   3814:     }
                   3815:     q = qp;
                   3816:     if (low_stack(avlim, stack_lim(av,1)))
                   3817:     {
                   3818:       GEN *gptr[3]; gptr[0]=&q; gptr[1]=&U; gptr[2]=&V;
                   3819:       if (DEBUGMEM>1) err(warnmem,"ZX_invmod");
                   3820:       gerepilemany(av2,gptr,3);
                   3821:     }
                   3822:   }
                   3823:   D = gmul(D,res);
                   3824:   return gerepileupto(av, gdiv(U,D));
                   3825: }
                   3826:

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