You can sort of do this in stim, but it's not well supported. The underlying issue is that the locations of errors within a circuit is actually kinda complex, which makes it not trivial.
Basically what you need to do is to give return_errors=True
to stim.CompiledDemSampler.sample
and then use stim.Circuit.explain_detector_error_model_errors
to find noise channels in the circuit that produce the symptoms corresponding to the returned dem errors.
Here's an example. It's kind of long, which is what I mean by "it's not well supported":
import numpy as np
from typing import List
import stim
# Pick a circuit.
circuit: stim.Circuit = stim.Circuit.generated(
'color_code:memory_xyz',
distance=9,
rounds=10,
before_round_data_depolarization=1e-2,
)
# Derive detector error model data we'll use to get the errors.
dem: stim.DetectorErrorModel = circuit.detector_error_model()
dem_sampler: stim.CompiledDemSampler = dem.compile_sampler()
flat_error_instructions: List[stim.DemInstruction] = [
instruction
for instruction in dem.flattened()
if instruction.type == 'error'
]
# Perform a shot and get the error data.
det_data, obs_data, err_data = dem_sampler.sample(shots=1, return_errors=True, bit_packed=False)
single_shot_err_data = err_data[0]
# Find the corresponding dem errors and convert them to circuit errors.
# Many individual circuits errors can have the exact same symptoms; we ask it to just pick one arbitrarily.
dem_filter = stim.DetectorErrorModel()
for error_index in np.flatnonzero(single_shot_err_data):
dem_filter.append(flat_error_instructions[error_index])
explained_errors: List[stim.ExplainedError] = circuit.explain_detector_error_model_errors(dem_filter=dem_filter, reduce_to_one_representative_error=True)
# Print information about circuit errors that would explain the symptoms seen in the shot.
for err in explained_errors:
rep_loc: stim.CircuitErrorLocation = err.circuit_error_locations[0]
if rep_loc.flipped_measurement is not None:
print("flipped measurement", rep_loc.flipped_measurement, "at time", rep_loc.tick_offset)
tc: stim.GateTargetWithCoords
for tc in rep_loc.flipped_pauli_product:
basis = 'X' if tc.gate_target.is_x_target else 'Y' if tc.gate_target.is_y_target else 'Z'
print("flipped", basis, "of qubit with coord", tc.coords, "at time", rep_loc.tick_offset)
which outputs something like:
flipped X of qubit with coord [10.0, 2.0] at time 1
flipped X of qubit with coord [9.0, 4.0] at time 1
flipped Y of qubit with coord [1.5, 3.0] at time 9
flipped Y of qubit with coord [7.0, 10.0] at time 9
flipped Y of qubit with coord [6.0, 10.0] at time 41
flipped Y of qubit with coord [8.5, 5.0] at time 49
flipped Y of qubit with coord [7.0, 6.0] at time 57