module Cat.Diagram.Colimit.Finite where

Finitely cocomplete categories🔗

Finitely cocomplete categories are dual to finitely complete categories in that they admit colimits for all diagrams of finite shape.

  is-finitely-cocomplete : Typeω
  is-finitely-cocomplete =  {o } {D : Precategory o }  is-finite-precategory D
                          (F : Functor D C)  Colimit F

Equivalently, a finitely cocomplete category has:

  • An initial object (colimit over the empty diagram)
  • All binary coproducts (colimits over any diagrams of shape
  • All binary coequalisers (colimits over any diagrams of shape
  • All binary pushouts (colimits over any diagrams of shape
  record Finitely-cocomplete : Type (  ℓ') where
    field
      initial      : Initial C
      coproducts   :  A B  Coproduct C A B
      coequalisers :  {A B} (f g : Hom A B)  Coequaliser C f g
      pushouts     :  {A B X} (f : Hom X A) (g : Hom X B)  Pushout C f g

    Coequ :  {A B} (f g : Hom A B)  Ob
    Coequ f g = coequalisers f g .Coequaliser.coapex

    Po :  {A B C} (f : Hom C A) (g : Hom C B)  Ob
    Po f g = pushouts f g .Pushout.coapex

  open Finitely-cocomplete

As seen on the page for finitely complete categories, this definition equivalently states that a finitely cocomplete category has either of the following:

  • An initial object, all binary coproducts, and all binary coequalisers
  • An initial object and all binary pushouts

This follows from the fact that we can build coproducts and coequalisers from pushouts, and that conversely, we can build pushouts from coproducts and coequalisers. We begin by proving the latter.

With coequalisers🔗

We construct a pushout under a span as a quotient object of a coproduct i.e. the coequaliser of and where and are injections into the coproduct.

Where is some object which admits injections and from X and Y respectively. This coequaliser represents a pushout

where is the pushout’s coapex, or equivalently, the coequaliser of and

  coproduct-coequaliser→pushout
    :  {E P X Y Z} {in1 : Hom X P} {in2 : Hom Y P} {f : Hom Z X}
        {g : Hom Z Y} {e : Hom P E}
     is-coproduct C in1 in2
     is-coequaliser C (in1  f) (in2  g) e
     is-pushout C f (e  in1) g (e  in2)
  coproduct-coequaliser→pushout {in1 = in1} {in2} {f} {g} {e} cp cq = po where
    open is-pushout
    module cq = is-coequaliser cq
    module cp = is-coproduct cp

    po : is-pushout C _ _ _ _
    po .square = sym (assoc _ _ _)  cq.coequal  assoc _ _ _
    po .universal {i₁' = i₁'} {i₂'} p =
      cq.universal {e' = cp.[ i₁' , i₂' ]} (
        cp.[ i₁' , i₂' ]  (in1  f) ≡⟨ pulll cp.[]∘ι₁ 
        i₁'  f                      ≡⟨ p 
        i₂'  g                      ≡˘⟨ pulll cp.[]∘ι₂ ≡˘
        cp.[ i₁' , i₂' ]  (in2  g) 
      )
    po .universal∘i₁ = pulll cq.factors  cp.[]∘ι₁
    po .universal∘i₂ = pulll cq.factors  cp.[]∘ι₂
    po .unique p q =
      cq.unique ((cp.unique (sym (assoc _ _ _)  p) (sym (assoc _ _ _)  q)))

Thus, if a category has an initial object, binary coproducts, and binary coequalisers, it is finitely cocomplete.

  with-coequalisers
    : Initial C
     (∀ A B  Coproduct C A B)
     (∀ {A B} (f g : Hom A B)  Coequaliser C f g)
     Finitely-cocomplete
  with-coequalisers init copr coeq .initial      = init
  with-coequalisers init copr coeq .coproducts   = copr
  with-coequalisers init copr coeq .coequalisers = coeq
  with-coequalisers init copr coeq .pushouts {A} {B} {X} f g =
    record { has-is-po = coproduct-coequaliser→pushout Copr.has-is-coproduct Coequ.has-is-coeq }
    where
      module Copr = Coproduct (copr A B)
      module Coequ = Coequaliser (coeq (Copr.ι₁  f) (Copr.ι₂  g))

With pushouts🔗

A coproduct is a pushout under a span whose vertex is the initial object.

  initial-pushout→coproduct
    :  {P X Y I} {in1 : Hom X P} {in2 : Hom Y P} {f : Hom I X} {g : Hom I Y}
     is-initial C I  is-pushout C f in1 g in2  is-coproduct C in1 in2
  initial-pushout→coproduct {in1 = in1} {in2} {f} {g} init po = coprod where
      module Po = is-pushout po

      coprod : is-coproduct C in1 in2
      coprod .is-coproduct.[_,_] in1' in2' =
        Po.universal {i₁' = in1'} {i₂' = in2'} (is-contr→is-prop (init _) _ _)
      coprod .is-coproduct.[]∘ι₁ = Po.universal∘i₁
      coprod .is-coproduct.[]∘ι₂ = Po.universal∘i₂
      coprod .is-coproduct.unique p q = Po.unique p q

  with-pushouts
    : Initial C
     (∀ {A B X} (f : Hom X A) (g : Hom X B)  Pushout C f g)
     Finitely-cocomplete
  with-pushouts bot po = fcc where
    module bot = Initial bot
    mkcoprod :  A B  Coproduct C A B
    mkcoprod A B = record { has-is-coproduct = initial-pushout→coproduct bot.has⊥ po' }
      where po' = po (bot.has⊥ A .centre) (bot.has⊥ B .centre) .Pushout.has-is-po

    mkcoeq :  {A B} (f g : Hom A B)  Coequaliser C f g
    mkcoeq {A = A} {B} f g = coequ where

The construction of coequalisers from pushouts follows its dual.

      coequ : Coequaliser C f g
      coequ .coapex = Po.coapex
      coequ .coeq = Po.i₁
      coequ .has-is-coeq .coequal =
        Po.i₁  f                  ≡˘⟨ ap (Po.i₁ ∘_) A+A.[]∘ι₁ ≡˘
        Po.i₁  [f,g]  A+A.ι₁     ≡⟨ assoc _ _ _  ap (_∘ A+A.ι₁) Po.square 
        (Po.i₂  [id,id])  A+A.ι₁ ≡⟨ sym (assoc _ _ _)  pushr (A+A.[]∘ι₁  sym A+A.[]∘ι₂) 
        (Po.i₂  [id,id])  A+A.ι₂ ≡⟨ ap (_∘ A+A.ι₂) (sym Po.square) 
        (Po.i₁  [f,g])  A+A.ι₂   ≡⟨ sym (assoc _ _ _)  ap (Po.i₁ ∘_) A+A.[]∘ι₂ 
        Po.i₁  g                  
      coequ .has-is-coeq .universal {e' = e'} p =
        Po.universal (A+A.unique₂ refl refl (in1) (in2))
        where
          in1 : ((e'  f)  [id,id])  A+A.ι₁  (e'  [f,g])  A+A.ι₁
          in1 =
            ((e'  f)  [id,id])  A+A.ι₁ ≡⟨ cancelr A+A.[]∘ι₁  -- ≡⟨ cancell A+A.[]∘ι₁ ⟩
            e'  f                        ≡˘⟨ pullr A+A.[]∘ι₁ ≡˘ -- ≡˘⟨ pulll A+A.[]∘ι₁ ⟩
            (e'  [f,g])  A+A.ι₁         

          in2 : ((e'  f)  [id,id])  A+A.ι₂  (e'  [f,g])  A+A.ι₂
          in2 =
            ((e'  f)  [id,id])  A+A.ι₂ ≡⟨ cancelr A+A.[]∘ι₂ 
            e'  f                        ≡⟨ p 
            e'  g                        ≡˘⟨ pullr A+A.[]∘ι₂ ≡˘
            (e'  [f,g])  A+A.ι₂         

      coequ .has-is-coeq .factors = Po.universal∘i₁
      coequ .has-is-coeq .unique {F} {e' = e'} {colim = colim} e'=col∘i₁ =
        Po.unique e'=col∘i₁ path
        where
          path : colim  Po.i₂  e'  f
          path =
            colim  Po.i₂                        ≡⟨ insertr A+A.[]∘ι₁ 
            ((colim  Po.i₂)  [id,id])  A+A.ι₁ ≡⟨ ap (_∘ A+A.ι₁) (extendr (sym Po.square)) 
            ((colim  Po.i₁)  [f,g])  A+A.ι₁   ≡⟨ ap (_∘ A+A.ι₁) (ap (_∘ [f,g]) e'=col∘i₁) 
            (e'  [f,g])  A+A.ι₁                ≡⟨ pullr A+A.[]∘ι₁ 
            e'  f           

    fcc : Finitely-cocomplete
    fcc .initial      = bot
    fcc .coproducts   = mkcoprod
    fcc .coequalisers = mkcoeq
    fcc .pushouts     = po

Rex functors🔗

A right exact, or rex, functor is a functor that preserves finite colimits.

  record is-rex (F : Functor C D) : Type (o    o'  ℓ') where
    private module F = Functor F

    field
      pres-⊥ :  {I}  is-initial C I  is-initial D (F.₀ I)
      pres-pushout
        :  {P X Y Z} {in1 : C.Hom X P} {in2 : C.Hom Y P}
            {f : C.Hom Z X} {g : C.Hom Z Y}
         is-pushout C f in1 g in2
         is-pushout D (F.₁ f) (F.₁ in1) (F.₁ g) (F.₁ in2)
    pres-coproduct
      :  {P A B I} {in1 : C.Hom A P} {in2 : C.Hom B P}
       is-initial C I
       is-coproduct C in1 in2
       is-coproduct D (F.₁ in1) (F.₁ in2)
    pres-coproduct  init copr = initial-pushout→coproduct D (pres-⊥ init)
      (pres-pushout {f = init _ .centre} {g = init _ .centre}
        (coproduct→initial-pushout C init copr))
    pres-epis :  {A B} {f : C.Hom A B}  C.is-epic f  D.is-epic (F.₁ f)
    pres-epis {f = f} epi = is-pushout→is-epic
      (subst  x  is-pushout D _ x _ x) F.F-id
        (pres-pushout
          (is-epic→is-pushout epi)))