l3lab/ntp-mathlib huggingface dataset:
theorem binaryCofan_isColimit_iff {X Y : Type u} (c : BinaryCofan X Y) :
    Nonempty (IsColimit c) ↔
      Injective c.inl ∧ Injective c.inr ∧ IsCompl (Set.range c.inl) (Set.range c.inr) := by
  classical
    constructor
    · rintro ⟨h⟩
      rw [← show _ = c.inl from
          h.comp_coconePointUniqueUpToIso_inv (binaryCoproductColimit X Y) ⟨WalkingPair.left⟩,
        ← show _ = c.inr from
          h.comp_coconePointUniqueUpToIso_inv (binaryCoproductColimit X Y) ⟨WalkingPair.right⟩]
      dsimp [binaryCoproductCocone]
      refine'
        ⟨(h.coconePointUniqueUpToIso (binaryCoproductColimit X Y)).symm.toEquiv.injective.comp
            Sum.inl_injective,
          (h.coconePointUniqueUpToIso (binaryCoproductColimit X Y)).symm.toEquiv.injective.comp
            Sum.inr_injective, _⟩
      erw [Set.range_comp, ← eq_compl_iff_isCompl, Set.range_comp _ Sum.inr, ←
        Set.image_compl_eq
          (h.coconePointUniqueUpToIso (binaryCoproductColimit X Y)).symm.toEquiv.bijective]
      simp
    · rintro ⟨h₁, h₂, h₃⟩
      have : ∀ x, x ∈ Set.range c.inl ∨ x ∈ Set.range c.inr := by
        rw [eq_compl_iff_isCompl.mpr h₃.symm]
        exact fun _ => or_not
      refine' ⟨BinaryCofan.IsColimit.mk _ _ _ _ _⟩
      · intro T f g x
        exact
          if h : x ∈ Set.range c.inl then f ((Equiv.ofInjective _ h₁).symm ⟨x, h⟩)
          else g ((Equiv.ofInjective _ h₂).symm ⟨x, (this x).resolve_left h⟩)
      · intro T f g
        funext x
        dsimp
        simp [h₁.eq_iff]
      · intro T f g
        funext x
        dsimp
        simp only [Set.mem_range, Equiv.ofInjective_symm_apply,
          dite_eq_right_iff, forall_exists_index]
        intro y e
        have : c.inr x ∈ Set.range c.inl ⊓ Set.range c.inr := ⟨⟨_, e⟩, ⟨_, rfl⟩⟩
        rw [disjoint_iff.mp h₃.1] at this
        exact this.elim
      · rintro T _ _ m rfl rfl
        funext x
        dsimp
        split_ifs <;> 

Proof state:
case pos
X Y : Type u
c : BinaryCofan X Y
h₁ : Injective (BinaryCofan.inl c)
h₂ : Injective (BinaryCofan.inr c)
h₃ : IsCompl (Set.range (BinaryCofan.inl c)) (Set.range (BinaryCofan.inr c))
this :
  ∀ (x : ((Functor.const (Discrete WalkingPair)).obj c.pt).obj { as := left }),
    x ∈ Set.range (BinaryCofan.inl c) ∨ x ∈ Set.range (BinaryCofan.inr c)
T : Type u
m : c.pt ⟶ T
x : c.pt
h✝ : x ∈ Set.range (BinaryCofan.inl c)
⊢ m x = m (BinaryCofan.inl c ((Equiv.ofInjective (BinaryCofan.inl c) h₁).symm { val := x, property := h✝ }))

Next tactic:
exact congr_arg _ (Equiv.apply_ofInjective_symm _ ⟨_, _⟩).symm
theorem binaryCofan_isColimit_iff {X Y : Type u} (c : BinaryCofan X Y) :
    Nonempty (IsColimit c) ↔
      Injective c.inl ∧ Injective c.inr ∧ IsCompl (Set.range c.inl) (Set.range c.inr) := by
  classical
    constructor
    · rintro ⟨h⟩
      rw [← show _ = c.inl from
          h.comp_coconePointUniqueUpToIso_inv (binaryCoproductColimit X Y) ⟨WalkingPair.left⟩,
        ← show _ = c.inr from
          h.comp_coconePointUniqueUpToIso_inv (binaryCoproductColimit X Y) ⟨WalkingPair.right⟩]
      dsimp [binaryCoproductCocone]
      refine'
        ⟨(h.coconePointUniqueUpToIso (binaryCoproductColimit X Y)).symm.toEquiv.injective.comp
            Sum.inl_injective,
          (h.coconePointUniqueUpToIso (binaryCoproductColimit X Y)).symm.toEquiv.injective.comp
            Sum.inr_injective, _⟩
      erw [Set.range_comp, ← eq_compl_iff_isCompl, Set.range_comp _ Sum.inr, ←
        Set.image_compl_eq
          (h.coconePointUniqueUpToIso (binaryCoproductColimit X Y)).symm.toEquiv.bijective]
      simp
    · rintro ⟨h₁, h₂, h₃⟩
      have : ∀ x, x ∈ Set.range c.inl ∨ x ∈ Set.range c.inr := by
        rw [eq_compl_iff_isCompl.mpr h₃.symm]
        exact fun _ => or_not
      refine' ⟨BinaryCofan.IsColimit.mk _ _ _ _ _⟩
      · intro T f g x
        exact
          if h : x ∈ Set.range c.inl then f ((Equiv.ofInjective _ h₁).symm ⟨x, h⟩)
          else g ((Equiv.ofInjective _ h₂).symm ⟨x, (this x).resolve_left h⟩)
      · intro T f g
        funext x
        dsimp
        simp [h₁.eq_iff]
      · intro T f g
        funext x
        dsimp
        simp only [Set.mem_range, Equiv.ofInjective_symm_apply,
          dite_eq_right_iff, forall_exists_index]
        intro y e
        have : c.inr x ∈ Set.range c.inl ⊓ Set.range c.inr := ⟨⟨_, e⟩, ⟨_, rfl⟩⟩
        rw [disjoint_iff.mp h₃.1] at this
        exact this.elim
      · rintro T _ _ m rfl rfl
        funext x
        dsimp
        split_ifs <;> 

Proof state:
case neg
X Y : Type u
c : BinaryCofan X Y
h₁ : Injective (BinaryCofan.inl c)
h₂ : Injective (BinaryCofan.inr c)
h₃ : IsCompl (Set.range (BinaryCofan.inl c)) (Set.range (BinaryCofan.inr c))
this :
  ∀ (x : ((Functor.const (Discrete WalkingPair)).obj c.pt).obj { as := left }),
    x ∈ Set.range (BinaryCofan.inl c) ∨ x ∈ Set.range (BinaryCofan.inr c)
T : Type u
m : c.pt ⟶ T
x : c.pt
h✝ : x ∉ Set.range (BinaryCofan.inl c)
⊢ m x =
    m
      (BinaryCofan.inr c
        ((Equiv.ofInjective (BinaryCofan.inr c) h₂).symm
          { val := x, property := (_ : x ∈ Set.range (BinaryCofan.inr c)) }))

Next tactic:
exact congr_arg _ (Equiv.apply_ofInjective_symm _ ⟨_, _⟩).symm
/-- Any monomorphism in `Type` is a coproduct injection. -/
noncomputable def isCoprodOfMono {X Y : Type u} (f : X ⟶ Y) [Mono f] :
    IsColimit (BinaryCofan.mk f (Subtype.val : ↑(Set.range f)ᶜ → Y)) := by
  

Proof state:
X Y : Type u
f : X ⟶ Y
inst✝ : Mono f
⊢ IsColimit (BinaryCofan.mk f Subtype.val)

Next tactic:
apply Nonempty.some
/-- Any monomorphism in `Type` is a coproduct injection. -/
noncomputable def isCoprodOfMono {X Y : Type u} (f : X ⟶ Y) [Mono f] :
    IsColimit (BinaryCofan.mk f (Subtype.val : ↑(Set.range f)ᶜ → Y)) := by
  apply Nonempty.some
  

Proof state:
case h
X Y : Type u
f : X ⟶ Y
inst✝ : Mono f
⊢ Nonempty (IsColimit (BinaryCofan.mk f Subtype.val))

Next tactic:
rw [binaryCofan_isColimit_iff]
/-- Any monomorphism in `Type` is a coproduct injection. -/
noncomputable def isCoprodOfMono {X Y : Type u} (f : X ⟶ Y) [Mono f] :
    IsColimit (BinaryCofan.mk f (Subtype.val : ↑(Set.range f)ᶜ → Y)) := by
  apply Nonempty.some
  rw [binaryCofan_isColimit_iff]
  

Proof state:
case h
X Y : Type u
f : X ⟶ Y
inst✝ : Mono f
⊢ Injective (BinaryCofan.inl (BinaryCofan.mk f Subtype.val)) ∧
    Injective (BinaryCofan.inr (BinaryCofan.mk f Subtype.val)) ∧
      IsCompl (Set.range (BinaryCofan.inl (BinaryCofan.mk f Subtype.val)))
        (Set.range (BinaryCofan.inr (BinaryCofan.mk f Subtype.val)))

Next tactic:
refine' ⟨(mono_iff_injective f).mp inferInstance, Subtype.val_injective, _⟩
/-- Any monomorphism in `Type` is a coproduct injection. -/
noncomputable def isCoprodOfMono {X Y : Type u} (f : X ⟶ Y) [Mono f] :
    IsColimit (BinaryCofan.mk f (Subtype.val : ↑(Set.range f)ᶜ → Y)) := by
  apply Nonempty.some
  rw [binaryCofan_isColimit_iff]
  refine' ⟨(mono_iff_injective f).mp inferInstance, Subtype.val_injective, _⟩
  

Proof state:
case h
X Y : Type u
f : X ⟶ Y
inst✝ : Mono f
⊢ IsCompl (Set.range (BinaryCofan.inl (BinaryCofan.mk f Subtype.val)))
    (Set.range (BinaryCofan.inr (BinaryCofan.mk f Subtype.val)))

Next tactic:
symm
/-- Any monomorphism in `Type` is a coproduct injection. -/
noncomputable def isCoprodOfMono {X Y : Type u} (f : X ⟶ Y) [Mono f] :
    IsColimit (BinaryCofan.mk f (Subtype.val : ↑(Set.range f)ᶜ → Y)) := by
  apply Nonempty.some
  rw [binaryCofan_isColimit_iff]
  refine' ⟨(mono_iff_injective f).mp inferInstance, Subtype.val_injective, _⟩
  symm
  

Proof state:
case h
X Y : Type u
f : X ⟶ Y
inst✝ : Mono f
⊢ IsCompl (Set.range (BinaryCofan.inr (BinaryCofan.mk f Subtype.val)))
    (Set.range (BinaryCofan.inl (BinaryCofan.mk f Subtype.val)))

Next tactic:
rw [← eq_compl_iff_isCompl]
/-- Any monomorphism in `Type` is a coproduct injection. -/
noncomputable def isCoprodOfMono {X Y : Type u} (f : X ⟶ Y) [Mono f] :
    IsColimit (BinaryCofan.mk f (Subtype.val : ↑(Set.range f)ᶜ → Y)) := by
  apply Nonempty.some
  rw [binaryCofan_isColimit_iff]
  refine' ⟨(mono_iff_injective f).mp inferInstance, Subtype.val_injective, _⟩
  symm
  rw [← eq_compl_iff_isCompl]
  

Proof state:
case h
X Y : Type u
f : X ⟶ Y
inst✝ : Mono f
⊢ Set.range (BinaryCofan.inr (BinaryCofan.mk f Subtype.val)) =
    (Set.range (BinaryCofan.inl (BinaryCofan.mk f Subtype.val)))ᶜ

Next tactic:
exact Subtype.range_val
/--
A variant of `productLimitCone` using a `Small` hypothesis rather than a function to `TypeMax`.
-/
noncomputable def productLimitCone :
    Limits.LimitCone (Discrete.functor F) where
  cone :=
    { pt := Shrink (∀ j, F j)
      π := Discrete.natTrans (fun ⟨j⟩ f => (equivShrink (∀ j, F j)).symm f j) }
  isLimit :=
    have : Small.{u} (∀ j, F j) := inferInstance
    { lift := fun s x => (equivShrink _) (fun j => s.π.app ⟨j⟩ x)
      uniq := fun s m w => funext fun x => Shrink.ext <| funext fun j => by
        

Proof state:
J : Type v
F : J → Type u
inst✝ : Small.{u, v} J
this : Small.{u, max u v} ((j : J) → F j)
s : Cone (Discrete.functor F)
m :
  s.pt ⟶
    { pt := Shrink.{u, max u v} ((j : J) → F j),
        π :=
          Discrete.natTrans fun x f =>
            match x, f with
            | { as := j }, f => (equivShrink ((j : J) → F j)).symm f j }.pt
w :
  ∀ (j : Discrete J),
    m ≫
        { pt := Shrink.{u, max u v} ((j : J) → F j),
                π :=
                  Discrete.natTrans fun x f =>
                    match x, f with
                    | { as := j }, f => (equivShrink ((j : J) → F j)).symm f j }.π.app
          j =
      s.π.app j
x : s.pt
j : J
⊢ (equivShrink ((j : J) → F j)).symm (m x) j =
    (equivShrink ((j : J) → F j)).symm ((fun s x => (equivShrink ((j : J) → F j)) fun j => s.π.app { as := j } x) s x) j

Next tactic:
simpa using (congr_fun (w ⟨j⟩) x : _)
/-- The category of types has `Σ j, f j` as the coproduct of a type family `f : J → Type`.
-/
def coproductColimitCocone {J : Type v} (F : J → TypeMax.{v, u}) :
    Limits.ColimitCocone (Discrete.functor F) where
  cocone :=
    { pt := Σj, F j
      ι := Discrete.natTrans (fun ⟨j⟩ x => ⟨j, x⟩)}
  isColimit :=
    { desc := fun s x => s.ι.app ⟨x.1⟩ x.2
      uniq := fun s m w => by
        

Proof state:
J : Type v
F : J → TypeMax
s : Cocone (Discrete.functor F)
m :
  { pt := (j : J) × F j,
        ι :=
          Discrete.natTrans fun x x_1 =>
            match x, x_1 with
            | { as := j }, x => { fst := j, snd := x } }.pt ⟶
    s.pt
w :
  ∀ (j : Discrete J),
    { pt := (j : J) × F j,
                ι :=
                  Discrete.natTrans fun x x_1 =>
                    match x, x_1 with
                    | { as := j }, x => { fst := j, snd := x } }.ι.app
          j ≫
        m =
      s.ι.app j
⊢ m = (fun s x => s.ι.app { as := x.fst } x.snd) s

Next tactic:
funext ⟨j, x⟩
/-- The category of types has `Σ j, f j` as the coproduct of a type family `f : J → Type`.
-/
def coproductColimitCocone {J : Type v} (F : J → TypeMax.{v, u}) :
    Limits.ColimitCocone (Discrete.functor F) where
  cocone :=
    { pt := Σj, F j
      ι := Discrete.natTrans (fun ⟨j⟩ x => ⟨j, x⟩)}
  isColimit :=
    { desc := fun s x => s.ι.app ⟨x.1⟩ x.2
      uniq := fun s m w => by
        funext ⟨j, x⟩
        

Proof state:
case h
J : Type v
F : J → TypeMax
s : Cocone (Discrete.functor F)
m :
  { pt := (j : J) × F j,
        ι :=
          Discrete.natTrans fun x x_1 =>
            match x, x_1 with
            | { as := j }, x => { fst := j, snd := x } }.pt ⟶
    s.pt
w :
  ∀ (j : Discrete J),
    { pt := (j : J) × F j,
                ι :=
                  Discrete.natTrans fun x x_1 =>
                    match x, x_1 with
                    | { as := j }, x => { fst := j, snd := x } }.ι.app
          j ≫
        m =
      s.ι.app j
j : J
x : F j
⊢ m { fst := j, snd := x } = (fun s x => s.ι.app { as := x.fst } x.snd) s { fst := j, snd := x }

Next tactic:
exact congr_fun (w ⟨j⟩) x
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
⊢ { l //
    l ≫ Fork.ι (Fork.ofι f w) = Fork.ι s ∧
      ∀
        {m :
          ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
            ((Functor.const WalkingParallelPair).obj (Fork.ofι f w).pt).obj WalkingParallelPair.zero},
        m ≫ Fork.ι (Fork.ofι f w) = Fork.ι s → m = l }

Next tactic:
refine' ⟨fun i => _, _, _⟩
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · 

Proof state:
case refine'_1
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
i : ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero
⊢ ((Functor.const WalkingParallelPair).obj (Fork.ofι f w).pt).obj WalkingParallelPair.zero

Next tactic:
apply Classical.choose (t (s.ι i) _)
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · apply Classical.choose (t (s.ι i) _)
      

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
i : ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero
⊢ g (Fork.ι s i) = h (Fork.ι s i)

Next tactic:
apply congr_fun s.condition i
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · apply Classical.choose (t (s.ι i) _)
      apply congr_fun s.condition i
    · 

Proof state:
case refine'_2
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
⊢ (fun i => Classical.choose (_ : ∃! x, f x = Fork.ι s i)) ≫ Fork.ι (Fork.ofι f w) = Fork.ι s

Next tactic:
funext i
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · apply Classical.choose (t (s.ι i) _)
      apply congr_fun s.condition i
    · funext i
      

Proof state:
case refine'_2.h
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
i : ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero
⊢ ((fun i => Classical.choose (_ : ∃! x, f x = Fork.ι s i)) ≫ Fork.ι (Fork.ofι f w)) i = Fork.ι s i

Next tactic:
exact (Classical.choose_spec (t (s.ι i) (congr_fun s.condition i))).1
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · apply Classical.choose (t (s.ι i) _)
      apply congr_fun s.condition i
    · funext i
      exact (Classical.choose_spec (t (s.ι i) (congr_fun s.condition i))).1
    · 

Proof state:
case refine'_3
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
⊢ ∀
    {m :
      ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
        ((Functor.const WalkingParallelPair).obj (Fork.ofι f w).pt).obj WalkingParallelPair.zero},
    m ≫ Fork.ι (Fork.ofι f w) = Fork.ι s → m = fun i => Classical.choose (_ : ∃! x, f x = Fork.ι s i)

Next tactic:
intro m hm
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · apply Classical.choose (t (s.ι i) _)
      apply congr_fun s.condition i
    · funext i
      exact (Classical.choose_spec (t (s.ι i) (congr_fun s.condition i))).1
    · intro m hm
      

Proof state:
case refine'_3
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
m :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (Fork.ofι f w).pt).obj WalkingParallelPair.zero
hm : m ≫ Fork.ι (Fork.ofι f w) = Fork.ι s
⊢ m = fun i => Classical.choose (_ : ∃! x, f x = Fork.ι s i)

Next tactic:
funext i
/--
Show the given fork in `Type u` is an equalizer given that any element in the "difference kernel"
comes from `X`.
The converse of `unique_of_type_equalizer`.
-/
noncomputable def typeEqualizerOfUnique (t : ∀ y : Y, g y = h y → ∃! x : X, f x = y) :
    IsLimit (Fork.ofι _ w) :=
  Fork.IsLimit.mk' _ fun s => by
    refine' ⟨fun i => _, _, _⟩
    · apply Classical.choose (t (s.ι i) _)
      apply congr_fun s.condition i
    · funext i
      exact (Classical.choose_spec (t (s.ι i) (congr_fun s.condition i))).1
    · intro m hm
      funext i
      

Proof state:
case refine'_3.h
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : ∀ (y : Y), g y = h y → ∃! x, f x = y
s : Fork g h
m :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (Fork.ofι f w).pt).obj WalkingParallelPair.zero
hm : m ≫ Fork.ι (Fork.ofι f w) = Fork.ι s
i : ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero
⊢ m i = Classical.choose (_ : ∃! x, f x = Fork.ι s i)

Next tactic:
exact (Classical.choose_spec (t (s.ι i) (congr_fun s.condition i))).2 _ (congr_fun hm i)
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
⊢ ∃! x, f x = y

Next tactic:
let y' : PUnit ⟶ Y := fun _ => y
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
⊢ ∃! x, f x = y

Next tactic:
have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
hy' : y' ≫ g = y' ≫ h
⊢ ∃! x, f x = y

Next tactic:
refine' ⟨(Fork.IsLimit.lift' t _ hy').1 ⟨⟩, congr_fun (Fork.IsLimit.lift' t y' _).2 ⟨⟩, _⟩
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
  refine' ⟨(Fork.IsLimit.lift' t _ hy').1 ⟨⟩, congr_fun (Fork.IsLimit.lift' t y' _).2 ⟨⟩, _⟩
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
hy' : y' ≫ g = y' ≫ h
⊢ ∀ (y_1 : X), (fun x => f x = y) y_1 → y_1 = ↑(Fork.IsLimit.lift' t y' hy') PUnit.unit

Next tactic:
intro x' hx'
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
  refine' ⟨(Fork.IsLimit.lift' t _ hy').1 ⟨⟩, congr_fun (Fork.IsLimit.lift' t y' _).2 ⟨⟩, _⟩
  intro x' hx'
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
hy' : y' ≫ g = y' ≫ h
x' : X
hx' : f x' = y
⊢ x' = ↑(Fork.IsLimit.lift' t y' hy') PUnit.unit

Next tactic:
suffices (fun _ : PUnit => x') = (Fork.IsLimit.lift' t y' hy').1 by
    rw [← this]
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
  refine' ⟨(Fork.IsLimit.lift' t _ hy').1 ⟨⟩, congr_fun (Fork.IsLimit.lift' t y' _).2 ⟨⟩, _⟩
  intro x' hx'
  suffices (fun _ : PUnit => x') = (Fork.IsLimit.lift' t y' hy').1 by
    

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
hy' : y' ≫ g = y' ≫ h
x' : X
hx' : f x' = y
this : (fun x => x') = ↑(Fork.IsLimit.lift' t y' hy')
⊢ x' = ↑(Fork.IsLimit.lift' t y' hy') PUnit.unit

Next tactic:
rw [← this]
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
  refine' ⟨(Fork.IsLimit.lift' t _ hy').1 ⟨⟩, congr_fun (Fork.IsLimit.lift' t y' _).2 ⟨⟩, _⟩
  intro x' hx'
  suffices (fun _ : PUnit => x') = (Fork.IsLimit.lift' t y' hy').1 by
    rw [← this]
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
hy' : y' ≫ g = y' ≫ h
x' : X
hx' : f x' = y
⊢ (fun x => x') = ↑(Fork.IsLimit.lift' t y' hy')

Next tactic:
apply Fork.IsLimit.hom_ext t
/-- The converse of `type_equalizer_of_unique`. -/
theorem unique_of_type_equalizer (t : IsLimit (Fork.ofι _ w)) (y : Y) (hy : g y = h y) :
    ∃! x : X, f x = y := by
  let y' : PUnit ⟶ Y := fun _ => y
  have hy' : y' ≫ g = y' ≫ h := funext fun _ => hy
  refine' ⟨(Fork.IsLimit.lift' t _ hy').1 ⟨⟩, congr_fun (Fork.IsLimit.lift' t y' _).2 ⟨⟩, _⟩
  intro x' hx'
  suffices (fun _ : PUnit => x') = (Fork.IsLimit.lift' t y' hy').1 by
    rw [← this]
  apply Fork.IsLimit.hom_ext t
  

Proof state:
X Y Z : Type u
f : X ⟶ Y
g h : Y ⟶ Z
w : f ≫ g = f ≫ h
t : IsLimit (Fork.ofι f w)
y : Y
hy : g y = h y
y' : PUnit.{u + 1} ⟶ Y := fun x => y
hy' : y' ≫ g = y' ≫ h
x' : X
hx' : f x' = y
⊢ (fun x => x') ≫ Fork.ι (Fork.ofι f w) = ↑(Fork.IsLimit.lift' t y' hy') ≫ Fork.ι (Fork.ofι f w)

Next tactic:
funext ⟨⟩