module Order.Diagram.Lub.Reasoning {o ℓ} (P : Poset o ℓ) where

Reasoning about least upper bounds🔗

This module provides syntax and reasoning combinators for working with partial orders that have all least upper bounds.

module Lubs
  {⋃      : ∀ {I : Type o} (f : I → Ob) → Ob}
  (⋃-lubs : ∀ {I : Type o} (f : I → Ob) → is-lub P f (⋃ f))
  where

  lubs : ∀ {I : Type o} (f : I → Ob) → Lub P f
  lubs f = record { lub = ⋃ f ; has-lub = ⋃-lubs f }

  module ⋃-lubs {I} {f : I → Ob} = is-lub (⋃-lubs f)
  open ⋃-lubs using () renaming (fam≀lub to ⋃-inj; least to ⋃-universal) public

Performing two nested joins over and is the same as taking a single join over

  ⋃-twice
    : ∀ {I : Type o} {J : I → Type o} (F : (i : I) → J i → Ob)
    → ⋃ (λ i → ⋃ λ j → F i j)
    ≡ ⋃ {I = Σ I J} (λ p → F (p .fst) (p .snd))
  ⋃-twice F = ≀-antisym
    (⋃-universal _ (λ i → ⋃-universal _ (λ j → ⋃-inj _)))
    (⋃-universal _ λ (i , j) → ≀-trans (⋃-inj j) (⋃-inj i))

Let and be a pair of families. If there is a map such that then the meet of is smaller than the meet of

  ⋃≀⋃-over
    : ∀ {I J : Type o} {f : I → Ob} {g : J → Ob}
    → (to : I → J)
    → (∀ i → f i ≀ g (to i))
    → ⋃ f ≀ ⋃ g
  ⋃≀⋃-over to p = ⋃-universal _ λ i → ≀-trans (p i) (⋃-inj (to i))

As a corollary, if is smaller than for each then the join of is smaller than the join of

  ⋃≀⋃
    : ∀ {I : Type o} {f g : I → Ob}
    → (∀ i → f i ≀ g i)
    → ⋃ f ≀ ⋃ g
  ⋃≀⋃ = ⋃≀⋃-over (λ i → i)

Taking the join over a contractible family is equal the unique value of the family.

  ⋃-singleton
    : ∀ {I : Type o} {f : I → Ob}
    → (p : is-contr I)
    → ⋃ f ≡ f (p .centre)
  ⋃-singleton {f = f} p = ≀-antisym
    (⋃-universal _ λ i → ≀-refl' $ sym $ ap f (p .paths i))
    (⋃-inj _)

We also provide syntax for binary joins and bottom elements.

  module _ (x y : Ob) where opaque
    private
      it : Join P x y
      it = Lub→Join (lower-lub (lubs _))

    infixr 24 _∪_
    _∪_ : Ob
    _∪_ = it .Join.lub

    ∪-joins : is-join P x y _∪_
    ∪-joins = it .Join.has-join

  opaque
    has-bottom : Bottom
    has-bottom = Lub→Bottom (lower-lub (lubs (λ ())))

  open Joins ∪-joins public
  open Bottom has-bottom using (bot; ¡) public

There is a distributive law relating binary and infinitary joins.

  ∪-distrib-⋃-≀l
    : ∀ {I : Type o} {x : Ob} {f : I → Ob}
    → ⋃ (λ i → x ∪ f i) ≀ x ∪ ⋃ f
  ∪-distrib-⋃-≀l =
    ⋃-universal _ λ i → ∪-universal _ l≀∪ (≀-trans (⋃-inj i) r≀∪)

If the infinitary join is taken over a non-empty family, then the previous distributive law can be extended to an equality.

  ∪-distrib-nonempty-⋃-l
    : ∀ {I : Type o} {x : Ob} {f : I → Ob}
    → ∥ I ∥
    → ⋃ (λ i → x ∪ f i) ≡ x ∪ ⋃ f
  ∪-distrib-nonempty-⋃-l i =
    ≀-antisym
      ∪-distrib-⋃-≀l
      (rec! (λ i → ∪-universal _ (≀-trans l≀∪ (⋃-inj i)) (⋃≀⋃ λ _ → r≀∪)) i)

Large joins🔗

Let be a poset. If has all joins of size then it has all joins, regardless of size.

is-cocomplete→is-large-cocomplete
  : (lubs : ∀ {I : Type o} (f : I → Ob) → Lub P f)
  → ∀ {ℓ} {I : Type ℓ} (F : I → Ob) → Lub P F
is-cocomplete→is-large-cocomplete lubs {I = I} F =
  cover-preserves-lub
    (Ω-corestriction-is-surjective F)
    (lubs fst)

We also provide some notation for large joins.

module
  Large
    {⋃ : {I : Type o} (F : I → Ob) → Ob}
    (⋃-lubs : ∀ {I} f → is-lub P f (⋃ {I} f))
  where

  open Lubs ⋃-lubs using (lubs)

  opaque
    ⋃ᮾ : ∀ {ℓ} {I : Type ℓ} (F : I → Ob) → Ob
    ⋃ᮾ F = is-cocomplete→is-large-cocomplete lubs F .Lub.lub

    ⋃ᮾ-inj : ∀ {ℓ} {I : Type ℓ} {F : I → Ob} (i : I) → F i ≀ ⋃ᮾ F
    ⋃ᮾ-inj = Lub.fam≀lub (is-cocomplete→is-large-cocomplete lubs _)

    ⋃ᮾ-universal : ∀ {ℓ} {I : Type ℓ} {F : I → Ob} (x : Ob) → (∀ i → F i ≀ x) → ⋃ᮾ F ≀ x
    ⋃ᮾ-universal = Lub.least (is-cocomplete→is-large-cocomplete lubs _)