Line data Source code
1 : /* Copyright (C) 2000-2005 The PARI group.
2 :
3 : This file is part of the PARI/GP package.
4 :
5 : PARI/GP is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 2 of the License, or (at your option) any later
8 : version. It is distributed in the hope that it will be useful, but WITHOUT
9 : ANY WARRANTY WHATSOEVER.
10 :
11 : Check the License for details. You should have received a copy of it, along
12 : with the package; see the file 'COPYING'. If not, write to the Free Software
13 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 :
15 : /***********************************************************************/
16 : /** **/
17 : /** ARITHMETIC OPERATIONS ON POLYNOMIALS **/
18 : /** (third part) **/
19 : /** **/
20 : /***********************************************************************/
21 : #include "pari.h"
22 : #include "paripriv.h"
23 :
24 : #define DEBUGLEVEL DEBUGLEVEL_pol
25 :
26 : /************************************************************************
27 : ** **
28 : ** Ring membership **
29 : ** **
30 : ************************************************************************/
31 : struct charact {
32 : GEN q;
33 : int isprime;
34 : };
35 : static void
36 1225 : char_update_prime(struct charact *S, GEN p)
37 : {
38 1225 : if (!S->isprime) { S->isprime = 1; S->q = p; }
39 1225 : if (!equalii(p, S->q)) pari_err_MODULUS("characteristic", S->q, p);
40 1218 : }
41 : static void
42 6594 : char_update_int(struct charact *S, GEN n)
43 : {
44 6594 : if (S->isprime)
45 : {
46 7 : if (dvdii(n, S->q)) return;
47 7 : pari_err_MODULUS("characteristic", S->q, n);
48 : }
49 6587 : S->q = gcdii(S->q, n);
50 : }
51 : static void
52 176946 : charact(struct charact *S, GEN x)
53 : {
54 176946 : const long tx = typ(x);
55 : long i, l;
56 176946 : switch(tx)
57 : {
58 5145 : case t_INTMOD:char_update_int(S, gel(x,1)); break;
59 1134 : case t_FFELT: char_update_prime(S, gel(x,4)); break;
60 25711 : case t_COMPLEX: case t_QUAD:
61 : case t_POLMOD: case t_POL: case t_SER: case t_RFRAC:
62 : case t_VEC: case t_COL: case t_MAT:
63 25711 : l = lg(x);
64 175021 : for (i=lontyp[tx]; i < l; i++) charact(S,gel(x,i));
65 25697 : break;
66 7 : case t_LIST:
67 7 : x = list_data(x);
68 7 : if (x) charact(S, x);
69 7 : break;
70 : }
71 176918 : }
72 : static void
73 4739 : charact_res(struct charact *S, GEN x)
74 : {
75 4739 : const long tx = typ(x);
76 : long i, l;
77 4739 : switch(tx)
78 : {
79 1449 : case t_INTMOD:char_update_int(S, gel(x,1)); break;
80 0 : case t_FFELT: char_update_prime(S, gel(x,4)); break;
81 91 : case t_PADIC: char_update_prime(S, padic_p(x)); break;
82 1722 : case t_COMPLEX: case t_QUAD:
83 : case t_POLMOD: case t_POL: case t_SER: case t_RFRAC:
84 : case t_VEC: case t_COL: case t_MAT:
85 1722 : l = lg(x);
86 6132 : for (i=lontyp[tx]; i < l; i++) charact_res(S,gel(x,i));
87 1722 : break;
88 0 : case t_LIST:
89 0 : x = list_data(x);
90 0 : if (x) charact_res(S, x);
91 0 : break;
92 : }
93 4739 : }
94 : GEN
95 27622 : characteristic(GEN x)
96 : {
97 : struct charact S;
98 27622 : S.q = gen_0; S.isprime = 0;
99 27622 : charact(&S, x); return S.q;
100 : }
101 : GEN
102 329 : residual_characteristic(GEN x)
103 : {
104 : struct charact S;
105 329 : S.q = gen_0; S.isprime = 0;
106 329 : charact_res(&S, x); return S.q;
107 : }
108 :
109 : int
110 70272878 : Rg_is_Fp(GEN x, GEN *pp)
111 : {
112 : GEN mod;
113 70272878 : switch(typ(x))
114 : {
115 2482676 : case t_INTMOD:
116 2482676 : mod = gel(x,1);
117 2482676 : if (!*pp) *pp = mod;
118 2341976 : else if (mod != *pp && !equalii(mod, *pp))
119 : {
120 0 : if (DEBUGLEVEL) pari_warn(warner,"different moduli in Rg_is_Fp");
121 0 : return 0;
122 : }
123 2482676 : return 1;
124 56412031 : case t_INT:
125 56412031 : return 1;
126 11378171 : default: return 0;
127 : }
128 : }
129 :
130 : int
131 28008732 : RgX_is_FpX(GEN x, GEN *pp)
132 : {
133 28008732 : long i, lx = lg(x);
134 86877301 : for (i=2; i<lx; i++)
135 70246737 : if (!Rg_is_Fp(gel(x, i), pp))
136 11378172 : return 0;
137 16630564 : return 1;
138 : }
139 :
140 : int
141 0 : RgV_is_FpV(GEN x, GEN *pp)
142 : {
143 0 : long i, lx = lg(x);
144 0 : for (i=1; i<lx; i++)
145 0 : if (!Rg_is_Fp(gel(x,i), pp)) return 0;
146 0 : return 1;
147 : }
148 :
149 : int
150 0 : RgM_is_FpM(GEN x, GEN *pp)
151 : {
152 0 : long i, lx = lg(x);
153 0 : for (i=1; i<lx; i++)
154 0 : if (!RgV_is_FpV(gel(x, i), pp)) return 0;
155 0 : return 1;
156 : }
157 :
158 : int
159 60802 : Rg_is_FpXQ(GEN x, GEN *pT, GEN *pp)
160 : {
161 : GEN pol, mod, p;
162 60802 : switch(typ(x))
163 : {
164 26131 : case t_INTMOD:
165 26131 : return Rg_is_Fp(x, pp);
166 8561 : case t_INT:
167 8561 : return 1;
168 21 : case t_POL:
169 21 : return RgX_is_FpX(x, pp);
170 21350 : case t_FFELT:
171 21350 : mod = x; p = FF_p_i(x);
172 21350 : if (!*pp) *pp = p;
173 21350 : if (!*pT) *pT = mod;
174 19824 : else if (typ(*pT)!=t_FFELT || !FF_samefield(*pT,mod))
175 : {
176 42 : if (DEBUGLEVEL) pari_warn(warner,"different moduli in Rg_is_FpXQ");
177 42 : return 0;
178 : }
179 21308 : return 1;
180 4585 : case t_POLMOD:
181 4585 : mod = gel(x,1); pol = gel(x, 2);
182 4585 : if (!RgX_is_FpX(mod, pp)) return 0;
183 4585 : if (typ(pol)==t_POL)
184 : {
185 4578 : if (!RgX_is_FpX(pol, pp)) return 0;
186 : }
187 7 : else if (!Rg_is_Fp(pol, pp)) return 0;
188 4585 : if (!*pT) *pT = mod;
189 4431 : else if (mod != *pT && !gequal(mod, *pT))
190 : {
191 0 : if (DEBUGLEVEL) pari_warn(warner,"different moduli in Rg_is_FpXQ");
192 0 : return 0;
193 : }
194 4585 : return 1;
195 :
196 154 : default: return 0;
197 : }
198 : }
199 :
200 : int
201 2021554 : RgX_is_ZXX(GEN x, long *v)
202 : {
203 : long i;
204 8484666 : for (i = lg(x)-1; i > 1; i--)
205 : {
206 6463321 : GEN xi = gel(x,i);
207 6463321 : long t = typ(xi), vi;
208 6463321 : if (t==t_INT) continue;
209 1011939 : if (t!=t_POL || !RgX_is_ZX(xi)) return 0;
210 1011765 : vi = varn(xi);
211 1011765 : if (*v < 0) *v = vi;
212 994 : else if (vi!=*v) return 0;
213 : }
214 2021345 : return 1;
215 : }
216 :
217 : int
218 3381 : RgX_is_FpXQX(GEN x, GEN *pT, GEN *pp)
219 : {
220 3381 : long i, lx = lg(x);
221 63427 : for (i = 2; i < lx; i++)
222 60144 : if (!Rg_is_FpXQ(gel(x,i), pT, pp)) return 0;
223 3283 : return 1;
224 : }
225 :
226 : /************************************************************************
227 : ** **
228 : ** Ring conversion **
229 : ** **
230 : ************************************************************************/
231 :
232 : /* p > 0 a t_INT, return lift(x * Mod(1,p)).
233 : * If x is an INTMOD, assume modulus is a multiple of p. */
234 : GEN
235 52334468 : Rg_to_Fp(GEN x, GEN p)
236 : {
237 52334468 : if (lgefint(p) == 3) return utoi(Rg_to_Fl(x, uel(p,2)));
238 4555528 : switch(typ(x))
239 : {
240 289105 : case t_INT: return modii(x, p);
241 18790 : case t_FRAC: {
242 18790 : pari_sp av = avma;
243 18790 : GEN z = modii(gel(x,1), p);
244 18790 : if (z == gen_0) return gen_0;
245 18785 : return gc_INT(av, remii(mulii(z, Fp_inv(gel(x,2), p)), p));
246 : }
247 70 : case t_PADIC: return padic_to_Fp(x, p);
248 4247567 : case t_INTMOD: {
249 4247567 : GEN q = gel(x,1), a = gel(x,2);
250 4247567 : if (equalii(q, p)) return icopy(a);
251 14 : if (!dvdii(q,p)) pari_err_MODULUS("Rg_to_Fp", q, p);
252 0 : return remii(a, p);
253 : }
254 0 : default: pari_err_TYPE("Rg_to_Fp",x);
255 : return NULL; /* LCOV_EXCL_LINE */
256 : }
257 : }
258 : /* If x is a POLMOD, assume modulus is a multiple of T. */
259 : GEN
260 1291986 : Rg_to_FpXQ(GEN x, GEN T, GEN p)
261 : {
262 1291986 : long ta, tx = typ(x), v = get_FpX_var(T);
263 : GEN a, b;
264 1291986 : if (is_const_t(tx))
265 : {
266 59182 : if (tx == t_FFELT)
267 : {
268 17355 : GEN z = FF_to_FpXQ(x);
269 17355 : setvarn(z, v);
270 17355 : return z;
271 : }
272 41827 : return scalar_ZX(degpol(T)? Rg_to_Fp(x, p): gen_0, v);
273 : }
274 1232804 : switch(tx)
275 : {
276 1230697 : case t_POLMOD:
277 1230697 : b = gel(x,1);
278 1230697 : a = gel(x,2); ta = typ(a);
279 1230697 : if (is_const_t(ta))
280 3885 : return scalar_ZX(degpol(T)? Rg_to_Fp(a, p): gen_0, v);
281 1226812 : b = RgX_to_FpX(b, p); if (varn(b) != v) break;
282 1226812 : a = RgX_to_FpX(a, p);
283 1226812 : if (ZX_equal(b,get_FpX_mod(T)) || signe(FpX_rem(b,T,p))==0)
284 1226812 : return FpX_rem(a, T, p);
285 0 : break;
286 2107 : case t_POL:
287 2107 : if (varn(x) != v) break;
288 2100 : return FpX_rem(RgX_to_FpX(x,p), T, p);
289 0 : case t_RFRAC:
290 0 : a = Rg_to_FpXQ(gel(x,1), T,p);
291 0 : b = Rg_to_FpXQ(gel(x,2), T,p);
292 0 : return FpXQ_div(a,b, T,p);
293 : }
294 7 : pari_err_TYPE("Rg_to_FpXQ",x);
295 : return NULL; /* LCOV_EXCL_LINE */
296 : }
297 : GEN
298 3335720 : RgX_to_FpX(GEN x, GEN p)
299 : {
300 : long i, l;
301 3335720 : GEN z = cgetg_copy(x, &l); z[1] = x[1];
302 14765324 : for (i = 2; i < l; i++) gel(z,i) = Rg_to_Fp(gel(x,i), p);
303 3335720 : return FpX_renormalize(z, l);
304 : }
305 :
306 : GEN
307 140 : RgV_to_FpV(GEN x, GEN p)
308 483 : { pari_APPLY_type(t_VEC, Rg_to_Fp(gel(x,i), p)) }
309 :
310 : GEN
311 1751090 : RgC_to_FpC(GEN x, GEN p)
312 28499485 : { pari_APPLY_type(t_COL, Rg_to_Fp(gel(x,i), p)) }
313 :
314 : GEN
315 222349 : RgM_to_FpM(GEN x, GEN p)
316 1973397 : { pari_APPLY_same(RgC_to_FpC(gel(x,i), p)) }
317 :
318 : GEN
319 369001 : RgV_to_Flv(GEN x, ulong p)
320 1676894 : { pari_APPLY_ulong(Rg_to_Fl(gel(x,i), p)) }
321 :
322 : GEN
323 118296 : RgM_to_Flm(GEN x, ulong p)
324 422998 : { pari_APPLY_same(RgV_to_Flv(gel(x,i), p)) }
325 :
326 : GEN
327 5105 : RgX_to_FpXQX(GEN x, GEN T, GEN p)
328 : {
329 5105 : long i, l = lg(x);
330 5105 : GEN z = cgetg(l, t_POL); z[1] = x[1];
331 43394 : for (i = 2; i < l; i++) gel(z,i) = Rg_to_FpXQ(gel(x,i), T,p);
332 5105 : return FpXQX_renormalize(z, l);
333 : }
334 : GEN
335 49186 : RgX_to_FqX(GEN x, GEN T, GEN p)
336 : {
337 49186 : long i, l = lg(x);
338 49186 : GEN z = cgetg(l, t_POL); z[1] = x[1];
339 49186 : if (T)
340 10990 : for (i = 2; i < l; i++) gel(z,i) = Rg_to_FpXQ(gel(x,i), T, p);
341 : else
342 791394 : for (i = 2; i < l; i++) gel(z,i) = Rg_to_Fp(gel(x,i), p);
343 49186 : return FpXQX_renormalize(z, l);
344 : }
345 :
346 : GEN
347 219128 : RgC_to_FqC(GEN x, GEN T, GEN p)
348 : {
349 219128 : long i, l = lg(x);
350 219128 : GEN z = cgetg(l, t_COL);
351 219128 : if (T)
352 1430310 : for (i = 1; i < l; i++) gel(z,i) = Rg_to_FpXQ(gel(x,i), T, p);
353 : else
354 0 : for (i = 1; i < l; i++) gel(z,i) = Rg_to_Fp(gel(x,i), p);
355 219128 : return z;
356 : }
357 :
358 : GEN
359 52325 : RgM_to_FqM(GEN x, GEN T, GEN p)
360 271418 : { pari_APPLY_same(RgC_to_FqC(gel(x, i), T, p)) }
361 :
362 : /* lg(V) > 1 */
363 : GEN
364 851487 : FpXV_FpC_mul(GEN V, GEN W, GEN p)
365 : {
366 851487 : pari_sp av = avma;
367 851487 : long i, l = lg(V);
368 851487 : GEN z = ZX_Z_mul(gel(V,1),gel(W,1));
369 4201029 : for(i=2; i<l; i++)
370 : {
371 3349542 : z = ZX_add(z, ZX_Z_mul(gel(V,i),gel(W,i)));
372 3349542 : if ((i & 7) == 0) z = gc_upto(av, z);
373 : }
374 851487 : return gc_upto(av, FpX_red(z,p));
375 : }
376 :
377 : GEN
378 55832 : FqX_Fq_add(GEN y, GEN x, GEN T, GEN p)
379 : {
380 55832 : long i, lz = lg(y);
381 : GEN z;
382 55832 : if (!T) return FpX_Fp_add(y, x, p);
383 8666 : if (lz == 2) return scalarpol(x, varn(y));
384 7952 : z = cgetg(lz,t_POL); z[1] = y[1];
385 7952 : gel(z,2) = Fq_add(gel(y,2),x, T, p);
386 7952 : if (lz == 3) z = FpXX_renormalize(z,lz);
387 : else
388 33145 : for(i=3;i<lz;i++) gel(z,i) = gcopy(gel(y,i));
389 7952 : return z;
390 : }
391 :
392 : GEN
393 1059 : FqX_Fq_sub(GEN y, GEN x, GEN T, GEN p)
394 : {
395 1059 : long i, lz = lg(y);
396 : GEN z;
397 1059 : if (!T) return FpX_Fp_sub(y, x, p);
398 1059 : if (lz == 2) return scalarpol(x, varn(y));
399 1059 : z = cgetg(lz,t_POL); z[1] = y[1];
400 1059 : gel(z,2) = Fq_sub(gel(y,2), x, T, p);
401 1059 : if (lz == 3) z = FpXX_renormalize(z,lz);
402 : else
403 10278 : for(i=3;i<lz;i++) gel(z,i) = gcopy(gel(y,i));
404 1059 : return z;
405 : }
406 :
407 : GEN
408 149052 : FqX_Fq_mul_to_monic(GEN P, GEN U, GEN T, GEN p)
409 : {
410 : long i, lP;
411 149052 : GEN res = cgetg_copy(P, &lP); res[1] = P[1];
412 918799 : for(i=2; i<lP-1; i++) gel(res,i) = Fq_mul(U,gel(P,i), T,p);
413 149052 : gel(res,lP-1) = gen_1; return res;
414 : }
415 :
416 : GEN
417 38189 : FpXQX_normalize(GEN z, GEN T, GEN p)
418 : {
419 : GEN lc;
420 38189 : if (lg(z) == 2) return z;
421 38175 : lc = leading_coeff(z);
422 38175 : if (typ(lc) == t_POL)
423 : {
424 2167 : if (lg(lc) > 3) /* nonconstant */
425 1902 : return FqX_Fq_mul_to_monic(z, Fq_inv(lc,T,p), T,p);
426 : /* constant */
427 265 : lc = gel(lc,2);
428 265 : z = shallowcopy(z);
429 265 : gel(z, lg(z)-1) = lc;
430 : }
431 : /* lc a t_INT */
432 36273 : if (equali1(lc)) return z;
433 87 : return FqX_Fq_mul_to_monic(z, Fp_inv(lc,p), T,p);
434 : }
435 :
436 : GEN
437 390935 : FqX_eval(GEN x, GEN y, GEN T, GEN p)
438 : {
439 : pari_sp av;
440 : GEN p1, r;
441 390935 : long j, i=lg(x)-1;
442 390935 : if (i<=2)
443 45107 : return (i==2)? Fq_red(gel(x,2), T, p): gen_0;
444 345828 : av=avma; p1=gel(x,i);
445 : /* specific attention to sparse polynomials (see poleval)*/
446 : /*You've guessed it! It's a copy-paste(tm)*/
447 1150441 : for (i--; i>=2; i=j-1)
448 : {
449 805300 : for (j=i; !signe(gel(x,j)); j--)
450 686 : if (j==2)
451 : {
452 490 : if (i!=j) y = Fq_pow(y,utoipos(i-j+1), T, p);
453 490 : return gc_upto(av, Fq_mul(p1,y, T, p));
454 : }
455 804614 : r = (i==j)? y: Fq_pow(y, utoipos(i-j+1), T, p);
456 804614 : p1 = Fq_add(Fq_mul(p1,r,T,p), gel(x,j), T, p);
457 : }
458 345337 : return gc_upto(av, p1);
459 : }
460 :
461 : GEN
462 97321 : FqXY_evalx(GEN Q, GEN x, GEN T, GEN p)
463 : {
464 97321 : long i, lb = lg(Q);
465 : GEN z;
466 97321 : if (!T) return FpXY_evalx(Q, x, p);
467 86961 : z = cgetg(lb, t_POL); z[1] = Q[1];
468 462945 : for (i=2; i<lb; i++)
469 : {
470 375984 : GEN q = gel(Q,i);
471 375984 : gel(z,i) = typ(q) == t_INT? modii(q,p): FqX_eval(q, x, T, p);
472 : }
473 86961 : return FpXQX_renormalize(z, lb);
474 : }
475 :
476 : /* Q an FpXY, evaluate at (X,Y) = (x,y) */
477 : GEN
478 14623 : FqXY_eval(GEN Q, GEN y, GEN x, GEN T, GEN p)
479 : {
480 14623 : pari_sp av = avma;
481 14623 : if (!T) return FpXY_eval(Q, y, x, p);
482 966 : return gc_upto(av, FqX_eval(FqXY_evalx(Q, x, T, p), y, T, p));
483 : }
484 :
485 : /* a X^d */
486 : GEN
487 13640799 : monomial(GEN a, long d, long v)
488 : {
489 : long i, n;
490 : GEN P;
491 13640799 : if (d < 0) {
492 14 : if (isrationalzero(a)) return pol_0(v);
493 14 : retmkrfrac(a, pol_xn(-d, v));
494 : }
495 13640785 : if (gequal0(a))
496 : {
497 93989 : if (isexactzero(a)) return scalarpol_shallow(a,v);
498 0 : n = d+2; P = cgetg(n+1, t_POL);
499 0 : P[1] = evalsigne(0) | evalvarn(v);
500 : }
501 : else
502 : {
503 13546793 : n = d+2; P = cgetg(n+1, t_POL);
504 13546794 : P[1] = evalsigne(1) | evalvarn(v);
505 : }
506 32923981 : for (i = 2; i < n; i++) gel(P,i) = gen_0;
507 13546794 : gel(P,i) = a; return P;
508 : }
509 : GEN
510 157969 : monomialcopy(GEN a, long d, long v)
511 : {
512 : long i, n;
513 : GEN P;
514 157969 : if (d < 0) {
515 14 : if (isrationalzero(a)) return pol_0(v);
516 14 : retmkrfrac(gcopy(a), pol_xn(-d, v));
517 : }
518 157955 : if (gequal0(a))
519 : {
520 14 : if (isexactzero(a)) return scalarpol(a,v);
521 7 : n = d+2; P = cgetg(n+1, t_POL);
522 7 : P[1] = evalsigne(0) | evalvarn(v);
523 : }
524 : else
525 : {
526 157941 : n = d+2; P = cgetg(n+1, t_POL);
527 157941 : P[1] = evalsigne(1) | evalvarn(v);
528 : }
529 314678 : for (i = 2; i < n; i++) gel(P,i) = gen_0;
530 157948 : gel(P,i) = gcopy(a); return P;
531 : }
532 : GEN
533 325951 : pol_x_powers(long N, long v)
534 : {
535 325951 : GEN L = cgetg(N+1,t_VEC);
536 : long i;
537 789059 : for (i=1; i<=N; i++) gel(L,i) = pol_xn(i-1, v);
538 325954 : return L;
539 : }
540 :
541 : GEN
542 0 : FqXQ_powers(GEN x, long l, GEN S, GEN T, GEN p)
543 : {
544 0 : return T ? FpXQXQ_powers(x, l, S, T, p): FpXQ_powers(x, l, S, p);
545 : }
546 :
547 : GEN
548 0 : FqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, GEN p)
549 : {
550 0 : return T ? FpXQXQ_matrix_pow(y, n, m, S, T, p): FpXQ_matrix_pow(y, n, m, S, p);
551 : }
552 :
553 : /*******************************************************************/
554 : /* */
555 : /* Fq */
556 : /* */
557 : /*******************************************************************/
558 :
559 : GEN
560 11592890 : Fq_add(GEN x, GEN y, GEN T/*unused*/, GEN p)
561 : {
562 : (void)T;
563 11592890 : switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
564 : {
565 1143687 : case 0: return Fp_add(x,y,p);
566 748136 : case 1: return FpX_Fp_add(x,y,p);
567 91991 : case 2: return FpX_Fp_add(y,x,p);
568 9609076 : case 3: return FpX_add(x,y,p);
569 : }
570 : return NULL;/*LCOV_EXCL_LINE*/
571 : }
572 :
573 : GEN
574 8563061 : Fq_sub(GEN x, GEN y, GEN T/*unused*/, GEN p)
575 : {
576 : (void)T;
577 8563061 : switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
578 : {
579 256368 : case 0: return Fp_sub(x,y,p);
580 24540 : case 1: return FpX_Fp_sub(x,y,p);
581 23896 : case 2: return Fp_FpX_sub(x,y,p);
582 8258257 : case 3: return FpX_sub(x,y,p);
583 : }
584 : return NULL;/*LCOV_EXCL_LINE*/
585 : }
586 :
587 : GEN
588 1080513 : Fq_neg(GEN x, GEN T/*unused*/, GEN p)
589 : {
590 : (void)T;
591 1080513 : return (typ(x)==t_POL)? FpX_neg(x,p): Fp_neg(x,p);
592 : }
593 :
594 : GEN
595 81354 : Fq_halve(GEN x, GEN T/*unused*/, GEN p)
596 : {
597 : (void)T;
598 81354 : return (typ(x)==t_POL)? FpX_halve(x,p): Fp_halve(x,p);
599 : }
600 :
601 : /* If T==NULL do not reduce*/
602 : GEN
603 8608661 : Fq_mul(GEN x, GEN y, GEN T, GEN p)
604 : {
605 8608661 : switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
606 : {
607 1037917 : case 0: return Fp_mul(x,y,p);
608 128565 : case 1: return FpX_Fp_mul(x,y,p);
609 394686 : case 2: return FpX_Fp_mul(y,x,p);
610 7047497 : case 3: if (T) return FpXQ_mul(x,y,T,p);
611 4478770 : else return FpX_mul(x,y,p);
612 : }
613 : return NULL;/*LCOV_EXCL_LINE*/
614 : }
615 :
616 : /* If T==NULL do not reduce*/
617 : GEN
618 490590 : Fq_mulu(GEN x, ulong y, /*unused*/GEN T, GEN p)
619 : {
620 : (void) T;
621 490590 : return typ(x)==t_POL ? FpX_Fp_mul(x,utoi(y),p): Fp_mulu(x, y, p);
622 : }
623 :
624 : /* y t_INT */
625 : GEN
626 44041 : Fq_Fp_mul(GEN x, GEN y, GEN T/*unused*/, GEN p)
627 : {
628 : (void)T;
629 6822 : return (typ(x) == t_POL)? FpX_Fp_mul(x,y,p)
630 50863 : : Fp_mul(x,y,p);
631 : }
632 : /* If T==NULL do not reduce*/
633 : GEN
634 611418 : Fq_sqr(GEN x, GEN T, GEN p)
635 : {
636 611418 : if (typ(x) == t_POL)
637 : {
638 70585 : if (T) return FpXQ_sqr(x,T,p);
639 0 : else return FpX_sqr(x,p);
640 : }
641 : else
642 540833 : return Fp_sqr(x,p);
643 : }
644 :
645 : GEN
646 0 : Fq_neg_inv(GEN x, GEN T, GEN p)
647 : {
648 0 : if (typ(x) == t_INT) return Fp_inv(Fp_neg(x,p),p);
649 0 : return FpXQ_inv(FpX_neg(x,p),T,p);
650 : }
651 :
652 : GEN
653 0 : Fq_invsafe(GEN x, GEN pol, GEN p)
654 : {
655 0 : if (typ(x) == t_INT) return Fp_invsafe(x,p);
656 0 : return FpXQ_invsafe(x,pol,p);
657 : }
658 :
659 : GEN
660 89312 : Fq_inv(GEN x, GEN pol, GEN p)
661 : {
662 89312 : if (typ(x) == t_INT) return Fp_inv(x,p);
663 81546 : return FpXQ_inv(x,pol,p);
664 : }
665 :
666 : GEN
667 343791 : Fq_div(GEN x, GEN y, GEN pol, GEN p)
668 : {
669 343791 : switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
670 : {
671 318402 : case 0: return Fp_div(x,y,p);
672 16702 : case 1: return FpX_Fp_div(x,y,p);
673 406 : case 2: return FpX_Fp_mul(FpXQ_inv(y,pol,p),x,p);
674 8281 : case 3: return FpXQ_div(x,y,pol,p);
675 : }
676 : return NULL;/*LCOV_EXCL_LINE*/
677 : }
678 :
679 : GEN
680 1088144 : Fq_pow(GEN x, GEN n, GEN pol, GEN p)
681 : {
682 1088144 : if (typ(x) == t_INT) return Fp_pow(x,n,p);
683 137457 : return FpXQ_pow(x,n,pol,p);
684 : }
685 :
686 : GEN
687 15050 : Fq_powu(GEN x, ulong n, GEN pol, GEN p)
688 : {
689 15050 : if (typ(x) == t_INT) return Fp_powu(x,n,p);
690 1267 : return FpXQ_powu(x,n,pol,p);
691 : }
692 :
693 : GEN
694 1892926 : Fq_sqrt(GEN x, GEN T, GEN p)
695 : {
696 1892926 : if (typ(x) == t_INT)
697 : {
698 1825064 : if (!T || odd(get_FpX_degree(T))) return Fp_sqrt(x,p);
699 9621 : x = scalarpol_shallow(x, get_FpX_var(T));
700 : }
701 77483 : return FpXQ_sqrt(x,T,p);
702 : }
703 : GEN
704 170786 : Fq_sqrtn(GEN x, GEN n, GEN T, GEN p, GEN *zeta)
705 : {
706 170786 : if (typ(x) == t_INT)
707 : {
708 : long d;
709 170415 : if (!T) return Fp_sqrtn(x,n,p,zeta);
710 126 : d = get_FpX_degree(T);
711 126 : if (ugcdiu(n,d) == 1)
712 : {
713 56 : if (!zeta) return Fp_sqrtn(x,n,p,NULL);
714 : /* gcd(n,p-1)=gcd(n,q-1): same number of solutions in Fp and F_q */
715 21 : if (equalii(gcdii(subiu(p,1),n), gcdii(subiu(Fp_powu(p,d,n), 1), n)))
716 14 : return Fp_sqrtn(x,n,p,zeta);
717 : }
718 77 : x = scalarpol(x, get_FpX_var(T)); /* left on stack */
719 : }
720 448 : return FpXQ_sqrtn(x,n,T,p,zeta);
721 : }
722 :
723 : struct _Fq_field
724 : {
725 : GEN T, p;
726 : };
727 :
728 : static GEN
729 303247 : _Fq_red(void *E, GEN x)
730 303247 : { struct _Fq_field *s = (struct _Fq_field *)E;
731 303247 : return Fq_red(x, s->T, s->p);
732 : }
733 :
734 : static GEN
735 362523 : _Fq_add(void *E, GEN x, GEN y)
736 : {
737 : (void) E;
738 362523 : switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
739 : {
740 14 : case 0: return addii(x,y);
741 0 : case 1: return ZX_Z_add(x,y);
742 15918 : case 2: return ZX_Z_add(y,x);
743 346591 : default: return ZX_add(x,y);
744 : }
745 : }
746 :
747 : static GEN
748 315028 : _Fq_neg(void *E, GEN x) { (void) E; return typ(x)==t_POL?ZX_neg(x):negi(x); }
749 :
750 : static GEN
751 243341 : _Fq_mul(void *E, GEN x, GEN y)
752 : {
753 : (void) E;
754 243341 : switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
755 : {
756 679 : case 0: return mulii(x,y);
757 1085 : case 1: return ZX_Z_mul(x,y);
758 1043 : case 2: return ZX_Z_mul(y,x);
759 240534 : default: return ZX_mul(x,y);
760 : }
761 : }
762 :
763 : static GEN
764 9331 : _Fq_inv(void *E, GEN x)
765 9331 : { struct _Fq_field *s = (struct _Fq_field *)E;
766 9331 : return Fq_inv(x,s->T,s->p);
767 : }
768 :
769 : static int
770 38388 : _Fq_equal0(GEN x) { return signe(x)==0; }
771 :
772 : static GEN
773 4151 : _Fq_s(void *E, long x) { (void) E; return stoi(x); }
774 :
775 : static const struct bb_field Fq_field={_Fq_red,_Fq_add,_Fq_mul,_Fq_neg,
776 : _Fq_inv,_Fq_equal0,_Fq_s};
777 :
778 4725 : const struct bb_field *get_Fq_field(void **E, GEN T, GEN p)
779 : {
780 4725 : if (!T)
781 0 : return get_Fp_field(E, p);
782 : else
783 : {
784 4725 : GEN z = new_chunk(sizeof(struct _Fq_field));
785 4725 : struct _Fq_field *e = (struct _Fq_field *) z;
786 4725 : e->T = T; e->p = p; *E = (void*)e;
787 4725 : return &Fq_field;
788 : }
789 : }
790 :
791 : /*******************************************************************/
792 : /* */
793 : /* Fq[X] */
794 : /* */
795 : /*******************************************************************/
796 : /* FpV_red(vecbinomial(n), p) */
797 : static GEN
798 0 : vecbinomial_Fp(long n, GEN p)
799 : {
800 0 : GEN C = vecbinomial(n) + 1;
801 0 : long k, d = (n + 1) >> 1;
802 0 : for (k = d; k >= 1; k--)
803 : {
804 0 : GEN a = gel(C,k);
805 0 : if (cmpii(a, p) < 0) break;
806 0 : gel(C,k) = gel(C, n-k) = remii(a, p);
807 : }
808 0 : return C - 1;
809 : }
810 : /* (X+u)^n */
811 : static GEN
812 434 : Fp_XpN_powu(GEN u, ulong n, GEN p, long v)
813 : {
814 : pari_sp av;
815 : ulong k;
816 : GEN B, C, V;
817 434 : if (!n) return pol_1(v);
818 434 : if (is_pm1(u))
819 434 : return Xpm1_powu(n, signe(u), v);
820 0 : av = avma;
821 0 : V = Fp_powers(u, n, p);
822 0 : B = vecbinomial_Fp(n, p);
823 0 : C = cgetg(n+3, t_POL);
824 0 : C[1] = evalsigne(1)| evalvarn(v);
825 0 : for (k=1; k <= n+1; k++)
826 0 : gel(C,k+1) = Fp_mul(gel(V,n+2-k), gel(B,k), p);
827 0 : return gc_upto(av, C);
828 : }
829 :
830 : static GEN
831 700 : FpX_Fp_translate_basecase(GEN P, GEN c, GEN p)
832 : {
833 700 : pari_sp av = avma;
834 : GEN Q;
835 : long i, k, n;
836 :
837 700 : if (!signe(P) || !signe(c)) return ZX_copy(P);
838 560 : Q = leafcopy(P); n = degpol(P);
839 1316 : for (i=1; i<=n; i++)
840 : {
841 2016 : for (k=n-i; k<n; k++)
842 1260 : gel(Q,2+k) = Fp_add(gel(Q,2+k), Fp_mul(c, gel(Q,2+k+1), p), p);
843 :
844 756 : if (gc_needed(av,2))
845 : {
846 0 : if(DEBUGMEM>1) pari_warn(warnmem,"FpX_Fp_translate, i = %ld/%ld", i,n);
847 0 : Q = gc_GEN(av, Q);
848 : }
849 : }
850 560 : return gc_GEN(av, FpX_renormalize(Q, lg(Q)));
851 : }
852 :
853 : GEN
854 1134 : FpX_Fp_translate(GEN P, GEN c, GEN p)
855 : {
856 1134 : pari_sp av = avma;
857 1134 : long n = degpol(P);
858 1134 : if (n<=3 || 25*(n-3) < expi(p))
859 700 : return FpX_Fp_translate_basecase(P, c, p);
860 : else
861 : {
862 434 : long d = n >> 1;
863 434 : GEN Q = FpX_Fp_translate(RgX_shift_shallow(P, -d), c, p);
864 434 : GEN R = FpX_Fp_translate(RgXn_red_shallow(P, d), c, p);
865 434 : GEN S = Fp_XpN_powu(c, d, p, varn(P));
866 434 : return gc_upto(av, FpX_add(FpX_mul(Q, S, p), R, p));
867 : }
868 : }
869 :
870 : /* (X+u)^n mod (T,p) */
871 : static GEN
872 0 : FpXQX_XpN_powu(GEN u, ulong n, GEN T, GEN p, long v)
873 : {
874 : pari_sp av;
875 : ulong k;
876 : GEN B, C, V;
877 0 : if (!n) return pol_1(v);
878 0 : av = avma;
879 0 : V = FpXQ_powers(u, n, T, p);
880 0 : B = vecbinomial_Fp(n, p);
881 0 : C = cgetg(n+3, t_POL);
882 0 : C[1] = evalsigne(1)| evalvarn(v);
883 0 : for (k=1; k <= n+1; k++)
884 0 : gel(C,k+1) = Fq_mul(gel(V,n+2-k), gel(B,k), T, p);
885 0 : return gc_upto(av, C);
886 : }
887 :
888 : static GEN
889 33887 : FpXQX_FpXQ_translate_basecase(GEN P, GEN c, GEN T, GEN p)
890 : {
891 33887 : pari_sp av = avma;
892 : GEN Q;
893 : long i, k, n;
894 :
895 : /* signe works for t_(INT|POL) */
896 33887 : if (!signe(P) || !signe(c)) return RgX_copy(P);
897 33887 : Q = leafcopy(P); n = degpol(P);
898 150080 : for (i=1; i<=n; i++)
899 : {
900 433594 : for (k=n-i; k<n; k++)
901 317401 : gel(Q,2+k) = Fq_add(gel(Q,2+k), Fq_mul(c, gel(Q,2+k+1), T, p), T, p);
902 :
903 116193 : if (gc_needed(av,2))
904 : {
905 0 : if(DEBUGMEM>1) pari_warn(warnmem,"FqX_Fq_translate, i = %ld/%ld", i,n);
906 0 : Q = gc_GEN(av, Q);
907 : }
908 : }
909 33887 : return gc_GEN(av, FpXQX_renormalize(Q, lg(Q)));
910 : }
911 :
912 : GEN
913 33887 : FpXQX_FpXQ_translate(GEN P, GEN c, GEN T, GEN p)
914 : {
915 33887 : pari_sp av = avma;
916 33887 : long n = degpol(P);
917 33887 : if (n < 220)
918 33887 : return FpXQX_FpXQ_translate_basecase(P, c, T, p);
919 : else
920 : {
921 0 : long d = n >> 1;
922 0 : GEN Q = FpXQX_FpXQ_translate(RgX_shift_shallow(P, -d), c, T, p);
923 0 : GEN R = FpXQX_FpXQ_translate(RgXn_red_shallow(P, d), c, T, p);
924 0 : GEN S = FpXQX_XpN_powu(c, d, T, p, varn(P));
925 0 : return gc_upto(av, FpXX_add(FpXQX_mul(Q, S, T, p), R, p));
926 : }
927 : }
928 :
929 : GEN
930 33880 : FqX_Fq_translate(GEN x, GEN y, GEN T, GEN p)
931 : {
932 33880 : if (!T) return FpX_Fp_translate(x,y,p);
933 33880 : if (typ(y)==t_INT)
934 : {
935 0 : pari_sp av = avma;
936 0 : y = scalarpol_shallow(y,varn(T));
937 0 : return gc_upto(av, FpXQX_FpXQ_translate(x,y,T,p));
938 : }
939 33880 : return FpXQX_FpXQ_translate(x,y,T,p);
940 : }
941 :
942 : GEN
943 40450 : FqV_roots_to_pol(GEN V, GEN T, GEN p, long v)
944 : {
945 40450 : pari_sp ltop = avma;
946 : long k;
947 : GEN W;
948 40450 : if (lgefint(p) == 3)
949 : {
950 31739 : ulong pp = p[2];
951 31739 : GEN Tl = ZX_to_Flx(T, pp);
952 31743 : GEN Vl = FqC_to_FlxqC(V, Tl, pp);
953 31745 : Tl = FlxqV_roots_to_pol(Vl, Tl, pp, v);
954 31744 : return gc_upto(ltop, FlxX_to_ZXX(Tl));
955 : }
956 8711 : W = cgetg(lg(V),t_VEC);
957 78117 : for(k=1; k < lg(V); k++)
958 69406 : gel(W,k) = deg1pol_shallow(gen_1,Fq_neg(gel(V,k),T,p),v);
959 8711 : return gc_upto(ltop, FpXQXV_prod(W, T, p));
960 : }
961 :
962 : GEN
963 109459 : FqV_red(GEN x, GEN T, GEN p)
964 778034 : { pari_APPLY_type(t_VEC, Fq_red(gel(x,i), T, p)) }
965 :
966 : GEN
967 24058 : FqC_red(GEN x, GEN T, GEN p)
968 163384 : { pari_APPLY_type(t_COL, Fq_red(gel(x,i), T, p)) }
969 :
970 : GEN
971 1701 : FqM_red(GEN x, GEN T, GEN p)
972 5411 : { pari_APPLY_same(FqC_red(gel(x,i), T, p)) }
973 :
974 : GEN
975 0 : FqC_add(GEN x, GEN y, GEN T, GEN p)
976 : {
977 0 : if (!T) return FpC_add(x, y, p);
978 0 : pari_APPLY_type(t_COL, Fq_add(gel(x,i), gel(y,i), T, p))
979 : }
980 :
981 : GEN
982 0 : FqM_add(GEN x, GEN y, GEN T, GEN p)
983 : {
984 0 : if (!T) return FpM_add(x, y, p);
985 0 : pari_APPLY_same(FqC_add(gel(x,i), gel(y,i), T, p))
986 : }
987 :
988 : GEN
989 0 : FqC_sub(GEN x, GEN y, GEN T, GEN p)
990 : {
991 0 : if (!T) return FpC_sub(x, y, p);
992 0 : pari_APPLY_type(t_COL, Fq_sub(gel(x,i), gel(y,i), T, p))
993 : }
994 :
995 : GEN
996 0 : FqM_sub(GEN x, GEN y, GEN T, GEN p)
997 : {
998 0 : if (!T) return FpM_sub(x, y, p);
999 0 : pari_APPLY_same(FqC_sub(gel(x,i), gel(y,i), T, p))
1000 : }
1001 :
1002 : GEN
1003 0 : FqC_Fq_mul(GEN x, GEN y, GEN T, GEN p)
1004 : {
1005 0 : if (!T) return FpC_Fp_mul(x, y, p);
1006 0 : pari_APPLY_type(t_COL, Fq_mul(gel(x,i),y,T,p))
1007 : }
1008 :
1009 : GEN
1010 105 : FqC_FqV_mul(GEN x, GEN y, GEN T, GEN p)
1011 : {
1012 105 : long i,j, lx=lg(x), ly=lg(y);
1013 : GEN z;
1014 105 : if (ly==1) return cgetg(1,t_MAT);
1015 105 : z = cgetg(ly,t_MAT);
1016 819 : for (j=1; j < ly; j++)
1017 : {
1018 714 : GEN zj = cgetg(lx,t_COL);
1019 4200 : for (i=1; i<lx; i++) gel(zj,i) = Fq_mul(gel(x,i),gel(y,j), T, p);
1020 714 : gel(z, j) = zj;
1021 : }
1022 105 : return z;
1023 : }
1024 :
1025 : GEN
1026 5467 : FpXC_center(GEN x, GEN p, GEN pov2)
1027 41476 : { pari_APPLY_type(t_COL, FpX_center(gel(x,i), p, pov2)) }
1028 :
1029 : GEN
1030 109020 : FqC_to_FlxqC(GEN x, GEN T, ulong p)
1031 109020 : { long sv = get_Flx_var(T);
1032 4834755 : pari_APPLY_type(t_COL,typ(gel(x,i))==t_INT ?
1033 : Z_to_Flx(gel(x,i), p, sv): ZX_to_Flx(gel(x,i), p)) }
1034 :
1035 : GEN
1036 8708 : FqM_to_FlxqM(GEN x, GEN T, ulong p)
1037 85985 : { pari_APPLY_same(FqC_to_FlxqC(gel(x,i), T, p)) }
1038 :
1039 : GEN
1040 1800 : FpXM_center(GEN x, GEN p, GEN pov2)
1041 7267 : { pari_APPLY_same(FpXC_center(gel(x,i), p, pov2)) }
1042 :
1043 : /*******************************************************************/
1044 : /* */
1045 : /* GENERIC CRT */
1046 : /* */
1047 : /*******************************************************************/
1048 : static GEN
1049 9414479 : primelist(forprime_t *S, long n, GEN dB)
1050 : {
1051 9414479 : GEN P = cgetg(n+1, t_VECSMALL);
1052 9414453 : long i = 1;
1053 : ulong p;
1054 22385319 : while (i <= n && (p = u_forprime_next(S)))
1055 12970866 : if (!dB || umodiu(dB, p)) P[i++] = p;
1056 9414448 : return P;
1057 : }
1058 :
1059 : void
1060 8826386 : gen_inccrt_i(const char *str, GEN worker, GEN dB, long n, long mmin,
1061 : forprime_t *S, GEN *pH, GEN *pmod, GEN crt(GEN, GEN, GEN*),
1062 : GEN center(GEN, GEN, GEN))
1063 : {
1064 8826386 : long m = mmin? minss(mmin, n): usqrt(n);
1065 : GEN H, P, mod;
1066 : pari_timer ti;
1067 8826384 : if (DEBUGLEVEL > 4)
1068 : {
1069 0 : timer_start(&ti);
1070 0 : err_printf("%s: nb primes: %ld\n",str, n);
1071 : }
1072 8826380 : if (m == 1)
1073 : {
1074 8510391 : GEN P = primelist(S, n, dB);
1075 8510351 : GEN done = closure_callgen1(worker, P);
1076 8510363 : H = gel(done,1);
1077 8510363 : mod = gel(done,2);
1078 8510363 : if (!*pH && center) H = center(H, mod, shifti(mod,-1));
1079 8510305 : if (DEBUGLEVEL>4) timer_printf(&ti,"%s: modular", str);
1080 : }
1081 : else
1082 : {
1083 315989 : long i, s = (n+m-1)/m, r = m - (m*s-n), di = 0;
1084 : struct pari_mt pt;
1085 315989 : long pending = 0;
1086 315989 : H = cgetg(m+1, t_VEC); P = cgetg(m+1, t_VEC);
1087 315989 : mt_queue_start_lim(&pt, worker, m);
1088 1286075 : for (i=1; i<=m || pending; i++)
1089 : {
1090 : GEN done;
1091 970085 : GEN pr = i <= m ? mkvec(primelist(S, i<=r ? s: s-1, dB)): NULL;
1092 970087 : mt_queue_submit(&pt, i, pr);
1093 970088 : done = mt_queue_get(&pt, NULL, &pending);
1094 970088 : if (done)
1095 : {
1096 904095 : di++;
1097 904095 : gel(H, di) = gel(done,1);
1098 904095 : gel(P, di) = gel(done,2);
1099 904095 : if (DEBUGLEVEL>5) err_printf("%ld%% ",100*di/m);
1100 : }
1101 : }
1102 315990 : mt_queue_end(&pt);
1103 315990 : if (DEBUGLEVEL>5) err_printf("\n");
1104 315990 : if (DEBUGLEVEL>4) timer_printf(&ti,"%s: modular", str);
1105 315990 : H = crt(H, P, &mod);
1106 315990 : if (DEBUGLEVEL>4) timer_printf(&ti,"%s: chinese", str);
1107 : }
1108 8826295 : if (*pH) H = crt(mkvec2(*pH, H), mkvec2(*pmod, mod), &mod);
1109 8826295 : *pH = H; *pmod = mod;
1110 8826295 : }
1111 : void
1112 3073116 : gen_inccrt(const char *str, GEN worker, GEN dB, long n, long mmin,
1113 : forprime_t *S, GEN *pH, GEN *pmod, GEN crt(GEN, GEN, GEN*),
1114 : GEN center(GEN, GEN, GEN))
1115 : {
1116 3073116 : pari_sp av = avma;
1117 3073116 : gen_inccrt_i(str, worker, dB, n, mmin, S, pH, pmod, crt, center);
1118 3073078 : (void)gc_all(av, 2, pH, pmod);
1119 3073203 : }
1120 :
1121 : GEN
1122 2285278 : gen_crt(const char *str, GEN worker, forprime_t *S, GEN dB, ulong bound, long mmin, GEN *pmod,
1123 : GEN crt(GEN, GEN, GEN*), GEN center(GEN, GEN, GEN))
1124 : {
1125 2285278 : GEN mod = gen_1, H = NULL;
1126 : ulong e;
1127 :
1128 2285278 : bound++;
1129 4570619 : while (bound > (e = expi(mod)))
1130 : {
1131 2285232 : long n = (bound - e) / expu(S->p) + 1;
1132 2285256 : gen_inccrt(str, worker, dB, n, mmin, S, &H, &mod, crt, center);
1133 : }
1134 2285329 : if (pmod) *pmod = mod;
1135 2285329 : return H;
1136 : }
1137 :
1138 : /*******************************************************************/
1139 : /* */
1140 : /* MODULAR GCD */
1141 : /* */
1142 : /*******************************************************************/
1143 : /* return z = a mod q, b mod p (p,q) = 1; qinv = 1/q mod p; a in ]-q,q] */
1144 : static GEN
1145 5162002 : Fl_chinese_coprime(GEN a, ulong b, GEN q, ulong p, ulong qinv, GEN pq, GEN pq2)
1146 : {
1147 5162002 : ulong d, amod = umodiu(a, p);
1148 5161982 : pari_sp av = avma;
1149 : GEN ax;
1150 :
1151 5161982 : if (b == amod) return NULL;
1152 2126105 : d = Fl_mul(Fl_sub(b, amod, p), qinv, p); /* != 0 */
1153 2126822 : if (d >= 1 + (p>>1))
1154 1037715 : ax = subii(a, mului(p-d, q));
1155 : else
1156 : {
1157 1089107 : ax = addii(a, mului(d, q)); /* in ]0, pq[ assuming a in ]-q,q[ */
1158 1088869 : if (cmpii(ax,pq2) > 0) ax = subii(ax,pq);
1159 : }
1160 2126261 : return gc_INT(av, ax);
1161 : }
1162 : GEN
1163 406 : Z_init_CRT(ulong Hp, ulong p) { return stoi(Fl_center(Hp, p, p>>1)); }
1164 : GEN
1165 32487 : ZX_init_CRT(GEN Hp, ulong p, long v)
1166 : {
1167 32487 : long i, l = lg(Hp), lim = (long)(p>>1);
1168 32487 : GEN H = cgetg(l, t_POL);
1169 32487 : H[1] = evalsigne(1) | evalvarn(v);
1170 801138 : for (i=2; i<l; i++)
1171 768651 : gel(H,i) = stoi(Fl_center(Hp[i], p, lim));
1172 32487 : return ZX_renormalize(H,l);
1173 : }
1174 :
1175 : GEN
1176 5978 : ZM_init_CRT(GEN Hp, ulong p)
1177 : {
1178 5978 : long i,j, m, l = lg(Hp), lim = (long)(p>>1);
1179 5978 : GEN c, cp, H = cgetg(l, t_MAT);
1180 5978 : if (l==1) return H;
1181 5978 : m = lgcols(Hp);
1182 20223 : for (j=1; j<l; j++)
1183 : {
1184 14245 : cp = gel(Hp,j);
1185 14245 : c = cgetg(m, t_COL);
1186 14245 : gel(H,j) = c;
1187 169316 : for (i=1; i<m; i++) gel(c,i) = stoi(Fl_center(cp[i],p, lim));
1188 : }
1189 5978 : return H;
1190 : }
1191 :
1192 : int
1193 7742 : Z_incremental_CRT(GEN *H, ulong Hp, GEN *ptq, ulong p)
1194 : {
1195 7742 : GEN h, q = *ptq, qp = muliu(q,p);
1196 7742 : ulong qinv = Fl_inv(umodiu(q,p), p);
1197 7742 : int stable = 1;
1198 7742 : h = Fl_chinese_coprime(*H,Hp,q,p,qinv,qp,shifti(qp,-1));
1199 7742 : if (h) { *H = h; stable = 0; }
1200 7742 : *ptq = qp; return stable;
1201 : }
1202 :
1203 : static int
1204 148375 : ZX_incremental_CRT_raw(GEN *ptH, GEN Hp, GEN q, GEN qp, ulong p)
1205 : {
1206 148375 : GEN H = *ptH, h, qp2 = shifti(qp,-1);
1207 148370 : ulong qinv = Fl_inv(umodiu(q,p), p);
1208 148380 : long i, l = lg(H), lp = lg(Hp);
1209 148380 : int stable = 1;
1210 :
1211 148380 : if (l < lp)
1212 : { /* degree increases */
1213 0 : GEN x = cgetg(lp, t_POL);
1214 0 : for (i=1; i<l; i++) x[i] = H[i];
1215 0 : for ( ; i<lp; i++) gel(x,i) = gen_0;
1216 0 : *ptH = H = x;
1217 0 : stable = 0;
1218 148380 : } else if (l > lp)
1219 : { /* degree decreases */
1220 0 : GEN x = cgetg(l, t_VECSMALL);
1221 0 : for (i=1; i<lp; i++) x[i] = Hp[i];
1222 0 : for ( ; i<l; i++) x[i] = 0;
1223 0 : Hp = x; lp = l;
1224 : }
1225 4938885 : for (i=2; i<lp; i++)
1226 : {
1227 4790595 : h = Fl_chinese_coprime(gel(H,i),Hp[i],q,p,qinv,qp,qp2);
1228 4790505 : if (h) { gel(H,i) = h; stable = 0; }
1229 : }
1230 148290 : (void)ZX_renormalize(H,lp);
1231 148377 : return stable;
1232 : }
1233 :
1234 : int
1235 0 : ZX_incremental_CRT(GEN *ptH, GEN Hp, GEN *ptq, ulong p)
1236 : {
1237 0 : GEN q = *ptq, qp = muliu(q,p);
1238 0 : int stable = ZX_incremental_CRT_raw(ptH, Hp, q, qp, p);
1239 0 : *ptq = qp; return stable;
1240 : }
1241 :
1242 : int
1243 7787 : ZM_incremental_CRT(GEN *pH, GEN Hp, GEN *ptq, ulong p)
1244 : {
1245 7787 : GEN h, H = *pH, q = *ptq, qp = muliu(q, p), qp2 = shifti(qp,-1);
1246 7787 : ulong qinv = Fl_inv(umodiu(q,p), p);
1247 7787 : long i,j, l = lg(H), m = lgcols(H);
1248 7787 : int stable = 1;
1249 27451 : for (j=1; j<l; j++)
1250 205516 : for (i=1; i<m; i++)
1251 : {
1252 185852 : h = Fl_chinese_coprime(gcoeff(H,i,j), coeff(Hp,i,j),q,p,qinv,qp,qp2);
1253 185852 : if (h) { gcoeff(H,i,j) = h; stable = 0; }
1254 : }
1255 7787 : *ptq = qp; return stable;
1256 : }
1257 :
1258 : GEN
1259 679 : ZXM_init_CRT(GEN Hp, long deg, ulong p)
1260 : {
1261 : long i, j, k;
1262 : GEN H;
1263 679 : long m, l = lg(Hp), lim = (long)(p>>1), n;
1264 679 : H = cgetg(l, t_MAT);
1265 679 : if (l==1) return H;
1266 679 : m = lgcols(Hp);
1267 679 : n = deg + 3;
1268 2268 : for (j=1; j<l; j++)
1269 : {
1270 1589 : GEN cp = gel(Hp,j);
1271 1589 : GEN c = cgetg(m, t_COL);
1272 1589 : gel(H,j) = c;
1273 24465 : for (i=1; i<m; i++)
1274 : {
1275 22876 : GEN dp = gel(cp, i);
1276 22876 : long l = lg(dp);
1277 22876 : GEN d = cgetg(n, t_POL);
1278 22876 : gel(c, i) = d;
1279 22876 : d[1] = dp[1] | evalsigne(1);
1280 46459 : for (k=2; k<l; k++)
1281 23583 : gel(d,k) = stoi(Fl_center(dp[k], p, lim));
1282 45493 : for ( ; k<n; k++)
1283 22617 : gel(d,k) = gen_0;
1284 : }
1285 : }
1286 679 : return H;
1287 : }
1288 :
1289 : int
1290 653 : ZXM_incremental_CRT(GEN *pH, GEN Hp, GEN *ptq, ulong p)
1291 : {
1292 653 : GEN v, H = *pH, q = *ptq, qp = muliu(q, p), qp2 = shifti(qp,-1);
1293 653 : ulong qinv = Fl_inv(umodiu(q,p), p);
1294 653 : long i,j,k, l = lg(H), m = lgcols(H), n = lg(gmael(H,1,1));
1295 653 : int stable = 1;
1296 2225 : for (j=1; j<l; j++)
1297 90418 : for (i=1; i<m; i++)
1298 : {
1299 88846 : GEN h = gmael(H,j,i), hp = gmael(Hp,j,i);
1300 88846 : long lh = lg(hp);
1301 246641 : for (k=2; k<lh; k++)
1302 : {
1303 157795 : v = Fl_chinese_coprime(gel(h,k),uel(hp,k),q,p,qinv,qp,qp2);
1304 157795 : if (v) { gel(h,k) = v; stable = 0; }
1305 : }
1306 108763 : for (; k<n; k++)
1307 : {
1308 19917 : v = Fl_chinese_coprime(gel(h,k),0,q,p,qinv,qp,qp2);
1309 19917 : if (v) { gel(h,k) = v; stable = 0; }
1310 : }
1311 : }
1312 653 : *ptq = qp; return stable;
1313 : }
1314 :
1315 : /* record the degrees of Euclidean remainders (make them as large as
1316 : * possible : smaller values correspond to a degenerate sequence) */
1317 : static void
1318 23741 : Flx_resultant_set_dglist(GEN a, GEN b, GEN dglist, ulong p)
1319 : {
1320 : long da,db,dc, ind;
1321 23741 : pari_sp av = avma;
1322 :
1323 23741 : if (lgpol(a)==0 || lgpol(b)==0) return;
1324 22474 : da = degpol(a);
1325 22474 : db = degpol(b);
1326 22474 : if (db > da)
1327 0 : { swapspec(a,b, da,db); }
1328 22474 : else if (!da) return;
1329 22474 : ind = 0;
1330 145766 : while (db)
1331 : {
1332 123292 : GEN c = Flx_rem(a,b, p);
1333 123291 : a = b; b = c; dc = degpol(c);
1334 123290 : if (dc < 0) break;
1335 :
1336 123290 : ind++;
1337 123290 : if (dc > dglist[ind]) dglist[ind] = dc;
1338 123290 : if (gc_needed(av,2))
1339 : {
1340 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flx_resultant_all");
1341 0 : (void)gc_all(av, 2, &a,&b);
1342 : }
1343 123292 : db = dc; /* = degpol(b) */
1344 : }
1345 22474 : if (ind+1 > lg(dglist)) setlg(dglist,ind+1);
1346 22474 : set_avma(av);
1347 : }
1348 : /* assuming the PRS finishes on a degree 1 polynomial C0 + C1X, with
1349 : * "generic" degree sequence as given by dglist, set *Ci and return
1350 : * resultant(a,b). Modular version of Collins's subresultant */
1351 : static ulong
1352 2089628 : Flx_resultant_all(GEN a, GEN b, long *C0, long *C1, GEN dglist, ulong p)
1353 : {
1354 : long da,db,dc, ind;
1355 2089628 : ulong lb, res, g = 1UL, h = 1UL, ca = 1UL, cb = 1UL;
1356 2089628 : int s = 1;
1357 2089628 : pari_sp av = avma;
1358 :
1359 2089628 : *C0 = 1; *C1 = 0;
1360 2089628 : if (lgpol(a)==0 || lgpol(b)==0) return 0;
1361 2080125 : da = degpol(a);
1362 2080115 : db = degpol(b);
1363 2080082 : if (db > da)
1364 : {
1365 0 : swapspec(a,b, da,db);
1366 0 : if (both_odd(da,db)) s = -s;
1367 : }
1368 2080082 : else if (!da) return 1; /* = a[2] ^ db, since 0 <= db <= da = 0 */
1369 2080082 : ind = 0;
1370 19813574 : while (db)
1371 : { /* sub-resultant algo., applied to ca * a and cb * b, ca,cb scalars,
1372 : * da = deg a, db = deg b */
1373 17737980 : GEN c = Flx_rem(a,b, p);
1374 17623078 : long delta = da - db;
1375 :
1376 17623078 : if (both_odd(da,db)) s = -s;
1377 17621320 : lb = Fl_mul(b[db+2], cb, p);
1378 17653802 : a = b; b = c; dc = degpol(c);
1379 17663124 : ind++;
1380 17663124 : if (dc != dglist[ind]) return gc_ulong(av,0); /* degenerates */
1381 17658148 : if (g == h)
1382 : { /* frequent */
1383 17598186 : ulong cc = Fl_mul(ca, Fl_powu(Fl_div(lb,g,p), delta+1, p), p);
1384 17675353 : ca = cb;
1385 17675353 : cb = cc;
1386 : }
1387 : else
1388 : {
1389 59962 : ulong cc = Fl_mul(ca, Fl_powu(lb, delta+1, p), p);
1390 59964 : ulong ghdelta = Fl_mul(g, Fl_powu(h, delta, p), p);
1391 59965 : ca = cb;
1392 59965 : cb = Fl_div(cc, ghdelta, p);
1393 : }
1394 17736000 : da = db; /* = degpol(a) */
1395 17736000 : db = dc; /* = degpol(b) */
1396 :
1397 17736000 : g = lb;
1398 17736000 : if (delta == 1)
1399 17635326 : h = g; /* frequent */
1400 : else
1401 100674 : h = Fl_mul(h, Fl_powu(Fl_div(g,h,p), delta, p), p);
1402 :
1403 17735354 : if (gc_needed(av,2))
1404 : {
1405 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flx_resultant_all");
1406 0 : (void)gc_all(av, 2, &a,&b);
1407 : }
1408 : }
1409 2075594 : if (da > 1) return 0; /* Failure */
1410 : /* last nonconstant polynomial has degree 1 */
1411 2075594 : *C0 = Fl_mul(ca, a[2], p);
1412 2075537 : *C1 = Fl_mul(ca, a[3], p);
1413 2075529 : res = Fl_mul(cb, b[2], p);
1414 2075503 : if (s == -1) res = p - res;
1415 2075503 : return gc_ulong(av,res);
1416 : }
1417 :
1418 : /* Q a vector of polynomials representing B in Fp[X][Y], evaluate at X = x,
1419 : * Return 0 in case of degree drop. */
1420 : static GEN
1421 2113548 : FlxY_evalx_drop(GEN Q, ulong x, ulong p)
1422 : {
1423 : GEN z;
1424 2113548 : long i, lb = lg(Q);
1425 2113548 : ulong leadz = Flx_eval(leading_coeff(Q), x, p);
1426 2113252 : long vs=mael(Q,2,1);
1427 2113252 : if (!leadz) return zero_Flx(vs);
1428 :
1429 2102592 : z = cgetg(lb, t_VECSMALL); z[1] = vs;
1430 20080798 : for (i=2; i<lb-1; i++) z[i] = Flx_eval(gel(Q,i), x, p);
1431 2102152 : z[i] = leadz; return z;
1432 : }
1433 :
1434 : GEN
1435 2072 : FpXY_FpXQ_evaly(GEN Q, GEN y, GEN T, GEN p, long vx)
1436 : {
1437 2072 : pari_sp av = avma;
1438 2072 : long i, lb = lg(Q);
1439 : GEN z;
1440 2072 : if (lb == 2) return pol_0(vx);
1441 2072 : z = gel(Q, lb-1);
1442 2072 : if (lb == 3 || !signe(y)) return typ(z)==t_INT? scalar_ZX(z, vx): ZX_copy(z);
1443 :
1444 2072 : if (typ(z) == t_INT) z = scalar_ZX_shallow(z, vx);
1445 48636 : for (i=lb-2; i>=2; i--)
1446 : {
1447 46564 : GEN c = gel(Q,i);
1448 46564 : z = FqX_Fq_mul(z, y, T, p);
1449 46564 : z = typ(c) == t_INT? FqX_Fq_add(z,c,T,p): FqX_add(z,c,T,p);
1450 : }
1451 2072 : return gc_upto(av, z);
1452 : }
1453 :
1454 : static GEN
1455 1303290 : ZX_norml1(GEN x)
1456 : {
1457 1303290 : long i, l = lg(x);
1458 : GEN s;
1459 :
1460 1303290 : if (l == 2) return gen_0;
1461 1210694 : s = gel(x, l-1); /* != 0 */
1462 2726305 : for (i = l-2; i > 1; i--) {
1463 1515617 : GEN xi = gel(x,i);
1464 1515617 : if (!signe(xi)) continue;
1465 1224391 : s = addii_sign(s,1, xi,1);
1466 : }
1467 1210688 : return s;
1468 : }
1469 : /* x >= 0, y != 0, return x + |y| */
1470 : static GEN
1471 25559 : addii_abs(GEN x, GEN y)
1472 : {
1473 25559 : if (!signe(x)) return absi_shallow(y);
1474 16048 : return addii_sign(x,1, y,1);
1475 : }
1476 :
1477 : /* x a ZX, return sum_{i >= k} |x[i]| binomial(i, k) */
1478 : static GEN
1479 31650 : ZX_norml1_1(GEN x, long k)
1480 : {
1481 31650 : long i, d = degpol(x);
1482 : GEN s, C; /* = binomial(i, k) */
1483 :
1484 31649 : if (!d || k > d) return gen_0;
1485 31650 : s = absi_shallow(gel(x, k+2)); /* may be 0 */
1486 31651 : C = gen_1;
1487 68055 : for (i = k+1; i <= d; i++) {
1488 36412 : GEN xi = gel(x,i+2);
1489 36412 : if (k) C = diviuexact(muliu(C, i), i-k);
1490 36413 : if (signe(xi)) s = addii_abs(s, mulii(C, xi));
1491 : }
1492 31643 : return s;
1493 : }
1494 : /* x has non-negative real coefficients */
1495 : static GEN
1496 3283 : RgX_norml1_1(GEN x, long k)
1497 : {
1498 3283 : long i, d = degpol(x);
1499 : GEN s, C; /* = binomial(i, k) */
1500 :
1501 3283 : if (!d || k > d) return gen_0;
1502 3283 : s = gel(x, k+2); /* may be 0 */
1503 3283 : C = gen_1;
1504 9198 : for (i = k+1; i <= d; i++) {
1505 5915 : GEN xi = gel(x,i+2);
1506 5915 : if (k) C = diviuexact(muliu(C, i), i-k);
1507 5915 : if (!gequal0(xi)) s = gadd(s, gmul(C, xi));
1508 : }
1509 3283 : return s;
1510 : }
1511 :
1512 : /* N_2(A)^2 */
1513 : static GEN
1514 9019 : sqrN2(GEN A, long prec)
1515 : {
1516 9019 : pari_sp av = avma;
1517 9019 : long i, l = lg(A);
1518 9019 : GEN a = gen_0;
1519 43727 : for (i = 2; i < l; i++)
1520 : {
1521 34708 : a = gadd(a, gabs(gnorm(gel(A,i)), prec));
1522 34708 : if (gc_needed(av,1))
1523 : {
1524 0 : if(DEBUGMEM>1) pari_warn(warnmem,"RgX_RgXY_ResBound i = %ld",i);
1525 0 : a = gc_upto(av, a);
1526 : }
1527 : }
1528 9019 : return a;
1529 : }
1530 : /* Interpolate at roots of 1 and use Hadamard bound for univariate resultant:
1531 : * bound = N_2(A)^degpol B N_2(B)^degpol(A), where
1532 : * N_2(A) = sqrt(sum (N_1(Ai))^2)
1533 : * Return e such that Res(A, B) < 2^e */
1534 : static GEN
1535 8165 : RgX_RgXY_ResBound(GEN A, GEN B, long prec)
1536 : {
1537 8165 : pari_sp av = avma;
1538 8165 : GEN b = gen_0, bnd;
1539 8165 : long i, lB = lg(B);
1540 31747 : for (i=2; i<lB; i++)
1541 : {
1542 23582 : GEN t = gel(B,i);
1543 23582 : if (typ(t) == t_POL) t = gnorml1(t, prec);
1544 23582 : b = gadd(b, gabs(gsqr(t), prec));
1545 23582 : if (gc_needed(av,1))
1546 : {
1547 0 : if(DEBUGMEM>1) pari_warn(warnmem,"RgX_RgXY_ResBound i = %ld",i);
1548 0 : b = gc_upto(av, b);
1549 : }
1550 : }
1551 8165 : bnd = gsqrt(gmul(gpowgs(sqrN2(A,prec), degpol(B)),
1552 : gpowgs(b, degpol(A))), prec);
1553 8165 : return gc_upto(av, bnd);
1554 : }
1555 : /* A,B in C[X] return RgX_RgXY_ResBound(A, B(x+y)) */
1556 : static GEN
1557 854 : RgX_RgXY_ResBound_1(GEN A, GEN B, long prec)
1558 : {
1559 854 : pari_sp av = avma, av2;
1560 854 : GEN b = gen_0, bnd;
1561 854 : long i, lB = lg(B);
1562 854 : B = shallowcopy(B);
1563 4137 : for (i=2; i<lB; i++) gel(B,i) = gabs(gel(B,i), prec);
1564 854 : av2 = avma;
1565 4137 : for (i=2; i<lB; i++)
1566 : {
1567 3283 : b = gadd(b, gsqr(RgX_norml1_1(B, i-2)));
1568 3283 : if (gc_needed(av2,1))
1569 : {
1570 0 : if(DEBUGMEM>1) pari_warn(warnmem,"RgX_RgXY_ResBound i = %ld",i);
1571 0 : b = gc_upto(av2, b);
1572 : }
1573 : }
1574 854 : bnd = gsqrt(gmul(gpowgs(sqrN2(A,prec), degpol(B)),
1575 : gpowgs(b, degpol(A))), prec);
1576 854 : return gc_upto(av, bnd);
1577 : }
1578 :
1579 : /* log2 N_2(A)^2 */
1580 : static double
1581 176984 : log2N2(GEN A)
1582 : {
1583 176984 : pari_sp av = avma;
1584 176984 : long i, l = lg(A);
1585 176984 : GEN a = gen_0;
1586 1336965 : for (i=2; i < l; i++)
1587 : {
1588 1159987 : a = addii(a, sqri(gel(A,i)));
1589 1159984 : if (gc_needed(av,1))
1590 : {
1591 0 : if(DEBUGMEM>1) pari_warn(warnmem,"ZX_ZXY_ResBound i = %ld",i);
1592 0 : a = gc_upto(av, a);
1593 : }
1594 : }
1595 176978 : return gc_double(av, dbllog2(a));
1596 : }
1597 : /* Interpolate at roots of 1 and use Hadamard bound for univariate resultant:
1598 : * bound = N_2(A)^degpol B N_2(B)^degpol(A), where
1599 : * N_2(A) = sqrt(sum (N_1(Ai))^2)
1600 : * Return e such that Res(A, B) < 2^e */
1601 :
1602 : static double
1603 2188192 : resbound(GEN B)
1604 : {
1605 2188192 : pari_sp av = avma;
1606 2188192 : long i, lB = lg(B);
1607 2188192 : GEN b = gen_0;
1608 9744617 : for (i=2; i<lB; i++)
1609 : {
1610 7556567 : GEN t = gel(B,i);
1611 7556567 : if (typ(t) == t_POL) t = ZX_norml1(t);
1612 7556562 : b = addii(b, sqri(t));
1613 7556424 : if (gc_needed(av,1))
1614 : {
1615 0 : if(DEBUGMEM>1) pari_warn(warnmem,"ZX_ZXY_ResBound i = %ld",i);
1616 0 : b = gc_upto(av, b);
1617 : }
1618 : }
1619 2188050 : return gc_double(av, dbllog2(b));
1620 : }
1621 :
1622 : ulong
1623 166902 : ZX_ZXY_ResBound(GEN A, GEN B, GEN dB)
1624 : {
1625 166902 : pari_sp av = avma;
1626 166902 : double logb = resbound(B);
1627 : long i;
1628 166898 : if (dB) logb -= 2 * dbllog2(dB);
1629 166898 : i = (long)((degpol(B) * log2N2(A) + degpol(A) * logb) / 2);
1630 166896 : return gc_ulong(av, (i <= 0)? 1: 1 + (ulong)i);
1631 : }
1632 : static ulong
1633 1010652 : ZXX_ResBound(GEN A, GEN B)
1634 : {
1635 1010652 : pari_sp av = avma;
1636 1010652 : double loga = resbound(A), logb = resbound(B);
1637 1010643 : long i = (long)((degpol(B) * loga + degpol(A) * logb) / 2);
1638 1010646 : return gc_ulong(av, (i <= 0)? 1: 1 + (ulong)i);
1639 : }
1640 :
1641 : /* A,B ZX. Return ZX_ZXY_ResBound(A(x), B(x+y)) */
1642 : static ulong
1643 10085 : ZX_ZXY_ResBound_1(GEN A, GEN B)
1644 : {
1645 10085 : pari_sp av = avma;
1646 10085 : GEN b = gen_0;
1647 10085 : long i, lB = lg(B);
1648 41735 : for (i=2; i<lB; i++)
1649 : {
1650 31651 : b = addii(b, sqri(ZX_norml1_1(B, i-2)));
1651 31650 : if (gc_needed(av,1))
1652 : {
1653 0 : if(DEBUGMEM>1) pari_warn(warnmem,"ZX_ZXY_ResBound i = %ld",i);
1654 0 : b = gc_upto(av, b);
1655 : }
1656 : }
1657 10084 : i = (long)((degpol(B) * log2N2(A) + degpol(A) * dbllog2(b)) / 2);
1658 10086 : return gc_ulong(av, (i <= 0)? 1: 1 + (ulong)i);
1659 : }
1660 : /* special case B = A' */
1661 : static ulong
1662 1134913 : ZX_discbound(GEN A)
1663 : {
1664 1134913 : pari_sp av = avma;
1665 1134913 : GEN a = gen_0, b = gen_0;
1666 1134913 : long i , lA = lg(A), dA = degpol(A);
1667 : double loga, logb;
1668 6772037 : for (i = 2; i < lA; i++)
1669 : {
1670 5637331 : GEN c = sqri(gel(A,i));
1671 5637031 : a = addii(a, c);
1672 5637114 : if (i > 2) b = addii(b, mulii(c, sqru(i-2)));
1673 5637174 : if (gc_needed(av,1))
1674 : {
1675 0 : if(DEBUGMEM>1) pari_warn(warnmem,"ZX_discbound i = %ld",i);
1676 0 : (void)gc_all(av, 2, &a, &b);
1677 : }
1678 : }
1679 1134706 : loga = dbllog2(a);
1680 1134817 : logb = dbllog2(b); set_avma(av);
1681 1134839 : i = (long)(((dA-1) * loga + dA * logb) / 2);
1682 1134839 : return (i <= 0)? 1: 1 + (ulong)i;
1683 : }
1684 :
1685 : /* return Res(a(Y), b(n,Y)) over Fp. la = leading_coeff(a) [for efficiency] */
1686 : static ulong
1687 5540077 : Flx_FlxY_eval_resultant(GEN a, GEN b, ulong n, ulong p, ulong pi, ulong la)
1688 : {
1689 5540077 : GEN ev = FlxY_evalx_pre(b, n, p, pi);
1690 5540445 : long drop = lg(b) - lg(ev);
1691 5540445 : ulong r = Flx_resultant_pre(a, ev, p, pi);
1692 5539884 : if (drop && la != 1) r = Fl_mul(r, Fl_powu_pre(la, drop, p, pi), p);
1693 5539896 : return r;
1694 : }
1695 : /* return Res(a(Y), b(n,Y)) over Fp. la = leading_coeff(a) [for efficiency] */
1696 : static ulong
1697 4387505 : FlxY_eval_resultant(GEN a, GEN b, ulong n, ulong p, ulong pi, GEN la, GEN lb)
1698 : {
1699 4387505 : GEN av = FlxY_evalx_pre(a, n, p, pi);
1700 4387497 : GEN bv = FlxY_evalx_pre(b, n, p, pi);
1701 4387504 : long lav = lgpol(av), lbv = lgpol(bv), dropa, dropb;
1702 : ulong r;
1703 4387487 : if (lav==0 && lbv==0) return 1UL;
1704 4387480 : dropa = lgpol(a) - lav;
1705 4387474 : dropb = lgpol(b) - lbv;
1706 4387473 : r = Flx_resultant_pre(av, bv, p, pi);
1707 4387481 : if (dropa)
1708 : { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */
1709 37 : ulong c = Flx_eval_pre(lb, n,p ,pi); /* lc(B) */
1710 37 : if (odd(degpol(b))) c = p - c;
1711 37 : c = Fl_powu(c, dropa, p);
1712 37 : if (c != 1UL) r = Fl_mul(r, c, p);
1713 : }
1714 4387444 : else if (dropb)
1715 : { /* multiply by lc(A)^(deg B - deg b) */
1716 7 : ulong c = Flx_eval_pre(la, n,p ,pi); /* lc(B) */
1717 7 : c = Fl_powu(c, dropb, p);
1718 7 : if (c != 1UL) r = Fl_mul(r, c, p);
1719 : }
1720 4387481 : return r;
1721 : }
1722 :
1723 : static GEN
1724 284 : FpX_FpXY_eval_resultant(GEN a, GEN b, GEN n, GEN p, GEN la, long db, long vX)
1725 : {
1726 284 : GEN ev = FpXY_evaly(b, n, p, vX);
1727 284 : long drop = db-degpol(ev);
1728 284 : GEN r = FpX_resultant(a, ev, p);
1729 284 : if (drop && !gequal1(la)) r = Fp_mul(r, Fp_powu(la, drop,p),p);
1730 284 : return r;
1731 : }
1732 :
1733 : /* assume dres := deg(Res_X(a,b), Y) <= deg(a,X) * deg(b,Y) < p */
1734 : /* Return a Fly */
1735 : static GEN
1736 368517 : Flx_FlxY_resultant_polint(GEN a, GEN b, ulong p, ulong pi, long dres, long sx)
1737 : {
1738 : long i;
1739 368517 : ulong n, la = Flx_lead(a);
1740 368516 : GEN x = cgetg(dres+2, t_VECSMALL);
1741 368518 : GEN y = cgetg(dres+2, t_VECSMALL);
1742 : /* Evaluate at dres+ 1 points: 0 (if dres even) and +/- n, so that P_n(X) =
1743 : * P_{-n}(-X), where P_i is Lagrange polynomial: P_i(j) = delta_{i,j} */
1744 2957681 : for (i=0,n = 1; i < dres; n++)
1745 : {
1746 2589170 : x[++i] = n; y[i] = Flx_FlxY_eval_resultant(a,b, x[i], p,pi,la);
1747 2589071 : x[++i] = p-n; y[i] = Flx_FlxY_eval_resultant(a,b, x[i], p,pi,la);
1748 : }
1749 368511 : if (i == dres)
1750 : {
1751 363005 : x[++i] = 0; y[i] = Flx_FlxY_eval_resultant(a,b, x[i], p,pi,la);
1752 : }
1753 368513 : return Flv_polint(x,y, p, sx);
1754 : }
1755 :
1756 : /* assume dres := deg(Res_X(a,b), Y) <= deg(a,X) * deg(b,Y) < p */
1757 : /* Return a Fly */
1758 : static GEN
1759 1118164 : FlxX_resultant_polint(GEN a, GEN b, ulong p, ulong pi, long dres, long sx)
1760 : {
1761 : long i;
1762 : ulong n;
1763 1118164 : GEN la = leading_coeff(a), lb = leading_coeff(b);
1764 1118164 : GEN x = cgetg(dres+2, t_VECSMALL);
1765 1118164 : GEN y = cgetg(dres+2, t_VECSMALL);
1766 : /* Evaluate at dres+ 1 points: 0 (if dres even) and +/- n, so that P_n(X) =
1767 : * P_{-n}(-X), where P_i is Lagrange polynomial: P_i(j) = delta_{i,j} */
1768 3018210 : for (i=0,n = 1; i < dres; n++)
1769 : {
1770 1900046 : x[++i] = n; y[i] = FlxY_eval_resultant(a,b, x[i], p,pi, la,lb);
1771 1900033 : x[++i] = p-n; y[i] = FlxY_eval_resultant(a,b, x[i], p,pi, la,lb);
1772 : }
1773 1118164 : if (i == dres)
1774 : {
1775 587496 : x[++i] = 0; y[i] = FlxY_eval_resultant(a,b, x[i], p,pi, la,lb);
1776 : }
1777 1118165 : return Flv_polint(x,y, p, sx);
1778 : }
1779 :
1780 : static GEN
1781 7633 : FlxX_pseudorem(GEN x, GEN y, ulong p, ulong pi)
1782 : {
1783 7633 : long vx = varn(x), dx, dy, dz, i, lx, dp;
1784 7633 : pari_sp av = avma, av2;
1785 :
1786 7633 : if (!signe(y)) pari_err_INV("FlxX_pseudorem",y);
1787 7633 : (void)new_chunk(2);
1788 7633 : dx=degpol(x); x = RgX_recip_i(x)+2;
1789 7635 : dy=degpol(y); y = RgX_recip_i(y)+2; dz=dx-dy; dp = dz+1;
1790 7635 : av2 = avma;
1791 : for (;;)
1792 : {
1793 62605 : gel(x,0) = Flx_neg(gel(x,0), p); dp--;
1794 234612 : for (i=1; i<=dy; i++)
1795 171747 : gel(x,i) = Flx_add( Flx_mul_pre(gel(y,0), gel(x,i), p, pi),
1796 171983 : Flx_mul_pre(gel(x,0), gel(y,i), p, pi), p );
1797 1140882 : for ( ; i<=dx; i++)
1798 1078981 : gel(x,i) = Flx_mul_pre(gel(y,0), gel(x,i), p, pi);
1799 66587 : do { x++; dx--; } while (dx >= 0 && lg(gel(x,0))==2);
1800 61901 : if (dx < dy) break;
1801 54265 : if (gc_needed(av2,1))
1802 : {
1803 0 : if(DEBUGMEM>1) pari_warn(warnmem,"FlxX_pseudorem dx = %ld >= %ld",dx,dy);
1804 0 : gc_slice(av2,x,dx+1);
1805 : }
1806 : }
1807 7636 : if (dx < 0) return zero_Flx(0);
1808 7636 : lx = dx+3; x -= 2;
1809 7636 : x[0]=evaltyp(t_POL) | _evallg(lx);
1810 7636 : x[1]=evalsigne(1) | evalvarn(vx);
1811 7636 : x = RgX_recip_i(x);
1812 7637 : if (dp)
1813 : { /* multiply by y[0]^dp [beware dummy vars from FpX_FpXY_resultant] */
1814 1995 : GEN t = Flx_powu_pre(gel(y,0), dp, p, pi);
1815 7983 : for (i=2; i<lx; i++) gel(x,i) = Flx_mul_pre(gel(x,i), t, p, pi);
1816 : }
1817 7636 : return gc_GEN(av, x);
1818 : }
1819 :
1820 : /* return a Flx */
1821 : static GEN
1822 2553 : FlxX_resultant_subres(GEN u, GEN v, ulong p, ulong pi, long sx)
1823 : {
1824 2553 : pari_sp av = avma, av2;
1825 : long degq, dx, dy, du, dv, dr, signh;
1826 : GEN z, g, h, r, p1;
1827 :
1828 2553 : dx = degpol(u); dy = degpol(v); signh = 1;
1829 2555 : if (dx < dy)
1830 : {
1831 7 : swap(u,v); lswap(dx,dy);
1832 7 : if (both_odd(dx, dy)) signh = -signh;
1833 : }
1834 2555 : if (dy < 0) return zero_Flx(sx);
1835 2555 : if (dy==0) return gc_upto(av, Flx_powu_pre(gel(v,2),dx,p,pi));
1836 :
1837 2555 : g = h = pol1_Flx(sx); av2 = avma;
1838 : for(;;)
1839 : {
1840 7633 : r = FlxX_pseudorem(u,v,p,pi); dr = lg(r);
1841 7636 : if (dr == 2) { set_avma(av); return zero_Flx(sx); }
1842 7636 : du = degpol(u); dv = degpol(v); degq = du-dv;
1843 7636 : u = v; p1 = g; g = leading_coeff(u);
1844 7636 : switch(degq)
1845 : {
1846 0 : case 0: break;
1847 5627 : case 1:
1848 5627 : p1 = Flx_mul_pre(h,p1, p, pi); h = g; break;
1849 2009 : default:
1850 2009 : p1 = Flx_mul_pre(Flx_powu_pre(h,degq,p,pi), p1, p, pi);
1851 2008 : h = Flx_div_pre(Flx_powu_pre(g,degq,p,pi),
1852 2008 : Flx_powu_pre(h,degq-1,p,pi), p, pi);
1853 : }
1854 7633 : if (both_odd(du,dv)) signh = -signh;
1855 7631 : v = FlxY_Flx_div(r, p1, p);
1856 7631 : if (dr==3) break;
1857 5078 : if (gc_needed(av2,1))
1858 : {
1859 0 : if(DEBUGMEM>1) pari_warn(warnmem,"FlxX_resultant, dr = %ld",dr);
1860 0 : (void)gc_all(av2,4, &u, &v, &g, &h);
1861 : }
1862 : }
1863 2553 : z = gel(v,2);
1864 2553 : if (dv > 1) z = Flx_div_pre(Flx_powu_pre(z,dv,p,pi),
1865 0 : Flx_powu_pre(h,dv-1,p,pi), p, pi);
1866 2553 : if (signh < 0) z = Flx_neg(z,p);
1867 2553 : return gc_upto(av, z);
1868 : }
1869 :
1870 : /* Return a Flx*/
1871 : GEN
1872 0 : FlxX_resultant_pre(GEN a, GEN b, ulong p, ulong pi, long sx)
1873 : {
1874 0 : pari_sp ltop = avma;
1875 0 : long da = degpol(a), db = degpol(b);
1876 : ulong dres;
1877 : GEN z;
1878 0 : if (da<0 || db<0) return pol0_Flx(sx);
1879 0 : dres = FlxY_degreex(a)*db+FlxY_degreex(b)*da;
1880 0 : z = dres >= p ? FlxX_resultant_subres(a, b, p, pi, sx)
1881 0 : : FlxX_resultant_polint(a, b, p, pi, dres, sx);
1882 0 : return gc_upto(ltop, z);
1883 : }
1884 :
1885 : GEN
1886 0 : FlxX_resultant(GEN a, GEN b, ulong p, long sx)
1887 0 : { return FlxX_resultant_pre(a, b, p, SMALL_ULONG(p)? 0: get_Fl_red(p), sx); }
1888 :
1889 : /* Warning:
1890 : * This function switches between valid and invalid variable ordering*/
1891 : static GEN
1892 6163 : FlxY_to_FlyX(GEN b, long sv)
1893 : {
1894 6163 : long i, n=-1;
1895 6163 : long sw = b[1]&VARNBITS;
1896 21049 : for(i=2;i<lg(b);i++) n = maxss(n,lgpol(gel(b,i)));
1897 6163 : return Flm_to_FlxX(Flm_transpose(FlxX_to_Flm(b,n)),sv,sw);
1898 : }
1899 :
1900 : /* Return a Fly*/
1901 : GEN
1902 6163 : Flx_FlxY_resultant(GEN a, GEN b, ulong p)
1903 : {
1904 6163 : pari_sp ltop=avma;
1905 6163 : long dres = degpol(a)*degpol(b);
1906 6163 : long sx=a[1], sy=b[1]&VARNBITS;
1907 6163 : ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
1908 : GEN z;
1909 6163 : b = FlxY_to_FlyX(b,sx);
1910 6164 : if ((ulong)dres >= p)
1911 2554 : z = FlxX_resultant_subres(Fly_to_FlxY(a, sy), b, p, pi, sy);
1912 : else
1913 3610 : z = Flx_FlxY_resultant_polint(a, b, p, pi, (ulong)dres, sy);
1914 6165 : return gc_upto(ltop,z);
1915 : }
1916 :
1917 : /* Return a t_POL in variable vc whose coeffs are the coeffs of b in
1918 : * variable v; vc must have higher priority than all variables occuring in b. */
1919 : GEN
1920 146884 : swap_vars(GEN b, long v, long vc)
1921 : {
1922 146884 : long i, n = RgX_degree(b, v);
1923 : GEN c, x;
1924 146884 : if (n < 0) return pol_0(vc);
1925 146884 : c = cgetg(n+3, t_POL); x = c + 2;
1926 146883 : c[1] = evalsigne(1) | evalvarn(vc);
1927 971224 : for (i = 0; i <= n; i++) gel(x,i) = polcoef_i(b, i, v);
1928 146882 : return c;
1929 : }
1930 :
1931 : /* assume varn(b) << varn(a) */
1932 : /* return a FpY*/
1933 : GEN
1934 15 : FpX_FpXY_resultant(GEN a, GEN b, GEN p)
1935 : {
1936 15 : long i,n,dres, db, vY = varn(b), vX = varn(a);
1937 : GEN la,x,y;
1938 :
1939 15 : if (lgefint(p) == 3)
1940 : {
1941 0 : ulong pp = uel(p,2);
1942 0 : b = ZXX_to_FlxX(b, pp, vX);
1943 0 : a = ZX_to_Flx(a, pp);
1944 0 : x = Flx_FlxY_resultant(a, b, pp);
1945 0 : return Flx_to_ZX(x);
1946 : }
1947 15 : db = RgXY_degreex(b);
1948 15 : dres = degpol(a)*degpol(b);
1949 15 : la = leading_coeff(a);
1950 15 : x = cgetg(dres+2, t_VEC);
1951 15 : y = cgetg(dres+2, t_VEC);
1952 : /* Evaluate at dres+ 1 points: 0 (if dres even) and +/- n, so that P_n(X) =
1953 : * P_{-n}(-X), where P_i is Lagrange polynomial: P_i(j) = delta_{i,j} */
1954 157 : for (i=0,n = 1; i < dres; n++)
1955 : {
1956 142 : gel(x,++i) = utoipos(n);
1957 142 : gel(y,i) = FpX_FpXY_eval_resultant(a,b,gel(x,i),p,la,db,vY);
1958 142 : gel(x,++i) = subiu(p,n);
1959 142 : gel(y,i) = FpX_FpXY_eval_resultant(a,b,gel(x,i),p,la,db,vY);
1960 : }
1961 15 : if (i == dres)
1962 : {
1963 0 : gel(x,++i) = gen_0;
1964 0 : gel(y,i) = FpX_FpXY_eval_resultant(a,b, gel(x,i), p,la,db,vY);
1965 : }
1966 15 : return FpV_polint(x,y, p, vY);
1967 : }
1968 :
1969 : GEN
1970 191 : FpX_composedsum(GEN P, GEN Q, GEN p)
1971 : {
1972 191 : pari_sp av = avma;
1973 191 : if (lgefint(p)==3)
1974 : {
1975 0 : ulong pp = p[2];
1976 0 : GEN z = Flx_composedsum(ZX_to_Flx(P, pp), ZX_to_Flx(Q, pp), pp);
1977 0 : return gc_upto(av, Flx_to_ZX(z));
1978 : }
1979 : else
1980 : {
1981 191 : long n = 1+ degpol(P)*degpol(Q);
1982 191 : GEN Pl = FpX_invLaplace(FpX_Newton(P,n,p), p);
1983 191 : GEN Ql = FpX_invLaplace(FpX_Newton(Q,n,p), p);
1984 191 : GEN L = FpX_Laplace(FpXn_mul(Pl, Ql, n, p), p);
1985 191 : GEN lead = Fp_mul(Fp_powu(leading_coeff(P),degpol(Q), p),
1986 191 : Fp_powu(leading_coeff(Q),degpol(P), p), p);
1987 191 : GEN R = FpX_fromNewton(L, p);
1988 191 : return gc_upto(av, FpX_Fp_mul(R, lead, p));
1989 : }
1990 : }
1991 :
1992 : GEN
1993 0 : FpX_composedprod(GEN P, GEN Q, GEN p)
1994 : {
1995 0 : pari_sp av = avma;
1996 0 : if (lgefint(p)==3)
1997 : {
1998 0 : ulong pp = p[2];
1999 0 : GEN z = Flx_composedprod(ZX_to_Flx(P, pp), ZX_to_Flx(Q, pp), pp);
2000 0 : return gc_upto(av, Flx_to_ZX(z));
2001 : }
2002 : else
2003 : {
2004 0 : long n = 1+ degpol(P)*degpol(Q);
2005 0 : GEN L = FpX_convol(FpX_Newton(P,n,p), FpX_Newton(Q,n,p), p);
2006 0 : return gc_upto(av,FpX_fromNewton(L, p));
2007 : }
2008 : }
2009 :
2010 : static GEN
2011 191 : _FpX_composedsum(void *E, GEN a, GEN b)
2012 191 : { return FpX_composedsum(a,b, (GEN)E); }
2013 :
2014 : GEN
2015 1637 : FpXV_composedsum(GEN V, GEN p)
2016 : {
2017 1637 : if (lgefint(p)==3)
2018 : {
2019 0 : ulong pp = p[2];
2020 0 : return Flx_to_ZX(FlxV_composedsum(ZXV_to_FlxV(V, pp), pp));
2021 : }
2022 1637 : return gen_product(V, (void *)p, &_FpX_composedsum);
2023 : }
2024 :
2025 : /* 0, 1, -1, 2, -2, ... */
2026 : #define next_lambda(a) (a>0 ? -a : 1-a)
2027 :
2028 : /* Assume A in Z[Y], B in Q[Y][X], B squarefree in (Q[Y]/(A))[X] and
2029 : * Res_Y(A, B) in Z[X]. Find a small lambda (start from *lambda, use
2030 : * next_lambda successively) such that C(X) = Res_Y(A(Y), B(X + lambda Y))
2031 : * is squarefree, reset *lambda to the chosen value and return C. Set LERS to
2032 : * the Last nonconstant polynomial in the Euclidean Remainder Sequence */
2033 : static GEN
2034 22421 : ZX_ZXY_resultant_LERS(GEN A, GEN B0, long *plambda, GEN *LERS)
2035 : {
2036 : ulong bound, dp;
2037 22421 : pari_sp av = avma, av2 = 0;
2038 22421 : long lambda = *plambda, degA = degpol(A), dres = degA*degpol(B0);
2039 : long stable, checksqfree, i,n, cnt, degB;
2040 22421 : long v, vX = varn(B0), vY = varn(A); /* vY < vX */
2041 : GEN x, y, dglist, B, q, a, b, ev, H, H0, H1, Hp, H0p, H1p, C0, C1;
2042 : forprime_t S;
2043 :
2044 22421 : if (degA == 1)
2045 : {
2046 1260 : GEN a1 = gel(A,3), a0 = gel(A,2);
2047 1260 : B = lambda? RgX_Rg_translate(B0, monomial(stoi(lambda), 1, vY)): B0;
2048 1260 : H = gsubst(B, vY, gdiv(gneg(a0),a1));
2049 1260 : if (!equali1(a1)) H = RgX_Rg_mul(H, powiu(a1, poldegree(B,vY)));
2050 1260 : *LERS = mkvec2(scalarpol_shallow(a0,vX), scalarpol_shallow(a1,vX));
2051 1260 : return gc_all(av, 2, &H, LERS);
2052 : }
2053 :
2054 21161 : dglist = Hp = H0p = H1p = C0 = C1 = NULL; /* gcc -Wall */
2055 21161 : C0 = cgetg(dres+2, t_VECSMALL);
2056 21161 : C1 = cgetg(dres+2, t_VECSMALL);
2057 21161 : dglist = cgetg(dres+1, t_VECSMALL);
2058 21161 : x = cgetg(dres+2, t_VECSMALL);
2059 21160 : y = cgetg(dres+2, t_VECSMALL);
2060 21160 : B0 = leafcopy(B0);
2061 21160 : A = leafcopy(A);
2062 21161 : B = B0;
2063 21161 : v = fetch_var_higher(); setvarn(A,v);
2064 : /* make sure p large enough */
2065 22320 : INIT:
2066 : /* always except the first time */
2067 22320 : if (av2) { set_avma(av2); lambda = next_lambda(lambda); }
2068 22320 : if (lambda) B = RgX_Rg_translate(B0, monomial(stoi(lambda), 1, vY));
2069 22320 : B = swap_vars(B, vY, v);
2070 : /* B0(lambda v + x, v) */
2071 22320 : if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda);
2072 22320 : av2 = avma;
2073 :
2074 22320 : if (degA <= 3)
2075 : { /* sub-resultant faster for small degrees */
2076 11319 : H = RgX_resultant_all(A,B,&q);
2077 11319 : if (typ(q) != t_POL || degpol(q)!=1) goto INIT;
2078 10374 : H0 = gel(q,2);
2079 10374 : if (typ(H0) == t_POL) setvarn(H0,vX); else H0 = scalarpol(H0,vX);
2080 10374 : H1 = gel(q,3);
2081 10374 : if (typ(H1) == t_POL) setvarn(H1,vX); else H1 = scalarpol(H1,vX);
2082 10374 : if (!ZX_is_squarefree(H)) goto INIT;
2083 10332 : goto END;
2084 : }
2085 :
2086 11001 : H = H0 = H1 = NULL;
2087 11001 : degB = degpol(B);
2088 11001 : bound = ZX_ZXY_ResBound(A, B, NULL);
2089 11000 : if (DEBUGLEVEL>4) err_printf("bound for resultant coeffs: 2^%ld\n",bound);
2090 11000 : dp = 1;
2091 11000 : init_modular_big(&S);
2092 11000 : for(cnt = 0, checksqfree = 1;;)
2093 49459 : {
2094 60459 : ulong p = u_forprime_next(&S);
2095 : GEN Hi;
2096 60458 : a = ZX_to_Flx(A, p);
2097 60460 : b = ZXX_to_FlxX(B, p, varn(A));
2098 60458 : if (degpol(a) < degA || degpol(b) < degB) continue; /* p | lc(A)lc(B) */
2099 60458 : if (checksqfree)
2100 : { /* find degree list for generic Euclidean Remainder Sequence */
2101 11000 : long goal = minss(degpol(a), degpol(b)); /* longest possible */
2102 74267 : for (n=1; n <= goal; n++) dglist[n] = 0;
2103 11001 : setlg(dglist, 1);
2104 24154 : for (n=0; n <= dres; n++)
2105 : {
2106 23741 : ev = FlxY_evalx_drop(b, n, p);
2107 23741 : Flx_resultant_set_dglist(a, ev, dglist, p);
2108 23741 : if (lg(dglist)-1 == goal) break;
2109 : }
2110 : /* last pol in ERS has degree > 1 ? */
2111 11001 : goal = lg(dglist)-1;
2112 11001 : if (degpol(B) == 1) { if (!goal) goto INIT; }
2113 : else
2114 : {
2115 10938 : if (goal <= 1) goto INIT;
2116 10854 : if (dglist[goal] != 0 || dglist[goal-1] != 1) goto INIT;
2117 : }
2118 10917 : if (DEBUGLEVEL>4)
2119 0 : err_printf("Degree list for ERS (trials: %ld) = %Ps\n",n+1,dglist);
2120 : }
2121 :
2122 2150230 : for (i=0,n = 0; i <= dres; n++)
2123 : {
2124 2089846 : ev = FlxY_evalx_drop(b, n, p);
2125 2089584 : x[++i] = n; y[i] = Flx_resultant_all(a, ev, C0+i, C1+i, dglist, p);
2126 2089855 : if (!C1[i]) i--; /* C1(i) = 0. No way to recover C0(i) */
2127 : }
2128 60384 : Hi = Flv_Flm_polint(x, mkvec3(y,C0,C1), p, 0);
2129 60377 : Hp = gel(Hi,1); H0p = gel(Hi,2); H1p = gel(Hi,3);
2130 60377 : if (!H && degpol(Hp) != dres) continue;
2131 60377 : if (dp != 1) Hp = Flx_Fl_mul(Hp, Fl_powu(Fl_inv(dp,p), degA, p), p);
2132 60377 : if (checksqfree) {
2133 10917 : if (!Flx_is_squarefree(Hp, p)) goto INIT;
2134 10829 : if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda);
2135 10829 : checksqfree = 0;
2136 : }
2137 :
2138 60289 : if (!H)
2139 : { /* initialize */
2140 10829 : q = utoipos(p); stable = 0;
2141 10829 : H = ZX_init_CRT(Hp, p,vX);
2142 10829 : H0= ZX_init_CRT(H0p, p,vX);
2143 10829 : H1= ZX_init_CRT(H1p, p,vX);
2144 : }
2145 : else
2146 : {
2147 49460 : GEN qp = muliu(q,p);
2148 49459 : stable = ZX_incremental_CRT_raw(&H, Hp, q,qp, p)
2149 49460 : & ZX_incremental_CRT_raw(&H0,H0p, q,qp, p)
2150 49459 : & ZX_incremental_CRT_raw(&H1,H1p, q,qp, p);
2151 49459 : q = qp;
2152 : }
2153 : /* could make it probabilistic for H ? [e.g if stable twice, etc]
2154 : * Probabilistic anyway for H0, H1 */
2155 60288 : if (DEBUGLEVEL>5 && (stable || ++cnt==100))
2156 0 : { cnt=0; err_printf("%ld%%%s ",100*expi(q)/bound,stable?"s":""); }
2157 60288 : if (stable && (ulong)expi(q) >= bound) break; /* DONE */
2158 49459 : if (gc_needed(av,2))
2159 : {
2160 0 : if (DEBUGMEM>1) pari_warn(warnmem,"ZX_ZXY_rnfequation");
2161 0 : (void)gc_all(av2, 4, &H, &q, &H0, &H1);
2162 : }
2163 : }
2164 21161 : END:
2165 21161 : if (DEBUGLEVEL>5) err_printf(" done\n");
2166 21161 : setvarn(H, vX); (void)delete_var();
2167 21161 : *LERS = mkvec2(H0,H1);
2168 21161 : *plambda = lambda; return gc_all(av, 2, &H, LERS);
2169 : }
2170 :
2171 : GEN
2172 60214 : ZX_ZXY_resultant_all(GEN A, GEN B, long *plambda, GEN *LERS)
2173 : {
2174 60214 : if (LERS)
2175 : {
2176 22421 : if (!plambda)
2177 0 : pari_err_BUG("ZX_ZXY_resultant_all [LERS != NULL needs lambda]");
2178 22421 : return ZX_ZXY_resultant_LERS(A, B, plambda, LERS);
2179 : }
2180 37793 : return ZX_ZXY_rnfequation(A, B, plambda);
2181 : }
2182 :
2183 : /* If lambda = NULL, return caract(Mod(A, T)), T,A in Z[X].
2184 : * Otherwise find a small lambda such that caract (Mod(A + lambda X, T)) is
2185 : * squarefree */
2186 : GEN
2187 22594 : ZXQ_charpoly_sqf(GEN A, GEN T, long *lambda, long v)
2188 : {
2189 22594 : pari_sp av = avma;
2190 : GEN R, a;
2191 : long dA;
2192 : int delvar;
2193 :
2194 22594 : if (v < 0) v = 0;
2195 22594 : switch (typ(A))
2196 : {
2197 22594 : case t_POL: dA = degpol(A); if (dA > 0) break;
2198 0 : A = constant_coeff(A);
2199 0 : default:
2200 0 : if (lambda) { A = scalar_ZX_shallow(A,varn(T)); dA = 0; break;}
2201 0 : return gc_upto(av, gpowgs(gsub(pol_x(v), A), degpol(T)));
2202 : }
2203 22594 : delvar = 0;
2204 22594 : if (varncmp(varn(T), 0) <= 0)
2205 : {
2206 3681 : long v0 = fetch_var(); delvar = 1;
2207 3681 : T = leafcopy(T); setvarn(T,v0);
2208 3681 : A = leafcopy(A); setvarn(A,v0);
2209 : }
2210 22594 : R = ZX_ZXY_rnfequation(T, deg1pol_shallow(gen_1, gneg_i(A), 0), lambda);
2211 22594 : if (delvar) (void)delete_var();
2212 22594 : setvarn(R, v); a = leading_coeff(T);
2213 22594 : if (!gequal1(a)) R = gdiv(R, powiu(a, dA));
2214 22594 : return gc_upto(av, R);
2215 : }
2216 :
2217 : /* charpoly(Mod(A,T)), A may be in Q[X], but assume T and result are integral */
2218 : GEN
2219 1247365 : ZXQ_charpoly(GEN A, GEN T, long v)
2220 : {
2221 1247365 : return (degpol(T) < 16) ? RgXQ_charpoly_i(A,T,v): ZXQ_charpoly_sqf(A,T, NULL, v);
2222 : }
2223 :
2224 : GEN
2225 9772 : QXQ_charpoly(GEN A, GEN T, long v)
2226 : {
2227 9772 : pari_sp av = avma;
2228 9772 : GEN den, B = Q_remove_denom(A, &den);
2229 9772 : GEN P = ZXQ_charpoly(B, T, v);
2230 9772 : return gc_GEN(av, den ? RgX_rescale(P, ginv(den)): P);
2231 : }
2232 :
2233 : static ulong
2234 3864991 : ZX_resultant_prime(GEN a, GEN b, GEN dB, long degA, long degB, ulong p)
2235 : {
2236 3864991 : pari_sp av = avma;
2237 3864991 : long dropa = degA - degpol(a), dropb = degB - degpol(b);
2238 : ulong H, dp;
2239 3864899 : if (dropa && dropb) return 0; /* p | lc(A), p | lc(B) */
2240 3864899 : H = Flx_resultant(a, b, p);
2241 3864641 : if (dropa)
2242 : { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */
2243 0 : ulong c = b[degB+2]; /* lc(B) */
2244 0 : if (odd(degB)) c = p - c;
2245 0 : c = Fl_powu(c, dropa, p);
2246 0 : if (c != 1) H = Fl_mul(H, c, p);
2247 : }
2248 3864641 : else if (dropb)
2249 : { /* multiply by lc(A)^(deg B - deg b) */
2250 0 : ulong c = a[degA+2]; /* lc(A) */
2251 0 : c = Fl_powu(c, dropb, p);
2252 0 : if (c != 1) H = Fl_mul(H, c, p);
2253 : }
2254 3864645 : dp = dB ? umodiu(dB, p): 1;
2255 3864645 : if (dp != 1) H = Fl_mul(H, Fl_powu(Fl_inv(dp,p), degA, p), p);
2256 3864647 : return gc_ulong(av, H);
2257 : }
2258 :
2259 : /* If B=NULL, assume B=A' */
2260 : static GEN
2261 1495318 : ZX_resultant_slice(GEN A, GEN B, GEN dB, GEN P, GEN *mod)
2262 : {
2263 1495318 : pari_sp av = avma, av2;
2264 1495318 : long degA, degB, i, n = lg(P)-1;
2265 : GEN H, T;
2266 :
2267 1495318 : degA = degpol(A);
2268 1495317 : degB = B? degpol(B): degA - 1;
2269 1495315 : if (n == 1)
2270 : {
2271 811315 : ulong Hp, p = uel(P,1);
2272 811315 : GEN a = ZX_to_Flx(A, p), b = B? ZX_to_Flx(B, p): Flx_deriv(a, p);
2273 811330 : Hp = ZX_resultant_prime(a, b, dB, degA, degB, p);
2274 811356 : set_avma(av); *mod = utoipos(p); return utoi(Hp);
2275 : }
2276 684000 : T = ZV_producttree(P);
2277 683997 : A = ZX_nv_mod_tree(A, P, T);
2278 683996 : if (B) B = ZX_nv_mod_tree(B, P, T);
2279 683995 : H = cgetg(n+1, t_VECSMALL); av2 = avma;
2280 3737348 : for(i=1; i <= n; i++, set_avma(av2))
2281 : {
2282 3053356 : ulong p = P[i];
2283 3053356 : GEN a = gel(A,i), b = B? gel(B,i): Flx_deriv(a, p);
2284 3053662 : H[i] = ZX_resultant_prime(a, b, dB, degA, degB, p);
2285 : }
2286 683992 : H = ZV_chinese_tree(H, P, T, ZV_chinesetree(P,T));
2287 683997 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2288 : }
2289 :
2290 : GEN
2291 1495326 : ZX_resultant_worker(GEN P, GEN A, GEN B, GEN dB)
2292 : {
2293 1495326 : GEN V = cgetg(3, t_VEC);
2294 1495317 : if (typ(B) == t_INT) B = NULL;
2295 1495317 : if (!signe(dB)) dB = NULL;
2296 1495317 : gel(V,1) = ZX_resultant_slice(A, B, dB, P, &gel(V,2));
2297 1495342 : return V;
2298 : }
2299 :
2300 : /* Compute Res(A, B/dB) in Z, assuming A,B in Z[X], dB in Z or NULL (= 1)
2301 : * If B=NULL, take B = A' and assume deg A > 1 and 'bound' is set */
2302 : GEN
2303 1350874 : ZX_resultant_all(GEN A, GEN B, GEN dB, ulong bound)
2304 : {
2305 1350874 : pari_sp av = avma;
2306 : forprime_t S;
2307 : GEN H, worker;
2308 1350874 : if (!B && degpol(A)==2)
2309 : {
2310 114099 : GEN a = gel(A,4), b = gel(A,3), c = gel(A,2);
2311 114099 : H = mulii(a, subii(shifti(mulii(a, c), 2), sqri(b)));
2312 114086 : if (dB) H = diviiexact(H, sqri(dB));
2313 114086 : return gc_INT(av, H);
2314 : }
2315 1236773 : if (B)
2316 : {
2317 153986 : long a = degpol(A), b = degpol(B);
2318 153986 : if (a < 0 || b < 0) return gen_0;
2319 153956 : if (!a) return powiu(gel(A,2), b);
2320 153956 : if (!b) return powiu(gel(B,2), a);
2321 153331 : if (minss(a, b) <= 1)
2322 : {
2323 76626 : H = RgX_resultant_all(A, B, NULL);
2324 76626 : if (dB) H = diviiexact(H, powiu(dB, a));
2325 76626 : return gc_INT(av, H);
2326 : }
2327 76705 : if (!bound) bound = ZX_ZXY_ResBound(A, B, dB);
2328 : }
2329 1159500 : worker = snm_closure(is_entry("_ZX_resultant_worker"),
2330 : mkvec3(A, B? B: gen_0, dB? dB: gen_0));
2331 1159566 : init_modular_big(&S);
2332 1159520 : H = gen_crt("ZX_resultant_all", worker, &S, dB, bound, 0, NULL,
2333 : ZV_chinese_center, Fp_center);
2334 1159567 : return gc_INT(av, H);
2335 : }
2336 :
2337 : /* A0 and B0 in Q[X] */
2338 : GEN
2339 56 : QX_resultant(GEN A0, GEN B0)
2340 : {
2341 : GEN s, a, b, A, B;
2342 56 : pari_sp av = avma;
2343 :
2344 56 : A = Q_primitive_part(A0, &a);
2345 56 : B = Q_primitive_part(B0, &b);
2346 56 : s = ZX_resultant(A, B);
2347 56 : if (!signe(s)) { set_avma(av); return gen_0; }
2348 56 : if (a) s = gmul(s, gpowgs(a,degpol(B)));
2349 56 : if (b) s = gmul(s, gpowgs(b,degpol(A)));
2350 56 : return gc_upto(av, s);
2351 : }
2352 :
2353 : GEN
2354 56077 : ZX_resultant(GEN A, GEN B) { return ZX_resultant_all(A,B,NULL,0); }
2355 :
2356 : GEN
2357 0 : QXQ_intnorm(GEN A, GEN B)
2358 : {
2359 : GEN c, n, R, lB;
2360 0 : long dA = degpol(A), dB = degpol(B);
2361 0 : pari_sp av = avma;
2362 0 : if (dA < 0) return gen_0;
2363 0 : A = Q_primitive_part(A, &c);
2364 0 : if (!c || typ(c) == t_INT) {
2365 0 : n = c;
2366 0 : R = ZX_resultant(B, A);
2367 : } else {
2368 0 : n = gel(c,1);
2369 0 : R = ZX_resultant_all(B, A, gel(c,2), 0);
2370 : }
2371 0 : if (n && !equali1(n)) R = mulii(R, powiu(n, dB));
2372 0 : lB = leading_coeff(B);
2373 0 : if (!equali1(lB)) R = diviiexact(R, powiu(lB, dA));
2374 0 : return gc_INT(av, R);
2375 : }
2376 :
2377 : GEN
2378 19418 : QXQ_norm(GEN A, GEN B)
2379 : {
2380 : GEN c, R, lB;
2381 19418 : long dA = degpol(A), dB = degpol(B);
2382 19418 : pari_sp av = avma;
2383 19418 : if (dA < 0) return gen_0;
2384 19418 : A = Q_primitive_part(A, &c);
2385 19418 : R = ZX_resultant(B, A);
2386 19418 : if (c) R = gmul(R, gpowgs(c, dB));
2387 19418 : lB = leading_coeff(B);
2388 19418 : if (!equali1(lB)) R = gdiv(R, gpowgs(lB, dA));
2389 19418 : return gc_upto(av, R);
2390 : }
2391 :
2392 : /* assume x has integral coefficients */
2393 : GEN
2394 1200231 : ZX_disc_all(GEN x, ulong bound)
2395 : {
2396 1200231 : pari_sp av = avma;
2397 1200231 : long s, d = degpol(x);
2398 : GEN l, R;
2399 :
2400 1200225 : if (d <= 1) return d == 1? gen_1: gen_0;
2401 1196932 : s = (d & 2) ? -1: 1;
2402 1196932 : l = leading_coeff(x);
2403 1196933 : if (!bound) bound = ZX_discbound(x);
2404 1196858 : R = ZX_resultant_all(x, NULL, NULL, bound);
2405 1196930 : if (is_pm1(l))
2406 1017891 : { if (signe(l) < 0) s = -s; }
2407 : else
2408 179037 : R = diviiexact(R,l);
2409 1196928 : if (s == -1) togglesign_safe(&R);
2410 1196923 : return gc_INT(av,R);
2411 : }
2412 :
2413 : GEN
2414 1138163 : ZX_disc(GEN x) { return ZX_disc_all(x,0); }
2415 :
2416 : static GEN
2417 11008 : ZXQX_resultant_prime(GEN a, GEN b, GEN dB, long degA, long degB, GEN T, ulong p)
2418 : {
2419 11008 : pari_sp av = avma;
2420 11008 : long dropa = degA - degpol(a), dropb = degB - degpol(b);
2421 : GEN H, dp;
2422 11008 : if (dropa && dropb) return pol0_Flx(T[1]); /* p | lc(A), p | lc(B) */
2423 11008 : H = FlxqX_saferesultant(a, b, T, p);
2424 11007 : if (!H) return NULL;
2425 11007 : if (dropa)
2426 : { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */
2427 0 : GEN c = gel(b,degB+2); /* lc(B) */
2428 0 : if (odd(degB)) c = Flx_neg(c, p);
2429 0 : c = Flxq_powu(c, dropa, T, p);
2430 0 : if (!Flx_equal1(c)) H = Flxq_mul(H, c, T, p);
2431 : }
2432 11007 : else if (dropb)
2433 : { /* multiply by lc(A)^(deg B - deg b) */
2434 0 : GEN c = gel(a,degA+2); /* lc(A) */
2435 0 : c = Flxq_powu(c, dropb, T, p);
2436 0 : if (!Flx_equal1(c)) H = Flxq_mul(H, c, T, p);
2437 : }
2438 11007 : dp = dB ? ZX_to_Flx(dB, p): pol1_Flx(T[1]);
2439 11007 : if (!Flx_equal1(dp))
2440 : {
2441 0 : GEN idp = Flxq_invsafe(dp, T, p);
2442 0 : if (!idp) return NULL;
2443 0 : H = Flxq_mul(H, Flxq_powu(idp, degA, T, p), T, p);
2444 : }
2445 11008 : return gc_leaf(av, H);
2446 : }
2447 :
2448 : /* If B=NULL, assume B=A' */
2449 : static GEN
2450 4911 : ZXQX_resultant_slice(GEN A, GEN B, GEN U, GEN dB, GEN P, GEN *mod)
2451 : {
2452 4911 : pari_sp av = avma;
2453 4911 : long degA, degB, i, n = lg(P)-1;
2454 : GEN H, T;
2455 4911 : long v = varn(U), redo = 0;
2456 :
2457 4911 : degA = degpol(A);
2458 4911 : degB = B? degpol(B): degA - 1;
2459 4911 : if (n == 1)
2460 : {
2461 3177 : ulong p = uel(P,1);
2462 3177 : GEN a = ZXX_to_FlxX(A, p, v), b = B? ZXX_to_FlxX(B, p, v): FlxX_deriv(a, p);
2463 3177 : GEN u = ZX_to_Flx(U, p);
2464 3177 : GEN Hp = ZXQX_resultant_prime(a, b, dB, degA, degB, u, p);
2465 3177 : if (!Hp) { set_avma(av); *mod = gen_1; return pol_0(v); }
2466 3177 : Hp = gc_upto(av, Flx_to_ZX(Hp)); *mod = utoipos(p); return Hp;
2467 : }
2468 1734 : T = ZV_producttree(P);
2469 1734 : A = ZXX_nv_mod_tree(A, P, T, v);
2470 1734 : if (B) B = ZXX_nv_mod_tree(B, P, T, v);
2471 1734 : U = ZX_nv_mod_tree(U, P, T);
2472 1734 : H = cgetg(n+1, t_VEC);
2473 9566 : for(i=1; i <= n; i++)
2474 : {
2475 7832 : ulong p = P[i];
2476 7832 : GEN a = gel(A,i), b = B? gel(B,i): FlxX_deriv(a, p), u = gel(U, i);
2477 7831 : GEN h = ZXQX_resultant_prime(a, b, dB, degA, degB, u, p);
2478 7832 : if (!h)
2479 : {
2480 0 : gel(H,i) = pol_0(v);
2481 0 : P[i] = 1; redo = 1;
2482 : }
2483 : else
2484 7832 : gel(H,i) = h;
2485 : }
2486 1734 : if (redo) T = ZV_producttree(P);
2487 1734 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
2488 1734 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2489 : }
2490 :
2491 : GEN
2492 4911 : ZXQX_resultant_worker(GEN P, GEN A, GEN B, GEN T, GEN dB)
2493 : {
2494 4911 : GEN V = cgetg(3, t_VEC);
2495 4911 : if (isintzero(B)) B = NULL;
2496 4911 : if (!signe(dB)) dB = NULL;
2497 4911 : gel(V,1) = ZXQX_resultant_slice(A, B, T, dB, P, &gel(V,2));
2498 4911 : return V;
2499 : }
2500 :
2501 : static ulong
2502 4315 : ZXQX_resultant_bound_i(GEN nf, GEN A, GEN B, GEN (*f)(GEN,GEN,long))
2503 : {
2504 4315 : pari_sp av = avma;
2505 4315 : GEN r, M = nf_L2_bound(nf, NULL, &r);
2506 4315 : long v = nf_get_varn(nf), i, l = lg(r);
2507 4315 : GEN a = cgetg(l, t_COL);
2508 13334 : for (i = 1; i < l; i++)
2509 9019 : gel(a, i) = f(gsubst(A, v, gel(r,i)), gsubst(B, v, gel(r,i)), DEFAULTPREC);
2510 4315 : return gc_ulong(av, (ulong) dbllog2(gmul(M,RgC_fpnorml2(a, DEFAULTPREC))));
2511 : }
2512 : static ulong
2513 4000 : ZXQX_resultant_bound(GEN nf, GEN A, GEN B)
2514 4000 : { return ZXQX_resultant_bound_i(nf, A, B, &RgX_RgXY_ResBound); }
2515 :
2516 : static GEN
2517 56 : _ZXQ_powu(GEN x, ulong u, GEN T)
2518 56 : { return typ(x) == t_INT? powiu(x, u): ZXQ_powu(x, u, T); }
2519 :
2520 : /* Compute Res(A, B/dB) in Z[X]/T, assuming A,B in Z[X,Y], dB in Z or NULL (= 1)
2521 : * If B=NULL, take B = A' and assume deg A > 1 */
2522 : static GEN
2523 3997 : ZXQX_resultant_all(GEN A, GEN B, GEN T, GEN dB, ulong bound)
2524 : {
2525 3997 : pari_sp av = avma;
2526 : forprime_t S;
2527 : GEN H, worker;
2528 3997 : if (B)
2529 : {
2530 63 : long a = degpol(A), b = degpol(B);
2531 63 : if (a < 0 || b < 0) return gen_0;
2532 63 : if (!a) return _ZXQ_powu(gel(A,2), b, T);
2533 63 : if (!b) return _ZXQ_powu(gel(B,2), a, T);
2534 : } else
2535 3934 : if (!bound) B = RgX_deriv(A);
2536 3997 : if (!bound) bound = ZXQX_resultant_bound(nfinit(T, DEFAULTPREC), A, B);
2537 3997 : worker = snm_closure(is_entry("_ZXQX_resultant_worker"),
2538 : mkvec4(A, B? B: gen_0, T, dB? dB: gen_0));
2539 3997 : init_modular_big(&S);
2540 3997 : H = gen_crt("ZXQX_resultant_all", worker, &S, dB, bound, 0, NULL,
2541 : nxV_chinese_center, FpX_center);
2542 3997 : if (DEBUGLEVEL)
2543 0 : err_printf("ZXQX_resultant_all: a priori bound: %lu, a posteriori: %lu\n",
2544 : bound, expi(gsupnorm(H, DEFAULTPREC)));
2545 3997 : return gc_upto(av, H);
2546 : }
2547 :
2548 : GEN
2549 119 : nfX_resultant(GEN nf, GEN x, GEN y)
2550 : {
2551 119 : pari_sp av = avma;
2552 119 : GEN cx, cy, D, T = nf_get_pol(nf);
2553 119 : long dx = degpol(x), dy = degpol(y);
2554 119 : if (dx < 0 || dy < 0) return gen_0;
2555 119 : x = Q_primitive_part(x, &cx); if (cx) cx = gpowgs(cx, dy);
2556 119 : y = Q_primitive_part(y, &cy); if (cy) cy = gpowgs(cy, dx);
2557 119 : if (!dx) D = _ZXQ_powu(gel(x,2), dy, T);
2558 119 : else if (!dy) D = _ZXQ_powu(gel(y,2), dx, T);
2559 : else
2560 : {
2561 63 : ulong bound = ZXQX_resultant_bound(nf, x, y);
2562 63 : D = ZXQX_resultant_all(x, y, T, NULL, bound);
2563 : }
2564 119 : cx = mul_content(cx, cy); if (cx) D = gmul(D, cx);
2565 119 : return gc_upto(av, D);
2566 : }
2567 :
2568 : static GEN
2569 252 : to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; }
2570 :
2571 : static GEN
2572 3934 : ZXQX_disc_all(GEN x, GEN T, ulong bound)
2573 : {
2574 3934 : pari_sp av = avma;
2575 3934 : long s, d = degpol(x), v = varn(T);
2576 : GEN l, R;
2577 :
2578 3934 : if (d <= 1) return d == 1? pol_1(v): pol_0(v);
2579 3934 : s = (d & 2) ? -1: 1;
2580 3934 : l = leading_coeff(x);
2581 3934 : R = ZXQX_resultant_all(x, NULL, T, NULL, bound);
2582 3934 : if (!gequal1(l)) R = QXQ_div(R, to_ZX(l,v), T);
2583 3934 : if (s == -1) R = RgX_neg(R);
2584 3934 : return gc_upto(av, R);
2585 : }
2586 :
2587 : GEN
2588 7 : QX_disc(GEN x)
2589 : {
2590 7 : pari_sp av = avma;
2591 7 : GEN c, d = ZX_disc( Q_primitive_part(x, &c) );
2592 7 : if (c) d = gmul(d, gpowgs(c, 2*degpol(x) - 2));
2593 7 : return gc_upto(av, d);
2594 : }
2595 :
2596 : GEN
2597 4165 : nfX_disc(GEN nf, GEN x)
2598 : {
2599 4165 : pari_sp av = avma;
2600 4165 : GEN c, D, T = nf_get_pol(nf);
2601 : ulong bound;
2602 4165 : long d = degpol(x), v = varn(T);
2603 4165 : if (d <= 1) return d == 1? pol_1(v): pol_0(v);
2604 3934 : x = Q_primitive_part(x, &c);
2605 3934 : bound = ZXQX_resultant_bound(nf, x, RgX_deriv(x));
2606 3934 : D = ZXQX_disc_all(x, T, bound);
2607 3934 : if (c) D = gmul(D, gpowgs(c, 2*d - 2));
2608 3934 : return gc_upto(av, D);
2609 : }
2610 :
2611 : GEN
2612 846035 : QXQ_mul(GEN x, GEN y, GEN T)
2613 : {
2614 846035 : GEN dx, nx = Q_primitive_part(x, &dx);
2615 846034 : GEN dy, ny = Q_primitive_part(y, &dy);
2616 846032 : GEN z = ZXQ_mul(nx, ny, T);
2617 846032 : if (dx || dy)
2618 : {
2619 843232 : GEN d = dx ? dy ? gmul(dx, dy): dx : dy;
2620 843232 : if (!gequal1(d)) z = ZX_Q_mul(z, d);
2621 : }
2622 846035 : return z;
2623 : }
2624 :
2625 : GEN
2626 407043 : QXQ_sqr(GEN x, GEN T)
2627 : {
2628 407043 : GEN dx, nx = Q_primitive_part(x, &dx);
2629 407043 : GEN z = ZXQ_sqr(nx, T);
2630 407043 : if (dx)
2631 405307 : z = ZX_Q_mul(z, gsqr(dx));
2632 407043 : return z;
2633 : }
2634 :
2635 : static GEN
2636 212912 : QXQ_inv_slice(GEN A, GEN B, GEN P, GEN *mod)
2637 : {
2638 212912 : pari_sp av = avma;
2639 212912 : long i, n = lg(P)-1, v = varn(A), redo = 0;
2640 : GEN H, T;
2641 212912 : if (n == 1)
2642 : {
2643 165824 : ulong p = uel(P,1);
2644 165824 : GEN a = ZX_to_Flx(A, p), b = ZX_to_Flx(B, p);
2645 165824 : GEN U = Flxq_invsafe(a, b, p);
2646 165824 : if (!U)
2647 : {
2648 24 : set_avma(av);
2649 24 : *mod = gen_1; return pol_0(v);
2650 : }
2651 165800 : H = gc_GEN(av, Flx_to_ZX(U));
2652 165800 : *mod = utoipos(p); return H;
2653 : }
2654 47088 : T = ZV_producttree(P);
2655 47088 : A = ZX_nv_mod_tree(A, P, T);
2656 47088 : B = ZX_nv_mod_tree(B, P, T);
2657 47088 : H = cgetg(n+1, t_VEC);
2658 238087 : for(i=1; i <= n; i++)
2659 : {
2660 190999 : ulong p = P[i];
2661 190999 : GEN a = gel(A,i), b = gel(B,i);
2662 190999 : GEN U = Flxq_invsafe(a, b, p);
2663 190999 : if (!U)
2664 : {
2665 601 : gel(H,i) = pol_0(v);
2666 601 : P[i] = 1; redo = 1;
2667 : }
2668 : else
2669 190398 : gel(H,i) = U;
2670 : }
2671 47088 : if (redo) T = ZV_producttree(P);
2672 47088 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
2673 47088 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2674 : }
2675 :
2676 : GEN
2677 212912 : QXQ_inv_worker(GEN P, GEN A, GEN B)
2678 : {
2679 212912 : GEN V = cgetg(3, t_VEC);
2680 212912 : gel(V,1) = QXQ_inv_slice(A, B, P, &gel(V,2));
2681 212912 : return V;
2682 : }
2683 :
2684 : /* lift(1 / Mod(A,B)). B a ZX, A a scalar or a QX */
2685 : GEN
2686 146111 : QXQ_inv(GEN A, GEN B)
2687 : {
2688 : GEN D, Ap, Bp;
2689 : ulong pp;
2690 146111 : pari_sp av2, av = avma;
2691 : forprime_t S;
2692 146111 : GEN worker, U, H = NULL, mod = gen_1;
2693 : pari_timer ti;
2694 : long k, dA, dB;
2695 146111 : if (is_scalar_t(typ(A))) return scalarpol(ginv(A), varn(B));
2696 : /* A a QX, B a ZX */
2697 146111 : A = Q_primitive_part(A, &D);
2698 146111 : dA = degpol(A); dB= degpol(B);
2699 : /* A, B in Z[X] */
2700 146111 : init_modular_small(&S);
2701 : do {
2702 146111 : pp = u_forprime_next(&S);
2703 146111 : Ap = ZX_to_Flx(A, pp);
2704 146111 : Bp = ZX_to_Flx(B, pp);
2705 146111 : } while (degpol(Ap) != dA || degpol(Bp) != dB);
2706 146111 : if (degpol(Flx_gcd(Ap, Bp, pp)) != 0 && degpol(ZX_gcd(A,B))!=0)
2707 14 : pari_err_INV("QXQ_inv",mkpolmod(A,B));
2708 146097 : worker = snm_closure(is_entry("_QXQ_inv_worker"), mkvec2(A, B));
2709 146097 : av2 = avma;
2710 146097 : for (k = 1; ;k *= 2)
2711 42591 : {
2712 : GEN res, b, N, den;
2713 188688 : gen_inccrt_i("QXQ_inv", worker, NULL, (k+1)>>1, 0, &S, &H, &mod,
2714 : nxV_chinese_center, FpX_center);
2715 188688 : (void)gc_all(av2, 2, &H, &mod);
2716 188688 : b = sqrti(shifti(mod,-1));
2717 188688 : if (DEBUGLEVEL>5) timer_start(&ti);
2718 188688 : U = FpX_ratlift(H, mod, b, b, NULL);
2719 188688 : if (DEBUGLEVEL>5) timer_printf(&ti,"QXQ_inv: ratlift");
2720 194434 : if (!U) continue;
2721 151843 : N = Q_remove_denom(U, &den); if (!den) den = gen_1;
2722 151843 : res = Flx_rem(Flx_Fl_sub(Flx_mul(Ap, ZX_to_Flx(N,pp), pp),
2723 : umodiu(den, pp), pp), Bp, pp);
2724 151843 : if (degpol(res) >= 0) continue;
2725 146097 : res = ZX_Z_sub(ZX_mul(A, N), den);
2726 146097 : res = ZX_is_monic(B) ? ZX_rem(res, B): RgX_pseudorem(res, B);
2727 146097 : if (DEBUGLEVEL>5) timer_printf(&ti,"QXQ_inv: final check");
2728 146097 : if (degpol(res)<0)
2729 : {
2730 146097 : if (D) U = RgX_Rg_div(U, D);
2731 146097 : return gc_GEN(av, U);
2732 : }
2733 : }
2734 : }
2735 :
2736 : static GEN
2737 121107 : QXQ_div_slice(GEN A, GEN B, GEN C, GEN P, GEN *mod)
2738 : {
2739 121107 : pari_sp av = avma;
2740 121107 : long i, n = lg(P)-1, v = varn(A), redo = 0;
2741 : GEN H, T;
2742 121107 : if (n == 1)
2743 : {
2744 44701 : ulong p = uel(P,1);
2745 44701 : GEN a = ZX_to_Flx(A, p), b = ZX_to_Flx(B, p), c = ZX_to_Flx(C, p);
2746 44701 : GEN bi = Flxq_invsafe(b, c, p), U;
2747 44701 : if (!bi)
2748 : {
2749 0 : set_avma(av);
2750 0 : *mod = gen_1; return pol_0(v);
2751 : }
2752 44701 : U = Flxq_mul(a, bi, c, p);
2753 44701 : H = gc_GEN(av, Flx_to_ZX(U));
2754 44701 : *mod = utoipos(p); return H;
2755 : }
2756 76406 : T = ZV_producttree(P);
2757 76406 : A = ZX_nv_mod_tree(A, P, T);
2758 76406 : B = ZX_nv_mod_tree(B, P, T);
2759 76406 : C = ZX_nv_mod_tree(C, P, T);
2760 76406 : H = cgetg(n+1, t_VEC);
2761 337448 : for(i=1; i <= n; i++)
2762 : {
2763 261042 : ulong p = P[i];
2764 261042 : GEN a = gel(A,i), b = gel(B,i), c = gel(C, i);
2765 261042 : GEN bi = Flxq_invsafe(b, c, p);
2766 261042 : if (!bi)
2767 : {
2768 4 : gel(H,i) = pol_0(v);
2769 4 : P[i] = 1; redo = 1;
2770 : }
2771 : else
2772 261038 : gel(H,i) = Flxq_mul(a, bi, c, p);
2773 : }
2774 76406 : if (redo) T = ZV_producttree(P);
2775 76406 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
2776 76406 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2777 : }
2778 :
2779 : GEN
2780 121107 : QXQ_div_worker(GEN P, GEN A, GEN B, GEN C)
2781 : {
2782 121107 : GEN V = cgetg(3, t_VEC);
2783 121107 : gel(V,1) = QXQ_div_slice(A, B, C, P, &gel(V,2));
2784 121107 : return V;
2785 : }
2786 :
2787 : /* lift(Mod(A/B, C)). C a ZX, A, B a scalar or a QX */
2788 : GEN
2789 33207 : QXQ_div(GEN A, GEN B, GEN C)
2790 : {
2791 : GEN DA, DB, Ap, Bp, Cp;
2792 : ulong pp;
2793 33207 : pari_sp av2, av = avma;
2794 : forprime_t S;
2795 33207 : GEN worker, U, H = NULL, mod = gen_1;
2796 : pari_timer ti;
2797 : long k, dA, dB, dC;
2798 33207 : if (is_scalar_t(typ(A))) return scalarpol(ginv(A), varn(B));
2799 : /* A a QX, B a ZX */
2800 33207 : A = Q_primitive_part(A, &DA);
2801 33207 : B = Q_primitive_part(B, &DB);
2802 33207 : dA = degpol(A); dB = degpol(B); dC = degpol(C);
2803 : /* A, B in Z[X] */
2804 33207 : init_modular_small(&S);
2805 : do {
2806 33207 : pp = u_forprime_next(&S);
2807 33207 : Ap = ZX_to_Flx(A, pp);
2808 33207 : Bp = ZX_to_Flx(B, pp);
2809 33207 : Cp = ZX_to_Flx(C, pp);
2810 33207 : } while (degpol(Ap) != dA || degpol(Bp) != dB || degpol(Cp) != dC);
2811 33207 : if (degpol(Flx_gcd(Bp, Cp, pp)) != 0 && degpol(ZX_gcd(B,C))!=0)
2812 0 : pari_err_INV("QXQ_div",mkpolmod(B,C));
2813 33207 : worker = snm_closure(is_entry("_QXQ_div_worker"), mkvec3(A, B, C));
2814 33207 : av2 = avma;
2815 33207 : for (k = 1; ;k *= 2)
2816 46720 : {
2817 : GEN res, b, N, den;
2818 79927 : gen_inccrt_i("QXQ_div", worker, NULL, (k+1)>>1, 0, &S, &H, &mod,
2819 : nxV_chinese_center, FpX_center);
2820 79927 : (void)gc_all(av2, 2, &H, &mod);
2821 79927 : b = sqrti(shifti(mod,-1));
2822 79927 : if (DEBUGLEVEL>5) timer_start(&ti);
2823 79927 : U = FpX_ratlift(H, mod, b, b, NULL);
2824 79927 : if (DEBUGLEVEL>5) timer_printf(&ti,"QXQ_div: ratlift");
2825 90556 : if (!U) continue;
2826 43836 : N = Q_remove_denom(U, &den); if (!den) den = gen_1;
2827 43836 : res = Flx_rem(Flx_sub(Flx_mul(Bp, ZX_to_Flx(N,pp), pp),
2828 : Flx_Fl_mul(Ap, umodiu(den, pp), pp), pp), Cp, pp);
2829 43836 : if (degpol(res) >= 0) continue;
2830 33207 : res = ZX_sub(ZX_mul(B, N), ZX_Z_mul(A,den));
2831 33207 : res = ZX_is_monic(C) ? ZX_rem(res, C): RgX_pseudorem(res, C);
2832 33207 : if (DEBUGLEVEL>5) timer_printf(&ti,"QXQ_div: final check");
2833 33207 : if (degpol(res)<0)
2834 : {
2835 33207 : if (DA && DB) U = RgX_Rg_mul(U, gdiv(DA,DB));
2836 28069 : else if (DA) U = RgX_Rg_mul(U, DA);
2837 15981 : else if (DB) U = RgX_Rg_div(U, DB);
2838 33207 : return gc_GEN(av, U);
2839 : }
2840 : }
2841 : }
2842 :
2843 : /************************************************************************
2844 : * *
2845 : * ZXQ_minpoly *
2846 : * *
2847 : ************************************************************************/
2848 :
2849 : static GEN
2850 3523 : ZXQ_minpoly_slice(GEN A, GEN B, long d, GEN P, GEN *mod)
2851 : {
2852 3523 : pari_sp av = avma;
2853 3523 : long i, n = lg(P)-1, v = evalvarn(varn(B));
2854 : GEN H, T;
2855 3523 : if (n == 1)
2856 : {
2857 716 : ulong p = uel(P,1);
2858 716 : GEN a = ZX_to_Flx(A, p), b = ZX_to_Flx(B, p);
2859 716 : GEN Hp = Flxq_minpoly(a, b, p);
2860 716 : if (degpol(Hp) != d) { p = 1; Hp = pol0_Flx(v); }
2861 716 : H = gc_upto(av, Flx_to_ZX(Hp));
2862 716 : *mod = utoipos(p); return H;
2863 : }
2864 2807 : T = ZV_producttree(P);
2865 2807 : A = ZX_nv_mod_tree(A, P, T);
2866 2807 : B = ZX_nv_mod_tree(B, P, T);
2867 2807 : H = cgetg(n+1, t_VEC);
2868 16838 : for(i=1; i <= n; i++)
2869 : {
2870 14031 : ulong p = P[i];
2871 14031 : GEN a = gel(A,i), b = gel(B,i);
2872 14031 : GEN m = Flxq_minpoly(a, b, p);
2873 14031 : if (degpol(m) != d) { P[i] = 1; m = pol0_Flx(v); }
2874 14031 : gel(H, i) = m;
2875 : }
2876 2807 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
2877 2807 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2878 : }
2879 :
2880 : GEN
2881 3523 : ZXQ_minpoly_worker(GEN P, GEN A, GEN B, long d)
2882 : {
2883 3523 : GEN V = cgetg(3, t_VEC);
2884 3523 : gel(V,1) = ZXQ_minpoly_slice(A, B, d, P, &gel(V,2));
2885 3523 : return V;
2886 : }
2887 :
2888 : GEN
2889 1701 : ZXQ_minpoly(GEN A, GEN B, long d, ulong bound)
2890 : {
2891 1701 : pari_sp av = avma;
2892 : GEN worker, H, dB;
2893 : forprime_t S;
2894 1701 : B = Q_remove_denom(B, &dB);
2895 1701 : worker = strtoclosure("_ZXQ_minpoly_worker", 3, A, B, stoi(d));
2896 1701 : init_modular_big(&S);
2897 1701 : H = gen_crt("ZXQ_minpoly", worker, &S, dB, bound, 0, NULL,
2898 : nxV_chinese_center, FpX_center_i);
2899 1701 : return gc_GEN(av, H);
2900 : }
2901 :
2902 : /************************************************************************
2903 : * *
2904 : * ZX_ZXY_resultant *
2905 : * *
2906 : ************************************************************************/
2907 :
2908 : static GEN
2909 364908 : ZX_ZXY_resultant_prime(GEN a, GEN b, ulong dp, ulong p,
2910 : long degA, long degB, long dres, long sX)
2911 : {
2912 364908 : pari_sp av = avma;
2913 364908 : long dropa = degA - degpol(a), dropb = degB - degpol(b);
2914 364907 : ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
2915 364907 : GEN Hp = Flx_FlxY_resultant_polint(a, b, p, pi, dres, sX);
2916 364910 : if (dropa && dropb)
2917 0 : Hp = zero_Flx(sX);
2918 : else {
2919 364910 : if (dropa)
2920 : { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */
2921 0 : GEN c = gel(b,degB+2); /* lc(B) */
2922 0 : if (odd(degB)) c = Flx_neg(c, p);
2923 0 : if (!Flx_equal1(c)) {
2924 0 : c = Flx_powu_pre(c, dropa, p, pi);
2925 0 : if (!Flx_equal1(c)) Hp = Flx_mul_pre(Hp, c, p, pi);
2926 : }
2927 : }
2928 364910 : else if (dropb)
2929 : { /* multiply by lc(A)^(deg B - deg b) */
2930 0 : ulong c = uel(a, degA+2); /* lc(A) */
2931 0 : c = Fl_powu(c, dropb, p);
2932 0 : if (c != 1) Hp = Flx_Fl_mul_pre(Hp, c, p, pi);
2933 : }
2934 : }
2935 364910 : if (dp != 1) Hp = Flx_Fl_mul_pre(Hp, Fl_powu_pre(Fl_inv(dp,p), degA, p, pi), p, pi);
2936 364910 : return gc_leaf(av, Hp);
2937 : }
2938 :
2939 : static GEN
2940 124962 : ZX_ZXY_resultant_slice(GEN A, GEN B, GEN dB, long degA, long degB, long dres,
2941 : GEN P, GEN *mod, long sX, long vY)
2942 : {
2943 124962 : pari_sp av = avma;
2944 124962 : long i, n = lg(P)-1;
2945 : GEN H, T, D;
2946 124962 : if (n == 1)
2947 : {
2948 40164 : ulong p = uel(P,1);
2949 40164 : ulong dp = dB ? umodiu(dB, p): 1;
2950 40164 : GEN a = ZX_to_Flx(A, p), b = ZXX_to_FlxX(B, p, vY);
2951 40164 : GEN Hp = ZX_ZXY_resultant_prime(a, b, dp, p, degA, degB, dres, sX);
2952 40165 : H = gc_upto(av, Flx_to_ZX(Hp));
2953 40165 : *mod = utoipos(p); return H;
2954 : }
2955 84798 : T = ZV_producttree(P);
2956 84798 : A = ZX_nv_mod_tree(A, P, T);
2957 84798 : B = ZXX_nv_mod_tree(B, P, T, vY);
2958 84798 : D = dB ? Z_ZV_mod_tree(dB, P, T): NULL;
2959 84798 : H = cgetg(n+1, t_VEC);
2960 364208 : for(i=1; i <= n; i++)
2961 : {
2962 279410 : ulong p = P[i];
2963 279410 : GEN a = gel(A,i), b = gel(B,i);
2964 279410 : ulong dp = D ? uel(D, i): 1;
2965 279410 : gel(H,i) = ZX_ZXY_resultant_prime(a, b, dp, p, degA, degB, dres, sX);
2966 : }
2967 84798 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
2968 84798 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2969 : }
2970 :
2971 : GEN
2972 124962 : ZX_ZXY_resultant_worker(GEN P, GEN A, GEN B, GEN dB, GEN v)
2973 : {
2974 124962 : GEN V = cgetg(3, t_VEC);
2975 124962 : if (isintzero(dB)) dB = NULL;
2976 124962 : gel(V,1) = ZX_ZXY_resultant_slice(A, B, dB, v[1], v[2], v[3], P, &gel(V,2), v[4], v[5]);
2977 124963 : return V;
2978 : }
2979 :
2980 : GEN
2981 79195 : ZX_ZXY_resultant(GEN A, GEN B)
2982 : {
2983 79195 : pari_sp av = avma;
2984 : forprime_t S;
2985 : ulong bound;
2986 79195 : long v = fetch_var_higher();
2987 79195 : long degA = degpol(A), degB, dres = degA * degpol(B);
2988 79195 : long vX = varn(B), vY = varn(A); /* assume vY has lower priority */
2989 79195 : long sX = evalvarn(vX);
2990 : GEN worker, H, dB;
2991 79195 : B = Q_remove_denom(B, &dB);
2992 79195 : if (!dB) B = leafcopy(B);
2993 79195 : A = leafcopy(A); setvarn(A,v);
2994 79195 : B = swap_vars(B, vY, v); degB = degpol(B);
2995 79196 : bound = ZX_ZXY_ResBound(A, B, dB);
2996 79193 : if (DEBUGLEVEL>4) err_printf("bound for resultant coeffs: 2^%ld\n",bound);
2997 158389 : worker = snm_closure(is_entry("_ZX_ZXY_resultant_worker"),
2998 79196 : mkvec4(A, B, dB? dB: gen_0,
2999 : mkvecsmall5(degA, degB, dres, sX, vY)));
3000 79195 : init_modular_big(&S);
3001 79195 : H = gen_crt("ZX_ZXY_resultant_all", worker, &S, dB, bound, 0, NULL,
3002 : nxV_chinese_center, FpX_center_i);
3003 79196 : setvarn(H, vX); (void)delete_var();
3004 79196 : return gc_GEN(av, H);
3005 : }
3006 :
3007 : static GEN
3008 1118164 : ZXX_resultant_prime(GEN a, GEN b, ulong p, long degA, long degB, long dres, long sX)
3009 : {
3010 1118164 : pari_sp av = avma;
3011 1118164 : long dropa = degA - degpol(a), dropb = degB - degpol(b);
3012 1118164 : ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
3013 1118164 : GEN Hp = FlxX_resultant_polint(a, b, p, pi, dres, sX);
3014 1118162 : if (dropa && dropb)
3015 0 : Hp = zero_Flx(sX);
3016 : else {
3017 1118162 : if (dropa)
3018 : { /* multiply by ((-1)^deg B lc(B))^(deg A - deg a) */
3019 0 : GEN c = gel(b,degB+2); /* lc(B) */
3020 0 : if (odd(degB)) c = Flx_neg(c, p);
3021 0 : if (!Flx_equal1(c)) {
3022 0 : c = Flx_powu_pre(c, dropa, p, pi);
3023 0 : if (!Flx_equal1(c)) Hp = Flx_mul_pre(Hp, c, p, pi);
3024 : }
3025 : }
3026 1118162 : else if (dropb)
3027 : { /* multiply by lc(A)^(deg B - deg b) */
3028 0 : ulong c = uel(a, degA+2); /* lc(A) */
3029 0 : c = Fl_powu(c, dropb, p);
3030 0 : if (c != 1) Hp = Flx_Fl_mul_pre(Hp, c, p, pi);
3031 : }
3032 : }
3033 1118162 : return gc_leaf(av, Hp);
3034 : }
3035 :
3036 : static GEN
3037 1015937 : ZXX_resultant_slice(GEN A, GEN B, long degA, long degB, long dres,
3038 : GEN P, GEN *mod, long sX, long vY)
3039 : {
3040 1015937 : pari_sp av = avma;
3041 1015937 : long i, n = lg(P)-1;
3042 : GEN H, T;
3043 1015937 : if (n == 1)
3044 : {
3045 931915 : ulong p = uel(P,1);
3046 931915 : GEN a = ZXX_to_FlxX(A, p, vY), b = ZXX_to_FlxX(B, p, vY);
3047 931914 : GEN Hp = ZXX_resultant_prime(a, b, p, degA, degB, dres, sX);
3048 931912 : H = gc_upto(av, Flx_to_ZX(Hp));
3049 931916 : *mod = utoipos(p); return H;
3050 : }
3051 84022 : T = ZV_producttree(P);
3052 84022 : A = ZXX_nv_mod_tree(A, P, T, vY);
3053 84022 : B = ZXX_nv_mod_tree(B, P, T, vY);
3054 84022 : H = cgetg(n+1, t_VEC);
3055 270272 : for(i=1; i <= n; i++)
3056 : {
3057 186250 : ulong p = P[i];
3058 186250 : GEN a = gel(A,i), b = gel(B,i);
3059 186250 : gel(H,i) = ZXX_resultant_prime(a, b, p, degA, degB, dres, sX);
3060 : }
3061 84022 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
3062 84022 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
3063 : }
3064 :
3065 : GEN
3066 1015937 : ZXX_resultant_worker(GEN P, GEN A, GEN B, GEN v)
3067 : {
3068 1015937 : GEN V = cgetg(3, t_VEC);
3069 1015937 : gel(V,1) = ZXX_resultant_slice(A, B, v[1], v[2], v[3], P, &gel(V,2), v[4], v[5]);
3070 1015938 : return V;
3071 : }
3072 :
3073 : GEN
3074 1010652 : ZXX_resultant(GEN A, GEN B, long vX)
3075 : {
3076 1010652 : pari_sp av = avma;
3077 : forprime_t S;
3078 : ulong bound;
3079 1010652 : long degA = degpol(A), degB = degpol(B), dres = degA * RgXY_degreex(B) + RgXY_degreex(A)*degB;
3080 1010652 : long vY = varn(A), sX = evalvarn(vX);
3081 : GEN worker, H;
3082 1010652 : bound = ZXX_ResBound(A, B);
3083 1010648 : if (DEBUGLEVEL>4) err_printf("bound for resultant coeffs: 2^%ld\n",bound);
3084 1010648 : worker = snm_closure(is_entry("_ZXX_resultant_worker"),
3085 : mkvec3(A, B, mkvecsmall5(degA, degB, dres, sX, vY)));
3086 1010655 : init_modular_big(&S);
3087 1010654 : H = gen_crt("ZXX_resultant", worker, &S, NULL, bound, 0, NULL, nxV_chinese_center, FpX_center_i);
3088 1010655 : return gc_GEN(av, H);
3089 : }
3090 :
3091 : static long
3092 40523 : ZX_ZXY_rnfequation_lambda(GEN A, GEN B0, long lambda)
3093 : {
3094 40523 : pari_sp av = avma;
3095 40523 : long degA = degpol(A), degB, dres = degA*degpol(B0);
3096 40523 : long v = fetch_var_higher();
3097 40523 : long vX = varn(B0), vY = varn(A); /* assume vY has lower priority */
3098 40523 : long sX = evalvarn(vX);
3099 : GEN dB, B, a, b, Hp;
3100 : forprime_t S;
3101 :
3102 40523 : B0 = Q_remove_denom(B0, &dB);
3103 40523 : if (!dB) B0 = leafcopy(B0);
3104 40523 : A = leafcopy(A);
3105 40523 : B = B0;
3106 40523 : setvarn(A,v);
3107 45335 : INIT:
3108 45335 : if (lambda) B = RgX_Rg_translate(B0, monomial(stoi(lambda), 1, vY));
3109 45335 : B = swap_vars(B, vY, v);
3110 : /* B0(lambda v + x, v) */
3111 45334 : if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda);
3112 :
3113 45334 : degB = degpol(B);
3114 45334 : init_modular_big(&S);
3115 : while (1)
3116 0 : {
3117 45334 : ulong p = u_forprime_next(&S);
3118 45334 : ulong dp = dB ? umodiu(dB, p): 1;
3119 45334 : if (!dp) continue;
3120 45334 : a = ZX_to_Flx(A, p);
3121 45335 : b = ZXX_to_FlxX(B, p, v);
3122 45335 : Hp = ZX_ZXY_resultant_prime(a, b, dp, p, degA, degB, dres, sX);
3123 45335 : if (degpol(Hp) != dres) continue;
3124 45335 : if (dp != 1) Hp = Flx_Fl_mul(Hp, Fl_powu(Fl_inv(dp,p), degA, p), p);
3125 45335 : if (!Flx_is_squarefree(Hp, p)) { lambda = next_lambda(lambda); goto INIT; }
3126 40522 : if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda);
3127 40522 : (void)delete_var(); return gc_long(av,lambda);
3128 : }
3129 : }
3130 :
3131 : GEN
3132 60562 : ZX_ZXY_rnfequation(GEN A, GEN B, long *lambda)
3133 : {
3134 60562 : if (lambda)
3135 : {
3136 40523 : *lambda = ZX_ZXY_rnfequation_lambda(A, B, *lambda);
3137 40522 : if (*lambda) B = RgX_Rg_translate(B, monomial(stoi(*lambda), 1, varn(A)));
3138 : }
3139 60561 : return ZX_ZXY_resultant(A,B);
3140 : }
3141 :
3142 : static GEN
3143 10350 : ZX_composedsum_slice(GEN A, GEN B, GEN P, GEN *mod)
3144 : {
3145 10350 : pari_sp av = avma;
3146 10350 : long i, n = lg(P)-1;
3147 : GEN H, T;
3148 10350 : if (n == 1)
3149 : {
3150 9848 : ulong p = uel(P,1);
3151 9848 : GEN a = ZX_to_Flx(A, p), b = ZX_to_Flx(B, p);
3152 9845 : GEN Hp = Flx_composedsum(a, b, p);
3153 9849 : H = gc_upto(av, Flx_to_ZX(Hp));
3154 9847 : *mod = utoipos(p); return H;
3155 : }
3156 502 : T = ZV_producttree(P);
3157 502 : A = ZX_nv_mod_tree(A, P, T);
3158 502 : B = ZX_nv_mod_tree(B, P, T);
3159 502 : H = cgetg(n+1, t_VEC);
3160 4526 : for(i=1; i <= n; i++)
3161 : {
3162 4024 : ulong p = P[i];
3163 4024 : GEN a = gel(A,i), b = gel(B,i);
3164 4024 : gel(H,i) = Flx_composedsum(a, b, p);
3165 : }
3166 502 : H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));
3167 502 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
3168 : }
3169 :
3170 : GEN
3171 10352 : ZX_composedsum_worker(GEN P, GEN A, GEN B)
3172 : {
3173 10352 : GEN V = cgetg(3, t_VEC);
3174 10350 : gel(V,1) = ZX_composedsum_slice(A, B, P, &gel(V,2));
3175 10350 : return V;
3176 : }
3177 :
3178 : static GEN
3179 10085 : ZX_composedsum_i(GEN A, GEN B, GEN lead)
3180 : {
3181 10085 : pari_sp av = avma;
3182 : forprime_t S;
3183 : ulong bound;
3184 : GEN H, worker, mod;
3185 10085 : if (degpol(A) < degpol(B)) swap(A, B);
3186 10085 : if (!lead) lead = mulii(leading_coeff(A),leading_coeff(B));
3187 10085 : bound = ZX_ZXY_ResBound_1(A, B);
3188 10086 : worker = snm_closure(is_entry("_ZX_composedsum_worker"), mkvec2(A,B));
3189 10087 : init_modular_big(&S);
3190 10087 : H = gen_crt("ZX_composedsum", worker, &S, lead, bound, 0, &mod,
3191 : nxV_chinese_center, FpX_center);
3192 10086 : return gc_upto(av, H);
3193 : }
3194 :
3195 : static long
3196 9696 : ZX_compositum_lambda(GEN A, GEN B, GEN lead, long lambda)
3197 : {
3198 9696 : pari_sp av = avma;
3199 : forprime_t S;
3200 : ulong p;
3201 9696 : init_modular_big(&S);
3202 9696 : p = u_forprime_next(&S);
3203 : while (1)
3204 112 : {
3205 : GEN Hp, a;
3206 9808 : if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda);
3207 9808 : if (lead && dvdiu(lead,p)) { p = u_forprime_next(&S); continue; }
3208 9802 : a = ZX_to_Flx(ZX_rescale(A, stoi(-lambda)), p);
3209 9804 : Hp = Flx_composedsum(a, ZX_to_Flx(B, p), p);
3210 9806 : if (!Flx_is_squarefree(Hp, p)) { lambda = next_lambda(lambda); continue; }
3211 9698 : if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda);
3212 9698 : return gc_long(av, lambda);
3213 : }
3214 : }
3215 :
3216 : GEN
3217 9698 : ZX_compositum(GEN A, GEN B, long *lambda)
3218 : {
3219 9698 : GEN lead = mulii(leading_coeff(A),leading_coeff(B));
3220 9696 : if (lambda)
3221 : {
3222 9696 : *lambda = ZX_compositum_lambda(A, B, lead, *lambda);
3223 9698 : A = ZX_rescale(A, stoi(-*lambda));
3224 : }
3225 9700 : return ZX_composedsum_i(A, B, lead);
3226 : }
3227 :
3228 : GEN
3229 385 : ZX_composedsum(GEN A, GEN B)
3230 385 : { return ZX_composedsum_i(A, B, NULL); }
3231 :
3232 : static GEN
3233 359 : ZXQX_composedsum_slice(GEN A, GEN B, GEN C, GEN P, GEN *mod)
3234 : {
3235 359 : pari_sp av = avma;
3236 359 : long i, n = lg(P)-1, dC = degpol(C), v = varn(C);
3237 : GEN H, T;
3238 359 : if (n == 1)
3239 : {
3240 181 : ulong p = uel(P,1);
3241 181 : GEN a = ZXX_to_FlxX(A, p, v), b = ZXX_to_FlxX(B, p, v);
3242 181 : GEN c = ZX_to_Flx(C, p);
3243 181 : GEN Hp = FlxX_to_Flm(FlxqX_composedsum(a, b, c, p), dC);
3244 181 : H = gc_upto(av, Flm_to_ZM(Hp));
3245 181 : *mod = utoipos(p); return H;
3246 : }
3247 178 : T = ZV_producttree(P);
3248 178 : A = ZXX_nv_mod_tree(A, P, T, v);
3249 178 : B = ZXX_nv_mod_tree(B, P, T, v);
3250 178 : C = ZX_nv_mod_tree(C, P, T);
3251 178 : H = cgetg(n+1, t_VEC);
3252 660 : for(i=1; i <= n; i++)
3253 : {
3254 482 : ulong p = P[i];
3255 482 : GEN a = gel(A,i), b = gel(B,i), c = gel(C,i);
3256 482 : gel(H,i) = FlxX_to_Flm(FlxqX_composedsum(a, b, c, p), dC);
3257 : }
3258 178 : H = nmV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P, T));
3259 178 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
3260 : }
3261 :
3262 : GEN
3263 359 : ZXQX_composedsum_worker(GEN P, GEN A, GEN B, GEN C)
3264 : {
3265 359 : GEN V = cgetg(3, t_VEC);
3266 359 : gel(V,1) = ZXQX_composedsum_slice(A, B, C, P, &gel(V,2));
3267 359 : return V;
3268 : }
3269 :
3270 : static GEN
3271 315 : ZXQX_composedsum(GEN A, GEN B, GEN T, ulong bound)
3272 : {
3273 315 : pari_sp av = avma;
3274 : forprime_t S;
3275 : GEN H, worker, mod;
3276 315 : GEN lead = mulii(Q_content(leading_coeff(A)), Q_content(leading_coeff(B)));
3277 315 : worker = snm_closure(is_entry("_ZXQX_composedsum_worker")
3278 : , mkvec3(A,B,T));
3279 315 : init_modular_big(&S);
3280 315 : H = gen_crt("ZXQX_composedsum", worker, &S, lead, bound, 0, &mod,
3281 : nmV_chinese_center, FpM_center);
3282 315 : if (DEBUGLEVEL > 4)
3283 0 : err_printf("nfcompositum: a priori bound: %lu, a posteriori: %lu\n",
3284 : bound, expi(gsupnorm(H, DEFAULTPREC)));
3285 315 : return gc_GEN(av, RgM_to_RgXX(H, varn(A), varn(T)));
3286 : }
3287 :
3288 : static long
3289 315 : ZXQX_composedsum_bound(GEN nf, GEN A, GEN B)
3290 315 : { return ZXQX_resultant_bound_i(nf, A, B, &RgX_RgXY_ResBound_1); }
3291 :
3292 : GEN
3293 315 : nf_direct_compositum(GEN nf, GEN A, GEN B)
3294 : {
3295 315 : ulong bnd = ZXQX_composedsum_bound(nf, A, B);
3296 315 : return ZXQX_composedsum(A, B, nf_get_pol(nf), bnd);
3297 : }
3298 :
3299 : /************************************************************************
3300 : * *
3301 : * IRREDUCIBLE POLYNOMIAL / Fp *
3302 : * *
3303 : ************************************************************************/
3304 :
3305 : /* irreducible (unitary) polynomial of degree n over Fp */
3306 : GEN
3307 0 : ffinit_rand(GEN p,long n)
3308 : {
3309 0 : for(;;) {
3310 0 : pari_sp av = avma;
3311 0 : GEN pol = ZX_add(pol_xn(n, 0), random_FpX(n-1,0, p));
3312 0 : if (FpX_is_irred(pol, p)) return pol;
3313 0 : set_avma(av);
3314 : }
3315 : }
3316 :
3317 : /* return an extension of degree 2^l of F_2, assume l > 0
3318 : * Not stack clean. */
3319 : static GEN
3320 608 : ffinit_Artin_Schreier_2(long l)
3321 : {
3322 : GEN Q, T, S;
3323 : long i, v;
3324 :
3325 608 : if (l == 1) return mkvecsmall4(0,1,1,1); /*x^2 + x + 1*/
3326 559 : v = fetch_var_higher();
3327 559 : S = mkvecsmall5(0, 0, 0, 1, 1); /* y(y^2 + y) */
3328 559 : Q = mkpoln(3, pol1_Flx(0), pol1_Flx(0), S); /* x^2 + x + y(y^2+y) */
3329 559 : setvarn(Q, v);
3330 :
3331 : /* x^4+x+1, irred over F_2, minimal polynomial of a root of Q */
3332 559 : T = mkvecsmalln(6,evalvarn(v),1UL,1UL,0UL,0UL,1UL);
3333 : /* Q = x^2 + x + a(y) irred. over K = F2[y] / (T(y))
3334 : * ==> x^2 + x + a(y) b irred. over K for any root b of Q
3335 : * ==> x^2 + x + (b^2+b)b */
3336 3091 : for (i=2; i<l; i++) T = Flx_FlxY_resultant(T, Q, 2); /* minpoly(b) / F2*/
3337 560 : (void)delete_var(); T[1] = 0; return T;
3338 : }
3339 :
3340 : /* return an extension of degree p^l of F_p, assume l > 0
3341 : * Not stack clean. */
3342 : GEN
3343 965 : ffinit_Artin_Schreier(ulong p, long l)
3344 : {
3345 : long i, v;
3346 : GEN Q, R, S, T, xp;
3347 965 : if (p==2) return ffinit_Artin_Schreier_2(l);
3348 357 : xp = polxn_Flx(p,0); /* x^p */
3349 357 : T = Flx_sub(xp, mkvecsmall3(0,1,1),p); /* x^p - x - 1 */
3350 357 : if (l == 1) return T;
3351 :
3352 7 : v = evalvarn(fetch_var_higher());
3353 7 : xp[1] = v;
3354 7 : R = Flx_sub(polxn_Flx(2*p-1,0), polxn_Flx(p,0),p);
3355 7 : S = Flx_sub(xp, polx_Flx(0), p);
3356 7 : Q = FlxX_Flx_sub(Flx_to_FlxX(S, v), R, p); /* x^p - x - (y^(2p-1)-y^p) */
3357 14 : for (i = 2; i <= l; ++i) T = Flx_FlxY_resultant(T, Q, p);
3358 7 : (void)delete_var(); T[1] = 0; return T;
3359 : }
3360 :
3361 : static long
3362 149719 : flinit_check(ulong p, long n, long l)
3363 : {
3364 : ulong q;
3365 149719 : if (!uisprime(n)) return 0;
3366 102496 : q = p % n; if (!q) return 0;
3367 99885 : return ugcd((n-1)/Fl_order(q, n-1, n), l) == 1;
3368 : }
3369 :
3370 : static GEN
3371 31944 : flinit(ulong p, long l)
3372 : {
3373 31944 : ulong n = 1+l;
3374 96782 : while (!flinit_check(p,n,l)) n += l;
3375 31944 : if (DEBUGLEVEL>=4) err_printf("FFInit: using polsubcyclo(%ld, %ld)\n",n,l);
3376 31944 : return ZX_to_Flx(polsubcyclo(n,l,0), p);
3377 : }
3378 :
3379 : static GEN
3380 28999 : ffinit_fact_Flx(ulong p, long n)
3381 : {
3382 28999 : GEN P, F = factoru_pow(n), Fp = gel(F,1), Fe = gel(F,2), Fm = gel(F,3);
3383 28999 : long i, l = lg(Fm);
3384 28999 : P = cgetg(l, t_VEC);
3385 61909 : for (i = 1; i < l; i++)
3386 32909 : gel(P,i) = p==uel(Fp,i) ? ffinit_Artin_Schreier(p, Fe[i])
3387 32909 : : flinit(p, uel(Fm,i));
3388 29000 : return FlxV_composedsum(P, p);
3389 : }
3390 :
3391 : static GEN
3392 52944 : init_Flxq_i(ulong p, long n, long sv)
3393 : {
3394 : GEN P;
3395 52944 : if (!odd(p) && p != 2) pari_err_PRIME("ffinit", utoi(p));
3396 52937 : if (n == 1) return polx_Flx(sv);
3397 52937 : if (flinit_check(p, n+1, n))
3398 : {
3399 23938 : P = const_vecsmall(n+2,1);
3400 23938 : P[1] = sv; return P;
3401 : }
3402 28999 : P = ffinit_fact_Flx(p,n);
3403 29000 : P[1] = sv; return P;
3404 : }
3405 :
3406 : GEN
3407 0 : init_Flxq(ulong p, long n, long v)
3408 : {
3409 0 : pari_sp av = avma;
3410 0 : return gc_upto(av, init_Flxq_i(p, n, v));
3411 : }
3412 :
3413 : /* check if polsubcyclo(n,l,0) is irreducible modulo p */
3414 : static long
3415 8207 : fpinit_check(GEN p, long n, long l)
3416 : {
3417 : ulong q;
3418 8207 : if (!uisprime(n)) return 0;
3419 4842 : q = umodiu(p,n); if (!q) return 0;
3420 4842 : return ugcd((n-1)/Fl_order(q, n-1, n), l) == 1;
3421 : }
3422 :
3423 : /* let k=2 if p%4==1, and k=4 else and assume k*p does not divide l.
3424 : * Return an irreducible polynomial of degree l over F_p.
3425 : * Variant of Adleman and Lenstra "Finding irreducible polynomials over
3426 : * finite fields", ACM, 1986 (5) 350--355.
3427 : * Not stack clean */
3428 : static GEN
3429 1828 : fpinit(GEN p, long l)
3430 : {
3431 1828 : ulong n = 1+l;
3432 6168 : while (!fpinit_check(p,n,l)) n += l;
3433 1828 : if (DEBUGLEVEL>=4) err_printf("FFInit: using polsubcyclo(%ld, %ld)\n",n,l);
3434 1828 : return FpX_red(polsubcyclo(n,l,0),p);
3435 : }
3436 :
3437 : static GEN
3438 1637 : ffinit_fact(GEN p, long n)
3439 : {
3440 1637 : GEN P, F = factoru_pow(n), Fp = gel(F,1), Fe = gel(F,2), Fm = gel(F,3);
3441 1637 : long i, l = lg(Fm);
3442 1637 : P = cgetg(l, t_VEC);
3443 3465 : for (i = 1; i < l; ++i)
3444 3656 : gel(P,i) = absequaliu(p, Fp[i]) ?
3445 0 : Flx_to_ZX(ffinit_Artin_Schreier(Fp[i], Fe[i]))
3446 1828 : : fpinit(p, Fm[i]);
3447 1637 : return FpXV_composedsum(P, p);
3448 : }
3449 :
3450 : static GEN
3451 55249 : init_Fq_i(GEN p, long n, long v)
3452 : {
3453 : GEN P;
3454 55249 : if (n <= 0) pari_err_DOMAIN("ffinit", "degree", "<=", gen_0, stoi(n));
3455 55249 : if (typ(p) != t_INT) pari_err_TYPE("ffinit",p);
3456 55249 : if (cmpiu(p, 2) < 0) pari_err_PRIME("ffinit",p);
3457 55242 : if (v < 0) v = 0;
3458 55242 : if (n == 1) return pol_x(v);
3459 54990 : if (lgefint(p) == 3)
3460 52944 : return Flx_to_ZX(init_Flxq_i(p[2], n, evalvarn(v)));
3461 2046 : if (!mpodd(p)) pari_err_PRIME("ffinit", p);
3462 2039 : if (fpinit_check(p, n+1, n)) return polcyclo(n+1, v);
3463 1637 : P = ffinit_fact(p,n);
3464 1637 : setvarn(P, v); return P;
3465 : }
3466 : GEN
3467 54682 : init_Fq(GEN p, long n, long v)
3468 : {
3469 54682 : pari_sp av = avma;
3470 54682 : return gc_upto(av, init_Fq_i(p, n, v));
3471 : }
3472 : GEN
3473 567 : ffinit(GEN p, long n, long v)
3474 : {
3475 567 : pari_sp av = avma;
3476 567 : return gc_upto(av, FpX_to_mod(init_Fq_i(p, n, v), p));
3477 : }
3478 :
3479 : GEN
3480 3178 : ffnbirred(GEN p, long n)
3481 : {
3482 3178 : pari_sp av = avma;
3483 3178 : GEN s = powiu(p,n), F = factoru(n), D = divisorsu_moebius(gel(F, 1));
3484 3178 : long j, l = lg(D);
3485 6797 : for (j = 2; j < l; j++) /* skip d = 1 */
3486 : {
3487 3619 : long md = D[j]; /* mu(d) * d, d squarefree */
3488 3619 : GEN pd = powiu(p, n / labs(md)); /* p^{n/d} */
3489 3619 : s = md > 0? addii(s, pd): subii(s,pd);
3490 : }
3491 3178 : return gc_INT(av, diviuexact(s, n));
3492 : }
3493 :
3494 : GEN
3495 616 : ffsumnbirred(GEN p, long n)
3496 : {
3497 616 : pari_sp av = avma, av2;
3498 616 : GEN q, t = p, v = vecfactoru_i(1, n);
3499 : long i;
3500 616 : q = cgetg(n+1,t_VEC); gel(q,1) = p;
3501 1764 : for (i=2; i<=n; i++) gel(q,i) = mulii(gel(q,i-1), p);
3502 616 : av2 = avma;
3503 1764 : for (i=2; i<=n; i++)
3504 : {
3505 1148 : GEN s = gel(q,i), F = gel(v,i), D = divisorsu_moebius(gel(F,1));
3506 1148 : long j, l = lg(D);
3507 2534 : for (j = 2; j < l; j++) /* skip 1 */
3508 : {
3509 1386 : long md = D[j];
3510 1386 : GEN pd = gel(q, i / labs(md)); /* p^{i/d} */
3511 1386 : s = md > 0? addii(s, pd): subii(s, pd);
3512 : }
3513 1148 : t = gc_INT(av2, addii(t, diviuexact(s, i)));
3514 : }
3515 616 : return gc_INT(av, t);
3516 : }
3517 :
3518 : GEN
3519 140 : ffnbirred0(GEN p, long n, long flag)
3520 : {
3521 140 : if (typ(p) != t_INT) pari_err_TYPE("ffnbirred", p);
3522 140 : if (n <= 0) pari_err_DOMAIN("ffnbirred", "degree", "<=", gen_0, stoi(n));
3523 140 : switch(flag)
3524 : {
3525 70 : case 0: return ffnbirred(p, n);
3526 70 : case 1: return ffsumnbirred(p, n);
3527 : }
3528 0 : pari_err_FLAG("ffnbirred");
3529 : return NULL; /* LCOV_EXCL_LINE */
3530 : }
3531 :
3532 : static void
3533 2261 : checkmap(GEN m, const char *s)
3534 : {
3535 2261 : if (typ(m)!=t_VEC || lg(m)!=3 || typ(gel(m,1))!=t_FFELT)
3536 0 : pari_err_TYPE(s,m);
3537 2261 : }
3538 :
3539 : GEN
3540 189 : ffembed(GEN a, GEN b)
3541 : {
3542 189 : pari_sp av = avma;
3543 189 : GEN p, Ta, Tb, g, r = NULL;
3544 189 : if (typ(a)!=t_FFELT) pari_err_TYPE("ffembed",a);
3545 189 : if (typ(b)!=t_FFELT) pari_err_TYPE("ffembed",b);
3546 189 : p = FF_p_i(a); g = FF_gen(a);
3547 189 : if (!equalii(p, FF_p_i(b))) pari_err_MODULUS("ffembed",a,b);
3548 189 : Ta = FF_mod(a);
3549 189 : Tb = FF_mod(b);
3550 189 : if (degpol(Tb)%degpol(Ta)!=0)
3551 7 : pari_err_DOMAIN("ffembed",GENtostr_raw(a),"is not a subfield of",b,a);
3552 182 : r = gel(FFX_roots(Ta, b), 1);
3553 182 : return gc_GEN(av, mkvec2(g,r));
3554 : }
3555 :
3556 : GEN
3557 91 : ffextend(GEN a, GEN P, long v)
3558 : {
3559 91 : pari_sp av = avma;
3560 : long n;
3561 : GEN p, T, R, g, m;
3562 91 : if (typ(a)!=t_FFELT) pari_err_TYPE("ffextend",a);
3563 91 : T = a; p = FF_p_i(a);
3564 91 : if (typ(P)!=t_POL || !RgX_is_FpXQX(P,&T,&p)) pari_err_TYPE("ffextend", P);
3565 49 : if (!FF_samefield(a, T)) pari_err_MODULUS("ffextend",a,T);
3566 49 : if (v < 0) v = varn(P);
3567 49 : n = FF_f(T) * degpol(P); R = ffinit(p, n, v); g = ffgen(R, v);
3568 49 : m = ffembed(a, g);
3569 49 : R = FFX_roots(ffmap(m, P),g);
3570 49 : return gc_GEN(av, mkvec2(gel(R,1), m));
3571 : }
3572 :
3573 : GEN
3574 42 : fffrobenius(GEN a, long n)
3575 : {
3576 42 : if (typ(a)!=t_FFELT) pari_err_TYPE("fffrobenius",a);
3577 42 : retmkvec2(FF_gen(a), FF_Frobenius(a, n));
3578 : }
3579 :
3580 : GEN
3581 133 : ffinvmap(GEN m)
3582 : {
3583 133 : pari_sp av = avma;
3584 : long i, l;
3585 133 : GEN T, F, a, g, r, f = NULL;
3586 133 : checkmap(m, "ffinvmap");
3587 133 : a = gel(m,1); r = gel(m,2);
3588 133 : if (typ(r) != t_FFELT)
3589 7 : pari_err_TYPE("ffinvmap", m);
3590 126 : g = FF_gen(a);
3591 126 : T = FF_mod(r);
3592 126 : F = gel(FFX_factor(T, a), 1);
3593 126 : l = lg(F);
3594 490 : for(i=1; i<l; i++)
3595 : {
3596 490 : GEN s = FFX_rem(FF_to_FpXQ_i(r), gel(F, i), a);
3597 490 : if (degpol(s)==0 && gequal(constant_coeff(s),g)) { f = gel(F, i); break; }
3598 : }
3599 126 : if (f==NULL) pari_err_TYPE("ffinvmap", m);
3600 126 : if (degpol(f)==1) f = FF_neg_i(gel(f,2));
3601 126 : return gc_GEN(av, mkvec2(FF_gen(r),f));
3602 : }
3603 :
3604 : static GEN
3605 1260 : ffpartmapimage(const char *s, GEN r)
3606 : {
3607 1260 : GEN a = NULL, p = NULL;
3608 1260 : if (typ(r)==t_POL && degpol(r) >= 1
3609 1260 : && RgX_is_FpXQX(r,&a,&p) && a && typ(a)==t_FFELT) return a;
3610 0 : pari_err_TYPE(s, r);
3611 : return NULL; /* LCOV_EXCL_LINE */
3612 : }
3613 :
3614 : static GEN
3615 2709 : ffeltmap_i(GEN m, GEN x)
3616 : {
3617 2709 : GEN r = gel(m,2);
3618 2709 : if (!FF_samefield(x, gel(m,1)))
3619 84 : pari_err_DOMAIN("ffmap","m","domain does not contain", x, r);
3620 2625 : if (typ(r)==t_FFELT)
3621 1659 : return FF_map(r, x);
3622 : else
3623 966 : return FFX_preimage(x, r, ffpartmapimage("ffmap", r));
3624 : }
3625 :
3626 : static GEN
3627 4459 : ffmap_i(GEN m, GEN x)
3628 : {
3629 : GEN y;
3630 4459 : long i, lx, tx = typ(x);
3631 4459 : switch(tx)
3632 : {
3633 2541 : case t_FFELT:
3634 2541 : return ffeltmap_i(m, x);
3635 1267 : case t_POL: case t_RFRAC: case t_SER:
3636 : case t_VEC: case t_COL: case t_MAT:
3637 1267 : y = cgetg_copy(x, &lx);
3638 1988 : for (i = 1; i < lontyp[tx]; i++) y[i] = x[i];
3639 4564 : for (; i < lx; i++)
3640 : {
3641 3339 : GEN yi = ffmap_i(m, gel(x,i));
3642 3297 : if (!yi) return NULL;
3643 3297 : gel(y,i) = yi;
3644 : }
3645 1225 : return y;
3646 : }
3647 651 : return gcopy(x);
3648 : }
3649 :
3650 : GEN
3651 1036 : ffmap(GEN m, GEN x)
3652 : {
3653 1036 : pari_sp ltop = avma;
3654 : GEN y;
3655 1036 : checkmap(m, "ffmap");
3656 1036 : y = ffmap_i(m, x);
3657 1036 : if (y) return y;
3658 42 : retgc_const(ltop, cgetg(1, t_VEC));
3659 : }
3660 :
3661 : static GEN
3662 252 : ffeltmaprel_i(GEN m, GEN x)
3663 : {
3664 252 : GEN g = gel(m,1), r = gel(m,2);
3665 252 : if (!FF_samefield(x, g))
3666 0 : pari_err_DOMAIN("ffmap","m","domain does not contain", x, r);
3667 252 : if (typ(r)==t_FFELT)
3668 84 : retmkpolmod(FF_map(r, x), pol_x(FF_var(g)));
3669 : else
3670 168 : retmkpolmod(FFX_preimagerel(x, r, ffpartmapimage("ffmap", r)), gcopy(r));
3671 : }
3672 :
3673 : static GEN
3674 252 : ffmaprel_i(GEN m, GEN x)
3675 : {
3676 252 : switch(typ(x))
3677 : {
3678 252 : case t_FFELT:
3679 252 : return ffeltmaprel_i(m, x);
3680 0 : case t_POL: pari_APPLY_pol_normalized(ffmaprel_i(m, gel(x,i)));
3681 0 : case t_SER: pari_APPLY_ser_normalized(ffmaprel_i(m, gel(x,i)));
3682 0 : case t_RFRAC: case t_VEC: case t_COL: case t_MAT:
3683 0 : pari_APPLY_same(ffmaprel_i(m, gel(x,i)));
3684 : }
3685 0 : return gcopy(x);
3686 : }
3687 : GEN
3688 252 : ffmaprel(GEN m, GEN x) { checkmap(m, "ffmaprel"); return ffmaprel_i(m, x); }
3689 :
3690 : static void
3691 84 : err_compo(GEN m, GEN n)
3692 84 : { pari_err_DOMAIN("ffcompomap","m","domain does not contain codomain of",n,m); }
3693 :
3694 : GEN
3695 420 : ffcompomap(GEN m, GEN n)
3696 : {
3697 420 : pari_sp av = avma;
3698 420 : GEN g = gel(n,1), r, m2, n2;
3699 420 : checkmap(m, "ffcompomap");
3700 420 : checkmap(n, "ffcompomap");
3701 420 : m2 = gel(m,2); n2 = gel(n,2);
3702 420 : switch((typ(m2)==t_POL)|((typ(n2)==t_POL)<<1))
3703 : {
3704 84 : case 0:
3705 84 : if (!FF_samefield(gel(m,1),n2)) err_compo(m,n);
3706 42 : r = FF_map(gel(m,2), n2);
3707 42 : break;
3708 84 : case 2:
3709 84 : r = ffmap_i(m, n2);
3710 42 : if (lg(r) == 1) err_compo(m,n);
3711 42 : break;
3712 168 : case 1:
3713 168 : r = ffeltmap_i(m, n2);
3714 126 : if (!r)
3715 : {
3716 : GEN a, A, R, M;
3717 : long dm, dn;
3718 42 : a = ffpartmapimage("ffcompomap",m2);
3719 42 : A = FF_to_FpXQ_i(FF_neg(n2));
3720 42 : setvarn(A, 1);
3721 42 : R = deg1pol(gen_1, A, 0);
3722 42 : setvarn(R, 0);
3723 42 : M = gcopy(m2);
3724 42 : setvarn(M, 1);
3725 42 : r = polresultant0(R, M, 1, 0);
3726 42 : dm = FF_f(gel(m,1)); dn = FF_f(gel(n,1));
3727 42 : if (dm % dn || !FFX_ispower(r, dm/dn, a, &r)) err_compo(m,n);
3728 42 : setvarn(r, varn(FF_mod(g)));
3729 : }
3730 126 : break;
3731 84 : case 3:
3732 : {
3733 : GEN M, R, T, p, a;
3734 84 : a = ffpartmapimage("ffcompomap",n2);
3735 84 : if (!FF_samefield(a, gel(m,1))) err_compo(m,n);
3736 42 : p = FF_p_i(gel(n,1));
3737 42 : T = FF_mod(gel(n,1));
3738 42 : setvarn(T, 1);
3739 42 : R = RgX_to_FpXQX(n2,T,p);
3740 42 : setvarn(R, 0);
3741 42 : M = gcopy(m2);
3742 42 : setvarn(M, 1);
3743 42 : r = polresultant0(R, M, 1, 0);
3744 42 : setvarn(r, varn(n2));
3745 : }
3746 : }
3747 252 : return gc_GEN(av, mkvec2(g,r));
3748 : }
|