random_variates 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +24 -13
- data/lib/random_variates.rb +33 -30
- metadata +28 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ae5af59fb1609e227a42bc3fe9b93f1cb0d561513526044de0f74bc95fe9040
|
4
|
+
data.tar.gz: 5a18534afb749cf8b0d829b64f1f67daec0809ee0669073872dcf477a24f4d99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a22d4223b928d7013deeb938fa497b231821d28939a75521b1e30f0bea1e20e95e8bb730c0a0dc8a2a0513b9174821abe36174a068dcc1cd81fafad941620af4
|
7
|
+
data.tar.gz: b4651ab9d4a17cb250a35a819658f92b6212c39f6cac9670ea3d069ab98e2335ea5b345e9ff138c7d642741a33441d0d29faa6c5eb41c545b65845bbf0257222
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
#### DESCRIPTION
|
2
2
|
|
3
3
|
This gem implements random variate generation for several
|
4
4
|
common statistical distributions. Each distribution is implemented
|
@@ -7,22 +7,33 @@ instances of the class using the constructor to specify the
|
|
7
7
|
parameterization. All constructors use named parameters for clarity,
|
8
8
|
so the order of parameters does not matter. All random variate classes
|
9
9
|
provide an optional argument `rng`, with which the user can specify a
|
10
|
-
|
11
|
-
|
10
|
+
pseudo-random number generator that has a `rand` method that provides
|
11
|
+
U(0,1) values to use as the core source of randomness.
|
12
|
+
If `rng` is not specified, it defaults to an instance of
|
13
|
+
class `Xoroshiro::Random`.
|
12
14
|
|
13
15
|
Once a random variate class has been instantiated, values can either be
|
14
|
-
generated on demand using the `next` method
|
15
|
-
|
16
|
+
generated on demand using the `next` method (preferred for speed) or by
|
17
|
+
creating an `Enumerator` for use in any iterable context. For example,
|
18
|
+
the following will create an array of fifty exponentially distributed
|
19
|
+
values having rate 3.
|
20
|
+
|
21
|
+
my_exp = RV::Exponential.new(rate: 3)
|
22
|
+
my_exp.each.take(50)
|
16
23
|
|
17
24
|
---
|
18
25
|
|
19
|
-
|
26
|
+
#### RELEASE NOTES
|
27
|
+
|
28
|
+
**v0.5**
|
20
29
|
|
21
|
-
|
22
|
-
|
30
|
+
Prior releases focused on statistical correctness and adding distributions. This
|
31
|
+
release is about speed improvements. Substantial speedups have been accomplished by:
|
23
32
|
|
24
|
-
|
25
|
-
-
|
26
|
-
|
27
|
-
-
|
28
|
-
|
33
|
+
- replacing the prior U(0,1) `Enumerator` architecture with direct calls to the PRNG;
|
34
|
+
- replacing `loop do` with the measurably faster `while true` in
|
35
|
+
acceptance/rejection based algorithms; and
|
36
|
+
- replacing ruby's built-in `Random` with `Xoroshiro::Random` as the default
|
37
|
+
PRNG. Xoshiro256** is faster than ruby's MT19937 implementation, and passes
|
38
|
+
all tests in the TestU01 suite. See [xoshiro / xoroshiro generators and the
|
39
|
+
PRNG shootout](https://prng.di.unimi.it) for more information.
|
data/lib/random_variates.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'xoroshiro'
|
4
|
+
|
3
5
|
# This library implements random variate generation for several
|
4
6
|
# common statistical distributions. Each distribution is implemented
|
5
7
|
# in its own class, and different parameterizations are created as
|
6
8
|
# instances of the class using the constructor to specify the
|
7
9
|
# parameterization. All constructors use named parameters for clarity,
|
8
10
|
# so the order of parameters does not matter. All RV classes provide an
|
9
|
-
# optional argument +rng+, with which the user can specify
|
10
|
-
#
|
11
|
+
# optional argument +rng+, with which the user can specify a U(0,1)
|
12
|
+
# PRNG object to use as the core source of randomness. If +rng+ is
|
11
13
|
# not specified, it defaults to +Kernel#rand+.
|
12
14
|
#
|
13
15
|
# Once a random variate class has been instantiated, values can either be
|
@@ -15,8 +17,8 @@
|
|
15
17
|
# a generator in any iterable context.
|
16
18
|
|
17
19
|
module RV
|
18
|
-
#
|
19
|
-
U_GENERATOR =
|
20
|
+
# Set default PRNG.
|
21
|
+
U_GENERATOR = Xoroshiro::Random.new
|
20
22
|
|
21
23
|
# The +RV_Generator+ module provides a common core of methods to make
|
22
24
|
# all of the RV classes iterable.
|
@@ -26,7 +28,11 @@ module RV
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def each
|
29
|
-
Enumerator.new
|
31
|
+
Enumerator.new do |y|
|
32
|
+
while true
|
33
|
+
y << self.next
|
34
|
+
end
|
35
|
+
end
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
@@ -40,18 +46,17 @@ module RV
|
|
40
46
|
class Uniform
|
41
47
|
include RV_Generator
|
42
48
|
|
43
|
-
attr_reader :min, :max
|
49
|
+
attr_reader :min, :max
|
44
50
|
|
45
51
|
def initialize(min: 0.0, max: 1.0, rng: U_GENERATOR)
|
46
|
-
raise 'Max must be greater than min.'
|
52
|
+
raise 'Max must be greater than min.' unless max > min
|
47
53
|
@min = min
|
48
54
|
@max = max
|
49
|
-
@range = max - min
|
50
55
|
@rng = rng
|
51
56
|
end
|
52
57
|
|
53
58
|
def next
|
54
|
-
@
|
59
|
+
@rng.rand(@min..@max)
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
@@ -110,7 +115,7 @@ module RV
|
|
110
115
|
end
|
111
116
|
|
112
117
|
def next
|
113
|
-
u = @rng.
|
118
|
+
u = @rng.rand
|
114
119
|
u < @crossover_p ?
|
115
120
|
@min + Math.sqrt(@range * (@mode - @min) * u) :
|
116
121
|
@max - Math.sqrt(@range * (@max - @mode) * (1.0 - u))
|
@@ -148,7 +153,7 @@ module RV
|
|
148
153
|
end
|
149
154
|
|
150
155
|
def next
|
151
|
-
-@mean * Math.log(@rng.
|
156
|
+
-@mean * Math.log(@rng.rand)
|
152
157
|
end
|
153
158
|
|
154
159
|
def rate=(rate)
|
@@ -189,10 +194,10 @@ module RV
|
|
189
194
|
end
|
190
195
|
|
191
196
|
def next
|
192
|
-
|
193
|
-
u = @rng.
|
197
|
+
while true
|
198
|
+
u = @rng.rand
|
194
199
|
next if u == 0.0
|
195
|
-
v = BOUND * (@rng.
|
200
|
+
v = BOUND * (@rng.rand - 0.5)
|
196
201
|
x = v / u
|
197
202
|
x_sqr = x * x
|
198
203
|
u_sqr = u * u
|
@@ -238,13 +243,12 @@ module RV
|
|
238
243
|
@sigma = sigma
|
239
244
|
@rng = rng
|
240
245
|
@need_new_pair = false
|
241
|
-
# @next_norm = 0.0
|
242
246
|
end
|
243
247
|
|
244
248
|
def next
|
245
249
|
if @need_new_pair ^= true
|
246
|
-
theta = TWO_PI * @rng.
|
247
|
-
d = @sigma * Math.sqrt(-2.0 * Math.log(@rng.
|
250
|
+
theta = TWO_PI * @rng.rand
|
251
|
+
d = @sigma * Math.sqrt(-2.0 * Math.log(@rng.rand))
|
248
252
|
@next_norm = @mu + d * Math.sin(theta)
|
249
253
|
@mu + d * Math.cos(theta)
|
250
254
|
else
|
@@ -297,21 +301,21 @@ module RV
|
|
297
301
|
z = v = 0.0
|
298
302
|
d = alpha - 1.0 / 3.0
|
299
303
|
c = (1.0 / 3.0) / Math.sqrt(d)
|
300
|
-
|
301
|
-
|
304
|
+
while true
|
305
|
+
while true
|
302
306
|
z = @std_normal.next
|
303
307
|
v = 1.0 + c * z
|
304
308
|
break if v > 0
|
305
309
|
end
|
306
310
|
z2 = z * z
|
307
311
|
v = v * v * v
|
308
|
-
u = @rng.
|
312
|
+
u = @rng.rand
|
309
313
|
break if u < 1.0 - 0.0331 * z2 * z2
|
310
314
|
break if Math.log(u) < (0.5 * z2 + d * (1.0 - v + Math.log(v)))
|
311
315
|
end
|
312
316
|
d * v * beta
|
313
317
|
else
|
314
|
-
__gen__(alpha + 1.0, beta) * (@rng.
|
318
|
+
__gen__(alpha + 1.0, beta) * (@rng.rand**(1.0 / alpha))
|
315
319
|
end
|
316
320
|
end
|
317
321
|
end
|
@@ -338,7 +342,7 @@ module RV
|
|
338
342
|
end
|
339
343
|
|
340
344
|
def next
|
341
|
-
(-Math.log(@rng.
|
345
|
+
(-Math.log(@rng.rand))**@power / @rate
|
342
346
|
end
|
343
347
|
end
|
344
348
|
|
@@ -381,9 +385,9 @@ module RV
|
|
381
385
|
end
|
382
386
|
|
383
387
|
def next
|
384
|
-
|
385
|
-
r1 = @rng.
|
386
|
-
theta = @s * (2.0 * @rng.
|
388
|
+
while true
|
389
|
+
r1 = @rng.rand
|
390
|
+
theta = @s * (2.0 * @rng.rand - 1.0) / r1
|
387
391
|
next if theta.abs > Math::PI
|
388
392
|
return theta if (0.25 * @kappa * theta * theta < 1.0 - r1) ||
|
389
393
|
(0.5 * @kappa * (Math.cos(theta) - 1.0) >= Math.log(r1))
|
@@ -420,7 +424,7 @@ module RV
|
|
420
424
|
def next
|
421
425
|
count = 0
|
422
426
|
product = 1.0
|
423
|
-
count += 1 until (product *= @rng.
|
427
|
+
count += 1 until (product *= @rng.rand) < @threshold
|
424
428
|
count
|
425
429
|
end
|
426
430
|
end
|
@@ -439,13 +443,12 @@ module RV
|
|
439
443
|
def initialize(p: 0.5, rng: U_GENERATOR)
|
440
444
|
raise 'Require 0 < p < 1.' if p <= 0 || p >= 1
|
441
445
|
|
442
|
-
@p = p
|
443
446
|
@log_q = Math.log(1 - p)
|
444
447
|
@rng = rng
|
445
448
|
end
|
446
449
|
|
447
450
|
def next
|
448
|
-
(Math.log(1.0 - @rng.
|
451
|
+
(Math.log(1.0 - @rng.rand) / @log_q).ceil
|
449
452
|
end
|
450
453
|
end
|
451
454
|
|
@@ -480,8 +483,8 @@ module RV
|
|
480
483
|
|
481
484
|
def next
|
482
485
|
result = sum = 0
|
483
|
-
|
484
|
-
sum += Math.log(@rng.
|
486
|
+
while true
|
487
|
+
sum += Math.log(@rng.rand) / (@n - result)
|
485
488
|
break if sum < @log_q
|
486
489
|
result += 1
|
487
490
|
end
|
metadata
CHANGED
@@ -1,16 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: random_variates
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul J Sanchez
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2023-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: xoroshiro
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.2'
|
27
|
+
description: Random variate generators implemented with Enumerator.
|
14
28
|
email: pjs@alum.mit.edu
|
15
29
|
executables: []
|
16
30
|
extensions: []
|
@@ -22,8 +36,11 @@ files:
|
|
22
36
|
homepage: https://bitbucket.org/paul_j_sanchez/random_variates.git
|
23
37
|
licenses:
|
24
38
|
- MIT
|
25
|
-
metadata:
|
26
|
-
|
39
|
+
metadata:
|
40
|
+
rubygems_mfa_required: 'true'
|
41
|
+
homepage_uri: https://bitbucket.org/paul_j_sanchez/random_variates.git
|
42
|
+
documentation_uri: https://rubydoc.info/gems/random_variates
|
43
|
+
post_install_message:
|
27
44
|
rdoc_options: []
|
28
45
|
require_paths:
|
29
46
|
- lib
|
@@ -31,15 +48,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
31
48
|
requirements:
|
32
49
|
- - ">="
|
33
50
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
51
|
+
version: '3.0'
|
35
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
53
|
requirements:
|
37
54
|
- - ">="
|
38
55
|
- !ruby/object:Gem::Version
|
39
56
|
version: '0'
|
40
57
|
requirements: []
|
41
|
-
rubygems_version: 3.
|
42
|
-
signing_key:
|
58
|
+
rubygems_version: 3.4.13
|
59
|
+
signing_key:
|
43
60
|
specification_version: 4
|
44
|
-
summary: Random variate generator classes.
|
61
|
+
summary: Random variate generator classes for popular distributions.
|
45
62
|
test_files: []
|