polynomial_factorization_monte_carlo.sf 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/ruby
  2. # Factorize a polynomial using evaluation with random integer values and integer factorization.
  3. # Reference:
  4. # Lecture 15, Week 8, 1hr - Polynomial factorization
  5. # https://youtube.com/watch?v=tMqKqsMb-Ro
  6. # This method is not recommended, as it is quite slow.
  7. func polynomial_factorization(f, tries = 500) {
  8. tries.times {
  9. var x = tries.irand
  10. var v = f(x).abs
  11. v.is_int || next
  12. v.divisors.each {|d|
  13. d > 1 || next
  14. d < v || next
  15. var e = d.ilog(x)
  16. e > 0 || break
  17. var (c,r) = divmod(d, x**e)
  18. var g = Poly([[0, r], [e, c]])
  19. if (f % g == 0) {
  20. return __FUNC__(g)+__FUNC__(f/g)
  21. }
  22. var (c,r) = divmod(x**(e+1), d)
  23. var g = Poly([[0, x-r], [e+1, c], [e, -1]])
  24. if (f % g == 0) {
  25. return __FUNC__(g)+__FUNC__(f/g)
  26. }
  27. }
  28. }
  29. return [f]
  30. }
  31. func display_factorization(f) {
  32. say (f.pretty, ' = ', polynomial_factorization(f).map{"(#{.pretty})"}.join(' * '))
  33. }
  34. display_factorization(Poly("9*x^4 - 1"))
  35. display_factorization(Poly("2*x^4 - 6*x^3 + 7*x^2 - 5*x + 1"))
  36. display_factorization(Poly("8*x^4 + 18*x^3 - 63*x^2 - 162*x - 81"))
  37. __END__
  38. 9*x^4 - 1 = (3*x^2 + 1) * (3*x^2 - 1)
  39. 2*x^4 - 6*x^3 + 7*x^2 - 5*x + 1 = (x^2 - x + 1) * (2*x^2 - 4*x + 1)
  40. 8*x^4 + 18*x^3 - 63*x^2 - 162*x - 81 = (x + 3) * (2*x + 3) * (4*x^2 - 9*x - 9)