l3lab/ntp-mathlib huggingface dataset:
theorem exact_iff_exact_coimage_π : Exact f g ↔ Exact f (coimage.π g) := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact f g ↔ Exact f (coimage.π g)

Next tactic:
conv_lhs => rw [← Abelian.coimage.fac g]
theorem exact_iff_exact_coimage_π : Exact f g ↔ Exact f (coimage.π g) := by
  conv_lhs => 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
| Exact f g

Next tactic:
rw [← Abelian.coimage.fac g]
theorem exact_iff_exact_coimage_π : Exact f g ↔ Exact f (coimage.π g) := by
  conv_lhs => rw [← Abelian.coimage.fac g]
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact f (coimage.π g ≫ Abelian.factorThruCoimage g) ↔ Exact f (coimage.π g)

Next tactic:
rw [exact_comp_mono_iff]
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ TFAE [Mono f, kernel.ι f = 0, Exact 0 f]

Next tactic:
tfae_have 3 → 2
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · 

Proof state:
case tfae_3_to_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact 0 f → kernel.ι f = 0

Next tactic:
exact kernel_ι_eq_zero_of_exact_zero_left Z
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · exact kernel_ι_eq_zero_of_exact_zero_left Z
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact 0 f → kernel.ι f = 0
⊢ TFAE [Mono f, kernel.ι f = 0, Exact 0 f]

Next tactic:
tfae_have 1 → 3
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · exact kernel_ι_eq_zero_of_exact_zero_left Z
  tfae_have 1 → 3
  · 

Proof state:
case tfae_1_to_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact 0 f → kernel.ι f = 0
⊢ Mono f → Exact 0 f

Next tactic:
intros
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · exact kernel_ι_eq_zero_of_exact_zero_left Z
  tfae_have 1 → 3
  · intros
    

Proof state:
case tfae_1_to_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact 0 f → kernel.ι f = 0
✝ : Mono f
⊢ Exact 0 f

Next tactic:
exact exact_zero_left_of_mono Z
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · exact kernel_ι_eq_zero_of_exact_zero_left Z
  tfae_have 1 → 3
  · intros
    exact exact_zero_left_of_mono Z
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact 0 f → kernel.ι f = 0
tfae_1_to_3 : Mono f → Exact 0 f
⊢ TFAE [Mono f, kernel.ι f = 0, Exact 0 f]

Next tactic:
tfae_have 2 → 1
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · exact kernel_ι_eq_zero_of_exact_zero_left Z
  tfae_have 1 → 3
  · intros
    exact exact_zero_left_of_mono Z
  tfae_have 2 → 1
  · 

Proof state:
case tfae_2_to_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact 0 f → kernel.ι f = 0
tfae_1_to_3 : Mono f → Exact 0 f
⊢ kernel.ι f = 0 → Mono f

Next tactic:
exact mono_of_kernel_ι_eq_zero _
open List in
theorem tfae_mono : TFAE [Mono f, kernel.ι f = 0, Exact (0 : Z ⟶ X) f] := by
  tfae_have 3 → 2
  · exact kernel_ι_eq_zero_of_exact_zero_left Z
  tfae_have 1 → 3
  · intros
    exact exact_zero_left_of_mono Z
  tfae_have 2 → 1
  · exact mono_of_kernel_ι_eq_zero _
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact 0 f → kernel.ι f = 0
tfae_1_to_3 : Mono f → Exact 0 f
tfae_2_to_1 : kernel.ι f = 0 → Mono f
⊢ TFAE [Mono f, kernel.ι f = 0, Exact 0 f]

Next tactic:
tfae_finish
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ TFAE [Epi f, cokernel.π f = 0, Exact f 0]

Next tactic:
tfae_have 3 → 2
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · 

Proof state:
case tfae_3_to_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact f 0 → cokernel.π f = 0

Next tactic:
rw [exact_iff]
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    

Proof state:
case tfae_3_to_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ f ≫ 0 = 0 ∧ kernel.ι 0 ≫ cokernel.π f = 0 → cokernel.π f = 0

Next tactic:
rintro ⟨-, h⟩
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    

Proof state:
case tfae_3_to_2.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : kernel.ι 0 ≫ cokernel.π f = 0
⊢ cokernel.π f = 0

Next tactic:
exact zero_of_epi_comp _ h
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
⊢ TFAE [Epi f, cokernel.π f = 0, Exact f 0]

Next tactic:
tfae_have 1 → 3
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · 

Proof state:
case tfae_1_to_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
⊢ Epi f → Exact f 0

Next tactic:
rw [exact_iff]
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    

Proof state:
case tfae_1_to_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
⊢ Epi f → f ≫ 0 = 0 ∧ kernel.ι 0 ≫ cokernel.π f = 0

Next tactic:
intro
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    intro
    

Proof state:
case tfae_1_to_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
✝ : Epi f
⊢ f ≫ 0 = 0 ∧ kernel.ι 0 ≫ cokernel.π f = 0

Next tactic:
exact ⟨by simp, by simp [cokernel.π_of_epi]⟩
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    intro
    exact ⟨by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
✝ : Epi f
⊢ f ≫ 0 = 0

Next tactic:
simp
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    intro
    exact ⟨by simp, by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
✝ : Epi f
⊢ kernel.ι 0 ≫ cokernel.π f = 0

Next tactic:
simp [cokernel.π_of_epi]
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    intro
    exact ⟨by simp, by simp [cokernel.π_of_epi]⟩
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
tfae_1_to_3 : Epi f → Exact f 0
⊢ TFAE [Epi f, cokernel.π f = 0, Exact f 0]

Next tactic:
tfae_have 2 → 1
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    intro
    exact ⟨by simp, by simp [cokernel.π_of_epi]⟩
  tfae_have 2 → 1
  · 

Proof state:
case tfae_2_to_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
tfae_1_to_3 : Epi f → Exact f 0
⊢ cokernel.π f = 0 → Epi f

Next tactic:
exact epi_of_cokernel_π_eq_zero _
open List in
theorem tfae_epi : TFAE [Epi f, cokernel.π f = 0, Exact f (0 : Y ⟶ Z)] := by
  tfae_have 3 → 2
  · rw [exact_iff]
    rintro ⟨-, h⟩
    exact zero_of_epi_comp _ h
  tfae_have 1 → 3
  · rw [exact_iff]
    intro
    exact ⟨by simp, by simp [cokernel.π_of_epi]⟩
  tfae_have 2 → 1
  · exact epi_of_cokernel_π_eq_zero _
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
tfae_3_to_2 : Exact f 0 → cokernel.π f = 0
tfae_1_to_3 : Epi f → Exact f 0
tfae_2_to_1 : cokernel.π f = 0 → Epi f
⊢ TFAE [Epi f, cokernel.π f = 0, Exact f 0]

Next tactic:
tfae_finish
theorem Exact.op (h : Exact f g) : Exact g.op f.op := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : Exact f g
⊢ Exact g.op f.op

Next tactic:
rw [exact_iff]
theorem Exact.op (h : Exact f g) : Exact g.op f.op := by
  rw [exact_iff]
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : Exact f g
⊢ g.op ≫ f.op = 0 ∧ kernel.ι f.op ≫ cokernel.π g.op = 0

Next tactic:
refine' ⟨by simp [← op_comp, h.w], Quiver.Hom.unop_inj _⟩
theorem Exact.op (h : Exact f g) : Exact g.op f.op := by
  rw [exact_iff]
  refine' ⟨by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : Exact f g
⊢ g.op ≫ f.op = 0

Next tactic:
simp [← op_comp, h.w]
theorem Exact.op (h : Exact f g) : Exact g.op f.op := by
  rw [exact_iff]
  refine' ⟨by simp [← op_comp, h.w], Quiver.Hom.unop_inj _⟩
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : Exact f g
⊢ (kernel.ι f.op ≫ cokernel.π g.op).unop = 0.unop

Next tactic:
simp only [unop_comp, cokernel.π_op, eqToHom_refl, kernel.ι_op, Category.id_comp,
    Category.assoc, kernel_comp_cokernel_assoc _ _ h, zero_comp, comp_zero, unop_zero]
theorem Exact.op_iff : Exact g.op f.op ↔ Exact f g :=
  ⟨fun e => by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
e : Exact g.op f.op
⊢ Exact f g

Next tactic:
rw [← IsEquivalence.exact_iff _ _ (opOpEquivalence C).inverse]
theorem Exact.op_iff : Exact g.op f.op ↔ Exact f g :=
  ⟨fun e => by
    rw [← IsEquivalence.exact_iff _ _ (opOpEquivalence C).inverse]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
e : Exact g.op f.op
⊢ Exact ((opOpEquivalence C).inverse.map f) ((opOpEquivalence C).inverse.map g)

Next tactic:
exact Exact.op _ _ e
theorem Exact.unop {X Y Z : Cᵒᵖ} (g : X ⟶ Y) (f : Y ⟶ Z) (h : Exact g f) : Exact f.unop g.unop := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
X Y Z : Cᵒᵖ
g : X ⟶ Y
f : Y ⟶ Z
h : Exact g f
⊢ Exact f.unop g.unop

Next tactic:
rw [← f.op_unop, ← g.op_unop] at h
theorem Exact.unop {X Y Z : Cᵒᵖ} (g : X ⟶ Y) (f : Y ⟶ Z) (h : Exact g f) : Exact f.unop g.unop := by
  rw [← f.op_unop, ← g.op_unop] at h
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
X Y Z : Cᵒᵖ
g : X ⟶ Y
f : Y ⟶ Z
h : Exact g.unop.op f.unop.op
⊢ Exact f.unop g.unop

Next tactic:
rwa [← Exact.op_iff]
theorem Exact.unop_iff {X Y Z : Cᵒᵖ} (g : X ⟶ Y) (f : Y ⟶ Z) : Exact f.unop g.unop ↔ Exact g f :=
  ⟨fun e => by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
X Y Z : Cᵒᵖ
g : X ⟶ Y
f : Y ⟶ Z
e : Exact f.unop g.unop
⊢ Exact g f

Next tactic:
rwa [← f.op_unop, ← g.op_unop, ← Exact.op_iff] at e
theorem Exact.unop_iff {X Y Z : Cᵒᵖ} (g : X ⟶ Y) (f : Y ⟶ Z) : Exact f.unop g.unop ↔ Exact g f :=
  ⟨fun e => by rwa [← f.op_unop, ← g.op_unop, ← Exact.op_iff] at e, fun e => by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
X Y Z : Cᵒᵖ
g : X ⟶ Y
f : Y ⟶ Z
e : Exact g f
⊢ Exact f.unop g.unop

Next tactic:
rw [← Exact.op_iff]
theorem Exact.unop_iff {X Y Z : Cᵒᵖ} (g : X ⟶ Y) (f : Y ⟶ Z) : Exact f.unop g.unop ↔ Exact g f :=
  ⟨fun e => by rwa [← f.op_unop, ← g.op_unop, ← Exact.op_iff] at e, fun e => by
    rw [← Exact.op_iff]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
g✝ : Y✝ ⟶ Z✝
X Y Z : Cᵒᵖ
g : X ⟶ Y
f : Y ⟶ Z
e : Exact g f
⊢ Exact g.unop.op f.unop.op

Next tactic:
exact e
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : Exact (F.map f) (F.map g)
⊢ Exact f g

Next tactic:
rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : f ≫ g = 0 ∧ kernel.ι (F.map g) ≫ cokernel.π (F.map f) = 0
⊢ Exact f g

Next tactic:
refine' (Abelian.exact_iff _ _).2 ⟨hfg.1, F.zero_of_map_zero _ _⟩
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
    refine' (Abelian.exact_iff _ _).2 ⟨hfg.1, F.zero_of_map_zero _ _⟩
    

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : f ≫ g = 0 ∧ kernel.ι (F.map g) ≫ cokernel.π (F.map f) = 0
⊢ F.map (kernel.ι g ≫ cokernel.π f) = 0

Next tactic:
obtain ⟨k, hk⟩ :=
      kernel.lift' (F.map g) (F.map (kernel.ι g))
        (by simp only [← F.map_comp, kernel.condition, CategoryTheory.Functor.map_zero])
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
    refine' (Abelian.exact_iff _ _).2 ⟨hfg.1, F.zero_of_map_zero _ _⟩
    obtain ⟨k, hk⟩ :=
      kernel.lift' (F.map g) (F.map (kernel.ι g))
        (by 

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : f ≫ g = 0 ∧ kernel.ι (F.map g) ≫ cokernel.π (F.map f) = 0
⊢ F.map (kernel.ι g) ≫ F.map g = 0

Next tactic:
simp only [← F.map_comp, kernel.condition, CategoryTheory.Functor.map_zero]
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
    refine' (Abelian.exact_iff _ _).2 ⟨hfg.1, F.zero_of_map_zero _ _⟩
    obtain ⟨k, hk⟩ :=
      kernel.lift' (F.map g) (F.map (kernel.ι g))
        (by simp only [← F.map_comp, kernel.condition, CategoryTheory.Functor.map_zero])
    

Proof state:
case mk
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : f ≫ g = 0 ∧ kernel.ι (F.map g) ≫ cokernel.π (F.map f) = 0
k : F.obj (kernel g) ⟶ kernel (F.map g)
hk : k ≫ kernel.ι (F.map g) = F.map (kernel.ι g)
⊢ F.map (kernel.ι g ≫ cokernel.π f) = 0

Next tactic:
obtain ⟨l, hl⟩ :=
      cokernel.desc' (F.map f) (F.map (cokernel.π f))
        (by simp only [← F.map_comp, cokernel.condition, CategoryTheory.Functor.map_zero])
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
    refine' (Abelian.exact_iff _ _).2 ⟨hfg.1, F.zero_of_map_zero _ _⟩
    obtain ⟨k, hk⟩ :=
      kernel.lift' (F.map g) (F.map (kernel.ι g))
        (by simp only [← F.map_comp, kernel.condition, CategoryTheory.Functor.map_zero])
    obtain ⟨l, hl⟩ :=
      cokernel.desc' (F.map f) (F.map (cokernel.π f))
        (by 

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : f ≫ g = 0 ∧ kernel.ι (F.map g) ≫ cokernel.π (F.map f) = 0
k : F.obj (kernel g) ⟶ kernel (F.map g)
hk : k ≫ kernel.ι (F.map g) = F.map (kernel.ι g)
⊢ F.map f ≫ F.map (cokernel.π f) = 0

Next tactic:
simp only [← F.map_comp, cokernel.condition, CategoryTheory.Functor.map_zero]
instance (priority := 100) reflectsExactSequencesOfPreservesZeroMorphismsOfFaithful [Faithful F] :
    ReflectsExactSequences F where
  reflects {X Y Z} f g hfg := by
    rw [Abelian.exact_iff, ← F.map_comp, F.map_eq_zero_iff] at hfg
    refine' (Abelian.exact_iff _ _).2 ⟨hfg.1, F.zero_of_map_zero _ _⟩
    obtain ⟨k, hk⟩ :=
      kernel.lift' (F.map g) (F.map (kernel.ι g))
        (by simp only [← F.map_comp, kernel.condition, CategoryTheory.Functor.map_zero])
    obtain ⟨l, hl⟩ :=
      cokernel.desc' (F.map f) (F.map (cokernel.π f))
        (by simp only [← F.map_comp, cokernel.condition, CategoryTheory.Functor.map_zero])
    

Proof state:
case mk.mk
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : Abelian C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : Abelian D
F : C ⥤ D
inst✝¹ : PreservesZeroMorphisms F
inst✝ : Faithful F
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
hfg : f ≫ g = 0 ∧ kernel.ι (F.map g) ≫ cokernel.π (F.map f) = 0
k : F.obj (kernel g) ⟶ kernel (F.map g)
hk : k ≫ kernel.ι (F.map g) = F.map (kernel.ι g)
l : cokernel (F.map f) ⟶ F.obj (cokernel f)
hl : cokernel.π (F.map f) ≫ l = F.map (cokernel.π f)
⊢ F.map (kernel.ι g ≫ cokernel.π f) = 0

Next tactic:
rw [F.map_comp, ← hk, ← hl, Category.assoc, reassoc_of% hfg.2, zero_comp, comp_zero]
/-- 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
  

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
⊢ Exact (L.map f) (L.map g)

Next tactic:
let hcoker := isColimitOfHasCokernelOfPreservesColimit L f
/-- 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
  

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
⊢ Exact (L.map f) (L.map g)

Next tactic:
let hker := isLimitOfHasKernelOfPreservesLimit L g
/-- 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
  

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
⊢ Exact (L.map f) (L.map g)

Next tactic:
refine' (exact_iff' _ _ hker hcoker).2 ⟨by simp [← L.map_comp, e1.1], _⟩
/-- 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 

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
⊢ L.map f ≫ L.map g = 0

Next tactic:
simp [← L.map_comp, e1.1]