Download dense_evolution/physics/qec.py from Tatopenn/dense-Evolution: direct link, hf CLI and curl.
- Browser
- Download file 5.59 kB
-
https://huggingface.co/Tatopenn/dense-Evolution/resolve/main/dense_evolution/physics/qec.py
- Command line
-
hf download hf://Tatopenn/dense-Evolution/dense_evolution/physics/qec.py
-
curl -L -o qec.py https://huggingface.co/Tatopenn/dense-Evolution/resolve/main/dense_evolution/physics/qec.py
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] | |