noise/index.py
class Error
A Kraus/error operator represented as a NumPy ndarray subclass.
Conceptually, an error operator
| name | type | default |
|---|---|---|
| correctable | bool | False |
| d | int | None |
| name | str | None |
| params | dict[str, Any] | None |
class Channel
A quantum channel represented in Kraus form using localized Gates.
For Kraus operators
| name | type | default |
|---|---|---|
| correctables | list[Union[int, list[int]]] | None |
| ops | list[list[Gate]] | None |
init
No Definition provided
def __init__(self: Any, ops: list[list[Gate]]) -> AnyImplementation
def __init__(self, ops: list[list[Gate]]):
assert isinstance(ops, list) and len(ops) > 0, 'ops must be a list of Gate lists'
self.ops = ops
self.correctables = []
first = ops[0][0]
self.d: int = first.total_dimrun
Apply the channel in Kraus form: forwardd.
def run(self: Any, rho: Union['State', pt.Tensor, np.ndarray]) -> pt.TensorImplementation
def run(self, rho: Union['State', pt.Tensor, np.ndarray]) -> pt.Tensor:
if hasattr(rho, 'isDensity'):
if not rho.isDensity:
rho = rho.density()
elif isinstance(rho, pt.Tensor) and rho.ndim == 1:
rho = rho.view(-1, 1) @ pt.conj(rho.view(1, -1))
rho = rho.to(pt.complex64)
tensor_rho = getattr(rho, 'tensor', rho)
if isinstance(tensor_rho, np.ndarray):
if tensor_rho.ndim == 1:
tensor_rho = np.outer(tensor_rho, tensor_rho.conj())
tensor_rho = pt.from_numpy(tensor_rho)
device = self.ops[0][0].device if len(self.ops[0]) > 0 else 'cpu'
tensor_rho = tensor_rho.to(device=device, dtype=C64)
rho_out = pt.zeros_like(tensor_rho)
for kraus_word in self.ops:
rho_branch = tensor_rho.clone()
for g in kraus_word:
rho_branch = g.forwardd(rho_branch)
rho_out += rho_branch
return rho_outcorrectable
Return the subset(s) of Kraus operators marked as correctable (if any).
def correctable(self: Any) -> AnyImplementation
def correctable(self) -> Any:
if not self.correctables:
return []
c0 = self.correctables[0]
if isinstance(c0, int):
idxs = [i for i in self.correctables if isinstance(i, int)]
return [self.ops[i] for i in idxs]
if isinstance(c0, list):
Ek: list[list[list[Gate]]] = []
sets = [s for s in self.correctables if isinstance(s, list)]
for s in sets:
Ek.append([self.ops[i] for i in s])
return Ek
return Exception("Please don't change correctables")isTP
Check trace-preservation (TP) via
def isTP(self: Any) -> boolImplementation
def isTP(self) -> bool:
first = self.ops[0][0]
total = pt.zeros((self.d, self.d), dtype=C64, device=first.device)
for word in self.ops:
Ek = self._materialize(word)
total += Ek.conj().T @ Ek
identity = pt.eye(self.d, dtype=C64, device=first.device)
return bool(pt.allclose(total, identity, atol=1e-08))isCP
Check complete-positivity (CP) by verifying Choi matrix is PSD.
def isCP(self: Any) -> boolImplementation
def isCP(self) -> bool:
J = self.toChoi()
eig = pt.linalg.eigvalsh(J.to(pt.complex128))
return bool((eig.real >= -1e-05).all().item())isCPTP
Check if the channel is CPTP (completely positive and trace preserving).
def isCPTP(self: Any) -> boolImplementation
def isCPTP(self) -> bool:
return self.isCP and self.isTPtoChoi
Compute the Choi matrix
def toChoi(self: Any) -> pt.TensorImplementation
def toChoi(self) -> pt.Tensor:
d = self.d
J = pt.zeros((d * d, d * d), dtype=pt.complex128)
basis = pt.eye(d, dtype=pt.complex128)
for i in range(d):
for j in range(d):
Eij = pt.outer(basis[i], basis[j])
J += pt.kron(Eij, self.run(Eij).to(pt.complex128))
return JtoSuperop
Compute the superoperator
def toSuperop(self: Any) -> pt.TensorImplementation
def toSuperop(self) -> pt.Tensor:
mats = [self._materialize(word).to(pt.complex128) for word in self.ops]
d = self.d
S = pt.zeros((d * d, d * d), dtype=pt.complex128)
for Ek in mats:
S += pt.kron(Ek, Ek.conj())
return StoStinespring
Compute a Stinespring isometry
Constructs
def toStinespring(self: Any) -> pt.TensorImplementation
def toStinespring(self) -> pt.Tensor:
K = len(self.ops)
d = self.d
r = K
V = pt.zeros((d * r, d), dtype=pt.complex128)
for n, O in enumerate(self.ops):
Ek = self._materialize(O).to(pt.complex128)
V[n * d:(n + 1) * d, :] = Ek
return VAk
Alias for the Kraus list
def Ak(self: Any) -> list[Error]Implementation
def Ak(self) -> list[Error]:
return self.opsclass Multiplex
Container class for multiple channels, e.g. for different noise models or parameter regimes. Allows us to run multiple channels on a state successively.
| name | type | default |
|---|---|---|
| channels | list['Channel'] | None |
init
No Definition provided
def __init__(self: Any, channels: list[Union['Channel', 'Multiplex']]) -> AnyImplementation
def __init__(self, channels: list[Union['Channel', 'Multiplex']]):
assert isinstance(channels, list) and len(channels) > 0, 'channels must be List[Channel] or List[Multiplex]'
clist: list['Channel'] = []
for ch in channels:
if isinstance(ch, Multiplex):
clist.extend(ch.channels)
else:
clist.append(ch)
self.channels = clistrun
Apply channels in sequence:
def run(self: Any, rho: Union['State', pt.Tensor, np.ndarray]) -> pt.TensorImplementation
def run(self, rho: Union['State', pt.Tensor, np.ndarray]) -> pt.Tensor:
result = rho
for channel in self.channels:
result = channel.run(result)
return result