l3lab/ntp-mathlib huggingface dataset:
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
⊢ (r ≫ a.hom ≫ Abelian.factorThruImage f) ≫ kernel.ι (cokernel.π f) = q ≫ kernel.ι g

Next tactic:
simp only [Category.assoc, Abelian.image.fac]
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          simp only [Category.assoc, Abelian.image.fac]
          

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
⊢ r ≫ a.hom ≫ f = q ≫ kernel.ι g

Next tactic:
exact comm
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          simp only [Category.assoc, Abelian.image.fac]
          exact comm)
      -- Let's give a name to the second pullback morphism.
      

Proof state:
case intro.intro.intro.intro.intro.intro.intro.mk.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
z : Z ⟶ pullback (kernel.ι (cokernel.π f)) (kernel.ι g)
left✝ : z ≫ pullback.fst = r ≫ a.hom ≫ Abelian.factorThruImage f
hz₂ : z ≫ pullback.snd = q
⊢ kernel.ι g ≫ cokernel.π f = 0

Next tactic:
let j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          simp only [Category.assoc, Abelian.image.fac]
          exact comm)
      -- Let's give a name to the second pullback morphism.
      let j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
      -- Since `q` is an epimorphism, in particular this means that `j` is an epimorphism.
      

Proof state:
case intro.intro.intro.intro.intro.intro.intro.mk.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
z : Z ⟶ pullback (kernel.ι (cokernel.π f)) (kernel.ι g)
left✝ : z ≫ pullback.fst = r ≫ a.hom ≫ Abelian.factorThruImage f
hz₂ : z ≫ pullback.snd = q
j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
⊢ kernel.ι g ≫ cokernel.π f = 0

Next tactic:
haveI pe : Epi j := epi_of_epi_fac hz₂
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          simp only [Category.assoc, Abelian.image.fac]
          exact comm)
      -- Let's give a name to the second pullback morphism.
      let j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
      -- Since `q` is an epimorphism, in particular this means that `j` is an epimorphism.
      haveI pe : Epi j := epi_of_epi_fac hz₂
      -- But it is also a monomorphism, because `kernel.ι (cokernel.π f)` is: A kernel is
      -- always a monomorphism and the pullback of a monomorphism is a monomorphism.
      -- But mono + epi = iso, so `j` is an isomorphism.
      

Proof state:
case intro.intro.intro.intro.intro.intro.intro.mk.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
z : Z ⟶ pullback (kernel.ι (cokernel.π f)) (kernel.ι g)
left✝ : z ≫ pullback.fst = r ≫ a.hom ≫ Abelian.factorThruImage f
hz₂ : z ≫ pullback.snd = q
j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
pe : Epi j
⊢ kernel.ι g ≫ cokernel.π f = 0

Next tactic:
haveI : IsIso j := isIso_of_mono_of_epi _
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          simp only [Category.assoc, Abelian.image.fac]
          exact comm)
      -- Let's give a name to the second pullback morphism.
      let j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
      -- Since `q` is an epimorphism, in particular this means that `j` is an epimorphism.
      haveI pe : Epi j := epi_of_epi_fac hz₂
      -- But it is also a monomorphism, because `kernel.ι (cokernel.π f)` is: A kernel is
      -- always a monomorphism and the pullback of a monomorphism is a monomorphism.
      -- But mono + epi = iso, so `j` is an isomorphism.
      haveI : IsIso j := isIso_of_mono_of_epi _
      -- But then `kernel.ι g` can be expressed using all of the maps of the pullback square, and we
      -- are done.
      

Proof state:
case intro.intro.intro.intro.intro.intro.intro.mk.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this✝ : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
z : Z ⟶ pullback (kernel.ι (cokernel.π f)) (kernel.ι g)
left✝ : z ≫ pullback.fst = r ≫ a.hom ≫ Abelian.factorThruImage f
hz₂ : z ≫ pullback.snd = q
j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
pe : Epi j
this : IsIso j
⊢ kernel.ι g ≫ cokernel.π f = 0

Next tactic:
rw [(Iso.eq_inv_comp (asIso j)).2 pullback.condition.symm]
/-- If two morphisms are exact on pseudoelements, they are exact. -/
theorem exact_of_pseudo_exact {P Q R : C} (f : P ⟶ Q) (g : Q ⟶ R) :
    ((∀ a, g (f a) = 0) ∧ ∀ b, g b = 0 → ∃ a, f a = b) → Exact f g :=
  fun ⟨h₁, h₂⟩ => (Abelian.exact_iff _ _).2
    ⟨zero_morphism_ext _ fun a => by rw [comp_apply, h₁ a], by
      -- If we apply `g` to the pseudoelement induced by its kernel, we get 0 (of course!).
      have : g (kernel.ι g) = 0 := apply_eq_zero_of_comp_eq_zero _ _ (kernel.condition _)
      -- By pseudo-exactness, we get a preimage.
      obtain ⟨a', ha⟩ := h₂ _ this
      obtain ⟨a, ha'⟩ := Quotient.exists_rep a'
      rw [← ha'] at ha
      obtain ⟨Z, r, q, _, eq, comm⟩ := Quotient.exact ha
      -- Consider the pullback of `kernel.ι (cokernel.π f)` and `kernel.ι g`.
      -- The commutative diagram given by the pseudo-equality `f a = b` induces
      -- a cone over this pullback, so we get a factorization `z`.
      obtain ⟨z, _, hz₂⟩ := @pullback.lift' _ _ _ _ _ _ (kernel.ι (cokernel.π f)) (kernel.ι g) _
        (r ≫ a.hom ≫ Abelian.factorThruImage f) q (by
          simp only [Category.assoc, Abelian.image.fac]
          exact comm)
      -- Let's give a name to the second pullback morphism.
      let j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
      -- Since `q` is an epimorphism, in particular this means that `j` is an epimorphism.
      haveI pe : Epi j := epi_of_epi_fac hz₂
      -- But it is also a monomorphism, because `kernel.ι (cokernel.π f)` is: A kernel is
      -- always a monomorphism and the pullback of a monomorphism is a monomorphism.
      -- But mono + epi = iso, so `j` is an isomorphism.
      haveI : IsIso j := isIso_of_mono_of_epi _
      -- But then `kernel.ι g` can be expressed using all of the maps of the pullback square, and we
      -- are done.
      rw [(Iso.eq_inv_comp (asIso j)).2 pullback.condition.symm]
      

Proof state:
case intro.intro.intro.intro.intro.intro.intro.mk.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q R : C
f : P ⟶ Q
g : Q ⟶ R
x✝ :
  (∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0) ∧
    ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
h₁ : ∀ (a : Pseudoelement P), pseudoApply g (pseudoApply f a) = 0
h₂ : ∀ (b : Pseudoelement Q), pseudoApply g b = 0 → ∃ a, pseudoApply f a = b
this✝ : pseudoApply g (Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))) = 0
a' : Pseudoelement P
a : Over P
ha : pseudoApply f ⟦a⟧ = Quot.mk (PseudoEqual Q) (Over.mk (kernel.ι g))
ha' : ⟦a⟧ = a'
Z : C
r : Z ⟶ ((fun g => app f g) a).left
q : Z ⟶ (Over.mk (kernel.ι g)).left
w✝ : Epi r
eq : Epi q
comm : r ≫ ((fun g => app f g) a).hom = q ≫ (Over.mk (kernel.ι g)).hom
z : Z ⟶ pullback (kernel.ι (cokernel.π f)) (kernel.ι g)
left✝ : z ≫ pullback.fst = r ≫ a.hom ≫ Abelian.factorThruImage f
hz₂ : z ≫ pullback.snd = q
j : pullback (kernel.ι (cokernel.π f)) (kernel.ι g) ⟶ kernel g := pullback.snd
pe : Epi j
this : IsIso j
⊢ ((asIso j).inv ≫ pullback.fst ≫ kernel.ι (cokernel.π f)) ≫ cokernel.π f = 0

Next tactic:
simp only [Category.assoc, kernel.condition, HasZeroMorphisms.comp_zero]
/-- If two pseudoelements `x` and `y` have the same image under some morphism `f`, then we can form
    their "difference" `z`. This pseudoelement has the properties that `f z = 0` and for all
    morphisms `g`, if `g y = 0` then `g z = g x`. -/
theorem sub_of_eq_image {P Q : C} (f : P ⟶ Q) (x y : P) :
    f x = f y → ∃ z, f z = 0 ∧ ∀ (R : C) (g : P ⟶ R), (g : P ⟶ R) y = 0 → g z = g x :=
  Quotient.inductionOn₂ x y fun a a' h =>
    match Quotient.exact h with
    | ⟨R, p, q, ep, _, comm⟩ =>
      let a'' : R ⟶ P := ↑(p ≫ a.hom) - ↑(q ≫ a'.hom)
      ⟨a'',
        ⟨show ⟦(a'' ≫ f : Over Q)⟧ = ⟦↑(0 : Q ⟶ Q)⟧ by
            

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q : C
f : P ⟶ Q
x y : Pseudoelement P
a a' : Over P
h : pseudoApply f ⟦a⟧ = pseudoApply f ⟦a'⟧
R : C
p : R ⟶ ((fun g => app f g) a).left
q : R ⟶ ((fun g => app f g) a').left
ep : Epi p
w✝ : Epi q
comm : p ≫ ((fun g => app f g) a).hom = q ≫ ((fun g => app f g) a').hom
a'' : R ⟶ P := p ≫ a.hom - q ≫ a'.hom
⊢ ⟦Over.mk (a'' ≫ f)⟧ = ⟦Over.mk 0⟧

Next tactic:
dsimp at comm
/-- If two pseudoelements `x` and `y` have the same image under some morphism `f`, then we can form
    their "difference" `z`. This pseudoelement has the properties that `f z = 0` and for all
    morphisms `g`, if `g y = 0` then `g z = g x`. -/
theorem sub_of_eq_image {P Q : C} (f : P ⟶ Q) (x y : P) :
    f x = f y → ∃ z, f z = 0 ∧ ∀ (R : C) (g : P ⟶ R), (g : P ⟶ R) y = 0 → g z = g x :=
  Quotient.inductionOn₂ x y fun a a' h =>
    match Quotient.exact h with
    | ⟨R, p, q, ep, _, comm⟩ =>
      let a'' : R ⟶ P := ↑(p ≫ a.hom) - ↑(q ≫ a'.hom)
      ⟨a'',
        ⟨show ⟦(a'' ≫ f : Over Q)⟧ = ⟦↑(0 : Q ⟶ Q)⟧ by
            dsimp at comm
            

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q : C
f : P ⟶ Q
x y : Pseudoelement P
a a' : Over P
h : pseudoApply f ⟦a⟧ = pseudoApply f ⟦a'⟧
R : C
p : R ⟶ ((fun g => app f g) a).left
q : R ⟶ ((fun g => app f g) a').left
ep : Epi p
w✝ : Epi q
comm : p ≫ a.hom ≫ f = q ≫ a'.hom ≫ f
a'' : R ⟶ P := p ≫ a.hom - q ≫ a'.hom
⊢ ⟦Over.mk (a'' ≫ f)⟧ = ⟦Over.mk 0⟧

Next tactic:
simp [sub_eq_zero.2 comm]
/-- If two pseudoelements `x` and `y` have the same image under some morphism `f`, then we can form
    their "difference" `z`. This pseudoelement has the properties that `f z = 0` and for all
    morphisms `g`, if `g y = 0` then `g z = g x`. -/
theorem sub_of_eq_image {P Q : C} (f : P ⟶ Q) (x y : P) :
    f x = f y → ∃ z, f z = 0 ∧ ∀ (R : C) (g : P ⟶ R), (g : P ⟶ R) y = 0 → g z = g x :=
  Quotient.inductionOn₂ x y fun a a' h =>
    match Quotient.exact h with
    | ⟨R, p, q, ep, _, comm⟩ =>
      let a'' : R ⟶ P := ↑(p ≫ a.hom) - ↑(q ≫ a'.hom)
      ⟨a'',
        ⟨show ⟦(a'' ≫ f : Over Q)⟧ = ⟦↑(0 : Q ⟶ Q)⟧ by
            dsimp at comm
            simp [sub_eq_zero.2 comm],
          fun Z g hh => by
          

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q : C
f : P ⟶ Q
x y : Pseudoelement P
a a' : Over P
h : pseudoApply f ⟦a⟧ = pseudoApply f ⟦a'⟧
R : C
p : R ⟶ ((fun g => app f g) a).left
q : R ⟶ ((fun g => app f g) a').left
ep : Epi p
w✝ : Epi q
comm : p ≫ ((fun g => app f g) a).hom = q ≫ ((fun g => app f g) a').hom
a'' : R ⟶ P := p ≫ a.hom - q ≫ a'.hom
Z : C
g : P ⟶ Z
hh : pseudoApply g ⟦a'⟧ = 0
⊢ pseudoApply g (Quot.mk (PseudoEqual P) (Over.mk a'')) = pseudoApply g ⟦a⟧

Next tactic:
obtain ⟨X, p', q', ep', _, comm'⟩ := Quotient.exact hh
/-- If two pseudoelements `x` and `y` have the same image under some morphism `f`, then we can form
    their "difference" `z`. This pseudoelement has the properties that `f z = 0` and for all
    morphisms `g`, if `g y = 0` then `g z = g x`. -/
theorem sub_of_eq_image {P Q : C} (f : P ⟶ Q) (x y : P) :
    f x = f y → ∃ z, f z = 0 ∧ ∀ (R : C) (g : P ⟶ R), (g : P ⟶ R) y = 0 → g z = g x :=
  Quotient.inductionOn₂ x y fun a a' h =>
    match Quotient.exact h with
    | ⟨R, p, q, ep, _, comm⟩ =>
      let a'' : R ⟶ P := ↑(p ≫ a.hom) - ↑(q ≫ a'.hom)
      ⟨a'',
        ⟨show ⟦(a'' ≫ f : Over Q)⟧ = ⟦↑(0 : Q ⟶ Q)⟧ by
            dsimp at comm
            simp [sub_eq_zero.2 comm],
          fun Z g hh => by
          obtain ⟨X, p', q', ep', _, comm'⟩ := Quotient.exact hh
          

Proof state:
case intro.intro.intro.intro.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q : C
f : P ⟶ Q
x y : Pseudoelement P
a a' : Over P
h : pseudoApply f ⟦a⟧ = pseudoApply f ⟦a'⟧
R : C
p : R ⟶ ((fun g => app f g) a).left
q : R ⟶ ((fun g => app f g) a').left
ep : Epi p
w✝¹ : Epi q
comm : p ≫ ((fun g => app f g) a).hom = q ≫ ((fun g => app f g) a').hom
a'' : R ⟶ P := p ≫ a.hom - q ≫ a'.hom
Z : C
g : P ⟶ Z
hh : pseudoApply g ⟦a'⟧ = 0
X : C
p' : X ⟶ ((fun g_1 => app g g_1) a').left
q' : X ⟶ (Over.mk 0).left
ep' : Epi p'
w✝ : Epi q'
comm' : p' ≫ ((fun g_1 => app g g_1) a').hom = q' ≫ (Over.mk 0).hom
⊢ pseudoApply g (Quot.mk (PseudoEqual P) (Over.mk a'')) = pseudoApply g ⟦a⟧

Next tactic:
have : a'.hom ≫ g = 0 := by
            apply (epi_iff_cancel_zero _).1 ep' _ (a'.hom ≫ g)
            simpa using comm'
/-- If two pseudoelements `x` and `y` have the same image under some morphism `f`, then we can form
    their "difference" `z`. This pseudoelement has the properties that `f z = 0` and for all
    morphisms `g`, if `g y = 0` then `g z = g x`. -/
theorem sub_of_eq_image {P Q : C} (f : P ⟶ Q) (x y : P) :
    f x = f y → ∃ z, f z = 0 ∧ ∀ (R : C) (g : P ⟶ R), (g : P ⟶ R) y = 0 → g z = g x :=
  Quotient.inductionOn₂ x y fun a a' h =>
    match Quotient.exact h with
    | ⟨R, p, q, ep, _, comm⟩ =>
      let a'' : R ⟶ P := ↑(p ≫ a.hom) - ↑(q ≫ a'.hom)
      ⟨a'',
        ⟨show ⟦(a'' ≫ f : Over Q)⟧ = ⟦↑(0 : Q ⟶ Q)⟧ by
            dsimp at comm
            simp [sub_eq_zero.2 comm],
          fun Z g hh => by
          obtain ⟨X, p', q', ep', _, comm'⟩ := Quotient.exact hh
          have : a'.hom ≫ g = 0 := by
            

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
P Q : C
f : P ⟶ Q
x y : Pseudoelement P
a a' : Over P
h : pseudoApply f ⟦a⟧ = pseudoApply f ⟦a'⟧
R : C
p : R ⟶ ((fun g => app f g) a).left
q : R ⟶ ((fun g => app f g) a').left
ep : Epi p
w✝¹ : Epi q
comm : p ≫ ((fun g => app f g) a).hom = q ≫ ((fun g => app f g) a').hom
a'' : R ⟶ P := p ≫ a.hom - q ≫ a'.hom
Z : C
g : P ⟶ Z
hh : pseudoApply g ⟦a'⟧ = 0
X : C
p' : X ⟶ ((fun g_1 => app g g_1) a').left
q' : X ⟶ (Over.mk 0).left
ep' : Epi p'
w✝ : Epi q'
comm' : p' ≫ ((fun g_1 => app g g_1) a').hom = q' ≫ (Over.mk 0).hom
⊢ a'.hom ≫ g = 0

Next tactic:
apply (epi_iff_cancel_zero _).1 ep' _ (a'.hom ≫ g)