{-# OPTIONS --cubical-compatible --safe #-}
module Data.Product.Function.Dependent.Setoid where
open import Data.Product.Base using (map; _,_; proj₁; proj₂)
open import Data.Product.Relation.Binary.Pointwise.Dependent as Σ
open import Level using (Level)
open import Function
open import Function.Consequences.Setoid
open import Function.Properties.Injection using (mkInjection)
open import Function.Properties.Surjection using (mkSurjection; ↠⇒⇔)
open import Function.Properties.Equivalence using (mkEquivalence; ⇔⇒⟶; ⇔⇒⟵)
open import Function.Properties.RightInverse using (mkRightInverse)
open import Relation.Binary.Core using (_=[_]⇒_)
open import Relation.Binary.Bundles as B
open import Relation.Binary.Indexed.Heterogeneous
using (IndexedSetoid)
open import Relation.Binary.Indexed.Heterogeneous.Construct.At
using (_atₛ_)
open import Relation.Binary.PropositionalEquality.Core as ≡ using (_≡_)
import Relation.Binary.PropositionalEquality.Properties as ≡
private
variable
i a b ℓ₁ ℓ₂ : Level
I J : Set i
A B : IndexedSetoid I a ℓ₁
private module _ (A : IndexedSetoid I a ℓ₁) where
open IndexedSetoid A
cast : ∀ {i j} → j ≡ i → Carrier i → Carrier j
cast j≡i = ≡.subst Carrier (≡.sym $ j≡i)
cast-cong : ∀ {i j} {x y : Carrier i}
(j≡i : j ≡ i) →
x ≈ y →
cast j≡i x ≈ cast j≡i y
cast-cong ≡.refl p = p
cast-eq : ∀ {i j x} (eq : i ≡ j) → cast eq x ≈ x
cast-eq ≡.refl = IndexedSetoid.refl A
private
_×ₛ_ : (I : Set i) → IndexedSetoid I a ℓ₁ → Setoid _ _
I ×ₛ A = Σ.setoid (≡.setoid I) A
module _ where
open Func
open Setoid
function :
(f : I ⟶ J) →
(∀ {i} → Func (A atₛ i) (B atₛ (to f i))) →
Func (I ×ₛ A) (J ×ₛ B)
function {I = I} {J = J} {A = A} {B = B} I⟶J A⟶B = record
{ to = to′
; cong = cong′
}
where
to′ = map (to I⟶J) (to A⟶B)
cong′ : Congruent (_≈_ (I ×ₛ A)) (_≈_ (J ×ₛ B)) to′
cong′ (≡.refl , ∼) = (≡.refl , cong A⟶B ∼)
module _ where
open Equivalence
equivalence :
(I⇔J : I ⇔ J) →
(∀ {i} → Func (A atₛ i) (B atₛ (to I⇔J i))) →
(∀ {j} → Func (B atₛ j) (A atₛ (from I⇔J j))) →
Equivalence (I ×ₛ A) (J ×ₛ B)
equivalence I⇔J A⟶B B⟶A = mkEquivalence
(function (⇔⇒⟶ I⇔J) A⟶B)
(function (⇔⇒⟵ I⇔J) B⟶A)
equivalence-↪ :
(I↪J : I ↪ J) →
(∀ {i} → Equivalence (A atₛ (RightInverse.from I↪J i)) (B atₛ i)) →
Equivalence (I ×ₛ A) (J ×ₛ B)
equivalence-↪ {A = A} {B = B} I↪J A⇔B =
equivalence (RightInverse.equivalence I↪J) A→B (fromFunction A⇔B)
where
A→B : ∀ {i} → Func (A atₛ i) (B atₛ (RightInverse.to I↪J i))
A→B = record
{ to = to A⇔B ∘ cast A (RightInverse.strictlyInverseʳ I↪J _)
; cong = to-cong A⇔B ∘ cast-cong A (RightInverse.strictlyInverseʳ I↪J _)
}
equivalence-↠ :
(I↠J : I ↠ J) →
(∀ {x} → Equivalence (A atₛ x) (B atₛ (Surjection.to I↠J x))) →
Equivalence (I ×ₛ A) (J ×ₛ B)
equivalence-↠ {A = A} {B = B} I↠J A⇔B =
equivalence (↠⇒⇔ I↠J) B-to B-from
where
B-to : ∀ {x} → Func (A atₛ x) (B atₛ (Surjection.to I↠J x))
B-to = toFunction A⇔B
B-from : ∀ {y} → Func (B atₛ y) (A atₛ (Surjection.to⁻ I↠J y))
B-from = record
{ to = from A⇔B ∘ cast B (Surjection.to∘to⁻ I↠J _)
; cong = from-cong A⇔B ∘ cast-cong B (Surjection.to∘to⁻ I↠J _)
}
module _ where
open Injection hiding (function)
open IndexedSetoid
injection :
(I↣J : I ↣ J) →
(∀ {i} → Injection (A atₛ i) (B atₛ (Injection.to I↣J i))) →
Injection (I ×ₛ A) (J ×ₛ B)
injection {I = I} {J = J} {A = A} {B = B} I↣J A↣B = mkInjection func inj
where
func : Func (I ×ₛ A) (J ×ₛ B)
func = function (Injection.function I↣J) (Injection.function A↣B)
inj : Injective (Func.Eq₁._≈_ func) (Func.Eq₂._≈_ func) (Func.to func)
inj (to[i]≡to[j] , y) =
injective I↣J to[i]≡to[j] ,
lemma (injective I↣J to[i]≡to[j]) y
where
lemma :
∀ {i j} {x : Carrier A i} {y : Carrier A j} →
i ≡ j →
(_≈_ B (to A↣B x) (to A↣B y)) →
_≈_ A x y
lemma ≡.refl = Injection.injective A↣B
module _ where
open Surjection hiding (function)
open Setoid
surjection :
(I↠J : I ↠ J) →
(∀ {x} → Surjection (A atₛ x) (B atₛ (to I↠J x))) →
Surjection (I ×ₛ A) (J ×ₛ B)
surjection {I = I} {J = J} {A = A} {B = B} I↠J A↠B =
mkSurjection func surj
where
func : Func (I ×ₛ A) (J ×ₛ B)
func = function (Surjection.function I↠J) (Surjection.function A↠B)
to⁻′ : Carrier (J ×ₛ B) → Carrier (I ×ₛ A)
to⁻′ (j , y) = to⁻ I↠J j , to⁻ A↠B (cast B (Surjection.to∘to⁻ I↠J _) y)
strictlySurj : StrictlySurjective (Func.Eq₂._≈_ func) (Func.to func)
strictlySurj (j , y) = to⁻′ (j , y) ,
to∘to⁻ I↠J j , IndexedSetoid.trans B (to∘to⁻ A↠B _) (cast-eq B (to∘to⁻ I↠J j))
surj : Surjective (Func.Eq₁._≈_ func) (Func.Eq₂._≈_ func) (Func.to func)
surj = strictlySurjective⇒surjective (I ×ₛ A) (J ×ₛ B) (Func.cong func) strictlySurj
module _ where
open RightInverse
open Setoid
left-inverse :
(I↪J : I ↪ J) →
(∀ {j} → RightInverse (A atₛ (from I↪J j)) (B atₛ j)) →
RightInverse (I ×ₛ A) (J ×ₛ B)
left-inverse {I = I} {J = J} {A = A} {B = B} I↪J A↪B =
mkRightInverse equiv invʳ
where
equiv : Equivalence (I ×ₛ A) (J ×ₛ B)
equiv = equivalence-↪ I↪J (RightInverse.equivalence A↪B)
strictlyInvʳ : StrictlyInverseʳ (_≈_ (I ×ₛ A)) (Equivalence.to equiv) (Equivalence.from equiv)
strictlyInvʳ (i , x) = strictlyInverseʳ I↪J i , IndexedSetoid.trans A (strictlyInverseʳ A↪B _) (cast-eq A (strictlyInverseʳ I↪J i))
invʳ : Inverseʳ (_≈_ (I ×ₛ A)) (_≈_ (J ×ₛ B)) (Equivalence.to equiv) (Equivalence.from equiv)
invʳ = strictlyInverseʳ⇒inverseʳ (I ×ₛ A) (J ×ₛ B) (Equivalence.from-cong equiv) strictlyInvʳ
module _ where
open Inverse hiding (inverse)
open Setoid
inverse : (I↔J : I ↔ J) →
(∀ {i} → Inverse (A atₛ i) (B atₛ (to I↔J i))) →
Inverse (I ×ₛ A) (J ×ₛ B)
inverse {I = I} {J = J} {A = A} {B = B} I↔J A↔B = record
{ to = to′
; from = from′
; to-cong = to′-cong
; from-cong = from′-cong
; inverse = invˡ , invʳ
}
where
to′ : Carrier (I ×ₛ A) → Carrier (J ×ₛ B)
to′ (i , x) = to I↔J i , to A↔B x
to′-cong : Congruent (_≈_ (I ×ₛ A)) (_≈_ (J ×ₛ B)) to′
to′-cong (≡.refl , x≈y) = to-cong I↔J ≡.refl , to-cong A↔B x≈y
from′ : Carrier (J ×ₛ B) → Carrier (I ×ₛ A)
from′ (j , y) = from I↔J j , from A↔B (cast B (strictlyInverseˡ I↔J _) y)
from′-cong : Congruent (_≈_ (J ×ₛ B)) (_≈_ (I ×ₛ A)) from′
from′-cong (≡.refl , x≈y) = from-cong I↔J ≡.refl , from-cong A↔B (cast-cong B (strictlyInverseˡ I↔J _) x≈y)
strictlyInvˡ : StrictlyInverseˡ (_≈_ (J ×ₛ B)) to′ from′
strictlyInvˡ (i , x) = strictlyInverseˡ I↔J i ,
IndexedSetoid.trans B (strictlyInverseˡ A↔B _)
(cast-eq B (strictlyInverseˡ I↔J i))
invˡ : Inverseˡ (_≈_ (I ×ₛ A)) (_≈_ (J ×ₛ B)) to′ from′
invˡ = strictlyInverseˡ⇒inverseˡ (I ×ₛ A) (J ×ₛ B) to′-cong strictlyInvˡ
lem : ∀ {i j} → i ≡ j → ∀ {x : IndexedSetoid.Carrier B (to I↔J i)} {y : IndexedSetoid.Carrier B (to I↔J j)} →
IndexedSetoid._≈_ B x y →
IndexedSetoid._≈_ A (from A↔B x) (from A↔B y)
lem ≡.refl x≈y = from-cong A↔B x≈y
strictlyInvʳ : StrictlyInverseʳ (_≈_ (I ×ₛ A)) to′ from′
strictlyInvʳ (i , x) = strictlyInverseʳ I↔J i ,
IndexedSetoid.trans A (lem (strictlyInverseʳ I↔J _) (cast-eq B (strictlyInverseˡ I↔J _))) (strictlyInverseʳ A↔B _)
invʳ : Inverseʳ (_≈_ (I ×ₛ A)) (_≈_ (J ×ₛ B)) to′ from′
invʳ = strictlyInverseʳ⇒inverseʳ (I ×ₛ A) (J ×ₛ B) from′-cong strictlyInvʳ