l3lab/ntp-mathlib huggingface dataset:
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    

Proof state:
case intro.a
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y : (X : C) × (d ⟶ F.obj X)
f : x.fst ⟶ y.fst
w : y.snd = (F ⋙ coyoneda.obj (op d)).map f x.snd
⊢ Zag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)

Next tactic:
left
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; 

Proof state:
case intro.a.h
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y : (X : C) × (d ⟶ F.obj X)
f : x.fst ⟶ y.fst
w : y.snd = (F ⋙ coyoneda.obj (op d)).map f x.snd
⊢ Nonempty (StructuredArrow.mk x.snd ⟶ StructuredArrow.mk y.snd)

Next tactic:
fconstructor
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    

Proof state:
case intro.a.h.val
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y : (X : C) × (d ⟶ F.obj X)
f : x.fst ⟶ y.fst
w : y.snd = (F ⋙ coyoneda.obj (op d)).map f x.snd
⊢ StructuredArrow.mk x.snd ⟶ StructuredArrow.mk y.snd

Next tactic:
exact StructuredArrow.homMk f
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  

Proof state:
case refl
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ : (X : C) × (d ⟶ F.obj X)
⊢ Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk x✝.snd)
case symm
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ y✝ : (X : C) × (d ⟶ F.obj X)
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x✝ y✝
a_ih✝ : Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk y✝.snd)
⊢ Zigzag (StructuredArrow.mk y✝.snd) (StructuredArrow.mk x✝.snd)
case trans
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ y✝ z✝ : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x✝ y✝
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y✝ z✝
a_ih✝¹ : Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk y✝.snd)
a_ih✝ : Zigzag (StructuredArrow.mk y✝.snd) (StructuredArrow.mk z✝.snd)
⊢ Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk z✝.snd)

Next tactic:
case refl => fconstructor
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ : (X : C) × (d ⟶ F.obj X)
⊢ Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk x✝.snd)

Next tactic:
case refl => fconstructor
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => 

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ : (X : C) × (d ⟶ F.obj X)
⊢ Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk x✝.snd)

Next tactic:
fconstructor
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  

Proof state:
case symm
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ y✝ : (X : C) × (d ⟶ F.obj X)
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x✝ y✝
a_ih✝ : Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk y✝.snd)
⊢ Zigzag (StructuredArrow.mk y✝.snd) (StructuredArrow.mk x✝.snd)
case trans
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ y✝ z✝ : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x✝ y✝
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y✝ z✝
a_ih✝¹ : Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk y✝.snd)
a_ih✝ : Zigzag (StructuredArrow.mk y✝.snd) (StructuredArrow.mk z✝.snd)
⊢ Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk z✝.snd)

Next tactic:
case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y : (X : C) × (d ⟶ F.obj X)
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
ih : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
⊢ Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk x.snd)

Next tactic:
case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y : (X : C) × (d ⟶ F.obj X)
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
ih : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
⊢ Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk x.snd)

Next tactic:
apply zigzag_symmetric
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    apply zigzag_symmetric
    

Proof state:
case a
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y : (X : C) × (d ⟶ F.obj X)
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
ih : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
⊢ Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)

Next tactic:
exact ih
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
  

Proof state:
case trans
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x✝ y✝ z✝ : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x✝ y✝
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y✝ z✝
a_ih✝¹ : Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk y✝.snd)
a_ih✝ : Zigzag (StructuredArrow.mk y✝.snd) (StructuredArrow.mk z✝.snd)
⊢ Zigzag (StructuredArrow.mk x✝.snd) (StructuredArrow.mk z✝.snd)

Next tactic:
case trans x y z _ _ ih₁ ih₂ =>
    apply Relation.ReflTransGen.trans
    exact ih₁; exact ih₂
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
  

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y z : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y z
ih₁ : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
ih₂ : Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)
⊢ Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk z.snd)

Next tactic:
case trans x y z _ _ ih₁ ih₂ =>
    apply Relation.ReflTransGen.trans
    exact ih₁; exact ih₂
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
  case trans x y z _ _ ih₁ ih₂ =>
    

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y z : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y z
ih₁ : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
ih₂ : Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)
⊢ Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk z.snd)

Next tactic:
apply Relation.ReflTransGen.trans
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
  case trans x y z _ _ ih₁ ih₂ =>
    apply Relation.ReflTransGen.trans
    

Proof state:
case hab
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y z : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y z
ih₁ : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
ih₂ : Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)
⊢ Relation.ReflTransGen Zag (StructuredArrow.mk x.snd) ?b
case hbc
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y z : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y z
ih₁ : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
ih₂ : Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)
⊢ Relation.ReflTransGen Zag ?b (StructuredArrow.mk z.snd)
case b
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y z : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y z
ih₁ : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
ih₂ : Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)
⊢ StructuredArrow d F

Next tactic:
exact ih₁
theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X}
    (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) :
    Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by
  induction t
  case rel x y r =>
    obtain ⟨f, w⟩ := r
    fconstructor
    swap; fconstructor
    left; fconstructor
    exact StructuredArrow.homMk f
  case refl => fconstructor
  case symm x y _ ih =>
    apply zigzag_symmetric
    exact ih
  case trans x y z _ _ ih₁ ih₂ =>
    apply Relation.ReflTransGen.trans
    exact ih₁; 

Proof state:
case hbc
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F✝ F : C ⥤ D
d : D
f₁ f₂ x y z : (X : C) × (d ⟶ F.obj X)
a✝¹ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) x y
a✝ : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj (op d))) y z
ih₁ : Zigzag (StructuredArrow.mk x.snd) (StructuredArrow.mk y.snd)
ih₂ : Zigzag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)
⊢ Relation.ReflTransGen Zag (StructuredArrow.mk y.snd) (StructuredArrow.mk z.snd)

Next tactic:
exact ih₂
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
⊢ IsConnected (StructuredArrow d F)

Next tactic:
have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
⊢ Nonempty (StructuredArrow d F)

Next tactic:
have := (I d).inv PUnit.unit
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : colimit (F ⋙ coyoneda.obj (op d))
⊢ Nonempty (StructuredArrow d F)

Next tactic:
obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      

Proof state:
case intro.intro
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
j : C
y : (F ⋙ coyoneda.obj (op d)).obj j
⊢ Nonempty (StructuredArrow d F)

Next tactic:
exact ⟨StructuredArrow.mk y⟩
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
    

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : Nonempty (StructuredArrow d F)
⊢ IsConnected (StructuredArrow d F)

Next tactic:
apply zigzag_isConnected
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
    apply zigzag_isConnected
    

Proof state:
case h
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : Nonempty (StructuredArrow d F)
⊢ ∀ (j₁ j₂ : StructuredArrow d F), Zigzag j₁ j₂

Next tactic:
rintro ⟨⟨⟨⟩⟩, X₁, f₁⟩ ⟨⟨⟨⟩⟩, X₂, f₂⟩
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
    apply zigzag_isConnected
    rintro ⟨⟨⟨⟩⟩, X₁, f₁⟩ ⟨⟨⟨⟩⟩, X₂, f₂⟩
    

Proof state:
case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : Nonempty (StructuredArrow d F)
X₁ : C
f₁ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₁
X₂ : C
f₂ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₂
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

Next tactic:
let y₁ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
    apply zigzag_isConnected
    rintro ⟨⟨⟨⟩⟩, X₁, f₁⟩ ⟨⟨⟨⟩⟩, X₂, f₂⟩
    let y₁ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
    

Proof state:
case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : Nonempty (StructuredArrow d F)
X₁ : C
f₁ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₁
X₂ : C
f₂ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₂
y₁ : colimit (F ⋙ coyoneda.obj (op d)) := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

Next tactic:
let y₂ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₂ f₂
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
    apply zigzag_isConnected
    rintro ⟨⟨⟨⟩⟩, X₁, f₁⟩ ⟨⟨⟨⟩⟩, X₂, f₂⟩
    let y₁ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
    let y₂ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₂ f₂
    

Proof state:
case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : Nonempty (StructuredArrow d F)
X₁ : C
f₁ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₁
X₂ : C
f₂ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₂
y₁ : colimit (F ⋙ coyoneda.obj (op d)) := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj (op d)) := colimit.ι (F ⋙ coyoneda.obj (op d)) X₂ f₂
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

Next tactic:
have e : y₁ = y₂ := by
      apply (I d).toEquiv.injective
      ext
/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal.
-/
theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit
    (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F :=
  ⟨fun d => by
    have : Nonempty (StructuredArrow d F) := by
      have := (I d).inv PUnit.unit
      obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
      exact ⟨StructuredArrow.mk y⟩
    apply zigzag_isConnected
    rintro ⟨⟨⟨⟩⟩, X₁, f₁⟩ ⟨⟨⟨⟩⟩, X₂, f₂⟩
    let y₁ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
    let y₂ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₂ f₂
    have e : y₁ = y₂ := by
      

Proof state:
C : Type v
inst✝¹ : Category.{v, v} C
D : Type u₁
inst✝ : Category.{v, u₁} D
F : C ⥤ D
I : (d : D) → colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit.{v + 1}
d : D
this : Nonempty (StructuredArrow d F)
X₁ : C
f₁ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₁
X₂ : C
f₂ : (fromPUnit d).obj { as := PUnit.unit } ⟶ F.obj X₂
y₁ : colimit (F ⋙ coyoneda.obj (op d)) := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj (op d)) := colimit.ι (F ⋙ coyoneda.obj (op d)) X₂ f₂
⊢ y₁ = y₂

Next tactic:
apply (I d).toEquiv.injective