RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
univariate.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
9
10namespace randlib
11{
12
14enum class Support
15{
16 Finite,
20};
21
26template <typename T>
28{
29protected:
31
32public:
34
35protected:
36public:
40 [[nodiscard]] virtual Support SupportType() const = 0;
41
45 [[nodiscard]] bool isLeftBounded() const;
46
50 [[nodiscard]] bool isRightBounded() const;
51
55 [[nodiscard]] virtual long double Mean() const = 0;
56
60 [[nodiscard]] virtual long double Variance() const = 0;
61
62private:
68 virtual T quantileImpl(double p, T initValue) const = 0;
69 virtual T quantileImpl(double p) const = 0;
70
76 virtual T quantileImpl1m(double p, T initValue) const = 0;
77 virtual T quantileImpl1m(double p) const = 0;
78
79protected:
84 virtual std::complex<double> CFImpl(double t) const;
85
92 virtual long double ExpectedValue(const std::function<double(T)> &funPtr, T minPoint, T maxPoint) const = 0;
93
94public:
99 [[nodiscard]] T Quantile(double p) const;
100
105 [[nodiscard]] T Quantile1m(double p) const;
106
112 void QuantileFunction(std::span<const double> p, std::span<T> y) const;
113
119 void QuantileFunction1m(std::span<const double> p, std::span<T> y) const;
120
125 [[nodiscard]] std::complex<double> CF(double t) const;
126
131 void CharacteristicFunction(std::span<const double> t, std::span<std::complex<double>> y) const;
132
137 [[nodiscard]] virtual double Hazard(const T &x) const = 0;
138
143 void HazardFunction(std::span<const T> x, std::span<double> y) const;
144
148 [[nodiscard]] virtual T Median() const;
149
156 [[nodiscard]] virtual T Mode() const = 0;
157
162 [[nodiscard]] virtual long double Skewness() const;
163
167 virtual long double Kurtosis() const;
168
173 [[nodiscard]] virtual long double ExcessKurtosis() const;
174
178 [[nodiscard]] virtual long double SecondMoment() const;
179
183 [[nodiscard]] virtual long double ThirdMoment() const;
184
188 [[nodiscard]] virtual long double FourthMoment() const;
189
194 [[nodiscard]] virtual double LikelihoodFunction(std::span<const T> sample) const = 0;
195
200 [[nodiscard]] virtual double LogLikelihoodFunction(std::span<const T> sample) const = 0;
201
202protected:
208 static bool allElementsAreNotGreaterThan(T value, std::span<const T> sample);
209
215 static bool allElementsAreNotSmallerThan(T value, std::span<const T> sample);
216
221 static bool allElementsAreNonNegative(std::span<const T> sample);
222
227 static bool allElementsArePositive(std::span<const T> sample);
228
229public:
234 [[nodiscard]] static long double GetSampleSum(std::span<const T> sample);
235
240 [[nodiscard]] static long double GetSampleMean(std::span<const T> sample);
241
246 [[nodiscard]] static long double GetSampleLogMean(std::span<const T> sample);
247
253 [[nodiscard]] static long double GetSampleVariance(std::span<const T> sample, double mean);
254
260 [[nodiscard]] static long double GetSampleLogVariance(std::span<const T> sample, double logMean);
261
266 [[nodiscard]] static LongDoublePair GetSampleMeanAndVariance(std::span<const T> sample);
267
272 [[nodiscard]] static LongDoublePair GetSampleLogMeanAndVariance(std::span<const T> sample);
273
278 [[nodiscard]] static std::tuple<long double, long double, long double, long double>
279 GetSampleStatistics(std::span<const T> sample);
280};
281
282} // namespace randlib
283
284namespace randlib
285{
286
287template <typename T>
291
292template <typename T>
294{
295 Support supp = this->SupportType();
296 return (supp == Support::RightSemiFinite || supp == Support::Finite);
297}
298
299template <typename T>
301{
302 Support supp = this->SupportType();
303 return (supp == Support::LeftSemiFinite || supp == Support::Finite);
304}
305
306template <typename T>
308{
309 if (!(p >= 0.0 && p <= 1.0))
310 throw std::invalid_argument("Probability p in quantile function should be in interval [0, 1]");
311 double minVal = this->MinValue();
312 if (p == 0.0)
313 return minVal;
314 double maxVal = this->MaxValue();
315 if (p == 1.0)
316 return maxVal;
317 double x = this->quantileImpl(p);
318 if (x < minVal)
319 return minVal;
320 return (x > maxVal) ? maxVal : x;
321}
322
323template <typename T>
325{
326 if (!(p >= 0.0 && p <= 1.0))
327 throw std::invalid_argument("Probability p in quantile function should be in interval [0, 1]");
328 double minVal = this->MinValue();
329 if (p == 1.0)
330 return minVal;
331 double maxVal = this->MaxValue();
332 if (p == 0.0)
333 return maxVal;
334 double x = this->quantileImpl1m(p);
335 if (x < minVal)
336 return minVal;
337 return (x > maxVal) ? maxVal : x;
338}
339
340template <typename T>
341void UnivariateDistribution<T>::QuantileFunction(std::span<const double> p, std::span<T> y) const
342{
343 const size_t size = std::min(p.size(), y.size());
344 for (size_t i = 0; i != size; ++i)
345 y[i] = this->Quantile(p[i]);
346}
347
348template <typename T>
349void UnivariateDistribution<T>::QuantileFunction1m(std::span<const double> p, std::span<T> y) const
350{
351 const size_t size = std::min(p.size(), y.size());
352 for (size_t i = 0; i != size; ++i)
353 y[i] = this->Quantile1m(p[i]);
354}
355
356template <typename T>
357std::complex<double> UnivariateDistribution<T>::CF(double t) const
358{
359 if (t == 0.0)
360 return 1.0;
361 return (t > 0.0) ? this->CFImpl(t) : std::conj(this->CFImpl(-t));
362}
363
364template <typename T>
365std::complex<double> UnivariateDistribution<T>::CFImpl(double t) const
366{
367 T leftBound = this->MinValue(), rightBound = this->MaxValue();
368 if (leftBound == rightBound)
369 return std::complex<double>(std::cos(t * leftBound), std::sin(t * leftBound));
370
371 double re = this->ExpectedValue([t](double x) { return std::cos(t * x); }, leftBound, rightBound);
372
373 double im = this->ExpectedValue([t](double x) { return std::sin(t * x); }, leftBound, rightBound);
374
375 return std::complex<double>(re, im);
376}
377
378template <typename T>
380 std::span<std::complex<double>> y) const
381{
382 const size_t size = std::min(t.size(), y.size());
383 for (size_t i = 0; i != size; ++i)
384 y[i] = this->CF(t[i]);
385}
386
387template <typename T>
388void UnivariateDistribution<T>::HazardFunction(std::span<const T> x, std::span<double> y) const
389{
390 const size_t size = std::min(x.size(), y.size());
391 for (size_t i = 0; i != size; ++i)
392 y[i] = this->Hazard(x[i]);
393}
394
395template <typename T>
397{
398 return quantileImpl(0.5);
399}
400
401template <typename T>
403{
404 long double var = this->Variance();
405 if (!std::isfinite(var))
406 return NAN;
407 long double mu = this->Mean();
408
409 long double sum = this->ExpectedValue(
410 [mu](double x) {
411 double xmmu = x - mu;
412 double skewness = xmmu * xmmu * xmmu;
413 return skewness;
414 },
415 this->MinValue(), this->MaxValue());
416
417 return sum / std::pow(var, 1.5);
418}
419
420template <typename T>
422{
423 long double var = this->Variance();
424 if (!std::isfinite(var))
425 return NAN;
426 long double mu = this->Mean();
427
428 long double sum = this->ExpectedValue(
429 [mu](double x) {
430 double xmmu = x - mu;
431 double kurtosisSqrt = xmmu * xmmu;
432 double kurtosis = kurtosisSqrt * kurtosisSqrt;
433 return kurtosis;
434 },
435 this->MinValue(), this->MaxValue());
436
437 return sum / (var * var) - 3;
438}
439
440template <typename T>
442{
443 return this->ExcessKurtosis() + 3.0;
444}
445
446template <typename T>
448{
449 long double mean = this->Mean();
450 return mean * mean + this->Variance();
451}
452
453template <typename T>
455{
456 long double mean = this->Mean();
457 long double variance = this->Variance();
458 long double skewness = this->Skewness();
459
460 long double moment = skewness * std::sqrt(variance) * variance;
461 moment += mean * mean * mean;
462 moment += 3 * mean * variance;
463 return moment;
464}
465
466template <typename T>
468{
469 long double mean = this->Mean();
470 long double variance = this->Variance();
471 long double moment3 = this->ThirdMoment();
472 long double kurtosis = this->Kurtosis();
473 long double meanSq = mean * mean;
474
475 long double moment = kurtosis * variance * variance;
476 moment -= 6 * meanSq * variance;
477 moment -= 3 * meanSq * meanSq;
478 moment += 4 * mean * moment3;
479 return moment;
480}
481
482template <typename T>
483bool UnivariateDistribution<T>::allElementsAreNotGreaterThan(T value, std::span<const T> sample)
484{
485 for (const T &var : sample) {
486 if (var > value)
487 return false;
488 }
489 return true;
490}
491
492template <typename T>
493bool UnivariateDistribution<T>::allElementsAreNotSmallerThan(T value, std::span<const T> sample)
494{
495 for (const T &var : sample) {
496 if (var < value)
497 return false;
498 }
499 return true;
500}
501
502template <typename T>
504{
505 return allElementsAreNotSmallerThan(0, sample);
506}
507
508template <typename T>
510{
511 for (const T &var : sample) {
512 if (var <= 0)
513 return false;
514 }
515 return true;
516}
517
518template <typename T>
519long double UnivariateDistribution<T>::GetSampleSum(std::span<const T> sample)
520{
521 return std::accumulate(sample.begin(), sample.end(), 0.0);
522}
523
524template <typename T>
525long double UnivariateDistribution<T>::GetSampleMean(std::span<const T> sample)
526{
527 size_t n = sample.size();
528 return (n > 0) ? GetSampleSum(sample) / n : 0.0;
529}
530
531template <typename T>
532long double UnivariateDistribution<T>::GetSampleLogMean(std::span<const T> sample)
533{
534 long double sum = 0.0;
535 for (const T &var : sample)
536 sum += std::log(var);
537 return sum / sample.size();
538}
539
540template <typename T>
541long double UnivariateDistribution<T>::GetSampleVariance(std::span<const T> sample, double mean)
542{
543 long double sum = 0.0l;
544 for (const T &var : sample) {
545 double temp = var - mean;
546 sum += temp * temp;
547 }
548 return sum / sample.size();
549}
550
551template <typename T>
552long double UnivariateDistribution<T>::GetSampleLogVariance(std::span<const T> sample, double logMean)
553{
554 long double sum = 0.0l;
555 for (const T &var : sample) {
556 double temp = std::log(var) - logMean;
557 sum += temp * temp;
558 }
559 return sum / sample.size();
560}
561
562template <typename T>
564{
566 long double m = 0.0l, v = 0.0l;
567 int n = sample.size();
568 for (int i = 0; i < n; ++i) {
569 double x = sample[i];
570 double diff = x - m;
571 m += diff / (i + 1);
572 v += diff * (x - m);
573 }
574 return std::make_pair(m, v / n);
575}
576
577template <typename T>
579{
581 long double m = 0.0l, v = 0.0l;
582 int n = sample.size();
583 for (int i = 0; i < n; ++i) {
584 double logX = std::log(sample[i]);
585 double diff = logX - m;
586 m += diff / (i + 1);
587 v += diff * (logX - m);
588 }
589 return std::make_pair(m, v / n);
590}
591
592template <typename T>
593std::tuple<long double, long double, long double, long double>
595{
597 long double M1{}, M2{}, M3{}, M4{};
598 long double m1{}, m2{}, m3{}, m4{};
599 size_t n = sample.size(), k = 0;
600 size_t t = 0;
601 static constexpr size_t BIG_NUMBER = 10000;
602 for (const T &var : sample) {
603 ++k;
604 long double delta = var - m1;
605 long double delta_k = delta / k;
606 long double delta_kSq = delta_k * delta_k;
607 long double term1 = delta * delta_k * (k - 1);
608 m1 += delta_k;
609 m4 += term1 * delta_kSq * (k * k - 3 * k + 3) + 6 * delta_kSq * m2 - 4 * delta_k * m3;
610 m3 += term1 * delta_k * (k - 2) - 3 * delta_k * m2;
611 m2 += term1;
612
616 if (k >= BIG_NUMBER) {
617 long double Delta = m1 - M1;
618 long double DeltaSq = Delta * Delta;
619 size_t tp1 = t + 1;
621 M4 += m4 + (DeltaSq * DeltaSq * t * (t * t - t + 1) * BIG_NUMBER) / (tp1 * tp1 * tp1);
622 M4 += 6 * DeltaSq * (t * t * m2 + M2) / (tp1 * tp1);
623 M4 += 4 * Delta * (t * m3 - M3) / tp1;
625 M3 += m3 + (DeltaSq * Delta * t * (t - 1) * BIG_NUMBER) / (tp1 * tp1);
626 M3 += 3 * Delta * (t * m2 - M2) / tp1;
628 M2 += m2 + (DeltaSq * t * BIG_NUMBER) / tp1;
629 M1 += Delta / tp1;
630 k = 0;
631 m1 = 0;
632 m2 = 0;
633 m3 = 0;
634 m4 = 0;
635 ++t;
636 }
637 }
638
640 long double res = static_cast<long double>(k) / BIG_NUMBER;
641 if (res != 0) {
642 long double Delta = m1 - M1;
643 long double DeltaSq = Delta * Delta;
644 long double tpres = t + res;
646 M4 += m4 + (DeltaSq * DeltaSq * t * res * (t * t - res * t + res * res) * BIG_NUMBER) / (tpres * tpres * tpres);
647 M4 += 6 * DeltaSq * (t * t * m2 + res * res * M2) / (tpres * tpres);
648 M4 += 4 * Delta * (t * m3 - res * M3) / tpres;
650 M3 += m3 + (DeltaSq * Delta * t * res * (t - res) * BIG_NUMBER) / (tpres * tpres);
651 M3 += 3 * Delta * (t * m2 - res * M2) / tpres;
653 M2 += m2 + (DeltaSq * t * res * BIG_NUMBER) / tpres;
654 M1 += Delta * res / tpres;
655 }
656
657 long double variance = M2 / n;
658 long double skewness = std::sqrt(n) * M3 / std::pow(M2, 1.5);
659 long double exkurtosis = (n * M4) / (M2 * M2) - 3.0;
660 return std::make_tuple(M1, variance, skewness, exkurtosis);
661}
662
663} // namespace randlib
The ProbabilityDistribution class Abstract class for all probability distributions.
Definition distribution.hpp:28
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
virtual double LogLikelihoodFunction(std::span< const T > sample) const =0
T Quantile(double p) const
Definition univariate.hpp:307
virtual std::complex< double > CFImpl(double t) const
Definition univariate.hpp:365
static bool allElementsAreNotGreaterThan(T value, std::span< const T > sample)
Definition univariate.hpp:483
virtual long double FourthMoment() const
Definition univariate.hpp:467
bool isLeftBounded() const
Definition univariate.hpp:293
virtual T Median() const
Definition univariate.hpp:396
virtual long double ExpectedValue(const std::function< double(T)> &funPtr, T minPoint, T maxPoint) const =0
T Quantile1m(double p) const
Definition univariate.hpp:324
static long double GetSampleMean(std::span< const T > sample)
Definition univariate.hpp:525
UnivariateDistribution()
Definition univariate.hpp:288
static std::tuple< long double, long double, long double, long double > GetSampleStatistics(std::span< const T > sample)
Definition univariate.hpp:594
virtual long double Skewness() const
Definition univariate.hpp:402
void HazardFunction(std::span< const T > x, std::span< double > y) const
Definition univariate.hpp:388
virtual long double ExcessKurtosis() const
Definition univariate.hpp:421
void QuantileFunction1m(std::span< const double > p, std::span< T > y) const
Definition univariate.hpp:349
virtual long double Kurtosis() const
Definition univariate.hpp:441
virtual ~UnivariateDistribution()
Definition univariate.hpp:33
bool isRightBounded() const
Definition univariate.hpp:300
std::complex< double > CF(double t) const
Definition univariate.hpp:357
static long double GetSampleSum(std::span< const T > sample)
Definition univariate.hpp:519
static LongDoublePair GetSampleMeanAndVariance(std::span< const T > sample)
Definition univariate.hpp:563
virtual double Hazard(const T &x) const =0
static bool allElementsAreNotSmallerThan(T value, std::span< const T > sample)
Definition univariate.hpp:493
virtual long double Mean() const =0
void CharacteristicFunction(std::span< const double > t, std::span< std::complex< double > > y) const
Definition univariate.hpp:379
virtual Support SupportType() const =0
virtual long double Variance() const =0
static long double GetSampleLogVariance(std::span< const T > sample, double logMean)
Definition univariate.hpp:552
virtual long double ThirdMoment() const
Definition univariate.hpp:454
virtual double LikelihoodFunction(std::span< const T > sample) const =0
static long double GetSampleVariance(std::span< const T > sample, double mean)
Definition univariate.hpp:541
static LongDoublePair GetSampleLogMeanAndVariance(std::span< const T > sample)
Definition univariate.hpp:578
virtual long double SecondMoment() const
Definition univariate.hpp:447
static bool allElementsArePositive(std::span< const T > sample)
Definition univariate.hpp:509
static bool allElementsAreNonNegative(std::span< const T > sample)
Definition univariate.hpp:503
static long double GetSampleLogMean(std::span< const T > sample)
Definition univariate.hpp:532
virtual T Mode() const =0
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
void QuantileFunction(std::span< const double > p, std::span< T > y) const
Definition univariate.hpp:341
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ LeftSemiFinite
(-∞, b]
@ RightSemiFinite
[a, ∞)
@ Infinite
(-∞, ∞)
Pair< long double > LongDoublePair
Definition fwd.hpp:40