A simple prime-number bot, in python. WIP
mastodon
python
fediverse
bot
mathematics
prime-numbers

lucas.py 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. # Finding lucas pseudoprimes
  2. from math import sqrt, gcd, floor, log
  3. from time import process_time
  4. def isqrt(n):
  5. """ Find the integer square root of n via newton's method, code via
  6. stackoverflow:
  7. (https://stackoverflow.com/questions/15390807/integer-square-root-in-python)
  8. """
  9. x = n
  10. y = (x + 1) // 2
  11. while y < x:
  12. x = y
  13. y = (x + n // x) // 2
  14. return x
  15. def hasIntSQRT(n):
  16. """Detect whether the square root of n is an integer,
  17. i.e. whether the isqrt(n) is the true square root.
  18. """
  19. isq = isqrt(n)
  20. return isq * isq == n
  21. def Dsequence():
  22. """Generate sequence 5, -7, 9, -11, 13, -15...
  23. """
  24. val = 5
  25. while True:
  26. if val % 4 == 1:
  27. yield val
  28. else:
  29. yield -val
  30. val = val + 2
  31. def Legendre(a, p):
  32. """Function for calculating Legendre symbol.
  33. Note that this is only supposed to be defined if p is an odd prime, but we
  34. don't know in advance if that is true - will therefore only throw and error
  35. if p is even.
  36. Uses original power definition from
  37. <https://en.wikipedia.org/wiki/Legendre_symbol>
  38. """
  39. if (p % 2 == 0):
  40. raise ValueError("p must be odd, is {}".format(p))
  41. lv = pow(a, (p-1)//2, p)
  42. if lv == p - 1:
  43. lv = -1
  44. return lv
  45. def Jacobi(a, n):
  46. """Function for calculating Jacobi symbol.
  47. Note that this is only defined for positive odd integers n.
  48. Uses algorithm from
  49. <https://en.wikipedia.org/wiki/Jacobi_symbol#Calculating_the_Jacobi_symbol>
  50. """
  51. if n < 1:
  52. raise ValueError("n must be positive")
  53. if (n % 2 == 0):
  54. raise ValueError("n must be odd")
  55. if a % n != a:
  56. return Jacobi(a%n, n)
  57. if a != 0 and a % 2 == 0:
  58. nm8 = n % 8
  59. if (nm8 == 3 or nm8 == 5):
  60. return -1 * Jacobi(a//2, n)
  61. else:
  62. return Jacobi(a//2, n)
  63. if a == 1:
  64. return 1
  65. if gcd(a, n) != 1:
  66. return 0
  67. if a == 0 and n == 1:
  68. return 1
  69. if n % 4 == 3 and a % 4 == 3:
  70. return -1 * Jacobi(n, a)
  71. return Jacobi(n, a)
  72. def FirstD(n):
  73. """Return first D in the sequence 5, -7, 9, -11, 13, -15... for which the
  74. Jacobi symbol (D/n) is -1. Returns 0 if the number is a perfect square, or
  75. otherwise the value can't be found
  76. """
  77. if n < 1 or n % 2 == 0:
  78. raise ValueError("n must be a positive odd number")
  79. # Flag to see if it's been checked whether or not n is
  80. # square
  81. haschecked = False
  82. for D in Dsequence():
  83. if Jacobi(D, n) == -1:
  84. return D
  85. # This is supposed to be faster
  86. if D > 30 and not haschecked:
  87. if hasIntSQRT(n):
  88. return 0
  89. # Shouldn't fire
  90. return 0
  91. def Lucas(n, p, q):
  92. """Function for generating values of a lucas sequence with parameters p, q.
  93. Via formula at <https://en.wikipedia.org/wiki/Lucas_sequence>
  94. """
  95. if n < 0:
  96. raise ValueError("n must be a non-negative integer")
  97. Uc = 0
  98. Vc = 2
  99. for i in range(n):
  100. Un = (p * Uc + Vc) // 2
  101. Vn = ((p * p - 4 * q) * Uc + p * Vc) // 2
  102. Uc = Un
  103. Vc = Vn
  104. return Uc, Vc
  105. def LucasUn(n, p, q):
  106. """Return only the U numbers from a lucas sequence Un(P, Q). For example if
  107. P = 1, and Q = -1 this will return the Fibonacci numbers; if P = 3 and Q =
  108. 2 then it returns the Mersenne numbers etc.
  109. """
  110. return Lucas(n, p, q)[0]
  111. def LucasVn(n, p, q):
  112. """Return only V numbers from a local sequence Vn(P, Q).
  113. """
  114. return Lucas(n, p, q)[1]
  115. def LucasFast(k, p, q, n):
  116. """Faster Lucas algorithm, modulo a number
  117. """
  118. if k < 0:
  119. raise ValueError("k must be a non-negative integer")
  120. if n < 1:
  121. raise ValueError("n must be a postive integer")
  122. if n % 2 == 0:
  123. raise ValueError("n must be odd")
  124. uc, vc = Lucas(0, p, q)
  125. dk = floor(log(k, 2))
  126. tp = 2**dk
  127. krunn = k
  128. ks = 0
  129. for i in range(dk + 1):
  130. un = (uc * vc)
  131. vn = (pow(vc, 2, n) - 2 * pow(q, ks, n))
  132. uc = un % n
  133. vc = vn % n
  134. ks = ks * 2
  135. if krunn >= tp:
  136. krunn = krunn - tp
  137. ks = ks + 1
  138. un = p * uc + vc
  139. if un % 2 != 0:
  140. un = un + n
  141. vn = (p * p - 4 * q) * uc + p * vc
  142. if vn % 2 != 0:
  143. vn = vn + n
  144. uc = (un // 2) % n
  145. vc = (vn // 2) % n
  146. tp = tp // 2
  147. return(uc, vc)
  148. def LucasPrime(n):
  149. """Lucas probable prime test
  150. (note: not the "strong" test.)
  151. """
  152. if n < 2:
  153. return False
  154. if n == 2:
  155. return True
  156. if n % 2 == 0:
  157. return False
  158. d = FirstD(n)
  159. if d == 0:
  160. return False
  161. q = (1 - d) // 4
  162. lnum = LucasFast(n + 1, 1, q, n)
  163. return lnum[0] == 0
  164. np = 0
  165. for i in range(1000):
  166. lp = LucasPrime(i)
  167. if lp:
  168. np = np + 1
  169. print("{}:\t{}".format(i, lp))
  170. print(np)