l3lab/ntp-mathlib huggingface dataset:
theorem zero_of_num_zero {q : ℚ} (hq : q.num = 0) : q = 0 := by
  

Proof state:
a b c q : ℚ
hq : q.num = 0
⊢ q = 0

Next tactic:
have : q = q.num /. q.den := num_den.symm
theorem zero_of_num_zero {q : ℚ} (hq : q.num = 0) : q = 0 := by
  have : q = q.num /. q.den := num_den.symm
  

Proof state:
a b c q : ℚ
hq : q.num = 0
this : q = q.num /. ↑q.den
⊢ q = 0

Next tactic:
simpa [hq] using this
theorem zero_iff_num_zero {q : ℚ} : q = 0 ↔ q.num = 0 :=
  ⟨fun _ => by 

Proof state:
a b c q : ℚ
x✝ : q = 0
⊢ q.num = 0

Next tactic:
simp [*]
theorem mk_num_ne_zero_of_ne_zero {q : ℚ} {n d : ℤ} (hq : q ≠ 0) (hqnd : q = n /. d) : n ≠ 0 :=
  fun this => hq <| by 

Proof state:
a b c q : ℚ
n d : ℤ
hq : q ≠ 0
hqnd : q = n /. d
this : n = 0
⊢ q = 0

Next tactic:
simpa [this] using hqnd
theorem mk_denom_ne_zero_of_ne_zero {q : ℚ} {n d : ℤ} (hq : q ≠ 0) (hqnd : q = n /. d) : d ≠ 0 :=
  fun this => hq <| by 

Proof state:
a b c q : ℚ
n d : ℤ
hq : q ≠ 0
hqnd : q = n /. d
this : d = 0
⊢ q = 0

Next tactic:
simpa [this] using hqnd
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  

Proof state:
a b c q r : ℚ
⊢ q * r = q.num * r.num /. ↑(q.den * r.den)

Next tactic:
have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by 

Proof state:
a b c q r : ℚ
⊢ ↑q.den ≠ 0

Next tactic:
have := den_nz q
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; 

Proof state:
a b c q r : ℚ
this : q.den ≠ 0
⊢ ↑q.den ≠ 0

Next tactic:
simpa
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
  

Proof state:
a b c q r : ℚ
hq' : ↑q.den ≠ 0
⊢ q * r = q.num * r.num /. ↑(q.den * r.den)

Next tactic:
have hr' : (↑r.den : ℤ) ≠ 0 := by have := den_nz r; simpa
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
  have hr' : (↑r.den : ℤ) ≠ 0 := by 

Proof state:
a b c q r : ℚ
hq' : ↑q.den ≠ 0
⊢ ↑r.den ≠ 0

Next tactic:
have := den_nz r
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
  have hr' : (↑r.den : ℤ) ≠ 0 := by have := den_nz r; 

Proof state:
a b c q r : ℚ
hq' : ↑q.den ≠ 0
this : r.den ≠ 0
⊢ ↑r.den ≠ 0

Next tactic:
simpa
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
  have hr' : (↑r.den : ℤ) ≠ 0 := by have := den_nz r; simpa
  

Proof state:
a b c q r : ℚ
hq' : ↑q.den ≠ 0
hr' : ↑r.den ≠ 0
⊢ q * r = q.num * r.num /. ↑(q.den * r.den)

Next tactic:
suffices q.num /. ↑q.den * (r.num /. ↑r.den) = q.num * r.num /. ↑(q.den * r.den) by
    simpa [num_den] using this
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
  have hr' : (↑r.den : ℤ) ≠ 0 := by have := den_nz r; simpa
  suffices q.num /. ↑q.den * (r.num /. ↑r.den) = q.num * r.num /. ↑(q.den * r.den) by
    

Proof state:
a b c q r : ℚ
hq' : ↑q.den ≠ 0
hr' : ↑r.den ≠ 0
this : q.num /. ↑q.den * (r.num /. ↑r.den) = q.num * r.num /. ↑(q.den * r.den)
⊢ q * r = q.num * r.num /. ↑(q.den * r.den)

Next tactic:
simpa [num_den] using this
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) := by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := den_nz q; simpa
  have hr' : (↑r.den : ℤ) ≠ 0 := by have := den_nz r; simpa
  suffices q.num /. ↑q.den * (r.num /. ↑r.den) = q.num * r.num /. ↑(q.den * r.den) by
    simpa [num_den] using this
  

Proof state:
a b c q r : ℚ
hq' : ↑q.den ≠ 0
hr' : ↑r.den ≠ 0
⊢ q.num /. ↑q.den * (r.num /. ↑r.den) = q.num * r.num /. ↑(q.den * r.den)

Next tactic:
simp [mul_def' hq' hr']
theorem div_num_den (q r : ℚ) : q / r = q.num * r.den /. (q.den * r.num) :=
  if hr : r.num = 0 then by
    

Proof state:
a b c q r : ℚ
hr : r.num = 0
⊢ q / r = q.num * ↑r.den /. (↑q.den * r.num)

Next tactic:
have hr' : r = 0 := zero_of_num_zero hr
theorem div_num_den (q r : ℚ) : q / r = q.num * r.den /. (q.den * r.num) :=
  if hr : r.num = 0 then by
    have hr' : r = 0 := zero_of_num_zero hr
    

Proof state:
a b c q r : ℚ
hr : r.num = 0
hr' : r = 0
⊢ q / r = q.num * ↑r.den /. (↑q.den * r.num)

Next tactic:
simp [*]
theorem div_num_den (q r : ℚ) : q / r = q.num * r.den /. (q.den * r.num) :=
  if hr : r.num = 0 then by
    have hr' : r = 0 := zero_of_num_zero hr
    simp [*]
  else
    calc
      q / r = q * r⁻¹ := div_eq_mul_inv q r
      _ = q.num /. q.den * (r.num /. r.den)⁻¹ := by 

Proof state:
a b c q r : ℚ
hr : ¬r.num = 0
⊢ q * r⁻¹ = q.num /. ↑q.den * (r.num /. ↑r.den)⁻¹

Next tactic:
simp [num_den]
theorem div_num_den (q r : ℚ) : q / r = q.num * r.den /. (q.den * r.num) :=
  if hr : r.num = 0 then by
    have hr' : r = 0 := zero_of_num_zero hr
    simp [*]
  else
    calc
      q / r = q * r⁻¹ := div_eq_mul_inv q r
      _ = q.num /. q.den * (r.num /. r.den)⁻¹ := by simp [num_den]
      _ = q.num /. q.den * (r.den /. r.num) := by 

Proof state:
a b c q r : ℚ
hr : ¬r.num = 0
⊢ q.num /. ↑q.den * (r.num /. ↑r.den)⁻¹ = q.num /. ↑q.den * (↑r.den /. r.num)

Next tactic:
rw [inv_def']
theorem div_num_den (q r : ℚ) : q / r = q.num * r.den /. (q.den * r.num) :=
  if hr : r.num = 0 then by
    have hr' : r = 0 := zero_of_num_zero hr
    simp [*]
  else
    calc
      q / r = q * r⁻¹ := div_eq_mul_inv q r
      _ = q.num /. q.den * (r.num /. r.den)⁻¹ := by simp [num_den]
      _ = q.num /. q.den * (r.den /. r.num) := by rw [inv_def']
      _ = q.num * r.den /. (q.den * r.num) := mul_def' (by 

Proof state:
a b c q r : ℚ
hr : ¬r.num = 0
⊢ ↑q.den ≠ 0

Next tactic:
simpa using den_nz q
protected theorem add_divInt (a b c : ℤ) : (a + b) /. c = a /. c + b /. c :=
  if h : c = 0 then by 

Proof state:
a✝ b✝ c✝ : ℚ
a b c : ℤ
h : c = 0
⊢ (a + b) /. c = a /. c + b /. c

Next tactic:
simp [h]
protected theorem add_divInt (a b c : ℤ) : (a + b) /. c = a /. c + b /. c :=
  if h : c = 0 then by simp [h]
  else by
    

Proof state:
a✝ b✝ c✝ : ℚ
a b c : ℤ
h : ¬c = 0
⊢ (a + b) /. c = a /. c + b /. c

Next tactic:
rw [add_def'' h h, divInt_eq_iff h (mul_ne_zero h h)]
protected theorem add_divInt (a b c : ℤ) : (a + b) /. c = a /. c + b /. c :=
  if h : c = 0 then by simp [h]
  else by
    rw [add_def'' h h, divInt_eq_iff h (mul_ne_zero h h)]
    

Proof state:
a✝ b✝ c✝ : ℚ
a b c : ℤ
h : ¬c = 0
⊢ (a + b) * (c * c) = (a * c + b * c) * c

Next tactic:
simp [add_mul, mul_assoc]
theorem divInt_eq_div (n d : ℤ) : n /. d = (n : ℚ) / d := by
  

Proof state:
a b c : ℚ
n d : ℤ
⊢ n /. d = ↑n / ↑d

Next tactic:
by_cases d0 : d = 0
theorem divInt_eq_div (n d : ℤ) : n /. d = (n : ℚ) / d := by
  by_cases d0 : d = 0
  · 

Proof state:
case pos
a b c : ℚ
n d : ℤ
d0 : d = 0
⊢ n /. d = ↑n / ↑d

Next tactic:
simp [d0, div_zero]
theorem divInt_eq_div (n d : ℤ) : n /. d = (n : ℚ) / d := by
  by_cases d0 : d = 0
  · simp [d0, div_zero]
  

Proof state:
case neg
a b c : ℚ
n d : ℤ
d0 : ¬d = 0
⊢ n /. d = ↑n / ↑d

Next tactic:
simp [division_def, coe_int_eq_divInt, mul_def' one_ne_zero d0]
theorem divInt_mul_divInt_cancel {x : ℤ} (hx : x ≠ 0) (n d : ℤ) : n /. x * (x /. d) = n /. d := by
  

Proof state:
a b c : ℚ
x : ℤ
hx : x ≠ 0
n d : ℤ
⊢ n /. x * (x /. d) = n /. d

Next tactic:
by_cases hd : d = 0
theorem divInt_mul_divInt_cancel {x : ℤ} (hx : x ≠ 0) (n d : ℤ) : n /. x * (x /. d) = n /. d := by
  by_cases hd : d = 0
  · 

Proof state:
case pos
a b c : ℚ
x : ℤ
hx : x ≠ 0
n d : ℤ
hd : d = 0
⊢ n /. x * (x /. d) = n /. d

Next tactic:
rw [hd]
theorem divInt_mul_divInt_cancel {x : ℤ} (hx : x ≠ 0) (n d : ℤ) : n /. x * (x /. d) = n /. d := by
  by_cases hd : d = 0
  · rw [hd]
    

Proof state:
case pos
a b c : ℚ
x : ℤ
hx : x ≠ 0
n d : ℤ
hd : d = 0
⊢ n /. x * (x /. 0) = n /. 0

Next tactic:
simp
theorem divInt_mul_divInt_cancel {x : ℤ} (hx : x ≠ 0) (n d : ℤ) : n /. x * (x /. d) = n /. d := by
  by_cases hd : d = 0
  · rw [hd]
    simp
  

Proof state:
case neg
a b c : ℚ
x : ℤ
hx : x ≠ 0
n d : ℤ
hd : ¬d = 0
⊢ n /. x * (x /. d) = n /. d

Next tactic:
rw [mul_def' hx hd, mul_comm x, divInt_mul_right hx]
theorem divInt_div_divInt_cancel_left {x : ℤ} (hx : x ≠ 0) (n d : ℤ) :
    n /. x / (d /. x) = n /. d := by
  

Proof state:
a b c : ℚ
x : ℤ
hx : x ≠ 0
n d : ℤ
⊢ n /. x / (d /. x) = n /. d

Next tactic:
rw [div_eq_mul_inv, inv_def', divInt_mul_divInt_cancel hx]
theorem divInt_div_divInt_cancel_right {x : ℤ} (hx : x ≠ 0) (n d : ℤ) :
    x /. n / (x /. d) = d /. n := by
  

Proof state:
a b c : ℚ
x : ℤ
hx : x ≠ 0
n d : ℤ
⊢ x /. n / (x /. d) = d /. n

Next tactic:
rw [div_eq_mul_inv, inv_def', mul_comm, divInt_mul_divInt_cancel hx]
theorem coe_int_div_eq_divInt {n d : ℤ} : (n : ℚ) / (d) = n /. d := by
  

Proof state:
a b c : ℚ
n d : ℤ
⊢ ↑n / ↑d = n /. d

Next tactic:
repeat' rw [coe_int_eq_divInt]
theorem coe_int_div_eq_divInt {n d : ℤ} : (n : ℚ) / (d) = n /. d := by
  repeat' 

Proof state:
a b c : ℚ
n d : ℤ
⊢ ↑n / ↑d = n /. d

Next tactic:
rw [coe_int_eq_divInt]
theorem coe_int_div_eq_divInt {n d : ℤ} : (n : ℚ) / (d) = n /. d := by
  repeat' 

Proof state:
a b c : ℚ
n d : ℤ
⊢ n /. 1 / ↑d = n /. d

Next tactic:
rw [coe_int_eq_divInt]
theorem coe_int_div_eq_divInt {n d : ℤ} : (n : ℚ) / (d) = n /. d := by
  repeat' 

Proof state:
a b c : ℚ
n d : ℤ
⊢ n /. 1 / (d /. 1) = n /. d

Next tactic:
rw [coe_int_eq_divInt]
theorem coe_int_div_eq_divInt {n d : ℤ} : (n : ℚ) / (d) = n /. d := by
  repeat' rw [coe_int_eq_divInt]
  

Proof state:
a b c : ℚ
n d : ℤ
⊢ n /. 1 / (d /. 1) = n /. d

Next tactic:
exact divInt_div_divInt_cancel_left one_ne_zero n d
theorem num_div_den (r : ℚ) : (r.num : ℚ) / (r.den : ℚ) = r := by
  

Proof state:
a b c r : ℚ
⊢ ↑r.num / ↑r.den = r

Next tactic:
rw [← Int.cast_ofNat]
theorem num_div_den (r : ℚ) : (r.num : ℚ) / (r.den : ℚ) = r := by
  rw [← Int.cast_ofNat]
  

Proof state:
a b c r : ℚ
⊢ ↑r.num / ↑↑r.den = r

Next tactic:
erw [← divInt_eq_div, num_den]
theorem coe_int_num_of_den_eq_one {q : ℚ} (hq : q.den = 1) : (q.num : ℚ) = q := by
  

Proof state:
a b c q : ℚ
hq : q.den = 1
⊢ ↑q.num = q

Next tactic:
conv_rhs => rw [← @num_den q, hq]
theorem coe_int_num_of_den_eq_one {q : ℚ} (hq : q.den = 1) : (q.num : ℚ) = q := by
  conv_rhs => 

Proof state:
a b c q : ℚ
hq : q.den = 1
| q

Next tactic:
rw [← @num_den q, hq]
theorem coe_int_num_of_den_eq_one {q : ℚ} (hq : q.den = 1) : (q.num : ℚ) = q := by
  conv_rhs => rw [← @num_den q, hq]
  

Proof state:
a b c q : ℚ
hq : q.den = 1
⊢ ↑q.num = q.num /. ↑1

Next tactic:
rw [coe_int_eq_divInt]
theorem coe_int_num_of_den_eq_one {q : ℚ} (hq : q.den = 1) : (q.num : ℚ) = q := by
  conv_rhs => rw [← @num_den q, hq]
  rw [coe_int_eq_divInt]
  

Proof state:
a b c q : ℚ
hq : q.den = 1
⊢ q.num /. 1 = q.num /. ↑1

Next tactic:
rfl
lemma eq_num_of_isInt {q : ℚ} (h : q.isInt) : q = q.num := by
  

Proof state:
a b c q : ℚ
h : Rat.isInt q = true
⊢ q = ↑q.num

Next tactic:
rw [Rat.isInt, Nat.beq_eq_true_eq] at h
lemma eq_num_of_isInt {q : ℚ} (h : q.isInt) : q = q.num := by
  rw [Rat.isInt, Nat.beq_eq_true_eq] at h
  

Proof state:
a b c q : ℚ
h : q.den = 1
⊢ q = ↑q.num

Next tactic:
exact (Rat.coe_int_num_of_den_eq_one h).symm
theorem coe_nat_eq_divInt (n : ℕ) : ↑n = n /. 1 := by
  

Proof state:
a b c : ℚ
n : ℕ
⊢ ↑n = ↑n /. 1

Next tactic:
rw [← Int.cast_ofNat, coe_int_eq_divInt]
@[simp, norm_cast]
theorem coe_nat_num (n : ℕ) : (n : ℚ).num = n := by
  

Proof state:
a b c : ℚ
n : ℕ
⊢ (↑n).num = ↑n

Next tactic:
rw [← Int.cast_ofNat, coe_int_num]
@[simp, norm_cast]
theorem coe_nat_den (n : ℕ) : (n : ℚ).den = 1 := by
  

Proof state:
a b c : ℚ
n : ℕ
⊢ (↑n).den = 1

Next tactic:
rw [← Int.cast_ofNat, coe_int_den]
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  

Proof state:
a b c : ℚ
n : ℤ
d : ℕ
⊢ mkRat n d = ↑n / ↑d

Next tactic:
simp only [mkRat, zero_mk]
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  

Proof state:
a b c : ℚ
n : ℤ
d : ℕ
⊢ (if h : d = 0 then 0 else normalize n d) = ↑n / ↑d

Next tactic:
by_cases h : d = 0
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  by_cases h : d = 0
  · 

Proof state:
case pos
a b c : ℚ
n : ℤ
d : ℕ
h : d = 0
⊢ (if h : d = 0 then 0 else normalize n d) = ↑n / ↑d

Next tactic:
simp [h]
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  by_cases h : d = 0
  · simp [h]
  · 

Proof state:
case neg
a b c : ℚ
n : ℤ
d : ℕ
h : ¬d = 0
⊢ (if h : d = 0 then 0 else normalize n d) = ↑n / ↑d

Next tactic:
simp [h, HDiv.hDiv, Rat.div, Div.div]
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  by_cases h : d = 0
  · simp [h]
  · simp [h, HDiv.hDiv, Rat.div, Div.div]
    

Proof state:
case neg
a b c : ℚ
n : ℤ
d : ℕ
h : ¬d = 0
⊢ normalize n d = ↑n * Rat.inv ↑d

Next tactic:
unfold Rat.inv
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  by_cases h : d = 0
  · simp [h]
  · simp [h, HDiv.hDiv, Rat.div, Div.div]
    unfold Rat.inv
    

Proof state:
case neg
a b c : ℚ
n : ℤ
d : ℕ
h : ¬d = 0
⊢ normalize n d =
    ↑n *
      if h : (↑d).num < 0 then mk' (-↑(↑d).den) (Int.natAbs (↑d).num)
      else if h : (↑d).num > 0 then mk' (↑(↑d).den) (Int.natAbs (↑d).num) else ↑d

Next tactic:
have h₁ : 0 < d := Nat.pos_iff_ne_zero.2 h
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  by_cases h : d = 0
  · simp [h]
  · simp [h, HDiv.hDiv, Rat.div, Div.div]
    unfold Rat.inv
    have h₁ : 0 < d := Nat.pos_iff_ne_zero.2 h
    

Proof state:
case neg
a b c : ℚ
n : ℤ
d : ℕ
h : ¬d = 0
h₁ : 0 < d
⊢ normalize n d =
    ↑n *
      if h : (↑d).num < 0 then mk' (-↑(↑d).den) (Int.natAbs (↑d).num)
      else if h : (↑d).num > 0 then mk' (↑(↑d).den) (Int.natAbs (↑d).num) else ↑d

Next tactic:
have h₂ : ¬ (d : ℤ) < 0 := of_decide_eq_false rfl
theorem mkRat_eq_div {n : ℤ} {d : ℕ} : mkRat n d = n / d := by
  simp only [mkRat, zero_mk]
  by_cases h : d = 0
  · simp [h]
  · simp [h, HDiv.hDiv, Rat.div, Div.div]
    unfold Rat.inv
    have h₁ : 0 < d := Nat.pos_iff_ne_zero.2 h
    have h₂ : ¬ (d : ℤ) < 0 := of_decide_eq_false rfl
    

Proof state:
case neg
a b c : ℚ
n : ℤ
d : ℕ
h : ¬d = 0
h₁ : 0 < d
h₂ : ¬↑d < 0
⊢ normalize n d =
    ↑n *
      if h : (↑d).num < 0 then mk' (-↑(↑d).den) (Int.natAbs (↑d).num)
      else if h : (↑d).num > 0 then mk' (↑(↑d).den) (Int.natAbs (↑d).num) else ↑d

Next tactic:
simp [h₁, h₂, ← Rat.normalize_eq_mk', Rat.normalize_eq_mkRat, ← mkRat_one,
      Rat.mkRat_mul_mkRat]
/-- The canonical map from `homologyC` to `homologyK`.
  This is an isomorphism, and it is used in obtaining the API for `homology f g w`
  in the bottom of this file. -/
abbrev homologyCToK : homologyC f g w ⟶ homologyK f g w :=
  cokernel.desc _ (kernel.lift _ (kernel.ι _ ≫ cokernel.π _) (by 

Proof state:
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
⊢ (kernel.ι g ≫ cokernel.π f) ≫ cokernel.desc f g w = 0

Next tactic:
simp
/-- The canonical map from `homologyC` to `homologyK`.
  This is an isomorphism, and it is used in obtaining the API for `homology f g w`
  in the bottom of this file. -/
abbrev homologyCToK : homologyC f g w ⟶ homologyK f g w :=
  cokernel.desc _ (kernel.lift _ (kernel.ι _ ≫ cokernel.π _) (by simp)) (by 

Proof state:
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
⊢ kernel.lift g f w ≫
      kernel.lift (cokernel.desc f g w) (kernel.ι g ≫ cokernel.π f)
        (_ : (kernel.ι g ≫ cokernel.π f) ≫ cokernel.desc f g w = 0) =
    0

Next tactic:
ext
/-- The canonical map from `homologyC` to `homologyK`.
  This is an isomorphism, and it is used in obtaining the API for `homology f g w`
  in the bottom of this file. -/
abbrev homologyCToK : homologyC f g w ⟶ homologyK f g w :=
  cokernel.desc _ (kernel.lift _ (kernel.ι _ ≫ cokernel.π _) (by simp)) (by ext; 

Proof state:
case h
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
⊢ (kernel.lift g f w ≫
        kernel.lift (cokernel.desc f g w) (kernel.ι g ≫ cokernel.π f)
          (_ : (kernel.ι g ≫ cokernel.π f) ≫ cokernel.desc f g w = 0)) ≫
      equalizer.ι (cokernel.desc f g w) 0 =
    0 ≫ equalizer.ι (cokernel.desc f g w) 0

Next tactic:
simp
instance : Mono (homologyCToK f g w) := by
  

Proof state:
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
⊢ Mono (homologyCToK f g w)

Next tactic:
apply Pseudoelement.mono_of_zero_of_map_zero
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  

Proof state:
case a
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
⊢ ∀ (a : Pseudoelement (homologyC f g w)), Pseudoelement.pseudoApply (homologyCToK f g w) a = 0 → a = 0

Next tactic:
intro a ha
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  

Proof state:
case a
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (homologyC f g w)
ha : Pseudoelement.pseudoApply (homologyCToK f g w) a = 0
⊢ a = 0

Next tactic:
obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  

Proof state:
case a.intro
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (kernel g)
ha : Pseudoelement.pseudoApply (homologyCToK f g w) (Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a) = 0
⊢ Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a = 0

Next tactic:
apply_fun kernel.ι (cokernel.desc f g w) at ha
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  apply_fun kernel.ι (cokernel.desc f g w) at ha
  

Proof state:
case a.intro
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (kernel g)
ha :
  Pseudoelement.pseudoApply (kernel.ι (cokernel.desc f g w))
      (Pseudoelement.pseudoApply (homologyCToK f g w) (Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a)) =
    Pseudoelement.pseudoApply (kernel.ι (cokernel.desc f g w)) 0
⊢ Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a = 0

Next tactic:
simp only [← Pseudoelement.comp_apply, cokernel.π_desc, kernel.lift_ι,
    Pseudoelement.apply_zero] at ha
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  apply_fun kernel.ι (cokernel.desc f g w) at ha
  simp only [← Pseudoelement.comp_apply, cokernel.π_desc, kernel.lift_ι,
    Pseudoelement.apply_zero] at ha
  

Proof state:
case a.intro
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (kernel g)
ha : Pseudoelement.pseudoApply (kernel.ι g ≫ cokernel.π f) a = 0
⊢ Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a = 0

Next tactic:
simp only [Pseudoelement.comp_apply] at ha
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  apply_fun kernel.ι (cokernel.desc f g w) at ha
  simp only [← Pseudoelement.comp_apply, cokernel.π_desc, kernel.lift_ι,
    Pseudoelement.apply_zero] at ha
  simp only [Pseudoelement.comp_apply] at ha
  

Proof state:
case a.intro
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (kernel g)
ha : Pseudoelement.pseudoApply (cokernel.π f) (Pseudoelement.pseudoApply (kernel.ι g) a) = 0
⊢ Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a = 0

Next tactic:
obtain ⟨b, hb⟩ : ∃ b, f b = _ := (Pseudoelement.pseudo_exact_of_exact (exact_cokernel f)).2 _ ha
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  apply_fun kernel.ι (cokernel.desc f g w) at ha
  simp only [← Pseudoelement.comp_apply, cokernel.π_desc, kernel.lift_ι,
    Pseudoelement.apply_zero] at ha
  simp only [Pseudoelement.comp_apply] at ha
  obtain ⟨b, hb⟩ : ∃ b, f b = _ := (Pseudoelement.pseudo_exact_of_exact (exact_cokernel f)).2 _ ha
  

Proof state:
case a.intro.intro
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (kernel g)
ha : Pseudoelement.pseudoApply (cokernel.π f) (Pseudoelement.pseudoApply (kernel.ι g) a) = 0
b : Pseudoelement X
hb : Pseudoelement.pseudoApply f b = Pseudoelement.pseudoApply (kernel.ι g) a
⊢ Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) a = 0

Next tactic:
rsuffices ⟨c, rfl⟩ : ∃ c, kernel.lift g f w c = a
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  apply_fun kernel.ι (cokernel.desc f g w) at ha
  simp only [← Pseudoelement.comp_apply, cokernel.π_desc, kernel.lift_ι,
    Pseudoelement.apply_zero] at ha
  simp only [Pseudoelement.comp_apply] at ha
  obtain ⟨b, hb⟩ : ∃ b, f b = _ := (Pseudoelement.pseudo_exact_of_exact (exact_cokernel f)).2 _ ha
  rsuffices ⟨c, rfl⟩ : ∃ c, kernel.lift g f w c = a
  · 

Proof state:
case a.intro.intro.intro
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
b c : Pseudoelement X
ha :
  Pseudoelement.pseudoApply (cokernel.π f)
      (Pseudoelement.pseudoApply (kernel.ι g) (Pseudoelement.pseudoApply (kernel.lift g f w) c)) =
    0
hb :
  Pseudoelement.pseudoApply f b =
    Pseudoelement.pseudoApply (kernel.ι g) (Pseudoelement.pseudoApply (kernel.lift g f w) c)
⊢ Pseudoelement.pseudoApply (cokernel.π (kernel.lift g f w)) (Pseudoelement.pseudoApply (kernel.lift g f w) c) = 0

Next tactic:
simp [← Pseudoelement.comp_apply]
instance : Mono (homologyCToK f g w) := by
  apply Pseudoelement.mono_of_zero_of_map_zero
  intro a ha
  obtain ⟨a, rfl⟩ := Pseudoelement.pseudo_surjective_of_epi (cokernel.π (kernel.lift g f w)) a
  apply_fun kernel.ι (cokernel.desc f g w) at ha
  simp only [← Pseudoelement.comp_apply, cokernel.π_desc, kernel.lift_ι,
    Pseudoelement.apply_zero] at ha
  simp only [Pseudoelement.comp_apply] at ha
  obtain ⟨b, hb⟩ : ∃ b, f b = _ := (Pseudoelement.pseudo_exact_of_exact (exact_cokernel f)).2 _ ha
  rsuffices ⟨c, rfl⟩ : ∃ c, kernel.lift g f w c = a
  · simp [← Pseudoelement.comp_apply]
  

Proof state:
A : Type u
inst✝¹ : Category.{v, u} A
inst✝ : Abelian A
X Y Z : A
f : X ⟶ Y
g : Y ⟶ Z
w : f ≫ g = 0
a : Pseudoelement (kernel g)
ha : Pseudoelement.pseudoApply (cokernel.π f) (Pseudoelement.pseudoApply (kernel.ι g) a) = 0
b : Pseudoelement X
hb : Pseudoelement.pseudoApply f b = Pseudoelement.pseudoApply (kernel.ι g) a
⊢ ∃ c, Pseudoelement.pseudoApply (kernel.lift g f w) c = a

Next tactic:
use b