19template <
typename IntType>
22 static_assert(std::is_integral_v<IntType> && std::is_signed_v<IntType>,
23 "Discrete distribution supports only signed integral types");
37 [[nodiscard]]
virtual double P(
const IntType &k)
const {
return std::exp(this->
logP(k)); }
43 [[nodiscard]]
virtual double logP(
const IntType &x)
const = 0;
59 [[nodiscard]] IntType
Mode()
const override;
66 long double ExpectedValue(
const std::function<
double(IntType)> &funPtr, IntType minPoint,
67 IntType maxPoint)
const override;
68 std::complex<double>
CFImpl(
double t)
const override;
77 IntType searchQuantile(
double p,
bool upperTail)
const;
84 [[nodiscard]]
double Hazard(
const IntType &x)
const override;
113 int upperBoundary,
size_t numberOfEstimatedParameters = 0)
const;
124 size_t numberOfEstimatedParameters = 0)
const;
135template <
typename IntType>
138 const size_t size = std::min(x.size(), y.size());
139 for (
size_t i = 0; i != size; ++i)
140 y[i] = this->P(x[i]);
143template <
typename IntType>
146 const size_t size = std::min(x.size(), y.size());
147 for (
size_t i = 0; i != size; ++i)
148 y[i] = this->logP(x[i]);
151template <
typename IntType>
155 IntType x = this->Median();
156 double logProb = this->logP(x), newLogProb = this->logP(x + 1);
157 if (logProb < newLogProb) {
160 logProb = newLogProb;
161 newLogProb = this->logP(x + 1);
162 }
while (logProb < newLogProb);
164 newLogProb = this->logP(x - 1);
165 while (logProb < newLogProb) {
167 logProb = newLogProb;
168 newLogProb = this->logP(x - 1);
174template <
typename IntType>
177 IntType down = initValue, up = down + 1;
178 double fu = this->F(up), fd = this->F(down);
187 fd = this->F(--down);
191 return (fd < p) ? up : down;
194template <
typename IntType>
197 return searchQuantile(p,
false);
200template <
typename IntType>
203 IntType down = initValue, up = down + 1;
204 double su = this->S(up), sd = this->S(down);
213 sd = this->S(--down);
218 return (sd > p) ? up : down;
221template <
typename IntType>
224 return searchQuantile(p,
true);
227template <
typename IntType>
232 static constexpr double slack = 8 * std::numeric_limits<double>::epsilon();
233 auto reached = [
this, p, upperTail](
long long k) {
234 return upperTail ? this->S(
static_cast<IntType
>(k)) <= p * (1 + slack)
235 : this->F(static_cast<IntType>(k)) >= p * (1 - slack);
237 const long long lo = this->MinValue(), hi = this->MaxValue();
238 const bool loBounded = lo >
static_cast<long long>(std::numeric_limits<IntType>::lowest());
242 if (loBounded || !reached(0)) {
243 a = loBounded ? lo - 1 : 0;
246 while (b < hi && !reached(b)) {
249 b = (step > hi - a) ? hi : a + step;
256 while (a > lo && reached(a)) {
259 a = (step > a - lo) ? lo : b - step;
263 long long middle = a + (b - a) / 2;
269 return static_cast<IntType
>(b);
272template <
typename IntType>
274 IntType maxPoint)
const
276 Support suppType = this->SupportType();
277 IntType k = minPoint, upperBoundary = maxPoint;
279 k = std::max(k, this->MinValue());
282 upperBoundary = std::min(upperBoundary, this->MaxValue());
287 double addon = funPtr(k);
289 double prob = this->P(k);
296 }
while (k <= upperBoundary);
300template <
typename IntType>
308 static constexpr long long MAX_TERMS = 1000000;
309 static constexpr double EPSILON = 1e-17;
310 const long long lo = this->MinValue(), hi = this->MaxValue(), start = this->Median();
311 std::complex<long double> sum = 0;
312 auto walk = [&](
long long from,
long long step,
long long end,
bool upper) {
313 const std::complex<double> ratio = std::polar(1.0, step * t);
314 const std::complex<double> w = ratio / (1.0 - ratio);
315 const double damping = std::abs(1.0 - ratio);
316 std::complex<double> zk = std::polar(1.0, t *
static_cast<double>(from));
317 double last[4] = {0, 0, 0, 0};
319 for (
long long terms = 0; (step > 0) ? k <= end : k >= end; k += step, ++terms) {
320 double p = this->P(
static_cast<IntType
>(k));
321 sum += std::complex<long double>(p * zk);
323 if (terms % 64 == 63)
324 zk = std::polar(1.0, t *
static_cast<double>(k + step));
329 if (p == 0.0 && terms > 16)
331 if (terms < 16 || damping == 0.0)
333 double thirdDifference = std::fabs(last[0] - 3 * last[1] + 3 * last[2] - last[3]);
334 double nextTerm = std::pow(std::abs(w), 3) * thirdDifference / damping;
335 bool unbounded = (step > 0) ? end - k > MAX_TERMS : k - end > MAX_TERMS;
336 bool decreasing = last[0] < last[1] && last[1] < last[2] && last[2] < last[3];
337 bool converged = unbounded && decreasing && nextTerm < EPSILON * std::abs(sum);
338 bool powerOfTwo = ((terms + 1) & terms) == 0;
339 bool massGone = powerOfTwo &&
340 (upper ? this->S(
static_cast<IntType
>(k)) : this->F(
static_cast<IntType
>(k - 1))) < EPSILON;
341 if (converged || massGone || terms >= MAX_TERMS)
344 if ((step > 0) ? k > end : k < end)
348 for (
int j = 0; j < 3; ++j)
349 next[j] = ((step > 0) ? k + j * step <= end : k + j * step >= end)
350 ? this->P(
static_cast<IntType
>(k + j * step))
352 std::complex<double> series = next[0] + w * (next[1] - next[0]) + w * w * (next[2] - 2 * next[1] + next[0]);
353 sum += std::complex<long double>(zk * series / (1.0 - ratio));
355 walk(start, 1, hi,
true);
357 walk(start - 1, -1, lo,
false);
358 return std::complex<double>(sum);
361template <
typename IntType>
364 if (x < this->MinValue())
366 if (x > this->MaxValue())
368 return this->P(x) / this->S(x);
371template <
typename IntType>
374 long double res = 1.0;
375 for (
const IntType &var : sample)
380template <
typename IntType>
383 long double res = 0.0;
384 for (
const IntType &var : sample)
385 res += this->logP(var);
389template <
typename IntType>
391 int lowerBoundary,
int upperBoundary,
392 size_t numberOfEstimatedParameters)
const
394 const size_t n = orderStatistic.size();
398 throw std::invalid_argument(
"Order statistic should not be empty");
399 if (!(alpha > 0 && alpha < 1))
400 throw std::invalid_argument(
"Significance level should be positive and smaller than 1");
401 if (lowerBoundary >= upperBoundary)
402 throw std::invalid_argument(
"Lower boundary should be smaller than upper one");
403 for (
size_t j = 1; j != n; ++j) {
404 if (orderStatistic[j] < orderStatistic[j - 1])
405 throw std::invalid_argument(
"Order statistic should be sorted in ascending order");
407 if (orderStatistic[0] < this->MinValue())
408 throw std::invalid_argument(
409 "Some elements in the sample are too small to belong to this distribution, they should be greater than " +
410 this->toStringWithPrecision(this->MinValue()));
411 if (orderStatistic[n - 1] > this->MaxValue())
412 throw std::invalid_argument(
413 "Some elements in the sample are too large to belong to this distribution, they should be smaller than " +
414 this->toStringWithPrecision(this->MaxValue()));
420 const long long minValue = this->MinValue(), maxValue = this->MaxValue();
421 const long long lower = (lowerBoundary > minValue) ? lowerBoundary : orderStatistic[0] - 1LL;
422 const long long upper = (upperBoundary < maxValue) ? upperBoundary : orderStatistic[n - 1];
423 const double nInv = 1.0 / n;
426 auto addCell = [&sum, &k, nInv](
size_t count,
double expectedProb) {
427 if (!(expectedProb > 0)) {
432 double addon = nInv * count - expectedProb;
433 sum += addon * addon / expectedProb;
438 if (lower >= minValue) {
439 i = std::upper_bound(orderStatistic.begin(), orderStatistic.end(), lower) - orderStatistic.begin();
440 addCell(i, this->F(
static_cast<IntType
>(lower)));
442 double observedMass = 0;
443 long long distinct = 0;
444 while (i < n && orderStatistic[i] <= upper) {
445 const IntType x = orderStatistic[i];
447 for (; i < n && orderStatistic[i] == x; ++i)
449 const double probability = this->P(x);
450 observedMass += probability;
452 addCell(count, probability);
454 const long long unobserved = upper - lower - distinct;
455 if (unobserved > 0) {
456 const double cellMass =
457 this->F(
static_cast<IntType
>(upper)) - ((lower >= minValue) ? this->F(
static_cast<IntType
>(lower)) : 0.0);
458 sum += std::max(cellMass - observedMass, 0.0);
459 k +=
static_cast<size_t>(unobserved);
461 if (upper < maxValue)
462 addCell(n - i, this->S(
static_cast<IntType
>(upper)));
464 if (k <= numberOfEstimatedParameters + 1) {
465 throw std::invalid_argument(
"Sample is too small, number of groups (" + this->toStringWithPrecision(k) +
466 ") should be bigger than number of estimated parameters plus 1 (" +
467 this->toStringWithPrecision(numberOfEstimatedParameters + 1) +
")");
469 double statistic = n * sum;
472 return statistic <= q;
475template <
typename IntType>
477 size_t numberOfEstimatedParameters)
const
479 return PearsonChiSquaredTest(orderStatistic, alpha, this->MinValue(), this->MaxValue(),
480 numberOfEstimatedParameters);
The ChiSquaredRand class Chi-squared distribution.
Definition continuous/gamma.hpp:355
The DiscreteDistribution class Abstract class for all discrete distributions.
Definition discrete.hpp:21
DiscreteDistribution()
Definition discrete.hpp:26
IntType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition discrete.hpp:152
double LogLikelihoodFunction(std::span< const IntType > sample) const override
Definition discrete.hpp:381
double Hazard(const IntType &x) const override
Definition discrete.hpp:362
long double ExpectedValue(const std::function< double(IntType)> &funPtr, IntType minPoint, IntType maxPoint) const override
Definition discrete.hpp:273
void ProbabilityMassFunction(std::span< const IntType > x, std::span< double > y) const
fill vector y with P(x)
Definition discrete.hpp:136
std::complex< double > CFImpl(double t) const override
Definition discrete.hpp:301
virtual ~DiscreteDistribution()
Definition discrete.hpp:29
IntType quantileImpl1m(double p) const override
Definition discrete.hpp:222
IntType quantileImpl1m(double p, IntType initValue) const override
Definition discrete.hpp:201
double LikelihoodFunction(std::span< const IntType > sample) const override
Definition discrete.hpp:372
bool PearsonChiSquaredTest(std::span< const IntType > orderStatistic, double alpha, int lowerBoundary, int upperBoundary, size_t numberOfEstimatedParameters=0) const
Definition discrete.hpp:390
virtual double logP(const IntType &x) const =0
bool PearsonChiSquaredTest(std::span< const IntType > orderStatistic, double alpha, size_t numberOfEstimatedParameters=0) const
Definition discrete.hpp:476
void LogProbabilityMassFunction(std::span< const IntType > x, std::span< double > y) const
fill vector y with logP(x)
Definition discrete.hpp:144
IntType quantileImpl(double p, IntType initValue) const override
Definition discrete.hpp:175
IntType quantileImpl(double p) const override
Definition discrete.hpp:195
virtual double P(const IntType &k) const
Definition discrete.hpp:37
virtual void sample(detail::EngineRef g, std::span< T > outputData) const
Fills the output with variate(g); distributions with a faster bulk algorithm override it.
Definition distribution.hpp:66
The UnivariateDistribution class Abstract class for all univariate probability distributions.
Definition univariate.hpp:28
T Quantile1m(double p) const
Definition univariate.hpp:324
constexpr long double minimumTolerance
Definition constants.hpp:44
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15