module Order.Lattice where

Lattices🔗

A lattice is a poset which is a semilattice in two compatible, dual ways. We have a “meet” semilattice (A,,)(A, \cap, \top), and a “join” semilattice (A,,)(A, \cup, \bot) — and we take the order on AA induced by, for definiteness, the \cap semilattice. The question is then: how do we write, algebraically, a condition on \cap and \cup which guarantees that \cup provides (A,)(A, \le) with joins?

The answer is yes! Of course, since if it were not, this page would not be being written. A lattice structure on (A,,,,)(A, \top, \bot, \cap, \cup) is a pair of semilattices (A,,)(A, \cap, \top) and (A,,)(A, \cup, \bot), such that the \cap and \cup operations satisfy the two absorption laws with respect to eachother:

  field
    has-meets : is-semilattice ⊤ __
    has-joins : is-semilattice ⊥ __

    ∩-absorbs-∪ :  {x y}  x ∩ (x ∪ y) ≡ x
    ∪-absorbs-∩ :  {x y}  x ∪ (x ∩ y) ≡ x

As usual, a lattice structure on a set is a record packaging together the operations and a proof that they are actually an instance of the algebraic structure we’re talking about.

record Lattice-on {} (A : Type ℓ) : Type ℓ where
  no-eta-equality
  field
    top : A
    bot : A
    __ : A  A  A
    __ : A  A  A
    has-is-lattice : is-lattice top __ bot __

  open is-lattice has-is-lattice public

  meets : Semilattice-on A
  meets = record { has-is-semilattice = has-meets }

  joins : Semilattice-on A
  joins = record { has-is-semilattice = has-joins }

  open Semilattice-on meets using () public
  private module x = Semilattice-on joins renaming (to)
  open x using () public

The question then becomes: what is the point of the absorption laws? I’ll tell you! Since we have two semilattice structures on the set, we can imagine defining two orders on it: one is given by xyx \le y iff x=xyx = x \cap y, and the other is given by y=xyy = x \cup y. As an exercise, try to work out that these are the same thing in the lattice of subsets of a fixed AA.

Really, there are four orderings we could imagine defining on a semilattice: xyx \le y iff. x=xyx = x \cap y, y=xyy = x \cap y, x=xyx = x \cup y, and y=xyy = x \cup y. The absorption laws serve to cut these possibilities in half, because using them we can show that x=xyx = x \cap y is the same as y=xyy = x \cup y (and, respectively, y=xyy = x \cap y is the same as x=xyx = x \cup y).

  ∪-order→∩-order :  {x y}  y ≡ x ∪ y  x ≡ x ∩ y
  ∪-order→∩-order {x} {y} y=x∪y =
    x             ≡˘⟨ ∩-absorbs-∪ ⟩
    x ∩ ⌜ x ∪ y ⌝ ≡˘⟨ ap¡ y=x∪y ⟩
    x ∩ y         ∎

  ∩-order→∪-order :  {x y}  x ≡ x ∩ y  y ≡ x ∪ y
  ∩-order→∪-order {x} {y} p =
    y             ≡⟨ sym ∪-absorbs-∩ ⟩
    y ∪ ⌜ y ∩ x ⌝ ≡⟨ ap! ∩-commutative ⟩
    y ∪ ⌜ x ∩ y ⌝ ≡˘⟨ ap¡ p ⟩
    y ∪ x         ≡⟨ ∪-commutative ⟩
    x ∪ y         ∎

Using the “cup ordering”, we can establish that cups provide a join of two elements. Since the cup ordering and the “cap ordering” agree, we can prove that cups give a join in that case, too!

  ∪-is-join :  {x y}  is-join Lattice→poset x y (x ∪ y)
  ∪-is-join .is-join.l≤join = sym ∩-absorbs-∪
  ∪-is-join {x} {y} .is-join.r≤join =
    y             ≡˘⟨ ∩-absorbs-∪ ⟩
    y ∩ ⌜ y ∪ x ⌝ ≡⟨ ap! ∪-commutative ⟩
    y ∩ (x ∪ y)
  ∪-is-join {x} {y} .is-join.least ub' x=x∩ub' y=y∩ub' = ∪-order→∩-order $ sym $
    (x ∪ y) ∪ ub'   ≡˘⟨ ∪-associative ⟩
    x ∪ ⌜ y ∪ ub' ⌝ ≡˘⟨ ap¡ (∩-order→∪-order y=y∩ub')
    x ∪ ub'         ≡˘⟨ ∩-order→∪-order x=x∩ub' ⟩
    ub'             ∎

  ⊥-is-bottom :  {x}  bot P.≤ x
  ⊥-is-bottom = ∪-order→∩-order (sym ∪-idl)

Category of lattices🔗

A lattice homomorphism is a function which is, at the same time, a homomorphism for both of the semilattice monoid structures: A function sending bottom to bottom, top to top, joins to joins, and meets to meets. Put more concisely, a function which preserves finite meets and finite joins.

record
  is-lattice-hom
    {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'}
    (f : A  B)
    (S : Lattice-on A) (T : Lattice-on B)
    : Type (ℓ ⊔ ℓ')
  where

  private
    module S = Lattice-on S
    module T = Lattice-on T

  field
    pres-⊤ : f S.top ≡ T.top
    pres-⊥ : f S.bot ≡ T.bot
    pres-∩ :  {x y}  f (x S.∩ y) ≡ f x T.∩ f y
    pres-∪ :  {x y}  f (x S.∪ y) ≡ f x T.∪ f y

Standard equational nonsense implies that (a) lattices and lattice homomorphisms form a precategory; and (b) this is a univalent category.

Lattice-structure :  Thin-structure ℓ Lattice-on

Lattice-structure ℓ .is-hom f S T ._= is-lattice-hom f S T
Lattice-structure ℓ .is-hom f S T .is-tr = hlevel!

Lattice-structure ℓ .id-is-hom .pres-⊤ = refl
Lattice-structure ℓ .id-is-hom .pres-⊥ = refl
Lattice-structure ℓ .id-is-hom .pres-∩ = refl
Lattice-structure ℓ .id-is-hom .pres-∪ = refl

Lattice-structure ℓ .∘-is-hom f g α β .pres-⊤ = ap f (β .pres-⊤) ∙ α .pres-⊤
Lattice-structure ℓ .∘-is-hom f g α β .pres-⊥ = ap f (β .pres-⊥) ∙ α .pres-⊥
Lattice-structure ℓ .∘-is-hom f g α β .pres-∩ = ap f (β .pres-∩) ∙ α .pres-∩
Lattice-structure ℓ .∘-is-hom f g α β .pres-∪ = ap f (β .pres-∪) ∙ α .pres-∪

Univalence follows from the special case of considering the identity as a lattice homomorphism (A,s)(A,t)(A, s) \to (A, t) — preservation of the operations guarantees that we get s=t\top_s = \top_t (for each operation; \bot, \cap and \cup), which eventually gives s=ts = t.

Lattice-structure ℓ .id-hom-unique {s = s} {t = t} α _ = p where
  open Lattice-on
  p : s ≡ t
  p i .top = α .pres-⊤ i
  p i .bot = α .pres-⊥ i
  p i .__ x y = α .pres-∩ {x} {y} i
  p i .__ x y = α .pres-∪ {x} {y} i
  p i .has-is-lattice =
    is-prop→pathp
       i  hlevel {T = is-lattice (α .pres-⊤ i)  x y  α .pres-∩ i)
                                    (α .pres-⊥ i)  x y  α .pres-∪ i)}
        1)
      (s .has-is-lattice) (t .has-is-lattice) i

Lattices :  Precategory (lsuc ℓ)
Lattices ℓ = Structured-objects (Lattice-structure ℓ)