---
layout: default
file: "src/Classical/Structures/Lattice/Dual.lagda.md"
title: "Classical.Structures.Lattice.Dual module"
date: "2026-07-24"
author: "the agda-algebras development team"
---
### The dual of a lattice {#classical-structures-lattice-dual}
This is the [Classical.Structures.Lattice.Dual][] module of the [Agda Universal Algebra Library][].
The **dual** (or *opposite*) of a lattice swaps meet and join, equivalently reverses
the order. Because the lattice theory `Th-Lattice` is self-dual, the construction is
a matter of re-interpreting the two operation symbols of
[`Sig-Lattice`][Classical.Signatures.Lattice] on the *same* carrier setoid: the
dual's meet is `𝑳`{.AgdaBound}'s join and vice versa, six of the eight equations
transfer verbatim with the `∧`/`∨` roles exchanged, and the two absorption laws
of the dual follow from those of `𝑳`{.AgdaBound} by one commutativity step each
(`a ∨ (a ∧ b) ≈ a` is `absorbʳ`{.AgdaFunction} read backwards).
The module also records how the dualization acts on the derived order-theoretic data
of [Classical.Properties.Lattice][].
+ The meet order flips: `x ≤ y` in the dual iff `y ≤ x` in `𝑳`{.AgdaBound}
(`≤ᵈ-flip`{.AgdaFunction} / `≤ᵈ-unflip`{.AgdaFunction}).
+ Chosen extrema swap: a top of `𝑳`{.AgdaBound} is a bottom of the dual and
conversely (`dualBottomOf`{.AgdaFunction} / `dualTopOf`{.AgdaFunction}).
Dualization is involutive up to the evident isomorphism (the identity map on the
carrier): applying `dualLattice`{.AgdaFunction} twice re-interprets each symbol by
its original operation, pointwise. We do not formalize the involution here — as a
propositional equality of `Lattice`{.AgdaFunction} values it would need function
extensionality — and no current consumer requires it; a consumer that dualizes
twice should transport along the identity carrier map.
The first consumer is the Kurzweil–Netter duality entry of the FLRP assumptions
registry: the classical theorem that the
class of representable lattices is closed under dualization is *stated* over
`dualLattice`{.AgdaFunction} and imported as an explicit hypothesis.[^1]
<!--
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
module Classical.Structures.Lattice.Dual where
open import Data.Product using ( _,_ ; proj₁ )
open import Level using ( Level )
open import Relation.Binary using ( Setoid )
open import Classical.Properties.Lattice using ( module Lattice-Order
; TopOf ; BottomOf )
open import Classical.Structures.Lattice.Basic using ( Lattice ; module Lattice-Op
; setoidEqsToLattice )
open import Setoid.Algebras.Basic using ( 𝔻[_] )
private variable α ρ : Level
```
-->
#### The dual construction
`LatticeDual`{.AgdaModule} `𝑳` packages the construction and its order-theoretic
companions for a fixed lattice.
```agda
module LatticeDual (𝑳 : Lattice α ρ) where
private 𝑨 = proj₁ 𝑳
open Setoid 𝔻[ 𝑨 ] using ( _≈_ )
renaming ( trans to ≈trans )
open Lattice-Op 𝑳 using
( _∧_ ; _∨_ ; ∧-cong ; ∨-cong
; ∧-assoc-law ; ∧-comm-law ; ∧-idem-law
; ∨-assoc-law ; ∨-comm-law ; ∨-idem-law
; absorbˡ-law ; absorbʳ-law )
```
The two absorption laws of the dual, derived from those of `𝑳` by one
commutativity step each.
```agda
dual-absorbˡ : ∀ {a b} → a ∨ (a ∧ b) ≈ a
dual-absorbˡ = ≈trans ∨-comm-law absorbʳ-law
dual-absorbʳ : ∀ {a b} → (a ∨ b) ∧ a ≈ a
dual-absorbʳ = ≈trans ∧-comm-law absorbˡ-law
```
The dual lattice: same carrier setoid, meet interpreted by `_∨_` and join by
`_∧_`, the six semilattice equations exchanged wholesale, and the two derived
absorption laws.
```agda
dual-Lattice : Lattice α ρ
dual-Lattice = setoidEqsToLattice 𝔻[ 𝑨 ] _∨_ _∧_ ∨-cong ∧-cong
∨-assoc-law ∨-comm-law ∨-idem-law ∧-assoc-law ∧-comm-law ∧-idem-law
dual-absorbˡ dual-absorbʳ
```
#### The dual order is the reversed order
The meet order of the dual unfolds definitionally to `x ∨ y ≈ x`, which is the
join-form characterization of `y ≤ x` in `𝑳` ([Classical.Properties.Lattice][]'s
connecting lemmas); the two directions are one commutativity step each.
```agda
open Lattice-Order 𝑳 using ( ≤-via-∨ ; ≤-from-∨ ) renaming ( _≤_ to _≤₀_ )
open Lattice-Order dual-Lattice using () renaming ( _≤_ to _≤ᵈ_ )
≤ᵈ-flip : ∀ {x y} → x ≤ᵈ y → y ≤₀ x
≤ᵈ-flip x≤ᵈy = ≤-from-∨ (≈trans ∨-comm-law x≤ᵈy)
≤ᵈ-unflip : ∀ {x y} → y ≤₀ x → x ≤ᵈ y
≤ᵈ-unflip y≤x = ≈trans ∨-comm-law (≤-via-∨ y≤x)
```
#### Extrema swap under dualization
A chosen top of `𝑳` is a chosen bottom of the dual, and conversely — the element
is unchanged, and its universal property flips through
`≤ᵈ-unflip`{.AgdaFunction}.
```agda
dualBottomOf : TopOf 𝑳 → BottomOf dual-Lattice
dualBottomOf (t , t-top) = t , λ x → ≤ᵈ-unflip (t-top x)
dualTopOf : BottomOf 𝑳 → TopOf dual-Lattice
dualTopOf (b , b-bot) = b , λ x → ≤ᵈ-unflip (b-bot x)
```
#### The dual operator
The standalone operator, for consumers that need only the lattice.
```agda
dualLattice : Lattice α ρ → Lattice α ρ
dualLattice 𝑳 = LatticeDual.dual-Lattice 𝑳
```
--------------------------------------
[^1]: See [FLRP.Assumptions][] and work package WP-5.