fermat_pseudoprimes_in_range.sf 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 30 August 2022
  4. # https://github.com/trizen
  5. # Generate all the k-omega Fermat pseudoprimes in range [a,b]. (not in sorted order)
  6. # Definition:
  7. # k-omega primes are numbers n such that omega(n) = k.
  8. # See also:
  9. # https://en.wikipedia.org/wiki/Almost_prime
  10. # https://en.wikipedia.org/wiki/Prime_omega_function
  11. # https://trizenx.blogspot.com/2020/08/pseudoprimes-construction-methods-and.html
  12. # PARI/GP program (slow):
  13. # fermat_psp(A, B, k, base) = A=max(A, vecprod(primes(k))); (f(m, l, p, j) = my(list=List()); forprime(q=p, sqrtnint(B\m, j), if(base%q != 0, my(v=m*q, t=q, r=nextprime(q+1)); while(v <= B, my(L=lcm(l, znorder(Mod(base, t)))); if(gcd(L, v) == 1, if(j==1, if(v>=A && if(k==1, !isprime(v), 1) && (v-1)%L == 0, listput(list, v)), if(v*r <= B, list=concat(list, f(v, L, r, j-1)))), break); v *= q; t *= q))); list); vecsort(Vec(f(1, 1, 2, k)));
  14. # PARI/GP program (fast):
  15. # fermat_psp(A, B, k, base) = A=max(A, vecprod(primes(k))); (f(m, l, lo, k) = my(list=List()); my(hi=sqrtnint(B\m, k)); if(lo > hi, return(list)); if(k==1, forstep(p=lift(1/Mod(m, l)), hi, l, if(isprimepower(p) && gcd(m*base, p) == 1, my(n=m*p); if(n >= A && (n-1) % znorder(Mod(base, p)) == 0, listput(list, n)))), forprime(p=lo, hi, base%p == 0 && next; my(z=znorder(Mod(base, p))); gcd(m,z) == 1 || next; my(q=p, v=m*p); while(v <= B, list=concat(list, f(v, lcm(l, z), p+1, k-1)); q *= p; Mod(base, q)^z == 1 || break; v *= p))); list); vecsort(Set(f(1, 1, 2, k)));
  16. func fermat_pseudoprimes_in_range(A, B, k, base, callback) {
  17. A = max(k.pn_primorial, A)
  18. var seen = Hash()
  19. func (m, L, lo, j) {
  20. var hi = idiv(B,m).iroot(j)
  21. lo > hi && return nil
  22. if (j == 1) {
  23. if (L == 1) { # optimization
  24. each_prime(lo, hi, {|p|
  25. p.divides(base) && next
  26. for (var v = (m == 1 ? p*p : m*p); v <= B; v *= p) {
  27. v >= A || next
  28. v.is_psp(base) || break
  29. callback(v) if !(seen{v} := 0 ++)
  30. }
  31. })
  32. return nil
  33. }
  34. var t = m.invmod(L)
  35. t > hi && return nil
  36. t += L*idiv_ceil(lo - t, L) if (t < lo)
  37. t > hi && return nil
  38. for p in (range(t, hi, L)) {
  39. p.is_prime_power || next
  40. p.is_coprime(m) || next
  41. p.is_coprime(base) || next
  42. var v = m*p
  43. v >= A || next
  44. if (znorder(base, p) `divides` v.dec) {
  45. callback(v) if !(seen{v} := 0 ++)
  46. }
  47. }
  48. return nil
  49. }
  50. each_prime(lo, hi, {|p|
  51. p.divides(base) && next
  52. var z = znorder(base, p)
  53. m.is_coprime(z) || next
  54. var v = m*p
  55. var q = p
  56. while (v <= B) {
  57. __FUNC__(v, lcm(L, z), p+1, j-1)
  58. q *= p
  59. powmod(base, z, q) == 1 || break
  60. v *= p
  61. }
  62. })
  63. }(1, 1, 2, k)
  64. return callback
  65. }
  66. # Generate all the Fermat pseudoprimes to base 3 in range [1, 10^4]
  67. var from = 1
  68. var upto = 1e4
  69. var base = 3
  70. var arr = gather {
  71. for k in (1..100) {
  72. break if (k.pn_primorial > upto)
  73. fermat_pseudoprimes_in_range(from, upto, k, base, { take(_) })
  74. }
  75. }
  76. say arr.sort
  77. # Run some tests
  78. if (false) { # true to run some tests
  79. for k in (1..5) {
  80. say "Testing: k = #{k}"
  81. var lo = k.pn_primorial
  82. var hi = lo*1000
  83. for base in (2..100) {
  84. var this = k.fermat_psp(base, lo, hi)
  85. #var this = k.omega_primes(lo,hi).grep{.is_psp(base) && .is_composite }
  86. var that = gather {
  87. fermat_pseudoprimes_in_range(lo, hi, k, base, func (n) { take(n) })
  88. }.sort
  89. this == that ||
  90. die "Error for k = #{k} and base = #{base} with hi = #{hi}\n#{this} != #{that}";
  91. }
  92. }
  93. }
  94. __END__
  95. [91, 121, 286, 671, 703, 949, 1105, 1541, 1729, 1891, 2465, 2665, 2701, 2821, 3281, 3367, 3751, 4961, 5551, 6601, 7381, 8401, 8911]