Skip to content

Noise Channels

qudit.noise provides building blocks for quantum noise models: Channel holds a Kraus decomposition, Multiplex sequences multiple channels, and the Process factory constructs standard multi-qudit noise models.

Channel

A Channel represents a completely positive map in Kraus form:

Φ()=kEk()Ek

Each Kraus operator Ek is stored as a list of local Gate objects; an operator "word" that is applied left-to-right via Gate.forwardd.

Property/MethodDescription
opsList of Kraus words (list[list[Gate]])
dFull Hilbert space dimension
run(rho)Apply Φ(ρ)=kEkρEk
correctable()Return Kraus words listed in correctables
isTPkEkEk=I?
isCPChoi matrix 0?
isCPTPboth CP and TP?
toChoi()Choi–Jamiołkowski matrix J(Φ)
toSuperop()Superoperator S s.t. vec(Φ(ρ))=Svec(ρ)
toStinespring()Stinespring isometry V s.t. Φ(ρ)=Trenv(VρV)

Running a channel

python
# Amplitude damping on 2 qubits
channel = Process.AD(d=2, n=2, Y=0.1)

# Apply to |00><00|
rho = np.zeros((4, 4), dtype=complex)
rho[0, 0] = 1.0

rho_out = channel.run(rho)
print(rho_out.shape)   # (4, 4)
python
from qudit.noise import Process
import numpy as np

Channel analysis

python
channel = Process.AD(d=2, n=2, Y=0.1)

print(channel.isTP)    # True
print(channel.isCP)    # True
print(channel.isCPTP)  # True

J = channel.toChoi()   # shape (d^2, d^2)
S = channel.toSuperop()
V = channel.toStinespring()  # isometry: V†V ≈ I
python
from qudit.noise import Process

NOTE

isTP, isCP, isCPTP are cached_property values; they are computed once on first access and cached.

Multiplex

Multiplex sequences multiple channels, applying each in turn:

ρΦnΦ2Φ1(ρ)

The main use case is independent identically distributed (IID) noise, where each wire gets its own channel applied sequentially.

python
# IID amplitude damping on 3 qubits
multi = IID.AD(n=3, y=0.05)

rho = np.zeros((8, 8), dtype=complex)
rho[0, 0] = 1.0

rho_out = multi.run(rho)
python
from qudit.noise import IID
import numpy as np

Multiplex flattens nested Multiplex inputs on construction, so Multiplex([multi1, multi2]) gives a single flat list of channels.

Process

Process constructs standard multi-qudit noise channels with correctable subsets pre-labeled.

Amplitude damping (AD)

Pure amplitude damping uses only lowering operators Ak (p=0 case of GAD):

Ak:|r(rk)1/2(1Y)(rk)/2Yk/2|rk
python
channel = Process.AD(d=2, n=4, Y=0.01, order=1)
ArgumentDescription
dLocal dimension per site (any d ≥ 2)
nNumber of physical sites
YDamping parameter Y[0,1]
orderMax correctable error order (default 1)
groupIf True, keep correctable sets grouped by order
iidIf True, return Multiplex of single-wire channels

Generalized amplitude damping (GAD)

GAD adds raising operators Rk parameterized by environment excitation probability p:

python
channel = Process.GAD(d=2, n=4, Y=0.01, p=0.001, order=1)

Same arguments as AD, plus p (environment excitation probability).

Pauli channel

python
px, py, pz = 0.01, 0.005, 0.01
channel = Process.Pauli(n=3, paulis=["X", "Y", "Z"], p=[px, py, pz], order=1)
python
from qudit.noise import Process

Kraus operators are tensor products of {I,pXX,pYY,pZZ} across all n sites. Correctable subsets are labeled by Hamming weight.

Depolarising channel

Applies all d2 Weyl-Heisenberg operators as Kraus terms. Works for any d2:

Φ(ρ)=(1p)ρ+pd2j,kWjkρWjk
python
channel = Process.Depolarising(d=2, n=2, p=0.05)
channel = Process.Depolarising(d=3, n=1, p=0.02)  # qutrit

Phase damping

Kills off-diagonal coherences without energy exchange. For d=2: K0=diag(1,1p), K1=diag(0,p). Works for any d:

python
channel = Process.PhaseDamp(d=2, n=2, p=0.1)

Bit-flip and phase-flip channels

Qudit generalizations using the cyclic shift Xd and clock Zd operators:

python
channel = Process.BitFlip(d=2, n=2, p=0.05)   # applies X_d with prob p
channel = Process.PhaseFlip(d=2, n=2, p=0.05)  # applies Z_d with prob p

Both reduce to the standard qubit channels when d=2.

Reset channel

Collapses each qudit to |0 with probability p:

Φ(ρ)=(1p)ρ+p|00|Tr(ρ)
python
channel = Process.Reset(d=2, n=2, p=0.1)

Thermal relaxation

Combined T1 energy decay and T2 dephasing for qubits (d=2 only). Requires T22T1:

python
channel = Process.ThermalRelax(n=2, T1=100e-6, T2=80e-6, t=50e-9)

All Process channels accept an iid=True flag to return a Multiplex of independent single-site channels instead of a joint n-site channel.

Weyl-Heisenberg channel (NoisyGate)

For circuit-level noise in Mode.NOISY, NoisyGate("weyl", param, ...) implements the Heisenberg-Weyl displacement channel for any local dimension d:

Φ(ρ)=(1(m,n)(0,0)pmn)ρ+(m,n)(0,0)pmnWmnρWmn

where Wmn=XdmZdn, Xd is the cyclic shift, and Zd is the clock operator. param is a length-(d21) tensor of probabilities in row-major order (0,1),(0,2),,(d1,d1) excluding (0,0).

python
from qudit.circuit.gates import NoisyGate
import torch

# Qubit Weyl (d=2): 3 parameters for W_01=Z, W_10=X, W_11=XZ
ng2 = NoisyGate("weyl", torch.tensor([0.02, 0.01, 0.01]), index=0, wires=1, dims=2)

# Qutrit Weyl (d=3): 8 parameters for all (m,n) ≠ (0,0)
ng3 = NoisyGate("weyl", torch.tensor([0.005]*8), index=0, wires=1, dims=3)

Correctable subsets

After building a channel, channel.correctables holds a flat list (or grouped list if group=True) of Kraus-word indices that are considered correctable up to the given order.

python
channel = Process.GAD(2, 4, Y=0.01, p=0.001)
Ek = channel.correctable()  # list of Kraus operator lists

These are passed directly to Recovery.leung for constructing recovery maps (see Error Correction).

IID noise

IID builds single-wire channels and multiplexes them for independent identically distributed noise. Both factories work for any local dimension d ≥ 2:

FactorySignatureDescription
IID.AD(n, d, y)Amplitude damping on each of n qudits independently
IID.GAD(n, d, y, p)Generalized amplitude damping on each qudit independently
IID.Depolarising(n, d, p)Depolarising channel on each qudit independently
IID.PhaseDamp(n, d, p)Phase damping on each qudit independently
IID.BitFlip(n, d, p)Bit-flip (Xd) on each qudit independently
IID.PhaseFlip(n, d, p)Phase-flip (Zd) on each qudit independently
IID.Reset(n, d, p)Reset to $
python
qubit = IID.AD(n=3, d=2, y=0.05)

qutrit = IID.AD(n=2, d=3, y=0.1)
python
from qudit.noise import IID

TIP

Use Process.AD(d=..., n=..., iid=True) as a shortcut; it delegates to IID.AD and returns a Multiplex.