random 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|