Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

Testing latest pari + WASM + node.js... and it works?! Wow.

28485 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2007 The PARI group.
2
3
This file is part of the PARI/GP package.
4
5
PARI/GP is free software; you can redistribute it and/or modify it under the
6
terms of the GNU General Public License as published by the Free Software
7
Foundation; either version 2 of the License, or (at your option) any later
8
version. It is distributed in the hope that it will be useful, but WITHOUT
9
ANY WARRANTY WHATSOEVER.
10
11
Check the License for details. You should have received a copy of it, along
12
with the package; see the file 'COPYING'. If not, write to the Free Software
13
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14
15
#include "pari.h"
16
#include "paripriv.h"
17
18
/* Not so fast arithmetic with polynomials over Fp */
19
20
static GEN
21
get_FpX_red(GEN T, GEN *B)
22
{
23
if (typ(T)!=t_VEC) { *B=NULL; return T; }
24
*B = gel(T,1); return gel(T,2);
25
}
26
27
/***********************************************************************/
28
/** **/
29
/** FpX **/
30
/** **/
31
/***********************************************************************/
32
33
/* FpX are polynomials over Z/pZ represented as t_POL with
34
* t_INT coefficients.
35
* 1) Coefficients should belong to {0,...,p-1}, though nonreduced
36
* coefficients should work but be slower.
37
*
38
* 2) p is not assumed to be prime, but it is assumed that impossible divisions
39
* will not happen.
40
* 3) Theses functions let some garbage on the stack, but are gerepileupto
41
* compatible.
42
*/
43
44
static ulong
45
to_Flx(GEN *P, GEN *Q, GEN p)
46
{
47
ulong pp = uel(p,2);
48
*P = ZX_to_Flx(*P, pp);
49
if(Q) *Q = ZX_to_Flx(*Q, pp);
50
return pp;
51
}
52
53
static ulong
54
to_Flxq(GEN *P, GEN *T, GEN p)
55
{
56
ulong pp = uel(p,2);
57
if (P) *P = ZX_to_Flx(*P, pp);
58
*T = ZXT_to_FlxT(*T, pp); return pp;
59
}
60
61
GEN
62
Z_to_FpX(GEN a, GEN p, long v)
63
{
64
pari_sp av = avma;
65
GEN z = cgetg(3, t_POL);
66
GEN x = modii(a, p);
67
if (!signe(x)) { set_avma(av); return pol_0(v); }
68
z[1] = evalsigne(1) | evalvarn(v);
69
gel(z,2) = x; return z;
70
}
71
72
/* z in Z[X], return lift(z * Mod(1,p)), normalized*/
73
GEN
74
FpX_red(GEN z, GEN p)
75
{
76
long i, l = lg(z);
77
GEN x = cgetg(l, t_POL);
78
for (i=2; i<l; i++) gel(x,i) = modii(gel(z,i),p);
79
x[1] = z[1]; return FpX_renormalize(x,l);
80
}
81
82
GEN
83
FpXV_red(GEN x, GEN p)
84
{ pari_APPLY_type(t_VEC, FpX_red(gel(x,i), p)) }
85
86
GEN
87
FpXT_red(GEN x, GEN p)
88
{
89
if (typ(x) == t_POL)
90
return FpX_red(x, p);
91
else
92
pari_APPLY_type(t_VEC, FpXT_red(gel(x,i), p))
93
}
94
95
GEN
96
FpX_normalize(GEN z, GEN p)
97
{
98
GEN p1 = leading_coeff(z);
99
if (lg(z) == 2 || equali1(p1)) return z;
100
return FpX_Fp_mul_to_monic(z, Fp_inv(p1,p), p);
101
}
102
103
GEN
104
FpX_center(GEN T, GEN p, GEN pov2)
105
{
106
long i, l = lg(T);
107
GEN P = cgetg(l,t_POL);
108
for(i=2; i<l; i++) gel(P,i) = Fp_center(gel(T,i), p, pov2);
109
P[1] = T[1]; return P;
110
}
111
GEN
112
FpX_center_i(GEN T, GEN p, GEN pov2)
113
{
114
long i, l = lg(T);
115
GEN P = cgetg(l,t_POL);
116
for(i=2; i<l; i++) gel(P,i) = Fp_center_i(gel(T,i), p, pov2);
117
P[1] = T[1]; return P;
118
}
119
120
GEN
121
FpX_add(GEN x,GEN y,GEN p)
122
{
123
long lx = lg(x), ly = lg(y), i;
124
GEN z;
125
if (lx < ly) swapspec(x,y, lx,ly);
126
z = cgetg(lx,t_POL); z[1] = x[1];
127
for (i=2; i<ly; i++) gel(z,i) = Fp_add(gel(x,i),gel(y,i), p);
128
for ( ; i<lx; i++) gel(z,i) = modii(gel(x,i), p);
129
z = ZX_renormalize(z, lx);
130
if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }
131
return z;
132
}
133
134
static GEN
135
Fp_red_FpX(GEN x, GEN p, long v)
136
{
137
GEN z;
138
if (!signe(x)) return pol_0(v);
139
z = cgetg(3, t_POL);
140
gel(z,2) = Fp_red(x,p);
141
z[1] = evalvarn(v);
142
return FpX_renormalize(z, 3);
143
}
144
145
static GEN
146
Fp_neg_FpX(GEN x, GEN p, long v)
147
{
148
GEN z;
149
if (!signe(x)) return pol_0(v);
150
z = cgetg(3, t_POL);
151
gel(z,2) = Fp_neg(x,p);
152
z[1] = evalvarn(v);
153
return FpX_renormalize(z, 3);
154
}
155
156
GEN
157
FpX_Fp_add(GEN y,GEN x,GEN p)
158
{
159
long i, lz = lg(y);
160
GEN z;
161
if (lz == 2) return Fp_red_FpX(x,p,varn(y));
162
z = cgetg(lz,t_POL); z[1] = y[1];
163
gel(z,2) = Fp_add(gel(y,2),x, p);
164
if (lz == 3) z = FpX_renormalize(z,lz);
165
else
166
for(i=3;i<lz;i++) gel(z,i) = icopy(gel(y,i));
167
return z;
168
}
169
GEN
170
FpX_Fp_add_shallow(GEN y,GEN x,GEN p)
171
{
172
long i, lz = lg(y);
173
GEN z;
174
if (lz == 2) return scalar_ZX_shallow(x,varn(y));
175
z = cgetg(lz,t_POL); z[1] = y[1];
176
gel(z,2) = Fp_add(gel(y,2),x, p);
177
if (lz == 3) z = FpX_renormalize(z,lz);
178
else
179
for(i=3;i<lz;i++) gel(z,i) = gel(y,i);
180
return z;
181
}
182
GEN
183
FpX_Fp_sub(GEN y,GEN x,GEN p)
184
{
185
long i, lz = lg(y);
186
GEN z;
187
if (lz == 2) return Fp_neg_FpX(x,p,varn(y));
188
z = cgetg(lz,t_POL); z[1] = y[1];
189
gel(z,2) = Fp_sub(gel(y,2),x, p);
190
if (lz == 3) z = FpX_renormalize(z,lz);
191
else
192
for(i=3;i<lz;i++) gel(z,i) = icopy(gel(y,i));
193
return z;
194
}
195
GEN
196
FpX_Fp_sub_shallow(GEN y,GEN x,GEN p)
197
{
198
long i, lz = lg(y);
199
GEN z;
200
if (lz == 2) return Fp_neg_FpX(x,p,varn(y));
201
z = cgetg(lz,t_POL); z[1] = y[1];
202
gel(z,2) = Fp_sub(gel(y,2),x, p);
203
if (lz == 3) z = FpX_renormalize(z,lz);
204
else
205
for(i=3;i<lz;i++) gel(z,i) = gel(y,i);
206
return z;
207
}
208
209
GEN
210
FpX_neg(GEN x,GEN p)
211
{
212
long i, lx = lg(x);
213
GEN y = cgetg(lx,t_POL);
214
y[1] = x[1];
215
for(i=2; i<lx; i++) gel(y,i) = Fp_neg(gel(x,i), p);
216
return ZX_renormalize(y, lx);
217
}
218
219
static GEN
220
FpX_subspec(GEN x,GEN y,GEN p, long nx, long ny)
221
{
222
long i, lz;
223
GEN z;
224
if (nx >= ny)
225
{
226
lz = nx+2;
227
z = cgetg(lz,t_POL); z[1] = 0; z += 2;
228
for (i=0; i<ny; i++) gel(z,i) = Fp_sub(gel(x,i),gel(y,i), p);
229
for ( ; i<nx; i++) gel(z,i) = modii(gel(x,i), p);
230
}
231
else
232
{
233
lz = ny+2;
234
z = cgetg(lz,t_POL); z[1] = 0; z += 2;
235
for (i=0; i<nx; i++) gel(z,i) = Fp_sub(gel(x,i),gel(y,i), p);
236
for ( ; i<ny; i++) gel(z,i) = Fp_neg(gel(y,i), p);
237
}
238
z = FpX_renormalize(z-2, lz);
239
if (!lgpol(z)) { set_avma((pari_sp)(z + lz)); return pol_0(0); }
240
return z;
241
}
242
243
GEN
244
FpX_sub(GEN x,GEN y,GEN p)
245
{
246
GEN z = FpX_subspec(x+2,y+2,p,lgpol(x),lgpol(y));
247
setvarn(z, varn(x));
248
return z;
249
}
250
251
GEN
252
Fp_FpX_sub(GEN x, GEN y, GEN p)
253
{
254
long ly = lg(y), i;
255
GEN z;
256
if (ly <= 3) {
257
z = cgetg(3, t_POL);
258
x = (ly == 3)? Fp_sub(x, gel(y,2), p): modii(x, p);
259
if (!signe(x)) { set_avma((pari_sp)(z + 3)); return pol_0(varn(y)); }
260
z[1] = evalsigne(1)|y[1]; gel(z,2) = x; return z;
261
}
262
z = cgetg(ly,t_POL);
263
gel(z,2) = Fp_sub(x, gel(y,2), p);
264
for (i = 3; i < ly; i++) gel(z,i) = Fp_neg(gel(y,i), p);
265
z = ZX_renormalize(z, ly);
266
if (!lgpol(z)) { set_avma((pari_sp)(z + ly)); return pol_0(varn(x)); }
267
z[1] = y[1]; return z;
268
}
269
270
GEN
271
FpX_convol(GEN x, GEN y, GEN p)
272
{
273
long lx = lg(x), ly = lg(y), i;
274
GEN z;
275
if (lx < ly) swapspec(x,y, lx,ly);
276
z = cgetg(lx,t_POL); z[1] = x[1];
277
for (i=2; i<ly; i++) gel(z,i) = Fp_mul(gel(x,i),gel(y,i), p);
278
for ( ; i<lx; i++) gel(z,i) = modii(gel(x,i), p);
279
z = ZX_renormalize(z, lx);
280
if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }
281
return z;
282
}
283
284
GEN
285
FpX_mul(GEN x,GEN y,GEN p)
286
{
287
if (lgefint(p) == 3)
288
{
289
ulong pp = to_Flx(&x, &y, p);
290
return Flx_to_ZX(Flx_mul(x, y, pp));
291
}
292
return FpX_red(ZX_mul(x, y), p);
293
}
294
295
GEN
296
FpX_mulspec(GEN a, GEN b, GEN p, long na, long nb)
297
{ return FpX_red(ZX_mulspec(a, b, na, nb), p); }
298
299
GEN
300
FpX_sqr(GEN x,GEN p)
301
{
302
if (lgefint(p) == 3)
303
{
304
ulong pp = to_Flx(&x, NULL, p);
305
return Flx_to_ZX(Flx_sqr(x, pp));
306
}
307
return FpX_red(ZX_sqr(x), p);
308
}
309
310
GEN
311
FpX_mulu(GEN y, ulong x,GEN p)
312
{
313
GEN z;
314
long i, l;
315
x = umodui(x, p);
316
if (!x) return zeropol(varn(y));
317
z = cgetg_copy(y, &l); z[1] = y[1];
318
for(i=2; i<l; i++) gel(z,i) = Fp_mulu(gel(y,i), x, p);
319
return z;
320
}
321
322
GEN
323
FpX_divu(GEN y, ulong x, GEN p)
324
{
325
return FpX_Fp_div(y, utoi(umodui(x, p)), p);
326
}
327
328
GEN
329
FpX_Fp_mulspec(GEN y,GEN x,GEN p,long ly)
330
{
331
GEN z;
332
long i;
333
if (!signe(x)) return pol_0(0);
334
z = cgetg(ly+2,t_POL); z[1] = evalsigne(1);
335
for(i=0; i<ly; i++) gel(z,i+2) = Fp_mul(gel(y,i), x, p);
336
return ZX_renormalize(z, ly+2);
337
}
338
339
GEN
340
FpX_Fp_mul(GEN y,GEN x,GEN p)
341
{
342
GEN z = FpX_Fp_mulspec(y+2,x,p,lgpol(y));
343
setvarn(z, varn(y)); return z;
344
}
345
346
GEN
347
FpX_Fp_div(GEN y, GEN x, GEN p)
348
{
349
return FpX_Fp_mul(y, Fp_inv(x, p), p);
350
}
351
352
GEN
353
FpX_Fp_mul_to_monic(GEN y,GEN x,GEN p)
354
{
355
GEN z;
356
long i, l;
357
z = cgetg_copy(y, &l); z[1] = y[1];
358
for(i=2; i<l-1; i++) gel(z,i) = Fp_mul(gel(y,i), x, p);
359
gel(z,l-1) = gen_1; return z;
360
}
361
362
struct _FpXQ {
363
GEN T, p, aut;
364
};
365
366
struct _FpX
367
{
368
GEN p;
369
long v;
370
};
371
372
static GEN
373
_FpX_mul(void* E, GEN x, GEN y)
374
{ struct _FpX *D = (struct _FpX *)E; return FpX_mul(x, y, D->p); }
375
static GEN
376
_FpX_sqr(void *E, GEN x)
377
{ struct _FpX *D = (struct _FpX *)E; return FpX_sqr(x, D->p); }
378
379
GEN
380
FpX_powu(GEN x, ulong n, GEN p)
381
{
382
struct _FpX D;
383
if (n==0) return pol_1(varn(x));
384
D.p = p;
385
return gen_powu(x, n, (void *)&D, _FpX_sqr, _FpX_mul);
386
}
387
388
GEN
389
FpXV_prod(GEN V, GEN p)
390
{
391
struct _FpX D;
392
D.p = p;
393
return gen_product(V, (void *)&D, &_FpX_mul);
394
}
395
396
static GEN
397
_FpX_pow(void* E, GEN x, GEN y)
398
{ struct _FpX *D = (struct _FpX *)E; return FpX_powu(x, itou(y), D->p); }
399
static GEN
400
_FpX_one(void *E)
401
{ struct _FpX *D = (struct _FpX *)E; return pol_1(D->v); }
402
403
GEN
404
FpXV_factorback(GEN f, GEN e, GEN p, long v)
405
{
406
struct _FpX D;
407
D.p = p; D.v = v;
408
return gen_factorback(f, e, (void *)&D, &_FpX_mul, &_FpX_pow, &_FpX_one);
409
}
410
411
GEN
412
FpX_halve(GEN y, GEN p)
413
{
414
GEN z;
415
long i, l;
416
z = cgetg_copy(y, &l); z[1] = y[1];
417
for(i=2; i<l; i++) gel(z,i) = Fp_halve(gel(y,i), p);
418
return z;
419
}
420
421
static GEN
422
FpX_divrem_basecase(GEN x, GEN y, GEN p, GEN *pr)
423
{
424
long vx, dx, dy, dy1, dz, i, j, sx, lr;
425
pari_sp av0, av;
426
GEN z,p1,rem,lead;
427
428
if (!signe(y)) pari_err_INV("FpX_divrem",y);
429
vx = varn(x);
430
dy = degpol(y);
431
dx = degpol(x);
432
if (dx < dy)
433
{
434
if (pr)
435
{
436
av0 = avma; x = FpX_red(x, p);
437
if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
438
if (pr == ONLY_REM) return x;
439
*pr = x;
440
}
441
return pol_0(vx);
442
}
443
lead = leading_coeff(y);
444
if (!dy) /* y is constant */
445
{
446
if (pr && pr != ONLY_DIVIDES)
447
{
448
if (pr == ONLY_REM) return pol_0(vx);
449
*pr = pol_0(vx);
450
}
451
av0 = avma;
452
if (equali1(lead)) return FpX_red(x, p);
453
else return gerepileupto(av0, FpX_Fp_div(x, lead, p));
454
}
455
av0 = avma; dz = dx-dy;
456
if (lgefint(p) == 3)
457
{ /* assume ab != 0 mod p */
458
ulong pp = to_Flx(&x, &y, p);
459
z = Flx_divrem(x, y, pp, pr);
460
set_avma(av0); /* HACK: assume pr last on stack, then z */
461
if (!z) return NULL;
462
z = leafcopy(z);
463
if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)
464
{
465
*pr = leafcopy(*pr);
466
*pr = Flx_to_ZX_inplace(*pr);
467
}
468
return Flx_to_ZX_inplace(z);
469
}
470
lead = equali1(lead)? NULL: gclone(Fp_inv(lead,p));
471
set_avma(av0);
472
z=cgetg(dz+3,t_POL); z[1] = x[1];
473
x += 2; y += 2; z += 2;
474
for (dy1=dy-1; dy1>=0 && !signe(gel(y, dy1)); dy1--);
475
476
p1 = gel(x,dx); av = avma;
477
gel(z,dz) = lead? gerepileuptoint(av, Fp_mul(p1,lead, p)): icopy(p1);
478
for (i=dx-1; i>=dy; i--)
479
{
480
av=avma; p1=gel(x,i);
481
for (j=i-dy1; j<=i && j<=dz; j++)
482
p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));
483
if (lead) p1 = mulii(p1,lead);
484
gel(z,i-dy) = gerepileuptoint(av,modii(p1, p));
485
}
486
if (!pr) { guncloneNULL(lead); return z-2; }
487
488
rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
489
for (sx=0; ; i--)
490
{
491
p1 = gel(x,i);
492
for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)
493
p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));
494
p1 = modii(p1,p); if (signe(p1)) { sx = 1; break; }
495
if (!i) break;
496
set_avma(av);
497
}
498
if (pr == ONLY_DIVIDES)
499
{
500
guncloneNULL(lead);
501
if (sx) return gc_NULL(av0);
502
return gc_const((pari_sp)rem, z-2);
503
}
504
lr=i+3; rem -= lr;
505
rem[0] = evaltyp(t_POL) | evallg(lr);
506
rem[1] = z[-1];
507
p1 = gerepileuptoint((pari_sp)rem, p1);
508
rem += 2; gel(rem,i) = p1;
509
for (i--; i>=0; i--)
510
{
511
av=avma; p1 = gel(x,i);
512
for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)
513
p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));
514
gel(rem,i) = gerepileuptoint(av, modii(p1,p));
515
}
516
rem -= 2;
517
guncloneNULL(lead);
518
if (!sx) (void)FpX_renormalize(rem, lr);
519
if (pr == ONLY_REM) return gerepileupto(av0,rem);
520
*pr = rem; return z-2;
521
}
522
523
GEN
524
FpX_div_by_X_x(GEN a, GEN x, GEN p, GEN *r)
525
{
526
long l = lg(a), i;
527
GEN z;
528
if (l <= 3)
529
{
530
if (r) *r = l == 2? gen_0: icopy(gel(a,2));
531
return pol_0(0);
532
}
533
l--; z = cgetg(l, t_POL); z[1] = evalsigne(1) | evalvarn(0);
534
gel(z, l-1) = gel(a,l);
535
for (i = l-2; i > 1; i--) /* z[i] = a[i+1] + x*z[i+1] */
536
gel(z,i) = Fp_addmul(gel(a,i+1), x, gel(z,i+1), p);
537
if (r) *r = Fp_addmul(gel(a,2), x, gel(z,2), p);
538
return z;
539
}
540
541
static GEN
542
_FpX_divrem(void * E, GEN x, GEN y, GEN *r)
543
{
544
struct _FpX *D = (struct _FpX*) E;
545
return FpX_divrem(x, y, D->p, r);
546
}
547
static GEN
548
_FpX_add(void * E, GEN x, GEN y) {
549
struct _FpX *D = (struct _FpX*) E;
550
return FpX_add(x, y, D->p);
551
}
552
553
static struct bb_ring FpX_ring = { _FpX_add,_FpX_mul,_FpX_sqr };
554
555
GEN
556
FpX_digits(GEN x, GEN T, GEN p)
557
{
558
pari_sp av = avma;
559
struct _FpX D;
560
long d = degpol(T), n = (lgpol(x)+d-1)/d;
561
GEN z;
562
D.p = p;
563
z = gen_digits(x,T,n,(void *)&D, &FpX_ring, _FpX_divrem);
564
return gerepileupto(av, z);
565
}
566
567
GEN
568
FpXV_FpX_fromdigits(GEN x, GEN T, GEN p)
569
{
570
pari_sp av = avma;
571
struct _FpX D;
572
GEN z;
573
D.p = p;
574
z = gen_fromdigits(x,T,(void *)&D, &FpX_ring);
575
return gerepileupto(av, z);
576
}
577
578
long
579
FpX_valrem(GEN x, GEN t, GEN p, GEN *py)
580
{
581
pari_sp av=avma;
582
long k;
583
GEN r, y;
584
585
for (k=0; ; k++)
586
{
587
y = FpX_divrem(x, t, p, &r);
588
if (signe(r)) break;
589
x = y;
590
}
591
*py = gerepilecopy(av,x);
592
return k;
593
}
594
595
static GEN
596
FpX_halfgcd_basecase(GEN a, GEN b, GEN p)
597
{
598
pari_sp av=avma;
599
GEN u,u1,v,v1;
600
long vx = varn(a);
601
long n = lgpol(a)>>1;
602
u1 = v = pol_0(vx);
603
u = v1 = pol_1(vx);
604
while (lgpol(b)>n)
605
{
606
GEN r, q = FpX_divrem(a,b,p, &r);
607
a = b; b = r; swap(u,u1); swap(v,v1);
608
u1 = FpX_sub(u1, FpX_mul(u, q, p), p);
609
v1 = FpX_sub(v1, FpX_mul(v, q ,p), p);
610
if (gc_needed(av,2))
611
{
612
if (DEBUGMEM>1) pari_warn(warnmem,"FpX_halfgcd (d = %ld)",degpol(b));
613
gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);
614
}
615
}
616
return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));
617
}
618
static GEN
619
FpX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN p)
620
{
621
return FpX_add(FpX_mul(u, x, p),FpX_mul(v, y, p), p);
622
}
623
624
static GEN
625
FpXM_FpX_mul2(GEN M, GEN x, GEN y, GEN p)
626
{
627
GEN res = cgetg(3, t_COL);
628
gel(res, 1) = FpX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p);
629
gel(res, 2) = FpX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p);
630
return res;
631
}
632
633
static GEN
634
FpXM_mul2(GEN A, GEN B, GEN p)
635
{
636
GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
637
GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
638
GEN M1 = FpX_mul(FpX_add(A11,A22, p), FpX_add(B11,B22, p), p);
639
GEN M2 = FpX_mul(FpX_add(A21,A22, p), B11, p);
640
GEN M3 = FpX_mul(A11, FpX_sub(B12,B22, p), p);
641
GEN M4 = FpX_mul(A22, FpX_sub(B21,B11, p), p);
642
GEN M5 = FpX_mul(FpX_add(A11,A12, p), B22, p);
643
GEN M6 = FpX_mul(FpX_sub(A21,A11, p), FpX_add(B11,B12, p), p);
644
GEN M7 = FpX_mul(FpX_sub(A12,A22, p), FpX_add(B21,B22, p), p);
645
GEN T1 = FpX_add(M1,M4, p), T2 = FpX_sub(M7,M5, p);
646
GEN T3 = FpX_sub(M1,M2, p), T4 = FpX_add(M3,M6, p);
647
retmkmat2(mkcol2(FpX_add(T1,T2, p), FpX_add(M2,M4, p)),
648
mkcol2(FpX_add(M3,M5, p), FpX_add(T3,T4, p)));
649
}
650
651
/* Return [0,1;1,-q]*M */
652
static GEN
653
FpX_FpXM_qmul(GEN q, GEN M, GEN p)
654
{
655
GEN u, v, res = cgetg(3, t_MAT);
656
u = FpX_sub(gcoeff(M,1,1), FpX_mul(gcoeff(M,2,1), q, p), p);
657
gel(res,1) = mkcol2(gcoeff(M,2,1), u);
658
v = FpX_sub(gcoeff(M,1,2), FpX_mul(gcoeff(M,2,2), q, p), p);
659
gel(res,2) = mkcol2(gcoeff(M,2,2), v);
660
return res;
661
}
662
663
static GEN
664
matid2_FpXM(long v)
665
{
666
retmkmat2(mkcol2(pol_1(v),pol_0(v)),
667
mkcol2(pol_0(v),pol_1(v)));
668
}
669
670
static GEN
671
FpX_shift(GEN a, long n) { return RgX_shift_shallow(a, n); }
672
673
static GEN
674
FpX_halfgcd_split(GEN x, GEN y, GEN p)
675
{
676
pari_sp av=avma;
677
GEN R, S, V;
678
GEN y1, r, q;
679
long l = lgpol(x), n = l>>1, k;
680
if (lgpol(y)<=n) return matid2_FpXM(varn(x));
681
R = FpX_halfgcd(FpX_shift(x,-n), FpX_shift(y,-n), p);
682
V = FpXM_FpX_mul2(R,x,y,p); y1 = gel(V,2);
683
if (lgpol(y1)<=n) return gerepilecopy(av, R);
684
q = FpX_divrem(gel(V,1), y1, p, &r);
685
k = 2*n-degpol(y1);
686
S = FpX_halfgcd(FpX_shift(y1,-k), FpX_shift(r,-k), p);
687
return gerepileupto(av, FpXM_mul2(S,FpX_FpXM_qmul(q,R,p),p));
688
}
689
690
/* Return M in GL_2(Fp[X]) such that:
691
if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
692
*/
693
694
static GEN
695
FpX_halfgcd_i(GEN x, GEN y, GEN p)
696
{
697
if (lg(x)<=FpX_HALFGCD_LIMIT) return FpX_halfgcd_basecase(x,y,p);
698
return FpX_halfgcd_split(x,y,p);
699
}
700
701
GEN
702
FpX_halfgcd(GEN x, GEN y, GEN p)
703
{
704
pari_sp av = avma;
705
GEN M,q,r;
706
if (lgefint(p)==3)
707
{
708
ulong pp = to_Flx(&x, &y, p);
709
M = FlxM_to_ZXM(Flx_halfgcd(x, y, pp));
710
}
711
else
712
{
713
if (!signe(x))
714
{
715
long v = varn(x);
716
retmkmat2(mkcol2(pol_0(v),pol_1(v)),
717
mkcol2(pol_1(v),pol_0(v)));
718
}
719
if (degpol(y)<degpol(x)) return FpX_halfgcd_i(x,y,p);
720
q = FpX_divrem(y,x,p,&r);
721
M = FpX_halfgcd_i(x,r,p);
722
gcoeff(M,1,1) = FpX_sub(gcoeff(M,1,1), FpX_mul(q, gcoeff(M,1,2), p), p);
723
gcoeff(M,2,1) = FpX_sub(gcoeff(M,2,1), FpX_mul(q, gcoeff(M,2,2), p), p);
724
}
725
return gerepilecopy(av, M);
726
}
727
728
static GEN
729
FpX_gcd_basecase(GEN a, GEN b, GEN p)
730
{
731
pari_sp av = avma, av0=avma;
732
while (signe(b))
733
{
734
GEN c;
735
if (gc_needed(av0,2))
736
{
737
if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd (d = %ld)",degpol(b));
738
gerepileall(av0,2, &a,&b);
739
}
740
av = avma; c = FpX_rem(a,b,p); a=b; b=c;
741
}
742
return gc_const(av, a);
743
}
744
745
GEN
746
FpX_gcd(GEN x, GEN y, GEN p)
747
{
748
pari_sp av = avma;
749
if (lgefint(p)==3)
750
{
751
ulong pp;
752
(void)new_chunk((lg(x) + lg(y)) << 2); /* scratch space */
753
pp = to_Flx(&x, &y, p);
754
x = Flx_gcd(x, y, pp);
755
set_avma(av); return Flx_to_ZX(x);
756
}
757
x = FpX_red(x, p);
758
y = FpX_red(y, p);
759
if (!signe(x)) return gerepileupto(av, y);
760
while (lg(y)>FpX_GCD_LIMIT)
761
{
762
GEN c;
763
if (lgpol(y)<=(lgpol(x)>>1))
764
{
765
GEN r = FpX_rem(x, y, p);
766
x = y; y = r;
767
}
768
c = FpXM_FpX_mul2(FpX_halfgcd(x,y, p), x, y, p);
769
x = gel(c,1); y = gel(c,2);
770
gerepileall(av,2,&x,&y);
771
}
772
return gerepileupto(av, FpX_gcd_basecase(x,y,p));
773
}
774
775
/* Return NULL if gcd can be computed else return a factor of p */
776
GEN
777
FpX_gcd_check(GEN x, GEN y, GEN p)
778
{
779
pari_sp av = avma;
780
GEN a,b,c;
781
782
a = FpX_red(x, p);
783
b = FpX_red(y, p);
784
while (signe(b))
785
{
786
GEN g;
787
if (!invmod(leading_coeff(b), p, &g)) return gerepileuptoint(av,g);
788
b = FpX_Fp_mul_to_monic(b, g, p);
789
c = FpX_rem(a, b, p); a = b; b = c;
790
if (gc_needed(av,1))
791
{
792
if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd_check (d = %ld)",degpol(b));
793
gerepileall(av,2,&a,&b);
794
}
795
}
796
return gc_NULL(av);
797
}
798
799
static GEN
800
FpX_extgcd_basecase(GEN a, GEN b, GEN p, GEN *ptu, GEN *ptv)
801
{
802
pari_sp av=avma;
803
GEN u,v,d,d1,v1;
804
long vx = varn(a);
805
d = a; d1 = b;
806
v = pol_0(vx); v1 = pol_1(vx);
807
while (signe(d1))
808
{
809
GEN r, q = FpX_divrem(d,d1,p, &r);
810
v = FpX_sub(v,FpX_mul(q,v1,p),p);
811
u=v; v=v1; v1=u;
812
u=r; d=d1; d1=u;
813
if (gc_needed(av,2))
814
{
815
if (DEBUGMEM>1) pari_warn(warnmem,"FpX_extgcd (d = %ld)",degpol(d));
816
gerepileall(av,5, &d,&d1,&u,&v,&v1);
817
}
818
}
819
if (ptu) *ptu = FpX_div(FpX_sub(d,FpX_mul(b,v,p),p),a,p);
820
*ptv = v; return d;
821
}
822
823
static GEN
824
FpX_extgcd_halfgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
825
{
826
pari_sp av=avma;
827
GEN u,v,R = matid2_FpXM(varn(x));
828
while (lg(y)>FpX_EXTGCD_LIMIT)
829
{
830
GEN M, c;
831
if (lgpol(y)<=(lgpol(x)>>1))
832
{
833
GEN r, q = FpX_divrem(x, y, p, &r);
834
x = y; y = r;
835
R = FpX_FpXM_qmul(q, R, p);
836
}
837
M = FpX_halfgcd(x,y, p);
838
c = FpXM_FpX_mul2(M, x,y, p);
839
R = FpXM_mul2(M, R, p);
840
x = gel(c,1); y = gel(c,2);
841
gerepileall(av,3,&x,&y,&R);
842
}
843
y = FpX_extgcd_basecase(x,y,p,&u,&v);
844
if (ptu) *ptu = FpX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1),p);
845
*ptv = FpX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2),p);
846
return y;
847
}
848
849
/* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st
850
* ux + vy = gcd (mod p) */
851
GEN
852
FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
853
{
854
GEN d;
855
pari_sp ltop=avma;
856
if (lgefint(p)==3)
857
{
858
ulong pp = to_Flx(&x, &y, p);
859
d = Flx_extgcd(x,y, pp, ptu,ptv);
860
d = Flx_to_ZX(d);
861
if (ptu) *ptu=Flx_to_ZX(*ptu);
862
*ptv=Flx_to_ZX(*ptv);
863
}
864
else
865
{
866
x = FpX_red(x, p);
867
y = FpX_red(y, p);
868
if (lg(y)>FpX_EXTGCD_LIMIT)
869
d = FpX_extgcd_halfgcd(x, y, p, ptu, ptv);
870
else
871
d = FpX_extgcd_basecase(x, y, p, ptu, ptv);
872
}
873
gerepileall(ltop,ptu?3:2,&d,ptv,ptu);
874
return d;
875
}
876
877
GEN
878
FpX_rescale(GEN P, GEN h, GEN p)
879
{
880
long i, l = lg(P);
881
GEN Q = cgetg(l,t_POL), hi = h;
882
gel(Q,l-1) = gel(P,l-1);
883
for (i=l-2; i>=2; i--)
884
{
885
gel(Q,i) = Fp_mul(gel(P,i), hi, p);
886
if (i == 2) break;
887
hi = Fp_mul(hi,h, p);
888
}
889
Q[1] = P[1]; return Q;
890
}
891
892
GEN
893
FpX_deriv(GEN x, GEN p) { return FpX_red(ZX_deriv(x), p); }
894
895
/* Compute intformal(x^n*S)/x^(n+1) */
896
static GEN
897
FpX_integXn(GEN x, long n, GEN p)
898
{
899
long i, lx = lg(x);
900
GEN y;
901
if (lx == 2) return ZX_copy(x);
902
y = cgetg(lx, t_POL); y[1] = x[1];
903
for (i=2; i<lx; i++)
904
{
905
GEN xi = gel(x,i);
906
if (!signe(xi))
907
gel(y,i) = gen_0;
908
else
909
{
910
ulong j = n+i-1;
911
ulong d = ugcd(j, umodiu(xi, j));
912
if (d==1)
913
gel(y,i) = Fp_divu(xi, j, p);
914
else
915
gel(y,i) = Fp_divu(diviuexact(xi, d), j/d, p);
916
}
917
}
918
return ZX_renormalize(y, lx);;
919
}
920
921
GEN
922
FpX_integ(GEN x, GEN p)
923
{
924
long i, lx = lg(x);
925
GEN y;
926
if (lx == 2) return ZX_copy(x);
927
y = cgetg(lx+1, t_POL); y[1] = x[1];
928
gel(y,2) = gen_0;
929
for (i=3; i<=lx; i++)
930
gel(y,i) = signe(gel(x,i-1))? Fp_divu(gel(x,i-1), i-2, p): gen_0;
931
return ZX_renormalize(y, lx+1);;
932
}
933
934
INLINE GEN
935
FpXn_recip(GEN P, long n)
936
{ return RgXn_recip_shallow(P, n); }
937
938
GEN
939
FpX_Newton(GEN P, long n, GEN p)
940
{
941
pari_sp av = avma;
942
GEN dP = FpX_deriv(P, p);
943
GEN Q = FpXn_recip(FpX_div(FpX_shift(dP,n), P, p), n);
944
return gerepilecopy(av, Q);
945
}
946
947
GEN
948
FpX_fromNewton(GEN P, GEN p)
949
{
950
pari_sp av = avma;
951
if (lgefint(p)==3)
952
{
953
ulong pp = p[2];
954
GEN Q = Flx_fromNewton(ZX_to_Flx(P, pp), pp);
955
return gerepileupto(av, Flx_to_ZX(Q));
956
} else
957
{
958
long n = itos(modii(constant_coeff(P), p))+1;
959
GEN z = FpX_neg(FpX_shift(P,-1),p);
960
GEN Q = FpXn_recip(FpXn_expint(z, n, p), n);
961
return gerepilecopy(av, Q);
962
}
963
}
964
965
GEN
966
FpX_invLaplace(GEN x, GEN p)
967
{
968
pari_sp av = avma;
969
long i, d = degpol(x);
970
GEN t, y;
971
if (d <= 1) return gcopy(x);
972
t = Fp_inv(factorial_Fp(d, p), p);
973
y = cgetg(d+3, t_POL);
974
y[1] = x[1];
975
for (i=d; i>=2; i--)
976
{
977
gel(y,i+2) = Fp_mul(gel(x,i+2), t, p);
978
t = Fp_mulu(t, i, p);
979
}
980
gel(y,3) = gel(x,3);
981
gel(y,2) = gel(x,2);
982
return gerepilecopy(av, y);
983
}
984
985
GEN
986
FpX_Laplace(GEN x, GEN p)
987
{
988
pari_sp av = avma;
989
long i, d = degpol(x);
990
GEN t = gen_1;
991
GEN y;
992
if (d <= 1) return gcopy(x);
993
y = cgetg(d+3, t_POL);
994
y[1] = x[1];
995
gel(y,2) = gel(x,2);
996
gel(y,3) = gel(x,3);
997
for (i=2; i<=d; i++)
998
{
999
t = Fp_mulu(t, i, p);
1000
gel(y,i+2) = Fp_mul(gel(x,i+2), t, p);
1001
}
1002
return gerepilecopy(av, y);
1003
}
1004
1005
int
1006
FpX_is_squarefree(GEN f, GEN p)
1007
{
1008
pari_sp av = avma;
1009
GEN z = FpX_gcd(f,FpX_deriv(f,p),p);
1010
set_avma(av);
1011
return degpol(z)==0;
1012
}
1013
1014
GEN
1015
random_FpX(long d1, long v, GEN p)
1016
{
1017
long i, d = d1+2;
1018
GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
1019
for (i=2; i<d; i++) gel(y,i) = randomi(p);
1020
return FpX_renormalize(y,d);
1021
}
1022
1023
GEN
1024
FpX_dotproduct(GEN x, GEN y, GEN p)
1025
{
1026
long i, l = minss(lg(x), lg(y));
1027
pari_sp av;
1028
GEN c;
1029
if (l == 2) return gen_0;
1030
av = avma; c = mulii(gel(x,2),gel(y,2));
1031
for (i=3; i<l; i++) c = addii(c, mulii(gel(x,i),gel(y,i)));
1032
return gerepileuptoint(av, modii(c,p));
1033
}
1034
1035
/* Evaluation in Fp
1036
* x a ZX and y an Fp, return x(y) mod p
1037
*
1038
* If p is very large (several longs) and x has small coefficients(<<p),
1039
* then Brent & Kung algorithm is faster. */
1040
GEN
1041
FpX_eval(GEN x,GEN y,GEN p)
1042
{
1043
pari_sp av;
1044
GEN p1,r,res;
1045
long j, i=lg(x)-1;
1046
if (i<=2 || !signe(y))
1047
return (i==1)? gen_0: modii(gel(x,2),p);
1048
res=cgeti(lgefint(p));
1049
av=avma; p1=gel(x,i);
1050
/* specific attention to sparse polynomials (see poleval)*/
1051
/*You've guessed it! It's a copy-paste(tm)*/
1052
for (i--; i>=2; i=j-1)
1053
{
1054
for (j=i; !signe(gel(x,j)); j--)
1055
if (j==2)
1056
{
1057
if (i!=j) y = Fp_powu(y,i-j+1,p);
1058
p1=mulii(p1,y);
1059
goto fppoleval;/*sorry break(2) no implemented*/
1060
}
1061
r = (i==j)? y: Fp_powu(y,i-j+1,p);
1062
p1 = Fp_addmul(gel(x,j), p1, r, p);
1063
if ((i & 7) == 0) { affii(p1, res); p1 = res; set_avma(av); }
1064
}
1065
fppoleval:
1066
modiiz(p1,p,res); return gc_const(av, res);
1067
}
1068
1069
/* Tz=Tx*Ty where Tx and Ty coprime
1070
* return lift(chinese(Mod(x*Mod(1,p),Tx*Mod(1,p)),Mod(y*Mod(1,p),Ty*Mod(1,p))))
1071
* if Tz is NULL it is computed
1072
* As we do not return it, and the caller will frequently need it,
1073
* it must compute it and pass it.
1074
*/
1075
GEN
1076
FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p)
1077
{
1078
pari_sp av = avma;
1079
GEN ax,p1;
1080
ax = FpX_mul(FpXQ_inv(Tx,Ty,p), Tx,p);
1081
p1 = FpX_mul(ax, FpX_sub(y,x,p),p);
1082
p1 = FpX_add(x,p1,p);
1083
if (!Tz) Tz=FpX_mul(Tx,Ty,p);
1084
p1 = FpX_rem(p1,Tz,p);
1085
return gerepileupto(av,p1);
1086
}
1087
1088
/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
1089
GEN
1090
FpX_resultant(GEN a, GEN b, GEN p)
1091
{
1092
long da,db,dc;
1093
pari_sp av;
1094
GEN c,lb, res = gen_1;
1095
1096
if (!signe(a) || !signe(b)) return gen_0;
1097
if (lgefint(p) == 3)
1098
{
1099
pari_sp av = avma;
1100
ulong pp = to_Flx(&a, &b, p);
1101
long r = Flx_resultant(a, b, pp);
1102
set_avma(av);
1103
return utoi(r);
1104
}
1105
1106
da = degpol(a);
1107
db = degpol(b);
1108
if (db > da)
1109
{
1110
swapspec(a,b, da,db);
1111
if (both_odd(da,db)) res = subii(p, res);
1112
}
1113
if (!da) return gen_1; /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
1114
av = avma;
1115
while (db)
1116
{
1117
lb = gel(b,db+2);
1118
c = FpX_rem(a,b, p);
1119
a = b; b = c; dc = degpol(c);
1120
if (dc < 0) return gc_const(av, gen_0);
1121
1122
if (both_odd(da,db)) res = subii(p, res);
1123
if (!equali1(lb)) res = Fp_mul(res, Fp_powu(lb, da - dc, p), p);
1124
if (gc_needed(av,2))
1125
{
1126
if (DEBUGMEM>1) pari_warn(warnmem,"FpX_resultant (da = %ld)",da);
1127
gerepileall(av,3, &a,&b,&res);
1128
}
1129
da = db; /* = degpol(a) */
1130
db = dc; /* = degpol(b) */
1131
}
1132
res = Fp_mul(res, Fp_powu(gel(b,2), da, p), p);
1133
return gerepileuptoint(av, res);
1134
}
1135
1136
/* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
1137
GEN
1138
FpX_disc(GEN P, GEN p)
1139
{
1140
pari_sp av = avma;
1141
GEN L, dP = FpX_deriv(P,p), D = FpX_resultant(P, dP, p);
1142
long dd;
1143
if (!signe(D)) return gen_0;
1144
dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
1145
L = leading_coeff(P);
1146
if (dd && !equali1(L))
1147
D = (dd == -1)? Fp_div(D,L,p): Fp_mul(D, Fp_powu(L, dd, p), p);
1148
if (degpol(P) & 2) D = Fp_neg(D ,p);
1149
return gerepileuptoint(av, D);
1150
}
1151
1152
GEN
1153
FpV_roots_to_pol(GEN V, GEN p, long v)
1154
{
1155
pari_sp ltop=avma;
1156
long i;
1157
GEN g=cgetg(lg(V),t_VEC);
1158
for(i=1;i<lg(V);i++)
1159
gel(g,i) = deg1pol_shallow(gen_1,modii(negi(gel(V,i)),p),v);
1160
return gerepileupto(ltop,FpXV_prod(g,p));
1161
}
1162
1163
/* invert all elements of x mod p using Montgomery's multi-inverse trick.
1164
* Not stack-clean. */
1165
GEN
1166
FpV_inv(GEN x, GEN p)
1167
{
1168
long i, lx = lg(x);
1169
GEN u, y = cgetg(lx, t_VEC);
1170
1171
gel(y,1) = gel(x,1);
1172
for (i=2; i<lx; i++) gel(y,i) = Fp_mul(gel(y,i-1), gel(x,i), p);
1173
1174
u = Fp_inv(gel(y,--i), p);
1175
for ( ; i > 1; i--)
1176
{
1177
gel(y,i) = Fp_mul(u, gel(y,i-1), p);
1178
u = Fp_mul(u, gel(x,i), p); /* u = 1 / (x[1] ... x[i-1]) */
1179
}
1180
gel(y,1) = u; return y;
1181
}
1182
GEN
1183
FqV_inv(GEN x, GEN T, GEN p)
1184
{
1185
long i, lx = lg(x);
1186
GEN u, y = cgetg(lx, t_VEC);
1187
1188
gel(y,1) = gel(x,1);
1189
for (i=2; i<lx; i++) gel(y,i) = Fq_mul(gel(y,i-1), gel(x,i), T,p);
1190
1191
u = Fq_inv(gel(y,--i), T,p);
1192
for ( ; i > 1; i--)
1193
{
1194
gel(y,i) = Fq_mul(u, gel(y,i-1), T,p);
1195
u = Fq_mul(u, gel(x,i), T,p); /* u = 1 / (x[1] ... x[i-1]) */
1196
}
1197
gel(y,1) = u; return y;
1198
}
1199
1200
/***********************************************************************/
1201
/** **/
1202
/** Barrett reduction **/
1203
/** **/
1204
/***********************************************************************/
1205
1206
static GEN
1207
FpX_invBarrett_basecase(GEN T, GEN p)
1208
{
1209
long i, l=lg(T)-1, lr = l-1, k;
1210
GEN r=cgetg(lr, t_POL); r[1]=T[1];
1211
gel(r,2) = gen_1;
1212
for (i=3; i<lr; i++)
1213
{
1214
pari_sp av = avma;
1215
GEN u = gel(T,l-i+2);
1216
for (k=3; k<i; k++)
1217
u = addii(u, mulii(gel(T,l-i+k), gel(r,k)));
1218
gel(r,i) = gerepileupto(av, modii(negi(u), p));
1219
}
1220
return FpX_renormalize(r,lr);
1221
}
1222
1223
/* Return new lgpol */
1224
static long
1225
ZX_lgrenormalizespec(GEN x, long lx)
1226
{
1227
long i;
1228
for (i = lx-1; i>=0; i--)
1229
if (signe(gel(x,i))) break;
1230
return i+1;
1231
}
1232
1233
INLINE GEN
1234
FpX_recipspec(GEN x, long l, long n)
1235
{
1236
return RgX_recipspec_shallow(x, l, n);
1237
}
1238
1239
static GEN
1240
FpX_invBarrett_Newton(GEN T, GEN p)
1241
{
1242
pari_sp av = avma;
1243
long nold, lx, lz, lq, l = degpol(T), i, lQ;
1244
GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
1245
ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
1246
for (i=0;i<l;i++) gel(x,i) = gen_0;
1247
q = FpX_recipspec(T+2,l+1,l+1); lQ = lgpol(q); q+=2;
1248
/* We work on _spec_ FpX's, all the l[xzq] below are lgpol's */
1249
1250
/* initialize */
1251
gel(x,0) = Fp_inv(gel(q,0), p);
1252
if (lQ>1) gel(q,1) = Fp_red(gel(q,1), p);
1253
if (lQ>1 && signe(gel(q,1)))
1254
{
1255
GEN u = gel(q, 1);
1256
if (!equali1(gel(x,0))) u = Fp_mul(u, Fp_sqr(gel(x,0), p), p);
1257
gel(x,1) = Fp_neg(u, p); lx = 2;
1258
}
1259
else
1260
lx = 1;
1261
nold = 1;
1262
for (; mask > 1; )
1263
{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
1264
long i, lnew, nnew = nold << 1;
1265
1266
if (mask & 1) nnew--;
1267
mask >>= 1;
1268
1269
lnew = nnew + 1;
1270
lq = ZX_lgrenormalizespec(q, minss(lQ,lnew));
1271
z = FpX_mulspec(x, q, p, lx, lq); /* FIXME: high product */
1272
lz = lgpol(z); if (lz > lnew) lz = lnew;
1273
z += 2;
1274
/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
1275
for (i = nold; i < lz; i++) if (signe(gel(z,i))) break;
1276
nold = nnew;
1277
if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
1278
1279
/* z + i represents (x*q - 1) / t^i */
1280
lz = ZX_lgrenormalizespec (z+i, lz-i);
1281
z = FpX_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */
1282
lz = lgpol(z); z += 2;
1283
if (lz > lnew-i) lz = ZX_lgrenormalizespec(z, lnew-i);
1284
1285
lx = lz+ i;
1286
y = x + i; /* x -= z * t^i, in place */
1287
for (i = 0; i < lz; i++) gel(y,i) = Fp_neg(gel(z,i), p);
1288
}
1289
x -= 2; setlg(x, lx + 2); x[1] = T[1];
1290
return gerepilecopy(av, x);
1291
}
1292
1293
/* 1/polrecip(T)+O(x^(deg(T)-1)) */
1294
GEN
1295
FpX_invBarrett(GEN T, GEN p)
1296
{
1297
pari_sp ltop = avma;
1298
long l = lg(T);
1299
GEN r;
1300
if (l<5) return pol_0(varn(T));
1301
if (l<=FpX_INVBARRETT_LIMIT)
1302
{
1303
GEN c = gel(T,l-1), ci=gen_1;
1304
if (!equali1(c))
1305
{
1306
ci = Fp_inv(c, p);
1307
T = FpX_Fp_mul(T, ci, p);
1308
r = FpX_invBarrett_basecase(T, p);
1309
r = FpX_Fp_mul(r, ci, p);
1310
} else
1311
r = FpX_invBarrett_basecase(T, p);
1312
}
1313
else
1314
r = FpX_invBarrett_Newton(T, p);
1315
return gerepileupto(ltop, r);
1316
}
1317
1318
GEN
1319
FpX_get_red(GEN T, GEN p)
1320
{
1321
if (typ(T)==t_POL && lg(T)>FpX_BARRETT_LIMIT)
1322
retmkvec2(FpX_invBarrett(T,p),T);
1323
return T;
1324
}
1325
1326
/* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1)
1327
* and mg is the Barrett inverse of T. */
1328
static GEN
1329
FpX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, GEN p, GEN *pr)
1330
{
1331
GEN q, r;
1332
long lt = degpol(T); /*We discard the leading term*/
1333
long ld, lm, lT, lmg;
1334
ld = l-lt;
1335
lm = minss(ld, lgpol(mg));
1336
lT = ZX_lgrenormalizespec(T+2,lt);
1337
lmg = ZX_lgrenormalizespec(mg+2,lm);
1338
q = FpX_recipspec(x+lt,ld,ld); /* q = rec(x) lq<=ld*/
1339
q = FpX_mulspec(q+2,mg+2,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/
1340
q = FpX_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lq<=ld*/
1341
if (!pr) return q;
1342
r = FpX_mulspec(q+2,T+2,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/
1343
r = FpX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */
1344
if (pr == ONLY_REM) return r;
1345
*pr = r; return q;
1346
}
1347
1348
static GEN
1349
FpX_divrem_Barrett(GEN x, GEN mg, GEN T, GEN p, GEN *pr)
1350
{
1351
GEN q = NULL, r = FpX_red(x, p);
1352
long l = lgpol(r), lt = degpol(T), lm = 2*lt-1, v = varn(T);
1353
long i;
1354
if (l <= lt)
1355
{
1356
if (pr == ONLY_REM) return r;
1357
if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
1358
if (pr) *pr = r;
1359
return pol_0(v);
1360
}
1361
if (lt <= 1)
1362
return FpX_divrem_basecase(r,T,p,pr);
1363
if (pr != ONLY_REM && l>lm)
1364
{
1365
q = cgetg(l-lt+2, t_POL); q[1] = T[1];
1366
for (i=0;i<l-lt;i++) gel(q+2,i) = gen_0;
1367
}
1368
while (l>lm)
1369
{
1370
GEN zr, zq = FpX_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr);
1371
long lz = lgpol(zr);
1372
if (pr != ONLY_REM)
1373
{
1374
long lq = lgpol(zq);
1375
for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
1376
}
1377
for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
1378
l = l-lm+lz;
1379
}
1380
if (pr == ONLY_REM)
1381
{
1382
if (l > lt)
1383
r = FpX_divrem_Barrettspec(r+2, l, mg, T, p, ONLY_REM);
1384
else
1385
r = FpX_renormalize(r, l+2);
1386
setvarn(r, v); return r;
1387
}
1388
if (l > lt)
1389
{
1390
GEN zq = FpX_divrem_Barrettspec(r+2,l,mg,T,p, pr? &r: NULL);
1391
if (!q) q = zq;
1392
else
1393
{
1394
long lq = lgpol(zq);
1395
for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
1396
}
1397
}
1398
else if (pr)
1399
r = FpX_renormalize(r, l+2);
1400
setvarn(q, v); q = FpX_renormalize(q, lg(q));
1401
if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
1402
if (pr) { setvarn(r, v); *pr = r; }
1403
return q;
1404
}
1405
1406
GEN
1407
FpX_divrem(GEN x, GEN T, GEN p, GEN *pr)
1408
{
1409
GEN B, y;
1410
long dy, dx, d;
1411
if (pr==ONLY_REM) return FpX_rem(x, T, p);
1412
y = get_FpX_red(T, &B);
1413
dy = degpol(y); dx = degpol(x); d = dx-dy;
1414
if (!B && d+3 < FpX_DIVREM_BARRETT_LIMIT)
1415
return FpX_divrem_basecase(x,y,p,pr);
1416
else if (lgefint(p)==3)
1417
{
1418
pari_sp av = avma;
1419
ulong pp = to_Flxq(&x, &T, p);
1420
GEN z = Flx_divrem(x, T, pp, pr);
1421
if (!z) return NULL;
1422
if (!pr || pr == ONLY_DIVIDES)
1423
return Flx_to_ZX_inplace(gerepileuptoleaf(av, z));
1424
z = Flx_to_ZX(z);
1425
*pr = Flx_to_ZX(*pr);
1426
gerepileall(av, 2, &z, pr);
1427
return z;
1428
} else
1429
{
1430
pari_sp av=avma;
1431
GEN mg = B? B: FpX_invBarrett(y, p);
1432
GEN q1 = FpX_divrem_Barrett(x,mg,y,p,pr);
1433
if (!q1) return gc_NULL(av);
1434
if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q1);
1435
gerepileall(av,2,&q1,pr);
1436
return q1;
1437
}
1438
}
1439
1440
GEN
1441
FpX_rem(GEN x, GEN T, GEN p)
1442
{
1443
GEN B, y = get_FpX_red(T, &B);
1444
long dy = degpol(y), dx = degpol(x), d = dx-dy;
1445
if (d < 0) return FpX_red(x,p);
1446
if (!B && d+3 < FpX_REM_BARRETT_LIMIT)
1447
return FpX_divrem_basecase(x,y,p,ONLY_REM);
1448
else if (lgefint(p)==3)
1449
{
1450
pari_sp av = avma;
1451
ulong pp = to_Flxq(&x, &T, p);
1452
return Flx_to_ZX_inplace(gerepileuptoleaf(av, Flx_rem(x, T, pp)));
1453
} else
1454
{
1455
pari_sp av = avma;
1456
GEN mg = B? B: FpX_invBarrett(y, p);
1457
return gerepileupto(av, FpX_divrem_Barrett(x, mg, y, p, ONLY_REM));
1458
}
1459
}
1460
1461
static GEN
1462
FpXV_producttree_dbl(GEN t, long n, GEN p)
1463
{
1464
long i, j, k, m = n==1 ? 1: expu(n-1)+1;
1465
GEN T = cgetg(m+1, t_VEC);
1466
gel(T,1) = t;
1467
for (i=2; i<=m; i++)
1468
{
1469
GEN u = gel(T, i-1);
1470
long n = lg(u)-1;
1471
GEN t = cgetg(((n+1)>>1)+1, t_VEC);
1472
for (j=1, k=1; k<n; j++, k+=2)
1473
gel(t, j) = FpX_mul(gel(u, k), gel(u, k+1), p);
1474
gel(T, i) = t;
1475
}
1476
return T;
1477
}
1478
1479
static GEN
1480
FpV_producttree(GEN xa, GEN s, GEN p, long vs)
1481
{
1482
long n = lg(xa)-1;
1483
long j, k, ls = lg(s);
1484
GEN t = cgetg(ls, t_VEC);
1485
for (j=1, k=1; j<ls; k+=s[j++])
1486
gel(t, j) = s[j] == 1 ?
1487
deg1pol_shallow(gen_1, Fp_neg(gel(xa,k), p), vs):
1488
deg2pol_shallow(gen_1,
1489
Fp_neg(Fp_add(gel(xa,k), gel(xa,k+1), p), p),
1490
Fp_mul(gel(xa,k), gel(xa,k+1), p), vs);
1491
return FpXV_producttree_dbl(t, n, p);
1492
}
1493
1494
static GEN
1495
FpX_FpXV_multirem_dbl_tree(GEN P, GEN T, GEN p)
1496
{
1497
long i,j,k;
1498
long m = lg(T)-1;
1499
GEN t;
1500
GEN Tp = cgetg(m+1, t_VEC);
1501
gel(Tp, m) = mkvec(P);
1502
for (i=m-1; i>=1; i--)
1503
{
1504
GEN u = gel(T, i);
1505
GEN v = gel(Tp, i+1);
1506
long n = lg(u)-1;
1507
t = cgetg(n+1, t_VEC);
1508
for (j=1, k=1; k<n; j++, k+=2)
1509
{
1510
gel(t, k) = FpX_rem(gel(v, j), gel(u, k), p);
1511
gel(t, k+1) = FpX_rem(gel(v, j), gel(u, k+1), p);
1512
}
1513
gel(Tp, i) = t;
1514
}
1515
return Tp;
1516
}
1517
1518
static GEN
1519
FpX_FpV_multieval_tree(GEN P, GEN xa, GEN T, GEN p)
1520
{
1521
pari_sp av = avma;
1522
long j,k;
1523
GEN Tp = FpX_FpXV_multirem_dbl_tree(P, T, p);
1524
GEN R = cgetg(lg(xa), t_VEC);
1525
GEN u = gel(T, 1);
1526
GEN v = gel(Tp, 1);
1527
long n = lg(u)-1;
1528
for (j=1, k=1; j<=n; j++)
1529
{
1530
long c, d = degpol(gel(u,j));
1531
for (c=1; c<=d; c++, k++)
1532
gel(R,k) = FpX_eval(gel(v, j), gel(xa,k), p);
1533
}
1534
return gerepileupto(av, R);
1535
}
1536
1537
static GEN
1538
FpVV_polint_tree(GEN T, GEN R, GEN s, GEN xa, GEN ya, GEN p, long vs)
1539
{
1540
pari_sp av = avma;
1541
long m = lg(T)-1;
1542
long i, j, k, ls = lg(s);
1543
GEN Tp = cgetg(m+1, t_VEC);
1544
GEN t = cgetg(ls, t_VEC);
1545
for (j=1, k=1; j<ls; k+=s[j++])
1546
if (s[j]==2)
1547
{
1548
GEN a = Fp_mul(gel(ya,k), gel(R,k), p);
1549
GEN b = Fp_mul(gel(ya,k+1), gel(R,k+1), p);
1550
gel(t, j) = deg1pol_shallow(Fp_add(a, b, p),
1551
Fp_neg(Fp_add(Fp_mul(gel(xa,k), b, p ),
1552
Fp_mul(gel(xa,k+1), a, p), p), p), vs);
1553
}
1554
else
1555
gel(t, j) = scalarpol(Fp_mul(gel(ya,k), gel(R,k), p), vs);
1556
gel(Tp, 1) = t;
1557
for (i=2; i<=m; i++)
1558
{
1559
GEN u = gel(T, i-1);
1560
GEN t = cgetg(lg(gel(T,i)), t_VEC);
1561
GEN v = gel(Tp, i-1);
1562
long n = lg(v)-1;
1563
for (j=1, k=1; k<n; j++, k+=2)
1564
gel(t, j) = FpX_add(ZX_mul(gel(u, k), gel(v, k+1)),
1565
ZX_mul(gel(u, k+1), gel(v, k)), p);
1566
gel(Tp, i) = t;
1567
}
1568
return gerepilecopy(av, gmael(Tp,m,1));
1569
}
1570
1571
GEN
1572
FpX_FpV_multieval(GEN P, GEN xa, GEN p)
1573
{
1574
pari_sp av = avma;
1575
GEN s = producttree_scheme(lg(xa)-1);
1576
GEN T = FpV_producttree(xa, s, p, varn(P));
1577
return gerepileupto(av, FpX_FpV_multieval_tree(P, xa, T, p));
1578
}
1579
1580
GEN
1581
FpV_polint(GEN xa, GEN ya, GEN p, long vs)
1582
{
1583
pari_sp av = avma;
1584
GEN s, T, P, R;
1585
long m;
1586
if (lgefint(p) == 3)
1587
{
1588
ulong pp = p[2];
1589
P = Flv_polint(ZV_to_Flv(xa, pp), ZV_to_Flv(ya, pp), pp, evalvarn(vs));
1590
return gerepileupto(av, Flx_to_ZX(P));
1591
}
1592
s = producttree_scheme(lg(xa)-1);
1593
T = FpV_producttree(xa, s, p, vs);
1594
m = lg(T)-1;
1595
P = FpX_deriv(gmael(T, m, 1), p);
1596
R = FpV_inv(FpX_FpV_multieval_tree(P, xa, T, p), p);
1597
return gerepileupto(av, FpVV_polint_tree(T, R, s, xa, ya, p, vs));
1598
}
1599
1600
GEN
1601
FpV_FpM_polint(GEN xa, GEN ya, GEN p, long vs)
1602
{
1603
pari_sp av = avma;
1604
GEN s = producttree_scheme(lg(xa)-1);
1605
GEN T = FpV_producttree(xa, s, p, vs);
1606
long i, m = lg(T)-1, l = lg(ya)-1;
1607
GEN P = FpX_deriv(gmael(T, m, 1), p);
1608
GEN R = FpV_inv(FpX_FpV_multieval_tree(P, xa, T, p), p);
1609
GEN M = cgetg(l+1, t_VEC);
1610
for (i=1; i<=l; i++)
1611
gel(M,i) = FpVV_polint_tree(T, R, s, xa, gel(ya,i), p, vs);
1612
return gerepileupto(av, M);
1613
}
1614
1615
GEN
1616
FpV_invVandermonde(GEN L, GEN den, GEN p)
1617
{
1618
pari_sp av = avma;
1619
long i, n = lg(L);
1620
GEN M, R;
1621
GEN s = producttree_scheme(n-1);
1622
GEN tree = FpV_producttree(L, s, p, 0);
1623
long m = lg(tree)-1;
1624
GEN T = gmael(tree, m, 1);
1625
R = FpV_inv(FpX_FpV_multieval_tree(FpX_deriv(T, p), L, tree, p), p);
1626
if (den) R = FpC_Fp_mul(R, den, p);
1627
M = cgetg(n, t_MAT);
1628
for (i = 1; i < n; i++)
1629
{
1630
GEN P = FpX_Fp_mul(FpX_div_by_X_x(T, gel(L,i), p, NULL), gel(R,i), p);
1631
gel(M,i) = RgX_to_RgC(P, n-1);
1632
}
1633
return gerepilecopy(av, M);
1634
}
1635
1636
static GEN
1637
FpXV_producttree(GEN xa, GEN s, GEN p)
1638
{
1639
long n = lg(xa)-1;
1640
long j, k, ls = lg(s);
1641
GEN t = cgetg(ls, t_VEC);
1642
for (j=1, k=1; j<ls; k+=s[j++])
1643
gel(t, j) = s[j] == 1 ?
1644
gel(xa,k): FpX_mul(gel(xa,k),gel(xa,k+1),p);
1645
return FpXV_producttree_dbl(t, n, p);
1646
}
1647
1648
static GEN
1649
FpX_FpXV_multirem_tree(GEN P, GEN xa, GEN T, GEN s, GEN p)
1650
{
1651
pari_sp av = avma;
1652
long j, k, ls = lg(s);
1653
GEN Tp = FpX_FpXV_multirem_dbl_tree(P, T, p);
1654
GEN R = cgetg(lg(xa), t_VEC);
1655
GEN v = gel(Tp, 1);
1656
for (j=1, k=1; j<ls; k+=s[j++])
1657
{
1658
gel(R,k) = FpX_rem(gel(v, j), gel(xa,k), p);
1659
if (s[j] == 2)
1660
gel(R,k+1) = FpX_rem(gel(v, j), gel(xa,k+1), p);
1661
}
1662
return gerepileupto(av, R);
1663
}
1664
1665
GEN
1666
FpX_FpXV_multirem(GEN P, GEN xa, GEN p)
1667
{
1668
pari_sp av = avma;
1669
GEN s = producttree_scheme(lg(xa)-1);
1670
GEN T = FpXV_producttree(xa, s, p);
1671
return gerepileupto(av, FpX_FpXV_multirem_tree(P, xa, T, s, p));
1672
}
1673
1674
/* T = ZV_producttree(P), R = ZV_chinesetree(P,T) */
1675
static GEN
1676
FpXV_chinese_tree(GEN A, GEN P, GEN T, GEN R, GEN s, GEN p)
1677
{
1678
long m = lg(T)-1, ls = lg(s);
1679
long i,j,k;
1680
GEN Tp = cgetg(m+1, t_VEC);
1681
GEN M = gel(T, 1);
1682
GEN t = cgetg(lg(M), t_VEC);
1683
for (j=1, k=1; j<ls; k+=s[j++])
1684
if (s[j] == 2)
1685
{
1686
pari_sp av = avma;
1687
GEN a = FpX_mul(gel(A,k), gel(R,k), p), b = FpX_mul(gel(A,k+1), gel(R,k+1), p);
1688
GEN tj = FpX_rem(FpX_add(FpX_mul(gel(P,k), b, p),
1689
FpX_mul(gel(P,k+1), a, p), p), gel(M,j), p);
1690
gel(t, j) = gerepileupto(av, tj);
1691
}
1692
else
1693
gel(t, j) = FpX_rem(FpX_mul(gel(A,k), gel(R,k), p), gel(M, j), p);
1694
gel(Tp, 1) = t;
1695
for (i=2; i<=m; i++)
1696
{
1697
GEN u = gel(T, i-1), M = gel(T, i);
1698
GEN t = cgetg(lg(M), t_VEC);
1699
GEN v = gel(Tp, i-1);
1700
long n = lg(v)-1;
1701
for (j=1, k=1; k<n; j++, k+=2)
1702
{
1703
pari_sp av = avma;
1704
gel(t, j) = gerepileupto(av, FpX_rem(FpX_add(FpX_mul(gel(u, k), gel(v, k+1), p),
1705
FpX_mul(gel(u, k+1), gel(v, k), p), p), gel(M, j), p));
1706
}
1707
if (k==n) gel(t, j) = gel(v, k);
1708
gel(Tp, i) = t;
1709
}
1710
return gmael(Tp,m,1);
1711
}
1712
1713
static GEN
1714
FpXV_sqr(GEN x, GEN p)
1715
{ pari_APPLY_type(t_VEC, FpX_sqr(gel(x,i), p)) }
1716
1717
static GEN
1718
FpXT_sqr(GEN x, GEN p)
1719
{
1720
if (typ(x) == t_POL)
1721
return FpX_sqr(x, p);
1722
pari_APPLY_type(t_VEC, FpXT_sqr(gel(x,i), p))
1723
}
1724
1725
static GEN
1726
FpXV_invdivexact(GEN x, GEN y, GEN p)
1727
{ pari_APPLY_type(t_VEC, FpXQ_inv(FpX_div(gel(x,i), gel(y,i),p), gel(y,i),p)) }
1728
1729
static GEN
1730
FpXV_chinesetree(GEN P, GEN T, GEN s, GEN p)
1731
{
1732
GEN T2 = FpXT_sqr(T, p), P2 = FpXV_sqr(P, p);
1733
GEN mod = gmael(T,lg(T)-1,1);
1734
return FpXV_invdivexact(FpX_FpXV_multirem_tree(mod, P2, T2, s, p), P, p);
1735
}
1736
1737
static GEN
1738
gc_chinese(pari_sp av, GEN T, GEN a, GEN *pt_mod)
1739
{
1740
if (!pt_mod)
1741
return gerepileupto(av, a);
1742
else
1743
{
1744
GEN mod = gmael(T, lg(T)-1, 1);
1745
gerepileall(av, 2, &a, &mod);
1746
*pt_mod = mod;
1747
return a;
1748
}
1749
}
1750
1751
GEN
1752
FpXV_chinese(GEN A, GEN P, GEN p, GEN *pt_mod)
1753
{
1754
pari_sp av = avma;
1755
GEN s = producttree_scheme(lg(P)-1);
1756
GEN T = FpXV_producttree(P, s, p);
1757
GEN R = FpXV_chinesetree(P, T, s, p);
1758
GEN a = FpXV_chinese_tree(A, P, T, R, s, p);
1759
return gc_chinese(av, T, a, pt_mod);
1760
}
1761
1762
/***********************************************************************/
1763
/** **/
1764
/** FpXQ **/
1765
/** **/
1766
/***********************************************************************/
1767
1768
/* FpXQ are elements of Fp[X]/(T), represented by FpX*/
1769
1770
GEN
1771
FpXQ_red(GEN x, GEN T, GEN p)
1772
{
1773
GEN z = FpX_red(x,p);
1774
return FpX_rem(z, T,p);
1775
}
1776
1777
GEN
1778
FpXQ_mul(GEN x,GEN y,GEN T,GEN p)
1779
{
1780
GEN z = FpX_mul(x,y,p);
1781
return FpX_rem(z, T, p);
1782
}
1783
1784
GEN
1785
FpXQ_sqr(GEN x, GEN T, GEN p)
1786
{
1787
GEN z = FpX_sqr(x,p);
1788
return FpX_rem(z, T, p);
1789
}
1790
1791
/* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist
1792
* return lift(1 / (x mod (p,pol))) */
1793
GEN
1794
FpXQ_invsafe(GEN x, GEN y, GEN p)
1795
{
1796
GEN V, z = FpX_extgcd(get_FpX_mod(y), x, p, NULL, &V);
1797
if (degpol(z)) return NULL;
1798
z = Fp_invsafe(gel(z,2), p);
1799
if (!z) return NULL;
1800
return FpX_Fp_mul(V, z, p);
1801
}
1802
1803
GEN
1804
FpXQ_inv(GEN x,GEN T,GEN p)
1805
{
1806
pari_sp av = avma;
1807
GEN U = FpXQ_invsafe(x, T, p);
1808
if (!U) pari_err_INV("FpXQ_inv",x);
1809
return gerepileupto(av, U);
1810
}
1811
1812
GEN
1813
FpXQ_div(GEN x,GEN y,GEN T,GEN p)
1814
{
1815
pari_sp av = avma;
1816
return gerepileupto(av, FpXQ_mul(x,FpXQ_inv(y,T,p),T,p));
1817
}
1818
1819
static GEN
1820
_FpXQ_add(void *data, GEN x, GEN y)
1821
{
1822
(void) data;
1823
return ZX_add(x, y);
1824
}
1825
static GEN
1826
_FpXQ_sub(void *data, GEN x, GEN y)
1827
{
1828
(void) data;
1829
return ZX_sub(x, y);
1830
}
1831
static GEN
1832
_FpXQ_cmul(void *data, GEN P, long a, GEN x)
1833
{
1834
(void) data;
1835
return ZX_Z_mul(x, gel(P,a+2));
1836
}
1837
static GEN
1838
_FpXQ_sqr(void *data, GEN x)
1839
{
1840
struct _FpXQ *D = (struct _FpXQ*)data;
1841
return FpXQ_sqr(x, D->T, D->p);
1842
}
1843
static GEN
1844
_FpXQ_mul(void *data, GEN x, GEN y)
1845
{
1846
struct _FpXQ *D = (struct _FpXQ*)data;
1847
return FpXQ_mul(x,y, D->T, D->p);
1848
}
1849
static GEN
1850
_FpXQ_zero(void *data)
1851
{
1852
struct _FpXQ *D = (struct _FpXQ*)data;
1853
return pol_0(get_FpX_var(D->T));
1854
}
1855
static GEN
1856
_FpXQ_one(void *data)
1857
{
1858
struct _FpXQ *D = (struct _FpXQ*)data;
1859
return pol_1(get_FpX_var(D->T));
1860
}
1861
static GEN
1862
_FpXQ_red(void *data, GEN x)
1863
{
1864
struct _FpXQ *D = (struct _FpXQ*)data;
1865
return FpX_red(x,D->p);
1866
}
1867
1868
static struct bb_algebra FpXQ_algebra = { _FpXQ_red, _FpXQ_add, _FpXQ_sub,
1869
_FpXQ_mul, _FpXQ_sqr, _FpXQ_one, _FpXQ_zero };
1870
1871
const struct bb_algebra *
1872
get_FpXQ_algebra(void **E, GEN T, GEN p)
1873
{
1874
GEN z = new_chunk(sizeof(struct _FpXQ));
1875
struct _FpXQ *e = (struct _FpXQ *) z;
1876
e->T = FpX_get_red(T, p);
1877
e->p = p; *E = (void*)e;
1878
return &FpXQ_algebra;
1879
}
1880
1881
static GEN
1882
_FpX_red(void *E, GEN x)
1883
{ struct _FpX *D = (struct _FpX*)E; return FpX_red(x,D->p); }
1884
1885
static GEN
1886
_FpX_zero(void *E)
1887
{ struct _FpX *D = (struct _FpX *)E; return pol_0(D->v); }
1888
1889
1890
static struct bb_algebra FpX_algebra = { _FpX_red, _FpXQ_add, _FpXQ_sub,
1891
_FpX_mul, _FpX_sqr, _FpX_one, _FpX_zero };
1892
1893
const struct bb_algebra *
1894
get_FpX_algebra(void **E, GEN p, long v)
1895
{
1896
GEN z = new_chunk(sizeof(struct _FpX));
1897
struct _FpX *e = (struct _FpX *) z;
1898
e->p = p; e->v = v; *E = (void*)e;
1899
return &FpX_algebra;
1900
}
1901
1902
/* x,pol in Z[X], p in Z, n in Z, compute lift(x^n mod (p, pol)) */
1903
GEN
1904
FpXQ_pow(GEN x, GEN n, GEN T, GEN p)
1905
{
1906
struct _FpXQ D;
1907
pari_sp av;
1908
long s = signe(n);
1909
GEN y;
1910
if (!s) return pol_1(varn(x));
1911
if (is_pm1(n)) /* +/- 1 */
1912
return (s < 0)? FpXQ_inv(x,T,p): FpXQ_red(x,T,p);
1913
av = avma;
1914
if (!is_bigint(p))
1915
{
1916
ulong pp = to_Flxq(&x, &T, p);
1917
y = Flxq_pow(x, n, T, pp);
1918
return Flx_to_ZX_inplace(gerepileuptoleaf(av, y));
1919
}
1920
if (s < 0) x = FpXQ_inv(x,T,p);
1921
D.p = p; D.T = FpX_get_red(T,p);
1922
y = gen_pow_i(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul);
1923
return gerepilecopy(av, y);
1924
}
1925
1926
GEN /*Assume n is very small*/
1927
FpXQ_powu(GEN x, ulong n, GEN T, GEN p)
1928
{
1929
struct _FpXQ D;
1930
pari_sp av;
1931
GEN y;
1932
if (!n) return pol_1(varn(x));
1933
if (n==1) return FpXQ_red(x,T,p);
1934
av = avma;
1935
if (!is_bigint(p))
1936
{
1937
ulong pp = to_Flxq(&x, &T, p);
1938
y = Flxq_powu(x, n, T, pp);
1939
return Flx_to_ZX_inplace(gerepileuptoleaf(av, y));
1940
}
1941
D.T = FpX_get_red(T, p); D.p = p;
1942
y = gen_powu_i(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul);
1943
return gerepilecopy(av, y);
1944
}
1945
1946
/* generates the list of powers of x of degree 0,1,2,...,l*/
1947
GEN
1948
FpXQ_powers(GEN x, long l, GEN T, GEN p)
1949
{
1950
struct _FpXQ D;
1951
int use_sqr;
1952
if (l>2 && lgefint(p) == 3) {
1953
pari_sp av = avma;
1954
ulong pp = to_Flxq(&x, &T, p);
1955
GEN z = FlxV_to_ZXV(Flxq_powers(x, l, T, pp));
1956
return gerepileupto(av, z);
1957
}
1958
use_sqr = 2*degpol(x)>=get_FpX_degree(T);
1959
D.T = FpX_get_red(T,p); D.p = p;
1960
return gen_powers(x, l, use_sqr, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul,&_FpXQ_one);
1961
}
1962
1963
GEN
1964
FpXQ_matrix_pow(GEN y, long n, long m, GEN P, GEN l)
1965
{
1966
return RgXV_to_RgM(FpXQ_powers(y,m-1,P,l),n);
1967
}
1968
1969
GEN
1970
FpX_Frobenius(GEN T, GEN p)
1971
{
1972
return FpXQ_pow(pol_x(get_FpX_var(T)), p, T, p);
1973
}
1974
1975
GEN
1976
FpX_matFrobenius(GEN T, GEN p)
1977
{
1978
long n = get_FpX_degree(T);
1979
return FpXQ_matrix_pow(FpX_Frobenius(T, p), n, n, T, p);
1980
}
1981
1982
GEN
1983
FpX_FpXQV_eval(GEN Q, GEN x, GEN T, GEN p)
1984
{
1985
struct _FpXQ D;
1986
D.T = FpX_get_red(T,p); D.p = p;
1987
return gen_bkeval_powers(Q,degpol(Q),x,(void*)&D,&FpXQ_algebra,_FpXQ_cmul);
1988
}
1989
1990
GEN
1991
FpX_FpXQ_eval(GEN Q, GEN x, GEN T, GEN p)
1992
{
1993
struct _FpXQ D;
1994
int use_sqr;
1995
if (lgefint(p) == 3)
1996
{
1997
pari_sp av = avma;
1998
ulong pp = to_Flxq(&x, &T, p);
1999
GEN z = Flx_Flxq_eval(ZX_to_Flx(Q, pp), x, T, pp);
2000
return Flx_to_ZX_inplace(gerepileuptoleaf(av, z));
2001
}
2002
use_sqr = 2*degpol(x) >= get_FpX_degree(T);
2003
D.T = FpX_get_red(T,p); D.p = p;
2004
return gen_bkeval(Q,degpol(Q),x,use_sqr,(void*)&D,&FpXQ_algebra,_FpXQ_cmul);
2005
}
2006
2007
GEN
2008
FpXC_FpXQV_eval(GEN x, GEN v, GEN T, GEN p)
2009
{ pari_APPLY_type(t_COL, FpX_FpXQV_eval(gel(x,i), v, T, p)) }
2010
2011
GEN
2012
FpXM_FpXQV_eval(GEN x, GEN v, GEN T, GEN p)
2013
{ pari_APPLY_same(FpXC_FpXQV_eval(gel(x,i), v, T, p)) }
2014
2015
GEN
2016
FpXC_FpXQ_eval(GEN x, GEN F, GEN T, GEN p)
2017
{
2018
long d = brent_kung_optpow(RgXV_maxdegree(x), lg(x)-1, 1);
2019
GEN Fp = FpXQ_powers(F, d, T, p);
2020
return FpXC_FpXQV_eval(x, Fp, T, p);
2021
}
2022
2023
GEN
2024
FpXQ_autpowers(GEN aut, long f, GEN T, GEN p)
2025
{
2026
pari_sp av = avma;
2027
long n = get_FpX_degree(T);
2028
long i, nautpow = brent_kung_optpow(n-1,f-2,1);
2029
long v = get_FpX_var(T);
2030
GEN autpow, V;
2031
T = FpX_get_red(T, p);
2032
autpow = FpXQ_powers(aut, nautpow,T,p);
2033
V = cgetg(f + 2, t_VEC);
2034
gel(V,1) = pol_x(v); if (f==0) return gerepileupto(av, V);
2035
gel(V,2) = gcopy(aut);
2036
for (i = 3; i <= f+1; i++)
2037
gel(V,i) = FpX_FpXQV_eval(gel(V,i-1),autpow,T,p);
2038
return gerepileupto(av, V);
2039
}
2040
2041
static GEN
2042
FpXQ_autpow_sqr(void *E, GEN x)
2043
{
2044
struct _FpXQ *D = (struct _FpXQ*)E;
2045
return FpX_FpXQ_eval(x, x, D->T, D->p);
2046
}
2047
2048
static GEN
2049
FpXQ_autpow_msqr(void *E, GEN x)
2050
{
2051
struct _FpXQ *D = (struct _FpXQ*)E;
2052
return FpX_FpXQV_eval(FpXQ_autpow_sqr(E, x), D->aut, D->T, D->p);
2053
}
2054
2055
GEN
2056
FpXQ_autpow(GEN x, ulong n, GEN T, GEN p)
2057
{
2058
pari_sp av = avma;
2059
struct _FpXQ D;
2060
long d;
2061
if (n==0) return FpX_rem(pol_x(varn(x)), T, p);
2062
if (n==1) return FpX_rem(x, T, p);
2063
D.T = FpX_get_red(T, p); D.p = p;
2064
d = brent_kung_optpow(degpol(T), hammingl(n)-1, 1);
2065
D.aut = FpXQ_powers(x, d, T, p);
2066
x = gen_powu_fold(x,n,(void*)&D,FpXQ_autpow_sqr,FpXQ_autpow_msqr);
2067
return gerepilecopy(av, x);
2068
}
2069
2070
static GEN
2071
FpXQ_auttrace_mul(void *E, GEN x, GEN y)
2072
{
2073
struct _FpXQ *D = (struct _FpXQ*)E;
2074
GEN T = D->T, p = D->p;
2075
GEN phi1 = gel(x,1), a1 = gel(x,2);
2076
GEN phi2 = gel(y,1), a2 = gel(y,2);
2077
ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1);
2078
GEN V1 = FpXQ_powers(phi1, d, T, p);
2079
GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);
2080
GEN aphi = FpX_FpXQV_eval(a2, V1, T, p);
2081
GEN a3 = FpX_add(a1, aphi, p);
2082
return mkvec2(phi3, a3);
2083
}
2084
2085
static GEN
2086
FpXQ_auttrace_sqr(void *E, GEN x)
2087
{ return FpXQ_auttrace_mul(E, x, x); }
2088
2089
GEN
2090
FpXQ_auttrace(GEN x, ulong n, GEN T, GEN p)
2091
{
2092
pari_sp av = avma;
2093
struct _FpXQ D;
2094
D.T = FpX_get_red(T, p); D.p = p;
2095
x = gen_powu_i(x,n,(void*)&D,FpXQ_auttrace_sqr,FpXQ_auttrace_mul);
2096
return gerepilecopy(av, x);
2097
}
2098
2099
static GEN
2100
FpXQ_autsum_mul(void *E, GEN x, GEN y)
2101
{
2102
struct _FpXQ *D = (struct _FpXQ*)E;
2103
GEN T = D->T, p = D->p;
2104
GEN phi1 = gel(x,1), a1 = gel(x,2);
2105
GEN phi2 = gel(y,1), a2 = gel(y,2);
2106
ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1);
2107
GEN V1 = FpXQ_powers(phi1, d, T, p);
2108
GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);
2109
GEN aphi = FpX_FpXQV_eval(a2, V1, T, p);
2110
GEN a3 = FpXQ_mul(a1, aphi, T, p);
2111
return mkvec2(phi3, a3);
2112
}
2113
static GEN
2114
FpXQ_autsum_sqr(void *E, GEN x)
2115
{ return FpXQ_autsum_mul(E, x, x); }
2116
2117
GEN
2118
FpXQ_autsum(GEN x, ulong n, GEN T, GEN p)
2119
{
2120
pari_sp av = avma;
2121
struct _FpXQ D;
2122
D.T = FpX_get_red(T, p); D.p = p;
2123
x = gen_powu_i(x,n,(void*)&D,FpXQ_autsum_sqr,FpXQ_autsum_mul);
2124
return gerepilecopy(av, x);
2125
}
2126
2127
static GEN
2128
FpXQM_autsum_mul(void *E, GEN x, GEN y)
2129
{
2130
struct _FpXQ *D = (struct _FpXQ*)E;
2131
GEN T = D->T, p = D->p;
2132
GEN phi1 = gel(x,1), a1 = gel(x,2);
2133
GEN phi2 = gel(y,1), a2 = gel(y,2);
2134
long g = lg(a2)-1, dT = get_FpX_degree(T);
2135
ulong d = brent_kung_optpow(dT-1, g*g+1, 1);
2136
GEN V1 = FpXQ_powers(phi1, d, T, p);
2137
GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);
2138
GEN aphi = FpXM_FpXQV_eval(a2, V1, T, p);
2139
GEN a3 = FqM_mul(a1, aphi, T, p);
2140
return mkvec2(phi3, a3);
2141
}
2142
static GEN
2143
FpXQM_autsum_sqr(void *E, GEN x)
2144
{ return FpXQM_autsum_mul(E, x, x); }
2145
2146
GEN
2147
FpXQM_autsum(GEN x, ulong n, GEN T, GEN p)
2148
{
2149
pari_sp av = avma;
2150
struct _FpXQ D;
2151
D.T = FpX_get_red(T, p); D.p = p;
2152
x = gen_powu_i(x, n, (void*)&D, FpXQM_autsum_sqr, FpXQM_autsum_mul);
2153
return gerepilecopy(av, x);
2154
}
2155
2156
static long
2157
bounded_order(GEN p, GEN b, long k)
2158
{
2159
long i;
2160
GEN a=modii(p,b);
2161
for(i=1;i<k;i++)
2162
{
2163
if (equali1(a))
2164
return i;
2165
a = Fp_mul(a,p,b);
2166
}
2167
return 0;
2168
}
2169
2170
/*
2171
n = (p^d-a)\b
2172
b = bb*p^vb
2173
p^k = 1 [bb]
2174
d = m*k+r+vb
2175
u = (p^k-1)/bb;
2176
v = (p^(r+vb)-a)/b;
2177
w = (p^(m*k)-1)/(p^k-1)
2178
n = p^r*w*u+v
2179
w*u = p^vb*(p^(m*k)-1)/b
2180
n = p^(r+vb)*(p^(m*k)-1)/b+(p^(r+vb)-a)/b
2181
*/
2182
2183
static GEN
2184
FpXQ_pow_Frobenius(GEN x, GEN n, GEN aut, GEN T, GEN p)
2185
{
2186
pari_sp av=avma;
2187
long d = get_FpX_degree(T);
2188
GEN an = absi_shallow(n), z, q;
2189
if (cmpii(an,p)<0 || cmpis(an,d)<=0) return FpXQ_pow(x, n, T, p);
2190
q = powiu(p, d);
2191
if (dvdii(q, n))
2192
{
2193
long vn = logint(an,p);
2194
GEN autvn = vn==1 ? aut: FpXQ_autpow(aut,vn,T,p);
2195
z = FpX_FpXQ_eval(x,autvn,T,p);
2196
} else
2197
{
2198
GEN b = diviiround(q, an), a = subii(q, mulii(an,b));
2199
GEN bb, u, v, autk;
2200
long vb = Z_pvalrem(b,p,&bb);
2201
long m, r, k = is_pm1(bb) ? 1 : bounded_order(p,bb,d);
2202
if (!k || d-vb<k) return FpXQ_pow(x,n, T, p);
2203
m = (d-vb)/k; r = (d-vb)%k;
2204
u = diviiexact(subiu(powiu(p,k),1),bb);
2205
v = diviiexact(subii(powiu(p,r+vb),a),b);
2206
autk = k==1 ? aut: FpXQ_autpow(aut,k,T,p);
2207
if (r)
2208
{
2209
GEN autr = r==1 ? aut: FpXQ_autpow(aut,r,T,p);
2210
z = FpX_FpXQ_eval(x,autr,T,p);
2211
} else z = x;
2212
if (m > 1) z = gel(FpXQ_autsum(mkvec2(autk, z), m, T, p), 2);
2213
if (!is_pm1(u)) z = FpXQ_pow(z, u, T, p);
2214
if (signe(v)) z = FpXQ_mul(z, FpXQ_pow(x, v, T, p), T, p);
2215
}
2216
return gerepileupto(av,signe(n)>0 ? z : FpXQ_inv(z,T,p));
2217
}
2218
2219
/* assume T irreducible mod p */
2220
int
2221
FpXQ_issquare(GEN x, GEN T, GEN p)
2222
{
2223
pari_sp av;
2224
if (lg(x) == 2 || absequalui(2, p)) return 1;
2225
if (lg(x) == 3) return Fq_issquare(gel(x,2), T, p);
2226
av = avma; /* Ng = g^((q-1)/(p-1)) */
2227
return gc_bool(av, kronecker(FpXQ_norm(x,T,p), p) == 1);
2228
}
2229
int
2230
Fp_issquare(GEN x, GEN p)
2231
{
2232
if (absequalui(2, p)) return 1;
2233
return kronecker(x, p) == 1;
2234
}
2235
/* assume T irreducible mod p */
2236
int
2237
Fq_issquare(GEN x, GEN T, GEN p)
2238
{
2239
if (typ(x) != t_INT) return FpXQ_issquare(x, T, p);
2240
return (T && ! odd(get_FpX_degree(T))) || Fp_issquare(x, p);
2241
}
2242
2243
long
2244
Fq_ispower(GEN x, GEN K, GEN T, GEN p)
2245
{
2246
pari_sp av = avma;
2247
long d;
2248
GEN Q;
2249
if (equaliu(K,2)) return Fq_issquare(x, T, p);
2250
if (!T) return Fp_ispower(x, K, p);
2251
d = get_FpX_degree(T);
2252
if (typ(x) == t_INT && !umodui(d, K)) return 1;
2253
Q = subiu(powiu(p,d), 1);
2254
Q = diviiexact(Q, gcdii(Q, K));
2255
d = gequal1(Fq_pow(x, Q, T,p));
2256
return gc_long(av, d);
2257
}
2258
2259
/* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */
2260
GEN
2261
Fp_FpXQ_log(GEN a, GEN g, GEN o, GEN T, GEN p)
2262
{
2263
pari_sp av = avma;
2264
GEN q,n_q,ord,ordp, op;
2265
2266
if (equali1(a)) return gen_0;
2267
/* p > 2 */
2268
2269
ordp = subiu(p, 1); /* even */
2270
ord = get_arith_Z(o);
2271
if (!ord) ord = T? subiu(powiu(p, get_FpX_degree(T)), 1): ordp;
2272
if (equalii(a, ordp)) /* -1 */
2273
return gerepileuptoint(av, shifti(ord,-1));
2274
ordp = gcdii(ordp,ord);
2275
op = typ(o)==t_MAT ? famat_Z_gcd(o,ordp) : ordp;
2276
2277
q = NULL;
2278
if (T)
2279
{ /* we want < g > = Fp^* */
2280
if (!equalii(ord,ordp)) {
2281
q = diviiexact(ord,ordp);
2282
g = FpXQ_pow(g,q,T,p);
2283
}
2284
g = constant_coeff(g);
2285
}
2286
n_q = Fp_log(a,g,op,p);
2287
if (lg(n_q)==1) return gerepileuptoleaf(av, n_q);
2288
if (q) n_q = mulii(q, n_q);
2289
return gerepileuptoint(av, n_q);
2290
}
2291
2292
static GEN
2293
_FpXQ_pow(void *data, GEN x, GEN n)
2294
{
2295
struct _FpXQ *D = (struct _FpXQ*)data;
2296
return FpXQ_pow_Frobenius(x,n, D->aut, D->T, D->p);
2297
}
2298
2299
static GEN
2300
_FpXQ_rand(void *data)
2301
{
2302
pari_sp av=avma;
2303
struct _FpXQ *D = (struct _FpXQ*)data;
2304
GEN z;
2305
do
2306
{
2307
set_avma(av);
2308
z=random_FpX(get_FpX_degree(D->T),get_FpX_var(D->T),D->p);
2309
} while (!signe(z));
2310
return z;
2311
}
2312
2313
static GEN
2314
_FpXQ_easylog(void *E, GEN a, GEN g, GEN ord)
2315
{
2316
struct _FpXQ *s=(struct _FpXQ*) E;
2317
if (degpol(a)) return NULL;
2318
return Fp_FpXQ_log(constant_coeff(a),g,ord,s->T,s->p);
2319
}
2320
2321
static const struct bb_group FpXQ_star={_FpXQ_mul,_FpXQ_pow,_FpXQ_rand,hash_GEN,ZX_equal,ZX_equal1,_FpXQ_easylog};
2322
2323
const struct bb_group *
2324
get_FpXQ_star(void **E, GEN T, GEN p)
2325
{
2326
struct _FpXQ *e = (struct _FpXQ *) stack_malloc(sizeof(struct _FpXQ));
2327
e->T = T; e->p = p; e->aut = FpX_Frobenius(T, p);
2328
*E = (void*)e; return &FpXQ_star;
2329
}
2330
2331
GEN
2332
FpXQ_order(GEN a, GEN ord, GEN T, GEN p)
2333
{
2334
if (lgefint(p)==3)
2335
{
2336
pari_sp av=avma;
2337
ulong pp = to_Flxq(&a, &T, p);
2338
GEN z = Flxq_order(a, ord, T, pp);
2339
return gerepileuptoint(av,z);
2340
}
2341
else
2342
{
2343
void *E;
2344
const struct bb_group *S = get_FpXQ_star(&E,T,p);
2345
return gen_order(a,ord,E,S);
2346
}
2347
}
2348
2349
GEN
2350
FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p)
2351
{
2352
pari_sp av=avma;
2353
if (lgefint(p)==3)
2354
{
2355
if (uel(p,2) == 2)
2356
{
2357
GEN z = F2xq_log(ZX_to_F2x(a), ZX_to_F2x(g), ord,
2358
ZX_to_F2x(get_FpX_mod(T)));
2359
return gerepileuptoleaf(av, z);
2360
}
2361
else
2362
{
2363
ulong pp = to_Flxq(&a, &T, p);
2364
GEN z = Flxq_log(a, ZX_to_Flx(g, pp), ord, T, pp);
2365
return gerepileuptoleaf(av, z);
2366
}
2367
}
2368
else
2369
{
2370
void *E;
2371
const struct bb_group *S = get_FpXQ_star(&E,T,p);
2372
GEN z = gen_PH_log(a,g,ord,E,S);
2373
return gerepileuptoleaf(av, z);
2374
}
2375
}
2376
2377
GEN
2378
Fq_log(GEN a, GEN g, GEN ord, GEN T, GEN p)
2379
{
2380
if (!T) return Fp_log(a,g,ord,p);
2381
if (typ(g) == t_INT)
2382
{
2383
if (typ(a) == t_POL)
2384
{
2385
if (degpol(a)) return cgetg(1,t_VEC);
2386
a = gel(a,2);
2387
}
2388
return Fp_log(a,g,ord,p);
2389
}
2390
return typ(a) == t_INT? Fp_FpXQ_log(a,g,ord,T,p): FpXQ_log(a,g,ord,T,p);
2391
}
2392
2393
GEN
2394
FpXQ_sqrtn(GEN a, GEN n, GEN T, GEN p, GEN *zeta)
2395
{
2396
pari_sp av = avma;
2397
GEN z;
2398
if (!signe(a))
2399
{
2400
long v=varn(a);
2401
if (signe(n) < 0) pari_err_INV("FpXQ_sqrtn",a);
2402
if (zeta) *zeta=pol_1(v);
2403
return pol_0(v);
2404
}
2405
if (lgefint(p)==3)
2406
{
2407
if (uel(p,2) == 2)
2408
{
2409
z = F2xq_sqrtn(ZX_to_F2x(a), n, ZX_to_F2x(get_FpX_mod(T)), zeta);
2410
if (!z) return NULL;
2411
z = F2x_to_ZX(z);
2412
if (!zeta) return gerepileuptoleaf(av, z);
2413
*zeta=F2x_to_ZX(*zeta);
2414
} else
2415
{
2416
ulong pp = to_Flxq(&a, &T, p);
2417
z = Flxq_sqrtn(a, n, T, pp, zeta);
2418
if (!z) return NULL;
2419
if (!zeta) return Flx_to_ZX_inplace(gerepileuptoleaf(av, z));
2420
z = Flx_to_ZX(z);
2421
*zeta=Flx_to_ZX(*zeta);
2422
}
2423
}
2424
else
2425
{
2426
void *E;
2427
const struct bb_group *S = get_FpXQ_star(&E,T,p);
2428
GEN o = subiu(powiu(p,get_FpX_degree(T)),1);
2429
z = gen_Shanks_sqrtn(a,n,o,zeta,E,S);
2430
if (!z) return NULL;
2431
if (!zeta) return gerepileupto(av, z);
2432
}
2433
gerepileall(av, 2, &z,zeta);
2434
return z;
2435
}
2436
2437
GEN
2438
FpXQ_sqrt(GEN a, GEN T, GEN p)
2439
{
2440
return FpXQ_sqrtn(a, gen_2, T, p, NULL);
2441
}
2442
2443
GEN
2444
FpXQ_norm(GEN x, GEN TB, GEN p)
2445
{
2446
pari_sp av = avma;
2447
GEN T = get_FpX_mod(TB);
2448
GEN y = FpX_resultant(T, x, p);
2449
GEN L = leading_coeff(T);
2450
if (gequal1(L) || signe(x)==0) return y;
2451
return gerepileupto(av, Fp_div(y, Fp_pows(L, degpol(x), p), p));
2452
}
2453
2454
GEN
2455
FpXQ_trace(GEN x, GEN TB, GEN p)
2456
{
2457
pari_sp av = avma;
2458
GEN T = get_FpX_mod(TB);
2459
GEN dT = FpX_deriv(T,p);
2460
long n = degpol(dT);
2461
GEN z = FpXQ_mul(x, dT, TB, p);
2462
if (degpol(z)<n) return gc_const(av, gen_0);
2463
return gerepileuptoint(av, Fp_div(gel(z,2+n), gel(T,3+n),p));
2464
}
2465
2466
GEN
2467
FpXQ_charpoly(GEN x, GEN T, GEN p)
2468
{
2469
pari_sp ltop=avma;
2470
long vT, v = fetch_var();
2471
GEN R;
2472
T = leafcopy(get_FpX_mod(T));
2473
vT = varn(T); setvarn(T, v);
2474
x = leafcopy(x); setvarn(x, v);
2475
R = FpX_FpXY_resultant(T, deg1pol_shallow(gen_1,FpX_neg(x,p),vT),p);
2476
(void)delete_var(); return gerepileupto(ltop,R);
2477
}
2478
2479
/* Computing minimal polynomial : */
2480
/* cf Shoup 'Efficient Computation of Minimal Polynomials */
2481
/* in Algebraic Extensions of Finite Fields' */
2482
2483
/* Let v a linear form, return the linear form z->v(tau*z)
2484
that is, v*(M_tau) */
2485
2486
static GEN
2487
FpXQ_transmul_init(GEN tau, GEN T, GEN p)
2488
{
2489
GEN bht;
2490
GEN h, Tp = get_FpX_red(T, &h);
2491
long n = degpol(Tp), vT = varn(Tp);
2492
GEN ft = FpX_recipspec(Tp+2, n+1, n+1);
2493
GEN bt = FpX_recipspec(tau+2, lgpol(tau), n);
2494
setvarn(ft, vT); setvarn(bt, vT);
2495
if (h)
2496
bht = FpXn_mul(bt, h, n-1, p);
2497
else
2498
{
2499
GEN bh = FpX_div(FpX_shift(tau, n-1), T, p);
2500
bht = FpX_recipspec(bh+2, lgpol(bh), n-1);
2501
setvarn(bht, vT);
2502
}
2503
return mkvec3(bt, bht, ft);
2504
}
2505
2506
static GEN
2507
FpXQ_transmul(GEN tau, GEN a, long n, GEN p)
2508
{
2509
pari_sp ltop = avma;
2510
GEN t1, t2, t3, vec;
2511
GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
2512
if (signe(a)==0) return pol_0(varn(a));
2513
t2 = FpX_shift(FpX_mul(bt, a, p),1-n);
2514
if (signe(bht)==0) return gerepilecopy(ltop, t2);
2515
t1 = FpX_shift(FpX_mul(ft, a, p),-n);
2516
t3 = FpXn_mul(t1, bht, n-1, p);
2517
vec = FpX_sub(t2, FpX_shift(t3, 1), p);
2518
return gerepileupto(ltop, vec);
2519
}
2520
2521
GEN
2522
FpXQ_minpoly(GEN x, GEN T, GEN p)
2523
{
2524
pari_sp ltop = avma;
2525
long vT, n;
2526
GEN v_x, g, tau;
2527
if (lgefint(p)==3)
2528
{
2529
ulong pp = to_Flxq(&x, &T, p);
2530
GEN g = Flxq_minpoly(x, T, pp);
2531
return gerepileupto(ltop, Flx_to_ZX(g));
2532
}
2533
vT = get_FpX_var(T);
2534
n = get_FpX_degree(T);
2535
g = pol_1(vT);
2536
tau = pol_1(vT);
2537
T = FpX_get_red(T, p);
2538
x = FpXQ_red(x, T, p);
2539
v_x = FpXQ_powers(x, usqrt(2*n), T, p);
2540
while(signe(tau) != 0)
2541
{
2542
long i, j, m, k1;
2543
GEN M, v, tr;
2544
GEN g_prime, c;
2545
if (degpol(g) == n) { tau = pol_1(vT); g = pol_1(vT); }
2546
v = random_FpX(n, vT, p);
2547
tr = FpXQ_transmul_init(tau, T, p);
2548
v = FpXQ_transmul(tr, v, n, p);
2549
m = 2*(n-degpol(g));
2550
k1 = usqrt(m);
2551
tr = FpXQ_transmul_init(gel(v_x,k1+1), T, p);
2552
c = cgetg(m+2,t_POL);
2553
c[1] = evalsigne(1)|evalvarn(vT);
2554
for (i=0; i<m; i+=k1)
2555
{
2556
long mj = minss(m-i, k1);
2557
for (j=0; j<mj; j++)
2558
gel(c,m+1-(i+j)) = FpX_dotproduct(v, gel(v_x,j+1), p);
2559
v = FpXQ_transmul(tr, v, n, p);
2560
}
2561
c = FpX_renormalize(c, m+2);
2562
/* now c contains <v,x^i> , i = 0..m-1 */
2563
M = FpX_halfgcd(pol_xn(m, vT), c, p);
2564
g_prime = gmael(M, 2, 2);
2565
if (degpol(g_prime) < 1) continue;
2566
g = FpX_mul(g, g_prime, p);
2567
tau = FpXQ_mul(tau, FpX_FpXQV_eval(g_prime, v_x, T, p), T, p);
2568
}
2569
g = FpX_normalize(g,p);
2570
return gerepilecopy(ltop,g);
2571
}
2572
2573
GEN
2574
FpXQ_conjvec(GEN x, GEN T, GEN p)
2575
{
2576
pari_sp av=avma;
2577
long i;
2578
long n = get_FpX_degree(T), v = varn(x);
2579
GEN M = FpX_matFrobenius(T, p);
2580
GEN z = cgetg(n+1,t_COL);
2581
gel(z,1) = RgX_to_RgC(x,n);
2582
for (i=2; i<=n; i++) gel(z,i) = FpM_FpC_mul(M,gel(z,i-1),p);
2583
gel(z,1) = x;
2584
for (i=2; i<=n; i++) gel(z,i) = RgV_to_RgX(gel(z,i),v);
2585
return gerepilecopy(av,z);
2586
}
2587
2588
/* p prime, p_1 = p-1, q = p^deg T, Lp = cofactors of some prime divisors
2589
* l_p of p-1, Lq = cofactors of some prime divisors l_q of q-1, return a
2590
* g in Fq such that
2591
* - Ng generates all l_p-Sylows of Fp^*
2592
* - g generates all l_q-Sylows of Fq^* */
2593
static GEN
2594
gener_FpXQ_i(GEN T, GEN p, GEN p_1, GEN Lp, GEN Lq)
2595
{
2596
pari_sp av;
2597
long vT = varn(T), f = degpol(T), l = lg(Lq);
2598
GEN F = FpX_Frobenius(T, p);
2599
int p_is_2 = is_pm1(p_1);
2600
for (av = avma;; set_avma(av))
2601
{
2602
GEN t, g = random_FpX(f, vT, p);
2603
long i;
2604
if (degpol(g) < 1) continue;
2605
if (p_is_2)
2606
t = g;
2607
else
2608
{
2609
t = FpX_resultant(T, g, p); /* Ng = g^((q-1)/(p-1)), assuming T monic */
2610
if (kronecker(t, p) == 1) continue;
2611
if (lg(Lp) > 1 && !is_gener_Fp(t, p, p_1, Lp)) continue;
2612
t = FpXQ_pow(g, shifti(p_1,-1), T, p);
2613
}
2614
for (i = 1; i < l; i++)
2615
{
2616
GEN a = FpXQ_pow_Frobenius(t, gel(Lq,i), F, T, p);
2617
if (!degpol(a) && equalii(gel(a,2), p_1)) break;
2618
}
2619
if (i == l) return g;
2620
}
2621
}
2622
2623
GEN
2624
gener_FpXQ(GEN T, GEN p, GEN *po)
2625
{
2626
long i, j, f = get_FpX_degree(T);
2627
GEN g, Lp, Lq, p_1, q_1, N, o;
2628
pari_sp av = avma;
2629
2630
p_1 = subiu(p,1);
2631
if (f == 1) {
2632
GEN Lp, fa;
2633
o = p_1;
2634
fa = Z_factor(o);
2635
Lp = gel(fa,1);
2636
Lp = vecslice(Lp, 2, lg(Lp)-1); /* remove 2 for efficiency */
2637
2638
g = cgetg(3, t_POL);
2639
g[1] = evalsigne(1) | evalvarn(get_FpX_var(T));
2640
gel(g,2) = pgener_Fp_local(p, Lp);
2641
if (po) *po = mkvec2(o, fa);
2642
return g;
2643
}
2644
if (lgefint(p) == 3)
2645
{
2646
ulong pp = to_Flxq(NULL, &T, p);
2647
g = gener_Flxq(T, pp, po);
2648
if (!po) return Flx_to_ZX_inplace(gerepileuptoleaf(av, g));
2649
g = Flx_to_ZX(g);
2650
gerepileall(av, 2, &g, po);
2651
return g;
2652
}
2653
/* p now odd */
2654
q_1 = subiu(powiu(p,f), 1);
2655
N = diviiexact(q_1, p_1);
2656
Lp = odd_prime_divisors(p_1);
2657
for (i=lg(Lp)-1; i; i--) gel(Lp,i) = diviiexact(p_1, gel(Lp,i));
2658
o = factor_pn_1(p,f);
2659
Lq = leafcopy( gel(o, 1) );
2660
for (i = j = 1; i < lg(Lq); i++)
2661
{
2662
if (dvdii(p_1, gel(Lq,i))) continue;
2663
gel(Lq,j++) = diviiexact(N, gel(Lq,i));
2664
}
2665
setlg(Lq, j);
2666
g = gener_FpXQ_i(get_FpX_mod(T), p, p_1, Lp, Lq);
2667
if (!po) g = gerepilecopy(av, g);
2668
else {
2669
*po = mkvec2(q_1, o);
2670
gerepileall(av, 2, &g, po);
2671
}
2672
return g;
2673
}
2674
2675
GEN
2676
gener_FpXQ_local(GEN T, GEN p, GEN L)
2677
{
2678
GEN Lp, Lq, p_1 = subiu(p,1), q_1, N, Q;
2679
long f, i, ip, iq, l = lg(L);
2680
T = get_FpX_mod(T);
2681
f = degpol(T);
2682
q_1 = subiu(powiu(p,f), 1);
2683
N = diviiexact(q_1, p_1);
2684
2685
Q = is_pm1(p_1)? gen_1: shifti(p_1,-1);
2686
Lp = cgetg(l, t_VEC); ip = 1;
2687
Lq = cgetg(l, t_VEC); iq = 1;
2688
for (i=1; i < l; i++)
2689
{
2690
GEN a, b, ell = gel(L,i);
2691
if (absequaliu(ell,2)) continue;
2692
a = dvmdii(Q, ell, &b);
2693
if (b == gen_0)
2694
gel(Lp,ip++) = a;
2695
else
2696
gel(Lq,iq++) = diviiexact(N,ell);
2697
}
2698
setlg(Lp, ip);
2699
setlg(Lq, iq);
2700
return gener_FpXQ_i(T, p, p_1, Lp, Lq);
2701
}
2702
2703
/***********************************************************************/
2704
/** **/
2705
/** FpXn **/
2706
/** **/
2707
/***********************************************************************/
2708
2709
INLINE GEN
2710
FpXn_red(GEN a, long n)
2711
{ return RgXn_red_shallow(a, n); }
2712
2713
GEN
2714
FpXn_mul(GEN a, GEN b, long n, GEN p)
2715
{
2716
return FpX_red(ZXn_mul(a, b, n), p);
2717
}
2718
2719
GEN
2720
FpXn_sqr(GEN a, long n, GEN p)
2721
{
2722
return FpX_red(ZXn_sqr(a, n), p);
2723
}
2724
2725
/* (f*g) \/ x^n */
2726
static GEN
2727
FpX_mulhigh_i(GEN f, GEN g, long n, GEN p)
2728
{
2729
return FpX_shift(FpX_mul(f,g, p),-n);
2730
}
2731
2732
static GEN
2733
FpXn_mulhigh(GEN f, GEN g, long n2, long n, GEN p)
2734
{
2735
GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2);
2736
return FpX_add(FpX_mulhigh_i(fl, g, n2, p), FpXn_mul(fh, g, n - n2, p), p);
2737
}
2738
2739
GEN
2740
FpXn_inv(GEN f, long e, GEN p)
2741
{
2742
pari_sp av = avma, av2;
2743
ulong mask;
2744
GEN W, a;
2745
long v = varn(f), n = 1;
2746
2747
if (!signe(f)) pari_err_INV("FpXn_inv",f);
2748
a = Fp_inv(gel(f,2), p);
2749
if (e == 1) return scalarpol(a, v);
2750
else if (e == 2)
2751
{
2752
GEN b;
2753
if (degpol(f) <= 0) return scalarpol(a, v);
2754
b = Fp_neg(gel(f,3),p);
2755
if (signe(b)==0) return scalarpol(a, v);
2756
if (!is_pm1(a)) b = Fp_mul(b, Fp_sqr(a, p), p);
2757
W = deg1pol_shallow(b, a, v);
2758
return gerepilecopy(av, W);
2759
}
2760
W = scalarpol_shallow(Fp_inv(gel(f,2), p),v);
2761
mask = quadratic_prec_mask(e);
2762
av2 = avma;
2763
for (;mask>1;)
2764
{
2765
GEN u, fr;
2766
long n2 = n;
2767
n<<=1; if (mask & 1) n--;
2768
mask >>= 1;
2769
fr = FpXn_red(f, n);
2770
u = FpXn_mul(W, FpXn_mulhigh(fr, W, n2, n, p), n-n2, p);
2771
W = FpX_sub(W, FpX_shift(u, n2), p);
2772
if (gc_needed(av2,2))
2773
{
2774
if(DEBUGMEM>1) pari_warn(warnmem,"FpXn_inv, e = %ld", n);
2775
W = gerepileupto(av2, W);
2776
}
2777
}
2778
return gerepileupto(av, W);
2779
}
2780
2781
GEN
2782
FpXn_expint(GEN h, long e, GEN p)
2783
{
2784
pari_sp av = avma, av2;
2785
long v = varn(h), n=1;
2786
GEN f = pol_1(v), g = pol_1(v);
2787
ulong mask = quadratic_prec_mask(e);
2788
av2 = avma;
2789
for (;mask>1;)
2790
{
2791
GEN u, w;
2792
long n2 = n;
2793
n<<=1; if (mask & 1) n--;
2794
mask >>= 1;
2795
u = FpXn_mul(g, FpX_mulhigh_i(f, FpXn_red(h, n2-1), n2-1, p), n-n2, p);
2796
u = FpX_add(u, FpX_shift(FpXn_red(h, n-1), 1-n2), p);
2797
w = FpXn_mul(f, FpX_integXn(u, n2-1, p), n-n2, p);
2798
f = FpX_add(f, FpX_shift(w, n2), p);
2799
if (mask<=1) break;
2800
u = FpXn_mul(g, FpXn_mulhigh(f, g, n2, n, p), n-n2, p);
2801
g = FpX_sub(g, FpX_shift(u, n2), p);
2802
if (gc_needed(av2,2))
2803
{
2804
if (DEBUGMEM>1) pari_warn(warnmem,"FpXn_exp, e = %ld", n);
2805
gerepileall(av2, 2, &f, &g);
2806
}
2807
}
2808
return gerepileupto(av, f);
2809
}
2810
2811
GEN
2812
FpXn_exp(GEN h, long e, GEN p)
2813
{
2814
if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2)))
2815
pari_err_DOMAIN("FpXn_exp","valuation", "<", gen_1, h);
2816
return FpXn_expint(FpX_deriv(h, p), e, p);
2817
}
2818
2819