noise/recovery.py
class Recovery
Construct common approximate/analytic recovery maps for a code subspace.
Each method returns a list of recovery Kraus operators
leung
Leung recovery via polar decomposition.
Given code states
def leung(error_kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray] [static]Implementation
def leung(error_kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray]:
P = sum([np.outer(state, state.conj().T) for state in codes])
Rks = []
for Ek in error_kraus:
Uk, _ = LA.polar(np.dot(Ek, P), side='right')
Rks.append(np.dot(P, Uk.conj().T))
return Rkscafaro
Cafaro recovery using code-state normalizations.
Builds
def cafaro(error_kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray] [static]Implementation
def cafaro(error_kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray]:
Rks = []
for Ek in error_kraus:
Rks.append(sum([np.dot(np.outer(state, state.conj().T), Ek.conj().T) / np.sqrt(MD([state.conj().T, Ek.conj().T, Ek, state])) for state in codes]))
return Rkspetz
Petz recovery (transpose channel) restricted to the code.
With code projector
def petz(kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray] [static]Implementation
def petz(kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray]:
P = sum([np.outer(state, state.conj().T) for state in codes])
channel = sum([MD([Ek, P, Ek.conj().T]) for Ek in kraus])
norm = LA.fractional_matrix_power(channel, -0.5)
return [MD([P, Ek.conj().T, norm]) for Ek in kraus]dutta
Dutta recovery for ensembles of error operators.
Expects a list of error-sets (each set may carry probabilities) and produces normalized recovery operators by averaging syndrome overlaps on the code.
def dutta(error_kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray] [static]Implementation
def dutta(error_kraus: list[np.ndarray], codes: list[np.ndarray]) -> list[np.ndarray]:
Rks = []
for Eks in error_kraus:
Rk = []
for i in codes:
chis = []
for En in Eks:
chis.append(sum([MD([i.conj().T, Em.conj().T, En, i]) for Em in Eks]))
X_av = np.average(chis, weights=[Eks[j].P for j in range(len(chis))])
Rk.append(sum([np.outer(i, np.dot(Em, i).conj().T) for Em in Eks]) / X_av)
Rk = np.sum(Rk, axis=0)
Rks.append(Rk / np.sqrt(np.linalg.eigvalsh(np.dot(Rk.conj().T, Rk))[-1]))
return Rks