[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     ! 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>