[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.2

1.2     ! noro        1: /* $Id: polarit3.c,v 1.147 2002/09/07 15:46:28 karim Exp $
1.1       noro        2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /***********************************************************************/
                     17: /**                                                                   **/
                     18: /**               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:
1.2     ! noro       36: #define both_odd(x,y) ((x)&(y)&1)
        !            37: extern GEN caractducos(GEN p, GEN x, int v);
        !            38: extern double mylog2(GEN z);
        !            39: extern GEN revpol(GEN x);
        !            40:
1.1       noro       41: /*******************************************************************/
                     42: /*                                                                 */
                     43: /*                  KARATSUBA (for polynomials)                    */
                     44: /*                                                                 */
                     45: /*******************************************************************/
                     46:
                     47: #if 1 /* for tunings */
                     48: long SQR_LIMIT = 6;
                     49: long MUL_LIMIT = 10;
                     50: long u_SQR_LIMIT = 6;
                     51: long u_MUL_LIMIT = 10;
                     52:
                     53: void
                     54: setsqpol(long a) { SQR_LIMIT=a; u_SQR_LIMIT=a; }
                     55: void
                     56: setmulpol(long a) { MUL_LIMIT=a; u_MUL_LIMIT=a; }
                     57:
                     58: GEN
                     59: u_specpol(GEN x, long nx)
                     60: {
                     61:   GEN z = cgetg(nx+2,t_POL);
                     62:   long i;
                     63:   for (i=0; i<nx; i++) z[i+2] = lstoi(x[i]);
                     64:   z[1]=evalsigne(1)|evallgef(nx+2);
                     65:   return z;
                     66: }
                     67:
                     68: GEN
                     69: specpol(GEN x, long nx)
                     70: {
                     71:   GEN z = cgetg(nx+2,t_POL);
                     72:   long i;
                     73:   for (i=0; i<nx; i++) z[i+2] = x[i];
                     74:   z[1]=evalsigne(1)|evallgef(nx+2);
                     75:   return z;
                     76: }
                     77: #else
                     78: #  define SQR_LIMIT 6
                     79: #  define MUL_LIMIT 10
                     80: #endif
                     81:
                     82: #ifndef HIGHWORD
                     83: #  define HIGHWORD(a) ((a) >> BITS_IN_HALFULONG)
                     84: #endif
                     85:
                     86: /* multiplication in Fp[X], p small */
                     87:
1.2     ! noro       88: GEN
1.1       noro       89: u_normalizepol(GEN x, long lx)
                     90: {
                     91:   long i;
                     92:   for (i=lx-1; i>1; i--)
                     93:     if (x[i]) break;
                     94:   setlgef(x,i+1);
                     95:   setsigne(x, (i > 1)); return x;
                     96: }
                     97:
                     98: GEN
                     99: u_FpX_deriv(GEN z, ulong p)
                    100: {
                    101:   long i,l = lgef(z)-1;
                    102:   GEN x;
                    103:   if (l < 2) l = 2;
                    104:   x = cgetg(l,t_VECSMALL); x[1] = z[1]; z++;
                    105:   if (HIGHWORD(l | p))
                    106:     for (i=2; i<l; i++) x[i] = mulssmod(i-1, z[i], p);
                    107:   else
                    108:     for (i=2; i<l; i++) x[i] = ((i-1) * z[i]) % p;
                    109:   return u_normalizepol(x,l);
                    110: }
                    111:
                    112: static GEN
                    113: u_FpX_gcd_i(GEN a, GEN b, ulong p)
                    114: {
                    115:   GEN c;
                    116:   if (lgef(b) > lgef(a)) swap(a, b);
                    117:   while (signe(b))
                    118:   {
                    119:     c = u_FpX_rem(a,b,p);
                    120:     a = b; b = c;
                    121:   }
                    122:   return a;
                    123: }
                    124:
                    125: GEN
                    126: u_FpX_gcd(GEN a, GEN b, ulong p)
                    127: {
1.2     ! noro      128:   gpmem_t av = avma;
1.1       noro      129:   return gerepileupto(av, u_FpX_gcd_i(a,b,p));
                    130: }
                    131:
                    132: int
                    133: u_FpX_is_squarefree(GEN z, ulong p)
                    134: {
1.2     ! noro      135:   gpmem_t av = avma;
1.1       noro      136:   GEN d = u_FpX_gcd_i(z, u_FpX_deriv(z,p) , p);
                    137:   avma = av; return (degpol(d) == 0);
                    138: }
                    139:
                    140: static GEN
                    141: u_FpX_addspec(GEN x, GEN y, long p, long lx, long ly)
                    142: {
                    143:   long i,lz;
                    144:   GEN z;
                    145:
                    146:   if (ly>lx) swapspec(x,y, lx,ly);
                    147:   lz = lx+2; z = cgetg(lz,t_VECSMALL) + 2;
                    148:   for (i=0; i<ly; i++) z[i] = addssmod(x[i],y[i],p);
                    149:   for (   ; i<lx; i++) z[i] = x[i];
                    150:   z -= 2; z[1]=0; return u_normalizepol(z, lz);
                    151: }
                    152:
                    153: #ifdef INLINE
                    154: INLINE
                    155: #endif
                    156: ulong
                    157: u_FpX_mullimb(GEN x, GEN y, ulong p, long a, long b)
                    158: {
                    159:   ulong p1 = 0;
                    160:   long i;
                    161:   for (i=a; i<b; i++)
                    162:     if (y[i])
                    163:     {
                    164:       p1 += y[i] * x[-i];
                    165:       if (p1 & HIGHBIT) p1 %= p;
                    166:     }
                    167:   return p1 % p;
                    168: }
                    169:
                    170: ulong
                    171: u_FpX_mullimb_safe(GEN x, GEN y, ulong p, long a, long b)
                    172: {
                    173:   ulong p1 = 0;
                    174:   long i;
                    175:   for (i=a; i<b; i++)
                    176:     if (y[i])
                    177:       p1 = addssmod(p1, mulssmod(y[i],x[-i],p), p);
                    178:   return p1;
                    179: }
                    180:
                    181: /* assume nx >= ny > 0 */
                    182: static GEN
                    183: s_FpX_mulspec(GEN x, GEN y, ulong p, long nx, long ny)
                    184: {
                    185:   long i,lz,nz;
                    186:   GEN z;
                    187:
                    188:   lz = nx+ny+1; nz = lz-2;
                    189:   z = cgetg(lz, t_VECSMALL) + 2; /* x:y:z [i] = term of degree i */
                    190:   if (u_OK_ULONG(p))
                    191:   {
                    192:     for (i=0; i<ny; i++)z[i] = (long)u_FpX_mullimb(x+i,y,p,0,i+1);
                    193:     for (  ; i<nx; i++) z[i] = (long)u_FpX_mullimb(x+i,y,p,0,ny);
                    194:     for (  ; i<nz; i++) z[i] = (long)u_FpX_mullimb(x+i,y,p,i-nx+1,ny);
                    195:   }
                    196:   else
                    197:   {
                    198:     for (i=0; i<ny; i++)z[i] = (long)u_FpX_mullimb_safe(x+i,y,p,0,i+1);
                    199:     for (  ; i<nx; i++) z[i] = (long)u_FpX_mullimb_safe(x+i,y,p,0,ny);
                    200:     for (  ; i<nz; i++) z[i] = (long)u_FpX_mullimb_safe(x+i,y,p,i-nx+1,ny);
                    201:   }
                    202:   z -= 2; z[1]=0; return u_normalizepol(z, lz);
                    203: }
                    204:
                    205: /* return (x * X^d) + y. Assume d > 0, x > 0 and y >= 0 */
                    206: GEN
                    207: u_FpX_addshift(GEN x, GEN y, ulong p, long d)
                    208: {
                    209:   GEN xd,yd,zd = (GEN)avma;
                    210:   long a,lz,ny = lgef(y)-2, nx = lgef(x)-2;
                    211:
                    212:   x += 2; y += 2; a = ny-d;
                    213:   if (a <= 0)
                    214:   {
                    215:     lz = (a>nx)? ny+2: nx+d+2;
                    216:     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
                    217:     while (xd > x) *--zd = *--xd;
                    218:     x = zd + a;
                    219:     while (zd > x) *--zd = 0;
                    220:   }
                    221:   else
                    222:   {
                    223:     xd = new_chunk(d); yd = y+d;
                    224:     x = u_FpX_addspec(x,yd,p, nx,a);
                    225:     lz = (a>nx)? ny+2: lgef(x)+d;
                    226:     x += 2; while (xd > x) *--zd = *--xd;
                    227:   }
                    228:   while (yd > y) *--zd = *--yd;
                    229:   *--zd = evalsigne(1) | evallgef(lz);
                    230:   *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;
                    231: }
                    232:
                    233: #define u_FpX_mul(x,y, p) u_FpX_Kmul(x+2,y+2,p, lgef(x)-2,lgef(y)-2)
                    234: #define u_FpX_sqr(x, p) u_FpX_Ksqr(x+2,p, lgef(x)-2)
                    235: #define u_FpX_add(x,y, p) u_FpX_addspec(x+2,y+2,p, lgef(x)-2,lgef(y)-2)
                    236:
1.2     ! noro      237: GEN
        !           238: u_zeropol()
        !           239: {
        !           240:   GEN z = cgetg(2, t_VECSMALL);
        !           241:   z[1] = evallgef(2) | evalvarn(0); return z;
        !           242: }
        !           243:
1.1       noro      244: static GEN
1.2     ! noro      245: u_mallocpol(long d)
1.1       noro      246: {
1.2     ! noro      247:   GEN z = (GEN)gpmalloc((d+3) * sizeof(long));
1.1       noro      248:   z[0] = evaltyp(t_VECSMALL) | evallg(d+3);
                    249:   z[1] = evalsigne((d >= 0)) | evallgef(d+3) | evalvarn(0);
                    250:   return z;
                    251: }
1.2     ! noro      252: static GEN
        !           253: u_getpol(long d)
        !           254: {
        !           255:   GEN z = cgetg(d + 3, t_VECSMALL);
        !           256:   z[1] = evalsigne((d >= 0)) | evallgef(d+3) | evalvarn(0);
        !           257:   return z;
        !           258: }
1.1       noro      259:
                    260: static GEN
1.2     ! noro      261: u_scalarpol(ulong x)
1.1       noro      262: {
1.2     ! noro      263:   GEN z;
        !           264:   if (!x) return u_zeropol();
        !           265:   z = u_getpol(0);
1.1       noro      266:   z[2] = x; return z;
                    267: }
                    268:
                    269: static GEN
1.2     ! noro      270: u_FpX_neg(GEN x, ulong p)
        !           271: {
        !           272:   long i, l = lgef(x);
        !           273:   GEN z = cgetg(l, t_VECSMALL);
        !           274:   z[1] = x[1];
        !           275:   for (i=2; i<l; i++) z[i] = x[i]? p - x[i]: 0;
        !           276:   return z;
        !           277: }
        !           278:
        !           279: static GEN
1.1       noro      280: u_FpX_neg_i(GEN x, ulong p)
                    281: {
                    282:   long i, l = lgef(x);
                    283:   for (i=2; i<l; i++)
                    284:     if (x[i]) x[i] = p - x[i];
                    285:   return x;
                    286: }
                    287:
                    288: /* shift polynomial + gerepile */
                    289: static GEN
1.2     ! noro      290: u_FpX_shiftip(gpmem_t av, GEN x, long v)
1.1       noro      291: {
                    292:   long i, lx = lgef(x), ly;
                    293:   GEN y;
                    294:   if (v <= 0 || !signe(x)) return gerepileupto(av, x);
                    295:   avma = av; ly = lx + v;
                    296:   x += lx; y = new_chunk(ly) + ly;
                    297:   for (i = 2; i<lx; i++) *--y = *--x;
                    298:   for (i = 0; i< v; i++) *--y = 0;
                    299:   *--y = evalsigne(1) | evallgef(ly);
                    300:   *--y = evaltyp(t_VECSMALL) | evallg(ly); return y;
                    301: }
                    302:
                    303: /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
                    304:  * b+2 were sent instead. na, nb = number of terms of a, b.
                    305:  * Only c, c0, c1, c2 are genuine GEN.
                    306:  */
                    307: GEN
                    308: u_FpX_Kmul(GEN a, GEN b, ulong p, long na, long nb)
                    309: {
                    310:   GEN a0,c,c0;
1.2     ! noro      311:   long n0, n0a, i, v = 0;
        !           312:   gpmem_t av;
1.1       noro      313:
                    314:   while (na && !a[0]) { a++; na--; v++; }
                    315:   while (nb && !b[0]) { b++; nb--; v++; }
                    316:   if (na < nb) swapspec(a,b, na,nb);
1.2     ! noro      317:   if (!nb) return u_zeropol();
1.1       noro      318:
                    319:   av = avma;
                    320:   if (nb < u_MUL_LIMIT)
                    321:     return u_FpX_shiftip(av,s_FpX_mulspec(a,b,p,na,nb), v);
                    322:   i=(na>>1); n0=na-i; na=i;
                    323:   a0=a+n0; n0a=n0;
                    324:   while (n0a && !a[n0a-1]) n0a--;
                    325:
                    326:   if (nb > n0)
                    327:   {
                    328:     GEN b0,c1,c2;
                    329:     long n0b;
                    330:
                    331:     nb -= n0; b0 = b+n0; n0b = n0;
                    332:     while (n0b && !b[n0b-1]) n0b--;
                    333:     c =  u_FpX_Kmul(a,b,p,n0a,n0b);
                    334:     c0 = u_FpX_Kmul(a0,b0,p,na,nb);
                    335:
                    336:     c2 = u_FpX_addspec(a0,a,p,na,n0a);
                    337:     c1 = u_FpX_addspec(b0,b,p,nb,n0b);
                    338:
                    339:     c1 = u_FpX_mul(c1,c2,p);
                    340:     c2 = u_FpX_add(c0,c,p);
                    341:
                    342:     c2 = u_FpX_neg_i(c2,p);
                    343:     c2 = u_FpX_add(c1,c2,p);
                    344:     c0 = u_FpX_addshift(c0,c2 ,p, n0);
                    345:   }
                    346:   else
                    347:   {
                    348:     c  = u_FpX_Kmul(a,b,p,n0a,nb);
                    349:     c0 = u_FpX_Kmul(a0,b,p,na,nb);
                    350:   }
                    351:   c0 = u_FpX_addshift(c0,c,p,n0);
                    352:   return u_FpX_shiftip(av,c0, v);
                    353: }
                    354:
                    355: GEN
                    356: u_FpX_sqrpol(GEN x, ulong p, long nx)
                    357: {
                    358:   long i,j,l,lz,nz;
                    359:   ulong p1;
                    360:   GEN z;
                    361:
1.2     ! noro      362:   if (!nx) return u_zeropol();
1.1       noro      363:   lz = (nx << 1) + 1, nz = lz-2;
                    364:   z = cgetg(lz,t_VECSMALL) + 2;
                    365:   for (i=0; i<nx; i++)
                    366:   {
                    367:     p1 = 0; l = (i+1)>>1;
                    368:     for (j=0; j<l; j++)
                    369:     {
                    370:       p1 += x[j] * x[i-j];
                    371:       if (p1 & HIGHBIT) p1 %= p;
                    372:     }
                    373:     p1 <<= 1; if (p1 & HIGHBIT) p1 %= p;
                    374:     if ((i&1) == 0)
                    375:       p1 += x[i>>1] * x[i>>1];
                    376:     z[i] = p1 % p;
                    377:   }
                    378:   for (  ; i<nz; i++)
                    379:   {
                    380:     p1 = 0; l = (i+1)>>1;
                    381:     for (j=i-nx+1; j<l; j++)
                    382:     {
                    383:       p1 += x[j] * x[i-j];
                    384:       if (p1 & HIGHBIT) p1 %= p;
                    385:     }
                    386:     p1 <<= 1; if (p1 & HIGHBIT) p1 %= p;
                    387:     if ((i&1) == 0)
                    388:       p1 += x[i>>1] * x[i>>1];
                    389:     z[i] = p1 % p;
                    390:   }
                    391:   z -= 2; z[1]=0; return u_normalizepol(z,lz);
                    392: }
                    393:
                    394: static GEN
                    395: u_Fp_gmul2_1(GEN x, ulong p)
                    396: {
                    397:   long i, l = lgef(x);
                    398:   GEN z = cgetg(l, t_VECSMALL);
                    399:   for (i=2; i<l; i++)
                    400:   {
                    401:     ulong p1 = x[i]<<1;
                    402:     if (p1 > p) p1 -= p;
                    403:     z[i] = p1;
                    404:   }
                    405:   z[1] = x[1]; return z;
                    406: }
                    407:
                    408: GEN
                    409: u_FpX_Ksqr(GEN a, ulong p, long na)
                    410: {
                    411:   GEN a0,c,c0,c1;
1.2     ! noro      412:   long n0, n0a, i, v = 0;
        !           413:   gpmem_t av;
1.1       noro      414:
                    415:   while (na && !a[0]) { a++; na--; v += 2; }
                    416:   av = avma;
                    417:   if (na < u_SQR_LIMIT) return u_FpX_shiftip(av, u_FpX_sqrpol(a,p,na), v);
                    418:   i=(na>>1); n0=na-i; na=i;
                    419:   a0=a+n0; n0a=n0;
                    420:   while (n0a && !a[n0a-1]) n0a--;
                    421:
                    422:   c = u_FpX_Ksqr(a,p,n0a);
                    423:   c0= u_FpX_Ksqr(a0,p,na);
                    424:   if (p == 2) n0 *= 2;
                    425:   else
                    426:   {
                    427:     c1 = u_Fp_gmul2_1(u_FpX_Kmul(a0,a,p, na,n0a), p);
                    428:     c0 = u_FpX_addshift(c0,c1,p,n0);
                    429:   }
                    430:   c0 = u_FpX_addshift(c0,c,p,n0);
                    431:   return u_FpX_shiftip(av,c0,v);
                    432: }
                    433:
                    434: /* generic multiplication */
                    435:
                    436: static GEN
                    437: addpol(GEN x, GEN y, long lx, long ly)
                    438: {
                    439:   long i,lz;
                    440:   GEN z;
                    441:
                    442:   if (ly>lx) swapspec(x,y, lx,ly);
                    443:   lz = lx+2; z = cgetg(lz,t_POL) + 2;
                    444:   for (i=0; i<ly; i++) z[i]=ladd((GEN)x[i],(GEN)y[i]);
                    445:   for (   ; i<lx; i++) z[i]=x[i];
                    446:   z -= 2; z[1]=0; return normalizepol_i(z, lz);
                    447: }
                    448:
                    449: static GEN
                    450: addpolcopy(GEN x, GEN y, long lx, long ly)
                    451: {
                    452:   long i,lz;
                    453:   GEN z;
                    454:
                    455:   if (ly>lx) swapspec(x,y, lx,ly);
                    456:   lz = lx+2; z = cgetg(lz,t_POL) + 2;
                    457:   for (i=0; i<ly; i++) z[i]=ladd((GEN)x[i],(GEN)y[i]);
                    458:   for (   ; i<lx; i++) z[i]=lcopy((GEN)x[i]);
                    459:   z -= 2; z[1]=0; return normalizepol_i(z, lz);
                    460: }
                    461:
                    462: #ifdef INLINE
                    463: INLINE
                    464: #endif
                    465: GEN
                    466: mulpol_limb(GEN x, GEN y, char *ynonzero, long a, long b)
                    467: {
                    468:   GEN p1 = NULL;
1.2     ! noro      469:   long i;
        !           470:   gpmem_t av = avma;
1.1       noro      471:   for (i=a; i<b; i++)
                    472:     if (ynonzero[i])
                    473:     {
                    474:       GEN p2 = gmul((GEN)y[i],(GEN)x[-i]);
                    475:       p1 = p1 ? gadd(p1, p2): p2;
                    476:     }
                    477:   return p1 ? gerepileupto(av, p1): gzero;
                    478: }
                    479:
                    480: /* assume nx >= ny > 0 */
                    481: static GEN
                    482: mulpol(GEN x, GEN y, long nx, long ny)
                    483: {
                    484:   long i,lz,nz;
                    485:   GEN z;
                    486:   char *p1;
                    487:
                    488:   lz = nx+ny+1; nz = lz-2;
                    489:   z = cgetg(lz, t_POL) + 2; /* x:y:z [i] = term of degree i */
                    490:   p1 = gpmalloc(ny);
                    491:   for (i=0; i<ny; i++)
                    492:   {
                    493:     p1[i] = !isexactzero((GEN)y[i]);
                    494:     z[i] = (long)mulpol_limb(x+i,y,p1,0,i+1);
                    495:   }
                    496:   for (  ; i<nx; i++) z[i] = (long)mulpol_limb(x+i,y,p1,0,ny);
                    497:   for (  ; i<nz; i++) z[i] = (long)mulpol_limb(x+i,y,p1,i-nx+1,ny);
                    498:   free(p1); z -= 2; z[1]=0; return normalizepol_i(z, lz);
                    499: }
                    500:
                    501: /* return (x * X^d) + y. Assume d > 0, x > 0 and y >= 0 */
                    502: GEN
                    503: addshiftw(GEN x, GEN y, long d)
                    504: {
                    505:   GEN xd,yd,zd = (GEN)avma;
                    506:   long a,lz,ny = lgef(y)-2, nx = lgef(x)-2;
                    507:
                    508:   x += 2; y += 2; a = ny-d;
                    509:   if (a <= 0)
                    510:   {
                    511:     lz = (a>nx)? ny+2: nx+d+2;
                    512:     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
                    513:     while (xd > x) *--zd = *--xd;
                    514:     x = zd + a;
                    515:     while (zd > x) *--zd = zero;
                    516:   }
                    517:   else
                    518:   {
                    519:     xd = new_chunk(d); yd = y+d;
                    520:     x = addpol(x,yd, nx,a);
                    521:     lz = (a>nx)? ny+2: lgef(x)+d;
                    522:     x += 2; while (xd > x) *--zd = *--xd;
                    523:   }
                    524:   while (yd > y) *--zd = *--yd;
                    525:   *--zd = evalsigne(1) | evallgef(lz);
                    526:   *--zd = evaltyp(t_POL) | evallg(lz); return zd;
                    527: }
                    528:
                    529: GEN
                    530: addshiftpol(GEN x, GEN y, long d)
                    531: {
                    532:   long v = varn(x);
                    533:   if (!signe(x)) return y;
                    534:   x = addshiftw(x,y,d);
                    535:   setvarn(x,v); return x;
                    536: }
                    537:
                    538: /* as above, producing a clean malloc */
                    539: static GEN
                    540: addshiftwcopy(GEN x, GEN y, long d)
                    541: {
                    542:   GEN xd,yd,zd = (GEN)avma;
                    543:   long a,lz,ny = lgef(y)-2, nx = lgef(x)-2;
                    544:
                    545:   x += 2; y += 2; a = ny-d;
                    546:   if (a <= 0)
                    547:   {
                    548:     lz = nx+d+2;
                    549:     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
                    550:     while (xd > x) *--zd = lcopy((GEN)*--xd);
                    551:     x = zd + a;
                    552:     while (zd > x) *--zd = zero;
                    553:   }
                    554:   else
                    555:   {
                    556:     xd = new_chunk(d); yd = y+d;
                    557:     x = addpolcopy(x,yd, nx,a);
                    558:     lz = (a>nx)? ny+2: lgef(x)+d;
                    559:     x += 2; while (xd > x) *--zd = *--xd;
                    560:   }
                    561:   while (yd > y) *--zd = lcopy((GEN)*--yd);
                    562:   *--zd = evalsigne(1) | evallgef(lz);
                    563:   *--zd = evaltyp(t_POL) | evallg(lz); return zd;
                    564: }
                    565:
                    566: /* shift polynomial in place. assume v free cells have been left before x */
                    567: static GEN
                    568: shiftpol_ip(GEN x, long v)
                    569: {
                    570:   long i, lx;
                    571:   GEN y;
                    572:   if (v <= 0 || !signe(x)) return x;
                    573:   lx = lgef(x);
                    574:   x += 2; y = x + v;
                    575:   for (i = lx-3; i>=0; i--) y[i] = x[i];
                    576:   for (i = 0   ; i< v; i++) x[i] = zero;
                    577:   lx += v;
                    578:   *--x = evalsigne(1) | evallgef(lx);
                    579:   *--x = evaltyp(t_POL) | evallg(lx); return x;
                    580: }
                    581:
                    582: /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
                    583:  * b+2 were sent instead. na, nb = number of terms of a, b.
                    584:  * Only c, c0, c1, c2 are genuine GEN.
                    585:  */
                    586: GEN
                    587: quickmul(GEN a, GEN b, long na, long nb)
                    588: {
                    589:   GEN a0,c,c0;
1.2     ! noro      590:   long n0, n0a, i, v = 0;
        !           591:   gpmem_t av;
1.1       noro      592:
                    593:   while (na && isexactzero((GEN)a[0])) { a++; na--; v++; }
                    594:   while (nb && isexactzero((GEN)b[0])) { b++; nb--; v++; }
                    595:   if (na < nb) swapspec(a,b, na,nb);
                    596:   if (!nb) return zeropol(0);
                    597:
                    598:   if (v) (void)cgetg(v,t_STR); /* v gerepile-safe cells for shiftpol_ip */
                    599:   if (nb < MUL_LIMIT)
                    600:     return shiftpol_ip(mulpol(a,b,na,nb), v);
                    601:   i=(na>>1); n0=na-i; na=i;
                    602:   av=avma; a0=a+n0; n0a=n0;
                    603:   while (n0a && isexactzero((GEN)a[n0a-1])) n0a--;
                    604:
                    605:   if (nb > n0)
                    606:   {
                    607:     GEN b0,c1,c2;
                    608:     long n0b;
                    609:
                    610:     nb -= n0; b0 = b+n0; n0b = n0;
                    611:     while (n0b && isexactzero((GEN)b[n0b-1])) n0b--;
                    612:     c = quickmul(a,b,n0a,n0b);
                    613:     c0 = quickmul(a0,b0, na,nb);
                    614:
                    615:     c2 = addpol(a0,a, na,n0a);
                    616:     c1 = addpol(b0,b, nb,n0b);
                    617:
                    618:     c1 = quickmul(c1+2,c2+2, lgef(c1)-2,lgef(c2)-2);
                    619:     c2 = gneg_i(gadd(c0,c));
                    620:     c0 = addshiftw(c0, gadd(c1,c2), n0);
                    621:   }
                    622:   else
                    623:   {
                    624:     c = quickmul(a,b,n0a,nb);
                    625:     c0 = quickmul(a0,b,na,nb);
                    626:   }
                    627:   c0 = addshiftwcopy(c0,c,n0);
                    628:   return shiftpol_ip(gerepileupto(av,c0), v);
                    629: }
                    630:
                    631: GEN
                    632: sqrpol(GEN x, long nx)
                    633: {
1.2     ! noro      634:   long i, j, l, lz, nz;
        !           635:   gpmem_t av;
1.1       noro      636:   GEN p1,z;
                    637:   char *p2;
                    638:
                    639:   if (!nx) return zeropol(0);
                    640:   lz = (nx << 1) + 1, nz = lz-2;
                    641:   z = cgetg(lz,t_POL) + 2;
                    642:   p2 = gpmalloc(nx);
                    643:   for (i=0; i<nx; i++)
                    644:   {
                    645:     p2[i] = !isexactzero((GEN)x[i]);
                    646:     p1=gzero; av=avma; l=(i+1)>>1;
                    647:     for (j=0; j<l; j++)
                    648:       if (p2[j] && p2[i-j])
                    649:         p1 = gadd(p1, gmul((GEN)x[j],(GEN)x[i-j]));
                    650:     p1 = gshift(p1,1);
                    651:     if ((i&1) == 0 && p2[i>>1])
                    652:       p1 = gadd(p1, gsqr((GEN)x[i>>1]));
                    653:     z[i] = lpileupto(av,p1);
                    654:   }
                    655:   for (  ; i<nz; i++)
                    656:   {
                    657:     p1=gzero; av=avma; l=(i+1)>>1;
                    658:     for (j=i-nx+1; j<l; j++)
                    659:       if (p2[j] && p2[i-j])
                    660:         p1 = gadd(p1, gmul((GEN)x[j],(GEN)x[i-j]));
                    661:     p1 = gshift(p1,1);
                    662:     if ((i&1) == 0 && p2[i>>1])
                    663:       p1 = gadd(p1, gsqr((GEN)x[i>>1]));
                    664:     z[i] = lpileupto(av,p1);
                    665:   }
                    666:   free(p2); z -= 2; z[1]=0; return normalizepol_i(z,lz);
                    667: }
                    668:
                    669: GEN
                    670: quicksqr(GEN a, long na)
                    671: {
                    672:   GEN a0,c,c0,c1;
1.2     ! noro      673:   long n0, n0a, i, v = 0;
        !           674:   gpmem_t av;
1.1       noro      675:
                    676:   while (na && isexactzero((GEN)a[0])) { a++; na--; v += 2; }
                    677:   if (v) (void)new_chunk(v);
                    678:   if (na<SQR_LIMIT) return shiftpol_ip(sqrpol(a,na), v);
                    679:   i=(na>>1); n0=na-i; na=i;
                    680:   av=avma; a0=a+n0; n0a=n0;
                    681:   while (n0a && isexactzero((GEN)a[n0a-1])) n0a--;
                    682:
                    683:   c = quicksqr(a,n0a);
                    684:   c0 = quicksqr(a0,na);
                    685:   c1 = gmul2n(quickmul(a0,a, na,n0a), 1);
                    686:   c0 = addshiftw(c0,c1, n0);
                    687:   c0 = addshiftwcopy(c0,c,n0);
                    688:   return shiftpol_ip(gerepileupto(av,c0), v);
                    689: }
                    690: /*****************************************
                    691:  * Arithmetic in Z/pZ[X]                 *
                    692:  *****************************************/
                    693:
                    694: /*********************************************************************
                    695: This functions supposes polynomials already reduced.
                    696: There are clean and memory efficient.
                    697: **********************************************************************/
                    698:
                    699: GEN
                    700: FpX_center(GEN T,GEN mod)
                    701: {/*OK centermod exists, but is not so clean*/
1.2     ! noro      702:   gpmem_t av;
1.1       noro      703:   long i, l=lg(T);
                    704:   GEN P,mod2;
                    705:   P=cgetg(l,t_POL);
                    706:   P[1]=T[1];
                    707:   av=avma;
                    708:   mod2=gclone(shifti(mod,-1));/*clone*/
                    709:   avma=av;
                    710:   for(i=2;i<l;i++)
                    711:     P[i]=cmpii((GEN)T[i],mod2)<0?licopy((GEN)T[i]):lsubii((GEN)T[i],mod);
                    712:   gunclone(mod2);/*unclone*/
                    713:   return P;
                    714: }
                    715:
                    716: GEN
                    717: FpX_neg(GEN x,GEN p)
                    718: {
                    719:   long i,d=lgef(x);
                    720:   GEN y;
                    721:   y=cgetg(d,t_POL); y[1]=x[1];
                    722:   for(i=2;i<d;i++)
                    723:     if (signe(x[i])) y[i]=lsubii(p,(GEN)x[i]);
                    724:     else y[i]=zero;
                    725:   return y;
                    726: }
                    727: /**********************************************************************
                    728: Unclean functions, do not garbage collect.
                    729: This is a feature: The malloc is corrupted only by the call to FpX_red
                    730: so garbage collecting so often is not desirable.
                    731: FpX_red can sometime be avoided by passing NULL for p.
                    732: In this case the function is usually clean (see below for detail)
                    733: Added to help not using POLMOD of INTMOD which are deadly slow.
                    734: gerepileupto of the result is legible.   Bill.
                    735: I don't like C++.  I am wrong.
                    736: **********************************************************************/
                    737: /*
                    738:  *If p is NULL no reduction is performed and the function is clean.
                    739:  * for FpX_add,FpX_mul,FpX_sqr,FpX_Fp_mul
                    740:  */
                    741: GEN
                    742: FpX_add(GEN x,GEN y,GEN p)
                    743: {
                    744:   long lx,ly,i;
                    745:   GEN z;
                    746:   lx = lgef(x); ly = lgef(y); if (lx < ly) swapspec(x,y, lx,ly);
                    747:   z = cgetg(lx,t_POL); z[1] = x[1];
                    748:   for (i=2; i<ly; i++) z[i]=laddii((GEN)x[i],(GEN)y[i]);
                    749:   for (   ; i<lx; i++) z[i]=licopy((GEN)x[i]);
                    750:   (void)normalizepol_i(z, lx);
1.2     ! noro      751:   if (lgef(z) == 2) { avma = (gpmem_t)(z + lx); z = zeropol(varn(x)); }
1.1       noro      752:   if (p) z= FpX_red(z, p);
                    753:   return z;
                    754: }
                    755: GEN
                    756: FpX_sub(GEN x,GEN y,GEN p)
                    757: {
                    758:   long lx,ly,i,lz;
                    759:   GEN z;
                    760:   lx = lgef(x); ly = lgef(y);
                    761:   lz=max(lx,ly);
                    762:   z = cgetg(lz,t_POL);
                    763:   if (lx >= ly)
                    764:   {
                    765:     z[1] = x[1];
                    766:     for (i=2; i<ly; i++) z[i]=lsubii((GEN)x[i],(GEN)y[i]);
                    767:     for (   ; i<lx; i++) z[i]=licopy((GEN)x[i]);
                    768:     (void)normalizepol_i(z, lz);
                    769:   }
                    770:   else
                    771:   {
                    772:     z[1] = y[1];
                    773:     for (i=2; i<lx; i++) z[i]=lsubii((GEN)x[i],(GEN)y[i]);
                    774:     for (   ; i<ly; i++) z[i]=lnegi((GEN)y[i]);
                    775:     /*polynomial is always normalized*/
                    776:   }
1.2     ! noro      777:   if (lgef(z) == 2) { avma = (gpmem_t)(z + lz); z = zeropol(varn(x)); }
1.1       noro      778:   if (p) z= FpX_red(z, p);
                    779:   return z;
                    780: }
                    781: GEN
                    782: FpX_mul(GEN x,GEN y,GEN p)
                    783: {
                    784:   GEN z = quickmul(y+2, x+2, lgef(y)-2, lgef(x)-2);
                    785:   setvarn(z,varn(x));
                    786:   if (!p) return z;
                    787:   return FpX_red(z, p);
                    788: }
                    789: GEN
                    790: FpX_sqr(GEN x,GEN p)
                    791: {
                    792:   GEN z = quicksqr(x+2, lgef(x)-2);
                    793:   setvarn(z,varn(x));
                    794:   if (!p) return z;
                    795:   return FpX_red(z, p);
                    796: }
1.2     ! noro      797: #define u_FpX_div(x,y,p) u_FpX_divrem((x),(y),(p),NULL)
1.1       noro      798:
                    799: /* Product of y and x in Z/pZ[X]/(pol), as t_VECSMALL. Assume OK_ULONG(p) */
                    800: static GEN
                    801: u_FpXQ_mul(GEN y,GEN x,GEN pol,ulong p)
                    802: {
                    803:   GEN z = u_FpX_mul(y,x,p);
                    804:   return u_FpX_rem(z,pol,p);
                    805: }
                    806: /* Square of y in Z/pZ[X]/(pol), as t_VECSMALL. Assume OK_ULONG(p) */
                    807: static GEN
                    808: u_FpXQ_sqr(GEN y,GEN pol,ulong p)
                    809: {
                    810:   GEN z = u_FpX_sqr(y,p);
                    811:   return u_FpX_rem(z,pol,p);
                    812: }
                    813:
                    814: /* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist
                    815:  * return lift(1 / (x mod (p,pol))) */
                    816: GEN
                    817: FpXQ_invsafe(GEN x, GEN T, GEN p)
                    818: {
                    819:   GEN z, U, V;
                    820:
                    821:   if (typ(x) != t_POL) return mpinvmod(x, p);
                    822:   z = FpX_extgcd(x, T, p, &U, &V);
1.2     ! noro      823:   if (degpol(z)) return NULL;
1.1       noro      824:   z = mpinvmod((GEN)z[2], p);
                    825:   return FpX_Fp_mul(U, z, p);
                    826: }
                    827:
                    828: /* Product of y and x in Z/pZ[X]/(T)
                    829:  * return lift(lift(Mod(x*y*Mod(1,p),T*Mod(1,p)))) */
1.2     ! noro      830: /* x and y must be poynomials in the same var as T.
        !           831:  * t_INT are not allowed. Use Fq_mul instead.
        !           832:  */
1.1       noro      833: GEN
                    834: FpXQ_mul(GEN y,GEN x,GEN T,GEN p)
                    835: {
                    836:   GEN z;
1.2     ! noro      837:   if (typ(x) == t_INT || typ(y) == t_INT)
        !           838:     err(bugparier,"FpXQ_mul, t_INT are absolutely forbidden");
1.1       noro      839:   z = quickmul(y+2, x+2, lgef(y)-2, lgef(x)-2); setvarn(z,varn(y));
                    840:   z = FpX_red(z, p); return FpX_res(z,T, p);
                    841: }
                    842:
                    843: /* Square of y in Z/pZ[X]/(pol)
                    844:  * return lift(lift(Mod(y^2*Mod(1,p),pol*Mod(1,p)))) */
                    845: GEN
                    846: FpXQ_sqr(GEN y,GEN pol,GEN p)
                    847: {
                    848:   GEN z = quicksqr(y+2,lgef(y)-2); setvarn(z,varn(y));
                    849:   z = FpX_red(z, p); return FpX_res(z,pol, p);
                    850: }
                    851: /*Modify y[2].
                    852:  *No reduction if p is NULL
                    853:  */
                    854: GEN
                    855: FpX_Fp_add(GEN y,GEN x,GEN p)
                    856: {
                    857:   if (!signe(x)) return y;
                    858:   if (!signe(y))
                    859:     return scalarpol(x,varn(y));
                    860:   y[2]=laddii((GEN)y[2],x);
                    861:   if (p) y[2]=lmodii((GEN)y[2],p);
                    862:   if (!signe(y[2]) && degpol(y) == 0) return zeropol(varn(y));
                    863:   return y;
                    864: }
                    865: GEN
                    866: ZX_s_add(GEN y,long x)
                    867: {
                    868:   if (!x) return y;
                    869:   if (!signe(y))
                    870:     return scalarpol(stoi(x),varn(y));
                    871:   y[2] = laddis((GEN)y[2],x);
                    872:   if (!signe(y[2]) && degpol(y) == 0) return zeropol(varn(y));
                    873:   return y;
                    874: }
                    875: /* y is a polynomial in ZZ[X] and x an integer.
1.2     ! noro      876:  * If p is NULL, no reduction is performed and return x*y
1.1       noro      877:  *
                    878:  * else the result is lift(y*x*Mod(1,p))
                    879:  */
                    880: GEN
                    881: FpX_Fp_mul(GEN y,GEN x,GEN p)
                    882: {
                    883:   GEN z;
                    884:   int i;
                    885:   if (!signe(x))
                    886:     return zeropol(varn(y));
                    887:   z=cgetg(lg(y),t_POL);
                    888:   z[1]=y[1];
                    889:   for(i=2;i<lgef(y);i++)
                    890:     z[i]=lmulii((GEN)y[i],x);
                    891:   if(!p) return z;
                    892:   return FpX_red(z,p);
                    893: }
                    894: /*****************************************************************
                    895:  *                 End of unclean functions.                     *
                    896:  *                                                               *
                    897:  *****************************************************************/
1.2     ! noro      898:
        !           899: /* modular power */
        !           900: ulong
        !           901: powuumod(ulong x, ulong n0, ulong p)
        !           902: {
        !           903:   ulong y, z, n;
        !           904:   if (n0 <= 2)
        !           905:   { /* frequent special cases */
        !           906:     if (n0 == 2) return mulssmod(x,x,p);
        !           907:     if (n0 == 1) return x;
        !           908:     if (n0 == 0) return 1;
        !           909:   }
        !           910:   y = 1; z = x; n = n0;
        !           911:   for(;;)
        !           912:   {
        !           913:     if (n&1) y = mulssmod(y,z,p);
        !           914:     n>>=1; if (!n) return y;
        !           915:     z = mulssmod(z,z,p);
        !           916:   }
        !           917: }
        !           918:
        !           919: GEN
        !           920: powgumod(GEN x, ulong n0, GEN p)
        !           921: {
        !           922:   GEN y, z;
        !           923:   ulong n;
        !           924:   if (n0 <= 2)
        !           925:   { /* frequent special cases */
        !           926:     if (n0 == 2) return resii(sqri(x),p);
        !           927:     if (n0 == 1) return x;
        !           928:     if (n0 == 0) return gun;
        !           929:   }
        !           930:   y = gun; z = x; n = n0;
        !           931:   for(;;)
        !           932:   {
        !           933:     if (n&1) y = resii(mulii(y,z),p);
        !           934:     n>>=1; if (!n) return y;
        !           935:     z = resii(sqri(z),p);
        !           936:   }
        !           937: }
        !           938:
1.1       noro      939: /*****************************************************************
                    940:  Clean and with no reduced hypothesis.  Beware that some operations
                    941:  will be much slower with big unreduced coefficient
                    942: *****************************************************************/
                    943: /* Inverse of x in Z[X] / (p,T)
                    944:  * return lift(lift(Mod(x*Mod(1,p), T*Mod(1,p))^-1)); */
                    945: GEN
                    946: FpXQ_inv(GEN x,GEN T,GEN p)
                    947: {
1.2     ! noro      948:   gpmem_t av;
1.1       noro      949:   GEN U;
                    950:
                    951:   if (!T) return mpinvmod(x,p);
                    952:   av = avma;
                    953:   U = FpXQ_invsafe(x, T, p);
                    954:   if (!U) err(talker,"non invertible polynomial in FpXQ_inv");
                    955:   return gerepileupto(av, U);
                    956: }
                    957:
                    958: GEN
1.2     ! noro      959: FpXQ_div(GEN x,GEN y,GEN T,GEN p)
        !           960: {
        !           961:   gpmem_t av = avma;
        !           962:   return gerepileupto(av, FpXQ_mul(x,FpXQ_inv(y,T,p),T,p));
        !           963: }
        !           964:
        !           965: GEN
        !           966: FpXV_FpV_innerprod(GEN V, GEN W, GEN p)
1.1       noro      967: {
1.2     ! noro      968:   gpmem_t ltop=avma;
1.1       noro      969:   long i;
                    970:   GEN z = FpX_Fp_mul((GEN)V[1],(GEN)W[1],NULL);
                    971:   for(i=2;i<lg(V);i++)
                    972:     z=FpX_add(z,FpX_Fp_mul((GEN)V[i],(GEN)W[i],NULL),NULL);
                    973:   return gerepileupto(ltop,FpX_red(z,p));
                    974: }
                    975:
                    976: /* generates the list of powers of x of degree 0,1,2,...,l*/
                    977: GEN
                    978: FpXQ_powers(GEN x, long l, GEN T, GEN p)
                    979: {
                    980:   GEN V=cgetg(l+2,t_VEC);
                    981:   long i;
                    982:   V[1] = (long) scalarpol(gun,varn(T));
                    983:   if (l==0) return V;
                    984:   V[2] = lcopy(x);
                    985:   if (l==1) return V;
                    986:   V[3] = (long) FpXQ_sqr(x,T,p);
                    987:   for(i=4;i<l+2;i++)
                    988:     V[i] = (long) FpXQ_mul((GEN) V[i-1],x,T,p);
                    989: #if 0
                    990:   TODO: Karim proposes to use squaring:
                    991:   V[i] = (long) ((i&1)?FpXQ_sqr((GEN) V[(i+1)>>1],T,p)
                    992:                        :FpXQ_mul((GEN) V[i-1],x,T,p));
                    993:   Please profile it.
                    994: #endif
                    995:   return V;
                    996: }
                    997: #if 0
                    998: static long brent_kung_nbmul(long d, long n, long p)
                    999: {
                   1000:   return p+n*((d+p-1)/p);
                   1001: }
                   1002:   TODO: This the the optimal parameter for the purpose of reducing
                   1003:   multiplications, but profiling need to be done to ensure it is not slower
                   1004:   than the other option in practice
                   1005: /*Return optimal parameter l for the evaluation of n polynomials of degree d*/
                   1006: long brent_kung_optpow(long d, long n)
                   1007: {
                   1008:   double r;
                   1009:   long f,c,pr;
                   1010:   if (n>=d ) return d;
                   1011:   pr=n*d;
                   1012:   if (pr<=1) return 1;
                   1013:   r=d/sqrt(pr);
                   1014:   c=(long)ceil(d/ceil(r));
                   1015:   f=(long)floor(d/floor(r));
                   1016:   return (brent_kung_nbmul(d, n, c) <= brent_kung_nbmul(d, n, f))?c:f;
                   1017: }
                   1018: #endif
                   1019: /*Return optimal parameter l for the evaluation of n polynomials of degree d*/
                   1020: long brent_kung_optpow(long d, long n)
                   1021: {
                   1022:   double r;
                   1023:   long l,pr;
                   1024:   if (n>=d ) return d;
                   1025:   pr=n*d;
                   1026:   if (pr<=1) return 1;
                   1027:   r=d/sqrt(pr);
                   1028:   l=(long)r;
                   1029:   return (d+l-1)/l;
                   1030: }
                   1031:
1.2     ! noro     1032: /*Close to FpXV_FpV_innerprod*/
1.1       noro     1033:
                   1034: static GEN
                   1035: spec_compo_powers(GEN P, GEN V, long a, long n)
                   1036: {
                   1037:   long i;
                   1038:   GEN z;
                   1039:   z = scalarpol((GEN)P[2+a],varn(P));
                   1040:   for(i=1;i<=n;i++)
                   1041:     z=FpX_add(z,FpX_Fp_mul((GEN)V[i+1],(GEN)P[2+a+i],NULL),NULL);
                   1042:   return z;
                   1043: }
                   1044: /*Try to implement algorithm in Brent & Kung (Fast algorithms for
                   1045:  *manipulating formal power series, JACM 25:581-595, 1978)
                   1046:
                   1047:  V must be as output by FpXQ_powers.
                   1048:  For optimal performance, l (of FpXQ_powers) must be as output by
                   1049:  brent_kung_optpow
                   1050:  */
                   1051:
                   1052: GEN
                   1053: FpX_FpXQV_compo(GEN P, GEN V, GEN T, GEN p)
                   1054: {
1.2     ! noro     1055:   gpmem_t ltop=avma;
1.1       noro     1056:   long l=lg(V)-1;
                   1057:   GEN z,u;
                   1058:   long d=degpol(P),cnt=0;
                   1059:   if (d==-1) return zeropol(varn(T));
                   1060:   if (d<l)
                   1061:   {
                   1062:     z=spec_compo_powers(P,V,0,d);
                   1063:     return gerepileupto(ltop,FpX_red(z,p));
                   1064:   }
                   1065:   if (l<=1)
                   1066:     err(talker,"powers is only [] or [1] in FpX_FpXQV_compo");
                   1067:   z=spec_compo_powers(P,V,d-l+1,l-1);
                   1068:   d-=l;
                   1069:   while(d>=l-1)
                   1070:   {
                   1071:     u=spec_compo_powers(P,V,d-l+2,l-2);
                   1072:     z=FpX_add(u,FpXQ_mul(z,(GEN)V[l],T,p),NULL);
                   1073:     d-=l-1;
                   1074:     cnt++;
                   1075:   }
                   1076:   u=spec_compo_powers(P,V,0,d);
                   1077:   z=FpX_add(u,FpXQ_mul(z,(GEN)V[d+2],T,p),NULL);
                   1078:   cnt++;
                   1079:   if (DEBUGLEVEL>=8) fprintferr("FpX_FpXQV_compo: %d FpXQ_mul [%d]\n",cnt,l-1);
                   1080:   return gerepileupto(ltop,FpX_red(z,p));
                   1081: }
                   1082:
                   1083: /* T in Z[X] and  x in Z/pZ[X]/(pol)
                   1084:  * return lift(lift(subst(T,variable(T),Mod(x*Mod(1,p),pol*Mod(1,p)))));
                   1085:  */
                   1086: GEN
                   1087: FpX_FpXQ_compo(GEN T,GEN x,GEN pol,GEN p)
                   1088: {
1.2     ! noro     1089:   gpmem_t ltop=avma;
1.1       noro     1090:   GEN z;
                   1091:   long d=degpol(T),rtd;
                   1092:   if (!signe(T)) return zeropol(varn(T));
                   1093:   rtd = (long) sqrt((double)d);
                   1094:   z = FpX_FpXQV_compo(T,FpXQ_powers(x,rtd,pol,p),pol,p);
                   1095:   return gerepileupto(ltop,z);
                   1096: }
                   1097:
                   1098: /* Evaluation in Fp
                   1099:  * x in Z[X] and y in Z return x(y) mod p
                   1100:  *
                   1101:  * If p is very large (several longs) and x has small coefficients(<<p),
                   1102:  * then Brent & Kung algorithm is faster. */
                   1103: GEN
                   1104: FpX_eval(GEN x,GEN y,GEN p)
                   1105: {
1.2     ! noro     1106:   gpmem_t av;
1.1       noro     1107:   GEN p1,r,res;
                   1108:   long i,j;
                   1109:   i=lgef(x)-1;
                   1110:   if (i<=2)
                   1111:     return (i==2)? modii((GEN)x[2],p): gzero;
                   1112:   res=cgetg(lgefint(p),t_INT);
                   1113:   av=avma; p1=(GEN)x[i];
                   1114:   /* specific attention to sparse polynomials (see poleval)*/
                   1115:   /*You've guess it! It's a copy-paste(tm)*/
                   1116:   for (i--; i>=2; i=j-1)
                   1117:   {
                   1118:     for (j=i; !signe((GEN)x[j]); j--)
                   1119:       if (j==2)
                   1120:       {
1.2     ! noro     1121:        if (i!=j) y = powgumod(y,i-j+1,p);
1.1       noro     1122:        p1=mulii(p1,y);
                   1123:        goto fppoleval;/*sorry break(2) no implemented*/
                   1124:       }
1.2     ! noro     1125:     r = (i==j)? y: powgumod(y,i-j+1,p);
1.1       noro     1126:     p1 = modii(addii(mulii(p1,r), (GEN)x[j]),p);
                   1127:   }
                   1128:  fppoleval:
                   1129:   modiiz(p1,p,res);
                   1130:   avma=av;
                   1131:   return res;
                   1132: }
                   1133: /* Tz=Tx*Ty where Tx and Ty coprime
                   1134:  * return lift(chinese(Mod(x*Mod(1,p),Tx*Mod(1,p)),Mod(y*Mod(1,p),Ty*Mod(1,p))))
                   1135:  * if Tz is NULL it is computed
                   1136:  * As we do not return it, and the caller will frequently need it,
                   1137:  * it must compute it and pass it.
                   1138:  */
                   1139: GEN
                   1140: FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p)
                   1141: {
1.2     ! noro     1142:   gpmem_t av = avma;
1.1       noro     1143:   GEN ax,p1;
                   1144:   ax = FpX_mul(FpXQ_inv(Tx,Ty,p), Tx,p);
                   1145:   p1=FpX_mul(ax, FpX_sub(y,x,p),p);
                   1146:   p1 = FpX_add(x,p1,p);
                   1147:   if (!Tz) Tz=FpX_mul(Tx,Ty,p);
                   1148:   p1 = FpX_res(p1,Tz,p);
                   1149:   return gerepileupto(av,p1);
                   1150: }
                   1151:
1.2     ! noro     1152: typedef struct {
        !          1153:   GEN pol, p;
        !          1154: } FpX_muldata;
        !          1155: typedef struct {
        !          1156:   GEN pol;
        !          1157:   ulong p;
        !          1158: } u_FpX_muldata;
        !          1159:
        !          1160: static GEN
        !          1161: _u_sqr(void *data, GEN x)
        !          1162: {
        !          1163:   u_FpX_muldata *D = (u_FpX_muldata*)data;
        !          1164:   return u_FpXQ_sqr(x, D->pol, D->p);
        !          1165: }
        !          1166: static GEN
        !          1167: _u_mul(void *data, GEN x, GEN y)
        !          1168: {
        !          1169:   u_FpX_muldata *D = (u_FpX_muldata*)data;
        !          1170:   return u_FpXQ_mul(x,y, D->pol, D->p);
        !          1171: }
        !          1172: static GEN
        !          1173: _sqr(void *data, GEN x)
        !          1174: {
        !          1175:   FpX_muldata *D = (FpX_muldata*)data;
        !          1176:   return FpXQ_sqr(x, D->pol, D->p);
        !          1177: }
        !          1178: static GEN
        !          1179: _mul(void *data, GEN x, GEN y)
        !          1180: {
        !          1181:   FpX_muldata *D = (FpX_muldata*)data;
        !          1182:   return FpXQ_mul(x,y, D->pol, D->p);
        !          1183: }
        !          1184:
1.1       noro     1185: /* assume n > 0 */
                   1186: GEN
                   1187: u_FpXQ_pow(GEN x, GEN n, GEN pol, ulong p)
                   1188: {
1.2     ! noro     1189:   gpmem_t av = avma;
        !          1190:   u_FpX_muldata D;
        !          1191:   GEN y;
        !          1192:   D.pol = pol;
        !          1193:   D.p   = p;
        !          1194:   y = leftright_pow(x, n, (void*)&D, &_u_sqr, &_u_mul);
1.1       noro     1195:   return gerepileupto(av, y);
                   1196: }
                   1197:
                   1198: /* x,pol in Z[X], p in Z, n in Z, compute lift(x^n mod (p, pol)) */
                   1199: GEN
                   1200: FpXQ_pow(GEN x, GEN n, GEN pol, GEN p)
                   1201: {
1.2     ! noro     1202:   gpmem_t av = avma;
        !          1203:   FpX_muldata D;
        !          1204:   long vx = varn(x);
        !          1205:   GEN y;
1.1       noro     1206:   if (!signe(n)) return polun[vx];
                   1207:   if (signe(n) < 0)
                   1208:   {
                   1209:     x=FpXQ_inv(x,pol,p);
                   1210:     if (is_pm1(n)) return x; /* n = -1*/
                   1211:   }
                   1212:   else
                   1213:     if (is_pm1(n)) return gcopy(x); /* n = 1 */
                   1214:   if (OK_ULONG(p))
                   1215:   {
                   1216:     ulong pp = p[2];
1.2     ! noro     1217:     pol = u_Fp_FpX(pol, pp);
        !          1218:     x   = u_Fp_FpX(x,   pp);
1.1       noro     1219:     y = u_FpXQ_pow(x, n, pol, pp);
                   1220:     y = small_to_pol(y,vx);
                   1221:   }
                   1222:   else
                   1223:   {
                   1224:     av = avma;
1.2     ! noro     1225:     D.pol = pol;
        !          1226:     D.p   = p;
        !          1227:     y = leftright_pow(x, n, (void*)&D, &_sqr, &_mul);
1.1       noro     1228:   }
1.2     ! noro     1229:   return gerepileupto(av, y);
        !          1230: }
        !          1231:
        !          1232: GEN
        !          1233: Fq_pow(GEN x, GEN n, GEN pol, GEN p)
        !          1234: {
        !          1235:   if (typ(x) == t_INT) return powmodulo(x,n,p);
        !          1236:   return FpXQ_pow(x,n,pol,p);
1.1       noro     1237: }
                   1238:
                   1239: /*******************************************************************/
                   1240: /*                                                                 */
                   1241: /*                             Fp[X][Y]                            */
                   1242: /*                                                                 */
                   1243: /*******************************************************************/
                   1244: /*Polynomials whose coefficients are either polynomials or integers*/
                   1245:
                   1246: GEN
                   1247: FpXX_red(GEN z, GEN p)
                   1248: {
1.2     ! noro     1249:   GEN res;
        !          1250:   int i;
        !          1251:   res=cgetg(lgef(z),t_POL);
        !          1252:   res[1] = evalsigne(1) | evalvarn(varn(z)) | evallgef(lgef(z));
        !          1253:   for(i=2;i<lgef(res);i++)
        !          1254:     if (typ(z[i])!=t_INT)
        !          1255:     {
        !          1256:       gpmem_t av=avma;
        !          1257:       res[i]=(long)FpX_red((GEN)z[i],p);
        !          1258:       if (lgef(res[i])<=3)
1.1       noro     1259:       {
1.2     ! noro     1260:         if (lgef(res[i])==2) {avma=av;res[i]=zero;}
        !          1261:         else res[i]=lpilecopy(av,gmael(res,i,2));
1.1       noro     1262:       }
1.2     ! noro     1263:     }
        !          1264:     else
        !          1265:       res[i]=lmodii((GEN)z[i],p);
        !          1266:   res=normalizepol_i(res,lgef(res));
        !          1267:   return res;
1.1       noro     1268: }
                   1269:
                   1270: /*******************************************************************/
                   1271: /*                                                                 */
                   1272: /*                             (Fp[X]/(Q))[Y]                      */
                   1273: /*                                                                 */
                   1274: /*******************************************************************/
1.2     ! noro     1275: extern GEN to_Kronecker(GEN P, GEN Q);
1.1       noro     1276:
                   1277: /*Not malloc nor warn-clean.*/
1.2     ! noro     1278: GEN
        !          1279: FpXQX_from_Kronecker(GEN Z, GEN T, GEN p)
1.1       noro     1280: {
1.2     ! noro     1281:   long i,j,lx,l = lgef(Z), N = (degpol(T)<<1) + 1;
        !          1282:   GEN x, t = cgetg(N,t_POL), z = FpX_red(Z, p);
        !          1283:   t[1] = T[1] & VARNBITS;
        !          1284:   lx = (l-2) / (N-2);
        !          1285:   x = cgetg(lx+3,t_POL);
1.1       noro     1286:   for (i=2; i<lx+2; i++)
                   1287:   {
                   1288:     for (j=2; j<N; j++) t[j] = z[j];
                   1289:     z += (N-2);
1.2     ! noro     1290:     x[i] = (long)FpX_res(normalizepol_i(t,N), T,p);
1.1       noro     1291:   }
                   1292:   N = (l-2) % (N-2) + 2;
                   1293:   for (j=2; j<N; j++) t[j] = z[j];
1.2     ! noro     1294:   x[i] = (long)FpX_res(normalizepol_i(t,N), T,p);
1.1       noro     1295:   return normalizepol_i(x, i+1);
                   1296: }
1.2     ! noro     1297:
        !          1298: GEN
        !          1299: FpVQX_red(GEN z, GEN T, GEN p)
        !          1300: {
        !          1301:   GEN res;
        !          1302:   int i, l = lg(z);
        !          1303:   res=cgetg(l,typ(z));
        !          1304:   for(i=1;i<l;i++)
        !          1305:     if (typ(z[i]) != t_INT)
        !          1306:     {
        !          1307:       if (T)
        !          1308:         res[i]=(long)FpX_res((GEN)z[i],T,p);
        !          1309:       else
        !          1310:         res[i]=(long)FpX_red((GEN)z[i],p);
        !          1311:     }
        !          1312:     else
        !          1313:       res[i] = lmodii((GEN)z[i],p);
        !          1314:   return res;
        !          1315: }
1.1       noro     1316: GEN
                   1317: FpXQX_red(GEN z, GEN T, GEN p)
                   1318: {
                   1319:   GEN res;
1.2     ! noro     1320:   int i, l = lgef(z);
        !          1321:   res=cgetg(l,t_POL);
1.1       noro     1322:   res[1] = evalsigne(1) | evalvarn(varn(z)) | evallgef(lgef(z));
1.2     ! noro     1323:   for(i=2;i<l;i++)
        !          1324:     if (typ(z[i]) != t_INT)
1.1       noro     1325:     {
                   1326:       if (T)
                   1327:         res[i]=(long)FpX_res((GEN)z[i],T,p);
                   1328:       else
                   1329:         res[i]=(long)FpX_red((GEN)z[i],p);
                   1330:     }
                   1331:     else
                   1332:       res[i]=lmodii((GEN)z[i],p);
                   1333:   res=normalizepol_i(res,lgef(res));
                   1334:   return res;
                   1335: }
                   1336: /* if T = NULL, call FpX_mul */
                   1337: GEN
                   1338: FpXQX_mul(GEN x, GEN y, GEN T, GEN p)
                   1339: {
1.2     ! noro     1340:   gpmem_t ltop;
1.1       noro     1341:   GEN z,kx,ky;
                   1342:   long vx;
                   1343:   if (!T) return FpX_mul(x,y,p);
                   1344:   ltop = avma;
                   1345:   vx = min(varn(x),varn(y));
                   1346:   kx= to_Kronecker(x,T);
                   1347:   ky= to_Kronecker(y,T);
                   1348:   z = quickmul(ky+2, kx+2, lgef(ky)-2, lgef(kx)-2);
                   1349:   z = FpXQX_from_Kronecker(z,T,p);
                   1350:   setvarn(z,vx);/*quickmul and Fq_from_Kronecker are not varn-clean*/
                   1351:   return gerepileupto(ltop,z);
                   1352: }
                   1353: GEN/*Unused/untested*/
                   1354: FpXQX_sqr(GEN x, GEN T, GEN p)
                   1355: {
1.2     ! noro     1356:   gpmem_t ltop=avma;
1.1       noro     1357:   GEN z,kx;
                   1358:   long vx=varn(x);
                   1359:   kx= to_Kronecker(x,T);
                   1360:   z = quicksqr(kx+2, lgef(kx)-2);
                   1361:   z = FpXQX_from_Kronecker(z,T,p);
                   1362:   setvarn(z,vx);/*quickmul and Fq_from_Kronecker are nor varn-clean*/
                   1363:   return gerepileupto(ltop,z);
                   1364: }
1.2     ! noro     1365:
1.1       noro     1366: GEN
                   1367: FpXQX_FpXQ_mul(GEN P, GEN U, GEN T, GEN p)
                   1368: {
                   1369:   int i, lP = lgef(P);
                   1370:   GEN res = cgetg(lP,t_POL);
                   1371:   res[1] = evalsigne(1) | evalvarn(varn(P)) | evallgef(lP);
                   1372:   for(i=2; i<lP; i++)
1.2     ! noro     1373:     res[i] = (long)Fq_mul(U,(GEN)P[i], T,p);
1.1       noro     1374:   return normalizepol_i(res,lgef(res));
                   1375: }
                   1376:
                   1377: /* a X^degpol, assume degpol >= 0 */
                   1378: static GEN
                   1379: monomial(GEN a, int degpol, int v)
                   1380: {
                   1381:   long i, lP = degpol+3;
                   1382:   GEN P = cgetg(lP, t_POL);
                   1383:   P[1] = evalsigne(1) | evalvarn(v) | evallgef(lP);
                   1384:   lP--; P[lP] = (long)a;
                   1385:   for (i=2; i<lP; i++) P[i] = zero;
                   1386:   return P;
                   1387: }
                   1388:
                   1389: /* return NULL if Euclidean remainder sequence fails (==> T reducible mod p)
                   1390:  * last non-zero remainder otherwise */
                   1391: GEN
                   1392: FpXQX_safegcd(GEN P, GEN Q, GEN T, GEN p)
                   1393: {
1.2     ! noro     1394:   gpmem_t btop, ltop = avma, st_lim;
1.1       noro     1395:   long dg, vx = varn(P);
                   1396:   GEN U, q;
1.2     ! noro     1397:   P = FpXX_red(P, p); btop = avma;
1.1       noro     1398:   Q = FpXX_red(Q, p);
                   1399:   if (!signe(P)) return gerepileupto(ltop, Q);
1.2     ! noro     1400:   if (!signe(Q)) { avma = btop; return P; }
1.1       noro     1401:   T = FpX_red(T, p);
                   1402:
                   1403:   btop = avma; st_lim = stack_lim(btop, 1);
                   1404:   dg = lgef(P)-lgef(Q);
                   1405:   if (dg < 0) { swap(P, Q); dg = -dg; }
                   1406:   for(;;)
                   1407:   {
                   1408:     U = FpXQ_invsafe(leading_term(Q), T, p);
                   1409:     if (!U) { avma = ltop; return NULL; }
                   1410:     do /* set P := P % Q */
                   1411:     {
1.2     ! noro     1412:       q = Fq_mul(U, gneg(leading_term(P)), T, p);
1.1       noro     1413:       P = gadd(P, FpXQX_mul(monomial(q, dg, vx), Q, T, p));
                   1414:       P = FpXQX_red(P, T, p); /* wasteful, but negligible */
                   1415:       dg = lgef(P)-lgef(Q);
                   1416:     } while (dg >= 0);
                   1417:     if (!signe(P)) break;
                   1418:
                   1419:     if (low_stack(st_lim, stack_lim(btop, 1)))
                   1420:     {
                   1421:       GEN *bptr[2]; bptr[0]=&P; bptr[1]=&Q;
                   1422:       if (DEBUGLEVEL>1) err(warnmem,"FpXQX_safegcd");
                   1423:       gerepilemany(btop, bptr, 2);
                   1424:     }
                   1425:     swap(P, Q); dg = -dg;
                   1426:   }
                   1427:   Q = FpXQX_FpXQ_mul(Q, U, T, p); /* normalize GCD */
                   1428:   return gerepileupto(ltop, Q);
                   1429: }
                   1430:
                   1431: /*******************************************************************/
                   1432: /*                                                                 */
1.2     ! noro     1433: /*                       (Fp[X]/T(X))[Y] / S(Y)                    */
        !          1434: /*                                                                 */
        !          1435: /*******************************************************************/
        !          1436: /* TODO: merge these 2 (I don't understand the first one) -- KB */
        !          1437:
        !          1438: /*Preliminary implementation to speed up Fp_isom*/
        !          1439: typedef struct {
        !          1440:   GEN S, T, p;
        !          1441: } FpXQYQ_muldata;
        !          1442:
        !          1443: static GEN
        !          1444: FpXQYQ_redswap(GEN x, GEN S, GEN T, GEN p)
        !          1445: {
        !          1446:   gpmem_t ltop=avma;
        !          1447:   long n=degpol(S);
        !          1448:   long m=degpol(T);
        !          1449:   long v=varn(T),w=varn(S);
        !          1450:   GEN V = swap_polpol(x,n,w);
        !          1451:   setvarn(T,w);
        !          1452:   V = FpXQX_red(V,T,p);
        !          1453:   setvarn(T,v);
        !          1454:   V = swap_polpol(V,m,w);
        !          1455:   return gerepilecopy(ltop,V);
        !          1456: }
        !          1457: static GEN
        !          1458: FpXQYQ_sqr(void *data, GEN x)
        !          1459: {
        !          1460:   FpXQYQ_muldata *D = (FpXQYQ_muldata*)data;
        !          1461:   return FpXQYQ_redswap(FpXQX_sqr(x, D->S, D->p),D->S,D->T,D->p);
        !          1462:
        !          1463: }
        !          1464: static GEN
        !          1465: FpXQYQ_mul(void *data, GEN x, GEN y)
        !          1466: {
        !          1467:   FpXQYQ_muldata *D = (FpXQYQ_muldata*)data;
        !          1468:   return FpXQYQ_redswap(FpXQX_mul(x,y, D->S, D->p),D->S,D->T,D->p);
        !          1469: }
        !          1470:
        !          1471: /* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */
        !          1472: GEN
        !          1473: FpXQYQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)
        !          1474: {
        !          1475:   gpmem_t av = avma;
        !          1476:   FpXQYQ_muldata D;
        !          1477:   GEN y;
        !          1478:   D.S = S;
        !          1479:   D.T = T;
        !          1480:   D.p = p;
        !          1481:   y = leftright_pow(x, n, (void*)&D, &FpXQYQ_sqr, &FpXQYQ_mul);
        !          1482:   return gerepileupto(av, y);
        !          1483: }
        !          1484:
        !          1485: typedef struct {
        !          1486:   GEN T, p, S;
        !          1487:   long v;
        !          1488: } kronecker_muldata;
        !          1489:
        !          1490: static GEN
        !          1491: _FqXQ_red(void *data, GEN x)
        !          1492: {
        !          1493:   kronecker_muldata *D = (kronecker_muldata*)data;
        !          1494:   GEN t = FpXQX_from_Kronecker(x, D->T,D->p);
        !          1495:   setvarn(t, D->v);
        !          1496:   t = FpXQX_divres(t, D->S,D->T,D->p, ONLY_REM);
        !          1497:   return to_Kronecker(t,D->T);
        !          1498: }
        !          1499: static GEN
        !          1500: _FqXQ_mul(void *data, GEN x, GEN y) {
        !          1501:   return _FqXQ_red(data, FpX_mul(x,y,NULL));
        !          1502: }
        !          1503: static GEN
        !          1504: _FqXQ_sqr(void *data, GEN x) {
        !          1505:   return _FqXQ_red(data, FpX_sqr(x,NULL));
        !          1506: }
        !          1507:
        !          1508: /* x over Fq, return lift(x^n) mod S */
        !          1509: GEN
        !          1510: FqXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)
        !          1511: {
        !          1512:   gpmem_t av0 = avma;
        !          1513:   long v = varn(x);
        !          1514:   GEN y;
        !          1515:   kronecker_muldata D;
        !          1516:
        !          1517:   x = to_Kronecker(x,T);
        !          1518:   D.S = S;
        !          1519:   D.T = T;
        !          1520:   D.p = p;
        !          1521:   D.v = v;
        !          1522:   y = leftright_pow(x, n, (void*)&D, &_FqXQ_sqr, &_FqXQ_mul);
        !          1523:   y = FpXQX_from_Kronecker(y, T,p);
        !          1524:   setvarn(y, v); return gerepileupto(av0, y);
        !          1525: }
        !          1526: /*******************************************************************/
        !          1527: /*                                                                 */
1.1       noro     1528: /*                             Fq[X]                               */
                   1529: /*                                                                 */
                   1530: /*******************************************************************/
                   1531:
                   1532: /*Well nothing, for now. So we reuse FpXQX*/
                   1533: #define FqX_mul FpXQX_mul
                   1534: #define FqX_sqr FpXQX_sqr
                   1535: #define FqX_red FpXQX_red
                   1536: static GEN
1.2     ! noro     1537: Fq_neg(GEN x, GEN T/*unused*/, GEN p)
1.1       noro     1538: {
                   1539:   switch(typ(x)==t_POL)
                   1540:   {
                   1541:     case 0: return signe(x)?subii(p,x):gzero;
                   1542:     case 1: return FpX_neg(x,p);
                   1543:   }
                   1544:   return NULL;
                   1545: }
                   1546: static GEN modulo,Tmodulo;
                   1547: static GEN fgmul(GEN a,GEN b){return FqX_mul(a,b,Tmodulo,modulo);}
                   1548: GEN
                   1549: FqV_roots_to_pol(GEN V, GEN Tp, GEN p, long v)
                   1550: {
1.2     ! noro     1551:   gpmem_t ltop=avma;
1.1       noro     1552:   long k;
                   1553:   GEN W=cgetg(lg(V),t_VEC);
                   1554:   for(k=1;k<lg(V);k++)
                   1555:     W[k]=(long)deg1pol(gun,Fq_neg((GEN)V[k],Tp,p),v);
                   1556:   modulo=p;Tmodulo=Tp;
                   1557:   W=divide_conquer_prod(W,&fgmul);
                   1558:   return gerepileupto(ltop,W);
                   1559: }
                   1560:
                   1561: /*******************************************************************/
                   1562: /*                                                                 */
                   1563: /*                       n-th ROOT in Fq                           */
                   1564: /*                                                                 */
                   1565: /*******************************************************************/
                   1566: /*NO clean malloc*/
                   1567: static GEN fflgen(GEN l, long e, GEN r, GEN T ,GEN p, GEN *zeta)
                   1568: {
1.2     ! noro     1569:   gpmem_t av1 = avma;
        !          1570:   GEN z, m, m1;
        !          1571:   const long pp = is_bigint(p)? VERYBIGINT: itos(p);
        !          1572:   long x=varn(T),k,u,v,i;
        !          1573:
        !          1574:   for (k=0; ; k++)
        !          1575:   {
        !          1576:     z = (degpol(T)==1)? polun[x]: polx[x];
        !          1577:     u = k/pp; v=2; /* FpX_Fp_add modify y */
        !          1578:     z = gaddgs(z, k%pp);
        !          1579:     while(u)
1.1       noro     1580:     {
1.2     ! noro     1581:       z = FpX_add(z, monomial(stoi(u%pp),v,x), NULL);
        !          1582:       u /= pp; v++;
1.1       noro     1583:     }
1.2     ! noro     1584:     if ( DEBUGLEVEL>=6 ) fprintferr("FF l-Gen:next %Z\n",z);
1.1       noro     1585:     m1 = m = FpXQ_pow(z,r,T,p);
1.2     ! noro     1586:     if (gcmp1(m)) { avma = av1; continue; }
        !          1587:
1.1       noro     1588:     for (i=1; i<e; i++)
1.2     ! noro     1589:       if (gcmp1(m = FpXQ_pow(m,l,T,p))) break;
1.1       noro     1590:     if (i==e) break;
                   1591:     avma = av1;
                   1592:   }
1.2     ! noro     1593:   *zeta = m; return m1;
1.1       noro     1594: }
1.2     ! noro     1595: /* Solve x^l = a mod (p,T)
        !          1596:  * l must be prime
        !          1597:  * q = p^degpol(T)-1 = (l^e)*r, with e>=1 and pgcd(r,l)=1
        !          1598:  * m = y^(q/l)
        !          1599:  * y not an l-th power [ m != 1 ] */
1.1       noro     1600: GEN
                   1601: ffsqrtlmod(GEN a, GEN l, GEN T ,GEN p , GEN q, long e, GEN r, GEN y, GEN m)
                   1602: {
1.2     ! noro     1603:   gpmem_t av = avma, lim;
1.1       noro     1604:   long i,k;
                   1605:   GEN p1,p2,u1,u2,v,w,z;
                   1606:
1.2     ! noro     1607:   if (gcmp1(a)) return gcopy(a);
        !          1608:
        !          1609:   (void)bezout(r,l,&u1,&u2); /* result is 1 */
        !          1610:   v = FpXQ_pow(a,u2,T,p);
        !          1611:   w = FpXQ_pow(a, modii(mulii(negi(u1),r),q), T,p);
1.1       noro     1612:   lim = stack_lim(av,1);
                   1613:   while (!gcmp1(w))
                   1614:   {
1.2     ! noro     1615:     k = 0;
        !          1616:     p1 = w;
        !          1617:     do { /* if p is not prime, loop will not end */
        !          1618:       z = p1;
        !          1619:       p1 = FpXQ_pow(p1,l,T,p);
1.1       noro     1620:       k++;
1.2     ! noro     1621:     } while (!gcmp1(p1));
1.1       noro     1622:     if (k==e) { avma=av; return NULL; }
                   1623:     p2 = FpXQ_mul(z,m,T,p);
1.2     ! noro     1624:     for (i=1; !gcmp1(p2); i++) p2 = FpXQ_mul(p2,m,T,p);/*TODO: BS/GS instead*/
        !          1625:     p1= FpXQ_pow(y, modii(mulsi(i,gpowgs(l,e-k-1)), q), T,p);
1.1       noro     1626:     m = FpXQ_pow(m,stoi(i),T,p);
                   1627:     e = k;
                   1628:     v = FpXQ_mul(p1,v,T,p);
                   1629:     y = FpXQ_pow(p1,l,T,p);
                   1630:     w = FpXQ_mul(y,w,T,p);
                   1631:     if (low_stack(lim, stack_lim(av,1)))
                   1632:     {
                   1633:       if(DEBUGMEM>1) err(warnmem,"ffsqrtlmod");
1.2     ! noro     1634:       gerepileall(av,4, &y,&v,&w,&m);
1.1       noro     1635:     }
                   1636:   }
1.2     ! noro     1637:   return gerepilecopy(av, v);
1.1       noro     1638: }
1.2     ! noro     1639: /* Solve x^n = a mod p: n integer, a in Fp[X]/(T) [ p prime, T irred. mod p ]
        !          1640:  *
        !          1641:  * 1) if no solution, return NULL and (if zetan != NULL) set zetan to gzero.
        !          1642:  *
        !          1643:  * 2) If there is a solution, there are exactly  m=gcd(p-1,n) of them.
        !          1644:  * If zetan != NULL, it is set to a primitive mth root of unity so that the set
        !          1645:  * of solutions is {x*zetan^k;k=0 to m-1}
        !          1646:  *
        !          1647:  * If a = 0, return 0 and (if zetan != NULL) set zetan = gun */
1.1       noro     1648: GEN ffsqrtnmod(GEN a, GEN n, GEN T, GEN p, GEN *zetan)
                   1649: {
1.2     ! noro     1650:   gpmem_t ltop=avma, av1, lim;
1.1       noro     1651:   long i,j,e;
                   1652:   GEN m,u1,u2;
                   1653:   GEN q,r,zeta,y,l,z;
1.2     ! noro     1654:
1.1       noro     1655:   if (typ(a) != t_POL || typ(n) != t_INT || typ(T) != t_POL || typ(p)!=t_INT)
                   1656:     err(typeer,"ffsqrtnmod");
1.2     ! noro     1657:   if (!degpol(T)) err(constpoler,"ffsqrtnmod");
        !          1658:   if (!signe(n)) err(talker,"1/0 exponent in ffsqrtnmod");
        !          1659:   if (gcmp1(n)) {if (zetan) *zetan=gun;return gcopy(a);}
        !          1660:   if (gcmp0(a)) {if (zetan) *zetan=gun;return gzero;}
        !          1661:
        !          1662:   q = addsi(-1, gpowgs(p,degpol(T)));
        !          1663:   m = bezout(n,q,&u1,&u2);
        !          1664:   if (!egalii(m,n)) a = FpXQ_pow(a, modii(u1,q), T,p);
        !          1665:   if (zetan) z = polun[varn(T)];
        !          1666:   lim = stack_lim(ltop,1);
1.1       noro     1667:   if (!gcmp1(m))
                   1668:   {
1.2     ! noro     1669:     m = decomp(m); av1 = avma;
1.1       noro     1670:     for (i = lg(m[1])-1; i; i--)
                   1671:     {
1.2     ! noro     1672:       l = gcoeff(m,i,1);
        !          1673:       j = itos(gcoeff(m,i,2));
        !          1674:       e = pvaluation(q,l,&r);
        !          1675:       if(DEBUGLEVEL>=6) (void)timer2();
        !          1676:       y = fflgen(l,e,r,T,p,&zeta);
        !          1677:       if(DEBUGLEVEL>=6) msgtimer("fflgen");
        !          1678:       if (zetan) z = FpXQ_mul(z, FpXQ_pow(y,gpowgs(l,e-j),T,p), T,p);
        !          1679:       for (; j; j--)
1.1       noro     1680:       {
1.2     ! noro     1681:        a = ffsqrtlmod(a,l,T,p,q,e,r,y,zeta);
        !          1682:        if (!a) {avma=ltop; return NULL;}
        !          1683:       }
1.1       noro     1684:       if (low_stack(lim, stack_lim(ltop,1)))
1.2     ! noro     1685:       { /* n can have lots of prime factors */
1.1       noro     1686:        if(DEBUGMEM>1) err(warnmem,"ffsqrtnmod");
1.2     ! noro     1687:         gerepileall(av1,zetan? 2: 1, &a,&z);
1.1       noro     1688:       }
                   1689:     }
                   1690:   }
                   1691:   if (zetan)
                   1692:   {
1.2     ! noro     1693:     *zetan = z;
        !          1694:     gerepileall(ltop,2,&a,zetan);
1.1       noro     1695:   }
                   1696:   else
1.2     ! noro     1697:     a = gerepileupto(ltop, a);
1.1       noro     1698:   return a;
                   1699: }
                   1700: /*******************************************************************/
                   1701: /*  Isomorphisms between finite fields                             */
                   1702: /*                                                                 */
                   1703: /*******************************************************************/
                   1704: GEN
                   1705: matrixpow(long n, long m, GEN y, GEN P,GEN l)
                   1706: {
                   1707:   return vecpol_to_mat(FpXQ_powers(y,m-1,P,l),n);
                   1708: }
                   1709: /* compute the reciprocical isomorphism of S mod T,p, i.e. V such that
                   1710:    V(S)=X  mod T,p*/
                   1711: GEN
                   1712: Fp_inv_isom(GEN S,GEN T, GEN p)
                   1713: {
1.2     ! noro     1714:   gpmem_t lbot, ltop = avma;
1.1       noro     1715:   GEN     M, V;
                   1716:   int     n, i;
                   1717:   long    x;
                   1718:   x = varn(T);
                   1719:   n = degpol(T);
                   1720:   M = matrixpow(n,n,S,T,p);
                   1721:   V = cgetg(n + 1, t_COL);
                   1722:   for (i = 1; i <= n; i++)
                   1723:     V[i] = zero;
                   1724:   V[2] = un;
                   1725:   V = FpM_invimage(M,V,p);
                   1726:   lbot = avma;
                   1727:   V = gtopolyrev(V, x);
                   1728:   return gerepile(ltop, lbot, V);
                   1729: }
1.2     ! noro     1730:
        !          1731: /* Let M the matrix of the x^p Frobenius automorphism.
        !          1732:  * Compute x^(p^i) for i=0..r
1.1       noro     1733:  */
                   1734: static GEN
                   1735: polfrobenius(GEN M, GEN p, long r, long v)
                   1736: {
                   1737:   GEN V,W;
                   1738:   long i;
                   1739:   V = cgetg(r+2,t_VEC);
                   1740:   V[1] = (long) polx[v];
                   1741:   if (r == 0) return V;
1.2     ! noro     1742:   V[2] = (long) vec_to_pol((GEN)M[2],v);
1.1       noro     1743:   W = (GEN) M[2];
                   1744:   for (i = 3; i <= r+1; ++i)
                   1745:   {
                   1746:     W = FpM_FpV_mul(M,W,p);
1.2     ! noro     1747:     V[i] = (long) vec_to_pol(W,v);
1.1       noro     1748:   }
                   1749:   return V;
                   1750: }
                   1751:
1.2     ! noro     1752: /* Let P a polynomial != 0 and M the matrix of the x^p Frobenius automorphism in
        !          1753:  * FFp[X]/T. Compute P(M)
        !          1754:  * V=polfrobenius(M, p, degpol(P), v)
        !          1755:  * not stack clean
        !          1756:  */
        !          1757:
1.1       noro     1758: static GEN
                   1759: matpolfrobenius(GEN V, GEN P, GEN T, GEN p)
                   1760: {
1.2     ! noro     1761:   gpmem_t btop;
1.1       noro     1762:   long i;
                   1763:   long l=degpol(T);
                   1764:   long v=varn(T);
1.2     ! noro     1765:   GEN M,W,Mi;
1.1       noro     1766:   GEN PV=gtovec(P);
1.2     ! noro     1767:   GEN *gptr[2];
        !          1768:   long lV=lg(V);
1.1       noro     1769:   PV=cgetg(degpol(P)+2,t_VEC);
                   1770:   for(i=1;i<lg(PV);i++)
                   1771:     PV[i]=P[1+i];
                   1772:   M=cgetg(l+1,t_VEC);
                   1773:   M[1]=(long)scalarpol(poleval(P,gun),v);
1.2     ! noro     1774:   M[2]=(long)FpXV_FpV_innerprod(V,PV,p);
        !          1775:   btop=avma;
        !          1776:   gptr[0]=&Mi;
        !          1777:   gptr[1]=&W;
        !          1778:   W=cgetg(lV,t_VEC);
        !          1779:   for(i=1;i<lV;i++)
1.1       noro     1780:      W[i]=V[i];
                   1781:   for(i=3;i<=l;i++)
                   1782:   {
                   1783:     long j;
1.2     ! noro     1784:     gpmem_t bbot;
        !          1785:     GEN W2=cgetg(lV,t_VEC);
        !          1786:     for(j=1;j<lV;j++)
        !          1787:       W2[j]=(long)FpXQ_mul((GEN)W[j],(GEN)V[j],T,p);
        !          1788:     bbot=avma;
        !          1789:     Mi=FpXV_FpV_innerprod(W2,PV,p);
        !          1790:     W=gcopy(W2);
        !          1791:     gerepilemanysp(btop,bbot,gptr,2);
        !          1792:     btop=(gpmem_t)W;
        !          1793:     M[i]=(long)Mi;
1.1       noro     1794:   }
                   1795:   return vecpol_to_mat(M,l);
                   1796: }
                   1797:
1.2     ! noro     1798: /* Let M the matrix of the Frobenius automorphism of Fp[X]/(T).
        !          1799:  * Compute M^d
        !          1800:  * TODO: use left-right binary (tricky!)
        !          1801:  */
        !          1802: GEN
        !          1803: FpM_frobenius_pow(GEN M, long d, GEN T, GEN p)
        !          1804: {
        !          1805:   gpmem_t ltop=avma;
        !          1806:   long i,l=degpol(T);
        !          1807:   GEN R, W = (GEN) M[2];
        !          1808:   for (i = 2; i <= d; ++i)
        !          1809:     W = FpM_FpV_mul(M,W,p);
        !          1810:   R=matrixpow(l,l,vec_to_pol(W,varn(T)),T,p);
        !          1811:   return gerepilecopy(ltop,R);
        !          1812: }
        !          1813:
1.1       noro     1814: /* Essentially we want to compute
1.2     ! noro     1815:  * FqM_ker(MA-polx[MAXVARN],U,l)
1.1       noro     1816:  * To avoid use of matrix in Fq we procede as follows:
1.2     ! noro     1817:  * We compute FpM_ker(U(MA),l) and then we recover
1.1       noro     1818:  * the eigen value by Galois action, see formula.
                   1819:  */
                   1820: static GEN
1.2     ! noro     1821: intersect_ker(GEN P, GEN MA, GEN U, GEN l)
1.1       noro     1822: {
1.2     ! noro     1823:   gpmem_t ltop=avma;
1.1       noro     1824:   long vp=varn(P);
1.2     ! noro     1825:   long vu=varn(U), r=degpol(U);
1.1       noro     1826:   long i;
                   1827:   GEN A, R, M, ib0, V;
1.2     ! noro     1828:   if (DEBUGLEVEL>=4) (void)timer2();
        !          1829:   V=polfrobenius(MA,l,r,vu);
1.1       noro     1830:   if (DEBUGLEVEL>=4) msgtimer("pol[frobenius]");
1.2     ! noro     1831:   M=matpolfrobenius(V,U,P,l);
1.1       noro     1832:   if (DEBUGLEVEL>=4) msgtimer("matrix cyclo");
                   1833:   A=FpM_ker(M,l);
                   1834:   if (DEBUGLEVEL>=4) msgtimer("kernel");
                   1835:   A=gerepileupto(ltop,A);
                   1836:   if (lg(A)!=r+1)
                   1837:     err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1838:        ,l,polx[vp],P);
                   1839:   /*The formula is
                   1840:    * a_{r-1}=-\phi(a_0)/b_0
                   1841:    * a_{i-1}=\phi(a_i)+b_ia_{r-1}  i=r-1 to 1
                   1842:    * Where a_0=A[1] and b_i=U[i+2]
                   1843:    */
1.2     ! noro     1844:   ib0=negi(mpinvmod((GEN)U[2],l));
1.1       noro     1845:   R=cgetg(r+1,t_MAT);
                   1846:   R[1]=A[1];
                   1847:   R[r]=(long)FpM_FpV_mul(MA,gmul((GEN)A[1],ib0),l);
                   1848:   for(i=r-1;i>1;i--)
                   1849:     R[i]=(long)FpV_red(gadd(FpM_FpV_mul(MA,(GEN)R[i+1],l),
1.2     ! noro     1850:          gmul((GEN)U[i+2],(GEN)R[r])),l);
1.1       noro     1851:   R=gtrans_i(R);
                   1852:   for(i=1;i<lg(R);i++)
1.2     ! noro     1853:     R[i]=(long)vec_to_pol((GEN)R[i],vu);
1.1       noro     1854:   A=gtopolyrev(R,vp);
                   1855:   return gerepileupto(ltop,A);
                   1856: }
                   1857:
                   1858: /* n must divide both the degree of P and Q.  Compute SP and SQ such
                   1859:   that the subfield of FF_l[X]/(P) generated by SP and the subfield of
                   1860:   FF_l[X]/(Q) generated by SQ are isomorphic of degree n.  P and Q do
                   1861:   not need to be of the same variable.  if MA (resp. MB) is not NULL,
                   1862:   must be the matrix of the frobenius map in FF_l[X]/(P) (resp.
                   1863:   FF_l[X]/(Q) ).  */
                   1864: /* Note on the implementation choice:
                   1865:  * We assume the prime p is very large
                   1866:  * so we handle Frobenius as matrices.
                   1867:  */
                   1868: void
                   1869: Fp_intersect(long n, GEN P, GEN Q, GEN l,GEN *SP, GEN *SQ, GEN MA, GEN MB)
                   1870: {
1.2     ! noro     1871:   gpmem_t lbot, ltop=avma;
1.1       noro     1872:   long vp,vq,np,nq,e,pg;
                   1873:   GEN q;
                   1874:   GEN A,B,Ap,Bp;
                   1875:   GEN *gptr[2];
                   1876:   vp=varn(P);vq=varn(Q);
                   1877:   np=degpol(P);nq=degpol(Q);
                   1878:   if (np<=0 || nq<=0 || n<=0 || np%n!=0 || nq%n!=0)
                   1879:     err(talker,"bad degrees in Fp_intersect: %d,%d,%d",n,degpol(P),degpol(Q));
                   1880:   e=pvaluation(stoi(n),l,&q);
                   1881:   pg=itos(q);
                   1882:   avma=ltop;
                   1883:   if(!MA) MA=matrixpow(np,np,FpXQ_pow(polx[vp],l,P,l),P,l);
                   1884:   if(!MB) MB=matrixpow(nq,nq,FpXQ_pow(polx[vq],l,Q,l),Q,l);
                   1885:   A=Ap=zeropol(vp);
                   1886:   B=Bp=zeropol(vq);
1.2     ! noro     1887:   if (pg > 1)
1.1       noro     1888:   {
1.2     ! noro     1889:     if (smodis(l,pg) == 1)
1.1       noro     1890:       /*We do not need to use relative extension in this setting, so
                   1891:         we don't. (Well,now that we don't in the other case also, it is more
                   1892:        dubious to treat cases apart...)*/
                   1893:     {
                   1894:       GEN L,An,Bn,ipg,z;
                   1895:       z=rootmod(cyclo(pg,-1),l);
                   1896:       if (lg(z)<2) err(talker,"%Z is not a prime in Fp_intersect",l);
                   1897:       z=negi(lift((GEN)z[1]));
                   1898:       ipg=stoi(pg);
1.2     ! noro     1899:       if (DEBUGLEVEL>=4) (void)timer2();
1.1       noro     1900:       A=FpM_ker(gaddmat(z, MA),l);
                   1901:       if (lg(A)!=2)
                   1902:        err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1903:            ,l,polx[vp],P);
1.2     ! noro     1904:       A=vec_to_pol((GEN)A[1],vp);
1.1       noro     1905:       B=FpM_ker(gaddmat(z, MB),l);
                   1906:       if (lg(B)!=2)
                   1907:        err(talker,"ZZ_%Z[%Z]/(%Z) is not a field in Fp_intersect"
                   1908:            ,l,polx[vq],Q);
1.2     ! noro     1909:       B=vec_to_pol((GEN)B[1],vq);
1.1       noro     1910:       if (DEBUGLEVEL>=4) msgtimer("FpM_ker");
                   1911:       An=(GEN) FpXQ_pow(A,ipg,P,l)[2];
                   1912:       Bn=(GEN) FpXQ_pow(B,ipg,Q,l)[2];
1.2     ! noro     1913:       if (!invmod(Bn,l,&z))
        !          1914:         err(talker,"Polynomials not irreducible in Fp_intersect");
        !          1915:       z=modii(mulii(An,z),l);
1.1       noro     1916:       L=mpsqrtnmod(z,ipg,l,NULL);
                   1917:       if ( !L )
                   1918:         err(talker,"Polynomials not irreducible in Fp_intersect");
                   1919:       if (DEBUGLEVEL>=4) msgtimer("mpsqrtnmod");
                   1920:       B=FpX_Fp_mul(B,L,l);
                   1921:     }
                   1922:     else
                   1923:     {
1.2     ! noro     1924:       GEN L,An,Bn,ipg,U,z;
        !          1925:       U=lift(gmael(factmod(cyclo(pg,MAXVARN),l),1,1));
1.1       noro     1926:       ipg=stoi(pg);
1.2     ! noro     1927:       A=intersect_ker(P, MA, U, l);
        !          1928:       B=intersect_ker(Q, MB, U, l);
        !          1929:       if (DEBUGLEVEL>=4) (void)timer2();
        !          1930:       An=(GEN) FpXQYQ_pow(A,stoi(pg),U,P,l)[2];
        !          1931:       Bn=(GEN) FpXQYQ_pow(B,stoi(pg),U,Q,l)[2];
1.1       noro     1932:       if (DEBUGLEVEL>=4) msgtimer("pows [P,Q]");
1.2     ! noro     1933:       z=FpXQ_inv(Bn,U,l);
        !          1934:       z=FpXQ_mul(An,z,U,l);
        !          1935:       L=ffsqrtnmod(z,ipg,U,l,NULL);
1.1       noro     1936:       if (DEBUGLEVEL>=4) msgtimer("ffsqrtn");
                   1937:       if ( !L )
                   1938:         err(talker,"Polynomials not irreducible in Fp_intersect");
1.2     ! noro     1939:       B=FpXQX_FpXQ_mul(B,L,U,l);
        !          1940:       B=gsubst(B,MAXVARN,gzero);
        !          1941:       A=gsubst(A,MAXVARN,gzero);
1.1       noro     1942:     }
                   1943:   }
                   1944:   if (e!=0)
                   1945:   {
                   1946:     GEN VP,VQ,moinsun,Ay,By,lmun;
                   1947:     int i,j;
                   1948:     moinsun=stoi(-1);
                   1949:     lmun=addis(l,-1);
                   1950:     MA=gaddmat(moinsun,MA);
                   1951:     MB=gaddmat(moinsun,MB);
                   1952:     Ay=polun[vp];
                   1953:     By=polun[vq];
                   1954:     VP=cgetg(np+1,t_COL);
                   1955:     VP[1]=un;
                   1956:     for(i=2;i<=np;i++) VP[i]=zero;
                   1957:     if (np==nq) VQ=VP;/*save memory*/
                   1958:     else
                   1959:     {
                   1960:       VQ=cgetg(nq+1,t_COL);
                   1961:       VQ[1]=un;
                   1962:       for(i=2;i<=nq;i++) VQ[i]=zero;
                   1963:     }
                   1964:     for(j=0;j<e;j++)
                   1965:     {
                   1966:       if (j)
                   1967:       {
                   1968:        Ay=FpXQ_mul(Ay,FpXQ_pow(Ap,lmun,P,l),P,l);
                   1969:        for(i=1;i<lgef(Ay)-1;i++) VP[i]=Ay[i+1];
                   1970:        for(;i<=np;i++) VP[i]=zero;
                   1971:       }
                   1972:       Ap=FpM_invimage(MA,VP,l);
1.2     ! noro     1973:       Ap=vec_to_pol(Ap,vp);
1.1       noro     1974:       if (j)
                   1975:       {
                   1976:        By=FpXQ_mul(By,FpXQ_pow(Bp,lmun,Q,l),Q,l);
                   1977:        for(i=1;i<lgef(By)-1;i++) VQ[i]=By[i+1];
                   1978:        for(;i<=nq;i++) VQ[i]=zero;
                   1979:       }
                   1980:       Bp=FpM_invimage(MB,VQ,l);
1.2     ! noro     1981:       Bp=vec_to_pol(Bp,vq);
1.1       noro     1982:       if (DEBUGLEVEL>=4) msgtimer("FpM_invimage");
                   1983:     }
                   1984:   }/*FpX_add is not clean, so we must do it *before* lbot=avma*/
                   1985:   A=FpX_add(A,Ap,NULL);
                   1986:   B=FpX_add(B,Bp,NULL);
                   1987:   lbot=avma;
                   1988:   *SP=FpX_red(A,l);
                   1989:   *SQ=FpX_red(B,l);
                   1990:   gptr[0]=SP;gptr[1]=SQ;
                   1991:   gerepilemanysp(ltop,lbot,gptr,2);
                   1992: }
                   1993: /* Let l be a prime number, P, Q in ZZ[X].  P and Q are both
                   1994:  * irreducible modulo l and degree(P) divides degree(Q).  Output a
                   1995:  * monomorphism between FF_l[X]/(P) and FF_l[X]/(Q) as a polynomial R such
                   1996:  * that Q | P(R) mod l.  If P and Q have the same degree, it is of course an
                   1997:  * isomorphism.  */
                   1998: GEN Fp_isom(GEN P,GEN Q,GEN l)
                   1999: {
1.2     ! noro     2000:   gpmem_t ltop=avma;
1.1       noro     2001:   GEN SP,SQ,R;
                   2002:   Fp_intersect(degpol(P),P,Q,l,&SP,&SQ,NULL,NULL);
                   2003:   R=Fp_inv_isom(SP,P,l);
                   2004:   R=FpX_FpXQ_compo(R,SQ,Q,l);
                   2005:   return gerepileupto(ltop,R);
                   2006: }
                   2007: GEN
1.2     ! noro     2008: Fp_factorgalois(GEN P,GEN l, long d, long w, GEN MP)
1.1       noro     2009: {
1.2     ! noro     2010:   gpmem_t ltop=avma;
        !          2011:   GEN R,V,Tl,z,M;
1.1       noro     2012:   long n,k,m;
                   2013:   long v;
                   2014:   v=varn(P);
                   2015:   n=degpol(P);
                   2016:   m=n/d;
1.2     ! noro     2017:   if (DEBUGLEVEL>=4) (void)timer2();
        !          2018:   M=FpM_frobenius_pow(MP,d,P,l);
        !          2019:   if (DEBUGLEVEL>=4) msgtimer("Fp_factorgalois: frobenius power");
1.1       noro     2020:   Tl=gcopy(P); setvarn(Tl,w);
                   2021:   V=cgetg(m+1,t_VEC);
                   2022:   V[1]=lpolx[w];
1.2     ! noro     2023:   z=pol_to_vec((GEN)V[1],n);
1.1       noro     2024:   for(k=2;k<=m;k++)
1.2     ! noro     2025:   {
        !          2026:     z=FpM_FpV_mul(M,z,l);
        !          2027:     V[k]=(long)vec_to_pol(z,w);
        !          2028:   }
        !          2029:   if (DEBUGLEVEL>=4) msgtimer("Fp_factorgalois: roots");
1.1       noro     2030:   R=FqV_roots_to_pol(V,Tl,l,v);
1.2     ! noro     2031:   if (DEBUGLEVEL>=4) msgtimer("Fp_factorgalois: pol");
1.1       noro     2032:   return gerepileupto(ltop,R);
                   2033: }
                   2034: /* P,Q irreducible over F_l. Factor P over FF_l[X] / Q  [factors are ordered as
                   2035:  * a Frobenius cycle] */
                   2036: GEN
                   2037: Fp_factor_irred(GEN P,GEN l, GEN Q)
                   2038: {
1.2     ! noro     2039:   gpmem_t ltop=avma, av;
        !          2040:   GEN SP,SQ,MP,MQ,M,FP,FQ,E,V,IR,res;
1.1       noro     2041:   long np=degpol(P),nq=degpol(Q);
                   2042:   long i,d=cgcd(np,nq);
                   2043:   long vp=varn(P),vq=varn(Q);
                   2044:   if (d==1)
                   2045:   {
                   2046:     res=cgetg(2,t_COL);
                   2047:     res[1]=lcopy(P);
                   2048:     return res;
                   2049:   }
1.2     ! noro     2050:   if (DEBUGLEVEL>=4) (void)timer2();
        !          2051:   FP=matrixpow(np,np,FpXQ_pow(polx[vp],l,P,l),P,l);
        !          2052:   FQ=matrixpow(nq,nq,FpXQ_pow(polx[vq],l,Q,l),Q,l);
        !          2053:   if (DEBUGLEVEL>=4) msgtimer("matrixpows");
        !          2054:   Fp_intersect(d,P,Q,l,&SP,&SQ,FP,FQ);
1.1       noro     2055:   av=avma;
1.2     ! noro     2056:   E=Fp_factorgalois(P,l,d,vq,FP);
1.1       noro     2057:   E=polpol_to_mat(E,np);
                   2058:   MP = matrixpow(np,d,SP,P,l);
                   2059:   IR = (GEN)FpM_sindexrank(MP,l)[1];
                   2060:   E = rowextract_p(E, IR);
                   2061:   M = rowextract_p(MP,IR);
                   2062:   M = FpM_inv(M,l);
                   2063:   MQ = matrixpow(nq,d,SQ,Q,l);
                   2064:   M = FpM_mul(MQ,M,l);
                   2065:   M = FpM_mul(M,E,l);
                   2066:   M = gerepileupto(av,M);
                   2067:   V = cgetg(d+1,t_VEC);
                   2068:   V[1]=(long)M;
                   2069:   for(i=2;i<=d;i++)
1.2     ! noro     2070:     V[i]=(long)FpM_mul(FQ,(GEN)V[i-1],l);
1.1       noro     2071:   res=cgetg(d+1,t_COL);
                   2072:   for(i=1;i<=d;i++)
                   2073:     res[i]=(long)mat_to_polpol((GEN)V[i],vp,vq);
                   2074:   return gerepilecopy(ltop,res);
                   2075: }
                   2076: GEN Fp_factor_rel0(GEN P,GEN l, GEN Q)
                   2077: {
1.2     ! noro     2078:   gpmem_t ltop=avma, tetpil;
1.1       noro     2079:   GEN V,ex,F,y,R;
                   2080:   long n,nbfact=0,nmax=lgef(P)-2;
                   2081:   long i;
                   2082:   F=factmod0(P,l);
                   2083:   n=lg((GEN)F[1]);
                   2084:   V=cgetg(nmax,t_VEC);
                   2085:   ex=cgetg(nmax,t_VECSMALL);
                   2086:   for(i=1;i<n;i++)
                   2087:   {
                   2088:     int j,r;
                   2089:     R=Fp_factor_irred(gmael(F,1,i),l,Q);
                   2090:     r=lg(R);
                   2091:     for (j=1;j<r;j++)
                   2092:     {
                   2093:       V[++nbfact]=R[j];
                   2094:       ex[nbfact]=mael(F,2,i);
                   2095:     }
                   2096:   }
                   2097:   setlg(V,nbfact+1);
                   2098:   setlg(ex,nbfact+1);
                   2099:   tetpil=avma; y=cgetg(3,t_VEC);
                   2100:   y[1]=lcopy(V);
                   2101:   y[2]=lcopy(ex);
                   2102:   (void)sort_factor(y,cmp_pol);
                   2103:   return gerepile(ltop,tetpil,y);
                   2104: }
                   2105: GEN Fp_factor_rel(GEN P, GEN l, GEN Q)
                   2106: {
1.2     ! noro     2107:   gpmem_t tetpil, av=avma;
1.1       noro     2108:   long nbfact;
                   2109:   long j;
                   2110:   GEN y,u,v;
                   2111:   GEN z=Fp_factor_rel0(P,l,Q),t = (GEN) z[1],ex = (GEN) z[2];
                   2112:   nbfact=lg(t);
                   2113:   tetpil=avma; y=cgetg(3,t_MAT);
                   2114:   u=cgetg(nbfact,t_COL); y[1]=(long)u;
                   2115:   v=cgetg(nbfact,t_COL); y[2]=(long)v;
                   2116:   for (j=1; j<nbfact; j++)
                   2117:   {
                   2118:     u[j] = lcopy((GEN)t[j]);
                   2119:     v[j] = lstoi(ex[j]);
                   2120:   }
                   2121:   return gerepile(av,tetpil,y);
                   2122: }
                   2123:
                   2124: /*******************************************************************/
                   2125: extern int ff_poltype(GEN *x, GEN *p, GEN *pol);
                   2126:
                   2127: static GEN
                   2128: to_intmod(GEN x, GEN p)
                   2129: {
                   2130:   GEN a = cgetg(3,t_INTMOD);
                   2131:   a[1] = (long)p;
                   2132:   a[2] = lmodii(x,p); return a;
                   2133: }
                   2134:
                   2135: /* z in Z[X], return z * Mod(1,p), normalized*/
                   2136: GEN
                   2137: FpX(GEN z, GEN p)
                   2138: {
                   2139:   long i,l = lgef(z);
                   2140:   GEN x = cgetg(l,t_POL);
                   2141:   if (isonstack(p)) p = icopy(p);
                   2142:   for (i=2; i<l; i++) x[i] = (long)to_intmod((GEN)z[i], p);
                   2143:   x[1] = z[1]; return normalizepol_i(x,l);
                   2144: }
                   2145:
                   2146: /* z in Z^n, return z * Mod(1,p), normalized*/
                   2147: GEN
                   2148: FpV(GEN z, GEN p)
                   2149: {
                   2150:   long i,l = lg(z);
                   2151:   GEN x = cgetg(l,typ(z));
                   2152:   if (isonstack(p)) p = icopy(p);
                   2153:   for (i=1; i<l; i++) x[i] = (long)to_intmod((GEN)z[i], p);
                   2154:   return x;
                   2155: }
                   2156: /* z in Mat m,n(Z), return z * Mod(1,p), normalized*/
                   2157: GEN
                   2158: FpM(GEN z, GEN p)
                   2159: {
                   2160:   long i,j,l = lg(z), m = lg((GEN)z[1]);
                   2161:   GEN x,y,zi;
                   2162:   if (isonstack(p)) p = icopy(p);
                   2163:   x = cgetg(l,t_MAT);
                   2164:   for (i=1; i<l; i++)
                   2165:   {
                   2166:     x[i] = lgetg(m,t_COL);
                   2167:     y = (GEN)x[i];
                   2168:     zi= (GEN)z[i];
                   2169:     for (j=1; j<m; j++) y[j] = (long)to_intmod((GEN)zi[j], p);
                   2170:   }
                   2171:   return x;
                   2172: }
                   2173: /* z in Z[X] or Z, return lift(z * Mod(1,p)), normalized*/
                   2174: GEN
                   2175: FpX_red(GEN z, GEN p)
                   2176: {
                   2177:   long i,l;
                   2178:   GEN x;
                   2179:   if (typ(z) == t_INT) return modii(z,p);
                   2180:   l = lgef(z);
                   2181:   x = cgetg(l,t_POL);
                   2182:   for (i=2; i<l; i++) x[i] = lmodii((GEN)z[i],p);
                   2183:   x[1] = z[1]; return normalizepol_i(x,l);
                   2184: }
                   2185:
                   2186: GEN
                   2187: FpXV_red(GEN z, GEN p)
                   2188: {
                   2189:   long i,l = lg(z);
                   2190:   GEN x = cgetg(l, t_VEC);
                   2191:   for (i=1; i<l; i++) x[i] = (long)FpX_red((GEN)z[i], p);
                   2192:   return x;
                   2193: }
                   2194:
                   2195: /* z in Z^n, return lift(z * Mod(1,p)) */
                   2196: GEN
                   2197: FpV_red(GEN z, GEN p)
                   2198: {
                   2199:   long i,l = lg(z);
                   2200:   GEN x = cgetg(l,typ(z));
                   2201:   for (i=1; i<l; i++) x[i] = lmodii((GEN)z[i],p);
                   2202:   return x;
                   2203: }
                   2204:
                   2205: /* z in Mat m,n(Z), return lift(z * Mod(1,p)) */
                   2206: GEN
                   2207: FpM_red(GEN z, GEN p)
                   2208: {
1.2     ! noro     2209:   long i, l = lg(z);
        !          2210:   GEN x = cgetg(l,t_MAT);
        !          2211:   for (i=1; i<l; i++) x[i] = (long)FpV_red((GEN)z[i], p);
1.1       noro     2212:   return x;
                   2213: }
                   2214:
                   2215: /* no garbage collection, divide by leading coeff, mod p */
                   2216: GEN
                   2217: FpX_normalize(GEN z, GEN p)
                   2218: {
                   2219:   GEN p1 = leading_term(z);
                   2220:   if (gcmp1(p1)) return z;
                   2221:   return FpX_Fp_mul(z, mpinvmod(p1,p), p);
                   2222: }
                   2223:
                   2224: GEN
                   2225: FpXQX_normalize(GEN z, GEN T, GEN p)
                   2226: {
                   2227:   GEN p1 = leading_term(z);
                   2228:   if (gcmp1(p1)) return z;
                   2229:   if (!T) return FpX_normalize(z,p);
                   2230:   return FpXQX_FpXQ_mul(z, FpXQ_inv(p1,T,p), T,p);
                   2231: }
                   2232:
                   2233: GEN
1.2     ! noro     2234: small_to_vec(GEN z)
        !          2235: {
        !          2236:   long i, l = lg(z);
        !          2237:   GEN x = cgetg(l,t_VEC);
        !          2238:   for (i=1; i<l; i++) x[i] = lstoi(z[i]);
        !          2239:   return x;
        !          2240: }
        !          2241:
        !          2242: GEN
        !          2243: small_to_col(GEN z)
        !          2244: {
        !          2245:   long i, l = lg(z);
        !          2246:   GEN x = cgetg(l,t_COL);
        !          2247:   for (i=1; i<l; i++) x[i] = lstoi(z[i]);
        !          2248:   return x;
        !          2249: }
        !          2250:
        !          2251: GEN
1.1       noro     2252: small_to_mat(GEN z)
                   2253: {
                   2254:   long i, l = lg(z);
                   2255:   GEN x = cgetg(l,t_MAT);
1.2     ! noro     2256:   for (i=1; i<l; i++)
        !          2257:     x[i] = (long)small_to_col((GEN)z[i]);
1.1       noro     2258:   return x;
                   2259: }
                   2260:
                   2261: GEN
                   2262: small_to_pol_i(GEN z, long l)
                   2263: {
                   2264:   long i;
                   2265:   GEN x = cgetg(l,t_POL);
                   2266:   for (i=2; i<l; i++) x[i] = lstoi(z[i]);
                   2267:   x[1] = z[1]; return x;
                   2268: }
                   2269:
                   2270: /* assume z[i] % p has been done */
                   2271: GEN
                   2272: small_to_pol(GEN z, long v)
                   2273: {
                   2274:   GEN x = small_to_pol_i(z, lgef(z));
                   2275:   setvarn(x,v); return x;
                   2276: }
1.2     ! noro     2277: /* same. In place */
        !          2278: GEN
        !          2279: small_to_pol_ip(GEN z, long v)
        !          2280: {
        !          2281:   long i, l = lgef(z);
        !          2282:   for (i=2; i<l; i++) z[i] = lstoi(z[i]);
        !          2283:   settyp(z, t_POL); setvarn(z, v); return z;
        !          2284: }
1.1       noro     2285:
                   2286: GEN
                   2287: pol_to_small(GEN x)
                   2288: {
                   2289:   long i, lx = lgef(x);
1.2     ! noro     2290:   GEN a = u_getpol(lx-3);
1.1       noro     2291:   for (i=2; i<lx; i++) a[i] = itos((GEN)x[i]);
                   2292:   return a;
                   2293: }
                   2294:
1.2     ! noro     2295: /* z in Z[X,Y] representing an elt in F_p[X,Y] mod T(Y) i.e F_q[X])
1.1       noro     2296:  * in Kronecker form. Recover the "real" z, normalized
                   2297:  * If p = NULL, use generic functions and the coeff. ring implied by the
                   2298:  * coefficients of z */
                   2299: GEN
1.2     ! noro     2300: FqX_from_Kronecker(GEN z, GEN T, GEN p)
1.1       noro     2301: {
1.2     ! noro     2302:   long i,j,lx,l = lgef(z), N = (degpol(T)<<1) + 1;
1.1       noro     2303:   GEN a,x, t = cgetg(N,t_POL);
1.2     ! noro     2304:   t[1] = T[1] & VARNBITS;
1.1       noro     2305:   lx = (l-2) / (N-2); x = cgetg(lx+3,t_POL);
1.2     ! noro     2306:   if (isonstack(T)) T = gcopy(T);
1.1       noro     2307:   for (i=2; i<lx+2; i++)
                   2308:   {
                   2309:     a = cgetg(3,t_POLMOD); x[i] = (long)a;
1.2     ! noro     2310:     a[1] = (long)T;
1.1       noro     2311:     for (j=2; j<N; j++) t[j] = z[j];
                   2312:     z += (N-2);
1.2     ! noro     2313:     a[2] = (long)FpX_res(normalizepol_i(t,N), T,p);
1.1       noro     2314:   }
                   2315:   a = cgetg(3,t_POLMOD); x[i] = (long)a;
1.2     ! noro     2316:   a[1] = (long)T;
1.1       noro     2317:   N = (l-2) % (N-2) + 2;
                   2318:   for (j=2; j<N; j++) t[j] = z[j];
1.2     ! noro     2319:   a[2] = (long)FpX_res(normalizepol_i(t,N), T,p);
1.1       noro     2320:   return normalizepol_i(x, i+1);
                   2321: }
                   2322:
1.2     ! noro     2323: #if 0
        !          2324: /* z in Kronecker form representing a polynomial in FqX. Reduce mod (p,T) */
        !          2325: GEN
        !          2326: FqX_Kronecker_red(GEN z, GEN T, GEN p)
        !          2327: {
        !          2328:   long i,j,lx,l = lgef(z), lT = lgef(T), N = ((dT-3)<<1) + 1;
        !          2329:   GEN a,x,y, t = cgetg(N,t_POL);
        !          2330:   t[1] = T[1] & VARNBITS;
        !          2331:   lx = (l-2) / (N-2); x = cgetg(lx+3,t_POL);
        !          2332:   x = y = z = FpX_red(z, p);
        !          2333:   for (i=2; i<lx+2; i++)
        !          2334:   {
        !          2335:     for (j=2; j<N; j++) t[j] = z[j];
        !          2336:     a = FpX_res(normalizepol_i(t,N), T,p);
        !          2337:     for (j=2; j<lT; j++) y[j] = a[j];
        !          2338:     for (   ; j<N;  j++) y[j] = zero;
        !          2339:     z += (N-2);
        !          2340:     y += (N-2);
        !          2341:   }
        !          2342:   N = (l-2) % (N-2) + 2;
        !          2343:   for (j=2; j<N; j++) t[j] = z[j];
        !          2344:   a = FpX_res(normalizepol_i(t,N), T,p);
        !          2345:   for (j=2; j<lT; j++) y[j] = a[j];
        !          2346:   for (   ; j<N;  j++) y[j] = zero;
        !          2347:   return normalizepol_i(x, l);
        !          2348: }
        !          2349: #endif
        !          2350:
1.1       noro     2351: /* z in ?[X,Y] mod Q(Y) in Kronecker form ((subst(lift(z), x, y^(2deg(z)-1)))
                   2352:  * Recover the "real" z, normalized */
                   2353: GEN
                   2354: from_Kronecker(GEN z, GEN pol)
                   2355: {
                   2356:   return FqX_from_Kronecker(z,pol,NULL);
                   2357: }
                   2358:
                   2359: /*******************************************************************/
                   2360: /*                                                                 */
                   2361: /*                          MODULAR GCD                            */
                   2362: /*                                                                 */
                   2363: /*******************************************************************/
1.2     ! noro     2364: extern ulong xgcduu(ulong d, ulong d1, int f, ulong* v, ulong* v1, long *s);
1.1       noro     2365: /* 1 / Mod(x,p) , or 0 if inverse doesn't exist */
                   2366: ulong
                   2367: u_invmod(ulong x, ulong p)
                   2368: {
                   2369:   long s;
                   2370:   ulong xv, xv1, g = xgcduu(p, x, 1, &xv, &xv1, &s);
                   2371:   if (g != 1UL) return 0UL;
                   2372:   xv = xv1 % p; if (s < 0) xv = p - xv;
                   2373:   return xv;
                   2374: }
                   2375:
1.2     ! noro     2376: int
        !          2377: u_val(ulong n, ulong p)
        !          2378: {
        !          2379:   ulong dummy;
        !          2380:   return svaluation(n,p,&dummy);
        !          2381: }
        !          2382:
        !          2383: /* assume p^k is SMALL */
        !          2384: int
        !          2385: u_pow(int p, int k)
        !          2386: {
        !          2387:   int i, pk;
        !          2388:
        !          2389:   if (!k) return 1;
        !          2390:   if (p == 2) return 1<<k;
        !          2391:   pk = p; for (i=2; i<=k; i++) pk *= p;
        !          2392:   return pk;
        !          2393: }
        !          2394:
        !          2395: #if 0
        !          2396: static ulong
        !          2397: umodratu(GEN a, ulong p)
1.1       noro     2398: {
                   2399:   if (typ(a) == t_INT)
                   2400:     return umodiu(a,p);
                   2401:   else { /* assume a a t_FRAC */
                   2402:     ulong num = umodiu((GEN)a[1],p);
                   2403:     ulong den = umodiu((GEN)a[2],p);
                   2404:     return (ulong)mulssmod(num, u_invmod(den,p), p);
                   2405:   }
                   2406: }
                   2407: #endif
                   2408:
                   2409: /* return x[0 .. dx] mod p as t_VECSMALL. Assume x a t_POL/VECSMALL/INT */
                   2410: GEN
1.2     ! noro     2411: u_Fp_FpX(GEN x, ulong p)
1.1       noro     2412: {
                   2413:   long i, lx;
                   2414:   GEN a;
                   2415:
                   2416:   switch (typ(x))
                   2417:   {
                   2418:     case t_VECSMALL: return x;
1.2     ! noro     2419:     case t_INT: a = u_getpol(0);
1.1       noro     2420:       a[2] = umodiu(x, p); return a;
                   2421:   }
1.2     ! noro     2422:   lx = lgef(x); a = u_getpol(lx-3);
1.1       noro     2423:   for (i=2; i<lx; i++) a[i] = (long)umodiu((GEN)x[i], p);
                   2424:   return u_normalizepol(a,lx);
                   2425: }
                   2426:
                   2427: GEN
1.2     ! noro     2428: u_Fp_FpV(GEN x, ulong p)
        !          2429: {
        !          2430:   long i, n = lg(x);
        !          2431:   GEN y = cgetg(n,t_VECSMALL);
        !          2432:   for (i=1; i<n; i++) y[i] = (long)umodiu((GEN)x[i], p);
        !          2433:   return y;
        !          2434: }
        !          2435:
        !          2436: GEN
1.1       noro     2437: u_Fp_FpM(GEN x, ulong p)
                   2438: {
1.2     ! noro     2439:   long j,n = lg(x);
1.1       noro     2440:   GEN y = cgetg(n,t_MAT);
                   2441:   if (n == 1) return y;
1.2     ! noro     2442:   for (j=1; j<n; j++) y[j] = (long)u_Fp_FpV((GEN)x[j], p);
1.1       noro     2443:   return y;
                   2444: }
                   2445:
                   2446: static GEN
1.2     ! noro     2447: u_FpX_Fp_mul(GEN y, ulong x,ulong p)
1.1       noro     2448: {
                   2449:   GEN z;
                   2450:   int i, l;
1.2     ! noro     2451:   if (!x) return u_zeropol();
        !          2452:   l = lgef(y); z = u_getpol(l-3);
1.1       noro     2453:   if (HIGHWORD(x | p))
                   2454:     for(i=2; i<l; i++) z[i] = mulssmod(y[i], x, p);
                   2455:   else
                   2456:     for(i=2; i<l; i++) z[i] = (y[i] * x) % p;
                   2457:   return z;
                   2458: }
                   2459:
                   2460: GEN
                   2461: u_FpX_normalize(GEN z, ulong p)
                   2462: {
                   2463:   long l = lgef(z)-1;
                   2464:   ulong p1 = z[l]; /* leading term */
                   2465:   if (p1 == 1) return z;
1.2     ! noro     2466:   return u_FpX_Fp_mul(z, u_invmod(p1,p), p);
1.1       noro     2467: }
                   2468:
                   2469: static GEN
1.2     ! noro     2470: u_copy(GEN x)
1.1       noro     2471: {
                   2472:   long i, l = lgef(x);
1.2     ! noro     2473:   GEN z = u_getpol(l-3);
1.1       noro     2474:   for (i=2; i<l; i++) z[i] = x[i];
                   2475:   return z;
                   2476: }
                   2477:
1.2     ! noro     2478: /* as FpX_divres but working only on ulong types. ASSUME pr != ONLY_DIVIDES
        !          2479:  * if relevant, *pr is the last object on stack */
1.1       noro     2480: GEN
1.2     ! noro     2481: u_FpX_divrem(GEN x, GEN y, ulong p, GEN *pr)
1.1       noro     2482: {
                   2483:   GEN z,q,c;
                   2484:   long dx,dy,dz,i,j;
                   2485:   ulong p1,inv;
                   2486:
1.2     ! noro     2487:   if (pr == ONLY_REM) return u_FpX_rem(x, y, p);
1.1       noro     2488:   dy = degpol(y);
                   2489:   if (!dy)
                   2490:   {
1.2     ! noro     2491:     if (y[2] == 1UL)
        !          2492:       q = u_copy(x);
        !          2493:     else
        !          2494:       q = u_FpX_Fp_mul(x, u_invmod(y[2], p), p);
        !          2495:     if (pr) *pr = u_zeropol();
        !          2496:     return q;
1.1       noro     2497:   }
                   2498:   dx = degpol(x);
                   2499:   dz = dx-dy;
                   2500:   if (dz < 0)
                   2501:   {
1.2     ! noro     2502:     q = u_zeropol();
        !          2503:     if (pr) *pr = u_copy(x);
        !          2504:     return q;
1.1       noro     2505:   }
                   2506:   x += 2;
                   2507:   y += 2;
1.2     ! noro     2508:   z = u_getpol(dz) + 2;
1.1       noro     2509:   inv = y[dy];
                   2510:   if (inv != 1UL) inv = u_invmod(inv,p);
                   2511:
                   2512:   if (u_OK_ULONG(p))
                   2513:   {
                   2514:     z[dz] = (inv*x[dx]) % p;
                   2515:     for (i=dx-1; i>=dy; --i)
                   2516:     {
                   2517:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   2518:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   2519:       {
                   2520:         p1 += z[j]*y[i-j];
1.2     ! noro     2521:         if (p1 & HIGHBIT) p1 %= p;
1.1       noro     2522:       }
                   2523:       p1 %= p;
                   2524:       z[i-dy] = p1? ((p - p1)*inv) % p: 0;
                   2525:     }
                   2526:   }
                   2527:   else
                   2528:   {
                   2529:     z[dz] = mulssmod(inv, x[dx], p);
                   2530:     for (i=dx-1; i>=dy; --i)
                   2531:     {
                   2532:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   2533:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   2534:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   2535:       z[i-dy] = p1? mulssmod(p - p1, inv, p): 0;
                   2536:     }
                   2537:   }
                   2538:   q = u_normalizepol(z-2, dz+3);
                   2539:   if (!pr) return q;
                   2540:
1.2     ! noro     2541:   c = u_getpol(dy) + 2;
1.1       noro     2542:   if (u_OK_ULONG(p))
                   2543:   {
                   2544:     for (i=0; i<dy; i++)
                   2545:     {
                   2546:       p1 = z[0]*y[i];
                   2547:       for (j=1; j<=i && j<=dz; j++)
                   2548:       {
                   2549:         p1 += z[j]*y[i-j];
1.2     ! noro     2550:         if (p1 & HIGHBIT) p1 %= p;
1.1       noro     2551:       }
                   2552:       c[i] = subssmod(x[i], p1%p, p);
                   2553:     }
                   2554:   }
                   2555:   else
                   2556:   {
                   2557:     for (i=0; i<dy; i++)
                   2558:     {
                   2559:       p1 = mulssmod(z[0],y[i],p);
                   2560:       for (j=1; j<=i && j<=dz; j++)
                   2561:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   2562:       c[i] = subssmod(x[i], p1, p);
                   2563:     }
                   2564:   }
                   2565:   i=dy-1; while (i>=0 && !c[i]) i--;
                   2566:   c = u_normalizepol(c-2, i+3);
                   2567:   *pr = c; return q;
                   2568: }
                   2569:
1.2     ! noro     2570: /*FIXME: Unify the following 3 divrem routines. Treat the case x,y (lifted) in
        !          2571:  * R[X], y non constant. Given: (lifted) [inv(), mul()], (delayed) red() in R */
        !          2572:
1.1       noro     2573: /* x and y in Z[X]. Possibly x in Z */
                   2574: GEN
                   2575: FpX_divres(GEN x, GEN y, GEN p, GEN *pr)
                   2576: {
1.2     ! noro     2577:   long vx, dx, dy, dz, i, j, sx, lrem;
        !          2578:   gpmem_t av0, av, tetpil;
1.1       noro     2579:   GEN z,p1,rem,lead;
                   2580:
                   2581:   if (!p) return poldivres(x,y,pr);
                   2582:   if (!signe(y)) err(talker,"division by zero in FpX_divres");
1.2     ! noro     2583:   vx = varn(x);
        !          2584:   dy = degpol(y);
        !          2585:   dx = (typ(x)==t_INT)? 0: degpol(x);
1.1       noro     2586:   if (dx < dy)
                   2587:   {
                   2588:     if (pr)
                   2589:     {
                   2590:       av0 = avma; x = FpX_red(x, p);
                   2591:       if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: gzero; }
                   2592:       if (pr == ONLY_REM) return x;
                   2593:       *pr = x;
                   2594:     }
                   2595:     return zeropol(vx);
                   2596:   }
                   2597:   lead = leading_term(y);
                   2598:   if (!dy) /* y is constant */
                   2599:   {
                   2600:     if (pr && pr != ONLY_DIVIDES)
                   2601:     {
                   2602:       if (pr == ONLY_REM) return zeropol(vx);
                   2603:       *pr = zeropol(vx);
                   2604:     }
                   2605:     if (gcmp1(lead)) return gcopy(x);
                   2606:     av0 = avma; x = gmul(x, mpinvmod(lead,p)); tetpil = avma;
                   2607:     return gerepile(av0,tetpil,FpX_red(x,p));
                   2608:   }
                   2609:   av0 = avma; dz = dx-dy;
                   2610:   if (OK_ULONG(p))
                   2611:   { /* assume ab != 0 mod p */
                   2612:     ulong pp = (ulong)p[2];
1.2     ! noro     2613:     GEN a = u_Fp_FpX(x, pp);
        !          2614:     GEN b = u_Fp_FpX(y, pp);
        !          2615:     z = u_FpX_divrem(a,b,pp, pr);
        !          2616:     avma = av0; /* HACK: assume pr last on stack, then z */
        !          2617:     setlg(z, lgef(z)); z = dummycopy(z);
1.1       noro     2618:     if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)
                   2619:     {
1.2     ! noro     2620:       setlg(*pr, lgef(*pr)); *pr = dummycopy(*pr);
        !          2621:       *pr = small_to_pol_ip(*pr,vx);
1.1       noro     2622:     }
1.2     ! noro     2623:     return small_to_pol_ip(z,vx);
1.1       noro     2624:   }
                   2625:   lead = gcmp1(lead)? NULL: gclone(mpinvmod(lead,p));
                   2626:   avma = av0;
                   2627:   z=cgetg(dz+3,t_POL);
                   2628:   z[1]=evalsigne(1) | evallgef(dz+3) | evalvarn(vx);
                   2629:   x += 2; y += 2; z += 2;
                   2630:
                   2631:   p1 = (GEN)x[dx]; av = avma;
                   2632:   z[dz] = lead? lpileupto(av, modii(mulii(p1,lead), p)): licopy(p1);
                   2633:   for (i=dx-1; i>=dy; i--)
                   2634:   {
                   2635:     av=avma; p1=(GEN)x[i];
                   2636:     for (j=i-dy+1; j<=i && j<=dz; j++)
                   2637:       p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j]));
                   2638:     if (lead) p1 = mulii(p1,lead);
                   2639:     tetpil=avma; z[i-dy] = lpile(av,tetpil,modii(p1, p));
                   2640:   }
                   2641:   if (!pr) { if (lead) gunclone(lead); return z-2; }
                   2642:
1.2     ! noro     2643:   rem = (GEN)avma; av = (gpmem_t)new_chunk(dx+3);
1.1       noro     2644:   for (sx=0; ; i--)
                   2645:   {
                   2646:     p1 = (GEN)x[i];
                   2647:     for (j=0; j<=i && j<=dz; j++)
                   2648:       p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j]));
                   2649:     tetpil=avma; p1 = modii(p1,p); if (signe(p1)) { sx = 1; break; }
                   2650:     if (!i) break;
                   2651:     avma=av;
                   2652:   }
                   2653:   if (pr == ONLY_DIVIDES)
                   2654:   {
                   2655:     if (lead) gunclone(lead);
                   2656:     if (sx) { avma=av0; return NULL; }
1.2     ! noro     2657:     avma = (gpmem_t)rem; return z-2;
1.1       noro     2658:   }
                   2659:   lrem=i+3; rem -= lrem;
                   2660:   rem[0]=evaltyp(t_POL) | evallg(lrem);
                   2661:   rem[1]=evalsigne(1) | evalvarn(vx) | evallgef(lrem);
1.2     ! noro     2662:   p1 = gerepile((gpmem_t)rem,tetpil,p1);
1.1       noro     2663:   rem += 2; rem[i]=(long)p1;
                   2664:   for (i--; i>=0; i--)
                   2665:   {
                   2666:     av=avma; p1 = (GEN)x[i];
                   2667:     for (j=0; j<=i && j<=dz; j++)
                   2668:       p1 = subii(p1, mulii((GEN)z[j],(GEN)y[i-j]));
                   2669:     tetpil=avma; rem[i]=lpile(av,tetpil, modii(p1,p));
                   2670:   }
                   2671:   rem -= 2;
                   2672:   if (lead) gunclone(lead);
1.2     ! noro     2673:   if (!sx) (void)normalizepol_i(rem, lrem);
1.1       noro     2674:   if (pr == ONLY_REM) return gerepileupto(av0,rem);
                   2675:   *pr = rem; return z-2;
                   2676: }
                   2677:
                   2678: /* x and y in Z[Y][X]. Assume T irreducible mod p */
                   2679: GEN
                   2680: FpXQX_divres(GEN x, GEN y, GEN T, GEN p, GEN *pr)
                   2681: {
1.2     ! noro     2682:   long vx, dx, dy, dz, i, j, sx, lrem;
        !          2683:   gpmem_t av0, av, tetpil;
1.1       noro     2684:   GEN z,p1,rem,lead;
                   2685:
                   2686:   if (!p) return poldivres(x,y,pr);
                   2687:   if (!T) return FpX_divres(x,y,p,pr);
                   2688:   if (!signe(y)) err(talker,"division by zero in FpX_divres");
                   2689:   vx=varn(x); dy=degpol(y); dx=degpol(x);
                   2690:   if (dx < dy)
                   2691:   {
                   2692:     if (pr)
                   2693:     {
                   2694:       av0 = avma; x = FpXQX_red(x, T, p);
                   2695:       if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: gzero; }
                   2696:       if (pr == ONLY_REM) return x;
                   2697:       *pr = x;
                   2698:     }
                   2699:     return zeropol(vx);
                   2700:   }
                   2701:   lead = leading_term(y);
                   2702:   if (!dy) /* y is constant */
                   2703:   {
                   2704:     if (pr && pr != ONLY_DIVIDES)
                   2705:     {
                   2706:       if (pr == ONLY_REM) return zeropol(vx);
                   2707:       *pr = zeropol(vx);
                   2708:     }
                   2709:     if (gcmp1(lead)) return gcopy(x);
                   2710:     av0 = avma; x = gmul(x, FpXQ_inv(lead,T,p)); tetpil = avma;
                   2711:     return gerepile(av0,tetpil,FpXQX_red(x,T,p));
                   2712:   }
                   2713:   av0 = avma; dz = dx-dy;
                   2714: #if 0 /* FIXME: to be done */
                   2715:   if (OK_ULONG(p))
                   2716:   { /* assume ab != 0 mod p */
                   2717:   }
                   2718: #endif
                   2719:   lead = gcmp1(lead)? NULL: gclone(FpXQ_inv(lead,T,p));
                   2720:   avma = av0;
                   2721:   z=cgetg(dz+3,t_POL);
                   2722:   z[1]=evalsigne(1) | evallgef(dz+3) | evalvarn(vx);
                   2723:   x += 2; y += 2; z += 2;
                   2724:
                   2725:   p1 = (GEN)x[dx]; av = avma;
                   2726:   z[dz] = lead? lpileupto(av, FpX_res(gmul(p1,lead), T, p)): lcopy(p1);
                   2727:   for (i=dx-1; i>=dy; i--)
                   2728:   {
                   2729:     av=avma; p1=(GEN)x[i];
                   2730:     for (j=i-dy+1; j<=i && j<=dz; j++)
                   2731:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
                   2732:     if (lead) p1 = gmul(FpX_res(p1, T, p), lead);
                   2733:     tetpil=avma; z[i-dy] = lpile(av,tetpil,FpX_res(p1, T, p));
                   2734:   }
                   2735:   if (!pr) { if (lead) gunclone(lead); return z-2; }
                   2736:
1.2     ! noro     2737:   rem = (GEN)avma; av = (gpmem_t)new_chunk(dx+3);
1.1       noro     2738:   for (sx=0; ; i--)
                   2739:   {
                   2740:     p1 = (GEN)x[i];
                   2741:     for (j=0; j<=i && j<=dz; j++)
                   2742:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
                   2743:     tetpil=avma; p1 = FpX_res(p1, T, p); if (signe(p1)) { sx = 1; break; }
                   2744:     if (!i) break;
                   2745:     avma=av;
                   2746:   }
                   2747:   if (pr == ONLY_DIVIDES)
                   2748:   {
                   2749:     if (lead) gunclone(lead);
                   2750:     if (sx) { avma=av0; return NULL; }
1.2     ! noro     2751:     avma = (gpmem_t)rem; return z-2;
1.1       noro     2752:   }
                   2753:   lrem=i+3; rem -= lrem;
                   2754:   rem[0]=evaltyp(t_POL) | evallg(lrem);
                   2755:   rem[1]=evalsigne(1) | evalvarn(vx) | evallgef(lrem);
1.2     ! noro     2756:   p1 = gerepile((gpmem_t)rem,tetpil,p1);
1.1       noro     2757:   rem += 2; rem[i]=(long)p1;
                   2758:   for (i--; i>=0; i--)
                   2759:   {
                   2760:     av=avma; p1 = (GEN)x[i];
                   2761:     for (j=0; j<=i && j<=dz; j++)
                   2762:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
                   2763:     tetpil=avma; rem[i]=lpile(av,tetpil, FpX_res(p1, T, p));
                   2764:   }
                   2765:   rem -= 2;
                   2766:   if (lead) gunclone(lead);
1.2     ! noro     2767:   if (!sx) (void)normalizepol_i(rem, lrem);
        !          2768:   if (pr == ONLY_REM) return gerepileupto(av0,rem);
        !          2769:   *pr = rem; return z-2;
        !          2770: }
        !          2771:
        !          2772: /* R = any base ring */
        !          2773: GEN
        !          2774: RXQX_red(GEN P, GEN T)
        !          2775: {
        !          2776:   long i, l = lgef(P);
        !          2777:   GEN Q = cgetg(l, t_POL);
        !          2778:   Q[1] = P[1];
        !          2779:   for (i=2; i<l; i++) Q[i] = lres((GEN)P[i], T);
        !          2780:   return Q;
        !          2781: }
        !          2782:
        !          2783: /* R = any base ring */
        !          2784: GEN
        !          2785: RXQV_red(GEN P, GEN T)
        !          2786: {
        !          2787:   long i, l = lg(P);
        !          2788:   GEN Q = cgetg(l, typ(P));
        !          2789:   for (i=1; i<l; i++) Q[i] = lres((GEN)P[i], T);
        !          2790:   return Q;
        !          2791: }
        !          2792:
        !          2793: /* x and y in (R[Y]/T)[X]  (lifted), T in R[Y]. y preferably monic */
        !          2794: GEN
        !          2795: RXQX_divrem(GEN x, GEN y, GEN T, GEN *pr)
        !          2796: {
        !          2797:   long vx, dx, dy, dz, i, j, sx, lrem;
        !          2798:   gpmem_t av0, av, tetpil;
        !          2799:   GEN z,p1,rem,lead;
        !          2800:
        !          2801:   if (!signe(y)) err(talker,"division by zero in RXQX_divrem");
        !          2802:   vx = varn(x);
        !          2803:   dx = degpol(x);
        !          2804:   dy = degpol(y);
        !          2805:   if (dx < dy)
        !          2806:   {
        !          2807:     if (pr)
        !          2808:     {
        !          2809:       av0 = avma; x = RXQX_red(x, T);
        !          2810:       if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: gzero; }
        !          2811:       if (pr == ONLY_REM) return x;
        !          2812:       *pr = x;
        !          2813:     }
        !          2814:     return zeropol(vx);
        !          2815:   }
        !          2816:   lead = leading_term(y);
        !          2817:   if (!dy) /* y is constant */
        !          2818:   {
        !          2819:     if (pr && pr != ONLY_DIVIDES)
        !          2820:     {
        !          2821:       if (pr == ONLY_REM) return zeropol(vx);
        !          2822:       *pr = zeropol(vx);
        !          2823:     }
        !          2824:     if (gcmp1(lead)) return gcopy(x);
        !          2825:     av0 = avma; x = gmul(x, ginvmod(lead,T)); tetpil = avma;
        !          2826:     return gerepile(av0,tetpil,RXQX_red(x,T));
        !          2827:   }
        !          2828:   av0 = avma; dz = dx-dy;
        !          2829:   lead = gcmp1(lead)? NULL: gclone(ginvmod(lead,T));
        !          2830:   avma = av0;
        !          2831:   z = cgetg(dz+3,t_POL);
        !          2832:   z[1] = evalsigne(1) | evallgef(dz+3) | evalvarn(vx);
        !          2833:   x += 2; y += 2; z += 2;
        !          2834:
        !          2835:   p1 = (GEN)x[dx]; av = avma;
        !          2836:   z[dz] = lead? lpileupto(av, gres(gmul(p1,lead), T)): lcopy(p1);
        !          2837:   for (i=dx-1; i>=dy; i--)
        !          2838:   {
        !          2839:     av=avma; p1=(GEN)x[i];
        !          2840:     for (j=i-dy+1; j<=i && j<=dz; j++)
        !          2841:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
        !          2842:     if (lead) p1 = gmul(gres(p1, T), lead);
        !          2843:     tetpil=avma; z[i-dy] = lpile(av,tetpil, gres(p1, T));
        !          2844:   }
        !          2845:   if (!pr) { if (lead) gunclone(lead); return z-2; }
        !          2846:
        !          2847:   rem = (GEN)avma; av = (gpmem_t)new_chunk(dx+3);
        !          2848:   for (sx=0; ; i--)
        !          2849:   {
        !          2850:     p1 = (GEN)x[i];
        !          2851:     for (j=0; j<=i && j<=dz; j++)
        !          2852:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
        !          2853:     tetpil=avma; p1 = gres(p1, T); if (signe(p1)) { sx = 1; break; }
        !          2854:     if (!i) break;
        !          2855:     avma=av;
        !          2856:   }
        !          2857:   if (pr == ONLY_DIVIDES)
        !          2858:   {
        !          2859:     if (lead) gunclone(lead);
        !          2860:     if (sx) { avma=av0; return NULL; }
        !          2861:     avma = (gpmem_t)rem; return z-2;
        !          2862:   }
        !          2863:   lrem=i+3; rem -= lrem;
        !          2864:   rem[0]=evaltyp(t_POL) | evallg(lrem);
        !          2865:   rem[1]=evalsigne(1) | evalvarn(vx) | evallgef(lrem);
        !          2866:   p1 = gerepile((gpmem_t)rem,tetpil,p1);
        !          2867:   rem += 2; rem[i]=(long)p1;
        !          2868:   for (i--; i>=0; i--)
        !          2869:   {
        !          2870:     av=avma; p1 = (GEN)x[i];
        !          2871:     for (j=0; j<=i && j<=dz; j++)
        !          2872:       p1 = gsub(p1, gmul((GEN)z[j],(GEN)y[i-j]));
        !          2873:     tetpil=avma; rem[i]=lpile(av,tetpil, gres(p1, T));
        !          2874:   }
        !          2875:   rem -= 2;
        !          2876:   if (lead) gunclone(lead);
        !          2877:   if (!sx) (void)normalizepol_i(rem, lrem);
1.1       noro     2878:   if (pr == ONLY_REM) return gerepileupto(av0,rem);
                   2879:   *pr = rem; return z-2;
                   2880: }
                   2881:
                   2882: static GEN
                   2883: FpX_gcd_long(GEN x, GEN y, GEN p)
                   2884: {
1.2     ! noro     2885:   ulong pp = (ulong)p[2];
        !          2886:   gpmem_t av = avma;
1.1       noro     2887:   GEN a,b;
                   2888:
                   2889:   (void)new_chunk((lgef(x) + lgef(y)) << 2); /* scratch space */
1.2     ! noro     2890:   a = u_Fp_FpX(x, pp);
1.1       noro     2891:   if (!signe(a)) { avma = av; return FpX_red(y,p); }
1.2     ! noro     2892:   b = u_Fp_FpX(y, pp);
1.1       noro     2893:   a = u_FpX_gcd_i(a,b, pp);
                   2894:   avma = av; return small_to_pol(a, varn(x));
                   2895: }
                   2896:
                   2897: /* x and y in Z[X], return lift(gcd(x mod p, y mod p)) */
                   2898: GEN
                   2899: FpX_gcd(GEN x, GEN y, GEN p)
                   2900: {
                   2901:   GEN a,b,c;
1.2     ! noro     2902:   gpmem_t av0, av;
1.1       noro     2903:
                   2904:   if (OK_ULONG(p)) return FpX_gcd_long(x,y,p);
                   2905:   av0=avma;
                   2906:   a = FpX_red(x, p); av = avma;
                   2907:   b = FpX_red(y, p);
                   2908:   while (signe(b))
                   2909:   {
                   2910:     av = avma; c = FpX_res(a,b,p); a=b; b=c;
                   2911:   }
                   2912:   avma = av; return gerepileupto(av0, a);
                   2913: }
                   2914:
1.2     ! noro     2915: /*Return 1 if gcd can be computed
        !          2916:  * else return a factor of p*/
        !          2917:
        !          2918: GEN
        !          2919: FpX_gcd_check(GEN x, GEN y, GEN p)
        !          2920: {
        !          2921:   GEN a,b,c;
        !          2922:   gpmem_t av=avma;
        !          2923:
        !          2924:   a = FpX_red(x, p);
        !          2925:   b = FpX_red(y, p);
        !          2926:   while (signe(b))
        !          2927:   {
        !          2928:     GEN lead = leading_term(b);
        !          2929:     GEN g = mppgcd(lead,p);
        !          2930:     if (!is_pm1(g)) return gerepileupto(av,g);
        !          2931:     c = FpX_res(a,b,p); a=b; b=c;
        !          2932:   }
        !          2933:   avma = av; return gun;
        !          2934: }
        !          2935:
1.1       noro     2936: GEN
                   2937: u_FpX_sub(GEN x, GEN y, ulong p)
                   2938: {
                   2939:   long i,lz,lx = lgef(x), ly = lgef(y);
                   2940:   GEN z;
                   2941:
                   2942:   if (ly <= lx)
                   2943:   {
                   2944:     lz = lx; z = cgetg(lz,t_VECSMALL);
                   2945:     for (i=2; i<ly; i++) z[i] = subssmod(x[i],y[i],p);
                   2946:     for (   ; i<lx; i++) z[i] = x[i];
                   2947:   }
                   2948:   else
                   2949:   {
                   2950:     lz = ly; z = cgetg(lz,t_VECSMALL);
                   2951:     for (i=2; i<lx; i++) z[i] = subssmod(x[i],y[i],p);
                   2952:     for (   ; i<ly; i++) z[i] = y[i]? p - y[i]: y[i];
                   2953:   }
                   2954:   z[1]=0; return u_normalizepol(z, lz);
                   2955: }
                   2956:
                   2957: /* list of u_FpX in gptr, return then as GEN */
                   2958: static void
1.2     ! noro     2959: u_gerepilemany(gpmem_t av, GEN* gptr[], long n, long v)
1.1       noro     2960: {
                   2961:   GEN *l = (GEN*)gpmalloc(n*sizeof(GEN));
                   2962:   long i;
                   2963:
                   2964:   /* copy objects */
                   2965:   for (i=0; i<n; i++) l[i] = gclone(*(gptr[i]));
                   2966:   avma = av;
                   2967:   /* copy them back, kill clones */
                   2968:   for (--i; i>=0; i--)
                   2969:   {
                   2970:     *(gptr[i]) = small_to_pol(l[i],v);
                   2971:     gunclone(l[i]);
                   2972:   }
                   2973:   free(l);
                   2974: }
                   2975:
                   2976: static GEN
                   2977: u_FpX_extgcd(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv)
                   2978: {
                   2979:   GEN q,z,u,v, x = a, y = b;
                   2980:
1.2     ! noro     2981:   u = u_zeropol();
        !          2982:   v= u_scalarpol(1); /* v = 1 */
1.1       noro     2983:   while (signe(y))
                   2984:   {
1.2     ! noro     2985:     q = u_FpX_divrem(x,y,p,&z);
1.1       noro     2986:     x = y; y = z; /* (x,y) = (y, x - q y) */
                   2987:     z = u_FpX_sub(u, u_FpX_mul(q,v, p), p);
                   2988:     u = v; v = z; /* (u,v) = (v, u - q v) */
                   2989:   }
                   2990:   z = u_FpX_sub(x, u_FpX_mul(b,u,p), p);
                   2991:   z = u_FpX_div(z,a,p);
                   2992:   *ptu = z;
                   2993:   *ptv = u; return x;
                   2994: }
                   2995:
                   2996: static GEN
                   2997: FpX_extgcd_long(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
                   2998: {
                   2999:   ulong pp = (ulong)p[2];
1.2     ! noro     3000:   gpmem_t av = avma;
1.1       noro     3001:   GEN a, b, d;
                   3002:
1.2     ! noro     3003:   a = u_Fp_FpX(x, pp);
        !          3004:   b = u_Fp_FpX(y, pp);
1.1       noro     3005:   d = u_FpX_extgcd(a,b, pp, ptu,ptv);
                   3006:   {
                   3007:     GEN *gptr[3]; gptr[0] = &d; gptr[1] = ptu; gptr[2] = ptv;
                   3008:     u_gerepilemany(av, gptr, 3, varn(x));
                   3009:   }
                   3010:   return d;
                   3011: }
                   3012:
                   3013: /* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st
                   3014:  * ux + vy = gcd (mod p) */
1.2     ! noro     3015: /*TODO: Document the typ() of *ptu and *ptv*/
1.1       noro     3016: GEN
                   3017: FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
                   3018: {
                   3019:   GEN a,b,q,r,u,v,d,d1,v1;
1.2     ! noro     3020:   gpmem_t ltop, lbot;
1.1       noro     3021:
                   3022:   if (OK_ULONG(p)) return FpX_extgcd_long(x,y,p,ptu,ptv);
                   3023:   ltop=avma;
                   3024:   a = FpX_red(x, p);
                   3025:   b = FpX_red(y, p);
                   3026:   d = a; d1 = b; v = gzero; v1 = gun;
                   3027:   while (signe(d1))
                   3028:   {
                   3029:     q = FpX_divres(d,d1,p, &r);
                   3030:     v = gadd(v, gneg_i(gmul(q,v1)));
                   3031:     v = FpX_red(v,p);
                   3032:     u=v; v=v1; v1=u;
                   3033:     u=r; d=d1; d1=u;
                   3034:   }
                   3035:   u = gadd(d, gneg_i(gmul(b,v)));
                   3036:   u = FpX_red(u, p);
                   3037:   lbot = avma;
                   3038:   u = FpX_div(u,a,p);
                   3039:   d = gcopy(d);
                   3040:   v = gcopy(v);
                   3041:   {
                   3042:     GEN *gptr[3]; gptr[0] = &d; gptr[1] = &u; gptr[2] = &v;
                   3043:     gerepilemanysp(ltop,lbot,gptr,3);
                   3044:   }
                   3045:   *ptu = u; *ptv = v; return d;
                   3046: }
                   3047:
                   3048: /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
                   3049:  * ux + vy = gcd (mod T,p) */
                   3050: GEN
                   3051: FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)
                   3052: {
                   3053:   GEN a,b,q,r,u,v,d,d1,v1;
1.2     ! noro     3054:   gpmem_t ltop, lbot;
1.1       noro     3055:
                   3056: #if 0 /* FIXME To be done...*/
                   3057:   if (OK_ULONG(p)) return FpXQX_extgcd_long(x,y,T,p,ptu,ptv);
                   3058: #endif
                   3059:   if (!T) return FpX_extgcd(x,y,p,ptu,ptv);
                   3060:   ltop=avma;
                   3061:   a = FpXQX_red(x, T, p);
                   3062:   b = FpXQX_red(y, T, p);
                   3063:   d = a; d1 = b; v = gzero; v1 = gun;
                   3064:   while (signe(d1))
                   3065:   {
                   3066:     q = FpXQX_divres(d,d1,T,p, &r);
                   3067:     v = gadd(v, gneg_i(gmul(q,v1)));
                   3068:     v = FpXQX_red(v,T,p);
                   3069:     u=v; v=v1; v1=u;
                   3070:     u=r; d=d1; d1=u;
                   3071:   }
                   3072:   u = gadd(d, gneg_i(gmul(b,v)));
                   3073:   u = FpXQX_red(u,T, p);
                   3074:   lbot = avma;
                   3075:   u = FpXQX_divres(u,a,T,p,NULL);
                   3076:   d = gcopy(d);
                   3077:   v = gcopy(v);
                   3078:   {
                   3079:     GEN *gptr[3]; gptr[0] = &d; gptr[1] = &u; gptr[2] = &v;
                   3080:     gerepilemanysp(ltop,lbot,gptr,3);
                   3081:   }
                   3082:   *ptu = u; *ptv = v; return d;
                   3083: }
                   3084:
1.2     ! noro     3085: /*x must be reduced*/
1.1       noro     3086: GEN
                   3087: FpXQ_charpoly(GEN x, GEN T, GEN p)
                   3088: {
1.2     ! noro     3089:   gpmem_t ltop=avma;
        !          3090:   long v=varn(T);
        !          3091:   GEN R;
        !          3092:   T=gcopy(T); setvarn(T,MAXVARN);
        !          3093:   x=gcopy(x); setvarn(x,MAXVARN);
        !          3094:   R=FpY_FpXY_resultant(T,deg1pol(gun,FpX_neg(x,p),v),p);
1.1       noro     3095:   return gerepileupto(ltop,R);
                   3096: }
                   3097:
                   3098: GEN
                   3099: FpXQ_minpoly(GEN x, GEN T, GEN p)
                   3100: {
1.2     ! noro     3101:   gpmem_t ltop=avma;
1.1       noro     3102:   GEN R=FpXQ_charpoly(x, T, p);
                   3103:   GEN G=FpX_gcd(R,derivpol(R),p);
                   3104:   G=FpX_normalize(G,p);
                   3105:   G=FpX_div(R,G,p);
                   3106:   return gerepileupto(ltop,G);
                   3107: }
                   3108:
                   3109: /* return z = a mod q, b mod p (p,q) = 1. qinv = 1/q mod p */
                   3110: static GEN
                   3111: u_chrem_coprime(GEN a, ulong b, GEN q, ulong p, ulong qinv, GEN pq)
                   3112: {
1.2     ! noro     3113:   ulong d, amod = umodiu(a, p);
        !          3114:   gpmem_t av = avma;
1.1       noro     3115:   GEN ax;
                   3116:
                   3117:   if (b == amod) return NULL;
                   3118:   d = (b > amod)? b - amod: p - (amod - b); /* (b - a) mod p */
                   3119:   (void)new_chunk(lgefint(pq)<<1); /* HACK */
                   3120:   ax = mului(mulssmod(d,qinv,p), q); /* d mod p, 0 mod q */
                   3121:   avma = av; return addii(a, ax); /* in ]-q, pq[ assuming a in -]-q,q[ */
                   3122: }
                   3123:
                   3124: /* centerlift(u mod p) */
1.2     ! noro     3125: long
1.1       noro     3126: u_center(ulong u, ulong p, ulong ps2)
                   3127: {
1.2     ! noro     3128:   return (long) (u > ps2)? u - p: u;
1.1       noro     3129: }
                   3130:
                   3131: GEN
                   3132: ZX_init_CRT(GEN Hp, ulong p, long v)
                   3133: {
                   3134:   long i, l = lgef(Hp), lim = (long)(p>>1);
                   3135:   GEN H = cgetg(l, t_POL);
                   3136:   H[1] = evalsigne(1)|evallgef(l)|evalvarn(v);
                   3137:   for (i=2; i<l; i++)
1.2     ! noro     3138:     H[i] = lstoi(u_center(Hp[i], p, lim));
1.1       noro     3139:   return H;
                   3140: }
                   3141:
                   3142: /* assume lg(Hp) > 1 */
                   3143: GEN
                   3144: ZM_init_CRT(GEN Hp, ulong p)
                   3145: {
                   3146:   long i,j, m = lg(Hp[1]), l = lg(Hp), lim = (long)(p>>1);
                   3147:   GEN c,cp,H = cgetg(l, t_MAT);
                   3148:   for (j=1; j<l; j++)
                   3149:   {
                   3150:     cp = (GEN)Hp[j];
                   3151:     c = cgetg(m, t_COL);
                   3152:     H[j] = (long)c;
1.2     ! noro     3153:     for (i=1; i<l; i++) c[i] = lstoi(u_center(cp[i],p, lim));
1.1       noro     3154:   }
                   3155:   return H;
                   3156: }
                   3157:
                   3158: int
                   3159: Z_incremental_CRT(GEN *H, ulong Hp, GEN q, GEN qp, ulong p)
                   3160: {
                   3161:   GEN h, lim = shifti(qp,-1);
                   3162:   ulong qinv = u_invmod(umodiu(q,p), p);
                   3163:   int stable = 1;
                   3164:   h = u_chrem_coprime(*H,Hp,q,p,qinv,qp);
                   3165:   if (h)
                   3166:   {
                   3167:     if (cmpii(h,lim) > 0) h = subii(h,qp);
                   3168:     *H = h; stable = 0;
                   3169:   }
                   3170:   return stable;
                   3171: }
                   3172:
                   3173: int
1.2     ! noro     3174: ZX_incremental_CRT(GEN *ptH, GEN Hp, GEN q, GEN qp, ulong p)
1.1       noro     3175: {
1.2     ! noro     3176:   GEN H = *ptH, h, lim = shifti(qp,-1);
1.1       noro     3177:   ulong qinv = u_invmod(umodiu(q,p), p);
                   3178:   long i, l = lgef(H), lp = lgef(Hp);
                   3179:   int stable = 1;
1.2     ! noro     3180:
        !          3181:   if (l < lp)
        !          3182:   { /* degree increases */
        !          3183:     GEN x = cgetg(lp, t_POL);
        !          3184:     for (i=1; i<l; i++) x[i] = H[i];
        !          3185:     for (   ; i<lp; i++)
        !          3186:     {
        !          3187:       h = stoi(Hp[i]);
        !          3188:       if (cmpii(h,lim) > 0) h = subii(h,qp);
        !          3189:       x[i] = (long)h;
        !          3190:     }
        !          3191:     setlgef(x,lp); *ptH = H = x;
        !          3192:     stable = 0; lp = l;
        !          3193:   }
1.1       noro     3194:   for (i=2; i<lp; i++)
                   3195:   {
                   3196:     h = u_chrem_coprime((GEN)H[i],Hp[i],q,p,qinv,qp);
                   3197:     if (h)
                   3198:     {
                   3199:       if (cmpii(h,lim) > 0) h = subii(h,qp);
                   3200:       H[i] = (long)h; stable = 0;
                   3201:     }
                   3202:   }
                   3203:   for (   ; i<l; i++)
                   3204:   {
                   3205:     h = u_chrem_coprime((GEN)H[i],   0,q,p,qinv,qp);
                   3206:     if (h)
                   3207:     {
                   3208:       if (cmpii(h,lim) > 0) h = subii(h,qp);
                   3209:       H[i] = (long)h; stable = 0;
                   3210:     }
                   3211:   }
                   3212:   return stable;
                   3213: }
                   3214:
                   3215: int
                   3216: ZM_incremental_CRT(GEN H, GEN Hp, GEN q, GEN qp, ulong p)
                   3217: {
                   3218:   GEN h, lim = shifti(qp,-1);
                   3219:   ulong qinv = u_invmod(umodiu(q,p), p);
                   3220:   long i,j, l = lg(H), m = lg(H[1]);
                   3221:   int stable = 1;
                   3222:   for (j=1; j<l; j++)
                   3223:     for (i=1; i<m; i++)
                   3224:     {
                   3225:       h = u_chrem_coprime(gcoeff(H,i,j), coeff(Hp,i,j),q,p,qinv,qp);
                   3226:       if (h)
                   3227:       {
                   3228:         if (cmpii(h,lim) > 0) h = subii(h,qp);
                   3229:         coeff(H,i,j) = (long)h; stable = 0;
                   3230:       }
                   3231:     }
                   3232:   return stable;
                   3233: }
                   3234:
                   3235: /* returns a polynomial in variable v, whose coeffs correspond to the digits
                   3236:  * of m (in base p) */
                   3237: GEN
                   3238: stopoly(long m, long p, long v)
                   3239: {
                   3240:   GEN y = cgetg(BITS_IN_LONG + 2, t_POL);
                   3241:   long l=2;
                   3242:
                   3243:   do { y[l++] = lstoi(m%p); m=m/p; } while (m);
                   3244:   y[1] = evalsigne(1)|evallgef(l)|evalvarn(v);
                   3245:   return y;
                   3246: }
                   3247:
                   3248: GEN
                   3249: stopoly_gen(GEN m, GEN p, long v)
                   3250: {
                   3251:   GEN y = cgetg(bit_accuracy(lgefint(m))+2, t_POL);
                   3252:   long l=2;
                   3253:
                   3254:   do { y[l++] = lmodii(m,p); m=divii(m,p); } while (signe(m));
                   3255:   y[1] = evalsigne(1)|evallgef(l)|evalvarn(v);
                   3256:   return y;
                   3257: }
                   3258:
                   3259: /* separate from u_FpX_divrem for maximal speed. Implicitly malloc = 0  */
                   3260: GEN
                   3261: u_FpX_rem(GEN x, GEN y, ulong p)
                   3262: {
                   3263:   GEN z, c;
                   3264:   long dx,dy,dz,i,j;
                   3265:   ulong p1,inv;
                   3266:
1.2     ! noro     3267:   dy = degpol(y); if (!dy) return u_zeropol();
1.1       noro     3268:   dx = degpol(x);
1.2     ! noro     3269:   dz = dx-dy; if (dz < 0) return u_copy(x);
1.1       noro     3270:   x += 2;
                   3271:   y += 2;
1.2     ! noro     3272:   z = u_mallocpol(dz) + 2;
1.1       noro     3273:   inv = y[dy];
                   3274:   if (inv != 1UL) inv = u_invmod(inv,p);
                   3275:
1.2     ! noro     3276:   c = u_getpol(dy) + 2;
1.1       noro     3277:   if (u_OK_ULONG(p))
                   3278:   {
                   3279:     z[dz] = (inv*x[dx]) % p;
                   3280:     for (i=dx-1; i>=dy; --i)
                   3281:     {
                   3282:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   3283:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   3284:       {
                   3285:         p1 += z[j]*y[i-j];
1.2     ! noro     3286:         if (p1 & HIGHBIT) p1 %= p;
1.1       noro     3287:       }
                   3288:       p1 %= p;
                   3289:       z[i-dy] = p1? ((p - p1)*inv) % p: 0;
                   3290:     }
                   3291:     for (i=0; i<dy; i++)
                   3292:     {
                   3293:       p1 = z[0]*y[i];
                   3294:       for (j=1; j<=i && j<=dz; j++)
                   3295:       {
                   3296:         p1 += z[j]*y[i-j];
1.2     ! noro     3297:         if (p1 & HIGHBIT) p1 %= p;
1.1       noro     3298:       }
                   3299:       c[i] = subssmod(x[i], p1%p, p);
                   3300:     }
                   3301:   }
                   3302:   else
                   3303:   {
                   3304:     z[dz] = mulssmod(inv, x[dx], p);
                   3305:     for (i=dx-1; i>=dy; --i)
                   3306:     {
                   3307:       p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
                   3308:       for (j=i-dy+1; j<=i && j<=dz; j++)
                   3309:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   3310:       z[i-dy] = p1? mulssmod(p - p1, inv, p): 0;
                   3311:     }
                   3312:     for (i=0; i<dy; i++)
                   3313:     {
                   3314:       p1 = mulssmod(z[0],y[i],p);
                   3315:       for (j=1; j<=i && j<=dz; j++)
                   3316:         p1 = addssmod(p1, mulssmod(z[j],y[i-j],p), p);
                   3317:       c[i] = subssmod(x[i], p1, p);
                   3318:     }
                   3319:   }
                   3320:   i = dy-1; while (i>=0 && !c[i]) i--;
                   3321:   free(z-2); return u_normalizepol(c-2, i+3);
                   3322: }
                   3323:
                   3324: ulong
                   3325: u_FpX_resultant(GEN a, GEN b, ulong p)
                   3326: {
                   3327:   long da,db,dc,cnt;
1.2     ! noro     3328:   ulong lb, res = 1UL;
        !          3329:   gpmem_t av;
1.1       noro     3330:   GEN c;
                   3331:
                   3332:   if (!signe(a) || !signe(b)) return 0;
                   3333:   da = degpol(a);
                   3334:   db = degpol(b);
                   3335:   if (db > da)
                   3336:   {
                   3337:     swapspec(a,b, da,db);
1.2     ! noro     3338:     if (both_odd(da,db)) res = p-res;
1.1       noro     3339:   }
                   3340:   if (!da) return 1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
                   3341:   cnt = 0; av = avma;
                   3342:   while (db)
                   3343:   {
                   3344:     lb = b[db+2];
                   3345:     c = u_FpX_rem(a,b, p);
                   3346:     a = b; b = c; dc = degpol(c);
                   3347:     if (dc < 0) { avma = av; return 0; }
                   3348:
1.2     ! noro     3349:     if (both_odd(da,db)) res = p - res;
1.1       noro     3350:     if (lb != 1) res = mulssmod(res, powuumod(lb, da - dc, p), p);
                   3351:     if (++cnt == 4) { cnt = 0; avma = av; }
                   3352:     da = db; /* = degpol(a) */
                   3353:     db = dc; /* = degpol(b) */
                   3354:   }
                   3355:   avma = av; return mulssmod(res, powuumod(b[2], da, p), p);
                   3356: }
                   3357:
1.2     ! noro     3358: static GEN
        !          3359: muliimod(GEN x, GEN y, GEN p)
        !          3360: {
        !          3361:   return modii(mulii(x,y), p);
        !          3362: }
        !          3363:
        !          3364: #define FpX_rem(x,y,p) FpX_divres((x),(y),(p),ONLY_REM)
        !          3365:
        !          3366: /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab+a+r), with R=A%B, a=deg(A) ...*/
        !          3367: GEN
        !          3368: FpX_resultant(GEN a, GEN b, GEN p)
        !          3369: {
        !          3370:   long da,db,dc,cnt;
        !          3371:   gpmem_t av, lim;
        !          3372:   GEN c,lb, res = gun;
        !          3373:
        !          3374:   if (!signe(a) || !signe(b)) return gzero;
        !          3375:   da = degpol(a);
        !          3376:   db = degpol(b);
        !          3377:   if (db > da)
        !          3378:   {
        !          3379:     swapspec(a,b, da,db);
        !          3380:     if (both_odd(da,db)) res = subii(p, res);
        !          3381:   }
        !          3382:   if (!da) return gun; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
        !          3383:   cnt = 0; av = avma; lim = stack_lim(av,2);
        !          3384:   while (db)
        !          3385:   {
        !          3386:     lb = (GEN)b[db+2];
        !          3387:     c = FpX_rem(a,b, p);
        !          3388:     a = b; b = c; dc = degpol(c);
        !          3389:     if (dc < 0) { avma = av; return 0; }
        !          3390:
        !          3391:     if (both_odd(da,db)) res = subii(p, res);
        !          3392:     if (!gcmp1(lb)) res = muliimod(res, powgumod(lb, da - dc, p), p);
        !          3393:     if (low_stack(lim,stack_lim(av,2)))
        !          3394:     {
        !          3395:       if (DEBUGMEM>1) err(warnmem,"FpX_resultant (da = %ld)",da);
        !          3396:       gerepileall(av,3, &a,&b,&res);
        !          3397:     }
        !          3398:     da = db; /* = degpol(a) */
        !          3399:     db = dc; /* = degpol(b) */
        !          3400:   }
        !          3401:   res = muliimod(res, powgumod((GEN)b[2], da, p), p);
        !          3402:   return gerepileuptoint(av, res);
        !          3403: }
        !          3404:
1.1       noro     3405: /* If resultant is 0, *ptU and *ptU are not set */
                   3406: ulong
                   3407: u_FpX_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV)
                   3408: {
                   3409:   GEN z,q,u,v, x = a, y = b;
1.2     ! noro     3410:   ulong lb, res = 1UL;
        !          3411:   gpmem_t av = avma;
1.1       noro     3412:   long dx,dy,dz;
                   3413:
                   3414:   if (!signe(x) || !signe(y)) return 0;
                   3415:   dx = degpol(x);
                   3416:   dy = degpol(y);
                   3417:   if (dy > dx)
                   3418:   {
                   3419:     swap(x,y); lswap(dx,dy); pswap(ptU, ptV);
                   3420:     a = x; b = y;
1.2     ! noro     3421:     if (both_odd(dx,dy)) res = p-res;
1.1       noro     3422:   }
1.2     ! noro     3423:   u = u_zeropol();
        !          3424:   v = u_scalarpol(1); /* v = 1 */
1.1       noro     3425:   while (dy)
                   3426:   { /* b u = x (a), b v = y (a) */
                   3427:     lb = y[dy+2];
1.2     ! noro     3428:     q = u_FpX_divrem(x,y, p, &z);
1.1       noro     3429:     x = y; y = z; /* (x,y) = (y, x - q y) */
                   3430:     dz = degpol(z); if (dz < 0) { avma = av; return 0; }
                   3431:     z = u_FpX_sub(u, u_FpX_mul(q,v, p), p);
                   3432:     u = v; v = z; /* (u,v) = (v, u - q v) */
                   3433:
1.2     ! noro     3434:     if (both_odd(dx,dy)) res = p - res;
1.1       noro     3435:     if (lb != 1) res = mulssmod(res, powuumod(lb, dx-dz, p), p);
                   3436:     dx = dy; /* = degpol(x) */
                   3437:     dy = dz; /* = degpol(y) */
                   3438:   }
                   3439:   res = mulssmod(res, powuumod(y[2], dx, p), p);
                   3440:   lb = mulssmod(res, u_invmod(y[2],p), p);
1.2     ! noro     3441:   v = gerepileupto(av, u_FpX_Fp_mul(v, lb, p));
1.1       noro     3442:   av = avma;
1.2     ! noro     3443:   u = u_FpX_sub(u_scalarpol(res), u_FpX_mul(b,v,p), p);
1.1       noro     3444:   u = gerepileupto(av, u_FpX_div(u,a,p)); /* = (res - b v) / a */
                   3445:   *ptU = u;
                   3446:   *ptV = v; return res;
                   3447: }
                   3448:
                   3449: /* assuming the PRS finishes on a degree 1 polynomial C0 + C1X, with "generic"
                   3450:  * degree sequence as given by dglist, set *Ci and return resultant(a,b) */
                   3451: ulong
                   3452: u_FpX_resultant_all(GEN a, GEN b, long *C0, long *C1, GEN dglist, ulong p)
                   3453: {
                   3454:   long da,db,dc,cnt,ind;
1.2     ! noro     3455:   ulong lb, cx = 1, res = 1UL;
        !          3456:   gpmem_t av;
1.1       noro     3457:   GEN c;
                   3458:
                   3459:   if (C0) { *C0 = 1; *C1 = 0; }
                   3460:   if (!signe(a) || !signe(b)) return 0;
                   3461:   da = degpol(a);
                   3462:   db = degpol(b);
                   3463:   if (db > da)
                   3464:   {
                   3465:     swapspec(a,b, da,db);
1.2     ! noro     3466:     if (both_odd(da,db)) res = p-res;
1.1       noro     3467:   }
                   3468:   /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
                   3469:   if (!da) return 1;
                   3470:   cnt = ind = 0; av = avma;
                   3471:   while (db)
                   3472:   {
                   3473:     lb = b[db+2];
                   3474:     c = u_FpX_rem(a,b, p);
                   3475:     a = b; b = c; dc = degpol(c);
                   3476:     if (dc < 0) { avma = av; return 0; }
                   3477:
                   3478:     ind++;
                   3479:     if (C0)
                   3480:     { /* check that Euclidean remainder sequence doesn't degenerate */
                   3481:       if (dc != dglist[ind]) { avma = av; return 0; }
                   3482:       /* update resultant */
1.2     ! noro     3483:       if (both_odd(da,db)) res = p-res;
1.1       noro     3484:       if (lb != 1)
                   3485:       {
                   3486:         ulong t = powuumod(lb, da - dc, p);
                   3487:         res = mulssmod(res, t, p);
                   3488:         if (dc) cx = mulssmod(cx, t, p);
                   3489:       }
                   3490:     }
                   3491:     else
                   3492:     {
                   3493:       if (dc > dglist[ind]) dglist[ind] = dc;
                   3494:     }
                   3495:     if (++cnt == 4) { cnt = 0; avma = av; }
                   3496:     da = db; /* = degpol(a) */
                   3497:     db = dc; /* = degpol(b) */
                   3498:   }
                   3499:   if (!C0)
                   3500:   {
                   3501:     if (ind+1 > lg(dglist)) setlg(dglist,ind+1);
                   3502:     return 0;
                   3503:   }
                   3504:
                   3505:   if (da == 1) /* last non-constant polynomial has degree 1 */
                   3506:   {
                   3507:     *C0 = mulssmod(cx, a[2], p);
                   3508:     *C1 = mulssmod(cx, a[3], p);
                   3509:     lb = b[2];
                   3510:   } else lb = powuumod(b[2], da, p);
                   3511:   avma = av; return mulssmod(res, lb, p);
                   3512: }
                   3513:
                   3514: static ulong global_pp;
                   3515: static GEN
                   3516: _u_FpX_mul(GEN a, GEN b)
                   3517: {
                   3518:   return u_FpX_mul(a,b, global_pp);
                   3519: }
                   3520:
                   3521: /* compute prod (x - a[i]) */
                   3522: GEN
                   3523: u_FpV_roots_to_pol(GEN a, ulong p)
                   3524: {
                   3525:   long i,k,lx = lg(a);
                   3526:   GEN p1,p2;
                   3527:   if (lx == 1) return polun[0];
                   3528:   p1 = cgetg(lx, t_VEC); global_pp = p;
                   3529:   for (k=1,i=1; i<lx-1; i+=2)
                   3530:   {
                   3531:     p2 = cgetg(5,t_VECSMALL); p1[k++] = (long)p2;
                   3532:     p2[2] = mulssmod(a[i], a[i+1], p);
1.2     ! noro     3533:     p2[3] = a[i] + a[i+1];
        !          3534:     if (p2[3] >= p) p2[3] -= p;
        !          3535:     if (p2[3]) p2[3] = p - p2[3]; /* - (a[i] + a[i+1]) mod p */
1.1       noro     3536:     p2[4] = 1; p2[1] = evallgef(5);
                   3537:   }
                   3538:   if (i < lx)
                   3539:   {
                   3540:     p2 = cgetg(4,t_POL); p1[k++] = (long)p2;
                   3541:     p2[1] = evallgef(4);
                   3542:     p2[2] = p - a[i];
                   3543:     p2[3] = 1;
                   3544:   }
                   3545:   setlg(p1, k); return divide_conquer_prod(p1, _u_FpX_mul);
                   3546: }
                   3547:
                   3548:
                   3549: /* u P(X) + v P(-X) */
                   3550: static GEN
                   3551: pol_comp(GEN P, GEN u, GEN v)
                   3552: {
                   3553:   long i, l = lgef(P);
                   3554:   GEN y = cgetg(l, t_POL);
                   3555:   for (i=2; i<l; i++)
                   3556:   {
                   3557:     GEN t = (GEN)P[i];
                   3558:     y[i] = gcmp0(t)? zero:
                   3559:                      (i&1)? lmul(t, gsub(u,v)) /*  odd degree */
                   3560:                           : lmul(t, gadd(u,v));/* even degree */
                   3561:   }
                   3562:   y[1] = P[1]; return normalizepol_i(y,l);
                   3563: }
                   3564:
                   3565: static GEN
                   3566: u_pol_comp(GEN P, ulong u, ulong v, ulong p)
                   3567: {
                   3568:   long i, l = lgef(P);
1.2     ! noro     3569:   GEN y = u_getpol(l-3);
1.1       noro     3570:   for (i=2; i<l; i++)
                   3571:   {
                   3572:     ulong t = P[i];
                   3573:     y[i] = (t == 0)? 0:
                   3574:                      (i&1)? mulssmod(t, u + (p - v), p)
                   3575:                           : mulssmod(t, u + v, p);
                   3576:   }
                   3577:   return u_normalizepol(y,l);
                   3578: }
                   3579:
1.2     ! noro     3580: extern GEN roots_to_pol(GEN a, long v);
1.1       noro     3581:
                   3582: GEN
                   3583: polint_triv(GEN xa, GEN ya)
                   3584: {
                   3585:   GEN P = NULL, Q = roots_to_pol(xa,0);
1.2     ! noro     3586:   long i, n = lg(xa);
        !          3587:   gpmem_t av = avma, lim = stack_lim(av, 2);
1.1       noro     3588:   for (i=1; i<n; i++)
                   3589:   {
                   3590:     GEN T,dP;
                   3591:     if (gcmp0((GEN)ya[i])) continue;
                   3592:     T = gdeuc(Q, gsub(polx[0], (GEN)xa[i]));
                   3593:     if (i < n-1 && absi_equal((GEN)xa[i], (GEN)xa[i+1]))
                   3594:     { /* x_i = -x_{i+1} */
                   3595:       T = gdiv(T, poleval(T, (GEN)xa[i]));
                   3596:       dP = pol_comp(T, (GEN)ya[i], (GEN)ya[i+1]);
                   3597:       i++;
                   3598:     }
                   3599:     else
                   3600:     {
                   3601:       dP = gmul((GEN)ya[i], T);
                   3602:       dP = gdiv(dP, poleval(T,(GEN)xa[i]));
                   3603:     }
                   3604:     P = P? gadd(P, dP): dP;
                   3605:     if (low_stack(lim,stack_lim(av,2)))
                   3606:     {
                   3607:       if (DEBUGMEM>1) err(warnmem,"polint_triv2 (i = %ld)",i);
                   3608:       P = gerepileupto(av, P);
                   3609:     }
                   3610:   }
                   3611:   return P? P: zeropol(0);
                   3612: }
                   3613:
                   3614: ulong
                   3615: u_FpX_eval(GEN x, ulong y, ulong p)
                   3616: {
                   3617:   ulong p1,r;
                   3618:   long i,j;
                   3619:   i=lgef(x)-1;
                   3620:   if (i<=2)
                   3621:     return (i==2)? x[2]: 0;
                   3622:   p1 = x[i];
                   3623:   /* specific attention to sparse polynomials (see poleval)*/
                   3624:   if (u_OK_ULONG(p))
                   3625:   {
                   3626:     for (i--; i>=2; i=j-1)
                   3627:     {
                   3628:       for (j=i; !x[j]; j--)
                   3629:         if (j==2)
                   3630:         {
                   3631:           if (i != j) y = powuumod(y, i-j+1, p);
                   3632:           return (p1 * y) % p;
                   3633:         }
                   3634:       r = (i==j)? y: powuumod(y, i-j+1, p);
                   3635:       p1 = ((p1*r) + x[j]) % p;
                   3636:     }
                   3637:   }
                   3638:   else
                   3639:   {
                   3640:     for (i--; i>=2; i=j-1)
                   3641:     {
                   3642:       for (j=i; !x[j]; j--)
                   3643:         if (j==2)
                   3644:         {
                   3645:           if (i != j) y = powuumod(y, i-j+1, p);
                   3646:           return mulssmod(p1, y, p);
                   3647:         }
                   3648:       r = (i==j)? y: powuumod(y, i-j+1, p);
                   3649:       p1 = addssmod(x[j], mulssmod(p1,r,p), p);
                   3650:     }
                   3651:   }
                   3652:   return p1;
                   3653: }
                   3654:
                   3655: static GEN
                   3656: u_FpX_div_by_X_x(GEN a, ulong x, ulong p)
                   3657: {
                   3658:   long l = lgef(a), i;
1.2     ! noro     3659:   GEN z = u_getpol(l-4), a0, z0;
1.1       noro     3660:   a0 = a + l-1;
                   3661:   z0 = z + l-2; *z0 = *a0--;
                   3662:   if (u_OK_ULONG(p))
                   3663:   {
                   3664:     for (i=l-3; i>1; i--) /* z[i] = (a[i+1] + x*z[i+1]) % p */
                   3665:     {
                   3666:       ulong t = (*a0-- + x *  *z0--) % p;
                   3667:       *z0 = t;
                   3668:     }
                   3669:   }
                   3670:   else
                   3671:   {
                   3672:     for (i=l-3; i>1; i--)
                   3673:     {
                   3674:       ulong t = addssmod(*a0--, mulssmod(x, *z0--, p), p);
                   3675:       *z0 = t;
                   3676:     }
                   3677:   }
                   3678:   return z;
                   3679: }
                   3680:
1.2     ! noro     3681: static GEN
        !          3682: FpX_div_by_X_x(GEN a, GEN x, GEN p)
        !          3683: {
        !          3684:   long l = lgef(a), i;
        !          3685:   GEN z = cgetg(l-1, t_POL), a0, z0;
        !          3686:   z[1] = evalsigne(1)|evalvarn(0)|evallgef(l-1);
        !          3687:   a0 = a + l-1;
        !          3688:   z0 = z + l-2; *z0 = *a0--;
        !          3689:   for (i=l-3; i>1; i--) /* z[i] = (a[i+1] + x*z[i+1]) % p */
        !          3690:   {
        !          3691:     GEN t = addii((GEN)*a0--, muliimod(x, (GEN)*z0--, p));
        !          3692:     *z0 = (long)t;
        !          3693:   }
        !          3694:   return z;
        !          3695: }
        !          3696:
1.1       noro     3697: /* xa, ya = t_VECSMALL */
                   3698: GEN
                   3699: u_FpV_polint(GEN xa, GEN ya, ulong p)
                   3700: {
                   3701:   GEN T,dP, P = NULL, Q = u_FpV_roots_to_pol(xa, p);
                   3702:   long i, n = lg(xa);
1.2     ! noro     3703:   ulong inv;
        !          3704:   gpmem_t av = avma;
1.1       noro     3705:   for (i=1; i<n; i++)
                   3706:   {
                   3707:     if (!ya[i]) continue;
                   3708:     T = u_FpX_div_by_X_x(Q, xa[i], p);
                   3709:     inv = u_invmod(u_FpX_eval(T,xa[i], p), p);
                   3710:     if (i < n-1 && (ulong)(xa[i] + xa[i+1]) == p)
                   3711:     {
                   3712:       dP = u_pol_comp(T, mulssmod(ya[i],inv,p), mulssmod(ya[i+1],inv,p), p);
                   3713:       i++; /* x_i = -x_{i+1} */
                   3714:     }
                   3715:     else
1.2     ! noro     3716:       dP = u_FpX_Fp_mul(T, mulssmod(ya[i],inv,p), p);
1.1       noro     3717:     P = P? u_FpX_add(P, dP, p): dP;
                   3718:   }
1.2     ! noro     3719:   return P? gerepileupto(av, P): u_zeropol();
        !          3720: }
        !          3721:
        !          3722: GEN
        !          3723: FpV_polint(GEN xa, GEN ya, GEN p)
        !          3724: {
        !          3725:   GEN inv,T,dP, P = NULL, Q = FpV_roots_to_pol(xa, p, 0);
        !          3726:   long i, n = lg(xa);
        !          3727:   gpmem_t av, lim;
        !          3728:   av = avma; lim = stack_lim(av,2);
        !          3729:   for (i=1; i<n; i++)
        !          3730:   {
        !          3731:     if (!signe(ya[i])) continue;
        !          3732:     T = FpX_div_by_X_x(Q, (GEN)xa[i], p);
        !          3733:     inv = mpinvmod(FpX_eval(T,(GEN)xa[i], p), p);
        !          3734:     if (i < n-1 && egalii(addii((GEN)xa[i], (GEN)xa[i+1]), p))
        !          3735:     {
        !          3736:       dP = pol_comp(T, muliimod((GEN)ya[i],  inv,p),
        !          3737:                        muliimod((GEN)ya[i+1],inv,p));
        !          3738:       i++; /* x_i = -x_{i+1} */
        !          3739:     }
        !          3740:     else
        !          3741:       dP = FpX_Fp_mul(T, muliimod((GEN)ya[i],inv,p), p);
        !          3742:     P = P? FpX_add(P, dP, p): dP;
        !          3743:     if (low_stack(lim, stack_lim(av,2)))
        !          3744:     {
        !          3745:       if (DEBUGMEM>1) err(warnmem,"FpV_polint");
        !          3746:       if (!P) avma = av; else P = gerepileupto(av, P);
        !          3747:     }
        !          3748:   }
        !          3749:   return P? P: zeropol(0);
1.1       noro     3750: }
                   3751:
                   3752: static void
                   3753: u_FpV_polint_all(GEN xa, GEN ya, GEN C0, GEN C1, ulong p)
                   3754: {
                   3755:   GEN T,Q = u_FpV_roots_to_pol(xa, p);
                   3756:   GEN dP  = NULL,  P = NULL;
                   3757:   GEN dP0 = NULL, P0= NULL;
                   3758:   GEN dP1 = NULL, P1= NULL;
                   3759:   long i, n = lg(xa);
                   3760:   ulong inv;
                   3761:   for (i=1; i<n; i++)
                   3762:   {
                   3763:     T = u_FpX_div_by_X_x(Q, xa[i], p);
                   3764:     inv = u_invmod(u_FpX_eval(T,xa[i], p), p);
                   3765:
1.2     ! noro     3766:     if (ya[i])
        !          3767:     {
        !          3768:       dP = u_FpX_Fp_mul(T, mulssmod(ya[i],inv,p), p);
        !          3769:       P = P ? u_FpX_add(P , dP , p): dP;
        !          3770:     }
        !          3771:     if (C0[i])
1.1       noro     3772:     {
1.2     ! noro     3773:       dP0= u_FpX_Fp_mul(T, mulssmod(C0[i],inv,p), p);
        !          3774:       P0= P0? u_FpX_add(P0, dP0, p): dP0;
1.1       noro     3775:     }
1.2     ! noro     3776:     if (C1[i])
1.1       noro     3777:     {
1.2     ! noro     3778:       dP1= u_FpX_Fp_mul(T, mulssmod(C1[i],inv,p), p);
        !          3779:       P1= P1? u_FpX_add(P1, dP1, p): dP1;
1.1       noro     3780:     }
                   3781:   }
1.2     ! noro     3782:   ya[1] = (long) (P ? P : u_zeropol());
        !          3783:   C0[1] = (long) (P0? P0: u_zeropol());
        !          3784:   C1[1] = (long) (P1? P1: u_zeropol());
1.1       noro     3785: }
                   3786:
                   3787: /* b a vector of polynomials representing B in Fp[X][Y], evaluate at X = x,
                   3788:  * Return 0 in case of degree drop. */
                   3789: static GEN
1.2     ! noro     3790: u_vec_FpX_eval(GEN b, ulong x, ulong p)
1.1       noro     3791: {
                   3792:   GEN z;
                   3793:   long i, lb = lgef(b);
                   3794:   ulong leadz = u_FpX_eval((GEN)b[lb-1], x, p);
1.2     ! noro     3795:   if (!leadz) return u_zeropol();
1.1       noro     3796:
1.2     ! noro     3797:   z = u_getpol(lb-3);
1.1       noro     3798:   for (i=2; i<lb-1; i++)
                   3799:     z[i] = u_FpX_eval((GEN)b[i], x, p);
                   3800:   z[i] = leadz; return z;
                   3801: }
                   3802:
                   3803: /* as above, but don't care about degree drop */
                   3804: static GEN
1.2     ! noro     3805: u_vec_FpX_eval_gen(GEN b, ulong x, ulong p, int *drop)
1.1       noro     3806: {
                   3807:   GEN z;
                   3808:   long i, lb = lgef(b);
1.2     ! noro     3809:   z = u_getpol(lb-3);
1.1       noro     3810:   for (i=2; i<lb; i++)
                   3811:     z[i] = u_FpX_eval((GEN)b[i], x, p);
                   3812:   z = u_normalizepol(z, lb);
                   3813:   *drop = lb - lgef(z);
                   3814:   return z;
                   3815: }
                   3816:
1.2     ! noro     3817: static GEN
        !          3818: vec_FpX_eval_gen(GEN b, GEN x, GEN p, int *drop)
        !          3819: {
        !          3820:   GEN z;
        !          3821:   long i, lb = lgef(b);
        !          3822:   z = cgetg(lb, t_POL);
        !          3823:   z[1] = b[1];
        !          3824:   for (i=2; i<lb; i++)
        !          3825:     z[i] = (long)FpX_eval((GEN)b[i], x, p);
        !          3826:   z = normalizepol_i(z, lb);
        !          3827:   *drop = lb - lgef(z);
        !          3828:   return z;
        !          3829: }
        !          3830:
1.1       noro     3831: /* Interpolate at roots of 1 and use Hadamard bound for univariate resultant:
1.2     ! noro     3832:  *   bound = N_2(A)^degpol B N_2(B)^degpol(A),  where
        !          3833:  *     N_2(A) = sqrt(sum (N_1(Ai))^2)
        !          3834:  * Return e such that Res(A, B) < 2^e */
1.1       noro     3835: ulong
                   3836: ZY_ZXY_ResBound(GEN A, GEN B)
                   3837: {
1.2     ! noro     3838:   gpmem_t av = avma;
1.1       noro     3839:   GEN a = gzero, b = gzero, run = realun(DEFAULTPREC);
                   3840:   long i , lA = lgef(A), lB = lgef(B);
                   3841:   for (i=2; i<lA; i++) a = addii(a, sqri((GEN)A[i]));
                   3842:   for (i=2; i<lB; i++)
                   3843:   {
                   3844:     GEN t = (GEN)B[i];
                   3845:     if (typ(t) == t_POL) t = gnorml1(t, 0);
                   3846:     b = addii(b, sqri(t));
                   3847:   }
1.2     ! noro     3848:   a = mulir(a,run);
        !          3849:   b = mulir(b,run);
        !          3850:   b = gmul(gpowgs(a, degpol(B)), gpowgs(b, degpol(A)));
1.1       noro     3851:   avma = av; return 1 + (gexpo(b)>>1);
                   3852: }
                   3853:
1.2     ! noro     3854: /* return Res(a(Y), b(n,Y)) over Fp. la = leading_term(a) [for efficiency] */
        !          3855: static ulong
        !          3856: u_FpX_resultant_after_eval(GEN a, GEN b, ulong n, ulong p, ulong la)
        !          3857: {
        !          3858:   int drop;
        !          3859:   GEN ev = u_vec_FpX_eval_gen(b, n, p, &drop);
        !          3860:   ulong r = u_FpX_resultant(a, ev, p);
        !          3861:   if (drop && la != 1) r = mulssmod(r, powuumod(la, drop,p),p);
        !          3862:   return r;
        !          3863: }
        !          3864: static GEN
        !          3865: FpX_resultant_after_eval(GEN a, GEN b, GEN n, GEN p, GEN la)
        !          3866: {
        !          3867:   int drop;
        !          3868:   GEN ev = vec_FpX_eval_gen(b, n, p, &drop);
        !          3869:   GEN r = FpX_resultant(a, ev, p);
        !          3870:   if (drop && !gcmp1(la)) r = muliimod(r, powgumod(la, drop,p),p);
        !          3871:   return r;
        !          3872: }
        !          3873:
        !          3874: /* assume dres := deg(Res_Y(a,b), X) <= deg(a,Y) * deg(b,X) < p */
        !          3875: static GEN
        !          3876: u_FpY_FpXY_resultant(GEN a, GEN b, ulong p, long dres)
        !          3877: {
        !          3878:   ulong la;
        !          3879:   long i,n,nmax;
        !          3880:   GEN x,y;
        !          3881:
        !          3882:   nmax = (dres+1)>>1;
        !          3883:   la = (ulong)leading_term(a);
        !          3884:   x = cgetg(dres+2, t_VECSMALL);
        !          3885:   y = cgetg(dres+2, t_VECSMALL);
        !          3886:  /* Evaluate at 0 (if dres even) and +/- n, so that P_n(X) = P_{-n}(-X),
        !          3887:   * where P_i is Lagrange polynomial: P_i(j) = 1 if i=j, 0 otherwise */
        !          3888:   for (i=0,n = 1; n <= nmax; n++)
        !          3889:   {
        !          3890:     i++; x[i] = n;   y[i] = u_FpX_resultant_after_eval(a,b, x[i], p,la);
        !          3891:     i++; x[i] = p-n; y[i] = u_FpX_resultant_after_eval(a,b, x[i], p,la);
        !          3892:   }
        !          3893:   if (i == dres)
        !          3894:   {
        !          3895:     i++; x[i] = 0;   y[i] = u_FpX_resultant_after_eval(a,b, x[i], p,la);
        !          3896:   }
        !          3897:   return u_FpV_polint(x,y, p);
        !          3898: }
        !          3899:
        !          3900: /* x^n mod p */
        !          3901: ulong
        !          3902: u_powmod(ulong x, long n, ulong p)
        !          3903: {
        !          3904:   ulong y = 1, z;
        !          3905:   long m;
        !          3906:
        !          3907:   if (n < 0) { n = -n; x = u_invmod(x, p); }
        !          3908:   m = n;
        !          3909:   z = x;
        !          3910:   for (;;)
        !          3911:   {
        !          3912:     if (m&1) y = mulssmod(y,z, p);
        !          3913:     m >>= 1; if (!m) return y;
        !          3914:     z = mulssmod(z,z, p);
        !          3915:   }
        !          3916: }
        !          3917:
        !          3918: /* x^n mod p, assume n > 0 */
        !          3919: static GEN
        !          3920: u_FpX_pow(GEN x, long n, ulong p)
        !          3921: {
        !          3922:   GEN y = u_scalarpol(1), z;
        !          3923:   long m;
        !          3924:   m = n;
        !          3925:   z = x;
        !          3926:   for (;;)
        !          3927:   {
        !          3928:     if (m&1) y = u_FpX_mul(y,z, p);
        !          3929:     m >>= 1; if (!m) return y;
        !          3930:     z = u_FpX_mul(z,z, p);
        !          3931:   }
        !          3932: }
        !          3933:
        !          3934: static GEN
        !          3935: u_FpXX_pseudorem(GEN x, GEN y, ulong p)
        !          3936: {
        !          3937:   long vx = varn(x), dx, dy, dz, i, lx, dp;
        !          3938:   gpmem_t av = avma, av2, lim;
        !          3939:
        !          3940:   if (!signe(y)) err(talker,"euclidean division by zero (pseudorem)");
        !          3941:   (void)new_chunk(2);
        !          3942:   dx=degpol(x); x = revpol(x);
        !          3943:   dy=degpol(y); y = revpol(y); dz=dx-dy; dp = dz+1;
        !          3944:   av2 = avma; lim = stack_lim(av2,1);
        !          3945:   for (;;)
        !          3946:   {
        !          3947:     x[0] = (long)u_FpX_neg((GEN)x[0], p); dp--;
        !          3948:     for (i=1; i<=dy; i++)
        !          3949:       x[i] = (long)u_FpX_add( u_FpX_mul((GEN)y[0], (GEN)x[i], p),
        !          3950:                               u_FpX_mul((GEN)x[0], (GEN)y[i], p), p );
        !          3951:     for (   ; i<=dx; i++)
        !          3952:       x[i] = (long)u_FpX_mul((GEN)y[0], (GEN)x[i], p);
        !          3953:     do { x++; dx--; } while (dx >= 0 && !signe((GEN)x[0]));
        !          3954:     if (dx < dy) break;
        !          3955:     if (low_stack(lim,stack_lim(av2,1)))
        !          3956:     {
        !          3957:       if(DEBUGMEM>1) err(warnmem,"pseudorem dx = %ld >= %ld",dx,dy);
        !          3958:       gerepilemanycoeffs(av2,x,dx+1);
        !          3959:     }
        !          3960:   }
        !          3961:   if (dx < 0) return u_zeropol();
        !          3962:   lx = dx+3; x -= 2;
        !          3963:   x[0]=evaltyp(t_POL) | evallg(lx);
        !          3964:   x[1]=evalsigne(1) | evalvarn(vx) | evallgef(lx);
        !          3965:   x = revpol(x) - 2;
        !          3966:   if (dp)
        !          3967:   { /* multiply by y[0]^dp   [beware dummy vars from FpY_FpXY_resultant] */
        !          3968:     GEN t = u_FpX_pow((GEN)y[0], dp, p);
        !          3969:     for (i=2; i<lx; i++)
        !          3970:       x[i] = (long)u_FpX_mul((GEN)x[i], t, p);
        !          3971:   }
        !          3972:   return gerepilecopy(av, x);
        !          3973: }
        !          3974:
        !          3975: static GEN
        !          3976: u_FpX_divexact(GEN x, GEN y, ulong p)
        !          3977: {
        !          3978:   long i, l;
        !          3979:   GEN z;
        !          3980:   if (degpol(y) == 0)
        !          3981:   {
        !          3982:     ulong t = (ulong)y[2];
        !          3983:     if (t == 1) return x;
        !          3984:     t = u_invmod(t, p);
        !          3985:     l = lgef(x); z = cgetg(l, t_POL); z[1] = x[1];
        !          3986:     for (i=2; i<l; i++) z[i] = (long)u_FpX_Fp_mul((GEN)x[i],t,p);
        !          3987:   }
        !          3988:   else
        !          3989:   {
        !          3990:     l = lgef(x); z = cgetg(l, t_POL); z[1] = x[1];
        !          3991:     for (i=2; i<l; i++) z[i] = (long)u_FpX_div((GEN)x[i],y,p);
        !          3992:   }
        !          3993:   return z;
        !          3994: }
        !          3995:
        !          3996: static GEN
        !          3997: u_FpYX_subres(GEN u, GEN v, ulong p)
        !          3998: {
        !          3999:   gpmem_t av = avma, av2, lim;
        !          4000:   long degq,dx,dy,du,dv,dr,signh;
        !          4001:   GEN z,g,h,r,p1;
        !          4002:
        !          4003:   dx=degpol(u); dy=degpol(v); signh=1;
        !          4004:   if (dx < dy)
        !          4005:   {
        !          4006:     swap(u,v); lswap(dx,dy);
        !          4007:     if (both_odd(dx, dy)) signh = -signh;
        !          4008:   }
        !          4009:   if (dy < 0) return gzero;
        !          4010:   if (dy==0) return gerepileupto(av, u_FpX_pow((GEN)v[2],dx,p));
        !          4011:
        !          4012:   g = h = u_scalarpol(1); av2 = avma; lim = stack_lim(av2,1);
        !          4013:   for(;;)
        !          4014:   {
        !          4015:     r = u_FpXX_pseudorem(u,v,p); dr = lgef(r);
        !          4016:     if (dr == 2) { avma = av; return gzero; }
        !          4017:     du = degpol(u); dv = degpol(v); degq = du-dv;
        !          4018:     u = v; p1 = g; g = leading_term(u);
        !          4019:     switch(degq)
        !          4020:     {
        !          4021:       case 0: break;
        !          4022:       case 1:
        !          4023:         p1 = u_FpX_mul(h,p1, p); h = g; break;
        !          4024:       default:
        !          4025:         p1 = u_FpX_mul(u_FpX_pow(h,degq,p), p1, p);
        !          4026:         h = u_FpX_div(u_FpX_pow(g,degq,p), u_FpX_pow(h,degq-1,p), p);
        !          4027:     }
        !          4028:     if (both_odd(du,dv)) signh = -signh;
        !          4029:     v = u_FpX_divexact(r, p1, p);
        !          4030:     if (dr==3) break;
        !          4031:     if (low_stack(lim,stack_lim(av2,1)))
        !          4032:     {
        !          4033:       if(DEBUGMEM>1) err(warnmem,"subresall, dr = %ld",dr);
        !          4034:       gerepileall(av2,4, &u, &v, &g, &h);
        !          4035:     }
        !          4036:   }
        !          4037:   z = (GEN)v[2];
        !          4038:   if (dv > 1) z = u_FpX_div(u_FpX_pow(z,dv,p), u_FpX_pow(h,dv-1,p), p);
        !          4039:   if (signh < 0) z = u_FpX_neg(z,p);
        !          4040:   return gerepileupto(av, z);
        !          4041: }
        !          4042:
        !          4043: /* return a t_POL (in dummy variable 0) whose coeffs are the coeffs of b,
        !          4044:  * in variable v. This is an incorrect PARI object if initially varn(b) < v.
        !          4045:  * We could return a vector of coeffs, but it is convenient to have degpol()
        !          4046:  * and friends available. Even in that case, it will behave nicely with all
        !          4047:  * functions treating a polynomial as a vector of coeffs (eg poleval).
        !          4048:  * FOR INTERNAL USE! */
        !          4049: GEN
        !          4050: swap_vars(GEN b0, long v)
        !          4051: {
        !          4052:   long i, n = poldegree(b0, v);
        !          4053:   GEN b = cgetg(n+3, t_POL), x = b + 2;
        !          4054:   b[1] = evalsigne(1) | evallgef(n+3) | evalvarn(v);
        !          4055:   for (i=0; i<=n; i++) x[i] = (long)polcoeff_i(b0, i, v);
        !          4056:   return b;
        !          4057: }
        !          4058:
        !          4059: /* assume varn(b) < varn(a) */
        !          4060: GEN
        !          4061: FpY_FpXY_resultant(GEN a, GEN b0, GEN p)
        !          4062: {
        !          4063:   long i,n,dres,nmax, vX = varn(b0), vY = varn(a);
        !          4064:   GEN la,x,y,b = swap_vars(b0, vY);
        !          4065:
        !          4066:   dres = degpol(a)*degpol(b0);
        !          4067:   if (OK_ULONG(p))
        !          4068:   {
        !          4069:     ulong pp = (ulong)p[2];
        !          4070:     long l = lgef(b);
        !          4071:
        !          4072:     a = u_Fp_FpX(a, pp);
        !          4073:     for (i=2; i<l; i++)
        !          4074:       b[i] = (long)u_Fp_FpX((GEN)b[i], pp);
        !          4075:     if (dres >= pp)
        !          4076:     {
        !          4077:       l = lgef(a);
        !          4078:       a[0] = evaltyp(t_POL) | evallg(l);
        !          4079:       a[1] = evalsigne(1)|evalvarn(vY)|evallgef(l);
        !          4080:       for (i=2; i<l; i++)
        !          4081:         a[i] = (long)u_scalarpol(a[i]);
        !          4082:       x = u_FpYX_subres(a, b, pp);
        !          4083:     }
        !          4084:     else
        !          4085:       x = u_FpY_FpXY_resultant(a, b, pp, dres);
        !          4086:     return small_to_pol(x, vX);
        !          4087:   }
        !          4088:
        !          4089:   nmax = (dres+1)>>1;
        !          4090:   la = leading_term(a);
        !          4091:   x = cgetg(dres+2, t_VEC);
        !          4092:   y = cgetg(dres+2, t_VEC);
        !          4093:  /* Evaluate at 0 (if dres even) and +/- n, so that P_n(X) = P_{-n}(-X),
        !          4094:   * where P_i is Lagrange polynomial: P_i(j) = 1 if i=j, 0 otherwise */
        !          4095:   for (i=0,n = 1; n <= nmax; n++)
        !          4096:   {
        !          4097:     i++; x[i] = lstoi(n);
        !          4098:     y[i] = (long)FpX_resultant_after_eval(a,b, (GEN)x[i], p,la);
        !          4099:     i++; x[i] = lsubis(p,n);
        !          4100:     y[i] = (long)FpX_resultant_after_eval(a,b, (GEN)x[i], p,la);
        !          4101:   }
        !          4102:   if (i == dres)
        !          4103:   {
        !          4104:     i++; x[i] = zero;
        !          4105:     y[i] = (long)FpX_resultant_after_eval(a,b, (GEN)x[i], p,la);
        !          4106:   }
        !          4107:   x = FpV_polint(x,y, p);
        !          4108:   setvarn(x, vX); return x;
        !          4109: }
        !          4110:
        !          4111: /* check that theta(maxprime) - theta(27448) >= 2^bound */
        !          4112: /* NB: theta(27449) ~ 27225.387, theta(x) > 0.98 x for x>7481
        !          4113:  * (Schoenfeld, 1976 for x > 1155901 + direct calculations) */
        !          4114: static void
        !          4115: check_theta(ulong bound)
        !          4116: {
        !          4117:   ulong c = (ulong)ceil((bound * LOG2 + 27225.388) / 0.98);
        !          4118:   if (maxprime() < c)
        !          4119:     err(talker,"not enough precalculated primes: need primelimit ~ %lu", c);
        !          4120: }
        !          4121:
1.1       noro     4122: /* 0, 1, -1, 2, -2, ... */
                   4123: #define next_lambda(a) (a>0 ? -a : 1-a)
                   4124:
                   4125: /* If lambda = NULL, assume A in Z[Y], B in Q[Y][X], return Res_Y(A,B)
                   4126:  * Otherwise, find a small lambda (start from *lambda, use the sequence above)
                   4127:  * such that R(X) = Res_Y(A, B(X + lambda Y)) is squarefree, reset *lambda to
                   4128:  * the chosen value and return R
                   4129:  *
                   4130:  * If LERS is non-NULL, set it to the last non-constant polynomial in the PRS */
                   4131: GEN
                   4132: ZY_ZXY_resultant_all(GEN A, GEN B0, long *lambda, GEN *LERS)
                   4133: {
1.2     ! noro     4134:   int checksqfree = lambda? 1: 0, delvar = 0, first = 1, stable;
        !          4135:   ulong bound;
        !          4136:   gpmem_t av = avma, av2, lim;
1.1       noro     4137:   long i,n, lb, dres = degpol(A)*degpol(B0), nmax = (dres+1)>>1;
                   4138:   long vX = varn(B0), vY = varn(A); /* assume vX < vY */
                   4139:   GEN x,y,dglist,cB,B,q,a,b,ev,H,H0,H1,Hp,H0p,H1p,C0,C1;
                   4140:   byteptr d = diffptr + 3000;
                   4141:   ulong p = 27449; /* p = prime(3000) */
                   4142:
                   4143:   dglist = Hp = H0p = H1p = C0 = C1 = NULL; /* gcc -Wall */
                   4144:   if (LERS)
                   4145:   {
                   4146:     if (!lambda) err(talker,"ZY_ZXY_resultant_all: LERS needs lambda");
                   4147:     C0 = cgetg(dres+2, t_VECSMALL);
                   4148:     C1 = cgetg(dres+2, t_VECSMALL);
                   4149:     dglist = cgetg(dres+1, t_VECSMALL);
                   4150:   }
                   4151:   x = cgetg(dres+2, t_VECSMALL);
                   4152:   y = cgetg(dres+2, t_VECSMALL);
                   4153:   if (vY == MAXVARN)
                   4154:   {
1.2     ! noro     4155:     vY = fetch_var(); delvar = 1;
1.1       noro     4156:     B0 = gsubst(B0, MAXVARN, polx[vY]);
                   4157:     A = dummycopy(A); setvarn(A, vY);
                   4158:   }
                   4159:   cB = content(B0);
                   4160:   if (typ(cB) == t_POL) cB = content(cB);
                   4161:   if (gcmp1(cB)) cB = NULL; else B0 = gdiv(B0, cB);
                   4162:
                   4163:   if (lambda)
                   4164:     B = poleval(B0, gadd(polx[MAXVARN], gmulsg(*lambda, polx[vY])));
                   4165:   else
                   4166:     B = poleval(B0, polx[MAXVARN]);
                   4167:   av2 = avma; lim = stack_lim(av,2);
                   4168:
                   4169: INIT:
                   4170:   if (first) first = 0;
                   4171:   else
                   4172:   { /* lambda != NULL */
                   4173:     avma = av2; *lambda = next_lambda(*lambda);
                   4174:     if (DEBUGLEVEL>4) fprintferr("Starting with lambda = %ld\n",*lambda);
                   4175:     B = poleval(B0, gadd(polx[MAXVARN], gmulsg(*lambda, polx[vY])));
                   4176:     av2 = avma;
                   4177:   }
                   4178:
                   4179:   if (degpol(A) <= 3)
                   4180:   { /* sub-resultant faster for small degrees */
                   4181:     if (LERS)
                   4182:     {
                   4183:       H = subresall(A,B,&q);
                   4184:       if (typ(q) != t_POL || degpol(q)!=1 || !ZX_is_squarefree(H)) goto INIT;
                   4185:       H0 = (GEN)q[2]; if (typ(H0) == t_POL) setvarn(H0,vX);
                   4186:       H1 = (GEN)q[3]; if (typ(H1) == t_POL) setvarn(H1,vX);
                   4187:     }
                   4188:     else
                   4189:     {
                   4190:       H = subres(A,B);
                   4191:       if (checksqfree && !ZX_is_squarefree(H)) goto INIT;
                   4192:     }
                   4193:     goto END;
                   4194:   }
                   4195:
1.2     ! noro     4196:   /* make sure p large enough */
        !          4197:   while (p < (dres<<1)) NEXT_PRIME_VIADIFF(p,d);
        !          4198:
1.1       noro     4199:   H = H0 = H1 = NULL;
1.2     ! noro     4200:   lb = lgef(B); b = u_getpol(degpol(B));
        !          4201:   bound = ZY_ZXY_ResBound(A, B);
1.1       noro     4202:   if (DEBUGLEVEL>4) fprintferr("bound for resultant coeffs: 2^%ld\n",bound);
1.2     ! noro     4203:   check_theta(bound);
1.1       noro     4204:
                   4205:   for(;;)
                   4206:   {
1.2     ! noro     4207:     NEXT_PRIME_VIADIFF_CHECK(p,d);
1.1       noro     4208:
1.2     ! noro     4209:     a = u_Fp_FpX(A, p);
1.1       noro     4210:     for (i=2; i<lb; i++)
1.2     ! noro     4211:       b[i] = (long)u_Fp_FpX((GEN)B[i], p);
1.1       noro     4212:     if (LERS)
                   4213:     {
                   4214:       if (!b[lb-1] || degpol(a) < degpol(A)) continue; /* p | lc(A)lc(B) */
                   4215:       if (checksqfree)
                   4216:       { /* find degree list for generic Euclidean Remainder Sequence */
                   4217:         int goal = min(degpol(a), degpol(b)); /* longest possible */
                   4218:         for (n=1; n <= goal; n++) dglist[n] = 0;
                   4219:         setlg(dglist, 1);
                   4220:         for (n=0; n <= dres; n++)
                   4221:         {
1.2     ! noro     4222:           ev = u_vec_FpX_eval(b, n, p);
1.1       noro     4223:           (void)u_FpX_resultant_all(a, ev, NULL, NULL, dglist, p);
                   4224:           if (lg(dglist)-1 == goal) break;
                   4225:         }
                   4226:         /* last pol in ERS has degree > 1 ? */
                   4227:         goal = lg(dglist)-1;
                   4228:         if (degpol(B) == 1) { if (!goal) goto INIT; }
                   4229:         else
                   4230:         {
                   4231:           if (goal <= 1) goto INIT;
                   4232:           if (dglist[goal] != 0 || dglist[goal-1] != 1) goto INIT;
                   4233:         }
                   4234:         if (DEBUGLEVEL>4)
                   4235:           fprintferr("Degree list for ERS (trials: %ld) = %Z\n",n+1,dglist);
                   4236:       }
                   4237:
                   4238:       for (i=0,n = 0; i <= dres; n++)
                   4239:       {
1.2     ! noro     4240:         i++; ev = u_vec_FpX_eval(b, n, p);
1.1       noro     4241:         x[i] = n;
                   4242:         y[i] = u_FpX_resultant_all(a, ev, C0+i, C1+i, dglist, p);
                   4243:         if (!C1[i]) i--; /* C1(i) = 0. No way to recover C0(i) */
                   4244:       }
                   4245:       u_FpV_polint_all(x,y,C0,C1, p);
                   4246:       Hp = (GEN)y[1];
                   4247:       H0p= (GEN)C0[1];
                   4248:       H1p= (GEN)C1[1];
                   4249:     }
                   4250:     else
1.2     ! noro     4251:     { /* cf u_FpXY_resultant */
1.1       noro     4252:       ulong la = (ulong)leading_term(a);
                   4253:      /* Evaluate at 0 (if dres even) and +/- n, so that P_n(X) = P_{-n}(-X),
                   4254:       * where P_i is Lagrange polynomial: P_i(j) = 1 if i=j, 0 otherwise */
                   4255:       for (i=0,n = 1; n <= nmax; n++)
                   4256:       {
1.2     ! noro     4257:         i++; x[i] = n;   y[i] = u_FpX_resultant_after_eval(a,b, x[i], p,la);
        !          4258:         i++; x[i] = p-n; y[i] = u_FpX_resultant_after_eval(a,b, x[i], p,la);
1.1       noro     4259:       }
                   4260:       if (i == dres)
                   4261:       {
1.2     ! noro     4262:         i++; x[i] = 0;   y[i] = u_FpX_resultant_after_eval(a,b, x[i], p,la);
1.1       noro     4263:       }
                   4264:       Hp = u_FpV_polint(x,y, p);
                   4265:     }
                   4266:     if (!H && degpol(Hp) != dres) continue;
                   4267:     if (checksqfree) {
                   4268:       if (!u_FpX_is_squarefree(Hp, p)) goto INIT;
                   4269:       if (DEBUGLEVEL>4) fprintferr("Final lambda = %ld\n",*lambda);
                   4270:       checksqfree = 0;
                   4271:     }
                   4272:
                   4273:     if (!H)
                   4274:     { /* initialize */
                   4275:       q = utoi(p); stable = 0;
                   4276:       H = ZX_init_CRT(Hp, p,vX);
                   4277:       if (LERS) {
                   4278:         H0= ZX_init_CRT(H0p, p,vX);
                   4279:         H1= ZX_init_CRT(H1p, p,vX);
                   4280:       }
                   4281:     }
                   4282:     else
                   4283:     {
                   4284:       GEN qp = muliu(q,p);
1.2     ! noro     4285:       stable = ZX_incremental_CRT(&H, Hp, q,qp, p);
1.1       noro     4286:       if (LERS) {
1.2     ! noro     4287:         stable &= ZX_incremental_CRT(&H0,H0p, q,qp, p);
        !          4288:         stable &= ZX_incremental_CRT(&H1,H1p, q,qp, p);
1.1       noro     4289:       }
                   4290:       q = qp;
                   4291:     }
                   4292:     /* could make it probabilistic for H ? [e.g if stable twice, etc]
                   4293:      * Probabilistic anyway for H0, H1 */
                   4294:     if (DEBUGLEVEL>5)
                   4295:       msgtimer("resultant mod %ld (bound 2^%ld, stable=%ld)", p,expi(q),stable);
                   4296:     if (stable && (ulong)expi(q) >= bound) break; /* DONE */
                   4297:     if (low_stack(lim, stack_lim(av,2)))
                   4298:     {
                   4299:       GEN *gptr[4]; gptr[0] = &H; gptr[1] = &q; gptr[2] = &H0; gptr[3] = &H1;
                   4300:       if (DEBUGMEM>1) err(warnmem,"ZY_ZXY_resultant");
1.2     ! noro     4301:       gerepilemany(av2,gptr,LERS? 4: 2); b = u_getpol(degpol(B));
1.1       noro     4302:     }
                   4303:   }
                   4304: END:
1.2     ! noro     4305:   setvarn(H, vX); if (delvar) (void)delete_var();
1.1       noro     4306:   if (cB) H = gmul(H, gpowgs(cB, degpol(A)));
                   4307:   if (LERS)
                   4308:   {
                   4309:     GEN *gptr[2];
                   4310:     GEN z = cgetg(3, t_VEC);
                   4311:     z[1] = (long)H0;
                   4312:     z[2] = (long)H1; *LERS = z;
                   4313:     gptr[0]=&H; gptr[1]=LERS;
                   4314:     gerepilemany(av, gptr, 2);
                   4315:     return H;
                   4316:   }
                   4317:   if (!cB) H = gcopy(H);
                   4318:   return gerepileupto(av, H);
                   4319: }
                   4320:
                   4321: GEN
1.2     ! noro     4322: ZY_ZXY_resultant(GEN A, GEN B, long *lambda)
1.1       noro     4323: {
1.2     ! noro     4324:   return ZY_ZXY_resultant_all(A, B, lambda, NULL);
1.1       noro     4325: }
                   4326:
                   4327: /* If lambda = NULL, return caract(Mod(B, A)), A,B in Z[X].
                   4328:  * Otherwise find a small lambda such that caract (Mod(B + lambda X, A)) is
                   4329:  * squarefree */
                   4330: GEN
                   4331: ZX_caract_sqf(GEN A, GEN B, long *lambda, long v)
                   4332: {
1.2     ! noro     4333:   gpmem_t av = avma;
1.1       noro     4334:   GEN B0, R, a;
                   4335:   long dB;
1.2     ! noro     4336:   int delvar;
1.1       noro     4337:
                   4338:   if (v < 0) v = 0;
                   4339:   switch (typ(B))
                   4340:   {
                   4341:     case t_POL: dB = degpol(B); if (dB > 0) break;
                   4342:       B = dB? (GEN)B[2]: gzero; /* fall through */
                   4343:     default:
                   4344:       if (lambda) { B = scalarpol(B,varn(A)); dB = 0; break;}
                   4345:       return gerepileupto(av, gpowgs(gsub(polx[v], B), degpol(A)));
                   4346:   }
1.2     ! noro     4347:   delvar = 0;
1.1       noro     4348:   if (varn(A) == 0)
                   4349:   {
1.2     ! noro     4350:     long v0 = fetch_var(); delvar = 1;
1.1       noro     4351:     A = dummycopy(A); setvarn(A,v0);
                   4352:     B = dummycopy(B); setvarn(B,v0);
                   4353:   }
                   4354:   B0 = cgetg(4, t_POL); B0[1] = evalsigne(1)|evalvarn(0)|evallgef(4);
                   4355:   B0[2] = (long)gneg_i(B);
                   4356:   B0[3] = un;
                   4357:   R = ZY_ZXY_resultant(A, B0, lambda);
1.2     ! noro     4358:   if (delvar) (void)delete_var();
1.1       noro     4359:   setvarn(R, v); a = leading_term(A);
                   4360:   if (!gcmp1(a)) R = gdiv(R, gpowgs(a, dB));
                   4361:   return gerepileupto(av, R);
                   4362: }
                   4363:
1.2     ! noro     4364:
1.1       noro     4365: GEN
                   4366: ZX_caract(GEN A, GEN B, long v)
                   4367: {
1.2     ! noro     4368:   return (degpol(A) < 16) ? caractducos(A,B,v): ZX_caract_sqf(A,B, NULL, v);
        !          4369: }
        !          4370:
        !          4371: /* assume A integral, B in Q[v] */
        !          4372: GEN
        !          4373: QX_caract(GEN A, GEN B, long v)
        !          4374: {
        !          4375:   gpmem_t av = avma;
        !          4376:   GEN cB, B0 = Q_primitive_part(B, &cB);
        !          4377:   GEN ch = ZX_caract(A, B0, v);
        !          4378:   if (cB)
        !          4379:     ch = gerepilecopy(av, rescale_pol(ch, cB));
        !          4380:   return ch;
1.1       noro     4381: }
                   4382:
                   4383: static GEN
                   4384: trivial_case(GEN A, GEN B)
                   4385: {
1.2     ! noro     4386:   long d;
1.1       noro     4387:   if (typ(A) == t_INT) return gpowgs(A, degpol(B));
1.2     ! noro     4388:   d = degpol(A);
        !          4389:   if (d == 0) return trivial_case((GEN)A[2],B);
        !          4390:   if (d < 0) return gzero;
1.1       noro     4391:   return NULL;
                   4392: }
                   4393:
1.2     ! noro     4394: /* Res(A, B/dB), assuming the A,B in Z[X] and result is integer */
1.1       noro     4395: GEN
1.2     ! noro     4396: ZX_resultant_all(GEN A, GEN B, GEN dB, ulong bound)
1.1       noro     4397: {
1.2     ! noro     4398:   ulong Hp, dp;
        !          4399:   gpmem_t av = avma, av2, lim;
        !          4400:   long degA;
1.1       noro     4401:   int stable;
                   4402:   GEN q, a, b, H;
                   4403:   byteptr d = diffptr + 3000;
                   4404:   ulong p = 27449; /* p = prime(3000) */
                   4405:
                   4406:   if ((H = trivial_case(A,B)) || (H = trivial_case(B,A))) return H;
                   4407:   q = H = NULL;
                   4408:   av2 = avma; lim = stack_lim(av,2);
1.2     ! noro     4409:   degA = degpol(A);
        !          4410:   if (!bound)
        !          4411:   {
        !          4412:     bound = ZY_ZXY_ResBound(A, B);
        !          4413:     if (bound > 50000)
        !          4414:     {
        !          4415:       GEN run = realun(MEDDEFAULTPREC);
        !          4416:       GEN Ar = gmul(A, run), Br = gmul(B, run);
        !          4417:       GEN R = subres(Ar,Br);
        !          4418:       bound = gexpo(R) + 1;
        !          4419:     }
        !          4420:     if (dB) bound -= (long)(mylog2(dB)*degA);
        !          4421:   }
1.1       noro     4422:   if (DEBUGLEVEL>4) fprintferr("bound for resultant: 2^%ld\n",bound);
1.2     ! noro     4423:   check_theta(bound);
1.1       noro     4424:
1.2     ! noro     4425:   dp = 0; /* gcc -Wall */
1.1       noro     4426:   for(;;)
                   4427:   {
1.2     ! noro     4428:     NEXT_PRIME_VIADIFF_CHECK(p,d);
        !          4429:     if (dB) { dp = smodis(dB, p); if (!dp) continue; }
        !          4430:
        !          4431:     a = u_Fp_FpX(A, p);
        !          4432:     b = u_Fp_FpX(B, p);
1.1       noro     4433:     Hp= u_FpX_resultant(a, b, p);
1.2     ! noro     4434:     if (dp) Hp = mulssmod(Hp, u_powmod(dp, -degA, p), p);
1.1       noro     4435:     if (!H)
                   4436:     {
                   4437:       stable = 0; q = utoi(p);
1.2     ! noro     4438:       H = stoi(u_center(Hp, p, p>>1));
1.1       noro     4439:     }
                   4440:     else /* could make it probabilistic ??? [e.g if stable twice, etc] */
                   4441:     {
                   4442:       GEN qp = muliu(q,p);
                   4443:       stable = Z_incremental_CRT(&H, Hp, q,qp, p);
                   4444:       q = qp;
                   4445:     }
                   4446:     if (DEBUGLEVEL>5)
                   4447:       msgtimer("resultant mod %ld (bound 2^%ld, stable = %d)",p,expi(q),stable);
                   4448:     if (stable && (ulong)expi(q) >= bound) break; /* DONE */
                   4449:     if (low_stack(lim, stack_lim(av,2)))
                   4450:     {
                   4451:       GEN *gptr[2]; gptr[0] = &H; gptr[1] = &q;
                   4452:       if (DEBUGMEM>1) err(warnmem,"ZX_resultant");
                   4453:       gerepilemany(av2,gptr, 2);
                   4454:     }
                   4455:   }
                   4456:   return gerepileuptoint(av, icopy(H));
                   4457: }
                   4458:
                   4459: GEN
1.2     ! noro     4460: ZX_resultant(GEN A, GEN B) { return ZX_resultant_all(A,B,NULL,0); }
        !          4461:
        !          4462: GEN
        !          4463: ZX_QX_resultant(GEN A, GEN B)
        !          4464: {
        !          4465:   GEN c, d, n, R;
        !          4466:   gpmem_t av = avma;
        !          4467:   B = Q_primitive_part(B, &c);
        !          4468:   if (!c) return ZX_resultant(A,B);
        !          4469:   n = numer(c);
        !          4470:   d = denom(c); if (is_pm1(d)) d = NULL;
        !          4471:   R = ZX_resultant_all(A, B, d, 0);
        !          4472:   if (!is_pm1(n)) R = mulii(R, gpowgs(n, degpol(A)));
        !          4473:   return gerepileuptoint(av, R);
        !          4474: }
1.1       noro     4475:
                   4476: /* assume x has integral coefficients */
                   4477: GEN
                   4478: ZX_disc_all(GEN x, ulong bound)
                   4479: {
1.2     ! noro     4480:   gpmem_t av = avma;
        !          4481:   GEN l, d = ZX_resultant_all(x, derivpol(x), NULL, bound);
        !          4482:   l = leading_term(x); if (!gcmp1(l)) d = diviiexact(d,l);
1.1       noro     4483:   if (degpol(x) & 2) d = negi(d);
                   4484:   return gerepileuptoint(av,d);
                   4485: }
                   4486: GEN ZX_disc(GEN x) { return ZX_disc_all(x,0); }
                   4487:
                   4488: int
                   4489: ZX_is_squarefree(GEN x)
                   4490: {
1.2     ! noro     4491:   gpmem_t av = avma;
1.1       noro     4492:   int d = (lgef(modulargcd(x,derivpol(x))) == 3);
                   4493:   avma = av; return d;
                   4494: }
                   4495:
1.2     ! noro     4496: static GEN
        !          4497: _gcd(GEN a, GEN b)
1.1       noro     4498: {
1.2     ! noro     4499:   if (!a) a = gun;
        !          4500:   if (!b) b = gun;
        !          4501:   return ggcd(a,b);
1.1       noro     4502: }
                   4503:
                   4504: /* A0 and B0 in Q[X] */
                   4505: GEN
                   4506: modulargcd(GEN A0, GEN B0)
                   4507: {
1.2     ! noro     4508:   GEN a,b,Hp,D,A,B,q,qp,H,g;
1.1       noro     4509:   long m,n;
1.2     ! noro     4510:   ulong p;
        !          4511:   gpmem_t av2, av = avma, avlim = stack_lim(av, 1);
1.1       noro     4512:   byteptr d = diffptr;
                   4513:
                   4514:   if ((typ(A0) | typ(B0)) !=t_POL) err(notpoler,"modulargcd");
                   4515:   if (!signe(A0)) return gcopy(B0);
                   4516:   if (!signe(B0)) return gcopy(A0);
1.2     ! noro     4517:   A = primitive_part(A0, &a); check_pol_int(A, "modulargcd");
        !          4518:   B = primitive_part(B0, &b); check_pol_int(B, "modulargcd");
        !          4519:   D = _gcd(a,b);
        !          4520:   if (varn(A) != varn(B)) err(talker,"different variables in modulargcd");
        !          4521:
1.1       noro     4522:   /* A, B in Z[X] */
                   4523:   g = mppgcd(leading_term(A), leading_term(B)); /* multiple of lead(gcd) */
                   4524:   if (degpol(A) < degpol(B)) swap(A, B);
                   4525:   n = 1 + degpol(B); /* > degree(gcd) */
                   4526:
                   4527:   av2 = avma; H = NULL;
                   4528:   d += 3000; /* 27449 = prime(3000) */
1.2     ! noro     4529:   for(p = 27449; ;)
1.1       noro     4530:   {
                   4531:     if (!*d) err(primer1);
1.2     ! noro     4532:     if (!umodiu(g,p)) goto repeat;
1.1       noro     4533:
1.2     ! noro     4534:     a = u_Fp_FpX(A, p);
        !          4535:     b = u_Fp_FpX(B, p); Hp = u_FpX_gcd_i(a,b, p);
1.1       noro     4536:     m = degpol(Hp);
                   4537:     if (m == 0) { H = polun[varn(A0)]; break; } /* coprime. DONE */
1.2     ! noro     4538:     if (m > n) goto repeat; /* p | Res(A/G, B/G). Discard */
1.1       noro     4539:
                   4540:     if (is_pm1(g)) /* make sure lead(H) = g mod p */
                   4541:       Hp = u_FpX_normalize(Hp, p);
                   4542:     else
                   4543:     {
                   4544:       ulong t = mulssmod(umodiu(g, p), u_invmod(Hp[m+2],p), p);
1.2     ! noro     4545:       Hp = u_FpX_Fp_mul(Hp, t, p);
1.1       noro     4546:     }
                   4547:     if (m < n)
                   4548:     { /* First time or degree drop [all previous p were as above; restart]. */
                   4549:       H = ZX_init_CRT(Hp,p,varn(A0));
1.2     ! noro     4550:       q = utoi(p); n = m; goto repeat;
1.1       noro     4551:     }
                   4552:
                   4553:     qp = muliu(q,p);
1.2     ! noro     4554:     if (ZX_incremental_CRT(&H, Hp, q, qp, p))
1.1       noro     4555:     { /* H stable: check divisibility */
1.2     ! noro     4556:       if (!is_pm1(g)) H = primpart(H);
        !          4557:       if (gcmp0(pseudorem(A,H)) && gcmp0(pseudorem(B,H))) break; /* DONE */
1.1       noro     4558:
                   4559:       if (DEBUGLEVEL) fprintferr("modulargcd: trial division failed");
                   4560:     }
                   4561:     q = qp;
                   4562:     if (low_stack(avlim, stack_lim(av,1)))
                   4563:     {
                   4564:       GEN *gptr[2]; gptr[0]=&H; gptr[1]=&q;
                   4565:       if (DEBUGMEM>1) err(warnmem,"modulargcd");
                   4566:       gerepilemany(av2,gptr,2);
                   4567:     }
1.2     ! noro     4568:    repeat:
        !          4569:     NEXT_PRIME_VIADIFF_CHECK(p,d);
1.1       noro     4570:   }
                   4571:   return gerepileupto(av, gmul(D,H));
                   4572: }
                   4573:
1.2     ! noro     4574: /* lift(1 / Mod(A,B)). B0 a t_POL, A0 a scalar or a t_POL. Rational coeffs */
1.1       noro     4575: GEN
1.2     ! noro     4576: QX_invmod(GEN A0, GEN B0)
1.1       noro     4577: {
                   4578:   GEN a,b,D,A,B,q,qp,Up,Vp,U,V,res;
                   4579:   long stable;
1.2     ! noro     4580:   ulong p;
        !          4581:   gpmem_t av2, av = avma, avlim = stack_lim(av, 1);
1.1       noro     4582:   byteptr d = diffptr;
                   4583:
1.2     ! noro     4584:   if (typ(B0) != t_POL) err(notpoler,"QX_invmod");
1.1       noro     4585:   if (typ(A0) != t_POL)
                   4586:   {
                   4587:     if (is_scalar_t(typ(A0))) return ginv(A0);
1.2     ! noro     4588:     err(notpoler,"QX_invmod");
1.1       noro     4589:   }
1.2     ! noro     4590:   if (degpol(A0) < 15) return ginvmod(A0,B0);
        !          4591:   A = primitive_part(A0, &D);
        !          4592:   B = primpart(B0);
1.1       noro     4593:   /* A, B in Z[X] */
                   4594:   av2 = avma; U = NULL;
                   4595:   d += 3000; /* 27449 = prime(3000) */
1.2     ! noro     4596:   for(p = 27449; ; )
1.1       noro     4597:   {
                   4598:     if (!*d) err(primer1);
1.2     ! noro     4599:     a = u_Fp_FpX(A, p);
        !          4600:     b = u_Fp_FpX(B, p);
1.1       noro     4601:     /* if p | Res(A/G, B/G), discard */
1.2     ! noro     4602:     if (!u_FpX_extresultant(b,a,p, &Vp,&Up)) goto repeat;
1.1       noro     4603:
                   4604:     if (!U)
                   4605:     { /* First time */
                   4606:       U = ZX_init_CRT(Up,p,varn(A0));
                   4607:       V = ZX_init_CRT(Vp,p,varn(A0));
1.2     ! noro     4608:       q = utoi(p); goto repeat;
1.1       noro     4609:     }
1.2     ! noro     4610:     if (DEBUGLEVEL>5) msgtimer("QX_invmod: mod %ld (bound 2^%ld)", p,expi(q));
1.1       noro     4611:     qp = muliu(q,p);
1.2     ! noro     4612:     stable  = ZX_incremental_CRT(&U, Up, q,qp, p);
        !          4613:     stable &= ZX_incremental_CRT(&V, Vp, q,qp, p);
1.1       noro     4614:     if (stable)
                   4615:     { /* all stable: check divisibility */
                   4616:       res = gadd(gmul(A,U), gmul(B,V));
                   4617:       if (degpol(res) == 0) break; /* DONE */
1.2     ! noro     4618:       if (DEBUGLEVEL) fprintferr("QX_invmod: char 0 check failed");
1.1       noro     4619:     }
                   4620:     q = qp;
                   4621:     if (low_stack(avlim, stack_lim(av,1)))
                   4622:     {
                   4623:       GEN *gptr[3]; gptr[0]=&q; gptr[1]=&U; gptr[2]=&V;
1.2     ! noro     4624:       if (DEBUGMEM>1) err(warnmem,"QX_invmod");
1.1       noro     4625:       gerepilemany(av2,gptr,3);
                   4626:     }
1.2     ! noro     4627:    repeat:
        !          4628:     NEXT_PRIME_VIADIFF_CHECK(p,d);
1.1       noro     4629:   }
1.2     ! noro     4630:   D = D? gmul(D,res): res;
1.1       noro     4631:   return gerepileupto(av, gdiv(U,D));
                   4632: }
                   4633:
1.2     ! noro     4634: /* irreducible (unitary) polynomial of degree n over Fp */
        !          4635: GEN
        !          4636: ffinit_rand(GEN p,long n)
        !          4637: {
        !          4638:   gpmem_t av = avma;
        !          4639:   GEN pol;
        !          4640:
        !          4641:   for(;; avma = av)
        !          4642:   {
        !          4643:     pol = gadd(gpowgs(polx[0],n), FpX_rand(n-1,0, p));
        !          4644:     if (FpX_is_irred(pol, p)) break;
        !          4645:   }
        !          4646:   return pol;
        !          4647: }
        !          4648:
        !          4649: GEN
        !          4650: FpX_direct_compositum(GEN A, GEN B, GEN p)
        !          4651: {
        !          4652:   GEN C,a,b,x;
        !          4653:   a = dummycopy(A); setvarn(a, MAXVARN);
        !          4654:   b = dummycopy(B); setvarn(b, MAXVARN);
        !          4655:   x = gadd(polx[0], polx[MAXVARN]);
        !          4656:   C = FpY_FpXY_resultant(a, poleval(b,x),p);
        !          4657:   return C;
        !          4658: }
        !          4659:
        !          4660: GEN
        !          4661: FpX_compositum(GEN A, GEN B, GEN p)
        !          4662: {
        !          4663:   GEN C, a,b;
        !          4664:   long k;
        !          4665:
        !          4666:   a = dummycopy(A); setvarn(a, MAXVARN);
        !          4667:   b = dummycopy(B); setvarn(b, MAXVARN);
        !          4668:   for (k = 1;; k = next_lambda(k))
        !          4669:   {
        !          4670:     GEN x = gadd(polx[0], gmulsg(k, polx[MAXVARN]));
        !          4671:     C = FpY_FpXY_resultant(a, poleval(b,x),p);
        !          4672:     if (FpX_is_squarefree(C, p)) break;
        !          4673:   }
        !          4674:   return C;
        !          4675: }
        !          4676:
        !          4677: /* return an extension of degree 2^l of F_2, assume l > 0
        !          4678:  * using Adleman-Lenstra Algorithm.
        !          4679:  * Not stack clean. */
        !          4680: static GEN
        !          4681: f2init(long l)
        !          4682: {
        !          4683:   long i;
        !          4684:   GEN a, q, T, S;
        !          4685:
        !          4686:   if (l == 1) return cyclo(3, MAXVARN);
        !          4687:
        !          4688:   a = gun;
        !          4689:   S = coefs_to_pol(4, gun,gun,gzero,gzero); /* #(#^2 + #) */
        !          4690:   setvarn(S, MAXVARN);
        !          4691:   q = coefs_to_pol(3, gun,gun, S); /* X^2 + X + #(#^2+#) */
        !          4692:
        !          4693:   /* x^4+x+1, irred over F_2, minimal polynomial of a root of q */
        !          4694:   T = coefs_to_pol(5, gun,gzero,gzero,gun,gun);
        !          4695:
        !          4696:   for (i=2; i<l; i++)
        !          4697:   { /* q = X^2 + X + a(#) irred. over K = F2[#] / (T(#))
        !          4698:      * ==> X^2 + X + a(#) b irred. over K for any root b of q
        !          4699:      * ==> X^2 + X + (b^2+b)b */
        !          4700:     setvarn(T, MAXVARN);
        !          4701:     T = FpY_FpXY_resultant(T, q, gdeux);
        !          4702:     /* T = minimal polynomial of b over F2 */
        !          4703:   }
        !          4704:   return T;
        !          4705: }
        !          4706:
        !          4707: /*Check if subcyclo(n,l,0) is irreducible modulo p*/
        !          4708: static long
        !          4709: fpinit_check(GEN p, long n, long l)
        !          4710: {
        !          4711:   gpmem_t ltop=avma;
        !          4712:   long q,o;
        !          4713:   if (!isprime(stoi(n))) {avma=ltop; return 0;}
        !          4714:   q = smodis(p,n);
        !          4715:   if (!q) {avma=ltop; return 0;}
        !          4716:   o = itos(order(gmodulss(q,n)));
        !          4717:   avma = ltop;
        !          4718:   return ( cgcd((n-1)/o,l) == 1 );
        !          4719: }
        !          4720:
        !          4721: /* let k=2 if p%4==1, and k=4 else and assume k*p does not divide l.
        !          4722:  * Return an irreducible polynomial of degree l over F_p.
        !          4723:  * This a variant of an algorithm of Adleman and Lenstra
        !          4724:  * "Finding irreducible polynomials over finite fields",
        !          4725:  * ACM, 1986 (5)  350--355
        !          4726:  * Not stack clean.
        !          4727:  */
        !          4728: static GEN
        !          4729: fpinit(GEN p, long l)
        !          4730: {
        !          4731:   ulong n = 1+l, k = 1;
        !          4732:   while (!fpinit_check(p,n,l)) { n += l; k++; }
        !          4733:   if (DEBUGLEVEL>=4)
        !          4734:     fprintferr("FFInit: using subcyclo(%ld, %ld)\n",n,l);
        !          4735:   return FpX_red(subcyclo(n,l,0),p);
        !          4736: }
        !          4737:
        !          4738: GEN
        !          4739: ffinit_fact(GEN p, long n)
        !          4740: {
        !          4741:   gpmem_t ltop=avma;
        !          4742:   GEN F;         /* vecsmall */
        !          4743:   GEN P;         /* pol */
        !          4744:   long i;
        !          4745:   F = decomp_primary_small(n);
        !          4746:   /* If n is even, then F[1] is 2^bfffo(n)*/
        !          4747:   if (!(n&1) && egalii(p, gdeux))
        !          4748:     P = f2init(vals(n));
        !          4749:   else
        !          4750:     P = fpinit(p, F[1]);
        !          4751:   for (i = 2; i < lg(F); ++i)
        !          4752:     P = FpX_direct_compositum(fpinit(p, F[i]), P, p);
        !          4753:   return gerepileupto(ltop,FpX(P,p));
        !          4754: }
        !          4755:
        !          4756: GEN
        !          4757: ffinit_nofact(GEN p, long n)
        !          4758: {
        !          4759:   gpmem_t av = avma;
        !          4760:   GEN P,Q=NULL;
        !          4761:   if (lgefint(p)==3)
        !          4762:   {
        !          4763:     ulong lp=p[2], q;
        !          4764:     long v=svaluation(n,lp,&q);
        !          4765:     if (v>0)
        !          4766:     {
        !          4767:       if (lp==2)
        !          4768:         Q=f2init(v);
        !          4769:       else
        !          4770:         Q=fpinit(p,n/q);
        !          4771:       n=q;
        !          4772:     }
        !          4773:   }
        !          4774:   if (n==1)
        !          4775:     P=Q;
        !          4776:   else
        !          4777:   {
        !          4778:     P = fpinit(p, n);
        !          4779:     if (Q) P = FpX_direct_compositum(P, Q, p);
        !          4780:   }
        !          4781:   return gerepileupto(av, FpX(P,p));
        !          4782: }
        !          4783:
        !          4784: GEN
        !          4785: ffinit(GEN p, long n, long v)
        !          4786: {
        !          4787:   gpmem_t ltop=avma;
        !          4788:   GEN P;
        !          4789:   if (n <= 0) err(talker,"non positive degree in ffinit");
        !          4790:   if (typ(p) != t_INT) err(typeer, "ffinit");
        !          4791:   if (v < 0) v = 0;
        !          4792:   if (n == 1) return FpX(polx[v],p);
        !          4793:   /*If we are in a easy case just use cyclo*/
        !          4794:   if (fpinit_check(p, n + 1, n))
        !          4795:     return gerepileupto(ltop,FpX(cyclo(n + 1, v),p));
        !          4796:   if (lgefint(p)-2<BITS_IN_LONG-bfffo(n))
        !          4797:     P=ffinit_fact(p,n);
        !          4798:   else
        !          4799:     P=ffinit_nofact(p,n);
        !          4800:   setvarn(P, v);
        !          4801:   return P;
        !          4802: }

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