l3lab/ntp-mathlib huggingface dataset:
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  

Proof state:
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
i : Finset β
f : β → Multiset α
⊢ Finset.sum i f = Finset.sup i f ↔ ∀ x ∈ i, ∀ y ∈ i, x ≠ y → Disjoint (f x) (f y)

Next tactic:
induction' i using Finset.cons_induction_on with z i hz hr
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  induction' i using Finset.cons_induction_on with z i hz hr
  · 

Proof state:
case h₁
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
f : β → Multiset α
⊢ Finset.sum ∅ f = Finset.sup ∅ f ↔ ∀ x ∈ ∅, ∀ y ∈ ∅, x ≠ y → Disjoint (f x) (f y)

Next tactic:
simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
      Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  induction' i using Finset.cons_induction_on with z i hz hr
  · simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
      Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
  · 

Proof state:
case h₂
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
f : β → Multiset α
z : β
i : Finset β
hz : z ∉ i
hr : Finset.sum i f = Finset.sup i f ↔ ∀ x ∈ i, ∀ y ∈ i, x ≠ y → Disjoint (f x) (f y)
⊢ Finset.sum (Finset.cons z i hz) f = Finset.sup (Finset.cons z i hz) f ↔
    ∀ x ∈ Finset.cons z i hz, ∀ y ∈ Finset.cons z i hz, x ≠ y → Disjoint (f x) (f y)

Next tactic:
simp_rw [Finset.sum_cons hz, Finset.sup_cons, Finset.mem_cons, Multiset.sup_eq_union,
      forall_eq_or_imp, Ne.def, not_true_eq_false, IsEmpty.forall_iff, true_and_iff,
      imp_and, forall_and, ← hr, @eq_comm _ z]
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  induction' i using Finset.cons_induction_on with z i hz hr
  · simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
      Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
  · simp_rw [Finset.sum_cons hz, Finset.sup_cons, Finset.mem_cons, Multiset.sup_eq_union,
      forall_eq_or_imp, Ne.def, not_true_eq_false, IsEmpty.forall_iff, true_and_iff,
      imp_and, forall_and, ← hr, @eq_comm _ z]
    

Proof state:
case h₂
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
f : β → Multiset α
z : β
i : Finset β
hz : z ∉ i
hr : Finset.sum i f = Finset.sup i f ↔ ∀ x ∈ i, ∀ y ∈ i, x ≠ y → Disjoint (f x) (f y)
⊢ f z + ∑ x in i, f x = f z ∪ Finset.sup i f ↔
    (∀ a ∈ i, ¬a = z → Disjoint (f z) (f a)) ∧
      (∀ x ∈ i, ¬x = z → Disjoint (f x) (f z)) ∧ Finset.sum i f = Finset.sup i f

Next tactic:
have := fun x (H : x ∈ i) => ne_of_mem_of_not_mem H hz
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  induction' i using Finset.cons_induction_on with z i hz hr
  · simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
      Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
  · simp_rw [Finset.sum_cons hz, Finset.sup_cons, Finset.mem_cons, Multiset.sup_eq_union,
      forall_eq_or_imp, Ne.def, not_true_eq_false, IsEmpty.forall_iff, true_and_iff,
      imp_and, forall_and, ← hr, @eq_comm _ z]
    have := fun x (H : x ∈ i) => ne_of_mem_of_not_mem H hz
    

Proof state:
case h₂
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
f : β → Multiset α
z : β
i : Finset β
hz : z ∉ i
hr : Finset.sum i f = Finset.sup i f ↔ ∀ x ∈ i, ∀ y ∈ i, x ≠ y → Disjoint (f x) (f y)
this : ∀ x ∈ i, x ≠ z
⊢ f z + ∑ x in i, f x = f z ∪ Finset.sup i f ↔
    (∀ a ∈ i, ¬a = z → Disjoint (f z) (f a)) ∧
      (∀ x ∈ i, ¬x = z → Disjoint (f x) (f z)) ∧ Finset.sum i f = Finset.sup i f

Next tactic:
simp (config := { contextual := true }) only [this, not_false_iff, true_imp_iff]
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  induction' i using Finset.cons_induction_on with z i hz hr
  · simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
      Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
  · simp_rw [Finset.sum_cons hz, Finset.sup_cons, Finset.mem_cons, Multiset.sup_eq_union,
      forall_eq_or_imp, Ne.def, not_true_eq_false, IsEmpty.forall_iff, true_and_iff,
      imp_and, forall_and, ← hr, @eq_comm _ z]
    have := fun x (H : x ∈ i) => ne_of_mem_of_not_mem H hz
    simp (config := { contextual := true }) only [this, not_false_iff, true_imp_iff]
    

Proof state:
case h₂
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
f : β → Multiset α
z : β
i : Finset β
hz : z ∉ i
hr : Finset.sum i f = Finset.sup i f ↔ ∀ x ∈ i, ∀ y ∈ i, x ≠ y → Disjoint (f x) (f y)
this : ∀ x ∈ i, x ≠ z
⊢ f z + ∑ x in i, f x = f z ∪ Finset.sup i f ↔
    (∀ a ∈ i, Disjoint (f z) (f a)) ∧ (∀ x ∈ i, Disjoint (f x) (f z)) ∧ Finset.sum i f = Finset.sup i f

Next tactic:
simp_rw [← disjoint_finset_sum_left, ← disjoint_finset_sum_right, disjoint_comm, ← and_assoc,
      and_self_iff]
theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} :
    i.sum f = i.sup f ↔
      ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by
  induction' i using Finset.cons_induction_on with z i hz hr
  · simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
      Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
  · simp_rw [Finset.sum_cons hz, Finset.sup_cons, Finset.mem_cons, Multiset.sup_eq_union,
      forall_eq_or_imp, Ne.def, not_true_eq_false, IsEmpty.forall_iff, true_and_iff,
      imp_and, forall_and, ← hr, @eq_comm _ z]
    have := fun x (H : x ∈ i) => ne_of_mem_of_not_mem H hz
    simp (config := { contextual := true }) only [this, not_false_iff, true_imp_iff]
    simp_rw [← disjoint_finset_sum_left, ← disjoint_finset_sum_right, disjoint_comm, ← and_assoc,
      and_self_iff]
    

Proof state:
case h₂
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β✝
inst✝ : DecidableEq α
β : Type u_2
f : β → Multiset α
z : β
i : Finset β
hz : z ∉ i
hr : Finset.sum i f = Finset.sup i f ↔ ∀ x ∈ i, ∀ y ∈ i, x ≠ y → Disjoint (f x) (f y)
this : ∀ x ∈ i, x ≠ z
⊢ f z + ∑ x in i, f x = f z ∪ Finset.sup i f ↔ Disjoint (f z) (∑ x in i, f x) ∧ Finset.sum i f = Finset.sup i f

Next tactic:
exact add_eq_union_left_of_le (Finset.sup_le fun x hx => le_sum_of_mem (mem_map_of_mem f hx))
theorem sup_powerset_len {α : Type*} [DecidableEq α] (x : Multiset α) :
    (Finset.sup (Finset.range (card x + 1)) fun k => x.powersetCard k) = x.powerset := by
  

Proof state:
ι : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
inst✝ : DecidableEq α
x : Multiset α
⊢ (Finset.sup (Finset.range (card x + 1)) fun k => powersetCard k x) = powerset x

Next tactic:
convert bind_powerset_len x using 1
theorem sup_powerset_len {α : Type*} [DecidableEq α] (x : Multiset α) :
    (Finset.sup (Finset.range (card x + 1)) fun k => x.powersetCard k) = x.powerset := by
  convert bind_powerset_len x using 1
  

Proof state:
case h.e'_2
ι : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
inst✝ : DecidableEq α
x : Multiset α
⊢ (Finset.sup (Finset.range (card x + 1)) fun k => powersetCard k x) =
    bind (range (card x + 1)) fun k => powersetCard k x

Next tactic:
rw [Multiset.bind, Multiset.join, ← Finset.range_val, ← Finset.sum_eq_multiset_sum]
theorem sup_powerset_len {α : Type*} [DecidableEq α] (x : Multiset α) :
    (Finset.sup (Finset.range (card x + 1)) fun k => x.powersetCard k) = x.powerset := by
  convert bind_powerset_len x using 1
  rw [Multiset.bind, Multiset.join, ← Finset.range_val, ← Finset.sum_eq_multiset_sum]
  

Proof state:
case h.e'_2
ι : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
inst✝ : DecidableEq α
x : Multiset α
⊢ (Finset.sup (Finset.range (card x + 1)) fun k => powersetCard k x) =
    ∑ x_1 in Finset.range (card x + 1), powersetCard x_1 x

Next tactic:
exact
    Eq.symm (finset_sum_eq_sup_iff_disjoint.mpr fun _ _ _ _ h => pairwise_disjoint_powersetCard x h)
@[simp]
theorem toFinset_sum_count_eq (s : Multiset α) : ∑ a in s.toFinset, s.count a = card s :=
  calc
    ∑ a in s.toFinset, s.count a = ∑ a in s.toFinset, s.count a • 1 := by
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
⊢ ∑ a in toFinset s, count a s = ∑ a in toFinset s, count a s • 1

Next tactic:
{ simp only [smul_eq_mul, mul_one] }
@[simp]
theorem toFinset_sum_count_eq (s : Multiset α) : ∑ a in s.toFinset, s.count a = card s :=
  calc
    ∑ a in s.toFinset, s.count a = ∑ a in s.toFinset, s.count a • 1 := by
      { 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
⊢ ∑ a in toFinset s, count a s = ∑ a in toFinset s, count a s • 1

Next tactic:
simp only [smul_eq_mul, mul_one]
@[simp]
theorem toFinset_sum_count_eq (s : Multiset α) : ∑ a in s.toFinset, s.count a = card s :=
  calc
    ∑ a in s.toFinset, s.count a = ∑ a in s.toFinset, s.count a • 1 := by
      { simp only [smul_eq_mul, mul_one] }
    _ = (s.map fun _ => 1).sum := (Finset.sum_multiset_map_count _ _).symm
    _ = card s := by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
⊢ sum (map (fun x => 1) s) = card s

Next tactic:
simp
theorem count_sum' {s : Finset β} {a : α} {f : β → Multiset α} :
    count a (∑ x in s, f x) = ∑ x in s, count a (f x) := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : DecidableEq α
s : Finset β
a : α
f : β → Multiset α
⊢ count a (∑ x in s, f x) = ∑ x in s, count a (f x)

Next tactic:
dsimp only [Finset.sum]
theorem count_sum' {s : Finset β} {a : α} {f : β → Multiset α} :
    count a (∑ x in s, f x) = ∑ x in s, count a (f x) := by
  dsimp only [Finset.sum]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : DecidableEq α
s : Finset β
a : α
f : β → Multiset α
⊢ count a (sum (map (fun x => f x) s.val)) = sum (map (fun x => count a (f x)) s.val)

Next tactic:
rw [count_sum]
@[simp]
theorem toFinset_sum_count_nsmul_eq (s : Multiset α) :
    ∑ a in s.toFinset, s.count a • {a} = s := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
⊢ ∑ a in toFinset s, count a s • {a} = s

Next tactic:
rw [← Finset.sum_multiset_map_count, Multiset.sum_map_singleton]
theorem exists_smul_of_dvd_count (s : Multiset α) {k : ℕ}
    (h : ∀ a : α, a ∈ s → k ∣ Multiset.count a s) : ∃ u : Multiset α, s = k • u := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
k : ℕ
h : ∀ a ∈ s, k ∣ count a s
⊢ ∃ u, s = k • u

Next tactic:
use ∑ a in s.toFinset, (s.count a / k) • {a}
theorem exists_smul_of_dvd_count (s : Multiset α) {k : ℕ}
    (h : ∀ a : α, a ∈ s → k ∣ Multiset.count a s) : ∃ u : Multiset α, s = k • u := by
  use ∑ a in s.toFinset, (s.count a / k) • {a}
  

Proof state:
case h
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
k : ℕ
h : ∀ a ∈ s, k ∣ count a s
⊢ s = k • ∑ a in toFinset s, (count a s / k) • {a}

Next tactic:
have h₂ :
    (∑ x : α in s.toFinset, k • (count x s / k) • ({x} : Multiset α)) =
      ∑ x : α in s.toFinset, count x s • {x} := by
    apply Finset.sum_congr rfl
    intro x hx
    rw [← mul_nsmul', Nat.mul_div_cancel' (h x (mem_toFinset.mp hx))]
theorem exists_smul_of_dvd_count (s : Multiset α) {k : ℕ}
    (h : ∀ a : α, a ∈ s → k ∣ Multiset.count a s) : ∃ u : Multiset α, s = k • u := by
  use ∑ a in s.toFinset, (s.count a / k) • {a}
  have h₂ :
    (∑ x : α in s.toFinset, k • (count x s / k) • ({x} : Multiset α)) =
      ∑ x : α in s.toFinset, count x s • {x} := by
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
k : ℕ
h : ∀ a ∈ s, k ∣ count a s
⊢ ∑ x in toFinset s, k • (count x s / k) • {x} = ∑ x in toFinset s, count x s • {x}

Next tactic:
apply Finset.sum_congr rfl
theorem exists_smul_of_dvd_count (s : Multiset α) {k : ℕ}
    (h : ∀ a : α, a ∈ s → k ∣ Multiset.count a s) : ∃ u : Multiset α, s = k • u := by
  use ∑ a in s.toFinset, (s.count a / k) • {a}
  have h₂ :
    (∑ x : α in s.toFinset, k • (count x s / k) • ({x} : Multiset α)) =
      ∑ x : α in s.toFinset, count x s • {x} := by
    apply Finset.sum_congr rfl
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
k : ℕ
h : ∀ a ∈ s, k ∣ count a s
⊢ ∀ x ∈ toFinset s, k • (count x s / k) • {x} = count x s • {x}

Next tactic:
intro x hx
theorem exists_smul_of_dvd_count (s : Multiset α) {k : ℕ}
    (h : ∀ a : α, a ∈ s → k ∣ Multiset.count a s) : ∃ u : Multiset α, s = k • u := by
  use ∑ a in s.toFinset, (s.count a / k) • {a}
  have h₂ :
    (∑ x : α in s.toFinset, k • (count x s / k) • ({x} : Multiset α)) =
      ∑ x : α in s.toFinset, count x s • {x} := by
    apply Finset.sum_congr rfl
    intro x hx
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
k : ℕ
h : ∀ a ∈ s, k ∣ count a s
x : α
hx : x ∈ toFinset s
⊢ k • (count x s / k) • {x} = count x s • {x}

Next tactic:
rw [← mul_nsmul', Nat.mul_div_cancel' (h x (mem_toFinset.mp hx))]
theorem exists_smul_of_dvd_count (s : Multiset α) {k : ℕ}
    (h : ∀ a : α, a ∈ s → k ∣ Multiset.count a s) : ∃ u : Multiset α, s = k • u := by
  use ∑ a in s.toFinset, (s.count a / k) • {a}
  have h₂ :
    (∑ x : α in s.toFinset, k • (count x s / k) • ({x} : Multiset α)) =
      ∑ x : α in s.toFinset, count x s • {x} := by
    apply Finset.sum_congr rfl
    intro x hx
    rw [← mul_nsmul', Nat.mul_div_cancel' (h x (mem_toFinset.mp hx))]
  

Proof state:
case h
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
s : Multiset α
k : ℕ
h : ∀ a ∈ s, k ∣ count a s
h₂ : ∑ x in toFinset s, k • (count x s / k) • {x} = ∑ x in toFinset s, count x s • {x}
⊢ s = k • ∑ a in toFinset s, (count a s / k) • {a}

Next tactic:
rw [← Finset.sum_nsmul, h₂, toFinset_sum_count_nsmul_eq]
theorem toFinset_prod_dvd_prod [CommMonoid α] (S : Multiset α) : S.toFinset.prod id ∣ S.prod := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
S : Multiset α
⊢ Finset.prod (toFinset S) id ∣ prod S

Next tactic:
rw [Finset.prod_eq_multiset_prod]
theorem toFinset_prod_dvd_prod [CommMonoid α] (S : Multiset α) : S.toFinset.prod id ∣ S.prod := by
  rw [Finset.prod_eq_multiset_prod]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
S : Multiset α
⊢ prod (map (fun x => id x) (toFinset S).val) ∣ prod S

Next tactic:
refine' Multiset.prod_dvd_prod_of_le _
theorem toFinset_prod_dvd_prod [CommMonoid α] (S : Multiset α) : S.toFinset.prod id ∣ S.prod := by
  rw [Finset.prod_eq_multiset_prod]
  refine' Multiset.prod_dvd_prod_of_le _
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : DecidableEq α
inst✝ : CommMonoid α
S : Multiset α
⊢ map (fun x => id x) (toFinset S).val ≤ S

Next tactic:
simp [Multiset.dedup_le S]
@[to_additive]
theorem prod_sum {α : Type*} {ι : Type*} [CommMonoid α] (f : ι → Multiset α) (s : Finset ι) :
    (∑ x in s, f x).prod = ∏ x in s, (f x).prod := by
  

Proof state:
ι✝ : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
ι : Type u_3
inst✝ : CommMonoid α
f : ι → Multiset α
s : Finset ι
⊢ prod (∑ x in s, f x) = ∏ x in s, prod (f x)

Next tactic:
classical
    induction' s using Finset.induction_on with a t hat ih
    · rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero]
    · rw [Finset.sum_insert hat, Finset.prod_insert hat, Multiset.prod_add, ih]
@[to_additive]
theorem prod_sum {α : Type*} {ι : Type*} [CommMonoid α] (f : ι → Multiset α) (s : Finset ι) :
    (∑ x in s, f x).prod = ∏ x in s, (f x).prod := by
  classical
    

Proof state:
ι✝ : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
ι : Type u_3
inst✝ : CommMonoid α
f : ι → Multiset α
s : Finset ι
⊢ prod (∑ x in s, f x) = ∏ x in s, prod (f x)

Next tactic:
induction' s using Finset.induction_on with a t hat ih
@[to_additive]
theorem prod_sum {α : Type*} {ι : Type*} [CommMonoid α] (f : ι → Multiset α) (s : Finset ι) :
    (∑ x in s, f x).prod = ∏ x in s, (f x).prod := by
  classical
    induction' s using Finset.induction_on with a t hat ih
    · 

Proof state:
case empty
ι✝ : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
ι : Type u_3
inst✝ : CommMonoid α
f : ι → Multiset α
⊢ prod (∑ x in ∅, f x) = ∏ x in ∅, prod (f x)

Next tactic:
rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero]
@[to_additive]
theorem prod_sum {α : Type*} {ι : Type*} [CommMonoid α] (f : ι → Multiset α) (s : Finset ι) :
    (∑ x in s, f x).prod = ∏ x in s, (f x).prod := by
  classical
    induction' s using Finset.induction_on with a t hat ih
    · rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero]
    · 

Proof state:
case insert
ι✝ : Type u_1
β : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a✝ : α✝
f✝ g : α✝ → β
inst✝¹ : DecidableEq α✝
α : Type u_2
ι : Type u_3
inst✝ : CommMonoid α
f : ι → Multiset α
a : ι
t : Finset ι
hat : a ∉ t
ih : prod (∑ x in t, f x) = ∏ x in t, prod (f x)
⊢ prod (∑ x in insert a t, f x) = ∏ x in insert a t, prod (f x)

Next tactic:
rw [Finset.sum_insert hat, Finset.prod_insert hat, Multiset.prod_add, ih]
theorem Units.mk0_prod [CommGroupWithZero β] (s : Finset α) (f : α → β) (h) :
    Units.mk0 (∏ b in s, f b) h =
      ∏ b in s.attach, Units.mk0 (f b) fun hh => h (Finset.prod_eq_zero b.2 hh) := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommGroupWithZero β
s : Finset α
f : α → β
h : ∏ b in s, f b ≠ 0
⊢ mk0 (∏ b in s, f b) h = ∏ b in Finset.attach s, mk0 (f ↑b) (_ : f ↑b = 0 → False)

Next tactic:
classical induction s using Finset.induction_on <;> simp [*]
theorem Units.mk0_prod [CommGroupWithZero β] (s : Finset α) (f : α → β) (h) :
    Units.mk0 (∏ b in s, f b) h =
      ∏ b in s.attach, Units.mk0 (f b) fun hh => h (Finset.prod_eq_zero b.2 hh) := by
  classical 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommGroupWithZero β
s : Finset α
f : α → β
h : ∏ b in s, f b ≠ 0
⊢ mk0 (∏ b in s, f b) h = ∏ b in Finset.attach s, mk0 (f ↑b) (_ : f ↑b = 0 → False)

Next tactic:
induction s using Finset.induction_on
theorem Units.mk0_prod [CommGroupWithZero β] (s : Finset α) (f : α → β) (h) :
    Units.mk0 (∏ b in s, f b) h =
      ∏ b in s.attach, Units.mk0 (f b) fun hh => h (Finset.prod_eq_zero b.2 hh) := by
  classical induction s using Finset.induction_on <;> 

Proof state:
case empty
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommGroupWithZero β
f : α → β
h : ∏ b in ∅, f b ≠ 0
⊢ mk0 (∏ b in ∅, f b) h = ∏ b in Finset.attach ∅, mk0 (f ↑b) (_ : f ↑b = 0 → False)

Next tactic:
simp [*]
theorem Units.mk0_prod [CommGroupWithZero β] (s : Finset α) (f : α → β) (h) :
    Units.mk0 (∏ b in s, f b) h =
      ∏ b in s.attach, Units.mk0 (f b) fun hh => h (Finset.prod_eq_zero b.2 hh) := by
  classical induction s using Finset.induction_on <;> 

Proof state:
case insert
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommGroupWithZero β
f : α → β
a✝² : α
s✝ : Finset α
a✝¹ : a✝² ∉ s✝
a✝ : ∀ (h : ∏ b in s✝, f b ≠ 0), mk0 (∏ b in s✝, f b) h = ∏ b in Finset.attach s✝, mk0 (f ↑b) (_ : f ↑b = 0 → False)
h : ∏ b in insert a✝² s✝, f b ≠ 0
⊢ mk0 (∏ b in insert a✝² s✝, f b) h = ∏ b in Finset.attach (insert a✝² s✝), mk0 (f ↑b) (_ : f ↑b = 0 → False)

Next tactic:
simp [*]
theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) :
    (∑ i in s, f i).natAbs ≤ ∑ i in s, (f i).natAbs := by
  

Proof state:
ι✝ : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
ι : Type u_2
s : Finset ι
f : ι → ℤ
⊢ Int.natAbs (∑ i in s, f i) ≤ ∑ i in s, Int.natAbs (f i)

Next tactic:
classical
    induction' s using Finset.induction_on with i s his IH
    · simp only [Finset.sum_empty, Int.natAbs_zero, le_refl]
    · simp only [his, Finset.sum_insert, not_false_iff]
      exact (Int.natAbs_add_le _ _).trans (add_le_add le_rfl IH)
theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) :
    (∑ i in s, f i).natAbs ≤ ∑ i in s, (f i).natAbs := by
  classical
    

Proof state:
ι✝ : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
ι : Type u_2
s : Finset ι
f : ι → ℤ
⊢ Int.natAbs (∑ i in s, f i) ≤ ∑ i in s, Int.natAbs (f i)

Next tactic:
induction' s using Finset.induction_on with i s his IH
theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) :
    (∑ i in s, f i).natAbs ≤ ∑ i in s, (f i).natAbs := by
  classical
    induction' s using Finset.induction_on with i s his IH
    · 

Proof state:
case empty
ι✝ : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
ι : Type u_2
f : ι → ℤ
⊢ Int.natAbs (∑ i in ∅, f i) ≤ ∑ i in ∅, Int.natAbs (f i)

Next tactic:
simp only [Finset.sum_empty, Int.natAbs_zero, le_refl]
theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) :
    (∑ i in s, f i).natAbs ≤ ∑ i in s, (f i).natAbs := by
  classical
    induction' s using Finset.induction_on with i s his IH
    · simp only [Finset.sum_empty, Int.natAbs_zero, le_refl]
    · 

Proof state:
case insert
ι✝ : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
ι : Type u_2
f : ι → ℤ
i : ι
s : Finset ι
his : i ∉ s
IH : Int.natAbs (∑ i in s, f i) ≤ ∑ i in s, Int.natAbs (f i)
⊢ Int.natAbs (∑ i in insert i s, f i) ≤ ∑ i in insert i s, Int.natAbs (f i)

Next tactic:
simp only [his, Finset.sum_insert, not_false_iff]
theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) :
    (∑ i in s, f i).natAbs ≤ ∑ i in s, (f i).natAbs := by
  classical
    induction' s using Finset.induction_on with i s his IH
    · simp only [Finset.sum_empty, Int.natAbs_zero, le_refl]
    · simp only [his, Finset.sum_insert, not_false_iff]
      

Proof state:
case insert
ι✝ : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
ι : Type u_2
f : ι → ℤ
i : ι
s : Finset ι
his : i ∉ s
IH : Int.natAbs (∑ i in s, f i) ≤ ∑ i in s, Int.natAbs (f i)
⊢ Int.natAbs (f i + ∑ i in s, f i) ≤ Int.natAbs (f i) + ∑ i in s, Int.natAbs (f i)

Next tactic:
exact (Int.natAbs_add_le _ _).trans (add_le_add le_rfl IH)