continued_fraction_factorization_method_simple.sf 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #!/usr/bin/ruby
  2. # A simple version of the continued fraction factorization method, without the linear algebra stage.
  3. # Similar to solving the Pell equation:
  4. # x^2 - d*y^2 = 1, where `d` is known.
  5. # See also:
  6. # https://en.wikipedia.org/wiki/Pell%27s_equation
  7. func cffm (n) {
  8. # Check for primes and negative numbers
  9. return [] if (n <= 1)
  10. return [n] if n.is_prime
  11. # Check for perfect powers
  12. if (n.is_power) {
  13. var root = n.perfect_root
  14. var power = n.perfect_power
  15. var factors = __FUNC__(root)
  16. return (factors * power -> sort)
  17. }
  18. # Check for divisibility by 2
  19. if (n.is_even) {
  20. var v = n.valuation(2)
  21. var t = n>>v
  22. var factors = v.of(2)
  23. if (t > 1) {
  24. factors += __FUNC__(t)
  25. }
  26. return factors
  27. }
  28. var resolve_factor = {|a,b|
  29. var g = gcd(a - b.isqrt, n)
  30. if ((g > 1) && (g < n)) {
  31. return (
  32. __FUNC__(g) +
  33. __FUNC__(n/g) -> sort
  34. )
  35. }
  36. }
  37. var x = n.isqrt
  38. var y = x
  39. var z = 1
  40. var r = x+x
  41. var (e1, e2) = (1, 0)
  42. var (f1, f2) = (0, 1)
  43. var S = Hash()
  44. do {
  45. y = (r*z - y)
  46. z = idiv(n - y*y, z)
  47. r = idiv(x + y, z)
  48. var a = addmod(x*f2, e2, n)
  49. var b = mulmod(a, a, n)
  50. if (b.is_square) {
  51. resolve_factor(a, b)
  52. }
  53. if (S.exists(b)) {
  54. resolve_factor(a * S{b}, b*b)
  55. }
  56. else {
  57. S{b} = a
  58. }
  59. (f1, f2) = (f2, addmod(r*f2, f1, n))
  60. (e1, e2) = (e2, addmod(r*e2, e1, n))
  61. } while (z != 1)
  62. return [n]
  63. }
  64. var composites = (ARGV ? ARGV.map{.to_i} : {|k| 2.of { random_prime(1<<k) }.prod }.map(2..25) )
  65. for n in (composites) {
  66. var factors = cffm(n)
  67. assert_eq(factors.prod, n)
  68. if (factors.all { .is_prime }) {
  69. say "#{n} = #{factors.join(' * ')}"
  70. }
  71. else {
  72. say "#{n} = #{factors.join(' * ')} (incomplete factorization)"
  73. }
  74. }