11/-
22Copyright (c) 2024 Antoine Chambert-Loir & María-Inés de Frutos—Fernández. All rights reserved.
33Released under Apache 2.0 license as described in the file LICENSE.
4- Authors: Antoine Chambert-Loir, María-Inés de Frutos—Fernández, Yu Shao, Beibei Xiong, Weijie Jiang
4+ Authors: Antoine Chambert-Loir, María-Inés de Frutos—Fernández, Yu Shao, Beibei Xiong, Weijie Jiang,
5+ Yi Yuan
56-/
67module
78
9+ public import Mathlib.Combinatorics.Enumerative.Partition.Basic
810public import Mathlib.Data.Nat.Choose.Multinomial
911
1012/-! # Bell numbers for multisets
@@ -74,15 +76,12 @@ private theorem bell_mul_eq_lemma {x : ℕ} (hx : x ≠ 0) :
7476 ring_nf
7577
7678theorem bell_mul_eq (m : Multiset ℕ) :
77- m.bell * (m.map (fun j ↦ j !)).prod * ∏ j ∈ (m.toFinset.erase 0 ), (m.count j)!
78- = m.sum ! := by
79+ m.bell * (m.map (fun j ↦ j !)).prod * ∏ j ∈ (m.toFinset.erase 0 ), (m.count j)! = m.sum ! := by
7980 unfold bell
8081 rw [← Nat.mul_right_inj (a := ∏ i ∈ m.toFinset, (i * count i m)!) (by positivity)]
81- simp only [← mul_assoc]
82- rw [Nat.multinomial_spec]
83- simp only [mul_assoc]
84- rw [mul_comm]
85- apply congr_arg₂
82+ simp only [← mul_assoc, Nat.multinomial_spec]
83+ rw [mul_assoc, mul_assoc, mul_comm]
84+ congr
8685 · rw [mul_comm, mul_assoc, ← Finset.prod_mul_distrib, Finset.prod_multiset_map_count]
8786 suffices this : _ by
8887 by_cases hm : 0 ∈ m.toFinset
@@ -94,30 +93,50 @@ theorem bell_mul_eq (m : Multiset ℕ) :
9493 nth_rewrite 3 [← Finset.erase_eq_of_notMem hm]
9594 exact this
9695 rw [← Finset.prod_mul_distrib]
97- apply Finset.prod_congr rfl
98- intro x hx
96+ congr! 1 with x hx
9997 rw [← mul_assoc, bell_mul_eq_lemma]
10098 simp only [Finset.mem_erase, ne_eq, mem_toFinset] at hx
10199 simp only [ne_eq, hx.1 , not_false_eq_true]
102- · apply congr_arg
103- rw [Finset.sum_multiset_count]
100+ · rw [Finset.sum_multiset_count]
104101 simp only [smul_eq_mul, mul_comm]
105102
106103theorem bell_eq (m : Multiset ℕ) :
107- m.bell = m.sum ! / ((m.map (fun j ↦ j !)).prod *
108- ∏ j ∈ (m.toFinset.erase 0 ), (m.count j)!) := by
104+ m.bell = m.sum ! / ((m.map fun j ↦ j !).prod * ∏ j ∈ m.toFinset.erase 0 , (m.count j)!) := by
109105 rw [← Nat.mul_left_inj, Nat.div_mul_cancel _]
110106 · rw [← mul_assoc]
111107 exact bell_mul_eq m
112108 · rw [← bell_mul_eq, mul_assoc]
113109 apply Nat.dvd_mul_left
114110 · rw [← Nat.pos_iff_ne_zero]
115- apply Nat.mul_pos
116- · simp only [CanonicallyOrderedAdd.multiset_prod_pos, mem_map, forall_exists_index, and_imp,
117- forall_apply_eq_imp_iff₂]
118- exact fun _ _ ↦ Nat.factorial_pos _
119- · apply Finset.prod_pos
120- exact fun _ _ ↦ Nat.factorial_pos _
111+ exact Nat.mul_pos (by simp [Nat.factorial_pos]) (by positivity)
112+
113+ private theorem bell_cons_mul_count (m : Multiset ℕ) {a : ℕ} (ha : a ≠ 0 ) :
114+ (a ::ₘ m).bell * (a ::ₘ m).count a = (m.sum + a).choose a * m.bell := by
115+ let rest := ∏ j ∈ (m.toFinset.erase 0 ).erase a, (m.count j)!
116+ have hrest : rest = ∏ j ∈ ((a ::ₘ m).toFinset.erase 0 ).erase a, ((a ::ₘ m).count j)! := by
117+ unfold rest
118+ congr! 1 with j hj
119+ · grind [Multiset.toFinset_cons]
120+ · simp [Finset.mem_erase.mp hj]
121+ let c := (m.map (· !)).prod * (m.count a)! * rest
122+ have hm0 : m.bell * c = m.sum ! := by
123+ have hsplit : (m.count a)! * rest = ∏ j ∈ m.toFinset.erase 0 , (m.count j)! := by
124+ by_cases hmem : a ∈ m.toFinset.erase 0
125+ · rw [← Finset.mul_prod_erase _ _ hmem]
126+ · have hcount : m.count a = 0 := by grind [Multiset.count_eq_zero_of_notMem]
127+ simp [rest, Finset.erase_eq_of_notMem hmem, hcount]
128+ simpa [c, hsplit, mul_assoc] using Multiset.bell_mul_eq m
129+ have hm : m.sum ! * a ! = m.bell * a ! * c := by grind
130+ have hc : 0 < a ! * c := Nat.mul_pos (by positivity) <|
131+ Nat.mul_pos (by simp [Nat.factorial_pos]) (by positivity)
132+ apply Nat.eq_of_mul_eq_mul_right hc
133+ calc
134+ _ = (m.sum + a)! := by
135+ have hq := Multiset.bell_mul_eq (a ::ₘ m)
136+ rw [← Finset.mul_prod_erase _ _ (a := a) (by simp [*]), ← hrest] at hq
137+ simpa [c, Nat.factorial_succ, add_comm, mul_assoc, mul_left_comm] using hq
138+ _ = ((m.sum + a).choose a * m.bell) * (a ! * c) := by
139+ simp [← Nat.add_choose_mul_factorial_mul_factorial, mul_assoc, hm]
121140
122141end Multiset
123142
@@ -128,7 +147,7 @@ of `n`-element subsets. -/
128147def uniformBell (m n : ℕ) : ℕ := bell (replicate m n)
129148
130149theorem uniformBell_eq (m n : ℕ) : m.uniformBell n =
131- ∏ p ∈ (Finset.range m), Nat. choose (p * n + n - 1 ) (n - 1 ) := by
150+ ∏ p ∈ (Finset.range m), choose (p * n + n - 1 ) (n - 1 ) := by
132151 unfold uniformBell bell
133152 rw [toFinset_replicate]
134153 split_ifs with hm
@@ -172,43 +191,96 @@ theorem uniformBell_eq_div (m : ℕ) {n : ℕ} (hn : n ≠ 0) :
172191 uniformBell m n = (m * n)! / (n ! ^ m * m !) := by
173192 rw [eq_comm]
174193 apply Nat.div_eq_of_eq_mul_left
175- · exact Nat.mul_pos (Nat.pow_pos (Nat .factorial_pos n) ) m.factorial_pos
194+ · exact Nat.mul_pos (Nat.pow_pos n .factorial_pos) m.factorial_pos
176195 · rw [← mul_assoc, ← uniformBell_mul_eq _ hn]
177196
178197/--
179198The `n`th standard Bell number,
180199which counts the number of partitions of a set of cardinality `n`.
181-
182- ## TODO
183-
184- Prove that `Nat.bell n` is equal to the sum of `Multiset.bell m`
185- over all multisets `m : Multiset ℕ` such that `m.sum = n`.
186200-/
187201protected def bell : ℕ → ℕ
188202 | 0 => 1
189- | n + 1 => ∑ i : Fin n.succ , choose n i * Nat.bell (n - i)
203+ | n + 1 => ∑ i ≤ n , choose n i * (n - i).bell
190204
191205theorem bell_succ (n : ℕ) :
192- Nat.bell (n + 1 ) = ∑ i : Fin n.succ, Nat. choose n i * Nat.bell (n - i) := by
206+ (n + 1 ).bell = ∑ i ≤ n, choose n i * (n - i).bell := by
193207 rw [Nat.bell]
194208
195209theorem bell_succ' (n : ℕ) :
196- Nat.bell (n + 1 ) = ∑ ij ∈ Finset.antidiagonal n, Nat. choose n ij.1 * Nat.bell ij.2 := by
210+ (n + 1 ).bell = ∑ ij ∈ Finset.antidiagonal n, choose n ij.1 * ij.2 .bell := by
197211 rw [Nat.bell_succ,
198- Finset.Nat.sum_antidiagonal_eq_sum_range_succ (fun x y => Nat.choose n x * Nat.bell y) n,
199- Finset.sum_range]
200-
212+ ← Nat.range_succ_eq_Iic,
213+ ← Finset.Nat.sum_antidiagonal_eq_sum_range_succ (fun x y ↦ choose n x * y.bell) n]
201214
202215@[simp]
203216theorem bell_zero : Nat.bell 0 = 1 := by
204217 simp [Nat.bell]
205218
206219@[simp]
207220theorem bell_one : Nat.bell 1 = 1 := by
208- simp [Nat.bell]
221+ have : Finset.Iic 0 = {0 } := Eq.symm (Finset.eq_of_veq rfl)
222+ simp [Nat.bell, this]
209223
210224@[simp]
211225theorem bell_two : Nat.bell 2 = 2 := by
212- simp [Nat.bell]
226+ have : Finset.Iic 1 = {0 , 1 } := Finset.eq_of_veq rfl
227+ simp [Nat.bell, this]
228+
229+ theorem bell_eq_sum_erase {n : ℕ} (p : (n + 1 ).Partition) :
230+ p.parts.bell = ∑ a ∈ p.parts.toFinset, n.choose (a - 1 ) * (p.parts.erase a).bell := by
231+ apply Nat.eq_of_mul_eq_mul_left n.succ_pos
232+ calc
233+ _ = (∑ a ∈ p.parts.toFinset, p.parts.count a * a) * p.parts.bell := by
234+ rw [succ_eq_add_one, mul_eq_mul_right_iff]
235+ left
236+ simpa [smul_eq_mul, p.parts_sum] using Finset.sum_multiset_count p.parts
237+ _ = ∑ a ∈ p.parts.toFinset, a * (p.parts.count a * p.parts.bell) := by grind [Finset.sum_mul]
238+ _ = ∑ a ∈ p.parts.toFinset, (n + 1 ) * (n.choose (a - 1 ) * (p.parts.erase a).bell) := by
239+ congr! 1 with a ha
240+ have ha0 : a ≠ 0 := by grind
241+ have hsum : (p.parts.erase a).sum + a = n + 1 := by
242+ simpa [p.parts_sum, add_comm] using congrArg Multiset.sum (cons_erase (mem_dedup.mp ha))
243+ grind [Nat.add_one_mul_choose_eq, cons_erase, bell_cons_mul_count]
244+ _ = _ := by rw [Finset.mul_sum]
245+
246+ private def sigmaPartitionWithPartEquiv (n : ℕ) :
247+ (Σ i : Fin n.succ, {p : (n + 1 ).Partition // (i + 1 : ℕ) ∈ p.parts}) ≃
248+ Σ p : (n + 1 ).Partition, {a : ℕ // a ∈ p.parts.toFinset} where
249+ toFun x := ⟨x.2 .1 , ⟨(x.1 + 1 : ℕ), by simpa using x.2 .2 ⟩⟩
250+ invFun x := ⟨⟨x.2 .1 - 1 , by grind⟩, ⟨x.1 , by grind⟩⟩
251+ left_inv x := by simp
252+ right_inv x := by grind
253+
254+ /-- `Nat.bell n` is equal to the sum of `Multiset.bell m` over all multisets `m : Multiset ℕ` such
255+ that `m.sum = n`. -/
256+ theorem bell_eq_sum_partition (n : ℕ) : n.bell = ∑ p : n.Partition, p.parts.bell := by
257+ refine Nat.strong_induction_on n ?_
258+ rintro (_ | n) ih
259+ · simp
260+ rw [Nat.bell_succ]
261+ calc
262+ _ = ∑ i ≤ n, ∑ q : (n - i).Partition, n.choose i * q.parts.bell := by
263+ congr! with i
264+ simp [ih (n - i) _, Finset.mul_sum]
265+ _ = ∑ i ≤ n, ∑ p : {p : (n + 1 ).Partition // (i + 1 : ℕ) ∈ p.parts},
266+ choose n i * (p.1 .parts.erase (i + 1 )).bell := by
267+ congr! with i hi
268+ have : i ≤ n := Finset.mem_Iic.mp hi
269+ have h1 : 1 ≤ (i + 1 : ℕ) := by lia
270+ have h2 : (i + 1 : ℕ) ≤ n + 1 := by lia
271+ have hsub : n + 1 - (i + 1 : ℕ) = n - i := by lia
272+ exact hsub ▸ (Fintype.sum_equiv (Partition.partitionWithPartEquiv h1 h2) _ _ (fun _ ↦ rfl)).symm
273+ _ = ∑ x : Σ p : (n + 1 ).Partition, p.parts.toFinset,
274+ choose n (x.2 .1 - 1 ) * (x.1 .parts.erase x.2 .1 ).bell := by
275+ rw [← Nat.range_succ_eq_Iic, Finset.sum_range, ← Fintype.sum_sigma']
276+ refine Fintype.sum_equiv (sigmaPartitionWithPartEquiv n) _ _ ?_
277+ simp [sigmaPartitionWithPartEquiv]
278+ _ = ∑ p : (n + 1 ).Partition, ∑ a : p.parts.toFinset, choose n (a - 1 ) * (p.parts.erase a).bell :=
279+ Fintype.sum_sigma' fun (p : (n + 1 ).Partition) (a : p.parts.toFinset) ↦
280+ choose n (a - 1 ) * (p.parts.erase a.1 ).bell
281+ _ = _ := by
282+ congr! with p
283+ rw [bell_eq_sum_erase p]
284+ exact p.parts.toFinset.sum_coe_sort (fun a ↦ choose n (a - 1 ) * (p.parts.erase a).bell)
213285
214286end Nat
0 commit comments