Line data Source code
1 : /* Copyright (C) 2004 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. It is distributed in the hope that it will be useful, but WITHOUT
8 : ANY WARRANTY WHATSOEVER.
9 :
10 : Check the License for details. You should have received a copy of it, along
11 : with the package; see the file 'COPYING'. If not, write to the Free Software
12 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
13 :
14 : #include "pari.h"
15 : #include "paripriv.h"
16 :
17 : /* Not so fast arithmetic with polynomials with small coefficients. */
18 :
19 : static GEN
20 563466064 : get_Flx_red(GEN T, GEN *B)
21 : {
22 563466064 : if (typ(T)!=t_VEC) { *B=NULL; return T; }
23 3792370 : *B = gel(T,1); return gel(T,2);
24 : }
25 :
26 : /***********************************************************************/
27 : /** **/
28 : /** Flx **/
29 : /** **/
30 : /***********************************************************************/
31 : /* Flx objects are defined as follows:
32 : Let l an ulong. An Flx is a t_VECSMALL:
33 : x[0] = codeword
34 : x[1] = evalvarn(variable number) (signe is not stored).
35 : x[2] = a_0 x[3] = a_1, etc.
36 : With 0 <= a_i < l
37 :
38 : signe(x) is not valid. Use degpol(x)>=0 instead.
39 : */
40 : /***********************************************************************/
41 : /** **/
42 : /** Conversion from Flx **/
43 : /** **/
44 : /***********************************************************************/
45 :
46 : GEN
47 43159499 : Flx_to_ZX(GEN z)
48 : {
49 43159499 : long i, l = lg(z);
50 43159499 : GEN x = cgetg(l,t_POL);
51 43159616 : for (i=2; i<l; i++) gel(x,i) = utoi(z[i]);
52 43159534 : x[1] = evalsigne(l-2!=0)| z[1]; return x;
53 : }
54 :
55 : GEN
56 26404 : Flx_to_FlxX(GEN z, long sv)
57 : {
58 26404 : long i, l = lg(z);
59 26404 : GEN x = cgetg(l,t_POL);
60 26404 : for (i=2; i<l; i++) gel(x,i) = Fl_to_Flx(z[i], sv);
61 26404 : x[1] = evalsigne(l-2!=0)| z[1]; return x;
62 : }
63 :
64 : GEN
65 128169 : Flv_to_ZV(GEN x)
66 128169 : { pari_APPLY_type(t_VEC, utoi(x[i])) }
67 :
68 : GEN
69 19340384 : Flc_to_ZC(GEN x)
70 19340384 : { pari_APPLY_type(t_COL, utoi(x[i])) }
71 :
72 : GEN
73 8271900 : Flm_to_ZM(GEN x)
74 8271900 : { pari_APPLY_type(t_MAT, Flc_to_ZC(gel(x,i))) }
75 :
76 : GEN
77 123364 : Flc_to_ZC_inplace(GEN z)
78 : {
79 123364 : long i, l = lg(z);
80 123364 : for (i=1; i<l; i++) gel(z,i) = utoi(z[i]);
81 123364 : settyp(z, t_COL);
82 123364 : return z;
83 : }
84 :
85 : GEN
86 56166 : Flm_to_ZM_inplace(GEN z)
87 : {
88 56166 : long i, l = lg(z);
89 56166 : for (i=1; i<l; i++) Flc_to_ZC_inplace(gel(z, i));
90 56166 : return z;
91 : }
92 :
93 : /* same as Flx_to_ZX, in place */
94 : GEN
95 43713651 : Flx_to_ZX_inplace(GEN z)
96 : {
97 43713651 : long i, l = lg(z);
98 43713651 : for (i=2; i<l; i++) gel(z,i) = utoi(z[i]);
99 43713580 : settyp(z, t_POL); z[1]=evalsigne(l-2!=0)|z[1]; return z;
100 : }
101 :
102 : /*Flx_to_Flv=zx_to_zv*/
103 : GEN
104 3556584 : Flx_to_Flv(GEN x, long N)
105 : {
106 : long i, l;
107 3556584 : GEN z = cgetg(N+1,t_VECSMALL);
108 3556566 : if (typ(x) != t_VECSMALL) pari_err_TYPE("Flx_to_Flv",x);
109 3556597 : l = lg(x)-1; x++;
110 3556597 : for (i=1; i<l ; i++) z[i]=x[i];
111 3556597 : for ( ; i<=N; i++) z[i]=0;
112 3556597 : return z;
113 : }
114 :
115 : /*Flv_to_Flx=zv_to_zx*/
116 : GEN
117 136313 : Flv_to_Flx(GEN x, long sv)
118 : {
119 136313 : long i, l=lg(x)+1;
120 136313 : GEN z = cgetg(l,t_VECSMALL); z[1]=sv;
121 136307 : x--;
122 136307 : for (i=2; i<l ; i++) z[i]=x[i];
123 136307 : return Flx_renormalize(z,l);
124 : }
125 :
126 : /*Flm_to_FlxV=zm_to_zxV*/
127 : GEN
128 1288 : Flm_to_FlxV(GEN x, long sv)
129 1288 : { pari_APPLY_type(t_VEC, Flv_to_Flx(gel(x,i), sv)) }
130 :
131 : /*FlxC_to_ZXC=zxC_to_ZXC*/
132 : GEN
133 40481 : FlxC_to_ZXC(GEN x)
134 40481 : { pari_APPLY_type(t_COL, Flx_to_ZX(gel(x,i))) }
135 :
136 : /*FlxC_to_ZXC=zxV_to_ZXV*/
137 : GEN
138 161353 : FlxV_to_ZXV(GEN x)
139 161353 : { pari_APPLY_type(t_VEC, Flx_to_ZX(gel(x,i))) }
140 :
141 : /*FlxM_to_ZXM=zxM_to_ZXM*/
142 : GEN
143 4403 : FlxM_to_ZXM(GEN x)
144 4403 : { pari_APPLY_same(FlxC_to_ZXC(gel(x,i))) }
145 :
146 : GEN
147 0 : FlxM_Flx_add_shallow(GEN x, GEN y, ulong p)
148 : {
149 0 : long l = lg(x), i, j;
150 0 : GEN z = cgetg(l,t_MAT);
151 :
152 0 : if (l==1) return z;
153 0 : if (l != lgcols(x)) pari_err_OP( "+", x, y);
154 0 : for (i=1; i<l; i++)
155 : {
156 0 : GEN zi = cgetg(l,t_COL), xi = gel(x,i);
157 0 : gel(z,i) = zi;
158 0 : for (j=1; j<l; j++) gel(zi,j) = gel(xi,j);
159 0 : gel(zi,i) = Flx_add(gel(zi,i), y, p);
160 : }
161 0 : return z;
162 : }
163 :
164 : /***********************************************************************/
165 : /** **/
166 : /** Conversion to Flx **/
167 : /** **/
168 : /***********************************************************************/
169 : /* Take an integer and return a scalar polynomial mod p, with evalvarn=vs */
170 : GEN
171 9675544 : Fl_to_Flx(ulong x, long sv)
172 : {
173 9675544 : return x? mkvecsmall2(sv, x): pol0_Flx(sv);
174 : }
175 :
176 : /* a X^d */
177 : GEN
178 183034 : monomial_Flx(ulong a, long d, long vs)
179 : {
180 : GEN P;
181 183034 : if (a==0) return pol0_Flx(vs);
182 183034 : P = const_vecsmall(d+2, 0);
183 183034 : P[1] = vs; P[d+2] = a;
184 183034 : return P;
185 : }
186 :
187 : GEN
188 1070456 : Z_to_Flx(GEN x, ulong p, long sv)
189 : {
190 1070456 : long u = umodiu(x,p);
191 1070997 : return u? mkvecsmall2(sv, u): pol0_Flx(sv);
192 : }
193 :
194 : /* return x[0 .. dx] mod p as t_VECSMALL. Assume x a t_POL*/
195 : GEN
196 178467608 : ZX_to_Flx(GEN x, ulong p)
197 : {
198 178467608 : long i, lx = lg(x);
199 178467608 : GEN a = cgetg(lx, t_VECSMALL);
200 178473300 : a[1]=((ulong)x[1])&VARNBITS;
201 178473300 : for (i=2; i<lx; i++) a[i] = umodiu(gel(x,i), p);
202 178470218 : return Flx_renormalize(a,lx);
203 : }
204 :
205 : /* return x[0 .. dx] mod p as t_VECSMALL. Assume x a t_POL*/
206 : GEN
207 3699673 : zx_to_Flx(GEN x, ulong p)
208 : {
209 3699673 : long i, lx = lg(x);
210 3699673 : GEN a = cgetg(lx, t_VECSMALL);
211 3699673 : a[1] = x[1];
212 3699673 : for (i=2; i<lx; i++) uel(a,i) = umodsu(x[i], p);
213 3699673 : return Flx_renormalize(a,lx);
214 : }
215 :
216 : ulong
217 41211569 : Rg_to_Fl(GEN x, ulong p)
218 : {
219 41211569 : switch(typ(x))
220 : {
221 22081253 : case t_INT: return umodiu(x, p);
222 : case t_FRAC: {
223 32570 : ulong z = umodiu(gel(x,1), p);
224 32570 : if (!z) return 0;
225 29693 : return Fl_div(z, umodiu(gel(x,2), p), p);
226 : }
227 49 : case t_PADIC: return padic_to_Fl(x, p);
228 : case t_INTMOD: {
229 19097697 : GEN q = gel(x,1), a = gel(x,2);
230 19097697 : if (absequaliu(q, p)) return itou(a);
231 0 : if (!dvdiu(q,p)) pari_err_MODULUS("Rg_to_Fl", q, utoi(p));
232 0 : return umodiu(a, p);
233 : }
234 0 : default: pari_err_TYPE("Rg_to_Fl",x);
235 : return 0; /* LCOV_EXCL_LINE */
236 : }
237 : }
238 :
239 : ulong
240 1099237 : Rg_to_F2(GEN x)
241 : {
242 1099237 : switch(typ(x))
243 : {
244 256857 : case t_INT: return mpodd(x);
245 : case t_FRAC:
246 0 : if (!mpodd(gel(x,2))) (void)Fl_inv(0,2); /* error */
247 0 : return mpodd(gel(x,1));
248 : case t_PADIC:
249 0 : if (!absequaliu(gel(x,2),2)) pari_err_OP("",x, mkintmodu(1,2));
250 0 : if (valp(x) < 0) (void)Fl_inv(0,2);
251 0 : return valp(x) & 1;
252 : case t_INTMOD: {
253 842380 : GEN q = gel(x,1), a = gel(x,2);
254 842380 : if (mpodd(q)) pari_err_MODULUS("Rg_to_F2", q, gen_2);
255 842380 : return mpodd(a);
256 : }
257 0 : default: pari_err_TYPE("Rg_to_F2",x);
258 : return 0; /* LCOV_EXCL_LINE */
259 : }
260 : }
261 :
262 : GEN
263 1816250 : RgX_to_Flx(GEN x, ulong p)
264 : {
265 1816250 : long i, lx = lg(x);
266 1816250 : GEN a = cgetg(lx, t_VECSMALL);
267 1816250 : a[1]=((ulong)x[1])&VARNBITS;
268 1816250 : for (i=2; i<lx; i++) a[i] = Rg_to_Fl(gel(x,i), p);
269 1816250 : return Flx_renormalize(a,lx);
270 : }
271 :
272 : /* If x is a POLMOD, assume modulus is a multiple of T. */
273 : GEN
274 1803409 : Rg_to_Flxq(GEN x, GEN T, ulong p)
275 : {
276 1803409 : long ta, tx = typ(x), v = T[1];
277 : GEN a, b;
278 1803409 : if (is_const_t(tx))
279 : {
280 1739331 : if (tx == t_FFELT) return FF_to_Flxq(x);
281 1013163 : return Fl_to_Flx(Rg_to_Fl(x, p), v);
282 : }
283 64078 : switch(tx)
284 : {
285 : case t_POLMOD:
286 707 : b = gel(x,1);
287 707 : a = gel(x,2); ta = typ(a);
288 707 : if (is_const_t(ta)) return Fl_to_Flx(Rg_to_Fl(a, p), v);
289 609 : b = RgX_to_Flx(b, p); if (b[1] != v) break;
290 609 : a = RgX_to_Flx(a, p); if (Flx_equal(b,T)) return a;
291 0 : if (lgpol(Flx_rem(b,T,p))==0) return Flx_rem(a, T, p);
292 0 : break;
293 : case t_POL:
294 63371 : x = RgX_to_Flx(x,p);
295 63371 : if (x[1] != v) break;
296 63371 : return Flx_rem(x, T, p);
297 : case t_RFRAC:
298 0 : a = Rg_to_Flxq(gel(x,1), T,p);
299 0 : b = Rg_to_Flxq(gel(x,2), T,p);
300 0 : return Flxq_div(a,b, T,p);
301 : }
302 0 : pari_err_TYPE("Rg_to_Flxq",x);
303 : return NULL; /* LCOV_EXCL_LINE */
304 : }
305 :
306 : /***********************************************************************/
307 : /** **/
308 : /** Basic operation on Flx **/
309 : /** **/
310 : /***********************************************************************/
311 : /* = zx_renormalize. Similar to normalizepol, in place */
312 : GEN
313 1386972749 : Flx_renormalize(GEN /*in place*/ x, long lx)
314 : {
315 : long i;
316 1588977658 : for (i = lx-1; i>1; i--)
317 1541029702 : if (x[i]) break;
318 1386972749 : stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1));
319 1385575910 : setlg(x, i+1); return x;
320 : }
321 :
322 : GEN
323 385246 : Flx_red(GEN z, ulong p)
324 : {
325 385246 : long i, l = lg(z);
326 385246 : GEN x = cgetg(l, t_VECSMALL);
327 385348 : x[1] = z[1];
328 385348 : for (i=2; i<l; i++) x[i] = uel(z,i)%p;
329 385348 : return Flx_renormalize(x,l);
330 : }
331 :
332 : GEN
333 1083248 : random_Flx(long d1, long vs, ulong p)
334 : {
335 1083248 : long i, d = d1+2;
336 1083248 : GEN y = cgetg(d,t_VECSMALL); y[1] = vs;
337 1083248 : for (i=2; i<d; i++) y[i] = random_Fl(p);
338 1083248 : return Flx_renormalize(y,d);
339 : }
340 :
341 : static GEN
342 6837 : Flx_addspec(GEN x, GEN y, ulong p, long lx, long ly)
343 : {
344 : long i,lz;
345 : GEN z;
346 :
347 6837 : if (ly>lx) swapspec(x,y, lx,ly);
348 6837 : lz = lx+2; z = cgetg(lz, t_VECSMALL) + 2;
349 6837 : for (i=0; i<ly; i++) z[i] = Fl_add(x[i], y[i], p);
350 6837 : for ( ; i<lx; i++) z[i] = x[i];
351 6837 : z -= 2; return Flx_renormalize(z, lz);
352 : }
353 :
354 : GEN
355 51480348 : Flx_add(GEN x, GEN y, ulong p)
356 : {
357 : long i,lz;
358 : GEN z;
359 51480348 : long lx=lg(x);
360 51480348 : long ly=lg(y);
361 51480348 : if (ly>lx) swapspec(x,y, lx,ly);
362 51480348 : lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1];
363 51406590 : for (i=2; i<ly; i++) z[i] = Fl_add(x[i], y[i], p);
364 51485435 : for ( ; i<lx; i++) z[i] = x[i];
365 51485435 : return Flx_renormalize(z, lz);
366 : }
367 :
368 : GEN
369 7263510 : Flx_Fl_add(GEN y, ulong x, ulong p)
370 : {
371 : GEN z;
372 : long lz, i;
373 7263510 : if (!lgpol(y))
374 270405 : return Fl_to_Flx(x,y[1]);
375 6992857 : lz=lg(y);
376 6992857 : z=cgetg(lz,t_VECSMALL);
377 6990928 : z[1]=y[1];
378 6990928 : z[2] = Fl_add(y[2],x,p);
379 39112993 : for(i=3;i<lz;i++)
380 32120319 : z[i] = y[i];
381 6992674 : if (lz==3) z = Flx_renormalize(z,lz);
382 6992610 : return z;
383 : }
384 :
385 : static GEN
386 2072539 : Flx_subspec(GEN x, GEN y, ulong p, long lx, long ly)
387 : {
388 : long i,lz;
389 : GEN z;
390 :
391 2072539 : if (ly <= lx)
392 : {
393 2072539 : lz = lx+2; z = cgetg(lz, t_VECSMALL)+2;
394 2073879 : for (i=0; i<ly; i++) z[i] = Fl_sub(x[i],y[i],p);
395 2072559 : for ( ; i<lx; i++) z[i] = x[i];
396 : }
397 : else
398 : {
399 0 : lz = ly+2; z = cgetg(lz, t_VECSMALL)+2;
400 0 : for (i=0; i<lx; i++) z[i] = Fl_sub(x[i],y[i],p);
401 0 : for ( ; i<ly; i++) z[i] = Fl_neg(y[i],p);
402 : }
403 2072559 : return Flx_renormalize(z-2, lz);
404 : }
405 :
406 : GEN
407 70875073 : Flx_sub(GEN x, GEN y, ulong p)
408 : {
409 70875073 : long i,lz,lx = lg(x), ly = lg(y);
410 : GEN z;
411 :
412 70875073 : if (ly <= lx)
413 : {
414 38744420 : lz = lx; z = cgetg(lz, t_VECSMALL);
415 38747215 : for (i=2; i<ly; i++) z[i] = Fl_sub(x[i],y[i],p);
416 38744276 : for ( ; i<lx; i++) z[i] = x[i];
417 : }
418 : else
419 : {
420 32130653 : lz = ly; z = cgetg(lz, t_VECSMALL);
421 32130833 : for (i=2; i<lx; i++) z[i] = Fl_sub(x[i],y[i],p);
422 32130651 : for ( ; i<ly; i++) z[i] = y[i]? (long)(p - y[i]): y[i];
423 : }
424 70874927 : z[1]=x[1]; return Flx_renormalize(z, lz);
425 : }
426 :
427 : static GEN
428 1104613 : Flx_negspec(GEN x, ulong p, long l)
429 : {
430 : long i;
431 1104613 : GEN z = cgetg(l+2, t_VECSMALL) + 2;
432 1104527 : for (i=0; i<l; i++) z[i] = Fl_neg(x[i], p);
433 1104650 : return z-2;
434 : }
435 :
436 :
437 : GEN
438 1104615 : Flx_neg(GEN x, ulong p)
439 : {
440 1104615 : GEN z = Flx_negspec(x+2, p, lgpol(x));
441 1104658 : z[1] = x[1];
442 1104658 : return z;
443 : }
444 :
445 : GEN
446 1531 : Flx_neg_inplace(GEN x, ulong p)
447 : {
448 1531 : long i, l = lg(x);
449 360208 : for (i=2; i<l; i++)
450 358677 : if (x[i]) x[i] = p - x[i];
451 1531 : return x;
452 : }
453 :
454 : GEN
455 1876789 : Flx_double(GEN y, ulong p)
456 : {
457 : long i, l;
458 1876789 : GEN z = cgetg_copy(y, &l); z[1] = y[1];
459 1876789 : for(i=2; i<l; i++) z[i] = Fl_double(y[i], p);
460 1876789 : return Flx_renormalize(z, l);
461 : }
462 : GEN
463 672818 : Flx_triple(GEN y, ulong p)
464 : {
465 : long i, l;
466 672818 : GEN z = cgetg_copy(y, &l); z[1] = y[1];
467 672818 : for(i=2; i<l; i++) z[i] = Fl_triple(y[i], p);
468 672818 : return Flx_renormalize(z, l);
469 : }
470 : GEN
471 37311694 : Flx_Fl_mul(GEN y, ulong x, ulong p)
472 : {
473 : GEN z;
474 : long i, l;
475 37311694 : if (!x) return pol0_Flx(y[1]);
476 28085608 : z = cgetg_copy(y, &l); z[1] = y[1];
477 28085567 : if (HIGHWORD(x | p))
478 164737 : for(i=2; i<l; i++) z[i] = Fl_mul(y[i], x, p);
479 : else
480 27920830 : for(i=2; i<l; i++) z[i] = (y[i] * x) % p;
481 28085572 : return Flx_renormalize(z, l);
482 : }
483 : GEN
484 6556420 : Flx_Fl_mul_to_monic(GEN y, ulong x, ulong p)
485 : {
486 : GEN z;
487 : long i, l;
488 6556420 : z = cgetg_copy(y, &l); z[1] = y[1];
489 6555067 : if (HIGHWORD(x | p))
490 2008387 : for(i=2; i<l-1; i++) z[i] = Fl_mul(y[i], x, p);
491 : else
492 4546680 : for(i=2; i<l-1; i++) z[i] = (y[i] * x) % p;
493 6555082 : z[l-1] = 1; return z;
494 : }
495 :
496 : /* Return a*x^n if n>=0 and a\x^(-n) if n<0 */
497 : GEN
498 5190060 : Flx_shift(GEN a, long n)
499 : {
500 5190060 : long i, l = lg(a);
501 : GEN b;
502 5190060 : if (l==2 || !n) return Flx_copy(a);
503 5173832 : if (l+n<=2) return pol0_Flx(a[1]);
504 5172210 : b = cgetg(l+n, t_VECSMALL);
505 5172217 : b[1] = a[1];
506 5172217 : if (n < 0)
507 1548249 : for (i=2-n; i<l; i++) b[i+n] = a[i];
508 : else
509 : {
510 3623968 : for (i=0; i<n; i++) b[2+i] = 0;
511 3623968 : for (i=2; i<l; i++) b[i+n] = a[i];
512 : }
513 5172217 : return b;
514 : }
515 :
516 : GEN
517 37849884 : Flx_normalize(GEN z, ulong p)
518 : {
519 37849884 : long l = lg(z)-1;
520 37849884 : ulong p1 = z[l]; /* leading term */
521 37849884 : if (p1 == 1) return z;
522 6555431 : return Flx_Fl_mul_to_monic(z, Fl_inv(p1,p), p);
523 : }
524 :
525 : /* return (x * X^d) + y. Assume d > 0, x > 0 and y >= 0 */
526 : static GEN
527 3542 : Flx_addshift(GEN x, GEN y, ulong p, long d)
528 : {
529 3542 : GEN xd,yd,zd = (GEN)avma;
530 3542 : long a,lz,ny = lgpol(y), nx = lgpol(x);
531 3542 : long vs = x[1];
532 :
533 3542 : x += 2; y += 2; a = ny-d;
534 3542 : if (a <= 0)
535 : {
536 7 : lz = (a>nx)? ny+2: nx+d+2;
537 7 : (void)new_chunk(lz); xd = x+nx; yd = y+ny;
538 7 : while (xd > x) *--zd = *--xd;
539 7 : x = zd + a;
540 7 : while (zd > x) *--zd = 0;
541 : }
542 : else
543 : {
544 3535 : xd = new_chunk(d); yd = y+d;
545 3535 : x = Flx_addspec(x,yd,p, nx,a);
546 3535 : lz = (a>nx)? ny+2: lg(x)+d;
547 3535 : x += 2; while (xd > x) *--zd = *--xd;
548 : }
549 3542 : while (yd > y) *--zd = *--yd;
550 3542 : *--zd = vs;
551 3542 : *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;
552 : }
553 :
554 : /* shift polynomial + gerepile */
555 : /* Do not set evalvarn*/
556 : static GEN
557 415869830 : Flx_shiftip(pari_sp av, GEN x, long v)
558 : {
559 415869830 : long i, lx = lg(x), ly;
560 : GEN y;
561 415869830 : if (!v || lx==2) return gerepileuptoleaf(av, x);
562 97022730 : ly = lx + v; /* result length */
563 97022730 : (void)new_chunk(ly); /* check that result fits */
564 97165974 : x += lx; y = (GEN)av;
565 97165974 : for (i = 2; i<lx; i++) *--y = *--x;
566 97165974 : for (i = 0; i< v; i++) *--y = 0;
567 97165974 : y -= 2; y[0] = evaltyp(t_VECSMALL) | evallg(ly);
568 97071986 : avma = (pari_sp)y; return y;
569 : }
570 :
571 : #define BITS_IN_QUARTULONG (BITS_IN_HALFULONG >> 1)
572 : #define QUARTMASK ((1UL<<BITS_IN_QUARTULONG)-1UL)
573 : #define LLQUARTWORD(x) ((x) & QUARTMASK)
574 : #define HLQUARTWORD(x) (((x) >> BITS_IN_QUARTULONG) & QUARTMASK)
575 : #define LHQUARTWORD(x) (((x) >> (2*BITS_IN_QUARTULONG)) & QUARTMASK)
576 : #define HHQUARTWORD(x) (((x) >> (3*BITS_IN_QUARTULONG)) & QUARTMASK)
577 : INLINE long
578 456915376 : maxlengthcoeffpol(ulong p, long n)
579 : {
580 456915376 : pari_sp ltop = avma;
581 456915376 : GEN z = muliu(sqru(p-1), n);
582 456497530 : long l = lgefint(z);
583 456497530 : avma = ltop;
584 456497530 : if (l==3 && HIGHWORD(z[2])==0)
585 : {
586 145068133 : if (HLQUARTWORD(z[2]) == 0) return -1;
587 43915507 : else return 0;
588 : }
589 311429397 : return l-2;
590 : }
591 :
592 : INLINE ulong
593 666628762 : Flx_mullimb_ok(GEN x, GEN y, ulong p, long a, long b)
594 : { /* Assume OK_ULONG*/
595 666628762 : ulong p1 = 0;
596 : long i;
597 2075886420 : for (i=a; i<b; i++)
598 1409257658 : if (y[i])
599 : {
600 1310780581 : p1 += y[i] * x[-i];
601 1310780581 : if (p1 & HIGHBIT) p1 %= p;
602 : }
603 666628762 : return p1 % p;
604 : }
605 :
606 : INLINE ulong
607 679363308 : Flx_mullimb(GEN x, GEN y, ulong p, ulong pi, long a, long b)
608 : {
609 679363308 : ulong p1 = 0;
610 : long i;
611 2117455080 : for (i=a; i<b; i++)
612 1437853738 : if (y[i])
613 1424280960 : p1 = Fl_addmul_pre(p1, y[i], x[-i], p, pi);
614 679601342 : return p1;
615 : }
616 :
617 : /* assume nx >= ny > 0 */
618 : static GEN
619 174634014 : Flx_mulspec_basecase(GEN x, GEN y, ulong p, long nx, long ny)
620 : {
621 : long i,lz,nz;
622 : GEN z;
623 :
624 174634014 : lz = nx+ny+1; nz = lz-2;
625 174634014 : z = cgetg(lz, t_VECSMALL) + 2; /* x:y:z [i] = term of degree i */
626 174340495 : if (SMALL_ULONG(p))
627 : {
628 101204313 : for (i=0; i<ny; i++)z[i] = Flx_mullimb_ok(x+i,y,p,0,i+1);
629 101573196 : for ( ; i<nx; i++) z[i] = Flx_mullimb_ok(x+i,y,p,0,ny);
630 101609478 : for ( ; i<nz; i++) z[i] = Flx_mullimb_ok(x+i,y,p,i-nx+1,ny);
631 : }
632 : else
633 : {
634 73136182 : ulong pi = get_Fl_red(p);
635 73150907 : for (i=0; i<ny; i++)z[i] = Flx_mullimb(x+i,y,p,pi,0,i+1);
636 73186625 : for ( ; i<nx; i++) z[i] = Flx_mullimb(x+i,y,p,pi,0,ny);
637 73185397 : for ( ; i<nz; i++) z[i] = Flx_mullimb(x+i,y,p,pi,i-nx+1,ny);
638 : }
639 174779260 : z -= 2; return Flx_renormalize(z, lz);
640 : }
641 :
642 : static GEN
643 48157691 : int_to_Flx(GEN z, ulong p)
644 : {
645 48157691 : long i, l = lgefint(z);
646 48157691 : GEN x = cgetg(l, t_VECSMALL);
647 48250703 : for (i=2; i<l; i++) x[i] = uel(z,i)%p;
648 48250703 : return Flx_renormalize(x, l);
649 : }
650 :
651 : INLINE GEN
652 5916438 : Flx_mulspec_mulii(GEN a, GEN b, ulong p, long na, long nb)
653 : {
654 5916438 : GEN z=muliispec(a,b,na,nb);
655 5926938 : return int_to_Flx(z,p);
656 : }
657 :
658 : static GEN
659 30400726 : Flx_to_int_halfspec(GEN a, long na)
660 : {
661 : long j;
662 30400726 : long n = (na+1)>>1UL;
663 30400726 : GEN V = cgetipos(2+n);
664 : GEN w;
665 292120370 : for (w = int_LSW(V), j=0; j+1<na; j+=2, w=int_nextW(w))
666 261719707 : *w = a[j]|(a[j+1]<<BITS_IN_HALFULONG);
667 30400663 : if (j<na)
668 21675061 : *w = a[j];
669 30400663 : return V;
670 : }
671 :
672 : static GEN
673 21399387 : int_to_Flx_half(GEN z, ulong p)
674 : {
675 : long i;
676 21399387 : long lx = (lgefint(z)-2)*2+2;
677 21399387 : GEN w, x = cgetg(lx, t_VECSMALL);
678 331623145 : for (w = int_LSW(z), i=2; i<lx; i+=2, w=int_nextW(w))
679 : {
680 310223771 : x[i] = LOWWORD((ulong)*w)%p;
681 310223771 : x[i+1] = HIGHWORD((ulong)*w)%p;
682 : }
683 21399374 : return Flx_renormalize(x, lx);
684 : }
685 :
686 : static GEN
687 9023997 : Flx_mulspec_halfmulii(GEN a, GEN b, ulong p, long na, long nb)
688 : {
689 9023997 : GEN A = Flx_to_int_halfspec(a,na);
690 9024001 : GEN B = Flx_to_int_halfspec(b,nb);
691 9024001 : GEN z = mulii(A,B);
692 9024007 : return int_to_Flx_half(z,p);
693 : }
694 :
695 : static GEN
696 80074956 : Flx_to_int_quartspec(GEN a, long na)
697 : {
698 : long j;
699 80074956 : long n = (na+3)>>2UL;
700 80074956 : GEN V = cgetipos(2+n);
701 : GEN w;
702 267301122 : for (w = int_LSW(V), j=0; j+3<na; j+=4, w=int_nextW(w))
703 187227498 : *w = a[j]|(a[j+1]<<BITS_IN_QUARTULONG)|(a[j+2]<<(2*BITS_IN_QUARTULONG))|(a[j+3]<<(3*BITS_IN_QUARTULONG));
704 80073624 : switch (na-j)
705 : {
706 : case 3:
707 24701150 : *w = a[j]|(a[j+1]<<BITS_IN_QUARTULONG)|(a[j+2]<<(2*BITS_IN_QUARTULONG));
708 24701150 : break;
709 : case 2:
710 24301831 : *w = a[j]|(a[j+1]<<BITS_IN_QUARTULONG);
711 24301831 : break;
712 : case 1:
713 21175733 : *w = a[j];
714 21175733 : break;
715 : case 0:
716 9897943 : break;
717 : }
718 80073624 : return V;
719 : }
720 :
721 : static GEN
722 45269637 : int_to_Flx_quart(GEN z, ulong p)
723 : {
724 : long i;
725 45269637 : long lx = (lgefint(z)-2)*4+2;
726 45269637 : GEN w, x = cgetg(lx, t_VECSMALL);
727 294001113 : for (w = int_LSW(z), i=2; i<lx; i+=4, w=int_nextW(w))
728 : {
729 248730178 : x[i] = LLQUARTWORD((ulong)*w)%p;
730 248730178 : x[i+1] = HLQUARTWORD((ulong)*w)%p;
731 248730178 : x[i+2] = LHQUARTWORD((ulong)*w)%p;
732 248730178 : x[i+3] = HHQUARTWORD((ulong)*w)%p;
733 : }
734 45270935 : return Flx_renormalize(x, lx);
735 : }
736 :
737 : static GEN
738 34805867 : Flx_mulspec_quartmulii(GEN a, GEN b, ulong p, long na, long nb)
739 : {
740 34805867 : GEN A = Flx_to_int_quartspec(a,na);
741 34806833 : GEN B = Flx_to_int_quartspec(b,nb);
742 34805629 : GEN z = mulii(A,B);
743 34806431 : return int_to_Flx_quart(z,p);
744 : }
745 :
746 : /*Eval x in 2^(k*BIL) in linear time, k==2 or 3*/
747 : static GEN
748 39437831 : Flx_eval2BILspec(GEN x, long k, long l)
749 : {
750 39437831 : long i, lz = k*l, ki;
751 39437831 : GEN pz = cgetipos(2+lz);
752 827334501 : for (i=0; i < lz; i++)
753 787839473 : *int_W(pz,i) = 0UL;
754 433133373 : for (i=0, ki=0; i<l; i++, ki+=k)
755 393638345 : *int_W(pz,ki) = x[i];
756 39495028 : return int_normalize(pz,0);
757 : }
758 :
759 : static GEN
760 29227125 : Z_mod2BIL_Flx_2(GEN x, long d, ulong p)
761 : {
762 29227125 : long i, offset, lm = lgefint(x)-2, l = d+3;
763 29227125 : ulong pi = get_Fl_red(p);
764 29203517 : GEN pol = cgetg(l, t_VECSMALL);
765 28848877 : pol[1] = 0;
766 572969032 : for (i=0, offset=0; offset+1 < lm; i++, offset += 2)
767 543728121 : pol[i+2] = remll_pre(*int_W(x,offset+1), *int_W(x,offset), p, pi);
768 29240911 : if (offset < lm)
769 21141798 : pol[i+2] = (*int_W(x,offset)) % p;
770 29240911 : return Flx_renormalize(pol,l);
771 : }
772 :
773 : static GEN
774 11236 : Z_mod2BIL_Flx_3(GEN x, long d, ulong p)
775 : {
776 11236 : long i, offset, lm = lgefint(x)-2, l = d+3;
777 11236 : ulong pi = get_Fl_red(p);
778 11236 : GEN pol = cgetg(l, t_VECSMALL);
779 11244 : pol[1] = 0;
780 4304569 : for (i=0, offset=0; offset+2 < lm; i++, offset += 3)
781 8586666 : pol[i+2] = remlll_pre(*int_W(x,offset+2), *int_W(x,offset+1),
782 4293333 : *int_W(x,offset), p, pi);
783 11236 : if (offset+1 < lm)
784 9522 : pol[i+2] = remll_pre(*int_W(x,offset+1), *int_W(x,offset), p, pi);
785 1714 : else if (offset < lm)
786 1714 : pol[i+2] = (*int_W(x,offset)) % p;
787 11236 : return Flx_renormalize(pol,l);
788 : }
789 :
790 : static GEN
791 29251556 : Z_mod2BIL_Flx(GEN x, long bs, long d, ulong p)
792 : {
793 29251556 : return bs==2 ? Z_mod2BIL_Flx_2(x, d, p): Z_mod2BIL_Flx_3(x, d, p);
794 : }
795 :
796 : static GEN
797 10217330 : Flx_mulspec_mulii_inflate(GEN x, GEN y, long N, ulong p, long nx, long ny)
798 : {
799 10217330 : pari_sp av = avma;
800 10217330 : GEN z = mulii(Flx_eval2BILspec(x,N,nx), Flx_eval2BILspec(y,N,ny));
801 10223272 : return gerepileupto(av, Z_mod2BIL_Flx(z, N, nx+ny-2, p));
802 : }
803 :
804 : /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
805 : * b+2 were sent instead. na, nb = number of terms of a, b.
806 : * Only c, c0, c1, c2 are genuine GEN.
807 : */
808 : static GEN
809 252325078 : Flx_mulspec(GEN a, GEN b, ulong p, long na, long nb)
810 : {
811 : GEN a0,c,c0;
812 252325078 : long n0, n0a, i, v = 0;
813 : pari_sp av;
814 :
815 252325078 : while (na && !a[0]) { a++; na--; v++; }
816 252325078 : while (nb && !b[0]) { b++; nb--; v++; }
817 252325078 : if (na < nb) swapspec(a,b, na,nb);
818 252325078 : if (!nb) return pol0_Flx(0);
819 :
820 234680204 : av = avma;
821 234680204 : switch (maxlengthcoeffpol(p,nb))
822 : {
823 : case -1:
824 67127006 : if (na>=Flx_MUL_QUARTMULII_LIMIT)
825 34805443 : return Flx_shiftip(av,Flx_mulspec_quartmulii(a,b,p,na,nb), v);
826 32321563 : break;
827 : case 0:
828 19320208 : if (na>=Flx_MUL_HALFMULII_LIMIT)
829 9023995 : return Flx_shiftip(av,Flx_mulspec_halfmulii(a,b,p,na,nb), v);
830 10296213 : break;
831 : case 1:
832 66746994 : if (na>=Flx_MUL_MULII_LIMIT)
833 5916353 : return Flx_shiftip(av,Flx_mulspec_mulii(a,b,p,na,nb), v);
834 60830641 : break;
835 : case 2:
836 78842169 : if (na>=Flx_MUL_MULII2_LIMIT)
837 10209199 : return Flx_shiftip(av,Flx_mulspec_mulii_inflate(a,b,2,p,na,nb), v);
838 68632970 : break;
839 : case 3:
840 2587522 : if (na>70)
841 9013 : return Flx_shiftip(av,Flx_mulspec_mulii_inflate(a,b,3,p,na,nb), v);
842 2578509 : break;
843 : }
844 174643422 : if (nb < Flx_MUL_KARATSUBA_LIMIT)
845 174641891 : return Flx_shiftip(av,Flx_mulspec_basecase(a,b,p,na,nb), v);
846 1531 : i=(na>>1); n0=na-i; na=i;
847 1531 : a0=a+n0; n0a=n0;
848 1531 : while (n0a && !a[n0a-1]) n0a--;
849 :
850 1531 : if (nb > n0)
851 : {
852 : GEN b0,c1,c2;
853 : long n0b;
854 :
855 1531 : nb -= n0; b0 = b+n0; n0b = n0;
856 1531 : while (n0b && !b[n0b-1]) n0b--;
857 1531 : c = Flx_mulspec(a,b,p,n0a,n0b);
858 1531 : c0 = Flx_mulspec(a0,b0,p,na,nb);
859 :
860 1531 : c2 = Flx_addspec(a0,a,p,na,n0a);
861 1531 : c1 = Flx_addspec(b0,b,p,nb,n0b);
862 :
863 1531 : c1 = Flx_mul(c1,c2,p);
864 1531 : c2 = Flx_add(c0,c,p);
865 :
866 1531 : c2 = Flx_neg_inplace(c2,p);
867 1531 : c2 = Flx_add(c1,c2,p);
868 1531 : c0 = Flx_addshift(c0,c2 ,p, n0);
869 : }
870 : else
871 : {
872 0 : c = Flx_mulspec(a,b,p,n0a,nb);
873 0 : c0 = Flx_mulspec(a0,b,p,na,nb);
874 : }
875 1531 : c0 = Flx_addshift(c0,c,p,n0);
876 1531 : return Flx_shiftip(av,c0, v);
877 : }
878 :
879 :
880 : GEN
881 248021348 : Flx_mul(GEN x, GEN y, ulong p)
882 : {
883 248021348 : GEN z = Flx_mulspec(x+2,y+2,p, lgpol(x),lgpol(y));
884 248049090 : z[1] = x[1]; return z;
885 : }
886 :
887 : static GEN
888 98914110 : Flx_sqrspec_basecase(GEN x, ulong p, long nx)
889 : {
890 : long i, lz, nz;
891 : ulong p1;
892 : GEN z;
893 :
894 98914110 : if (!nx) return pol0_Flx(0);
895 98914110 : lz = (nx << 1) + 1, nz = lz-2;
896 98914110 : z = cgetg(lz, t_VECSMALL) + 2;
897 98583028 : if (SMALL_ULONG(p))
898 : {
899 57262230 : z[0] = x[0]*x[0]%p;
900 132615138 : for (i=1; i<nx; i++)
901 : {
902 74899534 : p1 = Flx_mullimb_ok(x+i,x,p,0, (i+1)>>1);
903 75352908 : p1 <<= 1;
904 75352908 : if ((i&1) == 0) p1 += x[i>>1] * x[i>>1];
905 75352908 : z[i] = p1 % p;
906 : }
907 133329898 : for ( ; i<nz; i++)
908 : {
909 75584422 : p1 = Flx_mullimb_ok(x+i,x,p,i-nx+1, (i+1)>>1);
910 75614294 : p1 <<= 1;
911 75614294 : if ((i&1) == 0) p1 += x[i>>1] * x[i>>1];
912 75614294 : z[i] = p1 % p;
913 : }
914 : }
915 : else
916 : {
917 41320798 : ulong pi = get_Fl_red(p);
918 41327291 : z[0] = Fl_sqr_pre(x[0], p, pi);
919 199390644 : for (i=1; i<nx; i++)
920 : {
921 158043325 : p1 = Flx_mullimb(x+i,x,p,pi,0, (i+1)>>1);
922 158117375 : p1 = Fl_add(p1, p1, p);
923 158005674 : if ((i&1) == 0) p1 = Fl_add(p1, Fl_sqr_pre(x[i>>1], p, pi), p);
924 158033542 : z[i] = p1;
925 : }
926 199395978 : for ( ; i<nz; i++)
927 : {
928 158035557 : p1 = Flx_mullimb(x+i,x,p,pi,i-nx+1, (i+1)>>1);
929 158104750 : p1 = Fl_add(p1, p1, p);
930 158022826 : if ((i&1) == 0) p1 = Fl_add(p1, Fl_sqr_pre(x[i>>1], p, pi), p);
931 158048659 : z[i] = p1;
932 : }
933 : }
934 99105897 : z -= 2; return Flx_renormalize(z, lz);
935 : }
936 :
937 : static GEN
938 42030755 : Flx_sqrspec_sqri(GEN a, ulong p, long na)
939 : {
940 42030755 : GEN z=sqrispec(a,na);
941 42320925 : return int_to_Flx(z,p);
942 : }
943 :
944 : static GEN
945 12169947 : Flx_sqrspec_halfsqri(GEN a, ulong p, long na)
946 : {
947 12169947 : GEN z = sqri(Flx_to_int_halfspec(a,na));
948 12170012 : return int_to_Flx_half(z,p);
949 : }
950 :
951 : static GEN
952 10463331 : Flx_sqrspec_quartsqri(GEN a, ulong p, long na)
953 : {
954 10463331 : GEN z = sqri(Flx_to_int_quartspec(a,na));
955 10463358 : return int_to_Flx_quart(z,p);
956 : }
957 :
958 : static GEN
959 19023017 : Flx_sqrspec_sqri_inflate(GEN x, long N, ulong p, long nx)
960 : {
961 19023017 : pari_sp av = avma;
962 19023017 : GEN z = sqri(Flx_eval2BILspec(x,N,nx));
963 19046457 : return gerepileupto(av, Z_mod2BIL_Flx(z, N, (nx-1)*2, p));
964 : }
965 :
966 : static GEN
967 182782329 : Flx_sqrspec(GEN a, ulong p, long na)
968 : {
969 : GEN a0, c, c0;
970 182782329 : long n0, n0a, i, v = 0;
971 : pari_sp av;
972 :
973 182782329 : while (na && !a[0]) { a++; na--; v += 2; }
974 182782329 : if (!na) return pol0_Flx(0);
975 :
976 182693839 : av = avma;
977 182693839 : switch(maxlengthcoeffpol(p,na))
978 : {
979 : case -1:
980 21074950 : if (na>=Flx_SQR_QUARTSQRI_LIMIT)
981 10463339 : return Flx_shiftip(av, Flx_sqrspec_quartsqri(a,p,na), v);
982 10611611 : break;
983 : case 0:
984 18794994 : if (na>=Flx_SQR_HALFSQRI_LIMIT)
985 12169951 : return Flx_shiftip(av, Flx_sqrspec_halfsqri(a,p,na), v);
986 6625043 : break;
987 : case 1:
988 81040401 : if (na>=Flx_SQR_SQRI_LIMIT)
989 42048804 : return Flx_shiftip(av, Flx_sqrspec_sqri(a,p,na), v);
990 38991597 : break;
991 : case 2:
992 60539071 : if (na>=Flx_SQR_SQRI2_LIMIT)
993 19023506 : return Flx_shiftip(av, Flx_sqrspec_sqri_inflate(a,2,p,na), v);
994 41515565 : break;
995 : case 3:
996 1209901 : if (na>70)
997 2223 : return Flx_shiftip(av, Flx_sqrspec_sqri_inflate(a,3,p,na), v);
998 1207678 : break;
999 : }
1000 98932500 : if (na < Flx_SQR_KARATSUBA_LIMIT)
1001 98932260 : return Flx_shiftip(av, Flx_sqrspec_basecase(a,p,na), v);
1002 240 : i=(na>>1); n0=na-i; na=i;
1003 240 : a0=a+n0; n0a=n0;
1004 240 : while (n0a && !a[n0a-1]) n0a--;
1005 :
1006 240 : c = Flx_sqrspec(a,p,n0a);
1007 240 : c0= Flx_sqrspec(a0,p,na);
1008 240 : if (p == 2) n0 *= 2;
1009 : else
1010 : {
1011 240 : GEN c1, t = Flx_addspec(a0,a,p,na,n0a);
1012 240 : t = Flx_sqr(t,p);
1013 240 : c1= Flx_add(c0,c, p);
1014 240 : c1= Flx_sub(t, c1, p);
1015 240 : c0 = Flx_addshift(c0,c1,p,n0);
1016 : }
1017 240 : c0 = Flx_addshift(c0,c,p,n0);
1018 240 : return Flx_shiftip(av,c0,v);
1019 : }
1020 :
1021 : GEN
1022 182658861 : Flx_sqr(GEN x, ulong p)
1023 : {
1024 182658861 : GEN z = Flx_sqrspec(x+2,p, lgpol(x));
1025 182819516 : z[1] = x[1]; return z;
1026 : }
1027 :
1028 : GEN
1029 9549 : Flx_powu(GEN x, ulong n, ulong p)
1030 : {
1031 9549 : GEN y = pol1_Flx(x[1]), z;
1032 : ulong m;
1033 9535 : if (n == 0) return y;
1034 9535 : m = n; z = x;
1035 : for (;;)
1036 : {
1037 36014 : if (m&1UL) y = Flx_mul(y,z, p);
1038 36022 : m >>= 1; if (!m) return y;
1039 26468 : z = Flx_sqr(z, p);
1040 26479 : }
1041 : }
1042 :
1043 : GEN
1044 12972 : Flx_halve(GEN y, ulong p)
1045 : {
1046 : GEN z;
1047 : long i, l;
1048 12972 : z = cgetg_copy(y, &l); z[1] = y[1];
1049 12972 : for(i=2; i<l; i++) uel(z,i) = Fl_halve(uel(y,i), p);
1050 12972 : return z;
1051 : }
1052 :
1053 : static GEN
1054 5196063 : Flx_recipspec(GEN x, long l, long n)
1055 : {
1056 : long i;
1057 5196063 : GEN z=cgetg(n+2,t_VECSMALL)+2;
1058 207304430 : for(i=0; i<l; i++)
1059 202108259 : z[n-i-1] = x[i];
1060 7911179 : for( ; i<n; i++)
1061 2715008 : z[n-i-1] = 0;
1062 5196171 : return Flx_renormalize(z-2,n+2);
1063 : }
1064 :
1065 : GEN
1066 0 : Flx_recip(GEN x)
1067 : {
1068 0 : GEN z=Flx_recipspec(x+2,lgpol(x),lgpol(x));
1069 0 : z[1]=x[1];
1070 0 : return z;
1071 : }
1072 :
1073 : /* Return h^degpol(P) P(x / h) */
1074 : GEN
1075 701 : Flx_rescale(GEN P, ulong h, ulong p)
1076 : {
1077 701 : long i, l = lg(P);
1078 701 : GEN Q = cgetg(l,t_VECSMALL);
1079 701 : ulong hi = h;
1080 701 : Q[l-1] = P[l-1];
1081 5204 : for (i=l-2; i>=2; i--)
1082 : {
1083 5204 : Q[i] = Fl_mul(P[i], hi, p);
1084 5204 : if (i == 2) break;
1085 4503 : hi = Fl_mul(hi,h, p);
1086 : }
1087 701 : Q[1] = P[1]; return Q;
1088 : }
1089 :
1090 : static long
1091 40067622 : Flx_multhreshold(GEN T, ulong p, long quart, long half, long mul, long mul2, long kara)
1092 : {
1093 40067622 : long na = lgpol(T);
1094 40067243 : switch (maxlengthcoeffpol(p,na))
1095 : {
1096 : case -1:
1097 12959983 : if (na>=Flx_MUL_QUARTMULII_LIMIT)
1098 6818175 : return na>=quart;
1099 6141808 : break;
1100 : case 0:
1101 5800976 : if (na>=Flx_MUL_HALFMULII_LIMIT)
1102 3179760 : return na>=half;
1103 2621216 : break;
1104 : case 1:
1105 11333444 : if (na>=Flx_MUL_MULII_LIMIT)
1106 3178952 : return na>=mul;
1107 8154492 : break;
1108 : case 2:
1109 8804443 : if (na>=Flx_MUL_MULII2_LIMIT)
1110 986574 : return na>=mul2;
1111 7817869 : break;
1112 : case 3:
1113 1168561 : if (na>=70)
1114 1348 : return na>=70;
1115 1167213 : break;
1116 : }
1117 25902556 : return na>=kara;
1118 : }
1119 :
1120 : /*
1121 : * x/polrecip(P)+O(x^n)
1122 : */
1123 : static GEN
1124 85180 : Flx_invBarrett_basecase(GEN T, ulong p)
1125 : {
1126 85180 : long i, l=lg(T)-1, lr=l-1, k;
1127 85180 : GEN r=cgetg(lr,t_VECSMALL); r[1] = T[1];
1128 85179 : r[2] = 1;
1129 85179 : if (SMALL_ULONG(p))
1130 3838964 : for (i=3;i<lr;i++)
1131 : {
1132 3756328 : ulong u = uel(T, l-i+2);
1133 115141859 : for (k=3; k<i; k++)
1134 111385531 : { u += uel(T,l-i+k) * uel(r, k); if (u & HIGHBIT) u %= p; }
1135 3756328 : r[i] = Fl_neg(u % p, p);
1136 : }
1137 : else
1138 50441 : for (i=3;i<lr;i++)
1139 : {
1140 47895 : ulong u = Fl_neg(uel(T,l-i+2), p);
1141 512815 : for (k=3; k<i; k++)
1142 464917 : u = Fl_sub(u, Fl_mul(uel(T,l-i+k), uel(r,k), p), p);
1143 47898 : r[i] = u;
1144 : }
1145 85182 : return Flx_renormalize(r,lr);
1146 : }
1147 :
1148 : /* Return new lgpol */
1149 : static long
1150 4209788 : Flx_lgrenormalizespec(GEN x, long lx)
1151 : {
1152 : long i;
1153 12011104 : for (i = lx-1; i>=0; i--)
1154 12011032 : if (x[i]) break;
1155 4209788 : return i+1;
1156 : }
1157 : static GEN
1158 4347 : Flx_invBarrett_Newton(GEN T, ulong p)
1159 : {
1160 4347 : long nold, lx, lz, lq, l = degpol(T), lQ;
1161 4347 : GEN q, y, z, x = zero_zv(l+1) + 2;
1162 4348 : ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
1163 : pari_sp av;
1164 :
1165 4349 : y = T+2;
1166 4349 : q = Flx_recipspec(y,l+1,l+1); lQ = lgpol(q); q+=2;
1167 4347 : av = avma;
1168 : /* We work on _spec_ Flx's, all the l[xzq12] below are lgpol's */
1169 :
1170 : /* initialize */
1171 4347 : x[0] = Fl_inv(q[0], p);
1172 4349 : if (lQ>1 && q[1])
1173 2041 : {
1174 2043 : ulong u = q[1];
1175 2043 : if (x[0] != 1) u = Fl_mul(u, Fl_sqr(x[0],p), p);
1176 2041 : x[1] = p - u; lx = 2;
1177 : }
1178 : else
1179 2306 : lx = 1;
1180 4347 : nold = 1;
1181 32062 : for (; mask > 1; avma = av)
1182 : { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
1183 27713 : long i, lnew, nnew = nold << 1;
1184 :
1185 27713 : if (mask & 1) nnew--;
1186 27713 : mask >>= 1;
1187 :
1188 27713 : lnew = nnew + 1;
1189 27713 : lq = Flx_lgrenormalizespec(q, minss(lQ, lnew));
1190 27709 : z = Flx_mulspec(x, q, p, lx, lq); /* FIXME: high product */
1191 27719 : lz = lgpol(z); if (lz > lnew) lz = lnew;
1192 27719 : z += 2;
1193 : /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
1194 27719 : for (i = nold; i < lz; i++) if (z[i]) break;
1195 27719 : nold = nnew;
1196 27719 : if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
1197 :
1198 : /* z + i represents (x*q - 1) / t^i */
1199 19314 : lz = Flx_lgrenormalizespec (z+i, lz-i);
1200 19314 : z = Flx_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */
1201 19311 : lz = lgpol(z); z += 2;
1202 19311 : if (lz > lnew-i) lz = Flx_lgrenormalizespec(z, lnew-i);
1203 :
1204 19310 : lx = lz+ i;
1205 19310 : y = x + i; /* x -= z * t^i, in place */
1206 19310 : for (i = 0; i < lz; i++) y[i] = Fl_neg(z[i], p);
1207 : }
1208 4349 : x -= 2; setlg(x, lx + 2); x[1] = T[1];
1209 4349 : return x;
1210 : }
1211 :
1212 : /* x/polrecip(T)+O(x^deg(T)) */
1213 : GEN
1214 89527 : Flx_invBarrett(GEN T, ulong p)
1215 : {
1216 89527 : pari_sp ltop=avma;
1217 89527 : long l=lg(T);
1218 : GEN r;
1219 89527 : if (l<5) return pol0_Flx(T[1]);
1220 89525 : if (!Flx_multhreshold(T,p, Flx_INVBARRETT_QUARTMULII_LIMIT,
1221 : Flx_INVBARRETT_HALFMULII_LIMIT,
1222 : Flx_INVBARRETT_MULII_LIMIT,
1223 : Flx_INVBARRETT_MULII2_LIMIT,
1224 : Flx_INVBARRETT_KARATSUBA_LIMIT))
1225 : {
1226 85180 : ulong c = T[l-1];
1227 85180 : if (c!=1)
1228 : {
1229 478 : ulong ci = Fl_inv(c,p);
1230 478 : T=Flx_Fl_mul(T, ci, p);
1231 478 : r=Flx_invBarrett_basecase(T,p);
1232 478 : r=Flx_Fl_mul(r,ci,p);
1233 : }
1234 : else
1235 84702 : r=Flx_invBarrett_basecase(T,p);
1236 : }
1237 : else
1238 4347 : r = Flx_invBarrett_Newton(T,p);
1239 89529 : return gerepileuptoleaf(ltop, r);
1240 : }
1241 :
1242 : GEN
1243 40093335 : Flx_get_red(GEN T, ulong p)
1244 : {
1245 40093335 : if (typ(T)!=t_VECSMALL || !Flx_multhreshold(T,p,
1246 : Flx_BARRETT_QUARTMULII_LIMIT,
1247 : Flx_BARRETT_HALFMULII_LIMIT,
1248 : Flx_BARRETT_MULII_LIMIT,
1249 : Flx_BARRETT_MULII2_LIMIT,
1250 : Flx_BARRETT_KARATSUBA_LIMIT))
1251 40003895 : return T;
1252 88610 : retmkvec2(Flx_invBarrett(T,p),T);
1253 : }
1254 :
1255 : /* separate from Flx_divrem for maximal speed. */
1256 : static GEN
1257 434719364 : Flx_rem_basecase(GEN x, GEN y, ulong p)
1258 : {
1259 : pari_sp av;
1260 : GEN z, c;
1261 : long dx,dy,dy1,dz,i,j;
1262 : ulong p1,inv;
1263 434719364 : long vs=x[1];
1264 :
1265 434719364 : dy = degpol(y); if (!dy) return pol0_Flx(x[1]);
1266 427220744 : dx = degpol(x);
1267 427178171 : dz = dx-dy; if (dz < 0) return Flx_copy(x);
1268 427178171 : x += 2; y += 2;
1269 427178171 : inv = y[dy];
1270 427178171 : if (inv != 1UL) inv = Fl_inv(inv,p);
1271 427558892 : for (dy1=dy-1; dy1>=0 && !y[dy1]; dy1--);
1272 :
1273 427558892 : c = cgetg(dy+3, t_VECSMALL); c[1]=vs; c += 2; av=avma;
1274 425860946 : z = cgetg(dz+3, t_VECSMALL); z[1]=vs; z += 2;
1275 :
1276 429355960 : if (SMALL_ULONG(p))
1277 : {
1278 263073917 : z[dz] = (inv*x[dx]) % p;
1279 1011171381 : for (i=dx-1; i>=dy; --i)
1280 : {
1281 748097464 : p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
1282 4619678620 : for (j=i-dy1; j<=i && j<=dz; j++)
1283 : {
1284 3871581156 : p1 += z[j]*y[i-j];
1285 3871581156 : if (p1 & HIGHBIT) p1 %= p;
1286 : }
1287 748097464 : p1 %= p;
1288 748097464 : z[i-dy] = p1? ((p - p1)*inv) % p: 0;
1289 : }
1290 1841121728 : for (i=0; i<dy; i++)
1291 : {
1292 1578812090 : p1 = z[0]*y[i];
1293 6600716072 : for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)
1294 : {
1295 5021903982 : p1 += z[j]*y[i-j];
1296 5021903982 : if (p1 & HIGHBIT) p1 %= p;
1297 : }
1298 1574073406 : c[i] = Fl_sub(x[i], p1%p, p);
1299 : }
1300 : }
1301 : else
1302 : {
1303 166282043 : ulong pi = get_Fl_red(p);
1304 166341116 : z[dz] = Fl_mul_pre(inv, x[dx], p, pi);
1305 553085227 : for (i=dx-1; i>=dy; --i)
1306 : {
1307 386629751 : p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
1308 1658584815 : for (j=i-dy1; j<=i && j<=dz; j++)
1309 1272162663 : p1 = Fl_addmul_pre(p1, z[j], y[i - j], p, pi);
1310 386422152 : z[i-dy] = p1? Fl_mul_pre(p - p1, inv, p, pi): 0;
1311 : }
1312 1179760038 : for (i=0; i<dy; i++)
1313 : {
1314 1014670747 : p1 = Fl_mul_pre(z[0],y[i],p,pi);
1315 2944601647 : for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)
1316 1923502080 : p1 = Fl_addmul_pre(p1, z[j], y[i - j], p, pi);
1317 1005910595 : c[i] = Fl_sub(x[i], p1, p);
1318 : }
1319 : }
1320 427398929 : i = dy-1; while (i>=0 && !c[i]) i--;
1321 427398929 : avma=av;
1322 427398929 : return Flx_renormalize(c-2, i+3);
1323 : }
1324 :
1325 : /* as FpX_divrem but working only on ulong types.
1326 : * if relevant, *pr is the last object on stack */
1327 : static GEN
1328 26084920 : Flx_divrem_basecase(GEN x, GEN y, ulong p, GEN *pr)
1329 : {
1330 : GEN z,q,c;
1331 : long dx,dy,dy1,dz,i,j;
1332 : ulong p1,inv;
1333 26084920 : long sv=x[1];
1334 :
1335 26084920 : dy = degpol(y);
1336 26084880 : if (dy<0) pari_err_INV("Flx_divrem",y);
1337 26085106 : if (pr == ONLY_REM) return Flx_rem_basecase(x, y, p);
1338 26085104 : if (!dy)
1339 : {
1340 4149543 : if (pr && pr != ONLY_DIVIDES) *pr = pol0_Flx(sv);
1341 4149543 : if (y[2] == 1UL) return Flx_copy(x);
1342 2643143 : return Flx_Fl_mul(x, Fl_inv(y[2], p), p);
1343 : }
1344 21935561 : dx = degpol(x);
1345 21935558 : dz = dx-dy;
1346 21935558 : if (dz < 0)
1347 : {
1348 230235 : q = pol0_Flx(sv);
1349 230235 : if (pr && pr != ONLY_DIVIDES) *pr = Flx_copy(x);
1350 230235 : return q;
1351 : }
1352 21705323 : x += 2;
1353 21705323 : y += 2;
1354 21705323 : z = cgetg(dz + 3, t_VECSMALL); z[1] = sv; z += 2;
1355 21705267 : inv = uel(y, dy);
1356 21705267 : if (inv != 1UL) inv = Fl_inv(inv,p);
1357 21705325 : for (dy1=dy-1; dy1>=0 && !y[dy1]; dy1--);
1358 :
1359 21705325 : if (SMALL_ULONG(p))
1360 : {
1361 20800681 : z[dz] = (inv*x[dx]) % p;
1362 56327506 : for (i=dx-1; i>=dy; --i)
1363 : {
1364 35526825 : p1 = p - x[i]; /* compute -p1 instead of p1 (pb with ulongs otherwise) */
1365 177265261 : for (j=i-dy1; j<=i && j<=dz; j++)
1366 : {
1367 141738436 : p1 += z[j]*y[i-j];
1368 141738436 : if (p1 & HIGHBIT) p1 %= p;
1369 : }
1370 35526825 : p1 %= p;
1371 35526825 : z[i-dy] = p1? (long) ((p - p1)*inv) % p: 0;
1372 : }
1373 : }
1374 : else
1375 : {
1376 904644 : z[dz] = Fl_mul(inv, x[dx], p);
1377 7346958 : for (i=dx-1; i>=dy; --i)
1378 : { /* compute -p1 instead of p1 (pb with ulongs otherwise) */
1379 6442314 : p1 = p - uel(x,i);
1380 36607663 : for (j=i-dy1; j<=i && j<=dz; j++)
1381 30165348 : p1 = Fl_add(p1, Fl_mul(z[j],y[i-j],p), p);
1382 6442315 : z[i-dy] = p1? Fl_mul(p - p1, inv, p): 0;
1383 : }
1384 : }
1385 21705325 : q = Flx_renormalize(z-2, dz+3);
1386 21705311 : if (!pr) return q;
1387 :
1388 17237236 : c = cgetg(dy + 3, t_VECSMALL); c[1] = sv; c += 2;
1389 17237236 : if (SMALL_ULONG(p))
1390 : {
1391 196004730 : for (i=0; i<dy; i++)
1392 : {
1393 179604216 : p1 = (ulong)z[0]*y[i];
1394 402274571 : for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)
1395 : {
1396 222670355 : p1 += (ulong)z[j]*y[i-j];
1397 222670355 : if (p1 & HIGHBIT) p1 %= p;
1398 : }
1399 179604216 : c[i] = Fl_sub(x[i], p1%p, p);
1400 : }
1401 : }
1402 : else
1403 : {
1404 9737282 : for (i=0; i<dy; i++)
1405 : {
1406 8900560 : p1 = Fl_mul(z[0],y[i],p);
1407 54762313 : for (j=maxss(1,i-dy1); j<=i && j<=dz; j++)
1408 45861753 : p1 = Fl_add(p1, Fl_mul(z[j],y[i-j],p), p);
1409 8900560 : c[i] = Fl_sub(x[i], p1, p);
1410 : }
1411 : }
1412 17237236 : i=dy-1; while (i>=0 && !c[i]) i--;
1413 17237236 : c = Flx_renormalize(c-2, i+3);
1414 17237236 : if (pr == ONLY_DIVIDES)
1415 259 : { if (lg(c) != 2) return NULL; }
1416 : else
1417 17236977 : *pr = c;
1418 17237159 : return q;
1419 : }
1420 :
1421 :
1422 : /* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1)
1423 : * and mg is the Barrett inverse of T. */
1424 : static GEN
1425 2072546 : Flx_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, ulong p, GEN *pr)
1426 : {
1427 : GEN q, r;
1428 2072546 : long lt = degpol(T); /*We discard the leading term*/
1429 : long ld, lm, lT, lmg;
1430 2072544 : ld = l-lt;
1431 2072544 : lm = minss(ld, lgpol(mg));
1432 2072541 : lT = Flx_lgrenormalizespec(T+2,lt);
1433 2072526 : lmg = Flx_lgrenormalizespec(mg+2,lm);
1434 2072537 : q = Flx_recipspec(x+lt,ld,ld); /* q = rec(x) lz<=ld*/
1435 2072501 : q = Flx_mulspec(q+2,mg+2,p,lgpol(q),lmg); /* q = rec(x) * mg lz<=ld+lm*/
1436 2072545 : q = Flx_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lz<=ld*/
1437 2072529 : if (!pr) return q;
1438 2072529 : r = Flx_mulspec(q+2,T+2,p,lgpol(q),lT); /* r = q*pol lz<=ld+lt*/
1439 2072561 : r = Flx_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - q*pol lz<=lt */
1440 2072535 : if (pr == ONLY_REM) return r;
1441 5443 : *pr = r; return q;
1442 : }
1443 :
1444 : static GEN
1445 2067142 : Flx_divrem_Barrett_noGC(GEN x, GEN mg, GEN T, ulong p, GEN *pr)
1446 : {
1447 2067142 : long l = lgpol(x), lt = degpol(T), lm = 2*lt-1;
1448 2067147 : GEN q = NULL, r;
1449 : long i;
1450 2067147 : if (l <= lt)
1451 : {
1452 0 : if (pr == ONLY_REM) return Flx_copy(x);
1453 0 : if (pr == ONLY_DIVIDES) return lgpol(x)? NULL: pol0_Flx(x[1]);
1454 0 : if (pr) *pr = Flx_copy(x);
1455 0 : return pol0_Flx(x[1]);
1456 : }
1457 2067147 : if (lt <= 1)
1458 2 : return Flx_divrem_basecase(x,T,p,pr);
1459 2067145 : if (pr != ONLY_REM && l>lm)
1460 0 : q = zero_zv(l-lt+1);
1461 2067145 : r = Flx_copy(x);
1462 4139726 : while (l>lm)
1463 : {
1464 5396 : GEN zr, zq = Flx_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr);
1465 5395 : long lz = lgpol(zr);
1466 5396 : if (pr != ONLY_REM)
1467 : {
1468 0 : long lq = lgpol(zq);
1469 0 : for(i=0; i<lq; i++) q[2+l-lm+i] = zq[2+i];
1470 : }
1471 5396 : for(i=0; i<lz; i++) r[2+l-lm+i] = zr[2+i];
1472 5396 : l = l-lm+lz;
1473 : }
1474 2067165 : if (pr != ONLY_REM)
1475 : {
1476 48 : if (l > lt)
1477 : {
1478 48 : GEN zq = Flx_divrem_Barrettspec(r+2,l,mg,T,p,&r);
1479 48 : if (!q) q = zq;
1480 : else
1481 : {
1482 0 : long lq = lgpol(zq);
1483 0 : for(i=0; i<lq; i++) q[2+i] = zq[2+i];
1484 : }
1485 : }
1486 : else
1487 0 : r = Flx_renormalize(r, l+2);
1488 : }
1489 : else
1490 : {
1491 2067117 : if (l > lt)
1492 2067113 : r = Flx_divrem_Barrettspec(r+2,l,mg,T,p,ONLY_REM);
1493 : else
1494 4 : r = Flx_renormalize(r, l+2);
1495 2067088 : r[1] = x[1]; return Flx_renormalize(r, lg(r));
1496 : }
1497 48 : if (pr) { r[1] = x[1]; r = Flx_renormalize(r, lg(r)); }
1498 48 : q[1] = x[1]; q = Flx_renormalize(q, lg(q));
1499 48 : if (pr == ONLY_DIVIDES) return lgpol(r)? NULL: q;
1500 48 : if (pr) *pr = r;
1501 48 : return q;
1502 : }
1503 :
1504 : GEN
1505 63145975 : Flx_divrem(GEN x, GEN T, ulong p, GEN *pr)
1506 : {
1507 63145975 : GEN B, y = get_Flx_red(T, &B);
1508 63145964 : long dy = degpol(y), dx = degpol(x), d = dx-dy;
1509 63145825 : if (pr==ONLY_REM) return Flx_rem(x, y, p);
1510 26084869 : if (!B && d+3 < Flx_DIVREM_BARRETT_LIMIT)
1511 26084821 : return Flx_divrem_basecase(x,y,p,pr);
1512 : else
1513 : {
1514 48 : pari_sp av=avma;
1515 48 : GEN mg = B? B: Flx_invBarrett(y, p);
1516 48 : GEN q1 = Flx_divrem_Barrett_noGC(x,mg,y,p,pr);
1517 48 : if (!q1) {avma=av; return NULL;}
1518 48 : if (!pr || pr==ONLY_DIVIDES) return gerepileuptoleaf(av, q1);
1519 21 : gerepileall(av,2,&q1,pr);
1520 21 : return q1;
1521 : }
1522 : }
1523 :
1524 : GEN
1525 499769768 : Flx_rem(GEN x, GEN T, ulong p)
1526 : {
1527 499769768 : GEN B, y = get_Flx_red(T, &B);
1528 499842822 : long dy = degpol(y), dx = degpol(x), d = dx-dy;
1529 499596925 : if (d < 0) return Flx_copy(x);
1530 436859942 : if (!B && d+3 < Flx_REM_BARRETT_LIMIT)
1531 434792849 : return Flx_rem_basecase(x,y,p);
1532 : else
1533 : {
1534 2067093 : pari_sp av=avma;
1535 2067093 : GEN mg = B ? B: Flx_invBarrett(y, p);
1536 2067093 : GEN r = Flx_divrem_Barrett_noGC(x, mg, y, p, ONLY_REM);
1537 2067065 : return gerepileuptoleaf(av, r);
1538 : }
1539 : }
1540 :
1541 : /* reduce T mod (X^n - 1, p). Shallow function */
1542 : GEN
1543 4919355 : Flx_mod_Xnm1(GEN T, ulong n, ulong p)
1544 : {
1545 4919355 : long i, j, L = lg(T), l = n+2;
1546 : GEN S;
1547 4919355 : if (L <= l || n & ~LGBITS) return T;
1548 217 : S = cgetg(l, t_VECSMALL);
1549 217 : S[1] = T[1];
1550 217 : for (i = 2; i < l; i++) S[i] = T[i];
1551 560 : for (j = 2; i < L; i++) {
1552 343 : S[j] = Fl_add(S[j], T[i], p);
1553 343 : if (++j == l) j = 2;
1554 : }
1555 217 : return Flx_renormalize(S, l);
1556 : }
1557 : /* reduce T mod (X^n + 1, p). Shallow function */
1558 : GEN
1559 4816 : Flx_mod_Xn1(GEN T, ulong n, ulong p)
1560 : {
1561 4816 : long i, j, L = lg(T), l = n+2;
1562 : GEN S;
1563 4816 : if (L <= l || n & ~LGBITS) return T;
1564 168 : S = cgetg(l, t_VECSMALL);
1565 168 : S[1] = T[1];
1566 168 : for (i = 2; i < l; i++) S[i] = T[i];
1567 427 : for (j = 2; i < L; i++) {
1568 259 : S[j] = Fl_sub(S[j], T[i], p);
1569 259 : if (++j == l) j = 2;
1570 : }
1571 168 : return Flx_renormalize(S, l);
1572 : }
1573 :
1574 : struct _Flxq {
1575 : GEN aut;
1576 : GEN T;
1577 : ulong p;
1578 : };
1579 :
1580 : static GEN
1581 0 : _Flx_divrem(void * E, GEN x, GEN y, GEN *r)
1582 : {
1583 0 : struct _Flxq *D = (struct _Flxq*) E;
1584 0 : return Flx_divrem(x, y, D->p, r);
1585 : }
1586 : static GEN
1587 24101692 : _Flx_add(void * E, GEN x, GEN y) {
1588 24101692 : struct _Flxq *D = (struct _Flxq*) E;
1589 24101692 : return Flx_add(x, y, D->p);
1590 : }
1591 : static GEN
1592 9066984 : _Flx_mul(void *E, GEN x, GEN y) {
1593 9066984 : struct _Flxq *D = (struct _Flxq*) E;
1594 9066984 : return Flx_mul(x, y, D->p);
1595 : }
1596 : static GEN
1597 0 : _Flx_sqr(void *E, GEN x) {
1598 0 : struct _Flxq *D = (struct _Flxq*) E;
1599 0 : return Flx_sqr(x, D->p);
1600 : }
1601 :
1602 : static struct bb_ring Flx_ring = { _Flx_add,_Flx_mul,_Flx_sqr };
1603 :
1604 : GEN
1605 0 : Flx_digits(GEN x, GEN T, ulong p)
1606 : {
1607 0 : pari_sp av = avma;
1608 : struct _Flxq D;
1609 0 : long d = degpol(T), n = (lgpol(x)+d-1)/d;
1610 : GEN z;
1611 0 : D.p = p;
1612 0 : z = gen_digits(x,T,n,(void *)&D, &Flx_ring, _Flx_divrem);
1613 0 : return gerepileupto(av, z);
1614 : }
1615 :
1616 : GEN
1617 0 : FlxV_Flx_fromdigits(GEN x, GEN T, ulong p)
1618 : {
1619 0 : pari_sp av = avma;
1620 : struct _Flxq D;
1621 : GEN z;
1622 0 : D.p = p;
1623 0 : z = gen_fromdigits(x,T,(void *)&D, &Flx_ring);
1624 0 : return gerepileupto(av, z);
1625 : }
1626 :
1627 : long
1628 3112866 : Flx_val(GEN x)
1629 : {
1630 3112866 : long i, l=lg(x);
1631 3112866 : if (l==2) return LONG_MAX;
1632 3112866 : for (i=2; i<l && x[i]==0; i++) /*empty*/;
1633 3112866 : return i-2;
1634 : }
1635 : long
1636 22165404 : Flx_valrem(GEN x, GEN *Z)
1637 : {
1638 22165404 : long v, i, l=lg(x);
1639 : GEN y;
1640 22165404 : if (l==2) { *Z = Flx_copy(x); return LONG_MAX; }
1641 22165404 : for (i=2; i<l && x[i]==0; i++) /*empty*/;
1642 22165404 : v = i-2;
1643 22165404 : if (v == 0) { *Z = x; return 0; }
1644 35539 : l -= v;
1645 35539 : y = cgetg(l, t_VECSMALL); y[1] = x[1];
1646 35539 : for (i=2; i<l; i++) y[i] = x[i+v];
1647 35539 : *Z = y; return v;
1648 : }
1649 :
1650 : GEN
1651 5751789 : Flx_deriv(GEN z, ulong p)
1652 : {
1653 5751789 : long i,l = lg(z)-1;
1654 : GEN x;
1655 5751789 : if (l < 2) l = 2;
1656 5751789 : x = cgetg(l, t_VECSMALL); x[1] = z[1]; z++;
1657 5751548 : if (HIGHWORD(l | p))
1658 1226430 : for (i=2; i<l; i++) x[i] = Fl_mul((ulong)i-1, z[i], p);
1659 : else
1660 4525118 : for (i=2; i<l; i++) x[i] = ((i-1) * z[i]) % p;
1661 5753305 : return Flx_renormalize(x,l);
1662 : }
1663 :
1664 : GEN
1665 11851 : Flx_translate1(GEN P, ulong p)
1666 : {
1667 11851 : long i, k, n = degpol(P);
1668 11851 : GEN R = Flx_copy(P);
1669 51520 : for (i=1; i<=n; i++)
1670 146139 : for (k=n-i; k<n; k++)
1671 106470 : uel(R,k+2) = Fl_add(uel(R,k+2), uel(R,k+3), p);
1672 11851 : return R;
1673 : }
1674 :
1675 : GEN
1676 11851 : Flx_diff1(GEN P, ulong p)
1677 : {
1678 11851 : return Flx_sub(Flx_translate1(P, p), P, p);
1679 : }
1680 :
1681 : GEN
1682 72482 : Flx_deflate(GEN x0, long d)
1683 : {
1684 : GEN z, y, x;
1685 72482 : long i,id, dy, dx = degpol(x0);
1686 72482 : if (d == 1 || dx <= 0) return Flx_copy(x0);
1687 66406 : dy = dx/d;
1688 66406 : y = cgetg(dy+3, t_VECSMALL); y[1] = x0[1];
1689 66406 : z = y + 2;
1690 66406 : x = x0+ 2;
1691 66406 : for (i=id=0; i<=dy; i++,id+=d) z[i] = x[id];
1692 66406 : return y;
1693 : }
1694 :
1695 : GEN
1696 44286 : Flx_inflate(GEN x0, long d)
1697 : {
1698 44286 : long i, id, dy, dx = degpol(x0);
1699 44285 : GEN x = x0 + 2, z, y;
1700 44285 : if (dx <= 0) return Flx_copy(x0);
1701 43725 : dy = dx*d;
1702 43725 : y = cgetg(dy+3, t_VECSMALL); y[1] = x0[1];
1703 43733 : z = y + 2;
1704 43733 : for (i=0; i<=dy; i++) z[i] = 0;
1705 43733 : for (i=id=0; i<=dx; i++,id+=d) z[id] = x[i];
1706 43733 : return y;
1707 : }
1708 :
1709 : /* write p(X) = a_0(X^k) + X*a_1(X^k) + ... + X^(k-1)*a_{k-1}(X^k) */
1710 : GEN
1711 149822 : Flx_splitting(GEN p, long k)
1712 : {
1713 149822 : long n = degpol(p), v = p[1], m, i, j, l;
1714 : GEN r;
1715 :
1716 149823 : m = n/k;
1717 149823 : r = cgetg(k+1,t_VEC);
1718 686251 : for(i=1; i<=k; i++)
1719 : {
1720 536425 : gel(r,i) = cgetg(m+3, t_VECSMALL);
1721 536428 : mael(r,i,1) = v;
1722 : }
1723 4789668 : for (j=1, i=0, l=2; i<=n; i++)
1724 : {
1725 4639842 : mael(r,j,l) = p[2+i];
1726 4639842 : if (j==k) { j=1; l++; } else j++;
1727 : }
1728 686250 : for(i=1; i<=k; i++)
1729 536429 : gel(r,i) = Flx_renormalize(gel(r,i),i<j?l+1:l);
1730 149821 : return r;
1731 : }
1732 : static GEN
1733 177712 : Flx_halfgcd_basecase(GEN a, GEN b, ulong p)
1734 : {
1735 177712 : pari_sp av=avma;
1736 : GEN u,u1,v,v1;
1737 177712 : long vx = a[1];
1738 177712 : long n = lgpol(a)>>1;
1739 177712 : u1 = v = pol0_Flx(vx);
1740 177712 : u = v1 = pol1_Flx(vx);
1741 885061 : while (lgpol(b)>n)
1742 : {
1743 529637 : GEN r, q = Flx_divrem(a,b,p, &r);
1744 529637 : a = b; b = r; swap(u,u1); swap(v,v1);
1745 529637 : u1 = Flx_sub(u1, Flx_mul(u, q, p), p);
1746 529637 : v1 = Flx_sub(v1, Flx_mul(v, q ,p), p);
1747 529637 : if (gc_needed(av,2))
1748 : {
1749 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flx_halfgcd (d = %ld)",degpol(b));
1750 0 : gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);
1751 : }
1752 : }
1753 177712 : return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));
1754 : }
1755 : /* ux + vy */
1756 : static GEN
1757 5686 : Flx_addmulmul(GEN u, GEN v, GEN x, GEN y, ulong p)
1758 5686 : { return Flx_add(Flx_mul(u,x, p), Flx_mul(v,y, p), p); }
1759 :
1760 : static GEN
1761 2840 : FlxM_Flx_mul2(GEN M, GEN x, GEN y, ulong p)
1762 : {
1763 2840 : GEN res = cgetg(3, t_COL);
1764 2840 : gel(res, 1) = Flx_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p);
1765 2840 : gel(res, 2) = Flx_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p);
1766 2840 : return res;
1767 : }
1768 :
1769 : #if 0
1770 : static GEN
1771 : FlxM_mul2_old(GEN M, GEN N, ulong p)
1772 : {
1773 : GEN res = cgetg(3, t_MAT);
1774 : gel(res, 1) = FlxM_Flx_mul2(M,gcoeff(N,1,1),gcoeff(N,2,1),p);
1775 : gel(res, 2) = FlxM_Flx_mul2(M,gcoeff(N,1,2),gcoeff(N,2,2),p);
1776 : return res;
1777 : }
1778 : #endif
1779 : /* A,B are 2x2 matrices, Flx entries. Return A x B using Strassen 7M formula */
1780 : static GEN
1781 1635 : FlxM_mul2(GEN A, GEN B, ulong p)
1782 : {
1783 1635 : GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
1784 1635 : GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
1785 1635 : GEN M1 = Flx_mul(Flx_add(A11,A22, p), Flx_add(B11,B22, p), p);
1786 1635 : GEN M2 = Flx_mul(Flx_add(A21,A22, p), B11, p);
1787 1635 : GEN M3 = Flx_mul(A11, Flx_sub(B12,B22, p), p);
1788 1635 : GEN M4 = Flx_mul(A22, Flx_sub(B21,B11, p), p);
1789 1635 : GEN M5 = Flx_mul(Flx_add(A11,A12, p), B22, p);
1790 1635 : GEN M6 = Flx_mul(Flx_sub(A21,A11, p), Flx_add(B11,B12, p), p);
1791 1635 : GEN M7 = Flx_mul(Flx_sub(A12,A22, p), Flx_add(B21,B22, p), p);
1792 1635 : GEN T1 = Flx_add(M1,M4, p), T2 = Flx_sub(M7,M5, p);
1793 1635 : GEN T3 = Flx_sub(M1,M2, p), T4 = Flx_add(M3,M6, p);
1794 1635 : retmkmat2(mkcol2(Flx_add(T1,T2, p), Flx_add(M2,M4, p)),
1795 : mkcol2(Flx_add(M3,M5, p), Flx_add(T3,T4, p)));
1796 : }
1797 :
1798 : /* Return [0,1;1,-q]*M */
1799 : static GEN
1800 1632 : Flx_FlxM_qmul(GEN q, GEN M, ulong p)
1801 : {
1802 1632 : GEN u, v, res = cgetg(3, t_MAT);
1803 1632 : u = Flx_sub(gcoeff(M,1,1), Flx_mul(gcoeff(M,2,1), q, p), p);
1804 1632 : gel(res,1) = mkcol2(gcoeff(M,2,1), u);
1805 1632 : v = Flx_sub(gcoeff(M,1,2), Flx_mul(gcoeff(M,2,2), q, p), p);
1806 1632 : gel(res,2) = mkcol2(gcoeff(M,2,2), v);
1807 1632 : return res;
1808 : }
1809 :
1810 : static GEN
1811 3 : matid2_FlxM(long v)
1812 : {
1813 3 : return mkmat2(mkcol2(pol1_Flx(v),pol0_Flx(v)),
1814 : mkcol2(pol0_Flx(v),pol1_Flx(v)));
1815 : }
1816 :
1817 : static GEN
1818 2814 : Flx_halfgcd_split(GEN x, GEN y, ulong p)
1819 : {
1820 2814 : pari_sp av=avma;
1821 : GEN R, S, V;
1822 : GEN y1, r, q;
1823 2814 : long l = lgpol(x), n = l>>1, k;
1824 2814 : if (lgpol(y)<=n) return matid2_FlxM(x[1]);
1825 2814 : R = Flx_halfgcd(Flx_shift(x,-n),Flx_shift(y,-n),p);
1826 2814 : V = FlxM_Flx_mul2(R,x,y,p); y1 = gel(V,2);
1827 2814 : if (lgpol(y1)<=n) return gerepilecopy(av, R);
1828 1632 : q = Flx_divrem(gel(V,1), y1, p, &r);
1829 1632 : k = 2*n-degpol(y1);
1830 1632 : S = Flx_halfgcd(Flx_shift(y1,-k), Flx_shift(r,-k),p);
1831 1632 : return gerepileupto(av, FlxM_mul2(S,Flx_FlxM_qmul(q,R,p),p));
1832 : }
1833 :
1834 : /* Return M in GL_2(Fl[X]) such that:
1835 : if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
1836 : */
1837 :
1838 : static GEN
1839 180526 : Flx_halfgcd_i(GEN x, GEN y, ulong p)
1840 : {
1841 180526 : if (!Flx_multhreshold(x,p,
1842 : Flx_HALFGCD_QUARTMULII_LIMIT,
1843 : Flx_HALFGCD_HALFMULII_LIMIT,
1844 : Flx_HALFGCD_MULII_LIMIT,
1845 : Flx_HALFGCD_MULII2_LIMIT,
1846 : Flx_HALFGCD_KARATSUBA_LIMIT))
1847 177712 : return Flx_halfgcd_basecase(x,y,p);
1848 2814 : return Flx_halfgcd_split(x,y,p);
1849 : }
1850 :
1851 : GEN
1852 180526 : Flx_halfgcd(GEN x, GEN y, ulong p)
1853 : {
1854 : pari_sp av;
1855 : GEN M,q,r;
1856 180526 : long lx=lgpol(x), ly=lgpol(y);
1857 180526 : if (!lx)
1858 : {
1859 0 : long v = x[1];
1860 0 : retmkmat2(mkcol2(pol0_Flx(v),pol1_Flx(v)),
1861 : mkcol2(pol1_Flx(v),pol0_Flx(v)));
1862 : }
1863 180526 : if (ly < lx) return Flx_halfgcd_i(x,y,p);
1864 1244 : av = avma;
1865 1244 : q = Flx_divrem(y,x,p,&r);
1866 1244 : M = Flx_halfgcd_i(x,r,p);
1867 1244 : gcoeff(M,1,1) = Flx_sub(gcoeff(M,1,1), Flx_mul(q, gcoeff(M,1,2), p), p);
1868 1244 : gcoeff(M,2,1) = Flx_sub(gcoeff(M,2,1), Flx_mul(q, gcoeff(M,2,2), p), p);
1869 1244 : return gerepilecopy(av, M);
1870 : }
1871 :
1872 : /*Do not garbage collect*/
1873 : static GEN
1874 28713810 : Flx_gcd_basecase(GEN a, GEN b, ulong p)
1875 : {
1876 28713810 : pari_sp av = avma;
1877 28713810 : ulong iter = 0;
1878 28713810 : if (lg(b) > lg(a)) swap(a, b);
1879 145779486 : while (lgpol(b))
1880 : {
1881 88408629 : GEN c = Flx_rem(a,b,p);
1882 88351866 : iter++; a = b; b = c;
1883 88351866 : if (gc_needed(av,2))
1884 : {
1885 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flx_gcd (d = %ld)",degpol(c));
1886 0 : gerepileall(av,2, &a,&b);
1887 : }
1888 : }
1889 28687756 : return iter < 2 ? Flx_copy(a) : a;
1890 : }
1891 :
1892 : GEN
1893 29421666 : Flx_gcd(GEN x, GEN y, ulong p)
1894 : {
1895 29421666 : pari_sp av = avma;
1896 29421666 : if (!lgpol(x)) return Flx_copy(y);
1897 57430647 : while (lg(y)>Flx_GCD_LIMIT)
1898 : {
1899 : GEN c;
1900 23 : if (lgpol(y)<=(lgpol(x)>>1))
1901 : {
1902 0 : GEN r = Flx_rem(x, y, p);
1903 0 : x = y; y = r;
1904 : }
1905 23 : c = FlxM_Flx_mul2(Flx_halfgcd(x,y, p), x, y, p);
1906 23 : x = gel(c,1); y = gel(c,2);
1907 23 : if (gc_needed(av,2))
1908 : {
1909 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flx_gcd (y = %ld)",degpol(y));
1910 0 : gerepileall(av,2,&x,&y);
1911 : }
1912 : }
1913 28715259 : return gerepileuptoleaf(av, Flx_gcd_basecase(x,y,p));
1914 : }
1915 :
1916 : int
1917 3490804 : Flx_is_squarefree(GEN z, ulong p)
1918 : {
1919 3490804 : pari_sp av = avma;
1920 3490804 : GEN d = Flx_gcd(z, Flx_deriv(z,p) , p);
1921 3490804 : long res= (degpol(d) == 0);
1922 3490804 : avma = av; return res;
1923 : }
1924 :
1925 : static long
1926 93245 : Flx_is_smooth_squarefree(GEN f, long r, ulong p)
1927 : {
1928 93245 : pari_sp av = avma;
1929 : long i;
1930 93245 : GEN sx = polx_Flx(f[1]), a = sx;
1931 360427 : for(i=1;;i++)
1932 : {
1933 360427 : if (degpol(f)<=r) {avma = av; return 1;}
1934 348146 : a = Flxq_powu(Flx_rem(a,f,p), p, f, p);
1935 348300 : if (Flx_equal(a, sx)) {avma = av; return 1;}
1936 345275 : if (i==r) {avma = av; return 0;}
1937 267264 : f = Flx_div(f, Flx_gcd(Flx_sub(a,sx,p),f,p),p);
1938 267199 : }
1939 : }
1940 :
1941 : static long
1942 5045 : Flx_is_l_pow(GEN x, ulong p)
1943 : {
1944 5045 : ulong i, lx = lgpol(x);
1945 8669 : for (i=1; i<lx; i++)
1946 7999 : if (x[i+2] && i%p) return 0;
1947 670 : return 1;
1948 : }
1949 :
1950 : int
1951 88197 : Flx_is_smooth(GEN g, long r, ulong p)
1952 : {
1953 88197 : GEN f = gen_0;
1954 : while (1)
1955 : {
1956 93243 : f = Flx_gcd(g, Flx_deriv(g, p), p);
1957 93255 : if (!Flx_is_smooth_squarefree(Flx_div(g, f, p), r, p))
1958 78011 : return 0;
1959 15248 : if (degpol(f)==0) return 1;
1960 5045 : g = Flx_is_l_pow(f,p) ? Flx_deflate(f, p): f;
1961 5046 : }
1962 : }
1963 :
1964 : static GEN
1965 3868312 : Flx_extgcd_basecase(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv)
1966 : {
1967 3868312 : pari_sp av=avma;
1968 : GEN u,v,d,d1,v1;
1969 3868312 : long vx = a[1];
1970 3868312 : d = a; d1 = b;
1971 3868312 : v = pol0_Flx(vx); v1 = pol1_Flx(vx);
1972 25639168 : while (lgpol(d1))
1973 : {
1974 17902544 : GEN r, q = Flx_divrem(d,d1,p, &r);
1975 17902544 : v = Flx_sub(v,Flx_mul(q,v1,p),p);
1976 17902544 : u=v; v=v1; v1=u;
1977 17902544 : u=r; d=d1; d1=u;
1978 17902544 : if (gc_needed(av,2))
1979 : {
1980 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flx_extgcd (d = %ld)",degpol(d));
1981 0 : gerepileall(av,5, &d,&d1,&u,&v,&v1);
1982 : }
1983 : }
1984 3868312 : if (ptu) *ptu = Flx_div(Flx_sub(d, Flx_mul(b,v,p), p), a, p);
1985 3868312 : *ptv = v; return d;
1986 : }
1987 :
1988 : static GEN
1989 3 : Flx_extgcd_halfgcd(GEN x, GEN y, ulong p, GEN *ptu, GEN *ptv)
1990 : {
1991 3 : pari_sp av=avma;
1992 3 : GEN u,v,R = matid2_FlxM(x[1]);
1993 9 : while (lg(y)>Flx_EXTGCD_LIMIT)
1994 : {
1995 : GEN M, c;
1996 3 : if (lgpol(y)<=(lgpol(x)>>1))
1997 : {
1998 0 : GEN r, q = Flx_divrem(x, y, p, &r);
1999 0 : x = y; y = r;
2000 0 : R = Flx_FlxM_qmul(q, R, p);
2001 : }
2002 3 : M = Flx_halfgcd(x,y, p);
2003 3 : c = FlxM_Flx_mul2(M, x,y, p);
2004 3 : R = FlxM_mul2(M, R, p);
2005 3 : x = gel(c,1); y = gel(c,2);
2006 3 : gerepileall(av,3,&x,&y,&R);
2007 : }
2008 3 : y = Flx_extgcd_basecase(x,y,p,&u,&v);
2009 3 : if (ptu) *ptu = Flx_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1),p);
2010 3 : *ptv = Flx_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2),p);
2011 3 : return y;
2012 : }
2013 :
2014 : /* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st
2015 : * ux + vy = gcd (mod p) */
2016 : GEN
2017 3868312 : Flx_extgcd(GEN x, GEN y, ulong p, GEN *ptu, GEN *ptv)
2018 : {
2019 : GEN d;
2020 3868312 : pari_sp ltop=avma;
2021 3868312 : if (lg(y)>Flx_EXTGCD_LIMIT)
2022 3 : d = Flx_extgcd_halfgcd(x, y, p, ptu, ptv);
2023 : else
2024 3868309 : d = Flx_extgcd_basecase(x, y, p, ptu, ptv);
2025 3868312 : gerepileall(ltop,ptu?3:2,&d,ptv,ptu);
2026 3868312 : return d;
2027 : }
2028 :
2029 : ulong
2030 1938119 : Flx_resultant(GEN a, GEN b, ulong p)
2031 : {
2032 : long da,db,dc,cnt;
2033 1938119 : ulong lb, res = 1UL;
2034 : pari_sp av;
2035 : GEN c;
2036 :
2037 1938119 : if (lgpol(a)==0 || lgpol(b)==0) return 0;
2038 1938193 : da = degpol(a);
2039 1938207 : db = degpol(b);
2040 1944898 : if (db > da)
2041 : {
2042 84594 : swapspec(a,b, da,db);
2043 84594 : if (both_odd(da,db)) res = p-res;
2044 : }
2045 1860304 : else if (!da) return 1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
2046 1944904 : cnt = 0; av = avma;
2047 32205687 : while (db)
2048 : {
2049 28322990 : lb = b[db+2];
2050 28322990 : c = Flx_rem(a,b, p);
2051 28189756 : a = b; b = c; dc = degpol(c);
2052 28197681 : if (dc < 0) { avma = av; return 0; }
2053 :
2054 28197518 : if (both_odd(da,db)) res = p - res;
2055 28230418 : if (lb != 1) res = Fl_mul(res, Fl_powu(lb, da - dc, p), p);
2056 28315879 : if (++cnt == 100) { cnt = 0; gerepileall(av, 2, &a, &b); }
2057 28315879 : da = db; /* = degpol(a) */
2058 28315879 : db = dc; /* = degpol(b) */
2059 : }
2060 1937793 : avma = av; return Fl_mul(res, Fl_powu(b[2], da, p), p);
2061 : }
2062 :
2063 : /* If resultant is 0, *ptU and *ptU are not set */
2064 : ulong
2065 112797 : Flx_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV)
2066 : {
2067 112797 : GEN z,q,u,v, x = a, y = b;
2068 112797 : ulong lb, res = 1UL;
2069 112797 : pari_sp av = avma;
2070 : long dx, dy, dz;
2071 112797 : long vs=a[1];
2072 :
2073 112797 : dx = degpol(x);
2074 112797 : dy = degpol(y);
2075 112797 : if (dy > dx)
2076 : {
2077 407 : swap(x,y); lswap(dx,dy); pswap(ptU, ptV);
2078 407 : a = x; b = y;
2079 407 : if (both_odd(dx,dy)) res = p-res;
2080 : }
2081 : /* dx <= dy */
2082 112797 : if (dx < 0) return 0;
2083 :
2084 112797 : u = pol0_Flx(vs);
2085 112797 : v = pol1_Flx(vs); /* v = 1 */
2086 769275 : while (dy)
2087 : { /* b u = x (a), b v = y (a) */
2088 543695 : lb = y[dy+2];
2089 543695 : q = Flx_divrem(x,y, p, &z);
2090 543681 : x = y; y = z; /* (x,y) = (y, x - q y) */
2091 543681 : dz = degpol(z); if (dz < 0) { avma = av; return 0; }
2092 543681 : z = Flx_sub(u, Flx_mul(q,v, p), p);
2093 543681 : u = v; v = z; /* (u,v) = (v, u - q v) */
2094 :
2095 543681 : if (both_odd(dx,dy)) res = p - res;
2096 543681 : if (lb != 1) res = Fl_mul(res, Fl_powu(lb, dx-dz, p), p);
2097 543681 : dx = dy; /* = degpol(x) */
2098 543681 : dy = dz; /* = degpol(y) */
2099 : }
2100 112783 : res = Fl_mul(res, Fl_powu(y[2], dx, p), p);
2101 112783 : lb = Fl_mul(res, Fl_inv(y[2],p), p);
2102 112783 : v = gerepileuptoleaf(av, Flx_Fl_mul(v, lb, p));
2103 112783 : av = avma;
2104 112783 : u = Flx_sub(Fl_to_Flx(res,vs), Flx_mul(b,v,p), p);
2105 112783 : u = gerepileuptoleaf(av, Flx_div(u,a,p)); /* = (res - b v) / a */
2106 112783 : *ptU = u;
2107 112783 : *ptV = v; return res;
2108 : }
2109 :
2110 : ulong
2111 30076537 : Flx_eval_powers_pre(GEN x, GEN y, ulong p, ulong pi)
2112 : {
2113 30076537 : ulong l0, l1, h0, h1, v1, i = 1, lx = lg(x)-1;
2114 : LOCAL_OVERFLOW;
2115 : LOCAL_HIREMAINDER;
2116 30076537 : x++;
2117 :
2118 30076537 : if (lx == 1)
2119 3102975 : return 0;
2120 26973562 : l1 = mulll(uel(x,i), uel(y,i)); h1 = hiremainder; v1 = 0;
2121 88468932 : while (++i < lx) {
2122 34521808 : l0 = mulll(uel(x,i), uel(y,i)); h0 = hiremainder;
2123 34521808 : l1 = addll(l0, l1); h1 = addllx(h0, h1); v1 += overflow;
2124 : }
2125 26973562 : if (v1 == 0) return remll_pre(h1, l1, p, pi);
2126 5514 : else return remlll_pre(v1, h1, l1, p, pi);
2127 : }
2128 :
2129 : INLINE ulong
2130 3320861 : Flx_eval_pre_i(GEN x, ulong y, ulong p, ulong pi)
2131 : {
2132 : ulong p1;
2133 3320861 : long i=lg(x)-1;
2134 3320861 : if (i<=2)
2135 1425225 : return (i==2)? x[2]: 0;
2136 1895636 : p1 = x[i];
2137 9047940 : for (i--; i>=2; i--)
2138 7157659 : p1 = Fl_addmul_pre(uel(x, i), p1, y, p, pi);
2139 1890281 : return p1;
2140 : }
2141 :
2142 : ulong
2143 3393297 : Flx_eval_pre(GEN x, ulong y, ulong p, ulong pi)
2144 : {
2145 3393297 : if (degpol(x) > 15)
2146 : {
2147 79093 : pari_sp av = avma;
2148 79093 : GEN v = Fl_powers_pre(y, degpol(x), p, pi);
2149 79109 : ulong r = Flx_eval_powers_pre(x, v, p, pi);
2150 79124 : avma = av;
2151 79124 : return r;
2152 : }
2153 : else
2154 3313685 : return Flx_eval_pre_i(x, y, p, pi);
2155 : }
2156 :
2157 : ulong
2158 3388075 : Flx_eval(GEN x, ulong y, ulong p)
2159 : {
2160 3388075 : return Flx_eval_pre(x, y, p, get_Fl_red(p));
2161 : }
2162 :
2163 : ulong
2164 2933 : Flv_prod_pre(GEN x, ulong p, ulong pi)
2165 : {
2166 2933 : pari_sp ltop = avma;
2167 : GEN v;
2168 2933 : long i,k,lx = lg(x);
2169 : ulong r;
2170 2933 : if (lx == 1) return 1UL;
2171 2933 : if (lx == 2) return uel(x,1);
2172 2744 : v = cgetg(1+(lx << 1), t_VECSMALL);
2173 2744 : k = 1;
2174 25424 : for (i=1; i<lx-1; i+=2)
2175 22680 : uel(v,k++) = Fl_mul_pre(uel(x,i), uel(x,i+1), p, pi);
2176 2744 : if (i < lx) uel(v,k++) = uel(x,i);
2177 15008 : while (k > 2)
2178 : {
2179 9520 : lx = k; k = 1;
2180 32200 : for (i=1; i<lx-1; i+=2)
2181 22680 : uel(v,k++) = Fl_mul_pre(uel(v,i), uel(v,i+1), p, pi);
2182 9520 : if (i < lx) uel(v,k++) = uel(v,i);
2183 : }
2184 2744 : r = uel(v,1);
2185 2744 : avma = ltop; return r;
2186 : }
2187 :
2188 : ulong
2189 0 : Flv_prod(GEN v, ulong p)
2190 : {
2191 0 : return Flv_prod_pre(v, p, get_Fl_red(p));
2192 : }
2193 :
2194 : GEN
2195 0 : FlxV_prod(GEN V, ulong p)
2196 : {
2197 : struct _Flxq D;
2198 0 : D.T = NULL; D.aut = NULL; D.p = p;
2199 0 : return gen_product(V, (void *)&D, &_Flx_mul);
2200 : }
2201 :
2202 : /* compute prod (x - a[i]) */
2203 : GEN
2204 614485 : Flv_roots_to_pol(GEN a, ulong p, long vs)
2205 : {
2206 : struct _Flxq D;
2207 614485 : long i,k,lx = lg(a);
2208 : GEN p1;
2209 614485 : if (lx == 1) return pol1_Flx(vs);
2210 614485 : p1 = cgetg(lx, t_VEC);
2211 10227859 : for (k=1,i=1; i<lx-1; i+=2)
2212 19242515 : gel(p1,k++) = mkvecsmall4(vs, Fl_mul(a[i], a[i+1], p),
2213 9613603 : Fl_neg(Fl_add(a[i],a[i+1],p),p), 1);
2214 614256 : if (i < lx)
2215 51840 : gel(p1,k++) = mkvecsmall3(vs, Fl_neg(a[i],p), 1);
2216 614256 : D.T = NULL; D.aut = NULL; D.p = p;
2217 614256 : setlg(p1, k); return gen_product(p1, (void *)&D, _Flx_mul);
2218 : }
2219 :
2220 : INLINE void
2221 10243032 : Flv_inv_pre_indir(GEN w, GEN v, ulong p, ulong pi)
2222 : {
2223 10243032 : pari_sp av = avma;
2224 : GEN c;
2225 : register ulong u;
2226 10243032 : register long n = lg(w), i;
2227 :
2228 10243032 : if (n == 1)
2229 10243033 : return;
2230 :
2231 10243032 : c = cgetg(n, t_VECSMALL);
2232 10243029 : c[1] = w[1];
2233 56135489 : for (i = 2; i < n; ++i)
2234 45892456 : c[i] = Fl_mul_pre(w[i], c[i - 1], p, pi);
2235 :
2236 10243033 : i = n - 1;
2237 10243033 : u = Fl_inv(c[i], p);
2238 56135565 : for ( ; i > 1; --i) {
2239 45892532 : ulong t = Fl_mul_pre(u, c[i - 1], p, pi);
2240 45892529 : u = Fl_mul_pre(u, w[i], p, pi);
2241 45892523 : v[i] = t;
2242 : }
2243 10243033 : v[1] = u;
2244 10243033 : avma = av;
2245 : }
2246 :
2247 : void
2248 10211408 : Flv_inv_pre_inplace(GEN v, ulong p, ulong pi)
2249 : {
2250 10211408 : Flv_inv_pre_indir(v, v, p, pi);
2251 10211408 : }
2252 :
2253 : GEN
2254 10710 : Flv_inv_pre(GEN w, ulong p, ulong pi)
2255 : {
2256 10710 : GEN v = cgetg(lg(w), t_VECSMALL);
2257 10710 : Flv_inv_pre_indir(w, v, p, pi);
2258 10711 : return v;
2259 : }
2260 :
2261 : INLINE void
2262 29049 : Flv_inv_indir(GEN w, GEN v, ulong p)
2263 : {
2264 29049 : pari_sp av = avma;
2265 : GEN c;
2266 : register ulong u;
2267 29049 : register long n = lg(w), i;
2268 :
2269 29049 : if (n == 1)
2270 29054 : return;
2271 :
2272 29049 : c = cgetg(n, t_VECSMALL);
2273 29045 : c[1] = w[1];
2274 367440 : for (i = 2; i < n; ++i)
2275 338385 : c[i] = Fl_mul(w[i], c[i - 1], p);
2276 :
2277 29055 : i = n - 1;
2278 29055 : u = Fl_inv(c[i], p);
2279 367462 : for ( ; i > 1; --i) {
2280 338408 : ulong t = Fl_mul(u, c[i - 1], p);
2281 338408 : u = Fl_mul(u, w[i], p);
2282 338407 : v[i] = t;
2283 : }
2284 29054 : v[1] = u;
2285 29054 : avma = av;
2286 : }
2287 :
2288 : void
2289 0 : Flv_inv_inplace(GEN v, ulong p)
2290 : {
2291 0 : if (SMALL_ULONG(p))
2292 0 : Flv_inv_indir(v, v, p);
2293 : else
2294 0 : Flv_inv_pre_indir(v, v, p, get_Fl_red(p));
2295 0 : }
2296 :
2297 : GEN
2298 49964 : Flv_inv(GEN w, ulong p)
2299 : {
2300 49964 : GEN v = cgetg(lg(w), t_VECSMALL);
2301 49963 : if (SMALL_ULONG(p))
2302 29049 : Flv_inv_indir(w, v, p);
2303 : else
2304 20914 : Flv_inv_pre_indir(w, v, p, get_Fl_red(p));
2305 49968 : return v;
2306 : }
2307 :
2308 : GEN
2309 28724092 : Flx_div_by_X_x(GEN a, ulong x, ulong p, ulong *rem)
2310 : {
2311 28724092 : long l = lg(a), i;
2312 : GEN a0, z0;
2313 28724092 : GEN z = cgetg(l-1,t_VECSMALL);
2314 28697564 : z[1] = a[1];
2315 28697564 : a0 = a + l-1;
2316 28697564 : z0 = z + l-2; *z0 = *a0--;
2317 28697564 : if (SMALL_ULONG(p))
2318 : {
2319 70271151 : for (i=l-3; i>1; i--) /* z[i] = (a[i+1] + x*z[i+1]) % p */
2320 : {
2321 52633112 : ulong t = (*a0-- + x * *z0--) % p;
2322 52633112 : *z0 = (long)t;
2323 : }
2324 17638039 : if (rem) *rem = (*a0 + x * *z0) % p;
2325 : }
2326 : else
2327 : {
2328 43452139 : for (i=l-3; i>1; i--)
2329 : {
2330 32335558 : ulong t = Fl_add((ulong)*a0--, Fl_mul(x, *z0--, p), p);
2331 32392614 : *z0 = (long)t;
2332 : }
2333 11116581 : if (rem) *rem = Fl_add((ulong)*a0, Fl_mul(x, *z0, p), p);
2334 : }
2335 28753250 : return z;
2336 : }
2337 :
2338 : /* xa, ya = t_VECSMALL */
2339 : static GEN
2340 49965 : Flv_producttree(GEN xa, GEN s, ulong p, long vs)
2341 : {
2342 49965 : long n = lg(xa)-1;
2343 49965 : long m = n==1 ? 1: expu(n-1)+1;
2344 49965 : long i, j, k, ls = lg(s);
2345 49965 : GEN T = cgetg(m+1, t_VEC);
2346 49957 : GEN t = cgetg(ls, t_VEC);
2347 607544 : for (j=1, k=1; j<ls; k+=s[j++])
2348 1115154 : gel(t, j) = s[j] == 1 ?
2349 759688 : mkvecsmall3(vs, Fl_neg(xa[k], p), 1):
2350 202082 : mkvecsmall4(vs, Fl_mul(xa[k], xa[k+1], p),
2351 202042 : Fl_neg(Fl_add(xa[k],xa[k+1],p),p), 1);
2352 49965 : gel(T,1) = t;
2353 188844 : for (i=2; i<=m; i++)
2354 : {
2355 138878 : GEN u = gel(T, i-1);
2356 138878 : long n = lg(u)-1;
2357 138878 : GEN t = cgetg(((n+1)>>1)+1, t_VEC);
2358 646740 : for (j=1, k=1; k<n; j++, k+=2)
2359 507861 : gel(t, j) = Flx_mul(gel(u, k), gel(u, k+1), p);
2360 138879 : gel(T, i) = t;
2361 : }
2362 49966 : return T;
2363 : }
2364 :
2365 : static GEN
2366 49963 : Flx_Flv_multieval_tree(GEN P, GEN xa, GEN T, ulong p)
2367 : {
2368 : long i,j,k;
2369 49963 : long m = lg(T)-1;
2370 : GEN t;
2371 49963 : GEN R = cgetg(lg(xa), t_VECSMALL);
2372 49961 : GEN Tp = cgetg(m+1, t_VEC);
2373 49962 : gel(Tp, m) = mkvec(P);
2374 188845 : for (i=m-1; i>=1; i--)
2375 : {
2376 138872 : GEN u = gel(T, i);
2377 138872 : GEN v = gel(Tp, i+1);
2378 138872 : long n = lg(u)-1;
2379 138872 : t = cgetg(n+1, t_VEC);
2380 646532 : for (j=1, k=1; k<n; j++, k+=2)
2381 : {
2382 507658 : gel(t, k) = Flx_rem(gel(v, j), gel(u, k), p);
2383 507652 : gel(t, k+1) = Flx_rem(gel(v, j), gel(u, k+1), p);
2384 : }
2385 138874 : gel(Tp, i) = t;
2386 : }
2387 : {
2388 49973 : GEN u = gel(T, i+1);
2389 49973 : GEN v = gel(Tp, i+1);
2390 49973 : long n = lg(u)-1;
2391 607846 : for (j=1, k=1; j<=n; j++)
2392 : {
2393 557878 : long c, d = degpol(gel(u,j));
2394 1317781 : for (c=1; c<=d; c++, k++)
2395 759908 : R[k] = Flx_eval(gel(v, j), xa[k], p);
2396 : }
2397 49968 : avma = (pari_sp) R;
2398 49968 : return R;
2399 : }
2400 : }
2401 :
2402 : static GEN
2403 739876 : FlvV_polint_tree(GEN T, GEN R, GEN s, GEN xa, GEN ya, ulong p, long vs)
2404 : {
2405 739876 : pari_sp av = avma;
2406 739876 : long m = lg(T)-1;
2407 739876 : long i, j, k, ls = lg(s);
2408 739876 : GEN Tp = cgetg(m+1, t_VEC);
2409 739564 : GEN t = cgetg(ls, t_VEC);
2410 12977806 : for (j=1, k=1; j<ls; k+=s[j++])
2411 12238018 : if (s[j]==2)
2412 : {
2413 4197001 : ulong a = Fl_mul(ya[k], R[k], p);
2414 4216013 : ulong b = Fl_mul(ya[k+1], R[k+1], p);
2415 12650402 : gel(t, j) = mkvecsmall3(vs, Fl_neg(Fl_add(Fl_mul(xa[k], b, p ),
2416 8433465 : Fl_mul(xa[k+1], a, p), p), p), Fl_add(a, b, p));
2417 4211825 : gel(t, j) = Flx_renormalize(gel(t, j), 4);
2418 : }
2419 : else
2420 8041017 : gel(t, j) = Fl_to_Flx(Fl_mul(ya[k], R[k], p), vs);
2421 739788 : gel(Tp, 1) = t;
2422 3290424 : for (i=2; i<=m; i++)
2423 : {
2424 2550782 : GEN u = gel(T, i-1);
2425 2550782 : GEN t = cgetg(lg(gel(T,i)), t_VEC);
2426 2551649 : GEN v = gel(Tp, i-1);
2427 2551649 : long n = lg(v)-1;
2428 14054869 : for (j=1, k=1; k<n; j++, k+=2)
2429 34512699 : gel(t, j) = Flx_add(Flx_mul(gel(u, k), gel(v, k+1), p),
2430 23008466 : Flx_mul(gel(u, k+1), gel(v, k), p), p);
2431 2550636 : gel(Tp, i) = t;
2432 : }
2433 739642 : return gerepileuptoleaf(av, gmael(Tp,m,1));
2434 : }
2435 :
2436 : GEN
2437 0 : Flx_Flv_multieval(GEN P, GEN xa, ulong p)
2438 : {
2439 0 : pari_sp av = avma;
2440 0 : GEN s = producttree_scheme(lg(xa)-1);
2441 0 : GEN T = Flv_producttree(xa, s, p, P[1]);
2442 0 : return gerepileuptoleaf(av, Flx_Flv_multieval_tree(P, xa, T, p));
2443 : }
2444 :
2445 : GEN
2446 11923 : Flv_polint(GEN xa, GEN ya, ulong p, long vs)
2447 : {
2448 11923 : pari_sp av = avma;
2449 11923 : GEN s = producttree_scheme(lg(xa)-1);
2450 11924 : GEN T = Flv_producttree(xa, s, p, vs);
2451 11925 : long m = lg(T)-1;
2452 11925 : GEN P = Flx_deriv(gmael(T, m, 1), p);
2453 11925 : GEN R = Flv_inv(Flx_Flv_multieval_tree(P, xa, T, p), p);
2454 11925 : return gerepileuptoleaf(av, FlvV_polint_tree(T, R, s, xa, ya, p, vs));
2455 : }
2456 :
2457 : GEN
2458 35059 : Flv_Flm_polint(GEN xa, GEN ya, ulong p, long vs)
2459 : {
2460 35059 : pari_sp av = avma;
2461 35059 : GEN s = producttree_scheme(lg(xa)-1);
2462 35060 : GEN T = Flv_producttree(xa, s, p, vs);
2463 35058 : long i, m = lg(T)-1, l = lg(ya)-1;
2464 35058 : GEN P = Flx_deriv(gmael(T, m, 1), p);
2465 35057 : GEN R = Flv_inv(Flx_Flv_multieval_tree(P, xa, T, p), p);
2466 35061 : GEN M = cgetg(l+1, t_VEC);
2467 763055 : for (i=1; i<=l; i++)
2468 727996 : gel(M,i) = FlvV_polint_tree(T, R, s, xa, gel(ya,i), p, vs);
2469 35059 : return gerepileupto(av, M);
2470 : }
2471 :
2472 : GEN
2473 2982 : Flv_invVandermonde(GEN L, ulong den, ulong p)
2474 : {
2475 2982 : pari_sp av = avma;
2476 2982 : long i, n = lg(L);
2477 : GEN M, R;
2478 2982 : GEN s = producttree_scheme(n-1);
2479 2982 : GEN tree = Flv_producttree(L, s, p, 0);
2480 2981 : long m = lg(tree)-1;
2481 2981 : GEN T = gmael(tree, m, 1);
2482 2981 : R = Flv_inv(Flx_Flv_multieval_tree(Flx_deriv(T, p), L, tree, p), p);
2483 2982 : if (den!=1) R = Flv_Fl_mul(R, den, p);
2484 2982 : M = cgetg(n, t_MAT);
2485 12792 : for (i = 1; i < n; i++)
2486 : {
2487 9810 : GEN P = Flx_Fl_mul(Flx_div_by_X_x(T, uel(L,i), p, NULL), uel(R,i), p);
2488 9807 : gel(M,i) = Flx_to_Flv(P, n-1);
2489 : }
2490 2982 : return gerepilecopy(av, M);
2491 : }
2492 :
2493 : /***********************************************************************/
2494 : /** **/
2495 : /** Flxq **/
2496 : /** **/
2497 : /***********************************************************************/
2498 : /* Flxq objects are defined as follows:
2499 : They are Flx modulo another Flx called q.
2500 : */
2501 :
2502 : /* Product of y and x in Z/pZ[X]/(T), as t_VECSMALL. */
2503 : GEN
2504 114289554 : Flxq_mul(GEN x,GEN y,GEN T,ulong p)
2505 : {
2506 114289554 : return Flx_rem(Flx_mul(x,y,p),T,p);
2507 : }
2508 :
2509 : /* Square of y in Z/pZ[X]/(T), as t_VECSMALL. */
2510 : GEN
2511 182020855 : Flxq_sqr(GEN x,GEN T,ulong p)
2512 : {
2513 182020855 : return Flx_rem(Flx_sqr(x,p),T,p);
2514 : }
2515 :
2516 : static GEN
2517 10341687 : _Flxq_red(void *E, GEN x)
2518 10341687 : { struct _Flxq *s = (struct _Flxq *)E;
2519 10341687 : return Flx_rem(x, s->T, s->p); }
2520 : static GEN
2521 0 : _Flx_sub(void *E, GEN x, GEN y)
2522 0 : { struct _Flxq *s = (struct _Flxq *)E;
2523 0 : return Flx_sub(x,y,s->p); }
2524 : static GEN
2525 176185871 : _Flxq_sqr(void *data, GEN x)
2526 : {
2527 176185871 : struct _Flxq *D = (struct _Flxq*)data;
2528 176185871 : return Flxq_sqr(x, D->T, D->p);
2529 : }
2530 : static GEN
2531 96479768 : _Flxq_mul(void *data, GEN x, GEN y)
2532 : {
2533 96479768 : struct _Flxq *D = (struct _Flxq*)data;
2534 96479768 : return Flxq_mul(x,y, D->T, D->p);
2535 : }
2536 : static GEN
2537 12070361 : _Flxq_one(void *data)
2538 : {
2539 12070361 : struct _Flxq *D = (struct _Flxq*)data;
2540 12070361 : return pol1_Flx(get_Flx_var(D->T));
2541 : }
2542 : static GEN
2543 193375 : _Flxq_zero(void *data)
2544 : {
2545 193375 : struct _Flxq *D = (struct _Flxq*)data;
2546 193375 : return pol0_Flx(get_Flx_var(D->T));
2547 : }
2548 : static GEN
2549 28385883 : _Flxq_cmul(void *data, GEN P, long a, GEN x)
2550 : {
2551 28385883 : struct _Flxq *D = (struct _Flxq*)data;
2552 28385883 : return Flx_Fl_mul(x, P[a+2], D->p);
2553 : }
2554 :
2555 : /* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */
2556 : GEN
2557 10826375 : Flxq_powu(GEN x, ulong n, GEN T, ulong p)
2558 : {
2559 10826375 : pari_sp av = avma;
2560 : struct _Flxq D;
2561 : GEN y;
2562 10826375 : switch(n)
2563 : {
2564 0 : case 0: return pol1_Flx(T[1]);
2565 36643 : case 1: return Flx_copy(x);
2566 140841 : case 2: return Flxq_sqr(x, T, p);
2567 : }
2568 10648891 : D.T = Flx_get_red(T, p); D.p = p;
2569 10647624 : y = gen_powu_i(x, n, (void*)&D, &_Flxq_sqr, &_Flxq_mul);
2570 10646624 : return gerepileuptoleaf(av, y);
2571 : }
2572 :
2573 : /* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */
2574 : GEN
2575 18012343 : Flxq_pow(GEN x, GEN n, GEN T, ulong p)
2576 : {
2577 18012343 : pari_sp av = avma;
2578 : struct _Flxq D;
2579 : GEN y;
2580 18012343 : long s = signe(n);
2581 18012343 : if (!s) return pol1_Flx(get_Flx_var(T));
2582 17820020 : if (s < 0)
2583 590824 : x = Flxq_inv(x,T,p);
2584 17820020 : if (is_pm1(n)) return s < 0 ? x : Flx_copy(x);
2585 17040516 : D.T = Flx_get_red(T, p); D.p = p;
2586 17040516 : y = gen_pow_i(x, n, (void*)&D, &_Flxq_sqr, &_Flxq_mul);
2587 17040516 : return gerepileuptoleaf(av, y);
2588 : }
2589 :
2590 : /* Inverse of x in Z/lZ[X]/(T) or NULL if inverse doesn't exist
2591 : * not stack clean.
2592 : */
2593 : GEN
2594 3738257 : Flxq_invsafe(GEN x, GEN T, ulong p)
2595 : {
2596 3738257 : GEN V, z = Flx_extgcd(get_Flx_mod(T), x, p, NULL, &V);
2597 : ulong iz;
2598 3738257 : if (degpol(z)) return NULL;
2599 3738229 : iz = Fl_inv (uel(z,2), p);
2600 3738229 : return Flx_Fl_mul(V, iz, p);
2601 : }
2602 :
2603 : GEN
2604 3684365 : Flxq_inv(GEN x,GEN T,ulong p)
2605 : {
2606 3684365 : pari_sp av=avma;
2607 3684365 : GEN U = Flxq_invsafe(x, T, p);
2608 3684365 : if (!U) pari_err_INV("Flxq_inv",Flx_to_ZX(x));
2609 3684337 : return gerepileuptoleaf(av, U);
2610 : }
2611 :
2612 : GEN
2613 1942980 : Flxq_div(GEN x,GEN y,GEN T,ulong p)
2614 : {
2615 1942980 : pari_sp av = avma;
2616 1942980 : return gerepileuptoleaf(av, Flxq_mul(x,Flxq_inv(y,T,p),T,p));
2617 : }
2618 :
2619 : GEN
2620 3129458 : Flxq_powers(GEN x, long l, GEN T, ulong p)
2621 : {
2622 : struct _Flxq D;
2623 3129458 : int use_sqr = 2*degpol(x) >= get_Flx_degree(T);
2624 3129458 : D.T = Flx_get_red(T, p); D.p = p;
2625 3129458 : return gen_powers(x, l, use_sqr, (void*)&D, &_Flxq_sqr, &_Flxq_mul, &_Flxq_one);
2626 : }
2627 :
2628 : GEN
2629 32865 : Flxq_matrix_pow(GEN y, long n, long m, GEN P, ulong l)
2630 : {
2631 32865 : return FlxV_to_Flm(Flxq_powers(y,m-1,P,l),n);
2632 : }
2633 :
2634 : GEN
2635 3783845 : Flx_Frobenius(GEN T, ulong p)
2636 : {
2637 3783845 : return Flxq_powu(polx_Flx(get_Flx_var(T)), p, T, p);
2638 : }
2639 :
2640 : GEN
2641 16856 : Flx_matFrobenius(GEN T, ulong p)
2642 : {
2643 16856 : long n = get_Flx_degree(T);
2644 16856 : return Flxq_matrix_pow(Flx_Frobenius(T, p), n, n, T, p);
2645 : }
2646 :
2647 : static struct bb_algebra Flxq_algebra = { _Flxq_red, _Flx_add, _Flx_sub,
2648 : _Flxq_mul, _Flxq_sqr, _Flxq_one, _Flxq_zero};
2649 :
2650 : GEN
2651 3531559 : Flx_FlxqV_eval(GEN Q, GEN x, GEN T, ulong p)
2652 : {
2653 : struct _Flxq D;
2654 3531559 : D.T = Flx_get_red(T, p); D.p=p;
2655 3531558 : return gen_bkeval_powers(Q,degpol(Q),x,(void*)&D,&Flxq_algebra,_Flxq_cmul);
2656 : }
2657 :
2658 : GEN
2659 999135 : Flx_Flxq_eval(GEN Q, GEN x, GEN T, ulong p)
2660 : {
2661 999135 : int use_sqr = 2*degpol(x) >= get_Flx_degree(T);
2662 : struct _Flxq D;
2663 999135 : D.T = Flx_get_red(T, p); D.p=p;
2664 999135 : return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&D,&Flxq_algebra,_Flxq_cmul);
2665 : }
2666 :
2667 : static GEN
2668 377725 : Flxq_autpow_sqr(void *E, GEN x)
2669 : {
2670 377725 : struct _Flxq *D = (struct _Flxq*)E;
2671 377725 : return Flx_Flxq_eval(x, x, D->T, D->p);
2672 : }
2673 : static GEN
2674 20534 : Flxq_autpow_mul(void *E, GEN x, GEN y)
2675 : {
2676 20534 : struct _Flxq *D = (struct _Flxq*)E;
2677 20534 : return Flx_Flxq_eval(x, y, D->T, D->p);
2678 : }
2679 :
2680 : GEN
2681 304465 : Flxq_autpow(GEN x, ulong n, GEN T, ulong p)
2682 : {
2683 : struct _Flxq D;
2684 304465 : D.T = Flx_get_red(T, p); D.p = p;
2685 304465 : if (n==0) return polx_Flx(T[1]);
2686 304458 : if (n==1) return Flx_copy(x);
2687 303989 : return gen_powu(x,n,(void*)&D,Flxq_autpow_sqr,Flxq_autpow_mul);
2688 : }
2689 :
2690 : static GEN
2691 612971 : Flxq_autsum_mul(void *E, GEN x, GEN y)
2692 : {
2693 612971 : struct _Flxq *D = (struct _Flxq*)E;
2694 612971 : GEN T = D->T;
2695 612971 : ulong p = D->p;
2696 612971 : GEN phi1 = gel(x,1), a1 = gel(x,2);
2697 612971 : GEN phi2 = gel(y,1), a2 = gel(y,2);
2698 612971 : ulong d = brent_kung_optpow(maxss(degpol(phi1),degpol(a1)),2,1);
2699 612971 : GEN V2 = Flxq_powers(phi2, d, T, p);
2700 612971 : GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p);
2701 612971 : GEN aphi = Flx_FlxqV_eval(a1, V2, T, p);
2702 612971 : GEN a3 = Flxq_mul(aphi, a2, T, p);
2703 612971 : return mkvec2(phi3, a3);
2704 : }
2705 : static GEN
2706 364936 : Flxq_autsum_sqr(void *E, GEN x)
2707 364936 : { return Flxq_autsum_mul(E, x, x); }
2708 :
2709 : GEN
2710 306052 : Flxq_autsum(GEN x, ulong n, GEN T, ulong p)
2711 : {
2712 : struct _Flxq D;
2713 306052 : D.T = Flx_get_red(T, p); D.p = p;
2714 306052 : return gen_powu(x,n,(void*)&D,Flxq_autsum_sqr,Flxq_autsum_mul);
2715 : }
2716 :
2717 : static GEN
2718 204702 : Flxq_auttrace_mul(void *E, GEN x, GEN y)
2719 : {
2720 204702 : struct _Flxq *D = (struct _Flxq*)E;
2721 204702 : GEN T = D->T;
2722 204702 : ulong p = D->p;
2723 204702 : GEN phi1 = gel(x,1), a1 = gel(x,2);
2724 204702 : GEN phi2 = gel(y,1), a2 = gel(y,2);
2725 204702 : ulong d = brent_kung_optpow(maxss(degpol(phi1),degpol(a1)),2,1);
2726 204702 : GEN V1 = Flxq_powers(phi1, d, T, p);
2727 204702 : GEN phi3 = Flx_FlxqV_eval(phi2, V1, T, p);
2728 204702 : GEN aphi = Flx_FlxqV_eval(a2, V1, T, p);
2729 204702 : GEN a3 = Flx_add(a1, aphi, p);
2730 204702 : return mkvec2(phi3, a3);
2731 : }
2732 :
2733 : static GEN
2734 161320 : Flxq_auttrace_sqr(void *E, GEN x)
2735 161320 : { return Flxq_auttrace_mul(E, x, x); }
2736 :
2737 : GEN
2738 214396 : Flxq_auttrace(GEN x, ulong n, GEN T, ulong p)
2739 : {
2740 : struct _Flxq D;
2741 214396 : D.T = Flx_get_red(T, p); D.p = p;
2742 214396 : return gen_powu(x,n,(void*)&D,Flxq_auttrace_sqr,Flxq_auttrace_mul);
2743 : }
2744 :
2745 : static long
2746 661916 : bounded_order(ulong p, GEN b, long k)
2747 : {
2748 : long i;
2749 661916 : GEN a=modii(utoi(p),b);
2750 1684381 : for(i=1;i<k;i++)
2751 : {
2752 1396247 : if (equali1(a))
2753 373782 : return i;
2754 1022465 : a = modii(muliu(a,p),b);
2755 : }
2756 288134 : return 0;
2757 : }
2758 :
2759 : /*
2760 : n = (p^d-a)\b
2761 : b = bb*p^vb
2762 : p^k = 1 [bb]
2763 : d = m*k+r+vb
2764 : u = (p^k-1)/bb;
2765 : v = (p^(r+vb)-a)/b;
2766 : w = (p^(m*k)-1)/(p^k-1)
2767 : n = p^r*w*u+v
2768 : w*u = p^vb*(p^(m*k)-1)/b
2769 : n = p^(r+vb)*(p^(m*k)-1)/b+(p^(r+vb)-a)/b
2770 : */
2771 :
2772 : static GEN
2773 17780745 : Flxq_pow_Frobenius(GEN x, GEN n, GEN aut, GEN T, ulong p)
2774 : {
2775 17780745 : pari_sp av=avma;
2776 17780745 : long d = get_Flx_degree(T);
2777 17780745 : GEN an = absi(n), z, q;
2778 17780745 : if (abscmpiu(an,p)<0 || cmpis(an,d)<=0)
2779 17117982 : return Flxq_pow(x, n, T, p);
2780 662763 : q = powuu(p, d);
2781 662763 : if (dvdii(q, n))
2782 : {
2783 798 : long vn = logint(an,utoi(p));
2784 798 : GEN autvn = vn==1 ? aut: Flxq_autpow(aut,vn,T,p);
2785 798 : z = Flx_Flxq_eval(x,autvn,T,p);
2786 : } else
2787 : {
2788 661965 : GEN b = diviiround(q, an), a = subii(q, mulii(an,b));
2789 : GEN bb, u, v, autk;
2790 661965 : long vb = Z_lvalrem(b,p,&bb);
2791 661965 : long m, r, k = is_pm1(bb) ? 1 : bounded_order(p,bb,d);
2792 661965 : if (!k || d-vb<k) return Flxq_pow(x,n, T, p);
2793 373824 : m = (d-vb)/k; r = (d-vb)%k;
2794 373824 : u = diviiexact(subiu(powuu(p,k),1),bb);
2795 373824 : v = diviiexact(subii(powuu(p,r+vb),a),b);
2796 373824 : autk = k==1 ? aut: Flxq_autpow(aut,k,T,p);
2797 373824 : if (r)
2798 : {
2799 93723 : GEN autr = r==1 ? aut: Flxq_autpow(aut,r,T,p);
2800 93723 : z = Flx_Flxq_eval(x,autr,T,p);
2801 280101 : } else z = x;
2802 373824 : if (m > 1) z = gel(Flxq_autsum(mkvec2(autk, z), m, T, p), 2);
2803 373824 : if (!is_pm1(u)) z = Flxq_pow(z, u, T, p);
2804 373824 : if (signe(v)) z = Flxq_mul(z, Flxq_pow(x, v, T, p), T, p);
2805 : }
2806 374622 : return gerepileupto(av,signe(n)>0 ? z : Flxq_inv(z,T,p));
2807 : }
2808 :
2809 : static GEN
2810 17762186 : _Flxq_pow(void *data, GEN x, GEN n)
2811 : {
2812 17762186 : struct _Flxq *D = (struct _Flxq*)data;
2813 17762186 : return Flxq_pow_Frobenius(x, n, D->aut, D->T, D->p);
2814 : }
2815 :
2816 : static GEN
2817 317451 : _Flxq_rand(void *data)
2818 : {
2819 317451 : pari_sp av=avma;
2820 317451 : struct _Flxq *D = (struct _Flxq*)data;
2821 : GEN z;
2822 : do
2823 : {
2824 320408 : avma = av;
2825 320408 : z = random_Flx(get_Flx_degree(D->T),get_Flx_var(D->T),D->p);
2826 320408 : } while (lgpol(z)==0);
2827 317451 : return z;
2828 : }
2829 :
2830 : /* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */
2831 : static GEN
2832 10892 : Fl_Flxq_log(ulong a, GEN g, GEN o, GEN T, ulong p)
2833 : {
2834 10892 : pari_sp av = avma;
2835 : GEN q,n_q,ord,ordp, op;
2836 :
2837 10892 : if (a == 1UL) return gen_0;
2838 : /* p > 2 */
2839 :
2840 10892 : ordp = utoi(p - 1);
2841 10892 : ord = get_arith_Z(o);
2842 10892 : if (!ord) ord = T? subiu(powuu(p, get_FpX_degree(T)), 1): ordp;
2843 10892 : if (a == p - 1) /* -1 */
2844 761 : return gerepileuptoint(av, shifti(ord,-1));
2845 10131 : ordp = gcdii(ordp, ord);
2846 10131 : op = typ(o)==t_MAT ? famat_Z_gcd(o, ordp) : ordp;
2847 :
2848 10131 : q = NULL;
2849 10131 : if (T)
2850 : { /* we want < g > = Fp^* */
2851 10131 : if (!equalii(ord,ordp)) {
2852 563 : q = diviiexact(ord,ordp);
2853 563 : g = Flxq_pow(g,q,T,p);
2854 : }
2855 : }
2856 10131 : n_q = Fp_log(utoi(a), utoi(uel(g,2)), op, utoi(p));
2857 10131 : if (lg(n_q)==1) return gerepileuptoleaf(av, n_q);
2858 10131 : if (q) n_q = mulii(q, n_q);
2859 10131 : return gerepileuptoint(av, n_q);
2860 : }
2861 :
2862 : static GEN
2863 320389 : Flxq_easylog(void* E, GEN a, GEN g, GEN ord)
2864 : {
2865 320389 : struct _Flxq *f = (struct _Flxq *)E;
2866 320389 : GEN T = f->T;
2867 320389 : ulong p = f->p;
2868 320389 : long d = get_Flx_degree(T);
2869 320389 : if (Flx_equal1(a)) return gen_0;
2870 268986 : if (Flx_equal(a,g)) return gen_1;
2871 59025 : if (!degpol(a))
2872 10892 : return Fl_Flxq_log(uel(a,2), g, ord, T, p);
2873 48133 : if (typ(ord)!=t_INT || d <= 4 || d == 6 || abscmpiu(ord,1UL<<27)<0)
2874 48112 : return NULL;
2875 21 : return Flxq_log_index(a, g, ord, T, p);
2876 : }
2877 :
2878 : int
2879 19169775 : Flx_equal(GEN V, GEN W)
2880 : {
2881 19169775 : long l = lg(V);
2882 19169775 : if (lg(W) != l) return 0;
2883 38161789 : while (--l > 1) /* do not compare variables, V[1] */
2884 19000322 : if (V[l] != W[l]) return 0;
2885 602766 : return 1;
2886 : }
2887 :
2888 : static const struct bb_group Flxq_star={_Flxq_mul,_Flxq_pow,_Flxq_rand,hash_GEN,Flx_equal,Flx_equal1,Flxq_easylog};
2889 :
2890 : const struct bb_group *
2891 213342 : get_Flxq_star(void **E, GEN T, ulong p)
2892 : {
2893 213342 : struct _Flxq *e = (struct _Flxq *) stack_malloc(sizeof(struct _Flxq));
2894 213342 : e->T = T; e->p = p; e->aut = Flx_Frobenius(T, p);
2895 213342 : *E = (void*)e; return &Flxq_star;
2896 : }
2897 :
2898 : GEN
2899 12580 : Flxq_order(GEN a, GEN ord, GEN T, ulong p)
2900 : {
2901 : void *E;
2902 12580 : const struct bb_group *S = get_Flxq_star(&E,T,p);
2903 12580 : return gen_order(a,ord,E,S);
2904 : }
2905 :
2906 : GEN
2907 35090 : Flxq_log(GEN a, GEN g, GEN ord, GEN T, ulong p)
2908 : {
2909 : void *E;
2910 35090 : pari_sp av = avma;
2911 35090 : const struct bb_group *S = get_Flxq_star(&E,T,p);
2912 35090 : GEN v = get_arith_ZZM(ord), F = gmael(v,2,1);
2913 35090 : if (Flxq_log_use_index(gel(F,lg(F)-1), T, p))
2914 9163 : v = mkvec2(gel(v, 1), ZM_famat_limit(gel(v, 2), int2n(27)));
2915 35090 : return gerepileuptoleaf(av, gen_PH_log(a, g, v, E, S));
2916 : }
2917 :
2918 : GEN
2919 168787 : Flxq_sqrtn(GEN a, GEN n, GEN T, ulong p, GEN *zeta)
2920 : {
2921 168787 : if (!lgpol(a))
2922 : {
2923 3115 : if (signe(n) < 0) pari_err_INV("Flxq_sqrtn",a);
2924 3108 : if (zeta)
2925 0 : *zeta=pol1_Flx(get_Flx_var(T));
2926 3108 : return pol0_Flx(get_Flx_var(T));
2927 : }
2928 : else
2929 : {
2930 : void *E;
2931 165672 : pari_sp av = avma;
2932 165672 : const struct bb_group *S = get_Flxq_star(&E,T,p);
2933 165672 : GEN o = subiu(powuu(p,get_Flx_degree(T)), 1);
2934 165672 : GEN s = gen_Shanks_sqrtn(a,n,o,zeta,E,S);
2935 165672 : if (s) gerepileall(av, zeta?2:1, &s, zeta);
2936 165672 : return s;
2937 : }
2938 : }
2939 :
2940 : GEN
2941 160874 : Flxq_sqrt(GEN a, GEN T, ulong p)
2942 : {
2943 160874 : return Flxq_sqrtn(a, gen_2, T, p, NULL);
2944 : }
2945 :
2946 : /* assume T irreducible mod p */
2947 : int
2948 358983 : Flxq_issquare(GEN x, GEN T, ulong p)
2949 : {
2950 358983 : if (lgpol(x) == 0 || p == 2) return 1;
2951 355728 : return krouu(Flxq_norm(x,T,p), p) == 1;
2952 : }
2953 :
2954 : /* assume T irreducible mod p */
2955 : int
2956 280 : Flxq_is2npower(GEN x, long n, GEN T, ulong p)
2957 : {
2958 : pari_sp av;
2959 : GEN m;
2960 : int z;
2961 280 : if (n==1) return Flxq_issquare(x, T, p);
2962 280 : if (lgpol(x) == 0 || p == 2) return 1;
2963 280 : av = avma;
2964 280 : m = shifti(subiu(powuu(p, get_Flx_degree(T)), 1), -n);
2965 280 : z = Flx_equal1(Flxq_pow(x, m, T, p));
2966 280 : avma = av; return z;
2967 : }
2968 :
2969 : GEN
2970 113505 : Flxq_lroot_fast(GEN a, GEN sqx, GEN T, long p)
2971 : {
2972 113505 : pari_sp av=avma;
2973 113505 : GEN A = Flx_splitting(a,p);
2974 113505 : return gerepileuptoleaf(av, FlxqV_dotproduct(A,sqx,T,p));
2975 : }
2976 :
2977 : GEN
2978 25032 : Flxq_lroot(GEN a, GEN T, long p)
2979 : {
2980 25032 : pari_sp av=avma;
2981 25032 : long n = get_Flx_degree(T), d = degpol(a);
2982 : GEN sqx, V;
2983 25032 : if (n==1) return leafcopy(a);
2984 25032 : if (n==2) return Flxq_powu(a, p, T, p);
2985 25032 : sqx = Flxq_autpow(Flx_Frobenius(T, p), n-1, T, p);
2986 25032 : if (d==1 && a[2]==0 && a[3]==1) return gerepileuptoleaf(av, sqx);
2987 0 : if (d>=p)
2988 : {
2989 0 : V = Flxq_powers(sqx,p-1,T,p);
2990 0 : return gerepileuptoleaf(av, Flxq_lroot_fast(a,V,T,p));
2991 : } else
2992 0 : return gerepileuptoleaf(av, Flx_Flxq_eval(a,sqx,T,p));
2993 : }
2994 :
2995 : ulong
2996 385659 : Flxq_norm(GEN x, GEN TB, ulong p)
2997 : {
2998 385659 : GEN T = get_Flx_mod(TB);
2999 385659 : ulong y = Flx_resultant(T, x, p);
3000 385659 : ulong L = Flx_lead(T);
3001 385659 : if ( L==1 || lgpol(x)==0) return y;
3002 0 : return Fl_div(y, Fl_powu(L, (ulong)degpol(x), p), p);
3003 : }
3004 :
3005 : ulong
3006 3310 : Flxq_trace(GEN x, GEN TB, ulong p)
3007 : {
3008 3310 : pari_sp av = avma;
3009 : ulong t;
3010 3310 : GEN T = get_Flx_mod(TB);
3011 3310 : long n = degpol(T)-1;
3012 3310 : GEN z = Flxq_mul(x, Flx_deriv(T, p), TB, p);
3013 3310 : t = degpol(z)<n ? 0 : Fl_div(z[2+n],T[3+n],p);
3014 3310 : avma=av;
3015 3310 : return t;
3016 : }
3017 :
3018 : /*x must be reduced*/
3019 : GEN
3020 27 : Flxq_charpoly(GEN x, GEN TB, ulong p)
3021 : {
3022 27 : pari_sp ltop=avma;
3023 27 : GEN T = get_Flx_mod(TB);
3024 27 : long vs = evalvarn(fetch_var());
3025 27 : GEN xm1 = deg1pol_shallow(pol1_Flx(x[1]),Flx_neg(x,p),vs);
3026 27 : GEN r = Flx_FlxY_resultant(T, xm1, p);
3027 27 : r[1] = x[1];
3028 27 : (void)delete_var(); return gerepileupto(ltop, r);
3029 : }
3030 :
3031 : /* Computing minimal polynomial : */
3032 : /* cf Shoup 'Efficient Computation of Minimal Polynomials */
3033 : /* in Algebraic Extensions of Finite Fields' */
3034 :
3035 : GEN
3036 677263 : Flxn_mul(GEN a, GEN b, long n, ulong p)
3037 : {
3038 677263 : GEN c = Flx_mul(a, b, p);
3039 677263 : return vecsmall_shorten(c, minss(lg(c)-1,n+1));
3040 : }
3041 :
3042 : /* Let v a linear form, return the linear form z->v(tau*z)
3043 : that is, v*(M_tau) */
3044 :
3045 : static GEN
3046 349632 : Flxq_transmul_init(GEN tau, GEN T, ulong p)
3047 : {
3048 : GEN bht;
3049 349632 : GEN h, Tp = get_Flx_red(T, &h);
3050 349632 : long n = degpol(Tp), vT = Tp[1];
3051 349632 : GEN ft = Flx_recipspec(Tp+2, n+1, n+1);
3052 349632 : GEN bt = Flx_recipspec(tau+2, lgpol(tau), n);
3053 349632 : ft[1] = vT; bt[1] = vT;
3054 349632 : if (h)
3055 2218 : bht = Flxn_mul(bt, h, n-1, p);
3056 : else
3057 : {
3058 347414 : GEN bh = Flx_div(Flx_shift(tau, n-1), T, p);
3059 347414 : bht = Flx_recipspec(bh+2, lgpol(bh), n-1);
3060 347414 : bht[1] = vT;
3061 : }
3062 349632 : return mkvec3(bt, bht, ft);
3063 : }
3064 :
3065 : static GEN
3066 886517 : Flxq_transmul(GEN tau, GEN a, long n, ulong p)
3067 : {
3068 886517 : pari_sp ltop = avma;
3069 : GEN t1, t2, t3, vec;
3070 886517 : GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
3071 886517 : if (lgpol(a)==0) return pol0_Flx(a[1]);
3072 877325 : t2 = Flx_shift(Flx_mul(bt, a, p),1-n);
3073 877325 : if (lgpol(bht)==0) return gerepileuptoleaf(ltop, t2);
3074 664062 : t1 = Flx_shift(Flx_mul(ft, a, p),-n);
3075 664062 : t3 = Flxn_mul(t1, bht, n-1, p);
3076 664062 : vec = Flx_sub(t2, Flx_shift(t3, 1), p);
3077 664062 : return gerepileuptoleaf(ltop, vec);
3078 : }
3079 :
3080 : GEN
3081 160777 : Flxq_minpoly(GEN x, GEN T, ulong p)
3082 : {
3083 160777 : pari_sp ltop = avma;
3084 160777 : long vT = get_Flx_var(T), n = get_Flx_degree(T);
3085 : GEN v_x;
3086 160777 : GEN g = pol1_Flx(vT), tau = pol1_Flx(vT);
3087 160777 : T = Flx_get_red(T, p);
3088 160777 : v_x = Flxq_powers(x, usqrt(2*n), T, p);
3089 496370 : while (lgpol(tau) != 0)
3090 : {
3091 : long i, j, m, k1;
3092 : GEN M, v, tr;
3093 : GEN g_prime, c;
3094 174816 : if (degpol(g) == n) { tau = pol1_Flx(vT); g = pol1_Flx(vT); }
3095 174816 : v = random_Flx(n, vT, p);
3096 174816 : tr = Flxq_transmul_init(tau, T, p);
3097 174816 : v = Flxq_transmul(tr, v, n, p);
3098 174816 : m = 2*(n-degpol(g));
3099 174816 : k1 = usqrt(m);
3100 174816 : tr = Flxq_transmul_init(gel(v_x,k1+1), T, p);
3101 174816 : c = cgetg(m+2,t_VECSMALL);
3102 174816 : c[1] = T[1];
3103 886517 : for (i=0; i<m; i+=k1)
3104 : {
3105 711701 : long mj = minss(m-i, k1);
3106 2938331 : for (j=0; j<mj; j++)
3107 2226630 : uel(c,m+1-(i+j)) = Flx_dotproduct(v, gel(v_x,j+1), p);
3108 711701 : v = Flxq_transmul(tr, v, n, p);
3109 : }
3110 174816 : c = Flx_renormalize(c, m+2);
3111 : /* now c contains <v,x^i> , i = 0..m-1 */
3112 174816 : M = Flx_halfgcd(monomial_Flx(1, m, vT), c, p);
3113 174816 : g_prime = gmael(M, 2, 2);
3114 174816 : if (degpol(g_prime) < 1) continue;
3115 171528 : g = Flx_mul(g, g_prime, p);
3116 171528 : tau = Flxq_mul(tau, Flx_FlxqV_eval(g_prime, v_x, T, p), T, p);
3117 : }
3118 160777 : g = Flx_normalize(g,p);
3119 160777 : return gerepileuptoleaf(ltop,g);
3120 : }
3121 :
3122 : /* return (x % X^n). Shallow */
3123 : static GEN
3124 686 : Flxn_red_shallow(GEN a, long n)
3125 : {
3126 686 : long i, L, l = lg(a);
3127 : GEN b;
3128 686 : if (l == 2 || !n) return zero_Flx(a[1]);
3129 686 : L = n+2; if (L > l) L = l;
3130 686 : b = cgetg(L, t_POL); b[1] = a[1];
3131 686 : for (i=2; i<L; i++) b[i] = a[i];
3132 686 : return Flx_renormalize(b,L);
3133 : }
3134 : GEN
3135 112 : Flxn_inv(GEN f, long e, ulong p)
3136 : {
3137 112 : pari_sp av = avma, av2;
3138 : ulong mask;
3139 : GEN W;
3140 112 : long n=1;
3141 112 : if (lg(f)==2) pari_err_INV("Flxn_inv",f);
3142 112 : W = Fl_to_Flx(Fl_inv(f[2],p), f[1]);
3143 112 : mask = quadratic_prec_mask(e);
3144 112 : av2 = avma;
3145 910 : for (;mask>1;)
3146 : {
3147 : GEN u, fr;
3148 686 : long n2 = n;
3149 686 : n<<=1; if (mask & 1) n--;
3150 686 : mask >>= 1;
3151 686 : fr = Flxn_red_shallow(f, n);
3152 686 : u = Flx_shift(Flxn_mul(W, fr, n, p), -n2);
3153 686 : W = Flx_sub(W, Flx_shift(Flxn_mul(u, W, n-n2, p), n2), p);
3154 686 : if (gc_needed(av2,2))
3155 : {
3156 0 : if(DEBUGMEM>1) pari_warn(warnmem,"RgXn_inv, e = %ld", n);
3157 0 : W = gerepileupto(av2, W);
3158 : }
3159 : }
3160 112 : return gerepileupto(av, W);
3161 : }
3162 :
3163 : GEN
3164 20 : Flxq_conjvec(GEN x, GEN T, ulong p)
3165 : {
3166 20 : long i, l = 1+get_Flx_degree(T);
3167 20 : GEN z = cgetg(l,t_COL);
3168 20 : T = Flx_get_red(T,p);
3169 20 : gel(z,1) = Flx_copy(x);
3170 20 : for (i=2; i<l; i++) gel(z,i) = Flxq_powu(gel(z,i-1), p, T, p);
3171 20 : return z;
3172 : }
3173 :
3174 : GEN
3175 9224 : gener_Flxq(GEN T, ulong p, GEN *po)
3176 : {
3177 : long i, j;
3178 9224 : long vT = get_Flx_var(T), f =get_Flx_degree(T);
3179 : ulong p_1;
3180 : GEN g, L, L2, o, q, F;
3181 : pari_sp av0, av;
3182 :
3183 9224 : if (f == 1) {
3184 : GEN fa;
3185 28 : o = utoipos(p-1);
3186 28 : fa = Z_factor(o);
3187 28 : L = gel(fa,1);
3188 28 : L = vecslice(L, 2, lg(L)-1); /* remove 2 for efficiency */
3189 28 : g = Fl_to_Flx(pgener_Fl_local(p, vec_to_vecsmall(L)), vT);
3190 28 : if (po) *po = mkvec2(o, fa);
3191 28 : return g;
3192 : }
3193 :
3194 9196 : av0 = avma; p_1 = p - 1;
3195 9196 : q = diviuexact(subiu(powuu(p,f), 1), p_1);
3196 :
3197 9196 : L = cgetg(1, t_VECSMALL);
3198 9196 : if (p > 3)
3199 : {
3200 : ulong t;
3201 1111 : (void)u_lvalrem(p_1, 2, &t);
3202 1111 : L = gel(factoru(t),1);
3203 1111 : for (i=lg(L)-1; i; i--) L[i] = p_1 / L[i];
3204 : }
3205 9196 : o = factor_pn_1(utoipos(p),f);
3206 9196 : L2 = leafcopy( gel(o, 1) );
3207 25323 : for (i = j = 1; i < lg(L2); i++)
3208 : {
3209 16127 : if (umodui(p_1, gel(L2,i)) == 0) continue;
3210 13334 : gel(L2,j++) = diviiexact(q, gel(L2,i));
3211 : }
3212 9196 : setlg(L2, j);
3213 9196 : F = Flx_Frobenius(T, p);
3214 20369 : for (av = avma;; avma = av)
3215 : {
3216 : GEN tt;
3217 20369 : g = random_Flx(f, vT, p);
3218 20369 : if (degpol(g) < 1) continue;
3219 15407 : if (p == 2) tt = g;
3220 : else
3221 : {
3222 4879 : ulong t = Flxq_norm(g, T, p);
3223 4879 : if (t == 1 || !is_gener_Fl(t, p, p_1, L)) continue;
3224 2619 : tt = Flxq_powu(g, p_1>>1, T, p);
3225 : }
3226 27755 : for (i = 1; i < j; i++)
3227 : {
3228 18559 : GEN a = Flxq_pow_Frobenius(tt, gel(L2,i), F, T, p);
3229 18559 : if (!degpol(a) && uel(a,2) == p_1) break;
3230 : }
3231 13147 : if (i == j) break;
3232 11173 : }
3233 9196 : if (!po)
3234 : {
3235 173 : avma = (pari_sp)g;
3236 173 : g = gerepileuptoleaf(av0, g);
3237 : }
3238 : else {
3239 9023 : *po = mkvec2(subiu(powuu(p,f), 1), o);
3240 9023 : gerepileall(av0, 2, &g, po);
3241 : }
3242 9196 : return g;
3243 : }
3244 :
3245 : static GEN
3246 6517 : _Flxq_neg(void *E, GEN x)
3247 6517 : { struct _Flxq *s = (struct _Flxq *)E;
3248 6517 : return Flx_neg(x,s->p); }
3249 :
3250 : static GEN
3251 111125 : _Flxq_rmul(void *E, GEN x, GEN y)
3252 111125 : { struct _Flxq *s = (struct _Flxq *)E;
3253 111125 : return Flx_mul(x,y,s->p); }
3254 :
3255 : static GEN
3256 6118 : _Flxq_inv(void *E, GEN x)
3257 6118 : { struct _Flxq *s = (struct _Flxq *)E;
3258 6118 : return Flxq_inv(x,s->T,s->p); }
3259 :
3260 : static int
3261 42777 : _Flxq_equal0(GEN x) { return lgpol(x)==0; }
3262 :
3263 : static GEN
3264 12761 : _Flxq_s(void *E, long x)
3265 12761 : { struct _Flxq *s = (struct _Flxq *)E;
3266 12761 : ulong u = x<0 ? s->p+x: (ulong)x;
3267 12761 : return Fl_to_Flx(u, get_Flx_var(s->T));
3268 : }
3269 :
3270 : static const struct bb_field Flxq_field={_Flxq_red,_Flx_add,_Flxq_rmul,_Flxq_neg,
3271 : _Flxq_inv,_Flxq_equal0,_Flxq_s};
3272 :
3273 6958 : const struct bb_field *get_Flxq_field(void **E, GEN T, ulong p)
3274 : {
3275 6958 : GEN z = new_chunk(sizeof(struct _Flxq));
3276 6958 : struct _Flxq *e = (struct _Flxq *) z;
3277 6958 : e->T = Flx_get_red(T, p); e->p = p; *E = (void*)e;
3278 6958 : return &Flxq_field;
3279 : }
3280 :
3281 : /***********************************************************************/
3282 : /** **/
3283 : /** Fl2 **/
3284 : /** **/
3285 : /***********************************************************************/
3286 : /* Fl2 objects are Flv of length 2 [a,b] representing a+bsqrt(D) for
3287 : a non-square D.
3288 : */
3289 :
3290 : INLINE GEN
3291 6221791 : mkF2(ulong a, ulong b) { return mkvecsmall2(a,b); }
3292 :
3293 : GEN
3294 1670568 : Fl2_mul_pre(GEN x, GEN y, ulong D, ulong p, ulong pi)
3295 : {
3296 : ulong xaya, xbyb, Db2, mid;
3297 : ulong z1, z2;
3298 1670568 : ulong x1 = x[1], x2 = x[2], y1 = y[1], y2 = y[2];
3299 1670568 : xaya = Fl_mul_pre(x1,y1,p,pi);
3300 1670627 : if (x2==0 && y2==0) return mkF2(xaya,0);
3301 1617126 : if (x2==0) return mkF2(xaya,Fl_mul_pre(x1,y2,p,pi));
3302 1596501 : if (y2==0) return mkF2(xaya,Fl_mul_pre(x2,y1,p,pi));
3303 1596231 : xbyb = Fl_mul_pre(x2,y2,p,pi);
3304 1596244 : mid = Fl_mul_pre(Fl_add(x1,x2,p), Fl_add(y1,y2,p),p,pi);
3305 1596245 : Db2 = Fl_mul_pre(D, xbyb, p,pi);
3306 1596253 : z1 = Fl_add(xaya,Db2,p);
3307 1596189 : z2 = Fl_sub(mid,Fl_add(xaya,xbyb,p),p);
3308 1596152 : return mkF2(z1,z2);
3309 : }
3310 :
3311 : GEN
3312 4216302 : Fl2_sqr_pre(GEN x, ulong D, ulong p, ulong pi)
3313 : {
3314 4216302 : ulong a = x[1], b = x[2];
3315 : ulong a2, Db2, ab;
3316 4216302 : a2 = Fl_sqr_pre(a,p,pi);
3317 4216718 : if (b==0) return mkF2(a2,0);
3318 4042723 : Db2= Fl_mul_pre(D, Fl_sqr_pre(b,p,pi), p,pi);
3319 4042861 : ab = Fl_mul_pre(a,b,p,pi);
3320 4042859 : return mkF2(Fl_add(a2,Db2,p), Fl_double(ab,p));
3321 : }
3322 :
3323 : ulong
3324 65852 : Fl2_norm_pre(GEN x, ulong D, ulong p, ulong pi)
3325 : {
3326 65852 : ulong a2 = Fl_sqr_pre(x[1],p,pi);
3327 65852 : return x[2]? Fl_sub(a2, Fl_mul_pre(D, Fl_sqr_pre(x[2], p,pi), p,pi), p): a2;
3328 : }
3329 :
3330 : GEN
3331 165913 : Fl2_inv_pre(GEN x, ulong D, ulong p, ulong pi)
3332 : {
3333 : ulong n, ni;
3334 165913 : if (x[2] == 0) return mkF2(Fl_inv(x[1],p),0);
3335 142087 : n = Fl_sub(Fl_sqr_pre(x[1], p,pi),
3336 142087 : Fl_mul_pre(D, Fl_sqr_pre(x[2], p,pi), p,pi), p);
3337 142089 : ni = Fl_inv(n,p);
3338 142088 : return mkF2(Fl_mul_pre(x[1], ni, p,pi),
3339 142088 : Fl_neg(Fl_mul_pre(x[2], ni, p,pi), p));
3340 : }
3341 :
3342 : int
3343 376647 : Fl2_equal1(GEN x) { return x[1]==1 && x[2]==0; }
3344 :
3345 : struct _Fl2 {
3346 : ulong p, pi, D;
3347 : };
3348 :
3349 :
3350 : static GEN
3351 4215947 : _Fl2_sqr(void *data, GEN x)
3352 : {
3353 4215947 : struct _Fl2 *D = (struct _Fl2*)data;
3354 4215947 : return Fl2_sqr_pre(x, D->D, D->p, D->pi);
3355 : }
3356 : static GEN
3357 1642772 : _Fl2_mul(void *data, GEN x, GEN y)
3358 : {
3359 1642772 : struct _Fl2 *D = (struct _Fl2*)data;
3360 1642772 : return Fl2_mul_pre(x,y, D->D, D->p, D->pi);
3361 : }
3362 :
3363 : /* n-Power of x in Z/pZ[X]/(T), as t_VECSMALL. */
3364 : GEN
3365 563511 : Fl2_pow_pre(GEN x, GEN n, ulong D, ulong p, ulong pi)
3366 : {
3367 563511 : pari_sp av = avma;
3368 : struct _Fl2 d;
3369 : GEN y;
3370 563511 : long s = signe(n);
3371 563511 : if (!s) return mkF2(1,0);
3372 499388 : if (s < 0)
3373 165912 : x = Fl2_inv_pre(x,D,p,pi);
3374 499383 : if (is_pm1(n)) return s < 0 ? x : zv_copy(x);
3375 367290 : d.p = p; d.pi = pi; d.D=D;
3376 367290 : y = gen_pow_i(x, n, (void*)&d, &_Fl2_sqr, &_Fl2_mul);
3377 367283 : return gerepileuptoleaf(av, y);
3378 : }
3379 :
3380 : static GEN
3381 563500 : _Fl2_pow(void *data, GEN x, GEN n)
3382 : {
3383 563500 : struct _Fl2 *D = (struct _Fl2*)data;
3384 563500 : return Fl2_pow_pre(x, n, D->D, D->p, D->pi);
3385 : }
3386 :
3387 : static GEN
3388 95681 : _Fl2_rand(void *data)
3389 : {
3390 95681 : struct _Fl2 *D = (struct _Fl2*)data;
3391 95681 : ulong a = random_Fl(D->p), b=random_Fl(D->p-1)+1;
3392 95683 : return mkF2(a,b);
3393 : }
3394 :
3395 : static const struct bb_group Fl2_star={_Fl2_mul, _Fl2_pow, _Fl2_rand,
3396 : hash_GEN, zv_equal, Fl2_equal1, NULL};
3397 :
3398 : GEN
3399 64122 : Fl2_sqrtn_pre(GEN a, GEN n, ulong D, ulong p, ulong pi, GEN *zeta)
3400 : {
3401 : struct _Fl2 E;
3402 : GEN o;
3403 64122 : if (a[1]==0 && a[2]==0)
3404 : {
3405 0 : if (signe(n) < 0) pari_err_INV("Flxq_sqrtn",a);
3406 0 : if (zeta) *zeta=mkF2(1,0);
3407 0 : return zv_copy(a);
3408 : }
3409 64122 : E.p=p; E.pi = pi; E.D = D;
3410 64122 : o = subiu(powuu(p,2), 1);
3411 64122 : return gen_Shanks_sqrtn(a,n,o,zeta,(void*)&E,&Fl2_star);
3412 : }
3413 :
3414 : GEN
3415 10108 : Flx_Fl2_eval_pre(GEN x, GEN y, ulong D, ulong p, ulong pi)
3416 : {
3417 : GEN p1;
3418 10108 : long i = lg(x)-1;
3419 10108 : if (i <= 2)
3420 1883 : return mkF2(i == 2? x[2]: 0, 0);
3421 8225 : p1 = mkF2(x[i], 0);
3422 35952 : for (i--; i>=2; i--)
3423 : {
3424 27727 : p1 = Fl2_mul_pre(p1, y, D, p, pi);
3425 27727 : uel(p1,1) = Fl_add(uel(p1,1), uel(x,i), p);
3426 : }
3427 8225 : return p1;
3428 : }
3429 :
3430 :
3431 : /***********************************************************************/
3432 : /** **/
3433 : /** FlxV **/
3434 : /** **/
3435 : /***********************************************************************/
3436 : /* FlxV are t_VEC with Flx coefficients. */
3437 :
3438 : GEN
3439 0 : FlxV_Flc_mul(GEN V, GEN W, ulong p)
3440 : {
3441 0 : pari_sp ltop=avma;
3442 : long i;
3443 0 : GEN z = Flx_Fl_mul(gel(V,1),W[1],p);
3444 0 : for(i=2;i<lg(V);i++)
3445 0 : z=Flx_add(z,Flx_Fl_mul(gel(V,i),W[i],p),p);
3446 0 : return gerepileuptoleaf(ltop,z);
3447 : }
3448 :
3449 : GEN
3450 0 : ZXV_to_FlxV(GEN x, ulong p)
3451 0 : { pari_APPLY_type(t_VEC, ZX_to_Flx(gel(x,i), p)) }
3452 :
3453 : GEN
3454 1408340 : ZXT_to_FlxT(GEN x, ulong p)
3455 : {
3456 1408340 : if (typ(x) == t_POL)
3457 1353461 : return ZX_to_Flx(x, p);
3458 : else
3459 54879 : pari_APPLY_type(t_VEC, ZXT_to_FlxT(gel(x,i), p))
3460 : }
3461 :
3462 : GEN
3463 32865 : FlxV_to_Flm(GEN x, long n)
3464 32865 : { pari_APPLY_type(t_MAT, Flx_to_Flv(gel(x,i), n)) }
3465 :
3466 : GEN
3467 0 : FlxV_red(GEN x, ulong p)
3468 0 : { pari_APPLY_type(t_VEC, Flx_red(gel(x,i), p)) }
3469 :
3470 : GEN
3471 317732 : FlxT_red(GEN x, ulong p)
3472 : {
3473 317732 : if (typ(x) == t_VECSMALL)
3474 213622 : return Flx_red(x, p);
3475 : else
3476 104110 : pari_APPLY_type(t_VEC, FlxT_red(gel(x,i), p))
3477 : }
3478 :
3479 : GEN
3480 113505 : FlxqV_dotproduct(GEN x, GEN y, GEN T, ulong p)
3481 : {
3482 113505 : long i, lx = lg(x);
3483 : pari_sp av;
3484 : GEN c;
3485 113505 : if (lx == 1) return gen_0;
3486 113505 : av = avma; c = Flx_mul(gel(x,1),gel(y,1), p);
3487 113505 : for (i=2; i<lx; i++) c = Flx_add(c, Flx_mul(gel(x,i),gel(y,i), p), p);
3488 113505 : return gerepileuptoleaf(av, Flx_rem(c,T,p));
3489 : }
3490 :
3491 : GEN
3492 968 : FlxqX_dotproduct(GEN x, GEN y, GEN T, ulong p)
3493 : {
3494 968 : long i, l = minss(lg(x), lg(y));
3495 : pari_sp av;
3496 : GEN c;
3497 968 : if (l == 2) return gen_0;
3498 940 : av = avma; c = Flx_mul(gel(x,2),gel(y,2), p);
3499 940 : for (i=3; i<l; i++) c = Flx_add(c, Flx_mul(gel(x,i),gel(y,i), p), p);
3500 940 : return gerepileuptoleaf(av, Flx_rem(c,T,p));
3501 : }
3502 :
3503 : GEN
3504 162994 : FlxC_eval_powers_pre(GEN z, GEN x, ulong p, ulong pi)
3505 : {
3506 162994 : long i, l = lg(z);
3507 162994 : GEN y = cgetg(l, t_VECSMALL);
3508 5934848 : for (i=1; i<l; i++)
3509 5771847 : uel(y,i) = Flx_eval_powers_pre(gel(z,i), x, p, pi);
3510 163001 : return y;
3511 : }
3512 :
3513 : /***********************************************************************/
3514 : /** **/
3515 : /** FlxM **/
3516 : /** **/
3517 : /***********************************************************************/
3518 :
3519 : GEN
3520 12484 : FlxM_eval_powers_pre(GEN z, GEN x, ulong p, ulong pi)
3521 : {
3522 12484 : long i, l = lg(z);
3523 12484 : GEN y = cgetg(l, t_MAT);
3524 175483 : for (i=1; i<l; i++)
3525 162999 : gel(y,i) = FlxC_eval_powers_pre(gel(z,i), x, p, pi);
3526 12484 : return y;
3527 : }
3528 :
3529 : GEN
3530 3031 : zero_FlxC(long n, long sv)
3531 : {
3532 : long i;
3533 3031 : GEN x = cgetg(n + 1, t_COL);
3534 3031 : GEN z = zero_Flx(sv);
3535 14490 : for (i = 1; i <= n; i++)
3536 11459 : gel(x, i) = z;
3537 3031 : return x;
3538 : }
3539 :
3540 : GEN
3541 6433 : FlxC_neg(GEN x, ulong p)
3542 6433 : { pari_APPLY_type(t_COL, Flx_neg(gel(x, i), p)) }
3543 :
3544 : GEN
3545 158802 : FlxC_sub(GEN x, GEN y, ulong p)
3546 158802 : { pari_APPLY_type(t_COL, Flx_sub(gel(x, i), gel(y, i), p)) }
3547 :
3548 : GEN
3549 3017 : zero_FlxM(long r, long c, long sv)
3550 : {
3551 : long j;
3552 3017 : GEN x = cgetg(c + 1, t_MAT);
3553 3017 : GEN z = zero_FlxC(r, sv);
3554 11354 : for (j = 1; j <= c; j++)
3555 8337 : gel(x, j) = z;
3556 3017 : return x;
3557 : }
3558 :
3559 : GEN
3560 1813 : FlxM_neg(GEN x, ulong p)
3561 1813 : { pari_APPLY_same(FlxC_neg(gel(x, i), p)) }
3562 :
3563 : GEN
3564 22470 : FlxM_sub(GEN x, GEN y, ulong p)
3565 22470 : { pari_APPLY_same(FlxC_sub(gel(x, i), gel(y,i), p)) }
3566 :
3567 : /***********************************************************************/
3568 : /** **/
3569 : /** FlxX **/
3570 : /** **/
3571 : /***********************************************************************/
3572 :
3573 : /* FlxX are t_POL with Flx coefficients.
3574 : * Normally the variable ordering should be respected.*/
3575 :
3576 : /*Similar to normalizepol, in place*/
3577 : /*FlxX_renormalize=zxX_renormalize */
3578 : GEN
3579 8615574 : FlxX_renormalize(GEN /*in place*/ x, long lx)
3580 : {
3581 : long i;
3582 11543759 : for (i = lx-1; i>1; i--)
3583 10667036 : if (lgpol(gel(x,i))) break;
3584 8615576 : stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1));
3585 8615577 : setlg(x, i+1); setsigne(x, i!=1); return x;
3586 : }
3587 :
3588 : GEN
3589 873594 : pol1_FlxX(long v, long sv)
3590 : {
3591 873594 : GEN z = cgetg(3, t_POL);
3592 873594 : z[1] = evalsigne(1) | evalvarn(v);
3593 873594 : gel(z,2) = pol1_Flx(sv); return z;
3594 : }
3595 :
3596 : GEN
3597 6555 : polx_FlxX(long v, long sv)
3598 : {
3599 6555 : GEN z = cgetg(4, t_POL);
3600 6555 : z[1] = evalsigne(1) | evalvarn(v);
3601 6555 : gel(z,2) = pol0_Flx(sv);
3602 6555 : gel(z,3) = pol1_Flx(sv); return z;
3603 : }
3604 :
3605 : long
3606 1816916 : FlxY_degreex(GEN b)
3607 : {
3608 1816916 : long deg = -1, i;
3609 1816916 : if (!signe(b)) return -1;
3610 6616542 : for (i = 2; i < lg(b); ++i)
3611 4799626 : deg = maxss(deg, degpol(gel(b, i)));
3612 1816916 : return deg;
3613 : }
3614 :
3615 : /*Lift coefficient of B to constant Flx, to give a FlxY*/
3616 : GEN
3617 3085 : Fly_to_FlxY(GEN B, long sv)
3618 : {
3619 3085 : long lb=lg(B);
3620 : long i;
3621 3085 : GEN b=cgetg(lb,t_POL);
3622 3107 : b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
3623 75265 : for (i=2; i<lb; i++)
3624 72180 : gel(b,i) = Fl_to_Flx(B[i], sv);
3625 3085 : return FlxX_renormalize(b, lb);
3626 : }
3627 :
3628 : GEN
3629 1637255 : zxX_to_FlxX(GEN B, ulong p)
3630 : {
3631 1637255 : long i, lb = lg(B);
3632 1637255 : GEN b = cgetg(lb,t_POL);
3633 5336928 : for (i=2; i<lb; i++)
3634 3699673 : gel(b,i) = zx_to_Flx(gel(B,i), p);
3635 1637255 : b[1] = B[1]; return FlxX_renormalize(b, lb);
3636 : }
3637 :
3638 : GEN
3639 417993 : FlxX_to_ZXX(GEN B)
3640 : {
3641 417993 : long i, lb = lg(B);
3642 417993 : GEN b = cgetg(lb,t_POL);
3643 2363240 : for (i=2; i<lb; i++)
3644 : {
3645 1945247 : GEN c = gel(B,i);
3646 1945247 : switch(lgpol(c))
3647 : {
3648 41499 : case 0: c = gen_0; break;
3649 57343 : case 1: c = utoi(c[2]); break;
3650 1846405 : default: c = Flx_to_ZX(c); break;
3651 : }
3652 1945247 : gel(b,i) = c;
3653 : }
3654 417993 : b[1] = B[1]; return b;
3655 : }
3656 :
3657 : GEN
3658 1372 : FlxXC_to_ZXXC(GEN x)
3659 1372 : { pari_APPLY_type(t_COL, FlxX_to_ZXX(gel(x,i))) }
3660 :
3661 : GEN
3662 0 : FlxXM_to_ZXXM(GEN x)
3663 0 : { pari_APPLY_same(FlxXC_to_ZXXC(gel(x,i))) }
3664 :
3665 : /* Note: v is used _only_ for the t_INT. It must match
3666 : * the variable of any t_POL coefficients. */
3667 : GEN
3668 477012 : ZXX_to_FlxX(GEN B, ulong p, long v)
3669 : {
3670 477012 : long lb=lg(B);
3671 : long i;
3672 477012 : GEN b=cgetg(lb,t_POL);
3673 477011 : b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
3674 4177800 : for (i=2; i<lb; i++)
3675 3700788 : switch (typ(gel(B,i)))
3676 : {
3677 : case t_INT:
3678 462622 : gel(b,i) = Z_to_Flx(gel(B,i), p, evalvarn(v));
3679 462614 : break;
3680 : case t_POL:
3681 3238180 : gel(b,i) = ZX_to_Flx(gel(B,i), p);
3682 3238189 : break;
3683 : }
3684 477012 : return FlxX_renormalize(b, lb);
3685 : }
3686 :
3687 : GEN
3688 12 : ZXXV_to_FlxXV(GEN x, ulong p, long v)
3689 12 : { pari_APPLY_type(t_VEC, ZXX_to_FlxX(gel(x,i), p, v)) }
3690 :
3691 : GEN
3692 313 : ZXXT_to_FlxXT(GEN x, ulong p, long v)
3693 : {
3694 313 : if (typ(x) == t_POL)
3695 299 : return ZXX_to_FlxX(x, p, v);
3696 : else
3697 14 : pari_APPLY_type(t_VEC, ZXXT_to_FlxXT(gel(x,i), p, v))
3698 : }
3699 :
3700 : GEN
3701 0 : FlxX_to_FlxC(GEN x, long N, long sv)
3702 : {
3703 : long i, l;
3704 : GEN z;
3705 0 : l = lg(x)-1; x++;
3706 0 : if (l > N+1) l = N+1; /* truncate higher degree terms */
3707 0 : z = cgetg(N+1,t_COL);
3708 0 : for (i=1; i<l ; i++) gel(z,i) = gel(x,i);
3709 0 : for ( ; i<=N; i++) gel(z,i) = pol0_Flx(sv);
3710 0 : return z;
3711 : }
3712 :
3713 : GEN
3714 0 : FlxXV_to_FlxM(GEN v, long n, long sv)
3715 : {
3716 0 : long j, N = lg(v);
3717 0 : GEN y = cgetg(N, t_MAT);
3718 0 : for (j=1; j<N; j++) gel(y,j) = FlxX_to_FlxC(gel(v,j), n, sv);
3719 0 : return y;
3720 : }
3721 :
3722 : /* matrix whose entries are given by the coeffs of the polynomial v in
3723 : * two variables (considered as degree n polynomials) */
3724 : GEN
3725 12134 : FlxX_to_Flm(GEN v, long n)
3726 : {
3727 12134 : long j, N = lg(v)-1;
3728 12134 : GEN y = cgetg(N, t_MAT);
3729 12128 : v++;
3730 12128 : for (j=1; j<N; j++) gel(y,j) = Flx_to_Flv(gel(v,j), n);
3731 12135 : return y;
3732 : }
3733 :
3734 : GEN
3735 41082 : FlxX_to_Flx(GEN f)
3736 : {
3737 41082 : long i, l = lg(f);
3738 41082 : GEN V = cgetg(l, t_VECSMALL);
3739 41082 : V[1] = ((ulong)f[1])&VARNBITS;
3740 589316 : for(i=2; i<l; i++)
3741 548234 : V[i] = lgpol(gel(f,i)) ? mael(f,i,2): 0L;
3742 41082 : return V;
3743 : }
3744 :
3745 : GEN
3746 31007 : Flm_to_FlxX(GEN x, long v,long w)
3747 : {
3748 31007 : long j, lx = lg(x);
3749 31007 : GEN y = cgetg(lx+1, t_POL);
3750 31002 : y[1]=evalsigne(1) | v;
3751 31002 : y++;
3752 31002 : for (j=1; j<lx; j++) gel(y,j) = Flv_to_Flx(gel(x,j), w);
3753 31005 : return FlxX_renormalize(--y, lx+1);
3754 : }
3755 :
3756 : /* P(X,Y) --> P(Y,X), n-1 is the degree in Y */
3757 : GEN
3758 19096 : FlxX_swap(GEN x, long n, long ws)
3759 : {
3760 19096 : long j, lx = lg(x), ly = n+3;
3761 19096 : GEN y = cgetg(ly, t_POL);
3762 19096 : y[1] = x[1];
3763 209622 : for (j=2; j<ly; j++)
3764 : {
3765 : long k;
3766 190526 : GEN p1 = cgetg(lx, t_VECSMALL);
3767 190526 : p1[1] = ws;
3768 6206006 : for (k=2; k<lx; k++)
3769 6015480 : if (j<lg(gel(x,k)))
3770 4864772 : p1[k] = mael(x,k,j);
3771 : else
3772 1150708 : p1[k] = 0;
3773 190526 : gel(y,j) = Flx_renormalize(p1,lx);
3774 : }
3775 19096 : return FlxX_renormalize(y,ly);
3776 : }
3777 :
3778 : static GEN
3779 1387355 : zxX_to_Kronecker_spec(GEN P, long lp, long n)
3780 : { /* P(X) = sum Pi(Y) * X^i, return P( Y^(2n-1) ) */
3781 1387355 : long i, j, k, l, N = (n<<1) + 1;
3782 1387355 : GEN y = cgetg((N-2)*lp + 2, t_VECSMALL) + 2;
3783 15091299 : for (k=i=0; i<lp; i++)
3784 : {
3785 15087997 : GEN c = gel(P,i);
3786 15087997 : l = lg(c);
3787 15087997 : if (l-3 >= n)
3788 0 : pari_err_BUG("zxX_to_Kronecker, P is not reduced mod Q");
3789 15087997 : for (j=2; j < l; j++) y[k++] = c[j];
3790 15087997 : if (i == lp-1) break;
3791 13703944 : for ( ; j < N; j++) y[k++] = 0;
3792 : }
3793 1387355 : y -= 2;
3794 1387355 : y[1] = P[1]; setlg(y, k+2); return y;
3795 : }
3796 :
3797 : GEN
3798 1059727 : zxX_to_Kronecker(GEN P, GEN Q)
3799 : {
3800 1059727 : GEN z = zxX_to_Kronecker_spec(P+2, lg(P)-2, degpol(Q));
3801 1059727 : z[1] = P[1]; return z;
3802 : }
3803 :
3804 : GEN
3805 537516 : FlxX_add(GEN x, GEN y, ulong p)
3806 : {
3807 : long i,lz;
3808 : GEN z;
3809 537516 : long lx=lg(x);
3810 537516 : long ly=lg(y);
3811 537516 : if (ly>lx) swapspec(x,y, lx,ly);
3812 537516 : lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
3813 537516 : for (i=2; i<ly; i++) gel(z,i) = Flx_add(gel(x,i), gel(y,i), p);
3814 537516 : for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
3815 537516 : return FlxX_renormalize(z, lz);
3816 : }
3817 :
3818 : GEN
3819 392 : FlxX_Flx_add(GEN y, GEN x, ulong p)
3820 : {
3821 392 : long i, lz = lg(y);
3822 : GEN z;
3823 392 : if (signe(y) == 0) return scalarpol(x, varn(y));
3824 392 : z = cgetg(lz,t_POL); z[1] = y[1];
3825 392 : gel(z,2) = Flx_add(gel(y,2), x, p);
3826 392 : if (lz == 3) z = FlxX_renormalize(z,lz);
3827 : else
3828 322 : for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));
3829 392 : return z;
3830 : }
3831 :
3832 : GEN
3833 10506 : FlxX_Flx_sub(GEN y, GEN x, ulong p)
3834 : {
3835 10506 : long i, lz = lg(y);
3836 : GEN z;
3837 10506 : if (signe(y) == 0) return scalarpol(x, varn(y));
3838 10506 : z = cgetg(lz,t_POL); z[1] = y[1];
3839 10506 : gel(z,2) = Flx_sub(gel(y,2), x, p);
3840 10506 : if (lz == 3) z = FlxX_renormalize(z,lz);
3841 : else
3842 8679 : for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));
3843 10506 : return z;
3844 : }
3845 :
3846 : GEN
3847 1146 : FlxX_neg(GEN x, ulong p)
3848 : {
3849 1146 : long i, lx=lg(x);
3850 1146 : GEN z = cgetg(lx, t_POL);
3851 1146 : z[1]=x[1];
3852 1146 : for (i=2; i<lx; i++) gel(z,i) = Flx_neg(gel(x,i), p);
3853 1146 : return z;
3854 : }
3855 :
3856 : GEN
3857 212 : FlxX_Fl_mul(GEN x, ulong y, ulong p)
3858 : {
3859 212 : long i, lx=lg(x);
3860 212 : GEN z = cgetg(lx, t_POL);
3861 212 : z[1]=x[1];
3862 212 : for (i=2; i<lx; i++) gel(z,i) = Flx_Fl_mul(gel(x,i), y, p);
3863 212 : return FlxX_renormalize(z, lx);
3864 : }
3865 :
3866 : GEN
3867 0 : FlxX_triple(GEN x, ulong p)
3868 : {
3869 0 : long i, lx=lg(x);
3870 0 : GEN z = cgetg(lx, t_POL);
3871 0 : z[1]=x[1];
3872 0 : for (i=2; i<lx; i++) gel(z,i) = Flx_triple(gel(x,i), p);
3873 0 : return FlxX_renormalize(z, lx);
3874 : }
3875 :
3876 : GEN
3877 212 : FlxX_double(GEN x, ulong p)
3878 : {
3879 212 : long i, lx=lg(x);
3880 212 : GEN z = cgetg(lx, t_POL);
3881 212 : z[1]=x[1];
3882 212 : for (i=2; i<lx; i++) gel(z,i) = Flx_double(gel(x,i), p);
3883 212 : return FlxX_renormalize(z, lx);
3884 : }
3885 :
3886 : GEN
3887 62327 : FlxX_deriv(GEN z, ulong p)
3888 : {
3889 62327 : long i,l = lg(z)-1;
3890 : GEN x;
3891 62327 : if (l < 2) l = 2;
3892 62327 : x = cgetg(l, t_POL); x[1] = z[1];
3893 62327 : for (i=2; i<l; i++) gel(x,i) = Flx_mulu(gel(z,i+1), (ulong) i-1, p);
3894 62327 : return FlxX_renormalize(x,l);
3895 : }
3896 :
3897 : static GEN
3898 63635 : FlxX_subspec(GEN x, GEN y, ulong p, long lx, long ly)
3899 : {
3900 : long i,lz;
3901 : GEN z;
3902 :
3903 63635 : if (ly <= lx)
3904 : {
3905 63635 : lz = lx+2; z = cgetg(lz, t_POL)+2;
3906 63635 : for (i=0; i<ly; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
3907 63635 : for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
3908 : }
3909 : else
3910 : {
3911 0 : lz = ly+2; z = cgetg(lz, t_POL)+2;
3912 0 : for (i=0; i<lx; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
3913 0 : for ( ; i<ly; i++) gel(z,i) = Flx_neg(gel(y,i),p);
3914 : }
3915 63635 : return FlxX_renormalize(z-2, lz);
3916 : }
3917 :
3918 : GEN
3919 108600 : FlxX_sub(GEN x, GEN y, ulong p)
3920 : {
3921 : long lx,ly,i,lz;
3922 : GEN z;
3923 108600 : lx = lg(x); ly = lg(y);
3924 108600 : lz=maxss(lx,ly);
3925 108600 : z = cgetg(lz,t_POL);
3926 108600 : if (lx >= ly)
3927 : {
3928 69162 : z[1] = x[1];
3929 69162 : for (i=2; i<ly; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
3930 69162 : for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
3931 69162 : if (lx==ly) z = FlxX_renormalize(z, lz);
3932 : }
3933 : else
3934 : {
3935 39438 : z[1] = y[1];
3936 39438 : for (i=2; i<lx; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
3937 39438 : for ( ; i<ly; i++) gel(z,i) = Flx_neg(gel(y,i),p);
3938 : }
3939 108600 : if (!lgpol(z)) { avma = (pari_sp)(z + lz); z = pol_0(varn(x)); }
3940 108600 : return z;
3941 : }
3942 :
3943 : GEN
3944 653292 : FlxX_Flx_mul(GEN P, GEN U, ulong p)
3945 : {
3946 653292 : long i, lP = lg(P);
3947 653292 : GEN res = cgetg(lP,t_POL);
3948 653292 : res[1] = P[1];
3949 7106555 : for(i=2; i<lP; i++)
3950 6453263 : gel(res,i) = Flx_mul(U,gel(P,i), p);
3951 653292 : return FlxX_renormalize(res, lP);
3952 : }
3953 :
3954 : GEN
3955 249684 : FlxY_evalx(GEN Q, ulong x, ulong p)
3956 : {
3957 : GEN z;
3958 249684 : long i, lb = lg(Q);
3959 249684 : z = cgetg(lb,t_VECSMALL); z[1] = evalvarn(varn(Q));
3960 249174 : for (i=2; i<lb; i++) z[i] = Flx_eval(gel(Q,i), x, p);
3961 249696 : return Flx_renormalize(z, lb);
3962 : }
3963 :
3964 : GEN
3965 0 : FlxY_Flx_translate(GEN P, GEN c, ulong p)
3966 : {
3967 0 : pari_sp av = avma;
3968 : GEN Q;
3969 : long i, k, n;
3970 :
3971 0 : if (!signe(P) || gequal0(c)) return RgX_copy(P);
3972 0 : Q = leafcopy(P); n = degpol(P);
3973 0 : for (i=1; i<=n; i++)
3974 : {
3975 0 : for (k=n-i; k<n; k++)
3976 0 : gel(Q,2+k) = Flx_add(gel(Q,2+k), Flx_mul(gel(Q,2+k+1), c, p), p);
3977 0 : if (gc_needed(av,2))
3978 : {
3979 0 : if(DEBUGMEM>1)
3980 0 : pari_warn(warnmem,"FlxY_Flx_translate, i = %ld/%ld", i,n);
3981 0 : Q = gerepilecopy(av, Q);
3982 : }
3983 : }
3984 0 : return gerepilecopy(av, Q);
3985 : }
3986 :
3987 : GEN
3988 7911322 : FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi)
3989 : {
3990 7911322 : long i, len = lg(pol);
3991 7911322 : GEN res = cgetg(len, t_VECSMALL);
3992 7911322 : res[1] = pol[1] & VARNBITS;
3993 26832484 : for (i = 2; i < len; ++i)
3994 18921162 : res[i] = Flx_eval_powers_pre(gel(pol, i), ypowers, p, pi);
3995 7911322 : return Flx_renormalize(res, len);
3996 : }
3997 :
3998 : ulong
3999 5302436 : FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi)
4000 : {
4001 5302436 : pari_sp av = avma;
4002 5302436 : GEN t = FlxY_evalx_powers_pre(pol, ypowers, p, pi);
4003 5302436 : ulong out = Flx_eval_powers_pre(t, xpowers, p, pi);
4004 5302436 : avma = av;
4005 5302436 : return out;
4006 : }
4007 :
4008 : GEN
4009 119840 : FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p)
4010 : {
4011 119840 : long i, lP = lg(P);
4012 119840 : GEN res = cgetg(lP,t_POL);
4013 119840 : res[1] = P[1];
4014 760330 : for(i=2; i<lP; i++)
4015 640490 : gel(res,i) = Flx_FlxqV_eval(gel(P,i), x, T, p);
4016 119840 : return FlxX_renormalize(res, lP);
4017 : }
4018 :
4019 : GEN
4020 0 : FlxY_Flxq_evalx(GEN P, GEN x, GEN T, ulong p)
4021 : {
4022 0 : pari_sp av = avma;
4023 0 : long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(P),1);
4024 0 : GEN xp = Flxq_powers(x, n, T, p);
4025 0 : return gerepileupto(av, FlxY_FlxqV_evalx(P, xp, T, p));
4026 : }
4027 :
4028 : GEN
4029 9416 : FlxY_Flx_div(GEN x, GEN y, ulong p)
4030 : {
4031 : long i, l;
4032 : GEN z;
4033 9416 : if (degpol(y) == 0)
4034 : {
4035 6708 : ulong t = uel(y,2);
4036 6708 : if (t == 1) return x;
4037 35 : t = Fl_inv(t, p);
4038 35 : z = cgetg_copy(x, &l); z[1] = x[1];
4039 34 : for (i=2; i<l; i++) gel(z,i) = Flx_Fl_mul(gel(x,i),t,p);
4040 : }
4041 : else
4042 : {
4043 2708 : z = cgetg_copy(x, &l); z[1] = x[1];
4044 2709 : for (i=2; i<l; i++) gel(z,i) = Flx_div(gel(x,i),y,p);
4045 : }
4046 2740 : return z;
4047 : }
4048 :
4049 : GEN
4050 0 : FlxX_shift(GEN a, long n, long vs)
4051 : {
4052 0 : long i, l = lg(a);
4053 : GEN b;
4054 0 : if (l == 2 || !n) return a;
4055 0 : l += n;
4056 0 : if (n < 0)
4057 : {
4058 0 : if (l <= 2) return pol_0(varn(a));
4059 0 : b = cgetg(l, t_POL); b[1] = a[1];
4060 0 : a -= n;
4061 0 : for (i=2; i<l; i++) gel(b,i) = gel(a,i);
4062 : } else {
4063 0 : b = cgetg(l, t_POL); b[1] = a[1];
4064 0 : a -= n; n += 2;
4065 0 : for (i=2; i<n; i++) gel(b,i) = pol0_Flx(vs);
4066 0 : for ( ; i<l; i++) gel(b,i) = gel(a,i);
4067 : }
4068 0 : return b;
4069 : }
4070 :
4071 : static GEN
4072 131400 : FlxX_recipspec(GEN x, long l, long n, long vs)
4073 : {
4074 : long i;
4075 131400 : GEN z=cgetg(n+2,t_POL)+2;
4076 3152065 : for(i=0; i<l; i++)
4077 3020665 : gel(z,n-i-1) = Flx_copy(gel(x,i));
4078 136752 : for( ; i<n; i++)
4079 5352 : gel(z,n-i-1) = pol0_Flx(vs);
4080 131400 : return FlxX_renormalize(z-2,n+2);
4081 : }
4082 :
4083 : /***********************************************************************/
4084 : /** **/
4085 : /** FlxqX **/
4086 : /** **/
4087 : /***********************************************************************/
4088 :
4089 : static GEN
4090 1485422 : get_FlxqX_red(GEN T, GEN *B)
4091 : {
4092 1485422 : if (typ(T)!=t_VEC) { *B=NULL; return T; }
4093 73654 : *B = gel(T,1); return gel(T,2);
4094 : }
4095 :
4096 : GEN
4097 30519 : RgX_to_FlxqX(GEN x, GEN T, ulong p)
4098 : {
4099 30519 : long i, l = lg(x);
4100 30519 : GEN z = cgetg(l, t_POL); z[1] = x[1];
4101 571004 : for (i = 2; i < l; i++)
4102 540485 : gel(z,i) = Rg_to_Flxq(gel(x,i), T, p);
4103 30519 : return FlxX_renormalize(z, l);
4104 : }
4105 :
4106 : /* FlxqX are t_POL with Flxq coefficients.
4107 : * Normally the variable ordering should be respected.*/
4108 :
4109 : GEN
4110 474 : random_FlxqX(long d1, long v, GEN T, ulong p)
4111 : {
4112 474 : long dT = get_Flx_degree(T), vT = get_Flx_var(T);
4113 474 : long i, d = d1+2;
4114 474 : GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
4115 474 : for (i=2; i<d; i++) gel(y,i) = random_Flx(dT, vT, p);
4116 474 : return FlxX_renormalize(y,d);
4117 : }
4118 :
4119 : /*Not stack clean*/
4120 : GEN
4121 798052 : Kronecker_to_FlxqX(GEN z, GEN T, ulong p)
4122 : {
4123 798052 : long i,j,lx,l, N = (get_Flx_degree(T)<<1) + 1;
4124 798052 : GEN x, t = cgetg(N,t_VECSMALL);
4125 798052 : t[1] = get_Flx_var(T);
4126 798052 : l = lg(z); lx = (l-2) / (N-2);
4127 798052 : x = cgetg(lx+3,t_POL);
4128 798052 : x[1] = z[1];
4129 15565266 : for (i=2; i<lx+2; i++)
4130 : {
4131 14767214 : for (j=2; j<N; j++) t[j] = z[j];
4132 14767214 : z += (N-2);
4133 14767214 : gel(x,i) = Flx_rem(Flx_renormalize(t,N), T,p);
4134 : }
4135 798052 : N = (l-2) % (N-2) + 2;
4136 798052 : for (j=2; j<N; j++) t[j] = z[j];
4137 798052 : gel(x,i) = Flx_rem(Flx_renormalize(t,N), T,p);
4138 798052 : return FlxX_renormalize(x, i+1);
4139 : }
4140 :
4141 : GEN
4142 982412 : FlxqX_red(GEN z, GEN T, ulong p)
4143 : {
4144 : GEN res;
4145 982412 : long i, l = lg(z);
4146 982412 : res = cgetg(l,t_POL); res[1] = z[1];
4147 982412 : for(i=2;i<l;i++) gel(res,i) = Flx_rem(gel(z,i),T,p);
4148 982412 : return FlxX_renormalize(res,l);
4149 : }
4150 :
4151 : static GEN
4152 163814 : FlxqX_mulspec(GEN x, GEN y, GEN T, ulong p, long lx, long ly)
4153 : {
4154 163814 : pari_sp ltop=avma;
4155 : GEN z,kx,ky;
4156 163814 : long dT = get_Flx_degree(T);
4157 163814 : kx= zxX_to_Kronecker_spec(x,lx,dT);
4158 163814 : ky= zxX_to_Kronecker_spec(y,ly,dT);
4159 163814 : z = Flx_mul(ky, kx, p);
4160 163814 : z = Kronecker_to_FlxqX(z,T,p);
4161 163814 : return gerepileupto(ltop,z);
4162 : }
4163 :
4164 : GEN
4165 425489 : FlxqX_mul(GEN x, GEN y, GEN T, ulong p)
4166 : {
4167 425489 : pari_sp ltop=avma;
4168 : GEN z,kx,ky;
4169 425489 : kx= zxX_to_Kronecker(x,get_Flx_mod(T));
4170 425489 : ky= zxX_to_Kronecker(y,get_Flx_mod(T));
4171 425489 : z = Flx_mul(ky, kx, p);
4172 425489 : z = Kronecker_to_FlxqX(z,T,p);
4173 425489 : return gerepileupto(ltop,z);
4174 : }
4175 :
4176 : GEN
4177 208749 : FlxqX_sqr(GEN x, GEN T, ulong p)
4178 : {
4179 208749 : pari_sp ltop=avma;
4180 : GEN z,kx;
4181 208749 : kx= zxX_to_Kronecker(x,get_Flx_mod(T));
4182 208749 : z = Flx_sqr(kx, p);
4183 208749 : z = Kronecker_to_FlxqX(z,T,p);
4184 208749 : return gerepileupto(ltop,z);
4185 : }
4186 :
4187 : GEN
4188 8064 : FlxqX_Flxq_mul(GEN P, GEN U, GEN T, ulong p)
4189 : {
4190 8064 : long i, lP = lg(P);
4191 8064 : GEN res = cgetg(lP,t_POL);
4192 8064 : res[1] = P[1];
4193 37072 : for(i=2; i<lP; i++)
4194 29008 : gel(res,i) = Flxq_mul(U,gel(P,i), T,p);
4195 8064 : return FlxX_renormalize(res, lP);
4196 : }
4197 : GEN
4198 224477 : FlxqX_Flxq_mul_to_monic(GEN P, GEN U, GEN T, ulong p)
4199 : {
4200 224477 : long i, lP = lg(P);
4201 224477 : GEN res = cgetg(lP,t_POL);
4202 224477 : res[1] = P[1];
4203 224477 : for(i=2; i<lP-1; i++) gel(res,i) = Flxq_mul(U,gel(P,i), T,p);
4204 224477 : gel(res,lP-1) = pol1_Flx(get_Flx_var(T));
4205 224477 : return FlxX_renormalize(res, lP);
4206 : }
4207 :
4208 : GEN
4209 172285 : FlxqX_normalize(GEN z, GEN T, ulong p)
4210 : {
4211 172285 : GEN p1 = leading_coeff(z);
4212 172285 : if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;
4213 172264 : return FlxqX_Flxq_mul_to_monic(z, Flxq_inv(p1,T,p), T,p);
4214 : }
4215 :
4216 : /* x and y in Z[Y][X]. Assume T irreducible mod p */
4217 : static GEN
4218 1206872 : FlxqX_divrem_basecase(GEN x, GEN y, GEN T, ulong p, GEN *pr)
4219 : {
4220 : long vx, dx, dy, dz, i, j, sx, lr;
4221 : pari_sp av0, av, tetpil;
4222 : GEN z,p1,rem,lead;
4223 :
4224 1206872 : if (!signe(y)) pari_err_INV("FlxqX_divrem",y);
4225 1206872 : vx=varn(x); dy=degpol(y); dx=degpol(x);
4226 1206872 : if (dx < dy)
4227 : {
4228 12816 : if (pr)
4229 : {
4230 12677 : av0 = avma; x = FlxqX_red(x, T, p);
4231 12677 : if (pr == ONLY_DIVIDES) { avma=av0; return signe(x)? NULL: pol_0(vx); }
4232 12677 : if (pr == ONLY_REM) return x;
4233 12677 : *pr = x;
4234 : }
4235 12816 : return pol_0(vx);
4236 : }
4237 1194056 : lead = leading_coeff(y);
4238 1194056 : if (!dy) /* y is constant */
4239 : {
4240 113966 : if (pr && pr != ONLY_DIVIDES)
4241 : {
4242 109374 : if (pr == ONLY_REM) return pol_0(vx);
4243 5768 : *pr = pol_0(vx);
4244 : }
4245 10360 : if (Flx_equal1(lead)) return gcopy(x);
4246 6265 : av0 = avma; x = FlxqX_Flxq_mul(x,Flxq_inv(lead,T,p),T,p);
4247 6265 : return gerepileupto(av0,x);
4248 : }
4249 1080090 : av0 = avma; dz = dx-dy;
4250 1080090 : lead = Flx_equal1(lead)? NULL: gclone(Flxq_inv(lead,T,p));
4251 1080090 : avma = av0;
4252 1080090 : z = cgetg(dz+3,t_POL); z[1] = x[1];
4253 1080090 : x += 2; y += 2; z += 2;
4254 :
4255 1080090 : p1 = gel(x,dx); av = avma;
4256 1080090 : gel(z,dz) = lead? gerepileupto(av, Flxq_mul(p1,lead, T, p)): gcopy(p1);
4257 3009496 : for (i=dx-1; i>=dy; i--)
4258 : {
4259 1929406 : av=avma; p1=gel(x,i);
4260 7165737 : for (j=i-dy+1; j<=i && j<=dz; j++)
4261 5236331 : p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p);
4262 1929406 : if (lead) p1 = Flx_mul(p1, lead,p);
4263 1929406 : tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,Flx_rem(p1,T,p));
4264 : }
4265 1080090 : if (!pr) { if (lead) gunclone(lead); return z-2; }
4266 :
4267 1048878 : rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
4268 1291843 : for (sx=0; ; i--)
4269 : {
4270 1291843 : p1 = gel(x,i);
4271 4387043 : for (j=0; j<=i && j<=dz; j++)
4272 3095200 : p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p);
4273 1291843 : tetpil=avma; p1 = Flx_rem(p1, T, p); if (lgpol(p1)) { sx = 1; break; }
4274 298095 : if (!i) break;
4275 242965 : avma=av;
4276 242965 : }
4277 1048878 : if (pr == ONLY_DIVIDES)
4278 : {
4279 0 : if (lead) gunclone(lead);
4280 0 : if (sx) { avma=av0; return NULL; }
4281 0 : avma = (pari_sp)rem; return z-2;
4282 : }
4283 1048878 : lr=i+3; rem -= lr;
4284 1048878 : rem[0] = evaltyp(t_POL) | evallg(lr);
4285 1048878 : rem[1] = z[-1];
4286 1048878 : p1 = gerepile((pari_sp)rem,tetpil,p1);
4287 1048878 : rem += 2; gel(rem,i) = p1;
4288 10099039 : for (i--; i>=0; i--)
4289 : {
4290 9050161 : av=avma; p1 = gel(x,i);
4291 32140397 : for (j=0; j<=i && j<=dz; j++)
4292 23090236 : p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p), p);
4293 9050161 : tetpil=avma; gel(rem,i) = gerepile(av,tetpil, Flx_rem(p1, T, p));
4294 : }
4295 1048878 : rem -= 2;
4296 1048878 : if (lead) gunclone(lead);
4297 1048878 : if (!sx) (void)FlxX_renormalize(rem, lr);
4298 1048878 : if (pr == ONLY_REM) return gerepileupto(av0,rem);
4299 192675 : *pr = rem; return z-2;
4300 : }
4301 :
4302 : static GEN
4303 990 : FlxqX_invBarrett_basecase(GEN T, GEN Q, ulong p)
4304 : {
4305 990 : long i, l=lg(T)-1, lr = l-1, k;
4306 990 : long sv=Q[1];
4307 990 : GEN r=cgetg(lr,t_POL); r[1]=T[1];
4308 990 : gel(r,2) = pol1_Flx(sv);
4309 7511 : for (i=3;i<lr;i++)
4310 : {
4311 6521 : pari_sp ltop=avma;
4312 6521 : GEN u = Flx_neg(gel(T,l-i+2),p);
4313 40673 : for (k=3;k<i;k++)
4314 34152 : u = Flx_sub(u, Flxq_mul(gel(T,l-i+k),gel(r,k),Q,p),p);
4315 6521 : gel(r,i) = gerepileupto(ltop, u);
4316 : }
4317 990 : r = FlxX_renormalize(r,lr);
4318 990 : return r;
4319 : }
4320 :
4321 : /* Return new lgpol */
4322 : static long
4323 180641 : FlxX_lgrenormalizespec(GEN x, long lx)
4324 : {
4325 : long i;
4326 202237 : for (i = lx-1; i>=0; i--)
4327 202237 : if (lgpol(gel(x,i))) break;
4328 180641 : return i+1;
4329 : }
4330 :
4331 : static GEN
4332 3170 : FlxqX_invBarrett_Newton(GEN S, GEN T, ulong p)
4333 : {
4334 3170 : pari_sp av = avma;
4335 3170 : long nold, lx, lz, lq, l = degpol(S), i, lQ;
4336 3170 : GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
4337 3170 : long dT = get_Flx_degree(T);
4338 3170 : ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
4339 3170 : for (i=0;i<l;i++) gel(x,i) = pol0_Flx(T[1]);
4340 3170 : q = FlxX_recipspec(S+2,l+1,l+1,dT);
4341 3170 : lQ = lgpol(q); q+=2;
4342 : /* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */
4343 :
4344 : /* initialize */
4345 3170 : gel(x,0) = Flxq_inv(gel(q,0),T, p);
4346 3170 : if (lQ>1 && degpol(gel(q,1)) >= dT)
4347 0 : gel(q,1) = Flx_rem(gel(q,1), T, p);
4348 3170 : if (lQ>1 && lgpol(gel(q,1)))
4349 2166 : {
4350 2166 : GEN u = gel(q, 1);
4351 2166 : if (!Flx_equal1(gel(x,0))) u = Flxq_mul(u, Flxq_sqr(gel(x,0), T,p), T,p);
4352 2166 : gel(x,1) = Flx_neg(u, p); lx = 2;
4353 : }
4354 : else
4355 1004 : lx = 1;
4356 3170 : nold = 1;
4357 25053 : for (; mask > 1; )
4358 : { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
4359 18713 : long i, lnew, nnew = nold << 1;
4360 :
4361 18713 : if (mask & 1) nnew--;
4362 18713 : mask >>= 1;
4363 :
4364 18713 : lnew = nnew + 1;
4365 18713 : lq = FlxX_lgrenormalizespec(q, minss(lQ,lnew));
4366 18713 : z = FlxqX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */
4367 18713 : lz = lgpol(z); if (lz > lnew) lz = lnew;
4368 18713 : z += 2;
4369 : /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
4370 18713 : for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;
4371 18713 : nold = nnew;
4372 18713 : if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
4373 :
4374 : /* z + i represents (x*q - 1) / t^i */
4375 17831 : lz = FlxX_lgrenormalizespec (z+i, lz-i);
4376 17831 : z = FlxqX_mulspec(x, z+i, T,p, lx, lz); /* FIXME: low product */
4377 17831 : lz = lgpol(z); z += 2;
4378 17831 : if (lz > lnew-i) lz = FlxX_lgrenormalizespec(z, lnew-i);
4379 :
4380 17831 : lx = lz+ i;
4381 17831 : y = x + i; /* x -= z * t^i, in place */
4382 17831 : for (i = 0; i < lz; i++) gel(y,i) = Flx_neg(gel(z,i), p);
4383 : }
4384 3170 : x -= 2; setlg(x, lx + 2); x[1] = S[1];
4385 3170 : return gerepilecopy(av, x);
4386 : }
4387 :
4388 : /* x/polrecip(P)+O(x^n) */
4389 : GEN
4390 4160 : FlxqX_invBarrett(GEN T, GEN Q, ulong p)
4391 : {
4392 4160 : pari_sp ltop=avma;
4393 4160 : long l=lg(T), v = varn(T);
4394 : GEN r;
4395 4160 : GEN c = gel(T,l-1);
4396 4160 : if (l<5) return pol_0(v);
4397 4160 : if (l<=FlxqX_INVBARRETT_LIMIT)
4398 : {
4399 990 : if (!Flx_equal1(c))
4400 : {
4401 0 : GEN ci = Flxq_inv(c,Q,p);
4402 0 : T = FlxqX_Flxq_mul(T, ci, Q, p);
4403 0 : r = FlxqX_invBarrett_basecase(T,Q,p);
4404 0 : r = FlxqX_Flxq_mul(r,ci,Q,p);
4405 : } else
4406 990 : r = FlxqX_invBarrett_basecase(T,Q,p);
4407 : } else
4408 3170 : r = FlxqX_invBarrett_Newton(T,Q,p);
4409 4160 : return gerepileupto(ltop, r);
4410 : }
4411 :
4412 : GEN
4413 297011 : FlxqX_get_red(GEN S, GEN T, ulong p)
4414 : {
4415 297011 : if (typ(S)==t_POL && lg(S)>FlxqX_BARRETT_LIMIT)
4416 2593 : retmkvec2(FlxqX_invBarrett(S, T, p), S);
4417 294418 : return S;
4418 : }
4419 :
4420 : /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)
4421 : * * and mg is the Barrett inverse of S. */
4422 : static GEN
4423 63635 : FlxqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, ulong p, GEN *pr)
4424 : {
4425 : GEN q, r;
4426 63635 : long lt = degpol(S); /*We discard the leading term*/
4427 : long ld, lm, lT, lmg;
4428 63635 : ld = l-lt;
4429 63635 : lm = minss(ld, lgpol(mg));
4430 63635 : lT = FlxX_lgrenormalizespec(S+2,lt);
4431 63635 : lmg = FlxX_lgrenormalizespec(mg+2,lm);
4432 63635 : q = FlxX_recipspec(x+lt,ld,ld,0); /* q = rec(x) lq<=ld*/
4433 63635 : q = FlxqX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/
4434 63635 : q = FlxX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/
4435 63635 : if (!pr) return q;
4436 63635 : r = FlxqX_mulspec(q+2,S+2,T,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/
4437 63635 : r = FlxX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */
4438 63635 : if (pr == ONLY_REM) return r;
4439 63635 : *pr = r; return q;
4440 : }
4441 :
4442 : static GEN
4443 53342 : FlxqX_divrem_Barrett_noGC(GEN x, GEN mg, GEN S, GEN T, ulong p, GEN *pr)
4444 : {
4445 53342 : long l = lgpol(x), lt = degpol(S), lm = 2*lt-1;
4446 53342 : GEN q = NULL, r;
4447 : long i;
4448 53342 : if (l <= lt)
4449 : {
4450 0 : if (pr == ONLY_REM) return RgX_copy(x);
4451 0 : if (pr == ONLY_DIVIDES) return signe(x)? NULL: pol_0(varn(x));
4452 0 : if (pr) *pr = RgX_copy(x);
4453 0 : return pol_0(varn(x));
4454 : }
4455 53342 : if (lt <= 1)
4456 0 : return FlxqX_divrem_basecase(x,S,T,p,pr);
4457 53342 : if (pr != ONLY_REM && l>lm)
4458 : {
4459 750 : long vT = get_Flx_var(T);
4460 750 : q = cgetg(l-lt+2, t_POL);
4461 750 : for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_Flx(vT);
4462 : }
4463 53342 : r = l>lm ? shallowcopy(x): x;
4464 117059 : while (l>lm)
4465 : {
4466 10375 : GEN zr, zq = FlxqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr);
4467 10375 : long lz = lgpol(zr);
4468 10375 : if (pr != ONLY_REM)
4469 : {
4470 2568 : long lq = lgpol(zq);
4471 2568 : for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
4472 : }
4473 10375 : for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
4474 10375 : l = l-lm+lz;
4475 : }
4476 53342 : if (pr != ONLY_REM)
4477 : {
4478 1065 : if (l > lt)
4479 : {
4480 983 : GEN zq = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,&r);
4481 983 : if (!q) q = zq;
4482 : else
4483 : {
4484 668 : long lq = lgpol(zq);
4485 668 : for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
4486 : }
4487 : }
4488 : else
4489 82 : { setlg(r, l+2); r = RgX_copy(r); }
4490 : }
4491 : else
4492 : {
4493 52277 : if (l > lt)
4494 52277 : (void) FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,&r);
4495 : else
4496 0 : { setlg(r, l+2); r = RgX_copy(r); }
4497 52277 : r[1] = x[1]; return FlxX_renormalize(r, lg(r));
4498 : }
4499 1065 : if (pr) { r[1] = x[1]; r = FlxX_renormalize(r, lg(r)); }
4500 1065 : q[1] = x[1]; q = FlxX_renormalize(q, lg(q));
4501 1065 : if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
4502 1065 : if (pr) *pr = r;
4503 1065 : return q;
4504 : }
4505 :
4506 : GEN
4507 248128 : FlxqX_divrem(GEN x, GEN S, GEN T, ulong p, GEN *pr)
4508 : {
4509 248128 : GEN B, y = get_FlxqX_red(S, &B);
4510 248128 : long dy = degpol(y), dx = degpol(x), d = dx-dy;
4511 248128 : if (pr==ONLY_REM) return FlxqX_rem(x, y, T, p);
4512 248128 : if (!B && d+3 < FlxqX_DIVREM_BARRETT_LIMIT)
4513 247063 : return FlxqX_divrem_basecase(x,y,T,p,pr);
4514 : else
4515 : {
4516 1065 : pari_sp av=avma;
4517 1065 : GEN mg = B? B: FlxqX_invBarrett(y, T, p);
4518 1065 : GEN q = FlxqX_divrem_Barrett_noGC(x,mg,y,T,p,pr);
4519 1065 : if (!q) {avma=av; return NULL;}
4520 1065 : if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q);
4521 792 : gerepileall(av,2,&q,pr);
4522 792 : return q;
4523 : }
4524 : }
4525 :
4526 : GEN
4527 1236974 : FlxqX_rem(GEN x, GEN S, GEN T, ulong p)
4528 : {
4529 1236974 : GEN B, y = get_FlxqX_red(S, &B);
4530 1236974 : long dy = degpol(y), dx = degpol(x), d = dx-dy;
4531 1236974 : if (d < 0) return FlxqX_red(x, T, p);
4532 1012086 : if (!B && d+3 < FlxqX_REM_BARRETT_LIMIT)
4533 959809 : return FlxqX_divrem_basecase(x,y, T, p, ONLY_REM);
4534 : else
4535 : {
4536 52277 : pari_sp av=avma;
4537 52277 : GEN mg = B? B: FlxqX_invBarrett(y, T, p);
4538 52277 : GEN r = FlxqX_divrem_Barrett_noGC(x, mg, y, T, p, ONLY_REM);
4539 52277 : return gerepileupto(av, r);
4540 : }
4541 : }
4542 :
4543 : static GEN
4544 541 : FlxqX_halfgcd_basecase(GEN a, GEN b, GEN T, ulong p)
4545 : {
4546 541 : pari_sp av=avma;
4547 : GEN u,u1,v,v1;
4548 541 : long vx = varn(a);
4549 541 : long n = lgpol(a)>>1;
4550 541 : u1 = v = pol_0(vx);
4551 541 : u = v1 = pol1_FlxX(vx, get_Flx_var(T));
4552 9201 : while (lgpol(b)>n)
4553 : {
4554 8119 : GEN r, q = FlxqX_divrem(a,b, T, p, &r);
4555 8119 : a = b; b = r; swap(u,u1); swap(v,v1);
4556 8119 : u1 = FlxX_sub(u1, FlxqX_mul(u, q, T, p), p);
4557 8119 : v1 = FlxX_sub(v1, FlxqX_mul(v, q ,T, p), p);
4558 8119 : if (gc_needed(av,2))
4559 : {
4560 0 : if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_halfgcd (d = %ld)",degpol(b));
4561 0 : gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);
4562 : }
4563 : }
4564 541 : return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));
4565 : }
4566 : static GEN
4567 768 : FlxqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, ulong p)
4568 : {
4569 768 : return FlxX_add(FlxqX_mul(u, x, T, p),FlxqX_mul(v, y, T, p), p);
4570 : }
4571 :
4572 : static GEN
4573 384 : FlxqXM_FlxqX_mul2(GEN M, GEN x, GEN y, GEN T, ulong p)
4574 : {
4575 384 : GEN res = cgetg(3, t_COL);
4576 384 : gel(res, 1) = FlxqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p);
4577 384 : gel(res, 2) = FlxqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p);
4578 384 : return res;
4579 : }
4580 :
4581 : static GEN
4582 360 : FlxqXM_mul2(GEN A, GEN B, GEN T, ulong p)
4583 : {
4584 360 : GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
4585 360 : GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
4586 360 : GEN M1 = FlxqX_mul(FlxX_add(A11,A22, p), FlxX_add(B11,B22, p), T, p);
4587 360 : GEN M2 = FlxqX_mul(FlxX_add(A21,A22, p), B11, T, p);
4588 360 : GEN M3 = FlxqX_mul(A11, FlxX_sub(B12,B22, p), T, p);
4589 360 : GEN M4 = FlxqX_mul(A22, FlxX_sub(B21,B11, p), T, p);
4590 360 : GEN M5 = FlxqX_mul(FlxX_add(A11,A12, p), B22, T, p);
4591 360 : GEN M6 = FlxqX_mul(FlxX_sub(A21,A11, p), FlxX_add(B11,B12, p), T, p);
4592 360 : GEN M7 = FlxqX_mul(FlxX_sub(A12,A22, p), FlxX_add(B21,B22, p), T, p);
4593 360 : GEN T1 = FlxX_add(M1,M4, p), T2 = FlxX_sub(M7,M5, p);
4594 360 : GEN T3 = FlxX_sub(M1,M2, p), T4 = FlxX_add(M3,M6, p);
4595 360 : retmkmat2(mkcol2(FlxX_add(T1,T2, p), FlxX_add(M2,M4, p)),
4596 : mkcol2(FlxX_add(M3,M5, p), FlxX_add(T3,T4, p)));
4597 : }
4598 :
4599 : /* Return [0,1;1,-q]*M */
4600 : static GEN
4601 360 : FlxqX_FlxqXM_qmul(GEN q, GEN M, GEN T, ulong p)
4602 : {
4603 360 : GEN u, v, res = cgetg(3, t_MAT);
4604 360 : u = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(gcoeff(M,2,1), q, T, p), p);
4605 360 : gel(res,1) = mkcol2(gcoeff(M,2,1), u);
4606 360 : v = FlxX_sub(gcoeff(M,1,2), FlxqX_mul(gcoeff(M,2,2), q, T, p), p);
4607 360 : gel(res,2) = mkcol2(gcoeff(M,2,2), v);
4608 360 : return res;
4609 : }
4610 :
4611 : static GEN
4612 0 : matid2_FlxXM(long v, long sv)
4613 : {
4614 0 : retmkmat2(mkcol2(pol1_FlxX(v, sv),pol_0(v)),
4615 : mkcol2(pol_0(v),pol1_FlxX(v, sv)));
4616 : }
4617 :
4618 : static GEN
4619 363 : FlxqX_halfgcd_split(GEN x, GEN y, GEN T, ulong p)
4620 : {
4621 363 : pari_sp av=avma;
4622 : GEN R, S, V;
4623 : GEN y1, r, q;
4624 363 : long l = lgpol(x), n = l>>1, k;
4625 363 : if (lgpol(y)<=n) return matid2_FlxXM(varn(x),T[1]);
4626 363 : R = FlxqX_halfgcd(RgX_shift_shallow(x,-n),RgX_shift_shallow(y,-n), T, p);
4627 363 : V = FlxqXM_FlxqX_mul2(R,x,y, T, p); y1 = gel(V,2);
4628 363 : if (lgpol(y1)<=n) return gerepilecopy(av, R);
4629 360 : q = FlxqX_divrem(gel(V,1), y1, T, p, &r);
4630 360 : k = 2*n-degpol(y1);
4631 360 : S = FlxqX_halfgcd(RgX_shift_shallow(y1,-k), RgX_shift_shallow(r,-k), T, p);
4632 360 : return gerepileupto(av, FlxqXM_mul2(S,FlxqX_FlxqXM_qmul(q,R, T, p), T, p));
4633 : }
4634 :
4635 : /* Return M in GL_2(Fp[X]) such that:
4636 : if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
4637 : */
4638 :
4639 : static GEN
4640 904 : FlxqX_halfgcd_i(GEN x, GEN y, GEN T, ulong p)
4641 : {
4642 904 : if (lg(x)<=FlxqX_HALFGCD_LIMIT) return FlxqX_halfgcd_basecase(x, y, T, p);
4643 363 : return FlxqX_halfgcd_split(x, y, T, p);
4644 : }
4645 :
4646 : GEN
4647 904 : FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p)
4648 : {
4649 904 : pari_sp av = avma;
4650 : GEN M,q,r;
4651 904 : if (!signe(x))
4652 : {
4653 0 : long v = varn(x), vT = get_Flx_var(T);
4654 0 : retmkmat2(mkcol2(pol_0(v),pol1_FlxX(v,vT)),
4655 : mkcol2(pol1_FlxX(v,vT),pol_0(v)));
4656 : }
4657 904 : if (degpol(y)<degpol(x)) return FlxqX_halfgcd_i(x, y, T, p);
4658 12 : q = FlxqX_divrem(y, x, T, p, &r);
4659 12 : M = FlxqX_halfgcd_i(x, r, T, p);
4660 12 : gcoeff(M,1,1) = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(q, gcoeff(M,1,2), T, p), p);
4661 12 : gcoeff(M,2,1) = FlxX_sub(gcoeff(M,2,1), FlxqX_mul(q, gcoeff(M,2,2), T, p), p);
4662 12 : return gerepilecopy(av, M);
4663 : }
4664 :
4665 : static GEN
4666 149918 : FlxqX_gcd_basecase(GEN a, GEN b, GEN T, ulong p)
4667 : {
4668 149918 : pari_sp av = avma, av0=avma;
4669 970902 : while (signe(b))
4670 : {
4671 : GEN c;
4672 671066 : if (gc_needed(av0,2))
4673 : {
4674 28 : if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_gcd (d = %ld)",degpol(b));
4675 28 : gerepileall(av0,2, &a,&b);
4676 : }
4677 671066 : av = avma; c = FlxqX_rem(a, b, T, p); a=b; b=c;
4678 : }
4679 149918 : avma = av; return a;
4680 : }
4681 :
4682 : GEN
4683 154518 : FlxqX_gcd(GEN x, GEN y, GEN T, ulong p)
4684 : {
4685 154518 : pari_sp av = avma;
4686 154518 : x = FlxqX_red(x, T, p);
4687 154518 : y = FlxqX_red(y, T, p);
4688 154518 : if (!signe(x)) return gerepileupto(av, y);
4689 299857 : while (lg(y)>FlxqX_GCD_LIMIT)
4690 : {
4691 : GEN c;
4692 21 : if (lgpol(y)<=(lgpol(x)>>1))
4693 : {
4694 0 : GEN r = FlxqX_rem(x, y, T, p);
4695 0 : x = y; y = r;
4696 : }
4697 21 : c = FlxqXM_FlxqX_mul2(FlxqX_halfgcd(x,y, T, p), x, y, T, p);
4698 21 : x = gel(c,1); y = gel(c,2);
4699 21 : gerepileall(av,2,&x,&y);
4700 : }
4701 149918 : return gerepileupto(av, FlxqX_gcd_basecase(x, y, T, p));
4702 : }
4703 :
4704 : static GEN
4705 5775 : FlxqX_extgcd_basecase(GEN a, GEN b, GEN T, ulong p, GEN *ptu, GEN *ptv)
4706 : {
4707 5775 : pari_sp av=avma;
4708 : GEN u,v,d,d1,v1;
4709 5775 : long vx = varn(a);
4710 5775 : d = a; d1 = b;
4711 5775 : v = pol_0(vx); v1 = pol1_FlxX(vx, get_Flx_var(T));
4712 29022 : while (signe(d1))
4713 : {
4714 17472 : GEN r, q = FlxqX_divrem(d, d1, T, p, &r);
4715 17472 : v = FlxX_sub(v,FlxqX_mul(q,v1,T, p),p);
4716 17472 : u=v; v=v1; v1=u;
4717 17472 : u=r; d=d1; d1=u;
4718 17472 : if (gc_needed(av,2))
4719 : {
4720 0 : if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_extgcd (d = %ld)",degpol(d));
4721 0 : gerepileall(av,5, &d,&d1,&u,&v,&v1);
4722 : }
4723 : }
4724 5775 : if (ptu) *ptu = FlxqX_div(FlxX_sub(d,FlxqX_mul(b,v, T, p), p), a, T, p);
4725 5775 : *ptv = v; return d;
4726 : }
4727 :
4728 : static GEN
4729 0 : FlxqX_extgcd_halfgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)
4730 : {
4731 0 : pari_sp av=avma;
4732 0 : GEN u,v,R = matid2_FlxXM(varn(x), get_Flx_var(T));
4733 0 : while (lg(y)>FlxqX_EXTGCD_LIMIT)
4734 : {
4735 : GEN M, c;
4736 0 : if (lgpol(y)<=(lgpol(x)>>1))
4737 : {
4738 0 : GEN r, q = FlxqX_divrem(x, y, T, p, &r);
4739 0 : x = y; y = r;
4740 0 : R = FlxqX_FlxqXM_qmul(q, R, T, p);
4741 : }
4742 0 : M = FlxqX_halfgcd(x,y, T, p);
4743 0 : c = FlxqXM_FlxqX_mul2(M, x,y, T, p);
4744 0 : R = FlxqXM_mul2(M, R, T, p);
4745 0 : x = gel(c,1); y = gel(c,2);
4746 0 : gerepileall(av,3,&x,&y,&R);
4747 : }
4748 0 : y = FlxqX_extgcd_basecase(x,y, T, p, &u,&v);
4749 0 : if (ptu) *ptu = FlxqX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T, p);
4750 0 : *ptv = FlxqX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T, p);
4751 0 : return y;
4752 : }
4753 :
4754 : /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
4755 : * ux + vy = gcd (mod T,p) */
4756 : GEN
4757 5775 : FlxqX_extgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)
4758 : {
4759 : GEN d;
4760 5775 : pari_sp ltop=avma;
4761 5775 : x = FlxqX_red(x, T, p);
4762 5775 : y = FlxqX_red(y, T, p);
4763 5775 : if (lg(y)>FlxqX_EXTGCD_LIMIT)
4764 0 : d = FlxqX_extgcd_halfgcd(x, y, T, p, ptu, ptv);
4765 : else
4766 5775 : d = FlxqX_extgcd_basecase(x, y, T, p, ptu, ptv);
4767 5775 : gerepileall(ltop,ptu?3:2,&d,ptv,ptu);
4768 5775 : return d;
4769 : }
4770 :
4771 : GEN
4772 9491 : FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p)
4773 : {
4774 9491 : pari_sp av = avma;
4775 : GEN U;
4776 9491 : if (!signe(P)) return gcopy(Q);
4777 9491 : if (!signe(Q)) return gcopy(P);
4778 : for(;;)
4779 : {
4780 42722 : U = Flxq_invsafe(leading_coeff(Q), T, p);
4781 42722 : if (!U) { avma = av; return NULL; }
4782 42722 : Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p);
4783 42722 : P = FlxqX_rem(P,Q,T,p);
4784 42722 : if (!signe(P)) break;
4785 33231 : if (gc_needed(av, 1))
4786 : {
4787 0 : if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_safegcd");
4788 0 : gerepileall(av, 2, &P,&Q);
4789 : }
4790 33231 : swap(P, Q);
4791 33231 : }
4792 9491 : U = Flxq_invsafe(leading_coeff(Q), T, p);
4793 9491 : if (!U) { avma = av; return NULL; }
4794 9491 : Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p);
4795 9491 : return gerepileupto(av, Q);
4796 : }
4797 :
4798 : struct _FlxqX {ulong p; GEN T;};
4799 2484 : static GEN _FlxqX_mul(void *data,GEN a,GEN b)
4800 : {
4801 2484 : struct _FlxqX *d=(struct _FlxqX*)data;
4802 2484 : return FlxqX_mul(a,b,d->T,d->p);
4803 : }
4804 10255 : static GEN _FlxqX_sqr(void *data,GEN a)
4805 : {
4806 10255 : struct _FlxqX *d=(struct _FlxqX*)data;
4807 10255 : return FlxqX_sqr(a,d->T,d->p);
4808 : }
4809 :
4810 : GEN
4811 10227 : FlxqX_powu(GEN V, ulong n, GEN T, ulong p)
4812 : {
4813 10227 : struct _FlxqX d; d.p=p; d.T=T;
4814 10227 : return gen_powu(V, n, (void*)&d, &_FlxqX_sqr, &_FlxqX_mul);
4815 : }
4816 :
4817 : GEN
4818 1002 : FlxqXV_prod(GEN V, GEN T, ulong p)
4819 : {
4820 1002 : struct _FlxqX d; d.p=p; d.T=T;
4821 1002 : return gen_product(V, (void*)&d, &_FlxqX_mul);
4822 : }
4823 :
4824 : static GEN
4825 990 : FlxqV_roots_to_deg1(GEN x, GEN T, ulong p, long v)
4826 : {
4827 990 : long sv = get_Flx_var(T);
4828 990 : pari_APPLY_same(deg1pol_shallow(pol1_Flx(sv),Flx_neg(gel(x,i),p),v))
4829 : }
4830 :
4831 : GEN
4832 990 : FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v)
4833 : {
4834 990 : pari_sp ltop = avma;
4835 990 : GEN W = FlxqV_roots_to_deg1(V, T, p, v);
4836 990 : return gerepileupto(ltop, FlxqXV_prod(W, T, p));
4837 : }
4838 :
4839 : /*** FlxqM ***/
4840 :
4841 : GEN
4842 71239 : FlxqC_Flxq_mul(GEN x, GEN y, GEN T, ulong p)
4843 71239 : { pari_APPLY_type(t_COL, Flxq_mul(gel(x, i), y, T, p)) }
4844 :
4845 : GEN
4846 11844 : FlxqM_Flxq_mul(GEN x, GEN y, GEN T, ulong p)
4847 11844 : { pari_APPLY_same(FlxqC_Flxq_mul(gel(x, i), y, T, p)) }
4848 :
4849 : static GEN
4850 356149 : kron_pack_Flx_spec_half(GEN x, long l) {
4851 356149 : if (l == 0)
4852 173276 : return gen_0;
4853 182873 : return Flx_to_int_halfspec(x, l);
4854 : }
4855 :
4856 : static GEN
4857 21790 : kron_pack_Flx_spec(GEN x, long l) {
4858 : long i;
4859 : GEN w, y;
4860 21790 : if (l == 0)
4861 3880 : return gen_0;
4862 17910 : y = cgetipos(l + 2);
4863 71481 : for (i = 0, w = int_LSW(y); i < l; i++, w = int_nextW(w))
4864 53571 : *w = x[i];
4865 17910 : return y;
4866 : }
4867 :
4868 : static GEN
4869 0 : kron_pack_Flx_spec_2(GEN x, long l) {
4870 0 : return Flx_eval2BILspec(x, 2, l);
4871 : }
4872 :
4873 : static GEN
4874 0 : kron_pack_Flx_spec_3(GEN x, long l) {
4875 0 : return Flx_eval2BILspec(x, 3, l);
4876 : }
4877 :
4878 : static GEN
4879 98876 : kron_pack_Flx_spec_bits(GEN x, long b, long l) {
4880 : GEN y;
4881 : long i;
4882 98876 : if (l == 0)
4883 24185 : return gen_0;
4884 74691 : y = cgetg(l + 1, t_VECSMALL);
4885 379524 : for(i = 1; i <= l; i++)
4886 304833 : y[i] = x[l - i];
4887 74691 : return nv_fromdigits_2k(y, b);
4888 : }
4889 :
4890 : static GEN
4891 14740 : kron_unpack_Flx(GEN z, ulong p)
4892 : {
4893 14740 : long i, l = lgefint(z);
4894 14740 : GEN x = cgetg(l, t_VECSMALL), w;
4895 74179 : for (w = int_LSW(z), i = 2; i < l; w = int_nextW(w), i++)
4896 59439 : x[i] = ((ulong) *w) % p;
4897 14740 : return Flx_renormalize(x, l);
4898 : }
4899 :
4900 : static GEN
4901 0 : kron_unpack_Flx_2(GEN x, ulong p) {
4902 0 : long d = (lgefint(x)-1)/2 - 1;
4903 0 : return Z_mod2BIL_Flx_2(x, d, p);
4904 : }
4905 :
4906 : static GEN
4907 0 : kron_unpack_Flx_3(GEN x, ulong p) {
4908 0 : long d = lgefint(x)/3 - 1;
4909 0 : return Z_mod2BIL_Flx_3(x, d, p);
4910 : }
4911 :
4912 : /* assume b < BITS_IN_LONG */
4913 : static GEN
4914 53174 : kron_unpack_Flx_bits_narrow(GEN z, long b, ulong p) {
4915 53174 : GEN v = binary_2k_nv(z, b), x;
4916 53174 : long i, l = lg(v) + 1;
4917 53174 : x = cgetg(l, t_VECSMALL);
4918 332225 : for (i = 2; i < l; i++)
4919 279051 : x[i] = v[l - i] % p;
4920 53174 : return Flx_renormalize(x, l);
4921 : }
4922 :
4923 : static GEN
4924 7000 : kron_unpack_Flx_bits_wide(GEN z, long b, ulong p, ulong pi) {
4925 7000 : GEN v = binary_2k(z, b), x, y;
4926 7000 : long i, l = lg(v) + 1, ly;
4927 7000 : x = cgetg(l, t_VECSMALL);
4928 70000 : for (i = 2; i < l; i++) {
4929 63000 : y = gel(v, l - i);
4930 63000 : ly = lgefint(y);
4931 63000 : switch (ly) {
4932 0 : case 2: x[i] = 0; break;
4933 7849 : case 3: x[i] = *int_W_lg(y, 0, ly) % p; break;
4934 31574 : case 4: x[i] = remll_pre(*int_W_lg(y, 1, ly), *int_W_lg(y, 0, ly), p, pi); break;
4935 47154 : case 5: x[i] = remlll_pre(*int_W_lg(y, 2, ly), *int_W_lg(y, 1, ly),
4936 47154 : *int_W_lg(y, 0, ly), p, pi); break;
4937 0 : default: x[i] = umodiu(gel(v, l - i), p);
4938 : }
4939 : }
4940 7000 : return Flx_renormalize(x, l);
4941 : }
4942 :
4943 : static GEN
4944 21002 : FlxM_pack_ZM(GEN M, GEN (*pack)(GEN, long)) {
4945 : long i, j, l, lc;
4946 21002 : GEN N = cgetg_copy(M, &l), x;
4947 21002 : if (l == 1)
4948 0 : return N;
4949 21002 : lc = lgcols(M);
4950 132983 : for (j = 1; j < l; j++) {
4951 111981 : gel(N, j) = cgetg(lc, t_COL);
4952 489920 : for (i = 1; i < lc; i++) {
4953 377939 : x = gcoeff(M, i, j);
4954 377939 : gcoeff(N, i, j) = pack(x + 2, lgpol(x));
4955 : }
4956 : }
4957 21002 : return N;
4958 : }
4959 :
4960 : static GEN
4961 3825 : FlxM_pack_ZM_bits(GEN M, long b)
4962 : {
4963 : long i, j, l, lc;
4964 3825 : GEN N = cgetg_copy(M, &l), x;
4965 3825 : if (l == 1)
4966 0 : return N;
4967 3825 : lc = lgcols(M);
4968 23144 : for (j = 1; j < l; j++) {
4969 19319 : gel(N, j) = cgetg(lc, t_COL);
4970 118195 : for (i = 1; i < lc; i++) {
4971 98876 : x = gcoeff(M, i, j);
4972 98876 : gcoeff(N, i, j) = kron_pack_Flx_spec_bits(x + 2, b, lgpol(x));
4973 : }
4974 : }
4975 3825 : return N;
4976 : }
4977 :
4978 : static GEN
4979 10501 : ZM_unpack_FlxqM(GEN M, GEN T, ulong p, GEN (*unpack)(GEN, ulong))
4980 : {
4981 10501 : long i, j, l, lc, sv = get_Flx_var(T);
4982 10501 : GEN N = cgetg_copy(M, &l), x;
4983 10501 : if (l == 1)
4984 0 : return N;
4985 10501 : lc = lgcols(M);
4986 92313 : for (j = 1; j < l; j++) {
4987 81812 : gel(N, j) = cgetg(lc, t_COL);
4988 301950 : for (i = 1; i < lc; i++) {
4989 220138 : x = unpack(gcoeff(M, i, j), p);
4990 220138 : x[1] = sv;
4991 220138 : gcoeff(N, i, j) = Flx_rem(x, T, p);
4992 : }
4993 : }
4994 10501 : return N;
4995 : }
4996 :
4997 : static GEN
4998 1926 : ZM_unpack_FlxqM_bits(GEN M, long b, GEN T, ulong p)
4999 : {
5000 1926 : long i, j, l, lc, sv = get_Flx_var(T);
5001 1926 : GEN N = cgetg_copy(M, &l), x;
5002 1926 : if (l == 1)
5003 0 : return N;
5004 1926 : lc = lgcols(M);
5005 1926 : if (b < BITS_IN_LONG) {
5006 13899 : for (j = 1; j < l; j++) {
5007 12043 : gel(N, j) = cgetg(lc, t_COL);
5008 65217 : for (i = 1; i < lc; i++) {
5009 53174 : x = kron_unpack_Flx_bits_narrow(gcoeff(M, i, j), b, p);
5010 53174 : x[1] = sv;
5011 53174 : gcoeff(N, i, j) = Flx_rem(x, T, p);
5012 : }
5013 : }
5014 : } else {
5015 70 : ulong pi = get_Fl_red(p);
5016 770 : for (j = 1; j < l; j++) {
5017 700 : gel(N, j) = cgetg(lc, t_COL);
5018 7700 : for (i = 1; i < lc; i++) {
5019 7000 : x = kron_unpack_Flx_bits_wide(gcoeff(M, i, j), b, p, pi);
5020 7000 : x[1] = sv;
5021 7000 : gcoeff(N, i, j) = Flx_rem(x, T, p);
5022 : }
5023 : }
5024 : }
5025 1926 : return N;
5026 : }
5027 :
5028 : GEN
5029 12427 : FlxqM_mul_Kronecker(GEN A, GEN B, GEN T, ulong p)
5030 : {
5031 12427 : pari_sp av = avma;
5032 12427 : long b, d = degpol(T), n = lg(A) - 1;
5033 : GEN C, D, z;
5034 : GEN (*pack)(GEN, long), (*unpack)(GEN, ulong);
5035 12427 : int is_sqr = A==B;
5036 :
5037 12427 : z = muliu(muliu(sqru(p - 1), d), n);
5038 12427 : b = expi(z) + 1;
5039 : /* only do expensive bit-packing if it saves at least 1 limb */
5040 12427 : if (b <= BITS_IN_HALFULONG) {
5041 11971 : if (nbits2lg(d*b) - 2 == (d + 1)/2)
5042 10150 : b = BITS_IN_HALFULONG;
5043 : } else {
5044 456 : long l = lgefint(z) - 2;
5045 456 : if (nbits2lg(d*b) - 2 == d*l)
5046 351 : b = l*BITS_IN_LONG;
5047 : }
5048 12427 : avma = av;
5049 :
5050 12427 : switch (b) {
5051 : case BITS_IN_HALFULONG:
5052 10150 : pack = kron_pack_Flx_spec_half;
5053 10150 : unpack = int_to_Flx_half;
5054 10150 : break;
5055 : case BITS_IN_LONG:
5056 351 : pack = kron_pack_Flx_spec;
5057 351 : unpack = kron_unpack_Flx;
5058 351 : break;
5059 : case 2*BITS_IN_LONG:
5060 0 : pack = kron_pack_Flx_spec_2;
5061 0 : unpack = kron_unpack_Flx_2;
5062 0 : break;
5063 : case 3*BITS_IN_LONG:
5064 0 : pack = kron_pack_Flx_spec_3;
5065 0 : unpack = kron_unpack_Flx_3;
5066 0 : break;
5067 : default:
5068 1926 : A = FlxM_pack_ZM_bits(A, b);
5069 1926 : B = is_sqr? A: FlxM_pack_ZM_bits(B, b);
5070 1926 : C = ZM_mul(A, B);
5071 1926 : D = ZM_unpack_FlxqM_bits(C, b, T, p);
5072 1926 : return gerepilecopy(av, D);
5073 : }
5074 10501 : A = FlxM_pack_ZM(A, pack);
5075 10501 : B = is_sqr? A: FlxM_pack_ZM(B, pack);
5076 10501 : C = ZM_mul(A, B);
5077 10501 : D = ZM_unpack_FlxqM(C, T, p, unpack);
5078 10501 : return gerepilecopy(av, D);
5079 : }
5080 :
5081 : /*******************************************************************/
5082 : /* */
5083 : /* (Fl[X]/T(X))[Y] / S(Y) */
5084 : /* */
5085 : /*******************************************************************/
5086 :
5087 : GEN
5088 310976 : FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p) {
5089 310976 : return FlxqX_rem(FlxqX_mul(x,y,T,p),S,T,p);
5090 : }
5091 :
5092 : GEN
5093 190759 : FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p) {
5094 190759 : return FlxqX_rem(FlxqX_sqr(x,T,p),S,T,p);
5095 : }
5096 :
5097 : GEN
5098 14 : FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p)
5099 : {
5100 14 : GEN V, z = FlxqX_extgcd(get_FlxqX_mod(S), x, T, p, NULL, &V);
5101 14 : if (degpol(z)) return NULL;
5102 14 : z = Flxq_invsafe(gel(z,2),T,p);
5103 14 : if (!z) return NULL;
5104 14 : return FlxqX_Flxq_mul(V, z, T, p);
5105 : }
5106 :
5107 : GEN
5108 14 : FlxqXQ_inv(GEN x, GEN S, GEN T,ulong p)
5109 : {
5110 14 : pari_sp av = avma;
5111 14 : GEN U = FlxqXQ_invsafe(x, S, T, p);
5112 14 : if (!U) pari_err_INV("FlxqXQ_inv",x);
5113 14 : return gerepileupto(av, U);
5114 : }
5115 :
5116 : GEN
5117 0 : FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p) {
5118 0 : return FlxqXQ_mul(x, FlxqXQ_inv(y,S,T,p),S,T,p);
5119 : }
5120 :
5121 : struct _FlxqXQ {
5122 : GEN T, S;
5123 : ulong p;
5124 : };
5125 : static GEN
5126 532408 : _FlxqXQ_add(void *data, GEN x, GEN y) {
5127 532408 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5128 532408 : return FlxX_add(x,y, d->p);
5129 : }
5130 : static GEN
5131 2268 : _FlxqXQ_sub(void *data, GEN x, GEN y) {
5132 2268 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5133 2268 : return FlxX_sub(x,y, d->p);
5134 : }
5135 : static GEN
5136 653292 : _FlxqXQ_cmul(void *data, GEN P, long a, GEN x) {
5137 653292 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5138 653292 : return FlxX_Flx_mul(x,gel(P,a+2), d->p);
5139 : }
5140 : static GEN
5141 349342 : _FlxqXQ_red(void *data, GEN x) {
5142 349342 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5143 349342 : return FlxqX_red(x, d->T, d->p);
5144 : }
5145 : static GEN
5146 280470 : _FlxqXQ_mul(void *data, GEN x, GEN y) {
5147 280470 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5148 280470 : return FlxqXQ_mul(x,y, d->S,d->T, d->p);
5149 : }
5150 : static GEN
5151 190360 : _FlxqXQ_sqr(void *data, GEN x) {
5152 190360 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5153 190360 : return FlxqXQ_sqr(x, d->S,d->T, d->p);
5154 : }
5155 :
5156 : static GEN
5157 360922 : _FlxqXQ_one(void *data) {
5158 360922 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5159 360922 : return pol1_FlxX(get_FlxqX_var(d->S),get_Flx_var(d->T));
5160 : }
5161 :
5162 : static GEN
5163 184 : _FlxqXQ_zero(void *data) {
5164 184 : struct _FlxqXQ *d = (struct _FlxqXQ*) data;
5165 184 : return pol_0(get_FlxqX_var(d->S));
5166 : }
5167 :
5168 : static struct bb_algebra FlxqXQ_algebra = { _FlxqXQ_red, _FlxqXQ_add,
5169 : _FlxqXQ_sub, _FlxqXQ_mul, _FlxqXQ_sqr, _FlxqXQ_one, _FlxqXQ_zero };
5170 :
5171 : const struct bb_algebra *
5172 212 : get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p)
5173 : {
5174 212 : GEN z = new_chunk(sizeof(struct _FlxqXQ));
5175 212 : struct _FlxqXQ *e = (struct _FlxqXQ *) z;
5176 212 : e->T = Flx_get_red(T, p);
5177 212 : e->S = FlxqX_get_red(S, e->T, p);
5178 212 : e->p = p; *E = (void*)e;
5179 212 : return &FlxqXQ_algebra;
5180 : }
5181 :
5182 : /* x over Fq, return lift(x^n) mod S */
5183 : GEN
5184 42 : FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p)
5185 : {
5186 : struct _FlxqXQ D;
5187 42 : long s = signe(n);
5188 42 : if (!s) return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));
5189 42 : if (s < 0) x = FlxqXQ_inv(x,S,T,p);
5190 42 : if (is_pm1(n)) return s < 0 ? x : gcopy(x);
5191 42 : if (degpol(x)>=degpol(S)) x = FlxqX_rem(x,S,T,p);
5192 42 : T = Flx_get_red(T, p);
5193 42 : S = FlxqX_get_red(S, T, p);
5194 42 : D.S = S;
5195 42 : D.T = T;
5196 42 : D.p = p;
5197 42 : return gen_pow(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);
5198 : }
5199 :
5200 : /* x over Fq, return lift(x^n) mod S */
5201 : GEN
5202 72488 : FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p)
5203 : {
5204 : struct _FlxqXQ D;
5205 72488 : switch(n)
5206 : {
5207 0 : case 0: return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));
5208 7532 : case 1: return gcopy(x);
5209 399 : case 2: return FlxqXQ_sqr(x, S, T, p);
5210 : }
5211 64557 : T = Flx_get_red(T, p);
5212 64557 : S = FlxqX_get_red(S, T, p);
5213 64557 : D.S = S; D.T = T; D.p = p;
5214 64557 : return gen_powu(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);
5215 : }
5216 :
5217 : GEN
5218 28942 : FlxqXQ_powers(GEN x, long l, GEN S, GEN T, ulong p)
5219 : {
5220 : struct _FlxqXQ D;
5221 28942 : int use_sqr = 2*degpol(x) >= get_FlxqX_degree(S);
5222 28942 : T = Flx_get_red(T, p);
5223 28942 : S = FlxqX_get_red(S, T, p);
5224 28942 : D.S = S; D.T = T; D.p = p;
5225 28942 : return gen_powers(x, l, use_sqr, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul,&_FlxqXQ_one);
5226 : }
5227 :
5228 : static GEN
5229 486 : FlxqXn_mul(GEN a, GEN b, long n, GEN T, ulong p)
5230 : {
5231 486 : return RgXn_red_shallow(FlxqX_mul(a, b, T, p), n);
5232 : }
5233 :
5234 : /* Let v a linear form, return the linear form z->v(tau*z)
5235 : that is, v*(M_tau) */
5236 :
5237 : static GEN
5238 320 : FlxqXQ_transmul_init(GEN tau, GEN S, GEN T, ulong p)
5239 : {
5240 : GEN bht;
5241 320 : GEN h, Sp = get_FlxqX_red(S, &h);
5242 320 : long n = degpol(Sp), vS = varn(Sp), vT = get_Flx_var(T);
5243 320 : GEN ft = FlxX_recipspec(Sp+2, n+1, n+1, vT);
5244 320 : GEN bt = FlxX_recipspec(tau+2, lgpol(tau), n, vT);
5245 320 : setvarn(ft, vS); setvarn(bt, vS);
5246 320 : if (h)
5247 0 : bht = FlxqXn_mul(bt, h, n-1, T, p);
5248 : else
5249 : {
5250 320 : GEN bh = FlxqX_div(RgX_shift_shallow(tau, n-1), S, T, p);
5251 320 : bht = FlxX_recipspec(bh+2, lgpol(bh), n-1, vT);
5252 320 : setvarn(bht, vS);
5253 : }
5254 320 : return mkvec3(bt, bht, ft);
5255 : }
5256 :
5257 : static GEN
5258 632 : FlxqXQ_transmul(GEN tau, GEN a, long n, GEN T, ulong p)
5259 : {
5260 632 : pari_sp ltop = avma;
5261 : GEN t1, t2, t3, vec;
5262 632 : GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
5263 632 : if (signe(a)==0) return pol_0(varn(a));
5264 618 : t2 = RgX_shift_shallow(FlxqX_mul(bt, a, T, p),1-n);
5265 618 : if (signe(bht)==0) return gerepilecopy(ltop, t2);
5266 486 : t1 = RgX_shift_shallow(FlxqX_mul(ft, a, T, p),-n);
5267 486 : t3 = FlxqXn_mul(t1, bht, n-1, T, p);
5268 486 : vec = FlxX_sub(t2, RgX_shift_shallow(t3, 1), p);
5269 486 : return gerepileupto(ltop, vec);
5270 : }
5271 :
5272 : static GEN
5273 160 : polxn_FlxX(long n, long v, long vT)
5274 : {
5275 160 : long i, a = n+2;
5276 160 : GEN p = cgetg(a+1, t_POL);
5277 160 : p[1] = evalsigne(1)|evalvarn(v);
5278 160 : for (i = 2; i < a; i++) gel(p,i) = pol0_Flx(vT);
5279 160 : gel(p,a) = pol1_Flx(vT); return p;
5280 : }
5281 :
5282 : GEN
5283 132 : FlxqXQ_minpoly(GEN x, GEN S, GEN T, ulong p)
5284 : {
5285 132 : pari_sp ltop = avma;
5286 : long vS, vT, n;
5287 : GEN v_x, g, tau;
5288 132 : vS = get_FlxqX_var(S);
5289 132 : vT = get_Flx_var(T);
5290 132 : n = get_FlxqX_degree(S);
5291 132 : g = pol_1(vS);
5292 132 : tau = pol_1(vS);
5293 132 : S = FlxqX_get_red(S, T, p);
5294 132 : v_x = FlxqXQ_powers(x, usqrt(2*n), S, T, p);
5295 424 : while(signe(tau) != 0)
5296 : {
5297 : long i, j, m, k1;
5298 : GEN M, v, tr;
5299 : GEN g_prime, c;
5300 160 : if (degpol(g) == n) { tau = pol1_FlxX(vS, vT); g = pol1_FlxX(vS, vT); }
5301 160 : v = random_FlxqX(n, vS, T, p);
5302 160 : tr = FlxqXQ_transmul_init(tau, S, T, p);
5303 160 : v = FlxqXQ_transmul(tr, v, n, T, p);
5304 160 : m = 2*(n-degpol(g));
5305 160 : k1 = usqrt(m);
5306 160 : tr = FlxqXQ_transmul_init(gel(v_x,k1+1), S, T, p);
5307 160 : c = cgetg(m+2,t_POL);
5308 160 : c[1] = evalsigne(1)|evalvarn(vS);
5309 632 : for (i=0; i<m; i+=k1)
5310 : {
5311 472 : long mj = minss(m-i, k1);
5312 1440 : for (j=0; j<mj; j++)
5313 968 : gel(c,m+1-(i+j)) = FlxqX_dotproduct(v, gel(v_x,j+1), T, p);
5314 472 : v = FlxqXQ_transmul(tr, v, n, T, p);
5315 : }
5316 160 : c = FlxX_renormalize(c, m+2);
5317 : /* now c contains <v,x^i> , i = 0..m-1 */
5318 160 : M = FlxqX_halfgcd(polxn_FlxX(m, vS, vT), c, T, p);
5319 160 : g_prime = gmael(M, 2, 2);
5320 160 : if (degpol(g_prime) < 1) continue;
5321 153 : g = FlxqX_mul(g, g_prime, T, p);
5322 153 : tau = FlxqXQ_mul(tau, FlxqX_FlxqXQV_eval(g_prime, v_x, S, T, p), S, T, p);
5323 : }
5324 132 : g = FlxqX_normalize(g,T, p);
5325 132 : return gerepilecopy(ltop,g);
5326 : }
5327 :
5328 : GEN
5329 0 : FlxqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, ulong p)
5330 : {
5331 0 : return FlxXV_to_FlxM(FlxqXQ_powers(y,m-1,S,T,p), n, T[1]);
5332 : }
5333 :
5334 : GEN
5335 57157 : FlxqX_FlxqXQV_eval(GEN P, GEN V, GEN S, GEN T, ulong p)
5336 : {
5337 : struct _FlxqXQ D;
5338 57157 : T = Flx_get_red(T, p);
5339 57157 : S = FlxqX_get_red(S, T, p);
5340 57157 : D.S=S; D.T=T; D.p=p;
5341 57157 : return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &FlxqXQ_algebra,
5342 : _FlxqXQ_cmul);
5343 : }
5344 :
5345 : GEN
5346 63727 : FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)
5347 : {
5348 : struct _FlxqXQ D;
5349 63727 : int use_sqr = 2*degpol(x) >= degpol(S);
5350 63727 : T = Flx_get_red(T, p);
5351 63727 : S = FlxqX_get_red(S, T, p);
5352 63727 : D.S=S; D.T=T; D.p=p;
5353 63727 : return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &FlxqXQ_algebra,
5354 : _FlxqXQ_cmul);
5355 : }
5356 :
5357 : static GEN
5358 62414 : FlxqXQ_autpow_sqr(void * E, GEN x)
5359 : {
5360 62414 : struct _FlxqXQ *D = (struct _FlxqXQ *)E;
5361 62414 : GEN S = D->S, T = D->T;
5362 62414 : ulong p = D->p;
5363 62414 : GEN phi = gel(x,1), S1 = gel(x,2);
5364 62414 : long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);
5365 62414 : GEN V = Flxq_powers(phi, n, T, p);
5366 62414 : GEN phi2 = Flx_FlxqV_eval(phi, V, T, p);
5367 62414 : GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p);
5368 62414 : GEN S2 = FlxqX_FlxqXQ_eval(Sphi, S1, S, T, p);
5369 62414 : return mkvec2(phi2, S2);
5370 : }
5371 :
5372 : static GEN
5373 1084 : FlxqXQ_autpow_mul(void * E, GEN x, GEN y)
5374 : {
5375 1084 : struct _FlxqXQ *D = (struct _FlxqXQ *)E;
5376 1084 : GEN S = D->S, T = D->T;
5377 1084 : ulong p = D->p;
5378 1084 : GEN phi1 = gel(x,1), S1 = gel(x,2);
5379 1084 : GEN phi2 = gel(y,1), S2 = gel(y,2);
5380 1084 : long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);
5381 1084 : GEN V = Flxq_powers(phi2, n, T, p);
5382 1084 : GEN phi3 = Flx_FlxqV_eval(phi1, V, T, p);
5383 1084 : GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p);
5384 1084 : GEN S3 = FlxqX_FlxqXQ_eval(Sphi, S2, S, T, p);
5385 1084 : return mkvec2(phi3, S3);
5386 : }
5387 :
5388 : GEN
5389 61266 : FlxqXQ_autpow(GEN aut, long n, GEN S, GEN T, ulong p)
5390 : {
5391 : struct _FlxqXQ D;
5392 61266 : T = Flx_get_red(T, p);
5393 61266 : S = FlxqX_get_red(S, T, p);
5394 61266 : D.S=S; D.T=T; D.p=p;
5395 61266 : return gen_powu(aut,n,&D,FlxqXQ_autpow_sqr,FlxqXQ_autpow_mul);
5396 : }
5397 :
5398 : static GEN
5399 28171 : FlxqXQ_autsum_mul(void *E, GEN x, GEN y)
5400 : {
5401 28171 : struct _FlxqXQ *D = (struct _FlxqXQ *)E;
5402 28171 : GEN S = D->S, T = D->T;
5403 28171 : ulong p = D->p;
5404 28171 : GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);
5405 28171 : GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);
5406 28171 : long n2 = brent_kung_optpow(get_Flx_degree(T)-1, lgpol(S1)+lgpol(a1)+1,1);
5407 28171 : GEN V2 = Flxq_powers(phi2, n2, T, p);
5408 28171 : GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p);
5409 28171 : GEN Sphi = FlxY_FlxqV_evalx(S1, V2, T, p);
5410 28171 : GEN aphi = FlxY_FlxqV_evalx(a1, V2, T, p);
5411 28171 : long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);
5412 28171 : GEN V = FlxqXQ_powers(S2, n, S, T, p);
5413 28171 : GEN S3 = FlxqX_FlxqXQV_eval(Sphi, V, S, T, p);
5414 28171 : GEN aS = FlxqX_FlxqXQV_eval(aphi, V, S, T, p);
5415 28171 : GEN a3 = FlxqXQ_mul(aS, a2, S, T, p);
5416 28171 : return mkvec3(phi3, S3, a3);
5417 : }
5418 :
5419 : static GEN
5420 16869 : FlxqXQ_autsum_sqr(void * T, GEN x)
5421 16869 : { return FlxqXQ_autsum_mul(T, x, x); }
5422 :
5423 : GEN
5424 10791 : FlxqXQ_autsum(GEN aut, long n, GEN S, GEN T, ulong p)
5425 : {
5426 : struct _FlxqXQ D;
5427 10791 : T = Flx_get_red(T, p);
5428 10791 : S = FlxqX_get_red(S, T, p);
5429 10791 : D.S=S; D.T=T; D.p=p;
5430 10791 : return gen_powu(aut,n,&D,FlxqXQ_autsum_sqr,FlxqXQ_autsum_mul);
5431 : }
5432 :
5433 : static GEN
5434 20 : FlxqXQ_auttrace_mul(void *E, GEN x, GEN y)
5435 : {
5436 20 : struct _FlxqXQ *D = (struct _FlxqXQ *)E;
5437 20 : GEN S = D->S, T = D->T;
5438 20 : ulong p = D->p;
5439 20 : GEN S1 = gel(x,1), a1 = gel(x,2);
5440 20 : GEN S2 = gel(y,1), a2 = gel(y,2);
5441 20 : long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1);
5442 20 : GEN V = FlxqXQ_powers(S2, n, S, T, p);
5443 20 : GEN S3 = FlxqX_FlxqXQV_eval(S1, V, S, T, p);
5444 20 : GEN aS = FlxqX_FlxqXQV_eval(a1, V, S, T, p);
5445 20 : GEN a3 = FlxX_add(aS, a2, p);
5446 20 : return mkvec2(S3, a3);
5447 : }
5448 :
5449 : static GEN
5450 20 : FlxqXQ_auttrace_sqr(void *E, GEN x)
5451 20 : { return FlxqXQ_auttrace_mul(E, x, x); }
5452 :
5453 : GEN
5454 314 : FlxqXQ_auttrace(GEN x, ulong n, GEN S, GEN T, ulong p)
5455 : {
5456 : struct _FlxqXQ D;
5457 314 : T = Flx_get_red(T, p);
5458 314 : S = FlxqX_get_red(S, T, p);
5459 314 : D.S=S; D.T=T; D.p=p;
5460 314 : return gen_powu(x,n,(void*)&D,FlxqXQ_auttrace_sqr,FlxqXQ_auttrace_mul);
5461 : }
5462 :
5463 : /*******************************************************************/
5464 : /* */
5465 : /* FlxYqQ */
5466 : /* */
5467 : /*******************************************************************/
5468 :
5469 : /*Preliminary implementation to speed up FpX_ffisom*/
5470 : typedef struct {
5471 : GEN S, T;
5472 : ulong p;
5473 : } FlxYqq_muldata;
5474 :
5475 : /* reduce x in Fl[X, Y] in the algebra Fl[X, Y]/ (P(X),Q(Y)) */
5476 : static GEN
5477 9548 : FlxYqq_redswap(GEN x, GEN S, GEN T, ulong p)
5478 : {
5479 9548 : pari_sp ltop=avma;
5480 9548 : long n = get_Flx_degree(S);
5481 9548 : long m = get_Flx_degree(T);
5482 9548 : long w = get_Flx_var(T);
5483 9548 : GEN V = FlxX_swap(x,m,w);
5484 9548 : V = FlxqX_red(V,S,p);
5485 9548 : V = FlxX_swap(V,n,w);
5486 9548 : return gerepilecopy(ltop,V);
5487 : }
5488 : static GEN
5489 6622 : FlxYqq_sqr(void *data, GEN x)
5490 : {
5491 6622 : FlxYqq_muldata *D = (FlxYqq_muldata*)data;
5492 6622 : return FlxYqq_redswap(FlxqX_sqr(x, D->T, D->p),D->S,D->T,D->p);
5493 : }
5494 :
5495 : static GEN
5496 2926 : FlxYqq_mul(void *data, GEN x, GEN y)
5497 : {
5498 2926 : FlxYqq_muldata *D = (FlxYqq_muldata*)data;
5499 2926 : return FlxYqq_redswap(FlxqX_mul(x,y, D->T, D->p),D->S,D->T,D->p);
5500 : }
5501 :
5502 : /* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */
5503 : GEN
5504 3570 : FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p)
5505 : {
5506 3570 : pari_sp av = avma;
5507 : FlxYqq_muldata D;
5508 : GEN y;
5509 3570 : D.S = S;
5510 3570 : D.T = T;
5511 3570 : D.p = p;
5512 3570 : y = gen_pow(x, n, (void*)&D, &FlxYqq_sqr, &FlxYqq_mul);
5513 3570 : return gerepileupto(av, y);
5514 : }
|