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) 2019 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
/***********************************************************************/
19
/** **/
20
/** FlxX **/
21
/** **/
22
/***********************************************************************/
23
24
/* FlxX are t_POL with Flx coefficients.
25
* Normally the variable ordering should be respected.*/
26
27
/*Similar to normalizepol, in place*/
28
/*FlxX_renormalize=zxX_renormalize */
29
GEN
30
FlxX_renormalize(GEN /*in place*/ x, long lx)
31
{
32
long i;
33
for (i = lx-1; i>1; i--)
34
if (lgpol(gel(x,i))) break;
35
stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1));
36
setlg(x, i+1); setsigne(x, i!=1); return x;
37
}
38
39
GEN
40
pol1_FlxX(long v, long sv)
41
{
42
GEN z = cgetg(3, t_POL);
43
z[1] = evalsigne(1) | evalvarn(v);
44
gel(z,2) = pol1_Flx(sv); return z;
45
}
46
47
GEN
48
polx_FlxX(long v, long sv)
49
{
50
GEN z = cgetg(4, t_POL);
51
z[1] = evalsigne(1) | evalvarn(v);
52
gel(z,2) = pol0_Flx(sv);
53
gel(z,3) = pol1_Flx(sv); return z;
54
}
55
56
long
57
FlxY_degreex(GEN b)
58
{
59
long deg = 0, i;
60
if (!signe(b)) return -1;
61
for (i = 2; i < lg(b); ++i)
62
deg = maxss(deg, degpol(gel(b, i)));
63
return deg;
64
}
65
66
/*Lift coefficient of B to constant Flx, to give a FlxY*/
67
GEN
68
Fly_to_FlxY(GEN B, long sv)
69
{
70
long lb=lg(B);
71
long i;
72
GEN b=cgetg(lb,t_POL);
73
b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
74
for (i=2; i<lb; i++)
75
gel(b,i) = Fl_to_Flx(B[i], sv);
76
return FlxX_renormalize(b, lb);
77
}
78
79
GEN
80
zxX_to_FlxX(GEN B, ulong p)
81
{
82
long i, lb = lg(B);
83
GEN b = cgetg(lb,t_POL);
84
for (i=2; i<lb; i++)
85
gel(b,i) = zx_to_Flx(gel(B,i), p);
86
b[1] = B[1]; return FlxX_renormalize(b, lb);
87
}
88
89
GEN
90
FlxX_to_ZXX(GEN B)
91
{
92
long i, lb = lg(B);
93
GEN b = cgetg(lb,t_POL);
94
for (i=2; i<lb; i++)
95
{
96
GEN c = gel(B,i);
97
switch(lgpol(c))
98
{
99
case 0: c = gen_0; break;
100
case 1: c = utoi(c[2]); break;
101
default: c = Flx_to_ZX(c); break;
102
}
103
gel(b,i) = c;
104
}
105
b[1] = B[1]; return b;
106
}
107
108
GEN
109
FlxXC_to_ZXXC(GEN x)
110
{ pari_APPLY_type(t_COL, FlxX_to_ZXX(gel(x,i))) }
111
112
GEN
113
FlxXM_to_ZXXM(GEN x)
114
{ pari_APPLY_same(FlxXC_to_ZXXC(gel(x,i))) }
115
116
/* Note: v is used _only_ for the t_INT. It must match
117
* the variable of any t_POL coefficients. */
118
GEN
119
ZXX_to_FlxX(GEN B, ulong p, long v)
120
{
121
long lb=lg(B);
122
long i;
123
GEN b=cgetg(lb,t_POL);
124
b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
125
for (i=2; i<lb; i++)
126
switch (typ(gel(B,i)))
127
{
128
case t_INT:
129
gel(b,i) = Z_to_Flx(gel(B,i), p, evalvarn(v));
130
break;
131
case t_POL:
132
gel(b,i) = ZX_to_Flx(gel(B,i), p);
133
break;
134
}
135
return FlxX_renormalize(b, lb);
136
}
137
138
GEN
139
ZXXV_to_FlxXV(GEN x, ulong p, long v)
140
{ pari_APPLY_type(t_VEC, ZXX_to_FlxX(gel(x,i), p, v)) }
141
142
GEN
143
ZXXT_to_FlxXT(GEN x, ulong p, long v)
144
{
145
if (typ(x) == t_POL)
146
return ZXX_to_FlxX(x, p, v);
147
else
148
pari_APPLY_type(t_VEC, ZXXT_to_FlxXT(gel(x,i), p, v))
149
}
150
151
GEN
152
FlxX_to_FlxC(GEN x, long N, long sv)
153
{
154
long i, l;
155
GEN z;
156
l = lg(x)-1; x++;
157
if (l > N+1) l = N+1; /* truncate higher degree terms */
158
z = cgetg(N+1,t_COL);
159
for (i=1; i<l ; i++) gel(z,i) = gel(x,i);
160
for ( ; i<=N; i++) gel(z,i) = pol0_Flx(sv);
161
return z;
162
}
163
164
static GEN
165
FlxXV_to_FlxM_lg(GEN x, long m, long n, long sv)
166
{
167
long i;
168
GEN y = cgetg(n+1, t_MAT);
169
for (i=1; i<=n; i++) gel(y,i) = FlxX_to_FlxC(gel(x,i), m, sv);
170
return y;
171
}
172
173
GEN
174
FlxXV_to_FlxM(GEN v, long n, long sv)
175
{ return FlxXV_to_FlxM_lg(v, n, lg(v)-1, sv); }
176
177
/* matrix whose entries are given by the coeffs of the polynomial v in
178
* two variables (considered as degree n polynomials) */
179
GEN
180
FlxX_to_Flm(GEN v, long n)
181
{
182
long j, N = lg(v)-1;
183
GEN y = cgetg(N, t_MAT);
184
v++;
185
for (j=1; j<N; j++) gel(y,j) = Flx_to_Flv(gel(v,j), n);
186
return y;
187
}
188
189
GEN
190
FlxX_to_Flx(GEN f)
191
{
192
long i, l = lg(f);
193
GEN V = cgetg(l, t_VECSMALL);
194
V[1] = ((ulong)f[1])&VARNBITS;
195
for(i=2; i<l; i++)
196
V[i] = lgpol(gel(f,i)) ? mael(f,i,2): 0L;
197
return V;
198
}
199
200
GEN
201
Flm_to_FlxX(GEN x, long v,long w)
202
{
203
long j, lx = lg(x);
204
GEN y = cgetg(lx+1, t_POL);
205
y[1]=evalsigne(1) | v;
206
y++;
207
for (j=1; j<lx; j++) gel(y,j) = Flv_to_Flx(gel(x,j), w);
208
return FlxX_renormalize(--y, lx+1);
209
}
210
211
/* P(X,Y) --> P(Y,X), n is the degree in Y */
212
GEN
213
FlxX_swap(GEN x, long n, long ws)
214
{
215
long j, lx = lg(x), ly = n+3;
216
GEN y = cgetg(ly, t_POL);
217
y[1] = x[1];
218
for (j=2; j<ly; j++)
219
{
220
long k;
221
GEN p1 = cgetg(lx, t_VECSMALL);
222
p1[1] = ws;
223
for (k=2; k<lx; k++)
224
if (j<lg(gel(x,k)))
225
p1[k] = mael(x,k,j);
226
else
227
p1[k] = 0;
228
gel(y,j) = Flx_renormalize(p1,lx);
229
}
230
return FlxX_renormalize(y,ly);
231
}
232
233
static GEN
234
zxX_to_Kronecker_spec(GEN P, long lp, long n)
235
{ /* P(X) = sum Pi(Y) * X^i, return P( Y^(2n-1) ) */
236
long i, j, k, l, N = (n<<1) + 1;
237
GEN y = cgetg((N-2)*lp + 2, t_VECSMALL) + 2;
238
for (k=i=0; i<lp; i++)
239
{
240
GEN c = gel(P,i);
241
l = lg(c);
242
if (l-3 >= n)
243
pari_err_BUG("zxX_to_Kronecker, P is not reduced mod Q");
244
for (j=2; j < l; j++) y[k++] = c[j];
245
if (i == lp-1) break;
246
for ( ; j < N; j++) y[k++] = 0;
247
}
248
y -= 2;
249
y[1] = 0; setlg(y, k+2); return y;
250
}
251
252
GEN
253
zxX_to_Kronecker(GEN P, GEN Q)
254
{
255
GEN z = zxX_to_Kronecker_spec(P+2, lg(P)-2, degpol(Q));
256
z[1] = P[1]; return z;
257
}
258
259
GEN
260
FlxX_add(GEN x, GEN y, ulong p)
261
{
262
long i,lz;
263
GEN z;
264
long lx=lg(x);
265
long ly=lg(y);
266
if (ly>lx) swapspec(x,y, lx,ly);
267
lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
268
for (i=2; i<ly; i++) gel(z,i) = Flx_add(gel(x,i), gel(y,i), p);
269
for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
270
return FlxX_renormalize(z, lz);
271
}
272
273
GEN
274
FlxX_Flx_add(GEN y, GEN x, ulong p)
275
{
276
long i, lz = lg(y);
277
GEN z;
278
if (signe(y) == 0) return scalarpol(x, varn(y));
279
z = cgetg(lz,t_POL); z[1] = y[1];
280
gel(z,2) = Flx_add(gel(y,2), x, p);
281
if (lz == 3) z = FlxX_renormalize(z,lz);
282
else
283
for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));
284
return z;
285
}
286
287
GEN
288
FlxX_Flx_sub(GEN y, GEN x, ulong p)
289
{
290
long i, lz = lg(y);
291
GEN z;
292
if (signe(y) == 0) return scalarpol(x, varn(y));
293
z = cgetg(lz,t_POL); z[1] = y[1];
294
gel(z,2) = Flx_sub(gel(y,2), x, p);
295
if (lz == 3) z = FlxX_renormalize(z,lz);
296
else
297
for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));
298
return z;
299
}
300
301
GEN
302
FlxX_neg(GEN x, ulong p)
303
{
304
long i, lx=lg(x);
305
GEN z = cgetg(lx, t_POL);
306
z[1]=x[1];
307
for (i=2; i<lx; i++) gel(z,i) = Flx_neg(gel(x,i), p);
308
return z;
309
}
310
311
GEN
312
FlxX_Fl_mul(GEN x, ulong y, ulong p)
313
{
314
long i, lx=lg(x);
315
GEN z = cgetg(lx, t_POL);
316
z[1]=x[1];
317
for (i=2; i<lx; i++) gel(z,i) = Flx_Fl_mul(gel(x,i), y, p);
318
return FlxX_renormalize(z, lx);
319
}
320
321
GEN
322
FlxX_triple(GEN x, ulong p)
323
{
324
long i, lx=lg(x);
325
GEN z = cgetg(lx, t_POL);
326
z[1]=x[1];
327
for (i=2; i<lx; i++) gel(z,i) = Flx_triple(gel(x,i), p);
328
return FlxX_renormalize(z, lx);
329
}
330
331
GEN
332
FlxX_double(GEN x, ulong p)
333
{
334
long i, lx=lg(x);
335
GEN z = cgetg(lx, t_POL);
336
z[1]=x[1];
337
for (i=2; i<lx; i++) gel(z,i) = Flx_double(gel(x,i), p);
338
return FlxX_renormalize(z, lx);
339
}
340
341
GEN
342
FlxX_deriv(GEN z, ulong p)
343
{
344
long i,l = lg(z)-1;
345
GEN x;
346
if (l < 2) l = 2;
347
x = cgetg(l, t_POL); x[1] = z[1];
348
for (i=2; i<l; i++) gel(x,i) = Flx_mulu(gel(z,i+1), (ulong) i-1, p);
349
return FlxX_renormalize(x,l);
350
}
351
352
GEN
353
FlxX_translate1(GEN P, long p, long n)
354
{
355
GEN Q;
356
long i, l, ws, lP = lgpol(P);
357
if (!lP) return gcopy(P);
358
ws = mael(P,2,1);
359
Q = FlxX_swap(P, n, ws);
360
l = lg(Q);
361
for (i=2; i<l; i++) gel(Q, i) = Flx_translate1(gel(Q, i), p);
362
return FlxX_swap(Q, lP, ws);
363
}
364
365
GEN
366
zlxX_translate1(GEN P, long p, long e, long n)
367
{
368
GEN Q;
369
long i, l, ws, lP = lgpol(P);
370
if (!lP) return gcopy(P);
371
ws = mael(P,2,1);
372
Q = FlxX_swap(P, n, ws);
373
l = lg(Q);
374
for (i=2; i<l; i++) gel(Q, i) = zlx_translate1(gel(Q, i), p, e);
375
return FlxX_swap(Q, lP, ws);
376
}
377
378
static GEN
379
FlxX_subspec(GEN x, GEN y, ulong p, long lx, long ly)
380
{
381
long i,lz;
382
GEN z;
383
384
if (ly <= lx)
385
{
386
lz = lx+2; z = cgetg(lz, t_POL);
387
for (i=0; i<ly; i++) gel(z,i+2) = Flx_sub(gel(x,i),gel(y,i),p);
388
for ( ; i<lx; i++) gel(z,i+2) = Flx_copy(gel(x,i));
389
}
390
else
391
{
392
lz = ly+2; z = cgetg(lz, t_POL);
393
for (i=0; i<lx; i++) gel(z,i+2) = Flx_sub(gel(x,i),gel(y,i),p);
394
for ( ; i<ly; i++) gel(z,i+2) = Flx_neg(gel(y,i),p);
395
}
396
z[1] = 0; return FlxX_renormalize(z, lz);
397
}
398
399
GEN
400
FlxX_sub(GEN x, GEN y, ulong p)
401
{
402
long lx,ly,i,lz;
403
GEN z;
404
lx = lg(x); ly = lg(y);
405
lz=maxss(lx,ly);
406
z = cgetg(lz,t_POL);
407
if (lx >= ly)
408
{
409
z[1] = x[1];
410
for (i=2; i<ly; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
411
for ( ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
412
if (lx==ly) z = FlxX_renormalize(z, lz);
413
}
414
else
415
{
416
z[1] = y[1];
417
for (i=2; i<lx; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
418
for ( ; i<ly; i++) gel(z,i) = Flx_neg(gel(y,i),p);
419
}
420
if (!lgpol(z)) { set_avma((pari_sp)(z + lz)); z = pol_0(varn(x)); }
421
return z;
422
}
423
424
GEN
425
FlxX_Flx_mul(GEN P, GEN U, ulong p)
426
{
427
long i, lP = lg(P);
428
GEN res = cgetg(lP,t_POL);
429
res[1] = P[1];
430
for(i=2; i<lP; i++)
431
gel(res,i) = Flx_mul(U,gel(P,i), p);
432
return FlxX_renormalize(res, lP);
433
}
434
435
GEN
436
FlxY_evalx(GEN Q, ulong x, ulong p)
437
{
438
GEN z;
439
long i, lb = lg(Q);
440
z = cgetg(lb,t_VECSMALL); z[1] = evalvarn(varn(Q));
441
for (i=2; i<lb; i++) z[i] = Flx_eval(gel(Q,i), x, p);
442
return Flx_renormalize(z, lb);
443
}
444
445
GEN
446
FlxY_Flx_translate(GEN P, GEN c, ulong p)
447
{
448
pari_sp av = avma;
449
GEN Q;
450
long i, k, n;
451
452
if (!signe(P) || gequal0(c)) return RgX_copy(P);
453
Q = leafcopy(P); n = degpol(P);
454
for (i=1; i<=n; i++)
455
{
456
for (k=n-i; k<n; k++)
457
gel(Q,2+k) = Flx_add(gel(Q,2+k), Flx_mul(gel(Q,2+k+1), c, p), p);
458
if (gc_needed(av,2))
459
{
460
if(DEBUGMEM>1)
461
pari_warn(warnmem,"FlxY_Flx_translate, i = %ld/%ld", i,n);
462
Q = gerepilecopy(av, Q);
463
}
464
}
465
return gerepilecopy(av, Q);
466
}
467
468
GEN
469
FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi)
470
{
471
long i, len = lg(pol);
472
GEN res = cgetg(len, t_VECSMALL);
473
res[1] = pol[1] & VARNBITS;
474
for (i = 2; i < len; ++i)
475
res[i] = Flx_eval_powers_pre(gel(pol, i), ypowers, p, pi);
476
return Flx_renormalize(res, len);
477
}
478
479
ulong
480
FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi)
481
{
482
pari_sp av = avma;
483
GEN t = FlxY_evalx_powers_pre(pol, ypowers, p, pi);
484
return gc_ulong(av, Flx_eval_powers_pre(t, xpowers, p, pi));
485
}
486
487
GEN
488
FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p)
489
{
490
long i, lP = lg(P);
491
GEN res = cgetg(lP,t_POL);
492
res[1] = P[1];
493
for(i=2; i<lP; i++)
494
gel(res,i) = Flx_FlxqV_eval(gel(P,i), x, T, p);
495
return FlxX_renormalize(res, lP);
496
}
497
498
GEN
499
FlxY_Flxq_evalx(GEN P, GEN x, GEN T, ulong p)
500
{
501
pari_sp av = avma;
502
long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(P),1);
503
GEN xp = Flxq_powers(x, n, T, p);
504
return gerepileupto(av, FlxY_FlxqV_evalx(P, xp, T, p));
505
}
506
507
GEN
508
FlxY_Flx_div(GEN x, GEN y, ulong p)
509
{
510
long i, l;
511
GEN z;
512
if (degpol(y) == 0)
513
{
514
ulong t = uel(y,2);
515
if (t == 1) return x;
516
t = Fl_inv(t, p);
517
z = cgetg_copy(x, &l); z[1] = x[1];
518
for (i=2; i<l; i++) gel(z,i) = Flx_Fl_mul(gel(x,i),t,p);
519
}
520
else
521
{
522
z = cgetg_copy(x, &l); z[1] = x[1];
523
for (i=2; i<l; i++) gel(z,i) = Flx_div(gel(x,i),y,p);
524
}
525
return z;
526
}
527
528
GEN
529
FlxX_shift(GEN a, long n, long vs)
530
{
531
long i, l = lg(a);
532
GEN b;
533
if (l == 2 || !n) return a;
534
l += n;
535
if (n < 0)
536
{
537
if (l <= 2) return pol_0(varn(a));
538
b = cgetg(l, t_POL); b[1] = a[1];
539
a -= n;
540
for (i=2; i<l; i++) gel(b,i) = gel(a,i);
541
} else {
542
b = cgetg(l, t_POL); b[1] = a[1];
543
a -= n; n += 2;
544
for (i=2; i<n; i++) gel(b,i) = pol0_Flx(vs);
545
for ( ; i<l; i++) gel(b,i) = gel(a,i);
546
}
547
return b;
548
}
549
550
GEN
551
FlxX_blocks(GEN P, long n, long m, long vs)
552
{
553
GEN z = cgetg(m+1,t_VEC);
554
long i,j, k=2, l = lg(P);
555
for(i=1; i<=m; i++)
556
{
557
GEN zi = cgetg(n+2,t_POL);
558
zi[1] = P[1];
559
gel(z,i) = zi;
560
for(j=2; j<n+2; j++)
561
gel(zi, j) = k==l ? pol0_Flx(vs) : gel(P,k++);
562
zi = FlxX_renormalize(zi, n+2);
563
}
564
return z;
565
}
566
567
static GEN
568
FlxX_recipspec(GEN x, long l, long n, long vs)
569
{
570
long i;
571
GEN z = cgetg(n+2,t_POL);
572
z[1] = 0; z += 2;
573
for(i=0; i<l; i++)
574
gel(z,n-i-1) = Flx_copy(gel(x,i));
575
for( ; i<n; i++)
576
gel(z,n-i-1) = pol0_Flx(vs);
577
return FlxX_renormalize(z-2,n+2);
578
}
579
580
GEN
581
FlxX_invLaplace(GEN x, ulong p)
582
{
583
long i, d = degpol(x);
584
GEN y;
585
ulong t;
586
if (d <= 1) return gcopy(x);
587
t = Fl_inv(factorial_Fl(d, p), p);
588
y = cgetg(d+3, t_POL);
589
y[1] = x[1];
590
for (i=d; i>=2; i--)
591
{
592
gel(y,i+2) = Flx_Fl_mul(gel(x,i+2), t, p);
593
t = Fl_mul(t, i, p);
594
}
595
gel(y,3) = Flx_copy(gel(x,3));
596
gel(y,2) = Flx_copy(gel(x,2));
597
return FlxX_renormalize(y, d+3);
598
}
599
600
GEN
601
FlxX_Laplace(GEN x, ulong p)
602
{
603
long i, d = degpol(x);
604
ulong t = 1;
605
GEN y;
606
if (d <= 1) return gcopy(x);
607
y = cgetg(d+3, t_POL);
608
y[1] = x[1];
609
gel(y,2) = Flx_copy(gel(x,2));
610
gel(y,3) = Flx_copy(gel(x,3));
611
for (i=2; i<=d; i++)
612
{
613
t = Fl_mul(t, i%p, p);
614
gel(y,i+2) = Flx_Fl_mul(gel(x,i+2), t, p);
615
}
616
return FlxX_renormalize(y, d+3);
617
}
618
619
/***********************************************************************/
620
/** **/
621
/** FlxqX **/
622
/** **/
623
/***********************************************************************/
624
625
static GEN
626
get_FlxqX_red(GEN T, GEN *B)
627
{
628
if (typ(T)!=t_VEC) { *B=NULL; return T; }
629
*B = gel(T,1); return gel(T,2);
630
}
631
632
GEN
633
RgX_to_FlxqX(GEN x, GEN T, ulong p)
634
{
635
long i, l = lg(x);
636
GEN z = cgetg(l, t_POL); z[1] = x[1];
637
for (i = 2; i < l; i++)
638
gel(z,i) = Rg_to_Flxq(gel(x,i), T, p);
639
return FlxX_renormalize(z, l);
640
}
641
642
/* FlxqX are t_POL with Flxq coefficients.
643
* Normally the variable ordering should be respected.*/
644
645
GEN
646
random_FlxqX(long d1, long v, GEN T, ulong p)
647
{
648
long dT = get_Flx_degree(T), vT = get_Flx_var(T);
649
long i, d = d1+2;
650
GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
651
for (i=2; i<d; i++) gel(y,i) = random_Flx(dT, vT, p);
652
return FlxX_renormalize(y,d);
653
}
654
655
/*Not stack clean*/
656
GEN
657
Kronecker_to_FlxqX(GEN z, GEN T, ulong p)
658
{
659
long i,j,lx,l, N = (get_Flx_degree(T)<<1) + 1;
660
GEN x, t = cgetg(N,t_VECSMALL);
661
t[1] = get_Flx_var(T);
662
l = lg(z); lx = (l-2) / (N-2);
663
x = cgetg(lx+3,t_POL);
664
x[1] = z[1];
665
for (i=2; i<lx+2; i++)
666
{
667
for (j=2; j<N; j++) t[j] = z[j];
668
z += (N-2);
669
gel(x,i) = Flx_rem(Flx_renormalize(t,N), T,p);
670
}
671
N = (l-2) % (N-2) + 2;
672
for (j=2; j<N; j++) t[j] = z[j];
673
gel(x,i) = Flx_rem(Flx_renormalize(t,N), T,p);
674
return FlxX_renormalize(x, i+1);
675
}
676
677
GEN
678
FlxqX_red(GEN z, GEN T, ulong p)
679
{
680
GEN res;
681
long i, l = lg(z);
682
res = cgetg(l,t_POL); res[1] = z[1];
683
for(i=2;i<l;i++) gel(res,i) = Flx_rem(gel(z,i),T,p);
684
return FlxX_renormalize(res,l);
685
}
686
687
static GEN
688
FlxqX_mulspec(GEN x, GEN y, GEN T, ulong p, long lx, long ly)
689
{
690
pari_sp ltop=avma;
691
GEN z,kx,ky;
692
long dT = get_Flx_degree(T);
693
kx= zxX_to_Kronecker_spec(x,lx,dT);
694
ky= zxX_to_Kronecker_spec(y,ly,dT);
695
z = Flx_mul(ky, kx, p);
696
z = Kronecker_to_FlxqX(z,T,p);
697
return gerepileupto(ltop,z);
698
}
699
700
GEN
701
FlxqX_mul(GEN x, GEN y, GEN T, ulong p)
702
{
703
pari_sp ltop=avma;
704
GEN z, kx, ky, Tm = get_Flx_mod(T);
705
kx= zxX_to_Kronecker(x, Tm);
706
ky= zxX_to_Kronecker(y, Tm);
707
z = Flx_mul(ky, kx, p);
708
z = Kronecker_to_FlxqX(z, T, p);
709
return gerepileupto(ltop, z);
710
}
711
712
GEN
713
FlxqX_sqr(GEN x, GEN T, ulong p)
714
{
715
pari_sp ltop=avma;
716
GEN z,kx;
717
kx= zxX_to_Kronecker(x,get_Flx_mod(T));
718
z = Flx_sqr(kx, p);
719
z = Kronecker_to_FlxqX(z,T,p);
720
return gerepileupto(ltop,z);
721
}
722
723
GEN
724
FlxqX_Flxq_mul(GEN P, GEN U, GEN T, ulong p)
725
{
726
long i, lP = lg(P);
727
GEN res = cgetg(lP,t_POL);
728
res[1] = P[1];
729
for(i=2; i<lP; i++)
730
gel(res,i) = Flxq_mul(U,gel(P,i), T,p);
731
return FlxX_renormalize(res, lP);
732
}
733
GEN
734
FlxqX_Flxq_mul_to_monic(GEN P, GEN U, GEN T, ulong p)
735
{
736
long i, lP = lg(P);
737
GEN res = cgetg(lP,t_POL);
738
res[1] = P[1];
739
for(i=2; i<lP-1; i++) gel(res,i) = Flxq_mul(U,gel(P,i), T,p);
740
gel(res,lP-1) = pol1_Flx(get_Flx_var(T));
741
return FlxX_renormalize(res, lP);
742
}
743
744
GEN
745
FlxqX_normalize(GEN z, GEN T, ulong p)
746
{
747
GEN p1 = leading_coeff(z);
748
if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;
749
return FlxqX_Flxq_mul_to_monic(z, Flxq_inv(p1,T,p), T,p);
750
}
751
752
/* x and y in Z[Y][X]. Assume T irreducible mod p */
753
static GEN
754
FlxqX_divrem_basecase(GEN x, GEN y, GEN T, ulong p, GEN *pr)
755
{
756
long vx, dx, dy, dz, i, j, sx, lr;
757
pari_sp av0, av, tetpil;
758
GEN z,p1,rem,lead;
759
760
if (!signe(y)) pari_err_INV("FlxqX_divrem",y);
761
vx=varn(x); dy=degpol(y); dx=degpol(x);
762
if (dx < dy)
763
{
764
if (pr)
765
{
766
av0 = avma; x = FlxqX_red(x, T, p);
767
if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
768
if (pr == ONLY_REM) return x;
769
*pr = x;
770
}
771
return pol_0(vx);
772
}
773
lead = leading_coeff(y);
774
if (!dy) /* y is constant */
775
{
776
if (pr && pr != ONLY_DIVIDES)
777
{
778
if (pr == ONLY_REM) return pol_0(vx);
779
*pr = pol_0(vx);
780
}
781
if (Flx_equal1(lead)) return gcopy(x);
782
av0 = avma; x = FlxqX_Flxq_mul(x,Flxq_inv(lead,T,p),T,p);
783
return gerepileupto(av0,x);
784
}
785
av0 = avma; dz = dx-dy;
786
lead = Flx_equal1(lead)? NULL: gclone(Flxq_inv(lead,T,p));
787
set_avma(av0);
788
z = cgetg(dz+3,t_POL); z[1] = x[1];
789
x += 2; y += 2; z += 2;
790
791
p1 = gel(x,dx); av = avma;
792
gel(z,dz) = lead? gerepileupto(av, Flxq_mul(p1,lead, T, p)): gcopy(p1);
793
for (i=dx-1; i>=dy; i--)
794
{
795
av=avma; p1=gel(x,i);
796
for (j=i-dy+1; j<=i && j<=dz; j++)
797
p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p);
798
if (lead) p1 = Flx_mul(p1, lead,p);
799
tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,Flx_rem(p1,T,p));
800
}
801
if (!pr) { guncloneNULL(lead); return z-2; }
802
803
rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
804
for (sx=0; ; i--)
805
{
806
p1 = gel(x,i);
807
for (j=0; j<=i && j<=dz; j++)
808
p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p),p);
809
tetpil=avma; p1 = Flx_rem(p1, T, p); if (lgpol(p1)) { sx = 1; break; }
810
if (!i) break;
811
set_avma(av);
812
}
813
if (pr == ONLY_DIVIDES)
814
{
815
guncloneNULL(lead);
816
if (sx) return gc_NULL(av0);
817
return gc_const((pari_sp)rem, z-2);
818
}
819
lr=i+3; rem -= lr;
820
rem[0] = evaltyp(t_POL) | evallg(lr);
821
rem[1] = z[-1];
822
p1 = gerepile((pari_sp)rem,tetpil,p1);
823
rem += 2; gel(rem,i) = p1;
824
for (i--; i>=0; i--)
825
{
826
av=avma; p1 = gel(x,i);
827
for (j=0; j<=i && j<=dz; j++)
828
p1 = Flx_sub(p1, Flx_mul(gel(z,j),gel(y,i-j),p), p);
829
tetpil=avma; gel(rem,i) = gerepile(av,tetpil, Flx_rem(p1, T, p));
830
}
831
rem -= 2;
832
guncloneNULL(lead);
833
if (!sx) (void)FlxX_renormalize(rem, lr);
834
if (pr == ONLY_REM) return gerepileupto(av0,rem);
835
*pr = rem; return z-2;
836
}
837
838
static GEN
839
FlxqX_invBarrett_basecase(GEN T, GEN Q, ulong p)
840
{
841
long i, l=lg(T)-1, lr = l-1, k;
842
long sv=Q[1];
843
GEN r=cgetg(lr,t_POL); r[1]=T[1];
844
gel(r,2) = pol1_Flx(sv);
845
for (i=3;i<lr;i++)
846
{
847
pari_sp ltop=avma;
848
GEN u = Flx_neg(gel(T,l-i+2),p);
849
for (k=3;k<i;k++)
850
u = Flx_sub(u, Flxq_mul(gel(T,l-i+k),gel(r,k),Q,p),p);
851
gel(r,i) = gerepileupto(ltop, u);
852
}
853
r = FlxX_renormalize(r,lr);
854
return r;
855
}
856
857
/* Return new lgpol */
858
static long
859
FlxX_lgrenormalizespec(GEN x, long lx)
860
{
861
long i;
862
for (i = lx-1; i>=0; i--)
863
if (lgpol(gel(x,i))) break;
864
return i+1;
865
}
866
867
static GEN
868
FlxqX_invBarrett_Newton(GEN S, GEN T, ulong p)
869
{
870
pari_sp av = avma;
871
long nold, lx, lz, lq, l = degpol(S), i, lQ;
872
GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
873
long dT = get_Flx_degree(T), vT = get_Flx_var(T);
874
ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
875
for (i=0;i<l;i++) gel(x,i) = pol0_Flx(vT);
876
q = FlxX_recipspec(S+2,l+1,l+1,dT);
877
lQ = lgpol(q); q+=2;
878
/* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */
879
880
/* initialize */
881
gel(x,0) = Flxq_inv(gel(q,0),T, p);
882
if (lQ>1 && degpol(gel(q,1)) >= dT)
883
gel(q,1) = Flx_rem(gel(q,1), T, p);
884
if (lQ>1 && lgpol(gel(q,1)))
885
{
886
GEN u = gel(q, 1);
887
if (!Flx_equal1(gel(x,0))) u = Flxq_mul(u, Flxq_sqr(gel(x,0), T,p), T,p);
888
gel(x,1) = Flx_neg(u, p); lx = 2;
889
}
890
else
891
lx = 1;
892
nold = 1;
893
for (; mask > 1; )
894
{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
895
long i, lnew, nnew = nold << 1;
896
897
if (mask & 1) nnew--;
898
mask >>= 1;
899
900
lnew = nnew + 1;
901
lq = FlxX_lgrenormalizespec(q, minss(lQ,lnew));
902
z = FlxqX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */
903
lz = lgpol(z); if (lz > lnew) lz = lnew;
904
z += 2;
905
/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
906
for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;
907
nold = nnew;
908
if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
909
910
/* z + i represents (x*q - 1) / t^i */
911
lz = FlxX_lgrenormalizespec (z+i, lz-i);
912
z = FlxqX_mulspec(x, z+i, T,p, lx, lz); /* FIXME: low product */
913
lz = lgpol(z); z += 2;
914
if (lz > lnew-i) lz = FlxX_lgrenormalizespec(z, lnew-i);
915
916
lx = lz+ i;
917
y = x + i; /* x -= z * t^i, in place */
918
for (i = 0; i < lz; i++) gel(y,i) = Flx_neg(gel(z,i), p);
919
}
920
x -= 2; setlg(x, lx + 2); x[1] = S[1];
921
return gerepilecopy(av, x);
922
}
923
924
GEN
925
FlxqX_invBarrett(GEN T, GEN Q, ulong p)
926
{
927
pari_sp ltop=avma;
928
long l=lg(T), v = varn(T);
929
GEN r;
930
GEN c = gel(T,l-1);
931
if (l<5) return pol_0(v);
932
if (l<=FlxqX_INVBARRETT_LIMIT)
933
{
934
if (!Flx_equal1(c))
935
{
936
GEN ci = Flxq_inv(c,Q,p);
937
T = FlxqX_Flxq_mul(T, ci, Q, p);
938
r = FlxqX_invBarrett_basecase(T,Q,p);
939
r = FlxqX_Flxq_mul(r,ci,Q,p);
940
} else
941
r = FlxqX_invBarrett_basecase(T,Q,p);
942
} else
943
r = FlxqX_invBarrett_Newton(T,Q,p);
944
return gerepileupto(ltop, r);
945
}
946
947
GEN
948
FlxqX_get_red(GEN S, GEN T, ulong p)
949
{
950
if (typ(S)==t_POL && lg(S)>FlxqX_BARRETT_LIMIT)
951
retmkvec2(FlxqX_invBarrett(S, T, p), S);
952
return S;
953
}
954
955
/* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)
956
* * and mg is the Barrett inverse of S. */
957
static GEN
958
FlxqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, ulong p, GEN *pr)
959
{
960
GEN q, r;
961
long lt = degpol(S); /*We discard the leading term*/
962
long ld, lm, lT, lmg;
963
ld = l-lt;
964
lm = minss(ld, lgpol(mg));
965
lT = FlxX_lgrenormalizespec(S+2,lt);
966
lmg = FlxX_lgrenormalizespec(mg+2,lm);
967
q = FlxX_recipspec(x+lt,ld,ld,0); /* q = rec(x) lq<=ld*/
968
q = FlxqX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/
969
q = FlxX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/
970
if (!pr) return q;
971
r = FlxqX_mulspec(q+2,S+2,T,p,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/
972
r = FlxX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */
973
if (pr == ONLY_REM) return r;
974
*pr = r; return q;
975
}
976
977
static GEN
978
FlxqX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, ulong p, GEN *pr)
979
{
980
GEN q = NULL, r = FlxqX_red(x, T, p);
981
long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);
982
long i;
983
if (l <= lt)
984
{
985
if (pr == ONLY_REM) return r;
986
if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
987
if (pr) *pr = r;
988
return pol_0(v);
989
}
990
if (lt <= 1)
991
return FlxqX_divrem_basecase(x,S,T,p,pr);
992
if (pr != ONLY_REM && l>lm)
993
{
994
long vT = get_Flx_var(T);
995
q = cgetg(l-lt+2, t_POL); q[1] = S[1];
996
for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_Flx(vT);
997
}
998
while (l>lm)
999
{
1000
GEN zr, zq = FlxqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr);
1001
long lz = lgpol(zr);
1002
if (pr != ONLY_REM)
1003
{
1004
long lq = lgpol(zq);
1005
for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
1006
}
1007
for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
1008
l = l-lm+lz;
1009
}
1010
if (pr == ONLY_REM)
1011
{
1012
if (l > lt)
1013
r = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,ONLY_REM);
1014
else
1015
r = FlxX_renormalize(r, l+2);
1016
setvarn(r, v); return r;
1017
}
1018
if (l > lt)
1019
{
1020
GEN zq = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,pr? &r: NULL);
1021
if (!q) q = zq;
1022
else
1023
{
1024
long lq = lgpol(zq);
1025
for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
1026
}
1027
}
1028
else if (pr)
1029
r = FlxX_renormalize(r, l+2);
1030
setvarn(q, v); q = FlxX_renormalize(q, lg(q));
1031
if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
1032
if (pr) { setvarn(r, v); *pr = r; }
1033
return q;
1034
}
1035
1036
GEN
1037
FlxqX_divrem(GEN x, GEN S, GEN T, ulong p, GEN *pr)
1038
{
1039
GEN B, y;
1040
long dy, dx, d;
1041
if (pr==ONLY_REM) return FlxqX_rem(x, S, T, p);
1042
y = get_FlxqX_red(S, &B);
1043
dy = degpol(y); dx = degpol(x); d = dx-dy;
1044
if (!B && d+3 < FlxqX_DIVREM_BARRETT_LIMIT)
1045
return FlxqX_divrem_basecase(x,y,T,p,pr);
1046
else
1047
{
1048
pari_sp av = avma;
1049
GEN mg = B? B: FlxqX_invBarrett(y, T, p);
1050
GEN q = FlxqX_divrem_Barrett(x,mg,y,T,p,pr);
1051
if (!q) return gc_NULL(av);
1052
if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q);
1053
gerepileall(av,2,&q,pr);
1054
return q;
1055
}
1056
}
1057
1058
GEN
1059
FlxqX_rem(GEN x, GEN S, GEN T, ulong p)
1060
{
1061
GEN B, y = get_FlxqX_red(S, &B);
1062
long dy = degpol(y), dx = degpol(x), d = dx-dy;
1063
if (d < 0) return FlxqX_red(x, T, p);
1064
if (!B && d+3 < FlxqX_REM_BARRETT_LIMIT)
1065
return FlxqX_divrem_basecase(x,y, T, p, ONLY_REM);
1066
else
1067
{
1068
pari_sp av=avma;
1069
GEN mg = B? B: FlxqX_invBarrett(y, T, p);
1070
GEN r = FlxqX_divrem_Barrett(x, mg, y, T, p, ONLY_REM);
1071
return gerepileupto(av, r);
1072
}
1073
}
1074
1075
static GEN
1076
FlxqX_halfgcd_basecase(GEN a, GEN b, GEN T, ulong p)
1077
{
1078
pari_sp av=avma;
1079
GEN u,u1,v,v1;
1080
long vx = varn(a);
1081
long n = lgpol(a)>>1;
1082
u1 = v = pol_0(vx);
1083
u = v1 = pol1_FlxX(vx, get_Flx_var(T));
1084
while (lgpol(b)>n)
1085
{
1086
GEN r, q = FlxqX_divrem(a,b, T, p, &r);
1087
a = b; b = r; swap(u,u1); swap(v,v1);
1088
u1 = FlxX_sub(u1, FlxqX_mul(u, q, T, p), p);
1089
v1 = FlxX_sub(v1, FlxqX_mul(v, q ,T, p), p);
1090
if (gc_needed(av,2))
1091
{
1092
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_halfgcd (d = %ld)",degpol(b));
1093
gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);
1094
}
1095
}
1096
return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));
1097
}
1098
static GEN
1099
FlxqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, ulong p)
1100
{
1101
return FlxX_add(FlxqX_mul(u, x, T, p),FlxqX_mul(v, y, T, p), p);
1102
}
1103
1104
static GEN
1105
FlxqXM_FlxqX_mul2(GEN M, GEN x, GEN y, GEN T, ulong p)
1106
{
1107
GEN res = cgetg(3, t_COL);
1108
gel(res, 1) = FlxqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p);
1109
gel(res, 2) = FlxqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p);
1110
return res;
1111
}
1112
1113
static GEN
1114
FlxqXM_mul2(GEN A, GEN B, GEN T, ulong p)
1115
{
1116
GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
1117
GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
1118
GEN M1 = FlxqX_mul(FlxX_add(A11,A22, p), FlxX_add(B11,B22, p), T, p);
1119
GEN M2 = FlxqX_mul(FlxX_add(A21,A22, p), B11, T, p);
1120
GEN M3 = FlxqX_mul(A11, FlxX_sub(B12,B22, p), T, p);
1121
GEN M4 = FlxqX_mul(A22, FlxX_sub(B21,B11, p), T, p);
1122
GEN M5 = FlxqX_mul(FlxX_add(A11,A12, p), B22, T, p);
1123
GEN M6 = FlxqX_mul(FlxX_sub(A21,A11, p), FlxX_add(B11,B12, p), T, p);
1124
GEN M7 = FlxqX_mul(FlxX_sub(A12,A22, p), FlxX_add(B21,B22, p), T, p);
1125
GEN T1 = FlxX_add(M1,M4, p), T2 = FlxX_sub(M7,M5, p);
1126
GEN T3 = FlxX_sub(M1,M2, p), T4 = FlxX_add(M3,M6, p);
1127
retmkmat2(mkcol2(FlxX_add(T1,T2, p), FlxX_add(M2,M4, p)),
1128
mkcol2(FlxX_add(M3,M5, p), FlxX_add(T3,T4, p)));
1129
}
1130
1131
/* Return [0,1;1,-q]*M */
1132
static GEN
1133
FlxqX_FlxqXM_qmul(GEN q, GEN M, GEN T, ulong p)
1134
{
1135
GEN u, v, res = cgetg(3, t_MAT);
1136
u = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(gcoeff(M,2,1), q, T, p), p);
1137
gel(res,1) = mkcol2(gcoeff(M,2,1), u);
1138
v = FlxX_sub(gcoeff(M,1,2), FlxqX_mul(gcoeff(M,2,2), q, T, p), p);
1139
gel(res,2) = mkcol2(gcoeff(M,2,2), v);
1140
return res;
1141
}
1142
1143
static GEN
1144
matid2_FlxXM(long v, long sv)
1145
{
1146
retmkmat2(mkcol2(pol1_FlxX(v, sv),pol_0(v)),
1147
mkcol2(pol_0(v),pol1_FlxX(v, sv)));
1148
}
1149
1150
static GEN
1151
FlxqX_halfgcd_split(GEN x, GEN y, GEN T, ulong p)
1152
{
1153
pari_sp av=avma;
1154
GEN R, S, V;
1155
GEN y1, r, q;
1156
long l = lgpol(x), n = l>>1, k;
1157
long vT = get_Flx_var(T);
1158
if (lgpol(y)<=n) return matid2_FlxXM(varn(x),vT);
1159
R = FlxqX_halfgcd(FlxX_shift(x,-n,vT),FlxX_shift(y,-n,vT), T, p);
1160
V = FlxqXM_FlxqX_mul2(R,x,y, T, p); y1 = gel(V,2);
1161
if (lgpol(y1)<=n) return gerepilecopy(av, R);
1162
q = FlxqX_divrem(gel(V,1), y1, T, p, &r);
1163
k = 2*n-degpol(y1);
1164
S = FlxqX_halfgcd(FlxX_shift(y1,-k,vT), FlxX_shift(r,-k,vT), T, p);
1165
return gerepileupto(av, FlxqXM_mul2(S,FlxqX_FlxqXM_qmul(q,R, T, p), T, p));
1166
}
1167
1168
/* Return M in GL_2(Fp[X]) such that:
1169
if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
1170
*/
1171
1172
static GEN
1173
FlxqX_halfgcd_i(GEN x, GEN y, GEN T, ulong p)
1174
{
1175
if (lg(x)<=FlxqX_HALFGCD_LIMIT) return FlxqX_halfgcd_basecase(x, y, T, p);
1176
return FlxqX_halfgcd_split(x, y, T, p);
1177
}
1178
1179
GEN
1180
FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p)
1181
{
1182
pari_sp av = avma;
1183
GEN M,q,r;
1184
if (!signe(x))
1185
{
1186
long v = varn(x), vT = get_Flx_var(T);
1187
retmkmat2(mkcol2(pol_0(v),pol1_FlxX(v,vT)),
1188
mkcol2(pol1_FlxX(v,vT),pol_0(v)));
1189
}
1190
if (degpol(y)<degpol(x)) return FlxqX_halfgcd_i(x, y, T, p);
1191
q = FlxqX_divrem(y, x, T, p, &r);
1192
M = FlxqX_halfgcd_i(x, r, T, p);
1193
gcoeff(M,1,1) = FlxX_sub(gcoeff(M,1,1), FlxqX_mul(q, gcoeff(M,1,2), T, p), p);
1194
gcoeff(M,2,1) = FlxX_sub(gcoeff(M,2,1), FlxqX_mul(q, gcoeff(M,2,2), T, p), p);
1195
return gerepilecopy(av, M);
1196
}
1197
1198
static GEN
1199
FlxqX_gcd_basecase(GEN a, GEN b, GEN T, ulong p)
1200
{
1201
pari_sp av = avma, av0=avma;
1202
while (signe(b))
1203
{
1204
GEN c;
1205
if (gc_needed(av0,2))
1206
{
1207
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_gcd (d = %ld)",degpol(b));
1208
gerepileall(av0,2, &a,&b);
1209
}
1210
av = avma; c = FlxqX_rem(a, b, T, p); a=b; b=c;
1211
}
1212
return gc_const(av, a);
1213
}
1214
1215
GEN
1216
FlxqX_gcd(GEN x, GEN y, GEN T, ulong p)
1217
{
1218
pari_sp av = avma;
1219
x = FlxqX_red(x, T, p);
1220
y = FlxqX_red(y, T, p);
1221
if (!signe(x)) return gerepileupto(av, y);
1222
while (lg(y)>FlxqX_GCD_LIMIT)
1223
{
1224
GEN c;
1225
if (lgpol(y)<=(lgpol(x)>>1))
1226
{
1227
GEN r = FlxqX_rem(x, y, T, p);
1228
x = y; y = r;
1229
}
1230
c = FlxqXM_FlxqX_mul2(FlxqX_halfgcd(x,y, T, p), x, y, T, p);
1231
x = gel(c,1); y = gel(c,2);
1232
gerepileall(av,2,&x,&y);
1233
}
1234
return gerepileupto(av, FlxqX_gcd_basecase(x, y, T, p));
1235
}
1236
1237
static GEN
1238
FlxqX_extgcd_basecase(GEN a, GEN b, GEN T, ulong p, GEN *ptu, GEN *ptv)
1239
{
1240
pari_sp av=avma;
1241
GEN u,v,d,d1,v1;
1242
long vx = varn(a);
1243
d = a; d1 = b;
1244
v = pol_0(vx); v1 = pol1_FlxX(vx, get_Flx_var(T));
1245
while (signe(d1))
1246
{
1247
GEN r, q = FlxqX_divrem(d, d1, T, p, &r);
1248
v = FlxX_sub(v,FlxqX_mul(q,v1,T, p),p);
1249
u=v; v=v1; v1=u;
1250
u=r; d=d1; d1=u;
1251
if (gc_needed(av,2))
1252
{
1253
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_extgcd (d = %ld)",degpol(d));
1254
gerepileall(av,5, &d,&d1,&u,&v,&v1);
1255
}
1256
}
1257
if (ptu) *ptu = FlxqX_div(FlxX_sub(d,FlxqX_mul(b,v, T, p), p), a, T, p);
1258
*ptv = v; return d;
1259
}
1260
1261
static GEN
1262
FlxqX_extgcd_halfgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)
1263
{
1264
pari_sp av=avma;
1265
GEN u,v,R = matid2_FlxXM(varn(x), get_Flx_var(T));
1266
while (lg(y)>FlxqX_EXTGCD_LIMIT)
1267
{
1268
GEN M, c;
1269
if (lgpol(y)<=(lgpol(x)>>1))
1270
{
1271
GEN r, q = FlxqX_divrem(x, y, T, p, &r);
1272
x = y; y = r;
1273
R = FlxqX_FlxqXM_qmul(q, R, T, p);
1274
}
1275
M = FlxqX_halfgcd(x,y, T, p);
1276
c = FlxqXM_FlxqX_mul2(M, x,y, T, p);
1277
R = FlxqXM_mul2(M, R, T, p);
1278
x = gel(c,1); y = gel(c,2);
1279
gerepileall(av,3,&x,&y,&R);
1280
}
1281
y = FlxqX_extgcd_basecase(x,y, T, p, &u,&v);
1282
if (ptu) *ptu = FlxqX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T, p);
1283
*ptv = FlxqX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T, p);
1284
return y;
1285
}
1286
1287
/* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
1288
* ux + vy = gcd (mod T,p) */
1289
GEN
1290
FlxqX_extgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)
1291
{
1292
GEN d;
1293
pari_sp ltop=avma;
1294
x = FlxqX_red(x, T, p);
1295
y = FlxqX_red(y, T, p);
1296
if (lg(y)>FlxqX_EXTGCD_LIMIT)
1297
d = FlxqX_extgcd_halfgcd(x, y, T, p, ptu, ptv);
1298
else
1299
d = FlxqX_extgcd_basecase(x, y, T, p, ptu, ptv);
1300
gerepileall(ltop,ptu?3:2,&d,ptv,ptu);
1301
return d;
1302
}
1303
1304
static GEN
1305
FlxqX_saferem(GEN P, GEN Q, GEN T, ulong p)
1306
{
1307
GEN U = Flxq_invsafe(leading_coeff(Q), T, p);
1308
if (!U) return NULL;
1309
Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p);
1310
return FlxqX_rem(P,Q,T,p);
1311
}
1312
1313
GEN
1314
FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p)
1315
{
1316
pari_sp av = avma;
1317
GEN U;
1318
if (!signe(P)) return gcopy(Q);
1319
if (!signe(Q)) return gcopy(P);
1320
T = Flx_get_red(T,p);
1321
for(;;)
1322
{
1323
P = FlxqX_saferem(P,Q,T,p);
1324
if (!P) return gc_NULL(av);
1325
if (!signe(P)) break;
1326
if (gc_needed(av, 1))
1327
{
1328
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_safegcd");
1329
gerepileall(av, 2, &P,&Q);
1330
}
1331
swap(P, Q);
1332
}
1333
U = Flxq_invsafe(leading_coeff(Q), T, p);
1334
if (!U) return gc_NULL(av);
1335
Q = FlxqX_Flxq_mul_to_monic(Q,U,T,p);
1336
return gerepileupto(av, Q);
1337
}
1338
1339
struct _FlxqX {ulong p; GEN T;};
1340
static GEN _FlxqX_mul(void *data,GEN a,GEN b)
1341
{
1342
struct _FlxqX *d=(struct _FlxqX*)data;
1343
return FlxqX_mul(a,b,d->T,d->p);
1344
}
1345
static GEN _FlxqX_sqr(void *data,GEN a)
1346
{
1347
struct _FlxqX *d=(struct _FlxqX*)data;
1348
return FlxqX_sqr(a,d->T,d->p);
1349
}
1350
1351
GEN
1352
FlxqX_powu(GEN V, ulong n, GEN T, ulong p)
1353
{
1354
struct _FlxqX d; d.p=p; d.T=T;
1355
return gen_powu(V, n, (void*)&d, &_FlxqX_sqr, &_FlxqX_mul);
1356
}
1357
1358
/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
1359
GEN
1360
FlxqX_saferesultant(GEN a, GEN b, GEN T, ulong p)
1361
{
1362
long vT = get_Flx_var(T);
1363
long da,db,dc;
1364
pari_sp av;
1365
GEN c,lb, res = pol1_Flx(vT);
1366
1367
if (!signe(a) || !signe(b)) return pol0_Flx(vT);
1368
1369
da = degpol(a);
1370
db = degpol(b);
1371
if (db > da)
1372
{
1373
swapspec(a,b, da,db);
1374
if (both_odd(da,db)) res = Flx_neg(res, p);
1375
}
1376
if (!da) return pol1_Flx(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
1377
av = avma;
1378
while (db)
1379
{
1380
lb = gel(b,db+2);
1381
c = FlxqX_saferem(a,b, T,p);
1382
if (!c) return gc_NULL(av);
1383
a = b; b = c; dc = degpol(c);
1384
if (dc < 0) { set_avma(av); return pol0_Flx(vT); }
1385
1386
if (both_odd(da,db)) res = Flx_neg(res, p);
1387
if (!equali1(lb)) res = Flxq_mul(res, Flxq_powu(lb, da - dc, T, p), T, p);
1388
if (gc_needed(av,2))
1389
{
1390
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (da = %ld)",da);
1391
gerepileall(av,3, &a,&b,&res);
1392
}
1393
da = db; /* = degpol(a) */
1394
db = dc; /* = degpol(b) */
1395
}
1396
res = Flxq_mul(res, Flxq_powu(gel(b,2), da, T, p), T, p);
1397
return gerepileupto(av, res);
1398
}
1399
1400
/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
1401
GEN
1402
FlxqX_resultant(GEN a, GEN b, GEN T, ulong p)
1403
{
1404
long vT = get_Flx_var(T);
1405
long da,db,dc;
1406
pari_sp av;
1407
GEN c,lb, res = pol1_Flx(vT);
1408
1409
if (!signe(a) || !signe(b)) return pol0_Flx(vT);
1410
1411
da = degpol(a);
1412
db = degpol(b);
1413
if (db > da)
1414
{
1415
swapspec(a,b, da,db);
1416
if (both_odd(da,db)) res = Flx_neg(res, p);
1417
}
1418
if (!da) return pol1_Flx(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
1419
av = avma;
1420
while (db)
1421
{
1422
lb = gel(b,db+2);
1423
c = FlxqX_rem(a,b, T,p);
1424
a = b; b = c; dc = degpol(c);
1425
if (dc < 0) { set_avma(av); return pol0_Flx(vT); }
1426
1427
if (both_odd(da,db)) res = Flx_neg(res, p);
1428
if (!equali1(lb)) res = Flxq_mul(res, Flxq_powu(lb, da - dc, T, p), T, p);
1429
if (gc_needed(av,2))
1430
{
1431
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (da = %ld)",da);
1432
gerepileall(av,3, &a,&b,&res);
1433
}
1434
da = db; /* = degpol(a) */
1435
db = dc; /* = degpol(b) */
1436
}
1437
res = Flxq_mul(res, Flxq_powu(gel(b,2), da, T, p), T, p);
1438
return gerepileupto(av, res);
1439
}
1440
1441
/* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
1442
GEN
1443
FlxqX_disc(GEN P, GEN T, ulong p)
1444
{
1445
pari_sp av = avma;
1446
GEN L, dP = FlxX_deriv(P, p), D = FlxqX_resultant(P, dP, T, p);
1447
long dd;
1448
if (!lgpol(D)) return pol0_Flx(get_Flx_var(T));
1449
dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
1450
L = leading_coeff(P);
1451
if (dd && !Flx_equal1(L))
1452
D = (dd == -1)? Flxq_div(D,L,T,p): Flxq_mul(D, Flxq_powu(L, dd, T, p), T, p);
1453
if (degpol(P) & 2) D = Flx_neg(D, p);
1454
return gerepileupto(av, D);
1455
}
1456
1457
INLINE GEN
1458
FlxXn_recip(GEN x, long n, long v)
1459
{
1460
return FlxX_recipspec(x+2, minss(lgpol(x), n), n, v);
1461
}
1462
1463
GEN
1464
FlxqX_Newton(GEN P, long n, GEN T, ulong p)
1465
{
1466
pari_sp av = avma;
1467
long d = degpol(P), vT = get_Flx_var(T);
1468
GEN dP = FlxXn_recip(FlxX_deriv(P, p), d, vT);
1469
GEN Q = FlxqXn_mul(FlxqXn_inv(FlxXn_recip(P, d+1, vT), n, T, p), dP, n, T, p);
1470
return gerepilecopy(av, Q);
1471
}
1472
1473
GEN
1474
FlxqX_fromNewton(GEN P, GEN T, ulong p)
1475
{
1476
pari_sp av = avma;
1477
long vT = get_Flx_var(T);
1478
long n = Flx_constant(constant_coeff(P))+1;
1479
GEN z = FlxX_neg(FlxX_shift(P, -1, vT), p);
1480
GEN Q = FlxXn_recip(FlxqXn_expint(z, n, T, p), n, vT);
1481
return gerepilecopy(av, Q);
1482
}
1483
1484
static GEN
1485
FlxqX_composedsum(GEN P, GEN Q, GEN T, ulong p)
1486
{
1487
long n = 1+ degpol(P)*degpol(Q);
1488
GEN Pl = FlxX_invLaplace(FlxqX_Newton(P,n, T,p), p);
1489
GEN Ql = FlxX_invLaplace(FlxqX_Newton(Q,n, T,p), p);
1490
GEN L = FlxX_Laplace(FlxqXn_mul(Pl, Ql, n, T,p), p);
1491
GEN R = FlxqX_fromNewton(L, T, p);
1492
GEN lead = Flxq_mul(Flxq_powu(leading_coeff(P),degpol(Q), T, p),
1493
Flxq_powu(leading_coeff(Q),degpol(P), T, p), T, p);
1494
return FlxqX_Flxq_mul(R, lead, T, p);
1495
}
1496
1497
GEN
1498
FlxqX_direct_compositum(GEN P, GEN Q, GEN T, ulong p)
1499
{
1500
return FlxqX_composedsum(P, Q, T, p);
1501
}
1502
1503
GEN
1504
FlxqXV_prod(GEN V, GEN T, ulong p)
1505
{
1506
struct _FlxqX d; d.p=p; d.T=T;
1507
return gen_product(V, (void*)&d, &_FlxqX_mul);
1508
}
1509
1510
static GEN
1511
FlxqV_roots_to_deg1(GEN x, GEN T, ulong p, long v)
1512
{
1513
long sv = get_Flx_var(T);
1514
pari_APPLY_same(deg1pol_shallow(pol1_Flx(sv),Flx_neg(gel(x,i),p),v))
1515
}
1516
1517
GEN
1518
FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v)
1519
{
1520
pari_sp ltop = avma;
1521
GEN W = FlxqV_roots_to_deg1(V, T, p, v);
1522
return gerepileupto(ltop, FlxqXV_prod(W, T, p));
1523
}
1524
1525
/*******************************************************************/
1526
/* */
1527
/* (Fl[X]/T(X))[Y] / S(Y) */
1528
/* */
1529
/*******************************************************************/
1530
1531
GEN
1532
FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p) {
1533
return FlxqX_rem(FlxqX_mul(x,y,T,p),S,T,p);
1534
}
1535
1536
GEN
1537
FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p) {
1538
return FlxqX_rem(FlxqX_sqr(x,T,p),S,T,p);
1539
}
1540
1541
GEN
1542
FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p)
1543
{
1544
GEN V, z = FlxqX_extgcd(get_FlxqX_mod(S), x, T, p, NULL, &V);
1545
if (degpol(z)) return NULL;
1546
z = Flxq_invsafe(gel(z,2),T,p);
1547
if (!z) return NULL;
1548
return FlxqX_Flxq_mul(V, z, T, p);
1549
}
1550
1551
GEN
1552
FlxqXQ_inv(GEN x, GEN S, GEN T,ulong p)
1553
{
1554
pari_sp av = avma;
1555
GEN U = FlxqXQ_invsafe(x, S, T, p);
1556
if (!U) pari_err_INV("FlxqXQ_inv",x);
1557
return gerepileupto(av, U);
1558
}
1559
1560
GEN
1561
FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p) {
1562
return FlxqXQ_mul(x, FlxqXQ_inv(y,S,T,p),S,T,p);
1563
}
1564
1565
struct _FlxqXQ {
1566
GEN T, S;
1567
ulong p;
1568
};
1569
static GEN
1570
_FlxqXQ_add(void *data, GEN x, GEN y) {
1571
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1572
return FlxX_add(x,y, d->p);
1573
}
1574
static GEN
1575
_FlxqXQ_sub(void *data, GEN x, GEN y) {
1576
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1577
return FlxX_sub(x,y, d->p);
1578
}
1579
#if 0
1580
static GEN
1581
_FlxqXQ_cmul(void *data, GEN P, long a, GEN x) {
1582
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1583
return FlxX_Flx_mul(x,gel(P,a+2), d->p);
1584
}
1585
#endif
1586
static GEN
1587
_FlxqXQ_red(void *data, GEN x) {
1588
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1589
return FlxqX_red(x, d->T, d->p);
1590
}
1591
static GEN
1592
_FlxqXQ_mul(void *data, GEN x, GEN y) {
1593
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1594
return FlxqXQ_mul(x,y, d->S,d->T, d->p);
1595
}
1596
static GEN
1597
_FlxqXQ_sqr(void *data, GEN x) {
1598
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1599
return FlxqXQ_sqr(x, d->S,d->T, d->p);
1600
}
1601
1602
static GEN
1603
_FlxqXQ_one(void *data) {
1604
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1605
return pol1_FlxX(get_FlxqX_var(d->S),get_Flx_var(d->T));
1606
}
1607
1608
static GEN
1609
_FlxqXQ_zero(void *data) {
1610
struct _FlxqXQ *d = (struct _FlxqXQ*) data;
1611
return pol_0(get_FlxqX_var(d->S));
1612
}
1613
1614
static struct bb_algebra FlxqXQ_algebra = { _FlxqXQ_red, _FlxqXQ_add,
1615
_FlxqXQ_sub, _FlxqXQ_mul, _FlxqXQ_sqr, _FlxqXQ_one, _FlxqXQ_zero };
1616
1617
const struct bb_algebra *
1618
get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p)
1619
{
1620
GEN z = new_chunk(sizeof(struct _FlxqXQ));
1621
struct _FlxqXQ *e = (struct _FlxqXQ *) z;
1622
e->T = Flx_get_red(T, p);
1623
e->S = FlxqX_get_red(S, e->T, p);
1624
e->p = p; *E = (void*)e;
1625
return &FlxqXQ_algebra;
1626
}
1627
1628
/* x over Fq, return lift(x^n) mod S */
1629
GEN
1630
FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p)
1631
{
1632
pari_sp av = avma;
1633
struct _FlxqXQ D;
1634
long s = signe(n);
1635
if (!s) return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));
1636
if (s < 0) x = FlxqXQ_inv(x,S,T,p);
1637
if (is_pm1(n)) return s < 0 ? x : gcopy(x);
1638
if (degpol(x) >= get_FlxqX_degree(S)) x = FlxqX_rem(x,S,T,p);
1639
T = Flx_get_red(T, p);
1640
S = FlxqX_get_red(S, T, p);
1641
D.S = S;
1642
D.T = T;
1643
D.p = p;
1644
x = gen_pow_i(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);
1645
return gerepilecopy(av, x);
1646
}
1647
1648
/* x over Fq, return lift(x^n) mod S */
1649
GEN
1650
FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p)
1651
{
1652
pari_sp av = avma;
1653
struct _FlxqXQ D;
1654
switch(n)
1655
{
1656
case 0: return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));
1657
case 1: return gcopy(x);
1658
case 2: return FlxqXQ_sqr(x, S, T, p);
1659
}
1660
T = Flx_get_red(T, p);
1661
S = FlxqX_get_red(S, T, p);
1662
D.S = S; D.T = T; D.p = p;
1663
x = gen_powu_i(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);
1664
return gerepilecopy(av, x);
1665
}
1666
1667
GEN
1668
FlxqXQ_powers(GEN x, long l, GEN S, GEN T, ulong p)
1669
{
1670
struct _FlxqXQ D;
1671
int use_sqr = 2*degpol(x) >= get_FlxqX_degree(S);
1672
T = Flx_get_red(T, p);
1673
S = FlxqX_get_red(S, T, p);
1674
D.S = S; D.T = T; D.p = p;
1675
return gen_powers(x, l, use_sqr, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul,&_FlxqXQ_one);
1676
}
1677
1678
/* Let v a linear form, return the linear form z->v(tau*z)
1679
that is, v*(M_tau) */
1680
1681
static GEN
1682
FlxqXQ_transmul_init(GEN tau, GEN S, GEN T, ulong p)
1683
{
1684
GEN bht;
1685
GEN h, Sp = get_FlxqX_red(S, &h);
1686
long n = degpol(Sp), vS = varn(Sp), vT = get_Flx_var(T);
1687
GEN ft = FlxX_recipspec(Sp+2, n+1, n+1, vT);
1688
GEN bt = FlxX_recipspec(tau+2, lgpol(tau), n, vT);
1689
setvarn(ft, vS); setvarn(bt, vS);
1690
if (h)
1691
bht = FlxqXn_mul(bt, h, n-1, T, p);
1692
else
1693
{
1694
GEN bh = FlxqX_div(FlxX_shift(tau, n-1, vT), S, T, p);
1695
bht = FlxX_recipspec(bh+2, lgpol(bh), n-1, vT);
1696
setvarn(bht, vS);
1697
}
1698
return mkvec3(bt, bht, ft);
1699
}
1700
1701
static GEN
1702
FlxqXQ_transmul(GEN tau, GEN a, long n, GEN T, ulong p)
1703
{
1704
pari_sp ltop = avma;
1705
GEN t1, t2, t3, vec;
1706
GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
1707
long vT = get_Flx_var(T);
1708
if (signe(a)==0) return pol_0(varn(a));
1709
t2 = FlxX_shift(FlxqX_mul(bt, a, T, p),1-n,vT);
1710
if (signe(bht)==0) return gerepilecopy(ltop, t2);
1711
t1 = FlxX_shift(FlxqX_mul(ft, a, T, p),-n,vT);
1712
t3 = FlxqXn_mul(t1, bht, n-1, T, p);
1713
vec = FlxX_sub(t2, FlxX_shift(t3, 1, vT), p);
1714
return gerepileupto(ltop, vec);
1715
}
1716
1717
static GEN
1718
polxn_FlxX(long n, long v, long vT)
1719
{
1720
long i, a = n+2;
1721
GEN p = cgetg(a+1, t_POL);
1722
p[1] = evalsigne(1)|evalvarn(v);
1723
for (i = 2; i < a; i++) gel(p,i) = pol0_Flx(vT);
1724
gel(p,a) = pol1_Flx(vT); return p;
1725
}
1726
1727
GEN
1728
FlxqXQ_minpoly(GEN x, GEN S, GEN T, ulong p)
1729
{
1730
pari_sp ltop = avma;
1731
long vS, vT, n;
1732
GEN v_x, g, tau;
1733
vS = get_FlxqX_var(S);
1734
vT = get_Flx_var(T);
1735
n = get_FlxqX_degree(S);
1736
g = pol1_FlxX(vS,vT);
1737
tau = pol1_FlxX(vS,vT);
1738
S = FlxqX_get_red(S, T, p);
1739
v_x = FlxqXQ_powers(x, usqrt(2*n), S, T, p);
1740
while(signe(tau) != 0)
1741
{
1742
long i, j, m, k1;
1743
GEN M, v, tr;
1744
GEN g_prime, c;
1745
if (degpol(g) == n) { tau = pol1_FlxX(vS, vT); g = pol1_FlxX(vS, vT); }
1746
v = random_FlxqX(n, vS, T, p);
1747
tr = FlxqXQ_transmul_init(tau, S, T, p);
1748
v = FlxqXQ_transmul(tr, v, n, T, p);
1749
m = 2*(n-degpol(g));
1750
k1 = usqrt(m);
1751
tr = FlxqXQ_transmul_init(gel(v_x,k1+1), S, T, p);
1752
c = cgetg(m+2,t_POL);
1753
c[1] = evalsigne(1)|evalvarn(vS);
1754
for (i=0; i<m; i+=k1)
1755
{
1756
long mj = minss(m-i, k1);
1757
for (j=0; j<mj; j++)
1758
gel(c,m+1-(i+j)) = FlxqX_dotproduct(v, gel(v_x,j+1), T, p);
1759
v = FlxqXQ_transmul(tr, v, n, T, p);
1760
}
1761
c = FlxX_renormalize(c, m+2);
1762
/* now c contains <v,x^i> , i = 0..m-1 */
1763
M = FlxqX_halfgcd(polxn_FlxX(m, vS, vT), c, T, p);
1764
g_prime = gmael(M, 2, 2);
1765
if (degpol(g_prime) < 1) continue;
1766
g = FlxqX_mul(g, g_prime, T, p);
1767
tau = FlxqXQ_mul(tau, FlxqX_FlxqXQV_eval(g_prime, v_x, S, T, p), S, T, p);
1768
}
1769
g = FlxqX_normalize(g,T, p);
1770
return gerepilecopy(ltop,g);
1771
}
1772
1773
GEN
1774
FlxqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, ulong p)
1775
{
1776
return FlxXV_to_FlxM(FlxqXQ_powers(y,m-1,S,T,p), n, get_Flx_var(T));
1777
}
1778
1779
static GEN
1780
FlxX_blocks_FlxM(GEN P, long n, long m, long v)
1781
{
1782
GEN z = cgetg(m+1,t_MAT);
1783
long i,j, k=2, l = lg(P);
1784
for(i=1; i<=m; i++)
1785
{
1786
GEN zi = cgetg(n+1,t_COL);
1787
gel(z,i) = zi;
1788
for(j=1; j<=n; j++)
1789
gel(zi, j) = k==l ? pol0_Flx(v) : gel(P,k++);
1790
}
1791
return z;
1792
}
1793
1794
GEN
1795
FlxqX_FlxqXQV_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)
1796
{
1797
pari_sp btop, av = avma;
1798
long v = get_FlxqX_var(S), m = get_FlxqX_degree(S);
1799
long vT = get_Flx_var(T);
1800
long i, l = lg(x)-1, lQ = lgpol(Q), n, d;
1801
GEN A, B, C, R, g;
1802
if (lQ == 0) return pol_0(v);
1803
if (lQ <= l)
1804
{
1805
n = l;
1806
d = 1;
1807
}
1808
else
1809
{
1810
n = l-1;
1811
d = (lQ+n-1)/n;
1812
}
1813
A = FlxXV_to_FlxM_lg(x, m, n, vT);
1814
B = FlxX_blocks_FlxM(Q, n, d, vT);
1815
C = gerepileupto(av, FlxqM_mul(A, B, T, p));
1816
g = gel(x, l);
1817
T = Flx_get_red(T, p);
1818
S = FlxqX_get_red(S, T, p);
1819
btop = avma;
1820
R = FlxV_to_FlxX(gel(C, d), v);
1821
for (i = d-1; i>0; i--)
1822
{
1823
R = FlxX_add(FlxqXQ_mul(R, g, S, T, p), FlxV_to_FlxX(gel(C,i), v), p);
1824
if (gc_needed(btop,1))
1825
R = gerepileupto(btop, R);
1826
}
1827
return gerepilecopy(av, R);
1828
}
1829
1830
GEN
1831
FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)
1832
{
1833
pari_sp av = avma;
1834
GEN z, V;
1835
long d = degpol(Q), rtd;
1836
if (d < 0) return pol_0(get_FlxqX_var(S));
1837
rtd = (long) sqrt((double)d);
1838
T = Flx_get_red(T, p);
1839
S = FlxqX_get_red(S, T, p);
1840
V = FlxqXQ_powers(x, rtd, S, T, p);
1841
z = FlxqX_FlxqXQV_eval(Q, V, S, T, p);
1842
return gerepileupto(av, z);
1843
}
1844
1845
static GEN
1846
FlxqXQ_autpow_sqr(void * E, GEN x)
1847
{
1848
struct _FlxqXQ *D = (struct _FlxqXQ *)E;
1849
GEN S = D->S, T = D->T;
1850
ulong p = D->p;
1851
GEN phi = gel(x,1), S1 = gel(x,2);
1852
long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);
1853
GEN V = Flxq_powers(phi, n, T, p);
1854
GEN phi2 = Flx_FlxqV_eval(phi, V, T, p);
1855
GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p);
1856
GEN S2 = FlxqX_FlxqXQ_eval(Sphi, S1, S, T, p);
1857
return mkvec2(phi2, S2);
1858
}
1859
1860
static GEN
1861
FlxqXQ_autpow_mul(void * E, GEN x, GEN y)
1862
{
1863
struct _FlxqXQ *D = (struct _FlxqXQ *)E;
1864
GEN S = D->S, T = D->T;
1865
ulong p = D->p;
1866
GEN phi1 = gel(x,1), S1 = gel(x,2);
1867
GEN phi2 = gel(y,1), S2 = gel(y,2);
1868
long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);
1869
GEN V = Flxq_powers(phi2, n, T, p);
1870
GEN phi3 = Flx_FlxqV_eval(phi1, V, T, p);
1871
GEN Sphi = FlxY_FlxqV_evalx(S1, V, T, p);
1872
GEN S3 = FlxqX_FlxqXQ_eval(Sphi, S2, S, T, p);
1873
return mkvec2(phi3, S3);
1874
}
1875
1876
GEN
1877
FlxqXQ_autpow(GEN aut, long n, GEN S, GEN T, ulong p)
1878
{
1879
pari_sp av = avma;
1880
struct _FlxqXQ D;
1881
T = Flx_get_red(T, p);
1882
S = FlxqX_get_red(S, T, p);
1883
D.S=S; D.T=T; D.p=p;
1884
aut = gen_powu_i(aut,n,&D,FlxqXQ_autpow_sqr,FlxqXQ_autpow_mul);
1885
return gerepilecopy(av, aut);
1886
}
1887
1888
static GEN
1889
FlxqXQ_autsum_mul(void *E, GEN x, GEN y)
1890
{
1891
struct _FlxqXQ *D = (struct _FlxqXQ *)E;
1892
GEN S = D->S, T = D->T;
1893
ulong p = D->p;
1894
GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);
1895
GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);
1896
long n2 = brent_kung_optpow(get_Flx_degree(T)-1, lgpol(S1)+lgpol(a1)+1,1);
1897
GEN V2 = Flxq_powers(phi2, n2, T, p);
1898
GEN phi3 = Flx_FlxqV_eval(phi1, V2, T, p);
1899
GEN Sphi = FlxY_FlxqV_evalx(S1, V2, T, p);
1900
GEN aphi = FlxY_FlxqV_evalx(a1, V2, T, p);
1901
long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);
1902
GEN V = FlxqXQ_powers(S2, n, S, T, p);
1903
GEN S3 = FlxqX_FlxqXQV_eval(Sphi, V, S, T, p);
1904
GEN aS = FlxqX_FlxqXQV_eval(aphi, V, S, T, p);
1905
GEN a3 = FlxqXQ_mul(aS, a2, S, T, p);
1906
return mkvec3(phi3, S3, a3);
1907
}
1908
1909
static GEN
1910
FlxqXQ_autsum_sqr(void * T, GEN x)
1911
{ return FlxqXQ_autsum_mul(T, x, x); }
1912
1913
GEN
1914
FlxqXQ_autsum(GEN aut, long n, GEN S, GEN T, ulong p)
1915
{
1916
pari_sp av = avma;
1917
struct _FlxqXQ D;
1918
T = Flx_get_red(T, p);
1919
S = FlxqX_get_red(S, T, p);
1920
D.S=S; D.T=T; D.p=p;
1921
aut = gen_powu_i(aut,n,&D,FlxqXQ_autsum_sqr,FlxqXQ_autsum_mul);
1922
return gerepilecopy(av, aut);
1923
}
1924
1925
static GEN
1926
FlxqXQ_auttrace_mul(void *E, GEN x, GEN y)
1927
{
1928
struct _FlxqXQ *D = (struct _FlxqXQ *)E;
1929
GEN S = D->S, T = D->T;
1930
ulong p = D->p;
1931
GEN S1 = gel(x,1), a1 = gel(x,2);
1932
GEN S2 = gel(y,1), a2 = gel(y,2);
1933
long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1);
1934
GEN V = FlxqXQ_powers(S2, n, S, T, p);
1935
GEN S3 = FlxqX_FlxqXQV_eval(S1, V, S, T, p);
1936
GEN aS = FlxqX_FlxqXQV_eval(a1, V, S, T, p);
1937
GEN a3 = FlxX_add(aS, a2, p);
1938
return mkvec2(S3, a3);
1939
}
1940
1941
static GEN
1942
FlxqXQ_auttrace_sqr(void *E, GEN x)
1943
{ return FlxqXQ_auttrace_mul(E, x, x); }
1944
1945
GEN
1946
FlxqXQ_auttrace(GEN x, ulong n, GEN S, GEN T, ulong p)
1947
{
1948
pari_sp av = avma;
1949
struct _FlxqXQ D;
1950
T = Flx_get_red(T, p);
1951
S = FlxqX_get_red(S, T, p);
1952
D.S=S; D.T=T; D.p=p;
1953
x = gen_powu_i(x,n,(void*)&D,FlxqXQ_auttrace_sqr,FlxqXQ_auttrace_mul);
1954
return gerepilecopy(av, x);
1955
}
1956
1957
/*******************************************************************/
1958
/* */
1959
/* FlxYqQ */
1960
/* */
1961
/*******************************************************************/
1962
1963
/*Preliminary implementation to speed up FpX_ffisom*/
1964
typedef struct {
1965
GEN S, T;
1966
ulong p;
1967
} FlxYqq_muldata;
1968
1969
/* reduce x in Fl[X, Y] in the algebra Fl[X, Y]/ (P(X),Q(Y)) */
1970
static GEN
1971
FlxYqq_redswap(GEN x, GEN S, GEN T, ulong p)
1972
{
1973
pari_sp ltop=avma;
1974
long n = get_Flx_degree(S);
1975
long m = get_Flx_degree(T);
1976
long w = get_Flx_var(T);
1977
GEN V = FlxX_swap(x,m,w);
1978
V = FlxqX_red(V,S,p);
1979
V = FlxX_swap(V,n,w);
1980
return gerepilecopy(ltop,V);
1981
}
1982
static GEN
1983
FlxYqq_sqr(void *data, GEN x)
1984
{
1985
FlxYqq_muldata *D = (FlxYqq_muldata*)data;
1986
return FlxYqq_redswap(FlxqX_sqr(x, D->T, D->p),D->S,D->T,D->p);
1987
}
1988
1989
static GEN
1990
FlxYqq_mul(void *data, GEN x, GEN y)
1991
{
1992
FlxYqq_muldata *D = (FlxYqq_muldata*)data;
1993
return FlxYqq_redswap(FlxqX_mul(x,y, D->T, D->p),D->S,D->T,D->p);
1994
}
1995
1996
/* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */
1997
GEN
1998
FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p)
1999
{
2000
FlxYqq_muldata D;
2001
D.S = S;
2002
D.T = T;
2003
D.p = p;
2004
return gen_pow(x, n, (void*)&D, &FlxYqq_sqr, &FlxYqq_mul);
2005
}
2006
2007
/*******************************************************************/
2008
/* */
2009
/* FlxqXn */
2010
/* */
2011
/*******************************************************************/
2012
2013
GEN
2014
FlxXn_red(GEN a, long n)
2015
{
2016
long i, L = n+2, l = lg(a);
2017
GEN b;
2018
if (L >= l) return a; /* deg(x) < n */
2019
b = cgetg(L, t_POL); b[1] = a[1];
2020
for (i=2; i<L; i++) gel(b,i) = gel(a,i);
2021
return FlxX_renormalize(b,L);
2022
}
2023
2024
GEN
2025
FlxqXn_mul(GEN a, GEN b, long n, GEN T, ulong p)
2026
{ return FlxXn_red(FlxqX_mul(a, b, T, p), n); }
2027
2028
GEN
2029
FlxqXn_sqr(GEN a, long n, GEN T, ulong p)
2030
{ return FlxXn_red(FlxqX_sqr(a, T, p), n); }
2031
2032
/* (f*g) \/ x^n */
2033
static GEN
2034
FlxqX_mulhigh_i(GEN f, GEN g, long n, GEN T, ulong p)
2035
{
2036
return FlxX_shift(FlxqX_mul(f, g, T, p), -n , get_Flx_var(T));
2037
}
2038
2039
static GEN
2040
FlxqXn_mulhigh(GEN f, GEN g, long n2, long n, GEN T, ulong p)
2041
{
2042
long vT = get_Flx_var(T);
2043
GEN F = FlxX_blocks(f, n2, 2, vT), fl = gel(F,1), fh = gel(F,2);
2044
return FlxX_add(FlxqX_mulhigh_i(fl, g, n2, T, p),
2045
FlxqXn_mul(fh, g, n - n2, T, p), p);
2046
}
2047
2048
GEN
2049
FlxqXn_inv(GEN f, long e, GEN T, ulong p)
2050
{
2051
pari_sp av = avma, av2;
2052
ulong mask;
2053
GEN W, a;
2054
long v = varn(f), n = 1, vT = get_Flx_var(T);
2055
2056
if (!signe(f)) pari_err_INV("FlxqXn_inv",f);
2057
a = Flxq_inv(gel(f,2), T, p);
2058
if (e == 1) return scalarpol(a, v);
2059
else if (e == 2)
2060
{
2061
GEN b;
2062
if (degpol(f) <= 0) return scalarpol(a, v);
2063
b = Flx_neg(gel(f,3), p);
2064
if (lgpol(b)==0) return scalarpol(a, v);
2065
b = Flxq_mul(b, Flxq_sqr(a, T, p), T, p);
2066
W = deg1pol_shallow(b, a, v);
2067
return gerepilecopy(av, W);
2068
}
2069
W = scalarpol_shallow(Flxq_inv(gel(f,2), T, p),v);
2070
mask = quadratic_prec_mask(e);
2071
av2 = avma;
2072
for (;mask>1;)
2073
{
2074
GEN u, fr;
2075
long n2 = n;
2076
n<<=1; if (mask & 1) n--;
2077
mask >>= 1;
2078
fr = FlxXn_red(f, n);
2079
u = FlxqXn_mul(W, FlxqXn_mulhigh(fr, W, n2, n, T, p), n-n2, T, p);
2080
W = FlxX_sub(W, FlxX_shift(u, n2, vT), p);
2081
if (gc_needed(av2,2))
2082
{
2083
if(DEBUGMEM>1) pari_warn(warnmem,"FlxqXn_inv, e = %ld", n);
2084
W = gerepileupto(av2, W);
2085
}
2086
}
2087
return gerepileupto(av, W);
2088
}
2089
2090
/* Compute intformal(x^n*S)/x^(n+1) */
2091
static GEN
2092
FlxX_integXn(GEN x, long n, ulong p)
2093
{
2094
long i, lx = lg(x);
2095
GEN y;
2096
if (lx == 2) return gcopy(x);
2097
y = cgetg(lx, t_POL); y[1] = x[1];
2098
for (i=2; i<lx; i++)
2099
{
2100
GEN xi = gel(x,i);
2101
gel(y,i) = Flx_Fl_mul(xi, Fl_inv((n+i-1)%p, p), p);
2102
}
2103
return FlxX_renormalize(y, lx);;
2104
}
2105
2106
GEN
2107
FlxqXn_expint(GEN h, long e, GEN T, ulong p)
2108
{
2109
pari_sp av = avma, av2;
2110
long v = varn(h), n = 1, vT = get_Flx_var(T);
2111
GEN f = pol1_FlxX(v, vT), g = pol1_FlxX(v, vT);
2112
ulong mask = quadratic_prec_mask(e);
2113
av2 = avma;
2114
for (;mask>1;)
2115
{
2116
GEN u, w;
2117
long n2 = n;
2118
n<<=1; if (mask & 1) n--;
2119
mask >>= 1;
2120
u = FlxqXn_mul(g, FlxqX_mulhigh_i(f, FlxXn_red(h, n2-1), n2-1, T, p), n-n2, T, p);
2121
u = FlxX_add(u, FlxX_shift(FlxXn_red(h, n-1), 1-n2, vT), p);
2122
w = FlxqXn_mul(f, FlxX_integXn(u, n2-1, p), n-n2, T, p);
2123
f = FlxX_add(f, FlxX_shift(w, n2, vT), p);
2124
if (mask<=1) break;
2125
u = FlxqXn_mul(g, FlxqXn_mulhigh(f, g, n2, n, T, p), n-n2, T, p);
2126
g = FlxX_sub(g, FlxX_shift(u, n2, vT), p);
2127
if (gc_needed(av2,2))
2128
{
2129
if (DEBUGMEM>1) pari_warn(warnmem,"FlxqXn_exp, e = %ld", n);
2130
gerepileall(av2, 2, &f, &g);
2131
}
2132
}
2133
return gerepileupto(av, f);
2134
}
2135
2136