module Algebra.Matrix.Properties where
open import Level using (Level)
open import Function
open import Algebra.Bundles
import Algebra.Definitions as ADefinitions
open import Data.Nat as ℕ using (ℕ)
open import Data.Nat.Properties as ℕ using ()
open import Data.Fin hiding (_+_)
open import Data.Fin.Properties
open import Data.Sum.Base using (_⊎_; inj₁; inj₂; [_,_])
open import Data.List as L using (List; []; _∷_)
open import Data.Vec.Functional as V
open import Vector.Base as V using (module SetoidProps)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as ≡ using (_≡_)
open import Relation.Nullary
import Relation.Binary.Reasoning.Setoid as ≈-Reasoning
open import Algebra.Matrix.Base renaming (flip to flipM) using ()
open import Algebra.Matrix.Structures
open import Algebra.BigOps
private variable
a ℓ : Level
l m m₁ m₂ n n₁ n₂ p q k : ℕ
i j h : Fin n
A : Set ℓ
module MRingProps (ring : Ring a ℓ) where
open Ring ring hiding (zero)
open MRing rawRing renaming (Matrix to Matrix′) hiding (flip; ∑; δ; δss≡δ)
open import Data.Vec.Functional.Relation.Binary.Equality.Setoid setoid
open SumRing ring
open IsLinear
open module AD' {m} {n} = ADefinitions (_≈ᴹ_ {m} {n})
open module SProps {n} = SetoidProps (≋-setoid n)
private
Matrix = Matrix′ Carrier
private variable
M N K P Q : Matrix m n
x y : Vector Carrier n
r : Carrier
≈ᴹ-refl : Reflexive (_≈ᴹ_ {m = m} {n})
≈ᴹ-refl i j = refl
≈ᴹ-reflexive : (∀ i j → M i j ≡ N i j) → M ≈ᴹ N
≈ᴹ-reflexive p i j rewrite p i j = refl
≈ᴹ-sym : Symmetric (_≈ᴹ_ {m = m} {n})
≈ᴹ-sym M≈N i j = sym (M≈N i j)
≈ᴹ-trans : Transitive (_≈ᴹ_ {m = m} {n})
≈ᴹ-trans M≈N N≈P i j = trans (M≈N i j) (N≈P i j)
≈ᴹ-isEquivalence : IsEquivalence (_≈ᴹ_ {m = m} {n})
≈ᴹ-isEquivalence = record
{ refl = ≈ᴹ-refl
; sym = ≈ᴹ-sym
; trans = ≈ᴹ-trans
}
≈ᴹ-setoid : ∀ {m n} → Setoid _ _
≈ᴹ-setoid {m} {n} = record
{ isEquivalence = ≈ᴹ-isEquivalence {m} {n}
}
module ≈ᴹ-Reasoning {m} {n} = ≈-Reasoning (≈ᴹ-setoid {m} {n})
*ᴹ-zero : (M : Matrix m n) → 0ᴹ *ᴹ M ≈ᴹ (0ᴹ {m = m})
*ᴹ-zero {ℕ.zero} M i k = refl
*ᴹ-zero {ℕ.suc n} M i k = begin
0# * M zero k + _ ≈⟨ +-congʳ (zeroˡ _) ⟩
0# + _ ≈⟨ +-identityˡ _ ⟩
(∑ λ j → 0# * M (suc j) k) ≈˘⟨ ∑Mulrdist 0# (λ j → M (suc j) k) ⟩
0# * (∑ λ j → M (suc j) k) ≈⟨ zeroˡ _ ⟩
0# ∎ where open ≈-Reasoning setoid
*ᴹ-identityˡ : (M : Matrix m n) → 1ᴹ *ᴹ M ≈ᴹ M
*ᴹ-identityˡ {ℕ.suc n} M zero k = begin
(1ᴹ *ᴹ M) zero k ≡⟨⟩
(∑ λ j → δ zero j * M j k) ≡⟨⟩
foldr _+_ 0# {ℕ.suc n} (λ j → δ zero j * M j k) ≡⟨⟩
δ (zero {n}) zero * M zero k + (∑ λ j → δ zero (suc j) * M (suc j) k) ≡⟨⟩
1# * M zero k + (∑ λ j → 0# * M (suc j) k) ≈˘⟨ +-congˡ (∑Mulrdist 0# λ j → M (suc j) k) ⟩
1# * M zero k + 0# * (∑ λ j → M (suc j) k) ≈⟨ +-cong (*-identityˡ _) (zeroˡ _) ⟩
M zero k + 0# ≈⟨ +-identityʳ _ ⟩
M zero k ∎ where open ≈-Reasoning setoid
*ᴹ-identityˡ {ℕ.suc n} M (suc i) k = begin
(0# * M zero k + _) ≈⟨ +-congʳ (zeroˡ _) ⟩
(0# + _) ≈⟨ +-identityˡ _ ⟩
(∑ λ j → δ (suc i) (suc j) * M (suc j) k) ≈⟨ ∑Ext (λ j → *-congʳ (reflexive (δss≡δ i j))) ⟩
(∑ λ j → δ i j * M (suc j) k) ≈⟨ *ᴹ-identityˡ (tail M) i k ⟩
M (suc i) k ∎ where open ≈-Reasoning setoid
*ᴹ-congˡ : P ≈ᴹ Q → N *ᴹ P ≈ᴹ N *ᴹ Q
*ᴹ-congˡ P≈Q _ j = ∑Ext λ k → *-congˡ (P≈Q k j)
∑Exchange : (M : Matrix m n) → ∑ (λ i → ∑ (λ j → M i j)) ≈ ∑ (λ j → ∑ (λ i → M i j))
∑Exchange {ℕ.zero} {n} M = sym (∑0r n)
∑Exchange {ℕ.suc m} {ℕ.zero} M = begin
∑ (λ i → ∑ (M i)) ≈⟨ +-congˡ (∑0r m) ⟩
0# + 0# ≈⟨ +-identityˡ 0# ⟩
0# ∎ where open ≈-Reasoning setoid
∑Exchange {ℕ.suc m} {ℕ.suc n} M =
let a = M zero zero
L = ∑ λ j → M zero (suc j)
C = ∑ λ i → M (suc i) zero
N = ∑ λ i → ∑ λ j → M (suc i) (suc j)
N' = ∑ λ j → ∑ λ i → M (suc i) (suc j)
in begin
a + L + ∑ (λ i → ∑ (λ j → M (suc i) j)) ≈⟨ +-congˡ (∑Split (λ i → M (suc i) zero) λ i → ∑ (λ j → M (suc i) (suc j))) ⟩
a + L + (C + N) ≈⟨ +-congˡ (+-congˡ (∑Exchange (λ i j → M (suc i) (suc j)))) ⟩
a + L + (C + N') ≈⟨ +-assoc _ _ _ ⟩
a + (L + (C + N')) ≈˘⟨ +-congˡ (+-assoc _ _ _) ⟩
a + (L + C + N') ≈⟨ +-congˡ (+-congʳ (+-comm _ _)) ⟩
a + (C + L + N') ≈⟨ +-congˡ (+-assoc _ _ _) ⟩
a + (C + (L + N')) ≈˘⟨ +-assoc _ _ _ ⟩
a + C + (L + N') ≈˘⟨ +-congˡ (∑Split (λ j → M zero (suc j)) λ j → ∑ (λ i → M (suc i) (suc j))) ⟩
a + C + ∑ (λ j → ∑ (λ i → M i (suc j))) ∎
where open ≈-Reasoning setoid
*ᴹ-assoc : (M : Matrix m n) (N : Matrix n p) (K : Matrix p q)
→ (M *ᴹ N) *ᴹ K ≈ᴹ M *ᴹ (N *ᴹ K)
*ᴹ-assoc M N K i j = begin
∑ (λ l → ∑ (λ k → M i k * N k l) * K l j) ≈⟨ ∑Ext (λ l → ∑Mulldist (K l j) (λ k → M i k * N k l)) ⟩
∑ (λ l → ∑ (λ k → M i k * N k l * K l j)) ≈⟨ ∑Exchange (λ l k → M i k * N k l * K l j) ⟩
∑ (λ k → ∑ (λ l → M i k * N k l * K l j)) ≈⟨ ∑Ext (λ k → ∑Ext (λ l → *-assoc (M i k) (N k l) (K l j))) ⟩
∑ (λ k → ∑ (λ l → M i k * (N k l * K l j))) ≈˘⟨ ∑Ext (λ k → ∑Mulrdist (M i k) (λ l → N k l * K l j)) ⟩
∑ (λ k → M i k * ∑ (λ l → N k l * K l j)) ∎
where open ≈-Reasoning setoid
++-split : (M : Matrix m₁ n) (N : Matrix m₂ n) (P : Matrix n p) → (M ++ N) *ᴹ P ≈ᴹ M *ᴹ P ++ N *ᴹ P
++-split {m₁} M N P i j with splitAt m₁ i
... | inj₁ _ = refl
... | inj₂ _ = refl
++ⱽ-split : (L : Matrix l m) (M : Matrix m n₁) (N : Matrix m n₂) → L *ᴹ (M ++ⱽ N) ≈ᴹ L *ᴹ M ++ⱽ L *ᴹ N
++ⱽ-split {n₁ = n₁} L M N i j with splitAt n₁ j
... | inj₁ _ = refl
... | inj₂ _ = refl
take-++ : (M : Matrix m₁ n) (N : Matrix m₂ n) → take m₁ (M ++ N) ≈ᴹ M
take-++ {m₁} {m₂ = m₂} M N i j rewrite splitAt-↑ˡ m₁ i m₂ = refl
drop-++ : (M : Matrix m₁ n) (N : Matrix m₂ n) → drop m₁ (M ++ N) ≈ᴹ N
drop-++ {m₁} {m₂ = m₂} M N i j rewrite splitAt-↑ʳ m₁ m₂ i = refl
take-++ⱽ : (M : Matrix m n₁) (N : Matrix m n₂) → takeⱽ n₁ (M ++ⱽ N) ≈ᴹ M
take-++ⱽ {n₁ = n₁} {n₂} M N i j rewrite splitAt-↑ˡ n₁ j n₂ = refl
drop-++ⱽ : (M : Matrix m n₁) (N : Matrix m n₂) → dropⱽ n₁ (M ++ⱽ N) ≈ᴹ N
drop-++ⱽ {n₁ = n₁} {n₂} M N i j rewrite splitAt-↑ʳ n₁ n₂ j = refl
isLinearId : IsLinear {m = m} {n = n} id
isLinearId .transMat _ = 1ᴹ
isLinearId .transEq _ = ≈ᴹ-sym (*ᴹ-identityˡ _)
module _
{T₁ : Matrix m n → Matrix k n}
{T₂ : Matrix k n → Matrix l n}
(isLinearT₁ : IsLinear T₁)
(isLinearT₂ : IsLinear T₂) where
isLinearComp : IsLinear (T₂ ∘ T₁)
transMat isLinearComp M = isLinearT₂ .transMat (T₁ M) *ᴹ isLinearT₁ .transMat M
transEq isLinearComp M = begin
(T₂ ∘ T₁) M
≈⟨ isLinearT₂ .transEq _ ⟩
transMat isLinearT₂ (T₁ M) *ᴹ T₁ M
≈⟨ *ᴹ-congˡ {N = transMat isLinearT₂ (T₁ M)} (isLinearT₁ .transEq M) ⟩
transMat isLinearT₂ (T₁ M) *ᴹ (transMat isLinearT₁ M *ᴹ M)
≈˘⟨ *ᴹ-assoc (transMat isLinearT₂ (T₁ M)) (transMat isLinearT₁ M) M ⟩
transMat isLinearComp M *ᴹ M ∎
where open ≈ᴹ-Reasoning
swapIsLinear : (p q : Fin n) → IsLinear {n = m} (swap p q)
transMat (swapIsLinear p q) _ = swapMatrix p q
transEq (swapIsLinear p q) M i j with p ≟ i | q ≟ i
... | yes _ | yes _ = sym (∑Mul1r (flip M j) q)
... | yes _ | no _ = sym (∑Mul1r (flip M j) q)
... | no _ | yes _ = sym (∑Mul1r (flip M j) p)
... | no _ | no _ = sym (∑Mul1r (flip M j) i)
addConstRowIsLinear : (p q : Fin n) (r : Carrier)
→ IsLinear {n = m} (λ M → M [ p ]≔ r *[ q ])
transMat (addConstRowIsLinear p q r) _ = addConstRowMatrix p q r
transEq (addConstRowIsLinear p q r) M i j with q ≟ i
... | yes _ = begin
M i j + r * M p j ≈˘⟨ +-cong (∑Mul1r (λ k → M k j) _) α ⟩
∑ (λ k → δ i k * M k j) + ∑ (λ k → r * δ p k * M k j) ≈˘⟨ ∑Split _ (λ k → r * δ p k * M k j) ⟩
∑ (λ k → δ i k * M k j + r * δ p k * M k j) ≈˘⟨ ∑Ext (λ k → distribʳ (M k j) _ _ ) ⟩
∑ (λ k → (δ i k + r * δ p k) * M k j) ∎
where
open ≈-Reasoning setoid
α = begin
∑ (λ k → r * δ p k * M k j) ≈⟨ ∑Ext (λ k → *-assoc _ _ (M k j)) ⟩
∑ (λ k → r * (δ p k * M k j)) ≈˘⟨ ∑Mulrdist _ (λ k → δ p k * M k j) ⟩
r * ∑ (λ k → δ p k * M k j) ≈⟨ *-congˡ (∑Mul1r (λ k → M k j) _) ⟩
r * M p j ∎
... | no _ = sym (∑Mul1r (flip M j) i)
isLinear→bothLinear : {T : Matrix m n → Matrix k n}
(isLin : IsLinear T) → MatFunAreLinear (transMat isLin) T
isLinear→bothLinear isLin = record { transEq = transEq isLin }
bothLinear→isLinear :
{transMat : (M : Matrix m n) → Matrix k m}
{T : Matrix m n → Matrix k n} →
MatFunAreLinear transMat T → IsLinear T
bothLinear→isLinear {transMat = transMat} bothLin = record
{ transMat = transMat
; transEq = MF.transEq }
where module MF = MatFunAreLinear bothLin
matrixOpsLinear : (mops : MatrixOps m n)
→ MatFunAreLinear (const $ matOps→mat mops) (matOps→func mops)
matrixOpsLinear (swapOp p q) = isLinear→bothLinear (swapIsLinear p q)
matrixOpsLinear (addCons p q r) = isLinear→bothLinear (addConstRowIsLinear p q r)
cong-mopsFunc : ∀ mops → M ≈ᴹ N → matOps→func mops M ≈ᴹ matOps→func mops N
cong-mopsFunc (swapOp p q) M≈N i j with p ≟ i | q ≟ i
... | yes _ | _ = M≈N _ _
... | no _ | yes _ = M≈N _ _
... | no _ | no _ = M≈N _ _
cong-mopsFunc (addCons p q r) M≈N i j with q ≟ i
... | yes _ = +-cong (M≈N _ _) (*-congˡ (M≈N _ _))
... | no _ = M≈N _ _
listMatrixOpsLinear : (lMops : List $ MatrixOps m n)
→ MatFunAreLinear (const $ listMatOps→mat lMops) (listMatOps→func lMops)
listMatrixOpsLinear [] = isLinear→bothLinear isLinearId
listMatrixOpsLinear (x ∷ lMops) = isLinear→bothLinear
(isLinearComp (bothLinear→isLinear (listMatrixOpsLinear lMops))
(bothLinear→isLinear (matrixOpsLinear x)))
≈⇒list : ∀ (M≈N : M ≈ᴹ N) list → listMatOps→func list M ≈ᴹ listMatOps→func list N
≈⇒list M≈N [] = M≈N
≈⇒list M≈N (x ∷ xs) = cong-mopsFunc x (≈⇒list M≈N xs)
swapII≡const : ∀ p i j → swap p p N i j ≡ N i j
swapII≡const p i j with p ≟ i
... | yes ≡.refl = ≡.refl
... | no _ = ≡.refl
swapCons : swap i j M ≈ᴹ N → swap (suc i) (suc j) (x V.∷ M) ≈ᴹ x V.∷ N
swapCons {i = p} {q} swapMN zero j = refl
swapCons {i = p} {q} swapMN (suc i) j
with p ≟ i | q ≟ i | swapMN i j
... | yes _ | _ | swapIJ = swapIJ
... | no _ | yes _ | swapIJ = swapIJ
... | no _ | no _ | swapIJ = swapIJ
▹⇒list : (M▹N : M ▹ N) → listMatOps→func (▹⇒listMops M▹N) M ≈ᴹ N
▹⇒list (idR M≈N) = M≈N
▹⇒list {M = M} {N} (rec {xs = M‵} mOps M▹N mys≈zs) = begin
matOps→func mOps (listMatOps→func (▹⇒listMops M▹N) M)
≈⟨ cong-mopsFunc mOps (▹⇒list M▹N) ⟩
matOps→func mOps _
≈⟨ mys≈zs ⟩
N ∎
where open ≈ᴹ-Reasoning
[]▹[] : _▹_ {n = n} V.[] V.[]
[]▹[] = idR (λ ())
∷≈▹ : x ≋ y → M ≈ᴹ N → (x V.∷ M) ▹ (y V.∷ N)
∷≈▹ = idR ∘₂ ≋-cons
add∷ : (M [ i ]≔ r *[ j ]) ≈ᴹ N → (x V.∷ M) [ suc i ]≔ r *[ suc j ] ≈ᴹ x V.∷ N
add∷ Mcons zero j = refl
add∷ {j = q} Mcons (suc i) j
with q ≟ i | Mcons i j
... | yes _ | consIJ = consIJ
... | no _ | consIJ = consIJ
∷▹▹ : x ≋ y → M ▹ N → (x V.∷ M) ▹ (y V.∷ N)
∷▹▹ x≋y (idR M≈N) = ∷≈▹ x≋y M≈N
∷▹▹ {x = x} {y} {M = M} {N} x≋y (rec (swapOp p q) M▹N mopsM) =
rec (swapOp (suc p) (suc q))
(∷▹▹ x≋y M▹N) (swapCons mopsM)
∷▹▹ x≋y (rec (addCons p q r) M▹N mopsM) =
rec (addCons (suc p) (suc q) r) (∷▹▹ x≋y M▹N) (add∷ mopsM)
▹▹∷ : ∀ {xs ys : Matrix 1 n} → xs ▹ ys → M ≈ᴹ N → (xs zero V.∷ M) ▹ (ys zero V.∷ N)
▹▹∷ (idR x≈y) = ∷≈▹ (x≈y zero)
▹▹∷ {N = N} {ys = zs} (rec {ys = ys} (swapOp zero zero) x▹y mYs≈y) M≈N =
rec (swapOp zero zero)
(▹▹∷ x▹y M≈N) α
where
α : swap zero zero (ys zero V.∷ N) ≈ᴹ zs zero V.∷ N
α zero = mYs≈y zero
α (suc i) = ≋-refl
▹▹∷ {N = N} {ys = zs} (rec {ys = ys} (addCons zero zero r) x▹y mYs≈y) M≈N =
rec (addCons zero zero r) (▹▹∷ x▹y M≈N) α
where
α : (ys zero V.∷ N) [ zero ]≔ r *[ zero ] ≈ᴹ zs zero V.∷ N
α zero = mYs≈y zero
α (suc i) = ≋-refl
flip-flip : (xs : Matrix n m) → flipM (flipM xs) ≈ᴹ xs
flip-flip xs i j rewrite opposite-involutive i | opposite-involutive j = refl
open import Algebra.Matrix.Base
swapMatrixColumns : Matrix A m (n ℕ.+ p) → Matrix A m (p ℕ.+ n)
swapMatrixColumns {n = n} {p} xs i j = xs i (cast (ℕ.+-comm p n) j)