/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009-12 University of Washington
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This file is based on rng-test-suite.cc.
*
* Modified by Mitch Watrous <watrous@u.washington.edu>
*
*/
#include <gsl/gsl_cdf.h>
#include <gsl/gsl_histogram.h>
#include <gsl/gsl_sf_zeta.h>
#include <ctime>
#include <fstream>
#include <cmath>
#include "ns3/boolean.h"
#include "ns3/double.h"
#include "ns3/string.h"
#include "ns3/integer.h"
#include "ns3/test.h"
#include "ns3/rng-seed-manager.h"
#include "ns3/random-variable-stream.h"
using namespace ns3;
namespace {
void
FillHistoRangeUniformly (double *array, uint32_t n, double start, double end)
{
double increment = (end - start) / (n - 1.);
double d = start;
for (uint32_t i = 0; i < n; ++i)
{
array[i] = d;
d += increment;
}
}
} // anonymous namespace
// ===========================================================================
// Test case for uniform distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamUniformTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamUniformTestCase ();
virtual ~RandomVariableStreamUniformTestCase ();
double ChiSquaredTest (Ptr<UniformRandomVariable> u);
private:
virtual void DoRun (void);
};
RandomVariableStreamUniformTestCase::RandomVariableStreamUniformTestCase ()
: TestCase ("Uniform Random Variable Stream Generator")
{
}
RandomVariableStreamUniformTestCase::~RandomVariableStreamUniformTestCase ()
{
}
double
RandomVariableStreamUniformTestCase::ChiSquaredTest (Ptr<UniformRandomVariable> u)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
// Note that this assumes that the range for u is [0,1], which is
// the default range for this distribution.
gsl_histogram_set_ranges_uniform (h, 0., 1.);
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, u->GetValue ());
}
double tmp[N_BINS];
double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected;
tmp[i] *= tmp[i];
tmp[i] /= expected;
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamUniformTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<UniformRandomVariable> u = CreateObject<UniformRandomVariable> ();
double result = ChiSquaredTest (u);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double min = 0.0;
double max = 10.0;
double value;
// Create the RNG with the specified range.
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable> ();
x->SetAttribute ("Min", DoubleValue (min));
x->SetAttribute ("Max", DoubleValue (max));
// Test that values are always within the range:
//
// [min, max)
//
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
NS_TEST_ASSERT_MSG_EQ ((value >= min), true, "Value less than minimum.");
NS_TEST_ASSERT_MSG_LT (value, max, "Value greater than or equal to maximum.");
}
}
// ===========================================================================
// Test case for antithetic uniform distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamUniformAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamUniformAntitheticTestCase ();
virtual ~RandomVariableStreamUniformAntitheticTestCase ();
double ChiSquaredTest (Ptr<UniformRandomVariable> u);
private:
virtual void DoRun (void);
};
RandomVariableStreamUniformAntitheticTestCase::RandomVariableStreamUniformAntitheticTestCase ()
: TestCase ("Antithetic Uniform Random Variable Stream Generator")
{
}
RandomVariableStreamUniformAntitheticTestCase::~RandomVariableStreamUniformAntitheticTestCase ()
{
}
double
RandomVariableStreamUniformAntitheticTestCase::ChiSquaredTest (Ptr<UniformRandomVariable> u)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
// Note that this assumes that the range for u is [0,1], which is
// the default range for this distribution.
gsl_histogram_set_ranges_uniform (h, 0., 1.);
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, u->GetValue ());
}
double tmp[N_BINS];
double expected = ((double)N_MEASUREMENTS / (double)N_BINS);
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected;
tmp[i] *= tmp[i];
tmp[i] /= expected;
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamUniformAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<UniformRandomVariable> u = CreateObject<UniformRandomVariable> ();
// Make this generate antithetic values.
u->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (u);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double min = 0.0;
double max = 10.0;
double value;
// Create the RNG with the specified range.
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable> ();
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
x->SetAttribute ("Min", DoubleValue (min));
x->SetAttribute ("Max", DoubleValue (max));
// Test that values are always within the range:
//
// [min, max)
//
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
NS_TEST_ASSERT_MSG_EQ ((value >= min), true, "Value less than minimum.");
NS_TEST_ASSERT_MSG_LT (value, max, "Value greater than or equal to maximum.");
}
}
// ===========================================================================
// Test case for constant random variable stream generator
// ===========================================================================
class RandomVariableStreamConstantTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
static const double TOLERANCE = 1e-8;
RandomVariableStreamConstantTestCase ();
virtual ~RandomVariableStreamConstantTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamConstantTestCase::RandomVariableStreamConstantTestCase ()
: TestCase ("Constant Random Variable Stream Generator")
{
}
RandomVariableStreamConstantTestCase::~RandomVariableStreamConstantTestCase ()
{
}
void
RandomVariableStreamConstantTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
Ptr<ConstantRandomVariable> c = CreateObject<ConstantRandomVariable> ();
double constant;
// Test that the constant value can be changed using its attribute.
constant = 10.0;
c->SetAttribute ("Constant", DoubleValue (constant));
NS_TEST_ASSERT_MSG_EQ_TOL (c->GetValue (), constant, TOLERANCE, "Constant value changed");
c->SetAttribute ("Constant", DoubleValue (20.0));
NS_TEST_ASSERT_MSG_NE (c->GetValue (), constant, "Constant value not changed");
// Test that the constant value does not change.
constant = c->GetValue ();
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
NS_TEST_ASSERT_MSG_EQ_TOL (c->GetValue (), constant, TOLERANCE, "Constant value changed in loop");
}
}
// ===========================================================================
// Test case for sequential random variable stream generator
// ===========================================================================
class RandomVariableStreamSequentialTestCase : public TestCase
{
public:
static const double TOLERANCE = 1e-8;
RandomVariableStreamSequentialTestCase ();
virtual ~RandomVariableStreamSequentialTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamSequentialTestCase::RandomVariableStreamSequentialTestCase ()
: TestCase ("Sequential Random Variable Stream Generator")
{
}
RandomVariableStreamSequentialTestCase::~RandomVariableStreamSequentialTestCase ()
{
}
void
RandomVariableStreamSequentialTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
Ptr<SequentialRandomVariable> s = CreateObject<SequentialRandomVariable> ();
// The following four attributes should give the sequence
//
// 4, 4, 7, 7, 10, 10
//
s->SetAttribute ("Min", DoubleValue (4));
s->SetAttribute ("Max", DoubleValue (11));
s->SetAttribute ("Increment", StringValue("ns3::UniformRandomVariable[Min=3.0|Max=3.0]"));
s->SetAttribute ("Consecutive", IntegerValue (2));
double value;
// Test that the sequencet is correct.
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 4, TOLERANCE, "Sequence value 1 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 4, TOLERANCE, "Sequence value 2 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 7, TOLERANCE, "Sequence value 3 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 7, TOLERANCE, "Sequence value 4 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 10, TOLERANCE, "Sequence value 5 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 10, TOLERANCE, "Sequence value 6 wrong.");
}
// ===========================================================================
// Test case for normal distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamNormalTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamNormalTestCase ();
virtual ~RandomVariableStreamNormalTestCase ();
double ChiSquaredTest (Ptr<NormalRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamNormalTestCase::RandomVariableStreamNormalTestCase ()
: TestCase ("Normal Random Variable Stream Generator")
{
}
RandomVariableStreamNormalTestCase::~RandomVariableStreamNormalTestCase ()
{
}
double
RandomVariableStreamNormalTestCase::ChiSquaredTest (Ptr<NormalRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, -4., 4.);
range[0] = -std::numeric_limits<double>::max ();
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has mean equal to zero and standard
// deviation equal to one, which are their default values for this
// distribution.
double sigma = 1.;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_gaussian_P (range[i + 1], sigma) - gsl_cdf_gaussian_P (range[i], sigma);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamNormalTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<NormalRandomVariable> n = CreateObject<NormalRandomVariable> ();
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mean = 5.0;
double variance = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<NormalRandomVariable> x = CreateObject<NormalRandomVariable> ();
x->SetAttribute ("Mean", DoubleValue (mean));
x->SetAttribute ("Variance", DoubleValue (variance));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// normally distributed random variable is equal to mean.
double expectedMean = mean;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic normal distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamNormalAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamNormalAntitheticTestCase ();
virtual ~RandomVariableStreamNormalAntitheticTestCase ();
double ChiSquaredTest (Ptr<NormalRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamNormalAntitheticTestCase::RandomVariableStreamNormalAntitheticTestCase ()
: TestCase ("Antithetic Normal Random Variable Stream Generator")
{
}
RandomVariableStreamNormalAntitheticTestCase::~RandomVariableStreamNormalAntitheticTestCase ()
{
}
double
RandomVariableStreamNormalAntitheticTestCase::ChiSquaredTest (Ptr<NormalRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, -4., 4.);
range[0] = -std::numeric_limits<double>::max ();
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has mean equal to zero and standard
// deviation equal to one, which are their default values for this
// distribution.
double sigma = 1.;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_gaussian_P (range[i + 1], sigma) - gsl_cdf_gaussian_P (range[i], sigma);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamNormalAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<NormalRandomVariable> n = CreateObject<NormalRandomVariable> ();
// Make this generate antithetic values.
n->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mean = 5.0;
double variance = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<NormalRandomVariable> x = CreateObject<NormalRandomVariable> ();
x->SetAttribute ("Mean", DoubleValue (mean));
x->SetAttribute ("Variance", DoubleValue (variance));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// normally distributed random variable is equal to mean.
double expectedMean = mean;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for exponential distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamExponentialTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamExponentialTestCase ();
virtual ~RandomVariableStreamExponentialTestCase ();
double ChiSquaredTest (Ptr<ExponentialRandomVariable> e);
private:
virtual void DoRun (void);
};
RandomVariableStreamExponentialTestCase::RandomVariableStreamExponentialTestCase ()
: TestCase ("Exponential Random Variable Stream Generator")
{
}
RandomVariableStreamExponentialTestCase::~RandomVariableStreamExponentialTestCase ()
{
}
double
RandomVariableStreamExponentialTestCase::ChiSquaredTest (Ptr<ExponentialRandomVariable> e)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that e has mean equal to one, which is the
// default value for this distribution.
double mu = 1.;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_exponential_P (range[i + 1], mu) - gsl_cdf_exponential_P (range[i], mu);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, e->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamExponentialTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<ExponentialRandomVariable> e = CreateObject<ExponentialRandomVariable> ();
double result = ChiSquaredTest (e);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mean = 3.14;
double bound = 0.0;
double value;
// Create the RNG with the specified range.
Ptr<ExponentialRandomVariable> x = CreateObject<ExponentialRandomVariable> ();
x->SetAttribute ("Mean", DoubleValue (mean));
x->SetAttribute ("Bound", DoubleValue (bound));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// Test that values have approximately the right mean value.
double TOLERANCE = mean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, mean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic exponential distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamExponentialAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamExponentialAntitheticTestCase ();
virtual ~RandomVariableStreamExponentialAntitheticTestCase ();
double ChiSquaredTest (Ptr<ExponentialRandomVariable> e);
private:
virtual void DoRun (void);
};
RandomVariableStreamExponentialAntitheticTestCase::RandomVariableStreamExponentialAntitheticTestCase ()
: TestCase ("Antithetic Exponential Random Variable Stream Generator")
{
}
RandomVariableStreamExponentialAntitheticTestCase::~RandomVariableStreamExponentialAntitheticTestCase ()
{
}
double
RandomVariableStreamExponentialAntitheticTestCase::ChiSquaredTest (Ptr<ExponentialRandomVariable> e)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that e has mean equal to one, which is the
// default value for this distribution.
double mu = 1.;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_exponential_P (range[i + 1], mu) - gsl_cdf_exponential_P (range[i], mu);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, e->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamExponentialAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<ExponentialRandomVariable> e = CreateObject<ExponentialRandomVariable> ();
// Make this generate antithetic values.
e->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (e);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mean = 3.14;
double bound = 0.0;
double value;
// Create the RNG with the specified range.
Ptr<ExponentialRandomVariable> x = CreateObject<ExponentialRandomVariable> ();
x->SetAttribute ("Mean", DoubleValue (mean));
x->SetAttribute ("Bound", DoubleValue (bound));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// Test that values have approximately the right mean value.
double TOLERANCE = mean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, mean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for Pareto distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamParetoTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamParetoTestCase ();
virtual ~RandomVariableStreamParetoTestCase ();
double ChiSquaredTest (Ptr<ParetoRandomVariable> p);
private:
virtual void DoRun (void);
};
RandomVariableStreamParetoTestCase::RandomVariableStreamParetoTestCase ()
: TestCase ("Pareto Random Variable Stream Generator")
{
}
RandomVariableStreamParetoTestCase::~RandomVariableStreamParetoTestCase ()
{
}
double
RandomVariableStreamParetoTestCase::ChiSquaredTest (Ptr<ParetoRandomVariable> p)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that p has mean equal to 1 and shape equal
// to 2, which are their default values for this distribution.
double mean = 1.0;
double shape = 2.0;
double scale = mean * (shape - 1.0) / shape;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_pareto_P (range[i + 1], shape, scale) - gsl_cdf_pareto_P (range[i], shape, scale);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, p->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamParetoTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<ParetoRandomVariable> e = CreateObject<ParetoRandomVariable> ();
double result = ChiSquaredTest (e);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mean = 5.0;
double shape = 2.0;
double scale = mean * (shape - 1.0) / shape;
double value;
// Create the RNG with the specified range.
Ptr<ParetoRandomVariable> x = CreateObject<ParetoRandomVariable> ();
x->SetAttribute ("Mean", DoubleValue (mean));
x->SetAttribute ("Shape", DoubleValue (shape));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean is given by
//
// shape * scale
// E[value] = --------------- ,
// shape - 1
//
// where
//
// scale = mean * (shape - 1.0) / shape .
double expectedMean = (shape * scale) / (shape - 1.0);
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic Pareto distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamParetoAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamParetoAntitheticTestCase ();
virtual ~RandomVariableStreamParetoAntitheticTestCase ();
double ChiSquaredTest (Ptr<ParetoRandomVariable> p);
private:
virtual void DoRun (void);
};
RandomVariableStreamParetoAntitheticTestCase::RandomVariableStreamParetoAntitheticTestCase ()
: TestCase ("Antithetic Pareto Random Variable Stream Generator")
{
}
RandomVariableStreamParetoAntitheticTestCase::~RandomVariableStreamParetoAntitheticTestCase ()
{
}
double
RandomVariableStreamParetoAntitheticTestCase::ChiSquaredTest (Ptr<ParetoRandomVariable> p)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that p has mean equal to 1 and shape equal
// to 2, which are their default values for this distribution.
double mean = 1.0;
double shape = 2.0;
double scale = mean * (shape - 1.0) / shape;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_pareto_P (range[i + 1], shape, scale) - gsl_cdf_pareto_P (range[i], shape, scale);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, p->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamParetoAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<ParetoRandomVariable> e = CreateObject<ParetoRandomVariable> ();
// Make this generate antithetic values.
e->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (e);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mean = 5.0;
double shape = 2.0;
double scale = mean * (shape - 1.0) / shape;
double value;
// Create the RNG with the specified range.
Ptr<ParetoRandomVariable> x = CreateObject<ParetoRandomVariable> ();
x->SetAttribute ("Mean", DoubleValue (mean));
x->SetAttribute ("Shape", DoubleValue (shape));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean is given by
//
// shape * scale
// E[value] = --------------- ,
// shape - 1
//
// where
//
// scale = mean * (shape - 1.0) / shape .
//
double expectedMean = (shape * scale) / (shape - 1.0);
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for Weibull distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamWeibullTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamWeibullTestCase ();
virtual ~RandomVariableStreamWeibullTestCase ();
double ChiSquaredTest (Ptr<WeibullRandomVariable> p);
private:
virtual void DoRun (void);
};
RandomVariableStreamWeibullTestCase::RandomVariableStreamWeibullTestCase ()
: TestCase ("Weibull Random Variable Stream Generator")
{
}
RandomVariableStreamWeibullTestCase::~RandomVariableStreamWeibullTestCase ()
{
}
double
RandomVariableStreamWeibullTestCase::ChiSquaredTest (Ptr<WeibullRandomVariable> p)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that p has shape equal to one and scale
// equal to one, which are their default values for this
// distribution.
double a = 1.0;
double b = 1.0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_weibull_P (range[i + 1], a, b) - gsl_cdf_weibull_P (range[i], a, b);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, p->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamWeibullTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<WeibullRandomVariable> e = CreateObject<WeibullRandomVariable> ();
double result = ChiSquaredTest (e);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double scale = 5.0;
double shape = 1.0;
double value;
// Create the RNG with the specified range.
Ptr<WeibullRandomVariable> x = CreateObject<WeibullRandomVariable> ();
x->SetAttribute ("Scale", DoubleValue (scale));
x->SetAttribute ("Shape", DoubleValue (shape));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// Weibull distributed random variable is
//
// E[value] = scale * Gamma(1 + 1 / shape) ,
//
// where Gamma() is the Gamma function. Note that
//
// Gamma(n) = (n - 1)!
//
// if n is a positive integer.
//
// For this test,
//
// Gamma(1 + 1 / shape) = Gamma(1 + 1 / 1)
// = Gamma(2)
// = (2 - 1)!
// = 1
//
// which means
//
// E[value] = scale .
//
double expectedMean = scale;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic Weibull distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamWeibullAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamWeibullAntitheticTestCase ();
virtual ~RandomVariableStreamWeibullAntitheticTestCase ();
double ChiSquaredTest (Ptr<WeibullRandomVariable> p);
private:
virtual void DoRun (void);
};
RandomVariableStreamWeibullAntitheticTestCase::RandomVariableStreamWeibullAntitheticTestCase ()
: TestCase ("Antithetic Weibull Random Variable Stream Generator")
{
}
RandomVariableStreamWeibullAntitheticTestCase::~RandomVariableStreamWeibullAntitheticTestCase ()
{
}
double
RandomVariableStreamWeibullAntitheticTestCase::ChiSquaredTest (Ptr<WeibullRandomVariable> p)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 1., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that p has shape equal to one and scale
// equal to one, which are their default values for this
// distribution.
double a = 1.0;
double b = 1.0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_weibull_P (range[i + 1], a, b) - gsl_cdf_weibull_P (range[i], a, b);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, p->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamWeibullAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<WeibullRandomVariable> e = CreateObject<WeibullRandomVariable> ();
// Make this generate antithetic values.
e->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (e);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double scale = 5.0;
double shape = 1.0;
double value;
// Create the RNG with the specified range.
Ptr<WeibullRandomVariable> x = CreateObject<WeibullRandomVariable> ();
x->SetAttribute ("Scale", DoubleValue (scale));
x->SetAttribute ("Shape", DoubleValue (shape));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// Weibull distributed random variable is
//
// E[value] = scale * Gamma(1 + 1 / shape) ,
//
// where Gamma() is the Gamma function. Note that
//
// Gamma(n) = (n - 1)!
//
// if n is a positive integer.
//
// For this test,
//
// Gamma(1 + 1 / shape) = Gamma(1 + 1 / 1)
// = Gamma(2)
// = (2 - 1)!
// = 1
//
// which means
//
// E[value] = scale .
//
double expectedMean = scale;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for log-normal distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamLogNormalTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamLogNormalTestCase ();
virtual ~RandomVariableStreamLogNormalTestCase ();
double ChiSquaredTest (Ptr<LogNormalRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamLogNormalTestCase::RandomVariableStreamLogNormalTestCase ()
: TestCase ("Log-Normal Random Variable Stream Generator")
{
}
RandomVariableStreamLogNormalTestCase::~RandomVariableStreamLogNormalTestCase ()
{
}
double
RandomVariableStreamLogNormalTestCase::ChiSquaredTest (Ptr<LogNormalRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has mu equal to zero and sigma
// equal to one, which are their default values for this
// distribution.
double mu = 0.0;
double sigma = 1.0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_lognormal_P (range[i + 1], mu, sigma) - gsl_cdf_lognormal_P (range[i], mu, sigma);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamLogNormalTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<LogNormalRandomVariable> n = CreateObject<LogNormalRandomVariable> ();
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mu = 5.0;
double sigma = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<LogNormalRandomVariable> x = CreateObject<LogNormalRandomVariable> ();
x->SetAttribute ("Mu", DoubleValue (mu));
x->SetAttribute ("Sigma", DoubleValue (sigma));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// log-normally distributed random variable is equal to
//
// 2
// mu + sigma / 2
// E[value] = e .
//
double expectedMean = std::exp(mu + sigma * sigma / 2.0);
// Test that values have approximately the right mean value.
//
/// \todo This test fails sometimes if the required tolerance is less
/// than 3%, which may be because there is a bug in the
/// implementation or that the mean of this distribution is more
/// senstive to its parameters than the others are.
double TOLERANCE = expectedMean * 3e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic log-normal distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamLogNormalAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamLogNormalAntitheticTestCase ();
virtual ~RandomVariableStreamLogNormalAntitheticTestCase ();
double ChiSquaredTest (Ptr<LogNormalRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamLogNormalAntitheticTestCase::RandomVariableStreamLogNormalAntitheticTestCase ()
: TestCase ("Antithetic Log-Normal Random Variable Stream Generator")
{
}
RandomVariableStreamLogNormalAntitheticTestCase::~RandomVariableStreamLogNormalAntitheticTestCase ()
{
}
double
RandomVariableStreamLogNormalAntitheticTestCase::ChiSquaredTest (Ptr<LogNormalRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has mu equal to zero and sigma
// equal to one, which are their default values for this
// distribution.
double mu = 0.0;
double sigma = 1.0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_lognormal_P (range[i + 1], mu, sigma) - gsl_cdf_lognormal_P (range[i], mu, sigma);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamLogNormalAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<LogNormalRandomVariable> n = CreateObject<LogNormalRandomVariable> ();
// Make this generate antithetic values.
n->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double mu = 5.0;
double sigma = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<LogNormalRandomVariable> x = CreateObject<LogNormalRandomVariable> ();
x->SetAttribute ("Mu", DoubleValue (mu));
x->SetAttribute ("Sigma", DoubleValue (sigma));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// log-normally distributed random variable is equal to
//
// 2
// mu + sigma / 2
// E[value] = e .
//
double expectedMean = std::exp(mu + sigma * sigma / 2.0);
// Test that values have approximately the right mean value.
//
/// \todo This test fails sometimes if the required tolerance is less
/// than 3%, which may be because there is a bug in the
/// implementation or that the mean of this distribution is more
/// senstive to its parameters than the others are.
double TOLERANCE = expectedMean * 3e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for gamma distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamGammaTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamGammaTestCase ();
virtual ~RandomVariableStreamGammaTestCase ();
double ChiSquaredTest (Ptr<GammaRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamGammaTestCase::RandomVariableStreamGammaTestCase ()
: TestCase ("Gamma Random Variable Stream Generator")
{
}
RandomVariableStreamGammaTestCase::~RandomVariableStreamGammaTestCase ()
{
}
double
RandomVariableStreamGammaTestCase::ChiSquaredTest (Ptr<GammaRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has alpha equal to one and beta
// equal to one, which are their default values for this
// distribution.
double alpha = 1.0;
double beta = 1.0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_gamma_P (range[i + 1], alpha, beta) - gsl_cdf_gamma_P (range[i], alpha, beta);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamGammaTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<GammaRandomVariable> n = CreateObject<GammaRandomVariable> ();
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double alpha = 5.0;
double beta = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<GammaRandomVariable> x = CreateObject<GammaRandomVariable> ();
x->SetAttribute ("Alpha", DoubleValue (alpha));
x->SetAttribute ("Beta", DoubleValue (beta));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// gammaly distributed random variable is equal to
//
// E[value] = alpha * beta .
//
double expectedMean = alpha * beta;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic gamma distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamGammaAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamGammaAntitheticTestCase ();
virtual ~RandomVariableStreamGammaAntitheticTestCase ();
double ChiSquaredTest (Ptr<GammaRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamGammaAntitheticTestCase::RandomVariableStreamGammaAntitheticTestCase ()
: TestCase ("Antithetic Gamma Random Variable Stream Generator")
{
}
RandomVariableStreamGammaAntitheticTestCase::~RandomVariableStreamGammaAntitheticTestCase ()
{
}
double
RandomVariableStreamGammaAntitheticTestCase::ChiSquaredTest (Ptr<GammaRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has alpha equal to one and beta
// equal to one, which are their default values for this
// distribution.
double alpha = 1.0;
double beta = 1.0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_gamma_P (range[i + 1], alpha, beta) - gsl_cdf_gamma_P (range[i], alpha, beta);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamGammaAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<GammaRandomVariable> n = CreateObject<GammaRandomVariable> ();
// Make this generate antithetic values.
n->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
double alpha = 5.0;
double beta = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<GammaRandomVariable> x = CreateObject<GammaRandomVariable> ();
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
x->SetAttribute ("Alpha", DoubleValue (alpha));
x->SetAttribute ("Beta", DoubleValue (beta));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// gammaly distributed random variable is equal to
//
// E[value] = alpha * beta .
//
double expectedMean = alpha * beta;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for Erlang distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamErlangTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamErlangTestCase ();
virtual ~RandomVariableStreamErlangTestCase ();
double ChiSquaredTest (Ptr<ErlangRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamErlangTestCase::RandomVariableStreamErlangTestCase ()
: TestCase ("Erlang Random Variable Stream Generator")
{
}
RandomVariableStreamErlangTestCase::~RandomVariableStreamErlangTestCase ()
{
}
double
RandomVariableStreamErlangTestCase::ChiSquaredTest (Ptr<ErlangRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has k equal to one and lambda
// equal to one, which are their default values for this
// distribution.
uint32_t k = 1;
double lambda = 1.0;
// Note that Erlang distribution is equal to the gamma distribution
// when k is an iteger, which is why the gamma distribution's cdf
// function can be used here.
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_gamma_P (range[i + 1], k, lambda) - gsl_cdf_gamma_P (range[i], k, lambda);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamErlangTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<ErlangRandomVariable> n = CreateObject<ErlangRandomVariable> ();
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
uint32_t k = 5;
double lambda = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<ErlangRandomVariable> x = CreateObject<ErlangRandomVariable> ();
x->SetAttribute ("K", IntegerValue (k));
x->SetAttribute ("Lambda", DoubleValue (lambda));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// Erlangly distributed random variable is equal to
//
// E[value] = k * lambda .
//
double expectedMean = k * lambda;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic Erlang distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamErlangAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_RUNS = 5;
static const uint32_t N_BINS = 50;
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamErlangAntitheticTestCase ();
virtual ~RandomVariableStreamErlangAntitheticTestCase ();
double ChiSquaredTest (Ptr<ErlangRandomVariable> n);
private:
virtual void DoRun (void);
};
RandomVariableStreamErlangAntitheticTestCase::RandomVariableStreamErlangAntitheticTestCase ()
: TestCase ("Antithetic Erlang Random Variable Stream Generator")
{
}
RandomVariableStreamErlangAntitheticTestCase::~RandomVariableStreamErlangAntitheticTestCase ()
{
}
double
RandomVariableStreamErlangAntitheticTestCase::ChiSquaredTest (Ptr<ErlangRandomVariable> n)
{
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
double range[N_BINS + 1];
FillHistoRangeUniformly (range, N_BINS + 1, 0., 10.);
range[N_BINS] = std::numeric_limits<double>::max ();
gsl_histogram_set_ranges (h, range, N_BINS + 1);
double expected[N_BINS];
// Note that this assumes that n has k equal to one and lambda
// equal to one, which are their default values for this
// distribution.
uint32_t k = 1;
double lambda = 1.0;
// Note that Erlang distribution is equal to the gamma distribution
// when k is an iteger, which is why the gamma distribution's cdf
// function can be used here.
for (uint32_t i = 0; i < N_BINS; ++i)
{
expected[i] = gsl_cdf_gamma_P (range[i + 1], k, lambda) - gsl_cdf_gamma_P (range[i], k, lambda);
expected[i] *= N_MEASUREMENTS;
}
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
gsl_histogram_increment (h, n->GetValue ());
}
double tmp[N_BINS];
for (uint32_t i = 0; i < N_BINS; ++i)
{
tmp[i] = gsl_histogram_get (h, i);
tmp[i] -= expected[i];
tmp[i] *= tmp[i];
tmp[i] /= expected[i];
}
gsl_histogram_free (h);
double chiSquared = 0;
for (uint32_t i = 0; i < N_BINS; ++i)
{
chiSquared += tmp[i];
}
return chiSquared;
}
void
RandomVariableStreamErlangAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double sum = 0.;
double maxStatistic = gsl_cdf_chisq_Qinv (0.05, N_BINS);
for (uint32_t i = 0; i < N_RUNS; ++i)
{
Ptr<ErlangRandomVariable> n = CreateObject<ErlangRandomVariable> ();
// Make this generate antithetic values.
n->SetAttribute ("Antithetic", BooleanValue (true));
double result = ChiSquaredTest (n);
sum += result;
}
sum /= (double)N_RUNS;
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
uint32_t k = 5;
double lambda = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<ErlangRandomVariable> x = CreateObject<ErlangRandomVariable> ();
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
x->SetAttribute ("K", IntegerValue (k));
x->SetAttribute ("Lambda", DoubleValue (lambda));
// Calculate the mean of these values.
sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// Erlangly distributed random variable is equal to
//
// E[value] = k * lambda .
//
double expectedMean = k * lambda;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for Zipf distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamZipfTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamZipfTestCase ();
virtual ~RandomVariableStreamZipfTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamZipfTestCase::RandomVariableStreamZipfTestCase ()
: TestCase ("Zipf Random Variable Stream Generator")
{
}
RandomVariableStreamZipfTestCase::~RandomVariableStreamZipfTestCase ()
{
}
void
RandomVariableStreamZipfTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
uint32_t n = 1;
double alpha = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<ZipfRandomVariable> x = CreateObject<ZipfRandomVariable> ();
x->SetAttribute ("N", IntegerValue (n));
x->SetAttribute ("Alpha", DoubleValue (alpha));
// Calculate the mean of these values.
double sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// Zipfly distributed random variable is equal to
//
// H
// N, alpha - 1
// E[value] = ---------------
// H
// N, alpha
//
// where
//
// N
// ---
// \ -alpha
// H = / m .
// N, alpha ---
// m=1
//
// For this test,
//
// -(alpha - 1)
// 1
// E[value] = ---------------
// -alpha
// 1
//
// = 1 .
//
double expectedMean = 1.0;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic Zipf distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamZipfAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamZipfAntitheticTestCase ();
virtual ~RandomVariableStreamZipfAntitheticTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamZipfAntitheticTestCase::RandomVariableStreamZipfAntitheticTestCase ()
: TestCase ("Antithetic Zipf Random Variable Stream Generator")
{
}
RandomVariableStreamZipfAntitheticTestCase::~RandomVariableStreamZipfAntitheticTestCase ()
{
}
void
RandomVariableStreamZipfAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
uint32_t n = 1;
double alpha = 2.0;
double value;
// Create the RNG with the specified range.
Ptr<ZipfRandomVariable> x = CreateObject<ZipfRandomVariable> ();
x->SetAttribute ("N", IntegerValue (n));
x->SetAttribute ("Alpha", DoubleValue (alpha));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
double sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// Zipfly distributed random variable is equal to
//
// H
// N, alpha - 1
// E[value] = ---------------
// H
// N, alpha
//
// where
//
// N
// ---
// \ -alpha
// H = / m .
// N, alpha ---
// m=1
//
// For this test,
//
// -(alpha - 1)
// 1
// E[value] = ---------------
// -alpha
// 1
//
// = 1 .
//
double expectedMean = 1.0;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for Zeta distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamZetaTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamZetaTestCase ();
virtual ~RandomVariableStreamZetaTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamZetaTestCase::RandomVariableStreamZetaTestCase ()
: TestCase ("Zeta Random Variable Stream Generator")
{
}
RandomVariableStreamZetaTestCase::~RandomVariableStreamZetaTestCase ()
{
}
void
RandomVariableStreamZetaTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double alpha = 5.0;
double value;
// Create the RNG with the specified range.
Ptr<ZetaRandomVariable> x = CreateObject<ZetaRandomVariable> ();
x->SetAttribute ("Alpha", DoubleValue (alpha));
// Calculate the mean of these values.
double sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// zetaly distributed random variable is equal to
//
// zeta(alpha - 1)
// E[value] = --------------- for alpha > 2 ,
// zeta(alpha)
//
// where zeta(alpha) is the Riemann zeta function.
//
// There are no simple analytic forms for the Riemann zeta function,
// which is why the gsl library is used in this test to calculate
// the known mean of the values.
double expectedMean = gsl_sf_zeta_int (alpha - 1) / gsl_sf_zeta_int (alpha);
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic Zeta distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamZetaAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamZetaAntitheticTestCase ();
virtual ~RandomVariableStreamZetaAntitheticTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamZetaAntitheticTestCase::RandomVariableStreamZetaAntitheticTestCase ()
: TestCase ("Antithetic Zeta Random Variable Stream Generator")
{
}
RandomVariableStreamZetaAntitheticTestCase::~RandomVariableStreamZetaAntitheticTestCase ()
{
}
void
RandomVariableStreamZetaAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
double alpha = 5.0;
double value;
// Create the RNG with the specified range.
Ptr<ZetaRandomVariable> x = CreateObject<ZetaRandomVariable> ();
x->SetAttribute ("Alpha", DoubleValue (alpha));
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
double sum = 0.0;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by a
// zetaly distributed random variable is equal to
//
// zeta(alpha - 1)
// E[value] = --------------- for alpha > 2 ,
// zeta(alpha)
//
// where zeta(alpha) is the Riemann zeta function.
//
// There are no simple analytic forms for the Riemann zeta function,
// which is why the gsl library is used in this test to calculate
// the known mean of the values.
double expectedMean = gsl_sf_zeta_int (alpha - 1) / gsl_sf_zeta_int (alpha);
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for deterministic random variable stream generator
// ===========================================================================
class RandomVariableStreamDeterministicTestCase : public TestCase
{
public:
static const double TOLERANCE = 1e-8;
RandomVariableStreamDeterministicTestCase ();
virtual ~RandomVariableStreamDeterministicTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamDeterministicTestCase::RandomVariableStreamDeterministicTestCase ()
: TestCase ("Deterministic Random Variable Stream Generator")
{
}
RandomVariableStreamDeterministicTestCase::~RandomVariableStreamDeterministicTestCase ()
{
}
void
RandomVariableStreamDeterministicTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
Ptr<DeterministicRandomVariable> s = CreateObject<DeterministicRandomVariable> ();
// The following array should give the sequence
//
// 4, 4, 7, 7, 10, 10 .
//
double array1 [] = { 4, 4, 7, 7, 10, 10};
uint64_t count1 = 6;
s->SetValueArray (array1, count1);
double value;
// Test that the first sequence is correct.
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 4, TOLERANCE, "Sequence 1 value 1 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 4, TOLERANCE, "Sequence 1 value 2 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 7, TOLERANCE, "Sequence 1 value 3 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 7, TOLERANCE, "Sequence 1 value 4 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 10, TOLERANCE, "Sequence 1 value 5 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 10, TOLERANCE, "Sequence 1 value 6 wrong.");
// The following array should give the sequence
//
// 1000, 2000, 7, 7 .
//
double array2 [] = { 1000, 2000, 3000, 4000};
uint64_t count2 = 4;
s->SetValueArray (array2, count2);
// Test that the second sequence is correct.
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 1000, TOLERANCE, "Sequence 2 value 1 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 2000, TOLERANCE, "Sequence 2 value 2 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 3000, TOLERANCE, "Sequence 2 value 3 wrong.");
value = s->GetValue ();
NS_TEST_ASSERT_MSG_EQ_TOL (value, 4000, TOLERANCE, "Sequence 2 value 4 wrong.");
value = s->GetValue ();
}
// ===========================================================================
// Test case for empirical distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamEmpiricalTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamEmpiricalTestCase ();
virtual ~RandomVariableStreamEmpiricalTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamEmpiricalTestCase::RandomVariableStreamEmpiricalTestCase ()
: TestCase ("Empirical Random Variable Stream Generator")
{
}
RandomVariableStreamEmpiricalTestCase::~RandomVariableStreamEmpiricalTestCase ()
{
}
void
RandomVariableStreamEmpiricalTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
// Create the RNG with a uniform distribution between 0 and 10.
Ptr<EmpiricalRandomVariable> x = CreateObject<EmpiricalRandomVariable> ();
x->CDF ( 0.0, 0.0);
x->CDF ( 5.0, 0.5);
x->CDF (10.0, 1.0);
// Calculate the mean of these values.
double sum = 0.0;
double value;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by this
// empirical distribution is the midpoint of the distribution
//
// E[value] = 5 .
//
double expectedMean = 5.0;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
// ===========================================================================
// Test case for antithetic empirical distribution random variable stream generator
// ===========================================================================
class RandomVariableStreamEmpiricalAntitheticTestCase : public TestCase
{
public:
static const uint32_t N_MEASUREMENTS = 1000000;
RandomVariableStreamEmpiricalAntitheticTestCase ();
virtual ~RandomVariableStreamEmpiricalAntitheticTestCase ();
private:
virtual void DoRun (void);
};
RandomVariableStreamEmpiricalAntitheticTestCase::RandomVariableStreamEmpiricalAntitheticTestCase ()
: TestCase ("EmpiricalAntithetic Random Variable Stream Generator")
{
}
RandomVariableStreamEmpiricalAntitheticTestCase::~RandomVariableStreamEmpiricalAntitheticTestCase ()
{
}
void
RandomVariableStreamEmpiricalAntitheticTestCase::DoRun (void)
{
SeedManager::SetSeed (time (0));
// Create the RNG with a uniform distribution between 0 and 10.
Ptr<EmpiricalRandomVariable> x = CreateObject<EmpiricalRandomVariable> ();
x->CDF ( 0.0, 0.0);
x->CDF ( 5.0, 0.5);
x->CDF (10.0, 1.0);
// Make this generate antithetic values.
x->SetAttribute ("Antithetic", BooleanValue (true));
// Calculate the mean of these values.
double sum = 0.0;
double value;
for (uint32_t i = 0; i < N_MEASUREMENTS; ++i)
{
value = x->GetValue ();
sum += value;
}
double valueMean = sum / N_MEASUREMENTS;
// The expected value for the mean of the values returned by this
// empirical distribution is the midpoint of the distribution
//
// E[value] = 5 .
//
double expectedMean = 5.0;
// Test that values have approximately the right mean value.
double TOLERANCE = expectedMean * 1e-2;
NS_TEST_ASSERT_MSG_EQ_TOL (valueMean, expectedMean, TOLERANCE, "Wrong mean value.");
}
class RandomVariableStreamTestSuite : public TestSuite
{
public:
RandomVariableStreamTestSuite ();
};
RandomVariableStreamTestSuite::RandomVariableStreamTestSuite ()
: TestSuite ("random-variable-stream-generators", UNIT)
{
AddTestCase (new RandomVariableStreamUniformTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamUniformAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamConstantTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamSequentialTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamNormalTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamNormalAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamExponentialTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamExponentialAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamParetoTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamParetoAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamWeibullTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamWeibullAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamLogNormalTestCase, TestCase::QUICK);
/// \todo This test is currently disabled because it fails sometimes.
/// A possible reason for the failure is that the antithetic code is
/// not implemented properly for this log-normal case.
/*
AddTestCase (new RandomVariableStreamLogNormalAntitheticTestCase, TestCase::QUICK);
*/
AddTestCase (new RandomVariableStreamGammaTestCase, TestCase::QUICK);
/// \todo This test is currently disabled because it fails sometimes.
/// A possible reason for the failure is that the antithetic code is
/// not implemented properly for this gamma case.
/*
AddTestCase (new RandomVariableStreamGammaAntitheticTestCase, TestCase::QUICK);
*/
AddTestCase (new RandomVariableStreamErlangTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamErlangAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamZipfTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamZipfAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamZetaTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamZetaAntitheticTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamDeterministicTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamEmpiricalTestCase, TestCase::QUICK);
AddTestCase (new RandomVariableStreamEmpiricalAntitheticTestCase, TestCase::QUICK);
}
static RandomVariableStreamTestSuite randomVariableStreamTestSuite;