carmichael_generation_erdos_method_dynamic_programming.sf 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #!/usr/bin/ruby
  2. # Three approaches at implementing the Erdos method for constructing Carmichael numbers, using dynamic programming.
  3. # Erdos construction method for Carmichael numbers:
  4. # 1. Choose an integer L with many prime factors.
  5. # 2. Let P be the set of primes d+1, where d|L and d+1 does not divide L.
  6. # 3. Find a subset S of P such that prod(S) == 1 (mod L). Then prod(S) is a Carmichael number.
  7. # Alternatively:
  8. # 3. Find a subset S of P such that prod(S) == prod(P) (mod L). Then prod(P) / prod(S) is a Carmichael number.
  9. func carmichael_numbers_from_lambda(L, callback) { # smallest numbers first
  10. var P = L.divisors.map { .inc }.grep {|p| p.is_odd && p.is_prime && L.is_coprime(p) }
  11. var d = [1]
  12. P.each {|p|
  13. d << gather {
  14. d.each { |u|
  15. take(var c = u*p)
  16. if (c.is_congruent(1, L)) {
  17. callback(c)
  18. }
  19. }
  20. }...
  21. }
  22. return nil
  23. }
  24. func carmichael_numbers_from_lambda_large(L, callback) { # largest numbers first
  25. var P = L.divisors.map { .inc }.grep {|p| p.is_odd && p.is_prime && L.is_coprime(p) }
  26. var T = P.prod
  27. var s = T%L
  28. var d = [1]
  29. P.each {|p|
  30. d << gather {
  31. d.each { |u|
  32. take(var c = u*p)
  33. if (c.is_congruent(s, L)) {
  34. callback(idiv(T, c)) if (T > c)
  35. }
  36. }
  37. }...
  38. }
  39. return nil
  40. }
  41. func carmichael_numbers_from_lambda_lazy(L, callback) { # on-demand version
  42. var d1 = [1]
  43. var d2 = [1]
  44. for p,e in (L.factor_exp) {
  45. var r = 1
  46. d1 << gather {
  47. e.times {
  48. r *= p
  49. d1.each { |u|
  50. take(var t = u*r)
  51. var q = t+1
  52. next if !(q.is_odd && q.is_prime && L.is_coprime(q))
  53. d2 << gather {
  54. d2.each { |u|
  55. take(var c = u*q)
  56. if (c.is_congruent(1, L)) {
  57. callback(c)
  58. }
  59. }
  60. }...
  61. }
  62. }
  63. }...
  64. }
  65. return nil
  66. }
  67. carmichael_numbers_from_lambda(720, {|c| say c })
  68. carmichael_numbers_from_lambda_lazy(720, {|c| say c })
  69. carmichael_numbers_from_lambda_large(720, {|c| say c })