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

lucas.py 6.2KB

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