module Order.DCPO.Pointed where

Pointed DCPOsπŸ”—

A DCPO is pointed if it has a least element This is a property of a DCPO, as bottom elements are unique.

is-pointed-dcpo : DCPO o β„“ β†’ Type _
is-pointed-dcpo D = Bottom (DCPO.poset D)

is-pointed-dcpo-is-prop : βˆ€ (D : DCPO o β„“) β†’ is-prop (is-pointed-dcpo D)
is-pointed-dcpo-is-prop D = Bottom-is-prop (DCPO.poset D)

A DCPO is pointed if and only if it has least upper bounds of all semidirected families.

The forward direction is straightforward: bottom elements are equivalent to least upper bounds of the empty family and this family is trivially semidirected.

  semidirected-lub→pointed
    : (βˆ€ {Ix : Type o} (s : Ix β†’ Ob) β†’ is-semidirected-family poset s β†’ Lub poset s)
    β†’ is-pointed-dcpo D
  semidirected-lub→pointed lub =
    Lub→Bottom poset (lower-lub (lub (λ ()) (λ ())))

Conversely, if has a bottom element then we can extend any semidirected family to a directed family by sending nothing to the bottom element.

  extend-bottom : (Ix β†’ Ob) β†’ Maybe Ix β†’ Ob
  extend-bottom s nothing = bot
  extend-bottom s (just i) = s i

  extend-bottom-directed
    : (s : Ix β†’ Ob) β†’ is-semidirected-family poset s
    β†’ is-directed-family poset (extend-bottom s)
  extend-bottom-directed s semidir .elt = inc nothing
  extend-bottom-directed s semidir .semidirected (just i) (just j) = do
    (k , i≀k , j≀k) ← semidir i j
    pure (just k , i≀k , j≀k)
  extend-bottom-directed s semidir .semidirected (just x) nothing =
    pure (just x , ≀-refl , Β‘)
  extend-bottom-directed s semidir .semidirected nothing (just y) =
    pure (just y , Β‘ , ≀-refl)
  extend-bottom-directed s semidir .semidirected nothing nothing =
   pure (nothing , ≀-refl , ≀-refl)

Furthermore, has a least upper bound only if the extended family does.

  lub→extend-bottom-lub
    : βˆ€ {s : Ix β†’ Ob} {x : Ob} β†’ is-lub poset s x β†’ is-lub poset (extend-bottom s) x
  lubβ†’extend-bottom-lub {s = s} {x = x} x-lub .fam≀lub (just i) = x-lub .fam≀lub i
  lubβ†’extend-bottom-lub {s = s} {x = x} x-lub .fam≀lub nothing = Β‘
  lubβ†’extend-bottom-lub {s = s} {x = x} x-lub .least y le = x-lub .least y (le βŠ™ just)

  extend-bottom-lub→lub
    : βˆ€ {s : Ix β†’ Ob} {x : Ob} β†’ is-lub poset (extend-bottom s) x β†’ is-lub poset s x
  extend-bottom-lubβ†’lub x-lub .fam≀lub i = x-lub .fam≀lub (just i)
  extend-bottom-lub→lub x-lub .least y le = x-lub .least y λ where
    nothing β†’ Β‘
    (just i) β†’ le i

If we put this all together, we see that any semidirected family has a least upper bound in a pointed DCPO.

  pointed→semidirected-lub
    : is-pointed-dcpo D
    β†’ βˆ€ {Ix : Type o} (s : Ix β†’ Ob) β†’ is-semidirected-family poset s β†’ Lub poset s
  pointed→semidirected-lub pointed {Ix = Ix} s semidir .Lub.lub =
    ⋃ (extend-bottom s) (extend-bottom-directed s semidir)
  pointed→semidirected-lub pointed {Ix = Ix} s semidir .Lub.has-lub =
    extend-bottom-lubβ†’lub (⋃.has-lub _ _)

FixpointsπŸ”—

Let be a pointed DCPO. Every Scott continuous function has a least fixed point.

module _ {o β„“} {D : DCPO o β„“} where
  open DCPO D

  pointed→least-fixpoint
    : is-pointed-dcpo D
    β†’ (f : DCPOs.Hom D D)
    β†’ Least-fixpoint poset (Scott.mono f)
  pointed→least-fixpoint pointed f = f-fix where
    open Bottom pointed
    module f = Scott f

We begin by constructing a directed family that maps to

    fⁿ : Nat β†’ Ob β†’ Ob
    fⁿ zero x = x
    fⁿ (suc n) x = f # (fⁿ n x)

    fⁿ-mono : βˆ€ {i j} β†’ i Nat.≀ j β†’ fⁿ i bot ≀ fⁿ j bot
    fⁿ-mono Nat.0≀x = Β‘
    fⁿ-mono (Nat.s≀s p) = f.monotone (fⁿ-mono p)

    fⁿβŠ₯ : Lift o Nat β†’ Ob
    fⁿβŠ₯ (lift n) = fⁿ n bot

    fⁿβŠ₯-dir : is-directed-family poset fⁿβŠ₯
    fⁿβŠ₯-dir .is-directed-family.elt = inc (lift zero)
    fⁿβŠ₯-dir .is-directed-family.semidirected (lift i) (lift j) =
      inc (lift (Nat.max i j) , fⁿ-mono (Nat.max-≀l i j) , fⁿ-mono (Nat.max-≀r i j))

The least upper bound of this sequence shall be our least fixpoint. We begin by proving a slightly stronger variation of the universal property; namely for any such that This follows from som quick induction.

    fⁿβŠ₯≀fix : βˆ€ (y : Ob) β†’ f # y ≀ y β†’ βˆ€ n β†’ fⁿβŠ₯ n ≀ y
    fⁿβŠ₯≀fix y p (lift zero) = Β‘
    fⁿβŠ₯≀fix y p (lift (suc n)) =
      f # (fⁿ n bot)   β‰€βŸ¨ f.monotone (fⁿβŠ₯≀fix y p (lift n)) βŸ©β‰€
      f # y            β‰€βŸ¨ p βŸ©β‰€
      y                β‰€βˆŽ

    least-fix : βˆ€ (y : Ob) β†’ f # y ≀ y β†’ ⋃ fⁿβŠ₯ fⁿβŠ₯-dir ≀ y
    least-fix y p = ⋃.least _ _ _ (fⁿβŠ₯≀fix y p)

Now, let’s show that is actuall a fixpoint. First, the forward direction: This follows directly from Scott-continuity of

    roll : f # (⋃ fⁿβŠ₯ fⁿβŠ₯-dir) ≀ ⋃ fⁿβŠ₯ fⁿβŠ₯-dir
    roll =
      f # (⋃ fⁿβŠ₯ _)        =⟨ f.pres-⋃ fⁿβŠ₯ fⁿβŠ₯-dir ⟩=
      ⋃ (apply f βŠ™ fⁿβŠ₯) _  β‰€βŸ¨ ⋃.least _ _ _ (Ξ» (lift n) β†’ ⋃.fam≀lub _ _ (lift (suc n))) βŸ©β‰€
      ⋃ fⁿβŠ₯ _              β‰€βˆŽ

To show the converse, we use universal property we proved earlier to re-arrange the goal to We can then apply monotonicity of and then use the forward direction to finish off the proof.

    unroll : ⋃ fⁿβŠ₯ fⁿβŠ₯-dir ≀ f # (⋃ fⁿβŠ₯ fⁿβŠ₯-dir)
    unroll = least-fix (f # (⋃ fⁿβŠ₯ fⁿβŠ₯-dir)) $
      f.monotone roll

All that remains is to package up the data.

    f-fix : Least-fixpoint poset f.mono
    f-fix .Least-fixpoint.fixpoint = ⋃ fⁿβŠ₯ fⁿβŠ₯-dir
    f-fix .Least-fixpoint.has-least-fixpoint .is-least-fixpoint.fixed =
      ≀-antisym roll unroll
    f-fix .Least-fixpoint.has-least-fixpoint .is-least-fixpoint.least y y-fix =
      least-fix y (≀-refl' y-fix)

Strictly Scott-continuous mapsπŸ”—

A Scott-continuous map is strictly continuous if it preserves bottoms.

  is-strictly-scott-continuous : (f : DCPOs.Hom D E) β†’ Type _
  is-strictly-scott-continuous f =
    βˆ€ (x : D.Ob) β†’ is-bottom D.poset x β†’ is-bottom E.poset (f # x)
  is-strictly-scott-is-prop
    : (f : DCPOs.Hom D E) β†’ is-prop (is-strictly-scott-continuous f)
  is-strictly-scott-is-prop f = Ξ -is-hlevelΒ² 1 Ξ» x _ β†’
    is-bottom-is-prop E.poset (f # x)

Strictly Scott-continuous functions are closed under identities and composites.

strict-scott-id
  : βˆ€ {D : DCPO o β„“}
  β†’ is-strictly-scott-continuous (DCPOs.id {x = D})
strict-scott-id x x-bot = x-bot

strict-scott-∘
  : βˆ€ {D E F : DCPO o β„“}
  β†’ (f : DCPOs.Hom E F) (g : DCPOs.Hom D E)
  β†’ is-strictly-scott-continuous f β†’ is-strictly-scott-continuous g
  β†’ is-strictly-scott-continuous (f DCPOs.∘ g)
strict-scott-∘ f g f-strict g-strict x x-bot =
  f-strict (g # x) (g-strict x x-bot)

Pointed DCPOs and strictly Scott-continuous functions form a subcategory of the category of DCPOs.

Pointed-DCPOs-subcat : βˆ€ o β„“ β†’ Subcat (DCPOs o β„“) (o βŠ” β„“) (o βŠ” β„“)
Pointed-DCPOs-subcat o β„“ .Subcat.is-ob = is-pointed-dcpo
Pointed-DCPOs-subcat o β„“ .Subcat.is-hom f _ _ = is-strictly-scott-continuous f
Pointed-DCPOs-subcat o β„“ .Subcat.is-hom-prop f _ _ =
  is-strictly-scott-is-prop f
Pointed-DCPOs-subcat o β„“ .Subcat.is-hom-id {D} _ = strict-scott-id {D = D}
Pointed-DCPOs-subcat o β„“ .Subcat.is-hom-∘ {f = f} {g = g} f-strict g-strict =
  strict-scott-∘ f g f-strict g-strict

Pointed-DCPOs : βˆ€ o β„“ β†’ Precategory (lsuc (o βŠ” β„“)) (lsuc o βŠ” β„“)
Pointed-DCPOs o β„“ = Subcategory (Pointed-DCPOs-subcat o β„“)

Pointed-DCPOs-is-category : is-category (Pointed-DCPOs o β„“)
Pointed-DCPOs-is-category =
  subcat-is-category DCPOs-is-category is-pointed-dcpo-is-prop

Reasoning with pointed DCPOsπŸ”—

The following module re-exports facts about pointed DCPOs, and also proves a bunch of useful lemma.s

module Pointed-dcpo {o β„“} (D : Pointed-dcpo o β„“) where
These proofs are all quite straightforward, so we omit them.
  open is-directed-family

  dcpo : DCPO o β„“
  dcpo = D .fst

  has-pointed : is-pointed-dcpo dcpo
  has-pointed = D .snd

  open DCPO dcpo public

  bottom : Ob
  bottom = Bottom.bot (D .snd)

  bottom≀x : βˆ€ x β†’ bottom ≀ x
  bottom≀x = Bottom.has-bottom (D .snd)

  adjoin : βˆ€ {Ix : Type o} β†’ (Ix β†’ Ob) β†’ Maybe Ix β†’ Ob
  adjoin = extend-bottom dcpo has-pointed

  adjoin-directed
    : βˆ€ (s : Ix β†’ Ob) β†’ is-semidirected-family poset s
    β†’ is-directed-family poset (adjoin s)
  adjoin-directed = extend-bottom-directed dcpo has-pointed

  lubβ†’adjoin-lub : βˆ€ {s : Ix β†’ Ob} {x : Ob} β†’ is-lub poset s x β†’ is-lub poset (adjoin s) x
  lub→adjoin-lub = lub→extend-bottom-lub dcpo has-pointed

  adjoin-lubβ†’lub : βˆ€ {s : Ix β†’ Ob} {x : Ob} β†’ is-lub poset (adjoin s) x β†’ is-lub poset s x
  adjoin-lub→lub = extend-bottom-lub→lub dcpo has-pointed

  -- We put these behind 'opaque' to prevent blow ups in goals.
  opaque
    ⋃-semi : (s : Ix β†’ Ob) β†’ is-semidirected-family poset s β†’ Ob
    ⋃-semi s semidir = ⋃ (adjoin s) (adjoin-directed s semidir)

    ⋃-semi-lub
      : βˆ€ (s : Ix β†’ Ob) (dir : is-semidirected-family poset s)
      β†’ is-lub poset s (⋃-semi s dir)
    ⋃-semi-lub s dir = adjoin-lubβ†’lub (⋃.has-lub (adjoin s) (adjoin-directed s dir))

    ⋃-semi-le
      : βˆ€ (s : Ix β†’ Ob) (dir : is-semidirected-family poset s)
      β†’ βˆ€ i β†’ s i ≀ ⋃-semi s dir
    ⋃-semi-le s dir = is-lub.fam≀lub (⋃-semi-lub s dir)

    ⋃-semi-least
      : βˆ€ (s : Ix β†’ Ob) (dir : is-semidirected-family poset s)
      β†’ βˆ€ x β†’ (βˆ€ i β†’ s i ≀ x) β†’ ⋃-semi s dir ≀ x
    ⋃-semi-least s dir x le = is-lub.least (⋃-semi-lub s dir) x le

    ⋃-semi-pointwise
      : βˆ€ {Ix} {s s' : Ix β†’ Ob}
      β†’ {fam : is-semidirected-family poset s} {fam' : is-semidirected-family poset s'}
      β†’ (βˆ€ ix β†’ s ix ≀ s' ix)
      β†’ ⋃-semi s fam ≀ ⋃-semi s' fam'
    ⋃-semi-pointwise le = ⋃-pointwise Ξ» where
      (just i) β†’ le i
      nothing β†’ bottom≀x _

However, we do call attention to one extremely useful fact: if is a pointed DCPO, then it has least upper bounds of families indexed by propositions.

  opaque
    ⋃-prop : βˆ€ {Ix : Type o} β†’ (Ix β†’ Ob) β†’ is-prop Ix β†’ Ob
    ⋃-prop s ix-prop = ⋃-semi s (prop-indexedβ†’semidirected poset s ix-prop)

    ⋃-prop-le
      : βˆ€ (s : Ix β†’ Ob) (p : is-prop Ix)
      β†’ βˆ€ i β†’ s i ≀ ⋃-prop s p
    ⋃-prop-le s p i = ⋃-semi-le _ _ i

    ⋃-prop-least
      : βˆ€ (s : Ix β†’ Ob) (p : is-prop Ix)
      β†’ βˆ€ x β†’ (βˆ€ i β†’ s i ≀ x) β†’ ⋃-prop s p ≀ x
    ⋃-prop-least s p = ⋃-semi-least _ _

    ⋃-prop-lub
      : βˆ€ (s : Ix β†’ Ob) (p : is-prop Ix)
      β†’ is-lub poset s (⋃-prop s p)
    ⋃-prop-lub s p = ⋃-semi-lub _ _

This allows us to reflect the truth value of a proposition into

  opaque
    ⋃-prop-false
      : βˆ€ (s : Ix β†’ Ob) (p : is-prop Ix)
      β†’ Β¬ Ix β†’ ⋃-prop s p ≑ bottom
    ⋃-prop-false s p Β¬i =
      ≀-antisym
        (⋃-prop-least s p bottom (Ξ» x β†’ absurd (Β¬i x)))
        (bottom≀x _)

    ⋃-prop-true
      : βˆ€ (s : Ix β†’ Ob) (p : is-prop Ix)
      β†’ (i : Ix) β†’ ⋃-prop s p ≑ s i
    ⋃-prop-true s p i =
      sym $ lub-of-const-fam (Ξ» i j β†’ ap s (p i j)) (⋃-prop-lub s p) i

We define a similar module for strictly Scott-continuous maps.

module Strict-scott {D E : Pointed-dcpo o β„“} (f : Pointed-DCPOs.Hom D E) where
These proofs are all quite straightforward, so we omit them.
  private
    module D = Pointed-dcpo D
    module E = Pointed-dcpo E

  scott : DCPOs.Hom D.dcpo E.dcpo
  scott = Subcat-hom.hom f

  open Scott scott public

  opaque
    pres-bottoms : βˆ€ x β†’ is-bottom D.poset x β†’ is-bottom E.poset (f # x)
    pres-bottoms = Subcat-hom.witness f

    pres-βŠ₯ : f # D.bottom ≑ E.bottom
    pres-βŠ₯ = bottom-unique E.poset (pres-bottoms D.bottom D.bottom≀x) E.bottom≀x

    pres-adjoin-lub
      : βˆ€ {s : Ix β†’ D.Ob} {x : D.Ob}
      β†’ is-semidirected-family D.poset s
      β†’ is-lub D.poset (D.adjoin s) x β†’ is-lub E.poset (E.adjoin (apply f βŠ™ s)) (f # x)
    pres-adjoin-lub {s = s} {x = x} sdir x-lub .is-lub.fam≀lub (just i) =
      monotone (is-lub.fam≀lub x-lub (just i))
    pres-adjoin-lub {s = s} {x = x} sdir x-lub .is-lub.fam≀lub nothing =
      E.bottom≀x (f # x)
    pres-adjoin-lub {s = s} {x = x} sdir x-lub .is-lub.least y le =
      is-lub.least
        (pres-directed-lub (D.adjoin s) (D.adjoin-directed s sdir) x x-lub) y Ξ» where
          (just i) β†’ le (just i)
          nothing β†’ pres-bottoms _ D.bottom≀x y

    pres-semidirected-lub
      : βˆ€ {Ix} (s : Ix β†’ D.Ob) β†’ is-semidirected-family D.poset s
      β†’ βˆ€ x β†’ is-lub D.poset s x β†’ is-lub E.poset (apply f βŠ™ s) (f # x)
    pres-semidirected-lub s sdir x x-lub =
      E.adjoin-lub→lub (pres-adjoin-lub sdir (D.lub→adjoin-lub x-lub))

    pres-⋃-prop
      : βˆ€ {Ix} (s : Ix β†’ D.Ob) (p q : is-prop Ix)
      β†’ f # (D.⋃-prop s p) ≑ E.⋃-prop (apply f βŠ™ s) q
    pres-⋃-prop s p q =
      lub-unique
        (pres-semidirected-lub _
          (prop-indexedβ†’semidirected D.poset s p) (D.⋃-prop s p) (D.⋃-prop-lub s p))
        (E.⋃-prop-lub _ _)

    bottom-bounded : βˆ€ {x y} β†’ x D.≀ y β†’ f # y ≑ E.bottom β†’ f # x ≑ E.bottom
    bottom-bounded {x = x} {y = y} p y-bot =
      E.≀-antisym
        (f # x    E.β‰€βŸ¨ monotone p ⟩E.≀
         f # y    E.=⟨ y-bot ⟩E.=
         E.bottom E.β‰€βˆŽ)
        (E.bottom≀x _)

We also provide a handful of ways of constructing strictly Scott-continuous maps. First, we note that if is monotonic and preserves the chosen least upper bound of semidirected families, then is strictly Scott-continuous.

  to-strict-scott-⋃-semi
    : (f : D.Ob β†’ E.Ob)
    β†’ (βˆ€ {x y} β†’ x D.≀ y β†’ f x E.≀ f y)
    β†’ (βˆ€ {Ix} (s : Ix β†’ D.Ob) β†’ (dir : is-semidirected-family D.poset s)
       β†’ is-lub E.poset (f βŠ™ s) (f (D.⋃-semi s dir)))
    β†’ Pointed-DCPOs.Hom D E
  to-strict-scott-⋃-semi f monotone pres-⋃-semi =
    sub-hom (to-scott f monotone pres-⋃) pres-bot
    where
      pres-⋃
        : βˆ€ {Ix} (s : Ix β†’ D.Ob) β†’ (dir : is-directed-family D.poset s)
        β†’ is-lub E.poset (f βŠ™ s) (f (D.⋃ s dir))
      pres-⋃ s dir .is-lub.fam≀lub i =
        monotone $ D.⋃.fam≀lub _ _ i
      pres-⋃ s dir .is-lub.least y le =
        f (D.⋃ s dir)                      E.=⟨ ap f (lub-unique (D.⋃.has-lub _ _) (D.⋃-semi-lub s (dir .semidirected))) ⟩E.=
        f (D.⋃-semi s (dir .semidirected)) E.β‰€βŸ¨ pres-⋃-semi _ _ .is-lub.least y le ⟩E.≀
        y E.β‰€βˆŽ

      pres-bot : βˆ€ x β†’ is-bottom D.poset x β†’ is-bottom E.poset (f x)
      pres-bot x x-bot y =
        f x              E.β‰€βŸ¨ monotone (x-bot _) ⟩E.≀
        f (D.⋃-semi _ _) E.β‰€βŸ¨ is-lub.least (pres-⋃-semi (Ξ» x β†’ absurd (x .Lift.lower)) (Ξ» ())) y (Ξ» ()) ⟩E.≀
        y                E.β‰€βˆŽ

Next, if is monotonic, preserves chosen least upper bounds of directed families, and preserves chosen bottoms, then is strictly Scott-continuous.

  to-strict-scott-bottom
    : (f : D.Ob β†’ E.Ob)
    β†’ (βˆ€ {x y} β†’ x D.≀ y β†’ f x E.≀ f y)
    β†’ (βˆ€ {Ix} (s : Ix β†’ D.Ob) β†’ (dir : is-directed-family D.poset s)
       β†’ is-lub E.poset (f βŠ™ s) (f (D.⋃ s dir)))
    β†’ is-bottom E.poset (f D.bottom)
    β†’ Pointed-DCPOs.Hom D E
  to-strict-scott-bottom f monotone pres-⋃ pres-bot =
    sub-hom (to-scott f monotone pres-⋃) Ξ» x x-bot y β†’
      f x        E.β‰€βŸ¨ monotone (x-bot _) ⟩E.≀
      f D.bottom E.β‰€βŸ¨ pres-bot y ⟩E.≀
      y          E.β‰€βˆŽ

Finally, if preserves arbitrary least upper bounds of semidirected families, then must be monotonic, and thus strictly Scott-continuous.

  to-strict-scott-semidirected
    : (f : D.Ob β†’ E.Ob)
    β†’ (βˆ€ {Ix} (s : Ix β†’ D.Ob) β†’ (dir : is-semidirected-family D.poset s)
       β†’ βˆ€ x β†’ is-lub D.poset s x β†’ is-lub E.poset (f βŠ™ s) (f x))
    β†’ Pointed-DCPOs.Hom D E
  to-strict-scott-semidirected f pres =
    sub-hom
      (to-scott-directed f
        (Ξ» s dir x lub β†’ pres s (is-directed-family.semidirected dir) x lub))
      (Ξ» x x-bot y β†’ is-lub.least
          (pres _ (λ x → absurd (x .Lift.lower)) x (lift-is-lub (is-bottom→is-lub D.poset {f = λ ()} x-bot)))
          y (Ξ» ()))