Noise Models

The qilisdk.noise module contains classes that represent different types of noise in quantum systems. These noise models can be integrated into quantum simulations to account for real-world imperfections and decoherence effects. A NoiseModel can contains various types of noise, each of which is then applied during simulation.

Note: For now, only the CudaBackend supports noise models.

Usage

Noise passes are added to a NoiseModel, which should then be included when executing a functional. For example, to add a global bit-flip noise to a circuit and then execute it with the CUDA backend:

from qilisdk.noise import NoiseModel, BitFlip
from qilisdk.digital import X, Circuit
from qilisdk.functionals import Sampling
from qilisdk.backends import CudaBackend

# Define the random circuit and sampler
c = Circuit(nqubits=2)
c.add(X(0))
c.add(X(1))
sampler = Sampling(c, nshots=1000)

# Define a simple noise model
nm = NoiseModel()

# Apply bit-flip noise with 50% probability to X gates on qubit 1
nm.add(BitFlip(probability=0.5), gate=X, qubits=[1])

# Execute with CUDA backend
backend_cuda = CudaBackend()
res = backend_cuda.execute(sampler, noise_model=nm)
print(res)

Summary of Noise Types

Some of the noise passes available in QiliSDK can be used for both digital circuits and analog schedules, while others are specific to one or the other:

Noise Type

Digital Circuits

Analog Schedules

KrausChannel

LindbladGenerator

PauliChannel

BitFlip

PhaseFlip

Depolarizing

AmplitudeDamping

Dephasing

GaussianPerturbation

OffsetPerturbation

ReadoutAssignment

Noise Config

By default, when converting between different noise representations (e.g. from Kraus operators to Lindblad generators), certain parameters are assumed, such as gate durations. These defaults can be modified using the NoiseConfig class:

from qilisdk.noise import NoiseModel, NoiseConfig
from qilisdk.digital import X

# Create a noise configuration, setting the X gate duration to 20 ns
conf = NoiseConfig()
conf.set_gate_duration[X] = 20e-9

# Define a simple noise model using this config
nm = NoiseModel(noise_config=conf)

Parameters and their defaults are as follows:

Parameter

Default Value

gate_times

1.0 for all gates

Noise Types

KrausChannel

KrausChannel is a base class for digital noise models that use Kraus operators to represent quantum noise channels. Kraus operators can be used to represent a generic quantum channel \(\mathcal{E}\) acting on a density matrix \(\rho\) as:

\[\mathcal{E}(\rho) = \sum_i K_i \rho K_i^\dagger,\]

where \(K_i\) are the Kraus operators satisfying the completeness relation \(\sum_i K_i^\dagger K_i = I\). The class is initialized with a list of Kraus operators given as QTensors.

from qilisdk.noise import KrausChannel
from qilisdk.core import QTensor
import numpy as np
p = 0.1
K1 = QTensor(np.array([[1, 0], [0, np.sqrt(1 - p)]]))
K2 = QTensor(np.array([[0, np.sqrt(p)], [0, 0]]))
kraus_noise = KrausChannel(operators=[K1, K2])

LindbladGenerator

LindbladGenerator is a base class for analog noise models that use the Lindblad master equation to represent quantum noise processes. The Lindblad master equation describes the time evolution of a density matrix \(\rho\) under both unitary dynamics and dissipative processes:

\[\frac{d\rho}{dt} = -i[H, \rho] + \sum_i \left( J_i \rho J_i^\dagger - \frac{1}{2} \{ J_i^\dagger J_i, \rho \} \right),\]

where \(H\) is the system Hamiltonian, and \(J_i\) are the jump operators representing different dissipation channels. The class is initialized with a list of jump operators given as QTensors and their corresponding rates (assumed to be 1 if not specified).

from qilisdk.noise import LindbladGenerator
from qilisdk.core import QTensor
import numpy as np
J1 = QTensor(np.array([[0, 1], [0, 0]]))
J2 = QTensor(np.array([[1, 0], [0, 0]]))
lindblad_noise = LindbladGenerator(jump_operators=[J1, J2], rates=[0.1, 0.2])

PauliChannel

PauliChannel is a base class for noise models that use Pauli operators. A Pauli channel applies the Pauli operators (I, X, Y, Z) with certain probabilities. The channel can be represented as:

\[\mathcal{E}(\rho) = p_I \rho + p_X X \rho X + p_Y Y \rho Y + p_Z Z \rho Z,\]

where \(p_I\), \(p_X\), \(p_Y\), and \(p_Z\) are the probabilities for applying the respective Pauli operators, satisfying \(p_I + p_X + p_Y + p_Z = 1\). This corresponds to Kraus operators:

\[K_0 = \sqrt{p_I} I, \quad K_1 = \sqrt{p_X} X, \quad K_2 = \sqrt{p_Y} Y, \quad K_3 = \sqrt{p_Z} Z,\]

Or jump operators:

\[J_1 = \sqrt{\gamma_X} X, \quad J_2 = \sqrt{\gamma_Y} Y, \quad J_3 = \sqrt{\gamma_Z} Z,\]

where \(\gamma_i\) are rates related to the probabilities.

from qilisdk.noise import PauliChannel
pauli_noise = PauliChannel(p_X=0.1, p_Y=0.1, p_Z=0.1)

BitFlip

BitFlip represents a bit-flip error model where each qubit has a certain probability of flipping its state from |0⟩ to |1⟩ or from |1⟩ to |0⟩. This corresponds to the following channel:

\[\mathcal{E}(\rho) = (1 - p) \rho + p X \rho X,\]

where \(p\) is the bit-flip probability. As such, it is a special case of PauliChannel with \(p_X = p\) and \(p_I = 1 - p\). This can therefore be written as Kraus operators:

\[K_0 = \sqrt{1 - p} I, \quad K_1 = \sqrt{p} X,\]

or similarly as a jump operator:

\[J = \sqrt{\gamma} X,\]

where now \(\gamma\) is the bit-flip rate.

from qilisdk.noise import BitFlip
bit_flip_noise = BitFlip(probability=0.1)

PhaseFlip

PhaseFlip represents a phase-flip error model where each qubit has a certain probability of flipping its phase, changing the sign of the |1⟩ state. This corresponds to the following channel:

\[\mathcal{E}(\rho) = (1 - p) \rho + p Z \rho Z,\]

where \(p\) is the phase-flip probability. As such, it is a special case of PauliChannel with \(p_Z = p\) and \(p_I = 1 - p\). This can therefore be written as Kraus operators:

\[K_0 = \sqrt{1 - p} I, \quad K_1 = \sqrt{p} Z,\]

or similarly as a jump operator:

\[J = \sqrt{\gamma} Z,\]

where now \(\gamma\) is the phase-flip rate.

from qilisdk.noise import PhaseFlip
phase_flip_noise = PhaseFlip(probability=0.1)

Depolarizing

Depolarizing represents a depolarizing error model where each qubit has a certain probability of being replaced by the maximally mixed state. This corresponds to the following channel:

\[\mathcal{E}(\rho) = (1 - p) \rho + \frac{p}{3} (X \rho X + Y \rho Y + Z \rho Z),\]

where \(p\) is the depolarizing probability. As such, it is a special case of PauliChannel with \(p_X = p_Y = p_Z = p/3\) and \(p_I = 1 - p\). This can therefore be written as Kraus operators:

\[K_0 = \sqrt{1 - p} I, \quad K_1 = \sqrt{\frac{p}{3}} X, \quad K_2 = \sqrt{\frac{p}{3}} Y, \quad K_3 = \sqrt{\frac{p}{3}} Z,\]

or similarly as jump operators:

\[J_1 = \sqrt{\frac{\gamma}{3}} X, \quad J_2 = \sqrt{\frac{\gamma}{3}} Y, \quad J_3 = \sqrt{\frac{\gamma}{3}} Z,\]

where \(\gamma\) is the depolarizing rate.

from qilisdk.noise import Depolarizing
depolarizing_noise = Depolarizing(probability=0.1)

AmplitudeDampingNoise

AmplitudeDamping represents an amplitude damping error model where each qubit has a certain probability of decaying from the excited state |1⟩ to the ground state |0⟩. This corresponds to the following channel:

\[\mathcal{E}(\rho) = E_0 \rho E_0^\dagger + E_1 \rho E_1^\dagger.\]

Here the Kraus operators are defined as:

\[\begin{split}E_0 = \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1 - p} \end{pmatrix}, \quad E_1 = \begin{pmatrix} 0 & \sqrt{p} \\ 0 & 0 \end{pmatrix},\end{split}\]

where \(p\) is the amplitude damping probability. The channel can also be represented using the jump operator:

\[J = \sqrt{\gamma} \sigma_-,\]

where \(\gamma\) is the amplitude damping rate and \(\sigma_-\) is the lowering operator. The channel is defined by the \(T_1\) time constant, with the relations:

\[p = 1 - e^{-t / T_1}, \gamma = \frac{1}{T_1},\]

where \(t\) is the time duration over which the amplitude damping occurs.

from qilisdk.noise import AmplitudeDamping
amplitude_damping_noise = AmplitudeDamping(t1=0.1)

Dephasing

Dephasing represents a dephasing error model where each qubit has a certain probability of losing coherence between its |0⟩ and |1⟩ states. This corresponds to the following channel:

\[\mathcal{E}(\rho) = (1 - p) \rho + p Z \rho Z\]

where \(p\) is the dephasing probability. As such, it is a special case of PauliChannel with \(p_Z = p\) and \(p_I = 1 - p\). This can therefore be written as Kraus operators:

\[K_0 = \sqrt{1 - p} I, \quad K_1 = \sqrt{p} Z,\]

or similarly as a jump operator:

\[J = \sqrt{\gamma} Z,\]

where now \(\gamma\) is the dephasing rate. The channel is defined by the \(T_\phi\) time constant, with the relations:

\[p = \frac{1}{2} \left( 1 - e^{-t / T_\phi} \right), \gamma = \frac{1}{T_\phi},\]

where \(t\) is the time duration over which the dephasing occurs.

from qilisdk.noise import Dephasing
dephasing_noise = Dephasing(t_phi=0.1)

GaussianPerturbation

GaussianPerturbation represents a noise model that adds Gaussian-distributed perturbations to the parameters of gates or Hamiltonian terms in a quantum circuit or schedule. This simulates imperfections in control signals that can lead to deviations from the intended operations. The perturbations are drawn from a Gaussian distribution with a specified standard deviation:

\[\delta \theta \sim \mathcal{N}(\mu, \sigma^2),\]

where \(\sigma\) is the standard deviation of the perturbations and \(\mu\) is the mean (defaulting to 0).

from qilisdk.noise import GaussianPerturbation
gaussian_perturbation_noise = GaussianPerturbation(stddev=0.05, mean=0.0)

OffsetPerturbation

OffsetPerturbation represents a noise model that adds fixed offset perturbations to the parameters of gates or Hamiltonian terms in a quantum circuit or schedule. This simulates systematic errors in control signals that consistently shift the intended operations. The offsets are specified as fixed values for each parameter.

from qilisdk.noise import OffsetPerturbation
offset_perturbation_noise = OffsetPerturbation(offset=1.3)

ReadoutAssignment

ReadoutAssignment represents a readout error model that simulates imperfections in the measurement process of qubits. It is defined by two probabilities: the probability of misreading a |0⟩ state as |1⟩ (\(p_{0 \to 1}\)) and the probability of misreading a |1⟩ state as |0⟩ (\(p_{1 \to 0}\)).

from qilisdk.noise import ReadoutAssignment
readout_assignment_noise = ReadoutAssignment(p01=0.05, p10=0.1)