Noise

class NoiseModel(*args, **kwargs)

Python wrapper around C++ NoiseModel enabling multiprocessing and pickle serialization.

compute_damping(self, pauli_string: str) → float

Damping factor for a Pauli string observable from ONE application of the configured Pauli channels.

Exact only when the channel acts once, immediately before measurement; for a circuit with noise after every gate it underestimates the noise. Only the all-gates Pauli layer contributes.

compute_damping_covers_model(self) → bool

Return True iff compute_damping() captures every layer that affects Pauli expectations. False for thermal, T1, gate-type Pauli, 2Q depolarizing, coherent, correlated and crosstalk.

get_t1_2q(self, qubit: int) → float

Get T1 decay probability for 2Q gates (falls back to get_t1 if not set).

get_t1_for_gate(self, qubit: int, is_2q: bool) → float

Get gate-type-aware T1: returns t1_2q if is_2q and set, else t1.

has_1q_gate_noise(self) → bool

Return True if any 1Q gate-specific noise has been set.

has_2q_gate_noise(self) → bool

Return True if any 2Q gate-specific noise has been set.

has_additional_quantum_channels(self) → bool

Return True if a channel that ONLY an exact density-matrix/MPO backend can run is configured: generalized amplitude damping, correlated phase flips or custom Kraus maps. Phase damping and thermal relaxation are excluded – both have an exact or well-defined stochastic realization on sampled backends.

has_any(self) → bool

Return True if any noise of any type has been configured.

has_any_2q_depolarizing(self) → bool

Return True if any two-qubit depolarizing has been set.

has_coherent(self) → bool

Return True if any coherent noise parameters have been set.

has_correlated(self) → bool

Return True if any correlated noise parameters have been set.

has_crosstalk(self) → bool

Return True if any crosstalk couplings have been set.

has_idle_noise(self) → bool

Return True if any idle noise parameters have been set.

has_readout_error(self) → bool

Return True if any readout error parameters have been set.

has_t1(self) → bool

Return True if any T1 parameters have been set.

has_thermal_in_sampled_overdephasing_regime(self) → bool

Return True if any thermal-relaxation layer has T2 > T1, where the sampled reset+Z mixture over-dephases. Use density-matrix or MPO execution in that regime.

has_thermal_relaxation(self) → bool

Return True if any T1/T2 thermal relaxation has been set.

requires_exact_quantum_channels(self) → bool

Return True if sampled injection cannot faithfully realize this model (exact-only Kraus maps, or T2 > T1 requiring approximation on sampled paths).

set_1_over_f_noise(self, qubit: int, total_power: float, f_min: float, f_max: float, num_bands: int, gate_time: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Synthesize 1/f noise spectrum via logarithmically spaced OU fluctuator bands.

set_1q_gate_depolarizing(self, qubit: int, p: float) → None

Set depolarizing noise applied only after single-qubit gates.

This is separate from set_depolarizing() which applies after ALL gates.

Example

nm.set_1q_gate_depolarizing(0, 2.3e-4)
set_2q_depolarizing(self, q1: int, q2: int, p: float) → None

Set a correlated two-qubit depolarizing channel applied after every two-qubit gate on the pair (q1, q2).

Channel: Λ(ρ) = (1-p)ρ + p/15 · Σ PρP† (15 non-identity two-qubit Paulis), the same as Stim’s DEPOLARIZE2(p). Applied ONLY after 2Q gates, separate from per-qubit noise. Not to be confused with set_2q_gate_depolarizing(qubit, p), which applies independent single-qubit depolarizing to each qubit after its 2Q gates.

Example

nm.set_2q_depolarizing(0, 1, 1.8e-3)
set_2q_gate_depolarizing(self, qubit: int, p: float) → None

Set single-qubit depolarizing noise (DEPOLARIZE1(p)) applied to this qubit only after two-qubit gates involving it.

Each qubit of the gate gets an independent channel, so this is NOT Stim’s DEPOLARIZE2(p); for that use set_2q_depolarizing(q1, q2, p).

Example

nm.set_2q_gate_depolarizing(0, 1.8e-3)
set_all_1q_gate_depolarizing(self, num_qubits: int, p: float) → None

Set uniform 1Q gate depolarizing on qubits [0, num_qubits).

set_all_2q_gate_depolarizing(self, num_qubits: int, p: float) → None

Set uniform single-qubit depolarizing after 2Q gates on qubits [0, num_qubits). See set_2q_gate_depolarizing; for Stim’s DEPOLARIZE2 use set_2q_depolarizing on each coupled pair.

set_all_coherent_dephasing(self, num_qubits: int, p: float) → None

Set uniform coherent dephasing on qubits [0, num_qubits).

set_all_coherent_depolarizing(self, num_qubits: int, p: float) → None

Set uniform coherent depolarizing noise on qubits [0, num_qubits).

set_all_correlated_from_power(self, num_qubits: int, power: float, alpha: float, gate_time: float, after_1q: bool = True, after_2q: bool = True) → None

Set correlated noise from total noise power.

P_tot = N * sigma^2 * pi * alpha * gate_time Derives sigma from P_tot and sets OU noise on all qubits.

Parameters:
  • num_qubits – Number of qubits N.

  • power – Total noise power P_tot.

  • alpha – Correlation time in gate-time units.

  • gate_time – Gate duration in seconds.

  • after_1q – If True (default), inject after 1Q gates too.

  • after_2q – If True (default), inject after 2Q gates too.

Example

nm.set_all_correlated_from_power(20, power=1e-3, alpha=0.5, gate_time=100e-9)
set_all_correlated_ou(self, num_qubits: int, sigma: float, alpha: float, gate_time: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Set identical OU correlated noise on qubits [0, num_qubits).

Example

nm.set_all_correlated_ou(20, sigma=15.0, alpha=0.5, gate_time=100e-9)
set_all_dephasing(self, num_qubits: int, p: float) → None

Add uniform dephasing noise to all qubits [0, num_qubits).

set_all_depolarizing(self, num_qubits: int, p: float) → None

Add uniform depolarizing noise to all qubits [0, num_qubits).

set_all_multi_correlated_ou(self, num_qubits: int, bands: collections.abc.Sequence[tuple[float, float]], gate_time: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Uniform multi-OU setter across qubits 0..num_qubits-1.

set_all_readout_error(self, num_qubits: int, p_error: float) → None

Set uniform symmetric readout error on qubits [0, num_qubits).

Applied per measured qubit when the measurement writes its classical bit.

set_all_t1(self, num_qubits: int, gamma: float) → None

Set uniform T1 decay probability on qubits [0, num_qubits).

set_bit_flip(self, qubit: int, p: float) → None

Add bit-flip (X) noise.

set_coherent_bit_flip(self, qubit: int, p: float) → None

Set coherent bit-flip noise: Rx rotation from probability p. Replaces the X angle only, so it composes with other axes.

set_coherent_dephasing(self, qubit: int, p: float) → None

Set coherent dephasing noise: Rz rotation from probability p. Replaces the Z angle only, so it composes with other axes.

set_coherent_depolarizing(self, qubit: int, p: float) → None

Set isotropic coherent noise calibrated to DEPOLARIZE1(p).

After every gate on this qubit, rotates by ε = 2·arcsin(√p) about a body diagonal (±1, ±1, ±1)/√3 of the Bloch sphere, with the signs drawn once per qubit per noise realization. The Pauli twirl of that rotation is exactly DEPOLARIZE1(p), so it has the same infidelity and affects X-, Y- and Z-basis measurements. Composes with set_coherent_bit_flip/dephasing/rotation.

set_coherent_rotation(self, qubit: int, rx: float, ry: float, rz: float) → None

Set per-qubit coherent noise as rotation angles (radians). After every gate on this qubit, Rx(±rx), Ry(±ry), Rz(±rz) rotations are applied, with each ± sign drawn once per qubit per noise realization. Replaces the X, Y and Z angles only; set_coherent_depolarizing is kept.

set_coherent_strength(self, num_qubits: int, p: float) → None

Convenience: set uniform isotropic coherent noise on qubits [0, num_qubits). Equivalent to set_all_coherent_depolarizing(n, p).

set_correlated_ar1(self, qubit: int, phi: float, sigma_eta: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Set AR(1) correlated dephasing on a qubit.

After every gate, Rz(y[k]) is injected where:

y[k] = phi * y[k-1] + eta[k], eta ~ N(0, sigma_eta^2)

Parameters:
  • qubit – Qubit index.

  • phi – AR(1) autoregressive coefficient.

  • sigma_eta – Driving noise standard deviation.

  • after_1q – If True (default), inject after 1Q gates.

  • after_2q – If True (default), inject after 2Q gates.

  • stationary_init – If True (default), sample step 0 from stationary equilibrium.

Example

nm.set_correlated_ar1(0, phi=0.135, sigma_eta=2.35e-3)
set_correlated_ou(self, qubit: int, sigma: float, alpha: float, gate_time: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Set correlated noise from Ornstein-Uhlenbeck parameters.

OU: dX = -theta*X*dt + sigma*dW, discretized as AR(1).

theta = 1/(alpha * gate_time) phi = exp(-theta * gate_time) sigma_eta^2 = (sigma^2 / 2*theta) * (1 - phi^2)

Parameters:
  • qubit – Qubit index.

  • sigma – OU diffusion coefficient (noise strength).

  • alpha – Correlation time in gate-time units.

  • gate_time – Gate duration in seconds.

  • after_1q – If True (default), inject after 1Q gates.

  • after_2q – If True (default), inject after 2Q gates.

  • stationary_init – If True (default), sample step 0 from stationary equilibrium.

Example

nm.set_correlated_ou(0, sigma=15.0, alpha=0.5, gate_time=100e-9)
set_correlated_ou_band(self, qubit: int, sigma: float, alpha: float, gate_time: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Append an OU fluctuator band to a qubit’s band list, keeping the bands already set on it.

set_correlated_phase_flip(self, q1: int, q2: int, probability: float, correlation: float = 1.0) → None

Set a correlated two-qubit phase-flip channel after gates on the pair. correlation=0 is independent; correlation=1 is II/ZZ.

set_crosstalk(self, q1: int, q2: int, strength: float) → None

Set spectator-Z crosstalk between two qubits. After a gate on q1, Rz(strength) is applied on q2, and vice versa. This is not a genuine two-qubit ZZ interaction.

set_dephasing(self, qubit: int, p: float) → None

Add pure dephasing (Z) noise.

set_depolarizing(self, qubit: int, p: float) → None

Add symmetric depolarizing noise (px=py=pz=p/3).

set_generalized_amplitude_damping(self, qubit: int, gamma: float, excited_population: float) → None

Set finite-temperature generalized amplitude damping after each gate on a qubit. Requires an exact density-matrix or MPO backend.

set_idle_noise(self, qubit: int, t1: float, t2: float, excited_population: float = 0.0, detuning_hz: float = 0.0) → None

Configure idle dephasing/relaxation and detuning for delay instructions.

Parameters:
  • qubit – Qubit index.

  • t1 – T1 relaxation time in seconds.

  • t2 – T2 dephasing time in seconds (T2 <= 2*T1).

  • excited_population – Equilibrium |1> state population (default 0.0).

  • detuning_hz – Coherent detuning frequency in Hz (default 0.0).

set_kraus_channel(self, targets: collections.abc.Sequence[int], kraus_operators: collections.abc.Sequence[collections.abc.Sequence[collections.abc.Sequence[complex]]]) → None

Attach an arbitrary one- or two-qubit CPTP Kraus channel after gates on the same targets. Matrices are nested row-major lists; completeness (sum_k E_k^dag E_k = I) is validated.

BASIS ORDER for two-qubit operators: targets[0] is the LEAST significant bit of the 4x4 matrix index, targets[1] the most significant. So an operator acting as A on targets[0] and B on targets[1] must be supplied as the Kronecker product B (x) A. Getting this backwards silently transposes the channel onto the wrong qubit.

Example

# X on targets[0], identity on targets[1]
nm.set_kraus_channel([0, 2], [[[0,1,0,0],[1,0,0,0],[0,0,0,1],[0,0,1,0]]])
set_multi_correlated_ou(self, qubit: int, bands: collections.abc.Sequence[tuple[float, float]], gate_time: float, after_1q: bool = True, after_2q: bool = True, stationary_init: bool = True) → None

Batch multi-OU setter: clears existing bands and populates from a list of (sigma, alpha) pairs.

set_phase_damping(self, qubit: int, gamma: float) → None

Set phase damping with coherence multiplier sqrt(1-gamma).

Phase damping and the stochastic phase flip are the same channel (sqrt(1-gamma) = 1-2p), so this is realized exactly on every backend, not only density-matrix/MPO.

set_phase_damping_from_time(self, qubit: int, gate_time_s: float, t_phi_s: float) → None

Set pure phase damping so coherence decays as exp(-gate_time/T_phi). Realized exactly on every backend.

set_qubit_noise(self, qubit: int, px: float, py: float, pz: float) → None

Add Pauli channel: Λ(ρ) = (1-px-py-pz)ρ + px·XρX + py·YρY + pz·ZρZ

set_readout_error(self, qubit: int, p_meas1_prep0: float, p_meas0_prep1: float) → None

Set asymmetric readout error on a qubit.

Applied when a measurement of this qubit writes its classical bit, whatever bit index it targets, so mid-circuit and repeated measurements are covered and classically-conditioned operations downstream observe the noisy outcome.

Parameters:
  • qubit – Qubit index.

  • p_meas1_prep0 – P(measure 1 | state was 0) — false positive.

  • p_meas0_prep1 – P(measure 0 | state was 1) — false negative.

Example

nm.set_readout_error(0, 0.003, 0.06)
set_readout_error_symmetric(self, qubit: int, p_error: float) → None

Set symmetric readout error (same rate for both directions).

Applied per measured qubit when the measurement writes its classical bit.

Example

nm.set_readout_error_symmetric(0, 0.01)
set_t1(self, qubit: int, gamma: float) → None

Set per-gate T1 decay probability. Density-matrix/MPO execution uses exact amplitude damping; pure-state execution retains the legacy sampled-reset approximation.

set_t1_2q(self, qubit: int, gamma: float) → None

Set T1 decay probability applied only after two-qubit gates. When set, 2Q gates use this gamma instead of the ‘all gates’ value.

set_t1_2q_from_time(self, qubit: int, gate_time_s: float, t1_time_s: float) → None

Set T1 for 2Q gates from physical time constants. gamma = 1 - exp(-gate_time / T1).

Example

nm.set_t1_2q_from_time(0, gate_time_s=40e-9, t1_time_s=100e-6)
set_t1_from_time(self, qubit: int, gate_time_s: float, t1_time_s: float) → None

Set T1 from physical time constants. gamma = 1 - exp(-gate_time / T1).

Example

nm.set_t1_from_time(0, gate_time_s=30e-9, t1_time_s=100e-6)
set_thermal_relaxation(self, qubit: int, gate_time_s: float, t1_s: float, t2_s: float, excited_population: float = 0.0) → None

Set hardware-style T1/T2 thermal relaxation after each gate.

This is the preferred way to specify decoherence. Because T1 and T2 are given together, every backend reproduces the same coherence decay exp(-gate_time/T2): density-matrix/MPO use the exact CPTP channel, pure-state/MPS use the equivalent reset+Z mixture. Calling set_t1() and set_dephasing() separately cannot achieve that – the phase-flip probability that is correct for the sampled reset model under-dephases by exp(t/2*T1) per gate on the exact amplitude-damping path.

The physical constraint T2 <= 2*T1 is enforced.

set_thermal_relaxation_2q(self, qubit: int, gate_time_s: float, t1_s: float, t2_s: float, excited_population: float = 0.0) → None

Set T1/T2 thermal relaxation applied only after two-qubit gates, using the (longer) 2Q gate duration. When set, 2Q gates use this instead of the ‘all gates’ relaxation.

noisy_estimate(circuit: maestro.circuits.QuantumCircuit, observables: object, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig()) → dict
noisy_estimate(qasm_circuit: str, observables: object, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig()) → dict

Overloaded function.

  1. noisy_estimate(circuit: maestro.circuits.QuantumCircuit, observables: object, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig()) -> dict

Compute expectation values with single-layer analytical Pauli noise damping. Runs the noiseless simulation then applies the damping factor – zero simulation overhead compared to noiseless.

WARNING – this is a SINGLE-LAYER approximation, not an exact result. The damping factor is exact only for one Pauli layer applied immediately before measurement. A circuit that carries noise after every gate is not modelled: Pauli channels do not commute through non-Clifford gates, and the damping does not compound with the number of noisy layers acting on each qubit. The returned values therefore UNDERESTIMATE the noise, increasingly so with circuit depth.

Only the all-gates Pauli layer is modelled; a NoiseModel with any other layer (T1, thermal, coherent, correlated, gate-type or two-qubit noise) raises ValueError, see compute_damping_covers_model(). Readout error is ignored. Use noisy_estimate_montecarlo(), full_noise_estimate(), or noisy_execute() with a density-matrix or MPO method, when the magnitude of the noise matters.

  1. noisy_estimate(qasm_circuit: str, observables: object, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig()) -> dict

Compute expectation values from a QASM circuit with single-layer analytical Pauli noise damping. Zero simulation overhead.

WARNING – this is a SINGLE-LAYER approximation, not an exact result. The damping factor is exact only for one Pauli layer applied immediately before measurement. A circuit that carries noise after every gate is not modelled: Pauli channels do not commute through non-Clifford gates, and the damping does not compound with the number of noisy layers acting on each qubit. The returned values therefore UNDERESTIMATE the noise, increasingly so with circuit depth.

Only the all-gates Pauli layer is modelled; a NoiseModel with any other layer raises ValueError, see compute_damping_covers_model(). Use noisy_estimate_montecarlo(), full_noise_estimate(), or noisy_execute() with a density-matrix or MPO method, when the magnitude of the noise matters.

noisy_estimate_montecarlo(circuit: maestro.circuits.QuantumCircuit, observables: object, noise_model: maestro.NoiseModel, noise_realizations: int = 100, config: maestro.SimulatorConfig = SimulatorConfig(), noise_seed: int | None = None) → dict

Gate-by-gate Monte Carlo noisy estimation. Injects random Pauli errors after every gate and averages expectation values over noise_realizations independent samples. More accurate than analytical noisy_estimate for deep circuits. Coherent, correlated and crosstalk noise are not applied and raise ValueError; use full_noise_estimate for those.

noisy_execute(circuit: maestro.circuits.QuantumCircuit, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig(), shots: int = 1024, noise_realizations: int = 64, noise_seed: int | None = None) → dict

Execute with exact Pauli/T1 channels for density-matrix/MPO methods, or sampled trajectories for pure-state methods. Shots are distributed evenly across ‘noise_realizations’ batches. Coherent, correlated and crosstalk noise are not applied and raise ValueError; use full_noise_execute for those.

coherent_estimate(circuit: maestro.circuits.QuantumCircuit, observables: object, noise_model: maestro.NoiseModel, noise_realizations: int = 100, config: maestro.SimulatorConfig = SimulatorConfig(), noise_seed: int | None = None) → dict

Estimate expectation values with coherent noise (rotation errors). Injects systematic Rx/Ry/Rz rotations after every gate and averages expectation values over noise_realizations independent sign samples. Unlike Pauli noise, coherent noise preserves phase coherence and does not commute with the circuit — it can model systematic calibration errors.

Example

nm = maestro.NoiseModel()
nm.set_coherent_strength(n_qubits, 0.001)
result = maestro.coherent_estimate(qc, ['ZZ', 'XX'], nm)
coherent_execute(circuit: maestro.circuits.QuantumCircuit, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig(), shots: int = 1024, noise_realizations: int = 64, noise_seed: int | None = None) → dict

Execute a circuit with sampled coherent over/under-rotation errors. After every gate, Rx/Ry/Rz rotations are injected with random ± signs. Each of ‘noise_realizations’ batches uses a different sign pattern. Supported by statevector, MPS, density-matrix, and MPO methods (not Stabilizer). Readout error is applied; any other non-coherent layer raises ValueError (use full_noise_execute).

Example

nm = maestro.NoiseModel()
nm.set_all_coherent_depolarizing(n_qubits, 0.001)
result = maestro.coherent_execute(qc, nm, shots=1000)
full_noise_estimate(circuit: maestro.circuits.QuantumCircuit, observables: object, noise_model: maestro.NoiseModel, noise_realizations: int = 100, config: maestro.SimulatorConfig = SimulatorConfig(), noise_seed: int | None = None) → dict

Estimate expectation values with combined noise (coherent + crosstalk + T1 + Pauli). All configured noise layers are applied per gate.

Example

nm = maestro.NoiseModel()
nm.set_all_coherent_depolarizing(n, 0.001)
nm.set_crosstalk(0, 1, 0.005)
nm.set_all_t1(n, 0.0003)
result = maestro.full_noise_estimate(qc, ['ZZ'], nm)
full_noise_execute(circuit: maestro.circuits.QuantumCircuit, noise_model: maestro.NoiseModel, config: maestro.SimulatorConfig = SimulatorConfig(), shots: int = 1024, noise_realizations: int = 64, noise_seed: int | None = None) → dict

Execute a circuit with combined noise (coherent + crosstalk + T1 + Pauli). Density-matrix/MPO methods apply Markovian T1 and Pauli layers as exact channels; trajectory-only layers remain sampled.

Example

nm = maestro.NoiseModel()
nm.set_all_coherent_depolarizing(n, 0.001)
nm.set_crosstalk(0, 1, 0.005)
nm.set_all_t1(n, 0.0003)
nm.set_all_depolarizing(n, 0.001)
result = maestro.full_noise_execute(qc, nm, shots=1000)
noisy_fidelity(circuit: maestro.circuits.QuantumCircuit, noise_model: maestro.NoiseModel, noise_realizations: int = 100, config: maestro.SimulatorConfig = SimulatorConfig(), noise_seed: int | None = None) → dict

Compute fidelity to the ideal unitary circuit state under noise.

Injects all configured noise types (correlated, coherent, crosstalk, T1, Pauli) and averages |<psi_ideal|psi_noisy>|^2 over noise realizations.

Returns dict with ‘fidelity’, ‘infidelity’, ‘std_error’, ‘time_taken’, ‘noise_realizations’.

Example

maestro.noisy_fidelity(qc, nm, noise_realizations=200)