l3lab/ntp-mathlib huggingface dataset:
/-- Every fork is isomorphic to one of the form `Fork.of_ι _ _`. -/
def Fork.isoForkOfι (c : Fork f g) : c ≅ Fork.ofι c.ι c.condition :=
  Fork.ext (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Fork f g
⊢ c.pt ≅ (ofι (ι c) (_ : ι c ≫ f = ι c ≫ g)).pt

Next tactic:
simp only [Fork.ofι_pt, Functor.const_obj_obj]
/-- Every fork is isomorphic to one of the form `Fork.of_ι _ _`. -/
def Fork.isoForkOfι (c : Fork f g) : c ≅ Fork.ofι c.ι c.condition :=
  Fork.ext (by simp only [Fork.ofι_pt, Functor.const_obj_obj]; 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Fork f g
⊢ c.pt ≅ c.pt

Next tactic:
rfl
/-- Every fork is isomorphic to one of the form `Fork.of_ι _ _`. -/
def Fork.isoForkOfι (c : Fork f g) : c ≅ Fork.ofι c.ι c.condition :=
  Fork.ext (by simp only [Fork.ofι_pt, Functor.const_obj_obj]; rfl) (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Fork f g
⊢ (_root_.id (Iso.refl c.pt)).hom ≫ ι (ofι (ι c) (_ : ι c ≫ f = ι c ≫ g)) = ι c

Next tactic:
simp
/-- Helper function for constructing morphisms between coequalizer coforks.
-/
@[simps]
def Cofork.mkHom {s t : Cofork f g} (k : s.pt ⟶ t.pt) (w : s.π ≫ k = t.π) : s ⟶ t where
  hom := k
  w := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s t : Cofork f g
k : s.pt ⟶ t.pt
w : π s ≫ k = π t
⊢ ∀ (j : WalkingParallelPair), s.ι.app j ≫ k = t.ι.app j

Next tactic:
rintro ⟨_ | _⟩
/-- Helper function for constructing morphisms between coequalizer coforks.
-/
@[simps]
def Cofork.mkHom {s t : Cofork f g} (k : s.pt ⟶ t.pt) (w : s.π ≫ k = t.π) : s ⟶ t where
  hom := k
  w := by
    rintro ⟨_ | _⟩
    · 

Proof state:
case zero
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s t : Cofork f g
k : s.pt ⟶ t.pt
w : π s ≫ k = π t
⊢ s.ι.app zero ≫ k = t.ι.app zero

Next tactic:
simp [Cofork.app_zero_eq_comp_π_left, w]
/-- Helper function for constructing morphisms between coequalizer coforks.
-/
@[simps]
def Cofork.mkHom {s t : Cofork f g} (k : s.pt ⟶ t.pt) (w : s.π ≫ k = t.π) : s ⟶ t where
  hom := k
  w := by
    rintro ⟨_ | _⟩
    · simp [Cofork.app_zero_eq_comp_π_left, w]
    · 

Proof state:
case one
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s t : Cofork f g
k : s.pt ⟶ t.pt
w : π s ≫ k = π t
⊢ s.ι.app one ≫ k = t.ι.app one

Next tactic:
exact w
@[reassoc (attr := simp)]
theorem Fork.hom_comp_ι {s t : Fork f g} (f : s ⟶ t) : f.hom ≫ t.ι = s.ι := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
s t : Fork f✝ g
f : s ⟶ t
⊢ f.hom ≫ ι t = ι s

Next tactic:
cases s
@[reassoc (attr := simp)]
theorem Fork.hom_comp_ι {s t : Fork f g} (f : s ⟶ t) : f.hom ≫ t.ι = s.ι := by
  cases s; 

Proof state:
case mk
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
t : Fork f✝ g
pt✝ : C
π✝ : (Functor.const WalkingParallelPair).obj pt✝ ⟶ parallelPair f✝ g
f : { pt := pt✝, π := π✝ } ⟶ t
⊢ f.hom ≫ ι t = ι { pt := pt✝, π := π✝ }

Next tactic:
cases t
@[reassoc (attr := simp)]
theorem Fork.hom_comp_ι {s t : Fork f g} (f : s ⟶ t) : f.hom ≫ t.ι = s.ι := by
  cases s; cases t; 

Proof state:
case mk.mk
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
pt✝¹ : C
π✝¹ : (Functor.const WalkingParallelPair).obj pt✝¹ ⟶ parallelPair f✝ g
pt✝ : C
π✝ : (Functor.const WalkingParallelPair).obj pt✝ ⟶ parallelPair f✝ g
f : { pt := pt✝¹, π := π✝¹ } ⟶ { pt := pt✝, π := π✝ }
⊢ f.hom ≫ ι { pt := pt✝, π := π✝ } = ι { pt := pt✝¹, π := π✝¹ }

Next tactic:
cases f
@[reassoc (attr := simp)]
theorem Fork.hom_comp_ι {s t : Fork f g} (f : s ⟶ t) : f.hom ≫ t.ι = s.ι := by
  cases s; cases t; cases f; 

Proof state:
case mk.mk.mk
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
pt✝¹ : C
π✝¹ : (Functor.const WalkingParallelPair).obj pt✝¹ ⟶ parallelPair f g
pt✝ : C
π✝ : (Functor.const WalkingParallelPair).obj pt✝ ⟶ parallelPair f g
hom✝ : { pt := pt✝¹, π := π✝¹ }.pt ⟶ { pt := pt✝, π := π✝ }.pt
w✝ : ∀ (j : WalkingParallelPair), hom✝ ≫ { pt := pt✝, π := π✝ }.π.app j = { pt := pt✝¹, π := π✝¹ }.π.app j
⊢ (ConeMorphism.mk hom✝).hom ≫ ι { pt := pt✝, π := π✝ } = ι { pt := pt✝¹, π := π✝¹ }

Next tactic:
aesop
@[reassoc (attr := simp)]
theorem Fork.π_comp_hom {s t : Cofork f g} (f : s ⟶ t) : s.π ≫ f.hom = t.π := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
s t : Cofork f✝ g
f : s ⟶ t
⊢ Cofork.π s ≫ f.hom = Cofork.π t

Next tactic:
cases s
@[reassoc (attr := simp)]
theorem Fork.π_comp_hom {s t : Cofork f g} (f : s ⟶ t) : s.π ≫ f.hom = t.π := by
  cases s; 

Proof state:
case mk
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
t : Cofork f✝ g
pt✝ : C
ι✝ : parallelPair f✝ g ⟶ (Functor.const WalkingParallelPair).obj pt✝
f : { pt := pt✝, ι := ι✝ } ⟶ t
⊢ Cofork.π { pt := pt✝, ι := ι✝ } ≫ f.hom = Cofork.π t

Next tactic:
cases t
@[reassoc (attr := simp)]
theorem Fork.π_comp_hom {s t : Cofork f g} (f : s ⟶ t) : s.π ≫ f.hom = t.π := by
  cases s; cases t; 

Proof state:
case mk.mk
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
pt✝¹ : C
ι✝¹ : parallelPair f✝ g ⟶ (Functor.const WalkingParallelPair).obj pt✝¹
pt✝ : C
ι✝ : parallelPair f✝ g ⟶ (Functor.const WalkingParallelPair).obj pt✝
f : { pt := pt✝¹, ι := ι✝¹ } ⟶ { pt := pt✝, ι := ι✝ }
⊢ Cofork.π { pt := pt✝¹, ι := ι✝¹ } ≫ f.hom = Cofork.π { pt := pt✝, ι := ι✝ }

Next tactic:
cases f
@[reassoc (attr := simp)]
theorem Fork.π_comp_hom {s t : Cofork f g} (f : s ⟶ t) : s.π ≫ f.hom = t.π := by
  cases s; cases t; cases f; 

Proof state:
case mk.mk.mk
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
pt✝¹ : C
ι✝¹ : parallelPair f g ⟶ (Functor.const WalkingParallelPair).obj pt✝¹
pt✝ : C
ι✝ : parallelPair f g ⟶ (Functor.const WalkingParallelPair).obj pt✝
hom✝ : { pt := pt✝¹, ι := ι✝¹ }.pt ⟶ { pt := pt✝, ι := ι✝ }.pt
w✝ : ∀ (j : WalkingParallelPair), { pt := pt✝¹, ι := ι✝¹ }.ι.app j ≫ hom✝ = { pt := pt✝, ι := ι✝ }.ι.app j
⊢ Cofork.π { pt := pt✝¹, ι := ι✝¹ } ≫ (CoconeMorphism.mk hom✝).hom = Cofork.π { pt := pt✝, ι := ι✝ }

Next tactic:
aesop
/-- To construct an isomorphism between coforks,
it suffices to give an isomorphism between the cocone points
and check that it commutes with the `π` morphisms.
-/
@[simps]
def Cofork.ext {s t : Cofork f g} (i : s.pt ≅ t.pt) (w : s.π ≫ i.hom = t.π := by aesop_cat) :
    s ≅ t where
  hom := Cofork.mkHom i.hom w
  inv := Cofork.mkHom i.inv (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s t : Cofork f g
i : s.pt ≅ t.pt
w : autoParam (π s ≫ i.hom = π t) _auto✝
⊢ π t ≫ i.inv = π s

Next tactic:
rw [Iso.comp_inv_eq, w]
/-- Every cofork is isomorphic to one of the form `Cofork.ofπ _ _`. -/
def Cofork.isoCoforkOfπ (c : Cofork f g) : c ≅ Cofork.ofπ c.π c.condition :=
  Cofork.ext (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Cofork f g
⊢ c.pt ≅ (ofπ (π c) (_ : f ≫ π c = g ≫ π c)).pt

Next tactic:
simp only [Cofork.ofπ_pt, Functor.const_obj_obj]
/-- Every cofork is isomorphic to one of the form `Cofork.ofπ _ _`. -/
def Cofork.isoCoforkOfπ (c : Cofork f g) : c ≅ Cofork.ofπ c.π c.condition :=
  Cofork.ext (by simp only [Cofork.ofπ_pt, Functor.const_obj_obj]; 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Cofork f g
⊢ c.pt ≅ c.pt

Next tactic:
rfl
/-- Every cofork is isomorphic to one of the form `Cofork.ofπ _ _`. -/
def Cofork.isoCoforkOfπ (c : Cofork f g) : c ≅ Cofork.ofπ c.π c.condition :=
  Cofork.ext (by simp only [Cofork.ofπ_pt, Functor.const_obj_obj]; rfl) (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Cofork f g
⊢ π c ≫ (_root_.id (Iso.refl c.pt)).hom = π (ofπ (π c) (_ : f ≫ π c = g ≫ π c))

Next tactic:
dsimp
/-- Every cofork is isomorphic to one of the form `Cofork.ofπ _ _`. -/
def Cofork.isoCoforkOfπ (c : Cofork f g) : c ≅ Cofork.ofπ c.π c.condition :=
  Cofork.ext (by simp only [Cofork.ofπ_pt, Functor.const_obj_obj]; rfl) (by dsimp; 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Cofork f g
⊢ π c ≫ 𝟙 c.pt = π c

Next tactic:
simp
/-- The equalizer built from `equalizer.ι f g` is limiting. -/
noncomputable def equalizerIsEqualizer : IsLimit (Fork.ofι (equalizer.ι f g)
    (equalizer.condition f g)) :=
  IsLimit.ofIsoLimit (limit.isLimit _) (Fork.ext (Iso.refl _) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
inst✝ : HasEqualizer f g
⊢ (Iso.refl (limit.cone (parallelPair f g)).pt).hom ≫
      Fork.ι (Fork.ofι (equalizer.ι f g) (_ : equalizer.ι f g ≫ f = equalizer.ι f g ≫ g)) =
    Fork.ι (limit.cone (parallelPair f g))

Next tactic:
aesop
/-- The identity on `X` is an equalizer of `(f, g)`, if `f = g`. -/
def isLimitIdFork (h : f = g) : IsLimit (idFork h) :=
  Fork.IsLimit.mk _ (fun s => Fork.ι s) (fun s => Category.comp_id _) fun s m h => by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
h✝ : f = g
s : Fork f g
m : s.pt ⟶ (idFork h✝).pt
h : m ≫ Fork.ι (idFork h✝) = Fork.ι s
⊢ m = (fun s => Fork.ι s) s

Next tactic:
convert h
/-- The identity on `X` is an equalizer of `(f, g)`, if `f = g`. -/
def isLimitIdFork (h : f = g) : IsLimit (idFork h) :=
  Fork.IsLimit.mk _ (fun s => Fork.ι s) (fun s => Category.comp_id _) fun s m h => by
    convert h
    

Proof state:
case h.e'_2.h
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
h✝ : f = g
s : Fork f g
m : s.pt ⟶ (idFork h✝).pt
h : m ≫ Fork.ι (idFork h✝) = Fork.ι s
e_1✝ : (s.pt ⟶ (idFork h✝).pt) = (s.pt ⟶ (parallelPair f g).obj zero)
⊢ m = m ≫ Fork.ι (idFork h✝)

Next tactic:
exact (Category.comp_id _).symm
@[simp]
theorem equalizer.isoSourceOfSelf_inv :
    (equalizer.isoSourceOfSelf f).inv = equalizer.lift (𝟙 X) (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
⊢ 𝟙 X ≫ f = 𝟙 X ≫ f

Next tactic:
simp
@[simp]
theorem equalizer.isoSourceOfSelf_inv :
    (equalizer.isoSourceOfSelf f).inv = equalizer.lift (𝟙 X) (by simp) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
⊢ (isoSourceOfSelf f).inv = lift (𝟙 X) (_ : 𝟙 X ≫ f = 𝟙 X ≫ f)

Next tactic:
ext
@[simp]
theorem equalizer.isoSourceOfSelf_inv :
    (equalizer.isoSourceOfSelf f).inv = equalizer.lift (𝟙 X) (by simp) := by
  ext
  

Proof state:
case h
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
⊢ (isoSourceOfSelf f).inv ≫ ι f f = lift (𝟙 X) (_ : 𝟙 X ≫ f = 𝟙 X ≫ f) ≫ ι f f

Next tactic:
simp [equalizer.isoSourceOfSelf]
/-- The cofork built from `coequalizer.π f g` is colimiting. -/
noncomputable def coequalizerIsCoequalizer :
    IsColimit (Cofork.ofπ (coequalizer.π f g) (coequalizer.condition f g)) :=
  IsColimit.ofIsoColimit (colimit.isColimit _) (Cofork.ext (Iso.refl _) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
inst✝ : HasCoequalizer f g
⊢ Cofork.π (colimit.cocone (parallelPair f g)) ≫ (Iso.refl (colimit.cocone (parallelPair f g)).pt).hom =
    Cofork.π (Cofork.ofπ (coequalizer.π f g) (_ : f ≫ coequalizer.π f g = g ≫ coequalizer.π f g))

Next tactic:
aesop
theorem coequalizer.π_colimMap_desc {X' Y' Z : C} (f' g' : X' ⟶ Y') [HasCoequalizer f' g']
    (p : X ⟶ X') (q : Y ⟶ Y') (wf : f ≫ q = p ≫ f') (wg : g ≫ q = p ≫ g') (h : Y' ⟶ Z)
    (wh : f' ≫ h = g' ≫ h) :
    coequalizer.π f g ≫ colimMap (parallelPairHom f g f' g' p q wf wg) ≫ coequalizer.desc h wh =
      q ≫ h :=
  by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y : C
f g : X ⟶ Y
inst✝¹ : HasCoequalizer f g
X' Y' Z : C
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : X ⟶ X'
q : Y ⟶ Y'
wf : f ≫ q = p ≫ f'
wg : g ≫ q = p ≫ g'
h : Y' ⟶ Z
wh : f' ≫ h = g' ≫ h
⊢ π f g ≫ colimMap (parallelPairHom f g f' g' p q wf wg) ≫ desc h wh = q ≫ h

Next tactic:
rw [ι_colimMap_assoc, parallelPairHom_app_one, coequalizer.π_desc]
/-- The identity on `Y` is a coequalizer of `(f, g)`, where `f = g`.  -/
def isColimitIdCofork (h : f = g) : IsColimit (idCofork h) :=
  Cofork.IsColimit.mk _ (fun s => Cofork.π s) (fun s => Category.id_comp _) fun s m h => by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
h✝ : f = g
s : Cofork f g
m : (idCofork h✝).pt ⟶ s.pt
h : Cofork.π (idCofork h✝) ≫ m = Cofork.π s
⊢ m = (fun s => Cofork.π s) s

Next tactic:
convert h
/-- The identity on `Y` is a coequalizer of `(f, g)`, where `f = g`.  -/
def isColimitIdCofork (h : f = g) : IsColimit (idCofork h) :=
  Cofork.IsColimit.mk _ (fun s => Cofork.π s) (fun s => Category.id_comp _) fun s m h => by
    convert h
    

Proof state:
case h.e'_2.h
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
h✝ : f = g
s : Cofork f g
m : (idCofork h✝).pt ⟶ s.pt
h : Cofork.π (idCofork h✝) ≫ m = Cofork.π s
e_1✝ : ((idCofork h✝).pt ⟶ s.pt) = ((parallelPair f g).obj one ⟶ s.pt)
⊢ m = Cofork.π (idCofork h✝) ≫ m

Next tactic:
exact (Category.id_comp _).symm
@[simp]
theorem coequalizer.isoTargetOfSelf_hom :
    (coequalizer.isoTargetOfSelf f).hom = coequalizer.desc (𝟙 Y) (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
⊢ f ≫ 𝟙 Y = f ≫ 𝟙 Y

Next tactic:
simp
@[simp]
theorem coequalizer.isoTargetOfSelf_hom :
    (coequalizer.isoTargetOfSelf f).hom = coequalizer.desc (𝟙 Y) (by simp) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
⊢ (isoTargetOfSelf f).hom = desc (𝟙 Y) (_ : f ≫ 𝟙 Y = f ≫ 𝟙 Y)

Next tactic:
ext
@[simp]
theorem coequalizer.isoTargetOfSelf_hom :
    (coequalizer.isoTargetOfSelf f).hom = coequalizer.desc (𝟙 Y) (by simp) := by
  ext
  

Proof state:
case h
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
⊢ π f f ≫ (isoTargetOfSelf f).hom = π f f ≫ desc (𝟙 Y) (_ : f ≫ 𝟙 Y = f ≫ 𝟙 Y)

Next tactic:
simp [coequalizer.isoTargetOfSelf]
/-- The comparison morphism for the equalizer of `f,g`.
This is an isomorphism iff `G` preserves the equalizer of `f,g`; see
`CategoryTheory/Limits/Preserves/Shapes/Equalizers.lean`
-/
noncomputable def equalizerComparison [HasEqualizer f g] [HasEqualizer (G.map f) (G.map g)] :
    G.obj (equalizer f g) ⟶ equalizer (G.map f) (G.map g) :=
  equalizer.lift (G.map (equalizer.ι _ _))
    (by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
⊢ G.map (equalizer.ι f g) ≫ G.map f = G.map (equalizer.ι f g) ≫ G.map g

Next tactic:
simp only [← G.map_comp]
/-- The comparison morphism for the equalizer of `f,g`.
This is an isomorphism iff `G` preserves the equalizer of `f,g`; see
`CategoryTheory/Limits/Preserves/Shapes/Equalizers.lean`
-/
noncomputable def equalizerComparison [HasEqualizer f g] [HasEqualizer (G.map f) (G.map g)] :
    G.obj (equalizer f g) ⟶ equalizer (G.map f) (G.map g) :=
  equalizer.lift (G.map (equalizer.ι _ _))
    (by simp only [← G.map_comp]; 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
⊢ G.map (equalizer.ι f g ≫ f) = G.map (equalizer.ι f g ≫ g)

Next tactic:
rw[equalizer.condition]
@[reassoc (attr := simp)]
theorem map_lift_equalizerComparison [HasEqualizer f g] [HasEqualizer (G.map f) (G.map g)] {Z : C}
    {h : Z ⟶ X} (w : h ≫ f = h ≫ g) :
    G.map (equalizer.lift h w) ≫ equalizerComparison f g G =
      equalizer.lift (G.map h) (by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
Z : C
h : Z ⟶ X
w : h ≫ f = h ≫ g
⊢ G.map h ≫ G.map f = G.map h ≫ G.map g

Next tactic:
simp only [← G.map_comp, w]
@[reassoc (attr := simp)]
theorem map_lift_equalizerComparison [HasEqualizer f g] [HasEqualizer (G.map f) (G.map g)] {Z : C}
    {h : Z ⟶ X} (w : h ≫ f = h ≫ g) :
    G.map (equalizer.lift h w) ≫ equalizerComparison f g G =
      equalizer.lift (G.map h) (by simp only [← G.map_comp, w]) := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
Z : C
h : Z ⟶ X
w : h ≫ f = h ≫ g
⊢ G.map (equalizer.lift h w) ≫ equalizerComparison f g G =
    equalizer.lift (G.map h) (_ : G.map h ≫ G.map f = G.map h ≫ G.map g)

Next tactic:
apply equalizer.hom_ext
@[reassoc (attr := simp)]
theorem map_lift_equalizerComparison [HasEqualizer f g] [HasEqualizer (G.map f) (G.map g)] {Z : C}
    {h : Z ⟶ X} (w : h ≫ f = h ≫ g) :
    G.map (equalizer.lift h w) ≫ equalizerComparison f g G =
      equalizer.lift (G.map h) (by simp only [← G.map_comp, w]) := by
  apply equalizer.hom_ext
  

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
Z : C
h : Z ⟶ X
w : h ≫ f = h ≫ g
⊢ (G.map (equalizer.lift h w) ≫ equalizerComparison f g G) ≫ equalizer.ι (G.map f) (G.map g) =
    equalizer.lift (G.map h) (_ : G.map h ≫ G.map f = G.map h ≫ G.map g) ≫ equalizer.ι (G.map f) (G.map g)

Next tactic:
simp [← G.map_comp]
/-- The comparison morphism for the coequalizer of `f,g`. -/
noncomputable def coequalizerComparison [HasCoequalizer f g] [HasCoequalizer (G.map f) (G.map g)] :
    coequalizer (G.map f) (G.map g) ⟶ G.obj (coequalizer f g) :=
  coequalizer.desc (G.map (coequalizer.π _ _))
    (by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
⊢ G.map f ≫ G.map (coequalizer.π f g) = G.map g ≫ G.map (coequalizer.π f g)

Next tactic:
simp only [← G.map_comp]
/-- The comparison morphism for the coequalizer of `f,g`. -/
noncomputable def coequalizerComparison [HasCoequalizer f g] [HasCoequalizer (G.map f) (G.map g)] :
    coequalizer (G.map f) (G.map g) ⟶ G.obj (coequalizer f g) :=
  coequalizer.desc (G.map (coequalizer.π _ _))
    (by simp only [← G.map_comp]; 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
⊢ G.map (f ≫ coequalizer.π f g) = G.map (g ≫ coequalizer.π f g)

Next tactic:
rw [coequalizer.condition]
@[reassoc (attr := simp)]
theorem coequalizerComparison_map_desc [HasCoequalizer f g] [HasCoequalizer (G.map f) (G.map g)]
    {Z : C} {h : Y ⟶ Z} (w : f ≫ h = g ≫ h) :
    coequalizerComparison f g G ≫ G.map (coequalizer.desc h w) =
      coequalizer.desc (G.map h) (by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
Z : C
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ G.map f ≫ G.map h = G.map g ≫ G.map h

Next tactic:
simp only [← G.map_comp, w]
@[reassoc (attr := simp)]
theorem coequalizerComparison_map_desc [HasCoequalizer f g] [HasCoequalizer (G.map f) (G.map g)]
    {Z : C} {h : Y ⟶ Z} (w : f ≫ h = g ≫ h) :
    coequalizerComparison f g G ≫ G.map (coequalizer.desc h w) =
      coequalizer.desc (G.map h) (by simp only [← G.map_comp, w]) := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
Z : C
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ coequalizerComparison f g G ≫ G.map (coequalizer.desc h w) =
    coequalizer.desc (G.map h) (_ : G.map f ≫ G.map h = G.map g ≫ G.map h)

Next tactic:
apply coequalizer.hom_ext
@[reassoc (attr := simp)]
theorem coequalizerComparison_map_desc [HasCoequalizer f g] [HasCoequalizer (G.map f) (G.map g)]
    {Z : C} {h : Y ⟶ Z} (w : f ≫ h = g ≫ h) :
    coequalizerComparison f g G ≫ G.map (coequalizer.desc h w) =
      coequalizer.desc (G.map h) (by simp only [← G.map_comp, w]) := by
  apply coequalizer.hom_ext
  

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
Z : C
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G ≫ G.map (coequalizer.desc h w) =
    coequalizer.π (G.map f) (G.map g) ≫ coequalizer.desc (G.map h) (_ : G.map f ≫ G.map h = G.map g ≫ G.map h)

Next tactic:
simp [← G.map_comp]
/-- A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`.
Here we build the cone, and show in `isSplitMonoEqualizes` that it is a limit cone.
-/
-- @[simps (config := { rhsMd := semireducible })] Porting note: no semireducible
@[simps!]
noncomputable def coneOfIsSplitMono : Fork (𝟙 Y) (retraction f ≫ f) :=
  Fork.ofι f (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
inst✝ : IsSplitMono f
⊢ f ≫ 𝟙 Y = f ≫ retraction f ≫ f

Next tactic:
simp
/-- A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`.
-/
noncomputable def isSplitMonoEqualizes {X Y : C} (f : X ⟶ Y) [IsSplitMono f] :
    IsLimit (coneOfIsSplitMono f) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨s.ι ≫ retraction f, by
      

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X✝ Y✝ : C
f✝ g : X✝ ⟶ Y✝
inst✝¹ : IsSplitMono f✝
X Y : C
f : X ⟶ Y
inst✝ : IsSplitMono f
s : Fork (𝟙 Y) (retraction f ≫ f)
⊢ (Fork.ι s ≫ retraction f) ≫ Fork.ι (coneOfIsSplitMono f) = Fork.ι s

Next tactic:
dsimp
/-- A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`.
-/
noncomputable def isSplitMonoEqualizes {X Y : C} (f : X ⟶ Y) [IsSplitMono f] :
    IsLimit (coneOfIsSplitMono f) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨s.ι ≫ retraction f, by
      dsimp
      

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X✝ Y✝ : C
f✝ g : X✝ ⟶ Y✝
inst✝¹ : IsSplitMono f✝
X Y : C
f : X ⟶ Y
inst✝ : IsSplitMono f
s : Fork (𝟙 Y) (retraction f ≫ f)
⊢ (Fork.ι s ≫ retraction f) ≫ f = Fork.ι s

Next tactic:
rw [Category.assoc, ← s.condition]
/-- A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`.
-/
noncomputable def isSplitMonoEqualizes {X Y : C} (f : X ⟶ Y) [IsSplitMono f] :
    IsLimit (coneOfIsSplitMono f) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨s.ι ≫ retraction f, by
      dsimp
      rw [Category.assoc, ← s.condition]
      

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X✝ Y✝ : C
f✝ g : X✝ ⟶ Y✝
inst✝¹ : IsSplitMono f✝
X Y : C
f : X ⟶ Y
inst✝ : IsSplitMono f
s : Fork (𝟙 Y) (retraction f ≫ f)
⊢ Fork.ι s ≫ 𝟙 Y = Fork.ι s

Next tactic:
apply Category.comp_id
/-- A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`.
-/
noncomputable def isSplitMonoEqualizes {X Y : C} (f : X ⟶ Y) [IsSplitMono f] :
    IsLimit (coneOfIsSplitMono f) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨s.ι ≫ retraction f, by
      dsimp
      rw [Category.assoc, ← s.condition]
      apply Category.comp_id, fun hm => by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X✝ Y✝ : C
f✝ g : X✝ ⟶ Y✝
inst✝¹ : IsSplitMono f✝
X Y : C
f : X ⟶ Y
inst✝ : IsSplitMono f
s : Fork (𝟙 Y) (retraction f ≫ f)
m✝ :
  ((Functor.const WalkingParallelPair).obj s.pt).obj zero ⟶
    ((Functor.const WalkingParallelPair).obj (coneOfIsSplitMono f).pt).obj zero
hm : m✝ ≫ Fork.ι (coneOfIsSplitMono f) = Fork.ι s
⊢ m✝ = Fork.ι s ≫ retraction f

Next tactic:
simp [← hm]
/-- The fork obtained by postcomposing an equalizer fork with a monomorphism is an equalizer. -/
def isEqualizerCompMono {c : Fork f g} (i : IsLimit c) {Z : C} (h : Y ⟶ Z) [hm : Mono h] :
    have : Fork.ι c ≫ f ≫ h = Fork.ι c ≫ g ≫ h := by
      

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Fork f g
i : IsLimit c
Z : C
h : Y ⟶ Z
hm : Mono h
⊢ Fork.ι c ≫ f ≫ h = Fork.ι c ≫ g ≫ h

Next tactic:
simp only [← Category.assoc]
/-- The fork obtained by postcomposing an equalizer fork with a monomorphism is an equalizer. -/
def isEqualizerCompMono {c : Fork f g} (i : IsLimit c) {Z : C} (h : Y ⟶ Z) [hm : Mono h] :
    have : Fork.ι c ≫ f ≫ h = Fork.ι c ≫ g ≫ h := by
      simp only [← Category.assoc]
      

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
c : Fork f g
i : IsLimit c
Z : C
h : Y ⟶ Z
hm : Mono h
⊢ (Fork.ι c ≫ f) ≫ h = (Fork.ι c ≫ g) ≫ h

Next tactic:
exact congrArg (· ≫ h) c.condition