Tatopenn's picture
Sync mirror with GitHub main (v8.1.62): subpackage refactor, mitigation promotions, MCP server refactor
2a87ede verified
Raw History Blame Contribute Delete
5.59 kB
"""Stabilizer-code quantum error correction utilities: generic Pauli-string
commutation/syndrome primitives, and an erasure-aware decoder.
Promoted from Dense-Evolution-Discovery's Steane [[7,1,3]] code
investigation (scripts/steane_code_block6_erasure_conversion.py), where a
Steane-specific version of `erasure_aware_decode` was first built and
verified: on shots with exactly 2 simultaneous heralded erasures, it
achieved exactly 0 decoding failures across 94-12,469 such shots at every
tested physical error rate (0 failures out of >60,000 double-erasure
shots total, 40,000 trials x 10 p-values), versus ~25% failure for a
standard syndrome-only decoder blind to the erasure locations -- a clean
confirmation of the real erasure-correction bound below. This version is
code-agnostic (works from any stabilizer generator list, not a
hand-built Steane-specific table), so it moved here instead of staying
Discovery-repo-specific research code.
Erasure-aware decoding exploits a real, foundational fact: Grassl, Beth &
Pellizzari, "Codes for the quantum erasure channel", Phys. Rev. A 56, 33
(1997) -- a distance-d stabilizer code can correct up to (d-1) ERASURES
(known-location errors, e.g. a heralded lost photon in a dual-rail
photonic qubit), versus only floor((d-1)/2) arbitrary (unlocated)
errors. Erasure location information is worth roughly twice as much as
an ordinary syndrome bit, because knowing WHERE the error is removes
exactly the ambiguity a blind syndrome-only decoder has to guess at.
"""
import itertools
from typing import Optional, Sequence
_ANTICOMMUTING_PAIRS = {
frozenset(('X', 'Z')), frozenset(('X', 'Y')), frozenset(('Y', 'Z')),
}
PAULIS = ('I', 'X', 'Y', 'Z')
def pauli_commutes(p1: str, p2: str) -> bool:
"""Whether two equal-length Pauli strings (each character in IXYZ, no
global phase) commute -- the standard symplectic rule: they commute
iff the number of qubit positions where the local single-qubit
Paulis anticommute (X/Z, X/Y, or Y/Z, in either order; I commutes
with everything) is EVEN.
>>> pauli_commutes('XX', 'ZZ') # X,Z anticommute at both qubits -> 2 (even) -> commute
True
>>> pauli_commutes('XI', 'ZI') # X,Z anticommute at 1 qubit -> 1 (odd) -> anticommute
False
"""
if len(p1) != len(p2):
raise ValueError(f"Pauli strings must be equal length: {len(p1)} != {len(p2)}")
n_anticommuting = sum(
1 for a, b in zip(p1, p2)
if a != 'I' and b != 'I' and a != b and frozenset((a, b)) in _ANTICOMMUTING_PAIRS
)
return n_anticommuting % 2 == 0
def compute_syndrome(pauli_error: str, stabilizers: Sequence[str]) -> tuple:
"""The syndrome (one bit per stabilizer generator, 1 = anticommutes /
detected, 0 = commutes / undetected) a given Pauli error string would
produce against `stabilizers` (a list of equal-length Pauli strings,
the code's stabilizer generators -- X-type, Z-type, or mixed; this
function doesn't assume a CSS structure)."""
return tuple(0 if pauli_commutes(pauli_error, g) else 1 for g in stabilizers)
def _pauli_string(n_qubits: int, assignment: dict) -> str:
chars = ['I'] * n_qubits
for q, p in assignment.items():
chars[q] = p
return ''.join(chars)
def erasure_aware_decode(
observed_syndrome: tuple,
heralded_qubits: Sequence[int],
n_qubits: int,
stabilizers: Sequence[str],
) -> Optional[str]:
"""Erasure-aware decoder for any stabilizer code. Given the observed
syndrome and a list of qubits KNOWN to have been erased (e.g. a
heralded photon-loss event on a dual-rail-encoded qubit), brute-forces
every Pauli assignment (I/X/Y/Z, 4**len(heralded_qubits) combinations)
on just the heralded qubits and returns the unique full-length Pauli
string reproducing `observed_syndrome` exactly.
Returns `None` -- not a guess -- when there are zero heralded qubits,
when the observed syndrome is not explained by any assignment on the
heralded qubits alone, or when more than one assignment explains it
(ambiguous). Both `None` cases mean: fall back to a standard
syndrome-only decoder, or treat as a detected-but-uncorrectable
event -- this function will not silently return a wrong-but-plausible
correction. The number of heralded qubits this can actually resolve
unambiguously is bounded by the code's real distance (Grassl, Beth &
Pellizzari 1997: up to d-1 erasures) -- that bound emerges naturally
from the brute-force search itself (more heralded qubits than the
code can resolve typically yields zero or multiple matches), it is
not hard-coded here.
Cost is 4**len(heralded_qubits) syndrome computations, each O(n_qubits
* len(stabilizers)) -- fine for the small numbers of simultaneous
erasures a real per-shot noise rate produces (verified up to 2 in the
original Steane investigation; tractable up to 4-5 for most small
codes before it's worth switching to a smarter search).
"""
if not heralded_qubits:
return None
matches = []
for assignment_paulis in itertools.product(PAULIS, repeat=len(heralded_qubits)):
assignment = dict(zip(heralded_qubits, assignment_paulis))
candidate = _pauli_string(n_qubits, assignment)
if compute_syndrome(candidate, stabilizers) == tuple(observed_syndrome):
matches.append(candidate)
if len(matches) != 1:
return None
return matches[0]