Documentation

LeanPool.QECCertificates.GF2.HGPCleaning

HGP, part three: the cleaning argument and the X distance lower bound #

The first part gave the construction and CSS orthogonality, the second the compression identity $H_Xv=0 \iff H_1U=RH_2$, the transposed-code relation and the single-block weight lower bound. This part adds the cleaning/quotient argument for mixed blocks (both blocks nonzero at once), so that the X distance lower bound of the HGP holds for every nontrivial logical operator:

$$d_X \ge \min(d_1,\; d_2^\top),\qquad d_1 = \min\ker H_1,\quad d_2^\top = \min\ker H_2^\top.$$

1. The cleaning lemma (the core of this part) #

Let $v = (U,R) \in \ker H_X$, that is $H_1U = RH_2$, and let $|v|$ denote the weight.

Both are weight-counting arguments: the contradiction comes from the direct clash between "every kernel vector has weight at least the distance" and "the support of that vector is a subset of the support of $v$". No enumeration is needed.

2. Consistency (the cleaning certificate) #

Row cleaning gives $C_0$ with $C_0H_2 = U$; column cleaning makes every column of $\rho := R + H_1C_0$ lie in the column space of $H_1$, with $\rho H_2 = 0$. This part proves (exists_cleaning_cert) that

$$\text{the columns all lie in }\mathrm{col}(H_1)\;\wedge\;\rho H_2 = 0 \;\Longrightarrow\; \exists D,\; H_1D = \rho \;\wedge\; DH_2 = 0.$$

The construction is explicit: the columns of $\rho$ are read back through rowReduce (colList H₁) by col_decomp, the coefficients are the entries of the pivot rows, and then the preimage preimage is applied.

3. Assembly #

$C := C_0 + D$ satisfies both $CH_2 = U$ and $H_1C = R$, so $v = (CH_2,\, H_1C) = \sum_{a,d}C_{ad}\cdot(\text{row }(a,d)\text{ of }H_Z)$ lies in $\mathrm{row}\,H_Z$ (sum_smul_hgpHZ_apply + mem_spanL_hgpHZ_of_blocks).

Main results #

1. Row and column lists, and preimages #

def QECCertificates.matRowList {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) :
List (Vec k)

The rows of a matrix, as a list of Vec.

Equations
Instances For
    def QECCertificates.colList {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) :
    List (Vec m)

    The columns of a matrix, as a list of Vec (the vector length is the number of rows).

    Equations
    Instances For
      theorem QECCertificates.mem_matRowList {m k : ℕ} {M : Matrix (Fin m) (Fin k) (ZMod 2)} {y : Vec k} :
      y ∈ matRowList M ↔ ∃ (i : Fin m), (fun (j : Fin k) => M i j) = y
      theorem QECCertificates.exists_mulVec_of_mem_spanL_colList {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) {y : Vec m} (h : y ∈ spanL (colList M)) :
      ∃ (x : Vec k), M.mulVec x = y

      A vector in the column span is the image of right multiplication (the columns are the images of the unit vectors under that map).

      theorem QECCertificates.mulVec_mem_spanL_colList {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) (x : Vec k) :

      The image of right multiplication lies in the column span.

      theorem QECCertificates.exists_coeff_of_mem_spanL_matRowList {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) {y : Vec k} (h : y ∈ spanL (matRowList M)) :
      ∃ (co : Vec m), ∀ (j : Fin k), ∑ t : Fin m, co t * M t j = y j

      A vector in the row span is a linear combination of the rows with some coefficient vector: ∃ λ, ∀ j, Σ_t λ_t M_{tj} = y_j.

      noncomputable def QECCertificates.preimage {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) (y : Vec m) :
      Vec k

      The preimage of right multiplication: M *ᵥ preimage M y = y whenever y lies in the column span (see preimage_spec).

      Equations
      Instances For
        theorem QECCertificates.preimage_spec {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) {y : Vec m} (h : ∃ (x : Vec k), M.mulVec x = y) :
        M.mulVec (preimage M y) = y
        theorem QECCertificates.exists_mul_eq_of_rows_mem {m k p : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) (U : Matrix (Fin p) (Fin k) (ZMod 2)) (h : ∀ (a : Fin p), (fun (j : Fin k) => U a j) ∈ spanL (matRowList M)) :
        ∃ (C : Matrix (Fin p) (Fin m) (ZMod 2)), C * M = U

        Row decomposition: if every row of U lies in the row space of M, then U = C * M.

        2. Separation lemma: the row space is the orthogonal complement of the kernel #

        theorem QECCertificates.dot_eq_zero_of_mem_kerL_of_mem_spanL {n : ℕ} {L : List (Vec n)} {z u : Vec n} (hz : z ∈ kerL L) (hu : u ∈ spanL L) :
        u ⬝ᵥ z = 0

        A kernel vector is orthogonal to the whole row space.

        theorem QECCertificates.exists_ker_dot_ne_zero_of_not_mem {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) {y : Vec k} (h : y ∉ spanL (matRowList M)) :
        ∃ (z : Vec k), M.mulVec z = 0 ∧ y ⬝ᵥ z ≠ 0

        Separation lemma: a vector outside the row space has nonzero dot product with some kernel vector.

        The construction is explicit: reduce y against the output of the elimination, so that the residual y' is nonzero (otherwise y would lie in the row space) and vanishes on the pivot columns; take the free column j at which y' is nonzero, and kerVec D j is the required kernel vector (it is 1 on the free column j and 0 on the other free columns, while y' is nonzero only on free columns).

        theorem QECCertificates.mem_spanL_of_forall_dot_eq_zero {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) {y : Vec k} (h : ∀ (z : Vec k), M.mulVec z = 0 → y ⬝ᵥ z = 0) :

        Decidable form of the separation lemma: a vector orthogonal to the whole kernel lies in the row space.

        3. Weight counting: row-wise and column-wise dot products do not increase the weight #

        theorem QECCertificates.rowDot_hammingNorm_le {r₁ n₁ r₂ n₂ : ℕ} (v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2) (z : Vec n₂) :
        (hammingNorm fun (a : Fin n₁) => ∑ b : Fin n₂, v (Sum.inl (a, b)) * z b) ≤ hammingNorm v

        The weight after row-wise dot products is at most the weight of the whole vector (every row that is nonzero contributes one support point).

        theorem QECCertificates.colDot_hammingNorm_le {r₁ n₁ r₂ n₂ : ℕ} (v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2) (w : Vec r₁) :
        (hammingNorm fun (t : Fin r₂) => ∑ i : Fin r₁, v (Sum.inr (i, t)) * w i) ≤ hammingNorm v

        The weight after column-wise dot products is at most the weight of the whole vector (every column that is nonzero contributes one support point).

        4. The cleaning lemmas #

        theorem QECCertificates.blockL_rows_mem_of_small {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hcomp : H₁ * blockL v = blockR v * H₂) {d₁ : ℕ} (hd₁ : ∀ (w : Vec n₁), w ≠ 0 → H₁.mulVec w = 0 → d₁ ≤ hammingNorm w) (hsmall : hammingNorm v < d₁) (a : Fin n₁) :
        (fun (b : Fin n₂) => blockL v a b) ∈ spanL (matRowList H₂)

        Row cleaning: if $|v| < d_1$, every row of blockL v lies in the row space of H₂.

        The proof uses the matrix-level form of the compression identity: if some row has nonzero dot product with z ∈ ker H₂, then blockL v *ᵥ z ≠ 0, whereas H₁ *ᵥ (blockL v *ᵥ z) = (H₁ * blockL v) *ᵥ z = (blockR v * H₂) *ᵥ z = blockR v *ᵥ (H₂ *ᵥ z) = 0, which contradicts d₁.

        theorem QECCertificates.blockR_cols_mem_of_small {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hcomp : H₁ * blockL v = blockR v * H₂) {d₂T : ℕ} (hd₂ : ∀ (w : Vec r₂), w ≠ 0 → H₂.transpose.mulVec w = 0 → d₂T ≤ hammingNorm w) (hsmall : hammingNorm v < d₂T) (t : Fin r₂) :
        (fun (i : Fin r₁) => blockR v i t) ∈ spanL (colList H₁)

        Column cleaning: if $|v| < d_2^\top$, every column of blockR v lies in the column space of H₁.

        The dual matrix-level argument: the transposed-code identity for (blockR v)ᵀ *ᵥ w gives H₂ᵀ *ᵥ ((blockR v)ᵀ *ᵥ w) = (blockL v)ᵀ *ᵥ (H₁ᵀ *ᵥ w) = 0.

        5. Consistency: column decomposition and the cleaning certificate #

        theorem QECCertificates.col_decomp {m k : ℕ} (M : Matrix (Fin m) (Fin k) (ZMod 2)) (c : List (Vec m)) (hc : ∀ (j : Fin k), (fun (i : Fin m) => M i j) ∈ spanL c) (i : Fin m) (j : Fin k) :
        M i j = ∑ ri ∈ (rowReduce c).toFinset, M ri.2 j * ri.1 i

        Column decomposition (read back from the elimination): if every column of M lies in the span of the row list c, the pivot rows of the elimination output give an explicit set of coefficients: M i j = Σ_{ri} M ri.2 j * ri.1 i.

        theorem QECCertificates.exists_cleaning_cert {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {ρ : Matrix (Fin r₁) (Fin r₂) (ZMod 2)} (hcol : ∀ (j : Fin r₂), (fun (i : Fin r₁) => ρ i j) ∈ spanL (colList H₁)) (hrow : ρ * H₂ = 0) :
        ∃ (D : Matrix (Fin n₁) (Fin r₂) (ZMod 2)), H₁ * D = ρ ∧ D * H₂ = 0

        Cleaning certificate (consistency): a matrix ρ whose columns all lie in the column space of H₁ and which satisfies ρ H₂ = 0 can be written as H₁ D with D H₂ = 0, that is, it can be cleaned.

        Construction: D = Σ_{ri} preimage(ri.1) ⊗ (row ri.2 of ρ), where ri runs over the pivot rows of rowReduce (colList H₁) (col_decomp supplies the coefficients).

        6. Assembly: combinations of the rows of H_Z, and the main theorem #

        theorem QECCertificates.sum_smul_hgpHZ_apply {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) (C : Matrix (Fin n₁) (Fin r₂) (ZMod 2)) (c : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂) :
        (∑ p : Fin n₁ × Fin r₂, C p.1 p.2 • hgpHZ H₁ H₂ p) c = Sum.elim (fun (ab : Fin n₁ × Fin n₂) => (C * H₂) ab.1 ab.2) (fun (st : Fin r₁ × Fin r₂) => (H₁ * C) st.1 st.2) c

        A vector of the form (C H₂, H₁ C) is a linear combination of the rows of H_Z (computed entrywise).

        theorem QECCertificates.mem_rowSpace_hgpHZ_of_blocks {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} {C : Matrix (Fin n₁) (Fin r₂) (ZMod 2)} (hU : blockL v = C * H₂) (hR : blockR v = H₁ * C) :

        A vector whose two blocks are C H₂ and H₁ C lies in the row space of H_Z (the same object as Matrix.certificateRowSpace in LeanQEC).

        theorem QECCertificates.hgp_X_distance_ge {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₁ d₂T : ℕ} (hd₁ : ∀ (w : Vec n₁), w ≠ 0 → H₁.mulVec w = 0 → d₁ ≤ hammingNorm w) (hd₂ : ∀ (w : Vec r₂), w ≠ 0 → H₂.transpose.mulVec w = 0 → d₂T ≤ hammingNorm w) :
        min d₁ d₂T ≤ hammingNorm v

        X distance lower bound for the HGP (the cleaning theorem): a nonzero X-type operator outside the row space of H_Z, that is a nontrivial X-type logical operator, has weight at least $\min(d_1, d_2^\top)$, the smaller of the left code distance and the transposed code distance.

        This is complementary to the single-block lower bounds of the second part: those need no "outside the row space" hypothesis, whereas this theorem also covers mixed blocks (both blocks nonzero at once), at the cost of being stated in the quotient.

        6. Each of the two premises of the cleaning lower bound can be dropped: only one route #

        counts
        

        The two steps of the cleaning lower bound hgp_X_distance_ge each need a weight hypothesis: row cleaning needs $|v|<d_1$, column cleaning needs $|v|<d_2^\top$. This section shows that each step can be replaced by a kernel condition, leaving the lower bound with a single factor:

        The four distance theorems are the output of this section: the first two give $d_2^\top\le|v|$ (the factor $d_1$ does not participate), the last two give $d_1\le|v|$ ($d_2^\top$ does not participate). This is exactly the case in which the certificate kernel of one route is trivial: a downstream development uses it to close the "$\ge$" half of C1 on the residual classes.

        6.1. Four lemmas on dropping a cleaning step #

        theorem QECCertificates.blockL_rows_mem_of_H1Ker_trivial {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hcomp : H₁ * blockL v = blockR v * H₂) (hT : ∀ (u : Vec n₁), H₁.mulVec u = 0 → u = 0) (a : Fin n₁) :
        (fun (b : Fin n₂) => blockL v a b) ∈ spanL (matRowList H₂)

        Row cleaning (branch $\ker H_1=0$): when $H_1$ is injective, every row of blockL v lies in the row space of $H_2$ unconditionally.

        This is isomorphic to blockL_rows_mem_of_small, except that the "contradiction with $d_1$" step is replaced by injectivity: the identity of that step already sends $u:=U z$ into $\ker H_1$, so $u=0$; neither $u\ne 0$ nor a weight hypothesis is needed.

        theorem QECCertificates.blockL_rows_mem_of_H2Ker_trivial {r₁ n₁ r₂ n₂ : ℕ} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hT : ∀ (u : Vec n₂), H₂.mulVec u = 0 → u = 0) (a : Fin n₁) :
        (fun (b : Fin n₂) => blockL v a b) ∈ spanL (matRowList H₂)

        Row cleaning (branch $\ker H_2=0$): when $H_2$ is injective the orthogonality hypothesis is vacuous: the required $\langle U_{a\cdot},z\rangle=0$ is asked only for $z\in\ker H_2$, where $z=0$ is the only element. (This branch therefore does not need the compression identity: the conclusion mentions only blockL v and $H_2$.)

        theorem QECCertificates.blockR_cols_mem_of_adjoint_ker_trivial {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hT : ∀ (u : Vec r₁), H₁.transpose.mulVec u = 0 → u = 0) (t : Fin r₂) :
        (fun (i : Fin r₁) => blockR v i t) ∈ spanL (colList H₁)

        Column cleaning (branch $\ker H_1^\top=0$): here the columns of $H_1$ already span the whole of Vec r₁, so the conclusion holds unconditionally. (Again the compression identity is not needed.)

        theorem QECCertificates.blockR_cols_mem_of_H2TKer_trivial {r₁ n₁ r₂ n₂ : ℕ} {H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)} {H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)} {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hcomp : H₁ * blockL v = blockR v * H₂) (hT : ∀ (u : Vec r₂), H₂.transpose.mulVec u = 0 → u = 0) (t : Fin r₂) :
        (fun (i : Fin r₁) => blockR v i t) ∈ spanL (colList H₁)

        Column cleaning (branch $\ker H_2^\top=0$): isomorphic to blockR_cols_mem_of_small, but the "contradiction with $d_2^\top$" step is replaced by injectivity: the identity already sends $y:=R^\top w$ into $\ker H_2^\top$, so $y=0$.

        6.2. Two assembly theorems, each dropping one step #

        theorem QECCertificates.hgp_X_distance_ge_of_rowClean_free {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₂T : ℕ} (hd₂ : ∀ (w : Vec r₂), w ≠ 0 → H₂.transpose.mulVec w = 0 → d₂T ≤ hammingNorm w) (hrow : ∀ (a : Fin n₁), (fun (b : Fin n₂) => blockL v a b) ∈ spanL (matRowList H₂)) :

        Cleaning lower bound with row cleaning free: as soon as the rows of blockL v lie in the row space of $H_2$ unconditionally, the single factor $d_2^\top$ suffices; the rest is word for word hgp_X_distance_ge (column cleaning still uses $|v|<d_2^\top$).

        theorem QECCertificates.hgp_X_distance_ge_of_colClean_free {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₁ : ℕ} (hd₁ : ∀ (w : Vec n₁), w ≠ 0 → H₁.mulVec w = 0 → d₁ ≤ hammingNorm w) (hcol : ∀ (t : Fin r₂), (fun (i : Fin r₁) => blockR v i t) ∈ spanL (colList H₁)) :

        Cleaning lower bound with column cleaning free: as soon as the columns of blockR v lie in the column space of $H_1$ unconditionally, the single factor $d_1$ suffices (row cleaning still uses $|v|<d_1$).

        6.3. Four distance theorems #

        theorem QECCertificates.hgp_X_distance_ge_of_H1Ker_trivial {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₂T : ℕ} (hd₂ : ∀ (w : Vec r₂), w ≠ 0 → H₂.transpose.mulVec w = 0 → d₂T ≤ hammingNorm w) (hT : ∀ (u : Vec n₁), H₁.mulVec u = 0 → u = 0) :

        Lower bound for $d_X$ (branch $\ker H_1=0$): when $H_1$ is injective the single factor $d_2^\top$ suffices.

        theorem QECCertificates.hgp_X_distance_ge_of_H2Ker_trivial {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₂T : ℕ} (hd₂ : ∀ (w : Vec r₂), w ≠ 0 → H₂.transpose.mulVec w = 0 → d₂T ≤ hammingNorm w) (hT : ∀ (u : Vec n₂), H₂.mulVec u = 0 → u = 0) :

        Lower bound for $d_X$ (branch $\ker H_2=0$): when $H_2$ is injective the single factor $d_2^\top$ suffices.

        theorem QECCertificates.hgp_X_distance_ge_of_H2TKer_trivial {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₁ : ℕ} (hd₁ : ∀ (w : Vec n₁), w ≠ 0 → H₁.mulVec w = 0 → d₁ ≤ hammingNorm w) (hT : ∀ (u : Vec r₂), H₂.transpose.mulVec u = 0 → u = 0) :

        Lower bound for $d_X$ (branch $\ker H_2^\top=0$): when $H_2^\top$ is injective the single factor $d_1$ suffices.

        theorem QECCertificates.hgp_X_distance_ge_of_adjoint_ker_trivial {r₁ n₁ r₂ n₂ : ℕ} (H₁ : Matrix (Fin r₁) (Fin n₁) (ZMod 2)) (H₂ : Matrix (Fin r₂) (Fin n₂) (ZMod 2)) {v : Fin n₁ × Fin n₂ ⊕ Fin r₁ × Fin r₂ → ZMod 2} (hv : (hgpHX H₁ H₂).mulVec v = 0) (hlog : v ∉ (hgpHZ H₁ H₂).certificateRowSpace) {d₁ : ℕ} (hd₁ : ∀ (w : Vec n₁), w ≠ 0 → H₁.mulVec w = 0 → d₁ ≤ hammingNorm w) (hT : ∀ (u : Vec r₁), H₁.transpose.mulVec u = 0 → u = 0) :

        Lower bound for $d_X$, the branch where the certificate kernel is trivial: if $\ker H_1^\top = 0$, then every X-type logical operator has weight $\ge d_1$.

        Which gap this fills: the cleaning lower bound hgp_X_distance_ge gives $\min(d_1,d_2^\top)$, and $d_2^\top$ may be strictly smaller yet unattainable; "the certificate kernel of the right route is trivial" ($\ker H_1^\top=0$) is exactly that situation. The theorem says that the smaller value then does not participate in the lower bound and $d_1$ alone suffices.

        Proof (isomorphic to the cleaning lower bound, but using only row cleaning plus a surjectivity): suppose $|v|<d_1$. Row cleaning gives $U = C\,H_2$ (where $U$ is blockL v), so the remainder $\rho := R + H_1C$ satisfies $\rho H_2 = 0$. Now $\ker H_1^\top = 0$ together with the separation lemma mem_spanL_of_forall_dot_eq_zero gives that the columns of $H_1$ are surjective (every vector of Vec r₁ lies in the span of $\mathrm{colList}\,H_1$), so every column of $\rho$ lies there too. Both conditions are met, and exists_cleaning_cert gives $D$ with $H_1D = \rho$ and $DH_2 = 0$, so v and (C+D) form a stabilizer and $v$ lies in the row space, contradicting that $v$ is not a logical operator.