Class: SimpleRandom
- Inherits:
-
Object
show all
- Defined in:
- lib/simple-random/simple_random.rb
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 ⇒ 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.
-
#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.
2
3
4
5
|
# File 'lib/simple-random/simple_random.rb', line 2
def initialize
@m_w = 521288629
@m_z = 362436069
end
|
Instance Method Details
#beta(a, b) ⇒ Object
95
96
97
98
99
100
|
# File 'lib/simple-random/simple_random.rb', line 95
def beta(a, b)
raise "Alpha and beta parameters must be positive. Received a = #{a} and b = #{b}." unless a > 0 && b > 0
u = gamma(a, 1)
v = gamma(b, 1)
u / (u + v)
end
|
#cauchy(median, scale) ⇒ Object
108
109
110
111
112
|
# File 'lib/simple-random/simple_random.rb', line 108
def cauchy(median, scale)
raise 'Scale must be positive' if scale <= 0
median + scale * Math.tan(Math::PI * (uniform - 0.5))
end
|
#chi_square(degrees_of_freedom) ⇒ Object
87
88
89
|
# File 'lib/simple-random/simple_random.rb', line 87
def chi_square(degrees_of_freedom)
gamma(0.5 * degrees_of_freedom, 2.0)
end
|
#dirichlet(*parameters) ⇒ Object
129
130
131
132
133
|
# File 'lib/simple-random/simple_random.rb', line 129
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
41
42
43
44
|
# File 'lib/simple-random/simple_random.rb', line 41
def exponential(mean = 1)
raise 'Mean must be positive' if 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.
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
# File 'lib/simple-random/simple_random.rb', line 62
def gamma(shape, scale)
if shape >= 1.0
d = shape - 1.0 / 3.0
c = 1 / ((9 * d) ** 0.5)
while true
v = 0.0
while v <= 0.0
x = normal
v = 1.0 + c * x
end
v = v ** 3
u = uniform
if u < (1.0 - 0.0331 * (x ** 4)) || Math.log(u) < (0.5 * (x ** 2) + d * (1.0 - v + Math.log(v)))
return scale * d * v
end
end
elsif shape <= 0.0
raise 'Shape must be positive'
else
g = gamma(shape + 1.0, 1.0)
w = uniform
return scale * g * (w ** (1.0 / shape))
end
end
|
#inverse_gamma(shape, scale) ⇒ Object
91
92
93
|
# File 'lib/simple-random/simple_random.rb', line 91
def inverse_gamma(shape, scale)
1.0 / gamma(shape, 1.0 / scale)
end
|
#laplace(mean, scale) ⇒ Object
120
121
122
123
|
# File 'lib/simple-random/simple_random.rb', line 120
def laplace(mean, scale)
u = uniform
mean + Math.log(2) + ((u < 0.5 ? 1 : -1) * scale * Math.log(u < 0.5 ? u : 1 - u))
end
|
#log_normal(mu, sigma) ⇒ Object
125
126
127
|
# File 'lib/simple-random/simple_random.rb', line 125
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
35
36
37
38
|
# File 'lib/simple-random/simple_random.rb', line 35
def normal(mean = 0.0, standard_deviation = 1.0)
raise 'Invalid standard deviation' if standard_deviation <= 0
mean + standard_deviation * ((-2.0 * Math.log(uniform)) ** 0.5) * Math.sin(2.0 * Math::PI * uniform)
end
|
#set_seed(*args) ⇒ Object
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
# File 'lib/simple-random/simple_random.rb', line 7
def set_seed(*args)
if args.size > 1
@m_w = args.first.to_i if args.first.to_i != 0
@m_z = args.last.to_i if args.last.to_i != 0
elsif args.first.is_a?(Numeric)
@m_z = args.first.to_i if args.first.to_i != 0
elsif args.first.is_a?(Time)
x = (args.first.to_f * 1000000).to_i
@m_w = x >> 16
@m_z = x % 4294967296 else
x = (Time.now.to_f * 1000000).to_i
@m_w = x >> 16
@m_z = x % 4294967296 end
@m_w %= 4294967296
@m_z %= 4294967296
end
|
#student_t(degrees_of_freedom) ⇒ Object
114
115
116
117
118
|
# File 'lib/simple-random/simple_random.rb', line 114
def student_t(degrees_of_freedom)
raise 'Degrees of freedom must be positive' if 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
47
48
49
50
51
52
53
54
55
56
57
|
# File 'lib/simple-random/simple_random.rb', line 47
def triangular(lower, mode, upper)
raise 'Upper limit must be larger than lower limit' if upper < lower
raise 'Mode must lie between the upper and lower limits' if (mode < lower || mode > upper)
f_c = (mode - lower) / (upper - lower)
uniform_rand_num = uniform
if uniform_rand_num < f_c
lower + Math.sqrt(uniform_rand_num * (upper - lower) * (mode - lower))
else
upper - Math.sqrt((1 - uniform_rand_num) * (upper - lower) * (upper - mode))
end
end
|
Produce a uniform random sample from the open interval (lower, upper). The method will not return either end point.
29
30
31
32
|
# File 'lib/simple-random/simple_random.rb', line 29
def uniform(lower = 0, upper = 1)
raise 'Invalid range' if upper <= lower
((get_unsigned_int + 1) * (upper - lower) / 4294967296.0) + lower
end
|
#weibull(shape, scale) ⇒ Object
102
103
104
105
106
|
# File 'lib/simple-random/simple_random.rb', line 102
def weibull(shape, scale)
raise 'Shape and scale must be positive' if shape <= 0.0 || scale <= 0.0
scale * ((-Math.log(uniform)) ** (1.0 / shape))
end
|