aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Comeaux <jacquesrcomeaux@protonmail.com>2026-03-08 19:03:26 -0500
committerJacques Comeaux <jacquesrcomeaux@protonmail.com>2026-03-08 19:03:26 -0500
commit8af247cd8682f98ac1aebe235abca2cbda2342b9 (patch)
tree6184b8c1d34f591c69a478075319296774610be4
parent38e5da80b651a073b49505a92d71b15ca11e1b35 (diff)
Add monoidal category of finite relations
-rw-r--r--Data/WiringDiagram/FinRel.agda657
1 files changed, 657 insertions, 0 deletions
diff --git a/Data/WiringDiagram/FinRel.agda b/Data/WiringDiagram/FinRel.agda
new file mode 100644
index 0000000..0a60528
--- /dev/null
+++ b/Data/WiringDiagram/FinRel.agda
@@ -0,0 +1,657 @@
+{-# OPTIONS --without-K --safe #-}
+
+module Data.WiringDiagram.FinRel where
+
+open import Categories.Category using (Category)
+open import Categories.Category.Helper using (categoryHelper)
+open import Data.Fin using (Fin; splitAt; _↑ˡ_; _↑ʳ_; cast)
+open import Data.Fin.Properties using (splitAt⁻¹-↑ˡ; splitAt⁻¹-↑ʳ; splitAt-↑ˡ; splitAt-↑ʳ; ↑ˡ-injective; cast-is-id; cast-involutive; cast-trans)
+open import Data.Nat using (ℕ)
+open import Data.Nat.Properties using (+-assoc)
+open import Data.Product using (_,_; swap)
+open import Function using (flip; id; _∘_)
+open import Level using (0ℓ; suc)
+open import Relation.Binary using (REL; _⇒_; _⇔_)
+open import Relation.Binary.Construct.Composition using (_;_)
+open import Relation.Binary.PropositionalEquality as ≡ using (_≡_; module ≡-Reasoning)
+
+FinRel : Category 0ℓ (suc 0ℓ) 0ℓ
+FinRel = categoryHelper record
+ { Obj = ℕ
+ ; _⇒_ = λ n m → REL (Fin n) (Fin m) 0ℓ
+ ; _≈_ = _⇔_
+ ; id = _≡_
+ ; _∘_ = flip _;_
+ ; assoc = (λ (a , b , c , d , e) → c , (a , b , d) , e) , λ (a , (b , c , d) , e) → b , c , a , d , e
+ ; identityˡ = (λ { (_ , f[x,y] , ≡.refl) → f[x,y] }) , λ {x y} f[x,y] → y , f[x,y] , ≡.refl
+ ; identityʳ = (λ { (_ , ≡.refl , f[x,y]) → f[x,y] }) , λ {x y} f[x,y] → x , ≡.refl , f[x,y]
+ ; equiv = record
+ { refl = id , id
+ ; sym = swap
+ ; trans = λ (x , y) (x′ , y′) → x′ ∘ x , y ∘ y′
+ }
+ ; ∘-resp-≈ = λ (f⇒h , h⇒i) (g⇒i , i⇒g) → (λ (z , g-x-z , f-z-y) → z , g⇒i g-x-z , f⇒h f-z-y) , λ (z , i-x-z , h-z-y) → z , i⇒g i-x-z , h⇒i h-z-y
+ }
+
+open import Categories.Category.Monoidal using (Monoidal)
+open import Categories.Functor.Bifunctor using (Bifunctor)
+open import Data.Nat using (_+_)
+open import Data.Product using (_×_; Σ; Σ-syntax)
+open import Data.Sum using (_⊎_)
+open import Data.Sum.Properties using (inj₁-injective; inj₂-injective)
+open import Data.Empty using (⊥)
+open _⊎_
+
+opaque
+ _+₁_
+ : {A B C D : ℕ}
+ → REL (Fin A) (Fin B) 0ℓ
+ → REL (Fin C) (Fin D) 0ℓ
+ → REL (Fin (A + C)) (Fin (B + D)) 0ℓ
+ _+₁_ {A} {B} {C} {D} R S x y with splitAt A x | splitAt B y
+ ... | inj₁ x | inj₁ y = R x y
+ ... | inj₁ x | inj₂ y = ⊥
+ ... | inj₂ x | inj₁ y = ⊥
+ ... | inj₂ x | inj₂ y = S x y
+
+infixr 7 _+₁_
+
+opaque
+ unfolding _+₁_
+ +₁-⊎
+ : {A B C D : ℕ}
+ {R : REL (Fin A) (Fin B) 0ℓ}
+ {S : REL (Fin C) (Fin D) 0ℓ}
+ {x : Fin (A + C)}
+ {y : Fin (B + D)}
+ → (R +₁ S) x y
+ → Σ[ x′ ∈ Fin A ] Σ[ y′ ∈ Fin B ] (R x′ y′ × x ≡ x′ ↑ˡ C × y ≡ y′ ↑ˡ D)
+ ⊎ Σ[ x′ ∈ Fin C ] Σ[ y′ ∈ Fin D ] (S x′ y′ × x ≡ A ↑ʳ x′ × y ≡ B ↑ʳ y′)
+ +₁-⊎ {A} {B} {x = x} {y} RS with splitAt A x in eq₁ | splitAt B y in eq₂
+ ... | inj₁ x₁ | inj₁ x₂ = inj₁ (x₁ , x₂ , RS , ≡.sym (splitAt⁻¹-↑ˡ eq₁) , ≡.sym (splitAt⁻¹-↑ˡ eq₂))
+ ... | inj₂ y₁ | inj₂ y₂ = inj₂ (y₁ , y₂ , RS , ≡.sym (splitAt⁻¹-↑ʳ eq₁) , ≡.sym (splitAt⁻¹-↑ʳ eq₂))
+
+opaque
+
+ unfolding _+₁_
+
+ ↑ˡ-REL
+ : {X Y X′ Y′ : ℕ}
+ {x : Fin X}
+ {y : Fin Y}
+ {f : REL (Fin X) (Fin Y) 0ℓ}
+ {f′ : REL (Fin X′) (Fin Y′) 0ℓ}
+ → f x y
+ → (f +₁ f′) (x ↑ˡ X′) (y ↑ˡ Y′)
+ ↑ˡ-REL {X} {Y} {X′} {Y′} {x} {y} f-x-y
+ rewrite splitAt-↑ˡ X x X′
+ rewrite splitAt-↑ˡ Y y Y′ = f-x-y
+
+ ↑ʳ-REL
+ : {X Y X′ Y′ : ℕ}
+ {x′ : Fin X′}
+ {y′ : Fin Y′}
+ {f : REL (Fin X) (Fin Y) 0ℓ}
+ {f′ : REL (Fin X′) (Fin Y′) 0ℓ}
+ → f′ x′ y′
+ → (f +₁ f′) (X ↑ʳ x′) (Y ↑ʳ y′)
+ ↑ʳ-REL {X} {Y} {X′} {Y′} {x′} {y′} f′-x′-y′
+ rewrite splitAt-↑ʳ X X′ x′
+ rewrite splitAt-↑ʳ Y Y′ y′ = f′-x′-y′
+
+opaque
+ unfolding _+₁_
+ +₁-≡ : {A B : ℕ} {x y : Fin (A + B)} → ((_≡_ {A = Fin A}) +₁ _≡_) x y → x ≡ y
+ +₁-≡ {A} {B} {x} {y} x≡y₁₂ with splitAt A x in eq₁ | splitAt A y in eq₂
+ ... | inj₁ x₁ | inj₁ y₁ = ≡.trans (≡.sym (splitAt⁻¹-↑ˡ eq₁)) (≡.trans (≡.cong (_↑ˡ B) x≡y₁₂) (splitAt⁻¹-↑ˡ eq₂))
+ ... | inj₂ x₂ | inj₂ y₂ = ≡.trans (≡.sym (splitAt⁻¹-↑ʳ eq₁)) (≡.trans (≡.cong (A ↑ʳ_) x≡y₁₂) (splitAt⁻¹-↑ʳ eq₂))
+
+opaque
+ unfolding _+₁_
+ ≡-+₁ : {A B : ℕ} {x y : Fin (A + B)} → x ≡ y → ((_≡_ {A = Fin A}) +₁ _≡_) x y
+ ≡-+₁ {A} {B} {x} {y} x≡y with splitAt A x in eq₁ | splitAt A y in eq₂
+ ... | inj₁ x′ | inj₁ y′ = inj₁-injective (≡.trans (≡.sym eq₁) (≡.trans (≡.cong (splitAt A) x≡y) eq₂))
+ ... | inj₁ x′ | inj₂ y′ with () ← ≡.trans (≡.sym eq₁) (≡.trans (≡.cong (splitAt A) x≡y) eq₂)
+ ... | inj₂ x′ | inj₁ y′ with () ← ≡.trans (≡.sym eq₁) (≡.trans (≡.cong (splitAt A) x≡y) eq₂)
+ ... | inj₂ x′ | inj₂ y′ = inj₂-injective (≡.trans (≡.sym eq₁) (≡.trans (≡.cong (splitAt A) x≡y) eq₂))
+
+;-+₁
+ : {X X′ Y Y′ Z Z′ : ℕ}
+ (f : REL (Fin X) (Fin Y) 0ℓ)
+ (f′ : REL (Fin X′) (Fin Y′) 0ℓ)
+ (g : REL (Fin Y) (Fin Z) 0ℓ)
+ (g′ : REL (Fin Y′) (Fin Z′) 0ℓ)
+ (x : Fin (X + X′))
+ (y : Fin (Z + Z′))
+ → (f ; g +₁ f′ ; g′) x y
+ → ((f +₁ f′) ; (g +₁ g′)) x y
+;-+₁ {X} {X′} {Y} {Y′} {Z} {Z′} f f′ g g′ x y BER with +₁-⊎ BER
+... | inj₁ (x′ , z′ , (y , f-x′-y , g-y-z) , eq , eq₂)
+ rewrite eq
+ rewrite eq₂ = y ↑ˡ Y′ , ↑ˡ-REL f-x′-y , ↑ˡ-REL g-y-z
+... | inj₂ (x′ , y′ , (z , f′-x′-z′ , g′-z-y′) , eq₁ , eq₂)
+ rewrite eq₁
+ rewrite eq₂ = Y ↑ʳ z , ↑ʳ-REL f′-x′-z′ , ↑ʳ-REL g′-z-y′
+
+opaque
+ unfolding _+₁_
+ +₁-;
+ : {X X′ Y Y′ Z Z′ : ℕ}
+ (f : REL (Fin X) (Fin Y) 0ℓ)
+ (f′ : REL (Fin X′) (Fin Y′) 0ℓ)
+ (g : REL (Fin Y) (Fin Z) 0ℓ)
+ (g′ : REL (Fin Y′) (Fin Z′) 0ℓ)
+ (x : Fin (X + X′))
+ (y : Fin (Z + Z′))
+ → ((f +₁ f′) ; (g +₁ g′)) x y
+ → (f ; g +₁ f′ ; g′) x y
+ +₁-; {X} {X′} {Y} {Y′} {Z} {Z′} f f′ g g′ x z (y , fxygyz)
+ with splitAt X x | splitAt Y y | splitAt Z z
+ ... | inj₁ x′ | inj₁ y′ | inj₁ z′ = y′ , fxygyz
+ ... | inj₂ x′ | inj₂ y′ | inj₂ z′ = y′ , fxygyz
+
+module _ {A A′ B B′ : ℕ} {f g : REL (Fin A) (Fin B) 0ℓ} {f′ g′ : REL (Fin A′) (Fin B′) 0ℓ} where
+
+ +₁-resp-⇒ : f ⇒ g → f′ ⇒ g′ → f +₁ f′ ⇒ g +₁ g′
+ +₁-resp-⇒ f⇒g f′⇒g′ f+f′-a-b with +₁-⊎ f+f′-a-b
+ ... | inj₁ (a , b , f-a-b , ≡a↑ˡA′ , ≡b↑ˡB′) rewrite ≡a↑ˡA′ rewrite ≡b↑ˡB′ = ↑ˡ-REL (f⇒g f-a-b)
+ ... | inj₂ (a , b , f′-a-b , ≡A↑ʳa , ≡B↑ʳb) rewrite ≡A↑ʳa rewrite ≡B↑ʳb = ↑ʳ-REL (f′⇒g′ f′-a-b)
+
+⊗ : Bifunctor FinRel FinRel FinRel
+⊗ = record
+ { F₀ = λ (n , m) → n + m
+ ; F₁ = λ (f , g) → f +₁ g
+ ; identity = λ { {A , B} → +₁-≡ {A} {B} , ≡-+₁ {A} {B} }
+ ; homomorphism = λ { {X , X′} {Y , Y′} {Z , Z′} {f , f′} {g , g′} →
+ (λ { {x} {y} → ;-+₁ f f′ g g′ x y }) , (λ { {x} {y} → +₁-; f f′ g g′ x y }) }
+ ; F-resp-≈ = λ { {A , A′} {B , B′} {f , f′} {g , g′} ((f⇒g , g⇒f) , (f′⇒g′ , g′⇒f′))
+ → +₁-resp-⇒ f⇒g f′⇒g′ , +₁-resp-⇒ g⇒f g′⇒f′ }
+ }
+
+module _ {X : ℕ} where
+
+ ρ⇒ : REL (Fin (X + 0)) (Fin X) 0ℓ
+ ρ⇒ x+0 y with inj₁ x ← splitAt X x+0 = x ≡ y
+
+ ρ⇐ : REL (Fin X) (Fin (X + 0)) 0ℓ
+ ρ⇐ x y+0 with inj₁ y ← splitAt X y+0 = x ≡ y
+
+ ρ⇒⇐-≡ : ρ⇒ ; ρ⇐ ⇒ _≡_
+ ρ⇒⇐-≡ {x+0} {y+0} (z , x≡z , z≡y) with splitAt X x+0 in eq₁ | splitAt X y+0 in eq₂
+ ... | inj₁ x | inj₁ y rewrite ≡.sym (splitAt⁻¹-↑ˡ eq₁) rewrite ≡.sym (splitAt⁻¹-↑ˡ eq₂) = ≡.cong (_↑ˡ 0) (≡.trans x≡z z≡y)
+
+ ≡-ρ⇒⇐ : _≡_ ⇒ ρ⇒ ; ρ⇐
+ ≡-ρ⇒⇐ {x+0} {y+0} x↑ˡ0≡y↑ˡ0 with splitAt X x+0 in eq₁ | splitAt X y+0 in eq₂
+ ... | inj₁ x | inj₁ y rewrite ≡.sym (splitAt⁻¹-↑ˡ eq₁) rewrite ≡.sym (splitAt⁻¹-↑ˡ eq₂) = (x , ≡.refl , ↑ˡ-injective 0 x y x↑ˡ0≡y↑ˡ0)
+
+ ρ⇐⇒-≡ : ρ⇐ ; ρ⇒ ⇒ _≡_
+ ρ⇐⇒-≡ {x} {y} (z , x≡z , z≡y) with inj₁ z ← splitAt X z = ≡.trans x≡z z≡y
+
+ ≡-ρ⇐⇒ : _≡_ ⇒ ρ⇐ ; ρ⇒
+ ≡-ρ⇐⇒ {x} {y} x≡y = x ↑ˡ 0 , lemma
+ where
+ lemma : ρ⇐ x (x ↑ˡ 0) × ρ⇒ (x ↑ˡ 0) y
+ lemma with splitAt X (x ↑ˡ 0) in eq
+ ... | inj₁ x′ = ≡.sym x′≡x , ≡.trans x′≡x x≡y
+ where
+ x′≡x : x′ ≡ x
+ x′≡x = ↑ˡ-injective 0 x′ x (splitAt⁻¹-↑ˡ eq)
+
+open import Categories.Morphism FinRel using (_≅_; module ≅)
+
+module _ {X : ℕ} where
+
+ unitorˡ : 0 + X ≅ X
+ unitorˡ = ≅.refl
+
+ unitorʳ : X + 0 ≅ X
+ unitorʳ = record
+ { from = ρ⇒
+ ; to = ρ⇐
+ ; iso = record
+ { isoˡ = ρ⇒⇐-≡ , ≡-ρ⇒⇐
+ ; isoʳ = ρ⇐⇒-≡ , ≡-ρ⇐⇒
+ }
+ }
+
+module _ {X Y Z : ℕ} where
+
+ α⇒ : REL (Fin (X + Y + Z)) (Fin (X + (Y + Z))) 0ℓ
+ α⇒ [xy]z x[yz] = cast (+-assoc X Y Z) [xy]z ≡ x[yz]
+
+ α⇐ : REL (Fin (X + (Y + Z))) (Fin ((X + Y) + Z)) 0ℓ
+ α⇐ x[yz] [xy]z = cast (≡.sym (+-assoc X Y Z)) x[yz] ≡ [xy]z
+
+ α⇒;α⇐-⇒ : α⇒ ; α⇐ ⇒ _≡_
+ α⇒;α⇐-⇒ {x} {y} (z , cast-x≡z , cast-z≡y) =
+ ≡.trans
+ (≡.sym (cast-involutive (≡.sym (+-assoc X Y Z)) (+-assoc X Y Z) x))
+ (≡.trans (≡.cong (cast _) cast-x≡z) cast-z≡y)
+
+ α⇒;α⇐-⇐ : _≡_ ⇒ α⇒ ; α⇐
+ α⇒;α⇐-⇐ {x} {y} x≡y = cast _ x , ≡.refl , ≡.trans (cast-involutive (≡.sym (+-assoc X Y Z)) (+-assoc X Y Z) x) x≡y
+
+ α⇐;α⇒-⇒ : α⇐ ; α⇒ ⇒ _≡_
+ α⇐;α⇒-⇒ {x} {y} (z , cast-x≡z , cast-z≡y) =
+ ≡.trans
+ (≡.sym (cast-involutive (+-assoc X Y Z) (≡.sym (+-assoc X Y Z)) x))
+ (≡.trans (≡.cong (cast _) cast-x≡z) cast-z≡y)
+
+ α⇐;α⇒-⇐ : _≡_ ⇒ α⇐ ; α⇒
+ α⇐;α⇒-⇐ {x} {y} x≡y = cast _ x , ≡.refl , ≡.trans (cast-involutive (+-assoc X Y Z) (≡.sym (+-assoc X Y Z)) x) x≡y
+
+ associator : (X + Y) + Z ≅ X + (Y + Z)
+ associator = record
+ { from = α⇒
+ ; to = α⇐
+ ; iso = record
+ { isoˡ = α⇒;α⇐-⇒ , α⇒;α⇐-⇐
+ ; isoʳ = α⇐;α⇒-⇒ , α⇐;α⇒-⇐
+ }
+ }
+
+module _ (X Y : ℕ) (R : REL (Fin X) (Fin Y) 0ℓ) where
+
+ left₁ : (_≡_ +₁ R) ; _≡_ ⇒ _≡_ ; R
+ left₁ (_ , e-x-y′ , ≡.refl) with +₁-⊎ e-x-y′
+ ... | inj₂ (x , y , xRy , ≡.refl , ≡.refl) = x , ≡.refl , xRy
+
+ right₁ : _≡_ ; R ⇒ (_≡_ +₁ R) ; _≡_
+ right₁ {x} {y} (x , ≡.refl , xRy) = y , ↑ʳ-REL xRy , ≡.refl
+
+ unitorˡ-commute-to : (_≡_ +₁ R) ; _≡_ ⇔ _≡_ ; R
+ unitorˡ-commute-to = left₁ , right₁
+
+ left₂ : R ; _≡_ ⇒ _≡_ ; (_≡_ +₁ R)
+ left₂ {x} {y} (y , xRy , ≡.refl) = x , ≡.refl , ↑ʳ-REL xRy
+
+ right₂ : _≡_ ; (_≡_ +₁ R) ⇒ R ; _≡_
+ right₂ (_ , ≡.refl , e-x-y) with +₁-⊎ e-x-y
+ ... | inj₂ (x , y , xRy , ≡.refl , ≡.refl) = y , xRy , ≡.refl
+
+ unitorˡ-commute-from : R ; _≡_ ⇔ _≡_ ; (_≡_ +₁ R)
+ unitorˡ-commute-from = left₂ , right₂
+
+ left₃ : (R +₁ _≡_) ; ρ⇒ ⇒ ρ⇒ ; R
+ left₃ {x+0} {y} (y+0 , e-x-y , y≡y) with +₁-⊎ e-x-y | splitAt X x+0 in eq₁ | splitAt Y y+0 in eq₂ | y≡y
+ ... | inj₁ (x″ , y″ , x″Ry″ , x+0≡x″↑ˡ0 , y+0≡y″↑ˡ0) | inj₁ x′ | inj₁ y′ | y≡y′
+ rewrite (≡.sym (↑ˡ-injective 0 x′ x″ (≡.trans (splitAt⁻¹-↑ˡ eq₁) x+0≡x″↑ˡ0)))
+ rewrite (≡.sym (↑ˡ-injective 0 y′ y″ (≡.trans (splitAt⁻¹-↑ˡ eq₂) y+0≡y″↑ˡ0)))
+ rewrite ≡.sym y≡y′ = x′ , ≡.refl , x″Ry″
+
+ right₃ : ρ⇒ ; R ⇒ (R +₁ _≡_) ; ρ⇒
+ right₃ {x+0} {y} (x , e-x-y , xRy) with splitAt X x+0 in eq₁
+ ... | inj₁ x′
+ rewrite ≡.sym (splitAt⁻¹-↑ˡ eq₁)
+ rewrite e-x-y = y ↑ˡ 0 , ↑ˡ-REL xRy , lemma
+ where
+ lemma : ρ⇒ (y ↑ˡ 0) y
+ lemma with splitAt Y (y ↑ˡ 0) in eq₂
+ ... | inj₁ y′ = ↑ˡ-injective 0 y′ y (splitAt⁻¹-↑ˡ eq₂)
+
+ unitorʳ-commute-from : (R +₁ _≡_) ; ρ⇒ ⇒ ρ⇒ ; R × ρ⇒ ; R ⇒ (R +₁ _≡_) ; ρ⇒
+ unitorʳ-commute-from = left₃ , right₃
+
+ left₄ : R ; ρ⇐ ⇒ ρ⇐ ; (R +₁ _≡_)
+ left₄ {x} {y+0} (y , xRy′ , y≡y′) with splitAt Y y+0 in eq₁
+ ... | inj₁ y′
+ rewrite ≡.sym (splitAt⁻¹-↑ˡ eq₁)
+ rewrite y≡y′
+ = x ↑ˡ 0 , lemma , ↑ˡ-REL xRy′
+ where
+ lemma : ρ⇐ x (x ↑ˡ 0)
+ lemma with splitAt X (x ↑ˡ 0) in eq₂
+ ... | inj₁ x′ = ↑ˡ-injective 0 x x′ (≡.sym (splitAt⁻¹-↑ˡ eq₂))
+
+ right₄ : ρ⇐ ; (R +₁ _≡_) ⇒ R ; ρ⇐
+ right₄ {x} {y+0} (x+0 , x≡x″ , e-x-y) with +₁-⊎ e-x-y | splitAt X x+0 in eq₁
+ ... | inj₁ (x′ , y′ , x′Ry′ , x+0≡x′↑ˡ0 , y+0≡y′↑ˡ0) | inj₁ x″
+ rewrite x≡x″
+ rewrite (↑ˡ-injective 0 x″ x′ (≡.trans (splitAt⁻¹-↑ˡ eq₁) x+0≡x′↑ˡ0))
+ = y′ , x′Ry′ , lemma
+ where
+ lemma : ρ⇐ y′ y+0
+ lemma with splitAt Y y+0 in eq₂
+ ... | inj₁ y″ = ↑ˡ-injective 0 y′ y″ (≡.sym (≡.trans (splitAt⁻¹-↑ˡ eq₂) y+0≡y′↑ˡ0))
+
+ unitorʳ-commute-to : R ; ρ⇐ ⇔ ρ⇐ ; (R +₁ _≡_)
+ unitorʳ-commute-to = left₄ , right₄
+
++-↑ʳ : (A B : ℕ) {C : ℕ} (c : Fin C) → cast (+-assoc A B C) (A + B ↑ʳ c) ≡ A ↑ʳ (B ↑ʳ c)
++-↑ʳ ℕ.zero B c = cast-is-id ≡.refl (B ↑ʳ c)
++-↑ʳ (ℕ.suc A) B c = ≡.cong Fin.suc (+-↑ʳ A B c)
+
+↑ˡ-+ : {A : ℕ} (a : Fin A) (B C : ℕ) → cast (+-assoc A B C) (a ↑ˡ B ↑ˡ C) ≡ a ↑ˡ (B + C)
+↑ˡ-+ Fin.zero B C = ≡.refl
+↑ˡ-+ (Fin.suc a) B C = ≡.cong Fin.suc (↑ˡ-+ a B C)
+
+↑ʳ-↑ˡ : (A : ℕ) {B : ℕ} (b : Fin B) (C : ℕ) → cast (+-assoc A B C) ((A ↑ʳ b) ↑ˡ C) ≡ A ↑ʳ (b ↑ˡ C)
+↑ʳ-↑ˡ ℕ.zero b C = cast-is-id ≡.refl (b ↑ˡ C)
+↑ʳ-↑ˡ (ℕ.suc A) b C = ≡.cong Fin.suc (↑ʳ-↑ˡ A b C)
+
+cast-↑ˡ : {A B : ℕ} (A≡B : A ≡ B) (x : Fin A) (C : ℕ) → cast A≡B x ↑ˡ C ≡ cast (≡.cong (_+ C) A≡B) (x ↑ˡ C)
+cast-↑ˡ ≡.refl x C
+ rewrite cast-is-id ≡.refl x
+ rewrite cast-is-id ≡.refl (x ↑ˡ C) = ≡.refl
+
+cast-↑ʳ : {B C : ℕ} (B≡C : B ≡ C) (A : ℕ) (x : Fin B) → A ↑ʳ cast B≡C x ≡ cast (≡.cong (A +_) B≡C) (A ↑ʳ x)
+cast-↑ʳ ≡.refl A x
+ rewrite cast-is-id ≡.refl x
+ rewrite cast-is-id ≡.refl (A ↑ʳ x) = ≡.refl
+
+↑ˡ-assoc : {X : ℕ} (x : Fin X) (Y Z W : ℕ) → x ↑ˡ Y + Z + W ≡ cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (x ↑ˡ Y + (Z + W))
+↑ˡ-assoc {X} x Y Z W = begin
+ x ↑ˡ Y + Z + W ≡⟨ ↑ˡ-+ x (Y + Z) W ⟨
+ cast _ (x ↑ˡ Y + Z ↑ˡ W) ≡⟨ ≡.cong (cast _ ∘ (_↑ˡ W)) (↑ˡ-+ x Y Z) ⟨
+ cast (+-assoc X (Y + Z) W) (cast _ (x ↑ˡ Y ↑ˡ Z) ↑ˡ W) ≡⟨ ≡.cong (cast _) (cast-↑ˡ (+-assoc X Y Z) ((x ↑ˡ Y) ↑ˡ Z) W) ⟩
+ cast (+-assoc X (Y + Z) W) (cast _ (x ↑ˡ Y ↑ˡ Z ↑ˡ W)) ≡⟨ cast-trans _ (+-assoc X (Y + Z) W) (x ↑ˡ Y ↑ˡ Z ↑ˡ W) ⟩
+ cast _ (x ↑ˡ Y ↑ˡ Z ↑ˡ W) ≡⟨ cast-trans (+-assoc (X + Y) Z W) _ (x ↑ˡ Y ↑ˡ Z ↑ˡ W) ⟨
+ cast _ (cast (+-assoc (X + Y) Z W) (x ↑ˡ Y ↑ˡ Z ↑ˡ W)) ≡⟨ ≡.cong (cast _) (↑ˡ-+ (x ↑ˡ Y) Z W) ⟩
+ cast _ (x ↑ˡ Y ↑ˡ Z + W) ≡⟨ cast-trans _ (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (x ↑ˡ Y ↑ˡ Z + W) ⟨
+ cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (cast _ (x ↑ˡ Y ↑ˡ Z + W)) ≡⟨ ≡.cong (cast _) (↑ˡ-+ x Y (Z + W)) ⟩
+ cast _ (x ↑ˡ Y + (Z + W)) ∎
+ where
+ open ≡-Reasoning
+
+assoc-↑ʳ : (X Y Z : ℕ) {W : ℕ} (w : Fin W) → X + Y + Z ↑ʳ w ≡ cast (≡.cong (_+ W) (≡.sym (+-assoc X Y Z))) (X + (Y + Z) ↑ʳ w)
+assoc-↑ʳ X Y Z {W} w = begin
+ X + Y + Z ↑ʳ w ≡⟨ cast-involutive (≡.sym (+-assoc (X + Y) Z W)) (+-assoc (X + Y) Z W) (X + Y + Z ↑ʳ w) ⟨
+ cast _ (cast (+-assoc (X + Y) Z W) (X + Y + Z ↑ʳ w)) ≡⟨ ≡.cong (cast _) (+-↑ʳ (X + Y) Z w) ⟩
+ cast _ (X + Y ↑ʳ (Z ↑ʳ w)) ≡⟨ cast-trans (+-assoc X Y (Z + W)) eq₂ (X + Y ↑ʳ (Z ↑ʳ w)) ⟨
+ cast _ (cast (+-assoc X Y (Z + W)) (X + Y ↑ʳ (Z ↑ʳ w))) ≡⟨ ≡.cong (cast _) (+-↑ʳ X Y (Z ↑ʳ w)) ⟩
+ cast _ (X ↑ʳ Y ↑ʳ Z ↑ʳ w) ≡⟨ cast-trans (≡.cong (_+_ X) (≡.sym (+-assoc Y Z W))) eq (X ↑ʳ Y ↑ʳ Z ↑ʳ w) ⟨
+ cast eq (cast _ (X ↑ʳ Y ↑ʳ Z ↑ʳ w)) ≡⟨ ≡.cong (cast _) (cast-↑ʳ (≡.sym (+-assoc Y Z W)) X (Y ↑ʳ Z ↑ʳ w)) ⟨
+ cast _ (X ↑ʳ cast {Y + (Z + W)} {Y + Z + W} _ (Y ↑ʳ Z ↑ʳ w)) ≡⟨ ≡.cong (cast eq ∘ (X ↑ʳ_) ∘ cast _) (+-↑ʳ Y Z w) ⟨
+ cast _ (X ↑ʳ cast _ (cast (+-assoc Y Z W) (Y + Z ↑ʳ w))) ≡⟨ ≡.cong (cast eq ∘ (X ↑ʳ_)) (cast-involutive (≡.sym (+-assoc Y Z W)) (+-assoc Y Z W) (Y + Z ↑ʳ w)) ⟩
+ cast eq (X ↑ʳ (Y + Z ↑ʳ w)) ≡⟨ ≡.cong (cast eq) (+-↑ʳ X (Y + Z) w) ⟨
+ cast eq (cast _ (X + (Y + Z) ↑ʳ w)) ≡⟨ cast-trans (+-assoc X (Y + Z) W) eq (X + (Y + Z) ↑ʳ w) ⟩
+ cast _ (X + (Y + Z) ↑ʳ w) ∎
+ where
+ open ≡-Reasoning
+ eq : X + (Y + Z + W) ≡ X + Y + Z + W
+ eq = begin
+ X + (Y + Z + W) ≡⟨ +-assoc X (Y + Z) W ⟨
+ X + (Y + Z) + W ≡⟨ ≡.cong (_+ W) (+-assoc X Y Z) ⟨
+ X + Y + Z + W ∎
+ eq₂ : X + (Y + (Z + W)) ≡ X + Y + Z + W
+ eq₂ = begin
+ X + (Y + (Z + W)) ≡⟨ +-assoc X Y (Z + W) ⟨
+ X + Y + (Z + W) ≡⟨ +-assoc (X + Y) Z W ⟨
+ X + Y + Z + W ∎
+
+module _
+ {X Y X′ Y′ X″ Y″ : ℕ}
+ {R : REL (Fin X) (Fin Y) 0ℓ}
+ {S : REL (Fin X′) (Fin Y′) 0ℓ}
+ {T : REL (Fin X″) (Fin Y″) 0ℓ}
+ where
+
+ +₁-assoc-⇒
+ : {x : Fin (X + X′ + X″)}
+ {y : Fin (Y + Y′ + Y″)}
+ → ((R +₁ S) +₁ T) x y
+ → (R +₁ (S +₁ T)) (cast (+-assoc X X′ X″) x) (cast (+-assoc Y Y′ Y″) y)
+ +₁-assoc-⇒ xxxRSTyyy with +₁-⊎ xxxRSTyyy
+ ... | inj₂ (x , y , xTy , ≡.refl , ≡.refl) rewrite +-↑ʳ X X′ x rewrite +-↑ʳ Y Y′ y
+ = ↑ʳ-REL (↑ʳ-REL xTy)
+ ... | inj₁ (xx , yy , xxRSyy , ≡.refl , ≡.refl) with +₁-⊎ xxRSyy 
+ ... | inj₁ (x , y , xRy , ≡.refl , ≡.refl) rewrite ↑ˡ-+ x X′ X″ rewrite ↑ˡ-+ y Y′ Y″ = ↑ˡ-REL xRy
+ ... | inj₂ (x , y , xSy , ≡.refl , ≡.refl) rewrite ↑ʳ-↑ˡ X x X″ rewrite ↑ʳ-↑ˡ Y y Y″ = ↑ʳ-REL (↑ˡ-REL xSy)
+
+ +₁-assoc-⇐
+ : {x : Fin (X + (X′ + X″))}
+ {y : Fin (Y + (Y′ + Y″))}
+ → (R +₁ (S +₁ T)) x y
+ → ((R +₁ S) +₁ T) (cast (≡.sym (+-assoc X X′ X″)) x) (cast (≡.sym (+-assoc Y Y′ Y″)) y)
+ +₁-assoc-⇐ xxxRSTyyy with +₁-⊎ xxxRSTyyy
+ ... | inj₁ (x , y , xRy , ≡.refl , ≡.refl)
+ rewrite ≡.sym (↑ˡ-+ x X′ X″)
+ rewrite ≡.sym (↑ˡ-+ y Y′ Y″)
+ rewrite cast-involutive (≡.sym (+-assoc X X′ X″)) (+-assoc X X′ X″) (x ↑ˡ X′ ↑ˡ X″)
+ rewrite cast-involutive (≡.sym ((+-assoc Y Y′ Y″))) (+-assoc Y Y′ Y″) (y ↑ˡ Y′ ↑ˡ Y″)
+ = ↑ˡ-REL (↑ˡ-REL xRy)
+ ... | inj₂ (xx , yy , xxSTyy , ≡.refl , ≡.refl) with +₁-⊎ xxSTyy
+ ... | inj₁ (x , y , xSy , ≡.refl , ≡.refl)
+ rewrite ≡.sym (↑ʳ-↑ˡ X x X″)
+ rewrite ≡.sym (↑ʳ-↑ˡ Y y Y″)
+ rewrite cast-involutive (≡.sym (+-assoc X X′ X″)) (+-assoc X X′ X″) ((X ↑ʳ x) ↑ˡ X″)
+ rewrite cast-involutive (≡.sym (+-assoc Y Y′ Y″)) (+-assoc Y Y′ Y″) ((Y ↑ʳ y) ↑ˡ Y″)
+ = ↑ˡ-REL (↑ʳ-REL xSy)
+ ... | inj₂ (x , y , xTy , ≡.refl , ≡.refl)
+ rewrite ≡.sym (+-↑ʳ X X′ x)
+ rewrite ≡.sym (+-↑ʳ Y Y′ y)
+ rewrite cast-involutive (≡.sym (+-assoc X X′ X″)) (+-assoc X X′ X″) (X + X′ ↑ʳ x)
+ rewrite cast-involutive (≡.sym (+-assoc Y Y′ Y″)) (+-assoc Y Y′ Y″) (Y + Y′ ↑ʳ y)
+ = ↑ʳ-REL xTy
+
+module _
+ (X Y X′ Y′ X″ Y″ : ℕ)
+ (R : REL (Fin X) (Fin Y) 0ℓ)
+ (S : REL (Fin X′) (Fin Y′) 0ℓ)
+ (T : REL (Fin X″) (Fin Y″) 0ℓ)
+ where
+
+ left₅ : ((R +₁ S) +₁ T) ; α⇒ {Y} ⇒ α⇒ {X} ; (R +₁ S +₁ T)
+ left₅ {x} {y} (y′ , RST-x-y′ , y′≡y) rewrite ≡.sym y′≡y = cast (+-assoc X X′ X″) x , ≡.refl , +₁-assoc-⇒ RST-x-y′
+
+ right₅ : α⇒ {X} ; (R +₁ S +₁ T) ⇒ ((R +₁ S) +₁ T) ; α⇒ {Y}
+ right₅ {x} {y} (x′ , x≡x′ , x′RSTy)
+ rewrite ≡.trans (≡.sym (cast-involutive _ (+-assoc X X′ X″) x)) (≡.cong (cast (≡.sym (+-assoc X X′ X″))) x≡x′)
+ = cast (≡.sym (+-assoc Y Y′ Y″)) y , +₁-assoc-⇐ x′RSTy , cast-involutive (+-assoc Y Y′ Y″) _ y
+
+ assoc-commute-from : ((R +₁ S) +₁ T) ; α⇒ {Y} ⇔ α⇒ {X} ; (R +₁ S +₁ T)
+ assoc-commute-from = left₅ , right₅
+
+ left₆ : (R +₁ S +₁ T) ; α⇐ {Y} ⇒ α⇐ {X} ; ((R +₁ S) +₁ T)
+ left₆ {xxx} {yyy} (yyy′ , xxxRSTyyy′ , ≡.refl)
+ = cast (≡.sym (+-assoc X X′ X″)) xxx , ≡.refl , +₁-assoc-⇐ xxxRSTyyy′
+
+ right₆ : α⇐ {X} ; ((R +₁ S) +₁ T) ⇒ (R +₁ S +₁ T) ; α⇐ {Y}
+ right₆ {xxx} {yyy} (xxx′ , xxx≡xxx′ , xxx′RSTyyy)
+ rewrite ≡.trans (≡.sym (cast-involutive (+-assoc X X′ X″) _ xxx)) (≡.cong (cast (+-assoc X X′ X″)) (xxx≡xxx′))
+ = cast (+-assoc Y Y′ Y″) yyy , +₁-assoc-⇒ xxx′RSTyyy , cast-involutive (≡.sym (+-assoc Y Y′ Y″)) _ yyy
+
+ assoc-commute-to : (R +₁ S +₁ T) ; α⇐ {Y} ⇔ α⇐ {X} ; ((R +₁ S) +₁ T)
+ assoc-commute-to = left₆ , right₆
+
+module _ (X Y : ℕ) where
+
+ triˡ : α⇒ {X} ; (_≡_ {A = Fin X} +₁ _≡_) ⇒ ρ⇒ +₁ _≡_ {A = Fin Y}
+ triˡ {[x0]y} {x[0y]} (x[0y]′ , ≡.refl , e-[x0]y-x[0y]) with +₁-⊎ e-[x0]y-x[0y]
+ ... | inj₁ (x , x , ≡.refl , cast[x0]y≡x↑ˡY , ≡.refl)
+ rewrite ≡.trans
+ (≡.sym (cast-involutive (≡.sym (+-assoc X 0 Y)) _ [x0]y))
+ (≡.cong (cast _) cast[x0]y≡x↑ˡY)
+ rewrite ≡.trans
+ (≡.cong (cast (≡.sym (+-assoc X 0 Y))) (≡.sym (↑ˡ-+ x 0 Y)))
+ (cast-involutive _ (+-assoc X 0 Y) (x ↑ˡ 0 ↑ˡ Y))
+ = ↑ˡ-REL aux
+ where
+ aux : ρ⇒ (x ↑ˡ 0) x
+ aux with splitAt X (x ↑ˡ 0) in eq
+ ... | inj₁ x′ = ↑ˡ-injective 0 x′ x (splitAt⁻¹-↑ˡ eq)
+ ... | inj₂ (y , y , ≡.refl , cast[x0]y≡X↑ʳy , ≡.refl)
+ rewrite ≡.trans
+ (≡.sym (cast-involutive (≡.sym (+-assoc X 0 Y)) _ [x0]y))
+ (≡.cong (cast _) cast[x0]y≡X↑ʳy)
+ rewrite ≡.trans
+ (≡.cong (cast (≡.sym (+-assoc X 0 Y))) (≡.sym (+-↑ʳ X 0 y)))
+ (cast-involutive (≡.sym (+-assoc X 0 Y)) _ (X + 0 ↑ʳ y))
+ = ↑ʳ-REL ≡.refl
+
+ triʳ : ρ⇒ +₁ _≡_ {A = Fin Y} ⇒ α⇒ {X} ; (_≡_ {A = Fin X} +₁ _≡_)
+ triʳ {[x0]y} {x[0y]} e-[x0]y-x[0y] with +₁-⊎ e-[x0]y-x[0y]
+ ... | inj₂ (y , y , ≡.refl , ≡.refl , ≡.refl) = x[0y] , +-↑ʳ X 0 y , ↑ʳ-REL ≡.refl
+ ... | inj₁ (x0 , x , x′≡x , ≡.refl , ≡.refl) with splitAt X x0 in eq
+ ... | inj₁ x′ rewrite ≡.sym (splitAt⁻¹-↑ˡ eq) rewrite x′≡x = x[0y] , ↑ˡ-+ x 0 Y , ↑ˡ-REL ≡.refl
+
+ triangle : α⇒ {X} ; (_≡_ {A = Fin X} +₁ _≡_) ⇔ ρ⇒ +₁ _≡_ {A = Fin Y}
+ triangle = triˡ , triʳ
+
+module _ (X Y Z W : ℕ) where
+
+ pentˡ
+ : ((α⇒ {X} {Y} {Z} +₁ _≡_ {A = Fin W}) ; α⇒ {X}) ; (_≡_ {A = Fin X} +₁ (α⇒ {Y}))
+ ⇒ α⇒ {X + Y} ; α⇒ {X}
+ pentˡ {xyzw} {x[y[zw]]} (x[[yz]w] , ([x[yz]]w , xyzw~[x[yz]]w , ≡.refl) , [x[yz]]w~x[y[zw]])
+ with +₁-⊎ xyzw~[x[yz]]w | +₁-⊎ [x[yz]]w~x[y[zw]]
+ ... | inj₁ ([xy]z , x[y]z , ≡.refl , ≡.refl , ≡.refl)
+ | inj₁ (x , x′ , ≡.refl , [xy]z↑ˡW≡x↑ˡY+Z+W , ≡.refl)
+ = cast (≡.sym (+-assoc X Y (Z + W))) x[y[zw]]
+ , eq
+ , cast-involutive (+-assoc X Y (Z + W)) (≡.sym (+-assoc X Y (Z + W))) x[y[zw]]
+ where
+ lemma : cast _ [xy]z ↑ˡ W ≡ cast _ (x ↑ˡ Y + Z + W)
+ lemma = ≡.trans
+ (≡.sym (cast-involutive (≡.sym (+-assoc X (Y + Z) W)) (+-assoc X (Y + Z) W) (cast {X + Y + Z} {X + (Y + Z)} _ [xy]z ↑ˡ W)))
+ (≡.cong (cast (≡.sym (+-assoc X (Y + Z) W))) [xy]z↑ˡW≡x↑ˡY+Z+W)
+ open ≡-Reasoning
+ eq : cast {X + Y + Z + W} {X + Y + (Z + W)} _ ([xy]z ↑ˡ W)
+ ≡ cast {X + (Y + (Z + W))} {X + Y + (Z + W)} _ x[y[zw]]
+ eq = begin
+ cast (+-assoc (X + Y) Z W) ([xy]z ↑ˡ W)
+ ≡⟨ cast-trans _ (≡.trans (≡.cong (_+ W) (≡.sym (+-assoc X Y Z))) (+-assoc (X + Y) Z W)) ([xy]z ↑ˡ W) ⟨
+ cast (≡.trans (≡.cong (_+ W) (≡.sym (+-assoc X Y Z))) (+-assoc (X + Y) Z W)) (cast _ ([xy]z ↑ˡ W))
+ ≡⟨ ≡.cong (cast _) (cast-↑ˡ (+-assoc X Y Z) [xy]z W) ⟨
+ cast _ (cast _ [xy]z ↑ˡ W)
+ ≡⟨ ≡.cong (cast _) lemma ⟩
+ cast (≡.trans (≡.cong (_+ W) (≡.sym (+-assoc X Y Z))) (+-assoc (X + Y) Z W))
+ (cast (≡.sym (+-assoc X (Y + Z) W)) (x ↑ˡ Y + Z + W))
+ ≡⟨ cast-trans (≡.sym (+-assoc X (Y + Z) W)) (≡.trans (≡.cong (_+ W) (≡.sym (+-assoc X Y Z))) (+-assoc (X + Y) Z W)) (x ↑ˡ Y + Z + W) ⟩
+ cast _ (x ↑ˡ Y + Z + W)
+ ≡⟨ ≡.cong (cast _) (↑ˡ-assoc x Y Z W) ⟩
+ cast _ (cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (x ↑ˡ Y + (Z + W)))
+ ≡⟨ cast-trans (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) _ (x ↑ˡ Y + (Z + W)) ⟩
+ cast _ (x ↑ˡ (Y + (Z + W))) ∎
+ ... | inj₁ ([xy]z , x[yz] , ≡.refl , ≡.refl , ≡.refl) | inj₂ ([yz]w , y[zw] , ≡.refl , [xy]z↑ˡW≡X↑ʳ[yz]w , ≡.refl)
+ = cast (≡.sym (+-assoc X Y (Z + W))) (x[y[zw]])
+ , eq
+ , cast-involutive (+-assoc X Y (Z + W)) _ (X ↑ʳ cast _ [yz]w)
+ where
+ open ≡-Reasoning
+ lemma₁ : X + (Y + Z + W) ≡ X + Y + Z + W
+ lemma₁ = begin
+ X + (Y + Z + W) ≡⟨ +-assoc X (Y + Z) W ⟨
+ X + (Y + Z) + W ≡⟨ ≡.cong (_+ W) (+-assoc X Y Z) ⟨
+ X + Y + Z + W ∎
+ lemma₂ : cast {X + Y + Z + W} {X + (Y + Z) + W} _ ([xy]z ↑ˡ W) ≡ cast _ (X ↑ʳ [yz]w)
+ lemma₂ = begin
+ cast _ ([xy]z ↑ˡ W)   ≡⟨ cast-↑ˡ (+-assoc X Y Z) [xy]z W ⟨
+ cast _ [xy]z ↑ˡ W ≡⟨ cast-involutive (≡.sym (+-assoc X (Y + Z) W)) _ (cast _ [xy]z ↑ˡ W) ⟨
+ cast _ (cast (+-assoc X (Y + Z) W) (cast _ [xy]z ↑ˡ W)) ≡⟨ ≡.cong (cast _) [xy]z↑ˡW≡X↑ʳ[yz]w ⟩
+ cast _ (X ↑ʳ [yz]w) ∎
+ lemma₃ : [xy]z ↑ˡ W ≡ cast _ (X ↑ʳ [yz]w)
+ lemma₃ = begin
+ [xy]z ↑ˡ W ≡⟨ cast-involutive (≡.sym (≡.cong (_+ W) (+-assoc X Y Z))) _ ([xy]z ↑ˡ W) ⟨
+ cast _ (cast (≡.cong (_+ W) (+-assoc X Y Z)) ([xy]z ↑ˡ W)) ≡⟨ ≡.cong (cast _) lemma₂ ⟩
+ cast (≡.sym (≡.cong (_+ W) (+-assoc X Y Z))) (cast _ (X ↑ʳ [yz]w)) ≡⟨ cast-trans _ (≡.sym (≡.cong (_+ W) (+-assoc X Y Z))) (X ↑ʳ [yz]w) ⟩
+ cast _ (X ↑ʳ [yz]w) ∎
+ eq : cast (+-assoc (X + Y) Z W) ([xy]z ↑ˡ W) ≡ cast _ (X ↑ʳ cast _ [yz]w)
+ eq = begin
+ cast _ ([xy]z ↑ˡ W) ≡⟨ ≡.cong (cast _) lemma₃ ⟩
+ cast (+-assoc (X + Y) Z W) (cast _ (X ↑ʳ [yz]w)) ≡⟨ cast-trans lemma₁ (+-assoc (X + Y) Z W) (X ↑ʳ [yz]w) ⟩
+ cast _ (X ↑ʳ [yz]w) ≡⟨ cast-trans _ (≡.sym (+-assoc X Y (Z + W))) (X ↑ʳ [yz]w) ⟨
+ cast (≡.sym (+-assoc X Y (Z + W))) (cast _ (X ↑ʳ [yz]w)) ≡⟨ ≡.cong (cast _) (cast-↑ʳ (+-assoc Y Z W) X [yz]w) ⟨
+ cast _ (X ↑ʳ cast _ [yz]w) ∎
+ ... | inj₂ (w , w , ≡.refl , ≡.refl , ≡.refl) | inj₁ (x , x , ≡.refl , X+[Y+Z]↑ʳw≡x↑ˡY+Z+W , ≡.refl)
+ = cast (≡.sym (+-assoc X Y (Z + W))) x[y[zw]]
+ , eq
+ , cast-involutive (+-assoc X Y (Z + W)) _ (x ↑ˡ Y + (Z + W))
+ where
+ open ≡-Reasoning
+ lemma₁ : X + (Y + (Z + W)) ≡ X + (Y + Z + W)
+ lemma₁ = ≡.cong (X +_) (≡.sym (+-assoc Y Z W))
+ lemma₂ : X + (Y + Z + W) ≡ X + Y + (Z + W)
+ lemma₂ = ≡.trans (≡.cong (X +_) (+-assoc Y Z W)) (≡.sym (+-assoc X Y (Z + W)))
+ lemma₃ : X + (Y + Z) + W ≡ X + Y + Z + W
+ lemma₃ = ≡.cong (_+ W) (≡.sym (+-assoc X Y Z))
+ eq : cast _ (X + Y + Z ↑ʳ w) ≡ cast (≡.sym (+-assoc X Y (Z + W))) (x ↑ˡ Y + (Z + W))
+ eq = begin
+ cast _ (X + Y + Z ↑ʳ w) ≡⟨ ≡.cong (cast _) (assoc-↑ʳ X Y Z w) ⟩
+ cast _ (cast lemma₃ (X + (Y + Z) ↑ʳ w)) ≡⟨ cast-trans lemma₃ (+-assoc (X + Y) Z W) (X + (Y + Z) ↑ʳ w) ⟩
+ cast _ (X + (Y + Z) ↑ʳ w) ≡⟨ cast-trans (+-assoc X (Y + Z) W) _ (X + (Y + Z) ↑ʳ w) ⟨
+ cast _ (cast (+-assoc X (Y + Z) W) (X + (Y + Z) ↑ʳ w)) ≡⟨ ≡.cong (cast _) X+[Y+Z]↑ʳw≡x↑ˡY+Z+W ⟩
+ cast _ (x ↑ˡ Y + Z + W) ≡⟨ ≡.cong (cast _) (↑ˡ-assoc x Y Z W) ⟩
+ cast lemma₂ (cast lemma₁ (x ↑ˡ Y + (Z + W))) ≡⟨ cast-trans lemma₁ lemma₂ (x ↑ˡ Y + (Z + W)) ⟩
+ cast (≡.sym (+-assoc X Y (Z + W))) (x ↑ˡ Y + (Z + W)) ∎
+ ... | inj₂ (w , w , ≡.refl , ≡.refl , ≡.refl) | inj₂ ([yz]w , y[zw] , ≡.refl , X+[Y+Z]↑ʳw≡X↑ʳ[yz]w , ≡.refl)
+ = cast (≡.sym (+-assoc X Y (Z + W))) x[y[zw]]
+ , eq
+ , cast-involutive {X + Y + (Z + W)} {X + (Y + (Z + W))} (+-assoc X Y (Z + W)) _ (X ↑ʳ cast _ [yz]w)
+ where
+ open ≡-Reasoning
+ lemma : X + (Y + Z + W) ≡ X + Y + (Z + W)
+ lemma = ≡.trans (≡.cong (X +_) (+-assoc Y Z W)) (≡.sym (+-assoc X Y (Z + W)))
+ eq : cast (+-assoc (X + Y) Z W) (X + Y + Z ↑ʳ w) ≡ cast (≡.sym (+-assoc X Y (Z + W))) (X ↑ʳ cast (+-assoc Y Z W) [yz]w)
+ eq = begin
+ cast _ (X + Y + Z ↑ʳ w) ≡⟨ ≡.cong (cast _) (assoc-↑ʳ X Y Z w) ⟩
+ cast (+-assoc (X + Y) Z W) (cast _ (X + (Y + Z) ↑ʳ w)) ≡⟨ cast-trans _ (+-assoc (X + Y) Z W) (X + (Y + Z) ↑ʳ w) ⟩
+ cast _ (X + (Y + Z) ↑ʳ w) ≡⟨ cast-trans (+-assoc X (Y + Z) W) _ (X + (Y + Z) ↑ʳ w) ⟨
+ cast lemma (cast _ (X + (Y + Z) ↑ʳ w)) ≡⟨ ≡.cong (cast _) X+[Y+Z]↑ʳw≡X↑ʳ[yz]w ⟩
+ cast _ (X ↑ʳ [yz]w) ≡⟨ cast-trans (≡.cong (X +_) (+-assoc Y Z W)) _ (X ↑ʳ [yz]w) ⟨
+ cast _ (cast (≡.cong (X +_) (+-assoc Y Z W)) (X ↑ʳ [yz]w)) ≡⟨ ≡.cong (cast _) (cast-↑ʳ (+-assoc Y Z W) X [yz]w) ⟨
+ cast _ (X ↑ʳ cast _ [yz]w) ∎
+
+ pentʳ
+ : α⇒ {X + Y} ; α⇒ {X}
+ ⇒ ((α⇒ {X} {Y} {Z} +₁ _≡_ {A = Fin W}) ; α⇒ {X}) ; (_≡_ {A = Fin X} +₁ (α⇒ {Y}))
+ pentʳ {xyzw} {x[y[zw]]} (xy[zw] , ≡.refl , ≡.refl)
+ = cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) x[y[zw]]
+ , (cast (≡.cong (_+ W) (+-assoc X Y Z)) xyzw , eq₁ , eq₂)
+ , eq₃
+ where
+ eq₁ : ((λ [xy]z x[yz] → cast _ [xy]z ≡ x[yz]) +₁ _≡_) xyzw (cast {X + Y + Z + W} {X + (Y + Z) + W} (≡.cong (_+ W) (+-assoc X Y Z)) xyzw)
+ eq₁ with splitAt (X + Y + Z) xyzw in eq
+ ... | inj₁ xyz rewrite ≡.sym (splitAt⁻¹-↑ˡ eq) = lemma
+ where
+ lemma : ((λ [xy]z x[yz] → cast (+-assoc X Y Z) [xy]z ≡ x[yz]) +₁ _≡_) (xyz ↑ˡ W) (cast (≡.cong (_+ W) (+-assoc X Y Z)) (xyz ↑ˡ W))
+ lemma rewrite ≡.sym (cast-↑ˡ (+-assoc X Y Z) xyz W) = ↑ˡ-REL ≡.refl
+ ... | inj₂ w rewrite ≡.sym (splitAt⁻¹-↑ʳ eq) = lemma
+ where
+ open ≡-Reasoning
+ lemma′ : X + Y + Z + W ≡ X + (Y + Z) + W
+ lemma′ = ≡.cong (_+ W) (+-assoc X Y Z)
+ rw : cast lemma′ (X + Y + Z ↑ʳ w) ≡ X + (Y + Z) ↑ʳ w
+ rw = begin
+ cast _ (X + Y + Z ↑ʳ w) ≡⟨ ≡.cong (cast _) (assoc-↑ʳ X Y Z w) ⟩
+ cast (≡.cong (_+ W) (+-assoc X Y Z)) (cast _ (X + (Y + Z) ↑ʳ w)) ≡⟨ cast-involutive (≡.cong (_+ W) (+-assoc X Y Z)) _ (X + (Y + Z) ↑ʳ w) ⟩
+ X + (Y + Z) ↑ʳ w ∎
+ lemma : ((λ [xy]z → _≡_ (cast (+-assoc X Y Z) [xy]z)) +₁ _≡_) (X + Y + Z ↑ʳ w) (cast lemma′ (X + Y + Z ↑ʳ w))
+ lemma rewrite rw = ↑ʳ-REL ≡.refl
+ open ≡-Reasoning
+ eq₂ : cast (+-assoc X (Y + Z) W) (cast _ xyzw) ≡ cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (cast (+-assoc X Y (Z + W)) (cast (+-assoc (X + Y) Z W) xyzw))
+ eq₂ = begin
+ cast _ (cast (≡.cong (_+ W) (+-assoc X Y Z)) xyzw) ≡⟨ cast-trans (≡.cong (_+ W) (+-assoc X Y Z)) (+-assoc X (Y + Z) W) xyzw ⟩
+ cast _ xyzw ≡⟨ cast-trans _ (≡.trans (+-assoc X Y (Z + W)) (≡.cong (X +_) (≡.sym (+-assoc Y Z W)))) xyzw ⟨
+ cast (≡.trans (+-assoc X Y (Z + W)) (≡.cong (X +_) (≡.sym (+-assoc Y Z W)))) (cast (+-assoc (X + Y) Z W) xyzw) ≡⟨ cast-trans (+-assoc X Y (Z + W)) (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (cast (+-assoc (X + Y) Z W) xyzw) ⟨
+ cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (cast (+-assoc X Y (Z + W)) (cast _ xyzw)) ∎
+ arg₁ : Fin (X + (Y + Z + W))
+ arg₁ = cast (≡.cong (X +_) (≡.sym (+-assoc Y Z W))) (cast (+-assoc X Y (Z + W)) (cast (+-assoc (X + Y) Z W) xyzw))
+ arg₂ : Fin (X + (Y + (Z + W)))
+ arg₂ = cast (+-assoc X Y (Z + W)) (cast (+-assoc (X + Y) Z W) xyzw)
+ eq₃ : (_≡_ {A = Fin X} +₁ (λ [yz]w y[zw] → cast (+-assoc Y Z W) [yz]w ≡ y[zw])) arg₁ arg₂
+ eq₃ with splitAt X x[y[zw]] in eq
+ ... | inj₁ x rewrite ≡.sym (splitAt⁻¹-↑ˡ eq) rewrite ≡.sym (↑ˡ-assoc x Y Z W) = ↑ˡ-REL ≡.refl
+ ... | inj₂ yzw rewrite ≡.sym (splitAt⁻¹-↑ʳ eq) rewrite ≡.sym (cast-↑ʳ (≡.sym (+-assoc Y Z W)) X yzw) = ↑ʳ-REL (cast-involutive (+-assoc Y Z W) _ yzw)
+
+ pentagon
+ : ((α⇒ {X} {Y} {Z} +₁ _≡_ {A = Fin W}) ; α⇒ {X}) ; (_≡_ {A = Fin X} +₁ (α⇒ {Y}))
+ ⇔ α⇒ {X + Y} ; α⇒ {X}
+ pentagon = pentˡ , pentʳ
+
+FinRel-Monoidal : Monoidal FinRel
+FinRel-Monoidal = record
+ { ⊗ = ⊗
+ ; unit = 0
+ ; unitorˡ = unitorˡ
+ ; unitorʳ = unitorʳ
+ ; associator = λ {X Y Z} → associator {X} {Y} {Z}
+ ; unitorˡ-commute-from = λ {X} {Y} {R} → unitorˡ-commute-to X Y R
+ ; unitorˡ-commute-to = λ {X} {Y} {R} → unitorˡ-commute-from X Y R
+ ; unitorʳ-commute-from = λ {X} {Y} {R} → unitorʳ-commute-from X Y R
+ ; unitorʳ-commute-to = λ {X} {Y} {R} → unitorʳ-commute-to X Y R
+ ; assoc-commute-from = λ {X Y R X′ Y′ S X″ Y″ T} → assoc-commute-from X Y X′ Y′ X″ Y″ R S T
+ ; assoc-commute-to = λ {X Y R X′ Y′ S X″ Y″ T} → assoc-commute-to X Y X′ Y′ X″ Y″ R S T
+ ; triangle = λ {X Y} → triangle X Y
+ ; pentagon = λ {X Y Z W} → pentagon X Y Z W
+ }