105static void parse_start_list(
const char *
const str,
params_t *
const p){
108 p->start_list = NULL;
112 for (
const char *c = str; *c; c++)
115 int *list = malloc(cnt *
sizeof(
int));
117 ERROR(
"memory allocation");
119 for (
int k = 0; k < cnt; k++) {
122 long val = strtol(s, &end, 10);
123 if ((end == s) || errno || (val > INT_MAX) || (val < INT_MIN) || ((*end !=
',') && (*end !=
'\0')))
124 ERROR(
"invalid start='%s': expected a comma-separated list of column indices, e.g., start=0,48", str);
128 if ((cnt == 1) && (list[0] < 0)) {
132 for (
int k = 0; k < cnt; k++)
134 ERROR(
"invalid start='%s': column indices must be non-negative", str);
135 p->start_list = list;
139static int cmp_int(
const void *a,
const void *b){
140 const int x = *(
const int *) a, y = *(
const int *) b;
141 return (x > y) - (x < y);
146static int parse_debug_value(
const char *
const str,
const char *
const arg){
147 const int hex = (str[0] ==
'0') && ((str[1] ==
'x') || (str[1] ==
'X'));
148 const char *
const digits = hex ? str + 2 : str;
151 const long val = strtol(digits, &end, hex ? 16 : 10);
152 if ((end == digits) || (*end !=
'\0') || errno || (val < 0) || (val > INT_MAX))
153 ERROR(
"invalid '%s': expected a non-negative decimal or hexadecimal (0x...) integer", arg);
159static char * file_arg_value(
const int argc,
char **argv,
int *
const i,
const size_t len){
160 if (strlen(argv[*i]) > len)
161 return argv[*i] + len;
163 ERROR(
"argv[%d]='%s': missing file name", *i, argv[*i]);
168static int csr_nnz(
const csr_t *
const M){
169 return (M->
nz == -1) ? M->
p[M->
rows] : M->
nz;
173static int csr_max_col_wght(
const csr_t *
const M){
174 if ((M->
nz != -1) || (M->
cols <= 0))
return 0;
175 int *cnt = calloc(M->
cols,
sizeof(
int));
177 ERROR(
"memory allocation");
179 for (
int j = 0; j < M->
p[M->
rows]; j++)
180 if (++cnt[M->
i[j]] > wmax)
186void csr_dump(FILE *stream,
const csr_t *
const M,
const char name[],
const int debug){
188 fprintf(stream,
"# matrix %s: %d x %d, %d nonzeros", name, M->
rows, M->
cols, csr_nnz(M));
190 fprintf(stream,
" (not shown for n >= 150 without debug bit 2048)\n");
193 fprintf(stream,
" ('1': nonzero, '.': zero)\n");
194 char *row = malloc(M->
cols + 1);
196 ERROR(
"memory allocation");
198 for (
int i = 0; i < M->
rows; i++) {
199 for (
int j = 0; j < M->
cols; j++)
200 row[j] = mzd_read_bit(D, i, j) ?
'1' :
'.';
202 fprintf(stream,
"# %s\n", row);
209static void print_matrix_summary(FILE *stream,
const char name[],
const csr_t *
const M,
const char note[]){
210 fprintf(stream,
"# %s: %d x %d%s, %d nonzeros, max row weight %d, max column weight %d\n", name, M->
rows, M->
cols,
214static const char * drop_label(
const params_t *
const p);
217static void print_round_summary(FILE *stream,
const params_t *
const p){
219 fprintf(stream,
"# rounds of the DEM: D=%d detectors and L=%d columns per round (estimated: score %.3f)\n",
220 p->round_D,
p->round_L,
p->round_score);
222 fprintf(stream,
"# rounds of the DEM: no round structure found (best score %.3f < 0.5)\n",
223 (
p->round_score > 0.0) ?
p->round_score : 0.0);
227static void print_window_summary(FILE *stream,
const params_t *
const p){
228 fprintf(stream,
"# RW windows: %d columns on every other step, uniform permutations on the others (",
229 rw_hybrid_window(
p,
p->nvar));
231 fprintf(stream,
"win_hyb=%d)\n",
p->win_hyb);
233 fprintf(stream,
"win_hyb=0: 256 for a DEM, 512 for matrices)\n");
237static void print_input_summary(FILE *stream,
const params_t *
const p){
238 const char *
const type =
p->classical ?
"classical code" : (
p->fdem ?
"detector error model" :
"quantum CSS code");
239 fprintf(stream,
"# input: %s, n=%d (", type,
p->nvar);
241 fprintf(stream,
"fdem='%s'",
p->fdem);
243 fprintf(stream,
", pmin=%g",
p->pmin);
245 fprintf(stream,
"finH='%s'",
p->finH);
247 fprintf(stream,
", finG='%s'",
p->finG);
249 fprintf(stream,
", finL='%s'",
p->finL);
251 fprintf(stream,
")\n");
252 print_matrix_summary(stream,
"H",
p->spaH,
p->fdem ?
" (detectors)" :
"");
253 if (
p->nvar_merged > 0)
254 fprintf(stream,
"# merged %d equal columns of the DEM: %d of %d columns kept (merge=0 to keep all)\n",
255 p->nvar_orig -
p->nvar_merged,
p->nvar_merged,
p->nvar_orig);
257 fprintf(stream,
"# dropped %d of %d detectors (drop=%s), exact: the %d columns touching them have twins (%s), "
258 "%d columns kept\n",
p->ndrop,
p->ndrop_rows, drop_label(
p),
p->ndrop_cols,
259 p->drop_A ?
"L + A H with A != 0" :
"the same observables",
p->nvar);
260 else if (
p->drop_none)
261 fprintf(stream,
"# drop=auto: no detector can be dropped exactly (the full DEM is used)\n");
263 fprintf(stream,
"# rows of H sorted by increasing weight for CC (sort_rows=1; sort_rows=0 keeps their order)\n");
264 if (
p->round_score >= 0.0)
265 print_round_summary(stream,
p);
266 if ((
p->method & 1) && (
p->kwin == 0) && (
p->nvar >= 500))
267 print_window_summary(stream,
p);
269 print_matrix_summary(stream,
"G",
p->spaG,
"");
271 print_matrix_summary(stream,
"L",
p->spaL,
p->fdem ?
" (observables)" : (
p->finL ?
"" :
" (from H and G)"));
273 fprintf(stream,
"# irred=0 (expert option): reducible codewords are also recorded, as before version 0.14.8\n");
277static int csr_rank(
const csr_t *
const M){
279 const int rank = mzd_echelonize(D, 0);
285static void print_code_params(FILE *stream,
const params_t *
const p){
286 struct timespec t0, t1;
287 clock_gettime(CLOCK_MONOTONIC, &t0);
288 const int n =
p->nvar;
289 const int rank_H = csr_rank(
p->spaH);
292 if (
p->classical || !
p->spaL) {
294 snprintf(buf,
sizeof(buf),
"k=n-rank(H)=%d", k);
295 }
else if (
p->spaG) {
296 const int rank_G = csr_rank(
p->spaG);
297 k = n - rank_H - rank_G;
298 snprintf(buf,
sizeof(buf),
"rank(G)=%d, k=n-rank(H)-rank(G)=%d", rank_G, k);
302 mzd_t *mHL = mzd_stack(NULL, mH, mL);
303 const int rank_L = mzd_echelonize(mL, 0);
304 k = mzd_echelonize(mHL, 0) - rank_H;
308 snprintf(buf,
sizeof(buf),
"rank(L)=%d, k=rank([H;L])-rank(H)=%d", rank_L, k);
310 clock_gettime(CLOCK_MONOTONIC, &t1);
311 fprintf(stream,
"# code parameters: n=%d, rank(H)=%d, dim ker(H)=%d, %s (%.3g s)\n", n, rank_H, n - rank_H, buf,
312 (
double)(t1.tv_sec - t0.tv_sec) + 1e-9 * (
double)(t1.tv_nsec - t0.tv_nsec));
314 fprintf(stream,
"# Warning: k=%d, there are no non-trivial codewords\n", k);
321static int csr_sort_rows_by_weight(
csr_t *
const M){
324 const int m = M->
rows, nnz = M->
p[m];
325 int wmax = 0, sorted = 1;
326 for (
int r = 0; r < m; r++) {
327 const int w = M->
p[r + 1] - M->
p[r];
330 if ((r > 0) && (w < M->
p[r] - M->
p[r - 1]))
335 int *
const pos = calloc((
size_t)wmax + 2,
sizeof(
int));
336 int *
const order = malloc((
size_t)m *
sizeof(
int));
337 int *
const p2 = malloc(((
size_t)m + 1) *
sizeof(
int));
338 int *
const i2 = malloc(((
size_t)nnz + 1) *
sizeof(
int));
339 if (!pos || !order || !p2 || !i2)
340 ERROR(
"memory allocation");
341 for (
int r = 0; r < m; r++)
342 pos[M->
p[r + 1] - M->
p[r] + 1]++;
343 for (
int w = 0; w <= wmax; w++)
344 pos[w + 1] += pos[w];
345 for (
int r = 0; r < m; r++)
346 order[pos[M->
p[r + 1] - M->
p[r]]++] = r;
348 for (
int k = 0; k < m; k++) {
349 const int r = order[k];
351 for (
int t = M->
p[r]; t < M->
p[r + 1]; t++)
355 memcpy(M->
p, p2, ((
size_t)m + 1) *
sizeof(
int));
356 memcpy(M->
i, i2, (
size_t)nnz *
sizeof(
int));
364static void dem_merge_columns(
params_t *
const p);
365static void dem_drop_detectors(
params_t *
const p);
366static void dem_write_drop_list(
const params_t *
const p);
367static void dem_round_estimate(
params_t *
const p);
370#define HELP_MAX_NAMES 8
371#define HELP_NAME_LEN 32
372#define HELP_MAX_MEMBERS 16
387static void help_key(
char *
const key,
const char *
const s,
const size_t n) {
389 for (
size_t i = 0; (i < n) && s[i] && (s[i] !=
'=') && (k + 1 <
HELP_NAME_LEN); i++)
390 if ((s[i] !=
'-') && (s[i] !=
'_') && !isspace((
unsigned char)s[i]))
391 key[k++] = (char)tolower((
unsigned char)s[i]);
396static void help_add_name(
help_entry_t *
const e,
const char *
const s,
size_t n) {
401 for (
int i = 0; i < e->
nnames; i++)
402 if (strcmp(e->
key[i], key) == 0)
412static size_t help_name_len(
const char *
const s) {
414 while ((i < 2) && (s[i] ==
'-'))
416 if (!isalpha((
unsigned char)s[i]))
418 while (isalnum((
unsigned char)s[i]) || (s[i] ==
'_') || (s[i] ==
'-'))
426static int help_read_names(
help_entry_t *
const e,
const char *s) {
429 const size_t n = help_name_len(s);
432 help_add_name(e, s, n);
435 while (*s && (*s !=
' ') && (*s !=
','))
437 if ((s[0] ==
' ') && (s[1] ==
'[')) {
438 const char *
const t = strchr(s,
']');
443 if ((*s ==
'\0') || ((s[0] ==
' ') && (s[1] ==
' ')))
445 if ((s[0] ==
',') && (s[1] ==
' '))
455static int help_has_prefix(
const char *s,
const char *prefix) {
456 for (; *prefix; s++, prefix++)
457 if (tolower((
unsigned char)*s) != *prefix)
464static void help_read_aliases(
help_entry_t *
const e,
const char *
const s) {
465 for (
const char *
p = s; *
p;
p++) {
467 if (help_has_prefix(
p,
"aliases:"))
469 else if (help_has_prefix(
p,
"alias:"))
476 const size_t n = help_name_len(q);
479 help_add_name(e, q, n);
482 while (*q && (*q !=
',') && (*q !=
' ') && (*q !=
')'))
493static void help_read_members(
help_entry_t *
const e,
const char *s) {
495 while ((*s ==
' ') || (*s ==
','))
497 const size_t n = help_name_len(s);
508 for (
int i = 0; i < g->
nmembers; i++)
509 for (
int j = 0; j < e->
nnames; j++)
510 if (strcmp(g->
member[i], e->
key[j]) == 0)
517static int help_group_key_match(
const char *
const gkey,
const char *
const key) {
518 const size_t lg = strlen(gkey), lk = strlen(key);
519 if (strcmp(gkey, key) == 0)
521 if ((lg == lk + 1) && (gkey[lk] ==
's') && (strncmp(gkey, key, lk) == 0))
523 return (lk == lg + 1) && (key[lg] ==
's') && (strncmp(gkey, key, lg) == 0);
533static int help_entries(
char *
const text,
char ***
const lines,
int *
const nlines,
help_entry_t **
const ent) {
534 int nl = 0, cap = 256;
535 char **ln = malloc((
size_t)cap *
sizeof(
char *));
537 ERROR(
"memory allocation");
538 for (
char *s = text; *s; ) {
541 ln = realloc(ln, (
size_t)cap *
sizeof(
char *));
543 ERROR(
"memory allocation");
546 char *
const t = strchr(s,
'\n');
554 ERROR(
"memory allocation");
555 int ne = 0, sec = -1, groups = 0;
557 for (
int i = 0; i < nl; i++) {
558 const char *
const s = ln[i];
559 const size_t len = strlen(s);
560 if (len && !isspace((
unsigned char)s[0]) && (s[len - 1] ==
':')) {
563 groups = (strncmp(s,
"Option groups", 13) == 0);
564 const char *
const p = strchr(s,
'(');
565 const size_t n =
p ? help_name_len(
p + 1) : 0;
566 if (n && (
p[1 + n] ==
'=') && (
p[2 + n] ==
'[')) {
568 *cur = (
help_entry_t){.sec = i, .beg = i, .end = i + 1, .is_sec = 1};
569 help_add_name(cur,
p + 1, n);
572 else if (cur && cur->
is_sec) {
575 help_read_aliases(cur, s);
577 else if ((s[0] ==
' ') && (s[1] ==
' ') && s[2] && (s[2] !=
' ') && help_read_names(&en[ne], s + 2)) {
583 const char *
const d = strstr(s + 2,
" ");
585 help_read_members(cur, d);
588 help_read_aliases(cur, s);
590 else if (cur && (s[0] ==
' ') && (s[1] ==
' ') && (s[2] ==
' ')) {
593 help_read_members(cur, s);
595 help_read_aliases(cur, s);
607static int help_edit_distance(
const char *
const a,
const char *
const b) {
608 const size_t la = strlen(a), lb = strlen(b);
610 for (
size_t j = 0; j <= lb; j++)
612 for (
size_t i = 1; i <= la; i++) {
615 for (
size_t j = 1; j <= lb; j++) {
617 int best = diag + (a[i - 1] != b[j - 1]);
620 if (d[j - 1] + 1 < best)
632static void help_no_entry(
const char *
const prog,
const char *
const s,
const int n,
const char *
const key,
634 const int maxd = ((int)strlen(key) + 2) / 3 > 1 ? ((
int)strlen(key) + 2) / 3 : 1;
636 int bestd[5], nb = 0;
637 for (
int i = 0; i < ne; i++)
638 for (
int j = 0; j < ent[i].
nnames; j++) {
639 const int d = help_edit_distance(key, ent[i].key[j]);
643 while ((pos > 0) && (bestd[pos - 1] > d))
649 for (
int k = nb - 1; k > pos; k--) {
650 best[k] = best[k - 1];
651 bestd[k] = bestd[k - 1];
653 best[pos] = ent[i].
name[j];
656 fprintf(stderr,
"%s: no help entry for '%.*s'", prog, n, s);
657 for (
int k = 0; k < nb; k++)
658 fprintf(stderr,
"%s%s", k ?
", " :
"; did you mean ", best[k]);
659 fprintf(stderr,
"%s (--morehelp lists all parameters)\n", nb ?
"?" :
"");
669static int print_help_topics(
const char *
const prog,
const int ntopics,
const char *
const topics[]) {
671 char *
const text = malloc((
size_t)len + 1);
673 ERROR(
"memory allocation");
678 const int ne = help_entries(text, &lines, &nlines, &ent);
679 char *
const chosen = calloc((
size_t)ne + 1, 1);
680 char *
const asked = calloc((
size_t)ne + 1, 1);
681 if (!chosen || !asked)
682 ERROR(
"memory allocation");
683 int status = 0, nkeys = 0;
684 for (
int t = 0; t < ntopics; t++)
685 for (
const char *s = topics[t]; *s; ) {
686 const char *
const comma = strchr(s,
',');
687 int n = comma ? (int)(comma - s) : (int)strlen(s);
688 const char *
const next = comma ? comma + 1 : s + n;
689 while ((n > 0) && isspace((
unsigned char)*s)) {
693 while ((n > 0) && isspace((
unsigned char)s[n - 1]))
696 help_key(key, s, (
size_t)n);
700 for (
int i = 0; i < ne; i++)
701 for (
int j = 0; j < ent[i].
nnames; j++)
702 if ((ent[i].nmembers > 0) ? help_group_key_match(ent[i].key[j], key) : (strcmp(ent[i].key[j], key) == 0))
703 asked[i] = found = 1;
705 help_no_entry(prog, s, n, key, ent, ne);
711 for (
int g = 0; g < ne; g++) {
712 if (ent[g].nmembers <= 0)
715 for (
int i = 0; (i < ne) && !use; i++)
716 use = asked[i] && (ent[i].nmembers == 0) && help_is_member(&ent[g], &ent[i]);
720 for (
int i = 0; i < ne; i++)
721 if ((ent[i].nmembers == 0) && help_is_member(&ent[g], &ent[i]))
724 for (
int i = 0; i < ne; i++)
725 chosen[i] |= asked[i];
726 int sec = -2, any = 0;
727 for (
int i = 0; i < ne; i++) {
730 if (ent[i].sec != sec) {
733 if ((ent[i].sec >= 0) && !ent[i].is_sec)
734 printf(
"%s\n", lines[ent[i].sec]);
737 for (
int k = ent[i].beg; k < ent[i].
end; k++)
738 printf(
"%s\n", lines[k]);
746 return nkeys ? status : -1;
751static int help_option(
const char *
const arg,
const char **
const topic) {
752 static const char *
const opts[] = {
"--morehelp",
"-morehelp",
"--more-help",
"-more-help",
753 "--help",
"-help",
"-h",
"-?", NULL};
755 for (
int k = 0; opts[k]; k++) {
756 const size_t len = strlen(opts[k]);
757 if ((strncmp(arg, opts[k], len) == 0) && ((arg[len] ==
'\0') || (arg[len] ==
'='))) {
759 *topic = arg + len + 1;
760 return k < 4 ? 2 : 1;
770 long long int dbg_ll=0;
772 for (
int i = 1; i < argc; i++)
773 if ((strcmp(argv[i],
"--version") == 0) || (strcmp(argv[i],
"-version") == 0)) {
781 int help_kind = 0, ntopics = 0;
782 const char **
const topics = calloc((
size_t)argc + 1,
sizeof(
char *));
784 ERROR(
"memory allocation");
785 for (
int i = 1; i < argc; i++) {
787 const int kind = help_option(argv[i], &topic);
790 if (kind > help_kind)
792 if (!topic && (i + 1 < argc) && (argv[i + 1][0] !=
'-') && !strchr(argv[i + 1],
'='))
795 topics[ntopics++] = topic;
798 const int status = ntopics ? print_help_topics(argv[0], ntopics, topics) : -1;
806 exit(status > 0 ? 1 : 0);
811 fprintf(stderr,
"%s: no command-line arguments given\n\n", argv[0]);
822 for (
int i = 1; i < argc; i++)
823 if (0 == strncmp(argv[i],
"debug=", 6)) {
824 const int val = parse_debug_value(argv[i] + 6, argv[i]);
825 p->debug = debug_set ? (
p->debug | val) : val;
829 fprintf(stderr,
"# debug=%d (0x%x)%s\n",
p->debug, (
unsigned int)
p->debug, debug_set ?
"" :
" (default)");
831 for(
int i=1; i<argc; i++){
832 if (0 == strncmp(argv[i],
"debug=", 6)){
834 else if (sscanf(argv[i],
"css=%d",&dbg)==1){
837 fprintf(stderr,
"# read %s, css=%d\n",argv[i],
p->css);
839 else if (0==strncmp(argv[i],
"finH=",5)){
840 p->finH = file_arg_value(argc, argv, &i, 5);
842 fprintf(stderr,
"# read %s, finH=%s; setting fin=\"\"\n",argv[i],
p->finH);
843 if (strlen(
p->fin) != 0)
844 fprintf(stderr,
"# Warning: finH='%s' given: ignoring fin='%s'\n",
p->finH,
p->fin);
847 else if (0==strncmp(argv[i],
"finL=",5)){
848 p->finL = file_arg_value(argc, argv, &i, 5);
850 fprintf(stderr,
"# read %s, finL=%s; setting fin=\"\"\n",argv[i],
p->finL);
851 if (strlen(
p->fin) != 0)
852 fprintf(stderr,
"# Warning: finL='%s' given: ignoring fin='%s'\n",
p->finL,
p->fin);
855 else if (0==strncmp(argv[i],
"finG=",5)){
856 p->finG = file_arg_value(argc, argv, &i, 5);
858 fprintf(stderr,
"# read %s, finG=%s; setting fin=\"\"\n",argv[i],
p->finG);
859 if (strlen(
p->fin) != 0)
860 fprintf(stderr,
"# Warning: finG='%s' given: ignoring fin='%s'\n",
p->finG,
p->fin);
863 else if (0==strncmp(argv[i],
"fin=",4)){
865 ERROR(
"arg[%d]='%s' in conflict with finH=%s\n",i,argv[i],
p->finH);
867 ERROR(
"arg[%d]='%s' in conflict with finG=%s\n",i,argv[i],
p->finG);
869 ERROR(
"arg[%d]='%s' in conflict with finL=%s\n",i,argv[i],
p->finL);
870 p->fin = file_arg_value(argc, argv, &i, 4);
872 else if (sscanf(argv[i],
"method=%d",&dbg)==1){
875 fprintf(stderr,
"# read %s, method=%d\n",argv[i],
p->method);
876 if( (
p->method<=0) || (
p->method>3)) {
877 fprintf(stderr,
"%s: unsupported method=%d specified\n\n", argv[0],
p->method);
882 else if (sscanf(argv[i],
"smax=%d",&dbg)==1){
885 fprintf(stderr,
"# read %s, smax=%d\n",argv[i],
p->smax);
887 else if (sscanf(argv[i],
"wmax=%d",&dbg)==1){
890 fprintf(stderr,
"# read %s, wmax=%d\n",argv[i],
p->wmax);
892 else if (sscanf(argv[i],
"dmin=%d",&dbg)==1){
895 fprintf(stderr,
"# read %s, dmin=%d\n",argv[i],
p->dmin);
897 else if (sscanf(argv[i],
"dmax=%d",&dbg)==1){
900 fprintf(stderr,
"# read %s, dmax=%d\n",argv[i],
p->dmax);
902 else if (0==strncmp(argv[i],
"start=",6)){
903 parse_start_list(argv[i]+6,
p);
905 fprintf(stderr,
"# read %s, start_num=%d\n",argv[i],
p->start_num);
907 else if (sscanf(argv[i],
"start_scan=%d",&dbg)==1){
908 if (dbg != 0 && dbg != 1)
909 ERROR(
"invalid '%s': start_scan should be 0 or 1\n", argv[i]);
912 fprintf(stderr,
"# read %s, start_scan=%d\n",argv[i],
p->start_scan);
914 else if (sscanf(argv[i],
"cbeg=%d",&dbg)==1){
917 fprintf(stderr,
"# read %s, cbeg=%d\n",argv[i],
p->cbeg);
919 else if (sscanf(argv[i],
"cend=%d",&dbg)==1){
922 fprintf(stderr,
"# read %s, cend=%d\n",argv[i],
p->cend);
924 else if (sscanf(argv[i],
"wmin=%d",&dbg)==1){
927 fprintf(stderr,
"# read %s, wmin=%d\n",argv[i],
p->wmin);
929 else if (sscanf(argv[i],
"steps=%d",&dbg)==1){
933 fprintf(stderr,
"# read %s, steps=%d\n",argv[i],
p->steps);
935 else if (sscanf(argv[i],
"seed=%d",&dbg)==1){
938 fprintf(stderr,
"# read %s, seed=%d\n",argv[i],
p->seed);
940 else if (sscanf(argv[i],
"noscan=%d",&dbg)==1){
943 fprintf(stderr,
"# read %s, noscan=%d\n",argv[i],
p->noscan);
945 else if (0==strncmp(argv[i],
"fdem=",5)){
946 p->fdem = file_arg_value(argc, argv, &i, 5);
948 fprintf(stderr,
"# read %s, fdem=%s\n",argv[i],
p->fdem);
950 else if (sscanf(argv[i],
"pmin=%lg",&prob)==1){
953 fprintf(stderr,
"# read %s, pmin=%g\n",argv[i],
p->pmin);
955 else if (sscanf(argv[i],
"merge=%d",&dbg)==1){
956 if ((dbg != 0) && (dbg != 1))
957 ERROR(
"invalid '%s': merge should be 0 or 1\n", argv[i]);
960 fprintf(stderr,
"# read %s, merge=%d\n",argv[i],
p->merge);
962 else if (sscanf(argv[i],
"sort_rows=%d",&dbg)==1){
963 if ((dbg != 0) && (dbg != 1))
964 ERROR(
"invalid '%s': sort_rows should be 0 or 1\n", argv[i]);
967 fprintf(stderr,
"# read %s, sort_rows=%d\n",argv[i],
p->sort_rows);
969 else if (sscanf(argv[i],
"irred=%d",&dbg)==1){
970 if ((dbg != 0) && (dbg != 1))
971 ERROR(
"invalid '%s': irred should be 0 or 1\n", argv[i]);
974 fprintf(stderr,
"# read %s, irred=%d\n",argv[i],
p->irred);
976 else if (sscanf(argv[i],
"ortho=%d",&dbg)==1){
977 if ((dbg != 0) && (dbg != 1))
978 ERROR(
"invalid '%s': ortho should be 0 or 1\n", argv[i]);
981 fprintf(stderr,
"# read %s, ortho=%d\n",argv[i],
p->ortho);
983 else if (sscanf(argv[i],
"cc_prune=%d",&dbg)==1){
984 if ((dbg < 0) || (dbg > 2))
985 ERROR(
"invalid '%s': cc_prune should be 0, 1, or 2\n", argv[i]);
988 fprintf(stderr,
"# read %s, cc_prune=%d\n",argv[i],
p->cc_prune);
990 else if (0==strncmp(argv[i],
"drop=",5)){
991 char *
const val = file_arg_value(argc, argv, &i, 5);
993 if (strcmp(val,
"0") == 0)
995 else if ((strcmp(val,
"1") == 0) || (strcmp(val,
"auto") == 0))
1002 fprintf(stderr,
"# read %s, drop=%s\n",argv[i],val);
1004 else if (0==strncmp(argv[i],
"outD=",5)){
1005 p->outD = file_arg_value(argc, argv, &i, 5);
1007 fprintf(stderr,
"# read %s, outD=%s\n",argv[i],
p->outD);
1009 else if (0==strncmp(argv[i],
"finC=",5)){
1010 p->finC = file_arg_value(argc, argv, &i, 5);
1012 fprintf(stderr,
"# read %s, finC=%s\n",argv[i],
p->finC);
1014 else if (0==strncmp(argv[i],
"outC=",5)){
1015 p->outC = file_arg_value(argc, argv, &i, 5);
1017 fprintf(stderr,
"# read %s, outC=%s\n",argv[i],
p->outC);
1019 else if (sscanf(argv[i],
"maxC=%lld",&dbg_ll)==1){
1022 fprintf(stderr,
"# read %s, maxC=%lld\n",argv[i],
p->maxC);
1024 else if (sscanf(argv[i],
"dW=%d",&dbg)==1){
1027 fprintf(stderr,
"# read %s, dW=%d\n",argv[i],
p->dW);
1029 else if (sscanf(argv[i],
"classical=%d",&dbg)==1){
1032 fprintf(stderr,
"# read %s, classical=%d\n",argv[i],
p->classical);
1034 else if (sscanf(argv[i],
"threads=%d",&dbg)==1){
1037 fprintf(stderr,
"# read %s, threads=%d\n",argv[i],
p->threads);
1039 else if (sscanf(argv[i],
"dexp=%d",&dbg)==1){
1042 fprintf(stderr,
"# read %s, dexp=%d\n",argv[i],
p->dexp);
1044 else if (sscanf(argv[i],
"dest=%d",&dbg)==1){
1047 fprintf(stderr,
"# read %s, dest=%d (alias for dexp)\n",argv[i],
p->dexp);
1049 else if (sscanf(argv[i],
"dstop=%d",&dbg)==1){
1051 ERROR(
"invalid '%s': dstop must be non-negative", argv[i]);
1054 fprintf(stderr,
"# read %s, dstop=%d\n",argv[i],
p->dstop);
1056 else if (sscanf(argv[i],
"timeout=%lf",&prob)==1){
1059 fprintf(stderr,
"# read %s, timeout=%g\n",argv[i],
p->timeout);
1061 else if (sscanf(argv[i],
"nothrottle=%d",&dbg)==1){
1064 fprintf(stderr,
"# read %s, nothrottle=%d\n",argv[i],
p->nothrottle);
1066 else if (strcmp(argv[i],
"--no-throttle") == 0 || strcmp(argv[i],
"-no-throttle") == 0
1067 || strcmp(argv[i],
"nothrottle") == 0) {
1070 fprintf(stderr,
"# read %s, nothrottle=1\n",argv[i]);
1072 else if (sscanf(argv[i],
"chunk_size=%d",&dbg)==1 || sscanf(argv[i],
"batch=%d",&dbg)==1){
1075 fprintf(stderr,
"# read %s, chunk_size=%d\n",argv[i],
p->chunk_size);
1077 else if (sscanf(argv[i],
"ksub=%d",&dbg)==1){
1080 fprintf(stderr,
"# read %s, ksub=%d\n",argv[i],
p->ksub);
1082 else if (sscanf(argv[i],
"kwin=%d",&dbg)==1 || sscanf(argv[i],
"win=%d",&dbg)==1){
1085 fprintf(stderr,
"# read %s, kwin=%d\n",argv[i],
p->kwin);
1087 else if (sscanf(argv[i],
"win_mode=%d",&dbg)==1){
1090 fprintf(stderr,
"# read %s, win_mode=%d\n",argv[i],
p->win_mode);
1092 else if (sscanf(argv[i],
"win_hyb=%d",&dbg)==1){
1094 ERROR(
"invalid '%s': win_hyb should be 0 (256 columns for a DEM, 512 for matrices) or positive\n", argv[i]);
1097 fprintf(stderr,
"# read %s, win_hyb=%d\n",argv[i],
p->win_hyb);
1099 else if (sscanf(argv[i],
"pairs=%d",&dbg)==1){
1101 ERROR(
"invalid '%s': pairs should be -1 (auto), 0 (off), or 1 to %d (random pivot rows of the buckets)\n",
1105 fprintf(stderr,
"# read %s, pairs=%d\n",argv[i],
p->pairs);
1107 else if (sscanf(argv[i],
"min_hits=%d",&dbg)==1 || sscanf(argv[i],
"max_hits=%d",&dbg)==1){
1110 fprintf(stderr,
"# read %s, min_hits=%d\n",argv[i],
p->min_hits);
1112 else if (sscanf(argv[i],
"cov_cws=%d",&dbg)==1){
1115 fprintf(stderr,
"# read %s, cov_cws=%d\n",argv[i],
p->cov_cws);
1117 else if (sscanf(argv[i],
"refresh=%d",&dbg)==1){
1121 fprintf(stderr,
"# read %s, refresh=%d\n",argv[i],
p->refresh);
1124 fprintf(stderr,
"%s: unrecognized parameter \"%s\" at position %d\n\n", argv[0], argv[i], i);
1130 if (!refresh_set &&
p->ksub > 0) {
1134 if (
p->noscan &&
p->method != 2) {
1135 ERROR(
"noscan=1 only works with method=2");
1138 if (!
p->fdem && strlen(
p->fin) == 0 && !
p->finH && !
p->finG && !
p->finL) {
1139 p->fin =
"../examples/try";
1143 if (
p->finH ||
p->finG ||
p->finL || strlen(
p->fin) > 0) {
1144 ERROR(
"Cannot specify matrix files (fin, finH, finG, finL) along with fdem");
1147 if (
p->pmin != 0.0 && !
p->fdem) {
1148 ERROR(
"pmin can only be used when fdem is specified");
1150 if (
p->drop_set && (
p->drop_mode != 0) && !
p->fdem) {
1151 ERROR(
"drop can only be used when fdem is specified");
1153 if (
p->outD && !
p->fdem) {
1154 ERROR(
"outD can only be used when fdem is specified");
1156 if (
p->drop_set && (
p->drop_mode != 0) && (
p->classical == 1)) {
1157 ERROR(
"drop cannot be combined with classical=1 (the observables are needed)");
1159 if ((
p->drop_mode == 2) && (access(
p->fdrop, R_OK) != 0)) {
1160 ERROR(
"drop=%s: cannot read this file (%s); use drop=0, drop=1 or drop=auto, or a file",
p->fdrop,
1165 ERROR(
"parameter dmin=%d cannot be negative\n",
p->dmin);
1168 ERROR(
"parameter dmax=%d cannot be negative\n",
p->dmax);
1170 if (
p->dmin > 0 &&
p->dmax > 0 &&
p->dmin >
p->dmax) {
1171 ERROR(
"parameter dmin=%d cannot be larger than dmax=%d\n",
p->dmin,
p->dmax);
1173 if (
p->wmax > 0 &&
p->dmin >
p->wmax) {
1174 ERROR(
"parameter dmin=%d cannot be larger than wmax=%d\n",
p->dmin,
p->wmax);
1177 if (
p->wmax > 0 &&
p->wmin >
p->wmax) {
1178 ERROR(
"parameter wmin=%d cannot be larger than wmax=%d\n",
p->wmin,
p->wmax);
1180 if (
p->start_num > 0) {
1181 if (
p->cbeg >= 0 ||
p->cend >= 0) {
1182 ERROR(
"Cannot specify start along with cbeg or cend\n");
1185 if (
p->start_scan) {
1186 if (
p->start_num == 0)
1187 ERROR(
"start_scan=1 needs a start list (start=...)\n");
1189 ERROR(
"start_scan=1 is not available with fdem (the equal columns of a DEM are merged)\n");
1192 if (
p->method == 1) {
1193 if (
p->cbeg >= 0 ||
p->cend >= 0 ||
p->start_num > 0) {
1194 ERROR(
"Parameters start, cbeg, and cend only work with CC method (method=2 or method=3)\n");
1198 if (
p->cbeg >= 0 &&
p->cend >= 0 &&
p->cbeg >
p->cend) {
1199 ERROR(
"cbeg=%d cannot be larger than cend=%d\n",
p->cbeg,
p->cend);
1201 if (
p->noscan &&
p->smax > 0) {
1203 "# WARNING: smax=%d disabled (set to 0) because noscan=1 skips small cluster weights\n",
1206 }
else if (
p->dmin > 1 &&
p->smax > 0) {
1208 "# WARNING: smax=%d disabled (set to 0) because dmin=%d skips small cluster weights\n",
1213 if (
p->method == 2) {
1215 fprintf(stderr,
"# WARNING: steps=%d is ignored for CC method\n",
p->steps);
1219 if (
p->method == 1) {
1221 ERROR(
"parameter steps=%d should be positive for RW method=%d",
p->steps,
p->method);
1226 if((strlen(
p->fin)!=0) && (!
p->finH)){
1227 int len = strlen(
p->fin);
1228 char *s = (
char *) malloc((len+6)*
sizeof(
char));
1230 ERROR(
"memory allocation");
1231 sprintf(s,
"%s%s",
p->fin,swit>0?
"X.mtx":
"Z.mtx");
1233 s = (
char *) malloc((len+6)*
sizeof(
char));
1235 ERROR(
"memory allocation");
1236 sprintf(s,
"%s%s",
p->fin,swit>0?
"Z.mtx":
"X.mtx");
1239 fprintf(stderr,
"# read 'fin=%s'; "
1240 "assigning \n# finH=%s\n# finG=%s\n",
1248 dem_merge_columns(
p);
1249 if ((
p->drop_mode != 0) && (
p->classical != 1))
1250 dem_drop_detectors(
p);
1252 dem_write_drop_list(
p);
1255 dem_round_estimate(
p);
1256 if (
p->classical == -1)
p->classical = 0;
1257 p->nvar =
p->spaH->cols;
1259 p->nchk =
p->spaL->rows;
1266 fprintf(stderr,
"# read H <- file '%s'\n",
p->finH);
1270 ERROR(
"need to specify H=Hx input file name; use fin=[str] or finH=[str]\n");
1272 if((
p->finG) && (
p->finL))
1273 ERROR(
"either G=Hz or L=Lx matrix should be specified but not both! finG='%s' finL='%s'\n",
1277 if (
p->classical == -1)
p->classical = 0;
1280 fprintf(stderr,
"# read G <- file '%s'\n",
p->finG);
1282 ERROR(
"rows of H and G matrices are not orthogonal");
1286 if (
p->classical == -1)
p->classical = 0;
1289 fprintf(stderr,
"# read L <- file '%s'\n",
p->finL);
1291 p->nchk =
p->spaL->rows;
1294 if (
p->classical == -1)
p->classical = 1;
1300 if ((
p->wmax<=0) && ((
p->method & 1 )==0)) {
1303 if (
p->timeout <= 0.0 &&
p->dmax <= 0 &&
p->dstop <= 0) {
1304 ERROR(
"either parameter wmax>0, dmax>0, dstop>0, or timeout>0 should be specified for CC method=%d",
1310 ERROR(
"increase MAX_W=%d defined in 'util_io.h'",
MAX_W);
1311 for(
int i=0; i<
MAX_W; i++)
1312 p->swei[i]=
p->spaH->rows +1;
1316 p->seed = time(NULL) - 1000 *
p->seed + 10*getpid();
1318 fprintf(stderr,
"# initializing rng from time(NULL), seed=%d\n",
p->seed);
1321 fprintf(stderr,
"# initializing rng from seed=%d\n",
p->seed);
1325 rci_t n = (
p->spaH)-> cols;
1326 if ((!
p->classical) && ((
p->spaG) && (n != (
p->spaG) -> cols)))
1327 ERROR(
"Column count mismatch in H and G matrices: %d != %d",
1328 (
p->spaH)-> cols, (
p->spaG)->cols);
1332 ERROR(
"Non-CSS codes are currently not supported, css=%d",
p->css);
1335 const int n_orig = (
p->nvar_orig > 0) ?
p->nvar_orig :
p->nvar;
1336 if (
p->cbeg >= n_orig) {
1337 ERROR(
"cbeg=%d cannot be larger than nvar-1=%d\n",
p->cbeg, n_orig-1);
1339 if (
p->cend >= n_orig) {
1340 ERROR(
"cend=%d cannot be larger than nvar-1=%d\n",
p->cend, n_orig-1);
1342 if (
p->start_num > 0) {
1344 for (
int k = 0; k <
p->start_num; k++) {
1345 if (
p->start_list[k] >= n_orig)
1346 ERROR(
"start column %d cannot be larger than nvar-1=%d\n",
p->start_list[k], n_orig-1);
1347 const int c =
p->col_class ?
p->col_class[
p->start_list[k]] :
p->start_list[k];
1349 p->start_list[num++] = c;
1352 ERROR(
"no start column left: the columns listed touch only dropped detectors (drop=%s)\n", drop_label(
p));
1354 qsort(
p->start_list,
p->start_num,
sizeof(
int), cmp_int);
1356 for (
int k = 1; k <
p->start_num; k++)
1357 if (
p->start_list[k] !=
p->start_list[num-1])
1358 p->start_list[num++] =
p->start_list[k];
1362 if((
p->spaG) && (
p->spaL==NULL)){
1366 p->nchk =
p->spaL->rows;
1367 csr_dump(stderr,
p->spaL,
"L (from H and G)",
p->debug);
1371 if (
p->finL != NULL ||
p->finG != NULL) {
1372 ERROR(
"Conflict: classical=1 specified, but finL or finG was also provided.");
1374 if (
p->spaL != NULL) {
1376 fprintf(stderr,
"# Warning: classical=1 specified, discarding L matrix (logical operators)\n");
1381 if (
p->spaL == NULL) {
1382 ERROR(
"L matrix (logical operators) is required for quantum code (classical=0).\n"
1383 "Provide finL, fdem, or finG to construct it. Alternatively, set classical=1 "
1384 "to find the distance of the stabilizer code as a classical code.");
1393 if (
p->sort_rows < 0)
1394 p->sort_rows =
p->fdem ? 0 : 1;
1396 p->rows_sorted = csr_sort_rows_by_weight(
p->spaH);
1398 csr_dump(stderr,
p->spaH,
"H (rows sorted by weight)",
p->debug);
1401 if ((
p->method <= 0) || (
p->method > 3)){
1402 fprintf(stderr,
"%s: invalid method=%d specified\n\n", argv[0],
p->method);
1408 print_input_summary(stderr,
p);
1410 print_code_params(stderr,
p);
1412 if ((
p->debug &
DBG_SUMMARY) && !
p->fdem && (
p->method & 2) &&
p->smax == 0) {
1413 fprintf(stderr,
"# Warning: smax=0, confinement profile is not computed\n");
1420 fprintf(stderr,
"# WARNING: ortho=0 (expert option): the rows of H and G are not checked for orthogonality\n"
1421 "# (H G^T = 0); the result is valid only if they are orthogonal\n");
1423 fprintf(stderr,
"# WARNING: ortho=0 is ignored without finG (the check H G^T = 0 needs G)\n");
1426 const int d0 = (
p->dmin > 1) ?
p->dmin : 1;
1429 "# WARNING: noscan=1 (expert option): CC checks only weight w=wmax=%d; weights %d..%d are not\n"
1430 "# scanned, so a codeword found only gives an upper bound (dmax), and dmin=%d is not raised\n",
1431 p->wmax, d0,
p->wmax - 1, d0);
1434 "# WARNING: noscan=1 (expert option): CC checks only weight w=wmax=%d; the result relies on\n"
1435 "# the supplied dmin=%d being a certified lower bound\n",
p->wmax,
p->dmin);
1437 if (
p->start_num > 0) {
1438 fprintf(stderr,
"# WARNING: start=");
1439 for (
int k = 0; (k <
p->start_num) && (k < 8); k++)
1440 fprintf(stderr,
"%s%d", k ?
"," :
"", col_orig_index(
p,
p->start_list[k]));
1443 "%s start_scan=1 (expert options): CC clusters are grown only from %d listed column(s), each with\n"
1444 "# the larger columns only; dmin is valid only if a code symmetry maps every minimum-weight codeword\n"
1445 "# to one whose smallest column is listed\n",
1446 (
p->start_num > 8) ?
",..." :
"",
p->start_num);
1449 "%s (expert option): CC clusters are grown only from %d listed column(s)\n"
1450 "# (not limited to larger column indices); dmin is valid only if a code symmetry maps every\n"
1451 "# minimum-weight codeword to one containing a listed column\n",
1452 (
p->start_num > 8) ?
",..." :
"",
p->start_num);
1454 if (
p->cbeg >= 0 ||
p->cend >= 0) {
1455 const int beg = (
p->cbeg >= 0) ?
p->cbeg : 0;
1456 const int end = (
p->cend >= 0) ?
p->cend : n_orig - 1;
1458 "# WARNING: cbeg/cend (expert option for split runs): CC starts only from columns [%d,%d];\n"
1459 "# dmin only covers codewords whose smallest column is in this range; take the minimum of\n"
1460 "# dmin (and of dmax) over runs covering all columns 0..%d\n", beg, end, n_orig - 1);
1463 for (
int j = 0; j <
p->nvar; j++) {
1464 if (
p->col_orig[j] < beg) b = j + 1;
1465 if (
p->col_orig[j] <= end) e = j;
1471 if ((
p->win_hyb > 0) && (
p->method & 1)) {
1473 fprintf(stderr,
"# WARNING: win_hyb=%d is ignored with kwin=%d (a window of kwin columns on every RW step)\n",
1474 p->win_hyb,
p->kwin);
1475 else if (
p->nvar < 500)
1476 fprintf(stderr,
"# WARNING: win_hyb=%d is ignored for n=%d < 500 (uniform permutations in all RW steps)\n",
1477 p->win_hyb,
p->nvar);
1479 if ((
p->pairs > 0) && (
p->ksub > 0) && (
p->method & 1))
1480 fprintf(stderr,
"# WARNING: pairs=%d is ignored with ksub=%d (no RW pairs with the experimental ksub)\n",
p->pairs,
1483 if (
p->ksub > 0 && (
p->method & 1)) {
1485 "# WARNING: ksub=%d is experimental and should not be used: a RW step reduces the span of ksub rows\n"
1486 "# of a fixed basis of ker(H), so that a few codewords are found much more often than others; with\n"
1487 "# min_hits, RW may end early, and exp(-<n>) underestimates the probability to miss a lighter codeword\n",
1493 if (
p->start_list) {
1494 free(
p->start_list);
1495 p->start_list = NULL;
1500 p->col_orig =
p->col_class = NULL;
1502 p->drop_list = NULL;
1510 if (strlen(
p->fin) != 0) {
1532 p->cw_hits_w = NULL;
1541static dem_program_t *read_dem_to_program(
const char *fnam) {
1542 FILE *f = fopen(fnam,
"r");
1544 printf(
"FILE I/O ERROR: %s\n", strerror(errno));
1545 ERROR(
"can't open the (DEM) file %s for reading\n", fnam);
1557 while ((linelen = getline(&buf, &bufsiz, f)) >= 0) {
1558 if (linelen > 0 && buf[linelen - 1] ==
'\n') {
1559 buf[linelen - 1] =
'\0';
1565 prog->
lines[prog->
size++] = strdup(buf);
1573 for (
int i = 0; i < prog->
size; i++) {
1574 free(prog->
lines[i]);
1583static int dem_line_mod2(
int_pair *
const e,
const int cnt) {
1584 for (
int i = 1; i < cnt; i++) {
1587 while (j >= 0 && e[j].a > x.
a) {
1594 for (
int i = 0; i < cnt;) {
1595 if (i + 1 < cnt && e[i].a == e[i + 1].a) {
1604static void parse_instructions(
dem_program_t *prog,
int *p_line_idx,
1605 int *p_iD,
int_pair **p_inH,
int *p_maxH,
int *p_r,
1606 int *p_iL,
int_pair **p_inL,
int *p_maxL,
int *p_k,
1607 int *p_n,
double pmin,
int *p_detector_shift,
int debug) {
1608 while (*p_line_idx < prog->size) {
1609 char *line = prog->
lines[*p_line_idx];
1613 while (isspace(*c)) c++;
1615 if (*c ==
'\0' || *c ==
'#')
continue;
1626 if (sscanf(c,
"repeat %d { %n", &val, &num) == 1) {
1627 int start_idx = *p_line_idx;
1628 int temp_idx = start_idx;
1629 for (
int r = 0; r < val; r++) {
1630 temp_idx = start_idx;
1631 parse_instructions(prog, &temp_idx,
1632 p_iD, p_inH, p_maxH, p_r,
1633 p_iL, p_inL, p_maxL, p_k,
1634 p_n, pmin, p_detector_shift, debug);
1637 *p_line_idx = temp_idx;
1640 while (*p_line_idx < prog->size && depth > 0) {
1641 char *s = prog->
lines[*p_line_idx];
1643 while (isspace(*s)) s++;
1644 if (strncmp(s,
"repeat", 6) == 0 && strchr(s,
'{')) depth++;
1645 if (*s ==
'}') depth--;
1653 if (sscanf(c,
"shift_detectors ( %*[^)] ) %d %n", &shift_val, &num) == 1) {
1654 *p_detector_shift += shift_val;
1656 }
else if (sscanf(c,
"shift_detectors %d %n", &shift_val, &num) == 1) {
1657 *p_detector_shift += shift_val;
1662 if (sscanf(c,
"error( %lg ) %n", &prob, &num) == 1) {
1663 if ((prob <= 0) || (prob >= 1))
1664 ERROR(
"probability should be in (0,1) exclusive p=%g\n"
1665 "line %d: '%s'\n", prob, *p_line_idx, line);
1671 const int iD0 = *p_iD, iL0 = *p_iL;
1674 while (isspace(c[0])) c++;
1675 if (c[0] ==
'\0' || c[0] ==
'#' || c[0] ==
'\n')
break;
1678 if (sscanf(c,
"D%d%n", &val, &num) == 1) {
1681 int shifted_val = val + *p_detector_shift;
1682 if (shifted_val >= *p_r)
1683 *p_r = shifted_val + 1;
1684 if (*p_iD >= *p_maxH) {
1685 *p_maxH = 2 * (*p_maxH);
1686 *p_inH = realloc(*p_inH, (*p_maxH) *
sizeof(**p_inH));
1688 (*p_inH)[*p_iD].a = shifted_val;
1689 (*p_inH)[*p_iD].b = *p_n;
1691 }
else if (sscanf(c,
"L%d%n", &val, &num) == 1) {
1696 if (*p_iL >= *p_maxL) {
1697 *p_maxL = 2 * (*p_maxL);
1698 *p_inL = realloc(*p_inL, (*p_maxL) *
sizeof(**p_inL));
1700 (*p_inL)[*p_iL].a = val;
1701 (*p_inL)[*p_iL].b = *p_n;
1703 }
else if (c[0] ==
'^') {
1706 ERROR(
"unrecognized entry %s in error line %d: '%s'\n", c, *p_line_idx, line);
1710 *p_iD = iD0 + dem_line_mod2(*p_inH + iD0, *p_iD - iD0);
1711 *p_iL = iL0 + dem_line_mod2(*p_inL + iL0, *p_iL - iL0);
1716 if (strncmp(c,
"detector", 8) == 0) {
1720 if (strncmp(c,
"logical_observable", 18) == 0) {
1724 ERROR(
"unrecognized DEM entry in line %d: '%s'\n", *p_line_idx, line);
1731 int maxH=100, maxL=100;
1735 ERROR(
"memory allocation failed\n");
1737 int r=-1, k=-1, n=0;
1739 int detector_shift = 0;
1742 parse_instructions(prog, &line_idx,
1743 &iD, &inH, &maxH, &r,
1744 &iL, &inL, &maxL, &k,
1745 &n, pmin, &detector_shift, debug);
1747 if (line_idx < prog->size) {
1748 ERROR(
"Unmatched '}' in DEM file %s at line %d\n", fnam, line_idx);
1752 fprintf(stderr,
"# read DEM %s: rows_H=%d rows_L=%d cols=%d; nz_H=%d nz_L=%d\n",fnam,r,k,n,iD,iL);
1753 if((r<=0)||(k<=0)||(n<=0))
1754 ERROR(
"invalid DEM file %s: rows_H=%d rows_L=%d cols=%d; nz_H=%d nz_L=%d\n",
1762 free_dem_program(prog);
1766static inline uint64_t dem_hash64(uint64_t z) {
1767 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
1768 z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
1769 return z ^ (z >> 31);
1777static int dem_col_hash_cmp(
const void *a,
const void *b) {
1779 if (x->
h != y->h)
return (x->
h < y->h) ? -1 : 1;
1780 return (x->
j > y->j) - (x->
j < y->j);
1784static int dem_cols_equal(
const csr_t *
const HT,
const csr_t *
const LT,
const int a,
const int b) {
1785 const int wh = HT->
p[a + 1] - HT->
p[a], wl = LT->
p[a + 1] - LT->
p[a];
1786 if ((wh != HT->
p[b + 1] - HT->
p[b]) || (wl != LT->
p[b + 1] - LT->
p[b]))
return 0;
1787 return (memcmp(HT->
i + HT->
p[a], HT->
i + HT->
p[b], (
size_t)wh *
sizeof(
int)) == 0) &&
1788 (memcmp(LT->
i + LT->
p[a], LT->
i + LT->
p[b], (
size_t)wl *
sizeof(
int)) == 0);
1793static csr_t * csr_keep_columns(
const csr_t *
const M,
const int *
const keep,
const int ncols) {
1795 for (
int t = 0; t < M->
p[M->
rows]; t++) nz += (keep[M->
i[t]] >= 0);
1798 for (
int r = 0; r < M->
rows; r++) {
1800 for (
int t = M->
p[r]; t < M->
p[r + 1]; t++)
1801 if (keep[M->
i[t]] >= 0) R->
i[t2++] = keep[M->
i[t]];
1814static void dem_merge_columns(
params_t *
const p) {
1815 const int n =
p->spaH->cols;
1820 int *
const rep = malloc((
size_t)n *
sizeof(
int));
1821 if (!ch || !rep)
ERROR(
"memory allocation");
1822 for (
int j = 0; j < n; j++) {
1824 for (
int t = HT->
p[j]; t < HT->
p[j + 1]; t++) h ^= dem_hash64(2 * (uint64_t)HT->
i[t] + 1);
1825 for (
int t = LT->
p[j]; t < LT->
p[j + 1]; t++) h ^= dem_hash64(2 * (uint64_t)LT->
i[t] + 2);
1831 const int strip_zero_hl = (
p->classical != 1 &&
p->smax == 0);
1832 for (
int a = 0; a < n;) {
1834 while (b < n && ch[b].h == ch[a].h) b++;
1835 for (
int s = a; s < b; s++) {
1836 const int j = ch[s].
j;
1837 if (strip_zero_hl && HT->
p[j + 1] == HT->
p[j] && LT->
p[j + 1] == LT->
p[j]) {
1842 for (
int t = a; t < s; t++) {
1843 const int i = ch[t].
j;
1844 if (rep[i] == i && dem_cols_equal(HT, LT, i, j)) {
1849 if (rep[j] == j) nclass++;
1856 if (nclass == n || nclass == 0) {
1860 int *
const col_class = malloc((
size_t)n *
sizeof(
int));
1861 int *
const col_orig = malloc((
size_t)nclass *
sizeof(
int));
1862 int *
const keep = malloc((
size_t)n *
sizeof(
int));
1863 if (!col_class || !col_orig || !keep)
ERROR(
"memory allocation");
1864 for (
int j = 0, c = 0; j < n; j++) {
1867 col_class[j] = keep[j] = c++;
1868 }
else if (rep[j] >= 0) {
1869 col_class[j] = col_class[rep[j]];
1872 col_class[j] = keep[j] = -1;
1875 csr_t *
const H2 = csr_keep_columns(
p->spaH, keep, nclass);
1876 csr_t *
const L2 = csr_keep_columns(
p->spaL, keep, nclass);
1882 p->nvar_merged = nclass;
1883 p->col_orig = col_orig;
1884 p->col_class = col_class;
1890static int csr_rows_equal(
const csr_t *
const M,
const int a,
const int b) {
1891 const int w = M->
p[a + 1] - M->
p[a];
1892 return (w == M->
p[b + 1] - M->
p[b]) && (memcmp(M->
i + M->
p[a], M->
i + M->
p[b], (
size_t)w *
sizeof(
int)) == 0);
1897static int dem_kept_equal(
const csr_t *
const HT,
const char *
const inM,
const int j,
const int t) {
1899 for (
int u = HT->
p[j]; u < HT->
p[j + 1]; u++) {
1900 if (inM[HT->
i[u]])
continue;
1901 if (s >= HT->
p[t + 1] || HT->
i[s] != HT->
i[u])
return 0;
1904 return s == HT->
p[t + 1];
1908static csr_t * csr_keep_rows(
const csr_t *
const M,
const int *
const keep,
const int nrows) {
1910 for (
int r = 0; r < M->
rows; r++)
1911 if (keep[r] >= 0)
nz += M->
p[r + 1] - M->
p[r];
1914 for (
int r = 0; r < M->
rows; r++) {
1915 if (keep[r] < 0)
continue;
1917 for (
int t = M->
p[r]; t < M->
p[r + 1]; t++) R->
i[t2++] = M->
i[t];
1927static int dem_read_drop_list(
const char fnam[],
const int m,
char *
const inM) {
1928 FILE *
const f = fopen(fnam,
"r");
1930 ERROR(
"can't open the drop file '%s' for reading: %s", fnam, strerror(errno));
1933 int num = 0, lineno = 0;
1934 while (getline(&line, &cap, f) != -1) {
1937 while (isspace((
unsigned char)*s)) s++;
1938 if (*s ==
'#' || *s ==
'%')
continue;
1939 for (
char *tok = strtok(s,
" \t\r\n,"); tok; tok = strtok(NULL,
" \t\r\n,")) {
1942 const long v = strtol(tok, &end, 10);
1943 if ((*end !=
'\0') || errno || (v < 0) || (v > INT_MAX))
1944 ERROR(
"drop file '%s', line %d: invalid entry '%s' (expected 0-based detector indices)", fnam, lineno, tok);
1945 if ((v < m) && !inM[v]) {
1957static const char * drop_label(
const params_t *
const p) {
1958 return (
p->drop_mode == 1) ?
"auto" : ((
p->drop_mode == 2) ?
p->fdrop :
"0");
1963static double drop_wall_time(
void) {
1965 clock_gettime(CLOCK_MONOTONIC, &ts);
1966 return (
double)ts.tv_sec + 1e-9 * (double)ts.tv_nsec;
1976static void drop_queue_push(
drop_queue_t *
const Q,
const int j) {
1977 if (Q->
in[j])
return;
1983 const int j = Q->
q[Q->
head];
1990static int drop_find(
int *
const parent,
int x) {
1991 while (parent[x] != x) {
1992 parent[x] = parent[parent[x]];
2002static int drop_group_cmp(
const void *a,
const void *b) {
2004 if (x->
size != y->size)
return (x->
size < y->size) ? 1 : -1;
2005 return (x->
root > y->root) - (x->
root < y->root);
2022static int dem_drop_auto(
const params_t *
const p,
char *
const inM) {
2023 const csr_t *
const H =
p->spaH;
2024 const int m = H->
rows, n = H->
cols;
2025 const double t0 = (
p->debug &
DBG_TIMING) ? drop_wall_time() : 0.0;
2028 int *
const fp = calloc((
size_t)m + 2,
sizeof(
int));
2029 int *
const fi = malloc(((
size_t)n + 1) *
sizeof(
int));
2030 int *
const stamp = calloc((
size_t)m + 1,
sizeof(
int));
2031 char *
const posv = malloc((
size_t)m + 1);
2032 int *
const sp = malloc(((
size_t)n + 1) *
sizeof(
int));
2033 char *
const big = calloc((
size_t)n + 1, 1);
2034 if (!fp || !fi || !stamp || !posv || !sp || !big)
ERROR(
"memory allocation");
2035 for (
int j = 0; j < n; j++)
2036 if (HT->
p[j + 1] > HT->
p[j]) fp[HT->
i[HT->
p[j]] + 1]++;
2037 for (
int r = 0; r < m; r++) fp[r + 1] += fp[r];
2038 for (
int j = 0, *cnt = fp; j < n; j++)
2039 if (HT->
p[j + 1] > HT->
p[j]) fi[cnt[HT->
i[HT->
p[j]]]++] = j;
2040 for (
int r = m; r > 0; r--) fp[r] = fp[r - 1];
2042 size_t cap = (size_t)n + 16, ns = 0;
2043 int *st = malloc(cap *
sizeof(
int));
2044 uint64_t *sm = malloc(cap *
sizeof(uint64_t));
2045 if (!st || !sm)
ERROR(
"memory allocation");
2046 for (
int j = 0; j < n; j++) {
2048 const int b = HT->
p[j], w = HT->
p[j + 1] - b;
2049 if (w > 64) big[j] = 1;
2050 if ((w < 2) || (w > 64))
continue;
2051 for (
int u = 0; u < w; u++) {
2052 stamp[HT->
i[b + u]] = j + 1;
2053 posv[HT->
i[b + u]] = (char)u;
2055 for (
int u = 0; u < w; u++) {
2056 const int r = HT->
i[b + u];
2057 for (
int s = fp[r]; s < fp[r + 1]; s++) {
2058 const int t = fi[s], bt = HT->
p[t], wt = HT->
p[t + 1] - bt;
2059 if ((wt >= w) || (stamp[HT->
i[bt + wt - 1]] != j + 1) || !csr_rows_equal(LT, j, t))
continue;
2062 for (; (v < wt) && (stamp[HT->
i[bt + v]] == j + 1); v++) mask |= 1ULL << posv[HT->
i[bt + v]];
2063 if (v < wt)
continue;
2066 st = realloc(st, cap *
sizeof(
int));
2067 sm = realloc(sm, cap *
sizeof(uint64_t));
2068 if (!st || !sm)
ERROR(
"memory allocation");
2081 int *
const parent = malloc(((
size_t)m + 1) *
sizeof(
int));
2082 char *
const state = calloc((
size_t)m + 1, 1);
2083 char *
const keepg = calloc((
size_t)m + 1, 1);
2084 if (!parent || !state || !keepg)
ERROR(
"memory allocation");
2085 for (
int r = 0; r < m; r++) parent[r] = r;
2086 for (
int j = 0; j < n; j++) {
2087 const int b = HT->
p[j], w = HT->
p[j + 1] - b;
2088 if ((w == 0) || big[j] || (sp[j + 1] > sp[j]))
continue;
2089 const int r0 = drop_find(parent, HT->
i[b]);
2090 for (
int u = 1; u < w; u++) {
2091 const int r = drop_find(parent, HT->
i[b + u]);
2092 if (r != r0) parent[r] = r0;
2095 for (
int j = 0; j < n; j++) {
2096 const int b = HT->
p[j], w = HT->
p[j + 1] - b;
2097 if (w == 0)
continue;
2099 for (
int u = 0; u < w; u++) keepg[drop_find(parent, HT->
i[b + u])] = 1;
2100 }
else if ((sp[j + 1] == sp[j]) && (LT->
p[j + 1] > LT->
p[j])) {
2101 keepg[drop_find(parent, HT->
i[b])] = 1;
2104 int *
const gsize = calloc((
size_t)m + 1,
sizeof(
int));
2105 if (!gsize)
ERROR(
"memory allocation");
2106 for (
int r = 0; r < m; r++)
2107 parent[r] = drop_find(parent, r);
2108 for (
int r = 0; r < m; r++)
2109 if (H->
p[r + 1] == H->
p[r]) keepg[r] = 1;
2110 for (
int r = 0; r < m; r++) {
2111 const int g = parent[r];
2113 if (keepg[g]) state[r] =
DROP_NO;
2116 for (
int r = 0; r < m; r++) ng += (parent[r] == r) && !keepg[r];
2118 int *
const gp = calloc((
size_t)m + 2,
sizeof(
int));
2119 int *
const gi = malloc(((
size_t)m + 1) *
sizeof(
int));
2120 if (!grp || !gp || !gi)
ERROR(
"memory allocation");
2121 for (
int r = 0, g = 0; r < m; r++)
2122 if ((parent[r] == r) && !keepg[r]) grp[g++] = (
drop_group_t){.root = r, .size = gsize[r]};
2124 for (
int r = 0; r < m; r++) gp[parent[r] + 1]++;
2125 for (
int r = 0; r < m; r++) gp[r + 1] += gp[r];
2126 for (
int r = 0, *cnt = gsize; r < m; r++) cnt[r] = gp[r];
2127 for (
int r = 0; r < m; r++) gi[gsize[parent[r]]++] = r;
2129 drop_queue_t Q = {.q = malloc(((
size_t)n + 1) *
sizeof(
int)), .in = calloc((
size_t)n + 1, 1), .n = n + 1};
2130 int *
const ulog = malloc(((
size_t)m + 1) *
sizeof(
int));
2131 if (!Q.
q || !Q.
in || !ulog)
ERROR(
"memory allocation");
2132 int n_ok = 0, n_fail = 0, n_unver = 0;
2133 long long int work = 0;
2134 const long long int work_max = 64LL * (HT->
p[n] + n) + 1000000LL;
2135 for (
int g = 0; g < ng; g++) {
2136 const int g0 = gp[grp[g].
root], g1 = gp[grp[g].root + 1];
2137 int unk = (g0 < g1);
2138 for (
int s = g0; (s < g1) && unk; s++) unk = (state[gi[s]] ==
DROP_UNK);
2140 if (work > work_max)
break;
2141 int nlog = 0, fail = 0;
2142 for (
int s = g0; s < g1; s++) {
2143 const int r = gi[s];
2146 for (
int t = H->
p[r]; t < H->
p[r + 1]; t++) drop_queue_push(&Q, H->
i[t]);
2149 const int j = drop_queue_pop(&Q);
2152 const int b = HT->
p[j], w = HT->
p[j + 1] - b;
2153 if (big[j])
continue;
2154 uint64_t md = 0, mk = 0, mu = 0;
2155 for (
int u = 0; u < w; u++) {
2156 const char s = state[HT->
i[b + u]];
2157 if (s ==
DROP_YES) md |= 1ULL << u;
2158 else if (s ==
DROP_NO) mk |= 1ULL << u;
2159 else mu |= 1ULL << u;
2162 uint64_t any = 0, all = ~0ULL;
2164 for (
int s = sp[j]; s < sp[j + 1]; s++) {
2165 if ((sm[s] & md) || ((sm[s] & mk) != mk))
continue;
2170 if ((LT->
p[j + 1] == LT->
p[j]) && !mk) {
2178 const uint64_t fd = mu & ~any, fk = mu & all;
2179 for (
int u = 0; u < w; u++) {
2180 if (!((fd | fk) & (1ULL << u)))
continue;
2181 const int r = HT->
i[b + u];
2184 for (
int t = H->
p[r]; t < H->
p[r + 1]; t++) drop_queue_push(&Q, H->
i[t]);
2188 for (
int l = 0; (l < nlog) && !fail; l++) {
2189 const int r = ulog[l];
2190 if (state[r] !=
DROP_YES)
continue;
2191 for (
int t = H->
p[r]; (t < H->
p[r + 1]) && !fail; t++) {
2192 const int j = H->
i[t], b = HT->
p[j], w = HT->
p[j + 1] - b;
2194 for (
int u = 0; u < w; u++)
2195 if (state[HT->
i[b + u]] !=
DROP_YES) mo |= 1ULL << u;
2196 int ok = (mo == 0) && (LT->
p[j + 1] == LT->
p[j]);
2197 for (
int s = sp[j]; (s < sp[j + 1]) && !ok; s++) ok = (sm[s] == mo);
2203 for (
int l = 0; l < nlog; l++) state[ulog[l]] =
DROP_UNK;
2205 for (
int s = g0; s < g1; s++) state[gi[s]] =
DROP_NO;
2215 for (
int r = 0; r < m; r++)
2221 fprintf(stderr,
"# drop=auto: %d of %d detectors found (%d groups to try: %d dropped, %d kept, %d not verified%s; "
2222 "%zu sub-columns), %.3f s\n", num, m, ng, n_ok, n_fail, n_unver,
2223 (work > work_max) ?
", work limit reached" :
"", ns, drop_wall_time() - t0);
2245static void dem_write_drop_list(
const params_t *
const p) {
2246 FILE *
const f = fopen(
p->outD,
"w");
2248 ERROR(
"can't open the file outD='%s' for writing: %s",
p->outD, strerror(errno));
2249 const int m = (
p->ndrop > 0) ?
p->ndrop_rows :
p->spaH->
rows;
2250 fprintf(f,
"# %d of %d detectors dropped (drop=%s%s), 0-based\n",
p->ndrop, m,
2251 (
p->classical == 1) ?
"0, classical=1" : drop_label(
p),
p->drop_none ?
": none can be dropped exactly" :
"");
2252 for (
int i = 0; i <
p->ndrop; i++)
2253 fprintf(f,
"%d%c",
p->drop_list[i], ((i % 16 == 15) || (i ==
p->ndrop - 1)) ?
'\n' :
' ');
2256 fprintf(stderr,
"# wrote the %d detectors dropped to '%s'\n",
p->ndrop,
p->outD);
2270static void dem_drop_detectors(
params_t *
const p) {
2271 const int m =
p->spaH->rows, n =
p->spaH->cols, k =
p->spaL->rows;
2272 char *
const inM = calloc((
size_t)m + 1, 1);
2273 if (!inM)
ERROR(
"memory allocation");
2274 const char *
const label = drop_label(
p);
2275 const int num = (
p->drop_mode == 1) ? dem_drop_auto(
p, inM) : dem_read_drop_list(
p->fdrop, m, inM);
2277 if (
p->drop_mode == 1)
2280 fprintf(stderr,
"# Note: drop=%s: none of the listed detectors is in the DEM, nothing dropped\n", label);
2286 char *
const touch = calloc((
size_t)n + 1, 1);
2287 uint64_t *
const hk = malloc(((
size_t)n + 1) *
sizeof(uint64_t));
2289 int *
const twin = malloc(((
size_t)n + 1) *
sizeof(
int));
2290 if (!touch || !hk || !hs || !twin)
ERROR(
"memory allocation");
2292 for (
int j = 0; j < n; j++) {
2294 for (
int t = HT->
p[j]; t < HT->
p[j + 1]; t++) {
2295 if (inM[HT->
i[t]]) touch[j] = 1;
2296 else h ^= dem_hash64((uint64_t)HT->
i[t] + 1);
2308 int fail = -1, need_A = 0;
2309 const char *why = NULL;
2310 for (
int j = 0; (j < n) && (fail < 0); j++) {
2316 for (
int t = HT->
p[j]; t < HT->
p[j + 1]; t++) nk += !inM[HT->
i[t]];
2319 if (LT->
p[j + 1] > LT->
p[j]) need_A = 1;
2322 int lo = 0, hi = ns;
2324 const int mid = lo + (hi - lo) / 2;
2325 if (hs[mid].h < hk[j]) lo = mid + 1;
2329 for (
int s = lo; (s < ns) && (hs[s].
h == hk[j]); s++) {
2330 const int t = hs[s].
j;
2331 if (!dem_kept_equal(HT, inM, j, t))
continue;
2334 }
else if (!csr_rows_equal(LT, tw, t)) {
2336 why =
"it has two twins with different observables";
2340 if (fail >= 0)
break;
2343 why =
"no column with the same other detectors touches none of the dropped ones";
2347 if (!csr_rows_equal(LT, j, tw)) need_A = 1;
2349 if ((fail < 0) && need_A) {
2352 int *
const mind = malloc(((
size_t)m + 1) *
sizeof(
int));
2353 if (!mind)
ERROR(
"memory allocation");
2354 for (
int r = 0, c = 0; r < m; r++) mind[r] = inM[r] ? c++ : -1;
2355 mzd_t *
const E = mzd_init(nj, num + k);
2356 for (
int j = 0, row = 0; j < n; j++) {
2357 if (!touch[j])
continue;
2358 for (
int t = HT->
p[j]; t < HT->
p[j + 1]; t++)
2359 if (inM[HT->
i[t]]) mzd_write_bit(E, row, mind[HT->
i[t]], 1);
2360 for (
int t = LT->
p[j]; t < LT->
p[j + 1]; t++) mzd_flip_bit(E, row, num + LT->
i[t]);
2362 for (
int t = LT->
p[twin[j]]; t < LT->
p[twin[j] + 1]; t++) mzd_flip_bit(E, row, num + LT->
i[t]);
2365 const int rank = mzd_echelonize(E, 0);
2366 for (
int r = 0; (r < rank) && (fail < 0); r++) {
2368 while ((c < num) && !mzd_read_bit(E, r, c)) c++;
2371 why =
"the observables of the twins are not L + A H for any matrix A";
2379 fprintf(stderr,
"# Note: drop=%s not used: column %d (1-based) touches a dropped detector, but %s; using the "
2380 "full DEM\n", label, 1 + col_orig_index(
p, fail), why);
2382 fprintf(stderr,
"# Note: drop=%s not used: %s; using the full DEM\n", label, why);
2384 int *
const keepcol = malloc(((
size_t)n + 1) *
sizeof(
int));
2385 int *
const keeprow = malloc(((
size_t)m + 1) *
sizeof(
int));
2386 if (!keepcol || !keeprow)
ERROR(
"memory allocation");
2388 for (
int j = 0; j < n; j++) keepcol[j] = touch[j] ? -1 : n2++;
2389 for (
int r = 0; r < m; r++) keeprow[r] = inM[r] ? -1 : m2++;
2390 const int n_orig = (
p->nvar_orig > 0) ?
p->nvar_orig : n;
2391 int *
const col_orig = malloc(((
size_t)n2 + 1) *
sizeof(
int));
2392 int *
const col_class = malloc(((
size_t)n_orig + 1) *
sizeof(
int));
2393 if (!col_orig || !col_class)
ERROR(
"memory allocation");
2394 for (
int j = 0; j < n; j++)
2395 if (keepcol[j] >= 0) col_orig[keepcol[j]] = col_orig_index(
p, j);
2396 for (
int o = 0; o < n_orig; o++) {
2397 const int c =
p->col_class ?
p->col_class[o] : o;
2398 col_class[o] = (c >= 0 && twin[c] >= 0) ? keepcol[twin[c]] : -1;
2400 csr_t *
const H1 = csr_keep_columns(
p->spaH, keepcol, n2);
2401 csr_t *
const H2 = csr_keep_rows(H1, keeprow, m2);
2402 csr_t *
const L2 = csr_keep_columns(
p->spaL, keepcol, n2);
2410 p->col_orig = col_orig;
2411 p->col_class = col_class;
2412 p->nvar_orig = n_orig;
2417 p->drop_list = malloc(((
size_t)num + 1) *
sizeof(
int));
2418 if (!
p->drop_list)
ERROR(
"memory allocation");
2419 for (
int r = 0, c = 0; r < m; r++)
2420 if (inM[r])
p->drop_list[c++] = r;
2441static void dem_round_estimate(
params_t *
const p) {
2442 const int m =
p->spaH->rows, n =
p->spaH->cols;
2443 p->round_D =
p->round_L = 0;
2444 p->round_score = 0.0;
2445 if ((m < 6) || (n < 2))
return;
2447 int *
const cnt = calloc((
size_t)m,
sizeof(
int));
2448 if (!cnt)
ERROR(
"memory allocation");
2449 for (
int j = 0; j < n; j++)
2450 if (HT->
p[j + 1] - HT->
p[j] == 2)
2451 cnt[HT->
i[HT->
p[j] + 1] - HT->
i[HT->
p[j]]]++;
2453 int cand[NCAND], ncand = 0;
2454 for (
int D = 2; D <= m / 3; D++) {
2455 if ((cnt[D] == 0) || ((ncand == NCAND) && (cnt[D] <= cnt[cand[NCAND - 1]])))
continue;
2456 int k = (ncand < NCAND) ? ncand++ : NCAND - 1;
2457 for (; (k > 0) && (cnt[cand[k - 1]] < cnt[D]); k--)
2458 cand[k] = cand[k - 1];
2465 while (size < 2 * (
size_t)n) size <<= 1;
2466 uint64_t *
const key = malloc((
size_t)m *
sizeof(uint64_t));
2467 uint64_t *
const hcol = malloc((
size_t)n *
sizeof(uint64_t));
2468 int *
const table = malloc(size *
sizeof(
int));
2469 if (!key || !hcol || !table)
ERROR(
"memory allocation");
2470 for (
int d = 0; d < m; d++) key[d] = dem_hash64((uint64_t)d + 1);
2471 for (
size_t s = 0; s < size; s++) table[s] = -1;
2472 for (
int j = 0; j < n; j++) {
2474 for (
int t = HT->
p[j]; t < HT->
p[j + 1]; t++) h ^= key[HT->
i[t]];
2476 if (HT->
p[j + 1] > HT->
p[j]) {
2477 size_t s = (size_t)h & (size - 1);
2478 while (table[s] >= 0) s = (s + 1) & (size - 1);
2483 for (
int c = 0; c < ncand; c++) {
2484 const int D = cand[c];
2485 long tot = 0, hit = 0;
2486 for (
int j = 0; j < n; j++) {
2487 const int *
const dj = HT->
i + HT->
p[j];
2488 const int w = HT->
p[j + 1] - HT->
p[j];
2489 if ((w == 0) || (dj[w - 1] + D >= m))
continue;
2492 for (
int t = 0; t < w; t++) h ^= key[dj[t] + D];
2493 for (
size_t s = (
size_t)h & (size - 1); table[s] >= 0; s = (s + 1) & (size - 1)) {
2494 const int i = table[s];
2495 const int *
const di = HT->
i + HT->
p[i];
2496 if ((hcol[i] != h) || (HT->
p[i + 1] - HT->
p[i] != w))
continue;
2498 while ((t < w) && (di[t] == dj[t] + D)) t++;
2505 const double score = (tot > 0) ? (
double)hit / (double)tot : 0.0;
2506 if (score >
p->round_score) {
2507 p->round_score = score;
2515 if (
p->round_score >= 0.5) {
2516 const long L = lround((
double)n * best_D / m);
2517 p->round_D = best_D;
2518 p->round_L = (L > 1) ? (
int)L : 1;
2523 FILE *f=fopen(fnam,
"w");
2525 fprintf(stderr,
"FILE I/O ERROR: %s\n", strerror(errno));
2526 ERROR(
"can't open file %s for writing",fnam);
2528 fprintf(f,
"%%%% NZLIST\n");
2530 fprintf(f,
"%% %s\n",comment);
2535 assert(vec && vec->
weight >0 );
2538 if(fprintf(f,
"%d ",w)<=0)
2539 ERROR(
"can't write to `NZLIST` file");
2540 for(
int i=0; i < w; i++)
2541 if(fprintf(f,
" %d%s", 1 + col_orig_index(&
prm, vec->
arr[i]), i+1 < w ?
"" :
"\n")<=0)
2542 ERROR(
"can't write to `NZLIST` file");
2547 FILE *f=fopen(fnam,
"r");
2568 if ( ferror (f)|| feof(f) )
2585 if(fscanf(f,
" %d",&w) != 1){
2586 if (feof(f))
return NULL;
2587 fprintf(stderr,
"%s:%lld: invalid NZLIST entry\n", fnam, *lineno);
2588 ERROR(
"expected an integer");
2590 if ((vec!=NULL) && (vec->
weight<w)){
2595 vec = calloc(
sizeof(
cw_vec_t)+w*
sizeof(
int),
sizeof(
char));
2597 ERROR(
"memory allocation");
2601 for(
int i=0; i<w; i++){
2602 if(fscanf(f,
" %d ",vec->
arr + i) != 1){
2603 fprintf(stderr,
"%s:%lld: invalid entry of weight w=%d\n",fnam, *lineno, w);
2604 ERROR(
"expected an integer i=%d of %d",i,w);
2609 for(
int i=1; i<w; i++){
2610 if((vec->
arr[i-1] < 0) || (vec->
arr[i-1] >= vec->
arr[i])){
2611 fprintf(stderr,
"%s:%lld: invalid entry of weight w=%d\n",fnam, *lineno, w);
2612 ERROR(
"expected strictly increasing positive entries");
2620static inline int cw_collecting(
const params_t *
const p) {
2621 return (
p->outC != NULL) || (
p->maxC > 0);
2625static inline int cw_window_dw(
const params_t *
const p) {
2626 return (cw_collecting(
p) &&
p->dW > 0) ?
p->dW : 0;
2631static inline long long int cw_rep_size(
const params_t *
const p) {
2632 return (
p->min_hits > 0 &&
p->cov_cws > 0) ?
p->cov_cws : 0;
2636 if (
p->min_w == INT_MAX || !
p->cw_cnt_w)
return 0;
2637 const long long int top = (
long long int)
p->min_w + cw_window_dw(
p);
2638 const int w_top = (top <
p->cw_max_w) ? (
int)top :
p->cw_max_w;
2639 long long int num = 0;
2640 for (
int w =
p->min_w; w <= w_top; w++) num +=
p->cw_cnt_w[w];
2649 if (
p->min_hits <= 0)
return 0;
2650 if (
p->min_w == INT_MAX)
return INT_MAX;
2651 const long long int rep = cw_rep_size(
p);
2652 if (rep <= 0)
return p->min_w + 1;
2653 if (
p->num_cws < rep)
return INT_MAX;
2654 return p->cw_max_w + 1;
2659static void cw_trim(
params_t *
const p) {
2660 if (
p->min_w == INT_MAX ||
p->cw_max_w <=
p->min_w)
return;
2661 const long long int rep = cw_rep_size(
p);
2662 if (rep > 0 &&
p->num_cws <= rep)
return;
2663 const long long int top = (
long long int)
p->min_w + cw_window_dw(
p);
2664 if (top >=
p->cw_max_w)
return;
2665 int keep = (int)top;
2667 long long int cum = 0;
2668 int w_rep =
p->cw_max_w;
2669 for (
int w =
p->min_w; w < p->cw_max_w; w++) {
2670 cum +=
p->cw_cnt_w[w];
2676 if (w_rep > keep) keep = w_rep;
2678 if (keep >=
p->cw_max_w)
return;
2690 while (
p->cw_max_w >
p->min_w &&
p->cw_cnt_w[
p->cw_max_w] == 0)
p->cw_max_w--;
2694 if (weight <= 0 || weight >
p->nvar)
return p->codewords;
2696 p->cw_cnt_w = calloc((
size_t)
p->nvar + 2,
sizeof(
long long int));
2697 p->cw_hits_w = calloc((
size_t)
p->nvar + 2,
sizeof(
long long int));
2698 if (!
p->cw_cnt_w || !
p->cw_hits_w)
ERROR(
"memory allocation");
2701 const size_t keylen = weight *
sizeof(int);
2703 HASH_FIND(hh,
p->codewords, arr, keylen, pvec);
2708 p->cw_hits_w[weight]++;
2709 return p->codewords;
2713 if (weight < p->min_w) {
2715 }
else if ((
long long int)weight <= (
long long int)
p->min_w + cw_window_dw(
p)) {
2716 if (cw_collecting(
p))
2719 insert = (
p->cov_cws <= 0) || (
p->cw_cnt_w[weight] <
p->cov_cws);
2721 const long long int rep = cw_rep_size(
p);
2722 insert = (rep > 0) && (
p->num_cws < rep || weight < p->cw_max_w);
2724 if (!insert)
return p->codewords;
2727 if (!entry)
ERROR(
"memory allocation");
2732 memcpy(entry->
arr, arr, keylen);
2733 HASH_ADD(hh,
p->codewords, arr, keylen, entry);
2735 p->cw_cnt_w[weight]++;
2736 p->cw_hits_w[weight]++;
2737 if (weight >
p->cw_max_w)
p->cw_max_w = weight;
2738 if (weight < p->min_w)
p->min_w = weight;
2742 return p->codewords;
2746 double *avg_cnt,
double *stdev_cnt) {
2751 if (!
p || !
p->codewords ||
p->min_w == INT_MAX)
return;
2753 long long n_cws = 0;
2754 long long total_hits = 0;
2755 int c_min = INT_MAX;
2761 total_hits += cw->
cnt;
2762 if (cw->
cnt < c_min) c_min = cw->
cnt;
2763 if (cw->
cnt > c_max) c_max = cw->
cnt;
2766 if (n_cws <= 0)
return;
2768 double avg = (double)total_hits / (
double)n_cws;
2769 double sum_sq = 0.0;
2772 double diff = (double)cw->
cnt - avg;
2773 sum_sq += diff * diff;
2779 *stdev_cnt = sqrt(sum_sq / (
double)n_cws);
2792 const int nw = w_hi - w_lo + 1;
2794 if (!cs)
ERROR(
"memory allocation");
2795 for (
int i = 0; i < nw; i++) cs[i].c_min = INT_MAX;
2810 memset(st, 0,
sizeof(*st));
2811 if (
p->min_w == INT_MAX || !
p->cw_cnt_w ||
p->cw_cnt_w[
p->min_w] <= 0)
return;
2812 const long long int rep = cw_rep_size(
p);
2816 for (
int w =
p->min_w; w <= p->cw_max_w; w++) {
2817 if (
p->cw_cnt_w[w] <= 0)
continue;
2821 if (st->
set_cws >= rep)
break;
2825 st->
avg = (avg_set < avg_min) ? avg_set : avg_min;
2829 if (!stream || !
p)
return;
2830 if (
p->num_cws <= 0 || !
p->codewords ||
p->min_w == INT_MAX) {
2831 fprintf(stream,
"# codewords accumulated: total=0\n");
2835 const int w_lo =
p->min_w;
2836 const int w_hi = (
p->cw_max_w > w_lo) ?
p->cw_max_w : w_lo;
2839 int shown = 0, rest_classes = 0, rest_lo = 0, rest_hi = 0, rest_min = INT_MAX, rest_max = 0;
2840 long long rest_cws = 0, rest_hits = 0;
2841 for (
int w = w_lo; w <= w_hi; w++) {
2843 if (c->
n <= 0)
continue;
2844 const double avg = (double)c->
hits / (
double)c->
n;
2845 const double var = c->
sumsq / (double)c->
n - avg * avg;
2846 const double stdev = (var > 0.0) ? sqrt(var) : 0.0;
2849 "# codewords accumulated: total=%lld, min_w=%d: cws=%lld, total_hits=%lld, "
2850 "hits min=%d, max=%d, avg=%.2f, stdev=%.2f",
2852 if (
p->min_hits > 0) {
2855 fprintf(stream,
", <n>=%.2f over %lld cws of w=%d..%d (min_hits=%d, cov_cws=%d)",
2858 fprintf(stream,
"\n");
2859 }
else if ((
p->debug &
DBG_LARGE) || (shown < 4)) {
2862 "# codewords w=%d: cws=%lld, total_hits=%lld, "
2863 "hits min=%d, max=%d, avg=%.2f, stdev=%.2f\n",
2866 if (rest_classes++ == 0) rest_lo = w;
2869 rest_hits += c->
hits;
2870 if (c->
c_min < rest_min) rest_min = c->
c_min;
2871 if (c->
c_max > rest_max) rest_max = c->
c_max;
2874 if (rest_classes > 0)
2875 fprintf(stream,
"# codewords w=%d..%d: cws=%lld in %d weight classes, total_hits=%lld, hits min=%d, max=%d "
2876 "(each class with debug bit 2048)\n", rest_lo, rest_hi, rest_cws, rest_classes, rest_hits, rest_min,
2882 if (!stream || !
p || !
p->codewords ||
p->min_w == INT_MAX)
return;
2884 long long n[NW] = {0}, cws_u[NW] = {0}, hits_u[NW] = {0}, cws_w[NW] = {0}, hits_w[NW] = {0}, cws_b[NW] = {0};
2887 const int k = cw->
weight -
p->min_w;
2888 if (k < 0 || k >= NW)
continue;
2890 if (cw->
cnt_u > 0) {
2892 hits_u[k] += cw->
cnt_u;
2894 if (cw->
cnt_w > 0) {
2896 hits_w[k] += cw->
cnt_w;
2898 cws_b[k] += (cw->
cnt_u > 0) && (cw->
cnt_w > 0);
2900 for (
int k = 0; k < NW; k++)
2902 fprintf(stream,
"# RW step types, w=%d: uniform steps: cws=%lld, hits=%lld; window steps: cws=%lld, hits=%lld; "
2903 "both: cws=%lld (of %lld cws)\n",
p->min_w + k, cws_u[k], hits_u[k], cws_w[k], hits_w[k], cws_b[k], n[k]);
2907 if (
p->min_hits <= 0)
return 0;
2910 return (st.
set_cws > 0) && (st.
avg >= (double)
p->min_hits);
2915static double chi2_upper_tail(
const double x,
const long long int df) {
2916 if (!(x > 0.0))
return 1.0;
2917 if (df == 1)
return erfc(sqrt(0.5 * x));
2918 if (df == 2)
return exp(-0.5 * x);
2919 const double s = 2.0 / (9.0 * (double)df);
2920 const double z = (cbrt(x / (
double)df) - (1.0 - s)) / sqrt(s);
2921 return 0.5 * erfc(z / sqrt(2.0));
2926static double ztp_mu(
const double m) {
2928 for (
int it = 0; it < 200; it++) {
2929 const double e = exp(-mu);
2930 const double dg = 1.0 - m * e;
2931 if (!(dg > 0.0))
break;
2932 const double step = (mu - m * (1.0 - e)) / dg;
2934 if (fabs(step) <= 1e-12 * (1.0 + mu))
break;
2940 if (!
p ||
p->min_w == INT_MAX || !
p->cw_cnt_w)
return 0;
2943 if (st.
set_cws <= 0)
return 0;
2946 for (
int w = st.
w_lo; w <= st.
w_hi; w++) {
2948 if (c->
n < 2)
continue;
2949 const double n = (double)c->
n;
2950 const double m = (double)c->
hits / n;
2951 if (m <= 1.0 + 1e-9)
continue;
2952 double s2 = (c->
sumsq - n * m * m) / (n - 1.0);
2953 if (s2 < 0.0) s2 = 0.0;
2956 const double mu = ztp_mu(m);
2957 const double v0 = m * (1.0 + mu - m);
2958 if (!(mu > 0.0) || !(v0 > 0.0))
continue;
2959 const double pval = chi2_upper_tail((n - 1.0) * s2 / v0, c->
n - 1);
2960 const double cv2 = (s2 - v0) / (mu * mu);
2961 if (!(pval < 1e-3) || !(cv2 >= 1.0))
continue;
2965 const double p_unif = exp(-mu);
2966 const double p_spread = pow(1.0 + cv2 * mu, -1.0 / cv2);
2967 if (p_spread >= 3.0 * p_unif) {
2971 "# Warning: non-uniform RW hit counts of the %lld codewords of weight %d: hits min=%d, max=%d, "
2972 "avg=%.2f, stdev=%.2f (expected %.2f; p=%.1e)\n"
2973 "# some codewords are found much more often than others of the same weight (relative spread of "
2974 "hit rates %.2f):\n"
2975 "# a lighter codeword may be missed with probability ~%.2g rather than exp(-%.2f)=%.2g; "
2976 "consider a larger min_hits\n",
2977 c->
n, w, c->
c_min, c->
c_max, m, sqrt(s2), sqrt(v0), pval, sqrt(cv2), p_spread, mu, p_unif);
2986static double log_binom(
const double a,
const double b) {
2987 return lgamma(a + 1.0) - lgamma(b + 1.0) - lgamma(a - b + 1.0);
2991 const int k = n - rank;
2992 if (n <= 0 || rank < 0 || k <= 0 || w < 1 || w > n || w - 1 > rank)
return 0.0;
2994 double p = exp(log((
double)w) + log_binom(n - w, k - 1) - log_binom(n, k));
2996 if ((pairs_l > 0) && (w >= 2) && (k >= 2) && (w - 2 + pairs_l <= rank))
2997 p += exp(log_binom(w, 2) + log_binom(n - w, k - 2) - log_binom(n, k) + log_binom(rank - w + 2, pairs_l) -
2998 log_binom(rank, pairs_l));
2999 return (
p < 1.0) ?
p : 1.0;
3003static void format_duration(
char *
const buf,
const size_t size,
const double t) {
3004 if (t < 120.0) snprintf(buf, size,
"%.3g s", t);
3005 else if (t < 7200.0) snprintf(buf, size,
"%.3g min", t / 60.0);
3006 else if (t < 172800.0) snprintf(buf, size,
"%.3g h", t / 3600.0);
3007 else snprintf(buf, size,
"%.3g days", t / 86400.0);
3011 const long steps,
const long steps_total,
const double t_step,
const int pairs_l) {
3012 if (!stream || w_lo < 1 || w_hi < w_lo)
return;
3015 for (
int w = w_lo; w < w_hi; w++) {
3023 fprintf(stream,
"# information-set estimate: a codeword of weight %d cannot be found by RW (n=%d, rank(H)=%d)\n",
3027 const double lq = (p1 < 1.0) ? log1p(-p1) : -INFINITY;
3028 const double p_miss = (steps > 0) ? exp((
double)steps * lq) : 1.0;
3030 const double unif_steps_1pc = (p1 < 1.0) ? ceil(log(0.01) / lq) : 1.0;
3031 const double steps_1pc = (steps > 0 && steps_total > steps) ? ceil(unif_steps_1pc * steps_total / steps)
3033 char steps_str[32], time_str[64] =
"", pairs_str[48] =
"";
3034 snprintf(steps_str,
sizeof(steps_str), (steps_1pc < 1e9) ?
"%.0f" :
"%.3g", steps_1pc);
3037 format_duration(dur,
sizeof(dur), steps_1pc * t_step);
3038 snprintf(time_str,
sizeof(time_str),
", ~%s", dur);
3041 snprintf(pairs_str,
sizeof(pairs_str),
" with pairs (l=%d)", pairs_l);
3043 "# information-set estimate (uniform random information sets%s, n=%d, rank(H)=%d): a codeword of weight "
3045 "# is found with probability %.3g per RW step, missed in %ld uniform steps with probability %.2g "
3046 "(1%% after %s RW steps in total%s)\n",
3047 pairs_str, n, rank, w_hard, p1, steps, p_miss, steps_str, time_str);
3055static int codeword_reduce(
const params_t *
const p,
const csr_t *
const HT,
int arr[],
int w,
cols_ws_t *
const ws,
3056 int sub[],
int rest[]) {
3060 for (
int i = 0, j = 0; i < w; i++) {
3061 if (j < k && sub[j] == arr[i]) j++;
3062 else rest[nr++] = arr[i];
3064 const int nt_sub = !
p->maskL || colmask_syndrome_non_zero(
p->maskL, k, sub);
3065 const int nt_rest = !
p->maskL || colmask_syndrome_non_zero(
p->maskL, nr, rest);
3066 const int keep_sub = nt_sub && (!nt_rest || k <= nr);
3067 memcpy(arr, keep_sub ? sub : rest, (
size_t)(keep_sub ? k : nr) *
sizeof(
int));
3068 w = keep_sub ? k : nr;
3074 long long int count = 0, lineno;
3075 long long int skipped_invalid = 0, reduced = 0;
3078 int *sub = NULL, *rest = NULL;
3082 if ((
p->outC ==NULL) || (strcmp(fnam,
p->outC)!=0)){
3083 fprintf(stderr,
"codeword input file I/O ERROR: %s, outC=%s\n", strerror(errno),
p->outC);
3084 ERROR(
"can't open file %s for reading",fnam);
3090 const int n_orig = (
p->nvar_orig > 0) ?
p->nvar_orig :
p->nvar;
3096 int valid = (entry->
weight > 0) && (entry->
arr[entry->
weight - 1] < n_orig);
3097 if (valid &&
p->col_class) {
3099 for (
int i = 0; i < entry->
weight; i++) {
3100 const int c =
p->col_class[entry->
arr[i]];
3101 if (c >= 0) entry->
arr[w++] = c;
3103 qsort(entry->
arr, w,
sizeof(
int), cmp_int);
3106 for (
int i = 0; i < w0;) {
3107 if (i + 1 < w0 && entry->
arr[i] == entry->
arr[i + 1]) {
3110 entry->
arr[w++] = entry->
arr[i++];
3116 if (valid &&
p->spaH) {
3117 if (sparse_syndrome_non_zero(
p->spaH, entry->
weight, entry->
arr)) {
3121 if (valid &&
p->spaL) {
3122 if (!sparse_syndrome_non_zero(
p->spaL, entry->
weight, entry->
arr)) {
3126 if (valid &&
p->irred &&
p->spaH && entry->
weight > 1) {
3130 sub = malloc((
size_t)(
p->spaH->cols + 1) *
sizeof(
int));
3131 rest = malloc((
size_t)(
p->spaH->cols + 1) *
sizeof(
int));
3132 if (!sub || !rest)
ERROR(
"memory allocation");
3134 const int w0 = entry->
weight;
3135 entry->
weight = codeword_reduce(
p, HT, entry->
arr, w0, ws, sub, rest);
3136 if (entry->
weight < w0) reduced++;
3143 if((
p->wmax==0) ||((
p->wmax) && (entry->
weight <=
p->wmax))){
3144 const size_t keylen = entry->
weight *
sizeof(int);
3145 cw_vec_t *known = NULL, *added = NULL;
3160 if (skipped_invalid > 0) {
3162 "# Warning: skipped %lld invalid codewords (column out of range, not orthogonal to H, or orthogonal "
3167 fprintf(stderr,
"# read %lld codewords from %s, total %lld", count, fnam,
p->num_cws);
3168 if (
p->min_w != INT_MAX)
3169 fprintf(stderr,
", min weight %d",
p->min_w);
3171 fprintf(stderr,
"; %lld reducible codewords replaced by an irreducible part (irred=1)", reduced);
3172 fprintf(stderr,
"\n");
3187 if (!stream)
return;
3189 fprintf(stream,
"%s of weight %d (1-based columns):", prefix, weight);
3190 for (
int i = 0; i < max; i++)
3191 fprintf(stream,
" %d", col_orig_index(&
prm, arr[i]) + 1);
3193 fprintf(stream,
" ... (%d more)", weight - max);
3194 fprintf(stream,
"\n");
3198 long long int count=0;
3203 const long long int w_top = (
p->min_w == INT_MAX) ? 0 : (
long long int)
p->min_w + cw_window_dw(
p);
3206 for(pvec =
p->codewords; pvec != NULL; pvec = (
cw_vec_t *)(pvec->
hh.
next)){
3207 if (pvec->
weight > w_top)
continue;
Hit statistics for the min_hits stopping criterion, see codeword_hit_stats().
char name[HELP_MAX_NAMES][HELP_NAME_LEN]
char key[HELP_MAX_NAMES][HELP_NAME_LEN]
char member[HELP_MAX_MEMBERS][HELP_NAME_LEN]
#define HASH_DEL(head, delptr)
#define HASH_ITER(hh, head, el, tmp)
#define HASH_ADD(hh, head, fieldname, keylen_in, add)
#define HASH_FIND(hh, head, keyptr, keylen, out)
void read_dem_file(char *fnam, csr_t **p_spaH, csr_t **p_spaL, double pmin, int debug)
Read a Detector Error Model (DEM) file and construct H and L matrices.
long long int codeword_window_count(const params_t *const p)
Number of codewords in the collection window (weight up to min_w + dW with outC or maxC,...
void compute_min_w_hit_stats(const params_t *const p, int *min_cnt, int *max_cnt, double *avg_cnt, double *stdev_cnt)
Compute hit count statistics (min, max, avg, stdev) for minimum-weight codewords.
void codeword_hit_stats(const params_t *const p, cw_hit_stats_t *const st)
Compute the hit statistics of the min_hits stopping criterion.
int nzlist_w_append(FILE *f, const cw_vec_t *const vec)
int check_min_hits_convergence(const params_t *const p)
Check whether the QDistRnd-style hit count stopping condition is met.
FILE * nzlist_w_new(const char fnam[], const char comment[])
void print_short_help(const char *prog)
Print short help message listing all allowed parameters to stderr.
void var_kill(params_t *const p)
Clean up and free memory allocated in the params_t structure.
FILE * nzlist_r_open(const char fnam[], long long int *lineno)
double rw_infoset_find_prob(const int n, const int rank, const int w, const int pairs_l)
Information-set estimate of the probability that a RW step finds a given codeword of weight w.
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.
cw_vec_t * nzlist_r_one(FILE *f, cw_vec_t *vec, const char fnam[], long long int *lineno)
int codeword_maxc_reached(const params_t *const p)
Returns 1 if maxC > 0 and maxC codewords of the collection window are collected.
int codeword_feed_limit(const params_t *const p)
Weight limit (exclusive) of RW codewords needed for the min_hits statistic.
void print_rw_infoset_estimate(FILE *stream, const int n, const int rank, const int w_lo, const int w_hi, const long steps, const long steps_total, const double t_step, const int pairs_l)
Print the information-set estimate of the probability that RW missed a codeword lighter than the uppe...
void print_codeword_support(FILE *stream, const char *prefix, const int arr[], const int weight, const int debug)
Print the support of a codeword (1-based column indices) in one line, for DBG_CODEWORDS.
int codeword_hit_check(FILE *stream, const params_t *const p)
Check the uniformity of the hit counts within each weight class of the representative set.
void print_rw_step_stats(FILE *stream, const params_t *const p)
DBG_SUMMARY: the codewords of the lowest three weights in hash found by the RW steps with a uniform r...
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.
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.
void print_codeword_stats(FILE *stream, const params_t *const p)
Print accumulated codeword and hit statistics to the given stream.
void csr_dump(FILE *stream, const csr_t *const M, const char name[], const int debug)
Print a binary CSR matrix row by row ('1': nonzero, '.': zero), for DBG_MATRICES.
void var_init(int argc, char **argv, params_t *const p)
Initialize parameters and load matrices from command line arguments.
#define DIST_M4RI_VERSION
#define RW_PAIRS_MAX_BITS
The largest number of random pivot rows of the buckets of the RW pairs (pairs, a 64-bit key).
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.
colmask_t * colmask_free(colmask_t *cm)
Free the column masks allocated by colmask_from_csr().
cols_ws_t * cols_ws_free(cols_ws_t *ws)
Free the workspace allocated by cols_ws_init().
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.
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.
csr_t * csr_transpose(csr_t *dst, const csr_t *const p)
Transpose a compressed CSR sparse matrix.
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.
csr_t * Lx_for_CSS_code(const csr_t *const Hx, const csr_t *const Hz)
Compute logical generator matrix Lx for a CSS code.
csr_t * csr_init(csr_t *mat, int rows, int cols, int nzmax)
Initialize or reallocate a CSR sparse matrix to target size.
mzd_t * mzd_from_csr(mzd_t *dst, const csr_t *p)
Convert a CSR sparse matrix to an MZD dense matrix.
csr_t * csr_free(csr_t *p)
Free memory allocated for a CSR sparse matrix.
void csr_compress(csr_t *mat)
Compress CSR matrix (sort indices and remove duplicates/zeros).
int csr_max_row_wght(const csr_t *const p)
return max row weight of CSR matrix p TODO: add code for List of Pairs
colmask_t * colmask_from_csr(const csr_t *const A)
Construct the column bit masks of a sparse binary matrix (see colmask_t).
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.