Class: LoadedDie::Sampler

Inherits:
Object
  • Object
show all
Defined in:
lib/loaded_die.rb

Overview

Objects of this class can choose randomly from a set of options (called individuals here). The options can have different probabilities of being chosen.

Defined Under Namespace

Classes: Segment

Constant Summary collapse

DEFAULT_RNG =

The default random number generator.

::Object.new

Instance Method Summary collapse

Constructor Details

#initialize(population) ⇒ Sampler

Creates a sampler from a population. The argument should be an enumerable of two-element arrays (a hash qualifies). The first element of each array is an individual that can be chosen; the second element is its weight – that is, the likelihood (relative to the other weights) that the individual will be chosen. Weights must be positive numbers.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/loaded_die.rb', line 40

def initialize(population)
  @compiled = population.inject [] do |accum, (individual, weight)|
    if weight <= 0
      raise ::ArgumentError, "non-positive weight #{weight}"
    end
    prev_max =
      if last = accum.last
        last.maximum
      else
        0
      end
    accum << Segment.new(prev_max + weight, individual)
  end
  nil
end

Instance Method Details

#[](point) ⇒ Object

Returns the individual for the given point. The point should be a number. If it is greater than or equal to zero and less than the sum of weights, this returns the corresponding individual. If it is outside those bounds, this returns nil.



73
74
75
76
77
78
79
80
81
# File 'lib/loaded_die.rb', line 73

def [](point)
  if point < 0
    nil
  elsif choice = @compiled.detect { |segment| point < segment.maximum }
    choice.individual
  else
    nil
  end
end

#lengthObject

Returns the sum of weights.



59
60
61
62
63
64
65
# File 'lib/loaded_die.rb', line 59

def length
  if last = @compiled.last
    last.maximum
  else
    0
  end
end

#sample(options = {}) ⇒ Object

Returns a randomly-chosen individual. The argument is a hash, empty by default. If it contains a value for the :random key, that value will be used as the random number generator instead of the default. This RNG will be sent a “rand” message with one argument, the sum of weights, and should return a number greater than or equal to zero and less than the sum of weights.



91
92
93
94
95
# File 'lib/loaded_die.rb', line 91

def sample(options = {})
  rng = options.fetch(:random) { DEFAULT_RNG }
  point = rng.rand(length)
  self[point]
end