l3lab/ntp-mathlib huggingface dataset:
@[to_additive]
lemma eq_bot_iff_card : S = ⊥ ↔ card S = 1 :=
  ⟨by 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝¹ : Monoid M
a : M
S : Submonoid M
inst✝ : Fintype ↥S
⊢ S = ⊥ → card ↥S = 1

Next tactic:
rintro rfl
@[to_additive]
lemma eq_bot_iff_card : S = ⊥ ↔ card S = 1 :=
  ⟨by rintro rfl;  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝¹ : Monoid M
a : M
inst✝ : Fintype ↥⊥
⊢ card ↥⊥ = 1

Next tactic:
exact card_bot
@[to_additive]
theorem _root_.FreeMonoid.mrange_lift {α} (f : α → M) :
    mrange (FreeMonoid.lift f) = closure (Set.range f) := by
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
α : Type u_4
f : α → M
⊢ mrange (FreeMonoid.lift f) = closure (Set.range f)

Next tactic:
rw [mrange_eq_map, ← FreeMonoid.closure_range_of, map_mclosure, ← Set.range_comp,
    FreeMonoid.lift_comp_of]
@[to_additive]
theorem closure_eq_mrange (s : Set M) : closure s = mrange (FreeMonoid.lift ((↑) : s → M)) := by
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
⊢ closure s = mrange (FreeMonoid.lift Subtype.val)

Next tactic:
rw [FreeMonoid.mrange_lift, Subtype.range_coe]
@[to_additive]
theorem closure_eq_image_prod (s : Set M) :
    (closure s : Set M) = List.prod '' { l : List M | ∀ x ∈ l, x ∈ s } := by
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
⊢ ↑(closure s) = List.prod '' {l | ∀ x ∈ l, x ∈ s}

Next tactic:
rw [closure_eq_mrange, coe_mrange, ← Set.range_list_map_coe, ← Set.range_comp]
@[to_additive]
theorem closure_eq_image_prod (s : Set M) :
    (closure s : Set M) = List.prod '' { l : List M | ∀ x ∈ l, x ∈ s } := by
  rw [closure_eq_mrange, coe_mrange, ← Set.range_list_map_coe, ← Set.range_comp]
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
⊢ Set.range ⇑(FreeMonoid.lift Subtype.val) = Set.range (List.prod ∘ List.map Subtype.val)

Next tactic:
exact congrArg _ (funext <| FreeMonoid.lift_apply _)
@[to_additive]
theorem exists_list_of_mem_closure {s : Set M} {x : M} (hx : x ∈ closure s) :
    ∃ (l : List M) (_ : ∀ y ∈ l, y ∈ s), l.prod = x := by
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
x : M
hx : x ∈ closure s
⊢ ∃ l, ∃ (_ : ∀ y ∈ l, y ∈ s), List.prod l = x

Next tactic:
rwa [← SetLike.mem_coe, closure_eq_image_prod, Set.mem_image_iff_bex] at hx
@[to_additive]
theorem exists_multiset_of_mem_closure {M : Type*} [CommMonoid M] {s : Set M} {x : M}
    (hx : x ∈ closure s) : ∃ (l : Multiset M) (_ : ∀ y ∈ l, y ∈ s), l.prod = x := by
  

Proof state:
M✝ : Type u_1
A : Type u_2
B : Type u_3
inst✝¹ : Monoid M✝
a : M✝
M : Type u_4
inst✝ : CommMonoid M
s : Set M
x : M
hx : x ∈ closure s
⊢ ∃ l, ∃ (_ : ∀ y ∈ l, y ∈ s), Multiset.prod l = x

Next tactic:
obtain ⟨l, h1, h2⟩ := exists_list_of_mem_closure hx
@[to_additive]
theorem exists_multiset_of_mem_closure {M : Type*} [CommMonoid M] {s : Set M} {x : M}
    (hx : x ∈ closure s) : ∃ (l : Multiset M) (_ : ∀ y ∈ l, y ∈ s), l.prod = x := by
  obtain ⟨l, h1, h2⟩ := exists_list_of_mem_closure hx
  

Proof state:
case intro.intro
M✝ : Type u_1
A : Type u_2
B : Type u_3
inst✝¹ : Monoid M✝
a : M✝
M : Type u_4
inst✝ : CommMonoid M
s : Set M
x : M
hx : x ∈ closure s
l : List M
h1 : ∀ y ∈ l, y ∈ s
h2 : List.prod l = x
⊢ ∃ l, ∃ (_ : ∀ y ∈ l, y ∈ s), Multiset.prod l = x

Next tactic:
exact ⟨l, h1, (Multiset.coe_prod l).trans h2⟩
@[to_additive]
theorem closure_induction_left {s : Set M} {p : M → Prop} {x : M} (h : x ∈ closure s) (H1 : p 1)
    (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x := by
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
x : M
h : x ∈ closure s
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
⊢ p x

Next tactic:
rw [closure_eq_mrange] at h
@[to_additive]
theorem closure_induction_left {s : Set M} {p : M → Prop} {x : M} (h : x ∈ closure s) (H1 : p 1)
    (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x := by
  rw [closure_eq_mrange] at h
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
x : M
h : x ∈ mrange (FreeMonoid.lift Subtype.val)
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
⊢ p x

Next tactic:
obtain ⟨l, rfl⟩ := h
@[to_additive]
theorem closure_induction_left {s : Set M} {p : M → Prop} {x : M} (h : x ∈ closure s) (H1 : p 1)
    (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x := by
  rw [closure_eq_mrange] at h
  obtain ⟨l, rfl⟩ := h
  

Proof state:
case intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
l : FreeMonoid { x // x ∈ s }
⊢ p ((FreeMonoid.lift Subtype.val) l)

Next tactic:
induction' l using FreeMonoid.recOn with x y ih
@[to_additive]
theorem closure_induction_left {s : Set M} {p : M → Prop} {x : M} (h : x ∈ closure s) (H1 : p 1)
    (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x := by
  rw [closure_eq_mrange] at h
  obtain ⟨l, rfl⟩ := h
  induction' l using FreeMonoid.recOn with x y ih
  · 

Proof state:
case intro.h0
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
⊢ p ((FreeMonoid.lift Subtype.val) 1)

Next tactic:
exact H1
@[to_additive]
theorem closure_induction_left {s : Set M} {p : M → Prop} {x : M} (h : x ∈ closure s) (H1 : p 1)
    (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x := by
  rw [closure_eq_mrange] at h
  obtain ⟨l, rfl⟩ := h
  induction' l using FreeMonoid.recOn with x y ih
  · exact H1
  · 

Proof state:
case intro.ih
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
x : { x // x ∈ s }
y : FreeMonoid { x // x ∈ s }
ih : p ((FreeMonoid.lift Subtype.val) y)
⊢ p ((FreeMonoid.lift Subtype.val) (FreeMonoid.of x * y))

Next tactic:
simpa only [map_mul, FreeMonoid.lift_eval_of] using Hmul _ x.prop _ ih
@[to_additive (attr := elab_as_elim)]
theorem induction_of_closure_eq_top_left {s : Set M} {p : M → Prop} (hs : closure s = ⊤) (x : M)
    (H1 : p 1) (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x :=
  closure_induction_left
    (by
      

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
hs : closure s = ⊤
x : M
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
⊢ x ∈ closure s

Next tactic:
rw [hs]
@[to_additive (attr := elab_as_elim)]
theorem induction_of_closure_eq_top_left {s : Set M} {p : M → Prop} (hs : closure s = ⊤) (x : M)
    (H1 : p 1) (Hmul : ∀ x ∈ s, ∀ (y), p y → p (x * y)) : p x :=
  closure_induction_left
    (by
      rw [hs]
      

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
hs : closure s = ⊤
x : M
H1 : p 1
Hmul : ∀ x ∈ s, ∀ (y : M), p y → p (x * y)
⊢ x ∈ ⊤

Next tactic:
exact mem_top _
@[to_additive (attr := elab_as_elim)]
theorem induction_of_closure_eq_top_right {s : Set M} {p : M → Prop} (hs : closure s = ⊤) (x : M)
    (H1 : p 1) (Hmul : ∀ (x), ∀ y ∈ s, p x → p (x * y)) : p x :=
  closure_induction_right
    (by 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
hs : closure s = ⊤
x : M
H1 : p 1
Hmul : ∀ (x y : M), y ∈ s → p x → p (x * y)
⊢ x ∈ closure s

Next tactic:
rw [hs]
@[to_additive (attr := elab_as_elim)]
theorem induction_of_closure_eq_top_right {s : Set M} {p : M → Prop} (hs : closure s = ⊤) (x : M)
    (H1 : p 1) (Hmul : ∀ (x), ∀ y ∈ s, p x → p (x * y)) : p x :=
  closure_induction_right
    (by rw [hs]; 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a : M
s : Set M
p : M → Prop
hs : closure s = ⊤
x : M
H1 : p 1
Hmul : ∀ (x y : M), y ∈ s → p x → p (x * y)
⊢ x ∈ ⊤

Next tactic:
exact mem_top _
/-- The submonoid generated by an element. -/
def powers (n : M) : Submonoid M :=
  Submonoid.copy (mrange (powersHom M n)) (Set.range (n ^ · : ℕ → M)) <|
    Set.ext fun n => exists_congr fun i => by 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a n✝ n : M
i : ℕ
⊢ (fun x => n✝ ^ x) i = n ↔ ((powersHom M) n✝) i = n

Next tactic:
simp
/-- The submonoid generated by an element. -/
def powers (n : M) : Submonoid M :=
  Submonoid.copy (mrange (powersHom M n)) (Set.range (n ^ · : ℕ → M)) <|
    Set.ext fun n => exists_congr fun i => by simp; 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a n✝ n : M
i : ℕ
⊢ n✝ ^ i = n ↔ n✝ ^ Multiplicative.toAdd i = n

Next tactic:
rfl
theorem powers_eq_closure (n : M) : powers n = closure {n} := by
  

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a n : M
⊢ powers n = closure {n}

Next tactic:
ext
theorem powers_eq_closure (n : M) : powers n = closure {n} := by
  ext
  

Proof state:
case h
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a n x✝ : M
⊢ x✝ ∈ powers n ↔ x✝ ∈ closure {n}

Next tactic:
exact mem_closure_singleton.symm
lemma powers_le {n : M} {P : Submonoid M} : powers n ≤ P ↔ n ∈ P := by 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a n : M
P : Submonoid M
⊢ powers n ≤ P ↔ n ∈ P

Next tactic:
simp [powers_eq_closure]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by 

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
z : ↥(powers x)
⊢ (fun z x_1 => x_1 ^ Int.natMod z ↑n) 0 z = 1

Next tactic:
simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x✝ : M
n : ℕ
hpos : 0 < n
hx : x✝ ^ n = 1
m : ℕ
x : ↥(powers x✝)
⊢ ↑((fun z x => x ^ Int.natMod z ↑n) (Int.ofNat (Nat.succ m)) x) =
    ↑(x * (fun z x => x ^ Int.natMod z ↑n) (Int.ofNat m) x)

Next tactic:
obtain ⟨_, k, rfl⟩ := x
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ ↑((fun z x_1 => x_1 ^ Int.natMod z ↑n) (Int.ofNat (Nat.succ m))
        { val := (fun x_1 => x ^ x_1) k, property := (_ : ∃ y, (fun x_1 => x ^ x_1) y = (fun x_1 => x ^ x_1) k) }) =
    ↑({ val := (fun x_1 => x ^ x_1) k, property := (_ : ∃ y, (fun x_1 => x ^ x_1) y = (fun x_1 => x ^ x_1) k) } *
        (fun z x_1 => x_1 ^ Int.natMod z ↑n) (Int.ofNat m)
          { val := (fun x_1 => x ^ x_1) k, property := (_ : ∃ y, (fun x_1 => x ^ x_1) y = (fun x_1 => x ^ x_1) k) })

Next tactic:
simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul]
    

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ x ^ (k * Int.toNat (↑(Nat.succ m) % ↑n)) = x ^ k * x ^ (k * Int.toNat (↑m % ↑n))

Next tactic:
norm_cast
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul]
    norm_cast
    

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ x ^ (k * Int.toNat ↑(Nat.succ m % n)) = x ^ k * x ^ (k * Int.toNat ↑(m % n))

Next tactic:
iterate 2 rw [Int.toNat_coe_nat, mul_comm, pow_mul, ← pow_eq_pow_mod _ hx]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul]
    norm_cast
    iterate 2 

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ x ^ (k * Int.toNat ↑(Nat.succ m % n)) = x ^ k * x ^ (k * Int.toNat ↑(m % n))

Next tactic:
rw [Int.toNat_coe_nat, mul_comm, pow_mul, ← pow_eq_pow_mod _ hx]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul]
    norm_cast
    iterate 2 

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ (x ^ Nat.succ m) ^ k = x ^ k * x ^ (k * Int.toNat ↑(m % n))

Next tactic:
rw [Int.toNat_coe_nat, mul_comm, pow_mul, ← pow_eq_pow_mod _ hx]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]
    nth_rw 1 [← mul_one ((m + 1 : ℕ) : ℤ)]
    rw [← sub_eq_neg_add, ← mul_sub, ← Int.coe_pred_of_pos hpos]; norm_cast
    simp only [Int.toNat_coe_nat]
    rw [mul_comm, pow_mul, ← pow_eq_pow_mod _ hx, mul_comm k, mul_assoc, pow_mul _ (_ % _),
      ← pow_eq_pow_mod _ hx, pow_mul, pow_mul]
  zpow_succ' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul]
    norm_cast
    iterate 2 rw [Int.toNat_coe_nat, mul_comm, pow_mul, ← pow_eq_pow_mod _ hx]
    

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ (x ^ Nat.succ m) ^ k = x ^ k * (x ^ m) ^ k

Next tactic:
rw [← pow_mul _ m, mul_comm, pow_mul, ← pow_succ, ← pow_mul, mul_comm, pow_mul]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    

Proof state:
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x✝ : M
n : ℕ
hpos : 0 < n
hx : x✝ ^ n = 1
m : ℕ
x : ↥(powers x✝)
⊢ ↑((fun z x => x ^ Int.natMod z ↑n) (Int.negSucc m) x) = ↑((fun z x => x ^ Int.natMod z ↑n) (↑(Nat.succ m)) x)⁻¹

Next tactic:
obtain ⟨_, k, rfl⟩ := x
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ ↑((fun z x_1 => x_1 ^ Int.natMod z ↑n) (Int.negSucc m)
        { val := (fun x_1 => x ^ x_1) k, property := (_ : ∃ y, (fun x_1 => x ^ x_1) y = (fun x_1 => x ^ x_1) k) }) =
    ↑((fun z x_1 => x_1 ^ Int.natMod z ↑n) ↑(Nat.succ m)
          { val := (fun x_1 => x ^ x_1) k, property := (_ : ∃ y, (fun x_1 => x ^ x_1) y = (fun x_1 => x ^ x_1) k) })⁻¹

Next tactic:
simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
/-- The submonoid generated by an element is a group if that element has finite order. -/
abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where
  inv x := x ^ (n - 1)
  mul_left_inv y := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := y
    simp only [coe_one, coe_mul, SubmonoidClass.coe_pow]
    rw [← pow_succ', Nat.sub_add_cancel hpos, ← pow_mul, mul_comm, pow_mul, hx, one_pow]
  zpow z x := x ^ z.natMod n
  zpow_zero' z := by simp only [Int.natMod, Int.zero_emod, Int.toNat_zero, pow_zero]
  zpow_neg' m x := Subtype.ext <| by
    obtain ⟨_, k, rfl⟩ := x
    simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow]
    

Proof state:
case mk.intro
M : Type u_1
A : Type u_2
B : Type u_3
inst✝ : Monoid M
a x : M
n : ℕ
hpos : 0 < n
hx : x ^ n = 1
m k : ℕ
⊢ x ^ (k * Int.toNat (Int.negSucc m % ↑n)) = x ^ (k * (Int.toNat (↑(Nat.succ m) % ↑n) * (n - 1)))

Next tactic:
rw [Int.negSucc_coe, ← Int.add_mul_emod_self (b := (m + 1 : ℕ))]