l3lab/ntp-mathlib huggingface dataset:
/-- A functor preserving finite limits and finite colimits preserves exactness. The converse
result is also true, see `Functor.preservesFiniteLimitsOfMapExact` and
`Functor.preservesFiniteColimitsOfMapExact`. -/
theorem map_exact {X Y Z : A} (f : X ⟶ Y) (g : Y ⟶ Z) (e1 : Exact f g) :
    Exact (L.map f) (L.map g) := by
  let hcoker := isColimitOfHasCokernelOfPreservesColimit L f
  let hker := isLimitOfHasKernelOfPreservesLimit L g
  refine' (exact_iff' _ _ hker hcoker).2 ⟨by simp [← L.map_comp, e1.1], _⟩
  

Proof state:
C : Type u₁
inst✝⁷ : Category.{v₁, u₁} C
inst✝⁶ : Abelian C
A : Type u₁
B : Type u₂
inst✝⁵ : Category.{v₁, u₁} A
inst✝⁴ : Category.{v₂, u₂} B
inst✝³ : Abelian A
inst✝² : Abelian B
L : A ⥤ B
inst✝¹ : PreservesFiniteLimits L
inst✝ : PreservesFiniteColimits L
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
e1 : Exact f g
hcoker : IsColimit
  (Cofork.ofπ (L.map (cokernel.π f)) (_ : L.map f ≫ L.map (cokernel.π f) = 0 ≫ L.map (cokernel.π f))) :=
  isColimitOfHasCokernelOfPreservesColimit L f
hker : IsLimit (Fork.ofι (L.map (kernel.ι g)) (_ : L.map (kernel.ι g) ≫ L.map g = L.map (kernel.ι g) ≫ 0)) :=
  isLimitOfHasKernelOfPreservesLimit L g
⊢ Fork.ι (Fork.ofι (L.map (kernel.ι g)) (_ : L.map (kernel.ι g) ≫ L.map g = L.map (kernel.ι g) ≫ 0)) ≫
      Cofork.π (Cofork.ofπ (L.map (cokernel.π f)) (_ : L.map f ≫ L.map (cokernel.π f) = 0 ≫ L.map (cokernel.π f))) =
    0

Next tactic:
simp only [Fork.ι_ofι, Cofork.π_ofπ, ← L.map_comp, kernel_comp_cokernel _ _ e1, L.map_zero]
/-- A functor which preserves exactness preserves zero morphisms. -/
theorem preservesZeroMorphisms_of_map_exact : L.PreservesZeroMorphisms := by
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
⊢ PreservesZeroMorphisms L

Next tactic:
replace h := (h (exact_of_zero (𝟙 0) (𝟙 0))).w
/-- A functor which preserves exactness preserves zero morphisms. -/
theorem preservesZeroMorphisms_of_map_exact : L.PreservesZeroMorphisms := by
  replace h := (h (exact_of_zero (𝟙 0) (𝟙 0))).w
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : L.map (𝟙 0) ≫ L.map (𝟙 0) = 0
⊢ PreservesZeroMorphisms L

Next tactic:
rw [L.map_id, Category.comp_id] at h
/-- A functor which preserves exactness preserves zero morphisms. -/
theorem preservesZeroMorphisms_of_map_exact : L.PreservesZeroMorphisms := by
  replace h := (h (exact_of_zero (𝟙 0) (𝟙 0))).w
  rw [L.map_id, Category.comp_id] at h
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : 𝟙 (L.obj 0) = 0
⊢ PreservesZeroMorphisms L

Next tactic:
exact preservesZeroMorphisms_of_map_zero_object (idZeroEquivIsoZero _ h)
/-- A functor which preserves exactness preserves monomorphisms. -/
theorem preservesMonomorphisms_of_map_exact : L.PreservesMonomorphisms where
  preserves f hf := by
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Mono f
⊢ Mono (L.map f)

Next tactic:
letI := preservesZeroMorphisms_of_map_exact L h
/-- A functor which preserves exactness preserves monomorphisms. -/
theorem preservesMonomorphisms_of_map_exact : L.PreservesMonomorphisms where
  preserves f hf := by
    letI := preservesZeroMorphisms_of_map_exact L h
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Mono f
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ Mono (L.map f)

Next tactic:
apply ((tfae_mono (L.obj 0) (L.map f)).out 2 0).mp
/-- A functor which preserves exactness preserves monomorphisms. -/
theorem preservesMonomorphisms_of_map_exact : L.PreservesMonomorphisms where
  preserves f hf := by
    letI := preservesZeroMorphisms_of_map_exact L h
    apply ((tfae_mono (L.obj 0) (L.map f)).out 2 0).mp
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Mono f
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ Exact 0 (L.map f)

Next tactic:
rw [← L.map_zero]
/-- A functor which preserves exactness preserves monomorphisms. -/
theorem preservesMonomorphisms_of_map_exact : L.PreservesMonomorphisms where
  preserves f hf := by
    letI := preservesZeroMorphisms_of_map_exact L h
    apply ((tfae_mono (L.obj 0) (L.map f)).out 2 0).mp
    rw [← L.map_zero]
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Mono f
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ Exact (L.map 0) (L.map f)

Next tactic:
exact h (((tfae_mono 0 f).out 0 2).mp hf)
/-- A functor which preserves exactness preserves epimorphisms. -/
theorem preservesEpimorphisms_of_map_exact : L.PreservesEpimorphisms where
  preserves f hf := by
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Epi f
⊢ Epi (L.map f)

Next tactic:
letI := preservesZeroMorphisms_of_map_exact L h
/-- A functor which preserves exactness preserves epimorphisms. -/
theorem preservesEpimorphisms_of_map_exact : L.PreservesEpimorphisms where
  preserves f hf := by
    letI := preservesZeroMorphisms_of_map_exact L h
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Epi f
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ Epi (L.map f)

Next tactic:
apply ((tfae_epi (L.obj 0) (L.map f)).out 2 0).mp
/-- A functor which preserves exactness preserves epimorphisms. -/
theorem preservesEpimorphisms_of_map_exact : L.PreservesEpimorphisms where
  preserves f hf := by
    letI := preservesZeroMorphisms_of_map_exact L h
    apply ((tfae_epi (L.obj 0) (L.map f)).out 2 0).mp
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Epi f
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ Exact (L.map f) 0

Next tactic:
rw [← L.map_zero]
/-- A functor which preserves exactness preserves epimorphisms. -/
theorem preservesEpimorphisms_of_map_exact : L.PreservesEpimorphisms where
  preserves f hf := by
    letI := preservesZeroMorphisms_of_map_exact L h
    apply ((tfae_epi (L.obj 0) (L.map f)).out 2 0).mp
    rw [← L.map_zero]
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X✝ Y✝ : A
f : X✝ ⟶ Y✝
hf : Epi f
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ Exact (L.map f) (L.map 0)

Next tactic:
exact h (((tfae_epi 0 f).out 0 2).mp hf)
/-- A functor which preserves exactness preserves kernels. -/
def preservesKernelsOfMapExact (X Y : A) (f : X ⟶ Y) : PreservesLimit (parallelPair f 0) L where
  preserves {c} ic := by
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cone (parallelPair f 0)
ic : IsLimit c
⊢ IsLimit (L.mapCone c)

Next tactic:
letI := preservesZeroMorphisms_of_map_exact L h
/-- A functor which preserves exactness preserves kernels. -/
def preservesKernelsOfMapExact (X Y : A) (f : X ⟶ Y) : PreservesLimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cone (parallelPair f 0)
ic : IsLimit c
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ IsLimit (L.mapCone c)

Next tactic:
letI := preservesMonomorphisms_of_map_exact L h
/-- A functor which preserves exactness preserves kernels. -/
def preservesKernelsOfMapExact (X Y : A) (f : X ⟶ Y) : PreservesLimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    letI := preservesMonomorphisms_of_map_exact L h
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cone (parallelPair f 0)
ic : IsLimit c
this✝ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this : PreservesMonomorphisms L := preservesMonomorphisms_of_map_exact L h
⊢ IsLimit (L.mapCone c)

Next tactic:
letI := mono_of_isLimit_fork ic
/-- A functor which preserves exactness preserves kernels. -/
def preservesKernelsOfMapExact (X Y : A) (f : X ⟶ Y) : PreservesLimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    letI := preservesMonomorphisms_of_map_exact L h
    letI := mono_of_isLimit_fork ic
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cone (parallelPair f 0)
ic : IsLimit c
this✝¹ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this✝ : PreservesMonomorphisms L := preservesMonomorphisms_of_map_exact L h
this : Mono (Fork.ι c) := mono_of_isLimit_fork ic
⊢ IsLimit (L.mapCone c)

Next tactic:
have hf :=
      (isLimitMapConeForkEquiv' L (KernelFork.condition c)).symm
        (isLimitOfExactOfMono (L.map (Fork.ι c)) (L.map f)
          (h (exact_of_is_kernel (Fork.ι c) f (KernelFork.condition c)
              (ic.ofIsoLimit (isoOfι _)))))
/-- A functor which preserves exactness preserves kernels. -/
def preservesKernelsOfMapExact (X Y : A) (f : X ⟶ Y) : PreservesLimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    letI := preservesMonomorphisms_of_map_exact L h
    letI := mono_of_isLimit_fork ic
    have hf :=
      (isLimitMapConeForkEquiv' L (KernelFork.condition c)).symm
        (isLimitOfExactOfMono (L.map (Fork.ι c)) (L.map f)
          (h (exact_of_is_kernel (Fork.ι c) f (KernelFork.condition c)
              (ic.ofIsoLimit (isoOfι _)))))
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cone (parallelPair f 0)
ic : IsLimit c
this✝¹ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this✝ : PreservesMonomorphisms L := preservesMonomorphisms_of_map_exact L h
this : Mono (Fork.ι c) := mono_of_isLimit_fork ic
hf : IsLimit (L.mapCone (KernelFork.ofι (Fork.ι c) (_ : Fork.ι c ≫ f = 0)))
⊢ IsLimit (L.mapCone c)

Next tactic:
exact hf.ofIsoLimit ((Cones.functoriality _ L).mapIso (isoOfι _).symm)
/-- A functor which preserves exactness preserves zero cokernels. -/
def preservesCokernelsOfMapExact (X Y : A) (f : X ⟶ Y) :
    PreservesColimit (parallelPair f 0) L where
  preserves {c} ic := by
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cocone (parallelPair f 0)
ic : IsColimit c
⊢ IsColimit (L.mapCocone c)

Next tactic:
letI := preservesZeroMorphisms_of_map_exact L h
/-- A functor which preserves exactness preserves zero cokernels. -/
def preservesCokernelsOfMapExact (X Y : A) (f : X ⟶ Y) :
    PreservesColimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cocone (parallelPair f 0)
ic : IsColimit c
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ IsColimit (L.mapCocone c)

Next tactic:
letI := preservesEpimorphisms_of_map_exact L h
/-- A functor which preserves exactness preserves zero cokernels. -/
def preservesCokernelsOfMapExact (X Y : A) (f : X ⟶ Y) :
    PreservesColimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    letI := preservesEpimorphisms_of_map_exact L h
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cocone (parallelPair f 0)
ic : IsColimit c
this✝ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this : PreservesEpimorphisms L := preservesEpimorphisms_of_map_exact L h
⊢ IsColimit (L.mapCocone c)

Next tactic:
letI := epi_of_isColimit_cofork ic
/-- A functor which preserves exactness preserves zero cokernels. -/
def preservesCokernelsOfMapExact (X Y : A) (f : X ⟶ Y) :
    PreservesColimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    letI := preservesEpimorphisms_of_map_exact L h
    letI := epi_of_isColimit_cofork ic
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cocone (parallelPair f 0)
ic : IsColimit c
this✝¹ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this✝ : PreservesEpimorphisms L := preservesEpimorphisms_of_map_exact L h
this : Epi (Cofork.π c) := epi_of_isColimit_cofork ic
⊢ IsColimit (L.mapCocone c)

Next tactic:
have hf :=
      (isColimitMapCoconeCoforkEquiv' L (CokernelCofork.condition c)).symm
        (isColimitOfExactOfEpi (L.map f) (L.map (Cofork.π c))
          (h (exact_of_is_cokernel f (Cofork.π c) (CokernelCofork.condition c)
              (ic.ofIsoColimit (isoOfπ _)))))
/-- A functor which preserves exactness preserves zero cokernels. -/
def preservesCokernelsOfMapExact (X Y : A) (f : X ⟶ Y) :
    PreservesColimit (parallelPair f 0) L where
  preserves {c} ic := by
    letI := preservesZeroMorphisms_of_map_exact L h
    letI := preservesEpimorphisms_of_map_exact L h
    letI := epi_of_isColimit_cofork ic
    have hf :=
      (isColimitMapCoconeCoforkEquiv' L (CokernelCofork.condition c)).symm
        (isColimitOfExactOfEpi (L.map f) (L.map (Cofork.π c))
          (h (exact_of_is_cokernel f (Cofork.π c) (CokernelCofork.condition c)
              (ic.ofIsoColimit (isoOfπ _)))))
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
X Y : A
f : X ⟶ Y
c : Cocone (parallelPair f 0)
ic : IsColimit c
this✝¹ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this✝ : PreservesEpimorphisms L := preservesEpimorphisms_of_map_exact L h
this : Epi (Cofork.π c) := epi_of_isColimit_cofork ic
hf : IsColimit (L.mapCocone (CokernelCofork.ofπ (Cofork.π c) (_ : f ≫ Cofork.π c = 0)))
⊢ IsColimit (L.mapCocone c)

Next tactic:
exact hf.ofIsoColimit ((Cocones.functoriality _ L).mapIso (isoOfπ _).symm)
/-- A functor which preserves exactness is left exact, i.e. preserves finite limits.
This is part of the inverse implication to `Functor.map_exact`. -/
def preservesFiniteLimitsOfMapExact : PreservesFiniteLimits L := by
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
⊢ PreservesFiniteLimits L

Next tactic:
letI := preservesZeroMorphisms_of_map_exact L h
/-- A functor which preserves exactness is left exact, i.e. preserves finite limits.
This is part of the inverse implication to `Functor.map_exact`. -/
def preservesFiniteLimitsOfMapExact : PreservesFiniteLimits L := by
  letI := preservesZeroMorphisms_of_map_exact L h
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ PreservesFiniteLimits L

Next tactic:
letI := preservesKernelsOfMapExact L h
/-- A functor which preserves exactness is left exact, i.e. preserves finite limits.
This is part of the inverse implication to `Functor.map_exact`. -/
def preservesFiniteLimitsOfMapExact : PreservesFiniteLimits L := by
  letI := preservesZeroMorphisms_of_map_exact L h
  letI := preservesKernelsOfMapExact L h
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
this✝ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this : (X Y : A) → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) L := preservesKernelsOfMapExact L h
⊢ PreservesFiniteLimits L

Next tactic:
apply preservesFiniteLimitsOfPreservesKernels
/-- A functor which preserves exactness is right exact, i.e. preserves finite colimits.
This is part of the inverse implication to `Functor.map_exact`. -/
def preservesFiniteColimitsOfMapExact : PreservesFiniteColimits L := by
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
⊢ PreservesFiniteColimits L

Next tactic:
letI := preservesZeroMorphisms_of_map_exact L h
/-- A functor which preserves exactness is right exact, i.e. preserves finite colimits.
This is part of the inverse implication to `Functor.map_exact`. -/
def preservesFiniteColimitsOfMapExact : PreservesFiniteColimits L := by
  letI := preservesZeroMorphisms_of_map_exact L h
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
this : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
⊢ PreservesFiniteColimits L

Next tactic:
letI := preservesCokernelsOfMapExact L h
/-- A functor which preserves exactness is right exact, i.e. preserves finite colimits.
This is part of the inverse implication to `Functor.map_exact`. -/
def preservesFiniteColimitsOfMapExact : PreservesFiniteColimits L := by
  letI := preservesZeroMorphisms_of_map_exact L h
  letI := preservesCokernelsOfMapExact L h
  

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
A : Type u₁
B : Type u₂
inst✝³ : Category.{v₁, u₁} A
inst✝² : Category.{v₂, u₂} B
inst✝¹ : Abelian A
inst✝ : Abelian B
L : A ⥤ B
h : ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)
this✝ : PreservesZeroMorphisms L := preservesZeroMorphisms_of_map_exact L h
this : (X Y : A) → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) L := preservesCokernelsOfMapExact L h
⊢ PreservesFiniteColimits L

Next tactic:
apply preservesFiniteColimitsOfPreservesCokernels
/-- A functor preserving zero morphisms, monos, and cokernels preserves finite limits. -/
def preservesFiniteLimitsOfPreservesMonosAndCokernels [PreservesZeroMorphisms L]
    [PreservesMonomorphisms L] [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) L] :
    PreservesFiniteLimits L := by
  

Proof state:
C : Type u₁
inst✝⁸ : Category.{v₁, u₁} C
inst✝⁷ : Abelian C
A : Type u₁
B : Type u₂
inst✝⁶ : Category.{v₁, u₁} A
inst✝⁵ : Category.{v₂, u₂} B
inst✝⁴ : Abelian A
inst✝³ : Abelian B
L : A ⥤ B
inst✝² : PreservesZeroMorphisms L
inst✝¹ : PreservesMonomorphisms L
inst✝ : {X Y : A} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) L
⊢ PreservesFiniteLimits L

Next tactic:
apply preservesFiniteLimitsOfMapExact
/-- A functor preserving zero morphisms, monos, and cokernels preserves finite limits. -/
def preservesFiniteLimitsOfPreservesMonosAndCokernels [PreservesZeroMorphisms L]
    [PreservesMonomorphisms L] [∀ {X Y} (f : X ⟶ Y), PreservesColimit (parallelPair f 0) L] :
    PreservesFiniteLimits L := by
  apply preservesFiniteLimitsOfMapExact
  

Proof state:
case h
C : Type u₁
inst✝⁸ : Category.{v₁, u₁} C
inst✝⁷ : Abelian C
A : Type u₁
B : Type u₂
inst✝⁶ : Category.{v₁, u₁} A
inst✝⁵ : Category.{v₂, u₂} B
inst✝⁴ : Abelian A
inst✝³ : Abelian B
L : A ⥤ B
inst✝² : PreservesZeroMorphisms L
inst✝¹ : PreservesMonomorphisms L
inst✝ : {X Y : A} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) L
⊢ ∀ ⦃X Y Z : A⦄ {f : X ⟶ Y} {g : Y ⟶ Z}, Exact f g → Exact (L.map f) (L.map g)

Next tactic:
intro X Y Z f g h