Partition basics #
This file formalizes the basic theory of integer partitions from Section "Partition basics" of the Algebraic Combinatorics textbook.
Main definitions #
IversonBracket.iverson- the Iverson bracket[P]converting propositions to 0 or 1FloorCeiling.floor_def- the floor function⌊a⌋(largest integer ≤ a)FloorCeiling.ceil_def- the ceiling function⌈a⌉(smallest integer ≥ a)Nat.Partition.partitionCount- the partition functionp(n), counting partitions ofnNat.Partition.partsCount- the functionp_k(n), counting partitions ofnintokpartsNat.Partition.largestPart- the largest part of a partition (0 for the empty partition)Nat.Partition.transpose- the conjugate/transpose of a partitionNat.Partition.partsLeqCount- count of partitions with parts ≤ mNat.Partition.partsInCount- count of partitions with parts in a set I
Main results #
Integer partitions (Definition \ref{def.pars.parts}) #
Nat.Partition.size_eq- The size of a partition equals the sum of parts (Definition \ref{def.pars.parts} (c))Nat.Partition.parts_pos'- All parts are positive (Definition \ref{def.pars.parts} (a))Nat.Partition.parts_le- Each part is bounded by the sizeNat.Partition.parts_eq_zero_of_partition_zero- The partition of 0 has no partsNat.Partition.parts_card_zero- The partition of 0 has length 0Nat.Partition.indiscrete_parts_card- The indiscrete partition (n) has one partNat.Partition.ofList'- Construct a partition from a list of positive integersNat.Partition.eq_iff_parts_eq- Partitions are determined by their parts
Iverson bracket (Definition \ref{def.pars.iverson}) #
IversonBracket.iverson-[P] = 1ifPis true,[P] = 0ifPis falseIversonBracket.iverson_true-[P] = 1whenPis trueIversonBracket.iverson_false-[P] = 0whenPis falseIversonBracket.kronecker_eq_iverson- Kronecker deltaδ_{i,j} = [i = j]IversonBracket.sum_iverson_eq_card-∑ [P(x)] = |{x : P(x)}|IversonBracket.iverson_and-[P ∧ Q] = [P] * [Q]IversonBracket.iverson_not-[¬P] = 1 - [P]IversonBracket.iverson_or-[P ∨ Q] = [P] + [Q] - [P] * [Q]IversonBracket.iverson_imp-[P → Q] = 1 - [P] * (1 - [Q])
Floor and ceiling (Definition \ref{def.pars.floor-ceil}) #
FloorCeiling.floor_def-n ≤ ⌊a⌋ ↔ n ≤ a(characterization of floor)FloorCeiling.ceil_def-⌈a⌉ ≤ n ↔ a ≤ n(characterization of ceiling)FloorCeiling.floor_of_int-⌊n⌋ = nfor integersFloorCeiling.ceil_of_int-⌈n⌉ = nfor integersFloorCeiling.nat_div_eq_floor-n / m = ⌊n/m⌋for natural numbers
Basic properties (Proposition \ref{prop.pars.basics}) #
Nat.Partition.partsCount_of_gt-p_k(n) = 0whenk > nNat.Partition.partsCount_of_gt'-@[simp]lemma forp_k(n) = 0whenn < kNat.Partition.partsCount_eq_zero_iff-p_k(n) = 0iffk > nork = 0 ∧ n > 0Nat.Partition.partsCount_zero-p_0(n) = [n = 0]Nat.Partition.partsCount_one-p_1(n) = [n > 0]Nat.Partition.partsCount_recurrence-p_k(n) = p_k(n-k) + p_{k-1}(n-1)fork > 0andn > 0Nat.Partition.partsCount_two-p_2(n) = ⌊n/2⌋forn ∈ ℕNat.Partition.partitionCount_sum-p(n) = p_0(n) + p_1(n) + ... + p_n(n)forn ∈ ℕ
Generating functions (Theorems \ref{thm.pars.main-gf}, \ref{thm.pars.main-gf-parts-n}, \ref{thm.pars.main-gf-parts-I}, \ref{thm.pars.main-gf-0n}) #
Nat.Partition.partitionCount_genFun-∑ p(n) x^n = ∏_{k≥1} 1/(1-x^k)Nat.Partition.partitionCount_genFun_partsLeq-∑ p_{parts≤m}(n) x^n = ∏_{k=1}^m 1/(1-x^k)Nat.Partition.partitionCount_genFun_partsIn-∑ p_I(n) x^n = ∏_{k∈I} 1/(1-x^k)Nat.Partition.partsCountSum_genFun-∑ (p_0(n) + ... + p_m(n)) x^n = ∏_{k=1}^m 1/(1-x^k)
Odd-distinct theorem (Theorem \ref{thm.pars.odd-dist-equal}) #
Nat.Partition.card_odds_eq_card_distincts- Euler's odd-distinct identity (from Mathlib)
Conjugation (Proposition \ref{prop.pars.pkn=dual}) #
Nat.Partition.partsCount_eq_largestPartCount-p_k(n) = #{ partitions of n with largest part k }
Counting by parts and largest (Proposition \ref{prop.pars.qbinom.intro-count-binom}) #
Nat.Partition.partsAndLargestCountTotal_eq-#{ partitions with k parts and largest ℓ } = C(k+ℓ-2, k-1)
Partition numbers and divisor sums (Theorem \ref{thm.pars.sigma1}) #
Nat.Partition.partitionCount_divisorSum-n·p(n) = ∑_{k=1}^n σ(k)·p(n-k)
Implementation notes #
We use Mathlib's Nat.Partition type which represents a partition as a multiset of positive
integers. This is equivalent to the "weakly decreasing tuple" representation in the source text.
The functions partsCount and partitionCount are defined as cardinalities of finite sets,
which automatically ensures they are nonnegative. For negative n, there are no partitions,
so these functions return 0 naturally.
The generating function theorems use Mathlib's HasProd to express convergent infinite products
in the power series topology. The identity ∏_{k≥1} 1/(1-x^k) is expressed as
∏_{k≥1} ∑_{j≥0} x^{kj} since the geometric series 1/(1-x^k) = ∑_{j≥0} x^{kj}.
References #
- The source text: Algebraic Combinatorics, Section on Partition Basics
- Mathlib:
Mathlib.Combinatorics.Enumerative.Partition.Basic - Mathlib:
Mathlib.Combinatorics.Enumerative.Partition.GenFun - Mathlib:
Mathlib.Combinatorics.Enumerative.Partition.Glaisher
Iverson bracket notation (Definition \ref{def.pars.iverson}) #
The Iverson bracket notation represents the truth value of a proposition P:
In Lean, this is represented as if P then 1 else 0 or equivalently (decide P).toNat.
The Kronecker delta δ_{i,j} is a special case: δ_{i,j} = [i = j].
The Iverson bracket converts a proposition to its truth value (0 or 1). (Definition \ref{def.pars.iverson})
This is the standard way to embed boolean values into a semiring:
In Mathlib, this is if P then 1 else 0 or (decide P).toNat for naturals.
Equations
- IversonBracket.iverson P = if P then 1 else 0
Instances For
Notation ⦃P⦄ for the Iverson bracket.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The Kronecker delta is a special case of the Iverson bracket: δ_{i,j} = [i = j].
In Mathlib, this is represented by Pi.single i 1 j for dependent functions,
or if i = j then 1 else 0 directly.
The Iverson bracket for natural numbers equals Bool.toNat of the decision.
Sum of Iverson brackets equals cardinality of the filtered set.
The Iverson bracket satisfies [P]² = [P] (idempotent under multiplication).
Floor and ceiling functions (Definition \ref{def.pars.floor-ceil}) #
The floor of a real number a, denoted ⌊a⌋, is the largest integer that is ≤ a.
The ceiling of a real number a, denoted ⌈a⌉, is the smallest integer that is ≥ a.
In Mathlib, these are provided by the FloorRing and FloorSemiring typeclasses:
Int.floorgives the floor as an integerInt.ceilgives the ceiling as an integerNat.floorgives the floor as a natural number (for nonnegative inputs)Nat.ceilgives the ceiling as a natural number (for nonnegative inputs)
The notation ⌊a⌋ and ⌈a⌉ is available via import Mathlib.
Definition (def.pars.floor-ceil) #
Let a be a real number.
⌊a⌋(the floor ofa) is the largest integer that is ≤ a.⌈a⌉(the ceiling ofa) is the smallest integer that is ≥ a.
Examples from the textbook #
The textbook gives π ≈ 3.14 as an example. We use 3.14 directly as a rational.
Connection to natural number division #
Additional properties #
Definition of integer partitions (Definition \ref{def.pars.parts}) #
This section formalizes Definition \ref{def.pars.parts} from the source text.
In Mathlib, Nat.Partition n represents partitions of n. The underlying data is a
multiset of positive integers that sums to n. This is equivalent to the "weakly
decreasing tuple" representation in the source text:
Definition \ref{def.pars.parts}:
(a) An (integer) partition means a (finite) weakly decreasing tuple of positive integers -- i.e., a finite tuple (λ₁, λ₂, ..., λₘ) of positive integers such that λ₁ ≥ λ₂ ≥ ... ≥ λₘ.
(b) The parts of a partition (λ₁, λ₂, ..., λₘ) are simply its entries λ₁, λ₂, ..., λₘ.
(c) Let n ∈ ℤ. A partition of n means a partition whose size is n.
(d) Let n ∈ ℤ and k ∈ ℕ. A partition of n into k parts is a partition whose size is n and whose length is k.
Implementation note: Mathlib uses multisets rather than tuples, which is equivalent since partitions are determined by their parts (with multiplicity), regardless of order. The "weakly decreasing" constraint in the tuple representation is automatically satisfied when we sort the multiset in decreasing order.
Parts of a partition (Definition \ref{def.pars.parts} (b)) #
In Mathlib, Partition.parts returns the multiset of parts. Each part is a positive
integer (guaranteed by parts_pos), and the sum of parts equals the size
(guaranteed by parts_sum).
The parts are the fundamental data of a partition. They are positive integers
whose sum equals the size n. We use Mathlib's Partition.parts directly rather than
redefining it, and provide wrapper lemmas for the key properties.
The size of a partition is the sum of its parts. (Definition \ref{def.pars.parts} (c))
For a partition of n, the size is n. This is guaranteed by Partition.parts_sum.
The type Partition n itself encodes that the partition has size n.
All parts of a partition are positive. (Definition \ref{def.pars.parts} (a) - "tuple of positive integers")
This is a fundamental property: every entry in a partition is ≥ 1. This is the defining property that distinguishes partitions from weak compositions.
The empty partition is the unique partition of 0. (Definition \ref{def.pars.parts} (a) - empty tuple case)
The partition of 0 has no parts.
For n > 0, the indiscrete partition (n) has exactly one part. (Example of Definition \ref{def.pars.parts})
The parts of the indiscrete partition (n) for n > 0. (Example of Definition \ref{def.pars.parts})
Constructing a partition from a list of positive integers. (Definition \ref{def.pars.parts} (a) - the tuple representation)
Given a list of positive integers that sums to n, we can construct a partition of n.
The list need not be sorted; Mathlib's Partition uses multisets.
Equations
- Nat.Partition.ofList' l hl_pos hl_sum = { parts := ↑l, parts_pos := ⋯, parts_sum := ⋯ }
Instances For
Examples from the textbook (Example \ref{exa.pars.pars5}) #
The partitions of 5 are:
- (5): one part
- (4,1): two parts
- (3,2): two parts
- (3,1,1): three parts
- (2,2,1): three parts
- (2,1,1,1): four parts
- (1,1,1,1,1): five parts
Auxiliary lemmas #
Elements of a multiset are bounded by the fold max.
Extending the range of summation when elements are bounded.
The number of i < M with i < x is exactly min x M.
Double counting: sum of filter cardinalities equals multiset sum.
Filtering out zeros doesn't change the sum.
Partition counting functions #
The partition function p(n): the number of partitions of n.
(Definition \ref{def.pars.pn-pkn} (b))
Equations
Instances For
The number of partitions of n with all parts ≤ m.
(Used in Theorem \ref{thm.pars.main-gf-parts-n})
Equations
- Nat.Partition.partsLeqCount m n = (Nat.Partition.restricted n fun (x : ℕ) => x ≤ m).card
Instances For
The number of partitions of n with all parts in a set I.
(Used in Theorem \ref{thm.pars.main-gf-parts-I})
Equations
- Nat.Partition.partsInCount I n = (Nat.Partition.restricted n fun (x : ℕ) => x ∈ I).card
Instances For
Basic API for partition counting functions #
p(0) = 1: there is exactly one partition of 0 (the empty partition).
(Definition \ref{def.pars.pn-pkn} (b), special case)
p(1) = 1: there is exactly one partition of 1 (the partition (1)).
p(n) > 0 for all n ∈ ℕ: there is always at least one partition of any natural number.
For n > 0, the partition (n) has one part. For n = 0, the empty partition works.
Examples from the textbook #
The following examples verify the definitions against the values given in the textbook following Definition \ref{def.pars.pn-pkn}.
Basic properties of partition numbers #
Alternative characterization: partsCount k n counts partitions with numParts = k.
The largest part of a partition (0 for the empty partition). (Convention \ref{conv.pars.largest-part-0})
Equations
- p.largestPart = Multiset.fold max 0 p.parts
Instances For
A partition has largest part ≤ m iff all its parts are ≤ m. This is because the largest part is defined as the maximum of all parts.
This lemma is key for proving Theorem \ref{thm.pars.main-gf-0n}, which states that
the generating function for p_0(n) + p_1(n) + ... + p_m(n) equals ∏_{k=1}^m 1/(1-x^k).
The proof uses:
- Corollary \ref{cor.pars.p0kn=dual}: the sum equals the count of partitions with largest part ≤ m
- This lemma: "largest part ≤ m" is equivalent to "all parts ≤ m"
- Theorem \ref{thm.pars.main-gf-parts-n}: the generating function for "all parts ≤ m"
The set of partitions with largest part ≤ m equals the set of partitions
with all parts ≤ m (i.e., restricted n (· ≤ m)).
This is a key equivalence used in the proof of Theorem \ref{thm.pars.main-gf-0n}.
Partitions of 0 have no parts.
The largest part of the partition of 0 is 0. (Convention conv.pars.largest-part-0)
Since the partition of 0 has no parts, the largest part (defined as the maximum of all parts, with 0 as the default) is 0.
For a partition of n, the largest part is at most n.
This parallels the existing numParts_le lemma which states p.numParts ≤ n.
For a partition of n > 0, the largest part is positive.
This parallels largestPart_zero (for n = 0) and largestPart_le.
Since n > 0, the partition has at least one part (by numParts_pos),
and all parts are positive (by parts_pos). The largest part
(fold max 0) of a non-empty multiset of positive numbers is positive.
For a partition of n > 0, the number of parts is positive.
This parallels numParts_zero (for n = 0) and numParts_le.
There are no partitions of n into more than n parts.
(Proposition \ref{prop.pars.basics} (b))
p_k(n) = 0 when n < k: alternative form of partsCount_of_gt with
the hypothesis n < k instead of k > n, useful for simp.
(Proposition \ref{prop.pars.basics} (b))
p_0(n) = [n = 0]: the only partition into 0 parts is the empty partition of 0.
(Proposition \ref{prop.pars.basics} (c))
There are no partitions of n > 0 into exactly 0 parts.
This is a simp-friendly form of partsCount_zero for positive n.
(Corollary of Proposition \ref{prop.pars.basics} (c))
partsCount k n = 0 iff k > n or k = 0 ∧ n > 0.
This provides a complete characterization of when the partition count is zero.
p_1(n) = [n > 0]: the only partition of a positive n into 1 part is (n).
(Proposition \ref{prop.pars.basics} (d))
Helper lemmas for the recurrence relation #
Equations
Partitions of n into k parts that contain 1.
Equations
- Nat.Partition.partsWithOne k n = {p : n.Partition | p.parts.card = k ∧ p.containsOne}
Instances For
Partitions of n into k parts that don't contain 1.
Equations
- Nat.Partition.partsWithoutOne k n = {p : n.Partition | p.parts.card = k ∧ ¬p.containsOne}
Instances For
Subtract 1 from each part of a partition (when all parts > 1) to get a partition of n - k.
Equations
- p.subtractOneFromEach hk h = Nat.Partition.ofSums (n - k) (Multiset.map (fun (x : ℕ) => x - 1) p.parts) ⋯
Instances For
Add 1 to each part of a partition to get a partition of n + k.
Equations
- p.addOneToEach hk = Nat.Partition.ofSums (n + k) (Multiset.map (fun (x : ℕ) => x + 1) p.parts) ⋯
Instances For
Bijection: partsWithOne k n ↔ partitions of (n-1) into (k-1) parts.
Bijection: partsWithoutOne k n ↔ partitions of (n-k) into k parts.
The recurrence relation for partition numbers:
p_k(n) = p_k(n-k) + p_{k-1}(n-1) for k > 0 and n > 0.
(Proposition \ref{prop.pars.basics} (e))
Note: The hypothesis n > 0 is required because in natural number arithmetic,
0 - 1 = 0, so the recurrence fails for k = 1, n = 0:
- LHS =
p_1(0) = 0 - RHS =
p_1(0) + p_0(0) = 0 + 1 = 1
This classifies partitions into:
- Type 1: partitions with 1 as a part (bijection with partitions of n-1 into k-1 parts)
- Type 2: partitions without 1 (subtract 1 from each part → partitions of n-k into k parts)
The proof requires establishing two bijections:
- {partitions of n into k parts containing 1} ↔ {partitions of n-1 into k-1 parts} via removeOne/addOne
- {partitions of n into k parts not containing 1} ↔ {partitions of n-k into k parts} via subtractOneFromEach/addOneToEach
p_2(n) = ⌊n/2⌋ for n ∈ ℕ.
(Proposition \ref{prop.pars.basics} (f))
The partitions of n into 2 parts are (n-1,1), (n-2,2), ..., (⌈n/2⌉, ⌊n/2⌋).
p(n) = p_0(n) + p_1(n) + ... + p_n(n) for n ∈ ℕ.
(Proposition \ref{prop.pars.basics} (g))
Generating functions #
The generating function for partition numbers:
∑_{n≥0} p(n) x^n = ∏_{k≥1} 1/(1-x^k).
(Theorem \ref{thm.pars.main-gf})
More precisely, this states that the power series whose n-th coefficient is the number of partitions of n equals the infinite product ∏{k≥1} (∑{j≥0} x^{kj}).
The product converges in the power series topology because multiplying by 1/(1-x^k) = ∑_{j≥0} x^{kj} doesn't affect the first k coefficients.
The proof uses Mathlib's hasProd_powerSeriesMk_card_restricted with the trivially
true predicate.
The generating function for partitions with parts ≤ m:
∑_{n≥0} p_{parts≤m}(n) x^n = ∏_{k=1}^m 1/(1-x^k).
(Theorem \ref{thm.pars.main-gf-parts-n})
This is a finite product version of the partition generating function. The product is over k from 1 to m, expressed here with shifted index as a conditional infinite product.
The generating function for partitions with parts ≤ m, expressed as a finite product:
∑_{n≥0} p_{parts≤m}(n) x^n = ∏_{k=1}^m (∑_{j≥0} x^{kj}).
(Theorem \ref{thm.pars.main-gf-parts-n})
This is the same theorem as partitionCount_genFun_partsLeq, but expressed
as an equality of power series rather than a HasProd statement.
The product ∏_{k=1}^m (∑_{j≥0} x^{kj}) equals ∏_{k=1}^m 1/(1-x^k) since
the geometric series 1/(1-x^k) = ∑_{j≥0} x^{kj} converges in the power series topology.
The number of partitions with parts ≤ m equals the n-th coefficient of the finite product ∏{k=1}^m (∑{j≥0} x^{kj}). (Corollary to Theorem \ref{thm.pars.main-gf-parts-n})
The generating function for partitions with parts in a set I:
∑_{n≥0} p_I(n) x^n = ∏_{k∈I} 1/(1-x^k).
(Theorem \ref{thm.pars.main-gf-parts-I})
This generalizes both the standard partition generating function (I = ℕ⁺) and the finite product version (I = {1, ..., m}).
The product is over k in I, expressed here with shifted index as a conditional
infinite product. Each factor ∑' j, X^((k+1)*j) equals 1/(1-X^(k+1)) as
a geometric series.
Proof sketch: The bijection from the TeX source maps each essentially finite
family (u_i)_{i∈I} of nonnegative integers to the partition containing each
i ∈ I exactly u_i times. The coefficient of X^n on the product side counts
such families with ∑_{i∈I} i·u_i = n, which bijects with partitions of n
having all parts in I.
The infinite product form of the generating function for partitions with parts in I.
This is the tprod version of partitionCount_genFun_partsIn.
Expresses the generating function as an unconditional infinite product.
The infinite product for partitions with parts in I is multipliable. This is useful when manipulating the product form of the generating function.
Odd parts and distinct parts #
This section formalizes Euler's odd-distinct identity (Theorem \ref{thm.pars.odd-dist-equal}), which states that the number of partitions of n into odd parts equals the number of partitions of n into distinct parts.
Definition \ref{def.pars.odd-dist-parts} #
- A partition into odd parts is a partition whose all parts are odd.
- A partition into distinct parts is a partition whose parts are all different.
p_odd(n)= number of partitions of n into odd partsp_dist(n)= number of partitions of n into distinct parts
Theorem \ref{thm.pars.odd-dist-equal}: Euler's Odd-Distinct Identity #
We have p_odd(n) = p_dist(n) for each n ∈ ℕ.
Generating Function Proof #
The identity follows from the generating function identity:
∏_{i>0} (1-x^{2i-1})^{-1} = ∏_{k>0} (1+x^k)
The LHS generates partitions into odd parts (each odd k can appear any number of times). The RHS generates partitions into distinct parts (each k appears 0 or 1 times).
Bijective Proof #
Map A: odd parts → distinct parts Given a partition λ into odd parts, repeatedly merge pairs of equal parts until no equal parts remain. The result A(λ) is a partition into distinct parts.
Example: (5,5,3,1,1,1) → (10,3,2,1) by merging (5,5)→10 and (1,1)→2.
This is well-defined because merging equal odd parts produces even parts, and the process terminates. The final partition has distinct parts because if k appears m times in the original partition, then in A(λ), the parts 2^0·k, 2^1·k, 2^2·k, ... appear according to the binary representation of m.
Map B: distinct parts → odd parts Given a partition λ into distinct parts, repeatedly split even parts into halves until only odd parts remain.
Example: (10,3,2,1) → (5,5,3,1,1,1) by splitting 10→(5,5) and 2→(1,1).
The maps A and B are mutually inverse, establishing the bijection.
A partition into odd parts is a partition whose all parts are odd. (Definition \ref{def.pars.odd-dist-parts} (a))
For example, (7), (5,1,1), (3,3,1), (3,1,1,1,1), (1,1,1,1,1,1,1) are the partitions of 7 into odd parts.
Equations
- p.IsOddParts = ∀ i ∈ p.parts, Odd i
Instances For
A partition into distinct parts is a partition whose parts are all different. (Definition \ref{def.pars.odd-dist-parts} (b))
For example, (7), (6,1), (5,2), (4,3), (4,2,1) are the partitions of 7 into distinct parts. Note that repeated parts are not allowed.
Equations
- p.IsDistinctParts = p.parts.Nodup
Instances For
The number of partitions of n into odd parts: p_odd(n).
(Definition \ref{def.pars.odd-dist-parts} (c))
This counts the partitions of n where every part is an odd number.
Uses Mathlib's Nat.Partition.odds which filters partitions by the
predicate ¬Even (equivalent to Odd for positive integers).
Equations
Instances For
The number of partitions of n into distinct parts: p_dist(n).
(Definition \ref{def.pars.odd-dist-parts} (c))
This counts the partitions of n where all parts are different (no repeats).
Uses Mathlib's Nat.Partition.distincts which filters partitions by
the Nodup predicate on the parts multiset.
Equations
Instances For
Equations
- p.instDecidableIsOddParts = inferInstanceAs (Decidable (∀ i ∈ p.parts, Odd i))
Equations
Examples from the textbook (following Definition \ref{def.pars.odd-dist-parts}) #
p_odd(0) = 1: the only partition of 0 into odd parts is the empty partition.
(Following Definition \ref{def.pars.odd-dist-parts})
p_dist(0) = 1: the only partition of 0 into distinct parts is the empty partition.
(Following Definition \ref{def.pars.odd-dist-parts})
API for IsOddParts and IsDistinctParts #
The empty partition (of 0) is trivially a partition into odd parts.
The empty partition (of 0) is trivially a partition into distinct parts.
A partition is into odd parts iff all its parts satisfy Odd.
A partition is into distinct parts iff its parts multiset has no duplicates.
Alternative characterization: a partition is into distinct parts iff each part appears at most once.
Characterization of odds in terms of IsOddParts.
Characterization of distincts in terms of IsDistinctParts.
The counting function oddPartsCount equals the cardinality of the filter.
The counting function distinctPartsCount equals the cardinality of the filter.
Euler's odd-distinct identity: the number of partitions of n into odd parts equals the number of partitions of n into distinct parts. (Theorem \ref{thm.pars.odd-dist-equal})
This is Theorem 45 from Freek Wiedijk's list of 100 theorems.
The proof in Mathlib uses Glaisher's theorem, which generalizes this result: for any positive integer d, the number of partitions with parts not divisible by d equals the number of partitions where no part is repeated d or more times. Euler's identity is the special case d = 2.
The bijective proof (sketched in the module docstring) works by:
- Merging pairs of equal parts (odd → distinct)
- Splitting even parts into halves (distinct → odd)
Euler's odd-distinct identity in terms of counting functions.
The odd-distinct identity stated with predicates.
Conjugation / Transposition of partitions #
The transpose (conjugate) of a partition. For a partition λ = (λ₁, λ₂, ..., λₖ), the transpose λᵗ is defined by:
- The Young diagram of λᵗ is the transpose of the Young diagram of λ
- Equivalently: (λᵗ)ᵢ = #{j : λⱼ ≥ i}
The transpose satisfies:
- |λᵗ| = |λ| (same size)
- (λᵗ)ᵗ = λ (involution)
- length(λᵗ) = largest part of λ
- largest part of λᵗ = length(λ)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Helper lemma: for a sorted decreasing list, the count of elements > i is > j iff the j-th element > i. This is the key bijection for the Young diagram transpose.
The transpose is an involution.
The proof uses the fundamental property that transposing a Young diagram twice gives back the original diagram. For a partition λ = (λ₁, λ₂, ..., λₖ):
- The transpose λᵗ has parts μⱼ = #{i : λᵢ ≥ j} for j = 1, ..., λ₁
- Applying transpose again: #{j : μⱼ ≥ i} = λᵢ for all i
This is because the number of columns of height ≥ i in the Young diagram of λᵗ equals the i-th row length of λ.
Key lemma: for i < largest, the filter count is positive
The length of the transpose equals the largest part of the original partition.
The largest part of the transpose equals the length of the original partition.
The number of partitions of n into k parts equals the number of partitions of n whose largest part is k. (Proposition \ref{prop.pars.pkn=dual})
This follows from the fact that transpose is a bijection that swaps "number of parts" with "largest part".
Corollary: p_0(n) + p_1(n) + ... + p_k(n) equals the number of partitions
of n whose largest part is ≤ k.
(Corollary \ref{cor.pars.p0kn=dual})
The sum p_0(n) + p_1(n) + ... + p_m(n) equals the count of partitions with all parts ≤ m.
This combines Corollary \ref{cor.pars.p0kn=dual} (sum equals count with largest part ≤ m)
with the equivalence "largest part ≤ m" ↔ "all parts ≤ m" from filter_largestPart_le_eq_restricted.
The generating function for the sum p_0(n) + p_1(n) + ... + p_m(n):
∑_{n≥0} (p_0(n) + p_1(n) + ... + p_m(n)) x^n = ∏_{k=1}^m 1/(1-x^k).
(Theorem \ref{thm.pars.main-gf-0n})
The proof uses three key facts:
- Corollary \ref{cor.pars.p0kn=dual}:
p_0(n) + p_1(n) + ... + p_m(n)equals the number of partitions of n with largest part ≤ m. - Equivalence: "largest part ≤ m" is equivalent to "all parts ≤ m" (this is obvious from the definition of largest part as the maximum).
- Theorem \ref{thm.pars.main-gf-parts-n}: The generating function for partitions
with all parts ≤ m is
∏_{k=1}^m 1/(1-x^k).
The product ∏_{k=1}^m 1/(1-x^k) is represented here as ∏_{k=0}^{m-1} (∑_{j≥0} x^{(k+1)j})
since the geometric series 1/(1-x^k) = ∑_{j≥0} x^{kj} converges in the power series topology.
Counting partitions by parts and largest part #
The count of partitions with exactly k parts and largest part ℓ, for a specific size n.
Equations
- Nat.Partition.partsAndLargestCount k ℓ n = {p : n.Partition | p.numParts = k ∧ p.largestPart = ℓ}.card
Instances For
The total count of partitions with exactly k parts and largest part ℓ (summed over all sizes). The size ranges from k (minimum, when all parts are 1 except the largest) to k*ℓ (maximum, when all parts equal ℓ).
Equations
- Nat.Partition.partsAndLargestCountTotal k ℓ = ∑ n ∈ Finset.Icc k (k * ℓ), Nat.Partition.partsAndLargestCount k ℓ n
Instances For
Helper lemmas for the bijection #
The following lemmas provide infrastructure for the bijection proof in partsAndLargestCountTotal_eq.
They establish key properties of the forward map (Sym → Partition):
symToPartsMultiset: constructs partition parts from a SymsymToPartsMultiset_pos: all parts are positivesymToPartsMultiset_card: cardinality is ksymToPartsMultiset_fold_max: largest part is ℓsymToPartsMultiset_erase: erasing ℓ recovers the Sym elementssymToPartsMultiset_sum_range: sum lies in the valid range [k, k*ℓ]
The backward map (Partition → Sym) uses Multiset.pmap to map each part x in
p.parts.erase ℓ to ⟨x - 1, ...⟩ : Fin ℓ, which is valid since all such parts
are in {1, ..., ℓ}.
The Equiv construction is completed in partsAndLargestCountTotal_eq using
Equiv.ofBijective with toSigma_injective and toSigma_surj.
The cardinality of symToPartsMultiset is n + 1.
The largest part (fold max 0) of symToPartsMultiset is ℓ.
Erasing ℓ from symToPartsMultiset recovers the mapped parts.
Proposition \ref{prop.pars.qbinom.intro-count-binom}: For positive integers k and ℓ, the number of partitions with exactly k parts and largest part ℓ equals C(k+ℓ-2, k-1).
Proof outline: A partition with k parts and largest part ℓ has the form (ℓ, λ₂, ..., λₖ) where ℓ ≥ λ₂ ≥ ... ≥ λₖ ≥ 1.
The tuple (λ₂, ..., λₖ) is a weakly decreasing sequence of k-1 positive integers, each at most ℓ. This is equivalent to choosing a (k-1)-element multisubset of {1, 2, ..., ℓ}, which by the "stars and bars" formula equals C(ℓ + (k-1) - 1, k-1) = C(k + ℓ - 2, k - 1).
Note: This formula is independent of the size n of the partition.
Bijection details:
- Forward: partition (ℓ, λ₂, ..., λₖ) ↦ multiset {λ₂-1, ..., λₖ-1} ⊆ Fin ℓ
- Backward: multiset {a₁, ..., aₖ₋₁} ⊆ Fin ℓ ↦ partition (ℓ, a₁+1, ..., aₖ₋₁+1) sorted
This is well-defined because:
- Each λᵢ ∈ {1, ..., ℓ}, so λᵢ - 1 ∈ {0, ..., ℓ-1} = Fin ℓ
- Each aᵢ ∈ Fin ℓ gives aᵢ + 1 ∈ {1, ..., ℓ}
- The resulting partition has largest part ℓ (which is explicitly the first part)
- The partition has k parts (one ℓ, plus k-1 from the multiset)
Examples verifying the formula #
The following examples verify the formula C(k+ℓ-2, k-1) against computed values:
- k=1, ℓ=1: C(0,0) = 1. Partition: (1).
- k=1, ℓ=5: C(4,0) = 1. Partition: (5).
- k=2, ℓ=1: C(1,1) = 1. Partition: (1,1).
- k=2, ℓ=2: C(2,1) = 2. Partitions: (2,1), (2,2).
- k=2, ℓ=3: C(3,1) = 3. Partitions: (3,1), (3,2), (3,3).
- k=3, ℓ=2: C(3,2) = 3. Partitions: (2,1,1), (2,2,1), (2,2,2).
Partition numbers and divisor sums #
The sum of divisors function σ(n) = ∑_{d|n} d.
This is ArithmeticFunction.sigma 1 in Mathlib.
Equations
Instances For
Proof of Theorem σ₁ (thm.pars.sigma1) #
We prove the recurrence n · p(n) = ∑_{k=1}^n σ(k) · p(n-k) using generating functions.
Proof outline (from the TeX source) #
Define the generating functions:
P := ∑_{n≥0} p(n) x^n(the partition generating function)S := ∑_{k≥1} σ(k) x^k(the divisor sum generating function)
The key identity is X · P' = S · P, which we prove using logarithmic derivatives.
Since P = ∏_{k≥1} 1/(1-x^k), taking the logarithmic derivative gives:
P'/P = ∑_{k≥1} loder(1/(1-x^k))
= ∑_{k≥1} kx^{k-1}/(1-x^k)
= ∑_{n≥1} σ(n) x^{n-1}
Multiplying by xP gives xP' = SP.
Comparing coefficients of x^n on both sides:
- LHS: coefficient of
x^ninxP'isn · p(n) - RHS: coefficient of
x^ninSPis∑_{k=1}^n σ(k) · p(n-k)
This proves the theorem.
The partition generating function P = ∑_{n≥0} p(n) x^n, specialized to ℤ coefficients.
Equations
- Nat.Partition.P = Nat.Partition.genFun fun (x x_1 : ℕ) => 1
Instances For
The coefficient of x^n in P equals p(n).
The divisor sum generating function S = ∑_{k≥1} σ(k) x^k.
Equations
- Nat.Partition.S = PowerSeries.mk fun (n : ℕ) => if n = 0 then 0 else ↑(Nat.Partition.divisorSum n)
Instances For
The coefficient of x^n in X · P' equals n · p(n).
The coefficient of x^n in S · P equals ∑_{k=1}^n σ(k) · p(n-k).
LHS of the identity equals sum of parts over all partitions.
Helper lemmas for partitionCount_divisorSum_restricted #
These lemmas establish the key pieces needed for the double-counting proof:
- Bijection lemma: Removing j copies of d from a partition gives a partition of n - d*j
- Count sum identity: ∑p count(d, p) = ∑{j≥1} |{p : count(d,p) ≥ j}|
- Sum swap lemma: Swap the order of summation over partitions and parts
- Divisor sum reindexing: Transform ∑k ∑{d | k+1} to ∑d ∑{j : d*j ≤ n}
Remove j copies of element d from a partition, getting a partition of n - d*j. This is the forward direction of the bijection.
Equations
- p.removePartCopies d j _hd hj = { parts := p.parts - Multiset.replicate j d, parts_pos := ⋯, parts_sum := ⋯ }
Instances For
Add j copies of element d to a partition, getting a partition of m + d*j. This is the backward direction of the bijection.
Equations
- q.addPartCopies d j hd = { parts := q.parts + Multiset.replicate j d, parts_pos := ⋯, parts_sum := ⋯ }
Instances For
Helper: count(d, p) ≤ n/d for any partition of n and d > 0. This is the tight bound: at most n/d copies of d can fit in a partition of n.
The count sum identity: ∑p count(d, p) = ∑{j=1}^{max_count} |{p : count(d,p) ≥ j}|. This is the standard identity that sum of values equals sum of "at least j" counts.
The proof uses double counting: each partition p with count(d,p) = c contributes c to the LHS and is counted in exactly c of the sets {p : count(d,p) ≥ j+1} for j < c.
Partitions with count(d, p) ≥ j biject with partitions of n - dj. Specifically, {p ∈ restricted n I : count(d,p) ≥ j} ≃ restricted (n - dj) I.
Forward: remove j copies of d Backward: add j copies of d
Divisor sum reindexing: swaps the order of summation from ∑{k=0}^{n-1} ∑{d | k+1, d ∈ I} to ∑{d ∈ I, d ≤ n} ∑{j=1}^{⌊n/d⌋}.
The bijection is: (k, d) ↔ (d, j) where k = dj - 1, j = (k+1)/d. This transforms the constraint "d | k+1" to "k = dj - 1 for some j ≥ 1".
Used in the proof of partitionCount_divisorSum_restricted.
Generalization of the divisor sum recurrence for partitions with parts in a set I:
n · p_I(n) = ∑_{k=1}^n σ_I(k) · p_I(n-k)
where σ_I(n) is the sum of divisors of n that belong to I.
(Theorem \ref{thm.pars.sigma1-I})
The proof uses the generating function approach via logarithmic derivatives:
- Let P_I = ∑n p_I(n) x^n = ∏{k∈I} 1/(1-x^k)
- Let S_I = ∑_n σ_I(n) x^n
- Taking logarithmic derivative of P_I gives x·P_I'/P_I = S_I
- Therefore x·P_I' = S_I·P_I
- Comparing coefficients of x^n gives the identity
Equivalently, both sides count weighted pairs:
- LHS = ∑_p (sum of parts) = ∑_p ∑_d d·count(d,p)
- RHS = ∑_{m=1}^n σ_I(m)·p_I(n-m) = ∑d d·∑{j≥1} p_I(n-d·j)
- Both equal ∑{d∈I, d≤n} d·∑{j=1}^{n/d} p_I(n-d·j)
The recurrence relation connecting partition numbers and divisor sums:
n · p(n) = ∑_{k=1}^n σ(k) · p(n-k).
(Theorem \ref{thm.pars.sigma1})
This is proved using the generalized identity partitionCount_divisorSum_restricted
specialized to I = all positive integers.
The key generating function identity: X · P' = S · P.
This follows from the combinatorial identity partitionCount_divisorSum by
comparing coefficients.