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