------------------------------------------------------------------------ -- The Agda standard library -- -- Bundles for types of functions ------------------------------------------------------------------------ -- The contents of this file should usually be accessed from `Function`. -- Note that these bundles differ from those found elsewhere in other -- library hierarchies as they take Setoids as parameters. This is -- because a function is of no use without knowing what its domain and -- codomain is, as well which equalities are being considered over them. -- One consequence of this is that they are not built from the -- definitions found in `Function.Structures` as is usually the case in -- other library hierarchies, as this would duplicate the equality -- axioms. {-# OPTIONS --cubical-compatible --safe #-} module Function.Bundles where open import Function.Base using (_∘_) open import Function.Definitions import Function.Structures as FunctionStructures open import Level using (Level; _⊔_; suc) open import Data.Product.Base using (_,_; proj₁; proj₂) open import Relation.Binary.Bundles using (Setoid) open import Relation.Binary.Core using (_Preserves_⟶_) open import Relation.Binary.PropositionalEquality.Core as using (_≡_) import Relation.Binary.PropositionalEquality.Properties as open import Function.Consequences.Propositional open Setoid using (isEquivalence) private variable a b ℓ₁ ℓ₂ : Level ------------------------------------------------------------------------ -- Setoid bundles ------------------------------------------------------------------------ module _ (From : Setoid a ℓ₁) (To : Setoid b ℓ₂) where open Setoid From using () renaming (Carrier to A; _≈_ to _≈₁_) open Setoid To using () renaming (Carrier to B; _≈_ to _≈₂_) open FunctionStructures _≈₁_ _≈₂_ ------------------------------------------------------------------------ -- Bundles with one element -- Called `Func` rather than `Function` in order to avoid clashing -- with the top-level module. record Func : Set (a b ℓ₁ ℓ₂) where field to : A B cong : Congruent _≈₁_ _≈₂_ to isCongruent : IsCongruent to isCongruent = record { cong = cong ; isEquivalence₁ = isEquivalence From ; isEquivalence₂ = isEquivalence To } open IsCongruent isCongruent public using (module Eq₁; module Eq₂) record Injection : Set (a b ℓ₁ ℓ₂) where field to : A B cong : Congruent _≈₁_ _≈₂_ to injective : Injective _≈₁_ _≈₂_ to function : Func function = record { to = to ; cong = cong } open Func function public hiding (to; cong) isInjection : IsInjection to isInjection = record { isCongruent = isCongruent ; injective = injective } record Surjection : Set (a b ℓ₁ ℓ₂) where field to : A B cong : Congruent _≈₁_ _≈₂_ to surjective : Surjective _≈₁_ _≈₂_ to function : Func function = record { to = to ; cong = cong } open Func function public hiding (to; cong) isSurjection : IsSurjection to isSurjection = record { isCongruent = isCongruent ; surjective = surjective } open IsSurjection isSurjection public using ( strictlySurjective ) to⁻ : B A to⁻ = proj₁ surjective to∘to⁻ : x to (to⁻ x) ≈₂ x to∘to⁻ = proj₂ strictlySurjective record Bijection : Set (a b ℓ₁ ℓ₂) where field to : A B cong : Congruent _≈₁_ _≈₂_ to bijective : Bijective _≈₁_ _≈₂_ to injective : Injective _≈₁_ _≈₂_ to injective = proj₁ bijective surjective : Surjective _≈₁_ _≈₂_ to surjective = proj₂ bijective injection : Injection injection = record { cong = cong ; injective = injective } surjection : Surjection surjection = record { cong = cong ; surjective = surjective } open Injection injection public using (isInjection) open Surjection surjection public using (isSurjection; to⁻; strictlySurjective) isBijection : IsBijection to isBijection = record { isInjection = isInjection ; surjective = surjective } open IsBijection isBijection public using (module Eq₁; module Eq₂) ------------------------------------------------------------------------ -- Bundles with two elements module _ (From : Setoid a ℓ₁) (To : Setoid b ℓ₂) where open Setoid From using () renaming (Carrier to A; _≈_ to _≈₁_) open Setoid To using () renaming (Carrier to B; _≈_ to _≈₂_) open FunctionStructures _≈₁_ _≈₂_ record Equivalence : Set (a b ℓ₁ ℓ₂) where field to : A B from : B A to-cong : Congruent _≈₁_ _≈₂_ to from-cong : Congruent _≈₂_ _≈₁_ from toFunction : Func From To toFunction = record { to = to ; cong = to-cong } open Func toFunction public using (module Eq₁; module Eq₂) renaming (isCongruent to to-isCongruent) fromFunction : Func To From fromFunction = record { to = from ; cong = from-cong } open Func fromFunction public using () renaming (isCongruent to from-isCongruent) record LeftInverse : Set (a b ℓ₁ ℓ₂) where field to : A B from : B A to-cong : Congruent _≈₁_ _≈₂_ to from-cong : Congruent _≈₂_ _≈₁_ from inverseˡ : Inverseˡ _≈₁_ _≈₂_ to from isCongruent : IsCongruent to isCongruent = record { cong = to-cong ; isEquivalence₁ = isEquivalence From ; isEquivalence₂ = isEquivalence To } isLeftInverse : IsLeftInverse to from isLeftInverse = record { isCongruent = isCongruent ; from-cong = from-cong ; inverseˡ = inverseˡ } open IsLeftInverse isLeftInverse public using (module Eq₁; module Eq₂; strictlyInverseˡ; isSurjection) equivalence : Equivalence equivalence = record { to-cong = to-cong ; from-cong = from-cong } isSplitSurjection : IsSplitSurjection to isSplitSurjection = record { from = from ; isLeftInverse = isLeftInverse } surjection : Surjection From To surjection = record { to = to ; cong = to-cong ; surjective = λ y from y , inverseˡ } record RightInverse : Set (a b ℓ₁ ℓ₂) where field to : A B from : B A to-cong : Congruent _≈₁_ _≈₂_ to from-cong : from Preserves _≈₂_ _≈₁_ inverseʳ : Inverseʳ _≈₁_ _≈₂_ to from isCongruent : IsCongruent to isCongruent = record { cong = to-cong ; isEquivalence₁ = isEquivalence From ; isEquivalence₂ = isEquivalence To } isRightInverse : IsRightInverse to from isRightInverse = record { isCongruent = isCongruent ; from-cong = from-cong ; inverseʳ = inverseʳ } open IsRightInverse isRightInverse public using (module Eq₁; module Eq₂; strictlyInverseʳ) equivalence : Equivalence equivalence = record { to-cong = to-cong ; from-cong = from-cong } record Inverse : Set (a b ℓ₁ ℓ₂) where field to : A B from : B A to-cong : Congruent _≈₁_ _≈₂_ to from-cong : Congruent _≈₂_ _≈₁_ from inverse : Inverseᵇ _≈₁_ _≈₂_ to from inverseˡ : Inverseˡ _≈₁_ _≈₂_ to from inverseˡ = proj₁ inverse inverseʳ : Inverseʳ _≈₁_ _≈₂_ to from inverseʳ = proj₂ inverse leftInverse : LeftInverse leftInverse = record { to-cong = to-cong ; from-cong = from-cong ; inverseˡ = inverseˡ } rightInverse : RightInverse rightInverse = record { to-cong = to-cong ; from-cong = from-cong ; inverseʳ = inverseʳ } open LeftInverse leftInverse public using (isLeftInverse; strictlyInverseˡ) open RightInverse rightInverse public using (isRightInverse; strictlyInverseʳ) isInverse : IsInverse to from isInverse = record { isLeftInverse = isLeftInverse ; inverseʳ = inverseʳ } open IsInverse isInverse public using (module Eq₁; module Eq₂) ------------------------------------------------------------------------ -- Bundles with three elements record BiEquivalence : Set (a b ℓ₁ ℓ₂) where field to : A B from₁ : B A from₂ : B A to-cong : Congruent _≈₁_ _≈₂_ to from₁-cong : Congruent _≈₂_ _≈₁_ from₁ from₂-cong : Congruent _≈₂_ _≈₁_ from₂ record BiInverse : Set (a b ℓ₁ ℓ₂) where field to : A B from₁ : B A from₂ : B A to-cong : Congruent _≈₁_ _≈₂_ to from₁-cong : Congruent _≈₂_ _≈₁_ from₁ from₂-cong : Congruent _≈₂_ _≈₁_ from₂ inverseˡ : Inverseˡ _≈₁_ _≈₂_ to from₁ inverseʳ : Inverseʳ _≈₁_ _≈₂_ to from₂ to-isCongruent : IsCongruent to to-isCongruent = record { cong = to-cong ; isEquivalence₁ = isEquivalence From ; isEquivalence₂ = isEquivalence To } isBiInverse : IsBiInverse to from₁ from₂ isBiInverse = record { to-isCongruent = to-isCongruent ; from₁-cong = from₁-cong ; from₂-cong = from₂-cong ; inverseˡ = inverseˡ ; inverseʳ = inverseʳ } biEquivalence : BiEquivalence biEquivalence = record { to-cong = to-cong ; from₁-cong = from₁-cong ; from₂-cong = from₂-cong } ------------------------------------------------------------------------ -- Other -- A left inverse is also known as a “split surjection”. -- -- As the name implies, a split surjection is a special kind of -- surjection where the witness generated in the domain in the -- function for elements `x₁` and `x₂` are equal if `x₁ ≈ x₂` . -- -- The difference is the `from-cong` law --- generally, the section -- (called `Surjection.to⁻` or `SplitSurjection.from`) of a surjection -- need not respect equality, whereas it must in a split surjection. -- -- The two notions coincide when the equivalence relation on `B` is -- propositional equality (because all functions respect propositional -- equality). -- -- For further background on (split) surjections, one may consult any -- general mathematical references which work without the principle -- of choice. For example: -- -- https://ncatlab.org/nlab/show/split+epimorphism. -- -- The connection to set-theoretic notions with the same names is -- justified by the setoid type theory/homotopy type theory -- observation/definition that (∃x : A. P) = ∥ Σx : A. P ∥ --- i.e., -- we can read set-theoretic ∃ as squashed/propositionally truncated Σ. -- -- We see working with setoids as working in the MLTT model of a setoid -- type theory, in which ∥ X ∥ is interpreted as the setoid with carrier -- set X and the equivalence relation that relates all elements. -- All maps into ∥ X ∥ respect equality, so in the idiomatic definitions -- here, we drop the corresponding trivial `cong` field completely. SplitSurjection : Set _ SplitSurjection = LeftInverse module SplitSurjection (splitSurjection : SplitSurjection) = LeftInverse splitSurjection ------------------------------------------------------------------------ -- Infix abbreviations for oft-used items ------------------------------------------------------------------------ -- Same naming convention as used for propositional equality below, with -- appended ₛ (for 'S'etoid). infixr 0 _⟶ₛ_ _⟶ₛ_ : Setoid a ℓ₁ Setoid b ℓ₂ Set _ _⟶ₛ_ = Func ------------------------------------------------------------------------ -- Bundles specialised for propositional equality ------------------------------------------------------------------------ infix 3 _⟶_ _↣_ _↠_ _⤖_ _⇔_ _↩_ _↪_ _↩↪_ _↔_ _⟶_ : Set a Set b Set _ A B = Func (≡.setoid A) (≡.setoid B) _↣_ : Set a Set b Set _ A B = Injection (≡.setoid A) (≡.setoid B) _↠_ : Set a Set b Set _ A B = Surjection (≡.setoid A) (≡.setoid B) _⤖_ : Set a Set b Set _ A B = Bijection (≡.setoid A) (≡.setoid B) _⇔_ : Set a Set b Set _ A B = Equivalence (≡.setoid A) (≡.setoid B) _↩_ : Set a Set b Set _ A B = LeftInverse (≡.setoid A) (≡.setoid B) _↪_ : Set a Set b Set _ A B = RightInverse (≡.setoid A) (≡.setoid B) _↩↪_ : Set a Set b Set _ A ↩↪ B = BiInverse (≡.setoid A) (≡.setoid B) _↔_ : Set a Set b Set _ A B = Inverse (≡.setoid A) (≡.setoid B) -- We now define some constructors for the above that -- automatically provide the required congruency proofs. module _ {A : Set a} {B : Set b} where mk⟶ : (A B) A B mk⟶ to = record { to = to ; cong = ≡.cong to } mk↣ : {to : A B} Injective _≡_ _≡_ to A B mk↣ {to} inj = record { to = to ; cong = ≡.cong to ; injective = inj } mk↠ : {to : A B} Surjective _≡_ _≡_ to A B mk↠ {to} surj = record { to = to ; cong = ≡.cong to ; surjective = surj } mk⤖ : {to : A B} Bijective _≡_ _≡_ to A B mk⤖ {to} bij = record { to = to ; cong = ≡.cong to ; bijective = bij } mk⇔ : (to : A B) (from : B A) A B mk⇔ to from = record { to = to ; from = from ; to-cong = ≡.cong to ; from-cong = ≡.cong from } mk↩ : {to : A B} {from : B A} Inverseˡ _≡_ _≡_ to from A B mk↩ {to} {from} invˡ = record { to = to ; from = from ; to-cong = ≡.cong to ; from-cong = ≡.cong from ; inverseˡ = invˡ } mk↪ : {to : A B} {from : B A} Inverseʳ _≡_ _≡_ to from A B mk↪ {to} {from} invʳ = record { to = to ; from = from ; to-cong = ≡.cong to ; from-cong = ≡.cong from ; inverseʳ = invʳ } mk↩↪ : {to : A B} {from₁ : B A} {from₂ : B A} Inverseˡ _≡_ _≡_ to from₁ Inverseʳ _≡_ _≡_ to from₂ A ↩↪ B mk↩↪ {to} {from₁} {from₂} invˡ invʳ = record { to = to ; from₁ = from₁ ; from₂ = from₂ ; to-cong = ≡.cong to ; from₁-cong = ≡.cong from₁ ; from₂-cong = ≡.cong from₂ ; inverseˡ = invˡ ; inverseʳ = invʳ } mk↔ : {to : A B} {from : B A} Inverseᵇ _≡_ _≡_ to from A B mk↔ {to} {from} inv = record { to = to ; from = from ; to-cong = ≡.cong to ; from-cong = ≡.cong from ; inverse = inv } -- Strict variant of the above. mk↠ₛ : {to : A B} StrictlySurjective _≡_ to A B mk↠ₛ = mk↠ strictlySurjective⇒surjective mk↔ₛ′ : (to : A B) (from : B A) StrictlyInverseˡ _≡_ to from StrictlyInverseʳ _≡_ to from A B mk↔ₛ′ to from invˡ invʳ = mk↔ {to} {from} ( strictlyInverseˡ⇒inverseˡ to invˡ , strictlyInverseʳ⇒inverseʳ to invʳ ) ------------------------------------------------------------------------ -- Other ------------------------------------------------------------------------ -- Alternative syntax for the application of functions module _ {From : Setoid a ℓ₁} {To : Setoid b ℓ₂} where open Setoid infixl 5 _⟨$⟩_ _⟨$⟩_ : Func From To Carrier From Carrier To _⟨$⟩_ = Func.to