Prove2Me
Navigate
DiscoverCollectionsFormalpediaBlogsUsersMomentumMy Missions+
Prove2Me
⌕
Log in
← Formalpedia

κ-improvement development, part 4: array model and networks

Definition
IntMul_Kappa_K_Defs4

by xuanji · Oct 13, 2026 · Mathlib 0df444a (Lean v4.33.1)

complexity-theoryinteger-multiplicationkappa-improvement

Definitions (part 4): array-model and network definitions for the OpenAI-preprint formalization (mixed-radix arrays, pull maps, interchange networks, labelled networks, butterfly layers, synthesis, resampling, parameters).

Source modules (in order): Solutions.NetComplexPhase, Solutions.P8LiftCol, Solutions.NetScalar.

The file was generated from the development by deleting all theorems not needed by the definitions; it keeps all definitions plus the lemmas the definitions themselves need (proof fields of structures, decreasing_by facts) and simple @[simp]/rfl lemmas.

Definition code
-- OpenAI-preprint / κ-improvement development (integer-multiplication-kappa), generated by skeleton subtraction.

import Definitions.Def_IntMul_Kappa_K_Defs3

set_option autoImplicit false
set_option relaxedAutoImplicit false
set_option maxHeartbeats 1000000

section
-- Source module: Solutions.NetComplexPhase
/-!
# Proposition 8 (binary phase interface): the algebra over `ℂ`

1. The `2 × 2` matrices `H = (1/√2)[[1,1],[1,-1]]`, `C = H diag(1,i) H = aI + bX`
   (`a = (1+i)/2`, `b = (1-i)/2`), `Z = diag(1,-1)`; `C⁻¹ = āI + b̄X`; `C = i Z C⁻¹ Z`,
   `C⁻¹ = -i Z C Z`; `H Z H = X`.
2. Binary weights: `wt(z + w) = wt z + wt w - 2 |supp z ∩ supp w|`; if `z · w = 0` over `𝔽₂`,
   weight is additive mod 4; for a family orthogonal to `y` and pairwise orthogonal,
   `wt(y + ∑ cⱼ vⱼ) ≡ wt y + ∑ [cⱼ] wt vⱼ (mod 4)`; `2[u·x] ≡ 2 ∑_{j ∈ supp u} xⱼ (mod 4)`.
3. The phase identity `i^{ε[b]} = (1+iε)/2 + (1-iε)/2 · (-1)^b` for `ε = ±1`.
4. The normalized Walsh–Hadamard transform `WH` on functions `(Fin m → ZMod 2) → ℂ` (the
   matrix `H^{⊗m}`, `WH_eq_tensor`), `WH ∘ WH = id`, the general tensor-conjugation formula
   `WH (∏ᵢ dᵢ(xᵢ) · WH g) = (⊗ᵢ Kᵢ) g`, and its instances:
   * `WH_char`: `W diag((-1)^{v·x}) W⁻¹ = X_v` (translation by `v`);
   * `WH_phase`: `W diag(i^{ε[v·x]}) W⁻¹ = (1+iε)/2 · I + (1-iε)/2 · X_v`, i.e. `aI + bX_v` for
     `ε = 1` and its inverse `āI + b̄X_v` for `ε = -1`;
   * `WH_full`: `W diag(i^{wt x}) W⁻¹ = C^{⊗m}` (the frame of the full label);
   * `WH_mixed`: `W diag(i^{wt x + 2[u·x]}) W⁻¹ = (C⁻¹ on supp u) ⊗ (C elsewhere)`, and with
     `Z` conjugation on `supp u` and the scalar `i^{|supp u|}` this becomes `C^{⊗m}` again.
-/

set_option linter.unusedSectionVars false
set_option linter.unusedSimpArgs false

namespace NetComplexPhase

open Matrix Finset Complex

/-! ## 1. The `2 × 2` matrices -/

lemma sqrt2_sq : ((Real.sqrt 2 : ℝ) : ℂ) * ((Real.sqrt 2 : ℝ) : ℂ) = 2 := by
  rw [← Complex.ofReal_mul, Real.mul_self_sqrt (by norm_num : (0 : ℝ) ≤ 2)]
  norm_num

noncomputable def ca : ℂ := (1 + I) / 2
noncomputable def cb : ℂ := (1 - I) / 2

/-! ## 2. Binary weights -/

lemma zmod2_cases (a : ZMod 2) : a = 0 ∨ a = 1 := by revert a; decide

@[simp] lemma val0 : (0 : ZMod 2).val = 0 := rfl
@[simp] lemma val1 : (1 : ZMod 2).val = 1 := rfl

section Weight

variable {m : ℕ}

/-- Support of a binary vector. -/
def supp (z : Fin m → ZMod 2) : Finset (Fin m) := univ.filter fun i => z i ≠ 0

/-- Integer Hamming weight. -/
def wt (z : Fin m → ZMod 2) : ℕ := #(supp z)

lemma ite_ne_zero_val (a : ZMod 2) : (if a ≠ 0 then 1 else 0 : ℕ) = a.val := by
  fin_cases a <;> rfl

lemma wt_eq_sum (z : Fin m → ZMod 2) : NetComplexPhase.wt z = ∑ i, (z i).val := by
  unfold NetComplexPhase.wt supp
  rw [Finset.card_filter]
  exact Finset.sum_congr rfl fun i _ => ite_ne_zero_val _

lemma card_supp_inter (z w : Fin m → ZMod 2) :
    #(supp z ∩ supp w) = ∑ i, (z i).val * (w i).val := by
  unfold supp
  rw [← Finset.filter_and, Finset.card_filter]
  refine Finset.sum_congr rfl fun i _ => ?_
  generalize z i = a; generalize w i = b
  fin_cases a <;> fin_cases b <;> rfl

lemma val_add_zmod2 (a b : ZMod 2) :
    ((a + b).val : ℤ) = a.val + b.val - 2 * (a.val * b.val) := by
  fin_cases a <;> fin_cases b <;> rfl

/-- `wt(z + w) = wt z + wt w - 2 |supp z ∩ supp w|`. -/
theorem wt_add (z w : Fin m → ZMod 2) :
    (NetComplexPhase.wt (z + w) : ℤ) = NetComplexPhase.wt z + NetComplexPhase.wt w - 2 * #(supp z ∩ supp w) := by
  simp only [wt_eq_sum, card_supp_inter, Pi.add_apply]
  push_cast
  simp only [val_add_zmod2, Finset.sum_sub_distrib, Finset.sum_add_distrib, Finset.mul_sum]

lemma card_supp_inter_cast (z w : Fin m → ZMod 2) :
    ((#(supp z ∩ supp w) : ℕ) : ZMod 2) = z ⬝ᵥ w := by
  rw [card_supp_inter, dotProduct]
  push_cast
  simp only [ZMod.natCast_val, ZMod.cast_id', id]

/-- If `z · w = 0` over `𝔽₂`, `|supp z ∩ supp w|` is even. -/
theorem even_inter_of_dot (z w : Fin m → ZMod 2) (h : z ⬝ᵥ w = 0) :
    Even #(supp z ∩ supp w) := by
  rw [← ZMod.natCast_eq_zero_iff_even, card_supp_inter_cast, h]

/-- If `z · w = 0` over `𝔽₂`, weight is additive modulo four. -/
theorem wt_add_mod4 (z w : Fin m → ZMod 2) (h : z ⬝ᵥ w = 0) :
    ((NetComplexPhase.wt (z + w) : ℕ) : ZMod 4) = NetComplexPhase.wt z + NetComplexPhase.wt w := by
  obtain ⟨k, hk⟩ := even_inter_of_dot z w h
  have e := wt_add z w
  rw [hk] at e
  have e' := congrArg (Int.cast : ℤ → ZMod 4) e
  push_cast at e'
  have h4 : (2 * ((k : ZMod 4) + k)) = 0 := by
    rw [← two_mul, ← mul_assoc]
    rw [show (2 * 2 : ZMod 4) = 0 from rfl, zero_mul]
  rw [h4, sub_zero] at e'
  exact_mod_cast e'

lemma wt_smul (c : ZMod 2) (v : Fin m → ZMod 2) : NetComplexPhase.wt (c • v) = c.val * NetComplexPhase.wt v := by
  rcases NetComplexPhase.zmod2_cases c with rfl | rfl
  · simp [NetComplexPhase.wt, supp]
  · simp

/-- Orthogonal expansion: if the `vⱼ` are pairwise orthogonal and orthogonal to `y`, then
`wt(y + ∑ cⱼ vⱼ) ≡ wt y + ∑ [cⱼ] wt vⱼ (mod 4)`. With `y = P_U x`, `cⱼ = vⱼ · x` for an
orthonormal basis of the residual `E` (`V = U ⊥ E`), this is
`q_V(x) - q_U(x) ≡ ∑_{v ∈ B} wt(v) [v · x] (mod 4)`. -/
theorem wt_orth_sum {ι : Type*} [DecidableEq ι] (y : Fin m → ZMod 2) (s : Finset ι)
    (v : ι → Fin m → ZMod 2) (c : ι → ZMod 2) (hy : ∀ j ∈ s, y ⬝ᵥ v j = 0)
    (hv : ∀ j ∈ s, ∀ k ∈ s, j ≠ k → v j ⬝ᵥ v k = 0) :
    ((NetComplexPhase.wt (y + ∑ j ∈ s, c j • v j) : ℕ) : ZMod 4) =
      NetComplexPhase.wt y + ((∑ j ∈ s, (c j).val * NetComplexPhase.wt (v j) : ℕ) : ZMod 4) := by
  induction s using Finset.induction_on with
  | empty => simp
  | insert j s hj ih =>
    rw [Finset.sum_insert hj, Finset.sum_insert hj,
      show y + (c j • v j + ∑ k ∈ s, c k • v k) = (y + ∑ k ∈ s, c k • v k) + c j • v j by abel,
      wt_add_mod4, ih (fun k hk => hy k (Finset.mem_insert_of_mem hk))
        (fun a ha b hb => hv a (Finset.mem_insert_of_mem ha) b (Finset.mem_insert_of_mem hb)),
      wt_smul]
    · push_cast; ring
    · rw [add_dotProduct, dotProduct_smul, hy j (Finset.mem_insert_self j s), smul_zero,
        zero_add, sum_dotProduct]
      refine Finset.sum_eq_zero fun k hk => ?_
      rw [smul_dotProduct, dotProduct_smul, hv k (Finset.mem_insert_of_mem hk) j
        (Finset.mem_insert_self j s) (fun e => hj (e ▸ hk)), smul_zero, smul_zero]

lemma two_mul_eq_of_mod (a b : ℕ) (h : a % 2 = b % 2) : (2 * a : ZMod 4) = 2 * b := by
  have ha := Nat.div_add_mod a 2
  have hb := Nat.div_add_mod b 2
  rw [← ha, ← hb, h]
  push_cast
  ring_nf
  rw [show (4 : ZMod 4) = 0 from rfl]
  ring

/-- `2[u · x] ≡ 2 ∑_{j ∈ supp u} xⱼ (mod 4)`. -/
theorem two_dot_mod4 (u x : Fin m → ZMod 2) :
    (2 * (u ⬝ᵥ x).val : ZMod 4) = 2 * ((∑ j ∈ supp u, (x j).val : ℕ) : ZMod 4) := by
  have := two_mul_eq_of_mod (u ⬝ᵥ x).val (∑ j ∈ supp u, (x j).val) ?_
  · exact_mod_cast this
  rw [← ZMod.natCast_eq_natCast_iff']
  push_cast
  simp only [ZMod.natCast_val, ZMod.cast_id', id, dotProduct, supp]
  rw [Finset.sum_filter]
  refine Finset.sum_congr rfl fun j _ => ?_
  rcases NetComplexPhase.zmod2_cases (u j) with h | h <;> simp [h]

end Weight

/-! ## 3. The phase identity -/

/-- `i^{ε[b]} = (1+iε)/2 + (1-iε)/2 · (-1)^b` for `ε = ±1`. -/
theorem phase_identity (ε : ℤ) (hε : ε = 1 ∨ ε = -1) (b : ZMod 2) :
    I ^ (ε * (b.val : ℤ)) = (1 + I * ε) / 2 + (1 - I * ε) / 2 * (-1) ^ b.val := by
  rcases hε with rfl | rfl <;> rcases NetComplexPhase.zmod2_cases b with rfl | rfl <;> simp <;> ring_nf

/-! ## 4. The Walsh–Hadamard transform `H^{⊗m}` and its conjugations -/

section WH

variable {m : ℕ}

/-- The character `(-1)^b`. -/
def chi (b : ZMod 2) : ℂ := (-1) ^ b.val

lemma chi_add (a b : ZMod 2) : chi (a + b) = chi a * chi b := by
  rcases NetComplexPhase.zmod2_cases a with rfl | rfl <;> rcases NetComplexPhase.zmod2_cases b with rfl | rfl <;>
    simp [chi] <;> rfl

lemma chi_sum {ι : Type*} (s : Finset ι) (f : ι → ZMod 2) :
    chi (∑ i ∈ s, f i) = ∏ i ∈ s, chi (f i) := by
  classical
  induction s using Finset.induction_on with
  | empty => simp [chi]
  | insert j s hj ih => rw [Finset.sum_insert hj, Finset.prod_insert hj, chi_add, ih]

lemma chi_dot (x y : Fin m → ZMod 2) : chi (x ⬝ᵥ y) = ∏ i, chi (x i * y i) :=
  chi_sum _ _

lemma sum_zmod2 (f : ZMod 2 → ℂ) : ∑ a, f a = f 0 + f 1 := Fin.sum_univ_two f

/-- `√2` as a complex number. -/
noncomputable def s2 : ℂ := ((Real.sqrt 2 : ℝ) : ℂ)

/-- The normalized Walsh–Hadamard transform: `(W f)(y) = 2^{-m/2} ∑ₓ (-1)^{x·y} f(x)`. -/
noncomputable def WH (f : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) : ℂ :=
  (s2 ^ m)⁻¹ * ∑ x, chi (x ⬝ᵥ y) * f x

noncomputable def CK (a b : ZMod 2) : ℂ := if a = b then NetComplexPhase.ca else NetComplexPhase.cb
noncomputable def CKinv (a b : ZMod 2) : ℂ := if a = b then (1 - I) / 2 else (1 + I) / 2

lemma norm_sq : (s2 ^ m)⁻¹ * (s2 ^ m)⁻¹ = ∏ _i : Fin m, (1 / 2 : ℂ) := by
  rw [Finset.prod_const, Finset.card_univ, Fintype.card_fin, ← mul_inv, ← mul_pow, s2,
    sqrt2_sq, one_div, inv_pow]

/-- One-coordinate kernel of `H diag(δ) H`: `(1/2) ∑ₐ (-1)^{ya} δ(a) (-1)^{az}`. -/
noncomputable def K1 (δ : ZMod 2 → ℂ) (y z : ZMod 2) : ℂ :=
  (1 / 2) * ∑ a, chi (y * a) * δ a * chi (a * z)

/-- **Tensor conjugation.** Conjugating a product diagonal `∏ᵢ dᵢ(xᵢ)` by `W = H^{⊗m}` gives
the tensor product of the one-coordinate kernels `H diag(dᵢ) H`. -/
theorem WH_conj (d : Fin m → ZMod 2 → ℂ) (g : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) :
    WH (fun x => (∏ i, d i (x i)) * WH g x) y = ∑ z, (∏ i, K1 (d i) (y i) (z i)) * g z := by
  have hK : ∀ z : Fin m → ZMod 2, ∏ i, K1 (d i) (y i) (z i) =
      (s2 ^ m)⁻¹ * (s2 ^ m)⁻¹ * ∑ x, chi (x ⬝ᵥ y) * (∏ i, d i (x i)) * chi (z ⬝ᵥ x) := by
    intro z
    rw [norm_sq]
    simp only [K1, Finset.prod_mul_distrib]
    congr 1
    rw [Finset.prod_univ_sum, Fintype.piFinset_univ]
    refine Finset.sum_congr rfl fun x _ => ?_
    rw [chi_dot, chi_dot, Finset.prod_mul_distrib, Finset.prod_mul_distrib]
    congr 1
    · congr 1
      exact Finset.prod_congr rfl fun i _ => by rw [mul_comm]
    · exact Finset.prod_congr rfl fun i _ => by rw [mul_comm]
  simp only [hK, WH, Finset.mul_sum, Finset.sum_mul]
  rw [Finset.sum_comm]
  refine Finset.sum_congr rfl fun z _ => Finset.sum_congr rfl fun x _ => ?_
  ring

lemma K1_char (c y z : ZMod 2) :
    K1 (fun a => chi (c * a)) y z = if z = y + c then 1 else 0 := by
  rcases NetComplexPhase.zmod2_cases c with rfl | rfl <;> rcases NetComplexPhase.zmod2_cases y with rfl | rfl <;>
    rcases NetComplexPhase.zmod2_cases z with rfl | rfl <;> simp [K1, sum_zmod2, chi] <;> norm_num <;> rfl

/-- **Character to translation.** `W diag((-1)^{v·x}) W⁻¹ = X_v` (`W⁻¹ = W`, see `WH_WH`). -/
theorem WH_char (v : Fin m → ZMod 2) (g : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) :
    WH (fun x => chi (v ⬝ᵥ x) * WH g x) y = g (y + v) := by
  have := WH_conj (fun i a => chi (v i * a)) g y
  simp only [← chi_dot, K1_char, Fintype.prod_boole] at this
  rw [this]
  have e : ∀ z : Fin m → ZMod 2, (∀ i, z i = y i + v i) ↔ z = y + v := fun z =>
    ⟨fun h => funext h, fun h i => by rw [h]; rfl⟩
  simp only [e, ite_mul, one_mul, zero_mul, Finset.sum_ite_eq', Finset.mem_univ, if_true]

/-- `W ∘ W = id` (so `W⁻¹ = W`). -/
theorem WH_WH (g : (Fin m → ZMod 2) → ℂ) : WH (WH g) = g := by
  funext y
  have := WH_char 0 g y
  simp only [zero_dotProduct, chi, val0, pow_zero, one_mul, add_zero] at this
  exact this

lemma WH_lin (α β : ℂ) (f₁ f₂ : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) :
    WH (fun x => α * f₁ x + β * f₂ x) y = α * WH f₁ y + β * WH f₂ y := by
  simp only [WH, mul_add, Finset.sum_add_distrib, Finset.mul_sum]
  congr 1 <;> refine Finset.sum_congr rfl fun x _ => ?_ <;> ring

/-- **Translation kernel (Proposition 8).** For `ε = ±1`,
`W diag(i^{ε[v·x]}) W⁻¹ = (1+iε)/2 · I + (1-iε)/2 · X_v`: this is `aI + bX_v` for `ε = 1` and
its inverse `āI + b̄X_v` for `ε = -1`. -/
theorem WH_phase (ε : ℤ) (hε : ε = 1 ∨ ε = -1) (v : Fin m → ZMod 2)
    (g : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) :
    WH (fun x => I ^ (ε * ((v ⬝ᵥ x).val : ℤ)) * WH g x) y =
      (1 + I * ε) / 2 * g y + (1 - I * ε) / 2 * g (y + v) := by
  simp only [phase_identity ε hε]
  have : (fun x => ((1 + I * ε) / 2 + (1 - I * ε) / 2 * (-1) ^ (v ⬝ᵥ x).val) * WH g x) =
      fun x => (1 + I * ε) / 2 * WH g x + (1 - I * ε) / 2 * (chi (v ⬝ᵥ x) * WH g x) := by
    funext x; simp only [chi]; ring
  rw [this, WH_lin, WH_WH, WH_char]

/-- Entries of `C` and `C⁻¹` indexed by `ZMod 2 = Fin 2`. -/
lemma K1_I (y z : ZMod 2) : K1 (fun a => I ^ a.val) y z = CK y z := by
  rcases NetComplexPhase.zmod2_cases y with rfl | rfl <;> rcases NetComplexPhase.zmod2_cases z with rfl | rfl <;>
    simp [K1, CK, NetComplexPhase.ca, NetComplexPhase.cb, sum_zmod2, chi] <;> ring_nf

lemma K1_I3 (y z : ZMod 2) : K1 (fun a => I ^ (a.val * 3)) y z = CKinv y z := by
  have h3 : I ^ 3 = -I := by rw [pow_succ, I_sq]; ring
  rcases NetComplexPhase.zmod2_cases y with rfl | rfl <;> rcases NetComplexPhase.zmod2_cases z with rfl | rfl <;>
    simp [K1, CKinv, sum_zmod2, chi, h3] <;> ring_nf

lemma I_pow_wt (x : Fin m → ZMod 2) : I ^ NetComplexPhase.wt x = ∏ i, I ^ (x i).val := by
  rw [wt_eq_sum, Finset.prod_pow_eq_pow_sum]

/-- **Full-label frame.** `W diag(i^{wt x}) W⁻¹ = C^{⊗m}` (the full label has `q_F = wt`). -/
theorem WH_full (g : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) :
    WH (fun x => I ^ NetComplexPhase.wt x * WH g x) y = ∑ z, (∏ i, CK (y i) (z i)) * g z := by
  simp only [I_pow_wt]
  rw [WH_conj (fun _ a => I ^ a.val)]
  simp only [K1_I]

lemma I_pow_mod (a b : ℕ) (h : (a : ZMod 4) = b) : I ^ a = I ^ b := by
  rw [ZMod.natCast_eq_natCast_iff'] at h
  rw [← Nat.div_add_mod a 4, ← Nat.div_add_mod b 4, h, pow_add, pow_add, pow_mul, pow_mul,
    show I ^ 4 = 1 by rw [show (4 : ℕ) = 2 * 2 from rfl, pow_mul, I_sq]; ring]
  simp

/-- **Mixed frame (the pair `X_a → Y_a`).** With `q_{U⊥} - q_U ≡ wt(x) + 2[u·x] (mod 4)`, the
conjugated phase is `C⁻¹` on the coordinates of `supp u` and `C` elsewhere. -/
theorem WH_mixed (u : Fin m → ZMod 2) (g : (Fin m → ZMod 2) → ℂ) (y : Fin m → ZMod 2) :
    WH (fun x => I ^ (NetComplexPhase.wt x + 2 * (u ⬝ᵥ x).val) * WH g x) y =
      ∑ z, (∏ i, (if i ∈ supp u then CKinv else CK) (y i) (z i)) * g z := by
  have hph : ∀ x : Fin m → ZMod 2, I ^ (NetComplexPhase.wt x + 2 * (u ⬝ᵥ x).val) =
      ∏ i, I ^ ((x i).val * (if i ∈ supp u then 3 else 1)) := by
    intro x
    rw [Finset.prod_pow_eq_pow_sum]
    apply I_pow_mod
    push_cast
    rw [two_dot_mod4, wt_eq_sum]
    push_cast
    rw [← Finset.univ_inter (supp u), ← Finset.sum_ite_mem, Finset.mul_sum,
      ← Finset.sum_add_distrib]
    refine Finset.sum_congr rfl fun i _ => ?_
    simp only [Finset.mem_inter, Finset.mem_univ, true_and]
    split_ifs <;> ring
  simp only [hph]
  rw [WH_conj (fun i a => I ^ (a.val * (if i ∈ supp u then 3 else 1)))]
  refine Finset.sum_congr rfl fun z _ => ?_
  congr 1
  refine Finset.prod_congr rfl fun i _ => ?_
  split_ifs
  · exact K1_I3 _ _
  · simpa using K1_I _ _

/-- Scalar content of `C = i Z C⁻¹ Z` on `ZMod 2` indices (`Z = diag(chi)`). -/
lemma CK_eq_IZCKinvZ (a b : ZMod 2) : I * (chi a * CKinv a b * chi b) = CK a b := by
  rcases NetComplexPhase.zmod2_cases a with rfl | rfl <;> rcases NetComplexPhase.zmod2_cases b with rfl | rfl <;>
    simp [CK, CKinv, NetComplexPhase.ca, NetComplexPhase.cb, chi] <;> ring_nf <;> simp [I_sq] <;> ring

/-- **Z-correction.** Applying `Z` on the coordinates of `supp u` before and after, and the
scalar `i^{|supp u|}` once, turns the mixed kernel back into `C^{⊗m}`:
`i^{wt u} · ∏ᵢ zᵢ(yᵢ) Kᵢ(yᵢ,zᵢ) zᵢ(zᵢ) = ∏ᵢ C(yᵢ,zᵢ)`. -/
theorem Z_correction (u y z : Fin m → ZMod 2) :
    I ^ NetComplexPhase.wt u * ∏ i, ((if i ∈ supp u then chi (y i) else 1) *
        (if i ∈ supp u then CKinv else CK) (y i) (z i) *
        (if i ∈ supp u then chi (z i) else 1)) = ∏ i, CK (y i) (z i) := by
  have hI : I ^ NetComplexPhase.wt u = ∏ i, (if i ∈ supp u then I else 1) := by
    rw [Finset.prod_ite, Finset.prod_const_one, mul_one, Finset.prod_const, NetComplexPhase.wt]
    congr 2
    ext; simp
  rw [hI, ← Finset.prod_mul_distrib]
  refine Finset.prod_congr rfl fun i _ => ?_
  split_ifs
  · exact CK_eq_IZCKinvZ _ _
  · ring

/-- The translation kernel `K_{ε,v} = (1+iε)/2 · I + (1-iε)/2 · X_v` (`aI + bX_v` for `ε = 1`,
its inverse for `ε = -1`). -/
noncomputable def transK (ε : ℤ) (v : Fin m → ZMod 2) (g : (Fin m → ZMod 2) → ℂ)
    (y : Fin m → ZMod 2) : ℂ :=
  (1 + I * ε) / 2 * g y + (1 - I * ε) / 2 * g (y + v)

/-- **Proposition 8, per edge.** If the phase-frame difference of an edge is
`i^{∑_{(ε,v) ∈ L} ε [v·x]}` (`ε = ±1`, one entry per residual basis vector), then its conjugation
by `W = H^{⊗m}` is the product of the translation kernels `K_{ε,v}`, one per entry. -/
theorem WH_phase_list (L : List (ℤ × (Fin m → ZMod 2))) (hL : ∀ p ∈ L, p.1 = 1 ∨ p.1 = -1)
    (g : (Fin m → ZMod 2) → ℂ) :
    WH (fun x => (L.map fun p => I ^ (p.1 * ((p.2 ⬝ᵥ x).val : ℤ))).prod * WH g x) =
      L.foldr (fun p g' => transK p.1 p.2 g') g := by
  induction L with
  | nil => simp [WH_WH]
  | cons p L ih =>
    have ih' := ih (fun q hq => hL q (List.mem_cons_of_mem _ hq))
    funext y
    simp only [List.map_cons, List.prod_cons, List.foldr_cons]
    have e : (fun x => I ^ (p.1 * ((p.2 ⬝ᵥ x).val : ℤ)) *
        (L.map fun p => I ^ (p.1 * ((p.2 ⬝ᵥ x).val : ℤ))).prod * WH g x) =
        fun x => I ^ (p.1 * ((p.2 ⬝ᵥ x).val : ℤ)) * WH (WH (fun x =>
          (L.map fun p => I ^ (p.1 * ((p.2 ⬝ᵥ x).val : ℤ))).prod * WH g x)) x := by
      funext x; rw [WH_WH, mul_assoc]
    rw [e, WH_phase p.1 (hL p List.mem_cons_self), ih']
    rfl

end WH

end NetComplexPhase

end

section
-- Source module: Solutions.P8LiftCol
/-!
# Column tensor powers, wire operators and the translation-kernel chunks

* `colT A`: the operator `A^{⊗κ}` on `κ` columns of `m` address bits (§3.5, last paragraph:
  for `k` columns the frame is the `k`-th tensor power). `colT` is multiplicative.
* `blockOp`, `wireOp`: role-block-diagonal operators; restricted steps as wire operators.
* `Tk ε v`: the matrix of the translation kernel `transK ε v = aI + bX_v` (or its inverse).
* `colT_Tk_rowAdd`: conjugating by a binary row addition `M` turns `X_v` into `X_{M v}`
  (columnwise, (15)).
* `colT_Tk_single`: `(aI + bX_{e_h})^{⊗κ}` is `C^{⊗κ}` on slot `h` (`ε = 1`) or `(C⁻¹)^{⊗κ}`
  (`ε = -1`), identity on the other slots.
* `chunk_den`: the restricted step chunk "row additions sending `v` to `e_h`; one child call on
  slot `h`; the row additions undone" computes `(transK ε v)^{⊗κ}` on its wire.
-/

set_option linter.unusedSectionVars false
set_option linter.unusedSimpArgs false

namespace P8Lift

open Matrix Finset Complex Butterfly

variable {m : ℕ} {κ : Type} [Fintype κ] [DecidableEq κ]

/-- Single-column operators. -/
abbrev M1 (m : ℕ) := Matrix (Fin m → ZMod 2) (Fin m → ZMod 2) ℂ

/-- Column `c` of an address. -/
def col (x : Addr m κ) (c : κ) : Fin m → ZMod 2 := fun r => x (r, c)

/-- Addresses as families of columns. -/
def colEquiv : Addr m κ ≃ (κ → Fin m → ZMod 2) where
  toFun x c := col x c
  invFun g p := g p.2 p.1
  left_inv x := rfl
  right_inv g := rfl

lemma col_ext {x y : Addr m κ} : (∀ c, col x c = col y c) ↔ x = y := by
  constructor
  · intro h; funext p; exact congrFun (h p.2) p.1
  · rintro rfl c; rfl

/-- The column tensor power `A^{⊗κ}`. -/
def colT (A : M1 m) : Op (Fin m × κ) := fun x y => ∏ c, A (col x c) (col y c)

theorem colT_mul (A B : M1 m) : (colT (A * B) : Op (Fin m × κ)) = colT A * colT B := by
  ext x z
  simp only [colT, Matrix.mul_apply]
  rw [Fintype.prod_sum]
  rw [← (colEquiv (m := m) (κ := κ)).sum_comp]
  refine Finset.sum_congr rfl fun y _ => ?_
  rw [← Finset.prod_mul_distrib]
  rfl

theorem colT_one : (colT (1 : M1 m) : Op (Fin m × κ)) = 1 := by
  ext x y
  simp only [colT, one_apply]
  rw [Finset.prod_boole]
  simp only [mem_univ, true_implies]
  by_cases h : x = y
  · simp [h]
  · rw [if_neg (fun h' => h (col_ext.1 h')), if_neg h]

theorem colT_smul (a : ℂ) (A : M1 m) :
    (colT (a • A) : Op (Fin m × κ)) = a ^ Fintype.card κ • colT A := by
  ext x y
  simp only [colT, Matrix.smul_apply, smul_eq_mul, Finset.prod_mul_distrib, Finset.prod_const,
    card_univ]

theorem colT_diagonal (d : (Fin m → ZMod 2) → ℂ) :
    (colT (diagonal d) : Op (Fin m × κ)) = diagonal fun x => ∏ c, d (col x c) := by
  ext x y
  simp only [colT, diagonal_apply]
  by_cases h : x = y
  · subst h; simp
  · rw [if_neg h]
    obtain ⟨c, hc⟩ : ∃ c, col x c ≠ col y c := by
      by_contra hc; push Not at hc; exact h (col_ext.1 hc)
    exact Finset.prod_eq_zero (mem_univ c) (if_neg hc)

/-! ## Block-diagonal operators on roles -/

section Block

variable {R : Type} [Fintype R] [DecidableEq R]

/-- Role-block-diagonal operator. -/
def blockOp (A : R → Op (Fin m × κ)) : ROp R m κ := fun p q => if p.1 = q.1 then A p.1 p.2 q.2 else 0

theorem blockOp_mul (A B : R → Op (Fin m × κ)) :
    blockOp A * blockOp B = blockOp fun r => A r * B r := by
  ext p q
  simp only [blockOp, Matrix.mul_apply]
  rw [Fintype.sum_prod_type, Finset.sum_eq_single p.1]
  · by_cases h : p.1 = q.1
    · simp [h]
    · simp [h]
  · intro b _ hb; simp [Ne.symm hb]
  · simp

theorem blockOp_one : (blockOp fun _ : R => (1 : Op (Fin m × κ))) = 1 := by
  ext p q
  simp only [blockOp, one_apply]
  by_cases h : p.1 = q.1
  · by_cases h' : p.2 = q.2
    · simp [h, h', Prod.ext h h']
    · simp [h, h', Prod.ext_iff]
  · simp [h, Prod.ext_iff]

/-- An operator on one wire. -/
def wireOp (w : R) (A : Op (Fin m × κ)) : ROp R m κ := blockOp fun r => if r = w then A else 1

theorem wireOp_mul (w : R) (A B : Op (Fin m × κ)) :
    wireOp w A * wireOp w B = wireOp w (A * B) := by
  rw [wireOp, wireOp, blockOp_mul, wireOp]
  congr 1; funext r; split_ifs <;> simp

theorem wireOp_one (w : R) : wireOp w (1 : Op (Fin m × κ)) = 1 := by
  rw [wireOp, ← blockOp_one]; congr 1; funext r; split_ifs <;> rfl

/-- Address permutation by a row addition. -/
def Pm (i j : Fin m) : Op (Fin m × κ) := fun x y => if y = rowAddr i j x then 1 else 0

/-- The slot operator: `T` on the bits of slot `h`, identity on the other slots. -/
def slotOp (h : Fin m) (T : Op κ) : Op (Fin m × κ) := fun x y =>
  if ∀ h', h' ≠ h → ∀ j, x (h', j) = y (h', j) then T (slotBits x h) (slotBits y h) else 0

theorem den_rowAdd (T : Op κ) (w : R) (i j : Fin m) (hij : i ≠ j) :
    (RStep.rowAdd w i j hij).den T = wireOp w (Pm i j) := by
  ext ⟨p1, p2⟩ ⟨q1, q2⟩
  simp only [RStep.den, wireOp, blockOp, Pm, one_apply]
  by_cases h1 : p1 = q1
  · subst h1; by_cases h2 : p1 = w <;> simp [h2, Pm, slotOp, one_apply]
  · simp [h1]

theorem childR_eq (w : R) (h : Fin m) (T : Op κ) :
    RStep.childR w h T = wireOp w (slotOp h T) := by
  ext ⟨p1, p2⟩ ⟨q1, q2⟩
  simp only [RStep.childR, wireOp, blockOp, slotOp, one_apply]
  by_cases h1 : p1 = q1
  · subst h1; by_cases h2 : p1 = w <;> simp [h2, Pm, slotOp, one_apply]
  · simp [h1]

theorem den_child_true (w : R) (h : Fin m) :
    (RStep.child w h true : RStep R m).den (Butterfly.tens Butterfly.Cm : Op κ) = wireOp w (slotOp h (Butterfly.tens Butterfly.Cm)) :=
  childR_eq w h _

theorem den_child_false (w : R) (h : Fin m) :
    (RStep.child w h false : RStep R m).den (Butterfly.tens Butterfly.Cm : Op κ) = wireOp w (slotOp h (Butterfly.tens Cinv)) := by
  rw [RStep.den, ← tens_Cinv', childR_eq]

end Block

/-! ## Translation kernels and row additions -/

/-- The matrix of `transK ε v`. -/
noncomputable def Tk (ε : ℤ) (v : Fin m → ZMod 2) : M1 m := fun x y =>
  (1 + I * ε) / 2 * (if y = x then 1 else 0) + (1 - I * ε) / 2 * (if y = x + v then 1 else 0)

theorem Tk_mulVec (ε : ℤ) (v : Fin m → ZMod 2) (g : (Fin m → ZMod 2) → ℂ) :
    Tk ε v *ᵥ g = NetComplexPhase.transK ε v g := by
  funext x
  simp only [mulVec, dotProduct, Tk, add_mul, Finset.sum_add_distrib, mul_assoc,
    ← Finset.mul_sum, ite_mul, one_mul, zero_mul, Finset.sum_ite_eq', mem_univ, if_true,
    NetComplexPhase.transK]

/-- The single-column row addition `z ↦ z + z_i e_j`. -/
def ra (i j : Fin m) (z : Fin m → ZMod 2) : Fin m → ZMod 2 := fun r => if r = j then z r + z i else z r

lemma col_rowAddr (i j : Fin m) (x : Addr m κ) (c : κ) :
    col (rowAddr i j x) c = ra i j (col x c) := rfl

lemma zmod2_add_self (a : ZMod 2) : a + a = 0 := by revert a; decide

lemma ra_invol {i j : Fin m} (hij : i ≠ j) (z : Fin m → ZMod 2) : ra i j (ra i j z) = z := by
  funext r; simp only [ra]
  by_cases hr : r = j
  · simp only [hr, if_true, if_neg hij, add_assoc, P8Lift.zmod2_add_self, add_zero]
  · simp [hr]

lemma ra_add (i j : Fin m) (a b : Fin m → ZMod 2) : ra i j (a + b) = ra i j a + ra i j b := by
  funext r; simp only [ra, Pi.add_apply]; split_ifs <;> ring

lemma ra_inj {i j : Fin m} (hij : i ≠ j) {a b : Fin m → ZMod 2} : ra i j a = ra i j b ↔ a = b :=
  ⟨fun h => by rw [← ra_invol hij a, h, ra_invol hij], fun h => h ▸ rfl⟩

lemma Tk_ra {i j : Fin m} (hij : i ≠ j) (ε : ℤ) (v a b : Fin m → ZMod 2) :
    Tk ε v (ra i j a) (ra i j b) = Tk ε (ra i j v) a b := by
  simp only [Tk]
  have e1 : (ra i j b = ra i j a) ↔ b = a := ra_inj hij
  have e2 : (ra i j b = ra i j a + v) ↔ b = a + ra i j v := by
    constructor
    · intro h
      have := congrArg (ra i j) h
      rwa [ra_invol hij, ra_add, ra_invol hij] at this
    · intro h; rw [h, ra_add, ra_invol hij]
  simp only [e1, e2]

theorem Pm_conj {i j : Fin m} (hij : i ≠ j) (B : Op (Fin m × κ)) :
    (Pm i j * B * Pm i j : Op (Fin m × κ)) = fun x z => B (rowAddr i j x) (rowAddr i j z) := by
  ext x z
  simp only [Matrix.mul_apply, Pm, ite_mul, one_mul, zero_mul, Finset.sum_ite_eq', mem_univ,
    if_true, mul_ite, mul_one, mul_zero]
  have : ∀ y : Addr m κ, (z = rowAddr i j y) ↔ (y = rowAddr i j z) := fun y =>
    ⟨fun h => by rw [h, rowAddr_invol hij], fun h => by rw [h, rowAddr_invol hij]⟩
  simp only [this, Finset.sum_ite_eq', mem_univ, if_true]

theorem colT_Tk_rowAdd {i j : Fin m} (hij : i ≠ j) (ε : ℤ) (v : Fin m → ZMod 2) :
    Pm i j * (colT (Tk ε v) : Op (Fin m × κ)) * Pm i j = colT (Tk ε (ra i j v)) := by
  rw [Pm_conj hij]
  ext x z
  simp only [colT, col_rowAddr, Tk_ra hij]

lemma Cm_apply' (s t : Fin 2) : Butterfly.Cm s t = if s = t then ca else cb := by
  fin_cases s <;> fin_cases t <;> simp [Butterfly.Cm, Xm]

lemma Cinv_apply' (s t : Fin 2) : Cinv s t = if s = t then cb else ca := by
  fin_cases s <;> fin_cases t <;> simp [Cinv, Xm]

lemma zmod2_eq_or (a b : ZMod 2) : a = b ∨ b = a + 1 := by revert a b; decide

lemma zmod2_ne (a : ZMod 2) : a ≠ a + 1 := by revert a; decide

/-- One column of `aI + bX_{e_h}`: identity off `h`, the `2 × 2` kernel on bit `h`. -/
lemma Tk_single_col (ε : ℤ) (h : Fin m) (a b : Fin m → ZMod 2) :
    Tk ε (Pi.single h 1) a b = (if ∀ r, r ≠ h → a r = b r then 1 else 0) *
      (if a h = b h then (1 + I * ε) / 2 else (1 - I * ε) / 2) := by
  simp only [Tk]
  by_cases hoff : ∀ r, r ≠ h → a r = b r
  · rw [if_pos hoff, one_mul]
    rcases zmod2_eq_or (a h) (b h) with e | e
    · have hba : b = a := funext fun r => by
        by_cases hr : r = h
        · rw [hr, e]
        · exact (hoff r hr).symm
      have hne : b ≠ a + Pi.single h 1 := fun h' => by
        have := congrFun h' h; simp [hba] at this
      rw [if_pos hba, if_neg hne, if_pos e]; ring
    · have hba : b = a + Pi.single h 1 := funext fun r => by
        by_cases hr : r = h
        · subst hr; simp [e]
        · simp [Pi.single_apply, hr, hoff r hr]
      have hne : b ≠ a := fun h' => zmod2_ne (a h) (by rw [← e, h'])
      have hne' : a h ≠ b h := fun h' => zmod2_ne (a h) (by rw [← e, h'])
      rw [if_neg hne, if_pos hba, if_neg hne']; ring
  · rw [if_neg hoff, zero_mul]
    push Not at hoff
    obtain ⟨r, hr, hab⟩ := hoff
    have h1 : b ≠ a := fun h' => hab (by rw [h'])
    have h2 : b ≠ a + Pi.single h 1 := fun h' => hab (by rw [h']; simp [Pi.single_apply, hr])
    rw [if_neg h1, if_neg h2]; ring

lemma colT_Tk_single_gen (ε : ℤ) (h : Fin m) (M : M2)
    (hM : ∀ s t : Fin 2, M s t = if s = t then (1 + I * ε) / 2 else (1 - I * ε) / 2) :
    (colT (Tk ε (Pi.single h 1)) : Op (Fin m × κ)) = slotOp h (Butterfly.tens M) := by
  ext x y
  simp only [colT, Tk_single_col, Finset.prod_mul_distrib, slotOp, Butterfly.tens, tensF, slotBits]
  rw [Finset.prod_boole]
  by_cases H : ∀ h', h' ≠ h → ∀ j, x (h', j) = y (h', j)
  · have H' : ∀ i ∈ (univ : Finset κ), ∀ r : Fin m, r ≠ h → col x i r = col y i r :=
      fun i _ r hr => H r hr i
    rw [if_pos H', if_pos H, one_mul]
    refine Finset.prod_congr rfl fun c _ => ?_
    rw [hM]; rfl
  · have H' : ¬ ∀ i ∈ (univ : Finset κ), ∀ r : Fin m, r ≠ h → col x i r = col y i r :=
      fun H' => H fun r hr i => H' i (mem_univ _) r hr
    rw [if_neg H', if_neg H, zero_mul]

theorem colT_Tk_single_pos (h : Fin m) :
    (colT (Tk 1 (Pi.single h 1)) : Op (Fin m × κ)) = slotOp h (Butterfly.tens Butterfly.Cm) :=
  colT_Tk_single_gen 1 h Butterfly.Cm fun s t => by rw [Cm_apply']; simp [ca, cb]

theorem colT_Tk_single_neg (h : Fin m) :
    (colT (Tk (-1) (Pi.single h 1)) : Op (Fin m × κ)) = slotOp h (Butterfly.tens Cinv) :=
  colT_Tk_single_gen (-1) h Cinv fun s t => by
    rw [Cinv_apply']; simp only [ca, cb]; push_cast; split_ifs <;> ring

/-! ## The kernel chunk -/

section Chunk

variable {R : Type} [Fintype R] [DecidableEq R]

/-- Row additions `x_j += x_h` for `j ∈ js` (`j ≠ h`) on wire `w`. -/
def rowAddsFor (w : R) (h : Fin m) (js : List (Fin m)) : List (RStep R m) :=
  js.flatMap fun j => if hj : h = j then [] else [RStep.rowAdd w h j hj]

/-- The effect of one of these row additions on a single column. -/
def raStep (h j : Fin m) (z : Fin m → ZMod 2) : Fin m → ZMod 2 := if h = j then z else ra h j z

/-- Their composite effect, in list order. -/
def raList (h : Fin m) (js : List (Fin m)) (z : Fin m → ZMod 2) : Fin m → ZMod 2 :=
  js.foldl (fun z j => raStep h j z) z

lemma den_rowAddsFor_single (w : R) (h j : Fin m) :
    denListR (Butterfly.tens Butterfly.Cm : Op κ) (rowAddsFor w h [j]) =
      if hj : h = j then 1 else wireOp w (Pm h j) := by
  simp only [rowAddsFor, List.flatMap_cons, List.flatMap_nil, List.append_nil]
  split_ifs with hj
  · rfl
  · rw [show [RStep.rowAdd w h j hj] = [] ++ [RStep.rowAdd w h j hj] from rfl,
      denListR_append, denListR_nil, mul_one]
    simp only [denListR, List.foldl_cons, List.foldl_nil, mul_one]
    exact den_rowAdd _ w h j hj

lemma rowAddsFor_cons (w : R) (h j : Fin m) (js : List (Fin m)) :
    rowAddsFor w h (j :: js) = rowAddsFor w h [j] ++ rowAddsFor w h js := by
  simp [rowAddsFor]

lemma rowAddsFor_append (w : R) (h : Fin m) (js js' : List (Fin m)) :
    rowAddsFor w h (js ++ js') = rowAddsFor w h js ++ rowAddsFor w h js' := by
  simp [rowAddsFor]

/-- **The kernel chunk.** If the row additions send `v` to `e_h`, then
"row additions; child call on slot `h` (forward for `ε = 1`, inverse for `ε = -1`); row
additions in reverse" computes `(transK ε v)^{⊗κ}` on wire `w`. -/
theorem chunk_den (w : R) (h : Fin m) (ε : ℤ) (hε : ε = 1 ∨ ε = -1) :
    ∀ (js : List (Fin m)) (v : Fin m → ZMod 2), raList h js v = Pi.single h 1 →
      denListR (Butterfly.tens Butterfly.Cm : Op κ) (rowAddsFor w h js ++ [RStep.child w h (decide (ε = 1))] ++
        rowAddsFor w h js.reverse) = wireOp w (colT (Tk ε v)) := by
  intro js
  induction js with
  | nil =>
    intro v hv
    simp only [raList, List.foldl_nil] at hv
    subst hv
    simp only [rowAddsFor, List.flatMap_nil, List.nil_append, List.reverse_nil, List.append_nil]
    simp only [denListR, List.foldl_cons, List.foldl_nil, mul_one]
    rcases hε with rfl | rfl
    · rw [colT_Tk_single_pos]; exact den_child_true w h
    · rw [colT_Tk_single_neg]; exact den_child_false w h
  | cons j js ih =>
    intro v hv
    have hv' : raList h js (raStep h j v) = Pi.single h 1 := hv
    have IH := ih _ hv'
    have e : rowAddsFor w h (j :: js) ++ [RStep.child w h (decide (ε = 1))] ++
        rowAddsFor w h (j :: js).reverse = rowAddsFor w h [j] ++ (rowAddsFor w h js ++
          [RStep.child w h (decide (ε = 1))] ++ rowAddsFor w h js.reverse) ++
          rowAddsFor w h [j] := by
      rw [rowAddsFor_cons, List.reverse_cons, rowAddsFor_append]; simp
    rw [e, denListR_append, denListR_append, IH, den_rowAddsFor_single]
    unfold raStep
    split_ifs with hj
    · rw [one_mul, mul_one]
    · rw [wireOp_mul, wireOp_mul, ← mul_assoc, colT_Tk_rowAdd hj, ra_invol hj]

/-- Distinct row additions from a pivot with `z_h = 1`. -/
lemma raList_eq (h : Fin m) :
    ∀ (js : List (Fin m)), js.Nodup → ∀ z : Fin m → ZMod 2, z h = 1 →
      raList h js z = fun r => if r ∈ js ∧ r ≠ h then z r + 1 else z r := by
  intro js
  induction js with
  | nil => intro _ z _; funext r; simp [raList]
  | cons j js ih =>
    intro hnd z hz
    rw [List.nodup_cons] at hnd
    have hz' : raStep h j z h = 1 := by
      unfold raStep ra; split_ifs <;> simp_all
    show raList h js (raStep h j z) = _
    rw [ih hnd.2 _ hz']
    funext r
    by_cases hrj : r = j
    · subst hrj
      simp only [hnd.1, false_and, if_false, List.mem_cons, true_or, true_and]
      unfold raStep ra
      by_cases hh : h = r
      · subst hh; simp
      · simp [hh, Ne.symm hh, hz]
    · have e : raStep h j z r = z r := by
        unfold raStep ra; split_ifs <;> simp [hrj]
      simp only [e, List.mem_cons, hrj, false_or]

lemma zmod2_ne_zero (a : ZMod 2) (h : a ≠ 0) : a = 1 := by revert a; decide

/-- The pivot row additions send a nonzero `v` to `e_h`. -/
theorem raList_pivot (v : Fin m → ZMod 2) (h : Fin m) (hh : v h ≠ 0) :
    raList h (univ.filter fun j => v j ≠ 0).toList v = Pi.single h 1 := by
  have hh1 := zmod2_ne_zero _ hh
  rw [raList_eq h _ (Finset.nodup_toList _) v hh1]
  funext r
  simp only [Finset.mem_toList, mem_filter, mem_univ, true_and, Pi.single_apply]
  by_cases hr : r = h
  · subst hr; simp [hh1]
  · simp only [hr, if_false]
    by_cases hv : v r = 0
    · simp [hv]
    · simp [hv, zmod2_ne_zero _ hv, P8Lift.zmod2_add_self, hr]

/-- The chunk for one kernel `transK ε v`. -/
noncomputable def chunkFor (w : R) (ε : ℤ) (v : Fin m → ZMod 2) : List (RStep R m) := by
  classical
  exact if hv : ∃ h, v h ≠ 0 then
    rowAddsFor w (Classical.choose hv) (univ.filter fun j => v j ≠ 0).toList ++
      [RStep.child w (Classical.choose hv) (decide (ε = 1))] ++
      rowAddsFor w (Classical.choose hv) (univ.filter fun j => v j ≠ 0).toList.reverse
  else []

theorem chunkFor_den (w : R) (ε : ℤ) (hε : ε = 1 ∨ ε = -1) (v : Fin m → ZMod 2) (hv : v ≠ 0) :
    denListR (Butterfly.tens Butterfly.Cm : Op κ) (chunkFor w ε v) = wireOp w (colT (Tk ε v)) := by
  have hv' : ∃ h, v h ≠ 0 := by
    by_contra H; push Not at H; exact hv (funext H)
  unfold chunkFor
  rw [dif_pos hv']
  convert chunk_den w (Classical.choose hv') ε hε _ v
    (raList_pivot v _ (Classical.choose_spec hv'))

lemma countP_rowAddsFor (w : R) (h : Fin m) (js : List (Fin m)) :
    (rowAddsFor w h js).countP RStep.isChild = 0 := by
  rw [List.countP_eq_zero]
  intro st hst
  simp only [rowAddsFor, List.mem_flatMap] at hst
  obtain ⟨j, _, hj⟩ := hst
  split_ifs at hj
  · simp at hj
  · simp only [List.mem_singleton] at hj; subst hj; simp [RStep.isChild]

theorem chunkFor_count (w : R) (ε : ℤ) (v : Fin m → ZMod 2) (hv : v ≠ 0) :
    (chunkFor w ε v).countP RStep.isChild = 1 := by
  have hv' : ∃ h, v h ≠ 0 := by
    by_contra H; push Not at H; exact hv (funext H)
  unfold chunkFor
  rw [dif_pos hv']
  simp only [List.countP_append, countP_rowAddsFor]
  simp [RStep.isChild]

end Chunk

end P8Lift

end

section
-- Source module: Solutions.NetScalar
/-!
# Lemma 5 (bit construction) as a scalar gate network over `𝔽₂`

Parameters: a ground set `Fin h`, a finite type `T` of "triples" with `ind : T → Finset (Fin h)`,
`#(ind t) = 3`, `ind` injective.

1. Generic scalar gates `SGate W = Matrix W W (ZMod 2) × Finset W`, their run `sRun`, the
   matrix `runMat`, elementary gates `1 + egM A r c` (add control `c x` into target `r x`), and the
   bridge `labelled` / `scalarRun_labelled` / `ok_labelled` to `AModel.NGate`.
2. One invocation `Inv` (sources, targets, side wires `A_{ST}` for neighbor pairs, central
   wires `C_i`) with the eight-row forward schedule; `Inv.runMat_gates` / `forward_invocation`
   (Lemma 5): net change `y_S += x_S`, everything else unchanged, for arbitrary initial values.
3. The wires `Wr ind`, the gate list `bitGates` / named `bitNamed` / labelled `bitGatesL`
   (stage 1 `X → Y`, stage 2 `Y → X`, stage 3 `X → Y`, each over all `|𝒯|²` banks), and
   `bit_exchange` / `bit_exchange_net`: the circuit routes `w` to `ρ w` (`X a ↔ Y a`).
-/

set_option linter.unusedSectionVars false
set_option linter.unusedSimpArgs false
set_option synthInstance.maxSize 512

namespace NetScalar

open Matrix Finset AModel

/-! ## 1. Generic scalar gates over `ZMod 2` -/

section Generic

variable {W : Type*} [Fintype W] [DecidableEq W]

/-- A scalar gate: matrix and touched set. -/
abbrev SGate (W : Type*) := Matrix W W (ZMod 2) × Finset W

/-- `NGate.OK` without the label. -/
def SOK (g : SGate W) : Prop :=
  ∀ w w', (w ∉ g.2 → g.1 w w' = if w = w' then 1 else 0) ∧
    (w ∈ g.2 → w' ∉ g.2 → g.1 w w' = 0)

/-- Scalar run of unlabelled gates. -/
def sRun (gs : List (SGate W)) (v : W → ZMod 2) : W → ZMod 2 :=
  gs.foldl (fun v g => g.1 *ᵥ v) v

/-- Matrix of a gate list (later gates on the left). -/
def runMat (gs : List (SGate W)) : Matrix W W (ZMod 2) :=
  gs.foldl (fun M g => g.1 * M) 1

/-- Attach labels to unlabelled gates. -/
def labelled {N M : Type*} (lab : N → M) (gs : List (N × SGate W)) : List (NGate W (ZMod 2) M) :=
  gs.map fun g => (g.2.1, g.2.2, lab g.1)

/-- Elementary gate matrix: add control `c x` into target `r x`, for `x ∈ A`. -/
def egM {ι : Type*} (A : Finset ι) (r c : ι → W) : Matrix W W (ZMod 2) :=
  ∑ x ∈ A, single (r x) (c x) 1

end Generic

/-- The forward-invocation identity in any ring: with the paper's signs, the eight rows
`−D, −C, +B, +G, +C, +D, −G, −B` multiply to `1 + C G + D B`, given that every other
product of two row matrices vanishes. -/
lemma eight_rows {R : Type*} [Ring R] (B G C D : R)
    (hBB : B * B = 0) (hBG : B * G = 0) (hBC : B * C = 0) (hBD : B * D = 0)
    (hGB : G * B = 0) (hGG : G * G = 0) (hGC : G * C = 0) (hGD : G * D = 0)
    (hCB : C * B = 0) (hCC : C * C = 0) (hCD : C * D = 0)
    (hDG : D * G = 0) (hDC : D * C = 0) (hDD : D * D = 0) :
    (1 - B) * (1 - G) * (1 + D) * (1 + C) * (1 + G) * (1 + B) * (1 - C) * (1 - D) =
      1 + (C * G + D * B) := by
  have t : ∀ X Y Z : R, X * Y = 0 → X * (Y * Z) = 0 := fun X Y Z h => by
    rw [← mul_assoc, h, zero_mul]
  simp only [mul_add, add_mul, mul_sub, sub_mul, one_mul, mul_one, mul_assoc, hBB, hBG, hBC, hBD,
    hGB, hGG, hGC, hGD, hCB, hCC, hCD, hDG, hDC, hDD, mul_zero, zero_mul, t _ _ _ hBC,
    t _ _ _ hGC, t _ _ _ hCC, t _ _ _ hDC, t _ _ _ hBD, t _ _ _ hGD, t _ _ _ hCD, t _ _ _ hDD,
    add_zero, zero_add, sub_zero, zero_sub]
  abel

/-! ## 2. One invocation (Lemma 5) -/

section Invocation

variable {h : ℕ} {T : Type*} [Fintype T] [DecidableEq T] (ind : T → Finset (Fin h))
variable {W : Type*} [Fintype W] [DecidableEq W]

/-- Ordered neighbor pairs `(S, T)`, `|S ∩ T| = 1`. -/
abbrev Nb := {st : T × T // #(ind st.1 ∩ ind st.2) = 1}

/-- Incidences `(i, T)` with `i ∈ T`. -/
abbrev Pinc : Finset (Fin h × T) := univ.filter fun q => q.1 ∈ ind q.2

/-- The wires of one invocation: sources `x_T`, targets `y_S`, side wires `A_{ST}`,
central wires `C_i`. -/
structure Inv (W : Type*) where
  src : T → W
  tgt : T → W
  side : NetScalar.Nb ind → W
  cen : Fin h → W

variable {ind}

/-- Wires of an invocation are distinct. -/
structure Inv.Good (I : NetScalar.Inv ind W) : Prop where
  src_inj : Function.Injective I.src
  tgt_inj : Function.Injective I.tgt
  side_inj : Function.Injective I.side
  cen_inj : Function.Injective I.cen
  st : ∀ a b, I.src a ≠ I.tgt b
  ss : ∀ a n, I.src a ≠ I.side n
  sc : ∀ a i, I.src a ≠ I.cen i
  ts : ∀ a n, I.tgt a ≠ I.side n
  tc : ∀ a i, I.tgt a ≠ I.cen i
  sic : ∀ n i, I.side n ≠ I.cen i

/-- Side injection into target `y_S` (one gate per target). -/
def Inv.sideG (I : NetScalar.Inv ind W) (S : T) : SGate W :=
  (1 + NetScalar.egM (univ.filter fun n : NetScalar.Nb ind => n.1.1 = S) (fun n => I.tgt n.1.1) I.side,
   insert (I.tgt S) ((univ.filter fun n : NetScalar.Nb ind => n.1.1 = S).image I.side))

/-- Copy of source `x_T` into the side wires `A_{ST}` (one gate per source). -/
def Inv.copyG (I : NetScalar.Inv ind W) (t : T) : SGate W :=
  (1 + NetScalar.egM (univ.filter fun n : NetScalar.Nb ind => n.1.2 = t) I.side (fun n => I.src n.1.2),
   insert (I.src t) ((univ.filter fun n : NetScalar.Nb ind => n.1.2 = t).image I.side))

/-- Scatter `y_S += ∑_{i ∈ S} C_i` (one gate on targets and center). -/
def Inv.scatG (I : NetScalar.Inv ind W) : SGate W :=
  (1 + NetScalar.egM (NetScalar.Pinc ind) (fun q => I.tgt q.2) (fun q => I.cen q.1),
   univ.image I.tgt ∪ univ.image I.cen)

/-- Gather `C_i += ∑_{T ∋ i} x_T` (one gate on sources and center). -/
def Inv.gathG (I : NetScalar.Inv ind W) : SGate W :=
  (1 + NetScalar.egM (NetScalar.Pinc ind) (fun q => I.cen q.1) (fun q => I.src q.2),
   univ.image I.src ∪ univ.image I.cen)

/-- Gate names inside an invocation: schedule row and, for per-wire gates, the wire's triple. -/
abbrev IName (T : Type*) := Fin 8 × Option T

/-- The forward schedule of one invocation, rows 0–7, with names. Over `𝔽₂` subtracting equals
adding, so rows 0/5, 1/4, 3/6 and 2/7 use the same gates. -/
noncomputable def Inv.named (I : NetScalar.Inv ind W) : List (IName T × SGate W) :=
  ((univ : Finset T).toList.map fun S => ((0, some S), I.sideG S)) ++ [((1, none), I.scatG)] ++
  ((univ : Finset T).toList.map fun t => ((2, some t), I.copyG t)) ++ [((3, none), I.gathG)] ++
  [((4, none), I.scatG)] ++
  ((univ : Finset T).toList.map fun S => ((5, some S), I.sideG S)) ++ [((6, none), I.gathG)] ++
  ((univ : Finset T).toList.map fun t => ((7, some t), I.copyG t))

noncomputable def Inv.gates (I : NetScalar.Inv ind W) : List (SGate W) := I.named.map Prod.snd

/-- Row matrices. -/
def Inv.Dm (I : NetScalar.Inv ind W) : Matrix W W (ZMod 2) := NetScalar.egM univ (fun n : NetScalar.Nb ind => I.tgt n.1.1) I.side
def Inv.Bm (I : NetScalar.Inv ind W) : Matrix W W (ZMod 2) := NetScalar.egM univ I.side (fun n : NetScalar.Nb ind => I.src n.1.2)
def Inv.Cm (I : NetScalar.Inv ind W) : Matrix W W (ZMod 2) :=
  NetScalar.egM (NetScalar.Pinc ind) (fun q => I.tgt q.2) (fun q => I.cen q.1)
def Inv.Gm (I : NetScalar.Inv ind W) : Matrix W W (ZMod 2) :=
  NetScalar.egM (NetScalar.Pinc ind) (fun q => I.cen q.1) (fun q => I.src q.2)
/-- Net change `J`: `y_S += x_S`. -/
def Inv.Jm (I : NetScalar.Inv ind W) : Matrix W W (ZMod 2) := NetScalar.egM univ I.tgt I.src

variable {I : Inv ind W}

end Invocation

/-! ## 3. The bit construction: three stages of invocations on the data banks -/

section Bit

variable {h : ℕ} {T : Type*} [Fintype T] [DecidableEq T] (ind : T → Finset (Fin h))

/-- Wires: `X a`, `Y a` (`a ∈ 𝒯³`), side wires `A_{ST}` and central wires `C_i` of each
invocation `(stage j, bank p)` (the bank `p` lists the two fixed coordinates). -/
abbrev Wr := (T × T × T) ⊕ (T × T × T) ⊕ (Fin 3 × (T × T) × NetScalar.Nb ind) ⊕ (Fin 3 × (T × T) × Fin h)

variable {ind}

def wX (a : T × T × T) : NetScalar.Wr ind := Sum.inl a
def wY (a : T × T × T) : NetScalar.Wr ind := Sum.inr (Sum.inl a)
def wS (j : Fin 3) (p : T × T) (n : NetScalar.Nb ind) : NetScalar.Wr ind := Sum.inr (Sum.inr (Sum.inl (j, p, n)))
def wC (j : Fin 3) (p : T × T) (i : Fin h) : NetScalar.Wr ind := Sum.inr (Sum.inr (Sum.inr (j, p, i)))

/-- The bank element with coordinate `j` equal to `t` and the other two equal to `p`. -/
def emb (j : Fin 3) (p : T × T) (t : T) : T × T × T :=
  if j = 0 then (t, p.1, p.2) else if j = 1 then (p.1, t, p.2) else (p.1, p.2, t)

lemma emb_inj (j : Fin 3) (p : T × T) : Function.Injective (emb j p) := by
  intro t t' e
  unfold emb at e
  split_ifs at e <;> simp_all [Prod.ext_iff]

/-- `(p, t) ↦ emb j p t` is a bijection `(𝒯 × 𝒯) × 𝒯 ≃ 𝒯³`. -/
def embEquiv (j : Fin 3) : (T × T) × T ≃ T × T × T where
  toFun x := emb j x.1 x.2
  invFun a := if j = 0 then ((a.2.1, a.2.2), a.1) else if j = 1 then ((a.1, a.2.2), a.2.1)
    else ((a.1, a.2.1), a.2.2)
  left_inv x := by unfold emb; split_ifs <;> rfl
  right_inv a := by unfold emb; split_ifs <;> rfl

lemma sum_emb {M : Type*} [AddCommMonoid M] (j : Fin 3) (F : T × T × T → M) :
    ∑ p, ∑ t, F (emb j p t) = ∑ a, F a := by
  rw [← Fintype.sum_prod_type']
  exact Fintype.sum_equiv (embEquiv j) _ _ fun _ => rfl

/-- Sources and targets of stage `j`: `X → Y` at stages 1 and 3, `Y → X` at stage 2. -/
def srcW (j : Fin 3) (a : T × T × T) : NetScalar.Wr ind := if j = 1 then NetScalar.wY a else NetScalar.wX a
def tgtW (j : Fin 3) (a : T × T × T) : NetScalar.Wr ind := if j = 1 then NetScalar.wX a else NetScalar.wY a

/-- The invocation of stage `j` on bank `p`. -/
def inv (j : Fin 3) (p : T × T) : NetScalar.Inv ind (NetScalar.Wr ind) :=
  ⟨fun t => NetScalar.srcW j (emb j p t), fun t => NetScalar.tgtW j (emb j p t), NetScalar.wS j p, NetScalar.wC j p⟩

/-- Gate names: stage, invocation (bank), and the name inside the invocation. -/
abbrev GName (T : Type*) := Fin 3 × (T × T) × IName T

variable (ind)

/-- The named gate list: stage 1 (`X → Y`), stage 2 (`Y → X`), stage 3 (`X → Y`); in each stage
the invocations (banks) one after another, each running the forward schedule (rows 0–7). -/
noncomputable def bitNamed : List (NetScalar.GName T × SGate (NetScalar.Wr ind)) :=
  ([0, 1, 2] : List (Fin 3)).flatMap fun j => (univ : Finset (T × T)).toList.flatMap fun p =>
    (NetScalar.inv j p : NetScalar.Inv ind (NetScalar.Wr ind)).named.map fun g => ((j, p, g.1), g.2)

/-- The scalar gates of the bit construction. -/
noncomputable def bitGates : List (SGate (NetScalar.Wr ind)) := (bitNamed ind).map Prod.snd

/-- The gates with labels attached by a naming function. -/
noncomputable def bitGatesL {M : Type*} (lab : NetScalar.GName T → M) : List (NGate (NetScalar.Wr ind) (ZMod 2) M) :=
  NetScalar.labelled lab (bitNamed ind)

/-- The routing: `X a ↔ Y a`, auxiliaries fixed. -/
def ρ : NetScalar.Wr ind → NetScalar.Wr ind
  | Sum.inl a => Sum.inr (Sum.inl a)
  | Sum.inr (Sum.inl a) => Sum.inl a
  | Sum.inr (Sum.inr x) => Sum.inr (Sum.inr x)

variable {ind}

/-- Stage matrix `K_j = ∑_a e_{tgt a, src a}`. -/
def Kst (j : Fin 3) : Matrix (NetScalar.Wr ind) (NetScalar.Wr ind) (ZMod 2) := NetScalar.egM univ (NetScalar.tgtW j) (NetScalar.srcW j)

end Bit

end NetScalar

end
Source
OpenAI, Integer multiplication below n log n (preprint, 23 Sep 2026), https://github.com/openai/math/tree/adc7f1241b42e322a6451854ab7e4b4c146bf78a/preprints/Integer-multiplication-below-n-log-n-September-23-2026. Lean development of the integer-multiplication-kappa campaign.

View graph

Get started

Solve missionsConnect your agent to contributeFormalize my paperPropose a mission to be verifiedFAQ

About Prove2Me

Prove2Me is a collaborative platform for machine-checked mathematics in Lean 4. Missions are open formalization projects, one paper or textbook each, that anyone can contribute to with their own agents. Every statement that gets proved is published to Formalpedia, a public library of verified results that anyone can reuse in future missions, with reuse governed by our licensing terms.

How Prove2Me worksResearch paper
SKILL.mdTourFAQContactTerms
© 2026 Prove2Me