1-- Matrices as set-theoretic functions on pairs of natural indices.2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.LinearAlgebra.Matrix8import FiniteDimensional910-- Dimensions are cutoffs on a total array, so one matrix can be reused at11-- several finite sizes without changing its underlying set-theoretic graph.12predicate RealMatrix (M : Set) := FunctionBetween(M, ℕ × ℕ, ℝ)1314-- Coordinates are uniquely determined on the Cartesian product.15-- Extracting them needs only ZF and supports matrix graphs over index pairs.16defunique matrixFirstIndex (p : Set) (i ∈ ℕ) :=17∃ j ∈ ℕ, p = (i, j)18requires pair : p ∈ ℕ × ℕ19proof20have shape := product.membership.forward at ℕ, ℕ, p with pair21rcases shape with⟨bound, i, naturalI, j, naturalJ, equation⟩22witness i23refine⟨naturalI, j, naturalJ, equation⟩2425uniqueness26intros a aMember first c cMember second27obtain⟨b, bMember, firstPair⟩:= first28obtain⟨d, dMember, secondPair⟩:= second29have same : (a, b) = (c, d)30cc31have coordinates := orderedPair.injective at a, b, c, d with same32tauto3334defunique matrixSecondIndex (p : Set) (j ∈ ℕ) :=35∃ i ∈ ℕ, p = (i, j)36requires pair : p ∈ ℕ × ℕ37proof38have shape := product.membership.forward at ℕ, ℕ, p with pair39rcases shape with⟨bound, i, naturalI, j, naturalJ, equation⟩40witness j41refine⟨naturalJ, i, naturalI, equation⟩4243uniqueness44intros b bMember first d dMember second45obtain⟨a, aMember, firstPair⟩:= first46obtain⟨c, cMember, secondPair⟩:= second47have same : (a, b) = (c, d)48cc49have coordinates := orderedPair.injective at a, b, c, d with same50tauto5152theorem matrixFirstIndex.pair (i j : Nat)53shows matrixFirstIndex((i, j)) = i54proof55have naturalI : i ∈ ℕ bysimp [Nat]56have naturalJ : j ∈ ℕ bysimp [Nat]57have pair := product.pair with naturalI, naturalJ58obtain⟨natural, k, naturalK, shape⟩:= matrixFirstIndex.selected with pair59obtain⟨first, second⟩:= orderedPair.injective with shape60rw←first61rfl6263theorem matrixSecondIndex.pair (i j : Nat)64shows matrixSecondIndex((i, j)) = j65proof66have naturalI : i ∈ ℕ bysimp [Nat]67have naturalJ : j ∈ ℕ bysimp [Nat]68have pair := product.pair with naturalI, naturalJ69obtain⟨natural, k, naturalK, shape⟩:= matrixSecondIndex.selected with pair70obtain⟨first, second⟩:= orderedPair.injective with shape71rw←second72rfl7374theorem RealMatrix.entry (M : Set, i j : Nat)75requires matrix : RealMatrix(M)76showsReal(M[i, j])77proof78unfold RealMatrix at matrix79have iNatural : i ∈ ℕ bysimp [Nat]80have jNatural : j ∈ ℕ bysimp [Nat]81have pair := product.pair with iNatural, jNatural82exact FunctionBetween.apply_closed with matrix, pair8384defgraph matrixTranspose (M : Set) (p ∈ ℕ × ℕ) : ℝ :=85 M[matrixSecondIndex(p), matrixFirstIndex(p)]86requires matrix : RealMatrix(M)87proof88have first := matrixFirstIndex.selected with member89have second := matrixSecondIndex.selected with member90rcases first with⟨naturalFirst, j, naturalJ, shapeFirst⟩91rcases second with⟨naturalSecond, i, naturalI, shapeSecond⟩92have typedFirst := nat.omega.backward with naturalFirst93have typedSecond := nat.omega.backward with naturalSecond94exact RealMatrix.entry at95 M, matrixSecondIndex(p), matrixFirstIndex(p) with matrix9697theorem matrixTranspose.matrix (M : Set)98requires matrix : RealMatrix(M)99shows RealMatrix(matrixTranspose(M))100proof101unfold RealMatrix102exact matrixTranspose.function with matrix103104theorem matrixTranspose.entry (M : Set, i j : Nat)105requires matrix : RealMatrix(M)106shows matrixTranspose(M)[i, j] = M[j, i]107proof108have naturalI : i ∈ ℕ bysimp [Nat]109have naturalJ : j ∈ ℕ bysimp [Nat]110have pair := product.pair with naturalI, naturalJ111have value := matrixTranspose.value with matrix112rw [value, matrixFirstIndex.pair, matrixSecondIndex.pair]113rfl114115defgraph matrixAdd (A B : Set) (p ∈ ℕ × ℕ) : ℝ :=116 call2(realAdd, A[matrixFirstIndex(p), matrixSecondIndex(p)],117 B[matrixFirstIndex(p), matrixSecondIndex(p)])118requires matrixA : RealMatrix(A)119requires matrixB : RealMatrix(B)120proof121have first := matrixFirstIndex.selected with member122have second := matrixSecondIndex.selected with member123rcases first with⟨naturalFirst, j, naturalJ, shapeFirst⟩124rcases second with⟨naturalSecond, i, naturalI, shapeSecond⟩125have typedFirst := nat.omega.backward with naturalFirst126have typedSecond := nat.omega.backward with naturalSecond127haveleft:= RealMatrix.entry at A, matrixFirstIndex(p), matrixSecondIndex(p) with matrixA128haveright:= RealMatrix.entry at B, matrixFirstIndex(p), matrixSecondIndex(p) with matrixB129exact realAddValue.real withleft, right130131theorem matrixAdd.matrix (A B : Set)132requires matrixA : RealMatrix(A)133requires matrixB : RealMatrix(B)134shows RealMatrix(matrixAdd(A, B))135proof136unfold RealMatrix137exact matrixAdd.function with matrixA, matrixB138139theorem matrixAdd.entry (A B : Set, i j : Nat)140requires matrixA : RealMatrix(A)141requires matrixB : RealMatrix(B)142shows matrixAdd(A, B)[i, j] = (A[i, j]:R) + (B[i, j]:R)143proof144have naturalI : i ∈ ℕ bysimp [Nat]145have naturalJ : j ∈ ℕ bysimp [Nat]146have pair := product.pair with naturalI, naturalJ147have value := matrixAdd.value with matrixA, matrixB148rw [value, matrixFirstIndex.pair, matrixSecondIndex.pair]149rfl150151defgraph matrixScale (C : Real, M : Set) (p ∈ ℕ × ℕ) : ℝ :=152 realMul(C, M[matrixFirstIndex(p), matrixSecondIndex(p)])153requires matrix : RealMatrix(M)154proof155have first := matrixFirstIndex.selected with member156have second := matrixSecondIndex.selected with member157rcases first with⟨naturalFirst, j, naturalJ, shapeFirst⟩158rcases second with⟨naturalSecond, i, naturalI, shapeSecond⟩159have typedFirst := nat.omega.backward with naturalFirst160have typedSecond := nat.omega.backward with naturalSecond161have entry := RealMatrix.entry at M, matrixFirstIndex(p), matrixSecondIndex(p) with matrix162have scaled := realMulValue.real at C,163 M[matrixFirstIndex(p), matrixSecondIndex(p)] withassumption, entry164exact scaled165166theorem matrixScale.matrix (C : Real, M : Set)167requires matrix : RealMatrix(M)168shows RealMatrix(matrixScale(C, M))169proof170unfold RealMatrix171exact matrixScale.function with matrix172173theorem matrixScale.entry (C : Real, M : Set, i j : Nat)174requires matrix : RealMatrix(M)175shows matrixScale(C, M)[i, j] = C * (M[i, j]:R)176proof177have naturalI : i ∈ ℕ bysimp [Nat]178have naturalJ : j ∈ ℕ bysimp [Nat]179have pair := product.pair with naturalI, naturalJ180have value := matrixScale.value with matrix181rw [value, matrixFirstIndex.pair, matrixSecondIndex.pair]182rfl183184-- Equality of indices uniquely determines the diagonal coefficient in ZF.185defunique diagonalCoefficient (i j : Nat) (X ∈ ℝ) :=186 (i = j → X = (1:R)) ∧ (i ≠ j → X = (0:R))187proof188have alternatives : i = j ∨ i ≠ j bytauto189cases alternatives with equal | distinct190 . witness (1:R)191constructor192 . exact realOne.real193 . constructor194 . intro same195rfl196 . intro impossible197exfalso198exact impossible with equal199 . witness (0:R)200constructor201 . exact realZero.real202 . constructor203 . intro impossible204exfalso205exact distinct with impossible206 . intro different207rfl208209uniqueness210intros u uMember first v vMember second211have alternatives : i = j ∨¬(i = j) bytauto212cases alternatives with present | absent213 . have uValue : u = (1:R)214tauto215have vValue : v = (1:R) bytauto216cc217 . have uValue : u = (0:R)218tauto219have vValue : v = (0:R) bytauto220cc221222theorem diagonalCoefficient.same (i : Nat)223shows diagonalCoefficient(i, i) = (1:R)224proof225have selected := diagonalCoefficient.selected at i, i with*226rcases selected with⟨real, diagonal, offDiagonal⟩227haveself : i = i byrfl228exact diagonal withself229230theorem diagonalCoefficient.distinct (i j : Nat)231requires different : i ≠ j232shows diagonalCoefficient(i, j) = (0:R)233proof234have selected := diagonalCoefficient.selected at i, j with*235rcases selected with⟨real, diagonal, offDiagonal⟩236exact offDiagonal with different237238defgraph identityMatrix (n : Nat) (p ∈ ℕ × ℕ) : ℝ :=239 diagonalCoefficient(matrixFirstIndex(p), matrixSecondIndex(p))240proof241have first := matrixFirstIndex.selected with member242have second := matrixSecondIndex.selected with member243rcases first with⟨naturalFirst, j, naturalJ, shapeFirst⟩244rcases second with⟨naturalSecond, i, naturalI, shapeSecond⟩245have typedFirst := nat.omega.backward with naturalFirst246have typedSecond := nat.omega.backward with naturalSecond247obtain⟨real, diagonal, offDiagonal⟩:= diagonalCoefficient.selected with typedFirst, typedSecond248exact real249250theorem identityMatrix.matrix (n : Nat)251shows RealMatrix(identityMatrix(n))252proof253unfold RealMatrix254exact identityMatrix.function withassumption255256theorem identityMatrix.entry (n i j : Nat)257shows identityMatrix(n)[i, j] = diagonalCoefficient(i, j)258proof259have naturalI : i ∈ ℕ bysimp [Nat]260have naturalJ : j ∈ ℕ bysimp [Nat]261have pair := product.pair with naturalI, naturalJ262have value := identityMatrix.value at n, (i, j)263rw [value, matrixFirstIndex.pair, matrixSecondIndex.pair]264rfl265266theorem identityMatrix.diagonal (n i : Nat)267shows identityMatrix(n)[i, i] = (1:R)268proof269rw identityMatrix.entry270exact diagonalCoefficient.same withassumption271272theorem identityMatrix.off_diagonal (n i j : Nat)273requires different : i ≠ j274shows identityMatrix(n)[i, j] = (0:R)275proof276rw identityMatrix.entry277exact diagonalCoefficient.distinct with*278279theorem matrixAdd.commutative_entry (A B : Set, i j : Nat)280requires matrixA : RealMatrix(A)281requires matrixB : RealMatrix(B)282shows matrixAdd(A, B)[i, j] = matrixAdd(B, A)[i, j]283proof284have typedA := RealMatrix.entry at A, i, j with matrixA285have typedB := RealMatrix.entry at B, i, j with matrixB286rw [matrixAdd.entry, matrixAdd.entry]287ring288289theorem matrixAdd.associative_entry (A B C : Set, i j : Nat)290requires matrixA : RealMatrix(A)291requires matrixB : RealMatrix(B)292requires matrixC : RealMatrix(C)293shows matrixAdd(matrixAdd(A, B), C)[i, j] =294 matrixAdd(A, matrixAdd(B, C))[i, j]295proof296have typedAB := matrixAdd.matrix with matrixA, matrixB297have typedBC := matrixAdd.matrix with matrixB, matrixC298have typedA := RealMatrix.entry at A, i, j with matrixA299have typedB := RealMatrix.entry at B, i, j with matrixB300have typedC := RealMatrix.entry at C, i, j with matrixC301rw [matrixAdd.entry, matrixAdd.entry, matrixAdd.entry, matrixAdd.entry]302ring303304theorem matrixScale.add_entry (A B : Set, C : Real, i j : Nat)305requires matrixA : RealMatrix(A)306requires matrixB : RealMatrix(B)307shows matrixScale(C, matrixAdd(A, B))[i, j] =308 matrixAdd(matrixScale(C, A), matrixScale(C, B))[i, j]309proof310have combined := matrixAdd.matrix with matrixA, matrixB311have scaledA := matrixScale.matrix with matrixA312have scaledB := matrixScale.matrix with matrixB313have typedA := RealMatrix.entry at A, i, j with matrixA314have typedB := RealMatrix.entry at B, i, j with matrixB315rw [matrixScale.entry, matrixAdd.entry, matrixAdd.entry, matrixScale.entry, matrixScale.entry]316ring317318theorem matrixTranspose.add_entry (A B : Set, i j : Nat)319requires matrixA : RealMatrix(A)320requires matrixB : RealMatrix(B)321shows matrixTranspose(matrixAdd(A, B))[i, j] =322 matrixAdd(matrixTranspose(A), matrixTranspose(B))[i, j]323proof324have combined := matrixAdd.matrix with matrixA, matrixB325have transposedA := matrixTranspose.matrix with matrixA326have transposedB := matrixTranspose.matrix with matrixB327rw [matrixTranspose.entry, matrixAdd.entry, matrixAdd.entry, matrixTranspose.entry, matrixTranspose.entry]328rfl329330theorem matrixTranspose.scale_entry (C : Real, M : Set, i j : Nat)331requires matrix : RealMatrix(M)332shows matrixTranspose(matrixScale(C, M))[i, j] =333 matrixScale(C, matrixTranspose(M))[i, j]334proof335have scaled := matrixScale.matrix with matrix336have transposed := matrixTranspose.matrix with matrix337rw [matrixTranspose.entry, matrixScale.entry, matrixScale.entry, matrixTranspose.entry]338rfl339340defgraph matrixRow (M : Set, i : Nat) (j ∈ ℕ) : ℝ := M[i, j]341requires matrix : RealMatrix(M)342proof343have typedJ := nat.omega.backward with member344exact RealMatrix.entry at M, i, j with matrix345346theorem matrixRow.sequence (M : Set, i : Nat)347requires matrix : RealMatrix(M)348shows RealSequence(matrixRow(M, i))349proof350unfold RealSequence351exact matrixRow.function with matrix352353defgraph matrixColumn (M : Set, j : Nat) (i ∈ ℕ) : ℝ := M[i, j]354requires matrix : RealMatrix(M)355proof356have typedI := nat.omega.backward with member357exact RealMatrix.entry at M, i, j with matrix358359theorem matrixColumn.sequence (M : Set, j : Nat)360requires matrix : RealMatrix(M)361shows RealSequence(matrixColumn(M, j))362proof363unfold RealSequence364exact matrixColumn.function with matrix365366theorem matrixTranspose.involutive_entry (M : Set, i j : Nat)367requires matrix : RealMatrix(M)368shows matrixTranspose(matrixTranspose(M))[i, j] = M[i, j]369proof370have transposed := matrixTranspose.matrix with matrix371have outer := matrixTranspose.entry at matrixTranspose(M), i, j with transposed372have inner := matrixTranspose.entry at M, j, i with matrix373 rwa outer374375theorem matrixTranspose.row_column (M : Set, i j : Nat)376requires matrix : RealMatrix(M)377shows matrixRow(matrixTranspose(M), i)[j] = matrixColumn(M, i)[j]378proof379have transposed := matrixTranspose.matrix with matrix380have entry := matrixTranspose.entry at M, i, j with matrix381 rwa [matrixRow.value, matrixColumn.value]382383defgraph matrixProduct (A B : Set, n : Nat) (p ∈ ℕ × ℕ) : ℝ :=384 dotProduct(matrixRow(A, matrixFirstIndex(p)),385 matrixColumn(B, matrixSecondIndex(p)), n)386requires matrixA : RealMatrix(A)387requires matrixB : RealMatrix(B)388proof389have first := matrixFirstIndex.selected with member390have second := matrixSecondIndex.selected with member391rcases first with⟨naturalFirst, j, naturalJ, shapeFirst⟩392rcases second with⟨naturalSecond, i, naturalI, shapeSecond⟩393have typedFirst := nat.omega.backward with naturalFirst394have typedSecond := nat.omega.backward with naturalSecond395have row := matrixRow.sequence at A, matrixFirstIndex(p) with matrixA396have column := matrixColumn.sequence at B, matrixSecondIndex(p) with matrixB397have value := dotProduct.real at matrixRow(A, matrixFirstIndex(p)),398 matrixColumn(B, matrixSecondIndex(p)), n with row, column399exact value400401theorem matrixProduct.matrix (A B : Set, n : Nat)402requires matrixA : RealMatrix(A)403requires matrixB : RealMatrix(B)404shows RealMatrix(matrixProduct(A, B, n))405proof406unfold RealMatrix407exact matrixProduct.function with matrixA, matrixB408409theorem matrixProduct.entry (A B : Set, n i j : Nat)410requires matrixA : RealMatrix(A)411requires matrixB : RealMatrix(B)412shows matrixProduct(A, B, n)[i, j] =413 dotProduct(matrixRow(A, i), matrixColumn(B, j), n)414proof415have naturalI : i ∈ ℕ bysimp [Nat]416have naturalJ : j ∈ ℕ bysimp [Nat]417have pair := product.pair with naturalI, naturalJ418have value := matrixProduct.value at A, B, n, (i, j) with matrixA, matrixB419rw [value, matrixFirstIndex.pair, matrixSecondIndex.pair]420rfl421422theorem matrixProduct.zero (A B : Set, i j : Nat)423requires matrixA : RealMatrix(A)424requires matrixB : RealMatrix(B)425shows matrixProduct(A, B, 0)[i, j] = (0:R)426proof427have value := matrixProduct.entry at A, B, 0, i, j with matrixA, matrixB428rw value429exact dotProduct.zero430431theorem matrixProduct.succ (A B : Set, n i j : Nat)432requires matrixA : RealMatrix(A)433requires matrixB : RealMatrix(B)434shows matrixProduct(A, B, succ(n))[i, j] =435 (matrixProduct(A, B, n)[i, j]:R) + (A[i, n]:R) * (B[n, j]:R)436proof437have row := matrixRow.sequence at A, i with matrixA438have column := matrixColumn.sequence at B, j with matrixB439have step := dotProduct.succ at matrixRow(A, i), matrixColumn(B, j), n with row, column440rw [matrixRow.value, matrixColumn.value] at step441have next := matrixProduct.entry at A, B, succ(n), i, j with matrixA, matrixB442have previous := matrixProduct.entry at A, B, n, i, j with matrixA, matrixB443 rwa [next, previous]444445theorem matrixProduct.transpose_entry (A B : Set, n i j : Nat)446requires matrixA : RealMatrix(A)447requires matrixB : RealMatrix(B)448shows matrixTranspose(matrixProduct(A, B, n))[i, j] =449 matrixProduct(matrixTranspose(B), matrixTranspose(A), n)[i, j]450proof451induction n452| zero =>453have transposedA := matrixTranspose.matrix with matrixA454have transposedB := matrixTranspose.matrix with matrixB455have product := matrixProduct.matrix at A, B, 0with matrixA, matrixB456have flip := matrixTranspose.entry at matrixProduct(A, B, 0), i, j with product457haveleft:= matrixProduct.zero at A, B, j, i with matrixA, matrixB458haveright:= matrixProduct.zero at matrixTranspose(B), matrixTranspose(A), i, j with459 transposedB, transposedA460rw [flip, left, right]461rfl462| succ(k) using ih =>463have transposedA := matrixTranspose.matrix with matrixA464have transposedB := matrixTranspose.matrix with matrixB465have product := matrixProduct.matrix at A, B, succ(k) with matrixA, matrixB466have flip := matrixTranspose.entry at matrixProduct(A, B, succ(k)), i, j with product467haveleft:= matrixProduct.succ at A, B, k, j, i with matrixA, matrixB468haveright:= matrixProduct.succ at469 matrixTranspose(B), matrixTranspose(A), k, i, j with transposedB, transposedA470have oldProduct := matrixProduct.matrix at A, B, k with matrixA, matrixB471have oldFlip := matrixTranspose.entry at matrixProduct(A, B, k), i, j with oldProduct472have Bentry := matrixTranspose.entry at B, i, k with matrixB473have Aentry := matrixTranspose.entry at A, k, j with matrixA474have realA := RealMatrix.entry at A, j, k with matrixA475have realB := RealMatrix.entry at B, k, i with matrixB476have realOld := RealMatrix.entry at matrixProduct(A, B, k), j, i with oldProduct477have reverseProduct := matrixProduct.matrix at matrixTranspose(B),478 matrixTranspose(A), k with transposedB, transposedA479have realReverse := RealMatrix.entry at480 matrixProduct(matrixTranspose(B), matrixTranspose(A), k), i, j with reverseProduct481rw [flip, left, right, Bentry, Aentry, ←oldFlip, ih]482ring483484theorem matrixProduct.add_right_entry (A B C : Set, i j n : Nat)485requires matrixA : RealMatrix(A)486requires matrixB : RealMatrix(B)487requires matrixC : RealMatrix(C)488shows matrixProduct(A, matrixAdd(B, C), n)[i, j] =489 matrixAdd(matrixProduct(A, B, n), matrixProduct(A, C, n))[i, j]490proof491induction n492| zero =>493have combined := matrixAdd.matrix with matrixB, matrixC494have productB := matrixProduct.matrix at A, B, 0with matrixA, matrixB495have productC := matrixProduct.matrix at A, C, 0with matrixA, matrixC496haveleft:= matrixProduct.zero at A, matrixAdd(B, C), i, j with matrixA, combined497have rightB := matrixProduct.zero at A, B, i, j with matrixA, matrixB498have rightC := matrixProduct.zero at A, C, i, j with matrixA, matrixC499rw [left, matrixAdd.entry, rightB, rightC]500ring501| succ(k) using ih =>502have combined := matrixAdd.matrix with matrixB, matrixC503have nextB := matrixProduct.matrix at A, B, succ(k) with matrixA, matrixB504have nextC := matrixProduct.matrix at A, C, succ(k) with matrixA, matrixC505have oldB := matrixProduct.matrix at A, B, k with matrixA, matrixB506have oldC := matrixProduct.matrix at A, C, k with matrixA, matrixC507have oldCombined := matrixProduct.matrix at A, matrixAdd(B, C), k with matrixA, combined508haveleft:= matrixProduct.succ at A, matrixAdd(B, C), k, i, j with matrixA, combined509have rightB := matrixProduct.succ at A, B, k, i, j with matrixA, matrixB510have rightC := matrixProduct.succ at A, C, k, i, j with matrixA, matrixC511have entry := matrixAdd.entry at B, C, k, j with matrixB, matrixC512have previous := matrixAdd.entry at matrixProduct(A, B, k),513 matrixProduct(A, C, k), i, j with oldB, oldC514have realA := RealMatrix.entry at A, i, k with matrixA515have realB := RealMatrix.entry at B, k, j with matrixB516have realC := RealMatrix.entry at C, k, j with matrixC517have realOldB := RealMatrix.entry at matrixProduct(A, B, k), i, j with oldB518have realOldC := RealMatrix.entry at matrixProduct(A, C, k), i, j with oldC519have realOldCombined := RealMatrix.entry at matrixProduct(A, matrixAdd(B, C), k),520 i, j with oldCombined521rw [left, entry, matrixAdd.entry, rightB, rightC]522rw previous at ih523rw ih524ring525526theorem matrixProduct.add_left_entry (A B C : Set, i j n : Nat)527requires matrixA : RealMatrix(A)528requires matrixB : RealMatrix(B)529requires matrixC : RealMatrix(C)530shows matrixProduct(matrixAdd(A, B), C, n)[i, j] =531 matrixAdd(matrixProduct(A, C, n), matrixProduct(B, C, n))[i, j]532proof533induction n534| zero =>535have combined := matrixAdd.matrix with matrixA, matrixB536have productA := matrixProduct.matrix at A, C, 0with matrixA, matrixC537have productB := matrixProduct.matrix at B, C, 0with matrixB, matrixC538haveleft:= matrixProduct.zero at matrixAdd(A, B), C, i, j with combined, matrixC539have rightA := matrixProduct.zero at A, C, i, j with matrixA, matrixC540have rightB := matrixProduct.zero at B, C, i, j with matrixB, matrixC541rw [left, matrixAdd.entry, rightA, rightB]542ring543| succ(k) using ih =>544have combined := matrixAdd.matrix with matrixA, matrixB545have nextA := matrixProduct.matrix at A, C, succ(k) with matrixA, matrixC546have nextB := matrixProduct.matrix at B, C, succ(k) with matrixB, matrixC547have oldA := matrixProduct.matrix at A, C, k with matrixA, matrixC548have oldB := matrixProduct.matrix at B, C, k with matrixB, matrixC549haveleft:= matrixProduct.succ at matrixAdd(A, B), C, k, i, j with combined, matrixC550have rightA := matrixProduct.succ at A, C, k, i, j with matrixA, matrixC551have rightB := matrixProduct.succ at B, C, k, i, j with matrixB, matrixC552have entry := matrixAdd.entry at A, B, i, k with matrixA, matrixB553have previous := matrixAdd.entry at matrixProduct(A, C, k),554 matrixProduct(B, C, k), i, j with oldA, oldB555have realA := RealMatrix.entry at A, i, k with matrixA556have realB := RealMatrix.entry at B, i, k with matrixB557have realC := RealMatrix.entry at C, k, j with matrixC558have realOldA := RealMatrix.entry at matrixProduct(A, C, k), i, j with oldA559have realOldB := RealMatrix.entry at matrixProduct(B, C, k), i, j with oldB560rw [left, entry, matrixAdd.entry, rightA, rightB]561rw previous at ih562rw ih563ring564565-- A matrix with n columns acts on a vector by the dot product with each row.566defgraph matrixVectorProduct (M u : Set, n : Nat) (i ∈ ℕ) : ℝ :=567 dotProduct(matrixRow(M, i), u, n)568requires matrix : RealMatrix(M)569requires vector : RealSequence(u)570proof571have typedI := nat.omega.backward with member572have row := matrixRow.sequence at M, i with matrix573exact dotProduct.real at matrixRow(M, i), u, n with row, vector574575theorem matrixVectorProduct.sequence (M u : Set, n : Nat)576requires matrix : RealMatrix(M)577requires vector : RealSequence(u)578shows RealSequence(matrixVectorProduct(M, u, n))579proof580unfold RealSequence581exact matrixVectorProduct.function with matrix, vector582583theorem matrixProduct.column_action (A B : Set, n i j : Nat)584requires matrixA : RealMatrix(A)585requires matrixB : RealMatrix(B)586shows matrixProduct(A, B, n)[i, j] =587 matrixVectorProduct(A, matrixColumn(B, j), n)[i]588proof589have column := matrixColumn.sequence at B, j with matrixB590have product := matrixProduct.entry at A, B, n, i, j with matrixA, matrixB591rw [product, matrixVectorProduct.value]592rfl593594theorem matrixVectorProduct.zero (M u : Set, i : Nat)595requires matrix : RealMatrix(M)596requires vector : RealSequence(u)597shows matrixVectorProduct(M, u, 0)[i] = (0:R)598proof599rw matrixVectorProduct.value600exact dotProduct.zero601602theorem matrixVectorProduct.succ (M u : Set, n i : Nat)603requires matrix : RealMatrix(M)604requires vector : RealSequence(u)605shows matrixVectorProduct(M, u, succ(n))[i] =606 (matrixVectorProduct(M, u, n)[i]:R) + (M[i, n]:R) * (u[n]:R)607proof608have row := matrixRow.sequence at M, i with matrix609have step := dotProduct.succ at matrixRow(M, i), u, n with row, vector610rw matrixRow.value at step611 rwa [matrixVectorProduct.value, matrixVectorProduct.value]612613theorem matrixVectorProduct.add (M u v : Set, n i : Nat)614requires matrix : RealMatrix(M)615requires vectorU : RealSequence(u)616requires vectorV : RealSequence(v)617shows matrixVectorProduct(M, addSequence(u, v), n)[i] =618 (matrixVectorProduct(M, u, n)[i]:R) +619 (matrixVectorProduct(M, v, n)[i]:R)620proof621have row := matrixRow.sequence at M, i with matrix622have combined := addSequence.sequence with vectorU, vectorV623have distributive := dotProduct.add_right at matrixRow(M, i), u, v, n with624 row, vectorU, vectorV625 rwa [matrixVectorProduct.value, matrixVectorProduct.value, matrixVectorProduct.value]626627theorem matrixVectorProduct.add_matrix (A B u : Set, i n : Nat)628requires matrixA : RealMatrix(A)629requires matrixB : RealMatrix(B)630requires vector : RealSequence(u)631shows matrixVectorProduct(matrixAdd(A, B), u, n)[i] =632 (matrixVectorProduct(A, u, n)[i]:R) + (matrixVectorProduct(B, u, n)[i]:R)633proof634induction n635| zero =>636have combined := matrixAdd.matrix with matrixA, matrixB637haveleft:= matrixVectorProduct.zero with combined, vector638have rightA := matrixVectorProduct.zero with matrixA, vector639have rightB := matrixVectorProduct.zero with matrixB, vector640rw [left, rightA, rightB]641ring642| succ(k) using ih =>643have combined := matrixAdd.matrix with matrixA, matrixB644haveleft:= matrixVectorProduct.succ at matrixAdd(A, B), u, k, i with combined, vector645have rightA := matrixVectorProduct.succ at A, u, k, i with matrixA, vector646have rightB := matrixVectorProduct.succ at B, u, k, i with matrixB, vector647have entry := matrixAdd.entry at A, B, i, k with matrixA, matrixB648have typedA := RealMatrix.entry at A, i, k with matrixA649have typedB := RealMatrix.entry at B, i, k with matrixB650have typedU := RealSequence.value at u, k with vector651have seqA := matrixVectorProduct.sequence at A, u, k with matrixA, vector652have seqB := matrixVectorProduct.sequence at B, u, k with matrixB, vector653have oldA := RealSequence.value at matrixVectorProduct(A, u, k), i with seqA654have oldB := RealSequence.value at matrixVectorProduct(B, u, k), i with seqB655rw [left, rightA, rightB, entry, ih]656ring657658theorem matrixVectorProduct.scale_matrix (M u : Set, C : Real, i n : Nat)659requires matrix : RealMatrix(M)660requires vector : RealSequence(u)661shows matrixVectorProduct(matrixScale(C, M), u, n)[i] =662 C * (matrixVectorProduct(M, u, n)[i]:R)663proof664induction n665| zero =>666have scaled := matrixScale.matrix with matrix667haveleft:= matrixVectorProduct.zero with scaled, vector668haveright:= matrixVectorProduct.zero with matrix, vector669rw [left, right]670ring671| succ(k) using ih =>672have scaled := matrixScale.matrix with matrix673haveleft:= matrixVectorProduct.succ at matrixScale(C, M), u, k, i with scaled, vector674haveright:= matrixVectorProduct.succ at M, u, k, i with matrix, vector675have entry := matrixScale.entry at C, M, i, k with matrix676have typedM := RealMatrix.entry at M, i, k with matrix677have typedU := RealSequence.value at u, k with vector678have sequence := matrixVectorProduct.sequence at M, u, k with matrix, vector679have old := RealSequence.value at matrixVectorProduct(M, u, k), i with sequence680rw [left, right, entry, ih]681ring682683theorem matrixVectorProduct.scale (M u : Set, C : Real, n i : Nat)684requires matrix : RealMatrix(M)685requires vector : RealSequence(u)686shows matrixVectorProduct(M, mulSequence(constantSequence(C), u), n)[i] =687 C * (matrixVectorProduct(M, u, n)[i]:R)688proof689have row := matrixRow.sequence at M, i with matrix690have constants := constantSequence.sequence at C691have scaled := mulSequence.sequence with constants, vector692have distributive := dotProduct.scale_right at matrixRow(M, i), u, C, n with row, vector693 rwa [matrixVectorProduct.value, matrixVectorProduct.value]694695theorem matrixVectorProduct.eq_prefix (M u v : Set, n i : Nat)696requires matrix : RealMatrix(M)697requires vectorU : RealSequence(u)698requires vectorV : RealSequence(v)699requires equal : ∀ k ∈ ℕ, k < n → u[k] = v[k]700shows matrixVectorProduct(M, u, n)[i] = matrixVectorProduct(M, v, n)[i]701proof702have row := matrixRow.sequence at M, i with matrix703have sameRow : ∀ k ∈ ℕ, k < n →704 matrixRow(M, i)[k] = matrixRow(M, i)[k]705intros k naturalK before706rfl707haveprefix:= dotProduct.eq_prefix with row, vectorU, row, vectorV, sameRow, equal708 rwa [matrixVectorProduct.value, matrixVectorProduct.value]709710theorem matrixVectorProduct.equal_rows (M N u : Set, n i : Nat)711requires matrixM : RealMatrix(M)712requires matrixN : RealMatrix(N)713requires vector : RealSequence(u)714requires equal : ∀ j ∈ ℕ, j < n → M[i, j] = N[i, j]715shows matrixVectorProduct(M, u, n)[i] = matrixVectorProduct(N, u, n)[i]716proof717have rowM := matrixRow.sequence at M, i with matrixM718have rowN := matrixRow.sequence at N, i with matrixN719have sameRow : ∀ k ∈ ℕ, k < n →720 matrixRow(M, i)[k] = matrixRow(N, i)[k]721intros k naturalK before722have entry := equal with k, naturalK, before723 rwa [matrixRow.value, matrixRow.value]724have sameVector : ∀ k ∈ ℕ, k < n → u[k] = u[k]725intros k naturalK before726rfl727haveprefix:= dotProduct.eq_prefix with rowM, vector, rowN, vector, sameRow, sameVector728 rwa [matrixVectorProduct.value, matrixVectorProduct.value]729730-- Before its diagonal coordinate, an identity row contributes only zeros.731theorem identityMatrix.action_before_aux (m : Nat)732shows∀ n ∈ ℕ, ∀ i ∈ ℕ, ∀ u, RealSequence(u) → m ≤ i →733 matrixVectorProduct(identityMatrix(n), u, m)[i] = (0:R)734proof735induction m736| zero =>737intros n naturalN i naturalI u sequence outside738have typedN := nat.omega.backward with naturalN739have typedI := nat.omega.backward with naturalI740have matrix := identityMatrix.matrix with typedN741exact matrixVectorProduct.zero at identityMatrix(n), u, i with matrix, sequence742| succ(k) using ih =>743intros n naturalN i naturalI u sequence outside744have typedN := nat.omega.backward with naturalN745have typedI := nat.omega.backward with naturalI746have smaller : k < i byexact outside747have before := Less.implies_LessEqual at k, i with typedI, smaller748have different : i ≠ k749intro equal750rw equal at smaller751have impossible := Less.irreflexive at k752exact impossible with smaller753have matrix := identityMatrix.matrix with typedN754haveprefix:= ih with n, naturalN, i, naturalI, u, sequence, before755have zeroEntry := identityMatrix.off_diagonal with typedN, typedI, different756have term := RealSequence.value at u, k with sequence757have products := matrixVectorProduct.sequence at identityMatrix(n), u, k with matrix, sequence758have old := RealSequence.value at matrixVectorProduct(identityMatrix(n), u, k), i with products759rw [matrixVectorProduct.succ, prefix, zeroEntry]760ring761762theorem identityMatrix.action_before (n m i : Nat, u : Set)763requires vector : RealSequence(u)764requires outside : m ≤ i765shows matrixVectorProduct(identityMatrix(n), u, m)[i] = (0:R)766proof767exact identityMatrix.action_before_aux at m with768 n, nat.omega.forward at n withassumption,769 i, nat.omega.forward at i withassumption, u, vector, outside770771theorem identityMatrix.action_at_aux (m : Nat)772shows∀ n ∈ ℕ, ∀ i ∈ ℕ, ∀ u, RealSequence(u) → i < m →773 matrixVectorProduct(identityMatrix(n), u, m)[i] = u[i]774proof775induction m776| zero =>777intros n naturalN i naturalI u sequence before778have typedI := nat.omega.backward with naturalI779have weak := Grace.Core.Nat.Order.LessEqual.zero with typedI780have typedZero : Nat(0) bytypecheck781have cycle := Less.transitive_LessEqual with typedI, typedZero, typedI, before, weak782have impossible := Less.irreflexive with typedI783exfalso784exact impossible with cycle785| succ(k) using ih =>786intros n naturalN i naturalI u sequence before787have typedN := nat.omega.backward with naturalN788have typedI := nat.omega.backward with naturalI789have matrix := identityMatrix.matrix with typedN790have term := RealSequence.value at u, k with sequence791have products := matrixVectorProduct.sequence at identityMatrix(n), u, k with matrix, sequence792have old := RealSequence.value at matrixVectorProduct(identityMatrix(n), u, k), i with products793have member := membership.of_Less at i, succ(k) with794 typedI, Naturals.constructor.succ at k withassumption, before795have alternatives := membership.successor_forward{n := k} with member796cases alternatives with earlier | equal797 . have smaller := Less.of_membership at i, k with typedI, earlier798haveprefix:= ih with n, naturalN, i, naturalI, u, sequence, smaller799have different : i ≠ k800intro same801rw same at smaller802have impossible := Less.irreflexive at k803exact impossible with smaller804have zeroEntry := identityMatrix.off_diagonal with typedN, typedI, different805rw [matrixVectorProduct.succ, prefix, zeroEntry]806ring807 . rw equal808have reflexive := LessEqual.reflexive at k809haveprefix:= identityMatrix.action_before at n, k, k, u with810 sequence, reflexive811have diagonal := identityMatrix.diagonal at n, k with typedN812rw [matrixVectorProduct.succ, prefix, diagonal]813ring814815theorem identityMatrix.action (n i : Nat, u : Set)816requires vector : RealSequence(u)817requires inRange : i < n818shows matrixVectorProduct(identityMatrix(n), u, n)[i] = u[i]819proof820exact identityMatrix.action_at_aux at n with821 n, nat.omega.forward at n withassumption,822 i, nat.omega.forward at i withassumption, u, vector, inRange823824theorem matrixProduct.identity_left (A : Set, n i j : Nat)825requires matrix : RealMatrix(A)826requires inRange : i < n827shows matrixProduct(identityMatrix(n), A, n)[i, j] = A[i, j]828proof829have identity := identityMatrix.matrix at n830have column := matrixColumn.sequence at A, j with matrix831have action := identityMatrix.action with column, inRange832have product := matrixProduct.column_action at identityMatrix(n), A, n, i, j with833 identity, matrix834rw [product, action, matrixColumn.value]835rfl836837theorem diagonalCoefficient.not_equal_symmetric (i j : Nat)838requires different : i ≠ j839shows j ≠ i840proof841simp842843theorem diagonalCoefficient.symmetric (i j : Nat)844shows diagonalCoefficient(i, j) = diagonalCoefficient(j, i)845proof846have alternatives : i = j ∨ i ≠ j bytauto847cases alternatives with equal | different848 . rw equal849rfl850 . have reverse := diagonalCoefficient.not_equal_symmetric with different851have first := diagonalCoefficient.distinct with different852have second := diagonalCoefficient.distinct with reverse853rw [first, second]854rfl855856theorem identityMatrix.symmetric_entry (n i j : Nat)857shows identityMatrix(n)[i, j] = identityMatrix(n)[j, i]858proof859rw [identityMatrix.entry, identityMatrix.entry]860exact diagonalCoefficient.symmetric with*861862theorem matrixProduct.identity_right (A : Set, n i j : Nat)863requires matrix : RealMatrix(A)864requires inRange : j < n865shows matrixProduct(A, identityMatrix(n), n)[i, j] = A[i, j]866proof867have identity := identityMatrix.matrix at n868have rowA := matrixRow.sequence at A, i with matrix869have rowI := matrixRow.sequence at identityMatrix(n), j with identity870have colI := matrixColumn.sequence at identityMatrix(n), j with identity871have equal : ∀ k ∈ ℕ, k < n →872 matrixColumn(identityMatrix(n), j)[k] = matrixRow(identityMatrix(n), j)[k]873intros k naturalK before874have typedK := nat.omega.backward with naturalK875have symmetric := identityMatrix.symmetric_entry at n, k, j with876assumption, typedK, assumption877 rwa [matrixColumn.value, matrixRow.value]878have sameRow : ∀ k ∈ ℕ, k < n →879 matrixRow(A, i)[k] = matrixRow(A, i)[k]880intros k naturalK before881rfl882have equalDot := dotProduct.eq_prefix with colI, rowA, rowI, rowA, equal, sameRow883have swap := dotProduct.symmetric at matrixRow(A, i),884 matrixColumn(identityMatrix(n), j), n with rowA, colI885have product := matrixProduct.entry at A, identityMatrix(n), n, i, j with matrix, identity886have action := identityMatrix.action with rowA, inRange887rw [product, swap, equalDot, ←matrixVectorProduct.value, action, matrixRow.value]888rfl889890-- The two orders for summing a finite rectangle of a total matrix.891defgraph matrixRowTotals (M : Set, m : Nat) (i ∈ ℕ) : ℝ :=892 realPartialSum(matrixRow(M, i), m)893requires matrix : RealMatrix(M)894proof895have typedI := nat.omega.backward with member896have row := matrixRow.sequence at M, i with matrix897exact realPartialSum.real at matrixRow(M, i), m with row898899theorem matrixRowTotals.sequence (M : Set, m : Nat)900requires matrix : RealMatrix(M)901shows RealSequence(matrixRowTotals(M, m))902proof903unfold RealSequence904exact matrixRowTotals.function with matrix905906defgraph matrixColumnTotals (M : Set, n : Nat) (j ∈ ℕ) : ℝ :=907 realPartialSum(matrixColumn(M, j), n)908requires matrix : RealMatrix(M)909proof910have typedJ := nat.omega.backward with member911have column := matrixColumn.sequence at M, j with matrix912exact realPartialSum.real at matrixColumn(M, j), n with column913914theorem matrixColumnTotals.sequence (M : Set, n : Nat)915requires matrix : RealMatrix(M)916shows RealSequence(matrixColumnTotals(M, n))917proof918unfold RealSequence919exact matrixColumnTotals.function with matrix920921theorem matrixColumnTotals.succ (M : Set, n j : Nat)922requires matrix : RealMatrix(M)923shows matrixColumnTotals(M, succ(n))[j] =924 (matrixColumnTotals(M, n)[j]:R) + (M[n, j]:R)925proof926have column := matrixColumn.sequence at M, j with matrix927have next := matrixColumnTotals.value at M, succ(n), j with matrix928have previous := matrixColumnTotals.value at M, n, j with matrix929have entry := matrixColumn.value at M, j, n with matrix930rw [next, previous, realPartialSum.succ, entry]931unfold realAddValue932unfold call2933rfl934935theorem matrixColumnTotals.empty_sum (M : Set, m : Nat)936requires matrix : RealMatrix(M)937shows realPartialSum(matrixColumnTotals(M, 0), m) = (0:R)938proof939induction m940| zero =>941rw realPartialSum.zero942rfl943| succ(k) using ih =>944have value := matrixColumnTotals.value at M, 0, k with matrix945have zero := realPartialSum.zero at matrixColumn(M, k)946have sequence := matrixColumnTotals.sequence with matrix947have term := RealSequence.value with sequence948rw [realPartialSum.succ, ih, value, zero]949have unit := realAddValue.zero_right with realZero.real950unfold realAddValue951unfold call2 at unit952exact unit953954theorem matrixTotals.interchange_aux (n : Nat)955shows∀ M, RealMatrix(M) →∀ m ∈ ℕ,956 realPartialSum(matrixRowTotals(M, m), n) =957 realPartialSum(matrixColumnTotals(M, n), m)958proof959induction n960| zero =>961intros M matrix m naturalM962have typedM := nat.omega.backward with naturalM963rw realPartialSum.zero964have empty := matrixColumnTotals.empty_sum with matrix965rw empty966rfl967| succ(k) using ih =>968intros M matrix m naturalM969have typedM := nat.omega.backward with naturalM970have row := matrixRow.sequence at M, k with matrix971have earlier := matrixColumnTotals.sequence at M, k with matrix972have later := matrixColumnTotals.sequence at M, succ(k) with matrix973have combined := addSequence.sequence with earlier, row974have equal : ∀ j ∈ ℕ, j < m →975 matrixColumnTotals(M, succ(k))[j] =976 addSequence(matrixColumnTotals(M, k), matrixRow(M, k))[j]977intros j naturalJ before978have typedJ := nat.omega.backward with naturalJ979have step := matrixColumnTotals.succ at M, k, j with matrix980haveleft:= RealSequence.value at matrixColumnTotals(M, k), j with earlier981haveright:= RealSequence.value at matrixRow(M, k), j with row982have value := addSequence.value with earlier, row, left, right983have entry := matrixRow.value at M, k, j with matrix984rw [step, value, entry]985rfl986haveprefix:= realPartialSum.eq_prefix with later, combined, equal987have sumAdd := realPartialSum.add at matrixColumnTotals(M, k),988 matrixRow(M, k), m with earlier, row989have inductionStep := ih with M, matrix, m, naturalM990have rowTotal := matrixRowTotals.value at M, m, k with matrix991rw [realPartialSum.succ, rowTotal, inductionStep, prefix, sumAdd]992unfold realAddValue993unfold call2994rfl995996theorem matrixTotals.interchange (M : Set, n m : Nat)997requires matrix : RealMatrix(M)998shows realPartialSum(matrixRowTotals(M, m), n) =999 realPartialSum(matrixColumnTotals(M, n), m)1000proof1001exact matrixTotals.interchange_aux at n with M, matrix,1002 m, nat.omega.forward at m withassumption1003