Class: SimpleRandom
- Inherits:
-
Object
show all
- Defined in:
- lib/simple-random/simple_random.rb
Defined Under Namespace
Classes: InvalidSeedArgument
Constant Summary
collapse
- I_32_BIT =
4294967296
- F_32_BIT =
4294967296.0
- DEFAULT_SEEDS =
[521288629, 362436069]
Instance Method Summary
collapse
-
#beta(a, b) ⇒ Object
-
#cauchy(median, scale) ⇒ Object
-
#chi_square(degrees_of_freedom) ⇒ Object
-
#dirichlet(*parameters) ⇒ Object
-
#exponential(mean = 1) ⇒ Object
Get exponential random sample with specified mean.
-
#gamma(shape, scale) ⇒ Object
Implementation based on “A Simple Method for Generating Gamma Variables” by George Marsaglia and Wai Wan Tsang.
-
#initialize(*args) ⇒ SimpleRandom
constructor
A new instance of SimpleRandom.
-
#inverse_gamma(shape, scale) ⇒ Object
-
#laplace(mean, scale) ⇒ Object
-
#log_normal(mu, sigma) ⇒ Object
-
#normal(mean = 0.0, standard_deviation = 1.0) ⇒ Object
Sample normal distribution with given mean and standard deviation.
-
#seeds ⇒ Object
-
#seeds=(value) ⇒ Object
-
#set_seed(*args) ⇒ Object
-
#student_t(degrees_of_freedom) ⇒ Object
-
#triangular(lower, mode, upper) ⇒ Object
Get triangular random sample with specified lower limit, mode, upper limit.
-
#uniform(lower = 0, upper = 1) ⇒ Object
Produce a uniform random sample from the open interval (lower, upper).
-
#weibull(shape, scale) ⇒ Object
Constructor Details
Returns a new instance of SimpleRandom.
8
9
10
11
12
13
14
|
# File 'lib/simple-random/simple_random.rb', line 8
def initialize(*args)
if args.empty?
set_seed(*DEFAULT_SEEDS)
else
set_seed(*args)
end
end
|
Instance Method Details
#beta(a, b) ⇒ Object
102
103
104
105
106
107
|
# File 'lib/simple-random/simple_random.rb', line 102
def beta(a, b)
fail ArgumentError, "Parameters must be strictly positive" unless a > 0 && b > 0
u = gamma(a, 1)
v = gamma(b, 1)
u / (u + v)
end
|
#cauchy(median, scale) ⇒ Object
115
116
117
118
119
|
# File 'lib/simple-random/simple_random.rb', line 115
def cauchy(median, scale)
fail ArgumentError, 'Scale must be positive' unless scale > 0
median + scale * Math.tan(Math::PI * (uniform - 0.5))
end
|
#chi_square(degrees_of_freedom) ⇒ Object
94
95
96
|
# File 'lib/simple-random/simple_random.rb', line 94
def chi_square(degrees_of_freedom)
gamma(0.5 * degrees_of_freedom, 2.0)
end
|
#dirichlet(*parameters) ⇒ Object
139
140
141
142
143
|
# File 'lib/simple-random/simple_random.rb', line 139
def dirichlet(*parameters)
sample = parameters.map { |a| gamma(a, 1) }
sum = sample.inject(0.0) { |sum, g| sum + g }
sample.map { |g| g / sum }
end
|
#exponential(mean = 1) ⇒ Object
Get exponential random sample with specified mean
47
48
49
50
51
|
# File 'lib/simple-random/simple_random.rb', line 47
def exponential(mean = 1)
fail ArgumentError, "Mean must be strictly positive" unless mean > 0
-1.0 * mean * Math.log(uniform)
end
|
#gamma(shape, scale) ⇒ Object
Implementation based on “A Simple Method for Generating Gamma Variables” by George Marsaglia and Wai Wan Tsang. ACM Transactions on Mathematical Software Vol 26, No 3, September 2000, pages 363-372.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# File 'lib/simple-random/simple_random.rb', line 71
def gamma(shape, scale)
fail ArgumentError, 'Shape must be strictly positive' unless shape > 0
return scale * gamma(shape + 1.0, 1.0) * uniform ** -shape if shape < 1
d = shape - 1 / 3.0
c = (9 * d) ** -0.5
begin
z = normal
condition1 = z > (-1.0 / c)
condition2 = false
if condition1
u = uniform
v = (1 + c * z) ** 3
condition2 = Math.log(u) < (0.5 * (z ** 2) + d * (1.0 - v + Math.log(v)))
end
end while !condition2
scale * d * v
end
|
#inverse_gamma(shape, scale) ⇒ Object
98
99
100
|
# File 'lib/simple-random/simple_random.rb', line 98
def inverse_gamma(shape, scale)
1.0 / gamma(shape, 1.0 / scale)
end
|
#laplace(mean, scale) ⇒ Object
127
128
129
130
131
132
133
|
# File 'lib/simple-random/simple_random.rb', line 127
def laplace(mean, scale)
u_1 = uniform(-0.5, 0.5)
u_2 = uniform
sign = u_1 / u_1.abs
mean + sign * scale * Math.log(1 - u_2)
end
|
#log_normal(mu, sigma) ⇒ Object
135
136
137
|
# File 'lib/simple-random/simple_random.rb', line 135
def log_normal(mu, sigma)
Math.exp(normal(mu, sigma))
end
|
#normal(mean = 0.0, standard_deviation = 1.0) ⇒ Object
Sample normal distribution with given mean and standard deviation
40
41
42
43
44
|
# File 'lib/simple-random/simple_random.rb', line 40
def normal(mean = 0.0, standard_deviation = 1.0)
fail ArgumentError, 'Standard deviation must be strictly positive' unless standard_deviation > 0
mean + standard_deviation * ((-2.0 * Math.log(uniform)) ** 0.5) * Math.sin(2.0 * Math::PI * uniform)
end
|
#seeds ⇒ Object
28
29
30
|
# File 'lib/simple-random/simple_random.rb', line 28
def seeds
[@m_w, @m_z]
end
|
#seeds=(value) ⇒ Object
24
25
26
|
# File 'lib/simple-random/simple_random.rb', line 24
def seeds=(value)
set_seed(*[value].flatten.compact)
end
|
#set_seed(*args) ⇒ Object
16
17
18
19
20
21
22
|
# File 'lib/simple-random/simple_random.rb', line 16
def set_seed(*args)
validate_seeds!(*args)
@m_w, @m_z = determine_seeds(*args)
ensure_32bit_seeds!
end
|
#student_t(degrees_of_freedom) ⇒ Object
121
122
123
124
125
|
# File 'lib/simple-random/simple_random.rb', line 121
def student_t(degrees_of_freedom)
fail ArgumentError, 'Degrees of freedom must be strictly positive' unless degrees_of_freedom > 0
normal / ((chi_square(degrees_of_freedom) / degrees_of_freedom) ** 0.5)
end
|
#triangular(lower, mode, upper) ⇒ Object
Get triangular random sample with specified lower limit, mode, upper limit
54
55
56
57
58
59
60
61
62
63
64
65
66
|
# File 'lib/simple-random/simple_random.rb', line 54
def triangular(lower, mode, upper)
fail ArgumentError, 'Upper bound must be greater than lower bound.' unless lower < upper
fail ArgumentError, 'Mode must lie between the upper and lower limits' if mode > upper || mode < lower
r = (upper - lower).to_f
u = uniform
if u < ((mode - lower) / r)
lower + Math.sqrt(u * r * (mode - lower))
else
upper - Math.sqrt((1.0 - u) * r * (upper - mode))
end
end
|
Produce a uniform random sample from the open interval (lower, upper).
33
34
35
36
37
|
# File 'lib/simple-random/simple_random.rb', line 33
def uniform(lower = 0, upper = 1)
fail ArgumentError, 'Upper bound must be greater than lower bound.' unless lower < upper
((get_unsigned_int + 1) * (upper - lower) / F_32_BIT) + lower
end
|
#weibull(shape, scale) ⇒ Object
109
110
111
112
113
|
# File 'lib/simple-random/simple_random.rb', line 109
def weibull(shape, scale)
fail ArgumentError, 'Shape and scale must be positive' unless shape > 0 && scale > 0
scale * ((-Math.log(uniform)) ** (1.0 / shape))
end
|