Theorem: CategoryTheory.Functor.Final.cofinal_of_colimit_comp_coyoneda_iso_pUnit
File: Mathlib/CategoryTheory/Limits/Final.lean

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⟩
state_before: C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
d : D
⊢ IsConnected (StructuredArrow d F)

tactic: apply zigzag_isConnected
state_before: C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
d : D
this : Nonempty (StructuredArrow d F)
⊢ IsConnected (StructuredArrow d F)

tactic: rintro ⟨⟨⟨⟩⟩, X₁, f₁⟩ ⟨⟨⟨⟩⟩, X₂, f₂⟩
state_before: case h
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
d : D
this : Nonempty (StructuredArrow d F)
⊢ ∀ (j₁ j₂ : StructuredArrow d F), Zigzag j₁ j₂

tactic: dsimp at *
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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₂ }

tactic: let y₁ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₁ f₁
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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₂ }

tactic: let y₂ := colimit.ι (F ⋙ coyoneda.obj (op d)) X₂ f₂
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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 d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₁ f₁
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

tactic: have e : y₁ = y₂ := by
  apply (I d).toEquiv.injective
  ext
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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 d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₂ f₂
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

tactic: have t := Types.colimit_eq.{v, v} e
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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 d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₂ f₂
e : y₁ = y₂
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

tactic: clear e y₁ y₂
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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 d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₂ f₂
e : y₁ = y₂
t : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj d.op)) { fst := X₁, snd := f₁ } { fst := X₂, snd := f₂ }
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

tactic: exact zigzag_of_eqvGen_quot_rel t
state_before: case h.mk.mk.unit.mk.mk.unit
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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₂
t : EqvGen (Types.Quot.Rel (F ⋙ coyoneda.obj d.op)) { fst := X₁, snd := f₁ } { fst := X₂, snd := f₂ }
⊢ Zigzag { left := { as := PUnit.unit }, right := X₁, hom := f₁ }
    { left := { as := PUnit.unit }, right := X₂, hom := f₂ }

tactic: have := (I d).inv PUnit.unit
state_before: C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
d : D
⊢ Nonempty (StructuredArrow d F)

tactic: obtain ⟨j, y, rfl⟩ := Limits.Types.jointly_surjective'.{v, v} this
state_before: C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
d : D
this : colimit (F ⋙ coyoneda.obj d.op)
⊢ Nonempty (StructuredArrow d F)

tactic: exact ⟨StructuredArrow.mk y⟩
state_before: case intro.intro
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
d : D
j : C
y : (F ⋙ coyoneda.obj d.op).obj j
⊢ Nonempty (StructuredArrow d F)

tactic: apply (I d).toEquiv.injective
state_before: C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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 d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₂ f₂
⊢ y₁ = y₂

tactic: ext
state_before: case a
C : Type v
inst✝² : Category C
D : Type v
inst✝¹ : Category D
F : C ⥤ D
inst✝ : Final F
I : (d : D) → colimit (F ⋙ coyoneda.obj d.op) ≅ PUnit
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 d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₁ f₁
y₂ : colimit (F ⋙ coyoneda.obj d.op) := colimit.ι (F ⋙ coyoneda.obj d.op) X₂ f₂
⊢ ↑(I d).toEquiv y₁ = ↑(I d).toEquiv y₂