Noise Model¶
graphqomb.noise_model module¶
Noise model interface for Stim circuit compilation.
This module provides:
NoisePlacement: Enum for noise placement.Coordinate: N-dimensional coordinate dataclass.NodeInfo: Node identifier with optional coordinate.PrepareEvent,EntangleEvent,MeasureEvent,IdleEvent: Event dataclasses.NoiseEvent: Union type of all event types.PauliChannel1,PauliChannel2,HeraldedPauliChannel1,HeraldedErase,RawStimOp,MeasurementFlip: NoiseOp types.NoiseOp: Union type of all noise operation types.default_noise_placement: Global default placement policy for AUTO operations.NoiseModel: Base class for noise models.DepolarizingNoiseModel,MeasurementFlipNoiseModel: Built-in noise models.noise_op_to_stim: Conversion function.depolarize1_probs: Utility to create single-qubit depolarizing probabilities.depolarize2_probs: Utility to create 2-qubit depolarizing probabilities.PAULI_CHANNEL_2_ORDER: Constant for Pauli channel order.
See also
stim_compileThe main compilation function that accepts a NoiseModel.
Notes
Placement control: Each
NoiseOphas aplacementattribute.AUTOdefers todefault_noise_placement(), whileBEFORE/AFTERforce insertion side.Record delta: Heralded instructions (
HeraldedPauliChannel1,HeraldedErase) add measurement records. The compiler automatically tracks these to compute correct detector indices.Coordinate access: Events provide
NodeInfoobjects with optional coordinates, useful for position-dependent noise models.
Examples
Create a simple depolarizing noise model:
>>> from graphqomb.noise_model import (
... NoiseModel,
... PrepareEvent,
... EntangleEvent,
... PauliChannel1,
... PauliChannel2,
... depolarize1_probs,
... depolarize2_probs,
... )
>>>
>>> class DepolarizingNoise(NoiseModel):
... def __init__(self, p1: float, p2: float) -> None:
... self.p1 = p1 # Single-qubit depolarizing probability
... self.p2 = p2 # Two-qubit depolarizing probability
...
... def on_prepare(self, event: PrepareEvent) -> list[PauliChannel1]:
... return [PauliChannel1(**depolarize1_probs(self.p1), targets=[event.node.id])]
...
... def on_entangle(self, event: EntangleEvent) -> list[PauliChannel2]:
... return [
... PauliChannel2.from_mapping(
... probabilities=depolarize2_probs(self.p2),
... targets=[(event.node0.id, event.node1.id)],
... )
... ]
Use with stim_compile:
>>> from graphqomb.stim_compiler import stim_compile
>>> # pattern = ... # your compiled pattern
>>> # stim_str = stim_compile(pattern, noise_models=[DepolarizingNoise(0.001, 0.01)])
Use heralded noise that adds measurement records:
>>> from graphqomb.noise_model import NoiseModel, MeasureEvent, HeraldedPauliChannel1
>>>
>>> class HeraldedMeasurementNoise(NoiseModel):
... def on_measure(self, event: MeasureEvent) -> list[HeraldedPauliChannel1]:
... # Heralded erasure with 10% probability
... return [HeraldedPauliChannel1(pi=0.1, px=0.0, py=0.0, pz=0.0, targets=[event.node.id])]
- graphqomb.noise_model.depolarize1_probs(p)[source]¶
Create probability dict for single-qubit depolarizing channel.
- Parameters:
p (
float) – Total depolarizing probability.- Returns:
Mapping with keys
px,py,pzeach set top/3.- Return type:
Examples
>>> probs = depolarize1_probs(0.03) >>> probs["px"] 0.01 >>> probs["py"] 0.01
- graphqomb.noise_model.depolarize2_probs(p)[source]¶
Create probability dict for 2-qubit depolarizing channel.
- Parameters:
p (
float) – Total depolarizing probability.- Returns:
Mapping from Pauli pair to probability
p/15.- Return type:
Examples
>>> probs = depolarize2_probs(0.15) >>> probs["ZZ"] 0.01 >>> len(probs) 15
- class graphqomb.noise_model.NoisePlacement[source]¶
Where to insert noise relative to the main operation.
- AUTO = 1¶
- BEFORE = 2¶
- AFTER = 3¶
- class graphqomb.noise_model.Coordinate[source]¶
N-dimensional coordinate for a node.
Examples
>>> coord = Coordinate((1.0, 2.0, 3.0)) >>> coord.xy (1.0, 2.0) >>> coord.xyz (1.0, 2.0, 3.0)
- property xy: tuple[float, float] | None¶
Return the first two dimensions as (x, y), or None if fewer than 2 dimensions.
- property xyz: tuple[float, float, float] | None¶
Return the first three dimensions as (x, y, z), or None if fewer than 3 dimensions.
- __init__(values)¶
- class graphqomb.noise_model.NodeInfo[source]¶
Node identifier with optional coordinate.
- Parameters:
id (
int) – The unique node index in the pattern.coord (
Coordinate|None) – The spatial coordinate of the node, if available.
- coord: Coordinate | None¶
- __init__(id, coord)¶
- class graphqomb.noise_model.PrepareEvent[source]¶
Event emitted when a qubit is prepared (N command).
- Parameters:
- __init__(time, node, is_input)¶
- class graphqomb.noise_model.EntangleEvent[source]¶
Event emitted when two qubits are entangled (E command / CZ gate).
- Parameters:
- __init__(time, node0, node1, edge)¶
- class graphqomb.noise_model.MeasureEvent[source]¶
Event emitted when a qubit is measured (M command).
- Parameters:
- __init__(time, node, axis)¶
- class graphqomb.noise_model.IdleEvent[source]¶
Event emitted for qubits that are idle during a TICK.
- Parameters:
time (
int) – The current tick (time step) in the pattern execution.nodes (
collections.abc.Sequence[NodeInfo]) – Information about all nodes that are idle during this tick.duration (
float) – The duration of the idle period (fromtick_durationparameter).
- __init__(time, nodes, duration)¶
- graphqomb.noise_model.NoiseEvent = graphqomb.noise_model.PrepareEvent | graphqomb.noise_model.EntangleEvent | graphqomb.noise_model.MeasureEvent | graphqomb.noise_model.IdleEvent¶
Union type of all noise event types.
- graphqomb.noise_model.default_noise_placement(event)[source]¶
Return the global default placement for AUTO noise operations.
Measurement noise is inserted before measurement operations. Noise for all other events is inserted after the corresponding operation.
- Parameters:
event (
NoiseEvent) – The event for which to determine the default placement.- Returns:
BEFOREfor measurement events,AFTERfor all others.- Return type:
- class graphqomb.noise_model.PauliChannel1[source]¶
Single-qubit Pauli channel noise operation.
Applies independent X, Y, Z errors with given probabilities. Corresponds to Stim’s
PAULI_CHANNEL_1instruction.- Parameters:
px (
float) – Probability of X error.py (
float) – Probability of Y error.pz (
float) – Probability of Z error.targets (
collections.abc.Sequence[int]) – Target qubit indices.placement (
NoisePlacement) – Whether to insert before or after the main operation.AUTOdefers todefault_noise_placement().
Examples
>>> op = PauliChannel1(px=0.01, py=0.01, pz=0.01, targets=[0, 1]) >>> noise_op_to_stim(op) ('PAULI_CHANNEL_1(0.01,0.01,0.01) 0 1', 0)
- placement: NoisePlacement = 1¶
- __init__(px, py, pz, targets, placement=NoisePlacement.AUTO)¶
- class graphqomb.noise_model.PauliChannel2[source]¶
Two-qubit Pauli channel noise operation.
Applies correlated two-qubit Pauli errors. Corresponds to Stim’s
PAULI_CHANNEL_2instruction.- Parameters:
probabilities (
tuple[float, …]) – The canonical 15 probabilities in Stim’sPAULI_CHANNEL_2order:(IX, IY, IZ, XI, XX, XY, XZ, YI, YX, YY, YZ, ZI, ZX, ZY, ZZ). Prefer usingfrom_mappingorfrom_sequenceto construct instances.targets (
tuple[tuple[int,int], …]) – Target qubit pairs as((q0, q1), ...).placement (
NoisePlacement) – Whether to insert before or after the main operation.AUTOdefers todefault_noise_placement().
Examples
Using a mapping (recommended for sparse errors):
>>> op = PauliChannel2.from_mapping(probabilities={"ZZ": 0.01}, targets=[(0, 1)]) >>> text, delta = noise_op_to_stim(op) >>> "PAULI_CHANNEL_2" in text True
Using a full probability sequence:
>>> probs = [0.0] * 14 + [0.01] # Only ZZ error >>> op = PauliChannel2.from_sequence(probabilities=probs, targets=[(2, 3)])
- placement: NoisePlacement = 1¶
- classmethod from_mapping(probabilities, targets, placement=NoisePlacement.AUTO)[source]¶
Build a Pauli channel from sparse Pauli-pair probabilities.
- Returns:
A normalized two-qubit Pauli channel.
- Return type:
- classmethod from_sequence(probabilities, targets, placement=NoisePlacement.AUTO)[source]¶
Build a Pauli channel from probabilities in Stim’s required order.
- Returns:
A normalized two-qubit Pauli channel.
- Return type:
- __init__(probabilities, targets, placement=NoisePlacement.AUTO)¶
- class graphqomb.noise_model.HeraldedPauliChannel1[source]¶
Heralded single-qubit Pauli channel noise operation.
Similar to
PauliChannel1but produces a herald measurement record indicating whether an error occurred. The herald outcome is 1 if any error occurred (including identity with probabilitypi). Corresponds to Stim’sHERALDED_PAULI_CHANNEL_1instruction.- Parameters:
pi (
float) – Probability of heralded identity (no error but flagged).px (
float) – Probability of heralded X error.py (
float) – Probability of heralded Y error.pz (
float) – Probability of heralded Z error.targets (
collections.abc.Sequence[int]) – Target qubit indices.placement (
NoisePlacement) – Whether to insert before or after the main operation.AUTOdefers todefault_noise_placement().
Notes
This instruction adds one measurement record per target qubit. The compiler automatically tracks this when computing detector indices.
Examples
>>> op = HeraldedPauliChannel1(pi=0.0, px=0.01, py=0.0, pz=0.0, targets=[5]) >>> text, delta = noise_op_to_stim(op) >>> text 'HERALDED_PAULI_CHANNEL_1(0.0,0.01,0.0,0.0) 5' >>> delta # One record added per target 1
- placement: NoisePlacement = 1¶
- __init__(pi, px, py, pz, targets, placement=NoisePlacement.AUTO)¶
- class graphqomb.noise_model.HeraldedErase[source]¶
Heralded erasure noise operation.
Models photon loss or erasure errors with a herald signal. Corresponds to Stim’s
HERALDED_ERASEinstruction.- Parameters:
p (
float) – Probability of erasure.targets (
collections.abc.Sequence[int]) – Target qubit indices.placement (
NoisePlacement) – Whether to insert before or after the main operation.AUTOdefers todefault_noise_placement().
Notes
This instruction adds one measurement record per target qubit. The compiler automatically tracks this when computing detector indices.
Examples
>>> op = HeraldedErase(p=0.05, targets=[0, 1, 2]) >>> text, delta = noise_op_to_stim(op) >>> text 'HERALDED_ERASE(0.05) 0 1 2' >>> delta # One record added per target 3
- placement: NoisePlacement = 1¶
- __init__(p, targets, placement=NoisePlacement.AUTO)¶
- class graphqomb.noise_model.RawStimOp[source]¶
Raw Stim instruction for advanced use cases.
Use this when the typed noise operations don’t cover your use case. The text is inserted directly into the Stim circuit.
- Parameters:
text (
str) – A single Stim instruction line (without trailing newline).record_delta (
int) – The number of measurement records added by this instruction. Most noise instructions do not add records (default 0).placement (
NoisePlacement) – Whether to insert before or after the main operation.AUTOdefers todefault_noise_placement().
Examples
>>> op = RawStimOp("X_ERROR(0.001) 0 1 2") >>> noise_op_to_stim(op) ('X_ERROR(0.001) 0 1 2', 0)
With custom record delta for measurement-like instructions:
>>> op = RawStimOp("MR 5", record_delta=1) >>> noise_op_to_stim(op) ('MR 5', 1)
- placement: NoisePlacement = 1¶
- __init__(text, record_delta=0, placement=NoisePlacement.AUTO)¶
- class graphqomb.noise_model.MeasurementFlip[source]¶
Measurement flip error applied to measurement instruction.
Unlike other NoiseOp types that insert separate instructions, this modifies the measurement instruction itself to use Stim’s built-in measurement error probability: MX(p) instead of MX.
- Parameters:
p (
float) – Probability of measurement result flip.target (
int) – Target qubit index (must match the measurement target).placement (
NoisePlacement) – Placement attribute for compatibility (ignored, as this modifies the measurement instruction itself).
- placement: NoisePlacement = 1¶
- __init__(p, target, placement=NoisePlacement.AUTO)¶
- graphqomb.noise_model.NoiseOp = graphqomb.noise_model.PauliChannel1 | graphqomb.noise_model.PauliChannel2 | graphqomb.noise_model.HeraldedPauliChannel1 | graphqomb.noise_model.HeraldedErase | graphqomb.noise_model.RawStimOp | graphqomb.noise_model.MeasurementFlip¶
Union type of all noise operation types.
- class graphqomb.noise_model.NoiseModel[source]¶
Base class for custom noise injection during Stim compilation.
Subclass this to define custom noise behavior by overriding one or more of the event handler methods. Each method receives an event object with context about the current operation and returns noise operations to inject.
Examples
>>> class SimpleNoise(NoiseModel): ... def on_prepare(self, event: PrepareEvent) -> list[PauliChannel1]: ... # Add depolarizing noise after preparation ... p = 0.001 / 3 ... return [PauliChannel1(px=p, py=p, pz=p, targets=[event.node.id])] ... ... def on_measure(self, event: MeasureEvent) -> list[PauliChannel1]: ... # Add bit-flip noise before measurement ... return [ ... PauliChannel1(px=0.01, py=0.0, pz=0.0, targets=[event.node.id], placement=NoisePlacement.BEFORE) ... ]
- on_prepare(event)[source]¶
Return noise operations to inject at qubit preparation.
- Parameters:
event (
PrepareEvent) – Context about the preparation operation.- Returns:
Zero or more noise operations to inject.
- Return type:
- on_entangle(event)[source]¶
Return noise operations to inject at entanglement.
- Parameters:
event (
EntangleEvent) – Context about the entanglement operation.- Returns:
Zero or more noise operations to inject.
- Return type:
- on_measure(event)[source]¶
Return noise operations to inject at measurement.
- Parameters:
event (
MeasureEvent) – Context about the measurement operation.- Returns:
Zero or more noise operations to inject.
- Return type:
- graphqomb.noise_model.noise_op_to_stim(op)[source]¶
Convert a NoiseOp into a Stim instruction line and record delta.
- Parameters:
op (
NoiseOp) – The noise operation to convert.- Returns:
A tuple of
(stim_instruction, record_delta)wherestim_instructionis a single line of Stim code andrecord_deltais the number of measurement records added.- Return type:
- Raises:
TypeError – If
opis not a recognized NoiseOp type.
Examples
>>> op = PauliChannel1(px=0.01, py=0.02, pz=0.03, targets=[0]) >>> noise_op_to_stim(op) ('PAULI_CHANNEL_1(0.01,0.02,0.03) 0', 0)
- class graphqomb.noise_model.DepolarizingNoiseModel[source]¶
Depolarizing noise after single and two-qubit gates.
This model adds depolarizing noise after qubit preparation (RX) and entanglement (CZ) operations.
- Parameters:
Examples
>>> from graphqomb.noise_model import DepolarizingNoiseModel >>> model = DepolarizingNoiseModel(p1=0.001, p2=0.01) >>> # Use with stim_compile: >>> # stim_compile(pattern, noise_models=[model])
- on_prepare(event)[source]¶
Add single-qubit depolarizing noise after preparation.
- Returns:
A tuple containing DEPOLARIZE1 instruction, or empty if p1 <= 0.
- Return type:
- class graphqomb.noise_model.MeasurementFlipNoiseModel[source]¶
Measurement bit-flip noise using Stim’s built-in measurement error.
This model produces MX(p), MY(p), MZ(p) instead of MX, MY, MZ, which adds measurement flip error with probability p.
- Parameters:
p (
float) – Probability of measurement result flip.
Examples
>>> from graphqomb.noise_model import MeasurementFlipNoiseModel >>> model = MeasurementFlipNoiseModel(p=0.001) >>> # Use with stim_compile: >>> # stim_compile(pattern, noise_models=[model])