random 0.2.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.
- data/LICENSE +32 -0
- data/README +83 -0
- data/Rakefile +247 -0
- data/TODO +4 -0
- data/VERSION +1 -0
- data/doc/simple_example.rb +17 -0
- data/ext/random/extconf.rb +9 -0
- data/ext/random/mersenne_twister_ext.c +465 -0
- data/lib/math/statistics/chi_square.rb +76 -0
- data/lib/math/statistics/table_chi_square_probabilities.html +472 -0
- data/lib/random.rb +7 -0
- data/lib/random/array_random_element.rb +6 -0
- data/lib/random/random_number_generator.rb +196 -0
- data/lib/random/testing.rb +35 -0
- data/test/acceptance/wagner_distribution_1_0/testWagner.out +625 -0
- data/test/acceptance/wagner_distribution_1_0/test_compare_to_wagners_test_output.rb +91 -0
- data/test/performance/test_mersenne_twister.rb +20 -0
- data/test/unit/#mt19937ar.c# +190 -0
- data/test/unit/expected_mersenne_4357.txt +200 -0
- data/test/unit/test_chi_square.rb +25 -0
- data/test/unit/test_mersenne_twister.rb +131 -0
- data/test/unit/test_random_number_generator.rb +168 -0
- data/test/unit/test_random_testing.rb +22 -0
- data/test/unit/test_rng.rb +9 -0
- metadata +71 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'math/statistics/chi_square'
|
4
|
+
|
5
|
+
class TestChiSquare < Test::Unit::TestCase
|
6
|
+
def test_01_ensure_proper_parsing_of_file
|
7
|
+
assert_equal(nil, Math::Statistics.critical_chi_square_value(1, 0.995))
|
8
|
+
assert_equal(nil, Math::Statistics.critical_chi_square_value(1, 0.99))
|
9
|
+
assert_equal(0.001, Math::Statistics.critical_chi_square_value(1, 0.975))
|
10
|
+
assert_equal(6.635, Math::Statistics.critical_chi_square_value(1, 0.01))
|
11
|
+
assert_equal(7.879, Math::Statistics.critical_chi_square_value(1, 0.005))
|
12
|
+
|
13
|
+
assert_equal(0.010, Math::Statistics.critical_chi_square_value(2, 0.995))
|
14
|
+
assert_equal(0.020, Math::Statistics.critical_chi_square_value(2, 0.99))
|
15
|
+
assert_equal(5.991, Math::Statistics.critical_chi_square_value(2, 0.05))
|
16
|
+
assert_equal(10.597, Math::Statistics.critical_chi_square_value(2, 0.005))
|
17
|
+
|
18
|
+
assert_equal(8.907, Math::Statistics.critical_chi_square_value(19, 0.975))
|
19
|
+
assert_equal(38.582, Math::Statistics.critical_chi_square_value(19, 0.005))
|
20
|
+
|
21
|
+
assert_equal(104.215, Math::Statistics.critical_chi_square_value(70, 0.005))
|
22
|
+
|
23
|
+
assert_equal(67.328, Math::Statistics.critical_chi_square_value(100, 0.995))
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'random'
|
4
|
+
include Random
|
5
|
+
|
6
|
+
class TestMersenneTwister < Test::Unit::TestCase
|
7
|
+
NumReps = 30
|
8
|
+
NumSmallReps = NumReps / 10
|
9
|
+
|
10
|
+
def test_01_initialize
|
11
|
+
mt1 = MersenneTwister.new
|
12
|
+
assert_kind_of(Random::MersenneTwister, mt)
|
13
|
+
assert_equal(0, mt.min)
|
14
|
+
assert_equal(-1 + 2**32, mt.max)
|
15
|
+
|
16
|
+
# Lets just check that we do not get the same value multiple times
|
17
|
+
# (which happens if the state has not been initialized for example)
|
18
|
+
first_10 = Array.new(10).map {mt1.next}
|
19
|
+
assert(10 == first_10.uniq.length,
|
20
|
+
"First 10 generated nums: #{first_10.inspect}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup
|
24
|
+
@mt = MersenneTwister.new(rand(1e4))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Default test object
|
28
|
+
def mt; @mt; end
|
29
|
+
|
30
|
+
def test_02_rand_int_limited
|
31
|
+
NumSmallReps.times do
|
32
|
+
assert_chi_square {mt.rand_int_limited(10)}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def take_next(num, rng)
|
37
|
+
Array.new(num).map {rng.next}
|
38
|
+
end
|
39
|
+
|
40
|
+
def assert_next(num, mt1, mt2)
|
41
|
+
assert_equal(take_next(num, mt1), take_next(num, mt2))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_03_same_seed_gives_same_sequence
|
45
|
+
NumReps.times do
|
46
|
+
seed = rand(1e6)
|
47
|
+
mt1, mt2 = MersenneTwister.new(seed), MersenneTwister.new(seed)
|
48
|
+
assert_next(1000, mt1, mt2)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_04_different_seed_gives_different_sequence
|
53
|
+
NumReps.times do
|
54
|
+
seed = rand(1e6)
|
55
|
+
mt1 = MersenneTwister.new(seed)
|
56
|
+
mt2 = MersenneTwister.new(seed+1+rand(1e3))
|
57
|
+
assert(take_next(100, mt1) != take_next(100, mt2))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_05_rand_float
|
62
|
+
NumSmallReps.times do
|
63
|
+
assert_chi_square {(10.0 * mt.rand_float).floor}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_06_rand_without_arg
|
68
|
+
NumSmallReps.times do
|
69
|
+
assert_chi_square do
|
70
|
+
rv = mt.rand()
|
71
|
+
assert_kind_of(Float, rv)
|
72
|
+
(10.0 * rv).floor
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_07_rand_with_small_int_arg
|
78
|
+
NumSmallReps.times do
|
79
|
+
df = Math::Statistics.valid_degrees_of_freedom.random_element
|
80
|
+
limit = df + 1
|
81
|
+
assert_chi_square do
|
82
|
+
rv = mt.rand(limit)
|
83
|
+
assert(rv.kind_of?(Fixnum) && rv >= 0 && rv < limit)
|
84
|
+
rv
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_08_state
|
90
|
+
NumReps.times do
|
91
|
+
s = mt.state
|
92
|
+
assert_kind_of(Array, s)
|
93
|
+
assert_equal(624+1, s.length)
|
94
|
+
s.each {|e| assert(Integer === e)}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_09_state_set
|
99
|
+
NumReps.times do
|
100
|
+
mt1 = MersenneTwister.new(rand(1e6))
|
101
|
+
state_taken_at = rand(1e3)
|
102
|
+
state_taken_at.times {mt1.next}
|
103
|
+
state = mt1.state
|
104
|
+
assert_kind_of(Array, state)
|
105
|
+
assert_equal(624+1, state.length)
|
106
|
+
mt2 = MersenneTwister.new(rand(1e6))
|
107
|
+
mt2.state = state
|
108
|
+
assert_equal(mt1.state, mt2.state)
|
109
|
+
assert_equal(state, mt1.state)
|
110
|
+
assert_next(1000, mt1, mt2)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_10_marshaling
|
115
|
+
NumReps.times do
|
116
|
+
mt1 = MersenneTwister.new(rand(1e6))
|
117
|
+
state_taken_at = rand(1e3)
|
118
|
+
state_taken_at.times {mt1.next}
|
119
|
+
mstr1 = Marshal.dump(mt1)
|
120
|
+
mt2 = Marshal.load(mstr1)
|
121
|
+
assert_next(1000, mt1, mt2)
|
122
|
+
assert_equal(Marshal.dump(mt1), Marshal.dump(mt2))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_11_rand
|
127
|
+
assert_rand(mt)
|
128
|
+
assert_chi_square {mt.rand(2)}
|
129
|
+
assert_chi_square_floats {mt.rand}
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'random/random_number_generator'
|
4
|
+
include Random
|
5
|
+
|
6
|
+
# Mock sub-class that implements next simply by taking values from an array.
|
7
|
+
class MockRNG < Random::RandomNumberGenerator
|
8
|
+
def initialize(*values)
|
9
|
+
@values, @len = values, values.length
|
10
|
+
@index = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def next
|
14
|
+
n = @values[@index]
|
15
|
+
@index = (@index + 1) % @len
|
16
|
+
n
|
17
|
+
end
|
18
|
+
|
19
|
+
def marshal_dump; [@values, @index]; end
|
20
|
+
def marshal_load(ary)
|
21
|
+
@values, @index = ary
|
22
|
+
@len = @values.length
|
23
|
+
end
|
24
|
+
|
25
|
+
# Lift protected methods so we can test them
|
26
|
+
public :calc_mask, :mask, :num_bits_to_represent, :mask_for_int, :add_bits
|
27
|
+
end
|
28
|
+
|
29
|
+
class TestRandomNumberGenerator < Test::Unit::TestCase
|
30
|
+
NumReps = 30
|
31
|
+
NumSmallReps = NumReps / 10
|
32
|
+
|
33
|
+
attr_reader :rng
|
34
|
+
|
35
|
+
def setup
|
36
|
+
@rng = MockRNG.new(*(0..1000))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_01_initialize
|
40
|
+
assert_kind_of(MockRNG, rng)
|
41
|
+
assert_equal(0, rng.min)
|
42
|
+
assert_equal(2**32-1, rng.max)
|
43
|
+
assert_equal(32, rng.num_random_bits)
|
44
|
+
assert_equal(4, rng.num_random_bytes)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_02_calc_mask
|
48
|
+
assert_equal(0b0000, rng.calc_mask(0))
|
49
|
+
assert_equal(0b0001, rng.calc_mask(1))
|
50
|
+
assert_equal(0b0011, rng.calc_mask(2))
|
51
|
+
assert_equal(0b0111, rng.calc_mask(3))
|
52
|
+
assert_equal(0b1111, rng.calc_mask(4))
|
53
|
+
assert_equal(0x1f, rng.calc_mask(5))
|
54
|
+
assert_equal(0x3f, rng.calc_mask(6))
|
55
|
+
assert_equal(0x7f, rng.calc_mask(7))
|
56
|
+
assert_equal(0xff, rng.calc_mask(8))
|
57
|
+
(9..65).each {|i| assert_equal(2**i - 1, rng.calc_mask(i))}
|
58
|
+
assert_equal(2**1000 - 1, rng.calc_mask(1000))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_03_mask
|
62
|
+
assert_equal(0b0000, rng.mask(0))
|
63
|
+
assert_equal(0b0001, rng.mask(1))
|
64
|
+
assert_equal(0b0011, rng.mask(2))
|
65
|
+
assert_equal(0b0111, rng.mask(3))
|
66
|
+
assert_equal(0b1111, rng.mask(4))
|
67
|
+
assert_equal(0x1f, rng.mask(5))
|
68
|
+
assert_equal(0x3f, rng.mask(6))
|
69
|
+
assert_equal(0x7f, rng.mask(7))
|
70
|
+
assert_equal(0xff, rng.mask(8))
|
71
|
+
(9..65).each {|i| assert_equal(2**i - 1, rng.mask(i))}
|
72
|
+
assert_equal(2**1000 - 1, rng.mask(1000))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_04_num_bits
|
76
|
+
(0..1).each {|i| assert_equal(1, rng.num_bits_to_represent(i))}
|
77
|
+
(2..3).each {|i| assert_equal(2, rng.num_bits_to_represent(i))}
|
78
|
+
(4..7).each {|i| assert_equal(3, rng.num_bits_to_represent(i))}
|
79
|
+
(8..15).each {|i| assert_equal(4, rng.num_bits_to_represent(i))}
|
80
|
+
(16..31).each {|i| assert_equal(5, rng.num_bits_to_represent(i))}
|
81
|
+
(32..63).each {|i| assert_equal(6, rng.num_bits_to_represent(i))}
|
82
|
+
assert_equal(7, rng.num_bits_to_represent(64))
|
83
|
+
assert_equal(8, rng.num_bits_to_represent(128))
|
84
|
+
assert_equal(1023, rng.num_bits_to_represent(2**1023-1))
|
85
|
+
assert_equal(1024, rng.num_bits_to_represent(2**1023))
|
86
|
+
assert_equal(1025, rng.num_bits_to_represent(2**1024))
|
87
|
+
assert_equal(2048, rng.num_bits_to_represent(2**2048-1))
|
88
|
+
assert_equal(2049, rng.num_bits_to_represent(2**2048))
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_05_mask_for_int
|
92
|
+
assert_equal(0x0001, rng.mask_for_int(0))
|
93
|
+
assert_equal(0x0001, rng.mask_for_int(1))
|
94
|
+
assert_equal(0x0003, rng.mask_for_int(2))
|
95
|
+
assert_equal(0x0003, rng.mask_for_int(3))
|
96
|
+
assert_equal(0x0007, rng.mask_for_int(7))
|
97
|
+
assert_equal(0x000f, rng.mask_for_int(13))
|
98
|
+
end
|
99
|
+
|
100
|
+
def collect_samples(numSamples = 1e4, &block)
|
101
|
+
counts = Hash.new(0)
|
102
|
+
numSamples.to_i.times {counts[block.call] += 1}
|
103
|
+
counts
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_06_rand_int_limited
|
107
|
+
samples = collect_samples {rng.rand_int_limited(0)}
|
108
|
+
assert_equal((0..0).to_a, samples.keys.sort)
|
109
|
+
|
110
|
+
samples = collect_samples {rng.rand_int_limited(1)}
|
111
|
+
assert_equal((0..1).to_a, samples.keys.sort)
|
112
|
+
|
113
|
+
samples = collect_samples {rng.rand_int_limited(10)}
|
114
|
+
assert_equal((0..10).to_a, samples.keys.sort)
|
115
|
+
|
116
|
+
samples = collect_samples {rng.rand_int_limited(30)}
|
117
|
+
assert_equal((0..30).to_a, samples.keys.sort)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_07_rand_num
|
121
|
+
samples = collect_samples {rng.rand_num(7, 7)}
|
122
|
+
assert_equal((7..7).to_a, samples.keys.sort)
|
123
|
+
|
124
|
+
samples = collect_samples {rng.rand_num(32, 34)}
|
125
|
+
assert_equal((32..34).to_a, samples.keys.sort)
|
126
|
+
|
127
|
+
samples = collect_samples {rng.rand_num(1, 6)}
|
128
|
+
assert_equal((1..6).to_a, samples.keys.sort)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_08_rand_bytes
|
132
|
+
rng = MockRNG.new(0x01020304, 0x050607ff)
|
133
|
+
assert_equal(4.chr, rng.rand_bytes(1))
|
134
|
+
assert_equal(0xff.chr + 7.chr, rng.rand_bytes(2))
|
135
|
+
assert_equal(4.chr + 3.chr + 2.chr, rng.rand_bytes(3))
|
136
|
+
assert_equal(0xff.chr + 7.chr + 6.chr + 5.chr, rng.rand_bytes(4))
|
137
|
+
assert_equal(4.chr + 3.chr + 2.chr + 1.chr + 0xff.chr, rng.rand_bytes(5))
|
138
|
+
|
139
|
+
assert_equal(4.chr + 3.chr + 2.chr + 1.chr + 0xff.chr + 7.chr,
|
140
|
+
rng.rand_bytes(6))
|
141
|
+
assert_equal(4.chr + 3.chr + 2.chr + 1.chr + 0xff.chr + 7.chr + 6.chr,
|
142
|
+
rng.rand_bytes(7))
|
143
|
+
assert_equal(4.chr + 3.chr + 2.chr + 1.chr +
|
144
|
+
0xff.chr + 7.chr + 6.chr + 5.chr,
|
145
|
+
rng.rand_bytes(8))
|
146
|
+
assert_equal(4.chr + 3.chr + 2.chr + 1.chr +
|
147
|
+
0xff.chr + 7.chr + 6.chr + 5.chr +
|
148
|
+
4.chr,
|
149
|
+
rng.rand_bytes(9))
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_09_add_bits
|
153
|
+
assert_equal(0, rng.add_bits(0, 0, 1))
|
154
|
+
assert_equal(1, rng.add_bits(0, 1, 1))
|
155
|
+
assert_equal(2, rng.add_bits(0, 2, 2))
|
156
|
+
assert_equal(3, rng.add_bits(0, 2, 3))
|
157
|
+
assert_equal(7, rng.add_bits(1, 2, 3))
|
158
|
+
assert_equal(3, rng.add_bits(0, 2, 7))
|
159
|
+
assert_equal(10, rng.add_bits(5, 1, 2))
|
160
|
+
assert_equal(0xffff, rng.add_bits(1, 15, 0xffff))
|
161
|
+
assert_equal(0xfff, rng.add_bits(0, 12, 0xffff))
|
162
|
+
assert_equal(-1 + 2**64, rng.add_bits(3, 62, -1 + 2**64))
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_10_rand
|
166
|
+
assert_rand(rng)
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'random/testing'
|
4
|
+
include Random
|
5
|
+
|
6
|
+
class TestRandomTesting < Test::Unit::TestCase
|
7
|
+
def test_01_totally_uniform_should_easily_pass
|
8
|
+
assert(Testing.chi_square_test({0 => 5000, 1 => 5000}, 0.1))
|
9
|
+
assert(Testing.chi_square_test({0 => 2500, 1 => 2500,
|
10
|
+
2 => 2500, 3 => 2500}, 0.1))
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert_false(v)
|
14
|
+
assert(v ? false : true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_02_totally_nonuniform_should_fail
|
18
|
+
assert_false(Testing.chi_square_test({0 => 0, 1 => 10000}, 0.005))
|
19
|
+
assert_false(Testing.chi_square_test({0 => 10, 1 => 10,
|
20
|
+
2 => 9970, 3 => 10}, 0.005))
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: random
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2006-04-13 00:00:00 +02:00
|
8
|
+
summary: Stand-alone random number generator (RNG) class allowing multiple, active RNG's at the same time (which is not possible with Ruby's rand/srand).
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
- ext
|
12
|
+
- lib
|
13
|
+
email: Robert.Feldt@gmail.com
|
14
|
+
homepage: http://www.rubyforge.org/projects/random
|
15
|
+
rubyforge_project:
|
16
|
+
description: A Mersenne-Twister random number generator (RNG) packed up as a class. This allows multiple RNG streams to be active at the same time (which Ruby's normal rand/srand does not allow). The Mersenne-Twister is implemented with fast C code for speed.
|
17
|
+
autorequire:
|
18
|
+
default_executable:
|
19
|
+
bindir: bin
|
20
|
+
has_rdoc: false
|
21
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.0.0
|
26
|
+
version:
|
27
|
+
platform: ruby
|
28
|
+
signing_key:
|
29
|
+
cert_chain:
|
30
|
+
authors:
|
31
|
+
- Robert Feldt
|
32
|
+
files:
|
33
|
+
- README
|
34
|
+
- TODO
|
35
|
+
- LICENSE
|
36
|
+
- VERSION
|
37
|
+
- Rakefile
|
38
|
+
- ext/random/mersenne_twister_ext.c
|
39
|
+
- ext/random/extconf.rb
|
40
|
+
- lib/random.rb
|
41
|
+
- lib/random/array_random_element.rb
|
42
|
+
- lib/random/random_number_generator.rb
|
43
|
+
- lib/random/testing.rb
|
44
|
+
- lib/math/statistics/chi_square.rb
|
45
|
+
- lib/math/statistics/table_chi_square_probabilities.html
|
46
|
+
- doc/simple_example.rb
|
47
|
+
- test/acceptance/wagner_distribution_1_0
|
48
|
+
- test/acceptance/wagner_distribution_1_0/testWagner.out
|
49
|
+
- test/acceptance/wagner_distribution_1_0/test_compare_to_wagners_test_output.rb
|
50
|
+
- test/performance/test_mersenne_twister.rb
|
51
|
+
- test/unit/expected_mersenne_4357.txt
|
52
|
+
- test/unit/test_mersenne_twister.rb
|
53
|
+
- test/unit/test_random_testing.rb
|
54
|
+
- test/unit/test_rng.rb
|
55
|
+
- test/unit/test_chi_square.rb
|
56
|
+
- test/unit/#mt19937ar.c#
|
57
|
+
- test/unit/test_random_number_generator.rb
|
58
|
+
test_files: []
|
59
|
+
|
60
|
+
rdoc_options: []
|
61
|
+
|
62
|
+
extra_rdoc_files: []
|
63
|
+
|
64
|
+
executables: []
|
65
|
+
|
66
|
+
extensions:
|
67
|
+
- ext/random/extconf.rb
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
dependencies: []
|
71
|
+
|