Maestro 0.3.1
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
Sinter Integration (QEC Sampling)

Overview

Maestro provides seamless integration with Stim and Sinter, the standard Python benchmarking frameworks for quantum error correction (QEC).

Through maestro.sinter, you can execute Stim circuits and error correction benchmarks using Maestro's high-performance simulation engines (such as Matrix Product State or GPU-accelerated statevectors) as custom Sinter samplers.


Installation

To use the Sinter integration, install the optional sinter extra:

pip install "qoro-maestro[sinter]"

This installs sinter>=1.14 and stim>=1.14.


Core Classes and Functions

Class / Function Description
MaestroSinterSampler Implements sinter.Sampler. Passed to sinter.collect() as a custom sampler backend in custom_decoders.
MaestroCompiledSampler Implements sinter.CompiledSampler. Holds compiled circuit execution plans for repeated batch sampling or direct detection event generation.
translate_stim_to_maestro(circuit, qubit_order=None) Converts clean Stim circuits, extended gate strings or instruction tuples into (QuantumCircuit, empty NoiseModel, measurement_count).

Using with Sinter Collect

You can pass MaestroSinterSampler into sinter.collect via the custom_decoders dictionary:

import sinter
import stim
from maestro.sinter import MaestroSinterSampler
import maestro
# 1. Define a decoder prior separately from the clean execution circuit
prior = stim.Circuit.generated(
"surface_code:rotated_memory_z",
rounds=3,
distance=3,
after_clifford_depolarization=0.001,
)
surface_code_task = sinter.Task(
circuit=prior.without_noise(),
detector_error_model=prior.detector_error_model(decompose_errors=True),
json_metadata={"d": 3, "r": 3, "native_depolarizing": 0.001},
)
# 2. Configure Maestro backend options (e.g. Matrix Product State)
mps_config = maestro.SimulatorConfig()
mps_config.simulation_type = maestro.SimulationType.MatrixProductState
mps_config.max_bond_dimension = 64
# 3. Choose a native physical noise model, independently of the decoder prior.
# This is not an exact execution of the noise embedded in the prior.
noise = maestro.NoiseModel()
for q in range(prior.num_qubits):
noise.set_depolarizing(q, 0.001)
custom_decoders = {
"maestro": MaestroSinterSampler(config=mps_config, noise_model=noise, decoder="pymatching")
}
# 4. Collect error correction statistics
stats = sinter.collect(
num_workers=4,
max_shots=100_000,
max_errors=100,
tasks=[surface_code_task],
decoders=["maestro"],
custom_decoders=custom_decoders,
)
for sample in stats:
print(f"Errors: {sample.errors} / {sample.shots} (rate: {sample.errors / sample.shots:.4e})")

Clean-circuit execution contract

CLEAN_CIRCUIT_API_VERSION = 1 identifies translation with explicit initial resets, measurement/reset basis handling, classical record ordering and optional qubit allocation order. Measurement character k is classical bit k. Unsupported embedded noise, measurement inversion and record-controlled operations raise ValueError instead of silently changing their meaning. Native NoiseModel execution remains supported. The previous translation of instruction-local noise into a global hardware model was lossy and is removed. No embedded-noise sampler or coherent conversion policy is included here.

Counts must contain exactly the requested positive integer number of shots. Unexpected record widths and nonzero padding raise ValueError. A caller's SimulatorConfig is copied before sampling. Direct compiled samplers accept a seed (or config.seed); successive calls advance their random stream. An explicit per-call seed replays that call without consuming the stream. MaestroSinterSampler factories reject seed and config.seed because collect worker identities are unavailable for reproducible stream partitioning. Histograms do not preserve chronological shot order.

Direct Sampling with MaestroCompiledSampler

For direct shot sampling from Python without running a full Sinter task collection:

import stim
from maestro.sinter import MaestroCompiledSampler
import maestro
circuit = stim.Circuit("""
H 0
CX 0 1
M 0 1
DETECTOR(0, 0) rec[-1] rec[-2]
""")
sampler = MaestroCompiledSampler(circuit)
# Sample detection events and observable flips as numpy boolean arrays
det_samples, obs_samples = sampler.sample_detection_events(shots=1000)
print("Detection events shape:", det_samples.shape) # (1000, num_detectors)
print("Observable flips shape:", obs_samples.shape) # (1000, num_observables)