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

lucas.py 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. # Finding lucas pseudoprimes
  2. from math import gcd, floor, log
  3. from psimp import trd
  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. Jv = Jacobi(D, n)
  84. # What we're looking for
  85. if Jv == -1:
  86. return D
  87. # Have found a factor
  88. if Jv == 0 and abs(D) != n:
  89. return 0
  90. # Check for square at 13
  91. if D > 10 and not haschecked:
  92. if hasIntSQRT(n):
  93. return 0
  94. # Shouldn't fire
  95. return 0
  96. def Lucas(n, p, q):
  97. """Function for generating values of a lucas sequence with parameters p, q.
  98. Via formula at <https://en.wikipedia.org/wiki/Lucas_sequence>
  99. """
  100. if n < 0:
  101. raise ValueError("n must be a non-negative integer")
  102. Uc = 0
  103. Vc = 2
  104. for i in range(n):
  105. Un = (p * Uc + Vc) // 2
  106. Vn = ((p * p - 4 * q) * Uc + p * Vc) // 2
  107. Uc = Un
  108. Vc = Vn
  109. return Uc, Vc
  110. def LucasUn(n, p, q):
  111. """Return only the U numbers from a lucas sequence Un(P, Q). For example if
  112. P = 1, and Q = -1 this will return the Fibonacci numbers; if P = 3 and Q =
  113. 2 then it returns the Mersenne numbers etc.
  114. """
  115. return Lucas(n, p, q)[0]
  116. def LucasVn(n, p, q):
  117. """Return only V numbers from a local sequence Vn(P, Q).
  118. """
  119. return Lucas(n, p, q)[1]
  120. def LucasFast(k, p, q, n):
  121. """Faster Lucas algorithm, modulo a number
  122. """
  123. if k < 0:
  124. raise ValueError("k must be a non-negative integer")
  125. if n < 1:
  126. raise ValueError("n must be a postive integer")
  127. if n % 2 == 0:
  128. raise ValueError("n must be odd")
  129. uc, vc = Lucas(0, p, q)
  130. dk = floor(log(k, 2))
  131. tp = 2**dk
  132. krunn = k
  133. ks = 0
  134. for i in range(dk + 1):
  135. un = (uc * vc)
  136. vn = (pow(vc, 2, n) - 2 * pow(q, ks, n))
  137. uc = un % n
  138. vc = vn % n
  139. ks = ks * 2
  140. if krunn >= tp:
  141. krunn = krunn - tp
  142. ks = ks + 1
  143. un = p * uc + vc
  144. if un % 2 != 0:
  145. un = un + n
  146. vn = (p * p - 4 * q) * uc + p * vc
  147. if vn % 2 != 0:
  148. vn = vn + n
  149. uc = (un // 2) % n
  150. vc = (vn // 2) % n
  151. tp = tp // 2
  152. return(uc, vc)
  153. def LucasPrime(n):
  154. """Lucas probable prime test
  155. (note: not the "strong" test.)
  156. """
  157. if n < 2:
  158. return False
  159. if n == 2:
  160. return True
  161. if n % 2 == 0:
  162. return False
  163. d = FirstD(n)
  164. if d == 0:
  165. return False
  166. q = (1 - d) // 4
  167. lnum = LucasFast(n + 1, 1, q, n)
  168. return lnum[0] == 0
  169. def StrongLucasPrime(n):
  170. """Strong version of the Lucas probable prime test
  171. """
  172. if n < 2:
  173. return False
  174. if n == 2:
  175. return True
  176. if n % 2 == 0:
  177. return False
  178. d = FirstD(n)
  179. if d == 0:
  180. return False
  181. s, od = trd(n + 1)
  182. p = 1
  183. q = (1 - d) // 4
  184. uc, vc = Lucas(0, p, q)
  185. dk = floor(log(od, 2))
  186. tp = 2**dk
  187. krunn = od
  188. ks = 0
  189. for i in range(dk + 1):
  190. un = (uc * vc)
  191. vn = (pow(vc, 2, n) - 2 * pow(q, ks, n))
  192. uc = un % n
  193. vc = vn % n
  194. ks = ks * 2
  195. if krunn >= tp:
  196. krunn = krunn - tp
  197. ks = ks + 1
  198. un = p * uc + vc
  199. if un % 2 != 0:
  200. un = un + n
  201. vn = (p * p - 4 * q) * uc + p * vc
  202. if vn % 2 != 0:
  203. vn = vn + n
  204. uc = (un // 2) % n
  205. vc = (vn // 2) % n
  206. tp = tp // 2
  207. if uc == 0:
  208. return True
  209. if vc == 0:
  210. return True
  211. for r in range(1, s):
  212. un = (uc * vc)
  213. vn = (pow(vc, 2, n) - 2 * pow(q, ks, n))
  214. uc = un % n
  215. vc = vn % n
  216. if vc == 0:
  217. return True
  218. ks = ks * 2
  219. return False