open import Data.Empty
open import Data.Nat using (ℕ; _+_)
open import Data.Fin hiding (_+_)
open import Data.Fin.Properties
open import Data.Vec
open import Algebra
import Algebra.Morphism.Definitions as MorphDefs
open import Relation.Binary
open import Relation.Binary.Morphism.Structures
open import Relation.Binary.PropositionalEquality as ≡ using (_≢_)
import Data.Vec.Relation.Binary.Equality.Setoid as VecSetoid
open import Vec.Permutation
module Algebra.Morphism.vecCommMonoid {c} {ℓ} {a} {ℓ′}
(S : Setoid a ℓ′)
(let open module S = Setoid S renaming (Carrier to A; _≈_ to _≈₁_))
(open VecSetoid S)
(cMonoid : CommutativeMonoid c ℓ)
(let open module CM = CommutativeMonoid cMonoid renaming (Carrier to B; _≈_ to _≈₂_))
(let open module MD {n} = MorphDefs (Vec A n) B _≈₂_)
(⟦_⟧ : ∀ {n} → Vec A n → B)
(ε-homo : Homomorphic₀ ⟦_⟧ [] ε)
(isRelHomomorphism : ∀ {n} → IsRelHomomorphism (_≋_ {n}) _≈₂_ ⟦_⟧)
(homo : ∀ {m n} → (xs : Vec A m) (ys : Vec A n) → ⟦ xs ++ ys ⟧ ≈₂ ⟦ xs ⟧ ∙ ⟦ ys ⟧)
where
open module IRL {n} = IsRelHomomorphism (isRelHomomorphism {n})
open import Vec.View S
open import Relation.Binary.Reasoning.Setoid setoid
open import Algebra.Solver.CommutativeMonoid cMonoid hiding (⟦_⟧)
private variable
m n : ℕ
xs ys ws zs vs : Vec A n
p q : A
x y w z v : B
⦅_⦆ : A → B
⦅ x ⦆ = ⟦ [ x ] ⟧
↭⇒≈ : (_↭_ {n = n}) =[ ⟦_⟧ ]⇒ _≈₂_
↭⇒≈ _↭_.refl = CM.refl
↭⇒≈ (prep {n} {xs} {ys} x xs↔ys) = begin
⟦ [ x ] ++ xs ⟧ ≈⟨ homo _ _ ⟩
⦅ x ⦆ ∙ ⟦ xs ⟧ ≈⟨ ∙-congˡ (↭⇒≈ xs↔ys) ⟩
⦅ x ⦆ ∙ ⟦ ys ⟧ ≈˘⟨ homo _ _ ⟩
⟦ [ x ] ++ ys ⟧ ∎
↭⇒≈ (swap {n} {xs} {ys} x y xs↔ys) = begin
⟦ [ x ] ++ [ y ] ++ xs ⟧ ≈⟨ homo _ _ ⟩
⦅ x ⦆ ∙ ⟦ [ y ] ++ xs ⟧ ≈⟨ ∙-congˡ (homo _ _) ⟩
⦅ x ⦆ ∙ (⦅ y ⦆ ∙ ⟦ xs ⟧) ≈˘⟨ assoc _ _ _ ⟩
⦅ x ⦆ ∙ ⦅ y ⦆ ∙ ⟦ xs ⟧ ≈⟨ ∙-cong (comm _ _) (↭⇒≈ xs↔ys) ⟩
⦅ y ⦆ ∙ ⦅ x ⦆ ∙ ⟦ ys ⟧ ≈⟨ assoc _ _ _ ⟩
⦅ y ⦆ ∙ (⦅ x ⦆ ∙ ⟦ ys ⟧) ≈˘⟨ ∙-congˡ (homo _ _) ⟩
⦅ y ⦆ ∙ ⟦ [ x ] ++ ys ⟧ ≈˘⟨ homo _ _ ⟩
⟦ [ y ] ++ [ x ] ++ ys ⟧ ∎
↭⇒≈ (_↭_.trans {n} {xs} {ys} {zs} xs↔ys ys↔zs) = begin
⟦ xs ⟧ ≈⟨ ↭⇒≈ xs↔ys ⟩
⟦ ys ⟧ ≈⟨ ↭⇒≈ ys↔zs ⟩
⟦ zs ⟧ ∎
cong-vec : {xs : Vec A m} {ys : Vec A n} → xs ≋ ys → ⟦ xs ⟧ ≈₂ ⟦ ys ⟧
cong-vec eqn with length-equal eqn
... | ≡.refl = cong eqn
cong-⦅⦆ : p ≈₁ q → ⦅ p ⦆ ≈₂ ⦅ q ⦆
cong-⦅⦆ eqn = cong (eqn VecSetoid.∷ VecSetoid.[])
homo5 : ⟦ xs ++ ys ++ ws ++ zs ++ vs ⟧ ≈₂ ⟦ xs ⟧ ∙ (⟦ ys ⟧ ∙ (⟦ ws ⟧ ∙ (⟦ zs ⟧ ∙ ⟦ vs ⟧)))
homo5 {xs = xs} {ys = ys} {ws = ws} {zs = zs} {vs = vs} = begin
⟦ xs ++ ys ++ ws ++ zs ++ vs ⟧ ≈⟨ homo xs _ ⟩
⟦ xs ⟧ ∙ ⟦ ys ++ ws ++ zs ++ vs ⟧ ≈⟨ ∙-congˡ (homo ys _) ⟩
⟦ xs ⟧ ∙ (⟦ ys ⟧ ∙ ⟦ ws ++ zs ++ vs ⟧) ≈⟨ ∙-congˡ (∙-congˡ (homo ws _)) ⟩
⟦ xs ⟧ ∙ (⟦ ys ⟧ ∙ (⟦ ws ⟧ ∙ ⟦ zs ++ vs ⟧)) ≈⟨ ∙-congˡ (∙-congˡ (∙-congˡ (homo _ _))) ⟩
⟦ xs ⟧ ∙ (⟦ ys ⟧ ∙ (⟦ ws ⟧ ∙ (⟦ zs ⟧ ∙ ⟦ vs ⟧))) ∎
swap5 : x ∙ (y ∙ (w ∙ (z ∙ v))) ≈₂ (y ∙ z) ∙ (x ∙ (w ∙ v))
swap5 = solve 5 (λ x y w z v → x ⊕ (y ⊕ (w ⊕ (z ⊕ v))) ⊜ (y ⊕ z) ⊕ (x ⊕ (w ⊕ v))) CM.refl _ _ _ _ _
swap5' : x ∙ (y ∙ (w ∙ (z ∙ v))) ≈₂ (z ∙ y) ∙ (x ∙ (w ∙ v))
swap5' = solve 5 (λ x y w z v → x ⊕ (y ⊕ (w ⊕ (z ⊕ v))) ⊜ (z ⊕ y) ⊕ (x ⊕ (w ⊕ v))) CM.refl _ _ _ _ _
swapSameVecI<j : ∀ {xs : Vec A (2 + n)} {i j p q}
→ i < j
→ ⦅ lookup xs i ⦆ ∙ ⦅ lookup xs j ⦆ ≈₂ ⦅ p ⦆ ∙ ⦅ q ⦆
→ ⟦ xs ⟧ ≈₂ ⟦ xs [ i ]≔ p [ j ]≔ q ⟧
swapSameVecI<j {xs = xs} {i} {j} {p} {q} i<j eqn with vec→VecView2 xs i<j
... | view2 {ys = ys} {x} {zs} {w} {ws} vec≡xs = begin
⟦ xs ⟧ ≈˘⟨ cong-vec vec≡xs ⟩
⟦ ys ++ [ x ] ++ zs ++ [ w ] ++ ws ⟧ ≈⟨ homo5 ⟩
⟦ ys ⟧ ∙ (⦅ x ⦆ ∙ (⟦ zs ⟧ ∙ (⦅ w ⦆ ∙ ⟦ ws ⟧))) ≈⟨ swap5 ⟩
⦅ x ⦆ ∙ ⦅ w ⦆ ∙ (⟦ ys ⟧ ∙ (⟦ zs ⟧ ∙ ⟦ ws ⟧)) ≈⟨ ∙-congʳ xw≡pq ⟩
⦅ p ⦆ ∙ ⦅ q ⦆ ∙ (⟦ ys ⟧ ∙ (⟦ zs ⟧ ∙ ⟦ ws ⟧)) ≈˘⟨ swap5 ⟩
⟦ ys ⟧ ∙ (⦅ p ⦆ ∙ (⟦ zs ⟧ ∙ (⦅ q ⦆ ∙ ⟦ ws ⟧))) ≈˘⟨ homo5 ⟩
⟦ ys ++ [ p ] ++ zs ++ [ q ] ++ ws ⟧
≈⟨ cong-vec (changeVecView2ʳ i<j q (changeVecView2ˡ i<j p vec≡xs)) ⟩
⟦ xs [ i ]≔ p [ j ]≔ q ⟧ ∎ where
lXsI : lookup xs i ≈₁ x
lXsI = lookupVecView2ˡ i<j vec≡xs
lXsJ : lookup xs j ≈₁ w
lXsJ = lookupVecView2ʳ i<j vec≡xs
xw≡pq = begin
⦅ x ⦆ ∙ ⦅ w ⦆ ≈˘⟨ ∙-cong (cong-⦅⦆ lXsI) (cong-⦅⦆ lXsJ) ⟩
⦅ lookup xs i ⦆ ∙ ⦅ lookup xs j ⦆ ≈⟨ eqn ⟩
⦅ p ⦆ ∙ ⦅ q ⦆ ∎
swapSameVecI>j : ∀ {xs : Vec A (2 + n)} {i j p q}
→ i > j
→ ⦅ lookup xs i ⦆ ∙ ⦅ lookup xs j ⦆ ≈₂ ⦅ p ⦆ ∙ ⦅ q ⦆
→ ⟦ xs ⟧ ≈₂ ⟦ xs [ i ]≔ p [ j ]≔ q ⟧
swapSameVecI>j {xs = xs} {i} {j} {p} {q} i>j eqn with vec→VecView2 xs i>j
... | view2 {ys = ys} {x} {zs} {w} {ws} vec≡xs = begin
⟦ xs ⟧ ≈˘⟨ cong-vec vec≡xs ⟩
⟦ ys ++ [ x ] ++ zs ++ [ w ] ++ ws ⟧ ≈⟨ homo5 ⟩
⟦ ys ⟧ ∙ (⦅ x ⦆ ∙ (⟦ zs ⟧ ∙ (⦅ w ⦆ ∙ ⟦ ws ⟧))) ≈⟨ swap5' ⟩
⦅ w ⦆ ∙ ⦅ x ⦆ ∙ (⟦ ys ⟧ ∙ (⟦ zs ⟧ ∙ ⟦ ws ⟧)) ≈⟨ ∙-congʳ xw≡pq ⟩
⦅ p ⦆ ∙ ⦅ q ⦆ ∙ (⟦ ys ⟧ ∙ (⟦ zs ⟧ ∙ ⟦ ws ⟧)) ≈˘⟨ swap5' ⟩
⟦ ys ⟧ ∙ (⦅ q ⦆ ∙ (⟦ zs ⟧ ∙ (⦅ p ⦆ ∙ ⟦ ws ⟧))) ≈˘⟨ homo5 ⟩
⟦ ys ++ [ q ] ++ zs ++ [ p ] ++ ws ⟧
≈⟨ cong-vec (changeVecView2ˡ i>j q (changeVecView2ʳ i>j p vec≡xs)) ⟩
⟦ xs [ i ]≔ p [ j ]≔ q ⟧ ∎ where
lXsI : lookup xs i ≈₁ w
lXsI = lookupVecView2ʳ i>j vec≡xs
lXsJ : lookup xs j ≈₁ x
lXsJ = lookupVecView2ˡ i>j vec≡xs
xw≡pq = begin
⦅ w ⦆ ∙ ⦅ x ⦆ ≈˘⟨ ∙-cong (cong-⦅⦆ lXsI) (cong-⦅⦆ lXsJ) ⟩
⦅ lookup xs i ⦆ ∙ ⦅ lookup xs j ⦆ ≈⟨ eqn ⟩
⦅ p ⦆ ∙ ⦅ q ⦆ ∎
swapSameVecLookup : ∀ {xs : Vec A n} {i j p q}
→ i ≢ j
→ ⦅ lookup xs i ⦆ ∙ ⦅ lookup xs j ⦆ ≈₂ ⦅ p ⦆ ∙ ⦅ q ⦆
→ ⟦ xs ⟧ ≈₂ ⟦ xs [ i ]≔ p [ j ]≔ q ⟧
swapSameVecLookup {n = ℕ.suc ℕ.zero} {xs} {zero} {zero} i≢j eqn = ⊥-elim (i≢j ≡.refl)
swapSameVecLookup {n = ℕ.suc (ℕ.suc n)} {xs = xs} {i} {j} i≢j eqn with <-cmp i j
... | tri≈ _ i≡j _ = ⊥-elim (i≢j i≡j)
... | tri< i<j _ _ = swapSameVecI<j i<j eqn
... | tri> _ _ i>j = swapSameVecI>j i>j eqn