File: Mathlib/NumberTheory/LucasLehmer.lean

full_name: mersenne
code: /-- The Mersenne numbers, 2^p - 1. -/
def mersenne (p : ℕ) : ℕ 
goal: ℕ

full_name: strictMono_mersenne
code: theorem strictMono_mersenne : StrictMono mersenne 
goal: StrictMono mersenne

full_name: mersenne_lt_mersenne
code: @[simp]
theorem mersenne_lt_mersenne {p q : ℕ} : mersenne p < mersenne q ↔ p < q 
goal: mersenne p < mersenne q ↔ p < q

full_name: mersenne_le_mersenne
code: @[simp]
theorem mersenne_le_mersenne {p q : ℕ} : mersenne p ≤ mersenne q ↔ p ≤ q 
goal: mersenne p ≤ mersenne q ↔ p ≤ q

full_name: mersenne_zero
code: @[simp] theorem mersenne_zero : mersenne 0 = 0 
goal: mersenne 0 = 0

full_name: mersenne_pos
code: @[simp] theorem mersenne_pos {p : ℕ} : 0 < mersenne p ↔ 0 < p 
goal: 0 < mersenne p ↔ 0 < p

full_name: Mathlib.Meta.Positivity.evalMersenne
code: /-- Extension for the `positivity` tactic: `mersenne`. -/
@[positivity mersenne _]
def evalMersenne : PositivityExt 
goal: Mathlib.Meta.Positivity.PositivityExt

full_name: one_lt_mersenne
code: @[simp]
theorem one_lt_mersenne {p : ℕ} : 1 < mersenne p ↔ 1 < p 
goal: 1 < mersenne p ↔ 1 < p

full_name: succ_mersenne
code: @[simp]
theorem succ_mersenne (k : ℕ) : mersenne k + 1 = 2 ^ k 
goal: mersenne k + 1 = 2 ^ k

full_name: LucasLehmer.s
code: /-- The recurrence `s (i+1) = (s i)^2 - 2` in `ℤ`. -/
def s : ℕ → ℤ
  
goal: ℕ → ℤ

full_name: LucasLehmer.sZMod
code: /-- The recurrence `s (i+1) = (s i)^2 - 2` in `ZMod (2^p - 1)`. -/
def sZMod (p : ℕ) : ℕ → ZMod (2 ^ p - 1)
  
goal: ℕ → ZMod (2 ^ p - 1)

full_name: LucasLehmer.sMod
code: /-- The recurrence `s (i+1) = ((s i)^2 - 2) % (2^p - 1)` in `ℤ`. -/
def sMod (p : ℕ) : ℕ → ℤ
  
goal: ℕ → ℤ

full_name: LucasLehmer.mersenne_int_pos
code: theorem mersenne_int_pos {p : ℕ} (hp : p ≠ 0) : (0 : ℤ) < 2 ^ p - 1 
goal: 0 < 2 ^ p - 1

full_name: LucasLehmer.mersenne_int_ne_zero
code: theorem mersenne_int_ne_zero (p : ℕ) (hp : p ≠ 0) : (2 ^ p - 1 : ℤ) ≠ 0 
goal: 2 ^ p - 1 ≠ 0

full_name: LucasLehmer.sMod_nonneg
code: theorem sMod_nonneg (p : ℕ) (hp : p ≠ 0) (i : ℕ) : 0 ≤ sMod p i 
goal: 0 ≤ LucasLehmer.sMod p i

full_name: LucasLehmer.sMod_mod
code: theorem sMod_mod (p i : ℕ) : sMod p i % (2 ^ p - 1) = sMod p i 
goal: LucasLehmer.sMod p i % (2 ^ p - 1) = LucasLehmer.sMod p i

full_name: LucasLehmer.sMod_lt
code: theorem sMod_lt (p : ℕ) (hp : p ≠ 0) (i : ℕ) : sMod p i < 2 ^ p - 1 
goal: LucasLehmer.sMod p i < 2 ^ p - 1

full_name: LucasLehmer.sZMod_eq_s
code: theorem sZMod_eq_s (p' : ℕ) (i : ℕ) : sZMod (p' + 2) i = (s i : ZMod (2 ^ (p' + 2) - 1)) 
goal: LucasLehmer.sZMod (p' + 2) i = ↑(LucasLehmer.s i)

full_name: LucasLehmer.Int.natCast_pow_pred
code: theorem Int.natCast_pow_pred (b p : ℕ) (w : 0 < b) : ((b ^ p - 1 : ℕ) : ℤ) = (b : ℤ) ^ p - 1 
goal: ↑(b ^ p - 1) = ↑b ^ p - 1

full_name: LucasLehmer.Int.coe_nat_two_pow_pred
code: theorem Int.coe_nat_two_pow_pred (p : ℕ) : ((2 ^ p - 1 : ℕ) : ℤ) = (2 ^ p - 1 : ℤ) 
goal: ↑(2 ^ p - 1) = 2 ^ p - 1

full_name: LucasLehmer.sZMod_eq_sMod
code: theorem sZMod_eq_sMod (p : ℕ) (i : ℕ) : sZMod p i = (sMod p i : ZMod (2 ^ p - 1)) 
goal: LucasLehmer.sZMod p i = ↑(LucasLehmer.sMod p i)

full_name: LucasLehmer.lucasLehmerResidue
code: /-- The Lucas-Lehmer residue is `s p (p-2)` in `ZMod (2^p - 1)`. -/
def lucasLehmerResidue (p : ℕ) : ZMod (2 ^ p - 1) 
goal: ZMod (2 ^ p - 1)

full_name: LucasLehmer.residue_eq_zero_iff_sMod_eq_zero
code: theorem residue_eq_zero_iff_sMod_eq_zero (p : ℕ) (w : 1 < p) :
    lucasLehmerResidue p = 0 ↔ sMod p (p - 2) = 0 
goal: lucasLehmerResidue p = 0 ↔ LucasLehmer.sMod p (p - 2) = 0

full_name: LucasLehmer.LucasLehmerTest
code: /-- **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.
-/
def LucasLehmerTest (p : ℕ) : Prop 
goal: Prop

full_name: LucasLehmer.q
code: /-- `q` is defined as the minimum factor of `mersenne p`, bundled as an `ℕ+`. -/
def q (p : ℕ) : ℕ+ 
goal: ℕ+

full_name: LucasLehmer.X
code: /-- We construct the ring `X q` as ℤ/qℤ + √3 ℤ/qℤ. -/
def X (q : ℕ+) : Type 
goal: Type

full_name: LucasLehmer.X.instInhabited
code: instance : Inhabited (X q) 
goal: Inhabited (LucasLehmer.X q)

full_name: LucasLehmer.X.instFintype
code: instance : Fintype (X q) 
goal: Fintype (LucasLehmer.X q)

full_name: LucasLehmer.X.instDecidableEq
code: instance : DecidableEq (X q) 
goal: DecidableEq (LucasLehmer.X q)

full_name: LucasLehmer.X.instAddCommGroup
code: instance : AddCommGroup (X q) 
goal: AddCommGroup (LucasLehmer.X q)

full_name: LucasLehmer.X.ext
code: @[ext]
theorem ext {x y : X q} (h₁ : x.1 = y.1) (h₂ : x.2 = y.2) : x = y 
goal: x = y

full_name: LucasLehmer.X.zero_fst
code: @[simp] theorem zero_fst : (0 : X q).1 = 0 
goal: 0.1 = 0

full_name: LucasLehmer.X.zero_snd
code: @[simp] theorem zero_snd : (0 : X q).2 = 0 
goal: 0.2 = 0

full_name: LucasLehmer.X.add_fst
code: @[simp]
theorem add_fst (x y : X q) : (x + y).1 = x.1 + y.1 
goal: (x + y).1 = x.1 + y.1

full_name: LucasLehmer.X.add_snd
code: @[simp]
theorem add_snd (x y : X q) : (x + y).2 = x.2 + y.2 
goal: (x + y).2 = x.2 + y.2

full_name: LucasLehmer.X.neg_fst
code: @[simp]
theorem neg_fst (x : X q) : (-x).1 = -x.1 
goal: (-x).1 = -x.1

full_name: LucasLehmer.X.neg_snd
code: @[simp]
theorem neg_snd (x : X q) : (-x).2 = -x.2 
goal: (-x).2 = -x.2

full_name: LucasLehmer.X.instMul
code: instance : Mul (X q) 
goal: Mul (LucasLehmer.X q)

full_name: LucasLehmer.X.mul_fst
code: @[simp]
theorem mul_fst (x y : X q) : (x * y).1 = x.1 * y.1 + 3 * x.2 * y.2 
goal: (x * y).1 = x.1 * y.1 + 3 * x.2 * y.2

full_name: LucasLehmer.X.mul_snd
code: @[simp]
theorem mul_snd (x y : X q) : (x * y).2 = x.1 * y.2 + x.2 * y.1 
goal: (x * y).2 = x.1 * y.2 + x.2 * y.1

full_name: LucasLehmer.X.instOne
code: instance : One (X q) 
goal: One (LucasLehmer.X q)

full_name: LucasLehmer.X.one_fst
code: @[simp]
theorem one_fst : (1 : X q).1 = 1 
goal: 1.1 = 1

full_name: LucasLehmer.X.one_snd
code: @[simp]
theorem one_snd : (1 : X q).2 = 0 
goal: 1.2 = 0

full_name: LucasLehmer.X.instMonoid
code: instance : Monoid (X q) 
goal: Monoid (LucasLehmer.X q)

full_name: LucasLehmer.X.instNatCast
code: instance : NatCast (X q) 
goal: NatCast (LucasLehmer.X q)

full_name: LucasLehmer.X.fst_natCast
code: @[simp] theorem fst_natCast (n : ℕ) : (n : X q).fst = (n : ZMod q) 
goal: (↑n).1 = ↑n

full_name: LucasLehmer.X.snd_natCast
code: @[simp] theorem snd_natCast (n : ℕ) : (n : X q).snd = (0 : ZMod q) 
goal: (↑n).2 = 0

full_name: LucasLehmer.X.ofNat_fst
code: @[simp] theorem ofNat_fst (n : ℕ) [n.AtLeastTwo] :
    (no_index (OfNat.ofNat n) : X q).fst = OfNat.ofNat n 
goal: (OfNat.ofNat n).1 = OfNat.ofNat n

full_name: LucasLehmer.X.ofNat_snd
code: @[simp] theorem ofNat_snd (n : ℕ) [n.AtLeastTwo] :
    (no_index (OfNat.ofNat n) : X q).snd = 0 
goal: (OfNat.ofNat n).2 = 0

full_name: LucasLehmer.X.instAddGroupWithOne
code: instance : AddGroupWithOne (X q) 
goal: AddGroupWithOne (LucasLehmer.X q)

full_name: LucasLehmer.X.left_distrib
code: theorem left_distrib (x y z : X q) : x * (y + z) = x * y + x * z 
goal: x * (y + z) = x * y + x * z

full_name: LucasLehmer.X.right_distrib
code: theorem right_distrib (x y z : X q) : (x + y) * z = x * z + y * z 
goal: (x + y) * z = x * z + y * z

full_name: LucasLehmer.X.instRing
code: instance : Ring (X q) 
goal: Ring (LucasLehmer.X q)

full_name: LucasLehmer.X.instCommRing
code: instance : CommRing (X q) 
goal: CommRing (LucasLehmer.X q)

full_name: LucasLehmer.X.instNontrivialOfFactLtNatOfNatVal
code: instance [Fact (1 < (q : ℕ))] : Nontrivial (X q) 
goal: Nontrivial (LucasLehmer.X q)

full_name: LucasLehmer.X.fst_intCast
code: @[simp]
theorem fst_intCast (n : ℤ) : (n : X q).fst = (n : ZMod q) 
goal: (↑n).1 = ↑n

full_name: LucasLehmer.X.snd_intCast
code: @[simp]
theorem snd_intCast (n : ℤ) : (n : X q).snd = (0 : ZMod q) 
goal: (↑n).2 = 0

full_name: LucasLehmer.X.coe_mul
code: @[norm_cast]
theorem coe_mul (n m : ℤ) : ((n * m : ℤ) : X q) = (n : X q) * (m : X q) 
goal: ↑(n * m) = ↑n * ↑m

full_name: LucasLehmer.X.coe_natCast
code: @[norm_cast]
theorem coe_natCast (n : ℕ) : ((n : ℤ) : X q) = (n : X q) 
goal: ↑↑n = ↑n

full_name: LucasLehmer.X.card_eq
code: /-- The cardinality of `X` is `q^2`. -/
theorem card_eq : Fintype.card (X q) = q ^ 2 
goal: Fintype.card (LucasLehmer.X q) = ↑q ^ 2

full_name: LucasLehmer.X.card_units_lt
code: /-- There are strictly fewer than `q^2` units, since `0` is not a unit. -/
nonrec theorem card_units_lt (w : 1 < q) : Fintype.card (X q)ˣ < q ^ 2 
goal: Fintype.card (LucasLehmer.X q)ˣ < ↑q ^ 2

full_name: LucasLehmer.X.ω
code: /-- We define `ω = 2 + √3`. -/
def ω : X q 
goal: LucasLehmer.X q

full_name: LucasLehmer.X.ωb
code: /-- We define `ωb = 2 - √3`, which is the inverse of `ω`. -/
def ωb : X q 
goal: LucasLehmer.X q

full_name: LucasLehmer.X.ω_mul_ωb
code: theorem ω_mul_ωb (q : ℕ+) : (ω : X q) * ωb = 1 
goal: LucasLehmer.X.ω * LucasLehmer.X.ωb = 1

full_name: LucasLehmer.X.ωb_mul_ω
code: theorem ωb_mul_ω (q : ℕ+) : (ωb : X q) * ω = 1 
goal: LucasLehmer.X.ωb * LucasLehmer.X.ω = 1

full_name: LucasLehmer.X.closed_form
code: /-- A closed form for the recurrence relation. -/
theorem closed_form (i : ℕ) : (s i : X q) = (ω : X q) ^ 2 ^ i + (ωb : X q) ^ 2 ^ i 
goal: ↑(LucasLehmer.s i) = LucasLehmer.X.ω ^ 2 ^ i + LucasLehmer.X.ωb ^ 2 ^ i

full_name: LucasLehmer.two_lt_q
code: /-- If `1 < p`, then `q p`, the smallest prime factor of `mersenne p`, is more than 2. -/
theorem two_lt_q (p' : ℕ) : 2 < q (p' + 2) 
goal: 2 < LucasLehmer.q (p' + 2)

full_name: LucasLehmer.ω_pow_formula
code: theorem ω_pow_formula (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    ∃ k : ℤ,
      (ω : X (q (p' + 2))) ^ 2 ^ (p' + 1) =
        k * mersenne (p' + 2) * (ω : X (q (p' + 2))) ^ 2 ^ p' - 1 
goal: ∃ k, LucasLehmer.X.ω ^ 2 ^ (p' + 1) = ↑k * ↑(mersenne (p' + 2)) * LucasLehmer.X.ω ^ 2 ^ p' - 1

full_name: LucasLehmer.mersenne_coe_X
code: /-- `q` is the minimum factor of `mersenne p`, so `M p = 0` in `X q`. -/
theorem mersenne_coe_X (p : ℕ) : (mersenne p : X (q p)) = 0 
goal: ↑(mersenne p) = 0

full_name: LucasLehmer.ω_pow_eq_neg_one
code: theorem ω_pow_eq_neg_one (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    (ω : X (q (p' + 2))) ^ 2 ^ (p' + 1) = -1 
goal: LucasLehmer.X.ω ^ 2 ^ (p' + 1) = -1

full_name: LucasLehmer.ω_pow_eq_one
code: theorem ω_pow_eq_one (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    (ω : X (q (p' + 2))) ^ 2 ^ (p' + 2) = 1 
goal: LucasLehmer.X.ω ^ 2 ^ (p' + 2) = 1

full_name: LucasLehmer.ωUnit
code: /-- `ω` as an element of the group of units. -/
def ωUnit (p : ℕ) : Units (X (q p)) 
goal: (LucasLehmer.X (LucasLehmer.q p))ˣ

full_name: LucasLehmer.ωUnit_coe
code: @[simp]
theorem ωUnit_coe (p : ℕ) : (ωUnit p : X (q p)) = ω 
goal: ↑(LucasLehmer.ωUnit p) = LucasLehmer.X.ω

full_name: LucasLehmer.order_ω
code: /-- The order of `ω` in the unit group is exactly `2^p`. -/
theorem order_ω (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    orderOf (ωUnit (p' + 2)) = 2 ^ (p' + 2) 
goal: orderOf (LucasLehmer.ωUnit (p' + 2)) = 2 ^ (p' + 2)

full_name: LucasLehmer.order_ineq
code: theorem order_ineq (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    2 ^ (p' + 2) < (q (p' + 2) : ℕ) ^ 2 
goal: 2 ^ (p' + 2) < ↑(LucasLehmer.q (p' + 2)) ^ 2

full_name: lucas_lehmer_sufficiency
code: theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime 
goal: LucasLehmerTest p → Nat.Prime (mersenne p)

full_name: LucasLehmer.norm_num_ext.sMod'
code: /-- Version of `sMod` that is `ℕ`-valued. One should have `q = 2 ^ p - 1`.
This can be reduced by the kernel. -/
def sMod' (q : ℕ) : ℕ → ℕ
  
goal: ℕ → ℕ

full_name: LucasLehmer.norm_num_ext.sMod'_eq_sMod
code: theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k 
goal: ↑(LucasLehmer.norm_num_ext.sMod' (2 ^ p - 1) k) = LucasLehmer.sMod p k

full_name: LucasLehmer.norm_num_ext.testTrueHelper
code: lemma testTrueHelper (p : ℕ) (hp : Nat.blt 1 p = true) (h : sMod' (2 ^ p - 1) (p - 2) = 0) :
    LucasLehmerTest p 
goal: LucasLehmerTest p

full_name: LucasLehmer.norm_num_ext.testFalseHelper
code: lemma testFalseHelper (p : ℕ) (hp : Nat.blt 1 p = true)
    (h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p 
goal: ¬LucasLehmerTest p

full_name: LucasLehmer.norm_num_ext.isNat_lucasLehmerTest
code: theorem isNat_lucasLehmerTest : {p np : ℕ} →
    IsNat p np → LucasLehmerTest np → LucasLehmerTest p
  
goal: Mathlib.Meta.NormNum.IsNat p np → LucasLehmerTest np → LucasLehmerTest p

full_name: LucasLehmer.norm_num_ext.isNat_not_lucasLehmerTest
code: theorem isNat_not_lucasLehmerTest : {p np : ℕ} →
    IsNat p np → ¬ LucasLehmerTest np → ¬ LucasLehmerTest p
  
goal: Mathlib.Meta.NormNum.IsNat p np → ¬LucasLehmerTest np → ¬LucasLehmerTest p

full_name: LucasLehmer.norm_num_ext.evalLucasLehmerTest
code: /-- Calculate `LucasLehmer.LucasLehmerTest p` for `2 ≤ p` by using kernel reduction for the
`sMod'` function. -/
@[norm_num LucasLehmer.LucasLehmerTest (_ : ℕ)]
def evalLucasLehmerTest : NormNumExt 
goal: Mathlib.Meta.NormNum.NormNumExt

full_name: modEq_mersenne
code: theorem modEq_mersenne (n k : ℕ) : k ≡ k / 2 ^ n + k % 2 ^ n [MOD 2 ^ n - 1] 
goal: k ≡ k / 2 ^ n + k % 2 ^ n [MOD 2 ^ n - 1]