l3lab/ntp-mathlib huggingface dataset:
theorem noncommFoldr_eq_foldr (s : Multiset α) (h : LeftCommutative f) (b : β) :
    noncommFoldr f s (fun x _ y _ _ => h x y) b = foldr f h b s := by
  induction s using Quotient.inductionOn
  

Proof state:
case h
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
h : LeftCommutative f
b : β
a✝ : List α
⊢ noncommFoldr f ⟦a✝⟧ (_ : ∀ x ∈ {x | x ∈ ⟦a✝⟧}, ∀ y ∈ {x | x ∈ ⟦a✝⟧}, x ≠ y → ∀ (b : β), f x (f y b) = f y (f x b)) b =
    foldr f h b ⟦a✝⟧

Next tactic:
simp
/-- Fold of a `s : Multiset α` with an associative `op : α → α → α`, given a proofs that `op`
is commutative on all elements `x ∈ s`. -/
def noncommFold (s : Multiset α) (comm : { x | x ∈ s }.Pairwise fun x y => op x y = op y x) :
    α → α :=
  noncommFoldr op s fun x hx y hy h b => by 

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
assoc : IsAssociative α op
s : Multiset α
comm : Set.Pairwise {x | x ∈ s} fun x y => op x y = op y x
x : α
hx : x ∈ {x | x ∈ s}
y : α
hy : y ∈ {x | x ∈ s}
h : x ≠ y
b : α
⊢ op x (op y b) = op y (op x b)

Next tactic:
rw [← assoc.assoc, comm hx hy h, assoc.assoc]
@[simp]
theorem noncommFold_coe (l : List α) (comm) (a : α) :
    noncommFold op (l : Multiset α) comm a = l.foldr op a := by 

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
assoc : IsAssociative α op
l : List α
comm : Set.Pairwise {x | x ∈ ↑l} fun x y => op x y = op y x
a : α
⊢ noncommFold op (↑l) comm a = List.foldr op a l

Next tactic:
simp [noncommFold]
theorem noncommFold_cons (s : Multiset α) (a : α) (h h') (x : α) :
    noncommFold op (a ::ₘ s) h x = op a (noncommFold op s h' x) := by
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
assoc : IsAssociative α op
s : Multiset α
a : α
h : Set.Pairwise {x | x ∈ a ::ₘ s} fun x y => op x y = op y x
h' : Set.Pairwise {x | x ∈ s} fun x y => op x y = op y x
x : α
⊢ noncommFold op (a ::ₘ s) h x = op a (noncommFold op s h' x)

Next tactic:
induction s using Quotient.inductionOn
theorem noncommFold_cons (s : Multiset α) (a : α) (h h') (x : α) :
    noncommFold op (a ::ₘ s) h x = op a (noncommFold op s h' x) := by
  induction s using Quotient.inductionOn
  

Proof state:
case h
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
assoc : IsAssociative α op
a x : α
a✝ : List α
h : Set.Pairwise {x | x ∈ a ::ₘ ⟦a✝⟧} fun x y => op x y = op y x
h' : Set.Pairwise {x | x ∈ ⟦a✝⟧} fun x y => op x y = op y x
⊢ noncommFold op (a ::ₘ ⟦a✝⟧) h x = op a (noncommFold op ⟦a✝⟧ h' x)

Next tactic:
simp
theorem noncommFold_eq_fold (s : Multiset α) [IsCommutative α op] (a : α) :
    noncommFold op s (fun x _ y _ _ => IsCommutative.comm x y) a = fold op a s := by
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
assoc : IsAssociative α op
s : Multiset α
inst✝ : IsCommutative α op
a : α
⊢ noncommFold op s (_ : ∀ x ∈ {x | x ∈ s}, ∀ y ∈ {x | x ∈ s}, x ≠ y → op x y = op y x) a = fold op a s

Next tactic:
induction s using Quotient.inductionOn
theorem noncommFold_eq_fold (s : Multiset α) [IsCommutative α op] (a : α) :
    noncommFold op s (fun x _ y _ _ => IsCommutative.comm x y) a = fold op a s := by
  induction s using Quotient.inductionOn
  

Proof state:
case h
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
assoc : IsAssociative α op
inst✝ : IsCommutative α op
a : α
a✝ : List α
⊢ noncommFold op ⟦a✝⟧ (_ : ∀ x ∈ {x | x ∈ ⟦a✝⟧}, ∀ y ∈ {x | x ∈ ⟦a✝⟧}, x ≠ y → op x y = op y x) a = fold op a ⟦a✝⟧

Next tactic:
simp
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
l : List α
comm : Set.Pairwise {x | x ∈ ↑l} Commute
⊢ noncommProd (↑l) comm = List.prod l

Next tactic:
rw [noncommProd]
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  rw [noncommProd]
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
l : List α
comm : Set.Pairwise {x | x ∈ ↑l} Commute
⊢ noncommFold (fun x x_1 => x * x_1) (↑l) comm 1 = List.prod l

Next tactic:
simp only [noncommFold_coe]
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  rw [noncommProd]
  simp only [noncommFold_coe]
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
l : List α
comm : Set.Pairwise {x | x ∈ ↑l} Commute
⊢ List.foldr (fun x x_1 => x * x_1) 1 l = List.prod l

Next tactic:
induction' l with hd tl hl
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  rw [noncommProd]
  simp only [noncommFold_coe]
  induction' l with hd tl hl
  · 

Proof state:
case nil
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
comm : Set.Pairwise {x | x ∈ ↑[]} Commute
⊢ List.foldr (fun x x_1 => x * x_1) 1 [] = List.prod []

Next tactic:
simp
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  rw [noncommProd]
  simp only [noncommFold_coe]
  induction' l with hd tl hl
  · simp
  · 

Proof state:
case cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
hd : α
tl : List α
hl : Set.Pairwise {x | x ∈ ↑tl} Commute → List.foldr (fun x x_1 => x * x_1) 1 tl = List.prod tl
comm : Set.Pairwise {x | x ∈ ↑(hd :: tl)} Commute
⊢ List.foldr (fun x x_1 => x * x_1) 1 (hd :: tl) = List.prod (hd :: tl)

Next tactic:
rw [List.prod_cons, List.foldr, hl]
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  rw [noncommProd]
  simp only [noncommFold_coe]
  induction' l with hd tl hl
  · simp
  · rw [List.prod_cons, List.foldr, hl]
    

Proof state:
case cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
hd : α
tl : List α
hl : Set.Pairwise {x | x ∈ ↑tl} Commute → List.foldr (fun x x_1 => x * x_1) 1 tl = List.prod tl
comm : Set.Pairwise {x | x ∈ ↑(hd :: tl)} Commute
⊢ Set.Pairwise {x | x ∈ ↑tl} Commute

Next tactic:
intro x hx y hy
@[to_additive (attr := simp)]
theorem noncommProd_coe (l : List α) (comm) : noncommProd (l : Multiset α) comm = l.prod := by
  rw [noncommProd]
  simp only [noncommFold_coe]
  induction' l with hd tl hl
  · simp
  · rw [List.prod_cons, List.foldr, hl]
    intro x hx y hy
    

Proof state:
case cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
hd : α
tl : List α
hl : Set.Pairwise {x | x ∈ ↑tl} Commute → List.foldr (fun x x_1 => x * x_1) 1 tl = List.prod tl
comm : Set.Pairwise {x | x ∈ ↑(hd :: tl)} Commute
x : α
hx : x ∈ {x | x ∈ ↑tl}
y : α
hy : y ∈ {x | x ∈ ↑tl}
⊢ x ≠ y → Commute x y

Next tactic:
exact comm (List.mem_cons_of_mem _ hx) (List.mem_cons_of_mem _ hy)
@[to_additive (attr := simp)]
theorem noncommProd_cons (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = a * noncommProd s (comm.mono fun _ => mem_cons_of_mem) := by
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
s : Multiset α
a : α
comm : Set.Pairwise {x | x ∈ a ::ₘ s} Commute
⊢ noncommProd (a ::ₘ s) comm = a * noncommProd s (_ : Set.Pairwise {x | x ∈ s} Commute)

Next tactic:
induction s using Quotient.inductionOn
@[to_additive (attr := simp)]
theorem noncommProd_cons (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = a * noncommProd s (comm.mono fun _ => mem_cons_of_mem) := by
  induction s using Quotient.inductionOn
  

Proof state:
case h
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a : α
a✝ : List α
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦a✝⟧} Commute
⊢ noncommProd (a ::ₘ ⟦a✝⟧) comm = a * noncommProd ⟦a✝⟧ (_ : Set.Pairwise {x | x ∈ ⟦a✝⟧} Commute)

Next tactic:
simp
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  

Proof state:
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
s : Multiset α
a : α
comm : Set.Pairwise {x | x ∈ a ::ₘ s} Commute
⊢ noncommProd (a ::ₘ s) comm = noncommProd s (_ : Set.Pairwise {x | x ∈ s} Commute) * a

Next tactic:
induction' s using Quotient.inductionOn with s
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  

Proof state:
case h
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a : α
s : List α
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦s⟧} Commute
⊢ noncommProd (a ::ₘ ⟦s⟧) comm = noncommProd ⟦s⟧ (_ : Set.Pairwise {x | x ∈ ⟦s⟧} Commute) * a

Next tactic:
simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  

Proof state:
case h
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a : α
s : List α
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦s⟧} Commute
⊢ a * List.prod s = List.prod s * a

Next tactic:
induction' s with hd tl IH
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · 

Proof state:
case h.nil
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a : α
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦[]⟧} Commute
⊢ a * List.prod [] = List.prod [] * a

Next tactic:
simp
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · 

Proof state:
case h.cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
⊢ a * List.prod (hd :: tl) = List.prod (hd :: tl) * a

Next tactic:
rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · 

Proof state:
case h.cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
⊢ a * hd * List.prod tl = hd * a * List.prod tl

Next tactic:
congr 1
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      

Proof state:
case h.cons.e_a
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
⊢ a * hd = hd * a

Next tactic:
apply comm.of_refl
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> 

Proof state:
case h.cons.e_a.a
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
⊢ a ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
simp
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> 

Proof state:
case h.cons.e_a.a
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
⊢ hd ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
simp
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · 

Proof state:
case h.cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
⊢ Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute

Next tactic:
intro x hx y hy
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      

Proof state:
case h.cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x : α
hx : x ∈ {x | x ∈ a ::ₘ ⟦tl⟧}
y : α
hy : y ∈ {x | x ∈ a ::ₘ ⟦tl⟧}
⊢ x ≠ y → Commute x y

Next tactic:
simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      

Proof state:
case h.cons
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hx : x ∈ {x | x = a ∨ x ∈ tl}
hy : y ∈ {x | x = a ∨ x ∈ tl}
⊢ x ≠ y → Commute x y

Next tactic:
apply comm
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      apply comm
      · 

Proof state:
case h.cons.a
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hx : x ∈ {x | x = a ∨ x ∈ tl}
hy : y ∈ {x | x = a ∨ x ∈ tl}
⊢ x ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
cases hx
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      apply comm
      · cases hx <;> 

Proof state:
case h.cons.a.inl
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hy : y ∈ {x | x = a ∨ x ∈ tl}
h✝ : x = a
⊢ x ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
simp [*]
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      apply comm
      · cases hx <;> 

Proof state:
case h.cons.a.inr
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hy : y ∈ {x | x = a ∨ x ∈ tl}
h✝ : x ∈ tl
⊢ x ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
simp [*]
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      apply comm
      · cases hx <;> simp [*]
      · 

Proof state:
case h.cons.a
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hx : x ∈ {x | x = a ∨ x ∈ tl}
hy : y ∈ {x | x = a ∨ x ∈ tl}
⊢ y ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
cases hy
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      apply comm
      · cases hx <;> simp [*]
      · cases hy <;> 

Proof state:
case h.cons.a.inl
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hx : x ∈ {x | x = a ∨ x ∈ tl}
h✝ : y = a
⊢ y ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
simp [*]
@[to_additive]
theorem noncommProd_cons' (s : Multiset α) (a : α) (comm) :
    noncommProd (a ::ₘ s) comm = noncommProd s (comm.mono fun _ => mem_cons_of_mem) * a := by
  induction' s using Quotient.inductionOn with s
  simp only [quot_mk_to_coe, cons_coe, noncommProd_coe, List.prod_cons]
  induction' s with hd tl IH
  · simp
  · rw [List.prod_cons, mul_assoc, ← IH, ← mul_assoc, ← mul_assoc]
    · congr 1
      apply comm.of_refl <;> simp
    · intro x hx y hy
      simp only [quot_mk_to_coe, List.mem_cons, mem_coe, cons_coe] at hx hy
      apply comm
      · cases hx <;> simp [*]
      · cases hy <;> 

Proof state:
case h.cons.a.inr
F : Type u_1
ι : Type u_2
α : Type u_3
β : Type u_4
γ : Type u_5
f : α → β → β
op : α → α → α
inst✝¹ : Monoid α
inst✝ : Monoid β
a hd : α
tl : List α
IH : Set.Pairwise {x | x ∈ a ::ₘ ⟦tl⟧} Commute → a * List.prod tl = List.prod tl * a
comm : Set.Pairwise {x | x ∈ a ::ₘ ⟦hd :: tl⟧} Commute
x y : α
hx : x ∈ {x | x = a ∨ x ∈ tl}
h✝ : y ∈ tl
⊢ y ∈ {x | x ∈ a ::ₘ ⟦hd :: tl⟧}

Next tactic:
simp [*]