l3lab/ntp-mathlib huggingface dataset:
/-- A functor between preadditive categories preserves the equalizer of two
morphisms if it preserves all kernels. -/
def preservesEqualizerOfPreservesKernels [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F]
    {X Y : C} (f g : X ⟶ Y) : PreservesLimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryProducts F
  haveI := additive_of_preservesBinaryBiproducts F
  constructor; intro c i
  let c' := isLimitKernelForkOfFork (i.ofIsoLimit (Fork.isoForkOfι c))
  dsimp only [kernelForkOfFork_ofι] at c'
  let iFc := isLimitForkMapOfIsLimit' F _ c'
  apply IsLimit.ofIsoLimit _ ((Cones.functoriality _ F).mapIso (Fork.isoForkOfι c).symm)
  apply (isLimitMapConeForkEquiv F (Fork.condition c)).invFun
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryProducts F
this : Additive F
c : Cone (parallelPair f g)
i : IsLimit c
c' : IsLimit (KernelFork.ofι (Fork.ι c) (_ : Fork.ι c ≫ (f - g) = 0)) :=
  isLimitKernelForkOfFork (IsLimit.ofIsoLimit i (Fork.isoForkOfι c))
iFc : IsLimit (KernelFork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map (f - g) = 0)) :=
  isLimitForkMapOfIsLimit' F (_ : Fork.ι c ≫ (f - g) = 0) c'
⊢ IsLimit (Fork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map f = F.map (Fork.ι c) ≫ F.map g))

Next tactic:
let p : parallelPair (F.map (f - g)) 0 ≅ parallelPair (F.map f - F.map g) 0 :=
    parallelPair.eqOfHomEq F.map_sub rfl
/-- A functor between preadditive categories preserves the equalizer of two
morphisms if it preserves all kernels. -/
def preservesEqualizerOfPreservesKernels [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F]
    {X Y : C} (f g : X ⟶ Y) : PreservesLimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryProducts F
  haveI := additive_of_preservesBinaryBiproducts F
  constructor; intro c i
  let c' := isLimitKernelForkOfFork (i.ofIsoLimit (Fork.isoForkOfι c))
  dsimp only [kernelForkOfFork_ofι] at c'
  let iFc := isLimitForkMapOfIsLimit' F _ c'
  apply IsLimit.ofIsoLimit _ ((Cones.functoriality _ F).mapIso (Fork.isoForkOfι c).symm)
  apply (isLimitMapConeForkEquiv F (Fork.condition c)).invFun
  let p : parallelPair (F.map (f - g)) 0 ≅ parallelPair (F.map f - F.map g) 0 :=
    parallelPair.eqOfHomEq F.map_sub rfl
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryProducts F
this : Additive F
c : Cone (parallelPair f g)
i : IsLimit c
c' : IsLimit (KernelFork.ofι (Fork.ι c) (_ : Fork.ι c ≫ (f - g) = 0)) :=
  isLimitKernelForkOfFork (IsLimit.ofIsoLimit i (Fork.isoForkOfι c))
iFc : IsLimit (KernelFork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map (f - g) = 0)) :=
  isLimitForkMapOfIsLimit' F (_ : Fork.ι c ≫ (f - g) = 0) c'
p : parallelPair (F.map (f - g)) 0 ≅ parallelPair (F.map f - F.map g) 0 :=
  parallelPair.eqOfHomEq (_ : F.map (f - g) = F.map f - F.map g) (_ : 0 = 0)
⊢ IsLimit (Fork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map f = F.map (Fork.ι c) ≫ F.map g))

Next tactic:
exact
    IsLimit.ofIsoLimit
      (isLimitForkOfKernelFork ((IsLimit.postcomposeHomEquiv p _).symm iFc))
      (Fork.ext (Iso.refl _) (by simp))
/-- A functor between preadditive categories preserves the equalizer of two
morphisms if it preserves all kernels. -/
def preservesEqualizerOfPreservesKernels [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F]
    {X Y : C} (f g : X ⟶ Y) : PreservesLimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryProducts F
  haveI := additive_of_preservesBinaryBiproducts F
  constructor; intro c i
  let c' := isLimitKernelForkOfFork (i.ofIsoLimit (Fork.isoForkOfι c))
  dsimp only [kernelForkOfFork_ofι] at c'
  let iFc := isLimitForkMapOfIsLimit' F _ c'
  apply IsLimit.ofIsoLimit _ ((Cones.functoriality _ F).mapIso (Fork.isoForkOfι c).symm)
  apply (isLimitMapConeForkEquiv F (Fork.condition c)).invFun
  let p : parallelPair (F.map (f - g)) 0 ≅ parallelPair (F.map f - F.map g) 0 :=
    parallelPair.eqOfHomEq F.map_sub rfl
  exact
    IsLimit.ofIsoLimit
      (isLimitForkOfKernelFork ((IsLimit.postcomposeHomEquiv p _).symm iFc))
      (Fork.ext (Iso.refl _) (by 

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryProducts F
this : Additive F
c : Cone (parallelPair f g)
i : IsLimit c
c' : IsLimit (KernelFork.ofι (Fork.ι c) (_ : Fork.ι c ≫ (f - g) = 0)) :=
  isLimitKernelForkOfFork (IsLimit.ofIsoLimit i (Fork.isoForkOfι c))
iFc : IsLimit (KernelFork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map (f - g) = 0)) :=
  isLimitForkMapOfIsLimit' F (_ : Fork.ι c ≫ (f - g) = 0) c'
p : parallelPair (F.map (f - g)) 0 ≅ parallelPair (F.map f - F.map g) 0 :=
  parallelPair.eqOfHomEq (_ : F.map (f - g) = F.map f - F.map g) (_ : 0 = 0)
⊢ (Iso.refl
          (forkOfKernelFork
              ((Cones.postcompose p.hom).obj
                (KernelFork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map (f - g) = 0)))).pt).hom ≫
      Fork.ι (Fork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map f = F.map (Fork.ι c) ≫ F.map g)) =
    Fork.ι
      (forkOfKernelFork
        ((Cones.postcompose p.hom).obj (KernelFork.ofι (F.map (Fork.ι c)) (_ : F.map (Fork.ι c) ≫ F.map (f - g) = 0))))

Next tactic:
simp
/-- A functor between preadditive categories preserves all equalizers if it preserves all kernels.
-/
def preservesEqualizersOfPreservesKernels
    [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesLimitsOfShape WalkingParallelPair F where
  preservesLimit {K} := by
    

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
K : WalkingParallelPair ⥤ C
⊢ PreservesLimit K F

Next tactic:
letI := preservesEqualizerOfPreservesKernels F (K.map WalkingParallelPairHom.left)
        (K.map WalkingParallelPairHom.right)
/-- A functor between preadditive categories preserves all equalizers if it preserves all kernels.
-/
def preservesEqualizersOfPreservesKernels
    [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesLimitsOfShape WalkingParallelPair F where
  preservesLimit {K} := by
    letI := preservesEqualizerOfPreservesKernels F (K.map WalkingParallelPairHom.left)
        (K.map WalkingParallelPairHom.right)
    

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
K : WalkingParallelPair ⥤ C
this : PreservesLimit (parallelPair (K.map WalkingParallelPairHom.left) (K.map WalkingParallelPairHom.right)) F :=
  preservesEqualizerOfPreservesKernels F (K.map WalkingParallelPairHom.left) (K.map WalkingParallelPairHom.right)
⊢ PreservesLimit K F

Next tactic:
apply preservesLimitOfIsoDiagram F (diagramIsoParallelPair K).symm
/-- A functor between preadditive categories which preserves kernels preserves all finite limits.
-/
def preservesFiniteLimitsOfPreservesKernels [HasFiniteProducts C] [HasEqualizers C]
    [HasZeroObject C] [HasZeroObject D] [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesFiniteLimits F := by
  

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : Preadditive C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : Preadditive D
F : C ⥤ D
inst✝⁶ : PreservesZeroMorphisms F
inst✝⁵ : HasBinaryBiproducts C
inst✝⁴ : HasFiniteProducts C
inst✝³ : HasEqualizers C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroObject D
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
⊢ PreservesFiniteLimits F

Next tactic:
letI := preservesEqualizersOfPreservesKernels F
/-- A functor between preadditive categories which preserves kernels preserves all finite limits.
-/
def preservesFiniteLimitsOfPreservesKernels [HasFiniteProducts C] [HasEqualizers C]
    [HasZeroObject C] [HasZeroObject D] [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesFiniteLimits F := by
  letI := preservesEqualizersOfPreservesKernels F
  

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : Preadditive C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : Preadditive D
F : C ⥤ D
inst✝⁶ : PreservesZeroMorphisms F
inst✝⁵ : HasBinaryBiproducts C
inst✝⁴ : HasFiniteProducts C
inst✝³ : HasEqualizers C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroObject D
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
this : PreservesLimitsOfShape WalkingParallelPair F := preservesEqualizersOfPreservesKernels F
⊢ PreservesFiniteLimits F

Next tactic:
letI := preservesTerminalObjectOfPreservesZeroMorphisms F
/-- A functor between preadditive categories which preserves kernels preserves all finite limits.
-/
def preservesFiniteLimitsOfPreservesKernels [HasFiniteProducts C] [HasEqualizers C]
    [HasZeroObject C] [HasZeroObject D] [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesFiniteLimits F := by
  letI := preservesEqualizersOfPreservesKernels F
  letI := preservesTerminalObjectOfPreservesZeroMorphisms F
  

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : Preadditive C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : Preadditive D
F : C ⥤ D
inst✝⁶ : PreservesZeroMorphisms F
inst✝⁵ : HasBinaryBiproducts C
inst✝⁴ : HasFiniteProducts C
inst✝³ : HasEqualizers C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroObject D
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
this✝ : PreservesLimitsOfShape WalkingParallelPair F := preservesEqualizersOfPreservesKernels F
this : PreservesLimit (empty C) F := preservesTerminalObjectOfPreservesZeroMorphisms F
⊢ PreservesFiniteLimits F

Next tactic:
letI := preservesLimitsOfShapePemptyOfPreservesTerminal F
/-- A functor between preadditive categories which preserves kernels preserves all finite limits.
-/
def preservesFiniteLimitsOfPreservesKernels [HasFiniteProducts C] [HasEqualizers C]
    [HasZeroObject C] [HasZeroObject D] [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesFiniteLimits F := by
  letI := preservesEqualizersOfPreservesKernels F
  letI := preservesTerminalObjectOfPreservesZeroMorphisms F
  letI := preservesLimitsOfShapePemptyOfPreservesTerminal F
  

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : Preadditive C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : Preadditive D
F : C ⥤ D
inst✝⁶ : PreservesZeroMorphisms F
inst✝⁵ : HasBinaryBiproducts C
inst✝⁴ : HasFiniteProducts C
inst✝³ : HasEqualizers C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroObject D
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
this✝¹ : PreservesLimitsOfShape WalkingParallelPair F := preservesEqualizersOfPreservesKernels F
this✝ : PreservesLimit (empty C) F := preservesTerminalObjectOfPreservesZeroMorphisms F
this : PreservesLimitsOfShape (Discrete PEmpty.{1}) F := preservesLimitsOfShapePemptyOfPreservesTerminal F
⊢ PreservesFiniteLimits F

Next tactic:
letI : PreservesFiniteProducts F := ⟨preservesFiniteProductsOfPreservesBinaryAndTerminal F⟩
/-- A functor between preadditive categories which preserves kernels preserves all finite limits.
-/
def preservesFiniteLimitsOfPreservesKernels [HasFiniteProducts C] [HasEqualizers C]
    [HasZeroObject C] [HasZeroObject D] [∀ {X Y} (f : X ⟶ Y), PreservesLimit (parallelPair f 0) F] :
    PreservesFiniteLimits F := by
  letI := preservesEqualizersOfPreservesKernels F
  letI := preservesTerminalObjectOfPreservesZeroMorphisms F
  letI := preservesLimitsOfShapePemptyOfPreservesTerminal F
  letI : PreservesFiniteProducts F := ⟨preservesFiniteProductsOfPreservesBinaryAndTerminal F⟩
  

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : Preadditive C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : Preadditive D
F : C ⥤ D
inst✝⁶ : PreservesZeroMorphisms F
inst✝⁵ : HasBinaryBiproducts C
inst✝⁴ : HasFiniteProducts C
inst✝³ : HasEqualizers C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroObject D
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
this✝² : PreservesLimitsOfShape WalkingParallelPair F := preservesEqualizersOfPreservesKernels F
this✝¹ : PreservesLimit (empty C) F := preservesTerminalObjectOfPreservesZeroMorphisms F
this✝ : PreservesLimitsOfShape (Discrete PEmpty.{1}) F := preservesLimitsOfShapePemptyOfPreservesTerminal F
this : PreservesFiniteProducts F := { preserves := preservesFiniteProductsOfPreservesBinaryAndTerminal F }
⊢ PreservesFiniteLimits F

Next tactic:
exact preservesFiniteLimitsOfPreservesEqualizersAndFiniteProducts F
/-- A functor between preadditive categories which preserves cokernels preserves finite coproducts.
-/
def isColimitMapCoconeBinaryCofanOfPreservesCokernels {X Y Z : C} (ι₁ : X ⟶ Z) (ι₂ : Y ⟶ Z)
    [PreservesColimit (parallelPair ι₂ 0) F] (i : IsColimit (BinaryCofan.mk ι₁ ι₂)) :
    IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂)) := by
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Preadditive C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Preadditive D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
X Y Z : C
ι₁ : X ⟶ Z
ι₂ : Y ⟶ Z
inst✝ : PreservesColimit (parallelPair ι₂ 0) F
i : IsColimit (BinaryCofan.mk ι₁ ι₂)
⊢ IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂))

Next tactic:
let bc := BinaryBicone.ofColimitCocone i
/-- A functor between preadditive categories which preserves cokernels preserves finite coproducts.
-/
def isColimitMapCoconeBinaryCofanOfPreservesCokernels {X Y Z : C} (ι₁ : X ⟶ Z) (ι₂ : Y ⟶ Z)
    [PreservesColimit (parallelPair ι₂ 0) F] (i : IsColimit (BinaryCofan.mk ι₁ ι₂)) :
    IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂)) := by
  let bc := BinaryBicone.ofColimitCocone i
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Preadditive C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Preadditive D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
X Y Z : C
ι₁ : X ⟶ Z
ι₂ : Y ⟶ Z
inst✝ : PreservesColimit (parallelPair ι₂ 0) F
i : IsColimit (BinaryCofan.mk ι₁ ι₂)
bc : BinaryBicone X Y := BinaryBicone.ofColimitCocone i
⊢ IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂))

Next tactic:
let presf : PreservesColimit (parallelPair bc.inr 0) F := by simpa
/-- A functor between preadditive categories which preserves cokernels preserves finite coproducts.
-/
def isColimitMapCoconeBinaryCofanOfPreservesCokernels {X Y Z : C} (ι₁ : X ⟶ Z) (ι₂ : Y ⟶ Z)
    [PreservesColimit (parallelPair ι₂ 0) F] (i : IsColimit (BinaryCofan.mk ι₁ ι₂)) :
    IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂)) := by
  let bc := BinaryBicone.ofColimitCocone i
  let presf : PreservesColimit (parallelPair bc.inr 0) F := by 

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Preadditive C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Preadditive D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
X Y Z : C
ι₁ : X ⟶ Z
ι₂ : Y ⟶ Z
inst✝ : PreservesColimit (parallelPair ι₂ 0) F
i : IsColimit (BinaryCofan.mk ι₁ ι₂)
bc : BinaryBicone X Y := BinaryBicone.ofColimitCocone i
⊢ PreservesColimit (parallelPair bc.inr 0) F

Next tactic:
simpa
/-- A functor between preadditive categories which preserves cokernels preserves finite coproducts.
-/
def isColimitMapCoconeBinaryCofanOfPreservesCokernels {X Y Z : C} (ι₁ : X ⟶ Z) (ι₂ : Y ⟶ Z)
    [PreservesColimit (parallelPair ι₂ 0) F] (i : IsColimit (BinaryCofan.mk ι₁ ι₂)) :
    IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂)) := by
  let bc := BinaryBicone.ofColimitCocone i
  let presf : PreservesColimit (parallelPair bc.inr 0) F := by simpa
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Preadditive C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Preadditive D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
X Y Z : C
ι₁ : X ⟶ Z
ι₂ : Y ⟶ Z
inst✝ : PreservesColimit (parallelPair ι₂ 0) F
i : IsColimit (BinaryCofan.mk ι₁ ι₂)
bc : BinaryBicone X Y := BinaryBicone.ofColimitCocone i
presf : PreservesColimit (parallelPair bc.inr 0) F := id inst✝
⊢ IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂))

Next tactic:
let hf : IsColimit bc.inrCokernelCofork := BinaryBicone.isColimitInrCokernelCofork i
/-- A functor between preadditive categories which preserves cokernels preserves finite coproducts.
-/
def isColimitMapCoconeBinaryCofanOfPreservesCokernels {X Y Z : C} (ι₁ : X ⟶ Z) (ι₂ : Y ⟶ Z)
    [PreservesColimit (parallelPair ι₂ 0) F] (i : IsColimit (BinaryCofan.mk ι₁ ι₂)) :
    IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂)) := by
  let bc := BinaryBicone.ofColimitCocone i
  let presf : PreservesColimit (parallelPair bc.inr 0) F := by simpa
  let hf : IsColimit bc.inrCokernelCofork := BinaryBicone.isColimitInrCokernelCofork i
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Preadditive C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Preadditive D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
X Y Z : C
ι₁ : X ⟶ Z
ι₂ : Y ⟶ Z
inst✝ : PreservesColimit (parallelPair ι₂ 0) F
i : IsColimit (BinaryCofan.mk ι₁ ι₂)
bc : BinaryBicone X Y := BinaryBicone.ofColimitCocone i
presf : PreservesColimit (parallelPair bc.inr 0) F := id inst✝
hf : IsColimit (BinaryBicone.inrCokernelCofork bc) := BinaryBicone.isColimitInrCokernelCofork i
⊢ IsColimit (F.mapCocone (BinaryCofan.mk ι₁ ι₂))

Next tactic:
exact
    (isColimitMapCoconeBinaryCofanEquiv F ι₁ ι₂).invFun
      (BinaryBicone.isBilimitOfCokernelFst (F.mapBinaryBicone bc)
          (isColimitMapCoconeCoforkEquiv' F bc.inr_fst (isColimitOfPreserves F hf))).isColimit
/-- A functor between preadditive categories preserves the coequalizer of two
morphisms if it preserves all cokernels. -/
def preservesCoequalizerOfPreservesCokernels
    [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) F] {X Y : C} (f g : X ⟶ Y) :
    PreservesColimit (parallelPair f g) F := by
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
⊢ PreservesColimit (parallelPair f g) F

Next tactic:
letI := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
/-- A functor between preadditive categories preserves the coequalizer of two
morphisms if it preserves all cokernels. -/
def preservesCoequalizerOfPreservesCokernels
    [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) F] {X Y : C} (f g : X ⟶ Y) :
    PreservesColimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
⊢ PreservesColimit (parallelPair f g) F

Next tactic:
haveI := additive_of_preservesBinaryBiproducts F
/-- A functor between preadditive categories preserves the coequalizer of two
morphisms if it preserves all cokernels. -/
def preservesCoequalizerOfPreservesCokernels
    [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) F] {X Y : C} (f g : X ⟶ Y) :
    PreservesColimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
  haveI := additive_of_preservesBinaryBiproducts F
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
this : Additive F
⊢ PreservesColimit (parallelPair f g) F

Next tactic:
constructor
/-- A functor between preadditive categories preserves the coequalizer of two
morphisms if it preserves all cokernels. -/
def preservesCoequalizerOfPreservesCokernels
    [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) F] {X Y : C} (f g : X ⟶ Y) :
    PreservesColimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
  haveI := additive_of_preservesBinaryBiproducts F
  constructor
  

Proof state:
case preserves
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
this : Additive F
⊢ {c : Cocone (parallelPair f g)} → IsColimit c → IsColimit (F.mapCocone c)

Next tactic:
intro c i
/-- A functor between preadditive categories preserves the coequalizer of two
morphisms if it preserves all cokernels. -/
def preservesCoequalizerOfPreservesCokernels
    [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) F] {X Y : C} (f g : X ⟶ Y) :
    PreservesColimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
  haveI := additive_of_preservesBinaryBiproducts F
  constructor
  intro c i
  

Proof state:
case preserves
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
this : Additive F
c : Cocone (parallelPair f g)
i : IsColimit c
⊢ IsColimit (F.mapCocone c)

Next tactic:
let c' := isColimitCokernelCoforkOfCofork (i.ofIsoColimit (Cofork.isoCoforkOfπ c))
/-- A functor between preadditive categories preserves the coequalizer of two
morphisms if it preserves all cokernels. -/
def preservesCoequalizerOfPreservesCokernels
    [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) F] {X Y : C} (f g : X ⟶ Y) :
    PreservesColimit (parallelPair f g) F := by
  letI := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
  haveI := additive_of_preservesBinaryBiproducts F
  constructor
  intro c i
  let c' := isColimitCokernelCoforkOfCofork (i.ofIsoColimit (Cofork.isoCoforkOfπ c))
  

Proof state:
case preserves
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : Preadditive C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : Preadditive D
F : C ⥤ D
inst✝² : PreservesZeroMorphisms F
inst✝¹ : HasBinaryBiproducts C
inst✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
X Y : C
f g : X ⟶ Y
this✝ : PreservesBinaryBiproducts F := preservesBinaryBiproductsOfPreservesBinaryCoproducts F
this : Additive F
c : Cocone (parallelPair f g)
i : IsColimit c
c' : IsColimit (cokernelCoforkOfCofork (Cofork.ofπ (Cofork.π c) (_ : f ≫ Cofork.π c = g ≫ Cofork.π c))) :=
  isColimitCokernelCoforkOfCofork (IsColimit.ofIsoColimit i (Cofork.isoCoforkOfπ c))
⊢ IsColimit (F.mapCocone c)

Next tactic:
dsimp only [cokernelCoforkOfCofork_ofπ] at c'