module Cat.Diagram.Colimit.Cocone where
private variable
: Level
o ℓ o' ℓ'
open _=>_
Colimits via cocones🔗
As noted in the main page on colimits, most introductory texts opt to
define colimits via categorical gadgets called cocones.
A Cocone
over
is given by an object (the coapex
)
together with a family of maps ψ
—
one for each object in the indexing category J
— such that “everything in sight
commutes”.
module _ {J : Precategory o ℓ} {C : Precategory o' ℓ'} (F : Functor J C) where
private
module C = Cat.Reasoning C
module J = Precategory J
module F = Functor F
record Cocone : Type (o ⊔ ℓ ⊔ o' ⊔ ℓ') where
no-eta-equality
constructor cocone
field
: C.Ob
coapex : (x : J.Ob) → C.Hom (F.₀ x) coapex
ψ : ∀ {x y} (f : J.Hom x y) → ψ y C.∘ F.₁ f ≡ ψ x commutes
open Cocone
: {x y : Cocone}
Cocone-path → (p : x .coapex ≡ y .coapex)
→ (∀ o → PathP (λ i → C.Hom (F.₀ o) (p i)) (ψ x o) (ψ y o))
→ x ≡ y
.coapex = p i
Cocone-path p q i .ψ o = q o i
Cocone-path p q i {x = x} {y = y} p q i .commutes {x = a} {y = b} f =
Cocone-path (λ i → C.Hom-set _ _ (q b i C.∘ F.₁ f) (q a i))
is-prop→pathp (x .commutes f) (y .commutes f) i
Cocone maps🔗
To express the universal property of a colimit in terms of cocones, we now have to define the notion of cocone homomorphism. We define a cocone homomorphism to be a map between the coapices which commutes with the family
record Cocone-hom (x y : Cocone) : Type (o ⊔ ℓ') where
no-eta-equality
constructor cocone-hom
field
: C.Hom (x .coapex) (y .coapex)
hom : ∀ o → hom C.∘ x .ψ o ≡ y .ψ o commutes
private unquoteDecl eqv = declare-record-iso eqv (quote Cocone-hom)
open Cocone-hom
: ∀ {x y} {f g : Cocone-hom x y} → f .hom ≡ g .hom → f ≡ g
Cocone-hom-path .hom = p i
Cocone-hom-path p i {x = x} {y = y} {f = f} {g = g} p i .commutes o j =
Cocone-hom-path (λ i j → C.Hom-set _ _)
is-set→squarep (λ j → p j C.∘ x .ψ o) (f .commutes o) (g .commutes o) refl i j
Since cocone homomorphisms are closed under composition in the base category, it’s immediate that they form a category.
: Precategory _ _
Cocones = cat where
Cocones open Precategory
: ∀ {x y z} → Cocone-hom y z → Cocone-hom x y → Cocone-hom x z
compose .hom = K .hom C.∘ L .hom
compose K L {x = x} {y = y} {z = z} K L .commutes o =
compose (K .hom C.∘ L .hom) C.∘ x .ψ o ≡⟨ C.pullr (L .commutes o) ⟩
.hom C.∘ y .ψ o ≡⟨ K .commutes o ⟩
K .ψ o ∎ z
: Precategory _ _
cat .Ob = Cocone
cat .Hom = Cocone-hom
cat .id = cocone-hom C.id (λ _ → C.idl _)
cat ._∘_ = compose
cat .idr f = Cocone-hom-path (C.idr (f .hom))
cat .idl f = Cocone-hom-path (C.idl (f .hom))
cat .assoc f g h = Cocone-hom-path (C.assoc (f .hom) (g .hom) (h .hom))
cat .Hom-set x y = Iso→is-hlevel! 2 eqv cat
Initial cocones as colimits🔗
A cocone over some diagram contains the same data as natural transformation from to a constant functor. Since we have defined a colimit to consist of (a functor equipped with) a natural transformation into a constant functor, there is an equivalence between the cocones defined here and those considered in the definition of colimit.
: (K : Cocone) → F => Const (Cocone.coapex K)
Cocone→cocone .η = K .Cocone.ψ
Cocone→cocone K .is-natural x y f = K .Cocone.commutes f ∙ sym (C.idl _) Cocone→cocone K
We can then rephrase the universality from the definition of left Kan extension by asking that a particular cocone be initial in the category we have just constructed.
is-initial-cocone→is-colimit: ∀ {K : Cocone}
→ is-initial Cocones K
→ is-colimit F (Cocone.coapex K) (Cocone→cocone K)
{K = K} init = to-is-colimitp colim refl where
is-initial-cocone→is-colimit open make-is-colimit
open Cocone
open Cocone-hom
: make-is-colimit F (Cocone.coapex K)
colim .ψ = K .ψ
colim .commutes = K .commutes
colim .universal eta p = init (cocone _ eta p) .centre .hom
colim .factors eta p = init (cocone _ eta p) .centre .commutes _
colim .unique eta p other q =
colim (sym (init (cocone _ eta p) .paths (cocone-hom other q))) ap hom
To finish concretising the correspondence, note that this process is invertible: From a colimit, we can extract an initial cocone.
is-colimit→is-initial-cocone: ∀ {x} {eta : F => Const x}
→ (L : is-colimit F x eta)
→ is-initial Cocones (cocone x (is-colimit.ψ L) (is-colimit.commutes L))
The proof consists of more data shuffling, so we omit it.
{x = x} L K = init where
is-colimit→is-initial-cocone module L = is-colimit L
module K = Cocone K
open Cocone-hom
: is-contr (Cocone-hom (cocone x L.ψ L.commutes) K)
init .centre .hom = L.universal K.ψ K.commutes
init .centre .commutes _ = L.factors K.ψ K.commutes
init .paths f =
init (sym (L.unique K.ψ K.commutes (f .hom) (f .commutes))) Cocone-hom-path