Skip to content

Commit a796108

Browse files
committed
add test cases for MT random number generator
1 parent 44cde50 commit a796108

2 files changed

Lines changed: 194 additions & 0 deletions

File tree

test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ target_link_libraries (sets susa)
4949
add_test (NAME modulation COMMAND modulation)
5050
add_executable (modulation modulation.cpp)
5151
target_link_libraries (modulation susa)
52+
53+
add_test (NAME mt COMMAND mt)
54+
add_executable (mt mt.cpp)
55+
target_link_libraries (mt susa)

test/mt.cpp

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* This file is part of Susa.
3+
4+
* Susa is free software: you can redistribute it and/or modify
5+
* it under the terms of the Lesser GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* at your option) any later version.
8+
9+
* Susa is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* Lesser GNU General Public License for more details.
13+
14+
* You should have received a copy of the Lesser GNU General Public License
15+
* along with Susa. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
/**
19+
* @file mt_test.cpp
20+
* @brief Mersenne Twister Random Number Generator Unit Tests
21+
* @author Test Suite
22+
*/
23+
24+
#include "test.h"
25+
#include <cmath>
26+
27+
int main(void)
28+
{
29+
// ========== Constructor Tests ==========
30+
31+
// Test default constructor
32+
susa::mt rng_default;
33+
SUSA_TEST_EQ(true, true, "mt default constructor");
34+
35+
// Test constructor with seed
36+
susa::mt rng_seeded(12345);
37+
SUSA_TEST_EQ(true, true, "mt seeded constructor");
38+
39+
// ========== Determinism Test ==========
40+
// Same seed should produce same sequence
41+
susa::mt rng_a(42);
42+
susa::mt rng_b(42);
43+
44+
unsigned int val_a = rng_a.randint(1000);
45+
unsigned int val_b = rng_b.randint(1000);
46+
SUSA_TEST_EQ(val_a, val_b, "mt: same seed produces same sequence");
47+
48+
// ========== randint Tests ==========
49+
susa::mt rng_int(54321);
50+
51+
// Test randint range - max
52+
unsigned int rand_val_max = rng_int.randint(100);
53+
SUSA_TEST_EQ((rand_val_max < 100), true, "mt: randint produces value less than max");
54+
55+
// Test randint produces various values
56+
susa::mt rng_int2(12341);
57+
unsigned int val1 = rng_int2.randint(1000000);
58+
unsigned int val2 = rng_int2.randint(1000000);
59+
unsigned int val3 = rng_int2.randint(1000000);
60+
SUSA_TEST_EQ((val1 != val2 || val2 != val3), true, "mt: randint produces different values");
61+
62+
// ========== rand Tests ==========
63+
susa::mt rng_real(99999);
64+
65+
// Test rand returns matrix of correct size
66+
susa::matrix<double> rand_vals = rng_real.rand(10);
67+
SUSA_TEST_EQ(rand_vals.size(), 10, "mt: rand produces correct size");
68+
69+
// Test rand values are in [0, 1)
70+
bool all_in_range = true;
71+
for (size_t i = 0; i < rand_vals.size(); i++)
72+
{
73+
if (rand_vals(i) < 0.0 || rand_vals(i) >= 1.0)
74+
{
75+
all_in_range = false;
76+
break;
77+
}
78+
}
79+
SUSA_TEST_EQ(all_in_range, true, "mt: rand values in [0, 1) range");
80+
81+
// ========== randn Tests ==========
82+
susa::mt rng_normal(555);
83+
84+
// Test randn returns matrix of correct size
85+
susa::matrix<double> normal_vals = rng_normal.randn(50);
86+
SUSA_TEST_EQ(normal_vals.size(), 50, "mt: randn produces correct size");
87+
88+
// Test randn values - should have some variation
89+
double min_val = normal_vals(0);
90+
double max_val = normal_vals(0);
91+
for (size_t i = 0; i < normal_vals.size(); i++)
92+
{
93+
if (normal_vals(i) < min_val) min_val = normal_vals(i);
94+
if (normal_vals(i) > max_val) max_val = normal_vals(i);
95+
}
96+
SUSA_TEST_EQ((max_val > min_val), true, "mt: randn produces varied values");
97+
98+
// ========== rand_mask Tests ==========
99+
susa::mt rng_mask(777);
100+
101+
// Test rand_mask with mask value
102+
unsigned int mask_val = rng_mask.rand_mask(0xFF); // 255 mask
103+
SUSA_TEST_EQ((mask_val <= 0xFF), true, "mt: rand_mask respects mask");
104+
105+
// Test rand_mask matrix output
106+
susa::matrix<unsigned int> mask_vals = rng_mask.rand_mask(0x0F, 20); // 4-bit mask, 20 values
107+
SUSA_TEST_EQ(mask_vals.size(), 20, "mt: rand_mask matrix produces correct size");
108+
109+
bool all_masked = true;
110+
for (size_t i = 0; i < mask_vals.size(); i++)
111+
{
112+
if (mask_vals(i) > 0x0F)
113+
{
114+
all_masked = false;
115+
break;
116+
}
117+
}
118+
SUSA_TEST_EQ(all_masked, true, "mt: rand_mask matrix values respect mask");
119+
120+
// ========== bernoulli Tests ==========
121+
susa::mt rng_bernoulli(888);
122+
123+
// Test bernoulli with p=0.5 - should produce mix of 0s and 1s
124+
unsigned int heads = 0;
125+
unsigned int num_trials = 200;
126+
for (unsigned int i = 0; i < num_trials; i++)
127+
{
128+
heads += rng_bernoulli.bernoulli(0.5);
129+
}
130+
// With p=0.5 and 200 trials, expect roughly 100, but allow 30-170 range
131+
SUSA_TEST_EQ((heads > 30 && heads < 170), true, "mt: bernoulli(0.5) produces reasonable distribution");
132+
133+
// Test bernoulli with p=1.0 - should always return 1
134+
unsigned int ones = 0;
135+
for (unsigned int i = 0; i < 100; i++)
136+
{
137+
ones += rng_bernoulli.bernoulli(1.0);
138+
}
139+
SUSA_TEST_EQ(ones, 100, "mt: bernoulli(1.0) always returns 1");
140+
141+
// Test bernoulli with p=0.0 - should always return 0
142+
susa::mt rng_bernoulli_zero(999);
143+
unsigned int zeros = 0;
144+
for (unsigned int i = 0; i < 100; i++)
145+
{
146+
if (rng_bernoulli_zero.bernoulli(0.0) == 0)
147+
zeros++;
148+
}
149+
SUSA_TEST_EQ(zeros, 100, "mt: bernoulli(0.0) always returns 0");
150+
151+
// ========== Reproducibility Test ==========
152+
susa::mt rng_repro1(12321);
153+
susa::matrix<double> sequence1 = rng_repro1.rand(5);
154+
155+
susa::mt rng_repro2(12321);
156+
susa::matrix<double> sequence2 = rng_repro2.rand(5);
157+
158+
bool sequences_match = true;
159+
for (size_t i = 0; i < sequence1.size(); i++)
160+
{
161+
if (sequence1(i) != sequence2(i))
162+
{
163+
sequences_match = false;
164+
break;
165+
}
166+
}
167+
SUSA_TEST_EQ(sequences_match, true, "mt: reproducible with same seed");
168+
169+
// ========== Different Seeds Test ==========
170+
susa::mt rng_diff1(11111);
171+
susa::mt rng_diff2(22222);
172+
173+
susa::matrix<double> diff_seq1 = rng_diff1.rand(5);
174+
susa::matrix<double> diff_seq2 = rng_diff2.rand(5);
175+
176+
bool sequences_differ = false;
177+
for (size_t i = 0; i < diff_seq1.size(); i++)
178+
{
179+
if (diff_seq1(i) != diff_seq2(i))
180+
{
181+
sequences_differ = true;
182+
break;
183+
}
184+
}
185+
SUSA_TEST_EQ(sequences_differ, true, "mt: different seeds produce different sequences");
186+
187+
SUSA_TEST_PRINT_STATS();
188+
189+
return (uint_failed);
190+
}

0 commit comments

Comments
 (0)