Custom Noise Model
SkillAI & modelsConfigure noise models and error rates for LightStim experiments. Use this skill whenever the user asks about noise models, setting physical error rates, choosing between circuit_level / circuit_level_with_idling / phenomenological / code_capacity / XZ_biased noise, biased noise for neutral atom or trapped ion hardware, or wants to understand how noise is applied to a circuit. Also trigger when the user asks "what p should I use?" or "how do I add noise to my circuit?"
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Custom Noise Model skill
What this skill tells your AI
The instructions your AI receives, as published by qutone/lightstim in skills/custom-noise/SKILL.md and read by ahel’s review.
LightStim separates circuit construction from noise injection. Build the
noiseless circuit first (via builder.build_noisy_circuit), then inject noise
as a post-processing step. The clean circuit remains available in builder.circuit.
The injection API
noisy_circuit = builder.build_noisy_circuit(
noise_params, # NoiseConfig instance
noise_model, # str — strategy name, see table below
)
# Returns a new stim.Circuit. Does NOT modify builder.circuit in place.
NoiseConfig fields
from lightstim.noise.config import NoiseConfig
noise = NoiseConfig(
p_1q=1e-3, # Depolarizing after single-qubit gates (H, S, ...)
p_2q=1e-3, # Depolarizing after two-qubit gates (CX, CZ, ...)
p_meas=1e-3, # Measurement bit-flip probability
p_reset=1e-3, # State-preparation bit-flip probability
p_idle=0, # Placement depends on the selected noise model
custom_params={}, # Arbitrary extra rates for XZ_biased or custom rules
)
Unused fields default to 0. Set only the fields the target noise model uses.
Noise model strategies
| Strategy | Injects | Relevant params | Use for |
|---|---|---|---|
circuit_level | Gate/SPAM noise plus active-data idle at TICK[SE_start] | p_1q, p_2q, p_meas, p_reset, p_idle | LightStim's historical circuit-level convention |
circuit_level_with_idling | Same gate/SPAM noise plus idle depolarization on every unoperated qubit in each moment | p_1q, p_2q, p_meas, p_reset, p_idle | Paper models with per-moment idle coverage |
phenomenological | Data errors at SE_start tick + measurement flips | p_idle, p_meas | Fast threshold analysis, ignores gate structure |
code_capacity | Data errors only (no gate/meas noise) | p_idle | Ideal measurements, pure code distance study |
XZ_biased | Independent X and Z channels after each gate | See below | Biased noise (neutral atoms, trapped ions) |
Decision guide
- Superconducting hardware:
circuit_levelwithp_2q ≈ 10× p_1q,p_meas ≈ p_2q. - Per-moment idling:
circuit_level_with_idling; set all five rates equal toponly when the target paper defines one shared probability. - Threshold plots (fast):
phenomenologicalfirst, then cross-check key points withcircuit_level. - Code distance study only:
code_capacity— fastest, no gate noise. - Biased hardware (neutral atoms η ≫ 1, trapped ions η ≲ 1):
XZ_biased.
XZ-biased noise model
For hardware with asymmetric X/Z error rates, use XZ_biased with the
compute_XZ_biased_params helper to convert physical rates + bias ratio η:
from lightstim.noise.injector import NoiseInjector
# eta = p_X / p_Z: >1 means X-biased, <1 means Z-biased
biased_noise = NoiseInjector.compute_XZ_biased_params(
p_1q=1e-3, p_2q=2e-3, p_meas=1e-3, p_reset=1e-3,
eta=0.01, # strongly Z-biased (neutral atom regime)
)
noisy = builder.build_noisy_circuit(biased_noise, noise_model='XZ_biased')
compute_XZ_biased_params fills custom_params with:
p_1q_x, p_1q_z, p_2q_x, p_2q_z — the per-axis rates
derived from the total rates and the bias η.
Noiseless gate phases
Some protocol phases (e.g. state injection initialization, encoding circuits)
should not receive noise. Pass noiseless=True to suppress noise on specific calls:
builder.initialize(init_dict, n, noiseless=True) # RX/R tags 'noiseless'
builder.apply_syndrome_extraction(se.circuit, noiseless=True) # all gates tagged
builder.apply_unitary_block(gate, noiseless=True) # same
The noise injector skips all instructions tagged 'noiseless'.
This is how state-injection protocols avoid noising the unencoded region.
For circuit_level_with_idling, every TICK-delimited moment uses the complete
physical-qubit set. Resets, measurements, and unitary gates count as operations;
all other target qubits receive one DEPOLARIZE1(p_idle) channel. Empty moments
also receive idle noise. Moments containing only noiseless physical operations
remain noiseless.
Working examples
lightstim/protocols/memory.py— standard circuit-level noise viabuild_noisy_circuit()lightstim/protocols/state_injection.py— selective noise (injection region excluded via tags)lightstim/noise/injector.py—NoiseInjectorfactory methods for all five built-in models
Signals
- GitHub stars
- 46
- Forks
- 6
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
custom-noise- Source
- github.com/qutone/lightstim