Who plays what?
In Ms Okafor's class, some students play football, some play chess, some play both, and some play neither. She wants to answer questions like:
- Who plays both games?
- Who plays at least one of them?
- Who plays football but not chess?
Each question is about collections of people and how they overlap. In mathematics, a collection whose identity depends only on its members is called a set, and questions like these have precise answers.
Sets and their elements
Definition— set, element
A set is a collection of objects, called its elements. We write to mean " is an element of ", and to mean it is not.
We can describe a small set by listing its elements inside curly brackets — this is called roster notation:
Two facts about sets surprise people at first:
- Order doesn't matter. and are the same set.
- Repetition doesn't matter. is the same set as . An element is either in the set or not; it can't be in "twice".
Both facts come from one principle:
Definition— extensionality
Two sets are equal exactly when they have the same elements: means that for every , if and only if .
Definition— empty set
The empty set, written or , is the set with no elements at all. By extensionality there is only one empty set.
Definition— subset
is a subset of , written , if every element of is also an element of .
For example , and every set is a subset of itself. The empty set is a subset of every set: it has no elements, so none of its elements can fail to be in .
Explore: a Venn diagram that talks back
Here, is the set of students who play football and is the set who play chess. The rectangle — the universe — is the whole class. Shade any regions and the explorer will tell you which set you have made.
Shade a set, discover its name
Click regions of the diagram (or use the buttons). The explorer names the set you have made and lists its elements.
You have made
A ∩ B
{Kenji, Arjun}
Number of elements: 2
Try these
Challenge: two regions can be shaded in six different ways. Can you find all six, and name each one?
Making new sets from old
Definition— union
The union is the set of things in or in (or in both).
Definition— intersection
The intersection is the set of things in both and .
Definition— difference and complement
The difference is the set of things in but not in . When everything we are talking about lives in a universe , the complement is : everything in the universe that is not in .
In mathematics, "or" always means inclusive or: " or " is true when is in both. That is why the overlap belongs to .
Worked examples
Example— Union and intersection
Let and .
- — we list and only once.
- .
- and .
Example— Complement
In the universe , the complement of is . Change the universe and the complement changes: a complement always depends on .
Example— Set-builder notation
Sometimes listing is impossible, so we describe the elements by a property:
Read it as "the set of integers such that is even."
Proving things about sets
How can we be sure a statement about sets is true for every set — not just for the ones we have tried? We follow a single, arbitrary element and see where it must go.
Theorem— intersection sits inside
For all sets and : .
Proof
We must show that every element of is an element of . So let be any element of . By the definition of intersection, and . In particular, . Since was arbitrary, every element of is in .
∎
Theorem— De Morgan's law
For all subsets of a universe : .
Proof
By extensionality we show that each side contains exactly the same elements.
Take any . Then means is not in , which means it is not the case that ( or ). That is the same as saying and — which means and , i.e. .
Every step was an "if and only if", so the two sets have the same elements and are equal.
∎
Sets in Lean
In Lean, as in the Mathlib library, a set of elements of type is represented by its membership test: a function that takes an element and returns the statement "this element belongs". Here is our proof that . Compare it line by line with the human proof above:
/-- `A ∩ B ⊆ A`: whatever is in both sets is, in particular, in the first one. -/
theorem inter_subset_left (A B : Set α) : A ∩ B ⊆ A := by
intro x hx
-- `hx : x ∈ A ∧ x ∈ B`; keep the left half.
exact hx.1Equality of sets in Lean is exactly extensionality:
/-- **Extensionality.** Two sets are equal when they have exactly the same members.
This is where sets differ from lists: order and repetition are invisible.
The proof uses function extensionality and propositional extensionality, so the axiom
report lists `propext` and `Quot.sound` (from which `funext` is derived). -/
theorem ext {A B : Set α} (h : ∀ x, x ∈ A ↔ x ∈ B) : A = B :=
funext fun x => propext (h x)And here is De Morgan's law, proved by following an element, just as above:
/-- **De Morgan's law** for unions: `(A ∪ B)ᶜ = Aᶜ ∩ Bᶜ`.
Not being in `A ∪ B` means being in neither set. This proof is constructive: it does not
use the law of excluded middle. -/
theorem compl_union (A B : Set α) : (A ∪ B)ᶜ = Aᶜ ∩ Bᶜ := by
apply ext
intro x
constructor
· intro h
-- `h : ¬ (x ∈ A ∨ x ∈ B)`. If `x` were in `A`, it would be in `A ∪ B`; same for `B`.
exact ⟨fun hA => h (Or.inl hA), fun hB => h (Or.inr hB)⟩
· intro ⟨hnA, hnB⟩ hAB
-- `x` is in `A` or in `B`, and both cases contradict what we know.
cases hAB with
| inl hA => exact hnA hA
| inr hB => exact hnB hBThe other De Morgan law, , is subtler. To go from "not (in and in )" to "not in , or not in " the proof uses classical logic — the principle that every statement is either true or false. Look at the list of axioms under the proof: you can see Classical.choice appear. Lean keeps track of exactly which assumptions each proof depends on.
/-- **De Morgan's law** for intersections: `(A ∩ B)ᶜ = Aᶜ ∪ Bᶜ`.
The direction `(A ∩ B)ᶜ ⊆ Aᶜ ∪ Bᶜ` needs **classical logic**: knowing only that `x` is not in
both sets, we must still decide *which* set it misses. We use excluded middle
(`Classical.em`), so the axiom report for this theorem includes `Classical.choice`. -/
theorem compl_inter (A B : Set α) : (A ∩ B)ᶜ = Aᶜ ∪ Bᶜ := by
apply ext
intro x
constructor
· intro h
-- `h : ¬ (x ∈ A ∧ x ∈ B)`. Either `x ∈ A` or not (excluded middle).
cases Classical.em (x ∈ A) with
| inl hA =>
-- Then `x` cannot also be in `B`.
exact Or.inr (fun hB => h ⟨hA, hB⟩)
| inr hnA => exact Or.inl hnA
· intro h ⟨hA, hB⟩
cases h with
| inl hnA => exact hnA hA
| inr hnB => exact hnB hBChecking every case — and finding a counterexample
"""Checking set identities exhaustively.
Every subset of a small universe U is represented as a Python ``frozenset``
(and, equivalently, as a bitmask: one bit per element). We check De Morgan's
laws and the distributive laws for *every* pair or triple of subsets, and we
show that a plausible-looking "law", A - (B - C) = (A - B) - C, is false by
finding its smallest counterexample.
Runs unchanged in the browser (Pyodide) using only the standard library.
"""
from itertools import combinations, product
import textwrap
UNIVERSE = frozenset({1, 2, 3, 4})
def all_subsets(universe):
"""Return all 2^n subsets of ``universe`` as frozensets, smallest first.
Within one size, subsets are ordered by their sorted elements, so the order
is deterministic.
"""
elements = sorted(universe)
return [frozenset(c) for r in range(len(elements) + 1) for c in combinations(elements, r)]
def complement(s, universe):
"""Return U - s, the elements of the universe that are not in s."""
return frozenset(universe) - s
def to_bitmask(s, universe):
"""Encode subset s as an integer: bit i is 1 when the i-th smallest element is in s."""
elements = sorted(universe)
if not set(s) <= set(elements):
raise ValueError("s must be a subset of the universe")
return sum(1 << i for i, x in enumerate(elements) if x in s)
def from_bitmask(mask, universe):
"""Decode an integer bitmask back into a frozenset (inverse of :func:`to_bitmask`)."""
elements = sorted(universe)
if not 0 <= mask < (1 << len(elements)):
raise ValueError("mask out of range for this universe")
return frozenset(x for i, x in enumerate(elements) if mask >> i & 1)
def bit_operations_agree(universe):
"""Check union, intersection and complement against |, & and ~ on bitmasks.
Returns the number of (A, B) pairs checked. Raises AssertionError on a mismatch.
"""
full = (1 << len(universe)) - 1
subsets = all_subsets(universe)
for a, b in product(subsets, repeat=2):
ma, mb = to_bitmask(a, universe), to_bitmask(b, universe)
assert to_bitmask(a | b, universe) == ma | mb
assert to_bitmask(a & b, universe) == ma & mb
assert to_bitmask(complement(a, universe), universe) == ~ma & full
return len(subsets) ** 2
#: (description, arity, lhs, rhs). lhs and rhs take (U, A, B[, C]).
IDENTITIES = [
("U - (A ∪ B) = (U - A) ∩ (U - B)", 2,
lambda U, A, B: U - (A | B), lambda U, A, B: (U - A) & (U - B)),
("U - (A ∩ B) = (U - A) ∪ (U - B)", 2,
lambda U, A, B: U - (A & B), lambda U, A, B: (U - A) | (U - B)),
("A ∩ (B ∪ C) = (A ∩ B) ∪ (A ∩ C)", 3,
lambda U, A, B, C: A & (B | C), lambda U, A, B, C: (A & B) | (A & C)),
("A ∪ (B ∩ C) = (A ∪ B) ∩ (A ∪ C)", 3,
lambda U, A, B, C: A | (B & C), lambda U, A, B, C: (A | B) & (A | C)),
]
NON_IDENTITY = ("A - (B - C) = (A - B) - C", 3,
lambda U, A, B, C: A - (B - C), lambda U, A, B, C: (A - B) - C)
def check_identity(lhs, rhs, universe, arity):
"""Compare lhs and rhs on every tuple of ``arity`` subsets of ``universe``.
Returns ``(cases_checked, counterexamples)`` where counterexamples is a list
of the tuples of subsets on which the two sides differ.
"""
U = frozenset(universe)
subsets = all_subsets(U)
failures = []
cases = 0
for sets in product(subsets, repeat=arity):
cases += 1
if lhs(U, *sets) != rhs(U, *sets):
failures.append(sets)
return cases, failures
def smallest_counterexample(lhs, rhs, universe, arity):
"""Return the counterexample with the fewest elements in total, or None.
Ties are broken by comparing the sorted element lists, so the answer is
deterministic.
"""
_, failures = check_identity(lhs, rhs, universe, arity)
if not failures:
return None
return min(failures, key=lambda sets: (sum(len(s) for s in sets), [sorted(s) for s in sets]))
def fmt(s):
"""Format a set as {1, 2} or ∅."""
return "{" + ", ".join(str(x) for x in sorted(s)) + "}" if s else "∅"
def main():
U = UNIVERSE
n = len(U)
print(f"Universe U = {fmt(U)} has 2^{n} = {2 ** n} subsets.")
print(f"A subset is also a {n}-bit number: {fmt({1, 3})} -> {to_bitmask({1, 3}, U):0{n}b} (bit i = element i+1).")
pairs = bit_operations_agree(U)
print(f"∪, ∩ and complement match bitwise |, &, ~ on all {pairs} pairs: True")
print()
print(f"{'statement':<34}{'cases':>7}{'failures':>10}")
for name, arity, lhs, rhs in IDENTITIES + [NON_IDENTITY]:
cases, failures = check_identity(lhs, rhs, U, arity)
print(f"{name:<34}{cases:>7}{len(failures):>10}")
print()
name, arity, lhs, rhs = NON_IDENTITY
A, B, C = smallest_counterexample(lhs, rhs, U, arity)
print(f"The last line is NOT an identity. Smallest counterexample (fewest elements):")
print(f" A = {fmt(A)}, B = {fmt(B)}, C = {fmt(C)}")
print(f" A - (B - C) = {fmt(A)} - {fmt(B - C)} = {fmt(A - (B - C))}")
print(f" (A - B) - C = {fmt(A - B)} - {fmt(C)} = {fmt((A - B) - C)}")
cases, fails = check_identity(lambda U, A, B, C: (A - B) - C <= A - (B - C),
lambda U, A, B, C: True, U, 3)
print(f"What does hold: (A - B) - C ⊆ A - (B - C) in all {cases} cases ({len(fails)} failures).")
print()
print(textwrap.fill(
"Epistemic status: every pair and triple of subsets of this 4-element "
"universe was checked, so the four laws are proved for this universe "
"only, not for all sets (the lesson's element-by-element argument does "
"that). One counterexample, by contrast, is enough to show that "
"A - (B - C) = (A - B) - C fails for sets in general.",
width=78,
))
if __name__ == "__main__":
main()Notice the careful wording in the output. Checking all subsets of a 4-element universe is a complete proof for that universe — but not for all sets. Finding one counterexample, on the other hand, really does show that a general "law" is false.
Size, pairs and products
Definition— cardinality
For a finite set , its cardinality is the number of elements. So and .
Counting a union needs care, because the overlap would be counted twice:
Sometimes order does matter — for coordinates on a map, or (row, seat) in a theatre. For that we use ordered pairs: exactly when and . So , even though .
Definition— Cartesian product
The Cartesian product is the set of all ordered pairs with and .
If and then has elements, from to . In general — that is where the multiplication sign comes from.
/-- A pair `(a, b)` is in `A ×ˢ B` exactly when `a ∈ A` and `b ∈ B`. True by definition. -/
theorem mem_prod (a : α) (b : β) (A : Set α) (B : Set β) :
(a, b) ∈ A ×ˢ B ↔ a ∈ A ∧ b ∈ B :=
Iff.rflExercises
1. Sets
Warm-upHumanLet and . Write .
2. Sets
Warm-upHumanWith the same and , write .
3. Sets
CoreHumanIn the universe , write the complement of .
4. Sets
CoreFormalWhich statements are true? (Choose all that apply.)
5. Sets
CoreHumanWhat is the cardinality ?
6. Sets
CoreHumanA café offers 3 drinks and 4 snacks. A combo is an ordered pair (drink, snack). If is the set of drinks and the set of snacks, how many elements does have?
7. Sets
StretchHumanIn a class, 14 students play football, 9 play chess, and 5 play both. How many play at least one of the two games?
8. Sets
StretchComputationalWrite a Python function is_subset(a, b) that returns True exactly when every element of the set a is an element of the set b. Don't use Python's built-in <= or issubset — loop over the elements instead.
Common misconceptions
Misconception
Confusing with . is true, but is not even meaningful in school mathematics — is a number, not a set. Correct: .
Misconception
Thinking is empty. is a box containing an empty box. It has exactly one element, so , while .
Misconception
Adding sizes for a union. only when and have no elements in common.
Misconception
"I checked lots of examples, so it's proved." Examples can disprove a general statement, and they can build confidence, but they cannot prove a statement about all sets.
Wonder Trails
Naive and axiomatic set theory
In this lesson we have used naive set theory: we assumed that any clear description gives a set. That works perfectly for school mathematics. But in 1901, Bertrand Russell discovered that the description "the set of all sets that are not members of themselves" leads to a contradiction. Mathematicians responded by writing down precise axioms for which sets exist — most commonly the system called ZFC. You can meet that story on the Boxes inside boxes trail, and properly at university.
A first glimpse of structure
Subsets of a universe , ordered by , have a beautiful property. The intersection is the largest set that sits inside both and :
Describing an object by how other objects relate to it, rather than by listing its elements, is called a universal property. Much later you will see that this exact property makes a product in the category of subsets of — and that Cartesian products of sets are characterised in the same spirit.
History and global context
- Thinkers in many traditions reasoned about collections, wholes and parts long before modern set theory. Jain mathematical texts from ancient India, for example, are often described as distinguishing several kinds of infinite quantity.
- In the 1760s Leonhard Euler used circles to illustrate logical relationships in his Letters to a German Princess. John Venn introduced the diagrams that bear his name in 1880.
- Modern set theory was created in the 1870s–1890s, above all by Georg Cantor, with essential contributions from Richard Dedekind. Earlier, Bernard Bolzano's Paradoxes of the Infinite (published 1851) had already explored infinite collections.
- The axioms now most widely used, ZFC, are named after Ernst Zermelo and Abraham Fraenkel, with the axiom of Choice.
Further reading
- Paul R. Halmos, Naive Set Theory (1960).
- Herbert B. Enderton, Elements of Set Theory (1977).
- Jeremy Avigad, Patrick Massot et al., Mathematics in Lean — a free online book that formalises sets and functions with Mathlib.