Skip to content

Commit 75cc36e

Browse files
committed
chore: Golf prod_involution (#15832)
... and extract `prod_ite_zero` from the proof of `prod_boole` Co-authored-by: Bhavik Mehta, <bhavik.mehta8@gmail.com>
1 parent e024d5c commit 75cc36e

File tree

2 files changed

+47
-47
lines changed

2 files changed

+47
-47
lines changed

Mathlib/Algebra/BigOperators/Group/Finset.lean

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,45 +1510,41 @@ theorem prod_flip {n : ℕ} (f : ℕ → β) :
15101510
rw [prod_range_succ', prod_range_succ _ (Nat.succ n)]
15111511
simp [← ih]
15121512

1513-
@[to_additive]
1514-
theorem prod_involution {s : Finset α} {f : α → β} :
1515-
∀ (g : ∀ a ∈ s, α) (_ : ∀ a ha, f a * f (g a ha) = 1) (_ : ∀ a ha, f a ≠ 1 → g a ha ≠ a)
1516-
(g_mem : ∀ a ha, g a ha ∈ s) (_ : ∀ a ha, g (g a ha) (g_mem a ha) = a),
1517-
∏ x ∈ s, f x = 1 := by
1518-
haveI := Classical.decEq α; haveI := Classical.decEq β
1519-
exact
1520-
Finset.strongInductionOn s fun s ih g h g_ne g_mem g_inv =>
1521-
s.eq_empty_or_nonempty.elim (fun hs => hs.symm ▸ rfl) fun ⟨x, hx⟩ =>
1522-
have hmem : ∀ y ∈ (s.erase x).erase (g x hx), y ∈ s := fun y hy =>
1523-
mem_of_mem_erase (mem_of_mem_erase hy)
1524-
have g_inj : ∀ {x hx y hy}, g x hx = g y hy → x = y := fun {x hx y hy} h => by
1525-
rw [← g_inv x hx, ← g_inv y hy]; simp [h]
1526-
have ih' : (∏ y ∈ erase (erase s x) (g x hx), f y) = (1 : β) :=
1527-
ih ((s.erase x).erase (g x hx))
1528-
⟨Subset.trans (erase_subset _ _) (erase_subset _ _), fun h =>
1529-
not_mem_erase (g x hx) (s.erase x) (h (g_mem x hx))⟩
1530-
(fun y hy => g y (hmem y hy)) (fun y hy => h y (hmem y hy))
1531-
(fun y hy => g_ne y (hmem y hy))
1532-
(fun y hy =>
1533-
mem_erase.2
1534-
fun h : g y _ = g x hx => by simp [g_inj h] at hy,
1535-
mem_erase.2
1536-
fun h : g y _ = x => by
1537-
have : y = g x hx := g_inv y (hmem y hy) ▸ by simp [h]
1538-
simp [this] at hy, g_mem y (hmem y hy)⟩⟩)
1539-
fun y hy => g_inv y (hmem y hy)
1540-
if hx1 : f x = 1 then
1541-
ih' ▸
1542-
Eq.symm
1543-
(prod_subset hmem fun y hy hy₁ =>
1544-
have : y = x ∨ y = g x hx := by
1545-
simpa [hy, -not_and, mem_erase, not_and_or, or_comm] using hy₁
1546-
this.elim (fun hy => hy.symm ▸ hx1) fun hy =>
1547-
h x hx ▸ hy ▸ hx1.symm ▸ (one_mul _).symm)
1548-
else by
1549-
rw [← insert_erase hx, prod_insert (not_mem_erase _ _), ←
1550-
insert_erase (mem_erase.2 ⟨g_ne x hx hx1, g_mem x hx⟩),
1551-
prod_insert (not_mem_erase _ _), ih', mul_one, h x hx]
1513+
/-- The difference with `Finset.prod_ninvolution` is that the involution is allowed to use
1514+
membership of the domain of the product, rather than being a non-dependent function. -/
1515+
@[to_additive "The difference with `Finset.sum_ninvolution` is that the involution is allowed to use
1516+
membership of the domain of the sum, rather than being a non-dependent function."]
1517+
lemma prod_involution (g : ∀ a ∈ s, α) (hg₁ : ∀ a ha, f a * f (g a ha) = 1)
1518+
(hg₃ : ∀ a ha, f a ≠ 1 → g a ha ≠ a)
1519+
(g_mem : ∀ a ha, g a ha ∈ s) (hg₄ : ∀ a ha, g (g a ha) (g_mem a ha) = a) :
1520+
∏ x ∈ s, f x = 1 := by
1521+
classical
1522+
induction' s using Finset.strongInduction with s ih
1523+
obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty
1524+
· simp
1525+
have : {x, g x hx} ⊆ s := by simp [insert_subset_iff, hx, g_mem]
1526+
suffices h : ∏ x ∈ s \ {x, g x hx}, f x = 1 by
1527+
rw [← prod_sdiff this, h, one_mul]
1528+
rcases eq_or_ne (g x hx) x
1529+
case inl hx' => simpa [hx'] using hg₃ x hx
1530+
case inr hx' => rw [prod_pair hx'.symm, hg₁]
1531+
suffices h₃ : ∀ a (ha : a ∈ s \ {x, g x hx}), g a (sdiff_subset ha) ∈ s \ {x, g x hx} by
1532+
exact ih (s \ {x, g x hx}) (ssubset_iff.2 ⟨x, by simp [insert_subset_iff, hx]⟩) _
1533+
(by simp [hg₁]) (fun _ _ => hg₃ _ _) h₃ (fun _ _ => hg₄ _ _)
1534+
simp only [mem_sdiff, mem_insert, mem_singleton, not_or, g_mem, true_and]
1535+
rintro a ⟨ha₁, ha₂, ha₃⟩
1536+
refine ⟨fun h => by simp [← h, hg₄] at ha₃, fun h => ?_⟩
1537+
have : g (g a ha₁) (g_mem _ _) = g (g x hx) (g_mem _ _) := by simp only [h]
1538+
exact ha₂ (by simpa [hg₄] using this)
1539+
1540+
/-- The difference with `Finset.prod_involution` is that the involution is a non-dependent function,
1541+
rather than being allowed to use membership of the domain of the product. -/
1542+
@[to_additive "The difference with `Finset.sum_involution` is that the involution is a non-dependent
1543+
function, rather than being allowed to use membership of the domain of the sum."]
1544+
lemma prod_ninvolution (g : α → α) (hg₁ : ∀ a, f a * f (g a) = 1) (hg₂ : ∀ a, f a ≠ 1 → g a ≠ a)
1545+
(g_mem : ∀ a, g a ∈ s) (hg₃ : ∀ a, g (g a) = a) : ∏ x ∈ s, f x = 1 :=
1546+
prod_involution (fun i _ => g i) (fun i _ => hg₁ i) (fun _ _ hi => hg₂ _ hi)
1547+
(fun i _ => g_mem i) (fun i _ => hg₃ i)
15521548

15531549
/-- The product of the composition of functions `f` and `g`, is the product over `b ∈ s.image g` of
15541550
`f b` to the power of the cardinality of the fibre of `b`. See also `Finset.prod_image`. -/
@@ -1674,7 +1670,7 @@ theorem prod_erase [DecidableEq α] (s : Finset α) {f : α → β} {a : α} (h
16741670
rw [sdiff_singleton_eq_erase] at hnx
16751671
rwa [eq_of_mem_of_not_mem_erase hx hnx]
16761672

1677-
/-- See also `Finset.prod_boole`. -/
1673+
/-- See also `Finset.prod_ite_zero`. -/
16781674
@[to_additive "See also `Finset.sum_boole`."]
16791675
theorem prod_ite_one (s : Finset α) (p : α → Prop) [DecidablePred p]
16801676
(h : ∀ i ∈ s, ∀ j ∈ s, p i → p j → i = j) (a : β) :

Mathlib/Algebra/BigOperators/GroupWithZero/Finset.lean

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ variable [CommMonoidWithZero M₀] {p : ι → Prop} [DecidablePred p] {f : ι
2424
lemma prod_eq_zero (hi : i ∈ s) (h : f i = 0) : ∏ j ∈ s, f j = 0 := by
2525
classical rw [← prod_erase_mul _ _ hi, h, mul_zero]
2626

27-
lemma prod_boole : ∏ i ∈ s, (ite (p i) 1 0 : M₀) = ite (∀ i ∈ s, p i) 1 0 := by
27+
lemma prod_ite_zero :
28+
(∏ i ∈ s, if p i then f i else 0) = if ∀ i ∈ s, p i then ∏ i ∈ s, f i else 0 := by
2829
split_ifs with h
29-
· apply prod_eq_one
30-
intro i hi
31-
rw [if_pos (h i hi)]
30+
· exact prod_congr rfl fun i hi => by simp [h i hi]
3231
· push_neg at h
3332
rcases h with ⟨i, hi, hq⟩
34-
apply prod_eq_zero hi
35-
rw [if_neg hq]
33+
exact prod_eq_zero hi (by simp [hq])
34+
35+
lemma prod_boole : ∏ i ∈ s, (ite (p i) 1 0 : M₀) = ite (∀ i ∈ s, p i) 1 0 := by
36+
rw [prod_ite_zero, prod_const_one]
3637

3738
lemma support_prod_subset (s : Finset ι) (f : ι → κ → M₀) :
3839
support (fun x ↦ ∏ i ∈ s, f i x) ⊆ ⋂ i ∈ s, support (f i) :=
@@ -57,7 +58,10 @@ lemma support_prod (s : Finset ι) (f : ι → κ → M₀) :
5758
end Finset
5859

5960
namespace Fintype
60-
variable [Fintype ι] [CommMonoidWithZero M₀] {p : ι → Prop} [DecidablePred p]
61+
variable [Fintype ι] [CommMonoidWithZero M₀] {p : ι → Prop} [DecidablePred p] {f : ι → M₀}
62+
63+
lemma prod_ite_zero : (∏ i, if p i then f i else 0) = if ∀ i, p i then ∏ i, f i else 0 := by
64+
simp [Finset.prod_ite_zero]
6165

6266
lemma prod_boole : ∏ i, (ite (p i) 1 0 : M₀) = ite (∀ i, p i) 1 0 := by simp [Finset.prod_boole]
6367

0 commit comments

Comments
 (0)