Skip to content

Commit a803c6a

Browse files
committed
style: ruff format entire python/ tree (128 files)
1 parent 181c6c8 commit a803c6a

128 files changed

Lines changed: 721 additions & 643 deletions

File tree

Some content is hidden

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

python/qector_decoder_v3/__init__.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,15 @@
4040
def cuda_is_available():
4141
return False
4242

43+
4344
try:
4445
from .qector_decoder_v3 import opencl_is_available
4546
except ImportError:
47+
4648
def opencl_is_available():
4749
return False
4850

51+
4952
try:
5053
from .qector_decoder_v3 import run_grpc_server
5154
except ImportError:
@@ -64,10 +67,9 @@ def opencl_is_available():
6467
__version__ = "0.5.0"
6568

6669

67-
6870
class UnionFindDecoder:
6971
"""Production-ready Union-Find quantum error correction decoder.
70-
72+
7173
Rust core with PyO3 bindings. Zero-copy NumPy interop.
7274
GIL is released during decode for true parallelism.
7375
"""
@@ -242,7 +244,7 @@ def current_round(self):
242244

243245
class StreamingDecoder:
244246
"""Streaming decoder that accumulates syndromes over multiple rounds.
245-
247+
246248
Rust core with circular history buffer and OR accumulation.
247249
"""
248250

@@ -281,7 +283,7 @@ def n_checks(self):
281283

282284
class BatchDecoder:
283285
"""Parallel batch decoder using Rayon (Rust data parallelism).
284-
286+
285287
Distributes batch decoding across all CPU cores.
286288
"""
287289

@@ -486,7 +488,7 @@ def is_available():
486488

487489
class SparseBlossomDecoder:
488490
"""Region-growing Sparse Blossom decoder with RadixHeap.
489-
491+
490492
Supports dynamic weight overrides from GNN Pre-Decoder for enriched decoding.
491493
"""
492494

@@ -506,11 +508,11 @@ def decode(self, syndrome):
506508

507509
def decode_with_weights(self, syndrome, weights):
508510
"""Decode with per-qubit dynamic weight overrides.
509-
511+
510512
Args:
511513
syndrome: np.ndarray of shape (n_checks,) with dtype uint8.
512514
weights: List of (qubit_id, weight) tuples.
513-
515+
514516
Returns:
515517
np.ndarray of shape (n_qubits,) with correction.
516518
"""
@@ -542,7 +544,7 @@ def n_checks(self):
542544

543545
class BPOSDDecoder:
544546
"""Belief Propagation + Ordered Statistics Decoding.
545-
547+
546548
Min-sum BP with OSD stage for improved LER on complex codes.
547549
"""
548550

@@ -630,9 +632,9 @@ class GNNPredecoder:
630632
"""Graph Neural Network Pre-Decoder for dynamic edge weight prediction.
631633
632634
MPNN 3 layers + MLP readout. Predicts adjusted edge weights for SparseBlossom.
633-
635+
634636
**v2.0** : Full backpropagation through MPNN layers (P0). All layers are trainable.
635-
637+
636638
Dimensions must match the DetectorGraph:
637639
- node_feat_dim = 10 (NodeFeatures::DIM)
638640
- edge_feat_dim = 8 (EdgeFeatures::DIM)
@@ -644,7 +646,7 @@ class GNNPredecoder:
644646

645647
def __init__(self, node_feat_dim=None, edge_feat_dim=None, hidden_size=16, n_layers=2):
646648
"""Create a GNNPredecoder.
647-
649+
648650
If node_feat_dim and edge_feat_dim are not provided, uses the standard
649651
dimensions matching DetectorGraph (10 and 8).
650652
"""
@@ -763,19 +765,28 @@ def generate_dataset(self, n_samples):
763765

764766
class HybridDecoder:
765767
"""GNN Pre-Decoder + SparseBlossom hybrid decoder.
766-
768+
767769
Uses a lightweight MPNN to estimate dynamic edge weights, then passes
768770
them to SparseBlossom for enriched region-growing decoding.
769771
"""
770772

771-
def __init__(self, check_to_qubits, n_qubits=None, check_positions=None,
772-
check_types=None, base_weights=None, gnn_hidden_size=64, gnn_n_layers=3):
773+
def __init__(
774+
self,
775+
check_to_qubits,
776+
n_qubits=None,
777+
check_positions=None,
778+
check_types=None,
779+
base_weights=None,
780+
gnn_hidden_size=64,
781+
gnn_n_layers=3,
782+
):
773783
if not check_to_qubits:
774784
raise ValueError("check_to_qubits must be non-empty")
775785
c2q = [[int(q) for q in check] for check in check_to_qubits]
776786
nq = None if n_qubits is None else int(n_qubits)
777-
self._inner = _RustHybridDecoder(c2q, nq, check_positions, check_types,
778-
base_weights, gnn_hidden_size, gnn_n_layers)
787+
self._inner = _RustHybridDecoder(
788+
c2q, nq, check_positions, check_types, base_weights, gnn_hidden_size, gnn_n_layers
789+
)
779790

780791
def decode_hybrid(self, syndrome):
781792
if not isinstance(syndrome, np.ndarray):
@@ -965,12 +976,14 @@ def __init__(self, check_to_qubits, n_qubits=None, n_samples=10000, seed=42):
965976

966977
def run(self):
967978
import json
979+
968980
raw = self._inner.run()
969981
return json.loads(raw)
970982

971983
def save(self, path, results):
972984
import json
973985
from pathlib import Path
986+
974987
Path(path).write_text(json.dumps(results, indent=2), encoding="utf-8")
975988

976989

python/qector_decoder_v3/backend.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,7 @@ def select(self, batch_size: int) -> str:
168168
"""Return the backend that *would* run for a given batch size."""
169169
if self.config.force is not None:
170170
return self.config.force
171-
if (
172-
self.config.allow_gpu
173-
and batch_size >= self.config.gpu_threshold
174-
and (self._cuda_ok or self._opencl_ok)
175-
):
171+
if self.config.allow_gpu and batch_size >= self.config.gpu_threshold and (self._cuda_ok or self._opencl_ok):
176172
if self.config.prefer == Backend.OPENCL and self._opencl_ok:
177173
return Backend.OPENCL
178174
if self._cuda_ok:
@@ -271,9 +267,7 @@ def calibrate(self, sizes=(64, 256, 1024, 4096, 16384), repeats: int = 3, seed:
271267
self._diag.warnings.append("no GPU available for calibration; GPU disabled")
272268
self.config.gpu_threshold = 1 << 62
273269
elif crossover is None:
274-
self._diag.warnings.append(
275-
"GPU never beat CPU in calibration; keeping CPU for all sizes"
276-
)
270+
self._diag.warnings.append("GPU never beat CPU in calibration; keeping CPU for all sizes")
277271
self.config.gpu_threshold = 1 << 62
278272
else:
279273
self.config.gpu_threshold = int(crossover)

python/qector_decoder_v3/belief_matching.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@
4646

4747
@dataclass
4848
class _Matrices:
49-
hyper_check: np.ndarray # (num_detectors, num_hyper)
50-
hyper_obs: np.ndarray # (num_observables, num_hyper)
51-
hyper_priors: np.ndarray # (num_hyper,)
52-
hyper_to_edge: np.ndarray # (num_edges, num_hyper)
53-
edge_check: np.ndarray # (num_detectors, num_edges)
54-
edge_obs: np.ndarray # (num_observables, num_edges)
49+
hyper_check: np.ndarray # (num_detectors, num_hyper)
50+
hyper_obs: np.ndarray # (num_observables, num_hyper)
51+
hyper_priors: np.ndarray # (num_hyper,)
52+
hyper_to_edge: np.ndarray # (num_edges, num_hyper)
53+
edge_check: np.ndarray # (num_detectors, num_edges)
54+
edge_obs: np.ndarray # (num_observables, num_edges)
5555
num_detectors: int
5656
num_observables: int
5757

@@ -148,8 +148,7 @@ def handle(prob: float, dets: List[List[int]], frames: List[List[int]]):
148148
for hid, p in priors.items():
149149
prior_arr[hid] = p
150150

151-
return _Matrices(hyper_check, hyper_obs_m, prior_arr, hyper_to_edge, edge_check,
152-
edge_obs_m, nD, nO)
151+
return _Matrices(hyper_check, hyper_obs_m, prior_arr, hyper_to_edge, edge_check, edge_obs_m, nD, nO)
153152

154153

155154
class BeliefMatching:
@@ -176,8 +175,7 @@ def __init__(self, matrices: _Matrices, max_iter: int = 30, bp_shortcut: bool =
176175
# Matching graph = edge check matrix.
177176
self._n_edges = matrices.edge_check.shape[1]
178177
self._edge_c2q: List[List[int]] = [
179-
sorted(int(e) for e in np.nonzero(matrices.edge_check[c])[0])
180-
for c in range(self.n_checks)
178+
sorted(int(e) for e in np.nonzero(matrices.edge_check[c])[0]) for c in range(self.n_checks)
181179
]
182180

183181
# -- constructors ------------------------------------------------------
@@ -187,9 +185,7 @@ def from_detector_error_model(cls, dem: Any, max_iter: int = 20) -> "BeliefMatch
187185

188186
@classmethod
189187
def from_stim_circuit(cls, circuit, max_iter: int = 20) -> "BeliefMatching":
190-
return cls.from_detector_error_model(
191-
circuit.detector_error_model(decompose_errors=True), max_iter=max_iter
192-
)
188+
return cls.from_detector_error_model(circuit.detector_error_model(decompose_errors=True), max_iter=max_iter)
193189

194190
# -- decoding ----------------------------------------------------------
195191
def decode(self, syndrome) -> np.ndarray:
@@ -198,8 +194,13 @@ def decode(self, syndrome) -> np.ndarray:
198194
s = np.concatenate([s, np.zeros(self.n_checks - s.shape[0], np.uint8)])
199195

200196
posterior = sum_product_bp(
201-
self._hic, self._hie, self.n_checks, self._n_hyper,
202-
self._prior_llr, s, self.max_iter,
197+
self._hic,
198+
self._hie,
199+
self.n_checks,
200+
self._n_hyper,
201+
self._prior_llr,
202+
s,
203+
self.max_iter,
203204
)
204205
if self.bp_shortcut:
205206
hard = (posterior < 0.0).astype(np.uint8)

python/qector_decoder_v3/benchmarking.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ def git_commit() -> str:
110110

111111
def _safe_cmd(cmd: Sequence[str]) -> Optional[str]:
112112
try:
113-
out = subprocess.run(
114-
list(cmd), capture_output=True, text=True, timeout=10, check=False
115-
)
113+
out = subprocess.run(list(cmd), capture_output=True, text=True, timeout=10, check=False)
116114
return out.stdout.strip() or None
117115
except Exception: # pragma: no cover
118116
return None
@@ -166,7 +164,7 @@ def summarize(samples_seconds: Sequence[float]) -> Dict[str, float]:
166164
mean = float(us.mean())
167165
std = float(us.std(ddof=1)) if n > 1 else 0.0
168166
# 95% normal CI on the mean.
169-
half = 1.959963985 * std / (n ** 0.5) if n > 1 else 0.0
167+
half = 1.959963985 * std / (n**0.5) if n > 1 else 0.0
170168
summary = {
171169
"n": int(n),
172170
"mean": mean,
@@ -184,9 +182,7 @@ def summarize(samples_seconds: Sequence[float]) -> Dict[str, float]:
184182
# ---------------------------------------------------------------------------
185183
# Timing primitives
186184
# ---------------------------------------------------------------------------
187-
def time_iterations(
188-
fn: Callable[[], Any], n_trials: int, warmup: int = 0
189-
) -> List[float]:
185+
def time_iterations(fn: Callable[[], Any], n_trials: int, warmup: int = 0) -> List[float]:
190186
"""Time ``fn`` per-call ``n_trials`` times after ``warmup`` untimed calls."""
191187
for _ in range(max(0, warmup)):
192188
fn()
@@ -296,9 +292,7 @@ def one_decode():
296292
"syndrome_faithful": valid,
297293
"cold_path_us": summarize(cold_samples),
298294
"latency_us": summarize(hot_samples),
299-
"throughput_decodes_per_s": (1.0 / statistics.median(hot_samples))
300-
if hot_samples
301-
else None,
295+
"throughput_decodes_per_s": (1.0 / statistics.median(hot_samples)) if hot_samples else None,
302296
"peak_python_alloc_kib": peak_kib,
303297
}
304298
return report

python/qector_decoder_v3/bposd.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,24 @@ def decode(self, syndrome) -> np.ndarray:
7272
s = np.concatenate([s, np.zeros(self.n_checks - s.shape[0], np.uint8)])
7373
if self.bp_method == "sum_product":
7474
posterior = sum_product_bp(
75-
self.ic, self.ie, self.n_checks, self.n_qubits,
76-
self.prior_llr, s, self.max_iter,
75+
self.ic,
76+
self.ie,
77+
self.n_checks,
78+
self.n_qubits,
79+
self.prior_llr,
80+
s,
81+
self.max_iter,
7782
)
7883
else:
7984
posterior = min_sum_bp(
80-
self.ic, self.ie, self.n_checks, self.n_qubits,
81-
self.prior_llr, s, self.max_iter, self.ms_scale,
85+
self.ic,
86+
self.ie,
87+
self.n_checks,
88+
self.n_qubits,
89+
self.prior_llr,
90+
s,
91+
self.max_iter,
92+
self.ms_scale,
8293
)
8394
hard = (posterior < 0.0).astype(np.uint8)
8495
if np.array_equal((self.H @ hard) & 1, s):

python/qector_decoder_v3/dem.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,7 @@ def collapse_to_graph(self) -> "DemModel":
138138
for m in members:
139139
p = p * (1.0 - m.probability) + m.probability * (1.0 - p)
140140
best = min(members, key=lambda m: m.weight) # lowest weight == most likely
141-
merged.append(
142-
DemError(probability=p, detectors=sig, observables=best.observables)
143-
)
141+
merged.append(DemError(probability=p, detectors=sig, observables=best.observables))
144142

145143
return DemModel(
146144
errors=merged,
@@ -234,9 +232,7 @@ def predicted_observables(self, correction: Sequence[int]) -> np.ndarray:
234232
"""Logical observable flips implied by a correction (``L @ c mod 2``)."""
235233
c = np.asarray(correction, dtype=np.uint8).reshape(-1)
236234
if c.shape[0] != self.num_errors:
237-
raise ValueError(
238-
f"correction has length {c.shape[0]}, expected {self.num_errors}"
239-
)
235+
raise ValueError(f"correction has length {c.shape[0]}, expected {self.num_errors}")
240236
return (self.observables_matrix() @ c) & 1
241237

242238
def __repr__(self) -> str: # pragma: no cover - cosmetic
@@ -397,9 +393,7 @@ def _exec_instruction(tok: str, state: dict, errors: List[DemError], coords: dic
397393
state["max_det"] = max(state["max_det"], d)
398394
if coord_str:
399395
try:
400-
coords[d] = tuple(
401-
float(x) for x in coord_str.split(",") if x.strip()
402-
)
396+
coords[d] = tuple(float(x) for x in coord_str.split(",") if x.strip())
403397
except ValueError:
404398
pass
405399
return
@@ -450,9 +444,7 @@ def from_stim(dem: Any) -> DemModel:
450444
if isinstance(dem, str):
451445
return parse_dem(dem)
452446
if not hasattr(dem, "num_detectors"):
453-
raise TypeError(
454-
f"expected a stim.DetectorErrorModel (or DEM text), got {type(dem).__name__}"
455-
)
447+
raise TypeError(f"expected a stim.DetectorErrorModel (or DEM text), got {type(dem).__name__}")
456448
try:
457449
flat = dem.flattened()
458450
except Exception: # pragma: no cover - older Stim

python/qector_decoder_v3/pymatching_compat.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,7 @@ def add_edge(
132132
self._num_detectors = max(self._num_detectors, int(node1) + 1, int(node2) + 1)
133133
self._decoder = None
134134

135-
def add_boundary_edge(
136-
self, node: int, fault_ids: Any = None, weight: float = 1.0, **_: Any
137-
) -> None:
135+
def add_boundary_edge(self, node: int, fault_ids: Any = None, weight: float = 1.0, **_: Any) -> None:
138136
"""Add an edge from a detector node to the boundary."""
139137
self._edges.append(
140138
{
@@ -167,10 +165,7 @@ def num_fault_ids(self) -> int:
167165

168166
def edges(self) -> List[Tuple[Optional[int], Optional[int], dict]]:
169167
"""PyMatching-style edge list: ``(u, v, {"fault_ids":..., "weight":...})``."""
170-
return [
171-
(e["u"], e["v"], {"fault_ids": set(e["fault_ids"]), "weight": e["weight"]})
172-
for e in self._edges
173-
]
168+
return [(e["u"], e["v"], {"fault_ids": set(e["fault_ids"]), "weight": e["weight"]}) for e in self._edges]
174169

175170
def check_matrix(self) -> np.ndarray:
176171
"""The parity-check matrix (rows=detectors, cols=edges)."""
@@ -198,9 +193,7 @@ def _ensure_decoder(self) -> BlossomDecoder:
198193
# weights are equal, pass None so the uniform-weight fast path runs.
199194
weights = [e["weight"] for e in self._edges]
200195
uniform = len(set(round(w, 12) for w in weights)) <= 1
201-
self._decoder = BlossomDecoder(
202-
c2q, len(self._edges), None if uniform else weights
203-
)
196+
self._decoder = BlossomDecoder(c2q, len(self._edges), None if uniform else weights)
204197
return self._decoder
205198

206199
def _edge_correction(self, syndrome: np.ndarray) -> np.ndarray:

0 commit comments

Comments
 (0)