module Colimit where

open import Axioms public
open import InitialAlgebra public
open import Prelude public
open import ThinSemiCategory public

----------------------------------------------------------------------
-- Diagrams on thin semi categories
----------------------------------------------------------------------
record Diag (κ : Set){{_ : Thin κ}}(𝓒 : Set₁){{_ : CAT 𝓒}} : Set₁ where
  field
    V   : κ  𝓒
    E   :  i  ∏ᵇ j < i , (V j  V i)
    E∙E :  i  ∀ᵇ j < i , ∀ᵇ k < j , (E i j  E j k  E i k)

open Diag public

----------------------------------------------------------------------
-- Categories with colimits of diagrams
----------------------------------------------------------------------
record Cocomplete (𝓒 : Set₁){{_ : CAT 𝓒}} : Set₁ where
  field
    colim : {κ : Set}{{_ : Thin κ}}  Diag κ 𝓒  𝓒
    inc :
      {κ : Set}
      {{_ : Thin κ}}
      (D : Diag κ 𝓒)
      (i : κ)
       -------------
      V D i  colim D
    cocone :
      {κ : Set}
      {{_ : Thin κ}}
      (D : Diag κ 𝓒)
      {i : κ}
       --------------------------------------
      ∀ᵇ j < i , (inc D j  inc D i  E D i j)
    lift :
      {κ : Set}
      {{_ : Thin κ}}
      (D : Diag κ 𝓒)
      {C : 𝓒}
      (f :  i  V D i  C)
      (_ : {i : κ}  ∀ᵇ j < i , (f j  f i  E D i j))
       ----------------------------------------------
      colim D  C
    liftinc :
      {κ : Set}
      {{_ : Thin κ}}
      (D : Diag κ 𝓒)
      {C : 𝓒}
      (f :  i  V D i  C)
      (φ : ∀{i}  ∀ᵇ j < i , (f j  f i  E D i j))
      (i : κ)
       -------------------------------------------
      f i  lift D f φ  inc D i
    liftuniq :
      {κ : Set}
      {{_ : Thin κ}}
      (D : Diag κ 𝓒)
      {C : 𝓒}
      (f :  i  V D i  C)
      (φ : ∀{i}  ∀ᵇ j < i , (f j  f i  E D i j))
      {g : colim D  C}
      (_ :  i  f i  g  inc D i)
       -------------------------------------------
      lift D f φ  g

  colimext :
    {κ : Set}
    {{_ : Thin κ}}
    (D : Diag κ 𝓒)
    {C : 𝓒}
    {f g : colim D  C}
    (_ :  i  f  inc D i  g  inc D i)
     -----------------------------------
    f  g
  colimext D {C} {f} {g} finc=ginc =
    proof
      f
    =[ symm (liftuniq D _ φ'  _  refl)) ]
      lift D f' φ'
    =[ liftuniq D _ φ' finc=ginc ]
      g
    qed
    where
    f' :  i  V D i  C
    f' i = f  inc D i

    φ' : ∀{i}  ∀ᵇ j < i , (f' j  f' i  E D i j)
    φ' {i} j =
      proof
        f  inc D j
      =[ ap (f ∙_) (cocone _ _) ]
        f  (inc D i  E D i j)
      =[ symm ∙assoc ]
        (f  inc D i)  E D i j
      qed

open Cocomplete {{...}} public

----------------------------------------------------------------------
-- Compose a functor with a diagram
----------------------------------------------------------------------
infix 6 _⊙_
_⊙_ :
  {𝓒 𝓓 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : CAT 𝓓}}
  (F : 𝓒  𝓓)
  {{_ : Functor F}}
  {κ : Set}
  {{_ : Thin κ}}
  (D : Diag κ 𝓒)
   ---------------
  Diag κ 𝓓
V   (F  D) i = F (V D i)
E   (F  D) i j = F  (E D i j)
E∙E (_⊙_ F {{func}} D) i j k =
  proof
    F  (E D i j)  F  (E D j k)
  =[ symm (act∙ {{r = func}}) ]
    F  (E D i j  E D j k)
  =[ ap (F ′_) (E∙E D i j k) ]
     F  (E D i k)
  qed
-- The canonical morphism colim (F ⊙ D) → F (colim D)
can :
  {𝓒 𝓓 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  {{_ : CAT 𝓓}}
  {{_ : Cocomplete 𝓓}}
  (F : 𝓒  𝓓)
  {{_ : Functor F}}
  {κ : Set}
  {{_ : Thin κ}}
  (D : Diag κ 𝓒)
   -------------------------
  colim (F  D)  F (colim D)
can F {{func}} D = lift (F  D) caninc caninc'
  module _ where
  caninc :  i   F (V D i)  F (colim D)
  caninc i = F  inc D i

  caninc' : ∀{i}  ∀ᵇ j < i , (caninc j  caninc i  F  (E D i j))
  caninc' {i} j =
    proof
      F  (inc D j)
    =[ ap (F ′_) (cocone D j) ]
      F  (inc D i  E D i j)
    =[ act∙ {{r = func}} ]
      F  (inc D i)  F  (E D i j)
    qed

----------------------------------------------------------------------
-- Preservation of colimits
----------------------------------------------------------------------
Cocontinuous :
  (κ : Set)
  {{_ : Thin κ}}
  {𝓒 𝓓 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : CAT 𝓓}}
  {{_ : Cocomplete 𝓒}}
  {{_ : Cocomplete 𝓓}}
  (F : 𝓒  𝓓)
  {{_ : Functor F}}
   ------------------
  Prop₁
Cocontinuous κ {𝓒} F = (D : Diag κ 𝓒)  Iso (can F D)

----------------------------------------------------------------------
-- Bounded diagrams on thin semi categories
----------------------------------------------------------------------
record Diagᵇ
  {κ : Set}
  {{_ : Thin κ}}
  (i : κ)
  (𝓒 : Set₁)
  {{_ : CAT 𝓒}}
  : -----------
  Set₁
  where
  field
    Vᵇ    : ∏ᵇ j < i , 𝓒
    Eᵇ    : ∏ᵇ j < i , ∏ᵇ k < j , (Vᵇ k  Vᵇ j)
    Eᵇ∙Eᵇ : ∀ᵇ j < i , ∀ᵇ k < j , ∀ᵇ l < k ,
      (Eᵇ j k  Eᵇ k l  Eᵇ j l)

open Diagᵇ public

-- Extensionality principle for Diagᵇ
Diagᵇext :
  {κ : Set}
  {{_ : Thin κ}}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {i : κ}
  {D D' : Diagᵇ i 𝓒}
  (_ : ∀ᵇ j < i , (Vᵇ D j  Vᵇ D' j))
  (_ : ∀ᵇ j < i , ∀ᵇ k < j , (Eᵇ D j k  Eᵇ D' j k))
   ------------------------------------------------
  D  D'
Diagᵇext {i = i} {D} {D'} v e =
  match VᵇD=VᵇD' \ where
    refl  match EᵇD=EᵇD' \ where
      refl  refl
  where
  VᵇD=VᵇD' : Vᵇ D  Vᵇ D'
  VᵇD=VᵇD' = funext \
    j  instance-funexp \
      p  v j {{p}}

  EᵇD=EᵇD' : Eᵇ D  Eᵇ D'
  EᵇD=EᵇD' = match VᵇD=VᵇD' \ where
    refl  funext \
      j  instance-funexp \
        p  funext \
          k  instance-funexp \
            q  e j {{p}} k {{q}}

-- Restriction of a bounded diagram
infixl 6 _⇂_
_⇂_ :
  {κ : Set}
  {{_ : Thin κ}}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  (D : Diag κ 𝓒)
  (i : κ)
   ------------
  Diagᵇ i 𝓒
Vᵇ    (D  _) j     = V D j
Eᵇ    (D  _) j k   = E D j k
Eᵇ∙Eᵇ (D  _) j k l = E∙E D j k l

infixl 6 _⇂ᵇ_
_⇂ᵇ_ :
  {κ : Set}
  {{_ : Thin κ}}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {i : κ}
  (D : Diagᵇ i 𝓒)
  (j : κ)
  {{_ : j <ᵇ i}}
   -------------
  Diagᵇ j 𝓒
Vᵇ    (D ⇂ᵇ j)       = (Vᵇ D) ↓ᵇ j
Eᵇ    (D ⇂ᵇ j)       = (Eᵇ D) ↓ᵇ j
Eᵇ∙Eᵇ (D ⇂ᵇ j) k l m = Eᵇ∙Eᵇ D k l m

⇂ᵇ∙⇂ᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {i : κ}
  (D : Diagᵇ i 𝓒)
  (j k : κ)
  {{_ : j <ᵇ i}}
  {{_ : k <ᵇ j}}
   --------------------
  (D ⇂ᵇ j) ⇂ᵇ k  D ⇂ᵇ k
⇂ᵇ∙⇂ᵇ D j k  = Diagᵇext  _  refl)  _ _  refl)

-- Compose an endofunctor with a bounded diagram
infix 6 _⊙ᵇ_
_⊙ᵇ_ :
  {𝓒 𝓓 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : CAT 𝓓}}
  (F : 𝓒  𝓓)
  {{_ : Functor F}}
  {κ : Set}
  {{_ : Thin κ}}
  {i : κ}
   --------------------
  Diagᵇ i 𝓒  Diagᵇ i 𝓓
Vᵇ (F ⊙ᵇ D) j   = F   (Vᵇ D j)
Eᵇ (F ⊙ᵇ D) j k = F  (Eᵇ D j k)
Eᵇ∙Eᵇ (_⊙ᵇ_ F {{func}} D) j k l =
  proof
    F  (Eᵇ D j k)  F  (Eᵇ D k l)
  =[ symm (act∙ {{r = func}}) ]
    F  (Eᵇ D j k  Eᵇ D k l)
  =[ ap (F ′_) (Eᵇ∙Eᵇ D j k l) ]
    F  (Eᵇ D j l)
  qed

----------------------------------------------------------------------
-- Colimit of a bounded diagram
----------------------------------------------------------------------
Dwn : (κ : Set){{_ : Thin κ}}  κ  Set
Dwn κ i = set j  κ , (j < i)

dwn : {κ : Set}{{_ : Thin κ}}{i : κ}  ∏ᵇ j < i , Dwn κ i
dwn j {{p}} = j  <prf p

instance
  ThinDwn :
    {κ : Set}
    {{_ : Thin κ}}
    {i : κ}
     -----------
    Thin (Dwn κ i)
  _<_ {{ThinDwn}} k j = el k < el j
  <<  {{ThinDwn}} q p = << q p

diagᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  {i : κ}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  (D : Diagᵇ i 𝓒)
   --------------
  Diag (Dwn κ i) 𝓒
V (diagᵇ D) j                               =
  Vᵇ D (el j) {{<inst (pf j)}}
E (diagᵇ D) j k {{<inst p}}                 =
  Eᵇ D (el j) {{<inst (pf j)}} (el k) {{<inst p}}
E∙E (diagᵇ D) j k {{<inst p}} l {{<inst q}} =
  Eᵇ∙Eᵇ D (el j) {{<inst (pf j)}} (el k) {{<inst p}} (el l) {{<inst q}}

colimᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  (i : κ)
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
   ------------------
  Diagᵇ i 𝓒  𝓒
colimᵇ i D = colim (diagᵇ D)

incᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  {i : κ}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  (D : Diagᵇ i 𝓒)
   ------------------------------
  ∏ᵇ j < i , (Vᵇ D j  colimᵇ i D)
incᵇ D j = inc (diagᵇ D) (dwn j)

coconeincᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  {i : κ}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  (D : Diagᵇ i 𝓒)
   ----------------------------------------------------
  ∀ᵇ j < i , ∀ᵇ k < j , (incᵇ D k  incᵇ D j  Eᵇ D j k)
coconeincᵇ D j k {{p}} = cocone (diagᵇ D) (dwn k) {{<inst (<prf p)}}

module _
  {κ : Set}
  {{_ : Thin κ}}
  {i : κ}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  (D : Diagᵇ i 𝓒)
  {C : 𝓒}
  (f : ∏ᵇ j < i , (Vᵇ D j  C))
  (φ : ∀ᵇ j < i , ∀ᵇ k < j , (f k  f j  Eᵇ D j k))
  where
  private
    f' : ((j  p) : Dwn κ i)  (Vᵇ D j {{<inst p}}  C)
    f' (j  p) = f j {{<inst p}}

    φ' : {j : Dwn κ i}  ∀ᵇ k < j , (f' k  f' j  E (diagᵇ D) j k )
    φ' {j  p} (k  _) {{<inst r}} = φ j {{<inst p}} k {{<inst r}}

  liftᵇ : colimᵇ i D  C
  liftᵇ = lift (diagᵇ D) f' φ'

  liftincᵇ : ∀ᵇ j < i , (f j  liftᵇ  incᵇ D j)
  liftincᵇ j = liftinc (diagᵇ D) f' φ' (dwn j)

  liftuniqᵇ :
    (g : colimᵇ i D  C)
    (ψ : ∀ᵇ j < i , (f j  g  incᵇ D j))
     -----------------------------------
    liftᵇ  g
  liftuniqᵇ g ψ =
    liftuniq (diagᵇ D) f' φ' {g} λ{(j  p)  ψ j {{<inst p}}}

colimextᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  {i : κ}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  (D : Diagᵇ i 𝓒)
  {C : 𝓒}
  {f g : colimᵇ i D  C}
  (_ : ∀ᵇ j < i , (f  incᵇ D j  g  incᵇ D j))
   --------------------------------------------
  f  g
colimextᵇ {κ} {i} D e = colimext (diagᵇ D) λ{(j  p)  e j {{<inst p}}}

colimᵇ⇂ :
  {κ : Set}
  {{_ : Thin κ}}
  (i j : κ)
  {{_ : j <ᵇ i}}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  (D : Diagᵇ i 𝓒)
   ----------------------------
  colimᵇ j (D ⇂ᵇ j)  colimᵇ i D
colimᵇ⇂ i j D = liftᵇ (D ⇂ᵇ j)
   k    incᵇ D k)
   k l  coconeincᵇ D k l)

colimᵇ⇂incᵇ :
  {κ : Set}
  {{_ : Thin κ}}
  (i j k : κ)
  {{_ : j <ᵇ i}}
  {{_ : k <ᵇ j}}
  {𝓒 : Set₁}
  {{_ : CAT 𝓒}}
  {{_ : Cocomplete 𝓒}}
  (D : Diagᵇ i 𝓒)
   ----------------------------------------
  incᵇ D k  colimᵇ⇂ i j D  incᵇ (D ⇂ᵇ j) k
colimᵇ⇂incᵇ i j k D = liftincᵇ (D ⇂ᵇ j)
   k    incᵇ D k)
   k l  coconeincᵇ D k l) k