Syndrome-Net is a research-oriented framework for building, simulating, decoding, and evaluating QEC workflows with Stim. The project focuses on:
- Surface-code and dynamic-code circuit generation
- Colour code support (triangular, rectangular, growing, Loom-based hexagonal)
- Plugin-based support for multiple code families (
surface,qldpc,bosonic,dual_rail_erasure,color_code) - Classical and confidence-aware decoders
- Reinforcement-learning environments and agents for:
- one-shot decoding (
QECGymEnv,ColourCodeGymEnv) - continuous calibration (
QECContinuousControlEnv,ColourCodeCalibrationEnv) - code discovery (
QECCodeDiscoveryEnv,ColourCodeDiscoveryEnv)
- one-shot decoding (
- Integrated the NVIDIA Ising pre-decoder path with metadata-driven artifact selection in
surface_code_in_stem/decoders/ising_predecoder.py. - Fixed runtime pre-decoder configuration regressions and made baseline contract diagnostics deterministic in
surface_code_in_stem/rl_control/gym_env.py. - Added Streamlit and benchmark contract smoke checks that validate backend metadata (
backend_id,contract_flags,profiler_flags). - Aligned repo documentation, runbook guidance, and deployment instructions for cleaner push and onboarding workflows.
- Colour-code integration (Lee & Brown 2025, Entropica Loom):
ColorCodeStimBuilder: triangular, rectangular, growing circuits via color-code-stimLoomColorCodeBuilder: hexagonal lattice circuits via el-loom Eka/Block abstractionsConcatenatedMWPMDecoder: 6-matching decoder (2 per colour R/G/B)- Colour code RL environments (
ColourCodeGymEnv,ColourCodeDiscoveryEnv,ColourCodeCalibrationEnv) - Parallel threshold estimation with circuit caching (
ParallelColorCodeEstimator) - Hexagonal lattice visualization in Streamlit UI
- Gym-compatible QEC environments in
surface_code_in_stem/rl_control/gym_env.py - RL agent implementations in
surface_code_in_stem/rl_control/sota_agents.py- Transformer/TITANS-backed PPO for discrete decoding
- Continuous SAC for calibration control
- End-to-end training script in
scripts/train_sota_rl.py - Expanded code-family support:
- Bosonic variants (
gkp_surface,cat_code,squeezed_state) - qLDPC parity-matrix builders (toric, surface-derived, hypergraph-product, custom parity)
- Bosonic variants (
These screenshots were captured from the live Streamlit QEC dashboard and are checked into the repo so GitHub renders them directly:
| Circuit Viewer | Threshold Explorer |
|---|---|
![]() |
![]() |
The demo app includes:
- Stim circuit visualization with static SVG and interactive Crumble views
- Detector error graph + syndrome heatmap
- Threshold sweeps with Plotly curves
- Live RL training controls for PPO / SAC runs
- 🎨 Colour Codes tab: hexagonal lattice visualization, circuit generation, and RL training
surface_code_in_stem/: core circuit builders, decoders, RL control, noise modelssyndrome_net/: protocol definitions, circuit builders (including colour codes), decoders, parallel utilitiesapp/: Streamlit application (circuit viewer, RL training, threshold explorer, colour codes)codes/: plugin architecture and benchmarking harness across code familiesscripts/: runnable workflows (including RL training)tests/: targeted tests for gym envs, bosonic variants, qLDPC parity, and colour codessurface_code_in_stem/DYNAMIC_CODES.md: implementation notes mapped to Morvan et al. 2025
Python 3.10+ is recommended.
pip install -r requirements.lockpip install -r requirements.lock
pip install -r requirements-qec.txtThis installs color-code-stim, el-loom, and galois for colour code circuits and concatenated MWPM decoding.
pip install -r app/requirements.lockUse this for app-only experiments where CLI benchmark workflows are not required.
Accelerated sampling backends are optional and discovered at runtime.
qhybrid(qhybrid_kernels) — backend probe is exposed throughqhybrid_backend.probe_capability()cuquantum(tensornet)qujax(jax)cudaq
Runtime fallback behavior is explicit and instrumented:
- Automatic mode tries candidates in order:
qhybrid -> cuquantum -> qujax -> cudaq -> stim - Explicit mode (eg.
sampling_backend="stim") pins backend selection - Any failure in a candidate backend falls back to the next candidate (or to
stim) - Every emitted metric row carries backend metadata (
backend_id,backend_chain,contract_flags,profiler_flags) so users can verify whether acceleration was used
Install matrix guidance:
- Start with
requirements.lockfor baseline reproducible behavior. - Add optional GPU/runtime dependencies from your platform guide only when enabled in your workflow.
- For CI-like parity, prefer pinned files (
requirements.lock+app/requirements.lock) and keep optional packages optional.
from surface_code_in_stem.surface_code import surface_code_circuit_string
circuit = surface_code_circuit_string(distance=3, rounds=3, p=0.001)
print(circuit[:500])from surface_code_in_stem.rl_control.gym_env import QECGymEnv, QECContinuousControlEnv
from surface_code_in_stem.rl_control.gym_env import ColourCodeGymEnv
decoding_env = QECGymEnv(distance=3, rounds=3, physical_error_rate=0.005)
obs, info = decoding_env.reset(seed=7)
control_env = QECContinuousControlEnv(distance=3, rounds=3, parameter_dim=4)
obs_ctrl, _ = control_env.reset(seed=7)
# Colour code decoding environment
colour_env = ColourCodeGymEnv(distance=5, rounds=5, physical_error_rate=0.001)
obs_colour, info_colour = colour_env.reset(seed=7)from syndrome_net import CircuitSpec
from syndrome_net.codes import ColorCodeStimBuilder, LoomColorCodeBuilder
# Triangular colour code via color-code-stim
spec = CircuitSpec(distance=5, rounds=5, error_probability=0.001, circuit_type="tri")
builder = ColorCodeStimBuilder()
circuit = builder.build(spec)
# Hexagonal colour code via el-loom
spec_loom = CircuitSpec(distance=5, rounds=5, error_probability=0.001)
loom_builder = LoomColorCodeBuilder()
circuit_loom = loom_builder.build(spec_loom)# Decoder (Transformer/TITANS + PPO)
python3 scripts/train_sota_rl.py --mode ppo --episodes 512
# Calibration (Continuous SAC)
python3 scripts/train_sota_rl.py --mode sac --episodes 512
# Both
python3 scripts/train_sota_rl.py --mode all --episodes 1000python3 scripts/run_streamlit_smoke.py --timeout 35
python3 -m pytest \
tests/test_gym_env.py \
tests/test_ising_predecoder.py \
tests/test_benchmark_decoder_contracts.py \
tests/test_decoder_registry_backends.py \
tests/test_decoder_resolution.py \
tests/test_streamlit_backend_metadata.py \
tests/test_runtime_contracts.py
# Focused benchmark + contract smoke path
python3 scripts/benchmark_decoders.py --quick --sampling-backends stim --suite circuit --output-dir artifacts/benchmarks
python3 scripts/ci_contract_verification.sh
# Full repository test run (slower)
python3 -m pytest testsUse these commands to validate backend metadata contracts before sharing artifacts or opening a PR:
python3 scripts/ci_contract_verification.sh
python3 scripts/benchmark_decoders.py --quick --sampling-backends stim --suite circuit --output-dir artifacts/benchmarksThe contract script runs:
python3 -m pytest \
tests/test_sampling_backend_contracts.py \
tests/test_benchmark_decoder_contracts.py \
tests/test_runtime_contracts.py \
tests/test_streamlit_backend_metadata.py \
tests/test_decoder_registry_backends.py \
tests/test_decoder_resolution.py
python3 scripts/bench_runtime_contracts.py --output artifacts/benchmarks/ci_contract_runtime.jsonBoth the runtime path and benchmark scripts emit backend observability keys that are used by CI and for long-running experiment diffing:
backend_idbackend_enabledbackend_chainbackend_chain_tokensbackend_versioncontract_flagsprofiler_flagstrace_tokenssample_trace_idfallback_reasonsample_ussample_rate
Use this schema consistently when merging new profiling surfaces.
Current layout intentionally keeps quantumforge as an internal dependency directory within this repository, so CI and app code can import optional accelerated kernels without an extra git dependency at runtime.
Recommended workflow for repo-style evolution:
- Keep
quantumforge/as the local source-of-truth for Rust/PyO3 acceleration code. - When
quantumforgechanges upstream:- pull or rebase that component into the vendored directory.
- run
python3 -m pytest tests/test_*and at least onescripts/benchmark_decoders.py --quick ...smoke sweep. - validate
git diffonly touches intended directories.
- For an explicit split-repository topology:
- keep
quantumforgein its own git history. - mirror a release window by syncing via
git subtreeor periodic snapshot copy intosyndrome-net/quantumforge. - use a shared lockfile strategy to avoid dependency drift (see
requirements.lockandquantumforge/python/requirements.lock).
- keep
See docs/REPO_MERGE_AND_DEPLOYMENT.md for a concrete command sequence and recovery checks.
scripts/benchmark_decoders.py writes both CSV and JSON rows with explicit backend-trace metadata.
Each row includes:
domain: benchmark family (circuitorqldpc)family: code family name (eg.surface,xyz2)decoder: decoder identifierdistancephysical_error_rateshotsmetric_namemetric_valuebackendbackend_enabled: backend availability/fallback statusbackend_versionfallback_reasonsample_trace_idbackend_chainbackend_chain_tokenscontract_flags: e.g.backend_enabled,contract_metorbackend_disabled,contract_fallbackprofiler_flags: e.g.sample_trace_present,trace_chain_recorded
Use the --sampling-backends flag with one or more values (stim, qhybrid, cuquantum, qujax, cudaq) or sweep aliases (all, sweep, all_backends, *) to capture comparable backend metadata in each backend mode.
flowchart LR
U[User / Script / Notebook] --> A[Code Family Plugins]
U --> B[RL Gym Environments]
subgraph Plugins
A1[surface plugin]
A2[qldpc plugin]
A3[bosonic plugin]
A4[dual_rail_erasure plugin]
A5[color_code plugin]
end
A --> A1
A --> A2
A --> A3
A --> A4
A --> A5
A1 --> C[Stim Circuit String]
A2 --> C
A3 --> C
A4 --> C
A5 --> C
C --> D[stim.Circuit + sampler]
D --> E[Syndromes + Observables]
subgraph RL
B1[QECGymEnv<br/>one-shot decoding]
B2[QECContinuousControlEnv<br/>calibration control]
B3[ColourCodeGymEnv<br/>colour code decoding]
B4[ColourCodeDiscoveryEnv<br/>code discovery]
B5[ColourCodeCalibrationEnv<br/>calibration]
F1[Transformer/TITANS PPO]
F2[Continuous SAC]
end
B --> B1
B --> B2
B --> B3
B --> B4
B --> B5
E --> B1
E --> B2
E --> B3
E --> B4
E --> B5
B1 --> F1
B2 --> F2
B3 --> F1
B4 --> F1
B5 --> F2
F1 --> G[Decode action / logical prediction]
F2 --> H[Continuous control action / theta update]
G --> I[Reward / metrics]
H --> I
docs/README.md: docs index and reading pathdocs/RL_QEC_ARCHITECTURE.md: detailed architecture and algorithm internals with Mermaid diagramsRL_EXPERIMENTS.md: reproducibility notessurface_code_in_stem/DYNAMIC_CODES.md: dynamic-code implementation notes
- See
CONTRIBUTING.mdfor issue and PR flow. - See
SECURITY.mdfor vulnerability reporting guidance. - See
CODE_OF_CONDUCT.mdfor collaboration expectations.
The colour code implementation is based on:
- Lee & Brown (2025): "High-threshold and low-overhead fault-tolerant quantum memory", arXiv:2503.09704 — Breakthrough colour code architecture with concatenated MWPM decoding
- Entropica Loom (2024): "Loom: A quantum error correction lattice surgery tool", arXiv:2404.08663 — Eka/Block/Lattice abstractions for QEC circuit design
- color-code-stim: Python package for simulating and decoding colour code circuits using Stim — GitHub
The implementation includes:
- Two circuit builders:
ColorCodeStimBuilder(color-code-stim) andLoomColorCodeBuilder(el-loom) - Concatenated MWPM decoder with 6 matchings (2 per colour R/G/B)
- RL environments for decoding, discovery, and calibration
- Parallel threshold estimation with circuit caching
- Hexagonal lattice visualization in Streamlit UI
- RL environments are implemented with
gymnasium-compatible wrappers andgymcompatibility paths. QECGymEnvis currently a one-step episode formulation for decoding, ideal for policy learning over syndrome-to-logical mapping and baseline comparison against MWPM.

