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