Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28485 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2000 The PARI group.
2
3
This file is part of the PARI/GP package.
4
5
PARI/GP is free software; you can redistribute it and/or modify it under the
6
terms of the GNU General Public License as published by the Free Software
7
Foundation; either version 2 of the License, or (at your option) any later
8
version. It is distributed in the hope that it will be useful, but WITHOUT
9
ANY WARRANTY WHATSOEVER.
10
11
Check the License for details. You should have received a copy of it, along
12
with the package; see the file 'COPYING'. If not, write to the Free Software
13
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14
#include "pari.h"
15
#include "paripriv.h"
16
17
#define DEBUGLEVEL DEBUGLEVEL_alg
18
19
#define dbg_printf(lvl) if (DEBUGLEVEL >= (lvl) + 3) err_printf
20
21
/********************************************************************/
22
/** **/
23
/** ASSOCIATIVE ALGEBRAS, CENTRAL SIMPLE ALGEBRAS **/
24
/** contributed by Aurel Page (2014) **/
25
/** **/
26
/********************************************************************/
27
static GEN alg_subalg(GEN al, GEN basis);
28
static GEN alg_maximal_primes(GEN al, GEN P);
29
static GEN algnatmultable(GEN al, long D);
30
static GEN _tablemul_ej(GEN mt, GEN x, long j);
31
static GEN _tablemul_ej_Fp(GEN mt, GEN x, long j, GEN p);
32
static GEN _tablemul_ej_Fl(GEN mt, GEN x, long j, ulong p);
33
static ulong algtracei(GEN mt, ulong p, ulong expo, ulong modu);
34
static GEN alg_pmaximal(GEN al, GEN p);
35
static GEN alg_maximal(GEN al);
36
static GEN algtracematrix(GEN al);
37
static GEN algtableinit_i(GEN mt0, GEN p);
38
static GEN algbasisrightmultable(GEN al, GEN x);
39
static GEN algabstrace(GEN al, GEN x);
40
static GEN algbasismul(GEN al, GEN x, GEN y);
41
static GEN algbasismultable(GEN al, GEN x);
42
static GEN algbasismultable_Flm(GEN mt, GEN x, ulong m);
43
44
static int
45
checkalg_i(GEN al)
46
{
47
GEN mt, rnf;
48
if (typ(al) != t_VEC || lg(al) != 12) return 0;
49
mt = alg_get_multable(al);
50
if (typ(mt) != t_VEC || lg(mt) == 1 || typ(gel(mt,1)) != t_MAT) return 0;
51
rnf = alg_get_splittingfield(al);
52
if (isintzero(rnf) || !gequal0(alg_get_char(al))) return 1;
53
if (typ(gel(al,2)) != t_VEC || lg(gel(al,2)) == 1) return 0;
54
/* not checkrnf_i: beware placeholder from alg_csa_table */
55
return typ(rnf)==t_VEC && lg(rnf)==13;
56
}
57
void
58
checkalg(GEN al)
59
{ if (!checkalg_i(al)) pari_err_TYPE("checkalg [please apply alginit()]",al); }
60
61
static int
62
checklat_i(GEN al, GEN lat)
63
{
64
long N,i,j;
65
GEN m,t,c;
66
if (typ(lat)!=t_VEC || lg(lat) != 3) return 0;
67
t = gel(lat,2);
68
if (typ(t) != t_INT && typ(t) != t_FRAC) return 0;
69
if (gsigne(t)<=0) return 0;
70
m = gel(lat,1);
71
if (typ(m) != t_MAT) return 0;
72
N = alg_get_absdim(al);
73
if (lg(m)-1 != N || lg(gel(m,1))-1 != N) return 0;
74
for (i=1; i<=N; i++)
75
for (j=1; j<=N; j++) {
76
c = gcoeff(m,i,j);
77
if (typ(c) != t_INT) return 0;
78
if (j<i && signe(gcoeff(m,i,j))) return 0;
79
if (i==j && !signe(gcoeff(m,i,j))) return 0;
80
}
81
return 1;
82
}
83
void checklat(GEN al, GEN lat)
84
{ if (!checklat_i(al,lat)) pari_err_TYPE("checklat [please apply alglathnf()]", lat); }
85
86
/** ACCESSORS **/
87
long
88
alg_type(GEN al)
89
{
90
if (isintzero(alg_get_splittingfield(al)) || !gequal0(alg_get_char(al))) return al_TABLE;
91
switch(typ(gmael(al,2,1))) {
92
case t_MAT: return al_CSA;
93
case t_INT:
94
case t_FRAC:
95
case t_POL:
96
case t_POLMOD: return al_CYCLIC;
97
default: return al_NULL;
98
}
99
return -1; /*LCOV_EXCL_LINE*/
100
}
101
long
102
algtype(GEN al)
103
{ return checkalg_i(al)? alg_type(al): al_NULL; }
104
105
/* absdim == dim for al_TABLE. */
106
long
107
alg_get_dim(GEN al)
108
{
109
long d;
110
switch(alg_type(al)) {
111
case al_TABLE: return lg(alg_get_multable(al))-1;
112
case al_CSA: return lg(alg_get_relmultable(al))-1;
113
case al_CYCLIC: d = alg_get_degree(al); return d*d;
114
default: pari_err_TYPE("alg_get_dim", al);
115
}
116
return -1; /*LCOV_EXCL_LINE*/
117
}
118
119
long
120
alg_get_absdim(GEN al)
121
{
122
switch(alg_type(al)) {
123
case al_TABLE: return lg(alg_get_multable(al))-1;
124
case al_CSA: return alg_get_dim(al)*nf_get_degree(alg_get_center(al));
125
case al_CYCLIC:
126
return rnf_get_absdegree(alg_get_splittingfield(al))*alg_get_degree(al);
127
default: pari_err_TYPE("alg_get_absdim", al);
128
}
129
return -1;/*LCOV_EXCL_LINE*/
130
}
131
132
long
133
algdim(GEN al, long abs)
134
{
135
checkalg(al);
136
if (abs) return alg_get_absdim(al);
137
return alg_get_dim(al);
138
}
139
140
/* only cyclic */
141
GEN
142
alg_get_auts(GEN al)
143
{
144
if (alg_type(al) != al_CYCLIC)
145
pari_err_TYPE("alg_get_auts [noncyclic algebra]", al);
146
return gel(al,2);
147
}
148
GEN
149
alg_get_aut(GEN al)
150
{
151
if (alg_type(al) != al_CYCLIC)
152
pari_err_TYPE("alg_get_aut [noncyclic algebra]", al);
153
return gel(alg_get_auts(al),1);
154
}
155
GEN
156
algaut(GEN al) { checkalg(al); return alg_get_aut(al); }
157
GEN
158
alg_get_b(GEN al)
159
{
160
if (alg_type(al) != al_CYCLIC)
161
pari_err_TYPE("alg_get_b [noncyclic algebra]", al);
162
return gel(al,3);
163
}
164
GEN
165
algb(GEN al) { checkalg(al); return alg_get_b(al); }
166
167
/* only CSA */
168
GEN
169
alg_get_relmultable(GEN al)
170
{
171
if (alg_type(al) != al_CSA)
172
pari_err_TYPE("alg_get_relmultable [algebra not given via mult. table]", al);
173
return gel(al,2);
174
}
175
GEN
176
algrelmultable(GEN al) { checkalg(al); return alg_get_relmultable(al); }
177
GEN
178
alg_get_splittingdata(GEN al)
179
{
180
if (alg_type(al) != al_CSA)
181
pari_err_TYPE("alg_get_splittingdata [algebra not given via mult. table]",al);
182
return gel(al,3);
183
}
184
GEN
185
algsplittingdata(GEN al) { checkalg(al); return alg_get_splittingdata(al); }
186
GEN
187
alg_get_splittingbasis(GEN al)
188
{
189
if (alg_type(al) != al_CSA)
190
pari_err_TYPE("alg_get_splittingbasis [algebra not given via mult. table]",al);
191
return gmael(al,3,2);
192
}
193
GEN
194
alg_get_splittingbasisinv(GEN al)
195
{
196
if (alg_type(al) != al_CSA)
197
pari_err_TYPE("alg_get_splittingbasisinv [algebra not given via mult. table]",al);
198
return gmael(al,3,3);
199
}
200
201
/* only cyclic and CSA */
202
GEN
203
alg_get_splittingfield(GEN al) { return gel(al,1); }
204
GEN
205
algsplittingfield(GEN al)
206
{
207
long ta;
208
checkalg(al);
209
ta = alg_type(al);
210
if (ta != al_CYCLIC && ta != al_CSA)
211
pari_err_TYPE("alg_get_splittingfield [use alginit]",al);
212
return alg_get_splittingfield(al);
213
}
214
long
215
alg_get_degree(GEN al)
216
{
217
long ta;
218
ta = alg_type(al);
219
if (ta != al_CYCLIC && ta != al_CSA)
220
pari_err_TYPE("alg_get_degree [use alginit]",al);
221
return rnf_get_degree(alg_get_splittingfield(al));
222
}
223
long
224
algdegree(GEN al)
225
{
226
checkalg(al);
227
return alg_get_degree(al);
228
}
229
230
GEN
231
alg_get_center(GEN al)
232
{
233
long ta;
234
ta = alg_type(al);
235
if (ta != al_CSA && ta != al_CYCLIC)
236
pari_err_TYPE("alg_get_center [use alginit]",al);
237
return rnf_get_nf(alg_get_splittingfield(al));
238
}
239
GEN
240
alg_get_splitpol(GEN al)
241
{
242
long ta = alg_type(al);
243
if (ta != al_CYCLIC && ta != al_CSA)
244
pari_err_TYPE("alg_get_splitpol [use alginit]",al);
245
return rnf_get_pol(alg_get_splittingfield(al));
246
}
247
GEN
248
alg_get_abssplitting(GEN al)
249
{
250
long ta = alg_type(al), prec;
251
if (ta != al_CYCLIC && ta != al_CSA)
252
pari_err_TYPE("alg_get_abssplitting [use alginit]",al);
253
prec = nf_get_prec(alg_get_center(al));
254
return rnf_build_nfabs(alg_get_splittingfield(al), prec);
255
}
256
GEN
257
alg_get_hasse_i(GEN al)
258
{
259
long ta = alg_type(al);
260
if (ta != al_CYCLIC && ta != al_CSA)
261
pari_err_TYPE("alg_get_hasse_i [use alginit]",al);
262
if (ta == al_CSA) pari_err_IMPL("computation of Hasse invariants over table CSA");
263
return gel(al,4);
264
}
265
GEN
266
alghassei(GEN al) { checkalg(al); return alg_get_hasse_i(al); }
267
GEN
268
alg_get_hasse_f(GEN al)
269
{
270
long ta = alg_type(al);
271
if (ta != al_CYCLIC && ta != al_CSA)
272
pari_err_TYPE("alg_get_hasse_f [use alginit]",al);
273
if (ta == al_CSA) pari_err_IMPL("computation of Hasse invariants over table CSA");
274
return gel(al,5);
275
}
276
GEN
277
alghassef(GEN al) { checkalg(al); return alg_get_hasse_f(al); }
278
279
/* all types */
280
GEN
281
alg_get_basis(GEN al) { return gel(al,7); }
282
GEN
283
algbasis(GEN al) { checkalg(al); return alg_get_basis(al); }
284
GEN
285
alg_get_invbasis(GEN al) { return gel(al,8); }
286
GEN
287
alginvbasis(GEN al) { checkalg(al); return alg_get_invbasis(al); }
288
GEN
289
alg_get_multable(GEN al) { return gel(al,9); }
290
GEN
291
algmultable(GEN al) { checkalg(al); return alg_get_multable(al); }
292
GEN
293
alg_get_char(GEN al) { return gel(al,10); }
294
GEN
295
algchar(GEN al) { checkalg(al); return alg_get_char(al); }
296
GEN
297
alg_get_tracebasis(GEN al) { return gel(al,11); }
298
299
/* lattices */
300
GEN
301
alglat_get_primbasis(GEN lat) { return gel(lat,1); }
302
GEN
303
alglat_get_scalar(GEN lat) { return gel(lat,2); }
304
305
/** ADDITIONAL **/
306
307
/* no garbage collection */
308
static GEN
309
backtrackfacto(GEN y0, long n, GEN red, GEN pl, GEN nf, GEN data, int (*test)(GEN,GEN), GEN* fa, GEN N, GEN I)
310
{
311
long b, i;
312
ulong lim = 1UL << 17;
313
long *v = new_chunk(n+1);
314
pari_sp av = avma;
315
for (b = 0;; b += (2*b)/(3*n) + 1)
316
{
317
GEN ny, y1, y2;
318
set_avma(av);
319
for (i = 1; i <= n; i++) v[i] = -b;
320
v[n]--;
321
for(;;)
322
{
323
i = n;
324
while (i > 0)
325
{ if (v[i] == b) v[i--] = -b; else { v[i]++; break; } }
326
if (i==0) break;
327
328
y1 = y0;
329
for (i = 1; i <= n; i++) y1 = nfadd(nf, y1, ZC_z_mul(gel(red,i), v[i]));
330
if (!nfchecksigns(nf, y1, pl)) continue;
331
332
ny = absi_shallow(nfnorm(nf, y1));
333
if (!signe(ny)) continue;
334
ny = diviiexact(ny, gcdii(ny, N));
335
if (!Z_issmooth(ny, lim)) continue;
336
337
y2 = idealdivexact(nf, y1, idealadd(nf,y1,I));
338
*fa = idealfactor(nf, y2);
339
if (!data || test(data,*fa)) return y1;
340
}
341
}
342
}
343
344
/* if data == NULL, the test is skipped */
345
/* in the test, the factorization does not contain the known factors */
346
static GEN
347
factoredextchinesetest(GEN nf, GEN x, GEN y, GEN pl, GEN* fa, GEN data, int (*test)(GEN,GEN))
348
{
349
pari_sp av = avma;
350
long n,i;
351
GEN x1, y0, y1, red, N, I, P = gel(x,1), E = gel(x,2);
352
n = nf_get_degree(nf);
353
x = idealchineseinit(nf, mkvec2(x,pl));
354
x1 = gel(x,1);
355
red = lg(x1) == 1? matid(n): gel(x1,1);
356
y0 = idealchinese(nf, x, y);
357
358
E = shallowcopy(E);
359
if (!gequal0(y0))
360
for (i=1; i<lg(E); i++)
361
{
362
long v = nfval(nf,y0,gel(P,i));
363
if (cmpsi(v, gel(E,i)) < 0) gel(E,i) = stoi(v);
364
}
365
/* N and I : known factors */
366
I = factorbackprime(nf, P, E);
367
N = idealnorm(nf,I);
368
369
y1 = backtrackfacto(y0, n, red, pl, nf, data, test, fa, N, I);
370
371
/* restore known factors */
372
for (i=1; i<lg(E); i++) gel(E,i) = stoi(nfval(nf,y1,gel(P,i)));
373
*fa = famat_reduce(famat_mul_shallow(*fa, mkmat2(P, E)));
374
375
gerepileall(av, 2, &y1, fa);
376
return y1;
377
}
378
379
static GEN
380
factoredextchinese(GEN nf, GEN x, GEN y, GEN pl, GEN* fa)
381
{ return factoredextchinesetest(nf,x,y,pl,fa,NULL,NULL); }
382
383
/** OPERATIONS ON ASSOCIATIVE ALGEBRAS algebras.c **/
384
385
/*
386
Convention:
387
(K/F,sigma,b) = sum_{i=0..n-1} u^i*K
388
t*u = u*sigma(t)
389
390
Natural basis:
391
1<=i<=d*n^2
392
b_i = u^((i-1)/(dn))*ZKabs.((i-1)%(dn)+1)
393
394
Integral basis:
395
Basis of some order.
396
397
al:
398
1- rnf of the cyclic splitting field of degree n over the center nf of degree d
399
2- VEC of aut^i 1<=i<=n
400
3- b in nf
401
4- infinite hasse invariants (mod n) : VECSMALL of size r1, values only 0 or n/2 (if integral)
402
5- finite hasse invariants (mod n) : VEC[VEC of primes, VECSMALL of hasse inv mod n]
403
6- nf of the splitting field (absolute)
404
7* dn^2*dn^2 matrix expressing the integral basis in terms of the natural basis
405
8* dn^2*dn^2 matrix expressing the natural basis in terms of the integral basis
406
9* VEC of dn^2 matrices giving the dn^2*dn^2 left multiplication tables of the integral basis
407
10* characteristic of the base field (used only for algebras given by a multiplication table)
408
11* trace of basis elements
409
410
If al is given by a multiplication table (al_TABLE), only the * fields are present.
411
*/
412
413
/* assumes same center and same variable */
414
/* currently only works for coprime degrees */
415
GEN
416
algtensor(GEN al1, GEN al2, long maxord) {
417
pari_sp av = avma;
418
long v, k, d1, d2;
419
GEN nf, P1, P2, aut1, aut2, b1, b2, C, rnf, aut, b, x1, x2, al;
420
421
checkalg(al1);
422
checkalg(al2);
423
if (alg_type(al1) != al_CYCLIC || alg_type(al2) != al_CYCLIC)
424
pari_err_IMPL("tensor of noncyclic algebras"); /* TODO: do it. */
425
426
nf=alg_get_center(al1);
427
if (!gequal(alg_get_center(al2),nf))
428
pari_err_OP("tensor product [not the same center]", al1, al2);
429
430
P1=alg_get_splitpol(al1); aut1=alg_get_aut(al1); b1=alg_get_b(al1);
431
P2=alg_get_splitpol(al2); aut2=alg_get_aut(al2); b2=alg_get_b(al2);
432
v=varn(P1);
433
434
d1=alg_get_degree(al1);
435
d2=alg_get_degree(al2);
436
if (ugcd(d1,d2) != 1)
437
pari_err_IMPL("tensor of cylic algebras of noncoprime degrees"); /* TODO */
438
439
if (d1==1) return gcopy(al2);
440
if (d2==1) return gcopy(al1);
441
442
C = nfcompositum(nf, P1, P2, 3);
443
rnf = rnfinit(nf,gel(C,1));
444
x1 = gel(C,2);
445
x2 = gel(C,3);
446
k = itos(gel(C,4));
447
aut = gadd(gsubst(aut2,v,x2),gmulsg(k,gsubst(aut1,v,x1)));
448
b = nfmul(nf,nfpow_u(nf,b1,d2),nfpow_u(nf,b2,d1));
449
al = alg_cyclic(rnf,aut,b,maxord);
450
return gerepilecopy(av,al);
451
}
452
453
/* M an n x d Flm of rank d, n >= d. Initialize Mx = y solver */
454
static GEN
455
Flm_invimage_init(GEN M, ulong p)
456
{
457
GEN v = Flm_indexrank(M, p), perm = gel(v,1);
458
GEN MM = rowpermute(M, perm); /* square invertible */
459
return mkvec2(Flm_inv(MM,p), perm);
460
}
461
/* assume Mx = y has a solution, v = Flm_invimage_init(M,p); return x */
462
static GEN
463
Flm_invimage_pre(GEN v, GEN y, ulong p)
464
{
465
GEN inv = gel(v,1), perm = gel(v,2);
466
return Flm_Flc_mul(inv, vecsmallpermute(y, perm), p);
467
}
468
469
GEN
470
algradical(GEN al)
471
{
472
pari_sp av = avma;
473
GEN I, x, traces, K, MT, P, mt;
474
long l,i,ni, n;
475
ulong modu, expo, p;
476
checkalg(al);
477
P = alg_get_char(al);
478
mt = alg_get_multable(al);
479
n = alg_get_absdim(al);
480
dbg_printf(1)("algradical: char=%Ps, dim=%d\n", P, n);
481
traces = algtracematrix(al);
482
if (!signe(P))
483
{
484
dbg_printf(2)(" char 0, computing kernel...\n");
485
K = ker(traces);
486
dbg_printf(2)(" ...done.\n");
487
ni = lg(K)-1; if (!ni) return gc_const(av, gen_0);
488
return gerepileupto(av, K);
489
}
490
dbg_printf(2)(" char>0, computing kernel...\n");
491
K = FpM_ker(traces, P);
492
dbg_printf(2)(" ...done.\n");
493
ni = lg(K)-1; if (!ni) return gc_const(av, gen_0);
494
if (abscmpiu(P,n)>0) return gerepileupto(av, K);
495
496
/* tough case, p <= n. Ronyai's algorithm */
497
p = P[2]; l = 1;
498
expo = p; modu = p*p;
499
dbg_printf(2)(" char>0, hard case.\n");
500
while (modu<=(ulong)n) { l++; modu *= p; }
501
MT = ZMV_to_FlmV(mt, modu);
502
I = ZM_to_Flm(K,p); /* I_0 */
503
for (i=1; i<=l; i++) {/*compute I_i, expo = p^i, modu = p^(l+1) > n*/
504
long j, lig,col;
505
GEN v = cgetg(ni+1, t_VECSMALL);
506
GEN invI = Flm_invimage_init(I, p);
507
dbg_printf(2)(" computing I_%d:\n", i);
508
traces = cgetg(ni+1,t_MAT);
509
for (j = 1; j <= ni; j++)
510
{
511
GEN M = algbasismultable_Flm(MT, gel(I,j), modu);
512
uel(v,j) = algtracei(M, p,expo,modu);
513
}
514
for (col=1; col<=ni; col++)
515
{
516
GEN t = cgetg(n+1,t_VECSMALL); gel(traces,col) = t;
517
x = gel(I, col); /*col-th basis vector of I_{i-1}*/
518
for (lig=1; lig<=n; lig++)
519
{
520
GEN y = _tablemul_ej_Fl(MT,x,lig,p);
521
GEN z = Flm_invimage_pre(invI, y, p);
522
uel(t,lig) = Flv_dotproduct(v, z, p);
523
}
524
}
525
dbg_printf(2)(" computing kernel...\n");
526
K = Flm_ker(traces, p);
527
dbg_printf(2)(" ...done.\n");
528
ni = lg(K)-1; if (!ni) return gc_const(av, gen_0);
529
I = Flm_mul(I,K,p);
530
expo *= p;
531
}
532
return Flm_to_ZM(I);
533
}
534
535
/* compute the multiplication table of the element x, where mt is a
536
* multiplication table in an arbitrary ring */
537
static GEN
538
Rgmultable(GEN mt, GEN x)
539
{
540
long i, l = lg(x);
541
GEN z = NULL;
542
for (i = 1; i < l; i++)
543
{
544
GEN c = gel(x,i);
545
if (!gequal0(c))
546
{
547
GEN M = RgM_Rg_mul(gel(mt,i),c);
548
z = z? RgM_add(z, M): M;
549
}
550
}
551
return z;
552
}
553
554
static GEN
555
change_Rgmultable(GEN mt, GEN P, GEN Pi)
556
{
557
GEN mt2;
558
long lmt = lg(mt), i;
559
mt2 = cgetg(lmt,t_VEC);
560
for (i=1;i<lmt;i++) {
561
GEN mti = Rgmultable(mt,gel(P,i));
562
gel(mt2,i) = RgM_mul(Pi, RgM_mul(mti,P));
563
}
564
return mt2;
565
}
566
567
static GEN
568
alg_quotient0(GEN al, GEN S, GEN Si, long nq, GEN p, long maps)
569
{
570
GEN mt = cgetg(nq+1,t_VEC), P, Pi, d;
571
long i;
572
dbg_printf(3)(" alg_quotient0: char=%Ps, dim=%d, dim I=%d\n", p, alg_get_absdim(al), lg(S)-1);
573
for (i=1; i<=nq; i++) {
574
GEN mti = algbasismultable(al,gel(S,i));
575
if (signe(p)) gel(mt,i) = FpM_mul(Si, FpM_mul(mti,S,p), p);
576
else gel(mt,i) = RgM_mul(Si, RgM_mul(mti,S));
577
}
578
if (!signe(p) && !isint1(Q_denom(mt))) {
579
dbg_printf(3)(" bad case: denominator=%Ps\n", Q_denom(mt));
580
P = Q_remove_denom(Si,&d);
581
P = ZM_hnf(P);
582
P = RgM_Rg_div(P,d);
583
Pi = RgM_inv(P);
584
mt = change_Rgmultable(mt,P,Pi);
585
Si = RgM_mul(P,Si);
586
S = RgM_mul(S,Pi);
587
}
588
al = algtableinit_i(mt,p);
589
if (maps) al = mkvec3(al,Si,S); /* algebra, proj, lift */
590
return al;
591
}
592
593
/* quotient of an algebra by a nontrivial two-sided ideal */
594
GEN
595
alg_quotient(GEN al, GEN I, long maps)
596
{
597
pari_sp av = avma;
598
GEN p, IS, ISi, S, Si;
599
long n, ni;
600
601
checkalg(al);
602
p = alg_get_char(al);
603
n = alg_get_absdim(al);
604
ni = lg(I)-1;
605
606
/* force first vector of complement to be the identity */
607
IS = shallowconcat(I, gcoeff(alg_get_multable(al),1,1));
608
if (signe(p)) {
609
IS = FpM_suppl(IS,p);
610
ISi = FpM_inv(IS,p);
611
}
612
else {
613
IS = suppl(IS);
614
ISi = RgM_inv(IS);
615
}
616
S = vecslice(IS, ni+1, n);
617
Si = rowslice(ISi, ni+1, n);
618
return gerepilecopy(av, alg_quotient0(al, S, Si, n-ni, p, maps));
619
}
620
621
static GEN
622
image_keep_first(GEN m, GEN p) /* assume first column is nonzero or m==0, no GC */
623
{
624
GEN ir, icol, irow, M, c, x;
625
long i;
626
if (gequal0(gel(m,1))) return zeromat(nbrows(m),0);
627
628
if (signe(p)) ir = FpM_indexrank(m,p);
629
else ir = indexrank(m);
630
631
icol = gel(ir,2);
632
if (icol[1]==1) return extract0(m,icol,NULL);
633
634
irow = gel(ir,1);
635
M = extract0(m, irow, icol);
636
c = extract0(gel(m,1), irow, NULL);
637
if (signe(p)) x = FpM_FpC_invimage(M,c,p);
638
else x = inverseimage(M,c); /* TODO modulo a small prime */
639
640
for (i=1; i<lg(x); i++)
641
{
642
if (!gequal0(gel(x,i)))
643
{
644
icol[i] = 1;
645
vecsmall_sort(icol);
646
return extract0(m,icol,NULL);
647
}
648
}
649
650
return NULL; /* LCOV_EXCL_LINE */
651
}
652
653
/* z[1],...z[nz] central elements such that z[1]A + z[2]A + ... + z[nz]A = A
654
* is a direct sum. idempotents ==> first basis element is identity */
655
GEN
656
alg_centralproj(GEN al, GEN z, long maps)
657
{
658
pari_sp av = avma;
659
GEN S, U, Ui, alq, p;
660
long i, iu, lz = lg(z);
661
662
checkalg(al);
663
if (typ(z) != t_VEC) pari_err_TYPE("alcentralproj",z);
664
p = alg_get_char(al);
665
dbg_printf(3)(" alg_centralproj: char=%Ps, dim=%d, #z=%d\n", p, alg_get_absdim(al), lz-1);
666
S = cgetg(lz,t_VEC); /* S[i] = Im(z_i) */
667
for (i=1; i<lz; i++)
668
{
669
GEN mti = algbasismultable(al, gel(z,i));
670
gel(S,i) = image_keep_first(mti,p);
671
}
672
U = shallowconcat1(S); /* U = [Im(z_1)|Im(z_2)|...|Im(z_nz)], n x n */
673
if (lg(U)-1 < alg_get_absdim(al)) pari_err_TYPE("alcentralproj [z[i]'s not surjective]",z);
674
if (signe(p)) Ui = FpM_inv(U,p);
675
else Ui = RgM_inv(U);
676
if (!Ui) pari_err_BUG("alcentralproj"); /*LCOV_EXCL_LINE*/
677
678
alq = cgetg(lz,t_VEC);
679
for (iu=0,i=1; i<lz; i++)
680
{
681
long nq = lg(gel(S,i))-1, ju = iu + nq;
682
GEN Si = rowslice(Ui, iu+1, ju);
683
gel(alq, i) = alg_quotient0(al,gel(S,i),Si,nq,p,maps);
684
iu = ju;
685
}
686
return gerepilecopy(av, alq);
687
}
688
689
/* al is an al_TABLE */
690
static GEN
691
algtablecenter(GEN al)
692
{
693
pari_sp av = avma;
694
long n, i, j, k, ic;
695
GEN C, cij, mt, p;
696
697
n = alg_get_absdim(al);
698
mt = alg_get_multable(al);
699
p = alg_get_char(al);
700
C = cgetg(n+1,t_MAT);
701
for (j=1; j<=n; j++)
702
{
703
gel(C,j) = cgetg(n*n-n+1,t_COL);
704
ic = 1;
705
for (i=2; i<=n; i++) {
706
if (signe(p)) cij = FpC_sub(gmael(mt,i,j),gmael(mt,j,i),p);
707
else cij = RgC_sub(gmael(mt,i,j),gmael(mt,j,i));
708
for (k=1; k<=n; k++, ic++) gcoeff(C,ic,j) = gel(cij, k);
709
}
710
}
711
if (signe(p)) return gerepileupto(av, FpM_ker(C,p));
712
else return gerepileupto(av, ker(C));
713
}
714
715
GEN
716
algcenter(GEN al)
717
{
718
checkalg(al);
719
if (alg_type(al)==al_TABLE) return algtablecenter(al);
720
return alg_get_center(al);
721
}
722
723
/* Only in positive characteristic. Assumes that al is semisimple. */
724
GEN
725
algprimesubalg(GEN al)
726
{
727
pari_sp av = avma;
728
GEN p, Z, F, K;
729
long nz, i;
730
checkalg(al);
731
p = alg_get_char(al);
732
if (!signe(p)) pari_err_DOMAIN("algprimesubalg","characteristic","=",gen_0,p);
733
734
Z = algtablecenter(al);
735
nz = lg(Z)-1;
736
if (nz==1) return Z;
737
738
F = cgetg(nz+1, t_MAT);
739
for (i=1; i<=nz; i++) {
740
GEN zi = gel(Z,i);
741
gel(F,i) = FpC_sub(algpow(al,zi,p),zi,p);
742
}
743
K = FpM_ker(F,p);
744
return gerepileupto(av, FpM_mul(Z,K,p));
745
}
746
747
static GEN
748
out_decompose(GEN t, GEN Z, GEN P, GEN p)
749
{
750
GEN ali = gel(t,1), projm = gel(t,2), liftm = gel(t,3), pZ;
751
if (signe(p)) pZ = FpM_image(FpM_mul(projm,Z,p),p);
752
else pZ = image(RgM_mul(projm,Z));
753
return mkvec5(ali, projm, liftm, pZ, P);
754
}
755
/* fa factorization of charpol(x) */
756
static GEN
757
alg_decompose_from_facto(GEN al, GEN x, GEN fa, GEN Z, long mini)
758
{
759
long k = lgcols(fa)-1, k2 = mini? 1: k/2;
760
GEN v1 = rowslice(fa,1,k2);
761
GEN v2 = rowslice(fa,k2+1,k);
762
GEN alq, P, Q, p = alg_get_char(al);
763
dbg_printf(3)(" alg_decompose_from_facto\n");
764
if (signe(p)) {
765
P = FpXV_factorback(gel(v1,1), gel(v1,2), p, 0);
766
Q = FpXV_factorback(gel(v2,1), gel(v2,2), p, 0);
767
P = FpX_mul(P, FpXQ_inv(P,Q,p), p);
768
}
769
else {
770
P = factorback(v1);
771
Q = factorback(v2);
772
P = RgX_mul(P, RgXQ_inv(P,Q));
773
}
774
P = algpoleval(al, P, x);
775
if (signe(p)) Q = FpC_sub(col_ei(lg(P)-1,1), P, p);
776
else Q = gsub(gen_1, P);
777
if (gequal0(P) || gequal0(Q)) return NULL;
778
alq = alg_centralproj(al, mkvec2(P,Q), 1);
779
780
P = out_decompose(gel(alq,1), Z, P, p); if (mini) return P;
781
Q = out_decompose(gel(alq,2), Z, Q, p);
782
return mkvec2(P,Q);
783
}
784
785
static GEN
786
random_pm1(long n)
787
{
788
GEN z = cgetg(n+1,t_VECSMALL);
789
long i;
790
for (i = 1; i <= n; i++) z[i] = random_bits(5)%3 - 1;
791
return z;
792
}
793
794
static GEN alg_decompose(GEN al, GEN Z, long mini, GEN* pt_primelt);
795
/* Try to split al using x's charpoly. Return gen_0 if simple, NULL if failure.
796
* And a splitting otherwise
797
* If pt_primelt!=NULL, compute a primitive element of the center when simple */
798
static GEN
799
try_fact(GEN al, GEN x, GEN zx, GEN Z, GEN Zal, long mini, GEN* pt_primelt)
800
{
801
GEN z, dec0, dec1, cp = algcharpoly(Zal,zx,0,1), fa, p = alg_get_char(al);
802
long nfa, e;
803
dbg_printf(3)(" try_fact: zx=%Ps\n", zx);
804
if (signe(p)) fa = FpX_factor(cp,p);
805
else fa = factor(cp);
806
dbg_printf(3)(" charpoly=%Ps\n", fa);
807
nfa = nbrows(fa);
808
if (nfa == 1) {
809
if (signe(p)) e = gel(fa,2)[1];
810
else e = itos(gcoeff(fa,1,2));
811
if (e == 1) {
812
if (pt_primelt != NULL) *pt_primelt = mkvec2(x, cp);
813
return gen_0;
814
}
815
else return NULL;
816
}
817
dec0 = alg_decompose_from_facto(al, x, fa, Z, mini);
818
if (!dec0) return NULL;
819
if (!mini) return dec0;
820
dec1 = alg_decompose(gel(dec0,1), gel(dec0,4), 1, pt_primelt);
821
z = gel(dec0,5);
822
if (!isintzero(dec1)) {
823
if (signe(p)) z = FpM_FpC_mul(gel(dec0,3),dec1,p);
824
else z = RgM_RgC_mul(gel(dec0,3),dec1);
825
}
826
return z;
827
}
828
static GEN
829
randcol(long n, GEN b)
830
{
831
GEN N = addiu(shifti(b,1), 1);
832
long i;
833
GEN res = cgetg(n+1,t_COL);
834
for (i=1; i<=n; i++)
835
{
836
pari_sp av = avma;
837
gel(res,i) = gerepileuptoint(av, subii(randomi(N),b));
838
}
839
return res;
840
}
841
/* Return gen_0 if already simple. mini: only returns a central idempotent
842
* corresponding to one simple factor
843
* if pt_primelt!=NULL, sets it to a primitive element of the center when simple */
844
static GEN
845
alg_decompose(GEN al, GEN Z, long mini, GEN* pt_primelt)
846
{
847
pari_sp av;
848
GEN Zal, x, zx, rand, dec0, B, p;
849
long i, nz = lg(Z)-1;
850
851
if (nz == 1) {
852
if (pt_primelt != 0) *pt_primelt = mkvec2(zerocol(alg_get_dim(al)), pol_x(0));
853
return gen_0;
854
}
855
p = alg_get_char(al);
856
dbg_printf(2)(" alg_decompose: char=%Ps, dim=%d, dim Z=%d\n", p, alg_get_absdim(al), nz);
857
Zal = alg_subalg(al,Z);
858
Z = gel(Zal,2);
859
Zal = gel(Zal,1);
860
av = avma;
861
862
rand = random_pm1(nz);
863
zx = zc_to_ZC(rand);
864
if (signe(p)) {
865
zx = FpC_red(zx,p);
866
x = ZM_zc_mul(Z,rand);
867
x = FpC_red(x,p);
868
}
869
else x = RgM_zc_mul(Z,rand);
870
dec0 = try_fact(al,x,zx,Z,Zal,mini,pt_primelt);
871
if (dec0) return dec0;
872
set_avma(av);
873
874
for (i=2; i<=nz; i++)
875
{
876
dec0 = try_fact(al,gel(Z,i),col_ei(nz,i),Z,Zal,mini,pt_primelt);
877
if (dec0) return dec0;
878
set_avma(av);
879
}
880
B = int2n(10);
881
for (;;)
882
{
883
GEN x = randcol(nz,B), zx = ZM_ZC_mul(Z,x);
884
dec0 = try_fact(al,x,zx,Z,Zal,mini,pt_primelt);
885
if (dec0) return dec0;
886
set_avma(av);
887
}
888
}
889
890
static GEN
891
alg_decompose_total(GEN al, GEN Z, long maps)
892
{
893
GEN dec, sc, p;
894
long i;
895
896
dec = alg_decompose(al, Z, 0, NULL);
897
if (isintzero(dec))
898
{
899
if (maps) {
900
long n = alg_get_absdim(al);
901
al = mkvec3(al, matid(n), matid(n));
902
}
903
return mkvec(al);
904
}
905
p = alg_get_char(al); if (!signe(p)) p = NULL;
906
sc = cgetg(lg(dec), t_VEC);
907
for (i=1; i<lg(sc); i++) {
908
GEN D = gel(dec,i), a = gel(D,1), Za = gel(D,4);
909
GEN S = alg_decompose_total(a, Za, maps);
910
gel(sc,i) = S;
911
if (maps)
912
{
913
GEN projm = gel(D,2), liftm = gel(D,3);
914
long j, lS = lg(S);
915
for (j=1; j<lS; j++)
916
{
917
GEN Sj = gel(S,j), p2 = gel(Sj,2), l2 = gel(Sj,3);
918
if (p) p2 = FpM_mul(p2, projm, p);
919
else p2 = RgM_mul(p2, projm);
920
if (p) l2 = FpM_mul(liftm, l2, p);
921
else l2 = RgM_mul(liftm, l2);
922
gel(Sj,2) = p2;
923
gel(Sj,3) = l2;
924
}
925
}
926
}
927
return shallowconcat1(sc);
928
}
929
930
static GEN
931
alg_subalg(GEN al, GEN basis)
932
{
933
GEN invbasis, mt, p = alg_get_char(al);
934
long i, j, n = lg(basis)-1;
935
936
if (!signe(p)) p = NULL;
937
basis = shallowmatconcat(mkvec2(col_ei(n,1), basis));
938
if (p)
939
{
940
basis = image_keep_first(basis,p);
941
invbasis = FpM_inv(basis,p);
942
}
943
else
944
{ /* FIXME use an integral variant of image_keep_first */
945
basis = QM_ImQ_hnf(basis);
946
invbasis = RgM_inv(basis);
947
}
948
mt = cgetg(n+1,t_VEC);
949
gel(mt,1) = matid(n);
950
for (i = 2; i <= n; i++)
951
{
952
GEN mtx = cgetg(n+1,t_MAT), x = gel(basis,i);
953
gel(mtx,1) = col_ei(n,i);
954
for (j = 2; j <= n; j++)
955
{
956
GEN xy = algmul(al, x, gel(basis,j));
957
if (p) gel(mtx,j) = FpM_FpC_mul(invbasis, xy, p);
958
else gel(mtx,j) = RgM_RgC_mul(invbasis, xy);
959
}
960
gel(mt,i) = mtx;
961
}
962
return mkvec2(algtableinit_i(mt,p), basis);
963
}
964
965
GEN
966
algsubalg(GEN al, GEN basis)
967
{
968
pari_sp av = avma;
969
GEN p;
970
checkalg(al);
971
if (typ(basis) != t_MAT) pari_err_TYPE("algsubalg",basis);
972
p = alg_get_char(al);
973
if (signe(p)) basis = RgM_to_FpM(basis,p);
974
return gerepilecopy(av, alg_subalg(al,basis));
975
}
976
977
static int
978
cmp_algebra(GEN x, GEN y)
979
{
980
long d;
981
d = gel(x,1)[1] - gel(y,1)[1]; if (d) return d < 0? -1: 1;
982
d = gel(x,1)[2] - gel(y,1)[2]; if (d) return d < 0? -1: 1;
983
return cmp_universal(gel(x,2), gel(y,2));
984
}
985
986
GEN
987
algsimpledec_ss(GEN al, long maps)
988
{
989
pari_sp av = avma;
990
GEN Z, p, r, res, perm;
991
long i, l, n;
992
checkalg(al);
993
p = alg_get_char(al);
994
dbg_printf(1)("algsimpledec_ss: char=%Ps, dim=%d\n", p, alg_get_absdim(al));
995
if (signe(p)) Z = algprimesubalg(al);
996
else Z = algtablecenter(al);
997
998
if (lg(Z) == 2) {/* dim Z = 1 */
999
n = alg_get_absdim(al);
1000
set_avma(av);
1001
if (!maps) return mkveccopy(al);
1002
retmkvec(mkvec3(gcopy(al), matid(n), matid(n)));
1003
}
1004
res = alg_decompose_total(al, Z, maps);
1005
l = lg(res); r = cgetg(l, t_VEC);
1006
for (i = 1; i < l; i++)
1007
{
1008
GEN A = maps? gmael(res,i,1): gel(res,i);
1009
gel(r,i) = mkvec2(mkvecsmall2(alg_get_dim(A), lg(algtablecenter(A))),
1010
alg_get_multable(A));
1011
}
1012
perm = gen_indexsort(r, (void*)cmp_algebra, &cmp_nodata);
1013
return gerepilecopy(av, vecpermute(res, perm));
1014
}
1015
1016
GEN
1017
algsimpledec(GEN al, long maps)
1018
{
1019
pari_sp av = avma;
1020
int ss;
1021
GEN rad, dec, res, proj=NULL, lift=NULL;
1022
rad = algradical(al);
1023
ss = gequal0(rad);
1024
if (!ss)
1025
{
1026
al = alg_quotient(al, rad, maps);
1027
if (maps) {
1028
proj = gel(al,2);
1029
lift = gel(al,3);
1030
al = gel(al,1);
1031
}
1032
}
1033
dec = algsimpledec_ss(al, maps);
1034
if (!ss && maps) /* update maps */
1035
{
1036
GEN p = alg_get_char(al);
1037
long i;
1038
for (i=1; i<lg(dec); i++)
1039
{
1040
if (signe(p))
1041
{
1042
gmael(dec,i,2) = FpM_mul(gmael(dec,i,2), proj, p);
1043
gmael(dec,i,3) = FpM_mul(lift, gmael(dec,i,3), p);
1044
}
1045
else
1046
{
1047
gmael(dec,i,2) = RgM_mul(gmael(dec,i,2), proj);
1048
gmael(dec,i,3) = RgM_mul(lift, gmael(dec,i,3));
1049
}
1050
}
1051
}
1052
res = mkvec2(rad, dec);
1053
return gerepilecopy(av,res);
1054
}
1055
1056
static GEN alg_idempotent(GEN al, long n, long d);
1057
static GEN
1058
try_split(GEN al, GEN x, long n, long d)
1059
{
1060
GEN cp, p = alg_get_char(al), fa, e, pol, exp, P, Q, U, u, mx, mte, ire;
1061
long nfa, i, smalldim = alg_get_absdim(al)+1, dim, smalli = 0;
1062
cp = algcharpoly(al,x,0,1);
1063
fa = FpX_factor(cp,p);
1064
nfa = nbrows(fa);
1065
if (nfa == 1) return NULL;
1066
pol = gel(fa,1);
1067
exp = gel(fa,2);
1068
1069
/* charpoly is always a d-th power */
1070
for (i=1; i<lg(exp); i++) {
1071
if (exp[i]%d) pari_err(e_MISC, "the algebra must be simple (try_split 1)");
1072
exp[i] /= d;
1073
}
1074
cp = FpXV_factorback(gel(fa,1), gel(fa,2), p, 0);
1075
1076
/* find smallest Fp-dimension of a characteristic space */
1077
for (i=1; i<lg(pol); i++) {
1078
dim = degree(gel(pol,i))*exp[i];
1079
if (dim < smalldim) {
1080
smalldim = dim;
1081
smalli = i;
1082
}
1083
}
1084
i = smalli;
1085
if (smalldim != n) return NULL;
1086
/* We could also compute e*al*e and try again with this smaller algebra */
1087
/* Fq-rank 1 = Fp-rank n idempotent: success */
1088
1089
/* construct idempotent */
1090
mx = algbasismultable(al,x);
1091
P = gel(pol,i);
1092
P = FpX_powu(P, exp[i], p);
1093
Q = FpX_div(cp, P, p);
1094
e = algpoleval(al, Q, mkvec2(x,mx));
1095
U = FpXQ_inv(Q, P, p);
1096
u = algpoleval(al, U, mkvec2(x,mx));
1097
e = algbasismul(al, e, u);
1098
mte = algbasisrightmultable(al,e);
1099
ire = FpM_indexrank(mte,p);
1100
if (lg(gel(ire,1))-1 != smalldim*d) pari_err(e_MISC, "the algebra must be simple (try_split 2)");
1101
1102
return mkvec3(e,mte,ire);
1103
}
1104
1105
/*
1106
* Given a simple algebra al of dimension d^2 over its center of degree n,
1107
* find an idempotent e in al with rank n (which is minimal).
1108
*/
1109
static GEN
1110
alg_idempotent(GEN al, long n, long d)
1111
{
1112
pari_sp av = avma;
1113
long i, N = alg_get_absdim(al);
1114
GEN e, p = alg_get_char(al), x;
1115
for(i=2; i<=N; i++) {
1116
x = col_ei(N,i);
1117
e = try_split(al, x, n, d);
1118
if (e) return e;
1119
set_avma(av);
1120
}
1121
for(;;) {
1122
x = random_FpC(N,p);
1123
e = try_split(al, x, n, d);
1124
if (e) return e;
1125
set_avma(av);
1126
}
1127
}
1128
1129
static GEN
1130
try_descend(GEN M, GEN B, GEN p, long m, long n, long d)
1131
{
1132
GEN B2 = cgetg(m+1,t_MAT), b;
1133
long i, j, k=0;
1134
for (i=1; i<=d; i++)
1135
{
1136
k++;
1137
b = gel(B,i);
1138
gel(B2,k) = b;
1139
for (j=1; j<n; j++)
1140
{
1141
k++;
1142
b = FpM_FpC_mul(M,b,p);
1143
gel(B2,k) = b;
1144
}
1145
}
1146
if (!signe(FpM_det(B2,p))) return NULL;
1147
return FpM_inv(B2,p);
1148
}
1149
1150
/* Given an m*m matrix M with irreducible charpoly over F of degree n,
1151
* let K = F(M), which is a field, and write m=d*n.
1152
* Compute the d-dimensional K-vector space structure on V=F^m induced by M.
1153
* Return [B,C] where:
1154
* - B is m*d matrix over F giving a K-basis b_1,...,b_d of V
1155
* - C is d*m matrix over F[x] expressing the canonical F-basis of V on the b_i
1156
* Currently F = Fp TODO extend this. */
1157
static GEN
1158
descend_i(GEN M, long n, GEN p)
1159
{
1160
GEN B, C;
1161
long m,d,i;
1162
pari_sp av;
1163
m = lg(M)-1;
1164
d = m/n;
1165
B = cgetg(d+1,t_MAT);
1166
av = avma;
1167
1168
/* try a subset of the canonical basis */
1169
for (i=1; i<=d; i++)
1170
gel(B,i) = col_ei(m,n*(i-1)+1);
1171
C = try_descend(M,B,p,m,n,d);
1172
if (C) return mkvec2(B,C);
1173
set_avma(av);
1174
1175
/* try smallish elements */
1176
for (i=1; i<=d; i++)
1177
gel(B,i) = FpC_red(zc_to_ZC(random_pm1(m)),p);
1178
C = try_descend(M,B,p,m,n,d);
1179
if (C) return mkvec2(B,C);
1180
set_avma(av);
1181
1182
/* try random elements */
1183
for (;;)
1184
{
1185
for (i=1; i<=d; i++)
1186
gel(B,i) = random_FpC(m,p);
1187
C = try_descend(M,B,p,m,n,d);
1188
if (C) return mkvec2(B,C);
1189
set_avma(av);
1190
}
1191
}
1192
static GEN
1193
RgC_contract(GEN C, long n, long v) /* n>1 */
1194
{
1195
GEN C2, P;
1196
long m, d, i, j;
1197
m = lg(C)-1;
1198
d = m/n;
1199
C2 = cgetg(d+1,t_COL);
1200
for (i=1; i<=d; i++)
1201
{
1202
P = pol_xn(n-1,v);
1203
for (j=1; j<=n; j++)
1204
gel(P,j+1) = gel(C,n*(i-1)+j);
1205
P = normalizepol(P);
1206
gel(C2,i) = P;
1207
}
1208
return C2;
1209
}
1210
static GEN
1211
RgM_contract(GEN A, long n, long v) /* n>1 */
1212
{
1213
GEN A2 = cgetg(lg(A),t_MAT);
1214
long i;
1215
for (i=1; i<lg(A2); i++)
1216
gel(A2,i) = RgC_contract(gel(A,i),n,v);
1217
return A2;
1218
}
1219
static GEN
1220
descend(GEN M, long n, GEN p, long v)
1221
{
1222
GEN res = descend_i(M,n,p);
1223
gel(res,2) = RgM_contract(gel(res,2),n,v);
1224
return res;
1225
}
1226
1227
/* isomorphism of Fp-vector spaces M_d(F_p^n) -> (F_p)^(d^2*n) */
1228
static GEN
1229
Fq_mat2col(GEN M, long d, long n)
1230
{
1231
long N = d*d*n, i, j, k;
1232
GEN C = cgetg(N+1, t_COL);
1233
for (i=1; i<=d; i++)
1234
for (j=1; j<=d; j++)
1235
for (k=0; k<n; k++)
1236
gel(C,n*(d*(i-1)+j-1)+k+1) = polcoef_i(gcoeff(M,i,j),k,-1);
1237
return C;
1238
}
1239
1240
static GEN
1241
alg_finite_csa_split(GEN al, long v)
1242
{
1243
GEN Z, e, mte, ire, primelt, b, T, M, proje, lifte, extre, p, B, C, mt, mx, map, mapi, T2, ro;
1244
long n, d, N = alg_get_absdim(al), i;
1245
p = alg_get_char(al);
1246
/* compute the center */
1247
Z = algcenter(al);
1248
/* TODO option to give the center as input instead of computing it */
1249
n = lg(Z)-1;
1250
1251
/* compute a minimal rank idempotent e */
1252
if (n==N) {
1253
d = 1;
1254
e = col_ei(N,1);
1255
mte = matid(N);
1256
ire = mkvec2(identity_perm(n),identity_perm(n));
1257
}
1258
else {
1259
d = usqrt(N/n);
1260
if (d*d*n != N) pari_err(e_MISC, "the algebra must be simple (alg_finite_csa_split 1)");
1261
e = alg_idempotent(al,n,d);
1262
mte = gel(e,2);
1263
ire = gel(e,3);
1264
e = gel(e,1);
1265
}
1266
1267
/* identify the center */
1268
if (n==1)
1269
{
1270
T = pol_x(v);
1271
primelt = gen_0;
1272
}
1273
else
1274
{
1275
b = alg_decompose(al, Z, 1, &primelt);
1276
if (!gequal0(b)) pari_err(e_MISC, "the algebra must be simple (alg_finite_csa_split 2)");
1277
T = gel(primelt,2);
1278
primelt = gel(primelt,1);
1279
setvarn(T,v);
1280
}
1281
1282
/* use the ffinit polynomial */
1283
if (n>1)
1284
{
1285
T2 = init_Fq(p,n,v);
1286
setvarn(T,fetch_var_higher());
1287
ro = FpXQX_roots(T2,T,p);
1288
ro = gel(ro,1);
1289
primelt = algpoleval(al,ro,primelt);
1290
T = T2;
1291
}
1292
1293
/* descend al*e to a vector space over the center */
1294
/* lifte: al*e -> al ; proje: al*e -> al */
1295
lifte = shallowextract(mte,gel(ire,2));
1296
extre = shallowmatextract(mte,gel(ire,1),gel(ire,2));
1297
extre = FpM_inv(extre,p);
1298
proje = rowpermute(mte,gel(ire,1));
1299
proje = FpM_mul(extre,proje,p);
1300
if (n==1)
1301
{
1302
B = lifte;
1303
C = proje;
1304
}
1305
else
1306
{
1307
M = algbasismultable(al,primelt);
1308
M = FpM_mul(M,lifte,p);
1309
M = FpM_mul(proje,M,p);
1310
B = descend(M,n,p,v);
1311
C = gel(B,2);
1312
B = gel(B,1);
1313
B = FpM_mul(lifte,B,p);
1314
C = FqM_mul(C,proje,T,p);
1315
}
1316
1317
/* compute the isomorphism */
1318
mt = alg_get_multable(al);
1319
map = cgetg(N+1,t_VEC);
1320
M = cgetg(N+1,t_MAT);
1321
for (i=1; i<=N; i++)
1322
{
1323
mx = gel(mt,i);
1324
mx = FpM_mul(mx,B,p);
1325
mx = FqM_mul(C,mx,T,p);
1326
gel(map,i) = mx;
1327
gel(M,i) = Fq_mat2col(mx,d,n);
1328
}
1329
mapi = FpM_inv(M,p);
1330
if (!mapi) pari_err(e_MISC, "the algebra must be simple (alg_finite_csa_split 3)");
1331
return mkvec3(T,map,mapi);
1332
}
1333
1334
GEN
1335
algsplit(GEN al, long v)
1336
{
1337
pari_sp av = avma;
1338
GEN res, T, map, mapi, ff, p;
1339
long i,j,k,li,lj;
1340
checkalg(al);
1341
p = alg_get_char(al);
1342
if (gequal0(p))
1343
pari_err_IMPL("splitting a characteristic 0 algebra over its center");
1344
res = alg_finite_csa_split(al, v);
1345
T = gel(res,1);
1346
map = gel(res,2);
1347
mapi = gel(res,3);
1348
ff = Tp_to_FF(T,p);
1349
for (i=1; i<lg(map); i++)
1350
{
1351
li = lg(gel(map,i));
1352
for (j=1; j<li; j++)
1353
{
1354
lj = lg(gmael(map,i,j));
1355
for (k=1; k<lj; k++)
1356
gmael3(map,i,j,k) = Fq_to_FF(gmael3(map,i,j,k),ff);
1357
}
1358
}
1359
1360
return gerepilecopy(av, mkvec2(map,mapi));
1361
}
1362
1363
/* multiplication table sanity checks */
1364
static GEN
1365
check_mt_noid(GEN mt, GEN p)
1366
{
1367
long i, l;
1368
GEN MT = cgetg_copy(mt, &l);
1369
if (typ(MT) != t_VEC || l == 1) return NULL;
1370
for (i = 1; i < l; i++)
1371
{
1372
GEN M = gel(mt,i);
1373
if (typ(M) != t_MAT || lg(M) != l || lgcols(M) != l) return NULL;
1374
if (p) M = RgM_to_FpM(M,p);
1375
gel(MT,i) = M;
1376
}
1377
return MT;
1378
}
1379
static GEN
1380
check_mt(GEN mt, GEN p)
1381
{
1382
long i;
1383
GEN MT;
1384
MT = check_mt_noid(mt, p);
1385
if (!MT || !ZM_isidentity(gel(MT,1))) return NULL;
1386
for (i=2; i<lg(MT); i++)
1387
if (ZC_is_ei(gmael(MT,i,1)) != i) return NULL;
1388
return MT;
1389
}
1390
1391
static GEN
1392
check_relmt(GEN nf, GEN mt)
1393
{
1394
long i, l = lg(mt), j, k;
1395
GEN MT = gcopy(mt), a, b, d;
1396
if (typ(MT) != t_VEC || l == 1) return NULL;
1397
for (i = 1; i < l; i++)
1398
{
1399
GEN M = gel(MT,i);
1400
if (typ(M) != t_MAT || lg(M) != l || lgcols(M) != l) return NULL;
1401
for (k = 1; k < l; k++)
1402
for (j = 1; j < l; j++)
1403
{
1404
a = gcoeff(M,j,k);
1405
if (typ(a)==t_INT) continue;
1406
b = algtobasis(nf,a);
1407
d = Q_denom(b);
1408
if (!isint1(d))
1409
pari_err_DOMAIN("alg_csa_table", "denominator(mt)", "!=", gen_1, mt);
1410
gcoeff(M,j,k) = lift(basistoalg(nf,b));
1411
}
1412
if (i > 1 && RgC_is_ei(gel(M,1)) != i) return NULL; /* i = 1 checked at end */
1413
gel(MT,i) = M;
1414
}
1415
if (!RgM_isidentity(gel(MT,1))) return NULL;
1416
return MT;
1417
}
1418
1419
int
1420
algisassociative(GEN mt0, GEN p)
1421
{
1422
pari_sp av = avma;
1423
long i, j, k, n;
1424
GEN M, mt;
1425
1426
if (checkalg_i(mt0)) { p = alg_get_char(mt0); mt0 = alg_get_multable(mt0); }
1427
if (typ(p) != t_INT) pari_err_TYPE("algisassociative",p);
1428
mt = check_mt_noid(mt0, isintzero(p)? NULL: p);
1429
if (!mt) pari_err_TYPE("algisassociative (mult. table)", mt0);
1430
if (!ZM_isidentity(gel(mt,1))) return gc_bool(av,0);
1431
n = lg(mt)-1;
1432
M = cgetg(n+1,t_MAT);
1433
for (j=1; j<=n; j++) gel(M,j) = cgetg(n+1,t_COL);
1434
for (i=1; i<=n; i++)
1435
{
1436
GEN mi = gel(mt,i);
1437
for (j=1; j<=n; j++) gcoeff(M,i,j) = gel(mi,j); /* ei.ej */
1438
}
1439
for (i=2; i<=n; i++) {
1440
GEN mi = gel(mt,i);
1441
for (j=2; j<=n; j++) {
1442
for (k=2; k<=n; k++) {
1443
GEN x, y;
1444
if (signe(p)) {
1445
x = _tablemul_ej_Fp(mt,gcoeff(M,i,j),k,p);
1446
y = FpM_FpC_mul(mi,gcoeff(M,j,k),p);
1447
}
1448
else {
1449
x = _tablemul_ej(mt,gcoeff(M,i,j),k);
1450
y = RgM_RgC_mul(mi,gcoeff(M,j,k));
1451
}
1452
/* not cmp_universal: must not fail on 0 == Mod(0,2) for instance */
1453
if (!gequal(x,y)) return gc_bool(av,0);
1454
}
1455
}
1456
}
1457
return gc_bool(av,1);
1458
}
1459
1460
int
1461
algiscommutative(GEN al) /* assumes e_1 = 1 */
1462
{
1463
long i,j,k,N,sp;
1464
GEN mt,a,b,p;
1465
checkalg(al);
1466
if (alg_type(al) != al_TABLE) return alg_get_degree(al)==1;
1467
N = alg_get_absdim(al);
1468
mt = alg_get_multable(al);
1469
p = alg_get_char(al);
1470
sp = signe(p);
1471
for (i=2; i<=N; i++)
1472
for (j=2; j<=N; j++)
1473
for (k=1; k<=N; k++) {
1474
a = gcoeff(gel(mt,i),k,j);
1475
b = gcoeff(gel(mt,j),k,i);
1476
if (sp) {
1477
if (cmpii(Fp_red(a,p), Fp_red(b,p))) return 0;
1478
}
1479
else if (gcmp(a,b)) return 0;
1480
}
1481
return 1;
1482
}
1483
1484
int
1485
algissemisimple(GEN al)
1486
{
1487
pari_sp av = avma;
1488
GEN rad;
1489
checkalg(al);
1490
if (alg_type(al) != al_TABLE) return 1;
1491
rad = algradical(al);
1492
set_avma(av);
1493
return gequal0(rad);
1494
}
1495
1496
/* ss : known to be semisimple */
1497
int
1498
algissimple(GEN al, long ss)
1499
{
1500
pari_sp av = avma;
1501
GEN Z, dec, p;
1502
checkalg(al);
1503
if (alg_type(al) != al_TABLE) return 1;
1504
if (!ss && !algissemisimple(al)) return 0;
1505
1506
p = alg_get_char(al);
1507
if (signe(p)) Z = algprimesubalg(al);
1508
else Z = algtablecenter(al);
1509
1510
if (lg(Z) == 2) {/* dim Z = 1 */
1511
set_avma(av);
1512
return 1;
1513
}
1514
dec = alg_decompose(al, Z, 1, NULL);
1515
set_avma(av);
1516
return gequal0(dec);
1517
}
1518
1519
static long
1520
is_place_emb(GEN nf, GEN pl)
1521
{
1522
long r, r1, r2;
1523
if (typ(pl) != t_INT) pari_err_TYPE("is_place_emb", pl);
1524
if (signe(pl)<=0) pari_err_DOMAIN("is_place_emb", "pl", "<=", gen_0, pl);
1525
nf_get_sign(nf,&r1,&r2); r = r1+r2;
1526
if (cmpiu(pl,r)>0) pari_err_DOMAIN("is_place_emb", "pl", ">", utoi(r), pl);
1527
return itou(pl);
1528
}
1529
1530
static long
1531
alghasse_emb(GEN al, long emb)
1532
{
1533
GEN nf = alg_get_center(al);
1534
long r1 = nf_get_r1(nf);
1535
return (emb <= r1)? alg_get_hasse_i(al)[emb]: 0;
1536
}
1537
1538
static long
1539
alghasse_pr(GEN al, GEN pr)
1540
{
1541
GEN hf = alg_get_hasse_f(al);
1542
long i = tablesearch(gel(hf,1), pr, &cmp_prime_ideal);
1543
return i? gel(hf,2)[i]: 0;
1544
}
1545
1546
static long
1547
alghasse_0(GEN al, GEN pl)
1548
{
1549
GEN pr, nf;
1550
if (alg_type(al)== al_CSA)
1551
pari_err_IMPL("computation of Hasse invariants over table CSA");
1552
if ((pr = get_prid(pl))) return alghasse_pr(al, pr);
1553
nf = alg_get_center(al);
1554
return alghasse_emb(al, is_place_emb(nf, pl));
1555
}
1556
GEN
1557
alghasse(GEN al, GEN pl)
1558
{
1559
long h;
1560
checkalg(al);
1561
if (alg_type(al) == al_TABLE) pari_err_TYPE("alghasse [use alginit]",al);
1562
h = alghasse_0(al,pl);
1563
return sstoQ(h, alg_get_degree(al));
1564
}
1565
1566
/* h >= 0, d >= 0 */
1567
static long
1568
indexfromhasse(long h, long d) { return d/ugcd(h,d); }
1569
1570
long
1571
algindex(GEN al, GEN pl)
1572
{
1573
long d, res, i, l;
1574
GEN hi, hf;
1575
1576
checkalg(al);
1577
if (alg_type(al) == al_TABLE) pari_err_TYPE("algindex [use alginit]",al);
1578
d = alg_get_degree(al);
1579
if (pl) return indexfromhasse(alghasse_0(al,pl), d);
1580
1581
/* else : global index */
1582
res = 1;
1583
hi = alg_get_hasse_i(al); l = lg(hi);
1584
for (i=1; i<l && res!=d; i++) res = ulcm(res, indexfromhasse(hi[i],d));
1585
hf = gel(alg_get_hasse_f(al), 2); l = lg(hf);
1586
for (i=1; i<l && res!=d; i++) res = ulcm(res, indexfromhasse(hf[i],d));
1587
return res;
1588
}
1589
1590
int
1591
algisdivision(GEN al, GEN pl)
1592
{
1593
checkalg(al);
1594
if (alg_type(al) == al_TABLE) {
1595
if (!algissimple(al,0)) return 0;
1596
if (algiscommutative(al)) return 1;
1597
pari_err_IMPL("algisdivision for table algebras");
1598
}
1599
return algindex(al,pl) == alg_get_degree(al);
1600
}
1601
1602
int
1603
algissplit(GEN al, GEN pl)
1604
{
1605
checkalg(al);
1606
if (alg_type(al) == al_TABLE) pari_err_TYPE("algissplit [use alginit]", al);
1607
return algindex(al,pl) == 1;
1608
}
1609
1610
int
1611
algisramified(GEN al, GEN pl)
1612
{
1613
checkalg(al);
1614
if (alg_type(al) == al_TABLE) pari_err_TYPE("algisramified [use alginit]", al);
1615
return algindex(al,pl) != 1;
1616
}
1617
1618
GEN
1619
algramifiedplaces(GEN al)
1620
{
1621
pari_sp av = avma;
1622
GEN ram, hf, hi, Lpr;
1623
long r1, count, i;
1624
checkalg(al);
1625
if (alg_type(al) == al_TABLE) pari_err_TYPE("algramifiedplaces [use alginit]", al);
1626
r1 = nf_get_r1(alg_get_center(al));
1627
hi = alg_get_hasse_i(al);
1628
hf = alg_get_hasse_f(al);
1629
Lpr = gel(hf,1);
1630
hf = gel(hf,2);
1631
ram = cgetg(r1+lg(Lpr), t_VEC);
1632
count = 0;
1633
for (i=1; i<=r1; i++)
1634
if (hi[i]) {
1635
count++;
1636
gel(ram,count) = stoi(i);
1637
}
1638
for (i=1; i<lg(Lpr); i++)
1639
if (hf[i]) {
1640
count++;
1641
gel(ram,count) = gel(Lpr,i);
1642
}
1643
setlg(ram, count+1);
1644
return gerepilecopy(av, ram);
1645
}
1646
1647
/** OPERATIONS ON ELEMENTS operations.c **/
1648
1649
static long
1650
alg_model0(GEN al, GEN x)
1651
{
1652
long t, N = alg_get_absdim(al), lx = lg(x), d, n, D, i;
1653
if (typ(x) == t_MAT) return al_MATRIX;
1654
if (typ(x) != t_COL) return al_INVALID;
1655
if (N == 1) {
1656
if (lx != 2) return al_INVALID;
1657
switch(typ(gel(x,1)))
1658
{
1659
case t_INT: case t_FRAC: return al_TRIVIAL; /* cannot distinguish basis and alg from size */
1660
case t_POL: case t_POLMOD: return al_ALGEBRAIC;
1661
default: return al_INVALID;
1662
}
1663
}
1664
1665
switch(alg_type(al)) {
1666
case al_TABLE:
1667
if (lx != N+1) return al_INVALID;
1668
return al_BASIS;
1669
case al_CYCLIC:
1670
d = alg_get_degree(al);
1671
if (lx == N+1) return al_BASIS;
1672
if (lx == d+1) return al_ALGEBRAIC;
1673
return al_INVALID;
1674
case al_CSA:
1675
D = alg_get_dim(al);
1676
n = nf_get_degree(alg_get_center(al));
1677
if (n == 1) {
1678
if (lx != D+1) return al_INVALID;
1679
for (i=1; i<=D; i++) {
1680
t = typ(gel(x,i));
1681
if (t == t_POL || t == t_POLMOD) return al_ALGEBRAIC;
1682
/* TODO t_COL for coefficients in basis form ? */
1683
}
1684
return al_BASIS;
1685
}
1686
else {
1687
if (lx == N+1) return al_BASIS;
1688
if (lx == D+1) return al_ALGEBRAIC;
1689
return al_INVALID;
1690
}
1691
}
1692
return al_INVALID; /* LCOV_EXCL_LINE */
1693
}
1694
1695
static void
1696
checkalgx(GEN x, long model)
1697
{
1698
long t, i;
1699
switch(model) {
1700
case al_BASIS:
1701
for (i=1; i<lg(x); i++) {
1702
t = typ(gel(x,i));
1703
if (t != t_INT && t != t_FRAC)
1704
pari_err_TYPE("checkalgx", gel(x,i));
1705
}
1706
return;
1707
case al_TRIVIAL:
1708
case al_ALGEBRAIC:
1709
for (i=1; i<lg(x); i++) {
1710
t = typ(gel(x,i));
1711
if (t != t_INT && t != t_FRAC && t != t_POL && t != t_POLMOD)
1712
/* TODO t_COL ? */
1713
pari_err_TYPE("checkalgx", gel(x,i));
1714
}
1715
return;
1716
}
1717
}
1718
1719
long
1720
alg_model(GEN al, GEN x)
1721
{
1722
long res = alg_model0(al, x);
1723
if (res == al_INVALID) pari_err_TYPE("alg_model", x);
1724
checkalgx(x, res); return res;
1725
}
1726
1727
static GEN
1728
alC_add_i(GEN al, GEN x, GEN y, long lx)
1729
{
1730
GEN A = cgetg(lx, t_COL);
1731
long i;
1732
for (i=1; i<lx; i++) gel(A,i) = algadd(al, gel(x,i), gel(y,i));
1733
return A;
1734
}
1735
static GEN
1736
alM_add(GEN al, GEN x, GEN y)
1737
{
1738
long lx = lg(x), l, j;
1739
GEN z;
1740
if (lg(y) != lx) pari_err_DIM("alM_add (rows)");
1741
if (lx == 1) return cgetg(1, t_MAT);
1742
z = cgetg(lx, t_MAT); l = lgcols(x);
1743
if (lgcols(y) != l) pari_err_DIM("alM_add (columns)");
1744
for (j = 1; j < lx; j++) gel(z,j) = alC_add_i(al, gel(x,j), gel(y,j), l);
1745
return z;
1746
}
1747
GEN
1748
algadd(GEN al, GEN x, GEN y)
1749
{
1750
pari_sp av = avma;
1751
long tx, ty;
1752
GEN p;
1753
checkalg(al);
1754
tx = alg_model(al,x);
1755
ty = alg_model(al,y);
1756
p = alg_get_char(al);
1757
if (signe(p)) return FpC_add(x,y,p);
1758
if (tx==ty) {
1759
if (tx!=al_MATRIX) return gadd(x,y);
1760
return gerepilecopy(av, alM_add(al,x,y));
1761
}
1762
if (tx==al_ALGEBRAIC) x = algalgtobasis(al,x);
1763
if (ty==al_ALGEBRAIC) y = algalgtobasis(al,y);
1764
return gerepileupto(av, gadd(x,y));
1765
}
1766
1767
GEN
1768
algneg(GEN al, GEN x) { checkalg(al); (void)alg_model(al,x); return gneg(x); }
1769
1770
static GEN
1771
alC_sub_i(GEN al, GEN x, GEN y, long lx)
1772
{
1773
long i;
1774
GEN A = cgetg(lx, t_COL);
1775
for (i=1; i<lx; i++) gel(A,i) = algsub(al, gel(x,i), gel(y,i));
1776
return A;
1777
}
1778
static GEN
1779
alM_sub(GEN al, GEN x, GEN y)
1780
{
1781
long lx = lg(x), l, j;
1782
GEN z;
1783
if (lg(y) != lx) pari_err_DIM("alM_sub (rows)");
1784
if (lx == 1) return cgetg(1, t_MAT);
1785
z = cgetg(lx, t_MAT); l = lgcols(x);
1786
if (lgcols(y) != l) pari_err_DIM("alM_sub (columns)");
1787
for (j = 1; j < lx; j++) gel(z,j) = alC_sub_i(al, gel(x,j), gel(y,j), l);
1788
return z;
1789
}
1790
GEN
1791
algsub(GEN al, GEN x, GEN y)
1792
{
1793
long tx, ty;
1794
pari_sp av = avma;
1795
GEN p;
1796
checkalg(al);
1797
tx = alg_model(al,x);
1798
ty = alg_model(al,y);
1799
p = alg_get_char(al);
1800
if (signe(p)) return FpC_sub(x,y,p);
1801
if (tx==ty) {
1802
if (tx != al_MATRIX) return gsub(x,y);
1803
return gerepilecopy(av, alM_sub(al,x,y));
1804
}
1805
if (tx==al_ALGEBRAIC) x = algalgtobasis(al,x);
1806
if (ty==al_ALGEBRAIC) y = algalgtobasis(al,y);
1807
return gerepileupto(av, gsub(x,y));
1808
}
1809
1810
static GEN
1811
algalgmul_cyc(GEN al, GEN x, GEN y)
1812
{
1813
pari_sp av = avma;
1814
long n = alg_get_degree(al), i, k;
1815
GEN xalg, yalg, res, rnf, auts, sum, b, prod, autx;
1816
rnf = alg_get_splittingfield(al);
1817
auts = alg_get_auts(al);
1818
b = alg_get_b(al);
1819
1820
xalg = cgetg(n+1, t_COL);
1821
for (i=0; i<n; i++)
1822
gel(xalg,i+1) = lift_shallow(rnfbasistoalg(rnf,gel(x,i+1)));
1823
1824
yalg = cgetg(n+1, t_COL);
1825
for (i=0; i<n; i++) gel(yalg,i+1) = rnfbasistoalg(rnf,gel(y,i+1));
1826
1827
res = cgetg(n+1,t_COL);
1828
for (k=0; k<n; k++) {
1829
gel(res,k+1) = gmul(gel(xalg,k+1),gel(yalg,1));
1830
for (i=1; i<=k; i++) {
1831
autx = poleval(gel(xalg,k-i+1),gel(auts,i));
1832
prod = gmul(autx,gel(yalg,i+1));
1833
gel(res,k+1) = gadd(gel(res,k+1), prod);
1834
}
1835
1836
sum = gen_0;
1837
for (; i<n; i++) {
1838
autx = poleval(gel(xalg,k+n-i+1),gel(auts,i));
1839
prod = gmul(autx,gel(yalg,i+1));
1840
sum = gadd(sum,prod);
1841
}
1842
sum = gmul(b,sum);
1843
1844
gel(res,k+1) = gadd(gel(res,k+1),sum);
1845
}
1846
1847
return gerepilecopy(av, res);
1848
}
1849
1850
static GEN
1851
_tablemul(GEN mt, GEN x, GEN y)
1852
{
1853
pari_sp av = avma;
1854
long D = lg(mt)-1, i;
1855
GEN res = NULL;
1856
for (i=1; i<=D; i++) {
1857
GEN c = gel(x,i);
1858
if (!gequal0(c)) {
1859
GEN My = RgM_RgC_mul(gel(mt,i),y);
1860
GEN t = RgC_Rg_mul(My,c);
1861
res = res? RgC_add(res,t): t;
1862
}
1863
}
1864
if (!res) { set_avma(av); return zerocol(D); }
1865
return gerepileupto(av, res);
1866
}
1867
1868
static GEN
1869
_tablemul_Fp(GEN mt, GEN x, GEN y, GEN p)
1870
{
1871
pari_sp av = avma;
1872
long D = lg(mt)-1, i;
1873
GEN res = NULL;
1874
for (i=1; i<=D; i++) {
1875
GEN c = gel(x,i);
1876
if (signe(c)) {
1877
GEN My = FpM_FpC_mul(gel(mt,i),y,p);
1878
GEN t = FpC_Fp_mul(My,c,p);
1879
res = res? FpC_add(res,t,p): t;
1880
}
1881
}
1882
if (!res) { set_avma(av); return zerocol(D); }
1883
return gerepileupto(av, res);
1884
}
1885
1886
/* x*ej */
1887
static GEN
1888
_tablemul_ej(GEN mt, GEN x, long j)
1889
{
1890
pari_sp av = avma;
1891
long D = lg(mt)-1, i;
1892
GEN res = NULL;
1893
for (i=1; i<=D; i++) {
1894
GEN c = gel(x,i);
1895
if (!gequal0(c)) {
1896
GEN My = gel(gel(mt,i),j);
1897
GEN t = RgC_Rg_mul(My,c);
1898
res = res? RgC_add(res,t): t;
1899
}
1900
}
1901
if (!res) { set_avma(av); return zerocol(D); }
1902
return gerepileupto(av, res);
1903
}
1904
static GEN
1905
_tablemul_ej_Fp(GEN mt, GEN x, long j, GEN p)
1906
{
1907
pari_sp av = avma;
1908
long D = lg(mt)-1, i;
1909
GEN res = NULL;
1910
for (i=1; i<=D; i++) {
1911
GEN c = gel(x,i);
1912
if (!gequal0(c)) {
1913
GEN My = gel(gel(mt,i),j);
1914
GEN t = FpC_Fp_mul(My,c,p);
1915
res = res? FpC_add(res,t,p): t;
1916
}
1917
}
1918
if (!res) { set_avma(av); return zerocol(D); }
1919
return gerepileupto(av, res);
1920
}
1921
1922
static GEN
1923
_tablemul_ej_Fl(GEN mt, GEN x, long j, ulong p)
1924
{
1925
pari_sp av = avma;
1926
long D = lg(mt)-1, i;
1927
GEN res = NULL;
1928
for (i=1; i<=D; i++) {
1929
ulong c = x[i];
1930
if (c) {
1931
GEN My = gel(gel(mt,i),j);
1932
GEN t = Flv_Fl_mul(My,c, p);
1933
res = res? Flv_add(res,t, p): t;
1934
}
1935
}
1936
if (!res) { set_avma(av); return zero_Flv(D); }
1937
return gerepileupto(av, res);
1938
}
1939
1940
static GEN
1941
algalgmul_csa(GEN al, GEN x, GEN y)
1942
{
1943
GEN z, nf = alg_get_center(al);
1944
long i;
1945
z = _tablemul(alg_get_relmultable(al), x, y);
1946
for (i=1; i<lg(z); i++)
1947
gel(z,i) = basistoalg(nf,gel(z,i));
1948
return z;
1949
}
1950
1951
/* assumes x and y in algebraic form */
1952
static GEN
1953
algalgmul(GEN al, GEN x, GEN y)
1954
{
1955
switch(alg_type(al))
1956
{
1957
case al_CYCLIC: return algalgmul_cyc(al, x, y);
1958
case al_CSA: return algalgmul_csa(al, x, y);
1959
}
1960
return NULL; /*LCOV_EXCL_LINE*/
1961
}
1962
1963
static GEN
1964
algbasismul(GEN al, GEN x, GEN y)
1965
{
1966
GEN mt = alg_get_multable(al), p = alg_get_char(al);
1967
if (signe(p)) return _tablemul_Fp(mt, x, y, p);
1968
return _tablemul(mt, x, y);
1969
}
1970
1971
/* x[i,]*y. Assume lg(x) > 1 and 0 < i < lgcols(x) */
1972
static GEN
1973
alMrow_alC_mul_i(GEN al, GEN x, GEN y, long i, long lx)
1974
{
1975
pari_sp av = avma;
1976
GEN c = algmul(al,gcoeff(x,i,1),gel(y,1)), ZERO;
1977
long k;
1978
ZERO = zerocol(alg_get_absdim(al));
1979
for (k = 2; k < lx; k++)
1980
{
1981
GEN t = algmul(al, gcoeff(x,i,k), gel(y,k));
1982
if (!gequal(t,ZERO)) c = algadd(al, c, t);
1983
}
1984
return gerepilecopy(av, c);
1985
}
1986
/* return x * y, 1 < lx = lg(x), l = lgcols(x) */
1987
static GEN
1988
alM_alC_mul_i(GEN al, GEN x, GEN y, long lx, long l)
1989
{
1990
GEN z = cgetg(l,t_COL);
1991
long i;
1992
for (i=1; i<l; i++) gel(z,i) = alMrow_alC_mul_i(al,x,y,i,lx);
1993
return z;
1994
}
1995
static GEN
1996
alM_mul(GEN al, GEN x, GEN y)
1997
{
1998
long j, l, lx=lg(x), ly=lg(y);
1999
GEN z;
2000
if (ly==1) return cgetg(1,t_MAT);
2001
if (lx != lgcols(y)) pari_err_DIM("alM_mul");
2002
if (lx==1) return zeromat(0, ly-1);
2003
l = lgcols(x); z = cgetg(ly,t_MAT);
2004
for (j=1; j<ly; j++) gel(z,j) = alM_alC_mul_i(al,x,gel(y,j),lx,l);
2005
return z;
2006
}
2007
2008
GEN
2009
algmul(GEN al, GEN x, GEN y)
2010
{
2011
pari_sp av = avma;
2012
long tx, ty;
2013
checkalg(al);
2014
tx = alg_model(al,x);
2015
ty = alg_model(al,y);
2016
if (tx==al_MATRIX) {
2017
if (ty==al_MATRIX) return alM_mul(al,x,y);
2018
pari_err_TYPE("algmul", y);
2019
}
2020
if (signe(alg_get_char(al))) return algbasismul(al,x,y);
2021
if (tx==al_TRIVIAL) retmkcol(gmul(gel(x,1),gel(y,1)));
2022
if (tx==al_ALGEBRAIC && ty==al_ALGEBRAIC) return algalgmul(al,x,y);
2023
if (tx==al_ALGEBRAIC) x = algalgtobasis(al,x);
2024
if (ty==al_ALGEBRAIC) y = algalgtobasis(al,y);
2025
return gerepileupto(av,algbasismul(al,x,y));
2026
}
2027
2028
GEN
2029
algsqr(GEN al, GEN x)
2030
{
2031
pari_sp av = avma;
2032
long tx;
2033
checkalg(al);
2034
tx = alg_model(al,x);
2035
if (tx==al_MATRIX) return gerepilecopy(av,alM_mul(al,x,x));
2036
if (signe(alg_get_char(al))) return algbasismul(al,x,x);
2037
if (tx==al_TRIVIAL) retmkcol(gsqr(gel(x,1)));
2038
if (tx==al_ALGEBRAIC) return algalgmul(al,x,x);
2039
return gerepileupto(av,algbasismul(al,x,x));
2040
}
2041
2042
static GEN
2043
algmtK2Z_cyc(GEN al, GEN m)
2044
{
2045
pari_sp av = avma;
2046
GEN nf = alg_get_abssplitting(al), res, mt, rnf = alg_get_splittingfield(al), c, dc;
2047
long n = alg_get_degree(al), N = nf_get_degree(nf), Nn, i, j, i1, j1;
2048
Nn = N*n;
2049
res = zeromatcopy(Nn,Nn);
2050
for (i=0; i<n; i++)
2051
for (j=0; j<n; j++) {
2052
c = gcoeff(m,i+1,j+1);
2053
if (!gequal0(c)) {
2054
c = rnfeltreltoabs(rnf,c);
2055
c = algtobasis(nf,c);
2056
c = Q_remove_denom(c,&dc);
2057
mt = zk_multable(nf,c);
2058
if (dc) mt = ZM_Z_div(mt,dc);
2059
for (i1=1; i1<=N; i1++)
2060
for (j1=1; j1<=N; j1++)
2061
gcoeff(res,i*N+i1,j*N+j1) = gcoeff(mt,i1,j1);
2062
}
2063
}
2064
return gerepilecopy(av,res);
2065
}
2066
2067
static GEN
2068
algmtK2Z_csa(GEN al, GEN m)
2069
{
2070
pari_sp av = avma;
2071
GEN nf = alg_get_center(al), res, mt, c, dc;
2072
long d2 = alg_get_dim(al), n = nf_get_degree(nf), D, i, j, i1, j1;
2073
D = d2*n;
2074
res = zeromatcopy(D,D);
2075
for (i=0; i<d2; i++)
2076
for (j=0; j<d2; j++) {
2077
c = gcoeff(m,i+1,j+1);
2078
if (!gequal0(c)) {
2079
c = algtobasis(nf,c);
2080
c = Q_remove_denom(c,&dc);
2081
mt = zk_multable(nf,c);
2082
if (dc) mt = ZM_Z_div(mt,dc);
2083
for (i1=1; i1<=n; i1++)
2084
for (j1=1; j1<=n; j1++)
2085
gcoeff(res,i*n+i1,j*n+j1) = gcoeff(mt,i1,j1);
2086
}
2087
}
2088
return gerepilecopy(av,res);
2089
}
2090
2091
/* assumes al is a CSA or CYCLIC */
2092
static GEN
2093
algmtK2Z(GEN al, GEN m)
2094
{
2095
switch(alg_type(al))
2096
{
2097
case al_CYCLIC: return algmtK2Z_cyc(al, m);
2098
case al_CSA: return algmtK2Z_csa(al, m);
2099
}
2100
return NULL; /*LCOV_EXCL_LINE*/
2101
}
2102
2103
/* left multiplication table, as a vector space of dimension n over the splitting field (by right multiplication) */
2104
static GEN
2105
algalgmultable_cyc(GEN al, GEN x)
2106
{
2107
pari_sp av = avma;
2108
long n = alg_get_degree(al), i, j;
2109
GEN res, rnf, auts, b, pol;
2110
rnf = alg_get_splittingfield(al);
2111
auts = alg_get_auts(al);
2112
b = alg_get_b(al);
2113
pol = rnf_get_pol(rnf);
2114
2115
res = zeromatcopy(n,n);
2116
for (i=0; i<n; i++)
2117
gcoeff(res,i+1,1) = lift_shallow(rnfbasistoalg(rnf,gel(x,i+1)));
2118
2119
for (i=0; i<n; i++) {
2120
for (j=1; j<=i; j++)
2121
gcoeff(res,i+1,j+1) = gmodulo(poleval(gcoeff(res,i-j+1,1),gel(auts,j)),pol);
2122
for (; j<n; j++)
2123
gcoeff(res,i+1,j+1) = gmodulo(gmul(b,poleval(gcoeff(res,n+i-j+1,1),gel(auts,j))), pol);
2124
}
2125
2126
for (i=0; i<n; i++)
2127
gcoeff(res,i+1,1) = gmodulo(gcoeff(res,i+1,1),pol);
2128
2129
return gerepilecopy(av, res);
2130
}
2131
2132
static GEN
2133
elementmultable(GEN mt, GEN x)
2134
{
2135
pari_sp av = avma;
2136
long D = lg(mt)-1, i;
2137
GEN z = NULL;
2138
for (i=1; i<=D; i++)
2139
{
2140
GEN c = gel(x,i);
2141
if (!gequal0(c))
2142
{
2143
GEN M = RgM_Rg_mul(gel(mt,i),c);
2144
z = z? RgM_add(z, M): M;
2145
}
2146
}
2147
if (!z) { set_avma(av); return zeromatcopy(D,D); }
2148
return gerepileupto(av, z);
2149
}
2150
/* mt a t_VEC of Flm modulo m */
2151
static GEN
2152
algbasismultable_Flm(GEN mt, GEN x, ulong m)
2153
{
2154
pari_sp av = avma;
2155
long D = lg(gel(mt,1))-1, i;
2156
GEN z = NULL;
2157
for (i=1; i<=D; i++)
2158
{
2159
ulong c = x[i];
2160
if (c)
2161
{
2162
GEN M = Flm_Fl_mul(gel(mt,i),c, m);
2163
z = z? Flm_add(z, M, m): M;
2164
}
2165
}
2166
if (!z) { set_avma(av); return zero_Flm(D,D); }
2167
return gerepileupto(av, z);
2168
}
2169
static GEN
2170
elementabsmultable_Z(GEN mt, GEN x)
2171
{
2172
long i, l = lg(x);
2173
GEN z = NULL;
2174
for (i = 1; i < l; i++)
2175
{
2176
GEN c = gel(x,i);
2177
if (signe(c))
2178
{
2179
GEN M = ZM_Z_mul(gel(mt,i),c);
2180
z = z? ZM_add(z, M): M;
2181
}
2182
}
2183
return z;
2184
}
2185
static GEN
2186
elementabsmultable(GEN mt, GEN x)
2187
{
2188
GEN d, z = elementabsmultable_Z(mt, Q_remove_denom(x,&d));
2189
return (z && d)? ZM_Z_div(z, d): z;
2190
}
2191
static GEN
2192
elementabsmultable_Fp(GEN mt, GEN x, GEN p)
2193
{
2194
GEN z = elementabsmultable_Z(mt, x);
2195
return z? FpM_red(z, p): z;
2196
}
2197
static GEN
2198
algbasismultable(GEN al, GEN x)
2199
{
2200
pari_sp av = avma;
2201
GEN z, p = alg_get_char(al), mt = alg_get_multable(al);
2202
z = signe(p)? elementabsmultable_Fp(mt, x, p): elementabsmultable(mt, x);
2203
if (!z)
2204
{
2205
long D = lg(mt)-1;
2206
set_avma(av); return zeromat(D,D);
2207
}
2208
return gerepileupto(av, z);
2209
}
2210
2211
static GEN
2212
algalgmultable_csa(GEN al, GEN x)
2213
{
2214
GEN nf = alg_get_center(al), m;
2215
long i,j;
2216
m = elementmultable(alg_get_relmultable(al), x);
2217
for (i=1; i<lg(m); i++)
2218
for(j=1; j<lg(m); j++)
2219
gcoeff(m,i,j) = basistoalg(nf,gcoeff(m,i,j));
2220
return m;
2221
}
2222
2223
/* assumes x in algebraic form */
2224
static GEN
2225
algalgmultable(GEN al, GEN x)
2226
{
2227
switch(alg_type(al))
2228
{
2229
case al_CYCLIC: return algalgmultable_cyc(al, x);
2230
case al_CSA: return algalgmultable_csa(al, x);
2231
}
2232
return NULL; /*LCOV_EXCL_LINE*/
2233
}
2234
2235
/* on the natural basis */
2236
/* assumes x in algebraic form */
2237
static GEN
2238
algZmultable(GEN al, GEN x) {
2239
pari_sp av = avma;
2240
GEN res = NULL, x0;
2241
long tx = alg_model(al,x);
2242
switch(tx) {
2243
case al_TRIVIAL:
2244
x0 = gel(x,1);
2245
if (typ(x0)==t_POLMOD) x0 = gel(x0,2);
2246
if (typ(x0)==t_POL) x0 = constant_coeff(x0);
2247
res = mkmatcopy(mkcol(x0));
2248
break;
2249
case al_ALGEBRAIC: res = algmtK2Z(al,algalgmultable(al,x)); break;
2250
}
2251
return gerepileupto(av,res);
2252
}
2253
2254
/* x integral */
2255
static GEN
2256
algbasisrightmultable(GEN al, GEN x)
2257
{
2258
long N = alg_get_absdim(al), i,j,k;
2259
GEN res = zeromatcopy(N,N), c, mt = alg_get_multable(al), p = alg_get_char(al);
2260
if (gequal0(p)) p = NULL;
2261
for (i=1; i<=N; i++) {
2262
c = gel(x,i);
2263
if (!gequal0(c)) {
2264
for (j=1; j<=N; j++)
2265
for(k=1; k<=N; k++) {
2266
if (p) gcoeff(res,k,j) = Fp_add(gcoeff(res,k,j), Fp_mul(c, gcoeff(gel(mt,j),k,i), p), p);
2267
else gcoeff(res,k,j) = addii(gcoeff(res,k,j), mulii(c, gcoeff(gel(mt,j),k,i)));
2268
}
2269
}
2270
}
2271
return res;
2272
}
2273
2274
/* basis for matrices : 1, E_{i,j} for (i,j)!=(1,1) */
2275
/* index : ijk = ((i-1)*N+j-1)*n + k */
2276
/* square matrices only, coefficients in basis form, shallow function */
2277
static GEN
2278
algmat2basis(GEN al, GEN M)
2279
{
2280
long n = alg_get_absdim(al), N = lg(M)-1, i, j, k, ij, ijk;
2281
GEN res, x;
2282
res = zerocol(N*N*n);
2283
for (i=1; i<=N; i++) {
2284
for (j=1, ij=(i-1)*N+1; j<=N; j++, ij++) {
2285
x = gcoeff(M,i,j);
2286
for (k=1, ijk=(ij-1)*n+1; k<=n; k++, ijk++) {
2287
gel(res, ijk) = gel(x, k);
2288
if (i>1 && i==j) gel(res, ijk) = gsub(gel(res,ijk), gel(res,k));
2289
}
2290
}
2291
}
2292
2293
return res;
2294
}
2295
2296
static GEN
2297
algbasis2mat(GEN al, GEN M, long N)
2298
{
2299
long n = alg_get_absdim(al), i, j, k, ij, ijk;
2300
GEN res, x;
2301
res = zeromatcopy(N,N);
2302
for (i=1; i<=N; i++)
2303
for (j=1; j<=N; j++)
2304
gcoeff(res,i,j) = zerocol(n);
2305
2306
for (i=1; i<=N; i++) {
2307
for (j=1, ij=(i-1)*N+1; j<=N; j++, ij++) {
2308
x = gcoeff(res,i,j);
2309
for (k=1, ijk=(ij-1)*n+1; k<=n; k++, ijk++) {
2310
gel(x,k) = gel(M,ijk);
2311
if (i>1 && i==j) gel(x,k) = gadd(gel(x,k), gel(M,k));
2312
}
2313
}
2314
}
2315
2316
return res;
2317
}
2318
2319
static GEN
2320
algmatbasis_ei(GEN al, long ijk, long N)
2321
{
2322
long n = alg_get_absdim(al), i, j, k, ij;
2323
GEN res;
2324
2325
res = zeromatcopy(N,N);
2326
for (i=1; i<=N; i++)
2327
for (j=1; j<=N; j++)
2328
gcoeff(res,i,j) = zerocol(n);
2329
2330
k = ijk%n;
2331
if (k==0) k=n;
2332
ij = (ijk-k)/n+1;
2333
2334
if (ij==1) {
2335
for (i=1; i<=N; i++)
2336
gcoeff(res,i,i) = col_ei(n,k);
2337
return res;
2338
}
2339
2340
j = ij%N;
2341
if (j==0) j=N;
2342
i = (ij-j)/N+1;
2343
2344
gcoeff(res,i,j) = col_ei(n,k);
2345
return res;
2346
}
2347
2348
/* FIXME lazy implementation! */
2349
static GEN
2350
algleftmultable_mat(GEN al, GEN M)
2351
{
2352
long N = lg(M)-1, n = alg_get_absdim(al), D = N*N*n, j;
2353
GEN res, x, Mx;
2354
if (N == 0) return cgetg(1, t_MAT);
2355
if (N != nbrows(M)) pari_err_DIM("algleftmultable_mat (nonsquare)");
2356
res = cgetg(D+1, t_MAT);
2357
for (j=1; j<=D; j++) {
2358
x = algmatbasis_ei(al, j, N);
2359
Mx = algmul(al, M, x);
2360
gel(res, j) = algmat2basis(al, Mx);
2361
}
2362
return res;
2363
}
2364
2365
/* left multiplication table on integral basis */
2366
static GEN
2367
algleftmultable(GEN al, GEN x)
2368
{
2369
pari_sp av = avma;
2370
long tx;
2371
GEN res;
2372
2373
checkalg(al);
2374
tx = alg_model(al,x);
2375
switch(tx) {
2376
case al_TRIVIAL : res = mkmatcopy(mkcol(gel(x,1))); break;
2377
case al_ALGEBRAIC : x = algalgtobasis(al,x);
2378
case al_BASIS : res = algbasismultable(al,x); break;
2379
case al_MATRIX : res = algleftmultable_mat(al,x); break;
2380
default : return NULL; /* LCOV_EXCL_LINE */
2381
}
2382
return gerepileupto(av,res);
2383
}
2384
2385
static GEN
2386
algbasissplittingmatrix_csa(GEN al, GEN x)
2387
{
2388
long d = alg_get_degree(al), i, j;
2389
GEN rnf = alg_get_splittingfield(al), splba = alg_get_splittingbasis(al), splbainv = alg_get_splittingbasisinv(al), M;
2390
M = algbasismultable(al,x);
2391
M = RgM_mul(M, splba); /* TODO best order ? big matrix /Q vs small matrix /nf */
2392
M = RgM_mul(splbainv, M);
2393
for (i=1; i<=d; i++)
2394
for (j=1; j<=d; j++)
2395
gcoeff(M,i,j) = rnfeltabstorel(rnf, gcoeff(M,i,j));
2396
return M;
2397
}
2398
2399
GEN
2400
algtomatrix(GEN al, GEN x, long abs)
2401
{
2402
pari_sp av = avma;
2403
GEN res = NULL;
2404
long ta, tx, i, j;
2405
checkalg(al);
2406
ta = alg_type(al);
2407
if (abs || ta==al_TABLE) return algleftmultable(al,x);
2408
tx = alg_model(al,x);
2409
if (tx==al_MATRIX) {
2410
if (lg(x) == 1) return cgetg(1, t_MAT);
2411
res = zeromatcopy(nbrows(x),lg(x)-1);
2412
for (j=1; j<lg(x); j++)
2413
for (i=1; i<lgcols(x); i++)
2414
gcoeff(res,i,j) = algtomatrix(al,gcoeff(x,i,j),0);
2415
res = shallowmatconcat(res);
2416
}
2417
else switch(alg_type(al))
2418
{
2419
case al_CYCLIC:
2420
if (tx==al_BASIS) x = algbasistoalg(al,x);
2421
res = algalgmultable(al,x);
2422
break;
2423
case al_CSA:
2424
if (tx==al_ALGEBRAIC) x = algalgtobasis(al,x);
2425
res = algbasissplittingmatrix_csa(al,x);
2426
break;
2427
default:
2428
pari_err_DOMAIN("algtomatrix", "alg_type(al)", "=", stoi(alg_type(al)), stoi(alg_type(al)));
2429
}
2430
return gerepilecopy(av,res);
2431
}
2432
2433
/* x^(-1)*y, NULL if no solution */
2434
static GEN
2435
algdivl_i(GEN al, GEN x, GEN y, long tx, long ty) {
2436
pari_sp av = avma;
2437
GEN res, p = alg_get_char(al), mtx;
2438
if (tx != ty) {
2439
if (tx==al_ALGEBRAIC) { x = algalgtobasis(al,x); tx=al_BASIS; }
2440
if (ty==al_ALGEBRAIC) { y = algalgtobasis(al,y); ty=al_BASIS; }
2441
}
2442
if (ty == al_MATRIX)
2443
{
2444
if (alg_type(al) != al_TABLE) y = algalgtobasis(al,y);
2445
y = algmat2basis(al,y);
2446
}
2447
if (signe(p)) res = FpM_FpC_invimage(algbasismultable(al,x),y,p);
2448
else
2449
{
2450
if (ty==al_ALGEBRAIC) mtx = algalgmultable(al,x);
2451
else mtx = algleftmultable(al,x);
2452
res = inverseimage(mtx,y);
2453
}
2454
if (!res || lg(res)==1) return gc_NULL(av);
2455
if (tx == al_MATRIX) {
2456
res = algbasis2mat(al, res, lg(x)-1);
2457
return gerepilecopy(av,res);
2458
}
2459
return gerepileupto(av,res);
2460
}
2461
static GEN
2462
algdivl_i2(GEN al, GEN x, GEN y)
2463
{
2464
long tx, ty;
2465
checkalg(al);
2466
tx = alg_model(al,x);
2467
ty = alg_model(al,y);
2468
if (tx == al_MATRIX) {
2469
if (ty != al_MATRIX) pari_err_TYPE2("\\", x, y);
2470
if (lg(y) == 1) return cgetg(1, t_MAT);
2471
if (lg(x) == 1) return NULL;
2472
if (lgcols(x) != lgcols(y)) pari_err_DIM("algdivl");
2473
if (lg(x) != lgcols(x) || lg(y) != lgcols(y))
2474
pari_err_DIM("algdivl (nonsquare)");
2475
}
2476
return algdivl_i(al,x,y,tx,ty);
2477
}
2478
2479
GEN algdivl(GEN al, GEN x, GEN y)
2480
{
2481
GEN z;
2482
z = algdivl_i2(al,x,y);
2483
if (!z) pari_err_INV("algdivl", x);
2484
return z;
2485
}
2486
2487
int
2488
algisdivl(GEN al, GEN x, GEN y, GEN* ptz)
2489
{
2490
pari_sp av = avma;
2491
GEN z = algdivl_i2(al,x,y);
2492
if (!z) return gc_bool(av,0);
2493
if (ptz != NULL) *ptz = z;
2494
return 1;
2495
}
2496
2497
static GEN
2498
alginv_i(GEN al, GEN x)
2499
{
2500
pari_sp av = avma;
2501
GEN res = NULL, p = alg_get_char(al);
2502
long tx = alg_model(al,x), n;
2503
switch(tx) {
2504
case al_TRIVIAL :
2505
if (signe(p)) { res = mkcol(Fp_inv(gel(x,1),p)); break; }
2506
else { res = mkcol(ginv(gel(x,1))); break; }
2507
case al_ALGEBRAIC :
2508
switch(alg_type(al)) {
2509
case al_CYCLIC: n = alg_get_degree(al); break;
2510
case al_CSA: n = alg_get_dim(al); break;
2511
default: return NULL; /* LCOV_EXCL_LINE */
2512
}
2513
res = algdivl_i(al, x, col_ei(n,1), tx, al_ALGEBRAIC); break;
2514
case al_BASIS : res = algdivl_i(al, x, col_ei(alg_get_absdim(al),1), tx,
2515
al_BASIS); break;
2516
case al_MATRIX :
2517
n = lg(x)-1;
2518
if (n==0) return cgetg(1, t_MAT);
2519
if (n != nbrows(x)) pari_err_DIM("alginv_i (nonsquare)");
2520
res = algdivl_i(al, x, col_ei(n*n*alg_get_absdim(al),1), tx, al_BASIS);
2521
/* cheat on type because wrong dimension */
2522
}
2523
if (!res) return gc_NULL(av);
2524
return gerepilecopy(av,res);
2525
}
2526
GEN
2527
alginv(GEN al, GEN x)
2528
{
2529
GEN z;
2530
checkalg(al);
2531
z = alginv_i(al,x);
2532
if (!z) pari_err_INV("alginv", x);
2533
return z;
2534
}
2535
2536
int
2537
algisinv(GEN al, GEN x, GEN* ptix)
2538
{
2539
pari_sp av = avma;
2540
GEN ix;
2541
checkalg(al);
2542
ix = alginv_i(al,x);
2543
if (!ix) return gc_bool(av,0);
2544
if (ptix != NULL) *ptix = ix;
2545
return 1;
2546
}
2547
2548
/* x*y^(-1) */
2549
GEN
2550
algdivr(GEN al, GEN x, GEN y) { return algmul(al, x, alginv(al, y)); }
2551
2552
static GEN _mul(void* data, GEN x, GEN y) { return algmul((GEN)data,x,y); }
2553
static GEN _sqr(void* data, GEN x) { return algsqr((GEN)data,x); }
2554
2555
static GEN
2556
algmatid(GEN al, long N)
2557
{
2558
long n = alg_get_absdim(al), i, j;
2559
GEN res, one, zero;
2560
2561
res = zeromatcopy(N,N);
2562
one = col_ei(n,1);
2563
zero = zerocol(n);
2564
for (i=1; i<=N; i++)
2565
for (j=1; j<=N; j++)
2566
gcoeff(res,i,j) = i==j ? one : zero;
2567
return res;
2568
}
2569
2570
GEN
2571
algpow(GEN al, GEN x, GEN n)
2572
{
2573
pari_sp av = avma;
2574
GEN res;
2575
checkalg(al);
2576
switch(signe(n)) {
2577
case 0:
2578
if (alg_model(al,x) == al_MATRIX)
2579
res = algmatid(al,lg(x)-1);
2580
else
2581
res = col_ei(alg_get_absdim(al),1);
2582
return res;
2583
case 1:
2584
res = gen_pow_i(x, n, (void*)al, _sqr, _mul); break;
2585
default: /* -1 */
2586
res = gen_pow_i(alginv(al,x), gneg(n), (void*)al, _sqr, _mul);
2587
}
2588
return gerepilecopy(av,res);
2589
}
2590
2591
static GEN
2592
algredcharpoly_i(GEN al, GEN x, long v)
2593
{
2594
GEN rnf = alg_get_splittingfield(al);
2595
GEN cp = charpoly(algtomatrix(al,x,0),v);
2596
long i, m = lg(cp);
2597
for (i=2; i<m; i++) gel(cp,i) = rnfeltdown(rnf, gel(cp,i));
2598
return cp;
2599
}
2600
2601
/* assumes al is CSA or CYCLIC */
2602
static GEN
2603
algredcharpoly(GEN al, GEN x, long v)
2604
{
2605
pari_sp av = avma;
2606
long w = gvar(rnf_get_pol(alg_get_center(al)));
2607
if (varncmp(v,w)>=0) pari_err_PRIORITY("algredcharpoly",pol_x(v),">=",w);
2608
switch(alg_type(al))
2609
{
2610
case al_CYCLIC:
2611
case al_CSA:
2612
return gerepileupto(av, algredcharpoly_i(al, x, v));
2613
}
2614
return NULL; /*LCOV_EXCL_LINE*/
2615
}
2616
2617
static GEN
2618
algbasischarpoly(GEN al, GEN x, long v)
2619
{
2620
pari_sp av = avma;
2621
GEN p = alg_get_char(al), mx;
2622
if (alg_model(al,x) == al_MATRIX) mx = algleftmultable_mat(al,x);
2623
else mx = algbasismultable(al,x);
2624
if (signe(p)) {
2625
GEN res = FpM_charpoly(mx,p);
2626
setvarn(res,v);
2627
return gerepileupto(av, res);
2628
}
2629
return gerepileupto(av, charpoly(mx,v));
2630
}
2631
2632
GEN
2633
algcharpoly(GEN al, GEN x, long v, long abs)
2634
{
2635
checkalg(al);
2636
if (v<0) v=0;
2637
2638
/* gneg(x[1]) left on stack */
2639
if (alg_model(al,x) == al_TRIVIAL) {
2640
GEN p = alg_get_char(al);
2641
if (signe(p)) return deg1pol(gen_1,Fp_neg(gel(x,1),p),v);
2642
return deg1pol(gen_1,gneg(gel(x,1)),v);
2643
}
2644
2645
switch(alg_type(al)) {
2646
case al_CYCLIC: case al_CSA:
2647
if (abs)
2648
{
2649
if (alg_model(al,x)==al_ALGEBRAIC) x = algalgtobasis(al,x);
2650
}
2651
else return algredcharpoly(al,x,v);
2652
case al_TABLE: return algbasischarpoly(al,x,v);
2653
default : return NULL; /* LCOV_EXCL_LINE */
2654
}
2655
}
2656
2657
/* assumes x in basis form */
2658
static GEN
2659
algabstrace(GEN al, GEN x)
2660
{
2661
pari_sp av = avma;
2662
GEN res = NULL, p = alg_get_char(al);
2663
if (signe(p)) return FpV_dotproduct(x, alg_get_tracebasis(al), p);
2664
switch(alg_model(al,x)) {
2665
case al_TRIVIAL: return gcopy(gel(x,1)); break;
2666
case al_BASIS: res = RgV_dotproduct(x, alg_get_tracebasis(al)); break;
2667
}
2668
return gerepileupto(av,res);
2669
}
2670
2671
static GEN
2672
algredtrace(GEN al, GEN x)
2673
{
2674
pari_sp av = avma;
2675
GEN res = NULL;
2676
switch(alg_model(al,x)) {
2677
case al_TRIVIAL: return gcopy(gel(x,1)); break;
2678
case al_BASIS: return algredtrace(al, algbasistoalg(al,x));
2679
/* TODO precompute too? */
2680
case al_ALGEBRAIC:
2681
switch(alg_type(al))
2682
{
2683
case al_CYCLIC:
2684
res = rnfelttrace(alg_get_splittingfield(al),gel(x,1));
2685
break;
2686
case al_CSA:
2687
res = gtrace(algalgmultable_csa(al,x));
2688
res = gdiv(res, stoi(alg_get_degree(al)));
2689
break;
2690
default: return NULL; /* LCOV_EXCL_LINE */
2691
}
2692
}
2693
return gerepileupto(av,res);
2694
}
2695
2696
static GEN
2697
algtrace_mat(GEN al, GEN M, long abs) {
2698
pari_sp av = avma;
2699
long N = lg(M)-1, i;
2700
GEN res, p = alg_get_char(al);
2701
if (N == 0) return gen_0;
2702
if (N != nbrows(M)) pari_err_DIM("algtrace_mat (nonsquare)");
2703
2704
if (!signe(p)) p = NULL;
2705
res = algtrace(al, gcoeff(M,1,1), abs);
2706
for (i=2; i<=N; i++) {
2707
if (p) res = Fp_add(res, algtrace(al,gcoeff(M,i,i),abs), p);
2708
else res = gadd(res, algtrace(al,gcoeff(M,i,i),abs));
2709
}
2710
if (abs || alg_type(al) == al_TABLE) res = gmulgs(res, N); /* absolute trace */
2711
return gerepileupto(av, res);
2712
}
2713
2714
GEN
2715
algtrace(GEN al, GEN x, long abs)
2716
{
2717
checkalg(al);
2718
if (alg_model(al,x) == al_MATRIX) return algtrace_mat(al,x,abs);
2719
switch(alg_type(al)) {
2720
case al_CYCLIC: case al_CSA:
2721
if (!abs) return algredtrace(al,x);
2722
if (alg_model(al,x)==al_ALGEBRAIC) x = algalgtobasis(al,x);
2723
case al_TABLE: return algabstrace(al,x);
2724
default : return NULL; /* LCOV_EXCL_LINE */
2725
}
2726
}
2727
2728
static GEN
2729
ZM_trace(GEN x)
2730
{
2731
long i, lx = lg(x);
2732
GEN t;
2733
if (lx < 3) return lx == 1? gen_0: gcopy(gcoeff(x,1,1));
2734
t = gcoeff(x,1,1);
2735
for (i = 2; i < lx; i++) t = addii(t, gcoeff(x,i,i));
2736
return t;
2737
}
2738
static GEN
2739
FpM_trace(GEN x, GEN p)
2740
{
2741
long i, lx = lg(x);
2742
GEN t;
2743
if (lx < 3) return lx == 1? gen_0: gcopy(gcoeff(x,1,1));
2744
t = gcoeff(x,1,1);
2745
for (i = 2; i < lx; i++) t = Fp_add(t, gcoeff(x,i,i), p);
2746
return t;
2747
}
2748
2749
static GEN
2750
algtracebasis(GEN al)
2751
{
2752
pari_sp av = avma;
2753
GEN mt = alg_get_multable(al), p = alg_get_char(al);
2754
long i, l = lg(mt);
2755
GEN v = cgetg(l, t_VEC);
2756
if (signe(p)) for (i=1; i < l; i++) gel(v,i) = FpM_trace(gel(mt,i), p);
2757
else for (i=1; i < l; i++) gel(v,i) = ZM_trace(gel(mt,i));
2758
return gerepileupto(av,v);
2759
}
2760
2761
/* Assume: i > 0, expo := p^i <= absdim, x contained in I_{i-1} given by mult
2762
* table modulo modu=p^(i+1). Return Tr(x^(p^i)) mod modu */
2763
static ulong
2764
algtracei(GEN mt, ulong p, ulong expo, ulong modu)
2765
{
2766
pari_sp av = avma;
2767
long j, l = lg(mt);
2768
ulong tr = 0;
2769
mt = Flm_powu(mt,expo,modu);
2770
for (j=1; j<l; j++) tr += ucoeff(mt,j,j);
2771
return gc_ulong(av, (tr/expo) % p);
2772
}
2773
2774
GEN
2775
algnorm(GEN al, GEN x, long abs)
2776
{
2777
pari_sp av = avma;
2778
long tx;
2779
GEN p, rnf, res, mx;
2780
checkalg(al);
2781
p = alg_get_char(al);
2782
tx = alg_model(al,x);
2783
if (signe(p)) {
2784
if (tx == al_MATRIX) mx = algleftmultable_mat(al,x);
2785
else mx = algbasismultable(al,x);
2786
return gerepileupto(av, FpM_det(mx,p));
2787
}
2788
if (tx == al_TRIVIAL) return gcopy(gel(x,1));
2789
2790
switch(alg_type(al)) {
2791
case al_CYCLIC: case al_CSA:
2792
if (abs)
2793
{
2794
if (alg_model(al,x)==al_ALGEBRAIC) x = algalgtobasis(al,x);
2795
}
2796
else
2797
{
2798
rnf = alg_get_splittingfield(al);
2799
res = rnfeltdown(rnf, det(algtomatrix(al,x,0)));
2800
break;
2801
}
2802
case al_TABLE:
2803
if (tx == al_MATRIX) mx = algleftmultable_mat(al,x);
2804
else mx = algbasismultable(al,x);
2805
res = det(mx);
2806
break;
2807
default: return NULL; /* LCOV_EXCL_LINE */
2808
}
2809
return gerepileupto(av, res);
2810
}
2811
2812
static GEN
2813
algalgtonat_cyc(GEN al, GEN x)
2814
{
2815
pari_sp av = avma;
2816
GEN nf = alg_get_abssplitting(al), rnf = alg_get_splittingfield(al), res, c;
2817
long n = alg_get_degree(al), N = nf_get_degree(nf), i, i1;
2818
res = zerocol(N*n);
2819
for (i=0; i<n; i++) {
2820
c = gel(x,i+1);
2821
c = rnfeltreltoabs(rnf,c);
2822
if (!gequal0(c)) {
2823
c = algtobasis(nf,c);
2824
for (i1=1; i1<=N; i1++) gel(res,i*N+i1) = gel(c,i1);
2825
}
2826
}
2827
return gerepilecopy(av, res);
2828
}
2829
2830
static GEN
2831
algalgtonat_csa(GEN al, GEN x)
2832
{
2833
pari_sp av = avma;
2834
GEN nf = alg_get_center(al), res, c;
2835
long d2 = alg_get_dim(al), n = nf_get_degree(nf), i, i1;
2836
res = zerocol(d2*n);
2837
for (i=0; i<d2; i++) {
2838
c = gel(x,i+1);
2839
if (!gequal0(c)) {
2840
c = algtobasis(nf,c);
2841
for (i1=1; i1<=n; i1++) gel(res,i*n+i1) = gel(c,i1);
2842
}
2843
}
2844
return gerepilecopy(av, res);
2845
}
2846
2847
/* assumes al CSA or CYCLIC */
2848
static GEN
2849
algalgtonat(GEN al, GEN x)
2850
{
2851
switch(alg_type(al))
2852
{
2853
case al_CYCLIC: return algalgtonat_cyc(al, x);
2854
case al_CSA: return algalgtonat_csa(al, x);
2855
}
2856
return NULL; /*LCOV_EXCL_LINE*/
2857
}
2858
2859
static GEN
2860
algnattoalg_cyc(GEN al, GEN x)
2861
{
2862
pari_sp av = avma;
2863
GEN nf = alg_get_abssplitting(al), rnf = alg_get_splittingfield(al), res, c;
2864
long n = alg_get_degree(al), N = nf_get_degree(nf), i, i1;
2865
res = zerocol(n);
2866
c = zerocol(N);
2867
for (i=0; i<n; i++) {
2868
for (i1=1; i1<=N; i1++) gel(c,i1) = gel(x,i*N+i1);
2869
gel(res,i+1) = rnfeltabstorel(rnf,basistoalg(nf,c));
2870
}
2871
return gerepilecopy(av, res);
2872
}
2873
2874
static GEN
2875
algnattoalg_csa(GEN al, GEN x)
2876
{
2877
pari_sp av = avma;
2878
GEN nf = alg_get_center(al), res, c;
2879
long d2 = alg_get_dim(al), n = nf_get_degree(nf), i, i1;
2880
res = zerocol(d2);
2881
c = zerocol(n);
2882
for (i=0; i<d2; i++) {
2883
for (i1=1; i1<=n; i1++) gel(c,i1) = gel(x,i*n+i1);
2884
gel(res,i+1) = basistoalg(nf,c);
2885
}
2886
return gerepilecopy(av, res);
2887
}
2888
2889
/* assumes al CSA or CYCLIC */
2890
static GEN
2891
algnattoalg(GEN al, GEN x)
2892
{
2893
switch(alg_type(al))
2894
{
2895
case al_CYCLIC: return algnattoalg_cyc(al, x);
2896
case al_CSA: return algnattoalg_csa(al, x);
2897
}
2898
return NULL; /*LCOV_EXCL_LINE*/
2899
}
2900
2901
static GEN
2902
algalgtobasis_mat(GEN al, GEN x) /* componentwise */
2903
{
2904
pari_sp av = avma;
2905
long lx, lxj, i, j;
2906
GEN res;
2907
lx = lg(x);
2908
res = cgetg(lx, t_MAT);
2909
for (j=1; j<lx; j++) {
2910
lxj = lg(gel(x,j));
2911
gel(res,j) = cgetg(lxj, t_COL);
2912
for (i=1; i<lxj; i++)
2913
gcoeff(res,i,j) = algalgtobasis(al,gcoeff(x,i,j));
2914
}
2915
return gerepilecopy(av,res);
2916
}
2917
GEN
2918
algalgtobasis(GEN al, GEN x)
2919
{
2920
pari_sp av;
2921
long tx;
2922
checkalg(al);
2923
if (alg_type(al) == al_TABLE) pari_err_TYPE("algalgtobasis [use alginit]", al);
2924
tx = alg_model(al,x);
2925
if (tx==al_BASIS) return gcopy(x);
2926
if (tx==al_MATRIX) return algalgtobasis_mat(al,x);
2927
av = avma;
2928
x = algalgtonat(al,x);
2929
x = RgM_RgC_mul(alg_get_invbasis(al),x);
2930
return gerepileupto(av, x);
2931
}
2932
2933
static GEN
2934
algbasistoalg_mat(GEN al, GEN x) /* componentwise */
2935
{
2936
long j, lx = lg(x);
2937
GEN res = cgetg(lx, t_MAT);
2938
for (j=1; j<lx; j++) {
2939
long i, lxj = lg(gel(x,j));
2940
gel(res,j) = cgetg(lxj, t_COL);
2941
for (i=1; i<lxj; i++) gcoeff(res,i,j) = algbasistoalg(al,gcoeff(x,i,j));
2942
}
2943
return res;
2944
}
2945
GEN
2946
algbasistoalg(GEN al, GEN x)
2947
{
2948
pari_sp av;
2949
long tx;
2950
checkalg(al);
2951
if (alg_type(al) == al_TABLE) pari_err_TYPE("algbasistoalg [use alginit]", al);
2952
tx = alg_model(al,x);
2953
if (tx==al_ALGEBRAIC) return gcopy(x);
2954
if (tx==al_MATRIX) return algbasistoalg_mat(al,x);
2955
av = avma;
2956
x = RgM_RgC_mul(alg_get_basis(al),x);
2957
x = algnattoalg(al,x);
2958
return gerepileupto(av, x);
2959
}
2960
2961
GEN
2962
algrandom(GEN al, GEN b)
2963
{
2964
GEN res, p, N;
2965
long i, n;
2966
if (typ(b) != t_INT) pari_err_TYPE("algrandom",b);
2967
if (signe(b)<0) pari_err_DOMAIN("algrandom", "b", "<", gen_0, b);
2968
checkalg(al);
2969
n = alg_get_absdim(al);
2970
N = addiu(shifti(b,1), 1); /* left on stack */
2971
p = alg_get_char(al); if (!signe(p)) p = NULL;
2972
res = cgetg(n+1,t_COL);
2973
for (i=1; i<= n; i++)
2974
{
2975
pari_sp av = avma;
2976
GEN t = subii(randomi(N),b);
2977
if (p) t = modii(t, p);
2978
gel(res,i) = gerepileuptoint(av, t);
2979
}
2980
return res;
2981
}
2982
2983
/* Assumes pol has coefficients in the same ring as the COL x; x either
2984
* in basis or algebraic form or [x,mx] where mx is the mult. table of x.
2985
TODO more general version: pol with coeffs in center and x in basis form */
2986
GEN
2987
algpoleval(GEN al, GEN pol, GEN x)
2988
{
2989
pari_sp av = avma;
2990
GEN p, mx = NULL, res;
2991
long i;
2992
checkalg(al);
2993
p = alg_get_char(al);
2994
if (typ(pol) != t_POL) pari_err_TYPE("algpoleval", pol);
2995
if (typ(x) == t_VEC)
2996
{
2997
if (lg(x) != 3) pari_err_TYPE("algpoleval [vector must be of length 2]", x);
2998
mx = gel(x,2);
2999
x = gel(x,1);
3000
if (typ(mx)!=t_MAT || !gequal(x,gel(mx,1)))
3001
pari_err_TYPE("algpoleval [mx must be the multiplication table of x]", mx);
3002
}
3003
else
3004
{
3005
switch(alg_model(al,x))
3006
{
3007
case al_ALGEBRAIC: mx = algalgmultable(al,x); break;
3008
case al_BASIS: if (!RgX_is_QX(pol))
3009
pari_err_IMPL("algpoleval with x in basis form and pol not in Q[x]");
3010
case al_TRIVIAL: mx = algbasismultable(al,x); break;
3011
default: pari_err_TYPE("algpoleval", x);
3012
}
3013
}
3014
res = zerocol(lg(mx)-1);
3015
if (signe(p)) {
3016
for (i=lg(pol)-1; i>1; i--)
3017
{
3018
gel(res,1) = Fp_add(gel(res,1), gel(pol,i), p);
3019
if (i>2) res = FpM_FpC_mul(mx, res, p);
3020
}
3021
}
3022
else {
3023
for (i=lg(pol)-1; i>1; i--)
3024
{
3025
gel(res,1) = gadd(gel(res,1), gel(pol,i));
3026
if (i>2) res = RgM_RgC_mul(mx, res);
3027
}
3028
}
3029
return gerepileupto(av, res);
3030
}
3031
3032
/** GRUNWALD-WANG **/
3033
/*
3034
Song Wang's PhD thesis (pdf pages)
3035
p.25 definition of chi_b. K^Ker(chi_b) = K(b^(1/m))
3036
p.26 bound on the conductor (also Cohen adv. GTM 193 p.166)
3037
p.21 & p.34 description special case, also on wikipedia:
3038
http://en.wikipedia.org/wiki/Grunwald%E2%80%93Wang_theorem#Special_fields
3039
p.77 Kummer case
3040
*/
3041
3042
/* n > 0. Is n = 2^k ? */
3043
static int
3044
uispow2(ulong n) { return !(n &(n-1)); }
3045
3046
static GEN
3047
get_phi0(GEN bnr, GEN Lpr, GEN Ld, GEN pl, long *pr, long *pn)
3048
{
3049
const long NTRY = 10; /* FIXME: magic constant */
3050
const long n = (lg(Ld)==1)? 2: vecsmall_max(Ld);
3051
GEN S = bnr_get_cyc(bnr);
3052
GEN Sst, G, globGmod, loc, X, Rglob, Rloc, H, U, Lconj;
3053
long i, j, r, nbfrob, nbloc, nz, t;
3054
3055
*pn = n;
3056
*pr = r = lg(S)-1;
3057
if (!r) return NULL;
3058
Lconj = NULL;
3059
nbloc = nbfrob = lg(Lpr)-1;
3060
if (uispow2(n))
3061
{
3062
long l = lg(pl), k = 1;
3063
GEN real = cgetg(l, t_VECSMALL);
3064
for (i=1; i<l; i++)
3065
if (pl[i]==-1) real[k++] = i;
3066
if (k > 1)
3067
{
3068
GEN nf = bnr_get_nf(bnr), I = bid_get_fact(bnr_get_bid(bnr));
3069
GEN v, y, C = idealchineseinit(bnr, I);
3070
long r1 = nf_get_r1(nf), n = nbrows(I);
3071
nbloc += k-1;
3072
Lconj = cgetg(k, t_VEC);
3073
v = const_vecsmall(r1,1);
3074
y = const_vec(n, gen_1);
3075
for (i = 1; i < k; i++)
3076
{
3077
v[i] = -1; gel(Lconj,i) = idealchinese(nf,mkvec2(C,v),y);
3078
v[i] = 1;
3079
}
3080
}
3081
}
3082
3083
/* compute Z/n-dual */
3084
Sst = cgetg(r+1, t_VECSMALL);
3085
for (i=1; i<=r; i++) Sst[i] = ugcdiu(gel(S,i), n);
3086
if (Sst[1] != n) return NULL;
3087
3088
globGmod = cgetg(r+1,t_MAT);
3089
G = cgetg(r+1,t_VECSMALL);
3090
for (i=1; i<=r; i++)
3091
{
3092
G[i] = n / Sst[i]; /* pairing between S and Sst */
3093
gel(globGmod,i) = cgetg(nbloc+1,t_VECSMALL);
3094
}
3095
3096
/* compute images of Frobenius elements (and complex conjugation) */
3097
loc = cgetg(nbloc+1,t_VECSMALL);
3098
for (i=1; i<=nbloc; i++) {
3099
long L;
3100
if (i<=nbfrob)
3101
{
3102
X = gel(Lpr,i);
3103
L = Ld[i];
3104
}
3105
else
3106
{ /* X = 1 (mod f), sigma_i(x) < 0, positive at all other real places */
3107
X = gel(Lconj,i-nbfrob);
3108
L = 2;
3109
}
3110
X = ZV_to_Flv(isprincipalray(bnr,X), n);
3111
for (nz=0,j=1; j<=r; j++)
3112
{
3113
ulong c = (X[j] * G[j]) % L;
3114
ucoeff(globGmod,i,j) = c;
3115
if (c) nz = 1;
3116
}
3117
if (!nz) return NULL;
3118
loc[i] = L;
3119
}
3120
3121
/* try some random elements in the dual */
3122
Rglob = cgetg(r+1,t_VECSMALL);
3123
for (t=0; t<NTRY; t++) {
3124
for (j=1; j<=r; j++) Rglob[j] = random_Fl(Sst[j]);
3125
Rloc = zm_zc_mul(globGmod,Rglob);
3126
for (i=1; i<=nbloc; i++)
3127
if (Rloc[i] % loc[i] == 0) break;
3128
if (i > nbloc)
3129
return zv_to_ZV(Rglob);
3130
}
3131
3132
/* try to realize some random elements of the product of the local duals */
3133
H = ZM_hnfall_i(shallowconcat(zm_to_ZM(globGmod),
3134
diagonal_shallow(zv_to_ZV(loc))), &U, 2);
3135
/* H,U nbloc x nbloc */
3136
Rloc = cgetg(nbloc+1,t_COL);
3137
for (t=0; t<NTRY; t++) {
3138
/* nonzero random coordinate */ /* TODO add special case ? */
3139
for (i=1; i<=nbloc; i++) gel(Rloc,i) = stoi(1 + random_Fl(loc[i]-1));
3140
Rglob = hnf_invimage(H, Rloc);
3141
if (Rglob)
3142
{
3143
Rglob = ZM_ZC_mul(U,Rglob);
3144
return vecslice(Rglob,1,r);
3145
}
3146
}
3147
return NULL;
3148
}
3149
3150
static GEN
3151
bnrgwsearch(GEN bnr, GEN Lpr, GEN Ld, GEN pl)
3152
{
3153
pari_sp av = avma;
3154
long n, r;
3155
GEN phi0 = get_phi0(bnr,Lpr,Ld,pl, &r,&n), gn, v, H,U;
3156
if (!phi0) return gc_const(av, gen_0);
3157
gn = stoi(n);
3158
/* compute kernel of phi0 */
3159
v = ZV_extgcd(vec_append(phi0, gn));
3160
U = vecslice(gel(v,2), 1,r);
3161
H = ZM_hnfmodid(rowslice(U, 1,r), gn);
3162
return gerepileupto(av, H);
3163
}
3164
3165
GEN
3166
bnfgwgeneric(GEN bnf, GEN Lpr, GEN Ld, GEN pl, long var)
3167
{
3168
pari_sp av = avma;
3169
const long n = (lg(Ld)==1)? 2: vecsmall_max(Ld);
3170
forprime_t S;
3171
GEN bnr = NULL, ideal = gen_1, nf, dec, H = gen_0, finf, pol;
3172
ulong ell, p;
3173
long deg, i, degell;
3174
(void)uisprimepower(n, &ell);
3175
nf = bnf_get_nf(bnf);
3176
deg = nf_get_degree(nf);
3177
degell = ugcd(deg,ell-1);
3178
finf = cgetg(lg(pl),t_VEC);
3179
for (i=1; i<lg(pl); i++) gel(finf,i) = pl[i]==-1 ? gen_1 : gen_0;
3180
3181
u_forprime_init(&S, 2, ULONG_MAX);
3182
while ((p = u_forprime_next(&S))) {
3183
if (Fl_powu(p % ell, degell, ell) != 1) continue; /* ell | p^deg-1 ? */
3184
dec = idealprimedec(nf, utoipos(p));
3185
for (i=1; i<lg(dec); i++) {
3186
GEN pp = gel(dec,i);
3187
if (RgV_isin(Lpr,pp)) continue;
3188
/* TODO also accept the prime ideals at which there is a condition
3189
* (use local Artin)? */
3190
if (smodis(idealnorm(nf,pp),ell) != 1) continue; /* ell | N(pp)-1 ? */
3191
ideal = idealmul(bnf,ideal,pp);
3192
/* TODO: give factorization ? */
3193
bnr = Buchray(bnf, mkvec2(ideal,finf), nf_INIT);
3194
H = bnrgwsearch(bnr,Lpr,Ld,pl);
3195
if (H != gen_0)
3196
{
3197
pol = rnfkummer(bnr,H,nf_get_prec(nf));
3198
setvarn(pol, var);
3199
return gerepileupto(av,pol);
3200
}
3201
}
3202
}
3203
pari_err_BUG("bnfgwgeneric (no suitable p)"); /*LCOV_EXCL_LINE*/
3204
return NULL;/*LCOV_EXCL_LINE*/
3205
}
3206
3207
/* no garbage collection */
3208
static GEN
3209
localextdeg(GEN nf, GEN pr, GEN cnd, long d, long ell, long n)
3210
{
3211
long g = n/d;
3212
GEN res, modpr, ppr = pr, T, p, gen, k;
3213
if (d==1) return gen_1;
3214
if (equalsi(ell,pr_get_p(pr))) { /* ell == p */
3215
res = nfadd(nf, gen_1, pr_get_gen(pr));
3216
res = nfpowmodideal(nf, res, stoi(g), cnd);
3217
}
3218
else { /* ell != p */
3219
k = powis(stoi(ell),Z_lval(subiu(pr_norm(pr),1),ell));
3220
k = divis(k,g);
3221
modpr = nf_to_Fq_init(nf, &ppr, &T, &p);
3222
(void)Fq_sqrtn(gen_1,k,T,p,&gen);
3223
res = Fq_to_nf(gen, modpr);
3224
}
3225
return res;
3226
}
3227
3228
/* Ld[i] must be nontrivial powers of the same prime ell */
3229
/* pl : -1 at real places at which the extention must ramify, 0 elsewhere */
3230
GEN
3231
nfgwkummer(GEN nf, GEN Lpr, GEN Ld, GEN pl, long var)
3232
{
3233
const long n = (lg(Ld)==1)? 2: vecsmall_max(Ld);
3234
pari_sp av = avma;
3235
ulong ell;
3236
long i, v;
3237
GEN cnd, y, x, pol;
3238
v = uisprimepower(n, &ell);
3239
cnd = zeromatcopy(lg(Lpr)-1,2);
3240
3241
y = vec_ei(lg(Lpr)-1,1);
3242
for (i=1; i<lg(Lpr); i++) {
3243
GEN pr = gel(Lpr,i), p = pr_get_p(pr), E;
3244
long e = pr_get_e(pr);
3245
gcoeff(cnd,i,1) = pr;
3246
3247
if (!absequalui(ell,p))
3248
E = gen_1;
3249
else
3250
E = addui(1 + v*e, divsi(e,subiu(p,1)));
3251
gcoeff(cnd,i,2) = E;
3252
gel(y,i) = localextdeg(nf, pr, idealpow(nf,pr,E), Ld[i], ell, n);
3253
}
3254
3255
/* TODO use a factoredextchinese to ease computations afterwards ? */
3256
x = idealchinese(nf, mkvec2(cnd,pl), y);
3257
x = basistoalg(nf,x);
3258
pol = gsub(gpowgs(pol_x(var),n),x);
3259
3260
return gerepileupto(av,pol);
3261
}
3262
3263
static GEN
3264
get_vecsmall(GEN v)
3265
{
3266
switch(typ(v))
3267
{
3268
case t_VECSMALL: return v;
3269
case t_VEC: if (RgV_is_ZV(v)) return ZV_to_zv(v);
3270
}
3271
pari_err_TYPE("nfgrunwaldwang",v);
3272
return NULL;/*LCOV_EXCL_LINE*/
3273
}
3274
GEN
3275
nfgrunwaldwang(GEN nf0, GEN Lpr, GEN Ld, GEN pl, long var)
3276
{
3277
ulong n, ell, ell2;
3278
pari_sp av = avma;
3279
GEN nf, bnf;
3280
long t, w, i, vnf;
3281
3282
if (var < 0) var = 0;
3283
nf = get_nf(nf0,&t);
3284
if (!nf) pari_err_TYPE("nfgrunwaldwang",nf0);
3285
vnf = nf_get_varn(nf);
3286
if (varncmp(var, vnf) >= 0)
3287
pari_err_PRIORITY("nfgrunwaldwang", pol_x(var), ">=", vnf);
3288
if (typ(Lpr) != t_VEC) pari_err_TYPE("nfgrunwaldwang",Lpr);
3289
if (lg(Lpr) != lg(Ld)) pari_err_DIM("nfgrunwaldwang [#Lpr != #Ld]");
3290
if (nf_get_degree(nf)==1) Lpr = shallowcopy(Lpr);
3291
for (i=1; i<lg(Lpr); i++) {
3292
GEN pr = gel(Lpr,i);
3293
if (nf_get_degree(nf)==1 && typ(pr)==t_INT)
3294
gel(Lpr,i) = gel(idealprimedec(nf,pr), 1);
3295
else checkprid(pr);
3296
}
3297
if (lg(pl)-1 != nf_get_r1(nf))
3298
pari_err_DOMAIN("nfgrunwaldwang [pl should have r1 components]", "#pl",
3299
"!=", stoi(nf_get_r1(nf)), stoi(lg(pl)-1));
3300
3301
Ld = get_vecsmall(Ld);
3302
pl = get_vecsmall(pl);
3303
bnf = get_bnf(nf0,&t);
3304
n = (lg(Ld)==1)? 2: vecsmall_max(Ld);
3305
3306
if (!uisprimepower(n, &ell))
3307
pari_err_IMPL("nfgrunwaldwang for non prime-power local degrees (a)");
3308
for (i=1; i<lg(Ld); i++)
3309
if (Ld[i]!=1 && (!uisprimepower(Ld[i],&ell2) || ell2!=ell))
3310
pari_err_IMPL("nfgrunwaldwang for non prime-power local degrees (b)");
3311
for (i=1; i<lg(pl); i++)
3312
if (pl[i]==-1 && ell%2)
3313
pari_err_IMPL("nfgrunwaldwang for non prime-power local degrees (c)");
3314
3315
w = bnf? bnf_get_tuN(bnf): itos(gel(nfrootsof1(nf),1));
3316
3317
/* TODO choice between kummer and generic ? Let user choose between speed
3318
* and size */
3319
if (w%n==0 && lg(Ld)>1)
3320
return gerepileupto(av,nfgwkummer(nf,Lpr,Ld,pl,var));
3321
if (ell==n) {
3322
if (!bnf) bnf = Buchall(nf, nf_FORCE, 0);
3323
return gerepileupto(av,bnfgwgeneric(bnf,Lpr,Ld,pl,var));
3324
}
3325
pari_err_IMPL("nfgrunwaldwang for nonprime degree");
3326
return NULL; /*LCOV_EXCL_LINE*/
3327
}
3328
3329
/** HASSE INVARIANTS **/
3330
3331
/* TODO long -> ulong + uel */
3332
static GEN
3333
hasseconvert(GEN H, long n)
3334
{
3335
GEN h, c;
3336
long i, l;
3337
switch(typ(H)) {
3338
case t_VEC:
3339
l = lg(H); h = cgetg(l,t_VECSMALL);
3340
if (l == 1) return h;
3341
c = gel(H,1);
3342
if (typ(c) == t_VEC && l == 3)
3343
return mkvec2(gel(H,1),hasseconvert(gel(H,2),n));
3344
for (i=1; i<l; i++)
3345
{
3346
c = gel(H,i);
3347
switch(typ(c)) {
3348
case t_INT: break;
3349
case t_INTMOD:
3350
c = gel(c,2); break;
3351
case t_FRAC :
3352
c = gmulgs(c,n);
3353
if (typ(c) == t_INT) break;
3354
pari_err_DOMAIN("hasseconvert [degree should be a denominator of the invariant]", "denom(h)", "ndiv", stoi(n), Q_denom(gel(H,i)));
3355
default : pari_err_TYPE("Hasse invariant", c);
3356
}
3357
h[i] = smodis(c,n);
3358
}
3359
return h;
3360
case t_VECSMALL: return H;
3361
}
3362
pari_err_TYPE("Hasse invariant", H);
3363
return NULL;/*LCOV_EXCL_LINE*/
3364
}
3365
3366
/* assume f >= 2 */
3367
static long
3368
cyclicrelfrob0(GEN nf, GEN aut, GEN pr, GEN q, long f, long g)
3369
{
3370
GEN T, p, a, b, modpr = nf_to_Fq_init(nf,&pr,&T,&p);
3371
long s;
3372
3373
a = pol_x(nf_get_varn(nf));
3374
b = galoisapply(nf, aut, modpr_genFq(modpr));
3375
b = nf_to_Fq(nf, b, modpr);
3376
for (s = 0; !ZX_equal(a, b); s++) a = Fq_pow(a, q, T, p);
3377
return g * Fl_inv(s, f); /* < n */
3378
}
3379
3380
static long
3381
cyclicrelfrob(GEN rnf, GEN auts, GEN pr)
3382
{
3383
pari_sp av = avma;
3384
long f,g,frob, n = rnf_get_degree(rnf);
3385
GEN P = rnfidealprimedec(rnf, pr);
3386
3387
if (pr_get_e(gel(P,1)) > pr_get_e(pr))
3388
pari_err_DOMAIN("cyclicrelfrob","e(PR/pr)",">",gen_1,pr);
3389
g = lg(P) - 1;
3390
f = n / g;
3391
3392
if (f <= 2) frob = g % n;
3393
else {
3394
GEN nf2, PR = gel(P,1);
3395
GEN autabs = rnfeltreltoabs(rnf,gel(auts,g));
3396
nf2 = obj_check(rnf,rnf_NFABS);
3397
autabs = nfadd(nf2, autabs, gmul(rnf_get_k(rnf), rnf_get_alpha(rnf)));
3398
frob = cyclicrelfrob0(nf2, autabs, PR, pr_norm(pr), f, g);
3399
}
3400
return gc_long(av, frob);
3401
}
3402
3403
static long
3404
localhasse(GEN rnf, GEN cnd, GEN pl, GEN auts, GEN b, long k)
3405
{
3406
pari_sp av = avma;
3407
long v, m, h, lfa, frob, n, i;
3408
GEN previous, y, pr, nf, q, fa;
3409
nf = rnf_get_nf(rnf);
3410
n = rnf_get_degree(rnf);
3411
pr = gcoeff(cnd,k,1);
3412
v = nfval(nf, b, pr);
3413
m = lg(cnd)>1 ? nbrows(cnd) : 0;
3414
3415
/* add the valuation of b to the conductor... */
3416
previous = gcoeff(cnd,k,2);
3417
gcoeff(cnd,k,2) = addis(previous, v);
3418
3419
y = const_vec(m, gen_1);
3420
gel(y,k) = b;
3421
/* find a factored element y congruent to b mod pr^(vpr(b)+vpr(cnd)) and to 1 mod the conductor. */
3422
y = factoredextchinese(nf, cnd, y, pl, &fa);
3423
h = 0;
3424
lfa = nbrows(fa);
3425
/* sum of all Hasse invariants of (rnf/nf,aut,y) is 0, Hasse invariants at q!=pr are easy, Hasse invariant at pr is the same as for al=(rnf/nf,aut,b). */
3426
for (i=1; i<=lfa; i++) {
3427
q = gcoeff(fa,i,1);
3428
if (cmp_prime_ideal(pr,q)) {
3429
frob = cyclicrelfrob(rnf, auts, q);
3430
frob = Fl_mul(frob,umodiu(gcoeff(fa,i,2),n),n);
3431
h = Fl_add(h,frob,n);
3432
}
3433
}
3434
/* ...then restore it. */
3435
gcoeff(cnd,k,2) = previous;
3436
return gc_long(av, Fl_neg(h,n));
3437
}
3438
3439
static GEN
3440
allauts(GEN rnf, GEN aut)
3441
{
3442
long n = rnf_get_degree(rnf), i;
3443
GEN pol = rnf_get_pol(rnf), vaut;
3444
if (n==1) n=2;
3445
vaut = cgetg(n,t_VEC);
3446
aut = lift_shallow(rnfbasistoalg(rnf,aut));
3447
gel(vaut,1) = aut;
3448
for (i=1; i<n-1; i++)
3449
gel(vaut,i+1) = RgX_rem(poleval(gel(vaut,i), aut), pol);
3450
return vaut;
3451
}
3452
3453
static GEN
3454
clean_factor(GEN fa)
3455
{
3456
GEN P2,E2, P = gel(fa,1), E = gel(fa,2);
3457
long l = lg(P), i, j = 1;
3458
P2 = cgetg(l, t_COL);
3459
E2 = cgetg(l, t_COL);
3460
for (i = 1;i < l; i++)
3461
if (signe(gel(E,i))) {
3462
gel(P2,j) = gel(P,i);
3463
gel(E2,j) = gel(E,i); j++;
3464
}
3465
setlg(P2,j);
3466
setlg(E2,j); return mkmat2(P2,E2);
3467
}
3468
3469
/* shallow concat x[1],...x[nx],y[1], ... y[ny], returning a t_COL. To be
3470
* used when we do not know whether x,y are t_VEC or t_COL */
3471
static GEN
3472
colconcat(GEN x, GEN y)
3473
{
3474
long i, lx = lg(x), ly = lg(y);
3475
GEN z=cgetg(lx+ly-1, t_COL);
3476
for (i=1; i<lx; i++) z[i] = x[i];
3477
for (i=1; i<ly; i++) z[lx+i-1]= y[i];
3478
return z;
3479
}
3480
3481
/* return v(x) at all primes in listpr, replace x by cofactor */
3482
static GEN
3483
nfmakecoprime(GEN nf, GEN *px, GEN listpr)
3484
{
3485
long j, l = lg(listpr);
3486
GEN x1, x = *px, L = cgetg(l, t_COL);
3487
3488
if (typ(x) != t_MAT)
3489
{ /* scalar, divide at the end (fast valuation) */
3490
x1 = NULL;
3491
for (j=1; j<l; j++)
3492
{
3493
GEN pr = gel(listpr,j), e;
3494
long v = nfval(nf, x, pr);
3495
e = stoi(v); gel(L,j) = e;
3496
if (v) x1 = x1? idealmulpowprime(nf, x1, pr, e)
3497
: idealpow(nf, pr, e);
3498
}
3499
if (x1) x = idealdivexact(nf, idealhnf(nf,x), x1);
3500
}
3501
else
3502
{ /* HNF, divide as we proceed (reduce size) */
3503
for (j=1; j<l; j++)
3504
{
3505
GEN pr = gel(listpr,j);
3506
long v = idealval(nf, x, pr);
3507
gel(L,j) = stoi(v);
3508
if (v) x = idealmulpowprime(nf, x, pr, stoi(-v));
3509
}
3510
}
3511
*px = x; return L;
3512
}
3513
3514
/* Caveat: factorizations are not sorted wrt cmp_prime_ideal: Lpr comes first */
3515
static GEN
3516
computecnd(GEN rnf, GEN Lpr)
3517
{
3518
GEN id, nf, fa, Le, P,E;
3519
long n = rnf_get_degree(rnf);
3520
3521
nf = rnf_get_nf(rnf);
3522
id = rnf_get_idealdisc(rnf);
3523
Le = nfmakecoprime(nf, &id, Lpr);
3524
fa = idealfactor(nf, id); /* part of D_{L/K} coprime with Lpr */
3525
P = colconcat(Lpr,gel(fa,1));
3526
E = colconcat(Le, gel(fa,2));
3527
fa = mkmat2(P, gdiventgs(E, eulerphiu(n)));
3528
return mkvec2(fa, clean_factor(fa));
3529
}
3530
3531
/* h >= 0 */
3532
static void
3533
nextgen(GEN gene, long h, GEN* gens, GEN* hgens, long* ngens, long* curgcd) {
3534
long nextgcd = ugcd(h,*curgcd);
3535
if (nextgcd == *curgcd) return;
3536
(*ngens)++;
3537
gel(*gens,*ngens) = gene;
3538
gel(*hgens,*ngens) = utoi(h);
3539
*curgcd = nextgcd;
3540
return;
3541
}
3542
3543
static int
3544
dividesmod(long d, long h, long n) { return !(h%cgcd(d,n)); }
3545
3546
/* ramified prime with nontrivial Hasse invariant */
3547
static GEN
3548
localcomplete(GEN rnf, GEN pl, GEN cnd, GEN auts, long j, long n, long h, long* v)
3549
{
3550
GEN nf, gens, hgens, pr, modpr, T, p, sol, U, D, b, gene, randg, pu;
3551
long ngens, i, d, np, k, d1, d2, hg, dnf, vcnd, curgcd;
3552
nf = rnf_get_nf(rnf);
3553
pr = gcoeff(cnd,j,1);
3554
np = umodiu(pr_norm(pr), n);
3555
dnf = nf_get_degree(nf);
3556
vcnd = itos(gcoeff(cnd,j,2));
3557
ngens = 13+dnf;
3558
gens = zerovec(ngens);
3559
hgens = zerovec(ngens);
3560
*v = 0;
3561
curgcd = 0;
3562
ngens = 0;
3563
3564
if (!uisprime(n)) {
3565
gene = pr_get_gen(pr);
3566
hg = localhasse(rnf, cnd, pl, auts, gene, j);
3567
nextgen(gene, hg, &gens, &hgens, &ngens, &curgcd);
3568
}
3569
3570
if (ugcd(np,n) != 1) { /* GCD(Np,n) != 1 */
3571
pu = idealprincipalunits(nf,pr,vcnd);
3572
pu = abgrp_get_gen(pu);
3573
for (i=1; i<lg(pu) && !dividesmod(curgcd,h,n); i++) {
3574
gene = gel(pu,i);
3575
hg = localhasse(rnf, cnd, pl, auts, gene, j);
3576
nextgen(gene, hg, &gens, &hgens, &ngens, &curgcd);
3577
}
3578
}
3579
3580
d = ugcd(np-1,n);
3581
if (d != 1) { /* GCD(Np-1,n) != 1 */
3582
modpr = nf_to_Fq_init(nf, &pr, &T, &p);
3583
while (!dividesmod(curgcd,h,n)) { /* TODO gener_FpXQ_local */
3584
if (T==NULL) randg = randomi(p);
3585
else randg = random_FpX(degpol(T), varn(T),p);
3586
3587
if (!gequal0(randg) && !gequal1(randg)) {
3588
gene = Fq_to_nf(randg, modpr);
3589
hg = localhasse(rnf, cnd, pl, auts, gene, j);
3590
nextgen(gene, hg, &gens, &hgens, &ngens, &curgcd);
3591
}
3592
}
3593
}
3594
3595
setlg(gens,ngens+1);
3596
setlg(hgens,ngens+1);
3597
3598
sol = ZV_extgcd(hgens);
3599
D = gel(sol,1);
3600
U = gmael(sol,2,ngens);
3601
3602
b = gen_1;
3603
d = itou(D);
3604
d1 = ugcd(d,n);
3605
d2 = d/d1;
3606
d = ((h/d1)*Fl_inv(d2,n))%n;
3607
for (i=1; i<=ngens; i++) {
3608
k = (itos(gel(U,i))*d)%n;
3609
if (k<0) k = n-k;
3610
if (k) b = nfmul(nf, b, nfpow_u(nf, gel(gens,i),k));
3611
if (i==1) *v = k;
3612
}
3613
return b;
3614
}
3615
3616
static int
3617
testsplits(GEN data, GEN fa)
3618
{
3619
GEN rnf = gel(data,1), forbid = gel(data,2), P = gel(fa,1), E = gel(fa,2);
3620
long i, n, l = lg(P);
3621
3622
for (i = 1; i < l; i++)
3623
{
3624
GEN pr = gel(P,i);
3625
if (tablesearch(forbid, pr, &cmp_prime_ideal)) return 0;
3626
}
3627
n = rnf_get_degree(rnf);
3628
for (i = 1; i < l; i++)
3629
{
3630
long e = itos(gel(E,i)) % n;
3631
if (e)
3632
{
3633
GEN L = rnfidealprimedec(rnf, gel(P,i));
3634
long g = lg(L) - 1;
3635
if ((e * g) % n) return 0;
3636
}
3637
}
3638
return 1;
3639
}
3640
3641
/* remove entries with Hasse invariant 0 */
3642
static GEN
3643
hassereduce(GEN hf)
3644
{
3645
GEN pr,h, PR = gel(hf,1), H = gel(hf,2);
3646
long i, j, l = lg(PR);
3647
3648
pr= cgetg(l, t_VEC);
3649
h = cgetg(l, t_VECSMALL);
3650
for (i = j = 1; i < l; i++)
3651
if (H[i]) {
3652
gel(pr,j) = gel(PR,i);
3653
h[j] = H[i]; j++;
3654
}
3655
setlg(pr,j);
3656
setlg(h,j); return mkvec2(pr,h);
3657
}
3658
3659
/* v vector of prid. Return underlying list of rational primes */
3660
static GEN
3661
pr_primes(GEN v)
3662
{
3663
long i, l = lg(v);
3664
GEN w = cgetg(l,t_VEC);
3665
for (i=1; i<l; i++) gel(w,i) = pr_get_p(gel(v,i));
3666
return ZV_sort_uniq(w);
3667
}
3668
3669
/* rnf complete */
3670
static GEN
3671
alg_complete0(GEN rnf, GEN aut, GEN hf, GEN hi, long maxord)
3672
{
3673
pari_sp av = avma;
3674
GEN nf, pl, pl2, cnd, prcnd, cnds, y, Lpr, auts, b, fa, data, hfe;
3675
GEN forbid, al, ind;
3676
long D, n, d, i, j, l;
3677
nf = rnf_get_nf(rnf);
3678
n = rnf_get_degree(rnf);
3679
d = nf_get_degree(nf);
3680
D = d*n*n;
3681
checkhasse(nf,hf,hi,n);
3682
hf = hassereduce(hf);
3683
Lpr = gel(hf,1);
3684
hfe = gel(hf,2);
3685
3686
auts = allauts(rnf,aut);
3687
3688
pl = leafcopy(hi); /* conditions on the final b */
3689
pl2 = leafcopy(hi); /* conditions for computing local Hasse invariants */
3690
l = lg(pl); ind = cgetg(l, t_VECSMALL);
3691
for (i = j = 1; i < l; i++)
3692
if (hi[i]) { pl[i] = -1; pl2[i] = 1; } else ind[j++] = i;
3693
setlg(ind, j);
3694
y = nfpolsturm(nf, rnf_get_pol(rnf), ind);
3695
for (i = 1; i < j; i++)
3696
if (!signe(gel(y,i))) { pl[ind[i]] = 1; pl2[ind[i]] = 1; }
3697
3698
cnds = computecnd(rnf,Lpr);
3699
prcnd = gel(cnds,1);
3700
cnd = gel(cnds,2);
3701
y = cgetg(lgcols(prcnd),t_VEC);
3702
forbid = vectrunc_init(lg(Lpr));
3703
for (i=j=1; i<lg(Lpr); i++)
3704
{
3705
GEN pr = gcoeff(prcnd,i,1), yi;
3706
long v, e = itou( gcoeff(prcnd,i,2) );
3707
if (!e) {
3708
long frob = cyclicrelfrob(rnf,auts,pr), f1 = ugcd(frob,n);
3709
vectrunc_append(forbid, pr);
3710
yi = gen_0;
3711
v = ((hfe[i]/f1) * Fl_inv(frob/f1,n)) % n;
3712
}
3713
else
3714
yi = localcomplete(rnf, pl2, cnd, auts, j++, n, hfe[i], &v);
3715
gel(y,i) = yi;
3716
gcoeff(prcnd,i,2) = stoi(e + v);
3717
}
3718
for (; i<lgcols(prcnd); i++) gel(y,i) = gen_1;
3719
gen_sort_inplace(forbid, (void*)&cmp_prime_ideal, &cmp_nodata, NULL);
3720
data = mkvec2(rnf,forbid);
3721
b = factoredextchinesetest(nf,prcnd,y,pl,&fa,data,testsplits);
3722
3723
al = cgetg(12, t_VEC);
3724
gel(al,10)= gen_0; /* must be set first */
3725
gel(al,1) = rnf;
3726
gel(al,2) = auts;
3727
gel(al,3) = basistoalg(nf,b);
3728
gel(al,4) = hi;
3729
/* add primes | disc or b with trivial Hasse invariant to hf */
3730
Lpr = gel(prcnd,1); y = b;
3731
(void)nfmakecoprime(nf, &y, Lpr);
3732
Lpr = shallowconcat(Lpr, gel(idealfactor(nf,y), 1));
3733
settyp(Lpr,t_VEC);
3734
hf = mkvec2(Lpr, shallowconcat(hfe, const_vecsmall(lg(Lpr)-lg(hfe), 0)));
3735
gel(al,5) = hf;
3736
gel(al,6) = gen_0;
3737
gel(al,7) = matid(D);
3738
gel(al,8) = matid(D); /* TODO modify 7, 8 et 9 once LLL added */
3739
gel(al,9) = algnatmultable(al,D);
3740
gel(al,11)= algtracebasis(al);
3741
if (maxord) al = alg_maximal_primes(al, pr_primes(Lpr));
3742
return gerepilecopy(av, al);
3743
}
3744
3745
GEN
3746
alg_complete(GEN rnf, GEN aut, GEN hf, GEN hi, long maxord)
3747
{
3748
long n = rnf_get_degree(rnf);
3749
rnfcomplete(rnf);
3750
return alg_complete0(rnf,aut,hasseconvert(hf,n),hasseconvert(hi,n), maxord);
3751
}
3752
3753
void
3754
checkhasse(GEN nf, GEN hf, GEN hi, long n)
3755
{
3756
GEN Lpr, Lh;
3757
long i, sum;
3758
if (typ(hf) != t_VEC || lg(hf) != 3) pari_err_TYPE("checkhasse [hf]", hf);
3759
Lpr = gel(hf,1);
3760
Lh = gel(hf,2);
3761
if (typ(Lpr) != t_VEC) pari_err_TYPE("checkhasse [Lpr]", Lpr);
3762
if (typ(Lh) != t_VECSMALL) pari_err_TYPE("checkhasse [Lh]", Lh);
3763
if (typ(hi) != t_VECSMALL) pari_err_TYPE("checkhasse [hi]", hi);
3764
if ((nf && lg(hi) != nf_get_r1(nf)+1))
3765
pari_err_DOMAIN("checkhasse [hi should have r1 components]","#hi","!=",stoi(nf_get_r1(nf)),stoi(lg(hi)-1));
3766
if (lg(Lpr) != lg(Lh))
3767
pari_err_DIM("checkhasse [Lpr and Lh should have same length]");
3768
for (i=1; i<lg(Lpr); i++) checkprid(gel(Lpr,i));
3769
if (lg(gen_sort_uniq(Lpr, (void*)cmp_prime_ideal, cmp_nodata)) < lg(Lpr))
3770
pari_err(e_MISC, "error in checkhasse [duplicate prime ideal]");
3771
sum = 0;
3772
for (i=1; i<lg(Lh); i++) sum = (sum+Lh[i])%n;
3773
for (i=1; i<lg(hi); i++) {
3774
if (hi[i] && 2*hi[i] != n) pari_err_DOMAIN("checkhasse", "Hasse invariant at real place [must be 0 or 1/2]", "!=", n%2? gen_0 : stoi(n/2), stoi(hi[i]));
3775
sum = (sum+hi[i])%n;
3776
}
3777
if (sum<0) sum = n+sum;
3778
if (sum != 0)
3779
pari_err_DOMAIN("checkhasse","sum(Hasse invariants)","!=",gen_0,Lh);
3780
}
3781
3782
static GEN
3783
hassecoprime(GEN hf, GEN hi, long n)
3784
{
3785
pari_sp av = avma;
3786
long l, i, j, lk, inv;
3787
GEN fa, P,E, res, hil, hfl;
3788
hi = hasseconvert(hi, n);
3789
hf = hasseconvert(hf, n);
3790
checkhasse(NULL,hf,hi,n);
3791
fa = factoru(n);
3792
P = gel(fa,1); l = lg(P);
3793
E = gel(fa,2);
3794
res = cgetg(l,t_VEC);
3795
for (i=1; i<l; i++) {
3796
lk = upowuu(P[i],E[i]);
3797
inv = Fl_invsafe((n/lk)%lk, lk);
3798
hil = gcopy(hi);
3799
hfl = gcopy(hf);
3800
3801
if (P[i] == 2)
3802
for (j=1; j<lg(hil); j++) hil[j] = hi[j]==0 ? 0 : lk/2;
3803
else
3804
for (j=1; j<lg(hil); j++) hil[j] = 0;
3805
for (j=1; j<lgcols(hfl); j++) gel(hfl,2)[j] = (gel(hf,2)[j]*inv)%lk;
3806
hfl = hassereduce(hfl);
3807
gel(res,i) = mkvec3(hfl,hil,utoi(lk));
3808
}
3809
3810
return gerepilecopy(av, res);
3811
}
3812
3813
/* no garbage collection */
3814
static GEN
3815
genefrob(GEN nf, GEN gal, GEN r)
3816
{
3817
long i;
3818
GEN g = identity_perm(nf_get_degree(nf)), fa = Z_factor(r), p, pr, frob;
3819
for (i=1; i<lgcols(fa); i++) {
3820
p = gcoeff(fa,i,1);
3821
pr = idealprimedec(nf, p);
3822
pr = gel(pr,1);
3823
frob = idealfrobenius(nf, gal, pr);
3824
g = perm_mul(g, perm_pow(frob, gcoeff(fa,i,2)));
3825
}
3826
return g;
3827
}
3828
3829
static GEN
3830
rnfcycaut(GEN rnf)
3831
{
3832
GEN nf2 = obj_check(rnf, rnf_NFABS);
3833
GEN L, alpha, pol, salpha, s, sj, polabs, k, X, pol0, nf;
3834
long i, d, j;
3835
d = rnf_get_degree(rnf);
3836
L = galoisconj(nf2,NULL);
3837
alpha = lift_shallow(rnf_get_alpha(rnf));
3838
pol = rnf_get_pol(rnf);
3839
k = rnf_get_k(rnf);
3840
polabs = rnf_get_polabs(rnf);
3841
nf = rnf_get_nf(rnf);
3842
pol0 = nf_get_pol(nf);
3843
X = RgX_rem(pol_x(varn(pol0)), pol0);
3844
3845
/* TODO check mod prime of degree 1 */
3846
for (i=1; i<lg(L); i++) {
3847
s = gel(L,i);
3848
salpha = RgX_RgXQ_eval(alpha,s,polabs);
3849
if (!gequal(alpha,salpha)) continue;
3850
3851
s = lift_shallow(rnfeltabstorel(rnf,s));
3852
sj = s = gsub(s, gmul(k,X));
3853
for (j=1; !gequal0(gsub(sj,pol_x(varn(s)))); j++)
3854
sj = RgX_RgXQ_eval(sj,s,pol);
3855
if (j<d) continue;
3856
return s;
3857
}
3858
return NULL; /*LCOV_EXCL_LINE*/
3859
}
3860
3861
/* returns Lpr augmented with an extra, distinct prime */
3862
/* TODO be less lazy and return a small prime */
3863
static GEN
3864
extraprime(GEN nf, GEN Lpr)
3865
{
3866
GEN Lpr2, p = gen_2, pr;
3867
long i;
3868
Lpr2 = cgetg(lg(Lpr)+1,t_VEC);
3869
for (i=1; i<lg(Lpr); i++)
3870
{
3871
gel(Lpr2,i) = gel(Lpr,i);
3872
p = gmax_shallow(p, pr_get_p(gel(Lpr,i)));
3873
}
3874
p = nextprime(addis(p,1));
3875
pr = gel(idealprimedec_limit_f(nf, p, 0), 1);
3876
gel(Lpr2,lg(Lpr)) = pr;
3877
return Lpr2;
3878
}
3879
3880
GEN
3881
alg_hasse(GEN nf, long n, GEN hf, GEN hi, long var, long maxord)
3882
{
3883
pari_sp av = avma;
3884
GEN primary, al = gen_0, al2, rnf, hil, hfl, Ld, pl, pol, Lpr, aut, Lpr2, Ld2;
3885
long i, lk, j, maxdeg;
3886
dbg_printf(1)("alg_hasse\n");
3887
if (n<=1) pari_err_DOMAIN("alg_hasse", "degree", "<=", gen_1, stoi(n));
3888
primary = hassecoprime(hf, hi, n);
3889
for (i=1; i<lg(primary); i++) {
3890
lk = itos(gmael(primary,i,3));
3891
hfl = gmael(primary,i,1);
3892
hil = gmael(primary,i,2);
3893
checkhasse(nf, hfl, hil, lk);
3894
dbg_printf(1)("alg_hasse: i=%d hf=%Ps hi=%Ps lk=%d\n", i, hfl, hil, lk);
3895
3896
if (lg(gel(hfl,1))>1 || lk%2==0) {
3897
maxdeg = 1;
3898
Lpr = gel(hfl,1);
3899
Ld = gcopy(gel(hfl,2));
3900
for (j=1; j<lg(Ld); j++)
3901
{
3902
Ld[j] = lk/ugcd(lk,Ld[j]);
3903
maxdeg = maxss(Ld[j],maxdeg);
3904
}
3905
pl = gcopy(hil);
3906
for (j=1; j<lg(pl); j++) if(pl[j])
3907
{
3908
pl[j] = -1;
3909
maxdeg = maxss(maxdeg,2);
3910
}
3911
3912
Lpr2 = Lpr;
3913
Ld2 = Ld;
3914
if (maxdeg<lk)
3915
{
3916
if (maxdeg==1 && lk==2 && lg(pl)>1) pl[1] = -1;
3917
else
3918
{
3919
Lpr2 = extraprime(nf,Lpr);
3920
Ld2 = cgetg(lg(Ld)+1, t_VECSMALL);
3921
for (j=1; j<lg(Ld); j++) Ld2[j] = Ld[j];
3922
Ld2[lg(Ld)] = lk;
3923
}
3924
}
3925
3926
dbg_printf(2)("alg_hasse: calling nfgrunwaldwang Lpr=%Ps Pd=%Ps pl=%Ps\n",
3927
Lpr, Ld, pl);
3928
pol = nfgrunwaldwang(nf, Lpr2, Ld2, pl, var);
3929
dbg_printf(2)("alg_hasse: calling rnfinit(%Ps)\n", pol);
3930
rnf = rnfinit0(nf,pol,1);
3931
dbg_printf(2)("alg_hasse: computing automorphism\n");
3932
aut = rnfcycaut(rnf);
3933
dbg_printf(2)("alg_hasse: calling alg_complete\n");
3934
al2 = alg_complete0(rnf,aut,hfl,hil,maxord);
3935
}
3936
else al2 = alg_matrix(nf, lk, var, cgetg(1,t_VEC), maxord);
3937
3938
if (i==1) al = al2;
3939
else al = algtensor(al,al2,maxord);
3940
}
3941
return gerepilecopy(av,al);
3942
}
3943
3944
/** CYCLIC ALGEBRA WITH GIVEN HASSE INVARIANTS **/
3945
3946
/* no garbage collection */
3947
static int
3948
linindep(GEN pol, GEN L)
3949
{
3950
long i;
3951
GEN fa;
3952
for (i=1; i<lg(L); i++) {
3953
fa = nffactor(gel(L,i),pol);
3954
if (lgcols(fa)>2) return 0;
3955
}
3956
return 1;
3957
}
3958
3959
/* no garbage collection */
3960
static GEN
3961
subcycloindep(GEN nf, long n, long v, GEN L, GEN *pr)
3962
{
3963
pari_sp av;
3964
forprime_t S;
3965
ulong p;
3966
u_forprime_arith_init(&S, 1, ULONG_MAX, 1, n);
3967
av = avma;
3968
while ((p = u_forprime_next(&S)))
3969
{
3970
ulong r = pgener_Fl(p);
3971
GEN pol = galoissubcyclo(utoipos(p), utoipos(Fl_powu(r,n,p)), 0, v);
3972
GEN fa = nffactor(nf, pol);
3973
if (lgcols(fa) == 2 && linindep(pol,L)) { *pr = utoipos(r); return pol; }
3974
set_avma(av);
3975
}
3976
pari_err_BUG("subcycloindep (no suitable prime = 1(mod n))"); /*LCOV_EXCL_LINE*/
3977
*pr = NULL; return NULL; /*LCOV_EXCL_LINE*/
3978
}
3979
3980
GEN
3981
alg_matrix(GEN nf, long n, long v, GEN L, long maxord)
3982
{
3983
pari_sp av = avma;
3984
GEN pol, gal, rnf, cyclo, g, r, aut;
3985
dbg_printf(1)("alg_matrix\n");
3986
if (n<=0) pari_err_DOMAIN("alg_matrix", "n", "<=", gen_0, stoi(n));
3987
pol = subcycloindep(nf, n, v, L, &r);
3988
rnf = rnfinit(nf, pol);
3989
cyclo = nfinit(pol, nf_get_prec(nf));
3990
gal = galoisinit(cyclo, NULL);
3991
g = genefrob(cyclo,gal,r);
3992
aut = galoispermtopol(gal,g);
3993
return gerepileupto(av, alg_cyclic(rnf, aut, gen_1, maxord));
3994
}
3995
3996
GEN
3997
alg_hilbert(GEN nf, GEN a, GEN b, long v, long maxord)
3998
{
3999
pari_sp av = avma;
4000
GEN C, P, rnf, aut;
4001
dbg_printf(1)("alg_hilbert\n");
4002
checknf(nf);
4003
if (!isint1(Q_denom(a)))
4004
pari_err_DOMAIN("alg_hilbert", "denominator(a)", "!=", gen_1,a);
4005
if (!isint1(Q_denom(b)))
4006
pari_err_DOMAIN("alg_hilbert", "denominator(b)", "!=", gen_1,b);
4007
4008
if (v < 0) v = 0;
4009
C = Rg_col_ei(gneg(a), 3, 3);
4010
gel(C,1) = gen_1;
4011
P = gtopoly(C,v);
4012
rnf = rnfinit(nf, P);
4013
aut = gneg(pol_x(v));
4014
return gerepileupto(av, alg_cyclic(rnf, aut, b, maxord));
4015
}
4016
4017
GEN
4018
alginit(GEN A, GEN B, long v, long maxord)
4019
{
4020
long w;
4021
switch(nftyp(A))
4022
{
4023
case typ_NF:
4024
if (v<0) v=0;
4025
w = gvar(nf_get_pol(A));
4026
if (varncmp(v,w)>=0) pari_err_PRIORITY("alginit", pol_x(v), ">=", w);
4027
switch(typ(B))
4028
{
4029
long nB;
4030
case t_INT: return alg_matrix(A, itos(B), v, cgetg(1,t_VEC), maxord);
4031
case t_VEC:
4032
nB = lg(B)-1;
4033
if (nB && typ(gel(B,1)) == t_MAT) return alg_csa_table(A,B,v,maxord);
4034
switch(nB)
4035
{
4036
case 2: return alg_hilbert(A, gel(B,1), gel(B,2), v, maxord);
4037
case 3:
4038
if (typ(gel(B,1))!=t_INT)
4039
pari_err_TYPE("alginit [degree should be an integer]", gel(B,1));
4040
return alg_hasse(A, itos(gel(B,1)), gel(B,2), gel(B,3), v,
4041
maxord);
4042
}
4043
}
4044
pari_err_TYPE("alginit", B); break;
4045
4046
case typ_RNF:
4047
if (typ(B) != t_VEC || lg(B) != 3) pari_err_TYPE("alginit", B);
4048
return alg_cyclic(A, gel(B,1), gel(B,2), maxord);
4049
}
4050
pari_err_TYPE("alginit", A);
4051
return NULL;/*LCOV_EXCL_LINE*/
4052
}
4053
4054
/* assumes al CSA or CYCLIC */
4055
static GEN
4056
algnatmultable(GEN al, long D)
4057
{
4058
GEN res, x;
4059
long i;
4060
res = cgetg(D+1,t_VEC);
4061
for (i=1; i<=D; i++) {
4062
x = algnattoalg(al,col_ei(D,i));
4063
gel(res,i) = algZmultable(al,x);
4064
}
4065
return res;
4066
}
4067
4068
/* no garbage collection */
4069
static void
4070
algcomputehasse(GEN al)
4071
{
4072
long r1, k, n, m, m1, m2, m3, i, m23, m123;
4073
GEN rnf, nf, b, fab, disc2, cnd, fad, auts, pr, pl, perm, y, hi, PH, H, L;
4074
4075
rnf = alg_get_splittingfield(al);
4076
n = rnf_get_degree(rnf);
4077
nf = rnf_get_nf(rnf);
4078
b = alg_get_b(al);
4079
r1 = nf_get_r1(nf);
4080
auts = alg_get_auts(al);
4081
(void)alg_get_abssplitting(al);
4082
4083
y = nfpolsturm(nf, rnf_get_pol(rnf), NULL);
4084
pl = cgetg(r1+1, t_VECSMALL);
4085
/* real places where rnf/nf ramifies */
4086
for (k = 1; k <= r1; k++) pl[k] = !signe(gel(y,k));
4087
4088
/* infinite Hasse invariants */
4089
if (odd(n)) hi = const_vecsmall(r1, 0);
4090
else
4091
{
4092
GEN s = nfsign(nf, b);
4093
hi = cgetg(r1+1, t_VECSMALL);
4094
for (k = 1; k<=r1; k++) hi[k] = (s[k] && pl[k]) ? (n/2) : 0;
4095
}
4096
4097
fab = idealfactor(nf, b);
4098
disc2 = rnf_get_idealdisc(rnf);
4099
L = nfmakecoprime(nf, &disc2, gel(fab,1));
4100
m = lg(L)-1;
4101
/* m1 = #{pr|b: pr \nmid disc}, m3 = #{pr|b: pr | disc} */
4102
perm = cgetg(m+1, t_VECSMALL);
4103
for (i=1, m1=m, k=1; k<=m; k++)
4104
if (signe(gel(L,k))) perm[m1--] = k; else perm[i++] = k;
4105
m3 = m - m1;
4106
4107
/* disc2 : factor of disc coprime to b */
4108
fad = idealfactor(nf, disc2);
4109
/* m2 : number of prime factors of disc not dividing b */
4110
m2 = nbrows(fad);
4111
m23 = m2+m3;
4112
m123 = m1+m2+m3;
4113
4114
/* initialize the possibly ramified primes (hasse) and the factored conductor of rnf/nf (cnd) */
4115
cnd = zeromatcopy(m23,2);
4116
PH = cgetg(m123+1, t_VEC); /* ramified primes */
4117
H = cgetg(m123+1, t_VECSMALL); /* Hasse invariant */
4118
/* compute Hasse invariant at primes that are unramified in rnf/nf */
4119
for (k=1; k<=m1; k++) {/* pr | b, pr \nmid disc */
4120
long frob, e, j = perm[k];
4121
pr = gcoeff(fab,j,1);
4122
e = itos(gcoeff(fab,j,2));
4123
frob = cyclicrelfrob(rnf, auts, pr);
4124
gel(PH,k) = pr;
4125
H[k] = Fl_mul(frob, e, n);
4126
}
4127
/* compute Hasse invariant at primes that are ramified in rnf/nf */
4128
for (k=1; k<=m2; k++) {/* pr \nmid b, pr | disc */
4129
pr = gcoeff(fad,k,1);
4130
gel(PH,k+m1) = pr;
4131
gcoeff(cnd,k,1) = pr;
4132
gcoeff(cnd,k,2) = gcoeff(fad,k,2);
4133
}
4134
for (k=1; k<=m3; k++) { /* pr | (b, disc) */
4135
long j = perm[k+m1];
4136
pr = gcoeff(fab,j,1);
4137
gel(PH,k+m1+m2) = pr;
4138
gcoeff(cnd,k+m2,1) = pr;
4139
gcoeff(cnd,k+m2,2) = gel(L,j);
4140
}
4141
gel(cnd,2) = gdiventgs(gel(cnd,2), eulerphiu(n));
4142
for (k=1; k<=m23; k++) H[k+m1] = localhasse(rnf, cnd, pl, auts, b, k);
4143
gel(al,4) = hi;
4144
perm = gen_indexsort(PH, (void*)&cmp_prime_ideal, &cmp_nodata);
4145
gel(al,5) = mkvec2(vecpermute(PH,perm),vecsmallpermute(H,perm));
4146
checkhasse(nf,alg_get_hasse_f(al),alg_get_hasse_i(al),n);
4147
}
4148
4149
static GEN
4150
alg_maximal_primes(GEN al, GEN P)
4151
{
4152
pari_sp av = avma;
4153
long l = lg(P), i;
4154
for (i=1; i<l; i++)
4155
{
4156
if (i != 1) al = gerepilecopy(av, al);
4157
al = alg_pmaximal(al,gel(P,i));
4158
}
4159
return al;
4160
}
4161
4162
GEN
4163
alg_cyclic(GEN rnf, GEN aut, GEN b, long maxord)
4164
{
4165
pari_sp av = avma;
4166
GEN al, nf;
4167
long D, n, d;
4168
dbg_printf(1)("alg_cyclic\n");
4169
checkrnf(rnf);
4170
if (!isint1(Q_denom(b)))
4171
pari_err_DOMAIN("alg_cyclic", "denominator(b)", "!=", gen_1,b);
4172
4173
nf = rnf_get_nf(rnf);
4174
n = rnf_get_degree(rnf);
4175
d = nf_get_degree(nf);
4176
D = d*n*n;
4177
4178
al = cgetg(12,t_VEC);
4179
gel(al,10)= gen_0; /* must be set first */
4180
gel(al,1) = rnf;
4181
gel(al,2) = allauts(rnf, aut);
4182
gel(al,3) = basistoalg(nf,b);
4183
rnf_build_nfabs(rnf, nf_get_prec(nf));
4184
gel(al,6) = gen_0;
4185
gel(al,7) = matid(D);
4186
gel(al,8) = matid(D); /* TODO modify 7, 8 et 9 once LLL added */
4187
gel(al,9) = algnatmultable(al,D);
4188
gel(al,11)= algtracebasis(al);
4189
4190
algcomputehasse(al);
4191
4192
if (maxord) {
4193
GEN hf = alg_get_hasse_f(al), pr = gel(hf,1);
4194
al = alg_maximal_primes(al, pr_primes(pr));
4195
}
4196
return gerepilecopy(av, al);
4197
}
4198
4199
static int
4200
ismaximalsubfield(GEN al, GEN x, GEN d, long v, GEN *pt_minpol)
4201
{
4202
GEN cp = algbasischarpoly(al, x, v), lead;
4203
if (!ispower(cp, d, pt_minpol)) return 0;
4204
lead = leading_coeff(*pt_minpol);
4205
if (isintm1(lead)) *pt_minpol = gneg(*pt_minpol);
4206
return ZX_is_irred(*pt_minpol);
4207
}
4208
4209
static GEN
4210
findmaximalsubfield(GEN al, GEN d, long v)
4211
{
4212
long count, nb=2, i, N = alg_get_absdim(al), n = nf_get_degree(alg_get_center(al));
4213
GEN x, minpol, maxc = gen_1;
4214
4215
for (i=n+1; i<=N; i+=n) {
4216
for (count=0; count<2 && i+count<=N; count++) {
4217
x = col_ei(N,i+count);
4218
if (ismaximalsubfield(al, x, d, v, &minpol)) return mkvec2(x,minpol);
4219
}
4220
}
4221
4222
while(1) {
4223
x = zerocol(N);
4224
for (count=0; count<nb; count++)
4225
{
4226
i = random_Fl(N)+1;
4227
gel(x,i) = addiu(randomi(maxc),1);
4228
if (random_bits(1)) gel(x,i) = negi(gel(x,i));
4229
}
4230
if (ismaximalsubfield(al, x, d, v, &minpol)) return mkvec2(x,minpol);
4231
if (!random_bits(3)) maxc = addiu(maxc,1);
4232
if (nb<N) nb++;
4233
}
4234
4235
return NULL; /* LCOV_EXCL_LINE */
4236
}
4237
4238
static GEN
4239
frobeniusform(GEN al, GEN x)
4240
{
4241
GEN M, FP, P, Pi;
4242
4243
/* /!\ has to be the *right* multiplication table */
4244
M = algbasisrightmultable(al, x);
4245
4246
FP = matfrobenius(M,2,0); /* M = P^(-1)*F*P */
4247
P = gel(FP,2);
4248
Pi = RgM_inv(P);
4249
return mkvec2(P, Pi);
4250
}
4251
4252
static void
4253
computesplitting(GEN al, long d, long v)
4254
{
4255
GEN subf, x, pol, polabs, basis, P, Pi, nf = alg_get_center(al), rnf, Lbasis, Lbasisinv, Q, pows;
4256
long i, n = nf_get_degree(nf), nd = n*d, N = alg_get_absdim(al), j, j2;
4257
4258
subf = findmaximalsubfield(al, utoipos(d), v);
4259
x = gel(subf, 1);
4260
polabs = gel(subf, 2);
4261
4262
/* Frobenius form to obtain L-vector space structure */
4263
basis = frobeniusform(al, x);
4264
P = gel(basis, 1);
4265
Pi = gel(basis, 2);
4266
4267
/* construct rnf of splitting field */
4268
pol = nffactor(nf,polabs);
4269
pol = gcoeff(pol,1,1);
4270
gel(al,1) = rnf = rnfinit(nf, pol);
4271
/* since pol is irreducible over Q, we have k=0 in rnf. */
4272
if (!gequal0(rnf_get_k(rnf)))
4273
pari_err_BUG("computesplitting (k!=0)"); /*LCOV_EXCL_LINE*/
4274
gel(al,6) = gen_0;
4275
rnf_build_nfabs(rnf, nf_get_prec(nf));
4276
4277
/* construct splitting data */
4278
Lbasis = cgetg(d+1, t_MAT);
4279
for (j=j2=1; j<=d; j++, j2+=nd)
4280
gel(Lbasis,j) = gel(Pi,j2);
4281
4282
Q = zeromatcopy(d,N);
4283
pows = pol_x_powers(nd,v);
4284
for (i=j=1; j<=N; j+=nd, i++)
4285
for (j2=0; j2<nd; j2++)
4286
gcoeff(Q,i,j+j2) = mkpolmod(gel(pows,j2+1),polabs);
4287
Lbasisinv = RgM_mul(Q,P);
4288
4289
gel(al,3) = mkvec3(x,Lbasis,Lbasisinv);
4290
}
4291
4292
/* assumes that mt defines a central simple algebra over nf */
4293
GEN
4294
alg_csa_table(GEN nf, GEN mt0, long v, long maxord)
4295
{
4296
pari_sp av = avma;
4297
GEN al, mt;
4298
long n, D, d2 = lg(mt0)-1, d = usqrt(d2);
4299
dbg_printf(1)("alg_csa_table\n");
4300
4301
nf = checknf(nf);
4302
mt = check_relmt(nf,mt0);
4303
if (!mt) pari_err_TYPE("alg_csa_table", mt0);
4304
n = nf_get_degree(nf);
4305
D = n*d2;
4306
if (d*d != d2)
4307
pari_err_DOMAIN("alg_csa_table","(nonsquare) dimension","!=",stoi(d*d),mt);
4308
4309
al = cgetg(12, t_VEC);
4310
gel(al,10) = gen_0; /* must be set first */
4311
gel(al,1) = zerovec(12); gmael(al,1,10) = nf;
4312
gmael(al,1,1) = gpowgs(pol_x(0), d); /* placeholder before splitting field */
4313
gel(al,2) = mt;
4314
gel(al,3) = gen_0; /* placeholder */
4315
gel(al,4) = gel(al,5) = gen_0; /* TODO Hasse invariants */
4316
gel(al,5) = gel(al,6) = gen_0; /* placeholder */
4317
gel(al,7) = matid(D);
4318
gel(al,8) = matid(D);
4319
gel(al,9) = algnatmultable(al,D);
4320
gel(al,11)= algtracebasis(al);
4321
if (maxord) al = alg_maximal(al);
4322
computesplitting(al, d, v);
4323
return gerepilecopy(av, al);
4324
}
4325
4326
static GEN
4327
algtableinit_i(GEN mt0, GEN p)
4328
{
4329
GEN al, mt;
4330
long i, n;
4331
4332
if (p && !signe(p)) p = NULL;
4333
mt = check_mt(mt0,p);
4334
if (!mt) pari_err_TYPE("algtableinit", mt0);
4335
if (!p && !isint1(Q_denom(mt0)))
4336
pari_err_DOMAIN("algtableinit", "denominator(mt)", "!=", gen_1, mt0);
4337
n = lg(mt)-1;
4338
al = cgetg(12, t_VEC);
4339
for (i=1; i<=6; i++) gel(al,i) = gen_0;
4340
gel(al,7) = matid(n);
4341
gel(al,8) = matid(n);
4342
gel(al,9) = mt;
4343
gel(al,10) = p? p: gen_0;
4344
gel(al,11)= algtracebasis(al);
4345
return al;
4346
}
4347
GEN
4348
algtableinit(GEN mt0, GEN p)
4349
{
4350
pari_sp av = avma;
4351
if (p)
4352
{
4353
if (typ(p) != t_INT) pari_err_TYPE("algtableinit",p);
4354
if (signe(p) && !BPSW_psp(p)) pari_err_PRIME("algtableinit",p);
4355
}
4356
return gerepilecopy(av, algtableinit_i(mt0, p));
4357
}
4358
4359
/** REPRESENTATIONS OF GROUPS **/
4360
4361
static GEN
4362
list_to_regular_rep(GEN elts, long n)
4363
{
4364
GEN reg, elts2, g;
4365
long i,j;
4366
elts = shallowcopy(elts);
4367
gen_sort_inplace(elts, (void*)&vecsmall_lexcmp, &cmp_nodata, NULL);
4368
reg = cgetg(n+1, t_VEC);
4369
gel(reg,1) = identity_perm(n);
4370
for (i=2; i<=n; i++) {
4371
g = perm_inv(gel(elts,i));
4372
elts2 = cgetg(n+1, t_VEC);
4373
for (j=1; j<=n; j++) gel(elts2,j) = perm_mul(g,gel(elts,j));
4374
gen_sort_inplace(elts2, (void*)&vecsmall_lexcmp, &cmp_nodata, &gel(reg,i));
4375
}
4376
return reg;
4377
}
4378
4379
static GEN
4380
matrix_perm(GEN perm, long n)
4381
{
4382
GEN m;
4383
long j;
4384
m = cgetg(n+1, t_MAT);
4385
for (j=1; j<=n; j++) {
4386
gel(m,j) = col_ei(n,perm[j]);
4387
}
4388
return m;
4389
}
4390
4391
GEN
4392
conjclasses_algcenter(GEN cc, GEN p)
4393
{
4394
GEN mt, elts = gel(cc,1), conjclass = gel(cc,2), rep = gel(cc,3), card;
4395
long i, nbcl = lg(rep)-1, n = lg(elts)-1;
4396
pari_sp av;
4397
4398
card = zero_Flv(nbcl);
4399
for (i=1; i<=n; i++) card[conjclass[i]]++;
4400
4401
/* multiplication table of the center of Z[G] (class functions) */
4402
mt = cgetg(nbcl+1,t_VEC);
4403
for (i=1;i<=nbcl;i++) gel(mt,i) = zero_Flm_copy(nbcl,nbcl);
4404
av = avma;
4405
for (i=1;i<=nbcl;i++)
4406
{
4407
GEN xi = gel(elts,rep[i]), mi = gel(mt,i);
4408
long j,k;
4409
for (j=1;j<=n;j++)
4410
{
4411
GEN xj = gel(elts,j);
4412
k = vecsearch(elts, perm_mul(xi,xj), NULL);
4413
ucoeff(mi, conjclass[k], conjclass[j])++;
4414
}
4415
for (k=1; k<=nbcl; k++)
4416
for (j=1; j<=nbcl; j++)
4417
{
4418
ucoeff(mi,k,j) *= card[i];
4419
ucoeff(mi,k,j) /= card[k];
4420
}
4421
set_avma(av);
4422
}
4423
for (i=1;i<=nbcl;i++) gel(mt,i) = Flm_to_ZM(gel(mt,i));
4424
return algtableinit_i(mt,p);
4425
}
4426
4427
GEN
4428
alggroupcenter(GEN G, GEN p, GEN *pcc)
4429
{
4430
pari_sp av = avma;
4431
GEN cc = group_to_cc(G), al = conjclasses_algcenter(cc, p);
4432
if (!pcc) al = gerepilecopy(av,al);
4433
else
4434
{ *pcc = cc; gerepileall(av,2,&al,pcc); }
4435
return al;
4436
}
4437
4438
static GEN
4439
groupelts_algebra(GEN elts, GEN p)
4440
{
4441
pari_sp av = avma;
4442
GEN mt;
4443
long i, n = lg(elts)-1;
4444
elts = list_to_regular_rep(elts,n);
4445
mt = cgetg(n+1, t_VEC);
4446
for (i=1; i<=n; i++) gel(mt,i) = matrix_perm(gel(elts,i),n);
4447
return gerepilecopy(av, algtableinit_i(mt,p));
4448
}
4449
4450
GEN
4451
alggroup(GEN gal, GEN p)
4452
{
4453
GEN elts = checkgroupelts(gal);
4454
return groupelts_algebra(elts, p);
4455
}
4456
4457
/** MAXIMAL ORDER **/
4458
4459
GEN
4460
alg_changeorder(GEN al, GEN ord)
4461
{
4462
GEN al2, mt, iord, mtx;
4463
long i, n;
4464
pari_sp av = avma;
4465
4466
if (!gequal0(gel(al,10)))
4467
pari_err_DOMAIN("alg_changeorder","characteristic","!=",gen_0,gel(al,10));
4468
n = alg_get_absdim(al);
4469
4470
iord = QM_inv(ord);
4471
al2 = shallowcopy(al);
4472
4473
gel(al2,7) = RgM_mul(gel(al2,7), ord);
4474
4475
gel(al2,8) = RgM_mul(iord, gel(al,8));
4476
4477
mt = cgetg(n+1,t_VEC);
4478
gel(mt,1) = matid(n);
4479
for (i=2; i<=n; i++) {
4480
mtx = algbasismultable(al,gel(ord,i));
4481
gel(mt,i) = RgM_mul(iord, RgM_mul(mtx, ord));
4482
}
4483
gel(al2,9) = mt;
4484
4485
gel(al2,11) = algtracebasis(al2);
4486
4487
return gerepilecopy(av,al2);
4488
}
4489
4490
static GEN
4491
mattocol(GEN M, long n)
4492
{
4493
GEN C = cgetg(n*n+1, t_COL);
4494
long i,j,ic;
4495
ic = 1;
4496
for (i=1; i<=n; i++)
4497
for (j=1; j<=n; j++, ic++) gel(C,ic) = gcoeff(M,i,j);
4498
return C;
4499
}
4500
4501
/* Ip is a lift of a left O/pO-ideal where O is the integral basis of al */
4502
static GEN
4503
algleftordermodp(GEN al, GEN Ip, GEN p)
4504
{
4505
pari_sp av = avma;
4506
GEN I, Ii, M, mt, K, imi, p2;
4507
long n, i;
4508
n = alg_get_absdim(al);
4509
mt = alg_get_multable(al);
4510
p2 = sqri(p);
4511
4512
I = ZM_hnfmodid(Ip, p);
4513
Ii = ZM_inv(I,NULL);
4514
4515
M = cgetg(n+1, t_MAT);
4516
for (i=1; i<=n; i++) {
4517
imi = FpM_mul(Ii, FpM_mul(gel(mt,i), I, p2), p2);
4518
imi = ZM_Z_divexact(imi, p);
4519
gel(M,i) = mattocol(imi, n);
4520
}
4521
K = FpM_ker(M, p);
4522
if (lg(K)==1) { set_avma(av); return matid(n); }
4523
K = ZM_hnfmodid(K,p);
4524
4525
return gerepileupto(av, ZM_Z_div(K,p));
4526
}
4527
4528
static GEN
4529
alg_ordermodp(GEN al, GEN p)
4530
{
4531
GEN alp;
4532
long i, N = alg_get_absdim(al);
4533
alp = cgetg(12, t_VEC);
4534
for (i=1; i<=8; i++) gel(alp,i) = gen_0;
4535
gel(alp,9) = cgetg(N+1, t_VEC);
4536
for (i=1; i<=N; i++) gmael(alp,9,i) = FpM_red(gmael(al,9,i), p);
4537
gel(alp,10) = p;
4538
gel(alp,11) = cgetg(N+1, t_VEC);
4539
for (i=1; i<=N; i++) gmael(alp,11,i) = Fp_red(gmael(al,11,i), p);
4540
4541
return alp;
4542
}
4543
4544
static GEN
4545
algpradical_i(GEN al, GEN p, GEN zprad, GEN projs)
4546
{
4547
pari_sp av = avma;
4548
GEN alp = alg_ordermodp(al, p), liftrad, projrad, alq, alrad, res, Lalp, radq;
4549
long i;
4550
if (lg(zprad)==1) {
4551
liftrad = NULL;
4552
projrad = NULL;
4553
}
4554
else {
4555
alq = alg_quotient(alp, zprad, 1);
4556
alp = gel(alq,1);
4557
projrad = gel(alq,2);
4558
liftrad = gel(alq,3);
4559
}
4560
4561
if (projs) {
4562
if (projrad) {
4563
projs = gcopy(projs);
4564
for (i=1; i<lg(projs); i++)
4565
gel(projs,i) = FpM_FpC_mul(projrad, gel(projs,i), p);
4566
}
4567
Lalp = alg_centralproj(alp, projs, 1);
4568
4569
alrad = cgetg(lg(Lalp),t_VEC);
4570
for (i=1; i<lg(Lalp); i++) {
4571
alq = gel(Lalp,i);
4572
radq = algradical(gel(alq,1));
4573
if (gequal0(radq))
4574
gel(alrad,i) = cgetg(1,t_MAT);
4575
else {
4576
radq = FpM_mul(gel(alq,3),radq,p);
4577
gel(alrad,i) = radq;
4578
}
4579
}
4580
alrad = shallowmatconcat(alrad);
4581
alrad = FpM_image(alrad,p);
4582
}
4583
else alrad = algradical(alp);
4584
4585
if (!gequal0(alrad)) {
4586
if (liftrad) alrad = FpM_mul(liftrad, alrad, p);
4587
res = shallowmatconcat(mkvec2(alrad, zprad));
4588
res = FpM_image(res,p);
4589
}
4590
else res = lg(zprad)==1 ? gen_0 : zprad;
4591
return gerepilecopy(av, res);
4592
}
4593
4594
static GEN
4595
algpdecompose0(GEN al, GEN prad, GEN p, GEN projs)
4596
{
4597
pari_sp av = avma;
4598
GEN alp, quo, ss, liftm = NULL, projm = NULL, dec, res, I, Lss, deci;
4599
long i, j;
4600
4601
alp = alg_ordermodp(al, p);
4602
if (!gequal0(prad)) {
4603
quo = alg_quotient(alp, prad, 1);
4604
ss = gel(quo,1);
4605
projm = gel(quo,2);
4606
liftm = gel(quo,3);
4607
}
4608
else ss = alp;
4609
4610
if (projs) {
4611
if (projm) {
4612
for (i=1; i<lg(projs); i++)
4613
gel(projs,i) = FpM_FpC_mul(projm, gel(projs,i), p);
4614
}
4615
Lss = alg_centralproj(ss, projs, 1);
4616
4617
dec = cgetg(lg(Lss),t_VEC);
4618
for (i=1; i<lg(Lss); i++) {
4619
gel(dec,i) = algsimpledec_ss(gmael(Lss,i,1), 1);
4620
deci = gel(dec,i);
4621
for (j=1; j<lg(deci); j++)
4622
gmael(deci,j,3) = FpM_mul(gmael(Lss,i,3), gmael(deci,j,3), p);
4623
}
4624
dec = shallowconcat1(dec);
4625
}
4626
else dec = algsimpledec_ss(ss,1);
4627
4628
res = cgetg(lg(dec),t_VEC);
4629
for (i=1; i<lg(dec); i++) {
4630
I = gmael(dec,i,3);
4631
if (liftm) I = FpM_mul(liftm,I,p);
4632
I = shallowmatconcat(mkvec2(I,prad));
4633
gel(res,i) = I;
4634
}
4635
4636
return gerepilecopy(av, res);
4637
}
4638
4639
/* finds a nontrivial ideal of O/prad or gen_0 if there is none. */
4640
static GEN
4641
algpdecompose_i(GEN al, GEN p, GEN zprad, GEN projs)
4642
{
4643
pari_sp av = avma;
4644
GEN prad = algpradical_i(al,p,zprad,projs);
4645
return gerepileupto(av, algpdecompose0(al, prad, p, projs));
4646
}
4647
4648
/* ord is assumed to be in hnf wrt the integral basis of al. */
4649
/* assumes that alg_get_invbasis(al) is integral. */
4650
static GEN
4651
alg_change_overorder_shallow(GEN al, GEN ord)
4652
{
4653
GEN al2, mt, iord, mtx, den, den2, div;
4654
long i, n;
4655
n = alg_get_absdim(al);
4656
4657
iord = QM_inv(ord);
4658
al2 = shallowcopy(al);
4659
ord = Q_remove_denom(ord,&den);
4660
4661
gel(al2,7) = Q_remove_denom(gel(al,7), &den2);
4662
if (den2) div = mulii(den,den2);
4663
else div = den;
4664
gel(al2,7) = ZM_Z_div(ZM_mul(gel(al2,7), ord), div);
4665
4666
gel(al2,8) = ZM_mul(iord, gel(al,8));
4667
4668
mt = cgetg(n+1,t_VEC);
4669
gel(mt,1) = matid(n);
4670
div = sqri(den);
4671
for (i=2; i<=n; i++) {
4672
mtx = algbasismultable(al,gel(ord,i));
4673
gel(mt,i) = ZM_mul(iord, ZM_mul(mtx, ord));
4674
gel(mt,i) = ZM_Z_divexact(gel(mt,i), div);
4675
}
4676
gel(al2,9) = mt;
4677
4678
gel(al2,11) = algtracebasis(al2);
4679
4680
return al2;
4681
}
4682
4683
static GEN
4684
algfromcenter(GEN al, GEN x)
4685
{
4686
GEN nf = alg_get_center(al);
4687
long n;
4688
switch(alg_type(al)) {
4689
case al_CYCLIC:
4690
n = alg_get_degree(al);
4691
break;
4692
case al_CSA:
4693
n = alg_get_dim(al);
4694
break;
4695
default:
4696
return NULL; /*LCOV_EXCL_LINE*/
4697
}
4698
return algalgtobasis(al, scalarcol(basistoalg(nf, x), n));
4699
}
4700
4701
/* x is an ideal of the center in hnf form */
4702
static GEN
4703
algfromcenterhnf(GEN al, GEN x)
4704
{
4705
GEN res;
4706
long i;
4707
res = cgetg(lg(x), t_MAT);
4708
for (i=1; i<lg(x); i++) gel(res,i) = algfromcenter(al, gel(x,i));
4709
return res;
4710
}
4711
4712
/* assumes al is CSA or CYCLIC */
4713
static GEN
4714
algcenter_precompute(GEN al, GEN p)
4715
{
4716
GEN fa, pdec, nfprad, projs, nf = alg_get_center(al);
4717
long i, np;
4718
4719
pdec = idealprimedec(nf, p);
4720
settyp(pdec, t_COL);
4721
np = lg(pdec)-1;
4722
fa = mkmat2(pdec, const_col(np, gen_1));
4723
if (dvdii(nf_get_disc(nf), p))
4724
nfprad = idealprodprime(nf, pdec);
4725
else
4726
nfprad = scalarmat_shallow(p, nf_get_degree(nf));
4727
fa = idealchineseinit(nf, fa);
4728
projs = cgetg(np+1, t_VEC);
4729
for (i=1; i<=np; i++) gel(projs, i) = idealchinese(nf, fa, vec_ei(np,i));
4730
return mkvec2(nfprad, projs);
4731
}
4732
4733
static GEN
4734
algcenter_prad(GEN al, GEN p, GEN pre)
4735
{
4736
GEN nfprad, zprad, mtprad;
4737
long i;
4738
nfprad = gel(pre,1);
4739
zprad = algfromcenterhnf(al, nfprad);
4740
zprad = FpM_image(zprad, p);
4741
mtprad = cgetg(lg(zprad), t_VEC);
4742
for (i=1; i<lg(zprad); i++) gel(mtprad, i) = algbasismultable(al, gel(zprad,i));
4743
mtprad = shallowmatconcat(mtprad);
4744
zprad = FpM_image(mtprad, p);
4745
return zprad;
4746
}
4747
4748
static GEN
4749
algcenter_p_projs(GEN al, GEN p, GEN pre)
4750
{
4751
GEN projs, zprojs;
4752
long i;
4753
projs = gel(pre,2);
4754
zprojs = cgetg(lg(projs), t_VEC);
4755
for (i=1; i<lg(projs); i++) gel(zprojs,i) = FpC_red(algfromcenter(al, gel(projs,i)),p);
4756
return zprojs;
4757
}
4758
4759
/* al is assumed to be simple */
4760
static GEN
4761
alg_pmaximal(GEN al, GEN p)
4762
{
4763
GEN al2, prad, lord = gen_0, I, id, dec, zprad, projs, pre;
4764
long n, i;
4765
n = alg_get_absdim(al);
4766
id = matid(n);
4767
al2 = al;
4768
4769
dbg_printf(0)("Round 2 (noncommutative) at p=%Ps, dim=%d\n", p, n);
4770
4771
pre = algcenter_precompute(al,p);
4772
4773
while (1) {
4774
zprad = algcenter_prad(al2, p, pre);
4775
projs = algcenter_p_projs(al2, p, pre);
4776
if (lg(projs) == 2) projs = NULL;
4777
prad = algpradical_i(al2,p,zprad,projs);
4778
if (typ(prad) == t_INT) break;
4779
lord = algleftordermodp(al2,prad,p);
4780
if (!cmp_universal(lord,id)) break;
4781
al2 = alg_change_overorder_shallow(al2,lord);
4782
}
4783
4784
dec = algpdecompose0(al2,prad,p,projs);
4785
while (lg(dec)>2) {
4786
for (i=1; i<lg(dec); i++) {
4787
I = gel(dec,i);
4788
lord = algleftordermodp(al2,I,p);
4789
if (cmp_universal(lord,matid(n))) break;
4790
}
4791
if (i==lg(dec)) break;
4792
al2 = alg_change_overorder_shallow(al2,lord);
4793
zprad = algcenter_prad(al2, p, pre);
4794
projs = algcenter_p_projs(al2, p, pre);
4795
if (lg(projs) == 2) projs = NULL;
4796
dec = algpdecompose_i(al2,p,zprad,projs);
4797
}
4798
return al2;
4799
}
4800
4801
static GEN
4802
algtracematrix(GEN al)
4803
{
4804
GEN M, mt;
4805
long n, i, j;
4806
n = alg_get_absdim(al);
4807
mt = alg_get_multable(al);
4808
M = cgetg(n+1, t_MAT);
4809
for (i=1; i<=n; i++)
4810
{
4811
gel(M,i) = cgetg(n+1,t_MAT);
4812
for (j=1; j<=i; j++)
4813
gcoeff(M,j,i) = gcoeff(M,i,j) = algabstrace(al,gmael(mt,i,j));
4814
}
4815
return M;
4816
}
4817
static GEN
4818
algdisc_i(GEN al) { return ZM_det(algtracematrix(al)); }
4819
GEN
4820
algdisc(GEN al)
4821
{
4822
pari_sp av = avma;
4823
checkalg(al); return gerepileuptoint(av, algdisc_i(al));
4824
}
4825
static GEN
4826
alg_maximal(GEN al)
4827
{
4828
GEN fa = absZ_factor(algdisc_i(al));
4829
return alg_maximal_primes(al, gel(fa,1));
4830
}
4831
4832
/** LATTICES **/
4833
4834
/*
4835
Convention: lattice = [I,t] representing t*I, where
4836
- I integral nonsingular upper-triangular matrix representing a lattice over
4837
the integral basis of the algebra, and
4838
- t>0 either an integer or a rational number.
4839
4840
Recommended and returned by the functions below:
4841
- I HNF and primitive
4842
*/
4843
4844
/* TODO use hnfmodid whenever possible using a*O <= I <= O
4845
* for instance a = ZM_det_triangular(I) */
4846
4847
static GEN
4848
primlat(GEN lat)
4849
{
4850
GEN m, t, c;
4851
m = alglat_get_primbasis(lat);
4852
t = alglat_get_scalar(lat);
4853
m = Q_primitive_part(m,&c);
4854
if (c) return mkvec2(m,gmul(t,c));
4855
return lat;
4856
}
4857
4858
/* assumes the lattice contains d * integral basis, d=0 allowed */
4859
GEN
4860
alglathnf(GEN al, GEN m, GEN d)
4861
{
4862
pari_sp av = avma;
4863
long N,i,j;
4864
GEN m2, c;
4865
checkalg(al);
4866
N = alg_get_absdim(al);
4867
if (!d) d = gen_0;
4868
if (typ(m) == t_VEC) m = matconcat(m);
4869
if (typ(m) == t_COL) m = algleftmultable(al,m);
4870
if (typ(m) != t_MAT) pari_err_TYPE("alglathnf",m);
4871
if (typ(d) != t_FRAC && typ(d) != t_INT) pari_err_TYPE("alglathnf",d);
4872
if (lg(m)-1 < N || lg(gel(m,1))-1 != N) pari_err_DIM("alglathnf");
4873
for (i=1; i<=N; i++)
4874
for (j=1; j<lg(m); j++)
4875
if (typ(gcoeff(m,i,j)) != t_FRAC && typ(gcoeff(m,i,j)) != t_INT)
4876
pari_err_TYPE("alglathnf", gcoeff(m,i,j));
4877
m2 = Q_primitive_part(m,&c);
4878
if (!c) c = gen_1;
4879
if (!signe(d)) d = detint(m2);
4880
else d = gdiv(d,c); /* should be an integer */
4881
if (!signe(d)) pari_err_INV("alglathnf [m does not have full rank]", m2);
4882
m2 = ZM_hnfmodid(m2,d);
4883
return gerepilecopy(av, mkvec2(m2,c));
4884
}
4885
4886
static GEN
4887
prepare_multipliers(GEN *a, GEN *b)
4888
{
4889
GEN na, nb, da, db, d;
4890
na = numer_i(*a); da = denom_i(*a);
4891
nb = numer_i(*b); db = denom_i(*b);
4892
na = mulii(na,db);
4893
nb = mulii(nb,da);
4894
d = gcdii(na,nb);
4895
*a = diviiexact(na,d);
4896
*b = diviiexact(nb,d);
4897
return gdiv(d, mulii(da,db));
4898
}
4899
4900
static GEN
4901
prepare_lat(GEN m1, GEN t1, GEN m2, GEN t2)
4902
{
4903
GEN d = prepare_multipliers(&t1, &t2);
4904
m1 = ZM_Z_mul(m1,t1);
4905
m2 = ZM_Z_mul(m2,t2);
4906
return mkvec3(m1,m2,d);
4907
}
4908
4909
static GEN
4910
alglataddinter(GEN al, GEN lat1, GEN lat2, GEN *sum, GEN *inter)
4911
{
4912
GEN d, m1, m2, t1, t2, M, prep, d1, d2, ds, di, K;
4913
checkalg(al);
4914
checklat(al,lat1);
4915
checklat(al,lat2);
4916
4917
m1 = alglat_get_primbasis(lat1);
4918
t1 = alglat_get_scalar(lat1);
4919
m2 = alglat_get_primbasis(lat2);
4920
t2 = alglat_get_scalar(lat2);
4921
prep = prepare_lat(m1, t1, m2, t2);
4922
m1 = gel(prep,1);
4923
m2 = gel(prep,2);
4924
d = gel(prep,3);
4925
M = matconcat(mkvec2(m1,m2));
4926
d1 = ZM_det_triangular(m1);
4927
d2 = ZM_det_triangular(m2);
4928
ds = gcdii(d1,d2);
4929
if (inter)
4930
{
4931
di = diviiexact(mulii(d1,d2),ds);
4932
K = matkermod(M,di,sum);
4933
K = rowslice(K,1,lg(m1));
4934
*inter = hnfmodid(FpM_mul(m1,K,di),di);
4935
if (sum) *sum = hnfmodid(*sum,ds);
4936
}
4937
else *sum = hnfmodid(M,ds);
4938
return d;
4939
}
4940
4941
GEN
4942
alglatinter(GEN al, GEN lat1, GEN lat2, GEN* ptsum)
4943
{
4944
pari_sp av = avma;
4945
GEN inter, d;
4946
d = alglataddinter(al, lat1, lat2, ptsum, &inter);
4947
inter = primlat(mkvec2(inter, d));
4948
if (ptsum)
4949
{
4950
*ptsum = primlat(mkvec2(*ptsum,d));
4951
gerepileall(av, 2, &inter, ptsum);
4952
}
4953
else inter = gerepilecopy(av, inter);
4954
return inter;
4955
}
4956
4957
GEN
4958
alglatadd(GEN al, GEN lat1, GEN lat2, GEN* ptinter)
4959
{
4960
pari_sp av = avma;
4961
GEN sum, d;
4962
d = alglataddinter(al, lat1, lat2, &sum, ptinter);
4963
sum = primlat(mkvec2(sum, d));
4964
if (ptinter)
4965
{
4966
*ptinter = primlat(mkvec2(*ptinter,d));
4967
gerepileall(av, 2, &sum, ptinter);
4968
}
4969
else sum = gerepilecopy(av, sum);
4970
return sum;
4971
}
4972
4973
int
4974
alglatsubset(GEN al, GEN lat1, GEN lat2, GEN* ptindex)
4975
{
4976
/* TODO version that returns the quotient as abelian group? */
4977
/* return matrices to convert coordinates from one to other? */
4978
pari_sp av = avma;
4979
int res;
4980
GEN m1, m2, m2i, m, t;
4981
checkalg(al);
4982
checklat(al,lat1);
4983
checklat(al,lat2);
4984
m1 = alglat_get_primbasis(lat1);
4985
m2 = alglat_get_primbasis(lat2);
4986
m2i = RgM_inv_upper(m2);
4987
t = gdiv(alglat_get_scalar(lat1), alglat_get_scalar(lat2));
4988
m = RgM_Rg_mul(RgM_mul(m2i,m1), t);
4989
res = RgM_is_ZM(m);
4990
if (res && ptindex)
4991
{
4992
*ptindex = mpabs(ZM_det_triangular(m));
4993
gerepileall(av,1,ptindex);
4994
}
4995
else set_avma(av);
4996
return res;
4997
}
4998
4999
GEN
5000
alglatindex(GEN al, GEN lat1, GEN lat2)
5001
{
5002
pari_sp av = avma;
5003
long N;
5004
GEN res;
5005
checkalg(al);
5006
checklat(al,lat1);
5007
checklat(al,lat2);
5008
N = alg_get_absdim(al);
5009
res = alglat_get_scalar(lat1);
5010
res = gdiv(res, alglat_get_scalar(lat2));
5011
res = gpowgs(res, N);
5012
res = gmul(res,RgM_det_triangular(alglat_get_primbasis(lat1)));
5013
res = gdiv(res, RgM_det_triangular(alglat_get_primbasis(lat2)));
5014
res = gabs(res,0);
5015
return gerepilecopy(av, res);
5016
}
5017
5018
GEN
5019
alglatmul(GEN al, GEN lat1, GEN lat2)
5020
{
5021
pari_sp av = avma;
5022
long N,i;
5023
GEN m1, m2, m, V, lat, t, d, dp;
5024
checkalg(al);
5025
if (typ(lat1)==t_COL)
5026
{
5027
if (typ(lat2)==t_COL)
5028
pari_err_TYPE("alglatmul [one of lat1, lat2 has to be a lattice]", lat2);
5029
checklat(al,lat2);
5030
lat1 = Q_remove_denom(lat1,&d);
5031
m = algbasismultable(al,lat1);
5032
m2 = alglat_get_primbasis(lat2);
5033
dp = mulii(detint(m),ZM_det_triangular(m2));
5034
m = ZM_mul(m,m2);
5035
t = alglat_get_scalar(lat2);
5036
if (d) t = gdiv(t,d);
5037
}
5038
else /* typ(lat1)!=t_COL */
5039
{
5040
checklat(al,lat1);
5041
if (typ(lat2)==t_COL)
5042
{
5043
lat2 = Q_remove_denom(lat2,&d);
5044
m = algbasisrightmultable(al,lat2);
5045
m1 = alglat_get_primbasis(lat1);
5046
dp = mulii(detint(m),ZM_det_triangular(m1));
5047
m = ZM_mul(m,m1);
5048
t = alglat_get_scalar(lat1);
5049
if (d) t = gdiv(t,d);
5050
}
5051
else /* typ(lat2)!=t_COL */
5052
{
5053
checklat(al,lat2);
5054
N = alg_get_absdim(al);
5055
m1 = alglat_get_primbasis(lat1);
5056
m2 = alglat_get_primbasis(lat2);
5057
dp = mulii(ZM_det_triangular(m1), ZM_det_triangular(m2));
5058
V = cgetg(N+1,t_VEC);
5059
for (i=1; i<=N; i++) {
5060
gel(V,i) = algbasismultable(al,gel(m1,i));
5061
gel(V,i) = ZM_mul(gel(V,i),m2);
5062
}
5063
m = matconcat(V);
5064
t = gmul(alglat_get_scalar(lat1), alglat_get_scalar(lat2));
5065
}
5066
}
5067
5068
lat = alglathnf(al,m,dp);
5069
gel(lat,2) = gmul(alglat_get_scalar(lat), t);
5070
lat = primlat(lat);
5071
return gerepilecopy(av, lat);
5072
}
5073
5074
int
5075
alglatcontains(GEN al, GEN lat, GEN x, GEN *ptc)
5076
{
5077
pari_sp av = avma;
5078
GEN m, t, sol;
5079
checkalg(al);
5080
checklat(al,lat);
5081
m = alglat_get_primbasis(lat);
5082
t = alglat_get_scalar(lat);
5083
x = RgC_Rg_div(x,t);
5084
if (!RgV_is_ZV(x)) return gc_bool(av,0);
5085
sol = hnf_solve(m,x);
5086
if (!sol) return gc_bool(av,0);
5087
if (!ptc) return gc_bool(av,1);
5088
*ptc = sol; gerepileall(av,1,ptc); return 1;
5089
}
5090
5091
GEN
5092
alglatelement(GEN al, GEN lat, GEN c)
5093
{
5094
pari_sp av = avma;
5095
GEN res;
5096
checkalg(al);
5097
checklat(al,lat);
5098
if (typ(c)!=t_COL) pari_err_TYPE("alglatelement", c);
5099
res = ZM_ZC_mul(alglat_get_primbasis(lat),c);
5100
res = RgC_Rg_mul(res, alglat_get_scalar(lat));
5101
return gerepilecopy(av,res);
5102
}
5103
5104
/* idem QM_invimZ, knowing result is contained in 1/c*Z^n */
5105
static GEN
5106
QM_invimZ_mod(GEN m, GEN c)
5107
{
5108
GEN d, m0, K;
5109
m0 = Q_remove_denom(m, &d);
5110
if (d) d = mulii(d,c);
5111
else d = c;
5112
K = matkermod(m0, d, NULL);
5113
if (lg(K)==1) K = scalarmat(d, lg(m)-1);
5114
else K = hnfmodid(K, d);
5115
return RgM_Rg_div(K,c);
5116
}
5117
5118
/* If m is injective, computes a Z-basis of the submodule of elements whose
5119
* image under m is integral */
5120
static GEN
5121
QM_invimZ(GEN m)
5122
{
5123
return RgM_invimage(m, QM_ImQ_hnf(m));
5124
}
5125
5126
/* An isomorphism of R-modules M_{m,n}(R) -> R^{m*n} */
5127
static GEN
5128
mat2col(GEN M, long m, long n)
5129
{
5130
long i,j,k,p;
5131
GEN C;
5132
p = m*n;
5133
C = cgetg(p+1,t_COL);
5134
for (i=1,k=1;i<=m;i++)
5135
for (j=1;j<=n;j++,k++)
5136
gel(C,k) = gcoeff(M,i,j);
5137
return C;
5138
}
5139
5140
static GEN
5141
alglattransporter_i(GEN al, GEN lat1, GEN lat2, long right)
5142
{
5143
GEN m1, m2, m2i, M, MT, mt, t1, t2, T, c;
5144
long N, i;
5145
N = alg_get_absdim(al);
5146
m1 = alglat_get_primbasis(lat1);
5147
m2 = alglat_get_primbasis(lat2);
5148
m2i = RgM_inv_upper(m2);
5149
c = detint(m1);
5150
t1 = alglat_get_scalar(lat1);
5151
m1 = RgM_Rg_mul(m1,t1);
5152
t2 = alglat_get_scalar(lat2);
5153
m2i = RgM_Rg_div(m2i,t2);
5154
5155
MT = right? NULL: alg_get_multable(al);
5156
M = cgetg(N+1, t_MAT);
5157
for (i=1; i<=N; i++) {
5158
if (right) mt = algbasisrightmultable(al, vec_ei(N,i));
5159
else mt = gel(MT,i);
5160
mt = RgM_mul(m2i,mt);
5161
mt = RgM_mul(mt,m1);
5162
gel(M,i) = mat2col(mt, N, N);
5163
}
5164
5165
c = gdiv(t2,gmul(c,t1));
5166
c = denom_i(c);
5167
T = QM_invimZ_mod(M,c);
5168
return primlat(mkvec2(T,gen_1));
5169
}
5170
5171
/*
5172
{ x in al | x*lat1 subset lat2}
5173
*/
5174
GEN
5175
alglatlefttransporter(GEN al, GEN lat1, GEN lat2)
5176
{
5177
pari_sp av = avma;
5178
checkalg(al);
5179
checklat(al,lat1);
5180
checklat(al,lat2);
5181
return gerepilecopy(av, alglattransporter_i(al,lat1,lat2,0));
5182
}
5183
5184
/*
5185
{ x in al | lat1*x subset lat2}
5186
*/
5187
GEN
5188
alglatrighttransporter(GEN al, GEN lat1, GEN lat2)
5189
{
5190
pari_sp av = avma;
5191
checkalg(al);
5192
checklat(al,lat1);
5193
checklat(al,lat2);
5194
return gerepilecopy(av, alglattransporter_i(al,lat1,lat2,1));
5195
}
5196
5197
GEN
5198
algmakeintegral(GEN mt0, long maps)
5199
{
5200
pari_sp av = avma;
5201
long n,i;
5202
GEN m,P,Pi,mt2,mt;
5203
n = lg(mt0)-1;
5204
mt = check_mt(mt0,NULL);
5205
if (!mt) pari_err_TYPE("algmakeintegral", mt0);
5206
if (isint1(Q_denom(mt0))) {
5207
if (maps) mt = mkvec3(mt,matid(n),matid(n));
5208
return gerepilecopy(av,mt);
5209
}
5210
dbg_printf(2)(" algmakeintegral: dim=%d, denom=%Ps\n", n, Q_denom(mt0));
5211
m = cgetg(n+1,t_MAT);
5212
for (i=1;i<=n;i++)
5213
gel(m,i) = mat2col(gel(mt,i),n,n);
5214
dbg_printf(2)(" computing order, dims m = %d x %d...\n", nbrows(m), lg(m)-1);
5215
P = QM_invimZ(m);
5216
dbg_printf(2)(" ...done.\n");
5217
P = shallowmatconcat(mkvec2(col_ei(n,1),P));
5218
P = hnf(P);
5219
Pi = RgM_inv(P);
5220
mt2 = change_Rgmultable(mt,P,Pi);
5221
if (maps) mt2 = mkvec3(mt2,Pi,P); /* mt2, mt->mt2, mt2->mt */
5222
return gerepilecopy(av,mt2);
5223
}
5224
5225
/** ORDERS **/
5226
5227
/** IDEALS **/
5228
5229
5230