open import Level
open import Categories.Category.Core
open import Data.Product using (_,_; Σ; Σ-syntax)
open import Categories.Functor hiding (id)
open import Categories.Functor.Algebra
open import Categories.Functor.Coalgebra
open import Categories.Object.Terminal
open import Categories.NaturalTransformation.Core hiding (id)
open import Categories.Category.Distributive
open import Categories.Object.NaturalNumbers.Parametrized
open import Monad.Helper
open import Monad.Instance.Delay
import Categories.Morphism as M
import Categories.Morphism.Reasoning as MR
module Monad.Instance.Delay.Quotient {o ℓ e} {C : Category o ℓ e} (distributive : Distributive C) (DM : DelayM (Distributive.cocartesian distributive)) (PNNO : ParametrizedNNO C (Distributive.cartesian distributive)) where
open import Category.Distributive.Helper distributive
open Bundles
open Category C
open import Categories.Diagram.Coequalizer C
open import Algebra.Search cocartesian
open import Algebra.Elgot cocartesian
open F-Coalgebra-Morphism using () renaming (f to u; commutes to coalg-commutes)
preserves : ∀ {X Y} {f g : X ⇒ Y} → Endofunctor C → Coequalizer f g → Set (o ⊔ ℓ ⊔ e)
preserves {X} {Y} {f} {g} F coeq = IsCoequalizer (Functor.₁ F f) (Functor.₁ F g) (Functor.₁ F (Coequalizer.arr coeq))
open DelayM DM
open import Monad.Instance.Delay.Iota distributive DM PNNO
open ParametrizedNNO PNNO
open D-Monad
open D-Kleisli
open Later∘Extend
open Coit
open HomReasoning
open M C
open MR C
open Equiv
record DelayQ : Set (o ⊔ ℓ ⊔ e) where
field
coeqs : ∀ X → Coequalizer (extend (ι {X})) (D₁ π₁)
Ď₀ : Obj → Obj
Ď₀ X = Coequalizer.obj (coeqs X)
ρ : ∀ {X} → D₀ X ⇒ Ď₀ X
ρ {X} = Coequalizer.arr (coeqs X)
field
coeq-productsˡ : ∀ {X Y} (f : Y ⇒ Y) → IsCoequalizer (extend (ι {X}) ⁂ f) (D₁ π₁ ⁂ f) (ρ {X} ⁂ f)
coeq-productsᵐ : ∀ {X Y Z} → IsCoequalizer (id {X} ⁂ (extend (ι {Y}) ⁂ id {Z})) (id {X} ⁂ (D₁ (π₁ {Y} {N}) ⁂ id {Z})) (id {X} ⁂ (ρ {Y} ⁂ id {Z}))
abstract
coeq-productsʳ : ∀ {X Y} (f : Y ⇒ Y) → IsCoequalizer (f ⁂ extend (ι {X})) (f ⁂ D₁ π₁) (f ⁂ ρ {X})
coeq-productsʳ {X} {Y} f = record
{ equality = begin
(f ⁂ ρ) ∘ (f ⁂ extend ι) ≈⟨ ⁂∘⁂ ⟩
f ∘ f ⁂ ρ ∘ extend ι ≈⟨ ⁂-cong₂ refl c-equality ⟩
f ∘ f ⁂ ρ ∘ D₁ π₁ ≈˘⟨ ⁂∘⁂ ⟩
(f ⁂ ρ) ∘ (f ⁂ D₁ π₁) ∎
; coequalize = λ {Z} {h} eq → p-coequalize {h = h ∘ swap} (eq-to-swap eq) ∘ swap
; universal = λ {Z} {h} {eq} → begin
h ≈⟨ introʳ swap∘swap ⟩
h ∘ swap ∘ swap ≈⟨ extendʳ (p-universal {h = h ∘ swap} {eq = eq-to-swap eq}) ⟩
p-coequalize (eq-to-swap eq) ∘ (ρ ⁂ f) ∘ swap ≈˘⟨ pullʳ swap∘⁂ ⟩
(p-coequalize (eq-to-swap eq) ∘ swap) ∘ (f ⁂ ρ) ∎
; unique = λ {Z} {h} {i} {eqh} universal-i → begin
i ≈⟨ introʳ swap∘swap ⟩
i ∘ swap ∘ swap ≈⟨ pullˡ (p-unique (universal-swap universal-i)) ⟩
p-coequalize (eq-to-swap eqh) ∘ swap ∎
}
where
open Coequalizer (coeqs X) using () renaming (equality to c-equality)
open IsCoequalizer (coeq-productsˡ {X} {Y} f) using () renaming (coequalize to p-coequalize; universal to p-universal; unique to p-unique)
universal-swap : ∀ {Z} {h : Y × D₀ X ⇒ Z} {i : Y × Ď₀ X ⇒ Z} → h ≈ i ∘ (f ⁂ ρ) → h ∘ swap ≈ (i ∘ swap) ∘ (ρ ⁂ f)
universal-swap {Z} {h} {i} eq = begin
h ∘ swap ≈⟨ eq ⟩∘⟨refl ⟩
(i ∘ (f ⁂ ρ)) ∘ swap ≈˘⟨ extendˡ swap∘⁂ ⟩
(i ∘ swap) ∘ (ρ ⁂ f) ∎
eq-to-swap : ∀ {Z} {h : Y × D₀ X ⇒ Z} → h ∘ (f ⁂ extend ι) ≈ h ∘ (f ⁂ D₁ π₁) → (h ∘ swap) ∘ (extend ι ⁂ f) ≈ (h ∘ swap) ∘ (D₁ π₁ ⁂ f)
eq-to-swap {Z} {h} eq = begin
(h ∘ swap) ∘ (extend ι ⁂ f) ≈⟨ pullʳ swap∘⁂ ⟩
h ∘ (f ⁂ extend ι) ∘ swap ≈⟨ extendʳ eq ⟩
h ∘ (f ⁂ D₁ π₁) ∘ swap ≈˘⟨ pullʳ swap∘⁂ ⟩
(h ∘ swap) ∘ (D₁ π₁ ⁂ f) ∎
ρ-epi : ∀ {X} → Epi (ρ {X})
ρ-epi {X} = Coequalizer⇒Epi (coeqs X)
ρ-later : ∀ {X} → ρ ∘ later ≈ ρ {X}
ρ-later {X} = sym (begin
ρ ≈⟨ introʳ intro-helper ⟩
ρ ∘ D₁ π₁ ∘ D₁ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈⟨ pullˡ (sym equality) ⟩
(ρ ∘ extend ι) ∘ D₁ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈⟨ pullʳ (sym DK.assoc) ⟩
ρ ∘ extend (extend ι ∘ now ∘ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩) ≈⟨ (refl⟩∘⟨ extend-≈ (pullˡ DK.identityʳ)) ⟩
ρ ∘ extend (ι ∘ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩) ≈⟨ (refl⟩∘⟨ extend-≈ helper) ⟩
ρ ∘ extend (later ∘ now) ≈⟨ (refl⟩∘⟨ sym (extend∘later now)) ⟩
ρ ∘ extend now ∘ later ≈⟨ elim-center DK.identityˡ ⟩
ρ ∘ later ∎)
where
open Coequalizer (coeqs X) using (equality; coequalize; id-coequalize; coequalize-resp-≈) renaming (universal to coeq-universal; unique to coeq-unique; unique′ to coeq-unique′)
intro-helper : D₁ π₁ ∘ D₁ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈ id
intro-helper = sym D.F.homomorphism ○ D.F.F-resp-≈ project₁ ○ D.F.identity
helper : ι ∘ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈ later ∘ now
helper = begin
ι ∘ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈⟨ introˡ out⁻¹∘out ⟩
(out⁻¹ ∘ out) ∘ ι ∘ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈⟨ pullʳ (pullˡ ι-commutes) ⟩
out⁻¹ ∘ ((id +₁ ι) ∘ _≅_.from nno-iso) ∘ ⟨ id , s ∘ z ∘ Terminal.! terminal ⟩ ≈⟨ (refl⟩∘⟨ refl⟩∘⟨ sym (⁂∘⟨⟩ ○ ⟨⟩-cong₂ identity² refl)) ⟩
out⁻¹ ∘ ((id +₁ ι) ∘ _≅_.from nno-iso) ∘ (id ⁂ s) ∘ ⟨ id , z ∘ Terminal.! terminal ⟩ ≈⟨ (refl⟩∘⟨ refl⟩∘⟨ sym inject₂ ⟩∘⟨refl) ⟩
out⁻¹ ∘ ((id +₁ ι) ∘ _≅_.from nno-iso) ∘ (_≅_.to nno-iso ∘ i₂) ∘ ⟨ id , z ∘ Terminal.! terminal ⟩ ≈⟨ (refl⟩∘⟨ (pullʳ (pullˡ (cancelˡ (_≅_.isoʳ nno-iso))))) ⟩
out⁻¹ ∘ (id +₁ ι) ∘ i₂ ∘ ⟨ id , z ∘ Terminal.! terminal ⟩ ≈⟨ (refl⟩∘⟨ pullˡ +₁∘i₂) ⟩
out⁻¹ ∘ (i₂ ∘ ι) ∘ ⟨ id , z ∘ Terminal.! terminal ⟩ ≈⟨ (refl⟩∘⟨ refl⟩∘⟨ sym inject₁) ⟩
out⁻¹ ∘ (i₂ ∘ ι) ∘ _≅_.to nno-iso ∘ i₁ ≈⟨ (refl⟩∘⟨ intro-center out⁻¹∘out ⟩∘⟨refl) ⟩
out⁻¹ ∘ (i₂ ∘ (out⁻¹ ∘ out) ∘ ι) ∘ _≅_.to nno-iso ∘ i₁ ≈⟨ (refl⟩∘⟨ (refl⟩∘⟨ pullʳ ι-commutes) ⟩∘⟨refl) ⟩
out⁻¹ ∘ (i₂ ∘ out⁻¹ ∘ (id +₁ ι) ∘ _≅_.from nno-iso) ∘ _≅_.to nno-iso ∘ i₁ ≈⟨ (refl⟩∘⟨ (pullʳ (pullˡ (pullʳ (cancelʳ (_≅_.isoʳ nno-iso)))))) ⟩
out⁻¹ ∘ i₂ ∘ (out⁻¹ ∘ (id +₁ ι)) ∘ i₁ ≈⟨ (refl⟩∘⟨ refl⟩∘⟨ pullʳ +₁∘i₁) ⟩
out⁻¹ ∘ i₂ ∘ out⁻¹ ∘ i₁ ∘ id ≈⟨ (refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ identityʳ) ⟩
out⁻¹ ∘ i₂ ∘ out⁻¹ ∘ i₁ ≈⟨ ((refl⟩∘⟨ sym-assoc) ○ assoc²δγ) ⟩
later ∘ now ∎
ρ-earlier : ∀ {X} → ρ ∘ earlier ≈ ρ {X}
ρ-earlier {X} = D-jointly-epic (pullʳ earlier∘now) (pullʳ earlier∘later ○ identityʳ ○ sym ρ-later)
open IsCoequalizer
open Coequalizer using (isCoequalizer)
private
bisim-implies : ∀ {X Y} (h : D₀ X ⇒ Y) → (h ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ]) ≈ h ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ])) → (h ∘ extend ι ≈ h ∘ D₁ π₁)
bisim-implies {X} {Y} h eq = sym equality₁ ○ extendʳ (sym eq) ○ equality₂
where
h∘later≈h : h ≈ h ∘ later
h∘later≈h = begin
h ≈⟨ introʳ (extend∘F₁' kleisli _ _ ○ extend-≈ (pullˡ inject₂ ○ (extendʳ inject₂ ○ elimʳ project₁)) ○ DK.identityˡ) ⟩
h ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ]) ∘ D₁ (i₂ ∘ i₂ ∘ ⟨ id , z ∘ Terminal.! terminal ⟩) ≈⟨ extendʳ eq ⟩
h ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ]) ∘ D₁ (i₂ ∘ i₂ ∘ ⟨ id , z ∘ Terminal.! terminal ⟩) ≈⟨ refl⟩∘⟨ ((extend∘F₁' kleisli _ _) ○ extend-≈ (pullˡ inject₂ ○ (extendʳ inject₂))) ⟩
h ∘ extend (ι ∘ (id ⁂ s) ∘ ⟨ id , z ∘ Terminal.! terminal ⟩) ≈⟨ (refl⟩∘⟨ (extend-≈ (extendʳ ι-succ))) ⟩
h ∘ extend (later ∘ ι ∘ ⟨ id , z ∘ Terminal.! terminal ⟩) ≈⟨ (refl⟩∘⟨ (extend-≈ (refl⟩∘⟨ ι-zero))) ⟩
h ∘ extend (later ∘ now) ≈⟨ (refl⟩∘⟨ (sym (later∘extend now))) ⟩
h ∘ later ∘ extend now ≈⟨ refl⟩∘⟨ elimʳ DK.identityˡ ⟩
h ∘ later ∎
equality₁ : h ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ]) ∘ D₁ (i₂ ∘ i₂) ≈ h ∘ extend ι
equality₁ = begin
h ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ]) ∘ D₁ (i₂ ∘ i₂) ≈⟨ (refl⟩∘⟨ (extend∘F₁' kleisli _ _)) ⟩
h ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ] ∘ i₂ ∘ i₂) ≈⟨ (refl⟩∘⟨ (extend-≈ (pullˡ inject₂))) ⟩
h ∘ extend ([ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ∘ i₂) ≈⟨ (refl⟩∘⟨ (extend-≈ inject₂)) ⟩
h ∘ extend (ι ∘ (id ⁂ s)) ≈⟨ (refl⟩∘⟨ (extend-≈ ι-succ)) ⟩
h ∘ extend (later ∘ ι) ≈⟨ (refl⟩∘⟨ (sym (later∘extend ι))) ⟩
h ∘ later ∘ extend ι ≈⟨ pullˡ (sym h∘later≈h) ⟩
h ∘ extend ι ∎
equality₂ : h ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ]) ∘ D₁ (i₂ ∘ i₂) ≈ h ∘ D₁ π₁
equality₂ = begin
h ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ]) ∘ D₁ (i₂ ∘ i₂) ≈⟨ (refl⟩∘⟨ extend∘F₁' kleisli _ _) ⟩
h ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ] ∘ i₂ ∘ i₂) ≈⟨ (refl⟩∘⟨ (extend-≈ (pullˡ inject₂))) ⟩
h ∘ extend ([ ι ∘ (id ⁂ s) , now ∘ π₁ ] ∘ i₂) ≈⟨ (refl⟩∘⟨ (extend-≈ inject₂)) ⟩
h ∘ extend (now ∘ π₁) ∎
bisimilarityCoeq : ∀ {X} → IsCoequalizer {A = D₀ (X + ((X × N) + (X × N)))} {B = D₀ X} {E = Ď₀ X} (extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ])) (extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ])) ρ
bisimilarityCoeq {X} .equality = equality₁ ○ sym equality₂
where
open Terminal terminal using (!)
equality₁ : ρ ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ]) ≈ ρ ∘ extend ([ now , [ now ∘ π₁ , now ∘ π₁ ] ])
equality₁ = begin
ρ ∘ extend ([ now , [ ι ∘ (id ⁂ s) , now ∘ π₁ ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ ι-zero ([]-cong₂ refl (pullˡ ι-zero))))) ⟩
ρ ∘ extend ([ ι ∘ ⟨ id , z ∘ ! ⟩ , [ ι ∘ (id ⁂ s) , ι ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ (pullˡ DK.identityʳ) ([]-cong₂ (pullˡ DK.identityʳ) (pullˡ DK.identityʳ))))) ⟩
ρ ∘ extend ([ extend ι ∘ now ∘ ⟨ id , z ∘ ! ⟩ , [ extend ι ∘ now ∘ (id ⁂ s) , extend ι ∘ now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ (∘[] ○ []-cong₂ refl ∘[]))) ⟩
ρ ∘ extend (extend ι ∘ [ now ∘ ⟨ id , z ∘ ! ⟩ , [ now ∘ (id ⁂ s) , now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈⟨ refl⟩∘⟨ DK.assoc ⟩
ρ ∘ extend ι ∘ extend ([ now ∘ ⟨ id , z ∘ ! ⟩ , [ now ∘ (id ⁂ s) , now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈⟨ extendʳ (Coequalizer.equality (coeqs X)) ⟩
ρ ∘ D₁ π₁ ∘ extend ([ now ∘ ⟨ id , z ∘ ! ⟩ , [ now ∘ (id ⁂ s) , now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈⟨ refl⟩∘⟨ F₁∘extend' kleisli π₁ _ ⟩
ρ ∘ extend (D₁ π₁ ∘ [ now ∘ ⟨ id , z ∘ ! ⟩ , [ now ∘ (id ⁂ s) , now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈⟨ (refl⟩∘⟨ extend-≈ (∘[] ○ []-cong₂ refl ∘[])) ⟩
ρ ∘ extend ([ D₁ π₁ ∘ now ∘ ⟨ id , z ∘ ! ⟩ , [ D₁ π₁ ∘ now ∘ (id ⁂ s) , D₁ π₁ ∘ now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈⟨ (refl⟩∘⟨ extend-≈ ([]-cong₂ (extendʳ (sym (D.η.commute π₁))) ([]-cong₂ (extendʳ (sym (D.η.commute π₁))) (extendʳ (sym (D.η.commute π₁)))))) ⟩
ρ ∘ extend ([ now ∘ π₁ ∘ ⟨ id , z ∘ ! ⟩ , [ now ∘ π₁ ∘ (id ⁂ s) , now ∘ π₁ ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ ] ]) ≈⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ (elimʳ project₁) ([]-cong₂ (refl⟩∘⟨ (project₁ ○ identityˡ)) (refl⟩∘⟨ (cancelˡ project₁)))))) ⟩
ρ ∘ extend ([ now , [ now ∘ π₁ , now ∘ π₁ ] ]) ∎
equality₂ : ρ ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ]) ≈ ρ ∘ extend ([ now , [ now ∘ π₁ , now ∘ π₁ ] ])
equality₂ = begin
ρ ∘ extend ([ now , [ (now ∘ π₁) , (ι ∘ (id ⁂ s)) ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ ι-zero ([]-cong₂ (pullˡ ι-zero) refl)))) ⟩
ρ ∘ extend ([ ι ∘ ⟨ id , z ∘ ! ⟩ , [ ι ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁ , ι ∘ (id ⁂ s) ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ (pullˡ DK.identityʳ) ([]-cong₂ (pullˡ DK.identityʳ) (pullˡ DK.identityʳ))))) ⟩
ρ ∘ extend ([ extend ι ∘ (now ∘ ⟨ id , z ∘ ! ⟩) , [ extend ι ∘ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , extend ι ∘ now ∘ (id ⁂ s) ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ refl ∘[]))) ⟩
ρ ∘ extend ([ extend ι ∘ (now ∘ ⟨ id , z ∘ ! ⟩) , extend ι ∘ [ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , now ∘ (id ⁂ s) ] ]) ≈˘⟨ (refl⟩∘⟨ (extend-≈ ∘[])) ⟩
ρ ∘ extend (extend ι ∘ [ now ∘ ⟨ id , z ∘ ! ⟩ , [ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , now ∘ (id ⁂ s) ] ]) ≈⟨ refl⟩∘⟨ DK.assoc ⟩
ρ ∘ extend ι ∘ extend ([ now ∘ ⟨ id , z ∘ ! ⟩ , [ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , now ∘ (id ⁂ s) ] ]) ≈⟨ extendʳ (Coequalizer.equality (coeqs X)) ⟩
ρ ∘ D₁ π₁ ∘ extend ([ now ∘ ⟨ id , z ∘ ! ⟩ , [ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , now ∘ (id ⁂ s) ] ]) ≈⟨ (refl⟩∘⟨ F₁∘extend' kleisli π₁ _) ⟩
ρ ∘ extend (D₁ π₁ ∘ [ now ∘ ⟨ id , z ∘ ! ⟩ , [ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , now ∘ (id ⁂ s) ] ]) ≈⟨ (refl⟩∘⟨ (extend-≈ ∘[])) ⟩
ρ ∘ extend ([ D₁ π₁ ∘ (now ∘ ⟨ id , z ∘ ! ⟩) , D₁ π₁ ∘ [ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , now ∘ (id ⁂ s) ] ]) ≈⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ refl ∘[]))) ⟩
ρ ∘ extend ([ D₁ π₁ ∘ (now ∘ ⟨ id , z ∘ ! ⟩) , [ D₁ π₁ ∘ (now ∘ ⟨ id , z ∘ ! ⟩ ∘ π₁) , D₁ π₁ ∘ (now ∘ (id ⁂ s)) ] ]) ≈⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ (pullˡ (sym (D.η.commute π₁))) ([]-cong₂ (pullˡ (sym (D.η.commute π₁))) (pullˡ (sym (D.η.commute π₁))))))) ⟩
ρ ∘ extend ([ (now ∘ π₁) ∘ ⟨ id , z ∘ ! ⟩ , [ (now ∘ π₁) ∘ (⟨ id , z ∘ ! ⟩ ∘ π₁) , (now ∘ π₁) ∘ (id ⁂ s) ] ]) ≈⟨ (refl⟩∘⟨ (extend-≈ ([]-cong₂ (cancelʳ project₁) ([]-cong₂ (pullʳ (cancelˡ project₁)) (pullʳ (project₁ ○ identityˡ)))))) ⟩
ρ ∘ extend ([ now , [ now ∘ π₁ , now ∘ π₁ ] ]) ∎
bisimilarityCoeq {X} .coequalize {Y} {h} eq = coequalize (isCoequalizer (coeqs X)) {Y} {h} (bisim-implies h eq)
bisimilarityCoeq {X} .universal {Y} {h} {h∘f≈h∘g} = universal (isCoequalizer (coeqs X))
bisimilarityCoeq {X} .unique = unique (isCoequalizer (coeqs X))
Ď-Functor : Endofunctor C
Ď-Functor = record
{ F₀ = Ď₀
; F₁ = F₁'
; identity = λ {X} → Coequalizer.coequalize-resp-≈ (coeqs X) (elimʳ D.F.identity) ○ sym (Coequalizer.id-coequalize (coeqs X))
; homomorphism = λ {X} {Y} {Z} {f} {g} → sym (Coequalizer.unique (coeqs X) (sym (begin
(F₁' g ∘ F₁' f) ∘ ρ ≈⟨ pullʳ (sym (Coequalizer.universal (coeqs X))) ⟩
F₁' g ∘ ρ ∘ D₁ f ≈⟨ pullˡ (sym (Coequalizer.universal (coeqs Y))) ⟩
(ρ ∘ D₁ g) ∘ D₁ f ≈⟨ pullʳ (sym D.F.homomorphism) ⟩
ρ ∘ D₁ (g ∘ f) ∎)))
; F-resp-≈ = λ {X} {Y} {f} {g} eq → Coequalizer.coequalize-resp-≈ (coeqs X) (refl⟩∘⟨ (D.F.F-resp-≈ eq))
}
where
F₁' : ∀ {X} {Y} (f : X ⇒ Y) → Ď₀ X ⇒ Ď₀ Y
F₁' {X} {Y} f = Coequalizer.coequalize (coeqs X) {h = ρ ∘ D₁ f} (begin
(ρ ∘ D₁ f) ∘ extend ι ≈⟨ pullʳ (sym DK.assoc) ⟩
ρ ∘ extend (D₁ f ∘ ι) ≈˘⟨ (refl⟩∘⟨ (DK.extend-≈ (ι-natural f))) ⟩
ρ ∘ extend (ι ∘ (f ⁂ id)) ≈⟨ (refl⟩∘⟨ extend-≈ (pushˡ (sym DK.identityʳ))) ⟩
ρ ∘ extend (extend ι ∘ now ∘ (f ⁂ id)) ≈⟨ pushʳ DK.assoc ⟩
(ρ ∘ extend ι) ∘ D₁ (f ⁂ id) ≈⟨ pushˡ (Coequalizer.equality (coeqs Y)) ⟩
ρ ∘ D₁ π₁ ∘ D₁ (f ⁂ id) ≈⟨ refl⟩∘⟨ sym D.F.homomorphism ⟩
ρ ∘ D₁ (π₁ ∘ (f ⁂ id)) ≈⟨ (refl⟩∘⟨ (D.F.F-resp-≈ project₁)) ⟩
ρ ∘ D₁ (f ∘ π₁) ≈⟨ pushʳ D.F.homomorphism ⟩
(ρ ∘ D₁ f) ∘ D₁ π₁ ∎)
ρ-natural : NaturalTransformation D.F Ď-Functor
ρ-natural = ntHelper (record
{ η = λ X → ρ {X}
; commute = λ {X} {Y} f → Coequalizer.universal (coeqs X)
})