Fault-tolerant protocols: gadgets, ideal and *-decoders, Defs. 1–5, ExRecs and their
DefinitionQAlgorithms_Defs_FaultToleranceFault-tolerant protocols: gadgets, ideal and *-decoders, Defs. 1–5, ExRecs and their
QAlgorithms.FTProtocol
A fault-tolerance protocol is a bundle of the following data, with no conditions imposed.
Sizes:
- , the number of code qubits;
- ;
- , the number of ancilla qubits per block.
Code data:
- a complex linear subspace (the code);
- a complex matrix , with rows indexed by and columns by ;
- a map from complex matrices to complex matrices. It is an arbitrary function, not required to be linear.
Circuits:
- for each location kind , a location circuit on qubits, where and otherwise;
- a location circuit on qubits.
Measurement decoding:
- a map from finite bit lists to bits.
QAlgorithms.IsEncodingOf
For a subspace and a complex matrix , the proposition asserts both of the following:
- , i.e. is an isometry .
- The image of the linear map , from to , equals .
Together these force , and hence .
QAlgorithms.IsIdealDecoder
For a matrix , a number , and a map from matrices to matrices, the proposition asserts two things.
(i) is a channel. There exist and matrices with and for all .
(ii) undoes low-weight errors on encoded states. For every matrix in the complex linear span of all Pauli-string matrices of weight at most , and every unit vector , set . Then
The span used in (ii) is defined as follows:
- A Pauli-string matrix is with and each .
- Its weight is the number of positions with .
- The span includes , for which the condition reads .
QAlgorithms.IsStarDecoder
Let be a map from matrices to matrices, and let be a complex matrix with rows indexed by and columns indexed by . The proposition asserts three conditions:
- ;
- ;
- for every matrix , .
In condition 3, traces out the second factor:
Conditions 1 and 2 say that is unitary. This is satisfiable only when , i.e. and . For any other (in particular , or ) the proposition is false.
QAlgorithms.blockLayout
For , this is an explicit bijection
It splits the wires into consecutive blocks of wires each. Block consists of wires . Within block :
- the first wires form the data string;
- the last wires form the ancilla string.
Explicitly, a bit string is sent to the pair , where
QAlgorithms.singleLayout
For natural numbers and , is a bijection
Here a bit string on wires is a function from to . The map works in two steps:
- It splits into its first bits (the "data" part) and its last bits (the "ancilla" part).
- It wraps each part as the constant function on the one-element index set ("block ").
The inverse concatenates the data string of block followed by the ancilla string of block . Edge cases: or (an empty part) are allowed.
QAlgorithms.blockDataWires
For natural numbers , is a finite set of wires among the wires . It is the image of all pairs with and under Mathlib's standard product-to-index bijection , , applied with . That is,
Thinking of the wires as consecutive blocks of length , these are the first wires of each block. It has elements. It is empty if or .
QAlgorithms.ecDataWires
For natural numbers and , is the set of wires
the image of under the inclusion that keeps each index's value. These are the first of the wires. It is empty if .
QAlgorithms.embedVia
The inputs are:
- natural numbers ;
- a bijection . Write : the "data" strings of blocks and the "ancilla" strings of blocks;
- a complex matrix indexed by -tuples of -bit strings.
The output is a complex matrix indexed by pairs , where and ranges over the one-element set (a trivial "environment" factor). Its entries are
Thus, transported through , it equals , tensored with the matrix . No positivity, trace, or other condition is imposed on .
QAlgorithms.traceVia
The inputs are:
- natural numbers ;
- a bijection (data strings and ancilla strings of blocks);
- a complex matrix indexed by pairs with and .
The output is the matrix indexed by -tuples of -bit strings given by
This is the partial trace of over all ancilla bits (as identified by ) and over the trivial one-dimensional environment factor. No condition is imposed on .
QAlgorithms.gadgetOut
The inputs are:
- a natural number ;
- a located circuit on qubits: a list of time steps, each a list of locations; each location has a kind (prep, H, T, CNOT, meas, wait), an ordered tuple of distinct wires (2 for CNOT, otherwise 1), and a classical condition;
- a Pauli fault arrangement , which assigns to every pair (step , position ) either "no fault" or a pair of single-qubit Paulis ;
- a complex matrix indexed by ;
- a Boolean predicate on finite bit lists.
Let be the number of measurement locations of . Then
The initial state. is the classical–quantum state, i.e. a map from outcome records (bit lists) to matrices. It assigns to the empty record and to every other record.
What the run does. processes the locations in order: step by step, and within a step in list order. At each location it acts on the matrix stored under each record :
- prep: resets the location's first wire to , using Kraus operators for .
- meas: maps the record (ending in bit ) to the conjugation by the projector on the first wire, applied to the matrix stored under with its last bit removed. The empty record gets .
- wait: does nothing.
- H, T, CNOT: conjugates by the ideal gate on the location's wires if the location's condition evaluated on the earlier-step outcomes recorded in is true; otherwise does nothing.
The errors. assigns an error to location only if is an actual location of and . The error is conjugation by the Pauli operator that applies on the location's first wire and on its remaining wire (if any), tensored with on the environment. The error is applied:
- after the ideal action, for prep, gates and wait;
- before the projection, for meas.
The result is an unnormalized matrix on : the sum of the branches over all length- outcome records accepted by . If , the sum has the single empty record.
QAlgorithms.faultCount
The inputs are a natural number , a located circuit on qubits, and a Pauli fault arrangement (assigning to each pair either "no fault" or a pair of Paulis). Then is the natural number
This counts the faulty locations that are actual locations of . Fault assignments at pairs outside are not counted.
QAlgorithms.LocKind.IsGateOrWait
For a location kind , is the proposition
It is false exactly for prep and meas.
QAlgorithms.FTProtocol.gateOp
The protocol. Fix a protocol with the following components:
- a block size and an ancilla count ;
- for each location kind , a gadget circuit on qubits, where the arity is for CNOT and otherwise;
- an error-correction circuit;
- a classical decoder.
The definition. For a kind (any of the six; no restriction to gates is imposed) and a Pauli fault arrangement , is the map sending a complex matrix indexed by -tuples of -bit strings to
In this formula:
- The layout. The wires are arranged as consecutive blocks of . Wire is data bit of block when , and ancilla bit of block when .
- The input . It is the classical–quantum state that assigns, to the empty record, on all ancilla bits, times on a trivial one-dimensional environment, transported through this layout. Every other record gets .
- The run. executes the gadget location by location. At each location it conditions on earlier outcomes and stores the post-measurement branch under each outcome record.
- The faults. inserts, at each actual location of with , conjugation by on the location's first wire and on its second wire (if any). The fault comes after prep, gate and wait actions, and before measurement projections.
- The outcomes. The sum runs over all records of length , the number of measurement locations of . No outcome is filtered out.
- The partial trace. is the partial trace over all ancilla bits of all blocks and over the trivial environment.
The output is not required to be normalized or positive. Nothing about well-formedness of is assumed.
QAlgorithms.FTProtocol.prepState
The protocol. Fix a protocol with:
- a block size and an ancilla count ;
- a preparation gadget , a located circuit on qubits.
The definition. For a Pauli fault arrangement , is the complex matrix indexed by -bit strings obtained as follows:
- Start. Take the classical–quantum state that assigns, to the empty record, the pure all-zero state on all wires, tensored with the identity on a trivial environment. Every other record gets .
- Run. Run with the Pauli faults dictated by . At each actual location with , conjugate by on its first wire and on its second wire (if any); this comes after prep, gate and wait actions, and before measurement projections. Sum the resulting branch matrices over all outcome records of length equal to the number of measurement locations of ; no outcome is excluded.
- Trace out ancillas. Take the partial trace over the last wires (the ancillas of the single block, where wire is data bit ) and over the trivial environment.
- Reindex. Reindex from one-block tuples to -bit strings , via .
The input state is fixed to all-zeros on every wire, data included. The result need not be normalized.
QAlgorithms.FTProtocol.measFunctional
The protocol. Fix a protocol with:
- a block size and an ancilla count ;
- a measurement gadget on qubits;
- a classical decoding map from bit lists to bits.
The definition. For a Pauli fault arrangement , a bit , and a complex matrix indexed by -bit strings, is the complex number
In this formula:
- The input . It assigns, to the empty record, on the data wires tensored with on the ancilla wires and with on a trivial environment. Here is first reindexed to one-block tuples, i.e. tuple string . Every other record gets .
- The run. executes with the Pauli faults of . At each actual location with , conjugate by on its first wire and on its second wire; this comes after prep, gate and wait actions, and before measurement projections.
- The outcomes. is the number of measurement locations of . The sum keeps exactly the outcome records whose decoded bit equals .
- The trace. is the full trace over .
No condition (density matrix or otherwise) is imposed on .
QAlgorithms.FTProtocol.ecOp
The protocol. Fix a protocol with:
- a block size and an ancilla count ;
- an error-correction circuit , a located circuit on qubits.
The definition. For a Pauli fault arrangement , is the map sending a complex matrix indexed by -bit strings to the matrix indexed by -bit strings obtained as follows:
- Embed. Reindex to one-block tuples (). Then embed it as on the first wires (data) tensored with on the last wires (ancillas) and with on a trivial environment. This is the split of . The embedded matrix is assigned to the empty outcome record; every other record gets .
- Run. Run with the Pauli faults of . At each actual location with , conjugate by on its first wire and on its second wire (if any); this comes after prep, gate and wait actions, and before measurement projections.
- Sum over outcomes. Sum the branch matrices over all outcome records of length equal to the number of measurement locations of ; no record is excluded.
- Trace out ancillas. Take the partial trace over the ancilla wires and the trivial environment.
- Reindex back. Reindex back to -bit strings ( constant tuple ).
No condition is imposed on , and the output need not be normalized.
QAlgorithms.FTProtocol.filterOp
This definition is relative to a fixed fault-tolerance protocol . From it uses only the number of physical qubits per code block and a code subspace . The basis of is indexed by -bit strings.
For a natural number , define the filter space as the complex linear span of all vectors such that:
- ;
- is a Pauli-string matrix with and each ;
- has weight at most , meaning at most of the factors differ from .
Let be the matrix of the orthogonal projection onto . The filter operation is the map on all complex matrices given by conjugation:
The second equality holds because is Hermitian.
Edge cases:
- For , the only Pauli strings are scalar multiples , so and is the projector onto .
- If , then for every .
- If and , all Pauli strings are allowed. Their span applied to is the whole space, so .
QAlgorithms.FTProtocol.IsFaultTolerant
The protocol. This is a property of a fault-tolerance protocol , which consists of the following data:
- natural numbers (data qubits per block), (fault budget) and (ancilla qubits per block);
- a subspace ;
- a complex matrix ;
- an arbitrary map from complex matrices to complex matrices;
- for every location kind , a "gadget" circuit on wires;
- an error-correction circuit on wires;
- a classical map from bit lists to bits.
The location kinds are preparation, Hadamard, , CNOT, measurement and wait. The arity is for CNOT and otherwise.
Blocks. In a circuit on wires, block consists of wires . Its first wires are the data wires and its last wires are the ancilla wires.
Fault arrangements. A circuit is a list of steps. Each step is a list of locations, and a location has a kind, an ordered tuple of distinct wires, and a classical condition. A location is addressed by the pair (step index, position within the step).
A fault arrangement assigns to every address either nothing or a pair of single-qubit Paulis. The number of faults is the number of actual locations of that receive a pair. Values of at addresses that are not locations of are ignored.
Noisy run. Running a circuit with faults means executing on a classical–quantum state, that is, matrices indexed by measurement-outcome records, with a trivial one-dimensional environment. At each faulty location, conjugation by is inserted on its first wire, and by on its second wire for a CNOT. This insertion happens:
- after the location's ideal action for preparations (reset to ), gates and waits;
- before the outcome projection for measurements.
Gate locations act only when their classical condition on earlier outcomes holds.
Derived operations. Four objects are built from noisy runs.
- Gadget operation . For a matrix on data blocks:
- tensor with on all ancilla wires;
- run with faults ;
- sum the result over all outcome records;
- trace out the ancillas.
- EC operation . The same construction with the single-block circuit .
- Prepared state . Run from on all wires, sum over all records, and trace out the ancillas.
- Measurement functional . Tensor with zero ancillas and run with faults . Sum over exactly those outcome records with , and take the trace.
Notation.
- , where is the orthogonal projector onto .
- For maps on single-block matrices, is defined by applying the tensor product to matrix units and extending linearly:
- is the ideal gate: for Hadamard, , CNOT with the first qubit as control, and for wait.
- A superoperator is a channel if, for some , it equals for all , with .
- Equalities between maps are equalities on all complex matrices, not only on density matrices.
is fault-tolerant iff all of the following hold.
- Code. , and every matrix acting on at most qubits is detectable on .
- "Acting on at most qubits" means is some matrix on some tuple of wires inside a set of at most wires, tensored with the identity elsewhere.
- "Detectable" means there is a constant with for all unit .
- This conjunct forces .
- Encoding. and the range of is .
- Ideal decoder. is a channel. For every in the complex span of Pauli strings of weight and every unit ,
-
Well-formedness. Every circuit below is well-formed from an input live set to an output live set .
- The live sets evolve as and .
- In every step:
- distinct locations use disjoint wires;
- every wire in is used by some location;
- preparation locations use only wires outside ;
- all other locations use only wires in .
- The final live set equals .
The required live sets are:
- : from to the data wires;
- : from the data wires to ;
- each for : from the data wires of its blocks to the same set;
- : from the first of its wires to the same set.
-
Meas. For all and with , all bits and all matrices :
- Prep A. For all with : .
- Prep B. For all with : .
- Gate A. For all , all , and all with , where :
The same total index is used on every output block. 9. Gate B. Under the same hypotheses as Gate A:
- EC A. For all with : .
- EC B. For all and with : .
QAlgorithms.LocKind.leadCount
This function assigns a natural number to each of the six location kinds (preparation, Hadamard, , CNOT, measurement, wait). The arity of a kind is for CNOT and for every other kind.
- A preparation location gets the value .
- Every other kind gets its arity: for Hadamard, , measurement and wait, and for CNOT.
QAlgorithms.LocKind.trailCount
This function assigns a natural number to each of the six location kinds (preparation, Hadamard, , CNOT, measurement, wait). The arity of a kind is for CNOT and otherwise.
- A measurement location gets the value .
- Every other kind gets its arity: for preparation, Hadamard, and wait, and for CNOT.
QAlgorithms.ExRecFaults
For a location kind , an object of this type is a triple of fault arrangements.
A fault arrangement is a function assigning to every pair of natural numbers (step index, position within the step) either nothing or a pair of single-qubit Paulis from .
The three components are:
- : a family of fault arrangements, indexed by ;
- : a single fault arrangement;
- : a family of fault arrangements, indexed by .
The counts depend on :
- is for preparation and the arity of otherwise.
- is for measurement and the arity otherwise.
- The arity is for CNOT and otherwise.
So a preparation has no lead arrangements and one trail arrangement. A measurement has one lead arrangement and no trail arrangements. A CNOT has two of each, and Hadamard, and wait have one of each.
There are no constraints on the arrangements.
QAlgorithms.ExRecFaults.count
This definition uses three inputs:
- a fault-tolerance protocol , with error-correction circuit and, for each kind , a gadget circuit ;
- a location kind ;
- fault data for , with for and for . Here is for preparation and the arity otherwise, and is for measurement and the arity otherwise.
It also takes an arbitrary subset .
For a circuit and a fault arrangement , let be the number of actual locations of (addressed by step index and position within step) to which assigns a Pauli pair. Values of at non-location addresses do not count.
The count is the natural number
Trailing arrangements whose index lies in are not counted.
QAlgorithms.FTProtocol.leadOp
Fix a fault-tolerance protocol with data qubits and ancilla qubits per block and an error-correction circuit on wires. Let be a natural number and fault arrangements.
EC operation. For a fault arrangement , the map acts on a matrix as follows:
- tensor with on the ancillas;
- run with the Pauli faults prescribed by , inserted at each faulty location (after preparations, gates and waits; before measurement projections);
- sum the resulting matrices over all measurement-outcome records;
- partially trace out the ancillas.
The lead operation. It acts on matrices indexed by -tuples of -bit strings:
Here the tensor product of maps is defined through matrix units and extended linearly:
For , the index set has a single element and the product is empty, so maps a matrix to itself.
QAlgorithms.FTProtocol.trailOp
Fix a fault-tolerance protocol (with data qubits per block, ancilla qubits per block, and an error-correction circuit ). The inputs are:
- a natural number ;
- fault arrangements ;
- a subset .
For each , define a map on matrices:
- is the identity map if ;
- otherwise .
Here is obtained in four steps:
- tensor with ;
- run with the Pauli faults ;
- sum over all measurement-outcome records;
- trace out the ancillas.
The trail operation acts on matrices indexed by -tuples of -bit strings:
This is the tensor product of the , applied to matrix units and extended linearly.
QAlgorithms.FTProtocol.GateExRecCorrect
Setting. Fix a fault-tolerance protocol . It has data and ancilla qubits per block, an arbitrary decoding map from to complex matrices, gadget circuits , and an error-correction circuit .
Inputs.
- A location kind of arity : for CNOT and otherwise.
- Fault arrangements and for .
- A fault arrangement .
- A subset .
Operations involved.
- and , where is the identity map if and otherwise.
- is the EC operation: tensor with zero ancillas, run with Pauli faults , sum over outcome records, and trace out the ancillas.
- is the gadget operation: tensor data blocks with zero ancillas, run with faults , sum over all outcome records, and trace out the ancillas.
- of maps means applying them to matrix units and extending linearly.
- is , , or CNOT (first qubit as control) for those kinds, and the identity for wait, preparation and measurement.
The proposition. The two composite maps agree on every complex matrix indexed by -tuples of -bit strings:
The kind is not restricted to gates.
QAlgorithms.ExRecCorrect
This is a proposition about three inputs:
- a fault-tolerance protocol , with data and ancilla qubits per block, decoding map from to matrices, gadgets , and EC circuit ;
- a location kind ;
- fault data for , together with a subset of the trailing indices.
Operations involved.
- is the EC operation: tensor with zero ancillas, run with Pauli faults , sum over all outcome records, and trace out the ancillas.
- is the prepared state: run with faults from all-zero on its wires, sum over all records, and trace out the ancillas.
- is the measurement functional: tensor with zero ancillas, run with faults , sum over the outcome records whose decoded value is , and take the trace.
The definition proceeds by cases on .
- Preparation. There is one trailing index . Let be the identity if and otherwise. The condition is
- Measurement. There is one leading index and no trailing index, so is necessarily empty and is unused. The condition is that for both bits and every matrix ,
- Hadamard, , CNOT, wait. With arity ( for CNOT, otherwise), the condition is the following equality on all matrices indexed by -tuples of -bit strings:
The objects in this equality are:
- ;
- , where is the identity for and otherwise;
- is the gadget operation (tensor with zero ancillas, run with faults , sum over records, and trace out the ancillas);
- ;
- of maps is defined on matrix units and extended linearly.
QAlgorithms.pairedSuperop
The inputs are:
- natural numbers and ;
- a complex matrix , indexed by -bit strings;
- an arbitrary map from matrices indexed by to matrices of the same size, not assumed linear or a channel.
The result is a map on matrices indexed by -tuples of pairs . It is computed in four steps.
- Regroup. View as indexed by pairs with and .
- Apply blockwise. For each pair of bit strings , apply to the block and place the result back in that block:
- Conjugate. Form , with acting on the bit strings.
- Ungroup. Re-index back to -tuples of pairs.
When is linear, this is up to the regrouping of indices. When , the index sets are empty if .
QAlgorithms.FTProtocol.GateExRecCorrectStar
Setting. Fix a fault-tolerance protocol . It has data and ancilla qubits per block, gadget circuits , and an error-correction circuit .
Inputs.
- A natural number .
- A complex matrix , with rows indexed by and columns by -bit strings. No isometry or unitarity is assumed.
- A location kind of arity : for CNOT, otherwise.
- Fault arrangements and for , a fault arrangement , and a subset .
Operations involved.
- .
- , where is the identity for and otherwise.
- is the EC operation: tensor with zero ancillas, run with Pauli faults , sum over all outcome records, and trace out the ancillas.
- is the gadget operation, defined analogously with on blocks.
- , mapping matrices on blocks of qubits to matrices indexed by -tuples of pairs in .
- All tensor products of maps are defined on matrix units and extended linearly.
- is , , CNOT (first qubit as control), or the identity, according to .
The proposition. There exists a map on matrices indexed by satisfying two conditions.
- is a channel: for some and matrices with , we have for all .
- The following equality holds on all matrices indexed by -tuples of -bit strings:
Here acts on a matrix indexed by -tuples of pairs as follows:
- regroup the indices into (bit strings) × (strings over );
- apply to each block indexed by a pair of bit strings;
- conjugate by ;
- ungroup.
QAlgorithms.ExRecCorrectStar
This is a predicate defined by cases on a location kind . Its inputs are:
- a fault-tolerance protocol , which supplies:
- a code block of data qubits and ancilla qubits;
- a "decoder" superoperator;
- for each kind , a gadget circuit on qubits, where the arity is for cnot and otherwise;
- an error-correction circuit on qubits;
- a classical decoding map from bit lists to bits;
- a natural number ;
- an arbitrary complex matrix with rows indexed by and columns indexed by -bit strings (no isometry or unitarity condition is imposed);
- a fault record for kind , consisting of:
- "leading" Pauli arrangements , for ranging over indices if and indices otherwise;
- one gadget arrangement ;
- "trailing" arrangements , for ranging over indices if and indices otherwise;
- a set of trailing indices.
A Pauli arrangement assigns to each location id either nothing or a pair of single-qubit Paulis .
Operators used. Write .
- is computed as follows:
- embed the -qubit operator on the data wires of , with the ancillas set to ;
- run with Pauli faults . At each location where gives , conjugate by on its first wire and on its other wire. This happens after the location's action for preparations and gates, and before the projection for measurements;
- sum the resulting unnormalized operators over all complete measurement-outcome strings;
- trace out the ancillas.
- is the analogous output of run from the all-zero state.
- is the analogous superoperator of on data blocks.
- is the trace of the summed output of on input (ancillas zero). The sum is restricted to outcome strings with .
Case . Let be the identity map if trailing index belongs to , and otherwise. The condition is that there is a density matrix on (positive semidefinite, trace ) with
For no such exists, so in that case this branch is false.
Case . Here is irrelevant. The condition is that for every and every -qubit complex matrix (not only density matrices),
The right-hand side is the entry of the partial trace over the second factor.
Cases . Let . Define:
- ;
- , where is the identity if and otherwise.
Here of superoperators on blocks is defined linearly via matrix units. The condition is that there exists a quantum channel on such that, as maps on all matrices,
A quantum channel here means a map given by some finite Kraus family with . In the right-hand side:
- outputs on , which is regrouped as ;
- conjugates the first factor by the ideal gate , which is the Hadamard , , CNOT (first wire control), or the identity for wait;
- acts on the second factor.
import Definitions.Def_QAlgorithms_Defs_LocCircuit
/-!
# Fault-tolerant protocols: gadgets, ideal and *-decoders, Defs. 1–5, ExRecs and their
correctness (shared definition layer)
D. Gottesman, *An introduction to quantum error correction and fault-tolerant quantum
computation* (arXiv:0904.2557), cited "Gottesman intro p.N" (PDF pages), §§4.2, 5.1–5.2.
Model. A protocol uses one `[[n, 1, 2t + 1]]` code (p.19). Each gadget is a concrete circuit of
locations; a gadget for a location acting on `k` blocks runs on `k · (n + A)` qubits, where
physical qubit (block `i`, position `j`) is wire `finProdFinEquiv (i, j)`, positions `j < n` are
the block's data qubits and `n ≤ j < n + A` its ancillas. The superoperator a gadget implements
under a Pauli fault arrangement (p.20: faults are Pauli errors) is computed from
`LocCircuit.run`: the input on the data qubits, the ancillas in `|0⟩`, the measurement records
summed over, the ancillas traced out. All the diagram equations of Defs. 2–5 and 8 are equalities
of superoperators, i.e. on every input operator ("for all input states, including superpositions
and parts of entangled states", p.38).
-/
namespace QAlgorithms
open scoped Matrix
/-- Gottesman intro p.19 (Def. 1, §4.2), p.20 and p.33 (Def. 6): the data of a fault-tolerant
protocol for one `[[n, 1, 2t + 1]]` code: block length `n`, number `t` of errors corrected,
number `A` of ancillas per block, the code, its encoding isometry, the ideal decoder, a gadget for
every type of location (the wait gadget is the gate gadget for `U = I`, p.20), the error-correction
gadget, and the classical decoding of the measurement gadget's outcomes to the logical outcome. -/
structure FTProtocol where
n : ℕ
t : ℕ
A : ℕ
code : Submodule ℂ (EuclideanSpace ℂ (Qubits n))
enc : Matrix (Qubits n) Bool ℂ
dec : Superop (Qubits n) Bool
gadget : (κ : LocKind) → LocCircuit (κ.arity * (n + A))
ec : LocCircuit (n + A)
measDecode : List Bool → Bool
/-- Gottesman intro p.19 (§4.2: one encoded qubit per block): `enc` encodes one qubit into the
code `C`: it is an isometry (`enc† enc = I`) with range `C`. -/
def IsEncodingOf {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n)))
(enc : Matrix (Qubits n) Bool ℂ) : Prop :=
encᴴ * enc = 1 ∧ LinearMap.range (Matrix.toEuclideanLin enc) = C
/-- Gottesman intro p.19 (Def. 1: "a map constructed by taking the input state and performing a
decoding operation (including error correction) consisting of a circuit with no faulty
locations"): `D` is an ideal decoder for the encoding `enc` correcting `t` errors: a quantum
operation from one block to one qubit that maps `E (enc ψ)` back to `ψ` for every error `E` in the
span of the Pauli errors of weight `≤ t` and every normalized one-qubit state `ψ` (weighted by
`‖E enc ψ‖²`; by linearity this covers mixed and entangled inputs). Its action outside the
`t`-correctable inputs is unconstrained (any fault-free decoding circuit qualifies). -/
def IsIdealDecoder {n : ℕ} (enc : Matrix (Qubits n) Bool ℂ) (t : ℕ) (D : Superop (Qubits n) Bool) :
Prop :=
IsChannel D ∧ ∀ E ∈ pauliSpan n t, ∀ ψ : EuclideanSpace ℂ Bool, ‖ψ‖ = 1 →
D (pureDensity (act E (Matrix.toEuclideanLin enc ψ))) =
((‖act E (Matrix.toEuclideanLin enc ψ)‖ ^ 2 : ℝ) : ℂ) • pureDensity ψ
/-- Gottesman intro p.37 (§5.2: "the *-decoder is a unitary operation" whose extra output holds the
error syndrome) and p.38 (Lemma 2: "the ideal decoder is just the *-decoder with the error syndrome
discarded"): `W` is a *-decoder for the ideal decoder `D` with syndrome register `Fin σ`. -/
def IsStarDecoder {n σ : ℕ} (D : Superop (Qubits n) Bool) (W : Matrix (Bool × Fin σ) (Qubits n) ℂ) :
Prop :=
Wᴴ * W = 1 ∧ W * Wᴴ = 1 ∧ ∀ ρ, traceRight (W * ρ * Wᴴ) = D ρ
/-- The block layout of a gadget on `k` blocks: qubit `finProdFinEquiv (i, j)` is position `j` of
block `i`; positions `< n` are data, the others ancillas. -/
def blockLayout (k n A : ℕ) : Qubits (k * (n + A)) ≃ (Fin k → Qubits n) × (Fin k → Qubits A) :=
(Equiv.arrowCongr finProdFinEquiv.symm (Equiv.refl Bool)).trans
((Equiv.curry (Fin k) (Fin (n + A)) Bool).trans
((Equiv.arrowCongr (Equiv.refl (Fin k)) (qubitsAppendEquiv n A)).trans
(Equiv.arrowProdEquivProdArrow (Fin k) (fun _ => Qubits n) (fun _ => Qubits A))))
/-- The layout of the error-correction gadget on one block: positions `< n` are data. -/
def singleLayout (n A : ℕ) : Qubits (n + A) ≃ (Fin 1 → Qubits n) × (Fin 1 → Qubits A) :=
(qubitsAppendEquiv n A).trans
(Equiv.prodCongr (Equiv.funUnique (Fin 1) (Qubits n)).symm (Equiv.funUnique (Fin 1) (Qubits A)).symm)
/-- The data qubits of a gadget on `k` blocks. -/
def blockDataWires (k n A : ℕ) : Finset (Fin (k * (n + A))) :=
Finset.univ.image fun p : Fin k × Fin n => finProdFinEquiv (p.1, Fin.castAdd A p.2)
/-- The data qubits of the error-correction gadget. -/
def ecDataWires (n A : ℕ) : Finset (Fin (n + A)) :=
Finset.univ.image (Fin.castAdd A)
/-- The input operator `X` of the blocks' data placed on the data qubits, the ancillas in
`|0…0⟩⟨0…0|`, trivial environment. -/
def embedVia {N k n A : ℕ} (L : Qubits N ≃ (Fin k → Qubits n) × (Fin k → Qubits A))
(X : Matrix (Fin k → Qubits n) (Fin k → Qubits n) ℂ) :
Matrix (Qubits N × Fin 1) (Qubits N × Fin 1) ℂ :=
Matrix.of fun p p' =>
if (L p.1).2 = (fun _ _ => false) ∧ (L p'.1).2 = (fun _ _ => false) then X (L p.1).1 (L p'.1).1
else 0
/-- The partial trace over the ancillas and the environment, keeping the blocks' data. -/
def traceVia {N k n A : ℕ} (L : Qubits N ≃ (Fin k → Qubits n) × (Fin k → Qubits A))
(Y : Matrix (Qubits N × Fin 1) (Qubits N × Fin 1) ℂ) :
Matrix (Fin k → Qubits n) (Fin k → Qubits n) ℂ :=
Matrix.of fun x x' => ∑ a : Fin k → Qubits A, ∑ e : Fin 1, Y (L.symm (x, a), e) (L.symm (x', a), e)
/-- Gottesman intro p.20: the (unnormalized) state a gadget leaves under the Pauli arrangement
`fa`, started in `ρin`, summed over the measurement records accepted by `B`. -/
noncomputable def gadgetOut {N : ℕ} (G : LocCircuit N) (fa : PauliArrangement)
(ρin : Matrix (Qubits N × Fin 1) (Qubits N × Fin 1) ℂ) (B : List Bool → Bool) :
Matrix (Qubits N × Fin 1) (Qubits N × Fin 1) ℂ :=
∑ r : Fin G.measCount → Bool,
if B (List.ofFn r) then G.run (pauliErr G fa) (fun r' => if r' = [] then ρin else 0) (List.ofFn r)
else 0
/-- The number of faulty locations of a gadget under a Pauli arrangement (the `s` of its
diagram, p.20). -/
def faultCount {N : ℕ} (G : LocCircuit N) (fa : PauliArrangement) : ℕ :=
(faultyLocs G fa).card
/-- Gottesman intro p.20 (Def. 4) and p.35 (Def. 8): the location types handled as gates: `H`,
`R_{π/8}`, CNOT and wait (the wait gadget being the gate gadget for `U = I`). -/
def LocKind.IsGateOrWait (κ : LocKind) : Prop :=
κ = .had ∨ κ = .tgate ∨ κ = .cnot ∨ κ = .wait
namespace FTProtocol
variable (P : FTProtocol)
/-- Gottesman intro pp.20–21: the superoperator on the `k` input blocks implemented by the gadget
for the gate (or wait) location type `κ` under the Pauli arrangement `fa`. -/
noncomputable def gateOp (κ : LocKind) (fa : PauliArrangement) :
Superop (Fin κ.arity → Qubits P.n) (Fin κ.arity → Qubits P.n) :=
fun X => traceVia (blockLayout κ.arity P.n P.A)
(gadgetOut (P.gadget κ) fa (embedVia (blockLayout κ.arity P.n P.A) X) fun _ => true)
/-- Gottesman intro p.21 (Def. 3): the block state output by the preparation gadget under `fa`
(it takes no input: every qubit is prepared inside it). -/
noncomputable def prepState (fa : PauliArrangement) : Matrix (Qubits P.n) (Qubits P.n) ℂ :=
(traceVia (blockLayout 1 P.n P.A)
(gadgetOut (P.gadget .prep) fa (Matrix.kronecker (pureDensity (zeroKet _)) 1) fun _ => true)).submatrix
(fun y _ => y) (fun y _ => y)
/-- Gottesman intro p.20 (Def. 2): the measurement gadget under `fa` as an instrument on one
block: the weight of the decoded logical outcome `β` (`false` = `|0⟩`) on the block operator `ρ`.
Since every qubit of the gadget is measured, nothing else remains; equality of these functionals on
every block operator is equality of the instruments ("the remainder of the computer is left in the
same relative state"). -/
noncomputable def measFunctional (fa : PauliArrangement) (β : Bool) :
Matrix (Qubits P.n) (Qubits P.n) ℂ → ℂ :=
fun ρ => (gadgetOut (P.gadget .meas) fa
(embedVia (blockLayout 1 P.n P.A) (ρ.submatrix (fun x => x 0) (fun x => x 0)))
fun r => decide (P.measDecode r = β)).trace
/-- Gottesman intro p.21 (Def. 5): the superoperator on one block implemented by the
error-correction gadget under `fa`. -/
noncomputable def ecOp (fa : PauliArrangement) : Superop (Qubits P.n) (Qubits P.n) :=
fun ρ => (traceVia (singleLayout P.n P.A)
(gadgetOut P.ec fa (embedVia (singleLayout P.n P.A) (ρ.submatrix (fun x => x 0) (fun x => x 0)))
fun _ => true)).submatrix (fun y _ => y) (fun y _ => y)
/-- Gottesman intro p.19 (Def. 1): the `r`-filter applied to a block. -/
noncomputable def filterOp (r : ℕ) : Superop (Qubits P.n) (Qubits P.n) :=
conjSuperop (filterProj P.code r)
/-- Gottesman intro pp.19–22 (Defs. 1–5): the protocol is fault tolerant. The code is an
`[[n, 1, 2t + 1]]` code with encoding `enc` and ideal decoder `dec`; every gadget is a well-formed
circuit whose live qubits at its two ends are the data qubits of its input and output blocks; and,
for every Pauli fault arrangement with `s` faulty locations in the gadget and all filter sizes
(`F_r` the `r`-filter, applied to each block separately):
* Meas (Def. 2): `r + s ≤ t` → the gadget after `F_r` has the outcome weights of ideal decoding
followed by a standard-basis measurement;
* Prep A, Prep B (Def. 3): `s ≤ t` → the output passes the `s`-filter, and decodes to `|0⟩`;
* Gate A, Gate B (Def. 4), for `H`, `R_{π/8}`, CNOT and wait: `s + Σ_i r_i ≤ t` → after the
`r_i`-filters on the inputs, the output passes the `(s + Σ r_i)`-filter on each block, and
decoding each block gives the ideal gate applied to the decoded inputs;
* EC A, EC B (Def. 5): `s ≤ t` → the output passes the `s`-filter, whatever the input;
`r + s ≤ t` → decoding after the gadget equals decoding before it, after `F_r`. -/
def IsFaultTolerant : Prop :=
IsQCode P.n 1 (2 * P.t + 1) P.code ∧ IsEncodingOf P.code P.enc ∧ IsIdealDecoder P.enc P.t P.dec ∧
(P.gadget .prep).IsWellFormed ∅ (blockDataWires 1 P.n P.A) ∧
(P.gadget .meas).IsWellFormed (blockDataWires 1 P.n P.A) ∅ ∧
(∀ κ : LocKind, κ.IsGateOrWait →
(P.gadget κ).IsWellFormed (blockDataWires κ.arity P.n P.A) (blockDataWires κ.arity P.n P.A)) ∧
P.ec.IsWellFormed (ecDataWires P.n P.A) (ecDataWires P.n P.A) ∧
-- Meas
(∀ (fa : PauliArrangement) (r : ℕ), r + faultCount (P.gadget .meas) fa ≤ P.t →
∀ (β : Bool) (ρ : Matrix (Qubits P.n) (Qubits P.n) ℂ),
P.measFunctional fa β (P.filterOp r ρ) = P.dec (P.filterOp r ρ) β β) ∧
-- Prep A
(∀ fa : PauliArrangement, faultCount (P.gadget .prep) fa ≤ P.t →
P.filterOp (faultCount (P.gadget .prep) fa) (P.prepState fa) = P.prepState fa) ∧
-- Prep B
(∀ fa : PauliArrangement, faultCount (P.gadget .prep) fa ≤ P.t →
P.dec (P.prepState fa) = pureDensity (ket false)) ∧
-- Gate A
(∀ κ : LocKind, κ.IsGateOrWait → ∀ (fa : PauliArrangement) (r : Fin κ.arity → ℕ),
faultCount (P.gadget κ) fa + ∑ i, r i ≤ P.t →
piSuperop (fun _ => P.filterOp (faultCount (P.gadget κ) fa + ∑ i, r i)) ∘ P.gateOp κ fa ∘
piSuperop (fun i => P.filterOp (r i)) =
P.gateOp κ fa ∘ piSuperop (fun i => P.filterOp (r i))) ∧
-- Gate B
(∀ κ : LocKind, κ.IsGateOrWait → ∀ (fa : PauliArrangement) (r : Fin κ.arity → ℕ),
faultCount (P.gadget κ) fa + ∑ i, r i ≤ P.t →
piSuperop (fun _ => P.dec) ∘ P.gateOp κ fa ∘ piSuperop (fun i => P.filterOp (r i)) =
conjSuperop κ.idealMatrix ∘ piSuperop (fun _ => P.dec) ∘ piSuperop (fun i => P.filterOp (r i))) ∧
-- EC A
(∀ fa : PauliArrangement, faultCount P.ec fa ≤ P.t →
P.filterOp (faultCount P.ec fa) ∘ P.ecOp fa = P.ecOp fa) ∧
-- EC B
(∀ (fa : PauliArrangement) (r : ℕ), r + faultCount P.ec fa ≤ P.t →
P.dec ∘ P.ecOp fa ∘ P.filterOp r = P.dec ∘ P.filterOp r)
end FTProtocol
/-- Gottesman intro p.34 (Def. 7): the number of leading EC steps of an ExRec (one per input
block; none for a preparation). -/
def LocKind.leadCount : LocKind → ℕ
| .prep => 0
| κ => κ.arity
/-- Gottesman intro p.34 (Def. 7): the number of trailing EC steps of an ExRec (one per output
block; none for a measurement). -/
def LocKind.trailCount : LocKind → ℕ
| .meas => 0
| κ => κ.arity
/-- Gottesman intro p.34 (Def. 7), p.35 (Def. 9) and p.38 (Def. 10): a Pauli fault arrangement of
an ExRec of type `κ`: one for each leading EC, one for the gadget, one for each trailing EC. -/
structure ExRecFaults (κ : LocKind) where
lead : Fin κ.leadCount → PauliArrangement
gad : PauliArrangement
trail : Fin κ.trailCount → PauliArrangement
/-- Gottesman intro p.35 (Def. 9) and p.38 (Def. 10): the number of faults in the ExRec, the
trailing ECs of the blocks in `trunc` being removed (truncation; `trunc = ∅` is the full ExRec). -/
def ExRecFaults.count (P : FTProtocol) {κ : LocKind} (F : ExRecFaults κ)
(trunc : Finset (Fin κ.trailCount)) : ℕ :=
∑ i, faultCount P.ec (F.lead i) + faultCount (P.gadget κ) F.gad +
∑ i ∈ Finset.univ.filter (fun i => i ∉ trunc), faultCount P.ec (F.trail i)
namespace FTProtocol
variable (P : FTProtocol)
/-- The leading EC steps of a gate ExRec, one on each input block. -/
noncomputable def leadOp {k : ℕ} (lead : Fin k → PauliArrangement) :
Superop (Fin k → Qubits P.n) (Fin k → Qubits P.n) :=
piSuperop fun i => P.ecOp (lead i)
/-- The trailing EC steps of a gate ExRec, one on each output block not in `trunc` (removed
there, Def. 10). -/
noncomputable def trailOp {k : ℕ} (trail : Fin k → PauliArrangement) (trunc : Finset (Fin k)) :
Superop (Fin k → Qubits P.n) (Fin k → Qubits P.n) :=
piSuperop fun j => if j ∈ trunc then (fun ρ => ρ) else P.ecOp (trail j)
/-- Gottesman intro p.35 (Def. 8, eq. (72)): a gate or wait ExRec is correct for the ideal
decoder. -/
def GateExRecCorrect (κ : LocKind) (lead trail : Fin κ.arity → PauliArrangement)
(gad : PauliArrangement) (trunc : Finset (Fin κ.arity)) : Prop :=
piSuperop (fun _ => P.dec) ∘ P.trailOp trail trunc ∘ P.gateOp κ gad ∘ P.leadOp lead =
conjSuperop κ.idealMatrix ∘ piSuperop (fun _ => P.dec) ∘ P.leadOp lead
end FTProtocol
/-- Gottesman intro p.35 (Def. 8, eqs. (72)–(74)) and p.38 (Def. 10, truncated ExRecs: "removing
the trailing EC step from each diagram"): the ExRec of type `κ` is correct for the fault
arrangement `F`. Gate and wait (72): decoding after the trailing ECs equals the ideal gate after
decoding after the leading ECs. Preparation (73): decoding after the trailing EC gives `|0⟩`.
Measurement (74): the gadget after the leading EC has the outcome weights of decoding after the
leading EC and measuring. -/
def ExRecCorrect (P : FTProtocol) :
(κ : LocKind) → ExRecFaults κ → Finset (Fin κ.trailCount) → Prop
| .prep, F, trunc =>
P.dec ((if (⟨0, by decide⟩ : Fin LocKind.prep.trailCount) ∈ trunc then (fun ρ => ρ)
else P.ecOp (F.trail ⟨0, by decide⟩)) (P.prepState F.gad)) = pureDensity (ket false)
| .meas, F, _ =>
∀ β : Bool, P.measFunctional F.gad β ∘ P.ecOp (F.lead ⟨0, by decide⟩) =
fun ρ => P.dec (P.ecOp (F.lead ⟨0, by decide⟩) ρ) β β
| .had, F, trunc => P.GateExRecCorrect .had F.lead F.trail F.gad trunc
| .tgate, F, trunc => P.GateExRecCorrect .tgate F.lead F.trail F.gad trunc
| .cnot, F, trunc => P.GateExRecCorrect .cnot F.lead F.trail F.gad trunc
| .wait, F, trunc => P.GateExRecCorrect .wait F.lead F.trail F.gad trunc
/-- Gottesman intro p.38 (eq. (83): "`U` ⊗ some operation `V` on the error syndrome"): the
superoperator `ρ ↦ U ρ U†` on the decoded qubits tensored with `V` on the syndrome registers,
acting on `k` (qubit, syndrome) pairs. -/
noncomputable def pairedSuperop {k σ : ℕ} (U : Matrix (Fin k → Bool) (Fin k → Bool) ℂ)
(V : Superop (Fin k → Fin σ) (Fin k → Fin σ)) :
Superop (Fin k → Bool × Fin σ) (Fin k → Bool × Fin σ) :=
fun X =>
(conjSuperop (Matrix.kronecker U (1 : Matrix (Fin k → Fin σ) (Fin k → Fin σ) ℂ))
(idTensorSuperop (R := Fin k → Bool) V
(X.submatrix (Equiv.arrowProdEquivProdArrow (Fin k) (fun _ => Bool) (fun _ => Fin σ)).symm
(Equiv.arrowProdEquivProdArrow (Fin k) (fun _ => Bool) (fun _ => Fin σ)).symm))).submatrix
(Equiv.arrowProdEquivProdArrow (Fin k) (fun _ => Bool) (fun _ => Fin σ))
(Equiv.arrowProdEquivProdArrow (Fin k) (fun _ => Bool) (fun _ => Fin σ))
namespace FTProtocol
variable (P : FTProtocol)
/-- Gottesman intro p.38 (eq. (83)): a gate or wait ExRec is correct for the *-decoder `W`: for
some quantum operation `V` on the syndrome registers, the *-decoders after the trailing ECs give
the ideal gate on the decoded qubits and `V` on the syndromes, applied after the *-decoders after
the leading ECs. -/
def GateExRecCorrectStar {σ : ℕ} (W : Matrix (Bool × Fin σ) (Qubits P.n) ℂ) (κ : LocKind)
(lead trail : Fin κ.arity → PauliArrangement) (gad : PauliArrangement)
(trunc : Finset (Fin κ.arity)) : Prop :=
∃ V : Superop (Fin κ.arity → Fin σ) (Fin κ.arity → Fin σ), IsChannel V ∧
piSuperop (fun _ => conjSuperop W) ∘ P.trailOp trail trunc ∘ P.gateOp κ gad ∘ P.leadOp lead =
pairedSuperop κ.idealMatrix V ∘ piSuperop (fun _ => conjSuperop W) ∘ P.leadOp lead
end FTProtocol
/-- Gottesman intro p.38 (eq. (83) and "the definitions for preparation and measurement ExRecs are
similar; for the preparation ExRec, the error syndrome is brought in as a separate input on the RHS
of the definition, and for the measurement ExRec, the error syndrome is discarded immediately after
being produced"), with Def. 10's truncation: the ExRec is correct for the *-decoder `W`. -/
def ExRecCorrectStar (P : FTProtocol) {σ : ℕ} (W : Matrix (Bool × Fin σ) (Qubits P.n) ℂ) :
(κ : LocKind) → ExRecFaults κ → Finset (Fin κ.trailCount) → Prop
| .prep, F, trunc =>
∃ τ : Matrix (Fin σ) (Fin σ) ℂ, IsDensityMatrix τ ∧
conjSuperop W ((if (⟨0, by decide⟩ : Fin LocKind.prep.trailCount) ∈ trunc then (fun ρ => ρ)
else P.ecOp (F.trail ⟨0, by decide⟩)) (P.prepState F.gad)) =
Matrix.kronecker (pureDensity (ket false)) τ
| .meas, F, _ =>
∀ β : Bool, P.measFunctional F.gad β ∘ P.ecOp (F.lead ⟨0, by decide⟩) =
fun ρ => traceRight (W * P.ecOp (F.lead ⟨0, by decide⟩) ρ * Wᴴ) β β
| .had, F, trunc => P.GateExRecCorrectStar W .had F.lead F.trail F.gad trunc
| .tgate, F, trunc => P.GateExRecCorrectStar W .tgate F.lead F.trail F.gad trunc
| .cnot, F, trunc => P.GateExRecCorrectStar W .cnot F.lead F.trail F.gad trunc
| .wait, F, trunc => P.GateExRecCorrectStar W .wait F.lead F.trail F.gad trunc
/-! ### Sanity tests -/
example {k n A : ℕ} (z : Qubits (k * (n + A))) (i : Fin k) (j : Fin n) :
(blockLayout k n A z).1 i j = z (finProdFinEquiv (i, Fin.castAdd A j)) := rfl
example {k n A : ℕ} (z : Qubits (k * (n + A))) (i : Fin k) (a : Fin A) :
(blockLayout k n A z).2 i a = z (finProdFinEquiv (i, Fin.natAdd n a)) := rfl
example {n A : ℕ} (z : Qubits (n + A)) (j : Fin n) :
(singleLayout n A z).1 0 j = z (Fin.castAdd A j) := rfl
example : LocKind.leadCount .prep = 0 ∧ LocKind.trailCount .meas = 0 ∧
LocKind.leadCount .cnot = 2 := ⟨rfl, rfl, rfl⟩
example {N : ℕ} (G : LocCircuit N) : faultCount G (fun _ => none) = 0 := by
simp [faultCount, faultyLocs]
example (P : FTProtocol) (κ : LocKind) (F : ExRecFaults κ) (h : ∀ i, F.lead i = fun _ => none)
(hg : F.gad = fun _ => none) : F.count P Finset.univ = 0 := by
simp [ExRecFaults.count, h, hg, faultCount, faultyLocs]
end QAlgorithms