Dist m4ri 0.0.1.alpha
Computing distance of a classical or quantum CSS code
Loading...
Searching...
No Matches
test_dist_m4ri.py
Go to the documentation of this file.
1"""
2Unit tests for dist_m4ri.py Python wrapper.
3"""
4
5import os
6import sys
7import pytest
8import numpy as np
9import scipy.sparse as sp
10
11# Add root directory to sys.path
12sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
13
14import dist_m4ri
15
16EXAMPLES_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "examples"))
17
18
21 assert os.path.isfile(bin_path)
22 assert os.access(bin_path, os.X_OK)
23
24
26 h_file = os.path.join(EXAMPLES_DIR, "c204H.mmx")
27 d = dist_m4ri.compute_classical_distance(h_file, d_exp=10, threads=4)
28 assert d == 8
29
30
32 # Hamming [7, 4, 3] code
33 H = np.array([
34 [1, 0, 0, 1, 1, 0, 1],
35 [0, 1, 0, 1, 0, 1, 1],
36 [0, 0, 1, 0, 1, 1, 1]
37 ], dtype=np.int8)
39 assert d == 3
40
41 # With codewords
42 d, cws = dist_m4ri.compute_classical_distance(H, do_cws=True, threads=2)
43 assert d == 3
44 assert len(cws) > 0
45 assert all(len(cw) == 3 for cw in cws)
46
47
49 hx_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
50 hz_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
51 # For surf_d5: Hx as finH, Hz as finL gives d=5
52 dist, d_x, d_z = dist_m4ri.compute_css_distance(
53 Hx=hx_file, Hz=hx_file, Lz=hz_file, Lx=hz_file,
54 d_exp=5, threads=4
55 )
56 assert dist == 5
57 assert d_x == [5, 5, 0]
58 assert d_z == [5, 5, 0]
59
60
62 # Surface code d=3
63 hx = sp.csr_matrix([
64 [1, 1, 0, 1, 1, 0, 0, 0, 0],
65 [0, 1, 1, 0, 1, 1, 0, 0, 0],
66 [0, 0, 0, 1, 1, 0, 1, 1, 0],
67 [0, 0, 0, 0, 1, 1, 0, 1, 1]
68 ], dtype=np.int8)
69 hz = sp.csr_matrix([
70 [1, 0, 0, 1, 0, 0, 1, 0, 0],
71 [0, 1, 0, 0, 1, 0, 0, 1, 0],
72 [0, 0, 1, 0, 0, 1, 0, 0, 1]
73 ], dtype=np.int8)
74 dist, d_x, d_z = dist_m4ri.compute_css_distance(hx, hz, threads=2)
75 assert dist > 0
76 assert len(d_x) == 3
77 assert len(d_z) == 3
78
79
81 dem_file = os.path.join(EXAMPLES_DIR, "surf_d3.dem")
82 dist, d_info = dist_m4ri.compute_dem_distance(dem=dem_file, threads=4)
83 assert dist == 3
84 assert d_info == [3, 3, 0]
85
86 # With codewords (method=3 bracketing mode collects discovered cws)
87 dist, d_info, cws = dist_m4ri.compute_dem_distance(dem=dem_file, do_cws=True, threads=4)
88 assert dist == 3
89 assert d_info == [3, 3, 0]
90 assert len(cws) > 0
91 assert all(len(cw) == 3 for cw in cws)
92
93 # Exhaustive CC scan (method=2) finds all 128 codewords
94 dist, d_info, cws_cc = dist_m4ri.compute_dem_distance(dem=dem_file, method=2, wmax=3, do_cws=True, threads=4)
95 assert dist == 3
96 assert d_info == [3, 3, 0]
97 assert len(cws_cc) == 128
98 assert all(len(cw) == 3 for cw in cws_cc)
99
100
102 if not dist_m4ri._HAS_STIM:
103 pytest.skip("stim is not installed")
104 import stim
105 circuit = stim.Circuit.generated(
106 "surface_code:rotated_memory_z",
107 rounds=3,
108 distance=3,
109 after_clifford_depolarization=0.001
110 )
111 dem = circuit.detector_error_model(decompose_errors=True)
112 dist, d_info = dist_m4ri.compute_dem_distance(dem=dem, threads=4)
113 assert dist == 3
114 assert d_info == [3, 3, 0]
115
116
120
121 H = np.array([
122 [1, 0, 0, 1, 1, 0, 1],
123 [0, 1, 0, 1, 0, 1, 1],
124 [0, 0, 1, 0, 1, 1, 1]
125 ], dtype=np.int8)
126
127 d1 = dist_m4ri.compute_classical_distance(H, threads=2)
128 assert len(dist_m4ri._distance_cache) == 1
129
130 # Second call should be a cache hit
131 d2 = dist_m4ri.compute_classical_distance(H, threads=2)
132 assert d1 == d2
133 assert len(dist_m4ri._distance_cache) == 1
134
136 assert len(dist_m4ri._distance_cache) == 0
137
138
140 if not dist_m4ri._HAS_CODEDISTANCE:
141 pytest.skip("codedistance is not installed")
142
143 H = np.array([
144 [1, 0, 0, 1, 1, 0, 1],
145 [0, 1, 0, 1, 0, 1, 1],
146 [0, 0, 1, 0, 1, 1, 1]
147 ], dtype=np.int8)
148
150 # Method 2 (CC only): rw_steps must be 0
151 h_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
152 l_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
153 dmin, dmax, rw_steps = dist_m4ri.run_dist_m4ri(method=2, finH=h_file, finL=l_file, wmax=5, threads=4)
154 assert (dmin, dmax, rw_steps) == (5, 5, 0)
155
156 # Method 2 (CC not found): dmin=wmax+1, dmax=0, rw_steps=0
157 dmin, dmax, rw_steps = dist_m4ri.run_dist_m4ri(method=2, finH=h_file, finL=l_file, wmax=3, threads=4)
158 assert (dmin, dmax, rw_steps) == (4, 0, 0)
159
160 # Method 1 (RW): rw_steps reported
161 dem_file = os.path.join(EXAMPLES_DIR, "surf_d3.dem")
162 dmin, dmax, rw_steps = dist_m4ri.run_dist_m4ri(method=1, fdem=dem_file, steps=100, threads=4)
163 assert dmin == 1
164 assert dmax == 3
165 assert rw_steps >= 100
166
167
169 # Test dmin/dmax in run_dist_m4ri
170 h_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
171 l_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
172 dmin, dmax, rw_steps = dist_m4ri.run_dist_m4ri(method=3, finH=h_file, finL=l_file, dmin=4, dmax=5, timeout=5, threads=4)
173 assert (dmin, dmax) == (5, 5)
174
175 # Test dmin/dmax in compute_classical_distance
176 c_file = os.path.join(EXAMPLES_DIR, "c204H.mmx")
177 d = dist_m4ri.compute_classical_distance(c_file, dmin=5, dmax=8, threads=4)
178 assert d == 8
179
180 # Test dmin/dmax in compute_dem_distance
181 dem_file = os.path.join(EXAMPLES_DIR, "surf_d3.dem")
182 d_dem, _ = dist_m4ri.compute_dem_distance(dem=dem_file, dmin=2, dmax=4, threads=4)
183 assert d_dem == 3
184
185
189
190 c_file = os.path.join(EXAMPLES_DIR, "c1920H.mmx")
191
192 # Run 1: 50 steps
193 d1 = dist_m4ri.compute_classical_distance(c_file, method=1, num_steps=50, threads=4)
194 entry1 = dist_m4ri.get_cached_distance(H=c_file)
195 assert entry1 is not None
196 assert entry1["rw_steps"] == 50
197 assert entry1["dmax"] > 0
198 assert d1 == entry1["dmax"]
199
200 # Run 2: another 100 steps
201 d2 = dist_m4ri.compute_classical_distance(c_file, method=1, num_steps=100, threads=4)
202 entry2 = dist_m4ri.get_cached_distance(H=c_file)
203 assert entry2 is not None
204 assert entry2["rw_steps"] == 150
205 assert entry2["dmax"] <= entry1["dmax"]
206 assert d2 == entry2["dmax"]
207
209
210
212 # Exact known distance
213 assert dist_m4ri.format_bounds_list(5, 5, 0) == [5, 5, 0]
214 assert dist_m4ri.format_bounds_str([5, 5, 0]) == "5 5 0 (exact)"
215
216 # No upper bound (dmax == 0)
217 assert dist_m4ri.format_bounds_list(4, 0, 0) == [4, 0, 0]
218 assert dist_m4ri.format_bounds_str([4, 0, 0]) == "4 0 0"
219
220 # No lower bound (dmin <= 1)
221 assert dist_m4ri.format_bounds_list(0, 323, 100) == [0, 323, 100]
222 assert dist_m4ri.format_bounds_str([0, 323, 100]) == "0 323 100"
223
224 # Lower and upper bounds differing
225 assert dist_m4ri.format_bounds_list(4, 6, 1000) == [4, 6, 1000]
226 assert dist_m4ri.format_bounds_str([4, 6, 1000]) == "4 6 1000"
227
228
230 import json
231 json_file = str(tmp_path / "test_cache.json")
232
234 c_file = os.path.join(EXAMPLES_DIR, "c1920H.mmx")
235
236 # Run 1: 50 steps with cache_file
237 d1 = dist_m4ri.compute_classical_distance(c_file, method=1, num_steps=50, threads=4, cache_file=json_file)
238 assert os.path.isfile(json_file)
239
240 with open(json_file, "r") as f:
241 data1 = json.load(f)
242 assert len(data1) == 1
243 key = list(data1.keys())[0]
244 assert data1[key]["rw_steps"] == 50
245 assert data1[key]["dmax"] == d1
246
247 # Clear memory cache and re-read from JSON
249 entry = dist_m4ri.get_cached_distance(H=c_file, cache_file=json_file)
250 assert entry is not None
251 assert entry["rw_steps"] == 50
252
253 # Run 2: another 100 steps
254 d2 = dist_m4ri.compute_classical_distance(c_file, method=1, num_steps=100, threads=4, cache_file=json_file)
255 with open(json_file, "r") as f:
256 data2 = json.load(f)
257 assert data2[key]["rw_steps"] == 150
258 assert data2[key]["dmax"] <= d1
259
260 # CSS persistent caching
261 hx_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
262 hz_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
263 d_css, dx_info, dz_info = dist_m4ri.compute_css_distance(
264 Hx=hx_file, Hz=hx_file, Lz=hz_file, Lx=hz_file,
265 d_exp=5, threads=4, cache_file=json_file
266 )
267 assert d_css == 5
268 with open(json_file, "r") as f:
269 data_css = json.load(f)
270 assert len(data_css) >= 2
271
272 # DEM persistent caching
273 dem_file = os.path.join(EXAMPLES_DIR, "surf_d3.dem")
274 d_dem, d_info = dist_m4ri.compute_dem_distance(dem=dem_file, threads=4, cache_file=json_file)
275 assert d_dem == 3
276 with open(json_file, "r") as f:
277 data_dem = json.load(f)
278 assert len(data_dem) >= 3
279
280 dist_m4ri.clear_distance_cache(cache_file=json_file, clear_file=True)
281 assert not os.path.exists(json_file)
282
283
285 h_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
286 l_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
288 H=h_file, L=l_file, method=3, d_exp=5, threads=4, return_info=True
289 )
290 assert dist == 5
291 assert d_info == [5, 5, 0]
292
293
295 # Auto-infer classical = 0 when finG or finL is given
296 args1 = dist_m4ri.parse_cli_args(["finH=h.mtx", "finG=g.mtx", "smax=0", "finC=init.nz", "start=2"])
297 assert args1["classical"] == 0
298 assert args1["finH"] == "h.mtx"
299 assert args1["finG"] == "g.mtx"
300 assert args1["smax"] == 0
301 assert args1["finC"] == "init.nz"
302 assert args1["start"] == 2
303
304 # Auto-infer classical = 1 when only finH is given
305 args2 = dist_m4ri.parse_cli_args(["finH=h.mtx", "method=2"])
306 assert args2["classical"] == 1
307 assert args2["finH"] == "h.mtx"
308 assert args2["finG"] is None
309
310 # Auto-infer classical = 0 when fdem is given
311 args3 = dist_m4ri.parse_cli_args(["fdem=model.dem"])
312 assert args3["classical"] == 0
313
314
318
319 h_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
320 l_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
321
322 # Classical distance of H
323 d_class = dist_m4ri.compute_classical_distance(h_file, dmax=5, threads=4)
324 # Quantum distance of (H, L)
325 d_quant = dist_m4ri.compute_quantum_distance(h_file, L=l_file, dmax=5, threads=4)
326
328 class_keys = [k for k in cache if k.startswith("classical:")]
329 quant_keys = [k for k in cache if k.startswith("quantum:")]
330
331 assert len(class_keys) >= 1
332 assert len(quant_keys) >= 1
333
335
336
338 # Exact distance
339 exp1 = dist_m4ri.explain_bounds([5, 5, 0], method=2, label="dX")
340 assert "Lower bound (dmin = 5): Exact distance certified" in exp1
341 assert "Upper bound (dmax = 5): Weight of the smallest non-trivial codeword discovered" in exp1
342 assert "Random window steps (rw_steps = 0): Set to 0 because the exact distance d = 5 was proven" in exp1
343
344 # Pure lower bound in method 2
345 exp2 = dist_m4ri.explain_bounds([4, 0, 0], method=2)
346 assert "All cluster weights w <= 3 were exhaustively analyzed" in exp2
347 assert "Method 2 (Connected Cluster) is an exhaustive search" in exp2
348
349 # RW search
350 exp3 = dist_m4ri.explain_bounds([1, 8, 120], method=1)
351 assert "No non-trivial lower bound certified" in exp3
352 assert "120 completed random information set searches" in exp3
353
354
356 hx_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
357 lz_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
358 ret = dist_m4ri.main([
359 f"Hx={hx_file}", f"Hz={hx_file}", f"Lx={lz_file}", f"Lz={lz_file}",
360 "method=2", "wmax=5", "--no-cache", "threads=4"
361 ])
362 assert ret == 0
363 captured = capsys.readouterr()
364 assert "dX: 5 5 0 (exact)" in captured.out
365 assert "dZ: 5 5 0 (exact)" in captured.out
366 assert "(d = 5) (exact)" in captured.out
367
368
370 h_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
371 l_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
372 ret = dist_m4ri.main([
373 "--verbose", "method=2", f"finH={h_file}", f"finL={l_file}",
374 "wmax=5", "threads=4"
375 ])
376 assert ret == 0
377 captured = capsys.readouterr()
378 assert "Cache retrieval:" in captured.out
379 assert "Lower bound" in captured.out
380 assert "Upper bound" in captured.out
381 assert "Random window steps" in captured.out
382
383
385 import tempfile
386
387 # Non-existent file when finC == outC
388 assert dist_m4ri.check_finc_outc("nonexistent.nz", "nonexistent.nz") is None
389
390 # Non-existent file when finC != outC
391 assert dist_m4ri.check_finc_outc("nonexistent.nz", "other.nz") == "nonexistent.nz"
392
393 # Empty 0-byte file when finC == outC
394 with tempfile.NamedTemporaryFile(suffix=".nz", delete=False) as f:
395 tmp_empty = f.name
396 try:
397 assert dist_m4ri.check_finc_outc(tmp_empty, tmp_empty) is None
398 finally:
399 if os.path.exists(tmp_empty):
400 os.remove(tmp_empty)
401
402 # Existing non-empty file when finC == outC
403 with tempfile.NamedTemporaryFile(suffix=".nz", delete=False, mode="w") as f:
404 f.write("1 2 3\n")
405 tmp_nonempty = f.name
406 try:
407 assert dist_m4ri.check_finc_outc(tmp_nonempty, tmp_nonempty) == tmp_nonempty
408 finally:
409 if os.path.exists(tmp_nonempty):
410 os.remove(tmp_nonempty)
411
412
414 import tempfile
415 h_file = os.path.join(EXAMPLES_DIR, "surf_d5_H.mmx")
416 l_file = os.path.join(EXAMPLES_DIR, "surf_d5_L.mmx")
417
418 tmp_out = os.path.join(tempfile.gettempdir(), f"tmp_test_cw_{os.getpid()}.nz")
419 if os.path.exists(tmp_out):
420 os.remove(tmp_out)
421
422 try:
423 ret = dist_m4ri.main([
424 "--verbose", "--no-cache", "method=2",
425 f"finH={h_file}", f"finL={l_file}",
426 f"finC={tmp_out}", f"outC={tmp_out}",
427 "wmax=5", "threads=4"
428 ])
429 assert ret == 0
430 captured = capsys.readouterr()
431 assert "Warning: finC=" in captured.out
432 assert "is empty or non-existent; silently ignoring input codewords." in captured.out
433 assert "5 5 0 (exact)" in captured.out
434 assert os.path.exists(tmp_out)
435 finally:
436 if os.path.exists(tmp_out):
437 os.remove(tmp_out)
438
439
440if __name__ == "__main__":
441 pytest.main([__file__, "-v"])
442
443
444
str find_dist_m4ri_binary(Optional[str] custom_path=None)
Definition dist_m4ri.py:398
int main(Optional[List[str]] argv=None)
str format_bounds_str(List[int] bounds)
Definition dist_m4ri.py:189
List[int] format_bounds_list(int dmin, int dmax, int num_rw)
Definition dist_m4ri.py:168
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)
Definition dist_m4ri.py:594
Dict[str, Any] get_distance_cache()
Definition dist_m4ri.py:162
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)
Definition dist_m4ri.py:718
None clear_distance_cache(Optional[Union[str, Path]] cache_file=None, bool clear_file=False)
Definition dist_m4ri.py:136
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)
Definition dist_m4ri.py:253
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()
Definition dist_m4ri.py:150
Optional[str] check_finc_outc(Optional[str] finC, Optional[str] outC, bool verbose=False)
Definition dist_m4ri.py:544
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)
Definition dist_m4ri.py:955
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="")
Definition dist_m4ri.py:197
test_cli_verbose_mode(capsys)
test_quantum_distance_single_sided()
test_persistent_json_cache(tmp_path)
test_cli_css_dx_dz_bounds(capsys)
test_cli_identical_finc_outc_nonexistent(capsys)