----------------------------------------------------------------------------------------------------
-- Transitive and reflexive-transitive closures
----------------------------------------------------------------------------------------------------

{-# OPTIONS --cubical --safe #-}
module Relation.Closure where

open import Cubical.Foundations.Prelude
open import Cubical.Induction.WellFounded
  renaming (WellFounded to isWellFounded)

open import PropTrunc

module _ { ℓ' : Level}{A : Type }(_≺_ : A -> A -> Type ℓ') where

  data TransCl : A  A  Type (ℓ-max  ℓ') where
    emb :  {x y : A}  x  y  TransCl x y
    step :  {x y z : A}  x  y  TransCl y z  TransCl x z

  data ReflTransCl : A  A  Type (ℓ-max  ℓ') where
    done :  {x : A}  ReflTransCl x x
    step :  {x y z : A}  x  y  ReflTransCl y z  ReflTransCl x z

  Trans→ReflTrans :  {x y}  TransCl x y  ReflTransCl x y
  Trans→ReflTrans (emb x<y) = step x<y done
  Trans→ReflTrans (step x<y p) = step x<y (Trans→ReflTrans p)

  TransCl-trans :  {x y z}  TransCl x y  TransCl y z  TransCl x z
  TransCl-trans (emb x) q = step x q
  TransCl-trans (step x p) q = step x (TransCl-trans p q)

  ReflTransCl-trans :  {x y z}  ReflTransCl x y  ReflTransCl y z  ReflTransCl x z
  ReflTransCl-trans done q = q
  ReflTransCl-trans (step x p) q = step x (ReflTransCl-trans p q)

  ReflTransTransCl-trans :  {x y z}  ReflTransCl x y  TransCl y z  TransCl x z
  ReflTransTransCl-trans done qs = qs
  ReflTransTransCl-trans (step p ps) qs = step p (ReflTransTransCl-trans ps qs)

  embRT :  {x y : A}  x  y  ReflTransCl x y
  embRT p = step p done

  stepT :  {x y z : A}  x  y  ReflTransCl y z  TransCl x z
  stepT x<y done = emb x<y
  stepT x<y (step y<y' y'<*z) = step x<y (stepT y<y' y'<*z)

  TransClWellfounded : isWellFounded _≺_  isWellFounded TransCl
  TransClWellfounded wf x = lemma x (wf x)
    where
      lemma : (y : A)  Acc _≺_ y  Acc TransCl y
      lemma y (acc s) = acc g where
        g : (z : A)  TransCl z y  Acc TransCl z
        g z (emb p) = lemma z (s z p)
        g z (step p ps) = access (g _ ps) z (emb p)

∥∥-wellfounded :  { ℓ'}  {A : Type }{_≺_ : A -> A -> Type ℓ'} 
                isWellFounded _≺_  isWellFounded  x y   x  y )
∥∥-wellfounded {_≺_ = _≺_} wf x = lemma x (wf x)
  where
    lemma :  x  Acc _≺_ x  Acc  x y   x  y ) x
    lemma x (acc s) = acc λ y  ∥-∥rec (isPropAcc y) λ y<x  lemma y (s y y<x)

∥TransCl∥-wellfounded :  { ℓ'}  {A : Type }{_≺_ : A -> A -> Type ℓ'} 
                       isWellFounded _≺_  isWellFounded  x y   TransCl _≺_ x y )
∥TransCl∥-wellfounded wf = ∥∥-wellfounded (TransClWellfounded _ wf)

TransCl-map :  { ℓ'}  {A : Type }{B : Type ℓ'} 
              {_<A_ : A -> A -> Type }  {_<B_ : B -> B -> Type ℓ'} 
              (f : A  B)  ({x y : A}  x <A y  f x <B f y) 
              {x y : A}  TransCl _<A_ x y  TransCl _<B_ (f x) (f y)
TransCl-map f g (emb p) = emb (g p)
TransCl-map f g (step p ps) = step (g p) (TransCl-map f g ps)

ReflTransCl-map :  { ℓ'}  {A : Type }{B : Type ℓ'} 
              {_<A_ : A -> A -> Type }  {_<B_ : B -> B -> Type ℓ'} 
              (f : A  B)  ({x y : A}  x <A y  f x <B f y) 
              {x y : A}  ReflTransCl _<A_ x y  ReflTransCl _<B_ (f x) (f y)
ReflTransCl-map f g done = done
ReflTransCl-map f g (step p ps) = step (g p) (ReflTransCl-map f g ps)