Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28479 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
/* BASIC NF OPERATIONS */
18
/* */
19
/*******************************************************************/
20
#include "pari.h"
21
#include "paripriv.h"
22
23
#define DEBUGLEVEL DEBUGLEVEL_nf
24
25
/*******************************************************************/
26
/* */
27
/* OPERATIONS OVER NUMBER FIELD ELEMENTS. */
28
/* represented as column vectors over the integral basis */
29
/* */
30
/*******************************************************************/
31
static GEN
32
get_tab(GEN nf, long *N)
33
{
34
GEN tab = (typ(nf) == t_MAT)? nf: gel(nf,9);
35
*N = nbrows(tab); return tab;
36
}
37
38
/* x != 0, y t_INT. Return x * y (not memory clean if x = 1) */
39
static GEN
40
_mulii(GEN x, GEN y) {
41
return is_pm1(x)? (signe(x) < 0)? negi(y): y
42
: mulii(x, y);
43
}
44
45
GEN
46
tablemul_ei_ej(GEN M, long i, long j)
47
{
48
long N;
49
GEN tab = get_tab(M, &N);
50
tab += (i-1)*N; return gel(tab,j);
51
}
52
53
/* Outputs x.ei, where ei is the i-th elt of the algebra basis.
54
* x an RgV of correct length and arbitrary content (polynomials, scalars...).
55
* M is the multiplication table ei ej = sum_k M_k^(i,j) ek */
56
GEN
57
tablemul_ei(GEN M, GEN x, long i)
58
{
59
long j, k, N;
60
GEN v, tab;
61
62
if (i==1) return gcopy(x);
63
tab = get_tab(M, &N);
64
if (typ(x) != t_COL) { v = zerocol(N); gel(v,i) = gcopy(x); return v; }
65
tab += (i-1)*N; v = cgetg(N+1,t_COL);
66
/* wi . x = [ sum_j tab[k,j] x[j] ]_k */
67
for (k=1; k<=N; k++)
68
{
69
pari_sp av = avma;
70
GEN s = gen_0;
71
for (j=1; j<=N; j++)
72
{
73
GEN c = gcoeff(tab,k,j);
74
if (!gequal0(c)) s = gadd(s, gmul(c, gel(x,j)));
75
}
76
gel(v,k) = gerepileupto(av,s);
77
}
78
return v;
79
}
80
/* as tablemul_ei, assume x a ZV of correct length */
81
GEN
82
zk_ei_mul(GEN nf, GEN x, long i)
83
{
84
long j, k, N;
85
GEN v, tab;
86
87
if (i==1) return ZC_copy(x);
88
tab = get_tab(nf, &N); tab += (i-1)*N;
89
v = cgetg(N+1,t_COL);
90
for (k=1; k<=N; k++)
91
{
92
pari_sp av = avma;
93
GEN s = gen_0;
94
for (j=1; j<=N; j++)
95
{
96
GEN c = gcoeff(tab,k,j);
97
if (signe(c)) s = addii(s, _mulii(c, gel(x,j)));
98
}
99
gel(v,k) = gerepileuptoint(av, s);
100
}
101
return v;
102
}
103
104
/* table of multiplication by wi in R[w1,..., wN] */
105
GEN
106
ei_multable(GEN TAB, long i)
107
{
108
long k,N;
109
GEN m, tab = get_tab(TAB, &N);
110
tab += (i-1)*N;
111
m = cgetg(N+1,t_MAT);
112
for (k=1; k<=N; k++) gel(m,k) = gel(tab,k);
113
return m;
114
}
115
116
GEN
117
zk_multable(GEN nf, GEN x)
118
{
119
long i, l = lg(x);
120
GEN mul = cgetg(l,t_MAT);
121
gel(mul,1) = x; /* assume w_1 = 1 */
122
for (i=2; i<l; i++) gel(mul,i) = zk_ei_mul(nf,x,i);
123
return mul;
124
}
125
GEN
126
multable(GEN M, GEN x)
127
{
128
long i, N;
129
GEN mul;
130
if (typ(x) == t_MAT) return x;
131
M = get_tab(M, &N);
132
if (typ(x) != t_COL) return scalarmat(x, N);
133
mul = cgetg(N+1,t_MAT);
134
gel(mul,1) = x; /* assume w_1 = 1 */
135
for (i=2; i<=N; i++) gel(mul,i) = tablemul_ei(M,x,i);
136
return mul;
137
}
138
139
/* x integral in nf; table of multiplication by x in ZK = Z[w1,..., wN].
140
* Return a t_INT if x is scalar, and a ZM otherwise */
141
GEN
142
zk_scalar_or_multable(GEN nf, GEN x)
143
{
144
long tx = typ(x);
145
if (tx == t_MAT || tx == t_INT) return x;
146
x = nf_to_scalar_or_basis(nf, x);
147
return (typ(x) == t_COL)? zk_multable(nf, x): x;
148
}
149
150
GEN
151
nftrace(GEN nf, GEN x)
152
{
153
pari_sp av = avma;
154
nf = checknf(nf);
155
x = nf_to_scalar_or_basis(nf, x);
156
x = (typ(x) == t_COL)? RgV_dotproduct(x, gel(nf_get_Tr(nf),1))
157
: gmulgs(x, nf_get_degree(nf));
158
return gerepileupto(av, x);
159
}
160
GEN
161
rnfelttrace(GEN rnf, GEN x)
162
{
163
pari_sp av = avma;
164
checkrnf(rnf);
165
x = rnfeltabstorel(rnf, x);
166
x = (typ(x) == t_POLMOD)? rnfeltdown(rnf, gtrace(x))
167
: gmulgs(x, rnf_get_degree(rnf));
168
return gerepileupto(av, x);
169
}
170
171
/* assume nf is a genuine nf, fa a famat */
172
static GEN
173
famat_norm(GEN nf, GEN fa)
174
{
175
pari_sp av = avma;
176
GEN g = gel(fa,1), e = gel(fa,2), N = gen_1;
177
long i, l = lg(g);
178
for (i = 1; i < l; i++)
179
N = gmul(N, powgi(nfnorm(nf, gel(g,i)), gel(e,i)));
180
return gerepileupto(av, N);
181
}
182
GEN
183
nfnorm(GEN nf, GEN x)
184
{
185
pari_sp av = avma;
186
GEN c, den;
187
long n;
188
nf = checknf(nf);
189
n = nf_get_degree(nf);
190
if (typ(x) == t_MAT) return famat_norm(nf, x);
191
x = nf_to_scalar_or_basis(nf, x);
192
if (typ(x)!=t_COL)
193
return gerepileupto(av, gpowgs(x, n));
194
x = nf_to_scalar_or_alg(nf, Q_primitive_part(x, &c));
195
x = Q_remove_denom(x, &den);
196
x = ZX_resultant_all(nf_get_pol(nf), x, den, 0);
197
return gerepileupto(av, c ? gmul(x, gpowgs(c, n)): x);
198
}
199
200
static GEN
201
to_RgX(GEN P, long vx)
202
{
203
return varn(P) == vx ? P: scalarpol_shallow(P, vx);
204
}
205
206
GEN
207
rnfeltnorm(GEN rnf, GEN x)
208
{
209
pari_sp av = avma;
210
GEN nf, pol;
211
long v = rnf_get_varn(rnf);
212
checkrnf(rnf);
213
x = liftpol_shallow(rnfeltabstorel(rnf, x));
214
nf = rnf_get_nf(rnf); pol = rnf_get_pol(rnf);
215
x = (typ(x) == t_POL)
216
? rnfeltdown(rnf, nfX_resultant(nf,pol,to_RgX(x,v)))
217
: gpowgs(x, rnf_get_degree(rnf));
218
return gerepileupto(av, x);
219
}
220
221
/* x + y in nf */
222
GEN
223
nfadd(GEN nf, GEN x, GEN y)
224
{
225
pari_sp av = avma;
226
GEN z;
227
228
nf = checknf(nf);
229
x = nf_to_scalar_or_basis(nf, x);
230
y = nf_to_scalar_or_basis(nf, y);
231
if (typ(x) != t_COL)
232
{ z = (typ(y) == t_COL)? RgC_Rg_add(y, x): gadd(x,y); }
233
else
234
{ z = (typ(y) == t_COL)? RgC_add(x, y): RgC_Rg_add(x, y); }
235
return gerepileupto(av, z);
236
}
237
/* x - y in nf */
238
GEN
239
nfsub(GEN nf, GEN x, GEN y)
240
{
241
pari_sp av = avma;
242
GEN z;
243
244
nf = checknf(nf);
245
x = nf_to_scalar_or_basis(nf, x);
246
y = nf_to_scalar_or_basis(nf, y);
247
if (typ(x) != t_COL)
248
{ z = (typ(y) == t_COL)? Rg_RgC_sub(x,y): gsub(x,y); }
249
else
250
{ z = (typ(y) == t_COL)? RgC_sub(x,y): RgC_Rg_sub(x,y); }
251
return gerepileupto(av, z);
252
}
253
254
/* product of ZC x,y in nf; ( sum_i x_i sum_j y_j m^{i,j}_k )_k */
255
static GEN
256
nfmuli_ZC(GEN nf, GEN x, GEN y)
257
{
258
long i, j, k, N;
259
GEN TAB = get_tab(nf, &N), v = cgetg(N+1,t_COL);
260
261
for (k = 1; k <= N; k++)
262
{
263
pari_sp av = avma;
264
GEN s, TABi = TAB;
265
if (k == 1)
266
s = mulii(gel(x,1),gel(y,1));
267
else
268
s = addii(mulii(gel(x,1),gel(y,k)),
269
mulii(gel(x,k),gel(y,1)));
270
for (i=2; i<=N; i++)
271
{
272
GEN t, xi = gel(x,i);
273
TABi += N;
274
if (!signe(xi)) continue;
275
276
t = NULL;
277
for (j=2; j<=N; j++)
278
{
279
GEN p1, c = gcoeff(TABi, k, j); /* m^{i,j}_k */
280
if (!signe(c)) continue;
281
p1 = _mulii(c, gel(y,j));
282
t = t? addii(t, p1): p1;
283
}
284
if (t) s = addii(s, mulii(xi, t));
285
}
286
gel(v,k) = gerepileuptoint(av,s);
287
}
288
return v;
289
}
290
static int
291
is_famat(GEN x) { return typ(x) == t_MAT && lg(x) == 3; }
292
/* product of x and y in nf */
293
GEN
294
nfmul(GEN nf, GEN x, GEN y)
295
{
296
GEN z;
297
pari_sp av = avma;
298
299
if (x == y) return nfsqr(nf,x);
300
301
nf = checknf(nf);
302
if (is_famat(x) || is_famat(y)) return famat_mul(x, y);
303
x = nf_to_scalar_or_basis(nf, x);
304
y = nf_to_scalar_or_basis(nf, y);
305
if (typ(x) != t_COL)
306
{
307
if (isintzero(x)) return gen_0;
308
z = (typ(y) == t_COL)? RgC_Rg_mul(y, x): gmul(x,y); }
309
else
310
{
311
if (typ(y) != t_COL)
312
{
313
if (isintzero(y)) return gen_0;
314
z = RgC_Rg_mul(x, y);
315
}
316
else
317
{
318
GEN dx, dy;
319
x = Q_remove_denom(x, &dx);
320
y = Q_remove_denom(y, &dy);
321
z = nfmuli_ZC(nf,x,y);
322
dx = mul_denom(dx,dy);
323
if (dx) z = ZC_Z_div(z, dx);
324
}
325
}
326
return gerepileupto(av, z);
327
}
328
/* square of ZC x in nf */
329
static GEN
330
nfsqri_ZC(GEN nf, GEN x)
331
{
332
long i, j, k, N;
333
GEN TAB = get_tab(nf, &N), v = cgetg(N+1,t_COL);
334
335
for (k = 1; k <= N; k++)
336
{
337
pari_sp av = avma;
338
GEN s, TABi = TAB;
339
if (k == 1)
340
s = sqri(gel(x,1));
341
else
342
s = shifti(mulii(gel(x,1),gel(x,k)), 1);
343
for (i=2; i<=N; i++)
344
{
345
GEN p1, c, t, xi = gel(x,i);
346
TABi += N;
347
if (!signe(xi)) continue;
348
349
c = gcoeff(TABi, k, i);
350
t = signe(c)? _mulii(c,xi): NULL;
351
for (j=i+1; j<=N; j++)
352
{
353
c = gcoeff(TABi, k, j);
354
if (!signe(c)) continue;
355
p1 = _mulii(c, shifti(gel(x,j),1));
356
t = t? addii(t, p1): p1;
357
}
358
if (t) s = addii(s, mulii(xi, t));
359
}
360
gel(v,k) = gerepileuptoint(av,s);
361
}
362
return v;
363
}
364
/* square of x in nf */
365
GEN
366
nfsqr(GEN nf, GEN x)
367
{
368
pari_sp av = avma;
369
GEN z;
370
371
nf = checknf(nf);
372
if (is_famat(x)) return famat_sqr(x);
373
x = nf_to_scalar_or_basis(nf, x);
374
if (typ(x) != t_COL) z = gsqr(x);
375
else
376
{
377
GEN dx;
378
x = Q_remove_denom(x, &dx);
379
z = nfsqri_ZC(nf,x);
380
if (dx) z = RgC_Rg_div(z, sqri(dx));
381
}
382
return gerepileupto(av, z);
383
}
384
385
/* x a ZC, v a t_COL of ZC/Z */
386
GEN
387
zkC_multable_mul(GEN v, GEN x)
388
{
389
long i, l = lg(v);
390
GEN y = cgetg(l, t_COL);
391
for (i = 1; i < l; i++)
392
{
393
GEN c = gel(v,i);
394
if (typ(c)!=t_COL) {
395
if (!isintzero(c)) c = ZC_Z_mul(gel(x,1), c);
396
} else {
397
c = ZM_ZC_mul(x,c);
398
if (ZV_isscalar(c)) c = gel(c,1);
399
}
400
gel(y,i) = c;
401
}
402
return y;
403
}
404
405
GEN
406
nfC_multable_mul(GEN v, GEN x)
407
{
408
long i, l = lg(v);
409
GEN y = cgetg(l, t_COL);
410
for (i = 1; i < l; i++)
411
{
412
GEN c = gel(v,i);
413
if (typ(c)!=t_COL) {
414
if (!isintzero(c)) c = RgC_Rg_mul(gel(x,1), c);
415
} else {
416
c = RgM_RgC_mul(x,c);
417
if (QV_isscalar(c)) c = gel(c,1);
418
}
419
gel(y,i) = c;
420
}
421
return y;
422
}
423
424
GEN
425
nfC_nf_mul(GEN nf, GEN v, GEN x)
426
{
427
long tx;
428
GEN y;
429
430
x = nf_to_scalar_or_basis(nf, x);
431
tx = typ(x);
432
if (tx != t_COL)
433
{
434
long l, i;
435
if (tx == t_INT)
436
{
437
long s = signe(x);
438
if (!s) return zerocol(lg(v)-1);
439
if (is_pm1(x)) return s > 0? leafcopy(v): RgC_neg(v);
440
}
441
l = lg(v); y = cgetg(l, t_COL);
442
for (i=1; i < l; i++)
443
{
444
GEN c = gel(v,i);
445
if (typ(c) != t_COL) c = gmul(c, x); else c = RgC_Rg_mul(c, x);
446
gel(y,i) = c;
447
}
448
return y;
449
}
450
else
451
{
452
GEN dx;
453
x = zk_multable(nf, Q_remove_denom(x,&dx));
454
y = nfC_multable_mul(v, x);
455
return dx? RgC_Rg_div(y, dx): y;
456
}
457
}
458
static GEN
459
mulbytab(GEN M, GEN c)
460
{ return typ(c) == t_COL? RgM_RgC_mul(M,c): RgC_Rg_mul(gel(M,1), c); }
461
GEN
462
tablemulvec(GEN M, GEN x, GEN v)
463
{
464
long l, i;
465
GEN y;
466
467
if (typ(x) == t_COL && RgV_isscalar(x))
468
{
469
x = gel(x,1);
470
return typ(v) == t_POL? RgX_Rg_mul(v,x): RgV_Rg_mul(v,x);
471
}
472
x = multable(M, x); /* multiplication table by x */
473
y = cgetg_copy(v, &l);
474
if (typ(v) == t_POL)
475
{
476
y[1] = v[1];
477
for (i=2; i < l; i++) gel(y,i) = mulbytab(x, gel(v,i));
478
y = normalizepol(y);
479
}
480
else
481
{
482
for (i=1; i < l; i++) gel(y,i) = mulbytab(x, gel(v,i));
483
}
484
return y;
485
}
486
487
GEN
488
zkmultable_capZ(GEN mx) { return Q_denom(zkmultable_inv(mx)); }
489
GEN
490
zkmultable_inv(GEN mx) { return ZM_gauss(mx, col_ei(lg(mx)-1,1)); }
491
/* nf a true nf, x a ZC */
492
GEN
493
zk_inv(GEN nf, GEN x) { return zkmultable_inv(zk_multable(nf,x)); }
494
495
/* inverse of x in nf */
496
GEN
497
nfinv(GEN nf, GEN x)
498
{
499
pari_sp av = avma;
500
GEN z;
501
502
nf = checknf(nf);
503
if (is_famat(x)) return famat_inv(x);
504
x = nf_to_scalar_or_basis(nf, x);
505
if (typ(x) == t_COL)
506
{
507
GEN d;
508
x = Q_remove_denom(x, &d);
509
z = zk_inv(nf, x);
510
if (d) z = RgC_Rg_mul(z, d);
511
}
512
else
513
z = ginv(x);
514
return gerepileupto(av, z);
515
}
516
517
/* quotient of x and y in nf */
518
GEN
519
nfdiv(GEN nf, GEN x, GEN y)
520
{
521
pari_sp av = avma;
522
GEN z;
523
524
nf = checknf(nf);
525
if (is_famat(x) || is_famat(y)) return famat_div(x,y);
526
y = nf_to_scalar_or_basis(nf, y);
527
if (typ(y) != t_COL)
528
{
529
x = nf_to_scalar_or_basis(nf, x);
530
z = (typ(x) == t_COL)? RgC_Rg_div(x, y): gdiv(x,y);
531
}
532
else
533
{
534
GEN d;
535
y = Q_remove_denom(y, &d);
536
z = nfmul(nf, x, zk_inv(nf,y));
537
if (d) z = typ(z) == t_COL? RgC_Rg_mul(z, d): gmul(z, d);
538
}
539
return gerepileupto(av, z);
540
}
541
542
/* product of INTEGERS (t_INT or ZC) x and y in nf */
543
GEN
544
nfmuli(GEN nf, GEN x, GEN y)
545
{
546
if (typ(x) == t_INT) return (typ(y) == t_COL)? ZC_Z_mul(y, x): mulii(x,y);
547
if (typ(y) == t_INT) return ZC_Z_mul(x, y);
548
return nfmuli_ZC(nf, x, y);
549
}
550
GEN
551
nfsqri(GEN nf, GEN x)
552
{ return (typ(x) == t_INT)? sqri(x): nfsqri_ZC(nf, x); }
553
554
/* both x and y are RgV */
555
GEN
556
tablemul(GEN TAB, GEN x, GEN y)
557
{
558
long i, j, k, N;
559
GEN s, v;
560
if (typ(x) != t_COL) return gmul(x, y);
561
if (typ(y) != t_COL) return gmul(y, x);
562
N = lg(x)-1;
563
v = cgetg(N+1,t_COL);
564
for (k=1; k<=N; k++)
565
{
566
pari_sp av = avma;
567
GEN TABi = TAB;
568
if (k == 1)
569
s = gmul(gel(x,1),gel(y,1));
570
else
571
s = gadd(gmul(gel(x,1),gel(y,k)),
572
gmul(gel(x,k),gel(y,1)));
573
for (i=2; i<=N; i++)
574
{
575
GEN t, xi = gel(x,i);
576
TABi += N;
577
if (gequal0(xi)) continue;
578
579
t = NULL;
580
for (j=2; j<=N; j++)
581
{
582
GEN p1, c = gcoeff(TABi, k, j); /* m^{i,j}_k */
583
if (gequal0(c)) continue;
584
p1 = gmul(c, gel(y,j));
585
t = t? gadd(t, p1): p1;
586
}
587
if (t) s = gadd(s, gmul(xi, t));
588
}
589
gel(v,k) = gerepileupto(av,s);
590
}
591
return v;
592
}
593
GEN
594
tablesqr(GEN TAB, GEN x)
595
{
596
long i, j, k, N;
597
GEN s, v;
598
599
if (typ(x) != t_COL) return gsqr(x);
600
N = lg(x)-1;
601
v = cgetg(N+1,t_COL);
602
603
for (k=1; k<=N; k++)
604
{
605
pari_sp av = avma;
606
GEN TABi = TAB;
607
if (k == 1)
608
s = gsqr(gel(x,1));
609
else
610
s = gmul2n(gmul(gel(x,1),gel(x,k)), 1);
611
for (i=2; i<=N; i++)
612
{
613
GEN p1, c, t, xi = gel(x,i);
614
TABi += N;
615
if (gequal0(xi)) continue;
616
617
c = gcoeff(TABi, k, i);
618
t = !gequal0(c)? gmul(c,xi): NULL;
619
for (j=i+1; j<=N; j++)
620
{
621
c = gcoeff(TABi, k, j);
622
if (gequal0(c)) continue;
623
p1 = gmul(gmul2n(c,1), gel(x,j));
624
t = t? gadd(t, p1): p1;
625
}
626
if (t) s = gadd(s, gmul(xi, t));
627
}
628
gel(v,k) = gerepileupto(av,s);
629
}
630
return v;
631
}
632
633
static GEN
634
_mul(void *data, GEN x, GEN y) { return nfmuli((GEN)data,x,y); }
635
static GEN
636
_sqr(void *data, GEN x) { return nfsqri((GEN)data,x); }
637
638
/* Compute z^n in nf, left-shift binary powering */
639
GEN
640
nfpow(GEN nf, GEN z, GEN n)
641
{
642
pari_sp av = avma;
643
long s;
644
GEN x, cx;
645
646
if (typ(n)!=t_INT) pari_err_TYPE("nfpow",n);
647
nf = checknf(nf);
648
s = signe(n); if (!s) return gen_1;
649
if (is_famat(z)) return famat_pow(z, n);
650
x = nf_to_scalar_or_basis(nf, z);
651
if (typ(x) != t_COL) return powgi(x,n);
652
if (s < 0)
653
{ /* simplified nfinv */
654
GEN d;
655
x = Q_remove_denom(x, &d);
656
x = zk_inv(nf, x);
657
x = primitive_part(x, &cx);
658
cx = mul_content(cx, d);
659
n = negi(n);
660
}
661
else
662
x = primitive_part(x, &cx);
663
x = gen_pow_i(x, n, (void*)nf, _sqr, _mul);
664
if (cx)
665
x = gerepileupto(av, gmul(x, powgi(cx, n)));
666
else
667
x = gerepilecopy(av, x);
668
return x;
669
}
670
/* Compute z^n in nf, left-shift binary powering */
671
GEN
672
nfpow_u(GEN nf, GEN z, ulong n)
673
{
674
pari_sp av = avma;
675
GEN x, cx;
676
677
nf = checknf(nf);
678
if (!n) return gen_1;
679
x = nf_to_scalar_or_basis(nf, z);
680
if (typ(x) != t_COL) return gpowgs(x,n);
681
x = primitive_part(x, &cx);
682
x = gen_powu_i(x, n, (void*)nf, _sqr, _mul);
683
if (cx)
684
{
685
x = gmul(x, powgi(cx, utoipos(n)));
686
return gerepileupto(av,x);
687
}
688
return gerepilecopy(av, x);
689
}
690
691
static GEN
692
_nf_red(void *E, GEN x) { (void)E; return x; }
693
694
static GEN
695
_nf_add(void *E, GEN x, GEN y) { return nfadd((GEN)E,x,y); }
696
697
static GEN
698
_nf_neg(void *E, GEN x) { (void)E; return gneg(x); }
699
700
static GEN
701
_nf_mul(void *E, GEN x, GEN y) { return nfmul((GEN)E,x,y); }
702
703
static GEN
704
_nf_inv(void *E, GEN x) { return nfinv((GEN)E,x); }
705
706
static GEN
707
_nf_s(void *E, long x) { (void)E; return stoi(x); }
708
709
static const struct bb_field nf_field={_nf_red,_nf_add,_nf_mul,_nf_neg,
710
_nf_inv,&gequal0,_nf_s };
711
712
const struct bb_field *get_nf_field(void **E, GEN nf)
713
{ *E = (void*)nf; return &nf_field; }
714
715
GEN
716
nfM_det(GEN nf, GEN M)
717
{
718
void *E;
719
const struct bb_field *S = get_nf_field(&E, nf);
720
return gen_det(M, E, S);
721
}
722
GEN
723
nfM_inv(GEN nf, GEN M)
724
{
725
void *E;
726
const struct bb_field *S = get_nf_field(&E, nf);
727
return gen_Gauss(M, matid(lg(M)-1), E, S);
728
}
729
GEN
730
nfM_mul(GEN nf, GEN A, GEN B)
731
{
732
void *E;
733
const struct bb_field *S = get_nf_field(&E, nf);
734
return gen_matmul(A, B, E, S);
735
}
736
GEN
737
nfM_nfC_mul(GEN nf, GEN A, GEN B)
738
{
739
void *E;
740
const struct bb_field *S = get_nf_field(&E, nf);
741
return gen_matcolmul(A, B, E, S);
742
}
743
744
/* valuation of integral x (ZV), with resp. to prime ideal pr */
745
long
746
ZC_nfvalrem(GEN x, GEN pr, GEN *newx)
747
{
748
pari_sp av = avma;
749
long i, v, l;
750
GEN r, y, p = pr_get_p(pr), mul = pr_get_tau(pr);
751
752
/* p inert */
753
if (typ(mul) == t_INT) return newx? ZV_pvalrem(x, p, newx):ZV_pval(x, p);
754
y = cgetg_copy(x, &l); /* will hold the new x */
755
x = leafcopy(x);
756
for(v=0;; v++)
757
{
758
for (i=1; i<l; i++)
759
{ /* is (x.b)[i] divisible by p ? */
760
gel(y,i) = dvmdii(ZMrow_ZC_mul(mul,x,i),p,&r);
761
if (r != gen_0) { if (newx) *newx = x; return v; }
762
}
763
swap(x, y);
764
if (!newx && (v & 0xf) == 0xf) v += pr_get_e(pr) * ZV_pvalrem(x, p, &x);
765
if (gc_needed(av,1))
766
{
767
if(DEBUGMEM>1) pari_warn(warnmem,"ZC_nfvalrem, v >= %ld", v);
768
gerepileall(av, 2, &x, &y);
769
}
770
}
771
}
772
long
773
ZC_nfval(GEN x, GEN P)
774
{ return ZC_nfvalrem(x, P, NULL); }
775
776
/* v_P(x) != 0, x a ZV. Simpler version of ZC_nfvalrem */
777
int
778
ZC_prdvd(GEN x, GEN P)
779
{
780
pari_sp av = avma;
781
long i, l;
782
GEN p = pr_get_p(P), mul = pr_get_tau(P);
783
if (typ(mul) == t_INT) return ZV_Z_dvd(x, p);
784
l = lg(x);
785
for (i=1; i<l; i++)
786
if (!dvdii(ZMrow_ZC_mul(mul,x,i), p)) return gc_bool(av,0);
787
return gc_bool(av,1);
788
}
789
790
int
791
pr_equal(GEN P, GEN Q)
792
{
793
GEN gQ, p = pr_get_p(P);
794
long e = pr_get_e(P), f = pr_get_f(P), n;
795
if (!equalii(p, pr_get_p(Q)) || e != pr_get_e(Q) || f != pr_get_f(Q))
796
return 0;
797
gQ = pr_get_gen(Q); n = lg(gQ)-1;
798
if (2*e*f > n) return 1; /* room for only one such pr */
799
return ZV_equal(pr_get_gen(P), gQ) || ZC_prdvd(gQ, P);
800
}
801
802
GEN
803
famat_nfvalrem(GEN nf, GEN x, GEN pr, GEN *py)
804
{
805
pari_sp av = avma;
806
GEN P = gel(x,1), E = gel(x,2), V = gen_0, y = NULL;
807
long l = lg(P), simplify = 0, i;
808
if (py) { *py = gen_1; y = cgetg(l, t_COL); }
809
810
for (i = 1; i < l; i++)
811
{
812
GEN e = gel(E,i);
813
long v;
814
if (!signe(e))
815
{
816
if (py) gel(y,i) = gen_1;
817
simplify = 1; continue;
818
}
819
v = nfvalrem(nf, gel(P,i), pr, py? &gel(y,i): NULL);
820
if (v == LONG_MAX) { set_avma(av); if (py) *py = gen_0; return mkoo(); }
821
V = addmulii(V, stoi(v), e);
822
}
823
if (!py) V = gerepileuptoint(av, V);
824
else
825
{
826
y = mkmat2(y, gel(x,2));
827
if (simplify) y = famat_remove_trivial(y);
828
gerepileall(av, 2, &V, &y); *py = y;
829
}
830
return V;
831
}
832
long
833
nfval(GEN nf, GEN x, GEN pr)
834
{
835
pari_sp av = avma;
836
long w, e;
837
GEN cx, p;
838
839
if (gequal0(x)) return LONG_MAX;
840
nf = checknf(nf);
841
checkprid(pr);
842
p = pr_get_p(pr);
843
e = pr_get_e(pr);
844
x = nf_to_scalar_or_basis(nf, x);
845
if (typ(x) != t_COL) return e*Q_pval(x,p);
846
x = Q_primitive_part(x, &cx);
847
w = ZC_nfval(x,pr);
848
if (cx) w += e*Q_pval(cx,p);
849
return gc_long(av,w);
850
}
851
852
/* want to write p^v = uniformizer^(e*v) * z^v, z coprime to pr */
853
/* z := tau^e / p^(e-1), algebraic integer coprime to pr; return z^v */
854
static GEN
855
powp(GEN nf, GEN pr, long v)
856
{
857
GEN b, z;
858
long e;
859
if (!v) return gen_1;
860
b = pr_get_tau(pr);
861
if (typ(b) == t_INT) return gen_1;
862
e = pr_get_e(pr);
863
z = gel(b,1);
864
if (e != 1) z = gdiv(nfpow_u(nf, z, e), powiu(pr_get_p(pr),e-1));
865
if (v < 0) { v = -v; z = nfinv(nf, z); }
866
if (v != 1) z = nfpow_u(nf, z, v);
867
return z;
868
}
869
long
870
nfvalrem(GEN nf, GEN x, GEN pr, GEN *py)
871
{
872
pari_sp av = avma;
873
long w, e;
874
GEN cx, p, t;
875
876
if (!py) return nfval(nf,x,pr);
877
if (gequal0(x)) { *py = gen_0; return LONG_MAX; }
878
nf = checknf(nf);
879
checkprid(pr);
880
p = pr_get_p(pr);
881
e = pr_get_e(pr);
882
x = nf_to_scalar_or_basis(nf, x);
883
if (typ(x) != t_COL) {
884
w = Q_pvalrem(x,p, py);
885
if (!w) { *py = gerepilecopy(av, x); return 0; }
886
*py = gerepileupto(av, gmul(powp(nf, pr, w), *py));
887
return e*w;
888
}
889
x = Q_primitive_part(x, &cx);
890
w = ZC_nfvalrem(x,pr, py);
891
if (cx)
892
{
893
long v = Q_pvalrem(cx,p, &t);
894
*py = nfmul(nf, *py, gmul(powp(nf,pr,v), t));
895
*py = gerepileupto(av, *py);
896
w += e*v;
897
}
898
else
899
*py = gerepilecopy(av, *py);
900
return w;
901
}
902
GEN
903
gpnfvalrem(GEN nf, GEN x, GEN pr, GEN *py)
904
{
905
long v;
906
if (is_famat(x)) return famat_nfvalrem(nf, x, pr, py);
907
v = nfvalrem(nf,x,pr,py);
908
return v == LONG_MAX? mkoo(): stoi(v);
909
}
910
911
/* true nf */
912
GEN
913
coltoalg(GEN nf, GEN x)
914
{
915
return mkpolmod( nf_to_scalar_or_alg(nf, x), nf_get_pol(nf) );
916
}
917
918
GEN
919
basistoalg(GEN nf, GEN x)
920
{
921
GEN T;
922
923
nf = checknf(nf);
924
switch(typ(x))
925
{
926
case t_COL: {
927
pari_sp av = avma;
928
return gerepilecopy(av, coltoalg(nf, x));
929
}
930
case t_POLMOD:
931
T = nf_get_pol(nf);
932
if (!RgX_equal_var(T,gel(x,1)))
933
pari_err_MODULUS("basistoalg", T,gel(x,1));
934
return gcopy(x);
935
case t_POL:
936
T = nf_get_pol(nf);
937
if (varn(T) != varn(x)) pari_err_VAR("basistoalg",x,T);
938
retmkpolmod(RgX_rem(x, T), ZX_copy(T));
939
case t_INT:
940
case t_FRAC:
941
T = nf_get_pol(nf);
942
retmkpolmod(gcopy(x), ZX_copy(T));
943
default:
944
pari_err_TYPE("basistoalg",x);
945
return NULL; /* LCOV_EXCL_LINE */
946
}
947
}
948
949
/* true nf, x a t_POL */
950
static GEN
951
pol_to_scalar_or_basis(GEN nf, GEN x)
952
{
953
GEN T = nf_get_pol(nf);
954
long l = lg(x);
955
if (varn(x) != varn(T)) pari_err_VAR("nf_to_scalar_or_basis", x,T);
956
if (l >= lg(T)) { x = RgX_rem(x, T); l = lg(x); }
957
if (l == 2) return gen_0;
958
if (l == 3)
959
{
960
x = gel(x,2);
961
if (!is_rational_t(typ(x))) pari_err_TYPE("nf_to_scalar_or_basis",x);
962
return x;
963
}
964
return poltobasis(nf,x);
965
}
966
/* Assume nf is a genuine nf. */
967
GEN
968
nf_to_scalar_or_basis(GEN nf, GEN x)
969
{
970
switch(typ(x))
971
{
972
case t_INT: case t_FRAC:
973
return x;
974
case t_POLMOD:
975
x = checknfelt_mod(nf,x,"nf_to_scalar_or_basis");
976
switch(typ(x))
977
{
978
case t_INT: case t_FRAC: return x;
979
case t_POL: return pol_to_scalar_or_basis(nf,x);
980
}
981
break;
982
case t_POL: return pol_to_scalar_or_basis(nf,x);
983
case t_COL:
984
if (lg(x)-1 != nf_get_degree(nf)) break;
985
return QV_isscalar(x)? gel(x,1): x;
986
}
987
pari_err_TYPE("nf_to_scalar_or_basis",x);
988
return NULL; /* LCOV_EXCL_LINE */
989
}
990
/* Let x be a polynomial with coefficients in Q or nf. Return the same
991
* polynomial with coefficients expressed as vectors (on the integral basis).
992
* No consistency checks, not memory-clean. */
993
GEN
994
RgX_to_nfX(GEN nf, GEN x)
995
{
996
long i, l;
997
GEN y = cgetg_copy(x, &l); y[1] = x[1];
998
for (i=2; i<l; i++) gel(y,i) = nf_to_scalar_or_basis(nf, gel(x,i));
999
return y;
1000
}
1001
1002
/* Assume nf is a genuine nf. */
1003
GEN
1004
nf_to_scalar_or_alg(GEN nf, GEN x)
1005
{
1006
switch(typ(x))
1007
{
1008
case t_INT: case t_FRAC:
1009
return x;
1010
case t_POLMOD:
1011
x = checknfelt_mod(nf,x,"nf_to_scalar_or_alg");
1012
if (typ(x) != t_POL) return x;
1013
/* fall through */
1014
case t_POL:
1015
{
1016
GEN T = nf_get_pol(nf);
1017
long l = lg(x);
1018
if (varn(x) != varn(T)) pari_err_VAR("nf_to_scalar_or_alg", x,T);
1019
if (l >= lg(T)) { x = RgX_rem(x, T); l = lg(x); }
1020
if (l == 2) return gen_0;
1021
if (l == 3) return gel(x,2);
1022
return x;
1023
}
1024
case t_COL:
1025
{
1026
GEN dx;
1027
if (lg(x)-1 != nf_get_degree(nf)) break;
1028
if (QV_isscalar(x)) return gel(x,1);
1029
x = Q_remove_denom(x, &dx);
1030
x = RgV_RgC_mul(nf_get_zkprimpart(nf), x);
1031
dx = mul_denom(dx, nf_get_zkden(nf));
1032
return gdiv(x,dx);
1033
}
1034
}
1035
pari_err_TYPE("nf_to_scalar_or_alg",x);
1036
return NULL; /* LCOV_EXCL_LINE */
1037
}
1038
1039
/* gmul(A, RgX_to_RgC(x)), A t_MAT of compatible dimensions */
1040
GEN
1041
RgM_RgX_mul(GEN A, GEN x)
1042
{
1043
long i, l = lg(x)-1;
1044
GEN z;
1045
if (l == 1) return zerocol(nbrows(A));
1046
z = gmul(gel(x,2), gel(A,1));
1047
for (i = 2; i < l; i++)
1048
if (!gequal0(gel(x,i+1))) z = gadd(z, gmul(gel(x,i+1), gel(A,i)));
1049
return z;
1050
}
1051
GEN
1052
ZM_ZX_mul(GEN A, GEN x)
1053
{
1054
long i, l = lg(x)-1;
1055
GEN z;
1056
if (l == 1) return zerocol(nbrows(A));
1057
z = ZC_Z_mul(gel(A,1), gel(x,2));
1058
for (i = 2; i < l ; i++)
1059
if (signe(gel(x,i+1))) z = ZC_add(z, ZC_Z_mul(gel(A,i), gel(x,i+1)));
1060
return z;
1061
}
1062
/* x a t_POL, nf a genuine nf. No garbage collecting. No check. */
1063
GEN
1064
poltobasis(GEN nf, GEN x)
1065
{
1066
GEN d, T = nf_get_pol(nf);
1067
if (varn(x) != varn(T)) pari_err_VAR( "poltobasis", x,T);
1068
if (degpol(x) >= degpol(T)) x = RgX_rem(x,T);
1069
x = Q_remove_denom(x, &d);
1070
if (!RgX_is_ZX(x)) pari_err_TYPE("poltobasis",x);
1071
x = ZM_ZX_mul(nf_get_invzk(nf), x);
1072
if (d) x = RgC_Rg_div(x, d);
1073
return x;
1074
}
1075
1076
GEN
1077
algtobasis(GEN nf, GEN x)
1078
{
1079
pari_sp av;
1080
1081
nf = checknf(nf);
1082
switch(typ(x))
1083
{
1084
case t_POLMOD:
1085
if (!RgX_equal_var(nf_get_pol(nf),gel(x,1)))
1086
pari_err_MODULUS("algtobasis", nf_get_pol(nf),gel(x,1));
1087
x = gel(x,2);
1088
switch(typ(x))
1089
{
1090
case t_INT:
1091
case t_FRAC: return scalarcol(x, nf_get_degree(nf));
1092
case t_POL:
1093
av = avma;
1094
return gerepileupto(av,poltobasis(nf,x));
1095
}
1096
break;
1097
1098
case t_POL:
1099
av = avma;
1100
return gerepileupto(av,poltobasis(nf,x));
1101
1102
case t_COL:
1103
if (!RgV_is_QV(x)) pari_err_TYPE("nfalgtobasis",x);
1104
if (lg(x)-1 != nf_get_degree(nf)) pari_err_DIM("nfalgtobasis");
1105
return gcopy(x);
1106
1107
case t_INT:
1108
case t_FRAC: return scalarcol(x, nf_get_degree(nf));
1109
}
1110
pari_err_TYPE("algtobasis",x);
1111
return NULL; /* LCOV_EXCL_LINE */
1112
}
1113
1114
GEN
1115
rnfbasistoalg(GEN rnf,GEN x)
1116
{
1117
const char *f = "rnfbasistoalg";
1118
long lx, i;
1119
pari_sp av = avma;
1120
GEN z, nf, R, T;
1121
1122
checkrnf(rnf);
1123
nf = rnf_get_nf(rnf);
1124
T = nf_get_pol(nf);
1125
R = QXQX_to_mod_shallow(rnf_get_pol(rnf), T);
1126
switch(typ(x))
1127
{
1128
case t_COL:
1129
z = cgetg_copy(x, &lx);
1130
for (i=1; i<lx; i++)
1131
{
1132
GEN c = nf_to_scalar_or_alg(nf, gel(x,i));
1133
if (typ(c) == t_POL) c = mkpolmod(c,T);
1134
gel(z,i) = c;
1135
}
1136
z = RgV_RgC_mul(gel(rnf_get_zk(rnf),1), z);
1137
return gerepileupto(av, gmodulo(z,R));
1138
1139
case t_POLMOD:
1140
x = polmod_nffix(f, rnf, x, 0);
1141
if (typ(x) != t_POL) break;
1142
retmkpolmod(RgX_copy(x), RgX_copy(R));
1143
case t_POL:
1144
if (varn(x) == varn(T)) { RgX_check_QX(x,f); x = gmodulo(x,T); break; }
1145
if (varn(x) == varn(R))
1146
{
1147
x = RgX_nffix(f,nf_get_pol(nf),x,0);
1148
return gmodulo(x, R);
1149
}
1150
pari_err_VAR(f, x,R);
1151
}
1152
retmkpolmod(scalarpol(x, varn(R)), RgX_copy(R));
1153
}
1154
1155
GEN
1156
matbasistoalg(GEN nf,GEN x)
1157
{
1158
long i, j, li, lx;
1159
GEN z = cgetg_copy(x, &lx);
1160
1161
if (lx == 1) return z;
1162
switch(typ(x))
1163
{
1164
case t_VEC: case t_COL:
1165
for (i=1; i<lx; i++) gel(z,i) = basistoalg(nf, gel(x,i));
1166
return z;
1167
case t_MAT: break;
1168
default: pari_err_TYPE("matbasistoalg",x);
1169
}
1170
li = lgcols(x);
1171
for (j=1; j<lx; j++)
1172
{
1173
GEN c = cgetg(li,t_COL), xj = gel(x,j);
1174
gel(z,j) = c;
1175
for (i=1; i<li; i++) gel(c,i) = basistoalg(nf, gel(xj,i));
1176
}
1177
return z;
1178
}
1179
1180
GEN
1181
matalgtobasis(GEN nf,GEN x)
1182
{
1183
long i, j, li, lx;
1184
GEN z = cgetg_copy(x, &lx);
1185
1186
if (lx == 1) return z;
1187
switch(typ(x))
1188
{
1189
case t_VEC: case t_COL:
1190
for (i=1; i<lx; i++) gel(z,i) = algtobasis(nf, gel(x,i));
1191
return z;
1192
case t_MAT: break;
1193
default: pari_err_TYPE("matalgtobasis",x);
1194
}
1195
li = lgcols(x);
1196
for (j=1; j<lx; j++)
1197
{
1198
GEN c = cgetg(li,t_COL), xj = gel(x,j);
1199
gel(z,j) = c;
1200
for (i=1; i<li; i++) gel(c,i) = algtobasis(nf, gel(xj,i));
1201
}
1202
return z;
1203
}
1204
GEN
1205
RgM_to_nfM(GEN nf,GEN x)
1206
{
1207
long i, j, li, lx;
1208
GEN z = cgetg_copy(x, &lx);
1209
1210
if (lx == 1) return z;
1211
li = lgcols(x);
1212
for (j=1; j<lx; j++)
1213
{
1214
GEN c = cgetg(li,t_COL), xj = gel(x,j);
1215
gel(z,j) = c;
1216
for (i=1; i<li; i++) gel(c,i) = nf_to_scalar_or_basis(nf, gel(xj,i));
1217
}
1218
return z;
1219
}
1220
GEN
1221
RgC_to_nfC(GEN nf, GEN x)
1222
{ pari_APPLY_type(t_COL, nf_to_scalar_or_basis(nf, gel(x,i))) }
1223
1224
/* x a t_POLMOD, supposedly in rnf = K[z]/(T), K = Q[y]/(Tnf) */
1225
GEN
1226
polmod_nffix(const char *f, GEN rnf, GEN x, int lift)
1227
{ return polmod_nffix2(f, rnf_get_nfpol(rnf), rnf_get_pol(rnf), x,lift); }
1228
GEN
1229
polmod_nffix2(const char *f, GEN T, GEN R, GEN x, int lift)
1230
{
1231
if (RgX_equal_var(gel(x,1), R))
1232
{
1233
x = gel(x,2);
1234
if (typ(x) == t_POL && varn(x) == varn(R))
1235
{
1236
x = RgX_nffix(f, T, x, lift);
1237
switch(lg(x))
1238
{
1239
case 2: return gen_0;
1240
case 3: return gel(x,2);
1241
}
1242
return x;
1243
}
1244
}
1245
return Rg_nffix(f, T, x, lift);
1246
}
1247
GEN
1248
rnfalgtobasis(GEN rnf,GEN x)
1249
{
1250
const char *f = "rnfalgtobasis";
1251
pari_sp av = avma;
1252
GEN T, R;
1253
1254
checkrnf(rnf);
1255
R = rnf_get_pol(rnf);
1256
T = rnf_get_nfpol(rnf);
1257
switch(typ(x))
1258
{
1259
case t_COL:
1260
if (lg(x)-1 != rnf_get_degree(rnf)) pari_err_DIM(f);
1261
x = RgV_nffix(f, T, x, 0);
1262
return gerepilecopy(av, x);
1263
1264
case t_POLMOD:
1265
x = polmod_nffix(f, rnf, x, 0);
1266
if (typ(x) != t_POL) break;
1267
return gerepileupto(av, RgM_RgX_mul(rnf_get_invzk(rnf), x));
1268
case t_POL:
1269
if (varn(x) == varn(T))
1270
{
1271
RgX_check_QX(x,f);
1272
if (degpol(x) >= degpol(T)) x = RgX_rem(x,T);
1273
x = mkpolmod(x,T); break;
1274
}
1275
x = RgX_nffix(f, T, x, 0);
1276
if (degpol(x) >= degpol(R)) x = RgX_rem(x, R);
1277
return gerepileupto(av, RgM_RgX_mul(rnf_get_invzk(rnf), x));
1278
}
1279
return gerepileupto(av, scalarcol(x, rnf_get_degree(rnf)));
1280
}
1281
1282
/* Given a and b in nf, gives an algebraic integer y in nf such that a-b.y
1283
* is "small" */
1284
GEN
1285
nfdiveuc(GEN nf, GEN a, GEN b)
1286
{
1287
pari_sp av = avma;
1288
a = nfdiv(nf,a,b);
1289
return gerepileupto(av, ground(a));
1290
}
1291
1292
/* Given a and b in nf, gives a "small" algebraic integer r in nf
1293
* of the form a-b.y */
1294
GEN
1295
nfmod(GEN nf, GEN a, GEN b)
1296
{
1297
pari_sp av = avma;
1298
GEN p1 = gneg_i(nfmul(nf,b,ground(nfdiv(nf,a,b))));
1299
return gerepileupto(av, nfadd(nf,a,p1));
1300
}
1301
1302
/* Given a and b in nf, gives a two-component vector [y,r] in nf such
1303
* that r=a-b.y is "small". */
1304
GEN
1305
nfdivrem(GEN nf, GEN a, GEN b)
1306
{
1307
pari_sp av = avma;
1308
GEN p1,z, y = ground(nfdiv(nf,a,b));
1309
1310
p1 = gneg_i(nfmul(nf,b,y));
1311
z = cgetg(3,t_VEC);
1312
gel(z,1) = gcopy(y);
1313
gel(z,2) = nfadd(nf,a,p1); return gerepileupto(av, z);
1314
}
1315
1316
/*************************************************************************/
1317
/** **/
1318
/** LOGARITHMIC EMBEDDINGS **/
1319
/** **/
1320
/*************************************************************************/
1321
1322
static int
1323
low_prec(GEN x)
1324
{
1325
switch(typ(x))
1326
{
1327
case t_INT: return !signe(x);
1328
case t_REAL: return !signe(x) || realprec(x) <= DEFAULTPREC;
1329
default: return 0;
1330
}
1331
}
1332
1333
static GEN
1334
cxlog_1(GEN nf) { return zerocol(lg(nf_get_roots(nf))-1); }
1335
static GEN
1336
cxlog_m1(GEN nf, long prec)
1337
{
1338
long i, l = lg(nf_get_roots(nf)), r1 = nf_get_r1(nf);
1339
GEN v = cgetg(l, t_COL), p, P;
1340
p = mppi(prec); P = mkcomplex(gen_0, p);
1341
for (i = 1; i <= r1; i++) gel(v,i) = P; /* IPi*/
1342
if (i < l) P = gmul2n(P,1);
1343
for ( ; i < l; i++) gel(v,i) = P; /* 2IPi */
1344
return v;
1345
}
1346
static GEN
1347
famat_cxlog(GEN nf, GEN fa, long prec)
1348
{
1349
GEN g, e, y = NULL;
1350
long i, l;
1351
1352
if (typ(fa) != t_MAT) pari_err_TYPE("famat_cxlog",fa);
1353
if (lg(fa) == 1) return cxlog_1(nf);
1354
g = gel(fa,1);
1355
e = gel(fa,2); l = lg(e);
1356
for (i = 1; i < l; i++)
1357
{
1358
GEN t, x = nf_to_scalar_or_basis(nf, gel(g,i));
1359
/* multiplicative arch would be better (save logs), but exponents overflow
1360
* [ could keep track of expo separately, but not worth it ] */
1361
t = nf_cxlog(nf,x,prec); if (!t) return NULL;
1362
if (gel(t,1) == gen_0) continue; /* positive rational */
1363
t = RgC_Rg_mul(t, gel(e,i));
1364
y = y? RgV_add(y,t): t;
1365
}
1366
return y ? y: cxlog_1(nf);
1367
}
1368
/* Archimedean components: [e_i Log( sigma_i(X) )], where X = primpart(x),
1369
* and e_i = 1 (resp 2.) for i <= R1 (resp. > R1) */
1370
GEN
1371
nf_cxlog(GEN nf, GEN x, long prec)
1372
{
1373
long i, l, r1;
1374
GEN v;
1375
if (typ(x) == t_MAT) return famat_cxlog(nf,x,prec);
1376
x = nf_to_scalar_or_basis(nf,x);
1377
if (typ(x) != t_COL) return gsigne(x) > 0? cxlog_1(nf): cxlog_m1(nf, prec);
1378
x = RgM_RgC_mul(nf_get_M(nf), Q_primpart(x));
1379
l = lg(x); r1 = nf_get_r1(nf);
1380
for (i = 1; i <= r1; i++)
1381
if (low_prec(gel(x,i))) return NULL;
1382
for ( ; i < l; i++)
1383
if (low_prec(gnorm(gel(x,i)))) return NULL;
1384
v = cgetg(l,t_COL);
1385
for (i = 1; i <= r1; i++) gel(v,i) = glog(gel(x,i),prec);
1386
for ( ; i < l; i++) gel(v,i) = gmul2n(glog(gel(x,i),prec),1);
1387
return v;
1388
}
1389
GEN
1390
nfV_cxlog(GEN nf, GEN x, long prec)
1391
{
1392
long i, l;
1393
GEN v = cgetg_copy(x, &l);
1394
for (i = 1; i < l; i++)
1395
if (!(gel(v,i) = nf_cxlog(nf, gel(x,i), prec))) return NULL;
1396
return v;
1397
}
1398
1399
static GEN
1400
scalar_logembed(GEN nf, GEN u, GEN *emb)
1401
{
1402
GEN v, logu;
1403
long i, s = signe(u), RU = lg(nf_get_roots(nf))-1, R1 = nf_get_r1(nf);
1404
1405
if (!s) pari_err_DOMAIN("nflogembed","argument","=",gen_0,u);
1406
v = cgetg(RU+1, t_COL); logu = logr_abs(u);
1407
for (i = 1; i <= R1; i++) gel(v,i) = logu;
1408
if (i <= RU)
1409
{
1410
GEN logu2 = shiftr(logu,1);
1411
for ( ; i <= RU; i++) gel(v,i) = logu2;
1412
}
1413
if (emb) *emb = const_col(RU, u);
1414
return v;
1415
}
1416
1417
static GEN
1418
famat_logembed(GEN nf,GEN x,GEN *emb,long prec)
1419
{
1420
GEN A, M, T, a, t, g = gel(x,1), e = gel(x,2);
1421
long i, l = lg(e);
1422
1423
if (l == 1) return scalar_logembed(nf, real_1(prec), emb);
1424
A = NULL; T = emb? cgetg(l, t_COL): NULL;
1425
if (emb) *emb = M = mkmat2(T, e);
1426
for (i = 1; i < l; i++)
1427
{
1428
a = nflogembed(nf, gel(g,i), &t, prec);
1429
if (!a) return NULL;
1430
a = RgC_Rg_mul(a, gel(e,i));
1431
A = A? RgC_add(A, a): a;
1432
if (emb) gel(T,i) = t;
1433
}
1434
return A;
1435
}
1436
1437
/* Get archimedean components: [e_i log( | sigma_i(x) | )], with e_i = 1
1438
* (resp 2.) for i <= R1 (resp. > R1) and set emb to the embeddings of x.
1439
* Return NULL if precision problem */
1440
GEN
1441
nflogembed(GEN nf, GEN x, GEN *emb, long prec)
1442
{
1443
long i, l, r1;
1444
GEN v, t;
1445
1446
if (typ(x) == t_MAT) return famat_logembed(nf,x,emb,prec);
1447
x = nf_to_scalar_or_basis(nf,x);
1448
if (typ(x) != t_COL) return scalar_logembed(nf, gtofp(x,prec), emb);
1449
x = RgM_RgC_mul(nf_get_M(nf), x);
1450
l = lg(x); r1 = nf_get_r1(nf); v = cgetg(l,t_COL);
1451
for (i = 1; i <= r1; i++)
1452
{
1453
t = gabs(gel(x,i),prec); if (low_prec(t)) return NULL;
1454
gel(v,i) = glog(t,prec);
1455
}
1456
for ( ; i < l; i++)
1457
{
1458
t = gnorm(gel(x,i)); if (low_prec(t)) return NULL;
1459
gel(v,i) = glog(t,prec);
1460
}
1461
if (emb) *emb = x;
1462
return v;
1463
}
1464
1465
/*************************************************************************/
1466
/** **/
1467
/** REAL EMBEDDINGS **/
1468
/** **/
1469
/*************************************************************************/
1470
static GEN
1471
sarch_get_cyc(GEN sarch) { return gel(sarch,1); }
1472
static GEN
1473
sarch_get_archp(GEN sarch) { return gel(sarch,2); }
1474
static GEN
1475
sarch_get_MI(GEN sarch) { return gel(sarch,3); }
1476
static GEN
1477
sarch_get_lambda(GEN sarch) { return gel(sarch,4); }
1478
static GEN
1479
sarch_get_F(GEN sarch) { return gel(sarch,5); }
1480
1481
/* x not a scalar, true nf, return number of positive roots of char_x */
1482
static long
1483
num_positive(GEN nf, GEN x)
1484
{
1485
GEN T = nf_get_pol(nf), B, charx;
1486
long dnf, vnf, N;
1487
x = nf_to_scalar_or_alg(nf, x); /* not a scalar */
1488
charx = ZXQ_charpoly(x, T, 0);
1489
charx = ZX_radical(charx);
1490
N = degpol(T) / degpol(charx);
1491
/* real places are unramified ? */
1492
if (N == 1 || ZX_sturm(charx) * N == nf_get_r1(nf))
1493
return ZX_sturmpart(charx, mkvec2(gen_0,mkoo())) * N;
1494
/* painful case, multiply by random square until primitive */
1495
dnf = nf_get_degree(nf);
1496
vnf = varn(T);
1497
B = int2n(10);
1498
for(;;)
1499
{
1500
GEN y = RgXQ_sqr(random_FpX(dnf, vnf, B), T);
1501
y = RgXQ_mul(x, y, T);
1502
charx = ZXQ_charpoly(y, T, 0);
1503
if (ZX_is_squarefree(charx))
1504
return ZX_sturmpart(charx, mkvec2(gen_0,mkoo())) * N;
1505
}
1506
}
1507
1508
/* x a QC: return sigma_k(x) where 1 <= k <= r1+r2; correct but inefficient
1509
* if x in Q. M = nf_get_M(nf) */
1510
static GEN
1511
nfembed_i(GEN M, GEN x, long k)
1512
{
1513
long i, l = lg(M);
1514
GEN z = gel(x,1);
1515
for (i = 2; i < l; i++) z = gadd(z, gmul(gcoeff(M,k,i), gel(x,i)));
1516
return z;
1517
}
1518
GEN
1519
nfembed(GEN nf, GEN x, long k)
1520
{
1521
pari_sp av = avma;
1522
nf = checknf(nf);
1523
x = nf_to_scalar_or_basis(nf,x);
1524
if (typ(x) != t_COL) return gerepilecopy(av, x);
1525
return gerepileupto(av, nfembed_i(nf_get_M(nf),x,k));
1526
}
1527
1528
/* x a ZC */
1529
static GEN
1530
zk_embed(GEN M, GEN x, long k)
1531
{
1532
long i, l = lg(x);
1533
GEN z = gel(x,1); /* times M[k,1], which is 1 */
1534
for (i = 2; i < l; i++) z = mpadd(z, mpmul(gcoeff(M,k,i), gel(x,i)));
1535
return z;
1536
}
1537
1538
/* Given floating point approximation z of sigma_k(x), decide its sign
1539
* [0/+, 1/- and -1 for FAIL] */
1540
static long
1541
eval_sign_embed(GEN z)
1542
{ /* dubious, fail */
1543
if (typ(z) == t_REAL && realprec(z) <= LOWDEFAULTPREC) return -1;
1544
return (signe(z) < 1)? 1: 0;
1545
}
1546
/* return v such that (-1)^v = sign(sigma_k(x)), x primitive ZC */
1547
static long
1548
eval_sign(GEN M, GEN x, long k)
1549
{ return eval_sign_embed( zk_embed(M, x, k) ); }
1550
1551
/* check that signs[i..#signs] == s; signs = NULL encodes "totally positive" */
1552
static int
1553
oksigns(long l, GEN signs, long i, long s)
1554
{
1555
if (!signs) return s == 0;
1556
for (; i < l; i++)
1557
if (signs[i] != s) return 0;
1558
return 1;
1559
}
1560
/* check that signs[i] = s and signs[i+1..#signs] = 1-s */
1561
static int
1562
oksigns2(long l, GEN signs, long i, long s)
1563
{
1564
if (!signs) return s == 0 && i == l-1;
1565
return signs[i] == s && oksigns(l, signs, i+1, 1-s);
1566
}
1567
1568
/* true nf, x a ZC (primitive for efficiency), embx its embeddings or NULL */
1569
static int
1570
nfchecksigns_i(GEN nf, GEN x, GEN embx, GEN signs, GEN archp)
1571
{
1572
long l = lg(archp), i;
1573
GEN M = nf_get_M(nf), sarch = NULL;
1574
long np = -1;
1575
for (i = 1; i < l; i++)
1576
{
1577
long s;
1578
if (embx)
1579
s = eval_sign_embed(gel(embx,i));
1580
else
1581
s = eval_sign(M, x, archp[i]);
1582
/* 0 / + or 1 / -; -1 for FAIL */
1583
if (s < 0) /* failure */
1584
{
1585
long ni, r1 = nf_get_r1(nf);
1586
GEN xi;
1587
if (np < 0)
1588
{
1589
np = num_positive(nf, x);
1590
if (np == 0) return oksigns(l, signs, i, 1);
1591
if (np == r1) return oksigns(l, signs, i, 0);
1592
sarch = nfarchstar(nf, NULL, identity_perm(r1));
1593
}
1594
xi = set_sign_mod_divisor(nf, vecsmall_ei(r1, archp[i]), gen_1, sarch);
1595
xi = Q_primpart(xi);
1596
ni = num_positive(nf, nfmuli(nf,x,xi));
1597
if (ni == 0) return oksigns2(l, signs, i, 0);
1598
if (ni == r1) return oksigns2(l, signs, i, 1);
1599
s = ni < np? 0: 1;
1600
}
1601
if (s != (signs? signs[i]: 0)) return 0;
1602
}
1603
return 1;
1604
}
1605
static void
1606
pl_convert(GEN pl, GEN *psigns, GEN *parchp)
1607
{
1608
long i, j, l = lg(pl);
1609
GEN signs = cgetg(l, t_VECSMALL);
1610
GEN archp = cgetg(l, t_VECSMALL);
1611
for (i = j = 1; i < l; i++)
1612
{
1613
if (!pl[i]) continue;
1614
archp[j] = i;
1615
signs[j] = (pl[i] < 0)? 1: 0;
1616
j++;
1617
}
1618
setlg(archp, j); *parchp = archp;
1619
setlg(signs, j); *psigns = signs;
1620
}
1621
/* pl : requested signs for real embeddings, 0 = no sign constraint */
1622
int
1623
nfchecksigns(GEN nf, GEN x, GEN pl)
1624
{
1625
pari_sp av = avma;
1626
GEN signs, archp;
1627
nf = checknf(nf);
1628
x = nf_to_scalar_or_basis(nf,x);
1629
if (typ(x) != t_COL)
1630
{
1631
long i, l = lg(pl), s = gsigne(x);
1632
for (i = 1; i < l; i++)
1633
if (pl[i] && pl[i] != s) return gc_bool(av,0);
1634
return gc_bool(av,1);
1635
}
1636
pl_convert(pl, &signs, &archp);
1637
return gc_bool(av, nfchecksigns_i(nf, x, NULL, signs, archp));
1638
}
1639
1640
/* signs = NULL: totally positive, else sign[i] = 0 (+) or 1 (-) */
1641
static GEN
1642
get_C(GEN lambda, long l, GEN signs)
1643
{
1644
long i;
1645
GEN C, mlambda;
1646
if (!signs) return const_vec(l-1, lambda);
1647
C = cgetg(l, t_COL); mlambda = gneg(lambda);
1648
for (i = 1; i < l; i++) gel(C,i) = signs[i]? mlambda: lambda;
1649
return C;
1650
}
1651
/* signs = NULL: totally positive at archp */
1652
static GEN
1653
nfsetsigns(GEN nf, GEN signs, GEN x, GEN sarch)
1654
{
1655
long i, l = lg(sarch_get_archp(sarch));
1656
GEN ex;
1657
/* Is signature already correct ? */
1658
if (typ(x) != t_COL)
1659
{
1660
long s = gsigne(x);
1661
if (!s) i = 1;
1662
else if (!signs)
1663
i = (s < 0)? 1: l;
1664
else
1665
{
1666
s = s < 0? 1: 0;
1667
for (i = 1; i < l; i++)
1668
if (signs[i] != s) break;
1669
}
1670
ex = (i < l)? const_col(l-1, x): NULL;
1671
}
1672
else
1673
{
1674
pari_sp av = avma;
1675
GEN cex, M = nf_get_M(nf), archp = sarch_get_archp(sarch);
1676
GEN xp = Q_primitive_part(x,&cex);
1677
ex = cgetg(l,t_COL);
1678
for (i = 1; i < l; i++) gel(ex,i) = zk_embed(M,xp,archp[i]);
1679
if (nfchecksigns_i(nf, xp, ex, signs, archp)) { ex = NULL; set_avma(av); }
1680
else if (cex) ex = RgC_Rg_mul(ex, cex); /* put back content */
1681
}
1682
if (ex)
1683
{ /* If no, fix it */
1684
GEN MI = sarch_get_MI(sarch), F = sarch_get_F(sarch);
1685
GEN lambda = sarch_get_lambda(sarch);
1686
GEN t = RgC_sub(get_C(lambda, l, signs), ex);
1687
long e;
1688
t = grndtoi(RgM_RgC_mul(MI,t), &e);
1689
if (lg(F) != 1) t = ZM_ZC_mul(F, t);
1690
x = typ(x) == t_COL? RgC_add(t, x): RgC_Rg_add(t, x);
1691
}
1692
return x;
1693
}
1694
/* - sarch = nfarchstar(nf, F);
1695
* - x encodes a vector of signs at arch.archp: either a t_VECSMALL
1696
* (vector of signs as {0,1}-vector), NULL (totally positive at archp),
1697
* or a nonzero number field element (replaced by its signature at archp);
1698
* - y is a nonzero number field element
1699
* Return z = y (mod F) with signs(y, archp) = signs(x) (a {0,1}-vector) */
1700
GEN
1701
set_sign_mod_divisor(GEN nf, GEN x, GEN y, GEN sarch)
1702
{
1703
GEN archp = sarch_get_archp(sarch);
1704
if (lg(archp) == 1) return y;
1705
nf = checknf(nf);
1706
if (x && typ(x) != t_VECSMALL) x = nfsign_arch(nf, x, archp);
1707
y = nf_to_scalar_or_basis(nf,y);
1708
return nfsetsigns(nf, x, y, sarch);
1709
}
1710
1711
static GEN
1712
setsigns_init(GEN nf, GEN archp, GEN F, GEN DATA)
1713
{
1714
GEN lambda, Mr = rowpermute(nf_get_M(nf), archp), MI = F? RgM_mul(Mr,F): Mr;
1715
lambda = gmul2n(matrixnorm(MI,DEFAULTPREC), -1);
1716
if (typ(lambda) != t_REAL) lambda = gmul(lambda, sstoQ(1001,1000));
1717
if (lg(archp) < lg(MI))
1718
{
1719
GEN perm = gel(indexrank(MI), 2);
1720
if (!F) F = matid(nf_get_degree(nf));
1721
MI = vecpermute(MI, perm);
1722
F = vecpermute(F, perm);
1723
}
1724
if (!F) F = cgetg(1,t_MAT);
1725
MI = RgM_inv(MI);
1726
return mkvec5(DATA, archp, MI, lambda, F);
1727
}
1728
/* F nonzero integral ideal in HNF (or NULL: Z_K), compute elements in 1+F
1729
* whose sign matrix at archp is identity; archp in 'indices' format */
1730
GEN
1731
nfarchstar(GEN nf, GEN F, GEN archp)
1732
{
1733
long nba = lg(archp) - 1;
1734
if (!nba) return mkvec2(cgetg(1,t_VEC), archp);
1735
if (F && equali1(gcoeff(F,1,1))) F = NULL;
1736
if (F) F = idealpseudored(F, nf_get_roundG(nf));
1737
return setsigns_init(nf, archp, F, const_vec(nba, gen_2));
1738
}
1739
1740
/*************************************************************************/
1741
/** **/
1742
/** IDEALCHINESE **/
1743
/** **/
1744
/*************************************************************************/
1745
static int
1746
isprfact(GEN x)
1747
{
1748
long i, l;
1749
GEN L, E;
1750
if (typ(x) != t_MAT || lg(x) != 3) return 0;
1751
L = gel(x,1); l = lg(L);
1752
E = gel(x,2);
1753
for(i=1; i<l; i++)
1754
{
1755
checkprid(gel(L,i));
1756
if (typ(gel(E,i)) != t_INT) return 0;
1757
}
1758
return 1;
1759
}
1760
1761
/* initialize projectors mod pr[i]^e[i] for idealchinese */
1762
static GEN
1763
pr_init(GEN nf, GEN fa, GEN w, GEN dw)
1764
{
1765
GEN U, E, F, L = gel(fa,1), E0 = gel(fa,2);
1766
long i, r = lg(L);
1767
1768
if (w && lg(w) != r) pari_err_TYPE("idealchinese", w);
1769
if (r == 1 && !dw) return cgetg(1,t_VEC);
1770
E = leafcopy(E0); /* do not destroy fa[2] */
1771
for (i = 1; i < r; i++)
1772
if (signe(gel(E,i)) < 0) gel(E,i) = gen_0;
1773
F = factorbackprime(nf, L, E);
1774
if (dw)
1775
{
1776
F = ZM_Z_mul(F, dw);
1777
for (i = 1; i < r; i++)
1778
{
1779
GEN pr = gel(L,i);
1780
long e = itos(gel(E0,i)), v = idealval(nf, dw, pr);
1781
if (e >= 0)
1782
gel(E,i) = addiu(gel(E,i), v);
1783
else if (v + e <= 0)
1784
F = idealmulpowprime(nf, F, pr, stoi(-v)); /* coprime to pr */
1785
else
1786
{
1787
F = idealmulpowprime(nf, F, pr, stoi(e));
1788
gel(E,i) = stoi(v + e);
1789
}
1790
}
1791
}
1792
U = cgetg(r, t_VEC);
1793
for (i = 1; i < r; i++)
1794
{
1795
GEN u;
1796
if (w && gequal0(gel(w,i))) u = gen_0; /* unused */
1797
else
1798
{
1799
GEN pr = gel(L,i), e = gel(E,i), t;
1800
t = idealdivpowprime(nf,F, pr, e);
1801
u = hnfmerge_get_1(t, idealpow(nf, pr, e));
1802
if (!u) pari_err_COPRIME("idealchinese", t,pr);
1803
}
1804
gel(U,i) = u;
1805
}
1806
F = idealpseudored(F, nf_get_roundG(nf));
1807
return mkvec2(F, U);
1808
}
1809
1810
static GEN
1811
pl_normalize(GEN nf, GEN pl)
1812
{
1813
const char *fun = "idealchinese";
1814
if (lg(pl)-1 != nf_get_r1(nf)) pari_err_TYPE(fun,pl);
1815
switch(typ(pl))
1816
{
1817
case t_VEC: RgV_check_ZV(pl,fun); pl = ZV_to_zv(pl);
1818
/* fall through */
1819
case t_VECSMALL: break;
1820
default: pari_err_TYPE(fun,pl);
1821
}
1822
return pl;
1823
}
1824
1825
static int
1826
is_chineseinit(GEN x)
1827
{
1828
GEN fa, pl;
1829
long l;
1830
if (typ(x) != t_VEC || lg(x)!=3) return 0;
1831
fa = gel(x,1);
1832
pl = gel(x,2);
1833
if (typ(fa) != t_VEC || typ(pl) != t_VEC) return 0;
1834
l = lg(fa);
1835
if (l != 1)
1836
{
1837
if (l != 3 || typ(gel(fa,1)) != t_MAT || typ(gel(fa,2)) != t_VEC)
1838
return 0;
1839
}
1840
l = lg(pl);
1841
if (l != 1)
1842
{
1843
if (l != 6 || typ(gel(pl,3)) != t_MAT || typ(gel(pl,1)) != t_VECSMALL
1844
|| typ(gel(pl,2)) != t_VECSMALL)
1845
return 0;
1846
}
1847
return 1;
1848
}
1849
1850
/* nf a true 'nf' */
1851
static GEN
1852
chineseinit_i(GEN nf, GEN fa, GEN w, GEN dw)
1853
{
1854
const char *fun = "idealchineseinit";
1855
GEN archp = NULL, pl = NULL;
1856
switch(typ(fa))
1857
{
1858
case t_VEC:
1859
if (is_chineseinit(fa))
1860
{
1861
if (dw) pari_err_DOMAIN(fun, "denom(y)", "!=", gen_1, w);
1862
return fa;
1863
}
1864
if (lg(fa) != 3) pari_err_TYPE(fun, fa);
1865
/* of the form [x,s] */
1866
pl = pl_normalize(nf, gel(fa,2));
1867
fa = gel(fa,1);
1868
archp = vecsmall01_to_indices(pl);
1869
/* keep pr_init, reset pl */
1870
if (is_chineseinit(fa)) { fa = gel(fa,1); break; }
1871
/* fall through */
1872
case t_MAT: /* factorization? */
1873
if (isprfact(fa)) { fa = pr_init(nf, fa, w, dw); break; }
1874
default: pari_err_TYPE(fun,fa);
1875
}
1876
1877
if (!pl) pl = cgetg(1,t_VEC);
1878
else
1879
{
1880
long r = lg(archp);
1881
if (r == 1) pl = cgetg(1, t_VEC);
1882
else
1883
{
1884
GEN F = (lg(fa) == 1)? NULL: gel(fa,1), signs = cgetg(r, t_VECSMALL);
1885
long i;
1886
for (i = 1; i < r; i++) signs[i] = (pl[archp[i]] < 0)? 1: 0;
1887
pl = setsigns_init(nf, archp, F, signs);
1888
}
1889
}
1890
return mkvec2(fa, pl);
1891
}
1892
1893
/* Given a prime ideal factorization x, possibly with 0 or negative exponents,
1894
* and a vector w of elements of nf, gives b such that
1895
* v_p(b-w_p)>=v_p(x) for all prime ideals p in the ideal factorization
1896
* and v_p(b)>=0 for all other p, using the standard proof given in GTM 138. */
1897
GEN
1898
idealchinese(GEN nf, GEN x, GEN w)
1899
{
1900
const char *fun = "idealchinese";
1901
pari_sp av = avma;
1902
GEN x1, x2, s, dw, F;
1903
1904
nf = checknf(nf);
1905
if (!w) return gerepilecopy(av, chineseinit_i(nf,x,NULL,NULL));
1906
1907
if (typ(w) != t_VEC) pari_err_TYPE(fun,w);
1908
w = Q_remove_denom(matalgtobasis(nf,w), &dw);
1909
if (!is_chineseinit(x)) x = chineseinit_i(nf,x,w,dw);
1910
/* x is a 'chineseinit' */
1911
x1 = gel(x,1); s = NULL;
1912
x2 = gel(x,2);
1913
if (lg(x1) == 1) F = NULL;
1914
else
1915
{
1916
GEN U = gel(x1,2);
1917
long i, r = lg(w);
1918
F = gel(x1,1);
1919
for (i=1; i<r; i++)
1920
if (!gequal0(gel(w,i)))
1921
{
1922
GEN t = nfmuli(nf, gel(U,i), gel(w,i));
1923
s = s? ZC_add(s,t): t;
1924
}
1925
if (s) s = ZC_reducemodmatrix(s, F);
1926
}
1927
if (lg(x2) != 1) s = nfsetsigns(nf, gel(x2,1), s? s: gen_0, x2);
1928
if (!s) { s = zerocol(nf_get_degree(nf)); dw = NULL; }
1929
1930
if (dw) s = RgC_Rg_div(s,dw);
1931
return gerepileupto(av, s);
1932
}
1933
1934
/*************************************************************************/
1935
/** **/
1936
/** (Z_K/I)^* **/
1937
/** **/
1938
/*************************************************************************/
1939
GEN
1940
vecsmall01_to_indices(GEN v)
1941
{
1942
long i, k, l = lg(v);
1943
GEN p = new_chunk(l) + l;
1944
for (k=1, i=l-1; i; i--)
1945
if (v[i]) { *--p = i; k++; }
1946
*--p = evallg(k) | evaltyp(t_VECSMALL);
1947
set_avma((pari_sp)p); return p;
1948
}
1949
GEN
1950
vec01_to_indices(GEN v)
1951
{
1952
long i, k, l;
1953
GEN p;
1954
1955
switch (typ(v))
1956
{
1957
case t_VECSMALL: return v;
1958
case t_VEC: break;
1959
default: pari_err_TYPE("vec01_to_indices",v);
1960
}
1961
l = lg(v);
1962
p = new_chunk(l) + l;
1963
for (k=1, i=l-1; i; i--)
1964
if (signe(gel(v,i))) { *--p = i; k++; }
1965
*--p = evallg(k) | evaltyp(t_VECSMALL);
1966
set_avma((pari_sp)p); return p;
1967
}
1968
GEN
1969
indices_to_vec01(GEN p, long r)
1970
{
1971
long i, l = lg(p);
1972
GEN v = zerovec(r);
1973
for (i = 1; i < l; i++) gel(v, p[i]) = gen_1;
1974
return v;
1975
}
1976
1977
/* return (column) vector of R1 signatures of x (0 or 1) */
1978
GEN
1979
nfsign_arch(GEN nf, GEN x, GEN arch)
1980
{
1981
GEN sarch, M, V, archp = vec01_to_indices(arch);
1982
long i, s, np, n = lg(archp)-1;
1983
pari_sp av;
1984
1985
if (!n) return cgetg(1,t_VECSMALL);
1986
nf = checknf(nf);
1987
if (typ(x) == t_MAT)
1988
{ /* factorisation */
1989
GEN g = gel(x,1), e = gel(x,2);
1990
long l = lg(g);
1991
V = zero_zv(n);
1992
for (i = 1; i < l; i++)
1993
if (mpodd(gel(e,i)))
1994
Flv_add_inplace(V, nfsign_arch(nf,gel(g,i),archp), 2);
1995
set_avma((pari_sp)V); return V;
1996
}
1997
av = avma; V = cgetg(n+1,t_VECSMALL);
1998
x = nf_to_scalar_or_basis(nf, x);
1999
switch(typ(x))
2000
{
2001
case t_INT:
2002
s = signe(x);
2003
if (!s) pari_err_DOMAIN("nfsign_arch","element","=",gen_0,x);
2004
set_avma(av); return const_vecsmall(n, (s < 0)? 1: 0);
2005
case t_FRAC:
2006
s = signe(gel(x,1));
2007
set_avma(av); return const_vecsmall(n, (s < 0)? 1: 0);
2008
}
2009
x = Q_primpart(x); M = nf_get_M(nf); sarch = NULL; np = -1;
2010
for (i = 1; i <= n; i++)
2011
{
2012
long s = eval_sign(M, x, archp[i]);
2013
if (s < 0) /* failure */
2014
{
2015
long ni, r1 = nf_get_r1(nf);
2016
GEN xi;
2017
if (np < 0)
2018
{
2019
np = num_positive(nf, x);
2020
if (np == 0) { set_avma(av); return const_vecsmall(n, 1); }
2021
if (np == r1){ set_avma(av); return const_vecsmall(n, 0); }
2022
sarch = nfarchstar(nf, NULL, identity_perm(r1));
2023
}
2024
xi = set_sign_mod_divisor(nf, vecsmall_ei(r1, archp[i]), gen_1, sarch);
2025
xi = Q_primpart(xi);
2026
ni = num_positive(nf, nfmuli(nf,x,xi));
2027
if (ni == 0) { set_avma(av); V = const_vecsmall(n, 1); V[i] = 0; return V; }
2028
if (ni == r1){ set_avma(av); V = const_vecsmall(n, 0); V[i] = 1; return V; }
2029
s = ni < np? 0: 1;
2030
}
2031
V[i] = s;
2032
}
2033
set_avma((pari_sp)V); return V;
2034
}
2035
static void
2036
chk_ind(const char *s, long i, long r1)
2037
{
2038
if (i <= 0) pari_err_DOMAIN(s, "index", "<=", gen_0, stoi(i));
2039
if (i > r1) pari_err_DOMAIN(s, "index", ">", utoi(r1), utoi(i));
2040
}
2041
static GEN
2042
parse_embed(GEN ind, long r, const char *f)
2043
{
2044
long l, i;
2045
if (!ind) return identity_perm(r);
2046
switch(typ(ind))
2047
{
2048
case t_INT: case t_VEC: case t_COL: ind = gtovecsmall(ind); break;
2049
case t_VECSMALL: break;
2050
default: pari_err_TYPE(f, ind);
2051
}
2052
l = lg(ind);
2053
for (i = 1; i < l; i++) chk_ind(f, ind[i], r);
2054
return ind;
2055
}
2056
GEN
2057
nfeltsign(GEN nf, GEN x, GEN ind0)
2058
{
2059
pari_sp av = avma;
2060
long i, l;
2061
GEN v, ind;
2062
nf = checknf(nf);
2063
ind = parse_embed(ind0, nf_get_r1(nf), "nfeltsign");
2064
l = lg(ind);
2065
if (is_rational_t(typ(x)))
2066
{ /* nfsign_arch would test this, but avoid converting t_VECSMALL -> t_VEC */
2067
GEN s;
2068
switch(gsigne(x))
2069
{
2070
case -1:s = gen_m1; break;
2071
case 1: s = gen_1; break;
2072
default: s = gen_0; break;
2073
}
2074
set_avma(av);
2075
return (ind0 && typ(ind0) == t_INT)? s: const_vec(l-1, s);
2076
}
2077
v = nfsign_arch(nf, x, ind);
2078
if (ind0 && typ(ind0) == t_INT) { set_avma(av); return v[1]? gen_m1: gen_1; }
2079
settyp(v, t_VEC);
2080
for (i = 1; i < l; i++) gel(v,i) = v[i]? gen_m1: gen_1;
2081
return gerepileupto(av, v);
2082
}
2083
2084
GEN
2085
nfeltembed(GEN nf, GEN x, GEN ind0, long prec0)
2086
{
2087
pari_sp av = avma;
2088
long i, e, l, r1, r2, prec, prec1;
2089
GEN v, ind, cx;
2090
nf = checknf(nf); nf_get_sign(nf,&r1,&r2);
2091
x = nf_to_scalar_or_basis(nf, x);
2092
ind = parse_embed(ind0, r1+r2, "nfeltembed");
2093
l = lg(ind);
2094
if (typ(x) != t_COL)
2095
{
2096
if (!(ind0 && typ(ind0) == t_INT)) x = const_vec(l-1, x);
2097
return gerepilecopy(av, x);
2098
}
2099
x = Q_primitive_part(x, &cx);
2100
prec1 = prec0; e = gexpo(x);
2101
if (e > 8) prec1 += nbits2extraprec(e);
2102
prec = prec1;
2103
if (nf_get_prec(nf) < prec) nf = nfnewprec_shallow(nf, prec);
2104
v = cgetg(l, t_VEC);
2105
for(;;)
2106
{
2107
GEN M = nf_get_M(nf);
2108
for (i = 1; i < l; i++)
2109
{
2110
GEN t = nfembed_i(M, x, ind[i]);
2111
long e = gexpo(t);
2112
if (gequal0(t) || precision(t) < prec0
2113
|| (e < 0 && prec < prec1 + nbits2extraprec(-e)) ) break;
2114
if (cx) t = gmul(t, cx);
2115
gel(v,i) = t;
2116
}
2117
if (i == l) break;
2118
prec = precdbl(prec);
2119
if (DEBUGLEVEL>1) pari_warn(warnprec,"eltnfembed", prec);
2120
nf = nfnewprec_shallow(nf, prec);
2121
}
2122
if (ind0 && typ(ind0) == t_INT) v = gel(v,1);
2123
return gerepilecopy(av, v);
2124
}
2125
2126
/* number of distinct roots of sigma(f) */
2127
GEN
2128
nfpolsturm(GEN nf, GEN f, GEN ind0)
2129
{
2130
pari_sp av = avma;
2131
long d, l, r1, single;
2132
GEN ind, u, v, vr1, T, s, t;
2133
2134
nf = checknf(nf); T = nf_get_pol(nf); r1 = nf_get_r1(nf);
2135
ind = parse_embed(ind0, r1, "nfpolsturm");
2136
single = ind0 && typ(ind0) == t_INT;
2137
l = lg(ind);
2138
2139
if (gequal0(f)) pari_err_ROOTS0("nfpolsturm");
2140
if (typ(f) == t_POL && varn(f) != varn(T))
2141
{
2142
f = RgX_nffix("nfpolsturm", T, f,1);
2143
if (lg(f) == 3) f = NULL;
2144
}
2145
else
2146
{
2147
(void)Rg_nffix("nfpolsturm", T, f, 0);
2148
f = NULL;
2149
}
2150
if (!f) { set_avma(av); return single? gen_0: zerovec(l-1); }
2151
d = degpol(f);
2152
if (d == 1) { set_avma(av); return single? gen_1: const_vec(l-1,gen_1); }
2153
2154
vr1 = const_vecsmall(l-1, 1);
2155
u = Q_primpart(f); s = ZV_to_zv(nfeltsign(nf, gel(u,d+2), ind));
2156
v = RgX_deriv(u); t = odd(d)? leafcopy(s): zv_neg(s);
2157
for(;;)
2158
{
2159
GEN r = RgX_neg( Q_primpart(RgX_pseudorem(u, v)) ), sr;
2160
long i, dr = degpol(r);
2161
if (dr < 0) break;
2162
sr = ZV_to_zv(nfeltsign(nf, gel(r,dr+2), ind));
2163
for (i = 1; i < l; i++)
2164
if (sr[i] != s[i]) { s[i] = sr[i], vr1[i]--; }
2165
if (odd(dr)) sr = zv_neg(sr);
2166
for (i = 1; i < l; i++)
2167
if (sr[i] != t[i]) { t[i] = sr[i], vr1[i]++; }
2168
if (!dr) break;
2169
u = v; v = r;
2170
}
2171
if (single) { set_avma(av); return stoi(vr1[1]); }
2172
return gerepileupto(av, zv_to_ZV(vr1));
2173
}
2174
2175
/* return the vector of signs of x; the matrix of such if x is a vector
2176
* of nf elements */
2177
GEN
2178
nfsign(GEN nf, GEN x)
2179
{
2180
long i, l;
2181
GEN archp, S;
2182
2183
nf = checknf(nf);
2184
archp = identity_perm( nf_get_r1(nf) );
2185
if (typ(x) != t_VEC) return nfsign_arch(nf, x, archp);
2186
l = lg(x); S = cgetg(l, t_MAT);
2187
for (i=1; i<l; i++) gel(S,i) = nfsign_arch(nf, gel(x,i), archp);
2188
return S;
2189
}
2190
2191
/* x integral elt, A integral ideal in HNF; reduce x mod A */
2192
static GEN
2193
zk_modHNF(GEN x, GEN A)
2194
{ return (typ(x) == t_COL)? ZC_hnfrem(x, A): modii(x, gcoeff(A,1,1)); }
2195
2196
/* given an element x in Z_K and an integral ideal y in HNF, coprime with x,
2197
outputs an element inverse of x modulo y */
2198
GEN
2199
nfinvmodideal(GEN nf, GEN x, GEN y)
2200
{
2201
pari_sp av = avma;
2202
GEN a, yZ = gcoeff(y,1,1);
2203
2204
if (equali1(yZ)) return gen_0;
2205
x = nf_to_scalar_or_basis(nf, x);
2206
if (typ(x) == t_INT) return gerepileupto(av, Fp_inv(x, yZ));
2207
2208
a = hnfmerge_get_1(idealhnf_principal(nf,x), y);
2209
if (!a) pari_err_INV("nfinvmodideal", x);
2210
return gerepileupto(av, zk_modHNF(nfdiv(nf,a,x), y));
2211
}
2212
2213
static GEN
2214
nfsqrmodideal(GEN nf, GEN x, GEN id)
2215
{ return zk_modHNF(nfsqri(nf,x), id); }
2216
static GEN
2217
nfmulmodideal(GEN nf, GEN x, GEN y, GEN id)
2218
{ return x? zk_modHNF(nfmuli(nf,x,y), id): y; }
2219
/* assume x integral, k integer, A in HNF */
2220
GEN
2221
nfpowmodideal(GEN nf,GEN x,GEN k,GEN A)
2222
{
2223
long s = signe(k);
2224
pari_sp av;
2225
GEN y;
2226
2227
if (!s) return gen_1;
2228
av = avma;
2229
x = nf_to_scalar_or_basis(nf, x);
2230
if (typ(x) != t_COL) return Fp_pow(x, k, gcoeff(A,1,1));
2231
if (s < 0) { x = nfinvmodideal(nf, x,A); k = negi(k); }
2232
for(y = NULL;;)
2233
{
2234
if (mpodd(k)) y = nfmulmodideal(nf,y,x,A);
2235
k = shifti(k,-1); if (!signe(k)) break;
2236
x = nfsqrmodideal(nf,x,A);
2237
}
2238
return gerepileupto(av, y);
2239
}
2240
2241
/* a * g^n mod id */
2242
static GEN
2243
nfmulpowmodideal(GEN nf, GEN a, GEN g, GEN n, GEN id)
2244
{
2245
return nfmulmodideal(nf, a, nfpowmodideal(nf,g,n,id), id);
2246
}
2247
2248
/* assume (num(g[i]), id) = 1 for all i. Return prod g[i]^e[i] mod id.
2249
* EX = multiple of exponent of (O_K/id)^* */
2250
GEN
2251
famat_to_nf_modideal_coprime(GEN nf, GEN g, GEN e, GEN id, GEN EX)
2252
{
2253
GEN EXo2, plus = NULL, minus = NULL, idZ = gcoeff(id,1,1);
2254
long i, lx = lg(g);
2255
2256
if (equali1(idZ)) return gen_1; /* id = Z_K */
2257
EXo2 = (expi(EX) > 10)? shifti(EX,-1): NULL;
2258
for (i = 1; i < lx; i++)
2259
{
2260
GEN h, n = centermodii(gel(e,i), EX, EXo2);
2261
long sn = signe(n);
2262
if (!sn) continue;
2263
2264
h = nf_to_scalar_or_basis(nf, gel(g,i));
2265
switch(typ(h))
2266
{
2267
case t_INT: break;
2268
case t_FRAC:
2269
h = Fp_div(gel(h,1), gel(h,2), idZ); break;
2270
default:
2271
{
2272
GEN dh;
2273
h = Q_remove_denom(h, &dh);
2274
if (dh) h = FpC_Fp_mul(h, Fp_inv(dh,idZ), idZ);
2275
}
2276
}
2277
if (sn > 0)
2278
plus = nfmulpowmodideal(nf, plus, h, n, id);
2279
else /* sn < 0 */
2280
minus = nfmulpowmodideal(nf, minus, h, negi(n), id);
2281
}
2282
if (minus) plus = nfmulmodideal(nf, plus, nfinvmodideal(nf,minus,id), id);
2283
return plus? plus: gen_1;
2284
}
2285
2286
/* given 2 integral ideals x, y in HNF s.t x | y | x^2, compute (1+x)/(1+y) in
2287
* the form [[cyc],[gen], U], where U := ux^-1 as a pair [ZM, denom(U)] */
2288
static GEN
2289
zidealij(GEN x, GEN y)
2290
{
2291
GEN U, G, cyc, xp = gcoeff(x,1,1), xi = hnf_invscale(x, xp);
2292
long j, N;
2293
2294
/* x^(-1) y = relations between the 1 + x_i (HNF) */
2295
cyc = ZM_snf_group(ZM_Z_divexact(ZM_mul(xi, y), xp), &U, &G);
2296
N = lg(cyc); G = ZM_mul(x,G); settyp(G, t_VEC); /* new generators */
2297
for (j=1; j<N; j++)
2298
{
2299
GEN c = gel(G,j);
2300
gel(c,1) = addiu(gel(c,1), 1); /* 1 + g_j */
2301
if (ZV_isscalar(c)) gel(G,j) = gel(c,1);
2302
}
2303
return mkvec4(cyc, G, ZM_mul(U,xi), xp);
2304
}
2305
2306
/* lg(x) > 1, x + 1; shallow */
2307
static GEN
2308
ZC_add1(GEN x)
2309
{
2310
long i, l = lg(x);
2311
GEN y = cgetg(l, t_COL);
2312
for (i = 2; i < l; i++) gel(y,i) = gel(x,i);
2313
gel(y,1) = addiu(gel(x,1), 1); return y;
2314
}
2315
/* lg(x) > 1, x - 1; shallow */
2316
static GEN
2317
ZC_sub1(GEN x)
2318
{
2319
long i, l = lg(x);
2320
GEN y = cgetg(l, t_COL);
2321
for (i = 2; i < l; i++) gel(y,i) = gel(x,i);
2322
gel(y,1) = subiu(gel(x,1), 1); return y;
2323
}
2324
2325
/* x,y are t_INT or ZC */
2326
static GEN
2327
zkadd(GEN x, GEN y)
2328
{
2329
long tx = typ(x);
2330
if (tx == typ(y))
2331
return tx == t_INT? addii(x,y): ZC_add(x,y);
2332
else
2333
return tx == t_INT? ZC_Z_add(y,x): ZC_Z_add(x,y);
2334
}
2335
/* x a t_INT or ZC, x+1; shallow */
2336
static GEN
2337
zkadd1(GEN x)
2338
{
2339
long tx = typ(x);
2340
return tx == t_INT? addiu(x,1): ZC_add1(x);
2341
}
2342
/* x a t_INT or ZC, x-1; shallow */
2343
static GEN
2344
zksub1(GEN x)
2345
{
2346
long tx = typ(x);
2347
return tx == t_INT? subiu(x,1): ZC_sub1(x);
2348
}
2349
/* x,y are t_INT or ZC; x - y */
2350
static GEN
2351
zksub(GEN x, GEN y)
2352
{
2353
long tx = typ(x), ty = typ(y);
2354
if (tx == ty)
2355
return tx == t_INT? subii(x,y): ZC_sub(x,y);
2356
else
2357
return tx == t_INT? Z_ZC_sub(x,y): ZC_Z_sub(x,y);
2358
}
2359
/* x is t_INT or ZM (mult. map), y is t_INT or ZC; x * y */
2360
static GEN
2361
zkmul(GEN x, GEN y)
2362
{
2363
long tx = typ(x), ty = typ(y);
2364
if (ty == t_INT)
2365
return tx == t_INT? mulii(x,y): ZC_Z_mul(gel(x,1),y);
2366
else
2367
return tx == t_INT? ZC_Z_mul(y,x): ZM_ZC_mul(x,y);
2368
}
2369
2370
/* (U,V) = 1 coprime ideals. Want z = x mod U, = y mod V; namely
2371
* z =vx + uy = v(x-y) + y, where u + v = 1, u in U, v in V.
2372
* zkc = [v, UV], v a t_INT or ZM (mult. by v map), UV a ZM (ideal in HNF);
2373
* shallow */
2374
GEN
2375
zkchinese(GEN zkc, GEN x, GEN y)
2376
{
2377
GEN v = gel(zkc,1), UV = gel(zkc,2), z = zkadd(zkmul(v, zksub(x,y)), y);
2378
return zk_modHNF(z, UV);
2379
}
2380
/* special case z = x mod U, = 1 mod V; shallow */
2381
GEN
2382
zkchinese1(GEN zkc, GEN x)
2383
{
2384
GEN v = gel(zkc,1), UV = gel(zkc,2), z = zkadd1(zkmul(v, zksub1(x)));
2385
return (typ(z) == t_INT)? z: ZC_hnfrem(z, UV);
2386
}
2387
static GEN
2388
zkVchinese1(GEN zkc, GEN v)
2389
{
2390
long i, ly;
2391
GEN y = cgetg_copy(v, &ly);
2392
for (i=1; i<ly; i++) gel(y,i) = zkchinese1(zkc, gel(v,i));
2393
return y;
2394
}
2395
2396
/* prepare to solve z = x (mod A), z = y mod (B) [zkchinese or zkchinese1] */
2397
GEN
2398
zkchineseinit(GEN nf, GEN A, GEN B, GEN AB)
2399
{
2400
GEN v;
2401
long e;
2402
nf = checknf(nf);
2403
v = idealaddtoone_raw(nf, A, B);
2404
if ((e = gexpo(v)) > 5)
2405
{
2406
GEN b = (typ(v) == t_COL)? v: scalarcol_shallow(v, nf_get_degree(nf));
2407
b= ZC_reducemodlll(b, AB);
2408
if (gexpo(b) < e) v = b;
2409
}
2410
return mkvec2(zk_scalar_or_multable(nf,v), AB);
2411
}
2412
/* prepare to solve z = x (mod A), z = 1 mod (B)
2413
* and then z = 1 (mod A), z = y mod (B) [zkchinese1 twice] */
2414
static GEN
2415
zkchinese1init2(GEN nf, GEN A, GEN B, GEN AB)
2416
{
2417
GEN zkc = zkchineseinit(nf, A, B, AB);
2418
GEN mv = gel(zkc,1), mu;
2419
if (typ(mv) == t_INT) return mkvec2(zkc, mkvec2(subui(1,mv),AB));
2420
mu = RgM_Rg_add_shallow(ZM_neg(mv), gen_1);
2421
return mkvec2(mkvec2(mv,AB), mkvec2(mu,AB));
2422
}
2423
2424
static GEN
2425
apply_U(GEN L, GEN a)
2426
{
2427
GEN e, U = gel(L,3), dU = gel(L,4);
2428
if (typ(a) == t_INT)
2429
e = ZC_Z_mul(gel(U,1), subiu(a, 1));
2430
else
2431
{ /* t_COL */
2432
GEN t = shallowcopy(a);
2433
gel(t,1) = subiu(gel(t,1), 1); /* t = a - 1 */
2434
e = ZM_ZC_mul(U, t);
2435
}
2436
return gdiv(e, dU);
2437
}
2438
2439
/* true nf; vectors of [[cyc],[g],U.X^-1]. Assume k > 1. */
2440
static GEN
2441
principal_units(GEN nf, GEN pr, long k, GEN prk)
2442
{
2443
GEN list, prb;
2444
ulong mask = quadratic_prec_mask(k);
2445
long a = 1;
2446
2447
prb = pr_hnf(nf,pr);
2448
list = vectrunc_init(k);
2449
while (mask > 1)
2450
{
2451
GEN pra = prb;
2452
long b = a << 1;
2453
2454
if (mask & 1) b--;
2455
mask >>= 1;
2456
/* compute 1 + pr^a / 1 + pr^b, 2a <= b */
2457
prb = (b >= k)? prk: idealpows(nf,pr,b);
2458
vectrunc_append(list, zidealij(pra, prb));
2459
a = b;
2460
}
2461
return list;
2462
}
2463
/* a = 1 mod (pr) return log(a) on local-gens of 1+pr/1+pr^k */
2464
static GEN
2465
log_prk1(GEN nf, GEN a, long nh, GEN L2, GEN prk)
2466
{
2467
GEN y = cgetg(nh+1, t_COL);
2468
long j, iy, c = lg(L2)-1;
2469
for (j = iy = 1; j <= c; j++)
2470
{
2471
GEN L = gel(L2,j), cyc = gel(L,1), gen = gel(L,2), E = apply_U(L,a);
2472
long i, nc = lg(cyc)-1;
2473
int last = (j == c);
2474
for (i = 1; i <= nc; i++, iy++)
2475
{
2476
GEN t, e = gel(E,i);
2477
if (typ(e) != t_INT) pari_err_COPRIME("zlog_prk1", a, prk);
2478
t = Fp_neg(e, gel(cyc,i));
2479
gel(y,iy) = negi(t);
2480
if (!last && signe(t)) a = nfmulpowmodideal(nf, a, gel(gen,i), t, prk);
2481
}
2482
}
2483
return y;
2484
}
2485
/* true nf */
2486
static GEN
2487
principal_units_relations(GEN nf, GEN L2, GEN prk, long nh)
2488
{
2489
GEN h = cgetg(nh+1,t_MAT);
2490
long ih, j, c = lg(L2)-1;
2491
for (j = ih = 1; j <= c; j++)
2492
{
2493
GEN L = gel(L2,j), F = gel(L,1), G = gel(L,2);
2494
long k, lG = lg(G);
2495
for (k = 1; k < lG; k++,ih++)
2496
{ /* log(g^f) mod pr^e */
2497
GEN a = nfpowmodideal(nf,gel(G,k),gel(F,k),prk);
2498
gel(h,ih) = ZC_neg(log_prk1(nf, a, nh, L2, prk));
2499
gcoeff(h,ih,ih) = gel(F,k);
2500
}
2501
}
2502
return h;
2503
}
2504
/* true nf; k > 1; multiplicative group (1 + pr) / (1 + pr^k) */
2505
static GEN
2506
idealprincipalunits_i(GEN nf, GEN pr, long k, GEN *pU)
2507
{
2508
GEN cyc, gen, L2, prk = idealpows(nf, pr, k);
2509
2510
L2 = principal_units(nf, pr, k, prk);
2511
if (k == 2)
2512
{
2513
GEN L = gel(L2,1);
2514
cyc = gel(L,1);
2515
gen = gel(L,2);
2516
if (pU) *pU = matid(lg(gen)-1);
2517
}
2518
else
2519
{
2520
long c = lg(L2), j;
2521
GEN EX, h, Ui, vg = cgetg(c, t_VEC);
2522
for (j = 1; j < c; j++) gel(vg, j) = gmael(L2,j,2);
2523
vg = shallowconcat1(vg);
2524
h = principal_units_relations(nf, L2, prk, lg(vg)-1);
2525
h = ZM_hnfall_i(h, NULL, 0);
2526
cyc = ZM_snf_group(h, pU, &Ui);
2527
c = lg(Ui); gen = cgetg(c, t_VEC); EX = cyc_get_expo(cyc);
2528
for (j = 1; j < c; j++)
2529
gel(gen,j) = famat_to_nf_modideal_coprime(nf, vg, gel(Ui,j), prk, EX);
2530
}
2531
return mkvec4(cyc, gen, prk, L2);
2532
}
2533
GEN
2534
idealprincipalunits(GEN nf, GEN pr, long k)
2535
{
2536
pari_sp av;
2537
GEN v;
2538
nf = checknf(nf);
2539
if (k == 1) { checkprid(pr); retmkvec3(gen_1,cgetg(1,t_VEC),cgetg(1,t_VEC)); }
2540
av = avma; v = idealprincipalunits_i(nf, pr, k, NULL);
2541
return gerepilecopy(av, mkvec3(powiu(pr_norm(pr), k-1), gel(v,1), gel(v,2)));
2542
}
2543
2544
/* true nf; given an ideal pr^k dividing an integral ideal x (in HNF form)
2545
* compute an 'sprk', the structure of G = (Z_K/pr^k)^* [ x = NULL for x=pr^k ]
2546
* Return a vector with at least 4 components [cyc],[gen],[HNF pr^k,pr,k],ff,
2547
* where
2548
* cyc : type of G as abelian group (SNF)
2549
* gen : generators of G, coprime to x
2550
* pr^k: in HNF
2551
* ff : data for log_g in (Z_K/pr)^*
2552
* Two extra components are present iff k > 1: L2, U
2553
* L2 : list of data structures to compute local DL in (Z_K/pr)^*,
2554
* and 1 + pr^a/ 1 + pr^b for various a < b <= min(2a, k)
2555
* U : base change matrices to convert a vector of local DL to DL wrt gen
2556
* If MOD is not NULL, initialize G / G^MOD instead */
2557
static GEN
2558
sprkinit(GEN nf, GEN pr, long k, GEN x, GEN MOD)
2559
{
2560
GEN T, p, Ld, modpr, cyc, gen, g, g0, A, prk, U, L2, ord0 = NULL;
2561
long f = pr_get_f(pr);
2562
2563
if(DEBUGLEVEL>3) err_printf("treating pr^%ld, pr = %Ps\n",k,pr);
2564
modpr = nf_to_Fq_init(nf, &pr,&T,&p);
2565
if (MOD)
2566
{
2567
GEN A = subiu(powiu(p,f), 1), d = gcdii(A, MOD), fa = Z_factor(d);
2568
ord0 = mkvec2(A, fa); /* true order, factorization of order in G/G^MOD */
2569
Ld = gel(fa,1);
2570
if (lg(Ld) > 1 && equaliu(gel(Ld,1),2)) Ld = vecslice(Ld,2,lg(Ld)-1);
2571
}
2572
/* (Z_K / pr)^* */
2573
if (f == 1)
2574
{
2575
g0 = g = MOD? pgener_Fp_local(p, Ld): pgener_Fp(p);
2576
if (!ord0) ord0 = get_arith_ZZM(subiu(p,1));
2577
}
2578
else
2579
{
2580
g0 = g = MOD? gener_FpXQ_local(T, p, Ld): gener_FpXQ(T,p, &ord0);
2581
g = Fq_to_nf(g, modpr);
2582
if (typ(g) == t_POL) g = poltobasis(nf, g);
2583
}
2584
A = gel(ord0, 1); /* Norm(pr)-1 */
2585
/* If MOD != NULL, d = gcd(A, MOD): g^(A/d) has order d */
2586
if (k == 1)
2587
{
2588
cyc = mkvec(A);
2589
gen = mkvec(g);
2590
prk = pr_hnf(nf,pr);
2591
L2 = U = NULL;
2592
}
2593
else
2594
{ /* local-gens of (1 + pr)/(1 + pr^k) = SNF-gens * U */
2595
GEN AB, B, u, v, w;
2596
long j, l;
2597
w = idealprincipalunits_i(nf, pr, k, &U);
2598
/* incorporate (Z_K/pr)^*, order A coprime to B = expo(1+pr/1+pr^k)*/
2599
cyc = leafcopy(gel(w,1)); B = cyc_get_expo(cyc); AB = mulii(A,B);
2600
gen = leafcopy(gel(w,2));
2601
prk = gel(w,3);
2602
g = nfpowmodideal(nf, g, B, prk);
2603
g0 = Fq_pow(g0, modii(B,A), T, p); /* update primitive root */
2604
L2 = mkvec3(A, g, gel(w,4));
2605
gel(cyc,1) = AB;
2606
gel(gen,1) = nfmulmodideal(nf, gel(gen,1), g, prk);
2607
u = mulii(Fp_inv(A,B), A);
2608
v = subui(1, u); l = lg(U);
2609
for (j = 1; j < l; j++) gcoeff(U,1,j) = Fp_mul(u, gcoeff(U,1,j), AB);
2610
U = mkvec2(Rg_col_ei(v, lg(gen)-1, 1), U);
2611
}
2612
/* local-gens of (Z_K/pr^k)^* = SNF-gens * U */
2613
if (x)
2614
{
2615
GEN uv = zkchineseinit(nf, idealmulpowprime(nf,x,pr,utoineg(k)), prk, x);
2616
gen = zkVchinese1(uv, gen);
2617
}
2618
return mkvecn(U? 6: 4, cyc, gen, prk, mkvec3(modpr,g0,ord0), L2, U);
2619
}
2620
static GEN
2621
sprk_get_cyc(GEN s) { return gel(s,1); }
2622
static GEN
2623
sprk_get_expo(GEN s) { return cyc_get_expo(sprk_get_cyc(s)); }
2624
static GEN
2625
sprk_get_gen(GEN s) { return gel(s,2); }
2626
static GEN
2627
sprk_get_prk(GEN s) { return gel(s,3); }
2628
static GEN
2629
sprk_get_ff(GEN s) { return gel(s,4); }
2630
static GEN
2631
sprk_get_pr(GEN s) { GEN ff = gel(s,4); return modpr_get_pr(gel(ff,1)); }
2632
/* L2 to 1 + pr / 1 + pr^k */
2633
static GEN
2634
sprk_get_L2(GEN s) { return gmael(s,5,3); }
2635
/* lift to nf of primitive root of k(pr) */
2636
static GEN
2637
sprk_get_gnf(GEN s) { return gmael(s,5,2); }
2638
static void
2639
sprk_get_U2(GEN s, GEN *U1, GEN *U2)
2640
{ GEN v = gel(s,6); *U1 = gel(v,1); *U2 = gel(v,2); }
2641
static int
2642
sprk_is_prime(GEN s) { return lg(s) == 5; }
2643
2644
static GEN
2645
famat_zlog_pr(GEN nf, GEN g, GEN e, GEN sprk, GEN mod)
2646
{
2647
GEN x, expo = sprk_get_expo(sprk);
2648
if (mod) expo = gcdii(expo,mod);
2649
x = famat_makecoprime(nf, g, e, sprk_get_pr(sprk), sprk_get_prk(sprk), expo);
2650
return log_prk(nf, x, sprk, mod);
2651
}
2652
/* famat_zlog_pr assuming (g,sprk.pr) = 1 */
2653
static GEN
2654
famat_zlog_pr_coprime(GEN nf, GEN g, GEN e, GEN sprk, GEN MOD)
2655
{
2656
GEN x = famat_to_nf_modideal_coprime(nf, g, e, sprk_get_prk(sprk),
2657
sprk_get_expo(sprk));
2658
return log_prk(nf, x, sprk, MOD);
2659
}
2660
2661
/* o t_INT, O = [ord,fa] format for multiple of o (for Fq_log);
2662
* return o in [ord,fa] format */
2663
static GEN
2664
order_update(GEN o, GEN O)
2665
{
2666
GEN p = gmael(O,2,1), z = o, P, E;
2667
long i, j, l = lg(p);
2668
P = cgetg(l, t_COL);
2669
E = cgetg(l, t_COL);
2670
for (i = j = 1; i < l; i++)
2671
{
2672
long v = Z_pvalrem(z, gel(p,i), &z);
2673
if (v)
2674
{
2675
gel(P,j) = gel(p,i);
2676
gel(E,j) = utoipos(v); j++;
2677
if (is_pm1(z)) break;
2678
}
2679
}
2680
setlg(P, j);
2681
setlg(E, j); return mkvec2(o, mkmat2(P,E));
2682
}
2683
2684
/* a in Z_K (t_COL or t_INT), pr prime ideal, sprk = sprkinit(nf,pr,k,x),
2685
* mod positive t_INT or NULL (meaning mod=0).
2686
* return log(a) modulo mod on SNF-generators of (Z_K/pr^k)^* */
2687
GEN
2688
log_prk(GEN nf, GEN a, GEN sprk, GEN mod)
2689
{
2690
GEN e, prk, g, U1, U2, y, ff, O, o, oN, gN, N, T, p, modpr, pr, cyc;
2691
2692
if (typ(a) == t_MAT) return famat_zlog_pr(nf, gel(a,1), gel(a,2), sprk, mod);
2693
N = NULL;
2694
ff = sprk_get_ff(sprk);
2695
pr = gel(ff,1); /* modpr */
2696
g = gN = gel(ff,2);
2697
O = gel(ff,3); /* order of g = |Fq^*|, in [ord, fa] format */
2698
o = oN = gel(O,1); /* order as a t_INT */
2699
prk = sprk_get_prk(sprk);
2700
modpr = nf_to_Fq_init(nf, &pr, &T, &p);
2701
if (mod)
2702
{
2703
GEN d = gcdii(o,mod);
2704
if (!equalii(o, d))
2705
{
2706
N = diviiexact(o,d); /* > 1, coprime to p */
2707
a = nfpowmodideal(nf, a, N, prk);
2708
oN = d; /* order of g^N mod pr */
2709
}
2710
}
2711
if (equali1(oN))
2712
e = gen_0;
2713
else
2714
{
2715
if (N) { O = order_update(oN, O); gN = Fq_pow(g, N, T, p); }
2716
e = Fq_log(nf_to_Fq(nf,a,modpr), gN, O, T, p);
2717
}
2718
/* 0 <= e < oN is correct modulo oN */
2719
if (sprk_is_prime(sprk)) return mkcol(e); /* k = 1 */
2720
2721
sprk_get_U2(sprk, &U1,&U2);
2722
cyc = sprk_get_cyc(sprk);
2723
if (mod)
2724
{
2725
cyc = ZV_snf_gcd(cyc, mod);
2726
if (signe(remii(mod,p))) return vecmodii(ZC_Z_mul(U1,e), cyc);
2727
}
2728
if (signe(e))
2729
{
2730
GEN E = N? mulii(e, N): e;
2731
a = nfmulpowmodideal(nf, a, sprk_get_gnf(sprk), Fp_neg(E, o), prk);
2732
}
2733
/* a = 1 mod pr */
2734
y = log_prk1(nf, a, lg(U2)-1, sprk_get_L2(sprk), prk);
2735
if (N)
2736
{ /* from DL(a^N) to DL(a) */
2737
GEN E = gel(sprk_get_cyc(sprk), 1), q = powiu(p, Z_pval(E, p));
2738
y = ZC_Z_mul(y, Fp_inv(N, q));
2739
}
2740
y = ZC_lincomb(gen_1, e, ZM_ZC_mul(U2,y), U1);
2741
return vecmodii(y, cyc);
2742
}
2743
GEN
2744
log_prk_init(GEN nf, GEN pr, long k, GEN MOD)
2745
{ return sprkinit(checknf(nf),pr,k,NULL,MOD);}
2746
GEN
2747
veclog_prk(GEN nf, GEN v, GEN sprk)
2748
{
2749
long l = lg(v), i;
2750
GEN w = cgetg(l, t_MAT);
2751
for (i = 1; i < l; i++) gel(w,i) = log_prk(nf, gel(v,i), sprk, NULL);
2752
return w;
2753
}
2754
2755
static GEN
2756
famat_zlog(GEN nf, GEN fa, GEN sgn, zlog_S *S)
2757
{
2758
long i, l0, l = lg(S->U);
2759
GEN g = gel(fa,1), e = gel(fa,2), y = cgetg(l, t_COL);
2760
l0 = lg(S->sprk); /* = l (trivial arch. part), or l-1 */
2761
for (i=1; i < l0; i++) gel(y,i) = famat_zlog_pr(nf, g, e, gel(S->sprk,i), S->mod);
2762
if (l0 != l)
2763
{
2764
if (!sgn) sgn = nfsign_arch(nf, fa, S->archp);
2765
gel(y,l0) = Flc_to_ZC(sgn);
2766
}
2767
return y;
2768
}
2769
2770
/* assume that cyclic factors are normalized, in particular != [1] */
2771
static GEN
2772
split_U(GEN U, GEN Sprk)
2773
{
2774
long t = 0, k, n, l = lg(Sprk);
2775
GEN vU = cgetg(l+1, t_VEC);
2776
for (k = 1; k < l; k++)
2777
{
2778
n = lg(sprk_get_cyc(gel(Sprk,k))) - 1; /* > 0 */
2779
gel(vU,k) = vecslice(U, t+1, t+n);
2780
t += n;
2781
}
2782
/* t+1 .. lg(U)-1 */
2783
n = lg(U) - t - 1; /* can be 0 */
2784
if (!n) setlg(vU,l); else gel(vU,l) = vecslice(U, t+1, t+n);
2785
return vU;
2786
}
2787
2788
static void
2789
init_zlog_mod(zlog_S *S, GEN bid, GEN mod)
2790
{
2791
GEN fa2 = bid_get_fact2(bid);
2792
S->U = bid_get_U(bid);
2793
S->hU = lg(bid_get_cyc(bid))-1;
2794
S->archp = bid_get_archp(bid);
2795
S->sprk = bid_get_sprk(bid);
2796
S->bid = bid;
2797
S->mod = mod;
2798
S->P = gel(fa2,1);
2799
S->k = gel(fa2,2);
2800
S->no2 = lg(S->P) == lg(gel(bid_get_fact(bid),1));
2801
}
2802
void
2803
init_zlog(zlog_S *S, GEN bid)
2804
{
2805
return init_zlog_mod(S, bid, NULL);
2806
}
2807
2808
/* a a t_FRAC/t_INT, reduce mod bid */
2809
static GEN
2810
Q_mod_bid(GEN bid, GEN a)
2811
{
2812
GEN xZ = gcoeff(bid_get_ideal(bid),1,1);
2813
GEN b = Rg_to_Fp(a, xZ);
2814
if (gsigne(a) < 0) b = subii(b, xZ);
2815
return signe(b)? b: xZ;
2816
}
2817
/* Return decomposition of a on the CRT generators blocks attached to the
2818
* S->sprk and sarch; sgn = sign(a, S->arch), NULL if unknown */
2819
static GEN
2820
zlog(GEN nf, GEN a, GEN sgn, zlog_S *S)
2821
{
2822
long k, l;
2823
GEN y;
2824
a = nf_to_scalar_or_basis(nf, a);
2825
switch(typ(a))
2826
{
2827
case t_INT: break;
2828
case t_FRAC: a = Q_mod_bid(S->bid, a); break;
2829
default: /* case t_COL: */
2830
{
2831
GEN den;
2832
check_nfelt(a, &den);
2833
if (den)
2834
{
2835
a = Q_muli_to_int(a, den);
2836
a = mkmat2(mkcol2(a, den), mkcol2(gen_1, gen_m1));
2837
return famat_zlog(nf, a, sgn, S);
2838
}
2839
}
2840
}
2841
if (sgn)
2842
sgn = (lg(sgn) == 1)? NULL: leafcopy(sgn);
2843
else
2844
sgn = (lg(S->archp) == 1)? NULL: nfsign_arch(nf, a, S->archp);
2845
l = lg(S->sprk);
2846
y = cgetg(sgn? l+1: l, t_COL);
2847
for (k = 1; k < l; k++)
2848
{
2849
GEN sprk = gel(S->sprk,k);
2850
gel(y,k) = log_prk(nf, a, sprk, S->mod);
2851
}
2852
if (sgn) gel(y,l) = Flc_to_ZC(sgn);
2853
return y;
2854
}
2855
2856
/* true nf */
2857
GEN
2858
pr_basis_perm(GEN nf, GEN pr)
2859
{
2860
long f = pr_get_f(pr);
2861
GEN perm;
2862
if (f == nf_get_degree(nf)) return identity_perm(f);
2863
perm = cgetg(f+1, t_VECSMALL);
2864
perm[1] = 1;
2865
if (f > 1)
2866
{
2867
GEN H = pr_hnf(nf,pr);
2868
long i, k;
2869
for (i = k = 2; k <= f; i++)
2870
if (!equali1(gcoeff(H,i,i))) perm[k++] = i;
2871
}
2872
return perm;
2873
}
2874
2875
/* \sum U[i]*y[i], U[i] ZM, y[i] ZC. We allow lg(y) > lg(U). */
2876
static GEN
2877
ZMV_ZCV_mul(GEN U, GEN y)
2878
{
2879
long i, l = lg(U);
2880
GEN z = NULL;
2881
if (l == 1) return cgetg(1,t_COL);
2882
for (i = 1; i < l; i++)
2883
{
2884
GEN u = ZM_ZC_mul(gel(U,i), gel(y,i));
2885
z = z? ZC_add(z, u): u;
2886
}
2887
return z;
2888
}
2889
/* A * (U[1], ..., U[d] */
2890
static GEN
2891
ZM_ZMV_mul(GEN A, GEN U)
2892
{
2893
long i, l;
2894
GEN V = cgetg_copy(U,&l);
2895
for (i = 1; i < l; i++) gel(V,i) = ZM_mul(A,gel(U,i));
2896
return V;
2897
}
2898
2899
/* a = 1 mod pr, sprk mod pr^e, e >= 1 */
2900
static GEN
2901
sprk_log_prk1_2(GEN nf, GEN a, GEN sprk)
2902
{
2903
GEN U1, U2, y, L2 = sprk_get_L2(sprk);
2904
sprk_get_U2(sprk, &U1,&U2);
2905
y = ZM_ZC_mul(U2, log_prk1(nf, a, lg(U2)-1, L2, sprk_get_prk(sprk)));
2906
return vecmodii(y, sprk_get_cyc(sprk));
2907
}
2908
/* assume e >= 2 */
2909
static GEN
2910
sprk_log_gen_pr2(GEN nf, GEN sprk, long e)
2911
{
2912
GEN M, G, pr = sprk_get_pr(sprk);
2913
long i, l;
2914
if (e == 2)
2915
{
2916
GEN L2 = sprk_get_L2(sprk), L = gel(L2,1);
2917
G = gel(L,2); l = lg(G);
2918
}
2919
else
2920
{
2921
GEN perm = pr_basis_perm(nf,pr), PI = nfpow_u(nf, pr_get_gen(pr), e-1);
2922
l = lg(perm);
2923
G = cgetg(l, t_VEC);
2924
if (typ(PI) == t_INT)
2925
{ /* zk_ei_mul doesn't allow t_INT */
2926
long N = nf_get_degree(nf);
2927
gel(G,1) = addiu(PI,1);
2928
for (i = 2; i < l; i++)
2929
{
2930
GEN z = col_ei(N, 1);
2931
gel(G,i) = z; gel(z, perm[i]) = PI;
2932
}
2933
}
2934
else
2935
{
2936
gel(G,1) = nfadd(nf, gen_1, PI);
2937
for (i = 2; i < l; i++)
2938
gel(G,i) = nfadd(nf, gen_1, zk_ei_mul(nf, PI, perm[i]));
2939
}
2940
}
2941
M = cgetg(l, t_MAT);
2942
for (i = 1; i < l; i++) gel(M,i) = sprk_log_prk1_2(nf, gel(G,i), sprk);
2943
return M;
2944
}
2945
/* Log on bid.gen of generators of P_{1,I pr^{e-1}} / P_{1,I pr^e} (I,pr) = 1,
2946
* defined implicitly via CRT. 'ind' is the index of pr in modulus
2947
* factorization */
2948
GEN
2949
log_gen_pr(zlog_S *S, long ind, GEN nf, long e)
2950
{
2951
GEN Uind = gel(S->U, ind);
2952
if (e == 1) retmkmat( gel(Uind,1) );
2953
return ZM_mul(Uind, sprk_log_gen_pr2(nf, gel(S->sprk,ind), e));
2954
}
2955
GEN
2956
sprk_log_gen_pr(GEN nf, GEN sprk, long e)
2957
{
2958
if (e == 1)
2959
{
2960
long n = lg(sprk_get_cyc(sprk))-1;
2961
retmkmat(col_ei(n, 1));
2962
}
2963
return sprk_log_gen_pr2(nf, sprk, e);
2964
}
2965
/* a = 1 mod pr */
2966
GEN
2967
sprk_log_prk1(GEN nf, GEN a, GEN sprk)
2968
{
2969
if (lg(sprk) == 5) return mkcol(gen_0); /* mod pr */
2970
return sprk_log_prk1_2(nf, a, sprk);
2971
}
2972
/* Log on bid.gen of generator of P_{1,f} / P_{1,f v[index]}
2973
* v = vector of r1 real places */
2974
GEN
2975
log_gen_arch(zlog_S *S, long index)
2976
{
2977
GEN U = gel(S->U, lg(S->U)-1);
2978
return gel(U, index);
2979
}
2980
2981
/* compute bid.clgp: [h,cyc] or [h,cyc,gen] */
2982
static GEN
2983
bid_grp(GEN nf, GEN U, GEN cyc, GEN g, GEN F, GEN sarch)
2984
{
2985
GEN G, h = ZV_prod(cyc);
2986
long c;
2987
if (!U) return mkvec2(h,cyc);
2988
c = lg(U);
2989
G = cgetg(c,t_VEC);
2990
if (c > 1)
2991
{
2992
GEN U0, Uoo, EX = cyc_get_expo(cyc); /* exponent of bid */
2993
long i, hU = nbrows(U), nba = lg(sarch_get_cyc(sarch))-1; /* #f_oo */
2994
if (!nba) { U0 = U; Uoo = NULL; }
2995
else if (nba == hU) { U0 = NULL; Uoo = U; }
2996
else
2997
{
2998
U0 = rowslice(U, 1, hU-nba);
2999
Uoo = rowslice(U, hU-nba+1, hU);
3000
}
3001
for (i = 1; i < c; i++)
3002
{
3003
GEN t = gen_1;
3004
if (U0) t = famat_to_nf_modideal_coprime(nf, g, gel(U0,i), F, EX);
3005
if (Uoo) t = set_sign_mod_divisor(nf, ZV_to_Flv(gel(Uoo,i),2), t, sarch);
3006
gel(G,i) = t;
3007
}
3008
}
3009
return mkvec3(h, cyc, G);
3010
}
3011
3012
/* remove prime ideals of norm 2 with exponent 1 from factorization */
3013
static GEN
3014
famat_strip2(GEN fa)
3015
{
3016
GEN P = gel(fa,1), E = gel(fa,2), Q, F;
3017
long l = lg(P), i, j;
3018
Q = cgetg(l, t_COL);
3019
F = cgetg(l, t_COL);
3020
for (i = j = 1; i < l; i++)
3021
{
3022
GEN pr = gel(P,i), e = gel(E,i);
3023
if (!absequaliu(pr_get_p(pr), 2) || itou(e) != 1 || pr_get_f(pr) != 1)
3024
{
3025
gel(Q,j) = pr;
3026
gel(F,j) = e; j++;
3027
}
3028
}
3029
setlg(Q,j);
3030
setlg(F,j); return mkmat2(Q,F);
3031
}
3032
static int
3033
checkarchp(GEN v, long r1)
3034
{
3035
long i, l = lg(v);
3036
pari_sp av = avma;
3037
GEN p;
3038
if (l == 1) return 1;
3039
if (l == 2) return v[1] > 0 && v[1] <= r1;
3040
p = zero_zv(r1);
3041
for (i = 1; i < l; i++)
3042
{
3043
long j = v[i];
3044
if (j <= 0 || j > r1 || p[j]) return gc_long(av, 0);
3045
p[j] = 1;
3046
}
3047
return gc_long(av, 1);
3048
}
3049
3050
/* Compute [[ideal,arch], [h,[cyc],[gen]], idealfact, [liste], U]
3051
flag may include nf_GEN | nf_INIT */
3052
static GEN
3053
Idealstarmod_i(GEN nf, GEN ideal, long flag, GEN MOD)
3054
{
3055
long i, nbp, R1;
3056
GEN y, cyc, U, u1 = NULL, fa, fa2, sprk, x, arch, archp, E, P, sarch, gen;
3057
3058
nf = checknf(nf);
3059
R1 = nf_get_r1(nf);
3060
if (typ(ideal) == t_VEC && lg(ideal) == 3)
3061
{
3062
arch = gel(ideal,2);
3063
ideal= gel(ideal,1);
3064
switch(typ(arch))
3065
{
3066
case t_VEC:
3067
if (lg(arch) != R1+1)
3068
pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);
3069
archp = vec01_to_indices(arch);
3070
break;
3071
case t_VECSMALL:
3072
if (!checkarchp(arch, R1))
3073
pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);
3074
archp = arch;
3075
arch = indices_to_vec01(archp, R1);
3076
break;
3077
default:
3078
pari_err_TYPE("Idealstar [incorrect archimedean component]",arch);
3079
return NULL;/*LCOV_EXCL_LINE*/
3080
}
3081
}
3082
else
3083
{
3084
arch = zerovec(R1);
3085
archp = cgetg(1, t_VECSMALL);
3086
}
3087
if (MOD)
3088
{
3089
if (typ(MOD) != t_INT) pari_err_TYPE("bnrinit [incorrect cycmod]", MOD);
3090
if (mpodd(MOD) && lg(archp) != 1)
3091
MOD = shifti(MOD, 1); /* ensure elements of G^MOD are >> 0 */
3092
}
3093
if (is_nf_factor(ideal))
3094
{
3095
fa = ideal;
3096
x = factorbackprime(nf, gel(fa,1), gel(fa,2));
3097
}
3098
else
3099
{
3100
fa = idealfactor(nf, ideal);
3101
x = ideal;
3102
}
3103
if (typ(x) != t_MAT) x = idealhnf_shallow(nf, x);
3104
if (lg(x) == 1) pari_err_DOMAIN("Idealstar", "ideal","=",gen_0,x);
3105
if (typ(gcoeff(x,1,1)) != t_INT)
3106
pari_err_DOMAIN("Idealstar","denominator(ideal)", "!=",gen_1,x);
3107
sarch = nfarchstar(nf, x, archp);
3108
fa2 = famat_strip2(fa);
3109
P = gel(fa2,1);
3110
E = gel(fa2,2);
3111
nbp = lg(P)-1;
3112
sprk = cgetg(nbp+1,t_VEC);
3113
if (nbp)
3114
{
3115
GEN t = (lg(gel(fa,1))==2)? NULL: x; /* beware fa != fa2 */
3116
cyc = cgetg(nbp+2,t_VEC);
3117
gen = cgetg(nbp+1,t_VEC);
3118
for (i = 1; i <= nbp; i++)
3119
{
3120
GEN L = sprkinit(nf, gel(P,i), itou(gel(E,i)), t, MOD);
3121
gel(sprk,i) = L;
3122
gel(cyc,i) = sprk_get_cyc(L);
3123
/* true gens are congruent to those mod x AND positive at archp */
3124
gel(gen,i) = sprk_get_gen(L);
3125
}
3126
gel(cyc,i) = sarch_get_cyc(sarch);
3127
cyc = shallowconcat1(cyc);
3128
gen = shallowconcat1(gen);
3129
cyc = ZV_snf_group(cyc, &U, (flag & nf_GEN)? &u1: NULL);
3130
}
3131
else
3132
{
3133
cyc = sarch_get_cyc(sarch);
3134
gen = cgetg(1,t_VEC);
3135
U = matid(lg(cyc)-1);
3136
if (flag & nf_GEN) u1 = U;
3137
}
3138
y = bid_grp(nf, u1, cyc, gen, x, sarch);
3139
if (!(flag & nf_INIT)) return y;
3140
U = split_U(U, sprk);
3141
return mkvec5(mkvec2(x, arch), y, mkvec2(fa,fa2), mkvec2(sprk, sarch), U);
3142
}
3143
GEN
3144
Idealstarmod(GEN nf, GEN ideal, long flag, GEN MOD)
3145
{
3146
pari_sp av = avma;
3147
if (!nf) nf = nfinit(pol_x(0), DEFAULTPREC);
3148
return gerepilecopy(av, Idealstarmod_i(nf, ideal, flag, MOD));
3149
}
3150
GEN
3151
Idealstar(GEN nf, GEN ideal, long flag) { return Idealstarmod(nf, ideal, flag, NULL); }
3152
GEN
3153
Idealstarprk(GEN nf, GEN pr, long k, long flag)
3154
{
3155
pari_sp av = avma;
3156
GEN z = Idealstarmod_i(nf, mkmat2(mkcol(pr),mkcols(k)), flag, NULL);
3157
return gerepilecopy(av, z);
3158
}
3159
3160
/* FIXME: obsolete */
3161
GEN
3162
zidealstarinitgen(GEN nf, GEN ideal)
3163
{ return Idealstar(nf,ideal, nf_INIT|nf_GEN); }
3164
GEN
3165
zidealstarinit(GEN nf, GEN ideal)
3166
{ return Idealstar(nf,ideal, nf_INIT); }
3167
GEN
3168
zidealstar(GEN nf, GEN ideal)
3169
{ return Idealstar(nf,ideal, nf_GEN); }
3170
3171
GEN
3172
idealstarmod(GEN nf, GEN ideal, long flag, GEN MOD)
3173
{
3174
switch(flag)
3175
{
3176
case 0: return Idealstarmod(nf,ideal, nf_GEN, MOD);
3177
case 1: return Idealstarmod(nf,ideal, nf_INIT, MOD);
3178
case 2: return Idealstarmod(nf,ideal, nf_INIT|nf_GEN, MOD);
3179
default: pari_err_FLAG("idealstar");
3180
}
3181
return NULL; /* LCOV_EXCL_LINE */
3182
}
3183
GEN
3184
idealstar0(GEN nf, GEN ideal,long flag) { return idealstarmod(nf, ideal, flag, NULL); }
3185
3186
void
3187
check_nfelt(GEN x, GEN *den)
3188
{
3189
long l = lg(x), i;
3190
GEN t, d = NULL;
3191
if (typ(x) != t_COL) pari_err_TYPE("check_nfelt", x);
3192
for (i=1; i<l; i++)
3193
{
3194
t = gel(x,i);
3195
switch (typ(t))
3196
{
3197
case t_INT: break;
3198
case t_FRAC:
3199
if (!d) d = gel(t,2); else d = lcmii(d, gel(t,2));
3200
break;
3201
default: pari_err_TYPE("check_nfelt", x);
3202
}
3203
}
3204
*den = d;
3205
}
3206
3207
GEN
3208
vecmodii(GEN x, GEN y)
3209
{ pari_APPLY_same(modii(gel(x,i), gel(y,i))) }
3210
GEN
3211
ZV_snf_gcd(GEN x, GEN mod)
3212
{ pari_APPLY_same(gcdii(gel(x,i), mod)); }
3213
3214
GEN
3215
vecmoduu(GEN x, GEN y)
3216
{ pari_APPLY_ulong(uel(x,i) % uel(y,i)) }
3217
3218
/* assume a true bnf and bid */
3219
GEN
3220
ideallog_units0(GEN bnf, GEN bid, GEN MOD)
3221
{
3222
GEN nf = bnf_get_nf(bnf), D, y, C, cyc;
3223
long j, lU = lg(bnf_get_logfu(bnf)); /* r1+r2 */
3224
zlog_S S;
3225
init_zlog_mod(&S, bid, MOD);
3226
if (!S.hU) return zeromat(0,lU);
3227
cyc = bid_get_cyc(bid);
3228
if (MOD) cyc = ZV_snf_gcd(cyc, MOD);
3229
D = nfsign_fu(bnf, bid_get_archp(bid));
3230
y = cgetg(lU, t_MAT);
3231
if ((C = bnf_build_cheapfu(bnf)))
3232
{ for (j = 1; j < lU; j++) gel(y,j) = zlog(nf, gel(C,j), gel(D,j), &S); }
3233
else
3234
{
3235
long i, l = lg(S.U), l0 = lg(S.sprk);
3236
GEN X, U;
3237
if (!(C = bnf_compactfu_mat(bnf))) bnf_build_units(bnf); /* error */
3238
X = gel(C,1); U = gel(C,2);
3239
for (j = 1; j < lU; j++) gel(y,j) = cgetg(l, t_COL);
3240
for (i = 1; i < l0; i++)
3241
{
3242
GEN sprk = gel(S.sprk, i);
3243
GEN Xi = sunits_makecoprime(X, sprk_get_pr(sprk), sprk_get_prk(sprk));
3244
for (j = 1; j < lU; j++)
3245
gcoeff(y,i,j) = famat_zlog_pr_coprime(nf, Xi, gel(U,j), sprk, MOD);
3246
}
3247
if (l0 != l)
3248
for (j = 1; j < lU; j++) gcoeff(y,l0,j) = Flc_to_ZC(gel(D,j));
3249
}
3250
y = vec_prepend(y, zlog(nf, bnf_get_tuU(bnf), nfsign_tu(bnf, S.archp), &S));
3251
for (j = 1; j <= lU; j++)
3252
gel(y,j) = vecmodii(ZMV_ZCV_mul(S.U, gel(y,j)), cyc);
3253
return y;
3254
}
3255
GEN
3256
ideallog_units(GEN bnf, GEN bid)
3257
{ return ideallog_units0(bnf, bid, NULL); }
3258
GEN
3259
log_prk_units(GEN nf, GEN D, GEN sprk)
3260
{
3261
GEN L, Ltu = log_prk(nf, gel(D,1), sprk, NULL);
3262
D = gel(D,2);
3263
if (lg(D) != 3 || typ(gel(D,2)) != t_MAT) L = veclog_prk(nf, D, sprk);
3264
else
3265
{
3266
GEN X = gel(D,1), U = gel(D,2);
3267
long j, lU = lg(U);
3268
X = sunits_makecoprime(X, sprk_get_pr(sprk), sprk_get_prk(sprk));
3269
L = cgetg(lU, t_MAT);
3270
for (j = 1; j < lU; j++)
3271
gel(L,j) = famat_zlog_pr_coprime(nf, X, gel(U,j), sprk, NULL);
3272
}
3273
return vec_prepend(L, Ltu);
3274
}
3275
3276
static GEN
3277
ideallog_i(GEN nf, GEN x, zlog_S *S)
3278
{
3279
pari_sp av = avma;
3280
GEN y;
3281
if (!S->hU) return cgetg(1, t_COL);
3282
if (typ(x) == t_MAT)
3283
y = famat_zlog(nf, x, NULL, S);
3284
else
3285
y = zlog(nf, x, NULL, S);
3286
y = ZMV_ZCV_mul(S->U, y);
3287
return gerepileupto(av, vecmodii(y, bid_get_cyc(S->bid)));
3288
}
3289
GEN
3290
ideallogmod(GEN nf, GEN x, GEN bid, GEN mod)
3291
{
3292
zlog_S S;
3293
if (!nf)
3294
{
3295
if (mod) pari_err_IMPL("Zideallogmod");
3296
return Zideallog(bid, x);
3297
}
3298
checkbid(bid); init_zlog_mod(&S, bid, mod);
3299
return ideallog_i(checknf(nf), x, &S);
3300
}
3301
GEN
3302
ideallog(GEN nf, GEN x, GEN bid) { return ideallogmod(nf, x, bid, NULL); }
3303
3304
/*************************************************************************/
3305
/** **/
3306
/** JOIN BID STRUCTURES, IDEAL LISTS **/
3307
/** **/
3308
/*************************************************************************/
3309
/* bid1, bid2: for coprime modules m1 and m2 (without arch. part).
3310
* Output: bid for m1 m2 */
3311
static GEN
3312
join_bid(GEN nf, GEN bid1, GEN bid2)
3313
{
3314
pari_sp av = avma;
3315
long nbgen, l1,l2;
3316
GEN I1,I2, G1,G2, sprk1,sprk2, cyc1,cyc2, sarch;
3317
GEN sprk, fa,fa2, U, cyc, y, u1 = NULL, x, gen;
3318
3319
I1 = bid_get_ideal(bid1);
3320
I2 = bid_get_ideal(bid2);
3321
if (gequal1(gcoeff(I1,1,1))) return bid2; /* frequent trivial case */
3322
G1 = bid_get_grp(bid1);
3323
G2 = bid_get_grp(bid2);
3324
x = idealmul(nf, I1,I2);
3325
fa = famat_mul_shallow(bid_get_fact(bid1), bid_get_fact(bid2));
3326
fa2= famat_mul_shallow(bid_get_fact2(bid1), bid_get_fact2(bid2));
3327
sprk1 = bid_get_sprk(bid1);
3328
sprk2 = bid_get_sprk(bid2);
3329
sprk = shallowconcat(sprk1, sprk2);
3330
3331
cyc1 = abgrp_get_cyc(G1); l1 = lg(cyc1);
3332
cyc2 = abgrp_get_cyc(G2); l2 = lg(cyc2);
3333
gen = (lg(G1)>3 && lg(G2)>3)? gen_1: NULL;
3334
nbgen = l1+l2-2;
3335
cyc = ZV_snf_group(shallowconcat(cyc1,cyc2), &U, gen? &u1: NULL);
3336
if (nbgen)
3337
{
3338
GEN U1 = bid_get_U(bid1), U2 = bid_get_U(bid2);
3339
U1 = l1==1? const_vec(lg(sprk1), cgetg(1,t_MAT))
3340
: ZM_ZMV_mul(vecslice(U, 1, l1-1), U1);
3341
U2 = l2==1? const_vec(lg(sprk2), cgetg(1,t_MAT))
3342
: ZM_ZMV_mul(vecslice(U, l1, nbgen), U2);
3343
U = shallowconcat(U1, U2);
3344
}
3345
else
3346
U = const_vec(lg(sprk), cgetg(1,t_MAT));
3347
3348
if (gen)
3349
{
3350
GEN uv = zkchinese1init2(nf, I2, I1, x);
3351
gen = shallowconcat(zkVchinese1(gel(uv,1), abgrp_get_gen(G1)),
3352
zkVchinese1(gel(uv,2), abgrp_get_gen(G2)));
3353
}
3354
sarch = bid_get_sarch(bid1); /* trivial */
3355
y = bid_grp(nf, u1, cyc, gen, x, sarch);
3356
x = mkvec2(x, bid_get_arch(bid1));
3357
y = mkvec5(x, y, mkvec2(fa, fa2), mkvec2(sprk, sarch), U);
3358
return gerepilecopy(av,y);
3359
}
3360
3361
typedef struct _ideal_data {
3362
GEN nf, emb, L, pr, prL, sgnU, archp;
3363
} ideal_data;
3364
3365
/* z <- ( z | f(v[i])_{i=1..#v} ) */
3366
static void
3367
concat_join(GEN *pz, GEN v, GEN (*f)(ideal_data*,GEN), ideal_data *data)
3368
{
3369
long i, nz, lv = lg(v);
3370
GEN z, Z;
3371
if (lv == 1) return;
3372
z = *pz; nz = lg(z)-1;
3373
*pz = Z = cgetg(lv + nz, typ(z));
3374
for (i = 1; i <=nz; i++) gel(Z,i) = gel(z,i);
3375
Z += nz;
3376
for (i = 1; i < lv; i++) gel(Z,i) = f(data, gel(v,i));
3377
}
3378
static GEN
3379
join_idealinit(ideal_data *D, GEN x)
3380
{ return join_bid(D->nf, x, D->prL); }
3381
static GEN
3382
join_ideal(ideal_data *D, GEN x)
3383
{ return idealmulpowprime(D->nf, x, D->pr, D->L); }
3384
static GEN
3385
join_unit(ideal_data *D, GEN x)
3386
{
3387
GEN bid = join_idealinit(D, gel(x,1)), u = gel(x,2), v = mkvec(D->emb);
3388
if (lg(u) != 1) v = shallowconcat(u, v);
3389
return mkvec2(bid, v);
3390
}
3391
3392
GEN
3393
log_prk_units_init(GEN bnf)
3394
{
3395
GEN U = bnf_has_fu(bnf);
3396
if (U) U = matalgtobasis(bnf_get_nf(bnf), U);
3397
else if (!(U = bnf_compactfu_mat(bnf))) (void)bnf_build_units(bnf);
3398
return mkvec2(bnf_get_tuU(bnf), U);
3399
}
3400
/* flag & nf_GEN : generators, otherwise no
3401
* flag &2 : units, otherwise no
3402
* flag &4 : ideals in HNF, otherwise bid
3403
* flag &8 : omit ideals which cannot be conductors (pr^1 with Npr=2) */
3404
static GEN
3405
Ideallist(GEN bnf, ulong bound, long flag)
3406
{
3407
const long do_units = flag & 2, big_id = !(flag & 4), cond = flag & 8;
3408
const long istar_flag = (flag & nf_GEN) | nf_INIT;
3409
pari_sp av;
3410
long i, j;
3411
GEN nf, z, p, fa, id, BOUND, U, empty = cgetg(1,t_VEC);
3412
forprime_t S;
3413
ideal_data ID;
3414
GEN (*join_z)(ideal_data*, GEN);
3415
3416
if (do_units)
3417
{
3418
bnf = checkbnf(bnf);
3419
nf = bnf_get_nf(bnf);
3420
join_z = &join_unit;
3421
}
3422
else
3423
{
3424
nf = checknf(bnf);
3425
join_z = big_id? &join_idealinit: &join_ideal;
3426
}
3427
if ((long)bound <= 0) return empty;
3428
id = matid(nf_get_degree(nf));
3429
if (big_id) id = Idealstar(nf,id, istar_flag);
3430
3431
/* z[i] will contain all "objects" of norm i. Depending on flag, this means
3432
* an ideal, a bid, or a couple [bid, log(units)]. Such objects are stored
3433
* in vectors, computed one primary component at a time; join_z
3434
* reconstructs the global object */
3435
BOUND = utoipos(bound);
3436
z = const_vec(bound, empty);
3437
U = do_units? log_prk_units_init(bnf): NULL;
3438
gel(z,1) = mkvec(U? mkvec2(id, empty): id);
3439
ID.nf = nf;
3440
3441
p = cgetipos(3);
3442
u_forprime_init(&S, 2, bound);
3443
av = avma;
3444
while ((p[2] = u_forprime_next(&S)))
3445
{
3446
if (DEBUGLEVEL>1) err_printf("%ld ",p[2]);
3447
fa = idealprimedec_limit_norm(nf, p, BOUND);
3448
for (j = 1; j < lg(fa); j++)
3449
{
3450
GEN pr = gel(fa,j), z2 = leafcopy(z);
3451
ulong Q, q = upr_norm(pr);
3452
long l;
3453
ID.pr = ID.prL = pr;
3454
if (cond && q == 2) { l = 2; Q = 4; } else { l = 1; Q = q; }
3455
for (; Q <= bound; l++, Q *= q) /* add pr^l */
3456
{
3457
ulong iQ;
3458
ID.L = utoipos(l);
3459
if (big_id) {
3460
ID.prL = Idealstarprk(nf, pr, l, istar_flag);
3461
if (U)
3462
ID.emb = Q == 2? empty
3463
: log_prk_units(nf, U, gel(bid_get_sprk(ID.prL),1));
3464
}
3465
for (iQ = Q,i = 1; iQ <= bound; iQ += Q,i++)
3466
concat_join(&gel(z,iQ), gel(z2,i), join_z, &ID);
3467
}
3468
}
3469
if (gc_needed(av,1))
3470
{
3471
if(DEBUGMEM>1) pari_warn(warnmem,"Ideallist");
3472
z = gerepilecopy(av, z);
3473
}
3474
}
3475
return z;
3476
}
3477
GEN
3478
gideallist(GEN bnf, GEN B, long flag)
3479
{
3480
pari_sp av = avma;
3481
if (typ(B) != t_INT)
3482
{
3483
B = gfloor(B);
3484
if (typ(B) != t_INT) pari_err_TYPE("ideallist", B);
3485
if (signe(B) < 0) B = gen_0;
3486
}
3487
if (signe(B) < 0)
3488
{
3489
if (flag != 4) pari_err_IMPL("ideallist with bid for single norm");
3490
return gerepilecopy(av, ideals_by_norm(bnf, absi(B)));
3491
}
3492
if (flag < 0 || flag > 15) pari_err_FLAG("ideallist");
3493
return gerepilecopy(av, Ideallist(bnf, itou(B), flag));
3494
}
3495
GEN
3496
ideallist0(GEN bnf, long bound, long flag)
3497
{
3498
pari_sp av = avma;
3499
if (flag < 0 || flag > 15) pari_err_FLAG("ideallist");
3500
return gerepilecopy(av, Ideallist(bnf, bound, flag));
3501
}
3502
GEN
3503
ideallist(GEN bnf,long bound) { return ideallist0(bnf,bound,4); }
3504
3505
/* bid = for module m (without arch. part), arch = archimedean part.
3506
* Output: bid for [m,arch] */
3507
static GEN
3508
join_bid_arch(GEN nf, GEN bid, GEN archp)
3509
{
3510
pari_sp av = avma;
3511
GEN G, U;
3512
GEN sprk, cyc, y, u1 = NULL, x, sarch, gen;
3513
3514
checkbid(bid);
3515
G = bid_get_grp(bid);
3516
x = bid_get_ideal(bid);
3517
sarch = nfarchstar(nf, bid_get_ideal(bid), archp);
3518
sprk = bid_get_sprk(bid);
3519
3520
gen = (lg(G)>3)? gel(G,3): NULL;
3521
cyc = diagonal_shallow(shallowconcat(gel(G,2), sarch_get_cyc(sarch)));
3522
cyc = ZM_snf_group(cyc, &U, gen? &u1: NULL);
3523
y = bid_grp(nf, u1, cyc, gen, x, sarch);
3524
U = split_U(U, sprk);
3525
y = mkvec5(mkvec2(x, archp), y, gel(bid,3), mkvec2(sprk, sarch), U);
3526
return gerepilecopy(av,y);
3527
}
3528
static GEN
3529
join_arch(ideal_data *D, GEN x) {
3530
return join_bid_arch(D->nf, x, D->archp);
3531
}
3532
static GEN
3533
join_archunit(ideal_data *D, GEN x) {
3534
GEN bid = join_arch(D, gel(x,1)), u = gel(x,2), v = mkvec(D->emb);
3535
if (lg(u) != 1) v = shallowconcat(u, v);
3536
return mkvec2(bid, v);
3537
}
3538
3539
/* L from ideallist, add archimedean part */
3540
GEN
3541
ideallistarch(GEN bnf, GEN L, GEN arch)
3542
{
3543
pari_sp av;
3544
long i, j, l = lg(L), lz;
3545
GEN v, z, V;
3546
ideal_data ID;
3547
GEN (*join_z)(ideal_data*, GEN);
3548
3549
if (typ(L) != t_VEC) pari_err_TYPE("ideallistarch",L);
3550
if (l == 1) return cgetg(1,t_VEC);
3551
z = gel(L,1);
3552
if (typ(z) != t_VEC) pari_err_TYPE("ideallistarch",z);
3553
z = gel(z,1); /* either a bid or [bid,U] */
3554
ID.nf = checknf(bnf);
3555
ID.archp = vec01_to_indices(arch);
3556
if (lg(z) == 3) { /* the latter: do units */
3557
if (typ(z) != t_VEC) pari_err_TYPE("ideallistarch",z);
3558
ID.emb = zm_to_ZM( rowpermute(nfsign_units(bnf,NULL,1), ID.archp) );
3559
join_z = &join_archunit;
3560
} else
3561
join_z = &join_arch;
3562
av = avma; V = cgetg(l, t_VEC);
3563
for (i = 1; i < l; i++)
3564
{
3565
z = gel(L,i); lz = lg(z);
3566
gel(V,i) = v = cgetg(lz,t_VEC);
3567
for (j=1; j<lz; j++) gel(v,j) = join_z(&ID, gel(z,j));
3568
}
3569
return gerepilecopy(av,V);
3570
}
3571
3572