inverse_of_euler_totient.sf 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #!/usr/bin/ruby
  2. # Given a positive integer `n`, this algorithm finds all the numbers k such that φ(k) = n.
  3. # Based on Dana Jacobsen's code from Math::Prime::Util,
  4. # which in turn is based on invphi.gp v1.3 by Max Alekseyev.
  5. # See also:
  6. # https://projecteuler.net/problem=248
  7. # https://en.wikipedia.org/wiki/Euler%27s_totient_function
  8. # https://github.com/danaj/Math-Prime-Util/blob/master/examples/inverse_totient.pl
  9. func inverse_euler_phi (n) {
  10. var r = Hash(
  11. 1 => [1]
  12. )
  13. n.divisors.each { |d|
  14. is_prime(d+1) || next
  15. var t = Hash()
  16. for k in (1 .. (n.valuation(d+1) + 1)) {
  17. var u = (d * (d+1)**(k-1))
  18. var v = (d+1)**k
  19. (n/u).divisors.each {|f|
  20. if (r.contains(f)) {
  21. t{ f * u } := [] << r{f}.map{ _ * v }...
  22. }
  23. }
  24. }
  25. t.each { |i,v|
  26. r{i} := [] << v...
  27. }
  28. }
  29. return [] if !r.contains(n)
  30. return r{n}.sort
  31. }
  32. for n in (1..70) {
  33. var arr = inverse_euler_phi(n) || next
  34. say "φ−¹(#{n}) = [#{arr.join(', ')}]";
  35. }
  36. __END__
  37. φ−¹(1) = [1, 2]
  38. φ−¹(2) = [3, 4, 6]
  39. φ−¹(4) = [5, 8, 10, 12]
  40. φ−¹(6) = [7, 9, 14, 18]
  41. φ−¹(8) = [15, 16, 20, 24, 30]
  42. φ−¹(10) = [11, 22]
  43. φ−¹(12) = [13, 21, 26, 28, 36, 42]
  44. φ−¹(16) = [17, 32, 34, 40, 48, 60]
  45. φ−¹(18) = [19, 27, 38, 54]
  46. φ−¹(20) = [25, 33, 44, 50, 66]
  47. φ−¹(22) = [23, 46]
  48. φ−¹(24) = [35, 39, 45, 52, 56, 70, 72, 78, 84, 90]
  49. φ−¹(28) = [29, 58]
  50. φ−¹(30) = [31, 62]
  51. φ−¹(32) = [51, 64, 68, 80, 96, 102, 120]
  52. φ−¹(36) = [37, 57, 63, 74, 76, 108, 114, 126]
  53. φ−¹(40) = [41, 55, 75, 82, 88, 100, 110, 132, 150]
  54. φ−¹(42) = [43, 49, 86, 98]
  55. φ−¹(44) = [69, 92, 138]
  56. φ−¹(46) = [47, 94]
  57. φ−¹(48) = [65, 104, 105, 112, 130, 140, 144, 156, 168, 180, 210]