Martin Escardo, May 2020

We now consider σ-frames. A σ-frame is a poset with countable joins
and finite meets such that binary meets distribute over countable
joins. Countable joins are exhausted by finitely indexed joins and
ℕ-indexed joins. But, apart from the empty join, all finite joins can
be expressed as ℕ-indexed joins (of eventually constant sequences) and
hence it is enough to consider the empty join (a bottom element) and
ℕ-indexed joins, which is the approach we take here.

We denote the empty meet (a top element) by ⊤, the binary meet by ∧,
the empty join (a bottom element) by ⊥, and the ℕ-indexed join by
⋁. These are unary, binary and ℕ-ary operations.

TODO. Currently the order is derived from the binary meet. However,
for size reasons, it would be good to add the other as a separate
relation coinciding with the binary meet order, similarly to what we
did with σ-sup-lattices. Perhaps it would be better to define a
σ-frame as a σ-sup-lattice equipped with a binary meet.

\begin{code}

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

open import UF.FunExt

module OrderedTypes.sigma-frame (fe : Fun-Ext) where

open import MLTT.Spartan
open import UF.Equiv hiding (_≅_)
open import UF.SIP
open import UF.SIP-Examples
open import UF.Sets
open import UF.Sets-Properties
open import UF.Subsingletons
open import UF.Subsingletons-FunExt
open import UF.Univalence

σ-frame-structure : 𝓤 ̇ → 𝓤 ̇
σ-frame-structure X = X × (X → X → X) × X × ((ℕ → X) → X)

σ-frame-axioms : (X : 𝓤 ̇ ) → σ-frame-structure X → 𝓤 ̇
σ-frame-axioms {𝓤} X (⊤ , _∧_ , ⊥ , ⋁) = I × II × III × IV × V × VI × VII × VIII × IX
 where
  _≤_ : X → X → 𝓤 ̇
  x ≤ y = x ∧ y ＝ x

  I    = is-set X
  II   = (x : X) → x ∧ x ＝ x
  III  = (x y : X) → x ∧ y ＝ y ∧ x
  IV   = (x y z : X) → x ∧ (y ∧ z) ＝ (x ∧ y) ∧ z
  V    = (x : X) → ⊥ ≤ x
  VI   = (x : X) → x ≤ ⊤
  VII  = (x : X) (y : ℕ → X) → x ∧ (⋁ y) ＝ ⋁ (n ↦ (x ∧ y n))
  VIII = (x : ℕ → X) (n : ℕ) → x n ≤ ⋁ x
  IX   = (x : ℕ → X) (u : X) → ((n : ℕ) → x n ≤ u) → ⋁ x ≤ u
\end{code}

Axioms I-IV say that (X , ⊤ , ∧) is a bounded semilattice, axiom VII
says that ⋁ gives least upper bounds w.r.t. the induced partial order,
and axiom VI says that binary meets distribute over countable joins.

\begin{code}

σ-frame-axioms-is-prop : (X : 𝓤 ̇ ) (s : σ-frame-structure X)
                       → is-prop (σ-frame-axioms X s)
σ-frame-axioms-is-prop X (⊤ , _∧_ , ⊥ , ⋁) = prop-criterion δ
 where
  δ : σ-frame-axioms X (⊤ , _∧_ , ⊥ , ⋁) → is-prop (σ-frame-axioms X (⊤ , _∧_ , ⊥ , ⋁))
  δ (i , ii-ix) =
    ×-is-prop (being-set-is-prop fe)
   (×-is-prop (Π-is-prop fe (λ x →  i {x ∧ x} {x}))
   (×-is-prop (Π-is-prop fe (λ x →
               Π-is-prop fe (λ y →  i {x ∧ y} {y ∧ x})))
   (×-is-prop (Π-is-prop fe (λ x →
               Π-is-prop fe (λ y →
               Π-is-prop fe (λ z →  i {x ∧ (y ∧ z)} {(x ∧ y) ∧ z}))))
   (×-is-prop (Π-is-prop fe (λ x →  i {⊥ ∧ x} {⊥}))
   (×-is-prop (Π-is-prop fe (λ x →  i {x ∧ ⊤} {x}))
   (×-is-prop (Π-is-prop fe (λ x →
               Π-is-prop fe (λ y →  i {x ∧ ⋁ y} {⋁ (n ↦ x ∧ y n)})))
   (×-is-prop (Π-is-prop fe (λ x →
               Π-is-prop fe (λ n → i {x n ∧ ⋁ x} {x n})))
              (Π-is-prop fe (λ x →
               Π-is-prop fe (λ u →
               Π-is-prop fe (λ _ →  i {⋁ x ∧ u} {⋁ x})))))))))))

σ-Frame : (𝓤 : Universe) → 𝓤 ⁺ ̇
σ-Frame 𝓤 = Σ A ꞉ 𝓤 ̇ , Σ s ꞉ σ-frame-structure A , σ-frame-axioms A s

⟨_⟩ : σ-Frame 𝓤 → 𝓤 ̇
⟨ A , _ ⟩ = A

is-σ-frame-homomorphism : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
                        → (⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩) → 𝓤 ⊔ 𝓥 ̇
is-σ-frame-homomorphism  (_ , (⊤ , _∧_ , ⊥ , ⋁) , _) (_ , (⊤' , _∧'_ , ⊥' , ⋁') , _) f =
    (f ⊤ ＝ ⊤')
  × ((λ a b → f (a ∧ b)) ＝ (λ a b → f a ∧' f b))
  × (f ⊥ ＝ ⊥')
  × ((λ 𝕒 → f (⋁ 𝕒)) ＝ (λ 𝕒 → ⋁' (n ↦ f (𝕒 n))))

_≅[σ-Frame]_ : σ-Frame 𝓤 → σ-Frame 𝓤 → 𝓤 ̇
𝓐 ≅[σ-Frame] 𝓑 = Σ f ꞉ (⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩), is-equiv f × is-σ-frame-homomorphism 𝓐 𝓑 f

characterization-of-σ-Frame-＝ : is-univalent 𝓤
                              → (A B : σ-Frame 𝓤)
                              → (A ＝ B) ≃ (A ≅[σ-Frame] B)
characterization-of-σ-Frame-＝ ua =
  sip.characterization-of-＝ ua
   (sip-with-axioms.add-axioms
      σ-frame-axioms
      σ-frame-axioms-is-prop
     (sip-join.join
       pointed-type.sns-data
     (sip-join.join
       ∞-magma.sns-data
       (sip-join.join
        pointed-type.sns-data
        (∞-bigmagma.sns-data ℕ)))))

\end{code}

We name the projections (we wouldn't need to do this if we had used a
record, but we need Σ for our approach to SIP):

\begin{code}

⊤⟨_⟩ : (𝓐 : σ-Frame 𝓤) → ⟨ 𝓐 ⟩
⊤⟨ A , (⊤ , _∧_ , ⊥ , ⋁) , _ ⟩ = ⊤

meet : (𝓐 : σ-Frame 𝓤) → ⟨ 𝓐 ⟩ → ⟨ 𝓐 ⟩ → ⟨ 𝓐 ⟩
meet (A , (⊤ , _∧_ , ⊥ , ⋁) , _) = _∧_

syntax meet 𝓐 x y = x ∧⟨ 𝓐 ⟩ y

⊥⟨_⟩ : (𝓐 : σ-Frame 𝓤) → ⟨ 𝓐 ⟩
⊥⟨ A , (⊤ , _∧_ , ⊥ , ⋁) , _ ⟩ = ⊥

⋁⟨_⟩ : (𝓐 : σ-Frame 𝓤) → (ℕ → ⟨ 𝓐 ⟩) → ⟨ 𝓐 ⟩
⋁⟨ A , (⊤ , _∧_ , ⊥ , ⋁) , _ ⟩ = ⋁

⟨_⟩-is-set : (𝓐 : σ-Frame 𝓤) → is-set ⟨ 𝓐 ⟩
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-is-set = i

⟨_⟩-idempotency : (𝓐 : σ-Frame 𝓤) (a : ⟨ 𝓐 ⟩)
                → a ∧⟨ 𝓐 ⟩ a ＝ a
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-idempotency = ii

⟨_⟩-commutativity : (𝓐 : σ-Frame 𝓤) (a b : ⟨ 𝓐 ⟩)
                  → a ∧⟨ 𝓐 ⟩ b ＝ b ∧⟨ 𝓐 ⟩ a
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-commutativity = iii

⟨_⟩-associativity : (𝓐 : σ-Frame 𝓤) (a b c : ⟨ 𝓐 ⟩)
                  → a ∧⟨ 𝓐 ⟩ (b ∧⟨ 𝓐 ⟩ c) ＝ (a ∧⟨ 𝓐 ⟩ b) ∧⟨ 𝓐 ⟩ c
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-associativity = iv

order : (𝓐 : σ-Frame 𝓤)
   → ⟨ 𝓐 ⟩ → ⟨ 𝓐 ⟩ → 𝓤 ̇
order 𝓐 a b = a ∧⟨ 𝓐 ⟩ b ＝ a

syntax order 𝓐 x y = x ≤⟨ 𝓐 ⟩ y

⟨_⟩-⊥-minimum : (𝓐 : σ-Frame 𝓤) (a : ⟨ 𝓐 ⟩)
              → ⊥⟨ 𝓐 ⟩ ≤⟨ 𝓐 ⟩ a
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-⊥-minimum = v

⟨_⟩-⊤-maximum : (𝓐 : σ-Frame 𝓤) (a : ⟨ 𝓐 ⟩)
              → a ≤⟨ 𝓐 ⟩ ⊤⟨ 𝓐 ⟩
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-⊤-maximum = vi

⟨_⟩-distributivity : (𝓐 : σ-Frame 𝓤) (a : ⟨ 𝓐 ⟩) (b : ℕ → ⟨ 𝓐 ⟩)
                   → a ∧⟨ 𝓐 ⟩ (⋁⟨ 𝓐 ⟩ b) ＝ ⋁⟨ 𝓐 ⟩ (n ↦ (a ∧⟨ 𝓐 ⟩ b n))
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-distributivity = vii

⟨_⟩-⋁-is-ub : (𝓐 : σ-Frame 𝓤) (a : ℕ → ⟨ 𝓐 ⟩) (n : ℕ)
            → a n ≤⟨ 𝓐 ⟩ ⋁⟨ 𝓐 ⟩ a
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-⋁-is-ub = viii

⟨_⟩-⋁-is-lb-of-ubs : (𝓐 : σ-Frame 𝓤) (a : ℕ → ⟨ 𝓐 ⟩) (u : ⟨ 𝓐 ⟩)
                   → ((n : ℕ) → a n ≤⟨ 𝓐 ⟩ u) → ⋁⟨ 𝓐 ⟩ a ≤⟨ 𝓐 ⟩ u
⟨ A , _ , (i , ii , iii , iv , v , vi , vii , viii , ix) ⟩-⋁-is-lb-of-ubs = ix

⟨_⟩-refl : (𝓐 : σ-Frame 𝓤) (a : ⟨ 𝓐 ⟩) → a ≤⟨ 𝓐 ⟩ a
⟨_⟩-refl 𝓐 a = ⟨ 𝓐 ⟩-idempotency a

⟨_⟩-trans : (𝓐 : σ-Frame 𝓤) (a b c : ⟨ 𝓐 ⟩) → a ≤⟨ 𝓐 ⟩ b → b ≤⟨ 𝓐 ⟩ c → a ≤⟨ 𝓐 ⟩ c
⟨_⟩-trans 𝓐 a b c l m = (a ∧⟨ 𝓐 ⟩ c)             ＝⟨ ap (λ - → - ∧⟨ 𝓐 ⟩ c) (l ⁻¹) ⟩
                         ((a ∧⟨ 𝓐 ⟩ b) ∧⟨ 𝓐 ⟩ c) ＝⟨ (⟨ 𝓐 ⟩-associativity a b c)⁻¹ ⟩
                         (a ∧⟨ 𝓐 ⟩ (b ∧⟨ 𝓐 ⟩ c)) ＝⟨ ap (λ - → a ∧⟨ 𝓐 ⟩ -) m ⟩
                         (a ∧⟨ 𝓐 ⟩ b)             ＝⟨ l ⟩
                         a                         ∎

⟨_⟩-antisym : (𝓐 : σ-Frame 𝓤) (a b : ⟨ 𝓐 ⟩) → a ≤⟨ 𝓐 ⟩ b → b ≤⟨ 𝓐 ⟩ a → a ＝ b
⟨_⟩-antisym 𝓐 a b l m = a            ＝⟨ l ⁻¹ ⟩
                        (a ∧⟨ 𝓐 ⟩ b) ＝⟨ ⟨ 𝓐 ⟩-commutativity a b ⟩
                        (b ∧⟨ 𝓐 ⟩ a) ＝⟨ m ⟩
                        b             ∎


being-σ-frame-homomorphism-is-prop : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
                                   → (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩)
                                   → is-prop (is-σ-frame-homomorphism 𝓐 𝓑 f)
being-σ-frame-homomorphism-is-prop (_ , _ ,  _) (_ , _ , (i' , _)) f =
  ×-is-prop i'
 (×-is-prop (Π-is-set fe (λ a →
             Π-is-set fe (λ b → i')))
 (×-is-prop i' (Π-is-set fe (λ 𝕒 → i'))))

∘-σ-frame-homomorphism : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥) (𝓒 : σ-Frame 𝓦)
                         (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩) (g : ⟨ 𝓑 ⟩ → ⟨ 𝓒 ⟩)
                       → is-σ-frame-homomorphism 𝓐 𝓑 f
                       → is-σ-frame-homomorphism 𝓑 𝓒 g
                       → is-σ-frame-homomorphism 𝓐 𝓒 (g ∘ f)
∘-σ-frame-homomorphism 𝓐 𝓑 𝓒 f g (p₀ , q₀ , r₀ , s₀) (p₁ , q₁ , r₁ , s₁) = (p₂ , q₂ , r₂ , s₂)
 where
  p₂ = g (f ⊤⟨ 𝓐 ⟩) ＝⟨ ap g p₀ ⟩
       g ⊤⟨ 𝓑 ⟩     ＝⟨ p₁ ⟩
       ⊤⟨ 𝓒 ⟩       ∎

  q₂ = (λ a b → g (f (a ∧⟨ 𝓐 ⟩ b)))     ＝⟨ dfunext fe (λ a → dfunext fe (λ b → ap (λ - → g (- a b)) q₀)) ⟩
       (λ a b → g (f a ∧⟨ 𝓑 ⟩ f b))     ＝⟨ dfunext fe (λ a → dfunext fe (λ b → ap (λ - → - (f a) (f b)) q₁)) ⟩
       (λ a b → g (f a) ∧⟨ 𝓒 ⟩ g (f b)) ∎

  r₂ = g (f ⊥⟨ 𝓐 ⟩) ＝⟨ ap g r₀ ⟩
       g ⊥⟨ 𝓑 ⟩     ＝⟨ r₁ ⟩
       ⊥⟨ 𝓒 ⟩       ∎

  s₂ = (λ 𝕒 → g (f (⋁⟨ 𝓐 ⟩ 𝕒)))           ＝⟨ dfunext fe (λ 𝕒 → ap (λ - → g (- 𝕒)) s₀) ⟩
       (λ 𝕒 → g (⋁⟨ 𝓑 ⟩ (λ n → f (𝕒 n)))) ＝⟨ dfunext fe (λ 𝕒 → ap (λ - → - (λ n → f (𝕒 n))) s₁) ⟩
       (λ 𝕒 → ⋁⟨ 𝓒 ⟩ (λ n → g (f (𝕒 n)))) ∎

\end{code}

I think I prefer to work with pointwise homomorphisms:

\begin{code}
is-σ-frame-hom : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
               → (⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩) → 𝓤 ⊔ 𝓥 ̇
is-σ-frame-hom  (_ , (⊤ , _∧_ , ⊥ , ⋁) , _) (_ , (⊤' , _∧'_ , ⊥' , ⋁') , _) f =
    (f ⊤ ＝ ⊤')
  × (∀ a b → f (a ∧ b) ＝ f a ∧' f b)
  × (f ⊥ ＝ ⊥')
  × (∀ 𝕒 → f (⋁ 𝕒) ＝ ⋁' (n ↦ f (𝕒 n)))

σ-frame-hom-⊤ : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
              → (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩)
              → is-σ-frame-hom 𝓐 𝓑 f
              → f ⊤⟨ 𝓐 ⟩ ＝ ⊤⟨ 𝓑 ⟩
σ-frame-hom-⊤ 𝓐 𝓑 f (i , ii , iii , vi) = i

σ-frame-hom-∧ : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
              → (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩)
              → is-σ-frame-hom 𝓐 𝓑 f
              → ∀ a b → f (a ∧⟨ 𝓐 ⟩ b) ＝ f a ∧⟨ 𝓑 ⟩ f b
σ-frame-hom-∧ 𝓐 𝓑 f (i , ii , iii , vi) = ii

σ-frame-hom-⊥ : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
              → (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩)
              → is-σ-frame-hom 𝓐 𝓑 f
              → f ⊥⟨ 𝓐 ⟩ ＝ ⊥⟨ 𝓑 ⟩
σ-frame-hom-⊥ 𝓐 𝓑 f (i , ii , iii , vi) = iii

σ-frame-hom-⋁ : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
              → (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩)
              → is-σ-frame-hom 𝓐 𝓑 f
              → ∀ 𝕒 → f (⋁⟨ 𝓐 ⟩ 𝕒) ＝ ⋁⟨ 𝓑 ⟩ (n ↦ f (𝕒 n))
σ-frame-hom-⋁ 𝓐 𝓑 f (i , ii , iii , vi) = vi

being-σ-frame-hom-is-prop : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥)
                          → (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩)
                          → is-prop (is-σ-frame-hom 𝓐 𝓑 f)
being-σ-frame-hom-is-prop (_ , _ ,  _) (_ , _ , (i' , _)) f =

   ×₄-is-prop i' (Π₂-is-prop fe (λ a b → i')) i' (Π-is-prop fe (λ 𝕒 → i'))

id-is-σ-frame-hom : (𝓐 : σ-Frame 𝓤) → is-σ-frame-hom 𝓐 𝓐 id
id-is-σ-frame-hom 𝓐 = refl , (λ a b → refl) , refl , (λ 𝕒 → refl)

∘-σ-frame-hom : (𝓐 : σ-Frame 𝓤) (𝓑 : σ-Frame 𝓥) (𝓒 : σ-Frame 𝓦)
                (f : ⟨ 𝓐 ⟩ → ⟨ 𝓑 ⟩) (g : ⟨ 𝓑 ⟩ → ⟨ 𝓒 ⟩)
              → is-σ-frame-hom 𝓐 𝓑 f
              → is-σ-frame-hom 𝓑 𝓒 g
              → is-σ-frame-hom 𝓐 𝓒 (g ∘ f)
∘-σ-frame-hom 𝓐 𝓑 𝓒 f g (p₀ , q₀ , r₀ , s₀) (p₁ , q₁ , r₁ , s₁) = (p₂ , q₂ , r₂ , s₂)
 where
  p₂ = g (f ⊤⟨ 𝓐 ⟩) ＝⟨ ap g p₀ ⟩
       g ⊤⟨ 𝓑 ⟩     ＝⟨ p₁ ⟩
       ⊤⟨ 𝓒 ⟩       ∎

  q₂ = λ a b → g (f (a ∧⟨ 𝓐 ⟩ b))     ＝⟨ ap g (q₀ a b) ⟩
               g (f a ∧⟨ 𝓑 ⟩ f b)     ＝⟨ q₁ (f a) (f b) ⟩
               g (f a) ∧⟨ 𝓒 ⟩ g (f b) ∎

  r₂ = g (f ⊥⟨ 𝓐 ⟩) ＝⟨ ap g r₀ ⟩
       g ⊥⟨ 𝓑 ⟩     ＝⟨ r₁ ⟩
       ⊥⟨ 𝓒 ⟩       ∎

  s₂ = λ 𝕒 → g (f (⋁⟨ 𝓐 ⟩ 𝕒))           ＝⟨ ap g (s₀ 𝕒) ⟩
             g (⋁⟨ 𝓑 ⟩ (λ n → f (𝕒 n))) ＝⟨ s₁ (λ n → f (𝕒 n)) ⟩
             ⋁⟨ 𝓒 ⟩ (λ n → g (f (𝕒 n))) ∎

import OrderedTypes.sigma-sup-lattice

private σ-SupLat = OrderedTypes.sigma-sup-lattice.σ-SupLat fe

σ-frames-are-σ-suplats : σ-Frame 𝓤 → σ-SupLat 𝓤 𝓤
σ-frames-are-σ-suplats 𝓑  = ⟨ 𝓑 ⟩ ,
                            (⊥⟨ 𝓑 ⟩ , ⋁⟨ 𝓑 ⟩) ,
                            (λ x y → x ∧⟨ 𝓑 ⟩ y ＝ x) ,
                            (λ x y → ⟨ 𝓑 ⟩-is-set) ,
                            (⟨ 𝓑 ⟩-refl) ,
                            ⟨ 𝓑 ⟩-trans ,
                            ⟨ 𝓑 ⟩-antisym ,
                            ⟨ 𝓑 ⟩-⊥-minimum ,
                            ⟨ 𝓑 ⟩-⋁-is-ub ,
                            ⟨ 𝓑 ⟩-⋁-is-lb-of-ubs

open import OrderedTypes.Frame fe

frames-are-sigma-frames : Frame 𝓤 𝓤₀ → σ-Frame 𝓤
frames-are-sigma-frames (X , (⊤ , _∧_ , ⋁) , i , ii , iii , iv , v , vi , vii , viii) =
                        (X , (⊤ , _∧_ , ⋁ unique-from-𝟘 , ⋁ {ℕ}) , i , ii , iii , iv ,
                        (λ x → viii unique-from-𝟘 x (λ (n : 𝟘) → 𝟘-elim n)) ,
                        v , (λ x y → vi x {ℕ} y) , vii {ℕ} , viii {ℕ})

open import UF.PropTrunc

module _ (pe : Prop-Ext)
         (pt  : propositional-truncations-exist)
       where

 Ω-qua-σ-frame : σ-Frame (𝓤 ⁺)
 Ω-qua-σ-frame {𝓤} = frames-are-sigma-frames (Ω-qua-frame pe pt 𝓤₀ 𝓤)

 Ω-qua-σ-suplat : σ-SupLat (𝓤 ⁺) (𝓤 ⁺)
 Ω-qua-σ-suplat {𝓤} = σ-frames-are-σ-suplats (Ω-qua-σ-frame {𝓤})

\end{code}
