---
layout: default
title : "Legacy.Base.Algebras.Products module (Agda Universal Algebra Library)"
date : "2021-01-12"
author: "agda-algebras development team"
---
### <a id="products-of-algebras-and-product-algebras">Products of Algebras and Product Algebras</a>
This is the [Legacy.Base.Algebras.Products][] module of the [Agda Universal Algebra Library][].
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
open import Overture using ( ๐ ; ๐ฅ ; Signature )
module Legacy.Base.Algebras.Products {๐ : Signature ๐ ๐ฅ} where
open import Agda.Primitive using () renaming ( Set to Type )
open import Data.Product using ( _,_ ; ฮฃ ; ฮฃ-syntax )
open import Level using ( Level ; _โ_ ; suc )
open import Relation.Unary using ( Pred ; _โ_ ; _โ_ )
open import Overture using (_โปยน; ๐๐; โฃ_โฃ; โฅ_โฅ)
open import Legacy.Base.Algebras.Basic {๐ = ๐} using ( Algebra ; _ฬ_ ; algebra )
private variable ฮฑ ฮฒ ฯ ๐ : Level
```
From now on, the modules of the
[agda-algebras](https://github.com/ualib/agda-algebras) library will assume a
fixed signature `๐ : Signature ๐ ๐ฅ`.
Recall the informal definition of a *product* of `๐`-algebras. Given a type `I :
Type ๐` and a family `๐ : I โ Algebra ฮฑ`, the *product* `โจ
๐` is the algebra
whose domain is the Cartesian product `ฮ ๐ ๊ I , โฃ ๐ ๐ โฃ` of the domains of the
algebras in `๐`, and whose operations are defined as follows: if `๐` is a `J`-ary
operation symbol and if `๐ : ฮ ๐ ๊ I , J โ ๐ ๐` is an `I`-tuple of `J`-tuples such
that `๐ ๐` is a `J`-tuple of elements of `๐ ๐` (for each `๐`), then `(๐ ฬ โจ
๐) ๐ :=
(i : I) โ (๐ ฬ ๐ i)(๐ i)`.
In the [agda-algebras](https://github.com/ualib/agda-algebras) library a *product
of* `๐`-*algebras* is represented by the following type.
```agda
โจ
: {I : Type ๐ }(๐ : I โ Algebra ฮฑ ) โ Algebra (๐ โ ฮฑ)
โจ
{I = I} ๐ = ( โ (i : I) โ โฃ ๐ i โฃ ) ,
ฮป ๐ ๐ i โ (๐ ฬ ๐ i) ฮป x โ ๐ x i
```
The type just defined is the one that will be used throughout the
[agda-algebras](https://github.com/ualib/agda-algebras) library whenever the
product of an indexed collection of algebras (of type `Algebra`) is required.
However, for the sake of completeness, here is how one could define a type
representing the product of algebras inhabiting the record type `algebra`.
```agda
open algebra
โจ
' : {I : Type ๐ }(๐ : I โ algebra ฮฑ) โ algebra (๐ โ ฮฑ)
โจ
' {I} ๐ = record { carrier = โ i โ carrier (๐ i)
; opsymbol = ฮป ๐ ๐ i โ (opsymbol (๐ i)) ๐ ฮป x โ ๐ x i }
```
**Notation**. Given a signature `๐ : Signature ๐ ๐ฅ`, the type `Algebra ฮฑ` has
type `Type(๐ โ ๐ฅ โ lsuc ฮฑ)`. Such types occur so often in the
[agda-algebras](https://github.com/ualib/agda-algebras) library that we define
the following shorthand for their universes.
```agda
ov : Level โ Level
ov ฮฑ = ๐ โ ๐ฅ โ suc ฮฑ
```
### <a id="products-of-classes-of-algebras">Products of classes of algebras</a>
An arbitrary class `๐ฆ` of algebras is represented as a predicate over the type
`Algebra ฮฑ`, for some universe level `ฮฑ` and signature `๐`. That is, `๐ฆ : Pred
(Algebra ฮฑ) ฮฒ`, for some type `ฮฒ`. Later we will formally state and prove that
the product of all subalgebras of algebras in `๐ฆ` belongs to the class `SP(๐ฆ)` of
subalgebras of products of algebras in `๐ฆ`. That is, `โจ
S(๐ฆ) โ SP(๐ฆ )`. This turns
out to be a nontrivial exercise.
To begin, we need to define types that represent products over arbitrary
(nonindexed) families such as `๐ฆ` or `S(๐ฆ)`. Observe that `ฮ ๐ฆ` is certainly not
what we want. For recall that `Pred (Algebra ฮฑ) ฮฒ` is just an alias for the
function type `Algebra ฮฑ โ Type ฮฒ`, and the semantics of the latter takes `๐ฆ ๐จ`
(and `๐จ โ ๐ฆ`) to mean that `๐จ` belongs to the class `๐ฆ`. Thus, by definition,
ฮ ๐ฆ := ฮ ๐จ ๊ (Algebra ฮฑ) , ๐ฆ ๐จ := โ (๐จ : Algebra ฮฑ) โ ๐จ โ ๐ฆ,
which asserts that every inhabitant of the type `Algebra ฮฑ` belongs to `๐ฆ`.
Evidently this is not the product algebra that we seek.
What we need is a type that serves to index the class `๐ฆ`, and a function `๐` that
maps an index to the inhabitant of `๐ฆ` at that index. But `๐ฆ` is a predicate (of
type `(Algebra ฮฑ) โ Type ฮฒ`) and the type `Algebra ฮฑ` seems rather nebulous in
that there is no natural indexing class with which to "enumerate" all inhabitants
of `Algebra ฮฑ` belonging to `๐ฆ`.
The solution is to essentially take `๐ฆ` itself to be the indexing type, at least
heuristically that is how one can view the type `โ` that we now define.
```agda
module _ {๐ฆ : Pred (Algebra ฮฑ)(ov ฮฑ)} where
โ : Type (ov ฮฑ)
โ = ฮฃ[ ๐จ โ Algebra ฮฑ ] ๐จ โ ๐ฆ
```
Taking the product over the index type `โ` requires a function that maps an index
`i : โ` to the corresponding algebra. Each `i : โ` is a pair, `(๐จ , p)`, where
`๐จ` is an algebra and `p` is a proof that `๐จ` belongs to `๐ฆ`, so the function
mapping an index to the corresponding algebra is simply the first projection.
```agda
๐ : โ โ Algebra ฮฑ
๐ i = โฃ i โฃ
```
Finally, we define `class-product` which represents the product of all members of
๐ฆ.
```agda
class-product : Algebra (ov ฮฑ)
class-product = โจ
๐
```
If `p : ๐จ โ ๐ฆ`, we view the pair `(๐จ , p) โ โ` as an *index* over the class, so we
can think of `๐ (๐จ , p)` (which is simply `๐จ`) as the projection of the product `โจ
๐` onto the `(๐จ , p)`-th component.