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