l3lab/ntp-mathlib huggingface dataset:
/-- We can prove two cocone points `(s : Cocone F).pt` and `(t : Cocone G).pt` are isomorphic if
* both cocones are colimit cocones
* their indexing categories are equivalent via some `e : J ≌ K`,
* the triangle of functors commutes up to a natural isomorphism: `e.functor ⋙ G ≅ F`.

This is the most general form of uniqueness of cocone points,
allowing relabelling of both the indexing category (up to equivalence)
and the functor (up to natural isomorphism).
-/
@[simps]
def coconePointsIsoOfEquivalence {F : J ⥤ C} {s : Cocone F} {G : K ⥤ C} {t : Cocone G}
    (P : IsColimit s) (Q : IsColimit t) (e : J ≌ K) (w : e.functor ⋙ G ≅ F) : s.pt ≅ t.pt :=
  let w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
  { hom := P.desc ((Cocones.equivalenceOfReindexing e w).functor.obj t)
    inv := Q.desc ((Cocones.equivalenceOfReindexing e.symm w').functor.obj s)
    hom_inv_id := by
      apply hom_ext P; intro j
      dsimp
      simp only [Limits.Cocone.whisker_ι, fac, invFunIdAssoc_inv_app, whiskerLeft_app, assoc,
        comp_id, Limits.Cocones.precompose_obj_ι, fac_assoc, NatTrans.comp_app]
      rw [counitInv_app_functor, ← Functor.comp_map, ← w.inv.naturality_assoc]
      

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F✝ : J ⥤ C
t✝ : Cocone F✝
F : J ⥤ C
s : Cocone F
G : K ⥤ C
t : Cocone G
P : IsColimit s
Q : IsColimit t
e : J ≌ K
w : e.functor ⋙ G ≅ F
w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
j : J
⊢ F.map (e.unit.app j) ≫
      w.inv.app ((e.functor ⋙ e.inverse).obj j) ≫
        w.hom.app (e.inverse.obj (e.functor.obj j)) ≫ s.ι.app (e.inverse.obj (e.functor.obj j)) =
    s.ι.app j

Next tactic:
dsimp
/-- We can prove two cocone points `(s : Cocone F).pt` and `(t : Cocone G).pt` are isomorphic if
* both cocones are colimit cocones
* their indexing categories are equivalent via some `e : J ≌ K`,
* the triangle of functors commutes up to a natural isomorphism: `e.functor ⋙ G ≅ F`.

This is the most general form of uniqueness of cocone points,
allowing relabelling of both the indexing category (up to equivalence)
and the functor (up to natural isomorphism).
-/
@[simps]
def coconePointsIsoOfEquivalence {F : J ⥤ C} {s : Cocone F} {G : K ⥤ C} {t : Cocone G}
    (P : IsColimit s) (Q : IsColimit t) (e : J ≌ K) (w : e.functor ⋙ G ≅ F) : s.pt ≅ t.pt :=
  let w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
  { hom := P.desc ((Cocones.equivalenceOfReindexing e w).functor.obj t)
    inv := Q.desc ((Cocones.equivalenceOfReindexing e.symm w').functor.obj s)
    hom_inv_id := by
      apply hom_ext P; intro j
      dsimp
      simp only [Limits.Cocone.whisker_ι, fac, invFunIdAssoc_inv_app, whiskerLeft_app, assoc,
        comp_id, Limits.Cocones.precompose_obj_ι, fac_assoc, NatTrans.comp_app]
      rw [counitInv_app_functor, ← Functor.comp_map, ← w.inv.naturality_assoc]
      dsimp
      

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F✝ : J ⥤ C
t✝ : Cocone F✝
F : J ⥤ C
s : Cocone F
G : K ⥤ C
t : Cocone G
P : IsColimit s
Q : IsColimit t
e : J ≌ K
w : e.functor ⋙ G ≅ F
w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
j : J
⊢ F.map (e.unit.app j) ≫
      w.inv.app (e.inverse.obj (e.functor.obj j)) ≫
        w.hom.app (e.inverse.obj (e.functor.obj j)) ≫ s.ι.app (e.inverse.obj (e.functor.obj j)) =
    s.ι.app j

Next tactic:
simp
/-- We can prove two cocone points `(s : Cocone F).pt` and `(t : Cocone G).pt` are isomorphic if
* both cocones are colimit cocones
* their indexing categories are equivalent via some `e : J ≌ K`,
* the triangle of functors commutes up to a natural isomorphism: `e.functor ⋙ G ≅ F`.

This is the most general form of uniqueness of cocone points,
allowing relabelling of both the indexing category (up to equivalence)
and the functor (up to natural isomorphism).
-/
@[simps]
def coconePointsIsoOfEquivalence {F : J ⥤ C} {s : Cocone F} {G : K ⥤ C} {t : Cocone G}
    (P : IsColimit s) (Q : IsColimit t) (e : J ≌ K) (w : e.functor ⋙ G ≅ F) : s.pt ≅ t.pt :=
  let w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
  { hom := P.desc ((Cocones.equivalenceOfReindexing e w).functor.obj t)
    inv := Q.desc ((Cocones.equivalenceOfReindexing e.symm w').functor.obj s)
    hom_inv_id := by
      apply hom_ext P; intro j
      dsimp
      simp only [Limits.Cocone.whisker_ι, fac, invFunIdAssoc_inv_app, whiskerLeft_app, assoc,
        comp_id, Limits.Cocones.precompose_obj_ι, fac_assoc, NatTrans.comp_app]
      rw [counitInv_app_functor, ← Functor.comp_map, ← w.inv.naturality_assoc]
      dsimp
      simp
    inv_hom_id := by
      

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F✝ : J ⥤ C
t✝ : Cocone F✝
F : J ⥤ C
s : Cocone F
G : K ⥤ C
t : Cocone G
P : IsColimit s
Q : IsColimit t
e : J ≌ K
w : e.functor ⋙ G ≅ F
w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
⊢ desc Q ((Cocones.equivalenceOfReindexing e.symm w').functor.obj s) ≫
      desc P ((Cocones.equivalenceOfReindexing e w).functor.obj t) =
    𝟙 t.pt

Next tactic:
apply hom_ext Q
/-- We can prove two cocone points `(s : Cocone F).pt` and `(t : Cocone G).pt` are isomorphic if
* both cocones are colimit cocones
* their indexing categories are equivalent via some `e : J ≌ K`,
* the triangle of functors commutes up to a natural isomorphism: `e.functor ⋙ G ≅ F`.

This is the most general form of uniqueness of cocone points,
allowing relabelling of both the indexing category (up to equivalence)
and the functor (up to natural isomorphism).
-/
@[simps]
def coconePointsIsoOfEquivalence {F : J ⥤ C} {s : Cocone F} {G : K ⥤ C} {t : Cocone G}
    (P : IsColimit s) (Q : IsColimit t) (e : J ≌ K) (w : e.functor ⋙ G ≅ F) : s.pt ≅ t.pt :=
  let w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
  { hom := P.desc ((Cocones.equivalenceOfReindexing e w).functor.obj t)
    inv := Q.desc ((Cocones.equivalenceOfReindexing e.symm w').functor.obj s)
    hom_inv_id := by
      apply hom_ext P; intro j
      dsimp
      simp only [Limits.Cocone.whisker_ι, fac, invFunIdAssoc_inv_app, whiskerLeft_app, assoc,
        comp_id, Limits.Cocones.precompose_obj_ι, fac_assoc, NatTrans.comp_app]
      rw [counitInv_app_functor, ← Functor.comp_map, ← w.inv.naturality_assoc]
      dsimp
      simp
    inv_hom_id := by
      apply hom_ext Q
      

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F✝ : J ⥤ C
t✝ : Cocone F✝
F : J ⥤ C
s : Cocone F
G : K ⥤ C
t : Cocone G
P : IsColimit s
Q : IsColimit t
e : J ≌ K
w : e.functor ⋙ G ≅ F
w' : e.inverse ⋙ F ≅ G := (isoWhiskerLeft e.inverse w).symm ≪≫ invFunIdAssoc e G
⊢ ∀ (j : K),
    t.ι.app j ≫
        desc Q ((Cocones.equivalenceOfReindexing e.symm w').functor.obj s) ≫
          desc P ((Cocones.equivalenceOfReindexing e w).functor.obj t) =
      t.ι.app j ≫ 𝟙 t.pt

Next tactic:
aesop_cat
/-- The universal property of a colimit cocone: a map `X ⟶ W` is the same as
  a cocone on `F` with cone point `W`. -/
@[pp_dot]
def homIso (h : IsColimit t) (W : C) : ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅ F ⟶ (const J).obj W where
  hom f := (t.extend f.down).ι
  inv ι := ⟨h.desc
      { pt := W
        ι }⟩
  hom_inv_id := by
    

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
⊢ ((fun f => (Cocone.extend t f.down).ι) ≫ fun ι => { down := desc h { pt := W, ι := ι } }) =
    𝟙 (ULift.{u₁, v₃} (t.pt ⟶ W))

Next tactic:
funext f
/-- The universal property of a colimit cocone: a map `X ⟶ W` is the same as
  a cocone on `F` with cone point `W`. -/
@[pp_dot]
def homIso (h : IsColimit t) (W : C) : ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅ F ⟶ (const J).obj W where
  hom f := (t.extend f.down).ι
  inv ι := ⟨h.desc
      { pt := W
        ι }⟩
  hom_inv_id := by
    funext f; 

Proof state:
case h
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
f : ULift.{u₁, v₃} (t.pt ⟶ W)
⊢ ((fun f => (Cocone.extend t f.down).ι) ≫ fun ι => { down := desc h { pt := W, ι := ι } }) f =
    𝟙 (ULift.{u₁, v₃} (t.pt ⟶ W)) f

Next tactic:
apply ULift.ext
/-- The universal property of a colimit cocone: a map `X ⟶ W` is the same as
  a cocone on `F` with cone point `W`. -/
@[pp_dot]
def homIso (h : IsColimit t) (W : C) : ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅ F ⟶ (const J).obj W where
  hom f := (t.extend f.down).ι
  inv ι := ⟨h.desc
      { pt := W
        ι }⟩
  hom_inv_id := by
    funext f; apply ULift.ext
    

Proof state:
case h.h
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
f : ULift.{u₁, v₃} (t.pt ⟶ W)
⊢ (((fun f => (Cocone.extend t f.down).ι) ≫ fun ι => { down := desc h { pt := W, ι := ι } }) f).down =
    (𝟙 (ULift.{u₁, v₃} (t.pt ⟶ W)) f).down

Next tactic:
apply h.hom_ext
/-- The universal property of a colimit cocone: a map `X ⟶ W` is the same as
  a cocone on `F` with cone point `W`. -/
@[pp_dot]
def homIso (h : IsColimit t) (W : C) : ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅ F ⟶ (const J).obj W where
  hom f := (t.extend f.down).ι
  inv ι := ⟨h.desc
      { pt := W
        ι }⟩
  hom_inv_id := by
    funext f; apply ULift.ext
    apply h.hom_ext; 

Proof state:
case h.h
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
f : ULift.{u₁, v₃} (t.pt ⟶ W)
⊢ ∀ (j : J),
    t.ι.app j ≫ (((fun f => (Cocone.extend t f.down).ι) ≫ fun ι => { down := desc h { pt := W, ι := ι } }) f).down =
      t.ι.app j ≫ (𝟙 (ULift.{u₁, v₃} (t.pt ⟶ W)) f).down

Next tactic:
intro j
/-- The universal property of a colimit cocone: a map `X ⟶ W` is the same as
  a cocone on `F` with cone point `W`. -/
@[pp_dot]
def homIso (h : IsColimit t) (W : C) : ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅ F ⟶ (const J).obj W where
  hom f := (t.extend f.down).ι
  inv ι := ⟨h.desc
      { pt := W
        ι }⟩
  hom_inv_id := by
    funext f; apply ULift.ext
    apply h.hom_ext; intro j; 

Proof state:
case h.h
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
f : ULift.{u₁, v₃} (t.pt ⟶ W)
j : J
⊢ t.ι.app j ≫ (((fun f => (Cocone.extend t f.down).ι) ≫ fun ι => { down := desc h { pt := W, ι := ι } }) f).down =
    t.ι.app j ≫ (𝟙 (ULift.{u₁, v₃} (t.pt ⟶ W)) f).down

Next tactic:
simp
/-- Another, more explicit, formulation of the universal property of a colimit cocone.
See also `homIso`. -/
@[pp_dot]
def homIso' (h : IsColimit t) (W : C) :
    ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅
      { p : ∀ j, F.obj j ⟶ W // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j } :=
  h.homIso W ≪≫
    { hom := fun ι =>
        ⟨fun j => ι.app j, fun {j} {j'} f => by 

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
ι : F ⟶ (const J).obj W
j j' : J
f : j ⟶ j'
⊢ F.map f ≫ (fun j => ι.app j) j' = (fun j => ι.app j) j

Next tactic:
convert ← ι.naturality f
/-- Another, more explicit, formulation of the universal property of a colimit cocone.
See also `homIso`. -/
@[pp_dot]
def homIso' (h : IsColimit t) (W : C) :
    ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅
      { p : ∀ j, F.obj j ⟶ W // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j } :=
  h.homIso W ≪≫
    { hom := fun ι =>
        ⟨fun j => ι.app j, fun {j} {j'} f => by convert ← ι.naturality f; 

Proof state:
case h.e'_3.h
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
ι : F ⟶ (const J).obj W
j j' : J
f : j ⟶ j'
e_1✝ : (F.obj j ⟶ ((const J).obj W).obj j') = (F.obj j ⟶ W)
⊢ ι.app j ≫ ((const J).obj W).map f = (fun j => ι.app j) j

Next tactic:
apply comp_id
/-- Another, more explicit, formulation of the universal property of a colimit cocone.
See also `homIso`. -/
@[pp_dot]
def homIso' (h : IsColimit t) (W : C) :
    ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅
      { p : ∀ j, F.obj j ⟶ W // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j } :=
  h.homIso W ≪≫
    { hom := fun ι =>
        ⟨fun j => ι.app j, fun {j} {j'} f => by convert ← ι.naturality f; apply comp_id⟩
      inv := fun p =>
        { app := fun j => p.1 j
          naturality := fun j j' f => by 

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
p : { p // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j }
j j' : J
f : j ⟶ j'
⊢ F.map f ≫ (fun j => ↑p j) j' = (fun j => ↑p j) j ≫ ((const J).obj W).map f

Next tactic:
dsimp
/-- Another, more explicit, formulation of the universal property of a colimit cocone.
See also `homIso`. -/
@[pp_dot]
def homIso' (h : IsColimit t) (W : C) :
    ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅
      { p : ∀ j, F.obj j ⟶ W // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j } :=
  h.homIso W ≪≫
    { hom := fun ι =>
        ⟨fun j => ι.app j, fun {j} {j'} f => by convert ← ι.naturality f; apply comp_id⟩
      inv := fun p =>
        { app := fun j => p.1 j
          naturality := fun j j' f => by dsimp; 

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
p : { p // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j }
j j' : J
f : j ⟶ j'
⊢ F.map f ≫ ↑p j' = ↑p j ≫ 𝟙 W

Next tactic:
rw [comp_id]
/-- Another, more explicit, formulation of the universal property of a colimit cocone.
See also `homIso`. -/
@[pp_dot]
def homIso' (h : IsColimit t) (W : C) :
    ULift.{u₁} (t.pt ⟶ W : Type v₃) ≅
      { p : ∀ j, F.obj j ⟶ W // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j } :=
  h.homIso W ≪≫
    { hom := fun ι =>
        ⟨fun j => ι.app j, fun {j} {j'} f => by convert ← ι.naturality f; apply comp_id⟩
      inv := fun p =>
        { app := fun j => p.1 j
          naturality := fun j j' f => by dsimp; rw [comp_id]; 

Proof state:
J : Type u₁
inst✝² : Category.{v₁, u₁} J
K : Type u₂
inst✝¹ : Category.{v₂, u₂} K
C : Type u₃
inst✝ : Category.{v₃, u₃} C
F : J ⥤ C
t : Cocone F
h : IsColimit t
W : C
p : { p // ∀ {j j' : J} (f : j ⟶ j'), F.map f ≫ p j' = p j }
j j' : J
f : j ⟶ j'
⊢ F.map f ≫ ↑p j' = ↑p j

Next tactic:
exact p.2 f
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by 

Proof state:
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
j : J
⊢ t.ι.app j ≫ desc s = s.ι.app j

Next tactic:
apply G.map_injective
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; 

Proof state:
case a
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
j : J
⊢ G.map (t.ι.app j ≫ desc s) = G.map (s.ι.app j)

Next tactic:
rw [G.map_comp, h]
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; rw [G.map_comp, h]; 

Proof state:
case a
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
j : J
⊢ G.map (t.ι.app j) ≫ CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s) = G.map (s.ι.app j)

Next tactic:
apply ht.fac
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; rw [G.map_comp, h]; apply ht.fac
    uniq := fun s m w => by
      

Proof state:
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
m : t.pt ⟶ s.pt
w : ∀ (j : J), t.ι.app j ≫ m = s.ι.app j
⊢ m = desc s

Next tactic:
apply G.map_injective
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; rw [G.map_comp, h]; apply ht.fac
    uniq := fun s m w => by
      apply G.map_injective; 

Proof state:
case a
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
m : t.pt ⟶ s.pt
w : ∀ (j : J), t.ι.app j ≫ m = s.ι.app j
⊢ G.map m = G.map (desc s)

Next tactic:
rw [h]
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; rw [G.map_comp, h]; apply ht.fac
    uniq := fun s m w => by
      apply G.map_injective; rw [h]
      

Proof state:
case a
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
m : t.pt ⟶ s.pt
w : ∀ (j : J), t.ι.app j ≫ m = s.ι.app j
⊢ G.map m = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)

Next tactic:
refine' ht.uniq (mapCocone G s) _ fun j => _
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; rw [G.map_comp, h]; apply ht.fac
    uniq := fun s m w => by
      apply G.map_injective; rw [h]
      refine' ht.uniq (mapCocone G s) _ fun j => _
      

Proof state:
case a
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
m : t.pt ⟶ s.pt
w : ∀ (j : J), t.ι.app j ≫ m = s.ι.app j
j : J
⊢ (G.mapCocone t).ι.app j ≫ G.map m = (G.mapCocone s).ι.app j

Next tactic:
convert ← congrArg (fun f => G.map f) (w j)
/-- If G : C → D is a faithful functor which sends t to a colimit cocone,
  then it suffices to check that the induced maps for the image of t
  can be lifted to maps of C. -/
def ofFaithful {t : Cocone F} {D : Type u₄} [Category.{v₄} D] (G : C ⥤ D) [Faithful G]
    (ht : IsColimit (mapCocone G t)) (desc : ∀ s : Cocone F, t.pt ⟶ s.pt)
    (h : ∀ s, G.map (desc s) = ht.desc (mapCocone G s)) : IsColimit t :=
  { desc
    fac := fun s j => by apply G.map_injective; rw [G.map_comp, h]; apply ht.fac
    uniq := fun s m w => by
      apply G.map_injective; rw [h]
      refine' ht.uniq (mapCocone G s) _ fun j => _
      convert ← congrArg (fun f => G.map f) (w j)
      

Proof state:
case h.e'_2.h
J : Type u₁
inst✝⁴ : Category.{v₁, u₁} J
K : Type u₂
inst✝³ : Category.{v₂, u₂} K
C : Type u₃
inst✝² : Category.{v₃, u₃} C
F : J ⥤ C
t✝ t : Cocone F
D : Type u₄
inst✝¹ : Category.{v₄, u₄} D
G : C ⥤ D
inst✝ : Faithful G
ht : IsColimit (G.mapCocone t)
desc : (s : Cocone F) → t.pt ⟶ s.pt
h : ∀ (s : Cocone F), G.map (desc s) = CategoryTheory.Limits.IsColimit.desc ht (G.mapCocone s)
s : Cocone F
m : t.pt ⟶ s.pt
w : ∀ (j : J), t.ι.app j ≫ m = s.ι.app j
j : J
e_1✝ : (G.obj (F.obj j) ⟶ G.obj s.pt) = ((F ⋙ G).obj j ⟶ (G.mapCocone s).pt)
⊢ G.map (t.ι.app j ≫ m) = (G.mapCocone t).ι.app j ≫ G.map m

Next tactic:
apply G.map_comp
/-- If `F` and `G` are naturally isomorphic, then `F.mapCocone c` being a colimit implies
`G.mapCocone c` is also a colimit.
-/
def mapCoconeEquiv {D : Type u₄} [Category.{v₄} D] {K : J ⥤ C} {F G : C ⥤ D} (h : F ≅ G)
    {c : Cocone K} (t : IsColimit (mapCocone F c)) : IsColimit (mapCocone G c) := by
  

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K✝ : Type u₂
inst✝² : Category.{v₂, u₂} K✝
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
F✝ : J ⥤ C
t✝ : Cocone F✝
D : Type u₄
inst✝ : Category.{v₄, u₄} D
K : J ⥤ C
F G : C ⥤ D
h : F ≅ G
c : Cocone K
t : IsColimit (F.mapCocone c)
⊢ IsColimit (G.mapCocone c)

Next tactic:
apply IsColimit.ofIsoColimit _ (precomposeWhiskerLeftMapCocone h c)