Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2012-2019 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"1617#define DEBUGLEVEL DEBUGLEVEL_mat1819/***********************************************************************/20/** **/21/** F2v **/22/** **/23/***********************************************************************/24/* F2v objects are defined as follows:25An F2v is a t_VECSMALL:26v[0] = codeword27v[1] = number of components28x[2] = a_0...a_31 x[3] = a_32..a_63, etc. on 32bit29x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit3031where the a_i are bits.32*/3334int35F2v_equal0(GEN V)36{37long l = lg(V);38while (--l > 1)39if (V[l]) return 0;40return 1;41}4243GEN44F2c_to_ZC(GEN x)45{46long l = x[1]+1, lx = lg(x);47GEN z = cgetg(l, t_COL);48long i, j, k;49for (i=2, k=1; i<lx; i++)50for (j=0; j<BITS_IN_LONG && k<l; j++,k++)51gel(z,k) = (x[i]&(1UL<<j))? gen_1: gen_0;52return z;53}54GEN55F2c_to_mod(GEN x)56{57long l = x[1]+1, lx = lg(x);58GEN z = cgetg(l, t_COL);59GEN _0 = mkintmod(gen_0,gen_2);60GEN _1 = mkintmod(gen_1,gen_2);61long i, j, k;62for (i=2, k=1; i<lx; i++)63for (j=0; j<BITS_IN_LONG && k<l; j++,k++)64gel(z,k) = (x[i]&(1UL<<j))? _1: _0;65return z;66}6768/* x[a..b], a <= b */69GEN70F2v_slice(GEN x, long a, long b)71{72long i,j,k, l = b-a+1;73GEN z = cgetg(nbits2lg(l), t_VECSMALL);74z[1] = l;75for(i=a,k=1,j=BITS_IN_LONG; i<=b; i++,j++)76{77if (j==BITS_IN_LONG) { j=0; z[++k]=0; }78if (F2v_coeff(x,i)) z[k] |= 1UL<<j;79}80return z;81}82/* x[a..b,], a <= b */83GEN84F2m_rowslice(GEN x, long a, long b)85{86long i, l;87GEN y = cgetg_copy(x, &l);88for (i = 1; i < l; i++) gel(y,i) = F2v_slice(gel(x,i),a,b);89return y;90}9192GEN93F2m_to_ZM(GEN z)94{95long i, l = lg(z);96GEN x = cgetg(l,t_MAT);97for (i=1; i<l; i++) gel(x,i) = F2c_to_ZC(gel(z,i));98return x;99}100GEN101F2m_to_mod(GEN z)102{103long i, l = lg(z);104GEN x = cgetg(l,t_MAT);105for (i=1; i<l; i++) gel(x,i) = F2c_to_mod(gel(z,i));106return x;107}108109GEN110F2v_to_Flv(GEN x)111{112long l = x[1]+1, lx = lg(x);113GEN z = cgetg(l, t_VECSMALL);114long i,j,k;115for (i=2, k=1; i<lx; i++)116for (j=0; j<BITS_IN_LONG && k<l; j++,k++)117z[k] = (x[i]>>j)&1UL;118return z;119}120121GEN122F2m_to_Flm(GEN z)123{124long i, l = lg(z);125GEN x = cgetg(l,t_MAT);126for (i=1; i<l; i++) gel(x,i) = F2v_to_Flv(gel(z,i));127return x;128}129130GEN131ZV_to_F2v(GEN x)132{133long l = lg(x)-1;134GEN z = cgetg(nbits2lg(l), t_VECSMALL);135long i,j,k;136z[1] = l;137for(i=1,k=1,j=BITS_IN_LONG; i<=l; i++,j++)138{139if (j==BITS_IN_LONG) { j=0; z[++k]=0; }140if (mpodd(gel(x,i))) z[k] |= 1UL<<j;141}142return z;143}144145GEN146RgV_to_F2v(GEN x)147{148long l = lg(x)-1;149GEN z = cgetg(nbits2lg(l), t_VECSMALL);150long i,j,k;151z[1] = l;152for(i=1,k=1,j=BITS_IN_LONG; i<=l; i++,j++)153{154if (j==BITS_IN_LONG) { j=0; z[++k]=0; }155if (Rg_to_F2(gel(x,i))) z[k] |= 1UL<<j;156}157return z;158}159160GEN161Flv_to_F2v(GEN x)162{163long l = lg(x)-1;164GEN z = cgetg(nbits2lg(l), t_VECSMALL);165long i,j,k;166z[1] = l;167for(i=1,k=1,j=BITS_IN_LONG; i<=l; i++,j++)168{169if (j==BITS_IN_LONG) { j=0; z[++k]=0; }170if (x[i]&1L) z[k] |= 1UL<<j;171}172return z;173}174175GEN176ZM_to_F2m(GEN x) { pari_APPLY_same(ZV_to_F2v(gel(x,i))) }177GEN178RgM_to_F2m(GEN x) { pari_APPLY_same(RgV_to_F2v(gel(x,i))) }179GEN180Flm_to_F2m(GEN x) { pari_APPLY_same(Flv_to_F2v(gel(x,i))) }181182GEN183const_F2v(long m)184{185long i, l = nbits2lg(m);186GEN c = cgetg(l, t_VECSMALL);187c[1] = m;188for (i = 2; i < l; i++) uel(c,i) = -1UL;189if (remsBIL(m)) uel(c,l-1) = (1UL<<remsBIL(m))-1UL;190return c;191}192193/* Allow lg(y)<lg(x) */194void195F2v_add_inplace(GEN x, GEN y)196{197long n = lg(y);198long r = (n-2)&7L, q = n-r, i;199for (i = 2; i < q; i += 8)200{201x[ i] ^= y[ i]; x[1+i] ^= y[1+i]; x[2+i] ^= y[2+i]; x[3+i] ^= y[3+i];202x[4+i] ^= y[4+i]; x[5+i] ^= y[5+i]; x[6+i] ^= y[6+i]; x[7+i] ^= y[7+i];203}204switch (r)205{206case 7: x[i] ^= y[i]; i++; case 6: x[i] ^= y[i]; i++;207case 5: x[i] ^= y[i]; i++; case 4: x[i] ^= y[i]; i++;208case 3: x[i] ^= y[i]; i++; case 2: x[i] ^= y[i]; i++;209case 1: x[i] ^= y[i]; i++;210}211}212213/* Allow lg(y)<lg(x) */214void215F2v_and_inplace(GEN x, GEN y)216{217long n = lg(y);218long r = (n-2)&7L, q = n-r, i;219for (i = 2; i < q; i += 8)220{221x[ i] &= y[ i]; x[1+i] &= y[1+i]; x[2+i] &= y[2+i]; x[3+i] &= y[3+i];222x[4+i] &= y[4+i]; x[5+i] &= y[5+i]; x[6+i] &= y[6+i]; x[7+i] &= y[7+i];223}224switch (r)225{226case 7: x[i] &= y[i]; i++; case 6: x[i] &= y[i]; i++;227case 5: x[i] &= y[i]; i++; case 4: x[i] &= y[i]; i++;228case 3: x[i] &= y[i]; i++; case 2: x[i] &= y[i]; i++;229case 1: x[i] &= y[i]; i++;230}231}232233/* Allow lg(y)<lg(x) */234void235F2v_or_inplace(GEN x, GEN y)236{237long n = lg(y);238long r = (n-2)&7L, q = n-r, i;239for (i = 2; i < q; i += 8)240{241x[ i] |= y[ i]; x[1+i] |= y[1+i]; x[2+i] |= y[2+i]; x[3+i] |= y[3+i];242x[4+i] |= y[4+i]; x[5+i] |= y[5+i]; x[6+i] |= y[6+i]; x[7+i] |= y[7+i];243}244switch (r)245{246case 7: x[i] |= y[i]; i++; case 6: x[i] |= y[i]; i++;247case 5: x[i] |= y[i]; i++; case 4: x[i] |= y[i]; i++;248case 3: x[i] |= y[i]; i++; case 2: x[i] |= y[i]; i++;249case 1: x[i] |= y[i]; i++;250}251}252253/* Allow lg(y)<lg(x) */254void255F2v_negimply_inplace(GEN x, GEN y)256{257long n = lg(y);258long r = (n-2)&7L, q = n-r, i;259for (i = 2; i < q; i += 8)260{261x[ i] &= ~y[ i]; x[1+i] &= ~y[1+i]; x[2+i] &= ~y[2+i]; x[3+i] &= ~y[3+i];262x[4+i] &= ~y[4+i]; x[5+i] &= ~y[5+i]; x[6+i] &= ~y[6+i]; x[7+i] &= ~y[7+i];263}264switch (r)265{266case 7: x[i] &= ~y[i]; i++; case 6: x[i] &= ~y[i]; i++;267case 5: x[i] &= ~y[i]; i++; case 4: x[i] &= ~y[i]; i++;268case 3: x[i] &= ~y[i]; i++; case 2: x[i] &= ~y[i]; i++;269case 1: x[i] &= ~y[i]; i++;270}271}272273ulong274F2v_dotproduct(GEN x, GEN y)275{276long i, lx = lg(x);277ulong c;278if (lx <= 2) return 0;279c = uel(x,2) & uel(y,2);280for (i=3; i<lx; i++) c ^= uel(x,i) & uel(y,i);281#ifdef LONG_IS_64BIT282c ^= c >> 32;283#endif284c ^= c >> 16;285c ^= c >> 8;286c ^= c >> 4;287c ^= c >> 2;288c ^= c >> 1;289return c & 1;290}291292ulong293F2v_hamming(GEN H)294{295long i, n=0, l=lg(H);296for (i=2; i<l; i++) n += hammingl(uel(H,i));297return n;298}299300GEN301matid_F2m(long n)302{303GEN y = cgetg(n+1,t_MAT);304long i;305if (n < 0) pari_err_DOMAIN("matid_F2m", "dimension","<",gen_0,stoi(n));306for (i=1; i<=n; i++) { gel(y,i) = zero_F2v(n); F2v_set(gel(y,i),i); }307return y;308}309310GEN311F2m_row(GEN x, long j)312{313long i, l = lg(x);314GEN V = zero_F2v(l-1);315for(i = 1; i < l; i++)316if (F2m_coeff(x,j,i))317F2v_set(V,i);318return V;319}320321GEN322F2m_transpose(GEN x)323{324long i, dx, lx = lg(x);325GEN y;326if (lx == 1) return cgetg(1,t_MAT);327dx = coeff(x,1,1); y = cgetg(dx+1,t_MAT);328for (i=1; i<=dx; i++) gel(y,i) = F2m_row(x,i);329return y;330}331332INLINE GEN333F2m_F2c_mul_i(GEN x, GEN y, long lx, long l)334{335long j;336GEN z = NULL;337338for (j=1; j<lx; j++)339{340if (!F2v_coeff(y,j)) continue;341if (!z) z = vecsmall_copy(gel(x,j));342else F2v_add_inplace(z,gel(x,j));343}344if (!z) z = zero_F2v(l);345return z;346}347348GEN349F2m_mul(GEN x, GEN y)350{351long i,j,l,lx=lg(x), ly=lg(y);352GEN z;353if (ly==1) return cgetg(1,t_MAT);354z = cgetg(ly,t_MAT);355if (lx==1)356{357for (i=1; i<ly; i++) gel(z,i) = mkvecsmall(0);358return z;359}360l = coeff(x,1,1);361for (j=1; j<ly; j++) gel(z,j) = F2m_F2c_mul_i(x, gel(y,j), lx, l);362return z;363}364365GEN366F2m_F2c_mul(GEN x, GEN y)367{368long l, lx = lg(x);369if (lx==1) return cgetg(1,t_VECSMALL);370l = coeff(x,1,1);371return F2m_F2c_mul_i(x, y, lx, l);372}373374static GEN375_F2m_mul(void *data, GEN x, GEN y) { (void) data; return F2m_mul(x,y); }376static GEN377_F2m_sqr(void *data, GEN x) { (void) data; return F2m_mul(x,x); }378GEN379F2m_powu(GEN x, ulong n)380{381if (!n) return matid(lg(x)-1);382return gen_powu(x, n,NULL, &_F2m_sqr, &_F2m_mul);383}384385static long386F2v_find_nonzero(GEN x0, GEN mask0, long m)387{388ulong *x = (ulong *)x0+2, *mask = (ulong *)mask0+2, e;389long i, l = lg(x0)-2;390for (i = 0; i < l; i++)391{392e = *x++ & *mask++;393if (e) return i*BITS_IN_LONG+vals(e)+1;394}395return m+1;396}397398/* in place, destroy x */399GEN400F2m_ker_sp(GEN x, long deplin)401{402GEN y, c, d;403long i, j, k, r, m, n;404405n = lg(x)-1;406m = mael(x,1,1); r=0;407408d = cgetg(n+1, t_VECSMALL);409c = const_F2v(m);410for (k=1; k<=n; k++)411{412GEN xk = gel(x,k);413j = F2v_find_nonzero(xk, c, m);414if (j>m)415{416if (deplin) {417GEN c = zero_F2v(n);418for (i=1; i<k; i++)419if (F2v_coeff(xk, d[i]))420F2v_set(c, i);421F2v_set(c, k);422return c;423}424r++; d[k] = 0;425}426else427{428F2v_clear(c,j); d[k] = j;429F2v_clear(xk, j);430for (i=k+1; i<=n; i++)431{432GEN xi = gel(x,i);433if (F2v_coeff(xi,j)) F2v_add_inplace(xi, xk);434}435F2v_set(xk, j);436}437}438if (deplin) return NULL;439440y = zero_F2m_copy(n,r);441for (j=k=1; j<=r; j++,k++)442{443GEN C = gel(y,j); while (d[k]) k++;444for (i=1; i<k; i++)445if (d[i] && F2m_coeff(x,d[i],k))446F2v_set(C,i);447F2v_set(C, k);448}449return y;450}451452/* not memory clean */453GEN454F2m_ker(GEN x) { return F2m_ker_sp(F2m_copy(x), 0); }455GEN456F2m_deplin(GEN x) { return F2m_ker_sp(F2m_copy(x), 1); }457458ulong459F2m_det_sp(GEN x) { return !F2m_ker_sp(x, 1); }460461ulong462F2m_det(GEN x)463{464pari_sp av = avma;465ulong d = F2m_det_sp(F2m_copy(x));466return gc_ulong(av, d);467}468469/* Destroy x */470GEN471F2m_gauss_pivot(GEN x, long *rr)472{473GEN c, d;474long i, j, k, r, m, n;475476n = lg(x)-1; if (!n) { *rr=0; return NULL; }477m = mael(x,1,1); r=0;478479d = cgetg(n+1, t_VECSMALL);480c = const_F2v(m);481for (k=1; k<=n; k++)482{483GEN xk = gel(x,k);484j = F2v_find_nonzero(xk, c, m);485if (j>m) { r++; d[k] = 0; }486else487{488F2v_clear(c,j); d[k] = j;489for (i=k+1; i<=n; i++)490{491GEN xi = gel(x,i);492if (F2v_coeff(xi,j)) F2v_add_inplace(xi, xk);493}494}495}496497*rr = r; return gc_const((pari_sp)d, d);498}499500long501F2m_rank(GEN x)502{503pari_sp av = avma;504long r;505(void)F2m_gauss_pivot(F2m_copy(x),&r);506return gc_long(av, lg(x)-1 - r);507}508509static GEN510F2m_inv_upper_1_ind(GEN A, long index)511{512pari_sp av = avma;513long n = lg(A)-1, i = index, j;514GEN u = const_vecsmall(n, 0);515u[i] = 1;516for (i--; i>0; i--)517{518ulong m = F2m_coeff(A,i,i+1) & uel(u,i+1); /* j = i+1 */519for (j=i+2; j<=n; j++) m ^= F2m_coeff(A,i,j) & uel(u,j);520u[i] = m & 1;521}522return gerepileuptoleaf(av, Flv_to_F2v(u));523}524static GEN525F2m_inv_upper_1(GEN A)526{527long i, l;528GEN B = cgetg_copy(A, &l);529for (i = 1; i < l; i++) gel(B,i) = F2m_inv_upper_1_ind(A, i);530return B;531}532533static GEN534F2_get_col(GEN b, GEN d, long li, long aco)535{536long i, l = nbits2lg(aco);537GEN u = cgetg(l, t_VECSMALL);538u[1] = aco;539for (i = 1; i <= li; i++)540if (d[i]) /* d[i] can still be 0 if li > aco */541{542if (F2v_coeff(b, i))543F2v_set(u, d[i]);544else545F2v_clear(u, d[i]);546}547return u;548}549550/* destroy a, b */551GEN552F2m_gauss_sp(GEN a, GEN b)553{554long i, j, k, l, li, bco, aco = lg(a)-1;555GEN u, d;556557if (!aco) return cgetg(1,t_MAT);558li = gel(a,1)[1];559d = zero_Flv(li);560bco = lg(b)-1;561for (i=1; i<=aco; i++)562{563GEN ai = vecsmall_copy(gel(a,i));564if (!d[i] && F2v_coeff(ai, i))565k = i;566else567for (k = 1; k <= li; k++) if (!d[k] && F2v_coeff(ai,k)) break;568/* found a pivot on row k */569if (k > li) return NULL;570d[k] = i;571572/* Clear k-th row but column-wise instead of line-wise */573/* a_ij -= a_i1*a1j/a_11574line-wise grouping: L_j -= a_1j/a_11*L_1575column-wise: C_i -= a_i1/a_11*C_1576*/577F2v_clear(ai,k);578for (l=1; l<=aco; l++)579{580GEN al = gel(a,l);581if (F2v_coeff(al,k)) F2v_add_inplace(al,ai);582}583for (l=1; l<=bco; l++)584{585GEN bl = gel(b,l);586if (F2v_coeff(bl,k)) F2v_add_inplace(bl,ai);587}588}589u = cgetg(bco+1,t_MAT);590for (j = 1; j <= bco; j++) gel(u,j) = F2_get_col(gel(b,j), d, li, aco);591return u;592}593594GEN595F2m_gauss(GEN a, GEN b)596{597pari_sp av = avma;598if (lg(a) == 1) return cgetg(1,t_MAT);599return gerepileupto(av, F2m_gauss_sp(F2m_copy(a), F2m_copy(b)));600}601GEN602F2m_F2c_gauss(GEN a, GEN b)603{604pari_sp av = avma;605GEN z = F2m_gauss(a, mkmat(b));606if (!z) return gc_NULL(av);607if (lg(z) == 1) { set_avma(av); return cgetg(1,t_VECSMALL); }608return gerepileuptoleaf(av, gel(z,1));609}610611GEN612F2m_inv(GEN a)613{614pari_sp av = avma;615if (lg(a) == 1) return cgetg(1,t_MAT);616return gerepileupto(av, F2m_gauss_sp(F2m_copy(a), matid_F2m(gel(a,1)[1])));617}618619GEN620F2m_invimage_i(GEN A, GEN B)621{622GEN d, x, X, Y;623long i, j, nY, nA = lg(A)-1, nB = lg(B)-1;624x = F2m_ker_sp(shallowconcat(A, B), 0);625/* AX = BY, Y in strict upper echelon form with pivots = 1.626* We must find T such that Y T = Id_nB then X T = Z. This exists iff627* Y has at least nB columns and full rank */628nY = lg(x)-1;629if (nY < nB) return NULL;630631/* implicitly: Y = rowslice(x, nA+1, nA+nB), nB rows */632d = cgetg(nB+1, t_VECSMALL);633for (i = nB, j = nY; i >= 1; i--, j--)634{635for (; j>=1; j--)636if (F2m_coeff(x,nA+i,j)) { d[i] = j; break; } /* Y[i,j] */637if (!j) return NULL;638}639x = vecpermute(x, d);640641X = F2m_rowslice(x, 1, nA);642Y = F2m_rowslice(x, nA+1, nA+nB);643return F2m_mul(X, F2m_inv_upper_1(Y));644}645GEN646F2m_invimage(GEN A, GEN B)647{648pari_sp av = avma;649GEN X = F2m_invimage_i(A,B);650if (!X) return gc_NULL(av);651return gerepileupto(av, X);652}653654GEN655F2m_F2c_invimage(GEN A, GEN y)656{657pari_sp av = avma;658long i, l = lg(A);659GEN M, x;660661if (l==1) return NULL;662if (lg(y) != lgcols(A)) pari_err_DIM("F2m_F2c_invimage");663M = cgetg(l+1,t_MAT);664for (i=1; i<l; i++) gel(M,i) = gel(A,i);665gel(M,l) = y; M = F2m_ker(M);666i = lg(M)-1; if (!i) return gc_NULL(av);667668x = gel(M,i);669if (!F2v_coeff(x,l)) return gc_NULL(av);670F2v_clear(x, x[1]); x[1]--; /* remove last coord */671return gerepileuptoleaf(av, x);672}673674/* Block Lanczos algorithm for kernel of sparse matrix (F2Ms)675Based on lanczos.cpp by Jason Papadopoulos676<https://github.com/sagemath/FlintQS/blob/master/src/lanczos.cpp>677Copyright Jason Papadopoulos 2006678Released under the GNU General Public License v2 or later version.679*/680681/* F2Ms are vector of vecsmall which represents nonzero entries of columns682* F2w are vecsmall whoses entries are columns of a n x BIL F2m683* F2wB are F2w in the special case where dim = BIL.684*/685686#define BIL BITS_IN_LONG687688static GEN689F2w_transpose_F2m(GEN x)690{691long i, j, l = lg(x)-1;692GEN z = cgetg(BIL+1, t_MAT);693for (j = 1; j <= BIL; j++)694gel(z,j) = zero_F2v(l);695for (i = 1; i <= l; i++)696{697ulong xi = uel(x,i);698for(j = 1; j <= BIL; j++)699if (xi&(1UL<<(j-1)))700F2v_set(gel(z, j), i);701}702return z;703}704705static GEN706F2wB_mul(GEN a, GEN b)707{708long i, j;709GEN c = cgetg(BIL+1, t_VECSMALL);710for (i = 1; i <= BIL; i++)711{712ulong s = 0, ai = a[i];713for (j = 1; ai; j++, ai>>=1)714if (ai & 1)715s ^= b[j];716c[i] = s;717}718return c;719}720721static void722precompute_F2w_F2wB(GEN x, GEN c)723{724ulong z, xk;725ulong i, j, k, index;726x++; c++;727for (j = 0; j < (BIL>>3); j++)728{729for (i = 0; i < 256; i++)730{731k = 0;732index = i;733z = 0;734while (index) {735xk = x[k];736if (index & 1)737z ^= xk;738index >>= 1;739k++;740}741c[i] = z;742}743x += 8; c += 256;744}745}746747static void748F2w_F2wB_mul_add_inplace(GEN v, GEN x, GEN y)749{750long i, n = lg(y)-1;751ulong word;752GEN c = cgetg(1+(BIL<<5), t_VECSMALL);753precompute_F2w_F2wB(x, c);754c++;755for (i = 1; i <= n; i++)756{757word = v[i];758y[i] ^= c[ 0*256 + ((word>> 0) & 0xff) ]759^ c[ 1*256 + ((word>> 8) & 0xff) ]760^ c[ 2*256 + ((word>>16) & 0xff) ]761^ c[ 3*256 + ((word>>24) & 0xff) ]762#ifdef LONG_IS_64BIT763^ c[ 4*256 + ((word>>32) & 0xff) ]764^ c[ 5*256 + ((word>>40) & 0xff) ]765^ c[ 6*256 + ((word>>48) & 0xff) ]766^ c[ 7*256 + ((word>>56) ) ]767#endif768;769}770}771772/* Return x*y~, which is a F2wB */773static GEN774F2w_transmul(GEN x, GEN y)775{776long i, j, n = lg(x)-1;777GEN z = zero_zv(BIL);778pari_sp av = avma;779GEN c = zero_zv(BIL<<5) + 1;780GEN xy = z + 1;781782for (i = 1; i <= n; i++)783{784ulong xi = x[i];785ulong yi = y[i];786c[ 0*256 + ( xi & 0xff) ] ^= yi;787c[ 1*256 + ((xi >> 8) & 0xff) ] ^= yi;788c[ 2*256 + ((xi >> 16) & 0xff) ] ^= yi;789c[ 3*256 + ((xi >> 24) & 0xff) ] ^= yi;790#ifdef LONG_IS_64BIT791c[ 4*256 + ((xi >> 32) & 0xff) ] ^= yi;792c[ 5*256 + ((xi >> 40) & 0xff) ] ^= yi;793c[ 6*256 + ((xi >> 48) & 0xff) ] ^= yi;794c[ 7*256 + ((xi >> 56) ) ] ^= yi;795#endif796}797for(i = 0; i < 8; i++)798{799ulong a0 = 0, a1 = 0, a2 = 0, a3 = 0;800#ifdef LONG_IS_64BIT801ulong a4 = 0, a5 = 0, a6 = 0, a7 = 0;802#endif803for (j = 0; j < 256; j++) {804if ((j >> i) & 1) {805a0 ^= c[0*256 + j];806a1 ^= c[1*256 + j];807a2 ^= c[2*256 + j];808a3 ^= c[3*256 + j];809#ifdef LONG_IS_64BIT810a4 ^= c[4*256 + j];811a5 ^= c[5*256 + j];812a6 ^= c[6*256 + j];813a7 ^= c[7*256 + j];814#endif815}816}817xy[ 0] = a0; xy[ 8] = a1; xy[16] = a2; xy[24] = a3;818#ifdef LONG_IS_64BIT819xy[32] = a4; xy[40] = a5; xy[48] = a6; xy[56] = a7;820#endif821xy++;822}823return gc_const(av, z);824}825826static GEN827identity_F2wB(void)828{829long i;830GEN M = cgetg(BIL+1, t_VECSMALL);831for (i = 1; i <= BIL; i++)832uel(M,i) = 1UL<<(i-1);833return M;834}835836static GEN837find_nonsingular_sub(GEN t, GEN last_s, GEN *pt_s)838{839long i, j, dim = 0;840ulong mask, row_i, row_j;841long last_dim = lg(last_s)-1;842GEN s = cgetg(BIL+1, t_VECSMALL);843GEN M1 = identity_F2wB();844pari_sp av = avma;845GEN cols = cgetg(BIL+1, t_VECSMALL);846GEN M0 = zv_copy(t);847848mask = 0;849for (i = 1; i <= last_dim; i++)850{851cols[BIL + 1 - i] = last_s[i];852mask |= 1UL<<(last_s[i]-1);853}854for (i = j = 1; i <= BIL; i++)855if (!(mask & (1UL<<(i-1))))856cols[j++] = i;857858/* compute the inverse of t[][] */859860for (i = 1; i <= BIL; i++)861{862mask = 1UL<<(cols[i]-1);863row_i = cols[i];864for (j = i; j <= BIL; j++)865{866row_j = cols[j];867if (uel(M0,row_j) & mask)868{869swap(gel(M0, row_j), gel(M0, row_i));870swap(gel(M1, row_j), gel(M1, row_i));871break;872}873}874if (j <= BIL)875{876for (j = 1; j <= BIL; j++)877{878row_j = cols[j];879if (row_i != row_j && (M0[row_j] & mask))880{881uel(M0,row_j) ^= uel(M0,row_i);882uel(M1,row_j) ^= uel(M1,row_i);883}884}885s[++dim] = cols[i];886continue;887}888for (j = i; j <= BIL; j++)889{890row_j = cols[j];891if (uel(M1,row_j) & mask)892{893swap(gel(M0, row_j), gel(M0, row_i));894swap(gel(M1, row_j), gel(M1, row_i));895break;896}897}898if (j > BIL) return NULL;899for (j = 1; j <= BIL; j++)900{901row_j = cols[j];902if (row_i != row_j && (M1[row_j] & mask))903{904uel(M0,row_j) ^= uel(M0,row_i);905uel(M1,row_j) ^= uel(M1,row_i);906}907}908M0[row_i] = M1[row_i] = 0;909}910mask = 0;911for (i = 1; i <= dim; i++)912mask |= 1UL<<(s[i]-1);913for (i = 1; i <= last_dim; i++)914mask |= 1UL<<(last_s[i]-1);915if (mask != (ulong)(-1))916return NULL; /* Failure */917setlg(s, dim+1);918set_avma(av);919*pt_s = s;920return M1;921}922923/* Compute x * A~ */924static GEN925F2w_F2Ms_transmul(GEN x, GEN A, long nbrow)926{927long i, j, l = lg(A);928GEN b = zero_zv(nbrow);929for (i = 1; i < l; i++)930{931GEN c = gel(A,i);932long lc = lg(c);933ulong xi = x[i];934for (j = 1; j < lc; j++)935b[c[j]] ^= xi;936}937return b;938}939940/* Compute x * A */941static GEN942F2w_F2Ms_mul(GEN x, GEN A)943{944long i, j, l = lg(A);945GEN b = cgetg(l, t_VECSMALL);946for (i = 1; i < l; i++)947{948GEN c = gel(A,i);949long lc = lg(c);950ulong s = 0;951for (j = 1; j < lc; j++)952s ^= x[c[j]];953b[i] = s;954}955return b;956}957958static void959F2wB_addid_inplace(GEN f)960{961long i;962for (i = 1; i <= BIL; i++)963uel(f,i) ^= 1UL<<(i-1);964}965966static void967F2w_mask_inplace(GEN f, ulong m)968{969long i, l = lg(f);970for (i = 1; i < l; i++)971uel(f,i) &= m;972}973974static GEN975block_lanczos(GEN B, ulong nbrow)976{977pari_sp av = avma, av2;978GEN v0, v1, v2, vnext, x, w;979GEN winv0, winv1, winv2;980GEN vt_a_v0, vt_a_v1, vt_a2_v0, vt_a2_v1;981GEN d, e, f, f2, s0;982long i, iter;983long n = lg(B)-1;984long dim0;985ulong mask0, mask1;986v1 = zero_zv(n);987v2 = zero_zv(n);988vt_a_v1 = zero_zv(BIL);989vt_a2_v1 = zero_zv(BIL);990winv1 = zero_zv(BIL);991winv2 = zero_zv(BIL);992s0 = identity_zv(BIL);993mask1 = (ulong)(-1);994995x = random_zv(n);996w = F2w_F2Ms_mul(F2w_F2Ms_transmul(x, B, nbrow), B);997v0 = w;998av2 = avma;999for (iter=1;;iter++)1000{1001vnext = F2w_F2Ms_mul(F2w_F2Ms_transmul(v0, B, nbrow), B);1002vt_a_v0 = F2w_transmul(v0, vnext);1003if (zv_equal0(vt_a_v0)) break; /* success */1004vt_a2_v0 = F2w_transmul(vnext, vnext);1005winv0 = find_nonsingular_sub(vt_a_v0, s0, &s0);1006if (!winv0) return gc_NULL(av); /* failure */1007dim0 = lg(s0)-1;1008mask0 = 0;1009for (i = 1; i <= dim0; i++)1010mask0 |= 1UL<<(s0[i]-1);1011d = cgetg(BIL+1, t_VECSMALL);1012for (i = 1; i <= BIL; i++)1013d[i] = (vt_a2_v0[i] & mask0) ^ vt_a_v0[i];10141015d = F2wB_mul(winv0, d);1016F2wB_addid_inplace(d);1017e = F2wB_mul(winv1, vt_a_v0);1018F2w_mask_inplace(e, mask0);1019f = F2wB_mul(vt_a_v1, winv1);1020F2wB_addid_inplace(f);1021f = F2wB_mul(winv2, f);1022f2 = cgetg(BIL+1, t_VECSMALL);1023for (i = 1; i <= BIL; i++)1024f2[i] = ((vt_a2_v1[i] & mask1) ^ vt_a_v1[i]) & mask0;10251026f = F2wB_mul(f, f2);1027F2w_mask_inplace(vnext, mask0);1028F2w_F2wB_mul_add_inplace(v0, d, vnext);1029F2w_F2wB_mul_add_inplace(v1, e, vnext);1030F2w_F2wB_mul_add_inplace(v2, f, vnext);1031d = F2wB_mul(winv0, F2w_transmul(v0, w));1032F2w_F2wB_mul_add_inplace(v0, d, x);1033v2 = v1; v1 = v0; v0 = vnext;1034winv2 = winv1; winv1 = winv0;1035vt_a_v1 = vt_a_v0;1036vt_a2_v1 = vt_a2_v0;1037mask1 = mask0;1038gerepileall(av2, 9, &x, &s0, &v0, &v1, &v2,1039&winv1, &winv2, &vt_a_v1, &vt_a2_v1);1040}1041if (DEBUGLEVEL >= 5)1042err_printf("Lanczos halted after %ld iterations\n", iter);1043v1 = F2w_F2Ms_transmul(x, B, nbrow);1044v2 = F2w_F2Ms_transmul(v0, B, nbrow);1045x = shallowconcat(F2w_transpose_F2m(x), F2w_transpose_F2m(v0));1046v1 = shallowconcat(F2w_transpose_F2m(v1), F2w_transpose_F2m(v2));1047s0 = gel(F2m_indexrank(x), 2);1048x = shallowextract(x, s0);1049v1 = shallowextract(v1, s0);1050return F2m_mul(x, F2m_ker(v1));1051}10521053static GEN1054F2v_inflate(GEN v, GEN p, long n)1055{1056long i, l = lg(p)-1;1057GEN w = zero_F2v(n);1058for (i=1; i<=l; i++)1059if (F2v_coeff(v,i))1060F2v_set(w, p[i]);1061return w;1062}10631064static GEN1065F2m_inflate(GEN x, GEN p, long n)1066{ pari_APPLY_same(F2v_inflate(gel(x,i), p, n)) }10671068GEN1069F2Ms_ker(GEN M, long nbrow)1070{1071pari_sp av = avma;1072long nbcol = lg(M)-1;1073GEN Mp, R, Rp, p;1074if (nbrow <= 640)1075return gerepileupto(av, F2m_ker(F2Ms_to_F2m(M, nbrow)));1076p = F2Ms_colelim(M, nbrow);1077Mp = vecpermute(M, p);1078do1079{1080R = block_lanczos(Mp, nbrow);1081} while(!R);1082Rp = F2m_inflate(R, p, nbcol);1083return gerepilecopy(av, Rp);1084}10851086GEN1087F2m_to_F2Ms(GEN M)1088{1089long ncol = lg(M)-1;1090GEN B = cgetg(ncol+1, t_MAT);1091long i, j, k;1092for(i = 1; i <= ncol; i++)1093{1094GEN D, V = gel(M,i);1095long n = F2v_hamming(V), l = V[1];1096D = cgetg(n+1, t_VECSMALL);1097for (j=1, k=1; j<=l; j++)1098if( F2v_coeff(V,j))1099D[k++] = j;1100gel(B, i) = D;1101}1102return B;1103}11041105GEN1106F2Ms_to_F2m(GEN M, long nrow)1107{1108long i, j, l = lg(M);1109GEN B = cgetg(l, t_MAT);1110for(i = 1; i < l; i++)1111{1112GEN Bi = zero_F2v(nrow), Mi = gel(M,i);1113long l = lg(Mi);1114for (j = 1; j < l; j++)1115F2v_set(Bi, Mi[j]);1116gel(B, i) = Bi;1117}1118return B;1119}112011211122