The Lucas-Lehmer test for Mersenne primes. #
We define lucasLehmerResidue : Π p : ℕ, ZMod (2^p - 1)
, and
prove lucasLehmerResidue p = 0 → Prime (mersenne p)
.
We construct a norm_num
extension to calculate this residue to certify primality of Mersenne
primes using lucas_lehmer_sufficiency
.
TODO #
- Show reverse implication.
- Speed up the calculations using
n ≡ (n % 2^p) + (n / 2^p) [MOD 2^p - 1]
. - Find some bigger primes!
History #
This development began as a student project by Ainsley Pahljina,
and was then cleaned up for mathlib by Scott Morrison.
The tactic for certified computation of Lucas-Lehmer residues was provided by Mario Carneiro.
This tactic was ported by Thomas Murrills to Lean 4, and then it was converted to a norm_num
extension and made to use kernel reductions by Kyle Miller.
We now define three(!) different versions of the recurrence
s (i+1) = (s i)^2 - 2
.
These versions take values either in ℤ
, in ZMod (2^p - 1)
, or
in ℤ
but applying % (2^p - 1)
at each step.
They are each useful at different points in the proof, so we take a moment setting up the lemmas relating them.
The recurrence s (i+1) = (s i)^2 - 2
in ℤ
.
Equations
- LucasLehmer.s 0 = 4
- LucasLehmer.s (Nat.succ i) = LucasLehmer.s i ^ 2 - 2
Instances For
The recurrence s (i+1) = (s i)^2 - 2
in ZMod (2^p - 1)
.
Equations
- LucasLehmer.sZMod p 0 = 4
- LucasLehmer.sZMod p (Nat.succ i) = LucasLehmer.sZMod p i ^ 2 - 2
Instances For
The recurrence s (i+1) = ((s i)^2 - 2) % (2^p - 1)
in ℤ
.
Equations
- LucasLehmer.sMod p 0 = 4 % (2 ^ p - 1)
- LucasLehmer.sMod p (Nat.succ i) = (LucasLehmer.sMod p i ^ 2 - 2) % (2 ^ p - 1)
Instances For
The Lucas-Lehmer residue is s p (p-2)
in ZMod (2^p - 1)
.
Equations
- lucasLehmerResidue p = LucasLehmer.sZMod p (p - 2)
Instances For
Lucas-Lehmer Test: a Mersenne number 2^p-1
is prime if and only if
the Lucas-Lehmer residue s p (p-2) % (2^p - 1)
is zero.
Equations
- LucasLehmerTest p = (lucasLehmerResidue p = 0)
Instances For
q
is defined as the minimum factor of mersenne p
, bundled as an ℕ+
.
Equations
- LucasLehmer.q p = { val := Nat.minFac (mersenne p), property := (_ : 0 < Nat.minFac (mersenne p)) }
Instances For
Equations
- LucasLehmer.X.instDecidableEqX = inferInstanceAs (DecidableEq (ZMod ↑q × ZMod ↑q))
Equations
- LucasLehmer.X.instAddCommGroupX = inferInstanceAs (AddCommGroup (ZMod ↑q × ZMod ↑q))
Equations
- LucasLehmer.X.instOneX = { one := (1, 0) }
Equations
- One or more equations did not get rendered due to their size.
Equations
- One or more equations did not get rendered due to their size.
Equations
- One or more equations did not get rendered due to their size.
Equations
- LucasLehmer.X.instCommRingX = let src := inferInstanceAs (Ring (LucasLehmer.X q)); CommRing.mk (_ : ∀ (x x_1 : LucasLehmer.X q), x * x_1 = x_1 * x)
Equations
- (_ : Nontrivial (LucasLehmer.X q)) = (_ : Nontrivial (LucasLehmer.X q))
The cardinality of X
is q^2
.
There are strictly fewer than q^2
units, since 0
is not a unit.
Here and below, we introduce p' = p - 2
, in order to avoid using subtraction in ℕ
.
The order of ω
in the unit group is exactly 2^p
.
norm_num
extension #
Next we define a norm_num
extension that calculates LucasLehmerTest p
for 1 < p
.
It makes use of a version of sMod
that is specifically written to be reducible by the
Lean 4 kernel, which has the capability of efficiently reducing natural number expressions.
With this reduction in hand, it's a simple matter of applying the lemma
LucasLehmer.residue_eq_zero_iff_sMod_eq_zero
.
See [Archive/Examples/MersennePrimes.lean] for certifications of all Mersenne primes
up through mersenne 4423
.
Version of sMod
that is ℕ
-valued. One should have q = 2 ^ p - 1
.
This can be reduced by the kernel.
Equations
- LucasLehmer.norm_num_ext.sMod' q 0 = 4 % q
- LucasLehmer.norm_num_ext.sMod' q (Nat.succ i) = (LucasLehmer.norm_num_ext.sMod' q i ^ 2 + (q - 2)) % q
Instances For
Calculate LucasLehmer.LucasLehmerTest p
for 2 ≤ p
by using kernel reduction for the
sMod'
function.
Equations
- One or more equations did not get rendered due to their size.
Instances For
This implementation works successfully to prove (2^4423 - 1).Prime
,
and all the Mersenne primes up to this point appear in [Archive/Examples/MersennePrimes.lean].
These can be calculated nearly instantly, and (2^9689 - 1).Prime
only fails due to deep
recursion.
(Note by kmill: the following notes were for the Lean 3 version. They seem like they could still be useful, so I'm leaving them here.)
There's still low hanging fruit available to do faster computations based on the formula
n ≡ (n % 2^p) + (n / 2^p) [MOD 2^p - 1]
and the fact that % 2^p
and / 2^p
can be very efficient on the binary representation.
Someone should do this, too!