l3lab/ntp-mathlib huggingface dataset:
theorem exact_kernelSubobject_arrow : Exact (kernelSubobject f).arrow f := by
  refine' ⟨by 

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ Subobject.arrow (kernelSubobject f) ≫ f = 0

Next tactic:
simp
theorem exact_kernelSubobject_arrow : Exact (kernelSubobject f).arrow f := by
  refine' ⟨by simp, _⟩
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ Epi (imageToKernel (Subobject.arrow (kernelSubobject f)) f (_ : Subobject.arrow (kernelSubobject f) ≫ f = 0))

Next tactic:
refine' @IsIso.epi_of_iso _ _ _ _ _ ?_
theorem exact_kernelSubobject_arrow : Exact (kernelSubobject f).arrow f := by
  refine' ⟨by simp, _⟩
  refine' @IsIso.epi_of_iso _ _ _ _ _ ?_
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ IsIso (imageToKernel (Subobject.arrow (kernelSubobject f)) f (_ : Subobject.arrow (kernelSubobject f) ≫ f = 0))

Next tactic:
exact ⟨⟨factorThruImageSubobject _, by aesop_cat, by aesop_cat⟩⟩
theorem exact_kernelSubobject_arrow : Exact (kernelSubobject f).arrow f := by
  refine' ⟨by simp, _⟩
  refine' @IsIso.epi_of_iso _ _ _ _ _ ?_
  exact ⟨⟨factorThruImageSubobject _, by 

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ imageToKernel (Subobject.arrow (kernelSubobject f)) f (_ : Subobject.arrow (kernelSubobject f) ≫ f = 0) ≫
      factorThruImageSubobject (Subobject.arrow (kernelSubobject f)) =
    𝟙 (Subobject.underlying.obj (imageSubobject (Subobject.arrow (kernelSubobject f))))

Next tactic:
aesop_cat
theorem exact_kernelSubobject_arrow : Exact (kernelSubobject f).arrow f := by
  refine' ⟨by simp, _⟩
  refine' @IsIso.epi_of_iso _ _ _ _ _ ?_
  exact ⟨⟨factorThruImageSubobject _, by aesop_cat, by 

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ factorThruImageSubobject (Subobject.arrow (kernelSubobject f)) ≫
      imageToKernel (Subobject.arrow (kernelSubobject f)) f (_ : Subobject.arrow (kernelSubobject f) ≫ f = 0) =
    𝟙 (Subobject.underlying.obj (kernelSubobject f))

Next tactic:
aesop_cat
theorem exact_kernel_ι : Exact (kernel.ι f) f := by
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ Exact (kernel.ι f) f

Next tactic:
rw [← kernelSubobject_arrow', exact_iso_comp]
theorem exact_kernel_ι : Exact (kernel.ι f) f := by
  rw [← kernelSubobject_arrow', exact_iso_comp]
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
⊢ Exact (Subobject.arrow (kernelSubobject f)) f

Next tactic:
exact exact_kernelSubobject_arrow
instance Exact.epi_factorThruKernelSubobject (h : Exact f g) :
  Epi (factorThruKernelSubobject g f h.w) := by
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact f g
⊢ Epi (factorThruKernelSubobject g f (_ : f ≫ g = 0))

Next tactic:
rw [← factorThruImageSubobject_comp_imageToKernel]
instance Exact.epi_factorThruKernelSubobject (h : Exact f g) :
  Epi (factorThruKernelSubobject g f h.w) := by
  rw [← factorThruImageSubobject_comp_imageToKernel]
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact f g
⊢ Epi (factorThruImageSubobject f ≫ imageToKernel f g (_ : f ≫ g = 0))

Next tactic:
haveI := h.epi
instance Exact.epi_factorThruKernelSubobject (h : Exact f g) :
  Epi (factorThruKernelSubobject g f h.w) := by
  rw [← factorThruImageSubobject_comp_imageToKernel]
  haveI := h.epi
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact f g
this : Epi (imageToKernel f g (_ : f ≫ g = 0))
⊢ Epi (factorThruImageSubobject f ≫ imageToKernel f g (_ : f ≫ g = 0))

Next tactic:
apply epi_comp
lemma Exact.epi_kernel_lift (h : Exact f g) : Epi (kernel.lift g f h.w) := by
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact f g
⊢ Epi (kernel.lift g f (_ : f ≫ g = 0))

Next tactic:
rw [← factorThruKernelSubobject_comp_kernelSubobjectIso]
lemma Exact.epi_kernel_lift (h : Exact f g) : Epi (kernel.lift g f h.w) := by
  rw [← factorThruKernelSubobject_comp_kernelSubobjectIso]
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact f g
⊢ Epi (factorThruKernelSubobject g f (_ : f ≫ g = 0) ≫ (kernelSubobjectIso g).hom)

Next tactic:
haveI := h.epi_factorThruKernelSubobject
lemma Exact.epi_kernel_lift (h : Exact f g) : Epi (kernel.lift g f h.w) := by
  rw [← factorThruKernelSubobject_comp_kernelSubobjectIso]
  haveI := h.epi_factorThruKernelSubobject
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact f g
this : Epi (factorThruKernelSubobject g f (_ : f ≫ g = 0))
⊢ Epi (factorThruKernelSubobject g f (_ : f ≫ g = 0) ≫ (kernelSubobjectIso g).hom)

Next tactic:
apply epi_comp
theorem kernelSubobject_arrow_eq_zero_of_exact_zero_left (h : Exact (0 : A ⟶ B) g) :
    (kernelSubobject g).arrow = 0 := by
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact 0 g
⊢ Subobject.arrow (kernelSubobject g) = 0

Next tactic:
haveI := h.epi
theorem kernelSubobject_arrow_eq_zero_of_exact_zero_left (h : Exact (0 : A ⟶ B) g) :
    (kernelSubobject g).arrow = 0 := by
  haveI := h.epi
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact 0 g
this : Epi (imageToKernel 0 g (_ : 0 ≫ g = 0))
⊢ Subobject.arrow (kernelSubobject g) = 0

Next tactic:
rw [← cancel_epi (imageToKernel (0 : A ⟶ B) g h.w), ←
    cancel_epi (factorThruImageSubobject (0 : A ⟶ B))]
theorem kernelSubobject_arrow_eq_zero_of_exact_zero_left (h : Exact (0 : A ⟶ B) g) :
    (kernelSubobject g).arrow = 0 := by
  haveI := h.epi
  rw [← cancel_epi (imageToKernel (0 : A ⟶ B) g h.w), ←
    cancel_epi (factorThruImageSubobject (0 : A ⟶ B))]
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact 0 g
this : Epi (imageToKernel 0 g (_ : 0 ≫ g = 0))
⊢ factorThruImageSubobject 0 ≫ imageToKernel 0 g (_ : 0 ≫ g = 0) ≫ Subobject.arrow (kernelSubobject g) =
    factorThruImageSubobject 0 ≫ imageToKernel 0 g (_ : 0 ≫ g = 0) ≫ 0

Next tactic:
simp
theorem kernel_ι_eq_zero_of_exact_zero_left (h : Exact (0 : A ⟶ B) g) : kernel.ι g = 0 := by
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact 0 g
⊢ kernel.ι g = 0

Next tactic:
rw [← kernelSubobject_arrow']
theorem kernel_ι_eq_zero_of_exact_zero_left (h : Exact (0 : A ⟶ B) g) : kernel.ι g = 0 := by
  rw [← kernelSubobject_arrow']
  

Proof state:
V : Type u
inst✝³ : Category.{v, u} V
inst✝² : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝¹ : HasZeroMorphisms V
inst✝ : HasEqualizers V
h : Exact 0 g
⊢ (kernelSubobjectIso g).inv ≫ Subobject.arrow (kernelSubobject g) = 0

Next tactic:
simp [kernelSubobject_arrow_eq_zero_of_exact_zero_left A h]
theorem exact_zero_left_of_mono [HasZeroObject V] [Mono g] : Exact (0 : A ⟶ B) g :=
  ⟨by 

Proof state:
V : Type u
inst✝⁵ : Category.{v, u} V
inst✝⁴ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h : C ⟶ D
inst✝³ : HasZeroMorphisms V
inst✝² : HasEqualizers V
inst✝¹ : HasZeroObject V
inst✝ : Mono g
⊢ 0 ≫ g = 0

Next tactic:
simp
@[reassoc (attr := simp)]
theorem kernel_comp_cokernel (h : Exact f g) : kernel.ι g ≫ cokernel.π f = 0 := by
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
⊢ kernel.ι g ≫ cokernel.π f = 0

Next tactic:
suffices Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0 by
    rw [← kernelSubobject_arrow', Category.assoc, this, comp_zero]
@[reassoc (attr := simp)]
theorem kernel_comp_cokernel (h : Exact f g) : kernel.ι g ≫ cokernel.π f = 0 := by
  suffices Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0 by
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
this : Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0
⊢ kernel.ι g ≫ cokernel.π f = 0

Next tactic:
rw [← kernelSubobject_arrow', Category.assoc, this, comp_zero]
@[reassoc (attr := simp)]
theorem kernel_comp_cokernel (h : Exact f g) : kernel.ι g ≫ cokernel.π f = 0 := by
  suffices Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0 by
    rw [← kernelSubobject_arrow', Category.assoc, this, comp_zero]
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
⊢ Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0

Next tactic:
haveI := h.epi
@[reassoc (attr := simp)]
theorem kernel_comp_cokernel (h : Exact f g) : kernel.ι g ≫ cokernel.π f = 0 := by
  suffices Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0 by
    rw [← kernelSubobject_arrow', Category.assoc, this, comp_zero]
  haveI := h.epi
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
this : Epi (imageToKernel f g (_ : f ≫ g = 0))
⊢ Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0

Next tactic:
apply zero_of_epi_comp (imageToKernel f g h.w) _
@[reassoc (attr := simp)]
theorem kernel_comp_cokernel (h : Exact f g) : kernel.ι g ≫ cokernel.π f = 0 := by
  suffices Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0 by
    rw [← kernelSubobject_arrow', Category.assoc, this, comp_zero]
  haveI := h.epi
  apply zero_of_epi_comp (imageToKernel f g h.w) _
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
this : Epi (imageToKernel f g (_ : f ≫ g = 0))
⊢ imageToKernel f g (_ : f ≫ g = 0) ≫ Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0

Next tactic:
rw [imageToKernel_arrow_assoc, ← imageSubobject_arrow, Category.assoc, ← Iso.eq_inv_comp]
@[reassoc (attr := simp)]
theorem kernel_comp_cokernel (h : Exact f g) : kernel.ι g ≫ cokernel.π f = 0 := by
  suffices Subobject.arrow (kernelSubobject g) ≫ cokernel.π f = 0 by
    rw [← kernelSubobject_arrow', Category.assoc, this, comp_zero]
  haveI := h.epi
  apply zero_of_epi_comp (imageToKernel f g h.w) _
  rw [imageToKernel_arrow_assoc, ← imageSubobject_arrow, Category.assoc, ← Iso.eq_inv_comp]
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
this : Epi (imageToKernel f g (_ : f ≫ g = 0))
⊢ image.ι f ≫ cokernel.π f = (imageSubobjectIso f).inv ≫ 0

Next tactic:
aesop_cat
theorem comp_eq_zero_of_exact (h : Exact f g) {X Y : V} {ι : X ⟶ B} (hι : ι ≫ g = 0) {π : B ⟶ Y}
    (hπ : f ≫ π = 0) : ι ≫ π = 0 := by
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B C D : V
f : A ⟶ B
g : B ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroMorphisms V
inst✝¹ : HasEqualizers V
inst✝ : HasCokernels V
h : Exact f g
X Y : V
ι : X ⟶ B
hι : ι ≫ g = 0
π : B ⟶ Y
hπ : f ≫ π = 0
⊢ ι ≫ π = 0

Next tactic:
rw [← kernel.lift_ι _ _ hι, ← cokernel.π_desc _ _ hπ, Category.assoc,
    kernel_comp_cokernel_assoc _ _ h, zero_comp, comp_zero]
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f✝ : A✝ ⟶ B
g✝ : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
f : A ⟶ 0
g : 0 ⟶ C
⊢ Exact f g

Next tactic:
obtain rfl : f = 0 := by ext
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  obtain rfl : f = 0 := by 

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f✝ : A✝ ⟶ B
g✝ : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
f : A ⟶ 0
g : 0 ⟶ C
⊢ f = 0

Next tactic:
ext
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  obtain rfl : f = 0 := by ext
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f : A✝ ⟶ B
g✝ : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
g : 0 ⟶ C
⊢ Exact 0 g

Next tactic:
obtain rfl : g = 0 := by ext
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  obtain rfl : f = 0 := by ext
  obtain rfl : g = 0 := by 

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f : A✝ ⟶ B
g✝ : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
g : 0 ⟶ C
⊢ g = 0

Next tactic:
ext
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  obtain rfl : f = 0 := by ext
  obtain rfl : g = 0 := by ext
  

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f : A✝ ⟶ B
g : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
⊢ Exact 0 0

Next tactic:
fconstructor
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  obtain rfl : f = 0 := by ext
  obtain rfl : g = 0 := by ext
  fconstructor
  · 

Proof state:
case w
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f : A✝ ⟶ B
g : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
⊢ 0 ≫ 0 = 0

Next tactic:
simp
theorem exact_of_zero {A C : V} (f : A ⟶ 0) (g : 0 ⟶ C) : Exact f g := by
  obtain rfl : f = 0 := by ext
  obtain rfl : g = 0 := by ext
  fconstructor
  · simp
  · 

Proof state:
case epi
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B C✝ D : V
f : A✝ ⟶ B
g : B ⟶ C✝
h : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : HasZeroMorphisms V
inst✝ : HasKernels V
A C : V
⊢ Epi (imageToKernel 0 0 (_ : 0 ≫ 0 = 0))

Next tactic:
exact imageToKernel_epi_of_zero_of_mono 0
theorem mono_iff_exact_zero_left [HasKernels V] {B C : V} (f : B ⟶ C) :
    Mono f ↔ Exact (0 : 0 ⟶ B) f :=
  ⟨fun h => exact_zero_mono _, fun h =>
    Preadditive.mono_of_kernel_iso_zero
      ((kernelSubobjectIso f).symm ≪≫ isoZeroOfEpiZero (by 

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A B✝ C✝ D : V
f✝ : A ⟶ B✝
g : B✝ ⟶ C✝
h✝ : C✝ ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasKernels V
B C : V
f : B ⟶ C
h : Exact 0 f
⊢ Epi 0

Next tactic:
simpa using h.epi
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
⊢ Epi f

Next tactic:
have e₁ := h.epi
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    have e₁ := h.epi
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
e₁ : Epi (imageToKernel f 0 (_ : f ≫ 0 = 0))
⊢ Epi f

Next tactic:
rw [imageToKernel_zero_right] at e₁
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    have e₁ := h.epi
    rw [imageToKernel_zero_right] at e₁
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
e₁ : Epi (Subobject.arrow (imageSubobject f) ≫ inv (Subobject.arrow (kernelSubobject 0)))
⊢ Epi f

Next tactic:
have e₂ : Epi (((imageSubobject f).arrow ≫ inv (kernelSubobject 0).arrow) ≫
          (kernelSubobject 0).arrow) := @epi_comp _ _ _ _ _ _ e₁ _ _
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    have e₁ := h.epi
    rw [imageToKernel_zero_right] at e₁
    have e₂ : Epi (((imageSubobject f).arrow ≫ inv (kernelSubobject 0).arrow) ≫
          (kernelSubobject 0).arrow) := @epi_comp _ _ _ _ _ _ e₁ _ _
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
e₁ : Epi (Subobject.arrow (imageSubobject f) ≫ inv (Subobject.arrow (kernelSubobject 0)))
e₂ :
  Epi
    ((Subobject.arrow (imageSubobject f) ≫ inv (Subobject.arrow (kernelSubobject 0))) ≫
      Subobject.arrow (kernelSubobject 0))
⊢ Epi f

Next tactic:
rw [Category.assoc, IsIso.inv_hom_id, Category.comp_id] at e₂
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    have e₁ := h.epi
    rw [imageToKernel_zero_right] at e₁
    have e₂ : Epi (((imageSubobject f).arrow ≫ inv (kernelSubobject 0).arrow) ≫
          (kernelSubobject 0).arrow) := @epi_comp _ _ _ _ _ _ e₁ _ _
    rw [Category.assoc, IsIso.inv_hom_id, Category.comp_id] at e₂
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
e₁ : Epi (Subobject.arrow (imageSubobject f) ≫ inv (Subobject.arrow (kernelSubobject 0)))
e₂ : Epi (Subobject.arrow (imageSubobject f))
⊢ Epi f

Next tactic:
rw [← imageSubobject_arrow] at e₂
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    have e₁ := h.epi
    rw [imageToKernel_zero_right] at e₁
    have e₂ : Epi (((imageSubobject f).arrow ≫ inv (kernelSubobject 0).arrow) ≫
          (kernelSubobject 0).arrow) := @epi_comp _ _ _ _ _ _ e₁ _ _
    rw [Category.assoc, IsIso.inv_hom_id, Category.comp_id] at e₂
    rw [← imageSubobject_arrow] at e₂
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
e₁ : Epi (Subobject.arrow (imageSubobject f) ≫ inv (Subobject.arrow (kernelSubobject 0)))
e₂ : Epi ((imageSubobjectIso f).hom ≫ image.ι f)
⊢ Epi f

Next tactic:
haveI : Epi (image.ι f) := epi_of_epi (imageSubobjectIso f).hom (image.ι f)
theorem epi_iff_exact_zero_right [HasEqualizers V] {A B : V} (f : A ⟶ B) :
    Epi f ↔ Exact f (0 : B ⟶ 0) :=
  ⟨fun h => exact_epi_zero _, fun h => by
    have e₁ := h.epi
    rw [imageToKernel_zero_right] at e₁
    have e₂ : Epi (((imageSubobject f).arrow ≫ inv (kernelSubobject 0).arrow) ≫
          (kernelSubobject 0).arrow) := @epi_comp _ _ _ _ _ _ e₁ _ _
    rw [Category.assoc, IsIso.inv_hom_id, Category.comp_id] at e₂
    rw [← imageSubobject_arrow] at e₂
    haveI : Epi (image.ι f) := epi_of_epi (imageSubobjectIso f).hom (image.ι f)
    

Proof state:
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : HasImages V
A✝ B✝ C D : V
f✝ : A✝ ⟶ B✝
g : B✝ ⟶ C
h✝ : C ⟶ D
inst✝² : HasZeroObject V
inst✝¹ : Preadditive V
inst✝ : HasEqualizers V
A B : V
f : A ⟶ B
h : Exact f 0
e₁ : Epi (Subobject.arrow (imageSubobject f) ≫ inv (Subobject.arrow (kernelSubobject 0)))
e₂ : Epi ((imageSubobjectIso f).hom ≫ image.ι f)
this : Epi (image.ι f)
⊢ Epi f

Next tactic:
apply epi_of_epi_image
instance (α : Type u) : Inhabited (FreeRing α) := by
  

Proof state:
α : Type u
⊢ Inhabited (FreeRing α)

Next tactic:
dsimp only [FreeRing]
instance (α : Type u) : Inhabited (FreeRing α) := by
  dsimp only [FreeRing]
  

Proof state:
α : Type u
⊢ Inhabited (FreeAbelianGroup (FreeMonoid α))

Next tactic:
infer_instance
@[elab_as_elim]
protected theorem induction_on {C : FreeRing α → Prop} (z : FreeRing α) (hn1 : C (-1))
    (hb : ∀ b, C (of b)) (ha : ∀ x y, C x → C y → C (x + y)) (hm : ∀ x y, C x → C y → C (x * y)) :
    C z :=
  have hn : ∀ x, C x → C (-x) := fun x ih => neg_one_mul x ▸ hm _ _ hn1 ih
  have h1 : C 1 := neg_neg (1 : FreeRing α) ▸ hn _ hn1
  FreeAbelianGroup.induction_on z (add_left_neg (1 : FreeRing α) ▸ ha _ _ hn1 h1)
    (fun m => List.recOn m h1 fun a m ih => by
      -- porting note: in mathlib, convert was not necessary, `exact hm _ _ (hb a) ih` worked fine
      

Proof state:
α : Type u
C : FreeRing α → Prop
z : FreeRing α
hn1 : C (-1)
hb : ∀ (b : α), C (of b)
ha : ∀ (x y : FreeRing α), C x → C y → C (x + y)
hm : ∀ (x y : FreeRing α), C x → C y → C (x * y)
hn : ∀ (x : FreeRing α), C x → C (-x)
h1 : C 1
m✝ : FreeMonoid α
a : α
m : List α
ih : C (FreeAbelianGroup.of m)
⊢ C (FreeAbelianGroup.of (a :: m))

Next tactic:
convert hm _ _ (hb a) ih
@[elab_as_elim]
protected theorem induction_on {C : FreeRing α → Prop} (z : FreeRing α) (hn1 : C (-1))
    (hb : ∀ b, C (of b)) (ha : ∀ x y, C x → C y → C (x + y)) (hm : ∀ x y, C x → C y → C (x * y)) :
    C z :=
  have hn : ∀ x, C x → C (-x) := fun x ih => neg_one_mul x ▸ hm _ _ hn1 ih
  have h1 : C 1 := neg_neg (1 : FreeRing α) ▸ hn _ hn1
  FreeAbelianGroup.induction_on z (add_left_neg (1 : FreeRing α) ▸ ha _ _ hn1 h1)
    (fun m => List.recOn m h1 fun a m ih => by
      -- porting note: in mathlib, convert was not necessary, `exact hm _ _ (hb a) ih` worked fine
      convert hm _ _ (hb a) ih
      

Proof state:
case h.e'_1
α : Type u
C : FreeRing α → Prop
z : FreeRing α
hn1 : C (-1)
hb : ∀ (b : α), C (of b)
ha : ∀ (x y : FreeRing α), C x → C y → C (x + y)
hm : ∀ (x y : FreeRing α), C x → C y → C (x * y)
hn : ∀ (x : FreeRing α), C x → C (-x)
h1 : C 1
m✝ : FreeMonoid α
a : α
m : List α
ih : C (FreeAbelianGroup.of m)
⊢ FreeAbelianGroup.of (a :: m) = of a * FreeAbelianGroup.of m

Next tactic:
rw [of, ← FreeAbelianGroup.of_mul]