A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
rng-test-suite.cc
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/random-variable.h"
26 
27 using namespace ns3;
28 
29 void
30 FillHistoRangeUniformly (double *array, uint32_t n, double start, double end)
31 {
32  double increment = (end - start) / (n - 1.);
33  double d = start;
34 
35  for (uint32_t i = 0; i < n; ++i)
36  {
37  array[i] = d;
38  d += increment;
39  }
40 }
41 
42 // ===========================================================================
43 // Test case for uniform distribution random number generator
44 // ===========================================================================
46 {
47 public:
48  static const uint32_t N_RUNS = 5;
49  static const uint32_t N_BINS = 50;
50  static const uint32_t N_MEASUREMENTS = 1000000;
51 
53  virtual ~RngUniformTestCase ();
54 
55  double ChiSquaredTest (UniformVariable &u);
56 
57 private:
58  virtual void DoRun (void);
59 };
60 
61 RngUniformTestCase::RngUniformTestCase ()
62  : TestCase ("Uniform Random Number Generator")
63 {
64 }
65 
66 RngUniformTestCase::~RngUniformTestCase ()
67 {
68 }
69 
70 double
71 RngUniformTestCase::ChiSquaredTest (UniformVariable &u)
72 {
73  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
74  gsl_histogram_set_ranges_uniform (h, 0., 1.);
75 
76  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
77  {
78  gsl_histogram_increment (h, u.GetValue ());
79  }
80 
81  double tmp[N_BINS];
82 
83  double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
84 
85  for (uint32_t i = 0; i < N_BINS; ++i)
86  {
87  tmp[i] = gsl_histogram_get (h, i);
88  tmp[i] -= expected;
89  tmp[i] *= tmp[i];
90  tmp[i] /= expected;
91  }
92 
93  gsl_histogram_free (h);
94 
95  double chiSquared = 0;
96 
97  for (uint32_t i = 0; i < N_BINS; ++i)
98  {
99  chiSquared += tmp[i];
100  }
101 
102  return chiSquared;
103 }
104 
105 void
107 {
108  SeedManager::SetSeed (time (0));
109 
110  double sum = 0.;
111  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
112 
113  for (uint32_t i = 0; i < N_RUNS; ++i)
114  {
115  UniformVariable u;
116  double result = ChiSquaredTest (u);
117  sum += result;
118  }
119 
120  sum /= (double)N_RUNS;
121 
122  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
123 }
124 
125 // ===========================================================================
126 // Test case for normal distribution random number generator
127 // ===========================================================================
129 {
130 public:
131  static const uint32_t N_RUNS = 5;
132  static const uint32_t N_BINS = 50;
133  static const uint32_t N_MEASUREMENTS = 1000000;
134 
136  virtual ~RngNormalTestCase ();
137 
138  double ChiSquaredTest (NormalVariable &n);
139 
140 private:
141  virtual void DoRun (void);
142 };
143 
144 RngNormalTestCase::RngNormalTestCase ()
145  : TestCase ("Normal Random Number Generator")
146 {
147 }
148 
149 RngNormalTestCase::~RngNormalTestCase ()
150 {
151 }
152 
153 double
154 RngNormalTestCase::ChiSquaredTest (NormalVariable &n)
155 {
156  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
157 
158  double range[N_BINS + 1];
159  FillHistoRangeUniformly (range, N_BINS + 1, -4., 4.);
160  range[0] = -std::numeric_limits<double>::max ();
161  range[N_BINS] = std::numeric_limits<double>::max ();
162 
163  gsl_histogram_set_ranges (h, range, N_BINS + 1);
164 
165  double expected[N_BINS];
166 
167  double sigma = 1.;
168 
169  for (uint32_t i = 0; i < N_BINS; ++i)
170  {
171  expected[i] = gsl_cdf_gaussian_P (range[i + 1], sigma) - gsl_cdf_gaussian_P (range[i], sigma);
172  expected[i] *= N_MEASUREMENTS;
173  }
174 
175  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
176  {
177  gsl_histogram_increment (h, n.GetValue ());
178  }
179 
180  double tmp[N_BINS];
181 
182  for (uint32_t i = 0; i < N_BINS; ++i)
183  {
184  tmp[i] = gsl_histogram_get (h, i);
185  tmp[i] -= expected[i];
186  tmp[i] *= tmp[i];
187  tmp[i] /= expected[i];
188  }
189 
190  gsl_histogram_free (h);
191 
192  double chiSquared = 0;
193 
194  for (uint32_t i = 0; i < N_BINS; ++i)
195  {
196  chiSquared += tmp[i];
197  }
198 
199  return chiSquared;
200 }
201 
202 void
204 {
205  SeedManager::SetSeed (time (0));
206 
207  double sum = 0.;
208  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
209 
210  for (uint32_t i = 0; i < N_RUNS; ++i)
211  {
212  NormalVariable n;
213  double result = ChiSquaredTest (n);
214  sum += result;
215  }
216 
217  sum /= (double)N_RUNS;
218 
219  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
220 }
221 
222 // ===========================================================================
223 // Test case for exponential distribution random number generator
224 // ===========================================================================
226 {
227 public:
228  static const uint32_t N_RUNS = 5;
229  static const uint32_t N_BINS = 50;
230  static const uint32_t N_MEASUREMENTS = 1000000;
231 
233  virtual ~RngExponentialTestCase ();
234 
235  double ChiSquaredTest (ExponentialVariable &n);
236 
237 private:
238  virtual void DoRun (void);
239 };
240 
241 RngExponentialTestCase::RngExponentialTestCase ()
242  : TestCase ("Exponential Random Number Generator")
243 {
244 }
245 
246 RngExponentialTestCase::~RngExponentialTestCase ()
247 {
248 }
249 
250 double
251 RngExponentialTestCase::ChiSquaredTest (ExponentialVariable &e)
252 {
253  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
254 
255  double range[N_BINS + 1];
256  FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
257  range[N_BINS] = std::numeric_limits<double>::max ();
258 
259  gsl_histogram_set_ranges (h, range, N_BINS + 1);
260 
261  double expected[N_BINS];
262 
263  double mu = 1.;
264 
265  for (uint32_t i = 0; i < N_BINS; ++i)
266  {
267  expected[i] = gsl_cdf_exponential_P (range[i + 1], mu) - gsl_cdf_exponential_P (range[i], mu);
268  expected[i] *= N_MEASUREMENTS;
269  }
270 
271  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
272  {
273  gsl_histogram_increment (h, e.GetValue ());
274  }
275 
276  double tmp[N_BINS];
277 
278  for (uint32_t i = 0; i < N_BINS; ++i)
279  {
280  tmp[i] = gsl_histogram_get (h, i);
281  tmp[i] -= expected[i];
282  tmp[i] *= tmp[i];
283  tmp[i] /= expected[i];
284  }
285 
286  gsl_histogram_free (h);
287 
288  double chiSquared = 0;
289 
290  for (uint32_t i = 0; i < N_BINS; ++i)
291  {
292  chiSquared += tmp[i];
293  }
294 
295  return chiSquared;
296 }
297 
298 void
300 {
301  SeedManager::SetSeed (time (0));
302 
303  double sum = 0.;
304  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
305 
306  for (uint32_t i = 0; i < N_RUNS; ++i)
307  {
309  double result = ChiSquaredTest (e);
310  sum += result;
311  }
312 
313  sum /= (double)N_RUNS;
314 
315  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
316 }
317 
318 // ===========================================================================
319 // Test case for pareto distribution random number generator
320 // ===========================================================================
322 {
323 public:
324  static const uint32_t N_RUNS = 5;
325  static const uint32_t N_BINS = 50;
326  static const uint32_t N_MEASUREMENTS = 1000000;
327 
329  virtual ~RngParetoTestCase ();
330 
331  double ChiSquaredTest (ParetoVariable &p);
332 
333 private:
334  virtual void DoRun (void);
335 };
336 
337 RngParetoTestCase::RngParetoTestCase ()
338  : TestCase ("Pareto Random Number Generator")
339 {
340 }
341 
342 RngParetoTestCase::~RngParetoTestCase ()
343 {
344 }
345 
346 double
347 RngParetoTestCase::ChiSquaredTest (ParetoVariable &p)
348 {
349  gsl_histogram * h = gsl_histogram_alloc (N_BINS);
350 
351  double range[N_BINS + 1];
352  FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
353  range[N_BINS] = std::numeric_limits<double>::max ();
354 
355  gsl_histogram_set_ranges (h, range, N_BINS + 1);
356 
357  double expected[N_BINS];
358 
359  double a = 1.5;
360  double b = 0.33333333;
361 
362  for (uint32_t i = 0; i < N_BINS; ++i)
363  {
364  expected[i] = gsl_cdf_pareto_P (range[i + 1], a, b) - gsl_cdf_pareto_P (range[i], a, b);
365  expected[i] *= N_MEASUREMENTS;
366  }
367 
368  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
369  {
370  gsl_histogram_increment (h, p.GetValue ());
371  }
372 
373  double tmp[N_BINS];
374 
375  for (uint32_t i = 0; i < N_BINS; ++i)
376  {
377  tmp[i] = gsl_histogram_get (h, i);
378  tmp[i] -= expected[i];
379  tmp[i] *= tmp[i];
380  tmp[i] /= expected[i];
381  }
382 
383  gsl_histogram_free (h);
384 
385  double chiSquared = 0;
386 
387  for (uint32_t i = 0; i < N_BINS; ++i)
388  {
389  chiSquared += tmp[i];
390  }
391 
392  return chiSquared;
393 }
394 
395 void
397 {
398  SeedManager::SetSeed (time (0));
399 
400  double sum = 0.;
401  double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
402 
403  for (uint32_t i = 0; i < N_RUNS; ++i)
404  {
405  ParetoVariable e;
406  double result = ChiSquaredTest (e);
407  sum += result;
408  }
409 
410  sum /= (double)N_RUNS;
411 
412  NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
413 }
414 
415 class RngTestSuite : public TestSuite
416 {
417 public:
418  RngTestSuite ();
419 };
420 
421 RngTestSuite::RngTestSuite ()
422  : TestSuite ("random-number-generators", UNIT)
423 {
424  AddTestCase (new RngUniformTestCase, TestCase::QUICK);
425  AddTestCase (new RngNormalTestCase, TestCase::QUICK);
426  AddTestCase (new RngExponentialTestCase, TestCase::QUICK);
427  AddTestCase (new RngParetoTestCase, TestCase::QUICK);
428 }
429 
430 static RngTestSuite rngTestSuite;
virtual void DoRun(void)
Implementation to actually run this test case.
A suite of tests to run.
Definition: test.h:962
virtual void DoRun(void)
Implementation to actually run this test case.
ParetoVariable distributed random varThis class supports the creation of objects that return random n...
encapsulates test code
Definition: test.h:834
Class NormalVariable defines a random variable with a normal (Gaussian) distribution.This class supports the creation of objects that return random numbers from a fixed normal distribution. It also supports the generation of single random numbers from various normal distributions.
double GetValue(void) const
call RandomVariable::GetValue
The uniform distribution RNG for NS-3.This class supports the creation of objects that return random ...
virtual void DoRun(void)
Implementation to actually run this test case.
Exponentially Distributed random varThis class supports the creation of objects that return random nu...
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual test case to this test suite.
Definition: test.cc:172
virtual void DoRun(void)
Implementation to actually run this test case.
double GetValue(void) const
Returns a random double from the underlying distribution.