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 
31 void
32 FillHistoRangeUniformly (double *array, uint32_t n, double start, double end)
33 {
34  double increment = (end - start) / (n - 1.);
35  double d = start;
36 
37  for (uint32_t i = 0; i < n; ++i)
38  {
39  array[i] = d;
40  d += increment;
41  }
42 }
43 
44 // ===========================================================================
45 // Test case for uniform distribution random number generator
46 // ===========================================================================
48 {
49 public:
50  static const uint32_t N_RUNS = 5;
51  static const uint32_t N_BINS = 50;
52  static const uint32_t N_MEASUREMENTS = 1000000;
53 
55  virtual ~RngUniformTestCase ();
56 
57  double ChiSquaredTest (Ptr<UniformRandomVariable> u);
58 
59 private:
60  virtual void DoRun (void);
61 };
62 
64  : TestCase ("Uniform Random Number Generator")
65 {
66 }
67 
69 {
70 }
71 
72 double
74 {
75  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
76  gsl_histogram_set_ranges_uniform (h, 0., 1.);
77 
78  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
79  {
80  gsl_histogram_increment (h, u->GetValue ());
81  }
82 
83  double tmp[N_BINS];
84 
85  double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
86 
87  for (uint32_t i = 0; i < N_BINS; ++i)
88  {
89  tmp[i] = gsl_histogram_get (h, i);
90  tmp[i] -= expected;
91  tmp[i] *= tmp[i];
92  tmp[i] /= expected;
93  }
94 
95  gsl_histogram_free (h);
96 
97  double chiSquared = 0;
98 
99  for (uint32_t i = 0; i < N_BINS; ++i)
100  {
101  chiSquared += tmp[i];
102  }
103 
104  return chiSquared;
105 }
106 
107 void
109 {
110  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
111 
112  double sum = 0.;
113  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
114 
115  for (uint32_t i = 0; i < N_RUNS; ++i)
116  {
117  Ptr<UniformRandomVariable> u = CreateObject<UniformRandomVariable> ();
118  double result = ChiSquaredTest (u);
119  sum += result;
120  }
121 
122  sum /= (double)N_RUNS;
123 
124  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
125 }
126 
127 // ===========================================================================
128 // Test case for normal distribution random number generator
129 // ===========================================================================
131 {
132 public:
133  static const uint32_t N_RUNS = 5;
134  static const uint32_t N_BINS = 50;
135  static const uint32_t N_MEASUREMENTS = 1000000;
136 
138  virtual ~RngNormalTestCase ();
139 
141 
142 private:
143  virtual void DoRun (void);
144 };
145 
147  : TestCase ("Normal Random Number Generator")
148 {
149 }
150 
152 {
153 }
154 
155 double
157 {
158  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
159 
160  double range[N_BINS + 1];
161  FillHistoRangeUniformly (range, N_BINS + 1, -4., 4.);
162  range[0] = -std::numeric_limits<double>::max ();
163  range[N_BINS] = std::numeric_limits<double>::max ();
164 
165  gsl_histogram_set_ranges (h, range, N_BINS + 1);
166 
167  double expected[N_BINS];
168 
169  double sigma = 1.;
170 
171  for (uint32_t i = 0; i < N_BINS; ++i)
172  {
173  expected[i] = gsl_cdf_gaussian_P (range[i + 1], sigma) - gsl_cdf_gaussian_P (range[i], sigma);
174  expected[i] *= N_MEASUREMENTS;
175  }
176 
177  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
178  {
179  gsl_histogram_increment (h, n->GetValue ());
180  }
181 
182  double tmp[N_BINS];
183 
184  for (uint32_t i = 0; i < N_BINS; ++i)
185  {
186  tmp[i] = gsl_histogram_get (h, i);
187  tmp[i] -= expected[i];
188  tmp[i] *= tmp[i];
189  tmp[i] /= expected[i];
190  }
191 
192  gsl_histogram_free (h);
193 
194  double chiSquared = 0;
195 
196  for (uint32_t i = 0; i < N_BINS; ++i)
197  {
198  chiSquared += tmp[i];
199  }
200 
201  return chiSquared;
202 }
203 
204 void
206 {
207  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
208 
209  double sum = 0.;
210  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
211 
212  for (uint32_t i = 0; i < N_RUNS; ++i)
213  {
214  Ptr<NormalRandomVariable> n = CreateObject<NormalRandomVariable> ();
215  double result = ChiSquaredTest (n);
216  sum += result;
217  }
218 
219  sum /= (double)N_RUNS;
220 
221  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
222 }
223 
224 // ===========================================================================
225 // Test case for exponential distribution random number generator
226 // ===========================================================================
228 {
229 public:
230  static const uint32_t N_RUNS = 5;
231  static const uint32_t N_BINS = 50;
232  static const uint32_t N_MEASUREMENTS = 1000000;
233 
235  virtual ~RngExponentialTestCase ();
236 
238 
239 private:
240  virtual void DoRun (void);
241 };
242 
244  : TestCase ("Exponential Random Number Generator")
245 {
246 }
247 
249 {
250 }
251 
252 double
254 {
255  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
256 
257  double range[N_BINS + 1];
258  FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
259  range[N_BINS] = std::numeric_limits<double>::max ();
260 
261  gsl_histogram_set_ranges (h, range, N_BINS + 1);
262 
263  double expected[N_BINS];
264 
265  double mu = 1.;
266 
267  for (uint32_t i = 0; i < N_BINS; ++i)
268  {
269  expected[i] = gsl_cdf_exponential_P (range[i + 1], mu) - gsl_cdf_exponential_P (range[i], mu);
270  expected[i] *= N_MEASUREMENTS;
271  }
272 
273  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
274  {
275  gsl_histogram_increment (h, e->GetValue ());
276  }
277 
278  double tmp[N_BINS];
279 
280  for (uint32_t i = 0; i < N_BINS; ++i)
281  {
282  tmp[i] = gsl_histogram_get (h, i);
283  tmp[i] -= expected[i];
284  tmp[i] *= tmp[i];
285  tmp[i] /= expected[i];
286  }
287 
288  gsl_histogram_free (h);
289 
290  double chiSquared = 0;
291 
292  for (uint32_t i = 0; i < N_BINS; ++i)
293  {
294  chiSquared += tmp[i];
295  }
296 
297  return chiSquared;
298 }
299 
300 void
302 {
303  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
304 
305  double sum = 0.;
306  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
307 
308  for (uint32_t i = 0; i < N_RUNS; ++i)
309  {
310  Ptr<ExponentialRandomVariable> e = CreateObject<ExponentialRandomVariable> ();
311  double result = ChiSquaredTest (e);
312  sum += result;
313  }
314 
315  sum /= (double)N_RUNS;
316 
317  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
318 }
319 
320 // ===========================================================================
321 // Test case for pareto distribution random number generator
322 // ===========================================================================
324 {
325 public:
326  static const uint32_t N_RUNS = 5;
327  static const uint32_t N_BINS = 50;
328  static const uint32_t N_MEASUREMENTS = 1000000;
329 
331  virtual ~RngParetoTestCase ();
332 
334 
335 private:
336  virtual void DoRun (void);
337 };
338 
340  : TestCase ("Pareto Random Number Generator")
341 {
342 }
343 
345 {
346 }
347 
348 double
350 {
351  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
352 
353  double range[N_BINS + 1];
354  FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
355  range[N_BINS] = std::numeric_limits<double>::max ();
356 
357  gsl_histogram_set_ranges (h, range, N_BINS + 1);
358 
359  double expected[N_BINS];
360 
361  double a = 1.5;
362  double b = 0.33333333;
363 
364  // mean is 1 with these values
365 
366  for (uint32_t i = 0; i < N_BINS; ++i)
367  {
368  expected[i] = gsl_cdf_pareto_P (range[i + 1], a, b) - gsl_cdf_pareto_P (range[i], a, b);
369  expected[i] *= N_MEASUREMENTS;
370  }
371 
372  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
373  {
374  gsl_histogram_increment (h, p->GetValue ());
375  }
376 
377  double tmp[N_BINS];
378 
379  for (uint32_t i = 0; i < N_BINS; ++i)
380  {
381  tmp[i] = gsl_histogram_get (h, i);
382  tmp[i] -= expected[i];
383  tmp[i] *= tmp[i];
384  tmp[i] /= expected[i];
385  }
386 
387  gsl_histogram_free (h);
388 
389  double chiSquared = 0;
390 
391  for (uint32_t i = 0; i < N_BINS; ++i)
392  {
393  chiSquared += tmp[i];
394  }
395 
396  return chiSquared;
397 }
398 
399 void
401 {
402  RngSeedManager::SetSeed (static_cast<uint32_t> (time (0)));
403 
404  double sum = 0.;
405  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
406 
407  for (uint32_t i = 0; i < N_RUNS; ++i)
408  {
409  Ptr<ParetoRandomVariable> e = CreateObject<ParetoRandomVariable> ();
410  e->SetAttribute ("Shape", DoubleValue (1.5));
411  double result = ChiSquaredTest (e);
412  sum += result;
413  }
414 
415  sum /= (double)N_RUNS;
416 
417  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
418 }
419 
420 class RngTestSuite : public TestSuite
421 {
422 public:
423  RngTestSuite ();
424 };
425 
427  : TestSuite ("random-number-generators", UNIT)
428 {
429  AddTestCase (new RngUniformTestCase, TestCase::QUICK);
430  AddTestCase (new RngNormalTestCase, TestCase::QUICK);
431  AddTestCase (new RngExponentialTestCase, TestCase::QUICK);
432  AddTestCase (new RngParetoTestCase, TestCase::QUICK);
433 }
434 
virtual void DoRun(void)
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< NormalRandomVariable > n)
double ChiSquaredTest(Ptr< UniformRandomVariable > u)
static const uint32_t N_RUNS
void FillHistoRangeUniformly(double *array, uint32_t n, double start, double end)
static const uint32_t N_MEASUREMENTS
A suite of tests to run.
Definition: test.h:1270
def start()
Definition: core.py:1482
double ChiSquaredTest(Ptr< ParetoRandomVariable > p)
virtual void DoRun(void)
Implementation to actually run this TestCase.
double GetValue(double mean, double shape, double bound)
Returns a random double from a Pareto distribution with the specified mean, shape, and upper bound.
double GetValue(double mean, double variance, double bound=NormalRandomVariable::INFINITE_VALUE)
Returns a random double from a normal distribution with the specified mean, variance, and bound.
static const uint32_t N_MEASUREMENTS
static RngTestSuite rngTestSuite
encapsulates test code
Definition: test.h:1102
virtual ~RngParetoTestCase()
static const uint32_t N_RUNS
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:184
static const uint32_t N_RUNS
virtual void DoRun(void)
Implementation to actually run this TestCase.
static const uint32_t N_MEASUREMENTS
static const uint32_t N_BINS
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double ChiSquaredTest(Ptr< ExponentialRandomVariable > n)
double GetValue(double min, double max)
Returns a random double from the uniform distribution with the specified range.
virtual void DoRun(void)
Implementation to actually run this TestCase.
static const uint32_t N_MEASUREMENTS
static const uint32_t N_BINS
static const uint32_t N_BINS
double GetValue(double mean, double bound)
Returns a random double from an exponential distribution with the specified mean and upper bound...
This class can be used to hold variables of floating point type such as 'double' or 'float'...
Definition: double.h:41
virtual ~RngNormalTestCase()
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:190
#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:772
static const uint32_t N_RUNS
virtual ~RngUniformTestCase()
static const uint32_t N_BINS