l3lab/ntp-mathlib huggingface dataset:
theorem prod_eq_zero_iff : ∏ x in s, f x = 0 ↔ ∃ a ∈ s, f a = 0 := by
  classical
    induction' s using Finset.induction_on with a s ha ih
    · 

Proof state:
case empty
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
⊢ ∏ x in ∅, f x = 0 ↔ ∃ a ∈ ∅, f a = 0

Next tactic:
exact ⟨Not.elim one_ne_zero, fun ⟨_, H, _⟩ => by simp at H⟩
theorem prod_eq_zero_iff : ∏ x in s, f x = 0 ↔ ∃ a ∈ s, f a = 0 := by
  classical
    induction' s using Finset.induction_on with a s ha ih
    · exact ⟨Not.elim one_ne_zero, fun ⟨_, H, _⟩ => by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
x✝ : ∃ a ∈ ∅, f a = 0
w✝ : α
H : w✝ ∈ ∅
right✝ : f w✝ = 0
⊢ ∏ x in ∅, f x = 0

Next tactic:
simp at H
theorem prod_eq_zero_iff : ∏ x in s, f x = 0 ↔ ∃ a ∈ s, f a = 0 := by
  classical
    induction' s using Finset.induction_on with a s ha ih
    · exact ⟨Not.elim one_ne_zero, fun ⟨_, H, _⟩ => by simp at H⟩
    · 

Proof state:
case insert
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
a : α
s : Finset α
ha : a ∉ s
ih : ∏ x in s, f x = 0 ↔ ∃ a ∈ s, f a = 0
⊢ ∏ x in insert a s, f x = 0 ↔ ∃ a_1 ∈ insert a s, f a_1 = 0

Next tactic:
rw [prod_insert ha, mul_eq_zero, exists_mem_insert, ih, ← bex_def]
theorem prod_ne_zero_iff : ∏ x in s, f x ≠ 0 ↔ ∀ a ∈ s, f a ≠ 0 := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
⊢ ∏ x in s, f x ≠ 0 ↔ ∀ a ∈ s, f a ≠ 0

Next tactic:
rw [Ne, prod_eq_zero_iff]
theorem prod_ne_zero_iff : ∏ x in s, f x ≠ 0 ↔ ∀ a ∈ s, f a ≠ 0 := by
  rw [Ne, prod_eq_zero_iff]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
⊢ (¬∃ a ∈ s, f a = 0) ↔ ∀ a ∈ s, f a ≠ 0

Next tactic:
push_neg
theorem prod_ne_zero_iff : ∏ x in s, f x ≠ 0 ↔ ∀ a ∈ s, f a ≠ 0 := by
  rw [Ne, prod_eq_zero_iff]
  push_neg; 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
⊢ (∀ a ∈ s, f a ≠ 0) ↔ ∀ a ∈ s, f a ≠ 0

Next tactic:
rfl
lemma support_prod (s : Finset ι) (f : ι → α → β) :
    support (fun x ↦ ∏ i in s, f i x) = ⋂ i ∈ s, support (f i) :=
  Set.ext fun x ↦ by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝² : CommMonoidWithZero β
inst✝¹ : Nontrivial β
inst✝ : NoZeroDivisors β
s : Finset ι
f : ι → α → β
x : α
⊢ (x ∈ support fun x => ∏ i in s, f i x) ↔ x ∈ ⋂ i ∈ s, support (f i)

Next tactic:
simp [support, prod_eq_zero_iff]
@[to_additive]
theorem prod_unique_nonempty {α β : Type*} [CommMonoid β] [Unique α] (s : Finset α) (f : α → β)
    (h : s.Nonempty) : ∏ x in s, f x = f default := by
  

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝¹ : CommMonoid β
inst✝ : Unique α
s : Finset α
f : α → β
h : Finset.Nonempty s
⊢ ∏ x in s, f x = f default

Next tactic:
rw [h.eq_singleton_default, Finset.prod_singleton]
theorem sum_nat_mod (s : Finset α) (n : ℕ) (f : α → ℕ) :
    (∑ i in s, f i) % n = (∑ i in s, f i % n) % n :=
  (Multiset.sum_nat_mod _ _).trans <| by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
s : Finset α
n : ℕ
f : α → ℕ
⊢ Multiset.sum (Multiset.map (fun x => x % n) (Multiset.map (fun i => f i) s.val)) % n = (∑ i in s, f i % n) % n

Next tactic:
rw [Finset.sum, Multiset.map_map]
theorem sum_nat_mod (s : Finset α) (n : ℕ) (f : α → ℕ) :
    (∑ i in s, f i) % n = (∑ i in s, f i % n) % n :=
  (Multiset.sum_nat_mod _ _).trans <| by rw [Finset.sum, Multiset.map_map]; 

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

Next tactic:
rfl
theorem prod_nat_mod (s : Finset α) (n : ℕ) (f : α → ℕ) :
    (∏ i in s, f i) % n = (∏ i in s, f i % n) % n :=
  (Multiset.prod_nat_mod _ _).trans <| by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
s : Finset α
n : ℕ
f : α → ℕ
⊢ Multiset.prod (Multiset.map (fun x => x % n) (Multiset.map (fun i => f i) s.val)) % n = (∏ i in s, f i % n) % n

Next tactic:
rw [Finset.prod, Multiset.map_map]
theorem prod_nat_mod (s : Finset α) (n : ℕ) (f : α → ℕ) :
    (∏ i in s, f i) % n = (∏ i in s, f i % n) % n :=
  (Multiset.prod_nat_mod _ _).trans <| by rw [Finset.prod, Multiset.map_map]; 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
s : Finset α
n : ℕ
f : α → ℕ
⊢ Multiset.prod (Multiset.map ((fun x => x % n) ∘ fun i => f i) s.val) % n =
    Multiset.prod (Multiset.map (fun i => f i % n) s.val) % n

Next tactic:
rfl
theorem sum_int_mod (s : Finset α) (n : ℤ) (f : α → ℤ) :
    (∑ i in s, f i) % n = (∑ i in s, f i % n) % n :=
  (Multiset.sum_int_mod _ _).trans <| by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
s : Finset α
n : ℤ
f : α → ℤ
⊢ Multiset.sum (Multiset.map (fun x => x % n) (Multiset.map (fun i => f i) s.val)) % n = (∑ i in s, f i % n) % n

Next tactic:
rw [Finset.sum, Multiset.map_map]
theorem sum_int_mod (s : Finset α) (n : ℤ) (f : α → ℤ) :
    (∑ i in s, f i) % n = (∑ i in s, f i % n) % n :=
  (Multiset.sum_int_mod _ _).trans <| by rw [Finset.sum, Multiset.map_map]; 

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

Next tactic:
rfl
theorem prod_int_mod (s : Finset α) (n : ℤ) (f : α → ℤ) :
    (∏ i in s, f i) % n = (∏ i in s, f i % n) % n :=
  (Multiset.prod_int_mod _ _).trans <| by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
s : Finset α
n : ℤ
f : α → ℤ
⊢ Multiset.prod (Multiset.map (fun x => x % n) (Multiset.map (fun i => f i) s.val)) % n = (∏ i in s, f i % n) % n

Next tactic:
rw [Finset.prod, Multiset.map_map]
theorem prod_int_mod (s : Finset α) (n : ℤ) (f : α → ℤ) :
    (∏ i in s, f i) % n = (∏ i in s, f i % n) % n :=
  (Multiset.prod_int_mod _ _).trans <| by rw [Finset.prod, Multiset.map_map]; 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
s : Finset α
n : ℤ
f : α → ℤ
⊢ Multiset.prod (Multiset.map ((fun x => x % n) ∘ fun i => f i) s.val) % n =
    Multiset.prod (Multiset.map (fun i => f i % n) s.val) % n

Next tactic:
rfl
@[to_additive]
theorem prod_unique {α β : Type*} [CommMonoid β] [Unique α] [Fintype α] (f : α → β) :
    ∏ x : α, f x = f default := by 

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : CommMonoid β
inst✝¹ : Unique α
inst✝ : Fintype α
f : α → β
⊢ ∏ x : α, f x = f default

Next tactic:
rw [univ_unique, prod_singleton]
@[to_additive]
theorem prod_subsingleton {α β : Type*} [CommMonoid β] [Subsingleton α] [Fintype α] (f : α → β)
    (a : α) : ∏ x : α, f x = f a := by
  

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a✝ : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : CommMonoid β
inst✝¹ : Subsingleton α
inst✝ : Fintype α
f : α → β
a : α
⊢ ∏ x : α, f x = f a

Next tactic:
haveI : Unique α := uniqueOfSubsingleton a
@[to_additive]
theorem prod_subsingleton {α β : Type*} [CommMonoid β] [Subsingleton α] [Fintype α] (f : α → β)
    (a : α) : ∏ x : α, f x = f a := by
  haveI : Unique α := uniqueOfSubsingleton a
  

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a✝ : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : CommMonoid β
inst✝¹ : Subsingleton α
inst✝ : Fintype α
f : α → β
a : α
this : Unique α
⊢ ∏ x : α, f x = f a

Next tactic:
rw [prod_unique f, Subsingleton.elim default a]
@[to_additive]
theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid β] (p : α → Prop)
    (f : α → β) [DecidablePred p] :
    (∏ i : { x // p x }, f i) * ∏ i : { x // ¬p x }, f i = ∏ i, f i := by
  

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : Fintype α
inst✝¹ : CommMonoid β
p : α → Prop
f : α → β
inst✝ : DecidablePred p
⊢ (∏ i : { x // p x }, f ↑i) * ∏ i : { x // ¬p x }, f ↑i = ∏ i : α, f i

Next tactic:
classical
    let s := { x | p x }.toFinset
    rw [← Finset.prod_subtype s, ← Finset.prod_subtype sᶜ]
    · exact Finset.prod_mul_prod_compl _ _
    · simp
    · simp
@[to_additive]
theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid β] (p : α → Prop)
    (f : α → β) [DecidablePred p] :
    (∏ i : { x // p x }, f i) * ∏ i : { x // ¬p x }, f i = ∏ i, f i := by
  classical
    

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : Fintype α
inst✝¹ : CommMonoid β
p : α → Prop
f : α → β
inst✝ : DecidablePred p
⊢ (∏ i : { x // p x }, f ↑i) * ∏ i : { x // ¬p x }, f ↑i = ∏ i : α, f i

Next tactic:
let s := { x | p x }.toFinset
@[to_additive]
theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid β] (p : α → Prop)
    (f : α → β) [DecidablePred p] :
    (∏ i : { x // p x }, f i) * ∏ i : { x // ¬p x }, f i = ∏ i, f i := by
  classical
    let s := { x | p x }.toFinset
    

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : Fintype α
inst✝¹ : CommMonoid β
p : α → Prop
f : α → β
inst✝ : DecidablePred p
s : Finset α := Set.toFinset {x | p x}
⊢ (∏ i : { x // p x }, f ↑i) * ∏ i : { x // ¬p x }, f ↑i = ∏ i : α, f i

Next tactic:
rw [← Finset.prod_subtype s, ← Finset.prod_subtype sᶜ]
@[to_additive]
theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid β] (p : α → Prop)
    (f : α → β) [DecidablePred p] :
    (∏ i : { x // p x }, f i) * ∏ i : { x // ¬p x }, f i = ∏ i, f i := by
  classical
    let s := { x | p x }.toFinset
    rw [← Finset.prod_subtype s, ← Finset.prod_subtype sᶜ]
    · 

Proof state:
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : Fintype α
inst✝¹ : CommMonoid β
p : α → Prop
f : α → β
inst✝ : DecidablePred p
s : Finset α := Set.toFinset {x | p x}
⊢ (∏ a in s, f a) * ∏ a in sᶜ, f a = ∏ i : α, f i

Next tactic:
exact Finset.prod_mul_prod_compl _ _
@[to_additive]
theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid β] (p : α → Prop)
    (f : α → β) [DecidablePred p] :
    (∏ i : { x // p x }, f i) * ∏ i : { x // ¬p x }, f i = ∏ i, f i := by
  classical
    let s := { x | p x }.toFinset
    rw [← Finset.prod_subtype s, ← Finset.prod_subtype sᶜ]
    · exact Finset.prod_mul_prod_compl _ _
    · 

Proof state:
case h
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : Fintype α
inst✝¹ : CommMonoid β
p : α → Prop
f : α → β
inst✝ : DecidablePred p
s : Finset α := Set.toFinset {x | p x}
⊢ ∀ (x : α), x ∈ sᶜ ↔ ¬p x

Next tactic:
simp
@[to_additive]
theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid β] (p : α → Prop)
    (f : α → β) [DecidablePred p] :
    (∏ i : { x // p x }, f i) * ∏ i : { x // ¬p x }, f i = ∏ i, f i := by
  classical
    let s := { x | p x }.toFinset
    rw [← Finset.prod_subtype s, ← Finset.prod_subtype sᶜ]
    · exact Finset.prod_mul_prod_compl _ _
    · simp
    · 

Proof state:
case h
ι : Type u_1
β✝ : Type u
α✝ : Type v
γ : Type w
s✝ s₁ s₂ : Finset α✝
a : α✝
f✝ g : α✝ → β✝
α : Type u_2
β : Type u_3
inst✝² : Fintype α
inst✝¹ : CommMonoid β
p : α → Prop
f : α → β
inst✝ : DecidablePred p
s : Finset α := Set.toFinset {x | p x}
⊢ ∀ (x : α), x ∈ s ↔ p x

Next tactic:
simp
@[to_additive]
theorem prod_toFinset {M : Type*} [DecidableEq α] [CommMonoid M] (f : α → M) :
    ∀ {l : List α} (_hl : l.Nodup), l.toFinset.prod f = (l.map f).prod
  | [], _ => by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
M : Type u_2
inst✝¹ : DecidableEq α
inst✝ : CommMonoid M
f : α → M
x✝ : Nodup []
⊢ Finset.prod (toFinset []) f = prod (map f [])

Next tactic:
simp
@[to_additive]
theorem prod_toFinset {M : Type*} [DecidableEq α] [CommMonoid M] (f : α → M) :
    ∀ {l : List α} (_hl : l.Nodup), l.toFinset.prod f = (l.map f).prod
  | [], _ => by simp
  | a :: l, hl => by
    

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

Next tactic:
let ⟨not_mem, hl⟩ := List.nodup_cons.mp hl
@[to_additive]
theorem prod_toFinset {M : Type*} [DecidableEq α] [CommMonoid M] (f : α → M) :
    ∀ {l : List α} (_hl : l.Nodup), l.toFinset.prod f = (l.map f).prod
  | [], _ => by simp
  | a :: l, hl => by
    let ⟨not_mem, hl⟩ := List.nodup_cons.mp hl
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
M : Type u_2
inst✝¹ : DecidableEq α
inst✝ : CommMonoid M
f : α → M
a : α
l : List α
hl✝ : Nodup (a :: l)
not_mem : a ∉ l
hl : Nodup l
⊢ Finset.prod (toFinset (a :: l)) f = prod (map f (a :: l))

Next tactic:
simp [Finset.prod_insert (mt List.mem_toFinset.mp not_mem), prod_toFinset _ hl]
theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} :
    Multiset.Disjoint l.sum a ↔ ∀ b ∈ l, Multiset.Disjoint b a := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a : Multiset α
l : List (Multiset α)
⊢ Disjoint (List.sum l) a ↔ ∀ b ∈ l, Disjoint b a

Next tactic:
induction' l with b bs ih
theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} :
    Multiset.Disjoint l.sum a ↔ ∀ b ∈ l, Multiset.Disjoint b a := by
  induction' l with b bs ih
  · 

Proof state:
case nil
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a : Multiset α
⊢ Disjoint (List.sum []) a ↔ ∀ b ∈ [], Disjoint b a

Next tactic:
simp only [zero_disjoint, List.not_mem_nil, IsEmpty.forall_iff, forall_const, List.sum_nil]
theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} :
    Multiset.Disjoint l.sum a ↔ ∀ b ∈ l, Multiset.Disjoint b a := by
  induction' l with b bs ih
  · simp only [zero_disjoint, List.not_mem_nil, IsEmpty.forall_iff, forall_const, List.sum_nil]
  · 

Proof state:
case cons
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a b : Multiset α
bs : List (Multiset α)
ih : Disjoint (List.sum bs) a ↔ ∀ b ∈ bs, Disjoint b a
⊢ Disjoint (List.sum (b :: bs)) a ↔ ∀ b_1 ∈ b :: bs, Disjoint b_1 a

Next tactic:
simp_rw [List.sum_cons, disjoint_add_left, List.mem_cons, forall_eq_or_imp]
theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} :
    Multiset.Disjoint l.sum a ↔ ∀ b ∈ l, Multiset.Disjoint b a := by
  induction' l with b bs ih
  · simp only [zero_disjoint, List.not_mem_nil, IsEmpty.forall_iff, forall_const, List.sum_nil]
  · simp_rw [List.sum_cons, disjoint_add_left, List.mem_cons, forall_eq_or_imp]
    

Proof state:
case cons
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a b : Multiset α
bs : List (Multiset α)
ih : Disjoint (List.sum bs) a ↔ ∀ b ∈ bs, Disjoint b a
⊢ Disjoint b a ∧ Disjoint (List.sum bs) a ↔ Disjoint b a ∧ ∀ a_1 ∈ bs, Disjoint a_1 a

Next tactic:
simp [and_congr_left_iff, iff_self_iff, ih]
theorem disjoint_list_sum_right {a : Multiset α} {l : List (Multiset α)} :
    Multiset.Disjoint a l.sum ↔ ∀ b ∈ l, Multiset.Disjoint a b := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a : Multiset α
l : List (Multiset α)
⊢ Disjoint a (List.sum l) ↔ ∀ b ∈ l, Disjoint a b

Next tactic:
simpa only [@disjoint_comm _ a] using disjoint_list_sum_left
theorem disjoint_sum_left {a : Multiset α} {i : Multiset (Multiset α)} :
    Multiset.Disjoint i.sum a ↔ ∀ b ∈ i, Multiset.Disjoint b a :=
  Quotient.inductionOn i fun l => by
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a : Multiset α
i : Multiset (Multiset α)
l : List (Multiset α)
⊢ Disjoint (sum ⟦l⟧) a ↔ ∀ b ∈ ⟦l⟧, Disjoint b a

Next tactic:
rw [quot_mk_to_coe, Multiset.coe_sum]
theorem disjoint_sum_left {a : Multiset α} {i : Multiset (Multiset α)} :
    Multiset.Disjoint i.sum a ↔ ∀ b ∈ i, Multiset.Disjoint b a :=
  Quotient.inductionOn i fun l => by
    rw [quot_mk_to_coe, Multiset.coe_sum]
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a : Multiset α
i : Multiset (Multiset α)
l : List (Multiset α)
⊢ Disjoint (List.sum l) a ↔ ∀ b ∈ ↑l, Disjoint b a

Next tactic:
exact disjoint_list_sum_left
theorem disjoint_sum_right {a : Multiset α} {i : Multiset (Multiset α)} :
    Multiset.Disjoint a i.sum ↔ ∀ b ∈ i, Multiset.Disjoint a b := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f g : α → β
a : Multiset α
i : Multiset (Multiset α)
⊢ Disjoint a (sum i) ↔ ∀ b ∈ i, Disjoint a b

Next tactic:
simpa only [@disjoint_comm _ a] using disjoint_sum_left
theorem disjoint_finset_sum_left {β : Type*} {i : Finset β} {f : β → Multiset α} {a : Multiset α} :
    Multiset.Disjoint (i.sum f) a ↔ ∀ b ∈ i, Multiset.Disjoint (f b) a := by
  

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

Next tactic:
convert @disjoint_sum_left _ a (map f i.val)
theorem disjoint_finset_sum_left {β : Type*} {i : Finset β} {f : β → Multiset α} {a : Multiset α} :
    Multiset.Disjoint (i.sum f) a ↔ ∀ b ∈ i, Multiset.Disjoint (f b) a := by
  convert @disjoint_sum_left _ a (map f i.val)
  

Proof state:
case h.e'_2.a
ι : Type u_1
β✝ : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β✝
β : Type u_2
i : Finset β
f : β → Multiset α
a : Multiset α
⊢ (∀ b ∈ i, Disjoint (f b) a) ↔ ∀ b ∈ map f i.val, Disjoint b a

Next tactic:
simp [and_congr_left_iff, iff_self_iff]
theorem disjoint_finset_sum_right {β : Type*} {i : Finset β} {f : β → Multiset α}
    {a : Multiset α} : Multiset.Disjoint a (i.sum f) ↔ ∀ b ∈ i, Multiset.Disjoint a (f b) := by
  

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

Next tactic:
simpa only [disjoint_comm] using disjoint_finset_sum_left
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
⊢ z + x = z ∪ y ↔ Disjoint z x ∧ x = y

Next tactic:
rw [← add_eq_union_iff_disjoint]
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
⊢ z + x = z ∪ y ↔ z + x = z ∪ x ∧ x = y

Next tactic:
constructor
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · 

Proof state:
case mp
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
⊢ z + x = z ∪ y → z + x = z ∪ x ∧ x = y

Next tactic:
intro h0
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · intro h0
    

Proof state:
case mp
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
h0 : z + x = z ∪ y
⊢ z + x = z ∪ x ∧ x = y

Next tactic:
rw [and_iff_right_of_imp]
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · intro h0
    rw [and_iff_right_of_imp]
    · 

Proof state:
case mp
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
h0 : z + x = z ∪ y
⊢ x = y

Next tactic:
exact (le_of_add_le_add_left <| h0.trans_le <| union_le_add z y).antisymm h
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · intro h0
    rw [and_iff_right_of_imp]
    · exact (le_of_add_le_add_left <| h0.trans_le <| union_le_add z y).antisymm h
    · 

Proof state:
case mp
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
h0 : z + x = z ∪ y
⊢ x = y → z + x = z ∪ x

Next tactic:
rintro rfl
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · intro h0
    rw [and_iff_right_of_imp]
    · exact (le_of_add_le_add_left <| h0.trans_le <| union_le_add z y).antisymm h
    · rintro rfl
      

Proof state:
case mp
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x z : Multiset α
h : x ≤ x
h0 : z + x = z ∪ x
⊢ z + x = z ∪ x

Next tactic:
exact h0
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · intro h0
    rw [and_iff_right_of_imp]
    · exact (le_of_add_le_add_left <| h0.trans_le <| union_le_add z y).antisymm h
    · rintro rfl
      exact h0
  · 

Proof state:
case mpr
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : y ≤ x
⊢ z + x = z ∪ x ∧ x = y → z + x = z ∪ y

Next tactic:
rintro ⟨h0, rfl⟩
theorem add_eq_union_left_of_le {x y z : Multiset α} (h : y ≤ x) :
    z + x = z ∪ y ↔ z.Disjoint x ∧ x = y := by
  rw [← add_eq_union_iff_disjoint]
  constructor
  · intro h0
    rw [and_iff_right_of_imp]
    · exact (le_of_add_le_add_left <| h0.trans_le <| union_le_add z y).antisymm h
    · rintro rfl
      exact h0
  · rintro ⟨h0, rfl⟩
    

Proof state:
case mpr.intro
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x z : Multiset α
h0 : z + x = z ∪ x
h : x ≤ x
⊢ z + x = z ∪ x

Next tactic:
exact h0
theorem add_eq_union_right_of_le {x y z : Multiset α} (h : z ≤ y) :
    x + y = x ∪ z ↔ y = z ∧ x.Disjoint y := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : DecidableEq α
x y z : Multiset α
h : z ≤ y
⊢ x + y = x ∪ z ↔ y = z ∧ Disjoint x y

Next tactic:
simpa only [and_comm] using add_eq_union_left_of_le h