l3lab/ntp-mathlib huggingface dataset:
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · 

Proof state:
case mpr
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
⊢ Exact (δlast S) ∧ Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2))) → Exact S

Next tactic:
rintro ⟨h, h'⟩
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    

Proof state:
case mpr.intro
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
⊢ Exact S

Next tactic:
refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · 

Proof state:
case mpr.intro.refine'_1
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
i : ℕ
hi : autoParam (i + 2 ≤ n + 2) _auto✝
⊢ map' S i (i + 1) ≫ map' S (i + 1) (i + 2) = 0

Next tactic:
obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by 

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
i : ℕ
hi : autoParam (i + 2 ≤ n + 2) _auto✝
⊢ i ≤ n

Next tactic:
linarith
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · 

Proof state:
case mpr.intro.refine'_1.inl
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
i : ℕ
hi✝ : autoParam (i + 2 ≤ n + 2) _auto✝
hi : i < n
⊢ map' S i (i + 1) ≫ map' S (i + 1) (i + 2) = 0

Next tactic:
exact h.toIsComplex.zero i
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · exact h.toIsComplex.zero i
      · 

Proof state:
case mpr.intro.refine'_1.inr
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n : ℕ
S✝ : ComposableArrows C n
i : ℕ
S : ComposableArrows C (i + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S i (i + 1)) (map' S (i + 1) (i + 2)))
hi : autoParam (i + 2 ≤ i + 2) _auto✝
⊢ map' S i (i + 1) ≫ map' S (i + 1) (i + 2) = 0

Next tactic:
exact h'.toIsComplex.zero 0
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · exact h.toIsComplex.zero i
      · exact h'.toIsComplex.zero 0
    · 

Proof state:
case mpr.intro.refine'_2
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
i : ℕ
hi : autoParam (i + 2 ≤ n + 2) _auto✝
⊢ ShortComplex.Exact (sc S (_ : IsComplex S) i)

Next tactic:
obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · exact h.toIsComplex.zero i
      · exact h'.toIsComplex.zero 0
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by 

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
i : ℕ
hi : autoParam (i + 2 ≤ n + 2) _auto✝
⊢ i ≤ n

Next tactic:
linarith
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · exact h.toIsComplex.zero i
      · exact h'.toIsComplex.zero 0
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · 

Proof state:
case mpr.intro.refine'_2.inl
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n✝ : ℕ
S✝ : ComposableArrows C n✝
n : ℕ
S : ComposableArrows C (n + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S n (n + 1)) (map' S (n + 1) (n + 2)))
i : ℕ
hi✝ : autoParam (i + 2 ≤ n + 2) _auto✝
hi : i < n
⊢ ShortComplex.Exact (sc S (_ : IsComplex S) i)

Next tactic:
exact h.exact i
lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) :
    S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by
  constructor
  · intro h
    constructor
    · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i))
        (fun i hi => h.exact i)
    · rw [exact₂_iff]; swap
      · rw [isComplex₂_iff]
        exact h.toIsComplex.zero n
      exact h.exact n (by linarith)
  · rintro ⟨h, h'⟩
    refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _)
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · exact h.toIsComplex.zero i
      · exact h'.toIsComplex.zero 0
    · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith)
      · exact h.exact i
      · 

Proof state:
case mpr.intro.refine'_2.inr
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
n : ℕ
S✝ : ComposableArrows C n
i : ℕ
S : ComposableArrows C (i + 2)
h : Exact (δlast S)
h' : Exact (mk₂ (map' S i (i + 1)) (map' S (i + 1) (i + 2)))
hi : autoParam (i + 2 ≤ i + 2) _auto✝
⊢ ShortComplex.Exact (sc S (_ : IsComplex S) i)

Next tactic:
exact h'.exact 0
/-- The canonical morphism `Abelian.image S.f ⟶ kernel S.g` for a short complex `S`
in an abelian category. -/
noncomputable def abelianImageToKernel : Abelian.image S.f ⟶ kernel S.g :=
  kernel.lift S.g (Abelian.image.ι S.f)
    (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
⊢ Abelian.image.ι S.f ≫ S.g = 0

Next tactic:
simp only [← cancel_epi (Abelian.factorThruImage S.f),
      kernel.lift_ι_assoc, zero, comp_zero]
@[reassoc (attr := simp 1100)]
lemma abelianImageToKernel_comp_kernel_ι_comp_cokernel_π :
    S.abelianImageToKernel ≫ kernel.ι S.g ≫ cokernel.π S.f = 0 := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
⊢ abelianImageToKernel S ≫ kernel.ι S.g ≫ cokernel.π S.f = 0

Next tactic:
simp only [abelianImageToKernel_comp_kernel_ι_assoc, kernel.condition]
/-- `Abelian.image S.f` is the kernel of `kernel.ι S.g ≫ cokernel.π S.f` -/
noncomputable def abelianImageToKernelIsKernel :
    IsLimit (KernelFork.ofι S.abelianImageToKernel
      S.abelianImageToKernel_comp_kernel_ι_comp_cokernel_π) :=
  KernelFork.IsLimit.ofι _ _
    (fun k hk => kernel.lift _ (k ≫ kernel.ι S.g) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
W'✝ : C
k : W'✝ ⟶ kernel S.g
hk : k ≫ kernel.ι S.g ≫ cokernel.π S.f = 0
⊢ (k ≫ kernel.ι S.g) ≫ cokernel.π S.f = 0

Next tactic:
rw [assoc, hk]
/-- `Abelian.image S.f` is the kernel of `kernel.ι S.g ≫ cokernel.π S.f` -/
noncomputable def abelianImageToKernelIsKernel :
    IsLimit (KernelFork.ofι S.abelianImageToKernel
      S.abelianImageToKernel_comp_kernel_ι_comp_cokernel_π) :=
  KernelFork.IsLimit.ofι _ _
    (fun k hk => kernel.lift _ (k ≫ kernel.ι S.g) (by rw [assoc, hk]))
    (fun k hk => by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
W'✝ : C
k : W'✝ ⟶ kernel S.g
hk : k ≫ kernel.ι S.g ≫ cokernel.π S.f = 0
⊢ (fun {W'} k hk => kernel.lift (cokernel.π S.f) (k ≫ kernel.ι S.g) (_ : (k ≫ kernel.ι S.g) ≫ cokernel.π S.f = 0)) k
        hk ≫
      abelianImageToKernel S =
    k

Next tactic:
simp only [← cancel_mono (kernel.ι S.g), assoc,
      abelianImageToKernel_comp_kernel_ι, kernel.lift_ι]
/-- `Abelian.image S.f` is the kernel of `kernel.ι S.g ≫ cokernel.π S.f` -/
noncomputable def abelianImageToKernelIsKernel :
    IsLimit (KernelFork.ofι S.abelianImageToKernel
      S.abelianImageToKernel_comp_kernel_ι_comp_cokernel_π) :=
  KernelFork.IsLimit.ofι _ _
    (fun k hk => kernel.lift _ (k ≫ kernel.ι S.g) (by rw [assoc, hk]))
    (fun k hk => by simp only [← cancel_mono (kernel.ι S.g), assoc,
      abelianImageToKernel_comp_kernel_ι, kernel.lift_ι])
    (fun k hk b hb => by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
W'✝ : C
k : W'✝ ⟶ kernel S.g
hk : k ≫ kernel.ι S.g ≫ cokernel.π S.f = 0
b : W'✝ ⟶ Abelian.image S.f
hb : b ≫ abelianImageToKernel S = k
⊢ b =
    (fun {W'} k hk => kernel.lift (cokernel.π S.f) (k ≫ kernel.ι S.g) (_ : (k ≫ kernel.ι S.g) ≫ cokernel.π S.f = 0)) k
      hk

Next tactic:
simp only [← cancel_mono S.abelianImageToKernel,
      ← cancel_mono (kernel.ι S.g), hb, assoc, abelianImageToKernel_comp_kernel_ι, kernel.lift_ι]
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
⊢ LeftHomologyData S

Next tactic:
let γ := kernel.ι S.g ≫ cokernel.π S.f
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
⊢ LeftHomologyData S

Next tactic:
let f' := kernel.lift S.g S.f S.zero
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
⊢ LeftHomologyData S

Next tactic:
have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
⊢ f' ≫ γ = 0

Next tactic:
simp
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
⊢ f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ

Next tactic:
rw [kernel.lift_ι]
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
⊢ LeftHomologyData S

Next tactic:
have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    rw [hf']
    simp only [assoc, cokernel.condition, comp_zero]
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
⊢ f' ≫ cokernel.π (kernel.ι γ) = 0

Next tactic:
rw [hf']
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    rw [hf']
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
⊢ (kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ) ≫
      cokernel.π (kernel.ι γ) =
    0

Next tactic:
simp only [assoc, cokernel.condition, comp_zero]
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    rw [hf']
    simp only [assoc, cokernel.condition, comp_zero]
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
wπ : f' ≫ cokernel.π (kernel.ι γ) = 0
⊢ LeftHomologyData S

Next tactic:
let e : Abelian.image S.f ≅ kernel γ :=
    IsLimit.conePointUniqueUpToIso S.abelianImageToKernelIsKernel (limit.isLimit _)
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    rw [hf']
    simp only [assoc, cokernel.condition, comp_zero]
  let e : Abelian.image S.f ≅ kernel γ :=
    IsLimit.conePointUniqueUpToIso S.abelianImageToKernelIsKernel (limit.isLimit _)
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
wπ : f' ≫ cokernel.π (kernel.ι γ) = 0
e : Abelian.image S.f ≅ kernel γ :=
  IsLimit.conePointUniqueUpToIso (abelianImageToKernelIsKernel S)
    (limit.isLimit (parallelPair (kernel.ι S.g ≫ cokernel.π S.f) 0))
⊢ LeftHomologyData S

Next tactic:
have he : e.hom ≫ kernel.ι γ = S.abelianImageToKernel :=
    IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingParallelPair.zero
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    rw [hf']
    simp only [assoc, cokernel.condition, comp_zero]
  let e : Abelian.image S.f ≅ kernel γ :=
    IsLimit.conePointUniqueUpToIso S.abelianImageToKernelIsKernel (limit.isLimit _)
  have he : e.hom ≫ kernel.ι γ = S.abelianImageToKernel :=
    IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingParallelPair.zero
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
wπ : f' ≫ cokernel.π (kernel.ι γ) = 0
e : Abelian.image S.f ≅ kernel γ :=
  IsLimit.conePointUniqueUpToIso (abelianImageToKernelIsKernel S)
    (limit.isLimit (parallelPair (kernel.ι S.g ≫ cokernel.π S.f) 0))
he : e.hom ≫ kernel.ι γ = abelianImageToKernel S
⊢ LeftHomologyData S

Next tactic:
have fac : f' = Abelian.factorThruImage S.f ≫ e.hom ≫ kernel.ι γ := by
    rw [hf', he]
    simp only [kernel.lift_ι, abelianImageToKernel, ← cancel_mono (kernel.ι S.g), assoc]
/-- The canonical `LeftHomologyData` of a short complex `S` in an abelian category, for
which the `H` field is `Abelian.coimage (kernel.ι S.g ≫ cokernel.π S.f)`. -/
@[simps]
noncomputable def ofAbelian : S.LeftHomologyData := by
  let γ := kernel.ι S.g ≫ cokernel.π S.f
  let f' := kernel.lift S.g S.f S.zero
  have hf' : f' = kernel.lift γ f' (by simp) ≫ kernel.ι γ := by rw [kernel.lift_ι]
  have wπ : f' ≫ cokernel.π (kernel.ι γ) = 0 := by
    rw [hf']
    simp only [assoc, cokernel.condition, comp_zero]
  let e : Abelian.image S.f ≅ kernel γ :=
    IsLimit.conePointUniqueUpToIso S.abelianImageToKernelIsKernel (limit.isLimit _)
  have he : e.hom ≫ kernel.ι γ = S.abelianImageToKernel :=
    IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingParallelPair.zero
  have fac : f' = Abelian.factorThruImage S.f ≫ e.hom ≫ kernel.ι γ := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
S : ShortComplex C
γ : kernel S.g ⟶ cokernel S.f := kernel.ι S.g ≫ cokernel.π S.f
f' : S.X₁ ⟶ kernel S.g := kernel.lift S.g S.f (_ : S.f ≫ S.g = 0)
hf' :
  f' = kernel.lift γ f' (_ : kernel.lift S.g S.f (_ : S.f ≫ S.g = 0) ≫ kernel.ι S.g ≫ cokernel.π S.f = 0) ≫ kernel.ι γ
wπ : f' ≫ cokernel.π (kernel.ι γ) = 0
e : Abelian.image S.f ≅ kernel γ :=
  IsLimit.conePointUniqueUpToIso (abelianImageToKernelIsKernel S)
    (limit.isLimit (parallelPair (kernel.ι S.g ≫ cokernel.π S.f) 0))
he : e.hom ≫ kernel.ι γ = abelianImageToKernel S
⊢ f' = Abelian.factorThruImage S.f ≫ e.hom ≫ kernel.ι γ

Next tactic:
rw [hf', he]