Skip to content

Commit 5a55dce

Browse files
ChanceSiyuanclaude
andauthored
Add noisy circuit dataset for BP decoding demonstration (#14)
* Add noisy circuit dataset for BP decoding demonstration - Add Stim circuits for rotated surface code (d=3) memory experiments with circuit-level depolarizing noise (p=0.01) at 3, 5, 7 rounds - Add generation script (scripts/generate_noisy_circuits.py) - Add comprehensive README with BP decoding tutorial and examples - Add visualization images (qubit layout, parity check matrix, syndrome stats) - Update .gitignore to exclude .venv/ * Refactor to proper Python package structure - Convert scripts/ to src/bpdecoderplus/ package following Python best practices - Add pyproject.toml with uv/hatchling build system and dependencies - Add comprehensive test suite (32 tests) for circuit.py and cli.py - Update .gitignore with Python-specific patterns - Update README to use new CLI entry point via uv Addresses PR feedback from @GiggleLiu. * Add Makefile and uv support for automated workflow - Add Makefile with targets for install, setup, generate-dataset, test, and clean - Update pyproject.toml with uv dev-dependencies configuration - Addresses issue #12 requirements for automation and uv package management Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add GitHub Actions CI/CD workflow for automated testing - Add test.yml workflow to run tests on push and PR - Test on Python 3.10, 3.11, and 3.12 - Use uv for dependency management in CI - Addresses PR #14 review comment for CI/CD setup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add test coverage reporting and README badges - Update CI workflow to generate coverage reports with pytest-cov - Upload coverage to Codecov for tracking - Add test status and coverage badges to README - Add `make test-cov` target for local coverage reports - Update .gitignore to exclude coverage files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix CI: allow uv cache without lock file Set ignore-nothing-to-cache to true to allow CI to proceed when uv.lock is not present in the repository. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix CI: disable uv caching Remove enable-cache to avoid lock file requirement. Caching can be re-enabled later with a proper lock file. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3c0fcfe commit 5a55dce

19 files changed

Lines changed: 1227 additions & 0 deletions

.github/workflows/test.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main, feat/* ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.10", "3.11", "3.12"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Install uv
20+
uses: astral-sh/setup-uv@v4
21+
22+
- name: Set up Python ${{ matrix.python-version }}
23+
run: uv python install ${{ matrix.python-version }}
24+
25+
- name: Install dependencies
26+
run: uv sync --dev
27+
28+
- name: Run tests with coverage
29+
run: uv run pytest --verbose --cov=bpdecoderplus --cov-report=xml --cov-report=term
30+
31+
- name: Upload coverage to Codecov
32+
uses: codecov/codecov-action@v4
33+
with:
34+
file: ./coverage.xml
35+
flags: unittests
36+
name: codecov-umbrella
37+
fail_ci_if_error: false

.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,34 @@
1+
# macOS
12
.DS_Store
3+
4+
# Jupyter
25
.ipynb_checkpoints/
6+
7+
# Julia
38
Manifest.toml
9+
10+
# IDE
411
.vscode/
12+
.idea/
13+
14+
# Python
15+
.venv/
16+
__pycache__/
17+
*.py[cod]
18+
*$py.class
19+
*.egg-info/
20+
dist/
21+
build/
22+
.eggs/
23+
*.egg
24+
.pytest_cache/
25+
.coverage
26+
coverage.xml
27+
htmlcov/
28+
.uv/
29+
uv.lock
30+
31+
# LaTeX
532
*.aux
633
*.fls
734
*.log

Makefile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.PHONY: help install setup test test-cov generate-dataset clean
2+
3+
help:
4+
@echo "Available targets:"
5+
@echo " install - Install uv package manager"
6+
@echo " setup - Set up development environment with uv"
7+
@echo " generate-dataset - Generate noisy circuit dataset"
8+
@echo " test - Run tests"
9+
@echo " test-cov - Run tests with coverage report"
10+
@echo " clean - Remove generated files and caches"
11+
12+
install:
13+
@command -v uv >/dev/null 2>&1 || { \
14+
echo "Installing uv..."; \
15+
curl -LsSf https://astral.sh/uv/install.sh | sh; \
16+
}
17+
18+
setup: install
19+
uv sync --dev
20+
21+
generate-dataset:
22+
uv run generate-noisy-circuits --distance 3 --p 0.01 --rounds 3 5 7 --task z --output datasets/noisy_circuits
23+
24+
test:
25+
uv run pytest
26+
27+
test-cov:
28+
uv run pytest --cov=bpdecoderplus --cov-report=html --cov-report=term
29+
30+
clean:
31+
rm -rf .pytest_cache
32+
rm -rf __pycache__
33+
rm -rf htmlcov
34+
rm -rf .coverage
35+
rm -rf coverage.xml
36+
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
37+
find . -type f -name "*.pyc" -delete

README.md

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

3+
[![Tests](https://github.com/GiggleLiu/BPDecoderPlus/actions/workflows/test.yml/badge.svg)](https://github.com/GiggleLiu/BPDecoderPlus/actions/workflows/test.yml)
4+
[![codecov](https://codecov.io/gh/GiggleLiu/BPDecoderPlus/branch/main/graph/badge.svg)](https://codecov.io/gh/GiggleLiu/BPDecoderPlus)
5+
36
A winter school project on circuit-level decoding of surface codes using belief propagation and integer programming decoders, with extensions for atom loss in neutral atom quantum computers.
47

58
## Project Goals

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)