Complete API reference for the QENS SDK, organized by module.
The top-level qens package re-exports the most commonly used names for convenience:
Types: PauliOp, Outcome, PauliString, Syndrome, Coordinate
Circuit: Circuit, Gate, Moment
Codes: QECCode, RepetitionCode, SurfaceCode, ColorCode
Noise: ErrorModel, BitFlipNoise, PhaseFlipNoise, DepolarizingNoise, PauliYNoise, ReadoutNoise, OverRotationNoise, CrosstalkNoise, CorrelatedNoise, LeakageNoise, CombinedNoise
Decoders: Decoder, DecoderResult, LookupTableDecoder, MatchingDecoder, UnionFindDecoder
Simulation: simulate, ThresholdExperiment, Simulator, SimulationResult, ThresholdResult, PauliFrameSimulator
Visualization: draw_circuit, draw_lattice, draw_decoding_graph, plot_threshold, plot_logical_rates, plot_histogram
Low-level type definitions used throughout the SDK.
Enum representing single-qubit Pauli operators.
Members:
PauliOp.I-- IdentityPauliOp.X-- Pauli X (bit flip)PauliOp.Y-- Pauli YPauliOp.Z-- Pauli Z (phase flip)
Enum representing measurement outcomes.
Members:
Outcome.ZERO-- Measured |0>Outcome.ONE-- Measured |1>
PauliString = tuple[PauliOp, ...]An ordered tuple of Pauli operators, one per qubit.
Syndrome = tuple[int, ...]A tuple of integers (0 or 1) representing stabilizer measurement outcomes.
KrausMatrix = np.ndarrayA 2D complex NumPy array representing a single Kraus operator.
QubitIndex = intNon-negative integer identifying a qubit in a circuit or code.
Coordinate = tuple[float, float]A 2D coordinate pair used for qubit layout and visualization.
Circuit construction with a fluent API.
Represents a single quantum gate operation.
Properties:
name: str-- Gate name (e.g., "H", "CX", "M")qubits: tuple[int, ...]-- Qubit indices this gate acts onparams: dict[str, float] | None-- Optional gate parameters (e.g., rotation angles)
Methods:
is_measurement() -> bool-- True if this is a measurement gateis_two_qubit() -> bool-- True if the gate acts on two or more qubits
A collection of gates that can be executed in parallel (no overlapping qubits).
Properties:
gates: list[Gate]-- The gates in this momentqubits_used: set[int]-- All qubit indices involved in this moment
Methods:
add_gate(gate: Gate) -> None-- Add a gate; raises ValueError on qubit conflicthas_measurements() -> bool-- True if any gate in the moment is a measurement
Builder for quantum circuits. All gate methods return self for chaining.
Properties:
num_qubits: int-- Number of qubits in the circuitmoments: list[Moment]-- Ordered list of momentsdepth: int-- Number of moments in the circuit
Long-form gate methods (recommended for readability):
hadamard(qubit: int) -> Circuit-- Append Hadamard gatepauli_x(qubit: int) -> Circuit-- Append Pauli-X (bit flip) gatepauli_y(qubit: int) -> Circuit-- Append Pauli-Y gatepauli_z(qubit: int) -> Circuit-- Append Pauli-Z (phase flip) gatecnot(control: int, target: int) -> Circuit-- Append CNOT gatecontrolled_z(q0: int, q1: int) -> Circuit-- Append controlled-Z gatemeasure(qubit: int) -> Circuit-- Append measurementreset(qubit: int) -> Circuit-- Append qubit resetbarrier() -> Circuit-- Insert a scheduling barrier (empty time step)
Short aliases (delegate to the long-form methods above):
h(qubit)-- Alias forhadamard()x(qubit)-- Alias forpauli_x()z(qubit)-- Alias forpauli_z()cx(control, target)-- Alias forcnot()cz(q0, q1)-- Alias forcontrolled_z()
Other methods:
append_gate(gate: Gate) -> Circuit-- Append an arbitrary gateappend_moment(moment: Moment) -> Circuit-- Append a full moment__add__(other: Circuit) -> Circuit-- Concatenate two circuits__len__() -> int-- Number of moments
Kraus-operator representation of a quantum noise channel.
Represents a completely positive trace-preserving (CPTP) map.
Properties:
kraus_ops: list[KrausMatrix]-- List of Kraus operator matricesnum_kraus: int-- Number of Kraus operators
Methods:
validate() -> bool-- Check that Kraus operators sum to identity (CPTP condition)probabilities() -> list[float]-- Return the probability of each Kraus branch (trace of K^dag K)sample(rng: np.random.Generator) -> int-- Sample a Kraus branch index according to probabilities
Generic plugin registry.
A typed dictionary mapping string names to classes.
Methods:
register(name: str, cls: type[T]) -> None-- Register a class. RaisesValueErroron duplicate name.get(name: str) -> type[T]-- Retrieve a class by name. RaisesKeyErrorif not found.list_registered() -> list[str]-- Return all registered names.__contains__(name: str) -> bool-- Check if a name is registered.
Qubit metadata.
Enum for qubit roles in a QEC code.
Members:
QubitRole.DATA-- Data qubitQubitRole.ANCILLA-- Ancilla (syndrome measurement) qubit
Dataclass representing a qubit with metadata.
Fields:
index: int-- Qubit index in the circuitrole: QubitRole-- Whether this is a data or ancilla qubitcoordinate: Coordinate | None-- Optional 2D position for visualization
Error models for simulating quantum noise.
Base class for all error models.
Abstract Methods:
generate_errors(num_qubits: int, target_qubits: list[int], rng: np.random.Generator) -> PauliString-- Generate a random Pauli error
Optional Methods:
to_channel() -> NoiseChannel-- Convert to Kraus representationapplies_to(gate: Gate) -> bool-- Whether this model applies to a given gate (default: True)
Dunder Methods:
__add__(other: NoiseModel) -> CombinedNoise-- Compose two noise models with+. Automatically flattens nestedCombinedNoisesoa + b + cis a single flat list.__repr__() -> str-- Human-readable representation
Applies X with probability p independently to each affected qubit.
Parameters:
p: float-- Bit-flip probability per qubit (0 <= p <= 1)
Applies Z with probability p independently to each affected qubit.
Parameters:
p: float-- Phase-flip probability per qubit (0 <= p <= 1)
Applies X, Y, or Z each with probability p/3 independently to each affected qubit.
Parameters:
p: float-- Total depolarizing probability per qubit (0 <= p <= 1)
Applies Y with probability p independently to each affected qubit.
Parameters:
p: float-- Y-error probability per qubit (0 <= p <= 1)
Flips measurement outcomes asymmetrically.
Parameters:
p0: float-- Probability of flipping a 0 outcome to 1p1: float | None-- Probability of flipping a 1 outcome to 0 (defaults top0if None)
Applies a small coherent rotation about a Pauli axis, modeled as a probabilistic Pauli error.
Parameters:
angle: float-- Rotation angle in radiansaxis: str-- Rotation axis: "X", "Y", or "Z"
Applies correlated errors on specified qubit pairs when either is involved in a gate.
Parameters:
p: float-- Crosstalk probabilityqubit_pairs: list[tuple[int, int]]-- Pairs of qubits subject to crosstalk
Applies a fixed multi-qubit Pauli error with probability p.
Parameters:
p: float-- Probability of the correlated error occurringpauli_string: PauliString-- The multi-qubit Pauli operator to apply
Models qubit leakage to non-computational states with stateful tracking.
Parameters:
p_leak: float-- Probability of leaking out of the computational subspacep_return: float-- Probability of returning from a leaked state per round
Stacks multiple error models, applying each in sequence.
Parameters:
models: list[ErrorModel]-- Ordered list of error models to compose
Methods:
generate_errors(num_qubits: int, target_qubits: list[int], rng: np.random.Generator) -> PauliString-- Apply all models and multiply the resulting Pauli strings
Module-level registry for error models. See the Registry API for usage.
Quantum error-correcting codes.
Dataclass representing a stabilizer generator.
Fields:
name: str-- Human-readable stabilizer name (e.g., "S0")pauli_string: PauliString-- The Pauli operator for this stabilizer
Dataclass representing a logical operator of the code.
Fields:
name: str-- Logical operator name (e.g., "X_L", "Z_L")pauli_string: PauliString-- The Pauli operator
Graph structure representing the code's qubit layout.
Properties:
nodes: list[LatticeNode]-- All nodes in the latticeedges: list[LatticeEdge]-- All edges in the lattice
Dataclass for a node in a code lattice.
Fields:
index: int-- Node indexcoordinate: Coordinate-- 2D positionrole: QubitRole-- Data or ancilla
Dataclass for an edge in a code lattice.
Fields:
source: int-- Source node indextarget: int-- Target node indexweight: float-- Edge weight (default 1.0)
Base class for quantum error-correcting codes.
Abstract Properties:
name: str-- Code namenum_data_qubits: int-- Number of data qubitsnum_ancilla_qubits: int-- Number of ancilla qubitscode_distance: int-- Code distance
Computed Properties:
num_qubits: int-- Total qubits (data + ancilla)
Abstract Methods:
stabilizer_generators() -> list[Stabilizer]-- Return the stabilizer generatorslogical_operators() -> list[LogicalOperator]-- Return the logical operatorscheck_matrix() -> np.ndarray-- Return the parity check matrix (GF(2))syndrome_circuit(rounds: int = 1) -> Circuit-- Build the syndrome extraction circuitqubit_coordinates() -> dict[int, Coordinate]-- Return 2D positions for all qubits
Provided Methods:
compute_syndrome(error: PauliString) -> Syndrome-- Compute the syndrome for a given erroris_logical_error(correction: PauliString) -> bool-- Check if a correction results in a logical errorsimulate(noise: NoiseModel, decoder: Decoder, shots: int = 10_000, *, seed: int | None = None) -> SimulationResult-- Run a complete simulation directly from the code instance. Equivalent to calling the top-levelsimulate()function.
1D repetition code for bit-flip errors.
Parameters:
distance: int-- Code distance (>= 2)
Rotated surface code.
Parameters:
distance: int-- Code distance (odd, >= 3)
Color code on a 2D lattice.
Parameters:
distance: int-- Code distance (odd, >= 3)lattice_type: str-- Lattice geometry:"4.8.8"or"6.6.6"
Module-level registry for QEC codes.
Decoding algorithms for QEC.
Dataclass returned by all decoders.
Fields:
correction: PauliString-- The inferred Pauli correction to applyconfidence: float-- Decoder confidence (0.0 to 1.0)
Base class for decoders.
Constructor:
Decoder(code: QECCode)-- Initialize with the code to decode
Properties:
code: QECCode-- The associated QEC code
Methods:
decode(syndrome: Syndrome) -> DecoderResult-- Decode a syndrome into a correction. Automatically callsprepare()on first invocation.prepare() -> None-- Pre-build decoding structures (tables, graphs). Called automatically bydecode()— you rarely need to call this yourself.build_decoding_graph() -> Lattice-- Build a graph for visualization (optional)
Subclass hook:
_decode(syndrome: Syndrome) -> DecoderResult-- Implement actual decoding logic. Called bydecode()after auto-prepare.
Exhaustive lookup table decoder. Enumerates all single-qubit errors and caches the syndrome-to-correction map. Optimal for small codes.
Greedy minimum-weight perfect matching decoder.
Almost-linear-time decoder using the union-find data structure.
Module-level registry for decoders.
Simulation engines and experiment runners.
simulate(code: QECCode, noise: NoiseModel, decoder: Decoder, shots: int = 10_000, *, seed: int | None = None) -> SimulationResult
Recommended entry point. Run a complete error-correction simulation in one call. Creates a Simulator, automatically prepares the decoder, runs Monte Carlo sampling, and returns the result.
from qens import simulate, SurfaceCode, DepolarizingNoise, MatchingDecoder
result = simulate(SurfaceCode(3), DepolarizingNoise(error_rate=0.01), MatchingDecoder(SurfaceCode(3)), shots=10_000)Parameters:
code: QECCode-- The quantum error-correcting code to simulatenoise: NoiseModel-- The noise model to applydecoder: Decoder-- The decoder to use for error correctionshots: int-- Number of Monte Carlo shots (default 10,000)seed: int | None-- Optional RNG seed for reproducibility
SimulationResult(num_shots: int, num_errors: int, logical_error_rate: float, raw_syndromes: list[Syndrome] | None = None)
Dataclass holding the outcome of a simulation run.
Fields:
num_shots: int-- Number of Monte Carlo shotsnum_errors: int-- Number of detected logical errorslogical_error_rate: float-- Fraction of shots that resulted in a logical errorraw_syndromes: list[Syndrome] | None-- Optional list of raw syndrome measurements
ThresholdResult(physical_rates: list[float], logical_rates: dict[int, list[float]], threshold_estimate: float | None)
Dataclass holding the outcome of a threshold experiment.
Fields:
physical_rates: list[float]-- Physical error rates sweptlogical_rates: dict[int, list[float]]-- Logical error rates keyed by code distancethreshold_estimate: float | None-- Estimated threshold value (None if curves do not cross)
Monte Carlo sampler that injects errors, measures syndromes, decodes, and checks for logical errors.
Parameters:
code: QECCode-- The QEC codenoise_model: ErrorModel-- The error model to sample fromdecoder: Decoder-- The decoder to useseed: int | None-- Optional RNG seed for reproducibility
Methods:
run(num_shots: int) -> SimulationResult-- Runnum_shotsMonte Carlo trials
ThresholdExperiment(code_class: type[QECCode], distances: list[int], physical_rates: list[float], noise_model_class: type[ErrorModel], decoder_class: type[Decoder], num_shots: int = 10000, seed: int | None = None)
Sweeps physical error rates across multiple code distances to estimate the error-correction threshold.
Parameters:
code_class: type[QECCode]-- Code class to instantiate at each distancedistances: list[int]-- List of code distances to testphysical_rates: list[float]-- Physical error rates to sweepnoise_model_class: type[ErrorModel]-- Error model class (instantiated with each rate)decoder_class: type[Decoder]-- Decoder classnum_shots: int-- Shots per (distance, rate) pairseed: int | None-- Optional RNG seed
Methods:
run() -> ThresholdResult-- Execute the full sweep and return results
PauliFrameSimulator(circuit: Circuit, noise_model: ErrorModel | None = None, seed: int | None = None)
Efficient Clifford circuit simulator using the Pauli frame formalism.
Parameters:
circuit: Circuit-- The circuit to simulatenoise_model: ErrorModel | None-- Optional noise modelseed: int | None-- Optional RNG seed
Methods:
run(num_shots: int) -> list[PauliString]-- Simulate the circuit and return the final Pauli frame for each shot
Visualization functions and infrastructure.
FigureHandle(fig: matplotlib.figure.Figure, axes: matplotlib.axes.Axes | list[matplotlib.axes.Axes])
Wrapper around matplotlib figure objects returned by all visualization functions.
Fields:
fig: Figure-- The matplotlib Figureaxes: Axes | list[Axes]-- The axes (single or list)
Configurable color palette and sizing for all QENS visualizations. Frozen dataclass.
Key fields:
data_qubit_color: str-- Fill color for data qubits ("#4A90D9")ancilla_x_color: str-- Fill color for X-type ancilla markers ("#E74C3C")ancilla_z_color: str-- Fill color for Z-type ancilla markers ("#2ECC71")error_x_color / error_y_color / error_z_color: str-- Colors for X, Y, Z errorssyndrome_active: str-- Color for active syndrome bits ("#E74C3C")color_code_plaquette_colors: tuple[str, str, str]-- 3-color palette for color codes (("tomato", "yellowgreen", "steelblue"))background_color: str-- Figure background ("#FFFFFF")text_color: str-- Text label color ("#2C3E50")
See the Visualization Guide for the full field list.
draw_circuit(circuit: Circuit, errors: PauliString | None = None, style: QENSStyle | None = None, **kwargs) -> FigureHandle
Draw a quantum circuit diagram with optional error annotations.
Parameters:
circuit: Circuit-- The circuit to drawerrors: PauliString | None-- Optional error overlaystyle: QENSStyle | None-- Optional style override**kwargs-- Passed to matplotlib (e.g.,figsize)
draw_lattice(code: QECCode, syndrome: Syndrome | None = None, errors: PauliString | None = None, style: QENSStyle | None = None, **kwargs) -> FigureHandle
Draw the code lattice with optional syndrome and error overlays.
Parameters:
code: QECCode-- The code whose lattice to drawsyndrome: Syndrome | None-- Optional syndrome to highlighterrors: PauliString | None-- Optional errors to highlightstyle: QENSStyle | None-- Optional style override**kwargs-- Passed to matplotlib
draw_decoding_graph(decoder: Decoder, syndrome: Syndrome | None = None, matching: list[tuple[int, int]] | None = None, style: QENSStyle | None = None, **kwargs) -> FigureHandle
Draw the decoding graph with optional matching edges.
Parameters:
decoder: Decoder-- The decoder (must supportbuild_decoding_graph())syndrome: Syndrome | None-- Optional syndrome to highlightmatching: list[tuple[int, int]] | None-- Optional matched pairs to drawstyle: QENSStyle | None-- Optional style override**kwargs-- Passed to matplotlib
Plot logical error rate vs. physical error rate for multiple code distances (standard QEC threshold plot).
Parameters:
result: ThresholdResult-- Threshold experiment resultsstyle: QENSStyle | None-- Optional style override**kwargs-- Passed to matplotlib
plot_logical_rates(results: dict[str, float], style: QENSStyle | None = None, **kwargs) -> FigureHandle
Bar chart of logical error rates.
Parameters:
results: dict[str, float]-- Mapping of labels to logical error ratesstyle: QENSStyle | None-- Optional style override**kwargs-- Passed to matplotlib
plot_histogram(data: list[float] | np.ndarray, bins: int = 50, style: QENSStyle | None = None, **kwargs) -> FigureHandle
General-purpose histogram plot.
Parameters:
data: list[float] | np.ndarray-- Data to plotbins: int-- Number of binsstyle: QENSStyle | None-- Optional style override**kwargs-- Passed to matplotlib
Return the current default style instance.
Module-level registry for visualizers.
Utility functions for Pauli algebra and linear algebra over GF(2).
Create a seeded NumPy random generator. If seed is None, uses system entropy.
Multiply two single-qubit Pauli operators (ignoring phase).
Check whether two single-qubit Pauli operators commute.
Element-wise multiply two Pauli strings (ignoring global phase).
Compute the symplectic inner product of two Pauli strings. Returns 0 if they commute, 1 if they anticommute.
Sparse matrix over GF(2) with row reduction and kernel computation.
Parameters:
data: np.ndarray-- 2D array of 0s and 1s (dtype uint8)
Methods:
row_reduce() -> GF2Matrix-- Return the row-echelon formkernel() -> list[np.ndarray]-- Compute the null space over GF(2)rank() -> int-- Return the matrix rank over GF(2)__matmul__(other: np.ndarray) -> np.ndarray-- Matrix multiplication mod 2