lib/zipfian.rb in zipfian-0.0.2 vs lib/zipfian.rb in zipfian-0.0.3
- old
+ new
@@ -1,40 +1,53 @@
require "zipfian/version"
class Zipfian
attr_reader :n, :s
- def initialize n, s
+ @@global_mutex = Mutex.new
+ @@mutexes = {}
+ @@h = {}
+ @@cdf = {}
+
+ def initialize n, s, cache = false
unless n > 0 && n.is_a?(Integer)
raise ArgumentError.new("Number of elements must be a positive integer")
end
unless s > 0
raise ArgumentError.new("Exponent must be a positive number")
end
@n = n
@s = s
sums = [0]
- @h = (1..@n).inject(0) { |sum, i| sums[i] = sum + 1.0 / (i ** @s) }
- @cdf = (0..@n).map { |i| sums[i] / @h }
- class << @cdf
- def binary_search_index v
- l = 0
- r = self.length - 2
+ compute_h = lambda { (1..@n).inject(0) { |sum, i| sums[i] = sum + 1.0 / (i ** @s) } }
+ compute_cdf = lambda { (0..@n).map { |i| sums[i] / @h } }
- while (c = (l + r) / 2) && l < r
- if v < self[c]
- r = c - 1
- elsif v > self[c]
- l = c + 1
- else
- return c
- end
+ key = [n, s]
+ mutex = nil
+ if cache
+ @@global_mutex.synchronize do
+ mutex = @@mutexes[key] ||= Mutex.new
+ end
+ mutex.synchronize do
+ @h = @@h[key] ||= compute_h.call
+ @cdf = @@cdf[key] ||= compute_cdf.call
+ end
+ else
+ @@global_mutex.synchronize do
+ # Do not create mutex
+ mutex = @@mutexes[key]
+ end
+ if mutex
+ mutex.synchronize do
+ @h = @@h[key] || compute_h.call
+ @cdf = @@cdf[key] || compute_cdf.call
end
-
- v < self[c] ? c : c + 1
+ else
+ @h = compute_h.call
+ @cdf = compute_cdf.call
end
end
end
def inspect
@@ -53,16 +66,42 @@
check_rank k
@cdf[k]
end
def sample
- @cdf.binary_search_index rand
+ binary_search_index @cdf, rand
end
+ def self.cached
+ ret = []
+ @@global_mutex.synchronize do
+ @@mutexes.keys.each do |key|
+ ret << { :n => key.first, :s => key.last }
+ end
+ end
+ ret
+ end
private
def check_rank k
unless k.is_a?(Integer) && k >= 1 && k <= @n
raise ArgumentError.new("Rank must be a positive integer (max: #{@n})")
end
+ end
+
+ def binary_search_index arr, v
+ l = 0
+ r = arr.length - 2
+
+ while (c = (l + r) / 2) && l < r
+ if v < arr[c]
+ r = c - 1
+ elsif v > arr[c]
+ l = c + 1
+ else
+ return c
+ end
+ end
+
+ v < arr[c] ? c : c + 1
end
end