Dist m4ri 0.16.1
Computing distance of a classical or quantum CSS code
Loading...
Searching...
No Matches
util_m4ri.h
Go to the documentation of this file.
1#ifndef UTIL_M4RI_H
2#define UTIL_M4RI_H
3
4/************************************************************************
5 * helper functions for use with m4ri library, including binary sparse
6 * matrices and conversion utilities
7 * author: Leonid Pryadko <leonid.pryadko@ucr.edu>
8 * some code borrowed from various sources
9 ************************************************************************/
10
11#define SWAPINT(a,b) do{ int t=a; a=b; b=t; } while(0)
12
13#define ERROR(fmt,...) \
14 do{ \
15 fprintf (stderr, "%s:%d: *** ERROR in function '%s()' ***\n", __FILE__, __LINE__, __FUNCTION__); \
16 fprintf(stderr, " ␛[31;1m " fmt " ␛[0m\n",##__VA_ARGS__); \
17 exit(-1); \
18 } \
19 while(0)
20
22static inline word const * mzd_row_cons(const mzd_t * mat, const int row){
23 // return mat->rows[row] ;
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
26 return mzd_row(mat,row);
27#pragma GCC diagnostic pop
28}
29
34#ifdef __M4RI_MAX_MZD_BLOCKSIZE
35#define MZD_FIRST_ROW(M) mzd_row((M), 0)
36#else
37#define MZD_FIRST_ROW(M) ((M)->data)
38#endif
39
40
46#define SETWD(pos) ((pos)>>6)
47#define SETBT(pos) ((pos)&0x3F)
48#define TIMESWORDSIZE(w) ((w)<<6) /* w*WORDSIZE */
49
50#define FIRSTBIT(x) __builtin_ctzll(x) // number of trailing zeros
51
52// #ifdef __POPCNT__
53#if 1
54
55/*
56 * optimized code copied verbatim from https://danluu.com/assembly-intrinsics/
57 */
58/* uint32_t builtin_popcnt_unrolled_errata_manual(const uint64_t* buf, int len) { */
59/* assert(len % 4 == 0); */
60/* uint64_t cnt[4]; */
61/* for (int i = 0; i < 4; ++i) { */
62/* cnt[i] = 0; */
63/* } */
64
65/* for (int i = 0; i < len; i+=4) { */
66/* __asm__( */
67/* "popcnt %4, %4 \n\t" */
68/* "add %4, %0 \n\t" */
69/* "popcnt %5, %5 \n\t" */
70/* "add %5, %1 \n\t" */
71/* "popcnt %6, %6 \n\t" */
72/* "add %6, %2 \n\t" */
73/* "popcnt %7, %7 \n\t" */
74/* "add %7, %3 \n\t" // +r means input/output, r means intput */
75/* : "+r" (cnt[0]), "+r" (cnt[1]), "+r" (cnt[2]), "+r" (cnt[3]) */
76/* : "r" (buf[i]), "r" (buf[i+1]), "r" (buf[i+2]), "r" (buf[i+3])); */
77/* } */
78/* return cnt[0] + cnt[1] + cnt[2] + cnt[3]; */
79/* } */
80
81static inline int m4ri_bitcount(word w){
82 return __builtin_popcountll(w);
83}
84
85#else /* no __POPCNT__ */
86
87#define MASK(c) (((uint64_t)(-1)) / (__M4RI_TWOPOW(__M4RI_TWOPOW(c)) + 1))
88#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (__M4RI_TWOPOW(c))) & MASK(c))
89
90static inline int m4ri_bitcount(word w) {
91 uint64_t n = __M4RI_CONVERT_TO_UINT64_T(w);
92 n = COUNT(n, 0);
93 n = COUNT(n, 1);
94 n = COUNT(n, 2);
95 n = COUNT(n, 3);
96 n = COUNT(n, 4);
97 n = COUNT(n, 5);
98 return (int)n;
99}
100
101static inline int std_bitcount ( uint64_t x) {
102 uint64_t c1 = UINT64_C (0x5555555555555555 );
103 uint64_t c2 = UINT64_C (0x3333333333333333 );
104 uint64_t c4 = UINT64_C (0x0F0F0F0F0F0F0F0F );
105 x -= (x >> 1) & c1;
106 x = (( x >> 2) & c2) + (x & c2);
107 x = ( x + (x >> 4) ) & c4;
108 x *= UINT64_C (0x0101010101010101 );
109 return (int) (x >> 56);
110}
111
112#endif /* __POPCNT__ */
113
114
120typedef struct{ /* */
121 int rows ; /* number of rows */
122 int cols ; /* number of columns */
123 int nz ; /* # of entries in triplet matrix */
124 int nzmax ; /* # allocated size */
125 int *p ; /* row pointers (size rows+1) OR row indices */
126 int *i ; /* col indices, size nzmax */
127} csr_t ;
128
129
130typedef struct { int a; int b; } int_pair;
131
138typedef struct {
139 int rows;
140 int cols;
141 int kw;
142 word *mask;
143} colmask_t;
144
150typedef struct {
151 int m;
152 int *rmap;
153 int *rlist;
154 word *bits;
155 size_t cap;
156} cols_ws_t;
157
158#define SORT_NAME rci
159#define SORT_TYPE rci_t
160#define SORT_CMP(x, y) ((x) - (y))
161#define SORT_DEF static inline
162#include "sort.h"
163
164
165#if defined(__cplusplus) && !defined (_MSC_VER)
166extern "C" {
167#endif
168
174 size_t mzd_weight(const mzd_t *A);
175
181 size_t mzd_weight_naive(const mzd_t *A);
182
189 size_t mzd_weight_row(const mzd_t *A, rci_t i);
190
201 static inline int nextelement(const word * const set1, const int m, const int pos){
202 word setwd;
203 int w;
204 if (pos < 0){
205 w = 0;
206 setwd = set1[0];
207 }
208 else{
209 w = SETWD(pos);
210 if (w >= m) return -1;
211 setwd = set1[w] & (m4ri_ffff<< SETBT(pos));
212 }
213
214 for (;;){
215 if (setwd != 0)
216 return TIMESWORDSIZE(w) + FIRSTBIT(setwd);
217 if (++w == m)
218 return -1;
219 setwd = set1[w];
220 }
221 }
222
223
235 rci_t mzd_gauss_naive(mzd_t *M, mzp_t *q, int full);
236
242 int csr_max_row_wght(const csr_t * const p);
243
253 csr_t * csr_transpose(csr_t *dst, const csr_t * const p);
254
255
263 mzd_t *mzd_from_csr(mzd_t *dst, const csr_t *p);
264
276 mzd_t *mzd_generator_from_csr(mzd_t *G, const csr_t * const H);
277
289 mzd_t * csr_mzd_mul(mzd_t *C, const csr_t *S, const mzd_t *B, int clear);
290
302 mzd_t * syndrome_vector(mzd_t *syndrome, mzd_t *row, csr_t *spaQ, int clear);
303
304
315 size_t product_weight_csr_mzd(const csr_t *A, const mzd_t *B, int transpose);
316
322 int rand_uniform(const int max);
323
334 mzp_t * mzp_rand_len(mzp_t *q, rci_t length);
335
341 static inline mzp_t * mzp_rand(mzp_t *q){
342 if (q==NULL){
343 printf("mzp_rand: permutation must be initialized!");
344 exit(-1);
345 }
346 return mzp_rand_len(q,q->length);
347 }
348
353 void mzp_out(mzp_t const *p);
354
363 mzp_t *perm_p(mzp_t *q, const mzp_t *p,rci_t start);
364
373 mzp_t *perm_p_trans(mzp_t *q, const mzp_t *p,const rci_t start);
374
381
393 csr_t *csr_init(csr_t *mat, int rows, int cols, int nzmax);
394
403 void csr_compress(csr_t *mat);
404
415 csr_t * csr_from_pairs(csr_t *mat, const int nz, int_pair * const prs, const int nrows, const int ncols);
416
421 void csr_out(const csr_t *mat);
422
428 void csr_print(const csr_t * const smat, const char str[]);
429
438 csr_t *csr_mm_read(char *fin, csr_t *mat, int transpose);
439
448 csr_t *csr_apply_perm(csr_t *dst, const csr_t * const src, const mzp_t * const perm);
449
450
458
459static inline void mzd_flip_bit(mzd_t * const M, rci_t const row, rci_t const col ) {
460 word * const rawrow = mzd_row(M,row);
461 __M4RI_FLIP_BIT(rawrow[col/m4ri_radix], col%m4ri_radix);
462}
463
464#ifdef __M4RI_MAX_MZD_BLOCKSIZE
469int gauss_one_rows_blocks(mzd_t *M, const int idx, const int begrow, const rci_t nrows_eff);
470#endif
471
481static inline int gauss_one_rows(mzd_t *M, const int idx, const int begrow,
482 const rci_t nrows_eff) {
483 if (begrow >= nrows_eff) return 0;
484#ifdef __M4RI_MAX_MZD_BLOCKSIZE
485 /* The rows i are at mzd_row(M, 0) + i * rowstride, see MZD_FIRST_ROW(); with M4RI versions before 2024, unless the
486 * matrix spans several blocks */
487 if (__builtin_expect((uintptr_t)mzd_row(M, nrows_eff - 1) - (uintptr_t)mzd_row(M, 0) !=
488 (uintptr_t)(nrows_eff - 1) * (uintptr_t)M->rowstride * sizeof(word), 0)) {
489 return gauss_one_rows_blocks(M, idx, begrow, nrows_eff);
490 }
491#endif
492 const wi_t word_idx = idx >> 6;
493 const word bit_mask = (word)1 << (idx & 63);
494 const wi_t width = M->width;
495 const wi_t rowstride = M->rowstride;
496 word *row_j = mzd_row(M, begrow);
497 for (rci_t j = begrow; j < nrows_eff; ++j, row_j += rowstride) {
498 if (row_j[word_idx] & bit_mask) {
499 if (j != begrow) {
500 mzd_row_swap(M, begrow, j);
501 }
502 const word * const __restrict piv_row = mzd_row(M, begrow);
503 word * __restrict dst_row = MZD_FIRST_ROW(M);
504 for (rci_t ii = 0; ii < begrow; ++ii, dst_row += rowstride) {
505 if (dst_row[word_idx] & bit_mask) {
506 for (wi_t w = 0; w < width; ++w) {
507 dst_row[w] ^= piv_row[w];
508 }
509 }
510 }
511 dst_row += rowstride;
512 for (rci_t ii = begrow + 1; ii < nrows_eff; ++ii, dst_row += rowstride) {
513 if (dst_row[word_idx] & bit_mask) {
514 for (wi_t w = 0; w < width; ++w) {
515 dst_row[w] ^= piv_row[w];
516 }
517 }
518 }
519 return 1;
520 }
521 }
522 return 0;
523}
524
532static inline int gauss_one(mzd_t *M, const int idx, const int begrow) {
533 return gauss_one_rows(M, idx, begrow, M->nrows);
534}
535
546
547static inline int sparse_syndrome_non_zero(const csr_t * const H, const int cnt, const int ee[]){
548 for(int ir=0; ir < H->rows; ir++){
549 int nz=0;
550 for(int iL = H->p[ir], iE = 0; iL < H->p[ir+1]; iL++){
551 int ic = H->i[iL];
552 while((iE < cnt) && (ee[iE] < ic))
553 iE++;
554 if(iE >= cnt)
555 break;
556 if(ee[iE]==ic)
557 nz ^= 1;
558 }
559 if (nz)
560 return 1;
561 }
562 return 0;
563}
564
576static inline int colmask_syndrome_non_zero(const colmask_t * const cm, const int cnt, const int ee[]) {
577 const int kw = cm->kw;
578 const word * const mask = cm->mask;
579 if (kw == 1) {
580 word s = 0;
581 for (int i = 0; i < cnt; i++)
582 s ^= mask[ee[i]];
583 return s != 0;
584 }
585 for (int w = 0; w < kw; w++) {
586 word s = 0;
587 for (int i = 0; i < cnt; i++)
588 s ^= mask[(size_t)ee[i] * kw + w];
589 if (s)
590 return 1;
591 }
592 return 0;
593}
594
604 int csr_csr_mul_non_zero(const csr_t * const A, const csr_t * const B);
605
612 int syndrome_bit_count(const mzd_t * const row, const csr_t * const spaQ);
613
625
626 int do_reduce(mzd_t *row, const mzd_t *matP0, const rci_t rankP0);
627
633 void make_err(mzd_t *row, double p);
634
638 int do_dist_clus(const csr_t * const P, const mzd_t * const G, int debug, int wmax, int start, const int rankG);
639
646 csr_t * Lx_for_CSS_code(const csr_t * const Hx, const csr_t *const Hz);
647
657 mzd_t * mzd_nullspace(const csr_t * const H);
658
667 colmask_t * colmask_from_csr(const csr_t * const A);
668
675
681 cols_ws_t * cols_ws_init(const int m);
682
689
703 int csr_cols_rank(const csr_t * const HT, const int cnt, const int cols[], cols_ws_t * const ws);
704
718 int csr_cols_dependency(const csr_t * const HT, const int cnt, const int cols[], cols_ws_t * const ws,
719 int sub[]);
720
728 void localized_window_perm(mzp_t *perm, int nvar, int seed_col, int kwin, int win_mode,
729 const csr_t *spaH, const csr_t *mHT,
730 int *visited_cols, int *visited_checks, int *col_queue,
731 int *visit_marker, uint64_t *rng_state);
732
737 void refresh_nullspace_basis(mzd_t *N, const int *cw_arr, int cw_wt, uint64_t *rng_state);
738
748 int csr_all_ones_in_rowspan(const csr_t * const H);
749
750#if defined(__cplusplus) && !defined (_MSC_VER)
751}
752#endif
753
754#endif /* UTIL_M4RI_H */
word * mask
Definition util_m4ri.h:142
int * rmap
Definition util_m4ri.h:152
size_t cap
Definition util_m4ri.h:155
word * bits
Definition util_m4ri.h:154
int * rlist
Definition util_m4ri.h:153
int nz
Definition util_m4ri.h:123
int nzmax
Definition util_m4ri.h:124
int * p
Definition util_m4ri.h:125
int * i
Definition util_m4ri.h:126
int rows
Definition util_m4ri.h:121
int cols
Definition util_m4ri.h:122
params_t *const p
Definition util_io.c:93
mzd_t * mzd_nullspace(const csr_t *const H)
Compute the null space basis N = ker(H) of dimension nu x n.
Definition util_m4ri.c:974
cols_ws_t * cols_ws_init(const int m)
Allocate the workspace of csr_cols_rank() and csr_cols_dependency() for a matrix H with m rows.
Definition util_m4ri.c:1011
int syndrome_bit_count(const mzd_t *const row, const csr_t *const spaQ)
Compute the Hamming weight of the syndrome of a dense row vector against spaQ.
Definition util_m4ri.c:396
colmask_t * colmask_free(colmask_t *cm)
Free the column masks allocated by colmask_from_csr().
Definition util_m4ri.c:1003
cols_ws_t * cols_ws_free(cols_ws_t *ws)
Free the workspace allocated by cols_ws_init().
Definition util_m4ri.c:1022
mzp_t * mzp_rand_len(mzp_t *q, rci_t length)
Generate a random permutation of a given length in-place.
Definition util_m4ri.c:459
int do_reduce(mzd_t *row, const mzd_t *matP0, const rci_t rankP0)
Reduce a row vector against a matrix in standard form.
Definition util_m4ri.c:832
int csr_csr_mul_non_zero(const csr_t *const A, const csr_t *const B)
Check if the product of two sparse matrices A * B^T is non-zero.
Definition util_m4ri.c:342
#define FIRSTBIT(x)
Definition util_m4ri.h:50
void make_err(mzd_t *row, double p)
Generate a random binary error vector with error probability p.
Definition util_m4ri.c:870
int do_dist_clus(const csr_t *const P, const mzd_t *const G, int debug, int wmax, int start, const int rankG)
(Internal) Run cluster distance algorithm on matrices.
int csr_cols_rank(const csr_t *const HT, const int cnt, const int cols[], cols_ws_t *const ws)
Rank of a set of columns of a sparse binary matrix H.
Definition util_m4ri.c:1110
mzd_t * syndrome_vector(mzd_t *syndrome, mzd_t *row, csr_t *spaQ, int clear)
Calculate syndrome vector change.
Definition util_m4ri.c:314
size_t mzd_weight_row(const mzd_t *A, rci_t i)
Compute the Hamming weight of a specific row in a dense matrix.
Definition util_m4ri.c:55
csr_t * csr_from_pairs(csr_t *mat, const int nz, int_pair *const prs, const int nrows, const int ncols)
Construct a CSR sparse matrix from an array of coordinate pairs.
Definition util_m4ri.c:597
mzd_t * mzd_generator_from_csr(mzd_t *G, const csr_t *const H)
Construct the generator matrix from a parity check matrix in CSR form.
Definition util_m4ri.c:213
csr_t * csr_transpose(csr_t *dst, const csr_t *const p)
Transpose a compressed CSR sparse matrix.
Definition util_m4ri.c:163
csr_t * csr_mm_read(char *fin, csr_t *mat, int transpose)
Read a sparse matrix from a Matrix Market (.mtx) file into CSR format.
Definition util_m4ri.c:655
csr_t * Lx_for_CSS_code(const csr_t *const Hx, const csr_t *const Hz)
Construct the logical matrix Lx for a quantum CSS code given Hx and Hz.
Definition util_m4ri.c:934
csr_t * csr_init(csr_t *mat, int rows, int cols, int nzmax)
Initialize or reallocate a CSR sparse matrix to target size.
Definition util_m4ri.c:539
mzd_t * mzd_from_csr(mzd_t *dst, const csr_t *p)
Convert a CSR sparse matrix to an MZD dense matrix.
Definition util_m4ri.c:186
mzp_t * perm_p_trans(mzp_t *q, const mzp_t *p, const rci_t start)
Apply transposed pivot permutation p to permutation q in-place.
Definition util_m4ri.c:505
#define SETBT(pos)
Definition util_m4ri.h:47
void csr_out(const csr_t *mat)
Print raw contents of a CSR matrix to stdout.
Definition util_m4ri.c:616
void csr_print(const csr_t *const smat, const char str[])
Print a CSR matrix with a label string (formatted output).
Definition util_m4ri.c:638
csr_t * csr_free(csr_t *p)
Free memory allocated for a CSR sparse matrix.
Definition util_m4ri.c:522
#define SETWD(pos)
Definition util_m4ri.h:46
void csr_compress(csr_t *mat)
Compress CSR matrix (sort indices and remove duplicates/zeros).
Definition util_m4ri.c:574
int csr_max_row_wght(const csr_t *const p)
Get the maximum row weight of a CSR sparse matrix.
Definition util_m4ri.c:145
rci_t mzd_gauss_naive(mzd_t *M, mzp_t *q, int full)
Perform Gaussian elimination (naive) and return pivot column list.
Definition util_m4ri.c:104
void localized_window_perm(mzp_t *perm, int nvar, int seed_col, int kwin, int win_mode, const csr_t *spaH, const csr_t *mHT, int *visited_cols, int *visited_checks, int *col_queue, int *visit_marker, uint64_t *rng_state)
Construct a column permutation with a localized window at the front.
Definition util_m4ri.c:1160
void refresh_nullspace_basis(mzd_t *N, const int *cw_arr, int cw_wt, uint64_t *rng_state)
Refresh the null space basis N under a random column permutation and optionally inject a low-weight c...
Definition util_m4ri.c:1249
colmask_t * colmask_from_csr(const csr_t *const A)
Construct the column bit masks of a sparse binary matrix (see colmask_t).
Definition util_m4ri.c:985
int csr_all_ones_in_rowspan(const csr_t *const H)
Check whether the all-ones vector lies in the row span of a binary CSR matrix H over GF(2).
Definition util_m4ri.c:1312
size_t mzd_weight(const mzd_t *A)
Compute the number of set bits (Hamming weight) in a dense matrix A.
Definition util_m4ri.c:74
mzp_t * perm_p(mzp_t *q, const mzp_t *p, rci_t start)
Apply pivot permutation p to permutation q in-place starting from index.
Definition util_m4ri.c:487
void mzp_out(mzp_t const *p)
Print the permutation to stdout.
Definition util_m4ri.c:475
size_t mzd_weight_naive(const mzd_t *A)
Naive implementation to compute the Hamming weight of a dense matrix A.
Definition util_m4ri.c:46
mzd_t * csr_mzd_mul(mzd_t *C, const csr_t *S, const mzd_t *B, int clear)
Multiply a sparse matrix by a dense matrix.
Definition util_m4ri.c:257
#define TIMESWORDSIZE(w)
Definition util_m4ri.h:48
#define MZD_FIRST_ROW(M)
Definition util_m4ri.h:37
size_t product_weight_csr_mzd(const csr_t *A, const mzd_t *B, int transpose)
Compute the weight of the product of a sparse matrix and a dense matrix.
Definition util_m4ri.c:419
csr_t * csr_apply_perm(csr_t *dst, const csr_t *const src, const mzp_t *const perm)
Permute columns of a CSR sparse matrix.
Definition util_m4ri.c:798
int rand_uniform(const int max)
Return a uniformly distributed random integer in the range [0, max-1].
Definition util_m4ri.c:439
int csr_cols_dependency(const csr_t *const HT, const int cnt, const int cols[], cols_ws_t *const ws, int sub[])
A nonempty proper subset of a set of columns of H with zero sum, if there is one.
Definition util_m4ri.c:1123