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.Path
open import 1Lab.Type hiding (id; _∘_)

open import Cat.Base
```
-->

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

open import Cat.Morphism C public
```

# Reasoning combinators for categories

When doing category theory, we often have to perform many "trivial"
algebraic manipulations like reassociation, insertion of identity morphisms, etc.
On paper we can omit these steps, but Agda is a bit more picky!
We could just do these steps in our proofs one after another, but this
clutters things up. Instead, we provide a series of reasoning combinators
to make writing (and reading) proofs easier.

Most of these helpers were taken from `agda-categories`.

<!--
```agda
private variable
  u v w x y z : Ob
  a a' a'' b b' b'' c c' c'' : Hom x y
  f g h i : Hom x y
```
-->

## Identity morphisms

```agda
id-comm :  {a b} {f : Hom a b}  f  id  id  f
id-comm {f = f} = idr f  sym (idl f)

id-comm-sym :  {a b} {f : Hom a b}  id  f  f  id
id-comm-sym {f = f} = idl f  sym (idr f)

idr2 :  {a b c} (f : Hom b c) (g : Hom a b)  f  g  id  f  g
idr2 f g = ap (f ∘_) (idr g)

module _ (a≡id : a  id) where abstract
  eliml : a  f  f
  eliml {f = f} =
    a  f ≡⟨ ap (_∘ f) a≡id 
    id  f ≡⟨ idl f 
    f 

  elimr : f  a  f
  elimr {f = f} =
    f  a ≡⟨ ap (f ∘_) a≡id 
    f  id ≡⟨ idr f 
    f 

  elim-inner : f  a  h  f  h
  elim-inner {f = f} = ap (f ∘_) eliml

  introl : f  a  f
  introl = sym eliml

  intror : f  f  a
  intror = sym elimr

  intro-inner : f  h  f  a  h
  intro-inner {f = f} = ap (f ∘_) introl
```

## Reassocations

We often find ourselves in situations where we have an equality
involving the composition of 2 morphisms, but the association
is a bit off. These combinators aim to address that situation.

```agda
module _ (ab≡c : a  b  c) where abstract
  pulll : a  (b  f)  c  f
  pulll {f = f} =
    a  b  f   ≡⟨ assoc a b f 
    (a  b)  f ≡⟨ ap (_∘ f) ab≡c 
    c  f 

  pullr : (f  a)  b  f  c
  pullr {f = f} =
    (f  a)  b ≡˘⟨ assoc f a b 
    f  (a  b) ≡⟨ ap (f ∘_) ab≡c 
    f  c 

  pull-inner : (f  a)  (b  g)  f  c  g
  pull-inner {f = f} = sym (assoc _ _ _)  ap (f ∘_) pulll

module _ (c≡ab : c  a  b) where abstract
  pushl : c  f  a  (b  f)
  pushl = sym (pulll (sym c≡ab))

  pushr : f  c  (f  a)  b
  pushr = sym (pullr (sym c≡ab))

  push-inner : f  c  g  (f  a)  (b  g)
  push-inner {f = f} = ap (f ∘_) pushl  assoc _ _ _

module _ (p : f  h  g  i) where abstract
  extendl : f  (h  b)  g  (i  b)
  extendl {b = b} =
    f  (h  b) ≡⟨ assoc f h b 
    (f  h)  b ≡⟨ ap (_∘ b) p 
    (g  i)  b ≡˘⟨ assoc g i b 
    g  (i  b) 

  extendr : (a  f)  h  (a  g)  i
  extendr {a = a} =
    (a  f)  h ≡˘⟨ assoc a f h 
    a  (f  h) ≡⟨ ap (a ∘_) p 
    a  (g  i) ≡⟨ assoc a g i 
    (a  g)  i 

  extend-inner : a  f  h  b  a  g  i  b
  extend-inner {a = a} = ap (a ∘_) extendl
```

## Cancellation

These lemmas do 2 things at once: rearrange parenthesis, and also remove
things that are equal to `id`.

```agda
module _ (inv : h  i  id) where abstract
  cancell : h  (i  f)  f
  cancell {f = f} =
    h  (i  f) ≡⟨ pulll inv 
    id  f      ≡⟨ idl f 
    f           

  cancelr : (f  h)  i  f
  cancelr {f = f} =
    (f  h)  i ≡⟨ pullr inv 
    f  id      ≡⟨ idr f 
    f           

  insertl : f  h  (i  f)
  insertl = sym cancell

  insertr : f  (f  h)  i
  insertr = sym cancelr

  cancel-inner : (f  h)  (i  g)  f  g
  cancel-inner = pulll cancelr

  insert-inner : f  g  (f  h)  (i  g)
  insert-inner = pushl insertr

  deleter : (f  g  h)  i  f  g
  deleter = pullr cancelr

  deletel : h  (i  f)  g  f  g
  deletel = pulll cancell
```

We also have combinators which combine expanding on one side with a
cancellation on the other side:

```agda
lswizzle : g  h  i  f  h  id  f  g  i
lswizzle {g = g} {h = h} {i = i} {f = f} p q =
  f  g     ≡⟨ ap₂ _∘_ refl p 
  f  h  i ≡⟨ cancell q 
  i         

rswizzle : g  i  h  h  f  id  g  f  i
rswizzle {g = g} {i = i} {h = h} {f = f} p q =
  g  f       ≡⟨ ap₂ _∘_ p refl 
  (i  h)  f ≡⟨ cancelr q 
  i           
```

## Isomorphisms

These lemmas are useful for proving that partial inverses to an
isomorphism are unique. There's a helper for proving uniqueness of left
inverses, of right inverses, and for proving that any left inverse must
match any right inverse.

```agda
module _ {y z} (f : y  z) where abstract
  open _≅_

  left-inv-unique
    :  {g h}
     g  f .to  id  h  f .to  id
     g  h
  left-inv-unique {g = g} {h = h} p q =
    g                   ≡⟨ intror (f .invl) 
    g  f .to  f .from ≡⟨ extendl (p  sym q) 
    h  f .to  f .from ≡⟨ elimr (f .invl) 
    h                   

  left-right-inv-unique
    :  {g h}
     g  f .to  id  f .to  h  id
     g  h
  left-right-inv-unique {g = g} {h = h} p q =
    g                    ≡⟨ intror (f .invl) 
    g  f .to  f .from  ≡⟨ cancell p 
    f .from              ≡⟨ intror q 
    f .from  f .to  h  ≡⟨ cancell (f .invr) 
    h                    

  right-inv-unique
    :  {g h}
     f .to  g  id  f .to  h  id
     g  h
  right-inv-unique {g = g} {h} p q =
    g                     ≡⟨ introl (f .invr) 
    (f .from  f .to)  g ≡⟨ pullr (p  sym q) 
    f .from  f .to  h   ≡⟨ cancell (f .invr) 
    h                     
```

If we have a commuting triangle of isomorphisms, then we
can flip one of the sides to obtain a new commuting triangle
of isomorphisms.

```agda
Iso-swapr :
   {a : x  y} {b : y  z} {c : x  z}
   a ∘Iso b  c
   a  c ∘Iso (b Iso⁻¹)
Iso-swapr {a = a} {b = b} {c = c} p = ≅-path $
  a .to                     ≡⟨ introl (b .invr) 
  (b .from  b .to)  a .to ≡⟨ pullr (ap to p) 
  b .from  c .to           

Iso-swapl :
   {a : x  y} {b : y  z} {c : x  z}
   a ∘Iso b  c
   b  (a Iso⁻¹) ∘Iso c
Iso-swapl {a = a} {b = b} {c = c} p = ≅-path $
  b .to                   ≡⟨ intror (a .invl) 
  b .to  a .to  a .from ≡⟨ pulll (ap to p) 
  c .to  a .from         
```

Assume we have a prism of isomorphisms, as in the following diagram:

~~~{.quiver}
\begin{tikzcd}
  & v \\
  u && w \\
  & y \\
  x && z
  \arrow["c"{description, pos=0.7}, from=2-1, to=2-3]
  \arrow["i"{description}, from=4-1, to=4-3]
  \arrow["d"{description}, from=2-1, to=4-1]
  \arrow["f"{description}, from=2-3, to=4-3]
  \arrow["a"{description}, from=2-1, to=1-2]
  \arrow["g"{description}, from=4-1, to=3-2]
  \arrow["e"{description, pos=0.7}, from=1-2, to=3-2]
  \arrow["b"{description}, from=1-2, to=2-3]
  \arrow["h"{description}, from=3-2, to=4-3]
\end{tikzcd}
~~~

If the top, front, left, and right faces all commute, then so does the
bottom face.

```agda
Iso-prism :  {a : u  v} {b : v  w} {c : u  w}
       {d : u  x} {e : v  y} {f : w  z}
       {g : x  y} {h : y  z} {i : x  z}
       a ∘Iso b  c
       a ∘Iso e  d ∘Iso g
       b ∘Iso f  e ∘Iso h
       c ∘Iso f  d ∘Iso i
       g ∘Iso h  i
Iso-prism {a = a} {b} {c} {d} {e} {f} {g} {h} {i} top left right front =
  ≅-path $
    h .to  g .to                                           ≡⟨ ap₂ _∘_ (ap to (Iso-swapl (sym right))) (ap to (Iso-swapl (sym left))  sym (assoc _ _ _)) 
    ((f .to  b .to)  e .from)  (e .to  a .to  d .from) ≡⟨ cancel-inner (e .invr) 
    (f .to  b .to)  (a .to  d .from)                     ≡⟨ pull-inner (ap to top) 
    f .to  c .to  d .from                                 ≡⟨ assoc _ _ _  sym (ap to (Iso-swapl (sym front))) 
    i .to 
```


## Notation

When doing equational reasoning, it's often somewhat clumsy to have to write
`ap (f ∘_) p` when proving that `f ∘ g ≡ f ∘ h`. To fix this, we steal
some cute mixfix notation from `agda-categories` which allows us to write
`≡⟨ refl⟩∘⟨ p ⟩` instead, which is much more aesthetically pleasing!

```agda
_⟩∘⟨_ : f  h  g  i  f  g  h  i
_⟩∘⟨_ = ap₂ _∘_

infixr 40 _⟩∘⟨_

refl⟩∘⟨_ : g  h  f  g  f  h
refl⟩∘⟨_ {f = f} p = ap (f ∘_) p

_⟩∘⟨refl : f  h  f  g  h  g
_⟩∘⟨refl {g = g} p = ap (_∘ g) p
```