435 lines
9.6 KiB
C++
435 lines
9.6 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* 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
|
|
*/
|
|
|
|
|
|
#include <math.h>
|
|
#include <gsl/gsl_cdf.h>
|
|
#include <gsl/gsl_histogram.h>
|
|
#include <time.h>
|
|
#include <fstream>
|
|
|
|
#include "test.h"
|
|
#include "random-variable.h"
|
|
|
|
using namespace ns3;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Test case for uniform distribution random number generator
|
|
// ===========================================================================
|
|
class RngUniformTestCase : public TestCase
|
|
{
|
|
public:
|
|
static const uint32_t N_RUNS = 5;
|
|
static const uint32_t N_BINS = 50;
|
|
static const uint32_t N_MEASUREMENTS = 1000000;
|
|
|
|
RngUniformTestCase ();
|
|
virtual ~RngUniformTestCase ();
|
|
|
|
double ChiSquaredTest (UniformVariable &u);
|
|
|
|
private:
|
|
virtual bool DoRun (void);
|
|
};
|
|
|
|
RngUniformTestCase::RngUniformTestCase ()
|
|
: TestCase ("Uniform Random Number Generator")
|
|
{
|
|
}
|
|
|
|
RngUniformTestCase::~RngUniformTestCase ()
|
|
{
|
|
}
|
|
|
|
double
|
|
RngUniformTestCase::ChiSquaredTest (UniformVariable &u)
|
|
{
|
|
gsl_histogram * h = gsl_histogram_alloc (N_BINS);
|
|
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;
|
|
}
|
|
|
|
bool
|
|
RngUniformTestCase::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)
|
|
{
|
|
UniformVariable u;
|
|
double result = ChiSquaredTest (u);
|
|
sum += result;
|
|
}
|
|
|
|
sum /= (double)N_RUNS;
|
|
|
|
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
|
|
return false;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Test case for normal distribution random number generator
|
|
// ===========================================================================
|
|
class RngNormalTestCase : public TestCase
|
|
{
|
|
public:
|
|
static const uint32_t N_RUNS = 5;
|
|
static const uint32_t N_BINS = 50;
|
|
static const uint32_t N_MEASUREMENTS = 1000000;
|
|
|
|
RngNormalTestCase ();
|
|
virtual ~RngNormalTestCase ();
|
|
|
|
double ChiSquaredTest (NormalVariable &n);
|
|
|
|
private:
|
|
virtual bool DoRun (void);
|
|
};
|
|
|
|
RngNormalTestCase::RngNormalTestCase ()
|
|
: TestCase ("Normal Random Number Generator")
|
|
{
|
|
}
|
|
|
|
RngNormalTestCase::~RngNormalTestCase ()
|
|
{
|
|
}
|
|
|
|
double
|
|
RngNormalTestCase::ChiSquaredTest (NormalVariable &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];
|
|
|
|
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;
|
|
}
|
|
|
|
bool
|
|
RngNormalTestCase::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)
|
|
{
|
|
NormalVariable n;
|
|
double result = ChiSquaredTest (n);
|
|
sum += result;
|
|
}
|
|
|
|
sum /= (double)N_RUNS;
|
|
|
|
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
|
|
return false;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Test case for exponential distribution random number generator
|
|
// ===========================================================================
|
|
class RngExponentialTestCase : public TestCase
|
|
{
|
|
public:
|
|
static const uint32_t N_RUNS = 5;
|
|
static const uint32_t N_BINS = 50;
|
|
static const uint32_t N_MEASUREMENTS = 1000000;
|
|
|
|
RngExponentialTestCase ();
|
|
virtual ~RngExponentialTestCase ();
|
|
|
|
double ChiSquaredTest (ExponentialVariable &n);
|
|
|
|
private:
|
|
virtual bool DoRun (void);
|
|
};
|
|
|
|
RngExponentialTestCase::RngExponentialTestCase ()
|
|
: TestCase ("Exponential Random Number Generator")
|
|
{
|
|
}
|
|
|
|
RngExponentialTestCase::~RngExponentialTestCase ()
|
|
{
|
|
}
|
|
|
|
double
|
|
RngExponentialTestCase::ChiSquaredTest (ExponentialVariable &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];
|
|
|
|
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;
|
|
}
|
|
|
|
bool
|
|
RngExponentialTestCase::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)
|
|
{
|
|
ExponentialVariable e;
|
|
double result = ChiSquaredTest (e);
|
|
sum += result;
|
|
}
|
|
|
|
sum /= (double)N_RUNS;
|
|
|
|
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
|
|
return false;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Test case for pareto distribution random number generator
|
|
// ===========================================================================
|
|
class RngParetoTestCase : public TestCase
|
|
{
|
|
public:
|
|
static const uint32_t N_RUNS = 5;
|
|
static const uint32_t N_BINS = 50;
|
|
static const uint32_t N_MEASUREMENTS = 1000000;
|
|
|
|
RngParetoTestCase ();
|
|
virtual ~RngParetoTestCase ();
|
|
|
|
double ChiSquaredTest (ParetoVariable &p);
|
|
|
|
private:
|
|
virtual bool DoRun (void);
|
|
};
|
|
|
|
RngParetoTestCase::RngParetoTestCase ()
|
|
: TestCase ("Pareto Random Number Generator")
|
|
{
|
|
}
|
|
|
|
RngParetoTestCase::~RngParetoTestCase ()
|
|
{
|
|
}
|
|
|
|
double
|
|
RngParetoTestCase::ChiSquaredTest (ParetoVariable &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];
|
|
|
|
double a = 1.5;
|
|
double b = 0.33333333;
|
|
|
|
for (uint32_t i = 0; i < N_BINS; ++i)
|
|
{
|
|
expected[i] = gsl_cdf_pareto_P (range[i + 1], a, b) - gsl_cdf_pareto_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;
|
|
}
|
|
|
|
bool
|
|
RngParetoTestCase::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)
|
|
{
|
|
ParetoVariable e;
|
|
double result = ChiSquaredTest (e);
|
|
sum += result;
|
|
}
|
|
|
|
sum /= (double)N_RUNS;
|
|
|
|
NS_TEST_ASSERT_MSG_LT (sum, maxStatistic, "Chi-squared statistic out of range");
|
|
return false;
|
|
}
|
|
|
|
class RngTestSuite : public TestSuite
|
|
{
|
|
public:
|
|
RngTestSuite ();
|
|
};
|
|
|
|
RngTestSuite::RngTestSuite ()
|
|
: TestSuite ("random-number-generators", UNIT)
|
|
{
|
|
AddTestCase (new RngUniformTestCase);
|
|
AddTestCase (new RngNormalTestCase);
|
|
AddTestCase (new RngExponentialTestCase);
|
|
AddTestCase (new RngParetoTestCase);
|
|
}
|
|
|
|
RngTestSuite rngTestSuite;
|