Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28486 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
/* RAY CLASS FIELDS */
18
/* */
19
/*******************************************************************/
20
#include "pari.h"
21
#include "paripriv.h"
22
23
#define DEBUGLEVEL DEBUGLEVEL_bnr
24
25
static GEN
26
bnr_get_El(GEN bnr) { return gel(bnr,3); }
27
static GEN
28
bnr_get_U(GEN bnr) { return gel(bnr,4); }
29
static GEN
30
bnr_get_Ui(GEN bnr) { return gmael(bnr,4,3); }
31
32
/* faster than Buchray */
33
GEN
34
bnfnarrow(GEN bnf)
35
{
36
GEN nf, cyc, gen, Cyc, Gen, A, GD, v, w, H, invpi, L, R, u, U0, Uoo, archp, sarch;
37
long r1, j, l, t, RU;
38
pari_sp av;
39
40
bnf = checkbnf(bnf);
41
nf = bnf_get_nf(bnf);
42
r1 = nf_get_r1(nf); if (!r1) return gcopy( bnf_get_clgp(bnf) );
43
44
/* simplified version of nfsign_units; r1 > 0 so bnf.tu = -1 */
45
av = avma; archp = identity_perm(r1);
46
A = bnf_get_logfu(bnf); RU = lg(A)+1;
47
invpi = invr( mppi(nf_get_prec(nf)) );
48
v = cgetg(RU,t_MAT); gel(v, 1) = const_vecsmall(r1, 1); /* nfsign(-1) */
49
for (j=2; j<RU; j++) gel(v,j) = nfsign_from_logarch(gel(A,j-1), invpi, archp);
50
/* up to here */
51
52
v = Flm_image(v, 2); t = lg(v)-1;
53
if (t == r1) { set_avma(av); return gcopy( bnf_get_clgp(bnf) ); }
54
55
v = Flm_suppl(v,2); /* v = (sgn(U)|H) in GL_r1(F_2) */
56
H = zm_to_ZM( vecslice(v, t+1, r1) ); /* supplement H of sgn(U) */
57
w = rowslice(Flm_inv(v,2), t+1, r1); /* H*w*z = proj of z on H // sgn(U) */
58
59
sarch = nfarchstar(nf, NULL, archp);
60
cyc = bnf_get_cyc(bnf);
61
gen = bnf_get_gen(bnf); l = lg(gen);
62
L = cgetg(l,t_MAT); GD = gmael(bnf,9,3);
63
for (j=1; j<l; j++)
64
{
65
GEN z = nfsign_from_logarch(gel(GD,j), invpi, archp);
66
gel(L,j) = zc_to_ZC( Flm_Flc_mul(w, z, 2) );
67
}
68
/* [cyc, 0; L, 2] = relation matrix for Cl_f */
69
R = shallowconcat(
70
vconcat(diagonal_shallow(cyc), L),
71
vconcat(zeromat(l-1, r1-t), scalarmat_shallow(gen_2,r1-t)));
72
Cyc = ZM_snf_group(R, NULL, &u);
73
U0 = rowslice(u, 1, l-1);
74
Uoo = ZM_mul(H, rowslice(u, l, nbrows(u)));
75
l = lg(Cyc); Gen = cgetg(l,t_VEC);
76
for (j = 1; j < l; j++)
77
{
78
GEN g = gel(U0,j), s = gel(Uoo,j);
79
g = (lg(g) == 1)? gen_1: Q_primpart( idealfactorback(nf,gen,g,0) );
80
if (!ZV_equal0(s))
81
{
82
GEN a = set_sign_mod_divisor(nf, ZV_to_Flv(s,2), gen_1, sarch);
83
g = is_pm1(g)? a: idealmul(nf, a, g);
84
}
85
gel(Gen,j) = g;
86
}
87
return gerepilecopy(av, mkvec3(shifti(bnf_get_no(bnf),r1-t), Cyc, Gen));
88
}
89
90
/********************************************************************/
91
/** **/
92
/** REDUCTION MOD IDELE **/
93
/** **/
94
/********************************************************************/
95
96
static GEN
97
compute_fact(GEN nf, GEN U, GEN gen)
98
{
99
long i, j, l = lg(U), h = lgcols(U); /* l > 1 */
100
GEN basecl = cgetg(l,t_VEC), G;
101
102
G = mkvec2(NULL, trivial_fact());
103
for (j = 1; j < l; j++)
104
{
105
GEN z = NULL;
106
for (i = 1; i < h; i++)
107
{
108
GEN g, e = gcoeff(U,i,j); if (!signe(e)) continue;
109
110
g = gel(gen,i);
111
if (typ(g) != t_MAT)
112
{
113
if (z)
114
gel(z,2) = famat_mulpow_shallow(gel(z,2), g, e);
115
else
116
z = mkvec2(NULL, to_famat_shallow(g, e));
117
continue;
118
}
119
gel(G,1) = g;
120
g = idealpowred(nf,G,e);
121
z = z? idealmulred(nf,z,g): g;
122
}
123
gel(z,2) = famat_reduce(gel(z,2));
124
gel(basecl,j) = z;
125
}
126
return basecl;
127
}
128
129
static int
130
too_big(GEN nf, GEN bet)
131
{
132
GEN x = nfnorm(nf,bet);
133
switch (typ(x))
134
{
135
case t_INT: return abscmpii(x, gen_1);
136
case t_FRAC: return abscmpii(gel(x,1), gel(x,2));
137
}
138
pari_err_BUG("wrong type in too_big");
139
return 0; /* LCOV_EXCL_LINE */
140
}
141
142
/* true nf; GTM 193: Algo 4.3.4. Reduce x mod divisor */
143
static GEN
144
idealmoddivisor_aux(GEN nf, GEN x, GEN f, GEN sarch)
145
{
146
pari_sp av = avma;
147
GEN a, A;
148
149
if ( is_pm1(gcoeff(f,1,1)) ) /* f = 1 */
150
{
151
A = idealred(nf, mkvec2(x, gen_1));
152
A = nfinv(nf, gel(A,2));
153
}
154
else
155
{/* given coprime integral ideals x and f (f HNF), compute "small"
156
* G in x, such that G = 1 mod (f). GTM 193: Algo 4.3.3 */
157
GEN G = idealaddtoone_raw(nf, x, f);
158
GEN D = idealaddtoone_i(nf, idealdiv(nf,G,x), f);
159
A = nfdiv(nf,D,G);
160
}
161
if (too_big(nf,A) > 0) return gc_const(av, x);
162
a = set_sign_mod_divisor(nf, NULL, A, sarch);
163
if (a != A && too_big(nf,A) > 0) return gc_const(av, x);
164
return idealmul(nf, a, x);
165
}
166
167
GEN
168
idealmoddivisor(GEN bnr, GEN x)
169
{
170
GEN nf = bnr_get_nf(bnr), bid = bnr_get_bid(bnr);
171
return idealmoddivisor_aux(nf, x, bid_get_ideal(bid), bid_get_sarch(bid));
172
}
173
174
/* v_pr(L0 * cx) */
175
static long
176
fast_val(GEN L0, GEN cx, GEN pr)
177
{
178
pari_sp av = avma;
179
long v = typ(L0) == t_INT? 0: ZC_nfval(L0,pr);
180
if (cx)
181
{
182
long w = Q_pval(cx, pr_get_p(pr));
183
if (w) v += w * pr_get_e(pr);
184
}
185
return gc_long(av,v);
186
}
187
188
/* x coprime to fZ, return y = x mod fZ, y integral */
189
static GEN
190
make_integral_Z(GEN x, GEN fZ)
191
{
192
GEN d, y = Q_remove_denom(x, &d);
193
if (d) y = FpC_Fp_mul(y, Fp_inv(d, fZ), fZ);
194
return y;
195
}
196
197
/* p pi^(-1) mod f */
198
static GEN
199
get_pinvpi(GEN nf, GEN fZ, GEN p, GEN pi, GEN *v)
200
{
201
if (!*v) {
202
GEN invpi = nfinv(nf, pi);
203
*v = make_integral_Z(RgC_Rg_mul(invpi, p), mulii(p, fZ));
204
}
205
return *v;
206
}
207
/* uniformizer pi for pr, coprime to F/p */
208
static GEN
209
get_pi(GEN F, GEN pr, GEN *v)
210
{
211
if (!*v) *v = pr_uniformizer(pr, F);
212
return *v;
213
}
214
215
/* true nf */
216
static GEN
217
bnr_grp(GEN nf, GEN U, GEN gen, GEN cyc, GEN bid)
218
{
219
GEN h = ZV_prod(cyc);
220
GEN f, fZ, basecl, fa, pr, t, EX, sarch, F, P, vecpi, vecpinvpi;
221
long i,j,l,lp;
222
223
if (lg(U) == 1) return mkvec3(h, cyc, cgetg(1, t_VEC));
224
basecl = compute_fact(nf, U, gen); /* generators in factored form */
225
EX = gel(bid_get_cyc(bid),1); /* exponent of (O/f)^* */
226
f = bid_get_ideal(bid); fZ = gcoeff(f,1,1);
227
fa = bid_get_fact(bid);
228
sarch = bid_get_sarch(bid);
229
P = gel(fa,1); F = prV_lcm_capZ(P);
230
231
lp = lg(P);
232
vecpinvpi = cgetg(lp, t_VEC);
233
vecpi = cgetg(lp, t_VEC);
234
for (i=1; i<lp; i++)
235
{
236
pr = gel(P,i);
237
gel(vecpi,i) = NULL; /* to be computed if needed */
238
gel(vecpinvpi,i) = NULL; /* to be computed if needed */
239
}
240
241
l = lg(basecl);
242
for (i=1; i<l; i++)
243
{
244
GEN p, pi, pinvpi, dmulI, mulI, G, I, A, e, L, newL;
245
long la, v, k;
246
pari_sp av;
247
/* G = [I, A=famat(L,e)] is a generator, I integral */
248
G = gel(basecl,i);
249
I = gel(G,1);
250
A = gel(G,2); L = gel(A,1); e = gel(A,2);
251
/* if no reduction took place in compute_fact, everybody is still coprime
252
* to f + no denominators */
253
if (!I) { gel(basecl,i) = famat_to_nf_moddivisor(nf, L, e, bid); continue; }
254
if (lg(A) == 1) { gel(basecl,i) = I; continue; }
255
256
/* compute mulI so that mulI * I coprime to f
257
* FIXME: use idealcoprime ??? (Less efficient. Fix idealcoprime!) */
258
dmulI = mulI = NULL;
259
for (j=1; j<lp; j++)
260
{
261
pr = gel(P,j);
262
v = idealval(nf, I, pr);
263
if (!v) continue;
264
p = pr_get_p(pr);
265
pi = get_pi(F, pr, &gel(vecpi,j));
266
pinvpi = get_pinvpi(nf, fZ, p, pi, &gel(vecpinvpi,j));
267
t = nfpow_u(nf, pinvpi, (ulong)v);
268
mulI = mulI? nfmuli(nf, mulI, t): t;
269
t = powiu(p, v);
270
dmulI = dmulI? mulii(dmulI, t): t;
271
}
272
273
/* make all components of L coprime to f.
274
* Assuming (L^e * I, f) = 1, then newL^e * mulI = L^e */
275
la = lg(e); newL = cgetg(la, t_VEC);
276
for (k=1; k<la; k++)
277
{
278
GEN cx, LL = nf_to_scalar_or_basis(nf, gel(L,k));
279
GEN L0 = Q_primitive_part(LL, &cx); /* LL = L0*cx (faster nfval) */
280
for (j=1; j<lp; j++)
281
{
282
pr = gel(P,j);
283
v = fast_val(L0,cx, pr); /* = val_pr(LL) */
284
if (!v) continue;
285
p = pr_get_p(pr);
286
pi = get_pi(F, pr, &gel(vecpi,j));
287
if (v > 0)
288
{
289
pinvpi = get_pinvpi(nf, fZ, p, pi, &gel(vecpinvpi,j));
290
t = nfpow_u(nf,pinvpi, (ulong)v);
291
LL = nfmul(nf, LL, t);
292
LL = gdiv(LL, powiu(p, v));
293
}
294
else
295
{
296
t = nfpow_u(nf,pi,(ulong)(-v));
297
LL = nfmul(nf, LL, t);
298
}
299
}
300
LL = make_integral(nf,LL,f,P);
301
gel(newL,k) = typ(LL) == t_INT? LL: FpC_red(LL, fZ);
302
}
303
304
av = avma;
305
/* G in nf, = L^e mod f */
306
G = famat_to_nf_modideal_coprime(nf, newL, e, f, EX);
307
if (mulI)
308
{
309
G = nfmuli(nf, G, mulI);
310
G = typ(G) == t_COL? ZC_hnfrem(G, ZM_Z_mul(f, dmulI))
311
: modii(G, mulii(fZ,dmulI));
312
G = RgC_Rg_div(G, dmulI);
313
}
314
G = set_sign_mod_divisor(nf,A,G,sarch);
315
I = idealmul(nf,I,G);
316
/* more or less useless, but cheap at this point */
317
I = idealmoddivisor_aux(nf,I,f,sarch);
318
gel(basecl,i) = gerepilecopy(av, I);
319
}
320
return mkvec3(h, cyc, basecl);
321
}
322
323
/********************************************************************/
324
/** **/
325
/** INIT RAY CLASS GROUP **/
326
/** **/
327
/********************************************************************/
328
GEN
329
bnr_subgroup_check(GEN bnr, GEN H, GEN *pdeg)
330
{
331
GEN no = bnr_get_no(bnr);
332
if (H && isintzero(H)) H = NULL;
333
if (H)
334
{
335
GEN h, cyc = bnr_get_cyc(bnr);
336
switch(typ(H))
337
{
338
case t_INT:
339
H = scalarmat_shallow(H, lg(cyc)-1);
340
/* fall through */
341
case t_MAT:
342
RgM_check_ZM(H, "bnr_subgroup_check");
343
H = ZM_hnfmodid(H, cyc);
344
break;
345
case t_VEC:
346
if (char_check(cyc, H)) { H = charker(cyc, H); break; }
347
default: pari_err_TYPE("bnr_subgroup_check", H);
348
}
349
h = ZM_det_triangular(H);
350
if (equalii(h, no)) H = NULL; else no = h;
351
}
352
if (pdeg) *pdeg = no;
353
return H;
354
}
355
356
void
357
bnr_subgroup_sanitize(GEN *pbnr, GEN *pH)
358
{
359
GEN D, cnd, mod, cyc, bnr = *pbnr, H = *pH;
360
361
if (nftyp(bnr)==typ_BNF) bnr = Buchray(bnr, gen_1, nf_INIT);
362
else checkbnr(bnr);
363
cyc = bnr_get_cyc(bnr);
364
if (!H) mod = cyc_get_expo(cyc);
365
else switch(typ(H))
366
{
367
case t_INT: mod = H; break;
368
case t_VEC:
369
if (!char_check(cyc, H))
370
pari_err_TYPE("bnr_subgroup_sanitize [character]", H);
371
H = charker(cyc, H); /* character -> subgroup */
372
case t_MAT:
373
H = hnfmodid(H, cyc); /* make sure H is a left divisor of Mat(cyc) */
374
D = ZM_snf(H); /* structure of Cl_f / H */
375
mod = lg(D) == 1? gen_1: gel(D,1);
376
break;
377
default: pari_err_TYPE("bnr_subroup_sanitize [subgroup]", H);
378
mod = NULL;
379
}
380
cnd = bnrconductormod(bnr, H, mod);
381
*pbnr = gel(cnd,2); *pH = gel(cnd,3);
382
}
383
void
384
bnr_char_sanitize(GEN *pbnr, GEN *pchi)
385
{
386
GEN cnd, cyc, bnr = *pbnr, chi = *pchi;
387
388
if (nftyp(bnr)==typ_BNF) bnr = Buchray(bnr, gen_1, nf_INIT);
389
else checkbnr(bnr);
390
cyc = bnr_get_cyc(bnr);
391
if (typ(chi) != t_VEC || !char_check(cyc, chi))
392
pari_err_TYPE("bnr_char_sanitize [character]", chi);
393
cnd = bnrconductormod(bnr, chi, charorder(cyc, chi));
394
*pbnr = gel(cnd,2); *pchi = gel(cnd,3);
395
}
396
397
398
/* c a rational content (NULL or t_INT or t_FRAC), return u*c as a ZM/d */
399
static GEN
400
ZM_content_mul(GEN u, GEN c, GEN *pd)
401
{
402
*pd = gen_1;
403
if (c)
404
{
405
if (typ(c) == t_FRAC) { *pd = gel(c,2); c = gel(c,1); }
406
if (!is_pm1(c)) u = ZM_Z_mul(u, c);
407
}
408
return u;
409
}
410
411
/* bnr natural generators: bnf gens made coprime to modulus + bid gens */
412
static GEN
413
get_Gen(GEN bnf, GEN bid, GEN El)
414
{
415
GEN Gen = shallowconcat(bnf_get_gen(bnf), bid_get_gen(bid));
416
GEN nf = bnf_get_nf(bnf);
417
long i, l = lg(El);
418
for (i = 1; i < l; i++)
419
{
420
GEN e = gel(El,i);
421
if (!isint1(e)) gel(Gen,i) = idealmul(nf, gel(El,i), gel(Gen,i));
422
}
423
return Gen;
424
}
425
426
static GEN
427
Buchraymod_i(GEN bnf, GEN module, long flag, GEN MOD)
428
{
429
GEN nf, cyc0, cyc, gen, Cyc, clg, h, logU, U, Ui, vu;
430
GEN bid, cycbid, H, El;
431
long RU, Ri, j, ngen;
432
const long add_gen = flag & nf_GEN;
433
const long do_init = flag & nf_INIT;
434
435
if (MOD && typ(MOD) != t_INT)
436
pari_err_TYPE("bnrinit [incorrect cycmod]", MOD);
437
bnf = checkbnf(bnf);
438
nf = bnf_get_nf(bnf);
439
RU = lg(nf_get_roots(nf))-1; /* #K.futu */
440
El = NULL; /* gcc -Wall */
441
cyc = cyc0 = bnf_get_cyc(bnf);
442
gen = bnf_get_gen(bnf); ngen = lg(cyc)-1;
443
444
bid = checkbid_i(module);
445
if (!bid) bid = Idealstarmod(nf,module,nf_GEN|nf_INIT, MOD);
446
cycbid = bid_get_cyc(bid);
447
if (MOD)
448
{
449
cyc = ZV_snf_gcd(cyc, MOD);
450
cycbid = ZV_snf_gcd(cycbid, MOD);
451
}
452
Ri = lg(cycbid)-1;
453
if (Ri || add_gen || do_init)
454
{
455
GEN fx = bid_get_fact(bid);
456
El = cgetg(ngen+1,t_VEC);
457
for (j=1; j<=ngen; j++)
458
{
459
GEN c = idealcoprimefact(nf, gel(gen,j), fx);
460
gel(El,j) = nf_to_scalar_or_basis(nf,c);
461
}
462
}
463
if (!Ri)
464
{
465
GEN hK = bnf_get_no(bnf);
466
clg = add_gen? mkvec3(hK, cyc, get_Gen(bnf, bid, El)): mkvec2(hK, cyc);
467
if (!do_init) return clg;
468
U = matid(ngen);
469
U = mkvec3(U, cgetg(1,t_MAT), U);
470
vu = mkvec3(cgetg(1,t_MAT), matid(RU), gen_1);
471
return mkvecn(6, bnf, bid, El, U, clg, vu);
472
}
473
474
logU = ideallog_units0(bnf, bid, MOD);
475
if (do_init)
476
{ /* (log(Units)|D) * u = (0 | H) */
477
GEN c1,c2, u,u1,u2, Hi, D = shallowconcat(logU, diagonal_shallow(cycbid));
478
H = ZM_hnfall_i(D, &u, 1);
479
u1 = matslice(u, 1,RU, 1,RU);
480
u2 = matslice(u, 1,RU, RU+1,lg(u)-1);
481
/* log(Units) (u1|u2) = (0|H) (mod D), H HNF */
482
483
u1 = ZM_lll(u1, 0.99, LLL_INPLACE);
484
Hi = Q_primitive_part(RgM_inv_upper(H), &c1);
485
u2 = ZM_mul(ZM_reducemodmatrix(u2,u1), Hi);
486
u2 = Q_primitive_part(u2, &c2);
487
u2 = ZM_content_mul(u2, mul_content(c1,c2), &c2);
488
vu = mkvec3(u2,u1,c2); /* u2/c2 = H^(-1) (mod Im u1) */
489
}
490
else
491
{
492
H = ZM_hnfmodid(logU, cycbid);
493
vu = NULL; /* -Wall */
494
}
495
if (!ngen)
496
h = H;
497
else
498
{
499
GEN L = cgetg(ngen+1, t_MAT), cycgen = bnf_build_cycgen(bnf);
500
for (j=1; j<=ngen; j++)
501
{
502
GEN c = gel(cycgen,j), e = gel(El,j);
503
if (!equali1(e)) c = famat_mulpow_shallow(c, e, gel(cyc0,j));
504
gel(L,j) = ideallogmod(nf, c, bid, MOD); /* = log(Gen[j]^cyc[j]) */
505
}
506
/* [cyc0, 0; -L, H] = relation matrix for generators Gen of Cl_f */
507
h = shallowconcat(vconcat(diagonal_shallow(cyc0), ZM_neg(L)),
508
vconcat(zeromat(ngen, Ri), H));
509
h = MOD? ZM_hnfmodid(h, MOD): ZM_hnf(h);
510
}
511
Cyc = ZM_snf_group(h, &U, &Ui);
512
/* Gen = clg.gen*U, clg.gen = Gen*Ui */
513
clg = add_gen? bnr_grp(nf, Ui, get_Gen(bnf, bid, El), Cyc, bid)
514
: mkvec2(ZV_prod(Cyc), Cyc);
515
if (!do_init) return clg;
516
U = mkvec3(vecslice(U, 1,ngen), vecslice(U,ngen+1,lg(U)-1), Ui);
517
return mkvecn(6, bnf, bid, El, U, clg, vu);
518
}
519
GEN
520
Buchray(GEN bnf, GEN f, long flag)
521
{ return Buchraymod(bnf, f, flag, NULL); }
522
GEN
523
Buchraymod(GEN bnf, GEN f, long flag, GEN MOD)
524
{
525
pari_sp av = avma;
526
return gerepilecopy(av, Buchraymod_i(bnf, f, flag, MOD));
527
}
528
GEN
529
bnrinitmod(GEN bnf, GEN f, long flag, GEN MOD)
530
{
531
switch(flag)
532
{
533
case 0: flag = nf_INIT; break;
534
case 1: flag = nf_INIT | nf_GEN; break;
535
default: pari_err_FLAG("bnrinit");
536
}
537
return Buchraymod(bnf, f, flag, MOD);
538
}
539
GEN
540
bnrinit0(GEN bnf, GEN ideal, long flag)
541
{ return bnrinitmod(bnf, ideal, flag, NULL); }
542
543
GEN
544
bnrclassno(GEN bnf,GEN ideal)
545
{
546
GEN h, D, bid, cycbid;
547
pari_sp av = avma;
548
549
bnf = checkbnf(bnf);
550
h = bnf_get_no(bnf);
551
bid = checkbid_i(ideal);
552
if (!bid) bid = Idealstar(bnf, ideal, nf_INIT);
553
cycbid = bid_get_cyc(bid);
554
if (lg(cycbid) == 1) { set_avma(av); return icopy(h); }
555
D = ideallog_units(bnf, bid); /* (Z_K/f)^* / units ~ Z^n / D */
556
D = ZM_hnfmodid(D,cycbid);
557
return gerepileuptoint(av, mulii(h, ZM_det_triangular(D)));
558
}
559
GEN
560
bnrclassno0(GEN A, GEN B, GEN C)
561
{
562
pari_sp av = avma;
563
GEN h, H = NULL;
564
/* adapted from ABC_to_bnr, avoid costly bnrinit if possible */
565
if (typ(A) == t_VEC)
566
switch(lg(A))
567
{
568
case 7: /* bnr */
569
checkbnr(A); H = B;
570
break;
571
case 11: /* bnf */
572
if (!B) pari_err_TYPE("bnrclassno [bnf+missing conductor]",A);
573
if (!C) return bnrclassno(A, B);
574
A = Buchray(A, B, nf_INIT); H = C;
575
break;
576
default: checkbnf(A);/*error*/
577
}
578
else checkbnf(A);/*error*/
579
580
H = bnr_subgroup_check(A, H, &h);
581
if (!H) { set_avma(av); return icopy(h); }
582
return gerepileuptoint(av, h);
583
}
584
585
/* ZMV_ZCV_mul for two matrices U = [Ux,Uy], it may have more components
586
* (ignored) and vectors x,y */
587
static GEN
588
ZM2_ZC2_mul(GEN U, GEN x, GEN y)
589
{
590
GEN Ux = gel(U,1), Uy = gel(U,2);
591
if (lg(Ux) == 1) return ZM_ZC_mul(Uy,y);
592
if (lg(Uy) == 1) return ZM_ZC_mul(Ux,x);
593
return ZC_add(ZM_ZC_mul(Ux,x), ZM_ZC_mul(Uy,y));
594
}
595
596
GEN
597
bnrisprincipalmod(GEN bnr, GEN x, GEN MOD, long flag)
598
{
599
pari_sp av = avma;
600
GEN E, G, clgp, bnf, nf, bid, ex, cycray, alpha, El;
601
int trivialbid;
602
603
checkbnr(bnr);
604
El = bnr_get_El(bnr);
605
cycray = bnr_get_cyc(bnr);
606
if (MOD && flag) pari_err_FLAG("bnrisprincipalmod [MOD!=NULL and flag!=0]");
607
if (lg(cycray) == 1 && !(flag & nf_GEN)) return cgetg(1,t_COL);
608
if (MOD) cycray = ZV_snf_gcd(cycray, MOD);
609
610
bnf = bnr_get_bnf(bnr); nf = bnf_get_nf(bnf);
611
bid = bnr_get_bid(bnr);
612
trivialbid = lg(bid_get_cyc(bid)) == 1;
613
if (trivialbid) ex = isprincipal(bnf, x);
614
else
615
{
616
GEN v = bnfisprincipal0(bnf, x, nf_FORCE|nf_GENMAT);
617
GEN e = gel(v,1), b = gel(v,2);
618
long i, j = lg(e);
619
for (i = 1; i < j; i++) /* modify b as if bnf.gen were El*bnf.gen */
620
if (typ(gel(El,i)) != t_INT && signe(gel(e,i))) /* <==> != 1 */
621
b = famat_mulpow_shallow(b, gel(El,i), negi(gel(e,i)));
622
if (!MOD && !(flag & nf_GEN)) MOD = gel(cycray,1);
623
ex = ZM2_ZC2_mul(bnr_get_U(bnr), e, ideallogmod(nf, b, bid, MOD));
624
}
625
ex = vecmodii(ex, cycray);
626
if (!(flag & (nf_GEN|nf_GENMAT))) return gerepileupto(av, ex);
627
628
/* compute generator */
629
E = ZC_neg(ex);
630
clgp = bnr_get_clgp(bnr);
631
if (lg(clgp) == 4)
632
G = abgrp_get_gen(clgp);
633
else
634
{
635
G = get_Gen(bnf, bid, El);
636
E = ZM_ZC_mul(bnr_get_Ui(bnr), E);
637
}
638
alpha = isprincipalfact(bnf, x, G, E, nf_GENMAT|nf_GEN_IF_PRINCIPAL|nf_FORCE);
639
if (alpha == gen_0) pari_err_BUG("isprincipalray");
640
if (!trivialbid)
641
{
642
GEN v = gel(bnr,6), u2 = gel(v,1), u1 = gel(v,2), du2 = gel(v,3);
643
GEN y = ZM_ZC_mul(u2, ideallog(nf, alpha, bid));
644
if (!is_pm1(du2)) y = ZC_Z_divexact(y,du2);
645
y = ZC_reducemodmatrix(y, u1);
646
if (!ZV_equal0(y))
647
{
648
GEN U = shallowcopy(bnf_build_units(bnf));
649
settyp(U, t_COL);
650
alpha = famat_div_shallow(alpha, mkmat2(U,y));
651
}
652
}
653
alpha = famat_reduce(alpha);
654
if (!(flag & nf_GENMAT)) alpha = nffactorback(nf, alpha, NULL);
655
return gerepilecopy(av, mkvec2(ex,alpha));
656
}
657
658
GEN
659
bnrisprincipal(GEN bnr, GEN x, long flag)
660
{ return bnrisprincipalmod(bnr, x, NULL, flag); }
661
662
GEN
663
isprincipalray(GEN bnr, GEN x) { return bnrisprincipal(bnr,x,0); }
664
GEN
665
isprincipalraygen(GEN bnr, GEN x) { return bnrisprincipal(bnr,x,nf_GEN); }
666
667
/* N! / N^N * (4/pi)^r2 * sqrt(|D|) */
668
GEN
669
minkowski_bound(GEN D, long N, long r2, long prec)
670
{
671
pari_sp av = avma;
672
GEN c = divri(mpfactr(N,prec), powuu(N,N));
673
if (r2) c = mulrr(c, powru(divur(4,mppi(prec)), r2));
674
c = mulrr(c, gsqrt(absi_shallow(D),prec));
675
return gerepileuptoleaf(av, c);
676
}
677
678
/* N = [K:Q] > 1, D = disc(K) */
679
static GEN
680
zimmertbound(GEN D, long N, long R2)
681
{
682
pari_sp av = avma;
683
GEN w;
684
685
if (N > 20) w = minkowski_bound(D, N, R2, DEFAULTPREC);
686
else
687
{
688
const double c[19][11] = {
689
{/*2*/ 0.6931, 0.45158},
690
{/*3*/ 1.71733859, 1.37420604},
691
{/*4*/ 2.91799837, 2.50091538, 2.11943331},
692
{/*5*/ 4.22701425, 3.75471588, 3.31196660},
693
{/*6*/ 5.61209925, 5.09730381, 4.60693851, 4.14303665},
694
{/*7*/ 7.05406203, 6.50550021, 5.97735406, 5.47145968},
695
{/*8*/ 8.54052636, 7.96438858, 7.40555445, 6.86558259, 6.34608077},
696
{/*9*/ 10.0630022, 9.46382812, 8.87952524, 8.31139202, 7.76081149},
697
{/*10*/11.6153797, 10.9966020, 10.3907654, 9.79895170, 9.22232770, 8.66213267},
698
{/*11*/13.1930961, 12.5573772, 11.9330458, 11.3210061, 10.7222412, 10.1378082},
699
{/*12*/14.7926394, 14.1420915, 13.5016616, 12.8721114, 12.2542699, 11.6490374,
700
11.0573775},
701
{/*13*/16.4112395, 15.7475710, 15.0929680, 14.4480777, 13.8136054, 13.1903162,
702
12.5790381},
703
{/*14*/18.0466672, 17.3712806, 16.7040780, 16.0456127, 15.3964878, 14.7573587,
704
14.1289364, 13.5119848},
705
{/*15*/19.6970961, 19.0111606, 18.3326615, 17.6620757, 16.9999233, 16.3467686,
706
15.7032228, 15.0699480},
707
{/*16*/21.3610081, 20.6655103, 19.9768082, 19.2953176, 18.6214885, 17.9558093,
708
17.2988108, 16.6510652, 16.0131906},
709
710
{/*17*/23.0371259, 22.3329066, 21.6349299, 20.9435607, 20.2591899, 19.5822454,
711
18.9131878, 18.2525157, 17.6007672},
712
713
{/*18*/24.7243611, 24.0121449, 23.3056902, 22.6053167, 21.9113705, 21.2242247,
714
20.5442836, 19.8719830, 19.2077941, 18.5522234},
715
716
{/*19*/26.4217792, 25.7021950, 24.9879497, 24.2793271, 23.5766321, 22.8801952,
717
22.1903709, 21.5075437, 20.8321263, 20.1645647},
718
{/*20*/28.1285704, 27.4021674, 26.6807314, 25.9645140, 25.2537867, 24.5488420,
719
23.8499943, 23.1575823, 22.4719720, 21.7935548, 21.1227537}
720
};
721
w = mulrr(dbltor(exp(-c[N-2][R2])), gsqrt(absi_shallow(D),DEFAULTPREC));
722
}
723
return gerepileuptoint(av, ceil_safe(w));
724
}
725
726
/* return \gamma_n^n if known, an upper bound otherwise */
727
GEN
728
Hermite_bound(long n, long prec)
729
{
730
GEN h,h1;
731
pari_sp av;
732
733
switch(n)
734
{
735
case 1: return gen_1;
736
case 2: retmkfrac(utoipos(4), utoipos(3));
737
case 3: return gen_2;
738
case 4: return utoipos(4);
739
case 5: return utoipos(8);
740
case 6: retmkfrac(utoipos(64), utoipos(3));
741
case 7: return utoipos(64);
742
case 8: return utoipos(256);
743
case 24: return int2n(48);
744
}
745
av = avma;
746
h = powru(divur(2,mppi(prec)), n);
747
h1 = sqrr(ggamma(sstoQ(n+4,2),prec));
748
return gerepileuptoleaf(av, mulrr(h,h1));
749
}
750
751
/* 1 if L (= nf != Q) primitive for sure, 0 if MAYBE imprimitive (may have a
752
* subfield K) */
753
static long
754
isprimitive(GEN nf)
755
{
756
long p, i, l, ep, N = nf_get_degree(nf);
757
GEN D, fa;
758
759
p = ucoeff(factoru(N), 1,1); /* smallest prime | N */
760
if (p == N) return 1; /* prime degree */
761
762
/* N = [L:Q] = product of primes >= p, same is true for [L:K]
763
* d_L = t d_K^[L:K] --> check that some q^p divides d_L */
764
D = nf_get_disc(nf);
765
fa = gel(absZ_factor_limit(D,0),2); /* list of v_q(d_L). Don't check large primes */
766
if (mod2(D)) i = 1;
767
else
768
{ /* q = 2 */
769
ep = itos(gel(fa,1));
770
if ((ep>>1) >= p) return 0; /* 2 | d_K ==> 4 | d_K */
771
i = 2;
772
}
773
l = lg(fa);
774
for ( ; i < l; i++)
775
{
776
ep = itos(gel(fa,i));
777
if (ep >= p) return 0;
778
}
779
return 1;
780
}
781
782
static GEN
783
dft_bound(void)
784
{
785
if (DEBUGLEVEL>1) err_printf("Default bound for regulator: 0.2\n");
786
return dbltor(0.2);
787
}
788
789
static GEN
790
regulatorbound(GEN bnf)
791
{
792
long N, R1, R2, R;
793
GEN nf, dK, p1, c1;
794
795
nf = bnf_get_nf(bnf); N = nf_get_degree(nf);
796
if (!isprimitive(nf)) return dft_bound();
797
798
dK = absi_shallow(nf_get_disc(nf));
799
nf_get_sign(nf, &R1, &R2); R = R1+R2-1;
800
c1 = (!R2 && N<12)? int2n(N & (~1UL)): powuu(N,N);
801
if (cmpii(dK,c1) <= 0) return dft_bound();
802
803
p1 = sqrr(glog(gdiv(dK,c1),DEFAULTPREC));
804
p1 = divru(gmul2n(powru(divru(mulru(p1,3),N*(N*N-1)-6*R2),R),R2), N);
805
p1 = sqrtr(gdiv(p1, Hermite_bound(R, DEFAULTPREC)));
806
if (DEBUGLEVEL>1) err_printf("Mahler bound for regulator: %Ps\n",p1);
807
return gmax_shallow(p1, dbltor(0.2));
808
}
809
810
static int
811
is_unit(GEN M, long r1, GEN x)
812
{
813
pari_sp av = avma;
814
GEN Nx = ground( embed_norm(RgM_zc_mul(M,x), r1) );
815
return gc_bool(av, is_pm1(Nx));
816
}
817
818
/* FIXME: should use smallvectors */
819
static double
820
minimforunits(GEN nf, long BORNE, ulong w)
821
{
822
const long prec = MEDDEFAULTPREC;
823
long n, r1, i, j, k, *x, cnt = 0;
824
pari_sp av = avma;
825
GEN r, M;
826
double p, norme, normin;
827
double **q,*v,*y,*z;
828
double eps=0.000001, BOUND = BORNE * 1.00001;
829
830
if (DEBUGLEVEL>=2)
831
{
832
err_printf("Searching minimum of T2-form on units:\n");
833
if (DEBUGLEVEL>2) err_printf(" BOUND = %ld\n",BORNE);
834
}
835
n = nf_get_degree(nf); r1 = nf_get_r1(nf);
836
minim_alloc(n+1, &q, &x, &y, &z, &v);
837
M = gprec_w(nf_get_M(nf), prec);
838
r = gaussred_from_QR(nf_get_G(nf), prec);
839
for (j=1; j<=n; j++)
840
{
841
v[j] = gtodouble(gcoeff(r,j,j));
842
for (i=1; i<j; i++) q[i][j] = gtodouble(gcoeff(r,i,j));
843
}
844
normin = (double)BORNE*(1-eps);
845
k=n; y[n]=z[n]=0;
846
x[n] = (long)(sqrt(BOUND/v[n]));
847
848
for(;;x[1]--)
849
{
850
do
851
{
852
if (k>1)
853
{
854
long l = k-1;
855
z[l] = 0;
856
for (j=k; j<=n; j++) z[l] += q[l][j]*x[j];
857
p = (double)x[k] + z[k];
858
y[l] = y[k] + p*p*v[k];
859
x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]);
860
k = l;
861
}
862
for(;;)
863
{
864
p = (double)x[k] + z[k];
865
if (y[k] + p*p*v[k] <= BOUND) break;
866
k++; x[k]--;
867
}
868
}
869
while (k>1);
870
if (!x[1] && y[1]<=eps) break;
871
872
if (DEBUGLEVEL>8) err_printf(".");
873
if (++cnt == 5000) return -1.; /* too expensive */
874
875
p = (double)x[1] + z[1]; norme = y[1] + p*p*v[1];
876
if (is_unit(M, r1, x) && norme < normin)
877
{
878
/* exclude roots of unity */
879
if (norme < 2*n)
880
{
881
GEN t = nfpow_u(nf, zc_to_ZC(x), w);
882
if (typ(t) != t_COL || ZV_isscalar(t)) continue;
883
}
884
normin = norme*(1-eps);
885
if (DEBUGLEVEL>=2) err_printf("*");
886
}
887
}
888
if (DEBUGLEVEL>=2) err_printf("\n");
889
set_avma(av);
890
return normin;
891
}
892
893
#undef NBMAX
894
static int
895
is_zero(GEN x, long bitprec) { return (gexpo(x) < -bitprec); }
896
897
static int
898
is_complex(GEN x, long bitprec) { return !is_zero(imag_i(x), bitprec); }
899
900
/* assume M_star t_REAL
901
* FIXME: what does this do ? To be rewritten */
902
static GEN
903
compute_M0(GEN M_star,long N)
904
{
905
long m1,m2,n1,n2,n3,lr,lr1,lr2,i,j,l,vx,vy,vz,vM;
906
GEN pol,p1,p2,p3,p4,p5,p6,p7,p8,p9,u,v,w,r,r1,r2,M0,M0_pro,S,P,M;
907
GEN f1,f2,f3,g1,g2,g3,pg1,pg2,pg3,pf1,pf2,pf3,X,Y,Z;
908
long bitprec = 24;
909
910
if (N == 2) return gmul2n(sqrr(gacosh(gmul2n(M_star,-1),0)), -1);
911
vx = fetch_var(); X = pol_x(vx);
912
vy = fetch_var(); Y = pol_x(vy);
913
vz = fetch_var(); Z = pol_x(vz);
914
vM = fetch_var(); M = pol_x(vM);
915
916
M0 = NULL; m1 = N/3;
917
for (n1=1; n1<=m1; n1++) /* 1 <= n1 <= n2 <= n3 < N */
918
{
919
m2 = (N-n1)>>1;
920
for (n2=n1; n2<=m2; n2++)
921
{
922
pari_sp av = avma; n3=N-n1-n2;
923
if (n1==n2 && n1==n3) /* n1 = n2 = n3 = m1 = N/3 */
924
{
925
p1 = divru(M_star, m1);
926
p4 = sqrtr_abs( mulrr(addsr(1,p1),subrs(p1,3)) );
927
p5 = subrs(p1,1);
928
u = gen_1;
929
v = gmul2n(addrr(p5,p4),-1);
930
w = gmul2n(subrr(p5,p4),-1);
931
M0_pro=gmul2n(mulur(m1,addrr(sqrr(logr_abs(v)),sqrr(logr_abs(w)))), -2);
932
if (DEBUGLEVEL>2)
933
err_printf("[ %ld, %ld, %ld ]: %.28Pg\n",n1,n2,n3,M0_pro);
934
if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro;
935
}
936
else if (n1==n2 || n2==n3)
937
{ /* n3 > N/3 >= n1 */
938
long k = N - 2*n2;
939
p2 = deg1pol_shallow(stoi(-n2), M_star, vx); /* M* - n2 X */
940
p3 = gmul(powuu(k,k),
941
gpowgs(gsubgs(RgX_Rg_mul(p2, M_star), k*k), n2));
942
pol = gsub(p3, RgX_mul(monomial(powuu(n2,n2), n2, vx),
943
gpowgs(p2, N-n2)));
944
r = roots(pol, DEFAULTPREC); lr = lg(r);
945
for (i=1; i<lr; i++)
946
{
947
GEN n2S;
948
S = real_i(gel(r,i));
949
if (is_complex(gel(r,i), bitprec) || signe(S) <= 0) continue;
950
951
n2S = mulur(n2,S);
952
p4 = subrr(M_star, n2S);
953
P = divrr(mulrr(n2S,p4), subrs(mulrr(M_star,p4),k*k));
954
p5 = subrr(sqrr(S), gmul2n(P,2));
955
if (gsigne(p5) < 0) continue;
956
957
p6 = sqrtr(p5);
958
v = gmul2n(subrr(S,p6),-1);
959
if (gsigne(v) <= 0) continue;
960
961
u = gmul2n(addrr(S,p6),-1);
962
w = gpow(P, sstoQ(-n2,k), 0);
963
p6 = mulur(n2, addrr(sqrr(logr_abs(u)), sqrr(logr_abs(v))));
964
M0_pro = gmul2n(addrr(p6, mulur(k, sqrr(logr_abs(w)))),-2);
965
if (DEBUGLEVEL>2)
966
err_printf("[ %ld, %ld, %ld ]: %.28Pg\n",n1,n2,n3,M0_pro);
967
if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro;
968
}
969
}
970
else
971
{
972
f1 = gsub(gadd(gmulsg(n1,X),gadd(gmulsg(n2,Y),gmulsg(n3,Z))), M);
973
f2 = gmulsg(n1,gmul(Y,Z));
974
f2 = gadd(f2,gmulsg(n2,gmul(X,Z)));
975
f2 = gadd(f2,gmulsg(n3,gmul(X,Y)));
976
f2 = gsub(f2,gmul(M,gmul(X,gmul(Y,Z))));
977
f3 = gsub(gmul(gpowgs(X,n1),gmul(gpowgs(Y,n2),gpowgs(Z,n3))), gen_1);
978
/* f1 = n1 X + n2 Y + n3 Z - M */
979
/* f2 = n1 YZ + n2 XZ + n3 XY */
980
/* f3 = X^n1 Y^n2 Z^n3 - 1*/
981
g1=resultant(f1,f2); g1=primpart(g1);
982
g2=resultant(f1,f3); g2=primpart(g2);
983
g3=resultant(g1,g2); g3=primpart(g3);
984
pf1=gsubst(f1,vM,M_star); pg1=gsubst(g1,vM,M_star);
985
pf2=gsubst(f2,vM,M_star); pg2=gsubst(g2,vM,M_star);
986
pf3=gsubst(f3,vM,M_star); pg3=gsubst(g3,vM,M_star);
987
/* g3 = Res_Y,Z(f1,f2,f3) */
988
r = roots(pg3,DEFAULTPREC); lr = lg(r);
989
for (i=1; i<lr; i++)
990
{
991
w = real_i(gel(r,i));
992
if (is_complex(gel(r,i), bitprec) || signe(w) <= 0) continue;
993
p1=gsubst(pg1,vz,w);
994
p2=gsubst(pg2,vz,w);
995
p3=gsubst(pf1,vz,w);
996
p4=gsubst(pf2,vz,w);
997
p5=gsubst(pf3,vz,w);
998
r1 = roots(p1, DEFAULTPREC); lr1 = lg(r1);
999
for (j=1; j<lr1; j++)
1000
{
1001
v = real_i(gel(r1,j));
1002
if (is_complex(gel(r1,j), bitprec) || signe(v) <= 0
1003
|| !is_zero(gsubst(p2,vy,v), bitprec)) continue;
1004
1005
p7=gsubst(p3,vy,v);
1006
p8=gsubst(p4,vy,v);
1007
p9=gsubst(p5,vy,v);
1008
r2 = roots(p7, DEFAULTPREC); lr2 = lg(r2);
1009
for (l=1; l<lr2; l++)
1010
{
1011
u = real_i(gel(r2,l));
1012
if (is_complex(gel(r2,l), bitprec) || signe(u) <= 0
1013
|| !is_zero(gsubst(p8,vx,u), bitprec)
1014
|| !is_zero(gsubst(p9,vx,u), bitprec)) continue;
1015
1016
M0_pro = mulur(n1, sqrr(logr_abs(u)));
1017
M0_pro = gadd(M0_pro, mulur(n2, sqrr(logr_abs(v))));
1018
M0_pro = gadd(M0_pro, mulur(n3, sqrr(logr_abs(w))));
1019
M0_pro = gmul2n(M0_pro,-2);
1020
if (DEBUGLEVEL>2)
1021
err_printf("[ %ld, %ld, %ld ]: %.28Pg\n",n1,n2,n3,M0_pro);
1022
if (!M0 || gcmp(M0_pro,M0) < 0) M0 = M0_pro;
1023
}
1024
}
1025
}
1026
}
1027
if (!M0) set_avma(av); else M0 = gerepilecopy(av, M0);
1028
}
1029
}
1030
for (i=1;i<=4;i++) (void)delete_var();
1031
return M0? M0: gen_0;
1032
}
1033
1034
static GEN
1035
lowerboundforregulator(GEN bnf, GEN units)
1036
{
1037
long i, N, R2, RU = lg(units)-1;
1038
GEN nf, M0, M, G, minunit;
1039
double bound;
1040
1041
if (!RU) return gen_1;
1042
nf = bnf_get_nf(bnf);
1043
N = nf_get_degree(nf);
1044
R2 = nf_get_r2(nf);
1045
1046
G = nf_get_G(nf);
1047
minunit = gnorml2(RgM_RgC_mul(G, gel(units,1))); /* T2(units[1]) */
1048
for (i=2; i<=RU; i++)
1049
{
1050
GEN t = gnorml2(RgM_RgC_mul(G, gel(units,i)));
1051
if (gcmp(t,minunit) < 0) minunit = t;
1052
}
1053
if (gexpo(minunit) > 30) return NULL;
1054
1055
bound = minimforunits(nf, itos(gceil(minunit)), bnf_get_tuN(bnf));
1056
if (bound < 0) return NULL;
1057
if (DEBUGLEVEL>1) err_printf("M* = %Ps\n", dbltor(bound));
1058
M0 = compute_M0(dbltor(bound), N);
1059
if (DEBUGLEVEL>1) err_printf("M0 = %.28Pg\n",M0);
1060
M = gmul2n(divru(gdiv(powrs(M0,RU),Hermite_bound(RU, DEFAULTPREC)),N),R2);
1061
if (cmprr(M, dbltor(0.04)) < 0) return NULL;
1062
M = sqrtr(M);
1063
if (DEBUGLEVEL>1)
1064
err_printf("(lower bound for regulator) M = %.28Pg\n",M);
1065
return M;
1066
}
1067
1068
/* upper bound for the index of bnf.fu in the full unit group */
1069
static GEN
1070
bound_unit_index(GEN bnf, GEN units)
1071
{
1072
pari_sp av = avma;
1073
GEN x = lowerboundforregulator(bnf, units);
1074
if (!x) { set_avma(av); x = regulatorbound(bnf); }
1075
return gerepileuptoint(av, ground(gdiv(bnf_get_reg(bnf), x)));
1076
}
1077
1078
/* Compute a square matrix of rank #beta attached to a family
1079
* (P_i), 1<=i<=#beta, of primes s.t. N(P_i) = 1 mod p, and
1080
* (P_i,beta[j]) = 1 for all i,j. nf = true nf */
1081
static void
1082
primecertify(GEN nf, GEN beta, ulong p, GEN bad)
1083
{
1084
long lb = lg(beta), rmax = lb - 1;
1085
GEN M, vQ, L;
1086
ulong q;
1087
forprime_t T;
1088
1089
if (p == 2)
1090
L = cgetg(1,t_VECSMALL);
1091
else
1092
L = mkvecsmall(p);
1093
(void)u_forprime_arith_init(&T, 1, ULONG_MAX, 1, p);
1094
M = cgetg(lb,t_MAT); setlg(M,1);
1095
while ((q = u_forprime_next(&T)))
1096
{
1097
GEN qq, gg, og;
1098
long lQ, i, j;
1099
ulong g, m;
1100
if (!umodiu(bad,q)) continue;
1101
1102
qq = utoipos(q);
1103
vQ = idealprimedec_limit_f(nf,qq,1);
1104
lQ = lg(vQ); if (lQ == 1) continue;
1105
1106
/* cf rootsof1_Fl */
1107
g = pgener_Fl_local(q, L);
1108
m = (q-1) / p;
1109
gg = utoipos( Fl_powu(g, m, q) ); /* order p in (Z/q)^* */
1110
og = mkmat2(mkcol(utoi(p)), mkcol(gen_1)); /* order of g */
1111
1112
if (DEBUGLEVEL>3) err_printf(" generator of (Zk/Q)^*: %lu\n", g);
1113
for (i = 1; i < lQ; i++)
1114
{
1115
GEN C = cgetg(lb, t_VECSMALL);
1116
GEN Q = gel(vQ,i); /* degree 1 */
1117
GEN modpr = zkmodprinit(nf, Q);
1118
long r;
1119
1120
for (j = 1; j < lb; j++)
1121
{
1122
GEN t = nf_to_Fp_coprime(nf, gel(beta,j), modpr);
1123
t = utoipos( Fl_powu(t[2], m, q) );
1124
C[j] = itou( Fp_log(t, gg, og, qq) ) % p;
1125
}
1126
r = lg(M);
1127
gel(M,r) = C; setlg(M, r+1);
1128
if (Flm_rank(M, p) != r) { setlg(M,r); continue; }
1129
1130
if (DEBUGLEVEL>2)
1131
{
1132
if (DEBUGLEVEL>3)
1133
{
1134
err_printf(" prime ideal Q: %Ps\n",Q);
1135
err_printf(" matrix log(b_j mod Q_i): %Ps\n", M);
1136
}
1137
err_printf(" new rank: %ld\n",r);
1138
}
1139
if (r == rmax) return;
1140
}
1141
}
1142
pari_err_BUG("primecertify");
1143
}
1144
1145
struct check_pr {
1146
long w; /* #mu(K) */
1147
GEN mu; /* generator of mu(K) */
1148
GEN fu;
1149
GEN cyc;
1150
GEN cycgen;
1151
GEN bad; /* p | bad <--> p | some element occurring in cycgen */
1152
};
1153
1154
static void
1155
check_prime(ulong p, GEN nf, struct check_pr *S)
1156
{
1157
pari_sp av = avma;
1158
long i,b, lc = lg(S->cyc), lf = lg(S->fu);
1159
GEN beta = cgetg(lf+lc, t_VEC);
1160
1161
if (DEBUGLEVEL>1) err_printf(" *** testing p = %lu\n",p);
1162
for (b=1; b<lc; b++)
1163
{
1164
if (umodiu(gel(S->cyc,b), p)) break; /* p \nmid cyc[b] */
1165
if (b==1 && DEBUGLEVEL>2) err_printf(" p divides h(K)\n");
1166
gel(beta,b) = gel(S->cycgen,b);
1167
}
1168
if (S->w % p == 0)
1169
{
1170
if (DEBUGLEVEL>2) err_printf(" p divides w(K)\n");
1171
gel(beta,b++) = S->mu;
1172
}
1173
for (i=1; i<lf; i++) gel(beta,b++) = gel(S->fu,i);
1174
setlg(beta, b); /* beta = [cycgen[i] if p|cyc[i], tu if p|w, fu] */
1175
if (DEBUGLEVEL>3) err_printf(" Beta list = %Ps\n",beta);
1176
primecertify(nf, beta, p, S->bad); set_avma(av);
1177
}
1178
1179
static void
1180
init_bad(struct check_pr *S, GEN nf, GEN gen)
1181
{
1182
long i, l = lg(gen);
1183
GEN bad = gen_1;
1184
1185
for (i=1; i < l; i++)
1186
bad = lcmii(bad, gcoeff(gel(gen,i),1,1));
1187
for (i = 1; i < l; i++)
1188
{
1189
GEN c = gel(S->cycgen,i);
1190
long j;
1191
if (typ(c) == t_MAT)
1192
{
1193
GEN g = gel(c,1);
1194
for (j = 1; j < lg(g); j++)
1195
{
1196
GEN h = idealhnf_shallow(nf, gel(g,j));
1197
bad = lcmii(bad, gcoeff(h,1,1));
1198
}
1199
}
1200
}
1201
S->bad = bad;
1202
}
1203
1204
long
1205
bnfcertify0(GEN bnf, long flag)
1206
{
1207
pari_sp av = avma;
1208
long N;
1209
GEN nf, cyc, B, U;
1210
ulong bound, p;
1211
struct check_pr S;
1212
forprime_t T;
1213
1214
bnf = checkbnf(bnf);
1215
nf = bnf_get_nf(bnf);
1216
N = nf_get_degree(nf); if (N==1) return 1;
1217
B = zimmertbound(nf_get_disc(nf), N, nf_get_r2(nf));
1218
if (is_bigint(B))
1219
pari_warn(warner,"Zimmert's bound is large (%Ps), certification will take a long time", B);
1220
if (!is_pm1(nf_get_index(nf)))
1221
{
1222
GEN D = nf_get_diff(nf), L;
1223
if (DEBUGLEVEL>1) err_printf("**** Testing Different = %Ps\n",D);
1224
L = bnfisprincipal0(bnf, D, nf_FORCE);
1225
if (DEBUGLEVEL>1) err_printf(" is %Ps\n", L);
1226
}
1227
if (DEBUGLEVEL)
1228
{
1229
err_printf("PHASE 1 [CLASS GROUP]: are all primes good ?\n");
1230
err_printf(" Testing primes <= %Ps\n", B);
1231
}
1232
bnftestprimes(bnf, B);
1233
if (flag) return 1;
1234
1235
U = bnf_build_units(bnf);
1236
cyc = bnf_get_cyc(bnf);
1237
S.w = bnf_get_tuN(bnf);
1238
S.mu = gel(U,1);
1239
S.fu = vecslice(U,2,lg(U)-1);
1240
S.cyc = cyc;
1241
S.cycgen = bnf_build_cycgen(bnf);
1242
init_bad(&S, nf, bnf_get_gen(bnf));
1243
1244
B = bound_unit_index(bnf, S.fu);
1245
if (DEBUGLEVEL)
1246
{
1247
err_printf("PHASE 2 [UNITS/RELATIONS]: are all primes good ?\n");
1248
err_printf(" Testing primes <= %Ps\n", B);
1249
}
1250
bound = itou_or_0(B);
1251
if (!bound) pari_err_OVERFLOW("bnfcertify [too many primes to check]");
1252
if (u_forprime_init(&T, 2, bound))
1253
while ( (p = u_forprime_next(&T)) ) check_prime(p, nf, &S);
1254
if (lg(cyc) > 1)
1255
{
1256
GEN f = Z_factor(cyc_get_expo(cyc)), P = gel(f,1);
1257
long i;
1258
if (DEBUGLEVEL>1) err_printf(" Primes dividing h(K)\n\n");
1259
for (i = lg(P)-1; i; i--)
1260
{
1261
p = itou(gel(P,i)); if (p <= bound) break;
1262
check_prime(p, nf, &S);
1263
}
1264
}
1265
return gc_long(av,1);
1266
}
1267
long
1268
bnfcertify(GEN bnf) { return bnfcertify0(bnf, 0); }
1269
1270
/*******************************************************************/
1271
/* */
1272
/* RAY CLASS FIELDS: CONDUCTORS AND DISCRIMINANTS */
1273
/* */
1274
/*******************************************************************/
1275
/* \chi(gen[i]) = zeta_D^chic[i])
1276
* denormalize: express chi(gen[i]) in terms of zeta_{cyc[i]} */
1277
GEN
1278
char_denormalize(GEN cyc, GEN D, GEN chic)
1279
{
1280
long i, l = lg(chic);
1281
GEN chi = cgetg(l, t_VEC);
1282
/* \chi(gen[i]) = e(chic[i] / D) = e(chi[i] / cyc[i])
1283
* hence chi[i] = chic[i]cyc[i]/ D mod cyc[i] */
1284
for (i = 1; i < l; ++i)
1285
{
1286
GEN di = gel(cyc, i), t = diviiexact(mulii(di, gel(chic,i)), D);
1287
gel(chi, i) = modii(t, di);
1288
}
1289
return chi;
1290
}
1291
static GEN
1292
bnrchar_i(GEN bnr, GEN g, GEN v)
1293
{
1294
long i, h, l = lg(g);
1295
GEN CH, D, U, U2, H, cyc, cycD, dv, dchi;
1296
checkbnr(bnr);
1297
switch(typ(g))
1298
{
1299
GEN G;
1300
case t_VEC:
1301
G = cgetg(l, t_MAT);
1302
for (i = 1; i < l; i++) gel(G,i) = isprincipalray(bnr, gel(g,i));
1303
g = G; break;
1304
case t_MAT:
1305
if (RgM_is_ZM(g)) break;
1306
default:
1307
pari_err_TYPE("bnrchar",g);
1308
}
1309
cyc = bnr_get_cyc(bnr);
1310
H = ZM_hnfall_i(shallowconcat(g,diagonal_shallow(cyc)), v? &U: NULL, 1);
1311
dv = NULL;
1312
if (v)
1313
{
1314
GEN w = Q_remove_denom(v, &dv);
1315
if (typ(v)!=t_VEC || lg(v)!=l || !RgV_is_ZV(w)) pari_err_TYPE("bnrchar",v);
1316
if (!dv) v = NULL;
1317
else
1318
{
1319
U = rowslice(U, 1, l-1);
1320
w = FpV_red(ZV_ZM_mul(w, U), dv);
1321
for (i = 1; i < l; i++)
1322
if (signe(gel(w,i))) pari_err_TYPE("bnrchar [inconsistent values]",v);
1323
v = vecslice(w,l,lg(w)-1);
1324
}
1325
}
1326
/* chi defined on subgroup H, chi(H[i]) = e(v[i] / dv)
1327
* unless v = NULL: chi|H = 1*/
1328
h = itos( ZM_det_triangular(H) ); /* #(clgp/H) = number of chars */
1329
if (h == 1) /* unique character, H = Id */
1330
{
1331
if (v)
1332
v = char_denormalize(cyc,dv,v);
1333
else
1334
v = zerovec(lg(cyc)-1); /* trivial char */
1335
return mkvec(v);
1336
}
1337
1338
/* chi defined on a subgroup of index h > 1; U H V = D diagonal,
1339
* Z^#H / (H) = Z^#H / (D) ~ \oplus (Z/diZ) */
1340
D = ZM_snfall_i(H, &U, NULL, 1);
1341
cycD = cyc_normalize(D); gel(cycD,1) = gen_1; /* cycD[i] = d1/di */
1342
dchi = gel(D,1);
1343
U2 = ZM_diag_mul(cycD, U);
1344
if (v)
1345
{
1346
GEN Ui = ZM_inv(U, NULL);
1347
GEN Z = hnf_solve(H, ZM_mul_diag(Ui, D));
1348
v = ZV_ZM_mul(ZV_ZM_mul(v, Z), U2);
1349
dchi = mulii(dchi, dv);
1350
U2 = ZM_Z_mul(U2, dv);
1351
}
1352
CH = cyc2elts(D);
1353
for (i = 1; i <= h; i++)
1354
{
1355
GEN c = zv_ZM_mul(gel(CH,i), U2);
1356
if (v) c = ZC_add(c, v);
1357
gel(CH,i) = char_denormalize(cyc, dchi, c);
1358
}
1359
return CH;
1360
}
1361
GEN
1362
bnrchar(GEN bnr, GEN g, GEN v)
1363
{
1364
pari_sp av = avma;
1365
return gerepilecopy(av, bnrchar_i(bnr,g,v));
1366
}
1367
1368
/* Let bnr1, bnr2 be such that mod(bnr2) | mod(bnr1), compute surjective map
1369
* p: Cl(bnr1) ->> Cl(bnr2).
1370
* Write (bnr gens) for the concatenation of the bnf [corrected by El] and bid
1371
* generators; and bnr.gen for the SNF generators. Then
1372
* bnr.gen = (bnf.gen*bnr.El | bid.gen) bnr.Ui
1373
* (bnf.gen*bnr.El | bid.gen) = bnr.gen * bnr.U */
1374
GEN
1375
bnrsurjection(GEN bnr1, GEN bnr2)
1376
{
1377
GEN bnf = bnr_get_bnf(bnr2), nf = bnf_get_nf(bnf);
1378
GEN M, U = bnr_get_U(bnr2), bid2 = bnr_get_bid(bnr2);
1379
GEN gen1 = bid_get_gen(bnr_get_bid(bnr1));
1380
GEN cyc2 = bnr_get_cyc(bnr2), e2 = cyc_get_expo(cyc2);
1381
long i, l = lg(bnf_get_cyc(bnf)), lb = lg(gen1);
1382
/* p(bnr1.gen) = p(bnr1 gens) * bnr1.Ui
1383
* = (bnr2 gens) * P * bnr1.Ui
1384
* = bnr2.gen * (bnr2.U * P * bnr1.Ui) */
1385
1386
/* p(bid1.gen) on bid2.gen */
1387
M = cgetg(lb, t_MAT);
1388
for (i = 1; i < lb; i++) gel(M,i) = ideallogmod(nf, gel(gen1,i), bid2, e2);
1389
/* [U[1], U[2]] * [Id, 0; N, M] = [U[1] + U[2]*N, U[2]*M] */
1390
M = ZM_mul(gel(U,2), M);
1391
if (l > 1)
1392
{ /* non trivial class group */
1393
/* p(bnf.gen * bnr1.El) in terms of bnf.gen * bnr2.El and bid2.gen */
1394
GEN El2 = bnr_get_El(bnr2), El1 = bnr_get_El(bnr1);
1395
long ngen2 = lg(bid_get_gen(bid2))-1;
1396
if (!ngen2)
1397
M = gel(U,1);
1398
else
1399
{
1400
GEN U1 = gel(U,1), U2 = gel(U,2), T = cgetg(l, t_MAT);
1401
/* T = U1 + U2 log(El2/El1) */
1402
for (i = 1; i < l; i++)
1403
{ /* bnf gen in bnr1 is bnf.gen * El1 = bnf gen in bnr 2 * El1/El2 */
1404
GEN c = gel(U1,i);
1405
if (typ(gel(El1,i)) != t_INT) /* else El1[i] = 1 => El2[i] = 1 */
1406
{
1407
GEN z = nfdiv(nf,gel(El1,i),gel(El2,i));
1408
c = ZC_add(c, ZM_ZC_mul(U2, ideallogmod(nf, z, bid2, e2)));
1409
}
1410
gel(T,i) = c;
1411
}
1412
M = shallowconcat(T, M);
1413
}
1414
}
1415
/* could reduce the matrix mod cyc2 */
1416
return mkvec3(ZM_mul(M, bnr_get_Ui(bnr1)), bnr_get_cyc(bnr1), cyc2);
1417
}
1418
1419
/* nchi a normalized character, S a surjective map ; return S(nchi)
1420
* still normalized wrt the original cyclic structure (S[2]) */
1421
static GEN
1422
ag_nchar_image(GEN S, GEN nchi)
1423
{
1424
GEN U, M = gel(S,1), Mc = diagonal_shallow(gel(S,3));
1425
long l = lg(M);
1426
1427
(void)ZM_hnfall_i(shallowconcat(M, Mc), &U, 1); /* identity */
1428
U = matslice(U,1,l-1, l,lg(U)-1);
1429
return char_simplify(gel(nchi,1), ZV_ZM_mul(gel(nchi,2), U));
1430
}
1431
static GEN
1432
ag_char_image(GEN S, GEN chi)
1433
{
1434
GEN nchi = char_normalize(chi, cyc_normalize(gel(S,2)));
1435
GEN DC = ag_nchar_image(S, nchi);
1436
return char_denormalize(gel(S,3), gel(DC,1), gel(DC,2));
1437
}
1438
1439
GEN
1440
bnrmap(GEN A, GEN B)
1441
{
1442
pari_sp av = avma;
1443
GEN KA, KB, M, c, C;
1444
if ((KA = checkbnf_i(A)))
1445
{
1446
checkbnr(A); checkbnr(B); KB = bnr_get_bnf(B);
1447
if (!gidentical(KA, KB))
1448
pari_err_TYPE("bnrmap [different fields]", mkvec2(KA,KB));
1449
return gerepilecopy(av, bnrsurjection(A,B));
1450
}
1451
if (lg(A) != 4 || typ(A) != t_VEC) pari_err_TYPE("bnrmap [not a map]", A);
1452
M = gel(A,1); c = gel(A,2); C = gel(A,3);
1453
if (typ(M) != t_MAT || !RgM_is_ZM(M) || typ(c) != t_VEC ||
1454
typ(C) != t_VEC || lg(c) != lg(M) || (lg(M) > 1 && lgcols(M) != lg(C)))
1455
pari_err_TYPE("bnrmap [not a map]", A);
1456
switch(typ(B))
1457
{
1458
case t_INT: /* subgroup */
1459
B = scalarmat_shallow(B, lg(C)-1);
1460
B = ZM_hnfmodid(B, C); break;
1461
case t_MAT: /* subgroup */
1462
if (!RgM_is_ZM(B)) pari_err_TYPE("bnrmap [not a subgroup]", B);
1463
B = ZM_hnfmodid(B, c); B = ag_subgroup_image(A, B); break;
1464
case t_VEC: /* character */
1465
if (!char_check(c, B))
1466
pari_err_TYPE("bnrmap [not a character mod mA]", B);
1467
B = ag_char_image(A, B); break;
1468
case t_COL: /* discrete log mod mA */
1469
if (lg(B) != lg(c) || !RgV_is_ZV(B))
1470
pari_err_TYPE("bnrmap [not a discrete log]", B);
1471
B = vecmodii(ZM_ZC_mul(M, B), C);
1472
return gerepileupto(av, B);
1473
}
1474
return gerepilecopy(av, B);
1475
}
1476
1477
/* Given normalized chi on bnr.clgp of conductor bnrc.mod,
1478
* compute primitive character chic on bnrc.clgp equivalent to chi,
1479
* still normalized wrt. bnr:
1480
* chic(genc[i]) = zeta_C^chic[i]), C = cyc_normalize(bnr.cyc)[1] */
1481
GEN
1482
bnrchar_primitive(GEN bnr, GEN nchi, GEN bnrc)
1483
{ return ag_nchar_image(bnrsurjection(bnr, bnrc), nchi); }
1484
1485
/* s: <gen> = Cl_f -> Cl_f2 -> 0, H subgroup of Cl_f (generators given as
1486
* HNF on [gen]). Return subgroup s(H) in Cl_f2 */
1487
static GEN
1488
imageofgroup(GEN bnr, GEN bnr2, GEN H)
1489
{
1490
if (!H) return diagonal_shallow(bnr_get_cyc(bnr2));
1491
return ag_subgroup_image(bnrsurjection(bnr, bnr2), H);
1492
}
1493
GEN
1494
bnrchar_primitive_raw(GEN bnr, GEN bnrc, GEN chi)
1495
{
1496
GEN S = bnrsurjection(bnr, bnrc);
1497
return ag_char_image(S, chi);
1498
}
1499
1500
/* convert A,B,C to [bnr, H] */
1501
GEN
1502
ABC_to_bnr(GEN A, GEN B, GEN C, GEN *H, int gen)
1503
{
1504
if (typ(A) == t_VEC)
1505
switch(lg(A))
1506
{
1507
case 7: /* bnr */
1508
*H = B; return A;
1509
case 11: /* bnf */
1510
if (!B) pari_err_TYPE("ABC_to_bnr [bnf+missing conductor]",A);
1511
*H = C; return Buchray(A,B, gen? nf_INIT | nf_GEN: nf_INIT);
1512
}
1513
pari_err_TYPE("ABC_to_bnr",A);
1514
*H = NULL; return NULL; /* LCOV_EXCL_LINE */
1515
}
1516
1517
/* OBSOLETE */
1518
GEN
1519
bnrconductor0(GEN A, GEN B, GEN C, long flag)
1520
{
1521
pari_sp av = avma;
1522
GEN H, bnr = ABC_to_bnr(A,B,C,&H, 0);
1523
return gerepilecopy(av, bnrconductor(bnr, H, flag));
1524
}
1525
1526
long
1527
bnrisconductor0(GEN A,GEN B,GEN C)
1528
{
1529
GEN H, bnr = ABC_to_bnr(A,B,C,&H, 0);
1530
return bnrisconductor(bnr, H);
1531
}
1532
1533
static GEN
1534
ideallog_to_bnr_i(GEN Ubid, GEN cyc, GEN z)
1535
{ return (lg(Ubid)==1)? zerocol(lg(cyc)-1): vecmodii(ZM_ZC_mul(Ubid,z), cyc); }
1536
/* return bnrisprincipal(bnr, (x)), assuming z = ideallog(x); allow a
1537
* t_MAT for z, understood as a collection of ideallog(x_i) */
1538
static GEN
1539
ideallog_to_bnr(GEN bnr, GEN z)
1540
{
1541
GEN U = gel(bnr_get_U(bnr), 2); /* bid part */
1542
GEN y, cyc = bnr_get_cyc(bnr);
1543
long i, l;
1544
if (typ(z) == t_COL) return ideallog_to_bnr_i(U, cyc, z);
1545
y = cgetg_copy(z, &l);
1546
for (i = 1; i < l; i++) gel(y,i) = ideallog_to_bnr_i(U, cyc, gel(z,i));
1547
return y;
1548
}
1549
static GEN
1550
bnr_log_gen_pr(GEN bnr, zlog_S *S, long e, long index)
1551
{ return ideallog_to_bnr(bnr, log_gen_pr(S, index, bnr_get_nf(bnr), e)); }
1552
static GEN
1553
bnr_log_gen_arch(GEN bnr, zlog_S *S, long index)
1554
{ return ideallog_to_bnr(bnr, log_gen_arch(S, index)); }
1555
1556
/* A \subset H ? Allow H = NULL = trivial subgroup */
1557
static int
1558
contains(GEN H, GEN A)
1559
{ return H? (hnf_solve(H, A) != NULL): gequal0(A); }
1560
1561
/* finite part of the conductor of H is S.P^e2*/
1562
static GEN
1563
cond0_e(GEN bnr, GEN H, zlog_S *S)
1564
{
1565
long j, k, l = lg(S->k), iscond0 = S->no2;
1566
GEN e = S->k, e2 = cgetg(l, t_COL);
1567
for (k = 1; k < l; k++)
1568
{
1569
for (j = itos(gel(e,k)); j > 0; j--)
1570
{
1571
if (!contains(H, bnr_log_gen_pr(bnr, S, j, k))) break;
1572
iscond0 = 0;
1573
}
1574
gel(e2,k) = utoi(j);
1575
}
1576
return iscond0? NULL: e2;
1577
}
1578
/* infinite part of the conductor of H in archp form */
1579
static GEN
1580
condoo_archp(GEN bnr, GEN H, zlog_S *S)
1581
{
1582
GEN archp = S->archp, archp2 = leafcopy(archp);
1583
long j, k, l = lg(archp);
1584
for (k = j = 1; k < l; k++)
1585
{
1586
if (!contains(H, bnr_log_gen_arch(bnr, S, k)))
1587
{
1588
archp2[j++] = archp[k];
1589
continue;
1590
}
1591
}
1592
if (j == l) return S->archp;
1593
setlg(archp2, j); return archp2;
1594
}
1595
/* MOD useless in this function */
1596
static GEN
1597
bnrconductor_factored_i(GEN bnr, GEN H, long raw)
1598
{
1599
GEN nf, bid, ideal, arch, archp, e, fa, cond = NULL;
1600
zlog_S S;
1601
1602
checkbnr(bnr);
1603
bid = bnr_get_bid(bnr); init_zlog(&S, bid);
1604
nf = bnr_get_nf(bnr);
1605
H = bnr_subgroup_check(bnr, H, NULL);
1606
e = cond0_e(bnr, H, &S); /* in terms of S.P */
1607
archp = condoo_archp(bnr, H, &S);
1608
ideal = e? factorbackprime(nf, S.P, e): bid_get_ideal(bid);
1609
if (archp == S.archp)
1610
{
1611
if (!e) cond = bnr_get_mod(bnr);
1612
arch = bid_get_arch(bid);
1613
}
1614
else
1615
arch = indices_to_vec01(archp, nf_get_r1(nf));
1616
if (!cond) cond = mkvec2(ideal, arch);
1617
if (raw) return cond;
1618
fa = e? famat_remove_trivial(mkmat2(S.P, e)): bid_get_fact(bid);
1619
return mkvec2(cond, fa);
1620
}
1621
GEN
1622
bnrconductor_factored(GEN bnr, GEN H)
1623
{ return bnrconductor_factored_i(bnr, H, 0); }
1624
GEN
1625
bnrconductor_raw(GEN bnr, GEN H)
1626
{ return bnrconductor_factored_i(bnr, H, 1); }
1627
1628
/* (see bnrdisc_i). Given a bnr, and a subgroup
1629
* H0 (possibly given as a character chi, in which case H0 = ker chi) of the
1630
* ray class group, compute the conductor of H if flag=0. If flag > 0, compute
1631
* also the corresponding H' and output
1632
* if flag = 1: [[ideal,arch],[hm,cyc,gen],H']
1633
* if flag = 2: [[ideal,arch],newbnr,H'] */
1634
GEN
1635
bnrconductormod(GEN bnr, GEN H0, GEN MOD)
1636
{
1637
GEN nf, bid, arch, archp, bnrc, e, H, cond = NULL;
1638
int ischi;
1639
zlog_S S;
1640
1641
checkbnr(bnr);
1642
bid = bnr_get_bid(bnr); init_zlog(&S, bid);
1643
nf = bnr_get_nf(bnr);
1644
H = bnr_subgroup_check(bnr, H0, NULL);
1645
e = cond0_e(bnr, H, &S);
1646
archp = condoo_archp(bnr, H, &S);
1647
if (archp == S.archp)
1648
{
1649
if (!e) cond = bnr_get_mod(bnr);
1650
arch = gel(bnr_get_mod(bnr), 2);
1651
}
1652
else
1653
arch = indices_to_vec01(archp, nf_get_r1(nf));
1654
1655
/* character or subgroup ? */
1656
ischi = H0 && typ(H0) == t_VEC;
1657
if (cond)
1658
{ /* same conductor */
1659
bnrc = bnr;
1660
if (ischi)
1661
H = H0;
1662
else if (!H)
1663
H = diagonal_shallow(bnr_get_cyc(bnr));
1664
}
1665
else
1666
{
1667
long fl = lg(bnr_get_clgp(bnr)) == 4? nf_INIT | nf_GEN: nf_INIT;
1668
GEN fa = famat_remove_trivial(mkmat2(S.P, e? e: S.k)), bid;
1669
bid = Idealstarmod(nf, mkvec2(fa, arch), nf_INIT | nf_GEN, MOD);
1670
bnrc = Buchraymod_i(bnr, bid, fl, MOD);
1671
cond = bnr_get_mod(bnrc);
1672
if (ischi)
1673
H = bnrchar_primitive_raw(bnr, bnrc, H0);
1674
else
1675
H = imageofgroup(bnr, bnrc, H);
1676
}
1677
return mkvec3(cond, bnrc, H);
1678
}
1679
/* OBSOLETE */
1680
GEN
1681
bnrconductor_i(GEN bnr, GEN H, long flag)
1682
{
1683
GEN v;
1684
if (flag == 0) return bnrconductor_raw(bnr, H);
1685
v = bnrconductormod(bnr, H, NULL);
1686
if (flag == 1) gel(v,2) = bnr_get_clgp(gel(v,2));
1687
return v;
1688
}
1689
/* OBSOLETE */
1690
GEN
1691
bnrconductor(GEN bnr, GEN H, long flag)
1692
{
1693
pari_sp av = avma;
1694
if (flag > 2 || flag < 0) pari_err_FLAG("bnrconductor");
1695
return gerepilecopy(av, bnrconductor_i(bnr, H, flag));
1696
}
1697
1698
long
1699
bnrisconductor(GEN bnr, GEN H0)
1700
{
1701
pari_sp av = avma;
1702
long j, k, l;
1703
GEN archp, e, H;
1704
zlog_S S;
1705
1706
checkbnr(bnr);
1707
init_zlog(&S, bnr_get_bid(bnr));
1708
if (!S.no2) return 0;
1709
H = bnr_subgroup_check(bnr, H0, NULL);
1710
1711
archp = S.archp;
1712
e = S.k; l = lg(e);
1713
for (k = 1; k < l; k++)
1714
{
1715
j = itos(gel(e,k));
1716
if (contains(H, bnr_log_gen_pr(bnr, &S, j, k))) return gc_long(av,0);
1717
}
1718
l = lg(archp);
1719
for (k = 1; k < l; k++)
1720
if (contains(H, bnr_log_gen_arch(bnr, &S, k))) return gc_long(av,0);
1721
return gc_long(av,1);
1722
}
1723
1724
/* return the norm group corresponding to the relative extension given by
1725
* polrel over bnr.bnf, assuming it is abelian and the modulus of bnr is a
1726
* multiple of the conductor */
1727
static GEN
1728
rnfnormgroup_i(GEN bnr, GEN polrel)
1729
{
1730
long i, j, degrel, degnf, k;
1731
GEN bnf, index, discnf, nf, G, detG, fa, gdegrel;
1732
GEN fac, col, cnd;
1733
forprime_t S;
1734
ulong p;
1735
1736
checkbnr(bnr); bnf = bnr_get_bnf(bnr);
1737
nf = bnf_get_nf(bnf);
1738
cnd = gel(bnr_get_mod(bnr), 1);
1739
polrel = RgX_nffix("rnfnormgroup", nf_get_pol(nf),polrel,1);
1740
if (!gequal1(leading_coeff(polrel)))
1741
pari_err_IMPL("rnfnormgroup for nonmonic polynomials");
1742
1743
degrel = degpol(polrel);
1744
if (umodiu(bnr_get_no(bnr), degrel)) return NULL;
1745
/* degrel-th powers are in norm group */
1746
gdegrel = utoipos(degrel);
1747
G = ZV_snf_gcd(bnr_get_cyc(bnr), gdegrel);
1748
detG = ZV_prod(G);
1749
k = abscmpiu(detG,degrel);
1750
if (k < 0) return NULL;
1751
if (!k) return diagonal(G);
1752
1753
G = diagonal_shallow(G);
1754
discnf = nf_get_disc(nf);
1755
index = nf_get_index(nf);
1756
degnf = nf_get_degree(nf);
1757
u_forprime_init(&S, 2, ULONG_MAX);
1758
while ( (p = u_forprime_next(&S)) )
1759
{
1760
long oldf, nfa;
1761
/* If all pr are unramified and have the same residue degree, p =prod pr
1762
* and including last pr^f or p^f is the same, but the last isprincipal
1763
* is much easier! oldf is used to track this */
1764
1765
if (!umodiu(index, p)) continue; /* can't be treated efficiently */
1766
1767
/* primes of degree 1 are enough, and simpler */
1768
fa = idealprimedec_limit_f(nf, utoipos(p), 1);
1769
nfa = lg(fa)-1;
1770
if (!nfa) continue;
1771
/* all primes above p included ? */
1772
oldf = (nfa == degnf)? -1: 0;
1773
for (i=1; i<=nfa; i++)
1774
{
1775
GEN pr = gel(fa,i), pp, T, polr, modpr;
1776
long f, nfac;
1777
/* if pr (probably) ramified, we have to use all (unramified) P | pr */
1778
if (idealval(nf,cnd,pr)) { oldf = 0; continue; }
1779
modpr = zk_to_Fq_init(nf, &pr, &T, &pp); /* T = NULL, pp ignored */
1780
polr = nfX_to_FqX(polrel, nf, modpr); /* in Fp[X] */
1781
polr = ZX_to_Flx(polr, p);
1782
if (!Flx_is_squarefree(polr, p)) { oldf = 0; continue; }
1783
1784
fac = gel(Flx_factor(polr, p), 1);
1785
f = degpol(gel(fac,1));
1786
if (f == degrel) continue; /* degrel-th powers already included */
1787
nfac = lg(fac)-1;
1788
/* check decomposition of pr has Galois type */
1789
for (j=2; j<=nfac; j++)
1790
if (degpol(gel(fac,j)) != f) return NULL;
1791
if (oldf < 0) oldf = f; else if (oldf != f) oldf = 0;
1792
1793
/* last prime & all pr^f, pr | p, included. Include p^f instead */
1794
if (oldf && i == nfa && degrel == nfa*f && !umodiu(discnf, p))
1795
pr = utoipos(p);
1796
1797
/* pr^f = N P, P | pr, hence is in norm group */
1798
col = bnrisprincipalmod(bnr,pr,gdegrel,0);
1799
if (f > 1) col = ZC_z_mul(col, f);
1800
G = ZM_hnf(shallowconcat(G, col));
1801
detG = ZM_det_triangular(G);
1802
k = abscmpiu(detG,degrel);
1803
if (k < 0) return NULL;
1804
if (!k) { cgiv(detG); return G; }
1805
}
1806
}
1807
return NULL;
1808
}
1809
GEN
1810
rnfnormgroup(GEN bnr, GEN polrel)
1811
{
1812
pari_sp av = avma;
1813
GEN G = rnfnormgroup_i(bnr, polrel);
1814
if (!G) { set_avma(av); return cgetg(1,t_MAT); }
1815
return gerepileupto(av, G);
1816
}
1817
1818
GEN
1819
nf_deg1_prime(GEN nf)
1820
{
1821
GEN z, T = nf_get_pol(nf), D = nf_get_disc(nf), f = nf_get_index(nf);
1822
long degnf = degpol(T);
1823
forprime_t S;
1824
pari_sp av;
1825
ulong p;
1826
u_forprime_init(&S, degnf, ULONG_MAX);
1827
av = avma;
1828
while ( (p = u_forprime_next(&S)) )
1829
{
1830
ulong r;
1831
if (!umodiu(D, p) || !umodiu(f, p)) continue;
1832
r = Flx_oneroot(ZX_to_Flx(T,p), p);
1833
if (r != p)
1834
{
1835
z = utoi(Fl_neg(r, p));
1836
z = deg1pol_shallow(gen_1, z, varn(T));
1837
return idealprimedec_kummer(nf, z, 1, utoipos(p));
1838
}
1839
set_avma(av);
1840
}
1841
return NULL;
1842
}
1843
1844
static long
1845
rnfisabelian_i(GEN nf, GEN pol)
1846
{
1847
GEN modpr, pr, T, Tnf, pp, ro, nfL, C, a, sig, eq;
1848
long i, j, l, v;
1849
ulong p, k, ka;
1850
1851
if (typ(nf) == t_POL)
1852
Tnf = nf;
1853
else {
1854
nf = checknf(nf);
1855
Tnf = nf_get_pol(nf);
1856
}
1857
v = varn(Tnf);
1858
if (degpol(Tnf) != 1 && typ(pol) == t_POL && RgX_is_QX(pol)
1859
&& rnfisabelian_i(pol_x(v), pol)) return 1;
1860
pol = RgX_nffix("rnfisabelian",Tnf,pol,1);
1861
eq = nf_rnfeq(nf,pol); /* init L := K[x]/(pol), nf attached to K */
1862
C = gel(eq,1); setvarn(C, v); /* L = Q[t]/(C) */
1863
a = gel(eq,2); setvarn(a, v); /* root of K.pol in L */
1864
nfL = C;
1865
ro = nfroots_if_split(&nfL, QXY_QXQ_evalx(pol, a, C));
1866
if (!ro) return 0;
1867
l = lg(ro)-1;
1868
/* small groups are abelian, as are groups of prime order */
1869
if (l < 6 || uisprime(l)) return 1;
1870
1871
pr = nf_deg1_prime(nfL);
1872
modpr = nf_to_Fq_init(nfL, &pr, &T, &pp);
1873
p = itou(pp);
1874
k = umodiu(gel(eq,3), p);
1875
ka = (k * itou(nf_to_Fq(nfL, a, modpr))) % p;
1876
sig= cgetg(l+1, t_VECSMALL);
1877
/* image of c = ro[1] + k a [distinguished root of C] by the l automorphisms
1878
* sig[i]: ro[1] -> ro[i] */
1879
for (i = 1; i <= l; i++)
1880
sig[i] = Fl_add(ka, itou(nf_to_Fq(nfL, gel(ro,i), modpr)), p);
1881
ro = Q_primpart(ro);
1882
for (i=2; i<=l; i++) { /* start at 2, since sig[1] = identity */
1883
gel(ro,i) = ZX_to_Flx(gel(ro,i), p);
1884
for (j=2; j<i; j++)
1885
if (Flx_eval(gel(ro,j), sig[i], p)
1886
!= Flx_eval(gel(ro,i), sig[j], p)) return 0;
1887
}
1888
return 1;
1889
}
1890
long
1891
rnfisabelian(GEN nf, GEN pol)
1892
{ pari_sp av = avma; return gc_long(av, rnfisabelian_i(nf, pol)); }
1893
1894
/* Given bnf and T defining an abelian relative extension, compute the
1895
* corresponding conductor and congruence subgroup. Return
1896
* [cond,bnr(cond),H] where cond=[ideal,arch] is the conductor. */
1897
GEN
1898
rnfconductor0(GEN bnf, GEN T, long flag)
1899
{
1900
pari_sp av = avma;
1901
GEN D, nf, module, bnr, H, lim, Tr, MOD;
1902
1903
if (flag < 0 || flag > 2) pari_err_FLAG("rnfconductor");
1904
bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);
1905
Tr = rnfdisc_get_T(nf, T, &lim);
1906
T = nfX_to_monic(nf, Tr, NULL);
1907
if (!lim)
1908
D = rnfdisc_factored(nf, T, NULL);
1909
else
1910
{
1911
GEN P, E, Ez;
1912
long i, l, degT = degpol(T);
1913
D = idealfactor_partial(nf, nfX_disc(nf, Q_primpart(Tr)), lim);
1914
P = gel(D,1); l = lg(P);
1915
E = gel(D,2); Ez = ZV_to_zv(E);
1916
if (l > 1 && vecsmall_max(Ez) > 1)
1917
{ /* cheaply update tame primes */
1918
for (i = 1; i < l; i++)
1919
{ /* v_pr(f) = 1 + \sum_{0 < i < l} g_i/g_0
1920
<= 1 + max_{i>0} g_i/(g_i-1) \sum_{0 < i < l} g_i -1
1921
<= 1 + (p/(p-1)) * v_P(e(L/K, pr)), P | pr | p */
1922
GEN pr = gel(P,i), p = pr_get_p(pr), e = gen_1;
1923
long q, v = z_pvalrem(degT, p, &q);
1924
if (v)
1925
{ /* e = e_tame * e_wild, e_wild | p^v */
1926
long ee, pp = itou(p);
1927
long t = ugcd(umodiu(subiu(pr_norm(pr),1), q), q); /* e_tame | t */
1928
/* upper bound for 1 + p/(p-1) * v * e(L/Q,p) */
1929
ee = 1 + (pp * v * pr_get_e(pr) * upowuu(pp,v) * t) / (pp-1);
1930
e = utoi(minss(ee, Ez[i]));
1931
}
1932
gel(E,i) = e;
1933
}
1934
}
1935
}
1936
module = mkvec2(D, identity_perm(nf_get_r1(nf)));
1937
MOD = flag? utoipos(degpol(T)): NULL;
1938
bnr = Buchraymod_i(bnf, module, nf_INIT|nf_GEN, MOD);
1939
H = rnfnormgroup_i(bnr,T); if (!H) return gc_const(av,gen_0);
1940
return gerepilecopy(av, flag == 2? bnrconductor_factored(bnr, H)
1941
: bnrconductormod(bnr, H, MOD));
1942
}
1943
GEN
1944
rnfconductor(GEN bnf, GEN T) { return rnfconductor0(bnf, T, 0); }
1945
1946
static GEN
1947
prV_norms(GEN v)
1948
{
1949
long i, l;
1950
GEN w = cgetg_copy(v, &l);
1951
for (i = 1; i < l; i++) gel(w,i) = pr_norm(gel(v,i));
1952
return w;
1953
}
1954
1955
/* Given a number field bnf=bnr[1], a ray class group structure bnr, and a
1956
* subgroup H (HNF form) of the ray class group, compute [n, r1, dk]
1957
* attached to H. If flag & rnf_COND, abort (return NULL) if module is not the
1958
* conductor. If flag & rnf_REL, return relative data, else absolute */
1959
static GEN
1960
bnrdisc_i(GEN bnr, GEN H, long flag)
1961
{
1962
const long flcond = flag & rnf_COND;
1963
GEN nf, clhray, E, ED, dk;
1964
long k, d, l, n, r1;
1965
zlog_S S;
1966
1967
checkbnr(bnr);
1968
init_zlog(&S, bnr_get_bid(bnr));
1969
nf = bnr_get_nf(bnr);
1970
H = bnr_subgroup_check(bnr, H, &clhray);
1971
d = itos(clhray);
1972
if (!H) H = diagonal_shallow(bnr_get_cyc(bnr));
1973
E = S.k; ED = cgetg_copy(E, &l);
1974
for (k = 1; k < l; k++)
1975
{
1976
long j, e = itos(gel(E,k)), eD = e*d;
1977
GEN H2 = H;
1978
for (j = e; j > 0; j--)
1979
{
1980
GEN z = bnr_log_gen_pr(bnr, &S, j, k);
1981
long d2;
1982
H2 = ZM_hnf(shallowconcat(H2, z));
1983
d2 = itos( ZM_det_triangular(H2) );
1984
if (flcond && j==e && d2 == d) return NULL;
1985
if (d2 == 1) { eD -= j; break; }
1986
eD -= d2;
1987
}
1988
gel(ED,k) = utoi(eD); /* v_{P[k]}(relative discriminant) */
1989
}
1990
l = lg(S.archp); r1 = nf_get_r1(nf);
1991
for (k = 1; k < l; k++)
1992
{
1993
if (!contains(H, bnr_log_gen_arch(bnr, &S, k))) { r1--; continue; }
1994
if (flcond) return NULL;
1995
}
1996
/* d = relative degree
1997
* r1 = number of unramified real places;
1998
* [P,ED] = factorization of relative discriminant */
1999
if (flag & rnf_REL)
2000
{
2001
n = d;
2002
dk = factorbackprime(nf, S.P, ED);
2003
}
2004
else
2005
{
2006
n = d * nf_get_degree(nf);
2007
r1= d * r1;
2008
dk = factorback2(prV_norms(S.P), ED);
2009
if (((n-r1)&3) == 2) dk = negi(dk); /* (2r2) mod 4 = 2: r2(relext) is odd */
2010
dk = mulii(dk, powiu(absi_shallow(nf_get_disc(nf)), d));
2011
}
2012
return mkvec3(utoipos(n), utoi(r1), dk);
2013
}
2014
GEN
2015
bnrdisc(GEN bnr, GEN H, long flag)
2016
{
2017
pari_sp av = avma;
2018
GEN D = bnrdisc_i(bnr, H, flag);
2019
return D? gerepilecopy(av, D): gc_const(av, gen_0);
2020
}
2021
GEN
2022
bnrdisc0(GEN A, GEN B, GEN C, long flag)
2023
{
2024
GEN H, bnr = ABC_to_bnr(A,B,C,&H, 0);
2025
return bnrdisc(bnr,H,flag);
2026
}
2027
2028
/* Given a number field bnf=bnr[1], a ray class group structure bnr and a
2029
* vector chi representing a character on the generators bnr[2][3], compute
2030
* the conductor of chi. */
2031
GEN
2032
bnrconductorofchar(GEN bnr, GEN chi)
2033
{
2034
pari_sp av = avma;
2035
return gerepilecopy(av, bnrconductor_raw(bnr, chi));
2036
}
2037
2038
/* \sum U[i]*y[i], U[i],y[i] ZM, we allow lg(y) > lg(U). */
2039
static GEN
2040
ZMV_mul(GEN U, GEN y)
2041
{
2042
long i, l = lg(U);
2043
GEN z = NULL;
2044
if (l == 1) return cgetg(1,t_MAT);
2045
for (i = 1; i < l; i++)
2046
{
2047
GEN u = ZM_mul(gel(U,i), gel(y,i));
2048
z = z? ZM_add(z, u): u;
2049
}
2050
return z;
2051
}
2052
2053
/* t = [bid,U], h = #Cl(K) */
2054
static GEN
2055
get_classno(GEN t, GEN h)
2056
{
2057
GEN bid = gel(t,1), m = gel(t,2), cyc = bid_get_cyc(bid), U = bid_get_U(bid);
2058
return mulii(h, ZM_det_triangular(ZM_hnfmodid(ZMV_mul(U,m), cyc)));
2059
}
2060
2061
static void
2062
chk_listBU(GEN L, const char *s) {
2063
if (typ(L) != t_VEC) pari_err_TYPE(s,L);
2064
if (lg(L) > 1) {
2065
GEN z = gel(L,1);
2066
if (typ(z) != t_VEC) pari_err_TYPE(s,z);
2067
if (lg(z) == 1) return;
2068
z = gel(z,1); /* [bid,U] */
2069
if (typ(z) != t_VEC || lg(z) != 3) pari_err_TYPE(s,z);
2070
checkbid(gel(z,1));
2071
}
2072
}
2073
2074
/* Given lists of [bid, unit ideallogs], return lists of ray class numbers */
2075
GEN
2076
bnrclassnolist(GEN bnf,GEN L)
2077
{
2078
pari_sp av = avma;
2079
long i, l = lg(L);
2080
GEN V, h;
2081
2082
chk_listBU(L, "bnrclassnolist");
2083
if (l == 1) return cgetg(1, t_VEC);
2084
bnf = checkbnf(bnf);
2085
h = bnf_get_no(bnf);
2086
V = cgetg(l,t_VEC);
2087
for (i = 1; i < l; i++)
2088
{
2089
GEN v, z = gel(L,i);
2090
long j, lz = lg(z);
2091
gel(V,i) = v = cgetg(lz,t_VEC);
2092
for (j=1; j<lz; j++) gel(v,j) = get_classno(gel(z,j), h);
2093
}
2094
return gerepilecopy(av, V);
2095
}
2096
2097
static GEN
2098
Lbnrclassno(GEN L, GEN fac)
2099
{
2100
long i, l = lg(L);
2101
for (i=1; i<l; i++)
2102
if (gequal(gmael(L,i,1),fac)) return gmael(L,i,2);
2103
pari_err_BUG("Lbnrclassno");
2104
return NULL; /* LCOV_EXCL_LINE */
2105
}
2106
2107
static GEN
2108
factordivexact(GEN fa1,GEN fa2)
2109
{
2110
long i, j, k, c, l;
2111
GEN P, E, P1, E1, P2, E2, p1;
2112
2113
P1 = gel(fa1,1); E1 = gel(fa1,2); l = lg(P1);
2114
P2 = gel(fa2,1); E2 = gel(fa2,2);
2115
P = cgetg(l,t_COL);
2116
E = cgetg(l,t_COL);
2117
for (c = i = 1; i < l; i++)
2118
{
2119
j = RgV_isin(P2,gel(P1,i));
2120
if (!j) { gel(P,c) = gel(P1,i); gel(E,c) = gel(E1,i); c++; }
2121
else
2122
{
2123
p1 = subii(gel(E1,i), gel(E2,j)); k = signe(p1);
2124
if (k < 0) pari_err_BUG("factordivexact [not exact]");
2125
if (k > 0) { gel(P,c) = gel(P1,i); gel(E,c) = p1; c++; }
2126
}
2127
}
2128
setlg(P, c);
2129
setlg(E, c); return mkmat2(P, E);
2130
}
2131
/* remove index k */
2132
static GEN
2133
factorsplice(GEN fa, long k)
2134
{
2135
GEN p = gel(fa,1), e = gel(fa,2), P, E;
2136
long i, l = lg(p) - 1;
2137
P = cgetg(l, typ(p));
2138
E = cgetg(l, typ(e));
2139
for (i=1; i<k; i++) { P[i] = p[i]; E[i] = e[i]; }
2140
p++; e++;
2141
for ( ; i<l; i++) { P[i] = p[i]; E[i] = e[i]; }
2142
return mkvec2(P,E);
2143
}
2144
static GEN
2145
factorpow(GEN fa, long n)
2146
{
2147
if (!n) return trivial_fact();
2148
return mkmat2(gel(fa,1), gmulsg(n, gel(fa,2)));
2149
}
2150
static GEN
2151
factormul(GEN fa1,GEN fa2)
2152
{
2153
GEN p, pnew, e, enew, v, P, y = famat_mul_shallow(fa1,fa2);
2154
long i, c, lx;
2155
2156
p = gel(y,1); v = indexsort(p); lx = lg(p);
2157
e = gel(y,2);
2158
pnew = vecpermute(p, v);
2159
enew = vecpermute(e, v);
2160
P = gen_0; c = 0;
2161
for (i=1; i<lx; i++)
2162
{
2163
if (gequal(gel(pnew,i),P))
2164
gel(e,c) = addii(gel(e,c),gel(enew,i));
2165
else
2166
{
2167
c++; P = gel(pnew,i);
2168
gel(p,c) = P;
2169
gel(e,c) = gel(enew,i);
2170
}
2171
}
2172
setlg(p, c+1);
2173
setlg(e, c+1); return y;
2174
}
2175
2176
static long
2177
get_nz(GEN bnf, GEN ideal, GEN arch, long clhray)
2178
{
2179
GEN arch2, mod;
2180
long nz = 0, l = lg(arch), k, clhss;
2181
if (typ(arch) == t_VECSMALL)
2182
arch2 = indices_to_vec01(arch,nf_get_r1(bnf_get_nf(bnf)));
2183
else
2184
arch2 = leafcopy(arch);
2185
mod = mkvec2(ideal, arch2);
2186
for (k = 1; k < l; k++)
2187
{ /* FIXME: this is wasteful. Use the same algorithm as bnrconductor */
2188
if (signe(gel(arch2,k)))
2189
{
2190
gel(arch2,k) = gen_0; clhss = itos(bnrclassno(bnf,mod));
2191
gel(arch2,k) = gen_1;
2192
if (clhss == clhray) return -1;
2193
}
2194
else nz++;
2195
}
2196
return nz;
2197
}
2198
2199
static GEN
2200
get_NR1D(long Nf, long clhray, long degk, long nz, GEN fadkabs, GEN idealrel)
2201
{
2202
long n, R1;
2203
GEN dlk;
2204
if (nz < 0) return mkvec3(gen_0,gen_0,gen_0); /*EMPTY*/
2205
n = clhray * degk;
2206
R1 = clhray * nz;
2207
dlk = factordivexact(factorpow(Z_factor(utoipos(Nf)),clhray), idealrel);
2208
/* r2 odd, set dlk = -dlk */
2209
if (((n-R1)&3)==2) dlk = factormul(to_famat_shallow(gen_m1,gen_1), dlk);
2210
return mkvec3(utoipos(n),
2211
stoi(R1),
2212
factormul(dlk,factorpow(fadkabs,clhray)));
2213
}
2214
2215
/* t = [bid,U], h = #Cl(K) */
2216
static GEN
2217
get_discdata(GEN t, GEN h)
2218
{
2219
GEN bid = gel(t,1), fa = bid_get_fact(bid);
2220
GEN P = gel(fa,1), E = vec_to_vecsmall(gel(fa,2));
2221
return mkvec3(mkvec2(P, E), (GEN)itou(get_classno(t, h)), bid_get_mod(bid));
2222
}
2223
typedef struct _disc_data {
2224
long degk;
2225
GEN bnf, fadk, idealrelinit, V;
2226
} disc_data;
2227
2228
static GEN
2229
get_discray(disc_data *D, GEN V, GEN z, long N)
2230
{
2231
GEN idealrel = D->idealrelinit;
2232
GEN mod = gel(z,3), Fa = gel(z,1);
2233
GEN P = gel(Fa,1), E = gel(Fa,2);
2234
long k, nz, clhray = z[2], lP = lg(P);
2235
for (k=1; k<lP; k++)
2236
{
2237
GEN pr = gel(P,k), p = pr_get_p(pr);
2238
long e, ep = E[k], f = pr_get_f(pr);
2239
long S = 0, norm = N, Npr = upowuu(p[2],f), clhss;
2240
for (e=1; e<=ep; e++)
2241
{
2242
GEN fad;
2243
if (e < ep) { E[k] = ep-e; fad = Fa; }
2244
else fad = factorsplice(Fa, k);
2245
norm /= Npr;
2246
clhss = (long)Lbnrclassno(gel(V,norm), fad);
2247
if (e==1 && clhss==clhray) { E[k] = ep; return cgetg(1, t_VEC); }
2248
if (clhss == 1) { S += ep-e+1; break; }
2249
S += clhss;
2250
}
2251
E[k] = ep;
2252
idealrel = factormul(idealrel, to_famat_shallow(p, utoi(f * S)));
2253
}
2254
nz = get_nz(D->bnf, gel(mod,1), gel(mod,2), clhray);
2255
return get_NR1D(N, clhray, D->degk, nz, D->fadk, idealrel);
2256
}
2257
2258
/* Given a list of bids and attached unit log matrices, return the
2259
* list of discrayabs. Only keep moduli which are conductors. */
2260
GEN
2261
discrayabslist(GEN bnf, GEN L)
2262
{
2263
pari_sp av = avma;
2264
long i, l = lg(L);
2265
GEN nf, V, D, h;
2266
disc_data ID;
2267
2268
chk_listBU(L, "discrayabslist");
2269
if (l == 1) return cgetg(1, t_VEC);
2270
ID.bnf = bnf = checkbnf(bnf);
2271
nf = bnf_get_nf(bnf);
2272
h = bnf_get_no(bnf);
2273
ID.degk = nf_get_degree(nf);
2274
ID.fadk = absZ_factor(nf_get_disc(nf));
2275
ID.idealrelinit = trivial_fact();
2276
V = cgetg(l, t_VEC);
2277
D = cgetg(l, t_VEC);
2278
for (i = 1; i < l; i++)
2279
{
2280
GEN z = gel(L,i), v, d;
2281
long j, lz = lg(z);
2282
gel(V,i) = v = cgetg(lz,t_VEC);
2283
gel(D,i) = d = cgetg(lz,t_VEC);
2284
for (j=1; j<lz; j++) {
2285
gel(d,j) = get_discdata(gel(z,j), h);
2286
gel(v,j) = get_discray(&ID, D, gel(d,j), i);
2287
}
2288
}
2289
return gerepilecopy(av, V);
2290
}
2291
2292
/* a zsimp is [fa, cyc, v]
2293
* fa: vecsmall factorisation,
2294
* cyc: ZV (concatenation of (Z_K/pr^k)^* SNFs), the generators
2295
* are positive at all real places [defined implicitly by weak approximation]
2296
* v: ZC (log of units on (Z_K/pr^k)^* components) */
2297
static GEN
2298
zsimp(void)
2299
{
2300
GEN empty = cgetg(1, t_VECSMALL);
2301
return mkvec3(mkvec2(empty,empty), cgetg(1,t_VEC), cgetg(1,t_MAT));
2302
}
2303
2304
/* fa a vecsmall factorization, append p^e */
2305
static GEN
2306
fasmall_append(GEN fa, long p, long e)
2307
{
2308
GEN P = gel(fa,1), E = gel(fa,2);
2309
retmkvec2(vecsmall_append(P,p), vecsmall_append(E,e));
2310
}
2311
2312
static GEN
2313
sprk_get_cyc(GEN s) { return gel(s,1); }
2314
2315
/* sprk = sprkinit(pr,k), b zsimp with modulus coprime to pr */
2316
static GEN
2317
zsimpjoin(GEN b, GEN sprk, GEN U_pr, long prcode, long e)
2318
{
2319
GEN fa, cyc = sprk_get_cyc(sprk);
2320
if (lg(gel(b,2)) == 1) /* trivial group */
2321
fa = mkvec2(mkvecsmall(prcode),mkvecsmall(e));
2322
else
2323
{
2324
fa = fasmall_append(gel(b,1), prcode, e);
2325
cyc = shallowconcat(gel(b,2), cyc); /* no SNF ! */
2326
U_pr = vconcat(gel(b,3),U_pr);
2327
}
2328
return mkvec3(fa, cyc, U_pr);
2329
}
2330
/* B a zsimp, sgnU = [cyc[f_oo], sgn_{f_oo}(units)] */
2331
static GEN
2332
bnrclassno_1(GEN B, ulong h, GEN sgnU)
2333
{
2334
long lx = lg(B), j;
2335
GEN L = cgetg(lx,t_VEC);
2336
for (j=1; j<lx; j++)
2337
{
2338
pari_sp av = avma;
2339
GEN b = gel(B,j), cyc = gel(b,2), qm = gel(b,3);
2340
ulong z;
2341
cyc = shallowconcat(cyc, gel(sgnU,1));
2342
qm = vconcat(qm, gel(sgnU,2));
2343
z = itou( mului(h, ZM_det_triangular(ZM_hnfmodid(qm, cyc))) );
2344
set_avma(av);
2345
gel(L,j) = mkvec2(gel(b,1), mkvecsmall(z));
2346
}
2347
return L;
2348
}
2349
2350
static void
2351
vecselect_p(GEN A, GEN B, GEN p, long init, long lB)
2352
{
2353
long i; setlg(B, lB);
2354
for (i=init; i<lB; i++) B[i] = A[p[i]];
2355
}
2356
/* B := p . A = row selection according to permutation p. Treat only lower
2357
* right corner init x init */
2358
static void
2359
rowselect_p(GEN A, GEN B, GEN p, long init)
2360
{
2361
long i, lB = lg(A), lp = lg(p);
2362
for (i=1; i<init; i++) setlg(B[i],lp);
2363
for ( ; i<lB; i++) vecselect_p(gel(A,i),gel(B,i),p,init,lp);
2364
}
2365
static ulong
2366
hdet(ulong h, GEN m)
2367
{
2368
pari_sp av = avma;
2369
GEN z = mului(h, ZM_det_triangular(ZM_hnf(m)));
2370
return gc_ulong(av, itou(z));
2371
}
2372
static GEN
2373
bnrclassno_all(GEN B, ulong h, GEN sgnU)
2374
{
2375
long lx, k, kk, j, r1, jj, nba, nbarch;
2376
GEN _2, L, m, H, mm, rowsel;
2377
2378
if (typ(sgnU) == t_VEC) return bnrclassno_1(B,h,sgnU);
2379
lx = lg(B); if (lx == 1) return B;
2380
2381
r1 = nbrows(sgnU); _2 = const_vec(r1, gen_2);
2382
L = cgetg(lx,t_VEC); nbarch = 1L<<r1;
2383
for (j=1; j<lx; j++)
2384
{
2385
pari_sp av = avma;
2386
GEN b = gel(B,j), cyc = gel(b,2), qm = gel(b,3);
2387
long nc = lg(cyc)-1;
2388
/* [ qm cyc 0 ]
2389
* [ sgnU 0 2 ] */
2390
m = ZM_hnfmodid(vconcat(qm, sgnU), shallowconcat(cyc,_2));
2391
mm = RgM_shallowcopy(m);
2392
rowsel = cgetg(nc+r1+1,t_VECSMALL);
2393
H = cgetg(nbarch+1,t_VECSMALL);
2394
for (k = 0; k < nbarch; k++)
2395
{
2396
nba = nc+1;
2397
for (kk=k,jj=1; jj<=r1; jj++,kk>>=1)
2398
if (kk&1) rowsel[nba++] = nc + jj;
2399
setlg(rowsel, nba);
2400
rowselect_p(m, mm, rowsel, nc+1);
2401
H[k+1] = hdet(h, mm);
2402
}
2403
H = gerepileuptoleaf(av, H);
2404
gel(L,j) = mkvec2(gel(b,1), H);
2405
}
2406
return L;
2407
}
2408
2409
static int
2410
is_module(GEN v)
2411
{
2412
if (lg(v) != 3 || (typ(v) != t_MAT && typ(v) != t_VEC)) return 0;
2413
return typ(gel(v,1)) == t_VECSMALL && typ(gel(v,2)) == t_VECSMALL;
2414
}
2415
GEN
2416
decodemodule(GEN nf, GEN fa)
2417
{
2418
long n, nn, k;
2419
pari_sp av = avma;
2420
GEN G, E, id, pr;
2421
2422
nf = checknf(nf);
2423
if (!is_module(fa)) pari_err_TYPE("decodemodule [not a factorization]", fa);
2424
n = nf_get_degree(nf); nn = n*n; id = NULL;
2425
G = gel(fa,1);
2426
E = gel(fa,2);
2427
for (k=1; k<lg(G); k++)
2428
{
2429
long code = G[k], p = code / nn, j = (code%n)+1;
2430
GEN P = idealprimedec(nf, utoipos(p)), e = stoi(E[k]);
2431
if (lg(P) <= j) pari_err_BUG("decodemodule [incorrect hash code]");
2432
pr = gel(P,j);
2433
id = id? idealmulpowprime(nf,id, pr,e)
2434
: idealpow(nf, pr,e);
2435
}
2436
if (!id) { set_avma(av); return matid(n); }
2437
return gerepileupto(av,id);
2438
}
2439
2440
/* List of ray class fields. Do all from scratch, bound < 2^30. No subgroups.
2441
*
2442
* Output: a vector V, V[k] contains the ideals of norm k. Given such an ideal
2443
* m, the component is as follows:
2444
*
2445
* + if arch = NULL, run through all possible archimedean parts; archs are
2446
* ordered using inverse lexicographic order, [0,..,0], [1,0,..,0], [0,1,..,0],
2447
* Component is [m,V] where V is a vector with 2^r1 entries, giving for each
2448
* arch the triple [N,R1,D], with N, R1, D as in discrayabs; D is in factored
2449
* form.
2450
*
2451
* + otherwise [m,N,R1,D] */
2452
GEN
2453
discrayabslistarch(GEN bnf, GEN arch, ulong bound)
2454
{
2455
int allarch = (arch==NULL), flbou = 0;
2456
long degk, j, k, l, nba, nbarch, r1, c, sqbou;
2457
pari_sp av0 = avma, av, av1;
2458
GEN nf, p, Z, fa, Disc, U, sgnU, EMPTY, empty, archp;
2459
GEN res, Ray, discall, idealrel, idealrelinit, fadkabs, BOUND;
2460
ulong i, h;
2461
forprime_t S;
2462
2463
if (bound == 0)
2464
pari_err_DOMAIN("discrayabslistarch","bound","==",gen_0,utoi(bound));
2465
res = discall = NULL; /* -Wall */
2466
2467
bnf = checkbnf(bnf);
2468
nf = bnf_get_nf(bnf);
2469
r1 = nf_get_r1(nf);
2470
degk = nf_get_degree(nf);
2471
fadkabs = absZ_factor(nf_get_disc(nf));
2472
h = itou(bnf_get_no(bnf));
2473
2474
if (allarch)
2475
{
2476
if (r1>15) pari_err_IMPL("r1>15 in discrayabslistarch");
2477
arch = const_vec(r1, gen_1);
2478
}
2479
else if (lg(arch)-1 != r1)
2480
pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);
2481
U = log_prk_units_init(bnf);
2482
archp = vec01_to_indices(arch);
2483
nba = lg(archp)-1;
2484
sgnU = zm_to_ZM( nfsign_units(bnf, archp, 1) );
2485
if (!allarch) sgnU = mkvec2(const_vec(nba,gen_2), sgnU);
2486
2487
empty = cgetg(1,t_VEC);
2488
/* what follows was rewritten from Ideallist */
2489
BOUND = utoipos(bound);
2490
p = cgetipos(3);
2491
u_forprime_init(&S, 2, bound);
2492
av = avma;
2493
sqbou = (long)sqrt((double)bound) + 1;
2494
Z = const_vec(bound, empty);
2495
gel(Z,1) = mkvec(zsimp());
2496
if (DEBUGLEVEL>1) err_printf("Starting zidealstarunits computations\n");
2497
/* The goal is to compute Ray (lists of bnrclassno). Z contains "zsimps",
2498
* simplified bid, from which bnrclassno is easy to compute.
2499
* Once p > sqbou, delete Z[i] for i > sqbou and compute directly Ray */
2500
Ray = Z;
2501
while ((p[2] = u_forprime_next(&S)))
2502
{
2503
if (!flbou && p[2] > sqbou)
2504
{
2505
flbou = 1;
2506
if (DEBUGLEVEL>1) err_printf("\nStarting bnrclassno computations\n");
2507
Z = gerepilecopy(av,Z);
2508
Ray = cgetg(bound+1, t_VEC);
2509
for (i=1; i<=bound; i++) gel(Ray,i) = bnrclassno_all(gel(Z,i),h,sgnU);
2510
Z = vecslice(Z, 1, sqbou);
2511
}
2512
fa = idealprimedec_limit_norm(nf,p,BOUND);
2513
for (j=1; j<lg(fa); j++)
2514
{
2515
GEN pr = gel(fa,j);
2516
long prcode, f = pr_get_f(pr);
2517
ulong q, Q = upowuu(p[2], f);
2518
2519
/* p, f-1, j-1 as a single integer in "base degk" (f,j <= degk)*/
2520
prcode = (p[2]*degk + f-1)*degk + j-1;
2521
q = Q;
2522
/* FIXME: if Q = 2, should start at l = 2 */
2523
for (l = 1;; l++) /* Q <= bound */
2524
{
2525
ulong iQ;
2526
GEN sprk = log_prk_init(nf, pr, l, NULL);
2527
GEN U_pr = log_prk_units(nf, U, sprk);
2528
for (iQ = Q, i = 1; iQ <= bound; iQ += Q, i++)
2529
{
2530
GEN pz, p2, p1 = gel(Z,i);
2531
long lz = lg(p1);
2532
if (lz == 1) continue;
2533
2534
p2 = cgetg(lz,t_VEC); c = 0;
2535
for (k=1; k<lz; k++)
2536
{
2537
GEN z = gel(p1,k), v = gmael(z,1,1); /* primes in zsimp's fact. */
2538
long lv = lg(v);
2539
/* If z has a power of pr in its modulus, skip it */
2540
if (i != 1 && lv > 1 && v[lv-1] == prcode) break;
2541
gel(p2,++c) = zsimpjoin(z,sprk,U_pr,prcode,l);
2542
}
2543
setlg(p2, c+1);
2544
pz = gel(Ray,iQ);
2545
if (flbou) p2 = bnrclassno_all(p2,h,sgnU);
2546
if (lg(pz) > 1) p2 = shallowconcat(pz,p2);
2547
gel(Ray,iQ) = p2;
2548
}
2549
Q = itou_or_0( muluu(Q, q) );
2550
if (!Q || Q > bound) break;
2551
}
2552
}
2553
if (gc_needed(av,1))
2554
{
2555
if(DEBUGMEM>1) pari_warn(warnmem,"[1]: discrayabslistarch");
2556
gerepileall(av, flbou? 2: 1, &Z, &Ray);
2557
}
2558
}
2559
if (!flbou) /* occurs iff bound = 1,2,4 */
2560
{
2561
if (DEBUGLEVEL>1) err_printf("\nStarting bnrclassno computations\n");
2562
Ray = cgetg(bound+1, t_VEC);
2563
for (i=1; i<=bound; i++) gel(Ray,i) = bnrclassno_all(gel(Z,i),h,sgnU);
2564
}
2565
Ray = gerepilecopy(av, Ray);
2566
2567
if (DEBUGLEVEL>1) err_printf("Starting discrayabs computations\n");
2568
if (allarch) nbarch = 1L<<r1;
2569
else
2570
{
2571
nbarch = 1;
2572
discall = cgetg(2,t_VEC);
2573
}
2574
EMPTY = mkvec3(gen_0,gen_0,gen_0);
2575
idealrelinit = trivial_fact();
2576
av1 = avma;
2577
Disc = const_vec(bound, empty);
2578
for (i=1; i<=bound; i++)
2579
{
2580
GEN sousdisc, sous = gel(Ray,i);
2581
long ls = lg(sous);
2582
gel(Disc,i) = sousdisc = cgetg(ls,t_VEC);
2583
for (j=1; j<ls; j++)
2584
{
2585
GEN b = gel(sous,j), clhrayall = gel(b,2), Fa = gel(b,1);
2586
GEN P = gel(Fa,1), E = gel(Fa,2);
2587
long lP = lg(P), karch;
2588
2589
if (allarch) discall = cgetg(nbarch+1,t_VEC);
2590
for (karch=0; karch<nbarch; karch++)
2591
{
2592
long nz, clhray = clhrayall[karch+1];
2593
if (allarch)
2594
{
2595
long ka, k2;
2596
nba = 0;
2597
for (ka=karch,k=1; k<=r1; k++,ka>>=1)
2598
if (ka & 1) nba++;
2599
for (k2=1,k=1; k<=r1; k++,k2<<=1)
2600
if (karch&k2 && clhrayall[karch-k2+1] == clhray)
2601
{ res = EMPTY; goto STORE; }
2602
}
2603
idealrel = idealrelinit;
2604
for (k=1; k<lP; k++) /* cf get_discray */
2605
{
2606
long e, ep = E[k], pf = P[k] / degk, f = (pf%degk) + 1, S = 0;
2607
ulong normi = i, Npr;
2608
p = utoipos(pf / degk);
2609
Npr = upowuu(p[2],f);
2610
for (e=1; e<=ep; e++)
2611
{
2612
long clhss;
2613
GEN fad;
2614
if (e < ep) { E[k] = ep-e; fad = Fa; }
2615
else fad = factorsplice(Fa, k);
2616
normi /= Npr;
2617
clhss = Lbnrclassno(gel(Ray,normi),fad)[karch+1];
2618
if (e==1 && clhss==clhray) { E[k] = ep; res = EMPTY; goto STORE; }
2619
if (clhss == 1) { S += ep-e+1; break; }
2620
S += clhss;
2621
}
2622
E[k] = ep;
2623
idealrel = factormul(idealrel, to_famat_shallow(p, utoi(f * S)));
2624
}
2625
if (!allarch && nba)
2626
nz = get_nz(bnf, decodemodule(nf,Fa), arch, clhray);
2627
else
2628
nz = r1 - nba;
2629
res = get_NR1D(i, clhray, degk, nz, fadkabs, idealrel);
2630
STORE: gel(discall,karch+1) = res;
2631
}
2632
res = allarch? mkvec2(Fa, discall)
2633
: mkvec4(Fa, gel(res,1), gel(res,2), gel(res,3));
2634
gel(sousdisc,j) = res;
2635
if (gc_needed(av1,1))
2636
{
2637
long jj;
2638
if(DEBUGMEM>1) pari_warn(warnmem,"[2]: discrayabslistarch");
2639
for (jj=j+1; jj<ls; jj++) gel(sousdisc,jj) = gen_0; /* dummy */
2640
Disc = gerepilecopy(av1, Disc);
2641
sousdisc = gel(Disc,i);
2642
}
2643
}
2644
}
2645
return gerepilecopy(av0, Disc);
2646
}
2647
2648
int
2649
subgroup_conductor_ok(GEN H, GEN L)
2650
{ /* test conductor */
2651
long i, l = lg(L);
2652
for (i = 1; i < l; i++)
2653
if ( hnf_solve(H, gel(L,i)) ) return 0;
2654
return 1;
2655
}
2656
static GEN
2657
conductor_elts(GEN bnr)
2658
{
2659
long le, la, i, k;
2660
GEN e, L;
2661
zlog_S S;
2662
2663
if (!bnrisconductor(bnr, NULL)) return NULL;
2664
init_zlog(&S, bnr_get_bid(bnr));
2665
e = S.k; le = lg(e); la = lg(S.archp);
2666
L = cgetg(le + la - 1, t_VEC);
2667
i = 1;
2668
for (k = 1; k < le; k++)
2669
gel(L,i++) = bnr_log_gen_pr(bnr, &S, itos(gel(e,k)), k);
2670
for (k = 1; k < la; k++)
2671
gel(L,i++) = bnr_log_gen_arch(bnr, &S, k);
2672
return L;
2673
}
2674
2675
/* Let C a congruence group in bnr, compute its subgroups whose index is
2676
* described by bound (see subgrouplist) as subgroups of Clk(bnr).
2677
* Restrict to subgroups having the same conductor as bnr */
2678
GEN
2679
subgrouplist_cond_sub(GEN bnr, GEN C, GEN bound)
2680
{
2681
pari_sp av = avma;
2682
long l, i, j;
2683
GEN D, Mr, U, T, subgrp, L, cyc = bnr_get_cyc(bnr);
2684
2685
L = conductor_elts(bnr); if (!L) return cgetg(1,t_VEC);
2686
Mr = diagonal_shallow(cyc);
2687
D = ZM_snfall_i(hnf_solve(C, Mr), &U, NULL, 1);
2688
T = ZM_mul(C, RgM_inv(U));
2689
subgrp = subgrouplist(D, bound);
2690
l = lg(subgrp);
2691
for (i = j = 1; i < l; i++)
2692
{
2693
GEN H = ZM_hnfmodid(ZM_mul(T, gel(subgrp,i)), cyc);
2694
if (subgroup_conductor_ok(H, L)) gel(subgrp, j++) = H;
2695
}
2696
setlg(subgrp, j);
2697
return gerepilecopy(av, subgrp);
2698
}
2699
2700
static GEN
2701
subgroupcond(GEN bnr, GEN indexbound)
2702
{
2703
pari_sp av = avma;
2704
GEN L = conductor_elts(bnr);
2705
2706
if (!L) return cgetg(1, t_VEC);
2707
L = subgroupcondlist(bnr_get_cyc(bnr), indexbound, L);
2708
if (indexbound && typ(indexbound) != t_VEC)
2709
{ /* sort by increasing index if not single value */
2710
long i, l = lg(L);
2711
GEN D = cgetg(l,t_VEC);
2712
for (i=1; i<l; i++) gel(D,i) = ZM_det_triangular(gel(L,i));
2713
L = vecreverse( vecpermute(L, indexsort(D)) );
2714
}
2715
return gerepilecopy(av, L);
2716
}
2717
2718
GEN
2719
subgrouplist0(GEN cyc, GEN indexbound, long all)
2720
{
2721
if (!all && checkbnr_i(cyc)) return subgroupcond(cyc,indexbound);
2722
if (typ(cyc) != t_VEC || !RgV_is_ZV(cyc)) cyc = member_cyc(cyc);
2723
return subgrouplist(cyc,indexbound);
2724
}
2725
2726
GEN
2727
bnrdisclist0(GEN bnf, GEN L, GEN arch)
2728
{
2729
if (typ(L)!=t_INT) return discrayabslist(bnf,L);
2730
return discrayabslistarch(bnf,arch,itos(L));
2731
}
2732
2733
/****************************************************************************/
2734
/* Galois action on a BNR */
2735
/****************************************************************************/
2736
GEN
2737
bnrautmatrix(GEN bnr, GEN aut)
2738
{
2739
pari_sp av = avma;
2740
GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf), bid = bnr_get_bid(bnr);
2741
GEN M, Gen = get_Gen(bnf, bid, bnr_get_El(bnr)), cyc = bnr_get_cyc(bnr);
2742
long i, l = lg(Gen);
2743
2744
M = cgetg(l, t_MAT); aut = nfgaloismatrix(nf, aut);
2745
/* Gen = clg.gen*U, clg.gen = Gen*Ui */
2746
for (i = 1; i < l; i++)
2747
gel(M,i) = isprincipalray(bnr, nfgaloismatrixapply(nf, aut, gel(Gen,i)));
2748
M = ZM_mul(M, bnr_get_Ui(bnr));
2749
l = lg(M);
2750
for (i = 1; i < l; i++) gel(M,i) = vecmodii(gel(M,i), cyc);
2751
return gerepilecopy(av, M);
2752
}
2753
2754
GEN
2755
bnrgaloismatrix(GEN bnr, GEN aut)
2756
{
2757
checkbnr(bnr);
2758
switch (typ(aut))
2759
{
2760
case t_POL:
2761
case t_COL:
2762
return bnrautmatrix(bnr, aut);
2763
case t_VEC:
2764
{
2765
pari_sp av = avma;
2766
long i, l = lg(aut);
2767
GEN v;
2768
if (l == 9)
2769
{
2770
GEN g = gal_get_gen(aut);
2771
if (typ(g) == t_VEC) { aut = galoispermtopol(aut, g); l = lg(aut); }
2772
}
2773
v = cgetg(l, t_VEC);
2774
for(i = 1; i < l; i++) gel(v,i) = bnrautmatrix(bnr, gel(aut,i));
2775
return gerepileupto(av, v);
2776
}
2777
default:
2778
pari_err_TYPE("bnrgaloismatrix", aut);
2779
return NULL; /*LCOV_EXCL_LINE*/
2780
}
2781
}
2782
2783
GEN
2784
bnrgaloisapply(GEN bnr, GEN mat, GEN x)
2785
{
2786
pari_sp av=avma;
2787
GEN cyc;
2788
checkbnr(bnr);
2789
cyc = bnr_get_cyc(bnr);
2790
if (typ(mat)!=t_MAT || !RgM_is_ZM(mat))
2791
pari_err_TYPE("bnrgaloisapply",mat);
2792
if (typ(x)!=t_MAT || !RgM_is_ZM(x))
2793
pari_err_TYPE("bnrgaloisapply",x);
2794
return gerepileupto(av, ZM_hnfmodid(ZM_mul(mat, x), cyc));
2795
}
2796
2797
static GEN
2798
check_bnrgal(GEN bnr, GEN M)
2799
{
2800
checkbnr(bnr);
2801
if (typ(M)==t_MAT)
2802
return mkvec(M);
2803
else if (typ(M)==t_VEC && lg(M)==9 && typ(gal_get_gen(M))==t_VEC)
2804
{
2805
pari_sp av = avma;
2806
GEN V = galoispermtopol(M, gal_get_gen(M));
2807
return gerepileupto(av, bnrgaloismatrix(bnr, V));
2808
}
2809
else if (!is_vec_t(typ(M)))
2810
pari_err_TYPE("bnrisgalois",M);
2811
return M;
2812
}
2813
2814
long
2815
bnrisgalois(GEN bnr, GEN M, GEN H)
2816
{
2817
pari_sp av = avma;
2818
long i, l;
2819
if (typ(H)!=t_MAT || !RgM_is_ZM(H))
2820
pari_err_TYPE("bnrisgalois",H);
2821
M = check_bnrgal(bnr, M); l = lg(M);
2822
for (i=1; i<l; i++)
2823
{
2824
long res = ZM_equal(bnrgaloisapply(bnr,gel(M,i), H), H);
2825
if (!res) return gc_long(av,0);
2826
}
2827
return gc_long(av,1);
2828
}
2829
2830