Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/quantumlib/Stim/llms.txt

Use this file to discover all available pages before exploring further.

stim.Circuit is the central class in the Stim library. You describe a noisy stabilizer computation to Stim by building a Circuit object, then use it to generate detector error models for decoders, bulk-sample measurement outcomes, or search for undetectable logical errors. Circuits are mutable and support a text-based format that can be saved and reloaded from files.

Constructor

Creates a new stim.Circuit, optionally pre-populated from Stim program text.
def __init__(self, stim_program_text: str = '') -> None
Parameters
NameTypeDescription
stim_program_textstrStim program text to parse and append. Defaults to empty.
import stim

empty = stim.Circuit()
not_empty = stim.Circuit('''
    X 0
    CNOT 0 1
    M 1
''')
Generates complete, annotated circuits for well-known quantum error correcting codes.
@staticmethod
def generated(
    code_task: str,
    *,
    distance: int,
    rounds: int,
    after_clifford_depolarization: float = 0.0,
    before_round_data_depolarization: float = 0.0,
    before_measure_flip_probability: float = 0.0,
    after_reset_flip_probability: float = 0.0,
) -> stim.Circuit
Parameters
NameTypeDescription
code_taskstrOne of "repetition_code:memory", "surface_code:rotated_memory_x", "surface_code:rotated_memory_z", "surface_code:unrotated_memory_x", "surface_code:unrotated_memory_z", "color_code:memory_xyz".
distanceintCode distance (minimum number of physical errors causing a logical error).
roundsintNumber of measurement rounds.
after_clifford_depolarizationfloatProbability of depolarizing noise after each Clifford gate.
before_round_data_depolarizationfloatProbability of depolarizing data qubits at the start of each round.
before_measure_flip_probabilityfloatProbability of bit-flip before each measurement.
after_reset_flip_probabilityfloatProbability of bit-flip after each reset.
The returned circuit includes DETECTOR, OBSERVABLE_INCLUDE, and TICK annotations.
import stim

circuit = stim.Circuit.generated(
    "surface_code:rotated_memory_x",
    distance=5,
    rounds=10,
    after_clifford_depolarization=0.001,
)
print(circuit.num_qubits)     # number of physical qubits
print(circuit.num_detectors)  # number of parity check detectors

Building circuits

Appends a gate, instruction, repeat block, or another circuit onto this one.
def append(
    self,
    name: Union[str, stim.CircuitInstruction, stim.CircuitRepeatBlock, stim.Circuit],
    targets: Union[int, stim.GateTarget, stim.PauliString,
                   Iterable[Union[int, stim.GateTarget, stim.PauliString]]] = (),
    arg: Union[float, Iterable[float], None] = None,
    *,
    tag: str = '',
) -> None
Parameters
NameTypeDescription
namestr or instructionGate name (e.g. "H", "M", "CNOT") or an existing instruction/circuit to append.
targetsint, GateTarget, or iterableQubits or gate targets the operation acts on.
argfloat or list of floatsParens arguments such as noise probability.
tagstrOptional string tag attached to the instruction.
import stim

c = stim.Circuit()
c.append("H", [0, 1])
c.append("CNOT", [0, 1])
c.append("M", [0, stim.target_inv(1)])
c.append("X_ERROR", [0], 0.125)
print(c)
Combines two circuits by appending the second after the first.
def __add__(self, second: stim.Circuit) -> stim.Circuit
def __iadd__(self, second: stim.Circuit) -> stim.Circuit
import stim

c1 = stim.Circuit("X 0\nY 1 2")
c2 = stim.Circuit("M 0 1 2")
combined = c1 + c2   # new circuit
c1 += c2             # mutates c1 in place
Wraps the circuit contents into a REPEAT block.
def __mul__(self, repetitions: int) -> stim.Circuit
def __imul__(self, repetitions: int) -> stim.Circuit
Special cases: repetitions=0 returns an empty circuit; repetitions=1 returns a copy.
import stim

round_circuit = stim.Circuit('''
    CX 0 1 2 3
    M 1 3
''')
full = round_circuit * 100   # REPEAT 100 { ... }

Sampling

Returns a stim.CompiledMeasurementSampler that efficiently produces bulk measurement results.
def compile_sampler(
    self,
    *,
    skip_reference_sample: bool = False,
    seed: Optional[int] = None,
    reference_sample: Optional[np.ndarray] = None,
) -> stim.CompiledMeasurementSampler
Parameters
NameTypeDescription
skip_reference_sampleboolWhen True, skips collecting the noiseless reference sample; results will be flip-relative.
seedint or NoneDeterministic seed for the RNG. Results are consistent only within the same Stim version.
reference_samplenp.ndarray or NoneExplicit reference sample to use instead of collecting one.
import stim

sampler = stim.Circuit('''
    X_ERROR(0.01) 0
    M 0
''').compile_sampler()
results = sampler.sample(shots=1000)  # shape (1000, 1), dtype=bool_
Returns a stim.CompiledDetectorSampler that produces detection event and observable flip data.
def compile_detector_sampler(
    self,
    *,
    seed: object = None,
) -> stim.CompiledDetectorSampler
import stim

c = stim.Circuit('''
    H 0
    CNOT 0 1
    M 0 1
    DETECTOR rec[-1] rec[-2]
''')
sampler = c.compile_detector_sampler()
det_events, obs_flips = sampler.sample(shots=1000, separate_observables=True)
Creates a stim.CompiledMeasurementsToDetectionEventsConverter for converting raw measurement arrays into detection events offline.
def compile_m2d_converter(
    self,
    *,
    skip_reference_sample: bool = False,
) -> stim.CompiledMeasurementsToDetectionEventsConverter
import stim, numpy as np

converter = stim.Circuit('''
    X 0
    M 0
    DETECTOR rec[-1]
''').compile_m2d_converter()

raw = np.array([[0], [1]], dtype=np.bool_)
det = converter.convert(measurements=raw, append_observables=False)
# det == [[True], [False]]

Analysis

Converts the circuit into a stim.DetectorErrorModel describing all error mechanisms.
def detector_error_model(
    self,
    *,
    decompose_errors: bool = False,
    flatten_loops: bool = False,
    allow_gauge_detectors: bool = False,
    approximate_disjoint_errors: float = False,
    ignore_decomposition_failures: bool = False,
    block_decomposition_from_introducing_remnant_edges: bool = False,
) -> stim.DetectorErrorModel
Parameters
NameTypeDescription
decompose_errorsboolDecompose composite errors into at-most-two-detector components for matching decoders.
flatten_loopsboolExpand all REPEAT blocks into inline instructions.
allow_gauge_detectorsboolTreat non-deterministic detectors as gauge degrees of freedom.
approximate_disjoint_errorsbool or floatTreat disjoint error channels as independent (approximation).
import stim

dem = stim.Circuit('''
    X_ERROR(0.01) 0
    M 0
    DETECTOR rec[-1]
''').detector_error_model()
print(dem)
Finds the smallest set of graphlike errors that cause an undetected logical error.
def shortest_graphlike_error(
    self,
    *,
    ignore_ungraphlike_errors: bool = True,
    canonicalize_circuit_errors: bool = False,
) -> List[stim.ExplainedError]
import stim

circuit = stim.Circuit.generated(
    "repetition_code:memory",
    rounds=10,
    distance=7,
    before_round_data_depolarization=0.01,
)
errors = circuit.shortest_graphlike_error()
print(f"Code distance upper bound: {len(errors)}")
Explains how each stim.DetectorErrorModel error term is produced by physical circuit errors.
def explain_detector_error_model_errors(
    self,
    *,
    dem_filter: object = None,
    reduce_to_one_representative_error: bool = False,
) -> List[stim.ExplainedError]
import stim

circuit = stim.Circuit('''
    H 0
    CNOT 0 1
    DEPOLARIZE1(0.01) 0
    CNOT 0 1
    H 0
    M 0 1
    DETECTOR rec[-1]
    DETECTOR rec[-2]
''')
explained = circuit.explain_detector_error_model_errors(
    dem_filter=stim.DetectorErrorModel("error(1) D0 D1"),
    reduce_to_one_representative_error=True,
)
print(explained[0].circuit_error_locations[0])

Properties

num_qubits

int — Number of qubits used when simulating the circuit. Always one more than the largest qubit index referenced.
stim.Circuit("H 0\nM 0 1 100").num_qubits  # 101

num_measurements

int — Total number of measurement bits produced when running the circuit, including inside REPEAT blocks.
stim.Circuit("M 0\nREPEAT 100 { M 0 1 }").num_measurements  # 201

num_detectors

int — Number of DETECTOR bits produced when sampling the circuit.
c.num_detectors

num_observables

int — Number of logical observables declared via OBSERVABLE_INCLUDE. One more than the largest index used.
c.num_observables

num_ticks

int — Number of TICK instructions executed (counting each loop iteration).
c.num_ticks

num_sweep_bits

int — Number of sweep configuration bits required by the circuit.
c.num_sweep_bits

I/O

Reads a circuit from a .stim file or any file-like object.
@staticmethod
def from_file(
    file: Union[io.TextIOBase, str, pathlib.Path],
) -> stim.Circuit
import stim

circuit = stim.Circuit.from_file("my_circuit.stim")
Writes the circuit in Stim format to a file path or file-like object.
def to_file(
    self,
    file: Union[io.TextIOBase, str, pathlib.Path],
) -> None
import stim

c = stim.Circuit("H 0\nCNOT 0 1\nM 0 1")
c.to_file("output.stim")
Converts the circuit to an OpenQASM 2 or 3 string.
def to_qasm(
    self,
    *,
    open_qasm_version: int,
    skip_dets_and_obs: bool = False,
) -> str
Parameters
NameTypeDescription
open_qasm_versionintTarget OpenQASM version: 2 or 3.
skip_dets_and_obsboolOmit detector and observable registers from output.
Detector and observable support requires OpenQASM 3 (version 3 supports classical operations). Feedback and subroutines are also version-3 only.
import stim

qasm = stim.Circuit("H 0\nCNOT 0 1\nM 0 1").to_qasm(open_qasm_version=3)
print(qasm)
Returns a URL that opens the circuit in the Crumble interactive stabilizer circuit editor.
def to_crumble_url(
    self,
    *,
    skip_detectors: bool = False,
    mark: Optional[Dict[int, List[stim.ExplainedError]]] = None,
) -> str
import stim

url = stim.Circuit("H 0\nCNOT 0 1\nS 1").to_crumble_url()
# 'https://algassert.com/crumble#circuit=H_0;CX_0_1;S_1_'

Additional methods

Returns an equivalent circuit with all REPEAT and SHIFT_COORDS instructions expanded inline.
def flattened(self) -> stim.Circuit
Returns a copy of the circuit with all noise operations removed.
def without_noise(self) -> stim.Circuit
Returns the circuit with operations inverted and in reverse order.
def inverse(self) -> stim.Circuit
Raises ValueError if the circuit contains measurements or resets, which don’t have clean inverses.
Converts a noise-free, measurement-free, reset-free circuit to a stim.Tableau.
def to_tableau(
    self,
    *,
    ignore_noise: bool = False,
    ignore_measurement: bool = False,
    ignore_reset: bool = False,
) -> stim.Tableau
Checks whether the circuit implements the given stabilizer flow(s).
def has_flow(self, flow: stim.Flow, *, unsigned: bool = False) -> bool
def has_all_flows(self, flows: Iterable[stim.Flow], *, unsigned: bool = False) -> bool
import stim

stim.Circuit("H 0").has_flow(stim.Flow("X -> Z"))  # True
stim.Circuit("H 0").has_flow(stim.Flow("Z -> X"))  # True
Returns a nested dictionary mapping each detector/observable to the Pauli sensitivity at each tick.
def detecting_regions(
    self,
    *,
    targets: Optional[Iterable[Union[stim.DemTarget, str, Iterable[float]]]] = None,
    ticks: Optional[Iterable[int]] = None,
) -> Dict[stim.DemTarget, Dict[int, stim.PauliString]]

Build docs developers (and LLMs) love