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

lucas.py 6.2KB

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