------------------------------------------------------------------------
-- A comparison of the two definitions of bisimilarity
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

module Bisimilarity.Comparison where

open import Equality.Propositional
open import Logical-equivalence using (_⇔_)
open import Prelude hiding (Unit)

open import Bijection equality-with-J as Bijection using (_↔_)
open import Equality.Decision-procedures equality-with-J
open import Fin equality-with-J
open import Function-universe equality-with-J hiding (_∘_; id)
open import H-level equality-with-J as H-level
open import H-level.Closure equality-with-J
open import Nat equality-with-J as Nat
open import Surjection equality-with-J using (_↠_)

import Bisimilarity
import Bisimilarity.Classical
import Bisimilarity.Classical.Equational-reasoning-instances
import Bisimilarity.Equational-reasoning-instances
open import Equational-reasoning
import Indexed-container as IC
open import Labelled-transition-system
open import Relation

module _ {} {lts : LTS } where

  open LTS lts

  private
    module Cl = Bisimilarity.Classical lts
    module Co = Bisimilarity           lts

  -- Classically bisimilar processes are coinductively bisimilar.

  cl⇒co :  {i p q}  p Cl.∼ q  Co.[ i ] p  q
  cl⇒co = IC.gfp⊆ν 

  -- Coinductively bisimilar processes are classically bisimilar.

  co⇒cl :  {p q}  p Co.∼ q  p Cl.∼ q
  co⇒cl = IC.ν⊆gfp 

  -- The function cl⇒co is a left inverse of co⇒cl (up to pointwise
  -- bisimilarity).

  cl⇒co∘co⇒cl :  {i p q}
                (p∼q : p Co.∼ q) 
                Co.[ i ] cl⇒co (co⇒cl p∼q)  p∼q
  cl⇒co∘co⇒cl p∼q = IC.gfp⊆ν∘ν⊆gfp  p∼q

  -- If there are two processes that are not equal, but bisimilar,
  -- then co⇒cl is not a left inverse of cl⇒co.

  co⇒cl∘cl⇒co :  {p q} 
                p  q  p Co.∼ q 
                 λ (p∼p : p Cl.∼ p)  co⇒cl (cl⇒co p∼p)  p∼p
  co⇒cl∘cl⇒co {p} {q} p≢q p∼q =
      reflexive

    , (co⇒cl (cl⇒co reflexive)  reflexive  ↝⟨ cong  R  proj₁ R (p , q)) 
        _ (p Co.∼ q)   _ (p  q)         ↝⟨  eq  ≡⇒↝ _ eq $ lift p∼q) 
        _ (p  q)                          ↔⟨ Bijection.↑↔ 
       p  q                                ↝⟨ p≢q ⟩□
                                           )

  -- The two definitions of bisimilarity are logically equivalent.

  classical⇔coinductive :  {p q}  p Cl.∼ q  p Co.∼ q
  classical⇔coinductive = IC.gfp⇔ν 

  -- There is a split surjection from the classical definition of
  -- bisimilarity to the coinductive one (assuming two kinds of
  -- extensionality).

  classical↠coinductive :
    Extensionality   
    Co.Extensionality 
     {p q}  p Cl.∼ q  p Co.∼ q
  classical↠coinductive ext co-ext = IC.gfp↠ν ext  co-ext

-- There is at least one LTS for which there is a split surjection
-- from the coinductive definition of bisimilarity to the classical
-- one.

coinductive↠classical :
   {p q} 
  Bisimilarity._∼_           empty p q 
  Bisimilarity.Classical._∼_ empty p q
coinductive↠classical {p = ()}

-- There is an LTS for which coinductive bisimilarity is pointwise
-- propositional (assuming two kinds of extensionality).

coinductive-bisimilarity-is-sometimes-propositional :
  Extensionality lzero lzero 
  let module Co = Bisimilarity one-loop in
  Co.Extensionality  Is-proposition (tt Co.∼ tt)
coinductive-bisimilarity-is-sometimes-propositional ext co-ext =
  _⇔_.from propositional⇔irrelevant λ ∼₁ ∼₂ 
    extensionality ext co-ext (irr ∼₁ ∼₂)
  where
  open Bisimilarity one-loop

  irr :  {i} ∼₁ ∼₂  [ i ] ∼₁  ∼₂
  irr ∼₁ ∼₂ =
    Bisimilarity-of-∼.⟨ ext
                      , ∼₁
                      , ∼₂
                      ,  _  refl , refl , irr′ (proj₂ ∼₁ _)
                                                  (proj₂ ∼₂ _))
                      ,  _  refl , refl , irr′ (proj₂ ∼₁ _)
                                                  (proj₂ ∼₂ _))
                      
    where
    irr′ :  {i} ∼₁ ∼₂  [ i ] ∼₁ ≡′ ∼₂
    force (irr′ ∼₁ ∼₂) = irr (force ∼₁) (force ∼₂)

-- However, classical bisimilarity (of any size) is, for the same LTS,
-- not pointwise propositional.

classical-bisimilarity-is-not-propositional :
  let module Cl = Bisimilarity.Classical one-loop in
   {}  ¬ Is-proposition (Cl.Bisimilarity′  (tt , tt))
classical-bisimilarity-is-not-propositional {} =
  Is-proposition (Bisimilarity′  (tt , tt))    ↝⟨  is-prop  _⇔_.to propositional⇔irrelevant is-prop) 
  Proof-irrelevant (Bisimilarity′  (tt , tt))  ↝⟨  f  f tt∼tt₁ tt∼tt₂) 
  tt∼tt₁  tt∼tt₂                               ↝⟨ cong  R  proj₁ R (tt , tt)) {x = tt∼tt₁} {y = tt∼tt₂} 
  Unit  (Unit  Unit)                          ↝⟨  eq  Fin 1          ↝⟨ inverse Unit↔Fin1 
                                                           Unit           ↝⟨ ≡⇒↝ _ eq 
                                                           Unit  Unit    ↝⟨ Unit↔Fin1 ⊎-cong Unit↔Fin1 
                                                           Fin 1  Fin 1  ↝⟨ Fin⊎Fin↔Fin+ 1 1 ⟩□
                                                           Fin 2          ) 
  Fin 1  Fin 2                                 ↝⟨ _⇔_.to isomorphic-same-size 
  1  2                                         ↝⟨ from-⊎ (1 Nat.≟ 2) ⟩□
                                               
  where
  open Bisimilarity.Classical one-loop

  tt∼tt₁ : Bisimilarity′  (tt , tt)
  tt∼tt₁ = reflexive-∼′ _

  tt∼tt₂ : Bisimilarity′  (tt , tt)
  tt∼tt₂ =
    let R , R-is-a-bisimulation , ttRtt =
          _⇔_.to (Bisimilarity′↔ _ _) tt∼tt₁ in
    _⇔_.from (Bisimilarity′↔ _ _)
      ( (R  R)
      , ×2-preserves-bisimulations R-is-a-bisimulation
      , inj₁ ttRtt
      )

  Unit =   (tt  tt)

  Unit↔Fin1 =
    Unit     ↔⟨ Bijection.↑↔ 
    tt  tt  ↝⟨ _⇔_.to contractible⇔↔⊤ (mono₁ 0 ⊤-contractible _ _) 
            ↝⟨ inverse ⊎-right-identity ⟩□
    Fin 1    

-- Thus, assuming two kinds of extensionality, there is in general no
-- split surjection from the coinductive definition of bisimilarity to
-- the classical one (of any size).

¬coinductive↠classical :
  Extensionality lzero lzero 
  Bisimilarity.Extensionality one-loop 
   {} 
  ¬ (∀ {p q}  Bisimilarity._∼_                     one-loop    p   q 
               Bisimilarity.Classical.Bisimilarity′ one-loop  (p , q))
¬coinductive↠classical ext co-ext {} =
  (∀ {p q}  p Co.∼ q  Cl.Bisimilarity′  (p , q))  ↝⟨  co↠cl  co↠cl {q = _}) 

  tt Co.∼ tt  Cl.Bisimilarity′  (tt , tt)          ↝⟨  co↠cl  H-level.respects-surjection co↠cl 1) 

  (Is-proposition (tt Co.∼ tt) 
   Is-proposition (Cl.Bisimilarity′  (tt , tt)))    ↝⟨ (_$ coinductive-bisimilarity-is-sometimes-propositional ext co-ext) 

  Is-proposition (Cl.Bisimilarity′  (tt , tt))      ↝⟨ classical-bisimilarity-is-not-propositional ⟩□

                                                    
  where
  module Cl = Bisimilarity.Classical one-loop
  module Co = Bisimilarity           one-loop

-- Note also that coinductive bisimilarity is not always
-- propositional.

coinductive-bisimilarity-is-not-propositional :
  let open Bisimilarity two-bisimilar-processes in
  ¬ (∀ {p q}  Is-proposition (p  q))
coinductive-bisimilarity-is-not-propositional =
  (∀ {p q}  Is-proposition (p  q))            ↝⟨  is-prop  is-prop {p = true} {q = true}) 
  Is-proposition (true  true)                  ↝⟨ _⇔_.to propositional⇔irrelevant 
  Proof-irrelevant (true  true)                ↝⟨  irr  irr _ _) 
  proof true true true  proof false true true  ↝⟨ cong  p  proj₁ (left-to-right {p = true} {q = true} p {p′ = true} _)) 
  true  false                                  ↝⟨ Bool.true≢false ⟩□
                                               
  where
  open Bisimilarity two-bisimilar-processes

  open import Indexed-container

  mutual
    proof : Bool   b₁ b₂ {i}  [ i ] b₁  b₂
    proof b b₁ b₂ =
      ⟨_,_⟩ {p = b₁} {q = b₂}
         _  b , _ , proof′ b _ _)
         _  b , _ , proof′ b _ _)

    proof′ : Bool   b₁ b₂ {i}  [ i ] b₁ ∼′ b₂
    force (proof′ b b₁ b₂) = proof b b₁ b₂

-- In fact, for every type A there is a pointwise split surjection
-- from a certain instance of bisimilarity (of any size) to equality
-- on A.

bisimilarity↠equality :
   {a} {A : Set a} 
  let open Bisimilarity (bisimilarity⇔equality A) in
   {i} {p q : A}  ([ i ] p  q)  p  q
bisimilarity↠equality {A = A} {i} = record
  { logical-equivalence = record
    { to   = to
    ; from = from
    }
  ; right-inverse-of = to∘from
  }
  where
  open Bisimilarity (bisimilarity⇔equality A)

  to :  {p q}  [ i ] p  q  p  q
  to p∼q with left-to-right p∼q (refl , refl)
  ... | _ , (refl , _) , _ = refl

  from :  {p q}  p  q  [ i ] p  q
  from refl = reflexive

  to∘from :  {p q} (p≡q : p  q)  to (from p≡q)  p≡q
  to∘from refl = refl