Rem_1: Stabilizer Code Convention #
Statement #
Throughout this work, we consider an $[[n,k,d]]$ quantum low-density parity-check (qLDPC) stabilizer code on $n$ physical qubits, encoding $k$ logical qubits with distance $d$. The code is specified by a set of stabilizer checks $\{s_i\}$. A logical operator $L$ is a Pauli operator that commutes with all stabilizers but is not itself a stabilizer. By choosing an appropriate single-qubit basis for each physical qubit, we ensure that the logical operator $L$ being measured is a product of Pauli-$X$ matrices: $L = \prod_{v \in \text{supp}(L)} X_v$, where $\text{supp}(L)$ denotes the set of qubits on which $L$ acts non-trivially.
Main Definitions #
StabPauliType: The four single-qubit Pauli operators (I, X, Y, Z)PauliOp: A Pauli operator on n qubits (tensor product of single-qubit Paulis)StabilizerCode: An [[n,k,d]] stabilizer code specificationLogicalOp: A logical operator (commutes with stabilizers, not a stabilizer)XTypeLogical: A logical operator that is purely X-type (convention for L)
Key Properties #
XTypeLogical.support_eq: L acts as X on exactly supp(L)XTypeLogical.commutes_with_stabilizers: L commutes with all stabilizersXTypeLogical.not_in_stabilizer_group: L is not itself a stabilizer
Pauli Operators #
The four single-qubit Pauli operators
- I : StabPauliType
- X : StabPauliType
- Y : StabPauliType
- Z : StabPauliType
Instances For
Equations
- instReprStabPauliType = { reprPrec := instReprStabPauliType.repr }
Equations
- instReprStabPauliType.repr StabPauliType.I prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "StabPauliType.I")).group prec✝
- instReprStabPauliType.repr StabPauliType.X prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "StabPauliType.X")).group prec✝
- instReprStabPauliType.repr StabPauliType.Y prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "StabPauliType.Y")).group prec✝
- instReprStabPauliType.repr StabPauliType.Z prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "StabPauliType.Z")).group prec✝
Instances For
Instances For
Equations
Multiplication of Pauli types (ignoring phase)
Equations
- StabPauliType.I.mul x✝ = x✝
- x✝.mul StabPauliType.I = x✝
- StabPauliType.X.mul StabPauliType.X = StabPauliType.I
- StabPauliType.Y.mul StabPauliType.Y = StabPauliType.I
- StabPauliType.Z.mul StabPauliType.Z = StabPauliType.I
- StabPauliType.X.mul StabPauliType.Y = StabPauliType.Z
- StabPauliType.Y.mul StabPauliType.X = StabPauliType.Z
- StabPauliType.Y.mul StabPauliType.Z = StabPauliType.X
- StabPauliType.Z.mul StabPauliType.Y = StabPauliType.X
- StabPauliType.Z.mul StabPauliType.X = StabPauliType.Y
- StabPauliType.X.mul StabPauliType.Z = StabPauliType.Y
Instances For
Equations
- StabPauliType.instMul = { mul := StabPauliType.mul }
A Pauli type acts nontrivially iff it is not the identity
Equations
Instances For
A Pauli is X-type if it involves X (i.e., is X or Y)
Instances For
A Pauli is Z-type if it involves Z (i.e., is Z or Y)
Instances For
Two Paulis commute iff they are equal, one is identity, or they are both in {X,Z}
Equations
- StabPauliType.I.commutes q = true
- p.commutes StabPauliType.I = true
- StabPauliType.X.commutes StabPauliType.X = true
- StabPauliType.Y.commutes StabPauliType.Y = true
- StabPauliType.Z.commutes StabPauliType.Z = true
- StabPauliType.X.commutes StabPauliType.Z = false
- StabPauliType.Z.commutes StabPauliType.X = false
- StabPauliType.X.commutes StabPauliType.Y = false
- StabPauliType.Y.commutes StabPauliType.X = false
- StabPauliType.Y.commutes StabPauliType.Z = false
- StabPauliType.Z.commutes StabPauliType.Y = false
Instances For
Multi-qubit Pauli Operators #
A Pauli operator on n qubits is a function from qubit indices to Pauli types, together with a global phase (±1, ±i represented as ZMod 4)
- paulis : Fin n → StabPauliType
The Pauli type on each qubit
- phase : ZMod 4
The global phase: 0 = +1, 1 = +i, 2 = -1, 3 = -i
Instances For
The identity operator on n qubits
Equations
- PauliOp.identity n = { paulis := fun (x : Fin n) => StabPauliType.I, phase := 0 }
Instances For
A Pauli operator is purely X-type if it only contains I and X
Equations
- P.isPurelyXType = ∀ (i : Fin n), P.paulis i = StabPauliType.I ∨ P.paulis i = StabPauliType.X
Instances For
Construct a pure X-type operator from a set of qubits
Equations
- PauliOp.pureX S = { paulis := fun (i : Fin n) => if i ∈ S then StabPauliType.X else StabPauliType.I, phase := 0 }
Instances For
Stabilizer Codes #
A stabilizer group on n qubits is a subgroup of the Pauli group. For simplicity, we represent it as a set of generators (the stabilizer checks).
The generating stabilizer checks
- finite_generators : self.generators.Finite
Generators are finite
- generators_commute (s₁ s₂ : PauliOp n) : s₁ ∈ self.generators → s₂ ∈ self.generators → s₁.commutes s₂
All generators mutually commute
Instances For
An [[n, k, d]] stabilizer code specification
- n : ℕ
Number of physical qubits
- k : ℕ
Number of logical qubits encoded
- d : ℕ
Code distance
- stabilizers : StabilizerGroup self.n
The stabilizer group
Basic constraint: n ≥ k
Distance is positive
Instances For
A Pauli operator commutes with the stabilizer group iff it commutes with all generators
Equations
- C.commutesWithStabilizers P = ∀ s ∈ C.stabilizers.generators, P.commutes s
Instances For
The centralizer: all Paulis that commute with all stabilizers
Equations
- C.centralizer = {P : PauliOp C.n | C.commutesWithStabilizers P}
Instances For
A Pauli is in the stabilizer group if it can be generated by products of generators
Equations
- C.inStabilizerGroup P = ∃ (gens : Finset (PauliOp C.n)), ↑gens ⊆ C.stabilizers.generators ∧ (gens = ∅ → P = PauliOp.identity C.n) ∧ P ∈ C.stabilizers.generators ∨ P = PauliOp.identity C.n
Instances For
Logical Operators #
A logical operator for a stabilizer code:
- Commutes with all stabilizers
- Is not itself in the stabilizer group
The underlying Pauli operator
- commutes_with_stabilizers : C.commutesWithStabilizers self.op
Commutes with all stabilizers
- not_in_stabilizer_group : ¬C.inStabilizerGroup self.op
Not in the stabilizer group
Instances For
X-Type Logical Operator Convention #
An X-type logical operator: a logical that is purely X-type (only I and X Paulis). This captures the convention: L = ∏_{v ∈ supp(L)} X_v
- is_purely_xtype : self.op.isPurelyXType
The operator is purely X-type
Instances For
For an X-type logical, supp(L) = X-type support
For an X-type logical, the Z-type support is empty
Construct an X-type logical from a support set (assuming the properties hold)
Equations
- XTypeLogical.fromSupport C S h_commutes h_not_stab = { op := PauliOp.pureX S, commutes_with_stabilizers := h_commutes, not_in_stabilizer_group := h_not_stab, is_purely_xtype := ⋯ }
Instances For
The representation theorem: L = ∏_{v ∈ supp(L)} X_v (ignoring global phase). The Pauli content of L on each qubit matches pureX of the support.
LDPC Property #
A code is Low-Density Parity-Check (LDPC) if there's a constant bound on:
- The weight of each stabilizer check
- The number of checks each qubit participates in
- max_check_weight : ℕ
Maximum weight of any stabilizer check
- max_qubit_degree : ℕ
Maximum number of checks any qubit is in
- check_weight_bound (s : PauliOp C.n) : s ∈ C.stabilizers.generators → s.support.card ≤ self.max_check_weight
All checks have bounded weight
All qubits have bounded degree
Instances For
Summary of Convention #
The key convention established:
- We work with [[n,k,d]] qLDPC stabilizer codes
- Codes are specified by stabilizer checks {sᵢ}
- Logical operators commute with stabilizers but aren't stabilizers themselves
- The logical L being measured is always X-type: L = ∏_{v ∈ supp(L)} Xᵥ
- supp(L) is exactly the qubits where L acts nontrivially