A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
rng-test-suite.cc
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: GPL-2.0-only
3 */
4
5#include "ns3/double.h"
6#include "ns3/random-variable-stream.h"
7#include "ns3/rng-seed-manager.h"
8#include "ns3/test.h"
9
10#include <ctime>
11#include <gsl/gsl_cdf.h>
12#include <gsl/gsl_histogram.h>
13
14using namespace ns3;
15
16/**
17 * @file
18 * @ingroup rng-tests
19 * Random number generators tests.
20 */
21
22/**
23 * @ingroup core-tests
24 * @ingroup randomvariable
25 * @defgroup rng-tests Random number generators tests
26 */
27
28/**
29 * @ingroup rng-tests
30 *
31 * Fill an array with increasing values, in the [start, end] range.
32 * @param array The array to fill.
33 * @param n The size of the array.
34 * @param start The start value.
35 * @param end The end value.
36 */
37void
38FillHistoRangeUniformly(double* array, uint32_t n, double start, double end)
39{
40 double increment = (end - start) / (n - 1.);
41 double d = start;
42
43 for (uint32_t i = 0; i < n; ++i)
44 {
45 array[i] = d;
46 d += increment;
47 }
48}
49
50/**
51 * @ingroup core-tests
52 *
53 * Test case for uniform distribution random number generator.
54 */
56{
57 public:
58 /// Number of runs.
59 static const uint32_t N_RUNS = 5;
60 /// Number of bins.
61 static const uint32_t N_BINS = 50;
62 /// Number of measurements.
63 static const uint32_t N_MEASUREMENTS = 1000000;
64
66 ~RngUniformTestCase() override;
67
68 /**
69 * Run a chi-squared test on the results of the random number generator.
70 * @param u The random number generator.
71 * @return the chi-squared test result.
72 */
74
75 private:
76 void DoRun() override;
77};
78
80 : TestCase("Uniform Random Number Generator")
81{
82}
83
87
88double
90{
91 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
92 gsl_histogram_set_ranges_uniform(h, 0., 1.);
93
94 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
95 {
96 gsl_histogram_increment(h, u->GetValue());
97 }
98
99 double tmp[N_BINS];
100
101 double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
102
103 for (uint32_t i = 0; i < N_BINS; ++i)
104 {
105 tmp[i] = gsl_histogram_get(h, i);
106 tmp[i] -= expected;
107 tmp[i] *= tmp[i];
108 tmp[i] /= expected;
109 }
110
111 gsl_histogram_free(h);
112
113 double chiSquared = 0;
114
115 for (uint32_t i = 0; i < N_BINS; ++i)
116 {
117 chiSquared += tmp[i];
118 }
119
120 return chiSquared;
121}
122
123void
125{
126 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
127
128 double sum = 0.;
129 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
130
131 for (uint32_t i = 0; i < N_RUNS; ++i)
132 {
134 double result = ChiSquaredTest(u);
135 sum += result;
136 }
137
138 sum /= (double)N_RUNS;
139
140 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
141}
142
143/**
144 * @ingroup rng-tests
145 *
146 * Test case for normal distribution random number generator.
147 */
149{
150 public:
151 /// Number of runs.
152 static const uint32_t N_RUNS = 5;
153 /// Number of bins.
154 static const uint32_t N_BINS = 50;
155 /// Number of measurements.
156 static const uint32_t N_MEASUREMENTS = 1000000;
157
159 ~RngNormalTestCase() override;
160
161 /**
162 * Run a chi-squared test on the results of the random number generator.
163 * @param n The random number generator.
164 * @return the chi-squared test result.
165 */
167
168 private:
169 void DoRun() override;
170};
171
173 : TestCase("Normal Random Number Generator")
174{
175}
176
180
181double
183{
184 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
185
186 double range[N_BINS + 1];
187 FillHistoRangeUniformly(range, N_BINS + 1, -4., 4.);
188 range[0] = -std::numeric_limits<double>::max();
189 range[N_BINS] = std::numeric_limits<double>::max();
190
191 gsl_histogram_set_ranges(h, range, N_BINS + 1);
192
193 double expected[N_BINS];
194
195 double sigma = 1.;
196
197 for (uint32_t i = 0; i < N_BINS; ++i)
198 {
199 expected[i] = gsl_cdf_gaussian_P(range[i + 1], sigma) - gsl_cdf_gaussian_P(range[i], sigma);
200 expected[i] *= N_MEASUREMENTS;
201 }
202
203 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
204 {
205 gsl_histogram_increment(h, n->GetValue());
206 }
207
208 double tmp[N_BINS];
209
210 for (uint32_t i = 0; i < N_BINS; ++i)
211 {
212 tmp[i] = gsl_histogram_get(h, i);
213 tmp[i] -= expected[i];
214 tmp[i] *= tmp[i];
215 tmp[i] /= expected[i];
216 }
217
218 gsl_histogram_free(h);
219
220 double chiSquared = 0;
221
222 for (uint32_t i = 0; i < N_BINS; ++i)
223 {
224 chiSquared += tmp[i];
225 }
226
227 return chiSquared;
228}
229
230void
232{
233 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
234
235 double sum = 0.;
236 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
237
238 for (uint32_t i = 0; i < N_RUNS; ++i)
239 {
241 double result = ChiSquaredTest(n);
242 sum += result;
243 }
244
245 sum /= (double)N_RUNS;
246
247 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
248}
249
250/**
251 * @ingroup rng-tests
252 *
253 * Test case for exponential distribution random number generator.
254 */
256{
257 public:
258 /// Number of runs.
259 static const uint32_t N_RUNS = 5;
260 /// Number of bins.
261 static const uint32_t N_BINS = 50;
262 /// Number of measurements.
263 static const uint32_t N_MEASUREMENTS = 1000000;
264
266 ~RngExponentialTestCase() override;
267
268 /**
269 * Run a chi-squared test on the results of the random number generator.
270 * @param n The random number generator.
271 * @return the chi-squared test result.
272 */
274
275 private:
276 void DoRun() override;
277};
278
280 : TestCase("Exponential Random Number Generator")
281{
282}
283
287
288double
290{
291 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
292
293 double range[N_BINS + 1];
294 FillHistoRangeUniformly(range, N_BINS + 1, 0., 10.);
295 range[N_BINS] = std::numeric_limits<double>::max();
296
297 gsl_histogram_set_ranges(h, range, N_BINS + 1);
298
299 double expected[N_BINS];
300
301 double mu = 1.;
302
303 for (uint32_t i = 0; i < N_BINS; ++i)
304 {
305 expected[i] = gsl_cdf_exponential_P(range[i + 1], mu) - gsl_cdf_exponential_P(range[i], mu);
306 expected[i] *= N_MEASUREMENTS;
307 }
308
309 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
310 {
311 gsl_histogram_increment(h, e->GetValue());
312 }
313
314 double tmp[N_BINS];
315
316 for (uint32_t i = 0; i < N_BINS; ++i)
317 {
318 tmp[i] = gsl_histogram_get(h, i);
319 tmp[i] -= expected[i];
320 tmp[i] *= tmp[i];
321 tmp[i] /= expected[i];
322 }
323
324 gsl_histogram_free(h);
325
326 double chiSquared = 0;
327
328 for (uint32_t i = 0; i < N_BINS; ++i)
329 {
330 chiSquared += tmp[i];
331 }
332
333 return chiSquared;
334}
335
336void
338{
339 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
340
341 double sum = 0.;
342 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
343
344 for (uint32_t i = 0; i < N_RUNS; ++i)
345 {
347 double result = ChiSquaredTest(e);
348 sum += result;
349 }
350
351 sum /= (double)N_RUNS;
352
353 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
354}
355
356/**
357 * @ingroup rng-tests
358 *
359 * Test case for pareto distribution random number generator.
360 */
362{
363 public:
364 /// Number of runs.
365 static const uint32_t N_RUNS = 5;
366 /// Number of bins.
367 static const uint32_t N_BINS = 50;
368 /// Number of measurements.
369 static const uint32_t N_MEASUREMENTS = 1000000;
370
372 ~RngParetoTestCase() override;
373
374 /**
375 * Run a chi-squared test on the results of the random number generator.
376 * @param p The random number generator.
377 * @return the chi-squared test result.
378 */
380
381 private:
382 void DoRun() override;
383};
384
386 : TestCase("Pareto Random Number Generator")
387{
388}
389
393
394double
396{
397 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
398
399 double range[N_BINS + 1];
400 FillHistoRangeUniformly(range, N_BINS + 1, 1., 10.);
401 range[N_BINS] = std::numeric_limits<double>::max();
402
403 gsl_histogram_set_ranges(h, range, N_BINS + 1);
404
405 double expected[N_BINS];
406
407 double a = 1.5;
408 double b = 0.33333333;
409
410 // mean is 1 with these values
411
412 for (uint32_t i = 0; i < N_BINS; ++i)
413 {
414 expected[i] = gsl_cdf_pareto_P(range[i + 1], a, b) - gsl_cdf_pareto_P(range[i], a, b);
415 expected[i] *= N_MEASUREMENTS;
416 }
417
418 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
419 {
420 gsl_histogram_increment(h, p->GetValue());
421 }
422
423 double tmp[N_BINS];
424
425 for (uint32_t i = 0; i < N_BINS; ++i)
426 {
427 tmp[i] = gsl_histogram_get(h, i);
428 tmp[i] -= expected[i];
429 tmp[i] *= tmp[i];
430 tmp[i] /= expected[i];
431 }
432
433 gsl_histogram_free(h);
434
435 double chiSquared = 0;
436
437 for (uint32_t i = 0; i < N_BINS; ++i)
438 {
439 chiSquared += tmp[i];
440 }
441
442 return chiSquared;
443}
444
445void
447{
448 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
449
450 double sum = 0.;
451 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
452
453 for (uint32_t i = 0; i < N_RUNS; ++i)
454 {
456 e->SetAttribute("Shape", DoubleValue(1.5));
457 e->SetAttribute("Scale", DoubleValue(0.33333333));
458 double result = ChiSquaredTest(e);
459 sum += result;
460 }
461
462 sum /= (double)N_RUNS;
463
464 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
465}
466
467/**
468 * @ingroup rng-tests
469 *
470 * @brief The random number generators Test Suite.
471 */
473{
474 public:
475 RngTestSuite();
476};
477
486
487static RngTestSuite g_rngTestSuite; //!< Static variable for test initialization
uint32_t u
return result
Test case for exponential distribution random number generator.
static const uint32_t N_BINS
Number of bins.
void DoRun() override
Implementation to actually run this TestCase.
static const uint32_t N_MEASUREMENTS
Number of measurements.
double ChiSquaredTest(Ptr< ExponentialRandomVariable > n)
Run a chi-squared test on the results of the random number generator.
static const uint32_t N_RUNS
Number of runs.
Test case for normal distribution random number generator.
~RngNormalTestCase() override
double ChiSquaredTest(Ptr< NormalRandomVariable > n)
Run a chi-squared test on the results of the random number generator.
static const uint32_t N_MEASUREMENTS
Number of measurements.
static const uint32_t N_RUNS
Number of runs.
void DoRun() override
Implementation to actually run this TestCase.
static const uint32_t N_BINS
Number of bins.
Test case for pareto distribution random number generator.
static const uint32_t N_RUNS
Number of runs.
~RngParetoTestCase() override
double ChiSquaredTest(Ptr< ParetoRandomVariable > p)
Run a chi-squared test on the results of the random number generator.
void DoRun() override
Implementation to actually run this TestCase.
static const uint32_t N_BINS
Number of bins.
static const uint32_t N_MEASUREMENTS
Number of measurements.
The random number generators Test Suite.
Test case for uniform distribution random number generator.
double ChiSquaredTest(Ptr< UniformRandomVariable > u)
Run a chi-squared test on the results of the random number generator.
static const uint32_t N_MEASUREMENTS
Number of measurements.
static const uint32_t N_BINS
Number of bins.
~RngUniformTestCase() override
static const uint32_t N_RUNS
Number of runs.
void DoRun() override
Implementation to actually run this TestCase.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static void SetSeed(uint32_t seed)
Set the seed.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
void FillHistoRangeUniformly(double *array, uint32_t n, double start, double end)
Fill an array with increasing values, in the [start, end] range.
#define NS_TEST_ASSERT_MSG_LT(actual, limit, msg)
Test that an actual value is less than a limit and report and abort if not.
Definition test.h:698
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static RngTestSuite g_rngTestSuite
Static variable for test initialization.