```------------------------------------------------------------------------
-- The Agda standard library
--
-- Left inverses
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

-- Note: use of the standard function hierarchy is encouraged. The
-- module `Function` re-exports `Inverseˡ`, `IsLeftInverse` and
-- `LeftInverse`. The alternative definitions found in this file will
-- eventually be deprecated.

module Function.LeftInverse where

open import Data.Product
open import Level
import Relation.Binary.Reasoning.Setoid as EqReasoning
open import Relation.Binary
open import Function.Equality as Eq
using (_⟶_; _⟨\$⟩_) renaming (_∘_ to _⟪∘⟫_)
open import Function.Equivalence using (Equivalence)
open import Function.Injection using (Injective; Injection)
open import Relation.Binary.PropositionalEquality as P using (_≡_)

------------------------------------------------------------------------
-- Left and right inverses.

_LeftInverseOf_ :
∀ {f₁ f₂ t₁ t₂} {From : Setoid f₁ f₂} {To : Setoid t₁ t₂} →
To ⟶ From → From ⟶ To → Set _
_LeftInverseOf_ {From = From} f g = ∀ x → f ⟨\$⟩ (g ⟨\$⟩ x) ≈ x
where open Setoid From

_RightInverseOf_ :
∀ {f₁ f₂ t₁ t₂} {From : Setoid f₁ f₂} {To : Setoid t₁ t₂} →
To ⟶ From → From ⟶ To → Set _
f RightInverseOf g = g LeftInverseOf f

------------------------------------------------------------------------
-- The set of all left inverses between two setoids.

record LeftInverse {f₁ f₂ t₁ t₂}
(From : Setoid f₁ f₂) (To : Setoid t₁ t₂) :
Set (f₁ ⊔ f₂ ⊔ t₁ ⊔ t₂) where
field
to              : From ⟶ To
from            : To ⟶ From
left-inverse-of : from LeftInverseOf to

private
open module F = Setoid From
open module T = Setoid To
open EqReasoning From

injective : Injective to
injective {x} {y} eq = begin
x                    ≈⟨ F.sym (left-inverse-of x) ⟩
from ⟨\$⟩ (to ⟨\$⟩ x)  ≈⟨ Eq.cong from eq ⟩
from ⟨\$⟩ (to ⟨\$⟩ y)  ≈⟨ left-inverse-of y ⟩
y                    ∎

injection : Injection From To
injection = record { to = to; injective = injective }

equivalence : Equivalence From To
equivalence = record
{ to   = to
; from = from
}

to-from : ∀ {x y} → to ⟨\$⟩ x T.≈ y → from ⟨\$⟩ y F.≈ x
to-from {x} {y} to-x≈y = begin
from ⟨\$⟩ y           ≈⟨ Eq.cong from (T.sym to-x≈y) ⟩
from ⟨\$⟩ (to ⟨\$⟩ x)  ≈⟨ left-inverse-of x ⟩
x                    ∎

-- The set of all right inverses between two setoids.

RightInverse : ∀ {f₁ f₂ t₁ t₂}
(From : Setoid f₁ f₂) (To : Setoid t₁ t₂) → Set _
RightInverse From To = LeftInverse To From

------------------------------------------------------------------------
-- The set of all left inverses from one set to another (i.e. left
-- inverses with propositional equality).
--
-- Read A ↞ B as "surjection from B to A".

infix 3 _↞_

_↞_ : ∀ {f t} → Set f → Set t → Set _
From ↞ To = LeftInverse (P.setoid From) (P.setoid To)

leftInverse : ∀ {f t} {From : Set f} {To : Set t} →
(to : From → To) (from : To → From) →
(∀ x → from (to x) ≡ x) →
From ↞ To
leftInverse to from invˡ = record
{ to              = P.→-to-⟶ to
; from            = P.→-to-⟶ from
; left-inverse-of = invˡ
}

------------------------------------------------------------------------
-- Identity and composition.

id : ∀ {s₁ s₂} {S : Setoid s₁ s₂} → LeftInverse S S
id {S = S} = record
{ to              = Eq.id
; from            = Eq.id
; left-inverse-of = λ _ → Setoid.refl S
}

infixr 9 _∘_

_∘_ : ∀ {f₁ f₂ m₁ m₂ t₁ t₂}
{F : Setoid f₁ f₂} {M : Setoid m₁ m₂} {T : Setoid t₁ t₂} →
LeftInverse M T → LeftInverse F M → LeftInverse F T
_∘_ {F = F} f g = record
{ to              = to   f ⟪∘⟫ to   g
; from            = from g ⟪∘⟫ from f
; left-inverse-of = λ x → begin
from g ⟨\$⟩ (from f ⟨\$⟩ (to f ⟨\$⟩ (to g ⟨\$⟩ x)))  ≈⟨ Eq.cong (from g) (left-inverse-of f (to g ⟨\$⟩ x)) ⟩
from g ⟨\$⟩ (to g ⟨\$⟩ x)                          ≈⟨ left-inverse-of g x ⟩
x                                                ∎
}
where
open LeftInverse
open EqReasoning F
```