Skip to content

Commit 44effe7

Browse files
committed
feat(Combinatorics): generating function for partitions
1 parent 4c492e5 commit 44effe7

File tree

4 files changed

+241
-0
lines changed

4 files changed

+241
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2941,6 +2941,7 @@ import Mathlib.Combinatorics.Enumerative.DyckWord
29412941
import Mathlib.Combinatorics.Enumerative.IncidenceAlgebra
29422942
import Mathlib.Combinatorics.Enumerative.InclusionExclusion
29432943
import Mathlib.Combinatorics.Enumerative.Partition
2944+
import Mathlib.Combinatorics.Enumerative.Partition.GenFun
29442945
import Mathlib.Combinatorics.Enumerative.Stirling
29452946
import Mathlib.Combinatorics.Extremal.RuzsaSzemeredi
29462947
import Mathlib.Combinatorics.Graph.Basic

Mathlib/Algebra/Order/Antidiag/Finsupp.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ theorem finsuppAntidiag_insert {a : ι} {s : Finset ι}
102102
simp_rw [mem_map, mem_attach, true_and, Subtype.exists, Embedding.coeFn_mk, exists_prop, and_comm,
103103
eq_comm]
104104

105+
theorem finsuppAntidiag_mono {s t : Finset ι} (h : s ⊆ t) (n : μ) :
106+
finsuppAntidiag s n ⊆ finsuppAntidiag t n := by
107+
intro a
108+
simp_rw [mem_finsuppAntidiag']
109+
rintro ⟨hsum, hmem⟩
110+
exact ⟨hsum, hmem.trans h⟩
111+
105112
variable [AddCommMonoid μ'] [HasAntidiagonal μ'] [DecidableEq μ']
106113

107114
-- This should work under the assumption that e is an embedding and an AddHom

Mathlib/Combinatorics/Enumerative/Partition.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ deriving DecidableEq
6060

6161
namespace Partition
6262

63+
theorem le_of_mem_parts {n : ℕ} {p : Partition n} {m : ℕ} (h : m ∈ p.parts) : m ≤ n := by
64+
simpa [p.parts_sum] using Multiset.le_sum_of_mem h
65+
6366
/-- A composition induces a partition (just convert the list to a multiset). -/
6467
@[simps]
6568
def ofComposition (n : ℕ) (c : Composition n) : Partition n where
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/-
2+
Copyright (c) 2025 Weiyi Wang. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Weiyi Wang
5+
-/
6+
import Mathlib.Combinatorics.Enumerative.Partition
7+
import Mathlib.RingTheory.PowerSeries.PiTopology
8+
9+
/-!
10+
# Generating functions for partition functions
11+
12+
This file defines generating functions related to partitions. Given a character function $f(i, c)$
13+
of a part $i$ and the number of the part $c$, the related generating function is
14+
$$
15+
G_f(X) = \sum_{n = 0}^{\infty} \left(\sum_{p \in P_{n}} \prod_{i \in p} f(i, \#i)\right) X^n
16+
= \prod_{i = 0}^{\infty}\left(1 + \sum_{j=0}^{\infty} f(i + 1, j + 1) X ^ {(i + 1)(j + 1)}\right)
17+
$$
18+
where $P_n$ is all partitions of $n$, $\#i$ is the times $i$ appears in the partition $p$.
19+
We give the definition `Nat.Partition.genFun` using the first equation, and prove the second
20+
equation in `Nat.Partition.hasProd_genFun`.
21+
22+
This generating function can be specialized to
23+
* When $f(i, c) = 1$, this is the generating function for partition function $p(n)$.
24+
* When $f(i, 1) = 1$ and $f(i, c) = 0$ for $c > 1$, this is the generating function for
25+
`#(Nat.Partition.distincts n)`.
26+
* When $f(i, c) = 1$ for odd $i$ and $f(i, c) = 0$ for even $i$, this is the generating function for
27+
`#(Nat.Partition.odds n)`.
28+
(TODO: prove these)
29+
30+
The definition of `Nat.Partition.genFun` ignores the value of $f(0, c)$ and $f(i, 0)$. The formula
31+
can be interpreted as assuming $f(i, 0) = 1$ and $f(0, c) = 0$ for $c \ne 0$. In theory we could
32+
respect the actual value of $f(0, c)$ and $f(i, 0)$, but it makes the otherwise finite sum and
33+
product potentially infinite.
34+
-/
35+
36+
open PowerSeries
37+
open scoped PowerSeries.WithPiTopology
38+
39+
namespace Nat.Partition
40+
variable {M : Type*} [CommSemiring M]
41+
42+
/-- Generating function associated with character $f(i, c)$ for partition functions. The character
43+
function is multiplied within one `n.Partition`, and summed among all `n.Partition` for
44+
a fixed `n`. -/
45+
def genFun (f : ℕ → ℕ → M) : M⟦X⟧ :=
46+
PowerSeries.mk fun n ↦ ∑ p : n.Partition, ∏ i ∈ p.parts.toFinset, f i (p.parts.count i)
47+
48+
variable [TopologicalSpace M]
49+
50+
/-- The infinite sum in the formula `Nat.Partition.hasProd_genFun` always converges. -/
51+
theorem summable_genFun_term (f : ℕ → ℕ → M) (i : ℕ) :
52+
Summable fun j ↦ f (i + 1) (j + 1) • (X : M⟦X⟧) ^ ((i + 1) * (j + 1)) := by
53+
rcases subsingleton_or_nontrivial M with h | h
54+
· simpa [Subsingleton.eq_zero] using summable_zero
55+
apply WithPiTopology.summable_of_tendsto_order_atTop_nhds_top
56+
refine ENat.tendsto_nhds_top_iff_natCast_lt.mpr (fun n ↦ Filter.eventually_atTop.mpr ⟨n, ?_⟩)
57+
intro m hm
58+
rw [PowerSeries.smul_eq_C_mul]
59+
refine (lt_of_lt_of_le (lt_add_of_nonneg_of_lt (by simp) ?_) (le_order_mul _ _))
60+
rw [order_X_pow]
61+
norm_cast
62+
grind
63+
64+
variable [T2Space M]
65+
66+
private theorem aux_injOn_sub_one_parts {n : ℕ} (p : Partition n) :
67+
Set.InjOn (fun x ↦ x - 1) p.parts.toFinset := by
68+
intro a ha b hb
69+
exact tsub_inj_left (p.parts_pos (by simpa using ha)) (p.parts_pos (by simpa using hb))
70+
71+
private theorem aux_map_sub_one_parts_subset {n : ℕ} (p : Partition n) :
72+
(Multiset.map (fun x ↦ x - 1) p.parts).toFinset ⊆ Finset.range n := by
73+
intro m
74+
rw [Multiset.mem_toFinset, Finset.mem_range]
75+
suffices ∀ x ∈ p.parts, x - 1 = m → m < n by simpa
76+
rintro x h1 rfl
77+
exact Nat.sub_one_lt_of_le (p.parts_pos h1) (le_of_mem_parts h1)
78+
79+
private theorem aux_mapsTo_sub_one_parts {n : ℕ} (p : Partition n) :
80+
Set.MapsTo (fun x ↦ x - 1) p.parts.toFinset (Finset.range n) := by
81+
intro a ha
82+
apply Finset.mem_of_subset (aux_map_sub_one_parts_subset p)
83+
rw [Multiset.mem_toFinset, Multiset.mem_map]
84+
exact ⟨a, by simpa using ha⟩
85+
86+
private def aux_toFinsuppAntidiag {n : ℕ} (p : Partition n) : ℕ →₀ ℕ where
87+
toFun m := p.parts.count (m + 1) * (m + 1)
88+
support := (p.parts.map (· - 1)).toFinset
89+
mem_support_toFun m := by
90+
suffices (∃ a ∈ p.parts, a - 1 = m) ↔ m + 1 ∈ p.parts by simpa
91+
trans (∃ a ∈ p.parts, a = m + 1)
92+
· refine ⟨fun ⟨a, h1, h2⟩ ↦ ⟨a, h1, ?_⟩, fun ⟨a, h1, h2⟩ ↦ ⟨a, h1, Nat.sub_eq_of_eq_add h2⟩⟩
93+
exact Nat.eq_add_of_sub_eq (Nat.one_le_of_lt (p.parts_pos h1)) h2
94+
· simp
95+
96+
private theorem aux_toFinsuppAntidiag_injective (n : ℕ) :
97+
Function.Injective (aux_toFinsuppAntidiag (n := n)) := by
98+
unfold aux_toFinsuppAntidiag
99+
intro p q h
100+
rw [Finsupp.mk.injEq] at h
101+
obtain ⟨hfinset, hcount⟩ := h
102+
rw [Nat.Partition.ext_iff, Multiset.ext]
103+
intro m
104+
obtain rfl | h0 := Nat.eq_zero_or_pos m
105+
· trans 0
106+
· rw [Multiset.count_eq_zero]
107+
exact fun h ↦ (lt_self_iff_false _).mp <| p.parts_pos h
108+
· symm
109+
rw [Multiset.count_eq_zero]
110+
exact fun h ↦ (lt_self_iff_false _).mp <| q.parts_pos h
111+
· refine Nat.eq_of_mul_eq_mul_right h0 <| ?_
112+
convert funext_iff.mp hcount (m - 1) <;> exact (Nat.sub_eq_iff_eq_add h0).mp rfl
113+
114+
private theorem aux_range_toFinsuppAntidiag (n : ℕ) :
115+
Set.range (aux_toFinsuppAntidiag (n := n)) ⊆ (Finset.range n).finsuppAntidiag n := by
116+
unfold aux_toFinsuppAntidiag
117+
rw [Set.range_subset_iff]
118+
intro p
119+
suffices ∑ m ∈ Finset.range n, Multiset.count (m + 1) p.parts * (m + 1) = n by
120+
simpa [aux_map_sub_one_parts_subset p]
121+
refine Eq.trans ?_ p.parts_sum
122+
simp_rw [Finset.sum_multiset_count, smul_eq_mul]
123+
refine (Finset.sum_of_injOn (· - 1) (aux_injOn_sub_one_parts p)
124+
(aux_mapsTo_sub_one_parts p) ?_ ?_).symm
125+
· suffices ∀ i ∈ Finset.range n, (∀ x ∈ p.parts, x - 1 ≠ i) → i + 1 ∉ p.parts by simpa
126+
intro i hi h
127+
contrapose! h
128+
exact ⟨i + 1, by simpa using h⟩
129+
· intro i hi
130+
suffices i - 1 + 1 = i by simp [this]
131+
rw [Nat.sub_add_cancel (Nat.one_le_of_lt (p.parts_pos (by simpa using hi)))]
132+
133+
private theorem aux_dvd_of_coeff_ne_zero {f : ℕ → ℕ → M} {d : ℕ} {s : Finset ℕ}
134+
{g : ℕ →₀ ℕ} (hg : g ∈ s.finsuppAntidiag d)
135+
(hprod : ∀ x ∈ s,
136+
(coeff (g x)) (1 + ∑' (j : ℕ), f (x + 1) (j + 1) • X ^ ((x + 1) * (j + 1))) ≠ (0 : M))
137+
(x : ℕ) : x + 1 ∣ g x := by
138+
by_cases hx : x ∈ s
139+
· specialize hprod x hx
140+
contrapose! hprod
141+
rw [map_add, (summable_genFun_term f x).map_tsum _ (WithPiTopology.continuous_coeff _ _)]
142+
rw [show (0 : M) = 0 + ∑' (i : ℕ), 0 by simp]
143+
congrm (?_ + ∑' (i : ℕ), ?_)
144+
· suffices g x ≠ 0 by simp [this]
145+
contrapose! hprod
146+
simp [hprod]
147+
· rw [map_smul, coeff_X_pow]
148+
apply smul_eq_zero_of_right
149+
suffices g x ≠ (x + 1) * (i + 1) by simp [this]
150+
contrapose! hprod
151+
simp [hprod]
152+
· suffices g x = 0 by simp [this]
153+
contrapose! hx
154+
exact Finset.mem_of_subset (Finset.mem_finsuppAntidiag.mp hg).2 <| by simpa using hx
155+
156+
private theorem aux_prod_coeff_eq_zero_of_notMem_range (f : ℕ → ℕ → M) {d : ℕ} {s : Finset ℕ}
157+
{g : ℕ →₀ ℕ} (hg : g ∈ s.finsuppAntidiag d)
158+
(hg' : g ∉ Set.range (aux_toFinsuppAntidiag (n := d))) :
159+
∏ i ∈ s, (coeff (g i)) (1 + ∑' (j : ℕ),
160+
f (i + 1) (j + 1) • X ^ ((i + 1) * (j + 1)) : M⟦X⟧) = 0 := by
161+
suffices ∃ i ∈ s, (coeff (g i)) ((1 : M⟦X⟧) +
162+
∑' (j : ℕ), f (i + 1) (j + 1) • X ^ ((i + 1) * (j + 1))) = 0 by
163+
obtain ⟨i, hi, hi'⟩ := this
164+
apply Finset.prod_eq_zero hi hi'
165+
contrapose! hg' with hprod
166+
rw [Set.mem_range]
167+
refine ⟨Nat.Partition.mk (Finsupp.toMultiset
168+
(Finsupp.mk (g.support.map (Function.Embedding.mk (· + 1) (add_left_injective 1)))
169+
(fun i ↦ if i = 0 then 0 else g (i - 1) / i) ?_)) (by simp) ?_, ?_⟩
170+
· intro a
171+
suffices (∃ b, g b ≠ 0 ∧ b + 1 = a) ↔ a ≠ 0 ∧ a ≤ g (a - 1) by simpa
172+
constructor
173+
· rintro ⟨b, h1, rfl⟩
174+
simpa using Nat.le_of_dvd (Nat.pos_of_ne_zero h1) <| aux_dvd_of_coeff_ne_zero hg hprod b
175+
· rintro ⟨h1, h2⟩
176+
exact ⟨a - 1, by grind⟩
177+
· obtain ⟨h1, h2⟩ := Finset.mem_finsuppAntidiag.mp hg
178+
refine Eq.trans ?_ h1
179+
suffices ∑ x ∈ g.support, g x / (x + 1) * (x + 1) = ∑ x ∈ s, g x by simpa [Finsupp.sum]
180+
rw [Finset.sum_subset h2 (by
181+
intro x _
182+
suffices g x = 0 → g x < x + 1 by simpa;
183+
grind)]
184+
exact Finset.sum_congr rfl fun x _ ↦ Nat.div_mul_cancel <| aux_dvd_of_coeff_ne_zero hg hprod x
185+
· ext x
186+
simpa [aux_toFinsuppAntidiag] using Nat.div_mul_cancel <| aux_dvd_of_coeff_ne_zero hg hprod x
187+
188+
private theorem aux_prod_f_eq_prod_coeff
189+
(f : ℕ → ℕ → M) {n : ℕ} (p : Partition n) {s : Finset ℕ} (hs : Finset.range n ≤ s) :
190+
∏ i ∈ p.parts.toFinset, f i (Multiset.count i p.parts) =
191+
∏ i ∈ s, coeff (p.aux_toFinsuppAntidiag i)
192+
(1 + ∑' j : ℕ, f (i + 1) (j + 1) • X ^ ((i + 1) * (j + 1))) := by
193+
refine Finset.prod_of_injOn (· - 1) (aux_injOn_sub_one_parts _)
194+
((aux_mapsTo_sub_one_parts p).mono_right hs) ?_ ?_
195+
· intro x hx h
196+
have hx : x + 1 ∉ p.parts := by
197+
contrapose! h
198+
exact ⟨x + 1, by simpa using h⟩
199+
have hsum := (summable_genFun_term f x).map_tsum _ (WithPiTopology.continuous_constantCoeff M)
200+
simp [aux_toFinsuppAntidiag, hx, hsum]
201+
· intro i hi
202+
have hi : i ∈ p.parts := by simpa using hi
203+
have hicancel : i - 1 + 1 = i := by
204+
rw [Nat.sub_add_cancel (Nat.one_le_of_lt (p.parts_pos hi))]
205+
rw [map_add, (summable_genFun_term f _).map_tsum _ (WithPiTopology.continuous_coeff _ _)]
206+
suffices f i (Multiset.count i p.parts) =
207+
∑' j : ℕ, if Multiset.count i p.parts * i = i * (j + 1) then f i (j + 1) else 0 by
208+
simpa [hicancel, aux_toFinsuppAntidiag, hi, Nat.ne_zero_of_lt (p.parts_pos hi), coeff_X_pow]
209+
rw [tsum_eq_single (Multiset.count i p.parts - 1) ?_]
210+
· rw [mul_comm]
211+
simp [Nat.sub_add_cancel (Multiset.one_le_count_iff_mem.mpr hi)]
212+
intro b hb
213+
suffices Multiset.count i p.parts * i ≠ i * (b + 1) by simp [this]
214+
rw [mul_comm i, (mul_left_inj' (Nat.ne_zero_of_lt (p.parts_pos hi))).ne]
215+
grind
216+
217+
theorem hasProd_genFun (f : ℕ → ℕ → M) :
218+
HasProd (fun i ↦ (1 : M⟦X⟧) + ∑' j : ℕ, f (i + 1) (j + 1) • X ^ ((i + 1) * (j + 1)))
219+
(genFun f) := by
220+
rw [HasProd, WithPiTopology.tendsto_iff_coeff_tendsto]
221+
refine fun d ↦ tendsto_atTop_of_eventually_const (fun s (hs : s ≥ Finset.range d) ↦ ?_)
222+
rw [genFun, coeff_mk, coeff_prod]
223+
refine (Finset.sum_of_injOn aux_toFinsuppAntidiag
224+
(aux_toFinsuppAntidiag_injective d).injOn ?_ ?_ ?_).symm
225+
· refine Set.MapsTo.mono_right (Set.mapsTo_range _ _) ((aux_range_toFinsuppAntidiag d).trans ?_)
226+
simpa using Finset.finsuppAntidiag_mono hs.le _
227+
· exact fun g hg hg' ↦ aux_prod_coeff_eq_zero_of_notMem_range f hg (by simpa using hg')
228+
· exact fun p _ ↦ aux_prod_f_eq_prod_coeff f p hs.le
229+
230+
end Nat.Partition

0 commit comments

Comments
 (0)