Pauli group, weights, quantum codes, stabilizers, CSS codes, r-filters
DefinitionQAlgorithms_Defs_QECCPauli group, weights, quantum codes, stabilizers, CSS codes, r-filters
QAlgorithms.opsWeight
For and a tuple of Pauli labels from , the weight is the number of positions with :
For the weight is .
QAlgorithms.Stabilizer.PauliString.weight
A Pauli string on qubits is a pair , where is a phase exponent and is a tuple of labels in . Its weight is . The phase is ignored.
QAlgorithms.pauliOps
For a tuple of Pauli labels, this is the complex matrix of the Pauli string with phase exponent . Its entries, for , are
that is, . The single-qubit matrices, with row and column index meaning , are
For the result is the matrix .
QAlgorithms.pauliSpan
For , this is the complex linear span, inside the space of complex matrices, of all Pauli-string matrices of weight at most :
Here means raised to the representative of in . The case gives the scalar multiples of the identity.
QAlgorithms.pauliGroup
For , this is the subgroup of the unitary group generated by every unitary whose matrix equals some Pauli-string matrix
with taken as its representative in . The Pauli matrices are as given under pauliOps.
QAlgorithms.IsStabilizerGroup
For and a subgroup of the unitary group , the predicate holds exactly when all three of the following hold:
- is contained in the -qubit Pauli group, i.e. the subgroup of generated by all matrices ;
- is abelian: for all ;
- no element of has matrix equal to .
QAlgorithms.stabilizedSpace
For and any subgroup of the unitary group , this is the complex subspace of (indexed by ) given by
No hypothesis on is imposed, for example that it is a stabilizer group. If is the trivial group, is all of . If contains , then .
QAlgorithms.pauliCentralizer
For and any subgroup of , this is the subgroup
Here is the subgroup of generated by all matrices , with and .
QAlgorithms.phaseMultiples
For and any subgroup of , this is the set of unitaries for which there exist and with
where is taken as its representative in . Equivalently, it is the set of all and for . It is defined only as a set, not as a subgroup.
QAlgorithms.pauliSyndrome
Inputs.
- .
- A family of unitary matrices. Rows and columns are indexed by -bit strings .
- A single unitary of the same size.
Output. The function returns a vector whose -th entry is
Remarks.
- The test is literal matrix commutation, with no allowance for phases. Entry is assigned whenever and fail to commute exactly, whether they anticommute or stand in any other relation.
- Nothing is assumed about the or beyond unitarity. In particular, they need not be Pauli operators.
- When the result is the empty vector.
QAlgorithms.ActsWithin
Inputs.
- .
- A finite set of wires.
- An arbitrary complex matrix , indexed by -bit strings.
Definition. The predicate holds iff there exist:
- some ,
- an injective map whose image is contained in , and
- an arbitrary complex matrix (not required to be unitary, Hermitian, or anything else),
such that is the embedding of on the wires . Entrywise, for ,
Here is the -bit string . In words, is acting on the wires , in that order, tensored with the identity on all remaining wires.
Degenerate case. is allowed. Then is a scalar and . So every scalar multiple of the identity satisfies the predicate for every , including .
QAlgorithms.ActsOnAtMost
Inputs.
- .
- An arbitrary complex matrix .
Definition. The predicate holds iff there is a set of wires with such that acts within . Expanding the previous definition, this means:
for some arbitrary complex matrix placed, via an injective wire map, on wires lying in , with acting as the identity on every other wire.
Remarks.
- For the predicate holds exactly for the scalar multiples of the identity.
- For it holds for every . One can take to be all wires and the identity map, which gives .
QAlgorithms.Corrects
Inputs.
- A finite index type with decidable equality.
- A complex linear subspace .
- An arbitrary set of complex matrices. These need not be unitary.
Definition. The predicate holds iff there exists a map from matrices to matrices satisfying two conditions.
- is a channel. There exist and matrices with
- corrects every error in . For every and every with ,
Here denotes the matrix with entries .
Edge cases.
- If , both sides of the condition are .
- If or , the second condition is vacuous. The predicate then only requires that some channel exist.
QAlgorithms.IsDetectable
Inputs.
- A finite index type .
- A complex subspace .
- An arbitrary complex matrix .
Definition. The predicate holds iff there is a single complex number such that every unit vector satisfies
The inner product is , conjugate-linear in the first slot.
Remarks.
- Only these diagonal expectation values are constrained. No condition on for distinct is stated explicitly.
- If , the predicate holds vacuously.
QAlgorithms.IsQCode
Inputs.
- .
- A complex subspace of the -qubit space .
Definition. satisfies the predicate iff both of the following hold.
-
Dimension. .
-
Detection. Every complex matrix that acts on at most qubits is detectable on . Concretely:
- "Acts on at most qubits" means with an arbitrary complex matrix on at most wires.
- "Detectable on " means there is a constant with for all unit .
Edge cases.
- is truncated subtraction, so is treated like . In both cases only scalar multiples of are required to be detectable, which always holds.
- If , every matrix must be detectable.
- Only this one-sided requirement is imposed. Nothing says some matrix acting on qubits fails to be detectable, so the predicate is monotone downward in .
- means is one-dimensional.
QAlgorithms.HasDistance
Inputs.
- .
- A complex subspace .
Definition. The predicate holds iff both of the following hold.
-
Detection below . Every arbitrary complex matrix acting on at most qubits (truncated subtraction) is detectable on . That is, takes the same value for all unit .
-
Failure at . There exists some complex matrix acting on at most qubits (that is, with on at most wires) that is not detectable on . That is, there are unit vectors with
Edge case .
- The first clause concerns only scalar multiples of .
- The second clause asks for a non-detectable matrix acting on qubits. Such a matrix is a scalar multiple of , and those are always detectable.
- So the predicate is false for .
QAlgorithms.IsNondegenerate
Inputs.
- .
- A complex subspace .
Pauli operators. Consider all assignments of weight at most . The weight of is the number of wires with . Each such gives the operator
with phase factor . The single-qubit matrices, in basis order , are
Definition. The predicate holds iff for every with , the Gram matrix
indexed by pairs of such weight- assignments , has nonzero determinant.
Edge cases.
- For the index set is the single all- assignment, and .
- If , the predicate holds vacuously.
QAlgorithms.binDual
Input. A linear subspace , where .
Definition. This is the subspace
that is, the dual code with respect to the standard dot product over .
The accompanying proof obligations only verify that this set contains and is closed under addition and scalar multiplication.
QAlgorithms.bitsOfZMod
Input. A vector .
Output. The -bit string whose bit on wire is (true) exactly when , and (false) when .
This is the identification , , applied coordinatewise. Wire of the string corresponds to coordinate of , and wire is the most significant bit.
QAlgorithms.cssCosetState
Inputs.
- A linear subspace .
- A vector .
Output. The -qubit vector
Here:
- is the dual code over .
- is computed in , i.e. bitwise XOR.
- is the computational-basis vector of the bit string .
Remarks.
- The vector is not normalized. Since the terms are distinct, its squared norm is .
- No hypothesis relates to any other code.
QAlgorithms.cssCode
Inputs. Two arbitrary linear subspaces .
Definition. This is the complex subspace of the -qubit space
the linear span of the unnormalized coset states as ranges over all of . Here is the dual of , and is the computational-basis vector of the bit string .
Remarks.
- No hypothesis such as is imposed.
- Different may give the same coset state, namely when they differ by an element of .
- is allowed, giving the span of the single vector .
QAlgorithms.cssZeroState
Setting.
- is a natural number, the number of qubits.
- is any -linear subspace of .
- The state space is with the standard inner product. For a bit string , is the standard basis vector at .
Definition. The vector is
where:
- is the binary dual of .
- is the bit string with exactly when .
This is the coset-state construction evaluated at the offset .
Edge cases.
- The sum runs over the dual , not over itself.
- There is no normalization factor: the vector has norm , which is not in general. It equals only when , i.e. , in which case the vector is .
- For the vector is the single basis vector of the one-dimensional space.
QAlgorithms.cssPlusState
Setting.
- is a natural number.
- is any -linear subspace of .
Definition. The vector in is
where has iff in .
Edge cases.
- The sum runs over itself, not over a dual.
- No Hadamard transform is involved.
- There is no normalization: the norm is . This is only when , giving .
QAlgorithms.errorSpace
Setting.
- is a natural number.
- is any complex linear subspace of .
- is a finite set of wire indices (wire is qubit ; wire is the most significant).
Definition. is the complex linear span of all vectors such that:
- , and
- is a complex matrix that "acts within ".
"Acts within ". This means there exist:
- some ,
- an injective map with image contained in , and
- an arbitrary complex matrix ,
such that is placed on wires . Explicitly:
Here denotes the -bit string .
Edge cases.
- , and hence , need not be unitary or invertible. Any matrix, including , is allowed.
- Taking gives , a scalar multiple of the identity, so always.
- For , only is possible, and the space equals .
- If , the space is .
QAlgorithms.errorSpaceWithRef
Setting.
- is a natural number.
- is any finite type, serving as a reference system.
- is a complex subspace of .
- is a finite set of wires.
Definition. The subspace of (system register first, reference second) is
where:
- , and
- is the span of , exactly as in the previous entry.
In other words, it is .
Edge case. If is empty, the ambient space and this subspace are both .
QAlgorithms.filterSpace
Setting.
- is a natural number.
- is a complex subspace of .
- is a natural number.
Definition. is the complex span of all vectors with , where is the matrix of a Pauli string of weight at most .
Pauli strings. A Pauli string consists of:
- a phase , and
- single-qubit operators .
Its matrix has entries
i.e. , using the usual matrices:
with index first. The weight of the string is the number of with .
Edge cases.
- The phase does not affect the span.
- The weight- string is , so for every , including , where the space equals .
- For , all Pauli strings are allowed.
QAlgorithms.filterProj
Setting.
- is a natural number.
- is a complex subspace of .
- is a natural number.
Definition. is the complex matrix, in the standard basis, of the orthogonal projection (with respect to the standard Hermitian inner product) onto .
is the span of the matrix of a Pauli string with at most non-identity factors, as in the previous entry.
Edge cases.
- If , the matrix is .
- Since , the projection fixes every vector of .
import Definitions.Def_QAlgorithms_Defs_Channel
/-!
# Pauli group, weights, quantum codes, stabilizers, CSS codes, r-filters
(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), §§2–4.
Conventions. The `n`-qubit Pauli operators are the frozen `Stabilizer.PauliString n` (overall
phase `i^c`, factors `I, X, Y, Z` with `Y = [[0, −i], [i, 0]] = iXZ`, intro Table 1; factor `q`
acts on wire `q`). The Pauli group `P_n` is a subgroup of Mathlib's group
`Matrix.unitaryGroup (Qubits n) ℂ`. A quantum code is a `Submodule` of
`EuclideanSpace ℂ (Qubits n)` (intro p.3: "the coding space"); codewords in conditions on
states are normalized (`‖ψ‖ = 1`). Binary vectors are `Fin n → ZMod 2`.
-/
namespace QAlgorithms
open scoped ComplexConjugate Matrix
open Stabilizer
/-- Gottesman intro p.3 (Table 1): the four single-qubit Pauli labels `I, X, Y, Z` form a finite
type (needed to index the Pauli operators of weight at most `t` by `Fin n → Pauli`). -/
instance Stabilizer.instFintypePauli : Fintype Stabilizer.Pauli where
elems := {.I, .X, .Y, .Z}
complete := fun p => by cases p <;> simp
/-- Gottesman intro p.4 (§2.1): the weight of the tensor product with factors `o`, "the number of
tensor factors which are not `I`". -/
def opsWeight {n : ℕ} (o : Fin n → Pauli) : ℕ :=
(Finset.univ.filter fun q => o q ≠ Pauli.I).card
/-- Gottesman intro p.4 (§2.1): the weight `wt(Q)` of a Pauli operator `Q ∈ P_n` (independent of
its overall phase). -/
def Stabilizer.PauliString.weight {n : ℕ} (P : PauliString n) : ℕ :=
opsWeight P.ops
/-- Gottesman intro p.3 (Table 1): the phase-`+1` Pauli matrix `P_1 ⊗ ⋯ ⊗ P_n` with factors `o`
(factor `q` on wire `q`). -/
noncomputable def pauliOps {n : ℕ} (o : Fin n → Pauli) : Matrix (Qubits n) (Qubits n) ℂ :=
(⟨0, o⟩ : PauliString n).toMatrix
/-- Gottesman intro pp.4–5 (§2.1) and p.19 (Def. 1): the linear span of the Pauli errors of
weight at most `t` ("the n-qubit Pauli group spans the space of `2^n × 2^n` matrices"; the span is
the space of all operators acting on at most `t` qubits). -/
noncomputable def pauliSpan (n t : ℕ) : Submodule ℂ (Matrix (Qubits n) (Qubits n) ℂ) :=
Submodule.span ℂ {M | ∃ P : PauliString n, P.weight ≤ t ∧ M = P.toMatrix}
/-- Gottesman intro p.3 (§2): the `n`-qubit Pauli group `P_n`, generated by the tensor products of
`I, X, Y, Z` with overall phases `±1, ±i`, as a subgroup of the unitary group. (The set of the
`4^{n+1}` matrices `i^c P_1 ⊗ ⋯ ⊗ P_n` is already a group; taking the closure keeps the definition
free of proof obligations.) -/
noncomputable def pauliGroup (n : ℕ) : Subgroup (Matrix.unitaryGroup (Qubits n) ℂ) :=
Subgroup.closure {U | ∃ P : PauliString n, (U : Matrix (Qubits n) (Qubits n) ℂ) = P.toMatrix}
/-- Gottesman intro p.9 (§2.3) and p.12: `S` is a stabilizer: an Abelian subgroup of `P_n` not
containing `−1` ("S must be Abelian and cannot contain −1, or the code is trivial"). -/
def IsStabilizerGroup {n : ℕ} (S : Subgroup (Matrix.unitaryGroup (Qubits n) ℂ)) : Prop :=
S ≤ pauliGroup n ∧ (∀ a ∈ S, ∀ b ∈ S, a * b = b * a) ∧
∀ M ∈ S, (M : Matrix (Qubits n) (Qubits n) ℂ) ≠ -1
/-- Gottesman intro p.9 (§2.3): the code `T(S)`, "the set of states `|ψ⟩` for which `M|ψ⟩ = |ψ⟩`
for all `M ∈ S`". -/
noncomputable def stabilizedSpace {n : ℕ} (S : Subgroup (Matrix.unitaryGroup (Qubits n) ℂ)) :
Submodule ℂ (EuclideanSpace ℂ (Qubits n)) :=
⨅ M ∈ S, LinearMap.ker
(Matrix.toEuclideanLin ((M : Matrix (Qubits n) (Qubits n) ℂ) - 1))
/-- Gottesman intro p.10 (§2.3): `N(S)`, the normalizer of `S` in the Pauli group, "which is in
this case equal to the centralizer, composed of Pauli operators which commute with `S`". -/
noncomputable def pauliCentralizer {n : ℕ} (S : Subgroup (Matrix.unitaryGroup (Qubits n) ℂ)) :
Subgroup (Matrix.unitaryGroup (Qubits n) ℂ) :=
pauliGroup n ⊓ Subgroup.centralizer (S : Set (Matrix.unitaryGroup (Qubits n) ℂ))
/-- Gottesman intro p.3 ("the phase of the operators used is generally not very important") and
p.10 (Thm 5): the elements of `S` up to an overall phase `±1, ±i`. Thm 5's `N(S) \ S` is read as
`N(S)` minus this set: taken literally, `−I ∈ N(S) \ S` has weight `0` and would force `d = 0`. -/
def phaseMultiples {n : ℕ} (S : Subgroup (Matrix.unitaryGroup (Qubits n) ℂ)) :
Set (Matrix.unitaryGroup (Qubits n) ℂ) :=
{U | ∃ c : ZMod 4, ∃ M ∈ S,
(U : Matrix (Qubits n) (Qubits n) ℂ) = Complex.I ^ c.val • (M : Matrix (Qubits n) (Qubits n) ℂ)}
/-- Gottesman intro p.10 (§2.3) and p.12 (proof of Lemma 1): the error syndrome of `E` with
respect to the generators `g_0, …, g_{a−1}`: bit `i` is `0` if the `i`th generator commutes with
`E` and `1` otherwise (for Pauli operators: if it anticommutes). -/
noncomputable def pauliSyndrome {n a : ℕ} (g : Fin a → Matrix.unitaryGroup (Qubits n) ℂ)
(E : Matrix.unitaryGroup (Qubits n) ℂ) : Fin a → ZMod 2 :=
open Classical in
fun i => if g i * E = E * g i then 0 else 1
/-- Gottesman intro p.5 (§2.1: "all t-qubit errors really does apply to all t-qubit errors, not
just unitary ones") and p.28 (Claim 1: errors only on the qubits of a set): the operator `E` acts
only on the qubits in `F`: it is `M ⊗ I` for some operator `M` (not necessarily unitary) on qubits
inside `F` (frozen `embedOp`: the identity on the other qubits). -/
def ActsWithin {n : ℕ} (F : Finset (Fin n)) (E : Matrix (Qubits n) (Qubits n) ℂ) : Prop :=
∃ (k : ℕ) (w : Fin k ↪ Fin n) (M : Matrix (Qubits k) (Qubits k) ℂ),
Set.range w ⊆ (F : Set (Fin n)) ∧ E = embedOp M w
/-- Gottesman intro p.5 (Thm 2) and p.7 (§2.2): `E` is a `t`-qubit error, an operator acting on
at most `t` qubits. -/
def ActsOnAtMost {n : ℕ} (t : ℕ) (E : Matrix (Qubits n) (Qubits n) ℂ) : Prop :=
∃ F : Finset (Fin n), F.card ≤ t ∧ ActsWithin F E
/-- Gottesman intro p.4 (§2.1: "determine which error occurred and invert it") and p.6 (§2.2):
the code `C` corrects the errors in `S`: one recovery operation `R` (a quantum operation) maps
`E|ψ⟩⟨ψ|E†` back to `|ψ⟩⟨ψ|` for every error `E ∈ S` and every normalized codeword `ψ`, up to the
weight `‖Eψ‖²` forced by trace preservation (an `E` annihilating `ψ` never arises). -/
def Corrects {ι : Type*} [Fintype ι] [DecidableEq ι] (C : Submodule ℂ (EuclideanSpace ℂ ι))
(S : Set (Matrix ι ι ℂ)) : Prop :=
∃ R : Superop ι ι, IsChannel R ∧ ∀ E ∈ S, ∀ ψ ∈ C, ‖ψ‖ = 1 →
R (pureDensity (act E ψ)) = ((‖act E ψ‖ ^ 2 : ℝ) : ℂ) • pureDensity ψ
/-- Gottesman intro p.7 (§2.2, eq. (34)): the operator `E` satisfies `⟨ψ|E|ψ⟩ = C′(E)` on the code:
the value is the same for all normalized codewords (`E` is detectable). -/
def IsDetectable {ι : Type*} [Fintype ι] (C : Submodule ℂ (EuclideanSpace ℂ ι))
(E : Matrix ι ι ℂ) : Prop :=
∃ c : ℂ, ∀ ψ ∈ C, ‖ψ‖ = 1 → inner ℂ ψ (act E ψ) = c
/-- Gottesman intro p.7 (§2.2): `C` is an `[[n, k, d]]` code: a subspace of `n` qubits of dimension
`2^k` (it encodes `k` qubits) of distance at least `d`, the distance being "the minimum weight of an
operator `E` that violates equation (34)": every operator on at most `d − 1` qubits is detectable.
(At `d = 0` the condition concerns `0`-qubit operators, i.e. scalars, which are always
detectable.) -/
def IsQCode (n k d : ℕ) (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) : Prop :=
Module.finrank ℂ C = 2 ^ k ∧ ∀ E : Matrix (Qubits n) (Qubits n) ℂ, ActsOnAtMost (d - 1) E →
IsDetectable C E
/-- Gottesman intro p.7 (§2.2) and p.10 (Thm 5): the code `C` has distance exactly `d`: every
operator on at most `d − 1` qubits is detectable, and some operator on `d` qubits is not. -/
def HasDistance {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) (d : ℕ) : Prop :=
(∀ E : Matrix (Qubits n) (Qubits n) ℂ, ActsOnAtMost (d - 1) E → IsDetectable C E) ∧
∃ E : Matrix (Qubits n) (Qubits n) ℂ, ActsOnAtMost d E ∧ ¬ IsDetectable C E
/-- Gottesman intro p.7 (§2.2, eq. (30)): the code is nondegenerate for `t` errors: "the matrix
`C_ab` in (30) has maximum rank", where `C_ab = ⟨ψ|E_a†E_b|ψ⟩` with `E_a, E_b` ranging over the basis
of the `t`-qubit errors formed by the tensor products of `I, X, Y, Z` with at most `t` non-identity
factors (phases dropped); full rank is `det ≠ 0`, required at every normalized codeword. -/
def IsNondegenerate {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) (t : ℕ) : Prop :=
∀ ψ ∈ C, ‖ψ‖ = 1 →
(Matrix.of fun a b : {o : Fin n → Pauli // opsWeight o ≤ t} =>
inner ℂ (act (pauliOps a.1) ψ) (act (pauliOps b.1) ψ)).det ≠ 0
/-- Gottesman intro p.11 (§2.4, CSS codes): the dual `C⊥` of a binary linear code `C`, "those words
which are orthogonal to the codewords of `C`" under the dot product over `F₂`. -/
def binDual {n : ℕ} (C : Submodule (ZMod 2) (Fin n → ZMod 2)) :
Submodule (ZMod 2) (Fin n → ZMod 2) where
carrier := {x | ∀ c ∈ C, c ⬝ᵥ x = 0}
add_mem' := by
intro x y hx hy c hc
rw [dotProduct_add, hx c hc, hy c hc, add_zero]
zero_mem' := by
intro c _
exact dotProduct_zero c
smul_mem' := by
intro a x hx c hc
rw [dotProduct_smul, hx c hc, smul_zero]
/-- Gottesman intro p.11 (§2.4): the computational-basis label `|v⟩` of a binary vector
`v ∈ F₂ⁿ` (bit `q` is `1` iff `v_q = 1`). -/
def bitsOfZMod {n : ℕ} (v : Fin n → ZMod 2) : Qubits n :=
fun q => decide (v q = 1)
/-- Gottesman intro p.11 (§2.4, eq. (51)): the CSS codeword `Σ_{w ∈ C2⊥} |u + w⟩`, unnormalized
("I omit normalization, which is generally unimportant", p.2). -/
noncomputable def cssCosetState {n : ℕ} (C2 : Submodule (ZMod 2) (Fin n → ZMod 2))
(u : Fin n → ZMod 2) : EuclideanSpace ℂ (Qubits n) :=
open Classical in
∑ w : binDual C2, ket (bitsOfZMod (u + (w : Fin n → ZMod 2)))
/-- Gottesman intro p.11 (§2.4): the CSS code of the binary codes `C1`, `C2`: the span of the
codewords (51) for `u ∈ C1`. (The construction assumes `C2⊥ ⊆ C1`, a hypothesis of the
statements.) -/
noncomputable def cssCode {n : ℕ} (C1 C2 : Submodule (ZMod 2) (Fin n → ZMod 2)) :
Submodule ℂ (EuclideanSpace ℂ (Qubits n)) :=
Submodule.span ℂ (Set.range fun u : C1 => cssCosetState C2 (u : Fin n → ZMod 2))
/-- Gottesman intro p.27 (§4.4, Fig. 3, the phase ancilla of Steane EC): the encoded `|0⟩` of the
CSS code, `Σ_{w ∈ C2⊥} |w⟩` (unnormalized). -/
noncomputable def cssZeroState {n : ℕ} (C2 : Submodule (ZMod 2) (Fin n → ZMod 2)) :
EuclideanSpace ℂ (Qubits n) :=
cssCosetState C2 0
/-- Gottesman intro p.27 (§4.4, Fig. 3, the bit-flip ancilla of Steane EC): the encoded
`|0⟩ + |1⟩` of the CSS code, the sum `Σ_{u ∈ C1} |u⟩` of all its coset states (unnormalized). -/
noncomputable def cssPlusState {n : ℕ} (C1 : Submodule (ZMod 2) (Fin n → ZMod 2)) :
EuclideanSpace ℂ (Qubits n) :=
open Classical in
∑ u : C1, ket (bitsOfZMod (u : Fin n → ZMod 2))
/-- Gottesman intro p.28 (§4.4, Claim 1: "errors only on qubits from `F`"): the span of the states
`E|c⟩` with `c` a codeword and `E` any operator acting only on the qubits of `F`. -/
noncomputable def errorSpace {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n)))
(F : Finset (Fin n)) : Submodule ℂ (EuclideanSpace ℂ (Qubits n)) :=
Submodule.span ℂ {v | ∃ (E : Matrix (Qubits n) (Qubits n) ℂ) (c : EuclideanSpace ℂ (Qubits n)),
ActsWithin F E ∧ c ∈ C ∧ v = act E c}
/-- Gottesman intro p.28 (§4.4): `errorSpace C F` tensored with a reference register `R` (the data
block may be entangled with the rest of the computer); the block is the first factor. -/
noncomputable def errorSpaceWithRef {n : ℕ} (R : Type*) [Fintype R]
(C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) (F : Finset (Fin n)) :
Submodule ℂ (EuclideanSpace ℂ (Qubits n × R)) :=
Submodule.span ℂ {x | ∃ v ∈ errorSpace C F, ∃ r : EuclideanSpace ℂ R, x = tensorVec v r}
/-- Gottesman intro p.19 (Def. 1): the subspace "spanned by all states of the form `Q|ψ⟩`, where
`|ψ⟩` is an arbitrary codeword and `Q` is a Pauli error of weight at most `r`". -/
noncomputable def filterSpace {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) (r : ℕ) :
Submodule ℂ (EuclideanSpace ℂ (Qubits n)) :=
Submodule.span ℂ {v | ∃ (P : PauliString n) (c : EuclideanSpace ℂ (Qubits n)),
P.weight ≤ r ∧ c ∈ C ∧ v = act P.toMatrix c}
/-- Gottesman intro p.19 (Def. 1): the `r`-filter, the (orthogonal) projector onto
`filterSpace C r`, as a matrix; it acts on a block state `ρ` as `conjSuperop (filterProj C r)`. -/
noncomputable def filterProj {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) (r : ℕ) :
Matrix (Qubits n) (Qubits n) ℂ :=
Matrix.toEuclideanLin.symm
((filterSpace C r).starProjection : EuclideanSpace ℂ (Qubits n) →ₗ[ℂ] EuclideanSpace ℂ (Qubits n))
/-! ### Sanity tests -/
example : Fintype.card Stabilizer.Pauli = 4 := rfl
example : opsWeight (![Pauli.X, Pauli.Y, Pauli.I] : Fin 3 → Pauli) = 2 := by decide
example {n : ℕ} (c : ZMod 4) : (⟨c, fun _ => Pauli.I⟩ : PauliString n).weight = 0 := by
simp [Stabilizer.PauliString.weight, opsWeight]
example : bitsOfZMod (![1, 0] : Fin 2 → ZMod 2) = ![true, false] := by decide
example {n : ℕ} (x : Fin n → ZMod 2) : x ∈ binDual (⊥ : Submodule (ZMod 2) (Fin n → ZMod 2)) := by
intro c hc
rw [(Submodule.mem_bot _).1 hc, zero_dotProduct]
example {n : ℕ} (C : Submodule ℂ (EuclideanSpace ℂ (Qubits n))) (c : ℂ) :
IsDetectable C (c • (1 : Matrix (Qubits n) (Qubits n) ℂ)) := by
refine ⟨c, fun ψ _ hψ => ?_⟩
have h : act (c • (1 : Matrix (Qubits n) (Qubits n) ℂ)) ψ = c • ψ := by
ext z; simp [act, Matrix.smul_mulVec]
rw [h, inner_smul_right, inner_self_eq_norm_sq_to_K, hψ]
simp
example {n : ℕ} (E : Matrix (Qubits n) (Qubits n) ℂ) (F : Finset (Fin n)) (hE : ActsWithin F E) :
ActsOnAtMost F.card E :=
⟨F, le_rfl, hE⟩
theorem embedOp_one_mem_actsWithin {n : ℕ} (F : Finset (Fin n)) :
ActsWithin F (1 : Matrix (Qubits n) (Qubits n) ℂ) :=
⟨0, ⟨Fin.elim0, fun a => Fin.elim0 a⟩, 1, by
rintro _ ⟨a, _⟩; exact Fin.elim0 a, (embedOp_one _).symm⟩
end QAlgorithms