l3lab/ntp-mathlib huggingface dataset:
/-- The group homomorphism from the colimit abelian group to the cone point of any other cocone. -/
def descMorphism (s : Cocone F) : colimit.{w} F ⟶ s.pt where
  toFun := descFun F s
  map_zero' := rfl
  -- Porting note : in `mathlib3`, nothing needs to be done after `induction`
  map_add' x y := Quot.induction_on₂ x y fun _ _ => by dsimp; 

Proof state:
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : ↑(colimit F)
x✝¹ x✝ : Prequotient F
⊢ descFun F s (Quot.mk Setoid.r x✝¹ + Quot.mk Setoid.r x✝) =
    descFun F s (Quot.mk Setoid.r x✝¹) + descFun F s (Quot.mk Setoid.r x✝)

Next tactic:
rw [← quot_add F]
/-- The group homomorphism from the colimit abelian group to the cone point of any other cocone. -/
def descMorphism (s : Cocone F) : colimit.{w} F ⟶ s.pt where
  toFun := descFun F s
  map_zero' := rfl
  -- Porting note : in `mathlib3`, nothing needs to be done after `induction`
  map_add' x y := Quot.induction_on₂ x y fun _ _ => by dsimp; rw [← quot_add F]; 

Proof state:
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : ↑(colimit F)
x✝¹ x✝ : Prequotient F
⊢ descFun F s (Quot.mk Setoid.r (add x✝¹ x✝)) = descFun F s (Quot.mk Setoid.r x✝¹) + descFun F s (Quot.mk Setoid.r x✝)

Next tactic:
rfl
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    

Proof state:
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x : Prequotient F
⊢ m (Quot.mk Setoid.r x) = ((fun s => descMorphism F s) s) (Quot.mk Setoid.r x)

Next tactic:
change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    

Proof state:
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x : Prequotient F
⊢ m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)

Next tactic:
induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    | neg x ih =>
      dsimp only [quot_neg]
      rw [map_neg, map_neg, ih]
    | add x y ihx ihy =>
      simp only [quot_add]
      erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    

Proof state:
case of
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
j : J
x : ↑(F.obj j)
⊢ m (Quot.mk Setoid.r (Prequotient.of j x)) = (descMorphism F s) (Quot.mk Setoid.r (Prequotient.of j x))

Next tactic:
| of j x => exact FunLike.congr_fun (w j) x
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => 

Proof state:
case of
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
j : J
x : ↑(F.obj j)
⊢ m (Quot.mk Setoid.r (Prequotient.of j x)) = (descMorphism F s) (Quot.mk Setoid.r (Prequotient.of j x))

Next tactic:
exact FunLike.congr_fun (w j) x
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    

Proof state:
case zero
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x : Quot Setoid.r
⊢ m (Quot.mk Setoid.r zero) = (descMorphism F s) (Quot.mk Setoid.r zero)

Next tactic:
| zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      

Proof state:
case zero
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x : Quot Setoid.r
⊢ m (Quot.mk Setoid.r zero) = (descMorphism F s) (Quot.mk Setoid.r zero)

Next tactic:
dsimp only [quot_zero]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      

Proof state:
case zero
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x : Quot Setoid.r
⊢ m 0 = (descMorphism F s) 0

Next tactic:
rw [map_zero, map_zero]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    

Proof state:
case neg
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x : Prequotient F
ih : m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)
⊢ m (Quot.mk Setoid.r (neg x)) = (descMorphism F s) (Quot.mk Setoid.r (neg x))

Next tactic:
| neg x ih =>
      dsimp only [quot_neg]
      rw [map_neg, map_neg, ih]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    | neg x ih =>
      

Proof state:
case neg
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x : Prequotient F
ih : m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)
⊢ m (Quot.mk Setoid.r (neg x)) = (descMorphism F s) (Quot.mk Setoid.r (neg x))

Next tactic:
dsimp only [quot_neg]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    | neg x ih =>
      dsimp only [quot_neg]
      

Proof state:
case neg
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x : Prequotient F
ih : m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)
⊢ m (-Quot.mk Setoid.r x) = (descMorphism F s) (-Quot.mk Setoid.r x)

Next tactic:
rw [map_neg, map_neg, ih]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    | neg x ih =>
      dsimp only [quot_neg]
      rw [map_neg, map_neg, ih]
    

Proof state:
case add
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x y : Prequotient F
ihx : m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)
ihy : m (Quot.mk Setoid.r y) = (descMorphism F s) (Quot.mk Setoid.r y)
⊢ m (Quot.mk Setoid.r (add x y)) = (descMorphism F s) (Quot.mk Setoid.r (add x y))

Next tactic:
| add x y ihx ihy =>
      simp only [quot_add]
      erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    | neg x ih =>
      dsimp only [quot_neg]
      rw [map_neg, map_neg, ih]
    | add x y ihx ihy =>
      

Proof state:
case add
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x y : Prequotient F
ihx : m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)
ihy : m (Quot.mk Setoid.r y) = (descMorphism F s) (Quot.mk Setoid.r y)
⊢ m (Quot.mk Setoid.r (add x y)) = (descMorphism F s) (Quot.mk Setoid.r (add x y))

Next tactic:
simp only [quot_add]
/-- Evidence that the proposed colimit is the colimit. -/
def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where
  desc s := descMorphism F s
  uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by
    change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
    induction x using Prequotient.recOn with
    | of j x => exact FunLike.congr_fun (w j) x
    | zero =>
      dsimp only [quot_zero]
      rw [map_zero, map_zero]
    | neg x ih =>
      dsimp only [quot_neg]
      rw [map_neg, map_neg, ih]
    | add x y ihx ihy =>
      simp only [quot_add]
      

Proof state:
case add
J : Type u
inst✝ : Category.{v, u} J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), (colimitCocone F).ι.app j ≫ m = s.ι.app j
x✝ : Quot Setoid.r
x y : Prequotient F
ihx : m (Quot.mk Setoid.r x) = (descMorphism F s) (Quot.mk Setoid.r x)
ihy : m (Quot.mk Setoid.r y) = (descMorphism F s) (Quot.mk Setoid.r y)
⊢ m (Quot.mk Setoid.r x + Quot.mk Setoid.r y) = (descMorphism F s) (Quot.mk Setoid.r x + Quot.mk Setoid.r y)

Next tactic:
erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
⊢ f ≫ mk' (AddMonoidHom.range f) = 0

Next tactic:
ext x
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        

Proof state:
case w
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ (f ≫ mk' (AddMonoidHom.range f)) x = 0 x

Next tactic:
apply Quotient.sound
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        

Proof state:
case w.a
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ f x ≈ 0

Next tactic:
apply leftRel_apply.mpr
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        

Proof state:
case w.a
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ -f x + 0 ∈ AddMonoidHom.range f

Next tactic:
fconstructor
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        

Proof state:
case w.a.w
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ ↑G
case w.a.h G H : AddCommGroupCat f : G ⟶ H x : ↑G ⊢ f ?w.a.w = -f x + 0

Next tactic:
exact -x
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        

Proof state:
case w.a.h
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ f (-x) = -f x + 0

Next tactic:
simp only [add_zero, AddMonoidHom.map_neg]
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
⊢ AddMonoidHom.range f ≤ AddMonoidHom.ker (cokernel.π f)

Next tactic:
rintro _ ⟨x, rfl⟩
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      rintro _ ⟨x, rfl⟩
      

Proof state:
case intro
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ f x ∈ AddMonoidHom.ker (cokernel.π f)

Next tactic:
exact cokernel.condition_apply f x
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      rintro _ ⟨x, rfl⟩
      exact cokernel.condition_apply f x
  hom_inv_id := by
    

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
⊢ cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0) ≫
      lift (AddMonoidHom.range f) (cokernel.π f)
        (_ : ∀ ⦃x : ↑H⦄, x ∈ AddMonoidHom.range f → x ∈ AddMonoidHom.ker (cokernel.π f)) =
    𝟙 (cokernel f)

Next tactic:
refine coequalizer.hom_ext ?_
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      rintro _ ⟨x, rfl⟩
      exact cokernel.condition_apply f x
  hom_inv_id := by
    refine coequalizer.hom_ext ?_
    

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
⊢ coequalizer.π f 0 ≫
      cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0) ≫
        lift (AddMonoidHom.range f) (cokernel.π f)
          (_ : ∀ ⦃x : ↑H⦄, x ∈ AddMonoidHom.range f → x ∈ AddMonoidHom.ker (cokernel.π f)) =
    coequalizer.π f 0 ≫ 𝟙 (cokernel f)

Next tactic:
simp only [coequalizer_as_cokernel, cokernel.π_desc_assoc, Category.comp_id]
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      rintro _ ⟨x, rfl⟩
      exact cokernel.condition_apply f x
  hom_inv_id := by
    refine coequalizer.hom_ext ?_
    simp only [coequalizer_as_cokernel, cokernel.π_desc_assoc, Category.comp_id]
    

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
⊢ mk' (AddMonoidHom.range f) ≫
      lift (AddMonoidHom.range f) (cokernel.π f)
        (_ : ∀ ⦃x : ↑H⦄, x ∈ AddMonoidHom.range f → x ∈ AddMonoidHom.ker (cokernel.π f)) =
    cokernel.π f

Next tactic:
rfl
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      rintro _ ⟨x, rfl⟩
      exact cokernel.condition_apply f x
  hom_inv_id := by
    refine coequalizer.hom_ext ?_
    simp only [coequalizer_as_cokernel, cokernel.π_desc_assoc, Category.comp_id]
    rfl
  inv_hom_id := by
    

Proof state:
G H : AddCommGroupCat
f : G ⟶ H
⊢ lift (AddMonoidHom.range f) (cokernel.π f)
        (_ : ∀ ⦃x : ↑H⦄, x ∈ AddMonoidHom.range f → x ∈ AddMonoidHom.ker (cokernel.π f)) ≫
      cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0) =
    𝟙 (of (↑H ⧸ AddMonoidHom.range f))

Next tactic:
ext x
/-- The categorical cokernel of a morphism in `AddCommGroupCat`
agrees with the usual group-theoretical quotient.
-/
noncomputable def cokernelIsoQuotient {G H : AddCommGroupCat.{u}} (f : G ⟶ H) :
    cokernel f ≅ AddCommGroupCat.of (H ⧸ AddMonoidHom.range f) where
  hom := cokernel.desc f (mk' _) <| by
        ext x
        apply Quotient.sound
        apply leftRel_apply.mpr
        fconstructor
        exact -x
        simp only [add_zero, AddMonoidHom.map_neg]
  inv :=
    QuotientAddGroup.lift _ (cokernel.π f) <| by
      rintro _ ⟨x, rfl⟩
      exact cokernel.condition_apply f x
  hom_inv_id := by
    refine coequalizer.hom_ext ?_
    simp only [coequalizer_as_cokernel, cokernel.π_desc_assoc, Category.comp_id]
    rfl
  inv_hom_id := by
    ext x
    

Proof state:
case w
G H : AddCommGroupCat
f : G ⟶ H
x : ↑(of (↑H ⧸ AddMonoidHom.range f))
⊢ (lift (AddMonoidHom.range f) (cokernel.π f)
          (_ : ∀ ⦃x : ↑H⦄, x ∈ AddMonoidHom.range f → x ∈ AddMonoidHom.ker (cokernel.π f)) ≫
        cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0))
      x =
    (𝟙 (of (↑H ⧸ AddMonoidHom.range f))) x

Next tactic:
exact QuotientAddGroup.induction_on x <| cokernel.π_desc_apply f _ _
/-- The `R`-algebra map, taking a polynomial with coefficients in `R` to a Laurent polynomial
with coefficients in `R`. -/
def Polynomial.toLaurentAlg [CommSemiring R] : R[X] →ₐ[R] R[T;T⁻¹] := by
  

Proof state:
R : Type u_1
inst✝ : CommSemiring R
⊢ R[X] →ₐ[R] R[T;T⁻¹]

Next tactic:
refine' AlgHom.comp _ (toFinsuppIsoAlg R).toAlgHom
/-- The `R`-algebra map, taking a polynomial with coefficients in `R` to a Laurent polynomial
with coefficients in `R`. -/
def Polynomial.toLaurentAlg [CommSemiring R] : R[X] →ₐ[R] R[T;T⁻¹] := by
  refine' AlgHom.comp _ (toFinsuppIsoAlg R).toAlgHom
  

Proof state:
R : Type u_1
inst✝ : CommSemiring R
⊢ R[ℕ] →ₐ[R] R[T;T⁻¹]

Next tactic:
exact mapDomainAlgHom R R Int.ofNatHom
@[simp] lemma C_apply (t : R) (n : ℤ) : C t n = if n = 0 then t else 0 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
t : R
n : ℤ
⊢ (C t) n = if n = 0 then t else 0

Next tactic:
rw [← single_eq_C, Finsupp.single_apply]
@[simp] lemma C_apply (t : R) (n : ℤ) : C t n = if n = 0 then t else 0 := by
  rw [← single_eq_C, Finsupp.single_apply]; 

Proof state:
R : Type u_1
inst✝ : Semiring R
t : R
n : ℤ
⊢ (if 0 = n then t else 0) = if n = 0 then t else 0

Next tactic:
aesop
theorem T_add (m n : ℤ) : (T (m + n) : R[T;T⁻¹]) = T m * T n := by
  -- Porting note: was `convert single_mul_single.symm`
  

Proof state:
R : Type u_1
inst✝ : Semiring R
m n : ℤ
⊢ T (m + n) = T m * T n

Next tactic:
simp [T, single_mul_single]
theorem T_sub (m n : ℤ) : (T (m - n) : R[T;T⁻¹]) = T m * T (-n) := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
m n : ℤ
⊢ T (m - n) = T m * T (-n)

Next tactic:
rw [← T_add, sub_eq_add_neg]
@[simp]
theorem T_pow (m : ℤ) (n : ℕ) : (T m ^ n : R[T;T⁻¹]) = T (n * m) := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
m : ℤ
n : ℕ
⊢ T m ^ n = T (↑n * m)

Next tactic:
rw [T, T, single_pow n, one_pow, nsmul_eq_mul]