Skip to content

Commit 511b90d

Browse files
committed
feat(v0.7.0): add comprehensive benchmark suite, update symbol surfaces, export official data artifacts (JSON, CSV, MD, PDF)
1 parent 3d60a96 commit 511b90d

41 files changed

Lines changed: 5344 additions & 58 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

chart_official_batch_scaling.png

164 KB
Loading

chart_official_ler.png

173 KB
Loading

chart_official_throughput.png

188 KB
Loading

official_benchmark_results.csv

Lines changed: 265 additions & 0 deletions
Large diffs are not rendered by default.

official_benchmark_results.json

Lines changed: 4016 additions & 0 deletions
Large diffs are not rendered by default.

official_benchmark_results.md

Lines changed: 288 additions & 0 deletions
Large diffs are not rendered by default.

official_benchmark_results.pdf

385 KB
Binary file not shown.

python/qector_decoder_v3/__init__.py

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,7 @@ def _py_estimate_distance(check_to_qubits, n_qubits=None):
304304
max_q = 0
305305
for qs in check_to_qubits:
306306
for q in qs:
307-
if q > max_q:
308-
max_q = q
307+
max_q = max(max_q, q)
309308
nq = max_q + 1
310309
else:
311310
nq = n_qubits
@@ -1453,6 +1452,15 @@ def decode(self, syndrome):
14531452
raise TypeError(f"Syndrome must be dtype uint8, got {syndrome.dtype}")
14541453
return self._inner.decode(syndrome)
14551454

1455+
def batch_decode(self, syndromes):
1456+
if not isinstance(syndromes, _np.ndarray):
1457+
syndromes = _np.array(syndromes, dtype=_np.uint8)
1458+
if syndromes.dtype != _np.uint8:
1459+
syndromes = syndromes.astype(_np.uint8)
1460+
if syndromes.ndim != 2:
1461+
raise ValueError(f"syndromes must be 2D, got shape {syndromes.shape}")
1462+
return self._inner.batch_decode(syndromes)
1463+
14561464
@property
14571465
def n_qubits(self):
14581466
return self._inner.n_qubits
@@ -1488,6 +1496,15 @@ def decode(self, syndrome):
14881496
raise TypeError(f"Syndrome must be dtype uint8, got {syndrome.dtype}")
14891497
return self._inner.decode(syndrome)
14901498

1499+
def batch_decode(self, syndromes):
1500+
if not isinstance(syndromes, _np.ndarray):
1501+
syndromes = _np.array(syndromes, dtype=_np.uint8)
1502+
if syndromes.dtype != _np.uint8:
1503+
syndromes = syndromes.astype(_np.uint8)
1504+
if syndromes.ndim != 2:
1505+
raise ValueError(f"syndromes must be 2D, got shape {syndromes.shape}")
1506+
return self._inner.batch_decode(syndromes)
1507+
14911508
@property
14921509
def n_qubits(self):
14931510
return self._inner.n_qubits
@@ -2377,6 +2394,9 @@ def run_all(self):
23772394
"check_to_edges",
23782395
"compute_detector_differences",
23792396
"cuda_is_available",
2397+
"enforce_distance_cap",
2398+
"enforce_unlocked",
2399+
"estimate_distance",
23802400
"flush_usage",
23812401
"from_circuit",
23822402
"generate_biconnected_qldpc_checks",
@@ -2388,14 +2408,11 @@ def run_all(self):
23882408
"generate_toy_code_checks",
23892409
"generate_triangular_color_code_4_8_8_checks",
23902410
"get_latency_quantiles",
2391-
"set_license_key_file",
23922411
"opencl_is_available",
23932412
"run_grpc_server",
23942413
"run_mcp_server",
2414+
"set_license_key_file",
23952415
"start_metrics_server",
2396-
"enforce_unlocked",
2397-
"enforce_distance_cap",
2398-
"estimate_distance",
23992416
]
24002417

24012418

@@ -2435,8 +2452,6 @@ def run_all(self):
24352452
__all__ += [
24362453
"AmbiguityClusterDecoder",
24372454
"AutoDecoder",
2438-
"NativeAutoDecoder",
2439-
"TwoStageDecoder",
24402455
"Backend",
24412456
"BackendConfig",
24422457
"BeliefMatching",
@@ -2445,7 +2460,9 @@ def run_all(self):
24452460
"DecodeResult",
24462461
"DecoderPool",
24472462
"GNNBeliefMatcher",
2463+
"NativeAutoDecoder",
24482464
"PredecodedDecoder",
2465+
"TwoStageDecoder",
24492466
"Workbench",
24502467
"backend",
24512468
"belief_matching",
@@ -2488,18 +2505,38 @@ def run_all(self):
24882505
except Exception: # pragma: no cover
24892506
stripe_integration = None # type: ignore[assignment]
24902507

2508+
try:
2509+
from . import bench_quick
2510+
except Exception: # pragma: no cover
2511+
bench_quick = None # type: ignore[assignment]
2512+
2513+
try:
2514+
from . import cli
2515+
except Exception: # pragma: no cover
2516+
cli = None # type: ignore[assignment]
2517+
2518+
try:
2519+
from . import doctor
2520+
except Exception: # pragma: no cover
2521+
doctor = None # type: ignore[assignment]
2522+
2523+
try:
2524+
from . import ler
2525+
except Exception: # pragma: no cover
2526+
ler = None # type: ignore[assignment]
2527+
24912528
__all__ += [
24922529
"MAX_WORKERS",
2530+
"get_accumulated_shots",
2531+
"get_license_info",
24932532
"license",
24942533
"qiskit_plugin",
2534+
"record_shots",
24952535
"rest_api",
2536+
"set_license_key",
24962537
"stim_compat",
24972538
"stripe_integration",
24982539
"verify_license_token",
2499-
"set_license_key",
2500-
"get_license_info",
2501-
"record_shots",
2502-
"get_accumulated_shots",
25032540
]
25042541

25052542
# ---------------------------------------------------------------------------

python/qector_decoder_v3/bench_quick.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import sys
77
import time
88

9-
109
# A5: every guard in this module caught `RuntimeError`, which is not a base of
1110
# ImportError / PackageNotFoundError / OSError. A missing optional package or an
1211
# absent GPU driver therefore propagated instead of degrading — in a *diagnostic*

python/qector_decoder_v3/cli.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,16 @@ def _build_parser() -> argparse.ArgumentParser:
3939

4040
def cmd_decode(args: argparse.Namespace) -> None:
4141
import numpy as np
42-
from . import BlossomDecoder, SparseBlossomDecoder, UnionFindDecoder, \
43-
FastUnionFindDecoder, BPOSDDecoder, BeliefMatchingDecoder, AutoDecoder
42+
43+
from . import (
44+
AutoDecoder,
45+
BeliefMatchingDecoder,
46+
BlossomDecoder,
47+
BPOSDDecoder,
48+
FastUnionFindDecoder,
49+
SparseBlossomDecoder,
50+
UnionFindDecoder,
51+
)
4452

4553
syndromes = np.load(args.input) if args.input.endswith(".npy") else \
4654
np.loadtxt(args.input, dtype=np.uint8, delimiter=",")
@@ -61,7 +69,7 @@ def cmd_decode(args: argparse.Namespace) -> None:
6169
dec = decoder_map[args.decoder](c2q, nq)
6270
elif args.decoder == "belief_match":
6371
from .dem import from_stim
64-
dec = BeliefMatchingDecoder(c2q, nq, **{"dem_model": from_stim})
72+
dec = BeliefMatchingDecoder(c2q, nq, dem_model=from_stim)
6573
elif args.decoder == "auto":
6674
dec = AutoDecoder(c2q, nq)
6775
else:
@@ -76,6 +84,7 @@ def cmd_decode(args: argparse.Namespace) -> None:
7684

7785
def cmd_bench(args: argparse.Namespace) -> None:
7886
import stim
87+
7988
from . import BlossomDecoder
8089

8190
circuit = stim.Circuit.generated(
@@ -106,8 +115,9 @@ def cmd_bench(args: argparse.Namespace) -> None:
106115

107116
def cmd_serve(args: argparse.Namespace) -> None:
108117
if args.transport == "rest":
109-
from .rest_api import app as fastapi_app
110118
import uvicorn
119+
120+
from .rest_api import app as fastapi_app
111121
uvicorn.run(fastapi_app, host=args.host, port=args.port)
112122
elif args.transport == "grpc":
113123
print("gRPC server: use the native qector_decoder_v3 module directly")

0 commit comments

Comments
 (0)