open import Cubical.Foundations.Prelude

module DCPO.Base (ℓi : Level) where

open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Structure
open import Cubical.Foundations.Transport

open import Cubical.Data.Bool
open import Cubical.Data.Sigma

open import Cubical.HITs.PropositionalTruncation as ∥₁

open import Cubical.Relation.Binary.Base
open import Cubical.Relation.Binary.Order.Poset

open import Cubical.Reflection.RecordEquiv

open BinaryRelation

private
  variable
    ℓd ℓt ℓe ℓt' ℓf ℓt'' : Level

module _ {D : Type ℓd} (_⊑_ : D  D  Type ℓt) where

  isSemidirected : {I : Type ℓi} (α : I  D)  Type (ℓ-max ℓi ℓt)
  isSemidirected {I = I} α = (i j : I)  ∃[ k  I ] (α i  α k) × (α j  α k)

  isPropIsSemidirected : {I : Type ℓi} (α : I  D)  isProp (isSemidirected α)
  isPropIsSemidirected α = isPropΠ2  i j  isPropPropTrunc)

  isDirected : {I : Type ℓi} (α : I  D)  Type (ℓ-max ℓi ℓt)
  isDirected {I = I} α =  I ∥₁ × isSemidirected α

  isPropIsDirected : {I : Type ℓi} (α : I  D)  isProp (isDirected α)
  isPropIsDirected α = isProp× isPropPropTrunc (isPropIsSemidirected α)

  inhabitedIfDirected : {I : Type ℓi} {α : I  D}  isDirected α   I ∥₁
  inhabitedIfDirected = fst

  semidirectedIfDirected : {I : Type ℓi} {α : I  D}  isDirected α  isSemidirected α
  semidirectedIfDirected = snd

  isUpperbound : {I : Type ℓi} (x : D) (α : I  D)  Type (ℓ-max ℓi ℓt)
  isUpperbound {I = I} x α = (i : I)  α i  x

  isPropIsUpperbound : {I : Type ℓi}
                      IsPoset _⊑_
                      (x : D) (α : I  D)  isProp (isUpperbound x α)
  isPropIsUpperbound isPoset x α = isPropΠ λ i  is-prop-valued (α i) x
    where
      open IsPoset isPoset

  isLowerboundOfUpperbounds : {I : Type ℓi} (x : D) (α : I  D)  Type (ℓ-max (ℓ-max ℓi ℓd) ℓt)
  isLowerboundOfUpperbounds x α = (v : D)  isUpperbound v α  x  v

  isPropIsLowerboundOfUpperbounds : {I : Type ℓi}
                                   IsPoset _⊑_
                                   (x : D) (α : I  D)
                                   isProp (isLowerboundOfUpperbounds x α)
  isPropIsLowerboundOfUpperbounds isPoset x α = isPropΠ2  v _  is-prop-valued x v)
    where
      open IsPoset isPoset

  isSup : {I : Type ℓi} (x : D) (α : I  D)  Type (ℓ-max (ℓ-max ℓi ℓd) ℓt)
  isSup x α = isUpperbound x α × isLowerboundOfUpperbounds x α

  isPropIsSup : {I : Type ℓi}
               IsPoset _⊑_
               (x : D) (α : I  D)
               isProp (isSup x α)
  isPropIsSup isPoset x α = isProp× (isPropIsUpperbound isPoset x α)
                                    (isPropIsLowerboundOfUpperbounds isPoset x α)

  supIsUpperbound : {I : Type ℓi} {x : D} {α : I  D}
                   isSup x α
                   isUpperbound x α
  supIsUpperbound = fst

  supIsLowerboundOfUpperbounds : {I : Type ℓi} {x : D} {α : I  D}
                                isSup x α
                                isLowerboundOfUpperbounds x α
  supIsLowerboundOfUpperbounds = snd

  supsAreUnique : {I : Type ℓi}
                 IsPoset _⊑_
                 (α : I  D) (x y : D)
                 isSup x α
                 isSup y α
                 x  y
  supsAreUnique isPoset α x y xIsSup yIsSup =
    is-antisym x y
      (supIsLowerboundOfUpperbounds xIsSup y (supIsUpperbound yIsSup))
      (supIsLowerboundOfUpperbounds yIsSup x (supIsUpperbound xIsSup))
    where
      open IsPoset isPoset

  hasSup : {I : Type ℓi} (α : I  D)  Type (ℓ-max (ℓ-max ℓi ℓd) ℓt)
  hasSup α = Σ[ x  D ] isSup x α

  isPropHasSup : {I : Type ℓi} (α : I  D)  IsPoset _⊑_  isProp (hasSup α)
  isPropHasSup α isPoset (u , uIsSup) (v , vIsSup) =
    Σ≡Prop  x  isPropIsSup isPoset x α)
      (supsAreUnique isPoset α u v uIsSup vIsSup)

  isDirectedComplete : Type (ℓ-max (ℓ-max (ℓ-suc ℓi) ℓd) ℓt)
  isDirectedComplete = {I : Type ℓi} {α : I  D} (δ : isDirected α)  hasSup α

  isPropIsDirectedComplete : IsPoset _⊑_  isProp isDirectedComplete
  isPropIsDirectedComplete isPoset =
    isPropImplicitΠ2 λ I α 
      isPropΠ λ δ (x , xIsSup) (y , yIsSup) 
        Σ≡Prop  z  isPropIsSup isPoset z α)
               (supsAreUnique isPoset α x y xIsSup yIsSup)

  isLeast : (x : D)  Type (ℓ-max ℓd ℓt)
  isLeast x = (y : D)  x  y

record DCPOStr (ℓd ℓt : Level) (D : Type ℓd) : Type (ℓ-max (ℓ-max (ℓ-suc ℓi) (ℓ-suc ℓt)) ℓd) where
  constructor dcpostr

  field
    posetStr : PosetStr ℓt D

  _⊑_ : D  D  Type ℓt
  _⊑_ = PosetStr._≤_ posetStr

  field
    is-directed-complete : isDirectedComplete _⊑_

  module posetStr = PosetStr posetStr

DCPO : (ℓd ℓt : Level)  Type (ℓ-max (ℓ-max (ℓ-suc ℓi) (ℓ-suc ℓd)) (ℓ-suc ℓt))
DCPO ℓd ℓt = TypeWithStr ℓd (DCPOStr ℓd ℓt)

dcpo : (D : Type ℓd) (_⊑_ : D  D  Type ℓt)
      IsPoset _⊑_
      isDirectedComplete _⊑_
      DCPO ℓd ℓt
dcpo D _⊑_ isPoset dc = D , dcpostr (posetstr _⊑_ isPoset) dc

order : (D : DCPO ℓd ℓt)   D    D   Type ℓt
order D = DCPOStr._⊑_ (str D)

infix 6 order
syntax order D x y = x ⊑⟨ D  y

posetAxioms : (D : DCPO ℓd ℓt)  IsPoset (order D)
posetAxioms D = DCPOStr.posetStr.isPoset (str D)

sethood : (D : DCPO ℓd ℓt)  isSet  D 
sethood D = IsPoset.is-set (posetAxioms D)

propValuedness : (D : DCPO ℓd ℓt)  isPropValued (order D)
propValuedness D = IsPoset.is-prop-valued (posetAxioms D)

reflexivity : (D : DCPO ℓd ℓt)  isRefl (order D)
reflexivity D = IsPoset.is-refl (posetAxioms D)

transitivity : (D : DCPO ℓd ℓt)  isTrans (order D)
transitivity D = IsPoset.is-trans (posetAxioms D)

antisymmetry : (D : DCPO ℓd ℓt)  isAntisym (order D)
antisymmetry D = IsPoset.is-antisym (posetAxioms D)

≡→⊑ : (D : DCPO ℓd ℓt) {x y :  D }  x  y  x ⊑⟨ D  y
≡→⊑ D {x = x} p = subst  y  x ⊑⟨ D  y) p (reflexivity D x)

 : (D : DCPO ℓd ℓt) {I : Type ℓi} {α : I   D }  isDirected (order D) α   D 
 D δ = fst (DCPOStr.is-directed-complete (str D) δ)

∐isSup : (D : DCPO ℓd ℓt) {I : Type ℓi} {α : I   D }
        (δ : isDirected (order D) α)
        isSup (order D) ( D δ) α
∐isSup D δ = snd (DCPOStr.is-directed-complete (str D) δ)

∐isUpperbound : (D : DCPO ℓd ℓt) {I : Type ℓi} {α : I   D }
               (δ : isDirected (order D) α)
               isUpperbound (order D) ( D δ) α
∐isUpperbound D δ = fst (∐isSup D δ)

∐isLowerBoundOfUpperbounds : (D : DCPO ℓd ℓt) {I : Type ℓi} {α : I   D }
                            (δ : isDirected (order D) α)
                            isLowerboundOfUpperbounds (order D) ( D δ) α
∐isLowerBoundOfUpperbounds D δ = snd (∐isSup D δ)

∐isMonotone : (D : DCPO ℓd ℓt) {I : Type ℓi} {α β : I   D }
             (δ : isDirected (order D) α)
             (ε : isDirected (order D) β)
             ((i : I)  α i ⊑⟨ D  β i)
              D δ ⊑⟨ D   D ε
∐isMonotone D {I} {α} {β} δ ε p =
  ∐isLowerBoundOfUpperbounds D δ ( D ε)
     i  transitivity D _ (β i) _ (p i) (∐isUpperbound D ε i))

constIsSup : (D : DCPO ℓd ℓt) {I : Type ℓi} (i :  I ∥₁) {x :  D }
            isSup (order D) x (const {B = I} x)
constIsSup D i {x} =
  ∥₁.rec (isPropIsSup (order D) (posetAxioms D) x (const x))
     i   _  reflexivity D x) ,  v vIsUpper  vIsUpper i))
    i

module DCPOReasoning where
  transitivity' : (D : DCPO ℓd ℓt) (x :  D ) {y z :  D }
                 x ⊑⟨ D  y  y ⊑⟨ D  z  x ⊑⟨ D  z
  transitivity' D x = transitivity D x _ _

  reflexivity' = reflexivity

  syntax transitivity' D x x⊑y y⊑z = x ⊑⟨ D ⟩[ x⊑y ] y⊑z
  infixr 0 transitivity'

  syntax reflexivity' D x = x ∎⟨ D 
  infix 1 reflexivity'

isContinuous : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
              ( D    E )
              Type (ℓ-max (ℓ-max (ℓ-max (ℓ-max (ℓ-suc ℓi) ℓd) ℓt) ℓe) ℓt')
isContinuous D E f = (I : Type ℓi) (α : I   D ) (δ : isDirected (order D) α)
                     isSup (order E) (f ( D δ)) (f  α)

isPropIsContinuous : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt') (f :  D    E )
                    isProp (isContinuous D E f)
isPropIsContinuous D E f =
  isPropΠ3  I α δ 
    isPropIsSup (order E) (posetAxioms E) (f ( D δ)) (f  α))

isMonotone : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
            ( D    E )
            Type (ℓ-max (ℓ-max ℓd ℓt) ℓt')
isMonotone D E f = {x y :  D }  x ⊑⟨ D  y  f x ⊑⟨ E  f y

isPropIsMonotone : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
                  (f :  D    E )
                  isProp (isMonotone D E f)
isPropIsMonotone D E f =
  isPropImplicitΠ2  x y  isPropΠ  _  propValuedness E (f x) (f y)))

isMonotone→imageIsDirected : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
                            (f :  D    E )
                            isMonotone D E f
                            {I : Type ℓi} {α : I   D } (δ : isDirected (order D) α)
                            isDirected (order E) (f  α)
isMonotone→imageIsDirected D E f fMonotone δ =
  inhabitedIfDirected (order D) δ ,
  λ i j  ∥₁.map
             (k , αᵢ⊑αₖ , αⱼ⊑αₖ)  k , fMonotone αᵢ⊑αₖ , fMonotone αⱼ⊑αₖ)
            (semidirectedIfDirected (order D) δ i j)

isContinuous→isMonotone : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
                         (f :  D    E )
                         isContinuous D E f
                         isMonotone D E f
isContinuous→isMonotone D E f fCont {x} {y} x⊑y =
  supIsUpperbound (order E) fySup (lift false)
  where
    α : Bool*   D 
    α (lift false) = x
    α (lift true)  = y

    δ : isDirected (order D) α
    δ =  lift false ∣₁ ,
        λ { (lift false) (lift false)   true* , x⊑y , x⊑y ∣₁
          ; (lift false) (lift true)    true* , x⊑y , reflexivity D y ∣₁
          ; (lift true)  (lift false)   true* , reflexivity D y , x⊑y ∣₁
          ; (lift true)  (lift true)    true* , reflexivity D y , reflexivity D y ∣₁ }

    p :  D δ  y
    p = antisymmetry D _ _
          (∐isLowerBoundOfUpperbounds D δ y  { (lift false)  x⊑y
                                               ; (lift true)   reflexivity D y}))
          (∐isUpperbound D δ (lift true))

    fySup : isSup (order E) (f y) (f  α)
    fySup = subst  z  isSup (order E) (f z) (f  α)) p (fCont Bool* α δ)

isContinuous→imageIsDirected : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
                              (f :  D    E )
                              isContinuous D E f
                              {I : Type ℓi} {α : I   D } (δ : isDirected (order D) α)
                              isDirected (order E) (f  α)
isContinuous→imageIsDirected D E f fCont δ =
  isMonotone→imageIsDirected D E f (isContinuous→isMonotone D E f fCont) δ

continuous∐≡ : {I : Type ℓi} (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
              (f :  D    E )
              (fCont : isContinuous D E f)
              {α : I   D }
              (δ : isDirected (order D) α)
              f ( D δ)
               E {α = f  α} (isContinuous→imageIsDirected D E f fCont δ)
continuous∐≡ {I = I} D E f fCont {α} δ =
  antisymmetry E _ _
    (supIsLowerboundOfUpperbounds (order E) (fCont I α δ)
      ( E (isContinuous→imageIsDirected D E f fCont δ))
      (∐isUpperbound E (isContinuous→imageIsDirected D E f fCont δ)))
    (supIsLowerboundOfUpperbounds (order E)
      (∐isSup E (isContinuous→imageIsDirected D E f fCont δ))
      (f ( D δ))
      (supIsUpperbound (order E) (fCont I α δ)))

record DCPOMorphism (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt') : Type (ℓ-max (ℓ-max (ℓ-max (ℓ-max (ℓ-suc ℓi) ℓd) ℓt) ℓe) ℓt') where
  constructor scottcontinuousmap
  field
    function   :  D    E 
    continuity : isContinuous D E function

  monotonicty : isMonotone D E function
  monotonicty = isContinuous→isMonotone D E function continuity

  imageIsDirected : {I : Type ℓi} {α : I   D } (δ : isDirected (order D) α)
                   isDirected (order E) (function  α)
  imageIsDirected = isMonotone→imageIsDirected D E function monotonicty

  supPreservation : {I : Type ℓi} {α : I   D } (δ : isDirected (order D) α)
                   function ( D δ)
                    E {α = function  α} (imageIsDirected δ)
  supPreservation = continuous∐≡ D E function continuity
open DCPOMorphism public

isContinuous-∘ : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt') (F : DCPO ℓf ℓt'')
                (g :  E    F ) (f :  D    E )
                isContinuous E F g
                isContinuous D E f
                isContinuous D F (g  f)
isContinuous-∘ D E F g f gCont fCont I α δ =
  subst⁻  x  isSup (order F) x (g  f  α))
    (cong g (continuous∐≡ D E f fCont δ) 
     continuous∐≡ E F g gCont (isContinuous→imageIsDirected D E f fCont δ))
    (∐isSup F _)

unquoteDecl DCPOMorphismIsoΣ = declareRecordIsoΣ DCPOMorphismIsoΣ (quote DCPOMorphism)

DCPOMorphism≡ : {D : DCPO ℓd ℓt} {E : DCPO ℓe ℓt'}
               {f g : DCPOMorphism D E}
               function f  function g
               f  g
DCPOMorphism≡ {D = D} {E = E} {f = f} {g = g} p =
  isoFunInjective DCPOMorphismIsoΣ f g
    (Σ≡Prop (isPropIsContinuous D E) p)

isSetDCPOMorphism : {D : DCPO ℓd ℓt} {E : DCPO ℓe ℓt'}  isSet (DCPOMorphism D E)
isSetDCPOMorphism {D = D} {E = E} =
  isOfHLevelRetractFromIso 2 DCPOMorphismIsoΣ
    (isSetΣ (isSetΠ  _  sethood E)) λ f  isProp→isSet (isPropIsContinuous D E f))

constIsContinuous : (D : DCPO ℓd ℓt) (E : DCPO ℓe ℓt')
                   {x :  E }
                   isContinuous D E (const {B =  D } x)
constIsContinuous D E I α δ = constIsSup E (inhabitedIfDirected (order D) δ)

idIsContinuous : (D : DCPO ℓd ℓt)
                isContinuous D D  x  x)
idIsContinuous D I α δ = ∐isSup D δ

idᵈᶜᵖᵒ : {D : DCPO ℓd ℓt}  DCPOMorphism D D
idᵈᶜᵖᵒ {D = D} = scottcontinuousmap  x  x) (idIsContinuous D)

module _ {D : DCPO ℓd ℓt} {E : DCPO ℓe ℓt'} {F : DCPO ℓf ℓt''} where
  infixr 9 _∘ᵈᶜᵖᵒ_
  _∘ᵈᶜᵖᵒ_ : (g : DCPOMorphism E F) (f : DCPOMorphism D E)
           DCPOMorphism D F
  g ∘ᵈᶜᵖᵒ f =
    scottcontinuousmap (function g  function f)
      (isContinuous-∘ D E F (function g) (function f) (continuity g) (continuity f))