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 Kim 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.
Alias of the reverse direction of mersenne_lt_mersenne
.
Alias of the reverse direction of mersenne_le_mersenne
.
Alias of the reverse direction of mersenne_pos
.
Extension for the positivity
tactic: mersenne
.
Instances For
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 i.succ = 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 i.succ = 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 i.succ = (LucasLehmer.sMod p i ^ 2 - 2) % (2 ^ p - 1)
Instances For
Alias of LucasLehmer.Int.natCast_pow_pred
.
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 = ⟨(mersenne p).minFac, ⋯⟩
Instances For
Equations
- LucasLehmer.X.instDecidableEq = inferInstanceAs (DecidableEq (ZMod ↑q × ZMod ↑q))
Equations
- LucasLehmer.X.instAddCommGroup = inferInstanceAs (AddCommGroup (ZMod ↑q × ZMod ↑q))
Equations
- LucasLehmer.X.instOne = { one := (1, 0) }
Equations
- LucasLehmer.X.instAddGroupWithOne = AddGroupWithOne.mk ⋯ SubNegMonoid.zsmul ⋯ ⋯ ⋯ ⋯ ⋯ ⋯
Equations
- LucasLehmer.X.instCommRing = CommRing.mk ⋯
Equations
- ⋯ = ⋯
Alias of LucasLehmer.X.fst_natCast
.
Alias of LucasLehmer.X.snd_natCast
.
Alias of LucasLehmer.X.fst_intCast
.
Alias of LucasLehmer.X.snd_intCast
.
Alias of LucasLehmer.X.coe_natCast
.
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 ℕ
.
ω
as an element of the group of units.
Equations
- LucasLehmer.ωUnit p = { val := LucasLehmer.X.ω, inv := LucasLehmer.X.ωb, val_inv := ⋯, inv_val := ⋯ }
Instances For
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.sModNat q 0 = 4 % q
- LucasLehmer.norm_num_ext.sModNat q i.succ = (LucasLehmer.norm_num_ext.sModNat q i ^ 2 + (q - 2)) % q
Instances For
Helper function for sMod''
.
Equations
- LucasLehmer.norm_num_ext.sModNatTR.go q 0 x = x
- LucasLehmer.norm_num_ext.sModNatTR.go q n.succ x = LucasLehmer.norm_num_ext.sModNatTR.go q n ((x ^ 2 + (q - 2)) % q)
Instances For
Generalization of sModNat
with arbitrary base case,
useful for proving sModNatTR
and sModNat
agree.
Equations
- LucasLehmer.norm_num_ext.sModNat_aux b q 0 = b
- LucasLehmer.norm_num_ext.sModNat_aux b q i.succ = (LucasLehmer.norm_num_ext.sModNat_aux b 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!