A Discrete-Event Network Simulator
API
random-variable-stream-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-12 University of Washington
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * This file is based on rng-test-suite.cc.
18  *
19  * Modified by Mitch Watrous <watrous@u.washington.edu>
20  *
21  */
22 
23 #include "ns3/boolean.h"
24 #include "ns3/double.h"
25 #include "ns3/integer.h"
26 #include "ns3/log.h"
27 #include "ns3/random-variable-stream.h"
28 #include "ns3/rng-seed-manager.h"
29 #include "ns3/string.h"
30 #include "ns3/test.h"
31 
32 #include <cmath>
33 #include <ctime>
34 #include <fstream>
35 #include <gsl/gsl_cdf.h>
36 #include <gsl/gsl_histogram.h>
37 #include <gsl/gsl_randist.h>
38 #include <gsl/gsl_sf_zeta.h>
39 
40 using namespace ns3;
41 
42 NS_LOG_COMPONENT_DEFINE("RandomVariableStreamGenerators");
43 
44 namespace ns3
45 {
46 
47 namespace test
48 {
49 
50 namespace RandomVariable
51 {
52 
63 class TestCaseBase : public TestCase
64 {
65  public:
67  static const uint32_t N_BINS{50};
69  static const uint32_t N_MEASUREMENTS{1000000};
71  static const uint32_t N_RUNS{5};
72 
77  TestCaseBase(std::string name)
78  : TestCase(name)
79  {
80  }
81 
93  std::vector<double> UniformHistogramBins(gsl_histogram* h,
94  double start,
95  double end,
96  bool underflow = true,
97  bool overflow = true) const
98  {
99  NS_LOG_FUNCTION(this << h << start << end);
100  std::size_t nBins = gsl_histogram_bins(h);
101  double increment = (end - start) / (nBins - 1.);
102  double d = start;
103 
104  std::vector<double> range(nBins + 1);
105 
106  for (auto& r : range)
107  {
108  r = d;
109  d += increment;
110  }
111  if (underflow)
112  {
113  range[0] = -std::numeric_limits<double>::max();
114  }
115  if (overflow)
116  {
117  range[nBins] = std::numeric_limits<double>::max();
118  }
119 
120  gsl_histogram_set_ranges(h, range.data(), nBins + 1);
121  return range;
122  }
123 
130  {
131  NS_LOG_FUNCTION(this << rng);
132  double sum = 0.0;
133  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
134  {
135  double value = rng->GetValue();
136  sum += value;
137  }
138  double valueMean = sum / N_MEASUREMENTS;
139  return valueMean;
140  }
141 
144  {
145  public:
150  virtual Ptr<RandomVariableStream> Create() const = 0;
151  };
152 
158  template <typename RNG>
160  {
161  public:
166  RngGenerator(bool anti = false)
167  : m_anti(anti)
168  {
169  }
170 
171  // Inherited
173  {
174  auto rng = CreateObject<RNG>();
175  rng->SetAttribute("Antithetic", BooleanValue(m_anti));
176  return rng;
177  }
178 
179  private:
181  bool m_anti;
182  };
183 
199  double ChiSquared(gsl_histogram* h,
200  const std::vector<double>& expected,
201  Ptr<RandomVariableStream> rng) const
202  {
203  NS_LOG_FUNCTION(this << h << expected.size() << rng);
204  NS_ASSERT_MSG(gsl_histogram_bins(h) == expected.size(),
205  "Histogram and expected vector have different sizes.");
206 
207  // Sample the rng into the histogram
208  for (std::size_t i = 0; i < N_MEASUREMENTS; ++i)
209  {
210  double value = rng->GetValue();
211  gsl_histogram_increment(h, value);
212  }
213 
214  // Compute the chi square value
215  double chiSquared = 0;
216  std::size_t nBins = gsl_histogram_bins(h);
217  for (std::size_t i = 0; i < nBins; ++i)
218  {
219  double hbin = gsl_histogram_get(h, i);
220  double tmp = hbin - expected[i];
221  tmp *= tmp;
222  tmp /= expected[i];
223  chiSquared += tmp;
224  }
225 
226  return chiSquared;
227  }
228 
259  virtual double ChiSquaredTest(Ptr<RandomVariableStream> rng) const
260  {
261  return 0;
262  }
263 
272  double ChiSquaredsAverage(const RngGeneratorBase* generator, std::size_t nRuns) const
273  {
274  NS_LOG_FUNCTION(this << generator << nRuns);
275 
276  double sum = 0.;
277  for (std::size_t i = 0; i < nRuns; ++i)
278  {
279  auto rng = generator->Create();
280  double result = ChiSquaredTest(rng);
281  sum += result;
282  }
283  sum /= (double)nRuns;
284  return sum;
285  }
286 
319  {
320  if (!m_seedSet)
321  {
322  uint32_t seed;
323  if (RngSeedManager::GetRun() == 0)
324  {
325  seed = static_cast<uint32_t>(time(nullptr));
326  m_seedSet = true;
327  NS_LOG_DEBUG(
328  "Special run number value of zero; seeding with time of day: " << seed);
329  }
330  else
331  {
332  seed = RngSeedManager::GetSeed();
333  m_seedSet = true;
334  NS_LOG_DEBUG("Using the values seed: " << seed
335  << " and run: " << RngSeedManager::GetRun());
336  }
337  SeedManager::SetSeed(seed);
338  }
339  }
340 
341  private:
343  bool m_seedSet = false;
344 
345 }; // class TestCaseBase
346 
352 {
353  public:
354  // Constructor
355  UniformTestCase();
356 
357  // Inherited
358  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
359 
360  private:
361  // Inherited
362  void DoRun() override;
363 };
364 
366  : TestCaseBase("Uniform Random Variable Stream Generator")
367 {
368 }
369 
370 double
372 {
373  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
374 
375  // Note that this assumes that the range for u is [0,1], which is
376  // the default range for this distribution.
377  gsl_histogram_set_ranges_uniform(h, 0., 1.);
378 
379  std::vector<double> expected(N_BINS, ((double)N_MEASUREMENTS / (double)N_BINS));
380 
381  double chiSquared = ChiSquared(h, expected, rng);
382  gsl_histogram_free(h);
383  return chiSquared;
384 }
385 
386 void
388 {
389  NS_LOG_FUNCTION(this);
391 
392  double confidence = 0.99;
393  double maxStatistic = gsl_cdf_chisq_Pinv(confidence, (N_BINS - 1));
394  NS_LOG_DEBUG("Chi square required at " << confidence << " confidence for " << N_BINS
395  << " bins is " << maxStatistic);
396 
397  double result = maxStatistic;
398  // If chi-squared test fails, re-try it up to N_RUNS times
399  for (uint32_t i = 0; i < N_RUNS; ++i)
400  {
401  Ptr<UniformRandomVariable> rng = CreateObject<UniformRandomVariable>();
402  result = ChiSquaredTest(rng);
403  NS_LOG_DEBUG("Chi square result is " << result);
404  if (result < maxStatistic)
405  {
406  break;
407  }
408  }
409 
410  NS_TEST_ASSERT_MSG_LT(result, maxStatistic, "Chi-squared statistic out of range");
411 
412  double min = 0.0;
413  double max = 10.0;
414  double value;
415 
416  // Create the RNG with the specified range.
417  Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
418 
419  x->SetAttribute("Min", DoubleValue(min));
420  x->SetAttribute("Max", DoubleValue(max));
421 
422  // Test that values are always within the range:
423  //
424  // [min, max)
425  //
426  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
427  {
428  value = x->GetValue();
429  NS_TEST_ASSERT_MSG_EQ((value >= min), true, "Value less than minimum.");
430  NS_TEST_ASSERT_MSG_LT(value, max, "Value greater than or equal to maximum.");
431  }
432 
433  // Boundary checking on GetInteger; should be [min,max]; from bug 1964
434  static const uint32_t UNIFORM_INTEGER_MIN{0};
435  static const uint32_t UNIFORM_INTEGER_MAX{4294967295U};
436  // [0,0] should return 0
437  uint32_t intValue;
438  intValue = x->GetInteger(UNIFORM_INTEGER_MIN, UNIFORM_INTEGER_MIN);
439  NS_TEST_ASSERT_MSG_EQ(intValue, UNIFORM_INTEGER_MIN, "Uniform RV GetInteger boundary testing");
440  // [UNIFORM_INTEGER_MAX, UNIFORM_INTEGER_MAX] should return UNIFORM_INTEGER_MAX
441  intValue = x->GetInteger(UNIFORM_INTEGER_MAX, UNIFORM_INTEGER_MAX);
442  NS_TEST_ASSERT_MSG_EQ(intValue, UNIFORM_INTEGER_MAX, "Uniform RV GetInteger boundary testing");
443  // [0,1] should return mix of 0 or 1
444  intValue = 0;
445  for (int i = 0; i < 20; i++)
446  {
447  intValue += x->GetInteger(UNIFORM_INTEGER_MIN, UNIFORM_INTEGER_MIN + 1);
448  }
449  NS_TEST_ASSERT_MSG_GT(intValue, 0, "Uniform RV GetInteger boundary testing");
450  NS_TEST_ASSERT_MSG_LT(intValue, 20, "Uniform RV GetInteger boundary testing");
451  // [MAX-1,MAX] should return mix of MAX-1 or MAX
452  uint32_t count = 0;
453  for (int i = 0; i < 20; i++)
454  {
455  intValue = x->GetInteger(UNIFORM_INTEGER_MAX - 1, UNIFORM_INTEGER_MAX);
456  if (intValue == UNIFORM_INTEGER_MAX)
457  {
458  count++;
459  }
460  }
461  NS_TEST_ASSERT_MSG_GT(count, 0, "Uniform RV GetInteger boundary testing");
462  NS_TEST_ASSERT_MSG_LT(count, 20, "Uniform RV GetInteger boundary testing");
463  // multiple [0,UNIFORM_INTEGER_MAX] should return non-zero
464  intValue = x->GetInteger(UNIFORM_INTEGER_MIN, UNIFORM_INTEGER_MAX);
465  uint32_t intValue2 = x->GetInteger(UNIFORM_INTEGER_MIN, UNIFORM_INTEGER_MAX);
466  NS_TEST_ASSERT_MSG_GT(intValue + intValue2, 0, "Uniform RV GetInteger boundary testing");
467 }
468 
474 {
475  public:
476  // Constructor
478 
479  // Inherited
480  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
481 
482  private:
483  // Inherited
484  void DoRun() override;
485 };
486 
488  : TestCaseBase("Antithetic Uniform Random Variable Stream Generator")
489 {
490 }
491 
492 double
494 {
495  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
496 
497  // Note that this assumes that the range for u is [0,1], which is
498  // the default range for this distribution.
499  gsl_histogram_set_ranges_uniform(h, 0., 1.);
500 
501  std::vector<double> expected(N_BINS, ((double)N_MEASUREMENTS / (double)N_BINS));
502 
503  double chiSquared = ChiSquared(h, expected, rng);
504  gsl_histogram_free(h);
505  return chiSquared;
506 }
507 
508 void
510 {
511  NS_LOG_FUNCTION(this);
513 
514  auto generator = RngGenerator<UniformRandomVariable>(true);
515  double sum = ChiSquaredsAverage(&generator, N_RUNS);
516  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
517  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
518 
519  double min = 0.0;
520  double max = 10.0;
521  double value;
522 
523  // Create the RNG with the specified range.
524  Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
525 
526  // Make this generate antithetic values.
527  x->SetAttribute("Antithetic", BooleanValue(true));
528 
529  x->SetAttribute("Min", DoubleValue(min));
530  x->SetAttribute("Max", DoubleValue(max));
531 
532  // Test that values are always within the range:
533  //
534  // [min, max)
535  //
536  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
537  {
538  value = x->GetValue();
539  NS_TEST_ASSERT_MSG_EQ((value >= min), true, "Value less than minimum.");
540  NS_TEST_ASSERT_MSG_LT(value, max, "Value greater than or equal to maximum.");
541  }
542 }
543 
549 {
550  public:
551  // Constructor
553 
554  private:
555  // Inherited
556  void DoRun() override;
557 
559  static constexpr double TOLERANCE{1e-8};
560 };
561 
563  : TestCaseBase("Constant Random Variable Stream Generator")
564 {
565 }
566 
567 void
569 {
570  NS_LOG_FUNCTION(this);
572 
573  Ptr<ConstantRandomVariable> c = CreateObject<ConstantRandomVariable>();
574 
575  double constant;
576 
577  // Test that the constant value can be changed using its attribute.
578  constant = 10.0;
579  c->SetAttribute("Constant", DoubleValue(constant));
580  NS_TEST_ASSERT_MSG_EQ_TOL(c->GetValue(), constant, TOLERANCE, "Constant value changed");
581  c->SetAttribute("Constant", DoubleValue(20.0));
582  NS_TEST_ASSERT_MSG_NE(c->GetValue(), constant, "Constant value not changed");
583 
584  // Test that the constant value does not change.
585  constant = c->GetValue();
586  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
587  {
589  constant,
590  TOLERANCE,
591  "Constant value changed in loop");
592  }
593 }
594 
600 {
601  public:
602  // Constructor
604 
605  private:
606  // Inherited
607  void DoRun() override;
608 
610  static constexpr double TOLERANCE{1e-8};
611 };
612 
614  : TestCaseBase("Sequential Random Variable Stream Generator")
615 {
616 }
617 
618 void
620 {
621  NS_LOG_FUNCTION(this);
623 
624  Ptr<SequentialRandomVariable> s = CreateObject<SequentialRandomVariable>();
625 
626  // The following four attributes should give the sequence
627  //
628  // 4, 4, 7, 7, 10, 10
629  //
630  s->SetAttribute("Min", DoubleValue(4));
631  s->SetAttribute("Max", DoubleValue(11));
632  s->SetAttribute("Increment", StringValue("ns3::UniformRandomVariable[Min=3.0|Max=3.0]"));
633  s->SetAttribute("Consecutive", IntegerValue(2));
634 
635  double value;
636 
637  // Test that the sequencet is correct.
638  value = s->GetValue();
639  NS_TEST_ASSERT_MSG_EQ_TOL(value, 4, TOLERANCE, "Sequence value 1 wrong.");
640  value = s->GetValue();
641  NS_TEST_ASSERT_MSG_EQ_TOL(value, 4, TOLERANCE, "Sequence value 2 wrong.");
642  value = s->GetValue();
643  NS_TEST_ASSERT_MSG_EQ_TOL(value, 7, TOLERANCE, "Sequence value 3 wrong.");
644  value = s->GetValue();
645  NS_TEST_ASSERT_MSG_EQ_TOL(value, 7, TOLERANCE, "Sequence value 4 wrong.");
646  value = s->GetValue();
647  NS_TEST_ASSERT_MSG_EQ_TOL(value, 10, TOLERANCE, "Sequence value 5 wrong.");
648  value = s->GetValue();
649  NS_TEST_ASSERT_MSG_EQ_TOL(value, 10, TOLERANCE, "Sequence value 6 wrong.");
650 }
651 
657 {
658  public:
659  // Constructor
660  NormalTestCase();
661 
662  // Inherited
663  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
664 
665  private:
666  // Inherited
667  void DoRun() override;
668 
670  static constexpr double TOLERANCE{5};
671 };
672 
674  : TestCaseBase("Normal Random Variable Stream Generator")
675 {
676 }
677 
678 double
680 {
681  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
682  auto range = UniformHistogramBins(h, -4., 4.);
683 
684  std::vector<double> expected(N_BINS);
685 
686  // Note that this assumes that n has mean equal to zero and standard
687  // deviation equal to one, which are their default values for this
688  // distribution.
689  double sigma = 1.;
690 
691  for (std::size_t i = 0; i < N_BINS; ++i)
692  {
693  expected[i] = gsl_cdf_gaussian_P(range[i + 1], sigma) - gsl_cdf_gaussian_P(range[i], sigma);
694  expected[i] *= N_MEASUREMENTS;
695  }
696 
697  double chiSquared = ChiSquared(h, expected, rng);
698  gsl_histogram_free(h);
699  return chiSquared;
700 }
701 
702 void
704 {
705  NS_LOG_FUNCTION(this);
707 
708  auto generator = RngGenerator<NormalRandomVariable>();
709  auto rng = generator.Create();
710 
711  double sum = ChiSquaredsAverage(&generator, N_RUNS);
712  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
713  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
714 
715  double mean = 5.0;
716  double variance = 2.0;
717 
718  // Create the RNG with the specified range.
719  Ptr<NormalRandomVariable> x = CreateObject<NormalRandomVariable>();
720  x->SetAttribute("Mean", DoubleValue(mean));
721  x->SetAttribute("Variance", DoubleValue(variance));
722 
723  // Calculate the mean of these values.
724  double valueMean = Average(x);
725 
726  // The expected value for the mean of the values returned by a
727  // normally distributed random variable is equal to mean.
728  double expectedMean = mean;
729  double expectedRms = mean / std::sqrt(variance * N_MEASUREMENTS);
730 
731  // Test that values have approximately the right mean value.
732  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
733  expectedMean,
734  expectedRms * TOLERANCE,
735  "Wrong mean value.");
736 }
737 
743 {
744  public:
745  // Constructor
747 
748  // Inherited
749  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
750 
751  private:
752  // Inherited
753  void DoRun() override;
754 
756  static constexpr double TOLERANCE{5};
757 };
758 
760  : TestCaseBase("Antithetic Normal Random Variable Stream Generator")
761 {
762 }
763 
764 double
766 {
767  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
768  auto range = UniformHistogramBins(h, -4, 4);
769 
770  std::vector<double> expected(N_BINS);
771 
772  // Note that this assumes that n has mean equal to zero and standard
773  // deviation equal to one, which are their default values for this
774  // distribution.
775  double sigma = 1.;
776 
777  for (std::size_t i = 0; i < N_BINS; ++i)
778  {
779  expected[i] = gsl_cdf_gaussian_P(range[i + 1], sigma) - gsl_cdf_gaussian_P(range[i], sigma);
780  expected[i] *= N_MEASUREMENTS;
781  }
782 
783  double chiSquared = ChiSquared(h, expected, rng);
784 
785  gsl_histogram_free(h);
786  return chiSquared;
787 }
788 
789 void
791 {
792  NS_LOG_FUNCTION(this);
794 
795  auto generator = RngGenerator<NormalRandomVariable>(true);
796  double sum = ChiSquaredsAverage(&generator, N_RUNS);
797  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
798  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
799 
800  double mean = 5.0;
801  double variance = 2.0;
802 
803  // Create the RNG with the specified range.
804  Ptr<NormalRandomVariable> x = CreateObject<NormalRandomVariable>();
805  x->SetAttribute("Mean", DoubleValue(mean));
806  x->SetAttribute("Variance", DoubleValue(variance));
807 
808  // Make this generate antithetic values.
809  x->SetAttribute("Antithetic", BooleanValue(true));
810 
811  // Calculate the mean of these values.
812  double valueMean = Average(x);
813 
814  // The expected value for the mean of the values returned by a
815  // normally distributed random variable is equal to mean.
816  double expectedMean = mean;
817  double expectedRms = mean / std::sqrt(variance * N_MEASUREMENTS);
818 
819  // Test that values have approximately the right mean value.
820  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
821  expectedMean,
822  expectedRms * TOLERANCE,
823  "Wrong mean value.");
824 }
825 
831 {
832  public:
833  // Constructor
835 
836  // Inherited
837  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
838 
839  private:
840  // Inherited
841  void DoRun() override;
842 
844  static constexpr double TOLERANCE{5};
845 };
846 
848  : TestCaseBase("Exponential Random Variable Stream Generator")
849 {
850 }
851 
852 double
854 {
855  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
856  auto range = UniformHistogramBins(h, 0, 10, false);
857 
858  std::vector<double> expected(N_BINS);
859 
860  // Note that this assumes that e has mean equal to one, which is the
861  // default value for this distribution.
862  double mu = 1.;
863 
864  for (std::size_t i = 0; i < N_BINS; ++i)
865  {
866  expected[i] = gsl_cdf_exponential_P(range[i + 1], mu) - gsl_cdf_exponential_P(range[i], mu);
867  expected[i] *= N_MEASUREMENTS;
868  }
869 
870  double chiSquared = ChiSquared(h, expected, rng);
871 
872  gsl_histogram_free(h);
873  return chiSquared;
874 }
875 
876 void
878 {
879  NS_LOG_FUNCTION(this);
881 
882  auto generator = RngGenerator<ExponentialRandomVariable>();
883  double sum = ChiSquaredsAverage(&generator, N_RUNS);
884  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
885  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
886 
887  double mean = 3.14;
888  double bound = 0.0;
889 
890  // Create the RNG with the specified range.
891  Ptr<ExponentialRandomVariable> x = CreateObject<ExponentialRandomVariable>();
892  x->SetAttribute("Mean", DoubleValue(mean));
893  x->SetAttribute("Bound", DoubleValue(bound));
894 
895  // Calculate the mean of these values.
896  double valueMean = Average(x);
897  double expectedMean = mean;
898  double expectedRms = std::sqrt(mean / N_MEASUREMENTS);
899 
900  // Test that values have approximately the right mean value.
901  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
902  expectedMean,
903  expectedRms * TOLERANCE,
904  "Wrong mean value.");
905 }
906 
912 {
913  public:
914  // Constructor
916 
917  // Inherited
918  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
919 
920  private:
921  // Inherited
922  void DoRun() override;
923 
925  static constexpr double TOLERANCE{5};
926 };
927 
929  : TestCaseBase("Antithetic Exponential Random Variable Stream Generator")
930 {
931 }
932 
933 double
935 {
936  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
937  auto range = UniformHistogramBins(h, 0, 10, false);
938 
939  std::vector<double> expected(N_BINS);
940 
941  // Note that this assumes that e has mean equal to one, which is the
942  // default value for this distribution.
943  double mu = 1.;
944 
945  for (std::size_t i = 0; i < N_BINS; ++i)
946  {
947  expected[i] = gsl_cdf_exponential_P(range[i + 1], mu) - gsl_cdf_exponential_P(range[i], mu);
948  expected[i] *= N_MEASUREMENTS;
949  }
950 
951  double chiSquared = ChiSquared(h, expected, rng);
952 
953  gsl_histogram_free(h);
954  return chiSquared;
955 }
956 
957 void
959 {
960  NS_LOG_FUNCTION(this);
962 
963  auto generator = RngGenerator<ExponentialRandomVariable>(true);
964  double sum = ChiSquaredsAverage(&generator, N_RUNS);
965  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
966  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
967 
968  double mean = 3.14;
969  double bound = 0.0;
970 
971  // Create the RNG with the specified range.
972  Ptr<ExponentialRandomVariable> x = CreateObject<ExponentialRandomVariable>();
973  x->SetAttribute("Mean", DoubleValue(mean));
974  x->SetAttribute("Bound", DoubleValue(bound));
975 
976  // Make this generate antithetic values.
977  x->SetAttribute("Antithetic", BooleanValue(true));
978 
979  // Calculate the mean of these values.
980  double valueMean = Average(x);
981  double expectedMean = mean;
982  double expectedRms = std::sqrt(mean / N_MEASUREMENTS);
983 
984  // Test that values have approximately the right mean value.
985  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
986  expectedMean,
987  expectedRms * TOLERANCE,
988  "Wrong mean value.");
989 }
990 
996 {
997  public:
998  // Constructor
999  ParetoTestCase();
1000 
1001  // Inherited
1002  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1003 
1004  private:
1005  // Inherited
1006  void DoRun() override;
1007 
1012  static constexpr double TOLERANCE{1e-2};
1013 };
1014 
1016  : TestCaseBase("Pareto Random Variable Stream Generator")
1017 {
1018 }
1019 
1020 double
1022 {
1023  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1024  auto range = UniformHistogramBins(h, 1, 10, false);
1025 
1026  std::vector<double> expected(N_BINS);
1027 
1028  double shape = 2.0;
1029  double scale = 1.0;
1030 
1031  for (std::size_t i = 0; i < N_BINS; ++i)
1032  {
1033  expected[i] =
1034  gsl_cdf_pareto_P(range[i + 1], shape, scale) - gsl_cdf_pareto_P(range[i], shape, scale);
1035  expected[i] *= N_MEASUREMENTS;
1036  }
1037 
1038  double chiSquared = ChiSquared(h, expected, rng);
1039 
1040  gsl_histogram_free(h);
1041  return chiSquared;
1042 }
1043 
1044 void
1046 {
1047  NS_LOG_FUNCTION(this);
1048  SetTestSuiteSeed();
1049 
1050  auto generator = RngGenerator<ParetoRandomVariable>();
1051  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1052  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1053  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1054 
1055  double shape = 2.0;
1056  double scale = 1.0;
1057 
1058  // Create the RNG with the specified range.
1059  Ptr<ParetoRandomVariable> x = CreateObject<ParetoRandomVariable>();
1060  x->SetAttribute("Shape", DoubleValue(shape));
1061  x->SetAttribute("Scale", DoubleValue(scale));
1062 
1063  // Calculate the mean of these values.
1064  double valueMean = Average(x);
1065 
1066  // The expected value for the mean is given by
1067  //
1068  // shape * scale
1069  // E[value] = --------------- ,
1070  // shape - 1
1071  //
1072  // where
1073  //
1074  // scale = mean * (shape - 1.0) / shape .
1075  double expectedMean = (shape * scale) / (shape - 1.0);
1076 
1077  // Test that values have approximately the right mean value.
1078  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1079  expectedMean,
1080  expectedMean * TOLERANCE,
1081  "Wrong mean value.");
1082 }
1083 
1089 {
1090  public:
1091  // Constructor
1093 
1094  // Inherited
1095  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1096 
1097  private:
1098  // Inherited
1099  void DoRun() override;
1100 
1105  static constexpr double TOLERANCE{1e-2};
1106 };
1107 
1109  : TestCaseBase("Antithetic Pareto Random Variable Stream Generator")
1110 {
1111 }
1112 
1113 double
1115 {
1116  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1117  auto range = UniformHistogramBins(h, 1, 10, false);
1118 
1119  std::vector<double> expected(N_BINS);
1120 
1121  double shape = 2.0;
1122  double scale = 1.0;
1123 
1124  for (std::size_t i = 0; i < N_BINS; ++i)
1125  {
1126  expected[i] =
1127  gsl_cdf_pareto_P(range[i + 1], shape, scale) - gsl_cdf_pareto_P(range[i], shape, scale);
1128  expected[i] *= N_MEASUREMENTS;
1129  }
1130 
1131  double chiSquared = ChiSquared(h, expected, rng);
1132 
1133  gsl_histogram_free(h);
1134  return chiSquared;
1135 }
1136 
1137 void
1139 {
1140  NS_LOG_FUNCTION(this);
1141  SetTestSuiteSeed();
1142 
1143  auto generator = RngGenerator<ParetoRandomVariable>(true);
1144  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1145  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1146  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1147 
1148  double shape = 2.0;
1149  double scale = 1.0;
1150 
1151  // Create the RNG with the specified range.
1152  Ptr<ParetoRandomVariable> x = CreateObject<ParetoRandomVariable>();
1153  x->SetAttribute("Shape", DoubleValue(shape));
1154  x->SetAttribute("Scale", DoubleValue(scale));
1155 
1156  // Make this generate antithetic values.
1157  x->SetAttribute("Antithetic", BooleanValue(true));
1158 
1159  // Calculate the mean of these values.
1160  double valueMean = Average(x);
1161 
1162  // The expected value for the mean is given by
1163  //
1164  // shape * scale
1165  // E[value] = --------------- ,
1166  // shape - 1
1167  //
1168  // where
1169  //
1170  // scale = mean * (shape - 1.0) / shape .
1171  //
1172  double expectedMean = (shape * scale) / (shape - 1.0);
1173 
1174  // Test that values have approximately the right mean value.
1175  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1176  expectedMean,
1177  expectedMean * TOLERANCE,
1178  "Wrong mean value.");
1179 }
1180 
1186 {
1187  public:
1188  // Constructor
1189  WeibullTestCase();
1190 
1191  // Inherited
1192  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1193 
1194  private:
1195  // Inherited
1196  void DoRun() override;
1197 
1202  static constexpr double TOLERANCE{1e-2};
1203 };
1204 
1206  : TestCaseBase("Weibull Random Variable Stream Generator")
1207 {
1208 }
1209 
1210 double
1212 {
1213  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1214  auto range = UniformHistogramBins(h, 1, 10, false);
1215 
1216  std::vector<double> expected(N_BINS);
1217 
1218  // Note that this assumes that p has shape equal to one and scale
1219  // equal to one, which are their default values for this
1220  // distribution.
1221  double a = 1.0;
1222  double b = 1.0;
1223 
1224  for (std::size_t i = 0; i < N_BINS; ++i)
1225  {
1226  expected[i] = gsl_cdf_weibull_P(range[i + 1], a, b) - gsl_cdf_weibull_P(range[i], a, b);
1227  expected[i] *= N_MEASUREMENTS;
1228  NS_LOG_INFO("weibull: " << expected[i]);
1229  }
1230 
1231  double chiSquared = ChiSquared(h, expected, rng);
1232 
1233  gsl_histogram_free(h);
1234  return chiSquared;
1235 }
1236 
1237 void
1239 {
1240  NS_LOG_FUNCTION(this);
1241  SetTestSuiteSeed();
1242 
1243  auto generator = RngGenerator<WeibullRandomVariable>();
1244  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1245  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1246  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1247 
1248  double scale = 5.0;
1249  double shape = 1.0;
1250 
1251  // Create the RNG with the specified range.
1252  Ptr<WeibullRandomVariable> x = CreateObject<WeibullRandomVariable>();
1253  x->SetAttribute("Scale", DoubleValue(scale));
1254  x->SetAttribute("Shape", DoubleValue(shape));
1255 
1256  // Calculate the mean of these values.
1257  double valueMean = Average(x);
1258 
1259  // The expected value for the mean of the values returned by a
1260  // Weibull distributed random variable is
1261  //
1262  // E[value] = scale * Gamma(1 + 1 / shape) ,
1263  //
1264  // where Gamma() is the Gamma function. Note that
1265  //
1266  // Gamma(n) = (n - 1)!
1267  //
1268  // if n is a positive integer.
1269  //
1270  // For this test,
1271  //
1272  // Gamma(1 + 1 / shape) = Gamma(1 + 1 / 1)
1273  // = Gamma(2)
1274  // = (2 - 1)!
1275  // = 1
1276  //
1277  // which means
1278  //
1279  // E[value] = scale .
1280  //
1281  double expectedMean = scale;
1282 
1283  // Test that values have approximately the right mean value.
1284  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1285  expectedMean,
1286  expectedMean * TOLERANCE,
1287  "Wrong mean value.");
1288 }
1289 
1295 {
1296  public:
1297  // Constructor
1299 
1300  // Inherited
1301  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1302 
1303  private:
1304  // Inherited
1305  void DoRun() override;
1306 
1311  static constexpr double TOLERANCE{1e-2};
1312 };
1313 
1315  : TestCaseBase("Antithetic Weibull Random Variable Stream Generator")
1316 {
1317 }
1318 
1319 double
1321 {
1322  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1323  auto range = UniformHistogramBins(h, 1, 10, false);
1324 
1325  std::vector<double> expected(N_BINS);
1326 
1327  // Note that this assumes that p has shape equal to one and scale
1328  // equal to one, which are their default values for this
1329  // distribution.
1330  double a = 1.0;
1331  double b = 1.0;
1332 
1333  for (std::size_t i = 0; i < N_BINS; ++i)
1334  {
1335  expected[i] = gsl_cdf_weibull_P(range[i + 1], a, b) - gsl_cdf_weibull_P(range[i], a, b);
1336  expected[i] *= N_MEASUREMENTS;
1337  }
1338 
1339  double chiSquared = ChiSquared(h, expected, rng);
1340 
1341  gsl_histogram_free(h);
1342  return chiSquared;
1343 }
1344 
1345 void
1347 {
1348  NS_LOG_FUNCTION(this);
1349  SetTestSuiteSeed();
1350 
1351  auto generator = RngGenerator<WeibullRandomVariable>(true);
1352  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1353  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1354  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1355 
1356  double scale = 5.0;
1357  double shape = 1.0;
1358 
1359  // Create the RNG with the specified range.
1360  Ptr<WeibullRandomVariable> x = CreateObject<WeibullRandomVariable>();
1361  x->SetAttribute("Scale", DoubleValue(scale));
1362  x->SetAttribute("Shape", DoubleValue(shape));
1363 
1364  // Make this generate antithetic values.
1365  x->SetAttribute("Antithetic", BooleanValue(true));
1366 
1367  // Calculate the mean of these values.
1368  double valueMean = Average(x);
1369 
1370  // The expected value for the mean of the values returned by a
1371  // Weibull distributed random variable is
1372  //
1373  // E[value] = scale * Gamma(1 + 1 / shape) ,
1374  //
1375  // where Gamma() is the Gamma function. Note that
1376  //
1377  // Gamma(n) = (n - 1)!
1378  //
1379  // if n is a positive integer.
1380  //
1381  // For this test,
1382  //
1383  // Gamma(1 + 1 / shape) = Gamma(1 + 1 / 1)
1384  // = Gamma(2)
1385  // = (2 - 1)!
1386  // = 1
1387  //
1388  // which means
1389  //
1390  // E[value] = scale .
1391  //
1392  double expectedMean = scale;
1393 
1394  // Test that values have approximately the right mean value.
1395  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1396  expectedMean,
1397  expectedMean * TOLERANCE,
1398  "Wrong mean value.");
1399 }
1400 
1406 {
1407  public:
1408  // Constructor
1410 
1411  // Inherited
1412  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1413 
1414  private:
1415  // Inherited
1416  void DoRun() override;
1417 
1422  static constexpr double TOLERANCE{3e-2};
1423 };
1424 
1426  : TestCaseBase("Log-Normal Random Variable Stream Generator")
1427 {
1428 }
1429 
1430 double
1432 {
1433  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1434  auto range = UniformHistogramBins(h, 0, 10, false);
1435 
1436  std::vector<double> expected(N_BINS);
1437 
1438  // Note that this assumes that n has mu equal to zero and sigma
1439  // equal to one, which are their default values for this
1440  // distribution.
1441  double mu = 0.0;
1442  double sigma = 1.0;
1443 
1444  for (std::size_t i = 0; i < N_BINS; ++i)
1445  {
1446  expected[i] =
1447  gsl_cdf_lognormal_P(range[i + 1], mu, sigma) - gsl_cdf_lognormal_P(range[i], mu, sigma);
1448  expected[i] *= N_MEASUREMENTS;
1449  }
1450 
1451  double chiSquared = ChiSquared(h, expected, rng);
1452 
1453  gsl_histogram_free(h);
1454  return chiSquared;
1455 }
1456 
1457 void
1459 {
1460  NS_LOG_FUNCTION(this);
1461  SetTestSuiteSeed();
1462 
1463  auto generator = RngGenerator<LogNormalRandomVariable>();
1464  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1465  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1466 
1467  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1468 
1469  double mu = 5.0;
1470  double sigma = 2.0;
1471 
1472  // Create the RNG with the specified range.
1473  Ptr<LogNormalRandomVariable> x = CreateObject<LogNormalRandomVariable>();
1474  x->SetAttribute("Mu", DoubleValue(mu));
1475  x->SetAttribute("Sigma", DoubleValue(sigma));
1476 
1477  // Calculate the mean of these values.
1478  double valueMean = Average(x);
1479 
1480  // The expected value for the mean of the values returned by a
1481  // log-normally distributed random variable is equal to
1482  //
1483  // 2
1484  // mu + sigma / 2
1485  // E[value] = e .
1486  //
1487  double expectedMean = std::exp(mu + sigma * sigma / 2.0);
1488 
1489  // Test that values have approximately the right mean value.
1490  //
1497  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1498  expectedMean,
1499  expectedMean * TOLERANCE,
1500  "Wrong mean value.");
1501 }
1502 
1508 {
1509  public:
1510  // Constructor
1512 
1513  // Inherited
1514  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1515 
1516  private:
1517  // Inherited
1518  void DoRun() override;
1519 
1524  static constexpr double TOLERANCE{3e-2};
1525 };
1526 
1528  : TestCaseBase("Antithetic Log-Normal Random Variable Stream Generator")
1529 {
1530 }
1531 
1532 double
1534 {
1535  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1536  auto range = UniformHistogramBins(h, 0, 10, false);
1537 
1538  std::vector<double> expected(N_BINS);
1539 
1540  // Note that this assumes that n has mu equal to zero and sigma
1541  // equal to one, which are their default values for this
1542  // distribution.
1543  double mu = 0.0;
1544  double sigma = 1.0;
1545 
1546  for (std::size_t i = 0; i < N_BINS; ++i)
1547  {
1548  expected[i] =
1549  gsl_cdf_lognormal_P(range[i + 1], mu, sigma) - gsl_cdf_lognormal_P(range[i], mu, sigma);
1550  expected[i] *= N_MEASUREMENTS;
1551  }
1552 
1553  double chiSquared = ChiSquared(h, expected, rng);
1554 
1555  gsl_histogram_free(h);
1556  return chiSquared;
1557 }
1558 
1559 void
1561 {
1562  NS_LOG_FUNCTION(this);
1563  SetTestSuiteSeed();
1564 
1565  auto generator = RngGenerator<LogNormalRandomVariable>(true);
1566  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1567  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1568  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1569 
1570  double mu = 5.0;
1571  double sigma = 2.0;
1572 
1573  // Create the RNG with the specified range.
1574  Ptr<LogNormalRandomVariable> x = CreateObject<LogNormalRandomVariable>();
1575  x->SetAttribute("Mu", DoubleValue(mu));
1576  x->SetAttribute("Sigma", DoubleValue(sigma));
1577 
1578  // Make this generate antithetic values.
1579  x->SetAttribute("Antithetic", BooleanValue(true));
1580 
1581  // Calculate the mean of these values.
1582  double valueMean = Average(x);
1583 
1584  // The expected value for the mean of the values returned by a
1585  // log-normally distributed random variable is equal to
1586  //
1587  // 2
1588  // mu + sigma / 2
1589  // E[value] = e .
1590  //
1591  double expectedMean = std::exp(mu + sigma * sigma / 2.0);
1592 
1593  // Test that values have approximately the right mean value.
1594  //
1601  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1602  expectedMean,
1603  expectedMean * TOLERANCE,
1604  "Wrong mean value.");
1605 }
1606 
1612 {
1613  public:
1614  // Constructor
1615  GammaTestCase();
1616 
1617  // Inherited
1618  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1619 
1620  private:
1621  // Inherited
1622  void DoRun() override;
1623 
1628  static constexpr double TOLERANCE{1e-2};
1629 };
1630 
1632  : TestCaseBase("Gamma Random Variable Stream Generator")
1633 {
1634 }
1635 
1636 double
1638 {
1639  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1640  auto range = UniformHistogramBins(h, 0, 10, false);
1641 
1642  std::vector<double> expected(N_BINS);
1643 
1644  // Note that this assumes that n has alpha equal to one and beta
1645  // equal to one, which are their default values for this
1646  // distribution.
1647  double alpha = 1.0;
1648  double beta = 1.0;
1649 
1650  for (std::size_t i = 0; i < N_BINS; ++i)
1651  {
1652  expected[i] =
1653  gsl_cdf_gamma_P(range[i + 1], alpha, beta) - gsl_cdf_gamma_P(range[i], alpha, beta);
1654  expected[i] *= N_MEASUREMENTS;
1655  }
1656 
1657  double chiSquared = ChiSquared(h, expected, rng);
1658 
1659  gsl_histogram_free(h);
1660  return chiSquared;
1661 }
1662 
1663 void
1665 {
1666  NS_LOG_FUNCTION(this);
1667  SetTestSuiteSeed();
1668 
1669  auto generator = RngGenerator<GammaRandomVariable>();
1670  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1671  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1672  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1673 
1674  double alpha = 5.0;
1675  double beta = 2.0;
1676 
1677  // Create the RNG with the specified range.
1678  Ptr<GammaRandomVariable> x = CreateObject<GammaRandomVariable>();
1679  x->SetAttribute("Alpha", DoubleValue(alpha));
1680  x->SetAttribute("Beta", DoubleValue(beta));
1681 
1682  // Calculate the mean of these values.
1683  double valueMean = Average(x);
1684 
1685  // The expected value for the mean of the values returned by a
1686  // gammaly distributed random variable is equal to
1687  //
1688  // E[value] = alpha * beta .
1689  //
1690  double expectedMean = alpha * beta;
1691 
1692  // Test that values have approximately the right mean value.
1693  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1694  expectedMean,
1695  expectedMean * TOLERANCE,
1696  "Wrong mean value.");
1697 }
1698 
1704 {
1705  public:
1706  // Constructor
1708 
1709  // Inherited
1710  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1711 
1712  private:
1713  // Inherited
1714  void DoRun() override;
1715 
1720  static constexpr double TOLERANCE{1e-2};
1721 };
1722 
1724  : TestCaseBase("Antithetic Gamma Random Variable Stream Generator")
1725 {
1726 }
1727 
1728 double
1730 {
1731  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1732  auto range = UniformHistogramBins(h, 0, 10, false);
1733 
1734  std::vector<double> expected(N_BINS);
1735 
1736  // Note that this assumes that n has alpha equal to one and beta
1737  // equal to one, which are their default values for this
1738  // distribution.
1739  double alpha = 1.0;
1740  double beta = 1.0;
1741 
1742  for (std::size_t i = 0; i < N_BINS; ++i)
1743  {
1744  expected[i] =
1745  gsl_cdf_gamma_P(range[i + 1], alpha, beta) - gsl_cdf_gamma_P(range[i], alpha, beta);
1746  expected[i] *= N_MEASUREMENTS;
1747  }
1748 
1749  double chiSquared = ChiSquared(h, expected, rng);
1750 
1751  gsl_histogram_free(h);
1752  return chiSquared;
1753 }
1754 
1755 void
1757 {
1758  NS_LOG_FUNCTION(this);
1759  SetTestSuiteSeed();
1760 
1761  auto generator = RngGenerator<GammaRandomVariable>(true);
1762  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1763  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1764  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1765 
1766  double alpha = 5.0;
1767  double beta = 2.0;
1768 
1769  // Create the RNG with the specified range.
1770  Ptr<GammaRandomVariable> x = CreateObject<GammaRandomVariable>();
1771 
1772  // Make this generate antithetic values.
1773  x->SetAttribute("Antithetic", BooleanValue(true));
1774 
1775  x->SetAttribute("Alpha", DoubleValue(alpha));
1776  x->SetAttribute("Beta", DoubleValue(beta));
1777 
1778  // Calculate the mean of these values.
1779  double valueMean = Average(x);
1780 
1781  // The expected value for the mean of the values returned by a
1782  // gammaly distributed random variable is equal to
1783  //
1784  // E[value] = alpha * beta .
1785  //
1786  double expectedMean = alpha * beta;
1787 
1788  // Test that values have approximately the right mean value.
1789  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1790  expectedMean,
1791  expectedMean * TOLERANCE,
1792  "Wrong mean value.");
1793 }
1794 
1800 {
1801  public:
1802  // Constructor
1803  ErlangTestCase();
1804 
1805  // Inherited
1806  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1807 
1808  private:
1809  // Inherited
1810  void DoRun() override;
1811 
1816  static constexpr double TOLERANCE{1e-2};
1817 };
1818 
1820  : TestCaseBase("Erlang Random Variable Stream Generator")
1821 {
1822 }
1823 
1824 double
1826 {
1827  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1828  auto range = UniformHistogramBins(h, 0, 10, false);
1829 
1830  std::vector<double> expected(N_BINS);
1831 
1832  // Note that this assumes that n has k equal to one and lambda
1833  // equal to one, which are their default values for this
1834  // distribution.
1835  uint32_t k = 1;
1836  double lambda = 1.0;
1837 
1838  // Note that Erlang distribution is equal to the gamma distribution
1839  // when k is an integer, which is why the gamma distribution's cdf
1840  // function can be used here.
1841  for (std::size_t i = 0; i < N_BINS; ++i)
1842  {
1843  expected[i] =
1844  gsl_cdf_gamma_P(range[i + 1], k, lambda) - gsl_cdf_gamma_P(range[i], k, lambda);
1845  expected[i] *= N_MEASUREMENTS;
1846  }
1847 
1848  double chiSquared = ChiSquared(h, expected, rng);
1849 
1850  gsl_histogram_free(h);
1851  return chiSquared;
1852 }
1853 
1854 void
1856 {
1857  NS_LOG_FUNCTION(this);
1858  SetTestSuiteSeed();
1859 
1860  auto generator = RngGenerator<ErlangRandomVariable>();
1861  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1862  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1863  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1864 
1865  uint32_t k = 5;
1866  double lambda = 2.0;
1867 
1868  // Create the RNG with the specified range.
1869  Ptr<ErlangRandomVariable> x = CreateObject<ErlangRandomVariable>();
1870  x->SetAttribute("K", IntegerValue(k));
1871  x->SetAttribute("Lambda", DoubleValue(lambda));
1872 
1873  // Calculate the mean of these values.
1874  double valueMean = Average(x);
1875 
1876  // The expected value for the mean of the values returned by a
1877  // Erlangly distributed random variable is equal to
1878  //
1879  // E[value] = k * lambda .
1880  //
1881  double expectedMean = k * lambda;
1882 
1883  // Test that values have approximately the right mean value.
1884  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1885  expectedMean,
1886  expectedMean * TOLERANCE,
1887  "Wrong mean value.");
1888 }
1889 
1895 {
1896  public:
1897  // Constructor
1899 
1900  // Inherited
1901  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
1902 
1903  private:
1904  // Inherited
1905  void DoRun() override;
1906 
1911  static constexpr double TOLERANCE{1e-2};
1912 };
1913 
1915  : TestCaseBase("Antithetic Erlang Random Variable Stream Generator")
1916 {
1917 }
1918 
1919 double
1921 {
1922  gsl_histogram* h = gsl_histogram_alloc(N_BINS);
1923  auto range = UniformHistogramBins(h, 0, 10, false);
1924 
1925  std::vector<double> expected(N_BINS);
1926 
1927  // Note that this assumes that n has k equal to one and lambda
1928  // equal to one, which are their default values for this
1929  // distribution.
1930  uint32_t k = 1;
1931  double lambda = 1.0;
1932 
1933  // Note that Erlang distribution is equal to the gamma distribution
1934  // when k is an integer, which is why the gamma distribution's cdf
1935  // function can be used here.
1936  for (std::size_t i = 0; i < N_BINS; ++i)
1937  {
1938  expected[i] =
1939  gsl_cdf_gamma_P(range[i + 1], k, lambda) - gsl_cdf_gamma_P(range[i], k, lambda);
1940  expected[i] *= N_MEASUREMENTS;
1941  }
1942 
1943  double chiSquared = ChiSquared(h, expected, rng);
1944 
1945  gsl_histogram_free(h);
1946  return chiSquared;
1947 }
1948 
1949 void
1951 {
1952  NS_LOG_FUNCTION(this);
1953  SetTestSuiteSeed();
1954 
1955  auto generator = RngGenerator<ErlangRandomVariable>(true);
1956  double sum = ChiSquaredsAverage(&generator, N_RUNS);
1957  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, N_BINS);
1958  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
1959 
1960  uint32_t k = 5;
1961  double lambda = 2.0;
1962 
1963  // Create the RNG with the specified range.
1964  Ptr<ErlangRandomVariable> x = CreateObject<ErlangRandomVariable>();
1965 
1966  // Make this generate antithetic values.
1967  x->SetAttribute("Antithetic", BooleanValue(true));
1968 
1969  x->SetAttribute("K", IntegerValue(k));
1970  x->SetAttribute("Lambda", DoubleValue(lambda));
1971 
1972  // Calculate the mean of these values.
1973  double valueMean = Average(x);
1974 
1975  // The expected value for the mean of the values returned by a
1976  // Erlangly distributed random variable is equal to
1977  //
1978  // E[value] = k * lambda .
1979  //
1980  double expectedMean = k * lambda;
1981 
1982  // Test that values have approximately the right mean value.
1983  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
1984  expectedMean,
1985  expectedMean * TOLERANCE,
1986  "Wrong mean value.");
1987 }
1988 
1994 {
1995  public:
1996  // Constructor
1997  ZipfTestCase();
1998 
1999  private:
2000  // Inherited
2001  void DoRun() override;
2002 
2007  static constexpr double TOLERANCE{1e-2};
2008 };
2009 
2011  : TestCaseBase("Zipf Random Variable Stream Generator")
2012 {
2013 }
2014 
2015 void
2017 {
2018  NS_LOG_FUNCTION(this);
2019  SetTestSuiteSeed();
2020 
2021  uint32_t n = 1;
2022  double alpha = 2.0;
2023 
2024  // Create the RNG with the specified range.
2025  Ptr<ZipfRandomVariable> x = CreateObject<ZipfRandomVariable>();
2026  x->SetAttribute("N", IntegerValue(n));
2027  x->SetAttribute("Alpha", DoubleValue(alpha));
2028 
2029  // Calculate the mean of these values.
2030  double valueMean = Average(x);
2031 
2032  // The expected value for the mean of the values returned by a
2033  // Zipfly distributed random variable is equal to
2034  //
2035  // H
2036  // N, alpha - 1
2037  // E[value] = ---------------
2038  // H
2039  // N, alpha
2040  //
2041  // where
2042  //
2043  // N
2044  // ---
2045  // \ -alpha
2046  // H = / m .
2047  // N, alpha ---
2048  // m=1
2049  //
2050  // For this test,
2051  //
2052  // -(alpha - 1)
2053  // 1
2054  // E[value] = ---------------
2055  // -alpha
2056  // 1
2057  //
2058  // = 1 .
2059  //
2060  double expectedMean = 1.0;
2061 
2062  // Test that values have approximately the right mean value.
2063  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2064  expectedMean,
2065  expectedMean * TOLERANCE,
2066  "Wrong mean value.");
2067 }
2068 
2074 {
2075  public:
2076  // Constructor
2078 
2079  private:
2080  // Inherited
2081  void DoRun() override;
2082 
2087  static constexpr double TOLERANCE{1e-2};
2088 };
2089 
2091  : TestCaseBase("Antithetic Zipf Random Variable Stream Generator")
2092 {
2093 }
2094 
2095 void
2097 {
2098  NS_LOG_FUNCTION(this);
2099  SetTestSuiteSeed();
2100 
2101  uint32_t n = 1;
2102  double alpha = 2.0;
2103 
2104  // Create the RNG with the specified range.
2105  Ptr<ZipfRandomVariable> x = CreateObject<ZipfRandomVariable>();
2106  x->SetAttribute("N", IntegerValue(n));
2107  x->SetAttribute("Alpha", DoubleValue(alpha));
2108 
2109  // Make this generate antithetic values.
2110  x->SetAttribute("Antithetic", BooleanValue(true));
2111 
2112  // Calculate the mean of these values.
2113  double valueMean = Average(x);
2114 
2115  // The expected value for the mean of the values returned by a
2116  // Zipfly distributed random variable is equal to
2117  //
2118  // H
2119  // N, alpha - 1
2120  // E[value] = ---------------
2121  // H
2122  // N, alpha
2123  //
2124  // where
2125  //
2126  // N
2127  // ---
2128  // \ -alpha
2129  // H = / m .
2130  // N, alpha ---
2131  // m=1
2132  //
2133  // For this test,
2134  //
2135  // -(alpha - 1)
2136  // 1
2137  // E[value] = ---------------
2138  // -alpha
2139  // 1
2140  //
2141  // = 1 .
2142  //
2143  double expectedMean = 1.0;
2144 
2145  // Test that values have approximately the right mean value.
2146  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2147  expectedMean,
2148  expectedMean * TOLERANCE,
2149  "Wrong mean value.");
2150 }
2151 
2157 {
2158  public:
2159  // Constructor
2160  ZetaTestCase();
2161 
2162  private:
2163  // Inherited
2164  void DoRun() override;
2165 
2170  static constexpr double TOLERANCE{1e-2};
2171 };
2172 
2174  : TestCaseBase("Zeta Random Variable Stream Generator")
2175 {
2176 }
2177 
2178 void
2180 {
2181  NS_LOG_FUNCTION(this);
2182  SetTestSuiteSeed();
2183 
2184  double alpha = 5.0;
2185 
2186  // Create the RNG with the specified range.
2187  Ptr<ZetaRandomVariable> x = CreateObject<ZetaRandomVariable>();
2188  x->SetAttribute("Alpha", DoubleValue(alpha));
2189 
2190  // Calculate the mean of these values.
2191  double valueMean = Average(x);
2192 
2193  // The expected value for the mean of the values returned by a
2194  // zetaly distributed random variable is equal to
2195  //
2196  // zeta(alpha - 1)
2197  // E[value] = --------------- for alpha > 2 ,
2198  // zeta(alpha)
2199  //
2200  // where zeta(alpha) is the Riemann zeta function.
2201  //
2202  // There are no simple analytic forms for the Riemann zeta function,
2203  // which is why the gsl library is used in this test to calculate
2204  // the known mean of the values.
2205  double expectedMean =
2206  gsl_sf_zeta_int(static_cast<int>(alpha - 1)) / gsl_sf_zeta_int(static_cast<int>(alpha));
2207 
2208  // Test that values have approximately the right mean value.
2209  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2210  expectedMean,
2211  expectedMean * TOLERANCE,
2212  "Wrong mean value.");
2213 }
2214 
2220 {
2221  public:
2222  // Constructor
2224 
2225  private:
2226  // Inherited
2227  void DoRun() override;
2228 
2233  static constexpr double TOLERANCE{1e-2};
2234 };
2235 
2237  : TestCaseBase("Antithetic Zeta Random Variable Stream Generator")
2238 {
2239 }
2240 
2241 void
2243 {
2244  NS_LOG_FUNCTION(this);
2245  SetTestSuiteSeed();
2246 
2247  double alpha = 5.0;
2248 
2249  // Create the RNG with the specified range.
2250  Ptr<ZetaRandomVariable> x = CreateObject<ZetaRandomVariable>();
2251  x->SetAttribute("Alpha", DoubleValue(alpha));
2252 
2253  // Make this generate antithetic values.
2254  x->SetAttribute("Antithetic", BooleanValue(true));
2255 
2256  // Calculate the mean of these values.
2257  double valueMean = Average(x);
2258 
2259  // The expected value for the mean of the values returned by a
2260  // zetaly distributed random variable is equal to
2261  //
2262  // zeta(alpha - 1)
2263  // E[value] = --------------- for alpha > 2 ,
2264  // zeta(alpha)
2265  //
2266  // where zeta(alpha) is the Riemann zeta function.
2267  //
2268  // There are no simple analytic forms for the Riemann zeta function,
2269  // which is why the gsl library is used in this test to calculate
2270  // the known mean of the values.
2271  double expectedMean =
2272  gsl_sf_zeta_int(static_cast<int>(alpha) - 1) / gsl_sf_zeta_int(static_cast<int>(alpha));
2273 
2274  // Test that values have approximately the right mean value.
2275  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2276  expectedMean,
2277  expectedMean * TOLERANCE,
2278  "Wrong mean value.");
2279 }
2280 
2286 {
2287  public:
2288  // Constructor
2290 
2291  private:
2292  // Inherited
2293  void DoRun() override;
2294 
2296  static constexpr double TOLERANCE{1e-8};
2297 };
2298 
2300  : TestCaseBase("Deterministic Random Variable Stream Generator")
2301 {
2302 }
2303 
2304 void
2306 {
2307  NS_LOG_FUNCTION(this);
2308  SetTestSuiteSeed();
2309 
2310  Ptr<DeterministicRandomVariable> s = CreateObject<DeterministicRandomVariable>();
2311 
2312  // The following array should give the sequence
2313  //
2314  // 4, 4, 7, 7, 10, 10 .
2315  //
2316  double array1[] = {4, 4, 7, 7, 10, 10};
2317  std::size_t count1 = 6;
2318  s->SetValueArray(array1, count1);
2319 
2320  double value;
2321 
2322  // Test that the first sequence is correct.
2323  value = s->GetValue();
2324  NS_TEST_ASSERT_MSG_EQ_TOL(value, 4, TOLERANCE, "Sequence 1 value 1 wrong.");
2325  value = s->GetValue();
2326  NS_TEST_ASSERT_MSG_EQ_TOL(value, 4, TOLERANCE, "Sequence 1 value 2 wrong.");
2327  value = s->GetValue();
2328  NS_TEST_ASSERT_MSG_EQ_TOL(value, 7, TOLERANCE, "Sequence 1 value 3 wrong.");
2329  value = s->GetValue();
2330  NS_TEST_ASSERT_MSG_EQ_TOL(value, 7, TOLERANCE, "Sequence 1 value 4 wrong.");
2331  value = s->GetValue();
2332  NS_TEST_ASSERT_MSG_EQ_TOL(value, 10, TOLERANCE, "Sequence 1 value 5 wrong.");
2333  value = s->GetValue();
2334  NS_TEST_ASSERT_MSG_EQ_TOL(value, 10, TOLERANCE, "Sequence 1 value 6 wrong.");
2335 
2336  // The following array should give the sequence
2337  //
2338  // 1000, 2000, 7, 7 .
2339  //
2340  double array2[] = {1000, 2000, 3000, 4000};
2341  std::size_t count2 = 4;
2342  s->SetValueArray(array2, count2);
2343 
2344  // Test that the second sequence is correct.
2345  value = s->GetValue();
2346  NS_TEST_ASSERT_MSG_EQ_TOL(value, 1000, TOLERANCE, "Sequence 2 value 1 wrong.");
2347  value = s->GetValue();
2348  NS_TEST_ASSERT_MSG_EQ_TOL(value, 2000, TOLERANCE, "Sequence 2 value 2 wrong.");
2349  value = s->GetValue();
2350  NS_TEST_ASSERT_MSG_EQ_TOL(value, 3000, TOLERANCE, "Sequence 2 value 3 wrong.");
2351  value = s->GetValue();
2352  NS_TEST_ASSERT_MSG_EQ_TOL(value, 4000, TOLERANCE, "Sequence 2 value 4 wrong.");
2353  value = s->GetValue();
2354 }
2355 
2361 {
2362  public:
2363  // Constructor
2365 
2366  private:
2367  // Inherited
2368  void DoRun() override;
2369 
2374  static constexpr double TOLERANCE{1e-2};
2375 };
2376 
2378  : TestCaseBase("Empirical Random Variable Stream Generator")
2379 {
2380 }
2381 
2382 void
2384 {
2385  NS_LOG_FUNCTION(this);
2386  SetTestSuiteSeed();
2387 
2388  // Create the RNG with a uniform distribution between 0 and 10.
2389  Ptr<EmpiricalRandomVariable> x = CreateObject<EmpiricalRandomVariable>();
2390  x->SetInterpolate(false);
2391  x->CDF(0.0, 0.0);
2392  x->CDF(5.0, 0.25);
2393  x->CDF(10.0, 1.0);
2394 
2395  // Check that only the correct values are returned
2396  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
2397  {
2398  double value = x->GetValue();
2399  NS_TEST_EXPECT_MSG_EQ((value == 5) || (value == 10),
2400  true,
2401  "Incorrect value returned, expected only 5 or 10.");
2402  }
2403 
2404  // Calculate the mean of the sampled values.
2405  double valueMean = Average(x);
2406 
2407  // The expected distribution with sampled values is
2408  // Value Probability
2409  // 5 25%
2410  // 10 75%
2411  //
2412  // The expected mean is
2413  //
2414  // E[value] = 5 * 25% + 10 * 75% = 8.75
2415  //
2416  // Test that values have approximately the right mean value.
2417  double expectedMean = 8.75;
2418  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2419  expectedMean,
2420  expectedMean * TOLERANCE,
2421  "Wrong mean value.");
2422 
2423  // Calculate the mean of the interpolated values.
2424  x->SetInterpolate(true);
2425  valueMean = Average(x);
2426 
2427  // The expected distribution (with interpolation) is
2428  // Bin Probability
2429  // [0, 5) 25%
2430  // [5, 10) 75%
2431  //
2432  // Each bin is uniformly sampled, so the average of the samples in the
2433  // bin is the center of the bin.
2434  //
2435  // The expected mean is
2436  //
2437  // E[value] = 2.5 * 25% + 7.5 * 75% = 6.25
2438  //
2439  expectedMean = 6.25;
2440 
2441  // Test that values have approximately the right mean value.
2442  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2443  expectedMean,
2444  expectedMean * TOLERANCE,
2445  "Wrong mean value.");
2446 
2447  // Bug 2082: Create the RNG with a uniform distribution between -1 and 1.
2448  Ptr<EmpiricalRandomVariable> y = CreateObject<EmpiricalRandomVariable>();
2449  y->SetInterpolate(false);
2450  y->CDF(-1.0, 0.0);
2451  y->CDF(0.0, 0.5);
2452  y->CDF(1.0, 1.0);
2453  NS_TEST_ASSERT_MSG_LT(y->GetValue(), 2, "Empirical variable with negative domain");
2454 }
2455 
2461 {
2462  public:
2463  // Constructor
2465 
2466  private:
2467  // Inherited
2468  void DoRun() override;
2469 
2474  static constexpr double TOLERANCE{1e-2};
2475 };
2476 
2478  : TestCaseBase("EmpiricalAntithetic Random Variable Stream Generator")
2479 {
2480 }
2481 
2482 void
2484 {
2485  NS_LOG_FUNCTION(this);
2486  SetTestSuiteSeed();
2487 
2488  // Create the RNG with a uniform distribution between 0 and 10.
2489  Ptr<EmpiricalRandomVariable> x = CreateObject<EmpiricalRandomVariable>();
2490  x->SetInterpolate(false);
2491  x->CDF(0.0, 0.0);
2492  x->CDF(5.0, 0.25);
2493  x->CDF(10.0, 1.0);
2494 
2495  // Make this generate antithetic values.
2496  x->SetAttribute("Antithetic", BooleanValue(true));
2497 
2498  // Check that only the correct values are returned
2499  for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
2500  {
2501  double value = x->GetValue();
2502  NS_TEST_EXPECT_MSG_EQ((value == 5) || (value == 10),
2503  true,
2504  "Incorrect value returned, expected only 5 or 10.");
2505  }
2506 
2507  // Calculate the mean of these values.
2508  double valueMean = Average(x);
2509  // Expected
2510  // E[value] = 5 * 25% + 10 * 75% = 8.75
2511  double expectedMean = 8.75;
2512  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2513  expectedMean,
2514  expectedMean * TOLERANCE,
2515  "Wrong mean value.");
2516 
2517  // Check interpolated sampling
2518  x->SetInterpolate(true);
2519  valueMean = Average(x);
2520 
2521  // The expected value for the mean of the values returned by this
2522  // empirical distribution with interpolation is
2523  //
2524  // E[value] = 2.5 * 25% + 7.5 * 75% = 6.25
2525  //
2526  expectedMean = 6.25;
2527 
2528  // Test that values have approximately the right mean value.
2529  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2530  expectedMean,
2531  expectedMean * TOLERANCE,
2532  "Wrong mean value.");
2533 }
2534 
2540 {
2541  public:
2542  // Constructor
2544 
2545  private:
2546  // Inherited
2547  void DoRun() override;
2548 };
2549 
2551  : TestCaseBase("NormalRandomVariable caching of parameters")
2552 {
2553 }
2554 
2555 void
2557 {
2558  NS_LOG_FUNCTION(this);
2559  SetTestSuiteSeed();
2560 
2561  Ptr<NormalRandomVariable> n = CreateObject<NormalRandomVariable>();
2562  double v1 = n->GetValue(-10, 1, 10); // Mean -10, variance 1, bounded to [-20,0]
2563  double v2 = n->GetValue(10, 1, 10); // Mean 10, variance 1, bounded to [0,20]
2564 
2565  NS_TEST_ASSERT_MSG_LT(v1, 0, "Incorrect value returned, expected < 0");
2566  NS_TEST_ASSERT_MSG_GT(v2, 0, "Incorrect value returned, expected > 0");
2567 }
2568 
2574 {
2575  public:
2576  // Constructor
2578 
2579  // Inherited
2580  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
2581 
2582  private:
2583  // Inherited
2584  void DoRun() override;
2585 
2587  static constexpr double TOLERANCE{5};
2588 };
2589 
2591  : TestCaseBase("Bernoulli Random Variable Stream Generator")
2592 {
2593 }
2594 
2595 double
2597 {
2598  gsl_histogram* h = gsl_histogram_alloc(2);
2599  auto range = UniformHistogramBins(h, 0, 1);
2600 
2601  double p = 0.5;
2602  std::vector<double> expected = {N_MEASUREMENTS * (1 - p), N_MEASUREMENTS * p};
2603 
2604  double chiSquared = ChiSquared(h, expected, rng);
2605 
2606  gsl_histogram_free(h);
2607  return chiSquared;
2608 }
2609 
2610 void
2612 {
2613  NS_LOG_FUNCTION(this);
2614  SetTestSuiteSeed();
2615 
2616  auto generator = RngGenerator<BernoulliRandomVariable>();
2617  double sum = ChiSquaredsAverage(&generator, N_RUNS);
2618  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, 1);
2619  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
2620 
2621  double probability = 0.5;
2622 
2623  // Create the RNG with the specified range.
2624  Ptr<BernoulliRandomVariable> x = CreateObject<BernoulliRandomVariable>();
2625  x->SetAttribute("Probability", DoubleValue(probability));
2626 
2627  // Calculate the mean of these values.
2628  double mean = probability;
2629  double valueMean = Average(x);
2630  double expectedMean = mean;
2631  double expectedRms = std::sqrt(mean / N_MEASUREMENTS);
2632 
2633  // Test that values have approximately the right mean value.
2634  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2635  expectedMean,
2636  expectedRms * TOLERANCE,
2637  "Wrong mean value.");
2638 }
2639 
2645 {
2646  public:
2647  // Constructor
2649 
2650  // Inherited
2651  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
2652 
2653  private:
2654  // Inherited
2655  void DoRun() override;
2656 
2658  static constexpr double TOLERANCE{5};
2659 };
2660 
2662  : TestCaseBase("Antithetic Bernoulli Random Variable Stream Generator")
2663 {
2664 }
2665 
2666 double
2668 {
2669  gsl_histogram* h = gsl_histogram_alloc(2);
2670  auto range = UniformHistogramBins(h, 0, 1);
2671 
2672  double p = 0.5;
2673  std::vector<double> expected = {N_MEASUREMENTS * (1 - p), N_MEASUREMENTS * p};
2674 
2675  double chiSquared = ChiSquared(h, expected, rng);
2676 
2677  gsl_histogram_free(h);
2678  return chiSquared;
2679 }
2680 
2681 void
2683 {
2684  NS_LOG_FUNCTION(this);
2685  SetTestSuiteSeed();
2686 
2687  auto generator = RngGenerator<BernoulliRandomVariable>(true);
2688  double sum = ChiSquaredsAverage(&generator, N_RUNS);
2689  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, 1);
2690  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
2691 
2692  double probability = 0.5;
2693 
2694  // Create the RNG with the specified range.
2695  Ptr<BernoulliRandomVariable> x = CreateObject<BernoulliRandomVariable>();
2696  x->SetAttribute("Probability", DoubleValue(probability));
2697 
2698  // Make this generate antithetic values.
2699  x->SetAttribute("Antithetic", BooleanValue(true));
2700 
2701  // Calculate the mean of these values.
2702  double mean = probability;
2703  double valueMean = Average(x);
2704  double expectedMean = mean;
2705  double expectedRms = std::sqrt(mean / N_MEASUREMENTS);
2706 
2707  // Test that values have approximately the right mean value.
2708  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2709  expectedMean,
2710  expectedRms * TOLERANCE,
2711  "Wrong mean value.");
2712 }
2713 
2719 {
2720  public:
2721  // Constructor
2722  BinomialTestCase();
2723 
2724  // Inherited
2725  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
2726 
2727  private:
2728  // Inherited
2729  void DoRun() override;
2730 
2732  static constexpr double TOLERANCE{5};
2733 };
2734 
2736  : TestCaseBase("Binomial Random Variable Stream Generator")
2737 {
2738 }
2739 
2740 double
2742 {
2743  uint32_t trials = 10;
2744  double probability = 0.5;
2745 
2746  gsl_histogram* h = gsl_histogram_alloc(trials + 1);
2747  auto range = UniformHistogramBins(h, 0, trials);
2748 
2749  std::vector<double> expected(trials + 1);
2750  for (std::size_t i = 0; i < trials + 1; ++i)
2751  {
2752  expected[i] = N_MEASUREMENTS * gsl_ran_binomial_pdf(i, probability, trials);
2753  }
2754 
2755  double chiSquared = ChiSquared(h, expected, rng);
2756 
2757  gsl_histogram_free(h);
2758  return chiSquared;
2759 }
2760 
2761 void
2763 {
2764  NS_LOG_FUNCTION(this);
2765  SetTestSuiteSeed();
2766 
2767  uint32_t trials = 10;
2768  double probability = 0.5;
2769 
2770  auto generator = RngGenerator<BinomialRandomVariable>();
2771  double sum = ChiSquaredsAverage(&generator, N_RUNS);
2772  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, trials);
2773  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
2774 
2775  // Create the RNG with the specified range.
2776  Ptr<BinomialRandomVariable> x = CreateObject<BinomialRandomVariable>();
2777  x->SetAttribute("Trials", IntegerValue(trials));
2778  x->SetAttribute("Probability", DoubleValue(probability));
2779 
2780  // Calculate the mean of these values.
2781  double mean = trials * probability;
2782  double valueMean = Average(x);
2783  double expectedMean = mean;
2784  double expectedRms = std::sqrt(mean / N_MEASUREMENTS);
2785 
2786  // Test that values have approximately the right mean value.
2787  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2788  expectedMean,
2789  expectedRms * TOLERANCE,
2790  "Wrong mean value.");
2791 }
2792 
2798 {
2799  public:
2800  // Constructor
2802 
2803  // Inherited
2804  double ChiSquaredTest(Ptr<RandomVariableStream> rng) const override;
2805 
2806  private:
2807  // Inherited
2808  void DoRun() override;
2809 
2811  static constexpr double TOLERANCE{5};
2812 };
2813 
2815  : TestCaseBase("Antithetic Binomial Random Variable Stream Generator")
2816 {
2817 }
2818 
2819 double
2821 {
2822  uint32_t trials = 10;
2823  double probability = 0.5;
2824 
2825  gsl_histogram* h = gsl_histogram_alloc(trials + 1);
2826  auto range = UniformHistogramBins(h, 0, trials);
2827 
2828  std::vector<double> expected(trials + 1);
2829  for (std::size_t i = 0; i < trials + 1; ++i)
2830  {
2831  expected[i] = N_MEASUREMENTS * gsl_ran_binomial_pdf(i, probability, trials);
2832  }
2833 
2834  double chiSquared = ChiSquared(h, expected, rng);
2835 
2836  gsl_histogram_free(h);
2837  return chiSquared;
2838 }
2839 
2840 void
2842 {
2843  NS_LOG_FUNCTION(this);
2844  SetTestSuiteSeed();
2845 
2846  uint32_t trials = 10;
2847  double probability = 0.5;
2848 
2849  auto generator = RngGenerator<BinomialRandomVariable>(true);
2850  double sum = ChiSquaredsAverage(&generator, N_RUNS);
2851  double maxStatistic = gsl_cdf_chisq_Qinv(0.05, trials);
2852  NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range");
2853 
2854  // Create the RNG with the specified range.
2855  Ptr<BinomialRandomVariable> x = CreateObject<BinomialRandomVariable>();
2856  x->SetAttribute("Trials", IntegerValue(trials));
2857  x->SetAttribute("Probability", DoubleValue(probability));
2858 
2859  // Make this generate antithetic values.
2860  x->SetAttribute("Antithetic", BooleanValue(true));
2861 
2862  // Calculate the mean of these values.
2863  double mean = trials * probability;
2864  double valueMean = Average(x);
2865  double expectedMean = mean;
2866  double expectedRms = std::sqrt(mean / N_MEASUREMENTS);
2867 
2868  // Test that values have approximately the right mean value.
2869  NS_TEST_ASSERT_MSG_EQ_TOL(valueMean,
2870  expectedMean,
2871  expectedRms * TOLERANCE,
2872  "Wrong mean value.");
2873 }
2874 
2881 {
2882  public:
2883  // Constructor
2885 };
2886 
2888  : TestSuite("random-variable-stream-generators", UNIT)
2889 {
2906  /*
2907  AddTestCase (new LogNormalAntitheticTestCase);
2908  */
2913  /*
2914  AddTestCase (new GammaAntitheticTestCase);
2915  */
2931 }
2932 
2934 
2935 } // namespace RandomVariable
2936 
2937 } // namespace test
2938 
2939 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
double GetValue(double constant)
Get the next random value drawn from the distribution.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold a signed integer type.
Definition: integer.h:45
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:204
virtual double GetValue()=0
Get the next random value drawn from the distribution.
static void SetSeed(uint32_t seed)
Set the seed.
static uint64_t GetRun()
Get the current run number.
static uint32_t GetSeed()
Get the current seed value which will be used by all subsequently instantiated RandomVariableStream o...
Hold variables of type string.
Definition: string.h:56
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
Test case for antithetic bernoulli distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for bernoulli distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
void DoRun() override
Implementation to actually run this TestCase.
Test case for antithetic binomial distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
Test case for binomial distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for constant random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation.
void DoRun() override
Implementation to actually run this TestCase.
Test case for deterministic random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation.
Test case for antithetic empirical distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for empirical distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for antithetic Erlang distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for Erlang distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
Test case for antithetic exponential distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for exponential distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for antithetic gamma distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for gamma distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for antithetic log-normal distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
Test case for log-normal distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for antithetic normal distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for caching of Normal RV parameters (see issue #302)
void DoRun() override
Implementation to actually run this TestCase.
Test case for normal distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, in rms.
Test case for antithetic Pareto distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for Pareto distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
RandomVariableStream test suite, covering all random number variable stream generator types.
Test case for sequential random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation.
void DoRun() override
Implementation to actually run this TestCase.
A factory base class to create new instances of a random variable.
virtual Ptr< RandomVariableStream > Create() const =0
Create a new instance of a random variable stream.
Factory class to create new instances of a particular random variable stream.
Ptr< RandomVariableStream > Create() const override
Create a new instance of a random variable stream.
bool m_anti
Whether to create antithetic random variable streams.
Base class for RandomVariableStream test suites.
double ChiSquared(gsl_histogram *h, const std::vector< double > &expected, Ptr< RandomVariableStream > rng) const
Compute the chi squared value of a sampled distribution compared to the expected distribution.
static const uint32_t N_MEASUREMENTS
Number of samples to draw when populating the distributions.
void SetTestSuiteSeed()
Set the seed used for this test suite.
double ChiSquaredsAverage(const RngGeneratorBase *generator, std::size_t nRuns) const
Average the chi squared value over some number of runs, each run with a new instance of the random nu...
virtual double ChiSquaredTest(Ptr< RandomVariableStream > rng) const
Compute the chi square value from a random variable.
static const uint32_t N_BINS
Number of bins for sampling the distributions.
std::vector< double > UniformHistogramBins(gsl_histogram *h, double start, double end, bool underflow=true, bool overflow=true) const
Configure a GSL histogram with uniform bins, with optional under/over-flow bins.
bool m_seedSet
true if we've already set the seed the correctly.
static const uint32_t N_RUNS
Number of retry attempts to pass a chi-square test.
double Average(Ptr< RandomVariableStream > rng) const
Compute the average of a random variable.
Test case for antithetic uniform distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for uniform distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
Test case for antithetic Weibull distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for Weibull distribution random variable stream generator.
double ChiSquaredTest(Ptr< RandomVariableStream > rng) const override
Compute the chi square value from a random variable.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
Test case for antithetic Zeta distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
Test case for Zeta distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
Test case for antithetic Zipf distribution random variable stream generator.
void DoRun() override
Implementation to actually run this TestCase.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
Test case for Zipf distribution random variable stream generator.
static constexpr double TOLERANCE
Tolerance for testing rng values against expectation, as a fraction of mean value.
void DoRun() override
Implementation to actually run this TestCase.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#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
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:251
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:564
#define NS_TEST_ASSERT_MSG_GT(actual, limit, msg)
Test that an actual value is greater than a limit and report and abort if not.
Definition: test.h:874
#define NS_TEST_ASSERT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition: test.h:337
static RandomVariableSuite randomVariableSuite
Static variable for test initialization.
Every class exported by the ns3 library is enclosed in the ns3 namespace.