1-- Bundled matrix rings: the ring value matrixRing(R, n) of the n × n2-- matrices over a bundled commutative ring R, its ring instance, the3-- entries of sums and products, and the determinant and adjugate of a4-- square matrix read off the ring; everything here is ZF5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Algebra.Ring.MatrixRing11import DeterminantIdentity12import Basic1314-- The n × n matrices over R are the functions on the square of indices.15def squareMatrices (R n : Set) : Set:= functionSpace(n × n, Ring.carrier(R))1617theorem squareMatrices.membership (R n M : Set)18shows M ∈ squareMatrices(R, n) ↔ RingMatrix(n, Ring.carrier(R), M)19proof20simp [squareMatrices, RingMatrix, functionSpace.mem_iff]2122theorem squareMatrices.function (R n M : Set)23requires matrix : M ∈ squareMatrices(R, n)24shows M : n × n → Ring.carrier(R)25proof26have shape := squareMatrices.membership.forward with matrix27unfold RingMatrix at shape28exact shape2930theorem squareMatrices.of_function (R n M : Set)31requires function : M : n × n → Ring.carrier(R)32shows M ∈ squareMatrices(R, n)33proof34have shape : RingMatrix(n, Ring.carrier(R), M) byexact function35exact squareMatrices.membership.backward with shape3637-- The entrywise sum of two matrices.38defgraph matrixSum (R n M N : Set) (p ∈ n × n) : Ring.carrier(R) := M(p) + N(p)39requiresring : Ring(R)40requires matrixM : M ∈ squareMatrices(R, n)41requires matrixN : N∈ squareMatrices(R, n)42proof43have functionM := squareMatrices.function with matrixM44have functionN := squareMatrices.function with matrixN45haveleft:= FunctionBetween.apply_closed with functionM, member46haveright:= FunctionBetween.apply_closed with functionN, member47exact Ring.add_mem with*4849theorem matrixSum.entry (R n M N i j : Set)50requiresring : Ring(R)51requires matrixM : M ∈ squareMatrices(R, n)52requires matrixN : N∈ squareMatrices(R, n)53requires row : i ∈ n54requires column : j ∈ n55shows matrixSum(R, n, M, N)[i, j] = M[i, j] + N[i, j]56proof57have pair := product.pair at i, j, n, n with*58exact matrixSum.value at R, n, M, N, (i, j) with*5960theorem matrixSum.matrix (R n M N : Set)61requiresring : Ring(R)62requires matrixM : M ∈ squareMatrices(R, n)63requires matrixN : N∈ squareMatrices(R, n)64shows matrixSum(R, n, M, N) ∈ squareMatrices(R, n)65proof66have function := matrixSum.function at R, n, M, N with*67exact squareMatrices.of_function with function6869-- The entrywise negation of a matrix.70defgraph matrixNegative (R n M : Set) (p ∈ n × n) : Ring.carrier(R) := -M(p)71requiresring : Ring(R)72requires matrix : M ∈ squareMatrices(R, n)73proof74have function := squareMatrices.function with matrix75have entry := FunctionBetween.apply_closed with function, member76exact Ring.neg_mem with*7778theorem matrixNegative.entry (R n M i j : Set)79requiresring : Ring(R)80requires matrix : M ∈ squareMatrices(R, n)81requires row : i ∈ n82requires column : j ∈ n83shows matrixNegative(R, n, M)[i, j] = -M[i, j]84proof85have pair := product.pair at i, j, n, n with*86exact matrixNegative.value at R, n, M, (i, j) with*8788theorem matrixNegative.matrix (R n M : Set)89requiresring : Ring(R)90requires matrix : M ∈ squareMatrices(R, n)91shows matrixNegative(R, n, M) ∈ squareMatrices(R, n)92proof93have function := matrixNegative.function at R, n, M with*94exact squareMatrices.of_function with function9596-- The product, entry by entry the finite sum of the engine.97defunique matrixProductValue (R : Set, n : Nat, M N p : Set) (a ∈ Ring.carrier(R)) :=98∃ i ∈ n, ∃ j ∈ n, p = (i, j) ∧99 a = matrixProductEntry(n, Ring.carrier(R), Ring.add(R), Ring.zero(R),100 Ring.neg(R), Ring.mul(R), Ring.one(R), M, N, i, j)101requires comm : CommRing(R)102requires matrixM : M ∈ squareMatrices(R, n)103requires matrixN : N∈ squareMatrices(R, n)104requires pair : p ∈ n × n105proof106obtain⟨bound, i, hi, j, hj, shape⟩:= product.membership.forward at107 n, n, p with*108have parts := CommRing.parts with comm109have shapeM := squareMatrices.membership.forward with matrixM110have shapeN := squareMatrices.membership.forward with matrixN111have weights := matrixProductWeights.function at n, R.carrier, R.add, R.zero,112 R.neg, R.mul, R.one, M, N, i, j with*113have finiteN := Finite.natural at n114have finite := Finite.product with finiteN, finiteN115have value : matrixProductEntry(n, R.carrier, R.add, R.zero, R.neg, R.mul,116 R.one, M, N, i, j) ∈ R.carrier117unfold matrixProductEntry118exact finiteRingSum.closed with*119refine⟨matrixProductEntry(n, R.carrier, R.add, R.zero, R.neg, R.mul, R.one,120 M, N, i, j), value, i, hi, j, hj, shape, rfl⟩121uniqueness122intros u hu first v hv second123obtain⟨i, hi, j, hj, shapeU, valueU⟩:= first124obtain⟨k, hk, l, hl, shapeV, valueV⟩:= second125have equal : (i, j) = (k, l)126cc127have coordinates := orderedPair.injective at i, j, k, l with equal128cc129130defgraph matrixProduct (R : Set, n : Nat, M N : Set) (p ∈ n × n) : Ring.carrier(R) :=131 matrixProductValue(R, n, M, N, p)132requires comm : CommRing(R)133requires matrixM : M ∈ squareMatrices(R, n)134requires matrixN : N∈ squareMatrices(R, n)135proof136have selected := matrixProductValue.selected at R, n, M, N, p with*137exact selected.left138139theorem matrixProduct.entry (R : Set, n : Nat, M N i j : Set)140requires comm : CommRing(R)141requires matrixM : M ∈ squareMatrices(R, n)142requires matrixN : N∈ squareMatrices(R, n)143requires row : i ∈ n144requires column : j ∈ n145shows matrixProduct(R, n, M, N)[i, j] =146 matrixProductEntry(n, R.carrier, R.add, R.zero, R.neg, R.mul, R.one,147 M, N, i, j)148proof149have pair := product.pair at i, j, n, n with*150have selected := matrixProductValue.selected at R, n, M, N, (i, j) with*151obtain⟨k, hk, l, hl, shape, result⟩:= selected.right152have coordinates := orderedPair.injective with shape153have value := matrixProduct.value at R, n, M, N, (i, j) with*154cc155156theorem matrixProduct.matrix (R : Set, n : Nat, M N : Set)157requires comm : CommRing(R)158requires matrixM : M ∈ squareMatrices(R, n)159requires matrixN : N∈ squareMatrices(R, n)160shows matrixProduct(R, n, M, N) ∈ squareMatrices(R, n)161proof162have function := matrixProduct.function at R, n, M, N with*163exact squareMatrices.of_function with function164165-- The operations as graphs on the matrices, the data of the ring value.166defunique matrixAdditionValue (R n q : Set) (S ∈ squareMatrices(R, n)) :=167∃ M ∈ squareMatrices(R, n), ∃ N ∈ squareMatrices(R, n),168 q = (M, N) ∧ S = matrixSum(R, n, M, N)169requiresring : Ring(R)170requires pair : q ∈ squareMatrices(R, n) × squareMatrices(R, n)171proof172obtain⟨bound, M, hM, N, hN, shape⟩:= product.membership.forward at173 squareMatrices(R, n), squareMatrices(R, n), q with*174have value := matrixSum.matrix at R, n, M, N with*175refine⟨matrixSum(R, n, M, N), value, M, hM, N, hN, shape, rfl⟩176uniqueness177intros u hu first v hv second178obtain⟨M, hM, N, hN, shapeU, valueU⟩:= first179obtain⟨K, hK, L, hL, shapeV, valueV⟩:= second180have equal : (M, N) = (K, L)181cc182have coordinates := orderedPair.injective at M, N, K, L with equal183cc184185defgraph matrixAddition (R n : Set) (q ∈ squareMatrices(R, n) × squareMatrices(R, n)) :186 squareMatrices(R, n) :=187 matrixAdditionValue(R, n, q)188requiresring : Ring(R)189proof190have selected := matrixAdditionValue.selected at R, n, q with*191exact selected.left192193theorem matrixAddition.apply (R n M N : Set)194requiresring : Ring(R)195requires matrixM : M ∈ squareMatrices(R, n)196requires matrixN : N∈ squareMatrices(R, n)197shows matrixAddition(R, n)(M, N) = matrixSum(R, n, M, N)198proof199have pair := product.pair at M, N, squareMatrices(R, n), squareMatrices(R, n) with*200have selected := matrixAdditionValue.selected at R, n, (M, N) with*201obtain⟨K, hK, L, hL, shape, result⟩:= selected.right202have coordinates := orderedPair.injective with shape203have value := matrixAddition.value at R, n, (M, N) with*204unfold call2205cc206207defunique matrixMultiplicationValue (R : Set, n : Nat, q : Set) (S ∈ squareMatrices(R, n)) :=208∃ M ∈ squareMatrices(R, n), ∃ N ∈ squareMatrices(R, n),209 q = (M, N) ∧ S = matrixProduct(R, n, M, N)210requires comm : CommRing(R)211requires pair : q ∈ squareMatrices(R, n) × squareMatrices(R, n)212proof213obtain⟨bound, M, hM, N, hN, shape⟩:= product.membership.forward at214 squareMatrices(R, n), squareMatrices(R, n), q with*215have value := matrixProduct.matrix at R, n, M, N with*216refine⟨matrixProduct(R, n, M, N), value, M, hM, N, hN, shape, rfl⟩217uniqueness218intros u hu first v hv second219obtain⟨M, hM, N, hN, shapeU, valueU⟩:= first220obtain⟨K, hK, L, hL, shapeV, valueV⟩:= second221have equal : (M, N) = (K, L)222cc223have coordinates := orderedPair.injective at M, N, K, L with equal224cc225226defgraph matrixMultiplication (R : Set, n : Nat) (q ∈ squareMatrices(R, n) × squareMatrices(R, n)) :227 squareMatrices(R, n) :=228 matrixMultiplicationValue(R, n, q)229requires comm : CommRing(R)230proof231have selected := matrixMultiplicationValue.selected at R, n, q with*232exact selected.left233234theorem matrixMultiplication.apply (R : Set, n : Nat, M N : Set)235requires comm : CommRing(R)236requires matrixM : M ∈ squareMatrices(R, n)237requires matrixN : N∈ squareMatrices(R, n)238shows matrixMultiplication(R, n)(M, N) = matrixProduct(R, n, M, N)239proof240have pair := product.pair at M, N, squareMatrices(R, n), squareMatrices(R, n) with*241have selected := matrixMultiplicationValue.selected at R, n, (M, N) with*242obtain⟨K, hK, L, hL, shape, result⟩:= selected.right243have coordinates := orderedPair.injective with shape244have value := matrixMultiplication.value at R, n, (M, N) with*245unfold call2246cc247248defgraph matrixNegation (R n : Set) (M ∈ squareMatrices(R, n)) : squareMatrices(R, n) :=249 matrixNegative(R, n, M)250requiresring : Ring(R)251proof252exact matrixNegative.matrix at R, n, M with*253254-- The zero matrix and the identity matrix of the engine.255def zeroMatrix (R n : Set) : Set:=256 constantFunction(n × n, Ring.carrier(R), Ring.zero(R))257def oneMatrix (R n : Set) : Set:=258 identityMatrix(n, Ring.carrier(R), Ring.add(R), Ring.zero(R), Ring.neg(R),259 Ring.mul(R), Ring.one(R))260261-- The matrix ring itself.262def matrixRing (R n : Set) : Set:=263 Ring.mk(squareMatrices(R, n), matrixAddition(R, n), zeroMatrix(R, n),264 matrixNegation(R, n), matrixMultiplication(R, n), oneMatrix(R, n))265266theorem matrixRing.carrierOf (R n : Set)267shows Ring.carrier(matrixRing(R, n)) = squareMatrices(R, n)268proof269simp [matrixRing, Ring.mk.carrier]270271theorem matrixRing.addOf (R n : Set)272shows Ring.add(matrixRing(R, n)) = matrixAddition(R, n)273proof274simp [matrixRing, Ring.mk.add]275276theorem matrixRing.zeroOf (R n : Set)277shows Ring.zero(matrixRing(R, n)) = zeroMatrix(R, n)278proof279simp [matrixRing, Ring.mk.zero]280281theorem matrixRing.negOf (R n : Set)282shows Ring.neg(matrixRing(R, n)) = matrixNegation(R, n)283proof284simp [matrixRing, Ring.mk.neg]285286theorem matrixRing.mulOf (R n : Set)287shows Ring.mul(matrixRing(R, n)) = matrixMultiplication(R, n)288proof289simp [matrixRing, Ring.mk.mul]290291theorem matrixRing.oneOf (R n : Set)292shows Ring.one(matrixRing(R, n)) = oneMatrix(R, n)293proof294simp [matrixRing, Ring.mk.one]295296section Constants297variable (R : Set) (n : Nat)298hypothesis comm : CommRing(R)299notationring K := (R.carrier, R.add, R.zero, R.neg, R.mul, R.one)300301theorem zeroMatrix.matrix302shows zeroMatrix(R, n) ∈ squareMatrices(R, n)303proof304have zeroIn : R[0] ∈ R := Ring.zero_mem with*305have function := constantFunction.function at n × n, R.carrier, R.zero with*306unfold zeroMatrix307exact squareMatrices.of_function with function308309theorem zeroMatrix.entry (i j : Set)310requires row : i ∈ n311requires column : j ∈ n312shows zeroMatrix(R, n)[i, j] = R[0]313proof314have zeroIn : R[0] ∈ R := Ring.zero_mem with*315have pair := product.pair at i, j, n, n with*316unfold zeroMatrix317exact constantFunction.apply with*318319theorem oneMatrix.matrix320shows oneMatrix(R, n) ∈ squareMatrices(R, n)321proof322have parts := CommRing.parts with comm323have shape := identityMatrix.matrix at R.carrier, R.add, R.zero, R.neg,324 R.mul, R.one, n with*325unfold oneMatrix326exact squareMatrices.membership.backward with shape327328theorem oneMatrix.entry (i j : Set)329requires row : i ∈ n330requires column : j ∈ n331shows oneMatrix(R, n)[i, j] = singleValue(R.carrier, R.zero, R.one, j, i)332proof333have parts := CommRing.parts with comm334unfold oneMatrix335exact identityMatrix.entry with*336337theorem squareMatrices.entry (M i j : Set)338requires matrix : M ∈ squareMatrices(R, n)339requires row : i ∈ n340requires column : j ∈ n341shows M[i, j] ∈ R342proof343have function := squareMatrices.function with matrix344have pair := product.pair at i, j, n, n with*345exact FunctionBetween.apply_closed with function, pair346347theorem squareMatrices.ext (M N : Set)348requires matrixM : M ∈ squareMatrices(R, n)349requires matrixN : N∈ squareMatrices(R, n)350requires entries : ∀ i ∈ n, ∀ j ∈ n, M[i, j] = N[i, j]351shows M = N352proof353have shapeM := squareMatrices.membership.forward with matrixM354have shapeN := squareMatrices.membership.forward with matrixN355exact RingMatrix.ext with shapeM, shapeN, entries356357end Constants358359section AdditiveLaws360variable (R : Set) (n : Nat)361hypothesis comm : CommRing(R)362363theorem matrixSum.comm (M N : Set)364requires matrixM : M ∈ squareMatrices(R, n)365requires matrixN : N∈ squareMatrices(R, n)366shows matrixSum(R, n, M, N) = matrixSum(R, n, N, M)367proof368haveleft:= matrixSum.matrix at R, n, M, N with*369haveright:= matrixSum.matrix at R, n, N, M with*370apply squareMatrices.ext withleft, right371intros i hi j hj372have entryM := squareMatrices.entry at R, n, M, i, j with*373have entryN := squareMatrices.entry at R, n, N, i, j with*374have first := matrixSum.entry at R, n, M, N, i, j with*375have second := matrixSum.entry at R, n, N, M, i, j with*376rw [first, second]377ring378379theorem matrixSum.assoc (M N P : Set)380requires matrixM : M ∈ squareMatrices(R, n)381requires matrixN : N∈ squareMatrices(R, n)382requires matrixP : P ∈ squareMatrices(R, n)383shows matrixSum(R, n, matrixSum(R, n, M, N), P) =384 matrixSum(R, n, M, matrixSum(R, n, N, P))385proof386have sumMN := matrixSum.matrix at R, n, M, N with*387have sumNP := matrixSum.matrix at R, n, N, P with*388haveleft:= matrixSum.matrix at R, n, matrixSum(R, n, M, N), P with*389haveright:= matrixSum.matrix at R, n, M, matrixSum(R, n, N, P) with*390apply squareMatrices.ext withleft, right391intros i hi j hj392have entryM := squareMatrices.entry at R, n, M, i, j with*393have entryN := squareMatrices.entry at R, n, N, i, j with*394have entryP := squareMatrices.entry at R, n, P, i, j with*395have innerL := matrixSum.entry at R, n, M, N, i, j with*396have innerR := matrixSum.entry at R, n, N, P, i, j with*397have outerL := matrixSum.entry at R, n, matrixSum(R, n, M, N), P, i, j with*398have outerR := matrixSum.entry at R, n, M, matrixSum(R, n, N, P), i, j with*399rw [outerL, outerR, innerL, innerR]400ring401402theorem matrixSum.zero_left (M : Set)403requires matrix : M ∈ squareMatrices(R, n)404shows matrixSum(R, n, zeroMatrix(R, n), M) = M405proof406have zero := zeroMatrix.matrix at R, n with*407have sum := matrixSum.matrix at R, n, zeroMatrix(R, n), M with*408apply squareMatrices.ext with sum, matrix409intros i hi j hj410have entryM := squareMatrices.entry at R, n, M, i, j with*411have entryZ := zeroMatrix.entry at R, n, i, j with*412have entry := matrixSum.entry at R, n, zeroMatrix(R, n), M, i, j with*413rw [entry, entryZ]414ring415416theorem matrixSum.zero_right (M : Set)417requires matrix : M ∈ squareMatrices(R, n)418shows matrixSum(R, n, M, zeroMatrix(R, n)) = M419proof420have zero := zeroMatrix.matrix at R, n with*421have sum := matrixSum.matrix at R, n, M, zeroMatrix(R, n) with*422apply squareMatrices.ext with sum, matrix423intros i hi j hj424have entryM := squareMatrices.entry at R, n, M, i, j with*425have entryZ := zeroMatrix.entry at R, n, i, j with*426have entry := matrixSum.entry at R, n, M, zeroMatrix(R, n), i, j with*427rw [entry, entryZ]428ring429430theorem matrixSum.neg_left (M : Set)431requires matrix : M ∈ squareMatrices(R, n)432shows matrixSum(R, n, matrixNegative(R, n, M), M) = zeroMatrix(R, n)433proof434have zero := zeroMatrix.matrix at R, n with*435have negative := matrixNegative.matrix at R, n, M with*436have sum := matrixSum.matrix at R, n, matrixNegative(R, n, M), M with*437apply squareMatrices.ext with sum, zero438intros i hi j hj439have entryM := squareMatrices.entry at R, n, M, i, j with*440have entryZ := zeroMatrix.entry at R, n, i, j with*441have entryN := matrixNegative.entry at R, n, M, i, j with*442have entry := matrixSum.entry at R, n, matrixNegative(R, n, M), M, i, j with*443rw [entry, entryN, entryZ]444ring445446theorem matrixSum.neg_right (M : Set)447requires matrix : M ∈ squareMatrices(R, n)448shows matrixSum(R, n, M, matrixNegative(R, n, M)) = zeroMatrix(R, n)449proof450have zero := zeroMatrix.matrix at R, n with*451have negative := matrixNegative.matrix at R, n, M with*452have sum := matrixSum.matrix at R, n, M, matrixNegative(R, n, M) with*453apply squareMatrices.ext with sum, zero454intros i hi j hj455have entryM := squareMatrices.entry at R, n, M, i, j with*456have entryZ := zeroMatrix.entry at R, n, i, j with*457have entryN := matrixNegative.entry at R, n, M, i, j with*458have entry := matrixSum.entry at R, n, M, matrixNegative(R, n, M), i, j with*459rw [entry, entryN, entryZ]460ring461462end AdditiveLaws463464section MultiplicativeLaws465variable (R : Set) (n : Nat)466hypothesis comm : CommRing(R)467notationring K := (R.carrier, R.add, R.zero, R.neg, R.mul, R.one)468469theorem matrixProduct.entry_sum (M N i j : Set)470requires matrixM : M ∈ squareMatrices(R, n)471requires matrixN : N∈ squareMatrices(R, n)472requires row : i ∈ n473requires column : j ∈ n474shows matrixProduct(R, n, M, N)[i, j] =475 finiteRingSum(n, K, matrixProductWeights(n, K, M, N, i, j))476proof477have entry := matrixProduct.entry at R, n, M, N, i, j with*478rw entry479unfold matrixProductEntry480rfl481482theorem matrixProduct.one_right (M : Set)483requires matrix : M ∈ squareMatrices(R, n)484shows matrixProduct(R, n, M, oneMatrix(R, n)) = M485proof486have parts := CommRing.parts with comm487have one := oneMatrix.matrix at R, n with*488have product := matrixProduct.matrix at R, n, M, oneMatrix(R, n) with*489have shapeM := squareMatrices.membership.forward with matrix490have shapeOne := squareMatrices.membership.forward with one491have finite := Finite.natural at n492apply squareMatrices.ext with product, matrix493intros i hi j hj494have entryM := squareMatrices.entry at R, n, M, i, j with*495have weights := matrixProductWeights.function at n, R.carrier, R.add, R.zero,496 R.neg, R.mul, R.one, M, oneMatrix(R, n), i, j with*497have selector := coefficientSingle.function at n, R.carrier, R.zero, M[i, j], j with*498have values : ∀ k ∈ n, matrixProductWeights(n, K, M, oneMatrix(R, n), i, j)(k) =499 coefficientSingle(n, R.carrier, R.zero, M[i, j], j)(k)500intros k hk501have entryK := squareMatrices.entry at R, n, M, i, k with*502have weight := matrixProductWeights.value at n, R.carrier, R.add, R.zero,503 R.neg, R.mul, R.one, M, oneMatrix(R, n), i, j, k with*504have unit := oneMatrix.entry at R, n, k, j with*505have alternatives : k = j ∨ k ≠ j bytauto506cases alternatives with same | different507 . have delta := singleValue.same at R.carrier, R.zero, R.one, j, k with*508have selected := coefficientSingle.same at n, R.carrier, R.zero, M[i, j], j with*509rw [weight, unit, delta, same, selected]510ring511 . have delta := singleValue.other at R.carrier, R.zero, R.one, j, k with*512have selected := coefficientSingle.other at n, R.carrier, R.zero, M[i, j], j, k with*513rw [weight, unit, delta, selected]514ring515have same := finiteRingSum.congr with values516have single := finiteRingSum.single at n, R.carrier, R.add, R.zero, R.neg,517 R.mul, R.one, M[i, j], j with*518have entry := matrixProduct.entry_sum at R, n, M, oneMatrix(R, n), i, j with*519cc520521theorem matrixProduct.one_left (M : Set)522requires matrix : M ∈ squareMatrices(R, n)523shows matrixProduct(R, n, oneMatrix(R, n), M) = M524proof525have parts := CommRing.parts with comm526have one := oneMatrix.matrix at R, n with*527have product := matrixProduct.matrix at R, n, oneMatrix(R, n), M with*528have shapeM := squareMatrices.membership.forward with matrix529have shapeOne := squareMatrices.membership.forward with one530have finite := Finite.natural at n531apply squareMatrices.ext with product, matrix532intros i hi j hj533have entryM := squareMatrices.entry at R, n, M, i, j with*534have weights := matrixProductWeights.function at n, R.carrier, R.add, R.zero,535 R.neg, R.mul, R.one, oneMatrix(R, n), M, i, j with*536have selector := coefficientSingle.function at n, R.carrier, R.zero, M[i, j], i with*537have values : ∀ k ∈ n, matrixProductWeights(n, K, oneMatrix(R, n), M, i, j)(k) =538 coefficientSingle(n, R.carrier, R.zero, M[i, j], i)(k)539intros k hk540have entryK := squareMatrices.entry at R, n, M, k, j with*541have weight := matrixProductWeights.value at n, R.carrier, R.add, R.zero,542 R.neg, R.mul, R.one, oneMatrix(R, n), M, i, j, k with*543have unit := oneMatrix.entry at R, n, i, k with*544have alternatives : k = i ∨ k ≠ i bytauto545cases alternatives with same | different546 . have equal : i = k bycc547have delta := singleValue.same at R.carrier, R.zero, R.one, k, i with*548have selected := coefficientSingle.same at n, R.carrier, R.zero, M[i, j], i with*549rw [weight, unit, delta, same, selected]550ring551 . have reverse : i ≠ k552intro equal553apply different554cc555have delta := singleValue.other at R.carrier, R.zero, R.one, k, i with*556have selected := coefficientSingle.other at n, R.carrier, R.zero, M[i, j], i, k with*557rw [weight, unit, delta, selected]558ring559have same := finiteRingSum.congr with values560have single := finiteRingSum.single at n, R.carrier, R.add, R.zero, R.neg,561 R.mul, R.one, M[i, j], i with*562have entry := matrixProduct.entry_sum at R, n, oneMatrix(R, n), M, i, j with*563cc564565theorem matrixProduct.sum_left (M N P : Set)566requires matrixM : M ∈ squareMatrices(R, n)567requires matrixN : N∈ squareMatrices(R, n)568requires matrixP : P ∈ squareMatrices(R, n)569shows matrixProduct(R, n, matrixSum(R, n, M, N), P) =570 matrixSum(R, n, matrixProduct(R, n, M, P), matrixProduct(R, n, N, P))571proof572have parts := CommRing.parts with comm573have sum := matrixSum.matrix at R, n, M, N with*574have productM := matrixProduct.matrix at R, n, M, P with*575have productN := matrixProduct.matrix at R, n, N, P with*576haveleft:= matrixProduct.matrix at R, n, matrixSum(R, n, M, N), P with*577haveright:= matrixSum.matrix at R, n, matrixProduct(R, n, M, P),578 matrixProduct(R, n, N, P) with*579have shapeM := squareMatrices.membership.forward with matrixM580have shapeN := squareMatrices.membership.forward with matrixN581have shapeP := squareMatrices.membership.forward with matrixP582have shapeSum := squareMatrices.membership.forward with sum583have finite := Finite.natural at n584have oneIn : R[1] ∈ R := Ring.one_mem with*585apply squareMatrices.ext withleft, right586intros i hi j hj587have weightsM := matrixProductWeights.function at n, R.carrier, R.add, R.zero,588 R.neg, R.mul, R.one, M, P, i, j with*589have weightsN := matrixProductWeights.function at n, R.carrier, R.add, R.zero,590 R.neg, R.mul, R.one, N, P, i, j with*591have weightsSum := matrixProductWeights.function at n, R.carrier, R.add, R.zero,592 R.neg, R.mul, R.one, matrixSum(R, n, M, N), P, i, j with*593have values : ∀ k ∈ n, matrixProductWeights(n, K, matrixSum(R, n, M, N), P, i, j)(k) =594 R[1] * matrixProductWeights(n, K, M, P, i, j)(k) + R[1] * matrixProductWeights(n, K, N, P, i, j)(k)595intros k hk596have entryM := squareMatrices.entry at R, n, M, i, k with*597have entryN := squareMatrices.entry at R, n, N, i, k with*598have entryP := squareMatrices.entry at R, n, P, k, j with*599have weightM := matrixProductWeights.value at n, R.carrier, R.add, R.zero,600 R.neg, R.mul, R.one, M, P, i, j, k with*601have weightN := matrixProductWeights.value at n, R.carrier, R.add, R.zero,602 R.neg, R.mul, R.one, N, P, i, j, k with*603have weightSum := matrixProductWeights.value at n, R.carrier, R.add, R.zero,604 R.neg, R.mul, R.one, matrixSum(R, n, M, N), P, i, j, k with*605have entrySum := matrixSum.entry at R, n, M, N, i, k with*606rw [weightM, weightN, weightSum, entrySum]607ring608have linear := finiteRingSum.linear at n, R.carrier, R.add, R.zero, R.neg,609 R.mul, R.one, matrixProductWeights(n, K, M, P, i, j),610 matrixProductWeights(n, K, N, P, i, j),611 matrixProductWeights(n, K, matrixSum(R, n, M, N), P, i, j), R[1], R[1] with*612have closedM := finiteRingSum.closed at n, R.carrier, R.add, R.zero, R.neg,613 R.mul, R.one, matrixProductWeights(n, K, M, P, i, j) with*614have closedN := finiteRingSum.closed at n, R.carrier, R.add, R.zero, R.neg,615 R.mul, R.one, matrixProductWeights(n, K, N, P, i, j) with*616have entryL := matrixProduct.entry_sum at R, n, matrixSum(R, n, M, N), P, i, j with*617have entryM := matrixProduct.entry_sum at R, n, M, P, i, j with*618have entryN := matrixProduct.entry_sum at R, n, N, P, i, j with*619have entryR := matrixSum.entry at R, n, matrixProduct(R, n, M, P),620 matrixProduct(R, n, N, P), i, j with*621rw [entryL, entryR, entryM, entryN, linear]622ring623624theorem matrixProduct.sum_right (M N P : Set)625requires matrixM : M ∈ squareMatrices(R, n)626requires matrixN : N∈ squareMatrices(R, n)627requires matrixP : P ∈ squareMatrices(R, n)628shows matrixProduct(R, n, M, matrixSum(R, n, N, P)) =629 matrixSum(R, n, matrixProduct(R, n, M, N), matrixProduct(R, n, M, P))630proof631have parts := CommRing.parts with comm632have sum := matrixSum.matrix at R, n, N, P with*633have productN := matrixProduct.matrix at R, n, M, N with*634have productP := matrixProduct.matrix at R, n, M, P with*635haveleft:= matrixProduct.matrix at R, n, M, matrixSum(R, n, N, P) with*636haveright:= matrixSum.matrix at R, n, matrixProduct(R, n, M, N),637 matrixProduct(R, n, M, P) with*638have shapeM := squareMatrices.membership.forward with matrixM639have shapeN := squareMatrices.membership.forward with matrixN640have shapeP := squareMatrices.membership.forward with matrixP641have shapeSum := squareMatrices.membership.forward with sum642have finite := Finite.natural at n643have oneIn : R[1] ∈ R := Ring.one_mem with*644apply squareMatrices.ext withleft, right645intros i hi j hj646have weightsN := matrixProductWeights.function at n, R.carrier, R.add, R.zero,647 R.neg, R.mul, R.one, M, N, i, j with*648have weightsP := matrixProductWeights.function at n, R.carrier, R.add, R.zero,649 R.neg, R.mul, R.one, M, P, i, j with*650have weightsSum := matrixProductWeights.function at n, R.carrier, R.add, R.zero,651 R.neg, R.mul, R.one, M, matrixSum(R, n, N, P), i, j with*652have values : ∀ k ∈ n, matrixProductWeights(n, K, M, matrixSum(R, n, N, P), i, j)(k) =653 R[1] * matrixProductWeights(n, K, M, N, i, j)(k) + R[1] * matrixProductWeights(n, K, M, P, i, j)(k)654intros k hk655have entryM := squareMatrices.entry at R, n, M, i, k with*656have entryN := squareMatrices.entry at R, n, N, k, j with*657have entryP := squareMatrices.entry at R, n, P, k, j with*658have weightN := matrixProductWeights.value at n, R.carrier, R.add, R.zero,659 R.neg, R.mul, R.one, M, N, i, j, k with*660have weightP := matrixProductWeights.value at n, R.carrier, R.add, R.zero,661 R.neg, R.mul, R.one, M, P, i, j, k with*662have weightSum := matrixProductWeights.value at n, R.carrier, R.add, R.zero,663 R.neg, R.mul, R.one, M, matrixSum(R, n, N, P), i, j, k with*664have entrySum := matrixSum.entry at R, n, N, P, k, j with*665rw [weightN, weightP, weightSum, entrySum]666ring667have linear := finiteRingSum.linear at n, R.carrier, R.add, R.zero, R.neg,668 R.mul, R.one, matrixProductWeights(n, K, M, N, i, j),669 matrixProductWeights(n, K, M, P, i, j),670 matrixProductWeights(n, K, M, matrixSum(R, n, N, P), i, j), R[1], R[1] with*671have closedN := finiteRingSum.closed at n, R.carrier, R.add, R.zero, R.neg,672 R.mul, R.one, matrixProductWeights(n, K, M, N, i, j) with*673have closedP := finiteRingSum.closed at n, R.carrier, R.add, R.zero, R.neg,674 R.mul, R.one, matrixProductWeights(n, K, M, P, i, j) with*675have entryL := matrixProduct.entry_sum at R, n, M, matrixSum(R, n, N, P), i, j with*676have entryN := matrixProduct.entry_sum at R, n, M, N, i, j with*677have entryP := matrixProduct.entry_sum at R, n, M, P, i, j with*678have entryR := matrixSum.entry at R, n, matrixProduct(R, n, M, N),679 matrixProduct(R, n, M, P), i, j with*680rw [entryL, entryR, entryN, entryP, linear]681ring682683end MultiplicativeLaws684685-- The triple products behind associativity, as a double array over n × n.686defunique assocWeightValue (R : Set, n : Nat, M N P i j q : Set) (a ∈ Ring.carrier(R)) :=687∃ k ∈ n, ∃ l ∈ n, q = (k, l) ∧688 a = call2(Ring.mul(R), M[i, l], call2(Ring.mul(R), N[l, k], P[k, j]))689requires comm : CommRing(R)690requires matrixM : M ∈ squareMatrices(R, n)691requires matrixN : N∈ squareMatrices(R, n)692requires matrixP : P ∈ squareMatrices(R, n)693requires row : i ∈ n694requires column : j ∈ n695requires pair : q ∈ n × n696proof697obtain⟨bound, k, hk, l, hl, shape⟩:= product.membership.forward at698 n, n, q with*699have entryM := squareMatrices.entry at R, n, M, i, l with*700have entryN := squareMatrices.entry at R, n, N, l, k with*701have entryP := squareMatrices.entry at R, n, P, k, j with*702have inner : N[l, k] * P[k, j] ∈ R := Ring.mul_mem with*703have value : M[i, l] * (N[l, k] * P[k, j]) ∈ R := Ring.mul_mem with*704refine⟨M[i, l] * (N[l, k] * P[k, j]), value, k, hk, l, hl, shape, rfl⟩705uniqueness706intros u hu first v hv second707obtain⟨k, hk, l, hl, shapeU, valueU⟩:= first708obtain⟨a, ha, b, hb, shapeV, valueV⟩:= second709have equal : (k, l) = (a, b)710cc711have coordinates := orderedPair.injective at k, l, a, b with equal712cc713714defgraph assocWeights (R : Set, n : Nat, M N P i j : Set) (q ∈ n × n) : Ring.carrier(R) :=715 assocWeightValue(R, n, M, N, P, i, j, q)716requires comm : CommRing(R)717requires matrixM : M ∈ squareMatrices(R, n)718requires matrixN : N∈ squareMatrices(R, n)719requires matrixP : P ∈ squareMatrices(R, n)720requires row : i ∈ n721requires column : j ∈ n722proof723have selected := assocWeightValue.selected at R, n, M, N, P, i, j, q with*724exact selected.left725726theorem assocWeights.pair (R : Set, n : Nat, M N P i j k l : Set)727requires comm : CommRing(R)728requires matrixM : M ∈ squareMatrices(R, n)729requires matrixN : N∈ squareMatrices(R, n)730requires matrixP : P ∈ squareMatrices(R, n)731requires row : i ∈ n732requires column : j ∈ n733requires hk : k ∈ n734requires hl : l ∈ n735shows assocWeights(R, n, M, N, P, i, j)((k, l)) = M[i, l] * (N[l, k] * P[k, j])736proof737have pair := product.pair at k, l, n, n with*738have selected := assocWeightValue.selected at R, n, M, N, P, i, j, (k, l) with*739obtain⟨a, ha, b, hb, shape, result⟩:= selected.right740have coordinates := orderedPair.injective with shape741have value := assocWeights.value at R, n, M, N, P, i, j, (k, l) with*742cc743744section Associativity745variable (R : Set) (n : Nat)746hypothesis comm : CommRing(R)747notationring K := (R.carrier, R.add, R.zero, R.neg, R.mul, R.one)748749theorem matrixProduct.assoc (M N P : Set)750requires matrixM : M ∈ squareMatrices(R, n)751requires matrixN : N∈ squareMatrices(R, n)752requires matrixP : P ∈ squareMatrices(R, n)753shows matrixProduct(R, n, matrixProduct(R, n, M, N), P) =754 matrixProduct(R, n, M, matrixProduct(R, n, N, P))755proof756have parts := CommRing.parts with comm757have productMN := matrixProduct.matrix at R, n, M, N with*758have productNP := matrixProduct.matrix at R, n, N, P with*759haveleft:= matrixProduct.matrix at R, n, matrixProduct(R, n, M, N), P with*760haveright:= matrixProduct.matrix at R, n, M, matrixProduct(R, n, N, P) with*761have shapeM := squareMatrices.membership.forward with matrixM762have shapeN := squareMatrices.membership.forward with matrixN763have shapeP := squareMatrices.membership.forward with matrixP764have shapeMN := squareMatrices.membership.forward with productMN765have shapeNP := squareMatrices.membership.forward with productNP766have finite := Finite.natural at n767apply squareMatrices.ext withleft, right768intros i hi j hj769have array := assocWeights.function at R, n, M, N, P, i, j with*770have transposed := transposedMatrix.function at n, n, R.carrier,771 assocWeights(R, n, M, N, P, i, j) with*772have rowsL := finiteRowSums.function at n, n, R.carrier, R.add, R.zero, R.neg,773 R.mul, R.one, assocWeights(R, n, M, N, P, i, j) with*774have rowsR := finiteRowSums.function at n, n, R.carrier, R.add, R.zero, R.neg,775 R.mul, R.one, transposedMatrix(n, n, R.carrier, assocWeights(R, n, M, N, P, i, j)) with*776have weightsL := matrixProductWeights.function at n, R.carrier, R.add, R.zero,777 R.neg, R.mul, R.one, matrixProduct(R, n, M, N), P, i, j with*778have weightsR := matrixProductWeights.function at n, R.carrier, R.add, R.zero,779 R.neg, R.mul, R.one, M, matrixProduct(R, n, N, P), i, j with*780have leftRows : ∀ k ∈ n, matrixProductWeights(n, K, matrixProduct(R, n, M, N), P, i, j)(k) =781 finiteRowSums(n, n, Ring.carrier(R), R.add, R.zero, R.neg, R.mul, R.one, assocWeights(R, n, M, N, P, i, j))(k)782intros k hk783have entryP := squareMatrices.entry at R, n, P, k, j with*784have rowWeights := finiteRowWeights.function at n, n, R.carrier,785 assocWeights(R, n, M, N, P, i, j), k with*786have inner := matrixProductWeights.function at n, R.carrier, R.add, R.zero,787 R.neg, R.mul, R.one, M, N, i, k with*788have scaled : ∀ l ∈ n, finiteRowWeights(n, n, Ring.carrier(R), assocWeights(R, n, M, N, P, i, j), k)(l) =789 P[k, j] * matrixProductWeights(n, K, M, N, i, k)(l)790intros l hl791have entryM := squareMatrices.entry at R, n, M, i, l with*792have entryN := squareMatrices.entry at R, n, N, l, k with*793have rowWeight := finiteRowWeights.value at n, n, R.carrier,794 assocWeights(R, n, M, N, P, i, j), k, l with*795have cell := assocWeights.pair at R, n, M, N, P, i, j, k, l with*796have weight := matrixProductWeights.value at n, R.carrier, R.add, R.zero,797 R.neg, R.mul, R.one, M, N, i, k, l with*798rw [rowWeight, cell, weight]799ring800have scale := finiteRingSum.scale_eq at n, R.carrier, R.add, R.zero, R.neg,801 R.mul, R.one, matrixProductWeights(n, K, M, N, i, k),802 finiteRowWeights(n, n, R.carrier, assocWeights(R, n, M, N, P, i, j), k), P[k, j] with*803have rowSum := finiteRowSums.value at n, n, R.carrier, R.add, R.zero, R.neg,804 R.mul, R.one, assocWeights(R, n, M, N, P, i, j), k with*805have weight := matrixProductWeights.value at n, R.carrier, R.add, R.zero,806 R.neg, R.mul, R.one, matrixProduct(R, n, M, N), P, i, j, k with*807have entryMN := matrixProduct.entry_sum at R, n, M, N, i, k with*808have closed := finiteRingSum.closed at n, R.carrier, R.add, R.zero, R.neg,809 R.mul, R.one, matrixProductWeights(n, K, M, N, i, k) with*810rw [weight, rowSum, scale, entryMN]811ring812have rightRows : ∀ l ∈ n, matrixProductWeights(n, K, M, matrixProduct(R, n, N, P), i, j)(l) =813 finiteRowSums(n, n, Ring.carrier(R), R.add, R.zero, R.neg, R.mul, R.one, transposedMatrix(n, n, Ring.carrier(R), assocWeights(R, n, M, N, P, i, j)))(l)814intros l hl815have entryM := squareMatrices.entry at R, n, M, i, l with*816have rowWeights := finiteRowWeights.function at n, n, R.carrier,817 transposedMatrix(n, n, R.carrier, assocWeights(R, n, M, N, P, i, j)), l with*818have inner := matrixProductWeights.function at n, R.carrier, R.add, R.zero,819 R.neg, R.mul, R.one, N, P, l, j with*820have scaled : ∀ k ∈ n, finiteRowWeights(n, n, Ring.carrier(R), transposedMatrix(n, n, Ring.carrier(R), assocWeights(R, n, M, N, P, i, j)), l)(k) =821 M[i, l] * matrixProductWeights(n, K, N, P, l, j)(k)822intros k hk823have entryN := squareMatrices.entry at R, n, N, l, k with*824have entryP := squareMatrices.entry at R, n, P, k, j with*825have rowWeight := finiteRowWeights.value at n, n, R.carrier,826 transposedMatrix(n, n, R.carrier, assocWeights(R, n, M, N, P, i, j)), l, k with*827have swap := transposedMatrix.pair at n, n, R.carrier,828 assocWeights(R, n, M, N, P, i, j), k, l with*829have cell := assocWeights.pair at R, n, M, N, P, i, j, k, l with*830have weight := matrixProductWeights.value at n, R.carrier, R.add, R.zero,831 R.neg, R.mul, R.one, N, P, l, j, k with*832rw [rowWeight, swap, cell, weight]833ring834have scale := finiteRingSum.scale_eq at n, R.carrier, R.add, R.zero, R.neg,835 R.mul, R.one, matrixProductWeights(n, K, N, P, l, j),836 finiteRowWeights(n, n, R.carrier, transposedMatrix(n, n, R.carrier, assocWeights(R, n, M, N, P, i, j)), l), M[i, l] with*837have rowSum := finiteRowSums.value at n, n, R.carrier, R.add, R.zero, R.neg,838 R.mul, R.one, transposedMatrix(n, n, R.carrier, assocWeights(R, n, M, N, P, i, j)), l with*839have weight := matrixProductWeights.value at n, R.carrier, R.add, R.zero,840 R.neg, R.mul, R.one, M, matrixProduct(R, n, N, P), i, j, l with*841have entryNP := matrixProduct.entry_sum at R, n, N, P, l, j with*842rw [weight, rowSum, scale, entryNP]843rfl844have sameL := finiteRingSum.congr with leftRows845have sameR := finiteRingSum.congr with rightRows846have interchange := finiteDoubleSum.interchange at n, n, R.carrier, R.add, R.zero,847 R.neg, R.mul, R.one, assocWeights(R, n, M, N, P, i, j) with*848have entryL := matrixProduct.entry_sum at R, n, matrixProduct(R, n, M, N), P, i, j with*849have entryR := matrixProduct.entry_sum at R, n, M, matrixProduct(R, n, N, P), i, j with*850unfold finiteDoubleSum at interchange851cc852853end Associativity854855-- The ring laws over separate pieces, then the ring instance.856section Instances857variable (R : Set) (n : Nat)858hypothesis comm : CommRing(R)859notationring K := (R.carrier, R.add, R.zero, R.neg, R.mul, R.one)860861theorem matrixRing.engine862shows IsRing(squareMatrices(R, n), matrixAddition(R, n), zeroMatrix(R, n),863 matrixNegation(R, n), matrixMultiplication(R, n), oneMatrix(R, n))864proof865have addMagma : IsMagma(squareMatrices(R, n), matrixAddition(R, n))866exact matrixAddition.function at R, n with*867have mulMagma : IsMagma(squareMatrices(R, n), matrixMultiplication(R, n))868exact matrixMultiplication.function at R, n with*869have negF := matrixNegation.function at R, n with*870have zero := zeroMatrix.matrix at R, n with*871have one := oneMatrix.matrix at R, n with*872have addAssoc : Associative(squareMatrices(R, n), matrixAddition(R, n))873intros M hM N hN P hP874have sumMN := matrixSum.matrix at R, n, M, N with*875have sumNP := matrixSum.matrix at R, n, N, P with*876have first := matrixAddition.apply at R, n, M, N with*877have second := matrixAddition.apply at R, n, matrixSum(R, n, M, N), P with*878have third := matrixAddition.apply at R, n, N, P with*879have fourth := matrixAddition.apply at R, n, M, matrixSum(R, n, N, P) with*880have assoc := matrixSum.assoc at R, n, M, N, P with*881cc882have addComm : Commutative(squareMatrices(R, n), matrixAddition(R, n))883intros M hM N hN884have first := matrixAddition.apply at R, n, M, N with*885have second := matrixAddition.apply at R, n, N, M with*886have swap := matrixSum.comm at R, n, M, N with*887cc888have addUnit : Identity(squareMatrices(R, n), matrixAddition(R, n), zeroMatrix(R, n))889refine⟨zero, ?_⟩890intros M hM891have first := matrixAddition.apply at R, n, zeroMatrix(R, n), M with*892have second := matrixAddition.apply at R, n, M, zeroMatrix(R, n) with*893haveleft:= matrixSum.zero_left at R, n, M with*894haveright:= matrixSum.zero_right at R, n, M with*895constructor896 . cc897 . cc898have addInverse : Inverse(squareMatrices(R, n), matrixAddition(R, n),899 zeroMatrix(R, n), matrixNegation(R, n))900refine⟨negF, ?_⟩901intros M hM902have negative := matrixNegative.matrix at R, n, M with*903have value := matrixNegation.value at R, n, M with*904have first := matrixAddition.apply at R, n, matrixNegative(R, n, M), M with*905have second := matrixAddition.apply at R, n, M, matrixNegative(R, n, M) with*906haveleft:= matrixSum.neg_left at R, n, M with*907haveright:= matrixSum.neg_right at R, n, M with*908constructor909 . cc910 . cc911have mulAssoc : Associative(squareMatrices(R, n), matrixMultiplication(R, n))912intros M hM N hN P hP913have productMN := matrixProduct.matrix at R, n, M, N with*914have productNP := matrixProduct.matrix at R, n, N, P with*915have first := matrixMultiplication.apply at R, n, M, N with*916have second := matrixMultiplication.apply at R, n, matrixProduct(R, n, M, N), P with*917have third := matrixMultiplication.apply at R, n, N, P with*918have fourth := matrixMultiplication.apply at R, n, M, matrixProduct(R, n, N, P) with*919have assoc := matrixProduct.assoc at R, n, M, N, P with*920cc921have mulUnit : Identity(squareMatrices(R, n), matrixMultiplication(R, n), oneMatrix(R, n))922refine⟨one, ?_⟩923intros M hM924have first := matrixMultiplication.apply at R, n, oneMatrix(R, n), M with*925have second := matrixMultiplication.apply at R, n, M, oneMatrix(R, n) with*926haveleft:= matrixProduct.one_left at R, n, M with*927haveright:= matrixProduct.one_right at R, n, M with*928constructor929 . cc930 . cc931have distributive : Distributive(squareMatrices(R, n), matrixAddition(R, n),932 matrixMultiplication(R, n))933intros M hM N hN P hP934have sumNP := matrixSum.matrix at R, n, N, P with*935have sumMN := matrixSum.matrix at R, n, M, N with*936have productMN := matrixProduct.matrix at R, n, M, N with*937have productMP := matrixProduct.matrix at R, n, M, P with*938have productNP := matrixProduct.matrix at R, n, N, P with*939have addNP := matrixAddition.apply at R, n, N, P with*940have addMN := matrixAddition.apply at R, n, M, N with*941have mulLeft := matrixMultiplication.apply at R, n, M, matrixSum(R, n, N, P) with*942have mulRight := matrixMultiplication.apply at R, n, matrixSum(R, n, M, N), P with*943have mulMN := matrixMultiplication.apply at R, n, M, N with*944have mulMP := matrixMultiplication.apply at R, n, M, P with*945have mulNP := matrixMultiplication.apply at R, n, N, P with*946have addLeft := matrixAddition.apply at R, n, matrixProduct(R, n, M, N),947 matrixProduct(R, n, M, P) with*948have addRight := matrixAddition.apply at R, n, matrixProduct(R, n, M, P),949 matrixProduct(R, n, N, P) with*950haveleft:= matrixProduct.sum_right at R, n, M, N, P with*951haveright:= matrixProduct.sum_left at R, n, M, N, P with*952constructor953 . cc954 . cc955unfold IsRing956simp [IsAbelianGroup, IsGroup, IsMonoid, IsSemigroup]957958instance matrixRing.ring959shows Ring(matrixRing(R, n))960proof961have engine := matrixRing.engine at R, n with comm962unfold matrixRing963exact Ring.of_parts with engine964965end Instances966967-- A matrix as a guard: (M : R ^ n × n) is Matrix(M, R, n, n), membership968-- in the matrix ring, opened to M ∈ Ring.carrier(matrixRing(R, n))969-- wherever local evidence is consulted, so (M N : R ^ n × n) carry970-- M + N, M * N, -M, and the constants matrixRing(R, n)[0] and971-- matrixRing(R, n)[1]; det(M) and adj(M) are the determinant and the972-- adjugate over R. The shape m × n is written for the guard's sake: this973-- layer has square matrices only, and Matrix(M, R, m, n) requires m = n.974predicate Matrix (M R m n : Set) := m = n ∧ M ∈ Ring.carrier(matrixRing(R, n))975notationguard"_ : _ ^ _ × _"=> Matrix976notation function "det(M)"=> determinant(n, Ring.carrier(R), Ring.add(R), Ring.zero(R), Ring.neg(R), Ring.mul(R), Ring.one(R), M) viahypothesis Matrix(M, R, m, n)977notation function "adj(M)"=> adjugate(n, Ring.carrier(R), Ring.add(R), Ring.zero(R), Ring.neg(R), Ring.mul(R), Ring.one(R), M) viahypothesis Matrix(M, R, m, n)978notationinfixl60"+"=> call2(Ring.add(matrixRing(R, n)), _, _) viahypothesis Matrix(M, R, m, n) for Ring.carrier(matrixRing(R, n))979notationinfixl70"*"=> call2(Ring.mul(matrixRing(R, n)), _, _) viahypothesis Matrix(M, R, m, n) for Ring.carrier(matrixRing(R, n))980notationprefix75"-"=>apply(Ring.neg(matrixRing(R, n)), _) viahypothesis Matrix(M, R, m, n) for Ring.carrier(matrixRing(R, n))981notationinfixl60"-"=> Ring.sub(matrixRing(R, n), _, _) viahypothesis Matrix(M, R, m, n) for Ring.carrier(matrixRing(R, n))982983theorem Matrix.of_mem (M R n : Set)984requires member : M ∈ Ring.carrier(matrixRing(R, n))985shows M : R ^ n × n986proof987unfold Matrix988exact⟨rfl, member⟩989990theorem Matrix.mem_ring (M R n : Set)991requires matrix : M : R ^ n × n992shows M ∈ Ring.carrier(matrixRing(R, n))993proof994assumption995996theorem Matrix.square (M R n : Set)997requires matrix : M : R ^ n × n998shows M ∈ squareMatrices(R, n)999proof1000have member : M ∈ Ring.carrier(matrixRing(R, n)) byassumption1001rw matrixRing.carrierOf at member1002exact member10031004theorem Matrix.of_square (M R n : Set)1005requires matrix : M ∈ squareMatrices(R, n)1006shows M : R ^ n × n1007proof1008unfold Matrix1009refine⟨rfl, ?_⟩1010rw matrixRing.carrierOf1011exact matrix10121013theorem Matrix.function (M R n : Set)1014requires matrix : M : R ^ n × n1015shows M : n × n → Ring.carrier(R)1016proof1017have square := Matrix.square with matrix1018exact squareMatrices.function with square10191020theorem Matrix.of_function (M R n : Set)1021requires function : M : n × n → Ring.carrier(R)1022shows M : R ^ n × n1023proof1024have square := squareMatrices.of_function with function1025exact Matrix.of_square with square10261027theorem Matrix.entry (M R n i j : Set)1028requires matrix : M : R ^ n × n1029requires row : i ∈ n1030requires column : j ∈ n1031shows M[i, j] ∈ Ring.carrier(R)1032proof1033have function := Matrix.function with matrix1034have pair := product.pair at i, j, n, n with*1035exact FunctionBetween.apply_closed with function, pair10361037theorem Matrix.ext (M N R n : Set)1038requires matrixM : M : R ^ n × n1039requires matrixN : N : R ^ n × n1040requires entries : ∀ i ∈ n, ∀ j ∈ n, M[i, j] = N[i, j]1041shows M = N1042proof1043have functionM := Matrix.function with matrixM1044have functionN := Matrix.function with matrixN1045have values : ∀ p ∈ n × n, M(p) = N(p)1046intros p hp1047obtain⟨bound, i, hi, j, hj, shape⟩:= product.membership.forward with hp1048rw shape1049exact entries with i, hi, j, hj1050exact FunctionBetween.ext with functionM, functionN, values1051