index

⚠️ This module is not part of this project and is only included for reference.
It is either part of the 1lab, the cubical library, or a built-in Agda module.

<!--
```agda
open import 1Lab.Prelude hiding (_∘_ ; id ; _↪_ ; _↠_ ; module Extensionality)

open import Cat.Solver
open import Cat.Base
```
-->

```agda
module Cat.Morphism {o h} (C : Precategory o h) where
```

<!--
```agda
open Precategory C public
private variable
  a b c d : Ob
  f : Hom a b
```
-->

# Morphisms

This module defines the three most important classes of morphisms that
can be found in a category: **monomorphisms**, **epimorphisms**, and
**isomorphisms**.

## Monos {defines="monomorphism monic"}

A morphism is said to be **monic** when it is left-cancellable. A
**monomorphism** from $A$ to $B$, written $A \mono B$, is a monic
morphism.

```agda
is-monic : Hom a b  Type _
is-monic {a = a} f =  {c}  (g h : Hom c a)  f  g  f  h  g  h

is-monic-is-prop :  {a b} (f : Hom a b)  is-prop (is-monic f)
is-monic-is-prop f x y i {c} g h p = Hom-set _ _ _ _ (x g h p) (y g h p) i

record _↪_ (a b : Ob) : Type (o  h) where
  field
    mor   : Hom a b
    monic : is-monic mor

open _↪_ public
```

<!--
```agda
↪-is-set :  {a b}  is-set (a  b)
↪-is-set = Iso→is-hlevel 2 eqv hlevel!
  where unquoteDecl eqv = declare-record-iso eqv (quote _↪_)

instance
  H-Level-↪ :  {a b} {n}  H-Level (a  b) (suc (suc n))
  H-Level-↪ = basic-instance 2 ↪-is-set
```
-->

Conversely, a morphism is said to be **epic** when it is
right-cancellable.  An **epimorphism** from $A$ to $B$, written $A \epi
B$, is an epic morphism.

## Epis {defines="epimorphism epic"}

```agda
is-epic : Hom a b  Type _
is-epic {b = b} f =  {c}  (g h : Hom b c)  g  f  h  f  g  h

is-epic-is-prop :  {a b} (f : Hom a b)  is-prop (is-epic f)
is-epic-is-prop f x y i {c} g h p = Hom-set _ _ _ _ (x g h p) (y g h p) i

record _↠_ (a b : Ob) : Type (o  h) where
  field
    mor  : Hom a b
    epic : is-epic mor

open _↠_ public
```

<!--
```agda
↠-is-set :  {a b}  is-set (a  b)
↠-is-set = Iso→is-hlevel 2 eqv hlevel!
  where unquoteDecl eqv = declare-record-iso eqv (quote _↠_)

instance
  H-Level-↠ :  {a b} {n}  H-Level (a  b) (suc (suc n))
  H-Level-↠ = basic-instance 2 ↠-is-set
```
-->

The identity morphism is monic and epic.

```agda
id-monic :  {a}  is-monic (id {a})
id-monic g h p = sym (idl _) ·· p ·· idl _

id-epic :  {a}  is-epic (id {a})
id-epic g h p = sym (idr _) ·· p ·· idr _
```

Both monos and epis are closed under composition.

```agda
monic-∘
  :  {a b c} {f : Hom b c} {g : Hom a b}
   is-monic f
   is-monic g
   is-monic (f  g)
monic-∘ fm gm a b α = gm _ _ (fm _ _ (assoc _ _ _ ·· α ·· sym (assoc _ _ _)))

epic-∘
  :  {a b c} {f : Hom b c} {g : Hom a b}
   is-epic f
   is-epic g
   is-epic (f  g)
epic-∘ fe ge a b α = fe _ _ (ge _ _ (sym (assoc _ _ _) ·· α ·· (assoc _ _ _)))

_∘Mono_ :  {a b c}  b  c  a  b  a  c
(f ∘Mono g) .mor = f .mor  g .mor
(f ∘Mono g) .monic = monic-∘ (f .monic) (g .monic)

_∘Epi_ :  {a b c}  b  c  a  b  a  c
(f ∘Epi g) .mor = f .mor  g .mor
(f ∘Epi g) .epic = epic-∘ (f .epic) (g .epic)
```

If $f \circ g$ is monic, then $g$ must also be monic.

```agda
monic-cancell
  :  {a b c} {f : Hom b c} {g : Hom a b}
   is-monic (f  g)
   is-monic g
monic-cancell {f = f} fg-monic h h' p = fg-monic h h' $
  sym (assoc _ _ _) ·· ap (f ∘_) p ·· assoc _ _ _
```

Dually, if $f \circ g$ is epic, then $f$ must also be epic.

```agda
epic-cancelr
  :  {a b c} {f : Hom b c} {g : Hom a b}
   is-epic (f  g)
   is-epic f
epic-cancelr {g = g} fg-epic h h' p = fg-epic h h' $
  assoc _ _ _ ·· ap (_∘ g) p ·· sym (assoc _ _ _)
```

Postcomposition with a mono is an embedding.

```agda
monic-postcomp-embedding
  :  {a b c} {f : Hom b c}
   is-monic f
   is-embedding {A = Hom a b} (f ∘_)
monic-postcomp-embedding monic =
  injective→is-embedding (Hom-set _ _) _ (monic _ _)
```

Likewise, precomposition with an epi is an embedding.

```agda
epic-precomp-embedding
  :  {a b c} {f : Hom a b}
   is-epic f
   is-embedding {A = Hom b c} (_∘ f)
epic-precomp-embedding epic =
  injective→is-embedding (Hom-set _ _) _ (epic _ _)
```

## Sections

A morphism $s : B \to A$ is a section of another morphism $r : A \to B$
when $r \cdot s = id$. The intuition for this name is that $s$ picks
out a cross-section of $a$ from $b$. For instance, $r$ could map
animals to their species; a section of this map would have to pick out
a canonical representative of each species from the set of all animals.

```agda
_section-of_ : (s : Hom b a) (r : Hom a b)  Type _
s section-of r = r  s  id

section-of-is-prop
  :  {s : Hom b a} {r : Hom a b}
   is-prop (s section-of r)
section-of-is-prop = Hom-set _ _ _ _

record has-section (r : Hom a b) : Type h where
  constructor make-section
  field
    section : Hom b a
    is-section : section section-of r

open has-section public

id-has-section :  {a}  has-section (id {a})
id-has-section .section = id
id-has-section .is-section = idl _

section-of-∘
  :  {a b c} {f : Hom c b} {g : Hom b c} {h : Hom b a} {i : Hom a b}
   f section-of g  h section-of i
   (h  f) section-of (g  i)
section-of-∘ {f = f} {g = g} {h = h} {i = i} fg-sect hi-sect =
  (g  i)  h  f ≡⟨ cat! C 
  g  (i  h)  f ≡⟨ ap  ϕ  g  ϕ  f) hi-sect 
  g  id  f      ≡⟨ ap (g ∘_) (idl _) 
  g  f           ≡⟨ fg-sect 
  id 

section-∘
  :  {a b c} {f : Hom b c} {g : Hom a b}
   has-section f  has-section g  has-section (f  g)
section-∘ f-sect g-sect .section = g-sect .section  f-sect .section
section-∘ {f = f} {g = g} f-sect g-sect .is-section =
  section-of-∘ (f-sect .is-section) (g-sect .is-section)
```

If $f$ has a section, then $f$ is epic.

```agda
has-section→epic
  :  {a b} {f : Hom a b}
   has-section f
   is-epic f
has-section→epic {f = f} f-sect g h p =
  g                         ≡˘⟨ idr _ 
  g  id                    ≡˘⟨ ap (g ∘_) (f-sect .is-section) 
  g  f  f-sect .section   ≡⟨ assoc _ _ _ 
  (g  f)  f-sect .section ≡⟨ ap (_∘ f-sect .section) p 
  (h  f)  f-sect .section ≡˘⟨ assoc _ _ _ 
  h  f  f-sect .section   ≡⟨ ap (h ∘_) (f-sect .is-section) 
  h  id                    ≡⟨ idr _ 
  h 
```

<!--
```agda
has-section-is-set :  {a b} {f : Hom a b}  is-set (has-section f)
has-section-is-set = Iso→is-hlevel 2 eqv hlevel!
  where unquoteDecl eqv = declare-record-iso eqv (quote has-section)

instance
  H-Level-has-section
    :  {a b} {f : Hom a b} {n}
     H-Level (has-section f) (suc (suc n))
  H-Level-has-section = basic-instance 2 has-section-is-set
```
-->

## Retracts

A morphism $r : A \to B$ is a retract of another morphism $s : B \to A$
when $r \cdot s = id$. Note that this is the same equation involved
in the definition of a section; retracts and sections always come in
pairs. If sections solve a sort of "curation problem" where we are
asked to pick out canonical representatives, then retracts solve a
sort of "classification problem".

```agda
_retract-of_ : (r : Hom a b) (s : Hom b a)  Type _
r retract-of s = r  s  id

retract-of-is-prop
  :  {s : Hom b a} {r : Hom a b}
   is-prop (r retract-of s)
retract-of-is-prop = Hom-set _ _ _ _

record has-retract (s : Hom b a) : Type h where
  constructor make-retract
  field
    retract : Hom a b
    is-retract : retract retract-of s

open has-retract public

id-has-retract :  {a}  has-retract (id {a})
id-has-retract .retract = id
id-has-retract .is-retract = idl _

retract-of-∘
  :  {a b c} {f : Hom c b} {g : Hom b c} {h : Hom b a} {i : Hom a b}
   f retract-of g  h retract-of i
   (h  f) retract-of (g  i)
retract-of-∘ fg-ret hi-ret = section-of-∘ hi-ret fg-ret

retract-∘
  :  {a b c} {f : Hom b c} {g : Hom a b}
   has-retract f  has-retract g
   has-retract (f  g)
retract-∘ f-ret g-ret .retract = g-ret .retract  f-ret .retract
retract-∘ f-ret g-ret .is-retract =
  retract-of-∘ (f-ret .is-retract) (g-ret .is-retract)
```

<!--
```agda
has-retract-is-set :  {a b} {f : Hom a b}  is-set (has-retract f)
has-retract-is-set = Iso→is-hlevel 2 eqv hlevel!
  where unquoteDecl eqv = declare-record-iso eqv (quote has-retract)

instance
  H-Level-has-retract
    :  {a b} {f : Hom a b} {n}
     H-Level (has-retract f) (suc (suc n))
  H-Level-has-retract = basic-instance 2 has-retract-is-set
```
-->

If $f$ has a retract, then $f$ is monic.

```agda
has-retract→monic
  :  {a b} {f : Hom a b}
   has-retract f
   is-monic f
has-retract→monic {f = f} f-ret g h p =
  g                        ≡˘⟨ idl _ 
  id  g                   ≡˘⟨ ap (_∘ g) (f-ret .is-retract) 
  (f-ret .retract  f)  g ≡˘⟨ assoc _ _ _ 
  f-ret .retract  (f  g) ≡⟨ ap (f-ret .retract ∘_) p 
  f-ret .retract  f  h   ≡⟨ assoc _ _ _ 
  (f-ret .retract  f)  h ≡⟨ ap (_∘ h) (f-ret .is-retract) 
  id  h                   ≡⟨ idl _ 
  h                        
```

A section that is also epic is a retract.

```agda
section-of+epic→retract-of
  :  {a b} {s : Hom b a} {r : Hom a b}
   s section-of r
   is-epic s
   s retract-of r
section-of+epic→retract-of {s = s} {r = r} sect epic =
  epic (s  r) id $
    (s  r)  s ≡˘⟨ assoc s r s 
    s  (r  s) ≡⟨ ap (s ∘_) sect 
    s  id      ≡⟨ idr _ 
    s           ≡˘⟨ idl _ 
    id  s      
```

Dually, a retract that is also monic is a section.

```agda
retract-of+monic→section-of
  :  {a b} {s : Hom b a} {r : Hom a b}
   r retract-of s
   is-monic r
   r section-of s
retract-of+monic→section-of {s = s} {r = r} ret monic =
  monic (s  r) id $
    r  s  r   ≡⟨ assoc r s r 
    (r  s)  r ≡⟨ ap (_∘ r) ret 
    id  r      ≡⟨ idl _ 
    r           ≡˘⟨ idr _ 
    r  id      
```

<!--
```agda
has-retract+epic→has-section
  :  {a b} {f : Hom a b}
   has-retract f
   is-epic f
   has-section f
has-retract+epic→has-section ret epic .section = ret .retract
has-retract+epic→has-section ret epic .is-section =
  section-of+epic→retract-of (ret .is-retract) epic

has-section+monic→has-retract
  :  {a b} {f : Hom a b}
   has-section f
   is-monic f
   has-retract f
has-section+monic→has-retract sect monic .retract = sect .section
has-section+monic→has-retract sect monic .is-retract =
  retract-of+monic→section-of (sect .is-section) monic
```
-->


## Isos

Maps $f : A \to B$ and $g : B \to A$ are **inverses** when we have $f
\circ g$ and $g \circ f$ both equal to the identity. A map $f : A \to B$
**is invertible** (or **is an isomorphism**) when there exists a $g$ for
which $f$ and $g$ are inverses. An **isomorphism** $A \cong B$ is a
choice of map $A \to B$, together with a specified inverse.

```agda
record Inverses (f : Hom a b) (g : Hom b a) : Type h where
  field
    invl : f  g  id
    invr : g  f  id

open Inverses

record is-invertible (f : Hom a b) : Type h where
  field
    inv : Hom b a
    inverses : Inverses f inv

  open Inverses inverses public

  op : is-invertible inv
  op .inv = f
  op .inverses .Inverses.invl = invr inverses
  op .inverses .Inverses.invr = invl inverses

record _≅_ (a b : Ob) : Type h where
  field
    to       : Hom a b
    from     : Hom b a
    inverses : Inverses to from

  open Inverses inverses public

open _≅_ public
```

A given map is invertible in at most one way: If you have $f : A \to B$
with two _inverses_ $g : B \to A$ and $h : B \to A$, then not only are
$g = h$ equal, but the witnesses of these equalities are irrelevant.

```agda
Inverses-are-prop :  {f : Hom a b} {g : Hom b a}  is-prop (Inverses f g)
Inverses-are-prop x y i .Inverses.invl = Hom-set _ _ _ _ (x .invl) (y .invl) i
Inverses-are-prop x y i .Inverses.invr = Hom-set _ _ _ _ (x .invr) (y .invr) i

is-invertible-is-prop :  {f : Hom a b}  is-prop (is-invertible f)
is-invertible-is-prop {a = a} {b = b} {f = f} g h = p where
  module g = is-invertible g
  module h = is-invertible h

  g≡h : g.inv  h.inv
  g≡h =
    g.inv             ≡⟨ sym (idr _)  ap₂ _∘_ refl (sym h.invl) 
    g.inv  f  h.inv ≡⟨ assoc _ _ _ ·· ap₂ _∘_ g.invr refl ·· idl _ 
    h.inv             

  p : g  h
  p i .is-invertible.inv = g≡h i
  p i .is-invertible.inverses =
    is-prop→pathp  i  Inverses-are-prop {g = g≡h i}) g.inverses h.inverses i
```

We note that the identity morphism is always iso, and that isos compose:

```agda
id-invertible :  {a}  is-invertible (id {a})
id-invertible .is-invertible.inv = id
id-invertible .is-invertible.inverses .invl = idl id
id-invertible .is-invertible.inverses .invr = idl id

id-iso : a  a
id-iso .to = id
id-iso .from = id
id-iso .inverses .invl = idl id
id-iso .inverses .invr = idl id

Isomorphism = _≅_

Inverses-∘ : {f : Hom a b} {f⁻¹ : Hom b a} {g : Hom b c} {g⁻¹ : Hom c b}
            Inverses f f⁻¹  Inverses g g⁻¹  Inverses (g  f) (f⁻¹  g⁻¹)
Inverses-∘ {f = f} {f⁻¹} {g} {g⁻¹} finv ginv = record { invl = l ; invr = r } where
  module finv = Inverses finv
  module ginv = Inverses ginv

  abstract
    l : (g  f)  f⁻¹  g⁻¹  id
    l = (g  f)  f⁻¹  g⁻¹ ≡⟨ cat! C 
        g  (f  f⁻¹)  g⁻¹ ≡⟨  i  g  finv.invl i  g⁻¹) 
        g  id  g⁻¹        ≡⟨ cat! C 
        g  g⁻¹             ≡⟨ ginv.invl 
        id                  

    r : (f⁻¹  g⁻¹)  g  f  id
    r = (f⁻¹  g⁻¹)  g  f ≡⟨ cat! C 
        f⁻¹  (g⁻¹  g)  f ≡⟨  i  f⁻¹  ginv.invr i  f) 
        f⁻¹  id  f        ≡⟨ cat! C 
        f⁻¹  f             ≡⟨ finv.invr 
        id                  

_∘Iso_ : a  b  b  c  a  c
(f ∘Iso g) .to = g .to  f .to
(f ∘Iso g) .from = f .from  g .from
(f ∘Iso g) .inverses = Inverses-∘ (f .inverses) (g .inverses)

infixr 40 _∘Iso_

invertible-∘
  :  {f : Hom b c} {g : Hom a b}
   is-invertible f  is-invertible g
   is-invertible (f  g)
invertible-∘ f-inv g-inv = record
  { inv = g-inv.inv  f-inv.inv
  ; inverses = Inverses-∘ g-inv.inverses f-inv.inverses
  }
  where
    module f-inv = is-invertible f-inv
    module g-inv = is-invertible g-inv

_invertible⁻¹
  :  {f : Hom a b}  (f-inv : is-invertible f)
   is-invertible (is-invertible.inv f-inv)
_invertible⁻¹ {f = f} f-inv .is-invertible.inv = f
_invertible⁻¹ f-inv .is-invertible.inverses .invl =
  is-invertible.invr f-inv
_invertible⁻¹ f-inv .is-invertible.inverses .invr =
  is-invertible.invl f-inv

_Iso⁻¹ : a  b  b  a
(f Iso⁻¹) .to = f .from
(f Iso⁻¹) .from = f .to
(f Iso⁻¹) .inverses .invl = f .inverses .invr
(f Iso⁻¹) .inverses .invr = f .inverses .invl
```

<!--
```agda
make-inverses : {f : Hom a b} {g : Hom b a}  f  g  id  g  f  id  Inverses f g
make-inverses p q .invl = p
make-inverses p q .invr = q

make-invertible : {f : Hom a b}  (g : Hom b a)  f  g  id  g  f  id  is-invertible f
make-invertible g p q .is-invertible.inv = g
make-invertible g p q .is-invertible.inverses .invl = p
make-invertible g p q .is-invertible.inverses .invr = q

make-iso : (f : Hom a b) (g : Hom b a)  f  g  id  g  f  id  a  b
make-iso f g p q ._≅_.to = f
make-iso f g p q ._≅_.from = g
make-iso f g p q ._≅_.inverses .Inverses.invl = p
make-iso f g p q ._≅_.inverses .Inverses.invr = q

instance
  H-Level-is-invertible :  {f : Hom a b} {n}  H-Level (is-invertible f) (suc n)
  H-Level-is-invertible = prop-instance is-invertible-is-prop

inverses→invertible :  {f : Hom a b} {g : Hom b a}  Inverses f g  is-invertible f
inverses→invertible x .is-invertible.inv = _
inverses→invertible x .is-invertible.inverses = x

invertible→iso : (f : Hom a b)  is-invertible f  a  b
invertible→iso f x =
  record
    { to       = f
    ; from     = x .is-invertible.inv
    ; inverses = x .is-invertible.inverses
    }

is-invertible-inverse
  : {f : Hom a b} (g : is-invertible f)  is-invertible (g .is-invertible.inv)
is-invertible-inverse g =
  record { inv = _ ; inverses = record { invl = invr g ; invr = invl g } }
  where open Inverses (g .is-invertible.inverses)

iso→invertible : (i : a  b)  is-invertible (i ._≅_.to)
iso→invertible i = record { inv = i ._≅_.from ; inverses = i ._≅_.inverses }

≅-is-set : is-set (a  b)
≅-is-set x y p q = s where
  open _≅_
  open Inverses

  s : p  q
  s i j .to = Hom-set _ _ (x .to) (y .to) (ap to p) (ap to q) i j
  s i j .from = Hom-set _ _ (x .from) (y .from) (ap from p) (ap from q) i j
  s i j .inverses =
    is-prop→squarep
       i j  Inverses-are-prop {f = Hom-set _ _ (x .to) (y .to) (ap to p) (ap to q) i j}
                                 {g = Hom-set _ _ (x .from) (y .from) (ap from p) (ap from q) i j})
       i  x .inverses)  i  p i .inverses)  i  q i .inverses)  i  y .inverses) i j

instance
  H-Level-≅ :  {a b} {n}  H-Level (a  b) (suc (suc n))
  H-Level-≅ = basic-instance 2 ≅-is-set

private
  ≅-pathp-internal
    : (p : a  c) (q : b  d)
     {f : a  b} {g : c  d}
     PathP  i  Hom (p i) (q i)) (f ._≅_.to) (g ._≅_.to)
     PathP  i  Hom (q i) (p i)) (f ._≅_.from) (g ._≅_.from)
     PathP  i  p i  q i) f g
  ≅-pathp-internal p q r s i .to = r i
  ≅-pathp-internal p q r s i .from = s i
  ≅-pathp-internal p q {f} {g} r s i .inverses =
    is-prop→pathp  j  Inverses-are-prop {f = r j} {g = s j})
      (f .inverses) (g .inverses) i

abstract
  inverse-unique
    : {x y : Ob} (p : x  y) {b d : Ob} (q : b  d) {f : x  b} {g : y  d}
     PathP  i  Hom (p i) (q i)) (f .to) (g .to)
     PathP  i  Hom (q i) (p i)) (f .from) (g .from)
  inverse-unique =
    J'  a c p   {b d} (q : b  d) {f : a  b} {g : c  d}
       PathP  i  Hom (p i) (q i)) (f .to) (g .to)
       PathP  i  Hom (q i) (p i)) (f .from) (g .from))
      λ x  J'  b d q  {f : x  b} {g : x  d}
                 PathP  i  Hom x (q i)) (f .to) (g .to)
                 PathP  i  Hom (q i) x) (f .from) (g .from))
            λ y {f} {g} p 
              f .from                     ≡˘⟨ ap (f .from ∘_) (g .invl)  idr _ 
              f .from  g .to  g .from   ≡⟨ assoc _ _ _ 
              (f .from  g .to)  g .from ≡⟨ ap (_∘ g .from) (ap (f .from ∘_) (sym p)  f .invr)  idl _ 
              g .from                     

≅-pathp
  : (p : a  c) (q : b  d) {f : a  b} {g : c  d}
   PathP  i  Hom (p i) (q i)) (f ._≅_.to) (g ._≅_.to)
   PathP  i  p i  q i) f g
≅-pathp p q {f = f} {g = g} r = ≅-pathp-internal p q r (inverse-unique p q {f = f} {g = g} r)

≅-pathp-from
  : (p : a  c) (q : b  d) {f : a  b} {g : c  d}
   PathP  i  Hom (q i) (p i)) (f ._≅_.from) (g ._≅_.from)
   PathP  i  p i  q i) f g
≅-pathp-from p q {f = f} {g = g} r = ≅-pathp-internal p q (inverse-unique q p {f = f Iso⁻¹} {g = g Iso⁻¹} r) r

≅-path : {f g : a  b}  f ._≅_.to  g ._≅_.to  f  g
≅-path = ≅-pathp refl refl

≅-path-from : {f g : a  b}  f ._≅_.from  g ._≅_.from  f  g
≅-path-from = ≅-pathp-from refl refl

↪-pathp
  : {a : I  Ob} {b : I  Ob} {f : a i0  b i0} {g : a i1  b i1}
   PathP  i  Hom (a i) (b i)) (f .mor) (g .mor)
   PathP  i  a i  b i) f g
↪-pathp {a = a} {b} {f} {g} pa = go where
  go : PathP  i  a i  b i) f g
  go i .mor = pa i
  go i .monic {c = c} =
    is-prop→pathp
       i  Π-is-hlevel {A = Hom c (a i)} 1
       λ g  Π-is-hlevel {A = Hom c (a i)} 1
       λ h  fun-is-hlevel {A = pa i  g  pa i  h} 1
              (Hom-set c (a i) g h))
      (f .monic)
      (g .monic)
      i

↠-pathp
  : {a : I  Ob} {b : I  Ob} {f : a i0  b i0} {g : a i1  b i1}
   PathP  i  Hom (a i) (b i)) (f .mor) (g .mor)
   PathP  i  a i  b i) f g
↠-pathp {a = a} {b} {f} {g} pa = go where
  go : PathP  i  a i  b i) f g
  go i .mor = pa i
  go i .epic {c = c} =
    is-prop→pathp
       i  Π-is-hlevel {A = Hom (b i) c} 1
       λ g  Π-is-hlevel {A = Hom (b i) c} 1
       λ h  fun-is-hlevel {A = g  pa i  h  pa i} 1
              (Hom-set (b i) c g h))
      (f .epic)
      (g .epic)
      i
```
-->


We also note that invertible morphisms are both epic and monic.

```agda
invertible→monic : is-invertible f  is-monic f
invertible→monic {f = f} invert g h p =
  g             ≡˘⟨ idl g 
  id  g        ≡˘⟨ ap (_∘ g) (is-invertible.invr invert) 
  (inv  f)  g ≡˘⟨ assoc inv f g 
  inv  (f  g) ≡⟨ ap (inv ∘_) p 
  inv  (f  h) ≡⟨ assoc inv f h 
  (inv  f)  h ≡⟨ ap (_∘ h) (is-invertible.invr invert) 
  id  h        ≡⟨ idl h 
  h 
  where
    open is-invertible invert

invertible→epic : is-invertible f  is-epic f
invertible→epic {f = f} invert g h p =
  g             ≡˘⟨ idr g 
  g  id        ≡˘⟨ ap (g ∘_) (is-invertible.invl invert) 
  g  (f  inv) ≡⟨ assoc g f inv 
  (g  f)  inv ≡⟨ ap (_∘ inv) p 
  (h  f)  inv ≡˘⟨ assoc h f inv 
  h  (f  inv) ≡⟨ ap (h  ∘_) (is-invertible.invl invert) 
  h  id        ≡⟨ idr h 
  h 
  where
    open is-invertible invert

iso→monic : (f : a  b)  is-monic (f .to)
iso→monic f = invertible→monic (iso→invertible f)

iso→epic : (f : a  b)  is-epic (f .to)
iso→epic f = invertible→epic (iso→invertible f)
```

Furthermore, isomorphisms also yield section/retraction pairs.

```agda
inverses→to-has-section
  :  {f : Hom a b} {g : Hom b a}
   Inverses f g  has-section f
inverses→to-has-section {g = g} inv .section = g
inverses→to-has-section inv .is-section = Inverses.invl inv

inverses→from-has-section
  :  {f : Hom a b} {g : Hom b a}
   Inverses f g  has-section g
inverses→from-has-section {f = f} inv .section = f
inverses→from-has-section inv .is-section = Inverses.invr inv

inverses→to-has-retract
  :  {f : Hom a b} {g : Hom b a}
   Inverses f g  has-retract f
inverses→to-has-retract {g = g} inv .retract = g
inverses→to-has-retract inv .is-retract = Inverses.invr inv

inverses→from-has-retract
  :  {f : Hom a b} {g : Hom b a}
   Inverses f g  has-retract g
inverses→from-has-retract {f = f} inv .retract = f
inverses→from-has-retract inv .is-retract = Inverses.invl inv

iso→to-has-section : (f : a  b)  has-section (f .to)
iso→to-has-section f .section = f .from
iso→to-has-section f .is-section = f .invl

iso→from-has-section : (f : a  b)  has-section (f .from)
iso→from-has-section f .section = f .to
iso→from-has-section f .is-section = f .invr

iso→to-has-retract : (f : a  b)  has-retract (f .to)
iso→to-has-retract f .retract = f .from
iso→to-has-retract f .is-retract = f .invr

iso→from-has-retract : (f : a  b)  has-retract (f .from)
iso→from-has-retract f .retract = f .to
iso→from-has-retract f .is-retract = f .invl
```

Using our lemmas about section/retraction pairs from before, we
can show that if $f$ is a monic retract, then $f$ is an
iso.

```agda
retract-of+monic→inverses
  :  {a b} {s : Hom b a} {r : Hom a b}
   r retract-of s
   is-monic r
   Inverses r s
retract-of+monic→inverses ret monic .invl = ret
retract-of+monic→inverses ret monic .invr =
  retract-of+monic→section-of ret monic
```

We also have a dual result for sections and epis.

```agda
section-of+epic→inverses
  :  {a b} {s : Hom b a} {r : Hom a b}
   s retract-of r
   is-epic r
   Inverses r s
section-of+epic→inverses sect epic .invl =
  section-of+epic→retract-of sect epic
section-of+epic→inverses sect epic .invr = sect
```

<!--
```agda
has-retract+epic→invertible
  :  {a b} {f : Hom a b}
   has-retract f
   is-epic f
   is-invertible f
has-retract+epic→invertible f-ret epic .is-invertible.inv =
  f-ret .retract
has-retract+epic→invertible f-ret epic .is-invertible.inverses =
  section-of+epic→inverses (f-ret .is-retract) epic

has-section+monic→invertible
  :  {a b} {f : Hom a b}
   has-section f
   is-monic f
   is-invertible f
has-section+monic→invertible f-sect monic .is-invertible.inv =
  f-sect .section
has-section+monic→invertible f-sect monic .is-invertible.inverses =
  retract-of+monic→inverses (f-sect .is-section) monic
```
-->

Hom-sets between isomorphic objects are equivalent. Crucially, this
allows us to use [[univalence]] to transport properties between
hom-sets.

```agda
iso→hom-equiv
  :  {a a' b b'}  a  a'  b  b'
   Hom a b  Hom a' b'
iso→hom-equiv f g = Iso→Equiv $
   h  g .to  h  f .from) ,
  iso  h  g .from  h  f .to )
     h 
      g .to  (g .from  h  f .to)  f .from   ≡⟨ cat! C 
      (g .to  g .from)  h  (f .to  f .from) ≡⟨ ap₂  l r  l  h  r) (g .invl) (f .invl) 
      id  h  id                               ≡⟨ cat! C 
      h )
     h 
      g .from  (g .to  h  f .from)  f .to   ≡⟨ cat! C 
      (g .from  g .to)  h  (f .from  f .to) ≡⟨ ap₂  l r  l  h  r) (g .invr) (f .invr) 
      id  h  id                               ≡⟨ cat! C 
      h )
```

<!--
```agda
-- Optimized versions of Iso→Hom-equiv which yield nicer results
-- if only one isomorphism is needed.
dom-iso→hom-equiv
  :  {a a' b}  a  a'
   Hom a b  Hom a' b
dom-iso→hom-equiv f = Iso→Equiv $
   h  h  f .from) ,
  iso  h  h  f .to )
     h 
      (h  f .to)  f .from ≡⟨ sym (assoc _ _ _) 
      h  (f .to  f .from) ≡⟨ ap (h ∘_) (f .invl) 
      h  id                ≡⟨ idr _ 
      h )
     h 
      (h  f .from)  f .to ≡⟨ sym (assoc _ _ _) 
      h  (f .from  f .to) ≡⟨ ap (h ∘_) (f .invr) 
      h  id                ≡⟨ idr _ 
      h )

cod-iso→Hom-equiv
  :  {a b b'}  b  b'
   Hom a b  Hom a b'
cod-iso→Hom-equiv f = Iso→Equiv $
   h  f .to  h) ,
  iso  h  f .from  h)
     h 
      f .to  f .from  h   ≡⟨ assoc _ _ _ 
      (f .to  f .from)  h ≡⟨ ap (_∘ h) (f .invl) 
      id  h                ≡⟨ idl _ 
      h )
     h 
      f .from  f .to  h   ≡⟨ assoc _ _ _ 
      (f .from  f .to)  h ≡⟨ ap (_∘ h) (f .invr) 
      id  h                ≡⟨ idl _ 
      h )
```
-->

If $f$ is invertible, then both pre and post-composition with $f$ are
equivalences.

```agda
invertible-precomp-equiv
  :  {a b c} {f : Hom a b}
   is-invertible f
   is-equiv {A = Hom b c} (_∘ f)
invertible-precomp-equiv {f = f} f-inv = is-iso→is-equiv $
  iso  h  h  f-inv.inv)
     h  sym (assoc _ _ _) ·· ap (h ∘_) f-inv.invr ·· idr h)
     h  sym (assoc _ _ _) ·· ap (h ∘_) f-inv.invl ·· idr h)
  where module f-inv = is-invertible f-inv

invertible-postcomp-equiv
  :  {a b c} {f : Hom b c}
   is-invertible f
   is-equiv {A = Hom a b} (f ∘_)
invertible-postcomp-equiv {f = f} f-inv = is-iso→is-equiv $
  iso  h  f-inv.inv  h)
     h  assoc _ _ _ ·· ap (_∘ h) f-inv.invl ·· idl h)
     h  assoc _ _ _ ·· ap (_∘ h) f-inv.invr ·· idl h)
  where module f-inv = is-invertible f-inv
```