---
layout: default
title : "Setoid.Varieties.Closure module (The Agda Universal Algebra Library)"
date : "2021-01-14"
author: "agda-algebras development team"
---
#### Closure Operators for Setoid Algebras
Fix a signature π, let π¦ be a class of π-algebras, and define
+ `H π¦` = algebras isomorphic to a homomorphic image of a member of `π¦`;
+ `S π¦` = algebras isomorphic to a subalgebra of a member of `π¦`;
+ `P π¦` = algebras isomorphic to a product of members of `π¦`.
<!--
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
open import Overture using (π ; π₯ ; Signature)
module Setoid.Varieties.Closure {π : Signature π π₯} where
open import Agda.Primitive using () renaming ( Set to Type )
open import Data.Product using ( _,_ ; Ξ£-syntax )
renaming ( _Γ_ to _β§_ )
open import Data.Unit.Polymorphic using ( β€ ; tt )
open import Function using () renaming ( Func to _βΆ_ )
open import Level using ( Level ; _β_ )
open import Relation.Binary using ( Setoid )
open import Relation.Unary using ( Pred ; _β_ ; _β_ )
open import Setoid.Algebras {π = π} using ( Algebra ; ov ; Lift-Alg ; β¨
)
open import Setoid.Homomorphisms {π = π}
open import Setoid.Subalgebras {π = π}
open _βΆ_ renaming ( to to _β¨$β©_ )
```
-->
```agda
module _ {Ξ± Οα΅ Ξ² Οα΅ : Level} where
private
a b : Level
a = Ξ± β Οα΅ ; b = Ξ² β Οα΅
Level-closure : β β β Pred(Algebra Ξ± Οα΅) (a β ov β) β Pred(Algebra Ξ² Οα΅) (b β ov(a β β))
Level-closure β π¦ π© = Ξ£[ π¨ β Algebra Ξ± Οα΅ ] π¨ β π¦ β§ π¨ β
π©
module _ {Ξ± Οα΅ Ξ² Οα΅ : Level} where
Lift-closed : β β β {π¦ : Pred(Algebra Ξ± Οα΅) _}{π¨ : Algebra Ξ± Οα΅}
β π¨ β π¦ β Lift-Alg π¨ Ξ² Οα΅ β (Level-closure β π¦)
Lift-closed _ {π¨ = π¨} kA = π¨ , (kA , Lift-β
)
private
a b : Level
a = Ξ± β Οα΅ ; b = Ξ² β Οα΅
H S : β β β Pred(Algebra Ξ± Οα΅) (a β ov β) β Pred(Algebra Ξ² Οα΅) (b β ov(a β β))
H _ π¦ π© = Ξ£[ π¨ β Algebra Ξ± Οα΅ ] π¨ β π¦ β§ π© IsHomImageOf π¨
S _ π¦ π© = Ξ£[ π¨ β Algebra Ξ± Οα΅ ] π¨ β π¦ β§ π© β€ π¨
P : β β ΞΉ β Pred(Algebra Ξ± Οα΅) (a β ov β) β Pred(Algebra Ξ² Οα΅) (b β ov(a β β β ΞΉ))
P β ΞΉ π¦ π© = Ξ£[ I β Type ΞΉ ] Ξ£[ π β (I β Algebra Ξ± Οα΅) ] (β i β π i β π¦) β§ π© β
β¨
π
module _ {Ξ± Οα΅ Ξ² Οα΅ : Level} where
private
a b : Level
a = Ξ± β Οα΅ ; b = Ξ² β Οα΅
SP : β β ΞΉ β Pred(Algebra Ξ± Οα΅) (a β ov β) β Pred(Algebra Ξ² Οα΅) (b β ov(a β β β ΞΉ))
SP β ΞΉ π¦ = S{Ξ±}{Οα΅} (a β β β ΞΉ) (P β ΞΉ π¦)
module _ {Ξ³ ΟαΆ Ξ΄ Οα΅ : Level} where
private
c d : Level
c = Ξ³ β ΟαΆ ; d = Ξ΄ β Οα΅
V : β β ΞΉ
β Pred(Algebra Ξ± Οα΅) (a β ov β) β Pred(Algebra Ξ΄ Οα΅) (d β ov(a β b β c β β β ΞΉ))
V β ΞΉ π¦ = H{Ξ³}{ΟαΆ} (a β b β β β ΞΉ) (S{Ξ²}{Οα΅} (a β β β ΞΉ) (P β ΞΉ π¦))
```
Thus, if π¦ is a class of π-algebras, then the *variety generated by* π¦ is denoted by
`V π¦` and defined to be the smallest class that contains π¦ and is closed under `H`,
`S`, and `P`.
#### A common-case level specialization of `V`
The operator `V`{.AgdaFunction} carries *eight* independent universe levels.
The input class lives at `(Ξ±, Οα΅)` and the output algebra at `(Ξ΄, Οα΅)`, but the
intermediate pairs `(Ξ², Οα΅)` and `(Ξ³, ΟαΆ)` are the levels of the algebras threaded
through the `H β S β P` composition: they are determined by neither the input nor the
output, so they stay free metavariables whenever `V`{.AgdaFunction} is applied without
a goal that already pins them. That generality is essential for the HSP theorem, but
is unnecessary friction for the everyday request "the variety generated by a fixed algebra".
`Vβ²`{.AgdaFunction} is the specialization of `V`{.AgdaFunction} to the overwhelmingly
common case in which the generated variety is considered at the *same* levels as the
class that generates it. It collapses all four algebra positions to the input levels
`(Ξ±, Οα΅)` β exactly the pinning `is-variety`{.AgdaFunction} already performs above
(`Ξ² = Ξ³ = Ξ΄ = Ξ±` and `Οα΅ = ΟαΆ = Οα΅ = Οα΅`), under which the output level
`d β ov(a β b β c β β β ΞΉ)` of `V`{.AgdaFunction} collapses to `a β ov(a β β β ΞΉ)`.
This is a documented narrowing of the canonical operator, not a synonym:
`V`{.AgdaFunction} remains the level-polymorphic form, while `Vβ²`{.AgdaFunction} is the
fixed-level entry point that downstream examples and tests should prefer.
```agda
module _ {Ξ± Οα΅ : Level} where
private
a : Level
a = Ξ± β Οα΅
Vβ² : β β ΞΉ β Pred(Algebra Ξ± Οα΅)(a β ov β) β Pred(Algebra Ξ± Οα΅) (a β ov(a β β β ΞΉ))
Vβ² β ΞΉ π¦ = V {Ξ±}{Οα΅}{Ξ±}{Οα΅}{Ξ±}{Οα΅} β ΞΉ π¦
```
With the closure operator V representing closure under HSP, we represent formally
what it means to be a variety of algebras as follows.
```agda
module _ {Ξ± Οα΅ β ΞΉ : Level} where
is-variety : Pred (Algebra Ξ± Οα΅) (Ξ± β Οα΅ β ov β) β Type (ov (Ξ± β Οα΅ β β β ΞΉ))
is-variety π± = Vβ² β ΞΉ π± β π±
variety : Type (ov (Ξ± β Οα΅ β ov β β ΞΉ))
variety = Ξ£[ π± β Pred (Algebra Ξ± Οα΅) (Ξ± β Οα΅ β ov β) ] is-variety π±
```
#### Closure properties of S
`S` is a closure operator. The fact that `S` is expansive won't be needed, so we
omit the proof, but we will make use of monotonicity and idempotence of `S`.
```agda
module _ {Ξ± Οα΅ : Level} where
private a = Ξ± β Οα΅
S-mono : β{β} β {π¦ π¦' : Pred (Algebra Ξ± Οα΅)(a β ov β)}
β π¦ β π¦' β S{Ξ² = Ξ±}{Οα΅} β π¦ β S β π¦'
S-mono kk {π©} (π¨ , (kA , Bβ€A)) = π¨ , ((kk kA) , Bβ€A)
```
We say `S` is *idempotent* provided `S`{.AgdaFunction} (`S`{.AgdaFunction} `π¦`{.AgdaBound}) `=`{.AgdaSymbol} `S`{.AgdaFunction} `π¦`{.AgdaBound}.
Of course, this is proved by establishing two inclusions, but one of them is trivial, so only the other need be formalized, which we do as follows.
```agda
S-idem : β{Ξ² Οα΅ Ξ³ ΟαΆ β} β {π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)}
β S{Ξ² = Ξ³}{ΟαΆ} (a β β) (S{Ξ² = Ξ²}{Οα΅} β π¦) β S{Ξ² = Ξ³}{ΟαΆ} β π¦
S-idem (π¨ , (π© , sB , Aβ€B) , xβ€A) = π© , (sB , β€-trans xβ€A Aβ€B)
```
#### Closure properties of P
`P` is a closure operator. This is proved by checking that `P` is *monotone*, *expansive*, and *idempotent*. The meaning of these terms will be clear from the definitions of the types that follow.
```agda
H-expa : β{β} β {π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)} β π¦ β H β π¦
H-expa {β} {π¦}{π¨} kA = π¨ , kA , IdHomImage
S-expa : β{β} β {π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)} β π¦ β S β π¦
S-expa {β}{π¦}{π¨} kA = π¨ , (kA , β€-reflexive)
P-mono : β{β ΞΉ} β {π¦ π¦' : Pred (Algebra Ξ± Οα΅)(a β ov β)}
β π¦ β π¦' β P{Ξ² = Ξ±}{Οα΅} β ΞΉ π¦ β P β ΞΉ π¦'
P-mono {β}{ΞΉ}{π¦}{π¦'} kk {π©} (I , π , (kA , Bβ
β¨
A)) = I , (π , ((Ξ» i β kk (kA i)) , Bβ
β¨
A))
open _β
_
open IsHom
P-expa : β{β ΞΉ} β {π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)} β π¦ β P β ΞΉ π¦
P-expa {β}{ΞΉ}{π¦}{π¨} kA = β€ , (Ξ» x β π¨) , ((Ξ» i β kA) , Goal)
where
open Algebra π¨ using () renaming (Domain to A)
open Algebra (β¨
(Ξ» _ β π¨)) using () renaming (Domain to β¨
A)
open Setoid A using ( refl )
open Setoid β¨
A using () renaming ( refl to reflβ¨
)
toβ¨
: A βΆ β¨
A
(toβ¨
β¨$β© x) = Ξ» _ β x
cong toβ¨
xy = Ξ» _ β xy
toβ¨
IsHom : IsHom π¨ (β¨
(Ξ» _ β π¨)) toβ¨
compatible toβ¨
IsHom = reflβ¨
fromβ¨
: β¨
A βΆ A
(fromβ¨
β¨$β© x) = x tt
cong fromβ¨
xy = xy tt
fromβ¨
IsHom : IsHom (β¨
(Ξ» _ β π¨)) π¨ fromβ¨
compatible fromβ¨
IsHom = refl
Goal : π¨ β
β¨
(Ξ» x β π¨)
to Goal = toβ¨
, toβ¨
IsHom
from Goal = fromβ¨
, fromβ¨
IsHom
toβΌfrom Goal = Ξ» _ _ β refl
fromβΌto Goal = Ξ» _ β refl
V-expa : β β ΞΉ β {π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)} β π¦ β V β ΞΉ π¦
V-expa β ΞΉ {π¦} {π¨} x = H-expa {a β β β ΞΉ} (S-expa {a β β β ΞΉ} (P-expa {β}{ΞΉ} x) )
```
The expansiveness lemmas above are stated with `_β_`, i.e. `π¦ β β β β¦ π¦`, which
unfolds to `β {π¨} β π¨ β π¦ β π¨ β β β β¦ π¦` with both the class `π¦`{.AgdaBound} and the
element `π¨`{.AgdaBound} implicit. Recovering them from a single membership proof is a
higher-order unification problem (`_π¦ _π¨ β (π¨ β π¦)`) that Agda cannot solve once the
class predicate reduces. The variants below take the class `π¦`{.AgdaBound}
*explicitly*, so a membership in a closure operator follows directly from a membership
in the class with nothing to infer. The `_β_` forms above remain the abstract
statements; these are the ergonomic entry points (`V-expaβ²`{.AgdaFunction} is the one
exercised by `Examples.Setoid.HSPCommutativeMonoid`{.AgdaModule}).
```agda
H-expaβ² : β β (π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)) {π¨} β π¨ β π¦ β π¨ β H β π¦
H-expaβ² β π¦ = H-expa {β}{π¦}
S-expaβ² : β β (π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)) {π¨} β π¨ β π¦ β π¨ β S β π¦
S-expaβ² β π¦ = S-expa {β}{π¦}
P-expaβ² : β β ΞΉ (π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)) {π¨} β π¨ β π¦ β π¨ β P β ΞΉ π¦
P-expaβ² β ΞΉ π¦ = P-expa {β}{ΞΉ}{π¦}
V-expaβ² : β β ΞΉ (π¦ : Pred (Algebra Ξ± Οα΅)(a β ov β)) {π¨} β π¨ β π¦ β π¨ β V β ΞΉ π¦
V-expaβ² β ΞΉ π¦ = V-expa β ΞΉ {π¦}
```
We sometimes want to go back and forth between our two representations of subalgebras
of algebras in a class. The tools `subalgebraβS` and `Sβsubalgebra` are made for that
purpose.
```agda
module _
{Ξ± Οα΅ Ξ² Οα΅ β ΞΉ : Level}
{π¦ : Pred (Algebra Ξ± Οα΅) (Ξ± β Οα΅ β ov β)}
{π¨ : Algebra Ξ± Οα΅}
{π© : Algebra Ξ² Οα΅}
where
S-β
: π¨ β S β π¦ β π¨ β
π© β π© β S{Ξ± β Ξ²}{Οα΅ β Οα΅}(Ξ± β Οα΅ β β) (Level-closure β π¦)
S-β
(π¨' , kA' , Aβ€A') Aβ
B = lA' , (lklA' , Bβ€lA')
where
lA' : Algebra (Ξ± β Ξ²) (Οα΅ β Οα΅)
lA' = Lift-Alg π¨' Ξ² Οα΅
lklA' : lA' β Level-closure β π¦
lklA' = Lift-closed β kA'
subgoal : π¨ β€ lA'
subgoal = β€-trans-β
Aβ€A' Lift-β
Bβ€lA' : π© β€ lA'
Bβ€lA' = β
-trans-β€ (β
-sym Aβ
B) subgoal
V-β
: π¨ β V β ΞΉ π¦ β π¨ β
π© β π© β V{Ξ² = Ξ±}{Οα΅} β ΞΉ π¦
V-β
(π¨' , spA' , AimgA') Aβ
B = π¨' , spA' , HomImage-β
AimgA' Aβ
B
module _
{Ξ± Οα΅ β : Level}
(π¦ : Pred(Algebra Ξ± Οα΅) (Ξ± β Οα΅ β ov β))
(π¨ : Algebra (Ξ± β Οα΅ β β) (Ξ± β Οα΅ β β))
where
private ΞΉ = ov(Ξ± β Οα΅ β β)
V-β
-lc : Lift-Alg π¨ ΞΉ ΞΉ β V{Ξ² = ΞΉ}{ΞΉ} β ΞΉ π¦ β π¨ β V{Ξ³ = ΞΉ}{ΞΉ} β ΞΉ π¦
V-β
-lc (π¨' , spA' , lAimgA') = π¨' , (spA' , AimgA')
where
AimgA' : π¨ IsHomImageOf π¨'
AimgA' = Lift-HomImage-lemma lAimgA'
```
The remaining theorems in this file are as yet unused, but may be useful later and/or
for reference.
```agda
module _ {Ξ± Οα΅ β ΞΉ : Level}{π¦ : Pred (Algebra Ξ± Οα΅)(Ξ± β Οα΅ β ov β)} where
classP : Pred (Algebra Ξ± Οα΅) (ov(Ξ± β Οα΅ β β β ΞΉ))
classP = P{Ξ² = Ξ±}{Οα΅} β ΞΉ π¦
classSP : Pred (Algebra Ξ± Οα΅) (ov(Ξ± β Οα΅ β β β ΞΉ))
classSP = S{Ξ² = Ξ±}{Οα΅} (Ξ± β Οα΅ β β β ΞΉ) (P{Ξ² = Ξ±}{Οα΅} β ΞΉ π¦)
classHSP : Pred (Algebra Ξ± Οα΅) (ov(Ξ± β Οα΅ β β β ΞΉ))
classHSP = H{Ξ² = Ξ±}{Οα΅}(Ξ± β Οα΅ β β β ΞΉ) (S{Ξ² = Ξ±}{Οα΅}(Ξ± β Οα΅ β β β ΞΉ) (P{Ξ² = Ξ±}{Οα΅}β ΞΉ π¦))
classS : β{Ξ² Οα΅} β Pred (Algebra Ξ² Οα΅) (Ξ² β Οα΅ β ov(Ξ± β Οα΅ β β))
classS = S β π¦
classK : β{Ξ² Οα΅} β Pred (Algebra Ξ² Οα΅) (Ξ² β Οα΅ β ov(Ξ± β Οα΅ β β))
classK = Level-closure{Ξ±}{Οα΅} β π¦
module _ {Ξ± Οα΅ Ξ² Οα΅ Ξ³ ΟαΆ β : Level}{π¦ : Pred (Algebra Ξ± Οα΅)(Ξ± β Οα΅ β ov β)} where
private a = Ξ± β Οα΅ ; b = Ξ² β Οα΅ ; c = Ξ³ β ΟαΆ
LevelClosure-S : Pred (Algebra (Ξ± β Ξ³) (Οα΅ β ΟαΆ)) (c β ov(a β b β β))
LevelClosure-S = Level-closure{Ξ²}{Οα΅} (a β β) (S β π¦)
S-LevelClosure : Pred (Algebra (Ξ± β Ξ³) (Οα΅ β ΟαΆ)) (ov(a β c β β))
S-LevelClosure = S{Ξ± β Ξ³}{Οα΅ β ΟαΆ}(a β β) (Level-closure β π¦)
S-Lift-lemma : LevelClosure-S β S-LevelClosure
S-Lift-lemma {πͺ} (π© , (π¨ , (kA , Bβ€A)) , Bβ
C) =
Lift-Alg π¨ Ξ³ ΟαΆ , (Lift-closed{Ξ² = Ξ³}{ΟαΆ} β kA) , Cβ€lA
where
Bβ€lA : π© β€ Lift-Alg π¨ Ξ³ ΟαΆ
Bβ€lA = β€-Lift Bβ€A
Cβ€lA : πͺ β€ Lift-Alg π¨ Ξ³ ΟαΆ
Cβ€lA = β
-trans-β€ (β
-sym Bβ
C) Bβ€lA
module _ {Ξ± Οα΅ : Level} where
P-Lift-closed : β β ΞΉ β {π¦ : Pred (Algebra Ξ± Οα΅)(Ξ± β Οα΅ β ov β)}{π¨ : Algebra Ξ± Οα΅}
β π¨ β P{Ξ² = Ξ±}{Οα΅} β ΞΉ π¦
β {Ξ³ ΟαΆ : Level} β Lift-Alg π¨ Ξ³ ΟαΆ β P (Ξ± β Οα΅ β β) ΞΉ (Level-closure β π¦)
P-Lift-closed β ΞΉ {π¦}{π¨} (I , π , kA , Aβ
β¨
π) {Ξ³}{ΟαΆ} =
I , (Ξ» x β Lift-Alg (π x) Ξ³ ΟαΆ) , goal1 , goal2
where
goal1 : (i : I) β Lift-Alg (π i) Ξ³ ΟαΆ β Level-closure β π¦
goal1 i = Lift-closed β (kA i)
goal2 : Lift-Alg π¨ Ξ³ ΟαΆ β
β¨
(Ξ» x β Lift-Alg (π x) Ξ³ ΟαΆ)
goal2 = β
-trans (β
-sym Lift-β
) (β
-trans Aβ
β¨
π (β¨
β
β¨
βΟ{β = Ξ³}{Ο = ΟαΆ}))
```