l3lab/ntp-mathlib huggingface dataset:
@[to_additive]
theorem prod_range_add (f : ℕ → β) (n m : ℕ) :
    (∏ x in range (n + m), f x) = (∏ x in range n, f x) * ∏ x in range m, f (n + x) := by
  induction' m with m hm
  · 

Proof state:
case zero
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
f : ℕ → β
n : ℕ
⊢ ∏ x in range (n + Nat.zero), f x = (∏ x in range n, f x) * ∏ x in range Nat.zero, f (n + x)

Next tactic:
simp
@[to_additive]
theorem prod_range_add (f : ℕ → β) (n m : ℕ) :
    (∏ x in range (n + m), f x) = (∏ x in range n, f x) * ∏ x in range m, f (n + x) := by
  induction' m with m hm
  · simp
  · 

Proof state:
case succ
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
f : ℕ → β
n m : ℕ
hm : ∏ x in range (n + m), f x = (∏ x in range n, f x) * ∏ x in range m, f (n + x)
⊢ ∏ x in range (n + Nat.succ m), f x = (∏ x in range n, f x) * ∏ x in range (Nat.succ m), f (n + x)

Next tactic:
erw [Nat.add_succ, prod_range_succ, prod_range_succ, hm, mul_assoc]
@[to_additive]
theorem prod_range_zero (f : ℕ → β) : ∏ k in range 0, f k = 1 := by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
f : ℕ → β
⊢ ∏ k in range 0, f k = 1

Next tactic:
rw [range_zero, prod_empty]
@[to_additive sum_range_one]
theorem prod_range_one (f : ℕ → β) : ∏ k in range 1, f k = f 0 := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
f : ℕ → β
⊢ ∏ k in range 1, f k = f 0

Next tactic:
rw [range_one, prod_singleton]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
l : List α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
⊢ prod (List.map f l) = ∏ m in toFinset l, f m ^ count m l

Next tactic:
induction' l with a s IH
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · 

Proof state:
case nil
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
⊢ prod (List.map f []) = ∏ m in toFinset [], f m ^ count m []

Next tactic:
simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  

Proof state:
case cons
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
⊢ prod (List.map f (a :: s)) = ∏ m in toFinset (a :: s), f m ^ count m (a :: s)

Next tactic:
simp only [List.map, List.prod_cons, toFinset_cons, IH]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  

Proof state:
case cons
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
⊢ f a * ∏ m in toFinset s, f m ^ count m s = ∏ x in insert a (toFinset s), f x ^ count x (a :: s)

Next tactic:
by_cases has : a ∈ s.toFinset
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · 

Proof state:
case pos
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∈ toFinset s
⊢ f a * ∏ m in toFinset s, f m ^ count m s = ∏ x in insert a (toFinset s), f x ^ count x (a :: s)

Next tactic:
rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    

Proof state:
case pos
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∈ toFinset s
⊢ f a * f a ^ count a s * ∏ x in erase (toFinset s) a, f x ^ count x s =
    f a * f a ^ count a s * ∏ x in erase (toFinset s) a, f x ^ count x (a :: s)

Next tactic:
congr 1
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    

Proof state:
case pos.e_a
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∈ toFinset s
⊢ ∏ x in erase (toFinset s) a, f x ^ count x s = ∏ x in erase (toFinset s) a, f x ^ count x (a :: s)

Next tactic:
refine' prod_congr rfl fun x hx => _
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    

Proof state:
case pos.e_a
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∈ toFinset s
x : α
hx : x ∈ erase (toFinset s) a
⊢ f x ^ count x s = f x ^ count x (a :: s)

Next tactic:
rw [count_cons_of_ne (ne_of_mem_erase hx)]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    rw [count_cons_of_ne (ne_of_mem_erase hx)]
  

Proof state:
case neg
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∉ toFinset s
⊢ f a * ∏ m in toFinset s, f m ^ count m s = ∏ x in insert a (toFinset s), f x ^ count x (a :: s)

Next tactic:
rw [prod_insert has, count_cons_self, count_eq_zero_of_not_mem (mt mem_toFinset.2 has), pow_one]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    rw [count_cons_of_ne (ne_of_mem_erase hx)]
  rw [prod_insert has, count_cons_self, count_eq_zero_of_not_mem (mt mem_toFinset.2 has), pow_one]
  

Proof state:
case neg
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∉ toFinset s
⊢ f a * ∏ m in toFinset s, f m ^ count m s = f a * ∏ x in toFinset s, f x ^ count x (a :: s)

Next tactic:
congr 1
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    rw [count_cons_of_ne (ne_of_mem_erase hx)]
  rw [prod_insert has, count_cons_self, count_eq_zero_of_not_mem (mt mem_toFinset.2 has), pow_one]
  congr 1
  

Proof state:
case neg.e_a
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∉ toFinset s
⊢ ∏ m in toFinset s, f m ^ count m s = ∏ x in toFinset s, f x ^ count x (a :: s)

Next tactic:
refine' prod_congr rfl fun x hx => _
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    rw [count_cons_of_ne (ne_of_mem_erase hx)]
  rw [prod_insert has, count_cons_self, count_eq_zero_of_not_mem (mt mem_toFinset.2 has), pow_one]
  congr 1
  refine' prod_congr rfl fun x hx => _
  

Proof state:
case neg.e_a
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∉ toFinset s
x : α
hx : x ∈ toFinset s
⊢ f x ^ count x s = f x ^ count x (a :: s)

Next tactic:
rw [count_cons_of_ne]
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    rw [count_cons_of_ne (ne_of_mem_erase hx)]
  rw [prod_insert has, count_cons_self, count_eq_zero_of_not_mem (mt mem_toFinset.2 has), pow_one]
  congr 1
  refine' prod_congr rfl fun x hx => _
  rw [count_cons_of_ne]
  

Proof state:
case neg.e_a.h
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
a : α
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
has : a ∉ toFinset s
x : α
hx : x ∈ toFinset s
⊢ x ≠ a

Next tactic:
rintro rfl
@[to_additive]
theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) :
    (l.map f).prod = ∏ m in l.toFinset, f m ^ l.count m := by
  induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one]
  simp only [List.map, List.prod_cons, toFinset_cons, IH]
  by_cases has : a ∈ s.toFinset
  · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _),
      prod_insert (not_mem_erase _ _), ← mul_assoc, count_cons_self, pow_succ]
    congr 1
    refine' prod_congr rfl fun x hx => _
    rw [count_cons_of_ne (ne_of_mem_erase hx)]
  rw [prod_insert has, count_cons_self, count_eq_zero_of_not_mem (mt mem_toFinset.2 has), pow_one]
  congr 1
  refine' prod_congr rfl fun x hx => _
  rw [count_cons_of_ne]
  rintro rfl
  

Proof state:
case neg.e_a.h
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
s : List α
IH : prod (List.map f s) = ∏ m in toFinset s, f m ^ count m s
x : α
hx : x ∈ toFinset s
has : x ∉ toFinset s
⊢ False

Next tactic:
exact has hx
@[to_additive]
theorem prod_list_count [DecidableEq α] [CommMonoid α] (s : List α) :
    s.prod = ∏ m in s.toFinset, m ^ s.count m := by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
s : List α
⊢ prod s = ∏ m in toFinset s, m ^ count m s

Next tactic:
simpa using prod_list_map_count s id
@[to_additive]
theorem prod_list_count_of_subset [DecidableEq α] [CommMonoid α] (m : List α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : List α
s : Finset α
hs : toFinset m ⊆ s
⊢ prod m = ∏ i in s, i ^ count i m

Next tactic:
rw [prod_list_count]
@[to_additive]
theorem prod_list_count_of_subset [DecidableEq α] [CommMonoid α] (m : List α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  rw [prod_list_count]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : List α
s : Finset α
hs : toFinset m ⊆ s
⊢ ∏ m_1 in toFinset m, m_1 ^ count m_1 m = ∏ i in s, i ^ count i m

Next tactic:
refine' prod_subset hs fun x _ hx => _
@[to_additive]
theorem prod_list_count_of_subset [DecidableEq α] [CommMonoid α] (m : List α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  rw [prod_list_count]
  refine' prod_subset hs fun x _ hx => _
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : List α
s : Finset α
hs : toFinset m ⊆ s
x : α
x✝ : x ∈ s
hx : x ∉ toFinset m
⊢ x ^ count x m = 1

Next tactic:
rw [mem_toFinset] at hx
@[to_additive]
theorem prod_list_count_of_subset [DecidableEq α] [CommMonoid α] (m : List α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  rw [prod_list_count]
  refine' prod_subset hs fun x _ hx => _
  rw [mem_toFinset] at hx
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : List α
s : Finset α
hs : toFinset m ⊆ s
x : α
x✝ : x ∈ s
hx : x ∉ m
⊢ x ^ count x m = 1

Next tactic:
rw [count_eq_zero_of_not_mem hx, pow_zero]
theorem sum_filter_count_eq_countP [DecidableEq α] (p : α → Prop) [DecidablePred p] (l : List α) :
    ∑ x in l.toFinset.filter p, l.count x = l.countP p := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
p : α → Prop
inst✝ : DecidablePred p
l : List α
⊢ ∑ x in filter p (toFinset l), count x l = countP (fun b => decide (p b)) l

Next tactic:
simp [Finset.sum, sum_map_count_dedup_filter_eq_countP p l]
@[to_additive]
theorem prod_multiset_map_count [DecidableEq α] (s : Multiset α) {M : Type*} [CommMonoid M]
    (f : α → M) : (s.map f).prod = ∏ m in s.toFinset, f m ^ s.count m := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
s : Multiset α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
⊢ Multiset.prod (Multiset.map f s) = ∏ m in Multiset.toFinset s, f m ^ Multiset.count m s

Next tactic:
refine' Quot.induction_on s fun l => _
@[to_additive]
theorem prod_multiset_map_count [DecidableEq α] (s : Multiset α) {M : Type*} [CommMonoid M]
    (f : α → M) : (s.map f).prod = ∏ m in s.toFinset, f m ^ s.count m := by
  refine' Quot.induction_on s fun l => _
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
s : Multiset α
M : Type u_2
inst✝ : CommMonoid M
f : α → M
l : List α
⊢ Multiset.prod (Multiset.map f (Quot.mk Setoid.r l)) =
    ∏ m in Multiset.toFinset (Quot.mk Setoid.r l), f m ^ Multiset.count m (Quot.mk Setoid.r l)

Next tactic:
simp [prod_list_map_count l f]
@[to_additive]
theorem prod_multiset_count [DecidableEq α] [CommMonoid α] (s : Multiset α) :
    s.prod = ∏ m in s.toFinset, m ^ s.count m := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
s : Multiset α
⊢ Multiset.prod s = ∏ m in Multiset.toFinset s, m ^ Multiset.count m s

Next tactic:
convert prod_multiset_map_count s id
@[to_additive]
theorem prod_multiset_count [DecidableEq α] [CommMonoid α] (s : Multiset α) :
    s.prod = ∏ m in s.toFinset, m ^ s.count m := by
  convert prod_multiset_map_count s id
  

Proof state:
case h.e'_2.h.e'_3
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
s : Multiset α
⊢ s = Multiset.map id s

Next tactic:
rw [Multiset.map_id]
@[to_additive]
theorem prod_multiset_count_of_subset [DecidableEq α] [CommMonoid α] (m : Multiset α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : Multiset α
s : Finset α
hs : Multiset.toFinset m ⊆ s
⊢ Multiset.prod m = ∏ i in s, i ^ Multiset.count i m

Next tactic:
revert hs
@[to_additive]
theorem prod_multiset_count_of_subset [DecidableEq α] [CommMonoid α] (m : Multiset α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  revert hs
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : Multiset α
s : Finset α
⊢ Multiset.toFinset m ⊆ s → Multiset.prod m = ∏ i in s, i ^ Multiset.count i m

Next tactic:
refine' Quot.induction_on m fun l => _
@[to_additive]
theorem prod_multiset_count_of_subset [DecidableEq α] [CommMonoid α] (m : Multiset α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  revert hs
  refine' Quot.induction_on m fun l => _
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : Multiset α
s : Finset α
l : List α
⊢ Multiset.toFinset (Quot.mk Setoid.r l) ⊆ s →
    Multiset.prod (Quot.mk Setoid.r l) = ∏ i in s, i ^ Multiset.count i (Quot.mk Setoid.r l)

Next tactic:
simp only [quot_mk_to_coe'', coe_prod, coe_count]
@[to_additive]
theorem prod_multiset_count_of_subset [DecidableEq α] [CommMonoid α] (m : Multiset α) (s : Finset α)
    (hs : m.toFinset ⊆ s) : m.prod = ∏ i in s, i ^ m.count i := by
  revert hs
  refine' Quot.induction_on m fun l => _
  simp only [quot_mk_to_coe'', coe_prod, coe_count]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoid β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
m : Multiset α
s : Finset α
l : List α
⊢ Multiset.toFinset ↑l ⊆ s → List.prod l = ∏ x in s, x ^ List.count x l

Next tactic:
apply prod_list_count_of_subset l s
@[to_additive]
theorem prod_mem_multiset [DecidableEq α] (m : Multiset α) (f : { x // x ∈ m } → β) (g : α → β)
    (hfg : ∀ x, f x = g x) : ∏ x : { x // x ∈ m }, f x = ∏ x in m.toFinset, g x :=
  prod_bij (fun x _ => x.1) (fun x _ => Multiset.mem_toFinset.mpr x.2) (fun _ _ => hfg _)
    (fun _ _ _ _ h => by
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g✝ : α → β
inst✝¹ : CommMonoid β
inst✝ : DecidableEq α
m : Multiset α
f : { x // x ∈ m } → β
g : α → β
hfg : ∀ (x : { x // x ∈ m }), f x = g ↑x
x✝³ x✝² : { x // x ∈ m }
x✝¹ : x✝³ ∈ univ
x✝ : x✝² ∈ univ
h : (fun x x_1 => ↑x) x✝³ x✝¹ = (fun x x_1 => ↑x) x✝² x✝
⊢ x✝³ = x✝²

Next tactic:
ext
@[to_additive]
theorem prod_mem_multiset [DecidableEq α] (m : Multiset α) (f : { x // x ∈ m } → β) (g : α → β)
    (hfg : ∀ x, f x = g x) : ∏ x : { x // x ∈ m }, f x = ∏ x in m.toFinset, g x :=
  prod_bij (fun x _ => x.1) (fun x _ => Multiset.mem_toFinset.mpr x.2) (fun _ _ => hfg _)
    (fun _ _ _ _ h => by
      ext
      

Proof state:
case a
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g✝ : α → β
inst✝¹ : CommMonoid β
inst✝ : DecidableEq α
m : Multiset α
f : { x // x ∈ m } → β
g : α → β
hfg : ∀ (x : { x // x ∈ m }), f x = g ↑x
x✝³ x✝² : { x // x ∈ m }
x✝¹ : x✝³ ∈ univ
x✝ : x✝² ∈ univ
h : (fun x x_1 => ↑x) x✝³ x✝¹ = (fun x x_1 => ↑x) x✝² x✝
⊢ ↑x✝³ = ↑x✝²

Next tactic:
assumption