Skip to content

noise/lib.py

class Process

Factories for common multi-qudit noise processes.

Each constructor returns a Channel in Kraus form Φ(ρ)=kEkρEk, and records which Kraus terms are considered correctable up to a given order.

GAD

Build an n-site generalized amplitude damping channel.

Constructs tensor-product Kraus operators from single-site Ak (lowering) and Rk (raising) terms, then groups/filters “correctable” subsets by total order.

py
def GAD(d: int, n: int, Y: float, p: float, order: int, group: bool) -> Channel [static]
Implementation
python
def GAD(d: int, n: int, Y: float, p: float, order: int=1, group: bool=False) -> Channel:
    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]'

    def _op_gen(error_word: Sequence[str]) -> Any:
        temp: list[Any] = []
        for tag in error_word:
            order = int(tag[-1])
            if 'a' in tag:
                temp.append(GAD.A(order, d, Y, p))
            elif 'r' in tag:
                temp.append(GAD.R(order, d, Y, p))
            else:
                raise ValueError(f'Unknown tag {tag} in error word {error_word}')
        return mkron(temp)
    keys = list(permut(['a0', 'a1', 'r0', 'r1'] * n, n))
    Ak = [_op_gen(key) for key in keys]
    Ek: list[list[int]] = [[] for _ in range((order + 1) * 2 - 1)]
    for key in keys:
        s = np.sum([int(Em[-1]) for Em in key])
        if s <= order and (not np.all(np.isclose(Ak[keys.index(key)], 0, atol=1e-08))):
            if any(('r' in i and int(i[-1]) > 0 for i in key)):
                Ek[2 * s - 1].append(keys.index(key))
            else:
                Ek[2 * s - 0].append(keys.index(key))
    op_ch = Channel(Ak)
    op_ch.correctables = Ek if group else ungroup(Ek)
    return op_ch

Build an n-site (pure) amplitude damping channel.

This is the p=0 special case of GAD using only lowering operators Ak.

py
def AD(d: int, n: int, Y: float, order: int, group: bool) -> Channel [static]
Implementation
python
def AD(d: int, n: int, Y: float, order: int=1, group: bool=False) -> Channel:
    assert isinstance(Y, float), 'Y must be a float'
    assert Y <= 1, 'Y must be in [0, 1]'

    def _op_gen(error_word: Sequence[str]) -> Any:
        individual = [GAD.A(int(tag[-1]), d, Y) for tag in error_word]
        return mkron(individual)
    keys = list(permut(['a0', 'a1'] * n, n))
    Ak = [_op_gen(key) for key in keys]
    Ek: list[list[int]] = [[] for _ in range(order + 1)]
    for key in keys:
        s = np.sum([int(Em[-1]) for Em in key])
        if s <= order and (not np.all(np.isclose(Ak[keys.index(key)], 0, atol=1e-08))):
            Ek[s].append(keys.index(key))
    op_ch = Channel(Ak)
    op_ch.correctables = Ek if group else ungroup(Ek)
    return op_ch

Pauli

Build an n-site Pauli channel.

Constructs tensor-product Kraus operators from {I,X,Y,Z} with weights derived from p=[pX,pY,pZ], and groups “correctable” subsets by Hamming weight.

py
def Pauli(n: int, paulis: Optional[list[str]], p: Optional[list[float]], order: int, group: bool) -> Channel [static]
Implementation
python
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]) -> Any:
        return mkron([funcs[gate](p) for gate in word])
    keys = permut((['I'] + paulis) * n, n)
    Ak = [_op_gen(key) for key in keys]
    Ek: list[list[int]] = [[] for _ in range(order + 1)]
    for key in keys:
        s = np.sum([weight[i] for i in key])
        if s <= order and (not np.all(np.isclose(Ak[keys.index(key)], 0, atol=1e-08))):
            Ek[s].append(keys.index(key))
    op_ch = Channel(Ak)
    op_ch.correctables = Ek if group else ungroup(Ek)
    return op_ch

permut

Return unique length-n permutations of a list of symbols.

Used to enumerate Kraus-operator “words” (tensor-product factor choices).
py
def permut(lst: List[str], n: int) -> List[List[str]]
Implementation
python
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 set(permutations(lst, n))]

mkron

Compute a left-to-right Kronecker product A0A1.

This is used to build many-body Kraus operators from single-site ones.

py
def mkron(args: Sequence[Any]) -> Any
Implementation
python
def mkron(args: Sequence[Any]) -> Any:
    result = args[0]
    for i in range(1, len(args)):
        result = np.kron(result, args[i])
    return result

ungroup

No Definition provided

py
def ungroup(lst: List[List[Any]]) -> List[Any]
Implementation
python
def ungroup(lst: List[List[Any]]) -> List[Any]:
    return [item for sublist in lst for item in sublist]