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.

A detector error model (DEM) is a compact, probabilistic description of all the error mechanisms in a circuit, expressed in terms of which detectors each error flips. Conceptually it is a Tanner graph: nodes are detectors and logical observables, and edges (error mechanisms) connect the nodes whose parity they change. Decoders such as PyMatching consume this graph directly, so producing a correct DEM is the first step in any decoding pipeline.

Basic usage

Call circuit.detector_error_model() on any stim.Circuit that contains DETECTOR and OBSERVABLE_INCLUDE annotations:
import stim

circuit = stim.Circuit('''
    X_ERROR(0.125) 0
    X_ERROR(0.25) 1
    CORRELATED_ERROR(0.375) X0 X1
    M 0 1
    DETECTOR rec[-2]
    DETECTOR rec[-1]
''')

dem = circuit.detector_error_model()
print(dem)
# error(0.125) D0
# error(0.375) D0 D1
# error(0.25) D1
The returned stim.DetectorErrorModel object contains instructions of three types:
InstructionMeaning
error(p) D…Error with probability p that flips the listed detectors
error(p) D… L…Same, but also flips logical observable(s)
detector(coords) D…Coordinate metadata for a detector
logical_observable L…Declares a logical observable index

Key options

decompose_errors=True — graphlike decomposition

Matching decoders require that every error flips at most two detectors (graphlike errors). Some circuit errors — like Y errors in a CSS code — naturally flip four detectors. Setting decompose_errors=True asks Stim to split such hyper-errors into pairs of graphlike components, separated by ^ in the output:
dem = circuit.detector_error_model(decompose_errors=True)
# error(0.1) D0 D1 ^ D2 D3   ← decomposed into two graphlike pieces
Decomposition can fail if no valid graphlike splitting exists. In that case, Stim raises an exception. You can permit failures silently with ignore_decomposition_failures=True, but the resulting non-graphlike errors will be invisible to matching decoders.

approximate_disjoint_errors=True — disjoint error approximation

Some Stim error channels — PAULI_CHANNEL_1, PAULI_CHANNEL_2, ELSE_CORRELATED_ERROR — express disjoint (mutually exclusive) error cases. DEMs require independent mechanisms, so Stim will raise an error when it encounters these unless you enable the approximation:
dem = circuit.detector_error_model(approximate_disjoint_errors=True)
# PAULI_CHANNEL_1(0.1, 0.2, 0.0) → X_ERROR(0.1) + independent Y_ERROR(0.2)
DEPOLARIZE1 and DEPOLARIZE2 can be converted exactly (without approximation) for physically realistic error rates, so you rarely need this flag for depolarizing noise.

allow_gauge_detectors=True — non-deterministic detectors

By default, Stim verifies that every detector is deterministic under noiseless execution. If your circuit contains gauge detectors (detectors that anti-commute with resets or measurements), enable this flag so Stim resolves them via Gaussian elimination rather than raising an error:
dem = circuit.detector_error_model(allow_gauge_detectors=True)

flatten_loops=True — unroll REPEAT blocks

By default, Stim watches for periodic steady states inside REPEAT blocks and emits compact repeat blocks in the DEM. Set flatten_loops=True to expand all loops into individual instructions (useful for small circuits or for tools that cannot handle DEM repeat blocks):
dem = circuit.detector_error_model(flatten_loops=True)

Reading a DEM programmatically

Iterate over the instructions to inspect error mechanisms:
import stim

dem = stim.Circuit('''
    X_ERROR(0.01) 0
    M 0
    DETECTOR rec[-1]
    OBSERVABLE_INCLUDE(0) rec[-1]
''').detector_error_model()

for instruction in dem:
    if isinstance(instruction, stim.DemInstruction):
        if instruction.type == "error":
            prob = instruction.args_copy()[0]
            targets = instruction.targets_copy()
            dets = [t for t in targets if t.is_relative_detector_id()]
            obs  = [t for t in targets if t.is_logical_observable_id()]
            print(f"p={prob:.4f}  detectors={dets}  observables={obs}")
Each stim.DemInstruction exposes:
  • .type"error", "detector", or "logical_observable"
  • .args_copy() — list of float arguments (the probability for error instructions)
  • .targets_copy() — list of stim.DemTarget objects

Finding the shortest graphlike error

circuit.shortest_graphlike_error() (and the equivalent dem.shortest_graphlike_error()) returns the minimum-weight set of graphlike errors that produce an undetected logical flip:
import stim

circuit = stim.Circuit.generated(
    "surface_code:rotated_memory_x",
    rounds=3,
    distance=3,
    after_clifford_depolarization=0.001,
)

logical_error = circuit.shortest_graphlike_error()
print(f"Code distance (graphlike): {len(logical_error)}")
This is useful for verifying that a circuit implements the expected code distance before running expensive sampling.

Mapping DEM errors back to circuit locations

circuit.explain_detector_error_model_errors() traces each DEM error mechanism back to the physical circuit instruction(s) that produce it:
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,
)

for err in explained:
    for loc in err.circuit_error_locations:
        print(loc)
The output identifies the TICK offset, instruction number, and target within that instruction for each physical error.

Example: repetition code circuit → DEM

import stim

# 3-qubit repetition code, 2 rounds of stabilizer measurement
circuit = stim.Circuit('''
    X_ERROR(0.1) 0 1 2
    CNOT 0 3  1 3  1 4  2 4
    M 3 4
    DETECTOR rec[-2]
    DETECTOR rec[-1]
    X_ERROR(0.1) 0 1 2
    CNOT 0 3  1 3  1 4  2 4
    M 3 4
    DETECTOR rec[-2] rec[-4]
    DETECTOR rec[-1] rec[-3]
    M 0 1 2
    OBSERVABLE_INCLUDE(0) rec[-3] rec[-2] rec[-1]
''')

dem = circuit.detector_error_model(decompose_errors=True)
print(dem)
print(f"\nDetectors : {dem.num_detectors}")
print(f"Errors    : {dem.num_errors}")
print(f"Observables: {dem.num_observables}")

Build docs developers (and LLMs) love