Theorem: CategoryTheory.Abelian.exact_iff
File: Mathlib/CategoryTheory/Abelian/Exact.lean

tactic: constructor
state_before: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact f g ↔ f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
state_after: case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact f g → f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0

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

tactic: exact fun h ↦ ⟨h.1, kernel_comp_cokernel f g h⟩
state_before: case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ Exact f g → f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
state_after: no goals

tactic: refine fun h ↦ ⟨h.1, ?_⟩
state_before: case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
⊢ f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0 → Exact f g
state_after: case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
⊢ Epi (imageToKernel f g ⋯)

tactic: suffices hl : IsLimit
    (KernelFork.ofι (imageSubobject f).arrow (imageSubobject_arrow_comp_eq_zero h.1)) by
  have : imageToKernel f g h.1 = (hl.conePointUniqueUpToIso (limit.isLimit _)).hom ≫
      (kernelSubobjectIso _).inv := by ext; simp
  rw [this]
  infer_instance
state_before: case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
⊢ Epi (imageToKernel f g ⋯)
state_after: case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
⊢ IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)

tactic: refine KernelFork.IsLimit.ofι _ _ (fun u hu ↦ ?_) ?_ (fun _ _ _ h ↦ ?_)
state_before: case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
⊢ IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
state_after: case mpr.refine_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
u : W'✝ ⟶ Y
hu : u ≫ g = 0
⊢ W'✝ ⟶ Subobject.underlying.obj (imageSubobject f)

case mpr.refine_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
⊢ ∀ {W' : C} (g' : W' ⟶ Y) (eq' : g' ≫ g = 0), (fun {W'} u hu => ?m.9955 u hu) g' eq' ≫ (imageSubobject f).arrow = g'

case mpr.refine_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h✝ : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
x✝² : W'✝ ⟶ Y
x✝¹ : x✝² ≫ g = 0
x✝ : W'✝ ⟶ Subobject.underlying.obj (imageSubobject f)
h : x✝ ≫ (imageSubobject f).arrow = x✝²
⊢ x✝ = (fun {W'} u hu => ?m.9955 u hu) x✝² x✝¹

tactic: have : imageToKernel f g h.1 = (hl.conePointUniqueUpToIso (limit.isLimit _)).hom ≫
    (kernelSubobjectIso _).inv := by ext; simp
state_before: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
⊢ Epi (imageToKernel f g ⋯)
state_after: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
this :
  imageToKernel f g ⋯ = (hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv
⊢ Epi (imageToKernel f g ⋯)

tactic: rw [this]
state_before: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
this :
  imageToKernel f g ⋯ = (hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv
⊢ Epi (imageToKernel f g ⋯)
state_after: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
this :
  imageToKernel f g ⋯ = (hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv
⊢ Epi ((hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv)

tactic: infer_instance
state_before: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
this :
  imageToKernel f g ⋯ = (hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv
⊢ Epi ((hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv)
state_after: no goals

tactic: ext
state_before: C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
⊢ imageToKernel f g ⋯ = (hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv
state_after: case h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
⊢ imageToKernel f g ⋯ ≫ (kernelSubobject g).arrow =
    ((hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv) ≫
      (kernelSubobject g).arrow

tactic: simp
state_before: case h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
hl : IsLimit (KernelFork.ofι (imageSubobject f).arrow ⋯)
⊢ imageToKernel f g ⋯ ≫ (kernelSubobject g).arrow =
    ((hl.conePointUniqueUpToIso (limit.isLimit (parallelPair g 0))).hom ≫ (kernelSubobjectIso g).inv) ≫
      (kernelSubobject g).arrow
state_after: no goals

tactic: refine kernel.lift (cokernel.π f) u ?_ ≫ (imageIsoImage f).hom ≫ (imageSubobjectIso _).inv
state_before: case mpr.refine_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
u : W'✝ ⟶ Y
hu : u ≫ g = 0
⊢ W'✝ ⟶ Subobject.underlying.obj (imageSubobject f)
state_after: case mpr.refine_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
u : W'✝ ⟶ Y
hu : u ≫ g = 0
⊢ u ≫ cokernel.π f = 0

tactic: rw [← kernel.lift_ι g u hu, Category.assoc, h.2, comp_zero]
state_before: case mpr.refine_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
u : W'✝ ⟶ Y
hu : u ≫ g = 0
⊢ u ≫ cokernel.π f = 0
state_after: no goals

tactic: aesop_cat
state_before: case mpr.refine_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
⊢ ∀ {W' : C} (g' : W' ⟶ Y) (eq' : g' ≫ g = 0),
    (fun {W'} u hu => kernel.lift (cokernel.π f) u ⋯ ≫ (imageIsoImage f).hom ≫ (imageSubobjectIso f).inv) g' eq' ≫
        (imageSubobject f).arrow =
      g'
state_after: no goals

tactic: rw [← cancel_mono (imageSubobject f).arrow, h]
state_before: case mpr.refine_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h✝ : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
x✝² : W'✝ ⟶ Y
x✝¹ : x✝² ≫ g = 0
x✝ : W'✝ ⟶ Subobject.underlying.obj (imageSubobject f)
h : x✝ ≫ (imageSubobject f).arrow = x✝²
⊢ x✝ = (fun {W'} u hu => kernel.lift (cokernel.π f) u ⋯ ≫ (imageIsoImage f).hom ≫ (imageSubobjectIso f).inv) x✝² x✝¹
state_after: case mpr.refine_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h✝ : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
x✝² : W'✝ ⟶ Y
x✝¹ : x✝² ≫ g = 0
x✝ : W'✝ ⟶ Subobject.underlying.obj (imageSubobject f)
h : x✝ ≫ (imageSubobject f).arrow = x✝²
⊢ x✝² =
    (fun {W'} u hu => kernel.lift (cokernel.π f) u ⋯ ≫ (imageIsoImage f).hom ≫ (imageSubobjectIso f).inv) x✝² x✝¹ ≫
      (imageSubobject f).arrow

tactic: simp
state_before: case mpr.refine_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
h✝ : f ≫ g = 0 ∧ kernel.ι g ≫ cokernel.π f = 0
W'✝ : C
x✝² : W'✝ ⟶ Y
x✝¹ : x✝² ≫ g = 0
x✝ : W'✝ ⟶ Subobject.underlying.obj (imageSubobject f)
h : x✝ ≫ (imageSubobject f).arrow = x✝²
⊢ x✝² =
    (fun {W'} u hu => kernel.lift (cokernel.π f) u ⋯ ≫ (imageIsoImage f).hom ≫ (imageSubobjectIso f).inv) x✝² x✝¹ ≫
      (imageSubobject f).arrow
state_after: no goals