--------------------------------------------------------------------------------
title: The spectrum of a distributive lattice
author: Ayberk Tosun
date-started: 2024-02-21
date-completed: 2024-03-01
--------------------------------------------------------------------------------
We define the spectrum locale over a distributive lattice `L`, the defining
frame of which is the frame of ideals over `L`.
\begin{code}
{-# OPTIONS --safe --without-K #-}
open import UF.PropTrunc
open import UF.FunExt
open import UF.Subsingletons
module Locales.DistributiveLattice.Spectrum
(fe : Fun-Ext)
(pe : Prop-Ext)
(pt : propositional-truncations-exist)
where
open import Locales.DistributiveLattice.Definition fe pt
open import Locales.DistributiveLattice.Ideal pt fe pe
open import Locales.DistributiveLattice.Properties fe pt
open import Locales.Frame pt fe hiding (is-directed)
open import MLTT.List hiding ([_])
open import MLTT.Spartan
open import Slice.Family
open import UF.Logic
open import UF.Powerset-MultiUniverse
open import UF.SubtypeClassifier
open AllCombinators pt fe renaming (_∧_ to _∧ₚ_; _∨_ to _∨ₚ_)
open PropositionalSubsetInclusionNotation fe
open PropositionalTruncation pt hiding (_∨_)
\end{code}
We work with a fixed distributive lattice `L` in this module.
\begin{code}
module DefnOfFrameOfIdeal (L : DistributiveLattice 𝓤) where
open DistributiveLattice L renaming (X-is-set to σ)
\end{code}
We denote by `_⊆ᵢ_` the inclusion ordering between two ideals.
\begin{code}
_⊆ᵢ_ : Ideal L → Ideal L → Ω (𝓤)
ℐ₁ ⊆ᵢ ℐ₂ = Ɐ x ꞉ ∣ L ∣ᵈ , x ∈ₚ I₁ ⇒ x ∈ₚ I₂
where
open Ideal ℐ₁ renaming (I to I₁)
open Ideal ℐ₂ renaming (I to I₂)
infix 30 _⊆ᵢ_
⊆ᵢ-is-reflexive : (I : Ideal L) → I ⊆ᵢ I holds
⊆ᵢ-is-reflexive _ _ = id
⊆ᵢ-is-transitive : (I₁ I₂ I₃ : Ideal L) → (I₁ ⊆ᵢ I₂ ⇒ I₂ ⊆ᵢ I₃ ⇒ I₁ ⊆ᵢ I₃) holds
⊆ᵢ-is-transitive I₁ I₂ I₃ p q x r = q x (p x r)
⊆ᵢ-is-antisymmetric : {I₁ I₂ : Ideal L}
→ I₁ ⊆ᵢ I₂ holds → I₂ ⊆ᵢ I₁ holds → I₁ = I₂
⊆ᵢ-is-antisymmetric {I₁} {I₂} = ideal-extensionality L I₁ I₂
⊆ᵢ-is-partial-order : is-partial-order (Ideal L) _⊆ᵢ_
⊆ᵢ-is-partial-order = (⊆ᵢ-is-reflexive , ⊆ᵢ-is-transitive) , ⊆ᵢ-is-antisymmetric
poset-of-ideals : Poset (𝓤 ⁺) 𝓤
poset-of-ideals = Ideal L
, _⊆ᵢ_
, (⊆ᵢ-is-reflexive , ⊆ᵢ-is-transitive)
, ⊆ᵢ-is-antisymmetric
\end{code}
We denote by `𝟏ᵢ` the top ideal, which is the principal ideal on the top element
of the lattice `L`.
\begin{code}
open PrincipalIdeals L
𝟏ᵢ : Ideal L
𝟏ᵢ = principal-ideal 𝟏
𝟏ᵢ-is-top : (I : Ideal L) → (I ⊆ᵢ 𝟏ᵢ) holds
𝟏ᵢ-is-top I x _ = 𝟏ᵈ-is-top L x
\end{code}
The binary meets of two ideals `I₁` and `I₂` is just the set intersection
`I₁ ∩ I₂`. We denote this by `I₁ ∧ᵢ I₂`.
\begin{code}
_∧ᵢ_ : Ideal L → Ideal L → Ideal L
ℐ₁ ∧ᵢ ℐ₂ =
record
{ I = I₁ ∩ I₂
; I-is-inhabited = ∣ 𝟎 , I₁-contains-𝟎 , I₂-contains-𝟎 ∣
; I-is-downward-closed = †
; I-is-closed-under-∨ = ‡
}
where
open Ideal ℐ₁ renaming (I to I₁; I-contains-𝟎 to I₁-contains-𝟎)
open Ideal ℐ₂ renaming (I to I₂; I-contains-𝟎 to I₂-contains-𝟎)
† : is-downward-closed L (I₁ ∩ I₂) holds
† x y p (q₁ , q₂) = Ideal.I-is-downward-closed ℐ₁ x y p q₁
, Ideal.I-is-downward-closed ℐ₂ x y p q₂
‡ : is-closed-under-binary-joins L (I₁ ∩ I₂) holds
‡ x y (p₁ , p₂) (q₁ , q₂) = Ideal.I-is-closed-under-∨ ℐ₁ x y p₁ q₁
, Ideal.I-is-closed-under-∨ ℐ₂ x y p₂ q₂
infix 32 _∧ᵢ_
open Meets _⊆ᵢ_
∧ᵢ-is-lower : (I₁ I₂ : Ideal L)
→ ((I₁ ∧ᵢ I₂) is-a-lower-bound-of (I₁ , I₂)) holds
∧ᵢ-is-lower I₁ I₂ = (λ _ → pr₁) , (λ _ → pr₂)
∧ᵢ-is-greatest : (I₁ I₂ I₃ : Ideal L)
→ (I₃ is-a-lower-bound-of (I₁ , I₂) ⇒ I₃ ⊆ᵢ (I₁ ∧ᵢ I₂)) holds
∧ᵢ-is-greatest I₁ I₂ I₃ (φ , ψ) x p = φ x p , ψ x p
∧ᵢ-is-glb : (I₁ I₂ : Ideal L) → ((I₁ ∧ᵢ I₂) is-glb-of (I₁ , I₂)) holds
∧ᵢ-is-glb I₁ I₂ = ∧ᵢ-is-lower I₁ I₂ , λ { (I₃ , p) → ∧ᵢ-is-greatest I₁ I₂ I₃ p}
\end{code}
We now begin to do some preparation for the construction of small joins of
ideals. We first define the covering relation `xs ◁ ( Iⱼ )_{j : J}` which
expresses that a list `xs` of elements of the lattice `L` is contained in the
union of ideals `⋃_{j : J} I_j`. Intuitively, this just says: for every `x` in
`xs`, there is an ideal `Iⱼ` with `x ∈ Iⱼ`.
\begin{code}
open IdealNotation L
open binary-unions-of-subsets pt
infix 30 covering-syntax
covering-syntax : (S : Fam 𝓤 (Ideal L)) → List ∣ L ∣ᵈ → 𝓤 ̇
covering-syntax S [] = 𝟙
covering-syntax S (x ∷ xs) =
(Σ i ꞉ index S , x ∈ᵢ (S [ i ]) holds) × covering-syntax S xs
syntax covering-syntax S xs = xs ◁ S
\end{code}
Below are some simple lemmas about the covering relation.
\begin{code}
covering-cons : (S : Fam 𝓤 (Ideal L)) {x : ∣ L ∣ᵈ} {xs : List ∣ L ∣ᵈ}
→ (x ∷ xs) ◁ S → xs ◁ S
covering-cons S (_ , c) = c
covering-lemma : (S : Fam 𝓤 (Ideal L)) (xs : List ∣ L ∣ᵈ)
→ xs ◁ S
→ (x : ∣ L ∣ᵈ) → member x xs → Σ i ꞉ index S , x ∈ⁱ (S [ i ])
covering-lemma S [] p x ()
covering-lemma S (x ∷ xs) ((i , r) , q) x in-head = i , r
covering-lemma S (x ∷ xs) p x′ (in-tail r) = IH
where
IH : Σ i ꞉ index S , x′ ∈ᵢ (S [ i ]) holds
IH = covering-lemma S xs (covering-cons S p) x′ r
covering-++ : (S : Fam 𝓤 (Ideal L)) (xs ys : List ∣ L ∣ᵈ)
→ xs ◁ S → ys ◁ S → (xs ++ ys) ◁ S
covering-++ S [] [] _ q = q
covering-++ S [] ys@(_ ∷ _) _ q = q
covering-++ S xs@(_ ∷ _) [] p q = transport
(λ - → - ◁ S)
([]-right-neutral xs)
p
covering-++ S (x ∷ xs) (y ∷ ys) ((i , r) , p₂) q =
(i , r) , covering-++ S xs (y ∷ ys) p₂ q
covering-intersection : (S : Fam 𝓤 (Ideal L)) (I : Ideal L) (xs : List ∣ L ∣ᵈ)
→ join-listᵈ L xs ∈ⁱ I
→ xs ◁ S
→ xs ◁ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆
covering-intersection S I [] _ _ = ⋆
covering-intersection S I (x ∷ xs) p ((i , r) , c) =
(i , q , r) , covering-intersection S I xs p′ c
where
open Ideal I using (I-is-downward-closed)
† : (join-listᵈ L xs ≤ᵈ[ L ] join-listᵈ L (x ∷ xs)) holds
† = ∨-is-an-upper-bound₂ L x (join-listᵈ L xs)
q : x ∈ⁱ I
q = I-is-downward-closed
x
(join-listᵈ L (x ∷ xs))
(∨-is-an-upper-bound₁ L x (join-listᵈ L xs)) p
p′ : join-listᵈ L xs ∈ⁱ I
p′ = I-is-downward-closed (join-listᵈ L xs) (join-listᵈ L (x ∷ xs)) † p
covering-∧ : (S : Fam 𝓤 (Ideal L)) (x : ∣ L ∣ᵈ) (xs : List ∣ L ∣ᵈ)
→ xs ◁ S → map (x ∧_) xs ◁ S
covering-∧ S x [] q = q
covering-∧ S y (x ∷ xs) ((i , r) , c) = (i , †) , covering-∧ S y xs c
where
open Ideal (S [ i ]) renaming (I to I₁;
I-is-downward-closed to Sᵢ-is-downward-closed)
† : (y ∧ x) ∈ᵢ (S [ i ]) holds
† = Sᵢ-is-downward-closed (y ∧ x) x (∧-is-a-lower-bound₂ L y x) r
\end{code}
The lemma below captures the fact that covers of lists always have a finite
subcover.
\begin{code}
open Locale
open import Locales.DirectedFamily pt fe _⊆ᵢ_
finite-subcover : (S : Fam 𝓤 (Ideal L)) (xs : List ∣ L ∣ᵈ)
→ is-directed S holds
→ xs ◁ S
→ ∃ i ꞉ index S , join-listᵈ L xs ∈ᵢ (S [ i ]) holds
finite-subcover S [] δ c = ∥∥-rec ∃-is-prop γ (directed-implies-inhabited S δ)
where
γ : index S → ∃ i ꞉ index S , join-listᵈ L [] ∈ⁱ (S [ i ])
γ i = ∣ i , Sᵢ-contains-𝟎 ∣
where
open Ideal (S [ i ]) renaming (I-contains-𝟎 to Sᵢ-contains-𝟎)
finite-subcover S (x ∷ xs) δ ((i , μ) , c) = ∥∥-rec ∃-is-prop † IH
where
IH : ∃ i ꞉ index S , join-listᵈ L xs ∈ᵢ (S [ i ]) holds
IH = finite-subcover S xs δ c
† : Σ i ꞉ index S , join-listᵈ L xs ∈ⁱ (S [ i ])
→ ∃ k ꞉ index S , join-listᵈ L (x ∷ xs) ∈ⁱ (S [ k ])
† (j , p) = ∥∥-rec ∃-is-prop ‡ (pr₂ δ i j)
where
‡ : Σ k ꞉ index S , ((S [ i ]) ⊆ᵢ (S [ k ]) ∧ₚ (S [ j ]) ⊆ᵢ (S [ k ])) holds
→ ∃ k ꞉ index S , join-listᵈ L (x ∷ xs) ∈ⁱ (S [ k ])
‡ (k , μ₁ , μ₂) =
∣ k , Sᵢ-is-closed-under-∨ x (join-listᵈ L xs ) (μ₁ x μ) (μ₂ (join-listᵈ L xs) p) ∣
where
open Ideal (S [ k ]) renaming (I-is-closed-under-∨ to Sᵢ-is-closed-under-∨)
\end{code}
We are now ready to define the join. Given a family `( Iⱼ )_{j : J}` of ideals,
their union is given by the family:
{ (⋁ F) ∣ F ⊆ (⋃_{j : J} I_j), F finite}.
We capture finiteness using lists instead (which amounts to Kuratowski
finiteness).
We start by defining a preliminary version of the join operation that gives the
underlying subset of the ideal. We then proceed to prove that this forms an
ideal.
\begin{code}
⋁⁰ᵢ_ : Fam 𝓤 (Ideal L) → 𝓟 {𝓤} ∣ L ∣ᵈ
⋁⁰ᵢ_ S = λ y → Ǝ xs ꞉ List ∣ L ∣ᵈ , xs ◁ S × (y = join-listᵈ L xs)
infix 41 ⋁⁰ᵢ_
\end{code}
It is easy to see that this operation gives subsets that are closed under binary
joins.
\begin{code}
ideal-join-is-closed-under-∨ : (I : Fam 𝓤 (Ideal L))
→ is-closed-under-binary-joins L (⋁⁰ᵢ I) holds
ideal-join-is-closed-under-∨ S x y μ₁ μ₂ =
∥∥-rec₂ (holds-is-prop ((x ∨ y) ∈ₚ ⋁⁰ᵢ S)) † μ₁ μ₂
where
† : Σ xs ꞉ List X , xs ◁ S × (x = join-listᵈ L xs)
→ Σ ys ꞉ List X , ys ◁ S × (y = join-listᵈ L ys)
→ (x ∨ y) ∈ (⋁⁰ᵢ S)
† (xs , c₁ , p₁) (ys , c₂ , p₂) = ∣ (xs ++ ys) , c , p ∣
where
c : (xs ++ ys) ◁ S
c = covering-++ S xs ys c₁ c₂
p : (x ∨ y) = join-listᵈ L (xs ++ ys)
p = x ∨ y =⟨ Ⅰ ⟩
join-listᵈ L xs ∨ y =⟨ Ⅱ ⟩
join-listᵈ L xs ∨ join-listᵈ L ys =⟨ Ⅲ ⟩
join-listᵈ L (xs ++ ys) ∎
where
Ⅰ = ap (_∨ y) p₁
Ⅱ = ap (join-listᵈ L xs ∨_) p₂
Ⅲ = join-list-maps-∨-to-++ L xs ys
\end{code}
The operation `⋁⁰ᵢ_` gives subsets that are downward closed.
\begin{code}
ideal-join-is-downward-closed : (S : Fam 𝓤 (Ideal L))
→ is-downward-closed L (⋁⁰ᵢ S) holds
ideal-join-is-downward-closed S x y q = ∥∥-rec (holds-is-prop (x ∈ₚ ⋁⁰ᵢ S)) †
where
open PosetReasoning (poset-ofᵈ L)
† : Σ ys ꞉ List X , ys ◁ S × (y = join-listᵈ L ys) → x ∈ (⋁⁰ᵢ S)
† (ys , c , p) = ∣ map (x ∧_) ys , c′ , r ∣
where
c′ : map (x ∧_) ys ◁ S
c′ = covering-∧ S x ys c
Ⅰ : (x ≤ᵈ[ L ] join-listᵈ L ys) holds
Ⅰ = x ≤⟨ q ⟩ y =⟨ p ⟩ₚ join-listᵈ L ys ■
Ⅱ = finite-distributivity L ys x
r : x = join-listᵈ L (map (x ∧_) ys)
r = x =⟨ Ⅰ ⁻¹ ⟩
x ∧ join-listᵈ L ys =⟨ Ⅱ ⟩
join-listᵈ L (map (x ∧_) ys) ∎
\end{code}
We package the proofs up into the following join operation `⋁ᵢ_`.
\begin{code}
⋁ᵢ_ : Fam 𝓤 (Ideal L) → Ideal L
⋁ᵢ S = record
{ I = ⋁⁰ᵢ S
; I-is-inhabited = ∣ 𝟎 , ∣ [] , (⋆ , refl) ∣ ∣
; I-is-downward-closed = ideal-join-is-downward-closed S
; I-is-closed-under-∨ = ideal-join-is-closed-under-∨ S
}
\end{code}
It is obvious that this gives contains all the ideals in the family.
\begin{code}
⋁ᵢ-is-an-upper-bound : (S : Fam 𝓤 (Ideal L))
→ (i : index S) → (S [ i ]) ⊆ᵢ (⋁ᵢ S) holds
⋁ᵢ-is-an-upper-bound S i x p = ∣ (x ∷ []) , † , (∨-unit x ⁻¹) ∣
where
open Ideal (S [ i ]) renaming (I-is-downward-closed
to Sᵢ-is-downward-closed)
† : (x ∷ []) ◁ S
† = (i , p) , ⋆
\end{code}
The fact that it is a least upper bound is not as trivial and uses the
`covering-lemma` we gave above.
\begin{code}
open Joins _⊆ᵢ_
⋁ᵢ-is-least : (S : Fam 𝓤 (Ideal L))
→ (Iᵤ : Ideal L)
→ (Iᵤ is-an-upper-bound-of S ⇒ (⋁ᵢ S) ⊆ᵢ Iᵤ) holds
⋁ᵢ-is-least S Iᵤ υ x = ∥∥-rec (holds-is-prop (x ∈ᵢ Iᵤ)) †
where
† : Σ xs ꞉ List X , xs ◁ S × (x = join-listᵈ L xs) → x ∈ᵢ Iᵤ holds
† (xs , c , r) = transport
(λ - → - ∈ᵢ Iᵤ holds)
(r ⁻¹)
(ideals-are-closed-under-finite-joins L Iᵤ xs φ)
where
φ : ((x , _) : type-from-list xs) → x ∈ᵢ Iᵤ holds
φ (x , μ) = υ iₓ x ν
where
θ : Σ i ꞉ index S , x ∈ᵢ (S [ i ]) holds
θ = covering-lemma S xs c x μ
iₓ = pr₁ θ
ν : (x ∈ᵢ (S [ iₓ ])) holds
ν = pr₂ θ
\end{code}
Finally, we prove the distributivity law.
\begin{code}
distributivityᵢ : (I : Ideal L) (S : Fam 𝓤 (Ideal L))
→ I ∧ᵢ (⋁ᵢ S) = ⋁ᵢ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆
distributivityᵢ I S = ⊆ᵢ-is-antisymmetric † ‡
where
† : I ∧ᵢ (⋁ᵢ S) ⊆ᵢ (⋁ᵢ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆) holds
† x (μ₁ , μ₂) =
∥∥-rec (holds-is-prop (x ∈ᵢ (⋁ᵢ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆))) γ μ₂
where
γ : Σ xs ꞉ List X , xs ◁ S × (x = join-listᵈ L xs)
→ x ∈ᵢ (⋁ᵢ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆) holds
γ (xs , c , r) = ∣ xs , c′ , r ∣
where
μ : join-listᵈ L xs ∈ᵢ I holds
μ = transport (λ - → - ∈ᵢ I holds) r μ₁
c′ : xs ◁ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆
c′ = covering-intersection S I xs μ c
‡ : (⋁ᵢ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆) ⊆ᵢ (I ∧ᵢ (⋁ᵢ S)) holds
‡ x p = ∥∥-rec (holds-is-prop (x ∈ᵢ (I ∧ᵢ (⋁ᵢ S)))) γ p
where
open PosetReasoning (poset-ofᵈ L)
γ : Σ xs ꞉ List X ,
xs ◁ ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆ × (x = join-listᵈ L xs)
→ x ∈ᵢ I ∧ᵢ (⋁ᵢ S) holds
γ (xs , c , r) = μ₁ , μ₂
where
ϟ : (x : ∣ L ∣ᵈ)
→ member x xs
→ Σ i ꞉ index S , x ∈ᵢ I ∧ᵢ (S [ i ]) holds
ϟ x μ = covering-lemma ⁅ I ∧ᵢ (S [ i ]) ∣ i ∶ index S ⁆ xs c x μ
ϵ : ((x , μ) : type-from-list xs) → x ∈ⁱ I
ϵ (x , μ) = pr₁ (pr₂ (ϟ x μ))
δ : join-listᵈ L xs ∈ⁱ I
δ = ideals-are-closed-under-finite-joins L I xs ϵ
μ₁ : x ∈ᵢ I holds
μ₁ = transport (λ - → (- ∈ᵢ I) holds) (r ⁻¹) δ
ι : ((x , μ) : type-from-list xs) → x ∈ᵢ (⋁ᵢ S) holds
ι (x , μ) = ⋁ᵢ-is-an-upper-bound S iₓ x μ′
where
ν : Σ i ꞉ index S , x ∈ⁱ I ∧ᵢ (S [ i ])
ν = ϟ x μ
iₓ : index S
iₓ = pr₁ ν
μ′ : x ∈ⁱ (S [ iₓ ])
μ′ = pr₂ (pr₂ ν)
θ : join-listᵈ L xs ∈ⁱ (⋁ᵢ S)
θ = ideals-are-closed-under-finite-joins L (⋁ᵢ S) xs ι
μ₂ : x ∈ᵢ (⋁ᵢ S) holds
μ₂ = transport (λ - → - ∈ᵢ (⋁ᵢ S) holds) (r ⁻¹) θ
\end{code}
We are now ready to package everything up as a frame.
\begin{code}
frame-of-ideals : Frame (𝓤 ⁺) 𝓤 𝓤
frame-of-ideals =
Ideal L
, (_⊆ᵢ_ , 𝟏ᵢ , _∧ᵢ_ , ⋁ᵢ_)
, ⊆ᵢ-is-partial-order
, 𝟏ᵢ-is-top
, (λ (I₁ , I₂) → ∧ᵢ-is-lower I₁ I₂ , λ (I₃ , lb) → ∧ᵢ-is-greatest I₁ I₂ I₃ lb)
, (λ S → ⋁ᵢ-is-an-upper-bound S , λ (I , ub) → ⋁ᵢ-is-least S I ub)
, λ { (I , S) → distributivityᵢ I S}
\end{code}
This is the frame of opens of the “spectrum space” of the distributive lattice
`L`. Because we work with locales as our notion of space, we just take the
locale that this frame defines as the spectrum over the distributive lattice
`L`.
\begin{code}
spectrum : Locale (𝓤 ⁺) 𝓤 𝓤
spectrum = record
{ ⟨_⟩ₗ = Ideal L
; frame-str-of = pr₂ frame-of-ideals}
\end{code}