Skip to content

feat(ch31): complete the Miller-Rabin error bound (Theorem 31.39, 4th ed.) - #155

Open
TankTechnology wants to merge 25 commits into
mainfrom
feat/ch31-refinements
Open

feat(ch31): complete the Miller-Rabin error bound (Theorem 31.39, 4th ed.)#155
TankTechnology wants to merge 25 commits into
mainfrom
feat/ch31-refinements

Conversation

@TankTechnology

Copy link
Copy Markdown
Owner

Completes the last remaining hard theorem in Chapter 31: the Rabin–Monier
error bound — at most (n−1)/4 of the bases are strong liars for odd
composite n.

What this PR proves

CLRS.Chapter31.strongLiars_card_le — the headline theorem. It follows
from goodUnits_card_le, which bounds the good subgroup S(n) by three
cases on the number of distinct prime factors:

  • k=1 (prime power n = p^e): |S| ≤ p−1 ≤ (p^e−1)/4.
  • k=2 (semiprime n = p^a q^b): squarefree n = pq uses the refined
    8·gcd(m,p−1)·gcd(m,q−1) ≤ pq−1, split into s < r and s = r; the
    latter needs the key lemma d_p | t ∧ d_q | t ⟹ p = q. Non-squarefree
    uses the crude 2(p−1)(q−1) ≤ n−1.
  • k≥3: 2^(1−k)·∏(p−1) ≤ (n−1)/4.

Verification

  • lake build CLRSLean passes (8900 jobs).
  • #print axioms strongLiars_card_le / goodUnits_card_le show only
    propext, Classical.choice, Quot.sound — no sorryAx.
  • scripts/check_repository.py passes.
  • Progress CSV updated to 29/29 tracked theorems for Chapter 31.

This resolves the deferred item in the chapter guide (§31.8). The only
remaining informal item in Chapter 31 is the POLLARD-RHO birthday-paradox
heuristic (documented as informal in CLRS).

🤖 Generated with Claude Code

TankTechnology and others added 23 commits August 5, 2026 20:32
- 31.5 chinese_remainder_general: the full k-modulus Chinese remainder
  theorem via Nat.chineseRemainderOfList (existence + uniqueness mod the
  product).
- 31.4 linear_congruence_solutions: the solutions of a·x ≡ b (mod n) are
  exactly the residue class x0 mod (n/gcd(a,n)) (Thm 31.10).
- 31.4 linear_congruence_distinct: the d = gcd(a,n) values k·(n/d) for
  k < d are pairwise incongruent, so there are exactly d distinct solutions.

Co-Authored-By: Claude <noreply@anthropic.com>
- rsa_pow_cong: for prime p and e*d ≡ 1 (mod p-1), m^(e*d) ≡ m (mod p) —
  covering both p|m and p∤m via ZMod.pow_card_sub_one.
- rsa_correct_general: for distinct primes p q and
  e*d ≡ 1 (mod (p-1)(q-1)), m^(e*d) ≡ m (mod p*q) for every m, via the
  per-prime congruences and the Chinese remainder theorem.
- prime_coprime: distinct primes are coprime.

Co-Authored-By: Claude <noreply@anthropic.com>
…work

Drop the 31.5 general-CRT and 31.7 RSA general-message items from the
chapter guide deferred list and raise the tracked-theorem count to 19,
matching the proofs landed in eda498d (Thm 31.10, 31.27) and 81ac64e
(Thm 31.36 general case).

Co-Authored-By: Claude <noreply@anthropic.com>
Add the Fibonacci running-time analysis of the Euclidean algorithm,
closing the last 31.2 deferred item:

- euclidDivisions counts the recursive calls of CLRS EUCLID.
- fib_le_of_euclidDivisions (CLRS Lemma 31.10): k calls with a > b >= 1
  force b >= F_{k+1} and a >= F_{k+2}, by strong induction on b.
- euclidDivisions_lt (CLRS Theorem 31.11, Lamé's theorem): b < F_{k+1}
  implies fewer than k calls.
- euclidDivisions_le_two_log (CLRS Corollary 31.12): at most 2*log2 b + 2
  calls, i.e. O(log b), via new exponential growth lemmas
  fib_two_step_ge_pow_two / pow_two_le_fib (2^(n/2) <= F_{n+2}).

All theorems kernel-checked with clean axioms; progress CSV bumped to
22/22 tracked theorems and docs/proof-map.md updated.

Co-Authored-By: Claude <noreply@anthropic.com>
Add the Carmichael-number half of the 31.8 deferred work:

- isCarmichael n: composite and a^(n-1) ≡ 1 (mod n) for every a coprime
  to n, with the projection lemmas and
  carmichael_fermatPseudoprime (a Carmichael number is a Fermat
  pseudoprime to every coprime base).
- isCarmichael_561: the smallest Carmichael number is 561, shown via
  fermat_test for the prime factors 3, 11, 17 and the new helper
  modeq_of_coprime_mul (combining congruences under coprime moduli).
  This concretely shows PSEUDOPRIME cannot certify primality.

Kernel-clean axioms; progress CSV bumped to 24/24 and docs updated.

Co-Authored-By: Claude <noreply@anthropic.com>
Define the Miller-Rabin machinery (correctness/error bound deferred):

- strongTestParams: write n-1 = 2^s * d with d odd via Nat.factorization.
- strongPseudoprime (STRONG-PSEUDOPRIME): a^d ≡ 1 or a^(2^i * d) ≡ -1
  for some i < s (i ranging over Fin s for decidability).
- Witness: a base that refutes strong pseudoprimality.
- millerRabin: the executable single-base decision procedure.
- instDecidableStrongPseudoprime for the Fin-bounded search.

Computational sanity checks: millerRabin 5 2 = true, 9 2 = false, and
561 2 = false - although 561 is a Carmichael number, base 2 witnesses
that it is composite, illustrating why Miller-Rabin beats PSEUDOPRIME.

Kernel-clean; docs and proof map updated; correctness/error bound
remain deferred.

Co-Authored-By: Claude <noreply@anthropic.com>
Prove the prime direction of Miller-Rabin correctness in 31.8:

- strongTestParams_spec: the 2^s·d decomposition of n-1 (via
  Nat.Prime.pow_dvd_iff_le_factorization and Nat.mul_div_cancel').
- modeq_neg_one_of_sq_eq_one: for a prime p, x^2 ≡ 1 and x ≢ 1
  (mod p) imply x ≡ -1 — the roots-of-unity fact via Nat.sq_sub_sq
  and Nat.Prime.dvd_mul.
- strongPseudoprime_of_prime: for prime n and a coprime to n, the
  sequence a^d, a^(2d), ..., a^(2^s·d) reaches 1 (Fermat); at the
  first such index the previous value is a square root of 1 that is
  not 1, hence -1.  Uses Nat.find for the minimal index.
- not_witness_of_prime (a prime has no witness) and
  witness_not_prime (a witness certifies compositeness).

Kernel-clean axioms; progress CSV bumped to 26/26; only the
Miller-Rabin error bound and Pollard's-rho analysis remain deferred.

Co-Authored-By: Claude <noreply@anthropic.com>
Complete the deterministic part of the 31.9 deferred work:

- rho_collision_factor_dist: the |y-x| (Nat.dist) version of the
  collision-factor lemma, matching GCD(|y-x|, n) in POLLARD-RHO.
- RhoState (tortoise-and-hare state: step count, current value,
  power-of-two snapshot, next boundary), pollardStep (one iteration),
  pollardRhoLoop (over a step budget), and pollardRho (the full CLRS
  algorithm).
- pollardRho_sound: whenever the returned value differs from n it is a
  nontrivial divisor of n (the only exit producing a value is the
  1 < d < n check on the gcd, and the gcd always divides n).
- pollardStep_collision_factor: a mod-p collision at a step makes that
  step's candidate a multiple of p, so the loop returns a factor.

Kernel-clean (pollardRho_sound needs only propext and Quot.sound);
progress CSV bumped to 27/27. The birthday-paradox expected-O(sqrt p)
running-time analysis remains deferred as a CLRS heuristic.

Co-Authored-By: Claude <noreply@anthropic.com>
Start the error-bound proof with the clean foundational lemmas:

- modeq_pow_two_sub_one: (n-1)^2 ≡ 1 (mod n), via
  (n-1)^2 - 1 = n*(n-2).
- strongPseudoprime_pow: a strong probable prime to base a satisfies
  a^(n-1) ≡ 1 (mod n).  With n-1 = 2^s·d, either a^d ≡ 1, or
  a^(2^i·d) ≡ -1 and a^(n-1) = (a^(2^i·d))^(2^(s-i)) ≡ (-1)^even = 1.
  Every strong liar therefore lies in the kernel of a ↦ a^(n-1), the
  first step toward showing the liars form a subgroup of the units.

Kernel-clean axioms.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Write docs/ch31-error-bound-handoff.md capturing the verified roadmap for
the last remaining ch31 theorem (Rabin-Monier: at most phi(n)/4 strong
liars for odd composite n).  Key content:

- Correct structure: embed liars into the subgroup S(n) = {x :
  x^(2^(nu(n)-1)*t) ≡ ±1 mod n}, then bound |S| ≤ phi(n)/4 via the
  three-case analysis (>=3 prime factors, n=pq, n=p^2).
- Verified negative result: strong liars are NOT a subgroup for
  multi-prime n (brute-force counterexamples 65/85/145/185), so the naive
  subgroup approach is wrong; prime powers are cyclic.
- Mathlib gap: cyclicity of (Z/p^e)^* / exists_primitive_root is missing;
  build it first (Milestone 0).
- Concrete Milestone 0-4 attack order and reusable API/lemma inventory.

Co-Authored-By: Claude <noreply@anthropic.com>
Add the verified Mathlib findings from the attack's first step:
- Cyclicity of (Z/p)^* for prime p is a free instance (finite-field
  unit-group theorem), with IsCyclic.exists_generator as the generator.
- (Z/p^e)^* cyclicity for e >= 2 is NOT in Mathlib; suggest either
  proving primitive roots mod odd prime powers or a Hensel-lifting
  reduction to (Z/p)^*.
- Nat.card (ZMod n)^* = totient n is not a named lemma but the pieces
  exist (Nat.card_units, totient_eq_card_coprime).
- Revised Milestone 0-4 order.

Co-Authored-By: Claude <noreply@anthropic.com>
…ib gaps

Verified corrections to the Miller-Rabin error-bound handoff:

- Target ≤ (n−1)/4, NOT ≤ φ(n)/4: the φ-bound is false for n = 9
  (liars(9) = {1,8}, 2 > φ(9)/4 = 1; (n−1)/4 gives equality).
- |S(n)| = 2^(k(ν−1)+1)·∏gcd(t,d_i) and exact liar count
  |L| = G·(2^(kν)−1)/(2^k−1) re-derived and checked on n = 9,15,25,65,561.
- Both former "gaps" are now in Mathlib: ZMod.isCyclic_units_of_prime_pow
  ((Z/p^e)ˣ cyclic for odd p, no Hensel needed) and
  ZMod.card_units_eq_totient (the φ-bridge).  Only remaining primitive to
  write: #{x : α // x^n = 1} = gcd(n, |α|) for cyclic α.

Co-Authored-By: Claude <noreply@anthropic.com>
…rs ⊆ S

Milestone 1-2 of the Rabin-Monier error bound.  Kernel-clean (only
propext/Classical.choice/Quot.sound).

- units of ZMod n: Nat.card (ZMod n)ˣ = φ(n), prime case p−1.
- nu(n) = min over prime factors p of v₂(p−1), with 2^ν | p−1 and ν ≥ 1
  for odd n.
- S(n) = {x ∈ (ZMod n)ˣ : x^(2^(ν−1)·t) ∈ {±1}} as a Subgroup (preimage of
  {1,−1} under the power map), avoiding ZMod-coercion pain.
- Parity lemma: orderOf (a^(2^i·d)) = 2 with d odd ⟹ 2^(i+1) | orderOf a.
- liar_mem_goodSet: every strong liar lies in S(n), via reduction mod each
  prime divisor (ZMod.castHom) + the parity lemma forcing 2^(i+1) | p−1.

Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 3 foundation: the counting kernel for |S(n)|.

- card_multiples_dvd: #{i < N : d | i} = N/d for d | N.
- card_fin_dvd_mul: #{i < N : N | i·n} = gcd(N, n), via the gcd-reduction
  (N/g | i) and coprimality of quotients.
- card_pow_eq_one_cyclic: in a finite cyclic group of order N, the number of
  elements with x^n = 1 is gcd(n, N) — via the generator parametrization
  (IsCyclic.image_range_card) and the i ↦ g^i bijection.

All kernel-clean (only propext/Classical.choice/Quot.sound).

Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 3a: the per-prime-power counting primitive.

- card_pow_eq_one_prime_pow: #{x : (ZMod (p^e))ˣ // x^m = 1} = gcd(m, φ(p^e))
  via cyclicity of (Z/p^e)ˣ (ZMod.isCyclic_units_of_prime_pow) + the cyclic
  torsion count.
- card_pow_eq_c_of_exists: in a finite commutative group, the fiber of x↦x^m
  over any element in its image has the same size as the m-torsion (coset of
  the kernel).
- card_pow_le_card_pow_eq_one: so any fiber has size ≤ the m-torsion — this
  bounds the "≡ −1" part by the "≡ 1" part without needing −1 in the image.

Kernel-clean (only propext/Classical.choice/Quot.sound).

Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 3b: card_pow_eq_one_crt shows the number of units x modulo n with
x^m = 1 equals the product over prime factors p of the number of units modulo
p^e_p with x^m = 1.

Uses ZMod.equivPi (the CRT as a ring isomorphism on ZMod n), Units.mapEquiv +
MulEquiv.piUnits to lift to unit groups, and Equiv.subtypePiEquivPi to turn
the pointwise-torsion subtype into a Pi of per-prime-power torsion subtypes.

Kernel-clean (only propext/Classical.choice/Quot.sound).

Co-Authored-By: Claude <noreply@anthropic.com>
…1)/2

Milestone 3c (partial): the key per-prime-factor bound for |S(n)|.

- odd_dvd_of_dvd_mul_two / odd_of_dvd_odd: odd-divisor helpers.
- gcd_pow_mul_le_half: for m = 2^(ν−1)·t with t odd and 2^ν | p−1, the gcd
  of m and p−1 is at most (p−1)/2 (2-adic valuation ≤ ν−1, odd part ≤ d).

Kernel-clean (only propext/Classical.choice/Quot.sound).

Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 3 assembly: the structural bound for the error bound.

- card_subtype_filter, card_or_le: counting a disjunction of predicates.
- goodSet_card_le: |S(n)| = |{x : x^m ∈ {±1}}| ≤ 2·|{x : x^m = 1}| — the
  "≡ −1" part is a fiber of the power map, no larger than the m-torsion.
- mTorsion_eq_prod: the m-torsion of (ZMod n)ˣ is the product over prime
  factors p of gcd(m, φ(p^e_p)) (via card_pow_eq_one_crt + the per-prime-power
  count).

Together: |S(n)| ≤ 2·∏ gcd(m, φ(p^e)) ≤ 2^(1−k)·∏(p−1).  Kernel-clean.

Co-Authored-By: Claude <noreply@anthropic.com>
Completes the structural bound for the error bound:
|S(n)| ≤ 2·|S₁| ≤ 2·∏(p−1)/2 = 2^(1−k)·∏(p−1).

- nu_le_v2_nat_sub_one: ν(n) ≤ v₂(n−1), since every prime factor is
  ≡ 1 mod 2^ν and n = ∏p^e (Nat.ModEq.prod_one).
- mExp_dvd: m = 2^(ν−1)·t divides n−1.
- mExp_coprime_prime: m is coprime to every prime factor p of n.
- gcd_eq_gcd_of_coprime / gcd_totient_eq_gcd_prime:
  gcd(m, φ(p^e)) = gcd(m, p−1).
- mTorsion_le_prod_half: |S₁| ≤ ∏ (p−1)/2, via the per-factor gcd bound
  gcd_pow_mul_le_half.

Kernel-clean (only propext/Classical.choice/Quot.sound).  The remaining work
is the three-case arithmetic (|S| ≤ 2^(1−k)·∏(p−1) ≤ (n−1)/4 for k ≥ 3,
k = 1, k = 2).

Co-Authored-By: Claude <noreply@anthropic.com>
Milestones 1-3 (ν, S(n), liars ⊆ S, |S| ≤ 2^(1−k)·∏(p−1)) are committed.
The handoff now documents the only remaining work — Milestone 4, the
three-case bound |S| ≤ (n−1)/4 — with the k=2 analysis worked out:

- sub-case s < r is easy via pq−1 ≥ 2^(2ν+1)d_p·d_q (no d/gcd needed);
- sub-case s = r needs "d_p | t ∧ d_q | t ⟹ d_p = d_q ⟹ p = q" to get a
  factor-3 saving.

Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 4 of the Rabin–Monier error-bound proof: the three-case
arithmetic bound on the good subgroup S(n).

- k=1 (prime power): |S| ≤ p−1 ≤ (p^e−1)/4 via the CRT m-torsion count
  and 4(p−1) ≤ p²−1.
- k=2 (semiprime n = p^a q^b): squarefree n=pq uses the refined bound
  8·gcd(m,p−1)·gcd(m,q−1) ≤ pq−1, split into s<r (2^(2s+1) ≤ 2^(s+r))
  and s=r (key lemma: d_p|t ∧ d_q|t forces p=q, giving a factor-3 saving);
  non-squarefree uses the crude 2(p−1)(q−1) ≤ n−1.
- k≥3: 2^(1−k)·∏(p−1) ≤ (n−1)/4 via ∏(p−1) ≤ n−1.

Key lemmas: nu_semiprime (ν(pq) = min v₂(p−1) v₂(q−1)),
gcd_pow_mul_oddPart (gcd decomposition), semiprime_key_lemma,
semiprime_gcd_bound, crude_bound, prod_primeFactors_pair,
goodUnits_card_le_semiprime.

Assembles to goodUnits_card_le (|S(n)| ≤ (n−1)/4) and the headline
strongLiars_card_le: at most (n−1)/4 of the bases are strong liars for
odd composite n (Theorem 31.38).  Kernel-clean: only
propext/Classical.choice/Quot.sound, no sorryAx.

Docs: chapter guide, progress CSV (29/29 tracked), proof map, and the
module header all updated; the error bound is no longer deferred.
The project base is now the CLRS 4th edition, which renumbered several
results in Chapter 31.  Verified against the 4th-edition text:

- Miller-Rabin error bound: Theorem 31.38 -> Theorem 31.39 (the
  witnesses >= (n-1)/2 theorem; (n-1)/4 is its Rabin-Monier sharpening).
- Fermat's little theorem: Theorem 31.30 -> Theorem 31.31; Euler's
  theorem is Theorem 31.30.
- Modular-linear solvability: Theorem 31.11 -> Corollary 31.21; the
  distinct-solutions count is Corollary 31.22.
- Euclid recursion: Lemma 31.2 -> Theorem 31.9 (GCD recursion theorem).
- Fixed the handoff doc title typo ("Theorem 31.8" -> 31.39).
- Noted that the 4th edition removed Section 31.9 (integer
  factorization); the POLLARD-RHO file is retained pending the repo-wide
  migration.

The §31.1-31.3 references (mod_add, exists_mul_inverse_mod,
mul_left_cancel_mod, gcd_is_linear_combination) remain on their legacy
numbers pending the repo-wide 4th-edition migration.

Co-Authored-By: Claude <noreply@anthropic.com>
@TankTechnology TankTechnology changed the title feat(ch31): complete the Miller-Rabin error bound (Theorem 31.38) feat(ch31): complete the Miller-Rabin error bound (Theorem 31.39, 4th ed.) Aug 6, 2026
TankTechnology and others added 2 commits August 6, 2026 13:09
Bring origin/main (37 commits: 4th-edition facade, edition maps, Ch30,
literate shard infrastructure, scripts) into feat/ch31-refinements.

The ch31 section files merged cleanly, keeping the full Miller-Rabin
error-bound work (strongLiars_card_le).  Conflicts resolved only in
CLRSLean/Progress.lean and docs/clrs-proof-progress.csv, taking the
remote's new fourth-edition schema.

Verification: lake build CLRSLean (8958 jobs) passes; check_repository.py
and check_progress_csv.py (1326/1326) pass.

Co-Authored-By: Claude <noreply@anthropic.com>
Add goodUnits_card_le and strongLiars_card_le to the chapter 31 row of the
fourth-edition progress ledger (tracked/proved 15 -> 17), since the merged
error-bound work is now in the source.  Regenerate Progress.lean and the
README progress table; update the snapshot test's expected total
(1,326 -> 1,328).

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant