Skip to content

Commit 1458f69

Browse files
GiggleLiuclaude
andcommitted
Merge branch 'main' into feat/add-noisy-circuits-dataset
Resolved conflicts and integrated changes from main: - Updated codecov configuration with token and files parameter - Added torch dependency to pyproject.toml - Updated default output path to datasets/noisy_circuits - Preserved DEM and syndrome generation features from this branch - Removed .claude/settings.local.json from version control - Added .claude/settings.local.json to .gitignore - Added WIP note to README 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2 parents ad71d08 + b7a2a7f commit 1458f69

33 files changed

+1672
-27
lines changed

.claude/settings.local.json

Lines changed: 0 additions & 22 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ jobs:
3131
- name: Upload coverage to Codecov
3232
uses: codecov/codecov-action@v4
3333
with:
34-
file: ./coverage.xml
34+
token: ${{ secrets.CODECOV_TOKEN }}
35+
files: ./coverage.xml
3536
flags: unittests
3637
name: codecov-umbrella
3738
fail_ci_if_error: false

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ uv.lock
3838
*.blg
3939
*.fdb_latexmk
4040
*.synctex.gz
41-
note/belief_propagation_qec_plan.pdf
41+
note/belief_propagation_qec_plan.pdf.claude/settings.local.json

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# BPDecoderPlus: Quantum Error Correction with Belief Propagation
22

3+
Note: This WIP project is for AI + Quantum winter school training.
4+
35
[![Tests](https://github.com/GiggleLiu/BPDecoderPlus/actions/workflows/test.yml/badge.svg)](https://github.com/GiggleLiu/BPDecoderPlus/actions/workflows/test.yml)
46
[![codecov](https://codecov.io/gh/GiggleLiu/BPDecoderPlus/branch/main/graph/badge.svg)](https://codecov.io/gh/GiggleLiu/BPDecoderPlus)
57

@@ -186,6 +188,42 @@ BPDecoderPlus/
186188
└── belief_propagation_qec_plan.tex
187189
```
188190

191+
## PyTorch BP Module (UAI)
192+
193+
This repository also includes a PyTorch implementation of belief propagation for
194+
UAI factor graphs under `src/bpdecoderplus/pytorch_bp`.
195+
196+
### Python Setup
197+
198+
```bash
199+
pip install -e .
200+
```
201+
202+
### Quick Example
203+
204+
```python
205+
from bpdecoderplus.pytorch_bp import (
206+
read_model_file,
207+
BeliefPropagation,
208+
belief_propagate,
209+
compute_marginals,
210+
)
211+
212+
model = read_model_file("examples/simple_model.uai")
213+
bp = BeliefPropagation(model)
214+
state, info = belief_propagate(bp)
215+
print(info)
216+
print(compute_marginals(state, bp))
217+
```
218+
219+
### Examples and Tests
220+
221+
```bash
222+
python examples/simple_example.py
223+
python examples/evidence_example.py
224+
pytest tests/test_bp_basic.py tests/test_uai_parser.py tests/test_integration.py tests/testcase.py
225+
```
226+
189227
## Available Decoders
190228

191229
| Decoder | Symbol | Description |

datasets/noisy_circuits/README.md

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
# Noisy Circuit Dataset (Surface Code, d=3)
2+
3+
Circuit-level surface-code memory experiments generated with Stim for **Belief Propagation (BP) decoding** demonstrations.
4+
5+
## Overview
6+
7+
| Parameter | Value |
8+
|-----------|-------|
9+
| Code | Rotated surface code |
10+
| Distance | d = 3 |
11+
| Noise model | i.i.d. depolarizing |
12+
| Error rate | p = 0.01 |
13+
| Task | Z-memory experiment |
14+
| Rounds | 3, 5, 7 |
15+
16+
### Noise Application Points
17+
- Clifford gates (`after_clifford_depolarization`)
18+
- Data qubits between rounds (`before_round_data_depolarization`)
19+
- Resets (`after_reset_flip_probability`)
20+
- Measurements (`before_measure_flip_probability`)
21+
22+
## Files
23+
24+
| File | Description |
25+
|------|-------------|
26+
| `sc_d3_r3_p0010_z.stim` | 3 rounds, p=0.01, Z-memory |
27+
| `sc_d3_r5_p0010_z.stim` | 5 rounds, p=0.01, Z-memory |
28+
| `sc_d3_r7_p0010_z.stim` | 7 rounds, p=0.01, Z-memory |
29+
| `sc_d3_layout.png` | Qubit layout visualization |
30+
| `parity_check_matrix.png` | BP parity check matrix H |
31+
| `syndrome_stats.png` | Detection event statistics |
32+
| `single_syndrome.png` | Example syndrome pattern |
33+
34+
## Qubit Layout
35+
36+
The surface code layout showing qubit positions (data + ancilla):
37+
38+
![Qubit Layout](sc_d3_layout.png)
39+
40+
## Using This Dataset for BP Decoding
41+
42+
### Step 1: Load Circuit and Extract Detector Error Model (DEM)
43+
44+
The Detector Error Model is the key input for BP decoding. It describes which errors trigger which detectors.
45+
46+
```python
47+
import stim
48+
import numpy as np
49+
50+
# Load circuit
51+
circuit = stim.Circuit.from_file("datasets/noisy_circuits/sc_d3_r3_p0010_z.stim")
52+
53+
# Extract DEM - this is what BP needs
54+
dem = circuit.detector_error_model(decompose_errors=True)
55+
print(f"Detectors: {dem.num_detectors}") # 24
56+
print(f"Error mechanisms: {dem.num_errors}") # 286
57+
print(f"Observables: {dem.num_observables}") # 1
58+
```
59+
60+
### Step 2: Build Parity Check Matrix H
61+
62+
BP operates on the parity check matrix where `H[i,j] = 1` means error `j` triggers detector `i`.
63+
64+
```python
65+
def build_parity_check_matrix(dem):
66+
"""Convert DEM to parity check matrix H and prior probabilities."""
67+
errors = []
68+
for inst in dem.flattened():
69+
if inst.type == 'error':
70+
prob = inst.args_copy()[0]
71+
dets = [t.val for t in inst.targets_copy() if t.is_relative_detector_id()]
72+
obs = [t.val for t in inst.targets_copy() if t.is_logical_observable_id()]
73+
errors.append({'prob': prob, 'detectors': dets, 'observables': obs})
74+
75+
n_detectors = dem.num_detectors
76+
n_errors = len(errors)
77+
78+
# Parity check matrix
79+
H = np.zeros((n_detectors, n_errors), dtype=np.uint8)
80+
# Prior error probabilities (for BP initialization)
81+
priors = np.zeros(n_errors)
82+
# Which errors flip the logical observable
83+
obs_flip = np.zeros(n_errors, dtype=np.uint8)
84+
85+
for j, e in enumerate(errors):
86+
priors[j] = e['prob']
87+
for d in e['detectors']:
88+
H[d, j] = 1
89+
if e['observables']:
90+
obs_flip[j] = 1
91+
92+
return H, priors, obs_flip
93+
94+
H, priors, obs_flip = build_parity_check_matrix(dem)
95+
print(f"H shape: {H.shape}") # (24, 286)
96+
```
97+
98+
The parity check matrix structure:
99+
100+
![Parity Check Matrix](parity_check_matrix.png)
101+
102+
### Step 3: Sample Syndromes (Detection Events)
103+
104+
```python
105+
# Compile sampler
106+
sampler = circuit.compile_detector_sampler()
107+
108+
# Sample detection events + observable flip
109+
n_shots = 1000
110+
samples = sampler.sample(n_shots, append_observables=True)
111+
112+
# Split into syndrome and observable
113+
syndromes = samples[:, :-1] # shape: (n_shots, n_detectors)
114+
actual_obs_flips = samples[:, -1] # shape: (n_shots,)
115+
116+
print(f"Syndrome shape: {syndromes.shape}")
117+
print(f"Example syndrome: {syndromes[0]}")
118+
```
119+
120+
### Step 4: BP Decoding (Pseudocode)
121+
122+
```python
123+
def bp_decode(H, syndrome, priors, max_iter=50, damping=0.5):
124+
"""
125+
Belief Propagation decoder (min-sum variant).
126+
127+
Args:
128+
H: Parity check matrix (n_detectors, n_errors)
129+
syndrome: Detection events (n_detectors,)
130+
priors: Prior error probabilities (n_errors,)
131+
max_iter: Maximum BP iterations
132+
damping: Message damping factor
133+
134+
Returns:
135+
estimated_errors: Most likely error pattern (n_errors,)
136+
soft_output: Log-likelihood ratios (n_errors,)
137+
"""
138+
n_checks, n_vars = H.shape
139+
140+
# Initialize LLRs from priors: LLR = log((1-p)/p)
141+
llr_prior = np.log((1 - priors) / priors)
142+
143+
# Messages: check-to-variable and variable-to-check
144+
# ... BP message passing iterations ...
145+
146+
# Hard decision
147+
estimated_errors = (soft_output < 0).astype(int)
148+
149+
return estimated_errors, soft_output
150+
151+
# Decode each syndrome
152+
for i in range(n_shots):
153+
syndrome = syndromes[i]
154+
estimated_errors, _ = bp_decode(H, syndrome, priors)
155+
156+
# Predict observable flip
157+
predicted_obs_flip = np.dot(estimated_errors, obs_flip) % 2
158+
159+
# Check if decoding succeeded
160+
success = (predicted_obs_flip == actual_obs_flips[i])
161+
```
162+
163+
### Step 5: Evaluate Decoder Performance
164+
165+
After decoding, compare predicted vs actual observable flips to measure logical error rate.
166+
167+
```python
168+
def evaluate_decoder(decoder_fn, circuit, n_shots=10000):
169+
"""Evaluate decoder logical error rate."""
170+
dem = circuit.detector_error_model(decompose_errors=True)
171+
H, priors, obs_flip = build_parity_check_matrix(dem)
172+
173+
sampler = circuit.compile_detector_sampler()
174+
samples = sampler.sample(n_shots, append_observables=True)
175+
syndromes = samples[:, :-1]
176+
actual_obs = samples[:, -1]
177+
178+
errors = 0
179+
for i in range(n_shots):
180+
est_errors, _ = decoder_fn(H, syndromes[i], priors)
181+
pred_obs = np.dot(est_errors, obs_flip) % 2
182+
if pred_obs != actual_obs[i]:
183+
errors += 1
184+
185+
return errors / n_shots
186+
187+
# logical_error_rate = evaluate_decoder(bp_decode, circuit)
188+
```
189+
190+
## Syndrome Statistics
191+
192+
Detection event frequencies across 1000 shots (left) and baseline observable flip rate without decoding (right):
193+
194+
![Syndrome Statistics](syndrome_stats.png)
195+
196+
## Example Syndrome
197+
198+
A single syndrome sample showing which detectors fired (red = triggered):
199+
200+
![Single Syndrome](single_syndrome.png)
201+
202+
## Regenerating the Dataset
203+
204+
```bash
205+
# Install the package with uv
206+
uv sync
207+
208+
# Generate circuits using the CLI
209+
uv run generate-noisy-circuits \
210+
--distance 3 \
211+
--p 0.01 \
212+
--rounds 3 5 7 \
213+
--task z \
214+
--output datasets/noisy_circuits
215+
```
216+
217+
## Extending the Dataset
218+
219+
```bash
220+
# Different error rates
221+
uv run generate-noisy-circuits --p 0.005 --rounds 3 5 7
222+
223+
# Different distances
224+
uv run generate-noisy-circuits --distance 5 --rounds 5 7 9
225+
226+
# X-memory experiment
227+
uv run generate-noisy-circuits --task x --rounds 3 5 7
228+
```
229+
230+
## References
231+
232+
- [Stim Documentation](https://github.com/quantumlib/Stim)
233+
- [BP+OSD Decoder Paper](https://arxiv.org/abs/2005.07016)
234+
- [Surface Code Decoding Review](https://quantum-journal.org/papers/q-2024-10-10-1498/)
42.7 KB
Loading
67.9 KB
Loading

0 commit comments

Comments
 (0)