RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
continuous/gamma.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
10
11namespace randlib
12{
13
29template <typename RealType>
30class GammaDistribution : virtual public ContinuousDistribution<RealType>
31{
32 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
33 void sample(detail::EngineRef g, std::span<RealType> outputData) const override;
34
35protected:
36 double alpha = 1;
37 double beta = 1;
38 double theta = 1;
39 double lgammaAlpha = 0;
40 double pdfCoef = 0;
41 double logAlpha = 0;
42 double logBeta = 0;
44
45private:
47 struct genCoef_t
48 {
49 double t, b;
50 } genCoef = {0, 0};
51
52protected:
53 GammaDistribution(double shape, double rate);
54
55public:
56 virtual ~GammaDistribution() {}
57
58 [[nodiscard]] Support SupportType() const override { return Support::RightSemiFinite; }
59 [[nodiscard]] RealType MinValue() const override { return 0; }
60 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
61
62protected:
67 void SetParameters(double shape, double rate);
72 void SetShape(double shape);
73
74public:
78 [[nodiscard]] inline double GetShape() const noexcept { return alpha; }
82 [[nodiscard]] inline double GetScale() const noexcept { return theta; }
86 [[nodiscard]] inline double GetRate() const noexcept { return beta; }
90 [[nodiscard]] inline double GetLogGammaShape() const noexcept { return lgammaAlpha; }
94 [[nodiscard]] inline double GetLogShape() const noexcept { return logAlpha; }
98 [[nodiscard]] inline double GetDigammaShape() const noexcept { return digammaAlpha; }
102 [[nodiscard]] inline double GetLogRate() const noexcept { return logBeta; }
103
104 [[nodiscard]] double f(const RealType &x) const override;
105 [[nodiscard]] double logf(const RealType &x) const override;
106 [[nodiscard]] double F(const RealType &x) const override;
107 double logF(const RealType &x) const;
108 [[nodiscard]] double S(const RealType &x) const override;
109 double logS(const RealType &x) const;
110
111private:
112 enum GENERATOR_ID
113 {
114 INTEGER_SHAPE,
115 ONE_AND_A_HALF_SHAPE,
116 SMALL_SHAPE,
117 FISHMAN,
118 MARSAGLIA_TSANG
119 };
120
125 static GENERATOR_ID getIdOfUsedGenerator(double shape)
126 {
127 if (shape < 0.34)
128 return SMALL_SHAPE;
129 if (shape <= 3.0 && math::detail::areClose(shape, std::round(shape)))
130 return INTEGER_SHAPE;
131 if (math::detail::areClose(shape, 1.5))
132 return ONE_AND_A_HALF_SHAPE;
133 if (shape > 1.0 && shape < 1.2)
134 return FISHMAN;
135 return MARSAGLIA_TSANG;
136 }
137
142 template <std::uniform_random_bit_generator G>
143 static RealType variateThroughExponentialSum(int shape, G &g);
147 template <std::uniform_random_bit_generator G>
148 static RealType variateForShapeOneAndAHalf(G &g);
152 template <std::uniform_random_bit_generator G>
153 RealType variateBest(G &g) const;
158 template <std::uniform_random_bit_generator G>
159 static RealType variateAhrensDieter(double shape, G &g);
164 template <std::uniform_random_bit_generator G>
165 static RealType variateFishman(double shape, G &g);
170 template <std::uniform_random_bit_generator G>
171 static RealType variateMarsagliaTsang(double shape, G &g);
172
173public:
179 template <std::uniform_random_bit_generator G>
180 [[nodiscard]] static RealType StandardVariate(double shape, G &g);
187 template <std::uniform_random_bit_generator G>
188 [[nodiscard]] static RealType Variate(double shape, double rate, G &g);
189
190 template <std::uniform_random_bit_generator G>
191 [[nodiscard]] RealType operator()(G &g) const;
192
196 [[nodiscard]] long double Mean() const override;
200 long double GeometricMean() const;
204 [[nodiscard]] long double Variance() const override;
208 long double GeometricVariance() const;
209 [[nodiscard]] RealType Mode() const override;
210 [[nodiscard]] RealType Median() const override;
211 [[nodiscard]] long double Skewness() const override;
212 [[nodiscard]] long double ExcessKurtosis() const override;
213
214private:
216 RealType initRootForSmallP(double r) const;
217 RealType initRootForLargeP(double logQ) const;
218 RealType initRootForLargeShape(double p) const;
219 RealType initRootForLargeShape1m(double p) const;
220 RealType quantileInitialGuess(double p) const;
221 RealType quantileInitialGuess1m(double p) const;
222
228 double df(RealType x) const;
234 double dfDivf(RealType x) const;
235 RealType quantileImpl(double p, RealType initValue) const override;
236 RealType quantileImpl(double p) const override;
237 RealType quantileImpl1m(double p, RealType initValue) const override;
238 RealType quantileImpl1m(double p) const override;
239
240 std::complex<double> CFImpl(double t) const override;
241};
242
243template <typename RealType>
244class GammaRand;
245
250template <typename RealType>
252{
253protected:
254 FreeRateGammaDistribution(double shape, double rate) : GammaDistribution<RealType>(shape, rate) {}
255
256public:
261 void SetRate(double rate);
262
267 void SetScale(double scale);
268
275 RANDLIB_DEPRECATED_FIT_MEMBER void FitRate(std::span<const RealType> sample, bool unbiased = false);
276
285 const GammaDistribution<RealType> &priorDistribution,
286 bool MAP = false);
287};
288
293template <typename RealType>
294class GammaRand final : public FreeRateGammaDistribution<RealType>, public ExponentialFamily<RealType, DoublePair>
295{
296public:
297 GammaRand(double shape = 1, double rate = 1) : FreeRateGammaDistribution<RealType>(shape, rate) {}
298
304 [[nodiscard]] static GammaRand FromShapeRate(double shape, double rate) { return GammaRand(shape, rate); }
305
311 [[nodiscard]] static GammaRand FromShapeScale(double shape, double scale)
312 {
313 if (!(scale > 0.0))
314 throw std::invalid_argument("Gamma distribution: scale should be positive");
315 return GammaRand(shape, 1.0 / scale);
316 }
317 [[nodiscard]] std::string Name() const override;
318
319 using GammaDistribution<RealType>::SetParameters;
320 using GammaDistribution<RealType>::SetShape;
321
326 RANDLIB_DEPRECATED_FIT_MEMBER void FitShape(std::span<const RealType> sample);
327
332 RANDLIB_DEPRECATED_FIT_MEMBER void Fit(std::span<const RealType> sample);
333
334 DoublePair SufficientStatistic(RealType x) const override;
335 DoublePair SourceParameters() const override;
336 DoublePair SourceToNatural(DoublePair sourceParameters) const override;
337 double LogNormalizer(DoublePair parameters) const override;
338 DoublePair LogNormalizerGradient(DoublePair parameters) const override;
339 double CarrierMeasure(RealType) const override;
340 double CrossEntropyAdjusted(DoublePair parameters) const override;
341 double EntropyAdjusted() const override;
342};
343
353template <typename RealType>
354class ChiSquaredRand final : public GammaDistribution<RealType>
355{
356public:
357 explicit ChiSquaredRand(size_t degree = 1) : GammaDistribution<RealType>(0.5 * degree, 0.5) {}
358 [[nodiscard]] std::string Name() const override;
359 void SetDegree(size_t degree);
360 [[nodiscard]] inline size_t GetDegree() const { return static_cast<int>(2 * this->alpha); }
361};
362
373template <typename RealType>
374class ErlangRand final : public FreeRateGammaDistribution<RealType>
375{
376public:
377 ErlangRand(int shape = 1, double rate = 1) : FreeRateGammaDistribution<RealType>(shape, rate) {}
378
380 [[nodiscard]] static ErlangRand FromShapeRate(int shape, double rate) { return ErlangRand(shape, rate); }
381
383 [[nodiscard]] static ErlangRand FromShapeScale(int shape, double scale)
384 {
385 if (!(scale > 0.0))
386 throw std::invalid_argument("Erlang distribution: scale should be positive");
387 return ErlangRand(shape, 1.0 / scale);
388 }
389 [[nodiscard]] std::string Name() const override;
390 void SetParameters(size_t shape, double rate);
391 void SetShape(size_t shape);
392};
393
394} // namespace randlib
395
399
400namespace randlib
401{
402
403template <typename RealType>
405{
406 SetParameters(shape, rate);
407}
408
409template <typename RealType>
410void GammaDistribution<RealType>::SetParameters(double shape, double rate)
411{
412 if (!(shape > 0.0))
413 throw std::invalid_argument("Gamma distribution: shape should be positive, but it's equal to " +
414 std::to_string(shape));
415 if (!(rate > 0.0))
416 throw std::invalid_argument("Gamma distribution: rate should be positive, but it's equal to " +
417 std::to_string(rate));
418
419 this->alpha = shape > 0 ? shape : 1.0;
420
421 this->beta = (rate > 0.0) ? rate : 1.0;
422 theta = 1.0 / this->beta;
423
424 lgammaAlpha = std::lgammal(this->alpha);
425 logAlpha = std::log(this->alpha);
426 this->logBeta = std::log(this->beta);
427 pdfCoef = -lgammaAlpha + this->alpha * this->logBeta;
428
429 if (getIdOfUsedGenerator(this->alpha) == SMALL_SHAPE) {
431 genCoef.t = 0.5 * std::log1pl(-alpha);
432 genCoef.t = 0.07 + 0.75 * std::exp(genCoef.t);
433 genCoef.b = 1.0 + std::exp(-genCoef.t) * this->alpha / genCoef.t;
434 }
435}
436
437template <typename RealType>
439{
440 SetParameters(shape, this->beta);
441}
442
443template <typename RealType>
444double GammaDistribution<RealType>::f(const RealType &x) const
445{
446 if (x < 0.0)
447 return 0.0;
448 if (x == 0.0) {
449 if (this->alpha > 1.0)
450 return 0.0;
451 return (this->alpha == 1.0) ? this->beta : INFINITY;
452 }
453 return std::exp(logf(x));
454}
455
456template <typename RealType>
457double GammaDistribution<RealType>::logf(const RealType &x) const
458{
459 if (x < 0.0)
460 return -INFINITY;
461 if (x == 0.0) {
462 if (this->alpha > 1.0)
463 return -INFINITY;
464 return (this->alpha == 1.0) ? this->logBeta : INFINITY;
465 }
466 double y = (this->alpha - 1.0) * std::log(x);
467 y -= x * this->beta;
468 y += pdfCoef;
469 return y;
470}
471
472template <typename RealType>
473double GammaDistribution<RealType>::F(const RealType &x) const
474{
475 return (x > 0.0) ? math::pgamma(this->alpha, x * this->beta, logAlpha, lgammaAlpha) : 0.0;
476}
477
478template <typename RealType>
479double GammaDistribution<RealType>::logF(const RealType &x) const
480{
481 return (x > 0.0) ? math::lpgamma(this->alpha, x * this->beta, logAlpha, lgammaAlpha) : -INFINITY;
482}
483
484template <typename RealType>
485double GammaDistribution<RealType>::S(const RealType &x) const
486{
487 return (x > 0.0) ? math::qgamma(this->alpha, x * this->beta, logAlpha, lgammaAlpha) : 1.0;
488}
489
490template <typename RealType>
491double GammaDistribution<RealType>::logS(const RealType &x) const
492{
493 return (x > 0.0) ? math::lqgamma(this->alpha, x * this->beta, logAlpha, lgammaAlpha) : 0.0;
494}
495
496template <typename RealType>
497template <std::uniform_random_bit_generator G>
499{
500 double X = 0.0;
501 for (int i = 0; i < shape; ++i)
503 return X;
504}
505
506template <typename RealType>
507template <std::uniform_random_bit_generator G>
508RealType GammaDistribution<RealType>::variateForShapeOneAndAHalf(G &g)
509{
511 RealType N = detail::standardNormal<RealType>(g);
512 return W + 0.5 * N * N;
513}
514
515template <typename RealType>
516template <std::uniform_random_bit_generator G>
517RealType GammaDistribution<RealType>::variateBest(G &g) const
518{
520 double X = 0;
521 size_t iter = 0;
522 do {
523 double V = genCoef.b * detail::uniform01<RealType>(g);
524 double W = detail::uniform01<RealType>(g);
525 if (V <= 1) {
526 X = genCoef.t * std::pow(V, 1.0 / this->alpha);
527 if (W <= (2.0 - X) / (2.0 + X) || W <= std::exp(-X))
528 return X;
529 } else {
530 X = -std::log(genCoef.t * (genCoef.b - V) / this->alpha);
531 double Y = X / genCoef.t;
532 if (W * (this->alpha + Y - this->alpha * Y) <= 1 || W <= std::pow(Y, this->alpha - 1))
533 return X;
534 }
535 } while (++iter <= ProbabilityDistribution<RealType>::MAX_ITER_REJECTION);
536 throw std::runtime_error("Gamma distribution: sampling failed");
537}
538
539template <typename RealType>
540template <std::uniform_random_bit_generator G>
541RealType GammaDistribution<RealType>::variateAhrensDieter(double shape, G &g)
542{
544 double X = 0;
545 size_t iter = 0;
546 double shapeInv = 1.0 / shape;
547 double t = shapeInv + randlib::consts::inv_e;
548 do {
549 double U = detail::uniform01<RealType>(g);
550 double p = shape * t * U;
552 if (p <= 1) {
553 X = std::pow(p, shapeInv);
554 if (X <= W)
555 return X;
556 } else {
557 X = -std::log(t * (1 - U));
558 if ((1 - shape) * std::log(X) <= W)
559 return X;
560 }
561 } while (++iter <= ProbabilityDistribution<RealType>::MAX_ITER_REJECTION);
562 throw std::runtime_error("Gamma distribution: sampling failed");
563}
564
565template <typename RealType>
566template <std::uniform_random_bit_generator G>
567RealType GammaDistribution<RealType>::variateFishman(double shape, G &g)
568{
570 double W1, W2;
571 double shapem1 = shape - 1;
572 do {
575 } while (W2 < shapem1 * (W1 - std::log(W1) - 1));
576 return shape * W1;
577}
578
579template <typename RealType>
580template <std::uniform_random_bit_generator G>
581RealType GammaDistribution<RealType>::variateMarsagliaTsang(double shape, G &g)
582{
584 RealType d = shape - 1.0 / 3;
585 RealType c = 3 * std::sqrt(d);
586 size_t iter = 0;
587 do {
588 RealType N;
589 do {
591 } while (N <= -c);
592 RealType v = 1 + N / c;
593 v = v * v * v;
594 N *= N;
595 RealType U = detail::uniform01<RealType>(g);
596 if (U < 1.0 - 0.331 * N * N || std::log(U) < 0.5 * N + d * (1.0 - v + std::log(v))) {
597 return d * v;
598 }
599 } while (++iter <= ProbabilityDistribution<RealType>::MAX_ITER_REJECTION);
600 throw std::runtime_error("Gamma distribution: sampling failed");
601}
602
603template <typename RealType>
604template <std::uniform_random_bit_generator G>
606{
607 if (!(shape > 0))
608 throw std::invalid_argument("Gamma distribution: shape should be positive");
609
610 GENERATOR_ID genId = getIdOfUsedGenerator(shape);
611
612 switch (genId) {
613 case INTEGER_SHAPE:
614 return variateThroughExponentialSum(std::round(shape), g);
615 case ONE_AND_A_HALF_SHAPE:
616 return variateForShapeOneAndAHalf(g);
617 case SMALL_SHAPE:
618 return variateAhrensDieter(shape, g);
619 case FISHMAN:
620 return variateFishman(shape, g);
621 case MARSAGLIA_TSANG:
622 return variateMarsagliaTsang(shape, g);
623 default:
624 throw std::runtime_error("Gamma distribution: invalid generator id");
625 }
626}
627
628template <typename RealType>
629template <std::uniform_random_bit_generator G>
630RealType GammaDistribution<RealType>::Variate(double shape, double rate, G &g)
631{
632 if (!(shape > 0.0))
633 throw std::invalid_argument("Gamma distribution: shape should be positive");
634 if (!(rate > 0.0))
635 throw std::invalid_argument("Gamma distribution: rate should be positive");
636 return StandardVariate(shape, g) / rate;
637}
638
639template <typename RealType>
640template <std::uniform_random_bit_generator G>
642{
643 GENERATOR_ID genId = getIdOfUsedGenerator(this->alpha);
644
645 switch (genId) {
646 case INTEGER_SHAPE:
647 return theta * variateThroughExponentialSum(this->alpha, g);
648 case ONE_AND_A_HALF_SHAPE:
649 return theta * variateForShapeOneAndAHalf(g);
650 case SMALL_SHAPE:
651 return theta * variateBest(g);
652 case FISHMAN:
653 return theta * variateFishman(this->alpha, g);
654 case MARSAGLIA_TSANG:
655 return theta * variateMarsagliaTsang(this->alpha, g);
656 default:
657 throw std::runtime_error("Gamma distribution: invalid generator id");
658 }
659}
660
661template <typename RealType>
662void GammaDistribution<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
663{
664 GENERATOR_ID genId = getIdOfUsedGenerator(this->alpha);
665
666 switch (genId) {
667 case INTEGER_SHAPE:
668 for (RealType &var : outputData)
669 var = theta * variateThroughExponentialSum(this->alpha, g);
670 break;
671 case ONE_AND_A_HALF_SHAPE:
672 for (RealType &var : outputData)
673 var = theta * variateForShapeOneAndAHalf(g);
674 break;
675 case SMALL_SHAPE:
676 for (RealType &var : outputData)
677 var = theta * variateBest(g);
678 break;
679 case FISHMAN:
680 for (RealType &var : outputData)
681 var = theta * variateFishman(this->alpha, g);
682 break;
683 case MARSAGLIA_TSANG:
684 for (RealType &var : outputData)
685 var = theta * variateMarsagliaTsang(this->alpha, g);
686 break;
687 default:
688 return;
689 }
690}
691
692template <typename RealType>
694{
695 return this->alpha * theta;
696}
697
698template <typename RealType>
700{
701 return this->digammaAlpha - this->logBeta;
702}
703
704template <typename RealType>
706{
707 return this->alpha * theta * theta;
708}
709
710template <typename RealType>
712{
713 return math::trigamma(this->alpha);
714}
715
716template <typename RealType>
718{
719 return (this->alpha <= 1) ? 0 : (this->alpha - 1) * theta;
720}
721
722template <typename RealType>
724{
725 return (this->alpha == 1.0) ? theta * randlib::consts::ln2 : quantileImpl(0.5);
726}
727
728template <typename RealType>
730{
731 return 2.0l / std::sqrt(this->alpha);
732}
733
734template <typename RealType>
736{
737 return 6.0l / this->alpha;
738}
739
740template <typename RealType>
742{
743 double root = 0;
744 double c[5];
745 c[4] = 1;
747 double denominator = this->alpha + 1;
748 c[3] = 1.0 / denominator;
750 denominator *= denominator;
751 denominator *= this->alpha + 2;
752 c[2] = 0.5 * (3 * this->alpha + 5) / denominator;
754 denominator *= 3 * (this->alpha + 1) * (this->alpha + 3);
755 c[1] = 8 * this->alpha + 33;
756 c[1] *= this->alpha;
757 c[1] += 31;
758 c[1] /= denominator;
760 denominator *= 8 * (this->alpha + 1) * (this->alpha + 2) * (this->alpha + 4);
761 c[0] = 125 * this->alpha + 1179;
762 c[0] *= this->alpha;
763 c[0] += 3971;
764 c[0] *= this->alpha;
765 c[0] += 5661;
766 c[0] *= this->alpha;
767 c[0] += 2888;
768 c[0] /= denominator;
770 for (int i = 0; i != 5; ++i) {
771 root += c[i];
772 root *= r;
773 }
774 return root;
775}
776
777template <typename RealType>
778RealType GammaDistribution<RealType>::initRootForLargeP(double logQ) const
779{
781 double x = (logQ + lgammaAlpha) / this->alpha;
782 x = -std::exp(x) / this->alpha;
783 return -alpha * math::Wm1Lambert(x);
784}
785
786template <typename RealType>
787RealType GammaDistribution<RealType>::initRootForLargeShape(double p) const
788{
789 if (p == 0.5)
790 return this->alpha;
791 double x = math::erfcinv(2 * p);
792 double lambda = x * x / this->alpha + 1;
793 lambda = -std::exp(-lambda);
794 lambda = (x < 0) ? -math::Wm1Lambert(lambda) : -math::W0Lambert(lambda);
795 return lambda * this->alpha;
796}
797
798template <typename RealType>
799RealType GammaDistribution<RealType>::initRootForLargeShape1m(double p) const
800{
801 if (p == 0.5)
802 return this->alpha;
803 double x = -math::erfcinv(2 * p);
804 double lambda = x * x / this->alpha + 1;
805 lambda = -std::exp(-lambda);
806 lambda = (x < 0) ? -math::Wm1Lambert(lambda) : -math::W0Lambert(lambda);
807 return lambda * this->alpha;
808}
809
810template <typename RealType>
811RealType GammaDistribution<RealType>::quantileInitialGuess(double p) const
812{
818 double guess = 0;
819 if (this->alpha < 10) {
820 double r = std::log(p * this->alpha) + lgammaAlpha;
821 r = std::exp(r / this->alpha);
823 if (r < 0.2 * (this->alpha + 1)) {
824 guess = initRootForSmallP(r);
825 } else {
826 double logQ = std::log1pl(-p);
828 double maxBoundary1 = -0.5 * this->alpha - logAlpha - lgammaAlpha;
830 double maxBoundary2 = this->alpha * (logAlpha - 1) - lgammaAlpha;
832 if (logQ < std::min(maxBoundary1, maxBoundary2))
833 guess = initRootForLargeP(logQ);
834 else if (this->alpha < 1)
835 guess = r;
836 else
837 guess = initRootForLargeShape(p);
838 }
839 } else
840 guess = initRootForLargeShape(p);
841 return guess / this->beta;
842}
843
844template <typename RealType>
845RealType GammaDistribution<RealType>::quantileInitialGuess1m(double p) const
846{
847 if (this->alpha < 10) {
848 double logQ = std::log(p);
850 double maxBoundary1 = -0.5 * this->alpha - logAlpha - lgammaAlpha;
852 double maxBoundary2 = this->alpha * (logAlpha - 1) - lgammaAlpha;
854 if (logQ < std::min(maxBoundary1, maxBoundary2))
855 return initRootForLargeP(logQ) / this->beta;
856 } else {
857 return initRootForLargeShape1m(p) / this->beta;
858 }
859 return quantileInitialGuess(1.0 - p);
860}
861
862template <typename RealType>
863double GammaDistribution<RealType>::df(RealType x) const
864{
865 double z = (this->alpha - 1) - this->beta * x;
866 double y = (this->alpha - 2) * std::log(x);
867 y -= this->beta * x;
868 y += pdfCoef;
869 return z * std::exp(y);
870}
871
872template <typename RealType>
873double GammaDistribution<RealType>::dfDivf(RealType x) const
874{
875 return x / (this->alpha - 1 - this->beta * x);
876}
877
878template <typename RealType>
879RealType GammaDistribution<RealType>::quantileImpl(double p, RealType initValue) const
880{
882}
883
884template <typename RealType>
885RealType GammaDistribution<RealType>::quantileImpl(double p) const
886{
887 return (this->alpha == 1.0) ? -theta * std::log1pl(-p) : quantileImpl(p, quantileInitialGuess(p));
888}
889
890template <typename RealType>
891RealType GammaDistribution<RealType>::quantileImpl1m(double p, RealType initValue) const
892{
894}
895
896template <typename RealType>
897RealType GammaDistribution<RealType>::quantileImpl1m(double p) const
898{
899 return (this->alpha == 1.0) ? -theta * std::log(p) : quantileImpl1m(p, quantileInitialGuess1m(p));
900}
901
902template <typename RealType>
903std::complex<double> GammaDistribution<RealType>::CFImpl(double t) const
904{
905 return std::pow(std::complex<double>(1.0, -theta * t), -alpha);
906}
907// FREE-SCALE-GAMMA-DISTRIBUTION
908
909template <typename RealType>
911{
912 this->SetParameters(this->alpha, rate);
913}
914
915template <typename RealType>
917{
918 SetRate(1.0 / scale);
919}
920
921template <typename RealType>
922void FreeRateGammaDistribution<RealType>::FitRate(std::span<const RealType> sample, bool unbiased)
923{
925 if (!this->allElementsArePositive(sample))
926 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
927 double mean = this->GetSampleMean(sample);
928 double coef = this->alpha - (unbiased ? 1.0 / sample.size() : 0.0);
929 this->SetParameters(this->alpha, coef / mean);
930}
931
932template <typename RealType>
935 const GammaDistribution<RealType> &priorDistribution, bool MAP)
936{
938 if (!this->allElementsArePositive(sample))
939 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
940 double kappa = priorDistribution.GetShape();
941 double gamma = priorDistribution.GetRate();
942 double newShape = this->alpha * sample.size() + kappa;
943 double newRate = this->GetSampleSum(sample) + gamma;
944 GammaRand<RealType> posteriorDistribution(newShape, newRate);
945 this->SetParameters(this->alpha, MAP ? posteriorDistribution.Mode() : posteriorDistribution.Mean());
946 return posteriorDistribution;
947}
948// GAMMARAND
949
950template <typename RealType>
951std::string GammaRand<RealType>::Name() const
952{
953 return "Gamma(" + this->toStringWithPrecision(this->GetShape()) + ", " +
954 this->toStringWithPrecision(this->GetRate()) + ")";
955}
956
957template <typename RealType>
958void GammaRand<RealType>::FitShape(std::span<const RealType> sample)
959{
961 if (!this->allElementsArePositive(sample))
962 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
963
965 double shape = this->GetSampleMean(sample) * this->beta;
967 double s = this->GetSampleLogMean(sample) + this->logBeta;
968 if (!math::findRootNewtonFirstOrder<double>(
969 [s](double x) {
970 double first = math::digamma(x) - s;
971 double second = math::trigamma(x);
972 return DoublePair(first, second);
973 },
974 shape))
975 throw this->fitError(FitErrorCode::Undefined, "Error in root-finding procedure");
976 SetParameters(shape, this->beta);
977}
978
979template <typename RealType>
980void GammaRand<RealType>::Fit(std::span<const RealType> sample)
981{
983 if (!this->allElementsArePositive(sample))
984 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
985
987 double average = this->GetSampleMean(sample);
988 double s = std::log(average) - this->GetSampleLogMean(sample);
989 double sm3 = s - 3.0, sp12 = 12.0 * s;
990 double shape = sm3 * sm3 + 2 * sp12;
991 shape = std::sqrt(shape);
992 shape -= sm3;
993 shape /= sp12;
994
995 if (!math::findRootNewtonFirstOrder<double>(
996 [s](double x) {
997 double first = math::digammamLog(x) + s;
998 double second = math::trigamma(x) - 1.0 / x;
999 return DoublePair(first, second);
1000 },
1001 shape))
1002 throw this->fitError(FitErrorCode::Undefined, "Error in root-finding procedure");
1003
1004 SetParameters(shape, shape / average);
1005}
1006
1007template <typename RealType>
1009{
1010 return {std::log(x), x};
1011}
1012
1013template <typename RealType>
1015{
1016 return {this->alpha, this->beta};
1017}
1018
1019template <typename RealType>
1021{
1022 double shape = sourceParameters.first;
1023 double rate = sourceParameters.second;
1024 return {shape - 1, -rate};
1025}
1026
1027template <typename RealType>
1029{
1030 double shape = parameters.first + 1, rate = -parameters.second;
1031 double F = std::lgamma(shape);
1032 F -= shape * std::log(rate);
1033 return F;
1034}
1035
1036template <typename RealType>
1038{
1039 double shape = parameters.first + 1, rate = -parameters.second;
1040 double gradF1 = math::digamma(shape) - std::log(rate);
1041 double gradF2 = shape / rate;
1042 return {gradF1, gradF2};
1043}
1044
1045template <typename RealType>
1047{
1048 return 0;
1049}
1050
1051template <typename RealType>
1053{
1054 double shapeq = parameters.first + 1, rateq = -parameters.second;
1055 double H = std::lgamma(shapeq);
1056 H -= shapeq * std::log(rateq);
1057 H -= (shapeq - 1) * (this->digammaAlpha - this->logBeta);
1058 H += rateq * this->alpha / this->beta;
1059 return H;
1060}
1061
1062template <typename RealType>
1064{
1065 double H = this->lgammaAlpha;
1066 H -= this->logBeta;
1067 H -= (this->alpha - 1) * this->digammaAlpha;
1068 H += this->alpha;
1069 return H;
1070}
1071// CHI-SQUAREDRAND
1072
1073template <typename RealType>
1075{
1076 return "Chi-squared(" + this->toStringWithPrecision(GetDegree()) + ")";
1077}
1078
1079template <typename RealType>
1081{
1083}
1084// ERLANGRAND
1085
1086template <typename RealType>
1088{
1089 return "Erlang(" + this->toStringWithPrecision(this->GetShape()) + ", " +
1090 this->toStringWithPrecision(this->GetRate()) + ")";
1091}
1092
1093template <typename RealType>
1094void ErlangRand<RealType>::SetParameters(size_t shape, double rate)
1095{
1097}
1098
1099template <typename RealType>
1101{
1102 SetParameters(shape, this->beta);
1103}
1104
1105} // namespace randlib
The ChiSquaredRand class Chi-squared distribution.
Definition continuous/gamma.hpp:355
size_t GetDegree() const
Definition continuous/gamma.hpp:360
void SetDegree(size_t degree)
Definition continuous/gamma.hpp:1080
ChiSquaredRand(size_t degree=1)
Definition continuous/gamma.hpp:357
std::string Name() const override
Definition continuous/gamma.hpp:1074
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
RealType quantileImpl(double p, RealType initValue) const override
Definition continuous.hpp:140
RealType quantileImpl1m(double p, RealType initValue) const override
Definition continuous.hpp:152
The ErlangRand class Erlang distibution.
Definition continuous/gamma.hpp:375
static ErlangRand FromShapeScale(int shape, double scale)
Definition continuous/gamma.hpp:383
void SetParameters(size_t shape, double rate)
Definition continuous/gamma.hpp:1094
ErlangRand(int shape=1, double rate=1)
Definition continuous/gamma.hpp:377
std::string Name() const override
Definition continuous/gamma.hpp:1087
static ErlangRand FromShapeRate(int shape, double rate)
Definition continuous/gamma.hpp:380
void SetShape(size_t shape)
Definition continuous/gamma.hpp:1100
Definition exponential_family.hpp:14
The FreeRateGammaDistribution class Abstract class for Gamma distribution with arbitrary scale/rate...
Definition continuous/gamma.hpp:252
void SetRate(double rate)
set rate β
Definition continuous/gamma.hpp:910
void SetScale(double scale)
set scale θ = 1/β
Definition continuous/gamma.hpp:916
GammaRand< RealType > FitRateBayes(std::span< const RealType > sample, const GammaDistribution< RealType > &priorDistribution, bool MAP=false)
set rate, returned by bayesian estimation
Definition continuous/gamma.hpp:934
void FitRate(std::span< const RealType > sample, bool unbiased=false)
set rate, estimated via maximum-likelihood method if unbiased = false, otherwise set rate,...
Definition continuous/gamma.hpp:922
FreeRateGammaDistribution(double shape, double rate)
Definition continuous/gamma.hpp:254
The GammaDistribution class Abstract class for Gamma distribution.
Definition continuous/gamma.hpp:31
double beta
rate β
Definition continuous/gamma.hpp:37
RealType operator()(G &g) const
Definition continuous/gamma.hpp:641
Support SupportType() const override
Definition continuous/gamma.hpp:58
long double Variance() const override
Definition continuous/gamma.hpp:705
RealType Median() const override
Definition continuous/gamma.hpp:723
double digammaAlpha
ψ(α)
Definition continuous/gamma.hpp:43
long double GeometricMean() const
Definition continuous/gamma.hpp:699
double logBeta
log(β)
Definition continuous/gamma.hpp:42
double alpha
shape α
Definition continuous/gamma.hpp:36
static RealType StandardVariate(double shape, G &g)
Definition continuous/gamma.hpp:605
double GetLogRate() const noexcept
Definition continuous/gamma.hpp:102
double F(const RealType &x) const override
Definition continuous/gamma.hpp:473
double pdfCoef
α * log(β) - log(Γ(α))
Definition continuous/gamma.hpp:40
double GetShape() const noexcept
Definition continuous/gamma.hpp:78
void SetShape(double shape)
SetShape.
Definition continuous/gamma.hpp:438
RealType MinValue() const override
Definition continuous/gamma.hpp:59
double theta
scale θ = 1/β
Definition continuous/gamma.hpp:38
double GetLogGammaShape() const noexcept
Definition continuous/gamma.hpp:90
long double Mean() const override
Definition continuous/gamma.hpp:693
long double ExcessKurtosis() const override
Definition continuous/gamma.hpp:735
double GetLogShape() const noexcept
Definition continuous/gamma.hpp:94
void SetParameters(double shape, double rate)
Definition continuous/gamma.hpp:410
double GetDigammaShape() const noexcept
Definition continuous/gamma.hpp:98
double lgammaAlpha
log(Γ(α))
Definition continuous/gamma.hpp:39
static RealType Variate(double shape, double rate, G &g)
Definition continuous/gamma.hpp:630
RealType MaxValue() const override
Definition continuous/gamma.hpp:60
double GetScale() const noexcept
Definition continuous/gamma.hpp:82
double logF(const RealType &x) const
Definition continuous/gamma.hpp:479
long double GeometricVariance() const
Definition continuous/gamma.hpp:711
double GetRate() const noexcept
Definition continuous/gamma.hpp:86
double logAlpha
log(α)
Definition continuous/gamma.hpp:41
virtual ~GammaDistribution()
Definition continuous/gamma.hpp:56
double logf(const RealType &x) const override
Definition continuous/gamma.hpp:457
GammaDistribution(double shape, double rate)
Definition continuous/gamma.hpp:404
double logS(const RealType &x) const
Definition continuous/gamma.hpp:491
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition continuous/gamma.hpp:717
long double Skewness() const override
Definition continuous/gamma.hpp:729
double f(const RealType &x) const override
Definition continuous/gamma.hpp:444
double S(const RealType &x) const override
Definition continuous/gamma.hpp:485
The GammaRand class Gamma distribution.
Definition continuous/gamma.hpp:295
void Fit(std::span< const RealType > sample)
set shape and rate, estimated via maximum-likelihood method
Definition continuous/gamma.hpp:980
DoublePair SourceToNatural(DoublePair sourceParameters) const override
Definition continuous/gamma.hpp:1020
double CrossEntropyAdjusted(DoublePair parameters) const override
Definition continuous/gamma.hpp:1052
static GammaRand FromShapeScale(double shape, double scale)
Definition continuous/gamma.hpp:311
DoublePair LogNormalizerGradient(DoublePair parameters) const override
Definition continuous/gamma.hpp:1037
std::string Name() const override
Definition continuous/gamma.hpp:951
double EntropyAdjusted() const override
Definition continuous/gamma.hpp:1063
double CarrierMeasure(RealType) const override
Definition continuous/gamma.hpp:1046
void FitShape(std::span< const RealType > sample)
set shape, estimated via maximum-likelihood method
Definition continuous/gamma.hpp:958
GammaRand(double shape=1, double rate=1)
Definition continuous/gamma.hpp:297
static GammaRand FromShapeRate(double shape, double rate)
Definition continuous/gamma.hpp:304
double LogNormalizer(DoublePair parameters) const override
Definition continuous/gamma.hpp:1028
DoublePair SourceParameters() const override
Definition continuous/gamma.hpp:1014
DoublePair SufficientStatistic(RealType x) const override
Definition continuous/gamma.hpp:1008
T Variate() const
Uses the engine of this object, so it is not thread-safe for one object; use operator() with one engi...
Definition distribution.hpp:133
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
#define RANDLIB_DEPRECATED_FIT_MEMBER
Definition fwd.hpp:9
constexpr long double ln2
Definition constants.hpp:18
constexpr long double egamma
Definition constants.hpp:36
constexpr long double inv_e
Definition constants.hpp:35
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
bool areClose(RealType a, RealType b, RealType eps=1e-6)
Definition functions.hpp:38
Real qgamma(std::type_identity_t< Real > a, Real x, std::type_identity_t< Real > logA, std::type_identity_t< Real > lgammaA)
Calculate upper regularized incomplete gamma function, accelerated by using precalculated values of l...
Definition math/gamma.hpp:938
Real digamma(Real x)
Definition math/gamma.hpp:691
Real lpgamma(std::type_identity_t< Real > a, Real x, std::type_identity_t< Real > logA, std::type_identity_t< Real > lgammaA)
Calculate logarithm of lower incomplete gamma function, accelerated by using precalculated value of l...
Definition math/gamma.hpp:875
Real W0Lambert(Real x, std::type_identity_t< Real > epsilon=Real{1e-11})
Definition functions.hpp:689
Real Wm1Lambert(Real x, std::type_identity_t< Real > epsilon=Real{1e-11})
Definition functions.hpp:722
Real trigamma(Real x)
Definition math/gamma.hpp:720
Real lqgamma(std::type_identity_t< Real > a, Real x, std::type_identity_t< Real > logA, std::type_identity_t< Real > lgammaA)
Calculate logarithm of upper incomplete gamma function, accelerated by using precalculated values of ...
Definition math/gamma.hpp:917
Real pgamma(std::type_identity_t< Real > a, Real x, std::type_identity_t< Real > logA, std::type_identity_t< Real > lgammaA)
Calculate lower regularized incomplete gamma function, accelerated by using precalculated value of lo...
Definition math/gamma.hpp:896
Real digammamLog(Real x)
Definition math/gamma.hpp:710
Real erfcinv(Real p)
Definition functions.hpp:485
Definition bivariate_normal.hpp:10
@ WrongSample
the sample could not have been drawn from this distribution
@ Undefined
any other failure
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ RightSemiFinite
[a, ∞)
Pair< double > DoublePair
Definition fwd.hpp:39