Skip to content

qec/codes.py

class Code

A codeword is an N×d tensor d is the dimension of the code, and N is the number computational base states, where N=dn in a system of n qudits.

For now Code only supports uniform dimension codes. So a dim of means only codewords of the form 2n×2 will be supported. This is sufficient for many standard codes, but may need to be relaxed in the future.

nametypedefault
codewordspt.TensorNone
dimintNone
ditsintNone
gatesGategenNone
widthintNone

init

No Definition provided

py
def __init__(self: Any, codewords: pt.Tensor, d: int) -> Any
Implementation
python
def __init__(self, codewords: pt.Tensor, d: int=None):
    assert codewords.ndim >= 2, 'Codewords must be at least 2D tensors'
    self.codewords = codewords
    self.dim = codewords.shape[0]
    width = codewords.shape[1]
    _d = d if d is not None else self.dim
    self.dits = int(round(ma.log(width) / ma.log(_d)))
    self.gates = Gategen(_d)

toTensor

No Definition provided

py
def toTensor(self: Any) -> Any
Implementation
python
def toTensor(self):
    return self.codewords

isValid

No Definition provided

py
def isValid(code: Any) -> Any [static]
Implementation
python
def isValid(code):
    norms = pt.norm(code, dim=1)
    if not pt.allclose(norms, pt.ones_like(norms)):
        print('Norms:', pt.round(norms, decimals=2))
        raise ValueError('Codewords are not normalized!')
    ortho = code @ code.T - pt.eye(code.shape[0])
    if not pt.allclose(ortho, pt.zeros_like(ortho), atol=0.001):
        print('Orthogonality check:', pt.round(ortho, decimals=2))
        raise ValueError('Codewords are not orthogonal!')

fromStabilizers

We may get ["XXY", "ZZI"], or [["X", "X", "Y"], ["Z", "Z", "I"]]. In the first case we need to split the strings into lists of characters, in the second case we can directly use the lists.

We then use the constructed matrices to construct the projector onto the code space, and then extract the codewords using either method="svd" (Singular Value Decomposition, default) or method="rrf"(Randomized Range Finder).

SVD is more stable but may be slower for large codes, while RRF is faster but may be less stable. For small codes, SVD is usually preferred.

The d parameter sets the local dimension (default 2 for qubits). For d>2, X and Z are the generalized Weyl operators from Gategen.

py
def fromStabilizers(stabilizers: list[str] | list[list[str]], d: int, method: Any, numpy: Any) -> 'Code' [static]
Implementation
python
def fromStabilizers(stabilizers: list[str] | list[list[str]], d: int=2, method='svd', numpy=False) -> 'Code':
    assert method in ['svd', 'rrf'], f"method must be 'svd' or 'rrf', got '{method}'"
    if isinstance(stabilizers[0], str):
        stabilizers = [list(s) for s in stabilizers]
    gg = Gategen(dim=d)
    ops = {'I': pt.eye(d, dtype=C64), 'X': gg.X.tensor.to(C64), 'Z': gg.Z.tensor.to(C64)}
    proj = Projector([composite(s, ops) for s in stabilizers])
    if method == 'svd':
        _, S, Vh = LA.svd(proj)
        code = Vh[pt.isclose(S, pt.tensor(1.0))]
    elif numpy:
        code = SVD_RRF_np(proj)
    else:
        code = SVD_RRF(proj)
    Code.isValid(code)
    return Code(code, d=d)

composite

No Definition provided

py
def composite(stabilizer: list[str], ops: dict) -> pt.Tensor
Implementation
python
def composite(stabilizer: list[str], ops: dict=None) -> pt.Tensor:
    if ops is None:
        ops = Pauli
    mat = ops[stabilizer[0]]
    for p in stabilizer[1:]:
        mat = pt.kron(mat, ops[p])
    return mat

Projector

No Definition provided

py
def Projector(stabilizers: list[pt.Tensor]) -> pt.Tensor
Implementation
python
def Projector(stabilizers: list[pt.Tensor]) -> pt.Tensor:
    dim = stabilizers[0].shape[0]
    I = pt.eye(dim, dtype=C64)
    P = I
    for S in stabilizers:
        P = P @ ((I + S) * 0.5)
    return P

SVD_RRF

No Definition provided

py
def SVD_RRF(P: pt.Tensor, target_rank: Any) -> pt.Tensor
Implementation
python
def SVD_RRF(P: pt.Tensor, target_rank=2) -> pt.Tensor:
    Omega = pt.randn((P.shape[0], target_rank), dtype=pt.float32).to(pt.complex64)
    Y = P @ Omega
    Q = LA.qr(Y, mode='reduced')[0]
    return Q.T

SVD_RRF_np

No Definition provided

py
def SVD_RRF_np(P: Any, target_rank: Any) -> Any
Implementation
python
def SVD_RRF_np(P, target_rank=2):
    P = P.cpu().numpy()
    Omega = np.random.normal(size=(P.shape[0], target_rank))
    Y = P @ Omega
    Q = SLA.qr(Y, mode='economic', overwrite_a=True, check_finite=False)[0]
    return pt.from_numpy(Q.T)