/- Q16InverseProof.lean Complete proof: A × A⁻¹ = I for Q16_16 fixed-point matrices when all intermediate computations are exact. All mathematical axioms eliminated. Remaining axioms are implementation specs only. -/ import Mathlib.LinearAlgebra.Matrix.Adjugate import Semantics.FixedPoint import Semantics.AdjugateMatrix set_option linter.dupNamespace false set_option maxHeartbeats 800000 set_option synthInstance.maxHeartbeats 800000 open Semantics.FixedPoint open Semantics.FixedPoint.Q16_16 open Semantics.AdjugateMatrix -- ============================================================================ -- Section 1: The Q16_16 → ℚ Embedding -- ============================================================================ def toRat (q : Q16_16) : ℚ := (q.val : ℚ) / 65536 theorem toRat_injective : Function.Injective toRat := by intro a b h_val simp only [toRat] at h_val have h2 : (65536 : ℚ) ≠ 0 := by norm_num have h_eq : (a.val : ℚ) = (b.val : ℚ) := by have h : (a.val : ℚ) / 65536 * 65536 = (b.val : ℚ) / 65536 * 65536 := congr_arg (fun x => x * (65536 : ℚ)) h_val rw [div_mul_cancel₀ _ h2, div_mul_cancel₀ _ h2] at h exact h exact Subtype.ext (Int.cast_injective h_eq) -- ============================================================================ -- Section 2: Exactness Predicates -- ============================================================================ def Q16_16.ExactAdd (a b : Q16_16) : Prop := q16MinRaw ≤ a.val + b.val ∧ a.val + b.val ≤ q16MaxRaw def Q16_16.ExactMul (a b : Q16_16) : Prop := (a.val * b.val) % (q16Scale : Int) = 0 def Q16_16.ExactDiv (a b : Q16_16) : Prop := b.val ≠ 0 ∧ (a.val * (q16Scale : Int)) % b.val = 0 ∧ q16MinRaw ≤ (a.val * (q16Scale : Int)) / b.val ∧ (a.val * (q16Scale : Int)) / b.val ≤ q16MaxRaw def Q16_16.ExactMulFull (a b : Q16_16) : Prop := Q16_16.ExactMul a b ∧ q16MinRaw ≤ (a.val * b.val) / q16Scale ∧ (a.val * b.val) / q16Scale ≤ q16MaxRaw private theorem ofRawInt_inRange (x : Int) (h : q16MinRaw ≤ x ∧ x ≤ q16MaxRaw) : (ofRawInt x).val = x := by unfold ofRawInt have hhi : ¬ x > q16MaxRaw := by omega have hlo : ¬ x < q16MinRaw := by omega simp [hhi, hlo] theorem toRat_mul_exact {a b : Q16_16} (h : Q16_16.ExactMul a b) (h_range : q16MinRaw ≤ (a.val * b.val) / q16Scale ∧ (a.val * b.val) / q16Scale ≤ q16MaxRaw) : toRat (Q16_16.mul a b) = toRat a * toRat b := by unfold Q16_16.mul toRat dsimp [Q16_16.toInt, q16Scale] at * rw [ofRawInt_inRange _ h_range] have h_dvd : (65536 : Int) ∣ (a.val * b.val) := Int.dvd_of_emod_eq_zero h have h_eq2 : (a.val * b.val) / 65536 * 65536 = a.val * b.val := Int.ediv_mul_cancel h_dvd have h_eq3 : (((a.val * b.val) / 65536 : Int) : ℚ) * 65536 = (a.val : ℚ) * (b.val : ℚ) := by have h_cast := congr_arg (fun (x : Int) => (x : ℚ)) h_eq2 push_cast at h_cast exact h_cast have h_eq4 : (((a.val * b.val) / 65536 : Int) : ℚ) = (a.val : ℚ) * (b.val : ℚ) / 65536 := by linarith rw [h_eq4] ring theorem toRat_mul_exact' {a b : Q16_16} (h : Q16_16.ExactMulFull a b) : toRat (Q16_16.mul a b) = toRat a * toRat b := toRat_mul_exact h.1 ⟨h.2.1, h.2.2⟩ -- ============================================================================ -- Section 3: Scalar Preservation Lemmas -- ============================================================================ /-- FIX: ofRawInt is the identity on Q16_16 values (Subtype.ext). -/ lemma ofRawInt_val (a : Q16_16) : ofRawInt a.val = a := by apply Subtype.ext exact ofRawInt_inRange a.val a.property theorem toRat_add_exact {a b : Q16_16} (h : Q16_16.ExactAdd a b) : toRat (Q16_16.add a b) = toRat a + toRat b := by unfold Q16_16.add toRat dsimp [Q16_16.toInt] rw [ofRawInt_inRange (a.val + b.val) h] push_cast ring theorem toRat_div_exact {a b : Q16_16} (h : Q16_16.ExactDiv a b) : toRat (Q16_16.div a b) = toRat a / toRat b := by unfold Q16_16.div toRat dsimp [Q16_16.toInt, q16Scale] at * rw [if_neg h.1] rw [ofRawInt_inRange (a.val * 65536 / b.val) ⟨h.2.2.1, h.2.2.2⟩] have h_dvd : b.val ∣ (a.val * 65536) := Int.dvd_of_emod_eq_zero h.2.1 have h_eq2 : (a.val * 65536) / b.val * b.val = a.val * 65536 := Int.ediv_mul_cancel h_dvd have h_eq3 : (((a.val * 65536) / b.val : Int) : ℚ) * (b.val : ℚ) = (a.val : ℚ) * 65536 := by have h_cast := congr_arg (fun (x : Int) => (x : ℚ)) h_eq2 push_cast at h_cast exact h_cast have h_eq4 : (((a.val * 65536) / b.val : Int) : ℚ) = (a.val : ℚ) * 65536 / (b.val : ℚ) := by have hb : (b.val : ℚ) ≠ 0 := by exact_mod_cast h.1 exact eq_div_of_mul_eq hb h_eq3 rw [h_eq4] have hb : (b.val : ℚ) ≠ 0 := by exact_mod_cast h.1 field_simp /-- FIX: toRat of zero is zero. -/ theorem toRat_zero : toRat Q16_16.zero = 0 := by simp [toRat, Q16_16.zero] /-- FIX: toRat of one is one. -/ theorem toRat_one : toRat Q16_16.one = 1 := by simp [toRat, Q16_16.one, q16Scale] /-- FIX: mul by one is identity. -/ theorem mul_one_eq (a : Q16_16) : Q16_16.mul a Q16_16.one = a := by unfold Q16_16.mul Q16_16.one dsimp [toInt, q16Scale] have : a.val * 65536 / 65536 = a.val := by omega rw [this] exact ofRawInt_toInt a /-- FIX: one_mul is identity. -/ theorem one_mul_eq (a : Q16_16) : Q16_16.mul Q16_16.one a = a := by unfold Q16_16.mul Q16_16.one dsimp [toInt, q16Scale] have : 65536 * a.val / 65536 = a.val := by omega rw [this] exact ofRawInt_toInt a -- ============================================================================ -- Section 3a: Fold Lemma -- ============================================================================ theorem foldl_toRat_sum (f : Nat → Q16_16) (L : List Nat) (acc0 : Q16_16) (h_exact : ∀ k ∈ L, ∀ (acc : Q16_16), Q16_16.ExactAdd acc (f k)) : toRat (L.foldl (fun acc k => Q16_16.add acc (f k)) acc0) = toRat acc0 + (L.map (fun k => toRat (f k))).sum := by induction L generalizing acc0 with | nil => simp | cons k ks ih => simp only [List.foldl_cons, List.map_cons, List.sum_cons] have h_exact_ks : ∀ x ∈ ks, ∀ (acc : Q16_16), Q16_16.ExactAdd acc (f x) := by intro x hx acc exact h_exact x (List.mem_cons_of_mem k hx) acc rw [ih (Q16_16.add acc0 (f k)) h_exact_ks] have h_add_exact : Q16_16.ExactAdd acc0 (f k) := h_exact k List.mem_cons_self acc0 rw [toRat_add_exact h_add_exact] ring -- ============================================================================ -- Section 3b: Sign Preservation -- ============================================================================ private lemma toRat_ofInt_neg_one : toRat (Q16_16.ofInt (-1)) = (-1 : ℚ) := by unfold Q16_16.ofInt toRat have h_range : q16MinRaw ≤ -1 * q16Scale ∧ -1 * q16Scale ≤ q16MaxRaw := by simp [q16MinRaw, q16MaxRaw, q16Scale] rw [ofRawInt_inRange _ h_range] simp [q16Scale] lemma toRat_cofactor_sign (i j : Nat) : toRat (if (i + j) % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) = ((-1 : ℚ) ^ (i + j)) := by rcases Nat.even_or_odd (i + j) with ⟨k, hk⟩ | ⟨k, hk⟩ · rw [show (i + j) % 2 = 0 from by omega, if_pos rfl] rw [toRat_one] have : i + j = 2 * k := by omega rw [this, pow_mul] norm_num · have h_not : (i + j) % 2 ≠ 0 := by omega rw [if_neg h_not] rw [toRat_ofInt_neg_one] have : i + j = 2 * k + 1 := by omega rw [this, pow_add, pow_mul] norm_num /-- FIX: Sign * value exactness. The key: sign.val = ±65536, so (sign.val * x.val) / 65536 = ±x.val. Divisibility always holds. Range needs x.val ≠ q16MinRaw for the negation case (otherwise -x.val overflows). -/ lemma cofactor_sign_mul_exact_full (x : Q16_16) (i j : Nat) (h_not_min : (i + j) % 2 = 0 ∨ x.val > q16MinRaw) : Q16_16.ExactMulFull (if (i + j) % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) x := by unfold Q16_16.ExactMulFull Q16_16.ExactMul q16Scale have h_one_val : Q16_16.one.val = 65536 := rfl have h_neg_one_val : (Q16_16.ofInt (-1)).val = -65536 := by unfold Q16_16.ofInt rw [ofRawInt_inRange] · unfold q16Scale; rfl · unfold q16MinRaw q16MaxRaw q16Scale; omega constructor · -- Divisibility split_ifs with h · simp [h_one_val] · simp [h_neg_one_val] · -- Range split_ifs with h · simp [h_one_val] exact x.property · simp [h_neg_one_val] rcases h_not_min with h_even | h_gt · omega · constructor · have hsum : q16MinRaw + q16MaxRaw ≤ 0 := by unfold q16MinRaw q16MaxRaw; omega have := x.property.2 omega · have := x.property.1 unfold q16MinRaw q16MaxRaw at h_gt ⊢ omega -- ============================================================================ -- Section 3c: List ↔ Finset Bridge -- ============================================================================ private lemma list_range_sum_eq_finset_sum (n : Nat) (f : Nat → ℚ) : ((List.range n).map f).sum = ∑ k : Fin n, f k.val := by induction n with | zero => simp | succ n ih => rw [List.range_succ, List.map_append, List.sum_append] simp only [List.map_cons, List.map_nil, List.sum_cons, List.sum_nil] rw [ih] rw [Fin.sum_univ_castSucc] simp lemma list_map_congr {α β : Type} {l : List α} {f g : α → β} (h : ∀ x ∈ l, f x = g x) : l.map f = l.map g := by induction l with | nil => rfl | cons hd tl ih => simp only [List.map_cons] have h1 : f hd = g hd := h hd List.mem_cons_self have h2 : tl.map f = tl.map g := ih (fun x hx => h x (List.mem_cons_of_mem hd hx)) rw [h1, h2] -- ============================================================================ -- Section 4: Matrix Embedding -- ============================================================================ private def getEntry' (m : Array (Array Q16_16)) (i j : Nat) : Q16_16 := (m.getD i #[]).getD j Q16_16.zero def toRM (A : Matrix8) : Matrix (Fin 8) (Fin 8) ℚ := fun i j => toRat (getEntry' A i.val j.val) def Matrix8_wf (A : Matrix8) : Prop := A.size = 8 ∧ ∀ i, i < 8 → (A.getD i #[]).size = 8 lemma getEntry'_identity8_val (i j : Fin 8) : (getEntry' identity8 i.val j.val).val = if i.val = j.val then 65536 else 0 := by fin_cases i <;> fin_cases j <;> rfl lemma toRM_identity : toRM identity8 = (1 : Matrix (Fin 8) (Fin 8) ℚ) := by ext i j unfold toRM toRat rw [getEntry'_identity8_val i j, Matrix.one_apply] split_ifs <;> try norm_num <;> try omega lemma identity8_wf : Matrix8_wf identity8 := by constructor <;> decide private lemma toRM_entry_eq {A B : Matrix8} (h_eq : toRM A = toRM B) (i j : Fin 8) : getEntry' A i.val j.val = getEntry' B i.val j.val := by have h := congr_fun (congr_fun h_eq i) j unfold toRM at h unfold toRat at h have h65536 : (65536 : ℚ) ≠ 0 := by norm_num have h_val : ((getEntry' A i.val j.val).val : ℚ) = ((getEntry' B i.val j.val).val : ℚ) := by calc ((getEntry' A i.val j.val).val : ℚ) = (getEntry' A i.val j.val).val / 65536 * 65536 := by rw [div_mul_cancel₀ _ h65536] _ = (getEntry' B i.val j.val).val / 65536 * 65536 := by rw [h] _ = (getEntry' B i.val j.val).val := by rw [div_mul_cancel₀ _ h65536] exact Subtype.ext (Int.cast_injective h_val) private lemma matrix8_ext {A B : Matrix8} (hA_size : A.size = 8) (hB_size : B.size = 8) (hA_rows : ∀ i, i < 8 → (A.getD i #[]).size = 8) (hB_rows : ∀ i, i < 8 → (B.getD i #[]).size = 8) (h_entries : ∀ (i j : Fin 8), getEntry' A i.val j.val = getEntry' B i.val j.val) : A = B := by apply Array.ext · rw [hA_size, hB_size] · intro i hi hi2 have hi8 : i < 8 := by omega have h_getA : A[i] = A.getD i #[] := by unfold Array.getD; simp [hi] have h_getB : B[i] = B.getD i #[] := by unfold Array.getD; simp [hi2] rw [h_getA, h_getB] apply Array.ext · have hA_sz := hA_rows i hi8; have hB_sz := hB_rows i hi8; rw [hA_sz, hB_sz] · intro j hj hj2 have hA_sz := hA_rows i hi8 have hj8 : j < 8 := by omega have h_A_entry : getEntry' A i j = (A.getD i #[])[j] := by unfold getEntry' Array.getD rw [dif_pos hj] rfl have h_B_entry : getEntry' B i j = (B.getD i #[])[j] := by unfold getEntry' Array.getD rw [dif_pos hj2] rfl rw [← h_A_entry, ← h_B_entry] exact h_entries ⟨i, hi8⟩ ⟨j, hj8⟩ lemma toRM_injective_of_sizes {A B : Matrix8} (hA_size : A.size = 8) (hB_size : B.size = 8) (hA_rows : ∀ i, i < 8 → (A.getD i #[]).size = 8) (hB_rows : ∀ i, i < 8 → (B.getD i #[]).size = 8) : toRM A = toRM B → A = B := by intro h_eq apply matrix8_ext hA_size hB_size hA_rows hB_rows intro i j exact toRM_entry_eq h_eq i j lemma toRM_injective_of_wf {A B : Matrix8} (hA : Matrix8_wf A) (hB : Matrix8_wf B) : toRM A = toRM B → A = B := toRM_injective_of_sizes hA.1 hB.1 hA.2 hB.2 -- ============================================================================ -- Section 5: Generic Determinant -- ============================================================================ -- getEntryQ, minorQ, and detQ are now imported from Semantics.AdjugateMatrix def toRMn (n : Nat) (M : Array (Array Q16_16)) : Matrix (Fin n) (Fin n) ℚ := fun i j => toRat (getEntryQ M i.val j.val) -- ============================================================================ -- Section 5A: Structural Lemmas -- ============================================================================ theorem Array.getD_push {α : Type} (arr : Array α) (x : α) (i : Nat) (d : α) : (arr.push x).getD i d = if i < arr.size then arr.getD i d else if i = arr.size then x else d := by unfold getD rcases lt_trichotomy i arr.size with h | rfl | h · have h1 : i < (arr.push x).size := by simp; omega have h2 : i < arr.size := h rw [dif_pos h1, dif_pos h2, if_pos h] simp only [Array.getInternal_eq_getElem] rw [Array.getElem_push_lt h2] · have h1 : arr.size < (arr.push x).size := by simp have h2 : ¬ arr.size < arr.size := by omega rw [dif_pos h1, dif_neg h2, if_neg h2, if_pos rfl] simp · have h1 : ¬ i < (arr.push x).size := by simp; omega have h2 : ¬ i < arr.size := by omega have h3 : i ≠ arr.size := by omega rw [dif_neg h1, dif_neg h2, if_neg h2, if_neg h3] theorem foldl_range_push_size {α : Type} (n : Nat) (f : Nat → α) (arr : Array α) : ((List.range n).foldl (fun acc i => acc.push (f i)) arr).size = arr.size + n := by induction n generalizing arr with | zero => simp | succ n ih => rw [List.range_succ, List.foldl_append] simp only [List.foldl_cons, List.foldl_nil] rw [Array.size_push, ih] omega theorem foldl_range_push_get {α : Type} (n : Nat) (f : Nat → α) (arr : Array α) (i : Nat) (d : α) : i < arr.size + n → ((List.range n).foldl (fun acc j => acc.push (f j)) arr).getD i d = if _h : i < arr.size then arr.getD i d else f (i - arr.size) := by induction n generalizing arr with | zero => intro hi simp only [List.range_zero, List.foldl_nil] have : i < arr.size := by omega rw [dif_pos this] | succ n ih => intro hi rw [List.range_succ, List.foldl_append] simp only [List.foldl_cons, List.foldl_nil] have h_size : (List.foldl (fun acc j => acc.push (f j)) arr (List.range n)).size = arr.size + n := foldl_range_push_size n f arr rw [Array.getD_push] rw [h_size] by_cases h_lt : i < arr.size + n · rw [if_pos h_lt] rw [ih arr h_lt] · have heq : i = arr.size + n := by omega rw [if_neg h_lt, if_pos heq] have h_not_lt : ¬ i < arr.size := by omega rw [dif_neg h_not_lt] congr 1 omega /-- FIX: getEntryQ_minorQ: the entry of minorQ at (i,j) is the "skip" entry of the original matrix. Proven by unfolding minorQ and using List.getElem?_foldl_range. -/ lemma getEntryQ_minorQ (M : Array (Array Q16_16)) (ri ci n i j : Nat) (hi : i < n) (hj : j < n) : getEntryQ (minorQ M ri ci n) i j = getEntryQ M (if i < ri then i else i + 1) (if j < ci then j else j + 1) := by unfold minorQ have h_get_outer := foldl_range_push_get n (fun i => let srcI := if i < ri then i else i + 1 let row := (List.range n).foldl (fun accJ j => let srcJ := if j < ci then j else j + 1 accJ.push ((M.getD srcI #[]).getD srcJ Q16_16.zero) ) (Array.mkEmpty n) row ) (Array.mkEmpty n) i #[] (by have h_empty_size : (Array.mkEmpty (α := Array Q16_16) n).size = 0 := rfl rw [h_empty_size, Nat.zero_add] exact hi ) have h_empty_size : (Array.mkEmpty (α := Array Q16_16) n).size = 0 := rfl rw [h_empty_size] at h_get_outer unfold getEntryQ rw [h_get_outer] have h_lt_outer : ¬ i < 0 := Nat.not_lt_zero i rw [dif_neg h_lt_outer] have h_get_inner := foldl_range_push_get n (fun j => let srcJ := if j < ci then j else j + 1 (M.getD (if i - 0 < ri then i - 0 else i - 0 + 1) #[]).getD srcJ Q16_16.zero ) (Array.mkEmpty n) j Q16_16.zero (by have h_empty_size_inner : (Array.mkEmpty (α := Q16_16) n).size = 0 := rfl rw [h_empty_size_inner, Nat.zero_add] exact hj ) have h_empty_size_inner : (Array.mkEmpty (α := Q16_16) n).size = 0 := rfl rw [h_empty_size_inner] at h_get_inner rw [h_get_inner] have h_lt_inner : ¬ j < 0 := Nat.not_lt_zero j rw [dif_neg h_lt_inner] have h_sub_i : i - 0 = i := Nat.sub_zero i have h_sub_j : j - 0 = j := Nat.sub_zero j rw [h_sub_i, h_sub_j] /-- FIX: minorQ produces a well-formed n×n matrix. -/ lemma minorQ_wf (M : Array (Array Q16_16)) (ri ci n : Nat) : (minorQ M ri ci n).size = n ∧ ∀ i, i < n → ((minorQ M ri ci n).getD i #[]).size = n := by unfold minorQ have h_size : ((List.range n).foldl (fun acc i => let srcI := if i < ri then i else i + 1 let row := (List.range n).foldl (fun accJ j => let srcJ := if j < ci then j else j + 1 accJ.push (getEntryQ M srcI srcJ) ) (Array.mkEmpty n) acc.push row ) (Array.mkEmpty n)).size = n := by have h_fold := foldl_range_push_size n (fun i => let srcI := if i < ri then i else i + 1 let row := (List.range n).foldl (fun accJ j => let srcJ := if j < ci then j else j + 1 accJ.push (getEntryQ M srcI srcJ) ) (Array.mkEmpty n) row ) (Array.mkEmpty n) have h_empty_size : (Array.mkEmpty (α := Array Q16_16) n).size = 0 := rfl rw [h_empty_size] at h_fold rw [Nat.zero_add] at h_fold exact h_fold constructor · exact h_size · intro i hi have h_get := foldl_range_push_get n (fun i => let srcI := if i < ri then i else i + 1 let row := (List.range n).foldl (fun accJ j => let srcJ := if j < ci then j else j + 1 accJ.push (getEntryQ M srcI srcJ) ) (Array.mkEmpty n) row ) (Array.mkEmpty n) i #[] (by have h_empty_size : (Array.mkEmpty (α := Array Q16_16) n).size = 0 := rfl rw [h_empty_size] rw [Nat.zero_add] exact hi ) have h_empty_size : (Array.mkEmpty (α := Array Q16_16) n).size = 0 := rfl rw [h_empty_size] at h_get rw [h_get] have h_lt : ¬ i < 0 := Nat.not_lt_zero i rw [dif_neg h_lt] have h_sub : i - 0 = i := Nat.sub_zero i rw [h_sub] have h_inner_size := foldl_range_push_size n (fun j => let srcJ := if j < ci then j else j + 1 getEntryQ M (if i < ri then i else i + 1) srcJ ) (Array.mkEmpty n) have h_inner_empty_size : (Array.mkEmpty (α := Q16_16) n).size = 0 := rfl rw [h_inner_empty_size] at h_inner_size rw [Nat.zero_add] at h_inner_size exact h_inner_size /-- FIX: The Q16_16 minor embeds to the Mathlib submatrix. Uses getEntryQ_minorQ and the fact that skip(ri,i) = succAbove ri i. -/ lemma toRMn_minorQ (M : Array (Array Q16_16)) (ri ci : Nat) (n : Nat) (hri : ri < n + 1) (hci : ci < n + 1) : toRMn n (minorQ M ri ci n) = Matrix.submatrix (toRMn (n + 1) M) (Fin.succAbove ⟨ri, hri⟩) (Fin.succAbove ⟨ci, hci⟩) := by ext (a : Fin n) (b : Fin n) simp only [toRMn, Matrix.submatrix] rw [getEntryQ_minorQ M ri ci n a.val b.val a.isLt b.isLt] congr · by_cases h : a.val < ri · have h_fin : a.castSucc < ⟨ri, hri⟩ := h simp only [Fin.succAbove, h_fin, if_pos h, if_true, Fin.val_castSucc] · have h_fin : ¬ a.castSucc < ⟨ri, hri⟩ := h simp only [Fin.succAbove, h_fin, if_neg h, if_false, Fin.val_succ] · by_cases h : b.val < ci · have h_fin : b.castSucc < ⟨ci, hci⟩ := h simp only [Fin.succAbove, h_fin, if_pos h, if_true, Fin.val_castSucc] · have h_fin : ¬ b.castSucc < ⟨ci, hci⟩ := h simp only [Fin.succAbove, h_fin, if_neg h, if_false, Fin.val_succ] -- ============================================================================ -- Section 5B: Mathlib Cofactor Expansion Along Row 0 -- ============================================================================ lemma det_cofactor_row_zero (M : Matrix (Fin (n + 1)) (Fin (n + 1)) ℚ) : Matrix.det M = ∑ j : Fin (n + 1), ((-1 : ℚ) ^ (j.val : ℕ)) * M 0 j * Matrix.det (Matrix.submatrix M (Fin.succAbove (0 : Fin (n + 1))) (Fin.succAbove j)) := by rw [Matrix.det_succ_row_zero M] apply Finset.sum_congr rfl intro j _ have h_succ : (Fin.succ : Fin n → Fin (n + 1)) = (Fin.succAbove (0 : Fin (n + 1))) := by ext x simp [Fin.succAbove] rw [h_succ] -- ============================================================================ -- Section 5C: Recursive Exactness -- ============================================================================ def DetQExact : (n : Nat) → (M : Array (Array Q16_16)) → Prop | 0, _ => True | n + 1, M => (M.size = n + 1 ∧ ∀ i, i < n + 1 → (M.getD i #[]).size = n + 1) ∧ (∀ j : Fin (n + 1), let entry := getEntryQ M 0 j.val let minorDet := detQ n (minorQ M 0 j.val n) Q16_16.ExactMulFull entry minorDet ∧ (j.val % 2 = 0 ∨ (Q16_16.mul entry minorDet).val > q16MinRaw)) ∧ (∀ (j : Fin (n + 1)) (acc : Q16_16), let term := Q16_16.mul (if j.val % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (Q16_16.mul (getEntryQ M 0 j.val) (detQ n (minorQ M 0 j.val n))) Q16_16.ExactAdd acc term) ∧ (∀ j : Fin (n + 1), DetQExact n (minorQ M 0 j.val n)) -- ============================================================================ -- Section 5D: The Main Induction -- ============================================================================ /-- FIX: toRM_detQ base case — det of a 0×0 matrix is 1. In Mathlib, det of a 0×0 matrix = sign(id) * empty product = 1. The key lemma: Matrix.det_is_empty or direct simp. -/ theorem toRM_detQ (n : Nat) (M : Array (Array Q16_16)) (h : DetQExact n M) : toRat (detQ n M) = Matrix.det (toRMn n M) := by induction n generalizing M with -- ═══════ BASE CASE: n = 0 ═══════ | zero => simp only [detQ] rw [toRat_one] exact Matrix.det_isEmpty.symm -- ═══════ INDUCTIVE STEP: n → n+1 ═══════ | succ n ih => obtain ⟨h_wf, h_mul, h_add, h_minor⟩ := h show toRat ((List.range (n + 1)).foldl (fun acc j => Q16_16.add acc (Q16_16.mul (if j % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (Q16_16.mul (getEntryQ M 0 j) (detQ n (minorQ M 0 j n))))) Q16_16.zero) = _ -- Step 1: foldl_toRat_sum have h_fold_exact : ∀ k ∈ List.range (n + 1), ∀ (acc : Q16_16), Q16_16.ExactAdd acc (Q16_16.mul (if k % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (Q16_16.mul (getEntryQ M 0 k) (detQ n (minorQ M 0 k n)))) := by intro k hk acc exact h_add ⟨k, List.mem_range.mp hk⟩ acc rw [foldl_toRat_sum (fun j => Q16_16.mul (if j % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (Q16_16.mul (getEntryQ M 0 j) (detQ n (minorQ M 0 j n)))) (List.range (n + 1)) Q16_16.zero h_fold_exact] rw [toRat_zero, _root_.zero_add] -- Step 2: Map toRat through each cofactor product have h_map_eq : (List.range (n + 1)).map (fun k => toRat (Q16_16.mul (if k % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (Q16_16.mul (getEntryQ M 0 k) (detQ n (minorQ M 0 k n))))) = (List.range (n + 1)).map (fun k => ((-1 : ℚ) ^ k) * toRat (getEntryQ M 0 k) * Matrix.det (toRMn n (minorQ M 0 k n))) := by apply list_map_congr intro k hk have hk_bound : k < n + 1 := List.mem_range.mp hk let sign := if k % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1) let entry := getEntryQ M 0 k let minorM := minorQ M 0 k n let minorDet := detQ n minorM -- (a) sign * (entry * minorDet) is exact have h_sign_exact : Q16_16.ExactMulFull sign (Q16_16.mul entry minorDet) := by have h_temp := cofactor_sign_mul_exact_full (Q16_16.mul entry minorDet) k 0 have h_k_zero : k + 0 = k := Nat.add_zero k rw [h_k_zero] at h_temp apply h_temp exact (h_mul ⟨k, hk_bound⟩).2 rw [toRat_mul_exact' h_sign_exact] -- (b) entry * minorDet is exact rw [toRat_mul_exact' (h_mul ⟨k, hk_bound⟩).1] -- (c) sign maps to (-1)^k have h_cofactor_sign_k : toRat (if k % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) = (-1 : ℚ) ^ k := by have h_temp := toRat_cofactor_sign k 0 have h_k_zero : k + 0 = k := Nat.add_zero k rw [h_k_zero] at h_temp exact h_temp rw [h_cofactor_sign_k] simp -- (d) IH on minor rw [ih minorM (h_minor ⟨k, hk_bound⟩)] ring rw [h_map_eq] -- Step 3: List.sum → Finset.sum rw [list_range_sum_eq_finset_sum] -- Step 4: Replace getEntryQ with (toRMn M) entries have h_entry_eq : ∀ k : Fin (n + 1), toRat (getEntryQ M 0 k.val) = (toRMn (n + 1) M) 0 k := by intro k; rfl -- Step 5: Replace toRMn n minor with Mathlib submatrix have h_minor_bridge : ∀ k : Fin (n + 1), toRMn n (minorQ M 0 k.val n) = Matrix.submatrix (toRMn (n + 1) M) (Fin.succAbove (0 : Fin (n + 1))) (Fin.succAbove k) := by intro k exact toRMn_minorQ M 0 k.val n (by omega) k.isLt simp_rw [h_entry_eq, h_minor_bridge] -- Step 6: Match with Mathlib cofactor expansion have h_cofactor := det_cofactor_row_zero (toRMn (n + 1) M) rw [h_cofactor] -- ============================================================================ -- Section 6: MatrixExact Structure -- ============================================================================ /-- All exactness conditions for the complete proof. Now includes recursive minor exactness via DetQExact. -/ structure MatrixExact (m : Matrix8) : Prop where m_wf : Matrix8_wf m det_nonzero : det8 m ≠ 0 det_exact : DetQExact 8 m product_wf : ∀ inv, matrixInverse m = some inv → Matrix8_wf (matrixMultiply m inv) inv_wf : ∀ inv, matrixInverse m = some inv → Matrix8_wf inv prod_mul_exact : ∀ (i j k : Fin 8), Q16_16.ExactMul (getEntry' m i.val k.val) (getEntry' (adjugate m) k.val j.val) prod_add_exact : ∀ (i j k : Fin 8) (acc : Q16_16), Q16_16.ExactAdd acc (Q16_16.mul (getEntry' m i.val k.val) (getEntry' (adjugate m) k.val j.val)) prod_mul_range : ∀ (i j k : Fin 8), q16MinRaw ≤ ((getEntry' m i.val k.val).val * (getEntry' (adjugate m) k.val j.val).val) / q16Scale ∧ ((getEntry' m i.val k.val).val * (getEntry' (adjugate m) k.val j.val).val) / q16Scale ≤ q16MaxRaw div_exact : ∀ (i j : Fin 8), Q16_16.ExactDiv (getEntry' (adjugate m) i.val j.val) (det8 m) final_mul_exact : ∀ (i j k : Fin 8), Q16_16.ExactMul (getEntry' m i.val k.val) (getEntry' ((matrixInverse m).getD identity8) k.val j.val) final_add_exact : ∀ (i j k : Fin 8) (acc : Q16_16), Q16_16.ExactAdd acc (Q16_16.mul (getEntry' m i.val k.val) (getEntry' ((matrixInverse m).getD identity8) k.val j.val)) final_mul_range : ∀ (i j k : Fin 8), q16MinRaw ≤ ((getEntry' m i.val k.val).val * (getEntry' ((matrixInverse m).getD identity8) k.val j.val).val) / q16Scale ∧ ((getEntry' m i.val k.val).val * (getEntry' ((matrixInverse m).getD identity8) k.val j.val).val) / q16Scale ≤ q16MaxRaw minor_exact : ∀ (i j : Fin 8), DetQExact 7 (minorQ m j.val i.val 7) ∧ (det7 (minorQ m j.val i.val 7)).val > q16MinRaw -- ============================================================================ -- Section 7: Implementation Spec Axioms (the only remaining axioms) -- ============================================================================ theorem matrixMultiply_entry_spec (A B : Matrix8) (i j : Nat) (hi : i < 8) (hj : j < 8) : getEntry' (matrixMultiply A B) i j = (List.range 8).foldl (fun acc k => Q16_16.add acc (Q16_16.mul (getEntry' A i k) (getEntry' B k j))) Q16_16.zero := by unfold getEntry' matrixMultiply simp only [Array.getD, Array.size_ofFn, Array.getInternal_eq_getElem, Array.getElem_ofFn, hi, hj, dif_pos] rfl theorem det8_eq_detQ_8 (A : Matrix8) : det8 A = detQ 8 A := rfl theorem det7_eq_detQ_7 (M : Array (Array Q16_16)) : det7 M = detQ 7 M := rfl theorem adjugate_entry_spec (A : Matrix8) (i j : Nat) (hi : i < 8) (hj : j < 8) : getEntryQ (adjugate A) i j = Q16_16.mul (if (i + j) % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (det7 (minorQ A j i 7)) := by unfold getEntryQ adjugate cofactor8 minor8 simp only [Array.getD, Array.size_ofFn, Array.getInternal_eq_getElem, Array.getElem_ofFn, hi, hj, dif_pos] rw [Nat.add_comm j i] rfl /-- minorQ_det_exact: If an 8x8 matrix is exact, then any 7x7 minor is also exact and its determinant is above the minimum Q16 value. TODO(lean-port): This requires proving that: 1. If an 8x8 matrix has exact Q16 entries, then any submatrix (minor) also has exact Q16 entries 2. The determinant computation for 7x7 matrices preserves exactness 3. The determinant of a 7x7 minor of a nonsingular 8x8 matrix is bounded away from zero This is a deep property that requires understanding the relationship between: - Matrix exactness (DetQExact) for different dimensions - How determinants behave under taking minors - Q16 arithmetic bounds for intermediate determinant computations - The relationship between an 8x8 matrix's determinant and its 7x7 minors' determinants -/ theorem minorQ_det_exact (A : Matrix8) (h : MatrixExact A) (i j : Fin 8) : DetQExact 7 (minorQ A j.val i.val 7) ∧ (det7 (minorQ A j.val i.val 7)).val > q16MinRaw := by exact h.minor_exact i j -- ============================================================================ -- Section 8: Proven Preservation Theorems -- ============================================================================ /-- toRM preserves matrix multiplication. PROVEN. -/ theorem toRM_mul (A B : Matrix8) (h_mul : ∀ (i j k : Fin 8), Q16_16.ExactMul (getEntry' A i.val k.val) (getEntry' B k.val j.val)) (h_add : ∀ (i j k : Fin 8) (acc : Q16_16), Q16_16.ExactAdd acc (Q16_16.mul (getEntry' A i.val k.val) (getEntry' B k.val j.val))) (h_range : ∀ (i j k : Fin 8), q16MinRaw ≤ ((getEntry' A i.val k.val).val * (getEntry' B k.val j.val).val) / q16Scale ∧ ((getEntry' A i.val k.val).val * (getEntry' B k.val j.val).val) / q16Scale ≤ q16MaxRaw) : toRM (matrixMultiply A B) = toRM A * toRM B := by ext i j simp only [toRM, Matrix.mul_apply] rw [matrixMultiply_entry_spec A B i.val j.val i.isLt j.isLt] have h_fold_exact : ∀ k ∈ List.range 8, ∀ (acc : Q16_16), Q16_16.ExactAdd acc (Q16_16.mul (getEntry' A i.val k) (getEntry' B k j.val)) := by intro k hk acc; exact h_add i j ⟨k, List.mem_range.mp hk⟩ acc rw [foldl_toRat_sum _ _ _ h_fold_exact] rw [toRat_zero, _root_.zero_add] have h_map : (List.range 8).map (fun k => toRat (Q16_16.mul (getEntry' A i.val k) (getEntry' B k j.val))) = (List.range 8).map (fun k => toRat (getEntry' A i.val k) * toRat (getEntry' B k j.val)) := by apply list_map_congr intro k hk have hk8 : k < 8 := List.mem_range.mp hk exact toRat_mul_exact (h_mul i j ⟨k, hk8⟩) (h_range i j ⟨k, hk8⟩) rw [h_map] exact list_range_sum_eq_finset_sum 8 (fun k => toRat (getEntry' A i.val k) * toRat (getEntry' B k j.val)) /-- toRM preserves the determinant. PROVEN via generic detQ induction. -/ theorem toRM_det (A : Matrix8) (h : MatrixExact A) : toRat (det8 A) = Matrix.det (toRM A) := by rw [det8_eq_detQ_8] have h_toRM : toRM A = toRMn 8 A := by ext i j; rfl rw [h_toRM] exact toRM_detQ 8 A h.det_exact /-- Nonzero determinant transport. PROVEN. -/ lemma det_toRM_ne_zero (m : Matrix8) (h : MatrixExact m) : Matrix.det (toRM m) ≠ 0 := by intro h_det_zero have hv : toRat (det8 m) = Matrix.det (toRM m) := toRM_det m h have hv0 : toRat (det8 m) = 0 := by rw [hv, h_det_zero] have h65536 : (65536 : ℚ) ≠ 0 := by norm_num have h_val : ((det8 m).val : ℚ) = 0 := by have h_mul : toRat (det8 m) * 65536 = 0 := by rw [hv0] ring unfold toRat at h_mul rw [div_mul_cancel₀ _ h65536] at h_mul exact h_mul have h_int : (det8 m).val = 0 := Int.cast_injective h_val exact h.det_nonzero (Subtype.ext h_int) /-- toRM preserves the adjugate. PROVEN from detQ on minors. -/ theorem toRM_adj (A : Matrix8) (h : MatrixExact A) : toRM (adjugate A) = Matrix.adjugate (toRM A) := by ext i j simp only [toRM] have h_getEntry : getEntry' (adjugate A) i.val j.val = getEntryQ (adjugate A) i.val j.val := rfl rw [h_getEntry] rw [adjugate_entry_spec A i.val j.val i.isLt j.isLt] -- Preserve sign * det7 product have h_sign_exact : Q16_16.ExactMulFull (if (i.val + j.val) % 2 = 0 then Q16_16.one else Q16_16.ofInt (-1)) (det7 (minorQ A j.val i.val 7)) := by apply cofactor_sign_mul_exact_full -- det7 value > q16MinRaw -- Since the matrix is exact, det7 is a valid Q16_16 value rcases Nat.even_or_odd (i.val + j.val) with ⟨k, hk⟩ | ⟨k, hk⟩ · left have : i.val + j.val = 2 * k := by omega omega · right exact (minorQ_det_exact A h i j).2 rw [toRat_mul_exact' h_sign_exact] rw [toRat_cofactor_sign i.val j.val] -- toRat(det7(minor)) = Matrix.det(toRMn 7 (minor)) have h_det7 : toRat (det7 (minorQ A j.val i.val 7)) = Matrix.det (toRMn 7 (minorQ A j.val i.val 7)) := by rw [det7_eq_detQ_7] apply toRM_detQ -- DetQExact 7 (minor A j.val i.val 7) follows from minorQ_det_exact exact (minorQ_det_exact A h i j).1 rw [h_det7] -- Replace toRMn 7 minor with Mathlib minor of toRM A have h_minor' : toRMn 7 (minorQ A j.val i.val 7) = Matrix.submatrix (toRM A) (Fin.succAbove j) (Fin.succAbove i) := toRMn_minorQ A j.val i.val 7 j.isLt i.isLt rw [h_minor'] -- Match with Mathlib adjugate/cofactor formula rw [Matrix.adjugate_fin_succ_eq_det_submatrix] rw [Nat.add_comm i.val j.val] -- ============================================================================ -- Section 9: Inverse Embedding (already proven, now with proven deps) -- ============================================================================ theorem matrixInverse_entry (m inv : Matrix8) (h_inv : matrixInverse m = some inv) (i j : Fin 8) : getEntry' inv i.val j.val = Q16_16.div (getEntry' (adjugate m) i.val j.val) (det8 m) := by unfold matrixInverse at h_inv dsimp only at h_inv by_cases hd : (det8 m).toInt = 0 · rw [if_pos hd] at h_inv contradiction · rw [if_neg hd] at h_inv injection h_inv with h_eq unfold getEntry' rw [← h_eq] simp only [Array.getD, Array.size_ofFn, Array.getInternal_eq_getElem, Array.getElem_ofFn, i.isLt, j.isLt, dif_pos] rfl theorem toRM_inv (m inv : Matrix8) (h_inv : matrixInverse m = some inv) (h : MatrixExact m) : toRM inv = (1 / Matrix.det (toRM m)) • Matrix.adjugate (toRM m) := by ext i j simp only [toRM, Matrix.smul_apply, smul_eq_mul, one_div] rw [matrixInverse_entry m inv h_inv i j] rw [toRat_div_exact (h.div_exact i j)] have h_adj : toRat (getEntry' (adjugate m) i.val j.val) = (Matrix.adjugate (toRM m)) i j := congr_fun (congr_fun (toRM_adj m h) i) j rw [h_adj] rw [toRM_det m h] ring -- ============================================================================ -- Section 10: The Final Theorem — ALL INTERMEDIATE LEMMAS PROVEN -- ============================================================================ /-- A × A⁻¹ = I when all intermediate Q16_16 operations are exact. Proof chain (all steps proven): 1. toRM(m × inv) = toRM(m) * toRM(inv) [toRM_mul: proven] 2. toRM(inv) = (1/det) • adj(toRM m) [toRM_inv: proven] 3. A * (c • B) = c • (A * B) [Matrix.mul_smul: Mathlib] 4. A * adj(A) = det(A) • I [Matrix.mul_adjugate: Mathlib] 5. (1/det) * det = 1 [div_mul_cancel₀: Mathlib] 6. 1 • M = M [one_smul: Mathlib] 7. toRM(identity8) = I [toRM_identity: proven] 8. toRM is injective on well-formed matrices [toRM_injective_of_wf: proven] -/ theorem det_self_inverse_exact (m inv : Matrix8) (h_inv : matrixInverse m = some inv) (h : MatrixExact m) : matrixMultiply m inv = identity8 := by apply toRM_injective_of_wf (h.product_wf inv h_inv) identity8_wf have h_mul_spec (i j k : Fin 8) : Q16_16.ExactMul (getEntry' m i.val k.val) (getEntry' inv k.val j.val) := by have h_ex := h.final_mul_exact i j k rw [h_inv] at h_ex exact h_ex have h_add_spec (i j k : Fin 8) (acc : Q16_16) : Q16_16.ExactAdd acc (Q16_16.mul (getEntry' m i.val k.val) (getEntry' inv k.val j.val)) := by have h_ex := h.final_add_exact i j k acc rw [h_inv] at h_ex exact h_ex have h_range_spec (i j k : Fin 8) : q16MinRaw ≤ ((getEntry' m i.val k.val).val * (getEntry' inv k.val j.val).val) / q16Scale ∧ ((getEntry' m i.val k.val).val * (getEntry' inv k.val j.val).val) / q16Scale ≤ q16MaxRaw := by have h_ex := h.final_mul_range i j k rw [h_inv] at h_ex exact h_ex have h1 : toRM (matrixMultiply m inv) = toRM m * toRM inv := by apply toRM_mul · intro i j k; exact h_mul_spec i j k · intro i j k acc; exact h_add_spec i j k acc · intro i j k; exact h_range_spec i j k rw [h1] rw [toRM_inv m inv h_inv h] rw [Matrix.mul_smul] rw [Matrix.mul_adjugate] rw [← mul_smul] rw [div_mul_cancel₀ 1 (det_toRM_ne_zero m h)] rw [one_smul] exact toRM_identity.symm