Stim circuit import¶
Install the optional Stim integration before importing this module:
uv add "graphqomb[stim]"
The circuit importer converts supported Stim circuits into GraphQOMB
measurement patterns. It accepts initial Pauli resets, Clifford unitary blocks,
and Pauli measurement blocks separated by TICK. The supported Pauli
measurement instructions are M/MZ, MX, MY, MXX, MYY,
MZZ, and MPP.
Every unitary block is normalized by graphqomb.stim_glue.transpiler to the four
Clifford J(angle) gates (H = J(0), HS = J(pi/2), HZ = J(pi),
HS_DAG = J(-pi/2), corresponding to X+/Y-/X-/Y+ measurements) plus CZ
before graph conversion. This accepts all fixed one- and two-qubit Clifford
gates exposed by Stim as well as SPP and SPP_DAG. Each basis gate
becomes one GraphQOMB J primitive.
Here, circuit foliation means constructing an MBQC pattern from the
operations of a Clifford circuit, including gates, resets, measurements, and
feedback. We distinguish this circuit construction from code foliation for
memory operations such as CSS-code memories. YFoliation selects the graph
construction for products containing Y factors.
For closed syndrome-extraction windows, first apply Round-preserving syndrome extraction
and pass its result.circuit to this importer. Record references already
include any readout permutation; Pauli feedback follows the ordinary
xflow/zflow import path.
Initial reset instructions¶
Without an explicit reset, an input uses the Z+ state (|0>), matching
Stim’s default initialization. Both M 0 and R 0; M 0 therefore return
zero noiselessly. To prepare |+>, specify RX before the qubit’s first
quantum use. This default applies to Stim circuit import; GraphQOMB’s general
input initialization default remains X+.
Leading reset instructions determine the positive Pauli eigenstate used for an
input: R/RZ initializes Z+, RX initializes X+, and RY
initializes Y+. A reset is initial when its target qubit has not previously
participated in a unitary or measurement operation. Operations on other qubits
do not prevent a later initial reset. Repeated leading resets are accepted, and
the last reset on each qubit determines its initialization state.
Leading resets are normalized together with the Clifford gates in their
TICK block. When the resulting state is a positive Pauli eigenstate, the
gates are absorbed into R, RX, or RY before graph construction.
For example, R followed by H becomes RX and does not add a gate
node or shift that input to an earlier z layer.
Stim canonicalizes the Z-axis aliases internally, so the importer accepts both
M and MZ for Z measurement and both R and RZ for Z reset. Stim
export uses MZ for Z measurement and R for Z reset.
A mid-circuit reset starts a new wire on a fresh internal qubit index: the
reset and every later operation on that Stim qubit continue on the new wire,
which is initialized in the positive eigenstate of the reset axis at the
qubit’s XY coordinates on the next z layer. The reset discards the
previous state, so the new wire carries no outcome conditioning; when several
resets act on the qubit before its next quantum use, the last reset determines
the axis. A replaced wire that was not consumed by a direct measurement
remains a pattern output, which is channel-equivalent to the trace-out reset
on every recorded measurement. Combined measurement-reset instructions
(MR/MRZ, MRX, and MRY) are imported as a direct measurement
whose continuation re-prepares the measured axis eigenstate unconditionally.
StimImportResult.qubit_to_stim maps every fresh index back to the original
Stim qubit id. Because that mapping is many-to-one for a reset qubit,
stim_to_final_qubit gives the index of its last lifetime; the earlier
indices are discarded history. Equivalence to the source circuit is equivalence
of the recorded measurements, not of the pattern’s output channel: a replaced
live wire is a purification of Stim’s trace-out reset, so a caller that reads
every pattern output must trace out the outputs that are not named by
stim_to_final_qubit.
Internally each reset lifetime also receives its own Stim qubit id, and the
StimMppExtraction metadata of an MPP block (supports,
stim_to_column, and column_to_stim) reports the lifetime that each
product measured. A qubit measured before and after a reset therefore occupies
a different column in each block, and the same physical qubit may carry
different ids across blocks. StimImportResult.wire_to_stim maps every such
id back to the original circuit id; it is the identity for qubits that are
never reset mid-circuit.
Within one optimization block, single-qubit Cliffords preceding a terminal
measurement are absorbed into its signed Pauli basis when its post-state is
not reused. For example, H 0; M 0 becomes MX 0, and
S 0; MX 0 becomes MY !0. These readouts need no extra gate node.
TICK barriers and measurements whose qubits are reused limit this folding;
the latter must preserve the post-measurement state.
Single-qubit measurements assign an AxisMeasBasis directly to the measured
data-lane endpoint without replacing that node or its coordinate. They do not
create an MPP extraction or an ancillary parity measurement node. Inverted
single-qubit measurement targets select the minus sign of that node’s basis. A
direct single-qubit measurement ends that wire: a later quantum operation on
the same qubit continues on a fresh internal qubit index initialized in the
positive eigenstate of the measurement axis and conditioned on the outcome
through the correction flows. Reuse after an inverted plain target (M !q)
is rejected because negative-eigenstate initialization cannot be represented,
while an inverted measure-reset target may be reused because the reset
discards the outcome.
The first two components of QUBIT_COORDS are used as the fixed spatial
(x, y) position of each data lane. The importer supplies the temporal z
component. Wires split from a mid-circuit reset inherit the original qubit’s
(x, y). Fully coordinated and fully uncoordinated circuits both import
silently; when only some wires carry QUBIT_COORDS the importer emits a
UserWarning, because a mixture usually means coordinate metadata was lost
upstream — for example reset lifetimes split onto fresh qubit ids by another
tool, which cannot be mapped back to an original qubit. Every unitary TICK
block is transpiled before placement. Its
input layer starts at the preceding block’s output z, and all of its output
nodes share the maximum transpiled depth of the block. A shorter data-wire
chain is spread across that same interval. A live qubit with no operation in
the block remains a single input/output node and is relocated directly to the
common output layer; this adds no graph node or edge and does not change the
circuit semantics.
Two-qubit measurements are parity measurements and are lowered to equivalent
unsigned MPP products. Inverted targets in MXX, MYY, and MZZ
are rejected by the direct importer; the rewriter can normalize them to signed
MPP products. Signed MPP is supported: its product sign changes the
ancilla measurement basis. The Type-I Y construction also contributes its
own phase correction. Extraction supports and check matrices describe
unsigned support; the pattern retains the measurement sign.
Classical Pauli feedback¶
Stim measurement-record controls are imported as explicit Pauli-frame
corrections. CX rec[-k] q/CNOT rec[-k] q adds q to the
controlling measurement node’s X-correction flow, CZ rec[-k] q adds it to
the Z-correction flow, and CY rec[-k] q adds it to both. The equivalent
reverse-target spellings XCZ q rec[-k] and YCZ q rec[-k] are also
supported, as is the symmetric CZ q rec[-k] form. Batched target pairs in
one Stim instruction are supported, including instructions mixing quantum and
feedback pairs. The importer splits those pairs in source order; this also
handles Stim’s automatic fusion of adjacent instructions.
A feedback instruction is a graph-fragment boundary, so its correction targets the data-lane node at that exact circuit position. Repeating the same record-controlled Pauli correction cancels by parity. A feedback record must refer to an earlier imported measurement; records idealized to zero produce no correction.
Frame corrections are applied at their target’s measurement, after every graph edge on the target exists. An X or Y feedback therefore also XORs Z corrections onto the neighbors the target becomes entangled with after the feedback position, which is what pushing the deferred X through those later CZ edges leaves behind. Neighbors entangled before the feedback position receive no compensation, and Z feedback commutes with CZ so it needs none.
A feedback record may come from an MPP ancilla or from a direct
single-qubit measurement. Direct measurements are imported as measured output
nodes, which are scheduled like ordinary measurements, so the controlling
readout is always measured before any node that depends on its correction.
All MPP instructions within each feedback-free portion of one TICK
block are represented by one combined extraction and are validated to commute.
Anticommuting products in the same portion are rejected. Within a combined
block, local stabilizer interactions are ordered Z -> Y -> X on each
shared data qubit. If an odd number of shared-data-qubit pairs reverse the
order of the same two stabilizers, the graph-state builder adds the required CZ
edge between their ancillas. This rule is applied automatically for both Type
I and Type II circuit foliation.
Only data-wire nodes contribute to the graph-generated X-correction flow; MPP
ancilla nodes do not produce those corrections. After composing all graph
fragments, the importer first derives the Z-correction flow from the odd
neighborhood of this graph-generated X flow. It then XORs Stim’s explicit
classical X/Y/Z feedback into the two correction maps, including the
deferred-X compensation described above; a feedback entry never adopts the
full odd-neighbor rule, only the neighbors entangled after its position.
Both completed maps are passed directly to qompile() without Pauli
simplification or an importer-specific fallback. Non-commuting measurements
must be separated by TICK in the source circuit. Each unit has a distinct
unmeasured output layer, which is composed with the next unitary or measurement
fragment by qubit index. Pass
y_foliation=YFoliation.TYPE_II to any of the three import entry points to use
the three-layer Y-measurement construction; Type I is the default.
An MPP block starts at the preceding gate or MPP output layer and ends two
z units later. Live lanes not used by that MPP block are relocated to the
same output layer without adding nodes. Consequently, a composed output and
the next active fragment input have the same z coordinate, and imported
patterns do not mix 2D spatial coordinates with 3D spacetime coordinates.
The flattened ideal circuit is normalized before measurement-record analysis.
The original qubit inventory is retained even when a unitary block optimizes
to the identity. Records from single-qubit measurements, pair measurements,
MPP, and ideal-zero MPAD replacements share one absolute index space.
DETECTOR and OBSERVABLE_INCLUDE targets are resolved against that
whole-circuit index space, and each StimMppExtraction retains the
corresponding absolute record sets even when an annotation also references
records outside that MPP unit.
Noise policy¶
Circuit-level Stim noise is intentionally not imported. GraphQOMB applies noise to the compiled MBQC pattern through its own noise-model API, where preparation, entanglement, measurement, and idle events differ from the source circuit operations.
Pure noise instructions are omitted during import. Error probabilities attached
to Pauli measurements are also omitted while retaining the ideal measurement.
Heralded noise records are retained as ideal zero-valued record positions so
that later DETECTOR and OBSERVABLE_INCLUDE references remain aligned.
from graphqomb.qeccode import YFoliation
from graphqomb.stim_glue.importer import stim_text_to_pattern
result = stim_text_to_pattern(
"""
RY 0
R 1 2
MX 0
MYY 1 2
DETECTOR rec[-2] rec[-1]
""",
y_foliation=YFoliation.TYPE_II,
)
pattern = result.pattern
API reference¶
Import supported Stim circuits into GraphQOMB patterns.
This module provides:
StimImportResult: Result of importing a supported Stim circuit.stim_file_to_pattern: Import a supported Stim file into a GraphQOMB pattern.stim_text_to_pattern: Import supported Stim text into a GraphQOMB pattern.stim_circuit_to_pattern: Import a supported Stim circuit into a GraphQOMB pattern.
- class graphqomb.stim_glue.importer.StimImportResult[source]¶
Bases:
objectResult of importing a supported Stim circuit.
stim_to_qubit maps each Stim qubit id to the qubit index of its initial (input-side) wire. When a Stim qubit is used again after a direct single-qubit measurement or re-initialized by a mid-circuit reset, the importer issues a fresh internal qubit index for the new wire; qubit_to_stim maps every internal qubit index, including those continuation indices, back to its Stim qubit id. That mapping is many-to-one, so stim_to_final_qubit names the index of the last lifetime of each Stim qubit; the earlier indices of a reset qubit are its discarded history, whose wires may remain pattern outputs.
A mid-circuit reset also issues a fresh Stim qubit id for the reset lifetime, and that id is what mpp_extractions reports in supports, stim_to_column, and column_to_stim. wire_to_stim maps every such id back to the original circuit’s Stim qubit id; it is the identity on qubits that are never reset mid-circuit.
- stim_to_qubit¶
Original Stim qubit id to the internal qubit index of its initial wire.
- mpp_extractions¶
Stabilizer data of each imported MPP block, keyed by wire id.
- Type:
- stim_to_final_qubit¶
Original Stim qubit id to the internal qubit index of its last lifetime.
- __init__(pattern, stim_to_qubit, qubit_to_stim, mpp_extractions, wire_to_stim, stim_to_final_qubit)¶
- graphqomb.stim_glue.importer.stim_file_to_pattern(path, *, coord_dims=2, schedule_strategy=CircuitScheduleStrategy.PARALLEL, y_foliation=YFoliation.TYPE_I, merge_safe_ticks=False, schedule_config=None, schedule_timeout=60)[source]¶
Import a supported Stim file into a GraphQOMB pattern.
When merge_safe_ticks is true, TICK boundaries whose removal cannot change the imported semantics are dropped before import; see
stim_circuit_to_pattern. schedule_config and schedule_timeout select the pattern-level scheduler; seestim_circuit_to_pattern.- Returns:
Imported pattern, qubit mapping, and MPP extraction metadata.
- Return type:
- graphqomb.stim_glue.importer.stim_text_to_pattern(text, *, coord_dims=2, schedule_strategy=CircuitScheduleStrategy.PARALLEL, y_foliation=YFoliation.TYPE_I, merge_safe_ticks=False, schedule_config=None, schedule_timeout=60)[source]¶
Import supported Stim text into a GraphQOMB pattern.
When merge_safe_ticks is true, TICK boundaries whose removal cannot change the imported semantics are dropped before import; see
stim_circuit_to_pattern. schedule_config and schedule_timeout select the pattern-level scheduler; seestim_circuit_to_pattern.- Returns:
Imported pattern, qubit mapping, and MPP extraction metadata.
- Return type:
- graphqomb.stim_glue.importer.stim_circuit_to_pattern(circuit, *, coord_dims=2, schedule_strategy=CircuitScheduleStrategy.PARALLEL, y_foliation=YFoliation.TYPE_I, merge_safe_ticks=False, schedule_config=None, schedule_timeout=60)[source]¶
Import a supported Stim circuit into a GraphQOMB pattern.
schedule_config controls how the imported pattern is scheduled: when given, a
graphqomb.scheduler.core.Scheduleris built from the imported graph and flows, solved with that configuration (schedule_timeout bounds the CP-SAT solve time in seconds), and passed tographqomb.qompiler.qompile; whenNone,qompileschedules with its default greedy strategy.The importer supports initial Pauli resets, Clifford unitary blocks, and Pauli measurement blocks. Inputs without an explicit reset start in the positive Z eigenstate (
|0>), matching Stim’s default initialization. StimR,RX, andRYinstructions are imported as positive Z-, X-, and Y-eigenstate input initialization, respectively, when they occur before any other quantum operation on the target qubit. Adjacent Clifford gates are folded into those initial Pauli states when possible. Stim noise instructions and measurement-error probabilities are omitted because circuit-level noise is outside the GraphQOMB import model. Measurement-record-controlled Pauli gates are imported as X/Z correction-flow entries at their circuit positions; an X or Y feedback additionally contributes Z corrections on the neighbors its target becomes entangled with after the feedback position, so deferred frame-based application matches the circuit-position semantics.Unitary gates may share a TICK block with Pauli measurements. Single-qubit Cliffords ahead of a measurement are folded into the measurement basis when the measured qubit is never used again; any remaining mixed block is split into internal unitary, measurement, and feedback layers that preserve the original instruction order, each advancing the z coordinate by one layer.
A Stim qubit may be used again after a direct single-qubit measurement. The importer issues a fresh internal qubit index for the post-measurement wire: a new node is placed at the qubit’s XY coordinates on the next z layer, initialized in the positive eigenstate of the measurement axis, and the measurement outcome conditions the continuation through the pattern’s correction flows. Measure-reset gates (
MR,MRX,MRY) work the same way except that the reset re-prepares the positive eigenstate unconditionally, so the continuation carries no outcome correction. Reuse after an inverted plain measurement target (M !q) is not supported because negative-eigenstate initialization cannot be represented; an inverted measure-reset target may be reused since the reset discards the outcome. Reuse is decided on the normalized circuit: single-qubit Cliffords after a measurement that cancel to the identity during per-block optimization do not count as later use, so the measured wire ends and the pattern has one output fewer than the raw instruction stream suggests.A qubit may also be re-initialized with an explicit mid-circuit
R,RX, orRY. The importer splits each reset-started lifetime onto a fresh internal qubit index: the new wire starts at the qubit’s XY coordinates on the next z layer in the positive eigenstate of the reset axis, with no outcome conditioning because the reset discards the previous state. A wire that was not consumed by a direct measurement before the reset remains a pattern output; leaving it coherent and untouched is channel-equivalent to Stim’s trace-out reset on every recorded measurement, provided that discarded output is traced out rather than read. qubit_to_stim maps the fresh indices back to the original Stim qubit id, and stim_to_final_qubit selects the live one among them.DETECTORinstruction tags are preserved: each imported detector’s tag is carried into pattern.frame.parity_check_tags (aligned with parity_check_group) and re-emitted bygraphqomb.stim_glue.compiler.stim_compile, so post-selection flag detectors (DETECTOR[type=flag]) survive the import/export round trip.TICK boundaries are optimization barriers: gates in different TICK blocks are never cancelled against each other or folded into an adjacent reset or measurement, so a finely ticked circuit can import to a much larger graph than the same instructions in fewer blocks. When merge_safe_ticks is true, the importer drops every TICK whose removal cannot change the imported semantics before analyzing the circuit. Because per-qubit instruction order and measurement-record order survive block normalization, the only TICKs kept are those separating two blocks that both contain Pauli-product measurements, preserving the per-block product grouping (one
StimMppExtractionper block, block-level commutation validation, and the block’s foliation structure). Node coordinates come out z-compressed because merged blocks share layers.Each reset lifetime also gets its own Stim qubit id internally, and the mpp_extractions metadata (supports, stim_to_column, and column_to_stim) reports the lifetime that an
MPPproduct actually measured, so a qubit measured before and after a reset occupies a distinct column in each block. wire_to_stim maps those ids back to the original circuit ids.- Returns:
Imported pattern, qubit mapping, and MPP extraction metadata.
- Return type:
- Raises:
ValueError – If the circuit uses unsupported instructions or invalid coordinates, or if schedule_config is given and no schedule is found.