squarefree_fermat_overpseudoprimes_in_range.sf 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 29 August 2022
  4. # https://github.com/trizen
  5. # Generate all the squarefree Fermat overpseudoprimes to a given base with n prime factors in a given range [a,b]. (not in sorted order)
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Almost_prime
  8. # https://trizenx.blogspot.com/2020/08/pseudoprimes-construction-methods-and.html
  9. func inverse_znorder_primes(base, lambda) is cached {
  10. base**lambda - 1 -> prime_divisors
  11. }
  12. func iterate_over_primes(x,y,base,lambda,callback) {
  13. if ((lambda > 1) && (lambda <= 100)) {
  14. for q in (inverse_znorder_primes(base, lambda)) {
  15. next if (q < x)
  16. break if (q > y)
  17. #znorder(base, q) == lambda || next
  18. callback(q)
  19. }
  20. return nil
  21. }
  22. if (lambda > 1) {
  23. var u = lambda*idiv_ceil(x-1, lambda)
  24. return nil if (u > y)
  25. for w in (range(u, y, lambda)) {
  26. with (w+1) { |p|
  27. callback(p) if p.is_prime
  28. }
  29. }
  30. return nil
  31. }
  32. each_prime(x, y, callback)
  33. }
  34. func squarefree_fermat_overpseudoprimes_in_range(a, b, k, base, callback) {
  35. a = max(k.pn_primorial, a)
  36. func (m, L, lo, k) {
  37. var hi = idiv(b,m).iroot(k)
  38. return nil if (lo > hi)
  39. if (k == 1) {
  40. lo = max(lo, idiv_ceil(a, m))
  41. return nil if (lo > hi)
  42. iterate_over_primes(lo, hi, base, L, {|p|
  43. if (powmod(base, L, p) == 1) {
  44. with (m*p - 1) {|t|
  45. if ((L `divides` t) && (L == znorder(base, p))) {
  46. callback(t+1)
  47. }
  48. }
  49. }
  50. })
  51. return nil
  52. }
  53. iterate_over_primes(lo, hi, base, L, {|p|
  54. p.divides(base) && next
  55. var z = znorder(base, p)
  56. if (L > 1) {
  57. z == L || next
  58. }
  59. m.is_coprime(z) || next
  60. __FUNC__(m*p, z, p.next_prime, k-1)
  61. })
  62. }(1, 1, 2, k)
  63. return callback
  64. }
  65. # High-level implementation (unoptimized)
  66. func squarefree_fermat_overpseudoprimes_in_range_unoptimized(A, B, k, base, callback) {
  67. func F(m, lambda, p, k) {
  68. if (k == 1) {
  69. each_prime(max(p, ceil(A/m)), floor(B/m), {|q|
  70. if ((powmod(base, lambda, q) == 1) && (znorder(base, q) == lambda) && (lambda `divides` (m*q - 1))) {
  71. callback(m*q)
  72. }
  73. })
  74. }
  75. elsif (k >= 2) {
  76. for q in (primes(p, (B/m)**(1/k))) {
  77. if (!q.divides(base)) {
  78. var L = znorder(base, q)
  79. if ((lambda==L || lambda==1) && (gcd(L, m) == 1)) {
  80. F(m*q, L, q.next_prime, k-1)
  81. }
  82. }
  83. }
  84. }
  85. }
  86. F(1, 1, 2, k)
  87. }
  88. # Generate all the squarefree Fermat overpseudoprimes to base 2 with 3 prime factors in the range [1194649, 14325843000]
  89. var k = 3
  90. var base = 2
  91. var from = 1194649
  92. var upto = 14325843000
  93. say gather { squarefree_fermat_overpseudoprimes_in_range(from, upto, k, base, { take(_) }) }.sort
  94. say gather { squarefree_fermat_overpseudoprimes_in_range_unoptimized(from, upto, k, base, { take(_) }) }.sort if false
  95. __END__
  96. [13421773, 464955857, 536870911, 1220114377, 1541955409, 2454285751, 3435973837, 5256967999, 5726579371, 7030714813, 8493511669, 8538455017, 8788016089, 10545166433, 13893138041]