module Cat.Diagram.Colimit.Base where

IdeaπŸ”—

Colimits are dual to limits limit; much like their cousins, they generalize constructions in several settings to arbitrary categories. A colimit (if it exists), is the β€œbest solution” to an β€œidentification problem”. This is in contrast to the limit, which acts as a solution to an β€œequational problem”.

We define colimits in a similar way to limits; the only difference being that we define a colimits of a diagram FF as left Kan extensions instead of right Kan extensions. This gives us the expected β€œmapping out” universal property, as opposed to the β€œmapping in” property associated to limits.

Note that approach to colimits is not what normally presented in introductory material. Instead, most books opt to define colimits via cocones, as they are less abstract, though harder to work with in the long run.

module _ {J : Precategory o₁ h₁} {C : Precategory oβ‚‚ hβ‚‚} (Diagram : Functor J C) where
  private
    module C = Precategory C

  coconeβ†’unit : βˆ€ {x : C.Ob} β†’ (Diagram => Const x) β†’ Diagram => const! x F∘ !F
  unquoteDef cocone→unit = define-coherence cocone→unit

  is-colimit : (x : C.Ob) β†’ Diagram => Const x β†’ Type _
  is-colimit x cocone =
    is-lan !F Diagram (const! x) (cocone→unit cocone)

  Colimit : Type _
  Colimit = Lan !F Diagram

ConcretelyπŸ”—

As mentioned, our definition is very abstract, meaning we can directly re-use definitions and theorems about Kan extensions in the setting of colimits. The trade-off is that while working with colimits in general is easier, working with specific colimits becomes more difficult, as the data we actually care about has been obfuscated.

One particularly egregious failure is… actually constructing colimits. The definition in terms of Lan hides the concrete data behind a few abstractions, which would be very tedious to write out each time. To work around this, we provide an auxiliary record type, make-is-colimit, as an intermediate step in constructing left extensions.

First, we require morphisms from the every value of the diagram to the coapex; taken as a family, we call it Ο•\phi. Moreover, if f:xβ†’yf : x \to y is a morphism in the β€œshape” category J\mathcal{J}, we require ψy∘Ff=ψx\psi y \circ Ff = \psi x, which encodes the relevant naturality.

    field
      ψ : (j : J.Ob) β†’ C.Hom (Fβ‚€ j) coapex
      commutes : βˆ€ {x y} (f : J.Hom x y) β†’ ψ y C.∘ F₁ f ≑ ψ x

The rest of the data ensures that ψ\psi is the universal family of maps with this property; if Ξ΅j:Fjβ†’x\varepsilon_j : Fj \to x is another natural family, then each Ξ΅j\varepsilon_j factors through the coapex by a unique universal morphism:

      universal
        : βˆ€ {x : C.Ob}
        β†’ (eps : βˆ€ j β†’ C.Hom (Fβ‚€ j) x)
        β†’ (βˆ€ {x y} (f : J.Hom x y) β†’ eps y C.∘ F₁ f ≑ eps x)
        β†’ C.Hom coapex x
      factors
        : βˆ€ {j : J.Ob} {x : C.Ob}
        β†’ (eps : βˆ€ j β†’ C.Hom (Fβ‚€ j) x)
        β†’ (p : βˆ€ {x y} (f : J.Hom x y) β†’ eps y C.∘ F₁ f ≑ eps x)
        β†’ universal eps p C.∘ ψ j ≑ eps j
      unique
        : βˆ€ {x : C.Ob}
        β†’ (eps : βˆ€ j β†’ C.Hom (Fβ‚€ j) x)
        β†’ (p : βˆ€ {x y} (f : J.Hom x y) β†’ eps y C.∘ F₁ f ≑ eps x)
        β†’ (other : C.Hom coapex x)
        β†’ (βˆ€ j β†’ other C.∘ ψ j ≑ eps j)
        β†’ other ≑ universal eps p

Once we have this data, we can use it to construct a value of type is-colimit. The naturality condition we required above may seem too weak, but the full naturality condition can be derived from it and the rest of the data.

  to-is-colimit
    : βˆ€ {Diagram : Functor J C} {coapex}
    β†’ (mc : make-is-colimit Diagram coapex)
    β†’ is-colimit Diagram coapex (to-cocone mc)
  to-is-colimit {Diagram} {coapex} mkcolim = colim where
    open make-is-colimit mkcolim
    open is-lan
    open Functor

    colim : is-colimit Diagram coapex (to-cocone mkcolim)
    colim .Οƒ {M = M} Ξ± .Ξ· _ =
      universal (Ξ± .Ξ·) (Ξ» f β†’ Ξ± .is-natural _ _ f βˆ™ C.eliml (M .F-id))
    colim .Οƒ {M = M} Ξ± .is-natural _ _ _ =
       C.idr _ βˆ™ C.introl (M .F-id)
    colim .Οƒ-comm {Ξ± = Ξ±} = Nat-path Ξ» j β†’
      factors (Ξ± .Ξ·) _
    colim .Οƒ-uniq {Ξ± = Ξ±} {Οƒβ€² = Οƒβ€²} p = Nat-path Ξ» _ β†’
      sym $ unique (Ξ± .Ξ·) _ (Οƒβ€² .Ξ· _) (Ξ» j β†’ sym (p Ξ·β‚š j))
  -- We often find ourselves working with something that isn't a colimit
  -- on the nose due to some annoying extensionality reasons involving
  -- functors '⊀Cat β†’ C'
  -- We could use some general theorems of Kan extensions to adjust the
  -- colimit, but this has better definitional behaviour.
  generalize-colimitp
    : βˆ€ {D : Functor J C} {K : Functor ⊀Cat C}
    β†’ {eta : D => (const! (Functor.Fβ‚€ K tt)) F∘ !F} {eta' : D => K F∘ !F}
    β†’ is-lan !F D (const! (Functor.Fβ‚€ K tt)) eta
    β†’ (βˆ€ {j} β†’ eta .Ξ· j ≑ eta' .Ξ· j)
    β†’ is-lan !F D K eta'
  generalize-colimitp {D} {K} {eta} {eta'} lan q = lan' where
    module lan = is-lan lan
    open is-lan
    open Functor

    lan' : is-lan !F D K eta'
    lan' .Οƒ Ξ± = homβ†’βŠ€-natural-trans (lan.Οƒ Ξ± .Ξ· tt)
    lan' .Οƒ-comm {M} {Ξ±} = Nat-path Ξ» j β†’
      ap (_ C.∘_) (sym q)
      βˆ™ lan.Οƒ-comm {Ξ± = Ξ±} Ξ·β‚š _
    lan' .Οƒ-uniq {M} {Ξ±} {Οƒβ€²} r = Nat-path Ξ» j β†’
      lan.Οƒ-uniq {Οƒβ€² = homβ†’βŠ€-natural-trans (Οƒβ€² .Ξ· tt)}
        (Nat-path (Ξ» j β†’ r Ξ·β‚š j βˆ™ ap (_ C.∘_) (sym q))) Ξ·β‚š j

  to-is-colimitp
    : βˆ€ {D : Functor J C} {K : Functor ⊀Cat C} {eta : D => K F∘ !F}
    β†’ (mk : make-is-colimit D (Functor.Fβ‚€ K tt))
    β†’ (βˆ€ {j} β†’ to-cocone mk .Ξ· j ≑ eta .Ξ· j)
    β†’ is-lan !F D K eta
  to-is-colimitp {D} {K} {eta} mkcolim p =
    generalize-colimitp (to-is-colimit mkcolim) p

The concrete interface of make-is-colimit is also handy for consuming specific colimits. To enable this use case, we provide a function which unmakes a colimit.

  unmake-colimit
    : βˆ€ {D : Functor J C} {F : Functor ⊀Cat C} {eta}
    β†’ is-lan !F D F eta
    β†’ make-is-colimit D (Functor.Fβ‚€ F tt)
  unmake-colimit {D} {F} {eta} colim = mc module unmake-colimit where
    coapex = Functor.Fβ‚€ F tt
    module eta = _=>_ eta
    open is-lan colim
    open Functor D
    open make-is-colimit
    open _=>_

    module _ {x} (eps : βˆ€ j β†’ C.Hom (Fβ‚€ j) x)
                 (p : βˆ€ {x y} (f : J.Hom x y) β†’  eps y C.∘ F₁ f ≑ eps x)
      where

      eps-nt : D => const! x F∘ !F
      eps-nt .Ξ· = eps
      eps-nt .is-natural _ _ f = p f βˆ™ sym (C.idl _)

      hom : C.Hom coapex x
      hom = Οƒ {M = const! x} eps-nt .Ξ· tt

    mc : make-is-colimit D coapex
    mc .ψ = eta.η
    mc .commutes f = eta.is-natural _ _ f βˆ™ C.eliml (Functor.F-id F)
    mc .universal = hom
    mc .factors e p = Οƒ-comm {Ξ± = eps-nt e p} Ξ·β‚š _
    mc .unique {x = x} eta p other q =
      sym $ Οƒ-uniq {Οƒβ€² = other-nt} (Nat-path Ξ» j β†’ sym (q j)) Ξ·β‚š tt
      where
        other-nt : F => const! x
        other-nt .Ξ· _ = other
        other-nt .is-natural _ _ _ = C.elimr (Functor.F-id F) βˆ™ sym (C.idl _)

We also provide a similar interface for the bundled form of colimits.

module Colimit
  {J : Precategory o₁ h₁} {C : Precategory oβ‚‚ hβ‚‚} {D : Functor J C} (L : Colimit D)
  where

The coapex of the colimit can be obtained by applying the extension functor to the single object of ⊀Cat.

  coapex : C.Ob
  coapex = Ext .Fβ‚€ tt

Furthermore, we can show that the apex is the colimit, in the sense of is-colimit, of the diagram. You’d think this is immediate, but unfortunately, proof assistants: is-colimit asks for the constant functor functor {βˆ—}β†’C\{*\} \to \mathcal{C} with value coapex to be a Kan extension, but Colimit, being an instance of Lan, packages an arbitrary functor {βˆ—}β†’C\{*\} \to \mathcal{C}.

Since Agda does not compare functors for Ξ·\eta-equality, we have to shuffle our data around manually. Fortunately, this isn’t a very long computation.

  cocone : D => Const coapex
  cocone .Ξ· = eta .Ξ·
  cocone .is-natural x y f =
    eta .is-natural x y f βˆ™ ap (C._∘ _) (Ext .F-id)

  has-colimit : is-colimit D coapex cocone
  has-colimit .is-lan.Οƒ Ξ± .Ξ· = Οƒ Ξ± .Ξ·
  has-colimit .is-lan.Οƒ Ξ± .is-natural x y f =
    ap (_ C.∘_) (sym (Ext .F-id)) βˆ™ Οƒ Ξ± .is-natural tt tt tt
  has-colimit .is-lan.Οƒ-comm =
    Nat-path (Ξ» _ β†’ Οƒ-comm Ξ·β‚š _)
  has-colimit .is-lan.Οƒ-uniq {M = M} {Οƒβ€² = Οƒβ€²} p =
    Nat-path (Ξ» _ β†’ Οƒ-uniq {Οƒβ€² = nt} (Nat-path (Ξ» j β†’ p Ξ·β‚š j)) Ξ·β‚š _)
    where
      nt : Ext => M
      nt .Ξ· = Οƒβ€² .Ξ·
      nt .is-natural x y f = ap (_ C.∘_) (Ext .F-id) βˆ™ Οƒβ€² .is-natural x y f

  open is-colimit has-colimit public

UniquenessπŸ”—

Much like limits, colimits are unique up to isomorphism. This all follows from general properties of Kan extensions, combined with the fact that natural isomorphisms between functors βŠ€β†’C\top \to \mathcal{C} correspond with isomorphisms in C\mathcal{C}.

  colimits→inversesp
    : βˆ€ {f : C.Hom x y} {g : C.Hom y x}
    β†’ (βˆ€ {j : J.Ob} β†’ f C.∘ Cx.ψ j ≑ Cy.ψ j)
    β†’ (βˆ€ {j : J.Ob} β†’ g C.∘ Cy.ψ j ≑ Cx.ψ j)
    β†’ C.Inverses f g

  colimits→invertiblep
    : βˆ€ {f : C.Hom x y}
    β†’ (βˆ€ {j : J.Ob} β†’ f C.∘ Cx.ψ j ≑ Cy.ψ j)
    β†’ C.is-invertible f

  colimits-unique     : x C.β‰… y
  colimitsβ†’invertible : C.is-invertible (Cx.universal Cy.ψ Cy.commutes)
  colimits→inverses
    : C.Inverses (Cx.universal Cy.ψ Cy.commutes) (Cy.universal Cx.ψ Cx.commutes)

Furthermore, if the universal map is invertible, then that means its domain is also a colimit of the diagram. This also follows from a general theorem of Kan extensions, though some golfin is required to obtain the correct inverse definitionally.

  is-invertible→is-colimitp
    : βˆ€ {K' : Functor ⊀Cat C} {eta : D => K' F∘ !F}
    β†’ (eps : βˆ€ j β†’ C.Hom (D.β‚€ j) (K' .Fβ‚€ tt))
    β†’ (p : βˆ€ {x y} (f : J.Hom x y) β†’ eps y C.∘ D.₁ f ≑ eps x)
    β†’ (βˆ€ {j} β†’ eps j ≑ eta .Ξ· j)
    β†’ C.is-invertible (Cy.universal eps p)
    β†’ is-lan !F D K' eta
  is-invertible→is-colimitp {K' = K'} {eta = eta} eps p q invert =
    generalize-colimitp
      (is-invertible→is-lan Cy $ componentwise-invertible→invertible _ λ _ → invert)
      q

Another useful fact is that if CC is a colimit of some diagram DiaDia, and DiaDia is naturally isomorphic to some other diagram Diaβ€²Dia', then the coapex of CC is also a colimit of Diaβ€²Dia'.

  natural-iso-diagram→is-colimitp
    : βˆ€ {Dβ€² : Functor J C} {eta : Dβ€² => K F∘ !F}
    β†’ (isos : natural-iso D Dβ€²)
    β†’ (βˆ€ {j} β†’  Cy.ψ j C.∘ natural-iso.from isos .Ξ· j ≑ eta .Ξ· j)
    β†’ is-lan !F Dβ€² K eta
  natural-iso-diagram→is-colimitp {D′ = D′} isos q = generalize-colimitp
    (natural-iso-of→is-lan Cy isos)
    q

Since is-colimit is a proposition, and the colimiting cocones are all unique (β€œup to isomorphism”), if we’re talking about univalent categories, then Colimit itself is a proposition. This is also an instance of the more general uniqueness of Kan extensions.

  Colimit-is-prop : is-category C β†’ is-prop (Colimit Diagram)
  Colimit-is-prop cat = Lan-is-prop cat

Preservation of ColimitsπŸ”—

The definitions here are the same idea as preservation of limits, just dualized.

  preserves-colimit : Type _
  preserves-colimit =
     βˆ€ {K : Functor ⊀Cat C} {eta : Diagram => K F∘ !F}
     β†’ (colim : is-lan !F Diagram K eta)
     β†’ preserves-lan F colim

  reflects-colimit : Type _
  reflects-colimit =
    βˆ€ {K : Functor ⊀Cat C} {eps : Diagram => K F∘ !F}
    β†’ (lan : is-lan !F (F F∘ Diagram) (F F∘ K) (nat-assoc-to (F β–Έ eps)))
    β†’ reflects-lan F lan
module preserves-colimit
  {J : Precategory o₁ h₁} {C : Precategory oβ‚‚ hβ‚‚} {D : Precategory o₃ h₃}
  {F : Functor C D} {Dia : Functor J C}
  (preserves : preserves-colimit F Dia)

  where
  private
    module D = Precategory D
    module C = Precategory C
    module J = Precategory J
    module F = Func F
    module Dia = Func Dia

  universal
    : {x : C.Ob}
    β†’ {K : Functor ⊀Cat C} {eta : Dia => K F∘ !F}
    β†’ {eps : (j : J.Ob) β†’ C.Hom (Dia.Fβ‚€ j) x}
    β†’ {p : βˆ€ {i j} (f : J.Hom i j) β†’ eps j C.∘ Dia.F₁ f ≑ eps i}
    β†’ (colim : is-lan !F Dia K eta)
    β†’ F.F₁ (is-colimit.universal colim eps p) ≑ is-colimit.universal (preserves colim) (Ξ» j β†’ F.F₁ (eps j)) (Ξ» f β†’ F.collapse (p f))
  universal colim = is-colimit.unique (preserves colim) _ _ _ (Ξ» j β†’ F.collapse (is-colimit.factors colim _ _))

  colimit : Colimit Dia β†’ Colimit (F F∘ Dia)
  colimit colim = to-colimit (preserves (Colimit.has-colimit colim))

module _ {J : Precategory o₁ h₁} {C : Precategory oβ‚‚ hβ‚‚} {D : Precategory o₃ h₃}
         {F F' : Functor C D} {Dia : Functor J C} where

  private
    module D = Cat.Reasoning D
    open Func
    open _=>_

  natural-iso→preserves-colimits
    : natural-iso F F'
    β†’ preserves-colimit F Dia
    β†’ preserves-colimit F' Dia
  natural-iso→preserves-colimits α F-preserves {K = K} {eps} colim =
    natural-isos→is-lan
      idni (Ξ± β—‚ni Dia) (Ξ± β—‚ni K)
      (Nat-path Ξ» j β†’
        ⌜ F' .F₁ (K .F₁ tt) D.∘ Ξ±.to .Ξ· _ ⌝ D.∘ (F .F₁ (eps .Ξ· j) D.∘ Ξ±.from .Ξ· _) β‰‘βŸ¨ ap! (eliml F' (K .F-id)) βŸ©β‰‘
        Ξ±.to .Ξ· _ D.∘ (F .F₁ (eps .Ξ· j) D.∘ Ξ±.from .Ξ· _)                           β‰‘βŸ¨ D.pushr (sym (Ξ±.from .is-natural _ _ _)) βŸ©β‰‘
        ((Ξ±.to .Ξ· _ D.∘ Ξ±.from .Ξ· _) D.∘ F' .F₁ (eps .Ξ· j))                        β‰‘βŸ¨ D.eliml (Ξ±.invl Ξ·β‚š _) βŸ©β‰‘
        F' .F₁ (eps .Ξ· j) ∎)
      (F-preserves colim)
    where
      module Ξ± = natural-iso Ξ±

CocontinuityπŸ”—

is-cocontinuous
  : βˆ€ (oshape hshape : Level)
      {C : Precategory o₁ h₁}
      {D : Precategory oβ‚‚ hβ‚‚}
  β†’ Functor C D β†’ Type _

A cocontinuous functor is one that, for every shape of diagram J, and every diagram diagram of shape J in C, preserves the colimit for that diagram.

is-cocontinuous oshape hshape {C = C} F =
  βˆ€ {J : Precategory oshape hshape} {Diagram : Functor J C}
  β†’ preserves-colimit F Diagram

CocompletenessπŸ”—

A category is cocomplete if admits for limits of arbitrary shape. However, in the presence of excluded middle, if a category admits coproducts indexed by its class of morphisms, then it is automatically [thin]. Since excluded middle is independent of type theory, we can not prove that any non-thin categories have arbitrary colimits.

Instead, categories are cocomplete with respect to a pair of universes: A category is (o,β„“)(o, \ell)-cocomplete if it has colimits for any diagram indexed by a precategory with objects in TypeΒ o\mathrm{Type}\ o and morphisms in TypeΒ β„“\mathrm{Type}\ \ell.

is-cocomplete : βˆ€ {oc β„“c} o β„“ β†’ Precategory oc β„“c β†’ Type _
is-cocomplete o β„“ C = βˆ€ {D : Precategory o β„“} (F : Functor D C) β†’ Colimit F