l3lab/ntp-mathlib huggingface dataset:
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    

Proof state:
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
⊢ {
        toZeroHom :=
          { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
            map_zero' := (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) },
        map_add' :=
          (_ :
            ∀ (g g' : ↑(kernel f)),
              ZeroHom.toFun
                  { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                    map_zero' :=
                      (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                  (g + g') =
                ZeroHom.toFun
                    { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                      map_zero' :=
                        (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                    g +
                  ZeroHom.toFun
                    { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                      map_zero' :=
                        (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                    g') } ≫
      kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f)) (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0) =
    𝟙 (kernel f)

Next tactic:
refine equalizer.hom_ext ?_
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    

Proof state:
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
⊢ ({
          toZeroHom :=
            { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
              map_zero' :=
                (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) },
          map_add' :=
            (_ :
              ∀ (g g' : ↑(kernel f)),
                ZeroHom.toFun
                    { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                      map_zero' :=
                        (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                    (g + g') =
                  ZeroHom.toFun
                      { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                        map_zero' :=
                          (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                      g +
                    ZeroHom.toFun
                      { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                        map_zero' :=
                          (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                      g') } ≫
        kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f))
          (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0)) ≫
      equalizer.ι f 0 =
    𝟙 (kernel f) ≫ equalizer.ι f 0

Next tactic:
ext x
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    

Proof state:
case w
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
x : ↑(kernel f)
⊢ (({
            toZeroHom :=
              { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                map_zero' :=
                  (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) },
            map_add' :=
              (_ :
                ∀ (g g' : ↑(kernel f)),
                  ZeroHom.toFun
                      { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                        map_zero' :=
                          (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                      (g + g') =
                    ZeroHom.toFun
                        { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                          map_zero' :=
                            (_ :
                              (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                        g +
                      ZeroHom.toFun
                        { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                          map_zero' :=
                            (_ :
                              (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                        g') } ≫
          kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f))
            (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0)) ≫
        equalizer.ι f 0)
      x =
    (𝟙 (kernel f) ≫ equalizer.ι f 0) x

Next tactic:
dsimp
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    

Proof state:
case w
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
x : ↑(kernel f)
⊢ (kernel.ι f)
      ((kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f)) (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0))
        { val := (kernel.ι f) x, property := (_ : (kernel.ι f ≫ f) x = 0 x) }) =
    (kernel.ι f) x

Next tactic:
generalize_proofs _ h1 h2
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    

Proof state:
case w
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
x : ↑(kernel f)
h✝ : HasKernel f
h1 : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0
h2 : (kernel.ι f ≫ f) x = 0 x
⊢ (kernel.ι f)
      ((kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f)) h1) { val := (kernel.ι f) x, property := h2 }) =
    (kernel.ι f) x

Next tactic:
erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
    

Proof state:
case w
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
x : ↑(kernel f)
h✝ : HasKernel f
h1 : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0
h2 : (kernel.ι f ≫ f) x = 0 x
⊢ (AddSubgroup.subtype (AddMonoidHom.ker f)) { val := (kernel.ι f) x, property := h2 } = (kernel.ι f) x

Next tactic:
rfl
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
    rfl
  inv_hom_id := by
    

Proof state:
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
⊢ kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f)) (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0) ≫
      {
        toZeroHom :=
          { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
            map_zero' := (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) },
        map_add' :=
          (_ :
            ∀ (g g' : ↑(kernel f)),
              ZeroHom.toFun
                  { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                    map_zero' :=
                      (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                  (g + g') =
                ZeroHom.toFun
                    { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                      map_zero' :=
                        (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                    g +
                  ZeroHom.toFun
                    { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                      map_zero' :=
                        (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                    g') } =
    𝟙 (of ↥(AddMonoidHom.ker f))

Next tactic:
apply AddCommGroupCat.ext
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
    rfl
  inv_hom_id := by
    apply AddCommGroupCat.ext
    

Proof state:
case w
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
⊢ ∀ (x : ↑(of ↥(AddMonoidHom.ker f))),
    (kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f)) (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0) ≫
          {
            toZeroHom :=
              { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                map_zero' :=
                  (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) },
            map_add' :=
              (_ :
                ∀ (g g' : ↑(kernel f)),
                  ZeroHom.toFun
                      { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                        map_zero' :=
                          (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                      (g + g') =
                    ZeroHom.toFun
                        { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                          map_zero' :=
                            (_ :
                              (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                        g +
                      ZeroHom.toFun
                        { toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
                          map_zero' :=
                            (_ :
                              (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) }
                        g') })
        x =
      (𝟙 (of ↥(AddMonoidHom.ker f))) x

Next tactic:
simp only [AddMonoidHom.coe_mk, coe_id, coe_comp]
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
    rfl
  inv_hom_id := by
    apply AddCommGroupCat.ext
    simp only [AddMonoidHom.coe_mk, coe_id, coe_comp]
    

Proof state:
case w
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
⊢ ∀ (x : ↑(of ↥(AddMonoidHom.ker f))),
    (⇑{ toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
              map_zero' :=
                (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) } ∘
          ⇑(kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f))
              (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0)))
        x =
      id x

Next tactic:
rintro ⟨x, mem⟩
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
    rfl
  inv_hom_id := by
    apply AddCommGroupCat.ext
    simp only [AddMonoidHom.coe_mk, coe_id, coe_comp]
    rintro ⟨x, mem⟩
    

Proof state:
case w.mk
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
mem : x ∈ AddMonoidHom.ker f
⊢ (⇑{ toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
            map_zero' :=
              (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) } ∘
        ⇑(kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f))
            (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0)))
      { val := x, property := mem } =
    id { val := x, property := mem }

Next tactic:
refine Subtype.ext ?_
/-- The categorical kernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical kernel.
-/
def kernelIsoKer {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    kernel f ≅ AddCommGroupCat.of f.ker where
  hom :=
    { toFun := fun g => ⟨kernel.ι f g, FunLike.congr_fun (kernel.condition f) g⟩
      map_zero' := by
        refine Subtype.ext ?_
        simp [(AddSubgroup.coe_zero _).symm]
      map_add' := fun g g' => by
        refine Subtype.ext ?_
        change _ = _ + _
        dsimp
        simp }
  inv := kernel.lift f (AddSubgroup.subtype f.ker) <| by
    -- porting note : used to be `tidy`, but `aesop` can't do it
    refine FunLike.ext _ _ ?_
    rintro ⟨x, (hx : f _ = 0)⟩
    exact hx
  hom_inv_id := by
    -- Porting note: it would be nice to do the next two steps by a single `ext`,
    -- but this will require thinking carefully about the relative priorities of `@[ext]` lemmas.
    refine equalizer.hom_ext ?_
    ext x
    dsimp
    generalize_proofs _ h1 h2
    erw [FunLike.congr_fun (kernel.lift_ι f _ h1) ⟨_, h2⟩]
    rfl
  inv_hom_id := by
    apply AddCommGroupCat.ext
    simp only [AddMonoidHom.coe_mk, coe_id, coe_comp]
    rintro ⟨x, mem⟩
    refine Subtype.ext ?_
    

Proof state:
case w.mk
J : Type v
inst✝ : SmallCategory J
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
mem : x ∈ AddMonoidHom.ker f
⊢ ↑((⇑{ toFun := fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) },
              map_zero' :=
                (_ : (fun g => { val := (kernel.ι f) g, property := (_ : (kernel.ι f ≫ f) g = 0 g) }) 0 = 0) } ∘
          ⇑(kernel.lift f (AddSubgroup.subtype (AddMonoidHom.ker f))
              (_ : AddSubgroup.subtype (AddMonoidHom.ker f) ≫ f = 0)))
        { val := x, property := mem }) =
    ↑(id { val := x, property := mem })

Next tactic:
simp only [ZeroHom.coe_mk, Function.comp_apply, id_eq]