|
| 1 | +/- |
| 2 | +Copyright (c) 2026 ArkLib Contributors. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: ArkLib Contributors |
| 5 | +-/ |
| 6 | +import Mathlib.InformationTheory.Hamming |
| 7 | +import Mathlib.Algebra.Order.Chebyshev |
| 8 | +import Mathlib.Algebra.BigOperators.Ring.Finset |
| 9 | +import Mathlib.Tactic.Linarith |
| 10 | +import Mathlib.Tactic.Positivity |
| 11 | +import Mathlib.Tactic.Ring |
| 12 | +import Mathlib.Tactic.NormNum |
| 13 | + |
| 14 | +/-! |
| 15 | +# The Johnson list-size bound (combinatorial, isolated) |
| 16 | +
|
| 17 | +This file proves the classical **q-ary Johnson bound** on the number of codewords of a code that lie |
| 18 | +within a given Hamming radius of a fixed word — the foundational list-decoding bound underlying the |
| 19 | +correlated-agreement / proximity-gap "true form" (the Johnson radius `δ < 1 - √ρ`), which is |
| 20 | +**absent from mathlib**. |
| 21 | +
|
| 22 | +It is deliberately **self-contained**: it imports only `Mathlib` (Hamming distance, big operators, |
| 23 | +the Cauchy–Schwarz sum inequality), so it builds independently of the rest of ArkLib. The |
| 24 | +"universal-over-all-codes" form of the proximity gap is false; the correct form lives at the Johnson |
| 25 | +radius, whose combinatorial heart is the bound below. |
| 26 | +
|
| 27 | +## Main statement |
| 28 | +
|
| 29 | +`card_mul_johnsonDenom_le`: for a finite set of codewords `C` with pairwise distance `≥ d`, all |
| 30 | +within distance `e` of a word `w`, writing `n = |ι|`: |
| 31 | +
|
| 32 | + `(C.card) · ((n - e)² - n·(n - d)) ≤ n · d`. |
| 33 | +
|
| 34 | +In the **Johnson regime** `(n - e)² > n·(n - d)` this yields `card_le_div` : |
| 35 | +`C.card ≤ n·d / ((n - e)² - n·(n - d))`. |
| 36 | +
|
| 37 | +## Proof |
| 38 | +
|
| 39 | +Double counting. For each coordinate `i`, `colCount i` is the number of codewords agreeing with `w` |
| 40 | +at `i`. Then `∑ i, colCount i = ∑ c, agree(c, w) ≥ |C|·(n - e)` and, by Cauchy–Schwarz, |
| 41 | +`(∑ i, colCount i)² ≤ n · ∑ i, (colCount i)²`. Expanding `∑ i, (colCount i)²` over ordered pairs of |
| 42 | +codewords, the diagonal contributes `∑ c, agree(c, w) ≤ |C|·n` and each off-diagonal pair `(c, c')` |
| 43 | +contributes `agree(c, c') ≤ n - d`. Combining and cancelling one factor of `|C|` gives the bound. |
| 44 | +-/ |
| 45 | + |
| 46 | +open scoped BigOperators |
| 47 | + |
| 48 | +namespace ArkLib.JohnsonBound |
| 49 | + |
| 50 | +variable {ι : Type*} [Fintype ι] [DecidableEq ι] |
| 51 | +variable {Sigma : Type*} [DecidableEq Sigma] |
| 52 | + |
| 53 | +/-- The number of coordinates on which `c` and `w` agree. -/ |
| 54 | +def agree (c w : ι → Sigma) : ℕ := (Finset.univ.filter (fun i => c i = w i)).card |
| 55 | + |
| 56 | +/-- Agreement plus Hamming distance equals the block length. -/ |
| 57 | +theorem agree_add_hammingDist (c w : ι → Sigma) : |
| 58 | + agree c w + hammingDist c w = Fintype.card ι := by |
| 59 | + classical |
| 60 | + have h := Finset.filter_card_add_filter_neg_card_eq_card |
| 61 | + (s := (Finset.univ : Finset ι)) (p := fun i => c i = w i) |
| 62 | + simpa only [agree, hammingDist, Finset.card_univ, ne_eq] using h |
| 63 | + |
| 64 | +/-- Agreement is at least `n - e` when `c` is within distance `e` of `w` (as naturals). -/ |
| 65 | +theorem natSub_le_agree {c w : ι → Sigma} {e : ℕ} (h : hammingDist c w ≤ e) : |
| 66 | + Fintype.card ι - e ≤ agree c w := by |
| 67 | + have := agree_add_hammingDist c w; omega |
| 68 | + |
| 69 | +/-- Agreement is at most `n - d` for two words at distance `≥ d` (as naturals). -/ |
| 70 | +theorem agree_le_natSub {c c' : ι → Sigma} {d : ℕ} (h : d ≤ hammingDist c c') : |
| 71 | + agree c c' ≤ Fintype.card ι - d := by |
| 72 | + have := agree_add_hammingDist c c'; omega |
| 73 | + |
| 74 | +/-! ### Real-valued indicators and the counting identities -/ |
| 75 | + |
| 76 | +/-- `0/1` indicator (in `ℚ`) that `c` agrees with `w` at coordinate `i`. -/ |
| 77 | +noncomputable def ind (c w : ι → Sigma) (i : ι) : ℚ := if c i = w i then 1 else 0 |
| 78 | + |
| 79 | +theorem ind_nonneg (c w : ι → Sigma) (i : ι) : 0 ≤ ind c w i := by |
| 80 | + unfold ind; split <;> norm_num |
| 81 | + |
| 82 | +/-- Summing the indicator over coordinates gives the agreement count. -/ |
| 83 | +theorem sum_ind_eq_agree (c w : ι → Sigma) : ∑ i, ind c w i = (agree c w : ℚ) := by |
| 84 | + classical |
| 85 | + unfold ind agree |
| 86 | + rw [Finset.sum_boole] |
| 87 | + |
| 88 | +/-- Product of two agreement indicators is the "both agree with `w`" indicator. -/ |
| 89 | +theorem ind_mul_ind (c c' w : ι → Sigma) (i : ι) : |
| 90 | + ind c w i * ind c' w i = if c i = w i ∧ c' i = w i then 1 else 0 := by |
| 91 | + unfold ind; split_ifs with h1 h2 h3 <;> first | rfl | simp_all |
| 92 | + |
| 93 | +/-- The number of codewords in `C` agreeing with `w` at coordinate `i` (in `ℚ`). -/ |
| 94 | +noncomputable def colCount (C : Finset (ι → Sigma)) (w : ι → Sigma) (i : ι) : ℚ := |
| 95 | + ∑ c ∈ C, ind c w i |
| 96 | + |
| 97 | +theorem colCount_nonneg (C : Finset (ι → Sigma)) (w : ι → Sigma) (i : ι) : |
| 98 | + 0 ≤ colCount C w i := |
| 99 | + Finset.sum_nonneg (fun c _ => ind_nonneg c w i) |
| 100 | + |
| 101 | +/-- `∑ i, colCount i = ∑ c, agree(c, w)`. -/ |
| 102 | +theorem sum_colCount (C : Finset (ι → Sigma)) (w : ι → Sigma) : |
| 103 | + ∑ i, colCount C w i = ∑ c ∈ C, (agree c w : ℚ) := by |
| 104 | + unfold colCount |
| 105 | + rw [Finset.sum_comm] |
| 106 | + exact Finset.sum_congr rfl (fun c _ => sum_ind_eq_agree c w) |
| 107 | + |
| 108 | +/-- The "common agreement" count of `c, c'` against `w`, in `ℚ`. -/ |
| 109 | +noncomputable def common (c c' w : ι → Sigma) : ℚ := ∑ i, ind c w i * ind c' w i |
| 110 | + |
| 111 | +/-- `common c c w = agree(c, w)`. -/ |
| 112 | +theorem common_self (c w : ι → Sigma) : common c c w = (agree c w : ℚ) := by |
| 113 | + unfold common |
| 114 | + rw [← sum_ind_eq_agree c w] |
| 115 | + refine Finset.sum_congr rfl (fun i _ => ?_) |
| 116 | + unfold ind; split <;> norm_num |
| 117 | + |
| 118 | +/-- `common c c' w ≤ agree(c, c')`: coordinates where both agree with `w` are coordinates where |
| 119 | +`c` and `c'` agree with each other. -/ |
| 120 | +theorem common_le_agree (c c' w : ι → Sigma) : common c c' w ≤ (agree c c' : ℚ) := by |
| 121 | + classical |
| 122 | + unfold common |
| 123 | + have hpt : ∀ i, ind c w i * ind c' w i ≤ ind c c' i := by |
| 124 | + intro i; rw [ind_mul_ind]; unfold ind |
| 125 | + split_ifs with h hcc <;> first | norm_num | (exfalso; apply hcc; rw [h.1, h.2]) |
| 126 | + calc ∑ i, ind c w i * ind c' w i ≤ ∑ i, ind c c' i := Finset.sum_le_sum (fun i _ => hpt i) |
| 127 | + _ = (agree c c' : ℚ) := sum_ind_eq_agree c c' |
| 128 | + |
| 129 | +/-- `∑ i, (colCount i)² = ∑ c, ∑ c', common(c, c')`: expansion over ordered pairs. -/ |
| 130 | +theorem sum_colCount_sq (C : Finset (ι → Sigma)) (w : ι → Sigma) : |
| 131 | + ∑ i, (colCount C w i) ^ 2 = ∑ c ∈ C, ∑ c' ∈ C, common c c' w := by |
| 132 | + unfold colCount common |
| 133 | + have step : ∀ i, (∑ c ∈ C, ind c w i) ^ 2 = ∑ c ∈ C, ∑ c' ∈ C, ind c w i * ind c' w i := by |
| 134 | + intro i; rw [sq, Finset.sum_mul_sum] |
| 135 | + simp_rw [step] |
| 136 | + conv_lhs => rw [Finset.sum_comm] |
| 137 | + refine Finset.sum_congr rfl fun c _ => ?_ |
| 138 | + rw [Finset.sum_comm] |
| 139 | + |
| 140 | +/-- Cauchy–Schwarz specialised: `(∑ i, colCount i)² ≤ n · ∑ i, (colCount i)²`. -/ |
| 141 | +theorem sq_sum_colCount_le (C : Finset (ι → Sigma)) (w : ι → Sigma) : |
| 142 | + (∑ i, colCount C w i) ^ 2 ≤ (Fintype.card ι : ℚ) * ∑ i, (colCount C w i) ^ 2 := by |
| 143 | + have h := sq_sum_le_card_mul_sum_sq (s := (Finset.univ : Finset ι)) |
| 144 | + (f := fun i => colCount C w i) |
| 145 | + simpa [Finset.card_univ] using h |
| 146 | + |
| 147 | +/-- Each agreement count, in `ℚ`, is at most the block length. -/ |
| 148 | +theorem agree_le_card (c w : ι → Sigma) : (agree c w : ℚ) ≤ (Fintype.card ι : ℚ) := by |
| 149 | + have : agree c w ≤ Fintype.card ι := by |
| 150 | + unfold agree; rw [← Finset.card_univ]; exact Finset.card_filter_le _ _ |
| 151 | + exact_mod_cast this |
| 152 | + |
| 153 | +/-- The **Johnson denominator** `(n - e)² - n·(n - d)`. The Johnson regime is where it is positive. -/ |
| 154 | +noncomputable def johnsonDenom (n d e : ℕ) : ℚ := ((n : ℚ) - e) ^ 2 - (n : ℚ) * ((n : ℚ) - d) |
| 155 | + |
| 156 | +/-! ### The Johnson bound -/ |
| 157 | + |
| 158 | +/-- **Johnson bound (product form).** For a finite set of codewords `C` with pairwise Hamming |
| 159 | +distance at least `d`, all within distance `e` of a word `w` (with `e, d ≤ n := |ι|`): |
| 160 | +
|
| 161 | + `(C.card) · ((n - e)² - n·(n - d)) ≤ n · d`. -/ |
| 162 | +theorem card_mul_johnsonDenom_le |
| 163 | + (C : Finset (ι → Sigma)) (w : ι → Sigma) (d e : ℕ) |
| 164 | + (hd : ∀ c ∈ C, ∀ c' ∈ C, c ≠ c' → d ≤ hammingDist c c') |
| 165 | + (he : ∀ c ∈ C, hammingDist c w ≤ e) |
| 166 | + (hen : e ≤ Fintype.card ι) (hdn : d ≤ Fintype.card ι) : |
| 167 | + (C.card : ℚ) * johnsonDenom (Fintype.card ι) d e ≤ (Fintype.card ι : ℚ) * d := by |
| 168 | + classical |
| 169 | + set n := Fintype.card ι with hn |
| 170 | + set L : ℚ := (C.card : ℚ) with hL |
| 171 | + have hLnn : 0 ≤ L := by positivity |
| 172 | + set S1 : ℚ := ∑ c ∈ C, (agree c w : ℚ) with hS1def |
| 173 | + set S2 : ℚ := ∑ c ∈ C, ∑ c' ∈ C, common c c' w with hS2def |
| 174 | + have hne : (0 : ℚ) ≤ (n : ℚ) - e := by |
| 175 | + have h : (e : ℚ) ≤ (n : ℚ) := by exact_mod_cast hen |
| 176 | + linarith |
| 177 | + have hnd : (0 : ℚ) ≤ (n : ℚ) - d := by |
| 178 | + have h : (d : ℚ) ≤ (n : ℚ) := by exact_mod_cast hdn |
| 179 | + linarith |
| 180 | + -- (1) lower bound on S1 |
| 181 | + have hS1lower : L * ((n : ℚ) - e) ≤ S1 := by |
| 182 | + have hcast : ∀ c ∈ C, ((n : ℚ) - e) ≤ (agree c w : ℚ) := by |
| 183 | + intro c hc |
| 184 | + have hge : (n - e : ℕ) ≤ agree c w := natSub_le_agree (he c hc) |
| 185 | + have : ((n - e : ℕ) : ℚ) ≤ (agree c w : ℚ) := by exact_mod_cast hge |
| 186 | + rwa [Nat.cast_sub hen] at this |
| 187 | + calc L * ((n : ℚ) - e) = ∑ _c ∈ C, ((n : ℚ) - e) := by |
| 188 | + rw [Finset.sum_const, nsmul_eq_mul] |
| 189 | + _ ≤ S1 := Finset.sum_le_sum hcast |
| 190 | + -- (2) upper bound on S1 |
| 191 | + have hS1upper : S1 ≤ L * (n : ℚ) := by |
| 192 | + calc S1 ≤ ∑ _c ∈ C, (n : ℚ) := Finset.sum_le_sum (fun c _ => agree_le_card c w) |
| 193 | + _ = L * (n : ℚ) := by rw [Finset.sum_const, nsmul_eq_mul] |
| 194 | + -- (3) upper bound on S2 |
| 195 | + have hS2upper : S2 ≤ S1 + L * (L - 1) * ((n : ℚ) - d) := by |
| 196 | + have hrow : ∀ c ∈ C, |
| 197 | + ∑ c' ∈ C, common c c' w ≤ (agree c w : ℚ) + (L - 1) * ((n : ℚ) - d) := by |
| 198 | + intro c hc |
| 199 | + have hsplit : ∑ c' ∈ C, common c c' w |
| 200 | + = common c c w + ∑ c' ∈ C.erase c, common c c' w := |
| 201 | + (Finset.add_sum_erase C (fun c' => common c c' w) hc).symm |
| 202 | + have hoff : ∑ c' ∈ C.erase c, common c c' w ≤ (L - 1) * ((n : ℚ) - d) := by |
| 203 | + have hbound : ∀ c' ∈ C.erase c, common c c' w ≤ (n : ℚ) - d := by |
| 204 | + intro c' hc' |
| 205 | + have hne' : c' ≠ c := Finset.ne_of_mem_erase hc' |
| 206 | + have hc'mem : c' ∈ C := Finset.mem_of_mem_erase hc' |
| 207 | + have hag : agree c c' ≤ (n - d : ℕ) := |
| 208 | + agree_le_natSub (hd c hc c' hc'mem (Ne.symm hne')) |
| 209 | + have : (agree c c' : ℚ) ≤ ((n - d : ℕ) : ℚ) := by exact_mod_cast hag |
| 210 | + rw [Nat.cast_sub hdn] at this |
| 211 | + exact (common_le_agree c c' w).trans this |
| 212 | + calc ∑ c' ∈ C.erase c, common c c' w |
| 213 | + ≤ ∑ _c' ∈ C.erase c, ((n : ℚ) - d) := Finset.sum_le_sum hbound |
| 214 | + _ = ((C.erase c).card : ℚ) * ((n : ℚ) - d) := by rw [Finset.sum_const, nsmul_eq_mul] |
| 215 | + _ = (L - 1) * ((n : ℚ) - d) := by |
| 216 | + rw [Finset.card_erase_of_mem hc, |
| 217 | + Nat.cast_sub (Finset.one_le_card.mpr ⟨c, hc⟩)] |
| 218 | + push_cast; ring |
| 219 | + rw [hsplit, common_self] |
| 220 | + linarith |
| 221 | + calc S2 ≤ ∑ c ∈ C, ((agree c w : ℚ) + (L - 1) * ((n : ℚ) - d)) := Finset.sum_le_sum hrow |
| 222 | + _ = S1 + L * (L - 1) * ((n : ℚ) - d) := by |
| 223 | + rw [Finset.sum_add_distrib, Finset.sum_const, nsmul_eq_mul, ← hS1def]; ring |
| 224 | + -- (4) Cauchy–Schwarz |
| 225 | + have hCS : S1 ^ 2 ≤ (n : ℚ) * S2 := by |
| 226 | + have h1 := sq_sum_colCount_le C w |
| 227 | + rw [sum_colCount C w, ← hS1def] at h1 |
| 228 | + rw [sum_colCount_sq C w, ← hS2def] at h1 |
| 229 | + exact h1 |
| 230 | + -- (5) `(L (n-e))² ≤ S1²` |
| 231 | + have hsqle : (L * ((n : ℚ) - e)) ^ 2 ≤ S1 ^ 2 := |
| 232 | + pow_le_pow_left₀ (mul_nonneg hLnn hne) hS1lower 2 |
| 233 | + -- KEY inequality |
| 234 | + have hKEY : (L * ((n : ℚ) - e)) ^ 2 ≤ (n : ℚ) * (L * (n : ℚ) + L * (L - 1) * ((n : ℚ) - d)) := by |
| 235 | + have hnpos : (0 : ℚ) ≤ (n : ℚ) := by positivity |
| 236 | + calc (L * ((n : ℚ) - e)) ^ 2 ≤ S1 ^ 2 := hsqle |
| 237 | + _ ≤ (n : ℚ) * S2 := hCS |
| 238 | + _ ≤ (n : ℚ) * (S1 + L * (L - 1) * ((n : ℚ) - d)) := by |
| 239 | + apply mul_le_mul_of_nonneg_left _ hnpos; linarith [hS2upper] |
| 240 | + _ ≤ (n : ℚ) * (L * (n : ℚ) + L * (L - 1) * ((n : ℚ) - d)) := by |
| 241 | + apply mul_le_mul_of_nonneg_left _ hnpos; linarith [hS1upper] |
| 242 | + -- cancel a factor of `L` |
| 243 | + rcases eq_or_lt_of_le hLnn with hL0 | hLpos |
| 244 | + · rw [← hL0, zero_mul]; positivity |
| 245 | + · have hLLX : L * (L * johnsonDenom n d e) ≤ L * ((n : ℚ) * d) := by |
| 246 | + unfold johnsonDenom |
| 247 | + nlinarith [hKEY, hLpos, hne, hnd] |
| 248 | + exact le_of_mul_le_mul_left hLLX hLpos |
| 249 | + |
| 250 | +/-- **Johnson bound (list-size form).** In the Johnson regime `(n - e)² > n·(n - d)`, the number of |
| 251 | +codewords of `C` within distance `e` of `w` is at most `n·d / ((n - e)² - n·(n - d))`. -/ |
| 252 | +theorem card_le_div |
| 253 | + (C : Finset (ι → Sigma)) (w : ι → Sigma) (d e : ℕ) |
| 254 | + (hd : ∀ c ∈ C, ∀ c' ∈ C, c ≠ c' → d ≤ hammingDist c c') |
| 255 | + (he : ∀ c ∈ C, hammingDist c w ≤ e) |
| 256 | + (hen : e ≤ Fintype.card ι) (hdn : d ≤ Fintype.card ι) |
| 257 | + (hJohnson : 0 < johnsonDenom (Fintype.card ι) d e) : |
| 258 | + (C.card : ℚ) ≤ (Fintype.card ι : ℚ) * d / johnsonDenom (Fintype.card ι) d e := by |
| 259 | + rw [le_div_iff₀ hJohnson] |
| 260 | + exact card_mul_johnsonDenom_le C w d e hd he hen hdn |
| 261 | + |
| 262 | +end ArkLib.JohnsonBound |
0 commit comments