---
layout: default
title : "Setoid.Congruences.Generation module (The Agda Universal Algebra Library)"
date : "2026-06-01"
author: "agda-algebras development team"
---
### The Congruence Generated by a Relation
This is the [Setoid.Congruences.Generation][] module of the [Agda Universal Algebra Library][].
The [Setoid.Congruences.Lattice][] module made `Con π¨` a meet-semilattice
under containment, with meet given by intersection (the tractable half of the
congruence lattice). The join requires more work; it is the *least* congruence
containing the union; that is, the **congruence generated by** the union. This
module supplies the subsidiary result on which the join rests: for any binary
relation `R` on the carrier of `π¨` there is a least congruence `Cg R` containing `R`.
We build `Cg R` as the inductively-defined closure `Gen R` of `R` under the
congruence-forming rules: it contains `R` (`base`), it contains the setoid equality
`_β_` (`rfl`), and it is closed under symmetry, transitivity, and the basic
operations (`symmetric`, `transitive`, `compatible`). The following two facts make this *the*
generated congruence and constitute the **Congruence Generation Theorem**:
+ `Cg R` is a congruence containing `R` (so it is *an* upper bound of `R`); and
+ every congruence `Ο` containing `R` contains `Cg R` (so it is the *least* upper
bound) β this is `Cg-least`, proved by induction on `Gen`.
From `Cg` we obtain the **join** `ΞΈ β¨ Ο = Cg(ΞΈ βͺ Ο)` and prove it is the least
upper bound of `ΞΈ` and `Ο` in the containment order. Because the closure quantifies
over the operations and the carrier, `Gen R` lands at level `π β π₯ β Ξ± β Ο β β`
(not `β`); assembling this into a single-level `Lattice`/`CompleteLattice` bundle β
where that level is absorbed β is the remaining step of the congruence-lattice work
and is deferred to a follow-up.
<!--
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
open import Overture using (π ; π₯ ; Signature)
module Setoid.Congruences.Generation {π : Signature π π₯} where
open import Agda.Primitive using () renaming ( Set to Type )
open import Data.Product using ( _,_ ; projβ ; projβ )
open import Data.Sum.Base using ( _β_ ; injβ ; injβ ; [_,_] )
open import Level using ( Level ; _β_ )
open import Relation.Binary using ( Setoid ; IsEquivalence )
renaming ( Rel to BinaryRel ; _β_ to _β_)
open import Overture using ( OperationSymbolsOf ; ArityOf )
open import Setoid.Algebras.Basic {π = π} using ( Algebra ; π[_] ; π»[_] ; _^_ )
open import Setoid.Congruences.Basic {π = π} using ( Con ; mkcon ; is-equivalence
; is-compatible ; reflexive )
private variable Ξ± Ο β ββ² : Level
```
-->
#### Inductive Generation of a Congruence
Fix an algebra `π¨` and a binary relation `R` on its carrier. `Gen R` is the
smallest relation containing `R` that is reflexive over `_β_`, symmetric,
transitive, and compatible with every basic operation. The closure quantifies over
the operation symbols (`π`), their arities (`π₯`), and the carrier (`Ξ±`, `Ο`), so it
inhabits `BinaryRel π[ π¨ ] (π β π₯ β Ξ± β Ο β β)`; we name that level `π β`.
```agda
module _ {π¨ : Algebra Ξ± Ο} where
open Setoid π»[ π¨ ] using ( _β_ ) renaming ( refl to βrefl )
π : Level β Level
π β = π β π₯ β Ξ± β Ο β β
data Gen (R : BinaryRel π[ π¨ ] β) : BinaryRel π[ π¨ ] (π β) where
base : R β Gen R
rfl : {x y : π[ π¨ ]} β x β y β Gen R x y
symmetric : {x y : π[ π¨ ]} β Gen R x y β Gen R y x
transitive : {x y z : π[ π¨ ]} β Gen R x y β Gen R y z β Gen R x z
compatible : (f : OperationSymbolsOf π) {u v : ArityOf π f β π[ π¨ ]}
β (β i β Gen R (u i) (v i)) β Gen R ((f ^ π¨) u) ((f ^ π¨) v)
Cg : (R : BinaryRel π[ π¨ ] β) β Con π¨ (π β)
Cg R = Gen R , mkcon rfl g-isEquivalence compatible
where
open IsEquivalence using (refl ; sym ; trans )
g-isEquivalence : IsEquivalence (Gen R)
g-isEquivalence .refl = rfl βrefl
g-isEquivalence .sym = symmetric
g-isEquivalence .trans = transitive
```
#### The Congruence Generation Theorem
`R` is contained in `Cg R` (the `base` constructor), and `Cg R` is the *least*
congruence with that property: any congruence `Ο` containing `R` already contains
`Gen R`. The latter is proved by induction on the derivation of `Gen R x y`,
turning each closure rule into the corresponding congruence law of `Ο`. Note `Ο` may
live at any relation level `ββ²`, so this is a genuinely heterogeneous statement.
```agda
Cg-incl : (R : BinaryRel π[ π¨ ] β) β R β Gen R
Cg-incl R = base
Cg-least : {R : BinaryRel π[ π¨ ] β} (Ο : Con π¨ ββ²) β R β projβ Ο β Gen R β projβ Ο
Cg-least Ο RβΟ (base r) = RβΟ r
Cg-least (_ , Οcon) RβΟ (rfl e) = reflexive Οcon e
Cg-least Ο RβΟ (symmetric p) =
IsEquivalence.sym (is-equivalence (Ο .projβ)) (Cg-least Ο RβΟ p)
Cg-least Ο RβΟ (transitive p q) =
IsEquivalence.trans (is-equivalence (projβ Ο)) (Cg-least Ο RβΟ p) (Cg-least Ο RβΟ q)
Cg-least Ο RβΟ (compatible f h) = is-compatible (projβ Ο) f (Ξ» i β Cg-least Ο RβΟ (h i))
```
Monotonicity follows immediately: if `R` is contained in `S` then `Cg R` is
contained in `Cg S` (take `Ο = Cg S`, which contains `S` hence `R`).
```agda
Cg-mono : {R : BinaryRel π[ π¨ ] β} {S : BinaryRel π[ π¨ ] ββ²} β R β S β Gen R β Gen S
Cg-mono {S = S} RβS = Cg-least (Cg S) (Ξ» r β base (RβS r))
```
#### The Join of Two Congruences
For congruences `ΞΈ Ο : Con π¨` the union `ΞΈ βͺ Ο` of their underlying relations need
not be transitive, so we take the join to be the congruence it generates,
`ΞΈ β¨ Ο = Cg(ΞΈ βͺ Ο)`. We record the order facts using a heterogeneous containment
`_β_` (which coincides definitionally with the homogeneous `_β€_` of
[Setoid.Congruences.Lattice][] when the two levels agree), because the
join sits at the higher level `π β`.
```agda
_β_ : Con π¨ β β Con π¨ ββ² β Type (Ξ± β β β ββ²)
ΞΈ β Ο = projβ ΞΈ β projβ Ο
infix 4 _β_
_βͺα΅£_ : Con π¨ β β Con π¨ β β BinaryRel π[ π¨ ] β
(ΞΈ βͺα΅£ Ο) x y = projβ ΞΈ x y β projβ Ο x y
infixr 6 _βͺα΅£_
_β¨_ : Con π¨ β β Con π¨ β β Con π¨ (π β)
ΞΈ β¨ Ο = Cg (ΞΈ βͺα΅£ Ο)
infixr 6 _β¨_
```
The join is the least upper bound of its arguments: each argument is below it
(`base β injβ`, `base β injβ`), and it is below any common upper bound (by
`Cg-least`, since the union is below any congruence above both arguments).
```agda
β¨-upperΛ‘ : (ΞΈ Ο : Con π¨ β) β ΞΈ β (ΞΈ β¨ Ο)
β¨-upperΛ‘ _ _ p = base (injβ p)
β¨-upperΚ³ : (ΞΈ Ο : Con π¨ β) β Ο β (ΞΈ β¨ Ο)
β¨-upperΚ³ _ _ q = base (injβ q)
β¨-least : (ΞΈ Ο : Con π¨ β) (Ο : Con π¨ ββ²) β ΞΈ β Ο β Ο β Ο β (ΞΈ β¨ Ο) β Ο
β¨-least _ _ Ο ΞΈβΟ ΟβΟ = Cg-least Ο (Ξ» {x y} β [ ΞΈβΟ , ΟβΟ ])
```
#### The principal (single-pair) relation
For two carrier elements `a`, `b` of an algebra, `β΄ a , b β΅`{.AgdaFunction} is the
relation that relates exactly `a` to `b`. Its generated congruence `Cg β΄ a , b β΅` is
the *principal* congruence collapsing the one pair.
```agda
module principal (π¨ : Algebra Ξ± Ο) where
data β΄_,_β΅ (a b : π[ π¨ ]) : BinaryRel π[ π¨ ] Ξ± where
pα΅£ : β΄ a , b β΅ a b
open β΄_,_β΅
```