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-2019 The PARI group.
2
3
This file is part of the PARI/GP package.
4
5
PARI/GP is free software; you can redistribute it and/or modify it under the
6
terms of the GNU General Public License as published by the Free Software
7
Foundation; either version 2 of the License, or (at your option) any later
8
version. It is distributed in the hope that it will be useful, but WITHOUT
9
ANY WARRANTY WHATSOEVER.
10
11
Check the License for details. You should have received a copy of it, along
12
with the package; see the file 'COPYING'. If not, write to the Free Software
13
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14
15
#include "pari.h"
16
#include "paripriv.h"
17
18
GEN
19
Flv_to_ZV(GEN x)
20
{ pari_APPLY_type(t_VEC, utoi(x[i])) }
21
22
GEN
23
Flc_to_ZC(GEN x)
24
{ pari_APPLY_type(t_COL, utoi(x[i])) }
25
26
GEN
27
Flm_to_ZM(GEN x)
28
{ pari_APPLY_type(t_MAT, Flc_to_ZC(gel(x,i))) }
29
30
GEN
31
Flc_to_ZC_inplace(GEN z)
32
{
33
long i, l = lg(z);
34
for (i=1; i<l; i++) gel(z,i) = utoi(z[i]);
35
settyp(z, t_COL);
36
return z;
37
}
38
39
GEN
40
Flm_to_ZM_inplace(GEN z)
41
{
42
long i, l = lg(z);
43
for (i=1; i<l; i++) Flc_to_ZC_inplace(gel(z, i));
44
return z;
45
}
46
47
static GEN
48
Flm_solve_upper_1(GEN U, GEN B, ulong p, ulong pi)
49
{ return Flm_Fl_mul_pre(B, Fl_inv(ucoeff(U, 1, 1), p), p, pi); }
50
51
static GEN
52
Flm_rsolve_upper_2(GEN U, GEN B, ulong p, ulong pi)
53
{
54
ulong a = ucoeff(U, 1, 1), b = ucoeff(U, 1, 2), d = ucoeff(U, 2, 2);
55
ulong D = Fl_mul_pre(a, d, p, pi), Dinv = Fl_inv(D, p);
56
ulong ainv = Fl_mul_pre(d, Dinv, p, pi);
57
ulong dinv = Fl_mul_pre(a, Dinv, p, pi);
58
GEN B1 = rowslice(B, 1, 1);
59
GEN B2 = rowslice(B, 2, 2);
60
GEN X2 = Flm_Fl_mul_pre(B2, dinv, p, pi);
61
GEN X1 = Flm_Fl_mul_pre(Flm_sub(B1, Flm_Fl_mul_pre(X2, b, p, pi), p),
62
ainv, p, pi);
63
return vconcat(X1, X2);
64
}
65
66
/* solve U*X = B, U upper triangular and invertible */
67
static GEN
68
Flm_rsolve_upper_pre(GEN U, GEN B, ulong p, ulong pi)
69
{
70
long n = lg(U) - 1, n1;
71
GEN U2, U11, U12, U22, B1, B2, X1, X2, X;
72
pari_sp av = avma;
73
74
if (n == 0) return B;
75
if (n == 1) return Flm_solve_upper_1(U, B, p, pi);
76
if (n == 2) return Flm_rsolve_upper_2(U, B, p, pi);
77
n1 = (n + 1)/2;
78
U2 = vecslice(U, n1 + 1, n);
79
U22 = rowslice(U2, n1 + 1, n);
80
B2 = rowslice(B, n1 + 1, n);
81
X2 = Flm_rsolve_upper_pre(U22, B2, p, pi);
82
U12 = rowslice(U2, 1, n1);
83
B1 = rowslice(B, 1, n1);
84
B1 = Flm_sub(B1, Flm_mul_pre(U12, X2, p, pi), p);
85
if (gc_needed(av, 1)) gerepileall(av, 2, &B1, &X2);
86
U11 = matslice(U, 1,n1, 1,n1);
87
X1 = Flm_rsolve_upper_pre(U11, B1, p, pi);
88
X = vconcat(X1, X2);
89
if (gc_needed(av, 1)) X = gerepilecopy(av, X);
90
return X;
91
}
92
93
static GEN
94
Flm_lsolve_upper_2(GEN U, GEN B, ulong p, ulong pi)
95
{
96
ulong a = ucoeff(U, 1, 1), b = ucoeff(U, 1, 2), d = ucoeff(U, 2, 2);
97
ulong D = Fl_mul_pre(a, d, p, pi), Dinv = Fl_inv(D, p);
98
ulong ainv = Fl_mul_pre(d, Dinv, p, pi);
99
ulong dinv = Fl_mul_pre(a, Dinv, p, pi);
100
GEN B1 = vecslice(B, 1, 1);
101
GEN B2 = vecslice(B, 2, 2);
102
GEN X1 = Flm_Fl_mul_pre(B1, ainv, p, pi);
103
GEN X2 = Flm_Fl_mul_pre(Flm_sub(B2, Flm_Fl_mul_pre(X1, b, p, pi), p),
104
dinv, p, pi);
105
return shallowconcat(X1, X2);
106
}
107
108
/* solve X*U = B, U upper triangular and invertible */
109
static GEN
110
Flm_lsolve_upper_pre(GEN U, GEN B, ulong p, ulong pi)
111
{
112
long n = lg(U) - 1, n1;
113
GEN U2, U11, U12, U22, B1, B2, X1, X2, X;
114
pari_sp av = avma;
115
116
if (n == 0) return B;
117
if (n == 1) return Flm_solve_upper_1(U, B, p, pi);
118
if (n == 2) return Flm_lsolve_upper_2(U, B, p, pi);
119
n1 = (n + 1)/2;
120
U2 = vecslice(U, n1 + 1, n);
121
U11 = matslice(U, 1,n1, 1,n1);
122
U12 = rowslice(U2, 1, n1);
123
U22 = rowslice(U2, n1 + 1, n);
124
B1 = vecslice(B, 1, n1);
125
B2 = vecslice(B, n1 + 1, n);
126
X1 = Flm_lsolve_upper_pre(U11, B1, p, pi);
127
B2 = Flm_sub(B2, Flm_mul_pre(X1, U12, p, pi), p);
128
if (gc_needed(av, 1)) gerepileall(av, 3, &B2, &U22, &X1);
129
X2 = Flm_lsolve_upper_pre(U22, B2, p, pi);
130
X = shallowconcat(X1, X2);
131
if (gc_needed(av, 1)) X = gerepilecopy(av, X);
132
return X;
133
}
134
135
static GEN
136
Flm_rsolve_lower_unit_2(GEN L, GEN A, ulong p, ulong pi)
137
{
138
GEN X1 = rowslice(A, 1, 1);
139
GEN X2 = Flm_sub(rowslice(A, 2, 2),
140
Flm_Fl_mul_pre(X1, ucoeff(L, 2, 1), p, pi), p);
141
return vconcat(X1, X2);
142
}
143
144
/* solve L*X = A, L lower triangular with ones on the diagonal
145
* (at least as many rows as columns) */
146
static GEN
147
Flm_rsolve_lower_unit_pre(GEN L, GEN A, ulong p, ulong pi)
148
{
149
long m = lg(L) - 1, m1, n;
150
GEN L1, L11, L21, L22, A1, A2, X1, X2, X;
151
pari_sp av = avma;
152
153
if (m == 0) return zero_Flm(0, lg(A) - 1);
154
if (m == 1) return rowslice(A, 1, 1);
155
if (m == 2) return Flm_rsolve_lower_unit_2(L, A, p, pi);
156
m1 = (m + 1)/2;
157
n = nbrows(L);
158
L1 = vecslice(L, 1, m1);
159
L11 = rowslice(L1, 1, m1);
160
L21 = rowslice(L1, m1 + 1, n);
161
A1 = rowslice(A, 1, m1);
162
X1 = Flm_rsolve_lower_unit_pre(L11, A1, p, pi);
163
A2 = rowslice(A, m1 + 1, n);
164
A2 = Flm_sub(A2, Flm_mul_pre(L21, X1, p, pi), p);
165
if (gc_needed(av, 1)) gerepileall(av, 2, &A2, &X1);
166
L22 = matslice(L, m1+1,n, m1+1,m);
167
X2 = Flm_rsolve_lower_unit_pre(L22, A2, p, pi);
168
X = vconcat(X1, X2);
169
if (gc_needed(av, 1)) X = gerepilecopy(av, X);
170
return X;
171
}
172
173
static GEN
174
Flm_lsolve_lower_unit_2(GEN L, GEN A, ulong p, ulong pi)
175
{
176
GEN X2 = vecslice(A, 2, 2);
177
GEN X1 = Flm_sub(vecslice(A, 1, 1),
178
Flm_Fl_mul_pre(X2, ucoeff(L, 2, 1), p, pi), p);
179
return shallowconcat(X1, X2);
180
}
181
182
/* solve L*X = A, L square lower triangular with ones on the diagonal */
183
static GEN
184
Flm_lsolve_lower_unit_pre(GEN L, GEN A, ulong p, ulong pi)
185
{
186
long m = lg(L) - 1, m1;
187
GEN L1, L2, L11, L21, L22, A1, A2, X1, X2, X;
188
pari_sp av = avma;
189
190
if (m <= 1) return A;
191
if (m == 2) return Flm_lsolve_lower_unit_2(L, A, p, pi);
192
m1 = (m + 1)/2;
193
L2 = vecslice(L, m1 + 1, m);
194
L22 = rowslice(L2, m1 + 1, m);
195
A2 = vecslice(A, m1 + 1, m);
196
X2 = Flm_lsolve_lower_unit_pre(L22, A2, p, pi);
197
if (gc_needed(av, 1)) X2 = gerepilecopy(av, X2);
198
L1 = vecslice(L, 1, m1);
199
L21 = rowslice(L1, m1 + 1, m);
200
A1 = vecslice(A, 1, m1);
201
A1 = Flm_sub(A1, Flm_mul_pre(X2, L21, p, pi), p);
202
L11 = rowslice(L1, 1, m1);
203
if (gc_needed(av, 1)) gerepileall(av, 3, &A1, &L11, &X2);
204
X1 = Flm_lsolve_lower_unit_pre(L11, A1, p, pi);
205
X = shallowconcat(X1, X2);
206
if (gc_needed(av, 1)) X = gerepilecopy(av, X);
207
return X;
208
}
209
210
/* destroy A */
211
static long
212
Flm_CUP_basecase(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, ulong p, ulong pi)
213
{
214
long i, j, k, m = nbrows(A), n = lg(A) - 1, pr, pc;
215
ulong u, v;
216
217
if (P) *P = identity_perm(n);
218
*R = cgetg(m + 1, t_VECSMALL);
219
for (j = 1, pr = 0; j <= n; j++)
220
{
221
for (pr++, pc = 0; pr <= m; pr++)
222
{
223
for (k = j; k <= n; k++) { v = ucoeff(A, pr, k); if (!pc && v) pc = k; }
224
if (pc) break;
225
}
226
if (!pc) break;
227
(*R)[j] = pr;
228
if (pc != j)
229
{
230
swap(gel(A, j), gel(A, pc));
231
if (P) lswap((*P)[j], (*P)[pc]);
232
}
233
u = Fl_inv(ucoeff(A, pr, j), p);
234
for (i = pr + 1; i <= m; i++)
235
{
236
v = Fl_mul_pre(ucoeff(A, i, j), u, p, pi);
237
ucoeff(A, i, j) = v;
238
v = Fl_neg(v, p);
239
for (k = j + 1; k <= n; k++)
240
ucoeff(A, i, k) = Fl_addmul_pre(ucoeff(A, i, k),
241
ucoeff(A, pr, k), v, p, pi);
242
}
243
}
244
setlg(*R, j);
245
*C = vecslice(A, 1, j - 1);
246
if (U) *U = rowpermute(A, *R);
247
return j - 1;
248
}
249
250
static const long Flm_CUP_LIMIT = 8;
251
252
static long
253
Flm_CUP_pre(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, ulong p, ulong pi)
254
{
255
long m = nbrows(A), m1, n = lg(A) - 1, i, r1, r2, r;
256
GEN R1, C1, U1, P1, R2, C2, U2, P2;
257
GEN A1, A2, B2, C21, U11, U12, T21, T22;
258
pari_sp av = avma;
259
260
if (m < Flm_CUP_LIMIT || n < Flm_CUP_LIMIT)
261
/* destroy A; not called at the outermost recursion level */
262
return Flm_CUP_basecase(A, R, C, U, P, p, pi);
263
m1 = (minss(m, n) + 1)/2;
264
A1 = rowslice(A, 1, m1);
265
A2 = rowslice(A, m1 + 1, m);
266
r1 = Flm_CUP_pre(A1, &R1, &C1, &U1, &P1, p, pi);
267
if (r1 == 0)
268
{
269
r2 = Flm_CUP_pre(A2, &R2, &C2, &U2, &P2, p, pi);
270
*R = cgetg(r2 + 1, t_VECSMALL);
271
for (i = 1; i <= r2; i++) (*R)[i] = R2[i] + m1;
272
*C = vconcat(zero_Flm(m1, r2), C2);
273
*U = U2;
274
*P = P2;
275
r = r2;
276
}
277
else
278
{
279
U11 = vecslice(U1, 1, r1);
280
U12 = vecslice(U1, r1 + 1, n);
281
T21 = vecslicepermute(A2, P1, 1, r1);
282
T22 = vecslicepermute(A2, P1, r1 + 1, n);
283
C21 = Flm_lsolve_upper_pre(U11, T21, p, pi);
284
if (gc_needed(av, 1))
285
gerepileall(av, 7, &R1, &C1, &P1, &U11, &U12, &T22, &C21);
286
B2 = Flm_sub(T22, Flm_mul_pre(C21, U12, p, pi), p);
287
r2 = Flm_CUP_pre(B2, &R2, &C2, &U2, &P2, p, pi);
288
r = r1 + r2;
289
*R = cgetg(r + 1, t_VECSMALL);
290
for (i = 1; i <= r1; i++) (*R)[i] = R1[i];
291
for (; i <= r; i++) (*R)[i] = R2[i - r1] + m1;
292
*C = shallowconcat(vconcat(C1, C21),
293
vconcat(zero_Flm(m1, r2), C2));
294
*U = shallowconcat(vconcat(U11, zero_Flm(r2, r1)),
295
vconcat(vecpermute(U12, P2), U2));
296
*P = cgetg(n + 1, t_VECSMALL);
297
for (i = 1; i <= r1; i++) (*P)[i] = P1[i];
298
for (; i <= n; i++) (*P)[i] = P1[P2[i - r1] + r1];
299
}
300
if (gc_needed(av, 1)) gerepileall(av, 4, R, C, U, P);
301
return r;
302
}
303
304
static long
305
Flm_echelon_gauss(GEN A, GEN *R, GEN *C, ulong p, ulong pi)
306
{ return Flm_CUP_basecase(A, R, C, NULL, NULL, p, pi); }
307
308
/* complement of a strictly increasing subsequence of (1, 2, ..., n) */
309
static GEN
310
indexcompl(GEN v, long n)
311
{
312
long i, j, k, m = lg(v) - 1;
313
GEN w = cgetg(n - m + 1, t_VECSMALL);
314
for (i = j = k = 1; i <= n; i++)
315
if (j <= m && v[j] == i) j++; else w[k++] = i;
316
return w;
317
}
318
319
/* column echelon form */
320
static long
321
Flm_echelon_pre(GEN A, GEN *R, GEN *C, ulong p, ulong pi)
322
{
323
long j, j1, j2, m = nbrows(A), n = lg(A) - 1, n1, r, r1, r2;
324
GEN A1, A2, R1, R1c, C1, R2, C2;
325
GEN A12, A22, B2, C11, C21, M12;
326
pari_sp av = avma;
327
328
if (m < Flm_CUP_LIMIT || n < Flm_CUP_LIMIT)
329
return Flm_echelon_gauss(Flm_copy(A), R, C, p, pi);
330
331
n1 = (n + 1)/2;
332
A1 = vecslice(A, 1, n1);
333
A2 = vecslice(A, n1 + 1, n);
334
r1 = Flm_echelon_pre(A1, &R1, &C1, p, pi);
335
if (!r1) return Flm_echelon_pre(A2, R, C, p, pi);
336
if (r1 == m) { *R = R1; *C = C1; return r1; }
337
338
R1c = indexcompl(R1, m);
339
C11 = rowpermute(C1, R1);
340
C21 = rowpermute(C1, R1c);
341
A12 = rowpermute(A2, R1);
342
A22 = rowpermute(A2, R1c);
343
M12 = Flm_rsolve_lower_unit_pre(C11, A12, p, pi);
344
B2 = Flm_sub(A22, Flm_mul_pre(C21, M12, p, pi), p);
345
r2 = Flm_echelon_pre(B2, &R2, &C2, p, pi);
346
if (!r2) { *R = R1; *C = C1; r = r1; }
347
else
348
{
349
R2 = perm_mul(R1c, R2);
350
C2 = rowpermute(vconcat(zero_Flm(r1, r2), C2),
351
perm_inv(vecsmall_concat(R1, R1c)));
352
r = r1 + r2;
353
*R = cgetg(r + 1, t_VECSMALL);
354
*C = cgetg(r + 1, t_MAT);
355
for (j = j1 = j2 = 1; j <= r; j++)
356
if (j2 > r2 || (j1 <= r1 && R1[j1] < R2[j2]))
357
{
358
gel(*C, j) = gel(C1, j1);
359
(*R)[j] = R1[j1++];
360
}
361
else
362
{
363
gel(*C, j) = gel(C2, j2);
364
(*R)[j] = R2[j2++];
365
}
366
}
367
if (gc_needed(av, 1)) gerepileall(av, 2, R, C);
368
return r;
369
}
370
371
static void /* assume m < p */
372
_Fl_addmul(GEN b, long k, long i, ulong m, ulong p, ulong pi)
373
{
374
uel(b,k) = Fl_addmul_pre(uel(b, k), m, uel(b, i), p, pi);
375
}
376
static void /* same m = 1 */
377
_Fl_add(GEN b, long k, long i, ulong p)
378
{
379
uel(b,k) = Fl_add(uel(b,k), uel(b,i), p);
380
}
381
static void /* assume m < p && SMALL_ULONG(p) && (! (b[i] & b[k] & HIGHMASK)) */
382
_Fl_addmul_OK(GEN b, long k, long i, ulong m, ulong p)
383
{
384
uel(b,k) += m * uel(b,i);
385
if (uel(b,k) & HIGHMASK) uel(b,k) %= p;
386
}
387
static void /* assume SMALL_ULONG(p) && (! (b[i] & b[k] & HIGHMASK)) */
388
_Fl_add_OK(GEN b, long k, long i, ulong p)
389
{
390
uel(b,k) += uel(b,i);
391
if (uel(b,k) & HIGHMASK) uel(b,k) %= p;
392
}
393
394
/* assume 0 <= a[i,j] < p */
395
static GEN
396
Fl_get_col_OK(GEN a, GEN b, long li, ulong p)
397
{
398
GEN u = cgetg(li+1,t_VECSMALL);
399
ulong m = uel(b,li) % p;
400
long i,j;
401
402
uel(u,li) = (m * ucoeff(a,li,li)) % p;
403
for (i = li-1; i > 0; i--)
404
{
405
m = p - uel(b,i)%p;
406
for (j = i+1; j <= li; j++) {
407
if (m & HIGHBIT) m %= p;
408
m += ucoeff(a,i,j) * uel(u,j); /* 0 <= u[j] < p */
409
}
410
m %= p;
411
if (m) m = ((p-m) * ucoeff(a,i,i)) % p;
412
uel(u,i) = m;
413
}
414
return u;
415
}
416
static GEN
417
Fl_get_col(GEN a, GEN b, long li, ulong p)
418
{
419
GEN u = cgetg(li+1,t_VECSMALL);
420
ulong m = uel(b,li) % p;
421
long i,j;
422
423
uel(u,li) = Fl_mul(m, ucoeff(a,li,li), p);
424
for (i=li-1; i>0; i--)
425
{
426
m = b[i]%p;
427
for (j = i+1; j <= li; j++)
428
m = Fl_sub(m, Fl_mul(ucoeff(a,i,j), uel(u,j), p), p);
429
if (m) m = Fl_mul(m, ucoeff(a,i,i), p);
430
uel(u,i) = m;
431
}
432
return u;
433
}
434
435
static GEN
436
Flm_ker_gauss_OK(GEN x, ulong p, long deplin)
437
{
438
GEN y, c, d;
439
long i, j, k, r, t, m, n;
440
ulong a;
441
442
n = lg(x)-1;
443
m=nbrows(x); r=0;
444
445
c = zero_zv(m);
446
d = cgetg(n+1, t_VECSMALL);
447
a = 0; /* for gcc -Wall */
448
for (k=1; k<=n; k++)
449
{
450
for (j=1; j<=m; j++)
451
if (!c[j])
452
{
453
a = ucoeff(x,j,k) % p;
454
if (a) break;
455
}
456
if (j > m)
457
{
458
if (deplin==1) {
459
c = cgetg(n+1, t_VECSMALL);
460
for (i=1; i<k; i++) c[i] = ucoeff(x,d[i],k) % p;
461
c[k] = 1; for (i=k+1; i<=n; i++) c[i] = 0;
462
return c;
463
}
464
r++; d[k] = 0;
465
}
466
else
467
{
468
ulong piv = p - Fl_inv(a, p); /* -1/a */
469
c[j] = k; d[k] = j;
470
ucoeff(x,j,k) = p-1;
471
if (piv != 1)
472
for (i=k+1; i<=n; i++) ucoeff(x,j,i) = (piv * ucoeff(x,j,i)) % p;
473
for (t=1; t<=m; t++)
474
{
475
if (t == j) continue;
476
477
piv = ( ucoeff(x,t,k) %= p );
478
if (!piv) continue;
479
if (piv == 1)
480
for (i=k+1; i<=n; i++) _Fl_add_OK(gel(x,i),t,j, p);
481
else
482
for (i=k+1; i<=n; i++) _Fl_addmul_OK(gel(x,i),t,j,piv, p);
483
}
484
}
485
}
486
if (deplin==1) return NULL;
487
488
y = cgetg(r+1, t_MAT);
489
for (j=k=1; j<=r; j++,k++)
490
{
491
GEN C = cgetg(n+1, t_VECSMALL);
492
493
gel(y,j) = C; while (d[k]) k++;
494
for (i=1; i<k; i++)
495
if (d[i])
496
uel(C,i) = ucoeff(x,d[i],k) % p;
497
else
498
uel(C,i) = 0UL;
499
uel(C,k) = 1UL; for (i=k+1; i<=n; i++) uel(C,i) = 0UL;
500
}
501
if (deplin == 2) {
502
GEN pc = cgetg(n - r + 1, t_VECSMALL); /* indices of pivot columns */
503
for (i = j = 1; j <= n; j++)
504
if (d[j]) pc[i++] = j;
505
return mkvec2(y, pc);
506
}
507
return y;
508
}
509
510
/* in place, destroy x */
511
static GEN
512
Flm_ker_gauss(GEN x, ulong p, long deplin)
513
{
514
GEN y, c, d;
515
long i, j, k, r, t, m, n;
516
ulong a, pi;
517
n = lg(x)-1;
518
if (!n) return cgetg(1,t_MAT);
519
if (SMALL_ULONG(p)) return Flm_ker_gauss_OK(x, p, deplin);
520
pi = get_Fl_red(p);
521
522
m=nbrows(x); r=0;
523
524
c = zero_zv(m);
525
d = cgetg(n+1, t_VECSMALL);
526
a = 0; /* for gcc -Wall */
527
for (k=1; k<=n; k++)
528
{
529
for (j=1; j<=m; j++)
530
if (!c[j])
531
{
532
a = ucoeff(x,j,k);
533
if (a) break;
534
}
535
if (j > m)
536
{
537
if (deplin==1) {
538
c = cgetg(n+1, t_VECSMALL);
539
for (i=1; i<k; i++) c[i] = ucoeff(x,d[i],k);
540
c[k] = 1; for (i=k+1; i<=n; i++) c[i] = 0;
541
return c;
542
}
543
r++; d[k] = 0;
544
}
545
else
546
{
547
ulong piv = p - Fl_inv(a, p); /* -1/a */
548
c[j] = k; d[k] = j;
549
ucoeff(x,j,k) = p-1;
550
if (piv != 1)
551
for (i=k+1; i<=n; i++)
552
ucoeff(x,j,i) = Fl_mul_pre(piv, ucoeff(x,j,i), p, pi);
553
for (t=1; t<=m; t++)
554
{
555
if (t == j) continue;
556
557
piv = ucoeff(x,t,k);
558
if (!piv) continue;
559
if (piv == 1)
560
for (i=k+1; i<=n; i++) _Fl_add(gel(x,i),t,j,p);
561
else
562
for (i=k+1; i<=n; i++) _Fl_addmul(gel(x,i),t,j,piv,p, pi);
563
}
564
}
565
}
566
if (deplin==1) return NULL;
567
568
y = cgetg(r+1, t_MAT);
569
for (j=k=1; j<=r; j++,k++)
570
{
571
GEN C = cgetg(n+1, t_VECSMALL);
572
573
gel(y,j) = C; while (d[k]) k++;
574
for (i=1; i<k; i++)
575
if (d[i])
576
uel(C,i) = ucoeff(x,d[i],k);
577
else
578
uel(C,i) = 0UL;
579
uel(C,k) = 1UL; for (i=k+1; i<=n; i++) uel(C,i) = 0UL;
580
}
581
if (deplin == 2) {
582
GEN pc = cgetg(n - r + 1, t_VECSMALL); /* indices of pivot columns */
583
for (i = j = 1; j <= n; j++)
584
if (d[j]) pc[i++] = j;
585
return mkvec2(y, pc);
586
}
587
return y;
588
}
589
590
GEN
591
Flm_intersect_i(GEN x, GEN y, ulong p)
592
{
593
long j, lx = lg(x);
594
GEN z;
595
596
if (lx==1 || lg(y)==1) return cgetg(1,t_MAT);
597
z = Flm_ker(shallowconcat(x,y), p);
598
for (j=lg(z)-1; j; j--) setlg(gel(z,j),lx);
599
return Flm_mul(x,z,p);
600
}
601
GEN
602
Flm_intersect(GEN x, GEN y, ulong p)
603
{
604
pari_sp av = avma;
605
return gerepileupto(av, Flm_image(Flm_intersect_i(x, y, p), p));
606
}
607
608
static GEN
609
Flm_ker_echelon(GEN x, ulong p, long pivots) {
610
pari_sp av = avma;
611
GEN R, Rc, C, C1, C2, S, K;
612
long n = lg(x) - 1, r;
613
ulong pi = get_Fl_red(p);
614
r = Flm_echelon_pre(Flm_transpose(x), &R, &C, p, pi);
615
Rc = indexcompl(R, n);
616
C1 = rowpermute(C, R);
617
C2 = rowpermute(C, Rc);
618
S = Flm_lsolve_lower_unit_pre(C1, C2, p, pi);
619
K = vecpermute(shallowconcat(Flm_neg(S, p), matid_Flm(n - r)),
620
perm_inv(vecsmall_concat(R, Rc)));
621
K = Flm_transpose(K);
622
if (pivots)
623
return gerepilecopy(av, mkvec2(K, R));
624
return gerepileupto(av, K);
625
}
626
627
static GEN
628
Flm_deplin_echelon(GEN x, ulong p) {
629
pari_sp av = avma;
630
GEN R, Rc, C, C1, C2, s, v;
631
long i, n = lg(x) - 1, r;
632
ulong pi = get_Fl_red(p);
633
r = Flm_echelon_pre(Flm_transpose(x), &R, &C, p, pi);
634
if (r == n) return gc_NULL(av);
635
Rc = indexcompl(R, n);
636
i = Rc[1];
637
C1 = rowpermute(C, R);
638
C2 = rowslice(C, i, i);
639
s = Flm_row(Flm_lsolve_lower_unit_pre(C1, C2, p, pi), 1);
640
v = vecsmallpermute(vecsmall_concat(Flv_neg(s, p), vecsmall_ei(n - r, 1)),
641
perm_inv(vecsmall_concat(R, Rc)));
642
return gerepileuptoleaf(av, v);
643
}
644
645
static GEN
646
Flm_ker_i(GEN x, ulong p, long deplin, long inplace) {
647
if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT)
648
switch(deplin) {
649
case 0: return Flm_ker_echelon(x, p, 0);
650
case 1: return Flm_deplin_echelon(x, p);
651
case 2: return Flm_ker_echelon(x, p, 1);
652
}
653
return Flm_ker_gauss(inplace? x: Flm_copy(x), p, deplin);
654
}
655
656
GEN
657
Flm_ker_sp(GEN x, ulong p, long deplin) {
658
return Flm_ker_i(x, p, deplin, 1);
659
}
660
661
GEN
662
Flm_ker(GEN x, ulong p) {
663
return Flm_ker_i(x, p, 0, 0);
664
}
665
666
GEN
667
Flm_deplin(GEN x, ulong p) {
668
return Flm_ker_i(x, p, 1, 0);
669
}
670
671
/* in place, destroy a, SMALL_ULONG(p) is TRUE */
672
static ulong
673
Flm_det_gauss_OK(GEN a, long nbco, ulong p)
674
{
675
long i,j,k, s = 1;
676
ulong q, x = 1;
677
678
for (i=1; i<nbco; i++)
679
{
680
for(k=i; k<=nbco; k++)
681
{
682
ulong c = ucoeff(a,k,i) % p;
683
ucoeff(a,k,i) = c;
684
if (c) break;
685
}
686
for(j=k+1; j<=nbco; j++) ucoeff(a,j,i) %= p;
687
if (k > nbco) return ucoeff(a,i,i);
688
if (k != i)
689
{ /* exchange the lines s.t. k = i */
690
for (j=i; j<=nbco; j++) lswap(ucoeff(a,i,j), ucoeff(a,k,j));
691
s = -s;
692
}
693
q = ucoeff(a,i,i);
694
695
if (x & HIGHMASK) x %= p;
696
x *= q;
697
q = Fl_inv(q,p);
698
for (k=i+1; k<=nbco; k++)
699
{
700
ulong m = ucoeff(a,i,k) % p;
701
if (!m) continue;
702
703
m = p - ((m*q)%p);
704
for (j=i+1; j<=nbco; j++)
705
{
706
ulong c = ucoeff(a,j,k);
707
if (c & HIGHMASK) c %= p;
708
ucoeff(a,j,k) = c + m*ucoeff(a,j,i);
709
}
710
}
711
}
712
if (x & HIGHMASK) x %= p;
713
q = ucoeff(a,nbco,nbco);
714
if (q & HIGHMASK) q %= p;
715
x = (x*q) % p;
716
if (s < 0 && x) x = p - x;
717
return x;
718
}
719
720
/* in place, destroy a */
721
static ulong
722
Flm_det_gauss(GEN a, ulong p)
723
{
724
long i,j,k, s = 1, nbco = lg(a)-1;
725
ulong pi, q, x = 1;
726
727
if (SMALL_ULONG(p)) return Flm_det_gauss_OK(a, nbco, p);
728
pi = get_Fl_red(p);
729
for (i=1; i<nbco; i++)
730
{
731
for(k=i; k<=nbco; k++)
732
if (ucoeff(a,k,i)) break;
733
if (k > nbco) return ucoeff(a,i,i);
734
if (k != i)
735
{ /* exchange the lines s.t. k = i */
736
for (j=i; j<=nbco; j++) lswap(ucoeff(a,i,j), ucoeff(a,k,j));
737
s = -s;
738
}
739
q = ucoeff(a,i,i);
740
741
x = Fl_mul_pre(x, q, p, pi);
742
q = Fl_inv(q,p);
743
for (k=i+1; k<=nbco; k++)
744
{
745
ulong m = ucoeff(a,i,k);
746
if (!m) continue;
747
748
m = Fl_mul_pre(m, q, p, pi);
749
for (j=i+1; j<=nbco; j++)
750
ucoeff(a,j,k) = Fl_sub(ucoeff(a,j,k), Fl_mul_pre(m,ucoeff(a,j,i), p, pi), p);
751
}
752
}
753
if (s < 0) x = Fl_neg(x, p);
754
return Fl_mul(x, ucoeff(a,nbco,nbco), p);
755
}
756
757
static ulong
758
Flm_det_CUP(GEN a, ulong p) {
759
GEN R, C, U, P;
760
long i, n = lg(a) - 1, r;
761
ulong d;
762
ulong pi = get_Fl_red(p);
763
r = Flm_CUP_pre(a, &R, &C, &U, &P, p, pi);
764
if (r < n)
765
d = 0;
766
else {
767
d = perm_sign(P) == 1? 1: p-1;
768
for (i = 1; i <= n; i++)
769
d = Fl_mul_pre(d, ucoeff(U, i, i), p, pi);
770
}
771
return d;
772
}
773
774
static ulong
775
Flm_det_i(GEN x, ulong p, long inplace) {
776
pari_sp av = avma;
777
ulong d;
778
if (lg(x) - 1 >= Flm_CUP_LIMIT)
779
d = Flm_det_CUP(x, p);
780
else
781
d = Flm_det_gauss(inplace? x: Flm_copy(x), p);
782
return gc_ulong(av, d);
783
}
784
785
ulong
786
Flm_det_sp(GEN x, ulong p) { return Flm_det_i(x, p, 1); }
787
ulong
788
Flm_det(GEN x, ulong p) { return Flm_det_i(x, p, 0); }
789
790
/* Destroy x */
791
static GEN
792
Flm_gauss_pivot(GEN x, ulong p, long *rr)
793
{
794
GEN c,d;
795
long i,j,k,r,t,n,m;
796
797
n=lg(x)-1; if (!n) { *rr=0; return NULL; }
798
799
m=nbrows(x); r=0;
800
d=cgetg(n+1,t_VECSMALL);
801
c = zero_zv(m);
802
for (k=1; k<=n; k++)
803
{
804
for (j=1; j<=m; j++)
805
if (!c[j])
806
{
807
ucoeff(x,j,k) %= p;
808
if (ucoeff(x,j,k)) break;
809
}
810
if (j>m) { r++; d[k]=0; }
811
else
812
{
813
ulong piv = p - Fl_inv(ucoeff(x,j,k), p);
814
c[j]=k; d[k]=j;
815
for (i=k+1; i<=n; i++)
816
ucoeff(x,j,i) = Fl_mul(piv, ucoeff(x,j,i), p);
817
for (t=1; t<=m; t++)
818
if (!c[t]) /* no pivot on that line yet */
819
{
820
piv = ucoeff(x,t,k);
821
if (piv)
822
{
823
ucoeff(x,t,k) = 0;
824
for (i=k+1; i<=n; i++)
825
ucoeff(x,t,i) = Fl_add(ucoeff(x,t,i),
826
Fl_mul(piv,ucoeff(x,j,i),p),p);
827
}
828
}
829
for (i=k; i<=n; i++) ucoeff(x,j,i) = 0; /* dummy */
830
}
831
}
832
*rr = r; return gc_const((pari_sp)d, d);
833
}
834
835
static GEN
836
Flm_pivots_CUP(GEN x, ulong p, long *rr)
837
{
838
long i, n = lg(x) - 1, r;
839
GEN R, C, U, P, d = zero_zv(n);
840
ulong pi = get_Fl_red(p);
841
r = Flm_CUP_pre(x, &R, &C, &U, &P, p, pi);
842
for(i = 1; i <= r; i++)
843
d[P[i]] = R[i];
844
*rr = n - r; return gc_const((pari_sp)d, d);
845
}
846
847
GEN
848
Flm_pivots(GEN x, ulong p, long *rr, long inplace)
849
{
850
if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT)
851
return Flm_pivots_CUP(x, p, rr);
852
return Flm_gauss_pivot(inplace? x: Flm_copy(x), p, rr);
853
}
854
855
long
856
Flm_rank(GEN x, ulong p)
857
{
858
pari_sp av = avma;
859
long r;
860
if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT) {
861
GEN R, C;
862
ulong pi = get_Fl_red(p);
863
return gc_long(av, Flm_echelon_pre(x, &R, &C, p, pi));
864
}
865
(void) Flm_pivots(x, p, &r, 0);
866
return gc_long(av, lg(x)-1 - r);
867
}
868
869
/* assume dim A >= 1, A invertible + upper triangular, 1s on diagonal,
870
* reduced mod p */
871
static GEN
872
Flm_inv_upper_1_ind(GEN A, long index, ulong p)
873
{
874
long n = lg(A)-1, i = index, j;
875
GEN u = const_vecsmall(n, 0);
876
u[i] = 1;
877
if (SMALL_ULONG(p))
878
for (i--; i>0; i--)
879
{
880
ulong m = ucoeff(A,i,i+1) * uel(u,i+1); /* j = i+1 */
881
for (j=i+2; j<=n; j++)
882
{
883
if (m & HIGHMASK) m %= p;
884
m += ucoeff(A,i,j) * uel(u,j);
885
}
886
u[i] = Fl_neg(m % p, p);
887
}
888
else
889
for (i--; i>0; i--)
890
{
891
ulong m = Fl_mul(ucoeff(A,i,i+1),uel(u,i+1), p); /* j = i+1 */
892
for (j=i+2; j<=n; j++) m = Fl_add(m, Fl_mul(ucoeff(A,i,j),uel(u,j),p), p);
893
u[i] = Fl_neg(m, p);
894
}
895
return u;
896
}
897
static GEN
898
Flm_inv_upper_1(GEN A, ulong p)
899
{
900
long i, l;
901
GEN B = cgetg_copy(A, &l);
902
for (i = 1; i < l; i++) gel(B,i) = Flm_inv_upper_1_ind(A, i, p);
903
return B;
904
}
905
/* destroy a, b */
906
static GEN
907
Flm_gauss_sp_OK(GEN a, GEN b, ulong *detp, ulong p)
908
{
909
long i, j, k, li, bco, aco = lg(a)-1, s = 1;
910
ulong det = 1;
911
GEN u;
912
913
li = nbrows(a);
914
bco = lg(b)-1;
915
for (i=1; i<=aco; i++)
916
{
917
ulong invpiv;
918
/* Fl_get_col wants 0 <= a[i,j] < p for all i,j */
919
for (k = 1; k < i; k++) ucoeff(a,k,i) %= p;
920
for (k = i; k <= li; k++)
921
{
922
ulong piv = ( ucoeff(a,k,i) %= p );
923
if (piv)
924
{
925
ucoeff(a,k,i) = Fl_inv(piv, p);
926
if (detp)
927
{
928
if (det & HIGHMASK) det %= p;
929
det *= piv;
930
}
931
break;
932
}
933
}
934
/* found a pivot on line k */
935
if (k > li) return NULL;
936
if (k != i)
937
{ /* swap lines so that k = i */
938
s = -s;
939
for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
940
for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));
941
}
942
if (i == aco) break;
943
944
invpiv = p - ucoeff(a,i,i); /* -1/piv mod p */
945
for (k=i+1; k<=li; k++)
946
{
947
ulong m = ( ucoeff(a,k,i) %= p );
948
if (!m) continue;
949
950
m = Fl_mul(m, invpiv, p);
951
if (m == 1) {
952
for (j=i+1; j<=aco; j++) _Fl_add_OK(gel(a,j),k,i, p);
953
for (j=1; j<=bco; j++) _Fl_add_OK(gel(b,j),k,i, p);
954
} else {
955
for (j=i+1; j<=aco; j++) _Fl_addmul_OK(gel(a,j),k,i,m, p);
956
for (j=1; j<=bco; j++) _Fl_addmul_OK(gel(b,j),k,i,m, p);
957
}
958
}
959
}
960
if (detp)
961
{
962
det %= p;
963
if (s < 0 && det) det = p - det;
964
*detp = det;
965
}
966
u = cgetg(bco+1,t_MAT);
967
for (j=1; j<=bco; j++) gel(u,j) = Fl_get_col_OK(a,gel(b,j), aco,p);
968
return u;
969
}
970
971
/* destroy a, b */
972
static GEN
973
Flm_gauss_sp_i(GEN a, GEN b, ulong *detp, ulong p)
974
{
975
long i, j, k, li, bco, aco = lg(a)-1, s = 1;
976
ulong det = 1;
977
GEN u;
978
ulong pi;
979
if (!aco) { if (detp) *detp = 1; return cgetg(1,t_MAT); }
980
if (SMALL_ULONG(p)) return Flm_gauss_sp_OK(a, b, detp, p);
981
pi = get_Fl_red(p);
982
li = nbrows(a);
983
bco = lg(b)-1;
984
for (i=1; i<=aco; i++)
985
{
986
ulong invpiv;
987
/* Fl_get_col wants 0 <= a[i,j] < p for all i,j */
988
for (k = i; k <= li; k++)
989
{
990
ulong piv = ucoeff(a,k,i);
991
if (piv)
992
{
993
ucoeff(a,k,i) = Fl_inv(piv, p);
994
if (detp) det = Fl_mul_pre(det, piv, p, pi);
995
break;
996
}
997
}
998
/* found a pivot on line k */
999
if (k > li) return NULL;
1000
if (k != i)
1001
{ /* swap lines so that k = i */
1002
s = -s;
1003
for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
1004
for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));
1005
}
1006
if (i == aco) break;
1007
1008
invpiv = p - ucoeff(a,i,i); /* -1/piv mod p */
1009
for (k=i+1; k<=li; k++)
1010
{
1011
ulong m = ucoeff(a,k,i);
1012
if (!m) continue;
1013
1014
m = Fl_mul_pre(m, invpiv, p, pi);
1015
if (m == 1) {
1016
for (j=i+1; j<=aco; j++) _Fl_add(gel(a,j),k,i, p);
1017
for (j=1; j<=bco; j++) _Fl_add(gel(b,j),k,i, p);
1018
} else {
1019
for (j=i+1; j<=aco; j++) _Fl_addmul(gel(a,j),k,i,m, p, pi);
1020
for (j=1; j<=bco; j++) _Fl_addmul(gel(b,j),k,i,m, p, pi);
1021
}
1022
}
1023
}
1024
if (detp)
1025
{
1026
if (s < 0 && det) det = p - det;
1027
*detp = det;
1028
}
1029
u = cgetg(bco+1,t_MAT);
1030
for (j=1; j<=bco; j++) gel(u,j) = Fl_get_col(a,gel(b,j), aco,p);
1031
return u;
1032
}
1033
1034
static GEN
1035
Flm_gauss_from_CUP(GEN b, GEN R, GEN C, GEN U, GEN P, ulong p, ulong pi, ulong *detp)
1036
{
1037
GEN Y = Flm_rsolve_lower_unit_pre(rowpermute(C, R), rowpermute(b, R), p, pi);
1038
GEN X = rowpermute(Flm_rsolve_upper_pre(U, Y, p, pi), perm_inv(P));
1039
if (detp)
1040
{
1041
ulong d = perm_sign(P) == 1? 1: p-1;
1042
long i, r = lg(R);
1043
for (i = 1; i < r; i++)
1044
d = Fl_mul_pre(d, ucoeff(U, i, i), p, pi);
1045
*detp = d;
1046
}
1047
return X;
1048
}
1049
1050
static GEN
1051
Flm_gauss_CUP(GEN a, GEN b, ulong *detp, ulong p) {
1052
GEN R, C, U, P;
1053
long n = lg(a) - 1, r;
1054
ulong pi = get_Fl_red(p);
1055
if (nbrows(a) < n || (r = Flm_CUP_pre(a, &R, &C, &U, &P, p, pi)) < n)
1056
return NULL;
1057
return Flm_gauss_from_CUP(b, R, C, U, P, p, pi, detp);
1058
}
1059
1060
GEN
1061
Flm_gauss_sp(GEN a, GEN b, ulong *detp, ulong p) {
1062
pari_sp av = avma;
1063
GEN x;
1064
if (lg(a) - 1 >= Flm_CUP_LIMIT)
1065
x = Flm_gauss_CUP(a, b, detp, p);
1066
else
1067
x = Flm_gauss_sp_i(a, b, detp, p);
1068
if (!x) return gc_NULL(av);
1069
return gerepileupto(av, x);
1070
}
1071
1072
GEN
1073
Flm_gauss(GEN a, GEN b, ulong p) {
1074
pari_sp av = avma;
1075
GEN x;
1076
if (lg(a) - 1 >= Flm_CUP_LIMIT)
1077
x = Flm_gauss_CUP(a, b, NULL, p);
1078
else {
1079
a = RgM_shallowcopy(a);
1080
b = RgM_shallowcopy(b);
1081
x = Flm_gauss_sp(a, b, NULL, p);
1082
}
1083
if (!x) return gc_NULL(av);
1084
return gerepileupto(av, x);
1085
}
1086
1087
static GEN
1088
Flm_inv_i(GEN a, ulong *detp, ulong p, long inplace) {
1089
pari_sp av = avma;
1090
long n = lg(a) - 1;
1091
GEN b, x;
1092
if (n == 0) return cgetg(1, t_MAT);
1093
b = matid_Flm(nbrows(a));
1094
if (n >= Flm_CUP_LIMIT)
1095
x = Flm_gauss_CUP(a, b, detp, p);
1096
else {
1097
if (!inplace)
1098
a = RgM_shallowcopy(a);
1099
x = Flm_gauss_sp(a, b, detp, p);
1100
}
1101
if (!x) return gc_NULL(av);
1102
return gerepileupto(av, x);
1103
}
1104
1105
GEN
1106
Flm_inv_sp(GEN a, ulong *detp, ulong p) {
1107
return Flm_inv_i(a, detp, p, 1);
1108
}
1109
1110
GEN
1111
Flm_inv(GEN a, ulong p) {
1112
return Flm_inv_i(a, NULL, p, 0);
1113
}
1114
1115
GEN
1116
Flm_Flc_gauss(GEN a, GEN b, ulong p) {
1117
pari_sp av = avma;
1118
GEN z = Flm_gauss(a, mkmat(b), p);
1119
if (!z) return gc_NULL(av);
1120
if (lg(z) == 1) { set_avma(av); return cgetg(1,t_VECSMALL); }
1121
return gerepileuptoleaf(av, gel(z,1));
1122
}
1123
1124
GEN
1125
Flm_adjoint(GEN A, ulong p)
1126
{
1127
pari_sp av = avma;
1128
GEN R, C, U, P, C1, U1, v, c, d;
1129
long r, i, q, n = lg(A)-1, m;
1130
ulong D;
1131
ulong pi = get_Fl_red(p);
1132
if (n == 0) return cgetg(1, t_MAT);
1133
r = Flm_CUP_pre(A, &R, &C, &U, &P, p, pi);
1134
m = nbrows(A);
1135
if (r == n)
1136
{
1137
GEN X = Flm_gauss_from_CUP(matid_Flm(m), R, C, U, P, p, pi, &D);
1138
return gerepileupto(av, Flm_Fl_mul_pre(X, D, p, pi));
1139
}
1140
if (r < n-1) return zero_Flm(n, m);
1141
for (q = n, i = 1; i < n; i++)
1142
if (R[i] != i) { q = i; break; }
1143
C1 = matslice(C, 1, q-1, 1, q-1);
1144
c = vecslice(Flm_row(C, q), 1, q-1);
1145
c = Flm_lsolve_lower_unit_pre(C1, Flm_transpose(mkmat(c)), p, pi);
1146
d = cgetg(m+1, t_VECSMALL);
1147
for (i=1; i<q; i++) uel(d,i) = ucoeff(c,1,i);
1148
uel(d,q) = p-1;
1149
for (i=q+1; i<=m; i++) uel(d,i) = 0;
1150
U1 = vecslice(U, 1, n-1);
1151
v = gel(Flm_rsolve_upper_pre(U1, mkmat(gel(U,n)), p, pi),1);
1152
v = vecsmall_append(v, p-1);
1153
D = perm_sign(P) != (odd(q+n)?-1:1) ? p-1 : 1;
1154
for (i = 1; i <= n-1; i++)
1155
D = Fl_mul_pre(D, ucoeff(U1, i, i), p, pi);
1156
d = Flv_Fl_mul(d, D, p);
1157
return rowpermute(Flc_Flv_mul(v, d, p),perm_inv(P));
1158
}
1159
1160
static GEN
1161
Flm_invimage_CUP(GEN A, GEN B, ulong p) {
1162
pari_sp av = avma;
1163
GEN R, Rc, C, U, P, B1, B2, C1, C2, X, Y, Z;
1164
long r;
1165
ulong pi = get_Fl_red(p);
1166
r = Flm_CUP_pre(A, &R, &C, &U, &P, p, pi);
1167
Rc = indexcompl(R, nbrows(B));
1168
C1 = rowpermute(C, R);
1169
C2 = rowpermute(C, Rc);
1170
B1 = rowpermute(B, R);
1171
B2 = rowpermute(B, Rc);
1172
Z = Flm_rsolve_lower_unit_pre(C1, B1, p, pi);
1173
if (!gequal(Flm_mul_pre(C2, Z, p, pi), B2))
1174
return NULL;
1175
Y = vconcat(Flm_rsolve_upper_pre(vecslice(U, 1, r), Z, p, pi),
1176
zero_Flm(lg(A) - 1 - r, lg(B) - 1));
1177
X = rowpermute(Y, perm_inv(P));
1178
return gerepileupto(av, X);
1179
}
1180
1181
GEN
1182
Flm_invimage_i(GEN A, GEN B, ulong p)
1183
{
1184
GEN d, x, X, Y;
1185
long i, j, nY, nA = lg(A)-1, nB = lg(B)-1;
1186
1187
if (!nB) return cgetg(1, t_MAT);
1188
if (maxss(nA, nB) >= Flm_CUP_LIMIT && nbrows(B) >= Flm_CUP_LIMIT)
1189
return Flm_invimage_CUP(A, B, p);
1190
1191
x = Flm_ker(shallowconcat(Flm_neg(A,p), B), p);
1192
/* AX = BY, Y in strict upper echelon form with pivots = 1.
1193
* We must find T such that Y T = Id_nB then X T = Z. This exists iff
1194
* Y has at least nB columns and full rank */
1195
nY = lg(x)-1;
1196
if (nY < nB) return NULL;
1197
Y = rowslice(x, nA+1, nA+nB); /* nB rows */
1198
d = cgetg(nB+1, t_VECSMALL);
1199
for (i = nB, j = nY; i >= 1; i--, j--)
1200
{
1201
for (; j>=1; j--)
1202
if (coeff(Y,i,j)) { d[i] = j; break; }
1203
if (!j) return NULL;
1204
}
1205
/* reduce to the case Y square, upper triangular with 1s on diagonal */
1206
Y = vecpermute(Y, d);
1207
x = vecpermute(x, d);
1208
X = rowslice(x, 1, nA);
1209
return Flm_mul(X, Flm_inv_upper_1(Y,p), p);
1210
}
1211
GEN
1212
Flm_invimage(GEN A, GEN B, ulong p)
1213
{
1214
pari_sp av = avma;
1215
GEN X = Flm_invimage_i(A,B,p);
1216
if (!X) return gc_NULL(av);
1217
return gerepileupto(av, X);
1218
}
1219
1220
GEN
1221
Flm_Flc_invimage(GEN A, GEN y, ulong p)
1222
{
1223
pari_sp av = avma;
1224
long i, l = lg(A);
1225
GEN M, x;
1226
ulong t;
1227
1228
if (l==1) return NULL;
1229
if (lg(y) != lgcols(A)) pari_err_DIM("Flm_Flc_invimage");
1230
M = cgetg(l+1,t_MAT);
1231
for (i=1; i<l; i++) gel(M,i) = gel(A,i);
1232
gel(M,l) = y; M = Flm_ker(M,p);
1233
i = lg(M)-1; if (!i) return gc_NULL(av);
1234
1235
x = gel(M,i); t = x[l];
1236
if (!t) return gc_NULL(av);
1237
1238
setlg(x,l); t = Fl_inv(Fl_neg(t,p),p);
1239
if (t!=1) x = Flv_Fl_mul(x, t, p);
1240
return gerepileuptoleaf(av, x);
1241
}
1242
1243