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) 2016 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
#define DEBUGLEVEL DEBUGLEVEL_factorff
19
20
/*******************************************************************/
21
/** **/
22
/** Isomorphisms between finite fields **/
23
/** **/
24
/*******************************************************************/
25
static void
26
err_Flxq(const char *s, GEN P, ulong l)
27
{
28
if (!uisprime(l)) pari_err_PRIME(s, utoi(l));
29
pari_err_IRREDPOL(s, Flx_to_ZX(get_Flx_mod(P)));
30
}
31
static void
32
err_FpXQ(const char *s, GEN P, GEN l)
33
{
34
if (!BPSW_psp(l)) pari_err_PRIME(s, l);
35
pari_err_IRREDPOL(s, get_FpX_mod(P));
36
}
37
38
/* compute the reciprocical isomorphism of S mod T,p, i.e. V such that
39
V(S)=X mod T,p*/
40
GEN
41
Flxq_ffisom_inv(GEN S,GEN T, ulong p)
42
{
43
pari_sp ltop = avma;
44
long n = get_Flx_degree(T);
45
GEN M = Flxq_matrix_pow(S,n,n,T,p);
46
GEN V = Flm_Flc_invimage(M, vecsmall_ei(n, 2), p);
47
if (!V) err_Flxq("Flxq_ffisom_inv", T, p);
48
return gerepileupto(ltop, Flv_to_Flx(V, get_Flx_var(T)));
49
}
50
51
GEN
52
FpXQ_ffisom_inv(GEN S,GEN T, GEN p)
53
{
54
pari_sp ltop = avma;
55
long n = get_FpX_degree(T);
56
GEN M = FpXQ_matrix_pow(S,n,n,T,p);
57
GEN V = FpM_FpC_invimage(M, col_ei(n, 2), p);
58
if (!V) err_FpXQ("Flxq_ffisom_inv", T, p);
59
return gerepilecopy(ltop, RgV_to_RgX(V, get_FpX_var(T)));
60
}
61
62
/* Let M the matrix of the Frobenius automorphism of Fp[X]/(T). Compute M^d
63
* TODO: use left-right binary (tricky!) */
64
GEN
65
Flm_Frobenius_pow(GEN M, long d, GEN T, ulong p)
66
{
67
pari_sp ltop=avma;
68
long i,l = get_Flx_degree(T);
69
GEN R, W = gel(M,2);
70
for (i = 2; i <= d; ++i) W = Flm_Flc_mul(M,W,p);
71
R=Flxq_matrix_pow(Flv_to_Flx(W,get_Flx_var(T)),l,l,T,p);
72
return gerepileupto(ltop,R);
73
}
74
75
GEN
76
FpM_Frobenius_pow(GEN M, long d, GEN T, GEN p)
77
{
78
pari_sp ltop=avma;
79
long i,l = get_FpX_degree(T);
80
GEN R, W = gel(M,2);
81
for (i = 2; i <= d; ++i) W = FpM_FpC_mul(M,W,p);
82
R=FpXQ_matrix_pow(RgV_to_RgX(W, get_FpX_var(T)),l,l,T,p);
83
return gerepilecopy(ltop,R);
84
}
85
86
/* Essentially we want to compute FqM_ker(MA-pol_x(v),U,l)
87
* To avoid use of matrix in Fq we compute FpM_ker(U(MA),l) then recover the
88
* eigenvalue by Galois action */
89
static GEN
90
Flx_Flm_Flc_eval(GEN U, GEN MA, GEN a, ulong p)
91
{
92
long i, l = lg(U);
93
GEN b = Flv_Fl_mul(a, uel(U, l-1), p);
94
for (i=l-2; i>=2; i--)
95
b = Flv_add(Flm_Flc_mul(MA, b, p), Flv_Fl_mul(a, uel(U, i), p), p);
96
return b;
97
}
98
99
static GEN
100
Flx_intersect_ker(GEN P, GEN MA, GEN U, ulong p)
101
{
102
pari_sp ltop = avma;
103
long i, vp = get_Flx_var(P), vu = get_Flx_var(U), r = get_Flx_degree(U);
104
GEN V, A, R;
105
ulong ib0;
106
pari_timer T;
107
if (DEBUGLEVEL>=4) timer_start(&T);
108
V = Flx_div(Flx_Fl_add(monomial_Flx(1, get_Flx_degree(P), vu), p-1, p), U, p);
109
do
110
{
111
A = Flx_Flm_Flc_eval(V, MA, random_Flv(lg(MA)-1, p), p);
112
} while (zv_equal0(A));
113
if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo");
114
/*The formula is
115
* a_{r-1} = -\phi(a_0)/b_0
116
* a_{i-1} = \phi(a_i)+b_ia_{r-1} i=r-1 to 1
117
* Where a_0=A[1] and b_i=U[i+2] */
118
ib0 = Fl_inv(Fl_neg(U[2], p), p);
119
R = cgetg(r+1,t_MAT);
120
gel(R,1) = A;
121
gel(R,r) = Flm_Flc_mul(MA, Flv_Fl_mul(A,ib0, p), p);
122
for(i=r-1; i>1; i--)
123
{
124
gel(R,i) = Flm_Flc_mul(MA,gel(R,i+1),p);
125
Flv_add_inplace(gel(R,i), Flv_Fl_mul(gel(R,r), U[i+2], p), p);
126
}
127
return gerepileupto(ltop, Flm_to_FlxX(Flm_transpose(R),vp,vu));
128
}
129
130
static GEN
131
FpX_FpM_FpC_eval(GEN U, GEN MA, GEN a, GEN p)
132
{
133
long i, l = lg(U);
134
GEN b = FpC_Fp_mul(a, gel(U, l-1), p);
135
for (i=l-2; i>=2; i--)
136
b = FpC_add(FpM_FpC_mul(MA, b, p), FpC_Fp_mul(a, gel(U, i), p), p);
137
return b;
138
}
139
140
static GEN
141
FpX_intersect_ker(GEN P, GEN MA, GEN U, GEN l)
142
{
143
pari_sp ltop = avma;
144
long i, vp = get_FpX_var(P), vu = get_FpX_var(U), r = get_FpX_degree(U);
145
GEN V, A, R, ib0;
146
pari_timer T;
147
if (DEBUGLEVEL>=4) timer_start(&T);
148
V = FpX_div(FpX_Fp_sub(pol_xn(get_FpX_degree(P), vu), gen_1, l), U, l);
149
do
150
{
151
A = FpX_FpM_FpC_eval(V, MA, random_FpC(lg(MA)-1, l), l);
152
} while (ZV_equal0(A));
153
if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo");
154
/*The formula is
155
* a_{r-1} = -\phi(a_0)/b_0
156
* a_{i-1} = \phi(a_i)+b_ia_{r-1} i=r-1 to 1
157
* Where a_0=A[1] and b_i=U[i+2] */
158
ib0 = Fp_inv(negi(gel(U,2)),l);
159
R = cgetg(r+1,t_MAT);
160
gel(R,1) = A;
161
gel(R,r) = FpM_FpC_mul(MA, FpC_Fp_mul(A,ib0,l), l);
162
for(i=r-1;i>1;i--)
163
gel(R,i) = FpC_add(FpM_FpC_mul(MA,gel(R,i+1),l),
164
FpC_Fp_mul(gel(R,r), gel(U,i+2), l),l);
165
return gerepilecopy(ltop,RgM_to_RgXX(shallowtrans(R),vp,vu));
166
}
167
168
/* n must divide both the degree of P and Q. Compute SP and SQ such
169
* that the subfield of FF_l[X]/(P) generated by SP and the subfield of
170
* FF_l[X]/(Q) generated by SQ are isomorphic of degree n. P and Q do
171
* not need to be of the same variable; if MA, resp. MB, is not NULL, must be
172
* the matrix of the Frobenius map in FF_l[X]/(P), resp. FF_l[X]/(Q).
173
* Implementation choice: we assume the prime p is large so we handle
174
* Frobenius as matrices. */
175
void
176
Flx_ffintersect(GEN P, GEN Q, long n, ulong l,GEN *SP, GEN *SQ, GEN MA, GEN MB)
177
{
178
pari_sp ltop = avma;
179
long vp = get_Flx_var(P), vq = get_Flx_var(Q);
180
long np = get_Flx_degree(P), nq = get_Flx_degree(Q), e;
181
ulong pg;
182
GEN A, B, Ap, Bp;
183
if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P);
184
if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q);
185
if (n<=0 || np%n || nq%n)
186
pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n));
187
e = u_lvalrem(n, l, &pg);
188
if(!MA) MA = Flx_matFrobenius(P,l);
189
if(!MB) MB = Flx_matFrobenius(Q,l);
190
A = Ap = pol0_Flx(vp);
191
B = Bp = pol0_Flx(vq);
192
if (pg > 1)
193
{
194
pari_timer T;
195
GEN ipg = utoipos(pg);
196
if (l%pg == 1)
197
{ /* more efficient special case */
198
ulong L, z, An, Bn;
199
z = Fl_neg(rootsof1_Fl(pg, l), l);
200
if (DEBUGLEVEL>=4) timer_start(&T);
201
A = Flm_ker(Flm_Fl_add(MA, z, l),l);
202
if (lg(A)!=2) err_Flxq("FpX_ffintersect",P,l);
203
A = Flv_to_Flx(gel(A,1),vp);
204
205
B = Flm_ker(Flm_Fl_add(MB, z, l),l);
206
if (lg(B)!=2) err_Flxq("FpX_ffintersect",Q,l);
207
B = Flv_to_Flx(gel(B,1),vq);
208
209
if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker");
210
An = Flxq_powu(A,pg,P,l)[2];
211
Bn = Flxq_powu(B,pg,Q,l)[2];
212
if (!Bn) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
213
z = Fl_div(An,Bn,l);
214
L = Fl_sqrtn(z, pg, l, NULL);
215
if (L==ULONG_MAX) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
216
if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn");
217
B = Flx_Fl_mul(B,L,l);
218
}
219
else
220
{
221
GEN L, An, Bn, z, U;
222
U = gmael(Flx_factor(ZX_to_Flx(polcyclo(pg, fetch_var()),l),l),1,1);
223
A = Flx_intersect_ker(P, MA, U, l);
224
B = Flx_intersect_ker(Q, MB, U, l);
225
if (DEBUGLEVEL>=4) timer_start(&T);
226
An = gel(FlxYqq_pow(A,ipg,P,U,l),2);
227
Bn = gel(FlxYqq_pow(B,ipg,Q,U,l),2);
228
if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]");
229
z = Flxq_div(An,Bn,U,l);
230
L = Flxq_sqrtn(z,ipg,U,l,NULL);
231
if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
232
if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn");
233
B = FlxqX_Flxq_mul(B,L,U,l);
234
A = FlxY_evalx(A,0,l);
235
B = FlxY_evalx(B,0,l);
236
(void)delete_var();
237
}
238
}
239
if (e)
240
{
241
GEN VP, VQ, Ay, By;
242
ulong lmun = l-1;
243
long j;
244
MA = Flm_Fl_add(MA,lmun,l);
245
MB = Flm_Fl_add(MB,lmun,l);
246
Ay = pol1_Flx(vp);
247
By = pol1_Flx(vq);
248
VP = vecsmall_ei(np, 1);
249
VQ = np == nq? VP: vecsmall_ei(nq, 1); /* save memory */
250
for(j=0;j<e;j++)
251
{
252
if (j)
253
{
254
Ay = Flxq_mul(Ay,Flxq_powu(Ap,lmun,P,l),P,l);
255
VP = Flx_to_Flv(Ay,np);
256
}
257
Ap = Flm_Flc_invimage(MA,VP,l);
258
if (!Ap) err_Flxq("FpX_ffintersect",P,l);
259
Ap = Flv_to_Flx(Ap,vp);
260
261
if (j)
262
{
263
By = Flxq_mul(By,Flxq_powu(Bp,lmun,Q,l),Q,l);
264
VQ = Flx_to_Flv(By,nq);
265
}
266
Bp = Flm_Flc_invimage(MB,VQ,l);
267
if (!Bp) err_Flxq("FpX_ffintersect",Q,l);
268
Bp = Flv_to_Flx(Bp,vq);
269
}
270
}
271
*SP = Flx_add(A,Ap,l);
272
*SQ = Flx_add(B,Bp,l);
273
gerepileall(ltop,2,SP,SQ);
274
}
275
276
/* Let l be a prime number, P, Q in Z[X]; both are irreducible modulo l and
277
* degree(P) divides degree(Q). Output a monomorphism between F_l[X]/(P) and
278
* F_l[X]/(Q) as a polynomial R such that Q | P(R) mod l. If P and Q have the
279
* same degree, it is of course an isomorphism. */
280
GEN
281
Flx_ffisom(GEN P,GEN Q,ulong l)
282
{
283
pari_sp av = avma;
284
GEN SP, SQ, R;
285
Flx_ffintersect(P,Q,get_Flx_degree(P),l,&SP,&SQ,NULL,NULL);
286
R = Flxq_ffisom_inv(SP,P,l);
287
return gerepileupto(av, Flx_Flxq_eval(R,SQ,Q,l));
288
}
289
290
void
291
FpX_ffintersect(GEN P, GEN Q, long n, GEN l, GEN *SP, GEN *SQ, GEN MA, GEN MB)
292
{
293
pari_sp ltop = avma;
294
long vp, vq, np, nq, e;
295
ulong pg;
296
GEN A, B, Ap, Bp;
297
if (lgefint(l)==3)
298
{
299
ulong pp = l[2];
300
GEN Pp = ZX_to_Flx(P,pp), Qp = ZX_to_Flx(Q,pp);
301
GEN MAp = MA ? ZM_to_Flm(MA, pp): NULL;
302
GEN MBp = MB ? ZM_to_Flm(MB, pp): NULL;
303
Flx_ffintersect(Pp, Qp, n, pp, SP, SQ, MAp, MBp);
304
*SP = Flx_to_ZX(*SP); *SQ = Flx_to_ZX(*SQ);
305
gerepileall(ltop,2,SP,SQ);
306
return;
307
}
308
vp = get_FpX_var(P); np = get_FpX_degree(P);
309
vq = get_FpX_var(Q); nq = get_FpX_degree(Q);
310
if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P);
311
if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q);
312
if (n<=0 || np%n || nq%n)
313
pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n));
314
e = u_pvalrem(n, l, &pg);
315
if(!MA) MA = FpX_matFrobenius(P, l);
316
if(!MB) MB = FpX_matFrobenius(Q, l);
317
A = Ap = pol_0(vp);
318
B = Bp = pol_0(vq);
319
if (pg > 1)
320
{
321
GEN ipg = utoipos(pg);
322
pari_timer T;
323
if (umodiu(l,pg) == 1)
324
/* No need to use relative extension, so don't. (Well, now we don't
325
* in the other case either, but this special case is more efficient) */
326
{
327
GEN L, An, Bn, z;
328
z = negi( rootsof1u_Fp(pg, l) );
329
if (DEBUGLEVEL>=4) timer_start(&T);
330
A = FpM_ker(RgM_Rg_add_shallow(MA, z),l);
331
if (lg(A)!=2) err_FpXQ("FpX_ffintersect",P,l);
332
A = RgV_to_RgX(gel(A,1),vp);
333
334
B = FpM_ker(RgM_Rg_add_shallow(MB, z),l);
335
if (lg(B)!=2) err_FpXQ("FpX_ffintersect",Q,l);
336
B = RgV_to_RgX(gel(B,1),vq);
337
338
if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker");
339
An = gel(FpXQ_pow(A,ipg,P,l),2);
340
Bn = gel(FpXQ_pow(B,ipg,Q,l),2);
341
if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
342
z = Fp_div(An,Bn,l);
343
L = Fp_sqrtn(z,ipg,l,NULL);
344
if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
345
if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn");
346
B = FpX_Fp_mul(B,L,l);
347
}
348
else
349
{
350
GEN L, An, Bn, z, U;
351
U = gmael(FpX_factor(polcyclo(pg,fetch_var()),l),1,1);
352
A = FpX_intersect_ker(P, MA, U, l);
353
B = FpX_intersect_ker(Q, MB, U, l);
354
if (DEBUGLEVEL>=4) timer_start(&T);
355
An = gel(FpXYQQ_pow(A,ipg,P,U,l),2);
356
Bn = gel(FpXYQQ_pow(B,ipg,Q,U,l),2);
357
if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]");
358
if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
359
z = Fq_div(An,Bn,U,l);
360
L = Fq_sqrtn(z,ipg,U,l,NULL);
361
if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
362
if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn");
363
B = FqX_Fq_mul(B,L,U,l);
364
A = FpXY_evalx(A,gen_0,l);
365
B = FpXY_evalx(B,gen_0,l);
366
(void)delete_var();
367
}
368
}
369
if (e)
370
{
371
GEN VP, VQ, Ay, By, lmun = subiu(l,1);
372
long j;
373
MA = RgM_Rg_add_shallow(MA,gen_m1);
374
MB = RgM_Rg_add_shallow(MB,gen_m1);
375
Ay = pol_1(vp);
376
By = pol_1(vq);
377
VP = col_ei(np, 1);
378
VQ = np == nq? VP: col_ei(nq, 1); /* save memory */
379
for(j=0;j<e;j++)
380
{
381
if (j)
382
{
383
Ay = FpXQ_mul(Ay,FpXQ_pow(Ap,lmun,P,l),P,l);
384
VP = RgX_to_RgC(Ay,np);
385
}
386
Ap = FpM_FpC_invimage(MA,VP,l);
387
if (!Ap) err_FpXQ("FpX_ffintersect",P,l);
388
Ap = RgV_to_RgX(Ap,vp);
389
390
if (j)
391
{
392
By = FpXQ_mul(By,FpXQ_pow(Bp,lmun,Q,l),Q,l);
393
VQ = RgX_to_RgC(By,nq);
394
}
395
Bp = FpM_FpC_invimage(MB,VQ,l);
396
if (!Bp) err_FpXQ("FpX_ffintersect",Q,l);
397
Bp = RgV_to_RgX(Bp,vq);
398
}
399
}
400
*SP = FpX_add(A,Ap,l);
401
*SQ = FpX_add(B,Bp,l);
402
gerepileall(ltop,2,SP,SQ);
403
}
404
/* Let l be a prime number, P, Q in Z[X]; both are irreducible modulo l and
405
* degree(P) divides degree(Q). Output a monomorphism between F_l[X]/(P) and
406
* F_l[X]/(Q) as a polynomial R such that Q | P(R) mod l. If P and Q have the
407
* same degree, it is of course an isomorphism. */
408
GEN
409
FpX_ffisom(GEN P, GEN Q, GEN p)
410
{
411
pari_sp av = avma;
412
GEN SP, SQ, R;
413
if (lgefint(p)==3)
414
{
415
ulong pp = p[2];
416
GEN R = Flx_ffisom(ZX_to_Flx(P,pp), ZX_to_Flx(Q,pp), pp);
417
return gerepileupto(av, Flx_to_ZX(R));
418
}
419
FpX_ffintersect(P,Q,get_FpX_degree(P),p,&SP,&SQ,NULL,NULL);
420
R = FpXQ_ffisom_inv(SP,P,p);
421
return gerepileupto(av, FpX_FpXQ_eval(R,SQ,Q,p));
422
}
423
424
/* Let l be a prime number, P a ZX irreducible modulo l, MP the matrix of the
425
* Frobenius automorphism of F_l[X]/(P).
426
* Factor P over the subfield of F_l[X]/(P) of index d. */
427
static GEN
428
FpX_factorgalois(GEN P, GEN l, long d, long w, GEN MP)
429
{
430
pari_sp ltop = avma;
431
GEN R, V, Tl, z, M;
432
long v = get_FpX_var(P), n = get_FpX_degree(P);
433
long k, m = n/d;
434
435
/* x - y */
436
if (m == 1) return deg1pol_shallow(gen_1, deg1pol_shallow(subis(l,1), gen_0, w), v);
437
M = FpM_Frobenius_pow(MP,d,P,l);
438
439
Tl = leafcopy(P); setvarn(Tl,w);
440
V = cgetg(m+1,t_VEC);
441
gel(V,1) = pol_x(w);
442
z = gel(M,2);
443
gel(V,2) = RgV_to_RgX(z,w);
444
for(k=3;k<=m;k++)
445
{
446
z = FpM_FpC_mul(M,z,l);
447
gel(V,k) = RgV_to_RgX(z,w);
448
}
449
R = FqV_roots_to_pol(V,Tl,l,v);
450
return gerepileupto(ltop,R);
451
}
452
/* same: P is an Flx, MP an Flm */
453
static GEN
454
Flx_factorgalois(GEN P, ulong l, long d, long w, GEN MP)
455
{
456
pari_sp ltop = avma;
457
GEN R, V, Tl, z, M;
458
long k, n = get_Flx_degree(P), m = n/d;
459
long v = get_Flx_var(P);
460
461
if (m == 1) {
462
R = polx_Flx(v);
463
gel(R,2) = z = polx_Flx(w); z[3] = l - 1; /* - y */
464
gel(R,3) = pol1_Flx(w);
465
return R; /* x - y */
466
}
467
M = Flm_Frobenius_pow(MP,d,P,l);
468
469
Tl = leafcopy(P); Tl[1] = w;
470
V = cgetg(m+1,t_VEC);
471
gel(V,1) = polx_Flx(w);
472
z = gel(M,2);
473
gel(V,2) = Flv_to_Flx(z,w);
474
for(k=3;k<=m;k++)
475
{
476
z = Flm_Flc_mul(M,z,l);
477
gel(V,k) = Flv_to_Flx(z,w);
478
}
479
R = FlxqV_roots_to_pol(V,Tl,l,v);
480
return gerepileupto(ltop,R);
481
}
482
483
GEN
484
Flx_factorff_irred(GEN P, GEN Q, ulong p)
485
{
486
pari_sp ltop = avma, av;
487
GEN SP, SQ, MP, MQ, M, FP, FQ, E, V, IR, res;
488
long np = get_Flx_degree(P), nq = get_Flx_degree(Q), d = ugcd(np,nq);
489
long i, vp = get_Flx_var(P), vq = get_Flx_var(Q);
490
if (d==1) retmkcol(Flx_to_FlxX(P, vq));
491
FQ = Flx_matFrobenius(Q,p);
492
av = avma;
493
FP = Flx_matFrobenius(P,p);
494
Flx_ffintersect(P,Q,d,p,&SP,&SQ, FP, FQ);
495
E = Flx_factorgalois(P,p,d,vq, FP);
496
E = FlxX_to_Flm(E,np);
497
MP= Flxq_matrix_pow(SP,np,d,P,p);
498
IR= gel(Flm_indexrank(MP,p),1);
499
E = rowpermute(E, IR);
500
M = rowpermute(MP,IR);
501
M = Flm_inv(M,p);
502
MQ= Flxq_matrix_pow(SQ,nq,d,Q,p);
503
M = Flm_mul(MQ,M,p);
504
M = Flm_mul(M,E,p);
505
M = gerepileupto(av,M);
506
V = cgetg(d+1,t_VEC);
507
gel(V,1) = M;
508
for(i=2;i<=d;i++)
509
gel(V,i) = Flm_mul(FQ,gel(V,i-1),p);
510
res = cgetg(d+1,t_COL);
511
for(i=1;i<=d;i++)
512
gel(res,i) = Flm_to_FlxX(gel(V,i),vp,vq);
513
return gerepileupto(ltop,res);
514
}
515
516
/* P,Q irreducible over F_p. Factor P over FF_p[X] / Q [factors are ordered as
517
* a Frobenius cycle] */
518
GEN
519
FpX_factorff_irred(GEN P, GEN Q, GEN p)
520
{
521
pari_sp ltop = avma, av;
522
GEN res;
523
long np = get_FpX_degree(P), nq = get_FpX_degree(Q), d = ugcd(np,nq);
524
if (d==1) return mkcolcopy(P);
525
526
if (lgefint(p)==3)
527
{
528
ulong pp = p[2];
529
GEN F = Flx_factorff_irred(ZX_to_Flx(P,pp), ZX_to_Flx(Q,pp), pp);
530
long i, lF = lg(F);
531
res = cgetg(lF, t_COL);
532
for(i=1; i<lF; i++)
533
gel(res,i) = FlxX_to_ZXX(gel(F,i));
534
}
535
else
536
{
537
GEN SP, SQ, MP, MQ, M, FP, FQ, E, V, IR;
538
long i, vp = get_FpX_var(P), vq = get_FpX_var(Q);
539
FQ = FpX_matFrobenius(Q,p);
540
av = avma;
541
FP = FpX_matFrobenius(P,p);
542
FpX_ffintersect(P,Q,d,p,&SP,&SQ,FP,FQ);
543
544
E = FpX_factorgalois(P,p,d,vq,FP);
545
E = RgXX_to_RgM(E,np);
546
MP= FpXQ_matrix_pow(SP,np,d,P,p);
547
IR= gel(FpM_indexrank(MP,p),1);
548
E = rowpermute(E, IR);
549
M = rowpermute(MP,IR);
550
M = FpM_inv(M,p);
551
MQ= FpXQ_matrix_pow(SQ,nq,d,Q,p);
552
M = FpM_mul(MQ,M,p);
553
M = FpM_mul(M,E,p);
554
M = gerepileupto(av,M);
555
V = cgetg(d+1,t_VEC);
556
gel(V,1) = M;
557
for(i=2;i<=d;i++)
558
gel(V,i) = FpM_mul(FQ,gel(V,i-1),p);
559
res = cgetg(d+1,t_COL);
560
for(i=1;i<=d;i++)
561
gel(res,i) = RgM_to_RgXX(gel(V,i),vp,vq);
562
}
563
return gerepilecopy(ltop,res);
564
}
565
566
/* not memory-clean, as Flx_factorff_i, returning only linear factors */
567
static GEN
568
Flx_rootsff_i(GEN P, GEN T, ulong p)
569
{
570
GEN V, F = gel(Flx_factor(P,p), 1);
571
long i, lfact = 1, nmax = lgpol(P), n = lg(F), dT = get_Flx_degree(T);
572
573
V = cgetg(nmax,t_COL);
574
for(i=1;i<n;i++)
575
{
576
GEN R, Fi = gel(F,i);
577
long di = degpol(Fi), j, r;
578
if (dT % di) continue;
579
R = Flx_factorff_irred(gel(F,i),T,p);
580
r = lg(R);
581
for (j=1; j<r; j++,lfact++)
582
gel(V,lfact) = Flx_neg(gmael(R,j, 2), p);
583
}
584
setlg(V,lfact);
585
gen_sort_inplace(V, (void*) &cmp_Flx, &cmp_nodata, NULL);
586
return V;
587
}
588
GEN
589
Flx_rootsff(GEN P, GEN T, ulong p)
590
{
591
pari_sp av = avma;
592
return gerepilecopy(av, Flx_rootsff_i(P, T, p));
593
}
594
595
/* dummy implementation */
596
static GEN
597
F2x_rootsff_i(GEN P, GEN T)
598
{
599
return FlxC_to_F2xC(Flx_rootsff_i(F2x_to_Flx(P), F2x_to_Flx(T), 2UL));
600
}
601
602
/* not memory-clean, as FpX_factorff_i, returning only linear factors */
603
static GEN
604
FpX_rootsff_i(GEN P, GEN T, GEN p)
605
{
606
GEN V, F;
607
long i, lfact, nmax, n, dT;
608
if (lgefint(p)==3)
609
{
610
ulong pp = p[2];
611
GEN V = Flx_rootsff_i(ZX_to_Flx(P,pp), ZXT_to_FlxT(T,pp), pp);
612
return FlxC_to_ZXC(V);
613
}
614
F = gel(FpX_factor(P,p), 1);
615
lfact = 1; nmax = lgpol(P); n = lg(F); dT = get_FpX_degree(T);
616
617
V = cgetg(nmax,t_COL);
618
for(i=1;i<n;i++)
619
{
620
GEN R, Fi = gel(F,i);
621
long di = degpol(Fi), j, r;
622
if (dT % di) continue;
623
R = FpX_factorff_irred(gel(F,i),T,p);
624
r = lg(R);
625
for (j=1; j<r; j++,lfact++)
626
gel(V,lfact) = Fq_to_FpXQ(Fq_neg(gmael(R,j, 2), T, p), T, p);
627
}
628
setlg(V,lfact);
629
gen_sort_inplace(V, (void*) &cmp_RgX, &cmp_nodata, NULL);
630
return V;
631
}
632
GEN
633
FpX_rootsff(GEN P, GEN T, GEN p)
634
{
635
pari_sp av = avma;
636
return gerepilecopy(av, FpX_rootsff_i(P, T, p));
637
}
638
639
static GEN
640
Flx_factorff_i(GEN P, GEN T, ulong p)
641
{
642
GEN V, E, F = Flx_factor(P, p);
643
long i, lfact = 1, nmax = lgpol(P), n = lgcols(F);
644
645
V = cgetg(nmax,t_VEC);
646
E = cgetg(nmax,t_VECSMALL);
647
for(i=1;i<n;i++)
648
{
649
GEN R = Flx_factorff_irred(gmael(F,1,i),T,p), e = gmael(F,2,i);
650
long j, r = lg(R);
651
for (j=1; j<r; j++,lfact++)
652
{
653
gel(V,lfact) = gel(R,j);
654
gel(E,lfact) = e;
655
}
656
}
657
setlg(V,lfact);
658
setlg(E,lfact); return sort_factor_pol(mkvec2(V,E), cmp_Flx);
659
}
660
661
static long
662
simpleff_to_nbfact(GEN F, long dT)
663
{
664
long i, l = lg(F), k = 0;
665
for (i = 1; i < l; i++) k += ugcd(uel(F,i), dT);
666
return k;
667
}
668
669
static long
670
Flx_nbfactff(GEN P, GEN T, ulong p)
671
{
672
pari_sp av = avma;
673
GEN F = gel(Flx_degfact(P, p), 1);
674
long s = simpleff_to_nbfact(F, get_Flx_degree(T));
675
return gc_long(av,s);
676
}
677
678
/* dummy implementation */
679
static GEN
680
F2x_factorff_i(GEN P, GEN T)
681
{
682
GEN M = Flx_factorff_i(F2x_to_Flx(P), F2x_to_Flx(T), 2);
683
return mkvec2(FlxXC_to_F2xXC(gel(M,1)), gel(M,2));
684
}
685
686
/* not memory-clean */
687
static GEN
688
FpX_factorff_i(GEN P, GEN T, GEN p)
689
{
690
GEN V, E, F = FpX_factor(P,p);
691
long i, lfact = 1, nmax = lgpol(P), n = lgcols(F);
692
693
V = cgetg(nmax,t_VEC);
694
E = cgetg(nmax,t_VECSMALL);
695
for(i=1;i<n;i++)
696
{
697
GEN R = FpX_factorff_irred(gmael(F,1,i),T,p), e = gmael(F,2,i);
698
long j, r = lg(R);
699
for (j=1; j<r; j++,lfact++)
700
{
701
gel(V,lfact) = gel(R,j);
702
gel(E,lfact) = e;
703
}
704
}
705
setlg(V,lfact);
706
setlg(E,lfact); return sort_factor_pol(mkvec2(V,E), cmp_RgX);
707
}
708
709
static long
710
FpX_nbfactff(GEN P, GEN T, GEN p)
711
{
712
pari_sp av = avma;
713
GEN F = gel(FpX_degfact(P, p), 1);
714
long s = simpleff_to_nbfact(F, get_FpX_degree(T));
715
return gc_long(av,s);
716
}
717
718
GEN
719
FpX_factorff(GEN P, GEN T, GEN p)
720
{
721
pari_sp av = avma;
722
return gerepilecopy(av, FpX_factorff_i(P, T, p));
723
}
724
725
/***********************************************************************/
726
/** **/
727
/** Factorisation over finite fields **/
728
/** **/
729
/***********************************************************************/
730
731
static GEN
732
FlxqXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, ulong p)
733
{
734
GEN ap2 = FlxqXQ_powu(a, p>>1, S, T, p);
735
GEN V = FlxqXQ_autsum(mkvec3(xp, Xp, ap2), get_Flx_degree(T), S, T, p);
736
return gel(V,3);
737
}
738
739
GEN
740
FlxqXQ_halfFrobenius(GEN a, GEN S, GEN T, ulong p)
741
{
742
long vT = get_Flx_var(T);
743
GEN xp, Xp;
744
T = Flx_get_red(T, p);
745
S = FlxqX_get_red(S, T, p);
746
xp = Flx_Frobenius(T, p);
747
Xp = FlxqXQ_powu(polx_FlxX(get_FlxqX_var(S), vT), p, S, T, p);
748
return FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p);
749
}
750
751
static GEN
752
FpXQXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, GEN p)
753
{
754
GEN ap2 = FpXQXQ_pow(a, shifti(p,-1), S, T, p);
755
GEN V = FpXQXQ_autsum(mkvec3(xp, Xp, ap2), get_FpX_degree(T), S, T, p);
756
return gel(V, 3);
757
}
758
759
GEN
760
FpXQXQ_halfFrobenius(GEN a, GEN S, GEN T, GEN p)
761
{
762
pari_sp av = avma;
763
GEN z;
764
if (lgefint(p)==3)
765
{
766
ulong pp = p[2];
767
long v = get_FpX_var(T);
768
GEN Tp = ZXT_to_FlxT(T,pp), Sp = ZXXT_to_FlxXT(S, pp, v);
769
z = FlxX_to_ZXX(FlxqXQ_halfFrobenius(ZXX_to_FlxX(a,pp,v),Sp,Tp,pp));
770
}
771
else
772
{
773
GEN xp, Xp;
774
T = FpX_get_red(T, p);
775
S = FpXQX_get_red(S, T, p);
776
xp = FpX_Frobenius(T, p);
777
Xp = FpXQXQ_pow(pol_x(get_FpXQX_var(S)), p, S, T, p);
778
z = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p);
779
}
780
return gerepilecopy(av, z);
781
}
782
783
static GEN
784
FlxqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, ulong p)
785
{
786
ulong dT = get_Flx_degree(T), df = get_FlxqX_degree(f);
787
GEN q = powuu(p,dT);
788
if (expi(q) >= expu(dT)*(long)usqrt(df))
789
return gel(FlxqXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2);
790
else
791
return FlxqXQ_pow(pol_x(get_FlxqX_var(f)), q, f, T, p);
792
}
793
794
GEN
795
FlxqX_Frobenius(GEN S, GEN T, ulong p)
796
{
797
pari_sp av = avma;
798
GEN X = polx_FlxX(get_FlxqX_var(S), get_Flx_var(T));
799
GEN xp = Flx_Frobenius(T, p);
800
GEN Xp = FlxqXQ_powu(X, p, S, T, p);
801
GEN Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p);
802
return gerepilecopy(av, Xq);
803
}
804
805
static GEN
806
FpXQXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, GEN p)
807
{
808
ulong dT = get_FpX_degree(T), df = get_FpXQX_degree(f);
809
GEN q = powiu(p, dT);
810
if (expi(q) >= expu(dT)*(long)usqrt(df))
811
return gel(FpXQXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2);
812
else
813
return FpXQXQ_pow(pol_x(get_FpXQX_var(f)), q, f, T, p);
814
}
815
816
GEN
817
FpXQX_Frobenius(GEN S, GEN T, GEN p)
818
{
819
pari_sp av = avma;
820
GEN X = pol_x(get_FpXQX_var(S));
821
GEN xp = FpX_Frobenius(T, p);
822
GEN Xp = FpXQXQ_pow(X, p, S, T, p);
823
GEN Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);
824
return gerepilecopy(av, Xq);
825
}
826
827
static GEN
828
F2xqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T)
829
{
830
ulong dT = get_F2x_degree(T), df = get_F2xqX_degree(f);
831
if (dT >= expu(dT)*usqrt(df))
832
return gel(F2xqXQ_autpow(mkvec2(xp, Xp), dT, f, T), 2);
833
else
834
{
835
long v = get_F2xqX_var(f), vT = get_F2x_var(T);
836
return F2xqXQ_pow(polx_F2xX(v,vT), int2n(dT), f, T);
837
}
838
}
839
840
static GEN
841
FlxqX_split_part(GEN f, GEN T, ulong p)
842
{
843
long n = degpol(f);
844
GEN z, Xq, X = polx_FlxX(varn(f),get_Flx_var(T));
845
if (n <= 1) return f;
846
f = FlxqX_red(f, T, p);
847
Xq = FlxqX_Frobenius(f, T, p);
848
z = FlxX_sub(Xq, X , p);
849
return FlxqX_gcd(z, f, T, p);
850
}
851
852
GEN
853
FpXQX_split_part(GEN f, GEN T, GEN p)
854
{
855
if(lgefint(p)==3)
856
{
857
ulong pp=p[2];
858
GEN Tp = ZXT_to_FlxT(T, pp);
859
GEN z = FlxqX_split_part(ZXX_to_FlxX(f, pp, get_Flx_var(T)), Tp, pp);
860
return FlxX_to_ZXX(z);
861
} else
862
{
863
long n = degpol(f);
864
GEN z, X = pol_x(varn(f));
865
if (n <= 1) return f;
866
f = FpXQX_red(f, T, p);
867
z = FpXQX_Frobenius(f, T, p);
868
z = FpXX_sub(z, X , p);
869
return FpXQX_gcd(z, f, T, p);
870
}
871
}
872
873
long
874
FpXQX_nbroots(GEN f, GEN T, GEN p)
875
{
876
pari_sp av = avma;
877
GEN z = FpXQX_split_part(f, T, p);
878
return gc_long(av, degpol(z));
879
}
880
881
long
882
FqX_nbroots(GEN f, GEN T, GEN p)
883
{ return T ? FpXQX_nbroots(f, T, p): FpX_nbroots(f, p); }
884
885
long
886
FlxqX_nbroots(GEN f, GEN T, ulong p)
887
{
888
pari_sp av = avma;
889
GEN z = FlxqX_split_part(f, T, p);
890
return gc_long(av, degpol(z));
891
}
892
893
static GEN
894
FlxqX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, ulong p)
895
{
896
long j, N = get_FlxqX_degree(S);
897
GEN Q = FlxqXQ_matrix_pow(Xq,N,N,S,T,p);
898
for (j=1; j<=N; j++)
899
gcoeff(Q,j,j) = Flx_Fl_add(gcoeff(Q,j,j), p-1, p);
900
return FlxqM_ker(Q,T,p);
901
}
902
903
static GEN
904
FpXQX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, GEN p)
905
{
906
long j,N = get_FpXQX_degree(S);
907
GEN Q = FpXQXQ_matrix_pow(Xq,N,N,S,T,p);
908
for (j=1; j<=N; j++)
909
gcoeff(Q,j,j) = Fq_sub(gcoeff(Q,j,j), gen_1, T, p);
910
return FqM_ker(Q,T,p);
911
}
912
913
static long
914
isabsolutepol(GEN f)
915
{
916
long i, l = lg(f);
917
for(i=2; i<l; i++)
918
{
919
GEN c = gel(f,i);
920
if (typ(c) == t_POL && degpol(c) > 0) return 0;
921
}
922
return 1;
923
}
924
925
#define set_irred(i) { if ((i)>ir) swap(t[i],t[ir]); ir++;}
926
927
static long
928
FlxqX_split_Berlekamp(GEN *t, GEN xp, GEN T, ulong p)
929
{
930
GEN u = *t, a,b,vker,pol;
931
long vu = varn(u), vT = get_Flx_var(T), dT = get_Flx_degree(T);
932
long d, i, ir, L, la, lb;
933
GEN S, X, Xp, Xq;
934
if (degpol(u)==1) return 1;
935
T = Flx_get_red(T, p);
936
S = FlxqX_get_red(u, T, p);
937
X = polx_FlxX(get_FlxqX_var(S),get_Flx_var(T));
938
Xp = FlxqXQ_powu(X, p, S, T, p);
939
Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p);
940
vker = FlxqX_Berlekamp_ker_i(Xq, S, T, p);
941
vker = Flm_to_FlxV(vker,u[1]);
942
d = lg(vker)-1;
943
ir = 0;
944
/* t[i] irreducible for i < ir, still to be treated for i < L */
945
for (L=1; L<d; )
946
{
947
pol= scalarpol(random_Flx(dT,vT,p),vu);
948
for (i=2; i<=d; i++)
949
pol = FlxX_add(pol, FlxqX_Flxq_mul(gel(vker,i),
950
random_Flx(dT,vT,p), T, p), p);
951
pol = FlxqX_red(pol,T,p);
952
for (i=ir; i<L && L<d; i++)
953
{
954
a = t[i]; la = degpol(a);
955
if (la == 1) { set_irred(i); }
956
else
957
{
958
pari_sp av = avma;
959
GEN S = FlxqX_get_red(a, T, p);
960
b = FlxqX_rem(pol, S, T,p);
961
if (degpol(b)<=0) { set_avma(av); continue; }
962
b = FlxqXQ_halfFrobenius_i(b, xp, FlxqX_rem(Xp, S, T, p), S, T, p);
963
if (degpol(b)<=0) { set_avma(av); continue; }
964
gel(b,2) = Flxq_sub(gel(b,2), gen_1,T,p);
965
b = FlxqX_gcd(a,b, T,p); lb = degpol(b);
966
if (lb && lb < la)
967
{
968
b = FlxqX_normalize(b, T,p);
969
t[L] = FlxqX_div(a,b,T,p);
970
t[i]= b; L++;
971
}
972
else set_avma(av);
973
}
974
}
975
}
976
return d;
977
}
978
979
static long
980
FpXQX_split_Berlekamp(GEN *t, GEN T, GEN p)
981
{
982
GEN u = *t, a, b, vker, pol;
983
GEN X, xp, Xp, Xq, S;
984
long vu = varn(u), vT = get_FpX_var(T), dT = get_FpX_degree(T);
985
long d, i, ir, L, la, lb;
986
if (degpol(u)==1) return 1;
987
T = FpX_get_red(T, p);
988
xp = FpX_Frobenius(T, p);
989
S = FpXQX_get_red(u, T, p);
990
X = pol_x(get_FpXQX_var(S));
991
Xp = FpXQXQ_pow(X, p, S, T, p);
992
Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);
993
vker = FpXQX_Berlekamp_ker_i(Xq, S, T, p);
994
vker = RgM_to_RgXV(vker,vu);
995
d = lg(vker)-1;
996
ir = 0;
997
/* t[i] irreducible for i < ir, still to be treated for i < L */
998
for (L=1; L<d; )
999
{
1000
pol= scalarpol(random_FpX(dT,vT,p),vu);
1001
for (i=2; i<=d; i++)
1002
pol = FqX_add(pol, FqX_Fq_mul(gel(vker,i),
1003
random_FpX(dT,vT,p), T, p), T, p);
1004
pol = FpXQX_red(pol,T,p);
1005
for (i=ir; i<L && L<d; i++)
1006
{
1007
a = t[i]; la = degpol(a);
1008
if (la == 1) { set_irred(i); }
1009
else
1010
{
1011
pari_sp av = avma;
1012
GEN S = FpXQX_get_red(a, T, p);
1013
b = FqX_rem(pol, S, T,p);
1014
if (degpol(b)<=0) { set_avma(av); continue; }
1015
b = FpXQXQ_halfFrobenius_i(b, xp, FpXQX_rem(Xp, S, T, p), S, T, p);
1016
if (degpol(b)<=0) { set_avma(av); continue; }
1017
gel(b,2) = Fq_sub(gel(b,2), gen_1,T,p);
1018
b = FqX_gcd(a,b, T,p); lb = degpol(b);
1019
if (lb && lb < la)
1020
{
1021
b = FpXQX_normalize(b, T,p);
1022
t[L] = FqX_div(a,b,T,p);
1023
t[i]= b; L++;
1024
}
1025
else set_avma(av);
1026
}
1027
}
1028
}
1029
return d;
1030
}
1031
1032
static GEN
1033
F2xqX_quad_roots(GEN P, GEN T)
1034
{
1035
GEN b= gel(P,3), c = gel(P,2);
1036
if (lgpol(b))
1037
{
1038
GEN z, d = F2xq_div(c, F2xq_sqr(b,T),T);
1039
if (F2xq_trace(d,T))
1040
return cgetg(1, t_COL);
1041
z = F2xq_mul(b, F2xq_Artin_Schreier(d, T), T);
1042
return mkcol2(z, F2x_add(b, z));
1043
}
1044
else
1045
return mkcol(F2xq_sqrt(c, T));
1046
}
1047
1048
/* Assume p>2 and x monic */
1049
static GEN
1050
FlxqX_quad_roots(GEN x, GEN T, ulong p)
1051
{
1052
GEN s, D, nb, b = gel(x,3), c = gel(x,2);
1053
D = Flx_sub(Flxq_sqr(b,T,p), Flx_mulu(c,4,p), p);
1054
nb = Flx_neg(b,p);
1055
if (lgpol(D)==0)
1056
return mkcol(Flx_halve(nb, p));
1057
s = Flxq_sqrt(D,T,p);
1058
if (!s) return cgetg(1, t_COL);
1059
s = Flx_halve(Flx_add(s,nb,p),p);
1060
return mkcol2(s, Flx_sub(nb,s,p));
1061
}
1062
1063
static GEN
1064
FpXQX_quad_roots(GEN x, GEN T, GEN p)
1065
{
1066
GEN s, D, nb, b = gel(x,3), c = gel(x,2);
1067
if (absequaliu(p, 2))
1068
{
1069
GEN f2 = ZXX_to_F2xX(x, get_FpX_var(T));
1070
s = F2xqX_quad_roots(f2, ZX_to_F2x(get_FpX_mod(T)));
1071
return F2xC_to_ZXC(s);
1072
}
1073
D = Fq_sub(Fq_sqr(b,T,p), Fq_Fp_mul(c,utoi(4),T,p), T,p);
1074
nb = Fq_neg(b,T,p);
1075
if (signe(D)==0)
1076
return mkcol(Fq_to_FpXQ(Fq_halve(nb,T, p),T,p));
1077
s = Fq_sqrt(D,T,p);
1078
if (!s) return cgetg(1, t_COL);
1079
s = Fq_halve(Fq_add(s,nb,T,p),T, p);
1080
return mkcol2(Fq_to_FpXQ(s,T,p), Fq_to_FpXQ(Fq_sub(nb,s,T,p),T,p));
1081
}
1082
1083
static GEN
1084
F2xqX_Frobenius_deflate(GEN S, GEN T)
1085
{
1086
GEN F = RgX_deflate(S, 2);
1087
long i, l = lg(F);
1088
for (i=2; i<l; i++)
1089
gel(F,i) = F2xq_sqrt(gel(F,i), T);
1090
return F;
1091
}
1092
1093
static GEN
1094
F2xX_to_F2x(GEN x)
1095
{
1096
long l=nbits2lg(lgpol(x));
1097
GEN z=cgetg(l,t_VECSMALL);
1098
long i,j,k;
1099
z[1]=x[1];
1100
for(i=2, k=1,j=BITS_IN_LONG;i<lg(x);i++,j++)
1101
{
1102
if (j==BITS_IN_LONG)
1103
{
1104
j=0; k++; z[k]=0;
1105
}
1106
if (lgpol(gel(x,i)))
1107
z[k]|=1UL<<j;
1108
}
1109
return F2x_renormalize(z,l);
1110
}
1111
1112
static GEN
1113
F2xqX_easyroots(GEN f, GEN T)
1114
{
1115
if (F2xY_degreex(f) <= 0) return F2x_rootsff_i(F2xX_to_F2x(f), T);
1116
if (degpol(f)==1) return mkcol(constant_coeff(f));
1117
if (degpol(f)==2) return F2xqX_quad_roots(f,T);
1118
return NULL;
1119
}
1120
1121
/* Adapted from Shoup NTL */
1122
GEN
1123
F2xqX_factor_squarefree(GEN f, GEN T)
1124
{
1125
pari_sp av = avma;
1126
GEN r, t, v, tv;
1127
long i, q, n = degpol(f);
1128
GEN u = const_vec(n+1, pol1_F2xX(varn(f), get_F2x_var(T)));
1129
for(q = 1;;q *= 2)
1130
{
1131
r = F2xqX_gcd(f, F2xX_deriv(f), T);
1132
if (degpol(r) == 0)
1133
{
1134
gel(u, q) = F2xqX_normalize(f, T);
1135
break;
1136
}
1137
t = F2xqX_div(f, r, T);
1138
if (degpol(t) > 0)
1139
{
1140
long j;
1141
for(j = 1;;j++)
1142
{
1143
v = F2xqX_gcd(r, t, T);
1144
tv = F2xqX_div(t, v, T);
1145
if (degpol(tv) > 0)
1146
gel(u, j*q) = F2xqX_normalize(tv, T);
1147
if (degpol(v) <= 0) break;
1148
r = F2xqX_div(r, v, T);
1149
t = v;
1150
}
1151
if (degpol(r) == 0) break;
1152
}
1153
f = F2xqX_Frobenius_deflate(r, T);
1154
}
1155
for (i = n; i; i--)
1156
if (degpol(gel(u,i))) break;
1157
setlg(u,i+1); return gerepilecopy(av, u);
1158
}
1159
1160
long
1161
F2xqX_ispower(GEN f, long k, GEN T, GEN *pt_r)
1162
{
1163
pari_sp av = avma;
1164
GEN lc, F;
1165
long i, l, n = degpol(f);
1166
if (n % k) return 0;
1167
lc = F2xq_sqrtn(leading_coeff(f), stoi(k), T, NULL);
1168
if (!lc) return gc_long(av,0);
1169
F = F2xqX_factor_squarefree(f, T); l = lg(F)-1;
1170
for(i=1; i<=l; i++)
1171
if (i%k && degpol(gel(F,i))) return gc_long(av,0);
1172
if (pt_r)
1173
{
1174
long v = varn(f);
1175
GEN r = scalarpol(lc, v), s = pol1_F2xX(v, T[1]);
1176
for(i=l; i>=1; i--)
1177
{
1178
if (i%k) continue;
1179
s = F2xqX_mul(s, gel(F,i), T);
1180
r = F2xqX_mul(r, s, T);
1181
}
1182
*pt_r = gerepileupto(av, r);
1183
} else set_avma(av);
1184
return 1;
1185
}
1186
1187
static void
1188
F2xqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN V, long idx)
1189
{
1190
pari_sp btop;
1191
long n = degpol(Sp);
1192
GEN S, f, ff;
1193
long dT = get_F2x_degree(T);
1194
GEN R = F2xqX_easyroots(Sp, T);
1195
if (R)
1196
{
1197
long i, l = lg(R)-1;
1198
for (i=0; i<l; i++)
1199
gel(V, idx+i) = gel(R,1+i);
1200
return;
1201
}
1202
S = F2xqX_get_red(Sp, T);
1203
Xp = F2xqX_rem(Xp, S, T);
1204
btop = avma;
1205
while (1)
1206
{
1207
GEN a = random_F2xqX(degpol(Sp), varn(Sp), T);
1208
GEN R = gel(F2xqXQ_auttrace(mkvec3(xp, Xp, a), dT, S, T), 3);
1209
f = F2xqX_gcd(R, Sp, T);
1210
if (degpol(f) > 0 && degpol(f) < n) break;
1211
set_avma(btop);
1212
}
1213
f = gerepileupto(btop, F2xqX_normalize(f, T));
1214
ff = F2xqX_div(Sp, f, T);
1215
F2xqX_roots_edf(f, xp, Xp, T, V, idx);
1216
F2xqX_roots_edf(ff,xp, Xp, T, V, idx+degpol(f));
1217
}
1218
1219
static GEN
1220
F2xqX_roots_ddf(GEN f, GEN xp, GEN T)
1221
{
1222
GEN X, Xp, Xq, g, V;
1223
long n;
1224
GEN R = F2xqX_easyroots(f, T);
1225
if (R) return R;
1226
X = pol_x(varn(f));
1227
Xp = F2xqXQ_sqr(X, f, T);
1228
Xq = F2xqXQ_Frobenius(xp, Xp, f, T);
1229
g = F2xqX_gcd(F2xX_add(Xq, X), f, T);
1230
n = degpol(g);
1231
if (n==0) return cgetg(1, t_COL);
1232
g = F2xqX_normalize(g, T);
1233
V = cgetg(n+1,t_COL);
1234
F2xqX_roots_edf(g, xp, Xp, T, V, 1);
1235
return V;
1236
}
1237
static GEN
1238
F2xqX_roots_i(GEN S, GEN T)
1239
{
1240
GEN M;
1241
S = F2xqX_red(S, T);
1242
if (!signe(S)) pari_err_ROOTS0("F2xqX_roots");
1243
if (degpol(S)==0) return cgetg(1, t_COL);
1244
S = F2xqX_normalize(S, T);
1245
M = F2xqX_easyroots(S, T);
1246
if (!M)
1247
{
1248
GEN xp = F2x_Frobenius(T);
1249
GEN F, V = F2xqX_factor_squarefree(S, T);
1250
long i, j, l = lg(V);
1251
F = cgetg(l, t_VEC);
1252
for (i=1, j=1; i < l; i++)
1253
if (degpol(gel(V,i)))
1254
gel(F, j++) = F2xqX_roots_ddf(gel(V,i), xp, T);
1255
setlg(F,j); M = shallowconcat1(F);
1256
}
1257
gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL);
1258
return M;
1259
}
1260
1261
static GEN
1262
FlxqX_easyroots(GEN f, GEN T, ulong p)
1263
{
1264
if (FlxY_degreex(f) <= 0) return Flx_rootsff_i(FlxX_to_Flx(f), T, p);
1265
if (degpol(f)==1) return mkcol(Flx_neg(constant_coeff(f), p));
1266
if (degpol(f)==2) return FlxqX_quad_roots(f,T,p);
1267
return NULL;
1268
}
1269
1270
static GEN
1271
FlxqX_invFrobenius(GEN xp, GEN T, ulong p)
1272
{
1273
return Flxq_autpow(xp, get_Flx_degree(T)-1, T, p);
1274
}
1275
1276
static GEN
1277
FlxqX_Frobenius_deflate(GEN S, GEN ixp, GEN T, ulong p)
1278
{
1279
GEN F = RgX_deflate(S, p);
1280
long i, l = lg(F);
1281
if (typ(ixp)==t_INT)
1282
for (i=2; i<l; i++)
1283
gel(F,i) = Flxq_pow(gel(F,i), ixp, T, p);
1284
else
1285
{
1286
long n = brent_kung_optpow(get_Flx_degree(T)-1, l-2, 1);
1287
GEN V = Flxq_powers(ixp, n, T, p);
1288
for (i=2; i<l; i++)
1289
gel(F,i) = Flx_FlxqV_eval(gel(F,i), V, T, p);
1290
}
1291
return F;
1292
}
1293
1294
/* Adapted from Shoup NTL */
1295
static GEN
1296
FlxqX_factor_squarefree_i(GEN f, GEN xp, GEN T, ulong p)
1297
{
1298
pari_sp av = avma;
1299
GEN r, t, v, tv;
1300
long i, q, n = degpol(f);
1301
GEN u = const_vec(n+1, pol1_FlxX(varn(f),get_Flx_var(T)));
1302
GEN ixp = NULL;
1303
for(q = 1;;q *= p)
1304
{
1305
r = FlxqX_gcd(f, FlxX_deriv(f, p), T, p);
1306
if (degpol(r) == 0)
1307
{
1308
gel(u, q) = FlxqX_normalize(f, T, p);
1309
break;
1310
}
1311
t = FlxqX_div(f, r, T, p);
1312
if (degpol(t) > 0)
1313
{
1314
long j;
1315
for(j = 1;;j++)
1316
{
1317
v = FlxqX_gcd(r, t, T, p);
1318
tv = FlxqX_div(t, v, T, p);
1319
if (degpol(tv) > 0)
1320
gel(u, j*q) = FlxqX_normalize(tv, T, p);
1321
if (degpol(v) <= 0) break;
1322
r = FlxqX_div(r, v, T, p);
1323
t = v;
1324
}
1325
if (degpol(r) == 0) break;
1326
}
1327
if (!xp) xp = Flx_Frobenius(T, p);
1328
if (!ixp) ixp = FlxqX_invFrobenius(xp, T, p);
1329
f = FlxqX_Frobenius_deflate(r, ixp, T, p);
1330
}
1331
for (i = n; i; i--)
1332
if (degpol(gel(u,i))) break;
1333
setlg(u,i+1); return gerepilecopy(av, u);
1334
}
1335
1336
GEN
1337
FlxqX_factor_squarefree(GEN f, GEN T, ulong p)
1338
{
1339
return FlxqX_factor_squarefree_i(f, NULL, T, p);
1340
}
1341
1342
long
1343
FlxqX_ispower(GEN f, ulong k, GEN T, ulong p, GEN *pt_r)
1344
{
1345
pari_sp av = avma;
1346
GEN lc, F;
1347
long i, l, n = degpol(f), v = varn(f);
1348
if (n % k) return 0;
1349
lc = Flxq_sqrtn(leading_coeff(f), stoi(k), T, p, NULL);
1350
if (!lc) return gc_long(av,0);
1351
F = FlxqX_factor_squarefree_i(f, NULL, T, p); l = lg(F)-1;
1352
for(i=1; i<=l; i++)
1353
if (i%k && degpol(gel(F,i))) return gc_long(av,0);
1354
if (pt_r)
1355
{
1356
GEN r = scalarpol(lc, v), s = pol1_FlxX(v, T[1]);
1357
for(i=l; i>=1; i--)
1358
{
1359
if (i%k) continue;
1360
s = FlxqX_mul(s, gel(F,i), T, p);
1361
r = FlxqX_mul(r, s, T, p);
1362
}
1363
*pt_r = gerepileupto(av, r);
1364
} else set_avma(av);
1365
return 1;
1366
}
1367
1368
static GEN
1369
FlxqX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, ulong p)
1370
{
1371
pari_sp btop = avma;
1372
long n = degpol(Sp);
1373
GEN f;
1374
long vT = get_Flx_var(T), dT = get_Flx_degree(T);
1375
pari_timer ti;
1376
if (DEBUGLEVEL >= 7) timer_start(&ti);
1377
while (1)
1378
{
1379
GEN a = deg1pol(pol1_Flx(vT), random_Flx(dT, vT, p), varn(Sp));
1380
GEN R = FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p);
1381
if (DEBUGLEVEL >= 7) timer_printf(&ti, "FlxqXQ_halfFrobenius");
1382
f = FlxqX_gcd(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p);
1383
if (degpol(f) > 0 && degpol(f) < n) break;
1384
set_avma(btop);
1385
}
1386
return gerepileupto(btop, FlxqX_normalize(f, T, p));
1387
}
1388
1389
static void
1390
FlxqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, ulong p, GEN V, long idx)
1391
{
1392
GEN S, f, ff;
1393
GEN R = FlxqX_easyroots(Sp, T, p);
1394
if (R)
1395
{
1396
long i, l = lg(R)-1;
1397
for (i=0; i<l; i++)
1398
gel(V, idx+i) = gel(R,1+i);
1399
return;
1400
}
1401
S = FlxqX_get_red(Sp, T, p);
1402
Xp = FlxqX_rem(Xp, S, T, p);
1403
f = FlxqX_roots_split(Sp, xp, Xp, S, T, p);
1404
ff = FlxqX_div(Sp, f, T, p);
1405
FlxqX_roots_edf(f, xp, Xp, T, p, V, idx);
1406
FlxqX_roots_edf(ff,xp, Xp, T, p, V, idx+degpol(f));
1407
}
1408
1409
static GEN
1410
FlxqX_roots_ddf(GEN f, GEN xp, GEN T, ulong p)
1411
{
1412
GEN X, Xp, Xq, g, V;
1413
long n;
1414
GEN R = FlxqX_easyroots(f, T, p);
1415
if (R) return R;
1416
X = pol_x(varn(f));
1417
Xp = FlxqXQ_powu(X, p, f, T, p);
1418
Xq = FlxqXQ_Frobenius(xp, Xp, f, T, p);
1419
g = FlxqX_gcd(FlxX_sub(Xq, X, p), f, T, p);
1420
n = degpol(g);
1421
if (n==0) return cgetg(1, t_COL);
1422
g = FlxqX_normalize(g, T, p);
1423
V = cgetg(n+1,t_COL);
1424
FlxqX_roots_edf(g, xp, Xp, T, p, V, 1);
1425
return V;
1426
}
1427
1428
/* do not handle p==2 */
1429
static GEN
1430
FlxqX_roots_i(GEN S, GEN T, ulong p)
1431
{
1432
GEN M;
1433
S = FlxqX_red(S, T, p);
1434
if (!signe(S)) pari_err_ROOTS0("FlxqX_roots");
1435
if (degpol(S)==0) return cgetg(1, t_COL);
1436
S = FlxqX_normalize(S, T, p);
1437
M = FlxqX_easyroots(S, T, p);
1438
if (!M)
1439
{
1440
GEN xp = Flx_Frobenius(T, p);
1441
GEN F, V = FlxqX_factor_squarefree_i(S, xp, T, p);
1442
long i, j, l = lg(V);
1443
F = cgetg(l, t_VEC);
1444
for (i=1, j=1; i < l; i++)
1445
if (degpol(gel(V,i)))
1446
gel(F, j++) = FlxqX_roots_ddf(gel(V,i), xp, T, p);
1447
setlg(F,j); M = shallowconcat1(F);
1448
}
1449
gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL);
1450
return M;
1451
}
1452
1453
static GEN
1454
FpXQX_easyroots(GEN f, GEN T, GEN p)
1455
{
1456
if (isabsolutepol(f)) return FpX_rootsff_i(simplify_shallow(f), T, p);
1457
if (degpol(f)==1) return mkcol(Fq_to_FpXQ(Fq_neg(constant_coeff(f),T,p),T,p));
1458
if (degpol(f)==2) return FpXQX_quad_roots(f,T,p);
1459
return NULL;
1460
}
1461
1462
/* Adapted from Shoup NTL */
1463
static GEN
1464
FpXQX_factor_Yun(GEN f, GEN T, GEN p)
1465
{
1466
pari_sp av = avma;
1467
GEN r, t, v, tv;
1468
long j, n = degpol(f);
1469
GEN u = const_vec(n+1, pol_1(varn(f)));
1470
r = FpXQX_gcd(f, FpXX_deriv(f, p), T, p);
1471
t = FpXQX_div(f, r, T, p);
1472
for (j = 1;;j++)
1473
{
1474
v = FpXQX_gcd(r, t, T, p);
1475
tv = FpXQX_div(t, v, T, p);
1476
if (degpol(tv) > 0)
1477
gel(u, j) = FpXQX_normalize(tv, T, p);
1478
if (degpol(v) <= 0) break;
1479
r = FpXQX_div(r, v, T, p);
1480
t = v;
1481
}
1482
setlg(u, j+1); return gerepilecopy(av, u);
1483
}
1484
1485
GEN
1486
FpXQX_factor_squarefree(GEN f, GEN T, GEN p)
1487
{
1488
if (lgefint(p)==3)
1489
{
1490
pari_sp av = avma;
1491
ulong pp = p[2];
1492
GEN M;
1493
long vT = get_FpX_var(T);
1494
if (pp==2)
1495
{
1496
M = F2xqX_factor_squarefree(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));
1497
return gerepileupto(av, F2xXC_to_ZXXC(M));
1498
}
1499
M = FlxqX_factor_squarefree(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);
1500
return gerepileupto(av, FlxXC_to_ZXXC(M));
1501
}
1502
return FpXQX_factor_Yun(f, T, p);
1503
}
1504
1505
long
1506
FpXQX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r)
1507
{
1508
pari_sp av = avma;
1509
GEN lc, F;
1510
long i, l, n = degpol(f), v = varn(f);
1511
if (n % k) return 0;
1512
if (lgefint(p)==3)
1513
{
1514
ulong pp = p[2];
1515
GEN fp = ZXX_to_FlxX(f, pp, varn(T));
1516
if (!FlxqX_ispower(fp, k, ZX_to_Flx(T,pp), pp, pt_r)) return gc_long(av,0);
1517
if (pt_r) *pt_r = gerepileupto(av, FlxX_to_ZXX(*pt_r));
1518
else set_avma(av);
1519
return 1;
1520
}
1521
lc = FpXQ_sqrtn(leading_coeff(f), stoi(k), T, p, NULL);
1522
if (!lc) return gc_long(av,0);
1523
F = FpXQX_factor_Yun(f, T, p); l = lg(F)-1;
1524
for(i=1; i <= l; i++)
1525
if (i%k && degpol(gel(F,i))) return gc_long(av,0);
1526
if (pt_r)
1527
{
1528
GEN r = scalarpol(lc, v), s = pol_1(v);
1529
for(i=l; i>=1; i--)
1530
{
1531
if (i%k) continue;
1532
s = FpXQX_mul(s, gel(F,i), T, p);
1533
r = FpXQX_mul(r, s, T, p);
1534
}
1535
*pt_r = gerepileupto(av, r);
1536
} else set_avma(av);
1537
return 1;
1538
}
1539
1540
long
1541
FqX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r)
1542
{ return T ? FpXQX_ispower(f, k, T, p, pt_r): FpX_ispower(f, k, p, pt_r); }
1543
1544
static GEN
1545
FpXQX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, GEN p)
1546
{
1547
pari_sp btop = avma;
1548
long n = degpol(Sp);
1549
GEN f;
1550
long vT = get_FpX_var(T), dT = get_FpX_degree(T);
1551
pari_timer ti;
1552
if (DEBUGLEVEL >= 7) timer_start(&ti);
1553
while (1)
1554
{
1555
GEN a = deg1pol(pol_1(vT), random_FpX(dT, vT, p), varn(Sp));
1556
GEN R = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p);
1557
if (DEBUGLEVEL >= 7) timer_printf(&ti, "FpXQXQ_halfFrobenius");
1558
f = FpXQX_gcd(FqX_Fq_sub(R, pol_1(vT), T, p), Sp, T, p);
1559
if (degpol(f) > 0 && degpol(f) < n) break;
1560
set_avma(btop);
1561
}
1562
return gerepileupto(btop, FpXQX_normalize(f, T, p));
1563
}
1564
1565
static void
1566
FpXQX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN p, GEN V, long idx)
1567
{
1568
GEN S, f, ff;
1569
GEN R = FpXQX_easyroots(Sp, T, p);
1570
if (R)
1571
{
1572
long i, l = lg(R)-1;
1573
for (i=0; i<l; i++)
1574
gel(V, idx+i) = gel(R,1+i);
1575
return;
1576
}
1577
S = FpXQX_get_red(Sp, T, p);
1578
Xp = FpXQX_rem(Xp, S, T, p);
1579
f = FpXQX_roots_split(Sp, xp, Xp, S, T, p);
1580
ff = FpXQX_div(Sp, f, T, p);
1581
FpXQX_roots_edf(f, xp, Xp, T, p, V, idx);
1582
FpXQX_roots_edf(ff,xp, Xp, T, p, V, idx+degpol(f));
1583
}
1584
1585
static GEN
1586
FpXQX_roots_ddf(GEN f, GEN xp, GEN T, GEN p)
1587
{
1588
GEN X, Xp, Xq, g, V;
1589
long n;
1590
GEN R = FpXQX_easyroots(f, T, p);
1591
if (R) return R;
1592
X = pol_x(varn(f));
1593
Xp = FpXQXQ_pow(X, p, f, T, p);
1594
Xq = FpXQXQ_Frobenius(xp, Xp, f, T, p);
1595
g = FpXQX_gcd(FpXX_sub(Xq, X, p), f, T, p);
1596
n = degpol(g);
1597
if (n==0) return cgetg(1, t_COL);
1598
g = FpXQX_normalize(g, T, p);
1599
V = cgetg(n+1,t_COL);
1600
FpXQX_roots_edf(g, xp, Xp, T, p, V, 1);
1601
return V;
1602
}
1603
1604
/* do not handle small p */
1605
static GEN
1606
FpXQX_roots_i(GEN S, GEN T, GEN p)
1607
{
1608
GEN F, M;
1609
if (lgefint(p)==3)
1610
{
1611
ulong pp = p[2];
1612
if (pp == 2)
1613
{
1614
GEN V = F2xqX_roots_i(ZXX_to_F2xX(S,get_FpX_var(T)), ZX_to_F2x(get_FpX_mod(T)));
1615
return F2xC_to_ZXC(V);
1616
}
1617
else
1618
{
1619
GEN V = FlxqX_roots_i(ZXX_to_FlxX(S,pp,get_FpX_var(T)), ZXT_to_FlxT(T,pp), pp);
1620
return FlxC_to_ZXC(V);
1621
}
1622
}
1623
S = FpXQX_red(S, T, p);
1624
if (!signe(S)) pari_err_ROOTS0("FpXQX_roots");
1625
if (degpol(S)==0) return cgetg(1, t_COL);
1626
S = FpXQX_normalize(S, T, p);
1627
M = FpXQX_easyroots(S, T, p);
1628
if (!M)
1629
{
1630
GEN xp = FpX_Frobenius(T, p);
1631
GEN V = FpXQX_factor_Yun(S, T, p);
1632
long i, j, l = lg(V);
1633
F = cgetg(l, t_VEC);
1634
for (i=1, j=1; i < l; i++)
1635
if (degpol(gel(V,i)))
1636
gel(F, j++) = FpXQX_roots_ddf(gel(V,i), xp, T, p);
1637
setlg(F,j); M = shallowconcat1(F);
1638
}
1639
gen_sort_inplace(M, (void*) &cmp_RgX, &cmp_nodata, NULL);
1640
return M;
1641
}
1642
1643
GEN
1644
F2xqX_roots(GEN x, GEN T)
1645
{
1646
pari_sp av = avma;
1647
return gerepilecopy(av, F2xqX_roots_i(x, T));
1648
}
1649
1650
GEN
1651
FlxqX_roots(GEN x, GEN T, ulong p)
1652
{
1653
pari_sp av = avma;
1654
if (p==2)
1655
{
1656
GEN V = F2xqX_roots_i(FlxX_to_F2xX(x), Flx_to_F2x(get_Flx_mod(T)));
1657
return gerepileupto(av, F2xC_to_FlxC(V));
1658
}
1659
return gerepilecopy(av, FlxqX_roots_i(x, T, p));
1660
}
1661
1662
GEN
1663
FpXQX_roots(GEN x, GEN T, GEN p)
1664
{
1665
pari_sp av = avma;
1666
return gerepilecopy(av, FpXQX_roots_i(x, T, p));
1667
}
1668
1669
static GEN
1670
FE_concat(GEN F, GEN E, long l)
1671
{
1672
setlg(E,l); E = shallowconcat1(E);
1673
setlg(F,l); F = shallowconcat1(F); return mkvec2(F,E);
1674
}
1675
1676
static GEN
1677
F2xqX_factor_2(GEN f, GEN T)
1678
{
1679
long v = varn(f), vT = get_F2x_var(T);
1680
GEN r = F2xqX_quad_roots(f, T);
1681
switch(lg(r)-1)
1682
{
1683
case 0:
1684
return mkvec2(mkcolcopy(f), mkvecsmall(1));
1685
case 1:
1686
return mkvec2(mkcol(deg1pol_shallow(pol1_F2x(vT), gel(r,1), v)), mkvecsmall(2));
1687
default: /* 2 */
1688
{
1689
GEN f1 = deg1pol_shallow(pol1_F2x(vT), gel(r,1), v);
1690
GEN f2 = deg1pol_shallow(pol1_F2x(vT), gel(r,2), v);
1691
GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);
1692
sort_factor_pol(mkvec2(t, E), cmp_Flx);
1693
return mkvec2(t, E);
1694
}
1695
}
1696
}
1697
1698
static GEN
1699
FlxqX_factor_2(GEN f, GEN T, ulong p)
1700
{
1701
long v = varn(f), vT = get_Flx_var(T);
1702
GEN r = FlxqX_quad_roots(f, T, p);
1703
switch(lg(r)-1)
1704
{
1705
case 0:
1706
return mkvec2(mkcolcopy(f), mkvecsmall(1));
1707
case 1:
1708
return mkvec2(mkcol(deg1pol_shallow(pol1_Flx(vT),
1709
Flx_neg(gel(r,1), p), v)), mkvecsmall(2));
1710
default: /* 2 */
1711
{
1712
GEN f1 = deg1pol_shallow(pol1_Flx(vT), Flx_neg(gel(r,1), p), v);
1713
GEN f2 = deg1pol_shallow(pol1_Flx(vT), Flx_neg(gel(r,2), p), v);
1714
GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);
1715
sort_factor_pol(mkvec2(t, E), cmp_Flx);
1716
return mkvec2(t, E);
1717
}
1718
}
1719
}
1720
1721
static GEN
1722
FpXQX_factor_2(GEN f, GEN T, GEN p)
1723
{
1724
long v = varn(f);
1725
GEN r = FpXQX_quad_roots(f, T, p);
1726
switch(lg(r)-1)
1727
{
1728
case 0:
1729
return mkvec2(mkcolcopy(f), mkvecsmall(1));
1730
case 1:
1731
return mkvec2(mkcol(deg1pol_shallow(gen_1, Fq_neg(gel(r,1), T, p), v)),
1732
mkvecsmall(2));
1733
default: /* 2 */
1734
{
1735
GEN f1 = deg1pol_shallow(gen_1, Fq_neg(gel(r,1), T, p), v);
1736
GEN f2 = deg1pol_shallow(gen_1, Fq_neg(gel(r,2), T, p), v);
1737
GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);
1738
sort_factor_pol(mkvec2(t, E), cmp_RgX);
1739
return mkvec2(t, E);
1740
}
1741
}
1742
}
1743
1744
static GEN
1745
F2xqX_ddf_Shoup(GEN S, GEN Xq, GEN T)
1746
{
1747
pari_sp av = avma;
1748
GEN b, g, h, F, f, Sr, xq;
1749
long i, j, n, v, vT, dT, bo, ro;
1750
long B, l, m;
1751
pari_timer ti;
1752
n = get_F2xqX_degree(S); v = get_F2xqX_var(S);
1753
vT = get_F2x_var(T); dT = get_F2x_degree(T);
1754
if (n == 0) return cgetg(1, t_VEC);
1755
if (n == 1) return mkvec(get_F2xqX_mod(S));
1756
B = n/2;
1757
l = usqrt(B);
1758
m = (B+l-1)/l;
1759
S = F2xqX_get_red(S, T);
1760
b = cgetg(l+2, t_VEC);
1761
gel(b, 1) = polx_F2xX(v, vT);
1762
gel(b, 2) = Xq;
1763
bo = brent_kung_optpow(n, l-1, 1);
1764
ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
1765
if (DEBUGLEVEL>=7) timer_start(&ti);
1766
if (dT <= ro)
1767
for (i = 3; i <= l+1; i++)
1768
gel(b, i) = F2xqXQ_pow(gel(b, i-1), int2n(dT), S, T);
1769
else
1770
{
1771
xq = F2xqXQ_powers(gel(b, 2), bo, S, T);
1772
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq baby");
1773
for (i = 3; i <= l+1; i++)
1774
gel(b, i) = F2xqX_F2xqXQV_eval(gel(b, i-1), xq, S, T);
1775
}
1776
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: baby");
1777
xq = F2xqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T);
1778
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq giant");
1779
g = cgetg(m+1, t_VEC);
1780
gel(g, 1) = gel(xq, 2);
1781
for(i = 2; i <= m; i++)
1782
gel(g, i) = F2xqX_F2xqXQV_eval(gel(g, i-1), xq, S, T);
1783
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: giant");
1784
h = cgetg(m+1, t_VEC);
1785
for (j = 1; j <= m; j++)
1786
{
1787
pari_sp av = avma;
1788
GEN gj = gel(g, j);
1789
GEN e = F2xX_add(gj, gel(b, 1));
1790
for (i = 2; i <= l; i++)
1791
e = F2xqXQ_mul(e, F2xX_add(gj, gel(b, i)), S, T);
1792
gel(h, j) = gerepileupto(av, e);
1793
}
1794
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: diff");
1795
Sr = get_F2xqX_mod(S);
1796
F = cgetg(m+1, t_VEC);
1797
for (j = 1; j <= m; j++)
1798
{
1799
GEN u = F2xqX_gcd(Sr, gel(h,j), T);
1800
if (degpol(u))
1801
{
1802
u = F2xqX_normalize(u, T);
1803
Sr = F2xqX_div(Sr, u, T);
1804
}
1805
gel(F,j) = u;
1806
}
1807
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: F");
1808
f = const_vec(n, pol1_F2xX(v, vT));
1809
for (j = 1; j <= m; j++)
1810
{
1811
GEN e = gel(F, j);
1812
for (i=l-1; i >= 0; i--)
1813
{
1814
GEN u = F2xqX_gcd(e, F2xX_add(gel(g, j), gel(b, i+1)), T);
1815
if (degpol(u))
1816
{
1817
gel(f, l*j-i) = u = F2xqX_normalize(u, T);
1818
e = F2xqX_div(e, u, T);
1819
}
1820
if (!degpol(e)) break;
1821
}
1822
}
1823
if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: f");
1824
if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;
1825
return gerepilecopy(av, f);
1826
}
1827
1828
static GEN
1829
F2xqX_ddf_i(GEN f, GEN T, GEN X, GEN xp)
1830
{
1831
GEN Xp, Xq;
1832
if (!get_F2xqX_degree(f)) return cgetg(1,t_VEC);
1833
f = F2xqX_get_red(f, T);
1834
Xp = F2xqXQ_sqr(X, f, T);
1835
Xq = F2xqXQ_Frobenius(xp, Xp, f, T);
1836
return F2xqX_ddf_Shoup(f, Xq, T);
1837
}
1838
static void
1839
F2xqX_ddf_init(GEN *S, GEN *T, GEN *xp, GEN *X)
1840
{
1841
*T = F2x_get_red(*T);
1842
*S = F2xqX_normalize(get_F2xqX_mod(*S), *T);
1843
*xp = F2x_Frobenius(*T);
1844
*X = polx_F2xX(get_F2xqX_var(*S), get_F2x_var(*T));
1845
}
1846
GEN
1847
F2xqX_degfact(GEN S, GEN T)
1848
{
1849
GEN xp, X, V;
1850
long i, l;
1851
F2xqX_ddf_init(&S,&T,&xp,&X);
1852
V = F2xqX_factor_squarefree(S, T); l = lg(V);
1853
for (i=1; i < l; i++) gel(V,i) = F2xqX_ddf_i(gel(V,i), T, X, xp);
1854
return vddf_to_simplefact(V, degpol(S));
1855
}
1856
GEN
1857
F2xqX_ddf(GEN S, GEN T)
1858
{
1859
GEN xp, X;
1860
F2xqX_ddf_init(&S,&T,&xp,&X);
1861
return ddf_to_ddf2( F2xqX_ddf_i(S, T, X, xp) );
1862
}
1863
1864
static void
1865
F2xqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Sq, long d, GEN T, GEN V, long idx)
1866
{
1867
long v = varn(Sp), n = degpol(Sp), r = n/d;
1868
GEN S, f, ff;
1869
long dT = get_F2x_degree(T);
1870
if (r==1) { gel(V, idx) = Sp; return; }
1871
S = F2xqX_get_red(Sp, T);
1872
Xp = F2xqX_rem(Xp, S, T);
1873
Sq = F2xqXQV_red(Sq, S, T);
1874
while (1)
1875
{
1876
pari_sp btop = avma;
1877
long l;
1878
GEN w0 = random_F2xqX(n, v, T), g = w0;
1879
for (l=1; l<d; l++) /* sum_{0<i<d} w^(q^i), result in (F_q)^r */
1880
g = F2xX_add(w0, F2xqX_F2xqXQV_eval(g, Sq, S, T));
1881
w0 = g;
1882
for (l=1; l<dT; l++) /* sum_{0<i<k} w^(2^i), result in (F_2)^r */
1883
g = F2xX_add(w0, F2xqXQ_sqr(g,S,T));
1884
f = F2xqX_gcd(g, Sp, T);
1885
if (degpol(f) > 0 && degpol(f) < n) break;
1886
set_avma(btop);
1887
}
1888
f = F2xqX_normalize(f, T);
1889
ff = F2xqX_div(Sp, f , T);
1890
F2xqX_edf_simple(f, xp, Xp, Sq, d, T, V, idx);
1891
F2xqX_edf_simple(ff, xp, Xp, Sq, d, T, V, idx+degpol(f)/d);
1892
}
1893
1894
static GEN
1895
F2xqX_factor_Shoup(GEN S, GEN xp, GEN T)
1896
{
1897
long i, n, s = 0;
1898
GEN X, Xp, Xq, Sq, D, V;
1899
long vT = get_F2x_var(T);
1900
pari_timer ti;
1901
n = get_F2xqX_degree(S);
1902
S = F2xqX_get_red(S, T);
1903
if (DEBUGLEVEL>=6) timer_start(&ti);
1904
X = polx_F2xX(get_F2xqX_var(S), vT);
1905
Xp = F2xqXQ_sqr(X, S, T);
1906
Xq = F2xqXQ_Frobenius(xp, Xp, S, T);
1907
Sq = F2xqXQ_powers(Xq, n-1, S, T);
1908
if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_Frobenius");
1909
D = F2xqX_ddf_Shoup(S, Xq, T);
1910
if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_ddf_Shoup");
1911
s = ddf_to_nbfact(D);
1912
V = cgetg(s+1, t_COL);
1913
for (i = 1, s = 1; i <= n; i++)
1914
{
1915
GEN Di = gel(D,i);
1916
long ni = degpol(Di), ri = ni/i;
1917
if (ni == 0) continue;
1918
Di = F2xqX_normalize(Di, T);
1919
if (ni == i) { gel(V, s++) = Di; continue; }
1920
F2xqX_edf_simple(Di, xp, Xp, Sq, i, T, V, s);
1921
if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_edf(%ld)",i);
1922
s += ri;
1923
}
1924
return V;
1925
}
1926
1927
static GEN
1928
F2xqX_factor_Cantor(GEN f, GEN T)
1929
{
1930
GEN xp, E, F, V;
1931
long i, j, l;
1932
T = F2x_get_red(T);
1933
f = F2xqX_normalize(f, T);
1934
switch(degpol(f))
1935
{
1936
case -1: retmkmat2(mkcol(f), mkvecsmall(1));
1937
case 0: return trivial_fact();
1938
case 1: retmkmat2(mkcol(f), mkvecsmall(1));
1939
case 2: return F2xqX_factor_2(f, T);
1940
}
1941
if (F2xY_degreex(f) <= 0) return F2x_factorff_i(F2xX_to_F2x(f), T);
1942
xp = F2x_Frobenius(T);
1943
V = F2xqX_factor_squarefree(f, T);
1944
l = lg(V);
1945
F = cgetg(l, t_VEC);
1946
E = cgetg(l, t_VEC);
1947
for (i=1, j=1; i < l; i++)
1948
if (degpol(gel(V,i)))
1949
{
1950
GEN Fj = F2xqX_factor_Shoup(gel(V,i), xp, T);
1951
gel(F, j) = Fj;
1952
gel(E, j) = const_vecsmall(lg(Fj)-1, i);
1953
j++;
1954
}
1955
return sort_factor_pol(FE_concat(F,E,j), cmp_Flx);
1956
}
1957
1958
static GEN
1959
FlxqX_Berlekamp_i(GEN f, GEN T, ulong p)
1960
{
1961
long lfact, d = degpol(f), j, k, lV;
1962
GEN E, t, V, xp;
1963
switch(d)
1964
{
1965
case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1));
1966
case 0: return trivial_fact();
1967
}
1968
T = Flx_get_red(T, p);
1969
f = FlxqX_normalize(f, T, p);
1970
if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p);
1971
if (degpol(f)==2) return FlxqX_factor_2(f, T, p);
1972
xp = Flx_Frobenius(T, p);
1973
V = FlxqX_factor_squarefree_i(f, xp, T, p); lV = lg(V);
1974
1975
/* to hold factors and exponents */
1976
t = cgetg(d+1,t_VEC);
1977
E = cgetg(d+1, t_VECSMALL);
1978
lfact = 1;
1979
for (k=1; k<lV ; k++)
1980
{
1981
if (degpol(gel(V,k))==0) continue;
1982
gel(t,lfact) = FlxqX_normalize(gel(V, k), T,p);
1983
d = FlxqX_split_Berlekamp(&gel(t,lfact), xp, T, p);
1984
for (j = 0; j < d; j++) E[lfact+j] = k;
1985
lfact += d;
1986
}
1987
setlg(t, lfact);
1988
setlg(E, lfact);
1989
return sort_factor_pol(mkvec2(t, E), cmp_Flx);
1990
}
1991
1992
static GEN
1993
FpXQX_Berlekamp_i(GEN f, GEN T, GEN p)
1994
{
1995
long lfact, d = degpol(f), j, k, lV;
1996
GEN E, t, V;
1997
switch(d)
1998
{
1999
case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1));
2000
case 0: return trivial_fact();
2001
}
2002
T = FpX_get_red(T, p);
2003
f = FpXQX_normalize(f, T, p);
2004
if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p);
2005
if (degpol(f)==2) return FpXQX_factor_2(f, T, p);
2006
V = FpXQX_factor_Yun(f, T, p); lV = lg(V);
2007
2008
/* to hold factors and exponents */
2009
t = cgetg(d+1,t_VEC);
2010
E = cgetg(d+1, t_VECSMALL);
2011
lfact = 1;
2012
for (k=1; k<lV ; k++)
2013
{
2014
if (degpol(gel(V,k))==0) continue;
2015
gel(t,lfact) = FpXQX_normalize(gel(V, k), T,p);
2016
d = FpXQX_split_Berlekamp(&gel(t,lfact), T, p);
2017
for (j = 0; j < d; j++) E[lfact+j] = k;
2018
lfact += d;
2019
}
2020
setlg(t, lfact);
2021
setlg(E, lfact);
2022
return sort_factor_pol(mkvec2(t, E), cmp_RgX);
2023
}
2024
2025
long
2026
FlxqX_ddf_degree(GEN S, GEN XP, GEN T, ulong p)
2027
{
2028
pari_sp av = avma;
2029
GEN X, b, g, xq, q;
2030
long i, j, n, v, B, l, m, bo, ro;
2031
pari_timer ti;
2032
hashtable h;
2033
2034
n = get_FlxqX_degree(S); v = get_FlxqX_var(S);
2035
X = polx_FlxX(v,get_Flx_var(T));
2036
if (gequal(X,XP)) return 1;
2037
B = n/2;
2038
l = usqrt(B);
2039
m = (B+l-1)/l;
2040
T = Flx_get_red(T, p);
2041
S = FlxqX_get_red(S, T, p);
2042
hash_init_GEN(&h, l+2, gequal, 1);
2043
hash_insert_long(&h, X, 0);
2044
hash_insert_long(&h, XP, 1);
2045
bo = brent_kung_optpow(n, l-1, 1);
2046
ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
2047
q = powuu(p, get_Flx_degree(T));
2048
if (DEBUGLEVEL>=7) timer_start(&ti);
2049
b = XP;
2050
if (expi(q) > ro)
2051
{
2052
xq = FlxqXQ_powers(b, brent_kung_optpow(n, l-1, 1), S, T, p);
2053
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq baby");
2054
} else xq = NULL;
2055
for (i = 3; i <= l+1; i++)
2056
{
2057
b = xq ? FlxqX_FlxqXQV_eval(b, xq, S, T, p)
2058
: FlxqXQ_pow(b, q, S, T, p);
2059
if (gequal(b,X)) return gc_long(av,i-1);
2060
hash_insert_long(&h, b, i-1);
2061
}
2062
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: baby");
2063
g = b;
2064
xq = FlxqXQ_powers(g, brent_kung_optpow(n, m, 1), S, T, p);
2065
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq giant");
2066
for(i = 2; i <= m+1; i++)
2067
{
2068
g = FlxqX_FlxqXQV_eval(g, xq, S, T, p);
2069
if (hash_haskey_long(&h, g, &j)) return gc_long(av, l*i-j);
2070
}
2071
return gc_long(av,n);
2072
}
2073
2074
static GEN
2075
FlxqX_ddf_Shoup(GEN S, GEN Xq, GEN T, ulong p)
2076
{
2077
pari_sp av = avma;
2078
GEN b, g, h, F, f, Sr, xq, q;
2079
long i, j, n, v, vT, bo, ro;
2080
long B, l, m;
2081
pari_timer ti;
2082
n = get_FlxqX_degree(S); v = get_FlxqX_var(S);
2083
vT = get_Flx_var(T);
2084
if (n == 0) return cgetg(1, t_VEC);
2085
if (n == 1) return mkvec(get_FlxqX_mod(S));
2086
B = n/2;
2087
l = usqrt(B);
2088
m = (B+l-1)/l;
2089
S = FlxqX_get_red(S, T, p);
2090
b = cgetg(l+2, t_VEC);
2091
gel(b, 1) = polx_FlxX(v, vT);
2092
gel(b, 2) = Xq;
2093
bo = brent_kung_optpow(n, l-1, 1);
2094
ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
2095
q = powuu(p, get_Flx_degree(T));
2096
if (DEBUGLEVEL>=7) timer_start(&ti);
2097
if (expi(q) <= ro)
2098
for (i = 3; i <= l+1; i++)
2099
gel(b, i) = FlxqXQ_pow(gel(b, i-1), q, S, T, p);
2100
else
2101
{
2102
xq = FlxqXQ_powers(gel(b, 2), bo, S, T, p);
2103
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq baby");
2104
for (i = 3; i <= l+1; i++)
2105
gel(b, i) = FlxqX_FlxqXQV_eval(gel(b, i-1), xq, S, T, p);
2106
}
2107
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: baby");
2108
xq = FlxqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p);
2109
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq giant");
2110
g = cgetg(m+1, t_VEC);
2111
gel(g, 1) = gel(xq, 2);
2112
for(i = 2; i <= m; i++)
2113
gel(g, i) = FlxqX_FlxqXQV_eval(gel(g, i-1), xq, S, T, p);
2114
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: giant");
2115
h = cgetg(m+1, t_VEC);
2116
for (j = 1; j <= m; j++)
2117
{
2118
pari_sp av = avma;
2119
GEN gj = gel(g, j);
2120
GEN e = FlxX_sub(gj, gel(b, 1), p);
2121
for (i = 2; i <= l; i++)
2122
e = FlxqXQ_mul(e, FlxX_sub(gj, gel(b, i), p), S, T, p);
2123
gel(h, j) = gerepileupto(av, e);
2124
}
2125
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: diff");
2126
Sr = get_FlxqX_mod(S);
2127
F = cgetg(m+1, t_VEC);
2128
for (j = 1; j <= m; j++)
2129
{
2130
GEN u = FlxqX_gcd(Sr, gel(h, j), T, p);
2131
if (degpol(u))
2132
{
2133
u = FlxqX_normalize(u, T, p);
2134
Sr = FlxqX_div(Sr, u, T, p);
2135
}
2136
gel(F,j) = u;
2137
}
2138
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: F");
2139
f = const_vec(n, pol1_FlxX(v, vT));
2140
for (j = 1; j <= m; j++)
2141
{
2142
GEN e = gel(F, j);
2143
for (i=l-1; i >= 0; i--)
2144
{
2145
GEN u = FlxqX_gcd(e, FlxX_sub(gel(g, j), gel(b, i+1), p), T, p);
2146
if (degpol(u))
2147
{
2148
gel(f, l*j-i) = u = FlxqX_normalize(u, T, p);
2149
e = FlxqX_div(e, u, T, p);
2150
}
2151
if (!degpol(e)) break;
2152
}
2153
}
2154
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: f");
2155
if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;
2156
return gerepilecopy(av, f);
2157
}
2158
2159
static GEN
2160
FlxqX_ddf_i(GEN f, GEN T, ulong p)
2161
{
2162
GEN Xq;
2163
if (!get_FlxqX_degree(f)) return cgetg(1, t_VEC);
2164
f = FlxqX_get_red(f, T, p);
2165
Xq = FlxqX_Frobenius(f, T, p);
2166
return FlxqX_ddf_Shoup(f, Xq, T, p);
2167
}
2168
GEN
2169
FlxqX_ddf(GEN S, GEN T, ulong p)
2170
{
2171
T = Flx_get_red(T, p);
2172
S = FlxqX_normalize(get_FlxqX_mod(S), T, p);
2173
return ddf_to_ddf2( FlxqX_ddf_i(S, T, p) );
2174
}
2175
GEN
2176
FlxqX_degfact(GEN S, GEN T, ulong p)
2177
{
2178
GEN V;
2179
long i, l;
2180
T = Flx_get_red(T, p);
2181
S = FlxqX_normalize(get_FlxqX_mod(S), T, p);
2182
V = FlxqX_factor_squarefree(S, T, p); l = lg(V);
2183
for (i=1; i < l; i++) gel(V,i) = FlxqX_ddf_i(gel(V,i), T, p);
2184
return vddf_to_simplefact(V, degpol(S));
2185
}
2186
2187
static void
2188
FlxqX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, ulong p, GEN V, long idx)
2189
{
2190
GEN Sp = get_FlxqX_mod(S);
2191
GEN u1, u2, f1, f2;
2192
GEN h;
2193
h = FlxqX_get_red(hp, T, p);
2194
t = FlxqX_rem(t, S, T, p);
2195
Xp = FlxqX_rem(Xp, h, T, p);
2196
u1 = FlxqX_roots_split(hp, xp, Xp, h, T, p);
2197
f1 = FlxqX_gcd(FlxqX_FlxqXQ_eval(u1, t, S, T, p), Sp, T, p);
2198
f1 = FlxqX_normalize(f1, T, p);
2199
u2 = FlxqX_div(hp, u1, T, p);
2200
f2 = FlxqX_div(Sp, f1, T, p);
2201
if (degpol(u1)==1)
2202
gel(V, idx) = f1;
2203
else
2204
FlxqX_edf_rec(FlxqX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx);
2205
idx += degpol(f1)/d;
2206
if (degpol(u2)==1)
2207
gel(V, idx) = f2;
2208
else
2209
FlxqX_edf_rec(FlxqX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx);
2210
}
2211
2212
static void
2213
FlxqX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, GEN V, long idx)
2214
{
2215
long n = degpol(Sp), r = n/d, vS = varn(Sp), vT = get_Flx_var(T);
2216
GEN S, h, t;
2217
pari_timer ti;
2218
if (r==1) { gel(V, idx) = Sp; return; }
2219
S = FlxqX_get_red(Sp, T, p);
2220
Xp = FlxqX_rem(Xp, S, T, p);
2221
Xq = FlxqX_rem(Xq, S, T, p);
2222
if (DEBUGLEVEL>=7) timer_start(&ti);
2223
do
2224
{
2225
GEN g = random_FlxqX(n, vS, T, p);
2226
t = gel(FlxqXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);
2227
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_auttrace");
2228
h = FlxqXQ_minpoly(t, S, T, p);
2229
if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_minpoly");
2230
} while (degpol(h) != r);
2231
Xp = FlxqXQ_powu(polx_FlxX(vS, vT), p, h, T, p);
2232
FlxqX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx);
2233
}
2234
2235
static void
2236
FlxqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, GEN V, long idx)
2237
{
2238
long v = varn(Sp), n = degpol(Sp), r = n/d;
2239
GEN S, f, ff;
2240
long vT = get_Flx_var(T), dT = get_Flx_degree(T);
2241
if (r==1) { gel(V, idx) = Sp; return; }
2242
S = FlxqX_get_red(Sp, T, p);
2243
Xp = FlxqX_rem(Xp, S, T, p);
2244
Xq = FlxqX_rem(Xq, S, T, p);
2245
while (1)
2246
{
2247
pari_sp btop = avma;
2248
long i;
2249
GEN g = random_FlxqX(n, v, T, p);
2250
GEN t = gel(FlxqXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);
2251
if (lgpol(t) == 0) continue;
2252
for(i=1; i<=10; i++)
2253
{
2254
pari_sp btop2 = avma;
2255
GEN r = random_Flx(dT, vT, p);
2256
GEN R = FlxqXQ_halfFrobenius_i(FlxX_Flx_add(t, r, p), xp, Xp, S, T, p);
2257
f = FlxqX_gcd(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p);
2258
if (degpol(f) > 0 && degpol(f) < n) break;
2259
set_avma(btop2);
2260
}
2261
if (degpol(f) > 0 && degpol(f) < n) break;
2262
set_avma(btop);
2263
}
2264
f = FlxqX_normalize(f, T, p);
2265
ff = FlxqX_div(Sp, f , T, p);
2266
FlxqX_edf_simple(f, xp, Xp, Xq, d, T, p, V, idx);
2267
FlxqX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d);
2268
}
2269
2270
static GEN
2271
FlxqX_factor_Shoup(GEN S, GEN xp, GEN T, ulong p)
2272
{
2273
long i, n, s = 0;
2274
GEN X, Xp, Xq, D, V;
2275
long dT = get_Flx_degree(T), vT = get_Flx_var(T);
2276
long e = expi(powuu(p, dT));
2277
pari_timer ti;
2278
n = get_FlxqX_degree(S);
2279
S = FlxqX_get_red(S, T, p);
2280
if (DEBUGLEVEL>=6) timer_start(&ti);
2281
X = polx_FlxX(get_FlxqX_var(S), vT);
2282
Xp = FlxqXQ_powu(X, p, S, T, p);
2283
Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p);
2284
if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_Frobenius");
2285
D = FlxqX_ddf_Shoup(S, Xq, T, p);
2286
if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_ddf_Shoup");
2287
s = ddf_to_nbfact(D);
2288
V = cgetg(s+1, t_COL);
2289
for (i = 1, s = 1; i <= n; i++)
2290
{
2291
GEN Di = gel(D,i);
2292
long ni = degpol(Di), ri = ni/i;
2293
if (ni == 0) continue;
2294
Di = FlxqX_normalize(Di, T, p);
2295
if (ni == i) { gel(V, s++) = Di; continue; }
2296
if (ri <= e*expu(e))
2297
FlxqX_edf(Di, xp, Xp, Xq, i, T, p, V, s);
2298
else
2299
FlxqX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s);
2300
if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_edf(%ld)",i);
2301
s += ri;
2302
}
2303
return V;
2304
}
2305
2306
static GEN
2307
FlxqX_factor_Cantor(GEN f, GEN T, ulong p)
2308
{
2309
GEN xp, E, F, V;
2310
long i, j, l;
2311
T = Flx_get_red(T, p);
2312
f = FlxqX_normalize(f, T, p);
2313
switch(degpol(f))
2314
{
2315
case -1: retmkmat2(mkcol(f), mkvecsmall(1));
2316
case 0: return trivial_fact();
2317
case 1: retmkmat2(mkcol(f), mkvecsmall(1));
2318
case 2: return FlxqX_factor_2(f, T, p);
2319
}
2320
if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p);
2321
xp = Flx_Frobenius(T, p);
2322
V = FlxqX_factor_squarefree_i(f, xp, get_Flx_mod(T), p);
2323
l = lg(V);
2324
F = cgetg(l, t_VEC);
2325
E = cgetg(l, t_VEC);
2326
for (i=1, j=1; i < l; i++)
2327
if (degpol(gel(V,i)))
2328
{
2329
GEN Fj = FlxqX_factor_Shoup(gel(V,i), xp, T, p);
2330
gel(F, j) = Fj;
2331
gel(E, j) = const_vecsmall(lg(Fj)-1, i);
2332
j++;
2333
}
2334
return sort_factor_pol(FE_concat(F,E,j), cmp_Flx);
2335
}
2336
2337
long
2338
FlxqX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, ulong p)
2339
{
2340
pari_sp av = avma;
2341
GEN u = get_FlxqX_mod(S);
2342
long s;
2343
if (FlxY_degreex(u) <= 0)
2344
s = Flx_nbfactff(FlxX_to_Flx(u), T, p);
2345
else
2346
s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, Xq, T, p));
2347
return gc_long(av,s);
2348
}
2349
2350
long
2351
FlxqX_nbfact(GEN S, GEN T, ulong p)
2352
{
2353
pari_sp av = avma;
2354
GEN u = get_FlxqX_mod(S);
2355
long s;
2356
if (FlxY_degreex(u) <= 0)
2357
s = Flx_nbfactff(FlxX_to_Flx(u), T, p);
2358
else
2359
s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, FlxqX_Frobenius(S, T, p), T, p));
2360
return gc_long(av,s);
2361
}
2362
2363
GEN
2364
FlxqX_factor(GEN x, GEN T, ulong p)
2365
{
2366
pari_sp av = avma;
2367
return gerepilecopy(av, FlxqX_factor_Cantor(x, T, p));
2368
}
2369
2370
GEN
2371
F2xqX_factor(GEN x, GEN T)
2372
{
2373
pari_sp av = avma;
2374
return gerepilecopy(av, F2xqX_factor_Cantor(x, T));
2375
}
2376
2377
long
2378
FpXQX_ddf_degree(GEN S, GEN XP, GEN T, GEN p)
2379
{
2380
pari_sp av = avma;
2381
GEN X, b, g, xq, q;
2382
long i, j, n, v, B, l, m, bo, ro;
2383
pari_timer ti;
2384
hashtable h;
2385
2386
n = get_FpXQX_degree(S); v = get_FpXQX_var(S);
2387
X = pol_x(v);
2388
if (gequal(X,XP)) return 1;
2389
B = n/2;
2390
l = usqrt(B);
2391
m = (B+l-1)/l;
2392
T = FpX_get_red(T, p);
2393
S = FpXQX_get_red(S, T, p);
2394
hash_init_GEN(&h, l+2, gequal, 1);
2395
hash_insert_long(&h, X, 0);
2396
hash_insert_long(&h, simplify_shallow(XP), 1);
2397
bo = brent_kung_optpow(n, l-1, 1);
2398
ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
2399
q = powiu(p, get_FpX_degree(T));
2400
if (DEBUGLEVEL>=7) timer_start(&ti);
2401
b = XP;
2402
if (expi(q) > ro)
2403
{
2404
xq = FpXQXQ_powers(b, brent_kung_optpow(n, l-1, 1), S, T, p);
2405
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq baby");
2406
} else xq = NULL;
2407
for (i = 3; i <= l+1; i++)
2408
{
2409
b = xq ? FpXQX_FpXQXQV_eval(b, xq, S, T, p)
2410
: FpXQXQ_pow(b, q, S, T, p);
2411
if (gequal(b,X)) return gc_long(av,i-1);
2412
hash_insert_long(&h, simplify_shallow(b), i-1);
2413
}
2414
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: baby");
2415
g = b;
2416
xq = FpXQXQ_powers(g, brent_kung_optpow(n, m, 1), S, T, p);
2417
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq giant");
2418
for(i = 2; i <= m+1; i++)
2419
{
2420
g = FpXQX_FpXQXQV_eval(g, xq, S, T, p);
2421
if (hash_haskey_long(&h, simplify_shallow(g), &j)) return gc_long(av,l*i-j);
2422
}
2423
return gc_long(av,n);
2424
}
2425
2426
static GEN
2427
FpXQX_ddf_Shoup(GEN S, GEN Xq, GEN T, GEN p)
2428
{
2429
pari_sp av = avma;
2430
GEN b, g, h, F, f, Sr, xq, q;
2431
long i, j, n, v, bo, ro;
2432
long B, l, m;
2433
pari_timer ti;
2434
n = get_FpXQX_degree(S); v = get_FpXQX_var(S);
2435
if (n == 0) return cgetg(1, t_VEC);
2436
if (n == 1) return mkvec(get_FpXQX_mod(S));
2437
B = n/2;
2438
l = usqrt(B);
2439
m = (B+l-1)/l;
2440
S = FpXQX_get_red(S, T, p);
2441
b = cgetg(l+2, t_VEC);
2442
gel(b, 1) = pol_x(v);
2443
gel(b, 2) = Xq;
2444
bo = brent_kung_optpow(n, l-1, 1);
2445
ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
2446
q = powiu(p, get_FpX_degree(T));
2447
if (DEBUGLEVEL>=7) timer_start(&ti);
2448
if (expi(q) <= ro)
2449
for (i = 3; i <= l+1; i++)
2450
gel(b, i) = FpXQXQ_pow(gel(b, i-1), q, S, T, p);
2451
else
2452
{
2453
xq = FpXQXQ_powers(gel(b, 2), bo, S, T, p);
2454
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq baby");
2455
for (i = 3; i <= l+1; i++)
2456
gel(b, i) = FpXQX_FpXQXQV_eval(gel(b, i-1), xq, S, T, p);
2457
}
2458
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: baby");
2459
xq = FpXQXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p);
2460
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq giant");
2461
g = cgetg(m+1, t_VEC);
2462
gel(g, 1) = gel(xq, 2);
2463
for(i = 2; i <= m; i++)
2464
gel(g, i) = FpXQX_FpXQXQV_eval(gel(g, i-1), xq, S, T, p);
2465
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: giant");
2466
h = cgetg(m+1, t_VEC);
2467
for (j = 1; j <= m; j++)
2468
{
2469
pari_sp av = avma;
2470
GEN gj = gel(g, j);
2471
GEN e = FpXX_sub(gj, gel(b, 1), p);
2472
for (i = 2; i <= l; i++)
2473
e = FpXQXQ_mul(e, FpXX_sub(gj, gel(b, i), p), S, T, p);
2474
gel(h, j) = gerepileupto(av, e);
2475
}
2476
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: diff");
2477
Sr = get_FpXQX_mod(S);
2478
F = cgetg(m+1, t_VEC);
2479
for (j = 1; j <= m; j++)
2480
{
2481
GEN u = FpXQX_gcd(Sr, gel(h,j), T, p);
2482
if (degpol(u))
2483
{
2484
u = FpXQX_normalize(u, T, p);
2485
Sr = FpXQX_div(Sr, u, T, p);
2486
}
2487
gel(F,j) = u;
2488
}
2489
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: F");
2490
f = const_vec(n, pol_1(v));
2491
for (j = 1; j <= m; j++)
2492
{
2493
GEN e = gel(F, j);
2494
for (i=l-1; i >= 0; i--)
2495
{
2496
GEN u = FpXQX_gcd(e, FpXX_sub(gel(g, j), gel(b, i+1), p), T, p);
2497
if (degpol(u))
2498
{
2499
gel(f, l*j-i) = u = FpXQX_normalize(u, T, p);
2500
e = FpXQX_div(e, u, T, p);
2501
}
2502
if (!degpol(e)) break;
2503
}
2504
}
2505
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: f");
2506
if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;
2507
return gerepilecopy(av, f);
2508
}
2509
2510
static GEN
2511
FpXQX_ddf_i(GEN f, GEN T, GEN p)
2512
{
2513
GEN Xq;
2514
if (!get_FpXQX_degree(f)) return cgetg(1,t_VEC);
2515
f = FpXQX_get_red(f, T, p);
2516
Xq = FpXQX_Frobenius(f, T, p);
2517
return FpXQX_ddf_Shoup(f, Xq, T, p);
2518
}
2519
2520
static GEN
2521
FpXQX_ddf_raw(GEN f, GEN T, GEN p)
2522
{
2523
if (lgefint(p)==3)
2524
{
2525
ulong pp = p[2];
2526
GEN M;
2527
long vT = get_FpX_var(T);
2528
if (pp==2)
2529
{
2530
M = F2xqX_ddf(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));
2531
return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));
2532
}
2533
M = FlxqX_ddf(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);
2534
return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));
2535
}
2536
T = FpX_get_red(T, p);
2537
f = FpXQX_normalize(get_FpXQX_mod(f), T, p);
2538
return ddf_to_ddf2( FpXQX_ddf_i(f, T, p) );
2539
}
2540
2541
GEN
2542
FpXQX_ddf(GEN x, GEN T, GEN p)
2543
{ pari_sp av = avma; return gerepilecopy(av, FpXQX_ddf_raw(x,T,p)); }
2544
2545
static GEN
2546
FpXQX_degfact_raw(GEN f, GEN T, GEN p)
2547
{
2548
GEN V;
2549
long i,l;
2550
if (lgefint(p)==3)
2551
{
2552
ulong pp = p[2];
2553
long vT = get_FpX_var(T);
2554
if (pp==2)
2555
return F2xqX_degfact(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));
2556
else
2557
return FlxqX_degfact(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);
2558
}
2559
T = FpX_get_red(T, p);
2560
f = FpXQX_normalize(get_FpXQX_mod(f), T, p);
2561
V = FpXQX_factor_Yun(f, T, p); l = lg(V);
2562
for (i=1; i < l; i++) gel(V,i) = FpXQX_ddf_i(gel(V,i), T, p);
2563
return vddf_to_simplefact(V, degpol(f));
2564
}
2565
2566
GEN
2567
FpXQX_degfact(GEN x, GEN T, GEN p)
2568
{ pari_sp av = avma; return gerepilecopy(av, FpXQX_degfact_raw(x,T,p)); }
2569
2570
static void
2571
FpXQX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, GEN p, GEN V, long idx)
2572
{
2573
GEN Sp = get_FpXQX_mod(S);
2574
GEN u1, u2, f1, f2;
2575
GEN h;
2576
h = FpXQX_get_red(hp, T, p);
2577
t = FpXQX_rem(t, S, T, p);
2578
Xp = FpXQX_rem(Xp, h, T, p);
2579
u1 = FpXQX_roots_split(hp, xp, Xp, h, T, p);
2580
f1 = FpXQX_gcd(FpXQX_FpXQXQ_eval(u1, t, S, T, p), Sp, T, p);
2581
f1 = FpXQX_normalize(f1, T, p);
2582
u2 = FpXQX_div(hp, u1, T, p);
2583
f2 = FpXQX_div(Sp, f1, T, p);
2584
if (degpol(u1)==1)
2585
gel(V, idx) = f1;
2586
else
2587
FpXQX_edf_rec(FpXQX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx);
2588
idx += degpol(f1)/d;
2589
if (degpol(u2)==1)
2590
gel(V, idx) = f2;
2591
else
2592
FpXQX_edf_rec(FpXQX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx);
2593
}
2594
2595
static void
2596
FpXQX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx)
2597
{
2598
long n = degpol(Sp), r = n/d, vS = varn(Sp);
2599
GEN S, h, t;
2600
pari_timer ti;
2601
if (r==1) { gel(V, idx) = Sp; return; }
2602
S = FpXQX_get_red(Sp, T, p);
2603
Xp = FpXQX_rem(Xp, S, T, p);
2604
Xq = FpXQX_rem(Xq, S, T, p);
2605
if (DEBUGLEVEL>=7) timer_start(&ti);
2606
do
2607
{
2608
GEN g = random_FpXQX(n, vS, T, p);
2609
t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);
2610
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_auttrace");
2611
h = FpXQXQ_minpoly(t, S, T, p);
2612
if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_minpoly");
2613
} while (degpol(h) != r);
2614
Xp = FpXQXQ_pow(pol_x(vS), p, h, T, p);
2615
FpXQX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx);
2616
}
2617
2618
static void
2619
FpXQX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx)
2620
{
2621
long v = varn(Sp), n = degpol(Sp), r = n/d;
2622
GEN S, f, ff;
2623
long vT = get_FpX_var(T), dT = get_FpX_degree(T);
2624
if (r==1) { gel(V, idx) = Sp; return; }
2625
S = FpXQX_get_red(Sp, T, p);
2626
Xp = FpXQX_rem(Xp, S, T, p);
2627
Xq = FpXQX_rem(Xq, S, T, p);
2628
while (1)
2629
{
2630
pari_sp btop = avma;
2631
long i;
2632
GEN g = random_FpXQX(n, v, T, p);
2633
GEN t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);
2634
if (lgpol(t) == 0) continue;
2635
for(i=1; i<=10; i++)
2636
{
2637
pari_sp btop2 = avma;
2638
GEN r = random_FpX(dT, vT, p);
2639
GEN R = FpXQXQ_halfFrobenius_i(FqX_Fq_add(t, r, T, p), xp, Xp, S, T, p);
2640
f = FpXQX_gcd(FqX_Fq_add(R, gen_m1, T, p), Sp, T, p);
2641
if (degpol(f) > 0 && degpol(f) < n) break;
2642
set_avma(btop2);
2643
}
2644
if (degpol(f) > 0 && degpol(f) < n) break;
2645
set_avma(btop);
2646
}
2647
f = FpXQX_normalize(f, T, p);
2648
ff = FpXQX_div(Sp, f , T, p);
2649
FpXQX_edf_simple(f, xp, Xp, Xq, d, T, p, V, idx);
2650
FpXQX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d);
2651
}
2652
2653
static GEN
2654
FpXQX_factor_Shoup(GEN S, GEN xp, GEN T, GEN p)
2655
{
2656
long i, n, s = 0, dT = get_FpX_degree(T), e = expi(powiu(p, dT));
2657
GEN X, Xp, Xq, D, V;
2658
pari_timer ti;
2659
n = get_FpXQX_degree(S);
2660
S = FpXQX_get_red(S, T, p);
2661
if (DEBUGLEVEL>=6) timer_start(&ti);
2662
X = pol_x(get_FpXQX_var(S));
2663
Xp = FpXQXQ_pow(X, p, S, T, p);
2664
Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);
2665
if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_Frobenius");
2666
D = FpXQX_ddf_Shoup(S, Xq, T, p);
2667
if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_ddf_Shoup");
2668
s = ddf_to_nbfact(D);
2669
V = cgetg(s+1, t_COL);
2670
for (i = 1, s = 1; i <= n; i++)
2671
{
2672
GEN Di = gel(D,i);
2673
long ni = degpol(Di), ri = ni/i;
2674
if (ni == 0) continue;
2675
Di = FpXQX_normalize(Di, T, p);
2676
if (ni == i) { gel(V, s++) = Di; continue; }
2677
if (ri <= e*expu(e))
2678
FpXQX_edf(Di, xp, Xp, Xq, i, T, p, V, s);
2679
else
2680
FpXQX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s);
2681
if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_edf(%ld)",i);
2682
s += ri;
2683
}
2684
return V;
2685
}
2686
2687
static GEN
2688
FpXQX_factor_Cantor(GEN f, GEN T, GEN p)
2689
{
2690
GEN xp, E, F, V;
2691
long i, j, l;
2692
T = FpX_get_red(T, p);
2693
f = FpXQX_normalize(f, T, p);
2694
switch(degpol(f))
2695
{
2696
case -1: retmkmat2(mkcol(f), mkvecsmall(1));
2697
case 0: return trivial_fact();
2698
case 1: retmkmat2(mkcol(f), mkvecsmall(1));
2699
case 2: return FpXQX_factor_2(f, T, p);
2700
}
2701
if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p);
2702
xp = FpX_Frobenius(T, p);
2703
V = FpXQX_factor_Yun(f, T, p);
2704
l = lg(V);
2705
F = cgetg(l, t_VEC);
2706
E = cgetg(l, t_VEC);
2707
for (i=1, j=1; i < l; i++)
2708
if (degpol(gel(V,i)))
2709
{
2710
GEN Fj = FpXQX_factor_Shoup(gel(V,i), xp, T, p);
2711
gel(E,j) = const_vecsmall(lg(Fj)-1, i);
2712
gel(F,j) = Fj; j++;
2713
}
2714
return sort_factor_pol(FE_concat(F,E,j), cmp_RgX);
2715
}
2716
2717
long
2718
FpXQX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, GEN p)
2719
{
2720
pari_sp av = avma;
2721
GEN u = get_FpXQX_mod(S);
2722
long s;
2723
if (lgefint(p)==3)
2724
{
2725
ulong pp = p[2];
2726
long vT = get_FpX_var(T);
2727
GEN Sp = ZXXT_to_FlxXT(S,pp,vT), Xqp = ZXX_to_FlxX(Xq,pp,vT);
2728
s = FlxqX_nbfact_Frobenius(Sp, Xqp, ZXT_to_FlxT(T,pp), pp);
2729
}
2730
else if (isabsolutepol(u))
2731
s = FpX_nbfactff(simplify_shallow(u), T, p);
2732
else
2733
s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, Xq, T, p));
2734
return gc_long(av,s);
2735
}
2736
2737
long
2738
FpXQX_nbfact(GEN S, GEN T, GEN p)
2739
{
2740
pari_sp av = avma;
2741
GEN u = get_FpXQX_mod(S);
2742
long s;
2743
if (lgefint(p)==3)
2744
{
2745
ulong pp = p[2];
2746
long vT = get_FpX_var(T);
2747
s = FlxqX_nbfact(ZXXT_to_FlxXT(S,pp,vT), ZXT_to_FlxT(T,pp), pp);
2748
}
2749
else if (isabsolutepol(u))
2750
s = FpX_nbfactff(simplify_shallow(u), T, p);
2751
else
2752
s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, FpXQX_Frobenius(S, T, p), T, p));
2753
return gc_long(av,s);
2754
}
2755
long
2756
FqX_nbfact(GEN u, GEN T, GEN p)
2757
{ return T ? FpXQX_nbfact(u, T, p): FpX_nbfact(u, p); }
2758
2759
static GEN
2760
FpXQX_factor_Berlekamp_i(GEN f, GEN T, GEN p)
2761
{
2762
if (lgefint(p)==3)
2763
{
2764
ulong pp = p[2];
2765
GEN M;
2766
long vT = get_FpX_var(T);
2767
if (pp==2)
2768
{
2769
M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));
2770
return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));
2771
}
2772
M = FlxqX_Berlekamp_i(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);
2773
return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));
2774
}
2775
return FpXQX_Berlekamp_i(f, T, p);
2776
}
2777
GEN
2778
FpXQX_factor_Berlekamp(GEN x, GEN T, GEN p)
2779
{ pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_Berlekamp_i(x,T,p)); }
2780
2781
static GEN
2782
FpXQX_factor_i(GEN f, GEN T, GEN p)
2783
{
2784
if (lgefint(p)==3)
2785
{
2786
ulong pp = p[2];
2787
GEN M;
2788
long vT = get_FpX_var(T);
2789
if (pp==2)
2790
{
2791
M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));
2792
return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));
2793
}
2794
M = FlxqX_factor_Cantor(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);
2795
return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));
2796
}
2797
return FpXQX_factor_Cantor(f, T, p);
2798
}
2799
GEN
2800
FpXQX_factor(GEN x, GEN T, GEN p)
2801
{ pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_i(x,T,p)); }
2802
2803
long
2804
FlxqX_is_squarefree(GEN P, GEN T, ulong p)
2805
{
2806
pari_sp av = avma;
2807
GEN z = FlxqX_gcd(P, FlxX_deriv(P, p), T, p);
2808
return gc_long(av, degpol(z)==0);
2809
}
2810
2811
long
2812
FqX_is_squarefree(GEN P, GEN T, GEN p)
2813
{
2814
pari_sp av = avma;
2815
GEN z = FqX_gcd(P, FqX_deriv(P, T, p), T, p);
2816
return gc_long(av, degpol(z)==0);
2817
}
2818
2819
/* as RgX_to_FpXQ(FqX_to_FFX), leaving alone t_FFELT */
2820
static GEN
2821
RgX_to_FFX(GEN x, GEN ff)
2822
{
2823
long i, lx;
2824
GEN p = FF_p_i(ff), T = FF_mod(ff), y = cgetg_copy(x,&lx);
2825
y[1] = x[1]; if (degpol(T) == 1) T = NULL;
2826
for (i = 2; i < lx; i++)
2827
{
2828
GEN c = gel(x,i);
2829
gel(y,i) = typ(c) == t_FFELT? c: Fq_to_FF(Rg_to_Fq(c,T,p), ff);
2830
}
2831
return y;
2832
}
2833
2834
#define code(t1,t2) ((t1 << 6) | t2)
2835
/* Check types and replace F by a monic normalized FpX having the same roots
2836
* Don't bother to make constant polynomials monic */
2837
static GEN
2838
factmod_init(GEN f, GEN *pD, GEN *pT, GEN *pp)
2839
{
2840
const char *s = "factormod";
2841
GEN T, p, D = *pD;
2842
if (typ(f) != t_POL) pari_err_TYPE(s,f);
2843
if (!D)
2844
{
2845
long pa, t = RgX_type(f, pp, pT, &pa);
2846
if (t == t_FFELT) return f;
2847
*pD = gen_0;
2848
if (t != t_INTMOD && t != code(t_POLMOD,t_INTMOD)) pari_err_TYPE(s,f);
2849
return RgX_to_FqX(f, *pT, *pp);
2850
}
2851
if (typ(D) == t_FFELT) { *pD = NULL; *pT = D; return RgX_to_FFX(f,D); }
2852
if (!ff_parse_Tp(D, &T, &p, 1)) pari_err_TYPE(s,D);
2853
if (T && varncmp(varn(T), varn(f)) <= 0)
2854
pari_err_PRIORITY(s, T, "<=", varn(f));
2855
*pT = T; *pp = p; return RgX_to_FqX(f, T, p);
2856
}
2857
#undef code
2858
2859
int
2860
ff_parse_Tp(GEN Tp, GEN *T, GEN *p, long red)
2861
{
2862
long t = typ(Tp);
2863
*T = *p = NULL;
2864
if (t == t_INT) { *p = Tp; return cmpiu(*p, 1) > 0; }
2865
if (t != t_VEC || lg(Tp) != 3) return 0;
2866
*T = gel(Tp,1);
2867
*p = gel(Tp,2);
2868
if (typ(*p) != t_INT)
2869
{
2870
if (typ(*T) != t_INT) return 0;
2871
swap(*T, *p); /* support both [T,p] and [p,T] */
2872
}
2873
if (red) *T = RgX_to_FpX(*T, *p);
2874
return cmpiu(*p, 1) > 0 && typ(*T) == t_POL && RgX_is_ZX(*T);
2875
}
2876
2877
static GEN
2878
to_Fq(GEN x, GEN T, GEN p)
2879
{
2880
long i, lx, tx = typ(x);
2881
GEN y;
2882
2883
if (tx == t_INT)
2884
y = mkintmod(x,p);
2885
else
2886
{
2887
if (tx != t_POL) pari_err_TYPE("to_Fq",x);
2888
y = cgetg_copy(x,&lx); y[1] = x[1];
2889
for (i=2; i<lx; i++) gel(y,i) = mkintmod(gel(x,i), p);
2890
}
2891
return mkpolmod(y, T);
2892
}
2893
static GEN
2894
to_Fq_pol(GEN x, GEN T, GEN p)
2895
{
2896
long i, lx = lg(x);
2897
if (lx == 2)
2898
{
2899
GEN y = cgetg(3,t_POL); y[1]=x[1];
2900
gel(y,2) = mkintmod(gen_0,p); return y;
2901
}
2902
for (i = 2; i < lx; i++) gel(x,i) = to_Fq(gel(x,i),T,p);
2903
return x;
2904
}
2905
static GEN
2906
to_Fq_fact(GEN fa, GEN T, GEN p)
2907
{
2908
GEN P = gel(fa,1);
2909
long j, l = lg(P);
2910
p = icopy(p); T = FpX_to_mod(T, p);
2911
for (j=1; j<l; j++) gel(P,j) = to_Fq_pol(gel(P,j), T,p);
2912
return fa;
2913
}
2914
static GEN
2915
to_FqC(GEN P, GEN T, GEN p)
2916
{
2917
long j, l = lg(P);
2918
p = icopy(p); T = FpX_to_mod(T, p);
2919
for (j=1; j<l; j++) gel(P,j) = to_Fq(gel(P,j), T,p);
2920
return P;
2921
}
2922
2923
GEN
2924
factmod(GEN f, GEN D)
2925
{
2926
pari_sp av;
2927
GEN y, F, P, E, T, p;
2928
f = factmod_init(f, &D, &T,&p);
2929
if (!D) return FFX_factor(f, T);
2930
av = avma;
2931
F = FqX_factor(f, T, p); P = gel(F,1); E = gel(F,2);
2932
if (!T)
2933
{
2934
y = cgetg(3, t_MAT);
2935
gel(y,1) = FpXC_to_mod(P, p);
2936
gel(y,2) = Flc_to_ZC(E); return gerepileupto(av, y);
2937
}
2938
F = gerepilecopy(av, mkmat2(simplify_shallow(P), Flc_to_ZC(E)));
2939
return to_Fq_fact(F, T, p);
2940
}
2941
GEN
2942
simplefactmod(GEN f, GEN D)
2943
{
2944
pari_sp av = avma;
2945
GEN T, p;
2946
f = factmod_init(f, &D, &T,&p);
2947
if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }
2948
f = D? FqX_degfact(f, T, p): FFX_degfact(f, T);
2949
return gerepileupto(av, Flm_to_ZM(f));
2950
}
2951
static GEN
2952
sqf_to_fact(GEN f)
2953
{
2954
long i, j, l = lg(f);
2955
GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL);
2956
for (i = j = 1; i < l; i++)
2957
if (degpol(gel(f,i)))
2958
{
2959
gel(P,j) = gel(f,i);
2960
gel(E,j) = utoi(i); j++;
2961
}
2962
setlg(P,j);
2963
setlg(E,j); return mkvec2(P,E);
2964
}
2965
2966
GEN
2967
factormodSQF(GEN f, GEN D)
2968
{
2969
pari_sp av = avma;
2970
GEN F, T, p;
2971
f = factmod_init(f, &D, &T,&p);
2972
if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }
2973
if (!D)
2974
F = sqf_to_fact(FFX_factor_squarefree(f, T));
2975
else
2976
{
2977
F = sqf_to_fact(FqX_factor_squarefree(f,T,p));
2978
gel(F,1) = FqXC_to_mod(gel(F,1), T,p);
2979
}
2980
settyp(F,t_MAT); return gerepilecopy(av, F);
2981
}
2982
GEN
2983
factormodDDF(GEN f, GEN D)
2984
{
2985
pari_sp av = avma;
2986
GEN F, T, p;
2987
f = factmod_init(f, &D, &T,&p);
2988
if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }
2989
if (!D) return FFX_ddf(f, T);
2990
F = FqX_ddf(f,T,p);
2991
gel(F,1) = FqXC_to_mod(gel(F,1), T,p);
2992
gel(F,2) = Flc_to_ZC(gel(F,2));
2993
settyp(F, t_MAT); return gerepilecopy(av, F);
2994
}
2995
2996
GEN
2997
factormod0(GEN f, GEN p, long flag)
2998
{
2999
if (flag == 0) return factmod(f,p);
3000
if (flag != 1) pari_err_FLAG("factormod");
3001
return simplefactmod(f,p);
3002
}
3003
GEN
3004
polrootsmod(GEN f, GEN D)
3005
{
3006
pari_sp av;
3007
GEN y, T, p;
3008
f = factmod_init(f, &D, &T,&p);
3009
if (!D) return FFX_roots(f, T);
3010
av = avma; y = FqX_roots(f, T, p);
3011
if (!T) return gerepileupto(av, FpC_to_mod(y,p));
3012
y = gerepilecopy(av, simplify_shallow(y));
3013
return to_FqC(y, T, p);
3014
}
3015
3016
GEN /* OBSOLETE */
3017
rootmod0(GEN f, GEN p, long flag) { (void)flag; return polrootsmod(f,p); }
3018
GEN /* OBSOLETE */
3019
factorff(GEN f, GEN p, GEN T)
3020
{
3021
pari_sp av = avma;
3022
GEN D = (p && T)? mkvec2(T,p): NULL;
3023
return gerepileupto(av, factmod(f,D));
3024
}
3025
GEN /* OBSOLETE */
3026
polrootsff(GEN f, GEN p, GEN T)
3027
{
3028
pari_sp av = avma;
3029
GEN D = (p && T)? mkvec2(T,p): NULL;
3030
return gerepileupto(av, polrootsmod(f, D));
3031
}
3032
3033