Research-Stack/0-Core-Formalism/lean/Semantics/Semantics/Q16InverseProof.lean
allaun 475f6319ea chore(repo): push local 768-commit branch state onto clean remote baseline
This squashes all local history (768 commits) onto the scrubbed PR #90
baseline. Individual commits were lost during filter-repo corruption;
the working tree content is preserved intact.

Build: N/A (working tree state only)
2026-06-15 22:46:50 -05:00

977 lines
38 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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