A Discrete-Event Network Simulator
API
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 
27 using namespace ns3;
28 
49 void
50 FillHistoRangeUniformly(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 
85  double ChiSquaredTest(Ptr<UniformRandomVariable> u);
86 
87  private:
88  void DoRun() override;
89 };
90 
92  : TestCase("Uniform Random Number Generator")
93 {
94 }
95 
97 {
98 }
99 
100 double
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 
135 void
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 
193 double
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();
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 
242 void
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 
300 double
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.);
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 
348 void
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 
406 double
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.);
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 
457 void
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 
484 class RngTestSuite : public TestSuite
485 {
486  public:
487  RngTestSuite();
488 };
489 
491  : TestSuite("random-number-generators", UNIT)
492 {
493  AddTestCase(new RngUniformTestCase, TestCase::QUICK);
494  AddTestCase(new RngNormalTestCase, TestCase::QUICK);
495  AddTestCase(new RngExponentialTestCase, TestCase::QUICK);
496  AddTestCase(new RngParetoTestCase, TestCase::QUICK);
497 }
498 
#define max(a, b)
Definition: 80211b.c:42
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
double GetValue(double mean, double bound)
Get the next random value drawn from the distribution.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
double GetValue(double min, double max)
Get the next random value drawn from the distribution.
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:709
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static RngTestSuite g_rngTestSuite
Static variable for test initialization.