Class: LoadedDie::Sampler
- Inherits:
-
Object
- Object
- LoadedDie::Sampler
- Defined in:
- lib/loaded_die.rb
Overview
Instances of this class can choose randomly from a set of options (called individuals here). The options can have different probabilities of being chosen.
Constant Summary collapse
- DEFAULT_RNG =
The default random number generator. It samples from a uniform distribution.
::Object.new
Instance Method Summary collapse
-
#[](point) ⇒ Object
Returns the individual associated with the given point on a line.
-
#initialize(population) ⇒ Sampler
constructor
Creates a sampler from a population.
-
#length ⇒ Object
Returns the sum of weights.
-
#sample(options = {}) ⇒ Object
Returns a randomly-chosen individual.
Constructor Details
#initialize(population) ⇒ Sampler
Creates a sampler from a population. The argument should return an enumerable (conventionally an instance of Enumerator) of arrays when sent a to_enum message with no arguments. (A normal instance of Hash qualifies.) Each array must have at least two elements: the first element is an individual that can be chosen and the second element is its weight – that is, the likelihood relative to the other weights that the individual will be chosen. Weights must convert to finite floats that are zero or positive.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/loaded_die.rb', line 33 def initialize population @compiled = population.to_enum.inject [] do |accum, elem| individual = elem.fetch 0 weight = elem.fetch 1 weight_f = ::Kernel.Float weight unless 0.0 <= weight_f && weight_f.finite? ::Kernel.raise ::ArgumentError, "invalid weight #{weight_f}" break end prev_max = if last = accum.last last.fetch :maximum else 0.0 end accum << { :maximum => prev_max + weight_f, :individual => individual } end nil end |
Instance Method Details
#[](point) ⇒ Object
Returns the individual associated with the given point on a line. The point should convert to a float. 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.
70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/loaded_die.rb', line 70 def [] point point_f = ::Kernel.Float point if 0.0 > point_f nil elsif choice = @compiled.detect { |segment| segment.fetch(:maximum) > point_f } choice.fetch :individual else nil end end |
#length ⇒ Object
Returns the sum of weights.
56 57 58 59 60 61 62 |
# File 'lib/loaded_die.rb', line 56 def length if last = @compiled.last last.fetch :maximum else 0.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 (convertible to a float) greater than or equal to zero and less than the sum of weights.
90 91 92 93 94 |
# File 'lib/loaded_die.rb', line 90 def sample = {} rng = .fetch(:random) { ::LoadedDie::Sampler::DEFAULT_RNG } point = rng.rand length self[point] end |