Three questions
Choosing. A cricket coach in Lahore has a squad of and must name a team of . How many different teams are possible? Listing them is hopeless — but, as we will see, the answer is exactly , and it can be found in a few seconds.
Expanding. Multiply out . You could grind through five brackets — or notice that the coefficients are already written in a triangle of numbers that was known in India, Persia, North Africa and China centuries before Blaise Pascal wrote about it — though in English it carries his name, Pascal's triangle.
Guaranteeing. In any group of people, two were born in the same month. Not "probably" — certainly. Yet the argument does not tell us which two.
These are the three faces of combinatorics, the mathematics of finite arrangements: counting exactly, recognising the same count in different disguises, and proving that something must exist. Its favourite method is to count the same set in two different ways — and then the two answers must agree.
When does order matter?
From five friends — Amina, Bao, Carlos, Divya and Emeka — we choose two.
If we are choosing a captain and a vice-captain, order matters: (Amina, Bao) is different from (Bao, Amina). There are choices for the captain and then for the vice-captain, so ordered pairs, by the multiplication principle from counting principles.
If we are choosing two people to carry the drinks, order does not matter: is one pair, however we list it. Each unordered pair appears twice among the ordered pairs, so there are unordered pairs:
This is the division principle: if a list counts every object of interest exactly times, divide by . Choosing of the , there are ordered lists, and each set of three appears in orders, so there are sets of three.
Definitions
Recall , with , and that the number of ordered selections of different objects from is .
Definition— binomial coefficient
For whole numbers and , the binomial coefficient , read " choose ", is the number of -element subsets of an -element set. In particular when (there are no such subsets), and .
So by the list above. Notice that the definition is a counting definition; the formula comes next, as a theorem.
Definition— pigeonhole principle
If more than objects are placed in boxes, then some box contains at least two objects.
Definition— inclusion–exclusion (two sets)
For finite sets and : .
Here is the number of elements of , as in the lesson on sets. The pigeonhole principle and inclusion–exclusion are both proved below.
Worked examples
Example— The cricket team
Choosing the players who play is the same as choosing the who sit out, so the number of teams is .
Example— Routes through a grid
In a city laid out in blocks, a courier cycles from a corner to the corner blocks east and blocks north, always heading east or north. Every route is a word of letters with E's and N's, such as ENNEENE. A route is decided by which of the steps are north, so there are routes.
Example— Card hands
- A five-card hand from a pack of is a -element subset: there are hands.
- A full house (three cards of one rank, two of another): choose the rank of the three ( ways), which three suits (), the rank of the pair ( ways), and which two suits (). Multiplication principle: hands.
- Hands with at least one ace: count the complement. Hands with no ace choose all cards from the others, so the answer is .
Example— A word with repeated letters
How many different arrangements are there of the letters of BANANA? If the six letters were all different there would be . But swapping the three A's among themselves ( ways) or the two N's ( ways) gives the same word. Each word is counted times, so there are words.
Example— A non-example: overcounting
"Hands with at least one ace: choose an ace ( ways), then any of the other cards: ." This is wrong — it is larger than the correct . A hand with two aces, say the ace of hearts and the ace of spades, is counted twice: once when the hearts ace is "the chosen ace" and once when the spades ace is. Every counting argument must produce each object exactly once (or exactly times, and then we divide).
Theorems, proved by counting
Theorem— Theorem 1 (the factorial formula)
For : .
Proof
Count the ordered selections of different objects from in two ways. Directly, there are of them. Alternatively, first choose the set of objects ( ways) and then put it in order ( ways): so there are of them. Hence ; divide by .
∎
Theorem— Theorem 2 (symmetry)
For : .
Proof
Sending each -element subset of an -element set to its complement , which has elements, is a one-to-one correspondence: it is its own inverse, since the complement of the complement is again. So the two collections have the same size.
∎
Theorem— Theorem 3 (Pascal's rule)
For and : .
Proof
Count the -person committees chosen from people, one of whom is Amina. Every committee either contains Amina or it does not, and not both.
- Committees containing Amina: removing her leaves members chosen from the other people, and putting her back undoes this. So there are of them.
- Committees not containing Amina: all members come from the other people. There are of them.
Adding the two disjoint kinds counts every committee exactly once.
∎
Pascal's rule says that each entry of the triangle is the sum of the two entries above it. Starting from the s down the edges, it generates all the binomial coefficients without a single multiplication.
Theorem— Theorem 4 (the binomial theorem)
For every whole number and all numbers :
Proof
Write with brackets. Multiplying out, we get one term for each way of choosing either or from every bracket, and the term is the product of the choices. A choice that takes from exactly brackets (and from the other ) gives . The number of such choices is the number of ways to pick which of the brackets supply an : that is . Collecting equal terms (multiplication of numbers is commutative) gives the formula.
∎
There is also a proof by induction on , which is the one Lean checks below for : multiply by , and the coefficient of in the product is — which is by Pascal's rule. The induction proof and the counting proof are two views of the same fact, which links this lesson to proof by induction and to polynomials.
Example— Using the theorem
. Check: putting gives .
Theorem— Corollary 5 (row sums)
For every : , and for : .
Proof
Put in the binomial theorem for the first identity, and , for the second: and when .
A counting proof of the first: both sides count all subsets of an -element set. On the left, they are sorted by size; on the right, each of the elements is either in or out — possibilities. The second identity says that a non-empty set has as many subsets of even size as of odd size.
∎
The pigeonhole principle
Theorem— Theorem 6 (pigeonhole principle)
If more than objects are placed in boxes, some box contains at least two objects. More generally, if objects are placed in boxes, some box contains at least objects.
Proof
Suppose instead that every box contained at most objects. Since , the total number of objects would be less than — a contradiction. With we have , which is the first statement.
∎
The principle is almost too obvious to state — its power lies in choosing the objects and the boxes cleverly.
Example— Birth months
people, months as boxes: two people share a birth month.
Example— Remainders
Among any integers, two differ by a multiple of . Boxes: the possible remainders on division by . Two of the integers land in the same box, and two numbers with the same remainder differ by a multiple of .
Example— Points in a square
Place points anywhere in a square of side . Then some two are at distance at most . Boxes: cut the square into four unit squares (a point on a dividing line goes into either neighbouring square). Two points share a unit square, and no two points of a unit square are further apart than its diagonal, .
Example— Acquaintances at a party
At any gathering of people, two of them have the same number of acquaintances present (acquaintance being mutual). Each person knows between and others: possible numbers. But and cannot both occur — if someone knows everybody, nobody knows nobody. So the people have at most possible numbers between them, and two share a number. (In the language of graphs: every finite simple graph with at least two vertices has two vertices of the same degree.)
Inclusion–exclusion
Theorem— Theorem 7 (inclusion–exclusion for two and three sets)
For finite sets , , :
Proof
Two sets. counts every element of once, except the elements of , which are counted twice; subtracting corrects this.
Three sets. Apply the two-set rule to and : . Now , and , whose size by the two-set rule is , because . Substituting gives the formula.
∎
Example— Divisible by 2, 3 or 5
How many of are divisible by , or ? Let be the multiples of ; then and, for instance, . So the answer is
The same pattern works for any number of sets: add the sizes of the sets, subtract the sizes of all pairwise intersections, add all triple intersections, and so on, with alternating signs. Here is why — and the binomial theorem returns to help.
Theorem— Theorem 8 (inclusion–exclusion, general)
For finite sets ,
Proof
Take an element that lies in exactly of the sets. It is counted in exactly when is a non-empty set of indices of sets containing , and there are such of size . So the right-hand side counts exactly
time, by the alternating row sum (Corollary 5). An element in none of the sets is counted times on both sides.
∎
Example— Derangements: the hat-check problem
Guests at a wedding in Addis Ababa leave hats at the door, and the hats are handed back at random. In how many of the ways does nobody get their own hat? Such an arrangement is a derangement; call their number .
Let be the arrangements in which guest gets the right hat. If the guests in a set of size all get their own hats, the other hats can be arranged in ways, and there are sets of size . By inclusion–exclusion,
and , so
For example . The bracket is a partial sum of the series , which (as you may learn with sequences and series) converges to , and very quickly: with eight or more guests, the fraction of arrangements that are derangements is to four decimal places.
The proofs, checked by Lean
In Mathlib, Finset.powersetCard k s is the finite set of -element subsets of s, #s is the number of elements of s, and Nat.choose n k is . Interestingly, Mathlib defines Nat.choose by Pascal's rule — , , — so our counting definition becomes a theorem. First, Pascal's rule for subsets, proved exactly like the committee argument (avoid , or contain ):
/-- **Pascal's rule, by counting.** Let `a` be a new element, not in `s`. A `(k + 1)`-element
subset of `insert a s` either avoids `a` — then it is a `(k + 1)`-element subset of `s` — or
contains `a` — then it is `insert a t` for exactly one `k`-element subset `t` of `s`. The two
kinds do not overlap, so their numbers add up. -/
theorem pascal_subsets {α : Type*} [DecidableEq α] {a : α} {s : Finset α} (ha : a ∉ s)
(k : ℕ) :
#(powersetCard (k + 1) (insert a s)) = #(powersetCard (k + 1) s) + #(powersetCard k s) := by
rw [powersetCard_succ_insert ha, card_union_of_disjoint]
· -- putting `a` back is one-to-one on the subsets of `s`, since none of them contains `a`
congr 1
apply card_image_of_injOn
intro t ht u hu htu
have hat : a ∉ t := fun h => ha ((mem_powersetCard.1 ht).1 h)
have hau : a ∉ u := fun h => ha ((mem_powersetCard.1 hu).1 h)
have := congrArg (fun v => v.erase a) htu
simpa [erase_insert hat, erase_insert hau] using this
· -- no subset of `s` contains `a`, so the two kinds are disjoint
rw [disjoint_left]
intro t ht ht'
obtain ⟨u, -, rfl⟩ := mem_image.1 ht'
exact ha ((mem_powersetCard.1 ht).1 (mem_insert_self a u))Since counting subsets obeys the same rules that define Nat.choose, induction shows that the two agree:
/-- **`C(n, k)` counts the `k`-element subsets of an `n`-element set.** Mathlib defines
`Nat.choose` by the rules `C(n, 0) = 1`, `C(0, k + 1) = 0` and Pascal's rule
`C(n + 1, k + 1) = C(n, k) + C(n, k + 1)`. Counting subsets obeys the same three rules
(the last one is `pascal_subsets`), so, by induction on the set, the two agree.
(Mathlib states this as `Finset.card_powersetCard`.) -/
theorem card_subsets_eq_choose {α : Type*} [DecidableEq α] (s : Finset α) (k : ℕ) :
#(powersetCard k s) = (#s).choose k := by
induction s using Finset.induction_on generalizing k with
| empty =>
cases k with
| zero => rw [powersetCard_zero, card_singleton, card_empty, Nat.choose_zero_right]
| succ k =>
rw [powersetCard_eq_empty.2 (by simp), card_empty, card_empty, Nat.choose_zero_succ]
| insert a s ha ih =>
cases k with
| zero => rw [powersetCard_zero, card_singleton, Nat.choose_zero_right]
| succ k =>
rw [pascal_subsets ha, ih, ih, card_insert_of_notMem ha, Nat.choose_succ_succ', add_comm]The factorial formula and symmetry come from Mathlib, and Lean can evaluate the formula exactly:
/-- **The factorial formula.** For `k ≤ n`, `C(n, k) · k! · (n − k)! = n!`, that is
`C(n, k) = n! / (k! (n − k)!)`. This applies Mathlib's `Nat.choose_mul_factorial_mul_factorial`. -/
theorem choose_factorial {n k : ℕ} (hk : k ≤ n) :
n.choose k * k.factorial * (n - k).factorial = n.factorial :=
Nat.choose_mul_factorial_mul_factorial hk/-- **Symmetry of Pascal's triangle:** `C(n, n − k) = C(n, k)` for `k ≤ n` — choosing the `k`
members of a committee is the same as choosing the `n − k` people left out.
This applies Mathlib's `Nat.choose_symm`. -/
theorem choose_symm {n k : ℕ} (hk : k ≤ n) : n.choose (n - k) = n.choose k :=
Nat.choose_symm hk/-- There are `C(52, 5) = 2 598 960` five-card hands from a standard pack. Lean evaluates the
factorial formula exactly. -/
theorem five_card_hands : Nat.choose 52 5 = 2598960 := by
rw [Nat.choose_eq_factorial_div_factorial (by norm_num)]
rflThe binomial theorem for is proved by induction, as described after Theorem 4. It holds in any commutative semiring — any number system where addition and multiplication obey the usual laws, such as , , or . Mathlib's general version follows it.
/-- **The binomial theorem for `(1 + x)ⁿ`, by induction on `n`.** Multiplying
`(1 + x)ⁿ = Σₖ C(n, k) xᵏ` by `1 + x` gives the sum once as it is and once shifted up by one
power of `x`. Collecting the coefficient of `xᵏ⁺¹` gives `C(n, k + 1) + C(n, k)`, which is
`C(n + 1, k + 1)` by Pascal's rule. -/
theorem binomial_one_add {R : Type*} [CommSemiring R] (x : R) (n : ℕ) :
(1 + x) ^ n = ∑ k ∈ range (n + 1), (n.choose k : R) * x ^ k := by
induction n with
| zero => simp
| succ n ih =>
-- the old sum with one extra (zero) term on top
have top : ∑ k ∈ range (n + 2), (n.choose k : R) * x ^ k =
∑ k ∈ range (n + 1), (n.choose k : R) * x ^ k := by
rw [sum_range_succ, Nat.choose_succ_self, Nat.cast_zero, zero_mul, add_zero]
-- Pascal's rule, term by term
have pascal : ∑ k ∈ range (n + 2), ((n + 1).choose k : R) * x ^ k =
∑ k ∈ range (n + 1), (n.choose k : R) * x ^ (k + 1) +
∑ k ∈ range (n + 2), (n.choose k : R) * x ^ k := by
rw [sum_range_succ' _ (n + 1), sum_range_succ' (fun k => (n.choose k : R) * x ^ k) (n + 1)]
simp only [Nat.choose_succ_succ', Nat.cast_add, add_mul, sum_add_distrib,
Nat.choose_zero_right]
ring
rw [pascal, top, pow_succ, ih, mul_add, mul_one, sum_mul]
simp only [mul_assoc, ← pow_succ]
ring/-- **The binomial theorem** `(x + y)ⁿ = Σₖ C(n, k) xᵏ yⁿ⁻ᵏ` in any commutative semiring.
This applies Mathlib's `add_pow` (proved there for any two commuting elements of a semiring). -/
theorem binomial_theorem {R : Type*} [CommSemiring R] (x y : R) (n : ℕ) :
(x + y) ^ n = ∑ k ∈ range (n + 1), x ^ k * y ^ (n - k) * (n.choose k : R) :=
add_pow x y n/-- **Each row of Pascal's triangle adds up to a power of two:** `Σₖ C(n, k) = 2ⁿ`.
Put `x = 1` in `binomial_one_add`. (Counting proof: both sides count all subsets of an
`n`-element set.) -/
theorem row_sum (n : ℕ) : ∑ k ∈ range (n + 1), n.choose k = 2 ^ n := by
have h := binomial_one_add (1 : ℕ) n
simpa [one_add_one_eq_two] using h.symm/-- **Alternating row sums vanish:** `Σₖ (−1)ᵏ C(n + 1, k) = 0`. Put `x = −1` in
`binomial_one_add`: the left side is `(1 − 1)ⁿ⁺¹ = 0`. So a non-empty set has as many subsets
of even size as of odd size. -/
theorem alternating_row_sum (n : ℕ) :
∑ k ∈ range (n + 2), ((n + 1).choose k : ℤ) * (-1) ^ k = 0 := by
have h := binomial_one_add (-1 : ℤ) (n + 1)
rw [← h]
simpThe pigeonhole principle, proved by counting the objects box by box: if no box held two objects, the number of objects would be at most the number of boxes. Then Mathlib's version, and the remainders example.
/-- **The pigeonhole principle.** If `f` puts every object of `s` into a box of `t`, and there
are more objects than boxes, then two different objects share a box. Proof by counting: the
number of objects is the sum, over the boxes, of the number of objects in each box. If no box
held two objects, every term would be at most `1`, so there would be at most `#t` objects. -/
theorem pigeonhole {α β : Type*} [DecidableEq β] (s : Finset α) (t : Finset β) (f : α → β)
(hf : ∀ a ∈ s, f a ∈ t) (hst : #t < #s) : ∃ x ∈ s, ∃ y ∈ s, x ≠ y ∧ f x = f y := by
by_contra! h
-- if no two objects share a box, every box holds at most one object
have hbox : ∀ b ∈ t, #{a ∈ s | f a = b} ≤ 1 := by
intro b _
rw [card_le_one]
intro x hx y hy
rw [mem_filter] at hx hy
by_contra hxy
exact h x hx.1 y hy.1 hxy (hx.2.trans hy.2.symm)
have : #s ≤ #t :=
calc #s = ∑ b ∈ t, #{a ∈ s | f a = b} := card_eq_sum_card_fiberwise (fun a ha => hf a ha)
_ ≤ ∑ b ∈ t, 1 := sum_le_sum hbox
_ = #t := by simp
omega/-- The same principle from Mathlib: `Finset.exists_ne_map_eq_of_card_lt_of_maps_to`. -/
theorem pigeonhole_library {α β : Type*} (s : Finset α) (t : Finset β) (f : α → β)
(hf : ∀ a ∈ s, f a ∈ t) (hst : #t < #s) : ∃ x ∈ s, ∃ y ∈ s, x ≠ y ∧ f x = f y :=
exists_ne_map_eq_of_card_lt_of_maps_to hst (fun a ha => hf a ha)/-- **Among any `n + 1` integers, two differ by a multiple of `n`.** The boxes are the `n`
possible remainders `0, 1, …, n − 1` on division by `n`; there are `n + 1` integers, so two of
them have the same remainder, and their difference is divisible by `n`. Nothing tells us
*which* two — the pigeonhole principle only proves that they exist. -/
theorem same_remainder (n : ℕ) (hn : 0 < n) (a : Fin (n + 1) → ℤ) :
∃ i j, i ≠ j ∧ (n : ℤ) ∣ a i - a j := by
have hn' : (0 : ℤ) < n := by exact_mod_cast hn
obtain ⟨i, -, j, -, hij, h⟩ :=
pigeonhole (univ : Finset (Fin (n + 1))) (Ico (0 : ℤ) n) (fun i => a i % n)
(fun i _ => mem_Ico.2 ⟨Int.emod_nonneg _ hn'.ne', Int.emod_lt_of_pos _ hn'⟩)
(by simp)
exact ⟨i, j, hij, Int.ModEq.dvd h.symm⟩Inclusion–exclusion. Subtraction of natural numbers is awkward (in Lean, in ), so the formulas are written with every term on the side where it is added:
/-- **Inclusion–exclusion for two sets:** `|A ∪ B| + |A ∩ B| = |A| + |B|` (written without
subtraction, which is awkward in `ℕ`). This applies Mathlib's
`Finset.card_union_add_card_inter`. -/
theorem incl_excl_two {α : Type*} [DecidableEq α] (A B : Finset α) :
#(A ∪ B) + #(A ∩ B) = #A + #B :=
card_union_add_card_inter A B/-- **Inclusion–exclusion for three sets:**
`|A ∪ B ∪ C| = |A| + |B| + |C| − |A ∩ B| − |A ∩ C| − |B ∩ C| + |A ∩ B ∩ C|`,
written with every term on the side where it is added. The proof is the lesson's: apply the
two-set rule to `A ∪ B` and `C`, then to `A` and `B`, then to `A ∩ C` and `B ∩ C`, using
`(A ∪ B) ∩ C = (A ∩ C) ∪ (B ∩ C)`. -/
theorem incl_excl_three {α : Type*} [DecidableEq α] (A B C : Finset α) :
#(A ∪ B ∪ C) + #(A ∩ B) + #(A ∩ C) + #(B ∩ C) = #A + #B + #C + #(A ∩ B ∩ C) := by
have h1 := card_union_add_card_inter (A ∪ B) C
have h2 := card_union_add_card_inter A B
have h3 := card_union_add_card_inter (A ∩ C) (B ∩ C)
have e1 : (A ∪ B) ∩ C = A ∩ C ∪ B ∩ C := union_inter_distrib_right A B C
have e2 : A ∩ C ∩ (B ∩ C) = A ∩ B ∩ C := by
ext x
simp only [mem_inter]
tauto
rw [e1] at h1
rw [e2] at h3
omega/-- Of the numbers `1, 2, …, 100`, exactly `74` are divisible by `2`, `3` or `5`, as
inclusion–exclusion predicts: `50 + 33 + 20 − 16 − 10 − 6 + 3 = 74`. Lean checks all hundred. -/
theorem divisible_by_2_3_or_5 :
#{n ∈ Icc 1 100 | 2 ∣ n ∨ 3 ∣ n ∨ 5 ∣ n} = 74 := by
decideWhat is not formalised here: the general inclusion–exclusion formula (Mathlib has it, as Finset.inclusion_exclusion_card_biUnion, but its statement takes some unpacking), the derangement formula, and the geometric pigeonhole examples.
Counting by computer
"""Pascal's triangle three ways, and the binomial theorem checked symbolically.
The number of k-element subsets of an n-element set is computed in three
independent ways - by listing every subset (itertools.combinations), by
Pascal's rule, and by the factorial formula - and the three are compared for
every n up to 12 (listing) or 40 (rule versus formula). The row identities
(symmetry, row sums 2^n, alternating sums 0) are checked on the same range,
and SymPy expands (x + y)^n to confirm that its coefficients are the rows of
the triangle for n up to 12. All of this is exhaustive over a finite range:
evidence for the identities, which the lesson proves for every n.
"""
import itertools
import math
import sympy
def pascal_rows(n_max):
"""Rows 0..n_max of Pascal's triangle, built only from Pascal's rule."""
rows = [[1]]
for _ in range(n_max):
prev = rows[-1]
rows.append([1] + [prev[k - 1] + prev[k] for k in range(1, len(prev))]
+ [1])
return rows
def count_subsets(n, k):
"""Number of k-element subsets of {0, ..., n-1}, by listing them all."""
return sum(1 for _ in itertools.combinations(range(n), k))
def factorial_formula(n, k):
"""n! / (k! (n - k)!), computed with exact integers."""
if not 0 <= k <= n:
return 0
return math.factorial(n) // (math.factorial(k) * math.factorial(n - k))
def binomial_coefficients(n):
"""Coefficients of x^k y^(n-k), k = 0..n, in SymPy's expansion of (x+y)^n."""
x, y = sympy.symbols("x y")
poly = sympy.Poly(sympy.expand((x + y) ** n), x, y)
return [int(poly.coeff_monomial(x ** k * y ** (n - k)))
for k in range(n + 1)]
def row_identities_hold(row):
"""Symmetry, row sum 2^n and alternating sum 0 (for n >= 1) for one row."""
n = len(row) - 1
alternating = sum((-1) ** k * c for k, c in enumerate(row))
return (row == row[::-1] and sum(row) == 2 ** n
and (n == 0 or alternating == 0))
def main():
rows = pascal_rows(40)
print("Rows 0-8 of Pascal's triangle (built from Pascal's rule):")
for n in range(9):
print(" " * (2 * (8 - n)) + "".join(f"{c:4d}" for c in rows[n]))
listed = all(count_subsets(n, k) == rows[n][k]
for n in range(13) for k in range(n + 1))
print(f"Listing subsets agrees with the rule for all n <= 12: {listed}")
formula = all(factorial_formula(n, k) == rows[n][k]
for n in range(41) for k in range(n + 1))
print(f"Factorial formula agrees with the rule for all n <= 40: {formula}")
rows_ok = all(row_identities_hold(row) for row in rows)
print(f"Symmetry, sums 2^n, alternating sums 0 (n <= 40): {rows_ok}")
print(f"Row 40 has {sum(rows[40])} subsets in all = 2^40.")
expansion = sympy.expand((sympy.Symbol("x") + sympy.Symbol("y")) ** 5)
print("SymPy expands (x + y)^5 as")
print(f" {expansion}")
sym = all(binomial_coefficients(n) == rows[n] for n in range(13))
print(f"Coefficients of (x + y)^n = row n for all n <= 12: {sym}")
print()
print("Epistemic status: exhaustive checks over a finite range (listing")
print("subsets for n <= 12, exact integer arithmetic for n <= 40) and a")
print("symbolic expansion trusted as far as SymPy is. They support, but")
print("cannot prove, the identities for all n; the lesson's counting and")
print("induction proofs (checked in Lean) do that.")
if __name__ == "__main__":
main()"""Inclusion-exclusion and the pigeonhole principle, counted exactly.
Three checks. (1) How many of 1..N are divisible by 2, 3 or 5? Counting
every number agrees with the inclusion-exclusion formula. (2) Derangements:
the number of ways to hand back n hats so that nobody gets their own is found
by listing all n! arrangements (n <= 8) and agrees with the general
inclusion-exclusion formula n! * sum (-1)^k / k!; the fraction approaches
1/e. (3) Birthdays: the exact probability that k people (365 equally likely
days) share a birthday passes 1/2 at k = 23, but only the pigeonhole
principle makes it certain, at k = 366.
"""
import itertools
import math
from fractions import Fraction
def divisible_count_direct(n, divisors):
"""How many of 1..n are divisible by at least one of the divisors."""
return sum(1 for m in range(1, n + 1) if any(m % d == 0 for d in divisors))
def divisible_count_ie(n, divisors):
"""The same count by inclusion-exclusion over all non-empty subsets."""
total = 0
for r in range(1, len(divisors) + 1):
for subset in itertools.combinations(divisors, r):
lcm = math.lcm(*subset)
total += (-1) ** (r + 1) * (n // lcm)
return total
def derangements_brute(n):
"""Arrangements of 0..n-1 with no element in its own place, by listing."""
return sum(1 for p in itertools.permutations(range(n))
if all(p[i] != i for i in range(n)))
def derangements_ie(n):
"""n! * sum_{k=0}^{n} (-1)^k / k!, the inclusion-exclusion count."""
return sum((-1) ** k * math.factorial(n) // math.factorial(k)
for k in range(n + 1))
def shared_birthday(k, days=365):
"""Exact probability that some two of k people share a birthday."""
if k > days:
return Fraction(1)
none = Fraction(1)
for i in range(k):
none *= Fraction(days - i, days)
return 1 - none
def main():
print("1. Numbers in 1..N divisible by 2, 3 or 5")
for n in (100, 1000, 30000):
direct = divisible_count_direct(n, (2, 3, 5))
print(f" N = {n:5d}: counted {direct:5d}, inclusion-exclusion "
f"{divisible_count_ie(n, (2, 3, 5)):5d}")
print()
print("2. Derangements (nobody gets their own hat)")
print(" n listed formula fraction of n! 1/e = 0.367879")
for n in range(1, 9):
listed = derangements_brute(n)
frac = listed / math.factorial(n)
print(f" {n:2d} {listed:6d} {derangements_ie(n):7d} "
f"{frac:14.6f}")
print()
print("3. Shared birthdays among k people (365 equally likely days)")
print(" k P(shared) P(no two share)")
for k in (10, 22, 23, 50, 70, 365, 366):
p = shared_birthday(k)
none = "exactly 0" if p == 1 else f"{float(1 - p):.3e}"
print(f" {k:4d} {float(p):9.6f} {none}")
print()
print("Epistemic status: exact integer and rational arithmetic. Parts 1")
print("and 2 compare a direct count with a formula over a finite range")
print("(evidence; the lesson proves the formulas). Part 3 is an exact")
print("model calculation assuming 365 equally likely, independent days.")
if __name__ == "__main__":
main()Look at the last table. With people a shared birthday is already more likely than not (assuming equally likely birthdays) — but no number of people below makes it certain: even with people the probability that all birthdays differ is tiny but not zero. Only the pigeonhole principle, at people, turns "very likely" into "guaranteed". Probability and pigeonhole answer different questions.
Explore: Pascal's triangle in a Galton board
Binomial coefficients and birthdays
Balls bounce left or right at each row of pegs. The bins fill up in a binomial shape, close to a normal curve.
- balls in each bin
- exact binomial expectation
- normal approximation
- path of the latest ball
Average bin
Simulated4.98
Exactn/2 = 5
Balls in bin 5
Simulated249
Exact≈ 246.1
Simulation of 1,000 balls through 10 rows: the average bin was 4.98. The exact average is half the number of rows.
Evidence, not proofThis is a simulation of 1,000 balls (run 1) using a seeded random number generator. It is evidence, not proof: the exact values come from mathematics, and a new run gives slightly different numbers.
Bin j collects the balls that bounced right j times. C(n, j) of the 2ⁿ equally likely paths lead there, so the exact chance is C(n, j)/2ⁿ. With many rows this binomial shape is close to a normal curve (the central limit theorem).
On the Galton board, each ball bounces left or right at each of rows. A ball lands in bin when exactly of its bounces go right, and there are such paths — row of Pascal's triangle — out of equally likely paths. Compare the bars with the exact shape, then increase the number of balls. On the birthday tab, change the group size: find where the probability first passes one half, and notice that it creeps towards without reaching it.
Exercises
1. Combinatorics
Warm-upHumanA youth council in Kigali has members. In how many ways can a working group of members be chosen? (All members of the group have the same role.)
2. Combinatorics
Warm-upHumanFind all whole numbers with . List them separated by commas.
3. Combinatorics
CoreHumanHow many five-card hands from a standard pack of cards contain at least one ace? (There are hands in all, and .)
4. Combinatorics
CoreHumanWhat is the coefficient of in the expansion of ?
5. Combinatorics
CoreHumanIn the proof of Pascal's rule , the -person committees chosen from people are split by whether they contain Amina. Why are there exactly committees containing Amina?
6. Combinatorics
CoreHumanIn a class of students in Accra, play football, play basketball and play both. How many students play neither sport?
7. Combinatorics
StretchHumanWhat is the smallest number such that any different whole numbers chosen from must include two whose difference is divisible by ?
8. Combinatorics
StretchFormalHere s is a finite set of objects, t a finite set of boxes and f assigns a box to each object. Which Lean statement correctly formalises the pigeonhole principle?
9. Combinatorics
StretchComputationalWrite derangements(n) returning the number of ways to arrange hats so that nobody gets their own hat, using the inclusion–exclusion formula . Use exact integer arithmetic (math.factorial and //). Then check: does approach ?
Common misconceptions
Misconception
Using permutations when order does not matter. Choosing a committee of from is , not . The ordered count lists each committee times. Ask: "if I swap two of my choices, do I get a different outcome?" If not, order does not matter.
Misconception
"A pigeonhole argument must say which box has two objects." It need not, and usually cannot. "Two of these people share a birth month" is proved without knowing any birthdays at all.
Misconception
"." Already . The binomial theorem shows exactly which cross terms appear and how often.
Misconception
Counting "at least one" by fixing one. Choosing "the" ace first and then the rest counts hands with several aces several times. Count the complement ("no aces") instead, or use inclusion–exclusion.
Misconception
Stopping inclusion–exclusion too early. For three sets, after subtracting the pairwise intersections the elements of have been added three times and subtracted three times — so they must be added back once.
Other ways of seeing
Algebra— Counting with polynomials
The binomial theorem says that the polynomial stores the numbers as its coefficients. Identities between counts become identities between polynomials: comparing the coefficient of on both sides of gives Vandermonde's identity — which also has a counting proof (choose people from women and men). Turning counting problems into algebra in this way is the method of generating functions, the subject of recurrences and generating functions and enumerative combinatorics.
Probability— Counting is probability in disguise
If a fair coin is tossed times, the sequences are equally likely, and of them have exactly heads. So — the binomial distribution, the shape of the Galton board. Many probability questions are two counting questions, divided; see conditional probability and independence.
Number theory— Primes in Pascal's triangle
If is prime and , then divides : the prime divides the numerator but not the denominator. (Look at row : .) So and leave the same remainder on division by , and an induction on then proves Fermat's little theorem: divides for every whole number . Colouring the odd entries of Pascal's triangle reveals a pattern like the Sierpiński triangle, explained by Lucas's theorem on binomial coefficients modulo a prime; see congruences.
Set-theoretic connection
Combinatorics is the theory of the sizes of finite sets. The multiplication principle is ; the binomial coefficient counts the subsets of size inside the power set , which has elements; a "counting in two ways" proof is the statement that two finite sets in one-to-one correspondence have the same size; and inclusion–exclusion computes the size of a union from the sizes of intersections. The pigeonhole principle says exactly that there is no one-to-one function from a finite set to a smaller one — a fact that fails for infinite sets, as countability shows.
History and global context
- India. Piṅgala's Chandaḥśāstra (roughly the 3rd–2nd century BCE) counts the patterns of short and long syllables in Sanskrit verse; its 10th-century commentator Halāyudha describes the meru-prastāra, the "staircase of Mount Meru" — the triangle we call Pascal's. Varāhamihira (6th century) counted the perfumes that can be blended by choosing of ingredients (), and Mahāvīra's Gaṇitasārasaṅgraha (around 850) gives the general rule for .
- Persia and North Africa. Al-Karajī (around 1000) used the triangle to expand powers of a binomial; his work is known through al-Samawʾal (12th century). In Iran the triangle is often named after Omar Khayyam. In Marrakesh, Ibn Munʿim (died 1228) used a table of the same numbers to count the possible words of a language.
- China. Jia Xian (11th century) used the triangle to extract roots; it is preserved in Yang Hui's book of 1261 — in China it is called Yang Hui's triangle — and drawn in Zhu Shijie's Jade Mirror of the Four Unknowns (1303).
- Europe. Levi ben Gershon's Maaseh Hoshev (1321) gave formulas for arrangements and selections with careful proofs. Blaise Pascal's Traité du triangle arithmétique (written 1654, published 1665) proved many of its properties systematically and applied them to probability; Isaac Newton extended the binomial theorem to fractional exponents (1665).
- Pigeons and hats. The pigeonhole principle is named after P. G. L. Dirichlet, who used it in 1834 (as the Schubfachprinzip, "drawer principle"); it appears earlier, in a 1622 book by the French Jesuit Jean Leurechon. The hat-check problem goes back to Pierre Rémond de Montmort's problème des rencontres (1708), and Abraham de Moivre used inclusion–exclusion in The Doctrine of Chances (1718).
Further reading
- Arthur Engel, Problem-Solving Strategies (1998) — chapters on the pigeonhole principle and on enumerative combinatorics, with hundreds of competition problems.
- Arthur T. Benjamin and Jennifer J. Quinn, Proofs That Really Count (2003) — identities proved by counting in two ways.
- Richard A. Brualdi, Introductory Combinatorics (5th edition, 2010).
- Ronald L. Graham, Donald E. Knuth and Oren Patashnik, Concrete Mathematics (2nd edition, 1994), chapter 5 on binomial coefficients.
- A. W. F. Edwards, Pascal's Arithmetical Triangle (1987), for the history of the triangle.