noise/lib.py
class IID
No Definition provided
AD
Independent identical amplitude-damping on each of
Single-site Kraus set: GAD.A(k, d, y). For
def AD(n: int, d: int, y: float) -> 'Multiplex' [static]Implementation
def AD(n: int, d: int, y: float) -> 'Multiplex':
channel_list = []
kraus_mats = [GAD.A(k, d, y) for k in range(d)]
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'A{k}_{i}', params=[('y', y), ('i', i)]) for k, m in enumerate(kraus_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)GAD
Independent identical generalized amplitude-damping on each of
Single-site Kraus set: GAD.A/R(k, d, y, p). For
def GAD(n: int, d: int, y: float, p: float) -> 'Multiplex' [static]Implementation
def GAD(n: int, d: int, y: float, p: float) -> 'Multiplex':
channel_list = []
A_mats = [GAD.A(k, d, y, p) for k in range(d)]
R_mats = [GAD.R(k, d, y, p) for k in range(d)]
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'A{k}_{i}', params=[('y', y), ('p', p), ('i', i)]) for k, m in enumerate(A_mats)] + [Gate(m, index=[i], wires=n, dim=d, name=f'R{k}_{i}', params=[('y', y), ('p', p), ('i', i)]) for k, m in enumerate(R_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)Depolarising
Independent identical depolarising noise on each of
Single-site Kraus set: all Depolarising.ops(d, p).
def Depolarising(n: int, d: int, p: float) -> 'Multiplex' [static]Implementation
def Depolarising(n: int, d: int, p: float) -> 'Multiplex':
channel_list = []
kraus_mats = Depolarising.ops(d, p)
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'W{k}_{i}', params=[('p', p), ('i', i)]) for k, m in enumerate(kraus_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)PhaseDamp
Independent identical phase damping on each of
Single-site Kraus set: PhaseDamp.ops(d, p).
def PhaseDamp(n: int, d: int, p: float) -> 'Multiplex' [static]Implementation
def PhaseDamp(n: int, d: int, p: float) -> 'Multiplex':
channel_list = []
kraus_mats = PhaseDamp.ops(d, p)
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'PD{k}_{i}', params=[('p', p), ('i', i)]) for k, m in enumerate(kraus_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)BitFlip
Independent identical bit-flip (shift) noise on each of
Single-site Kraus set:
def BitFlip(n: int, d: int, p: float) -> 'Multiplex' [static]Implementation
def BitFlip(n: int, d: int, p: float) -> 'Multiplex':
channel_list = []
shift = pt.roll(pt.eye(d, dtype=C128), shifts=-1, dims=1)
kraus_mats = [(1 - p) ** 0.5 * pt.eye(d, dtype=C128), p ** 0.5 * shift]
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'BF{k}_{i}', params=[('p', p), ('i', i)]) for k, m in enumerate(kraus_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)PhaseFlip
Independent identical phase-flip (clock) noise on each of
Single-site Kraus set:
def PhaseFlip(n: int, d: int, p: float) -> 'Multiplex' [static]Implementation
def PhaseFlip(n: int, d: int, p: float) -> 'Multiplex':
import cmath as cm
w = cm.exp(2j * cm.pi / d)
channel_list = []
clock = pt.diag(pt.tensor([w ** k for k in range(d)], dtype=C128))
kraus_mats = [(1 - p) ** 0.5 * pt.eye(d, dtype=C128), p ** 0.5 * clock]
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'PF{k}_{i}', params=[('p', p), ('i', i)]) for k, m in enumerate(kraus_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)Reset
Independent identical reset noise on each of
Single-site Kraus set: Reset.ops(d, p).
def Reset(n: int, d: int, p: float) -> 'Multiplex' [static]Implementation
def Reset(n: int, d: int, p: float) -> 'Multiplex':
channel_list = []
kraus_mats = Reset.ops(d, p)
for i in range(n):
kraus_gates = [Gate(m, index=[i], wires=n, dim=d, name=f'RS{k}_{i}', params=[('p', p), ('i', i)]) for k, m in enumerate(kraus_mats)]
channel_list.append(Channel([[g] for g in kraus_gates]))
return Multiplex(channel_list)class Process
Factories for common multi-qudit noise processes.
Each constructor returns a Channel in Kraus form
GAD
Build an
Constructs tensor-product Kraus operators from single-site
def GAD(d: int, n: int, Y: float, p: float, order: int, group: bool, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def GAD(d: int, n: int, Y: float, p: float, order: int=1, group: bool=False, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert isinstance(p, float), 'p must be a float'
assert isinstance(Y, float), 'Y must be a float'
assert p <= 1 and Y <= 1, 'p,Y must be in [0, 1]'
if iid:
return IID.GAD(n, d, Y, p)
def _op_gen(error_word: Sequence[str]) -> Optional[list[Gate]]:
gates = []
for i, tag in enumerate(error_word):
ord_val = int(tag[-1])
m = GAD.A(ord_val, d, Y, p) if 'a' in tag else GAD.R(ord_val, d, Y, p)
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'{tag}_{i}'))
return gates
base_tags = [f'a{k}' for k in range(d)] + [f'r{k}' for k in range(d)]
keys = list(permut(base_tags * n, n))
Ak = []
valid_keys = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
valid_keys.append(key)
Ek: list[list[int]] = [[] for _ in range((order + 1) * 2 - 1)]
for idx, key in enumerate(valid_keys):
s = sum((int(Em[-1]) for Em in key))
if s <= order:
if any(('r' in i and int(i[-1]) > 0 for i in key)):
Ek[2 * s - 1].append(idx)
else:
Ek[2 * s - 0].append(idx)
op_ch = Channel(Ak)
op_ch.correctables = Ek if group else ungroup(Ek)
return op_chAD
Build an
This is the
def AD(d: int, n: int, Y: float, order: int, group: bool, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def AD(d: int, n: int, Y: float, order: int=1, group: bool=False, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert isinstance(Y, float), 'Y must be a float'
assert Y <= 1, 'Y must be in [0, 1]'
if iid:
return IID.AD(n, d, Y)
def _op_gen(error_word: Sequence[str]) -> Optional[list[Gate]]:
gates = []
for i, tag in enumerate(error_word):
m = GAD.A(int(tag[-1]), d, Y)
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'{tag}_{i}'))
return gates
keys = list(permut([f'a{k}' for k in range(d)] * n, n))
Ak = []
valid_keys = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
valid_keys.append(key)
Ek: list[list[int]] = [[] for _ in range(order + 1)]
for idx, key in enumerate(valid_keys):
s = sum((int(Em[-1]) for Em in key))
if s <= order:
Ek[s].append(idx)
op_ch = Channel(Ak)
op_ch.correctables = Ek if group else ungroup(Ek)
return op_chPauli
Build an
Constructs tensor-product Kraus operators from
def Pauli(n: int, paulis: Optional[list[str]], p: Optional[list[float]], order: int, group: bool) -> Channel [static]Implementation
def Pauli(n: int, paulis: Optional[list[str]]=None, p: Optional[list[float]]=None, order: int=1, group: bool=False) -> Channel:
if paulis is None:
paulis = ['X', 'Y', 'Z']
if p is None:
p = [0.0, 0.0, 0.0]
funcs = {'I': Pauli.I, 'X': lambda p: Pauli.X(p[0]), 'Y': lambda p: Pauli.Y(p[1]), 'Z': lambda p: Pauli.Z(p[2])}
weight = {'I': 0, 'X': 1, 'Y': 1, 'Z': 1}
def _op_gen(word: Sequence[str]) -> Optional[list[Gate]]:
gates = []
for i, gate_str in enumerate(word):
m = funcs[gate_str](p)
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(2, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=2, name=f'{gate_str}_{i}'))
return gates
keys = list(permut((['I'] + paulis) * n, n))
Ak = []
valid_keys = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
valid_keys.append(key)
Ek: list[list[int]] = [[] for _ in range(order + 1)]
for idx, key in enumerate(valid_keys):
s = sum((weight[i] for i in key))
if s <= order:
Ek[s].append(idx)
op_ch = Channel(Ak)
op_ch.correctables = Ek if group else ungroup(Ek)
return op_chDepolarising
Build an
Applies all
def Depolarising(d: int, n: int, p: float, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def Depolarising(d: int, n: int, p: float, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert 0 <= p <= 1, 'p must be in [0, 1]'
if iid:
return IID.Depolarising(n, d, p)
kraus_single = Depolarising.ops(d, p)
def _op_gen(word: Sequence[int]) -> Optional[list[Gate]]:
gates = []
for i, ki in enumerate(word):
m = kraus_single[ki]
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'W{ki}_{i}'))
return gates
num_ops = d * d
keys = list(product(range(num_ops), repeat=n))
Ak = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
return Channel(Ak)PhaseDamp
Build an
Eliminates off-diagonal coherences without energy exchange. Works for any
def PhaseDamp(d: int, n: int, p: float, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def PhaseDamp(d: int, n: int, p: float, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert 0 <= p <= 1, 'p must be in [0, 1]'
if iid:
return IID.PhaseDamp(n, d, p)
kraus_single = PhaseDamp.ops(d, p)
def _op_gen(word: Sequence[int]) -> Optional[list[Gate]]:
gates = []
for i, ki in enumerate(word):
m = kraus_single[ki]
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'PD{ki}_{i}'))
return gates
num_ops = d
keys = list(product(range(num_ops), repeat=n))
Ak = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
return Channel(Ak)BitFlip
Build an
Applies the cyclic shift
def BitFlip(d: int, n: int, p: float, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def BitFlip(d: int, n: int, p: float, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert 0 <= p <= 1, 'p must be in [0, 1]'
if iid:
return IID.BitFlip(n, d, p)
shift = pt.roll(pt.eye(d, dtype=C128), shifts=-1, dims=1)
kraus_single = [(1 - p) ** 0.5 * pt.eye(d, dtype=C128), p ** 0.5 * shift]
def _op_gen(word: Sequence[int]) -> Optional[list[Gate]]:
gates = []
for i, ki in enumerate(word):
m = kraus_single[ki]
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'BF{ki}_{i}'))
return gates
keys = list(product(range(2), repeat=n))
Ak = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
return Channel(Ak)PhaseFlip
Build an
Applies the clock operator
def PhaseFlip(d: int, n: int, p: float, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def PhaseFlip(d: int, n: int, p: float, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert 0 <= p <= 1, 'p must be in [0, 1]'
if iid:
return IID.PhaseFlip(n, d, p)
import cmath as cm
w = cm.exp(2j * cm.pi / d)
clock = pt.diag(pt.tensor([w ** k for k in range(d)], dtype=C128))
kraus_single = [(1 - p) ** 0.5 * pt.eye(d, dtype=C128), p ** 0.5 * clock]
def _op_gen(word: Sequence[int]) -> Optional[list[Gate]]:
gates = []
for i, ki in enumerate(word):
m = kraus_single[ki]
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'PF{ki}_{i}'))
return gates
keys = list(product(range(2), repeat=n))
Ak = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
return Channel(Ak)Reset
Build an
Collapses each qudit to
def Reset(d: int, n: int, p: float, iid: bool) -> Union[Channel, 'Multiplex'] [static]Implementation
def Reset(d: int, n: int, p: float, iid: bool=False) -> Union[Channel, 'Multiplex']:
assert 0 <= p <= 1, 'p must be in [0, 1]'
if iid:
return IID.Reset(n, d, p)
kraus_single = Reset.ops(d, p)
def _op_gen(word: Sequence[int]) -> Optional[list[Gate]]:
gates = []
for i, ki in enumerate(word):
m = kraus_single[ki]
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'RS{ki}_{i}'))
return gates
num_ops = d + 1
keys = list(product(range(num_ops), repeat=n))
Ak = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
return Channel(Ak)ThermalRelax
Build an
Combines ValueError for
Args: n: number of qubits T1: longitudinal relaxation time T2: transverse dephasing time (
def ThermalRelax(n: int, T1: float, T2: float, t: float) -> Channel [static]Implementation
def ThermalRelax(n: int, T1: float, T2: float, t: float) -> Channel:
d = 2
if T2 > 2 * T1:
raise ValueError('ThermalRelax requires T2 <= 2*T1')
kraus_single = ThermalRelax.ops(T1, T2, t)
def _op_gen(word: Sequence[int]) -> Optional[list[Gate]]:
gates = []
for i, ki in enumerate(word):
m = kraus_single[ki]
if pt.allclose(m, pt.zeros_like(m), atol=1e-08):
return None
if not pt.allclose(m, pt.eye(d, dtype=m.dtype), atol=1e-08):
gates.append(Gate(m, index=[i], wires=n, dim=d, name=f'TR{ki}_{i}'))
return gates
num_ops = len(kraus_single)
keys = list(product(range(num_ops), repeat=n))
Ak = []
for key in keys:
word_gates = _op_gen(key)
if word_gates is not None:
Ak.append(word_gates)
return Channel(Ak)permut
Return unique length-
Used to enumerate Kraus-operator "words" (tensor-product factor choices).
def permut(lst: List[str], n: int) -> List[List[str]]Implementation
def permut(lst: List[str], n: int) -> List[List[str]]:
if n > len(lst):
raise ValueError('n must be less than or equal to the length of lst')
return [list(p) for p in product(set(lst), repeat=n)]mkron
Compute a left-to-right Kronecker product
This is used to build many-body Kraus operators from single-site ones.
def mkron(args: Sequence[Any]) -> AnyImplementation
def mkron(args: Sequence[Any]) -> Any:
result = args[0]
for i in range(1, len(args)):
result = pt.kron(result, args[i])
return resultungroup
No Definition provided
def ungroup(lst: List[List[Any]]) -> List[Any]Implementation
def ungroup(lst: List[List[Any]]) -> List[Any]:
return [item for sublist in lst for item in sublist]