l3lab/ntp-mathlib huggingface dataset:
theorem finprod_eq_zero {M₀ : Type*} [CommMonoidWithZero M₀] (f : α → M₀) (x : α) (hx : f x = 0)
    (hf : (mulSupport f).Finite) : ∏ᶠ x, f x = 0 := by
  nontriviality
  rw [finprod_eq_prod f hf]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g : α → M
a b : α
s t : Set α
M₀ : Type u_7
inst✝ : CommMonoidWithZero M₀
f : α → M₀
x : α
hx : f x = 0
hf : Set.Finite (mulSupport f)
✝ : Nontrivial M₀
⊢ ∏ i in Finite.toFinset hf, f i = 0

Next tactic:
refine' Finset.prod_eq_zero (hf.mem_toFinset.2 _) hx
theorem finprod_eq_zero {M₀ : Type*} [CommMonoidWithZero M₀] (f : α → M₀) (x : α) (hx : f x = 0)
    (hf : (mulSupport f).Finite) : ∏ᶠ x, f x = 0 := by
  nontriviality
  rw [finprod_eq_prod f hf]
  refine' Finset.prod_eq_zero (hf.mem_toFinset.2 _) hx
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g : α → M
a b : α
s t : Set α
M₀ : Type u_7
inst✝ : CommMonoidWithZero M₀
f : α → M₀
x : α
hx : f x = 0
hf : Set.Finite (mulSupport f)
✝ : Nontrivial M₀
⊢ x ∈ mulSupport f

Next tactic:
simp [hx]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
⊢ ∏ᶠ (a : α), ∏ b in s, f a b = ∏ b in s, ∏ᶠ (a : α), f a b

Next tactic:
have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
⊢ (mulSupport fun a => ∏ b in s, f a b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))

Next tactic:
rw [Finite.coe_toFinset]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
⊢ (mulSupport fun a => ∏ b in s, f a b) ⊆ ⋃ i ∈ ↑s, mulSupport fun a => f a i

Next tactic:
intro x hx
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
x : α
hx : x ∈ mulSupport fun a => ∏ b in s, f a b
⊢ x ∈ ⋃ i ∈ ↑s, mulSupport fun a => f a i

Next tactic:
simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
x : α
hx : x ∈ mulSupport fun a => ∏ b in s, f a b
⊢ ∃ i ∈ s, ¬f x i = 1

Next tactic:
contrapose! hx
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
x : α
hx : ∀ i ∈ s, f x i = 1
⊢ x ∉ mulSupport fun a => ∏ b in s, f a b

Next tactic:
rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
hU : (mulSupport fun a => ∏ b in s, f a b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))
⊢ ∏ᶠ (a : α), ∏ b in s, f a b = ∏ b in s, ∏ᶠ (a : α), f a b

Next tactic:
rw [finprod_eq_prod_of_mulSupport_subset _ hU, Finset.prod_comm]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
  rw [finprod_eq_prod_of_mulSupport_subset _ hU, Finset.prod_comm]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
hU : (mulSupport fun a => ∏ b in s, f a b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))
⊢ ∏ y in s, ∏ x in Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)), f x y =
    ∏ b in s, ∏ᶠ (a : α), f a b

Next tactic:
refine' Finset.prod_congr rfl fun b hb => (finprod_eq_prod_of_mulSupport_subset _ _).symm
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
  rw [finprod_eq_prod_of_mulSupport_subset _ hU, Finset.prod_comm]
  refine' Finset.prod_congr rfl fun b hb => (finprod_eq_prod_of_mulSupport_subset _ _).symm
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a b✝ : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
hU : (mulSupport fun a => ∏ b in s, f a b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))
b : β
hb : b ∈ s
⊢ (mulSupport fun x => f x b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))

Next tactic:
intro a ha
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
  rw [finprod_eq_prod_of_mulSupport_subset _ hU, Finset.prod_comm]
  refine' Finset.prod_congr rfl fun b hb => (finprod_eq_prod_of_mulSupport_subset _ _).symm
  intro a ha
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a✝ b✝ : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
hU : (mulSupport fun a => ∏ b in s, f a b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))
b : β
hb : b ∈ s
a : α
ha : a ∈ mulSupport fun x => f x b
⊢ a ∈ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))

Next tactic:
simp only [Finite.coe_toFinset, mem_iUnion]
@[to_additive]
theorem finprod_prod_comm (s : Finset β) (f : α → β → M)
    (h : ∀ b ∈ s, (mulSupport fun a => f a b).Finite) :
    (∏ᶠ a : α, ∏ b in s, f a b) = ∏ b in s, ∏ᶠ a : α, f a b := by
  have hU :
    (mulSupport fun a => ∏ b in s, f a b) ⊆
      (s.finite_toSet.biUnion fun b hb => h b (Finset.mem_coe.1 hb)).toFinset := by
    rw [Finite.coe_toFinset]
    intro x hx
    simp only [exists_prop, mem_iUnion, Ne.def, mem_mulSupport, Finset.mem_coe]
    contrapose! hx
    rw [mem_mulSupport, not_not, Finset.prod_congr rfl hx, Finset.prod_const_one]
  rw [finprod_eq_prod_of_mulSupport_subset _ hU, Finset.prod_comm]
  refine' Finset.prod_congr rfl fun b hb => (finprod_eq_prod_of_mulSupport_subset _ _).symm
  intro a ha
  simp only [Finite.coe_toFinset, mem_iUnion]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝¹ : CommMonoid M
inst✝ : CommMonoid N
f✝ g : α → M
a✝ b✝ : α
s✝ t : Set α
s : Finset β
f : α → β → M
h : ∀ b ∈ s, Set.Finite (mulSupport fun a => f a b)
hU : (mulSupport fun a => ∏ b in s, f a b) ⊆ ↑(Finite.toFinset (_ : Set.Finite (⋃ i ∈ ↑s, mulSupport fun a => f a i)))
b : β
hb : b ∈ s
a : α
ha : a ∈ mulSupport fun x => f x b
⊢ ∃ i, ∃ (_ : i ∈ ↑s), a ∈ mulSupport fun a => f a i

Next tactic:
exact ⟨b, hb, ha⟩
@[to_additive]
theorem Finset.mulSupport_of_fiberwise_prod_subset_image [DecidableEq β] (s : Finset α) (f : α → M)
    (g : α → β) : (mulSupport fun b => (s.filter fun a => g a = b).prod f) ⊆ s.image g := by
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g✝ : α → M
a b : α
s✝ t : Set α
inst✝ : DecidableEq β
s : Finset α
f : α → M
g : α → β
⊢ (mulSupport fun b => Finset.prod (filter (fun a => g a = b) s) f) ⊆ ↑(image g s)

Next tactic:
simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, Function.support_subset_iff]
@[to_additive]
theorem Finset.mulSupport_of_fiberwise_prod_subset_image [DecidableEq β] (s : Finset α) (f : α → M)
    (g : α → β) : (mulSupport fun b => (s.filter fun a => g a = b).prod f) ⊆ s.image g := by
  simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, Function.support_subset_iff]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g✝ : α → M
a b : α
s✝ t : Set α
inst✝ : DecidableEq β
s : Finset α
f : α → M
g : α → β
⊢ (mulSupport fun b => Finset.prod (filter (fun a => g a = b) s) f) ⊆ g '' ↑s

Next tactic:
intro b h
@[to_additive]
theorem Finset.mulSupport_of_fiberwise_prod_subset_image [DecidableEq β] (s : Finset α) (f : α → M)
    (g : α → β) : (mulSupport fun b => (s.filter fun a => g a = b).prod f) ⊆ s.image g := by
  simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, Function.support_subset_iff]
  intro b h
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g✝ : α → M
a b✝ : α
s✝ t : Set α
inst✝ : DecidableEq β
s : Finset α
f : α → M
g : α → β
b : β
h : b ∈ mulSupport fun b => Finset.prod (filter (fun a => g a = b) s) f
⊢ b ∈ g '' ↑s

Next tactic:
suffices (s.filter fun a : α => g a = b).Nonempty by
    simpa only [s.fiber_nonempty_iff_mem_image g b, Finset.mem_image, exists_prop]
@[to_additive]
theorem Finset.mulSupport_of_fiberwise_prod_subset_image [DecidableEq β] (s : Finset α) (f : α → M)
    (g : α → β) : (mulSupport fun b => (s.filter fun a => g a = b).prod f) ⊆ s.image g := by
  simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, Function.support_subset_iff]
  intro b h
  suffices (s.filter fun a : α => g a = b).Nonempty by
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g✝ : α → M
a b✝ : α
s✝ t : Set α
inst✝ : DecidableEq β
s : Finset α
f : α → M
g : α → β
b : β
h : b ∈ mulSupport fun b => Finset.prod (filter (fun a => g a = b) s) f
this : Finset.Nonempty (filter (fun a => g a = b) s)
⊢ b ∈ g '' ↑s

Next tactic:
simpa only [s.fiber_nonempty_iff_mem_image g b, Finset.mem_image, exists_prop]
@[to_additive]
theorem Finset.mulSupport_of_fiberwise_prod_subset_image [DecidableEq β] (s : Finset α) (f : α → M)
    (g : α → β) : (mulSupport fun b => (s.filter fun a => g a = b).prod f) ⊆ s.image g := by
  simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, Function.support_subset_iff]
  intro b h
  suffices (s.filter fun a : α => g a = b).Nonempty by
    simpa only [s.fiber_nonempty_iff_mem_image g b, Finset.mem_image, exists_prop]
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
f✝ g✝ : α → M
a b✝ : α
s✝ t : Set α
inst✝ : DecidableEq β
s : Finset α
f : α → M
g : α → β
b : β
h : b ∈ mulSupport fun b => Finset.prod (filter (fun a => g a = b) s) f
⊢ Finset.Nonempty (filter (fun a => g a = b) s)

Next tactic:
exact Finset.nonempty_of_prod_ne_one h
/-- Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
we can simplify the right hand side of this lemma. However the form stated here is more useful for
iterating this lemma, e.g., if we have `f : α × β × γ → M`. -/
@[to_additive
      "Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
      we can simplify the right hand side of this lemma. However the form stated here is more
      useful for iterating this lemma, e.g., if we have `f : α × β × γ → M`."]
theorem finprod_mem_finset_product' [DecidableEq α] [DecidableEq β] (s : Finset (α × β))
    (f : α × β → M) :
    (∏ᶠ (ab) (_ : ab ∈ s), f ab) =
      ∏ᶠ (a) (b) (_ : b ∈ (s.filter fun ab => Prod.fst ab = a).image Prod.snd), f (a, b) := by
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
s : Finset (α × β)
f : α × β → M
⊢ ∏ᶠ (ab : α × β) (_ : ab ∈ s), f ab =
    ∏ᶠ (a : α) (b : β) (_ : b ∈ Finset.image Prod.snd (Finset.filter (fun ab => ab.1 = a) s)), f (a, b)

Next tactic:
have :
    ∀ a,
      (∏ i : β in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i)) =
        (Finset.filter (fun ab => Prod.fst ab = a) s).prod f := by
    refine' fun a => Finset.prod_bij (fun b _ => (a, b)) _ _ _ _ <;> simp
    suffices ∀ a' b, (a', b) ∈ s → a' = a → (a, b) ∈ s ∧ a' = a by simpa
    rintro a' b hp rfl
    exact ⟨hp, rfl⟩
/-- Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
we can simplify the right hand side of this lemma. However the form stated here is more useful for
iterating this lemma, e.g., if we have `f : α × β × γ → M`. -/
@[to_additive
      "Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
      we can simplify the right hand side of this lemma. However the form stated here is more
      useful for iterating this lemma, e.g., if we have `f : α × β × γ → M`."]
theorem finprod_mem_finset_product' [DecidableEq α] [DecidableEq β] (s : Finset (α × β))
    (f : α × β → M) :
    (∏ᶠ (ab) (_ : ab ∈ s), f ab) =
      ∏ᶠ (a) (b) (_ : b ∈ (s.filter fun ab => Prod.fst ab = a).image Prod.snd), f (a, b) := by
  have :
    ∀ a,
      (∏ i : β in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i)) =
        (Finset.filter (fun ab => Prod.fst ab = a) s).prod f := by
    

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
f✝ g : α → M
a b : α
s✝ t : Set α
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
s : Finset (α × β)
f : α × β → M
⊢ ∀ (a : α),
    ∏ i in Finset.image Prod.snd (Finset.filter (fun ab => ab.1 = a) s), f (a, i) =
      Finset.prod (Finset.filter (fun ab => ab.1 = a) s) f

Next tactic:
refine' fun a => Finset.prod_bij (fun b _ => (a, b)) _ _ _ _
/-- Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
we can simplify the right hand side of this lemma. However the form stated here is more useful for
iterating this lemma, e.g., if we have `f : α × β × γ → M`. -/
@[to_additive
      "Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
      we can simplify the right hand side of this lemma. However the form stated here is more
      useful for iterating this lemma, e.g., if we have `f : α × β × γ → M`."]
theorem finprod_mem_finset_product' [DecidableEq α] [DecidableEq β] (s : Finset (α × β))
    (f : α × β → M) :
    (∏ᶠ (ab) (_ : ab ∈ s), f ab) =
      ∏ᶠ (a) (b) (_ : b ∈ (s.filter fun ab => Prod.fst ab = a).image Prod.snd), f (a, b) := by
  have :
    ∀ a,
      (∏ i : β in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i)) =
        (Finset.filter (fun ab => Prod.fst ab = a) s).prod f := by
    refine' fun a => Finset.prod_bij (fun b _ => (a, b)) _ _ _ _ <;> 

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
f✝ g : α → M
a✝ b : α
s✝ t : Set α
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
s : Finset (α × β)
f : α × β → M
a : α
⊢ ∀ (a_1 : β) (ha : a_1 ∈ Finset.image Prod.snd (Finset.filter (fun ab => ab.1 = a) s)),
    (fun b x => (a, b)) a_1 ha ∈ Finset.filter (fun ab => ab.1 = a) s

Next tactic:
simp
/-- Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
we can simplify the right hand side of this lemma. However the form stated here is more useful for
iterating this lemma, e.g., if we have `f : α × β × γ → M`. -/
@[to_additive
      "Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
      we can simplify the right hand side of this lemma. However the form stated here is more
      useful for iterating this lemma, e.g., if we have `f : α × β × γ → M`."]
theorem finprod_mem_finset_product' [DecidableEq α] [DecidableEq β] (s : Finset (α × β))
    (f : α × β → M) :
    (∏ᶠ (ab) (_ : ab ∈ s), f ab) =
      ∏ᶠ (a) (b) (_ : b ∈ (s.filter fun ab => Prod.fst ab = a).image Prod.snd), f (a, b) := by
  have :
    ∀ a,
      (∏ i : β in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i)) =
        (Finset.filter (fun ab => Prod.fst ab = a) s).prod f := by
    refine' fun a => Finset.prod_bij (fun b _ => (a, b)) _ _ _ _ <;> 

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
f✝ g : α → M
a✝ b : α
s✝ t : Set α
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
s : Finset (α × β)
f : α × β → M
a : α
⊢ ∀ (a_1 : β) (ha : a_1 ∈ Finset.image Prod.snd (Finset.filter (fun ab => ab.1 = a) s)),
    f (a, a_1) = f ((fun b x => (a, b)) a_1 ha)

Next tactic:
simp
/-- Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
we can simplify the right hand side of this lemma. However the form stated here is more useful for
iterating this lemma, e.g., if we have `f : α × β × γ → M`. -/
@[to_additive
      "Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
      we can simplify the right hand side of this lemma. However the form stated here is more
      useful for iterating this lemma, e.g., if we have `f : α × β × γ → M`."]
theorem finprod_mem_finset_product' [DecidableEq α] [DecidableEq β] (s : Finset (α × β))
    (f : α × β → M) :
    (∏ᶠ (ab) (_ : ab ∈ s), f ab) =
      ∏ᶠ (a) (b) (_ : b ∈ (s.filter fun ab => Prod.fst ab = a).image Prod.snd), f (a, b) := by
  have :
    ∀ a,
      (∏ i : β in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i)) =
        (Finset.filter (fun ab => Prod.fst ab = a) s).prod f := by
    refine' fun a => Finset.prod_bij (fun b _ => (a, b)) _ _ _ _ <;> 

Proof state:
case refine'_3
α : Type u_1
β : Type u_2
ι : Type u_3
G : Type u_4
M : Type u_5
N : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
f✝ g : α → M
a✝ b : α
s✝ t : Set α
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
s : Finset (α × β)
f : α × β → M
a : α
⊢ ∀ (a₁ a₂ : β) (ha₁ : a₁ ∈ Finset.image Prod.snd (Finset.filter (fun ab => ab.1 = a) s))
    (ha₂ : a₂ ∈ Finset.image Prod.snd (Finset.filter (fun ab => ab.1 = a) s)),
    (fun b x => (a, b)) a₁ ha₁ = (fun b x => (a, b)) a₂ ha₂ → a₁ = a₂

Next tactic:
simp