l3lab/ntp-mathlib huggingface dataset:
/-- Generalization of `Finset.prod_comm` to the case when the inner `Finset`s depend on the outer
variable. -/
@[to_additive "Generalization of `Finset.sum_comm` to the case when the inner `Finset`s depend on
the outer variable."]
theorem prod_comm' {s : Finset γ} {t : γ → Finset α} {t' : Finset α} {s' : α → Finset γ}
    (h : ∀ x y, x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t') {f : γ → α → β} :
    (∏ x in s, ∏ y in t x, f x y) = ∏ y in t', ∏ x in s' y, f x y := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset γ
t : γ → Finset α
t' : Finset α
s' : α → Finset γ
h : ∀ (x : γ) (y : α), x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t'
f : γ → α → β
⊢ ∏ x in s, ∏ y in t x, f x y = ∏ y in t', ∏ x in s' y, f x y

Next tactic:
classical
    have : ∀ z : γ × α, (z ∈ s.biUnion fun x => (t x).map <| Function.Embedding.sectr x _) ↔
      z.1 ∈ s ∧ z.2 ∈ t z.1 := by
      rintro ⟨x, y⟩
      simp only [mem_biUnion, mem_map, Function.Embedding.sectr_apply, Prod.mk.injEq,
        exists_eq_right, ← and_assoc]
    exact
      (prod_finset_product' _ _ _ this).symm.trans
        ((prod_finset_product_right' _ _ _) fun ⟨x, y⟩ => (this _).trans ((h x y).trans and_comm))
/-- Generalization of `Finset.prod_comm` to the case when the inner `Finset`s depend on the outer
variable. -/
@[to_additive "Generalization of `Finset.sum_comm` to the case when the inner `Finset`s depend on
the outer variable."]
theorem prod_comm' {s : Finset γ} {t : γ → Finset α} {t' : Finset α} {s' : α → Finset γ}
    (h : ∀ x y, x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t') {f : γ → α → β} :
    (∏ x in s, ∏ y in t x, f x y) = ∏ y in t', ∏ x in s' y, f x y := by
  classical
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset γ
t : γ → Finset α
t' : Finset α
s' : α → Finset γ
h : ∀ (x : γ) (y : α), x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t'
f : γ → α → β
⊢ ∏ x in s, ∏ y in t x, f x y = ∏ y in t', ∏ x in s' y, f x y

Next tactic:
have : ∀ z : γ × α, (z ∈ s.biUnion fun x => (t x).map <| Function.Embedding.sectr x _) ↔
      z.1 ∈ s ∧ z.2 ∈ t z.1 := by
      rintro ⟨x, y⟩
      simp only [mem_biUnion, mem_map, Function.Embedding.sectr_apply, Prod.mk.injEq,
        exists_eq_right, ← and_assoc]
/-- Generalization of `Finset.prod_comm` to the case when the inner `Finset`s depend on the outer
variable. -/
@[to_additive "Generalization of `Finset.sum_comm` to the case when the inner `Finset`s depend on
the outer variable."]
theorem prod_comm' {s : Finset γ} {t : γ → Finset α} {t' : Finset α} {s' : α → Finset γ}
    (h : ∀ x y, x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t') {f : γ → α → β} :
    (∏ x in s, ∏ y in t x, f x y) = ∏ y in t', ∏ x in s' y, f x y := by
  classical
    have : ∀ z : γ × α, (z ∈ s.biUnion fun x => (t x).map <| Function.Embedding.sectr x _) ↔
      z.1 ∈ s ∧ z.2 ∈ t z.1 := by
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset γ
t : γ → Finset α
t' : Finset α
s' : α → Finset γ
h : ∀ (x : γ) (y : α), x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t'
f : γ → α → β
⊢ ∀ (z : γ × α), (z ∈ Finset.biUnion s fun x => map (Embedding.sectr x α) (t x)) ↔ z.1 ∈ s ∧ z.2 ∈ t z.1

Next tactic:
rintro ⟨x, y⟩
/-- Generalization of `Finset.prod_comm` to the case when the inner `Finset`s depend on the outer
variable. -/
@[to_additive "Generalization of `Finset.sum_comm` to the case when the inner `Finset`s depend on
the outer variable."]
theorem prod_comm' {s : Finset γ} {t : γ → Finset α} {t' : Finset α} {s' : α → Finset γ}
    (h : ∀ x y, x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t') {f : γ → α → β} :
    (∏ x in s, ∏ y in t x, f x y) = ∏ y in t', ∏ x in s' y, f x y := by
  classical
    have : ∀ z : γ × α, (z ∈ s.biUnion fun x => (t x).map <| Function.Embedding.sectr x _) ↔
      z.1 ∈ s ∧ z.2 ∈ t z.1 := by
      rintro ⟨x, y⟩
      

Proof state:
case mk
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset γ
t : γ → Finset α
t' : Finset α
s' : α → Finset γ
h : ∀ (x : γ) (y : α), x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t'
f : γ → α → β
x : γ
y : α
⊢ ((x, y) ∈ Finset.biUnion s fun x => map (Embedding.sectr x α) (t x)) ↔ (x, y).1 ∈ s ∧ (x, y).2 ∈ t (x, y).1

Next tactic:
simp only [mem_biUnion, mem_map, Function.Embedding.sectr_apply, Prod.mk.injEq,
        exists_eq_right, ← and_assoc]
/-- Generalization of `Finset.prod_comm` to the case when the inner `Finset`s depend on the outer
variable. -/
@[to_additive "Generalization of `Finset.sum_comm` to the case when the inner `Finset`s depend on
the outer variable."]
theorem prod_comm' {s : Finset γ} {t : γ → Finset α} {t' : Finset α} {s' : α → Finset γ}
    (h : ∀ x y, x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t') {f : γ → α → β} :
    (∏ x in s, ∏ y in t x, f x y) = ∏ y in t', ∏ x in s' y, f x y := by
  classical
    have : ∀ z : γ × α, (z ∈ s.biUnion fun x => (t x).map <| Function.Embedding.sectr x _) ↔
      z.1 ∈ s ∧ z.2 ∈ t z.1 := by
      rintro ⟨x, y⟩
      simp only [mem_biUnion, mem_map, Function.Embedding.sectr_apply, Prod.mk.injEq,
        exists_eq_right, ← and_assoc]
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset γ
t : γ → Finset α
t' : Finset α
s' : α → Finset γ
h : ∀ (x : γ) (y : α), x ∈ s ∧ y ∈ t x ↔ x ∈ s' y ∧ y ∈ t'
f : γ → α → β
this : ∀ (z : γ × α), (z ∈ Finset.biUnion s fun x => map (Embedding.sectr x α) (t x)) ↔ z.1 ∈ s ∧ z.2 ∈ t z.1
⊢ ∏ x in s, ∏ y in t x, f x y = ∏ y in t', ∏ x in s' y, f x y

Next tactic:
exact
      (prod_finset_product' _ _ _ this).symm.trans
        ((prod_finset_product_right' _ _ _) fun ⟨x, y⟩ => (this _).trans ((h x y).trans and_comm))
@[to_additive]
theorem prod_hom_rel [CommMonoid γ] {r : β → γ → Prop} {f : α → β} {g : α → γ} {s : Finset α}
    (h₁ : r 1 1) (h₂ : ∀ a b c, r b c → r (f a * b) (g a * c)) :
    r (∏ x in s, f x) (∏ x in s, g x) := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g✝ : α → β
inst✝¹ : CommMonoid β
inst✝ : CommMonoid γ
r : β → γ → Prop
f : α → β
g : α → γ
s : Finset α
h₁ : r 1 1
h₂ : ∀ (a : α) (b : β) (c : γ), r b c → r (f a * b) (g a * c)
⊢ r (∏ x in s, f x) (∏ x in s, g x)

Next tactic:
delta Finset.prod
@[to_additive]
theorem prod_hom_rel [CommMonoid γ] {r : β → γ → Prop} {f : α → β} {g : α → γ} {s : Finset α}
    (h₁ : r 1 1) (h₂ : ∀ a b c, r b c → r (f a * b) (g a * c)) :
    r (∏ x in s, f x) (∏ x in s, g x) := by
  delta Finset.prod
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g✝ : α → β
inst✝¹ : CommMonoid β
inst✝ : CommMonoid γ
r : β → γ → Prop
f : α → β
g : α → γ
s : Finset α
h₁ : r 1 1
h₂ : ∀ (a : α) (b : β) (c : γ), r b c → r (f a * b) (g a * c)
⊢ r (Multiset.prod (Multiset.map (fun x => f x) s.val)) (Multiset.prod (Multiset.map (fun x => g x) s.val))

Next tactic:
apply Multiset.prod_hom_rel
@[to_additive]
theorem prod_hom_rel [CommMonoid γ] {r : β → γ → Prop} {f : α → β} {g : α → γ} {s : Finset α}
    (h₁ : r 1 1) (h₂ : ∀ a b c, r b c → r (f a * b) (g a * c)) :
    r (∏ x in s, f x) (∏ x in s, g x) := by
  delta Finset.prod
  apply Multiset.prod_hom_rel <;> 

Proof state:
case h₁
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g✝ : α → β
inst✝¹ : CommMonoid β
inst✝ : CommMonoid γ
r : β → γ → Prop
f : α → β
g : α → γ
s : Finset α
h₁ : r 1 1
h₂ : ∀ (a : α) (b : β) (c : γ), r b c → r (f a * b) (g a * c)
⊢ r 1 1

Next tactic:
assumption
@[to_additive]
theorem prod_hom_rel [CommMonoid γ] {r : β → γ → Prop} {f : α → β} {g : α → γ} {s : Finset α}
    (h₁ : r 1 1) (h₂ : ∀ a b c, r b c → r (f a * b) (g a * c)) :
    r (∏ x in s, f x) (∏ x in s, g x) := by
  delta Finset.prod
  apply Multiset.prod_hom_rel <;> 

Proof state:
case h₂
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g✝ : α → β
inst✝¹ : CommMonoid β
inst✝ : CommMonoid γ
r : β → γ → Prop
f : α → β
g : α → γ
s : Finset α
h₁ : r 1 1
h₂ : ∀ (a : α) (b : β) (c : γ), r b c → r (f a * b) (g a * c)
⊢ ∀ ⦃a : α⦄ ⦃b : β⦄ ⦃c : γ⦄, r b c → r (f a * b) (g a * c)

Next tactic:
assumption
@[to_additive]
theorem prod_subset_one_on_sdiff [DecidableEq α] (h : s₁ ⊆ s₂) (hg : ∀ x ∈ s₂ \ s₁, g x = 1)
    (hfg : ∀ x ∈ s₁, f x = g x) : ∏ i in s₁, f i = ∏ i in s₂, g i := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : CommMonoid β
inst✝ : DecidableEq α
h : s₁ ⊆ s₂
hg : ∀ x ∈ s₂ \ s₁, g x = 1
hfg : ∀ x ∈ s₁, f x = g x
⊢ ∏ i in s₁, f i = ∏ i in s₂, g i

Next tactic:
rw [← prod_sdiff h, prod_eq_one hg, one_mul]
@[to_additive]
theorem prod_subset_one_on_sdiff [DecidableEq α] (h : s₁ ⊆ s₂) (hg : ∀ x ∈ s₂ \ s₁, g x = 1)
    (hfg : ∀ x ∈ s₁, f x = g x) : ∏ i in s₁, f i = ∏ i in s₂, g i := by
  rw [← prod_sdiff h, prod_eq_one hg, one_mul]
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : CommMonoid β
inst✝ : DecidableEq α
h : s₁ ⊆ s₂
hg : ∀ x ∈ s₂ \ s₁, g x = 1
hfg : ∀ x ∈ s₁, f x = g x
⊢ ∏ i in s₁, f i = ∏ x in s₁, g x

Next tactic:
exact prod_congr rfl hfg
@[to_additive]
theorem prod_subset (h : s₁ ⊆ s₂) (hf : ∀ x ∈ s₂, x ∉ s₁ → f x = 1) :
    ∏ x in s₁, f x = ∏ x in s₂, f x :=
  haveI := Classical.decEq α
  prod_subset_one_on_sdiff h (by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝ : CommMonoid β
h : s₁ ⊆ s₂
hf : ∀ x ∈ s₂, x ∉ s₁ → f x = 1
this : DecidableEq α
⊢ ∀ x ∈ s₂ \ s₁, f x = 1

Next tactic:
simpa
@[to_additive]
theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, f x ≠ 1 → p x) :
    ∏ x in s.filter p, f x = ∏ x in s, f x :=
  (prod_subset (filter_subset _ _)) fun x => by
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
hp : ∀ x ∈ s, f x ≠ 1 → p x
x : α
⊢ x ∈ s → x ∉ filter p s → f x = 1

Next tactic:
classical
      rw [not_imp_comm, mem_filter]
      exact fun h₁ h₂ => ⟨h₁, by simpa using hp _ h₁ h₂⟩
@[to_additive]
theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, f x ≠ 1 → p x) :
    ∏ x in s.filter p, f x = ∏ x in s, f x :=
  (prod_subset (filter_subset _ _)) fun x => by
    classical
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
hp : ∀ x ∈ s, f x ≠ 1 → p x
x : α
⊢ x ∈ s → x ∉ filter p s → f x = 1

Next tactic:
rw [not_imp_comm, mem_filter]
@[to_additive]
theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, f x ≠ 1 → p x) :
    ∏ x in s.filter p, f x = ∏ x in s, f x :=
  (prod_subset (filter_subset _ _)) fun x => by
    classical
      rw [not_imp_comm, mem_filter]
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
hp : ∀ x ∈ s, f x ≠ 1 → p x
x : α
⊢ x ∈ s → ¬f x = 1 → x ∈ s ∧ p x

Next tactic:
exact fun h₁ h₂ => ⟨h₁, by simpa using hp _ h₁ h₂⟩
@[to_additive]
theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, f x ≠ 1 → p x) :
    ∏ x in s.filter p, f x = ∏ x in s, f x :=
  (prod_subset (filter_subset _ _)) fun x => by
    classical
      rw [not_imp_comm, mem_filter]
      exact fun h₁ h₂ => ⟨h₁, by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
hp : ∀ x ∈ s, f x ≠ 1 → p x
x : α
h₁ : x ∈ s
h₂ : ¬f x = 1
⊢ p x

Next tactic:
simpa using hp _ h₁ h₂
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
a : α
h : a ∈ filter p s
⊢ f a = if p a then f a else 1

Next tactic:
rw [if_pos]
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by rw [if_pos]; 

Proof state:
case hc
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
a : α
h : a ∈ filter p s
⊢ p a

Next tactic:
simpa using (mem_filter.1 h).2
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by rw [if_pos]; simpa using (mem_filter.1 h).2
    _ = ∏ a in s, if p a then f a else 1 := by
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
⊢ (∏ a in filter p s, if p a then f a else 1) = ∏ a in s, if p a then f a else 1

Next tactic:
{ refine' prod_subset (filter_subset _ s) fun x hs h => _
        rw [mem_filter, not_and] at h
        exact if_neg (by simpa using h hs) }
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by rw [if_pos]; simpa using (mem_filter.1 h).2
    _ = ∏ a in s, if p a then f a else 1 := by
      { 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
⊢ (∏ a in filter p s, if p a then f a else 1) = ∏ a in s, if p a then f a else 1

Next tactic:
refine' prod_subset (filter_subset _ s) fun x hs h => _
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by rw [if_pos]; simpa using (mem_filter.1 h).2
    _ = ∏ a in s, if p a then f a else 1 := by
      { refine' prod_subset (filter_subset _ s) fun x hs h => _
        

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
x : α
hs : x ∈ s
h : x ∉ filter p s
⊢ (if p x then f x else 1) = 1

Next tactic:
rw [mem_filter, not_and] at h
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by rw [if_pos]; simpa using (mem_filter.1 h).2
    _ = ∏ a in s, if p a then f a else 1 := by
      { refine' prod_subset (filter_subset _ s) fun x hs h => _
        rw [mem_filter, not_and] at h
        

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
x : α
hs : x ∈ s
h : x ∈ s → ¬p x
⊢ (if p x then f x else 1) = 1

Next tactic:
exact if_neg (by simpa using h hs)
@[to_additive]
theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) :
    ∏ a in s.filter p, f a = ∏ a in s, if p a then f a else 1 :=
  calc
    ∏ a in s.filter p, f a = ∏ a in s.filter p, if p a then f a else 1 :=
      prod_congr rfl fun a h => by rw [if_pos]; simpa using (mem_filter.1 h).2
    _ = ∏ a in s, if p a then f a else 1 := by
      { refine' prod_subset (filter_subset _ s) fun x hs h => _
        rw [mem_filter, not_and] at h
        exact if_neg (by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝¹ : CommMonoid β
p : α → Prop
inst✝ : DecidablePred p
f : α → β
x : α
hs : x ∈ s
h : x ∈ s → ¬p x
⊢ ¬p x

Next tactic:
simpa using h hs
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
⊢ ∏ x in s, f x = f a

Next tactic:
haveI := Classical.decEq α
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  haveI := Classical.decEq α
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
this : DecidableEq α
⊢ ∏ x in s, f x = f a

Next tactic:
calc
    ∏ x in s, f x = ∏ x in {a}, f x := by
      { refine' (prod_subset _ _).symm
        · intro _ H
          rwa [mem_singleton.1 H]
        · simpa only [mem_singleton] }
    _ = f a := prod_singleton _ _
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  haveI := Classical.decEq α
  calc
    ∏ x in s, f x = ∏ x in {a}, f x := by
      

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
this : DecidableEq α
⊢ ∏ x in s, f x = ∏ x in {a}, f x

Next tactic:
{ refine' (prod_subset _ _).symm
        · intro _ H
          rwa [mem_singleton.1 H]
        · simpa only [mem_singleton] }
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  haveI := Classical.decEq α
  calc
    ∏ x in s, f x = ∏ x in {a}, f x := by
      { 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
this : DecidableEq α
⊢ ∏ x in s, f x = ∏ x in {a}, f x

Next tactic:
refine' (prod_subset _ _).symm
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  haveI := Classical.decEq α
  calc
    ∏ x in s, f x = ∏ x in {a}, f x := by
      { refine' (prod_subset _ _).symm
        · 

Proof state:
case refine'_1
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
this : DecidableEq α
⊢ {a} ⊆ s

Next tactic:
intro _ H
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  haveI := Classical.decEq α
  calc
    ∏ x in s, f x = ∏ x in {a}, f x := by
      { refine' (prod_subset _ _).symm
        · intro _ H
          

Proof state:
case refine'_1
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝¹ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
this : DecidableEq α
a✝ : α
H : a✝ ∈ {a}
⊢ a✝ ∈ s

Next tactic:
rwa [mem_singleton.1 H]
@[to_additive]
theorem prod_eq_single_of_mem {s : Finset α} {f : α → β} (a : α) (h : a ∈ s)
    (h₀ : ∀ b ∈ s, b ≠ a → f b = 1) : ∏ x in s, f x = f a := by
  haveI := Classical.decEq α
  calc
    ∏ x in s, f x = ∏ x in {a}, f x := by
      { refine' (prod_subset _ _).symm
        · intro _ H
          rwa [mem_singleton.1 H]
        · 

Proof state:
case refine'_2
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h : a ∈ s
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
this : DecidableEq α
⊢ ∀ x ∈ s, x ∉ {a} → f x = 1

Next tactic:
simpa only [mem_singleton]
@[to_additive]
theorem prod_eq_single {s : Finset α} {f : α → β} (a : α) (h₀ : ∀ b ∈ s, b ≠ a → f b = 1)
    (h₁ : a ∉ s → f a = 1) : ∏ x in s, f x = f a :=
  haveI := Classical.decEq α
  by_cases (prod_eq_single_of_mem a · h₀) fun this =>
    (prod_congr rfl fun b hb => h₀ b hb <| by 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a : α
h₀ : ∀ b ∈ s, b ≠ a → f b = 1
h₁ : a ∉ s → f a = 1
this✝ : DecidableEq α
this : a ∉ s
b : α
hb : b ∈ s
⊢ b ≠ a

Next tactic:
rintro rfl
@[to_additive]
theorem prod_eq_single {s : Finset α} {f : α → β} (a : α) (h₀ : ∀ b ∈ s, b ≠ a → f b = 1)
    (h₁ : a ∉ s → f a = 1) : ∏ x in s, f x = f a :=
  haveI := Classical.decEq α
  by_cases (prod_eq_single_of_mem a · h₀) fun this =>
    (prod_congr rfl fun b hb => h₀ b hb <| by rintro rfl; 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
this✝ : DecidableEq α
b : α
hb : b ∈ s
h₀ : ∀ b_1 ∈ s, b_1 ≠ b → f b_1 = 1
h₁ : b ∉ s → f b = 1
this : b ∉ s
⊢ False

Next tactic:
exact this hb
@[to_additive]
theorem prod_eq_mul_of_mem {s : Finset α} {f : α → β} (a b : α) (ha : a ∈ s) (hb : b ∈ s)
    (hn : a ≠ b) (h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1) : ∏ x in s, f x = f a * f b := by
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a b : α
ha : a ∈ s
hb : b ∈ s
hn : a ≠ b
h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1
⊢ ∏ x in s, f x = f a * f b

Next tactic:
haveI := Classical.decEq α
@[to_additive]
theorem prod_eq_mul_of_mem {s : Finset α} {f : α → β} (a b : α) (ha : a ∈ s) (hb : b ∈ s)
    (hn : a ≠ b) (h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1) : ∏ x in s, f x = f a * f b := by
  haveI := Classical.decEq α; 

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a b : α
ha : a ∈ s
hb : b ∈ s
hn : a ≠ b
h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1
this : DecidableEq α
⊢ ∏ x in s, f x = f a * f b

Next tactic:
let s' := ({a, b} : Finset α)
@[to_additive]
theorem prod_eq_mul_of_mem {s : Finset α} {f : α → β} (a b : α) (ha : a ∈ s) (hb : b ∈ s)
    (hn : a ≠ b) (h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1) : ∏ x in s, f x = f a * f b := by
  haveI := Classical.decEq α; let s' := ({a, b} : Finset α)
  

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a b : α
ha : a ∈ s
hb : b ∈ s
hn : a ≠ b
h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1
this : DecidableEq α
s' : Finset α := {a, b}
⊢ ∏ x in s, f x = f a * f b

Next tactic:
have hu : s' ⊆ s := by
    refine' insert_subset_iff.mpr _
    apply And.intro ha
    apply singleton_subset_iff.mpr hb
@[to_additive]
theorem prod_eq_mul_of_mem {s : Finset α} {f : α → β} (a b : α) (ha : a ∈ s) (hb : b ∈ s)
    (hn : a ≠ b) (h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1) : ∏ x in s, f x = f a * f b := by
  haveI := Classical.decEq α; let s' := ({a, b} : Finset α)
  have hu : s' ⊆ s := by
    

Proof state:
ι : Type u_1
β : Type u
α : Type v
γ : Type w
s✝ s₁ s₂ : Finset α
a✝ : α
f✝ g : α → β
inst✝ : CommMonoid β
s : Finset α
f : α → β
a b : α
ha : a ∈ s
hb : b ∈ s
hn : a ≠ b
h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1
this : DecidableEq α
s' : Finset α := {a, b}
⊢ s' ⊆ s

Next tactic:
refine' insert_subset_iff.mpr _