Tiles, jugs and a suspicious certainty
A workshop floor in Nairobi measures cm by cm. The carpenter wants to cover it with identical square tiles, as large as possible, without cutting any. How big can the tiles be?
A tile of side fits exactly when divides both and . So we want the greatest common divisor of and . Listing all the divisors of both numbers would work, but slowly. Euclid, about years ago, described a far faster method — and we will see that the answer is cm.
A second puzzle: with a -litre jug and a -litre jug and a tap, can you measure exactly litre? (Yes: fill the -litre jug twice and pour it into the -litre jug; the second time, litre is left over. In symbols, .) Which amounts can be measured with jugs of and litres? The answer is the same greatest common divisor.
Finally, a certainty you have relied on since primary school: every whole number breaks into primes in only one way, . It feels obvious. This lesson proves it — and shows a number system in which it is false.
Divisors, remainders and the gcd
Definition— divides
For integers and , divides , written , if for some integer . We also say is a divisor of and is a multiple of . If does not divide we write .
So , , , and every integer divides (since ).
Theorem— Lemma 1 (rules for divisibility)
For integers : (a) if and , then ; (b) if and , then ; (c) if and , then .
Proof
(a) If and , then . (b) If and , then . (c) If with , then , so and .
∎
Theorem— Theorem 2 (division with remainder)
Let and be integers with . There are unique integers (the quotient) and (the remainder) with
Proof
Existence. The set is non-empty (take ; then ). By the well-ordering principle it has a least element . Then , and : otherwise would be a smaller element of . Uniqueness. If with , then , a multiple of strictly between and . The only such multiple is , so and .
∎
Definition— greatest common divisor, coprime, least common multiple
For integers not both zero, the greatest common divisor is the largest integer that divides both. (It exists: is a common divisor, and by Lemma 1(c) common divisors are at most .) Integers with are coprime. For non-zero the least common multiple is the smallest positive integer divisible by both.
Definition— prime
A prime is an integer whose only positive divisors are and . An integer that is not prime is composite. (We met primes in factors, multiples and primes.)
Example— gcd versus lcm
For and : the common divisors are , so ; the common multiples are , so . Notice — no accident, as we will prove. The gcd is at most the smaller number; the lcm is at least the larger one.
Euclid's algorithm
The whole algorithm rests on one observation.
Theorem— Lemma 3
If , then the common divisors of and are exactly the common divisors of and . In particular, if , then .
Proof
If and , then by Lemma 1(b). Conversely, if and , then . The two pairs have the same set of common divisors, hence the same greatest one.
∎
Theorem— Theorem 4 (Euclid's algorithm)
Let . Divide repeatedly, each time dividing the previous divisor by the previous remainder:
The process stops with a remainder , and the last non-zero remainder is . (If , then .)
Proof
The remainders form a strictly decreasing sequence of natural numbers . Such a sequence cannot go on for ever (its terms would form a non-empty set of natural numbers with no least element, contradicting well-ordering), so some remainder is . By Lemma 3,
since the greatest divisor of that also divides is itself.
∎
Example— The tiles: gcd(1071, 462)
The last non-zero remainder is , so : the largest tile is cm, and the floor takes tiles. Three divisions instead of listing dozens of divisors.
How fast is it? Each remainder is less than half of the number two steps before it (), so the number of steps grows only like the number of digits. Lamé's theorem (Gabriel Lamé, 1844) makes this precise: the number of division steps is at most five times the number of decimal digits of the smaller number, with consecutive Fibonacci numbers as the worst cases. The computation section tests this.
Explore: Euclid's algorithm as cutting squares
Here is the algorithm as geometry. From a rectangle, cut the largest possible squares; then do the same to the leftover strip, and so on. A square tile that fits both sides of the rectangle also fits the leftover — that is Lemma 3 — so the last square is the largest tile that fits exactly.
Euclid's algorithm: cutting squares
Step through the cuts. How many squares of each size do you cut, and how does that match the quotients 2, 2, 2?
252 × 105
Step 1 of 4
A 252 by 105 rectangle. Press “Next step” to cut off the biggest squares that fit.
- …
Things to try: change the sides to two consecutive Fibonacci numbers such as and (every cut removes just one square — the slowest case), and to two coprime numbers such as and (the last square has side ).
Bézout's identity and Euclid's lemma
Running Euclid's algorithm backwards writes the gcd in terms of and . From the tiles example:
Check: and , which differ by . This always works.
Theorem— Theorem 5 (Bézout's identity)
If and are integers, not both zero, there are integers and with
Moreover, is the smallest positive integer of the form , and every common divisor of and divides .
Proof
Let be the set of positive integers of the form with . It is non-empty ( is in it), so by well-ordering it has a least element .
divides . Divide: with . Then has the form . If were positive it would be an element of smaller than , which is impossible; so and . In the same way .
Every common divisor divides . If and , then by Lemma 1(b). In particular .
So is a common divisor and is at least as large as every common divisor: .
∎
The jug puzzle is now solved completely: with jugs of and litres one can measure exactly the multiples of (up to the size of the larger jug). And Bézout gives a useful test: and are coprime exactly when has an integer solution.
Theorem— Theorem 6 (Euclid's lemma)
Let be a prime. If , then or .
Proof
Suppose and . The only positive divisors of are and , and does not divide , so . By Bézout there are integers with . Multiplying by :
Both terms on the right are divisible by (the second because ), so by Lemma 1(b).
∎
The same proof shows more generally: if and , then . But the hypothesis matters: , yet . And by induction on the number of factors, if a prime divides a product , it divides at least one .
The fundamental theorem of arithmetic
Theorem— Theorem 7 (fundamental theorem of arithmetic)
Every integer can be written as a product of primes, , and this factorisation is unique apart from the order of the factors.
Proof
Existence, by strong induction on . If is prime, it is a product of one prime. Otherwise with ; by the induction hypothesis and are products of primes, and so is .
Uniqueness, by strong induction on . Suppose
with all and prime. Then divides , so by Euclid's lemma (for several factors) for some . Since is prime and , . Reorder the 's so that and cancel: . If this number is , both sides are empty products (). Otherwise it is smaller than and bigger than , and by the induction hypothesis the remaining primes agree apart from order. So the two factorisations agree apart from order.
∎
Collecting equal primes gives the familiar form with distinct primes and exponents . Uniqueness lets us read off divisors: the divisors of are exactly the numbers with . Consequently, for and (allowing exponents ),
and since , we get for positive . For and : and .
A second consequence answers a question from primary school: why do and stop, while and go on for ever?
Theorem— Theorem 8 (terminating decimals)
Let be a fraction in lowest terms, with . Its decimal expansion terminates if and only if has no prime factors other than and , that is, for some .
Proof
A decimal with digits after the point is a fraction with an integer. So terminates exactly when is an integer for some , that is, when for some .
If : let . Then , so , and terminates after at most digits.
Conversely, suppose and let be a prime factor of . Then . Since the fraction is in lowest terms, (otherwise would divide ). By Euclid's lemma (for several factors) divides one of the factors of , so , and by Euclid's lemma once more or , so or . By unique factorisation, .
∎
For example terminates because (indeed ); does not, because ; and "lowest terms" matters: terminates, although the denominator as written has the prime factor . (The lesson on fractions and decimals uses this rule.)
Why uniqueness needs a proof
Imagine the only numbers you knew were the Hilbert numbers — the numbers of the form . The product of two of them is again one of them, since . Call a Hilbert number bigger than irreducible if it is not a product of two smaller Hilbert numbers bigger than . Then , and are irreducible (, but is not a Hilbert number), and
Two different factorisations into irreducibles! Existence still holds (the same strong-induction proof works), but uniqueness fails. What breaks is Euclid's lemma: divides but does not divide (in the Hilbert numbers). There is no Bézout identity to rescue it, because the Hilbert numbers are not closed under subtraction.
So the proof of unique factorisation in really depends on Euclid's algorithm, through Bézout and Euclid's lemma. The same phenomenon appears in more serious number systems — see the algebraist's viewpoint below — and it shaped the history of number theory.
Euclid, Bézout and unique factorisation in Lean
Divisibility and division. Lemma 1(b), division with remainder from the library, and the uniqueness half proved here (nlinarith handles the inequalities).
/-- If `d ∣ a` and `d ∣ b`, then `d` divides every integer combination `a·x + b·y`:
from `a = d·k` and `b = d·l` we get `a·x + b·y = d·(k·x + l·y)`. -/
theorem dvd_linear_combination {d a b : ℤ} (ha : d ∣ a) (hb : d ∣ b) (x y : ℤ) :
d ∣ a * x + b * y := by
obtain ⟨k, rfl⟩ := ha
obtain ⟨l, rfl⟩ := hb
exact ⟨k * x + l * y, by ring⟩/-- **Division with remainder** (existence): for `b > 0`, every integer `a` is `b·q + r` with
`0 ≤ r < b`. This assembles core Lean's `Int.mul_ediv_add_emod`, `Int.emod_nonneg` and
`Int.emod_lt_of_pos`, with `q = a / b` and `r = a % b`. -/
theorem division_algorithm (a b : ℤ) (hb : 0 < b) :
∃ q r : ℤ, a = b * q + r ∧ 0 ≤ r ∧ r < b :=
⟨a / b, a % b, (Int.mul_ediv_add_emod a b).symm, Int.emod_nonneg a hb.ne', Int.emod_lt_of_pos a hb⟩/-- **Division with remainder** (uniqueness): if `b·q + r = b·q' + r'` with both remainders in
`[0, b)`, then `q = q'` and `r = r'`. Indeed `b·(q − q') = r' − r` lies strictly between `−b` and
`b`, and the only multiple of `b` there is `0`. -/
theorem division_unique {b q r q' r' : ℤ} (hb : 0 < b)
(h : b * q + r = b * q' + r') (hr : 0 ≤ r) (hrb : r < b) (hr' : 0 ≤ r') (hrb' : r' < b) :
q = q' ∧ r = r' := by
have hq : q = q' := by
by_contra hne
rcases lt_or_gt_of_ne hne with hlt | hgt
· have : b * q + b ≤ b * q' := by nlinarith
linarith
· have : b * q' + b ≤ b * q := by nlinarith
linarith
subst hq
exact ⟨rfl, by linarith⟩Our own Euclid. Lemma 3, then the algorithm as a recursive function. Lean only accepts the definition because it can check that the recursion terminates: the second argument decreases, . The correctness proof follows the recursion, using Lemma 3 at each step.
/-- **The key step of Euclid's algorithm**: `a, b` and `b, a mod b` have exactly the same common
divisors, because `a = b·(a / b) + (a mod b)`. -/
theorem common_divisors_mod (a b d : ℕ) : (d ∣ a ∧ d ∣ b) ↔ (d ∣ b ∧ d ∣ a % b) := by
have e : b * (a / b) + a % b = a := Nat.div_add_mod a b
constructor
· rintro ⟨ha, hb⟩
refine ⟨hb, ?_⟩
rw [← e] at ha
exact (Nat.dvd_add_right (Dvd.dvd.mul_right hb _)).mp ha
· rintro ⟨hb, hr⟩
refine ⟨?_, hb⟩
rw [← e]
exact Nat.dvd_add (Dvd.dvd.mul_right hb _) hr/-- **Euclid's algorithm**: `euclid a 0 = a`, and otherwise `euclid a b = euclid b (a mod b)`.
It terminates because the second argument strictly decreases (`a mod b < b`), and a decreasing
sequence of natural numbers cannot go on for ever. Lean checks this (`termination_by`). -/
def euclid : ℕ → ℕ → ℕ
| a, 0 => a
| a, b + 1 => euclid (b + 1) (a % (b + 1))
termination_by _ b => b
decreasing_by exact Nat.mod_lt _ (Nat.succ_pos _)/-- **Euclid's algorithm computes a greatest common divisor**: its output divides both inputs,
and every common divisor of the inputs divides the output. Proof by induction following the
recursion: when `b = 0` the output is `a`; otherwise apply `common_divisors_mod`. -/
theorem euclid_spec (a b : ℕ) :
(euclid a b ∣ a ∧ euclid a b ∣ b) ∧ ∀ d, d ∣ a → d ∣ b → d ∣ euclid a b := by
induction a, b using euclid.induct with
| case1 a =>
rw [euclid]
exact ⟨⟨dvd_refl a, dvd_zero a⟩, fun d ha _ => ha⟩
| case2 a b ih =>
rw [euclid]
obtain ⟨⟨h1, h2⟩, h3⟩ := ih
refine ⟨(common_divisors_mod a (b + 1) _).mpr ⟨h1, h2⟩, fun d ha hdb => ?_⟩
exact h3 d hdb ((common_divisors_mod a (b + 1) d).mp ⟨ha, hdb⟩).2/-- Our `euclid` agrees with Lean's `Nat.gcd`: two numbers that divide each other are equal. -/
theorem euclid_eq_gcd (a b : ℕ) : euclid a b = Nat.gcd a b := by
obtain ⟨⟨h1, h2⟩, h3⟩ := euclid_spec a b
exact Nat.dvd_antisymm (Nat.dvd_gcd h1 h2) (h3 _ (Nat.gcd_dvd_left a b) (Nat.gcd_dvd_right a b))/-- The lesson's worked example: `gcd(1071, 462) = 21` (`1071 = 2·462 + 147`, `462 = 3·147 + 21`,
`147 = 7·21`), computed by Lean's kernel. -/
theorem gcd_1071_462 : euclid 1071 462 = 21 := by
rw [euclid_eq_gcd]
rflBézout. The extended algorithm keeps track of the coefficients, and the proof is the back-substitution of the text, checked by linear_combination. Mathlib has its own extended algorithm, Nat.gcdA and Nat.gcdB.
/-- The **extended Euclidean algorithm**: integers `(x, y)` with `a·x + b·y = gcd(a, b)`.
If `b = 0` take `(1, 0)`. Otherwise, from `b·x' + (a mod b)·y' = g` and
`a mod b = a − b·(a / b)` we get `a·y' + b·(x' − (a / b)·y') = g`. -/
def xgcd : ℕ → ℕ → ℤ × ℤ
| _, 0 => (1, 0)
| a, b + 1 =>
let p := xgcd (b + 1) (a % (b + 1))
(p.2, p.1 - ((a / (b + 1) : ℕ) : ℤ) * p.2)
termination_by _ b => b
decreasing_by exact Nat.mod_lt _ (Nat.succ_pos _)/-- **Bézout's identity**, with the coefficients produced by `xgcd`:
`a·x + b·y = gcd(a, b)`. Proof by induction following the recursion, using the back-substitution
described in `xgcd`. -/
theorem bezout (a b : ℕ) :
(a : ℤ) * (xgcd a b).1 + (b : ℤ) * (xgcd a b).2 = (Nat.gcd a b : ℤ) := by
rw [← euclid_eq_gcd]
induction a, b using xgcd.induct with
| case1 a =>
rw [xgcd, euclid]
simp
| case2 a b ih =>
rw [xgcd, euclid]
have hcast : ((a % (b + 1) : ℕ) : ℤ) + ((b + 1 : ℕ) : ℤ) * ((a / (b + 1) : ℕ) : ℤ) = (a : ℤ) := by
exact_mod_cast Nat.mod_add_div a (b + 1)
simp only
linear_combination ih - (xgcd (b + 1) (a % (b + 1))).2 * hcast/-- Bézout's identity in Mathlib: `Nat.gcd_eq_gcd_ab`, with Mathlib's extended Euclidean algorithm
`Nat.gcdA`, `Nat.gcdB`. -/
theorem bezout_library (a b : ℕ) :
(Nat.gcd a b : ℤ) = a * Nat.gcdA a b + b * Nat.gcdB a b :=
Nat.gcd_eq_gcd_ab a b/-- **Euclid's lemma**: if a prime `p` divides `a·b`, then `p ∣ a` or `p ∣ b`.
If `p ∤ a` then `gcd(p, a) = 1` (the only positive divisors of `p` are `1` and `p`), so by Bézout
`p·x + a·y = 1`. Multiplying by `b`: `b = p·(b·x) + (a·b)·y`, and `p` divides both terms. -/
theorem euclid_lemma {p a b : ℕ} (hp : p.Prime) (h : p ∣ a * b) : p ∣ a ∨ p ∣ b := by
by_cases hpa : p ∣ a
· exact Or.inl hpa
· right
have hcop : Nat.gcd p a = 1 := (Nat.Prime.coprime_iff_not_dvd hp).mpr hpa
have hbez := bezout p a
rw [hcop, Nat.cast_one] at hbez
have hZ : (p : ℤ) ∣ (a : ℤ) * (b : ℤ) := by exact_mod_cast h
have key : (b : ℤ) = (p : ℤ) * ((b : ℤ) * (xgcd p a).1) + ((a : ℤ) * (b : ℤ)) * (xgcd p a).2 := by
linear_combination (-(b : ℤ)) * hbez
have : (p : ℤ) ∣ (b : ℤ) := by
rw [key]
exact dvd_add (dvd_mul_right _ _) (Dvd.dvd.mul_right hZ _)
exact_mod_cast this/-- Euclid's lemma in Mathlib: `Nat.Prime.dvd_mul`. -/
theorem euclid_lemma_library {p a b : ℕ} (hp : p.Prime) : p ∣ a * b ↔ p ∣ a ∨ p ∣ b :=
hp.dvd_mul/-- **Primality matters in Euclid's lemma**: `4 ∣ 2·2`, but `4 ∤ 2`. -/
theorem four_counterexample : 4 ∣ 2 * 2 ∧ ¬ 4 ∣ 2 := by decideThe fundamental theorem. Factorisations are lists of primes; "unique apart from order" means the two lists are permutations of each other (List.Perm, written ~).
/-- **Existence of prime factorisations**, by strong induction: every `n ≥ 1` is the product of a
list of primes (`1` is the empty product). For `n > 1`, let `p` be its smallest factor bigger
than `1` — a prime — and factorise the smaller number `n / p`. -/
theorem exists_prime_factorization (n : ℕ) (hn : n ≠ 0) :
∃ l : List ℕ, (∀ p ∈ l, p.Prime) ∧ l.prod = n := by
induction n using Nat.strong_induction_on with
| _ n ih =>
by_cases h1 : n = 1
· exact ⟨[], by simp, by simp [h1]⟩
· have hp : (Nat.minFac n).Prime := Nat.minFac_prime h1
have hdiv : Nat.minFac n * (n / Nat.minFac n) = n := Nat.mul_div_cancel' (Nat.minFac_dvd n)
have hlt : n / Nat.minFac n < n := Nat.div_lt_self (Nat.pos_of_ne_zero hn) hp.one_lt
have hne : n / Nat.minFac n ≠ 0 := by
intro h0
rw [h0, Nat.mul_zero] at hdiv
exact hn hdiv.symm
obtain ⟨l, hl, hprod⟩ := ih (n / Nat.minFac n) hlt hne
refine ⟨Nat.minFac n :: l, ?_, ?_⟩
· intro q hq
rcases List.mem_cons.mp hq with rfl | hq
· exact hp
· exact hl q hq
· rw [List.prod_cons, hprod, hdiv]/-- Euclid's lemma for several factors: if a prime divides a product of a list of numbers, it
divides one of them. Induction on the list, using `euclid_lemma` at each step. -/
theorem prime_dvd_prod {p : ℕ} (hp : p.Prime) :
∀ l : List ℕ, p ∣ l.prod → ∃ q ∈ l, p ∣ q
| [], h => absurd (Nat.dvd_one.mp h) hp.one_lt.ne'
| q :: t, h => by
rw [List.prod_cons] at h
rcases euclid_lemma hp h with hq | ht
· exact ⟨q, List.mem_cons_self, hq⟩
· obtain ⟨r, hr, hpr⟩ := prime_dvd_prod hp t ht
exact ⟨r, List.mem_cons_of_mem q hr, hpr⟩/-- **Uniqueness of prime factorisations**: two lists of primes with the same product are
rearrangements of each other (`List.Perm`, written `~`). Induction on the first list: its head `p`
divides the product of the second, so (Euclid's lemma) it divides — hence equals — one of its
primes `q`; remove `p` from both sides and cancel. -/
theorem factorization_unique :
∀ l₁ l₂ : List ℕ, (∀ p ∈ l₁, p.Prime) → (∀ p ∈ l₂, p.Prime) → l₁.prod = l₂.prod → l₁.Perm l₂
| [], l₂, _, h₂, h => by
cases l₂ with
| nil => exact List.Perm.refl []
| cons q t =>
exfalso
have hq : q ∣ (q :: t).prod := by rw [List.prod_cons]; exact dvd_mul_right q _
rw [← h, List.prod_nil] at hq
exact (h₂ q List.mem_cons_self).one_lt.ne' (Nat.dvd_one.mp hq)
| p :: t, l₂, h₁, h₂, h => by
have hp : p.Prime := h₁ p List.mem_cons_self
have hdvd : p ∣ l₂.prod := by rw [← h, List.prod_cons]; exact dvd_mul_right p _
obtain ⟨q, hq, hpq⟩ := prime_dvd_prod hp l₂ hdvd
have hpq' : p = q := (Nat.prime_dvd_prime_iff_eq hp (h₂ q hq)).mp hpq
subst hpq'
have hperm : l₂.Perm (p :: l₂.erase p) := List.perm_cons_erase hq
have hprod : t.prod = (l₂.erase p).prod := by
have e : p * t.prod = p * (l₂.erase p).prod := by
rw [← List.prod_cons, h, hperm.prod_eq, List.prod_cons]
exact Nat.eq_of_mul_eq_mul_left hp.pos e
have ht : t.Perm (l₂.erase p) :=
factorization_unique t (l₂.erase p) (fun r hr => h₁ r (List.mem_cons_of_mem p hr))
(fun r hr => h₂ r (List.mem_of_mem_erase hr)) hprod
exact (ht.cons p).trans hperm.symm/-- Unique factorisation in Mathlib: `Nat.primeFactorsList_unique` — any list of primes with
product `n` is a rearrangement of Mathlib's list `n.primeFactorsList`. -/
theorem factorization_unique_library {n : ℕ} {l : List ℕ} (h₁ : l.prod = n)
(h₂ : ∀ p ∈ l, p.Prime) : l.Perm n.primeFactorsList :=
Nat.primeFactorsList_unique h₁ h₂Terminating decimals (Theorem 8). A fraction terminates when for some ; both directions of Theorem 8 are proved in that form.
/-- If a prime divides a power `n ^ k`, it divides `n`: Euclid's lemma applied `k` times
(induction on `k`; for `k = 0`, no prime divides `1`). -/
theorem prime_dvd_pow {p n : ℕ} (hp : p.Prime) : ∀ k : ℕ, p ∣ n ^ k → p ∣ n
| 0, h => absurd (Nat.dvd_one.mp (by simpa using h)) hp.one_lt.ne'
| k + 1, h => by
rw [pow_succ] at h
rcases euclid_lemma hp h with h1 | h2
· exact prime_dvd_pow hp k h1
· exact h2/-- **Terminating decimals, one direction.** A fraction `a / b` has a terminating decimal exactly
when `a · 10ᵏ / b` is a whole number for some `k`, i.e. `b ∣ a · 10ᵏ`. If moreover `a / b` is in
lowest terms (`gcd(a, b) = 1`), then every prime factor `p` of `b` is `2` or `5`: `p` divides
`a · 10ᵏ` but not `a`, so (Euclid's lemma) it divides `10ᵏ`, hence `10 = 2 · 5`, hence `2` or `5`. -/
theorem terminating_prime_factors {a b k p : ℕ} (hcop : Nat.gcd a b = 1) (h : b ∣ a * 10 ^ k)
(hp : p.Prime) (hpb : p ∣ b) : p = 2 ∨ p = 5 := by
have hpa10 : p ∣ a * 10 ^ k := Nat.dvd_trans hpb h
rcases euclid_lemma hp hpa10 with hpa | hp10
· have : p ∣ Nat.gcd a b := Nat.dvd_gcd hpa hpb
rw [hcop] at this
exact absurd (Nat.dvd_one.mp this) hp.one_lt.ne'
· have h10 : p ∣ 2 * 5 := prime_dvd_pow hp k hp10
rcases euclid_lemma hp h10 with h2 | h5
· exact Or.inl ((Nat.prime_dvd_prime_iff_eq hp Nat.prime_two).mp h2)
· exact Or.inr ((Nat.prime_dvd_prime_iff_eq hp Nat.prime_five).mp h5)/-- **Terminating decimals, the other direction.** If `b = 2ˢ · 5ᵗ`, then `b ∣ 10^(s + t)`, so
`a / b = a · c / 10^(s + t)` for a whole number `c`: the decimal terminates after `s + t` digits
(in fact after `max(s, t)`). Proof: `10^(s+t) = 2^(s+t) · 5^(s+t)`. -/
theorem two_five_dvd_ten_pow (s t : ℕ) : 2 ^ s * 5 ^ t ∣ 10 ^ (s + t) := by
have e : (10 : ℕ) ^ (s + t) = 2 ^ (s + t) * 5 ^ (s + t) := by
rw [← mul_pow]
rfl
rw [e]
exact Nat.mul_dvd_mul (Nat.pow_dvd_pow 2 (Nat.le_add_right s t))
(Nat.pow_dvd_pow 5 (Nat.le_add_left t s))Hilbert numbers. Irreducibility is defined with an unbounded "for all", proved equivalent to a finite check, and the finite check is run by Lean's kernel.
/-- In the **Hilbert numbers** `1, 5, 9, 13, …` (those leaving remainder `1` on division by `4`,
which are closed under multiplication), `n > 1` is *irreducible* if it is not a product of two
smaller Hilbert numbers bigger than `1`. -/
def HilbertIrreducible (n : ℕ) : Prop :=
n % 4 = 1 ∧ 1 < n ∧ ∀ a b : ℕ, (a % 4 = 1 ∧ b % 4 = 1 ∧ a * b = n) → a = 1 ∨ b = 1/-- Irreducibility is a **finite check**: if `a · b = n` with `n > 0`, both factors are at most `n`,
so only `a, b ≤ n` need to be tried. -/
theorem hilbertIrreducible_iff (n : ℕ) :
HilbertIrreducible n ↔ n % 4 = 1 ∧ 1 < n ∧
∀ a < n + 1, ∀ b < n + 1, (a % 4 = 1 ∧ b % 4 = 1 ∧ a * b = n) → a = 1 ∨ b = 1 := by
constructor
· rintro ⟨h4, h1, h⟩
exact ⟨h4, h1, fun a _ b _ hab => h a b hab⟩
· rintro ⟨h4, h1, h⟩
refine ⟨h4, h1, fun a b hab => ?_⟩
have hn : 0 < n := by omega
have ha : a ≤ n := Nat.le_of_dvd hn ⟨b, hab.2.2.symm⟩
have hb : b ≤ n := Nat.le_of_dvd hn ⟨a, by rw [Nat.mul_comm]; exact hab.2.2.symm⟩
exact h a (by omega) b (by omega) hab/-- **Unique factorisation needs proof**: among Hilbert numbers, `9`, `21` and `49` are irreducible,
yet `441 = 9 · 49 = 21 · 21` — two genuinely different factorisations into irreducibles. Checked
by the finite search of `hilbertIrreducible_iff` (`decide`). -/
theorem hilbert_non_unique :
HilbertIrreducible 9 ∧ HilbertIrreducible 21 ∧ HilbertIrreducible 49 ∧
9 * 49 = 441 ∧ 21 * 21 = 441 := by
refine ⟨?_, ?_, ?_, rfl, rfl⟩ <;> rw [hilbertIrreducible_iff] <;> decideWhat is formalised: every theorem of the lesson except Lamé's theorem and the gcd–lcm formula. Mathlib also has these facts in great generality — for instance unique factorisation in every unique factorisation domain (UniqueFactorizationMonoid), which includes every Euclidean domain.
Euclid by machine
"""Euclid's algorithm: the steps, Bezout's coefficients, and how fast it is.
1. The extended Euclidean algorithm on (1071, 462): each division step
a = q*b + r, and the integers x, y with 1071x + 462y = gcd(1071, 462).
2. Lame's theorem (1844): the number of division steps is at most five times
the number of decimal digits of the smaller number. We find the slowest
pair below each power of 10 by exhaustive search and compare: consecutive
Fibonacci numbers are the worst cases.
Runs unchanged in the browser (Pyodide) using only the standard library.
"""
def euclid_steps(a, b):
"""The division steps (a, q, b, r) with a = q*b + r of Euclid's algorithm."""
if a < 0 or b < 0:
raise ValueError("a and b must be non-negative")
steps = []
while b:
q, r = divmod(a, b)
steps.append((a, q, b, r))
a, b = b, r
return steps
def extended_gcd(a, b):
"""Return (g, x, y) with a*x + b*y = g = gcd(a, b), by back-substitution
through Euclid's algorithm (iterative version)."""
x0, y0, x1, y1 = 1, 0, 0, 1
while b:
q, r = divmod(a, b)
a, b = b, r
x0, x1 = x1, x0 - q * x1
y0, y1 = y1, y0 - q * y1
return a, x0, y0
def fibonacci(k):
"""F_0 = 0, F_1 = 1, F_(k+1) = F_k + F_(k-1)."""
a, b = 0, 1
for _ in range(k):
a, b = b, a + b
return a
def slowest_pair(b_limit, a_limit):
"""Among 1 <= b < a < a_limit with b < b_limit, a pair with the most
division steps (the first found), and that number of steps."""
best, best_pair = -1, None
for b in range(1, b_limit):
for a in range(b + 1, a_limit):
n = len(euclid_steps(a, b))
if n > best:
best, best_pair = n, (a, b)
return best_pair, best
def main():
print("1. Euclid's algorithm on 1071 and 462:")
for a, q, b, r in euclid_steps(1071, 462):
print(f" {a:5d} = {q} * {b:4d} + {r}")
g, x, y = extended_gcd(1071, 462)
print(f" gcd = {g} = 1071 * ({x}) + 462 * {y}"
f" [check: {1071 * x + 462 * y}]")
print()
print("2. Slowest pairs (exhaustive search) and Lame's bound:")
print(" b < a < slowest pair (a, b) steps 5 x digits of b")
for b_limit, a_limit in [(10, 60), (100, 300), (1000, 1000)]:
(a, b), n = slowest_pair(b_limit, a_limit)
print(f" {b_limit:4d} {a_limit:4d} {str((a, b)):19} {n:5d}"
f" {5 * len(str(b)):15d}")
fib = [fibonacci(k) for k in range(8, 18)]
print(" Fibonacci numbers:", ", ".join(map(str, fib)))
print(" steps for (F_(k+1), F_k), k = 2..16:", " ".join(
str(len(euclid_steps(fibonacci(k + 1), fibonacci(k)))) for k in range(2, 17)))
print()
print("Epistemic status: exact integer arithmetic; part 2 is an exhaustive")
print("search over the stated finite ranges. It agrees with Lame's theorem")
print("but proves it only there; the general proof compares the remainders")
print("with Fibonacci numbers.")
if __name__ == "__main__":
main()The slowest pairs are consecutive Fibonacci numbers, where every quotient is — exactly the squares-widget picture in which each cut removes a single square.
"""When factorisation is not unique - and how often numbers are coprime.
1. The Hilbert numbers 1, 5, 9, 13, ... (those of the form 4k + 1) are closed
under multiplication. Call one irreducible if it is bigger than 1 and not a
product of two smaller Hilbert numbers bigger than 1. Every Hilbert number
is a product of irreducibles, but not uniquely: 441 = 9 * 49 = 21 * 21.
We list all factorisations into irreducibles up to 1500.
2. For contrast, we check that among ordinary integers 2..1500 every number has
exactly one factorisation into primes (as the fundamental theorem says).
3. Two numbers picked "at random" are coprime with probability 6/pi^2. We
count exactly the coprime pairs in {1, ..., N}^2 using Euler's totient
function, for N up to 100 000.
Runs unchanged in the browser (Pyodide) using only the standard library.
"""
import math
def factorizations(n, atoms):
"""All factorisations of n as non-decreasing products of numbers in the
sorted list ``atoms``, as tuples."""
if n == 1:
return [()]
out = []
def go(m, start, acc):
if m == 1:
out.append(tuple(acc))
return
for i in range(start, len(atoms)):
a = atoms[i]
if a > m:
break
if m % a == 0:
go(m // a, i, acc + [a])
go(n, 0, [])
return out
def hilbert_irreducibles(limit):
"""Hilbert numbers 5 <= n <= limit that are not a product of two smaller
Hilbert numbers greater than 1."""
irr = []
for n in range(5, limit + 1, 4):
if not any(n % a == 0 and (n // a) % 4 == 1 for a in irr if a * a <= n):
irr.append(n)
return irr
def primes_up_to(limit):
"""Sieve of Eratosthenes."""
sieve = bytearray([1]) * (limit + 1)
sieve[0:2] = b"\x00\x00"
for p in range(2, int(limit ** 0.5) + 1):
if sieve[p]:
sieve[p * p::p] = bytearray(len(range(p * p, limit + 1, p)))
return [i for i in range(limit + 1) if sieve[i]]
def totients(limit):
"""phi(0..limit) by a sieve."""
phi = list(range(limit + 1))
for p in range(2, limit + 1):
if phi[p] == p: # p is prime
for k in range(p, limit + 1, p):
phi[k] -= phi[k] // p
return phi
def coprime_pairs(n, phi):
"""Number of ordered pairs (a, b) in {1..n}^2 with gcd(a, b) = 1:
2 * (phi(1) + ... + phi(n)) - 1."""
return 2 * sum(phi[1:n + 1]) - 1
def main():
limit = 1500
irr = hilbert_irreducibles(limit)
print("1. Hilbert irreducibles start:", ", ".join(map(str, irr[:12])), "...")
print(" Hilbert numbers <= 1500 with more than one factorisation:")
for n in range(1, limit + 1, 4):
fs = factorizations(n, irr)
if len(fs) > 1:
print(f" {n:5d} = " + " = ".join(" * ".join(map(str, f)) for f in fs))
primes = primes_up_to(limit)
counts = [len(factorizations(n, primes)) for n in range(2, limit + 1)]
print(f"2. Integers 2..{limit}: every one has exactly one prime factorisation:"
f" {all(c == 1 for c in counts)}")
phi = totients(100_000)
print("3. Proportion of coprime pairs in {1..N}^2 (6/pi^2 = "
f"{6 / math.pi ** 2:.6f}):")
for n in (10, 100, 1000, 10_000, 100_000):
print(f" N = {n:6d}: {coprime_pairs(n, phi) / n ** 2:.6f}")
print()
print("Epistemic status: parts 1 and 2 are exhaustive searches up to 1500;")
print("part 3 is an exact count turned into decimals. They illustrate the")
print("theorems - unique factorisation in Z, its failure for Hilbert numbers,")
print("and the limit 6/pi^2, a classical theorem - but a finite range proves")
print("none of them.")
if __name__ == "__main__":
main()Part 3 counts, among all pairs of whole numbers up to , the fraction that are coprime. It approaches — a classical theorem, and a first meeting between number theory and . The computation is exact counting, but a finite range can only illustrate the limit.
Exercises
1. Divisibility, Euclid's algorithm and unique factorisation
Warm-upHumanUse Euclid's algorithm to compute .
2. Divisibility, Euclid's algorithm and unique factorisation
Warm-upHumanWhich pairs satisfy ? (Choose all that apply.)
3. Divisibility, Euclid's algorithm and unique factorisation
CoreHumanFor which of these numbers is it true that for all integers : if then or ? (Choose all that apply.)
4. Divisibility, Euclid's algorithm and unique factorisation
CoreHumanCompute .
5. Divisibility, Euclid's algorithm and unique factorisation
CoreHumanWhich of these fractions have a terminating decimal expansion? (Choose all that apply.)
6. Divisibility, Euclid's algorithm and unique factorisation
CoreHumanIn the proof of Euclid's lemma we assume and , and then say . Why?
7. Divisibility, Euclid's algorithm and unique factorisation
CoreHumanWith a -litre jug, a -litre jug and a tap, what is the smallest positive amount of water you can measure exactly (by filling, emptying and pouring between the jugs)?
8. Divisibility, Euclid's algorithm and unique factorisation
StretchHumanIn the Hilbert numbers (numbers of the form ), which statement is true?
9. Divisibility, Euclid's algorithm and unique factorisation
CoreFormalWhich Lean statement correctly formalises Euclid's lemma for natural numbers?
10. Divisibility, Euclid's algorithm and unique factorisation
StretchComputationalWrite extended_gcd(a, b) for natural numbers a, b (not both zero), returning a triple (g, x, y) with g == gcd(a, b) and a * x + b * y == g. Use the recursion: if b == 0 return (a, 1, 0); otherwise get (g, x, y) for (b, a % b) and back-substitute using a % b == a - (a // b) * b.
Common misconceptions
Misconception
"Unique factorisation is obvious." It feels obvious because we have used it for years, but it is a theorem whose proof needs Euclid's lemma, and so Bézout's identity and Euclid's algorithm. In the Hilbert numbers it fails: .
Misconception
"If , then or ." True when is prime (Euclid's lemma), false in general: but ; but divides neither.
Misconception
Confusing gcd and lcm. The greatest common divisor is the biggest number that goes into both (); the least common multiple is the smallest number that both go into (). A quick check: the gcd is never bigger than the smaller number, and the lcm never smaller than the larger.
Misconception
"Coprime means at least one of the numbers is prime." and are coprime, and neither is prime. Coprime means the two numbers share no prime factor.
Misconception
"To find a gcd you must factorise first." Euclid's algorithm needs no factorisation at all — which matters, because factorising large numbers is believed to be very hard, while Euclid's algorithm is fast even for numbers with hundreds of digits.
Many ways of seeing
Algebra— ideals and unique factorisation domains
The set of all combinations , written , is closed under addition, subtraction and multiplication by integers — an ideal of . Bézout's theorem says it equals with : every ideal of consists of the multiples of one number ( is a principal ideal domain). The same proof works wherever there is division with a remainder that gets smaller — in a Euclidean domain, such as polynomials over or the Gaussian integers — so these too have unique factorisation. But in ,
with all four factors irreducible: unique factorisation fails. Ernst Kummer's "ideal numbers" and Richard Dedekind's ideals were invented in the 19th century to repair this; see rings, ideals and fields.
Geometry— lattice points and cutting squares
Draw the integer grid. The line passes through a grid point exactly when — Bézout in geometric form. The segment from to , with , passes through exactly grid points (counting both ends), because the points on it are for with . And Euclid's algorithm is literally geometric: the Greeks thought of it as repeatedly subtracting the smaller length from the larger (anthyphairesis), the squares-cutting picture of the explorer. Applied to a diagonal and side of a square, the process never ends — one route to the irrationality of .
Probability— the chance of being coprime
Pick two whole numbers "at random". The chance that both are even is about , that both are multiples of about , and so on for each prime. If these events behaved independently, the chance of sharing no prime factor would be , and Euler showed this product equals , where . The heuristic can be made rigorous (the limit statement is a classical theorem), and the computation section shows the proportions creeping towards
Computation— an algorithm for the ages
Euclid's algorithm is among the oldest algorithms still in everyday use. By Lamé's theorem it needs a number of steps proportional to the number of digits, so it handles numbers with hundreds of digits instantly. The extended version computes inverses in clock arithmetic: if then gives . That is how the RSA cryptosystem, which protects much of the world's online communication, computes its secret key. See algorithms and efficiency and congruences.
Wonder Trails
Remainders lead to the arithmetic of clocks — where Bézout's identity decides which numbers can be "divided by".
Wonder Trail · Optional · never gradedRemainder familiesSort every integer — positive, negative and zero — into families by its remainder after dividing by 3. If you add a member of one family to a member of another, does the family of the answer depend on which members you chose?Follow the trail Wonder Trail · Optional · never gradedClock arithmeticIt's 9 o'clock. What time will it be in 5 hours — and in 29 hours? Can a clock teach us a whole new kind of arithmetic?Follow the trailHistory and global context
- Euclid's Elements (around 300 BCE), Book VII, opens with the algorithm (Propositions 1–2), phrased as repeatedly subtracting the smaller number from the larger, and proves Euclid's lemma as Proposition 30. Book IX, Proposition 14, comes close to the uniqueness of factorisation.
- China. The Nine Chapters on the Mathematical Art (compiled by about the 1st century CE) reduces fractions using the "mutual subtraction" method (gēng xiāng jiǎn sǔn), which is Euclid's algorithm by repeated subtraction.
- India. Āryabhaṭa (499 CE) gave the kuṭṭaka ("pulveriser") method for solving in integers, essentially the extended Euclidean algorithm; Brahmagupta (628 CE) and later Indian mathematicians developed it further, including applications to astronomy and calendars.
- Bézout's identity for integers appears in the work of Claude-Gaspard Bachet de Méziriac (1624); Étienne Bézout (1779) proved the analogous result for polynomials, and his name stuck.
- Unique factorisation. Kamāl al-Dīn al-Fārisī (Persia, around 1300) proved the existence of prime factorisations and took steps towards uniqueness. The first clear statement and proof of uniqueness is in Carl Friedrich Gauss's Disquisitiones Arithmeticae (1801).
- Algorithms and ideals. Gabriel Lamé's 1844 bound on Euclid's algorithm is often called the first analysis of the running time of an algorithm. In the 1840s Ernst Kummer discovered that unique factorisation fails in some number systems arising from Fermat's Last Theorem, and invented "ideal numbers" to restore it.
Further reading
- G. H. Hardy and E. M. Wright, An Introduction to the Theory of Numbers (1938), chapters 1–2: primes, the fundamental theorem and its proofs.
- Ivan Niven, Herbert S. Zuckerman and Hugh L. Montgomery, An Introduction to the Theory of Numbers (5th edition, 1991), chapter 1.
- Harold Davenport, The Higher Arithmetic (1952) — a short, beautifully written introduction.
- Donald E. Knuth, The Art of Computer Programming, volume 2: Seminumerical Algorithms (1969), section 4.5.2 on the analysis of Euclid's algorithm.