l3lab/ntp-mathlib huggingface dataset:
/--
If `(a,b)` is a kernel pair for `f₁ ≫ f₂` and `a ≫ f₁ = b ≫ f₁`, then `(a,b)` is a kernel pair for
just `f₁`.
That is, to show that `(a,b)` is a kernel pair for `f₁` it suffices to only show the square
commutes, rather than to additionally show it's a pullback.
-/
theorem cancel_right {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} (comm : a ≫ f₁ = b ≫ f₁)
    (big_k : IsKernelPair (f₁ ≫ f₂) a b) : IsKernelPair f₁ a b :=
  { w := comm
    isLimit' :=
      ⟨PullbackCone.isLimitAux' _ fun s => by
        let s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) :=
          PullbackCone.mk s.fst s.snd (s.condition_assoc _)
        refine' ⟨big_k.isLimit.lift s', big_k.isLimit.fac _ WalkingCospan.left,
          big_k.isLimit.fac _ WalkingCospan.right, fun m₁ m₂ => _⟩
        apply big_k.isLimit.hom_ext
        refine' (PullbackCone.mk a b _ : PullbackCone (f₁ ≫ f₂) _).equalizer_ext _ _
        · apply reassoc_of% comm
        · apply m₁.trans (big_k.isLimit.fac s' WalkingCospan.left).symm
        · 

Proof state:
case refine'_3
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) :=
  PullbackCone.mk (PullbackCone.fst s) (PullbackCone.snd s)
    (_ : PullbackCone.fst s ≫ f₁ ≫ f₂ = PullbackCone.snd s ≫ f₁ ≫ f₂)
m✝ : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ = b ≫ f₁)).pt
m₁ : m✝ ≫ PullbackCone.fst (PullbackCone.mk a b (_ : a ≫ f₁ = b ≫ f₁)) = PullbackCone.fst s
m₂ : m✝ ≫ PullbackCone.snd (PullbackCone.mk a b (_ : a ≫ f₁ = b ≫ f₁)) = PullbackCone.snd s
⊢ m✝ ≫ PullbackCone.snd (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)) =
    IsLimit.lift (IsPullback.isLimit big_k) s' ≫ PullbackCone.snd (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂))

Next tactic:
apply m₂.trans (big_k.isLimit.fac s' WalkingCospan.right).symm
/-- If `(a,b)` is a kernel pair for `f₁ ≫ f₂` and `f₂` is mono, then `(a,b)` is a kernel pair for
just `f₁`.
The converse of `comp_of_mono`.
-/
theorem cancel_right_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂]
    (big_k : IsKernelPair (f₁ ≫ f₂) a b) : IsKernelPair f₁ a b :=
  cancel_right (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
big_k : IsKernelPair (f₁ ≫ f₂) a b
⊢ a ≫ f₁ = b ≫ f₁

Next tactic:
rw [← cancel_mono f₂, assoc, assoc, big_k.w]
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
⊢ a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂

Next tactic:
rw [small_k.w_assoc]
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
⊢ IsLimit (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂))

Next tactic:
refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
⊢ PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁

Next tactic:
rw [← cancel_mono f₂, assoc, s.condition, assoc]
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
⊢ ∀ (s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)),
    (fun s =>
            lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
              (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
          s ≫
        PullbackCone.fst (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)) =
      PullbackCone.fst s

Next tactic:
simp
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
⊢ ∀ (s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)),
    (fun s =>
            lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
              (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
          s ≫
        PullbackCone.snd (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)) =
      PullbackCone.snd s

Next tactic:
simp
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
⊢ ∀ (s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)) (m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt),
    (∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j) →
      m =
        (fun s =>
            lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
              (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
          s

Next tactic:
intro s m hm
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · intro s m hm
        

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt
hm : ∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j
⊢ m =
    (fun s =>
        lift small_k (PullbackCone.fst s) (PullbackCone.snd s) (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
      s

Next tactic:
apply small_k.isLimit.hom_ext
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · intro s m hm
        apply small_k.isLimit.hom_ext
        

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt
hm : ∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j
⊢ ∀ (j : WalkingCospan),
    m ≫ (IsPullback.cone small_k).π.app j =
      (fun s =>
            lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
              (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
          s ≫
        (IsPullback.cone small_k).π.app j

Next tactic:
apply PullbackCone.equalizer_ext small_k.cone _ _
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · intro s m hm
        apply small_k.isLimit.hom_ext
        apply PullbackCone.equalizer_ext small_k.cone _ _
        · 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt
hm : ∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j
⊢ m ≫ PullbackCone.fst (IsPullback.cone small_k) =
    (fun s =>
          lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
            (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
        s ≫
      PullbackCone.fst (IsPullback.cone small_k)

Next tactic:
exact (hm WalkingCospan.left).trans (by simp)
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · intro s m hm
        apply small_k.isLimit.hom_ext
        apply PullbackCone.equalizer_ext small_k.cone _ _
        · exact (hm WalkingCospan.left).trans (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt
hm : ∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j
⊢ s.π.app WalkingCospan.left =
    (fun s =>
          lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
            (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
        s ≫
      PullbackCone.fst (IsPullback.cone small_k)

Next tactic:
simp
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · intro s m hm
        apply small_k.isLimit.hom_ext
        apply PullbackCone.equalizer_ext small_k.cone _ _
        · exact (hm WalkingCospan.left).trans (by simp)
        · 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt
hm : ∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j
⊢ m ≫ PullbackCone.snd (IsPullback.cone small_k) =
    (fun s =>
          lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
            (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
        s ≫
      PullbackCone.snd (IsPullback.cone small_k)

Next tactic:
exact (hm WalkingCospan.right).trans (by simp)
/--
If `(a,b)` is a kernel pair for `f₁` and `f₂` is mono, then `(a,b)` is a kernel pair for `f₁ ≫ f₂`.
The converse of `cancel_right_of_mono`.
-/
theorem comp_of_mono {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} [Mono f₂] (small_k : IsKernelPair f₁ a b) :
    IsKernelPair (f₁ ≫ f₂) a b :=
  { w := by rw [small_k.w_assoc]
    isLimit' := ⟨by
      refine' PullbackCone.isLimitAux _
        (fun s => small_k.lift s.fst s.snd (by rw [← cancel_mono f₂, assoc, s.condition, assoc]))
        (by simp) (by simp) _
      · intro s m hm
        apply small_k.isLimit.hom_ext
        apply PullbackCone.equalizer_ext small_k.cone _ _
        · exact (hm WalkingCospan.left).trans (by simp)
        · exact (hm WalkingCospan.right).trans (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
inst✝ : Mono f₂
small_k : IsKernelPair f₁ a b
s : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂)
m : s.pt ⟶ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).pt
hm : ∀ (j : WalkingCospan), m ≫ (PullbackCone.mk a b (_ : a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂)).π.app j = s.π.app j
⊢ s.π.app WalkingCospan.right =
    (fun s =>
          lift small_k (PullbackCone.fst s) (PullbackCone.snd s)
            (_ : PullbackCone.fst s ≫ f₁ = PullbackCone.snd s ≫ f₁))
        s ≫
      PullbackCone.snd (IsPullback.cone small_k)

Next tactic:
simp
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
⊢ IsColimit (Cofork.ofπ f (_ : a ≫ f = b ≫ f))

Next tactic:
let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
⊢ IsColimit (Cofork.ofπ f (_ : a ≫ f = b ≫ f))

Next tactic:
have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
ht : t ≫ a = RegularEpi.left
⊢ IsColimit (Cofork.ofπ f (_ : a ≫ f = b ≫ f))

Next tactic:
have kt : t ≫ b = r.right := k.isLimit.fac _ WalkingCospan.right
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
  have kt : t ≫ b = r.right := k.isLimit.fac _ WalkingCospan.right
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
ht : t ≫ a = RegularEpi.left
kt : t ≫ b = RegularEpi.right
⊢ IsColimit (Cofork.ofπ f (_ : a ≫ f = b ≫ f))

Next tactic:
refine' Cofork.IsColimit.mk _
    (fun s => Cofork.IsColimit.desc r.isColimit s.π
      (by rw [← ht, assoc, s.condition, reassoc_of% kt]))
    (fun s => _) (fun s m w => _)
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
  have kt : t ≫ b = r.right := k.isLimit.fac _ WalkingCospan.right
  refine' Cofork.IsColimit.mk _
    (fun s => Cofork.IsColimit.desc r.isColimit s.π
      (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
ht : t ≫ a = RegularEpi.left
kt : t ≫ b = RegularEpi.right
s : Cofork a b
⊢ RegularEpi.left ≫ Cofork.π s = RegularEpi.right ≫ Cofork.π s

Next tactic:
rw [← ht, assoc, s.condition, reassoc_of% kt]
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
  have kt : t ≫ b = r.right := k.isLimit.fac _ WalkingCospan.right
  refine' Cofork.IsColimit.mk _
    (fun s => Cofork.IsColimit.desc r.isColimit s.π
      (by rw [← ht, assoc, s.condition, reassoc_of% kt]))
    (fun s => _) (fun s m w => _)
  · 

Proof state:
case refine'_1
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
ht : t ≫ a = RegularEpi.left
kt : t ≫ b = RegularEpi.right
s : Cofork a b
⊢ Cofork.π (Cofork.ofπ f (_ : a ≫ f = b ≫ f)) ≫
      (fun s =>
          Cofork.IsColimit.desc RegularEpi.isColimit (Cofork.π s)
            (_ : RegularEpi.left ≫ Cofork.π s = RegularEpi.right ≫ Cofork.π s))
        s =
    Cofork.π s

Next tactic:
apply Cofork.IsColimit.π_desc' r.isColimit
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
  have kt : t ≫ b = r.right := k.isLimit.fac _ WalkingCospan.right
  refine' Cofork.IsColimit.mk _
    (fun s => Cofork.IsColimit.desc r.isColimit s.π
      (by rw [← ht, assoc, s.condition, reassoc_of% kt]))
    (fun s => _) (fun s m w => _)
  · apply Cofork.IsColimit.π_desc' r.isColimit
  · 

Proof state:
case refine'_2
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
ht : t ≫ a = RegularEpi.left
kt : t ≫ b = RegularEpi.right
s : Cofork a b
m : (Cofork.ofπ f (_ : a ≫ f = b ≫ f)).pt ⟶ s.pt
w : Cofork.π (Cofork.ofπ f (_ : a ≫ f = b ≫ f)) ≫ m = Cofork.π s
⊢ m =
    (fun s =>
        Cofork.IsColimit.desc RegularEpi.isColimit (Cofork.π s)
          (_ : RegularEpi.left ≫ Cofork.π s = RegularEpi.right ≫ Cofork.π s))
      s

Next tactic:
apply Cofork.IsColimit.hom_ext r.isColimit
/--
If `(a,b)` is the kernel pair of `f`, and `f` is a coequalizer morphism for some parallel pair, then
`f` is a coequalizer morphism of `a` and `b`.
-/
def toCoequalizer (k : IsKernelPair f a b) [r : RegularEpi f] : IsColimit (Cofork.ofπ f k.w) := by
  let t := k.isLimit.lift (PullbackCone.mk _ _ r.w)
  have ht : t ≫ a = r.left := k.isLimit.fac _ WalkingCospan.left
  have kt : t ≫ b = r.right := k.isLimit.fac _ WalkingCospan.right
  refine' Cofork.IsColimit.mk _
    (fun s => Cofork.IsColimit.desc r.isColimit s.π
      (by rw [← ht, assoc, s.condition, reassoc_of% kt]))
    (fun s => _) (fun s m w => _)
  · apply Cofork.IsColimit.π_desc' r.isColimit
  · apply Cofork.IsColimit.hom_ext r.isColimit
    

Proof state:
case refine'_2
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
f : X ⟶ Y
a b : R ⟶ X
k : IsKernelPair f a b
r : RegularEpi f
t : (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)).pt ⟶
  (IsPullback.cone k).pt :=
  IsLimit.lift (IsPullback.isLimit k)
    (PullbackCone.mk RegularEpi.left RegularEpi.right (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f))
ht : t ≫ a = RegularEpi.left
kt : t ≫ b = RegularEpi.right
s : Cofork a b
m : (Cofork.ofπ f (_ : a ≫ f = b ≫ f)).pt ⟶ s.pt
w : Cofork.π (Cofork.ofπ f (_ : a ≫ f = b ≫ f)) ≫ m = Cofork.π s
⊢ Cofork.π (Cofork.ofπ f (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)) ≫ m =
    Cofork.π (Cofork.ofπ f (_ : RegularEpi.left ≫ f = RegularEpi.right ≫ f)) ≫
      (fun s =>
          Cofork.IsColimit.desc RegularEpi.isColimit (Cofork.π s)
            (_ : RegularEpi.left ≫ Cofork.π s = RegularEpi.right ≫ Cofork.π s))
        s

Next tactic:
exact w.trans (Cofork.IsColimit.π_desc' r.isColimit _ _).symm