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 <cmath>
11#include <ctime>
12#include <fstream>
13#include <gsl/gsl_cdf.h>
14#include <gsl/gsl_histogram.h>
15
16using namespace ns3;
17
18/**
19 * @file
20 * @ingroup rng-tests
21 * Random number generators tests.
22 */
23
24/**
25 * @ingroup core-tests
26 * @ingroup randomvariable
27 * @defgroup rng-tests Random number generators tests
28 */
29
30/**
31 * @ingroup rng-tests
32 *
33 * Fill an array with increasing values, in the [start, end] range.
34 * @param array The array to fill.
35 * @param n The size of the array.
36 * @param start The start value.
37 * @param end The end value.
38 */
39void
40FillHistoRangeUniformly(double* array, uint32_t n, double start, double end)
41{
42 double increment = (end - start) / (n - 1.);
43 double d = start;
44
45 for (uint32_t i = 0; i < n; ++i)
46 {
47 array[i] = d;
48 d += increment;
49 }
50}
51
52/**
53 * @ingroup core-tests
54 *
55 * Test case for uniform distribution random number generator.
56 */
58{
59 public:
60 /// Number of runs.
61 static const uint32_t N_RUNS = 5;
62 /// Number of bins.
63 static const uint32_t N_BINS = 50;
64 /// Number of measurements.
65 static const uint32_t N_MEASUREMENTS = 1000000;
66
68 ~RngUniformTestCase() override;
69
70 /**
71 * Run a chi-squared test on the results of the random number generator.
72 * @param u The random number generator.
73 * @return the chi-squared test result.
74 */
76
77 private:
78 void DoRun() override;
79};
80
82 : TestCase("Uniform Random Number Generator")
83{
84}
85
89
90double
92{
93 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
94 gsl_histogram_set_ranges_uniform(h, 0., 1.);
95
96 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
97 {
98 gsl_histogram_increment(h, u->GetValue());
99 }
100
101 double tmp[N_BINS];
102
103 double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
104
105 for (uint32_t i = 0; i < N_BINS; ++i)
106 {
107 tmp[i] = gsl_histogram_get(h, i);
108 tmp[i] -= expected;
109 tmp[i] *= tmp[i];
110 tmp[i] /= expected;
111 }
112
113 gsl_histogram_free(h);
114
115 double chiSquared = 0;
116
117 for (uint32_t i = 0; i < N_BINS; ++i)
118 {
119 chiSquared += tmp[i];
120 }
121
122 return chiSquared;
123}
124
125void
127{
128 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
129
130 double sum = 0.;
131 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
132
133 for (uint32_t i = 0; i < N_RUNS; ++i)
134 {
136 double result = ChiSquaredTest(u);
137 sum += result;
138 }
139
140 sum /= (double)N_RUNS;
141
142 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
143}
144
145/**
146 * @ingroup rng-tests
147 *
148 * Test case for normal distribution random number generator.
149 */
151{
152 public:
153 /// Number of runs.
154 static const uint32_t N_RUNS = 5;
155 /// Number of bins.
156 static const uint32_t N_BINS = 50;
157 /// Number of measurements.
158 static const uint32_t N_MEASUREMENTS = 1000000;
159
161 ~RngNormalTestCase() override;
162
163 /**
164 * Run a chi-squared test on the results of the random number generator.
165 * @param n The random number generator.
166 * @return the chi-squared test result.
167 */
169
170 private:
171 void DoRun() override;
172};
173
175 : TestCase("Normal Random Number Generator")
176{
177}
178
182
183double
185{
186 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
187
188 double range[N_BINS + 1];
189 FillHistoRangeUniformly(range, N_BINS + 1, -4., 4.);
190 range[0] = -std::numeric_limits<double>::max();
191 range[N_BINS] = std::numeric_limits<double>::max();
192
193 gsl_histogram_set_ranges(h, range, N_BINS + 1);
194
195 double expected[N_BINS];
196
197 double sigma = 1.;
198
199 for (uint32_t i = 0; i < N_BINS; ++i)
200 {
201 expected[i] = gsl_cdf_gaussian_P(range[i + 1], sigma) - gsl_cdf_gaussian_P(range[i], sigma);
202 expected[i] *= N_MEASUREMENTS;
203 }
204
205 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
206 {
207 gsl_histogram_increment(h, n->GetValue());
208 }
209
210 double tmp[N_BINS];
211
212 for (uint32_t i = 0; i < N_BINS; ++i)
213 {
214 tmp[i] = gsl_histogram_get(h, i);
215 tmp[i] -= expected[i];
216 tmp[i] *= tmp[i];
217 tmp[i] /= expected[i];
218 }
219
220 gsl_histogram_free(h);
221
222 double chiSquared = 0;
223
224 for (uint32_t i = 0; i < N_BINS; ++i)
225 {
226 chiSquared += tmp[i];
227 }
228
229 return chiSquared;
230}
231
232void
234{
235 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
236
237 double sum = 0.;
238 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
239
240 for (uint32_t i = 0; i < N_RUNS; ++i)
241 {
243 double result = ChiSquaredTest(n);
244 sum += result;
245 }
246
247 sum /= (double)N_RUNS;
248
249 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
250}
251
252/**
253 * @ingroup rng-tests
254 *
255 * Test case for exponential distribution random number generator.
256 */
258{
259 public:
260 /// Number of runs.
261 static const uint32_t N_RUNS = 5;
262 /// Number of bins.
263 static const uint32_t N_BINS = 50;
264 /// Number of measurements.
265 static const uint32_t N_MEASUREMENTS = 1000000;
266
268 ~RngExponentialTestCase() override;
269
270 /**
271 * Run a chi-squared test on the results of the random number generator.
272 * @param n The random number generator.
273 * @return the chi-squared test result.
274 */
276
277 private:
278 void DoRun() override;
279};
280
282 : TestCase("Exponential Random Number Generator")
283{
284}
285
289
290double
292{
293 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
294
295 double range[N_BINS + 1];
296 FillHistoRangeUniformly(range, N_BINS + 1, 0., 10.);
297 range[N_BINS] = std::numeric_limits<double>::max();
298
299 gsl_histogram_set_ranges(h, range, N_BINS + 1);
300
301 double expected[N_BINS];
302
303 double mu = 1.;
304
305 for (uint32_t i = 0; i < N_BINS; ++i)
306 {
307 expected[i] = gsl_cdf_exponential_P(range[i + 1], mu) - gsl_cdf_exponential_P(range[i], mu);
308 expected[i] *= N_MEASUREMENTS;
309 }
310
311 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
312 {
313 gsl_histogram_increment(h, e->GetValue());
314 }
315
316 double tmp[N_BINS];
317
318 for (uint32_t i = 0; i < N_BINS; ++i)
319 {
320 tmp[i] = gsl_histogram_get(h, i);
321 tmp[i] -= expected[i];
322 tmp[i] *= tmp[i];
323 tmp[i] /= expected[i];
324 }
325
326 gsl_histogram_free(h);
327
328 double chiSquared = 0;
329
330 for (uint32_t i = 0; i < N_BINS; ++i)
331 {
332 chiSquared += tmp[i];
333 }
334
335 return chiSquared;
336}
337
338void
340{
341 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
342
343 double sum = 0.;
344 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
345
346 for (uint32_t i = 0; i < N_RUNS; ++i)
347 {
349 double result = ChiSquaredTest(e);
350 sum += result;
351 }
352
353 sum /= (double)N_RUNS;
354
355 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
356}
357
358/**
359 * @ingroup rng-tests
360 *
361 * Test case for pareto distribution random number generator.
362 */
364{
365 public:
366 /// Number of runs.
367 static const uint32_t N_RUNS = 5;
368 /// Number of bins.
369 static const uint32_t N_BINS = 50;
370 /// Number of measurements.
371 static const uint32_t N_MEASUREMENTS = 1000000;
372
374 ~RngParetoTestCase() override;
375
376 /**
377 * Run a chi-squared test on the results of the random number generator.
378 * @param p The random number generator.
379 * @return the chi-squared test result.
380 */
382
383 private:
384 void DoRun() override;
385};
386
388 : TestCase("Pareto Random Number Generator")
389{
390}
391
395
396double
398{
399 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
400
401 double range[N_BINS + 1];
402 FillHistoRangeUniformly(range, N_BINS + 1, 1., 10.);
403 range[N_BINS] = std::numeric_limits<double>::max();
404
405 gsl_histogram_set_ranges(h, range, N_BINS + 1);
406
407 double expected[N_BINS];
408
409 double a = 1.5;
410 double b = 0.33333333;
411
412 // mean is 1 with these values
413
414 for (uint32_t i = 0; i < N_BINS; ++i)
415 {
416 expected[i] = gsl_cdf_pareto_P(range[i + 1], a, b) - gsl_cdf_pareto_P(range[i], a, b);
417 expected[i] *= N_MEASUREMENTS;
418 }
419
420 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
421 {
422 gsl_histogram_increment(h, p->GetValue());
423 }
424
425 double tmp[N_BINS];
426
427 for (uint32_t i = 0; i < N_BINS; ++i)
428 {
429 tmp[i] = gsl_histogram_get(h, i);
430 tmp[i] -= expected[i];
431 tmp[i] *= tmp[i];
432 tmp[i] /= expected[i];
433 }
434
435 gsl_histogram_free(h);
436
437 double chiSquared = 0;
438
439 for (uint32_t i = 0; i < N_BINS; ++i)
440 {
441 chiSquared += tmp[i];
442 }
443
444 return chiSquared;
445}
446
447void
449{
450 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
451
452 double sum = 0.;
453 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
454
455 for (uint32_t i = 0; i < N_RUNS; ++i)
456 {
458 e->SetAttribute("Shape", DoubleValue(1.5));
459 e->SetAttribute("Scale", DoubleValue(0.33333333));
460 double result = ChiSquaredTest(e);
461 sum += result;
462 }
463
464 sum /= (double)N_RUNS;
465
466 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
467}
468
469/**
470 * @ingroup rng-tests
471 *
472 * @brief The random number generators Test Suite.
473 */
475{
476 public:
477 RngTestSuite();
478};
479
488
489static 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:293
@ 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:491
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.