Class: Triangle

Inherits:
Object
  • Object
show all
Includes:
RV_Generator
Defined in:
lib/random_variates.rb

Overview

Triangular random variate generator with specified min, mode, and max.

Arguments
  • rng -> the (Enumerable) source of U(0, 1)‘s (default: U_GENERATOR)

  • min -> the lower bound for the range.

  • max -> the upper bound for the range.

  • mode -> the highest likelihood value (minmodemax).

  • mean -> the expected value of the distribution.

Instance Attribute Summary collapse

Attributes included from RV_Generator

#generator

Instance Method Summary collapse

Methods included from RV_Generator

#each, #next

Constructor Details

#initialize(rng: U_GENERATOR, **args) ⇒ Triangle



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/random_variates.rb', line 74

def initialize(rng: U_GENERATOR, **args)
  param_names = %i[mean min max mode]
  unless args.size > 2 && args.keys.all? { |k| param_names.include? k }
    raise "invalid args - can only be #{param_names.join ', '}, or rng."
  end

  param_names.each { |k| args[k] ||= nil } if args.size < param_names.size

  nil_args = args.select { |_, v| v.nil? }.keys
  nil_args_count = nil_args.count
  raise 'too many nil args' if nil_args_count > 1

  args.transform_values! &:to_f

  if nil_args_count == 0
    if args[:mean] != (args[:min] + args[:max] + args[:mode]) / 3.0
      raise 'inconsistent args'
    end
  else
    key = nil_args.shift
    case key
    when :mean
      args[key] = (args[:min] + args[:max] + args[:mode]) / 3.0
    else
      others = param_names - [key, :mean]
      args[key] = 3 * args[:mean] - args.values_at(*others).sum
    end
  end

  param_names.each { |parm| instance_variable_set("@#{parm}", args[parm]) }

  @range = @max - @min
  raise 'Min must be less than Max.' if @range <= 0
  raise 'Mode must be between Min and Max.' unless (@min..@max).include? @mode

  crossover_p = (@mode - @min).to_f / @range
  @generator = Enumerator.new do |yielder|
    loop do
      u = rng.next
      yielder << (
        u < crossover_p ?
          @min + Math.sqrt(@range * (@mode - @min) * u) :
          @max - Math.sqrt(@range * (@max - @mode) * (1.0 - u))
      )
    end
  end
end

Instance Attribute Details

#maxObject (readonly)

Returns the value of attribute max.



72
73
74
# File 'lib/random_variates.rb', line 72

def max
  @max
end

#meanObject (readonly)

Returns the value of attribute mean.



72
73
74
# File 'lib/random_variates.rb', line 72

def mean
  @mean
end

#minObject (readonly)

Returns the value of attribute min.



72
73
74
# File 'lib/random_variates.rb', line 72

def min
  @min
end

#modeObject (readonly)

Returns the value of attribute mode.



72
73
74
# File 'lib/random_variates.rb', line 72

def mode
  @mode
end

#rangeObject (readonly)

Returns the value of attribute range.



72
73
74
# File 'lib/random_variates.rb', line 72

def range
  @range
end