A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
40using namespace ns3;
41
42NS_LOG_COMPONENT_DEFINE("RandomVariableStreamGenerators");
43
44namespace ns3
45{
46
47namespace test
48{
49
50namespace RandomVariable
51{
52
63class 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:
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,
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
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;
328 "Special run number value of zero; seeding with time of day: " << seed);
329 }
330 else
331 {
333 m_seedSet = true;
334 NS_LOG_DEBUG("Using the values seed: " << seed
335 << " and run: " << RngSeedManager::GetRun());
336 }
338 }
339 }
340
341 private:
343 bool m_seedSet = false;
344
345}; // class TestCaseBase
346
352{
353 public:
354 // Constructor
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
370double
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
386void
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
492double
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
508void
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
567void
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 {
588 NS_TEST_ASSERT_MSG_EQ_TOL(c->GetValue(),
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
618void
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
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
678double
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
702void
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.
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
764double
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
789void
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.
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
852double
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
876void
878{
879 NS_LOG_FUNCTION(this);
881
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.
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
933double
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
957void
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.
986 expectedMean,
987 expectedRms * TOLERANCE,
988 "Wrong mean value.");
989}
990
996{
997 public:
998 // Constructor
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
1020double
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
1044void
1046{
1047 NS_LOG_FUNCTION(this);
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
1113double
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
1137void
1139{
1140 NS_LOG_FUNCTION(this);
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
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
1210double
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
1237void
1239{
1240 NS_LOG_FUNCTION(this);
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
1319double
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
1345void
1347{
1348 NS_LOG_FUNCTION(this);
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
1430double
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
1457void
1459{
1460 NS_LOG_FUNCTION(this);
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
1532double
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
1559void
1561{
1562 NS_LOG_FUNCTION(this);
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
1636double
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
1663void
1665{
1666 NS_LOG_FUNCTION(this);
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
1728double
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
1755void
1757{
1758 NS_LOG_FUNCTION(this);
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
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
1824double
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
1854void
1856{
1857 NS_LOG_FUNCTION(this);
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
1919double
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
1949void
1951{
1952 NS_LOG_FUNCTION(this);
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
2015void
2017{
2018 NS_LOG_FUNCTION(this);
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
2095void
2097{
2098 NS_LOG_FUNCTION(this);
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
2178void
2180{
2181 NS_LOG_FUNCTION(this);
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
2241void
2243{
2244 NS_LOG_FUNCTION(this);
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
2304void
2306{
2307 NS_LOG_FUNCTION(this);
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
2382void
2384{
2385 NS_LOG_FUNCTION(this);
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
2482void
2484{
2485 NS_LOG_FUNCTION(this);
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
2555void
2557{
2558 NS_LOG_FUNCTION(this);
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
2595double
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
2610void
2612{
2613 NS_LOG_FUNCTION(this);
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
2666double
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
2681void
2683{
2684 NS_LOG_FUNCTION(this);
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
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
2740double
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
2761void
2763{
2764 NS_LOG_FUNCTION(this);
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
2819double
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
2840void
2842{
2843 NS_LOG_FUNCTION(this);
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", Type::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
Simple average, min, max and std.
Definition: average.h:43
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
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...
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.
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.
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:710
#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:145
#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:252
#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:565
#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:875
#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:338
static RandomVariableSuite randomVariableSuite
Static variable for test initialization.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
-ns3 Test suite for the ns3 wrapper script