l3lab/ntp-mathlib huggingface dataset:
/-- This is a helper construction that can be useful when verifying that a category has all
    coequalizers. Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)`, and a cofork on `F.map left` and `F.map right`,
    we get a cocone on `F`.

    If you're thinking about using this, have a look at
    `hasCoequalizers_of_hasColimit_parallelPair`, which you may find to be an easier way of
    achieving your goal. -/
def Cocone.ofCofork {F : WalkingParallelPair ⥤ C} (t : Cofork (F.map left) (F.map right)) : Cocone F
    where
  pt := t.pt
  ι :=
    { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
      naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cofork (F.map left) (F.map right)
X✝ : WalkingParallelPair
⊢ F.map (WalkingParallelPairHom.id X✝) ≫
      (fun X => eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X) ≫ t.ι.app X) X✝ =
    (fun X => eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X) ≫ t.ι.app X) X✝ ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map (WalkingParallelPairHom.id X✝)

Next tactic:
dsimp
/-- This is a helper construction that can be useful when verifying that a category has all
    coequalizers. Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)`, and a cofork on `F.map left` and `F.map right`,
    we get a cocone on `F`.

    If you're thinking about using this, have a look at
    `hasCoequalizers_of_hasColimit_parallelPair`, which you may find to be an easier way of
    achieving your goal. -/
def Cocone.ofCofork {F : WalkingParallelPair ⥤ C} (t : Cofork (F.map left) (F.map right)) : Cocone F
    where
  pt := t.pt
  ι :=
    { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
      naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cofork (F.map left) (F.map right)
X✝ : WalkingParallelPair
⊢ F.map (𝟙 X✝) ≫ eqToHom (_ : F.obj X✝ = (parallelPair (F.map left) (F.map right)).obj X✝) ≫ t.ι.app X✝ =
    (eqToHom (_ : F.obj X✝ = (parallelPair (F.map left) (F.map right)).obj X✝) ≫ t.ι.app X✝) ≫ 𝟙 t.pt

Next tactic:
simp [t.condition]
@[simp]
theorem Cone.ofFork_π {F : WalkingParallelPair ⥤ C} (t : Fork (F.map left) (F.map right)) (j) :
    (Cone.ofFork t).π.app j = t.π.app j ≫ eqToHom (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Fork (F.map left) (F.map right)
j : WalkingParallelPair
⊢ (parallelPair (F.map left) (F.map right)).obj j = F.obj j

Next tactic:
aesop
@[simp]
theorem Cocone.ofCofork_ι {F : WalkingParallelPair ⥤ C} (t : Cofork (F.map left) (F.map right))
    (j) : (Cocone.ofCofork t).ι.app j = eqToHom (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cofork (F.map left) (F.map right)
j : WalkingParallelPair
⊢ F.obj j = (parallelPair (F.map left) (F.map right)).obj j

Next tactic:
aesop
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X✝ Y : C
f g : X✝ ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
X : WalkingParallelPair
⊢ F.obj X = (parallelPair (F.map left) (F.map right)).obj X

Next tactic:
aesop
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ ∀ ⦃X Y : WalkingParallelPair⦄ (f : X ⟶ Y),
    ((Functor.const WalkingParallelPair).obj t.pt).map f ≫
        (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) Y =
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) X ≫
        (parallelPair (F.map left) (F.map right)).map f

Next tactic:
rintro _ _ (_|_|_)
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ ((Functor.const WalkingParallelPair).obj t.pt).map left ≫
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) one =
    (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) zero ≫
      (parallelPair (F.map left) (F.map right)).map left

Next tactic:
{dsimp; simp}
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ ((Functor.const WalkingParallelPair).obj t.pt).map left ≫
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) one =
    (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) zero ≫
      (parallelPair (F.map left) (F.map right)).map left

Next tactic:
dsimp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ 𝟙 t.pt ≫ t.π.app one ≫ 𝟙 (F.obj one) = (t.π.app zero ≫ 𝟙 (F.obj zero)) ≫ F.map left

Next tactic:
simp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ ((Functor.const WalkingParallelPair).obj t.pt).map right ≫
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) one =
    (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) zero ≫
      (parallelPair (F.map left) (F.map right)).map right

Next tactic:
{dsimp; simp}
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ ((Functor.const WalkingParallelPair).obj t.pt).map right ≫
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) one =
    (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) zero ≫
      (parallelPair (F.map left) (F.map right)).map right

Next tactic:
dsimp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
⊢ 𝟙 t.pt ≫ t.π.app one ≫ 𝟙 (F.obj one) = (t.π.app zero ≫ 𝟙 (F.obj zero)) ≫ F.map right

Next tactic:
simp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
X✝ : WalkingParallelPair
⊢ ((Functor.const WalkingParallelPair).obj t.pt).map (WalkingParallelPairHom.id X✝) ≫
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) X✝ =
    (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) X✝ ≫
      (parallelPair (F.map left) (F.map right)).map (WalkingParallelPairHom.id X✝)

Next tactic:
{dsimp; simp}
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
X✝ : WalkingParallelPair
⊢ ((Functor.const WalkingParallelPair).obj t.pt).map (WalkingParallelPairHom.id X✝) ≫
      (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) X✝ =
    (fun X => t.π.app X ≫ eqToHom (_ : F.obj X = (parallelPair (F.map left) (F.map right)).obj X)) X✝ ≫
      (parallelPair (F.map left) (F.map right)).map (WalkingParallelPairHom.id X✝)

Next tactic:
dsimp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on
    `F.map left` and `F.map right`. -/
def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) (F.map right)
    where
  pt := t.pt
  π := { app := fun X => t.π.app X ≫ eqToHom (by aesop)
         naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
X✝ : WalkingParallelPair
⊢ 𝟙 t.pt ≫ t.π.app X✝ ≫ eqToHom (_ : F.obj X✝ = (parallelPair (F.map left) (F.map right)).obj X✝) =
    (t.π.app X✝ ≫ eqToHom (_ : F.obj X✝ = (parallelPair (F.map left) (F.map right)).obj X✝)) ≫
      (parallelPair (F.map left) (F.map right)).map (𝟙 X✝)

Next tactic:
simp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X✝ Y : C
f g : X✝ ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
X : WalkingParallelPair
⊢ (parallelPair (F.map left) (F.map right)).obj X = F.obj X

Next tactic:
aesop
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ ∀ ⦃X Y : WalkingParallelPair⦄ (f : X ⟶ Y),
    (parallelPair (F.map left) (F.map right)).map f ≫
        (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) Y =
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) X ≫
        ((Functor.const WalkingParallelPair).obj t.pt).map f

Next tactic:
rintro _ _ (_|_|_)
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ (parallelPair (F.map left) (F.map right)).map left ≫
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) one =
    (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) zero ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map left

Next tactic:
{dsimp; simp}
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ (parallelPair (F.map left) (F.map right)).map left ≫
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) one =
    (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) zero ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map left

Next tactic:
dsimp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ F.map left ≫ 𝟙 (F.obj one) ≫ t.ι.app one = (𝟙 (F.obj zero) ≫ t.ι.app zero) ≫ 𝟙 t.pt

Next tactic:
simp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ (parallelPair (F.map left) (F.map right)).map right ≫
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) one =
    (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) zero ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map right

Next tactic:
{dsimp; simp}
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ (parallelPair (F.map left) (F.map right)).map right ≫
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) one =
    (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) zero ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map right

Next tactic:
dsimp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
⊢ F.map right ≫ 𝟙 (F.obj one) ≫ t.ι.app one = (𝟙 (F.obj zero) ≫ t.ι.app zero) ≫ 𝟙 t.pt

Next tactic:
simp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
X✝ : WalkingParallelPair
⊢ (parallelPair (F.map left) (F.map right)).map (WalkingParallelPairHom.id X✝) ≫
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) X✝ =
    (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) X✝ ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map (WalkingParallelPairHom.id X✝)

Next tactic:
{dsimp; simp}
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> {

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
X✝ : WalkingParallelPair
⊢ (parallelPair (F.map left) (F.map right)).map (WalkingParallelPairHom.id X✝) ≫
      (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) X✝ =
    (fun X => eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X = F.obj X) ≫ t.ι.app X) X✝ ≫
      ((Functor.const WalkingParallelPair).obj t.pt).map (WalkingParallelPairHom.id X✝)

Next tactic:
dsimp
/-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as
    `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on
    `F.map left` and `F.map right`. -/
def Cofork.ofCocone {F : WalkingParallelPair ⥤ C} (t : Cocone F) : Cofork (F.map left) (F.map right)
    where
  pt := t.pt
  ι := { app := fun X => eqToHom (by aesop) ≫ t.ι.app X
         naturality := by rintro _ _ (_|_|_) <;> {dsimp; 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
X✝ : WalkingParallelPair
⊢ (parallelPair (F.map left) (F.map right)).map (𝟙 X✝) ≫
      eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X✝ = F.obj X✝) ≫ t.ι.app X✝ =
    (eqToHom (_ : (parallelPair (F.map left) (F.map right)).obj X✝ = F.obj X✝) ≫ t.ι.app X✝) ≫ 𝟙 t.pt

Next tactic:
simp
@[simp]
theorem Fork.ofCone_π {F : WalkingParallelPair ⥤ C} (t : Cone F) (j) :
    (Fork.ofCone t).π.app j = t.π.app j ≫ eqToHom (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cone F
j : WalkingParallelPair
⊢ F.obj j = (parallelPair (F.map left) (F.map right)).obj j

Next tactic:
aesop
@[simp]
theorem Cofork.ofCocone_ι {F : WalkingParallelPair ⥤ C} (t : Cocone F) (j) :
    (Cofork.ofCocone t).ι.app j = eqToHom (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
F : WalkingParallelPair ⥤ C
t : Cocone F
j : WalkingParallelPair
⊢ (parallelPair (F.map left) (F.map right)).obj j = F.obj j

Next tactic:
aesop
/-- Helper function for constructing morphisms between equalizer forks.
-/
@[simps]
def Fork.mkHom {s t : Fork f g} (k : s.pt ⟶ t.pt) (w : k ≫ t.ι = s.ι) : 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 : Fork f g
k : s.pt ⟶ t.pt
w : k ≫ ι t = ι s
⊢ ∀ (j : WalkingParallelPair), k ≫ t.π.app j = s.π.app j

Next tactic:
rintro ⟨_ | _⟩
/-- Helper function for constructing morphisms between equalizer forks.
-/
@[simps]
def Fork.mkHom {s t : Fork f g} (k : s.pt ⟶ t.pt) (w : k ≫ t.ι = s.ι) : 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 : Fork f g
k : s.pt ⟶ t.pt
w : k ≫ ι t = ι s
⊢ k ≫ t.π.app zero = s.π.app zero

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

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

Next tactic:
simp only [Fork.app_one_eq_ι_comp_left,← Category.assoc]
/-- Helper function for constructing morphisms between equalizer forks.
-/
@[simps]
def Fork.mkHom {s t : Fork f g} (k : s.pt ⟶ t.pt) (w : k ≫ t.ι = s.ι) : s ⟶ t where
  hom := k
  w := by
    rintro ⟨_ | _⟩
    · exact w
    · simp only [Fork.app_one_eq_ι_comp_left,← Category.assoc]
      

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

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

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

Next tactic:
rw [← w, Iso.inv_hom_id_assoc]