module Cat.Diagram.Coproduct.Indexed {o ā„“} (C : Precategory o ā„“) where

Indexed coproductsšŸ”—

Indexed coproducts are the dual notion to indexed products, so see there for motivation and exposition.

record is-indexed-coproduct (F : Idx ā†’ C.Ob) (Ī¹ : āˆ€ i ā†’ C.Hom (F i) S)
  : Type (o āŠ” ā„“ āŠ” level-of Idx) where
  no-eta-equality
  field
    match   : āˆ€ {Y} ā†’ (āˆ€ i ā†’ C.Hom (F i) Y) ā†’ C.Hom S Y
    commute : āˆ€ {i} {Y} {f : āˆ€ i ā†’ C.Hom (F i) Y} ā†’ match f C.āˆ˜ Ī¹ i ā‰” f i
    unique  : āˆ€ {Y} {h : C.Hom S Y} (f : āˆ€ i ā†’ C.Hom (F i) Y)
            ā†’ (āˆ€ i ā†’ h C.āˆ˜ Ī¹ i ā‰” f i)
            ā†’ h ā‰” match f

  eta : āˆ€ {Y} (h : C.Hom S Y) ā†’ h ā‰” match (Ī» i ā†’ h C.āˆ˜ Ī¹ i)
  eta h = unique _ Ī» _ ā†’ refl

  uniqueā‚‚ : āˆ€ {Y} {g h : C.Hom S Y} ā†’ (āˆ€ i ā†’ g C.āˆ˜ Ī¹ i ā‰” h C.āˆ˜ Ī¹ i) ā†’ g ā‰” h
  uniqueā‚‚ {g = g} {h} eq = eta g āˆ™ ap match (funext eq) āˆ™ sym (eta h)

  hom-iso : āˆ€ {Y} ā†’ C.Hom S Y ā‰ƒ (āˆ€ i ā†’ C.Hom (F i) Y)
  hom-iso = (Ī» z i ā†’ z C.āˆ˜ Ī¹ i) , is-isoā†’is-equiv Ī» where
    .is-iso.inv ā†’ match
    .is-iso.rinv x ā†’ funext Ī» i ā†’ commute
    .is-iso.linv x ā†’ sym (unique _ Ī» _ ā†’ refl)

A category admits indexed coproducts (of level if, for any type and family there is an indexed coproduct of

record Indexed-coproduct (F : Idx ā†’ C.Ob) : Type (o āŠ” ā„“ āŠ” level-of Idx) where
  no-eta-equality
  field
    {Ī£F}      : C.Ob
    Ī¹         : āˆ€ i ā†’ C.Hom (F i) Ī£F
    has-is-ic : is-indexed-coproduct F Ī¹
  open is-indexed-coproduct has-is-ic public
Indexed-coproduct-ā‰ƒ
  : āˆ€ {ā„“ ā„“'} {I : Type ā„“} {J : Type ā„“'} ā†’ (e : I ā‰ƒ J)
  ā†’ {F : I ā†’ C.Ob} ā†’ Indexed-coproduct (F āŠ™ Equiv.from e) ā†’ Indexed-coproduct F
Indexed-coproduct-ā‰ƒ e {F} p = Ī» where
  .Ī£F ā†’ p .Ī£F
  .Ī¹ j ā†’ p .Ī¹ (e.to j) C.āˆ˜ C.from (pathā†’iso (ap F (e.Ī· _)))
  .has-is-ic .match f ā†’ p .match (f āŠ™ e.from)
  .has-is-ic .commute {f = f} ā†’
    C.pulll (p .commute) āˆ™ from-pathp-to (C ^op) _ (ap f (e.Ī· _))
  .has-is-ic .unique f comm ā†’ p .unique _ Ī» j ā†’
      ap (_ C.āˆ˜_) (sym (from-pathp-to (C ^op) _ (ap (p .Ī¹) (e.Īµ j)))
                  āˆ™ ap (Ī» z ā†’ p .Ī¹ _ C.āˆ˜ C.from (pathā†’iso (ap F z))) (e.zag j))
    āˆ™ comm (e.from j)
    where
      open Indexed-coproduct
      open is-indexed-coproduct
      module e = Equiv e

Lift-Indexed-coproduct
  : āˆ€ {ā„“} ā„“' ā†’ {I : Type ā„“} ā†’ {F : I ā†’ C.Ob}
  ā†’ Indexed-coproduct {Idx = Lift ā„“' I} (F āŠ™ lower)
  ā†’ Indexed-coproduct F
Lift-Indexed-coproduct _ = Indexed-coproduct-ā‰ƒ (Lift-ā‰ƒ eā»Ā¹)

is-indexed-coproduct-is-prop
  : āˆ€ {ā„“'} {Idx : Type ā„“'}
  ā†’ {F : Idx ā†’ C.Ob} {Ī£F : C.Ob} {Ī¹ : āˆ€ idx ā†’ C.Hom (F idx) Ī£F}
  ā†’ is-prop (is-indexed-coproduct F Ī¹)
is-indexed-coproduct-is-prop {Idx = Idx} {F} {Ī£F} {Ī¹} P Q = path where
  open is-indexed-coproduct

  p : āˆ€ {X} ā†’ (f : āˆ€ i ā†’ C.Hom (F i) X) ā†’ P .match f ā‰” Q .match f
  p f = Q .unique f (Ī» i ā†’ P .commute)

  path : P ā‰” Q
  path i .match f = p f i
  path i .commute {i = idx} {f = f} =
    is-propā†’pathp (Ī» i ā†’ C.Hom-set _ _ (p f i C.āˆ˜ Ī¹ idx) (f idx))
      (P .commute)
      (Q .commute) i
  path i .unique {h = h} f q =
    is-propā†’pathp (Ī» i ā†’ C.Hom-set _ _ h (p f i))
      (P .unique f q)
      (Q .unique f q) i

module _ {ā„“'} {Idx : Type ā„“'} {F : Idx ā†’ C.Ob} {P P' : Indexed-coproduct F} where
  private
    module P = Indexed-coproduct P
    module P' = Indexed-coproduct P'

  Indexed-coproduct-path
    : (p : P.Ī£F ā‰” P'.Ī£F)
    ā†’ (āˆ€ idx ā†’ PathP (Ī» i ā†’ C.Hom (F idx) (p i)) (P.Ī¹ idx) (P'.Ī¹ idx))
    ā†’ P ā‰” P'
  Indexed-coproduct-path p q i .Indexed-coproduct.Ī£F = p i
  Indexed-coproduct-path p q i .Indexed-coproduct.Ī¹ idx = q idx i
  Indexed-coproduct-path p q i .Indexed-coproduct.has-is-ic =
    is-propā†’pathp (Ī» i ā†’ is-indexed-coproduct-is-prop {Ī£F = p i} {Ī¹ = Ī» idx ā†’ q idx i})
      P.has-is-ic
      P'.has-is-ic i

UniquenessšŸ”—

As universal constructions, indexed coproducts are unique up to isomorphism. The proof follows the usual pattern: we use the universal morphisms to construct morphisms in both directions, and uniqueness ensures that these maps form an isomorphism.

is-indexed-coproductā†’iso
  : āˆ€ {ā„“'} {Idx : Type ā„“'} {F : Idx ā†’ C.Ob}
  ā†’ {Ī£F Ī£F' : C.Ob}
  ā†’ {Ī¹ : āˆ€ i ā†’ C.Hom (F i) Ī£F} {Ī¹' : āˆ€ i ā†’ C.Hom (F i) Ī£F'}
  ā†’ is-indexed-coproduct F Ī¹
  ā†’ is-indexed-coproduct F Ī¹'
  ā†’ Ī£F C.ā‰… Ī£F'
is-indexed-coproductā†’iso {Ī¹ = Ī¹} {Ī¹' = Ī¹'} Ī£F-coprod Ī£F'-coprod =
  C.make-iso (Ī£F.match Ī¹') (Ī£F'.match Ī¹)
    (Ī£F'.uniqueā‚‚ (Ī» i ā†’ C.pullr Ī£F'.commute āˆ™ Ī£F.commute āˆ™ sym (C.idl _)))
    (Ī£F.uniqueā‚‚ (Ī» i ā†’ C.pullr Ī£F.commute āˆ™ Ī£F'.commute āˆ™ sym (C.idl _)))
  where
    module Ī£F = is-indexed-coproduct Ī£F-coprod
    module Ī£F' = is-indexed-coproduct Ī£F'-coprod

PropertiesšŸ”—

Let be a family of objects in If the the indexed coproducts and exists, then they are isomorphic.

The formal statement of this is a bit of a mouthful, but all of these arguments are just required to ensure that the various coproducts actually exist.

is-indexed-coproduct-assoc
  : āˆ€ {Īŗ Īŗ'} {A : Type Īŗ} {B : A ā†’ Type Īŗ'}
  ā†’ {X : Ī£ A B ā†’ C.Ob}
  ā†’ {Ī£įµƒįµ‡X : C.Ob} {Ī£įµƒĪ£įµ‡X : C.Ob} {Ī£įµ‡X : A ā†’ C.Ob}
  ā†’ {Ī¹įµƒįµ‡ : (ab : Ī£ A B) ā†’ C.Hom (X ab) Ī£įµƒįµ‡X}
  ā†’ {Ī¹įµƒ : āˆ€ a ā†’ C.Hom (Ī£įµ‡X a) Ī£įµƒĪ£įµ‡X}
  ā†’ {Ī¹įµ‡ : āˆ€ a ā†’ (b : B a) ā†’ C.Hom (X (a , b)) (Ī£įµ‡X a)}
  ā†’ is-indexed-coproduct X Ī¹įµƒįµ‡
  ā†’ is-indexed-coproduct Ī£įµ‡X Ī¹įµƒ
  ā†’ (āˆ€ a ā†’ is-indexed-coproduct (Ī» b ā†’ X (a , b)) (Ī¹įµ‡ a))
  ā†’ Ī£įµƒįµ‡X C.ā‰… Ī£įµƒĪ£įµ‡X

Luckily, the proof of this fact is easier than the statement! Indexed coproducts are unique up to isomorphism, so it suffices to show that is an indexed product over which follows almost immediately from our hypotheses.

is-indexed-coproduct-assoc {A = A} {B} {X} {Ī£įµƒĪ£įµ‡X = Ī£įµƒĪ£įµ‡X} {Ī¹įµƒ = Ī¹įµƒ} {Ī¹įµ‡} Ī£įµƒįµ‡ Ī£įµƒĪ£įµ‡ Ī£įµ‡ =
  is-indexed-coproductā†’iso Ī£įµƒįµ‡ Ī£įµƒįµ‡'
  where
    open is-indexed-coproduct

    Ī¹įµƒįµ‡' : āˆ€ (ab : Ī£ A B) ā†’ C.Hom (X ab) Ī£įµƒĪ£įµ‡X
    Ī¹įµƒįµ‡' (a , b) = Ī¹įµƒ a C.āˆ˜ Ī¹įµ‡ a b

    Ī£įµƒįµ‡' : is-indexed-coproduct X Ī¹įµƒįµ‡'
    Ī£įµƒįµ‡' .match f = Ī£įµƒĪ£įµ‡ .match Ī» a ā†’ Ī£įµ‡ a .match Ī» b ā†’ f (a , b)
    Ī£įµƒįµ‡' .commute = C.pulll (Ī£įµƒĪ£įµ‡ .commute) āˆ™ Ī£įµ‡ _ .commute
    Ī£įµƒįµ‡' .unique {h = h} f p =
      Ī£įµƒĪ£įµ‡ .unique _ Ī» a ā†’
      Ī£įµ‡ _ .unique _ Ī» b ā†’
      sym (C.assoc _ _ _) āˆ™ p (a , b)

Categories with all indexed coproductsšŸ”—

has-coproducts-indexed-by : āˆ€ {ā„“} (I : Type ā„“) ā†’ Type _
has-coproducts-indexed-by I = āˆ€ (F : I ā†’ C.Ob) ā†’ Indexed-coproduct F

has-indexed-coproducts : āˆ€ ā„“ ā†’ Type _
has-indexed-coproducts ā„“ = āˆ€ {I : Type ā„“} ā†’ has-coproducts-indexed-by I

module Indexed-coproducts-by
  {Īŗ : Level} {Idx : Type Īŗ}
  (has-ic : has-coproducts-indexed-by Idx)
  where
  module āˆ (F : Idx ā†’ C.Ob) = Indexed-coproduct (has-ic F)

  open āˆ renaming (commute to Ī¹-commute; unique to match-unique) public


module Indexed-coproducts
  {Īŗ : Level}
  (has-ic : has-indexed-coproducts Īŗ)
  where
  module āˆ {Idx : Type Īŗ} (F : Idx ā†’ C.Ob) = Indexed-coproduct (has-ic F)

  open āˆ renaming (commute to Ī¹-commute; unique to match-unique) public

Disjoint coproductsšŸ”—

An indexed coproduct is said to be disjoint if every one of its inclusions is monic, and, for unequal the square below is a pullback with initial apex. Since the maps are monic, the pullback below computes the intersection of and as subobjects of hence the name disjoint coproduct: If is an initial object, then

record is-disjoint-coproduct (F : Idx ā†’ C.Ob) (Ī¹ : āˆ€ i ā†’ C.Hom (F i) S)
  : Type (o āŠ” ā„“ āŠ” level-of Idx) where
  field
    has-is-ic            : is-indexed-coproduct F Ī¹
    injections-are-monic : āˆ€ i ā†’ C.is-monic (Ī¹ i)
    summands-intersect   : āˆ€ i j ā†’ Pullback C (Ī¹ i) (Ī¹ j)
    different-images-are-disjoint
      : āˆ€ i j ā†’ Ā¬ i ā‰” j ā†’ is-initial C (summands-intersect i j .Pullback.apex)

Initial objects are disjointšŸ”—

We prove that if is an initial object, then it is also an indexed coproduct ā€” for any family ā€” and furthermore, it is a disjoint coproduct.

is-initialā†’is-disjoint-coproduct
  : āˆ€ {āˆ…} {F : āŠ„ ā†’ C.Ob} {i : āˆ€ i ā†’ C.Hom (F i) āˆ…}
  ā†’ is-initial C āˆ…
  ā†’ is-disjoint-coproduct F i
is-initialā†’is-disjoint-coproduct {F = F} {i = i} init = is-disjoint where
  open is-indexed-coproduct
  is-coprod : is-indexed-coproduct F i
  is-coprod .match _ = init _ .centre
  is-coprod .commute {i = i} = absurd i
  is-coprod .unique {h = h} f p i = init _ .paths h (~ i)

  open is-disjoint-coproduct
  is-disjoint : is-disjoint-coproduct F i
  is-disjoint .has-is-ic = is-coprod
  is-disjoint .injections-are-monic i = absurd i
  is-disjoint .summands-intersect i j = absurd i
  is-disjoint .different-images-are-disjoint i j p = absurd i

Coproducts and zero objectsšŸ”—

Let be a category with a zero object, and let be a coproduct. If is a discrete type, then every coproduct inclusion has a retract.

First, a useful lemma. Suppose that we have a coproduct indexed by a discrete type, and a map for some If there exists maps for every then we can obtain a map

  detect
    : āˆ€ {X} ā¦ƒ Idx-Discrete : Discrete Idx ā¦„
    ā†’ (i : Idx) ā†’ C.Hom (P i) X
    ā†’ (āˆ€ (j : Idx) ā†’ Ā¬ i ā‰” j ā†’ C.Hom (P j) X)
    ā†’ C.Hom āˆP X

The key idea here is to check if when invoking the universal property of if we use otherwise we use

  detect {X = X} ā¦ƒ Idx-Discrete ā¦„ i tįµ¢ fā±¼ = match probe
    module detect where
      probe : āˆ€ (j : Idx) ā†’ C.Hom (P j) X
      probe j with i ā‰”? j
      ... | yes i=j = subst _ i=j tįµ¢
      ... | no Ā¬i=j = fā±¼ j Ā¬i=j

      probe-yes : probe i ā‰” tįµ¢
      probe-yes with i ā‰”? i
      ... | yes i=i =
        is-setā†’subst-refl
          (Ī» j ā†’ C.Hom (P j) X)
          (Discreteā†’is-set Idx-Discrete)
          i=i tįµ¢
      ... | no Ā¬i=i = absurd (Ā¬i=i refl)

      probe-no : āˆ€ j ā†’ (Ā¬i=j : Ā¬ (i ā‰” j)) ā†’ probe j ā‰” fā±¼ j Ā¬i=j
      probe-no j Ā¬i=j with i ā‰”? j
      ... | yes i=j = absurd (Ā¬i=j i=j)
      ... | no _ = ap (fā±¼ j) prop!

Moreover, we observe that our newly created map interacts nicely with the inclusions into the coproduct.

  detect-yes
    : āˆ€ {X} ā¦ƒ Idx-Discrete : Discrete Idx ā¦„
    ā†’ {i : Idx} ā†’ {tįµ¢ : C.Hom (P i) X}
    ā†’ {fā±¼ : āˆ€ (j : Idx) ā†’ Ā¬ i ā‰” j ā†’ C.Hom (P j) X}
    ā†’ detect i tįµ¢ fā±¼ C.āˆ˜ Ī¹ i ā‰” tįµ¢
  detect-yes = commute āˆ™ detect.probe-yes _ _ _

  detect-no
    : āˆ€ {X} ā¦ƒ Idx-Discrete : Discrete Idx ā¦„
    ā†’ {i : Idx} ā†’ {tįµ¢ : C.Hom (P i) X}
    ā†’ {fā±¼ : āˆ€ (j : Idx) ā†’ Ā¬ i ā‰” j ā†’ C.Hom (P j) X}
    ā†’ āˆ€ j ā†’ (Ā¬i=j : Ā¬ i ā‰” j) ā†’ detect i tįµ¢ fā±¼ C.āˆ˜ Ī¹ j ā‰” fā±¼ j Ā¬i=j
  detect-no j Ā¬i=j = commute āˆ™ detect.probe-no _ _ _ j Ā¬i=j

Refocusing our attention back to our original claim, suppose that has a zero object. This means that there is a canonical choice of morphism between any two objects, so we can apply our previous lemma to obtain a retract

  zeroā†’Ī¹-has-retract
    : āˆ€ ā¦ƒ Idx-Discrete : Discrete Idx ā¦„
    ā†’ Zero C
    ā†’ āˆ€ i ā†’ C.has-retract (Ī¹ i)
  zeroā†’Ī¹-has-retract z i =
    C.make-retract (detect i C.id (Ī» _ _ ā†’ zeroā†’)) detect-yes
    where open Zero z