Setoid.Algebras.Basic¶
Basic definitions¶
This is the Setoid.Algebras.Basic module of the Agda Universal Algebra Library.
An algebra over a signature π is a setoid (i.e., a carrier
type together with an equivalence relation on it) equipped with an interpretation
of every operation symbol of π as a function on that carrier
which respects the equivalence.
That last clause is the entire difference from the type-based development: on a
setoid an operation is not a bare function but a Func, that is, a
function bundled with a proof that it sends related arguments to related results.
Carrying the proof inside the structure yields quotients: a quotient algebra is
the same carrier under a coarser equivalence, so forming one needs neither
quotient types nor an axiom. That matters here, because the library is
--safe --cubical-compatible, where function extensionality is unavailable; see
the discussion at mkAlgebra below for where the cost reappears.
This module is the canonical entry point for the Setoid/ tree. It defines the
Algebra record, two smart constructors for building one from an
ordinary interpretation function, the operation-interpretation operator
_^_, and the universe-lifting operations that let algebras at
different levels be compared and related.
Modules most closely related to this one are the following:
- Setoid.Algebras.Products: indexed products;
- Setoid.Algebras.Finite: finite algebras;
- Setoid.Algebras.Reduct: reducts (to a smaller signature);
- Setoid.Congruences.Basic: congruences and the quotients they generate;
- Setoid.Homomorphisms.Basic: structure-preserving maps between algebras.
ov abbreviates the recurring level join ov Ξ± = π β π₯ β lsuc Ξ±;
it combines the levels of operation symbols and arities with the successor of a
caller-supplied level. Abbreviating this join keeps many common level expressions
readable.
ov : {π π₯ : Level}{π : Signature π π₯} β Level β Level ov {π = π}{π₯ = π₯} Ξ± = π β π₯ β lsuc Ξ±
Other modules combine this shorthand with whatever carrier, equality, class, and
index levels their definitions quantify over. For example,
Setoid.Algebras.Products accepts π¦ : Pred (Algebra Ξ± Ο) (ov Ξ±) and places
the type of pairs (π¨ , π¨ β π¦) at ov (Ξ± β Ο), which is also the carrier level
of class-product; the signatures of H, S, and P in
Setoid.Varieties.Closure add the corresponding equality, class, and index
levels explicitly.
The Term type over X : Type Ο is defined at Type (ov Ο)
because the term construction needs the levels of the operation symbols and
arities, plus one more level for the carrier of the term itself.1
Setoid Algebras¶
Here we define algebras over a setoid, instead of a mere type with no equivalence on it.
open Func renaming ( to to _β¨$β©_ ; cong to βcong )
The Algebra defines a setoid algebra, which is just like an
ordinary algebra but we require that all of its basic operations respect the
underlying setoid equality. The Func record packs a function (f, aka apply,
aka _β¨$β©_) with a proof (cong) that the function respects equality.
record Algebra {π : Signature π π₯} Ξ± Ο : Type (π β π₯ β lsuc (Ξ± β Ο)) where field Domain : Setoid Ξ± Ο Interp : Func (β¨ π β© Domain) Domain -- ^^^^^^^^^^^^^^^^^^^^^^^ is a record type with two fields: -- 1. a function f : Carrier (β¨ π β© Domain) β Carrier Domain -- 2. a proof cong : f Preserves _ββ_ βΆ _ββ_ (that f preserves the setoid equalities) open Setoid Domain using ( _β_ ) -- Actually, we already have the following: (it's called "reflexive"; see Structures.IsEquivalence) β‘ββ : β{x}{y} β x β‘ y β x β y β‘ββ refl = Setoid.refl Domain open Algebra
The operator β¨_β© translates an ordinary signature into a
signature over a setoid domain, together with its companion
EqArgs; it is defined in the signature-generic module
Setoid.Signatures.2
π»[_] is the domain of an algebra, which is the setoid
underlying it. In other words, the domain is the carrier and equivalence of the
algebra, taken together. It is the projection to reach for whenever the equality
matters.
π»[_] : Algebra {π = π} Ξ± Ο β Setoid Ξ± Ο π»[ π¨ ] = Domain π¨
π[_] forgets one step further, to the bare carrier type.
Mathematically it is the underlying-set functor from algebras to sets, minus the
equality: π[ π¨ ] is inhabited by the elements of π¨ and
carries no notion of equality of its elements.
-- Forgetful functor: returns the carrier of (the domain of) π¨, forgetting its structure. π[_] : Algebra {π = π} Ξ± Ο β Type Ξ± π[ π¨ ] = Setoid.Carrier π»[ π¨ ]
We use the ascii symbol ^ to define an infix function for operation-symbol
interpretation in an algebra.3
-- Interpretation of an operation symbol in an algebra. _^_ : (f : OperationSymbolsOf π)(π¨ : Algebra {π = π} Ξ± Ο) β Op (ArityOf π f) π[ π¨ ] f ^ π¨ = Ξ» a β (Interp π¨) β¨$β© (f , a)
We previously used a unicode symbol for this purpose; the definition is preserved for backward compatibility, but its use is deprecated in favor of the ascii version above. See ADR-002 Β§7 for the rationale.
_Μ_ : (f : OperationSymbolsOf π)(π¨ : Algebra {π = π} Ξ± Ο) β Op (ArityOf π f) π[ π¨ ] f Μ π¨ = Ξ» a β (Interp π¨) β¨$β© (f , a) {-# WARNING_ON_USAGE _Μ_ "The combining-caret notation `_Μ_` is deprecated as of v3.0 and will be removed in v3.1. Use the ASCII `_^_` defined immediately above. See ADR-002 Β§7." #-}
Smart constructors for concrete algebras¶
Authoring a concrete Algebra by hand means supplying the
Interp field as a Func (β¨ π β© Domain) Domain, whose
congruence proof must take apart the Ξ£/EqArgs encoding of β¨ π β©:
the clause βcong {o , _} {.o , _} (refl , argsβ) = β¦ recurs verbatim in every such
algebra (it appears across Examples.Setoid.* and Classical.Bundles.*). The two
builders below package that destructuring once.
A fully automatic congruence is not derivable at this layer, and deliberately so.
Passing from the pointwise hypothesis β i β u i β v i to f o u β f o v is exactly an
application of function extensionality, which the Setoid development avoids on principle
and which is in any case unavailable under --safe --cubical-compatible.
So each constructor still requires a per-operation, pointwise congruence cong-f;
it removes only the (refl , argsβ) boilerplate, never the mathematical content.
mkAlgebra is the general builder. Given a carrier setoid π, an
interpretation f of each operation symbol, and a proof cong-f that every f o
respects pointwise setoid equality of its argument tuple, mkAlgebra
assembles the Algebra, discharging the {o , _} {.o , _} (refl , argsβ)
match internally.
module _ (π· : Setoid Ξ± Ο) where open Setoid π· using (_β_) renaming (Carrier to D) mkAlgebra : (f : (o : OperationSymbolsOf π) β Op (ArityOf π o) D) β (β o β {u v : ArityOf π o β D} β (β i β u i β v i) β f o u β f o v) β Algebra {π = π} Ξ± Ο mkAlgebra f cong-f .Domain = π· mkAlgebra f cong-f .Interp β¨$β© (o , args) = f o args mkAlgebra f cong-f .Interp .βcong {o , _} {.o , _} (refl , argsβ) = cong-f o argsβ
mkAlgebraβ specialises mkAlgebra to a carrier whose
equality is propositional _β‘_. It takes a bare type A, builds Domain = β‘.setoid A
(a Setoid Ξ± Ξ±, so the result is Algebra Ξ± Ξ±), and asks for cong-f in pointwise _β‘_
form; e.g., β‘.congβ for a binary operation, as in the ββΈ-magma of
Examples.Setoid.FreeMagma.
mkAlgebraβ : (A : Type Ξ±) (f : (o : OperationSymbolsOf π) β Op (ArityOf π o) A) β (β o β {u v : ArityOf π o β A} β (β i β u i β‘ v i) β f o u β‘ f o v) β Algebra {π = π} Ξ± Ξ± mkAlgebraβ A f cong-f = mkAlgebra (β‘.setoid A) f cong-f
Sometimes a level has to be named that is only implicit in an algebra's type. Because Agda's universes are non-cumulative, an algebra cannot be silently reused at a larger level; the two projections below recover the levels so that a caller can state the lifting it needs.
Level-of-Alg is the level of the algebra type,
π β π₯ β lsuc (Ξ± β Ο), which is one universe above both the carrier and the
equality, since Algebra Ξ± Ο is a record containing a Setoid Ξ± Ο.
-- The universe level of an algebra Level-of-Alg : {Ξ± Ο π π₯ : Level}{π : Signature π π₯} β Algebra {π = π} Ξ± Ο β Level Level-of-Alg {Ξ± = Ξ±}{Ο}{π}{π₯} _ = π β π₯ β lsuc (Ξ± β Ο)
Level-of-Carrier is the universe level of the carrier of an algebra.
-- The universe level of the carrier of an algebra Level-of-Carrier : {Ξ± Ο π π₯ : Level}{π : Signature π π₯} β Algebra {π = π} Ξ± Ο β Level Level-of-Carrier {Ξ± = Ξ±} _ = Ξ±
Level lifting setoid algebra types¶
Agda's universes are non-cumulative: an inhabitant of Type Ξ± is not an
inhabitant of Type (Ξ± β β), so two algebras built at different levels cannot
simply be compared, and a theorem proved about Algebra Ξ± Ο does not
automatically apply to Algebra (Ξ± β β) Ο.
This bites constantly in universal algebra, where the closure operators of
Setoid.Varieties.Closure move between levels at every step. The remedy is to
lift an algebra explicitly, and the reason the remedy costs nothing
mathematically is that a lifted algebra is isomorphic to the original:
Setoid.Homomorphisms.Isomorphisms proves Lift-β
: π¨ β
Lift-Alg π¨ β Ο, so
isomorphism classes are closed under lifting and every isomorphism-invariant
property survives it.
An algebra carries two independent levels: the carrier's Ξ± and the equality's
Ο; so there are two liftings, and they are kept separate.
Lift-AlgΛ‘ raises the carrier level, from Ξ± to Ξ± β β,
leaving the equality where it is. The carrier becomes Lift β π[ π¨ ] and two
lifted elements are related exactly when the elements underneath them were, so the
equivalence is transported unchanged.
module _ {π : Signature π π₯}(π¨ : Algebra {π = π} Ξ± Ο)(β : Level) where open Algebra π¨ using () renaming ( Domain to A ) open Setoid A using (sym ; trans ) renaming ( Carrier to β£Aβ£ ; _β_ to _ββ_ ; refl to reflβ ) open Level Lift-AlgΛ‘ : Algebra {π = π} (Ξ± β β) Ο Lift-AlgΛ‘ .Domain = record { Carrier = Lift β β£Aβ£ ; _β_ = Ξ» x y β lower x ββ lower y ; isEquivalence = record { refl = reflβ ; sym = sym ; trans = trans } } Lift-AlgΛ‘ .Interp β¨$β© (f , la) = lift $ (f ^ π¨) (lower β la) Lift-AlgΛ‘ .Interp .βcong (refl , la=lb) = βcong (Interp π¨) (refl , la=lb)
Lift-AlgΚ³ raises the level of the equality, from Ο to Ο β
β, and leaves the carrier alone. The relation becomes Lift β ββ _ββ_, a
proposition-level lift of the original, and the equivalence proofs are re-wrapped
accordingly.
Lift-AlgΚ³ : Algebra {π = π} Ξ± (Ο β β) Lift-AlgΚ³ .Domain = record { Carrier = β£Aβ£ ; _β_ = (Lift β) ββ _ββ_ ; isEquivalence = record { refl = lift reflβ ; sym = lift β sym β lower ; trans = Ξ» x y β lift $ trans (lower x) (lower y) } } Lift-AlgΚ³ .Interp β¨$β© (f , la) = (f ^ π¨) la Lift-AlgΚ³ .Interp .βcong (refl , laβ‘lb) = lift $ βcong (Interp π¨) (β‘.refl , (lower β laβ‘lb))
Lift-Alg composes the two, raising both levels at once: given
target increments ββ and ββ it produces an algebra at (Ξ± β ββ, Ο β ββ).
It is the operation the closure operators use to bring a class and a candidate
algebra to a common level; Lift-β
of
Setoid.Homomorphisms.Isomorphisms is the isomorphism that makes the move
harmless.
Lift-Alg : (π¨ : Algebra {π = π} Ξ± Ο)(ββ ββ : Level) β Algebra {π = π} (Ξ± β ββ) (Ο β ββ) Lift-Alg π¨ ββ = Lift-AlgΚ³ (Lift-AlgΛ‘ π¨ ββ)
-
This is why the term construction is a relative monad rather than a monad; see Setoid.Terms.Monad. ↩
-
Because the carrier of
β¨ π β© Domainis aΞ£-type, anInterpclause matches it as(o , args), which needs the pair constructor_,_in scope. We therefore re-export_,_andΞ£-syntaxfrom this module (and hence from theSetoid.Algebrasbarrel), so that pattern-matching such a carrier needs no separateData.Productimport, and no longer trips the misleading "β-Opis not a constructor of the datatype β¦Ξ£" error, which points at the operation symbol rather than at the missing_,_. ↩ -
The
_^_symbol is definitionally identical to_Μ_and was introduced for grep-friendliness and to survive shell-pipeline tooling. NewClassical/code uses_^_exclusively; existingSetoid/code may continue to use_Μ_until v3.1. See ADR-002 Β§7 for the rationale and per-tree policy. ↩