05.1 因數與質數#
本節目標#
- 理解整除關係 \(a \mid b\) 的形式定義,並熟悉
Nat.dvd的基本性質。 - 認識 Lean 4 / Mathlib 中
Nat.Prime的定義。 - 用 Lean 證明質數有無窮多個(Euclid 的經典論證)。
- 寫出一個判斷質數的小工具,並與
Nat.Prime掛勾。
整除的定義#
在數論中,我們說 \(a\) 整除 \(b\) (記作 \(a \mid b\) ),是指存在整數 \(k\) 使得 \(b = a \cdot k\) 。例如 \(3 \mid 12\) ,因為 \(12 = 3 \times 4\) ;但 \(5 \nmid 12\) 。
在 Mathlib 中,這個關係是廣義的 Dvd 類別,自然數上的版本就是 Nat.dvd:
-- Mathlib 中的定義(概念示意)
-- a ∣ b ↔ ∃ k, b = a * k
example (a b : ℕ) : a ∣ b ↔ ∃ k, b = a * k := dvd_iff_exists_eq_mul_left
注意 Lean 中 ∣ 是一個符號記號(輸入方式:\mid),3 ∣ 12 讀作「3 整除 12」。
整除的基本性質#
整除最重要的兩條性質是反身性與傳遞性:
- 反身性: \(a \mid a\) ,因為 \(a = a \cdot 1\) 。
- 傳遞性:若 \(a \mid b\) 且 \(b \mid c\) ,則 \(a \mid c\) 。
example (a : ℕ) : a ∣ a := Nat.dvd_refl a
example (a b c : ℕ) (hab : a ∣ b) (hbc : b ∣ c) : a ∣ c :=
Nat.dvd_trans hab hbc
其他常用的性質:
example (a : ℕ) : 1 ∣ a := Nat.one_dvd a
example (a : ℕ) : a ∣ 0 := dvd_zero a
-- 若 a ∣ b 且 a ∣ c,則 a ∣ b + c
example (a b c : ℕ) (hab : a ∣ b) (hac : a ∣ c) : a ∣ b + c :=
Nat.dvd_add hab hac
-- 若 a ∣ b,則對任意 k,a ∣ k * b
example (a b k : ℕ) (hab : a ∣ b) : a ∣ k * b :=
Nat.dvd_mul_of_dvd_right hab k
這些引理的命名都有規律:dvd_refl、dvd_trans、dvd_add、dvd_mul_of_dvd_right, 讀者可以從名稱猜出內容,這正是 Mathlib 命名規範的威力。
質數的定義#
定義:自然數 \(p > 1\) 稱為質數(prime),若 \(p\) 的正因數只有 \(1\) 和 \(p\) 本身。
等價的說法:若 \(p = a \cdot b\) ,則 \(a = 1\) 或 \(b = 1\) 。
Mathlib 中 Nat.Prime p 的定義正是後者:
-- Mathlib 定義(示意)
-- def Nat.Prime (p : ℕ) : Prop :=
-- 2 ≤ p ∧ ∀ a b : ℕ, p = a * b → a = 1 ∨ b = 1
example : Nat.Prime 2 := by decide
example : Nat.Prime 3 := by decide
example : ¬ Nat.Prime 4 := by decide
example : ¬ Nat.Prime 1 := by simp [Nat.Prime]
decide 能處理這些具體數字,是因為 Nat.Prime 是可判定的命題(對小數字而言)。
篩法的直覺#
要找出不超過 \(n\) 的所有質數,Eratosthenes 篩法(sieve)的想法是:
- 列出 \(2, 3, 4, \dots, n\) 。
- 取最小的未刪數 \(2\) ,它是質數;刪掉所有 \(2\) 的倍數。
- 取下一個未刪數 \(3\) ,它是質數;刪掉所有 \(3\) 的倍數。
- 重複,直到剩下的最小未刪數超過 \(\sqrt{n}\) 。
正確性的關鍵觀察:若 \(n\) 是合數,則 \(n = a \cdot b\) 且 \(1 < a \le b\) , 於是 \(a \le \sqrt{n}\) ,即 \(n\) 必有一個不超過 \(\sqrt{n}\) 的質因數。
-- 合數必有大於 1 且小於自身的因數
example (n : ℕ) (hn : ¬ Nat.Prime n) (hn1 : 1 < n) :
∃ m, m ∣ n ∧ 1 < m ∧ m < n := by
rcases Nat.exists_eq_mul_of_not_prime hn hn1 with ⟨a, b, heq, ha, hb⟩
exact ⟨a, ⟨a, by rw [heq]⟩, ha, by have := Nat.lt_of_mul_lt_mul_left hb; omega⟩
用 Lean 形式化完整的篩法需要陣列操作,超出本節範圍,但上面這個「合數有真因數」 的引理正是篩法與下一節唯一分解定理的基石。
質數無窮多:Euclid 的論證#
定理(Euclid):質數有無窮多個。
Euclid 的證明思路:假設質數只有有限個 \(p_1, \dots, p_k\) ,考慮 \(N = p_1 \cdot p_2 \cdots p_k + 1\) 。任何 \(p_i\) 都不整除 \(N\) (因為 \(N \div p_i\) 餘 1), 所以 \(N\) 的質因數不在名單中,矛盾。
Mathlib 已經內建這個結果:
theorem Nat.Prime.infinite : {p : ℕ | Nat.Prime p}.Infinite := by
exact Nat.prime_infinite
更精確地,Mathlib 提供的 Nat.Prime.infinite 是從「任意有限集合都會遺漏某個質數」 的角度陳述的。我們也可以自己動手證一個局部版本,體會 Euclid 的論證:
-- 給定一個數 n,存在質數大於 n
example (n : ℕ) : ∃ p, Nat.Prime p ∧ n < p := by
obtain ⟨p, hp, hn⟩ := Nat.exists_infinite_prime n 0
exact ⟨p, hp, hn⟩
背後的核心引理是: \(n + 1\) 有一個質因數,且該質因數大於 \(n\) 的所有質因數會導出矛盾。 Mathlib 中的 Nat.exists_infinite_prime 就封裝了這條路線。
判斷質數的小工具#
實作上,判斷 \(n\) 是否為質數只需檢查 \(2\) 到 \(\sqrt{n}\) 之間有沒有因數:
/-- 用試除法判斷 n 是否為質數(作為程式,不是證明)。 -/
def isPrimeTrial (n : ℕ) : Bool :=
if n < 2 then false
else (2 * 2 ≤ n → ∀ k, 2 ≤ k → k * k ≤ n → n % k ≠ 0) && true
上面的寫法刻意保守:把「沒有小於等於 \(\sqrt{n}\) 的因數」寫成命題,而不是迴圈, 因為在 Lean 中直接寫迴圈還需要證明終止。若要驗證它與 Nat.Prime 一致,可利用 Mathlib 的 Nat.Prime 判定引理:
-- Nat.Prime 的判定:n 是質數 ↔ 沒有 2 ≤ k ≤ √n 的因數
example (n : ℕ) (hn : 2 ≤ n) :
Nat.Prime n ↔ ∀ k, 2 ≤ k → k ≤ n → ¬ (k ∣ n) := by
rw [Nat.prime_def_lt_two] <;> sorry -- 完整證明見練習
Mathlib 中實際可用的工具還有:
#check Nat.prime_def_lt_two
#check Nat.Prime.ne_zero
#check Nat.Prime.not_dvd_one
#check Nat.prime_two
#check Nat.prime_three
小結與練習#
本節重點:
- \(a \mid b\) 定義為 \(\exists k,\ b = a \cdot k\) ,核心引理是
dvd_refl、dvd_trans。 Nat.Prime p定義為 \(2 \le p\) 且「乘積分解必有一邊為 1」。- Euclid 論證: \(p_1 \cdots p_k + 1\) 製造新質數;Mathlib 對應
Nat.Prime.infinite。
練習:
- 證明:若 \(a \mid b\) 且 \(b \mid a\) ,則 \(a = b\) (提示:
Nat.dvd_antisymm)。 - 證明:若 \(p\) 是質數且 \(p \mid n \cdot n\) ,則 \(p \mid n\) (提示:先證 \(p \mid n\) 或 \(p \mid n\) ,其實這是 Euclid lemma 的特例,可用
Nat.Prime.dvd_mul)。 - 用
decide檢查 \(5, 7, 11, 13\) 都是質數, \(9, 15, 21\) 不是。 - 挑戰:證明對任意 \(n \ge 2\) ,存在嚴格大於 \(n\) 的質數(提示:考慮 \(n! + 1\) , 用
Nat.factorial與Nat.Prime.exists_gt)。 - 思考題:Euclid 論證中為什麼 \(p_i \nmid (p_1 \cdots p_k + 1)\) ? 試在 Lean 中用
Nat.dvd_add_right或餘數論證表達這件事。