summaryrefslogtreecommitdiff
path: root/jni/ruby/lib/prime.rb
diff options
context:
space:
mode:
Diffstat (limited to 'jni/ruby/lib/prime.rb')
-rw-r--r--jni/ruby/lib/prime.rb487
1 files changed, 487 insertions, 0 deletions
diff --git a/jni/ruby/lib/prime.rb b/jni/ruby/lib/prime.rb
new file mode 100644
index 0000000..b2b55f1
--- /dev/null
+++ b/jni/ruby/lib/prime.rb
@@ -0,0 +1,487 @@
+#
+# = prime.rb
+#
+# Prime numbers and factorization library.
+#
+# Copyright::
+# Copyright (c) 1998-2008 Keiju ISHITSUKA(SHL Japan Inc.)
+# Copyright (c) 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
+#
+# Documentation::
+# Yuki Sonoda
+#
+
+require "singleton"
+require "forwardable"
+
+class Integer
+ # Re-composes a prime factorization and returns the product.
+ #
+ # See Prime#int_from_prime_division for more details.
+ def Integer.from_prime_division(pd)
+ Prime.int_from_prime_division(pd)
+ end
+
+ # Returns the factorization of +self+.
+ #
+ # See Prime#prime_division for more details.
+ def prime_division(generator = Prime::Generator23.new)
+ Prime.prime_division(self, generator)
+ end
+
+ # Returns true if +self+ is a prime number, else returns false.
+ def prime?
+ Prime.prime?(self)
+ end
+
+ # Iterates the given block over all prime numbers.
+ #
+ # See +Prime+#each for more details.
+ def Integer.each_prime(ubound, &block) # :yields: prime
+ Prime.each(ubound, &block)
+ end
+end
+
+#
+# The set of all prime numbers.
+#
+# == Example
+#
+# Prime.each(100) do |prime|
+# p prime #=> 2, 3, 5, 7, 11, ...., 97
+# end
+#
+# Prime is Enumerable:
+#
+# Prime.first 5 # => [2, 3, 5, 7, 11]
+#
+# == Retrieving the instance
+#
+# +Prime+.new is obsolete. Now +Prime+ has the default instance and you can
+# access it as +Prime+.instance.
+#
+# For convenience, each instance method of +Prime+.instance can be accessed
+# as a class method of +Prime+.
+#
+# e.g.
+# Prime.instance.prime?(2) #=> true
+# Prime.prime?(2) #=> true
+#
+# == Generators
+#
+# A "generator" provides an implementation of enumerating pseudo-prime
+# numbers and it remembers the position of enumeration and upper bound.
+# Furthermore, it is an external iterator of prime enumeration which is
+# compatible with an Enumerator.
+#
+# +Prime+::+PseudoPrimeGenerator+ is the base class for generators.
+# There are few implementations of generator.
+#
+# [+Prime+::+EratosthenesGenerator+]
+# Uses eratosthenes' sieve.
+# [+Prime+::+TrialDivisionGenerator+]
+# Uses the trial division method.
+# [+Prime+::+Generator23+]
+# Generates all positive integers which are not divisible by either 2 or 3.
+# This sequence is very bad as a pseudo-prime sequence. But this
+# is faster and uses much less memory than the other generators. So,
+# it is suitable for factorizing an integer which is not large but
+# has many prime factors. e.g. for Prime#prime? .
+
+class Prime
+ include Enumerable
+ @the_instance = Prime.new
+
+ # obsolete. Use +Prime+::+instance+ or class methods of +Prime+.
+ def initialize
+ @generator = EratosthenesGenerator.new
+ extend OldCompatibility
+ warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
+ end
+
+ class << self
+ extend Forwardable
+ include Enumerable
+ # Returns the default instance of Prime.
+ def instance; @the_instance end
+
+ def method_added(method) # :nodoc:
+ (class<< self;self;end).def_delegator :instance, method
+ end
+ end
+
+ # Iterates the given block over all prime numbers.
+ #
+ # == Parameters
+ #
+ # +ubound+::
+ # Optional. An arbitrary positive number.
+ # The upper bound of enumeration. The method enumerates
+ # prime numbers infinitely if +ubound+ is nil.
+ # +generator+::
+ # Optional. An implementation of pseudo-prime generator.
+ #
+ # == Return value
+ #
+ # An evaluated value of the given block at the last time.
+ # Or an enumerator which is compatible to an +Enumerator+
+ # if no block given.
+ #
+ # == Description
+ #
+ # Calls +block+ once for each prime number, passing the prime as
+ # a parameter.
+ #
+ # +ubound+::
+ # Upper bound of prime numbers. The iterator stops after it
+ # yields all prime numbers p <= +ubound+.
+ #
+ # == Note
+ #
+ # +Prime+.+new+ returns an object extended by +Prime+::+OldCompatibility+
+ # in order to be compatible with Ruby 1.8, and +Prime+#each is overwritten
+ # by +Prime+::+OldCompatibility+#+each+.
+ #
+ # +Prime+.+new+ is now obsolete. Use +Prime+.+instance+.+each+ or simply
+ # +Prime+.+each+.
+ def each(ubound = nil, generator = EratosthenesGenerator.new, &block)
+ generator.upper_bound = ubound
+ generator.each(&block)
+ end
+
+
+ # Returns true if +value+ is a prime number, else returns false.
+ #
+ # == Parameters
+ #
+ # +value+:: an arbitrary integer to be checked.
+ # +generator+:: optional. A pseudo-prime generator.
+ def prime?(value, generator = Prime::Generator23.new)
+ return false if value < 2
+ for num in generator
+ q,r = value.divmod num
+ return true if q < num
+ return false if r == 0
+ end
+ end
+
+ # Re-composes a prime factorization and returns the product.
+ #
+ # == Parameters
+ # +pd+:: Array of pairs of integers. The each internal
+ # pair consists of a prime number -- a prime factor --
+ # and a natural number -- an exponent.
+ #
+ # == Example
+ # For <tt>[[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]]</tt>, it returns:
+ #
+ # p_1**e_1 * p_2**e_2 * .... * p_n**e_n.
+ #
+ # Prime.int_from_prime_division([[2,2], [3,1]]) #=> 12
+ def int_from_prime_division(pd)
+ pd.inject(1){|value, (prime, index)|
+ value * prime**index
+ }
+ end
+
+ # Returns the factorization of +value+.
+ #
+ # == Parameters
+ # +value+:: An arbitrary integer.
+ # +generator+:: Optional. A pseudo-prime generator.
+ # +generator+.succ must return the next
+ # pseudo-prime number in the ascending
+ # order. It must generate all prime numbers,
+ # but may also generate non prime numbers too.
+ #
+ # === Exceptions
+ # +ZeroDivisionError+:: when +value+ is zero.
+ #
+ # == Example
+ # For an arbitrary integer:
+ #
+ # n = p_1**e_1 * p_2**e_2 * .... * p_n**e_n,
+ #
+ # prime_division(n) returns:
+ #
+ # [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]].
+ #
+ # Prime.prime_division(12) #=> [[2,2], [3,1]]
+ #
+ def prime_division(value, generator = Prime::Generator23.new)
+ raise ZeroDivisionError if value == 0
+ if value < 0
+ value = -value
+ pv = [[-1, 1]]
+ else
+ pv = []
+ end
+ for prime in generator
+ count = 0
+ while (value1, mod = value.divmod(prime)
+ mod) == 0
+ value = value1
+ count += 1
+ end
+ if count != 0
+ pv.push [prime, count]
+ end
+ break if value1 <= prime
+ end
+ if value > 1
+ pv.push [value, 1]
+ end
+ return pv
+ end
+
+ # An abstract class for enumerating pseudo-prime numbers.
+ #
+ # Concrete subclasses should override succ, next, rewind.
+ class PseudoPrimeGenerator
+ include Enumerable
+
+ def initialize(ubound = nil)
+ @ubound = ubound
+ end
+
+ def upper_bound=(ubound)
+ @ubound = ubound
+ end
+ def upper_bound
+ @ubound
+ end
+
+ # returns the next pseudo-prime number, and move the internal
+ # position forward.
+ #
+ # +PseudoPrimeGenerator+#succ raises +NotImplementedError+.
+ def succ
+ raise NotImplementedError, "need to define `succ'"
+ end
+
+ # alias of +succ+.
+ def next
+ raise NotImplementedError, "need to define `next'"
+ end
+
+ # Rewinds the internal position for enumeration.
+ #
+ # See +Enumerator+#rewind.
+ def rewind
+ raise NotImplementedError, "need to define `rewind'"
+ end
+
+ # Iterates the given block for each prime number.
+ def each
+ return self.dup unless block_given?
+ if @ubound
+ last_value = nil
+ loop do
+ prime = succ
+ break last_value if prime > @ubound
+ last_value = yield prime
+ end
+ else
+ loop do
+ yield succ
+ end
+ end
+ end
+
+ # see +Enumerator+#with_index.
+ alias with_index each_with_index
+
+ # see +Enumerator+#with_object.
+ def with_object(obj)
+ return enum_for(:with_object) unless block_given?
+ each do |prime|
+ yield prime, obj
+ end
+ end
+ end
+
+ # An implementation of +PseudoPrimeGenerator+.
+ #
+ # Uses +EratosthenesSieve+.
+ class EratosthenesGenerator < PseudoPrimeGenerator
+ def initialize
+ @last_prime_index = -1
+ super
+ end
+
+ def succ
+ @last_prime_index += 1
+ EratosthenesSieve.instance.get_nth_prime(@last_prime_index)
+ end
+ def rewind
+ initialize
+ end
+ alias next succ
+ end
+
+ # An implementation of +PseudoPrimeGenerator+ which uses
+ # a prime table generated by trial division.
+ class TrialDivisionGenerator<PseudoPrimeGenerator
+ def initialize
+ @index = -1
+ super
+ end
+
+ def succ
+ TrialDivision.instance[@index += 1]
+ end
+ def rewind
+ initialize
+ end
+ alias next succ
+ end
+
+ # Generates all integers which are greater than 2 and
+ # are not divisible by either 2 or 3.
+ #
+ # This is a pseudo-prime generator, suitable on
+ # checking primality of an integer by brute force
+ # method.
+ class Generator23<PseudoPrimeGenerator
+ def initialize
+ @prime = 1
+ @step = nil
+ super
+ end
+
+ def succ
+ if (@step)
+ @prime += @step
+ @step = 6 - @step
+ else
+ case @prime
+ when 1; @prime = 2
+ when 2; @prime = 3
+ when 3; @prime = 5; @step = 2
+ end
+ end
+ return @prime
+ end
+ alias next succ
+ def rewind
+ initialize
+ end
+ end
+
+ # Internal use. An implementation of prime table by trial division method.
+ class TrialDivision
+ include Singleton
+
+ def initialize # :nodoc:
+ # These are included as class variables to cache them for later uses. If memory
+ # usage is a problem, they can be put in Prime#initialize as instance variables.
+
+ # There must be no primes between @primes[-1] and @next_to_check.
+ @primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
+ # @next_to_check % 6 must be 1.
+ @next_to_check = 103 # @primes[-1] - @primes[-1] % 6 + 7
+ @ulticheck_index = 3 # @primes.index(@primes.reverse.find {|n|
+ # n < Math.sqrt(@@next_to_check) })
+ @ulticheck_next_squared = 121 # @primes[@ulticheck_index + 1] ** 2
+ end
+
+ # Returns the cached prime numbers.
+ def cache
+ return @primes
+ end
+ alias primes cache
+ alias primes_so_far cache
+
+ # Returns the +index+th prime number.
+ #
+ # +index+ is a 0-based index.
+ def [](index)
+ while index >= @primes.length
+ # Only check for prime factors up to the square root of the potential primes,
+ # but without the performance hit of an actual square root calculation.
+ if @next_to_check + 4 > @ulticheck_next_squared
+ @ulticheck_index += 1
+ @ulticheck_next_squared = @primes.at(@ulticheck_index + 1) ** 2
+ end
+ # Only check numbers congruent to one and five, modulo six. All others
+
+ # are divisible by two or three. This also allows us to skip checking against
+ # two and three.
+ @primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
+ @next_to_check += 4
+ @primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
+ @next_to_check += 2
+ end
+ return @primes[index]
+ end
+ end
+
+ # Internal use. An implementation of eratosthenes' sieve
+ class EratosthenesSieve
+ include Singleton
+
+ def initialize
+ @primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
+ # @max_checked must be an even number
+ @max_checked = @primes.last + 1
+ end
+
+ def get_nth_prime(n)
+ compute_primes while @primes.size <= n
+ @primes[n]
+ end
+
+ private
+ def compute_primes
+ # max_segment_size must be an even number
+ max_segment_size = 1e6.to_i
+ max_cached_prime = @primes.last
+ # do not double count primes if #compute_primes is interrupted
+ # by Timeout.timeout
+ @max_checked = max_cached_prime + 1 if max_cached_prime > @max_checked
+
+ segment_min = @max_checked
+ segment_max = [segment_min + max_segment_size, max_cached_prime * 2].min
+ root = Integer(Math.sqrt(segment_max).floor)
+
+ sieving_primes = @primes[1 .. -1].take_while { |prime| prime <= root }
+ offsets = Array.new(sieving_primes.size) do |i|
+ (-(segment_min + 1 + sieving_primes[i]) / 2) % sieving_primes[i]
+ end
+
+ segment = ((segment_min + 1) .. segment_max).step(2).to_a
+ sieving_primes.each_with_index do |prime, index|
+ composite_index = offsets[index]
+ while composite_index < segment.size do
+ segment[composite_index] = nil
+ composite_index += prime
+ end
+ end
+
+ segment.each do |prime|
+ @primes.push prime unless prime.nil?
+ end
+ @max_checked = segment_max
+ end
+ end
+
+ # Provides a +Prime+ object with compatibility to Ruby 1.8 when instantiated via +Prime+.+new+.
+ module OldCompatibility
+ # Returns the next prime number and forwards internal pointer.
+ def succ
+ @generator.succ
+ end
+ alias next succ
+
+ # Overwrites Prime#each.
+ #
+ # Iterates the given block over all prime numbers. Note that enumeration
+ # starts from the current position of internal pointer, not rewound.
+ def each
+ return @generator.dup unless block_given?
+ loop do
+ yield succ
+ end
+ end
+ end
+end