------------------------------------------------------------------------
-- The Agda standard library
--
-- Surjections
------------------------------------------------------------------------

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

module Function.Surjection where

open import Level
open import Function.Equality as F
  using (_⟶_) renaming (_∘_ to _⟪∘⟫_)
open import Function.Equivalence using (Equivalence)
open import Function.Injection           hiding (id; _∘_; injection)
open import Function.LeftInverse as Left hiding (id; _∘_)
open import Data.Product
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (_≡_)

------------------------------------------------------------------------
-- Surjective functions.

record Surjective {f₁ f₂ t₁ t₂}
                  {From : Setoid f₁ f₂} {To : Setoid t₁ t₂}
                  (to : From  To) :
                  Set (f₁  f₂  t₁  t₂) where
  field
    from             : To  From
    right-inverse-of : from RightInverseOf to

------------------------------------------------------------------------
-- The set of all surjections from one setoid to another.

record Surjection {f₁ f₂ t₁ t₂}
                  (From : Setoid f₁ f₂) (To : Setoid t₁ t₂) :
                  Set (f₁  f₂  t₁  t₂) where
  field
    to         : From  To
    surjective : Surjective to

  open Surjective surjective public

  right-inverse : RightInverse From To
  right-inverse = record
    { to              = from
    ; from            = to
    ; left-inverse-of = right-inverse-of
    }

  open LeftInverse right-inverse public
    using () renaming (to-from to from-to)

  injective : Injective from
  injective = LeftInverse.injective right-inverse

  injection : Injection To From
  injection = LeftInverse.injection right-inverse

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

-- Right inverses can be turned into surjections.

fromRightInverse :
   {f₁ f₂ t₁ t₂} {From : Setoid f₁ f₂} {To : Setoid t₁ t₂} 
  RightInverse From To  Surjection From To
fromRightInverse r = record
  { to         = from
  ; surjective = record
    { from             = to
    ; right-inverse-of = left-inverse-of
    }
  } where open LeftInverse r

------------------------------------------------------------------------
-- The set of all surjections from one set to another (i.e. sujections
-- with propositional equality)

infix 3 _↠_

_↠_ :  {f t}  Set f  Set t  Set _
From  To = Surjection (P.setoid From) (P.setoid To)

surjection :  {f t} {From : Set f} {To : Set t} 
             (to : From  To) (from : To  From) 
             (∀ x  to (from x)  x) 
             From  To
surjection to from surjective = record
  { to         = P.→-to-⟶ to
  ; surjective = record
    { from             = P.→-to-⟶ from
    ; right-inverse-of = surjective
    }
  }

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

id :  {s₁ s₂} {S : Setoid s₁ s₂}  Surjection S S
id {S = S} = record
  { to         = F.id
  ; surjective = record
    { from             = LeftInverse.to              id′
    ; right-inverse-of = LeftInverse.left-inverse-of id′
    }
  } where id′ = Left.id {S = S}

infixr 9 _∘_

_∘_ :  {f₁ f₂ m₁ m₂ t₁ t₂}
        {F : Setoid f₁ f₂} {M : Setoid m₁ m₂} {T : Setoid t₁ t₂} 
      Surjection M T  Surjection F M  Surjection F T
f  g = record
  { to         = to f ⟪∘⟫ to g
  ; surjective = record
    { from             = LeftInverse.to              g∘f
    ; right-inverse-of = LeftInverse.left-inverse-of g∘f
    }
  }
  where
  open Surjection
  g∘f = Left._∘_ (right-inverse g) (right-inverse f)