Dist m4ri 0.16.1
Computing distance of a classical or quantum CSS code
Loading...
Searching...
No Matches
dist_rw.c
Go to the documentation of this file.
1
17// #include <m4ri/config.h>
18#include <inttypes.h>
19#include <strings.h>
20#include <stdlib.h>
21#include <time.h>
22#include <m4ri/m4ri.h>
23
24#include "mmio.h"
25#include "util_m4ri.h"
26#include "util_io.h"
27#include "dist_m4ri.h"
28
29
38int do_RW_dist(params_t * const p){
39 const csr_t * const spaH0 = p->spaH;
40 const csr_t * const spaL0 = p->spaL;
41 const int steps = p->steps;
42 const int wmin = p->wmin;
43 const int wmax = p->wmax;
44 const int classical = p->classical;
45 const int debug = p->debug;
47 const int nvar = spaH0->cols;
48 if(((!classical)&&(spaL0==NULL)) ||
49 ((classical)&&(spaL0!=NULL))){
50 printf("L0 %s NULL classical=%d\n",spaL0==NULL ? "=" : "!=", classical);
51 ERROR("L0 should be non-NULL only for classical code!\n");
52 }
53
54 int minW = nvar + 1;
55 if (p->dmax > 0 && p->dmax < minW) {
56 minW = p->dmax;
57 }
58 if (p->min_w != INT_MAX && p->min_w < minW) {
59 minW = p->min_w;
60 }
61
62 if (debug & DBG_PROGRESS)
63 printf("# running do_RW_dist() with steps=%d wmin=%d wmax=%d classical=%d nvar=%d\n",
64 steps, wmin, wmax, classical, nvar);
65
66 mzd_t * mH = mzd_from_csr(NULL, spaH0);
67 mzd_t *mHT = NULL;
69 rci_t *ee = malloc(nvar*sizeof(rci_t));
70
71 if((!mH) || (!ee))
72 ERROR("memory allocation failed!\n");
73
75 mzp_t * perm=mzp_init(nvar);
76 mzp_t * pivs=mzp_init(nvar);
77 word * piv_mask=calloc(mH->width, sizeof(word));
78 if((!pivs) || (!perm) || (!piv_mask))
79 ERROR("memory allocation failed!\n");
80 int eff_nrows = spaH0->rows;
81
82 mzd_t *N_ker = NULL;
83 mzd_t *M_sub = NULL;
84 int nu = 0;
85 int ksub_eff = 0;
86 if (p->ksub > 0) {
87 if (2 * spaH0->rows < nvar) {
88 if (debug & DBG_SUMMARY) {
89 fprintf(stderr,
90 "# Warning: ksub=%d requested, but m=%d < n-m=%d (<= nu); "
91 "falling back to full-matrix RW (ksub=0)\n",
92 p->ksub, spaH0->rows, nvar - spaH0->rows);
93 }
94 p->ksub = 0;
95 } else {
96 N_ker = mzd_nullspace(spaH0);
97 nu = N_ker ? N_ker->nrows : 0;
98 if (spaH0->rows < nu || nu <= 0) {
99 if (debug & DBG_SUMMARY) {
100 fprintf(stderr,
101 "# Warning: ksub=%d requested, but m=%d < nu=%d; "
102 "falling back to full-matrix RW (ksub=0)\n",
103 p->ksub, spaH0->rows, nu);
104 }
105 if (N_ker) {
106 mzd_free(N_ker);
107 N_ker = NULL;
108 }
109 nu = 0;
110 p->ksub = 0;
111 } else {
112 ksub_eff = minint(p->ksub, nu);
113 if (ksub_eff > 0) {
114 M_sub = mzd_init(ksub_eff, nvar);
115 }
116 }
117 }
118 }
119
120 csr_t *mHT_csr = NULL;
121 int *visited_cols = NULL;
122 int *visited_checks = NULL;
123 int *col_queue = NULL;
124 int visit_marker = 0;
125 uint64_t rng_state = (uint64_t)p->seed + 0x517cc1b727220a95ULL;
126 if ((p->kwin > 0 && p->kwin < nvar) || nvar >= 500) {
127 mHT_csr = csr_transpose(NULL, spaH0);
128 visited_cols = calloc(nvar, sizeof(int));
129 visited_checks = calloc(spaH0->rows, sizeof(int));
130 col_queue = calloc(nvar, sizeof(int));
131 }
132
133 for (int ii=0; ii< steps; ii++){
134 int eff_kwin = p->kwin;
135 int eff_win_mode = p->win_mode;
136 if (eff_kwin == 0 && nvar >= 500 && (ii & 1) == 1) {
137 eff_kwin = rw_hybrid_window(p, nvar);
138 eff_win_mode = 1;
139 }
140 /* the source of the codewords found in this step, see codeword_add_maybe() */
141 const int src = (eff_kwin > 0 && eff_kwin < nvar) ? CW_SRC_RW_WINDOW : CW_SRC_RW_UNIFORM;
142 if (eff_kwin > 0 && eff_kwin < nvar) {
143 int seed_col = rand_uniform(nvar);
144 localized_window_perm(perm, nvar, seed_col, eff_kwin, eff_win_mode,
145 spaH0, mHT_csr, visited_cols, visited_checks,
146 col_queue, &visit_marker, &rng_state);
147 } else {
148 pivs=mzp_rand(pivs);
149 mzp_set_ui(perm,1);
150 perm=perm_p_trans(perm,pivs,0);
151 }
152
153 if (p->ksub > 0) {
154 if (ksub_eff <= 0) break;
155 for (int i = 0; i < ksub_eff; i++) {
156 int r = rand_uniform(nu);
157 mzd_copy_row(M_sub, i, N_ker, r);
158 }
159 int rank = 0;
160 for (int i = 0; i < nvar && rank < ksub_eff; i++) {
161 int col = perm->values[i];
162 if (gauss_one(M_sub, col, rank)) {
163 rank++;
164 }
165 }
166 for (int ir = 0; ir < rank; ir++) {
167 int cnt = 0;
168 const int cur_d = (minW <= nvar) ? minW : 0;
169 const int limit = codeword_rw_limit(p, cur_d, codeword_feed_limit(p));
170 word *rawrow = mzd_row(M_sub, ir);
171 rci_t j = -1;
172 while (cnt < limit) {
173 j = nextelement(rawrow, M_sub->width, j);
174 if (j == -1 || j >= nvar) break;
175 ee[cnt++] = j++;
176 }
177 if (cnt > 0 && cnt < limit) {
178 int nz = classical ? 1 : sparse_syndrome_non_zero(spaL0, cnt, ee);
179 if (nz) {
180 p->codewords = codeword_add_maybe(p, ee, cnt, src);
181 if (cnt < minW) minW = cnt;
182 if (codeword_maxc_reached(p)) goto alldone;
183 if (check_min_hits_convergence(p)) goto alldone;
184 if (minW <= wmin) {
185 minW = -minW;
186 goto alldone;
187 }
188 }
189 }
190 }
191 if (p->refresh > 0 && (ii + 1) % p->refresh == 0) {
192 int cw_wt = 0;
193 if (p->codewords && p->min_w < nvar) {
194 cw_vec_t *cw, *tmp;
195 HASH_ITER(hh, p->codewords, cw, tmp) {
196 if (cw->weight == p->min_w) {
197 cw_wt = cw->weight;
198 for (int k = 0; k < cw_wt; k++) ee[k] = cw->arr[k];
199 break;
200 }
201 }
202 }
203 refresh_nullspace_basis(N_ker, cw_wt > 0 ? ee : NULL, cw_wt, &rng_state);
204 }
205 continue;
206 }
207
209 memset(piv_mask, 0, mH->width * sizeof(word));
210 int rank = 0;
211 for (int i = 0; i < nvar && rank < eff_nrows; i++) {
212 int col = perm->values[i];
213 if (gauss_one_rows(mH, col, rank, eff_nrows)) {
214 pivs->values[rank++] = col;
215 piv_mask[col >> 6] |= (word)1 << (col & 63);
216 }
217 }
218 eff_nrows = rank;
219
220#ifndef NEW
221# define NEW 1
222#endif
223#if (NEW==1)
225 mHT = mzd_transpose(mHT,mH);
226#endif
233 for (int col = 0, ir = 0; col < nvar; col++){
234 if ((piv_mask[col >> 6] >> (col & 63)) & 1) continue;
235 ir++;
236 int cnt=0;
237 ee[cnt++] = col;
238 const int cur_d = (minW <= nvar) ? minW : 0;
240 const int limit = codeword_rw_limit(p, cur_d, codeword_feed_limit(p));
241#if (NEW==0)
242 for(int ix=0; ix<rank; ix++){
243 if(mzd_read_bit(mH,ix,col))
244 ee[cnt++] = pivs->values[ix];
245 if (cnt >= limit)
246 break;
247 }
248#elif (NEW==2)
254 rci_t ic=col, ix=0;
255 while (ix < rank){
256 int res = mzd_find_pivot(mH, ix, col, &ix, &ic);
257 if((res)&&(ic==col)){
258 ee[cnt++] = pivs->values[ix++];
259 // printf("cnt=%d j=%d\n",cnt,ix);
260 if (cnt >= limit)
261 break;
262 }
263 else
264 break;
265 }
266#else
267 word * rawrow = mzd_row(mHT,col);
268 rci_t j=-1;
269 const int active_width = (rank + 63) >> 6;
270 while(cnt < limit){
271 j=nextelement(rawrow,active_width,j);
272 if(j==-1 || j >= rank) // empty line after simplification
273 break;
274 ee[cnt++] = pivs->values[j++];
275 }
276#endif /* NEW */
277 if (cnt < limit){
279 rci_quick_sort(ee, cnt);
280#ifndef NDEBUG
282 if(sparse_syndrome_non_zero(spaH0, cnt, ee)){
283 printf("# cw of weight %d: [",cnt);
284 for(int i=0; i<cnt;i++)
285 printf("%d%s",ee[i],i+1==cnt?" ":"]\n");
286 ERROR("this should not happen: cw not orthogonal to H");
287 }
288#endif /* NDEBUG */
289
291 int nz;
292 if (classical)
293 nz=1;
294 else
295 nz = sparse_syndrome_non_zero(spaL0, cnt, ee);
296 if(nz){
299 p->codewords = codeword_add_maybe(p, ee, cnt, src);
300 if (debug & DBG_CODEWORDS){
301 printf("# step=%d row=%d minW=%d found cw of W=%d: [",ii,ir,minW,cnt);
302 const int max = ((cnt<25) || (debug & DBG_LARGE)) ? cnt : 25 ;
303 for(int i=0; i< max; i++)
304 printf("%d%s", ee[i], i+1!=max?" ": (cnt==max ? "]\n" : "...]\n"));
305 }
306 if (cnt < minW) {
307 minW = cnt;
308 }
310 goto alldone;
311 }
313 goto alldone;
314 }
315 if (minW <= wmin){
316 minW = - minW;
317 goto alldone;
318 }
319 }
320 }
321 }
322 if (debug & DBG_STATUS){
323 if(ii%1000==999)
324 printf("# round=%d of %d minW=%d\n", ii+1, steps, minW);
325 }
326
327 }
328
329 alldone:
330
332 if (M_sub) mzd_free(M_sub);
333 if (N_ker) mzd_free(N_ker);
334 if (mHT_csr) csr_free(mHT_csr);
335 free(visited_cols);
336 free(visited_checks);
337 free(col_queue);
338 free(piv_mask);
339 mzp_free(perm);
340 mzp_free(pivs);
341 free(ee);
342 if(mHT)
343 mzd_free(mHT);
344 mzd_free(mH);
345
346 if (minW < 0) {
347 return minW;
348 }
349 if (p->min_w == INT_MAX) {
350 return 0;
351 }
352 if (wmax > 0 && p->min_w > wmax) {
353 return 0;
354 }
355 return p->min_w;
356}
357
358
359#ifdef STANDALONE
360
361int do_CC_dist(params_t * const p);
362
363
364int main(int argc, char **argv){
365 params_t * const p = &prm;
366
367 var_init(argc,argv,p);
368
369 if (p->finC) {
370 nzlist_read(p->finC, p);
371 }
372
373 // const int n=p->nvar;
374
375 if (prm.method & 1){ /* RW method */
376
377 prm.dist_max=do_RW_dist(p);
378
379 if (prm.debug & DBG_SUMMARY){
380 if (prm.dist_max != 0)
381 printf("### RW upper bound on the distance: %d\n",prm.dist_max);
382 else
383 printf("### RW: no upper bound found up to wmax = %d\n", prm.wmax);
384 if(prm.dist_max <0)
385 printf("### negative distance due to wmin=%d set (early termination)\n",prm.wmin);
386 else if (prm.dist_max ==0)
387 printf("### no codewords of weight <= %d found\n",prm.wmax);
388 }
389 if (prm.dist_max < 0) {
390 if (prm.debug & DBG_SUMMARY) {
391 if (prm.method == 1)
392 printf("RW algorithm upper bound for the distance d=%d\n", prm.dist_max);
393 else
394 printf("RW algorithm upper bound for the distance d=%d "
395 "(early termination due to wmin=%d)\n", prm.dist_max, prm.wmin);
396 }
397 printf("%d\n",prm.dist_max);
398 prm.dist_min = prm.dist_max;
399 goto end_all;
400 }
401 if (prm.method==1){
402 if (prm.debug & DBG_SUMMARY) {
403 if (prm.dist_max > 0)
404 printf("RW algorithm upper bound for the distance d=%d\n", prm.dist_max);
405 else
406 printf("RW algorithm: no upper bound found up to wmax = %d\n", prm.wmax);
407 }
408 printf("%d\n",prm.dist_max);
409 }
410 else{
411 if (prm.wmax==0) {
412 if (prm.dist_max == 0) {
413 ERROR("RW found no codewords, cannot run CC with wmax=0. Please specify wmax > 0.\n");
414 }
415 prm.wmax=abs(prm.dist_max)-1;
416 }
417 else if (prm.dist_max != 0) {
418 prm.wmax=minint(prm.wmax, abs(prm.dist_max)-1);
419 }
420 if (prm.wmax == 0) {
421 prm.dist_min = 1;
422 prm.dist_max = 1;
423 if (prm.debug & DBG_SUMMARY) {
424 printf("success (distance is 1) d=1\n");
425 }
426 printf("1\n");
427 goto end_all;
428 }
429 }
430 }
431
432 if (prm.method & 2){ /* cluster method */
433 int dmin=do_CC_dist(p);
434 /* with noscan=1 (unless the supplied dmin equals wmax) lower weights are not scanned */
435 const int certified = (!prm.noscan) || (prm.wmax <= ((prm.dmin > 1) ? prm.dmin : 1));
436
437 if (dmin>0){
438 if (prm.debug & DBG_SUMMARY){
439 if (certified)
440 printf("### Cluster (actual min-weight codeword found): d=%d\n",dmin);
441 else
442 printf("### Cluster (codeword found, upper bound only with noscan=1): d<=%d\n",dmin);
443 }
444 printf("%d\n",dmin);
445 if (certified)
446 prm.dist_min = dmin; /* actual distance found */
447 prm.dist_max = dmin;
448 goto end_all;
449 }
450 else if (dmin<0){
451 if (prm.debug & DBG_SUMMARY)
452 printf("### Cluster dmin=%d (no codewords of weight up to %d)\n",dmin,-dmin);
453 if (-dmin==abs(prm.dist_max)-1){
454 prm.dist_min=abs(prm.dist_max); /* OK */
455 if (prm.debug & DBG_SUMMARY)
456 printf("success (two distance bounds coincide) d=%d\n",prm.dist_min);
457 printf("%d\n",prm.dist_min);
458 goto end_all;
459 }
460 else{
461 prm.dist_min=-dmin;
462 if (prm.debug & DBG_SUMMARY){
463 if (prm.dist_max>prm.dist_min)
464 printf("# distance in the interval (inclusive) %d to %d\n", prm.dist_min,prm.dist_max);
465 else
466 printf("# cluster algorithm failed to find a codeword up to wmax=%d\n",-dmin);
467 }
468 printf("%d\n",dmin);
469 }
470 }
471 else { /* noscan=1 without dmin: no codeword of weight wmax, and no lower bound certified */
472 if (prm.debug & DBG_SUMMARY)
473 printf("### Cluster: no codewords of weight %d (noscan=1: lower weights not scanned)\n", prm.wmax);
474 printf("0\n");
475 }
476 }
477 end_all:
478 if (p->outC) {
479 char comment[256];
480 sprintf(comment, "generated by dist_m4ri");
481 nzlist_write(p->outC, comment, p);
482 }
483 if (p->debug & DBG_CWDUMP) {
484 cw_vec_t *cw;
485 for(cw = p->codewords; cw != NULL; cw = (cw_vec_t *)(cw->hh.next)){
486 printf("# cw: [ ");
487 for(int i=0; i<cw->weight; i++) printf("%d ", 1 + col_orig_index(p, cw->arr[i]));
488 printf("] cnt=%d\n", cw->cnt);
489 }
490 }
491 var_kill(p);
492
493 return 0;
494 }
495
496#endif /* STANDALONE */
int do_CC_dist(params_t *const p)
Definition dist_cc.c:173
int main(int argc, char **argv)
Definition dist_m4ri.c:3396
int do_RW_dist(params_t *const p)
distance of a classical or quantum CSS code
Definition dist_rw.c:38
int arr[0]
Definition util_hash.h:42
int cnt
Definition util_hash.h:39
UT_hash_handle hh
Definition util_hash.h:37
int weight
Definition util_hash.h:38
void * next
Definition uthash.h:1129
int rows
Definition util_m4ri.h:121
int cols
Definition util_m4ri.h:122
#define HASH_ITER(hh, head, el, tmp)
Definition uthash.h:1060
int check_min_hits_convergence(const params_t *const p)
Check whether the QDistRnd-style hit count stopping condition is met.
Definition util_io.c:2906
void var_kill(params_t *const p)
Clean up and free memory allocated in the params_t structure.
Definition util_io.c:1492
params_t *const p
Definition util_io.c:93
long long int nzlist_read(const char fnam[], params_t *p)
Read codewords from a .nz list file and add them to the codeword hash.
Definition util_io.c:3073
int codeword_maxc_reached(const params_t *const p)
Returns 1 if maxC > 0 and maxC codewords of the collection window are collected.
Definition util_io.c:2644
int codeword_feed_limit(const params_t *const p)
Weight limit (exclusive) of RW codewords needed for the min_hits statistic.
Definition util_io.c:2648
long long int nzlist_write(const char fnam[], const char comment[], params_t *p)
Write the collected codewords from the hash table to a .nz file.
Definition util_io.c:3197
cw_vec_t * codeword_add_maybe(params_t *const p, const int arr[], int weight, int src)
Add a candidate codeword to the hash table, or count one more hit of a known codeword.
Definition util_io.c:2693
params_t prm
Definition util_io.c:8
void var_init(int argc, char **argv, params_t *const p)
Initialize parameters and load matrices from command line arguments.
Definition util_io.c:766
#define DBG_PROGRESS
Definition util_io.h:32
struct CW_VEC_T cw_vec_t
Definition util_io.h:49
#define DBG_SUMMARY
Definition util_io.h:31
#define DBG_CODEWORDS
Definition util_io.h:36
#define DBG_LARGE
Definition util_io.h:40
@ CW_SRC_RW_WINDOW
Definition util_io.h:253
@ CW_SRC_RW_UNIFORM
Definition util_io.h:253
#define DBG_STATUS
Definition util_io.h:33
#define DBG_CWDUMP
Definition util_io.h:39
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
csr_t * csr_transpose(csr_t *dst, const csr_t *const p)
Transpose a compressed CSR sparse matrix.
Definition util_m4ri.c:163
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
csr_t * csr_free(csr_t *p)
Free memory allocated for a CSR sparse matrix.
Definition util_m4ri.c:522
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
int rand_uniform(const int max)
Return a uniformly distributed random integer in the range [0, max-1].
Definition util_m4ri.c:439
#define ERROR(fmt,...)
Definition util_m4ri.h:13