Baillie-PSW_high-level.sf 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 04 March 2020
  4. # https://github.com/trizen
  5. # High-level implementation of the Baillie-PSW primality.
  6. # The strong and extra-strong versions.
  7. # See also:
  8. # https://oeis.org/A217255 -- Strong Lucas pseudoprimes
  9. # https://oeis.org/A217719 -- Extra strong Lucas pseudoprimes
  10. # https://arxiv.org/pdf/2006.14425.pdf -- STRENGTHENING THE BAILLIE-PSW PRIMALITY TEST
  11. # Find Q for P = 1, such that kronecker(1 - 4Q, n) = -1.
  12. func findQ(N) {
  13. for k in (2 .. Inf) {
  14. var D = ((-1)**k * (2*k + 1))
  15. var K = kronecker(D, N)
  16. if (K.is_zero && gcd(D, N).is_between(2, N-1)) {
  17. return nil
  18. }
  19. return ((1 - D)/4) if (K == -1)
  20. }
  21. }
  22. # Find P >= 3 for Q = 1, such that kronecker(P^2 - 4, n) = -1.
  23. func findP(N) {
  24. for P in (3 .. Inf) {
  25. var D = (P*P - 4)
  26. var K = kronecker(D, N)
  27. if (K.is_zero && gcd(D, N).is_between(2, N-1)) {
  28. return nil
  29. }
  30. return P if (K == -1)
  31. }
  32. }
  33. # Strong Lucas pseudoprime test.
  34. func is_strong_lucas_pseudoprime(n) {
  35. return false if (n <= 1)
  36. return true if (n == 2)
  37. return false if n.is_even
  38. return false if n.is_power
  39. var P = 1
  40. var Q = findQ(n) \\ return false
  41. var k = valuation(n+1, 2)
  42. var d = (n+1)>>k
  43. if (lucasUmod(P, Q, d, n) == 0) {
  44. return true
  45. }
  46. for r in (^k) {
  47. if (lucasVmod(P, Q, d * 2**r, n) == 0) {
  48. return true
  49. }
  50. }
  51. return false
  52. }
  53. # Extra-strong Lucas pseudoprime test.
  54. func is_extra_strong_lucas_pseudoprime(n) {
  55. return false if (n <= 1)
  56. return true if (n == 2)
  57. return false if n.is_even
  58. return false if n.is_power
  59. var Q = 1
  60. var P = findP(n) \\ return false
  61. var k = valuation(n+1, 2)
  62. var d = (n+1)>>k
  63. if (lucasUmod(P, Q, d, n) == 0) {
  64. var V = lucasVmod(P, Q, d, n)
  65. if (V.is_congruent(2, n) || V.is_congruent(-2, n)) {
  66. return true
  67. }
  68. }
  69. for r in (^k) {
  70. if (lucasVmod(P, Q, d * 2**r, n) == 0) {
  71. return true
  72. }
  73. }
  74. return false
  75. }
  76. func strong_Baillie_PSW (n) {
  77. return false if (n <= 1)
  78. return true if (n == 2)
  79. return false if (n.is_even)
  80. n.is_strong_pseudoprime(2) && is_strong_lucas_pseudoprime(n)
  81. }
  82. func extra_strong_Baillie_PSW (n) {
  83. return false if (n <= 1)
  84. return true if (n == 2)
  85. return false if (n.is_even)
  86. n.is_strong_pseudoprime(2) && is_extra_strong_lucas_pseudoprime(n)
  87. }
  88. var strong_lucas_psp = [5459, 5777, 10877, 16109, 18971, 22499, 24569, 25199, 40309, 58519, 75077, 97439, 100127, 113573, 115639, 130139, 155819, 158399, 161027, 162133, 176399, 176471, 189419, 192509, 197801, 224369, 230691, 231703, 243629, 253259, 268349, 288919, 313499, 324899]
  89. var extra_strong_lucas_psp = [989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059, 72389, 73919, 75077, 100127, 113573, 125249, 137549, 137801, 153931, 155819, 161027, 162133, 189419, 218321, 231703, 249331, 370229, 429479, 430127, 459191, 473891, 480689, 600059, 621781, 632249, 635627]
  90. assert(strong_lucas_psp.all(is_strong_lucas_pseudoprime))
  91. assert(extra_strong_lucas_psp.all(is_extra_strong_lucas_pseudoprime))
  92. assert(!strong_lucas_psp.all(is_extra_strong_lucas_pseudoprime))
  93. assert(!extra_strong_lucas_psp.all(is_strong_lucas_pseudoprime))
  94. say 25.by(strong_Baillie_PSW)
  95. say 25.by(extra_strong_Baillie_PSW)
  96. say 25.by(is_strong_lucas_pseudoprime)
  97. say 25.by(is_extra_strong_lucas_pseudoprime)
  98. assert_eq(strong_Baillie_PSW.grep(1..900), is_strong_lucas_pseudoprime.grep(1..900))
  99. assert_eq(extra_strong_Baillie_PSW.grep(1..900), is_extra_strong_lucas_pseudoprime.grep(1..900))