A Discrete-Event Network Simulator
API
rng-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation;
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  */
16 
17 
18 #include <cmath>
19 #include <gsl/gsl_cdf.h>
20 #include <gsl/gsl_histogram.h>
21 #include <ctime>
22 #include <fstream>
23 
24 #include "ns3/test.h"
25 #include "ns3/double.h"
26 #include "ns3/random-variable-stream.h"
27 #include "ns3/rng-seed-manager.h"
28 
29 using namespace ns3;
30 
51 void
52 FillHistoRangeUniformly (double *array, uint32_t n, double start, double end)
53 {
54  double increment = (end - start) / (n - 1.);
55  double d = start;
56 
57  for (uint32_t i = 0; i < n; ++i)
58  {
59  array[i] = d;
60  d += increment;
61  }
62 }
63 
70 {
71 public:
73  static const uint32_t N_RUNS = 5;
75  static const uint32_t N_BINS = 50;
77  static const uint32_t N_MEASUREMENTS = 1000000;
78 
80  virtual ~RngUniformTestCase ();
81 
87  double ChiSquaredTest (Ptr<UniformRandomVariable> u);
88 
89 private:
90  virtual void DoRun (void);
91 };
92 
94  : TestCase ("Uniform Random Number Generator")
95 {}
96 
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 (0)));
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  virtual ~RngNormalTestCase ();
172 
179 
180 private:
181  virtual void DoRun (void);
182 };
183 
185  : TestCase ("Normal Random Number Generator")
186 {}
187 
189 {}
190 
191 double
193 {
194  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
195 
196  double range[N_BINS + 1];
197  FillHistoRangeUniformly (range, N_BINS + 1, -4., 4.);
198  range[0] = -std::numeric_limits<double>::max ();
200 
201  gsl_histogram_set_ranges (h, range, N_BINS + 1);
202 
203  double expected[N_BINS];
204 
205  double sigma = 1.;
206 
207  for (uint32_t i = 0; i < N_BINS; ++i)
208  {
209  expected[i] = gsl_cdf_gaussian_P (range[i + 1], sigma) - gsl_cdf_gaussian_P (range[i], sigma);
210  expected[i] *= N_MEASUREMENTS;
211  }
212 
213  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
214  {
215  gsl_histogram_increment (h, n->GetValue ());
216  }
217 
218  double tmp[N_BINS];
219 
220  for (uint32_t i = 0; i < N_BINS; ++i)
221  {
222  tmp[i] = gsl_histogram_get (h, i);
223  tmp[i] -= expected[i];
224  tmp[i] *= tmp[i];
225  tmp[i] /= expected[i];
226  }
227 
228  gsl_histogram_free (h);
229 
230  double chiSquared = 0;
231 
232  for (uint32_t i = 0; i < N_BINS; ++i)
233  {
234  chiSquared += tmp[i];
235  }
236 
237  return chiSquared;
238 }
239 
240 void
242 {
243  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
244 
245  double sum = 0.;
246  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
247 
248  for (uint32_t i = 0; i < N_RUNS; ++i)
249  {
250  Ptr<NormalRandomVariable> n = CreateObject<NormalRandomVariable> ();
251  double result = ChiSquaredTest (n);
252  sum += result;
253  }
254 
255  sum /= (double)N_RUNS;
256 
257  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
258 }
259 
266 {
267 public:
269  static const uint32_t N_RUNS = 5;
271  static const uint32_t N_BINS = 50;
273  static const uint32_t N_MEASUREMENTS = 1000000;
274 
276  virtual ~RngExponentialTestCase ();
277 
284 
285 private:
286  virtual void DoRun (void);
287 };
288 
290  : TestCase ("Exponential Random Number Generator")
291 {}
292 
294 {}
295 
296 double
298 {
299  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
300 
301  double range[N_BINS + 1];
302  FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
304 
305  gsl_histogram_set_ranges (h, range, N_BINS + 1);
306 
307  double expected[N_BINS];
308 
309  double mu = 1.;
310 
311  for (uint32_t i = 0; i < N_BINS; ++i)
312  {
313  expected[i] = gsl_cdf_exponential_P (range[i + 1], mu) - gsl_cdf_exponential_P (range[i], mu);
314  expected[i] *= N_MEASUREMENTS;
315  }
316 
317  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
318  {
319  gsl_histogram_increment (h, e->GetValue ());
320  }
321 
322  double tmp[N_BINS];
323 
324  for (uint32_t i = 0; i < N_BINS; ++i)
325  {
326  tmp[i] = gsl_histogram_get (h, i);
327  tmp[i] -= expected[i];
328  tmp[i] *= tmp[i];
329  tmp[i] /= expected[i];
330  }
331 
332  gsl_histogram_free (h);
333 
334  double chiSquared = 0;
335 
336  for (uint32_t i = 0; i < N_BINS; ++i)
337  {
338  chiSquared += tmp[i];
339  }
340 
341  return chiSquared;
342 }
343 
344 void
346 {
347  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
348 
349  double sum = 0.;
350  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
351 
352  for (uint32_t i = 0; i < N_RUNS; ++i)
353  {
354  Ptr<ExponentialRandomVariable> e = CreateObject<ExponentialRandomVariable> ();
355  double result = ChiSquaredTest (e);
356  sum += result;
357  }
358 
359  sum /= (double)N_RUNS;
360 
361  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
362 }
363 
370 {
371 public:
373  static const uint32_t N_RUNS = 5;
375  static const uint32_t N_BINS = 50;
377  static const uint32_t N_MEASUREMENTS = 1000000;
378 
380  virtual ~RngParetoTestCase ();
381 
388 
389 private:
390  virtual void DoRun (void);
391 };
392 
394  : TestCase ("Pareto Random Number Generator")
395 {}
396 
398 {}
399 
400 double
402 {
403  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
404 
405  double range[N_BINS + 1];
406  FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
408 
409  gsl_histogram_set_ranges (h, range, N_BINS + 1);
410 
411  double expected[N_BINS];
412 
413  double a = 1.5;
414  double b = 0.33333333;
415 
416  // mean is 1 with these values
417 
418  for (uint32_t i = 0; i < N_BINS; ++i)
419  {
420  expected[i] = gsl_cdf_pareto_P (range[i + 1], a, b) - gsl_cdf_pareto_P (range[i], a, b);
421  expected[i] *= N_MEASUREMENTS;
422  }
423 
424  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
425  {
426  gsl_histogram_increment (h, p->GetValue ());
427  }
428 
429  double tmp[N_BINS];
430 
431  for (uint32_t i = 0; i < N_BINS; ++i)
432  {
433  tmp[i] = gsl_histogram_get (h, i);
434  tmp[i] -= expected[i];
435  tmp[i] *= tmp[i];
436  tmp[i] /= expected[i];
437  }
438 
439  gsl_histogram_free (h);
440 
441  double chiSquared = 0;
442 
443  for (uint32_t i = 0; i < N_BINS; ++i)
444  {
445  chiSquared += tmp[i];
446  }
447 
448  return chiSquared;
449 }
450 
451 void
453 {
454  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
455 
456  double sum = 0.;
457  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
458 
459  for (uint32_t i = 0; i < N_RUNS; ++i)
460  {
461  Ptr<ParetoRandomVariable> e = CreateObject<ParetoRandomVariable> ();
462  e->SetAttribute ("Shape", DoubleValue (1.5));
463  e->SetAttribute ("Scale", DoubleValue (0.33333333));
464  double result = ChiSquaredTest (e);
465  sum += result;
466  }
467 
468  sum /= (double)N_RUNS;
469 
470  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
471 }
472 
478 class RngTestSuite : public TestSuite
479 {
480 public:
481  RngTestSuite ();
482 };
483 
485  : TestSuite ("random-number-generators", UNIT)
486 {
487  AddTestCase (new RngUniformTestCase, TestCase::QUICK);
488  AddTestCase (new RngNormalTestCase, TestCase::QUICK);
489  AddTestCase (new RngExponentialTestCase, TestCase::QUICK);
490  AddTestCase (new RngParetoTestCase, TestCase::QUICK);
491 }
492 
493 static RngTestSuite g_rngTestSuite; //!< Static variable for test initialization
#define max(a, b)
Definition: 80211b.c:43
Test case for exponential distribution random number generator.
static const uint32_t N_BINS
Number of bins.
virtual void DoRun(void)
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.
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.
virtual ~RngNormalTestCase()
static const uint32_t N_RUNS
Number of runs.
virtual void DoRun(void)
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.
double ChiSquaredTest(Ptr< ParetoRandomVariable > p)
Run a chi-squared test on the results of the random number generator.
static const uint32_t N_BINS
Number of bins.
static const uint32_t N_MEASUREMENTS
Number of measurements.
virtual ~RngParetoTestCase()
virtual void DoRun(void)
Implementation to actually run this TestCase.
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.
virtual void DoRun(void)
Implementation to actually run this TestCase.
static const uint32_t N_BINS
Number of bins.
static const uint32_t N_RUNS
Number of runs.
virtual ~RngUniformTestCase()
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:41
double GetValue(double mean, double bound)
Get the next random value, as a double from the exponential distribution with the specified mean and ...
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
double GetValue(double min, double max)
Get the next random value, as a double in the specified range .
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:675
Every class exported by the ns3 library is enclosed in the ns3 namespace.
def start()
Definition: core.py:1853