quadratic_integers.sf 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/ruby
  2. # Simple implementation of quadratic integers.
  3. # See also:
  4. # https://en.wikipedia.org/wiki/Quadratic_integer
  5. class QuadraticInteger(a, b, w = 2) { # represents: a + b*sqrt(w)
  6. method to_s {
  7. "QuadraticInteger(#{a}, #{b}, #{w})"
  8. }
  9. method ==(QuadraticInteger c) {
  10. (a == c.a) && (b == c.b) && (w == c.w)
  11. }
  12. method conjugate {
  13. QuadraticInteger(a, -b, w)
  14. }
  15. method norm {
  16. a*a - w*b*b
  17. }
  18. method add (Number c) {
  19. QuadraticInteger(a+c, b, w)
  20. }
  21. method add (QuadraticInteger z) {
  22. var (c,d) = (z.a, z.b)
  23. QuadraticInteger(a+c, b+d, w)
  24. }
  25. __CLASS__.alias_method(:add, '+')
  26. method sub (Number c) {
  27. QuadraticInteger(a-c, b, w)
  28. }
  29. method sub (QuadraticInteger z) {
  30. var (c,d) = (z.a, z.b)
  31. QuadraticInteger(a-c, b-d, w)
  32. }
  33. __CLASS__.alias_method(:sub, '-')
  34. method mul (Number c) {
  35. QuadraticInteger(a*c, b*c, w)
  36. }
  37. method mul (QuadraticInteger z) {
  38. var (c,d) = (z.a, z.b)
  39. QuadraticInteger(a*c + b*d*w, a*d + b*c, w)
  40. }
  41. __CLASS__.alias_method(:mul, '*')
  42. method mod (Number m) {
  43. QuadraticInteger(a % m, b % m, w)
  44. }
  45. __CLASS__.alias_method(:mod, '%')
  46. method pow(Number n) {
  47. var x = self
  48. var c = QuadraticInteger(1, 0, w)
  49. for bit in (n.digits(2)) {
  50. c *= x if bit
  51. x *= x
  52. }
  53. return c
  54. }
  55. __CLASS__.alias_method(:pow, '**')
  56. method powmod(Number n, Number m) {
  57. var x = self
  58. var c = QuadraticInteger(1, 0, w)
  59. for bit in (n.digits(2)) {
  60. (c *= x) %= m if bit #=
  61. (x *= x) %= m #=
  62. }
  63. return c
  64. }
  65. }
  66. #---------------------------------------------------------------------
  67. # Determine if a given number is probably a prime number.
  68. func is_quadratic_pseudoprime (n, r=2) {
  69. return false if (n <= 1)
  70. return true if (n <= 3)
  71. return true if (r <= 0)
  72. var x = QuadraticInteger(r, 1, r+2).powmod(n, n)
  73. x.a == r || return false
  74. var y = QuadraticInteger(r, -1, r+2).powmod(n, n)
  75. y.a == r || return false
  76. (x.b + y.b == n) && __FUNC__(n, r-1)
  77. }
  78. say is_quadratic_pseudoprime(43) #=> true
  79. say is_quadratic_pseudoprime(97) #=> true
  80. with (QuadraticInteger(1, 1, 2)) {|q|
  81. say 15.of { q.pow(_).a } #=> A001333
  82. say 15.of { q.pow(_).b } #=> A000129
  83. }
  84. with (QuadraticInteger(1, 1, 3)) {|q|
  85. say 15.of { q.pow(_).a } #=> A026150
  86. say 15.of { q.pow(_).b } #=> A002605
  87. }
  88. var n = (274177-1)
  89. var m = (2**64 + 1)
  90. with (QuadraticInteger(3, 4, 2)) {|q|
  91. var r = q.powmod(n, m)
  92. say gcd(r.a-1, m) #=> 2741177
  93. say gcd(r.b, m) #=> 2741177
  94. }
  95. #---------------------------------------------------------------------
  96. func is_gaussian_quadratic_pseudoprime(n) {
  97. return false if (n <= 1)
  98. return true if (n <= 3)
  99. static x = QuadraticInteger(1, -1, -2)
  100. given (n%8) {
  101. when ([1,3]) {
  102. var t = x.powmod(n-1, n)
  103. (t.a==1 && t.b==0)
  104. }
  105. when ([5, 7]) {
  106. var t = x.powmod(n+1, n)
  107. (t.a==3 && t.b==0)
  108. }
  109. else {
  110. false
  111. }
  112. }
  113. }
  114. assert([88561,107185,162401,221761,226801,334153,410041,665281,825265,1569457,1615681,2727649].all(is_gaussian_quadratic_pseudoprime))
  115. assert([80375707,154287451,267559627,326266051,478614067,573183451,643767931,2433943891,4297753027].all(is_gaussian_quadratic_pseudoprime))
  116. for n in (1..1e2) {
  117. if (is_gaussian_quadratic_pseudoprime(n)) {
  118. if (n.is_composite) {
  119. say "Counter-example: #{n}"
  120. }
  121. }
  122. elsif (n.is_prime) {
  123. say "Missed prime: #{n}"
  124. }
  125. }