l3lab/ntp-mathlib huggingface dataset:
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> 

Proof state:
case one.one
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f✝ = ι ≫ g
f : one ⟶ one
⊢ ((Functor.const WalkingParallelPair).obj P).map f ≫
      (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f✝ g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f✝) (_ : X_1 = X_1))
        one =
    (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f✝ g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f✝) (_ : X_1 = X_1))
        one ≫
      (parallelPair f✝ g).map f

Next tactic:
cases f
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> 

Proof state:
case zero.zero.id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ ((Functor.const WalkingParallelPair).obj P).map (WalkingParallelPairHom.id zero) ≫
      (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        zero =
    (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        zero ≫
      (parallelPair f g).map (WalkingParallelPairHom.id zero)

Next tactic:
dsimp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> 

Proof state:
case zero.one.left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ ((Functor.const WalkingParallelPair).obj P).map left ≫
      (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        one =
    (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        zero ≫
      (parallelPair f g).map left

Next tactic:
dsimp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> 

Proof state:
case zero.one.right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ ((Functor.const WalkingParallelPair).obj P).map right ≫
      (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        one =
    (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        zero ≫
      (parallelPair f g).map right

Next tactic:
dsimp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> 

Proof state:
case one.one.id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ ((Functor.const WalkingParallelPair).obj P).map (WalkingParallelPairHom.id one) ≫
      (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        one =
    (fun X_1 =>
          WalkingParallelPair.casesOn (motive := fun t =>
            X_1 = t → (((Functor.const WalkingParallelPair).obj P).obj X_1 ⟶ (parallelPair f g).obj X_1)) X_1
            (fun h => (_ : zero = X_1) ▸ ι) (fun h => (_ : one = X_1) ▸ ι ≫ f) (_ : X_1 = X_1))
        one ≫
      (parallelPair f g).map (WalkingParallelPairHom.id one)

Next tactic:
dsimp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> dsimp <;> 

Proof state:
case zero.zero.id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ 𝟙 P ≫ ι = ι ≫ (parallelPair f g).map (𝟙 zero)

Next tactic:
simp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> dsimp <;> 

Proof state:
case zero.one.left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ 𝟙 P ≫ ι ≫ f = ι ≫ f

Next tactic:
simp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> dsimp <;> 

Proof state:
case zero.one.right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ 𝟙 P ≫ ι ≫ f = ι ≫ g

Next tactic:
simp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> dsimp <;> 

Proof state:
case one.one.id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ 𝟙 P ≫ ι ≫ f = (ι ≫ f) ≫ (parallelPair f g).map (𝟙 one)

Next tactic:
simp
/-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`.
-/
@[simps]
def Fork.ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : Fork f g where
  pt := P
  π :=
    { app := fun X => by cases X; exact ι; exact ι ≫ f
      naturality := fun {X} {Y} f =>
        by cases X <;> cases Y <;> cases f <;> dsimp <;> simp; 

Proof state:
case zero.one.right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ ι ≫ f = ι ≫ g

Next tactic:
assumption
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f✝ g : X ⟶ Y
P : C
π : Y ⟶ P
w : f✝ ≫ π = g ≫ π
i j : WalkingParallelPair
f : i ⟶ j
⊢ (parallelPair f✝ g).map f ≫ (fun X_1 => WalkingParallelPair.casesOn X_1 (f✝ ≫ π) π) j =
    (fun X_1 => WalkingParallelPair.casesOn X_1 (f✝ ≫ π) π) i ≫ ((Functor.const WalkingParallelPair).obj P).map f

Next tactic:
cases f
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by cases f <;> 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
⊢ (parallelPair f g).map left ≫ (fun X_1 => WalkingParallelPair.casesOn X_1 (f ≫ π) π) one =
    (fun X_1 => WalkingParallelPair.casesOn X_1 (f ≫ π) π) zero ≫ ((Functor.const WalkingParallelPair).obj P).map left

Next tactic:
dsimp
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by cases f <;> 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
⊢ (parallelPair f g).map right ≫ (fun X_1 => WalkingParallelPair.casesOn X_1 (f ≫ π) π) one =
    (fun X_1 => WalkingParallelPair.casesOn X_1 (f ≫ π) π) zero ≫ ((Functor.const WalkingParallelPair).obj P).map right

Next tactic:
dsimp
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by cases f <;> 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
i : WalkingParallelPair
⊢ (parallelPair f g).map (WalkingParallelPairHom.id i) ≫ (fun X_1 => WalkingParallelPair.casesOn X_1 (f ≫ π) π) i =
    (fun X_1 => WalkingParallelPair.casesOn X_1 (f ≫ π) π) i ≫
      ((Functor.const WalkingParallelPair).obj P).map (WalkingParallelPairHom.id i)

Next tactic:
dsimp
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by cases f <;> dsimp <;> 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
⊢ f ≫ π = (f ≫ π) ≫ 𝟙 P

Next tactic:
simp [w]
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by cases f <;> dsimp <;> 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
⊢ g ≫ π = (f ≫ π) ≫ 𝟙 P

Next tactic:
simp [w]
/-- A cofork on `f g : X ⟶ Y` is determined by the morphism `π : Y ⟶ P` satisfying
    `f ≫ π = g ≫ π`. -/
@[simps]
def Cofork.ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : Cofork f g where
  pt := P
  ι :=
    { app := fun X => WalkingParallelPair.casesOn X (f ≫ π) π
      naturality := fun i j f => by cases f <;> dsimp <;> 

Proof state:
case id
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
i : WalkingParallelPair
⊢ (parallelPair f g).map (𝟙 i) ≫ WalkingParallelPair.rec (f ≫ π) π i = WalkingParallelPair.rec (f ≫ π) π i ≫ 𝟙 P

Next tactic:
simp [w]
@[reassoc (attr := simp)]
theorem Fork.condition (t : Fork f g) : t.ι ≫ f = t.ι ≫ g := by
  

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

Next tactic:
rw [← t.app_one_eq_ι_comp_left, ← t.app_one_eq_ι_comp_right]
@[reassoc (attr := simp)]
theorem Cofork.condition (t : Cofork f g) : f ≫ t.π = g ≫ t.π := by
  

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

Next tactic:
rw [← t.app_zero_eq_comp_π_left, ← t.app_zero_eq_comp_π_right]
/-- To check whether two maps are equalized by both maps of a fork, it suffices to check it for the
    first map -/
theorem Fork.equalizer_ext (s : Fork f g) {W : C} {k l : W ⟶ s.pt} (h : k ≫ s.ι = l ≫ s.ι) :
    ∀ j : WalkingParallelPair, k ≫ s.π.app j = l ≫ s.π.app j
  | zero => h
  | one => by
    

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

Next tactic:
have : k ≫ ι s ≫ f = l ≫ ι s ≫ f := by
      simp only [← Category.assoc]; exact congrArg (· ≫ f) h
/-- To check whether two maps are equalized by both maps of a fork, it suffices to check it for the
    first map -/
theorem Fork.equalizer_ext (s : Fork f g) {W : C} {k l : W ⟶ s.pt} (h : k ≫ s.ι = l ≫ s.ι) :
    ∀ j : WalkingParallelPair, k ≫ s.π.app j = l ≫ s.π.app j
  | zero => h
  | one => by
    have : k ≫ ι s ≫ f = l ≫ ι s ≫ f := by
      

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s : Fork f g
W : C
k l : W ⟶ s.pt
h : k ≫ ι s = l ≫ ι s
⊢ k ≫ ι s ≫ f = l ≫ ι s ≫ f

Next tactic:
simp only [← Category.assoc]
/-- To check whether two maps are equalized by both maps of a fork, it suffices to check it for the
    first map -/
theorem Fork.equalizer_ext (s : Fork f g) {W : C} {k l : W ⟶ s.pt} (h : k ≫ s.ι = l ≫ s.ι) :
    ∀ j : WalkingParallelPair, k ≫ s.π.app j = l ≫ s.π.app j
  | zero => h
  | one => by
    have : k ≫ ι s ≫ f = l ≫ ι s ≫ f := by
      simp only [← Category.assoc]; 

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

Next tactic:
exact congrArg (· ≫ f) h
/-- To check whether two maps are equalized by both maps of a fork, it suffices to check it for the
    first map -/
theorem Fork.equalizer_ext (s : Fork f g) {W : C} {k l : W ⟶ s.pt} (h : k ≫ s.ι = l ≫ s.ι) :
    ∀ j : WalkingParallelPair, k ≫ s.π.app j = l ≫ s.π.app j
  | zero => h
  | one => by
    have : k ≫ ι s ≫ f = l ≫ ι s ≫ f := by
      simp only [← Category.assoc]; exact congrArg (· ≫ f) h
    

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

Next tactic:
rw [s.app_one_eq_ι_comp_left, this]
/-- To check whether two maps are coequalized by both maps of a cofork, it suffices to check it for
    the second map -/
theorem Cofork.coequalizer_ext (s : Cofork f g) {W : C} {k l : s.pt ⟶ W}
    (h : Cofork.π s ≫ k = Cofork.π s ≫ l) : ∀ j : WalkingParallelPair, s.ι.app j ≫ k = s.ι.app j ≫ l
  | zero => by 

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

Next tactic:
simp only [s.app_zero_eq_comp_π_left, Category.assoc, h]
/-- If `s` is a limit fork over `f` and `g`, then a morphism `k : W ⟶ X` satisfying
    `k ≫ f = k ≫ g` induces a morphism `l : W ⟶ s.pt` such that `l ≫ fork.ι s = k`. -/
def Fork.IsLimit.lift' {s : Fork f g} (hs : IsLimit s) {W : C} (k : W ⟶ X) (h : k ≫ f = k ≫ g) :
    { l : W ⟶ s.pt // l ≫ Fork.ι s = k } :=
  ⟨Fork.IsLimit.lift hs k h, by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s : Fork f g
hs : IsLimit s
W : C
k : W ⟶ X
h : k ≫ f = k ≫ g
⊢ lift hs k h ≫ ι s = k

Next tactic:
simp
/-- If `s` is a colimit cofork over `f` and `g`, then a morphism `k : Y ⟶ W` satisfying
    `f ≫ k = g ≫ k` induces a morphism `l : s.pt ⟶ W` such that `cofork.π s ≫ l = k`. -/
def Cofork.IsColimit.desc' {s : Cofork f g} (hs : IsColimit s) {W : C} (k : Y ⟶ W)
    (h : f ≫ k = g ≫ k) : { l : s.pt ⟶ W // Cofork.π s ≫ l = k } :=
  ⟨Cofork.IsColimit.desc hs k h, by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
s : Cofork f g
hs : IsColimit s
W : C
k : Y ⟶ W
h : f ≫ k = g ≫ k
⊢ π s ≫ desc hs k h = k

Next tactic:
simp
/-- This is a slightly more convenient method to verify that a fork is a limit cone. It
    only asks for a proof of facts that carry any mathematical content -/
@[simps]
def Fork.IsLimit.mk (t : Fork f g) (lift : ∀ s : Fork f g, s.pt ⟶ t.pt)
    (fac : ∀ s : Fork f g, lift s ≫ Fork.ι t = Fork.ι s)
    (uniq : ∀ (s : Fork f g) (m : s.pt ⟶ t.pt) (_ : m ≫ t.ι = s.ι), m = lift s) : IsLimit t :=
  { lift
    fac := fun s j =>
      WalkingParallelPair.casesOn j (fac s) <| by
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Fork f g
lift : (s : Fork f g) → s.pt ⟶ t.pt
fac : ∀ (s : Fork f g), lift s ≫ ι t = ι s
uniq : ∀ (s : Fork f g) (m : s.pt ⟶ t.pt), m ≫ ι t = ι s → m = lift s
s : Cone (parallelPair f g)
j : WalkingParallelPair
⊢ lift s ≫ t.π.app one = s.π.app one

Next tactic:
erw [← s.w left, ← t.w left, ← Category.assoc, fac]
/-- This is a slightly more convenient method to verify that a fork is a limit cone. It
    only asks for a proof of facts that carry any mathematical content -/
@[simps]
def Fork.IsLimit.mk (t : Fork f g) (lift : ∀ s : Fork f g, s.pt ⟶ t.pt)
    (fac : ∀ s : Fork f g, lift s ≫ Fork.ι t = Fork.ι s)
    (uniq : ∀ (s : Fork f g) (m : s.pt ⟶ t.pt) (_ : m ≫ t.ι = s.ι), m = lift s) : IsLimit t :=
  { lift
    fac := fun s j =>
      WalkingParallelPair.casesOn j (fac s) <| by
        erw [← s.w left, ← t.w left, ← Category.assoc, fac]; 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Fork f g
lift : (s : Fork f g) → s.pt ⟶ t.pt
fac : ∀ (s : Fork f g), lift s ≫ ι t = ι s
uniq : ∀ (s : Fork f g) (m : s.pt ⟶ t.pt), m ≫ ι t = ι s → m = lift s
s : Cone (parallelPair f g)
j : WalkingParallelPair
⊢ ι s ≫ (parallelPair f g).map left = s.π.app zero ≫ (parallelPair f g).map left

Next tactic:
rfl
/-- This is a slightly more convenient method to verify that a fork is a limit cone. It
    only asks for a proof of facts that carry any mathematical content -/
@[simps]
def Fork.IsLimit.mk (t : Fork f g) (lift : ∀ s : Fork f g, s.pt ⟶ t.pt)
    (fac : ∀ s : Fork f g, lift s ≫ Fork.ι t = Fork.ι s)
    (uniq : ∀ (s : Fork f g) (m : s.pt ⟶ t.pt) (_ : m ≫ t.ι = s.ι), m = lift s) : IsLimit t :=
  { lift
    fac := fun s j =>
      WalkingParallelPair.casesOn j (fac s) <| by
        erw [← s.w left, ← t.w left, ← Category.assoc, fac]; rfl
    uniq := fun s m j => by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Fork f g
lift : (s : Fork f g) → s.pt ⟶ t.pt
fac : ∀ (s : Fork f g), lift s ≫ ι t = ι s
uniq : ∀ (s : Fork f g) (m : s.pt ⟶ t.pt), m ≫ ι t = ι s → m = lift s
s : Cone (parallelPair f g)
m : s.pt ⟶ t.pt
j : ∀ (j : WalkingParallelPair), m ≫ t.π.app j = s.π.app j
⊢ m = lift s

Next tactic:
aesop
/-- This is a slightly more convenient method to verify that a cofork is a colimit cocone. It
    only asks for a proof of facts that carry any mathematical content -/
def Cofork.IsColimit.mk (t : Cofork f g) (desc : ∀ s : Cofork f g, t.pt ⟶ s.pt)
    (fac : ∀ s : Cofork f g, Cofork.π t ≫ desc s = Cofork.π s)
    (uniq : ∀ (s : Cofork f g) (m : t.pt ⟶ s.pt) (_ : t.π ≫ m = s.π), m = desc s) : IsColimit t :=
  { desc
    fac := fun s j =>
      WalkingParallelPair.casesOn j (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Cofork f g
desc : (s : Cofork f g) → t.pt ⟶ s.pt
fac : ∀ (s : Cofork f g), π t ≫ desc s = π s
uniq : ∀ (s : Cofork f g) (m : t.pt ⟶ s.pt), π t ≫ m = π s → m = desc s
s : Cocone (parallelPair f g)
j : WalkingParallelPair
⊢ t.ι.app zero ≫ desc s = s.ι.app zero

Next tactic:
erw [← s.w left, ← t.w left, Category.assoc, fac]
/-- This is a slightly more convenient method to verify that a cofork is a colimit cocone. It
    only asks for a proof of facts that carry any mathematical content -/
def Cofork.IsColimit.mk (t : Cofork f g) (desc : ∀ s : Cofork f g, t.pt ⟶ s.pt)
    (fac : ∀ s : Cofork f g, Cofork.π t ≫ desc s = Cofork.π s)
    (uniq : ∀ (s : Cofork f g) (m : t.pt ⟶ s.pt) (_ : t.π ≫ m = s.π), m = desc s) : IsColimit t :=
  { desc
    fac := fun s j =>
      WalkingParallelPair.casesOn j (by erw [← s.w left, ← t.w left, Category.assoc, fac]; 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Cofork f g
desc : (s : Cofork f g) → t.pt ⟶ s.pt
fac : ∀ (s : Cofork f g), π t ≫ desc s = π s
uniq : ∀ (s : Cofork f g) (m : t.pt ⟶ s.pt), π t ≫ m = π s → m = desc s
s : Cocone (parallelPair f g)
j : WalkingParallelPair
⊢ (parallelPair f g).map left ≫ π s = (parallelPair f g).map left ≫ s.ι.app one

Next tactic:
rfl
/-- This is a slightly more convenient method to verify that a cofork is a colimit cocone. It
    only asks for a proof of facts that carry any mathematical content -/
def Cofork.IsColimit.mk (t : Cofork f g) (desc : ∀ s : Cofork f g, t.pt ⟶ s.pt)
    (fac : ∀ s : Cofork f g, Cofork.π t ≫ desc s = Cofork.π s)
    (uniq : ∀ (s : Cofork f g) (m : t.pt ⟶ s.pt) (_ : t.π ≫ m = s.π), m = desc s) : IsColimit t :=
  { desc
    fac := fun s j =>
      WalkingParallelPair.casesOn j (by erw [← s.w left, ← t.w left, Category.assoc, fac]; rfl)
        (fac s)
    uniq := by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Cofork f g
desc : (s : Cofork f g) → t.pt ⟶ s.pt
fac : ∀ (s : Cofork f g), π t ≫ desc s = π s
uniq : ∀ (s : Cofork f g) (m : t.pt ⟶ s.pt), π t ≫ m = π s → m = desc s
⊢ ∀ (s : Cocone (parallelPair f g)) (m : t.pt ⟶ s.pt),
    (∀ (j : WalkingParallelPair), t.ι.app j ≫ m = s.ι.app j) → m = desc s

Next tactic:
aesop
/-- Noncomputably make a limit cone from the existence of unique factorizations. -/
noncomputable def Fork.IsLimit.ofExistsUnique {t : Fork f g}
    (hs : ∀ s : Fork f g, ∃! l : s.pt ⟶ t.pt, l ≫ Fork.ι t = Fork.ι s) : IsLimit t := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Fork f g
hs : ∀ (s : Fork f g), ∃! l, l ≫ ι t = ι s
⊢ IsLimit t

Next tactic:
choose d hd hd' using hs
/-- Noncomputably make a limit cone from the existence of unique factorizations. -/
noncomputable def Fork.IsLimit.ofExistsUnique {t : Fork f g}
    (hs : ∀ s : Fork f g, ∃! l : s.pt ⟶ t.pt, l ≫ Fork.ι t = Fork.ι s) : IsLimit t := by
  choose d hd hd' using hs
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Fork f g
d : (s : Fork f g) → s.pt ⟶ t.pt
hd : ∀ (s : Fork f g), (fun l => l ≫ ι t = ι s) (d s)
hd' : ∀ (s : Fork f g) (y : s.pt ⟶ t.pt), (fun l => l ≫ ι t = ι s) y → y = d s
⊢ IsLimit t

Next tactic:
exact Fork.IsLimit.mk _ d hd fun s m hm => hd' _ _ hm
/-- Noncomputably make a colimit cocone from the existence of unique factorizations. -/
noncomputable def Cofork.IsColimit.ofExistsUnique {t : Cofork f g}
    (hs : ∀ s : Cofork f g, ∃! d : t.pt ⟶ s.pt, Cofork.π t ≫ d = Cofork.π s) : IsColimit t := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f g : X ⟶ Y
t : Cofork f g
hs : ∀ (s : Cofork f g), ∃! d, π t ≫ d = π s
⊢ IsColimit t

Next tactic:
choose d hd hd' using hs