l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem comp_right_eq_zero [IsIso g] : f ≫ g = 0 ↔ f = 0 := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
P Q R : C
f f' : P ⟶ Q
g g' : Q ⟶ R
inst✝ : IsIso g
⊢ f ≫ g = 0 ↔ f = 0

Next tactic:
rw [← IsIso.eq_comp_inv, Limits.zero_comp]
/-- Map a kernel cone on the difference of two morphisms to the equalizer fork. -/
@[simps! pt]
def forkOfKernelFork (c : KernelFork (f - g)) : Fork f g :=
  Fork.ofι c.ι <| by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : KernelFork (f - g)
⊢ Fork.ι c ≫ f = Fork.ι c ≫ g

Next tactic:
rw [← sub_eq_zero, ← comp_sub, c.condition]
/-- Map any equalizer fork to a cone on the difference of the two morphisms. -/
def kernelForkOfFork (c : Fork f g) : KernelFork (f - g) :=
  Fork.ofι c.ι <| by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : Fork f g
⊢ Fork.ι c ≫ (f - g) = Fork.ι c ≫ 0

Next tactic:
rw [comp_sub, comp_zero, sub_eq_zero, c.condition]
@[simp]
theorem kernelForkOfFork_ofι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) :
    kernelForkOfFork (Fork.ofι ι w) = KernelFork.ofι ι (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
P : C
ι : P ⟶ X
w : ι ≫ f = ι ≫ g
⊢ ι ≫ (f - g) = 0

Next tactic:
simp [w]
/-- A kernel of `f - g` is an equalizer of `f` and `g`. -/
def isLimitForkOfKernelFork {c : KernelFork (f - g)} (i : IsLimit c) :
    IsLimit (forkOfKernelFork c) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨i.lift (kernelForkOfFork s), i.fac _ _, fun h => by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : KernelFork (f - g)
i : IsLimit c
s : Fork f g
m✝ :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (forkOfKernelFork c).pt).obj WalkingParallelPair.zero
h : m✝ ≫ Fork.ι (forkOfKernelFork c) = Fork.ι s
⊢ m✝ = IsLimit.lift i (kernelForkOfFork s)

Next tactic:
apply Fork.IsLimit.hom_ext i
/-- A kernel of `f - g` is an equalizer of `f` and `g`. -/
def isLimitForkOfKernelFork {c : KernelFork (f - g)} (i : IsLimit c) :
    IsLimit (forkOfKernelFork c) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨i.lift (kernelForkOfFork s), i.fac _ _, fun h => by apply Fork.IsLimit.hom_ext i; 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : KernelFork (f - g)
i : IsLimit c
s : Fork f g
m✝ :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (forkOfKernelFork c).pt).obj WalkingParallelPair.zero
h : m✝ ≫ Fork.ι (forkOfKernelFork c) = Fork.ι s
⊢ m✝ ≫ Fork.ι c = IsLimit.lift i (kernelForkOfFork s) ≫ Fork.ι c

Next tactic:
aesop_cat
/-- An equalizer of `f` and `g` is a kernel of `f - g`. -/
def isLimitKernelForkOfFork {c : Fork f g} (i : IsLimit c) : IsLimit (kernelForkOfFork c) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨i.lift (forkOfKernelFork s), i.fac _ _, fun h => by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : Fork f g
i : IsLimit c
s : Fork (f - g) 0
m✝ :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (kernelForkOfFork c).pt).obj WalkingParallelPair.zero
h : m✝ ≫ Fork.ι (kernelForkOfFork c) = Fork.ι s
⊢ m✝ = IsLimit.lift i (forkOfKernelFork s)

Next tactic:
apply Fork.IsLimit.hom_ext i
/-- An equalizer of `f` and `g` is a kernel of `f - g`. -/
def isLimitKernelForkOfFork {c : Fork f g} (i : IsLimit c) : IsLimit (kernelForkOfFork c) :=
  Fork.IsLimit.mk' _ fun s =>
    ⟨i.lift (forkOfKernelFork s), i.fac _ _, fun h => by apply Fork.IsLimit.hom_ext i; 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : Fork f g
i : IsLimit c
s : Fork (f - g) 0
m✝ :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (kernelForkOfFork c).pt).obj WalkingParallelPair.zero
h : m✝ ≫ Fork.ι (kernelForkOfFork c) = Fork.ι s
⊢ m✝ ≫ Fork.ι c = IsLimit.lift i (forkOfKernelFork s) ≫ Fork.ι c

Next tactic:
aesop_cat
/-- Map a cokernel cocone on the difference of two morphisms to the coequalizer cofork. -/
@[simps! pt]
def coforkOfCokernelCofork (c : CokernelCofork (f - g)) : Cofork f g :=
  Cofork.ofπ c.π <| by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : CokernelCofork (f - g)
⊢ f ≫ Cofork.π c = g ≫ Cofork.π c

Next tactic:
rw [← sub_eq_zero, ← sub_comp, c.condition]
/-- Map any coequalizer cofork to a cocone on the difference of the two morphisms. -/
def cokernelCoforkOfCofork (c : Cofork f g) : CokernelCofork (f - g) :=
  Cofork.ofπ c.π <| by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : Cofork f g
⊢ (f - g) ≫ Cofork.π c = 0 ≫ Cofork.π c

Next tactic:
rw [sub_comp, zero_comp, sub_eq_zero, c.condition]
@[simp]
theorem cokernelCoforkOfCofork_ofπ {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) :
    cokernelCoforkOfCofork (Cofork.ofπ π w) = CokernelCofork.ofπ π (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
P : C
π : Y ⟶ P
w : f ≫ π = g ≫ π
⊢ (f - g) ≫ π = 0

Next tactic:
simp [w]
/-- A cokernel of `f - g` is a coequalizer of `f` and `g`. -/
def isColimitCoforkOfCokernelCofork {c : CokernelCofork (f - g)} (i : IsColimit c) :
    IsColimit (coforkOfCokernelCofork c) :=
  Cofork.IsColimit.mk' _ fun s =>
    ⟨i.desc (cokernelCoforkOfCofork s), i.fac _ _, fun h => by
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : CokernelCofork (f - g)
i : IsColimit c
s : Cofork f g
m✝ :
  ((Functor.const WalkingParallelPair).obj (coforkOfCokernelCofork c).pt).obj WalkingParallelPair.one ⟶
    ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.one
h : Cofork.π (coforkOfCokernelCofork c) ≫ m✝ = Cofork.π s
⊢ m✝ = IsColimit.desc i (cokernelCoforkOfCofork s)

Next tactic:
apply Cofork.IsColimit.hom_ext i
/-- A cokernel of `f - g` is a coequalizer of `f` and `g`. -/
def isColimitCoforkOfCokernelCofork {c : CokernelCofork (f - g)} (i : IsColimit c) :
    IsColimit (coforkOfCokernelCofork c) :=
  Cofork.IsColimit.mk' _ fun s =>
    ⟨i.desc (cokernelCoforkOfCofork s), i.fac _ _, fun h => by
      apply Cofork.IsColimit.hom_ext i; 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : CokernelCofork (f - g)
i : IsColimit c
s : Cofork f g
m✝ :
  ((Functor.const WalkingParallelPair).obj (coforkOfCokernelCofork c).pt).obj WalkingParallelPair.one ⟶
    ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.one
h : Cofork.π (coforkOfCokernelCofork c) ≫ m✝ = Cofork.π s
⊢ Cofork.π c ≫ m✝ = Cofork.π c ≫ IsColimit.desc i (cokernelCoforkOfCofork s)

Next tactic:
aesop_cat
/-- A coequalizer of `f` and `g` is a cokernel of `f - g`. -/
def isColimitCokernelCoforkOfCofork {c : Cofork f g} (i : IsColimit c) :
    IsColimit (cokernelCoforkOfCofork c) :=
  Cofork.IsColimit.mk' _ fun s =>
    ⟨i.desc (coforkOfCokernelCofork s), i.fac _ _, fun h => by
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : Cofork f g
i : IsColimit c
s : Cofork (f - g) 0
m✝ :
  ((Functor.const WalkingParallelPair).obj (cokernelCoforkOfCofork c).pt).obj WalkingParallelPair.one ⟶
    ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.one
h : Cofork.π (cokernelCoforkOfCofork c) ≫ m✝ = Cofork.π s
⊢ m✝ = IsColimit.desc i (coforkOfCokernelCofork s)

Next tactic:
apply Cofork.IsColimit.hom_ext i
/-- A coequalizer of `f` and `g` is a cokernel of `f - g`. -/
def isColimitCokernelCoforkOfCofork {c : Cofork f g} (i : IsColimit c) :
    IsColimit (cokernelCoforkOfCofork c) :=
  Cofork.IsColimit.mk' _ fun s =>
    ⟨i.desc (coforkOfCokernelCofork s), i.fac _ _, fun h => by
      apply Cofork.IsColimit.hom_ext i; 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Preadditive C
X Y : C
f g : X ⟶ Y
c : Cofork f g
i : IsColimit c
s : Cofork (f - g) 0
m✝ :
  ((Functor.const WalkingParallelPair).obj (cokernelCoforkOfCofork c).pt).obj WalkingParallelPair.one ⟶
    ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.one
h : Cofork.π (cokernelCoforkOfCofork c) ≫ m✝ = Cofork.π s
⊢ Cofork.π c ≫ m✝ = Cofork.π c ≫ IsColimit.desc i (coforkOfCokernelCofork s)

Next tactic:
aesop_cat
instance : SMul (Units ℤ) (X ≅ Y) where
  smul a e :=
    { hom := (a : ℤ) • e.hom
      inv := ((a⁻¹ : Units ℤ) : ℤ) • e.inv
      hom_inv_id := by
        

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.123911, u_1} C
inst✝ : Preadditive C
X Y : C
a : ℤˣ
e : X ≅ Y
⊢ (↑a • e.hom) ≫ (↑a⁻¹ • e.inv) = 𝟙 X

Next tactic:
simp only [comp_zsmul, zsmul_comp, smul_smul, Units.inv_mul, one_smul, e.hom_inv_id]
instance : SMul (Units ℤ) (X ≅ Y) where
  smul a e :=
    { hom := (a : ℤ) • e.hom
      inv := ((a⁻¹ : Units ℤ) : ℤ) • e.inv
      hom_inv_id := by
        simp only [comp_zsmul, zsmul_comp, smul_smul, Units.inv_mul, one_smul, e.hom_inv_id]
      inv_hom_id := by
        

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.123911, u_1} C
inst✝ : Preadditive C
X Y : C
a : ℤˣ
e : X ≅ Y
⊢ (↑a⁻¹ • e.inv) ≫ (↑a • e.hom) = 𝟙 Y

Next tactic:
simp only [comp_zsmul, zsmul_comp, smul_smul, Units.mul_inv, one_smul, e.inv_hom_id]
lemma exact_iff_isZero_homology [S.HasHomology] :
    S.Exact ↔ IsZero S.homology := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.1374, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
⊢ Exact S ↔ IsZero (homology S)

Next tactic:
constructor
lemma exact_iff_isZero_homology [S.HasHomology] :
    S.Exact ↔ IsZero S.homology := by
  constructor
  · 

Proof state:
case mp
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.1374, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
⊢ Exact S → IsZero (homology S)

Next tactic:
rintro ⟨⟨h', z⟩⟩
lemma exact_iff_isZero_homology [S.HasHomology] :
    S.Exact ↔ IsZero S.homology := by
  constructor
  · rintro ⟨⟨h', z⟩⟩
    

Proof state:
case mp.mk.intro
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.1374, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
h' : HomologyData S
z : IsZero h'.left.H
⊢ IsZero (homology S)

Next tactic:
exact IsZero.of_iso z h'.left.homologyIso
lemma exact_iff_isZero_homology [S.HasHomology] :
    S.Exact ↔ IsZero S.homology := by
  constructor
  · rintro ⟨⟨h', z⟩⟩
    exact IsZero.of_iso z h'.left.homologyIso
  · 

Proof state:
case mpr
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.1374, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
⊢ IsZero (homology S) → Exact S

Next tactic:
intro h
lemma exact_iff_isZero_homology [S.HasHomology] :
    S.Exact ↔ IsZero S.homology := by
  constructor
  · rintro ⟨⟨h', z⟩⟩
    exact IsZero.of_iso z h'.left.homologyIso
  · intro h
    

Proof state:
case mpr
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.1374, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
h : IsZero (homology S)
⊢ Exact S

Next tactic:
exact ⟨⟨_, h⟩⟩
lemma LeftHomologyData.exact_iff [S.HasHomology]
    (h : S.LeftHomologyData) :
    S.Exact ↔ IsZero h.H := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.2159, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
h : LeftHomologyData S
⊢ Exact S ↔ IsZero h.H

Next tactic:
rw [S.exact_iff_isZero_homology]
lemma LeftHomologyData.exact_iff [S.HasHomology]
    (h : S.LeftHomologyData) :
    S.Exact ↔ IsZero h.H := by
  rw [S.exact_iff_isZero_homology]
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.2159, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
h : LeftHomologyData S
⊢ IsZero (homology S) ↔ IsZero h.H

Next tactic:
exact Iso.isZero_iff h.homologyIso
lemma RightHomologyData.exact_iff [S.HasHomology]
    (h : S.RightHomologyData) :
    S.Exact ↔ IsZero h.H := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.2604, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
h : RightHomologyData S
⊢ Exact S ↔ IsZero h.H

Next tactic:
rw [S.exact_iff_isZero_homology]
lemma RightHomologyData.exact_iff [S.HasHomology]
    (h : S.RightHomologyData) :
    S.Exact ↔ IsZero h.H := by
  rw [S.exact_iff_isZero_homology]
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{?u.2604, u_2} D
inst✝² : HasZeroMorphisms C
inst✝¹ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝ : HasHomology S
h : RightHomologyData S
⊢ IsZero (homology S) ↔ IsZero h.H

Next tactic:
exact Iso.isZero_iff h.homologyIso
lemma HomologyData.exact_iff (h : S.HomologyData) :
    S.Exact ↔ IsZero h.left.H := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.4193, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
h : HomologyData S
⊢ Exact S ↔ IsZero h.left.H

Next tactic:
haveI := HasHomology.mk' h
lemma HomologyData.exact_iff (h : S.HomologyData) :
    S.Exact ↔ IsZero h.left.H := by
  haveI := HasHomology.mk' h
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.4193, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
h : HomologyData S
this : HasHomology S
⊢ Exact S ↔ IsZero h.left.H

Next tactic:
exact LeftHomologyData.exact_iff h.left
lemma HomologyData.exact_iff' (h : S.HomologyData) :
    S.Exact ↔ IsZero h.right.H := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.4629, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
h : HomologyData S
⊢ Exact S ↔ IsZero h.right.H

Next tactic:
haveI := HasHomology.mk' h
lemma HomologyData.exact_iff' (h : S.HomologyData) :
    S.Exact ↔ IsZero h.right.H := by
  haveI := HasHomology.mk' h
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.4629, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
h : HomologyData S
this : HasHomology S
⊢ Exact S ↔ IsZero h.right.H

Next tactic:
exact RightHomologyData.exact_iff h.right
lemma exact_iff_homology_iso_zero [S.HasHomology] [HasZeroObject C] :
    S.Exact ↔ Nonempty (S.homology ≅ 0) := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{u_3, u_1} C
inst✝⁴ : Category.{?u.5166, u_2} D
inst✝³ : HasZeroMorphisms C
inst✝² : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝¹ : HasHomology S
inst✝ : HasZeroObject C
⊢ Exact S ↔ Nonempty (homology S ≅ 0)

Next tactic:
rw [exact_iff_isZero_homology]
lemma exact_iff_homology_iso_zero [S.HasHomology] [HasZeroObject C] :
    S.Exact ↔ Nonempty (S.homology ≅ 0) := by
  rw [exact_iff_isZero_homology]
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{u_3, u_1} C
inst✝⁴ : Category.{?u.5166, u_2} D
inst✝³ : HasZeroMorphisms C
inst✝² : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝¹ : HasHomology S
inst✝ : HasZeroObject C
⊢ IsZero (homology S) ↔ Nonempty (homology S ≅ 0)

Next tactic:
constructor
lemma exact_iff_homology_iso_zero [S.HasHomology] [HasZeroObject C] :
    S.Exact ↔ Nonempty (S.homology ≅ 0) := by
  rw [exact_iff_isZero_homology]
  constructor
  · 

Proof state:
case mp
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{u_3, u_1} C
inst✝⁴ : Category.{?u.5166, u_2} D
inst✝³ : HasZeroMorphisms C
inst✝² : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝¹ : HasHomology S
inst✝ : HasZeroObject C
⊢ IsZero (homology S) → Nonempty (homology S ≅ 0)

Next tactic:
intro h
lemma exact_iff_homology_iso_zero [S.HasHomology] [HasZeroObject C] :
    S.Exact ↔ Nonempty (S.homology ≅ 0) := by
  rw [exact_iff_isZero_homology]
  constructor
  · intro h
    

Proof state:
case mp
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{u_3, u_1} C
inst✝⁴ : Category.{?u.5166, u_2} D
inst✝³ : HasZeroMorphisms C
inst✝² : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝¹ : HasHomology S
inst✝ : HasZeroObject C
h : IsZero (homology S)
⊢ Nonempty (homology S ≅ 0)

Next tactic:
exact ⟨h.isoZero⟩
lemma exact_iff_homology_iso_zero [S.HasHomology] [HasZeroObject C] :
    S.Exact ↔ Nonempty (S.homology ≅ 0) := by
  rw [exact_iff_isZero_homology]
  constructor
  · intro h
    exact ⟨h.isoZero⟩
  · 

Proof state:
case mpr
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{u_3, u_1} C
inst✝⁴ : Category.{?u.5166, u_2} D
inst✝³ : HasZeroMorphisms C
inst✝² : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝¹ : HasHomology S
inst✝ : HasZeroObject C
⊢ Nonempty (homology S ≅ 0) → IsZero (homology S)

Next tactic:
rintro ⟨e⟩
lemma exact_iff_homology_iso_zero [S.HasHomology] [HasZeroObject C] :
    S.Exact ↔ Nonempty (S.homology ≅ 0) := by
  rw [exact_iff_isZero_homology]
  constructor
  · intro h
    exact ⟨h.isoZero⟩
  · rintro ⟨e⟩
    

Proof state:
case mpr.intro
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{u_3, u_1} C
inst✝⁴ : Category.{?u.5166, u_2} D
inst✝³ : HasZeroMorphisms C
inst✝² : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
inst✝¹ : HasHomology S
inst✝ : HasZeroObject C
e : homology S ≅ 0
⊢ IsZero (homology S)

Next tactic:
exact IsZero.of_iso (isZero_zero C) e
lemma exact_of_iso (e : S₁ ≅ S₂) (h : S₁.Exact) : S₂.Exact := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.6207, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
e : S₁ ≅ S₂
h : Exact S₁
⊢ Exact S₂

Next tactic:
obtain ⟨⟨h, z⟩⟩ := h
lemma exact_of_iso (e : S₁ ≅ S₂) (h : S₁.Exact) : S₂.Exact := by
  obtain ⟨⟨h, z⟩⟩ := h
  

Proof state:
case mk.intro
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.6207, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
e : S₁ ≅ S₂
h : HomologyData S₁
z : IsZero h.left.H
⊢ Exact S₂

Next tactic:
exact ⟨⟨HomologyData.ofIso e h, z⟩⟩
lemma exact_and_mono_f_iff_of_iso (e : S₁ ≅ S₂) :
    S₁.Exact ∧ Mono S₁.f ↔ S₂.Exact ∧ Mono S₂.f := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.7742, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
e : S₁ ≅ S₂
⊢ Exact S₁ ∧ Mono S₁.f ↔ Exact S₂ ∧ Mono S₂.f

Next tactic:
have : Mono S₁.f ↔ Mono S₂.f :=
    MorphismProperty.RespectsIso.arrow_mk_iso_iff
      (MorphismProperty.RespectsIso.monomorphisms C)
      (Arrow.isoMk (ShortComplex.π₁.mapIso e) (ShortComplex.π₂.mapIso e) e.hom.comm₁₂)
lemma exact_and_mono_f_iff_of_iso (e : S₁ ≅ S₂) :
    S₁.Exact ∧ Mono S₁.f ↔ S₂.Exact ∧ Mono S₂.f := by
  have : Mono S₁.f ↔ Mono S₂.f :=
    MorphismProperty.RespectsIso.arrow_mk_iso_iff
      (MorphismProperty.RespectsIso.monomorphisms C)
      (Arrow.isoMk (ShortComplex.π₁.mapIso e) (ShortComplex.π₂.mapIso e) e.hom.comm₁₂)
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.7742, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
e : S₁ ≅ S₂
this : Mono S₁.f ↔ Mono S₂.f
⊢ Exact S₁ ∧ Mono S₁.f ↔ Exact S₂ ∧ Mono S₂.f

Next tactic:
rw [exact_iff_of_iso e, this]
lemma exact_and_epi_g_iff_of_iso (e : S₁ ≅ S₂) :
    S₁.Exact ∧ Epi S₁.g ↔ S₂.Exact ∧ Epi S₂.g := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.9829, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
e : S₁ ≅ S₂
⊢ Exact S₁ ∧ Epi S₁.g ↔ Exact S₂ ∧ Epi S₂.g

Next tactic:
have : Epi S₁.g ↔ Epi S₂.g :=
    MorphismProperty.RespectsIso.arrow_mk_iso_iff
      (MorphismProperty.RespectsIso.epimorphisms C)
      (Arrow.isoMk (ShortComplex.π₂.mapIso e) (ShortComplex.π₃.mapIso e) e.hom.comm₂₃)
lemma exact_and_epi_g_iff_of_iso (e : S₁ ≅ S₂) :
    S₁.Exact ∧ Epi S₁.g ↔ S₂.Exact ∧ Epi S₂.g := by
  have : Epi S₁.g ↔ Epi S₂.g :=
    MorphismProperty.RespectsIso.arrow_mk_iso_iff
      (MorphismProperty.RespectsIso.epimorphisms C)
      (Arrow.isoMk (ShortComplex.π₂.mapIso e) (ShortComplex.π₃.mapIso e) e.hom.comm₂₃)
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.9829, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
e : S₁ ≅ S₂
this : Epi S₁.g ↔ Epi S₂.g
⊢ Exact S₁ ∧ Epi S₁.g ↔ Exact S₂ ∧ Epi S₂.g

Next tactic:
rw [exact_iff_of_iso e, this]
lemma exact_of_isZero_X₂ (h : IsZero S.X₂) : S.Exact := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.11916, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
h : IsZero S.X₂
⊢ Exact S

Next tactic:
rw [(HomologyData.ofZeros S (IsZero.eq_of_tgt h _ _) (IsZero.eq_of_src h _ _)).exact_iff]
lemma exact_of_isZero_X₂ (h : IsZero S.X₂) : S.Exact := by
  rw [(HomologyData.ofZeros S (IsZero.eq_of_tgt h _ _) (IsZero.eq_of_src h _ _)).exact_iff]
  

Proof state:
C : Type u_1
D : Type u_2
inst✝³ : Category.{u_3, u_1} C
inst✝² : Category.{?u.11916, u_2} D
inst✝¹ : HasZeroMorphisms C
inst✝ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
h : IsZero S.X₂
⊢ IsZero (HomologyData.ofZeros S (_ : S.f = 0) (_ : S.g = 0)).left.H

Next tactic:
exact h
lemma exact_iff_of_epi_of_isIso_of_mono (φ : S₁ ⟶ S₂) [Epi φ.τ₁] [IsIso φ.τ₂] [Mono φ.τ₃] :
    S₁.Exact ↔ S₂.Exact := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁶ : Category.{u_3, u_1} C
inst✝⁵ : Category.{?u.12305, u_2} D
inst✝⁴ : HasZeroMorphisms C
inst✝³ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
φ : S₁ ⟶ S₂
inst✝² : Epi φ.τ₁
inst✝¹ : IsIso φ.τ₂
inst✝ : Mono φ.τ₃
⊢ Exact S₁ ↔ Exact S₂

Next tactic:
constructor
lemma exact_iff_of_epi_of_isIso_of_mono (φ : S₁ ⟶ S₂) [Epi φ.τ₁] [IsIso φ.τ₂] [Mono φ.τ₃] :
    S₁.Exact ↔ S₂.Exact := by
  constructor
  · 

Proof state:
case mp
C : Type u_1
D : Type u_2
inst✝⁶ : Category.{u_3, u_1} C
inst✝⁵ : Category.{?u.12305, u_2} D
inst✝⁴ : HasZeroMorphisms C
inst✝³ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
φ : S₁ ⟶ S₂
inst✝² : Epi φ.τ₁
inst✝¹ : IsIso φ.τ₂
inst✝ : Mono φ.τ₃
⊢ Exact S₁ → Exact S₂

Next tactic:
rintro ⟨h₁, z₁⟩
lemma exact_iff_of_epi_of_isIso_of_mono (φ : S₁ ⟶ S₂) [Epi φ.τ₁] [IsIso φ.τ₂] [Mono φ.τ₃] :
    S₁.Exact ↔ S₂.Exact := by
  constructor
  · rintro ⟨h₁, z₁⟩
    

Proof state:
case mp.mk.intro
C : Type u_1
D : Type u_2
inst✝⁶ : Category.{u_3, u_1} C
inst✝⁵ : Category.{?u.12305, u_2} D
inst✝⁴ : HasZeroMorphisms C
inst✝³ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
φ : S₁ ⟶ S₂
inst✝² : Epi φ.τ₁
inst✝¹ : IsIso φ.τ₂
inst✝ : Mono φ.τ₃
h₁ : HomologyData S₁
z₁ : IsZero h₁.left.H
⊢ Exact S₂

Next tactic:
exact ⟨HomologyData.ofEpiOfIsIsoOfMono φ h₁, z₁⟩
lemma exact_iff_of_epi_of_isIso_of_mono (φ : S₁ ⟶ S₂) [Epi φ.τ₁] [IsIso φ.τ₂] [Mono φ.τ₃] :
    S₁.Exact ↔ S₂.Exact := by
  constructor
  · rintro ⟨h₁, z₁⟩
    exact ⟨HomologyData.ofEpiOfIsIsoOfMono φ h₁, z₁⟩
  · 

Proof state:
case mpr
C : Type u_1
D : Type u_2
inst✝⁶ : Category.{u_3, u_1} C
inst✝⁵ : Category.{?u.12305, u_2} D
inst✝⁴ : HasZeroMorphisms C
inst✝³ : HasZeroMorphisms D
S S₁ S₂ : ShortComplex C
φ : S₁ ⟶ S₂
inst✝² : Epi φ.τ₁
inst✝¹ : IsIso φ.τ₂
inst✝ : Mono φ.τ₃
⊢ Exact S₂ → Exact S₁

Next tactic:
rintro ⟨h₂, z₂⟩