---
title:          SIP for distributive lattices
author:         Ayberk Tosun
date-started:   2024-05-16
---

\begin{code}[hide]

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

open import MLTT.Spartan hiding (𝟚; ₀; ₁)
open import UF.FunExt
open import UF.PropTrunc
open import UF.Size
open import UF.Subsingletons
open import UF.UA-FunExt
open import UF.Univalence

module Locales.SIP.DistributiveLatticeSIP
        (ua : Univalence)
        (pt : propositional-truncations-exist)
        (sr : Set-Replacement pt)
       where

private
 fe : Fun-Ext
 fe {𝓤} {𝓥} = univalence-gives-funext' 𝓤 𝓥 (ua 𝓤) (ua (𝓤 ⊔ 𝓥))

 pe : Prop-Ext
 pe {𝓤} = univalence-gives-propext (ua 𝓤)

open import Locales.DistributiveLattice.Definition fe pt
open import Locales.DistributiveLattice.Definition-SigmaBased fe pt
open import Locales.DistributiveLattice.Homomorphism fe pt
open import Locales.DistributiveLattice.Isomorphism fe pt
open import Locales.Frame pt fe
open import UF.Base
open import UF.Equiv
open import UF.Logic
open import UF.SIP
open import UF.SubtypeClassifier

open AllCombinators pt fe
open sip hiding (⟨_⟩)

\end{code}

We work in a module parameterized by two distributive lattice structures that
we call `str₁` and `str₂`.

\begin{code}

module SIP-For-Distributive-Lattices
        {A : 𝓤  ̇}
        (str₁ str₂ : Distributive-Lattice-Structure A)
       where

\end{code}

We denote by `K` and `L` the distributive lattices `(A , str₁)` and `(B , str₂)`.

\begin{code}

 K : Distributive-Lattice₀ 𝓤
 K = A , str₁

 L : Distributive-Lattice₀ 𝓤
 L = A , str₂

\end{code}

To avoid using projections, we also define the record-based versions of these
two distributive lattices.

\begin{code}

 private
  Kᵣ : DistributiveLattice 𝓤
  Kᵣ = to-distributive-lattice 𝓤 K

  Lᵣ : DistributiveLattice 𝓤
  Lᵣ = to-distributive-lattice 𝓤 L

\end{code}

We define a bunch of other abbreviations that we will use throughout this
module.

\begin{code}

 lattice-data-of-K : Distributive-Lattice-Data A
 lattice-data-of-K = pr₁ str₁

 lattice-data-of-L : Distributive-Lattice-Data A
 lattice-data-of-L = pr₁ str₂

 _≤₁_ : A → A → Ω 𝓤
 _≤₁_ = λ x y → x ≤[ poset-ofᵈ Kᵣ ] y

 _≤₂_ : A → A → Ω 𝓤
 _≤₂_ = λ x y → x ≤[ poset-ofᵈ Lᵣ  ] y

 𝟏₁ : A
 𝟏₁ = DistributiveLattice.𝟏 Kᵣ

 𝟏₂ : A
 𝟏₂ = DistributiveLattice.𝟏 Lᵣ

 𝟎₁ : A
 𝟎₁ = DistributiveLattice.𝟎 Kᵣ

 𝟎₂ : A
 𝟎₂ = DistributiveLattice.𝟎 Lᵣ

 _∧₁_ : A → A → A
 _∧₁_ = λ x y → x ∧∙ y
  where
   open DistributiveLattice Kᵣ renaming (_∧_ to _∧∙_)

 _∧₂_ : A → A → A
 _∧₂_ = λ x y → x ∧∙ y
  where
   open DistributiveLattice Lᵣ renaming (_∧_ to _∧∙_)

 _∨₁_ : A → A → A
 _∨₁_ = λ x y → x ∨∙ y
  where
   open DistributiveLattice Kᵣ renaming (_∨_ to _∨∙_)

 _∨₂_ : A → A → A
 _∨₂_ = λ x y → x ∨∙ y
  where
   open DistributiveLattice Lᵣ renaming (_∨_ to _∨∙_)

 open HomomorphicEquivalences Kᵣ Lᵣ

 homomorphic-identity-equivalence-gives-order-agreement
  : is-homomorphic (≃-refl ∣ Lᵣ ∣ᵈ) holds
  → _≤₁_ ＝ _≤₂_
 homomorphic-identity-equivalence-gives-order-agreement (𝓂₁ , 𝓂₂) =
  dfunext fe λ x → dfunext fe λ y → † x y
   where
    † : (x y : ∣ Kᵣ ∣ᵈ) → x ≤₁ y ＝ x ≤₂ y
    † x y = ⇔-gives-＝ pe (x ≤₁ y) (x ≤₂ y) ‡
     where
      ‡ : (x ≤₁ y) ⇔ (x ≤₂ y) ＝ ⊤
      ‡ = holds-gives-equal-⊤ pe fe ((x ≤₁ y) ⇔ (x ≤₂ y)) (β , γ)
       where
        β : (x ≤₁ y ⇒ x ≤₂ y) holds
        β = 𝓂₁ (x , y)

        γ : (x ≤₂ y ⇒ x ≤₁ y) holds
        γ = 𝓂₂ (x , y)

\end{code}

The identity equivalence being homomorphic gives the equality of top elements.

\begin{code}

 open DistributiveLatticeIsomorphisms Kᵣ Lᵣ

 homomorphic-identity-equivalence-gives-top-agreement
  : is-homomorphic (≃-refl ∣ Lᵣ ∣ᵈ) holds
  → 𝟏₁ ＝ 𝟏₂
 homomorphic-identity-equivalence-gives-top-agreement 𝒽 = †
  where
   iso : DistributiveLatticeIsomorphisms.Isomorphismᵈᵣ Kᵣ Lᵣ
   iso = to-isomorphismᵈᵣ (≃-refl A , 𝒽)

   † : preserves-𝟏 Kᵣ Lᵣ id holds
   † = Homomorphismᵈᵣ.h-preserves-𝟏 (Isomorphismᵈᵣ.𝓈 iso)

\end{code}

The identity function being homomorphic gives the equality of bottom elements.

\begin{code}

 homomorphic-identity-equivalence-gives-bottom-agreement
  : is-homomorphic (≃-refl ∣ Lᵣ ∣ᵈ) holds
  → 𝟎₁ ＝ 𝟎₂
 homomorphic-identity-equivalence-gives-bottom-agreement 𝒽 = †
  where
   iso : DistributiveLatticeIsomorphisms.Isomorphismᵈᵣ Kᵣ Lᵣ
   iso = to-isomorphismᵈᵣ (≃-refl A , 𝒽)

   † : preserves-𝟎 Kᵣ Lᵣ id holds
   † = Homomorphismᵈᵣ.h-preserves-𝟎 (Isomorphismᵈᵣ.𝓈 iso)

\end{code}

The identity function being homomorphic gives the equality of meets.

\begin{code}

 homomorphic-identity-equivalence-gives-meet-agreement
  : is-homomorphic (≃-refl ∣ Lᵣ ∣ᵈ) holds
  → _∧₁_ ＝ _∧₂_
 homomorphic-identity-equivalence-gives-meet-agreement 𝒽 =
  dfunext fe λ x → dfunext fe λ y → φ x y
   where
    iso : Isomorphismᵈᵣ
    iso = to-isomorphismᵈᵣ (≃-refl A , 𝒽)

    φ : preserves-∧ Kᵣ Lᵣ id holds
    φ = Homomorphismᵈᵣ.h-preserves-∧ (Isomorphismᵈᵣ.𝓈 iso)

\end{code}

The identity function being homomorphic gives join agreement.

\begin{code}

 homomorphic-identity-equivalence-gives-join-agreement
  : is-homomorphic (≃-refl ∣ Lᵣ ∣ᵈ) holds
  → _∨₁_ ＝ _∨₂_
 homomorphic-identity-equivalence-gives-join-agreement 𝒽 =
  dfunext fe λ x → dfunext fe λ y → φ x y
   where
    iso : Isomorphismᵈᵣ
    iso = to-isomorphismᵈᵣ (≃-refl A , 𝒽)

    φ : preserves-∨ Kᵣ Lᵣ id holds
    φ = Homomorphismᵈᵣ.h-preserves-∨ (Isomorphismᵈᵣ.𝓈 iso)


\end{code}

If the identity equivalence is homomorphic, then the two distributive lattice
structures must be equal.

\begin{code}

 abstract
  homomorphic-equivalence-gives-distributive-lattice-data-agreement
   : is-homomorphic (≃-refl A) holds
   → distributive-lattice-data-of A str₁ ＝ distributive-lattice-data-of A str₂
  homomorphic-equivalence-gives-distributive-lattice-data-agreement 𝒽 = β
   where
    ϵ : _∨₁_ ＝ _∨₂_
    ϵ = homomorphic-identity-equivalence-gives-join-agreement 𝒽

    δ : _∧₁_ , _∨₁_ ＝ _∧₂_ , _∨₂_
    δ = transport
         (λ - → _∧₁_ , _∨₁_ ＝ - , _∨₂_)
         (homomorphic-identity-equivalence-gives-meet-agreement 𝒽)
         (to-Σ-＝' ϵ)

    γ : 𝟏₁ , _∧₁_ , _∨₁_ ＝ 𝟏₂ , _∧₂_ , _∨₂_
    γ = transport
         (λ - → 𝟏₁ , _∧₁_ , _∨₁_ ＝ - , _∧₂_ , _∨₂_)
         (homomorphic-identity-equivalence-gives-top-agreement 𝒽)
         (to-Σ-＝' δ)

    β : 𝟎₁ , 𝟏₁ , _∧₁_ , _∨₁_ ＝ 𝟎₂ , 𝟏₂ , _∧₂_ , _∨₂_
    β = transport
         (λ - → 𝟎₁ , 𝟏₁ , _∧₁_ , _∨₁_ ＝ - , 𝟏₂ , _∧₂_ , _∨₂_)
         (homomorphic-identity-equivalence-gives-bottom-agreement 𝒽)
         (to-Σ-＝' γ)

 abstract
  homomorphic-equivalence-gives-structural-equality
   : is-homomorphic (≃-refl A) holds
   → str₁ ＝ str₂
  homomorphic-equivalence-gives-structural-equality 𝒽 =
   to-subtype-＝
    satisfying-distributive-lattice-laws-is-prop
    (homomorphic-equivalence-gives-distributive-lattice-data-agreement 𝒽)

\end{code}

The distributive lattice structure is a standard notion of structure.

\begin{code}

distributive-lattice-sns-data : SNS Distributive-Lattice-Structure 𝓤
distributive-lattice-sns-data {𝓤} = ι , ρ , θ
 where
  ι : (K′ L′ : Distributive-Lattice₀ 𝓤) → sip.⟨ K′ ⟩ ≃ sip.⟨ L′ ⟩ → 𝓤  ̇
  ι K′ L′ e = is-homomorphic e holds
   where
    K′ᵣ = to-distributive-lattice 𝓤 K′
    L′ᵣ = to-distributive-lattice 𝓤 L′

    open HomomorphicEquivalences K′ᵣ L′ᵣ

  ρ : (L : Distributive-Lattice₀ 𝓤) → ι L L (≃-refl sip.⟨ L ⟩)
  ρ L = (λ _ → id) , (λ _ → id)

  θ : {X : 𝓤  ̇}
    → (str₁ str₂ : Distributive-Lattice-Structure X)
    → is-equiv (canonical-map ι ρ str₁ str₂)
  θ {X} str₁ str₂ = (homomorphic-equivalence-gives-structural-equality , †)
                  , (homomorphic-equivalence-gives-structural-equality , ‡)
   where
    open SIP-For-Distributive-Lattices str₁ str₂
    open HomomorphicEquivalences

    Kᵣ = to-distributive-lattice 𝓤 (X , str₁)
    Lᵣ = to-distributive-lattice 𝓤 (X , str₂)

    † : (h : is-homomorphic Kᵣ Lᵣ (≃-refl X) holds)
      → let
         p = homomorphic-equivalence-gives-structural-equality h
        in
         canonical-map ι ρ str₁ str₂ p ＝ h
    † h = holds-is-prop
           (is-homomorphic Kᵣ Lᵣ (≃-refl X))
           (canonical-map ι ρ str₁ str₂ (homomorphic-equivalence-gives-structural-equality h))
           h

    ‡ : (p : str₁ ＝ str₂)
      → homomorphic-equivalence-gives-structural-equality (canonical-map ι ρ str₁ str₂ p) ＝ p
    ‡ p = distributive-lattice-structure-is-set
           X
           pe
           (homomorphic-equivalence-gives-structural-equality (canonical-map ι ρ str₁ str₂ p))
           p

\end{code}

We abbreviate this proof by `snsᵈ`.

\begin{code}

private
 snsᵈ = distributive-lattice-sns-data

\end{code}

The notion of isomorphism given by `snsᵈ` is trivially equivalent to the type
`Isomorphismᵈ₀`.

\begin{code}

 open HomomorphicEquivalences

 isomorphism₀-equivalent-to-sns-isomorphism
  : (K L : Distributive-Lattice₀ 𝓤)
  → let
     Kᵣ = to-distributive-lattice 𝓤 K
     Lᵣ = to-distributive-lattice 𝓤 L
    in
     (K ≃[ snsᵈ ] L) ≃ (Isomorphism₀ Kᵣ Lᵣ)
 isomorphism₀-equivalent-to-sns-isomorphism {𝓤} K L = 𝔰 , qinvs-are-equivs 𝔰 †
  where
   Kᵣ = to-distributive-lattice 𝓤 K
   Lᵣ = to-distributive-lattice 𝓤 L

   𝔰 : K ≃[ snsᵈ ] L → Isomorphism₀ Kᵣ Lᵣ
   𝔰 (f , (e , φ)) = (f , e) , φ

   𝔯 : Isomorphism₀ Kᵣ Lᵣ → K ≃[ snsᵈ ] L
   𝔯 ((f , e) , φ) = f , (e , φ)

   † : qinv 𝔰
   † = 𝔯 , (λ _ → refl) , (λ _ → refl)

\end{code}

From this, we get the characterization of equality for distributive lattices.

\begin{code}

characterization-of-distributive-lattice₀-＝ : (K L : Distributive-Lattice₀ 𝓤)
                                             → (K ＝ L) ≃ (K ≃[ snsᵈ ] L)
characterization-of-distributive-lattice₀-＝ {𝓤} K L =
 characterization-of-＝ (ua 𝓤) snsᵈ K L

characterization-of-distributive-lattice-＝ : (K L : DistributiveLattice 𝓤)
                                            → (K ＝ L) ≃ (K ≅d≅ L)
characterization-of-distributive-lattice-＝ {𝓤} K L =
 let
  K₀ = to-distributive-lattice₀ 𝓤 K
  L₀ = to-distributive-lattice₀ 𝓤 L

  Ⅱ = characterization-of-distributive-lattice₀-＝ K₀ L₀
  Ⅲ = isomorphism₀-equivalent-to-sns-isomorphism K₀ L₀
  Ⅳ = isomorphismᵈᵣ-is-equivalent-to-isomorphism₀ K L

  𝔰 : K ＝ L → K₀ ＝ L₀
  𝔰 = λ { refl → refl }

  𝔯 : K₀ ＝ L₀ → K ＝ L
  𝔯 = λ { refl → refl }

  † : (𝔯 ∘ 𝔰) ∼ id
  † = (λ { refl → refl })

  ‡ : (𝔰 ∘ 𝔯) ∼ id
  ‡ = (λ { refl → refl })

  goal : (K ＝ L) ≃ (K₀ ＝ L₀)
  goal = 𝔰 , qinvs-are-equivs 𝔰 (𝔯 , † , ‡)
 in
  (K ＝ L)           ≃⟨ goal ⟩
  (K₀ ＝ L₀)         ≃⟨ Ⅱ ⟩
  (K₀ ≃[ snsᵈ ] L₀)  ≃⟨ Ⅲ ⟩
  (Isomorphism₀ K L) ≃⟨ Ⅳ ⟩
  (K ≅d≅ L)          ■

\end{code}

Finally, we record the fact that isomorphic distributive lattices are _equal_.

\begin{code}

isomorphic-distributive-lattices-are-equal
 : (K L : DistributiveLattice 𝓤)
 → K ≅d≅ L
 → K ＝ L
isomorphic-distributive-lattices-are-equal K L =
 ⌜ ≃-sym (characterization-of-distributive-lattice-＝ K L) ⌝

\end{code}
