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) 2000 The PARI group.
2
3
This file is part of the PARI/GP package.
4
5
PARI/GP is free software; you can redistribute it and/or modify it under the
6
terms of the GNU General Public License as published by the Free Software
7
Foundation; either version 2 of the License, or (at your option) any later
8
version. It is distributed in the hope that it will be useful, but WITHOUT
9
ANY WARRANTY WHATSOEVER.
10
11
Check the License for details. You should have received a copy of it, along
12
with the package; see the file 'COPYING'. If not, write to the Free Software
13
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14
15
/**************************************************************/
16
/* */
17
/* NUMBER FIELDS */
18
/* */
19
/**************************************************************/
20
#include "pari.h"
21
#include "paripriv.h"
22
23
#define DEBUGLEVEL DEBUGLEVEL_nf
24
25
int new_galois_format = 0;
26
27
/* v a t_VEC, lg(v) = 13, sanity check for true rnf */
28
static int
29
v13checkrnf(GEN v)
30
{ return typ(gel(v,6)) == t_VEC; }
31
static int
32
rawcheckbnf(GEN v) { return typ(v)==t_VEC && lg(v)==11; }
33
static int
34
rawchecknf(GEN v) { return typ(v)==t_VEC && lg(v)==10; }
35
/* v a t_VEC, lg(v) = 11, sanity check for true bnf */
36
static int
37
v11checkbnf(GEN v) { return rawchecknf(bnf_get_nf(v)); }
38
/* v a t_VEC, lg(v) = 10, sanity check for true nf */
39
static int
40
v10checknf(GEN v) { return typ(gel(v,1))==t_POL; }
41
/* v a t_VEC, lg(v) = 9, sanity check for true gal */
42
static int
43
v9checkgal(GEN v)
44
{ GEN x = gel(v,2); return typ(x) == t_VEC && lg(x) == 4; }
45
46
int
47
checkrnf_i(GEN rnf)
48
{ return (typ(rnf)==t_VEC && lg(rnf)==13 && v13checkrnf(rnf)); }
49
50
void
51
checkrnf(GEN rnf)
52
{ if (!checkrnf_i(rnf)) pari_err_TYPE("checkrnf",rnf); }
53
54
GEN
55
checkbnf_i(GEN X)
56
{
57
if (typ(X) == t_VEC)
58
switch (lg(X))
59
{
60
case 11:
61
if (typ(gel(X,6)) != t_INT) return NULL; /* pre-2.2.4 format */
62
if (lg(gel(X,10)) != 4) return NULL; /* pre-2.8.1 format */
63
return X;
64
case 7: return checkbnf_i(bnr_get_bnf(X));
65
}
66
return NULL;
67
}
68
69
GEN
70
checknf_i(GEN X)
71
{
72
if (typ(X)==t_VEC)
73
switch(lg(X))
74
{
75
case 10: return X;
76
case 11: return checknf_i(bnf_get_nf(X));
77
case 7: return checknf_i(bnr_get_bnf(X));
78
case 3: if (typ(gel(X,2)) == t_POLMOD) return checknf_i(gel(X,1));
79
}
80
return NULL;
81
}
82
83
GEN
84
checkbnf(GEN x)
85
{
86
GEN bnf = checkbnf_i(x);
87
if (!bnf) pari_err_TYPE("checkbnf [please apply bnfinit()]",x);
88
return bnf;
89
}
90
91
GEN
92
checknf(GEN x)
93
{
94
GEN nf = checknf_i(x);
95
if (!nf) pari_err_TYPE("checknf [please apply nfinit()]",x);
96
return nf;
97
}
98
99
GEN
100
checkbnr_i(GEN bnr)
101
{
102
if (typ(bnr)!=t_VEC || lg(bnr)!=7 || !checkbnf_i(bnr_get_bnf(bnr)))
103
return NULL;
104
return bnr;
105
}
106
void
107
checkbnr(GEN bnr)
108
{
109
if (!checkbnr_i(bnr))
110
pari_err_TYPE("checkbnr [please apply bnrinit()]",bnr);
111
}
112
113
void
114
checksqmat(GEN x, long N)
115
{
116
if (typ(x)!=t_MAT) pari_err_TYPE("checksqmat",x);
117
if (lg(x) == 1 || lgcols(x) != N+1) pari_err_DIM("checksqmat");
118
}
119
120
GEN
121
checkbid_i(GEN bid)
122
{
123
GEN f;
124
if (typ(bid)!=t_VEC || lg(bid)!=6 || typ(bid_get_U(bid)) != t_VEC)
125
return NULL;
126
f = bid_get_mod(bid);
127
if (typ(f)!=t_VEC || lg(f)!=3) return NULL;
128
return bid;
129
}
130
void
131
checkbid(GEN bid)
132
{
133
if (!checkbid_i(bid)) pari_err_TYPE("checkbid",bid);
134
}
135
void
136
checkabgrp(GEN v)
137
{
138
if (typ(v) == t_VEC) switch(lg(v))
139
{
140
case 4: if (typ(gel(v,3)) != t_VEC) break;
141
case 3: if (typ(gel(v,2)) != t_VEC) break;
142
if (typ(gel(v,1)) != t_INT) break;
143
return;/*OK*/
144
default: break;
145
}
146
pari_err_TYPE("checkabgrp",v);
147
}
148
149
GEN
150
checknfelt_mod(GEN nf, GEN x, const char *s)
151
{
152
GEN T = gel(x,1), a = gel(x,2), Tnf = nf_get_pol(nf);
153
if (!RgX_equal_var(T, Tnf)) pari_err_MODULUS(s, T, Tnf);
154
return a;
155
}
156
157
void
158
check_ZKmodule(GEN x, const char *s)
159
{
160
if (typ(x) != t_VEC || lg(x) < 3) pari_err_TYPE(s,x);
161
if (typ(gel(x,1)) != t_MAT) pari_err_TYPE(s,gel(x,1));
162
if (typ(gel(x,2)) != t_VEC) pari_err_TYPE(s,gel(x,2));
163
if (lg(gel(x,2)) != lgcols(x)) pari_err_DIM(s);
164
}
165
166
static long
167
typv6(GEN x)
168
{
169
if (typ(gel(x,1)) == t_VEC && lg(gel(x,3)) == 3)
170
{
171
GEN t = gel(x,3);
172
if (typ(t) != t_VEC) return typ_NULL;
173
t = gel(x,5);
174
switch(typ(gel(x,5)))
175
{
176
case t_VEC: return typ_BID;
177
case t_MAT: return typ_BIDZ;
178
default: return typ_NULL;
179
}
180
}
181
if (typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT) return typ_PRID;
182
return typ_NULL;
183
}
184
185
GEN
186
get_bnf(GEN x, long *t)
187
{
188
switch(typ(x))
189
{
190
case t_POL: *t = typ_POL; return NULL;
191
case t_QUAD: *t = typ_Q ; return NULL;
192
case t_VEC:
193
switch(lg(x))
194
{
195
case 5: if (typ(gel(x,1)) != t_INT) break;
196
*t = typ_QUA; return NULL;
197
case 6: *t = typv6(x); return NULL;
198
case 7: *t = typ_BNR;
199
x = bnr_get_bnf(x);
200
if (!rawcheckbnf(x)) break;
201
return x;
202
case 9:
203
if (!v9checkgal(x)) break;
204
*t = typ_GAL; return NULL;
205
case 10:
206
if (!v10checknf(x)) break;
207
*t = typ_NF; return NULL;
208
case 11:
209
if (!v11checkbnf(x)) break;
210
*t = typ_BNF; return x;
211
case 13:
212
if (!v13checkrnf(x)) break;
213
*t = typ_RNF; return NULL;
214
case 17: *t = typ_ELL; return NULL;
215
}
216
break;
217
case t_COL:
218
if (get_prid(x)) { *t = typ_MODPR; return NULL; }
219
break;
220
}
221
*t = typ_NULL; return NULL;
222
}
223
224
GEN
225
get_nf(GEN x, long *t)
226
{
227
switch(typ(x))
228
{
229
case t_POL : *t = typ_POL; return NULL;
230
case t_QUAD: *t = typ_Q ; return NULL;
231
case t_VEC:
232
switch(lg(x))
233
{
234
case 3:
235
if (typ(gel(x,2)) != t_POLMOD) break;
236
return get_nf(gel(x,1),t);
237
case 5:
238
if (typ(gel(x,1)) != t_INT) break;
239
*t = typ_QUA; return NULL;
240
case 6: *t = typv6(x); return NULL;
241
case 7:
242
x = bnr_get_bnf(x);
243
if (!rawcheckbnf(x) || !rawchecknf(x = bnf_get_nf(x))) break;
244
*t = typ_BNR; return x;
245
case 9:
246
if (!v9checkgal(x)) break;
247
*t = typ_GAL; return NULL;
248
case 10:
249
if (!v10checknf(x)) break;
250
*t = typ_NF; return x;
251
case 11:
252
if (!rawchecknf(x = bnf_get_nf(x))) break;
253
*t = typ_BNF; return x;
254
case 13:
255
if (!v13checkrnf(x)) break;
256
*t = typ_RNF; return NULL;
257
case 17: *t = typ_ELL; return NULL;
258
}
259
break;
260
case t_QFB: *t = typ_QFB; return NULL;
261
case t_COL:
262
if (get_prid(x)) { *t = typ_MODPR; return NULL; }
263
break;
264
}
265
*t = typ_NULL; return NULL;
266
}
267
268
long
269
nftyp(GEN x)
270
{
271
switch(typ(x))
272
{
273
case t_POL : return typ_POL;
274
case t_QUAD: return typ_Q;
275
case t_VEC:
276
switch(lg(x))
277
{
278
case 13:
279
if (!v13checkrnf(x)) break;
280
return typ_RNF;
281
case 10:
282
if (!v10checknf(x)) break;
283
return typ_NF;
284
case 11:
285
if (!v11checkbnf(x)) break;
286
return typ_BNF;
287
case 7:
288
x = bnr_get_bnf(x);
289
if (!rawcheckbnf(x) || !v11checkbnf(x)) break;
290
return typ_BNR;
291
case 6:
292
return typv6(x);
293
case 9:
294
if (!v9checkgal(x)) break;
295
return typ_GAL;
296
case 17: return typ_ELL;
297
}
298
}
299
return typ_NULL;
300
}
301
302
/*************************************************************************/
303
/** **/
304
/** GALOIS GROUP **/
305
/** **/
306
/*************************************************************************/
307
308
GEN
309
tschirnhaus(GEN x)
310
{
311
pari_sp av = avma, av2;
312
long a, v = varn(x);
313
GEN u, y = cgetg(5,t_POL);
314
315
if (typ(x)!=t_POL) pari_err_TYPE("tschirnhaus",x);
316
if (lg(x) < 4) pari_err_CONSTPOL("tschirnhaus");
317
if (v) { u = leafcopy(x); setvarn(u,0); x=u; }
318
y[1] = evalsigne(1)|evalvarn(0);
319
do
320
{
321
a = random_bits(2); if (a==0) a = 1; gel(y,4) = stoi(a);
322
a = random_bits(3); if (a>=4) a -= 8; gel(y,3) = stoi(a);
323
a = random_bits(3); if (a>=4) a -= 8; gel(y,2) = stoi(a);
324
u = RgXQ_charpoly(y,x,v); av2 = avma;
325
}
326
while (degpol(RgX_gcd(u,RgX_deriv(u)))); /* while u not separable */
327
if (DEBUGLEVEL>1)
328
err_printf("Tschirnhaus transform. New pol: %Ps",u);
329
set_avma(av2); return gerepileupto(av,u);
330
}
331
332
/* Assume pol in Z[X], monic of degree n. Find L in Z such that
333
* POL = L^(-n) pol(L x) is monic in Z[X]. Return POL and set *ptk = L.
334
* No GC. */
335
GEN
336
ZX_Z_normalize(GEN pol, GEN *ptk)
337
{
338
long i,j, sk, n = degpol(pol); /* > 0 */
339
GEN k, fa, P, E, a, POL;
340
341
if (ptk) *ptk = gen_1;
342
if (!n) return pol;
343
a = pol + 2; k = gel(a,n-1); /* a[i] = coeff of degree i */
344
for (i = n-2; i >= 0; i--)
345
{
346
k = gcdii(k, gel(a,i));
347
if (is_pm1(k)) return pol;
348
}
349
sk = signe(k);
350
if (!sk) return pol; /* monomial! */
351
fa = absZ_factor_limit(k, 0); k = gen_1;
352
P = gel(fa,1);
353
E = gel(fa,2);
354
POL = leafcopy(pol); a = POL+2;
355
for (i = lg(P)-1; i > 0; i--)
356
{
357
GEN p = gel(P,i), pv, pvj;
358
long vmin = itos(gel(E,i));
359
/* find v_p(k) = min floor( v_p(a[i]) / (n-i)) */
360
for (j=n-1; j>=0; j--)
361
{
362
long v;
363
if (!signe(gel(a,j))) continue;
364
v = Z_pval(gel(a,j), p) / (n - j);
365
if (v < vmin) vmin = v;
366
}
367
if (!vmin) continue;
368
pvj = pv = powiu(p,vmin); k = mulii(k, pv);
369
/* a[j] /= p^(v*(n-j)) */
370
for (j=n-1; j>=0; j--)
371
{
372
if (j < n-1) pvj = mulii(pvj, pv);
373
gel(a,j) = diviiexact(gel(a,j), pvj);
374
}
375
}
376
if (ptk) *ptk = k;
377
return POL;
378
}
379
380
/* Assume pol != 0 in Z[X]. Find C in Q, L in Z such that POL = C pol(x/L) monic
381
* in Z[X]. Return POL and set *pL = L. Wasteful (but correct) if pol is not
382
* primitive: better if caller used Q_primpart already. No GC. */
383
GEN
384
ZX_primitive_to_monic(GEN pol, GEN *pL)
385
{
386
long i,j, n = degpol(pol);
387
GEN lc = leading_coeff(pol), L, fa, P, E, a, POL;
388
389
if (is_pm1(lc))
390
{
391
if (pL) *pL = gen_1;
392
return signe(lc) < 0? ZX_neg(pol): pol;
393
}
394
if (signe(lc) < 0)
395
POL = ZX_neg(pol);
396
else
397
POL = leafcopy(pol);
398
a = POL+2; lc = gel(a,n);
399
fa = absZ_factor_limit(lc,0); L = gen_1;
400
P = gel(fa,1);
401
E = gel(fa,2);
402
for (i = lg(P)-1; i > 0; i--)
403
{
404
GEN p = gel(P,i), pk, pku;
405
long v, j0, e = itos(gel(E,i)), k = e/n, d = k*n - e;
406
407
if (d < 0) { k++; d += n; }
408
/* k = ceil(e[i] / n); find d, k such that p^d pol(x / p^k) monic */
409
for (j=n-1; j>0; j--)
410
{
411
if (!signe(gel(a,j))) continue;
412
v = Z_pval(gel(a,j), p);
413
while (v + d < k * j) { k++; d += n; }
414
}
415
pk = powiu(p,k); j0 = d/k;
416
L = mulii(L, pk);
417
418
pku = powiu(p,d - k*j0);
419
/* a[j] *= p^(d - kj) */
420
for (j=j0; j>=0; j--)
421
{
422
if (j < j0) pku = mulii(pku, pk);
423
gel(a,j) = mulii(gel(a,j), pku);
424
}
425
j0++;
426
pku = powiu(p,k*j0 - d);
427
/* a[j] /= p^(kj - d) */
428
for (j=j0; j<=n; j++)
429
{
430
if (j > j0) pku = mulii(pku, pk);
431
gel(a,j) = diviiexact(gel(a,j), pku);
432
}
433
}
434
if (pL) *pL = L;
435
return POL;
436
}
437
/* Assume pol != 0 in Z[X]. Find C,L in Q such that POL = C pol(x/L)
438
* monic in Z[X]. Return POL and set *pL = L.
439
* Wasteful (but correct) if pol is not primitive: better if caller used
440
* Q_primpart already. No GC. */
441
GEN
442
ZX_Q_normalize(GEN pol, GEN *pL)
443
{
444
GEN lc, POL = ZX_primitive_to_monic(pol, &lc);
445
POL = ZX_Z_normalize(POL, pL);
446
if (pL) *pL = gdiv(lc, *pL);
447
return POL;
448
}
449
450
GEN
451
ZX_Q_mul(GEN A, GEN z)
452
{
453
pari_sp av = avma;
454
long i, l = lg(A);
455
GEN d, n, Ad, B, u;
456
if (typ(z)==t_INT) return ZX_Z_mul(A,z);
457
n = gel(z, 1); d = gel(z, 2);
458
Ad = RgX_to_RgC(FpX_red(A, d), l-2);
459
u = gcdii(d, FpV_factorback(Ad, NULL, d));
460
B = cgetg(l, t_POL);
461
B[1] = A[1];
462
if (equali1(u))
463
{
464
for(i=2; i<l; i++)
465
gel(B, i) = mkfrac(mulii(n, gel(A,i)), d);
466
} else
467
{
468
for(i=2; i<l; i++)
469
{
470
GEN di = gcdii(gel(Ad, i-1), u);
471
GEN ni = mulii(n, diviiexact(gel(A,i), di));
472
if (equalii(d, di))
473
gel(B, i) = ni;
474
else
475
gel(B, i) = mkfrac(ni, diviiexact(d, di));
476
}
477
}
478
return gerepilecopy(av, B);
479
}
480
481
/* pol != 0 in Z[x], returns a monic polynomial POL in Z[x] generating the
482
* same field: there exist C in Q, L in Z such that POL(x) = C pol(x/L).
483
* Set *L = NULL if L = 1, and to L otherwise. No garbage collecting. */
484
GEN
485
ZX_to_monic(GEN pol, GEN *L)
486
{
487
long n = lg(pol)-1;
488
GEN lc = gel(pol,n);
489
if (is_pm1(lc)) { *L = gen_1; return signe(lc) > 0? pol: ZX_neg(pol); }
490
return ZX_primitive_to_monic(Q_primpart(pol), L);
491
}
492
493
GEN
494
ZXX_Q_mul(GEN A, GEN z)
495
{
496
long i, l;
497
GEN B;
498
if (typ(z)==t_INT) return ZXX_Z_mul(A,z);
499
B = cgetg_copy(A, &l);
500
B[1] = A[1];
501
for (i=2; i<l; i++)
502
{
503
GEN Ai = gel(A,i);
504
gel(B,i) = typ(Ai)==t_POL ? ZX_Q_mul(Ai, z): gmul(Ai, z);
505
}
506
return B;
507
}
508
509
/* Evaluate pol in s using nfelt arithmetic and Horner rule */
510
GEN
511
nfpoleval(GEN nf, GEN pol, GEN s)
512
{
513
pari_sp av=avma;
514
long i=lg(pol)-1;
515
GEN res;
516
if (i==1) return gen_0;
517
res = nf_to_scalar_or_basis(nf, gel(pol,i));
518
for (i-- ; i>=2; i--)
519
res = nfadd(nf, nfmul(nf, s, res), gel(pol,i));
520
return gerepileupto(av, res);
521
}
522
523
static GEN
524
QX_table_nfpoleval(GEN nf, GEN pol, GEN m)
525
{
526
pari_sp av = avma;
527
long i = lg(pol)-1;
528
GEN res, den;
529
if (i==1) return gen_0;
530
pol = Q_remove_denom(pol, &den);
531
res = scalarcol_shallow(gel(pol,i), nf_get_degree(nf));
532
for (i-- ; i>=2; i--)
533
res = ZC_Z_add(ZM_ZC_mul(m, res), gel(pol,i));
534
if (den) res = RgC_Rg_div(res, den);
535
return gerepileupto(av, res);
536
}
537
538
GEN
539
FpX_FpC_nfpoleval(GEN nf, GEN pol, GEN a, GEN p)
540
{
541
pari_sp av=avma;
542
long i=lg(pol)-1, n=nf_get_degree(nf);
543
GEN res, Ma;
544
if (i==1) return zerocol(n);
545
Ma = FpM_red(zk_multable(nf, a), p);
546
res = scalarcol(gel(pol,i),n);
547
for (i-- ; i>=2; i--)
548
{
549
res = FpM_FpC_mul(Ma, res, p);
550
gel(res,1) = Fp_add(gel(res,1), gel(pol,i), p);
551
}
552
return gerepileupto(av, res);
553
}
554
555
/* compute s(x), not stack clean */
556
static GEN
557
ZC_galoisapply(GEN nf, GEN s, GEN x)
558
{
559
x = nf_to_scalar_or_alg(nf, x);
560
if (typ(x) != t_POL) return scalarcol(x, nf_get_degree(nf));
561
return QX_table_nfpoleval(nf, x, zk_multable(nf, s));
562
}
563
564
/* true nf; S = automorphism in basis form, return an FpC = S(z) mod p */
565
GEN
566
zk_galoisapplymod(GEN nf, GEN z, GEN S, GEN p)
567
{
568
GEN den, pe, pe1, denpe, R;
569
570
z = nf_to_scalar_or_alg(nf, z);
571
if (typ(z) != t_POL) return z;
572
if (gequalX(z)) return FpC_red(S, p); /* common, e.g. modpr_genFq */
573
z = Q_remove_denom(z,&den);
574
denpe = pe = NULL;
575
pe1 = p;
576
if (den)
577
{
578
ulong e = Z_pvalrem(den, p, &den);
579
if (e) { pe = powiu(p, e); pe1 = mulii(pe, p); }
580
denpe = Fp_inv(den, pe1);
581
}
582
R = FpX_FpC_nfpoleval(nf, FpX_red(z, pe1), FpC_red(S, pe1), pe1);
583
if (denpe) R = FpC_Fp_mul(R, denpe, pe1);
584
if (pe) R = gdivexact(R, pe);
585
return R;
586
}
587
588
/* true nf */
589
static GEN
590
pr_make(GEN nf, GEN p, GEN u, GEN e, GEN f)
591
{
592
GEN t = FpM_deplin(zk_multable(nf, u), p);
593
t = zk_scalar_or_multable(nf, t);
594
return mkvec5(p, u, e, f, t);
595
}
596
static GEN
597
pr_galoisapply(GEN nf, GEN pr, GEN aut)
598
{
599
GEN p = pr_get_p(pr), u = zk_galoisapplymod(nf, pr_get_gen(pr), aut, p);
600
return pr_make(nf, p, u, gel(pr,3), gel(pr,4));
601
}
602
static GEN
603
pr_galoismatrixapply(GEN nf, GEN pr, GEN M)
604
{
605
GEN p = pr_get_p(pr), u = FpC_red(ZM_ZC_mul(M, pr_get_gen(pr)), p);
606
return pr_make(nf, p, u, gel(pr,3), gel(pr,4));
607
}
608
609
static GEN
610
vecgaloisapply(GEN nf, GEN aut, GEN x)
611
{ pari_APPLY_same(galoisapply(nf, aut, gel(x,i))); }
612
static GEN
613
vecgaloismatrixapply(GEN nf, GEN aut, GEN x)
614
{ pari_APPLY_same(nfgaloismatrixapply(nf, aut, gel(x,i))); }
615
616
/* x: famat or standard algebraic number, aut automorphism in ZC form
617
* simplified from general galoisapply */
618
static GEN
619
elt_galoisapply(GEN nf, GEN aut, GEN x)
620
{
621
pari_sp av = avma;
622
switch(typ(x))
623
{
624
case t_INT: return icopy(x);
625
case t_FRAC: return gcopy(x);
626
case t_POLMOD: x = gel(x,2); /* fall through */
627
case t_POL: {
628
GEN y = basistoalg(nf, ZC_galoisapply(nf, aut, x));
629
return gerepileupto(av,y);
630
}
631
case t_COL:
632
return gerepileupto(av, ZC_galoisapply(nf, aut, x));
633
case t_MAT:
634
switch(lg(x)) {
635
case 1: return cgetg(1, t_MAT);
636
case 3: retmkmat2(vecgaloisapply(nf,aut,gel(x,1)), ZC_copy(gel(x,2)));
637
}
638
}
639
pari_err_TYPE("galoisapply",x);
640
return NULL; /* LCOV_EXCL_LINE */
641
}
642
/* M automorphism in matrix form */
643
static GEN
644
elt_galoismatrixapply(GEN nf, GEN M, GEN x)
645
{
646
if (typ(x) == t_MAT)
647
switch(lg(x)) {
648
case 1: return cgetg(1, t_MAT);
649
case 3: retmkmat2(vecgaloismatrixapply(nf,M,gel(x,1)), ZC_copy(gel(x,2)));
650
}
651
return nfgaloismatrixapply(nf, M, x);
652
}
653
654
GEN
655
galoisapply(GEN nf, GEN aut, GEN x)
656
{
657
pari_sp av = avma;
658
long lx;
659
GEN y;
660
661
nf = checknf(nf);
662
switch(typ(x))
663
{
664
case t_INT: return icopy(x);
665
case t_FRAC: return gcopy(x);
666
667
case t_POLMOD: x = gel(x,2); /* fall through */
668
case t_POL:
669
aut = algtobasis(nf, aut);
670
y = basistoalg(nf, ZC_galoisapply(nf, aut, x));
671
return gerepileupto(av,y);
672
673
case t_VEC:
674
aut = algtobasis(nf, aut);
675
switch(lg(x))
676
{
677
case 6:
678
if (pr_is_inert(x)) { set_avma(av); return gcopy(x); }
679
return gerepilecopy(av, pr_galoisapply(nf, x, aut));
680
case 3: y = cgetg(3,t_VEC);
681
gel(y,1) = galoisapply(nf, aut, gel(x,1));
682
gel(y,2) = elt_galoisapply(nf, aut, gel(x,2));
683
return gerepileupto(av, y);
684
}
685
break;
686
687
case t_COL:
688
aut = algtobasis(nf, aut);
689
return gerepileupto(av, ZC_galoisapply(nf, aut, x));
690
691
case t_MAT: /* ideal */
692
lx = lg(x); if (lx==1) return cgetg(1,t_MAT);
693
if (nbrows(x) != nf_get_degree(nf)) break;
694
y = RgM_mul(nfgaloismatrix(nf,aut), x);
695
return gerepileupto(av, idealhnf_shallow(nf,y));
696
}
697
pari_err_TYPE("galoisapply",x);
698
return NULL; /* LCOV_EXCL_LINE */
699
}
700
701
/* M automorphism in galoismatrix form */
702
GEN
703
nfgaloismatrixapply(GEN nf, GEN M, GEN x)
704
{
705
pari_sp av = avma;
706
long lx;
707
GEN y;
708
709
nf = checknf(nf);
710
switch(typ(x))
711
{
712
case t_INT: return icopy(x);
713
case t_FRAC: return gcopy(x);
714
715
case t_POLMOD: x = gel(x,2); /* fall through */
716
case t_POL:
717
x = algtobasis(nf, x);
718
return gerepileupto(av, basistoalg(nf, RgM_RgC_mul(M, x)));
719
720
case t_VEC:
721
switch(lg(x))
722
{
723
case 6:
724
if (pr_is_inert(x)) { set_avma(av); return gcopy(x); }
725
return gerepilecopy(av, pr_galoismatrixapply(nf, x, M));
726
case 3: y = cgetg(3,t_VEC);
727
gel(y,1) = nfgaloismatrixapply(nf, M, gel(x,1));
728
gel(y,2) = elt_galoismatrixapply(nf, M, gel(x,2));
729
return gerepileupto(av, y);
730
}
731
break;
732
733
case t_COL: return RgM_RgC_mul(M, x);
734
735
case t_MAT: /* ideal */
736
lx = lg(x); if (lx==1) return cgetg(1,t_MAT);
737
if (nbrows(x) != nf_get_degree(nf)) break;
738
return gerepileupto(av, idealhnf_shallow(nf,RgM_mul(M, x)));
739
}
740
pari_err_TYPE("galoisapply",x);
741
return NULL; /* LCOV_EXCL_LINE */
742
}
743
744
/* compute action of automorphism s on nf.zk */
745
GEN
746
nfgaloismatrix(GEN nf, GEN s)
747
{
748
pari_sp av2, av = avma;
749
GEN zk, D, M, H, m;
750
long k, n;
751
752
nf = checknf(nf);
753
zk = nf_get_zkprimpart(nf); n = lg(zk)-1;
754
M = cgetg(n+1, t_MAT);
755
gel(M,1) = col_ei(n, 1); /* s(1) = 1 */
756
if (n == 1) return M;
757
av2 = avma;
758
if (typ(s) != t_COL) s = algtobasis(nf, s);
759
D = nf_get_zkden(nf);
760
H = RgV_to_RgM(zk, n);
761
if (n == 2)
762
{
763
GEN t = gel(H,2); /* D * s(w_2) */
764
t = ZC_Z_add(ZC_Z_mul(s, gel(t,2)), gel(t,1));
765
gel(M,2) = gerepileupto(av2, gdiv(t, D));
766
return M;
767
}
768
m = zk_multable(nf, s);
769
gel(M,2) = s; /* M[,k] = s(x^(k-1)) */
770
for (k = 3; k <= n; k++) gel(M,k) = ZM_ZC_mul(m, gel(M,k-1));
771
M = ZM_mul(M, H);
772
if (!equali1(D)) M = ZM_Z_divexact(M, D);
773
return gerepileupto(av, M);
774
}
775
776
static GEN
777
get_aut(GEN nf, GEN gal, GEN aut, GEN g)
778
{
779
return aut ? gel(aut, g[1]): poltobasis(nf, galoispermtopol(gal, g));
780
}
781
782
static GEN
783
idealquasifrob(GEN nf, GEN gal, GEN grp, GEN pr, GEN subg, GEN *S, GEN aut)
784
{
785
pari_sp av = avma;
786
long i, n = nf_get_degree(nf), f = pr_get_f(pr);
787
GEN pi = pr_get_gen(pr);
788
for (i=1; i<=n; i++)
789
{
790
GEN g = gel(grp,i);
791
if ((!subg && perm_orderu(g) == (ulong)f)
792
|| (subg && perm_relorder(g, subg)==f))
793
{
794
*S = get_aut(nf, gal, aut, g);
795
if (ZC_prdvd(ZC_galoisapply(nf, *S, pi), pr)) return g;
796
set_avma(av);
797
}
798
}
799
pari_err_BUG("idealquasifrob [Frobenius not found]");
800
return NULL;/*LCOV_EXCL_LINE*/
801
}
802
803
GEN
804
nfgaloispermtobasis(GEN nf, GEN gal)
805
{
806
GEN grp = gal_get_group(gal);
807
long i, n = lg(grp)-1;
808
GEN aut = cgetg(n+1, t_VEC);
809
for(i=1; i<=n; i++)
810
{
811
pari_sp av = avma;
812
GEN g = gel(grp, i);
813
GEN vec = poltobasis(nf, galoispermtopol(gal, g));
814
gel(aut, g[1]) = gerepileupto(av, vec);
815
}
816
return aut;
817
}
818
819
static void
820
gal_check_pol(const char *f, GEN x, GEN y)
821
{ if (!RgX_equal_var(x,y)) pari_err_MODULUS(f,x,y); }
822
823
/* true nf */
824
GEN
825
idealfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN aut)
826
{
827
pari_sp av = avma;
828
GEN S=NULL, g=NULL; /*-Wall*/
829
GEN T, p, a, b, modpr;
830
long f, n, s;
831
f = pr_get_f(pr); n = nf_get_degree(nf);
832
if (f==1) { set_avma(av); return identity_perm(n); }
833
g = idealquasifrob(nf, gal, gal_get_group(gal), pr, NULL, &S, aut);
834
if (f==2) return gerepileuptoleaf(av, g);
835
modpr = zk_to_Fq_init(nf,&pr,&T,&p);
836
a = pol_x(nf_get_varn(nf));
837
b = nf_to_Fq(nf, zk_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr);
838
for (s = 1; s < f-1; s++)
839
{
840
a = Fq_pow(a, p, T, p);
841
if (ZX_equal(a, b)) break;
842
}
843
g = perm_powu(g, Fl_inv(s, f));
844
return gerepileupto(av, g);
845
}
846
847
GEN
848
idealfrobenius(GEN nf, GEN gal, GEN pr)
849
{
850
nf = checknf(nf);
851
checkgal(gal);
852
checkprid(pr);
853
gal_check_pol("idealfrobenius",nf_get_pol(nf),gal_get_pol(gal));
854
if (pr_get_e(pr)>1) pari_err_DOMAIN("idealfrobenius","pr.e", ">", gen_1,pr);
855
return idealfrobenius_aut(nf, gal, pr, NULL);
856
}
857
858
/* true nf */
859
GEN
860
idealramfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN ram, GEN aut)
861
{
862
pari_sp av = avma;
863
GEN S=NULL, g=NULL; /*-Wall*/
864
GEN T, p, a, b, modpr;
865
GEN isog, deco;
866
long f, n, s;
867
f = pr_get_f(pr); n = nf_get_degree(nf);
868
if (f==1) { set_avma(av); return identity_perm(n); }
869
modpr = zk_to_Fq_init(nf,&pr,&T,&p);
870
deco = group_elts(gel(ram,1), nf_get_degree(nf));
871
isog = group_set(gel(ram,2), nf_get_degree(nf));
872
g = idealquasifrob(nf, gal, deco, pr, isog, &S, aut);
873
a = pol_x(nf_get_varn(nf));
874
b = nf_to_Fq(nf, zk_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr);
875
for (s=0; !ZX_equal(a, b); s++)
876
a = Fq_pow(a, p, T, p);
877
g = perm_powu(g, Fl_inv(s, f));
878
return gerepileupto(av, g);
879
}
880
881
GEN
882
idealramfrobenius(GEN nf, GEN gal, GEN pr, GEN ram)
883
{
884
return idealramfrobenius_aut(nf, gal, pr, ram, NULL);
885
}
886
887
static GEN
888
idealinertiagroup(GEN nf, GEN gal, GEN aut, GEN pr)
889
{
890
long i, n = nf_get_degree(nf);
891
GEN p, T, modpr = zk_to_Fq_init(nf,&pr,&T,&p);
892
GEN b = modpr_genFq(modpr);
893
long e = pr_get_e(pr), coprime = ugcd(e, pr_get_f(pr)) == 1;
894
GEN grp = gal_get_group(gal), pi = pr_get_gen(pr);
895
pari_sp ltop = avma;
896
for (i=1; i<=n; i++)
897
{
898
GEN iso = gel(grp,i);
899
if (perm_orderu(iso) == (ulong)e)
900
{
901
GEN S = get_aut(nf, gal, aut, iso);
902
if (ZC_prdvd(ZC_galoisapply(nf, S, pi), pr)
903
&& (coprime || gequalX(nf_to_Fq(nf, galoisapply(nf,S,b), modpr))))
904
return iso;
905
set_avma(ltop);
906
}
907
}
908
pari_err_BUG("idealinertiagroup [no isotropic element]");
909
return NULL;/*LCOV_EXCL_LINE*/
910
}
911
912
static GEN
913
idealramgroupstame(GEN nf, GEN gal, GEN aut, GEN pr)
914
{
915
pari_sp av = avma;
916
GEN iso, frob, giso, isog, S, res;
917
long e = pr_get_e(pr), f = pr_get_f(pr);
918
GEN grp = gal_get_group(gal);
919
if (e == 1)
920
{
921
if (f==1)
922
return cgetg(1,t_VEC);
923
frob = idealquasifrob(nf, gal, grp, pr, NULL, &S, aut);
924
set_avma(av);
925
res = cgetg(2, t_VEC);
926
gel(res, 1) = cyclicgroup(frob, f);
927
return res;
928
}
929
res = cgetg(3, t_VEC);
930
av = avma;
931
iso = idealinertiagroup(nf, gal, aut, pr);
932
set_avma(av);
933
giso = cyclicgroup(iso, e);
934
gel(res, 2) = giso;
935
if (f==1)
936
{
937
gel(res, 1) = giso;
938
return res;
939
}
940
av = avma;
941
isog = group_set(giso, nf_get_degree(nf));
942
frob = idealquasifrob(nf, gal, grp, pr, isog, &S, aut);
943
set_avma(av);
944
gel(res, 1) = dicyclicgroup(iso,frob,e,f);
945
return res;
946
}
947
948
/* true nf, p | e */
949
static GEN
950
idealramgroupswild(GEN nf, GEN gal, GEN aut, GEN pr)
951
{
952
pari_sp av2, av = avma;
953
GEN p, T, idx, g, gbas, pi, pibas, Dpi, modpr = zk_to_Fq_init(nf,&pr,&T,&p);
954
long bound, i, vDpi, vDg, n = nf_get_degree(nf);
955
long e = pr_get_e(pr);
956
long f = pr_get_f(pr);
957
ulong nt,rorder;
958
GEN pg, ppi, grp = gal_get_group(gal);
959
960
/* G_i = {s: v(s(pi) - pi) > i} trivial for i > bound;
961
* v_pr(Diff) = sum_{i = 0}^{bound} (#G_i - 1) >= e-1 + bound*(p-1)*/
962
bound = (idealval(nf, nf_get_diff(nf), pr) - (e-1)) / (itou(p)-1);
963
(void) u_pvalrem(n,p,&nt);
964
rorder = e*f*(n/nt);
965
idx = const_vecsmall(n,-1);
966
pg = NULL;
967
vDg = 0;
968
if (f == 1)
969
g = gbas = NULL;
970
else
971
{
972
GEN Dg;
973
g = nf_to_scalar_or_alg(nf, modpr_genFq(modpr));
974
if (!gequalX(g)) /* p | nf.index */
975
{
976
g = Q_remove_denom(g, &Dg);
977
vDg = Z_pval(Dg,p);
978
pg = powiu(p, vDg + 1);
979
g = FpX_red(g, pg);
980
}
981
gbas = nf_to_scalar_or_basis(nf, g);
982
}
983
pi = nf_to_scalar_or_alg(nf, pr_get_gen(pr));
984
pi = Q_remove_denom(pi, &Dpi);
985
vDpi = Dpi ? Z_pval(Dpi, p): 0;
986
ppi = powiu(p, vDpi + (bound + e)/e);
987
pi = FpX_red(pi, ppi);
988
pibas = nf_to_scalar_or_basis(nf, pi);
989
av2 = avma;
990
for (i = 2; i <= n; i++)
991
{
992
GEN S, Spi, piso, iso = gel(grp, i);
993
long j, o, ix = iso[1];
994
if (idx[ix] >= 0 || rorder % (o = (long)perm_orderu(iso))) continue;
995
996
piso = iso;
997
S = get_aut(nf, gal, aut, iso);
998
Spi = FpX_FpC_nfpoleval(nf, pi, FpC_red(S, ppi), ppi);
999
/* Computation made knowing that the valuation is <= bound + 1. Correct
1000
* to maximal value if reduction mod ppi altered this */
1001
idx[ix] = minss(bound+1, idealval(nf, gsub(Spi,pibas), pr) - e*vDpi);
1002
if (idx[ix] == 0) idx[ix] = -1;
1003
else if (g)
1004
{
1005
GEN Sg = pg? FpX_FpC_nfpoleval(nf, g, FpC_red(S, pg), pg): S;
1006
if (vDg)
1007
{ if (nfval(nf, gsub(Sg, gbas), pr) - e*vDg <= 0) idx[ix] = 0; }
1008
else /* same, more efficient */
1009
{ if (!ZC_prdvd(gsub(Sg, gbas), pr)) idx[ix] = 0; }
1010
}
1011
for (j = 2; j < o; j++)
1012
{
1013
piso = perm_mul(piso,iso);
1014
if (ugcd(j,o)==1) idx[ piso[1] ] = idx[ix];
1015
}
1016
set_avma(av2);
1017
}
1018
return gerepileuptoleaf(av, idx);
1019
}
1020
1021
GEN
1022
idealramgroups_aut(GEN nf, GEN gal, GEN pr, GEN aut)
1023
{
1024
pari_sp av = avma;
1025
GEN tbl, idx, res, set, sub;
1026
long i, j, e, n, maxm, p;
1027
ulong et;
1028
nf = checknf(nf);
1029
checkgal(gal);
1030
checkprid(pr);
1031
gal_check_pol("idealramgroups",nf_get_pol(nf),gal_get_pol(gal));
1032
e = pr_get_e(pr); n = nf_get_degree(nf);
1033
p = itos(pr_get_p(pr));
1034
if (e%p) return idealramgroupstame(nf, gal, aut, pr);
1035
(void) u_lvalrem(e,p,&et);
1036
idx = idealramgroupswild(nf, gal, aut, pr);
1037
sub = group_subgroups(galois_group(gal));
1038
tbl = subgroups_tableset(sub, n);
1039
maxm = vecsmall_max(idx)+1;
1040
res = cgetg(maxm+1,t_VEC);
1041
set = zero_F2v(n); F2v_set(set,1);
1042
for(i=maxm; i>0; i--)
1043
{
1044
long ix;
1045
for(j=1;j<=n;j++)
1046
if (idx[j]==i-1)
1047
F2v_set(set,j);
1048
ix = tableset_find_index(tbl, set);
1049
if (ix==0) pari_err_BUG("idealramgroups");
1050
gel(res,i) = gel(sub, ix);
1051
}
1052
return gerepilecopy(av, res);
1053
}
1054
1055
GEN
1056
idealramgroups(GEN nf, GEN gal, GEN pr)
1057
{
1058
return idealramgroups_aut(nf, gal, pr, NULL);
1059
}
1060
1061
/* x = relative polynomial nf = absolute nf, bnf = absolute bnf */
1062
GEN
1063
get_bnfpol(GEN x, GEN *bnf, GEN *nf)
1064
{
1065
*bnf = checkbnf_i(x);
1066
*nf = checknf_i(x);
1067
if (*nf) x = nf_get_pol(*nf);
1068
if (typ(x) != t_POL) pari_err_TYPE("get_bnfpol",x);
1069
return x;
1070
}
1071
1072
GEN
1073
get_nfpol(GEN x, GEN *nf)
1074
{
1075
if (typ(x) == t_POL) { *nf = NULL; return x; }
1076
*nf = checknf(x); return nf_get_pol(*nf);
1077
}
1078
1079
static GEN
1080
incl_disc(GEN nfa, GEN a, int nolocal)
1081
{
1082
GEN d;
1083
if (nfa) return nf_get_disc(nfa);
1084
if (nolocal) return NULL;
1085
d = ZX_disc(a);
1086
if (!signe(d)) pari_err_IRREDPOL("nfisincl",a);
1087
return d;
1088
}
1089
1090
static int
1091
badp(GEN fa, GEN db, long q)
1092
{
1093
GEN P = gel(fa,1), E = gel(fa,2);
1094
long i, l = lg(P);
1095
for (i = 1; i < l; i++)
1096
if (mod2(gel(E,i)) && !dvdii(db, powiu(gel(P,i),q))) return 1;
1097
return 0;
1098
}
1099
1100
/* is isomorphism / inclusion (a \subset b) compatible with what we know about
1101
* basic invariants ? (degree, signature, discriminant); test for isomorphism
1102
* if fliso is set and for inclusion otherwise */
1103
static int
1104
tests_OK(GEN a, GEN nfa, GEN b, GEN nfb, long fliso)
1105
{
1106
GEN da2, da, db, fa, P, U;
1107
long i, l, q, m = degpol(a), n = degpol(b);
1108
1109
if (m <= 0) pari_err_IRREDPOL("nfisincl",a);
1110
if (n <= 0) pari_err_IRREDPOL("nfisincl",b);
1111
q = n / m; /* relative degree */
1112
if (fliso) { if (n != m) return 0; } else { if (n % m) return 0; }
1113
if (m == 1) return 1;
1114
1115
/*local test expensive if n^2 >> m^4 <=> q = n/m >> m */
1116
db = incl_disc(nfb, b, q > m);
1117
da = db? incl_disc(nfa, a, 0): NULL;
1118
if (nfa && nfb) /* both nf structures available */
1119
{
1120
long r1a = nf_get_r1(nfa), r1b = nf_get_r1(nfb);
1121
return fliso ? (r1a == r1b && equalii(da, db))
1122
: (r1b <= r1a * q && dvdii(db, powiu(da, q)));
1123
}
1124
if (!db) return 1;
1125
if (fliso) return issquare(gdiv(da,db));
1126
1127
if (nfa)
1128
{
1129
P = nf_get_ramified_primes(nfa); l = lg(P);
1130
for (i = 1; i < l; i++)
1131
if (Z_pval(db, gel(P,i)) < q * Z_pval(da, gel(P,i))) return 0;
1132
return 1;
1133
}
1134
else if (nfb)
1135
{
1136
P = nf_get_ramified_primes(nfb); l = lg(P);
1137
for (i = 1; i < l; i++)
1138
{
1139
GEN p = gel(P,i);
1140
long va = Z_pval(nfdisc(mkvec2(a, mkvec(p))), p);
1141
if (va && Z_pval(db, gel(P,i)) < va * q) return 0;
1142
}
1143
return 1;
1144
}
1145
/* da = dK A^2, db = dL B^2, dL = dK^q * N(D)
1146
* da = da1 * da2, da2 maximal s.t. (da2, db) = 1: let p a prime divisor of
1147
* da2 then p \nmid da1 * dK and p | A => v_p(da) = v_p(da2) is even */
1148
da2 = Z_ppo(da, db);
1149
if (!is_pm1(da2))
1150
{ /* replace da by da1 all of whose prime divisors divide db */
1151
da2 = absi_shallow(da2);
1152
if (!Z_issquare(da2)) return 0;
1153
da = diviiexact(da, da2);
1154
}
1155
if (is_pm1(da)) return 1;
1156
fa = absZ_factor_limit_strict(da, 0, &U);
1157
if (badp(fa, db, q)) return 0;
1158
if (U && mod2(gel(U,2)) && expi(gel(U,1)) < 150)
1159
{ /* cofactor is small, finish */
1160
fa = absZ_factor(gel(U,1));
1161
if (badp(fa, db, q)) return 0;
1162
}
1163
return 1;
1164
}
1165
1166
GEN
1167
nfisisom(GEN a, GEN b)
1168
{
1169
pari_sp av = avma;
1170
long i, va, vb, lx;
1171
GEN nfa, nfb, y, la, lb;
1172
int newvar, sw = 0;
1173
1174
a = get_nfpol(a, &nfa);
1175
b = get_nfpol(b, &nfb);
1176
if (!nfa) { a = Q_primpart(a); RgX_check_ZX(a, "nfisisom"); }
1177
if (!nfb) { b = Q_primpart(b); RgX_check_ZX(b, "nfisisom"); }
1178
if (nfa && !nfb) { swap(a,b); nfb = nfa; nfa = NULL; sw = 1; }
1179
if (!tests_OK(a, nfa, b, nfb, 1)) { set_avma(av); return gen_0; }
1180
1181
if (nfb) lb = gen_1; else nfb = b = ZX_Q_normalize(b,&lb);
1182
if (nfa) la = gen_1; else nfa = a = ZX_Q_normalize(a,&la);
1183
va = varn(a); vb = varn(b); newvar = (varncmp(vb,va) <= 0);
1184
if (newvar) { a = leafcopy(a); setvarn(a, fetch_var_higher()); }
1185
y = lift_shallow(nfroots(nfb,a));
1186
if (newvar) (void)delete_var();
1187
lx = lg(y); if (lx==1) { set_avma(av); return gen_0; }
1188
if (sw) { vb = va; b = leafcopy(b); setvarn(b, vb); }
1189
for (i=1; i<lx; i++)
1190
{
1191
GEN t = gel(y,i);
1192
if (typ(t) == t_POL) setvarn(t, vb); else t = scalarpol(t, vb);
1193
if (lb != gen_1) t = RgX_unscale(t, lb);
1194
if (la != gen_1) t = RgX_Rg_div(t, la);
1195
gel(y,i) = sw? RgXQ_reverse(t, b): t;
1196
}
1197
return gerepilecopy(av,y);
1198
}
1199
1200
static GEN
1201
partmap_reverse(GEN a, GEN b, GEN t, GEN la, GEN lb, long v)
1202
{
1203
pari_sp av = avma;
1204
GEN rnf = rnfequation2(a, t), z;
1205
if (!RgX_equal(b, gel(rnf,1)))
1206
{ setvarn(b,v); pari_err_IRREDPOL("nfisincl", b); }
1207
z = liftpol_shallow(gel(rnf, 2));
1208
setvarn(z, v);
1209
if (!isint1(lb)) z = RgX_unscale(z, lb);
1210
if (!isint1(la)) z = RgX_Rg_div(z, la);
1211
return gerepilecopy(av, z);
1212
}
1213
1214
static GEN
1215
partmap_reverse_frac(GEN a, GEN b, GEN t, GEN la, GEN lb, long v)
1216
{
1217
pari_sp av = avma;
1218
long k = 0;
1219
GEN N, D, G, L, de;
1220
GEN C = ZX_ZXY_resultant_all(a, Q_remove_denom(t,&de), &k, &L);
1221
if (k || degpol(b) != degpol(C))
1222
{ setvarn(b,v); pari_err_IRREDPOL("nfisincl", b); }
1223
N = RgX_neg(gel(L,1)); D = gel(L,2);
1224
setvarn(N, v); setvarn(D, v);
1225
G = QX_gcd(N,D);
1226
if (degpol(G))
1227
{
1228
N = RgX_div(N,G); D = RgX_div(D,G);
1229
}
1230
if (!isint1(lb)) { N = RgX_unscale(N, lb); D = RgX_unscale(D, lb); }
1231
if (!isint1(la)) D = RgX_Rg_mul(D, la);
1232
return gerepilecopy(av, mkrfrac(N,D));
1233
}
1234
1235
static GEN
1236
nfisincl_from_fact(GEN a, long da, GEN b, GEN la, GEN lb, long vb, GEN y, long flag)
1237
{
1238
long i, k, lx = lg(y);
1239
long db = degpol(b), d = db/da;
1240
GEN x = cgetg(lx, t_VEC);
1241
for (i=1, k=1; i<lx; i++)
1242
{
1243
GEN t = gel(y,i);
1244
if (degpol(t)!=d) continue;
1245
gel(x, k++) = partmap_reverse(a, b, t, la, lb, vb);
1246
if (flag==1) return gel(x,1);
1247
}
1248
if (k==1) return gen_0;
1249
setlg(x, k);
1250
gen_sort_inplace(x, (void*)&cmp_RgX, &cmp_nodata, NULL);
1251
return x;
1252
}
1253
1254
static GEN
1255
nfisincl_from_fact_frac(GEN a, GEN b, GEN la, GEN lb, long vb, GEN y)
1256
{
1257
long i, k, lx = lg(y);
1258
long da = degpol(a), db = degpol(b), d = db/da;
1259
GEN x = cgetg(lx, t_VEC);
1260
for (i=1, k=1; i<lx; i++)
1261
{
1262
GEN t = gel(y,i);
1263
if (degpol(t)!=d) continue;
1264
gel(x, k++) = partmap_reverse_frac(a, b, t, la, lb, vb);
1265
}
1266
if (k==1) return gen_0;
1267
setlg(x, k);
1268
return x;
1269
}
1270
1271
GEN
1272
nfisincl0(GEN fa, GEN fb, long flag)
1273
{
1274
pari_sp av = avma;
1275
long vb;
1276
GEN a, b, nfa, nfb, x, y, la, lb;
1277
int newvar;
1278
if (flag < 0 || flag > 3) pari_err_FLAG("nfisincl");
1279
1280
a = get_nfpol(fa, &nfa);
1281
b = get_nfpol(fb, &nfb);
1282
if (!nfa) { a = Q_primpart(a); RgX_check_ZX(a, "nsisincl"); }
1283
if (!nfb) { b = Q_primpart(b); RgX_check_ZX(b, "nsisincl"); }
1284
if (ZX_equal(a, b) && flag<=1)
1285
{
1286
if (flag==1)
1287
{
1288
x = pol_x(varn(b));
1289
return degpol(b) > 1 ? x: RgX_rem(x,b);
1290
}
1291
x = galoisconj(fb, NULL); settyp(x, t_VEC);
1292
return gerepilecopy(av,x);
1293
}
1294
if (flag==0 && !tests_OK(a, nfa, b, nfb, 0)) { set_avma(av); return gen_0; }
1295
1296
if (nfb) lb = gen_1; else nfb = b = ZX_Q_normalize(b,&lb);
1297
if (nfa) la = gen_1; else nfa = a = ZX_Q_normalize(a,&la);
1298
vb = varn(b); newvar = (varncmp(varn(a),vb) <= 0);
1299
if (newvar) { b = leafcopy(b); setvarn(b, fetch_var_higher()); }
1300
y = lift_shallow(gel(nffactor(nfa,b),1));
1301
if (flag>=2)
1302
x = nfisincl_from_fact_frac(a, b, la, lb, vb, y);
1303
else
1304
x = nfisincl_from_fact(nfa, degpol(a), b, la, lb, vb, y, flag);
1305
if (newvar) (void)delete_var();
1306
return gerepilecopy(av,x);
1307
}
1308
1309
GEN
1310
nfisincl(GEN fa, GEN fb) { return nfisincl0(fa, fb, 0); }
1311
1312
static GEN
1313
lastel(GEN x) { return gel(x, lg(x)-1); }
1314
1315
static GEN
1316
RgF_to_Flxq(GEN F, GEN T, ulong p)
1317
{
1318
return typ(F)==t_POL ? RgX_to_Flx(F, p)
1319
: Flxq_div(RgX_to_Flx(gel(F,1), p), RgX_to_Flx(gel(F,2), p), T, p);
1320
}
1321
1322
static GEN
1323
RgFV_to_FlxqV(GEN x, GEN T, ulong p)
1324
{ pari_APPLY_same(RgF_to_Flxq(gel(x,i), T, p)) }
1325
1326
static GEN
1327
nfsplitting_auto(GEN g, GEN R)
1328
{
1329
forprime_t T;
1330
long i, d = degpol(g);
1331
ulong p;
1332
GEN P, K, N, G, q, den = Q_denom(R), Rp, Gp;
1333
u_forprime_init(&T, d*maxss(expu(d)-3, 2), ULONG_MAX);
1334
for(;;)
1335
{
1336
p = u_forprime_next(&T);
1337
if (dvdiu(den,p)) continue;
1338
Gp = ZX_to_Flx(g, p);
1339
if (Flx_is_totally_split(Gp, p)) break;
1340
}
1341
P = Flx_roots(Gp, p);
1342
Rp = RgFV_to_FlxqV(R, Gp, p);
1343
K = Flm_Flc_invimage(FlxV_to_Flm(Rp, d), vecsmall_ei(d, 2), p);
1344
N = Flm_transpose(FlxV_Flv_multieval(Rp, P, p));
1345
q = perm_inv(vecsmall_indexsort(gel(N,1)));
1346
G = cgetg(d+1, t_COL);
1347
for (i=1; i<=d; i++)
1348
{
1349
GEN r = perm_mul(vecsmall_indexsort(gel(N,i)), q);
1350
gel(G,i) = FlxV_Flc_mul(Rp, vecpermute(K, r), p);
1351
}
1352
return mkvec3(g, G, utoi(p));
1353
}
1354
1355
static GEN
1356
nfsplitting_composite(GEN P)
1357
{
1358
GEN F = gel(ZX_factor(P), 1), Q = NULL;
1359
long i, n = lg(F)-1;
1360
for (i = 1; i <= n; i++)
1361
{
1362
GEN Fi = gel(F, i);
1363
if (degpol(Fi) == 1) continue;
1364
Q = Q ? lastel(compositum(Q, Fi)): Fi;
1365
}
1366
return Q ? Q: pol_x(varn(P));
1367
}
1368
GEN
1369
nfsplitting0(GEN T0, GEN D, long flag)
1370
{
1371
pari_sp av = avma;
1372
long d, Ds, v;
1373
GEN T, F, K, N = NULL;
1374
T = T0 = get_nfpol(T0, &K);
1375
if (!K)
1376
{
1377
if (typ(T) != t_POL) pari_err_TYPE("nfsplitting",T);
1378
T = Q_primpart(T);
1379
RgX_check_ZX(T,"nfsplitting");
1380
}
1381
T = nfsplitting_composite(T);
1382
d = degpol(T); v = varn(T);
1383
if (d <= 1 && flag==0)
1384
{ set_avma(av); return pol_x(v); }
1385
if (!K) {
1386
if (!isint1(leading_coeff(T))) K = T = polredbest(T,0);
1387
K = T;
1388
}
1389
if (flag==1 && !ZX_equal(T, T0))
1390
pari_err_FLAG("nfsplitting");
1391
if (D)
1392
{
1393
if (typ(D) != t_INT || signe(D) < 1) pari_err_TYPE("nfsplitting",D);
1394
}
1395
else
1396
{
1397
char *data = stack_strcat(pari_datadir, "/galdata");
1398
long dmax = pari_is_dir(data)? 11: 7;
1399
D = (d <= dmax)? gel(polgalois(T,DEFAULTPREC), 1): mpfact(d);
1400
}
1401
Ds = itos_or_0(D);
1402
T = leafcopy(T); setvarn(T, fetch_var_higher());
1403
for(F = T;;)
1404
{
1405
GEN P = gel(nffactor(K, F), 1), Q = gel(P,lg(P)-1);
1406
if (degpol(gel(P,1)) == degpol(Q))
1407
{
1408
if (flag==1 && ZX_equal(T, T0))
1409
N = nfisincl_from_fact(K, d, F, gen_1, gen_1, v, liftall(P), flag);
1410
else if (flag>1 && ZX_equal(T, T0))
1411
N = nfisincl_from_fact_frac(T0, F, gen_1, gen_1, v, liftall(P));
1412
break;
1413
}
1414
F = rnfequation(K,Q);
1415
if (degpol(F) == Ds && flag==0)
1416
break;
1417
}
1418
if (umodiu(D,degpol(F)))
1419
{
1420
char *sD = itostr(D);
1421
pari_warn(warner,stack_strcat("ignoring incorrect degree bound ",sD));
1422
}
1423
setvarn(F, v);
1424
(void)delete_var();
1425
if (flag==2) return gerepilecopy(av, nfsplitting_auto(F, N));
1426
return gerepilecopy(av, odd(flag) ? mkvec2(F,N): F);
1427
}
1428
1429
GEN
1430
nfsplitting(GEN T, GEN D) { return nfsplitting0(T, D, 0); }
1431
1432
GEN
1433
nfsplitting_gp(GEN T, GEN D, long flag)
1434
{
1435
if (flag < 0 || flag > 1)
1436
pari_err_FLAG("nfsplitting");
1437
return nfsplitting0(T, D, flag);
1438
}
1439
1440
/*************************************************************************/
1441
/** **/
1442
/** INITALG **/
1443
/** **/
1444
/*************************************************************************/
1445
typedef struct {
1446
GEN T;
1447
GEN ro; /* roots of T */
1448
long r1;
1449
GEN basden;
1450
long prec;
1451
long extraprec; /* possibly -1 = irrelevant or not computed */
1452
GEN M, G; /* possibly NULL = irrelevant or not computed */
1453
} nffp_t;
1454
1455
static GEN
1456
get_roots(GEN x, long r1, long prec)
1457
{
1458
long i, ru;
1459
GEN z;
1460
if (typ(x) != t_POL)
1461
{
1462
z = leafcopy(x);
1463
ru = (lg(z)-1 + r1) >> 1;
1464
}
1465
else
1466
{
1467
long n = degpol(x);
1468
z = (r1 == n)? ZX_realroots_irred(x, prec): QX_complex_roots(x,prec);
1469
ru = (n+r1)>>1;
1470
}
1471
for (i=r1+1; i<=ru; i++) gel(z,i) = gel(z, (i<<1)-r1);
1472
z[0]=evaltyp(t_VEC)|evallg(ru+1); return z;
1473
}
1474
1475
GEN
1476
nf_get_allroots(GEN nf)
1477
{
1478
return embed_roots(nf_get_roots(nf), nf_get_r1(nf));
1479
}
1480
1481
/* For internal use. compute trace(x mod pol), sym=polsym(pol,deg(pol)-1) */
1482
static GEN
1483
quicktrace(GEN x, GEN sym)
1484
{
1485
GEN p1 = gen_0;
1486
long i;
1487
1488
if (typ(x) != t_POL) return gmul(x, gel(sym,1));
1489
if (signe(x))
1490
{
1491
sym--;
1492
for (i=lg(x)-1; i>1; i--)
1493
p1 = gadd(p1, gmul(gel(x,i),gel(sym,i)));
1494
}
1495
return p1;
1496
}
1497
1498
static GEN
1499
get_Tr(GEN mul, GEN x, GEN basden)
1500
{
1501
GEN t, bas = gel(basden,1), den = gel(basden,2);
1502
long i, j, n = lg(bas)-1;
1503
GEN T = cgetg(n+1,t_MAT), TW = cgetg(n+1,t_COL), sym = polsym(x, n-1);
1504
1505
gel(TW,1) = utoipos(n);
1506
for (i=2; i<=n; i++)
1507
{
1508
t = quicktrace(gel(bas,i), sym);
1509
if (den && gel(den,i)) t = diviiexact(t,gel(den,i));
1510
gel(TW,i) = t; /* tr(w[i]) */
1511
}
1512
gel(T,1) = TW;
1513
for (i=2; i<=n; i++)
1514
{
1515
gel(T,i) = cgetg(n+1,t_COL); gcoeff(T,1,i) = gel(TW,i);
1516
for (j=2; j<=i; j++) /* Tr(W[i]W[j]) */
1517
gcoeff(T,i,j) = gcoeff(T,j,i) = ZV_dotproduct(gel(mul,j+(i-1)*n), TW);
1518
}
1519
return T;
1520
}
1521
1522
/* return [bas[i]*denom(bas[i]), denom(bas[i])], denom 1 is given as NULL */
1523
static GEN
1524
get_bas_den(GEN bas)
1525
{
1526
GEN b,d,den, dbas = leafcopy(bas);
1527
long i, l = lg(bas);
1528
int power = 1;
1529
den = cgetg(l,t_VEC);
1530
for (i=1; i<l; i++)
1531
{
1532
b = Q_remove_denom(gel(bas,i), &d);
1533
gel(dbas,i) = b;
1534
gel(den,i) = d; if (d) power = 0;
1535
}
1536
if (power) den = NULL; /* power basis */
1537
return mkvec2(dbas, den);
1538
}
1539
1540
/* return multiplication table for S->basis */
1541
static GEN
1542
nf_multable(nfmaxord_t *S, GEN invbas)
1543
{
1544
GEN T = S->T, w = gel(S->basden,1), den = gel(S->basden,2);
1545
long i,j, n = degpol(T);
1546
GEN mul = cgetg(n*n+1,t_MAT);
1547
1548
/* i = 1 split for efficiency, assume w[1] = 1 */
1549
for (j=1; j<=n; j++)
1550
gel(mul,j) = gel(mul,1+(j-1)*n) = col_ei(n, j);
1551
for (i=2; i<=n; i++)
1552
for (j=i; j<=n; j++)
1553
{
1554
pari_sp av = avma;
1555
GEN z = (i == j)? ZXQ_sqr(gel(w,i), T): ZXQ_mul(gel(w,i),gel(w,j), T);
1556
z = ZM_ZX_mul(invbas, z); /* integral column */
1557
if (den)
1558
{
1559
GEN d = mul_denom(gel(den,i), gel(den,j));
1560
if (d) z = ZC_Z_divexact(z, d);
1561
}
1562
gel(mul,j+(i-1)*n) = gel(mul,i+(j-1)*n) = gerepileupto(av,z);
1563
}
1564
return mul;
1565
}
1566
1567
/* as get_Tr, mul_table not precomputed */
1568
static GEN
1569
make_Tr(nfmaxord_t *S)
1570
{
1571
GEN T = S->T, w = gel(S->basden,1), den = gel(S->basden,2);
1572
long i,j, n = degpol(T);
1573
GEN c, t, d, M = cgetg(n+1,t_MAT), sym = polsym(T, n-1);
1574
1575
/* W[i] = w[i]/den[i]; assume W[1] = 1, case i = 1 split for efficiency */
1576
c = cgetg(n+1,t_COL); gel(M,1) = c;
1577
gel(c, 1) = utoipos(n);
1578
for (j=2; j<=n; j++)
1579
{
1580
pari_sp av = avma;
1581
t = quicktrace(gel(w,j), sym);
1582
if (den)
1583
{
1584
d = gel(den,j);
1585
if (d) t = diviiexact(t, d);
1586
}
1587
gel(c,j) = gerepileuptoint(av, t);
1588
}
1589
for (i=2; i<=n; i++)
1590
{
1591
c = cgetg(n+1,t_COL); gel(M,i) = c;
1592
for (j=1; j<i ; j++) gel(c,j) = gcoeff(M,i,j);
1593
for ( ; j<=n; j++)
1594
{
1595
pari_sp av = avma;
1596
t = (i == j)? ZXQ_sqr(gel(w,i), T): ZXQ_mul(gel(w,i),gel(w,j), T);
1597
t = quicktrace(t, sym);
1598
if (den)
1599
{
1600
d = mul_denom(gel(den,i),gel(den,j));
1601
if (d) t = diviiexact(t, d);
1602
}
1603
gel(c,j) = gerepileuptoint(av, t); /* Tr (W[i]W[j]) */
1604
}
1605
}
1606
return M;
1607
}
1608
1609
/* [bas[i]/den[i]]= integer basis. roo = real part of the roots */
1610
static void
1611
make_M(nffp_t *F, int trunc)
1612
{
1613
GEN bas = gel(F->basden,1), den = gel(F->basden,2), ro = F->ro;
1614
GEN m, d, M;
1615
long i, j, l = lg(ro), n = lg(bas);
1616
M = cgetg(n,t_MAT);
1617
gel(M,1) = const_col(l-1, gen_1); /* bas[1] = 1 */
1618
for (j=2; j<n; j++) gel(M,j) = cgetg(l,t_COL);
1619
for (i=1; i<l; i++)
1620
{
1621
GEN r = gel(ro,i), ri;
1622
ri = (gexpo(r) > 1)? ginv(r): NULL;
1623
for (j=2; j<n; j++) gcoeff(M,i,j) = RgX_cxeval(gel(bas,j), r, ri);
1624
}
1625
if (den)
1626
for (j=2; j<n; j++)
1627
{
1628
d = gel(den,j); if (!d) continue;
1629
m = gel(M,j);
1630
for (i=1; i<l; i++) gel(m,i) = gdiv(gel(m,i), d);
1631
}
1632
1633
if (trunc && gprecision(M) > F->prec)
1634
{
1635
M = gprec_w(M, F->prec);
1636
F->ro = gprec_w(ro,F->prec);
1637
}
1638
F->M = M;
1639
}
1640
1641
/* return G real such that G~ * G = T_2 */
1642
static void
1643
make_G(nffp_t *F)
1644
{
1645
GEN G, M = F->M;
1646
long i, j, k, r1 = F->r1, l = lg(M);
1647
1648
if (r1 == l-1) { F->G = M; return; }
1649
G = cgetg(l, t_MAT);
1650
for (j = 1; j < l; j++)
1651
{
1652
GEN g, m = gel(M,j);
1653
gel(G,j) = g = cgetg(l, t_COL);
1654
for (k = i = 1; i <= r1; i++) gel(g,k++) = gel(m,i);
1655
for ( ; k < l; i++)
1656
{
1657
GEN r = gel(m,i);
1658
if (typ(r) == t_COMPLEX)
1659
{
1660
GEN a = gel(r,1), b = gel(r,2);
1661
gel(g,k++) = mpadd(a, b);
1662
gel(g,k++) = mpsub(a, b);
1663
}
1664
else
1665
{
1666
gel(g,k++) = r;
1667
gel(g,k++) = r;
1668
}
1669
}
1670
}
1671
F->G = G;
1672
}
1673
1674
static long
1675
prec_fix(long prec)
1676
{
1677
#ifndef LONG_IS_64BIT
1678
/* make sure that default accuracy is the same on 32/64bit */
1679
if (odd(prec)) prec += EXTRAPRECWORD;
1680
#endif
1681
return prec;
1682
}
1683
static void
1684
make_M_G(nffp_t *F, int trunc)
1685
{
1686
long n, eBD, prec;
1687
if (F->extraprec < 0)
1688
{ /* not initialized yet; compute roots so that absolute accuracy
1689
* of M & G >= prec */
1690
double er;
1691
n = degpol(F->T);
1692
eBD = 1 + gexpo(gel(F->basden,1));
1693
er = F->ro? (1+gexpo(F->ro)): fujiwara_bound(F->T);
1694
if (er < 0) er = 0;
1695
F->extraprec = nbits2extraprec(n*er + eBD + log2(n));
1696
}
1697
prec = prec_fix(F->prec + F->extraprec);
1698
if (!F->ro || gprecision(gel(F->ro,1)) < prec)
1699
F->ro = get_roots(F->T, F->r1, prec);
1700
1701
make_M(F, trunc);
1702
make_G(F);
1703
}
1704
1705
static void
1706
nffp_init(nffp_t *F, nfmaxord_t *S, long prec)
1707
{
1708
F->T = S->T;
1709
F->r1 = S->r1;
1710
F->basden = S->basden;
1711
F->ro = NULL;
1712
F->extraprec = -1;
1713
F->prec = prec;
1714
}
1715
1716
/* let bas a t_VEC of QX giving a Z-basis of O_K. Return the index of the
1717
* basis. Assume bas[1] = 1 and that the leading coefficient of elements
1718
* of bas are of the form 1/b for a t_INT b */
1719
static GEN
1720
get_nfindex(GEN bas)
1721
{
1722
pari_sp av = avma;
1723
long n = lg(bas)-1, i;
1724
GEN D, d, mat;
1725
1726
/* assume bas[1] = 1 */
1727
D = gel(bas,1);
1728
if (! is_pm1(simplify_shallow(D))) pari_err_TYPE("get_nfindex", D);
1729
D = gen_1;
1730
for (i = 2; i <= n; i++)
1731
{ /* after nfbasis, basis is upper triangular! */
1732
GEN B = gel(bas,i), lc;
1733
if (degpol(B) != i-1) break;
1734
lc = gel(B, i+1);
1735
switch (typ(lc))
1736
{
1737
case t_INT: continue;
1738
case t_FRAC: if (is_pm1(gel(lc,1)) ) {D = mulii(D, gel(lc,2)); continue;}
1739
default: pari_err_TYPE("get_nfindex", B);
1740
}
1741
}
1742
if (i <= n)
1743
{ /* not triangular after all */
1744
bas = vecslice(bas,i,n);
1745
bas = Q_remove_denom(bas, &d);
1746
if (!d) return D;
1747
mat = RgV_to_RgM(bas, n);
1748
mat = rowslice(mat, i,n);
1749
D = mulii(D, diviiexact(powiu(d, n-i+1), absi_shallow(ZM_det(mat))));
1750
}
1751
return gerepileuptoint(av, D);
1752
}
1753
/* make sure all components of S are initialized */
1754
static void
1755
nfmaxord_complete(nfmaxord_t *S)
1756
{
1757
if (!S->dT) S->dT = ZX_disc(S->T);
1758
if (!S->index)
1759
{
1760
if (S->dK) /* fast */
1761
S->index = sqrti( diviiexact(S->dT, S->dK) );
1762
else
1763
S->index = get_nfindex(S->basis);
1764
}
1765
if (!S->dK) S->dK = diviiexact(S->dT, sqri(S->index));
1766
if (S->r1 < 0) S->r1 = ZX_sturm_irred(S->T);
1767
if (!S->basden) S->basden = get_bas_den(S->basis);
1768
}
1769
1770
GEN
1771
nfmaxord_to_nf(nfmaxord_t *S, GEN ro, long prec)
1772
{
1773
GEN nf = cgetg(10,t_VEC);
1774
GEN T = S->T, Tr, D, w, A, dA, MDI, mat = cgetg(9,t_VEC);
1775
long n = degpol(T);
1776
nffp_t F;
1777
nfmaxord_complete(S);
1778
nffp_init(&F,S,prec);
1779
F.ro = ro;
1780
make_M_G(&F, 0);
1781
1782
gel(nf,1) = S->T;
1783
gel(nf,2) = mkvec2s(S->r1, (n - S->r1)>>1);
1784
gel(nf,3) = S->dK;
1785
gel(nf,4) = S->index;
1786
gel(nf,5) = mat;
1787
if (gprecision(gel(F.ro,1)) > prec) F.ro = gprec_wtrunc(F.ro, prec);
1788
gel(nf,6) = F.ro;
1789
w = S->basis;
1790
if (!is_pm1(S->index)) w = Q_remove_denom(w, NULL);
1791
gel(nf,7) = w;
1792
gel(nf,8) = ZM_inv(RgV_to_RgM(w,n), NULL);
1793
gel(nf,9) = nf_multable(S, nf_get_invzk(nf));
1794
gel(mat,1) = F.M;
1795
gel(mat,2) = F.G;
1796
1797
Tr = get_Tr(gel(nf,9), T, S->basden);
1798
gel(mat,6) = A = ZM_inv(Tr, &dA); /* dA T^-1, primitive */
1799
A = ZM_hnfmodid(A, dA);
1800
/* CAVEAT: nf is not complete yet, but the fields needed for
1801
* idealtwoelt, zk_scalar_or_multable and idealinv are present ! */
1802
MDI = idealtwoelt(nf, A);
1803
gel(MDI,2) = zk_scalar_or_multable(nf, gel(MDI,2));
1804
gel(mat,7) = MDI;
1805
if (is_pm1(S->index))
1806
{ /* principal ideal (T'), whose norm is |dK| */
1807
D = zk_scalar_or_multable(nf, ZX_deriv(T));
1808
if (typ(D) == t_MAT) D = ZM_hnfmod(D, absi_shallow(S->dK));
1809
}
1810
else
1811
{
1812
GEN c = diviiexact(dA, gcoeff(A,1,1));
1813
D = idealHNF_inv_Z(nf, A); /* (A\cap Z) / A */
1814
if (!is_pm1(c)) D = ZM_Z_mul(D, c);
1815
}
1816
gel(mat,3) = RM_round_maxrank(F.G);
1817
gel(mat,4) = Tr;
1818
gel(mat,5) = D;
1819
gel(mat,8) = shallowtrans(S->dKP? S->dKP: gel(absZ_factor(S->dK), 1));
1820
return nf;
1821
}
1822
1823
static GEN
1824
primes_certify(GEN dK, GEN dKP)
1825
{
1826
long i, l = lg(dKP);
1827
GEN v, w, D = dK;
1828
v = vectrunc_init(l);
1829
w = vectrunc_init(l);
1830
for (i = 1; i < l; i++)
1831
{
1832
GEN p = gel(dKP,i);
1833
vectrunc_append(isprime(p)? w: v, p);
1834
(void)Z_pvalrem(D, p, &D);
1835
}
1836
if (!is_pm1(D))
1837
{
1838
if (signe(D) < 0) D = negi(D);
1839
vectrunc_append(isprime(D)? w: v, D);
1840
}
1841
return mkvec2(v,w);
1842
}
1843
GEN
1844
nfcertify(GEN nf)
1845
{
1846
pari_sp av = avma;
1847
GEN vw;
1848
nf = checknf(nf);
1849
vw = primes_certify(nf_get_disc(nf), nf_get_ramified_primes(nf));
1850
return gerepilecopy(av, gel(vw,1));
1851
}
1852
1853
/* set *pro to roots of S->T */
1854
static GEN
1855
get_red_G(nfmaxord_t *S, GEN *pro)
1856
{
1857
GEN G, u, u0 = NULL;
1858
pari_sp av;
1859
long i, prec, n = degpol(S->T);
1860
nffp_t F;
1861
1862
prec = nbits2prec(n+32);
1863
nffp_init(&F, S, prec);
1864
av = avma;
1865
for (i=1; ; i++)
1866
{
1867
F.prec = prec; make_M_G(&F, 0); G = F.G;
1868
if (u0) G = RgM_mul(G, u0);
1869
if (DEBUGLEVEL)
1870
err_printf("get_red_G: starting LLL, prec = %ld (%ld + %ld)\n",
1871
prec + F.extraprec, prec, F.extraprec);
1872
if ((u = lllfp(G, 0.99, LLL_KEEP_FIRST)))
1873
{
1874
if (lg(u)-1 == n) break;
1875
/* singular ==> loss of accuracy */
1876
if (u0) u0 = gerepileupto(av, RgM_mul(u0,u));
1877
else u0 = gerepilecopy(av, u);
1878
}
1879
prec = precdbl(prec) + nbits2extraprec(gexpo(u0));
1880
F.ro = NULL;
1881
if (DEBUGLEVEL) pari_warn(warnprec,"get_red_G", prec);
1882
}
1883
if (u0) u = RgM_mul(u0,u);
1884
*pro = F.ro; return u;
1885
}
1886
1887
/* Compute an LLL-reduced basis for the integer basis of nf(T).
1888
* set *pro = roots of x if computed [NULL if not computed] */
1889
static void
1890
set_LLL_basis(nfmaxord_t *S, GEN *pro, double DELTA)
1891
{
1892
GEN B = S->basis;
1893
long N = degpol(S->T);
1894
if (S->r1 < 0)
1895
{
1896
S->r1 = ZX_sturm_irred(S->T);
1897
if (odd(N - S->r1)) pari_err_IRREDPOL("set_LLL_basis", S->T);
1898
}
1899
if (!S->basden) S->basden = get_bas_den(B);
1900
if (S->r1 == N) {
1901
pari_sp av = avma;
1902
GEN u = ZM_lll(make_Tr(S), DELTA, LLL_GRAM|LLL_KEEP_FIRST|LLL_IM);
1903
B = gerepileupto(av, RgV_RgM_mul(B, u));
1904
*pro = NULL;
1905
}
1906
else
1907
B = RgV_RgM_mul(B, get_red_G(S, pro));
1908
S->basis = B;
1909
S->basden = get_bas_den(B);
1910
}
1911
1912
/* = 1 iff |a| > |b| or equality and a > 0 */
1913
static int
1914
cmpii_polred(GEN a, GEN b)
1915
{
1916
int fl = abscmpii(a, b);
1917
long sa, sb;
1918
if (fl) return fl;
1919
sa = signe(a);
1920
sb = signe(b);
1921
if (sa == sb) return 0;
1922
return sa == 1? 1: -1;
1923
}
1924
static int
1925
ZX_cmp(GEN x, GEN y)
1926
{ return gen_cmp_RgX((void*)cmpii_polred, x, y); }
1927
/* current best: ZX x of discriminant *dx, is ZX y better than x ?
1928
* (if so update *dx); both x and y are monic */
1929
static int
1930
ZX_is_better(GEN y, GEN x, GEN *dx)
1931
{
1932
GEN d = ZX_disc(y);
1933
int cmp;
1934
if (!*dx) *dx = ZX_disc(x);
1935
cmp = abscmpii(d, *dx);
1936
if (cmp < 0) { *dx = d; return 1; }
1937
return cmp? 0: (ZX_cmp(y, x) < 0);
1938
}
1939
1940
static void polredbest_aux(nfmaxord_t *S, GEN *pro, GEN *px, GEN *pdx, GEN *pa);
1941
/* Seek a simpler, polynomial pol defining the same number field as
1942
* x (assumed to be monic at this point) */
1943
static GEN
1944
nfpolred(nfmaxord_t *S, GEN *pro)
1945
{
1946
GEN x = S->T, dx, b, rev;
1947
long n = degpol(x), v = varn(x);
1948
1949
if (n == 1) {
1950
S->T = pol_x(v);
1951
*pro = NULL;
1952
return scalarpol_shallow(negi(gel(x,2)), v);
1953
}
1954
polredbest_aux(S, pro, &x, &dx, &b);
1955
if (x == S->T) return NULL; /* no improvement */
1956
if (DEBUGLEVEL>1) err_printf("xbest = %Ps\n",x);
1957
1958
/* update T */
1959
rev = QXQ_reverse(b, S->T);
1960
S->basis = QXV_QXQ_eval(S->basis, rev, x);
1961
S->index = sqrti( diviiexact(dx,S->dK) );
1962
S->basden = get_bas_den(S->basis);
1963
S->dT = dx;
1964
S->T = x;
1965
*pro = NULL; /* reset */
1966
return rev;
1967
}
1968
1969
/* Either nf type or ZX or [monic ZX, data], where data is either an integral
1970
* basis (deprecated), or listP data (nfbasis input format) to specify
1971
* a set of primes at with the basis order must be maximal.
1972
* 1) nf type (or unrecognized): return t_VEC
1973
* 2) ZX or [ZX, listP]: return t_POL
1974
* 3) [ZX, order basis]: return 0 (deprecated)
1975
* incorrect: return -1 */
1976
static long
1977
nf_input_type(GEN x)
1978
{
1979
GEN T, V, DKP = NULL;
1980
long i, d, v;
1981
switch(typ(x))
1982
{
1983
case t_POL: return t_POL;
1984
case t_VEC:
1985
switch(lg(x))
1986
{
1987
case 4: DKP = gel(x,3);
1988
case 3: break;
1989
default: return t_VEC; /* nf or incorrect */
1990
}
1991
T = gel(x,1); V = gel(x,2);
1992
if (typ(T) != t_POL) return -1;
1993
switch(typ(V))
1994
{
1995
case t_INT: case t_MAT: return t_POL;
1996
case t_VEC: case t_COL:
1997
if (RgV_is_ZV(V)) return t_POL;
1998
break;
1999
default: return -1;
2000
}
2001
d = degpol(T); v = varn(T);
2002
if (d<1 || !RgX_is_ZX(T) || !isint1(gel(T,d+2)) || lg(V)-1!=d) return -1;
2003
for (i = 1; i <= d; i++)
2004
{ /* check integer basis */
2005
GEN c = gel(V,i);
2006
switch(typ(c))
2007
{
2008
case t_INT: break;
2009
case t_POL: if (varn(c) == v && RgX_is_QX(c) && degpol(c) < d) break;
2010
/* fall through */
2011
default: return -1;
2012
}
2013
}
2014
if (DKP && (typ(DKP) != t_VEC || !RgV_is_ZV(DKP))) return -1;
2015
return 0;
2016
}
2017
return t_VEC; /* nf or incorrect */
2018
}
2019
2020
/* cater for obsolete nf_PARTIALFACT flag */
2021
static void
2022
nfinit_basic_partial(nfmaxord_t *S, GEN T)
2023
{
2024
if (typ(T) == t_POL) { nfmaxord(S, mkvec2(T,utoipos(500000)), 0); }
2025
else nfinit_basic(S, T);
2026
}
2027
/* true nf */
2028
static GEN
2029
nf_basden(GEN nf)
2030
{
2031
GEN zkD = nf_get_zkprimpart(nf), D = nf_get_zkden(nf);
2032
D = equali1(D)? NULL: const_vec(lg(zkD)-1, D);
2033
return mkvec2(zkD, D);
2034
}
2035
void
2036
nfinit_basic(nfmaxord_t *S, GEN T)
2037
{
2038
switch (nf_input_type(T))
2039
{
2040
case t_POL: nfmaxord(S, T, 0); return;
2041
case t_VEC:
2042
{ /* nf, bnf, bnr */
2043
GEN nf = checknf(T);
2044
S->T = S->T0 = nf_get_pol(nf);
2045
S->basis = nf_get_zk(nf); /* probably useless */
2046
S->basden = nf_basden(nf);
2047
S->index = nf_get_index(nf);
2048
S->dK = nf_get_disc(nf);
2049
S->dKP = nf_get_ramified_primes(nf);
2050
S->dT = mulii(S->dK, sqri(S->index));
2051
S->r1 = nf_get_r1(nf); break;
2052
}
2053
case 0: /* monic integral polynomial + integer basis (+ ramified primes)*/
2054
S->T = S->T0 = gel(T,1);
2055
S->basis = gel(T,2);
2056
S->basden = NULL;
2057
S->index = NULL;
2058
S->dK = NULL;
2059
S->dKP = lg(T) == 4? gel(T,3): NULL;
2060
S->dT = NULL;
2061
S->r1 = -1; break;
2062
default: /* -1 */
2063
pari_err_TYPE("nfinit_basic", T);
2064
}
2065
S->dTP = S->dTE = S->dKE = NULL;
2066
S->unscale = gen_1;
2067
}
2068
2069
GEN
2070
nfinit_complete(nfmaxord_t *S, long flag, long prec)
2071
{
2072
GEN nf, unscale;
2073
2074
if (!ZX_is_irred(S->T)) pari_err_IRREDPOL("nfinit",S->T);
2075
if (!(flag & nf_RED) && !ZX_is_monic(S->T0))
2076
{
2077
pari_warn(warner,"nonmonic polynomial. Result of the form [nf,c]");
2078
flag |= nf_RED | nf_ORIG;
2079
}
2080
unscale = S->unscale;
2081
if (!(flag & nf_RED) && !isint1(unscale))
2082
{ /* implies lc(x0) = 1 and L := 1/unscale is integral */
2083
long d = degpol(S->T0);
2084
GEN L = ginv(unscale); /* x = L^(-deg(x)) x0(L X) */
2085
GEN f= powiu(L, (d*(d-1)) >> 1);
2086
S->T = S->T0; /* restore original user-supplied x0, unscale data */
2087
S->unscale = gen_1;
2088
S->dT = gmul(S->dT, sqri(f));
2089
S->basis = RgXV_unscale(S->basis, unscale);
2090
S->index = gmul(S->index, f);
2091
}
2092
nfmaxord_complete(S); /* more expensive after set_LLL_basis */
2093
if (flag & nf_RED)
2094
{
2095
GEN ro, rev;
2096
/* lie to polred: more efficient to update *after* modreverse, than to
2097
* unscale in the polred subsystem */
2098
S->unscale = gen_1;
2099
rev = nfpolred(S, &ro);
2100
nf = nfmaxord_to_nf(S, ro, prec);
2101
if (flag & nf_ORIG)
2102
{
2103
if (!rev) rev = pol_x(varn(S->T)); /* no improvement */
2104
if (!isint1(unscale)) rev = RgX_Rg_div(rev, unscale);
2105
nf = mkvec2(nf, mkpolmod(rev, S->T));
2106
}
2107
S->unscale = unscale; /* restore */
2108
} else {
2109
GEN ro; set_LLL_basis(S, &ro, 0.99);
2110
nf = nfmaxord_to_nf(S, ro, prec);
2111
}
2112
return nf;
2113
}
2114
/* Initialize the number field defined by the polynomial x (in variable v)
2115
* flag & nf_RED: try a polred first.
2116
* flag & nf_ORIG
2117
* do a polred and return [nfinit(x), Mod(a,red)], where
2118
* Mod(a,red) = Mod(v,x) (i.e return the base change). */
2119
GEN
2120
nfinitall(GEN x, long flag, long prec)
2121
{
2122
const pari_sp av = avma;
2123
nfmaxord_t S;
2124
GEN nf;
2125
2126
if (checkrnf_i(x)) return rnf_build_nfabs(x, prec);
2127
nfinit_basic(&S, x);
2128
nf = nfinit_complete(&S, flag, prec);
2129
return gerepilecopy(av, nf);
2130
}
2131
2132
GEN
2133
nfinitred(GEN x, long prec) { return nfinitall(x, nf_RED, prec); }
2134
GEN
2135
nfinitred2(GEN x, long prec) { return nfinitall(x, nf_RED|nf_ORIG, prec); }
2136
GEN
2137
nfinit(GEN x, long prec) { return nfinitall(x, 0, prec); }
2138
2139
GEN
2140
nfinit0(GEN x, long flag,long prec)
2141
{
2142
switch(flag)
2143
{
2144
case 0:
2145
case 1: return nfinitall(x,0,prec);
2146
case 2: case 4: return nfinitall(x,nf_RED,prec);
2147
case 3: case 5: return nfinitall(x,nf_RED|nf_ORIG,prec);
2148
default: pari_err_FLAG("nfinit");
2149
}
2150
return NULL; /* LCOV_EXCL_LINE */
2151
}
2152
2153
/* assume x a bnr/bnf/nf */
2154
long
2155
nf_get_prec(GEN x)
2156
{
2157
GEN nf = checknf(x), ro = nf_get_roots(nf);
2158
return (typ(ro)==t_VEC)? precision(gel(ro,1)): DEFAULTPREC;
2159
}
2160
2161
/* true nf */
2162
GEN
2163
nfnewprec_shallow(GEN nf, long prec)
2164
{
2165
GEN m, NF = leafcopy(nf);
2166
nffp_t F;
2167
2168
F.T = nf_get_pol(nf);
2169
F.ro = NULL;
2170
F.r1 = nf_get_r1(nf);
2171
F.basden = nf_basden(nf);
2172
F.extraprec = -1;
2173
F.prec = prec; make_M_G(&F, 0);
2174
gel(NF,5) = m = leafcopy(gel(NF,5));
2175
gel(m,1) = F.M;
2176
gel(m,2) = F.G;
2177
gel(NF,6) = F.ro; return NF;
2178
}
2179
2180
GEN
2181
nfnewprec(GEN nf, long prec)
2182
{
2183
GEN z;
2184
switch(nftyp(nf))
2185
{
2186
default: pari_err_TYPE("nfnewprec", nf);
2187
case typ_BNF: z = bnfnewprec(nf,prec); break;
2188
case typ_BNR: z = bnrnewprec(nf,prec); break;
2189
case typ_NF: {
2190
pari_sp av = avma;
2191
z = gerepilecopy(av, nfnewprec_shallow(checknf(nf), prec));
2192
break;
2193
}
2194
}
2195
return z;
2196
}
2197
2198
/********************************************************************/
2199
/** **/
2200
/** POLRED **/
2201
/** **/
2202
/********************************************************************/
2203
GEN
2204
embednorm_T2(GEN x, long r1)
2205
{
2206
pari_sp av = avma;
2207
GEN p = RgV_sumpart(x, r1);
2208
GEN q = RgV_sumpart2(x,r1+1, lg(x)-1);
2209
if (q != gen_0) p = gadd(p, gmul2n(q,1));
2210
return avma == av? gcopy(p): gerepileupto(av, p);
2211
}
2212
2213
/* simplified version of gnorm for scalar, noncomplex inputs, without GC */
2214
static GEN
2215
real_norm(GEN x)
2216
{
2217
switch(typ(x))
2218
{
2219
case t_INT: return sqri(x);
2220
case t_REAL: return sqrr(x);
2221
case t_FRAC: return sqrfrac(x);
2222
}
2223
pari_err_TYPE("real_norm", x);
2224
return NULL;/*LCOV_EXCL_LINE*/
2225
}
2226
/* simplified version of gnorm, without GC */
2227
static GEN
2228
complex_norm(GEN x)
2229
{
2230
return typ(x) == t_COMPLEX? cxnorm(x): real_norm(x);
2231
}
2232
/* return T2(x), argument r1 needed in case x has components whose type
2233
* is unexpected, e.g. all of them t_INT for embed(gen_1) */
2234
GEN
2235
embed_T2(GEN x, long r1)
2236
{
2237
pari_sp av = avma;
2238
long i, l = lg(x);
2239
GEN c, s = NULL, t = NULL;
2240
if (typ(gel(x,1)) == t_INT) return muliu(gel(x,1), 2*(l-1)-r1);
2241
for (i = 1; i <= r1; i++)
2242
{
2243
c = real_norm(gel(x,i));
2244
s = s? gadd(s, c): c;
2245
}
2246
for (; i < l; i++)
2247
{
2248
c = complex_norm(gel(x,i));
2249
t = t? gadd(t, c): c;
2250
}
2251
if (t) { t = gmul2n(t,1); s = s? gadd(s,t): t; }
2252
return gerepileupto(av, s);
2253
}
2254
/* return N(x) */
2255
GEN
2256
embed_norm(GEN x, long r1)
2257
{
2258
pari_sp av = avma;
2259
long i, l = lg(x);
2260
GEN c, s = NULL, t = NULL;
2261
if (typ(gel(x,1)) == t_INT) return powiu(gel(x,1), 2*(l-1)-r1);
2262
for (i = 1; i <= r1; i++)
2263
{
2264
c = gel(x,i);
2265
s = s? gmul(s, c): c;
2266
}
2267
for (; i < l; i++)
2268
{
2269
c = complex_norm(gel(x,i));
2270
t = t? gmul(t, c): c;
2271
}
2272
if (t) s = s? gmul(s,t): t;
2273
return gerepileupto(av, s);
2274
}
2275
2276
typedef struct {
2277
long r1, v, prec;
2278
GEN ZKembed; /* embeddings of fincke-pohst-reduced Zk basis */
2279
GEN u; /* matrix giving fincke-pohst-reduced Zk basis */
2280
GEN M; /* embeddings of initial (LLL-reduced) Zk basis */
2281
GEN bound; /* T2 norm of the polynomial defining nf */
2282
long expo_best_disc; /* expo(disc(x)), best generator so far */
2283
} CG_data;
2284
2285
/* characteristic pol of x (given by embeddings) */
2286
static GEN
2287
get_pol(CG_data *d, GEN x)
2288
{
2289
long e;
2290
GEN g = grndtoi(roots_to_pol_r1(x, d->v, d->r1), &e);
2291
return (e > -5)? NULL: g;
2292
}
2293
2294
/* characteristic pol of x (given as vector on (w_i)) */
2295
static GEN
2296
get_polchar(CG_data *d, GEN x)
2297
{ return get_pol(d, RgM_RgC_mul(d->ZKembed,x)); }
2298
2299
/* Choose a canonical polynomial in the pair { Pmin_a, Pmin_{-a} }, i.e.
2300
* { z(X), (-1)^(deg z) z(-Z) } and keeping the smallest wrt cmpii_polred
2301
* Either leave z alone (return 1) or set z <- (-1)^n z(-X). In place. */
2302
static int
2303
ZX_canon_neg(GEN z)
2304
{
2305
long i, s;
2306
for (i = lg(z)-2; i >= 2; i -= 2)
2307
{ /* examine the odd (resp. even) part of z if deg(z) even (resp. odd). */
2308
s = signe(gel(z,i));
2309
if (!s) continue;
2310
/* non trivial */
2311
if (s < 0) break; /* z(X) < (-1)^n z(-X) */
2312
2313
for (; i>=2; i-=2) gel(z,i) = negi(gel(z,i));
2314
return 1;
2315
}
2316
return 0;
2317
}
2318
/* return a defining polynomial for Q(alpha), v = embeddings of alpha.
2319
* Return NULL on failure: discriminant too large or non primitive */
2320
static GEN
2321
try_polmin(CG_data *d, nfmaxord_t *S, GEN v, long flag, GEN *ai)
2322
{
2323
const long best = flag & nf_ABSOLUTE;
2324
long ed;
2325
pari_sp av = avma;
2326
GEN g;
2327
if (best)
2328
{
2329
ed = expo(embed_disc(v, d->r1, LOWDEFAULTPREC));
2330
set_avma(av); if (d->expo_best_disc < ed) return NULL;
2331
}
2332
else
2333
ed = 0;
2334
g = get_pol(d, v);
2335
/* accuracy too low, compute algebraically */
2336
if (!g) { set_avma(av); g = ZXQ_charpoly(*ai, S->T, varn(S->T)); }
2337
g = ZX_radical(g);
2338
if (best && degpol(g) != degpol(S->T)) return gc_NULL(av);
2339
g = gerepilecopy(av, g);
2340
d->expo_best_disc = ed;
2341
if (flag & nf_ORIG)
2342
{
2343
if (ZX_canon_neg(g)) *ai = RgX_neg(*ai);
2344
if (!isint1(S->unscale)) *ai = RgX_unscale(*ai, S->unscale);
2345
}
2346
else
2347
(void)ZX_canon_neg(g);
2348
if (DEBUGLEVEL>3) err_printf("polred: generator %Ps\n", g);
2349
return g;
2350
}
2351
2352
/* does x generate the correct field ? */
2353
static GEN
2354
chk_gen(void *data, GEN x)
2355
{
2356
pari_sp av = avma, av1;
2357
GEN h, g = get_polchar((CG_data*)data,x);
2358
if (!g) pari_err_PREC("chk_gen");
2359
av1 = avma;
2360
h = ZX_gcd(g, ZX_deriv(g));
2361
if (degpol(h)) return gc_NULL(av);
2362
if (DEBUGLEVEL>3) err_printf(" generator: %Ps\n",g);
2363
set_avma(av1); return gerepileupto(av, g);
2364
}
2365
2366
static long
2367
chk_gen_prec(long N, long bit)
2368
{ return prec_fix(nbits2prec(10 + (long)log2((double)N) + bit)); }
2369
2370
/* v = [P,A] two vectors (of ZX and ZV resp.) of same length; remove duplicate
2371
* polynomials in P, updating A, in place. Among elements having the same
2372
* characteristic pol, choose the smallest according to ZV_abscmp */
2373
static void
2374
remove_duplicates(GEN v)
2375
{
2376
GEN x, a, P = gel(v,1), A = gel(v,2);
2377
long k, i, l = lg(P);
2378
pari_sp av = avma;
2379
2380
if (l < 2) return;
2381
(void)sort_factor_pol(mkvec2(P, A), cmpii);
2382
x = gel(P,1); a = gel(A,1);
2383
for (k=1,i=2; i<l; i++)
2384
if (ZX_equal(gel(P,i), x))
2385
{
2386
if (ZV_abscmp(gel(A,i), a) < 0) a = gel(A,i);
2387
}
2388
else
2389
{
2390
gel(A,k) = a;
2391
gel(P,k) = x;
2392
k++;
2393
x = gel(P,i); a = gel(A,i);
2394
}
2395
l = k+1;
2396
gel(A,k) = a; setlg(A,l);
2397
gel(P,k) = x; setlg(P,l); set_avma(av);
2398
}
2399
2400
static void
2401
polred_init(nfmaxord_t *S, nffp_t *F, CG_data *d)
2402
{
2403
long e, prec, n = degpol(S->T);
2404
double log2rho;
2405
GEN ro;
2406
set_LLL_basis(S, &ro, 0.9999);
2407
/* || polchar ||_oo < 2^e ~ 2 (n * rho)^n, rho = max modulus of root */
2408
log2rho = ro ? (double)gexpo(ro): fujiwara_bound(S->T);
2409
e = n * (long)(log2rho + log2((double)n)) + 1;
2410
if (e < 0) e = 0; /* can occur if n = 1 */
2411
prec = chk_gen_prec(n, e);
2412
nffp_init(F,S,prec);
2413
F->ro = ro;
2414
make_M_G(F, 1);
2415
2416
d->v = varn(S->T);
2417
d->expo_best_disc = -1;
2418
d->ZKembed = NULL;
2419
d->M = NULL;
2420
d->u = NULL;
2421
d->r1= S->r1;
2422
}
2423
static GEN
2424
findmindisc(GEN y)
2425
{
2426
GEN x = gel(y,1), dx = NULL;
2427
long i, l = lg(y);
2428
for (i = 2; i < l; i++)
2429
{
2430
GEN yi = gel(y,i);
2431
if (ZX_is_better(yi,x,&dx)) x = yi;
2432
}
2433
return x;
2434
}
2435
/* filter [y,b] from polred_aux: keep a single polynomial of degree n in y
2436
* [ the best wrt discriminant ordering ], but keep all imprimitive
2437
* polynomials */
2438
static void
2439
filter(GEN y, GEN b, long n)
2440
{
2441
GEN x, a, dx;
2442
long i, k = 1, l = lg(y);
2443
a = x = dx = NULL;
2444
for (i = 1; i < l; i++)
2445
{
2446
GEN yi = gel(y,i), ai = gel(b,i);
2447
if (degpol(yi) == n)
2448
{
2449
pari_sp av = avma;
2450
if (!dx) dx = ZX_disc(yi);
2451
else if (!ZX_is_better(yi,x,&dx)) { set_avma(av); continue; }
2452
x = yi; a = ai; continue;
2453
}
2454
gel(y,k) = yi;
2455
gel(b,k) = ai; k++;
2456
}
2457
if (dx)
2458
{
2459
gel(y,k) = x;
2460
gel(b,k) = a; k++;
2461
}
2462
setlg(y, k);
2463
setlg(b, k);
2464
}
2465
2466
static GEN
2467
polred_aux(nfmaxord_t *S, GEN *pro, long flag)
2468
{ /* only keep polynomials of max degree and best discriminant */
2469
const long best = flag & nf_ABSOLUTE;
2470
const long orig = flag & nf_ORIG;
2471
GEN M, b, y, x = S->T;
2472
long maxi, i, j, k, v = varn(x), n = lg(S->basis)-1;
2473
nffp_t F;
2474
CG_data d;
2475
2476
if (n == 1)
2477
{
2478
if (!best)
2479
{
2480
GEN X = pol_x(v);
2481
return orig? mkmat2(mkcol(X),mkcol(gen_1)): mkvec(X);
2482
}
2483
else
2484
return orig? trivial_fact(): cgetg(1,t_VEC);
2485
}
2486
2487
polred_init(S, &F, &d);
2488
if (pro) *pro = F.ro;
2489
M = F.M;
2490
if (best)
2491
{
2492
if (!S->dT) S->dT = ZX_disc(S->T);
2493
d.expo_best_disc = expi(S->dT);
2494
}
2495
2496
/* n + 2 sum_{1 <= i <= n} n-i = n + n(n-1) = n*n */
2497
y = cgetg(n*n + 1, t_VEC);
2498
b = cgetg(n*n + 1, t_COL);
2499
k = 1;
2500
if (!best) { gel(y,1) = pol_x(v); gel(b,1) = gen_0; k++; }
2501
for (i = 2; i <= n; i++)
2502
{
2503
GEN ch, ai;
2504
ai = gel(S->basis,i);
2505
ch = try_polmin(&d, S, gel(M,i), flag, &ai);
2506
if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }
2507
}
2508
maxi = minss(n, 3);
2509
for (i = 1; i <= maxi; i++)
2510
for (j = i+1; j <= n; j++)
2511
{
2512
GEN ch, ai, v;
2513
ai = gadd(gel(S->basis,i), gel(S->basis,j));
2514
v = RgV_add(gel(M,i), gel(M,j));
2515
/* defining polynomial for Q(w_i+w_j) */
2516
ch = try_polmin(&d, S, v, flag, &ai);
2517
if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }
2518
2519
ai = gsub(gel(S->basis,i), gel(S->basis,j));
2520
v = RgV_sub(gel(M,i), gel(M,j));
2521
/* defining polynomial for Q(w_i-w_j) */
2522
ch = try_polmin(&d, S, v, flag, &ai);
2523
if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }
2524
}
2525
setlg(y, k);
2526
setlg(b, k); filter(y, b, n);
2527
if (!orig) return gen_sort_uniq(y, (void*)cmpii, &gen_cmp_RgX);
2528
settyp(y, t_COL);
2529
(void)sort_factor_pol(mkmat2(y, b), cmpii);
2530
return mkmat2(b, y);
2531
}
2532
2533
/* FIXME: obsolete */
2534
static GEN
2535
Polred(GEN x, long flag, GEN fa)
2536
{
2537
pari_sp av = avma;
2538
nfmaxord_t S;
2539
if (fa)
2540
nfinit_basic(&S, mkvec2(x,fa));
2541
else if (flag & nf_PARTIALFACT)
2542
nfinit_basic_partial(&S, x);
2543
else
2544
nfinit_basic(&S, x);
2545
return gerepilecopy(av, polred_aux(&S, NULL, flag));
2546
}
2547
2548
/* finds "best" polynomial in polred_aux list, defaulting to S->T if none of
2549
* them is primitive. *px is the ZX, characteristic polynomial of Mod(*pb,S->T),
2550
* *pdx its discriminant if pdx != NULL. Set *pro = polroots(S->T) */
2551
static void
2552
polredbest_aux(nfmaxord_t *S, GEN *pro, GEN *px, GEN *pdx, GEN *pb)
2553
{
2554
GEN y, dx, x = S->T; /* default value */
2555
long i, l;
2556
y = polred_aux(S, pro, pb? nf_ORIG|nf_ABSOLUTE: nf_ABSOLUTE);
2557
dx = S->dT;
2558
if (pb)
2559
{
2560
GEN a, b = deg1pol_shallow(S->unscale, gen_0, varn(x));
2561
a = gel(y,1); l = lg(a);
2562
y = gel(y,2);
2563
for (i=1; i<l; i++)
2564
{
2565
GEN yi = gel(y,i);
2566
pari_sp av = avma;
2567
if (ZX_is_better(yi,x,&dx)) { x = yi; b = gel(a,i); } else set_avma(av);
2568
}
2569
*pb = b;
2570
}
2571
else
2572
{
2573
l = lg(y);
2574
for (i=1; i<l; i++)
2575
{
2576
GEN yi = gel(y,i);
2577
pari_sp av = avma;
2578
if (ZX_is_better(yi,x,&dx)) x = yi; else set_avma(av);
2579
}
2580
}
2581
if (pdx) { if (!dx) dx = ZX_disc(x); *pdx = dx; }
2582
*px = x;
2583
}
2584
static GEN
2585
polredbest_i(GEN T0, long flag)
2586
{
2587
GEN T = T0, a;
2588
nfmaxord_t S;
2589
nfinit_basic_partial(&S, T);
2590
polredbest_aux(&S, NULL, &T, NULL, flag? &a: NULL);
2591
if (flag == 2)
2592
T = mkvec2(T, a);
2593
else if (flag == 1)
2594
{
2595
GEN b = (T0 == T)? pol_x(varn(T)): QXQ_reverse(a, T0);
2596
/* charpoly(Mod(a,T0)) = T; charpoly(Mod(b,T)) = S.x */
2597
if (degpol(T) == 1) b = grem(b,T);
2598
T = mkvec2(T, mkpolmod(b,T));
2599
}
2600
return T;
2601
}
2602
GEN
2603
polredbest(GEN T, long flag)
2604
{
2605
pari_sp av = avma;
2606
if (flag < 0 || flag > 1) pari_err_FLAG("polredbest");
2607
return gerepilecopy(av, polredbest_i(T, flag));
2608
}
2609
/* DEPRECATED: backward compatibility */
2610
GEN
2611
polred0(GEN x, long flag, GEN fa)
2612
{
2613
long fl = 0;
2614
if (flag & 1) fl |= nf_PARTIALFACT;
2615
if (flag & 2) fl |= nf_ORIG;
2616
return Polred(x, fl, fa);
2617
}
2618
2619
GEN
2620
polredord(GEN x)
2621
{
2622
pari_sp av = avma;
2623
GEN v, lt;
2624
long i, n, vx;
2625
2626
if (typ(x) != t_POL) pari_err_TYPE("polredord",x);
2627
x = Q_primpart(x); RgX_check_ZX(x,"polredord");
2628
n = degpol(x); if (n <= 0) pari_err_CONSTPOL("polredord");
2629
if (n == 1) return gerepilecopy(av, mkvec(x));
2630
lt = leading_coeff(x); vx = varn(x);
2631
if (is_pm1(lt))
2632
{
2633
if (signe(lt) < 0) x = ZX_neg(x);
2634
v = pol_x_powers(n, vx);
2635
}
2636
else
2637
{ GEN L;
2638
/* basis for Dedekind order */
2639
v = cgetg(n+1, t_VEC);
2640
gel(v,1) = scalarpol_shallow(lt, vx);
2641
for (i = 2; i <= n; i++)
2642
gel(v,i) = RgX_Rg_add(RgX_mulXn(gel(v,i-1), 1), gel(x,n+3-i));
2643
gel(v,1) = pol_1(vx);
2644
x = ZX_Q_normalize(x, &L);
2645
v = gsubst(v, vx, monomial(ginv(L),1,vx));
2646
for (i=2; i <= n; i++)
2647
if (Q_denom(gel(v,i)) == gen_1) gel(v,i) = pol_xn(i-1, vx);
2648
}
2649
return gerepileupto(av, polred(mkvec2(x, v)));
2650
}
2651
2652
GEN
2653
polred(GEN x) { return Polred(x, 0, NULL); }
2654
GEN
2655
smallpolred(GEN x) { return Polred(x, nf_PARTIALFACT, NULL); }
2656
GEN
2657
factoredpolred(GEN x, GEN fa) { return Polred(x, 0, fa); }
2658
GEN
2659
polred2(GEN x) { return Polred(x, nf_ORIG, NULL); }
2660
GEN
2661
smallpolred2(GEN x) { return Polred(x, nf_PARTIALFACT|nf_ORIG, NULL); }
2662
GEN
2663
factoredpolred2(GEN x, GEN fa) { return Polred(x, nf_PARTIALFACT, fa); }
2664
2665
/********************************************************************/
2666
/** **/
2667
/** POLREDABS **/
2668
/** **/
2669
/********************************************************************/
2670
/* set V[k] := matrix of multiplication by nk.zk[k] */
2671
static GEN
2672
set_mulid(GEN V, GEN M, GEN Mi, long r1, long r2, long N, long k)
2673
{
2674
GEN v, Mk = cgetg(N+1, t_MAT);
2675
long i, e;
2676
for (i = 1; i < k; i++) gel(Mk,i) = gmael(V, i, k);
2677
for ( ; i <=N; i++)
2678
{
2679
v = vecmul(gel(M,k), gel(M,i));
2680
v = RgM_RgC_mul(Mi, split_realimag(v, r1, r2));
2681
gel(Mk,i) = grndtoi(v, &e);
2682
if (e > -5) return NULL;
2683
}
2684
gel(V,k) = Mk; return Mk;
2685
}
2686
2687
static GEN
2688
ZM_image_shallow(GEN M, long *pr)
2689
{
2690
long j, k, r;
2691
GEN y, d = ZM_pivots(M, &k);
2692
r = lg(M)-1 - k;
2693
y = cgetg(r+1,t_MAT);
2694
for (j=k=1; j<=r; k++)
2695
if (d[k]) gel(y,j++) = gel(M,k);
2696
*pr = r; return y;
2697
}
2698
2699
/* U = base change matrix, R = Cholesky form of the quadratic form [matrix
2700
* Q from algo 2.7.6] */
2701
static GEN
2702
chk_gen_init(FP_chk_fun *chk, GEN R, GEN U)
2703
{
2704
CG_data *d = (CG_data*)chk->data;
2705
GEN P, V, D, inv, bound, S, M;
2706
long N = lg(U)-1, r1 = d->r1, r2 = (N-r1)>>1;
2707
long i, j, prec, firstprim = 0, skipfirst = 0;
2708
pari_sp av;
2709
2710
d->u = U;
2711
d->ZKembed = M = RgM_mul(d->M, U);
2712
2713
av = avma; bound = d->bound;
2714
D = cgetg(N+1, t_VECSMALL);
2715
for (i = 1; i <= N; i++)
2716
{
2717
pari_sp av2 = avma;
2718
P = get_pol(d, gel(M,i));
2719
if (!P) pari_err_PREC("chk_gen_init");
2720
P = gerepilecopy(av2, ZX_radical(P));
2721
D[i] = degpol(P);
2722
if (D[i] == N)
2723
{ /* primitive element */
2724
GEN B = embed_T2(gel(M,i), r1);
2725
if (!firstprim) firstprim = i; /* index of first primitive element */
2726
if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P);
2727
if (gcmp(B,bound) < 0) bound = gerepileuptoleaf(av2, B);
2728
}
2729
else
2730
{
2731
if (DEBUGLEVEL>2) err_printf("chk_gen_init: subfield %Ps\n",P);
2732
if (firstprim)
2733
{ /* cycle basis vectors so that primitive elements come last */
2734
GEN u = d->u, e = M;
2735
GEN te = gel(e,i), tu = gel(u,i), tR = gel(R,i);
2736
long tS = D[i];
2737
for (j = i; j > firstprim; j--)
2738
{
2739
u[j] = u[j-1];
2740
e[j] = e[j-1];
2741
R[j] = R[j-1];
2742
D[j] = D[j-1];
2743
}
2744
gel(u,firstprim) = tu;
2745
gel(e,firstprim) = te;
2746
gel(R,firstprim) = tR;
2747
D[firstprim] = tS; firstprim++;
2748
}
2749
}
2750
}
2751
if (!firstprim)
2752
{ /* try (a little) to find primitive elements to improve bound */
2753
GEN x = cgetg(N+1, t_VECSMALL);
2754
if (DEBUGLEVEL>1)
2755
err_printf("chk_gen_init: difficult field, trying random elements\n");
2756
for (i = 0; i < 10; i++)
2757
{
2758
GEN e, B;
2759
for (j = 1; j <= N; j++) x[j] = (long)random_Fl(7) - 3;
2760
e = RgM_zc_mul(M, x);
2761
B = embed_T2(e, r1);
2762
if (gcmp(B,bound) >= 0) continue;
2763
P = get_pol(d, e); if (!P) pari_err_PREC( "chk_gen_init");
2764
if (!ZX_is_squarefree(P)) continue;
2765
if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P);
2766
bound = B ;
2767
}
2768
}
2769
2770
if (firstprim != 1)
2771
{
2772
inv = ginv( split_realimag(M, r1, r2) ); /*TODO: use QR?*/
2773
V = gel(inv,1);
2774
for (i = 2; i <= r1+r2; i++) V = gadd(V, gel(inv,i));
2775
/* V corresponds to 1_Z */
2776
V = grndtoi(V, &j);
2777
if (j > -5) pari_err_BUG("precision too low in chk_gen_init");
2778
S = mkmat(V); /* 1 */
2779
2780
V = cgetg(N+1, t_VEC);
2781
for (i = 1; i <= N; i++,skipfirst++)
2782
{ /* S = Q-basis of subfield generated by nf.zk[1..i-1] */
2783
GEN Mx, M2;
2784
long j, k, h, rkM, dP = D[i];
2785
2786
if (dP == N) break; /* primitive */
2787
Mx = set_mulid(V, M, inv, r1, r2, N, i);
2788
if (!Mx) break; /* prec. problem. Stop */
2789
if (dP == 1) continue;
2790
rkM = lg(S)-1;
2791
M2 = cgetg(N+1, t_MAT); /* we will add to S the elts of M2 */
2792
gel(M2,1) = col_ei(N, i); /* nf.zk[i] */
2793
k = 2;
2794
for (h = 1; h < dP; h++)
2795
{
2796
long r; /* add to M2 the elts of S * nf.zk[i] */
2797
for (j = 1; j <= rkM; j++) gel(M2,k++) = ZM_ZC_mul(Mx, gel(S,j));
2798
setlg(M2, k); k = 1;
2799
S = ZM_image_shallow(shallowconcat(S,M2), &r);
2800
if (r == rkM) break;
2801
if (r > rkM)
2802
{
2803
rkM = r;
2804
if (rkM == N) break;
2805
}
2806
}
2807
if (rkM == N) break;
2808
/* Q(w[1],...,w[i-1]) is a strict subfield of nf */
2809
}
2810
}
2811
/* x_1,...,x_skipfirst generate a strict subfield [unless N=skipfirst=1] */
2812
chk->skipfirst = skipfirst;
2813
if (DEBUGLEVEL>2) err_printf("chk_gen_init: skipfirst = %ld\n",skipfirst);
2814
2815
/* should be DEF + gexpo( max_k C^n_k (bound/k)^(k/2) ) */
2816
bound = gerepileuptoleaf(av, bound);
2817
prec = chk_gen_prec(N, (gexpo(bound)*N)/2);
2818
if (DEBUGLEVEL)
2819
err_printf("chk_gen_init: new prec = %ld (initially %ld)\n", prec, d->prec);
2820
if (prec > d->prec) pari_err_BUG("polredabs (precision problem)");
2821
if (prec < d->prec) d->ZKembed = gprec_w(M, prec);
2822
return bound;
2823
}
2824
2825
static GEN
2826
polredabs_i(GEN x, nfmaxord_t *S, GEN *u, long flag)
2827
{
2828
FP_chk_fun chk = { &chk_gen, &chk_gen_init, NULL, NULL, 0 };
2829
nffp_t F;
2830
CG_data d;
2831
GEN v, y, a;
2832
long i, l;
2833
2834
nfinit_basic_partial(S, x);
2835
x = S->T0;
2836
if (degpol(x) == 1)
2837
{
2838
long vx = varn(x);
2839
*u = NULL;
2840
return mkvec2(mkvec( pol_x(vx) ),
2841
mkvec( deg1pol_shallow(gen_1, negi(gel(S->T,2)), vx) ));
2842
}
2843
if (!(flag & nf_PARTIALFACT) && S->dK && S->dKP)
2844
{
2845
GEN vw = primes_certify(S->dK, S->dKP);
2846
v = gel(vw,1); l = lg(v);
2847
if (l != 1)
2848
{ /* fix integral basis */
2849
GEN w = gel(vw,2);
2850
for (i = 1; i < l; i++)
2851
w = ZV_union_shallow(w, gel(Z_factor(gel(v,i)),1));
2852
nfinit_basic(S, mkvec2(S->T0,w));
2853
}
2854
}
2855
2856
chk.data = (void*)&d;
2857
polred_init(S, &F, &d);
2858
d.bound = embed_T2(F.ro, d.r1);
2859
if (realprec(d.bound) > F.prec) d.bound = rtor(d.bound, F.prec);
2860
for (;;)
2861
{
2862
GEN R = R_from_QR(F.G, F.prec);
2863
if (R)
2864
{
2865
d.prec = F.prec;
2866
d.M = F.M;
2867
v = fincke_pohst(mkvec(R),NULL,-1, 0, &chk);
2868
if (v) break;
2869
}
2870
F.prec = precdbl(F.prec);
2871
F.ro = NULL;
2872
make_M_G(&F, 1);
2873
if (DEBUGLEVEL) pari_warn(warnprec,"polredabs0",F.prec);
2874
}
2875
y = gel(v,1);
2876
a = gel(v,2); l = lg(a);
2877
for (i = 1; i < l; i++) /* normalize wrt z -> -z */
2878
if (ZX_canon_neg(gel(y,i)) && (flag & (nf_ORIG|nf_RAW)))
2879
gel(a,i) = ZC_neg(gel(a,i));
2880
*u = d.u; return v;
2881
}
2882
2883
GEN
2884
polredabs0(GEN x, long flag)
2885
{
2886
pari_sp av = avma;
2887
GEN Y, A, u, v;
2888
nfmaxord_t S;
2889
long i, l;
2890
2891
v = polredabs_i(x, &S, &u, flag);
2892
remove_duplicates(v);
2893
Y = gel(v,1);
2894
A = gel(v,2);
2895
l = lg(A); if (l == 1) pari_err_BUG("polredabs (missing vector)");
2896
if (DEBUGLEVEL) err_printf("Found %ld minimal polynomials.\n",l-1);
2897
if (!(flag & nf_ALL))
2898
{
2899
GEN y = findmindisc(Y);
2900
for (i = 1; i < l; i++)
2901
if (ZX_equal(gel(Y,i), y)) break;
2902
Y = mkvec(gel(Y,i));
2903
A = mkvec(gel(A,i)); l = 2;
2904
}
2905
if (flag & (nf_RAW|nf_ORIG)) for (i = 1; i < l; i++)
2906
{
2907
GEN y = gel(Y,i), a = gel(A,i);
2908
if (u) a = RgV_RgC_mul(S.basis, ZM_ZC_mul(u, a));
2909
if (flag & nf_ORIG)
2910
{
2911
a = QXQ_reverse(a, S.T);
2912
if (!isint1(S.unscale)) a = gdiv(a, S.unscale); /* not RgX_Rg_div */
2913
a = mkpolmod(a,y);
2914
}
2915
gel(Y,i) = mkvec2(y, a);
2916
}
2917
return gerepilecopy(av, (flag & nf_ALL)? Y: gel(Y,1));
2918
}
2919
2920
GEN
2921
polredabsall(GEN x, long flun) { return polredabs0(x, flun | nf_ALL); }
2922
GEN
2923
polredabs(GEN x) { return polredabs0(x,0); }
2924
GEN
2925
polredabs2(GEN x) { return polredabs0(x,nf_ORIG); }
2926
2927
/* relative polredabs/best. Returns relative polynomial by default (flag = 0)
2928
* flag & nf_ORIG: + element (base change)
2929
* flag & nf_ABSOLUTE: absolute polynomial */
2930
static GEN
2931
rnfpolred_i(GEN nf, GEN R, long flag, long best)
2932
{
2933
const char *f = best? "rnfpolredbest": "rnfpolredabs";
2934
const long abs = ((flag & nf_ORIG) && (flag & nf_ABSOLUTE));
2935
GEN listP = NULL, red, pol, A, P, T, rnfeq;
2936
pari_sp av = avma;
2937
2938
if (typ(R) == t_VEC) {
2939
if (lg(R) != 3) pari_err_TYPE(f,R);
2940
listP = gel(R,2);
2941
R = gel(R,1);
2942
}
2943
if (typ(R) != t_POL) pari_err_TYPE(f,R);
2944
nf = checknf(nf);
2945
T = nf_get_pol(nf);
2946
R = RgX_nffix(f, T, R, 0);
2947
if (best || (flag & nf_PARTIALFACT))
2948
{
2949
rnfeq = abs? nf_rnfeq(nf, R): nf_rnfeqsimple(nf, R);
2950
pol = gel(rnfeq,1);
2951
if (listP) pol = mkvec2(pol, listP);
2952
red = best? polredbest_i(pol, abs? 1: 2)
2953
: polredabs0(pol, (abs? nf_ORIG: nf_RAW)|nf_PARTIALFACT);
2954
P = gel(red,1);
2955
A = gel(red,2);
2956
}
2957
else
2958
{
2959
nfmaxord_t S;
2960
GEN rnf, u, v, y, a;
2961
long i, j, l;
2962
pari_timer ti;
2963
if (DEBUGLEVEL>1) timer_start(&ti);
2964
rnf = rnfinit(nf, R);
2965
rnfeq = rnf_get_map(rnf);
2966
pol = rnf_zkabs(rnf);
2967
if (DEBUGLEVEL>1) timer_printf(&ti, "absolute basis");
2968
v = polredabs_i(pol, &S, &u, nf_ORIG);
2969
pol = gel(pol,1);
2970
y = gel(v,1); P = findmindisc(y);
2971
a = gel(v,2);
2972
l = lg(y); A = cgetg(l, t_VEC);
2973
for (i = j = 1; i < l; i++)
2974
if (ZX_equal(gel(y,i),P))
2975
{
2976
GEN t = gel(a,i);
2977
if (u) t = RgV_RgC_mul(S.basis, ZM_ZC_mul(u,t));
2978
gel(A,j++) = t;
2979
}
2980
setlg(A,j); /* mod(A[i], pol) are all roots of P in Q[X]/(pol) */
2981
}
2982
if (DEBUGLEVEL>1) err_printf("reduced absolute generator: %Ps\n",P);
2983
if (flag & nf_ABSOLUTE)
2984
{
2985
if (flag & nf_ORIG)
2986
{
2987
GEN a = gel(rnfeq,2); /* Mod(a,pol) root of T */
2988
GEN k = gel(rnfeq,3); /* Mod(variable(R),R) + k*a root of pol */
2989
if (typ(A) == t_VEC) A = gel(A,1); /* any root will do */
2990
a = RgX_RgXQ_eval(a, lift_shallow(A), P); /* Mod(a, P) root of T */
2991
P = mkvec3(P, mkpolmod(a,P), gsub(A, gmul(k,a)));
2992
}
2993
return gerepilecopy(av, P);
2994
}
2995
if (typ(A) != t_VEC)
2996
{
2997
A = eltabstorel_lift(rnfeq, A);
2998
P = lift_if_rational( RgXQ_charpoly(A, R, varn(R)) );
2999
}
3000
else
3001
{ /* canonical factor */
3002
long i, l = lg(A), v = varn(R);
3003
GEN besta = NULL;
3004
for (i = 1; i < l; i++)
3005
{
3006
GEN a = eltabstorel_lift(rnfeq, gel(A,i));
3007
GEN p = lift_if_rational( RgXQ_charpoly(a, R, v) );
3008
if (i == 1 || cmp_universal(p, P) < 0) { P = p; besta = a; }
3009
}
3010
A = besta;
3011
}
3012
if (flag & nf_ORIG) P = mkvec2(P, mkpolmod(RgXQ_reverse(A,R),P));
3013
return gerepilecopy(av, P);
3014
}
3015
GEN
3016
rnfpolredabs(GEN nf, GEN R, long flag)
3017
{ return rnfpolred_i(nf,R,flag, 0); }
3018
GEN
3019
rnfpolredbest(GEN nf, GEN R, long flag)
3020
{
3021
if (flag < 0 || flag > 3) pari_err_FLAG("rnfpolredbest");
3022
return rnfpolred_i(nf,R,flag, 1);
3023
}
3024
3025