l3lab/ntp-mathlib huggingface dataset:
/-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivisionMonoid` if it admits an injective map
that preserves `1`, `*`, `⁻¹`, and `/` to a `DivisionMonoid`. See note [reducible non-instances] -/
@[to_additive (attr := reducible) subtractionMonoid
"A type endowed with `0`, `+`, unary `-`, and binary `-`
is a `SubtractionMonoid` if it admits an injective map that preserves `0`, `+`, unary `-`, and
binary `-` to a `SubtractionMonoid`. This version takes custom `nsmul` and `zsmul` as `[SMul ℕ M₁]`
and `[SMul ℤ M₁]` arguments."]
protected def divisionMonoid [DivisionMonoid M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
    (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n)
    (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivisionMonoid M₁ :=
  { hf.divInvMonoid f one mul inv div npow zpow, hf.involutiveInv f inv with
    mul_inv_rev := fun x y => hf <| by erw [inv, mul, mul_inv_rev, mul, inv, inv],
    inv_eq_of_mul := fun x y h => hf <| by
      

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝⁶ : Mul M₁
inst✝⁵ : One M₁
inst✝⁴ : Pow M₁ ℕ
inst✝³ : Inv M₁
inst✝² : Div M₁
inst✝¹ : Pow M₁ ℤ
inst✝ : DivisionMonoid M₂
f : M₁ → M₂
hf : Injective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
inv : ∀ (x : M₁), f x⁻¹ = (f x)⁻¹
div : ∀ (x y : M₁), f (x / y) = f x / f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
zpow : ∀ (x : M₁) (n : ℤ), f (x ^ n) = f x ^ n
src✝¹ : DivInvMonoid M₁ := Injective.divInvMonoid f hf one mul inv div npow zpow
src✝ : InvolutiveInv M₁ := Injective.involutiveInv f hf inv
x y : M₁
h : x * y = 1
⊢ f x⁻¹ = f y

Next tactic:
erw [inv, inv_eq_of_mul_eq_one_right (by erw [← mul, h, one])]
/-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivisionMonoid` if it admits an injective map
that preserves `1`, `*`, `⁻¹`, and `/` to a `DivisionMonoid`. See note [reducible non-instances] -/
@[to_additive (attr := reducible) subtractionMonoid
"A type endowed with `0`, `+`, unary `-`, and binary `-`
is a `SubtractionMonoid` if it admits an injective map that preserves `0`, `+`, unary `-`, and
binary `-` to a `SubtractionMonoid`. This version takes custom `nsmul` and `zsmul` as `[SMul ℕ M₁]`
and `[SMul ℤ M₁]` arguments."]
protected def divisionMonoid [DivisionMonoid M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
    (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n)
    (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivisionMonoid M₁ :=
  { hf.divInvMonoid f one mul inv div npow zpow, hf.involutiveInv f inv with
    mul_inv_rev := fun x y => hf <| by erw [inv, mul, mul_inv_rev, mul, inv, inv],
    inv_eq_of_mul := fun x y h => hf <| by
      erw [inv, inv_eq_of_mul_eq_one_right (by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝⁶ : Mul M₁
inst✝⁵ : One M₁
inst✝⁴ : Pow M₁ ℕ
inst✝³ : Inv M₁
inst✝² : Div M₁
inst✝¹ : Pow M₁ ℤ
inst✝ : DivisionMonoid M₂
f : M₁ → M₂
hf : Injective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
inv : ∀ (x : M₁), f x⁻¹ = (f x)⁻¹
div : ∀ (x y : M₁), f (x / y) = f x / f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
zpow : ∀ (x : M₁) (n : ℤ), f (x ^ n) = f x ^ n
src✝¹ : DivInvMonoid M₁ := Injective.divInvMonoid f hf one mul inv div npow zpow
src✝ : InvolutiveInv M₁ := Injective.involutiveInv f hf inv
x y : M₁
h : x * y = 1
⊢ f x * ?m.20553 = 1

Next tactic:
erw [← mul, h, one]
/-- A type endowed with `1`, `*` and `⁻¹` is a group, if it admits an injective map that preserves
`1`, `*` and `⁻¹` to a group. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an additive group, if it admits an
injective map that preserves `0` and `+` to an additive group."]
protected def group [Group M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
    (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n)
    (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : Group M₁ :=
  { hf.divInvMonoid f one mul inv div npow zpow with
    mul_left_inv := fun x => hf <| by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝⁶ : Mul M₁
inst✝⁵ : One M₁
inst✝⁴ : Pow M₁ ℕ
inst✝³ : Inv M₁
inst✝² : Div M₁
inst✝¹ : Pow M₁ ℤ
inst✝ : Group M₂
f : M₁ → M₂
hf : Injective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
inv : ∀ (x : M₁), f x⁻¹ = (f x)⁻¹
div : ∀ (x y : M₁), f (x / y) = f x / f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
zpow : ∀ (x : M₁) (n : ℤ), f (x ^ n) = f x ^ n
src✝ : DivInvMonoid M₁ := Injective.divInvMonoid f hf one mul inv div npow zpow
x : M₁
⊢ f (x⁻¹ * x) = f 1

Next tactic:
erw [mul, inv, mul_left_inv, one]
/-- A type endowed with `0`, `1` and `+` is an additive group with one, if it admits an injective
map that preserves `0`, `1` and `+` to an additive group with one.  See note
[reducible non-instances]. -/
@[reducible]
protected def addGroupWithOne {M₁} [Zero M₁] [One M₁] [Add M₁] [SMul ℕ M₁] [Neg M₁] [Sub M₁]
    [SMul ℤ M₁] [NatCast M₁] [IntCast M₁] [AddGroupWithOne M₂] (f : M₁ → M₂) (hf : Injective f)
    (zero : f 0 = 0) (one : f 1 = 1) (add : ∀ x y, f (x + y) = f x + f y) (neg : ∀ x, f (-x) = -f x)
    (sub : ∀ x y, f (x - y) = f x - f y) (nsmul : ∀ (x) (n : ℕ), f (n • x) = n • f x)
    (zsmul : ∀ (x) (n : ℤ), f (n • x) = n • f x) (nat_cast : ∀ n : ℕ, f n = n)
    (int_cast : ∀ n : ℤ, f n = n) : AddGroupWithOne M₁ :=
  { hf.addGroup f zero add neg sub nsmul zsmul,
    hf.addMonoidWithOne f zero one add nsmul nat_cast with
    intCast := Int.cast,
    intCast_ofNat := fun n => hf (by 

Proof state:
M₁✝ : Type u_1
M₂ : Type u_2
inst✝¹⁵ : Mul M₁✝
inst✝¹⁴ : One M₁✝
inst✝¹³ : Pow M₁✝ ℕ
inst✝¹² : Inv M₁✝
inst✝¹¹ : Div M₁✝
inst✝¹⁰ : Pow M₁✝ ℤ
M₁ : Type ?u.24257
inst✝⁹ : Zero M₁
inst✝⁸ : One M₁
inst✝⁷ : Add M₁
inst✝⁶ : SMul ℕ M₁
inst✝⁵ : Neg M₁
inst✝⁴ : Sub M₁
inst✝³ : SMul ℤ M₁
inst✝² : NatCast M₁
inst✝¹ : IntCast M₁
inst✝ : AddGroupWithOne M₂
f : M₁ → M₂
hf : Injective f
zero : f 0 = 0
one : f 1 = 1
add : ∀ (x y : M₁), f (x + y) = f x + f y
neg : ∀ (x : M₁), f (-x) = -f x
sub : ∀ (x y : M₁), f (x - y) = f x - f y
nsmul : ∀ (x : M₁) (n : ℕ), f (n • x) = n • f x
zsmul : ∀ (x : M₁) (n : ℤ), f (n • x) = n • f x
nat_cast : ∀ (n : ℕ), f ↑n = ↑n
int_cast : ∀ (n : ℤ), f ↑n = ↑n
src✝¹ : AddGroup M₁ := Injective.addGroup f hf zero add neg sub nsmul zsmul
src✝ : AddMonoidWithOne M₁ := Injective.addMonoidWithOne f hf zero one add nsmul nat_cast
n : ℕ
⊢ f (IntCast.intCast ↑n) = f ↑n

Next tactic:
rw [nat_cast, ← Int.cast, int_cast, Int.cast_ofNat]
/-- A type endowed with `0`, `1` and `+` is an additive group with one, if it admits an injective
map that preserves `0`, `1` and `+` to an additive group with one.  See note
[reducible non-instances]. -/
@[reducible]
protected def addGroupWithOne {M₁} [Zero M₁] [One M₁] [Add M₁] [SMul ℕ M₁] [Neg M₁] [Sub M₁]
    [SMul ℤ M₁] [NatCast M₁] [IntCast M₁] [AddGroupWithOne M₂] (f : M₁ → M₂) (hf : Injective f)
    (zero : f 0 = 0) (one : f 1 = 1) (add : ∀ x y, f (x + y) = f x + f y) (neg : ∀ x, f (-x) = -f x)
    (sub : ∀ x y, f (x - y) = f x - f y) (nsmul : ∀ (x) (n : ℕ), f (n • x) = n • f x)
    (zsmul : ∀ (x) (n : ℤ), f (n • x) = n • f x) (nat_cast : ∀ n : ℕ, f n = n)
    (int_cast : ∀ n : ℤ, f n = n) : AddGroupWithOne M₁ :=
  { hf.addGroup f zero add neg sub nsmul zsmul,
    hf.addMonoidWithOne f zero one add nsmul nat_cast with
    intCast := Int.cast,
    intCast_ofNat := fun n => hf (by rw [nat_cast, ← Int.cast, int_cast, Int.cast_ofNat]),
    intCast_negSucc := fun n => hf (by 

Proof state:
M₁✝ : Type u_1
M₂ : Type u_2
inst✝¹⁵ : Mul M₁✝
inst✝¹⁴ : One M₁✝
inst✝¹³ : Pow M₁✝ ℕ
inst✝¹² : Inv M₁✝
inst✝¹¹ : Div M₁✝
inst✝¹⁰ : Pow M₁✝ ℤ
M₁ : Type ?u.24257
inst✝⁹ : Zero M₁
inst✝⁸ : One M₁
inst✝⁷ : Add M₁
inst✝⁶ : SMul ℕ M₁
inst✝⁵ : Neg M₁
inst✝⁴ : Sub M₁
inst✝³ : SMul ℤ M₁
inst✝² : NatCast M₁
inst✝¹ : IntCast M₁
inst✝ : AddGroupWithOne M₂
f : M₁ → M₂
hf : Injective f
zero : f 0 = 0
one : f 1 = 1
add : ∀ (x y : M₁), f (x + y) = f x + f y
neg : ∀ (x : M₁), f (-x) = -f x
sub : ∀ (x y : M₁), f (x - y) = f x - f y
nsmul : ∀ (x : M₁) (n : ℕ), f (n • x) = n • f x
zsmul : ∀ (x : M₁) (n : ℤ), f (n • x) = n • f x
nat_cast : ∀ (n : ℕ), f ↑n = ↑n
int_cast : ∀ (n : ℤ), f ↑n = ↑n
src✝¹ : AddGroup M₁ := Injective.addGroup f hf zero add neg sub nsmul zsmul
src✝ : AddMonoidWithOne M₁ := Injective.addMonoidWithOne f hf zero one add nsmul nat_cast
n : ℕ
⊢ f (IntCast.intCast (Int.negSucc n)) = f (-↑(n + 1))

Next tactic:
erw [int_cast, neg, nat_cast, Int.cast_negSucc]
/-- A type endowed with `*` is a semigroup, if it admits a surjective map that preserves `*` from a
semigroup. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `+` is an additive semigroup, if it admits a
surjective map that preserves `+` from an additive semigroup."]
protected def semigroup [Semigroup M₁] (f : M₁ → M₂) (hf : Surjective f)
    (mul : ∀ x y, f (x * y) = f x * f y) : Semigroup M₂ :=
  { ‹Mul M₂› with mul_assoc := hf.forall₃.2 fun x y z => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝¹ : Mul M₂
inst✝ : Semigroup M₁
f : M₁ → M₂
hf : Surjective f
mul : ∀ (x y : M₁), f (x * y) = f x * f y
src✝ : Mul M₂ := inst✝¹
x y z : M₁
⊢ f x * f y * f z = f x * (f y * f z)

Next tactic:
simp only [← mul, mul_assoc]
/-- A type endowed with `*` is a commutative semigroup, if it admits a surjective map that preserves
`*` from a commutative semigroup. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `+` is an additive commutative semigroup, if it admits
a surjective map that preserves `+` from an additive commutative semigroup."]
protected def commSemigroup [CommSemigroup M₁] (f : M₁ → M₂) (hf : Surjective f)
    (mul : ∀ x y, f (x * y) = f x * f y) : CommSemigroup M₂ :=
  { hf.semigroup f mul with
    mul_comm := hf.forall₂.2 fun x y => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝¹ : Mul M₂
inst✝ : CommSemigroup M₁
f : M₁ → M₂
hf : Surjective f
mul : ∀ (x y : M₁), f (x * y) = f x * f y
src✝ : Semigroup M₂ := Surjective.semigroup f hf mul
x y : M₁
⊢ f x * f y = f y * f x

Next tactic:
erw [← mul, ← mul, mul_comm]
/-- A type endowed with `1` and `*` is a `MulOneClass`, if it admits a surjective map that preserves
`1` and `*` from a `MulOneClass`. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an `AddZeroClass`, if it admits a
surjective map that preserves `0` and `+` to an `AddZeroClass`."]
protected def mulOneClass [MulOneClass M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₂ :=
  { ‹One M₂›, ‹Mul M₂› with
    one_mul := hf.forall.2 fun x => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝² : Mul M₂
inst✝¹ : One M₂
inst✝ : MulOneClass M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
src✝¹ : One M₂ := inst✝¹
src✝ : Mul M₂ := inst✝²
x : M₁
⊢ 1 * f x = f x

Next tactic:
erw [← one, ← mul, one_mul]
/-- A type endowed with `1` and `*` is a `MulOneClass`, if it admits a surjective map that preserves
`1` and `*` from a `MulOneClass`. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an `AddZeroClass`, if it admits a
surjective map that preserves `0` and `+` to an `AddZeroClass`."]
protected def mulOneClass [MulOneClass M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₂ :=
  { ‹One M₂›, ‹Mul M₂› with
    one_mul := hf.forall.2 fun x => by erw [← one, ← mul, one_mul],
    mul_one := hf.forall.2 fun x => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝² : Mul M₂
inst✝¹ : One M₂
inst✝ : MulOneClass M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
src✝¹ : One M₂ := inst✝¹
src✝ : Mul M₂ := inst✝²
x : M₁
⊢ f x * 1 = f x

Next tactic:
erw [← one, ← mul, mul_one]
/-- A type endowed with `1` and `*` is a monoid, if it admits a surjective map that preserves `1`
and `*` to a monoid. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an additive monoid, if it admits a
surjective map that preserves `0` and `+` to an additive monoid. This version takes a custom `nsmul`
as a `[SMul ℕ M₂]` argument."]
protected def monoid [Monoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₂ :=
  { hf.semigroup f mul, hf.mulOneClass f one mul with
    npow := fun n x => x ^ n,
    npow_zero := hf.forall.2 fun x => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝³ : Mul M₂
inst✝² : One M₂
inst✝¹ : Pow M₂ ℕ
inst✝ : Monoid M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
src✝¹ : Semigroup M₂ := Surjective.semigroup f hf mul
src✝ : MulOneClass M₂ := Surjective.mulOneClass f hf one mul
x : M₁
⊢ (fun n x => x ^ n) 0 (f x) = 1

Next tactic:
dsimp only
/-- A type endowed with `1` and `*` is a monoid, if it admits a surjective map that preserves `1`
and `*` to a monoid. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an additive monoid, if it admits a
surjective map that preserves `0` and `+` to an additive monoid. This version takes a custom `nsmul`
as a `[SMul ℕ M₂]` argument."]
protected def monoid [Monoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₂ :=
  { hf.semigroup f mul, hf.mulOneClass f one mul with
    npow := fun n x => x ^ n,
    npow_zero := hf.forall.2 fun x => by dsimp only; 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝³ : Mul M₂
inst✝² : One M₂
inst✝¹ : Pow M₂ ℕ
inst✝ : Monoid M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
src✝¹ : Semigroup M₂ := Surjective.semigroup f hf mul
src✝ : MulOneClass M₂ := Surjective.mulOneClass f hf one mul
x : M₁
⊢ f x ^ 0 = 1

Next tactic:
erw [← npow, pow_zero, ← one]
/-- A type endowed with `1` and `*` is a monoid, if it admits a surjective map that preserves `1`
and `*` to a monoid. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an additive monoid, if it admits a
surjective map that preserves `0` and `+` to an additive monoid. This version takes a custom `nsmul`
as a `[SMul ℕ M₂]` argument."]
protected def monoid [Monoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₂ :=
  { hf.semigroup f mul, hf.mulOneClass f one mul with
    npow := fun n x => x ^ n,
    npow_zero := hf.forall.2 fun x => by dsimp only; erw [← npow, pow_zero, ← one],
    npow_succ := fun n => hf.forall.2 fun x => by
      

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝³ : Mul M₂
inst✝² : One M₂
inst✝¹ : Pow M₂ ℕ
inst✝ : Monoid M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
src✝¹ : Semigroup M₂ := Surjective.semigroup f hf mul
src✝ : MulOneClass M₂ := Surjective.mulOneClass f hf one mul
n : ℕ
x : M₁
⊢ (fun n x => x ^ n) (n + 1) (f x) = f x * (fun n x => x ^ n) n (f x)

Next tactic:
dsimp only
/-- A type endowed with `1` and `*` is a monoid, if it admits a surjective map that preserves `1`
and `*` to a monoid. See note [reducible non-instances]. -/
@[to_additive (attr := reducible)
"A type endowed with `0` and `+` is an additive monoid, if it admits a
surjective map that preserves `0` and `+` to an additive monoid. This version takes a custom `nsmul`
as a `[SMul ℕ M₂]` argument."]
protected def monoid [Monoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₂ :=
  { hf.semigroup f mul, hf.mulOneClass f one mul with
    npow := fun n x => x ^ n,
    npow_zero := hf.forall.2 fun x => by dsimp only; erw [← npow, pow_zero, ← one],
    npow_succ := fun n => hf.forall.2 fun x => by
      dsimp only
      

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝³ : Mul M₂
inst✝² : One M₂
inst✝¹ : Pow M₂ ℕ
inst✝ : Monoid M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
src✝¹ : Semigroup M₂ := Surjective.semigroup f hf mul
src✝ : MulOneClass M₂ := Surjective.mulOneClass f hf one mul
n : ℕ
x : M₁
⊢ f x ^ (n + 1) = f x * f x ^ n

Next tactic:
erw [← npow, pow_succ, ← npow, ← mul]
/-- A type endowed with `0`, `1` and `+` is an additive monoid with one, if it admits a surjective
map that preserves `0`, `1` and `*` from an additive monoid with one. See note
[reducible non-instances]. -/
@[reducible]
protected def addMonoidWithOne {M₂} [Zero M₂] [One M₂] [Add M₂] [SMul ℕ M₂] [NatCast M₂]
    [AddMonoidWithOne M₁] (f : M₁ → M₂) (hf : Surjective f) (zero : f 0 = 0) (one : f 1 = 1)
    (add : ∀ x y, f (x + y) = f x + f y) (nsmul : ∀ (x) (n : ℕ), f (n • x) = n • f x)
    (nat_cast : ∀ n : ℕ, f n = n) : AddMonoidWithOne M₂ :=
  { hf.addMonoid f zero add nsmul with
    natCast := Nat.cast,
    natCast_zero := by 

Proof state:
M₁ : Type u_1
M₂✝ : Type u_2
inst✝⁸ : Mul M₂✝
inst✝⁷ : One M₂✝
inst✝⁶ : Pow M₂✝ ℕ
M₂ : Type ?u.33275
inst✝⁵ : Zero M₂
inst✝⁴ : One M₂
inst✝³ : Add M₂
inst✝² : SMul ℕ M₂
inst✝¹ : NatCast M₂
inst✝ : AddMonoidWithOne M₁
f : M₁ → M₂
hf : Surjective f
zero : f 0 = 0
one : f 1 = 1
add : ∀ (x y : M₁), f (x + y) = f x + f y
nsmul : ∀ (x : M₁) (n : ℕ), f (n • x) = n • f x
nat_cast : ∀ (n : ℕ), f ↑n = ↑n
src✝ : AddMonoid M₂ := Surjective.addMonoid f hf zero add nsmul
⊢ NatCast.natCast 0 = 0

Next tactic:
rw [← Nat.cast, ← nat_cast, Nat.cast_zero, zero]
/-- A type endowed with `0`, `1` and `+` is an additive monoid with one, if it admits a surjective
map that preserves `0`, `1` and `*` from an additive monoid with one. See note
[reducible non-instances]. -/
@[reducible]
protected def addMonoidWithOne {M₂} [Zero M₂] [One M₂] [Add M₂] [SMul ℕ M₂] [NatCast M₂]
    [AddMonoidWithOne M₁] (f : M₁ → M₂) (hf : Surjective f) (zero : f 0 = 0) (one : f 1 = 1)
    (add : ∀ x y, f (x + y) = f x + f y) (nsmul : ∀ (x) (n : ℕ), f (n • x) = n • f x)
    (nat_cast : ∀ n : ℕ, f n = n) : AddMonoidWithOne M₂ :=
  { hf.addMonoid f zero add nsmul with
    natCast := Nat.cast,
    natCast_zero := by rw [← Nat.cast, ← nat_cast, Nat.cast_zero, zero]
    natCast_succ := fun n => by 

Proof state:
M₁ : Type u_1
M₂✝ : Type u_2
inst✝⁸ : Mul M₂✝
inst✝⁷ : One M₂✝
inst✝⁶ : Pow M₂✝ ℕ
M₂ : Type ?u.33275
inst✝⁵ : Zero M₂
inst✝⁴ : One M₂
inst✝³ : Add M₂
inst✝² : SMul ℕ M₂
inst✝¹ : NatCast M₂
inst✝ : AddMonoidWithOne M₁
f : M₁ → M₂
hf : Surjective f
zero : f 0 = 0
one : f 1 = 1
add : ∀ (x y : M₁), f (x + y) = f x + f y
nsmul : ∀ (x : M₁) (n : ℕ), f (n • x) = n • f x
nat_cast : ∀ (n : ℕ), f ↑n = ↑n
src✝ : AddMonoid M₂ := Surjective.addMonoid f hf zero add nsmul
n : ℕ
⊢ NatCast.natCast (n + 1) = NatCast.natCast n + 1

Next tactic:
rw [← Nat.cast, ← nat_cast, Nat.cast_succ, add, one, nat_cast]
/-- A type has an involutive inversion if it admits a surjective map that preserves `⁻¹` to a type
which has an involutive inversion. See note [reducible non-instances] -/
@[to_additive (attr := reducible)
"A type has an involutive negation if it admits a surjective map that
preserves `-` to a type which has an involutive negation."]
protected def involutiveInv {M₂ : Type*} [Inv M₂] [InvolutiveInv M₁] (f : M₁ → M₂)
    (hf : Surjective f) (inv : ∀ x, f x⁻¹ = (f x)⁻¹) : InvolutiveInv M₂ where
  inv := Inv.inv
  inv_inv := hf.forall.2 fun x => by 

Proof state:
M₁ : Type u_1
M₂✝ : Type u_2
inst✝⁴ : Mul M₂✝
inst✝³ : One M₂✝
inst✝² : Pow M₂✝ ℕ
M₂ : Type u_3
inst✝¹ : Inv M₂
inst✝ : InvolutiveInv M₁
f : M₁ → M₂
hf : Surjective f
inv : ∀ (x : M₁), f x⁻¹ = (f x)⁻¹
x : M₁
⊢ (f x)⁻¹⁻¹ = f x

Next tactic:
erw [← inv, ← inv, inv_inv]
/-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivInvMonoid` if it admits a surjective map
that preserves `1`, `*`, `⁻¹`, and `/` to a `DivInvMonoid`. See note [reducible non-instances]. -/
@[to_additive (attr := reducible) subNegMonoid
"A type endowed with `0`, `+`, unary `-`, and binary `-` is a
`SubNegMonoid` if it admits a surjective map that preserves `0`, `+`, unary `-`, and binary `-` to
a `SubNegMonoid`."]
protected def divInvMonoid [DivInvMonoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
    (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n)
    (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivInvMonoid M₂ :=
  { hf.monoid f one mul npow, ‹Div M₂›, ‹Inv M₂› with
    zpow := fun n x => x ^ n,
    zpow_zero' := hf.forall.2 fun x => by dsimp only; erw [← zpow, zpow_zero, ← one],
    zpow_succ' := fun n => hf.forall.2 fun x => by
      dsimp only
      erw [← zpow, ← zpow, zpow_ofNat, zpow_ofNat, pow_succ, ← mul],
    zpow_neg' := fun n => hf.forall.2 fun x => by
      dsimp only
      erw [← zpow, ← zpow, zpow_negSucc, zpow_ofNat, inv],
    div_eq_mul_inv := hf.forall₂.2 fun x y => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝⁶ : Mul M₂
inst✝⁵ : One M₂
inst✝⁴ : Pow M₂ ℕ
inst✝³ : Inv M₂
inst✝² : Div M₂
inst✝¹ : Pow M₂ ℤ
inst✝ : DivInvMonoid M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
inv : ∀ (x : M₁), f x⁻¹ = (f x)⁻¹
div : ∀ (x y : M₁), f (x / y) = f x / f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
zpow : ∀ (x : M₁) (n : ℤ), f (x ^ n) = f x ^ n
src✝² : Monoid M₂ := Surjective.monoid f hf one mul npow
src✝¹ : Div M₂ := inst✝²
src✝ : Inv M₂ := inst✝³
x y : M₁
⊢ f x / f y = f x * (f y)⁻¹

Next tactic:
erw [← inv, ← mul, ← div, div_eq_mul_inv]
/-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivInvMonoid` if it admits a surjective map
that preserves `1`, `*`, `⁻¹`, and `/` to a `DivInvMonoid`. See note [reducible non-instances]. -/
@[to_additive (attr := reducible) subNegMonoid
"A type endowed with `0`, `+`, unary `-`, and binary `-` is a
`SubNegMonoid` if it admits a surjective map that preserves `0`, `+`, unary `-`, and binary `-` to
a `SubNegMonoid`."]
protected def divInvMonoid [DivInvMonoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1)
    (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
    (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n)
    (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivInvMonoid M₂ :=
  { hf.monoid f one mul npow, ‹Div M₂›, ‹Inv M₂› with
    zpow := fun n x => x ^ n,
    zpow_zero' := hf.forall.2 fun x => by 

Proof state:
M₁ : Type u_1
M₂ : Type u_2
inst✝⁶ : Mul M₂
inst✝⁵ : One M₂
inst✝⁴ : Pow M₂ ℕ
inst✝³ : Inv M₂
inst✝² : Div M₂
inst✝¹ : Pow M₂ ℤ
inst✝ : DivInvMonoid M₁
f : M₁ → M₂
hf : Surjective f
one : f 1 = 1
mul : ∀ (x y : M₁), f (x * y) = f x * f y
inv : ∀ (x : M₁), f x⁻¹ = (f x)⁻¹
div : ∀ (x y : M₁), f (x / y) = f x / f y
npow : ∀ (x : M₁) (n : ℕ), f (x ^ n) = f x ^ n
zpow : ∀ (x : M₁) (n : ℤ), f (x ^ n) = f x ^ n
src✝² : Monoid M₂ := Surjective.monoid f hf one mul npow
src✝¹ : Div M₂ := inst✝²
src✝ : Inv M₂ := inst✝³
x : M₁
⊢ (fun n x => x ^ n) 0 (f x) = 1

Next tactic:
dsimp only