Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28486 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2012-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
#define DEBUGLEVEL DEBUGLEVEL_mat
19
20
/***********************************************************************/
21
/** **/
22
/** F2v **/
23
/** **/
24
/***********************************************************************/
25
/* F2v objects are defined as follows:
26
An F2v is a t_VECSMALL:
27
v[0] = codeword
28
v[1] = number of components
29
x[2] = a_0...a_31 x[3] = a_32..a_63, etc. on 32bit
30
x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit
31
32
where the a_i are bits.
33
*/
34
35
int
36
F2v_equal0(GEN V)
37
{
38
long l = lg(V);
39
while (--l > 1)
40
if (V[l]) return 0;
41
return 1;
42
}
43
44
GEN
45
F2c_to_ZC(GEN x)
46
{
47
long l = x[1]+1, lx = lg(x);
48
GEN z = cgetg(l, t_COL);
49
long i, j, k;
50
for (i=2, k=1; i<lx; i++)
51
for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
52
gel(z,k) = (x[i]&(1UL<<j))? gen_1: gen_0;
53
return z;
54
}
55
GEN
56
F2c_to_mod(GEN x)
57
{
58
long l = x[1]+1, lx = lg(x);
59
GEN z = cgetg(l, t_COL);
60
GEN _0 = mkintmod(gen_0,gen_2);
61
GEN _1 = mkintmod(gen_1,gen_2);
62
long i, j, k;
63
for (i=2, k=1; i<lx; i++)
64
for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
65
gel(z,k) = (x[i]&(1UL<<j))? _1: _0;
66
return z;
67
}
68
69
/* x[a..b], a <= b */
70
GEN
71
F2v_slice(GEN x, long a, long b)
72
{
73
long i,j,k, l = b-a+1;
74
GEN z = cgetg(nbits2lg(l), t_VECSMALL);
75
z[1] = l;
76
for(i=a,k=1,j=BITS_IN_LONG; i<=b; i++,j++)
77
{
78
if (j==BITS_IN_LONG) { j=0; z[++k]=0; }
79
if (F2v_coeff(x,i)) z[k] |= 1UL<<j;
80
}
81
return z;
82
}
83
/* x[a..b,], a <= b */
84
GEN
85
F2m_rowslice(GEN x, long a, long b)
86
{
87
long i, l;
88
GEN y = cgetg_copy(x, &l);
89
for (i = 1; i < l; i++) gel(y,i) = F2v_slice(gel(x,i),a,b);
90
return y;
91
}
92
93
GEN
94
F2m_to_ZM(GEN z)
95
{
96
long i, l = lg(z);
97
GEN x = cgetg(l,t_MAT);
98
for (i=1; i<l; i++) gel(x,i) = F2c_to_ZC(gel(z,i));
99
return x;
100
}
101
GEN
102
F2m_to_mod(GEN z)
103
{
104
long i, l = lg(z);
105
GEN x = cgetg(l,t_MAT);
106
for (i=1; i<l; i++) gel(x,i) = F2c_to_mod(gel(z,i));
107
return x;
108
}
109
110
GEN
111
F2v_to_Flv(GEN x)
112
{
113
long l = x[1]+1, lx = lg(x);
114
GEN z = cgetg(l, t_VECSMALL);
115
long i,j,k;
116
for (i=2, k=1; i<lx; i++)
117
for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
118
z[k] = (x[i]>>j)&1UL;
119
return z;
120
}
121
122
GEN
123
F2m_to_Flm(GEN z)
124
{
125
long i, l = lg(z);
126
GEN x = cgetg(l,t_MAT);
127
for (i=1; i<l; i++) gel(x,i) = F2v_to_Flv(gel(z,i));
128
return x;
129
}
130
131
GEN
132
ZV_to_F2v(GEN x)
133
{
134
long l = lg(x)-1;
135
GEN z = cgetg(nbits2lg(l), t_VECSMALL);
136
long i,j,k;
137
z[1] = l;
138
for(i=1,k=1,j=BITS_IN_LONG; i<=l; i++,j++)
139
{
140
if (j==BITS_IN_LONG) { j=0; z[++k]=0; }
141
if (mpodd(gel(x,i))) z[k] |= 1UL<<j;
142
}
143
return z;
144
}
145
146
GEN
147
RgV_to_F2v(GEN x)
148
{
149
long l = lg(x)-1;
150
GEN z = cgetg(nbits2lg(l), t_VECSMALL);
151
long i,j,k;
152
z[1] = l;
153
for(i=1,k=1,j=BITS_IN_LONG; i<=l; i++,j++)
154
{
155
if (j==BITS_IN_LONG) { j=0; z[++k]=0; }
156
if (Rg_to_F2(gel(x,i))) z[k] |= 1UL<<j;
157
}
158
return z;
159
}
160
161
GEN
162
Flv_to_F2v(GEN x)
163
{
164
long l = lg(x)-1;
165
GEN z = cgetg(nbits2lg(l), t_VECSMALL);
166
long i,j,k;
167
z[1] = l;
168
for(i=1,k=1,j=BITS_IN_LONG; i<=l; i++,j++)
169
{
170
if (j==BITS_IN_LONG) { j=0; z[++k]=0; }
171
if (x[i]&1L) z[k] |= 1UL<<j;
172
}
173
return z;
174
}
175
176
GEN
177
ZM_to_F2m(GEN x) { pari_APPLY_same(ZV_to_F2v(gel(x,i))) }
178
GEN
179
RgM_to_F2m(GEN x) { pari_APPLY_same(RgV_to_F2v(gel(x,i))) }
180
GEN
181
Flm_to_F2m(GEN x) { pari_APPLY_same(Flv_to_F2v(gel(x,i))) }
182
183
GEN
184
const_F2v(long m)
185
{
186
long i, l = nbits2lg(m);
187
GEN c = cgetg(l, t_VECSMALL);
188
c[1] = m;
189
for (i = 2; i < l; i++) uel(c,i) = -1UL;
190
if (remsBIL(m)) uel(c,l-1) = (1UL<<remsBIL(m))-1UL;
191
return c;
192
}
193
194
/* Allow lg(y)<lg(x) */
195
void
196
F2v_add_inplace(GEN x, GEN y)
197
{
198
long n = lg(y);
199
long r = (n-2)&7L, q = n-r, i;
200
for (i = 2; i < q; i += 8)
201
{
202
x[ i] ^= y[ i]; x[1+i] ^= y[1+i]; x[2+i] ^= y[2+i]; x[3+i] ^= y[3+i];
203
x[4+i] ^= y[4+i]; x[5+i] ^= y[5+i]; x[6+i] ^= y[6+i]; x[7+i] ^= y[7+i];
204
}
205
switch (r)
206
{
207
case 7: x[i] ^= y[i]; i++; case 6: x[i] ^= y[i]; i++;
208
case 5: x[i] ^= y[i]; i++; case 4: x[i] ^= y[i]; i++;
209
case 3: x[i] ^= y[i]; i++; case 2: x[i] ^= y[i]; i++;
210
case 1: x[i] ^= y[i]; i++;
211
}
212
}
213
214
/* Allow lg(y)<lg(x) */
215
void
216
F2v_and_inplace(GEN x, GEN y)
217
{
218
long n = lg(y);
219
long r = (n-2)&7L, q = n-r, i;
220
for (i = 2; i < q; i += 8)
221
{
222
x[ i] &= y[ i]; x[1+i] &= y[1+i]; x[2+i] &= y[2+i]; x[3+i] &= y[3+i];
223
x[4+i] &= y[4+i]; x[5+i] &= y[5+i]; x[6+i] &= y[6+i]; x[7+i] &= y[7+i];
224
}
225
switch (r)
226
{
227
case 7: x[i] &= y[i]; i++; case 6: x[i] &= y[i]; i++;
228
case 5: x[i] &= y[i]; i++; case 4: x[i] &= y[i]; i++;
229
case 3: x[i] &= y[i]; i++; case 2: x[i] &= y[i]; i++;
230
case 1: x[i] &= y[i]; i++;
231
}
232
}
233
234
/* Allow lg(y)<lg(x) */
235
void
236
F2v_or_inplace(GEN x, GEN y)
237
{
238
long n = lg(y);
239
long r = (n-2)&7L, q = n-r, i;
240
for (i = 2; i < q; i += 8)
241
{
242
x[ i] |= y[ i]; x[1+i] |= y[1+i]; x[2+i] |= y[2+i]; x[3+i] |= y[3+i];
243
x[4+i] |= y[4+i]; x[5+i] |= y[5+i]; x[6+i] |= y[6+i]; x[7+i] |= y[7+i];
244
}
245
switch (r)
246
{
247
case 7: x[i] |= y[i]; i++; case 6: x[i] |= y[i]; i++;
248
case 5: x[i] |= y[i]; i++; case 4: x[i] |= y[i]; i++;
249
case 3: x[i] |= y[i]; i++; case 2: x[i] |= y[i]; i++;
250
case 1: x[i] |= y[i]; i++;
251
}
252
}
253
254
/* Allow lg(y)<lg(x) */
255
void
256
F2v_negimply_inplace(GEN x, GEN y)
257
{
258
long n = lg(y);
259
long r = (n-2)&7L, q = n-r, i;
260
for (i = 2; i < q; i += 8)
261
{
262
x[ i] &= ~y[ i]; x[1+i] &= ~y[1+i]; x[2+i] &= ~y[2+i]; x[3+i] &= ~y[3+i];
263
x[4+i] &= ~y[4+i]; x[5+i] &= ~y[5+i]; x[6+i] &= ~y[6+i]; x[7+i] &= ~y[7+i];
264
}
265
switch (r)
266
{
267
case 7: x[i] &= ~y[i]; i++; case 6: x[i] &= ~y[i]; i++;
268
case 5: x[i] &= ~y[i]; i++; case 4: x[i] &= ~y[i]; i++;
269
case 3: x[i] &= ~y[i]; i++; case 2: x[i] &= ~y[i]; i++;
270
case 1: x[i] &= ~y[i]; i++;
271
}
272
}
273
274
ulong
275
F2v_dotproduct(GEN x, GEN y)
276
{
277
long i, lx = lg(x);
278
ulong c;
279
if (lx <= 2) return 0;
280
c = uel(x,2) & uel(y,2);
281
for (i=3; i<lx; i++) c ^= uel(x,i) & uel(y,i);
282
#ifdef LONG_IS_64BIT
283
c ^= c >> 32;
284
#endif
285
c ^= c >> 16;
286
c ^= c >> 8;
287
c ^= c >> 4;
288
c ^= c >> 2;
289
c ^= c >> 1;
290
return c & 1;
291
}
292
293
ulong
294
F2v_hamming(GEN H)
295
{
296
long i, n=0, l=lg(H);
297
for (i=2; i<l; i++) n += hammingl(uel(H,i));
298
return n;
299
}
300
301
GEN
302
matid_F2m(long n)
303
{
304
GEN y = cgetg(n+1,t_MAT);
305
long i;
306
if (n < 0) pari_err_DOMAIN("matid_F2m", "dimension","<",gen_0,stoi(n));
307
for (i=1; i<=n; i++) { gel(y,i) = zero_F2v(n); F2v_set(gel(y,i),i); }
308
return y;
309
}
310
311
GEN
312
F2m_row(GEN x, long j)
313
{
314
long i, l = lg(x);
315
GEN V = zero_F2v(l-1);
316
for(i = 1; i < l; i++)
317
if (F2m_coeff(x,j,i))
318
F2v_set(V,i);
319
return V;
320
}
321
322
GEN
323
F2m_transpose(GEN x)
324
{
325
long i, dx, lx = lg(x);
326
GEN y;
327
if (lx == 1) return cgetg(1,t_MAT);
328
dx = coeff(x,1,1); y = cgetg(dx+1,t_MAT);
329
for (i=1; i<=dx; i++) gel(y,i) = F2m_row(x,i);
330
return y;
331
}
332
333
INLINE GEN
334
F2m_F2c_mul_i(GEN x, GEN y, long lx, long l)
335
{
336
long j;
337
GEN z = NULL;
338
339
for (j=1; j<lx; j++)
340
{
341
if (!F2v_coeff(y,j)) continue;
342
if (!z) z = vecsmall_copy(gel(x,j));
343
else F2v_add_inplace(z,gel(x,j));
344
}
345
if (!z) z = zero_F2v(l);
346
return z;
347
}
348
349
GEN
350
F2m_mul(GEN x, GEN y)
351
{
352
long i,j,l,lx=lg(x), ly=lg(y);
353
GEN z;
354
if (ly==1) return cgetg(1,t_MAT);
355
z = cgetg(ly,t_MAT);
356
if (lx==1)
357
{
358
for (i=1; i<ly; i++) gel(z,i) = mkvecsmall(0);
359
return z;
360
}
361
l = coeff(x,1,1);
362
for (j=1; j<ly; j++) gel(z,j) = F2m_F2c_mul_i(x, gel(y,j), lx, l);
363
return z;
364
}
365
366
GEN
367
F2m_F2c_mul(GEN x, GEN y)
368
{
369
long l, lx = lg(x);
370
if (lx==1) return cgetg(1,t_VECSMALL);
371
l = coeff(x,1,1);
372
return F2m_F2c_mul_i(x, y, lx, l);
373
}
374
375
static GEN
376
_F2m_mul(void *data, GEN x, GEN y) { (void) data; return F2m_mul(x,y); }
377
static GEN
378
_F2m_sqr(void *data, GEN x) { (void) data; return F2m_mul(x,x); }
379
GEN
380
F2m_powu(GEN x, ulong n)
381
{
382
if (!n) return matid(lg(x)-1);
383
return gen_powu(x, n,NULL, &_F2m_sqr, &_F2m_mul);
384
}
385
386
static long
387
F2v_find_nonzero(GEN x0, GEN mask0, long m)
388
{
389
ulong *x = (ulong *)x0+2, *mask = (ulong *)mask0+2, e;
390
long i, l = lg(x0)-2;
391
for (i = 0; i < l; i++)
392
{
393
e = *x++ & *mask++;
394
if (e) return i*BITS_IN_LONG+vals(e)+1;
395
}
396
return m+1;
397
}
398
399
/* in place, destroy x */
400
GEN
401
F2m_ker_sp(GEN x, long deplin)
402
{
403
GEN y, c, d;
404
long i, j, k, r, m, n;
405
406
n = lg(x)-1;
407
m = mael(x,1,1); r=0;
408
409
d = cgetg(n+1, t_VECSMALL);
410
c = const_F2v(m);
411
for (k=1; k<=n; k++)
412
{
413
GEN xk = gel(x,k);
414
j = F2v_find_nonzero(xk, c, m);
415
if (j>m)
416
{
417
if (deplin) {
418
GEN c = zero_F2v(n);
419
for (i=1; i<k; i++)
420
if (F2v_coeff(xk, d[i]))
421
F2v_set(c, i);
422
F2v_set(c, k);
423
return c;
424
}
425
r++; d[k] = 0;
426
}
427
else
428
{
429
F2v_clear(c,j); d[k] = j;
430
F2v_clear(xk, j);
431
for (i=k+1; i<=n; i++)
432
{
433
GEN xi = gel(x,i);
434
if (F2v_coeff(xi,j)) F2v_add_inplace(xi, xk);
435
}
436
F2v_set(xk, j);
437
}
438
}
439
if (deplin) return NULL;
440
441
y = zero_F2m_copy(n,r);
442
for (j=k=1; j<=r; j++,k++)
443
{
444
GEN C = gel(y,j); while (d[k]) k++;
445
for (i=1; i<k; i++)
446
if (d[i] && F2m_coeff(x,d[i],k))
447
F2v_set(C,i);
448
F2v_set(C, k);
449
}
450
return y;
451
}
452
453
/* not memory clean */
454
GEN
455
F2m_ker(GEN x) { return F2m_ker_sp(F2m_copy(x), 0); }
456
GEN
457
F2m_deplin(GEN x) { return F2m_ker_sp(F2m_copy(x), 1); }
458
459
ulong
460
F2m_det_sp(GEN x) { return !F2m_ker_sp(x, 1); }
461
462
ulong
463
F2m_det(GEN x)
464
{
465
pari_sp av = avma;
466
ulong d = F2m_det_sp(F2m_copy(x));
467
return gc_ulong(av, d);
468
}
469
470
/* Destroy x */
471
GEN
472
F2m_gauss_pivot(GEN x, long *rr)
473
{
474
GEN c, d;
475
long i, j, k, r, m, n;
476
477
n = lg(x)-1; if (!n) { *rr=0; return NULL; }
478
m = mael(x,1,1); r=0;
479
480
d = cgetg(n+1, t_VECSMALL);
481
c = const_F2v(m);
482
for (k=1; k<=n; k++)
483
{
484
GEN xk = gel(x,k);
485
j = F2v_find_nonzero(xk, c, m);
486
if (j>m) { r++; d[k] = 0; }
487
else
488
{
489
F2v_clear(c,j); d[k] = j;
490
for (i=k+1; i<=n; i++)
491
{
492
GEN xi = gel(x,i);
493
if (F2v_coeff(xi,j)) F2v_add_inplace(xi, xk);
494
}
495
}
496
}
497
498
*rr = r; return gc_const((pari_sp)d, d);
499
}
500
501
long
502
F2m_rank(GEN x)
503
{
504
pari_sp av = avma;
505
long r;
506
(void)F2m_gauss_pivot(F2m_copy(x),&r);
507
return gc_long(av, lg(x)-1 - r);
508
}
509
510
static GEN
511
F2m_inv_upper_1_ind(GEN A, long index)
512
{
513
pari_sp av = avma;
514
long n = lg(A)-1, i = index, j;
515
GEN u = const_vecsmall(n, 0);
516
u[i] = 1;
517
for (i--; i>0; i--)
518
{
519
ulong m = F2m_coeff(A,i,i+1) & uel(u,i+1); /* j = i+1 */
520
for (j=i+2; j<=n; j++) m ^= F2m_coeff(A,i,j) & uel(u,j);
521
u[i] = m & 1;
522
}
523
return gerepileuptoleaf(av, Flv_to_F2v(u));
524
}
525
static GEN
526
F2m_inv_upper_1(GEN A)
527
{
528
long i, l;
529
GEN B = cgetg_copy(A, &l);
530
for (i = 1; i < l; i++) gel(B,i) = F2m_inv_upper_1_ind(A, i);
531
return B;
532
}
533
534
static GEN
535
F2_get_col(GEN b, GEN d, long li, long aco)
536
{
537
long i, l = nbits2lg(aco);
538
GEN u = cgetg(l, t_VECSMALL);
539
u[1] = aco;
540
for (i = 1; i <= li; i++)
541
if (d[i]) /* d[i] can still be 0 if li > aco */
542
{
543
if (F2v_coeff(b, i))
544
F2v_set(u, d[i]);
545
else
546
F2v_clear(u, d[i]);
547
}
548
return u;
549
}
550
551
/* destroy a, b */
552
GEN
553
F2m_gauss_sp(GEN a, GEN b)
554
{
555
long i, j, k, l, li, bco, aco = lg(a)-1;
556
GEN u, d;
557
558
if (!aco) return cgetg(1,t_MAT);
559
li = gel(a,1)[1];
560
d = zero_Flv(li);
561
bco = lg(b)-1;
562
for (i=1; i<=aco; i++)
563
{
564
GEN ai = vecsmall_copy(gel(a,i));
565
if (!d[i] && F2v_coeff(ai, i))
566
k = i;
567
else
568
for (k = 1; k <= li; k++) if (!d[k] && F2v_coeff(ai,k)) break;
569
/* found a pivot on row k */
570
if (k > li) return NULL;
571
d[k] = i;
572
573
/* Clear k-th row but column-wise instead of line-wise */
574
/* a_ij -= a_i1*a1j/a_11
575
line-wise grouping: L_j -= a_1j/a_11*L_1
576
column-wise: C_i -= a_i1/a_11*C_1
577
*/
578
F2v_clear(ai,k);
579
for (l=1; l<=aco; l++)
580
{
581
GEN al = gel(a,l);
582
if (F2v_coeff(al,k)) F2v_add_inplace(al,ai);
583
}
584
for (l=1; l<=bco; l++)
585
{
586
GEN bl = gel(b,l);
587
if (F2v_coeff(bl,k)) F2v_add_inplace(bl,ai);
588
}
589
}
590
u = cgetg(bco+1,t_MAT);
591
for (j = 1; j <= bco; j++) gel(u,j) = F2_get_col(gel(b,j), d, li, aco);
592
return u;
593
}
594
595
GEN
596
F2m_gauss(GEN a, GEN b)
597
{
598
pari_sp av = avma;
599
if (lg(a) == 1) return cgetg(1,t_MAT);
600
return gerepileupto(av, F2m_gauss_sp(F2m_copy(a), F2m_copy(b)));
601
}
602
GEN
603
F2m_F2c_gauss(GEN a, GEN b)
604
{
605
pari_sp av = avma;
606
GEN z = F2m_gauss(a, mkmat(b));
607
if (!z) return gc_NULL(av);
608
if (lg(z) == 1) { set_avma(av); return cgetg(1,t_VECSMALL); }
609
return gerepileuptoleaf(av, gel(z,1));
610
}
611
612
GEN
613
F2m_inv(GEN a)
614
{
615
pari_sp av = avma;
616
if (lg(a) == 1) return cgetg(1,t_MAT);
617
return gerepileupto(av, F2m_gauss_sp(F2m_copy(a), matid_F2m(gel(a,1)[1])));
618
}
619
620
GEN
621
F2m_invimage_i(GEN A, GEN B)
622
{
623
GEN d, x, X, Y;
624
long i, j, nY, nA = lg(A)-1, nB = lg(B)-1;
625
x = F2m_ker_sp(shallowconcat(A, B), 0);
626
/* AX = BY, Y in strict upper echelon form with pivots = 1.
627
* We must find T such that Y T = Id_nB then X T = Z. This exists iff
628
* Y has at least nB columns and full rank */
629
nY = lg(x)-1;
630
if (nY < nB) return NULL;
631
632
/* implicitly: Y = rowslice(x, nA+1, nA+nB), nB rows */
633
d = cgetg(nB+1, t_VECSMALL);
634
for (i = nB, j = nY; i >= 1; i--, j--)
635
{
636
for (; j>=1; j--)
637
if (F2m_coeff(x,nA+i,j)) { d[i] = j; break; } /* Y[i,j] */
638
if (!j) return NULL;
639
}
640
x = vecpermute(x, d);
641
642
X = F2m_rowslice(x, 1, nA);
643
Y = F2m_rowslice(x, nA+1, nA+nB);
644
return F2m_mul(X, F2m_inv_upper_1(Y));
645
}
646
GEN
647
F2m_invimage(GEN A, GEN B)
648
{
649
pari_sp av = avma;
650
GEN X = F2m_invimage_i(A,B);
651
if (!X) return gc_NULL(av);
652
return gerepileupto(av, X);
653
}
654
655
GEN
656
F2m_F2c_invimage(GEN A, GEN y)
657
{
658
pari_sp av = avma;
659
long i, l = lg(A);
660
GEN M, x;
661
662
if (l==1) return NULL;
663
if (lg(y) != lgcols(A)) pari_err_DIM("F2m_F2c_invimage");
664
M = cgetg(l+1,t_MAT);
665
for (i=1; i<l; i++) gel(M,i) = gel(A,i);
666
gel(M,l) = y; M = F2m_ker(M);
667
i = lg(M)-1; if (!i) return gc_NULL(av);
668
669
x = gel(M,i);
670
if (!F2v_coeff(x,l)) return gc_NULL(av);
671
F2v_clear(x, x[1]); x[1]--; /* remove last coord */
672
return gerepileuptoleaf(av, x);
673
}
674
675
/* Block Lanczos algorithm for kernel of sparse matrix (F2Ms)
676
Based on lanczos.cpp by Jason Papadopoulos
677
<https://github.com/sagemath/FlintQS/blob/master/src/lanczos.cpp>
678
Copyright Jason Papadopoulos 2006
679
Released under the GNU General Public License v2 or later version.
680
*/
681
682
/* F2Ms are vector of vecsmall which represents nonzero entries of columns
683
* F2w are vecsmall whoses entries are columns of a n x BIL F2m
684
* F2wB are F2w in the special case where dim = BIL.
685
*/
686
687
#define BIL BITS_IN_LONG
688
689
static GEN
690
F2w_transpose_F2m(GEN x)
691
{
692
long i, j, l = lg(x)-1;
693
GEN z = cgetg(BIL+1, t_MAT);
694
for (j = 1; j <= BIL; j++)
695
gel(z,j) = zero_F2v(l);
696
for (i = 1; i <= l; i++)
697
{
698
ulong xi = uel(x,i);
699
for(j = 1; j <= BIL; j++)
700
if (xi&(1UL<<(j-1)))
701
F2v_set(gel(z, j), i);
702
}
703
return z;
704
}
705
706
static GEN
707
F2wB_mul(GEN a, GEN b)
708
{
709
long i, j;
710
GEN c = cgetg(BIL+1, t_VECSMALL);
711
for (i = 1; i <= BIL; i++)
712
{
713
ulong s = 0, ai = a[i];
714
for (j = 1; ai; j++, ai>>=1)
715
if (ai & 1)
716
s ^= b[j];
717
c[i] = s;
718
}
719
return c;
720
}
721
722
static void
723
precompute_F2w_F2wB(GEN x, GEN c)
724
{
725
ulong z, xk;
726
ulong i, j, k, index;
727
x++; c++;
728
for (j = 0; j < (BIL>>3); j++)
729
{
730
for (i = 0; i < 256; i++)
731
{
732
k = 0;
733
index = i;
734
z = 0;
735
while (index) {
736
xk = x[k];
737
if (index & 1)
738
z ^= xk;
739
index >>= 1;
740
k++;
741
}
742
c[i] = z;
743
}
744
x += 8; c += 256;
745
}
746
}
747
748
static void
749
F2w_F2wB_mul_add_inplace(GEN v, GEN x, GEN y)
750
{
751
long i, n = lg(y)-1;
752
ulong word;
753
GEN c = cgetg(1+(BIL<<5), t_VECSMALL);
754
precompute_F2w_F2wB(x, c);
755
c++;
756
for (i = 1; i <= n; i++)
757
{
758
word = v[i];
759
y[i] ^= c[ 0*256 + ((word>> 0) & 0xff) ]
760
^ c[ 1*256 + ((word>> 8) & 0xff) ]
761
^ c[ 2*256 + ((word>>16) & 0xff) ]
762
^ c[ 3*256 + ((word>>24) & 0xff) ]
763
#ifdef LONG_IS_64BIT
764
^ c[ 4*256 + ((word>>32) & 0xff) ]
765
^ c[ 5*256 + ((word>>40) & 0xff) ]
766
^ c[ 6*256 + ((word>>48) & 0xff) ]
767
^ c[ 7*256 + ((word>>56) ) ]
768
#endif
769
;
770
}
771
}
772
773
/* Return x*y~, which is a F2wB */
774
static GEN
775
F2w_transmul(GEN x, GEN y)
776
{
777
long i, j, n = lg(x)-1;
778
GEN z = zero_zv(BIL);
779
pari_sp av = avma;
780
GEN c = zero_zv(BIL<<5) + 1;
781
GEN xy = z + 1;
782
783
for (i = 1; i <= n; i++)
784
{
785
ulong xi = x[i];
786
ulong yi = y[i];
787
c[ 0*256 + ( xi & 0xff) ] ^= yi;
788
c[ 1*256 + ((xi >> 8) & 0xff) ] ^= yi;
789
c[ 2*256 + ((xi >> 16) & 0xff) ] ^= yi;
790
c[ 3*256 + ((xi >> 24) & 0xff) ] ^= yi;
791
#ifdef LONG_IS_64BIT
792
c[ 4*256 + ((xi >> 32) & 0xff) ] ^= yi;
793
c[ 5*256 + ((xi >> 40) & 0xff) ] ^= yi;
794
c[ 6*256 + ((xi >> 48) & 0xff) ] ^= yi;
795
c[ 7*256 + ((xi >> 56) ) ] ^= yi;
796
#endif
797
}
798
for(i = 0; i < 8; i++)
799
{
800
ulong a0 = 0, a1 = 0, a2 = 0, a3 = 0;
801
#ifdef LONG_IS_64BIT
802
ulong a4 = 0, a5 = 0, a6 = 0, a7 = 0;
803
#endif
804
for (j = 0; j < 256; j++) {
805
if ((j >> i) & 1) {
806
a0 ^= c[0*256 + j];
807
a1 ^= c[1*256 + j];
808
a2 ^= c[2*256 + j];
809
a3 ^= c[3*256 + j];
810
#ifdef LONG_IS_64BIT
811
a4 ^= c[4*256 + j];
812
a5 ^= c[5*256 + j];
813
a6 ^= c[6*256 + j];
814
a7 ^= c[7*256 + j];
815
#endif
816
}
817
}
818
xy[ 0] = a0; xy[ 8] = a1; xy[16] = a2; xy[24] = a3;
819
#ifdef LONG_IS_64BIT
820
xy[32] = a4; xy[40] = a5; xy[48] = a6; xy[56] = a7;
821
#endif
822
xy++;
823
}
824
return gc_const(av, z);
825
}
826
827
static GEN
828
identity_F2wB(void)
829
{
830
long i;
831
GEN M = cgetg(BIL+1, t_VECSMALL);
832
for (i = 1; i <= BIL; i++)
833
uel(M,i) = 1UL<<(i-1);
834
return M;
835
}
836
837
static GEN
838
find_nonsingular_sub(GEN t, GEN last_s, GEN *pt_s)
839
{
840
long i, j, dim = 0;
841
ulong mask, row_i, row_j;
842
long last_dim = lg(last_s)-1;
843
GEN s = cgetg(BIL+1, t_VECSMALL);
844
GEN M1 = identity_F2wB();
845
pari_sp av = avma;
846
GEN cols = cgetg(BIL+1, t_VECSMALL);
847
GEN M0 = zv_copy(t);
848
849
mask = 0;
850
for (i = 1; i <= last_dim; i++)
851
{
852
cols[BIL + 1 - i] = last_s[i];
853
mask |= 1UL<<(last_s[i]-1);
854
}
855
for (i = j = 1; i <= BIL; i++)
856
if (!(mask & (1UL<<(i-1))))
857
cols[j++] = i;
858
859
/* compute the inverse of t[][] */
860
861
for (i = 1; i <= BIL; i++)
862
{
863
mask = 1UL<<(cols[i]-1);
864
row_i = cols[i];
865
for (j = i; j <= BIL; j++)
866
{
867
row_j = cols[j];
868
if (uel(M0,row_j) & mask)
869
{
870
swap(gel(M0, row_j), gel(M0, row_i));
871
swap(gel(M1, row_j), gel(M1, row_i));
872
break;
873
}
874
}
875
if (j <= BIL)
876
{
877
for (j = 1; j <= BIL; j++)
878
{
879
row_j = cols[j];
880
if (row_i != row_j && (M0[row_j] & mask))
881
{
882
uel(M0,row_j) ^= uel(M0,row_i);
883
uel(M1,row_j) ^= uel(M1,row_i);
884
}
885
}
886
s[++dim] = cols[i];
887
continue;
888
}
889
for (j = i; j <= BIL; j++)
890
{
891
row_j = cols[j];
892
if (uel(M1,row_j) & mask)
893
{
894
swap(gel(M0, row_j), gel(M0, row_i));
895
swap(gel(M1, row_j), gel(M1, row_i));
896
break;
897
}
898
}
899
if (j > BIL) return NULL;
900
for (j = 1; j <= BIL; j++)
901
{
902
row_j = cols[j];
903
if (row_i != row_j && (M1[row_j] & mask))
904
{
905
uel(M0,row_j) ^= uel(M0,row_i);
906
uel(M1,row_j) ^= uel(M1,row_i);
907
}
908
}
909
M0[row_i] = M1[row_i] = 0;
910
}
911
mask = 0;
912
for (i = 1; i <= dim; i++)
913
mask |= 1UL<<(s[i]-1);
914
for (i = 1; i <= last_dim; i++)
915
mask |= 1UL<<(last_s[i]-1);
916
if (mask != (ulong)(-1))
917
return NULL; /* Failure */
918
setlg(s, dim+1);
919
set_avma(av);
920
*pt_s = s;
921
return M1;
922
}
923
924
/* Compute x * A~ */
925
static GEN
926
F2w_F2Ms_transmul(GEN x, GEN A, long nbrow)
927
{
928
long i, j, l = lg(A);
929
GEN b = zero_zv(nbrow);
930
for (i = 1; i < l; i++)
931
{
932
GEN c = gel(A,i);
933
long lc = lg(c);
934
ulong xi = x[i];
935
for (j = 1; j < lc; j++)
936
b[c[j]] ^= xi;
937
}
938
return b;
939
}
940
941
/* Compute x * A */
942
static GEN
943
F2w_F2Ms_mul(GEN x, GEN A)
944
{
945
long i, j, l = lg(A);
946
GEN b = cgetg(l, t_VECSMALL);
947
for (i = 1; i < l; i++)
948
{
949
GEN c = gel(A,i);
950
long lc = lg(c);
951
ulong s = 0;
952
for (j = 1; j < lc; j++)
953
s ^= x[c[j]];
954
b[i] = s;
955
}
956
return b;
957
}
958
959
static void
960
F2wB_addid_inplace(GEN f)
961
{
962
long i;
963
for (i = 1; i <= BIL; i++)
964
uel(f,i) ^= 1UL<<(i-1);
965
}
966
967
static void
968
F2w_mask_inplace(GEN f, ulong m)
969
{
970
long i, l = lg(f);
971
for (i = 1; i < l; i++)
972
uel(f,i) &= m;
973
}
974
975
static GEN
976
block_lanczos(GEN B, ulong nbrow)
977
{
978
pari_sp av = avma, av2;
979
GEN v0, v1, v2, vnext, x, w;
980
GEN winv0, winv1, winv2;
981
GEN vt_a_v0, vt_a_v1, vt_a2_v0, vt_a2_v1;
982
GEN d, e, f, f2, s0;
983
long i, iter;
984
long n = lg(B)-1;
985
long dim0;
986
ulong mask0, mask1;
987
v1 = zero_zv(n);
988
v2 = zero_zv(n);
989
vt_a_v1 = zero_zv(BIL);
990
vt_a2_v1 = zero_zv(BIL);
991
winv1 = zero_zv(BIL);
992
winv2 = zero_zv(BIL);
993
s0 = identity_zv(BIL);
994
mask1 = (ulong)(-1);
995
996
x = random_zv(n);
997
w = F2w_F2Ms_mul(F2w_F2Ms_transmul(x, B, nbrow), B);
998
v0 = w;
999
av2 = avma;
1000
for (iter=1;;iter++)
1001
{
1002
vnext = F2w_F2Ms_mul(F2w_F2Ms_transmul(v0, B, nbrow), B);
1003
vt_a_v0 = F2w_transmul(v0, vnext);
1004
if (zv_equal0(vt_a_v0)) break; /* success */
1005
vt_a2_v0 = F2w_transmul(vnext, vnext);
1006
winv0 = find_nonsingular_sub(vt_a_v0, s0, &s0);
1007
if (!winv0) return gc_NULL(av); /* failure */
1008
dim0 = lg(s0)-1;
1009
mask0 = 0;
1010
for (i = 1; i <= dim0; i++)
1011
mask0 |= 1UL<<(s0[i]-1);
1012
d = cgetg(BIL+1, t_VECSMALL);
1013
for (i = 1; i <= BIL; i++)
1014
d[i] = (vt_a2_v0[i] & mask0) ^ vt_a_v0[i];
1015
1016
d = F2wB_mul(winv0, d);
1017
F2wB_addid_inplace(d);
1018
e = F2wB_mul(winv1, vt_a_v0);
1019
F2w_mask_inplace(e, mask0);
1020
f = F2wB_mul(vt_a_v1, winv1);
1021
F2wB_addid_inplace(f);
1022
f = F2wB_mul(winv2, f);
1023
f2 = cgetg(BIL+1, t_VECSMALL);
1024
for (i = 1; i <= BIL; i++)
1025
f2[i] = ((vt_a2_v1[i] & mask1) ^ vt_a_v1[i]) & mask0;
1026
1027
f = F2wB_mul(f, f2);
1028
F2w_mask_inplace(vnext, mask0);
1029
F2w_F2wB_mul_add_inplace(v0, d, vnext);
1030
F2w_F2wB_mul_add_inplace(v1, e, vnext);
1031
F2w_F2wB_mul_add_inplace(v2, f, vnext);
1032
d = F2wB_mul(winv0, F2w_transmul(v0, w));
1033
F2w_F2wB_mul_add_inplace(v0, d, x);
1034
v2 = v1; v1 = v0; v0 = vnext;
1035
winv2 = winv1; winv1 = winv0;
1036
vt_a_v1 = vt_a_v0;
1037
vt_a2_v1 = vt_a2_v0;
1038
mask1 = mask0;
1039
gerepileall(av2, 9, &x, &s0, &v0, &v1, &v2,
1040
&winv1, &winv2, &vt_a_v1, &vt_a2_v1);
1041
}
1042
if (DEBUGLEVEL >= 5)
1043
err_printf("Lanczos halted after %ld iterations\n", iter);
1044
v1 = F2w_F2Ms_transmul(x, B, nbrow);
1045
v2 = F2w_F2Ms_transmul(v0, B, nbrow);
1046
x = shallowconcat(F2w_transpose_F2m(x), F2w_transpose_F2m(v0));
1047
v1 = shallowconcat(F2w_transpose_F2m(v1), F2w_transpose_F2m(v2));
1048
s0 = gel(F2m_indexrank(x), 2);
1049
x = shallowextract(x, s0);
1050
v1 = shallowextract(v1, s0);
1051
return F2m_mul(x, F2m_ker(v1));
1052
}
1053
1054
static GEN
1055
F2v_inflate(GEN v, GEN p, long n)
1056
{
1057
long i, l = lg(p)-1;
1058
GEN w = zero_F2v(n);
1059
for (i=1; i<=l; i++)
1060
if (F2v_coeff(v,i))
1061
F2v_set(w, p[i]);
1062
return w;
1063
}
1064
1065
static GEN
1066
F2m_inflate(GEN x, GEN p, long n)
1067
{ pari_APPLY_same(F2v_inflate(gel(x,i), p, n)) }
1068
1069
GEN
1070
F2Ms_ker(GEN M, long nbrow)
1071
{
1072
pari_sp av = avma;
1073
long nbcol = lg(M)-1;
1074
GEN Mp, R, Rp, p;
1075
if (nbrow <= 640)
1076
return gerepileupto(av, F2m_ker(F2Ms_to_F2m(M, nbrow)));
1077
p = F2Ms_colelim(M, nbrow);
1078
Mp = vecpermute(M, p);
1079
do
1080
{
1081
R = block_lanczos(Mp, nbrow);
1082
} while(!R);
1083
Rp = F2m_inflate(R, p, nbcol);
1084
return gerepilecopy(av, Rp);
1085
}
1086
1087
GEN
1088
F2m_to_F2Ms(GEN M)
1089
{
1090
long ncol = lg(M)-1;
1091
GEN B = cgetg(ncol+1, t_MAT);
1092
long i, j, k;
1093
for(i = 1; i <= ncol; i++)
1094
{
1095
GEN D, V = gel(M,i);
1096
long n = F2v_hamming(V), l = V[1];
1097
D = cgetg(n+1, t_VECSMALL);
1098
for (j=1, k=1; j<=l; j++)
1099
if( F2v_coeff(V,j))
1100
D[k++] = j;
1101
gel(B, i) = D;
1102
}
1103
return B;
1104
}
1105
1106
GEN
1107
F2Ms_to_F2m(GEN M, long nrow)
1108
{
1109
long i, j, l = lg(M);
1110
GEN B = cgetg(l, t_MAT);
1111
for(i = 1; i < l; i++)
1112
{
1113
GEN Bi = zero_F2v(nrow), Mi = gel(M,i);
1114
long l = lg(Mi);
1115
for (j = 1; j < l; j++)
1116
F2v_set(Bi, Mi[j]);
1117
gel(B, i) = Bi;
1118
}
1119
return B;
1120
}
1121
1122