2dist_m4ri.py: Python wrapper for the multithreaded dist_m4ri distance calculator.
4Provides high-level APIs for computing:
5- Classical code distance: compute_classical_distance(...)
6- Single-sided quantum code distance: compute_quantum_distance(...)
7- CSS quantum code distance: compute_css_distance(...)
8- Detector Error Model (DEM) distance: compute_dem_distance(...)
10Supports distance caching, codeword export, and fallback/option for the codedistance library.
11Since dist_m4ri natively handles multithreading (via POSIX threads and dynamic bracketing),
12no Python-level threading or subprocess-per-core logic is necessary.
25from pathlib
import Path
26from typing
import List, Tuple, Union, Optional, Dict, Any
28_codedistance_mod =
None
33 """Lazily imports the codedistance library only when requested."""
34 global _codedistance_mod
35 if _codedistance_mod
is None:
38 _codedistance_mod = codedistance
40 raise ImportError(
"codedistance library is requested but not installed.")
41 return _codedistance_mod
45 """Lazily imports stim only when requested."""
52 raise ImportError(
"stim library is requested but not installed.")
57 """Lazily resolves module attributes without loading heavy dependencies at startup."""
58 if name ==
"_HAS_STIM":
64 if name ==
"_HAS_CODEDISTANCE":
70 raise AttributeError(f
"module '{__name__}' has no attribute '{name}'")
73_distance_cache: Dict[str, Any] = {}
74_use_distance_cache: bool =
True
75_distance_cache_file: Optional[str] =
None
78_css_distance_cache = _distance_cache
79_use_css_distance_cache = _use_distance_cache
84 Sets the default JSON file for persistent distance caching.
85 If the file exists, its contents are loaded into memory.
87 global _distance_cache_file
88 if filepath
is not None:
89 _distance_cache_file = str(Path(filepath).resolve())
92 _distance_cache_file =
None
97 Loads distance cache from a JSON file into memory.
99 global _distance_cache, _distance_cache_file
100 target_file = str(Path(filepath).resolve())
if filepath
is not None else _distance_cache_file
101 if target_file
and os.path.isfile(target_file):
103 with open(target_file,
"r")
as f:
105 if isinstance(data, dict):
106 _distance_cache.update(data)
107 except Exception
as e:
108 sys.stderr.write(f
"# Warning: Failed to load distance cache from {target_file}: {e}\n")
109 return _distance_cache
114 Saves the in-memory distance cache to a JSON file.
115 Uses atomic write via a temporary file to prevent corruption.
117 global _distance_cache, _distance_cache_file
118 target_file = str(Path(filepath).resolve())
if filepath
is not None else _distance_cache_file
122 parent_dir = os.path.dirname(os.path.abspath(target_file))
or "."
123 os.makedirs(parent_dir, exist_ok=
True)
124 fd, temp_path = tempfile.mkstemp(suffix=
".tmp", prefix=
"dist_cache_", dir=parent_dir)
126 with open(fd,
"w")
as f:
127 json.dump(_distance_cache, f, indent=2)
128 os.replace(temp_path, target_file)
129 except Exception
as e:
130 if os.path.exists(temp_path):
131 try: os.remove(temp_path)
133 sys.stderr.write(f
"# Warning: Failed to save distance cache to {target_file}: {e}\n")
138 Clears all cached distance calculations from memory, and optionally deletes the persistent JSON file.
140 global _distance_cache, _distance_cache_file
141 _distance_cache.clear()
142 target_file = str(Path(cache_file).resolve())
if cache_file
is not None else _distance_cache_file
143 if clear_file
and target_file
and os.path.isfile(target_file):
145 os.remove(target_file)
151 """Enables distance caching."""
152 global _use_distance_cache
153 _use_distance_cache =
True
157 """Disables distance caching."""
158 global _use_distance_cache
159 _use_distance_cache =
False
163 """Returns the global distance cache dictionary."""
164 global _distance_cache
165 return _distance_cache
170 Returns [dmin, dmax, num_rw] according to:
171 - [d, d, 0] if known exactly
172 - [dmin, 0, 0] if there is no upper bound (dmax == 0)
173 - [0, dmax, num_rw] if there is no lower bound (dmin <= 1)
174 - [dmin, dmax, num_rw] otherwise
176 eff_dmin = dmin
if dmin > 1
else 0
177 eff_dmax = dmax
if dmax > 0
else 0
178 eff_rw = num_rw
if num_rw > 0
else 0
179 if eff_dmin > 0
and eff_dmin == eff_dmax:
180 return [eff_dmin, eff_dmax, 0]
182 return [eff_dmin, 0, 0]
184 return [0, eff_dmax, eff_rw]
186 return [eff_dmin, eff_dmax, eff_rw]
190 """Formats a bounds list [dmin, dmax, num_rw] as a string, stating '(exact)' if bounds coincide."""
191 dmin, dmax, num_rw = bounds[0], bounds[1], bounds[2]
192 if dmin > 0
and dmin == dmax:
193 return f
"{dmin} {dmax} {num_rw} (exact)"
194 return f
"{dmin} {dmax} {num_rw}"
197def explain_bounds(bounds: List[int], method: Optional[int] =
None, label: str =
"") -> str:
199 Returns a human-readable explanation of [dmin, dmax, num_rw] following README.md.
202 bounds: [dmin, dmax, rw_steps] list.
203 method: Optional solver method (1=RW, 2=CC, 3=Bracketing).
204 label: Optional prefix/label (e.g. "dX", "dZ", "").
207 Multi-line formatted explanation string.
209 dmin, dmax, num_rw = bounds[0], bounds[1], bounds[2]
211 prefix = f
"{label} " if label
else ""
214 if dmin > 0
and dmin == dmax:
215 lines.append(f
" {prefix}Lower bound (dmin = {dmin}): Exact distance certified (dmin == dmax == {dmin}).")
217 lines.append(f
" {prefix}Lower bound (dmin = {dmin}): All cluster weights w <= {dmin - 1} were exhaustively analyzed by CC without finding any non-trivial codewords.")
219 lines.append(f
" {prefix}Lower bound (dmin = {dmin}): No non-trivial lower bound certified (dmin <= 1).")
223 lines.append(f
" {prefix}Upper bound (dmax = {dmax}): Weight of the smallest non-trivial codeword discovered.")
225 lines.append(f
" {prefix}Upper bound (dmax = {dmax}): No non-trivial codeword discovered yet (dmax = 0).")
229 lines.append(f
" {prefix}Random window steps (rw_steps = {num_rw}): {num_rw} completed random information set searches across worker threads.")
231 if dmin > 0
and dmin == dmax:
232 lines.append(f
" {prefix}Random window steps (rw_steps = 0): Set to 0 because the exact distance d = {dmin} was proven by Connected Cluster search or certified bounds coincided.")
234 lines.append(f
" {prefix}Random window steps (rw_steps = 0): Set to 0 because Method 2 (Connected Cluster) is an exhaustive search that does not perform random information set (RW) sampling.")
236 lines.append(f
" {prefix}Random window steps (rw_steps = 0): 0 completed random information set steps.")
238 return "\n".join(lines)
242 H: Optional[Any] =
None,
243 G: Optional[Any] =
None,
244 L: Optional[Any] =
None,
245 Hx: Optional[Any] =
None,
246 Hz: Optional[Any] =
None,
247 Lx: Optional[Any] =
None,
248 Lz: Optional[Any] =
None,
249 dem: Optional[Any] =
None,
250 circuit: Optional[Any] =
None,
252 cache_file: Optional[Union[str, Path]] =
None
253) -> Optional[Dict[str, Any]]:
255 Retrieves the cached distance entry (including bounds and cumulative rw_steps)
256 for a given code matrix, CSS code, or DEM.
259 dict with keys {"dist", "dmin", "dmax", "rw_steps", ...} or None if not cached.
261 global _distance_cache, _distance_cache_file
262 eff_cache_file = str(Path(cache_file).resolve())
if cache_file
is not None else _distance_cache_file
268 key = f
"quantum:H={get_sparse_array_state(H)}:G={get_sparse_array_state(G)}"
270 key = f
"quantum:H={get_sparse_array_state(H)}:L={get_sparse_array_state(L)}"
272 key = f
"classical:{get_sparse_array_state(H)}"
273 entry = _distance_cache.get(key)
276 entry[
"d_info"] =
format_bounds_list(entry.get(
"dmin", 0), entry.get(
"dmax", 0), entry.get(
"rw_steps", 0))
278 elif Hx
is not None or Hz
is not None:
281 key = f
"css:X={hx_st}:Z={hz_st}"
282 if Lx
is not None or Lz
is not None:
285 key = f
"{key}:Lx={lx_st}:Lz={lz_st}"
286 entry = _distance_cache.get(key)
289 if "dmin_X" in entry:
290 entry[
"dX"] =
format_bounds_list(entry.get(
"dmin_X", 0), entry.get(
"dmax_X", 0), entry.get(
"rw_steps_X", 0))
291 if "dmin_Z" in entry:
292 entry[
"dZ"] =
format_bounds_list(entry.get(
"dmin_Z", 0), entry.get(
"dmax_Z", 0), entry.get(
"rw_steps_Z", 0))
294 elif dem
is not None or circuit
is not None:
295 if dem
is None and circuit
is not None:
296 if hasattr(circuit,
'detector_error_model'):
297 obj = circuit.detector_error_model(decompose_errors=
True)
303 key = f
"dem:{dem_st}" if pmin <= 0.0
else f
"dem:{dem_st}:pmin={pmin}"
304 entry = _distance_cache.get(key)
307 entry[
"d_info"] =
format_bounds_list(entry.get(
"dmin", 0), entry.get(
"dmax", 0), entry.get(
"rw_steps", 0))
313clear_css_distance_cache = clear_distance_cache
314enable_css_distance_cache = enable_distance_cache
315disable_css_distance_cache = disable_distance_cache
319 """Returns a deterministic string representation for JSON-compatible cache keys."""
322 if isinstance(A, (str, Path)):
323 path_str = str(Path(A).resolve())
324 if os.path.isfile(path_str):
326 with open(path_str,
"rb")
as f:
327 content_h = hashlib.sha256(f.read()).hexdigest()
328 return f
"file:{path_str}:{content_h}"
330 return f
"file:{path_str}"
332 if hasattr(A,
'shape')
and hasattr(A,
'dtype')
and hasattr(A,
'tobytes'):
333 h = hashlib.sha256(A.tobytes()).hexdigest()
334 dtype_str = getattr(A.dtype,
'str', str(A.dtype))
335 return f
"ndarray:{A.shape}:{dtype_str}:{h}"
336 if hasattr(A,
'tocsr'):
338 h = hashlib.sha256(csr.data.tobytes() + csr.indices.tobytes() + csr.indptr.tobytes()).hexdigest()
339 return f
"csr:{csr.shape}:{h}"
340 if hasattr(A,
'tobytes'):
341 h = hashlib.sha256(A.tobytes()).hexdigest()
343 h = hashlib.sha256(str(A).encode(
'utf-8')).hexdigest()
344 return f
"str_sha256:{h}"
348 """Creates a unique temporary file path and ensures the parent directory exists."""
349 os.makedirs(directory, exist_ok=
True)
350 fd, path = tempfile.mkstemp(suffix=extension, dir=directory)
357 Reads a list of sparse vectors from a text file in NZLIST format,
358 converting from 1-based indexing (in the file) to 0-based indexing (in Python).
361 filepath (str): The path to the text file.
364 list of list of int: A list where each element is a 0-based sparse vector.
367 if not os.path.exists(filepath)
or os.path.getsize(filepath) == 0:
368 return sparse_vectors
370 with open(filepath,
'r')
as f:
371 first_line = f.readline().strip()
373 return sparse_vectors
374 if first_line !=
'%% NZLIST':
375 raise ValueError(f
"Invalid file format in {filepath}: Missing '%% NZLIST' header.")
377 for line_num, line
in enumerate(f, start=2):
379 if not line
or line.startswith(
'%'):
382 parts = list(map(int, line.split()))
384 raise ValueError(f
"Non-integer data found on line {line_num}: {line}")
386 stated_length = parts[0]
387 vector_elements = [x - 1
for x
in parts[1:]]
388 if len(vector_elements) != stated_length:
390 f
"Length mismatch on line {line_num}. "
391 f
"Expected {stated_length} elements, but found {len(vector_elements)}."
393 sparse_vectors.append(vector_elements)
395 return sparse_vectors
399 """Finds the dist_m4ri executable."""
400 if custom_path
and os.path.isfile(custom_path)
and os.access(custom_path, os.X_OK):
401 return os.path.abspath(custom_path)
403 pkg_dir = os.path.dirname(os.path.abspath(__file__))
405 os.path.join(pkg_dir,
"src",
"dist_m4ri"),
406 os.path.join(pkg_dir,
"dist_m4ri"),
407 os.path.join(pkg_dir,
"bin",
"dist_m4ri"),
408 os.path.join(pkg_dir,
"..",
"dist-m4ri",
"src",
"dist_m4ri"),
409 os.path.join(os.getcwd(),
"src",
"dist_m4ri"),
410 os.path.join(os.getcwd(),
"dist_m4ri"),
411 os.path.join(os.getcwd(),
"bin",
"dist_m4ri"),
414 for cand
in candidates:
415 if os.path.isfile(cand)
and os.access(cand, os.X_OK):
416 return os.path.abspath(cand)
418 which_path = shutil.which(
"dist_m4ri")
422 raise FileNotFoundError(
423 "Could not find executable 'dist_m4ri'. Please run 'make -C src' to build it."
429 Parses the standard output of dist_m4ri.
430 Expected format on stdout: "dmin dmax rw_steps", "dmin dmax", or a single integer.
433 tuple (dmin, dmax, rw_steps)
435 lines = stdout.strip().split(
'\n')
436 for line
in reversed(lines):
438 if not line
or line.startswith(
'#'):
443 return int(parts[0]), int(parts[1]), int(parts[2])
446 elif len(parts) == 2:
448 return int(parts[0]), int(parts[1]), 0
451 elif len(parts) == 1:
458 raise RuntimeError(f
"Could not parse dist_m4ri output: {stdout}")
463 Structured result for code distance calculations containing:
464 - dmin: lower bound on distance
465 - dmax: upper bound on distance (minimum non-trivial codeword weight found)
466 - rw_steps: cumulative number of completed random window information sets
467 - cws: discovered codewords (if requested)
474 cws: Optional[List[List[int]]] =
None,
475 cws_X: Optional[List[List[int]]] =
None,
476 cws_Z: Optional[List[List[int]]] =
None,
477 dmin_X: Optional[int] =
None,
478 dmax_X: Optional[int] =
None,
479 rw_steps_X: Optional[int] =
None,
480 dmin_Z: Optional[int] =
None,
481 dmax_Z: Optional[int] =
None,
482 rw_steps_Z: Optional[int] =
None,
512 if isinstance(other, DistanceResult):
513 return (self.
dmin, self.
dmax, self.
rw_steps) == (other.dmin, other.dmax, other.rw_steps)
514 if isinstance(other, (tuple, list)):
515 return tuple(self) == tuple(other)
516 if isinstance(other, (int, np.integer)):
521 if self.
cws_X is not None or self.
cws_Z is not None:
523 if self.
cws is not None:
528 return tuple(self)[index]
531 return len(tuple(self))
535 return f
"{self.dmin} {self.dmax} {self.rw_steps} (exact)"
536 return f
"{self.dmin} {self.dmax} {self.rw_steps}"
540 return f
"DistanceResult({self.dmin} {self.dmax} {self.rw_steps} (exact))"
541 return f
"DistanceResult(dmin={self.dmin}, dmax={self.dmax}, rw_steps={self.rw_steps})"
544def check_finc_outc(finC: Optional[str], outC: Optional[str], verbose: bool =
False) -> Optional[str]:
546 When finC and outC names are identical, an empty or non-existent file is silently ignored
547 (with a warning if verbose is True).
550 The effective finC filepath to use (or None if ignored).
554 if outC
and (finC == outC
or os.path.abspath(finC) == os.path.abspath(outC)):
555 if not os.path.exists(finC)
or os.path.getsize(finC) == 0:
557 print(f
"[dist_m4ri] Warning: finC='{finC}' (identical to outC) is empty or non-existent; silently ignoring input codewords.")
563 dist_m4ri_path: Optional[str] =
None,
565 finH: Optional[str] =
None,
566 finG: Optional[str] =
None,
567 finL: Optional[str] =
None,
568 fin: Optional[str] =
None,
569 finC: Optional[str] =
None,
570 fdem: Optional[str] =
None,
577 steps: Optional[int] =
None,
578 threads: Optional[int] =
None,
579 timeout: float = 60.0,
580 smax: Optional[int] =
None,
581 start: Optional[int] =
None,
582 cbeg: Optional[int] =
None,
583 cend: Optional[int] =
None,
584 css: Optional[int] =
None,
590 outC: Optional[str] =
None,
593 stop_event: Optional[threading.Event] =
None
594) -> Tuple[int, int, int]:
596 Low-level invocation of the multithreaded dist_m4ri binary.
599 tuple (dmin, dmax, rw_steps)
605 if method == 2
and wmax <= 0:
609 raise ValueError(
"either parameter wmax>0 or timeout>0 should be specified for CC method=2.")
611 cmd = [exec_path, f
"debug={debug}", f
"method={method}"]
613 if finH: cmd.append(f
"finH={finH}")
614 if finG: cmd.append(f
"finG={finG}")
615 if finL: cmd.append(f
"finL={finL}")
616 if fin: cmd.append(f
"fin={fin}")
617 if finC: cmd.append(f
"finC={finC}")
618 if fdem: cmd.append(f
"fdem={fdem}")
619 if dmin > 0: cmd.append(f
"dmin={dmin}")
620 if dmax > 0: cmd.append(f
"dmax={dmax}")
621 if wmax > 0: cmd.append(f
"wmax={wmax}")
622 if wmin > 1: cmd.append(f
"wmin={wmin}")
623 if dexp > 0: cmd.append(f
"dexp={dexp}")
624 elif dest > 0: cmd.append(f
"dest={dest}")
625 if steps
is not None and steps > 0: cmd.append(f
"steps={steps}")
626 if threads
is not None and threads > 0: cmd.append(f
"threads={threads}")
627 if timeout > 0: cmd.append(f
"timeout={timeout}")
628 if smax
is not None: cmd.append(f
"smax={smax}")
629 if start
is not None and start >= 0: cmd.append(f
"start={start}")
630 if cbeg
is not None and cbeg >= 0: cmd.append(f
"cbeg={cbeg}")
631 if cend
is not None and cend >= 0: cmd.append(f
"cend={cend}")
632 if css
is not None: cmd.append(f
"css={css}")
633 if noscan: cmd.append(f
"noscan={noscan}")
634 if classical >= 0: cmd.append(f
"classical={classical}")
635 if dW >= 0: cmd.append(f
"dW={dW}")
636 if maxC > 0: cmd.append(f
"maxC={maxC}")
637 if pmin > 0.0: cmd.append(f
"pmin={pmin}")
638 if outC: cmd.append(f
"outC={outC}")
639 if seed != 0: cmd.append(f
"seed={seed}")
642 print(f
"[dist_m4ri] Running: {' '.join(cmd)}")
644 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=
True)
646 if stop_event
is not None:
647 while proc.poll()
is None:
648 if stop_event.is_set():
651 proc.wait(timeout=1.0)
652 except subprocess.TimeoutExpired:
654 raise RuntimeError(
"dist_m4ri execution cancelled by stop_event")
656 stdout, stderr = proc.communicate()
658 stdout, stderr = proc.communicate()
660 if proc.returncode != 0:
661 raise RuntimeError(f
"dist_m4ri failed with exit code {proc.returncode}:\n{stderr}")
667 """Helper to convert a matrix (numpy or scipy sparse) or file path to an MTX file path."""
668 if isinstance(matrix, (str, Path)):
672 from scipy.io
import mmwrite
673 from scipy.sparse
import csr_matrix, issparse
677 csr = matrix.astype(np.int8)
678 mmwrite(path, csr, symmetry=
'general')
680 mat_arr = np.asarray(matrix, dtype=np.int8)
681 csr = csr_matrix(mat_arr)
682 mmwrite(path, csr, symmetry=
'general')
688 dist_m4ri: Optional[str] =
None,
690 threads: Optional[int] =
None,
691 timeout: float = 60.0,
692 num_steps: Optional[int] =
None,
700 smax: Optional[int] =
None,
701 start: Optional[int] =
None,
702 cbeg: Optional[int] =
None,
703 cend: Optional[int] =
None,
707 finC: Optional[str] =
None,
708 outC: Optional[str] =
None,
709 do_cws: bool =
False,
710 return_info: bool =
False,
711 cache_file: Optional[Union[str, Path]] =
None,
712 solver: str =
"dist_m4ri",
713 codedistance_method: str =
"QDistEvol",
714 codedistance_params: Optional[Dict[str, Any]] =
None,
717 verbose: bool =
False
720 Computes the minimum distance of a classical linear code given parity check matrix H.
723 H: Parity check matrix (numpy array, scipy sparse matrix, or file path).
724 dist_m4ri: Path to dist_m4ri executable (optional).
725 method: Solver method (1=RW, 2=CC, 3=Bracketing default).
726 threads: Number of worker threads.
727 timeout: Execution timeout in seconds.
728 num_steps: Maximum RW steps.
729 d_exp: Expected distance estimate.
730 d_min / dmin: Known lower bound on distance.
731 d_max / dmax: Known upper bound on distance.
732 wmin: Minimum distance of interest (terminate early if cw of weight <= wmin is found in RW or CC, default: 1).
733 wmax: Maximum weight to search in CC.
734 smax: Maximum syndrome weight for CC confinement profile.
735 start / cbeg / cend: Column search range for CC.
736 noscan: Skip CC scan loop if 1.
737 dW: Extra weight window above dmin to collect codewords.
738 maxC: Maximum number of codewords to collect.
739 finC: Input file with initial codewords.
740 outC: Output file to save codewords (NZLIST format).
741 do_cws: Whether to return extracted codewords.
742 return_info: If True, return (dist, d_info) or (dist, d_info, cws) where d_info is [dmin, dmax, num_rw].
743 cache_file: Optional JSON file path for persistent distance caching.
744 solver: "dist_m4ri" or "codedistance".
745 codedistance_method: Method if using codedistance library.
746 codedistance_params: Extra parameters for codedistance library.
748 debug: Debug level flags.
749 verbose: Verbose reporting flag.
752 dist or (dist, cws) if do_cws is True (or (dist, d_info) / (dist, d_info, cws) if return_info=True)
754 eff_dmin = dmin
if dmin > 0
else d_min
755 eff_dmax = dmax
if dmax > 0
else d_max
759 global _distance_cache, _use_distance_cache, _distance_cache_file
760 eff_cache_file = str(Path(cache_file).resolve())
if cache_file
is not None else _distance_cache_file
764 if solver ==
"codedistance":
766 raise ValueError(
"Codeword extraction is not supported with codedistance solver; use solver='dist_m4ri'.")
769 params = dict(codedistance_params
or {})
770 if num_steps
is not None and "iterCount" not in params:
771 params[
"iterCount"] = num_steps
773 H_mat = H.toarray()
if hasattr(H,
'toarray')
else (np.asarray(H, dtype=np.int8)
if isinstance(H, (np.ndarray, list))
else None)
774 res = codedistance.codeDistance(
775 H_mat,
None, tB=1, method=codedistance_method, params=params,
776 seed=seed
if seed != 0
else None
778 return res.get(
"d", -1)
781 if _use_distance_cache:
786 code_key = f
"classical:{h_state}"
787 cached_entry = _distance_cache.get(code_key)
788 if cached_entry
is not None:
790 if cached_entry.get(
"dmin", 0) > 0
and cached_entry.get(
"dmin") == cached_entry.get(
"dmax"):
791 if not (do_cws
or outC)
or (cached_entry.get(
"cws")
and len(cached_entry[
"cws"]) > 0):
792 d_info =
format_bounds_list(cached_entry.get(
"dmin", 0), cached_entry.get(
"dmax", 0), cached_entry.get(
"rw_steps", 0))
794 print(f
"[dist_m4ri] Cache retrieval: SUCCESS (found cached exact distance for '{code_key}')")
795 print(f
"[dist_m4ri] Cached result: dist={cached_entry['dist']}, bounds={format_bounds_str(d_info)}")
797 print(
"[dist_m4ri] Cache hit for classical distance (exact distance known)!")
798 cws_res = cached_entry.get(
"cws", [])
802 return (cached_entry[
"dist"], d_info, cws_res)
if do_cws
else (cached_entry[
"dist"], d_info)
803 return (cached_entry[
"dist"], cws_res)
if do_cws
else cached_entry[
"dist"]
805 print(f
"[dist_m4ri] Cache retrieval: PARTIAL (cached bounds: dmin={cached_entry.get('dmin', 0)}, dmax={cached_entry.get('dmax', 0)}, rw_steps={cached_entry.get('rw_steps', 0)}; continuing search)")
807 if eff_dmax == 0
and cached_entry.get(
"dmax", 0) > 0:
808 eff_dmax = cached_entry[
"dmax"]
809 elif eff_dmax > 0
and cached_entry.get(
"dmax", 0) > 0:
810 eff_dmax = min(eff_dmax, cached_entry[
"dmax"])
811 if eff_dmin <= 1
and cached_entry.get(
"dmin", 0) > 1:
812 eff_dmin = cached_entry[
"dmin"]
813 elif eff_dmin > 1
and cached_entry.get(
"dmin", 0) > 1:
814 eff_dmin = max(eff_dmin, cached_entry[
"dmin"])
817 print(f
"[dist_m4ri] Cache retrieval: MISS (no entry for '{code_key}')")
823 print(
"[dist_m4ri] Cache retrieval: DISABLED (cache is turned off)")
827 if isinstance(H, (str, Path))
and os.path.exists(str(H)):
831 temp_files.append(file_H)
836 temp_files.append(outC_file)
839 dist_m4ri_path=dist_m4ri,
864 dist = dmin_res
if (dmin_res == dmax_res
or dmax_res == 0)
else dmax_res
866 if (do_cws
or outC)
and outC_file
and os.path.exists(outC_file):
874 if _use_distance_cache
and code_key
is not None:
875 prev_steps = cached_entry.get(
"rw_steps", 0)
if cached_entry
else 0
876 prev_dmax = cached_entry.get(
"dmax", 0)
if cached_entry
else 0
877 prev_dmin = cached_entry.get(
"dmin", 0)
if cached_entry
else 0
878 prev_cws = list(cached_entry.get(
"cws", []))
if cached_entry
else []
880 total_rw_steps = prev_steps + rw_steps
881 best_dmax = min(prev_dmax, dmax_res)
if (prev_dmax > 0
and dmax_res > 0)
else (dmax_res
if dmax_res > 0
else prev_dmax)
882 best_dmin = max(prev_dmin, dmin_res)
884 combined_cws = prev_cws
886 existing_set = {tuple(cw)
for cw
in combined_cws}
888 if tuple(cw)
not in existing_set:
889 combined_cws.append(cw)
890 existing_set.add(tuple(cw))
891 combined_cws.sort(key=len)
895 _distance_cache[code_key] = {
899 "rw_steps": total_rw_steps,
907 return (dist, d_info, combined_cws)
if do_cws
else (dist, d_info)
908 return (dist, combined_cws)
if do_cws
else dist
911 return (dist, d_info, cws)
if do_cws
else (dist, d_info)
912 return (dist, cws)
if do_cws
else dist
916 if os.path.exists(f):
923 G: Optional[Any] =
None,
924 L: Optional[Any] =
None,
925 dist_m4ri: Optional[str] =
None,
927 threads: Optional[int] =
None,
928 timeout: float = 60.0,
929 num_steps: Optional[int] =
None,
937 smax: Optional[int] =
None,
938 start: Optional[int] =
None,
939 cbeg: Optional[int] =
None,
940 cend: Optional[int] =
None,
944 finC: Optional[str] =
None,
945 outC: Optional[str] =
None,
946 do_cws: bool =
False,
947 return_info: bool =
False,
948 cache_file: Optional[Union[str, Path]] =
None,
949 solver: str =
"dist_m4ri",
950 codedistance_method: str =
"QDistEvol",
951 codedistance_params: Optional[Dict[str, Any]] =
None,
954 verbose: bool =
False
957 Computes the minimum distance of a single-sided quantum code given parity check matrix H
958 and degeneracy generator G (or logical operator matrix L).
961 H: Parity check matrix (numpy array, scipy sparse matrix, or file path).
962 G: Degeneracy generator matrix (numpy array, scipy sparse matrix, or file path).
963 L: Logical operator matrix (numpy array, scipy sparse matrix, or file path).
964 dist_m4ri: Path to dist_m4ri executable (optional).
965 method: Solver method (1=RW, 2=CC, 3=Bracketing default).
966 threads: Number of worker threads.
967 timeout: Execution timeout in seconds.
968 num_steps: Maximum RW steps.
969 d_exp: Expected distance estimate.
970 d_min / dmin: Known lower bound on distance.
971 d_max / dmax: Known upper bound on distance.
972 wmin: Minimum distance of interest (terminate early if cw of weight <= wmin is found in RW or CC, default: 1).
973 wmax: Maximum weight to search in CC.
974 smax: Maximum syndrome weight for CC confinement profile.
975 start / cbeg / cend: Column search range for CC.
976 noscan: Skip CC scan loop if 1.
977 dW: Extra weight window above dmin to collect codewords.
978 maxC: Maximum number of codewords to collect.
979 finC: Input file with initial codewords.
980 outC: Output file to save codewords (NZLIST format).
981 do_cws: Whether to return extracted codewords.
982 return_info: If True, return (dist, d_info) or (dist, d_info, cws) where d_info is [dmin, dmax, num_rw].
983 cache_file: Optional JSON file path for persistent distance caching.
984 solver: "dist_m4ri" or "codedistance".
985 codedistance_method: Method if using codedistance library.
986 codedistance_params: Extra parameters for codedistance library.
988 debug: Debug level flags.
989 verbose: Verbose reporting flag.
992 dist or (dist, cws) if do_cws is True (or (dist, d_info) / (dist, d_info, cws) if return_info=True)
994 eff_dmin = dmin
if dmin > 0
else d_min
995 eff_dmax = dmax
if dmax > 0
else d_max
997 if G
is None and L
is None:
998 raise ValueError(
"Either G (dual generator matrix) or L (logical operator matrix) must be specified for quantum distance.")
1002 global _distance_cache, _use_distance_cache, _distance_cache_file
1003 eff_cache_file = str(Path(cache_file).resolve())
if cache_file
is not None else _distance_cache_file
1007 if solver ==
"codedistance":
1009 raise ValueError(
"Codeword extraction is not supported with codedistance solver; use solver='dist_m4ri'.")
1012 params = dict(codedistance_params
or {})
1013 if num_steps
is not None and "iterCount" not in params:
1014 params[
"iterCount"] = num_steps
1016 H_mat = H.toarray()
if hasattr(H,
'toarray')
else (np.asarray(H, dtype=np.int8)
if isinstance(H, (np.ndarray, list))
else None)
1017 dual_mat = G
if G
is not None else L
1018 dual_arr = dual_mat.toarray()
if hasattr(dual_mat,
'toarray')
else (np.asarray(dual_mat, dtype=np.int8)
if isinstance(dual_mat, (np.ndarray, list))
else None)
1020 res = codedistance.codeDistance(
1021 H_mat, dual_arr, tB=1, method=codedistance_method, params=params,
1022 seed=seed
if seed != 0
else None
1024 return res.get(
"d", -1)
1027 if _use_distance_cache:
1034 code_key = f
"quantum:H={h_state}:G={g_state}"
1037 code_key = f
"quantum:H={h_state}:L={l_state}"
1038 cached_entry = _distance_cache.get(code_key)
1039 if cached_entry
is not None:
1040 if cached_entry.get(
"dmin", 0) > 0
and cached_entry.get(
"dmin") == cached_entry.get(
"dmax"):
1041 if not (do_cws
or outC)
or (cached_entry.get(
"cws")
and len(cached_entry[
"cws"]) > 0):
1042 d_info =
format_bounds_list(cached_entry.get(
"dmin", 0), cached_entry.get(
"dmax", 0), cached_entry.get(
"rw_steps", 0))
1044 print(f
"[dist_m4ri] Cache retrieval: SUCCESS (found cached exact distance for '{code_key}')")
1045 print(f
"[dist_m4ri] Cached result: dist={cached_entry['dist']}, bounds={format_bounds_str(d_info)}")
1047 print(
"[dist_m4ri] Cache hit for quantum distance (exact distance known)!")
1048 cws_res = cached_entry.get(
"cws", [])
1049 if outC
and cws_res:
1052 return (cached_entry[
"dist"], d_info, cws_res)
if do_cws
else (cached_entry[
"dist"], d_info)
1053 return (cached_entry[
"dist"], cws_res)
if do_cws
else cached_entry[
"dist"]
1055 print(f
"[dist_m4ri] Cache retrieval: PARTIAL (cached bounds: dmin={cached_entry.get('dmin', 0)}, dmax={cached_entry.get('dmax', 0)}, rw_steps={cached_entry.get('rw_steps', 0)}; continuing search)")
1056 if eff_dmax == 0
and cached_entry.get(
"dmax", 0) > 0:
1057 eff_dmax = cached_entry[
"dmax"]
1058 elif eff_dmax > 0
and cached_entry.get(
"dmax", 0) > 0:
1059 eff_dmax = min(eff_dmax, cached_entry[
"dmax"])
1060 if eff_dmin <= 1
and cached_entry.get(
"dmin", 0) > 1:
1061 eff_dmin = cached_entry[
"dmin"]
1062 elif eff_dmin > 1
and cached_entry.get(
"dmin", 0) > 1:
1063 eff_dmin = max(eff_dmin, cached_entry[
"dmin"])
1066 print(f
"[dist_m4ri] Cache retrieval: MISS (no entry for '{code_key}')")
1072 print(
"[dist_m4ri] Cache retrieval: DISABLED (cache is turned off)")
1076 if isinstance(H, (str, Path))
and os.path.exists(str(H)):
1080 temp_files.append(file_H)
1084 if isinstance(G, (str, Path))
and os.path.exists(str(G)):
1088 temp_files.append(file_G)
1092 if isinstance(L, (str, Path))
and os.path.exists(str(L)):
1096 temp_files.append(file_L)
1101 temp_files.append(outC_file)
1104 dist_m4ri_path=dist_m4ri,
1131 dist = dmin_res
if (dmin_res == dmax_res
or dmax_res == 0)
else dmax_res
1133 if (do_cws
or outC)
and outC_file
and os.path.exists(outC_file):
1141 if _use_distance_cache
and code_key
is not None:
1142 prev_steps = cached_entry.get(
"rw_steps", 0)
if cached_entry
else 0
1143 prev_dmax = cached_entry.get(
"dmax", 0)
if cached_entry
else 0
1144 prev_dmin = cached_entry.get(
"dmin", 0)
if cached_entry
else 0
1145 prev_cws = list(cached_entry.get(
"cws", []))
if cached_entry
else []
1147 total_rw_steps = prev_steps + rw_steps
1148 best_dmax = min(prev_dmax, dmax_res)
if (prev_dmax > 0
and dmax_res > 0)
else (dmax_res
if dmax_res > 0
else prev_dmax)
1149 best_dmin = max(prev_dmin, dmin_res)
1151 combined_cws = prev_cws
1153 existing_set = {tuple(cw)
for cw
in combined_cws}
1155 if tuple(cw)
not in existing_set:
1156 combined_cws.append(cw)
1157 existing_set.add(tuple(cw))
1158 combined_cws.sort(key=len)
1162 _distance_cache[code_key] = {
1166 "rw_steps": total_rw_steps,
1174 return (dist, d_info, combined_cws)
if do_cws
else (dist, d_info)
1175 return (dist, combined_cws)
if do_cws
else dist
1178 return (dist, d_info, cws)
if do_cws
else (dist, d_info)
1179 return (dist, cws)
if do_cws
else dist
1182 for f
in temp_files:
1183 if os.path.exists(f):
1185 except OSError:
pass
1191 Lx: Optional[Any] =
None,
1192 Lz: Optional[Any] =
None,
1193 dist_m4ri: Optional[str] =
None,
1195 threads: Optional[int] =
None,
1196 timeout: float = 60.0,
1197 num_steps: Optional[int] =
None,
1205 smax: Optional[int] =
None,
1206 start: Optional[int] =
None,
1207 cbeg: Optional[int] =
None,
1208 cend: Optional[int] =
None,
1212 finC: Optional[str] =
None,
1213 outC: Optional[str] =
None,
1214 do_cws: bool =
False,
1215 cache_file: Optional[Union[str, Path]] =
None,
1216 solver: str =
"dist_m4ri",
1217 codedistance_method: str =
"QDistEvol",
1218 codedistance_params: Optional[Dict[str, Any]] =
None,
1221 verbose: bool =
False,
1223) -> Tuple[Any, ...]:
1225 Computes CSS quantum code distance d = min(d_X, d_Z).
1228 Hx: X-stabilizer parity check matrix.
1229 Hz: Z-stabilizer parity check matrix.
1230 Lx: Optional X-logical operator matrix (alternative to Hz as finG).
1231 Lz: Optional Z-logical operator matrix (alternative to Hx as finG).
1232 dist_m4ri: Path to dist_m4ri executable (optional).
1233 method: Solver method (1=RW, 2=CC, 3=Bracketing default).
1234 threads: Number of worker threads.
1235 timeout: Execution timeout in seconds.
1236 num_steps: Maximum RW steps.
1237 d_exp: Expected distance estimate.
1238 d_min / dmin: Known lower bound on distance, inclusive.
1239 d_max / dmax: Known upper bound on distance, inclusive.
1240 wmin: Minimum distance of interest (terminate early if cw of weight <= wmin is found in RW or CC, default: 1).
1241 wmax: Maximum weight to search in CC.
1242 smax: Maximum syndrome weight for CC confinement profile.
1243 start / cbeg / cend: Column search range for CC.
1244 noscan: Skip CC scan loop if 1.
1245 dW: Extra weight window above dmin to collect codewords.
1246 maxC: Maximum number of codewords to collect.
1247 finC: Input file with initial codewords.
1248 outC: Output file to save codewords (NZLIST format).
1249 do_cws: Whether to return extracted X and Z codewords.
1250 cache_file: Optional JSON file path for persistent distance caching.
1251 solver: "dist_m4ri" or "codedistance".
1252 codedistance_method: Method if using codedistance library.
1253 codedistance_params: Extra parameters for codedistance library.
1255 debug: Debug level flags.
1256 verbose: Verbose reporting flag.
1259 tuple (dist, dX_info, dZ_info, cws_X, cws_Z) if do_cws
1260 else (dist, dX_info, dZ_info)
1262 eff_dmin = dmin
if dmin > 0
else d_min
1263 eff_dmax = dmax
if dmax > 0
else d_max
1265 can_compute_Z = Hx
is not None and (hasattr(Hx,
'shape')
and Hx.shape[0] > 0
if not isinstance(Hx, str)
else True)
1266 can_compute_X = Hz
is not None and (hasattr(Hz,
'shape')
and Hz.shape[0] > 0
if not isinstance(Hz, str)
else True)
1268 if not can_compute_Z
and not can_compute_X:
1269 raise ValueError(
"Cannot compute CSS distance: Both Hx and Hz are empty.")
1273 global _distance_cache, _use_distance_cache, _distance_cache_file
1274 eff_cache_file = str(Path(cache_file).resolve())
if cache_file
is not None else _distance_cache_file
1278 if solver ==
"codedistance":
1280 raise ValueError(
"Codeword extraction is not supported with codedistance solver; use solver='dist_m4ri'.")
1283 params = dict(codedistance_params
or {})
1284 if num_steps
is not None and "iterCount" not in params:
1285 params[
"iterCount"] = num_steps
1287 dist_Z, dist_X =
None,
None
1288 dX_info, dZ_info =
None,
None
1290 Hx_mat = Hx.toarray()
if hasattr(Hx,
'toarray')
else (np.asarray(Hx, dtype=np.int8)
if isinstance(Hx, (np.ndarray, list))
else None)
1291 Hz_mat = Hz.toarray()
if hasattr(Hz,
'toarray')
else (np.asarray(Hz, dtype=np.int8)
if isinstance(Hz, (np.ndarray, list))
else None)
1294 res_Z = codedistance.CSScodeDistance(
1295 Hx_mat, Hz_mat, method=codedistance_method, params=params.copy(),
1296 component=
"Z", seed=seed
if seed != 0
else None
1298 dist_Z = res_Z.get(
"d", -1)
1302 res_X = codedistance.CSScodeDistance(
1303 Hx_mat, Hz_mat, method=codedistance_method, params=params.copy(),
1304 component=
"X", seed=seed
if seed != 0
else None
1306 dist_X = res_X.get(
"d", -1)
1309 if dist_X
is not None and dist_Z
is not None:
1310 dist = min(dist_Z, dist_X)
if (dist_Z > 0
and dist_X > 0)
else max(dist_Z, dist_X)
1311 elif dist_X
is not None:
1316 return (dist, dX_info, dZ_info)
1319 if _use_distance_cache:
1325 code_key = f
"css:X={hx_state}:Z={hz_state}"
1326 if Lx
is not None or Lz
is not None:
1329 code_key = f
"{code_key}:Lx={lx_state}:Lz={lz_state}"
1330 cached_entry = _distance_cache.get(code_key)
1331 if cached_entry
is not None:
1333 if cached_entry.get(
"dmin", 0) > 0
and cached_entry.get(
"dmin") == cached_entry.get(
"dmax"):
1334 if not (do_cws
or outC)
or (cached_entry.get(
"cws_X")
and cached_entry.get(
"cws_Z")):
1335 dx_res = cached_entry.get(
"dX",
format_bounds_list(cached_entry.get(
"dmin_X", 0), cached_entry.get(
"dmax_X", 0), cached_entry.get(
"rw_steps_X", 0)))
1336 dz_res = cached_entry.get(
"dZ",
format_bounds_list(cached_entry.get(
"dmin_Z", 0), cached_entry.get(
"dmax_Z", 0), cached_entry.get(
"rw_steps_Z", 0)))
1338 print(f
"[dist_m4ri] Cache retrieval: SUCCESS (found cached exact CSS distance for '{code_key}')")
1339 print(f
"[dist_m4ri] Cached result: dist={cached_entry['dist']}, dX={format_bounds_str(dx_res)}, dZ={format_bounds_str(dz_res)}")
1341 print(
"[dist_m4ri] Cache hit for CSS distance (exact distance known)!")
1342 cws_x = cached_entry.get(
"cws_X", [])
1343 cws_z = cached_entry.get(
"cws_Z", [])
1344 if outC
and (cws_x
or cws_z):
1347 cached_entry[
"dist"], dx_res, dz_res,
1350 cached_entry[
"dist"], dx_res, dz_res
1353 print(f
"[dist_m4ri] Cache retrieval: PARTIAL (cached CSS bounds: dmin={cached_entry.get('dmin', 0)}, dmax={cached_entry.get('dmax', 0)}; continuing search)")
1355 if eff_dmax == 0
and cached_entry.get(
"dmax", 0) > 0:
1356 eff_dmax = cached_entry[
"dmax"]
1357 elif eff_dmax > 0
and cached_entry.get(
"dmax", 0) > 0:
1358 eff_dmax = min(eff_dmax, cached_entry[
"dmax"])
1359 if eff_dmin <= 1
and cached_entry.get(
"dmin", 0) > 1:
1360 eff_dmin = cached_entry[
"dmin"]
1361 elif eff_dmin > 1
and cached_entry.get(
"dmin", 0) > 1:
1362 eff_dmin = max(eff_dmin, cached_entry[
"dmin"])
1365 print(f
"[dist_m4ri] Cache retrieval: MISS (no entry for '{code_key}')")
1371 print(
"[dist_m4ri] Cache retrieval: DISABLED (cache is turned off)")
1375 file_Hx =
_matrix_to_file(Hx, extension=
"_Hx.mtx")
if can_compute_Z
else None
1376 file_Hz =
_matrix_to_file(Hz, extension=
"_Hz.mtx")
if can_compute_X
else None
1377 file_Lx =
_matrix_to_file(Lx, extension=
"_Lx.mtx")
if Lx
is not None else None
1378 file_Lz =
_matrix_to_file(Lz, extension=
"_Lz.mtx")
if Lz
is not None else None
1380 for f
in (file_Hx, file_Hz, file_Lx, file_Lz):
1381 if f
and not isinstance(f, (str, Path))
or (f
and not os.path.exists(f)):
1383 elif f
and f.startswith(tempfile.gettempdir()):
1384 temp_files.append(f)
1386 outZ =
create_unique_file(extension=
"_Z.nz")
if ((do_cws
or outC)
and can_compute_Z)
else None
1387 outX =
create_unique_file(extension=
"_X.nz")
if ((do_cws
or outC)
and can_compute_X)
else None
1388 if outZ: temp_files.append(outZ)
1389 if outX: temp_files.append(outX)
1391 dist_Z, dist_X =
None,
None
1392 dmin_z, dmax_z, rw_steps_z = 0, 0, 0
1393 dmin_x, dmax_x, rw_steps_x = 0, 0, 0
1394 cws_Z, cws_X = [], []
1399 dist_m4ri_path=dist_m4ri,
1402 finG=file_Hz
if file_Lz
is None else None,
1424 dist_Z = dmin_z
if (dmin_z == dmax_z
or dmax_z == 0)
else dmax_z
1425 if (do_cws
or outC)
and outZ
and os.path.exists(outZ):
1432 dist_m4ri_path=dist_m4ri,
1435 finG=file_Hx
if file_Lx
is None else None,
1457 dist_X = dmin_x
if (dmin_x == dmax_x
or dmax_x == 0)
else dmax_x
1458 if (do_cws
or outC)
and outX
and os.path.exists(outX):
1465 if dist_X
is not None and dist_Z
is not None:
1466 dist = min(dist_Z, dist_X)
if (dist_Z > 0
and dist_X > 0)
else max(dist_Z, dist_X)
1467 elif dist_X
is not None:
1475 res_tuple = (dist, dX_info, dZ_info, cws_X, cws_Z)
if do_cws
else (dist, dX_info, dZ_info)
1477 if _use_distance_cache
and code_key
is not None:
1478 prev_steps = cached_entry.get(
"rw_steps", 0)
if cached_entry
else 0
1479 prev_dmax = cached_entry.get(
"dmax", 0)
if cached_entry
else 0
1480 prev_dmin = cached_entry.get(
"dmin", 0)
if cached_entry
else 0
1482 run_steps = (rw_steps_z
if can_compute_Z
else 0) + (rw_steps_x
if can_compute_X
else 0)
1483 total_rw_steps = prev_steps + run_steps
1485 curr_dmax = dist
if dist > 0
else 0
1486 best_dmax = min(prev_dmax, curr_dmax)
if (prev_dmax > 0
and curr_dmax > 0)
else (curr_dmax
if curr_dmax > 0
else prev_dmax)
1489 if can_compute_Z
and can_compute_X:
1490 curr_dmin = min(dmin_z, dmin_x)
1495 best_dmin = max(prev_dmin, curr_dmin)
1497 _distance_cache[code_key] = {
1501 "rw_steps": total_rw_steps,
1504 "rw_steps_X": rw_steps_x,
1507 "rw_steps_Z": rw_steps_z,
1518 for f
in temp_files:
1519 if f
and os.path.exists(f):
1521 except OSError:
pass
1525 dem: Optional[Any] =
None,
1526 circuit: Optional[Any] =
None,
1527 dist_m4ri: Optional[str] =
None,
1529 threads: Optional[int] =
None,
1530 timeout: float = 60.0,
1531 num_steps: Optional[int] =
None,
1539 smax: Optional[int] =
None,
1540 start: Optional[int] =
None,
1541 cbeg: Optional[int] =
None,
1542 cend: Optional[int] =
None,
1547 finC: Optional[str] =
None,
1548 outC: Optional[str] =
None,
1549 do_cws: bool =
False,
1550 cache_file: Optional[Union[str, Path]] =
None,
1551 solver: str =
"dist_m4ri",
1552 codedistance_method: str =
"UndetectableErrorStim",
1553 codedistance_params: Optional[Dict[str, Any]] =
None,
1556 verbose: bool =
False,
1558) -> Tuple[Any, ...]:
1560 Computes minimum graph/hypergraph distance of a Stim Detector Error Model (DEM).
1563 dem: stim.DetectorErrorModel object or path to .dem file.
1564 circuit: stim.Circuit object (converted to DEM).
1565 dist_m4ri: Path to dist_m4ri executable (optional).
1566 method: Solver method (1=RW, 2=CC, 3=Bracketing default).
1567 threads: Number of worker threads.
1568 timeout: Execution timeout in seconds.
1569 num_steps: Maximum RW steps.
1570 d_exp: Expected distance estimate.
1571 d_min / dmin: Known lower bound on distance, inclusive.
1572 d_max / dmax: Known upper bound on distance, inclusive.
1573 wmin: Minimum distance of interest (terminate early if cw of weight <= wmin is found in RW or CC, default: 1).
1574 wmax: Maximum weight to search in CC.
1575 smax: Maximum syndrome weight for CC confinement profile.
1576 start / cbeg / cend: Column search range for CC.
1577 noscan: Skip CC scan loop if 1.
1578 dW: Extra weight window above dmin to collect codewords.
1579 maxC: Maximum number of codewords to collect.
1580 pmin: Probability cutoff for error mechanisms in DEM.
1581 finC: Input file with initial codewords.
1582 outC: Output file to save codewords (NZLIST format).
1583 do_cws: Whether to return extracted error mechanisms / codewords.
1584 cache_file: Optional JSON file path for persistent distance caching.
1585 solver: "dist_m4ri" or "codedistance".
1586 codedistance_method: Method if using codedistance library.
1587 codedistance_params: Extra parameters for codedistance library.
1589 debug: Debug level flags.
1590 verbose: Verbose reporting flag.
1593 tuple (dist, d_info, cws) if do_cws else (dist, d_info)
1595 eff_dmin = dmin
if dmin > 0
else d_min
1596 eff_dmax = dmax
if dmax > 0
else d_max
1598 if dem
is None and circuit
is not None:
1599 if hasattr(circuit,
'detector_error_model'):
1600 dem = circuit.detector_error_model(decompose_errors=
True)
1602 raise ValueError(
"Provided circuit object does not have detector_error_model() method.")
1605 raise ValueError(
"Either 'dem' or 'circuit' must be provided.")
1609 if solver ==
"codedistance":
1611 raise ValueError(
"Codeword extraction is not supported with codedistance solver; use solver='dist_m4ri'.")
1613 params = dict(codedistance_params
or {})
1614 params.setdefault(
"filterCircuit",
False)
1615 if num_steps
is not None and "iterCount" not in params:
1616 params[
"iterCount"] = num_steps
1618 if circuit
is not None:
1619 res = codedistance.circuitDistance(
1620 circuit, method=codedistance_method, params=params,
1621 seed=seed
if seed != 0
else None
1624 H, L, priors = codedistance.StimDEM2HL(dem)
1625 if "priors" not in params
and len(priors) > 0:
1626 params[
"priors"] = priors
1627 res = codedistance.codeDistance(
1628 H, L, tB=1, method=codedistance_method, params=params,
1629 seed=seed
if seed != 0
else None
1631 d = res.get(
"d", -1)
1636 global _distance_cache, _use_distance_cache, _distance_cache_file
1637 eff_cache_file = str(Path(cache_file).resolve())
if cache_file
is not None else _distance_cache_file
1640 if _use_distance_cache:
1644 dem_obj = dem
if dem
is not None else circuit
1646 code_key = f
"dem:{dem_state}" if pmin <= 0.0
else f
"dem:{dem_state}:pmin={pmin}"
1647 cached_entry = _distance_cache.get(code_key)
1648 if cached_entry
is not None:
1650 if cached_entry.get(
"dmin", 0) > 0
and cached_entry.get(
"dmin") == cached_entry.get(
"dmax"):
1651 if not (do_cws
or outC)
or (cached_entry.get(
"cws")
and len(cached_entry[
"cws"]) > 0):
1652 d_info =
format_bounds_list(cached_entry.get(
"dmin", 0), cached_entry.get(
"dmax", 0), cached_entry.get(
"rw_steps", 0))
1654 print(f
"[dist_m4ri] Cache retrieval: SUCCESS (found cached exact DEM distance for '{code_key}')")
1655 print(f
"[dist_m4ri] Cached result: dist={cached_entry['dist']}, bounds={format_bounds_str(d_info)}")
1657 print(
"[dist_m4ri] Cache hit for DEM distance (exact distance known)!")
1658 cws_res = cached_entry.get(
"cws", [])
1659 if outC
and cws_res:
1662 cached_entry[
"dist"], d_info, cws_res
1664 cached_entry[
"dist"], d_info
1667 print(f
"[dist_m4ri] Cache retrieval: PARTIAL (cached DEM bounds: dmin={cached_entry.get('dmin', 0)}, dmax={cached_entry.get('dmax', 0)}; continuing search)")
1669 if eff_dmax == 0
and cached_entry.get(
"dmax", 0) > 0:
1670 eff_dmax = cached_entry[
"dmax"]
1671 elif eff_dmax > 0
and cached_entry.get(
"dmax", 0) > 0:
1672 eff_dmax = min(eff_dmax, cached_entry[
"dmax"])
1673 if eff_dmin <= 1
and cached_entry.get(
"dmin", 0) > 1:
1674 eff_dmin = cached_entry[
"dmin"]
1675 elif eff_dmin > 1
and cached_entry.get(
"dmin", 0) > 1:
1676 eff_dmin = max(eff_dmin, cached_entry[
"dmin"])
1679 print(f
"[dist_m4ri] Cache retrieval: MISS (no entry for '{code_key}')")
1685 print(
"[dist_m4ri] Cache retrieval: DISABLED (cache is turned off)")
1689 if isinstance(dem, (str, Path))
and os.path.exists(str(dem)):
1693 temp_files.append(file_dem)
1694 if hasattr(dem,
'flattened'):
1695 dem.flattened().to_file(file_dem)
1696 elif hasattr(dem,
'to_file'):
1697 dem.to_file(file_dem)
1699 with open(file_dem,
'w')
as f:
1705 temp_files.append(outC_file)
1708 dist_m4ri_path=dist_m4ri,
1716 smax=smax
if smax
is not None else 0,
1733 dist = dmin_res
if (dmin_res == dmax_res
or dmax_res == 0)
else dmax_res
1735 if (do_cws
or outC)
and outC_file
and os.path.exists(outC_file):
1743 if _use_distance_cache
and code_key
is not None:
1744 prev_steps = cached_entry.get(
"rw_steps", 0)
if cached_entry
else 0
1745 prev_dmax = cached_entry.get(
"dmax", 0)
if cached_entry
else 0
1746 prev_dmin = cached_entry.get(
"dmin", 0)
if cached_entry
else 0
1747 prev_cws = list(cached_entry.get(
"cws", []))
if cached_entry
else []
1749 total_rw_steps = prev_steps + rw_steps
1750 best_dmax = min(prev_dmax, dmax_res)
if (prev_dmax > 0
and dmax_res > 0)
else (dmax_res
if dmax_res > 0
else prev_dmax)
1751 best_dmin = max(prev_dmin, dmin_res)
1753 combined_cws = prev_cws
1755 existing_set = {tuple(cw)
for cw
in combined_cws}
1757 if tuple(cw)
not in existing_set:
1758 combined_cws.append(cw)
1759 existing_set.add(tuple(cw))
1760 combined_cws.sort(key=len)
1764 _distance_cache[code_key] = {
1768 "rw_steps": total_rw_steps,
1776 return dist, d_info, cws
1780 for f
in temp_files:
1781 if f
and os.path.exists(f):
1783 except OSError:
pass
1787 """Writes codewords to a text file in NZLIST format (1-based indices)."""
1788 with open(filepath,
"w")
as f:
1789 f.write(
"%% NZLIST\n")
1790 f.write(f
"% {len(cws)} codewords\n")
1792 f.write(f
"{len(cw)} " +
" ".join(str(idx + 1)
for idx
in cw) +
"\n")
1796 """Parses CLI arguments supporting both key=value pairs and standard --flags."""
1797 args: Dict[str, Any] = {
1830 "solver":
"dist_m4ri",
1831 "cache_file":
"tmp_dist_cache.json",
1838 while i < len(argv):
1844 if arg
in (
"-h",
"--help",
"help"):
1849 if arg
in (
"-v",
"--verbose",
"verbose",
"-verbose"):
1850 args[
"verbose"] =
True
1854 if arg
in (
"--no-cache",
"-no-cache",
"nocache",
"--nocache"):
1855 args[
"use_cache"] =
False
1856 args[
"cache_file"] =
None
1860 if arg
in (
"--cws",
"-cws",
"cws",
"do_cws=1",
"--do_cws"):
1861 args[
"do_cws"] =
True
1868 key, val = arg.split(
"=", 1)
1869 if key.startswith(
"--"):
1871 elif key.startswith(
"-"):
1873 elif arg.startswith(
"--")
or arg.startswith(
"-"):
1874 key = arg.lstrip(
"-")
1875 if i + 1 < len(argv)
and not argv[i + 1].startswith(
"-")
and "=" not in argv[i + 1]:
1881 if os.path.exists(arg):
1882 if arg.endswith(
".dem"):
1884 elif arg.endswith(
".mmx")
or arg.endswith(
".mtx"):
1885 if args[
"finH"]
is None:
1887 elif args[
"finG"]
is None and args[
"finL"]
is None:
1893 key_lower = key.lower()
1894 if key_lower
in (
"cache",
"cache_file",
"cachefile"):
1895 if val.lower()
in (
"0",
"none",
"false",
"off",
"no"):
1896 args[
"use_cache"] =
False
1897 args[
"cache_file"] =
None
1899 args[
"use_cache"] =
True
1900 args[
"cache_file"] = val
1901 elif key_lower
in (
"fdem",
"dem"):
1903 elif key_lower ==
"finh":
1905 elif key_lower ==
"fing":
1907 elif key_lower ==
"finl":
1909 elif key_lower ==
"fin":
1911 elif key_lower
in (
"hx",
"finhx"):
1913 elif key_lower
in (
"hz",
"finhz"):
1915 elif key_lower
in (
"lx",
"finlx"):
1917 elif key_lower
in (
"lz",
"finlz"):
1919 elif key_lower ==
"finc":
1921 elif key_lower ==
"outc":
1923 args[
"do_cws"] =
True
1924 elif key_lower
in (
"method",
"m"):
1925 args[
"method"] = int(val)
1926 elif key_lower
in (
"dmin",
"d_min"):
1927 args[
"dmin"] = int(val)
1928 elif key_lower
in (
"dmax",
"d_max"):
1929 args[
"dmax"] = int(val)
1930 elif key_lower
in (
"wmin",
"w_min"):
1931 args[
"wmin"] = int(val)
1932 elif key_lower
in (
"wmax",
"w_max"):
1933 args[
"wmax"] = int(val)
1934 elif key_lower ==
"smax":
1935 args[
"smax"] = int(val)
1936 elif key_lower ==
"start":
1937 args[
"start"] = int(val)
1938 elif key_lower ==
"cbeg":
1939 args[
"cbeg"] = int(val)
1940 elif key_lower ==
"cend":
1941 args[
"cend"] = int(val)
1942 elif key_lower ==
"css":
1943 args[
"css"] = int(val)
1944 elif key_lower
in (
"dexp",
"dest",
"d_exp"):
1945 args[
"dexp"] = int(val)
1946 elif key_lower
in (
"steps",
"num_steps",
"nsteps"):
1947 args[
"steps"] = int(val)
1948 elif key_lower
in (
"threads",
"num_threads",
"t"):
1949 args[
"threads"] = int(val)
1950 elif key_lower
in (
"timeout",
"time"):
1951 args[
"timeout"] = float(val)
1952 elif key_lower ==
"dw":
1953 args[
"dW"] = int(val)
1954 elif key_lower
in (
"maxc",
"max_c"):
1955 args[
"maxC"] = int(val)
1956 elif key_lower ==
"pmin":
1957 args[
"pmin"] = float(val)
1958 elif key_lower ==
"noscan":
1959 args[
"noscan"] = int(val)
1960 elif key_lower ==
"classical":
1961 args[
"classical"] = int(val)
1962 elif key_lower ==
"seed":
1963 args[
"seed"] = int(val)
1964 elif key_lower
in (
"debug",
"dbg"):
1965 args[
"debug"] = int(val)
1966 elif key_lower ==
"solver":
1967 args[
"solver"] = val
1968 elif key_lower
in (
"verbose",
"v"):
1969 args[
"verbose"] = bool(int(val))
if val.isdigit()
else (val.lower()
not in (
"0",
"false",
"no",
"off"))
1970 elif key_lower ==
"cws":
1971 args[
"do_cws"] = bool(int(val))
if val.isdigit()
else (val.lower()
not in (
"0",
"false",
"no"))
1976 if args[
"classical"] == -1:
1977 if args[
"finG"]
is not None or args[
"finL"]
is not None or args[
"Hz"]
is not None or args[
"Lz"]
is not None or args[
"fdem"]
is not None or args[
"fin"]
is not None:
1978 args[
"classical"] = 0
1979 elif args[
"finH"]
is not None or args[
"Hx"]
is not None:
1980 args[
"classical"] = 1
1986 help_text =
"""dist_m4ri.py: Multithreaded distance calculator Python CLI
1988Usage: dist_m4ri.py [key=val | --flag val ...]
1991 fdem=FILE Detector Error Model input file (.dem)
1992 finH=FILE Parity check matrix input file (.mmx / .mtx)
1993 finG=FILE Generator matrix input file (.mmx / .mtx)
1994 finL=FILE Logical operator matrix input file (.mmx / .mtx)
1995 fin=PREFIX Prefix for check matrices (e.g. try -> tryX.mtx, tryZ.mtx)
1996 Hx=FILE, Hz=FILE CSS check matrices (alternative to finH/finL)
1997 Lx=FILE, Lz=FILE CSS logical operators (optional)
1998 method=N 1=RW, 2=CC, 3=Bracketing (default: 3)
1999 dmin=N Certified lower bound, inclusive (default: 0)
2000 dmax=N Known upper bound, inclusive (default: 0)
2001 wmin=N Minimum distance of interest (terminate early if cw of weight <= wmin is found in RW or CC, default: 1)
2002 wmax=N Maximum weight to search in CC
2003 smax=N Maximum syndrome weight for CC confinement profile
2004 start=N / cbeg=N Starting column index for CC scan
2005 cend=N Ending column index for CC scan
2006 dexp=N Expected distance estimate
2007 steps=N Maximum RW steps (default: 1000 in method 3)
2008 threads=N Worker threads (default: hardware concurrency)
2009 timeout=SEC Execution timeout in seconds (default: 60.0)
2010 dW=N Extra weight window above dmin to collect codewords
2011 maxC=N Maximum number of codewords to collect
2012 finC=FILE Input file with initial codewords (NZLIST format)
2013 outC=FILE File to output non-trivial codewords (NZLIST format)
2014 pmin=PROB Probability threshold for DEM errors
2015 noscan=1 Skip CC scan loop
2016 classical=1 Force classical mode (0 for CSS / quantum)
2018 debug=N Debug bitmask (e.g. 1, 2, 4)
2019 solver=NAME 'dist_m4ri' (default) or 'codedistance'
2020 cache=FILE Persistent JSON cache file (default: tmp_dist_cache.json)
2021 --no-cache / nocache Disable persistent JSON caching
2022 --verbose / -v Output detailed explanations of bounds, steps, and cache status
2023 --cws Collect and output non-trivial codewords
2028def main(argv: Optional[List[str]] =
None) -> int:
2034 if args.get(
"help")
or (
not args.get(
"fdem")
and not args.get(
"finH")
and not args.get(
"Hx")
and not args.get(
"fin")):
2039 args[
"finC"] =
check_finc_outc(args[
"finC"], args[
"outC"], verbose=args[
"verbose"])
2041 cache_file = args[
"cache_file"]
if args[
"use_cache"]
else None
2042 if not args[
"use_cache"]:
2049 method=args[
"method"],
2050 threads=args[
"threads"],
2051 timeout=args[
"timeout"],
2052 num_steps=args[
"steps"],
2059 start=args[
"start"],
2062 noscan=args[
"noscan"],
2068 do_cws=args[
"do_cws"]
or (args[
"outC"]
is not None),
2069 cache_file=cache_file,
2070 solver=args[
"solver"],
2072 debug=args[
"debug"],
2073 verbose=args[
"verbose"]
2075 if args[
"do_cws"]
or (args[
"outC"]
is not None):
2076 dist, d_info, cws = res
2083 print(
"=== DEM Distance Results ===")
2084 print(
explain_bounds(d_info, method=args[
"method"], label=
"DEM"))
2085 print(f
" Summary bounds: {format_bounds_str(d_info)}")
2089 if args[
"Hx"]
is not None or args[
"Hz"]
is not None:
2095 method=args[
"method"],
2096 threads=args[
"threads"],
2097 timeout=args[
"timeout"],
2098 num_steps=args[
"steps"],
2105 start=args[
"start"],
2108 noscan=args[
"noscan"],
2113 do_cws=args[
"do_cws"]
or (args[
"outC"]
is not None),
2114 cache_file=cache_file,
2115 solver=args[
"solver"],
2117 debug=args[
"debug"],
2118 verbose=args[
"verbose"]
2120 if args[
"do_cws"]
or (args[
"outC"]
is not None):
2121 dist, dx_info, dz_info, cws_x, cws_z = res
2125 dist, dx_info, dz_info = res
2127 exact_tag =
" (exact)" if (dx_info
and dx_info[0] > 0
and dx_info[0] == dx_info[1]
and dz_info
and dz_info[0] > 0
and dz_info[0] == dz_info[1])
else ""
2130 print(
"=== CSS Quantum Code Distance Results ===")
2132 print(
"--- X-Component Distance (dX) ---")
2133 print(
explain_bounds(dx_info, method=args[
"method"], label=
"dX"))
2134 print(f
" dX bounds: {format_bounds_str(dx_info)}")
2136 print(
"--- Z-Component Distance (dZ) ---")
2137 print(
explain_bounds(dz_info, method=args[
"method"], label=
"dZ"))
2138 print(f
" dZ bounds: {format_bounds_str(dz_info)}")
2139 print(
"--- Overall CSS Code Distance ---")
2140 print(f
" d = min(dX, dZ) = {dist}{exact_tag}")
2144 print(f
"dX: {dx_str} dZ: {dz_str} (d = {dist}){exact_tag}")
2151 if finH
is None: finH = f
"{args['fin']}X.mtx"
2152 if finG
is None and args[
"finL"]
is None: finG = f
"{args['fin']}Z.mtx"
2155 if finH
and (finG
is not None or args[
"finL"]
is not None or args[
"classical"] == 0):
2160 method=args[
"method"],
2161 threads=args[
"threads"],
2162 timeout=args[
"timeout"],
2163 num_steps=args[
"steps"],
2170 start=args[
"start"],
2173 noscan=args[
"noscan"],
2178 do_cws=args[
"do_cws"]
or (args[
"outC"]
is not None),
2180 cache_file=cache_file,
2181 solver=args[
"solver"],
2183 debug=args[
"debug"],
2184 verbose=args[
"verbose"]
2186 if args[
"do_cws"]
or (args[
"outC"]
is not None):
2187 dist, d_info, cws = res
2194 print(
"=== Quantum Code Distance Results (Single-Sided) ===")
2195 print(
explain_bounds(d_info, method=args[
"method"], label=
"Quantum"))
2196 print(f
" Summary bounds: {format_bounds_str(d_info)}")
2204 method=args[
"method"],
2205 threads=args[
"threads"],
2206 timeout=args[
"timeout"],
2207 num_steps=args[
"steps"],
2214 start=args[
"start"],
2217 noscan=args[
"noscan"],
2222 do_cws=args[
"do_cws"]
or (args[
"outC"]
is not None),
2224 cache_file=cache_file,
2225 solver=args[
"solver"],
2227 debug=args[
"debug"],
2228 verbose=args[
"verbose"]
2230 if args[
"do_cws"]
or (args[
"outC"]
is not None):
2231 dist, d_info, cws = res
2238 print(
"=== Classical Code Distance Results ===")
2239 print(
explain_bounds(d_info, method=args[
"method"], label=
"Classical"))
2240 print(f
" Summary bounds: {format_bounds_str(d_info)}")
2243 except ValueError
as e:
2244 sys.stderr.write(f
"Error: {e}\n")
2250if __name__ ==
"__main__":
bool __eq__(self, Any other)
__init__(self, int dmin, int dmax, int rw_steps=0, Optional[List[List[int]]] cws=None, Optional[List[List[int]]] cws_X=None, Optional[List[List[int]]] cws_Z=None, Optional[int] dmin_X=None, Optional[int] dmax_X=None, Optional[int] rw_steps_X=None, Optional[int] dmin_Z=None, Optional[int] dmax_Z=None, Optional[int] rw_steps_Z=None)
__getitem__(self, int index)
str find_dist_m4ri_binary(Optional[str] custom_path=None)
int main(Optional[List[str]] argv=None)
str create_unique_file(Union[str, Path] directory="tmp", str extension=".tmp")
str format_bounds_str(List[int] bounds)
List[int] format_bounds_list(int dmin, int dmax, int num_rw)
Any __getattr__(str name)
None set_distance_cache_file(Optional[Union[str, Path]] filepath=None)
Tuple[int, int, int] run_dist_m4ri(Optional[str] dist_m4ri_path=None, int method=3, Optional[str] finH=None, Optional[str] finG=None, Optional[str] finL=None, Optional[str] fin=None, Optional[str] finC=None, Optional[str] fdem=None, int dmin=0, int dmax=0, int wmax=0, int wmin=1, int dexp=0, int dest=0, Optional[int] steps=None, Optional[int] threads=None, float timeout=60.0, Optional[int] smax=None, Optional[int] start=None, Optional[int] cbeg=None, Optional[int] cend=None, Optional[int] css=None, int noscan=0, int classical=-1, int dW=-1, int maxC=0, float pmin=0.0, Optional[str] outC=None, int seed=0, int debug=0, Optional[threading.Event] stop_event=None)
Dict[str, Any] get_distance_cache()
str _matrix_to_file(matrix, str extension=".mtx", str temp_dir="tmp")
None _write_nzlist_file(str filepath, List[List[int]] cws)
Dict[str, Any] parse_cli_args(List[str] argv)
Any compute_classical_distance(Any H, Optional[str] dist_m4ri=None, int method=3, Optional[int] threads=None, float timeout=60.0, Optional[int] num_steps=None, int d_exp=0, int d_min=0, int d_max=0, int dmin=0, int dmax=0, int wmin=1, int wmax=0, Optional[int] smax=None, Optional[int] start=None, Optional[int] cbeg=None, Optional[int] cend=None, int noscan=0, int dW=-1, int maxC=0, Optional[str] finC=None, Optional[str] outC=None, bool do_cws=False, bool return_info=False, Optional[Union[str, Path]] cache_file=None, str solver="dist_m4ri", str codedistance_method="QDistEvol", Optional[Dict[str, Any]] codedistance_params=None, int seed=0, int debug=0, bool verbose=False)
Tuple[int, int, int] parse_dist_m4ri_output(str stdout)
None clear_distance_cache(Optional[Union[str, Path]] cache_file=None, bool clear_file=False)
List[List[int]] read_sparse_vectors(str filepath)
str get_sparse_array_state(A)
Optional[Dict[str, Any]] get_cached_distance(Optional[Any] H=None, Optional[Any] G=None, Optional[Any] L=None, Optional[Any] Hx=None, Optional[Any] Hz=None, Optional[Any] Lx=None, Optional[Any] Lz=None, Optional[Any] dem=None, Optional[Any] circuit=None, float pmin=0.0, Optional[Union[str, Path]] cache_file=None)
Tuple[Any,...] compute_dem_distance(Optional[Any] dem=None, Optional[Any] circuit=None, Optional[str] dist_m4ri=None, int method=3, Optional[int] threads=None, float timeout=60.0, Optional[int] num_steps=None, int d_exp=0, int d_min=0, int d_max=0, int dmin=0, int dmax=0, int wmin=1, int wmax=0, Optional[int] smax=None, Optional[int] start=None, Optional[int] cbeg=None, Optional[int] cend=None, int noscan=0, int dW=-1, int maxC=0, float pmin=0.0, Optional[str] finC=None, Optional[str] outC=None, bool do_cws=False, Optional[Union[str, Path]] cache_file=None, str solver="dist_m4ri", str codedistance_method="UndetectableErrorStim", Optional[Dict[str, Any]] codedistance_params=None, int seed=0, int debug=0, bool verbose=False, **kwargs)
None enable_distance_cache()
None save_distance_cache(Optional[Union[str, Path]] filepath=None)
Optional[str] check_finc_outc(Optional[str] finC, Optional[str] outC, bool verbose=False)
Any compute_quantum_distance(Any H, Optional[Any] G=None, Optional[Any] L=None, Optional[str] dist_m4ri=None, int method=3, Optional[int] threads=None, float timeout=60.0, Optional[int] num_steps=None, int d_exp=0, int d_min=0, int d_max=0, int dmin=0, int dmax=0, int wmin=1, int wmax=0, Optional[int] smax=None, Optional[int] start=None, Optional[int] cbeg=None, Optional[int] cend=None, int noscan=0, int dW=-1, int maxC=0, Optional[str] finC=None, Optional[str] outC=None, bool do_cws=False, bool return_info=False, Optional[Union[str, Path]] cache_file=None, str solver="dist_m4ri", str codedistance_method="QDistEvol", Optional[Dict[str, Any]] codedistance_params=None, int seed=0, int debug=0, bool verbose=False)
Dict[str, Any] load_distance_cache(Optional[Union[str, Path]] filepath=None)
Tuple[Any,...] compute_css_distance(Any Hx, Any Hz, Optional[Any] Lx=None, Optional[Any] Lz=None, Optional[str] dist_m4ri=None, int method=3, Optional[int] threads=None, float timeout=60.0, Optional[int] num_steps=None, int d_exp=0, int d_min=0, int d_max=0, int dmin=0, int dmax=0, int wmin=1, int wmax=0, Optional[int] smax=None, Optional[int] start=None, Optional[int] cbeg=None, Optional[int] cend=None, int noscan=0, int dW=-1, int maxC=0, Optional[str] finC=None, Optional[str] outC=None, bool do_cws=False, Optional[Union[str, Path]] cache_file=None, str solver="dist_m4ri", str codedistance_method="QDistEvol", Optional[Dict[str, Any]] codedistance_params=None, int seed=0, int debug=0, bool verbose=False, **kwargs)
str explain_bounds(List[int] bounds, Optional[int] method=None, str label="")
None disable_distance_cache()