A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
rng-test-suite.cc
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation;
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 */
15
16#include "ns3/double.h"
17#include "ns3/random-variable-stream.h"
18#include "ns3/rng-seed-manager.h"
19#include "ns3/test.h"
20
21#include <cmath>
22#include <ctime>
23#include <fstream>
24#include <gsl/gsl_cdf.h>
25#include <gsl/gsl_histogram.h>
26
27using namespace ns3;
28
49void
50FillHistoRangeUniformly(double* array, uint32_t n, double start, double end)
51{
52 double increment = (end - start) / (n - 1.);
53 double d = start;
54
55 for (uint32_t i = 0; i < n; ++i)
56 {
57 array[i] = d;
58 d += increment;
59 }
60}
61
68{
69 public:
71 static const uint32_t N_RUNS = 5;
73 static const uint32_t N_BINS = 50;
75 static const uint32_t N_MEASUREMENTS = 1000000;
76
78 ~RngUniformTestCase() override;
79
86
87 private:
88 void DoRun() override;
89};
90
92 : TestCase("Uniform Random Number Generator")
93{
94}
95
97{
98}
99
100double
102{
103 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
104 gsl_histogram_set_ranges_uniform(h, 0., 1.);
105
106 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
107 {
108 gsl_histogram_increment(h, u->GetValue());
109 }
110
111 double tmp[N_BINS];
112
113 double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
114
115 for (uint32_t i = 0; i < N_BINS; ++i)
116 {
117 tmp[i] = gsl_histogram_get(h, i);
118 tmp[i] -= expected;
119 tmp[i] *= tmp[i];
120 tmp[i] /= expected;
121 }
122
123 gsl_histogram_free(h);
124
125 double chiSquared = 0;
126
127 for (uint32_t i = 0; i < N_BINS; ++i)
128 {
129 chiSquared += tmp[i];
130 }
131
132 return chiSquared;
133}
134
135void
137{
138 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
139
140 double sum = 0.;
141 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
142
143 for (uint32_t i = 0; i < N_RUNS; ++i)
144 {
145 Ptr<UniformRandomVariable> u = CreateObject<UniformRandomVariable>();
146 double result = ChiSquaredTest(u);
147 sum += result;
148 }
149
150 sum /= (double)N_RUNS;
151
152 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
153}
154
161{
162 public:
164 static const uint32_t N_RUNS = 5;
166 static const uint32_t N_BINS = 50;
168 static const uint32_t N_MEASUREMENTS = 1000000;
169
171 ~RngNormalTestCase() override;
172
179
180 private:
181 void DoRun() override;
182};
183
185 : TestCase("Normal Random Number Generator")
186{
187}
188
190{
191}
192
193double
195{
196 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
197
198 double range[N_BINS + 1];
199 FillHistoRangeUniformly(range, N_BINS + 1, -4., 4.);
200 range[0] = -std::numeric_limits<double>::max();
201 range[N_BINS] = std::numeric_limits<double>::max();
202
203 gsl_histogram_set_ranges(h, range, N_BINS + 1);
204
205 double expected[N_BINS];
206
207 double sigma = 1.;
208
209 for (uint32_t i = 0; i < N_BINS; ++i)
210 {
211 expected[i] = gsl_cdf_gaussian_P(range[i + 1], sigma) - gsl_cdf_gaussian_P(range[i], sigma);
212 expected[i] *= N_MEASUREMENTS;
213 }
214
215 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
216 {
217 gsl_histogram_increment(h, n->GetValue());
218 }
219
220 double tmp[N_BINS];
221
222 for (uint32_t i = 0; i < N_BINS; ++i)
223 {
224 tmp[i] = gsl_histogram_get(h, i);
225 tmp[i] -= expected[i];
226 tmp[i] *= tmp[i];
227 tmp[i] /= expected[i];
228 }
229
230 gsl_histogram_free(h);
231
232 double chiSquared = 0;
233
234 for (uint32_t i = 0; i < N_BINS; ++i)
235 {
236 chiSquared += tmp[i];
237 }
238
239 return chiSquared;
240}
241
242void
244{
245 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
246
247 double sum = 0.;
248 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
249
250 for (uint32_t i = 0; i < N_RUNS; ++i)
251 {
252 Ptr<NormalRandomVariable> n = CreateObject<NormalRandomVariable>();
253 double result = ChiSquaredTest(n);
254 sum += result;
255 }
256
257 sum /= (double)N_RUNS;
258
259 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
260}
261
268{
269 public:
271 static const uint32_t N_RUNS = 5;
273 static const uint32_t N_BINS = 50;
275 static const uint32_t N_MEASUREMENTS = 1000000;
276
278 ~RngExponentialTestCase() override;
279
286
287 private:
288 void DoRun() override;
289};
290
292 : TestCase("Exponential Random Number Generator")
293{
294}
295
297{
298}
299
300double
302{
303 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
304
305 double range[N_BINS + 1];
306 FillHistoRangeUniformly(range, N_BINS + 1, 0., 10.);
307 range[N_BINS] = std::numeric_limits<double>::max();
308
309 gsl_histogram_set_ranges(h, range, N_BINS + 1);
310
311 double expected[N_BINS];
312
313 double mu = 1.;
314
315 for (uint32_t i = 0; i < N_BINS; ++i)
316 {
317 expected[i] = gsl_cdf_exponential_P(range[i + 1], mu) - gsl_cdf_exponential_P(range[i], mu);
318 expected[i] *= N_MEASUREMENTS;
319 }
320
321 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
322 {
323 gsl_histogram_increment(h, e->GetValue());
324 }
325
326 double tmp[N_BINS];
327
328 for (uint32_t i = 0; i < N_BINS; ++i)
329 {
330 tmp[i] = gsl_histogram_get(h, i);
331 tmp[i] -= expected[i];
332 tmp[i] *= tmp[i];
333 tmp[i] /= expected[i];
334 }
335
336 gsl_histogram_free(h);
337
338 double chiSquared = 0;
339
340 for (uint32_t i = 0; i < N_BINS; ++i)
341 {
342 chiSquared += tmp[i];
343 }
344
345 return chiSquared;
346}
347
348void
350{
351 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
352
353 double sum = 0.;
354 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
355
356 for (uint32_t i = 0; i < N_RUNS; ++i)
357 {
358 Ptr<ExponentialRandomVariable> e = CreateObject<ExponentialRandomVariable>();
359 double result = ChiSquaredTest(e);
360 sum += result;
361 }
362
363 sum /= (double)N_RUNS;
364
365 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
366}
367
374{
375 public:
377 static const uint32_t N_RUNS = 5;
379 static const uint32_t N_BINS = 50;
381 static const uint32_t N_MEASUREMENTS = 1000000;
382
384 ~RngParetoTestCase() override;
385
392
393 private:
394 void DoRun() override;
395};
396
398 : TestCase("Pareto Random Number Generator")
399{
400}
401
403{
404}
405
406double
408{
409 gsl_histogram* h = gsl_histogram_alloc(N_BINS);
410
411 double range[N_BINS + 1];
412 FillHistoRangeUniformly(range, N_BINS + 1, 1., 10.);
413 range[N_BINS] = std::numeric_limits<double>::max();
414
415 gsl_histogram_set_ranges(h, range, N_BINS + 1);
416
417 double expected[N_BINS];
418
419 double a = 1.5;
420 double b = 0.33333333;
421
422 // mean is 1 with these values
423
424 for (uint32_t i = 0; i < N_BINS; ++i)
425 {
426 expected[i] = gsl_cdf_pareto_P(range[i + 1], a, b) - gsl_cdf_pareto_P(range[i], a, b);
427 expected[i] *= N_MEASUREMENTS;
428 }
429
430 for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
431 {
432 gsl_histogram_increment(h, p->GetValue());
433 }
434
435 double tmp[N_BINS];
436
437 for (uint32_t i = 0; i < N_BINS; ++i)
438 {
439 tmp[i] = gsl_histogram_get(h, i);
440 tmp[i] -= expected[i];
441 tmp[i] *= tmp[i];
442 tmp[i] /= expected[i];
443 }
444
445 gsl_histogram_free(h);
446
447 double chiSquared = 0;
448
449 for (uint32_t i = 0; i < N_BINS; ++i)
450 {
451 chiSquared += tmp[i];
452 }
453
454 return chiSquared;
455}
456
457void
459{
460 RngSeedManager::SetSeed(static_cast<uint32_t>(time(nullptr)));
461
462 double sum = 0.;
463 double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
464
465 for (uint32_t i = 0; i < N_RUNS; ++i)
466 {
467 Ptr<ParetoRandomVariable> e = CreateObject<ParetoRandomVariable>();
468 e->SetAttribute("Shape", DoubleValue(1.5));
469 e->SetAttribute("Scale", DoubleValue(0.33333333));
470 double result = ChiSquaredTest(e);
471 sum += result;
472 }
473
474 sum /= (double)N_RUNS;
475
476 NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
477}
478
485{
486 public:
487 RngTestSuite();
488};
489
491 : TestSuite("random-number-generators", Type::UNIT)
492{
493 AddTestCase(new RngUniformTestCase, TestCase::Duration::QUICK);
494 AddTestCase(new RngNormalTestCase, TestCase::Duration::QUICK);
495 AddTestCase(new RngExponentialTestCase, TestCase::Duration::QUICK);
496 AddTestCase(new RngParetoTestCase, TestCase::Duration::QUICK);
497}
498
Test case for exponential distribution random number generator.
~RngExponentialTestCase() override
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:42
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static void SetSeed(uint32_t seed)
Set the seed.
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
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:710
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static RngTestSuite g_rngTestSuite
Static variable for test initialization.