Page MenuHomeHEPForge

No OneTemporary

Index: trunk/npstat/stat/Distributions1D.cc
===================================================================
--- trunk/npstat/stat/Distributions1D.cc (revision 743)
+++ trunk/npstat/stat/Distributions1D.cc (revision 744)
@@ -1,2820 +1,2820 @@
#include <cmath>
#include <cfloat>
#include <algorithm>
#include <stdexcept>
#include "geners/binaryIO.hh"
#include "npstat/nm/MathUtils.hh"
#include "npstat/nm/SpecialFunctions.hh"
#include "npstat/nm/interpolate.hh"
#include "npstat/stat/Distributions1D.hh"
#include "npstat/stat/StatUtils.hh"
#include "npstat/stat/distributionReadError.hh"
#define SQR2PI 2.5066282746310005
#define SQRT2 1.41421356237309505
#define SQRPI 1.77245385090551603
#define SQRT2L 1.414213562373095048801689L
#define SQRPIL 1.77245385090551602729816748L
#define TWOPIL 6.28318530717958647692528676656L
static long double inverseErf(const long double fval)
{
long double x = npstat::inverseGaussCdf((fval + 1.0L)/2.0L)/SQRT2L;
for (unsigned i=0; i<2; ++i)
{
const long double guessed = erfl(x);
const long double deri = 2.0L/SQRPIL*expl(-x*x);
x += (fval - guessed)/deri;
}
return x;
}
static unsigned improved_random(npstat::AbsRandomGenerator& g,
long double* generatedRandom)
{
const long double extra = sqrt(DBL_EPSILON);
long double u = 0.0L;
unsigned callcount = 0;
while (u <= 0.0L || u >= 1.0L)
{
u = g()*(1.0L + extra) - extra/2.0L;
u += (g() - 0.5L)*extra;
callcount += 2U;
}
*generatedRandom = u;
return callcount;
}
static unsigned gauss_random(const double mean, const double sigma,
npstat::AbsRandomGenerator& g,
double* generatedRandom)
{
assert(generatedRandom);
long double r1 = 0.0L, r2 = 0.0L;
const unsigned calls = improved_random(g, &r1) + improved_random(g, &r2);
*generatedRandom = mean + sigma*sqrtl(-2.0L*logl(r1))*sinl(TWOPIL*(r2-0.5L));
return calls;
}
// static unsigned gauss_random(const double mean, const double sigma,
// npstat::AbsRandomGenerator& g,
// double* generatedRandom)
// {
// assert(generatedRandom);
// long double r1 = 0.0L;
// const unsigned count = improved_random(g, &r1);
// *generatedRandom = mean + sigma*SQRT2*inverseErf(2.0L*r1 - 1.0L);
// return count;
// }
namespace npstat {
bool SymmetricBeta1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, n_);
return !os.fail();
}
SymmetricBeta1D* SymmetricBeta1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(
gs::ClassId::makeId<SymmetricBeta1D>());
current.ensureSameId(id);
double location, scale;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
double n;
gs::read_pod(in, &n);
if (!in.fail())
return new SymmetricBeta1D(location, scale, n);
}
distributionReadError(in, classname());
return 0;
}
bool SymmetricBeta1D::isEqual(const AbsDistribution1D& otherBase) const
{
const SymmetricBeta1D& r =
static_cast<const SymmetricBeta1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) && n_ == r.n_;
}
SymmetricBeta1D::SymmetricBeta1D(const double location,
const double scale,
const double power)
: AbsScalableDistribution1D(location, scale),
n_(power), intpow_(-1)
{
norm_ = calculateNorm();
}
SymmetricBeta1D::SymmetricBeta1D(const double location,
const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
n_(params[0]), intpow_(-1)
{
norm_ = calculateNorm();
}
double SymmetricBeta1D::calculateNorm()
{
static const double normcoeffs[11] = {
0.5, 0.75, 0.9375, 1.09375, 1.23046875, 1.353515625,
1.46630859375, 1.571044921875, 1.6692352294921875,
1.76197052001953125, 1.85006904602050781};
if (n_ <= -1.0) throw std::invalid_argument(
"In npstat::SymmetricBeta1D::calculateNorm: "
"invalid power parameter");
const int intpow = static_cast<int>(floor(n_));
if (static_cast<double>(intpow) == n_ &&
intpow >= 0 && intpow <= 10)
{
intpow_ = intpow;
return normcoeffs[intpow];
}
else
return Gamma(1.5 + n_)/sqrt(M_PI)/Gamma(1.0 + n_);
}
double SymmetricBeta1D::unscaledDensity(const double x) const
{
const double oneminusrsq = 1.0 - x*x;
if (oneminusrsq <= 0.0)
return 0.0;
else
{
double fcn;
switch (intpow_)
{
case 0:
fcn = 1.0;
break;
case 1:
fcn = oneminusrsq;
break;
case 2:
fcn = oneminusrsq*oneminusrsq;
break;
case 3:
fcn = oneminusrsq*oneminusrsq*oneminusrsq;
break;
case 4:
{
const double tmp2 = oneminusrsq*oneminusrsq;
fcn = tmp2*tmp2;
}
break;
case 5:
{
const double tmp2 = oneminusrsq*oneminusrsq;
fcn = tmp2*tmp2*oneminusrsq;
}
break;
case 6:
{
const double tmp2 = oneminusrsq*oneminusrsq;
fcn = tmp2*tmp2*tmp2;
}
break;
default:
fcn = pow(oneminusrsq, n_);
break;
}
return norm_*fcn;
}
}
double SymmetricBeta1D::unscaledCdf(const double x) const
{
if (x >= 1.0)
return 1.0;
else if (x <= -1.0)
return 0.0;
else if (n_ == 0.0)
return (x + 1.0)/2.0;
else
return incompleteBeta(n_+1.0, n_+1.0, (x + 1.0)/2.0);
}
double SymmetricBeta1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::SymmetricBeta1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return -1.0;
else if (r1 == 1.0)
return 1.0;
else
{
double r;
if (n_ == 0.0)
r = r1*2.0 - 1.0;
else
r = 2.0*inverseIncompleteBeta(n_+1.0, n_+1.0, r1) - 1.0;
if (r < -1.0)
r = -1.0;
else if (r > 1.0)
r = 1.0;
return r;
}
}
bool Beta1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, alpha_);
gs::write_pod(os, beta_);
return !os.fail();
}
Beta1D* Beta1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Beta1D>());
current.ensureSameId(id);
double location, scale, a, b;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &a);
gs::read_pod(in, &b);
if (!in.fail())
return new Beta1D(location, scale, a, b);
}
distributionReadError(in, classname());
return 0;
}
bool Beta1D::isEqual(const AbsDistribution1D& otherBase) const
{
const Beta1D& r = static_cast<const Beta1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
alpha_ == r.alpha_ && beta_ == r.beta_;
}
Beta1D::Beta1D(const double location, const double scale,
const double pa, const double pb)
: AbsScalableDistribution1D(location, scale),
alpha_(pa),
beta_(pb)
{
norm_ = calculateNorm();
}
Beta1D::Beta1D(const double location,
const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
alpha_(params[0]),
beta_(params[1])
{
norm_ = calculateNorm();
}
double Beta1D::calculateNorm() const
{
if (!(alpha_ > 0.0 && beta_ > 0.0)) throw std::invalid_argument(
"In npstat::Beta1D::calculateNorm: invalid power parameters");
return Gamma(alpha_ + beta_)/Gamma(alpha_)/Gamma(beta_);
}
double Beta1D::unscaledDensity(const double x) const
{
if (x <= 0.0 || x >= 1.0)
return 0.0;
else if (alpha_ == 1.0 && beta_ == 1.0)
return 1.0;
else
return norm_*pow(x, alpha_-1.0)*pow(1.0-x, beta_-1.0);
}
double Beta1D::unscaledCdf(const double x) const
{
if (x >= 1.0)
return 1.0;
else if (x <= 0.0)
return 0.0;
else if (alpha_ == 1.0 && beta_ == 1.0)
return x;
else
return incompleteBeta(alpha_, beta_, x);
}
double Beta1D::unscaledExceedance(const double x) const
{
return 1.0 - unscaledCdf(x);
}
double Beta1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Beta1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return 0.0;
else if (r1 == 1.0)
return 1.0;
else if (alpha_ == 1.0 && beta_ == 1.0)
return r1;
else
return inverseIncompleteBeta(alpha_, beta_, r1);
}
Gamma1D::Gamma1D(const double location, const double scale,
const double a)
: AbsScalableDistribution1D(location, scale),
alpha_(a)
{
initialize();
}
Gamma1D::Gamma1D(double location, double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
alpha_(params[0])
{
initialize();
}
void Gamma1D::initialize()
{
if (!(alpha_ > 0.0)) throw std::invalid_argument(
"In npstat::Gamma1D::initialize: invalid power parameter");
norm_ = 1.0/Gamma(alpha_);
}
bool Gamma1D::isEqual(const AbsDistribution1D& otherBase) const
{
const Gamma1D& r = static_cast<const Gamma1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) && alpha_ == r.alpha_;
}
double Gamma1D::unscaledDensity(const double x) const
{
if (x > 0.0)
return norm_*pow(x, alpha_-1.0)*exp(-x);
else
return 0.0;
}
double Gamma1D::unscaledCdf(const double x) const
{
if (x > 0.0)
return incompleteGamma(alpha_, x);
else
return 0.0;
}
double Gamma1D::unscaledExceedance(const double x) const
{
if (x > 0.0)
return incompleteGammaC(alpha_, x);
else
return 1.0;
}
double Gamma1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Gamma1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
return inverseIncompleteGamma(alpha_, r1);
}
bool Gamma1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, alpha_);
return !os.fail();
}
Gamma1D* Gamma1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Gamma1D>());
current.ensureSameId(id);
double location, scale, a;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &a);
if (!in.fail())
return new Gamma1D(location, scale, a);
}
distributionReadError(in, classname());
return 0;
}
Gauss1D::Gauss1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale),
xmin_(inverseGaussCdf(0.0)), xmax_(inverseGaussCdf(1.0))
{
}
Gauss1D::Gauss1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale),
xmin_(inverseGaussCdf(0.0)), xmax_(inverseGaussCdf(1.0))
{
}
double Gauss1D::unscaledDensity(const double x) const
{
if (x < xmin_ || x > xmax_)
return 0.0;
else
return exp(-x*x/2.0)/SQR2PI;
}
unsigned Gauss1D::random(AbsRandomGenerator& g,
double* generatedRandom) const
{
return gauss_random(location(), scale(), g, generatedRandom);
}
bool Gauss1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
Gauss1D* Gauss1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Gauss1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new Gauss1D(location, scale);
}
double Gauss1D::unscaledCdf(const double x) const
{
if (x <= xmin_)
return 0.0;
if (x >= xmax_)
return 1.0;
if (x < 0.0)
return erfc(-x/SQRT2)/2.0;
else
return (1.0 + erf(x/SQRT2))/2.0;
}
double Gauss1D::unscaledExceedance(const double x) const
{
if (x <= xmin_)
return 1.0;
if (x >= xmax_)
return 0.0;
if (x > 0.0)
return erfc(x/SQRT2)/2.0;
else
return (1.0 - erf(x/SQRT2))/2.0;
}
double Gauss1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Gauss1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
return inverseGaussCdf(r1);
}
double Uniform1D::unscaledDensity(const double x) const
{
if (x >= 0.0 && x <= 1.0)
return 1.0;
else
return 0.0;
}
bool Uniform1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
Uniform1D* Uniform1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Uniform1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new Uniform1D(location, scale);
}
double Uniform1D::unscaledCdf(const double x) const
{
if (x <= 0.0)
return 0.0;
else if (x >= 1.0)
return 1.0;
else
return x;
}
double Uniform1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Uniform1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
return r1;
}
double IsoscelesTriangle1D::unscaledDensity(const double x) const
{
if (x > -1.0 && x < 1.0)
return 1.0 - fabs(x);
else
return 0.0;
}
bool IsoscelesTriangle1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
IsoscelesTriangle1D* IsoscelesTriangle1D::read(
const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(
gs::ClassId::makeId<IsoscelesTriangle1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new IsoscelesTriangle1D(location, scale);
}
double IsoscelesTriangle1D::unscaledCdf(const double x) const
{
if (x <= -1.0)
return 0.0;
else if (x >= 1.0)
return 1.0;
else if (x <= 0.0)
{
const double tmp = 1.0 + x;
return 0.5*tmp*tmp;
}
else
{
const double tmp = 1.0 - x;
return 1.0 - 0.5*tmp*tmp;
}
}
double IsoscelesTriangle1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::IsoscelesTriangle1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return -1.0;
else if (r1 == 1.0)
return 1.0;
else if (r1 <= 0.5)
return sqrt(2.0*r1) - 1.0;
else
return 1.0 - sqrt((1.0 - r1)*2.0);
}
bool Exponential1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
Exponential1D* Exponential1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Exponential1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new Exponential1D(location, scale);
}
double Exponential1D::unscaledDensity(const double x) const
{
if (x < 0.0)
return 0.0;
const double eval = exp(-x);
return eval < DBL_MIN ? 0.0 : eval;
}
double Exponential1D::unscaledCdf(const double x) const
{
return x > 0.0 ? 1.0 - exp(-x) : 0.0;
}
double Exponential1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Exponential1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 1.0)
return -log(DBL_MIN);
else
return -log(1.0 - r1);
}
double Exponential1D::unscaledExceedance(const double x) const
{
if (x < 0.0)
return 1.0;
const double eval = exp(-x);
return eval < DBL_MIN ? 0.0 : eval;
}
bool Logistic1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
Logistic1D* Logistic1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Logistic1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new Logistic1D(location, scale);
}
double Logistic1D::unscaledDensity(const double x) const
{
const double eval = exp(-x);
if (eval < DBL_MIN)
return 0.0;
else
{
const double tmp = 1.0 + eval;
return eval/tmp/tmp;
}
}
double Logistic1D::unscaledCdf(const double x) const
{
const double lmax = -log(DBL_MIN);
if (x <= -lmax)
return 0.0;
else if (x >= lmax)
return 1.0;
else
return 1.0/(1.0 + exp(-x));
}
double Logistic1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Logistic1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
const double lmax = -log(DBL_MIN);
if (r1 == 0.0)
return -lmax;
else if (r1 == 1.0)
return lmax;
else
return log(r1/(1.0 - r1));
}
double Logistic1D::unscaledExceedance(const double x) const
{
const double lmax = -log(DBL_MIN);
if (x >= lmax)
return 0.0;
else if (x <= -lmax)
return 1.0;
else
{
const double eval = exp(-x);
return eval/(1.0 + eval);
}
}
bool Quadratic1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, a_);
gs::write_pod(os, b_);
return !os.fail();
}
Quadratic1D* Quadratic1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Quadratic1D>());
current.ensureSameId(id);
double location, scale;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
double a, b;
gs::read_pod(in, &a);
gs::read_pod(in, &b);
if (!in.fail())
return new Quadratic1D(location, scale, a, b);
}
distributionReadError(in, classname());
return 0;
}
bool Quadratic1D::isEqual(const AbsDistribution1D& otherBase) const
{
const Quadratic1D& r = static_cast<const Quadratic1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
a_ == r.a_ && b_ == r.b_;
}
Quadratic1D::Quadratic1D(const double location, const double scale,
const double a, const double b)
: AbsScalableDistribution1D(location, scale), a_(a), b_(b)
{
verifyNonNegative();
}
Quadratic1D::Quadratic1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
a_(params[0]),
b_(params[1])
{
verifyNonNegative();
}
void Quadratic1D::verifyNonNegative()
{
- const double a = 2.0*a_;
- const double b = 2.0*b_;
+ const double a = a_;
+ const double b = b_;
if (b == 0.0)
{
if (fabs(a) > 1.0)
throw std::invalid_argument(
"In npstat::Quadratic1D::verifyNonNegative:"
" invalid distribution parameters");
}
else
{
double x1 = 0.0, x2 = 0.0;
const double sixb = 6*b;
if (solveQuadratic((2*a-sixb)/sixb, (1-a+b)/sixb, &x1, &x2))
{
if (!(fabs(x1 - 0.5) >= 0.5 && fabs(x2 - 0.5) >= 0.5))
throw std::invalid_argument(
"In npstat::Quadratic1D::verifyNonNegative:"
" invalid distribution parameters");
}
}
}
double Quadratic1D::unscaledDensity(const double x) const
{
if (x < 0.0 || x > 1.0)
return 0.0;
else
- return 1.0 + 2.0*(b_ - a_ + x*(2.0*a_ + 6.0*b_*(x - 1.0)));
+ return 1.0 + b_ - a_ + x*(2.0*a_ + 6.0*b_*(x - 1.0));
}
double Quadratic1D::unscaledCdf(const double x) const
{
if (x <= 0.0)
return 0.0;
else if (x >= 1.0)
return 1.0;
else
- return x*(1.0 + 2.0*(b_ - a_ + x*(a_ - 3.0*b_ + 2.0*b_*x)));
+ return x*(1.0 + b_ - a_ + x*(a_ - 3.0*b_ + 2.0*b_*x));
}
double Quadratic1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Quadratic1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return 0.0;
else if (r1 == 1.0)
return 1.0;
else
{
- const double a = 2.0*a_;
- const double b = 2.0*b_;
+ const double a = a_;
+ const double b = b_;
if (b == 0.0)
{
if (a == 0.0)
return r1;
else
{
double x0 = 0.0, x1 = 0.0;
const unsigned n = solveQuadratic(
(1.0 - a)/a, -r1/a, &x0, &x1);
if (!n) throw std::runtime_error(
"In npstat::Quadratic1D::unscaledQuantile: "
"no solutions");
if (fabs(x0 - 0.5) < fabs(x1 - 0.5))
return x0;
else
return x1;
}
}
else
{
const double twob = 2*b;
double x[3] = {0.0};
const unsigned n = solveCubic(
(a - 3*b)/twob, (1 - a + b)/twob, -r1/twob, x);
if (n == 1U)
return x[0];
else
{
unsigned ibest = 0;
double dbest = fabs(x[0] - 0.5);
for (unsigned i=1; i<n; ++i)
if (fabs(x[i] - 0.5) < dbest)
{
ibest = i;
dbest = fabs(x[i] - 0.5);
}
return x[ibest];
}
}
}
}
bool LogQuadratic1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, a_);
gs::write_pod(os, b_);
return !os.fail();
}
LogQuadratic1D* LogQuadratic1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<LogQuadratic1D>());
current.ensureSameId(id);
double location, scale, a, b;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &a);
gs::read_pod(in, &b);
if (!in.fail())
return new LogQuadratic1D(location, scale, a, b);
}
distributionReadError(in, classname());
return 0;
}
bool LogQuadratic1D::isEqual(const AbsDistribution1D& otherBase) const
{
const LogQuadratic1D& r = static_cast<const LogQuadratic1D&>(
otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
a_ == r.a_ && b_ == r.b_;
}
LogQuadratic1D::LogQuadratic1D(const double location, const double scale,
const double a, const double b)
: AbsScalableDistribution1D(location, scale), a_(a), b_(b)
{
normalize();
}
LogQuadratic1D::LogQuadratic1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
a_(params[0]),
b_(params[1])
{
normalize();
}
inline long double LogQuadratic1D::quadInteg(const long double x) const
{
return dawsonIntegral(x)*expl(x*x);
}
void LogQuadratic1D::normalize()
{
ref_ = 0.0L;
range_ = 1.0L;
k_ = 0.0;
s_ = 0.0;
norm_ = 1.0;
- const double b = 2.0*b_;
- const double a = 2.0*a_;
+ const double b = b_;
+ const double a = a_;
if (b > DBL_EPSILON)
{
k_ = sqrt(6.0*b);
s_ = 0.5 - a/(6.0*b);
ref_ = quadInteg(k_*s_);
range_ = ref_ - quadInteg(k_*(s_ - 1.0));
norm_ = k_/range_;
}
else if (b < -DBL_EPSILON)
{
k_ = sqrt(-6.0*b);
s_ = 0.5 - a/(6.0*b);
ref_ = erfl(k_*s_);
range_ = ref_ - erfl(k_*(s_ - 1.0));
norm_ = 2.0*k_/SQRPI/range_;
}
else if (fabs(a) > DBL_EPSILON)
{
range_ = expl(2.0L*a) - 1.0L;
if (fabs(a) > 1.e-10)
norm_ = a/sinh(a);
}
}
double LogQuadratic1D::unscaledDensity(const double x) const
{
if (x < 0.0 || x > 1.0)
return 0.0;
- const double b = 2.0*b_;
+ const double b = b_;
if (fabs(b) > DBL_EPSILON)
{
const double delta = x - s_;
return norm_*exp(6.0*b*delta*delta);
}
- const double a = 2.0*a_;
+ const double a = a_;
if (fabs(a) > DBL_EPSILON)
return norm_*exp((2.0*x - 1.0)*a);
else
return 1.0;
}
double LogQuadratic1D::unscaledCdf(const double x) const
{
if (x <= 0.0)
return 0.0;
else if (x >= 1.0)
return 1.0;
else
{
- const double b = 2.0*b_;
- const double a = 2.0*a_;
+ const double b = b_;
+ const double a = a_;
if (b > DBL_EPSILON)
return (ref_ - quadInteg(k_*(s_ - x)))/range_;
else if (b < -DBL_EPSILON)
return (ref_ - erfl(k_*(s_ - x)))/range_;
else if (fabs(a) > DBL_EPSILON)
return (expl(2.0L*a*x) - 1.0L)/range_;
else
return x;
}
}
double LogQuadratic1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::LogQuadratic1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return 0.0;
else if (r1 == 1.0)
return 1.0;
else
{
- const double b = 2.0*b_;
- const double a = 2.0*a_;
+ const double b = b_;
+ const double a = a_;
double q = 0.0;
if (b > DBL_EPSILON)
q = s_ - inverseExpsqIntegral(ref_ - r1*range_)/k_;
else if (b < -DBL_EPSILON)
q = s_ - inverseErf(ref_ - r1*range_)/k_;
else if (fabs(a) > DBL_EPSILON)
q = logl(r1*range_ + 1.0L)/2.0/a;
else
q = r1;
if (q < 0.0)
q = 0.0;
else if (q > 1.0)
q = 1.0;
return q;
}
}
bool TruncatedGauss1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, nsigma_);
return !os.fail();
}
TruncatedGauss1D* TruncatedGauss1D::read(
const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(
gs::ClassId::makeId<TruncatedGauss1D>());
current.ensureSameId(id);
double location, scale, nsig;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &nsig);
if (!in.fail())
return new TruncatedGauss1D(location, scale, nsig);
}
distributionReadError(in, classname());
return 0;
}
bool TruncatedGauss1D::isEqual(const AbsDistribution1D& otherBase) const
{
const TruncatedGauss1D& r =
static_cast<const TruncatedGauss1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) && nsigma_ == r.nsigma_;
}
void TruncatedGauss1D::initialize()
{
if (nsigma_ <= 0.0) throw std::invalid_argument(
"In npstat::TruncatedGauss1D::initialize: "
"invalid truncation parameter");
const double maxSig = inverseGaussCdf(1.0);
if (nsigma_ >= maxSig)
{
nsigma_ = maxSig;
cdf0_ = 0.0;
norm_ = 1.0;
}
else
{
cdf0_ = erfc(nsigma_/SQRT2)/2.0;
const double u = (1.0 + erf(nsigma_/SQRT2))/2.0;
norm_ = 1.0/(u - cdf0_);
}
}
TruncatedGauss1D::TruncatedGauss1D(const double location,
const double scale,
const double i_nsigma)
: AbsScalableDistribution1D(location, scale),
nsigma_(i_nsigma)
{
initialize();
}
TruncatedGauss1D::TruncatedGauss1D(const double location,
const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
nsigma_(params[0])
{
initialize();
}
double TruncatedGauss1D::unscaledDensity(const double x) const
{
if (fabs(x) > nsigma_)
return 0.0;
else
return norm_*exp(-x*x/2.0)/SQR2PI;
}
unsigned TruncatedGauss1D::random(AbsRandomGenerator& g,
double* generatedRandom) const
{
const double m = location();
const double s = scale();
unsigned cnt = gauss_random(m, s, g, generatedRandom);
while (fabs(*generatedRandom - m) > nsigma_*s)
cnt += gauss_random(m, s, g, generatedRandom);
return cnt;
}
double TruncatedGauss1D::unscaledCdf(const double x) const
{
if (x <= -nsigma_)
return 0.0;
else if (x >= nsigma_)
return 1.0;
else if (x < 0.0)
return (erfc(-x/SQRT2)/2.0 - cdf0_)*norm_;
else
return ((1.0 + erf(x/SQRT2))/2.0 - cdf0_)*norm_;
}
double TruncatedGauss1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::TruncatedGauss1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return -nsigma_;
else if (r1 == 1.0)
return nsigma_;
else
return inverseGaussCdf(r1/norm_ + cdf0_);
}
bool MirroredGauss1D::isEqual(const AbsDistribution1D& otherBase) const
{
const MirroredGauss1D& r =
static_cast<const MirroredGauss1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
mu0_ == r.mu0_ && sigma0_ == r.sigma0_;
}
MirroredGauss1D::MirroredGauss1D(const double location, const double scale,
const double mean, double const sigma)
: AbsScalableDistribution1D(location, scale),
mu0_(mean),
sigma0_(sigma)
{
validate();
}
MirroredGauss1D::MirroredGauss1D(const double location,
const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
mu0_(params[0]),
sigma0_(params[1])
{
validate();
}
bool MirroredGauss1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, mu0_);
gs::write_pod(os, sigma0_);
return !os.fail();
}
MirroredGauss1D* MirroredGauss1D::read(
const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(
gs::ClassId::makeId<MirroredGauss1D>());
current.ensureSameId(id);
double location, scale, mu, sig;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &mu);
gs::read_pod(in, &sig);
if (!in.fail())
return new MirroredGauss1D(location, scale, mu, sig);
}
distributionReadError(in, classname());
return 0;
}
double MirroredGauss1D::unscaledDensity(const double x) const
{
if (x < 0.0 || x > 1.0)
return 0.0;
Gauss1D g(x, sigma0_);
long double acc = g.density(mu0_)*1.0L + g.density(-mu0_);
for (unsigned k=1; ; ++k)
{
const long double old = acc;
acc += g.density(2.0*k + mu0_);
acc += g.density(2.0*k - mu0_);
acc += g.density(-2.0*k + mu0_);
acc += g.density(-2.0*k - mu0_);
if (old == acc)
break;
}
return acc;
}
long double MirroredGauss1D::ldCdf(const double x) const
{
if (x <= 0.0)
return 0.0L;
else if (x >= 1.0)
return 1.0L;
else
{
long double acc = 0.0L;
{
Gauss1D g(mu0_, sigma0_);
acc += (g.cdf(x) - g.cdf(0.0));
}
{
Gauss1D g(-mu0_, sigma0_);
acc += (g.cdf(x) - g.cdf(0.0));
}
for (unsigned k=1; ; ++k)
{
const long double old = acc;
{
Gauss1D g(2.0*k + mu0_, sigma0_);
acc += (g.cdf(x) - g.cdf(0.0));
}
{
Gauss1D g(2.0*k - mu0_, sigma0_);
acc += (g.cdf(x) - g.cdf(0.0));
}
{
Gauss1D g(-2.0*k + mu0_, sigma0_);
acc -= (g.exceedance(x) - g.exceedance(0.0));
}
{
Gauss1D g(-2.0*k - mu0_, sigma0_);
acc -= (g.exceedance(x) - g.exceedance(0.0));
}
if (old == acc)
break;
}
return acc;
}
}
double MirroredGauss1D::unscaledCdf(const double x) const
{
return ldCdf(x);
}
double MirroredGauss1D::unscaledExceedance(const double x) const
{
return 1.0L - ldCdf(x);
}
double MirroredGauss1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::MirroredGauss1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return 0.0;
else if (r1 == 1.0)
return 1.0;
else
{
const long double ldr1 = r1;
double xmin = 0.0;
double xmax = 1.0;
for (unsigned i=0; i<1000; ++i)
{
if ((xmax - xmin)/xmax <= 2.0*DBL_EPSILON)
break;
const double xtry = (xmin + xmax)/2.0;
const long double ld = ldCdf(xtry);
if (ld == ldr1)
return xtry;
else if (ld > ldr1)
xmax = xtry;
else
xmin = xtry;
}
return (xmin + xmax)/2.0;
}
}
void MirroredGauss1D::validate()
{
if (mu0_ < 0.0 || mu0_ > 1.0) throw std::invalid_argument(
"In MirroredGauss1D::validate: interval mean must be within [0, 1]");
if (sigma0_ <= 0.0) throw std::invalid_argument(
"In MirroredGauss1D::validate: interval sigma must be positive");
}
BifurcatedGauss1D::BifurcatedGauss1D(
const double location, const double scale,
const double i_leftSigmaFraction,
const double i_nSigmasLeft, const double i_nSigmasRight)
: AbsScalableDistribution1D(location, scale),
leftSigma_(i_leftSigmaFraction*2.0),
rightSigma_(2.0 - leftSigma_),
nSigmasLeft_(i_nSigmasLeft),
nSigmasRight_(i_nSigmasRight)
{
initialize();
}
BifurcatedGauss1D::BifurcatedGauss1D(const double location,
const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
leftSigma_(params[0]*2.0),
rightSigma_(2.0 - leftSigma_),
nSigmasLeft_(params[1]),
nSigmasRight_(params[2])
{
initialize();
}
void BifurcatedGauss1D::initialize()
{
if (leftSigma_ < 0.0 || rightSigma_ < 0.0)
throw std::invalid_argument(
"In npstat::BifurcatedGauss1D::initialize: "
"invalid left sigma fraction");
if (nSigmasLeft_ < 0.0) throw std::invalid_argument(
"In npstat::BifurcatedGauss1D::initialize: "
"invalid left truncation parameter");
if (nSigmasRight_ < 0.0) throw std::invalid_argument(
"In npstat::BifurcatedGauss1D::initialize: "
"invalid right truncation parameter");
if (nSigmasLeft_ + nSigmasRight_ == 0.0) throw std::invalid_argument(
"In npstat::BifurcatedGauss1D::initialize: "
"both truncation parameters can not be 0");
const double maxNSigma = inverseGaussCdf(1.0);
if (nSigmasRight_ > maxNSigma)
nSigmasRight_ = maxNSigma;
if (nSigmasLeft_ > maxNSigma)
nSigmasLeft_ = maxNSigma;
cdf0Left_ = erfc(nSigmasLeft_/SQRT2)/2.0;
cdf0Right_ = (1.0 + erf(nSigmasRight_/SQRT2))/2.0;
assert(cdf0Right_ > cdf0Left_);
const double leftArea = (0.5 - cdf0Left_)*leftSigma_;
const double rightArea = (cdf0Right_ - 0.5)*rightSigma_;
norm_ = 1.0/(leftArea + rightArea);
leftCdfFrac_ = leftArea/(leftArea + rightArea);
}
double BifurcatedGauss1D::unscaledDensity(const double x) const
{
if (x == 0.0)
return norm_/SQR2PI;
else if (x > 0.0)
{
if (x > rightSigma_*nSigmasRight_)
return 0.0;
else
{
const double dx = x/rightSigma_;
return norm_*exp(-dx*dx/2.0)/SQR2PI;
}
}
else
{
if (x < -leftSigma_*nSigmasLeft_)
return 0.0;
else
{
const double dx = x/leftSigma_;
return norm_*exp(-dx*dx/2.0)/SQR2PI;
}
}
}
double BifurcatedGauss1D::unscaledCdf(const double x) const
{
if (x == 0.0)
return leftCdfFrac_;
else if (x > 0.0)
{
if (x > rightSigma_*nSigmasRight_)
return 1.0;
else
{
const double dx = x/rightSigma_;
const double cdfDelta = (1.0 + erf(dx/SQRT2))/2.0 - cdf0Right_;
return 1.0 + cdfDelta*(1.0 - leftCdfFrac_)/(cdf0Right_ - 0.5);
}
}
else
{
if (x < -leftSigma_*nSigmasLeft_)
return 0.0;
else
{
const double dx = x/leftSigma_;
const double cdfDelta = erfc(-dx/SQRT2)/2.0 - cdf0Left_;
return cdfDelta*leftCdfFrac_/(0.5 - cdf0Left_);
}
}
}
double BifurcatedGauss1D::unscaledExceedance(const double x) const
{
return 1.0 - unscaledCdf(x);
}
double BifurcatedGauss1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::BifurcatedGauss1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return -nSigmasLeft_*leftSigma_;
else if (r1 == 1.0)
return nSigmasRight_*rightSigma_;
else
{
if (r1 == leftCdfFrac_)
return 0.0;
else if (r1 < leftCdfFrac_)
{
// Map 0 into cdf0Left_ and leftCdfFrac_ into 0.5
const double arg = r1/leftCdfFrac_*(0.5-cdf0Left_) + cdf0Left_;
return leftSigma_*inverseGaussCdf(arg);
}
else
{
// Map leftCdfFrac_ into 0.5 and 1.0 into cdf0Right_
const double d = (r1 - leftCdfFrac_)/(1.0 - leftCdfFrac_);
const double arg = 0.5 + d*(cdf0Right_ - 0.5);
return rightSigma_*inverseGaussCdf(arg);
}
}
}
bool BifurcatedGauss1D::isEqual(const AbsDistribution1D& otherBase) const
{
const BifurcatedGauss1D& r =
static_cast<const BifurcatedGauss1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
leftSigma_ == r.leftSigma_ &&
rightSigma_ == r.rightSigma_ &&
nSigmasLeft_ == r.nSigmasLeft_ &&
nSigmasRight_ == r.nSigmasRight_ &&
norm_ == r.norm_ &&
leftCdfFrac_ == r.leftCdfFrac_ &&
cdf0Left_ == r.cdf0Left_ &&
cdf0Right_ == r.cdf0Right_;
}
bool BifurcatedGauss1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, leftSigma_);
gs::write_pod(os, rightSigma_);
gs::write_pod(os, nSigmasLeft_);
gs::write_pod(os, nSigmasRight_);
gs::write_pod(os, norm_);
gs::write_pod(os, leftCdfFrac_);
gs::write_pod(os, cdf0Left_);
gs::write_pod(os, cdf0Right_);
return !os.fail();
}
BifurcatedGauss1D::BifurcatedGauss1D(const double location,
const double scale)
: AbsScalableDistribution1D(location, scale)
{
}
BifurcatedGauss1D* BifurcatedGauss1D::read(
const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(
gs::ClassId::makeId<BifurcatedGauss1D>());
current.ensureSameId(id);
double location, scale;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
BifurcatedGauss1D* ptr = new BifurcatedGauss1D(location, scale);
gs::read_pod(in, &ptr->leftSigma_);
gs::read_pod(in, &ptr->rightSigma_);
gs::read_pod(in, &ptr->nSigmasLeft_);
gs::read_pod(in, &ptr->nSigmasRight_);
gs::read_pod(in, &ptr->norm_);
gs::read_pod(in, &ptr->leftCdfFrac_);
gs::read_pod(in, &ptr->cdf0Left_);
gs::read_pod(in, &ptr->cdf0Right_);
if (!in.fail() &&
ptr->leftSigma_ >= 0.0 &&
ptr->rightSigma_ >= 0.0 &&
ptr->leftSigma_ + ptr->rightSigma_ > 0.0 &&
ptr->nSigmasLeft_ >= 0.0 &&
ptr->nSigmasRight_ >= 0.0 &&
ptr->nSigmasLeft_ + ptr->nSigmasRight_ > 0.0 &&
ptr->norm_ > 0.0 &&
ptr->leftCdfFrac_ >= 0.0 &&
ptr->cdf0Left_ >= 0.0 &&
ptr->cdf0Right_ > ptr->cdf0Left_)
return ptr;
else
delete ptr;
}
distributionReadError(in, classname());
return 0;
}
Cauchy1D::Cauchy1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale),
support_(sqrt(DBL_MAX/M_PI))
{
}
Cauchy1D::Cauchy1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale),
support_(sqrt(DBL_MAX/M_PI))
{
}
bool Cauchy1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
Cauchy1D* Cauchy1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Cauchy1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new Cauchy1D(location, scale);
}
double Cauchy1D::unscaledDensity(const double x) const
{
if (fabs(x) < support_)
return 1.0/M_PI/(1.0 + x*x);
else
return 0.0;
}
double Cauchy1D::unscaledCdf(const double x) const
{
if (x < -support_)
return 0.0;
else if (x > support_)
return 1.0;
else
return atan(x)/M_PI + 0.5;
}
double Cauchy1D::unscaledQuantile(const double x) const
{
if (!(x >= 0.0 && x <= 1.0)) throw std::domain_error(
"In npstat::Cauchy1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (x == 0.0)
return -support_;
else if (x == 1.0)
return support_;
else
return tan(M_PI*(x - 0.5));
}
bool LogNormal::isEqual(const AbsDistribution1D& otherBase) const
{
const LogNormal& r = static_cast<const LogNormal&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
skew_ == r.skew_;
}
bool LogNormal::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, skew_);
return !os.fail();
}
LogNormal* LogNormal::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<LogNormal>());
current.ensureSameId(id);
double location, scale, skew;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &skew);
if (!in.fail())
return new LogNormal(location, scale, skew);
}
distributionReadError(in, classname());
return 0;
}
void LogNormal::initialize()
{
logw_ = 0.0;
s_ = 0.0;
xi_ = 0.0;
emgamovd_ = 0.0;
if (skew_)
{
const double b1 = skew_*skew_;
const double tmp = pow((2.0+b1+sqrt(b1*(4.0+b1)))/2.0, 1.0/3.0);
const double w = tmp + 1.0/tmp - 1.0;
logw_ = log(w);
if (logw_ > 0.0)
{
s_ = sqrt(logw_);
emgamovd_ = 1.0/sqrt(w*(w-1.0));
xi_ = -emgamovd_*sqrt(w);
}
else
{
// This is not different from a Gaussian within
// the numerical precision of our calculations
logw_ = 0.0;
skew_ = 0.0;
}
}
}
LogNormal::LogNormal(const double mean, const double stdev,
const double skewness)
: AbsScalableDistribution1D(mean, stdev),
skew_(skewness)
{
initialize();
}
LogNormal::LogNormal(const double mean, const double stdev,
const std::vector<double>& params)
: AbsScalableDistribution1D(mean, stdev),
skew_(params[0])
{
initialize();
}
double LogNormal::unscaledDensity(const double x) const
{
if (skew_)
{
const double diff = skew_ > 0.0 ? x - xi_ : -x - xi_;
if (diff <= 0.0)
return 0.0;
else
{
const double lg = log(diff/emgamovd_);
return exp(-lg*lg/2.0/logw_)/s_/SQR2PI/diff;
}
}
else
{
// This is a Gaussian
return exp(-x*x/2.0)/SQR2PI;
}
}
double LogNormal::unscaledCdf(const double x) const
{
if (skew_)
{
const double diff = skew_ > 0.0 ? x - xi_ : -x - xi_;
double posCdf = 0.0;
if (diff > 0.0)
posCdf = (1.0 + erf(log(diff/emgamovd_)/s_/SQRT2))/2.0;
return skew_ > 0.0 ? posCdf : 1.0 - posCdf;
}
else
return (1.0 + erf(x/SQRT2))/2.0;
}
double LogNormal::unscaledExceedance(const double x) const
{
return 1.0 - unscaledCdf(x);
}
double LogNormal::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::LogNormal::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
const double g = inverseGaussCdf(skew_ >= 0.0 ? r1 : 1.0 - r1);
if (skew_)
{
const double v = emgamovd_*exp(s_*g) + xi_;
return skew_ > 0.0 ? v : -v;
}
else
return g;
}
Moyal1D::Moyal1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale),
xmax_(-2.0*log(DBL_MIN*SQR2PI)),
xmin_(-log(xmax_))
{
}
Moyal1D::Moyal1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale),
xmax_(-2.0*log(DBL_MIN*SQR2PI)),
xmin_(-log(xmax_))
{
}
double Moyal1D::unscaledDensity(const double x) const
{
if (x <= xmin_ || x >= xmax_)
return 0.0;
else
return exp(-0.5*(x + exp(-x)))/SQR2PI;
}
double Moyal1D::unscaledCdf(const double x) const
{
if (x <= xmin_)
return 0.0;
else if (x >= xmax_)
return 1.0;
else
return incompleteGammaC(0.5, 0.5*exp(-x));
}
double Moyal1D::unscaledExceedance(const double x) const
{
if (x <= xmin_)
return 1.0;
else if (x >= xmax_)
return 0.0;
else
return incompleteGamma(0.5, 0.5*exp(-x));
}
double Moyal1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Moyal1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return xmin_;
else if (r1 == 1.0)
return xmax_;
else
{
const double d = inverseIncompleteGammaC(0.5, r1);
return -log(2.0*d);
}
}
bool Moyal1D::write(std::ostream& os) const
{
return AbsScalableDistribution1D::write(os);
}
Moyal1D* Moyal1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Moyal1D>());
current.ensureSameId(id);
double location, scale;
if (!AbsScalableDistribution1D::read(in, &location, &scale))
{
distributionReadError(in, classname());
return 0;
}
return new Moyal1D(location, scale);
}
bool Pareto1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, c_);
return !os.fail();
}
Pareto1D* Pareto1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Pareto1D>());
current.ensureSameId(id);
double location, scale, c;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &c);
if (!in.fail())
return new Pareto1D(location, scale, c);
}
distributionReadError(in, classname());
return 0;
}
bool Pareto1D::isEqual(const AbsDistribution1D& otherBase) const
{
const Pareto1D& r = static_cast<const Pareto1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
c_ == r.c_;
}
void Pareto1D::initialize()
{
if (c_ <= 0.0) throw std::invalid_argument(
"In npstat::Pareto1D::initialize: power parameter must be positive");
if (c_ > 1.0)
support_ = pow(1.0/DBL_MIN, 1.0/c_);
else
support_ = 1.0/DBL_MIN;
}
Pareto1D::Pareto1D(const double location, const double scale,
const double powerParam)
: AbsScalableDistribution1D(location, scale),
c_(powerParam)
{
initialize();
}
Pareto1D::Pareto1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
c_(params[0])
{
initialize();
}
double Pareto1D::unscaledDensity(const double x) const
{
if (x < 1.0 || x > support_)
return 0.0;
else
return c_/pow(x, c_ + 1.0);
}
double Pareto1D::unscaledCdf(const double x) const
{
if (x <= 1.0)
return 0.0;
else if (x >= support_)
return 1.0;
else
return 1.0 - 1.0/pow(x, c_);
}
double Pareto1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Pareto1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return 1.0;
else if (r1 == 1.0)
return support_;
else
return pow(1.0 - r1, -1.0/c_);
}
double Pareto1D::unscaledExceedance(const double x) const
{
if (x <= 1.0)
return 1.0;
else if (x >= support_)
return 0.0;
else
return 1.0/pow(x, c_);
}
bool UniPareto1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, c_);
return !os.fail();
}
UniPareto1D* UniPareto1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<UniPareto1D>());
current.ensureSameId(id);
double location, scale, c;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &c);
if (!in.fail())
return new UniPareto1D(location, scale, c);
}
distributionReadError(in, classname());
return 0;
}
bool UniPareto1D::isEqual(const AbsDistribution1D& otherBase) const
{
const UniPareto1D& r = static_cast<const UniPareto1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
c_ == r.c_;
}
void UniPareto1D::initialize()
{
if (c_ <= 0.0) throw std::invalid_argument(
"In npstat::UniPareto1D::initialize: power parameter must be positive");
if (c_ > 1.0)
support_ = pow(1.0/DBL_MIN, 1.0/c_);
else
support_ = 1.0/DBL_MIN;
amplitude_ = c_/(c_ + 1.0);
}
UniPareto1D::UniPareto1D(const double location, const double scale,
const double powerParam)
: AbsScalableDistribution1D(location, scale),
c_(powerParam)
{
initialize();
}
UniPareto1D::UniPareto1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
c_(params[0])
{
initialize();
}
double UniPareto1D::unscaledDensity(const double x) const
{
if (x < 0.0 || x > support_)
return 0.0;
else if (x <= 1.0)
return amplitude_;
else
return amplitude_/pow(x, c_ + 1.0);
}
double UniPareto1D::unscaledCdf(const double x) const
{
if (x <= 0.0)
return 0.0;
else if (x >= support_)
return 1.0;
else if (x <= 1.0)
return x*amplitude_;
else
return amplitude_ + (1.0 - amplitude_)*(1.0 - 1.0/pow(x, c_));
}
double UniPareto1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::UniPareto1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 <= amplitude_)
return r1/amplitude_;
else if (r1 == 1.0)
return support_;
else
return pow(1.0 - (r1 - amplitude_)/(1.0 - amplitude_), -1.0/c_);
}
double UniPareto1D::unscaledExceedance(const double x) const
{
if (x > 1.0)
return (1.0 - amplitude_)/pow(x, c_);
else
return 1.0 - unscaledCdf(x);
}
bool Huber1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, tailWeight_);
return !os.fail();
}
Huber1D* Huber1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Huber1D>());
current.ensureSameId(id);
double location, scale, tailWeight;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
gs::read_pod(in, &tailWeight);
if (!in.fail())
return new Huber1D(location, scale, tailWeight);
}
distributionReadError(in, classname());
return 0;
}
bool Huber1D::isEqual(const AbsDistribution1D& otherBase) const
{
const Huber1D& r = static_cast<const Huber1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
tailWeight_ == r.tailWeight_;
}
void Huber1D::initialize()
{
if (!(tailWeight_ >= 0.0 && tailWeight_ < 1.0))
throw std::invalid_argument(
"In npstat::Huber1D::initialize: "
"tail weight not inside [0, 1) interval");
if (tailWeight_ == 0.0)
{
// Pure Gaussian
a_ = DBL_MAX;
normfactor_ = 1.0/sqrt(2.0*M_PI);
support_ = inverseGaussCdf(1.0);
cdf0_ = 0.0;
}
else
{
// Solve the equation for "a" by bisection
const double eps = 2.0*DBL_EPSILON;
double c = -2.0*log(tailWeight_);
assert(c > 0.0);
assert(weight(c) <= tailWeight_);
double b = 0.0;
while ((c - b)/(c + b) > eps)
{
const double half = (c + b)/2.0;
if (weight(half) >= tailWeight_)
b = half;
else
c = half;
}
a_ = (c + b)/2.0;
normfactor_ = 0.5/(exp(-a_*a_/2.0)/a_ +
sqrt(M_PI/2.0)*erf(a_/SQRT2));
support_ = a_/2.0 - log(DBL_MIN)/a_;
cdf0_ = (1.0 + erf(-a_/SQRT2))/2.0;
}
}
Huber1D::Huber1D(const double location, const double scale,
const double tailWeight)
: AbsScalableDistribution1D(location, scale),
tailWeight_(tailWeight)
{
initialize();
}
Huber1D::Huber1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
tailWeight_(params[0])
{
initialize();
}
double Huber1D::unscaledDensity(const double x) const
{
const double absx = fabs(x);
if (absx <= a_)
return normfactor_*exp(-x*x/2.0);
else
return normfactor_*exp(a_*(a_/2.0 - absx));
}
double Huber1D::unscaledCdf(const double x) const
{
if (tailWeight_ == 0.0)
return (1.0 + erf(x/SQRT2))/2.0;
if (x < -a_)
return normfactor_*exp((a_*(a_ + 2*x))/2.0)/a_;
else if (x <= a_)
{
static const double sq1 = sqrt(M_PI/2.0);
static const double sq2 = sqrt(2.0);
return normfactor_*sq1*(erf(a_/sq2) + erf(x/sq2)) + tailWeight_/2;
}
else
return 1.0 - normfactor_*exp((a_*(a_ - 2*x))/2.0)/a_;
}
double Huber1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Huber1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (tailWeight_ == 0.0)
return inverseGaussCdf(r1);
if (r1 == 0.0)
return -support_;
else if (r1 == 1.0)
return support_;
else if (r1 <= tailWeight_/2.0)
return log(r1*a_/normfactor_)/a_ - 0.5*a_;
else if (r1 < 1.0 - tailWeight_/2.0)
{
const double t = (r1 - tailWeight_/2.0)/normfactor_/SQR2PI + cdf0_;
return inverseGaussCdf(t);
}
else
return 0.5*a_ - log((1.0 - r1)*a_/normfactor_)/a_;
}
double Huber1D::weight(const double a) const
{
static const double sq1 = sqrt(M_PI/2.0);
return 1.0/(1.0 + a*exp(a*a/2.0)*sq1*erf(a/SQRT2));
}
bool Tabulated1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, deg_);
gs::write_pod_vector(os, table_);
return !os.fail();
}
Tabulated1D* Tabulated1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<Tabulated1D>());
current.ensureSameId(id);
double location, scale;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
unsigned deg = 0;
gs::read_pod(in, &deg);
std::vector<double> table;
gs::read_pod_vector(in, &table);
if (!in.fail() && table.size())
return new Tabulated1D(location, scale,
&table[0], table.size(), deg);
}
distributionReadError(in, classname());
return 0;
}
bool Tabulated1D::isEqual(const AbsDistribution1D& otherBase) const
{
const Tabulated1D& r = static_cast<const Tabulated1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
table_ == r.table_ && deg_ == r.deg_;
}
Tabulated1D::Tabulated1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale)
{
const unsigned npara = params.size();
if (npara)
initialize(&params[0], npara, std::min(3U, npara-1U));
else
initialize(static_cast<double*>(0), 0U, 0U);
}
void Tabulated1D::normalize()
{
cdf_.clear();
cdf_.reserve(len_);
cdf_.push_back(0.0);
long double sum = 0.0L;
for (unsigned i=0; i<len_-1; ++i)
{
sum += intervalInteg(i);
cdf_.push_back(static_cast<double>(sum));
}
double norm = cdf_[len_ - 1];
assert(norm > 0.0);
for (unsigned i=0; i<len_; ++i)
{
table_[i] /= norm;
cdf_[i] /= norm;
}
exceed_.resize(len_);
exceed_[len_ - 1U] = 0.0;
sum = 0.0L;
for (unsigned i=len_-1; i>0; --i)
{
sum += intervalInteg(i-1);
exceed_[i-1] = static_cast<double>(sum);
}
norm = exceed_[0];
for (unsigned i=0; i<len_; ++i)
exceed_[i] /= norm;
}
double Tabulated1D::intervalInteg(const unsigned i) const
{
// The formula used here is exact for cubic polynomials
static const double legendreRootOver2 = 0.5/sqrt(3.0);
const double x0 = step_*(i + 0.5);
const double v0 = unscaledDensity(x0 - legendreRootOver2*step_);
const double v1 = unscaledDensity(x0 + legendreRootOver2*step_);
return step_*(v0 + v1)/2.0;
}
double Tabulated1D::interpolate(const double x) const
{
if (x < 0.0 || x > 1.0)
return 0.0;
if (x == 0.0)
return table_[0];
if (x == 1.0)
return table_[len_ - 1];
unsigned idx = static_cast<unsigned>(x/step_);
if (idx >= len_ - 1)
idx = len_ - 2;
const double dx = x/step_ - idx;
switch (deg_)
{
case 0:
if (dx < 0.5)
return table_[idx];
else
return table_[idx + 1];
case 1:
return interpolate_linear(dx, table_[idx], table_[idx + 1]);
case 2:
if (idx == 0)
return interpolate_quadratic(dx, table_[idx], table_[idx + 1],
table_[idx + 2]);
else if (idx == len_ - 2)
return interpolate_quadratic(dx+1.0, table_[idx - 1],
table_[idx], table_[idx + 1]);
else
{
const double v0 = interpolate_quadratic(
dx, table_[idx], table_[idx + 1], table_[idx + 2]);
const double v1 = interpolate_quadratic(
dx+1.0, table_[idx - 1], table_[idx], table_[idx + 1]);
return (v0 + v1)/2.0;
}
case 3:
if (idx == 0)
return interpolate_cubic(dx, table_[idx], table_[idx + 1],
table_[idx + 2], table_[idx + 3]);
else if (idx == len_ - 2)
return interpolate_cubic(dx+2.0, table_[idx-2], table_[idx-1],
table_[idx], table_[idx + 1]);
else
return interpolate_cubic(dx+1.0, table_[idx - 1], table_[idx],
table_[idx + 1], table_[idx + 2]);
default:
assert(0);
return 0.0;
}
}
double Tabulated1D::unscaledDensity(const double x) const
{
const double v = this->interpolate(x);
if (v >= 0.0)
return v;
else
return 0.0;
}
double Tabulated1D::unscaledCdf(double x) const
{
if (x <= 0.0)
return 0.0;
if (x >= 1.0)
return 1.0;
unsigned idx = static_cast<unsigned>(x/step_);
if (idx >= len_ - 1)
idx = len_ - 2;
double v;
switch (deg_)
{
case 0:
{
const double dx = x/step_ - idx;
if (dx < 0.5)
v = table_[idx]*dx*step_;
else
v = (table_[idx]*0.5 + table_[idx + 1]*(dx - 0.5))*step_;
}
break;
default:
v = interpIntegral(step_*idx, x);
}
return cdf_[idx] + v;
}
double Tabulated1D::unscaledExceedance(double x) const
{
if (x <= 0.0)
return 1.0;
if (x >= 1.0)
return 0.0;
unsigned idx = static_cast<unsigned>(x/step_);
if (idx >= len_ - 1)
idx = len_ - 2;
double v;
switch (deg_)
{
case 0:
{
const double dx = x/step_ - idx;
if (dx < 0.5)
v = table_[idx]*dx*step_;
else
v = (table_[idx]*0.5 + table_[idx + 1]*(dx - 0.5))*step_;
}
break;
default:
v = interpIntegral(step_*idx, x);
}
return exceed_[idx] - v;
}
double Tabulated1D::interpIntegral(const double a, const double b) const
{
static const double legendreRootOver2 = 0.5/sqrt(3.0);
const double x0 = (b + a)/2.0;
const double step = b - a;
const double v0 = unscaledDensity(x0 - legendreRootOver2*step);
const double v1 = unscaledDensity(x0 + legendreRootOver2*step);
return step*(v0 + v1)/2.0;
}
double Tabulated1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::Tabulated1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0)
return 0.0;
if (r1 == 1.0)
return 1.0;
unsigned idx = std::lower_bound(cdf_.begin(), cdf_.end(), r1) -
cdf_.begin() - 1U;
double xlo = step_*idx;
const double dcdf = r1 - cdf_[idx];
assert(dcdf > 0.0);
switch (deg_)
{
case 0:
{
const double c1 = table_[idx]*0.5*step_;
if (dcdf <= c1)
{
assert(table_[idx] > 0.0);
return xlo + dcdf/table_[idx];
}
else
{
assert(table_[idx+1] > 0.0);
return xlo + 0.5*step_ + (dcdf - c1)/table_[idx+1];
}
}
case 1:
{
const double a = (table_[idx+1] - table_[idx])/step_/2.0;
if (a == 0.0)
{
assert(table_[idx] > 0.0);
return xlo + dcdf/table_[idx];
}
else
{
double x1, x2;
const unsigned nroots = solveQuadratic(
table_[idx]/a, -dcdf/a, &x1, &x2);
if (nroots != 2U) throw std::runtime_error(
"In npstat::Tabulated1D::unscaledQuantile: "
"unexpected number of solutions");
if (fabs(x1 - 0.5*step_) < fabs(x2 - 0.5*step_))
return xlo + x1;
else
return xlo + x2;
}
}
default:
{
double xhi = xlo + step_;
const double eps = 2.0*DBL_EPSILON;
while ((xhi - xlo)/(xhi + xlo) > eps)
{
const double med = (xhi + xlo)/2.0;
if (unscaledCdf(med) >= r1)
xhi = med;
else
xlo = med;
}
return (xhi + xlo)/2.0;
}
}
}
bool BinnedDensity1D::isEqual(const AbsDistribution1D& otherBase) const
{
const double eps = 1.0e-12;
const BinnedDensity1D& r =
static_cast<const BinnedDensity1D&>(otherBase);
if (!AbsScalableDistribution1D::isEqual(r))
return false;
if (!(deg_ == r.deg_))
return false;
const unsigned long n = table_.size();
if (!(n == r.table_.size()))
return false;
for (unsigned long i=0; i<n; ++i)
if (fabs(table_[i] - r.table_[i])/
((fabs(table_[i]) + fabs(r.table_[i]))/2.0 + 1.0) > eps)
return false;
return true;
}
BinnedDensity1D::BinnedDensity1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale)
{
const unsigned npara = params.size();
if (npara)
initialize(&params[0], npara, std::min(1U, npara-1U));
else
initialize(static_cast<double*>(0), 0U, 0U);
}
void BinnedDensity1D::normalize()
{
cdf_.clear();
cdf_.reserve(len_);
long double sum = 0.0L;
switch (deg_)
{
case 0U:
for (unsigned i=0; i<len_; ++i)
{
sum += table_[i];
cdf_.push_back(static_cast<double>(sum));
}
break;
case 1U:
{
double oldval = 0.0;
double* data = &table_[0];
for (unsigned i=0; i<len_; ++i)
{
sum += (data[i] + oldval)*0.5;
oldval = data[i];
cdf_.push_back(static_cast<double>(sum));
}
sum += oldval*0.5;
}
break;
default:
assert(0);
}
const double norm = static_cast<double>(sum);
assert(norm > 0.0);
const double integ = norm*step_;
for (unsigned i=0; i<len_; ++i)
{
table_[i] /= integ;
cdf_[i] /= norm;
}
}
double BinnedDensity1D::unscaledDensity(const double x) const
{
double v = interpolate(x);
if (v < 0.0)
v = 0.0;
return v;
}
double BinnedDensity1D::interpolate(const double x) const
{
if (x < 0.0 || x > 1.0)
return 0.0;
switch (deg_)
{
case 0:
{
unsigned idx = static_cast<unsigned>(x/step_);
if (idx > len_ - 1)
idx = len_ - 1;
return table_[idx];
}
case 1:
{
const double xs = x - step_/2.0;
if (xs <= 0.0)
return table_[0];
const unsigned idx = static_cast<unsigned>(xs/step_);
if (idx > len_ - 2)
return table_[len_ - 1];
const double dx = xs/step_ - idx;
return interpolate_linear(dx, table_[idx], table_[idx + 1]);
}
default:
assert(0);
return 0.0;
}
}
double BinnedDensity1D::unscaledCdf(double x) const
{
if (x <= 0.0)
return 0.0;
if (x >= 1.0)
return 1.0;
double v = 0.0;
switch (deg_)
{
case 0:
{
unsigned idx = static_cast<unsigned>(x/step_);
if (idx > len_ - 1)
idx = len_ - 1;
v = (idx ? cdf_[idx - 1] : 0.0) + table_[idx]*(x - idx*step_);
}
break;
case 1:
{
const double xs = x - step_/2.0;
if (xs <= 0.0)
v = table_[0]*x;
else
{
const unsigned idx = static_cast<unsigned>(xs/step_);
if (idx > len_ - 2)
v = 1.0 - table_[len_ - 1]*(1.0 - x);
else
{
const double dx = xs - idx*step_;
const double slope = (table_[idx+1] - table_[idx])/step_;
v = cdf_[idx] + table_[idx]*dx + slope*dx*dx/2.0;
}
}
}
break;
default:
assert(0);
break;
}
if (v < 0.0)
v = 0.0;
else if (v > 1.0)
v = 1.0;
return v;
}
double BinnedDensity1D::unscaledQuantile(const double r1) const
{
if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
"In npstat::BinnedDensity1D::unscaledQuantile: "
"cdf argument outside of [0, 1] interval");
if (r1 == 0.0 && deg_)
return 0.0;
if (r1 == 1.0 && deg_)
return 1.0;
double v = 0.0;
switch (deg_)
{
case 0:
{
if (r1 == 0)
v = firstNonZeroBin_;
else if (r1 == 1.0)
v = lastNonZeroBin_ + 1U;
else if (r1 <= cdf_[0])
v = r1/cdf_[0];
else
{
double rem;
const unsigned bin = quantileBinFromCdf(&cdf_[0],len_,r1,&rem) + 1U;
assert(bin < len_);
v = bin + rem;
}
}
break;
case 1:
{
if (r1 <= cdf_[0])
v = 0.5*r1/cdf_[0];
else if (r1 >= cdf_[len_ - 1])
v = (len_-0.5+0.5*(r1-cdf_[len_-1])/(1.0-cdf_[len_-1]));
else
{
const unsigned idx = std::lower_bound(cdf_.begin(),cdf_.end(),r1) -
cdf_.begin() - 1U;
assert(idx < len_ - 1);
const double k = (table_[idx+1] - table_[idx])/step_;
const double y = r1 - cdf_[idx];
double x;
if (fabs(k) < 1.e-10*table_[idx])
x = y/table_[idx];
else
{
const double b = 2.0*table_[idx]/k;
const double c = -2.0*y/k;
double x1, x2;
if (solveQuadratic(b, c, &x1, &x2))
{
if (fabs(x1 - step_*0.5) < fabs(x2 - step_*0.5))
x = x1;
else
x = x2;
}
else
{
// This can happen due to various round-off problems.
// Assume that the quadratic equation determinant
// should have been 0 instead of negative.
x = -b/2.0;
}
}
if (x < 0.0)
x = 0.0;
else if (x > step_)
x = step_;
v = x/step_ + idx + 0.5;
}
}
break;
default:
assert(0);
return 0.0;
}
v *= step_;
if (v < 0.0)
v = 0.0;
else if (v > 1.0)
v = 1.0;
return v;
}
bool BinnedDensity1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, deg_);
gs::write_pod_vector(os, table_);
return !os.fail();
}
BinnedDensity1D* BinnedDensity1D::read(const gs::ClassId& id,
std::istream& in)
{
static const gs::ClassId current(
gs::ClassId::makeId<BinnedDensity1D>());
current.ensureSameId(id);
double location, scale;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
unsigned deg = 0;
gs::read_pod(in, &deg);
std::vector<double> table;
gs::read_pod_vector(in, &table);
if (!in.fail() && table.size())
return new BinnedDensity1D(location, scale,
&table[0], table.size(), deg);
}
distributionReadError(in, classname());
return 0;
}
bool StudentsT1D::write(std::ostream& os) const
{
AbsScalableDistribution1D::write(os);
gs::write_pod(os, nDoF_);
return !os.fail();
}
StudentsT1D* StudentsT1D::read(const gs::ClassId& id, std::istream& in)
{
static const gs::ClassId current(gs::ClassId::makeId<StudentsT1D>());
current.ensureSameId(id);
double location, scale;
if (AbsScalableDistribution1D::read(in, &location, &scale))
{
double nDoF;
gs::read_pod(in, &nDoF);
if (!in.fail())
return new StudentsT1D(location, scale, nDoF);
}
distributionReadError(in, classname());
return 0;
}
bool StudentsT1D::isEqual(const AbsDistribution1D& otherBase) const
{
const StudentsT1D& r = static_cast<const StudentsT1D&>(otherBase);
return AbsScalableDistribution1D::isEqual(r) &&
nDoF_ == r.nDoF_;
}
StudentsT1D::StudentsT1D(const double location, const double scale,
const double degreesOfFreedom)
: AbsScalableDistribution1D(location, scale),
nDoF_(degreesOfFreedom)
{
initialize();
}
StudentsT1D::StudentsT1D(const double location, const double scale,
const std::vector<double>& params)
: AbsScalableDistribution1D(location, scale),
nDoF_(params[0])
{
initialize();
}
void StudentsT1D::initialize()
{
if (nDoF_ <= 0.0) throw std::invalid_argument(
"In npstat::StudentsT1D::initialize: invalid number "
"of degrees of freedom");
power_ = (nDoF_ + 1.0)/2.0;
bignum_ = 0.0;
normfactor_ = Gamma(power_)/Gamma(nDoF_/2.0)/sqrt(nDoF_)/SQRPI;
}
double StudentsT1D::unscaledDensity(const double x) const
{
return normfactor_*pow(1.0 + x*x/nDoF_, -power_);
}
double StudentsT1D::unscaledCdf(const double t) const
{
const double s = sqrt(t*t + nDoF_);
return incompleteBeta(nDoF_/2.0, nDoF_/2.0, (t + s)/(2.0*s));
}
double StudentsT1D::unscaledExceedance(const double x) const
{
return 1.0 - unscaledCdf(x);
}
double StudentsT1D::unscaledQuantile(const double r1) const
{
if (r1 == 0.5)
return 0.0;
const double c = inverseIncompleteBeta(nDoF_/2.0, nDoF_/2.0, r1);
const double tmp = 2.0*c - 1.0;
const double a = tmp*tmp;
const double denom = 1.0 - a;
if (denom > 0.0)
{
const double sqroot = sqrt(nDoF_*a/denom);
return r1 > 0.5 ? sqroot : -sqroot;
}
else
{
if (bignum_ == 0.0)
(const_cast<StudentsT1D*>(this))->bignum_ = effectiveSupport();
return r1 > 0.5 ? bignum_ : -bignum_;
}
}
double StudentsT1D::effectiveSupport() const
{
// Figure out at which (positive) values of the argument
// the density becomes effectively indistinguishable from 0
const double biglog = (log(normfactor_) - log(DBL_MIN) +
power_*log(nDoF_))/(2.0*power_);
if (biglog >= log(DBL_MAX))
return DBL_MAX;
else
return exp(biglog);
}
}
Index: trunk/npstat/stat/Distributions1D.hh
===================================================================
--- trunk/npstat/stat/Distributions1D.hh (revision 743)
+++ trunk/npstat/stat/Distributions1D.hh (revision 744)
@@ -1,1067 +1,1067 @@
#ifndef NPSTAT_DISTRIBUTIONS1D_HH_
#define NPSTAT_DISTRIBUTIONS1D_HH_
/*!
// \file Distributions1D.hh
//
// \brief A number of useful 1-d continuous statistical distributions
//
// Author: I. Volobouev
//
// November 2009
*/
#include "npstat/stat/Distribution1DFactory.hh"
namespace npstat {
/**
// The uniform distribution is defined here by a constant density
// equal to 1 between 0 and 1 and equal to 0 everywhere else
*/
class Uniform1D : public AbsScalableDistribution1D
{
public:
inline Uniform1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale) {}
inline virtual Uniform1D* clone() const {return new Uniform1D(*this);}
inline virtual ~Uniform1D() {}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Uniform1D";}
static inline unsigned version() {return 1;}
static Uniform1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<Uniform1D>;
inline Uniform1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale) {}
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return 1.0 - unscaledCdf(x);}
};
/** Isosceles triangle distribution: 1 - |x| supported on [-1, 1] */
class IsoscelesTriangle1D : public AbsScalableDistribution1D
{
public:
inline IsoscelesTriangle1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale) {}
inline virtual IsoscelesTriangle1D* clone() const
{return new IsoscelesTriangle1D(*this);}
inline virtual ~IsoscelesTriangle1D() {}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname()
{return "npstat::IsoscelesTriangle1D";}
static inline unsigned version() {return 1;}
static IsoscelesTriangle1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<IsoscelesTriangle1D>;
inline IsoscelesTriangle1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale) {}
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return 1.0 - unscaledCdf(x);}
};
/** Exponential distribution. "scale" is the decay time. */
class Exponential1D : public AbsScalableDistribution1D
{
public:
inline Exponential1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale) {}
inline virtual Exponential1D* clone() const
{return new Exponential1D(*this);}
inline virtual ~Exponential1D() {}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Exponential1D";}
static inline unsigned version() {return 1;}
static Exponential1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<Exponential1D>;
inline Exponential1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale) {}
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
};
/** Logistic distribution */
class Logistic1D : public AbsScalableDistribution1D
{
public:
inline Logistic1D(const double location, const double scale)
: AbsScalableDistribution1D(location, scale) {}
inline virtual Logistic1D* clone() const
{return new Logistic1D(*this);}
inline virtual ~Logistic1D() {}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Logistic1D";}
static inline unsigned version() {return 1;}
static Logistic1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<Logistic1D>;
inline Logistic1D(const double location, const double scale,
const std::vector<double>& /* params */)
: AbsScalableDistribution1D(location, scale) {}
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
};
/**
// A distribution whose density has a simple quadratic shape.
// The support is from 0 to 1, and the coefficients "a" and "b"
// are the coefficients for the Legendre polynomials of 1st
// and 2nd degree translated to the support region. Note that
// only those values of "a" and "b" that guarantee non-negativity
// of the density are allowed, otherwise the code will generate
// a run-time error.
*/
class Quadratic1D : public AbsScalableDistribution1D
{
public:
Quadratic1D(double location, double scale, double a, double b);
inline virtual Quadratic1D* clone() const
{return new Quadratic1D(*this);}
inline virtual ~Quadratic1D() {}
inline double a() const {return a_;}
inline double b() const {return b_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Quadratic1D";}
- static inline unsigned version() {return 2;}
+ static inline unsigned version() {return 3;}
static Quadratic1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<Quadratic1D>;
Quadratic1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 2;}
void verifyNonNegative();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return 1.0 - unscaledCdf(x);}
double a_;
double b_;
};
/**
// A distribution whose density logarithm has a simple quadratic
// shape. The support is from 0 to 1, and the coefficients "a" and "b"
// are the coefficients for the Legendre polynomials of 1st and 2nd
// degree translated to the support region.
*/
class LogQuadratic1D : public AbsScalableDistribution1D
{
public:
LogQuadratic1D(double location, double scale, double a, double b);
inline virtual LogQuadratic1D* clone() const
{return new LogQuadratic1D(*this);}
inline virtual ~LogQuadratic1D() {}
inline double a() const {return a_;}
inline double b() const {return b_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::LogQuadratic1D";}
- static inline unsigned version() {return 2;}
+ static inline unsigned version() {return 3;}
static LogQuadratic1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<LogQuadratic1D>;
LogQuadratic1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 2;}
void normalize();
long double quadInteg(long double x) const;
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return 1.0 - unscaledCdf(x);}
long double ref_;
long double range_;
double a_;
double b_;
double k_;
double s_;
double norm_;
};
/** The Gaussian (or Normal) distribution */
class Gauss1D : public AbsScalableDistribution1D
{
public:
Gauss1D(double location, double scale);
inline virtual Gauss1D* clone() const {return new Gauss1D(*this);}
inline virtual ~Gauss1D() {}
// Higher quality generator than the one provided by
// the quantile function
virtual unsigned random(AbsRandomGenerator& g,
double* generatedRandom) const;
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Gauss1D";}
static inline unsigned version() {return 1;}
static Gauss1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<Gauss1D>;
Gauss1D(const double location, const double scale,
const std::vector<double>& params);
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
double xmin_;
double xmax_;
};
/** Gaussian distribution truncated at some number of sigmas */
class TruncatedGauss1D : public AbsScalableDistribution1D
{
public:
TruncatedGauss1D(double location, double scale, double nsigma);
inline virtual TruncatedGauss1D* clone() const
{return new TruncatedGauss1D(*this);}
inline virtual ~TruncatedGauss1D() {}
inline double nsigma() const {return nsigma_;}
// Higher quality generator than the one provided by
// the quantile function
virtual unsigned random(AbsRandomGenerator& g,
double* generatedRandom) const;
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::TruncatedGauss1D";}
static inline unsigned version() {return 1;}
static TruncatedGauss1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<TruncatedGauss1D>;
TruncatedGauss1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
void initialize();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return unscaledCdf(-x);}
double nsigma_;
double norm_;
double cdf0_;
};
/**
// Gaussian distribution on the [0, 1] interval, mirrored at the boundaries.
// This is the Green's function of the diffusion equation on [0, 1]. The
// interval can be shifted and scaled as for the uniform distribution.
*/
class MirroredGauss1D : public AbsScalableDistribution1D
{
public:
MirroredGauss1D(double location, double scale,
double meanOn0_1, double sigmaOn0_1);
inline virtual MirroredGauss1D* clone() const
{return new MirroredGauss1D(*this);}
inline virtual ~MirroredGauss1D() {}
inline double meanOn0_1() const {return mu0_;}
inline double sigmaOn0_1() const {return sigma0_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::MirroredGauss1D";}
static inline unsigned version() {return 1;}
static MirroredGauss1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<MirroredGauss1D>;
MirroredGauss1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 2;}
void validate();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
long double ldCdf(double x) const;
double mu0_;
double sigma0_;
};
/**
// Bifurcated Gaussian distribution. Different sigmas
// can be used on the left and on the right, with constructor
// parameter "leftSigmaFraction" specifying the ratio of
// the left sigma to the sum of sigmas (this ratio must be
// between 0 and 1). Different truncations in terms of the
// number of sigmas can be used as well.
*/
class BifurcatedGauss1D : public AbsScalableDistribution1D
{
public:
BifurcatedGauss1D(double location, double scale,
double leftSigmaFraction,
double nSigmasLeft, double nSigmasRight);
inline virtual BifurcatedGauss1D* clone() const
{return new BifurcatedGauss1D(*this);}
inline virtual ~BifurcatedGauss1D() {}
inline double leftSigmaFraction() const
{return leftSigma_/(leftSigma_ + rightSigma_);}
inline double nSigmasLeft() const
{return nSigmasLeft_;}
inline double nSigmasRight() const
{return nSigmasRight_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::BifurcatedGauss1D";}
static inline unsigned version() {return 1;}
static BifurcatedGauss1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
BifurcatedGauss1D(double location, double scale);
friend class ScalableDistribution1DFactory<BifurcatedGauss1D>;
BifurcatedGauss1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 3;}
void initialize();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
double leftSigma_;
double rightSigma_;
double nSigmasLeft_;
double nSigmasRight_;
double norm_;
double leftCdfFrac_;
double cdf0Left_;
double cdf0Right_;
};
/** Symmetric beta distribution */
class SymmetricBeta1D : public AbsScalableDistribution1D
{
public:
SymmetricBeta1D(double location, double scale, double power);
inline virtual SymmetricBeta1D* clone() const
{return new SymmetricBeta1D(*this);}
inline virtual ~SymmetricBeta1D() {}
inline double power() const {return n_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::SymmetricBeta1D";}
static inline unsigned version() {return 1;}
static SymmetricBeta1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<SymmetricBeta1D>;
SymmetricBeta1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return unscaledCdf(-x);}
double calculateNorm();
double n_;
double norm_;
int intpow_;
};
/** Beta1D density is proportional to x^(apha-1) * (1-x)^(beta-1) */
class Beta1D : public AbsScalableDistribution1D
{
public:
Beta1D(double location, double scale, double alpha, double beta);
inline virtual Beta1D* clone() const
{return new Beta1D(*this);}
inline virtual ~Beta1D() {}
inline double alpha() const {return alpha_;}
inline double beta() const {return beta_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Beta1D";}
static inline unsigned version() {return 1;}
static Beta1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<Beta1D>;
Beta1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 2;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledExceedance(double x) const;
double unscaledQuantile(double x) const;
double calculateNorm() const;
double alpha_;
double beta_;
double norm_;
};
/** Shiftable gamma distribution */
class Gamma1D : public AbsScalableDistribution1D
{
public:
Gamma1D(double location, double scale, double alpha);
inline virtual Gamma1D* clone() const
{return new Gamma1D(*this);}
inline virtual ~Gamma1D() {}
inline double alpha() const {return alpha_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Gamma1D";}
static inline unsigned version() {return 1;}
static Gamma1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<Gamma1D>;
Gamma1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledExceedance(double x) const;
double unscaledQuantile(double x) const;
void initialize();
double alpha_;
double norm_;
};
/**
// Pareto distribution. Location parameter is location of 0, scale
// parameter is the distance between 0 and the start of the density
// (like the normal Pareto distribution location parameter).
*/
class Pareto1D : public AbsScalableDistribution1D
{
public:
Pareto1D(double location, double scale, double powerParameter);
inline virtual Pareto1D* clone() const {return new Pareto1D(*this);}
inline virtual ~Pareto1D() {}
inline double powerParameter() const {return c_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Pareto1D";}
static inline unsigned version() {return 1;}
static Pareto1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<Pareto1D>;
Pareto1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
void initialize();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
double c_;
double support_;
};
/**
// Uniform distribution with Pareto tail attached to the right, where
// the support of the uniform would normally end. Location parameter
// is location of 0, scale parameter is the width of the uniform part
// (like the normal Pareto distribution location parameter).
*/
class UniPareto1D : public AbsScalableDistribution1D
{
public:
UniPareto1D(double location, double scale, double powerParameter);
inline virtual UniPareto1D* clone() const {return new UniPareto1D(*this);}
inline virtual ~UniPareto1D() {}
inline double powerParameter() const {return c_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::UniPareto1D";}
static inline unsigned version() {return 1;}
static UniPareto1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<UniPareto1D>;
UniPareto1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
void initialize();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
double c_;
double support_;
double amplitude_;
};
/** "Huber" distribution */
class Huber1D : public AbsScalableDistribution1D
{
public:
Huber1D(double location, double scale, double tailWeight);
inline virtual Huber1D* clone() const {return new Huber1D(*this);}
inline virtual ~Huber1D() {}
inline double tailWeight() const {return tailWeight_;}
inline double tailStart() const {return a_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Huber1D";}
static inline unsigned version() {return 1;}
static Huber1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<Huber1D>;
Huber1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
void initialize();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return unscaledCdf(-x);}
double weight(double a) const;
double tailWeight_;
double a_;
double normfactor_;
double support_;
double cdf0_;
};
/** Cauchy (or Breit-Wigner) distribution */
class Cauchy1D : public AbsScalableDistribution1D
{
public:
Cauchy1D(double location, double scale);
inline virtual Cauchy1D* clone() const {return new Cauchy1D(*this);}
inline virtual ~Cauchy1D() {}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Cauchy1D";}
static inline unsigned version() {return 1;}
static Cauchy1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<Cauchy1D>;
Cauchy1D(const double location, const double scale,
const std::vector<double>& params);
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return unscaledCdf(-x);}
double support_;
};
/**
// Log-normal distribution represented by its mean, standard
// deviation, and skewness. This representation is more useful
// than other representations encountered in statistical literature.
*/
class LogNormal : public AbsScalableDistribution1D
{
public:
LogNormal(double mean, double stdev, double skewness);
inline virtual LogNormal* clone() const {return new LogNormal(*this);}
inline virtual ~LogNormal() {}
inline double skewness() const {return skew_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::LogNormal";}
static inline unsigned version() {return 1;}
static LogNormal* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<LogNormal>;
LogNormal(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
void initialize();
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledExceedance(double x) const;
double unscaledQuantile(double x) const;
double skew_;
double logw_;
double s_;
double xi_;
double emgamovd_;
};
/**
// Moyal Distribution (originally derived by Moyal as an approximation
// to the Landau distribution)
*/
class Moyal1D : public AbsScalableDistribution1D
{
public:
Moyal1D(double location, double scale);
inline virtual Moyal1D* clone() const {return new Moyal1D(*this);}
inline virtual ~Moyal1D() {}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Moyal1D";}
static inline unsigned version() {return 1;}
static Moyal1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D& r) const
{return AbsScalableDistribution1D::isEqual(r);}
private:
friend class ScalableDistribution1DFactory<Moyal1D>;
Moyal1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 0;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
double xmax_;
double xmin_;
};
/** Student's t-distribution */
class StudentsT1D : public AbsScalableDistribution1D
{
public:
StudentsT1D(double location, double scale, double nDegreesOfFreedom);
inline virtual StudentsT1D* clone() const
{return new StudentsT1D(*this);}
inline virtual ~StudentsT1D() {}
inline double nDegreesOfFreedom() const {return nDoF_;}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::StudentsT1D";}
static inline unsigned version() {return 1;}
static StudentsT1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<StudentsT1D>;
StudentsT1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return 1;}
void initialize();
double effectiveSupport() const;
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledExceedance(double x) const;
double unscaledQuantile(double x) const;
double nDoF_;
double normfactor_;
double power_;
double bignum_;
};
/** Distribution defined by an interpolation table */
class Tabulated1D : public AbsScalableDistribution1D
{
public:
// The "data" array gives (unnormalized) density values at
// equidistant intervals. data[0] is density at 0.0, and
// data[dataLen-1] is density at 1.0. If "dataLen" is less
// than 2, uniform distribution will be created. Internally,
// the data is kept in double precision.
//
// "interpolationDegree" must be less than 4 and less than "dataLen".
//
template <typename Real>
Tabulated1D(double location, double scale,
const Real* data, unsigned dataLen,
unsigned interpolationDegree);
inline Tabulated1D(const double location, const double scale,
const std::vector<double>& table,
const unsigned interpolationDegree)
: AbsScalableDistribution1D(location, scale)
{
const unsigned long sz = table.size();
initialize(sz ? &table[0] : (double*)0, sz, interpolationDegree);
}
inline virtual Tabulated1D* clone() const
{return new Tabulated1D(*this);}
inline virtual ~Tabulated1D() {}
inline unsigned interpolationDegree() const {return deg_;}
inline unsigned tableLength() const {return len_;}
inline const double* tableData() const {return &table_[0];}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::Tabulated1D";}
static inline unsigned version() {return 1;}
static Tabulated1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<Tabulated1D>;
// The following constructor creates interpolator
// of maximum degree possible
Tabulated1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return -1;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
double unscaledExceedance(double x) const;
template <typename Real> void initialize(
const Real* data, unsigned dataLen, unsigned interpolationDegree);
void normalize();
double interpolate(double x) const;
double intervalInteg(unsigned intervalNumber) const;
double interpIntegral(double x0, double x1) const;
std::vector<double> table_;
std::vector<double> cdf_;
std::vector<double> exceed_;
double step_;
unsigned len_;
unsigned deg_;
};
/**
// Another interpolated distribution. For this one, we will assume
// that the coordinates correspond to 1-d histogram bin centers.
*/
class BinnedDensity1D : public AbsScalableDistribution1D
{
public:
// The "data" array gives density values at equidistant intervals.
// data[0] is density at 0.5/dataLen, and data[dataLen-1] is density
// at 1.0 - 0.5/dataLen.
//
// "interpolationDegree" must be less than 2.
//
template <typename Real>
BinnedDensity1D(double location, double scale,
const Real* data, unsigned dataLen,
unsigned interpolationDegree);
inline BinnedDensity1D(const double location, const double scale,
const std::vector<double>& table,
const unsigned interpolationDegree)
: AbsScalableDistribution1D(location, scale)
{
const unsigned long sz = table.size();
initialize(sz ? &table[0] : (double*)0, sz, interpolationDegree);
}
inline virtual BinnedDensity1D* clone() const
{return new BinnedDensity1D(*this);}
inline virtual ~BinnedDensity1D() {}
inline unsigned interpolationDegree() const {return deg_;}
inline unsigned tableLength() const {return len_;}
inline const double* tableData() const {return &table_[0];}
// Methods needed for I/O
virtual gs::ClassId classId() const {return gs::ClassId(*this);}
virtual bool write(std::ostream& os) const;
static inline const char* classname() {return "npstat::BinnedDensity1D";}
static inline unsigned version() {return 1;}
static BinnedDensity1D* read(const gs::ClassId& id, std::istream& in);
protected:
virtual bool isEqual(const AbsDistribution1D&) const;
private:
friend class ScalableDistribution1DFactory<BinnedDensity1D>;
// The following constructor creates interpolator
// of maximum degree possible
BinnedDensity1D(double location, double scale,
const std::vector<double>& params);
inline static int nParameters() {return -1;}
double unscaledDensity(double x) const;
double unscaledCdf(double x) const;
double unscaledQuantile(double x) const;
inline double unscaledExceedance(const double x) const
{return 1.0 - unscaledCdf(x);}
template <typename Real> void initialize(
const Real* data, unsigned dataLen, unsigned interpolationDegree);
void normalize();
double interpolate(double x) const;
std::vector<double> table_;
std::vector<double> cdf_;
double step_;
unsigned len_;
unsigned deg_;
unsigned firstNonZeroBin_;
unsigned lastNonZeroBin_;
};
}
#include "npstat/stat/Distributions1D.icc"
#endif // NPSTAT_DISTRIBUTIONS1D_HH_
Index: trunk/tests/test_Distributions1D.cc
===================================================================
--- trunk/tests/test_Distributions1D.cc (revision 743)
+++ trunk/tests/test_Distributions1D.cc (revision 744)
@@ -1,2084 +1,2136 @@
#include <complex>
#include <iostream>
#include "UnitTest++.h"
#include "test_utils.hh"
#include "EdgeworthSeries1DOld.hh"
#include "npstat/stat/Distributions1D.hh"
#include "npstat/stat/GaussianMixture1D.hh"
#include "npstat/stat/JohnsonCurves.hh"
#include "npstat/stat/TruncatedDistribution1D.hh"
#include "npstat/stat/LeftCensoredDistribution.hh"
#include "npstat/stat/RightCensoredDistribution.hh"
#include "npstat/stat/QuantileTable1D.hh"
#include "npstat/stat/DistributionMix1D.hh"
#include "npstat/stat/VerticallyInterpolatedDistribution1D.hh"
#include "npstat/stat/UGaussConvolution1D.hh"
#include "npstat/stat/RatioOfNormals.hh"
#include "npstat/stat/InterpolatedDistro1D1P.hh"
#include "npstat/stat/TransformedDistribution1D.hh"
#include "npstat/stat/EdgeworthSeries1D.hh"
#include "npstat/stat/DeltaMixture1D.hh"
#include "npstat/stat/CompositeDistribution1D.hh"
#include "npstat/stat/ComparisonDistribution1D.hh"
#include "npstat/stat/PolynomialDistro1D.hh"
#include "npstat/stat/distro1DStats.hh"
#include "npstat/stat/cumulantConversion.hh"
#include "npstat/stat/IdentityTransform1D.hh"
#include "npstat/stat/AsinhTransform1D.hh"
#include "npstat/stat/LogRatioTransform1D.hh"
#include "npstat/stat/LocationScaleTransform1.hh"
#include "npstat/stat/Distribution1DReader.hh"
#include "npstat/stat/DistributionTransform1DReader.hh"
#include "npstat/stat/arrayStats.hh"
#include "npstat/nm/EquidistantSequence.hh"
#include "npstat/nm/LinearMapper1d.hh"
#include "npstat/nm/ClassicalOrthoPolys1D.hh"
#include "npstat/nm/MathUtils.hh"
#include "npstat/nm/GaussHermiteQuadrature.hh"
#include "npstat/nm/GaussLegendreQuadrature.hh"
#include "npstat/nm/SpecialFunctions.hh"
#include "npstat/rng/MersenneTwister.hh"
#include "LogLogQuadratic1D.hh"
#include "geners/pseudoIO.hh"
#define LSQR2 1.41421356237309504880169L
#define SQRTWOPIL 2.50662827463100050241577L
using namespace npstat;
using namespace std;
struct Two : public npstat::ConstValue1<double,double>
{
inline Two() : npstat::ConstValue1<double,double>(2.0) {}
};
gs_enable_pseudo_io(Two)
struct Three : public npstat::ConstValue1<double,double>
{
inline Three() : npstat::ConstValue1<double,double>(3.0) {}
};
gs_enable_pseudo_io(Three)
struct Xsq
{
inline double operator()(const double x) const {return x*x;}
inline bool operator==(const Xsq&) const {return true;}
};
gs_enable_pseudo_io(Xsq)
struct Xp1
{
inline double operator()(const double x) const {return x + 1.0;}
inline bool operator==(const Xp1&) const {return true;}
};
gs_enable_pseudo_io(Xp1)
static long double ldgexceedance(const long double x)
{
return erfcl(x/LSQR2)/2.0L;
}
static long double ldgcdf(const long double x)
{
return erfcl(-x/LSQR2)/2.0L;
}
namespace {
double he0(const double x)
{
return 1.0;
}
double he1(const double x)
{
return x;
}
double he2(const double x)
{
return x*x - 1.0;
}
double he3(const double x)
{
return x*(x*x - 3.0);
}
double he4(const long double x)
{
const long double xsq = x*x;
return 3 - 6*xsq + xsq*xsq;
}
double he5(const long double x)
{
const long double xsq = x*x;
return x*(xsq*xsq - 10*xsq + 15);
}
double he6(const long double x)
{
const long double xsq = x*x;
return -15 + 45*xsq - 15*xsq*xsq + xsq*xsq*xsq;
}
double he7(const long double x)
{
const long double xsq = x*x;
return x*(-105 + 105*xsq - 21*xsq*xsq + xsq*xsq*xsq);
}
double he8(const long double x)
{
const long double xsq = x*x;
const long double x4 = xsq*xsq;
return 105 - 420*xsq + 210*x4 - 28*x4*xsq + x4*x4;
}
double he9(const long double x)
{
const long double xsq = x*x;
const long double x4 = xsq*xsq;
return x*(945 - 1260*xsq + 378*x4 - 36*xsq*x4 + x4*x4);
}
double he10(const long double x)
{
const long double xsq = x*x;
const long double x4 = xsq*xsq;
const long double x6 = x4*xsq;
const long double x8 = x6*xsq;
const long double x10 = x8*xsq;
return -945 + 4725*xsq - 3150*x4 + 630*x6 - 45*x8 + x10;
}
double he11(const long double x)
{
const long double xsq = x*x;
const long double x4 = xsq*xsq;
const long double x6 = x4*xsq;
const long double x8 = x6*xsq;
const long double x10 = x8*xsq;
return x*(-10395 + 17325*xsq - 6930*x4 + 990*x6 - 55*x8 + x10);
}
double he12(const long double x)
{
const long double xsq = x*x;
const long double x4 = xsq*xsq;
const long double x6 = x4*xsq;
const long double x8 = x6*xsq;
const long double x10 = x8*xsq;
const long double x12 = x10*xsq;
return 10395 - 62370*xsq + 51975*x4 - 13860*x6 + 1485*x8 - 66*x10 + x12;
}
/*
void cumulants_from_moments(const double m[10], double cumulants[10])
{
cumulants[0] = 0.0;
for (unsigned i=1; i<4; ++i)
cumulants[i] = m[i];
const double m2sq = m[2]*m[2];
const double m3sq = m[3]*m[3];
cumulants[4] = m[4] - 3*m2sq;
cumulants[5] = m[5] - 10*m[2]*m[3];
cumulants[6] = m[6] - 15*m[2]*m[4] - 10*m[3]*m[3] + 30*m2sq*m[2];
cumulants[7] = m[7] + 210*m2sq*m[3] - 35*m[3]*m[4] - 21*m[2]*m[5];
cumulants[8] = -630*m2sq*m2sq + 420*m2sq*m[4] - 35*m[4]*m[4] - 56*m[3]*m[5] +
28*m[2]*(20*m3sq - m[6]) + m[8];
cumulants[9] = -7560*m2sq*m[2]*m[3] + 560*m[3]*m3sq + 756*m2sq*m[5] - 126*m[4]*m[5] -
84*m[3]*m[6] + 36*m[2]*(70*m[3]*m[4] - m[7]) + m[9];
}
*/
void get_edgeworth_cumulants(const EdgeworthSeries1D& s, double cumulants[10])
{
double m[10];
for (unsigned i=0; i<10; ++i)
m[i] = s.empiricalCentralMoment(i);
if (s.order())
m[1] = s.cum(0);
npstat::convertCentralMomentsToCumulants(m, 9, cumulants);
}
+ class DummyFunct : public Functor1<double,double>
+ {
+ public:
+ inline DummyFunct(double a, double b)
+ : a_(a), b_(b) {}
+
+ inline double operator()(const double& x) const
+ {
+ const double twoxm1 = 2*x - 1;
+ const double p1 = twoxm1;
+ const double p2 = 0.5*(3.0*twoxm1*twoxm1 - 1.0);
+ return exp(a_*p1 + b_*p2);
+ }
+
+ private:
+ double a_;
+ double b_;
+ };
+
void io_test(const AbsDistribution1D& d)
{
std::ostringstream os;
CHECK(d.classId().write(os));
CHECK(d.write(os));
std::istringstream is(os.str());
gs::ClassId id(is, 1);
AbsDistribution1D* phoenix = AbsDistribution1D::read(id, is);
CHECK(*phoenix == d);
delete phoenix;
}
void standard_test(const AbsDistribution1D& d, const double range,
const double eps, const bool do_io = true)
{
const double cdf0 = d.cdf(0.0);
for (unsigned i=0; i<100; ++i)
{
const double r = 2*range*(test_rng() - 0.5);
const double cdfr = d.cdf(r);
if (cdfr > 0.0 && cdfr < 1.0)
{
CHECK_CLOSE(cdfr, 1.0 - d.exceedance(r), eps);
CHECK_CLOSE(r, d.quantile(cdfr), eps);
const double integ = simpson_integral(
DensityFunctor1D(d), 0.0, r);
CHECK_CLOSE(integ, cdfr-cdf0, eps);
}
}
if (do_io)
io_test(d);
}
void standard_test_01(const AbsDistribution1D& d,
const double eps, const bool do_io = true)
{
const double cdf0 = d.cdf(0.0);
for (unsigned i=0; i<100; ++i)
{
const double r = test_rng();
const double cdfr = d.cdf(r);
if (cdfr > 0.0 && cdfr < 1.0)
{
CHECK_CLOSE(cdfr, 1.0 - d.exceedance(r), eps);
CHECK_CLOSE(r, d.quantile(cdfr), eps);
const double integ = simpson_integral(
DensityFunctor1D(d), 0.0, r);
CHECK_CLOSE(integ, cdfr-cdf0, eps);
}
}
if (do_io)
io_test(d);
}
void invcdf_test(const AbsDistribution1D& d, const double eps)
{
for (unsigned i=0; i<1000; ++i)
{
const double r = test_rng();
const double x = d.quantile(r);
const double cdf = d.cdf(x);
CHECK_CLOSE(cdf, r, eps);
CHECK_CLOSE(cdf, 1.0 - d.exceedance(x), eps);
}
}
void invexceedance_test(const EdgeworthSeries1D& d, const double eps)
{
for (unsigned i=0; i<1000; ++i)
{
const double r = test_rng();
const double x = d.inverseExceedance(r);
const double exc = d.exceedance(x);
CHECK_CLOSE(exc, r, eps);
CHECK_CLOSE(exc, 1.0 - d.cdf(x), eps);
}
}
class MirroredGauss1D_meanFunctor : public Functor1<double,double>
{
public:
inline MirroredGauss1D_meanFunctor(const MirroredGauss1D& mg,
const double y)
: location_(mg.location()), scale_(mg.scale()),
sigmaOn0_1_(mg.sigmaOn0_1()), y_(y),
mapper_(location_, 0.0, location_+scale_, 1.0) {}
inline double operator()(const double& mean) const
{
MirroredGauss1D mg(location_, scale_, mapper_(mean), sigmaOn0_1_);
return mg.density(y_);
}
private:
double location_;
double scale_;
double sigmaOn0_1_;
double y_;
LinearMapper1d mapper_;
};
TEST(expectation)
{
const double eps = 1.0e-14;
Gauss1D g(2.0, 1.0);
auto lamx = [](double x) {return x;};
auto lamx2 = [](double x) {return x*x;};
auto lamx3 = [](double x) {return x*x*x;};
CHECK_CLOSE(2.0, g.expectation(lamx), eps);
CHECK_CLOSE(5.0, g.expectation(lamx2), eps);
CHECK_CLOSE(14.0, g.expectation(lamx3), eps);
}
TEST(cumulantConversion)
{
const double eps1 = 1.0e-15;
const double eps2 = 1.0e-13;
const unsigned maxOrder = 20U;
const unsigned npoints = 100U;
long double moments[maxOrder+1U];
long double moments2[maxOrder+1U];
long double cumulants[maxOrder+1U];
std::vector<double> points(npoints);
for (unsigned i=0; i<npoints; ++i)
points[i] = test_rng();
arrayCentralMoments(&points[0], points.size(), maxOrder, moments);
convertCentralMomentsToCumulants(moments, maxOrder, cumulants);
convertCumulantsToCentralMoments(cumulants, maxOrder, moments2);
for (unsigned k=0; k<=maxOrder; ++k)
{
if (k <= 12)
CHECK_CLOSE(moments[k], moments2[k], eps1);
else
CHECK_CLOSE(moments[k], moments2[k], eps2);
}
}
TEST(Distributions1D_Gauss)
{
Gauss1D g(0., 1.);
double value = simpson_integral(DensityFunctor1D(g), -6, 6);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(g, 6, 1.e-7);
CHECK_CLOSE(7.61985302416e-24, g.cdf(-10.0), 1.e-34);
CHECK_CLOSE(7.61985302416e-24, g.exceedance(10.0), 1.e-34);
CHECK_CLOSE(2.75362411861e-89, g.cdf(-20.0), 1.e-99);
CHECK_CLOSE(2.75362411861e-89, g.exceedance(20.0), 1.e-99);
}
TEST(Distributions1D_Bifgauss_0)
{
const double lfrac = 0.3;
const double lsigma = lfrac*2.0;
const double rsigma = 2.0 - lsigma;
BifurcatedGauss1D g(0.0, 1.0, lfrac, 2.0, 1.5);
double value = simpson_integral(DensityFunctor1D(g),
-lsigma*g.nSigmasLeft(),
rsigma*g.nSigmasRight());
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(g, lsigma*g.nSigmasLeft(), 1.e-7);
}
TEST(Distributions1D_Bifgauss_1)
{
const double eps = 1.0e-12;
BifurcatedGauss1D g1(0.0, 2.0, 0.5, 2.0, 2.0);
TruncatedGauss1D g2(0.0, 2.0, 2.0);
for (unsigned i=0; i<100; ++i)
{
const double r = test_rng();
const double q1 = g1.quantile(r);
const double q2 = g2.quantile(r);
CHECK_CLOSE(q1, q2, eps);
CHECK_CLOSE(g1.density(q1), g2.density(q1), eps);
CHECK_CLOSE(g1.cdf(q1), g2.cdf(q1), eps);
CHECK_CLOSE(g1.exceedance(q1), g2.exceedance(q1), eps);
}
}
TEST(Distributions1D_Bifgauss_2)
{
BifurcatedGauss1D g(0.0, 1.0, 0.0, 2.0, 2.0);
double value = simpson_integral(DensityFunctor1D(g), 0.0, 4.0);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(g, 4.0, 1.e-7);
}
TEST(Distributions1D_Bifgauss_3)
{
BifurcatedGauss1D g(0.0, 1.0, 1.0, 2.0, 2.0);
double value = simpson_integral(DensityFunctor1D(g), -4.0, 0.0);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(g, 4.0, 1.e-7);
IdentityTransform1D it(5.0);
TransformedDistribution1D td(it, g);
value = simpson_integral(DensityFunctor1D(td), -4.0, 0.0);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(td, 4.0, 1.e-7);
}
TEST(Distributions1D_uniform)
{
Uniform1D g(0., 1.);
double value = simpson_integral(DensityFunctor1D(g), -0.1, 1.1);
CHECK_CLOSE(1.0, value, 1.e-3);
standard_test(g, 1, 1.e-7);
}
TEST(Distributions1D_exp)
{
Exponential1D g(0., 1.);
standard_test(g, 20.0, 1.e-7);
g.setScale(3.);
standard_test(g, 60.0, 1.e-7);
}
TEST(Distributions1D_Pareto)
{
Pareto1D p1(0., 1., 1.5);
double value = simpson_integral(DensityFunctor1D(p1), 1, 6);
CHECK_CLOSE(0.93195861825602283, value, 1.e-8);
invcdf_test(p1, 1.e-10);
io_test(p1);
}
TEST(Distributions1D_MirroredGauss)
{
{
MirroredGauss1D g(0., 1., 0.3, 0.1);
const double value = simpson_integral(DensityFunctor1D(g), 0, 1);
CHECK_CLOSE(1.0, value, 1.e-12);
invcdf_test(g, 1.e-10);
io_test(g);
for (unsigned i=0; i<100; ++i)
{
const double y = test_rng();
const double cdfy = simpson_integral(DensityFunctor1D(g), 0, y);
CHECK_CLOSE(cdfy, g.cdf(y), 1.0e-10);
}
}
{
MirroredGauss1D g(0., 2., 0.7, 0.1);
const double value = simpson_integral(DensityFunctor1D(g), 0, 2);
CHECK_CLOSE(1.0, value, 1.e-12);
invcdf_test(g, 1.e-10);
io_test(g);
for (unsigned i=0; i<100; ++i)
{
const double y = 2.0*test_rng();
const double cdfy = simpson_integral(DensityFunctor1D(g), 0, y);
CHECK_CLOSE(cdfy, g.cdf(y), 1.0e-10);
}
}
}
TEST(Distributions1D_MirroredGauss_doublestochastic)
{
const double loc = 1.0;
const double scale = 3.0;
const double eps = 1.0e-12;
MirroredGauss1D g(loc, scale, 0.7, 0.1);
GaussLegendreQuadrature glq(1024);
CHECK_CLOSE(1.0, glq.integrate(DensityFunctor1D(g), loc, loc+scale), eps);
const unsigned ntries = 50;
for (unsigned i=0; i<ntries; ++i)
{
const double y = loc + test_rng()*scale;
MirroredGauss1D_meanFunctor mf(g, y);
CHECK_CLOSE(1.0, glq.integrate(mf, loc, loc+scale), eps);
}
}
TEST(Distributions1D_Huber)
{
Huber1D h1(0., 1., 0.0);
double value = simpson_integral(DensityFunctor1D(h1), -6, 6);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(h1, 6, 1.e-7);
double tailW = 0.2;
double sigma = 0.8;
Huber1D h2(0., sigma, tailW);
CHECK_EQUAL(tailW, h2.tailWeight());
value = simpson_integral(DensityFunctor1D(h2), -20, 20, 10000);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(h2, 6, 1.e-7);
const double a = sigma*h2.tailStart();
value = simpson_integral(DensityFunctor1D(h2), -a, a, 10000);
CHECK_CLOSE(1.0-tailW, value, 1.e-8);
for (unsigned i=0; i<1000; ++i)
{
const double rndx = 6*a*(test_rng() - 0.5);
const double cdf = h2.cdf(rndx);
value = simpson_integral(DensityFunctor1D(h2), -20, rndx, 10000);
CHECK_CLOSE(cdf, value, 1.e-8);
CHECK_CLOSE(h2.quantile(cdf), rndx, 1.e-8);
}
}
TEST(Distributions1D_Symbeta)
{
SymmetricBeta1D sb(0.0, 1.0, 3);
double value = simpson_integral(DensityFunctor1D(sb), -1, 1);
CHECK_CLOSE(1.0, value, 1.e-8);
for (unsigned i=0; i<10; ++i)
{
SymmetricBeta1D sb(0.0, 2.0, i);
standard_test(sb, 1.8, 1.e-8);
}
}
TEST(Distributions1D_Moyal)
{
Moyal1D mo(0.0, 1.0);
double value = simpson_integral(DensityFunctor1D(mo), -7, 1000, 100000);
CHECK_CLOSE(1.0, value, 1.e-9);
CHECK_CLOSE(0.24197072451914335, mo.density(0.0), 1.0e-14);
CHECK_CLOSE(0.20131624406488799, mo.density(1.0), 1.0e-14);
CHECK_CLOSE(0.31731050786291410, mo.cdf(0.0), 1.0e-12);
CHECK_CLOSE(0.54416242936230305, mo.cdf(1.0), 1.0e-12);
invcdf_test(mo, 1.e-8);
io_test(mo);
}
TEST(Distributions1D_StudentsT1D)
{
for (unsigned i=1; i<10; ++i)
{
StudentsT1D t(0.0, 1.0, i);
invcdf_test(t, 1.e-8);
}
}
TEST(Distributions1D_beta)
{
Beta1D b(0.0, 1.0, 3.0, 4.0);
double value = simpson_integral(DensityFunctor1D(b), 0, 1);
CHECK_CLOSE(1.0, value, 1.e-8);
for (unsigned i=1; i<5; ++i)
for (unsigned j=1; j<5; ++j)
{
Beta1D sb(0.5, 2.0, i, j);
standard_test(sb, 0.9, 1.e-3);
}
}
TEST(Distributions1D_beta_symbeta_compare)
{
const double eps = 1.0e-14;
SymmetricBeta1D sb(0.0, 2.0, 3);
Beta1D b(-2.0, 4.0, 4.0, 4.0);
for (unsigned i=0; i<100; ++i)
{
const double x = test_rng()*2.0 - 1.0;
CHECK_CLOSE(b.density(x), sb.density(x), eps);
}
}
TEST(Distributions1D_gamma)
{
Gamma1D g1(0., 0.8, 1.0);
standard_test(g1, 20.0, 5.e-3);
Gamma1D g2(0., 0.9, 2.0);
standard_test(g2, 20.0, 2.e-5);
Gamma1D g3(0., 1.1, 3.0);
standard_test(g3, 20.0, 2.e-5);
}
TEST(UGaussConvolution1D)
{
UGaussConvolution1D ug(0, 1, -1, 1);
standard_test(ug, 6.0, 1.0e-6);
}
TEST(Distributions1D_Transformed)
{
StaticDistributionTransform1DReader::registerClass<
LocationScaleTransform1<Two,Three> >();
const double teps = 1.0e-12;
Two two;
Three three;
LocationScaleTransform1<Two,Three> tr(two, three);
Gauss1D g(0.0, 1.0);
TransformedDistribution1D d1(tr, g);
io_test(d1);
Gauss1D g1(2.0, 3.0);
for (unsigned i=0; i<100; ++i)
{
const double x = 10.0*(test_rng() - 0.5);
CHECK_CLOSE(g1.density(x), d1.density(x), teps);
CHECK_CLOSE(g1.cdf(x), d1.cdf(x), teps);
CHECK_CLOSE(g1.exceedance(x), d1.exceedance(x), teps);
const double y = test_rng();
CHECK_CLOSE(g1.quantile(y), d1.quantile(y), teps);
}
}
TEST(Distributions1D_JohnsonSu)
{
const double teps = 1.0e-12;
JohnsonSu jsu1(0.0, 1.0, 1.0, 10.0);
standard_test(jsu1, 6, 1.e-8);
AsinhTransform1D tr1(jsu1.getDelta(), jsu1.getLambda(),
jsu1.getGamma(), jsu1.getXi());
Gauss1D g(0.0, 1.0);
TransformedDistribution1D d1(tr1, g);
standard_test(d1, 6, 1.e-8);
for (unsigned i=0; i<100; ++i)
{
const double x = 10.0*(test_rng() - 0.5);
CHECK_CLOSE(jsu1.density(x), d1.density(x), teps);
CHECK_CLOSE(jsu1.cdf(x), d1.cdf(x), teps);
CHECK_CLOSE(jsu1.exceedance(x), d1.exceedance(x), teps);
const double y = test_rng();
CHECK_CLOSE(jsu1.quantile(y), d1.quantile(y), teps);
}
JohnsonSu jsu2(0.1, 1.0, -1.0, 10.0);
standard_test(jsu2, 6, 1.e-8);
AsinhTransform1D tr2(jsu2.getDelta(), jsu2.getLambda(),
jsu2.getGamma(), jsu2.getXi());
TransformedDistribution1D d2(tr2, g);
standard_test(d2, 6, 1.e-8);
double mean, sigma, skew, kurt;
distro1DStats(jsu2, -30.0, 20.0, 500000, &mean, &sigma, &skew, &kurt);
CHECK_CLOSE(0.1, mean, 1.0e-5);
CHECK_CLOSE(1.0, sigma, 1.0e-4);
CHECK_CLOSE(-1.0, skew, 0.01);
CHECK_CLOSE(10.0, kurt, 0.2);
}
TEST(Distributions1D_JohnsonSb)
{
const double teps = 1.0e-12;
JohnsonSb jsb1(0.0, 1.0, 1.0, 2.9);
LogRatioTransform1D tr1(jsb1.getDelta(), jsb1.getLambda(),
jsb1.getGamma(), jsb1.getXi());
Gauss1D g(0.0, 1.0);
TransformedDistribution1D d1(tr1, g);
const double lolim = jsb1.getXi();
const double range = jsb1.getLambda();
for (unsigned i=0; i<100; ++i)
{
const double x = lolim + range*test_rng();
CHECK_CLOSE(jsb1.density(x), d1.density(x), teps);
CHECK_CLOSE(jsb1.cdf(x), d1.cdf(x), teps);
CHECK_CLOSE(jsb1.exceedance(x), d1.exceedance(x), teps);
const double y = test_rng();
CHECK_CLOSE(jsb1.quantile(y), d1.quantile(y), teps);
}
}
TEST(Distributions1D_LogNormal0)
{
LogNormal g(0., 1., 0.);
double value = simpson_integral(DensityFunctor1D(g), -6, 6);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(g, 6, 1.e-6);
}
TEST(Distributions1D_LogNormal1)
{
LogNormal ln1(0., 1., 2.0);
double value = simpson_integral(DensityFunctor1D(ln1), -6, 20);
CHECK_CLOSE(1.0, value, 1.e-6);
standard_test(ln1, 7, 2.e-4);
}
TEST(Distributions1D_LogNormal2)
{
LogNormal ln2(0., 1., -2.0);
double value = simpson_integral(DensityFunctor1D(ln2), -20, 6);
CHECK_CLOSE(1.0, value, 1.e-6);
standard_test(ln2, 7, 4.e-4);
}
TEST(Distributions1D_LogNormal3)
{
LogNormal ln3(-0.5, 1., 2.0);
standard_test(ln3, 7, 1.e-3);
}
TEST(Distributions1D_LogNormal4)
{
LogNormal ln4(-0.5, 1., -2.0);
standard_test(ln4, 7, 1.e-3);
}
TEST(Distributions1D_LogNormal5)
{
LogNormal ln5(0.5, 2., 2.0);
standard_test(ln5, 7, 1.e-3);
}
TEST(Distributions1D_LogNormal6)
{
LogNormal ln6(0.5, 2., -2.0);
standard_test(ln6, 7, 1.e-3);
}
TEST(Distributions1D_LogNormal7)
{
LogNormal ln7(1., 2., 10.0);
standard_test(ln7, 7, 1.e-3);
}
TEST(Distributions1D_LogNormal8)
{
LogNormal ln8(1., 2., -10.0);
standard_test(ln8, 7, 1.e-3);
}
TEST(Distributions1D_misc)
{
Cauchy1D ch(0.0, 0.5);
standard_test(ch, 5, 1.e-8);
TruncatedGauss1D tg(0.0, 2.0, 3.0);
standard_test(tg, 6.0, 1.e-8);
Gauss1D gauss(0.0, 2.0);
TruncatedDistribution1D td(gauss, -6.0, 6.0);
standard_test(td, 6.0, 1.e-8);
CHECK_CLOSE(td.density(0.5), tg.density(0.5), 1.0e-14);
CHECK_CLOSE(td.cdf(0.5), tg.cdf(0.5), 1.0e-14);
CHECK_CLOSE(td.quantile(0.3), tg.quantile(0.3), 1.0e-14);
CHECK_CLOSE(td.exceedance(0.3), tg.exceedance(0.3), 1.0e-14);
}
TEST(EdgeworthSeries1D_io)
{
const unsigned order = 2;
std::vector<double> cumulants(4);
for (unsigned i=0; i<cumulants.size(); ++i)
cumulants[i] = i+1;
EdgeworthSeries1D s1(cumulants, EDGEWORTH_CLASSICAL, order, false);
io_test(s1);
}
TEST(EdgeworthSeries1D_0)
{
const unsigned order = 0;
std::vector<double> dummy;
double empCum[10];
EdgeworthSeries1D es1(dummy, EDGEWORTH_SEVERINI, order, false);
CHECK_CLOSE(0.241970724519143, es1.density(1.0), 1.e-14);
CHECK_CLOSE(7.61985302416e-24, es1.cdf(-10.0), 1.e-34);
CHECK_CLOSE(7.61985302416e-24, es1.exceedance(10.0), 1.e-34);
standard_test(es1, 6, 1.e-7);
invexceedance_test(es1, 1.e-8);
get_edgeworth_cumulants(es1, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(0.0, empCum[1], 1.e-14);
CHECK_CLOSE(1.0, empCum[2], 1.e-14);
CHECK_CLOSE(0.0, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
EdgeworthSeries1D es2(dummy, EDGEWORTH_SEVERINI, order, true);
CHECK_CLOSE(0.241970724519143, es2.density(1.0), 1.e-14);
CHECK_CLOSE(7.61985302416e-24, es2.cdf(-10.0), 1.e-34);
CHECK_CLOSE(7.61985302416e-24, es2.exceedance(10.0), 1.e-34);
standard_test(es2, 6, 1.e-7);
invexceedance_test(es2, 1.e-8);
get_edgeworth_cumulants(es2, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(0.0, empCum[1], 1.e-14);
CHECK_CLOSE(1.0, empCum[2], 1.e-14);
CHECK_CLOSE(0.0, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
EdgeworthSeries1D es3(dummy, EDGEWORTH_CLASSICAL, order, false);
CHECK_CLOSE(0.241970724519143, es3.density(1.0), 1.e-14);
CHECK_CLOSE(7.61985302416e-24, es3.cdf(-10.0), 1.e-34);
CHECK_CLOSE(7.61985302416e-24, es3.exceedance(10.0), 1.e-34);
standard_test(es3, 6, 1.e-7);
invexceedance_test(es3, 1.e-8);
get_edgeworth_cumulants(es3, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(0.0, empCum[1], 1.e-14);
CHECK_CLOSE(1.0, empCum[2], 1.e-14);
CHECK_CLOSE(0.0, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
EdgeworthSeries1D es4(dummy, EDGEWORTH_CLASSICAL, order, true);
CHECK_CLOSE(0.241970724519143, es4.density(1.0), 1.e-14);
CHECK_CLOSE(7.61985302416e-24, es4.cdf(-10.0), 1.e-34);
CHECK_CLOSE(7.61985302416e-24, es4.exceedance(10.0), 1.e-34);
standard_test(es4, 6, 1.e-7);
invexceedance_test(es4, 1.e-8);
get_edgeworth_cumulants(es4, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(0.0, empCum[1], 1.e-14);
CHECK_CLOSE(1.0, empCum[2], 1.e-14);
CHECK_CLOSE(0.0, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
}
TEST(EdgeworthSeries1D_1)
{
const double range = 5.0;
const unsigned ntries = 10;
const unsigned order = 1;
const double k1 = 3, k2 = 2, k3 = 0.5;
double empCum[10];
std::vector<double> c_slr(1);
c_slr[0] = k1;
std::vector<double> c_gen(3);
c_gen[0] = k1;
c_gen[1] = k2;
c_gen[2] = k3;
EdgeworthSeries1D es1(c_slr, EDGEWORTH_SEVERINI, order, true);
standard_test(es1, 6, 1.e-8);
invexceedance_test(es1, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double fact = 1 + k1*he1(x);
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*(k1);
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*(k1);
CHECK_CLOSE(k1, es1.cdfFactor(x), 1.0e-14);
CHECK_CLOSE(fact, es1.densityFactor(x), 1.0e-14);
CHECK_CLOSE(dens, es1.density(x), 1.0e-14);
CHECK_CLOSE(cdf, es1.cdf(x), 1.0e-14);
CHECK_CLOSE(exc, es1.exceedance(x), 1.0e-14);
}
get_edgeworth_cumulants(es1, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(1.0 - k1*k1, empCum[2], 1.e-14);
CHECK_CLOSE(2.0*k1*k1*k1, empCum[3], 1.e-14);
CHECK_CLOSE(-6*k1*k1*k1*k1, empCum[4], 1.e-14);
EdgeworthSeries1D es2(c_gen, EDGEWORTH_SEVERINI, order, false);
standard_test(es2, 6, 1.e-8);
invexceedance_test(es2, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double fact = 1 + k1*he1(x) + k3/6.0*he3(x);
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdffact = k1*he0(x) + k3/6.0*he2(x);
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es2.cdfFactor(x), 1.0e-14);
CHECK_CLOSE(fact, es2.densityFactor(x), 1.0e-14);
CHECK_CLOSE(dens, es2.density(x), 1.0e-14);
CHECK_CLOSE(cdf, es2.cdf(x), 1.0e-14);
CHECK_CLOSE(exc, es2.exceedance(x), 1.0e-14);
}
get_edgeworth_cumulants(es2, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(1.0 - k1*k1, empCum[2], 1.e-14);
CHECK_CLOSE(2*k1*k1*k1 + k3, empCum[3], 1.e-14);
CHECK_CLOSE(-6*k1*k1*k1*k1 - 4*k1*k3, empCum[4], 1.e-14);
EdgeworthSeries1D es3(c_slr, EDGEWORTH_CLASSICAL, order, true);
standard_test(es3, 6, 1.e-8);
invexceedance_test(es3, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = x0 - k1;
const double fact = 1;
const double expfact = exp(-x*x/2)/SQRTWOPIL;
const double dens = expfact*fact;
const double cdffact = 0.0;
const double cdf = ldgcdf(x) - expfact*cdffact;
const double exc = ldgexceedance(x) + expfact*cdffact;
CHECK_CLOSE(cdffact, es3.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es3.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es3.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es3.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es3.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es3, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(1.0, empCum[2], 1.e-14);
CHECK_CLOSE(0.0, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
CHECK_CLOSE(0.0, empCum[5], 1.e-14);
CHECK_CLOSE(0.0, empCum[6], 1.e-14);
CHECK_CLOSE(0.0, empCum[7], 1.e-14);
EdgeworthSeries1D es4(c_gen, EDGEWORTH_CLASSICAL, order, false);
standard_test(es4, 6, 1.e-8);
invexceedance_test(es4, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = x0 - k1;
const double fact = 1 + k3/6.0*he3(x);
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdffact = k3/6.0*he2(x);
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es4.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es4.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es4.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es4.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es4.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es4, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(1.0, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
CHECK_CLOSE(0.0, empCum[5], 1.e-14);
CHECK_CLOSE(-10*k3*k3, empCum[6], 1.e-14);
CHECK_CLOSE(0.0, empCum[7], 1.e-13);
}
TEST(EdgeworthSeries1D_2)
{
const double range = 5.0;
const unsigned ntries = 10;
const unsigned order = 2;
const double k1 = 0.3, k2 = 1.01, k3 = 0.2, k4 = 0.1;
const double k2m1 = k2 - 1.0;
const double sigma = sqrt(k2);
double empCum[10];
std::vector<double> c_slr(2);
c_slr[0] = k1;
c_slr[1] = k2;
std::vector<double> c_gen(4);
c_gen[0] = k1;
c_gen[1] = k2;
c_gen[2] = k3;
c_gen[3] = k4;
EdgeworthSeries1D es1(c_slr, EDGEWORTH_SEVERINI, order, true);
standard_test(es1, 6, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double cdffact = k1 + (k1*k1 + k2m1)/2.0*he1(x);
const double fact = 1 + k1*he1(x) + (k1*k1 + k2m1)/2.0*he2(x);
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es1.cdfFactor(x), 1.0e-14);
CHECK_CLOSE(fact, es1.densityFactor(x), 1.0e-14);
CHECK_CLOSE(dens, es1.density(x), 1.0e-14);
CHECK_CLOSE(cdf, es1.cdf(x), 1.0e-14);
CHECK_CLOSE(exc, es1.exceedance(x), 1.0e-14);
}
get_edgeworth_cumulants(es1, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(-(k1*(k1*k1 + 3*k2m1)), empCum[3], 1.e-14);
CHECK_CLOSE(3*k1*k1*k1*k1 + 6*k1*k1*k2m1 - 3*k2m1*k2m1, empCum[4], 1.e-14);
EdgeworthSeries1D es2(c_gen, EDGEWORTH_SEVERINI, order, false);
standard_test(es2, 6, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double cdffact = (72*k1 + 36*(k1*k1 + k2m1)*he1(x) +
12*k3*he2(x) + 12*k1*k3*he3(x) +
3*k4*he3(x) + k3*k3*he5(x))/72;
const double fact = (72 + 72*k1*he1(x) + 36*(k1*k1 + k2m1)*he2(x) +
12*k3*he3(x) + 12*k1*k3*he4(x) +
3*k4*he4(x) + k3*k3*he6(x))/72;
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es2.cdfFactor(x), 1.0e-12);
CHECK_CLOSE(fact, es2.densityFactor(x), 1.0e-12);
CHECK_CLOSE(dens, es2.density(x), 1.0e-12);
CHECK_CLOSE(cdf, es2.cdf(x), 1.0e-12);
CHECK_CLOSE(exc, es2.exceedance(x), 1.0e-12);
}
get_edgeworth_cumulants(es2, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(-k1*k1*k1 - 3*k1*k2m1 + k3, empCum[3], 1.e-14);
CHECK_CLOSE(3*k1*k1*k1*k1 + 6*k1*k1*k2m1 - 3*k2m1*k2m1 + k4, empCum[4], 1.e-14);
EdgeworthSeries1D es3(c_slr, EDGEWORTH_CLASSICAL, order, true);
standard_test(es3, 6, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = (x0 - k1)/sigma;
const double fact = 1;
const double expfact = exp(-x*x/2)/SQRTWOPIL/sigma;
const double dens = expfact*fact;
const double cdffact = 0.0;
const double cdf = ldgcdf(x) - expfact*cdffact;
const double exc = ldgexceedance(x) + expfact*cdffact;
CHECK_CLOSE(cdffact, es3.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es3.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es3.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es3.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es3.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es3, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-12);
CHECK_CLOSE(k1, empCum[1], 1.e-12);
CHECK_CLOSE(k2, empCum[2], 1.e-12);
CHECK_CLOSE(0.0, empCum[3], 1.e-12);
CHECK_CLOSE(0.0, empCum[4], 1.e-12);
CHECK_CLOSE(0.0, empCum[5], 1.e-12);
CHECK_CLOSE(0.0, empCum[6], 1.e-12);
CHECK_CLOSE(0.0, empCum[7], 1.e-12);
EdgeworthSeries1D es4(c_gen, EDGEWORTH_CLASSICAL, order, false);
standard_test(es4, 6, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = (x0 - k1)/sigma;
const double cdffact = k3*he2(x)/6/sigma/sigma +
k4*he3(x)/24/pow(sigma,3) + k3*k3*he5(x)/72/pow(sigma,5);
const double fact = 1 + (k3*he3(x)/6/sigma/sigma +
k4*he4(x)/24/pow(sigma,3) + k3*k3*he6(x)/72/pow(sigma,5))/sigma;
const double dens = exp(-x*x/2)/SQRTWOPIL/sigma*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL/sigma*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL/sigma*cdffact;
CHECK_CLOSE(cdffact, es4.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es4.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es4.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es4.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es4.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es4, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(k4, empCum[4], 1.e-14);
CHECK_CLOSE(0.0, empCum[5], 1.e-14);
CHECK_CLOSE(0.0, empCum[6], 1.e-13);
CHECK_CLOSE(-35*k3*k4, empCum[7], 1.e-13);
}
TEST(EdgeworthSeries1D_3)
{
const double range = 5.0;
const unsigned ntries = 10;
const unsigned order = 3;
double k1 = 0.3, k2 = 1.01, k3 = 0.2, k4 = 0.1, k5 = 0.015;
double k2m1 = k2 - 1.0;
const double sigma = sqrt(k2);
double empCum[10];
std::vector<double> c_slr(3);
c_slr[0] = k1;
c_slr[1] = k2;
c_slr[2] = k3;
std::vector<double> c_gen(5);
c_gen[0] = k1;
c_gen[1] = k2;
c_gen[2] = k3;
c_gen[3] = k4;
c_gen[4] = k5;
EdgeworthSeries1D es1(c_slr, EDGEWORTH_SEVERINI, order, true);
standard_test(es1, 3, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double cdffact = k1 + (k1*k1*he1(x))/2 + (k2m1*he1(x))/2 + (k1*k1*k1*he2(x))/6 +
(k1*k2m1*he2(x))/2 + (k3*he2(x))/6;
const double fact = 1 + k1*he1(x) + (k1*k1*he2(x))/2 + (k2m1*he2(x))/2 + (k1*k1*k1*he3(x))/6 +
(k1*k2m1*he3(x))/2 + (k3*he3(x))/6;
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es1.cdfFactor(x), 1.0e-14);
CHECK_CLOSE(fact, es1.densityFactor(x), 1.0e-14);
CHECK_CLOSE(dens, es1.density(x), 1.0e-14);
CHECK_CLOSE(cdf, es1.cdf(x), 1.0e-14);
CHECK_CLOSE(exc, es1.exceedance(x), 1.0e-14);
}
get_edgeworth_cumulants(es1, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(-k1*k1*k1*k1 - 6*k1*k1*k2m1 - 3*k2m1*k2m1 - 4*k1*k3, empCum[4], 1.e-14);
EdgeworthSeries1D es2(c_gen, EDGEWORTH_SEVERINI, order, false);
standard_test(es2, 3, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double cdffact = k1 + (k1*k1*he1(x))/2 + (k2m1*he1(x))/2 + (k1*k1*k1*he2(x))/6 +
(k1*k2m1*he2(x))/2 + (k3*he2(x))/6 + (k1*k3*he3(x))/6 +
(k4*he3(x))/24 + (k1*k1*k3*he4(x))/12 + (k2m1*k3*he4(x))/12 +
(k1*k4*he4(x))/24 + (k5*he4(x))/120 + (k3*k3*he5(x))/72 +
(k1*k3*k3*he6(x))/72 + (k3*k4*he6(x))/144 + (k3*k3*k3*he8(x))/1296;
const double fact = 1 + k1*he1(x) + (k1*k1*he2(x))/2 + (k2m1*he2(x))/2 + (k1*k1*k1*he3(x))/6 +
(k1*k2m1*he3(x))/2 + (k3*he3(x))/6 + (k1*k3*he4(x))/6 +
(k4*he4(x))/24 + (k1*k1*k3*he5(x))/12 + (k2m1*k3*he5(x))/12 +
(k1*k4*he5(x))/24 + (k5*he5(x))/120 + (k3*k3*he6(x))/72 +
(k1*k3*k3*he7(x))/72 + (k3*k4*he7(x))/144 + (k3*k3*k3*he9(x))/1296;
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es2.cdfFactor(x), 1.0e-12);
CHECK_CLOSE(fact, es2.densityFactor(x), 1.0e-12);
CHECK_CLOSE(dens, es2.density(x), 1.0e-12);
CHECK_CLOSE(cdf, es2.cdf(x), 1.0e-12);
CHECK_CLOSE(exc, es2.exceedance(x), 1.0e-12);
}
get_edgeworth_cumulants(es2, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(-k1*k1*k1*k1 - 6*k1*k1*k2m1 - 3*k2m1*k2m1 + k4, empCum[4], 1.e-14);
EdgeworthSeries1D es3(c_slr, EDGEWORTH_CLASSICAL, order, true);
standard_test(es3, 3, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = (x0 - k1)/sigma;
const double cdffact = (k3/6)*he2(x)/sigma/sigma;
const double fact = 1 + (k3/6)*he3(x)/sigma/sigma/sigma;
const double expfact = exp(-x*x/2)/SQRTWOPIL/sigma;
const double dens = expfact*fact;
const double cdf = ldgcdf(x) - expfact*cdffact;
const double exc = ldgexceedance(x) + expfact*cdffact;
CHECK_CLOSE(cdffact, es3.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es3.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es3.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es3.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es3.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es3, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(0.0, empCum[4], 1.e-14);
CHECK_CLOSE(0.0, empCum[5], 1.e-14);
CHECK_CLOSE(-10*k3*k3, empCum[6], 1.e-14);
CHECK_CLOSE(0.0, empCum[7], 1.e-14);
EdgeworthSeries1D es4(c_gen, EDGEWORTH_CLASSICAL, order, false);
standard_test(es4, 3, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = (x0 - k1)/sigma;
const double k1orig = k1;
const double k2m1orig = k2m1;
k1 = 0.0;
k2m1 = 0.0;
const double cdffact = (k1*k1*k1*he2(x)/powl(sigma,2))/6 +
(k1*k2m1*he2(x)/powl(sigma,2))/2 + (k3*he2(x)/powl(sigma,2))/6 + (k1*k3*he3(x)/powl(sigma,3))/6 +
(k4*he3(x)/powl(sigma,3))/24 + (k1*k1*k3*he4(x)/powl(sigma,4))/12 + (k2m1*k3*he4(x)/powl(sigma,4))/12 +
(k1*k4*he4(x)/powl(sigma,4))/24 + (k5*he4(x)/powl(sigma,4))/120 + (k3*k3*he5(x)/powl(sigma,5))/72 +
(k1*k3*k3*he6(x)/powl(sigma,6))/72 + (k3*k4*he6(x)/powl(sigma,6))/144 + (k3*k3*k3*he8(x)/powl(sigma,8))/1296;
const double fact = 1 + (k1*k1*k1*he3(x)/powl(sigma,3))/6 +
(k1*k2m1*he3(x)/powl(sigma,3))/2 + (k3*he3(x)/powl(sigma,3))/6 + (k1*k3*he4(x)/powl(sigma,4))/6 +
(k4*he4(x)/powl(sigma,4))/24 + (k1*k1*k3*he5(x)/powl(sigma,5))/12 + (k2m1*k3*he5(x)/powl(sigma,5))/12 +
(k1*k4*he5(x)/powl(sigma,5))/24 + (k5*he5(x)/powl(sigma,5))/120 + (k3*k3*he6(x)/powl(sigma,6))/72 +
(k1*k3*k3*he7(x)/powl(sigma,7))/72 + (k3*k4*he7(x)/powl(sigma,7))/144 + (k3*k3*k3*he9(x)/powl(sigma,9))/1296;
k1 = k1orig;
k2m1 = k2m1orig;
const double dens = exp(-x*x/2)/SQRTWOPIL/sigma*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL/sigma*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL/sigma*cdffact;
CHECK_CLOSE(cdffact, es4.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es4.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es4.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es4.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es4.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es4, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(k4, empCum[4], 1.e-14);
CHECK_CLOSE(k5, empCum[5], 1.e-14);
CHECK_CLOSE(0.0, empCum[6], 1.e-13);
CHECK_CLOSE(0.0, empCum[7], 1.e-13);
}
TEST(EdgeworthSeries1D_4)
{
const double range = 5;
const unsigned ntries = 10;
const unsigned order = 4;
double k1 = 0.3, k2 = 1.01, k3 = 0.2, k4 = 0.1, k5 = 0.015, k6 = 0.07;
double k2m1 = k2 - 1.0;
const double sigma = sqrt(k2);
double empCum[10];
std::vector<double> c_slr(4);
c_slr[0] = k1;
c_slr[1] = k2;
c_slr[2] = k3;
c_slr[3] = k4;
std::vector<double> c_gen(6);
c_gen[0] = k1;
c_gen[1] = k2;
c_gen[2] = k3;
c_gen[3] = k4;
c_gen[4] = k5;
c_gen[5] = k6;
EdgeworthSeries1D es1(c_slr, EDGEWORTH_SEVERINI, order, true);
standard_test(es1, 3, 1.e-8);
invexceedance_test(es1, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x = range*(2.0*test_rng()-1.0);
const double cdffact = k1 + (k1*k1*he1(x))/2 + (k2m1*he1(x))/2 + (k1*k1*k1*he2(x))/6 +
(k1*k2m1*he2(x))/2 + (k3*he2(x))/6 +
(k1*k1*k1*k1 + 6*k1*k1*k2m1 + 3*k2m1*k2m1 + 4*k1*k3 + k4)/24*he3(x);
const double fact = 1 + k1*he1(x) + (k1*k1*he2(x))/2 + (k2m1*he2(x))/2 + (k1*k1*k1*he3(x))/6 +
(k1*k2m1*he3(x))/2 + (k3*he3(x))/6 +
(k1*k1*k1*k1 + 6*k1*k1*k2m1 + 3*k2m1*k2m1 + 4*k1*k3 + k4)/24*he4(x);
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, es1.cdfFactor(x), 1.0e-14);
CHECK_CLOSE(fact, es1.densityFactor(x), 1.0e-14);
CHECK_CLOSE(dens, es1.density(x), 1.0e-14);
CHECK_CLOSE(cdf, es1.cdf(x), 1.0e-14);
CHECK_CLOSE(exc, es1.exceedance(x), 1.0e-14);
}
get_edgeworth_cumulants(es1, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(k4, empCum[4], 1.e-14);
CHECK_CLOSE(-pow(k1,5) - 10*k1*k1*k1*k2m1 - 15*k1*k2m1*k2m1 - 10*k1*k1*k3 - 10*k2m1*k3 - 5*k1*k4, empCum[5], 1.e-14);
EdgeworthSeries1D es2(c_gen, EDGEWORTH_SEVERINI, order, false);
standard_test(es2, 3, 1.e-8);
invexceedance_test(es2, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
double coeffs[13];
const double x = range*(2.0*test_rng()-1.0);
coeffs[0] = 1.0;
coeffs[1] = k1;
coeffs[2] = (k1*k1 + k2m1)/2;
coeffs[3] = (k1*k1*k1 + 3*k1*k2m1 + k3)/6;
coeffs[4] = (k1*k1*k1*k1 + 6*k1*k1*k2m1 + 3*k2m1*k2m1 + 4*k1*k3 + k4)/24;
coeffs[5] = (10*k1*k1*k3 + 10*k2m1*k3 + 5*k1*k4 + k5)/120;
coeffs[6] = (20*k1*k1*k1*k3 + 10*k3*k3 + 15*k1*k1*k4 + 15*k2m1*k4 + 6*k1*(10*k2m1*k3 + k5) + k6)/720;
coeffs[7] = (k3*(2*k1*k3 + k4))/144;
coeffs[8] = (40*k1*k1*k3*k3 + 40*k2m1*k3*k3 + 40*k1*k3*k4 + 5*k4*k4 + 8*k3*k5)/5760;
coeffs[9] = k3*k3*k3/1296;
coeffs[10] = (k3*k3*(4*k1*k3 + 3*k4))/5184;
coeffs[11] = 0.0;
coeffs[12] = k3*k3*k3*k3/31104;
const double fact = hermiteSeriesSumProb(coeffs, 12, x);
const double cdffact = hermiteSeriesSumProb(coeffs+1, 11, x);
const double cdffactAlt = k1*he0(x) +
(k1*k1 + k2m1)/2*he1(x) +
(k1*k1*k1 + 3*k1*k2m1 + k3)/6*he2(x) +
(k1*k1*k1*k1 + 6*k1*k1*k2m1 + 3*k2m1*k2m1 + 4*k1*k3 + k4)/24*he3(x) +
(10*k1*k1*k3 + 10*k2m1*k3 + 5*k1*k4 + k5)/120*he4(x) +
(20*k1*k1*k1*k3 + 10*k3*k3 + 15*k1*k1*k4 + 15*k2m1*k4 + 6*k1*(10*k2m1*k3 + k5) + k6)/720*he5(x) +
(k3*(2*k1*k3 + k4))/144*he6(x) +
(40*k1*k1*k3*k3 + 40*k2m1*k3*k3 + 40*k1*k3*k4 + 5*k4*k4 + 8*k3*k5)/5760*he7(x) +
k3*k3*k3/1296*he8(x) +
(k3*k3*(4*k1*k3 + 3*k4))/5184*he9(x) +
k3*k3*k3*k3/31104*he11(x);
const double factAlt = 1 + k1*he1(x) +
(k1*k1 + k2m1)/2*he2(x) +
(k1*k1*k1 + 3*k1*k2m1 + k3)/6*he3(x) +
(k1*k1*k1*k1 + 6*k1*k1*k2m1 + 3*k2m1*k2m1 + 4*k1*k3 + k4)/24*he4(x) +
(10*k1*k1*k3 + 10*k2m1*k3 + 5*k1*k4 + k5)/120*he5(x) +
(20*k1*k1*k1*k3 + 10*k3*k3 + 15*k1*k1*k4 + 15*k2m1*k4 + 6*k1*(10*k2m1*k3 + k5) + k6)/720*he6(x) +
(k3*(2*k1*k3 + k4))/144*he7(x) +
(40*k1*k1*k3*k3 + 40*k2m1*k3*k3 + 40*k1*k3*k4 + 5*k4*k4 + 8*k3*k5)/5760*he8(x) +
k3*k3*k3/1296*he9(x) +
(k3*k3*(4*k1*k3 + 3*k4))/5184*he10(x) +
k3*k3*k3*k3/31104*he12(x);
const double dens = exp(-x*x/2)/SQRTWOPIL*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL*cdffact;
CHECK_CLOSE(cdffact, cdffactAlt, 1.0e-12);
CHECK_CLOSE(fact, factAlt, 1.0e-12);
CHECK_CLOSE(cdffact, es2.cdfFactor(x), 1.0e-12);
CHECK_CLOSE(fact, es2.densityFactor(x), 1.0e-12);
CHECK_CLOSE(dens, es2.density(x), 1.0e-12);
CHECK_CLOSE(cdf, es2.cdf(x), 1.0e-12);
CHECK_CLOSE(exc, es2.exceedance(x), 1.0e-12);
}
get_edgeworth_cumulants(es2, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(k4, empCum[4], 1.e-14);
CHECK_CLOSE(-pow(k1,5) - 10*k1*k1*k1*k2m1 - 15*k1*k2m1*k2m1 + k5, empCum[5], 1.e-14);
CHECK_CLOSE(5*pow(k1,6) + 45*pow(k1,4)*k2m1 + 45*k1*k1*k2m1*k2m1 -
15*k2m1*k2m1*k2m1 + k6, empCum[6], 1.e-14);
EdgeworthSeries1D es3(c_slr, EDGEWORTH_CLASSICAL, order, true);
standard_test(es3, 3, 1.e-8);
invexceedance_test(es3, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = (x0 - k1)/sigma;
const double cdffact = (k3*he2(x)/sigma/sigma)/6 +
(k4)/24*he3(x)/sigma/sigma/sigma;
const double fact = 1 + (k3*he3(x)/sigma/sigma/sigma)/6 +
(k4)/24*he4(x)/sigma/sigma/sigma/sigma;
const double expfact = exp(-x*x/2)/SQRTWOPIL/sigma;
const double dens = expfact*fact;
const double cdf = ldgcdf(x) - expfact*cdffact;
const double exc = ldgexceedance(x) + expfact*cdffact;
CHECK_CLOSE(cdffact, es3.cdfFactor(x0), 1.0e-14);
CHECK_CLOSE(fact, es3.densityFactor(x0), 1.0e-14);
CHECK_CLOSE(dens, es3.density(x0), 1.0e-14);
CHECK_CLOSE(cdf, es3.cdf(x0), 1.0e-14);
CHECK_CLOSE(exc, es3.exceedance(x0), 1.0e-14);
}
get_edgeworth_cumulants(es3, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(k4, empCum[4], 1.e-14);
CHECK_CLOSE(0.0, empCum[5], 1.e-14);
CHECK_CLOSE(-10*k3*k3, empCum[6], 1.e-14);
CHECK_CLOSE(-35*k3*k4, empCum[7], 1.e-14);
EdgeworthSeries1D es4(c_gen, EDGEWORTH_CLASSICAL, order, false);
standard_test(es4, 3, 1.e-8);
invexceedance_test(es4, 1.e-8);
for (unsigned i=0; i<ntries; ++i)
{
const double x0 = range*(2.0*test_rng()-1.0);
const double x = (x0 - k1)/sigma;
const double k1orig = k1;
const double k2m1orig = k2m1;
k1 = 0.0;
k2m1 = 0.0;
double coeffs[13];
coeffs[0] = 0.0;
coeffs[1] = k1;
coeffs[2] = (k1*k1 + k2m1)/2;
coeffs[3] = (k1*k1*k1 + 3*k1*k2m1 + k3)/6;
coeffs[4] = (k1*k1*k1*k1 + 6*k1*k1*k2m1 + 3*k2m1*k2m1 + 4*k1*k3 + k4)/24;
coeffs[5] = (10*k1*k1*k3 + 10*k2m1*k3 + 5*k1*k4 + k5)/120;
coeffs[6] = (20*k1*k1*k1*k3 + 10*k3*k3 + 15*k1*k1*k4 + 15*k2m1*k4 + 6*k1*(10*k2m1*k3 + k5) + k6)/720;
coeffs[7] = (k3*(2*k1*k3 + k4))/144;
coeffs[8] = (40*k1*k1*k3*k3 + 40*k2m1*k3*k3 + 40*k1*k3*k4 + 5*k4*k4 + 8*k3*k5)/5760;
coeffs[9] = k3*k3*k3/1296;
coeffs[10] = (k3*k3*(4*k1*k3 + 3*k4))/5184;
coeffs[11] = 0.0;
coeffs[12] = k3*k3*k3*k3/31104;
k1 = k1orig;
k2m1 = k2m1orig;
for (unsigned i=3; i<13; ++i)
coeffs[i] /= powl(sigma, i-1);
const double cdffact = hermiteSeriesSumProb(coeffs+1, 11, x);
const double fact = 1.0 + hermiteSeriesSumProb(coeffs, 12, x)/sigma;
const double dens = exp(-x*x/2)/SQRTWOPIL/sigma*fact;
const double cdf = ldgcdf(x) - exp(-x*x/2)/SQRTWOPIL/sigma*cdffact;
const double exc = ldgexceedance(x) + exp(-x*x/2)/SQRTWOPIL/sigma*cdffact;
CHECK_CLOSE(cdffact, es4.cdfFactor(x0), 1.0e-12);
CHECK_CLOSE(fact, es4.densityFactor(x0), 1.0e-12);
CHECK_CLOSE(dens, es4.density(x0), 1.0e-12);
CHECK_CLOSE(cdf, es4.cdf(x0), 1.0e-12);
CHECK_CLOSE(exc, es4.exceedance(x0), 1.0e-12);
}
get_edgeworth_cumulants(es4, empCum);
CHECK_CLOSE(0.0, empCum[0], 1.e-14);
CHECK_CLOSE(k1, empCum[1], 1.e-14);
CHECK_CLOSE(k2, empCum[2], 1.e-14);
CHECK_CLOSE(k3, empCum[3], 1.e-14);
CHECK_CLOSE(k4, empCum[4], 1.e-14);
CHECK_CLOSE(k5, empCum[5], 1.e-14);
CHECK_CLOSE(k6, empCum[6], 1.e-13);
CHECK_CLOSE(0.0, empCum[7], 1.e-13);
CHECK_CLOSE(0.0, empCum[8], 1.e-12);
CHECK_CLOSE(-126*k4*k5 - 84*k3*k6, empCum[9], 1.e-10);
}
TEST(EdgeworthSeries1D_5)
{
const double eps = 1.0e-12;
const unsigned ntries = 100;
const unsigned order = 4;
double k1 = 0.3, k2 = 1.01, k3 = 0.2, k4 = 0.1, k5 = 0.015, k6 = 0.07;
std::vector<double> c_gen(6);
c_gen[0] = k1;
c_gen[1] = k2;
c_gen[2] = k3;
c_gen[3] = k4;
c_gen[4] = k5;
c_gen[5] = k6;
EdgeworthSeries1D es1(c_gen, EDGEWORTH_CLASSICAL, order, false);
EdgeworthSeries1DOld es2(c_gen, EDGEWORTH_CLASSICAL, order, false);
for (unsigned i=0; i<ntries; ++i)
{
const double x = -3.0 + 6.0*test_rng();
CHECK_CLOSE(es2.density(x), es1.density(x), eps);
}
}
TEST(Tabulated1D_1)
{
const double data[] = {0, 1, 2, 3, 3, 0};
const double location = 1.7;
const double width = 5.9;
for (unsigned deg = 0; deg<4; ++deg)
{
Tabulated1D t1(location, width,
data, sizeof(data)/sizeof(data[0]), deg);
invcdf_test(t1, 1.e-8);
double in = simpson_integral(DensityFunctor1D(t1), location,
location+width);
CHECK_CLOSE(1.0, in, 1.e-8);
}
}
TEST(Tabulated1D_2)
{
const double data[] = {1};
const double location = 1.7;
const double width = 5.9;
for (unsigned deg = 0; deg<4; ++deg)
{
Tabulated1D t1(location, width,
data, sizeof(data)/sizeof(data[0]), deg);
invcdf_test(t1, 1.e-8);
double in = simpson_integral(DensityFunctor1D(t1), location,
location+width);
CHECK_CLOSE(1.0, in, 1.e-8);
}
}
TEST(QuantileTable1D)
{
const double data[] = {0.2, 0.25, 0.4, 0.5, 0.55};
const double location = 1.0;
const double width = 2.5;
QuantileTable1D qt(location, width, data, sizeof(data)/sizeof(data[0]));
invcdf_test(qt, 1.e-12);
standard_test(qt, 3.5, 5.0e-3);
}
TEST(BinnedDensity1D_1)
{
const double data[] = {0, 1, 3, 3, 3, 0, 8};
const double location = 1.7;
const double width = 5.9;
for (unsigned deg = 0; deg<2; ++deg)
{
BinnedDensity1D t1(location, width,
data, sizeof(data)/sizeof(data[0]), deg);
invcdf_test(t1, 1.e-8);
double in = simpson_integral(DensityFunctor1D(t1), location,
location+width);
CHECK_CLOSE(1.0, in, 1.e-3);
}
}
TEST(BinnedDensity1D_2)
{
const double data[] = {0, 0, 1, 11, 3, 7, 0, 8, 0, 0};
const double location = 0.0;
const double width = 1.0;
const unsigned nquant = 1000;
EquidistantInLinearSpace qs(0.0, 1.0, nquant);
std::vector<double> quantiles(nquant);
arrayQuantiles1D(data, sizeof(data)/sizeof(data[0]), 0.0, 1.0,
&qs[0], &quantiles[0], nquant);
BinnedDensity1D t1(location, width,
data, sizeof(data)/sizeof(data[0]), 0);
for (unsigned i=0; i<nquant; ++i)
CHECK_CLOSE(quantiles[i], t1.quantile(qs[i]), 1.0e-14);
}
TEST(BinnedDensity1D_3)
{
const double data[] = {1};
const double location = 1.7;
const double width = 5.9;
for (unsigned deg = 0; deg<2; ++deg)
{
BinnedDensity1D t1(location, width,
data, sizeof(data)/sizeof(data[0]), deg);
invcdf_test(t1, 1.e-8);
double in = simpson_integral(DensityFunctor1D(t1), location,
location+width);
CHECK_CLOSE(1.0, in, 1.e-3);
}
}
TEST(PolynomialDistro1D_1)
{
const double coeffs[] = {0.2, 0.1};
PolynomialDistro1D pd(-1.0, 2.0, coeffs, sizeof(coeffs)/sizeof(coeffs[0]));
standard_test(pd, 1.0, 1.e-10);
invcdf_test(pd, 1.e-12);
}
TEST(Quadratic1D_1)
{
Quadratic1D q1(-1.0, 2.0, 0.5/2.0, 0.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-12);
}
TEST(Quadratic1D_2)
{
Quadratic1D q1(-1.0, 2.0, 0.5/2.0, 0.2/2.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-12);
}
TEST(Quadratic1D_3)
{
- Quadratic1D q1(10.0, 60.0, 0.16, 0.08);
- CHECK_CLOSE(10.0, q1.quantile(0.0), 1.0e-14);
- CHECK_CLOSE(70.0, q1.quantile(1.0), 1.0e-14);
- CHECK_CLOSE(0.01391555555555556, q1.density(11.0), 1.0e-14);
- CHECK_CLOSE(0.01633333333333333, q1.density(45.0), 1.0e-14);
+ for (unsigned i=0; i<10; ++i)
+ {
+ const double a = (test_rng()-0.5)/10.0;
+ const double b = (test_rng()-0.5)/10.0;
+ Quadratic1D q1(0.0, 1.0, a, b);
+ for (unsigned j=0; j<10; ++j)
+ {
+ const double x = test_rng();
+ const double twoxm1 = 2*x - 1;
+ const double p1 = twoxm1;
+ const double p2 = 0.5*(3.0*twoxm1*twoxm1 - 1.0);
+ const double ref = 1.0 + a*p1 + b*p2;
+ CHECK_CLOSE(ref, q1.density(x), 1.0e-12);
+ }
+ }
}
TEST(LogQuadratic1D_1)
{
LogQuadratic1D q1(-1.0, 2.0, 0.5, 1.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-14);
}
TEST(LogQuadratic1D_2)
{
LogQuadratic1D q1(-1.0, 2.0, 0.5, -1.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-14);
}
TEST(LogQuadratic1D_3)
{
LogQuadratic1D q1(-1.0, 2.0, 0.5, 0.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-14);
}
TEST(LogQuadratic1D_4)
{
LogQuadratic1D q1(-1.0, 2.0, -0.5, 0.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-14);
}
TEST(LogQuadratic1D_5)
{
LogQuadratic1D q1(-1.0, 2.0, 0.0, -10.0/2.0);
standard_test(q1, 1.0, 1.e-10);
invcdf_test(q1, 1.e-14);
}
TEST(LogQuadratic1D_6)
{
LogQuadratic1D q1(-1.0, 2.0, 0.0, 10.0/2.0);
standard_test(q1, 1.0, 1.e-9);
invcdf_test(q1, 1.e-14);
}
+ TEST(LogQuadratic1D_7)
+ {
+ for (unsigned i=0; i<10; ++i)
+ {
+ const double a = (test_rng()-0.5)/10.0;
+ const double b = (test_rng()-0.5)/10.0;
+ LogQuadratic1D q1(0.0, 1.0, a, b);
+
+ GaussLegendreQuadrature glq(1024);
+ const double norm = glq.integrate(DummyFunct(a, b), 0.0, 1.0);
+
+ for (unsigned j=0; j<10; ++j)
+ {
+ const double x = test_rng();
+ const double twoxm1 = 2*x - 1;
+ const double p1 = twoxm1;
+ const double p2 = 0.5*(3.0*twoxm1*twoxm1 - 1.0);
+ const double ref = exp(a*p1 + b*p2)/norm;
+ CHECK_CLOSE(ref, q1.density(x), 1.0e-12);
+ }
+ }
+ }
+
TEST(LogLogQuadratic1D_1)
{
StaticDistribution1DReader::registerClass<LogLogQuadratic1D>();
LogLogQuadratic1D q1(1.0, 10.0, 0.5, 1.0);
standard_test(q1, 1.0, 1.e-9);
invcdf_test(q1, 1.e-14);
}
TEST(GaussianMixture1D_1)
{
std::vector<GaussianMixtureEntry> entries;
entries.push_back(GaussianMixtureEntry(3, 0, 1));
GaussianMixture1D g(0, 1, &entries[0], entries.size());
double value = simpson_integral(DensityFunctor1D(g), -6, 6);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(g, 6, 1.e-7);
Gauss1D g2(0, 1);
DistributionMix1D mix;
mix.add(g2, 3.0);
value = simpson_integral(DensityFunctor1D(mix), -6, 6);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(mix, 6, 1.e-7);
VerticallyInterpolatedDistribution1D shmix(1U);
shmix.add(g2, 3.0);
value = simpson_integral(DensityFunctor1D(shmix), -6, 6);
CHECK_CLOSE(1.0, value, 1.e-8);
standard_test(shmix, 6, 1.e-7, false);
for (unsigned i=0; i<100; ++i)
{
const double r = test_rng();
CHECK_CLOSE(shmix.quantile(r), mix.quantile(r), 1.e-15);
}
}
TEST(GaussianMixture1D_2)
{
for (unsigned i=0; i<100; ++i)
{
Gauss1D g(test_rng(), 0.1+test_rng());
GaussianMixture1D mix(g);
for (unsigned j=0; j<100; ++j)
{
const double x = -3 + 6*test_rng();
CHECK_CLOSE(g.density(x), mix.density(x), 1.0e-15);
CHECK_CLOSE(g.cdf(x), mix.cdf(x), 1.0e-15);
}
}
}
TEST(DistributionMix1D_2)
{
for (unsigned i=0; i<100; ++i)
{
Gauss1D g(test_rng(), 0.1+test_rng());
DistributionMix1D mix;
VerticallyInterpolatedDistribution1D shmix;
mix.add(g, 1);
shmix.add(g, 1);
for (unsigned j=0; j<100; ++j)
{
const double x = -3 + 6*test_rng();
CHECK_CLOSE(g.density(x), mix.density(x), 1.0e-15);
CHECK_CLOSE(g.cdf(x), mix.cdf(x), 1.0e-15);
CHECK_CLOSE(g.density(x), shmix.density(x), 1.0e-15);
CHECK_CLOSE(g.cdf(x), shmix.cdf(x), 1.0e-15);
}
}
}
TEST(GaussianMixture1D_3)
{
std::vector<GaussianMixtureEntry> entries;
entries.push_back(GaussianMixtureEntry(3, 0, 1));
entries.push_back(GaussianMixtureEntry(2, -0.5, 1.5));
entries.push_back(GaussianMixtureEntry(1, 0.5, 0.5));
GaussianMixture1D g(0, 1, &entries[0], entries.size());
double value = simpson_integral(DensityFunctor1D(g), -8, 8);
CHECK_CLOSE(1.0, value, 1.e-7);
standard_test(g, 4, 1.e-7);
}
TEST(DistributionMix1D_3)
{
DistributionMix1D mix;
VerticallyInterpolatedDistribution1D shmix(3);
Gauss1D g1(0, 1), g2(-0.5, 1.5), g3(0.5, 0.5);
mix.add(g1, 3);
mix.add(g2, 2);
mix.add(g3, 1);
shmix.add(g1, 3);
shmix.add(g2, 2);
shmix.add(g3, 1);
double value = simpson_integral(DensityFunctor1D(mix), -8, 8);
CHECK_CLOSE(1.0, value, 1.e-7);
value = simpson_integral(DensityFunctor1D(shmix), -8, 8);
CHECK_CLOSE(1.0, value, 1.e-7);
standard_test(mix, 4, 1.e-7);
standard_test(shmix, 4, 1.e-7, false);
}
TEST(GaussianMixture1D_4)
{
const double m0 = 1.3;
const double s0 = 3/2.0;
std::vector<GaussianMixtureEntry> entries;
entries.push_back(GaussianMixtureEntry(3, 0, 1));
entries.push_back(GaussianMixtureEntry(2, -0.5, 1.5));
entries.push_back(GaussianMixtureEntry(1, 0.5, 0.5));
GaussianMixture1D g(m0, s0, &entries[0], entries.size());
// G[x_, m_, s_] := 1/Sqrt[2 Pi]/s Exp[-(x - m)^2/s^2/2]
// w1 = 3/6; m1 = 0; s1 = 1
// w2 = 2/6; m2 = -1/2; s2 = 3/2
// w3 = 1/6; m3 = 1/2; s3 = 1/2
// m0 = 1 + 3/10
// s0 = 3/2
// f = (w1*G[(x-m0)/s0,m1,s1]+w2*G[(x-m0)/s0,m2,s2]+w3*G[(x-m0)/s0,m3,s3])/s0
// mean = Integrate[x f, {x, -Infinity, Infinity}]
// stdev = Sqrt[Integrate[(x - mean)^2 f, {x, -Infinity, Infinity}]]
// q0 = Integrate[f, {x, -Infinity, 5/2}]
// N[q0, 20]
const double expmean = 47.0/40;
const double expstdev = sqrt(203.0)/8.0;
const double expcdf = 0.78400933536932041748;
CHECK_CLOSE(expmean, g.mean(), 1.0e-15);
CHECK_CLOSE(expstdev, g.stdev(), 1.0e-15);
CHECK_CLOSE(expcdf, g.cdf(2.5), 1.0e-15);
CHECK_CLOSE(2.5, g.quantile(expcdf), 1.0e-12);
}
TEST(LeftCensoredDistribution)
{
const double cutoff = 0.1234;
const double eps = 1.0e-9;
const double infty = -100.0;
Gauss1D gauss(0.0, 1.0);
TruncatedDistribution1D td(gauss, cutoff, 100.0);
const double frac = gauss.exceedance(cutoff);
LeftCensoredDistribution lc(td, frac, infty);
CHECK_CLOSE(lc.cdf(cutoff-1.0), 1.0-frac, eps);
CHECK_CLOSE(lc.exceedance(cutoff-1.0), frac, eps);
CHECK_EQUAL(lc.cdf(infty-10.0), 0.0);
CHECK_EQUAL(lc.exceedance(infty-10.0), 1.0);
for (unsigned i=0; i<1000; ++i)
{
const double r = cutoff + test_rng()*5.0;
CHECK_CLOSE(gauss.density(r), lc.density(r), eps);
CHECK_CLOSE(gauss.exceedance(r), lc.exceedance(r), eps);
CHECK_CLOSE(gauss.cdf(r), lc.cdf(r), eps);
CHECK_CLOSE(lc.quantile(lc.cdf(r)), r, eps);
}
io_test(lc);
}
TEST(RightCensoredDistribution)
{
const double cutoff = 0.1234;
const double eps = 1.0e-10;
const double infty = 100.0;
Gauss1D gauss(0.0, 1.0);
TruncatedDistribution1D td(gauss, -100.0, cutoff);
const double frac = gauss.cdf(cutoff);
RightCensoredDistribution rc(td, frac, infty);
CHECK_CLOSE(rc.cdf(cutoff+1.0), frac, eps);
CHECK_CLOSE(rc.exceedance(cutoff+1.0), 1.0-frac, eps);
CHECK_EQUAL(rc.cdf(infty+10.0), 1.0);
CHECK_EQUAL(rc.exceedance(infty+10.0), 0.0);
for (unsigned i=0; i<1000; ++i)
{
const double r = cutoff - test_rng()*5.0;
CHECK_CLOSE(gauss.density(r), rc.density(r), eps);
CHECK_CLOSE(gauss.exceedance(r), rc.exceedance(r), eps);
CHECK_CLOSE(gauss.cdf(r), rc.cdf(r), eps);
CHECK_CLOSE(rc.quantile(rc.cdf(r)), r, eps);
}
io_test(rc);
}
TEST(RatioOfNormals)
{
RatioOfNormals r1(-2.0, 1.0, 0.5, 1.0, 0.7);
standard_test(r1, 10, 1.e-8);
RatioOfNormals r2(1.0, 3.0, 2.0, 1.0, 0.5);
standard_test(r2, 10, 1.e-7);
const double x = 1.0;
const double cdf = r2.cdf(x);
const double quantile = r2.quantile(cdf);
CHECK_CLOSE(x, quantile, 1.0e-8);
}
TEST(InterpolatedDistro1D1P)
{
const double eps = 1.0e-8;
const double gridPoints[] = {1.0, 2.0};
double param = 1.3;
const unsigned nGridPoints = sizeof(gridPoints)/sizeof(gridPoints[0]);
GridAxis ax(std::vector<double>(gridPoints, gridPoints+nGridPoints));
std::vector<CPP11_shared_ptr<const AbsDistribution1D> > distros;
distros.push_back(CPP11_shared_ptr<const AbsDistribution1D>(new Gauss1D(1.0, 2.0)));
distros.push_back(CPP11_shared_ptr<const AbsDistribution1D>(new Gauss1D(-1.0, 1.0)));
InterpolatedDistro1D1P idist(ax, distros, param);
standard_test(idist, 10.0, 1.e-7);
LinearMapper1d meanmap(gridPoints[0], 1.0, gridPoints[1], -1.0);
LinearMapper1d sigmap(gridPoints[0], 2.0, gridPoints[1], 1.0);
for (unsigned i=0; i<100; ++i)
{
param = 1.0 + test_rng();
idist.setParameter(param);
Gauss1D g(meanmap(param), sigmap(param));
const double r = test_rng();
const double x = g.quantile(r);
CHECK_CLOSE(x, idist.quantile(r), eps);
CHECK_CLOSE(g.density(x), idist.density(x), eps);
CHECK_CLOSE(g.cdf(x), idist.cdf(x), eps);
}
}
TEST(distro1DStats_1)
{
const double eps = 1.0e-7;
for (unsigned i=0; i<100; ++i)
{
const double mean = test_rng();
const double sigma = 0.5 + test_rng();
double m, s, skew, kurt;
distro1DStats(Gauss1D(mean, sigma), -10., 11., 100000,
&m, &s, &skew, &kurt);
CHECK_CLOSE(mean, m, eps);
CHECK_CLOSE(sigma, s, eps);
CHECK_CLOSE(0.0, skew, eps);
CHECK_CLOSE(3.0, kurt, eps);
}
}
TEST(DeltaMixture1D_1)
{
const double eps = 1.0e-12;
const unsigned nPoints = 3;
double coords[nPoints] = {0., 1., 2.};
double weights[nPoints] = {1., 3., 2.};
DeltaMixture1D dmix(5.0, 1.0, coords, weights, nPoints);
io_test(dmix);
CHECK_CLOSE(0.6666666666666666, dmix.cdf(6.0), eps);
CHECK_CLOSE(0.3333333333333333, dmix.exceedance(6.0), eps);
MersenneTwister rng;
int counts[nPoints] = {0};
for (unsigned i=0; i<6000; ++i)
{
double rnd;
dmix.random(rng, &rnd);
CHECK(rnd == 5.0 || rnd == 6.0 || rnd == 7.0);
if (rnd == 5.0)
++counts[0];
if (rnd == 6.0)
++counts[1];
if (rnd == 7.0)
++counts[2];
}
CHECK(std::abs(counts[0] - 1000) < 200);
CHECK(std::abs(counts[2] - 2000) < 300);
CHECK_CLOSE(0.5, dmix.integral(6.0, true, 6.0, true), eps);
CHECK_CLOSE(0.0, dmix.integral(6.0, false, 6.0, false), eps);
CHECK_CLOSE(0.0, dmix.integral(6.0, false, 6.0, true), eps);
CHECK_CLOSE(0.0, dmix.integral(6.0, true, 6.0, false), eps);
CHECK_CLOSE(1.0, dmix.integral(5.0, true, 7.0, true), eps);
CHECK_CLOSE(0.5, dmix.integral(5.0, false, 7.0, false), eps);
CHECK_CLOSE(0.8333333333333334, dmix.integral(5.0, false, 7.0, true), eps);
CHECK_CLOSE(0.6666666666666667, dmix.integral(5.0, true, 7.0, false), eps);
const double expectedMoments[4] = {1.0, 37/6.0, 77/2.0, 1459/6.0};
long double moments[4];
dmix.moments(0, 3, moments);
for (unsigned i=0; i<=3; ++i)
CHECK_CLOSE(expectedMoments[i], moments[i], eps);
const double expectedCMoments[4] = {1.0, 37/6.0, 17/36.0, -2/27.0};
dmix.centralMoments(3, moments);
for (unsigned i=0; i<=3; ++i)
CHECK_CLOSE(expectedCMoments[i], moments[i], eps);
}
TEST(DeltaMixture1D_2)
{
const double eps = 1.0e-12;
const unsigned nPoints = 3;
double coords[nPoints] = {0., 1., 2.};
double weights[nPoints] = {1., 3., 2.};
DeltaMixture1D dmix(5.0, 2.0, coords, weights, nPoints);
io_test(dmix);
CHECK_CLOSE(0.6666666666666666, dmix.cdf(7.0), eps);
CHECK_CLOSE(0.3333333333333333, dmix.exceedance(7.0), eps);
MersenneTwister rng;
int counts[nPoints] = {0};
for (unsigned i=0; i<6000; ++i)
{
double rnd;
dmix.random(rng, &rnd);
CHECK(rnd == 5.0 || rnd == 7.0 || rnd == 9.0);
if (rnd == 5.0)
++counts[0];
if (rnd == 7.0)
++counts[1];
if (rnd == 9.0)
++counts[2];
}
CHECK(std::abs(counts[0] - 1000) < 200);
CHECK(std::abs(counts[2] - 2000) < 300);
CHECK_CLOSE(0.5, dmix.integral(7.0, true, 7.0, true), eps);
CHECK_CLOSE(0.0, dmix.integral(7.0, false, 7.0, false), eps);
CHECK_CLOSE(0.0, dmix.integral(7.0, false, 7.0, true), eps);
CHECK_CLOSE(0.0, dmix.integral(7.0, true, 7.0, false), eps);
CHECK_CLOSE(1.0, dmix.integral(5.0, true, 9.0, true), eps);
CHECK_CLOSE(0.5, dmix.integral(5.0, false, 9.0, false), eps);
CHECK_CLOSE(0.8333333333333334, dmix.integral(5.0, false, 9.0, true), eps);
CHECK_CLOSE(0.6666666666666667, dmix.integral(5.0, true, 9.0, false), eps);
const double expectedMoments[4] = {1.0, 22/3.0, 167/3.0, 1306/3.0};
long double moments[4];
dmix.moments(0, 3, moments);
for (unsigned i=0; i<=3; ++i)
CHECK_CLOSE(expectedMoments[i], moments[i], eps);
const double expectedCMoments[4] = {1.0, 22/3.0, 17/9.0, -16/27.0};
dmix.centralMoments(3, moments);
for (unsigned i=0; i<=3; ++i)
CHECK_CLOSE(expectedCMoments[i], moments[i], eps);
}
TEST(ComparisonDistribution1D)
{
Gauss1D d1(0, 1);
Quadratic1D d2(0.0, 1.0, 0.5, 0.2);
CompositeDistribution1D d3(d2, d1);
ComparisonDistribution1D d4(d3, d1);
for (unsigned i=0; i<100; ++i)
{
const double x = test_rng();
CHECK_CLOSE(d2.density(x), d4.density(x), 1.0e-10);
}
standard_test_01(d2, 1.e-12);
standard_test_01(d4, 1.e-10);
}
TEST(ChiSquare)
{
const double eps = 1.0e-10;
const int n = 7;
const double norm = pow(2.0,-n/2.0)/Gamma(n/2.0);
Gamma1D chisq(0.0, 2.0, n/2.0);
for (unsigned i=0; i<100; ++i)
{
const double x = test_rng()*20;
const double ref = norm*pow(x,n/2.0-1)*exp(-x/2);
CHECK_CLOSE(ref, chisq.density(x), eps);
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Dec 21, 6:22 PM (8 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4023781
Default Alt Text
(201 KB)

Event Timeline