l3lab/ntp-mathlib huggingface dataset:
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x✝ : N
hx✝ : x✝ ∈ closure s
x : N
hx : x ∈ s
⊢ (fun x => r • x) x = r ^ 1 • x

Next tactic:
rw [pow_one]
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩
  · 

Proof state:
case refine'_2
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x : N
hx : x ∈ closure s
⊢ (fun x => ∃ n, r ^ n • x ∈ closure (r • s)) 1

Next tactic:
exact ⟨0, by simpa using one_mem _⟩
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩
  · exact ⟨0, by 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x : N
hx : x ∈ closure s
⊢ r ^ 0 • 1 ∈ closure (r • s)

Next tactic:
simpa using one_mem _
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩
  · exact ⟨0, by simpa using one_mem _⟩
  · 

Proof state:
case refine'_3
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x : N
hx : x ∈ closure s
⊢ ∀ (x y : N),
    (fun x => ∃ n, r ^ n • x ∈ closure (r • s)) x →
      (fun x => ∃ n, r ^ n • x ∈ closure (r • s)) y → (fun x => ∃ n, r ^ n • x ∈ closure (r • s)) (x * y)

Next tactic:
rintro x y ⟨nx, hx⟩ ⟨ny, hy⟩
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩
  · exact ⟨0, by simpa using one_mem _⟩
  · rintro x y ⟨nx, hx⟩ ⟨ny, hy⟩
    

Proof state:
case refine'_3.intro.intro
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x✝ : N
hx✝ : x✝ ∈ closure s
x y : N
nx : ℕ
hx : r ^ nx • x ∈ closure (r • s)
ny : ℕ
hy : r ^ ny • y ∈ closure (r • s)
⊢ ∃ n, r ^ n • (x * y) ∈ closure (r • s)

Next tactic:
use ny + nx
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩
  · exact ⟨0, by simpa using one_mem _⟩
  · rintro x y ⟨nx, hx⟩ ⟨ny, hy⟩
    use ny + nx
    

Proof state:
case h
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x✝ : N
hx✝ : x✝ ∈ closure s
x y : N
nx : ℕ
hx : r ^ nx • x ∈ closure (r • s)
ny : ℕ
hy : r ^ ny • y ∈ closure (r • s)
⊢ r ^ (ny + nx) • (x * y) ∈ closure (r • s)

Next tactic:
rw [pow_add, mul_smul, ← smul_mul_assoc, mul_comm, ← smul_mul_assoc]
@[to_additive]
theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N]
    (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by
  refine' @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx _ _ _
  · intro x hx
    exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩
  · exact ⟨0, by simpa using one_mem _⟩
  · rintro x y ⟨nx, hx⟩ ⟨ny, hy⟩
    use ny + nx
    rw [pow_add, mul_smul, ← smul_mul_assoc, mul_comm, ← smul_mul_assoc]
    

Proof state:
case h
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝⁴ : Monoid M
inst✝³ : AddMonoid A
s✝ t u : Set M
N : Type u_6
inst✝² : CommMonoid N
inst✝¹ : MulAction M N
inst✝ : IsScalarTower M N N
r : M
s : Set N
x✝ : N
hx✝ : x✝ ∈ closure s
x y : N
nx : ℕ
hx : r ^ nx • x ∈ closure (r • s)
ny : ℕ
hy : r ^ ny • y ∈ closure (r • s)
⊢ r ^ ny • y * r ^ nx • x ∈ closure (r • s)

Next tactic:
exact mul_mem hy hx
/-- The submonoid with every element inverted. -/
@[to_additive " The additive submonoid with every element negated. "]
protected def inv : Inv (Submonoid G) where
  inv S :=
    { carrier := (S : Set G)⁻¹
      mul_mem' := fun ha hb => by 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s t u : Set M
inst✝ : Group G
S : Submonoid G
a✝ b✝ : G
ha : a✝ ∈ (↑S)⁻¹
hb : b✝ ∈ (↑S)⁻¹
⊢ a✝ * b✝ ∈ (↑S)⁻¹

Next tactic:
rw [mem_inv, mul_inv_rev]
/-- The submonoid with every element inverted. -/
@[to_additive " The additive submonoid with every element negated. "]
protected def inv : Inv (Submonoid G) where
  inv S :=
    { carrier := (S : Set G)⁻¹
      mul_mem' := fun ha hb => by rw [mem_inv, mul_inv_rev]; 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s t u : Set M
inst✝ : Group G
S : Submonoid G
a✝ b✝ : G
ha : a✝ ∈ (↑S)⁻¹
hb : b✝ ∈ (↑S)⁻¹
⊢ b✝⁻¹ * a✝⁻¹ ∈ ↑S

Next tactic:
exact mul_mem hb ha
/-- The submonoid with every element inverted. -/
@[to_additive " The additive submonoid with every element negated. "]
protected def inv : Inv (Submonoid G) where
  inv S :=
    { carrier := (S : Set G)⁻¹
      mul_mem' := fun ha hb => by rw [mem_inv, mul_inv_rev]; exact mul_mem hb ha
      one_mem' := mem_inv.2 <| by 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s t u : Set M
inst✝ : Group G
S : Submonoid G
⊢ 1⁻¹ ∈ ↑S

Next tactic:
rw [inv_one]
/-- The submonoid with every element inverted. -/
@[to_additive " The additive submonoid with every element negated. "]
protected def inv : Inv (Submonoid G) where
  inv S :=
    { carrier := (S : Set G)⁻¹
      mul_mem' := fun ha hb => by rw [mem_inv, mul_inv_rev]; exact mul_mem hb ha
      one_mem' := mem_inv.2 <| by rw [inv_one]; 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s t u : Set M
inst✝ : Group G
S : Submonoid G
⊢ 1 ∈ ↑S

Next tactic:
exact S.one_mem'
@[to_additive]
theorem closure_inv (s : Set G) : closure s⁻¹ = (closure s)⁻¹ := by
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s✝ t u : Set M
inst✝ : Group G
s : Set G
⊢ closure s⁻¹ = (closure s)⁻¹

Next tactic:
apply le_antisymm
@[to_additive]
theorem closure_inv (s : Set G) : closure s⁻¹ = (closure s)⁻¹ := by
  apply le_antisymm
  · 

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s✝ t u : Set M
inst✝ : Group G
s : Set G
⊢ closure s⁻¹ ≤ (closure s)⁻¹

Next tactic:
rw [closure_le, coe_inv, ← Set.inv_subset, inv_inv]
@[to_additive]
theorem closure_inv (s : Set G) : closure s⁻¹ = (closure s)⁻¹ := by
  apply le_antisymm
  · rw [closure_le, coe_inv, ← Set.inv_subset, inv_inv]
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s✝ t u : Set M
inst✝ : Group G
s : Set G
⊢ s ⊆ ↑(closure s)

Next tactic:
exact subset_closure
@[to_additive]
theorem closure_inv (s : Set G) : closure s⁻¹ = (closure s)⁻¹ := by
  apply le_antisymm
  · rw [closure_le, coe_inv, ← Set.inv_subset, inv_inv]
    exact subset_closure
  · 

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s✝ t u : Set M
inst✝ : Group G
s : Set G
⊢ (closure s)⁻¹ ≤ closure s⁻¹

Next tactic:
rw [inv_le, closure_le, coe_inv, ← Set.inv_subset]
@[to_additive]
theorem closure_inv (s : Set G) : closure s⁻¹ = (closure s)⁻¹ := by
  apply le_antisymm
  · rw [closure_le, coe_inv, ← Set.inv_subset, inv_inv]
    exact subset_closure
  · rw [inv_le, closure_le, coe_inv, ← Set.inv_subset]
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
s✝ t u : Set M
inst✝ : Group G
s : Set G
⊢ s⁻¹ ⊆ ↑(closure s⁻¹)

Next tactic:
exact subset_closure
/-- The action on a submonoid corresponding to applying the action to every element.

This is available as an instance in the `Pointwise` locale. -/
protected def pointwiseMulAction : MulAction α (Submonoid M) where
  smul a S := S.map (MulDistribMulAction.toMonoidEnd _ M a)
  one_smul S := by
    

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝³ : Monoid M
inst✝² : AddMonoid A
inst✝¹ : Monoid α
inst✝ : MulDistribMulAction α M
S : Submonoid M
⊢ 1 • S = S

Next tactic:
change S.map _ = S
/-- The action on a submonoid corresponding to applying the action to every element.

This is available as an instance in the `Pointwise` locale. -/
protected def pointwiseMulAction : MulAction α (Submonoid M) where
  smul a S := S.map (MulDistribMulAction.toMonoidEnd _ M a)
  one_smul S := by
    change S.map _ = S
    

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝³ : Monoid M
inst✝² : AddMonoid A
inst✝¹ : Monoid α
inst✝ : MulDistribMulAction α M
S : Submonoid M
⊢ map ((MulDistribMulAction.toMonoidEnd α M) 1) S = S

Next tactic:
simpa only [map_one] using S.map_id
@[to_additive]
theorem mem_closure_inv {G : Type*} [Group G] (S : Set G) (x : G) :
    x ∈ Submonoid.closure S⁻¹ ↔ x⁻¹ ∈ Submonoid.closure S := by 

Proof state:
α : Type u_1
G✝ : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
G : Type u_6
inst✝ : Group G
S : Set G
x : G
⊢ x ∈ closure S⁻¹ ↔ x⁻¹ ∈ closure S

Next tactic:
rw [closure_inv, mem_inv]
theorem one_eq_closure : (1 : AddSubmonoid R) = closure {1} := by
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : AddMonoidWithOne R
⊢ 1 = closure {1}

Next tactic:
rw [closure_singleton_eq, one_eq_mrange]
theorem one_eq_closure : (1 : AddSubmonoid R) = closure {1} := by
  rw [closure_singleton_eq, one_eq_mrange]
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : AddMonoidWithOne R
⊢ AddMonoidHom.mrange (Nat.castAddMonoidHom R) = AddMonoidHom.mrange ((multiplesHom R) 1)

Next tactic:
congr 1
theorem one_eq_closure : (1 : AddSubmonoid R) = closure {1} := by
  rw [closure_singleton_eq, one_eq_mrange]
  congr 1
  

Proof state:
case e_f
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : AddMonoidWithOne R
⊢ Nat.castAddMonoidHom R = (multiplesHom R) 1

Next tactic:
ext
theorem one_eq_closure : (1 : AddSubmonoid R) = closure {1} := by
  rw [closure_singleton_eq, one_eq_mrange]
  congr 1
  ext
  

Proof state:
case e_f.a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : AddMonoidWithOne R
⊢ (Nat.castAddMonoidHom R) 1 = ((multiplesHom R) 1) 1

Next tactic:
simp
theorem mul_mem_mul {M N : AddSubmonoid R} {m n : R} (hm : m ∈ M) (hn : n ∈ N) : m * n ∈ M * N :=
  (le_iSup _ ⟨m, hm⟩ : _ ≤ M * N) ⟨n, hn, by 

Proof state:
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
M N : AddSubmonoid R
m n : R
hm : m ∈ M
hn : n ∈ N
⊢ (AddMonoidHom.mul ↑{ val := m, property := hm }) n = m * n

Next tactic:
rfl
@[elab_as_elim]
protected theorem mul_induction_on {M N : AddSubmonoid R} {C : R → Prop} {r : R} (hr : r ∈ M * N)
    (hm : ∀ m ∈ M, ∀ n ∈ N, C (m * n)) (ha : ∀ x y, C x → C y → C (x + y)) : C r :=
  (@mul_le _ _ _ _ ⟨⟨setOf C, ha _ _⟩, by
    

Proof state:
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
M N : AddSubmonoid R
C : R → Prop
r : R
hr : r ∈ M * N
hm : ∀ m ∈ M, ∀ n ∈ N, C (m * n)
ha : ∀ (x y : R), C x → C y → C (x + y)
⊢ 0 ∈ { carrier := setOf C, add_mem' := (_ : ∀ {a b : R}, C a → C b → C (a + b)) }.carrier

Next tactic:
simpa only [zero_mul] using hm _ (zero_mem _) _ (zero_mem _)
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
⊢ closure S * closure T = closure (S * T)

Next tactic:
apply le_antisymm
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · 

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
⊢ closure S * closure T ≤ closure (S * T)

Next tactic:
refine mul_le.2 fun a ha b hb => ?_
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a : R
ha : a ∈ closure S
b : R
hb : b ∈ closure T
⊢ a * b ∈ closure (S * T)

Next tactic:
rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a : R
ha : a ∈ closure S
b : R
hb : b ∈ closure T
⊢ a ∈ comap (AddMonoidHom.mulRight b) (closure (S * T))

Next tactic:
refine (closure_le.2 fun a' ha' => ?_) ha
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a : R
ha : a ∈ closure S
b : R
hb : b ∈ closure T
a' : R
ha' : a' ∈ S
⊢ a' ∈ ↑(comap (AddMonoidHom.mulRight b) (closure (S * T)))

Next tactic:
change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a : R
ha : a ∈ closure S
b : R
hb : b ∈ closure T
a' : R
ha' : a' ∈ S
⊢ b ∈ comap (AddMonoidHom.mulLeft a') (closure (S * T))

Next tactic:
refine (closure_le.2 fun b' hb' => ?_) hb
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
    refine (closure_le.2 fun b' hb' => ?_) hb
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a : R
ha : a ∈ closure S
b : R
hb : b ∈ closure T
a' : R
ha' : a' ∈ S
b' : R
hb' : b' ∈ T
⊢ b' ∈ ↑(comap (AddMonoidHom.mulLeft a') (closure (S * T)))

Next tactic:
change a' * b' ∈ closure (S * T)
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
    refine (closure_le.2 fun b' hb' => ?_) hb
    change a' * b' ∈ closure (S * T)
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a : R
ha : a ∈ closure S
b : R
hb : b ∈ closure T
a' : R
ha' : a' ∈ S
b' : R
hb' : b' ∈ T
⊢ a' * b' ∈ closure (S * T)

Next tactic:
exact subset_closure (Set.mul_mem_mul ha' hb')
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
    refine (closure_le.2 fun b' hb' => ?_) hb
    change a' * b' ∈ closure (S * T)
    exact subset_closure (Set.mul_mem_mul ha' hb')
  · 

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
⊢ closure (S * T) ≤ closure S * closure T

Next tactic:
rw [closure_le]
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
    refine (closure_le.2 fun b' hb' => ?_) hb
    change a' * b' ∈ closure (S * T)
    exact subset_closure (Set.mul_mem_mul ha' hb')
  · rw [closure_le]
    

Proof state:
case a
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
⊢ S * T ⊆ ↑(closure S * closure T)

Next tactic:
rintro _ ⟨a, b, ha, hb, rfl⟩
theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by
  apply le_antisymm
  · refine mul_le.2 fun a ha b hb => ?_
    rw [← AddMonoidHom.mulRight_apply, ← AddSubmonoid.mem_comap]
    refine (closure_le.2 fun a' ha' => ?_) ha
    change b ∈ (closure (S * T)).comap (AddMonoidHom.mulLeft a')
    refine (closure_le.2 fun b' hb' => ?_) hb
    change a' * b' ∈ closure (S * T)
    exact subset_closure (Set.mul_mem_mul ha' hb')
  · rw [closure_le]
    rintro _ ⟨a, b, ha, hb, rfl⟩
    

Proof state:
case a.intro.intro.intro.intro
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S T : Set R
a b : R
ha : a ∈ S
hb : b ∈ T
⊢ (fun x x_1 => x * x_1) a b ∈ ↑(closure S * closure T)

Next tactic:
exact mul_mem_mul (subset_closure ha) (subset_closure hb)
theorem mul_eq_closure_mul_set (M N : AddSubmonoid R) :
    M * N = closure ((M : Set R) * (N : Set R)) := by
  

Proof state:
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
M N : AddSubmonoid R
⊢ M * N = closure (↑M * ↑N)

Next tactic:
rw [← closure_mul_closure, closure_eq, closure_eq]
@[simp]
theorem mul_bot (S : AddSubmonoid R) : S * ⊥ = ⊥ :=
  eq_bot_iff.2 <| mul_le.2 fun m _ n hn => by
    

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S : AddSubmonoid R
m : R
x✝ : m ∈ S
n : R
hn : n ∈ ⊥
⊢ m * n ∈ ⊥

Next tactic:
rw [AddSubmonoid.mem_bot] at hn ⊢
@[simp]
theorem mul_bot (S : AddSubmonoid R) : S * ⊥ = ⊥ :=
  eq_bot_iff.2 <| mul_le.2 fun m _ n hn => by
    rw [AddSubmonoid.mem_bot] at hn ⊢; 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S : AddSubmonoid R
m : R
x✝ : m ∈ S
n : R
hn : n = 0
⊢ m * n = 0

Next tactic:
rw [hn, mul_zero]
@[simp]
theorem bot_mul (S : AddSubmonoid R) : ⊥ * S = ⊥ :=
  eq_bot_iff.2 <| mul_le.2 fun m hm n hn => by
    

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S : AddSubmonoid R
m : R
hm : m ∈ ⊥
n : R
hn : n ∈ S
⊢ m * n ∈ ⊥

Next tactic:
rw [AddSubmonoid.mem_bot] at hm ⊢
@[simp]
theorem bot_mul (S : AddSubmonoid R) : ⊥ * S = ⊥ :=
  eq_bot_iff.2 <| mul_le.2 fun m hm n hn => by
    rw [AddSubmonoid.mem_bot] at hm ⊢; 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
S : AddSubmonoid R
m : R
hm : m = 0
n : R
hn : n ∈ S
⊢ m * n = 0

Next tactic:
rw [hm, zero_mul]
theorem mul_subset_mul {M N : AddSubmonoid R} :
    (↑M : Set R) * (↑N : Set R) ⊆ (↑(M * N) : Set R) := by
  

Proof state:
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
M N : AddSubmonoid R
⊢ ↑M * ↑N ⊆ ↑(M * N)

Next tactic:
rintro _ ⟨i, j, hi, hj, rfl⟩
theorem mul_subset_mul {M N : AddSubmonoid R} :
    (↑M : Set R) * (↑N : Set R) ⊆ (↑(M * N) : Set R) := by
  rintro _ ⟨i, j, hi, hj, rfl⟩
  

Proof state:
case intro.intro.intro.intro
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocSemiring R
M N : AddSubmonoid R
i j : R
hi : i ∈ ↑M
hj : j ∈ ↑N
⊢ (fun x x_1 => x * x_1) i j ∈ ↑(M * N)

Next tactic:
exact mul_mem_mul hi hj
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
⊢ -x * y = -(x * y)

Next tactic:
refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _)