open import Cat.Diagram.Limit.Base
open import Cat.Instances.Discrete
open import Cat.Diagram.Terminal
open import Cat.Prelude

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

Indexed productsπŸ”—

If a category admits a terminal object and binary products, then it admits products of any finite cardinality: iterate the binary product, and use the terminal object when there aren’t any objects. However, these two classes of limit do not let us speak of products of arbitrary cardinality, or, in the univalent context, indexed by types which are not sets.

That’s where II-indexed products come in: Rather than having a functor giving the objects to take the limit over, we have an arbitrary map FF from II to the space of objects of C\ca{C}. An indexed product for this β€œdiagram” is then an object admitting an universal family of maps Ο€i:(∏F)β†’Fi\pi_i : (\prod F) \to F_i.

record is-indexed-product (F : Idx β†’ C.Ob) (Ο€ : βˆ€ i β†’ C.Hom P (F i))
  : Type (o βŠ” β„“ βŠ” level-of Idx) where
  no-eta-equality
  field
    ⟨_⟩     : βˆ€ {Y} β†’ (βˆ€ i β†’ C.Hom Y (F i)) β†’ C.Hom Y P
    commute : βˆ€ {i} {Y} {f : βˆ€ i β†’ C.Hom Y (F i)} β†’ Ο€ i C.∘ ⟨ f ⟩ ≑ f i
    unique  : βˆ€ {Y} {h : C.Hom Y P} (f : βˆ€ i β†’ C.Hom Y (F i))
            β†’ (βˆ€ i β†’ Ο€ i C.∘ h ≑ f i)
            β†’ h ≑ ⟨ f ⟩

  eta : βˆ€ {Y} (h : C.Hom Y P) β†’ h ≑ ⟨ (Ξ» i β†’ Ο€ i C.∘ h) ⟩
  eta h = unique _ Ξ» _ β†’ refl

A category C\ca{C} admits indexed products (of level ℓ\ell) if, for any type I:Type ℓI : \ty\ \ell and family F:I→CF : I \to \ca{C}, there is an indexed product of FF.

record Indexed-product (F : Idx β†’ C.Ob) : Type (o βŠ” β„“ βŠ” level-of Idx) where
  no-eta-equality
  field
    {Ξ F}      : C.Ob
    Ο€         : βˆ€ i β†’ C.Hom Ξ F (F i)
    has-is-ip : is-indexed-product F Ο€
  open is-indexed-product has-is-ip public

has-indexed-products : βˆ€ β„“ β†’ Type _
has-indexed-products β„“ = βˆ€ {I : Type β„“} (F : I β†’ C.Ob) β†’ Indexed-product F

As limitsπŸ”—

In the particular case where II is a groupoid, e.g. because it arises as the space of objects of a univalent category, an indexed product for F:I→CF : I \to \ca{C} is the same thing as a limit over FF, considered as a functor \discI→C\disc{I} \to \ca{C}. We can not lift this restriction: If II is not a groupoid, then its path spaces x=yx = y are not necessarily sets, and so the Disc construction does not apply to it.

module _ {I : Type β„“'} (i-is-grpd : is-groupoid I) (F : I β†’ C.Ob) where
  open Cone-hom
  open Terminal
  open Cone

  IP→Limit : Indexed-product F → Limit {C = C} (Disc-adjunct {iss = i-is-grpd} F)
  IP→Limit IP = lim where
    module IP = Indexed-product IP

    thelim : Cone _
    thelim .apex = IP.Ξ F
    thelim .ψ = IP.Ο€
    thelim .commutes {x} =
      J (Ξ» y p β†’ subst (C.Hom (F x) βŠ™ F) p C.id C.∘ (IP.Ο€ x) ≑ IP.Ο€ y)
        (C.eliml (transport-refl _))

    lim : Limit _
    lim .top = thelim
    lim .has⊀ x .centre .hom = IP.⟨ x .ψ ⟩IP.
    lim .has⊀ x .centre .commutes o = IP.commute
    lim .has⊀ x .paths h = Cone-hom-path _ (sym (IP.unique _ Ξ» i β†’ h .commutes _))

module _ {I : Type β„“'} (isg : is-groupoid I) (F : Functor (Disc I isg) C) where
  private module F = Functor F
  open is-indexed-product
  open Indexed-product
  open Cone-hom
  open Terminal
  open Cone

  Projβ†’Cone : βˆ€ {Y} β†’ (βˆ€ i β†’ C.Hom Y (F.β‚€ i)) β†’ Cone F
  Proj→Cone f .apex = _
  Projβ†’Cone f .ψ = f
  Proj→Cone f .commutes {x} =
    J (Ξ» y p β†’ F.₁ p C.∘ f x ≑ f y) (C.eliml F.F-id)

  Limit→IP : Limit {C = C} F → Indexed-product F.₀
  Limit→IP lim = the-ip where
    module lim = Cone (lim .top)

    the-ip : Indexed-product _
    the-ip .Ξ F = lim.apex
    the-ip .Ο€ = lim.ψ
    the-ip .has-is-ip .⟨_⟩ f = lim .has⊀ (Projβ†’Cone f) .centre .hom
    the-ip .has-is-ip .commute = lim .has⊀ (Projβ†’Cone _) .centre .commutes _
    the-ip .has-is-ip .unique {h = h} f p i =
      lim .has⊀ (Projβ†’Cone f) .paths other (~ i) .hom
      where
        other : Cone-hom _ _ _
        other .hom = h
        other .commutes i = p i