RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
continuous/beta.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
10
12
13namespace randlib
14{
15
31template <typename RealType>
33{
34 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
35 void sample(detail::EngineRef g, std::span<RealType> outputData) const override;
36
37protected:
38 double alpha = 1;
39 double beta = 1;
40 double a = 0;
41 double b = 1;
42 double bma = 1;
43 double bmaInv = 1;
44 double logbma = 0;
45
47
48private:
49 static constexpr double edgeForGenerators = 8.0;
50 double logBetaFun = 0;
51 double betaFun = 1;
52
53 static double logStandardized(double distance, double complement);
54
56 struct genCoef_t
57 {
58 double s, t, u;
59 } genCoef = {0, 0, 0};
60
61protected:
62 BetaDistribution(double shape1 = 1, double shape2 = 1, double minValue = 0, double maxValue = 1);
63
64public:
65 virtual ~BetaDistribution() {}
66
67 [[nodiscard]] Support SupportType() const override { return Support::Finite; }
68 [[nodiscard]] RealType MinValue() const override { return a; }
69 [[nodiscard]] RealType MaxValue() const override { return b; }
70
71private:
72 enum GENERATOR_ID
73 {
74 UNIFORM,
75 ARCSINE,
76 CHENG,
77 REJECTION_UNIFORM,
78 REJECTION_UNIFORM_EXTENDED,
79 REJECTION_NORMAL,
80 JOHNK,
81 ATKINSON_WHITTAKER,
82 GAMMA_RATIO
83 };
84
88 GENERATOR_ID getIdOfUsedGenerator() const
89 {
90 if (alpha < 1 && beta < 1 && alpha + beta > 1)
91 return ATKINSON_WHITTAKER;
92
95 return UNIFORM;
96 else if (math::detail::areClose(alpha, 0.5))
97 return ARCSINE;
98 else if (math::detail::areClose(alpha, 1.5))
99 return REJECTION_UNIFORM;
100 else if (alpha > 1)
101 return (alpha < 2) ? REJECTION_UNIFORM_EXTENDED : REJECTION_NORMAL;
102 }
103 if (std::min(alpha, beta) > 0.5 && std::max(alpha, beta) > 1)
104 return CHENG;
105 return (alpha + beta < 2) ? JOHNK : GAMMA_RATIO;
106 }
107
110 void setCoefficientsForGenerator();
111
112protected:
117 void SetShapes(double shape1, double shape2);
122 void SetSupport(double minValue, double maxValue);
123
124public:
128 [[nodiscard]] inline double GetAlpha() const noexcept { return alpha; }
132 [[nodiscard]] inline double GetBeta() const noexcept { return beta; }
136 [[nodiscard]] inline double GetBetaFunction() const noexcept { return betaFun; }
140 [[nodiscard]] inline double GetLogBetaFunction() const noexcept { return logBetaFun; }
141
142 [[nodiscard]] double f(const RealType &x) const override;
143 [[nodiscard]] double logf(const RealType &x) const override;
144 [[nodiscard]] double F(const RealType &x) const override;
145 [[nodiscard]] double S(const RealType &x) const override;
146
147private:
152 template <std::uniform_random_bit_generator G>
153 RealType variateRejectionUniform(G &g) const;
154
159 template <std::uniform_random_bit_generator G>
160 RealType variateRejectionUniformExtended(G &g) const;
161
166 template <std::uniform_random_bit_generator G>
167 RealType variateArcsine(G &g) const;
168
173 template <std::uniform_random_bit_generator G>
174 RealType variateRejectionNormal(G &g) const;
175
180 template <std::uniform_random_bit_generator G>
181 RealType variateJohnk(G &g) const;
182
187 template <std::uniform_random_bit_generator G>
188 RealType variateCheng(G &g) const;
189
194 template <std::uniform_random_bit_generator G>
195 RealType variateAtkinsonWhittaker(G &g) const;
196
201 template <std::uniform_random_bit_generator G>
202 RealType variateGammaRatio(G &g) const;
203
204public:
205 template <std::uniform_random_bit_generator G>
206 [[nodiscard]] RealType operator()(G &g) const;
207
208 [[nodiscard]] long double Mean() const override;
212 long double GeometricMean() const;
213 [[nodiscard]] long double Variance() const override;
217 long double GeometricVariance() const;
218 [[nodiscard]] RealType Median() const override;
219 [[nodiscard]] RealType Mode() const override;
220 [[nodiscard]] long double Skewness() const override;
221 [[nodiscard]] long double ExcessKurtosis() const override;
226 long double MeanAbsoluteDeviation() const;
227
228protected:
229 RealType quantileImpl(double p) const override;
230 RealType quantileImpl1m(double p) const override;
231
232 std::complex<double> CFImpl(double t) const override;
233
234 static constexpr char ALPHA_ZERO[] =
235 "Possibly one or more elements of the sample coincide with the lower boundary a.";
236 static constexpr char BETA_ZERO[] =
237 "Possibly one or more elements of the sample coincide with the upper boundary b.";
238};
239
244template <typename RealType>
245class BetaRand final : public BetaDistribution<RealType>, public ExponentialFamily<RealType, DoublePair>
246{
247public:
248 BetaRand(double shape1 = 1, double shape2 = 1, double minValue = 0, double maxValue = 1)
249 : BetaDistribution<RealType>(shape1, shape2, minValue, maxValue)
250 {
251 }
252 [[nodiscard]] std::string Name() const override;
253
254 using BetaDistribution<RealType>::SetShapes;
255 using BetaDistribution<RealType>::SetSupport;
256
257 DoublePair SufficientStatistic(RealType x) const override;
258 DoublePair SourceParameters() const override;
259 DoublePair SourceToNatural(DoublePair sourceParameters) const override;
260 double LogNormalizer(DoublePair theta) const override;
262 double CarrierMeasure(RealType) const override;
263
269 [[nodiscard]] long double GetSampleLogMeanNorm(std::span<const RealType> sample) const;
275 [[nodiscard]] long double GetSampleLog1pMeanNorm(std::span<const RealType> sample) const;
281 [[nodiscard]] long double GetSampleLog1mMeanNorm(std::span<const RealType> sample) const;
282
289 RANDLIB_DEPRECATED_FIT_MEMBER void FitAlpha(long double lnG, long double meanNorm);
290
295 RANDLIB_DEPRECATED_FIT_MEMBER void FitAlpha(std::span<const RealType> sample);
296
303 RANDLIB_DEPRECATED_FIT_MEMBER void FitBeta(long double lnG1m, long double meanNorm);
304
309 RANDLIB_DEPRECATED_FIT_MEMBER void FitBeta(std::span<const RealType> sample);
310
319 RANDLIB_DEPRECATED_FIT_MEMBER void FitShapes(long double lnG, long double lnG1m, long double mean,
320 long double variance);
321
326 RANDLIB_DEPRECATED_FIT_MEMBER void FitShapes(std::span<const RealType> sample);
327};
328
338template <typename RealType>
339class ArcsineRand final : public BetaDistribution<RealType>
340{
341public:
342 ArcsineRand(double shape = 0.5, double minValue = 0, double maxValue = 1)
343 : BetaDistribution<RealType>(1.0 - shape, shape, minValue, maxValue)
344 {
345 }
346 [[nodiscard]] std::string Name() const override;
347
348 using BetaDistribution<RealType>::SetSupport;
349
350 void SetShape(double shape);
351 [[nodiscard]] inline double GetShape() const noexcept { return this->beta; }
352
359 RANDLIB_DEPRECATED_FIT_MEMBER void FitShape(long double lnG, long double lnG1m);
360
365 RANDLIB_DEPRECATED_FIT_MEMBER void FitShape(std::span<const RealType> sample);
366};
367
377template <typename RealType>
378class BaldingNicholsRand final : public BetaDistribution<RealType>
379{
380 double fixationIndex = 0.5, p = 0.5;
381
382public:
383 BaldingNicholsRand(double fixatingIndex, double frequency);
384 [[nodiscard]] std::string Name() const override;
385
386 void SetFixatingIndexAndFrequency(double fixatingIndex, double frequency);
387 [[nodiscard]] inline double GetFixatingIndex() const noexcept { return fixationIndex; }
388 [[nodiscard]] inline double GetFrequency() const noexcept { return p; }
389};
390
391} // namespace randlib
392
398
399namespace randlib
400{
401
402template <typename RealType>
403BetaDistribution<RealType>::BetaDistribution(double shape1, double shape2, double minValue, double maxValue)
404{
405 SetShapes(shape1, shape2);
406 SetSupport(minValue, maxValue);
407}
408
409template <typename RealType>
411{
412 GENERATOR_ID id = getIdOfUsedGenerator();
413 if (id == REJECTION_NORMAL) {
414 double alpham1 = alpha - 1;
415 genCoef.s = alpham1 * std::log1pl(0.5 / alpham1) - 0.5;
416 genCoef.t = 1.0 / std::sqrt(8 * alpha - 4);
417 } else if (id == CHENG) {
418 genCoef.s = alpha + beta;
419 genCoef.t = std::min(alpha, beta);
420 if (genCoef.t > 1)
421 genCoef.t = std::sqrt((2 * alpha * beta - genCoef.s) / (genCoef.s - 2));
422 genCoef.u = alpha + genCoef.t;
423 } else if (id == ATKINSON_WHITTAKER) {
424 genCoef.t = std::sqrt(alpha * (1 - alpha));
425 genCoef.t /= (genCoef.t + std::sqrt(beta * (1 - beta)));
426 genCoef.s = beta * genCoef.t;
427 genCoef.s /= (genCoef.s + alpha * (1 - genCoef.t));
428 }
429}
430
431template <typename RealType>
432void BetaDistribution<RealType>::SetShapes(double shape1, double shape2)
433{
434 if (!(shape1 > 0 && shape2 > 0))
435 throw std::invalid_argument("Beta distribution: shapes should be positive");
436 GammaRV1.SetParameters(shape1, 1);
437 GammaRV2.SetParameters(shape2, 1);
438 alpha = GammaRV1.GetShape();
439 beta = GammaRV2.GetShape();
440 logBetaFun = math::logBeta(alpha, beta);
441 betaFun = std::exp(logBetaFun);
442 setCoefficientsForGenerator();
443}
444
445template <typename RealType>
446void BetaDistribution<RealType>::SetSupport(double minValue, double maxValue)
447{
448 if (!(minValue < maxValue))
449 throw std::invalid_argument("Beta distribution: minimum value should be smaller than maximum value");
450
451 a = minValue;
452 b = maxValue;
453 bma = b - a;
454 bmaInv = 1.0 / bma;
455 logbma = std::log(bma);
456}
457
458template <typename RealType>
459double BetaDistribution<RealType>::f(const RealType &x) const
460{
461 if (x < a || x > b)
462 return 0.0;
463 if (x == a) {
464 if (alpha == 1)
465 return beta / bma;
466 return (alpha > 1) ? 0 : INFINITY;
467 }
468 if (x == b) {
469 if (beta == 1)
470 return alpha / bma;
471 return (beta > 1) ? 0 : INFINITY;
472 }
473 return std::exp(logf(x));
474}
475
476template <typename RealType>
477double BetaDistribution<RealType>::logf(const RealType &x) const
478{
479 if (x < a || x > b)
480 return -INFINITY;
481 if (x == a) {
482 if (alpha == 1)
483 return std::log(beta / bma);
484 return (alpha > 1) ? -INFINITY : INFINITY;
485 }
486 if (x == b) {
487 if (beta == 1)
488 return std::log(alpha / bma);
489 return (beta > 1) ? -INFINITY : INFINITY;
490 }
491 const double xSt = (x - a) * bmaInv, ySt = (b - x) * bmaInv;
492 double y = (alpha - 1) * logStandardized(xSt, ySt);
493 y += (beta - 1) * logStandardized(ySt, xSt);
494 return y - logBetaFun - logbma;
495}
496
497template <typename RealType>
498double BetaDistribution<RealType>::logStandardized(double distance, double complement)
499{
501 return (complement < 0.5) ? std::log1p(-complement) : std::log(distance);
502}
503
504template <typename RealType>
505double BetaDistribution<RealType>::F(const RealType &x) const
506{
507 if (x <= a)
508 return 0.0;
509 if (x >= b)
510 return 1.0;
512 double xSt = std::min((x - a) * bmaInv, 1.0), ySt = std::min((b - x) * bmaInv, 1.0);
514 if (alpha == beta && beta == 0.5)
515 return (xSt <= ySt) ? randlib::consts::two_inv_pi * std::asin(std::sqrt(xSt))
516 : 1.0 - randlib::consts::two_inv_pi * std::asin(std::sqrt(ySt));
517 return math::ibeta(xSt, alpha, beta, logBetaFun, logStandardized(xSt, ySt), logStandardized(ySt, xSt));
518}
519
520template <typename RealType>
521double BetaDistribution<RealType>::S(const RealType &x) const
522{
523 if (x <= a)
524 return 1.0;
525 if (x >= b)
526 return 0.0;
528 double xSt = std::min((x - a) * bmaInv, 1.0), ySt = std::min((b - x) * bmaInv, 1.0);
530 if (alpha == beta && beta == 0.5)
531 return (ySt <= xSt) ? randlib::consts::two_inv_pi * std::asin(std::sqrt(ySt))
532 : 1.0 - randlib::consts::two_inv_pi * std::asin(std::sqrt(xSt));
533 return math::ibeta(ySt, beta, alpha, logBetaFun, logStandardized(ySt, xSt), logStandardized(xSt, ySt));
534}
535
536template <typename RealType>
537template <std::uniform_random_bit_generator G>
539{
540 RealType U = 2 * detail::uniform01<RealType>(g) - 1;
541 RealType X = std::sin(randlib::consts::pi * U);
542 return X * X;
543}
544
545template <typename RealType>
546template <std::uniform_random_bit_generator G>
547RealType BetaDistribution<RealType>::variateRejectionUniform(G &g) const
548{
549 size_t iter = 0;
550 do {
551 RealType U = detail::uniform01<RealType>(g);
552 RealType V = detail::uniform01<RealType>(g);
553 if (0.25 * V * V <= U - U * U)
554 return U;
555 } while (++iter <= this->MAX_ITER_REJECTION);
556 throw std::runtime_error("Beta distribution: sampling failed");
557}
558
559template <typename RealType>
560template <std::uniform_random_bit_generator G>
561RealType BetaDistribution<RealType>::variateRejectionUniformExtended(G &g) const
562{
563 size_t iter = 0;
564 static constexpr double M_LN4 = randlib::consts::ln2 + randlib::consts::ln2;
565 do {
566 RealType U = detail::uniform01<RealType>(g);
568 RealType edge = M_LN4 + std::log(U - U * U);
569 if (W >= (1.0 - alpha) * edge)
570 return U;
571 } while (++iter <= this->MAX_ITER_REJECTION);
572 throw std::runtime_error("Beta distribution: sampling failed");
573}
574
575template <typename RealType>
576template <std::uniform_random_bit_generator G>
577RealType BetaDistribution<RealType>::variateRejectionNormal(G &g) const
578{
579 size_t iter = 0;
580 RealType N = 0, Z = 0;
581 RealType alpham1 = alpha - 1;
582 RealType alpha2m1 = alpha + alpham1;
583 do {
584 do {
586 Z = N * N;
587 } while (Z >= alpha2m1);
588
589 RealType W = detail::standardExponential<RealType>(g) + genCoef.s;
590 RealType aux = 0.5 - alpham1 / (alpha2m1 - Z);
591 aux *= Z;
592 if (W + aux >= 0)
593 return 0.5 + N * genCoef.t;
594 aux = std::log1pl(-Z / alpha2m1);
595 aux *= alpham1;
596 aux += W + 0.5 * Z;
597 if (aux >= 0)
598 return 0.5 + N * genCoef.t;
599 } while (++iter <= this->MAX_ITER_REJECTION);
600 throw std::runtime_error("Beta distribution: sampling failed");
601}
602
603template <typename RealType>
604template <std::uniform_random_bit_generator G>
605RealType BetaDistribution<RealType>::variateJohnk(G &g) const
606{
607 RealType X = 0, Z = 0;
608 RealType W = 0, V = 0;
609 do {
612 X = std::exp(-W);
613 Z = X + std::exp(-V);
614 } while (Z > 1);
615 return (Z > 0) ? (X / Z) : (W < V);
616 ;
617}
618
619template <typename RealType>
620template <std::uniform_random_bit_generator G>
621RealType BetaDistribution<RealType>::variateCheng(G &g) const
622{
623 RealType R, T, Y;
624 do {
625 RealType U = detail::uniform01<RealType>(g);
626 RealType V = detail::uniform01<RealType>(g);
627 RealType X = std::log(U / (1 - U)) / genCoef.t;
628 Y = alpha * std::exp(X);
629 R = 1.0 / (beta + Y);
630 T = 4 * U * U * V;
631 T = std::log(T);
632 T -= genCoef.u * X;
633 T -= genCoef.s * std::log(genCoef.s * R);
634 } while (T > 0);
635 return Y * R;
636}
637
638template <typename RealType>
639template <std::uniform_random_bit_generator G>
640RealType BetaDistribution<RealType>::variateAtkinsonWhittaker(G &g) const
641{
642 size_t iter = 0;
643 do {
644 RealType U = detail::uniform01<RealType>(g);
646 if (U <= genCoef.s) {
647 RealType X = genCoef.t * std::pow(U / genCoef.s, 1.0 / alpha);
648 if (W >= (1.0 - beta) * std::log((1.0 - X) / (1.0 - genCoef.t)))
649 return X;
650 } else {
651 RealType X = 1.0 - (1.0 - genCoef.t) * std::pow((1.0 - U) / (1.0 - genCoef.s), 1.0 / beta);
652 if (W >= (1.0 - alpha) * std::log(X / genCoef.t))
653 return X;
654 }
655 } while (++iter <= this->MAX_ITER_REJECTION);
656 throw std::runtime_error("Beta distribution: sampling failed");
657}
658
659template <typename RealType>
660template <std::uniform_random_bit_generator G>
661RealType BetaDistribution<RealType>::variateGammaRatio(G &g) const
662{
663 RealType Y = GammaRV1(g);
664 RealType Z = GammaRV2(g);
665 return Y / (Y + Z);
666}
667
668template <typename RealType>
669template <std::uniform_random_bit_generator G>
671{
672 double var = 0;
673 GENERATOR_ID id = getIdOfUsedGenerator();
674
675 switch (id) {
676 case UNIFORM:
678 break;
679 case ARCSINE:
680 var = variateArcsine(g);
681 break;
682 case CHENG:
683 var = variateCheng(g);
684 break;
685 case REJECTION_UNIFORM:
686 var = variateRejectionUniform(g);
687 break;
688 case REJECTION_UNIFORM_EXTENDED:
689 var = variateRejectionUniformExtended(g);
690 break;
691 case REJECTION_NORMAL:
692 var = variateRejectionNormal(g);
693 break;
694 case JOHNK:
695 var = variateJohnk(g);
696 break;
697 case ATKINSON_WHITTAKER:
698 var = variateAtkinsonWhittaker(g);
699 break;
700 case GAMMA_RATIO:
701 default:
702 var = variateGammaRatio(g);
703 break;
704 }
705
706 return a + bma * var;
707}
708
709template <typename RealType>
710void BetaDistribution<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
711{
712 GENERATOR_ID id = getIdOfUsedGenerator();
713
714 switch (id) {
715 case UNIFORM: {
716 for (RealType &var : outputData)
717 var = detail::uniform01<RealType>(g);
718 } break;
719 case ARCSINE: {
720 for (RealType &var : outputData)
721 var = variateArcsine(g);
722 } break;
723 case CHENG: {
724 for (RealType &var : outputData)
725 var = variateCheng(g);
726 } break;
727 case REJECTION_UNIFORM: {
728 for (RealType &var : outputData)
729 var = variateRejectionUniform(g);
730 } break;
731 case REJECTION_UNIFORM_EXTENDED: {
732 for (RealType &var : outputData)
733 var = variateRejectionUniformExtended(g);
734 } break;
735 case REJECTION_NORMAL: {
736 for (RealType &var : outputData)
737 var = variateRejectionNormal(g);
738 } break;
739 case JOHNK: {
740 for (RealType &var : outputData)
741 var = variateJohnk(g);
742 } break;
743 case ATKINSON_WHITTAKER: {
744 for (RealType &var : outputData)
745 var = variateAtkinsonWhittaker(g);
746 } break;
747 case GAMMA_RATIO:
748 default: {
749 GammaRV1.Sample(g, outputData);
750 for (RealType &var : outputData)
751 var /= (var + GammaRV2(g));
752 } break;
753 }
754
756 for (RealType &var : outputData)
757 var = a + bma * var;
758}
759
760template <typename RealType>
762{
763 double mean = alpha / (alpha + beta);
764 return a + bma * mean;
765}
766
767template <typename RealType>
769{
770 return math::digamma(alpha) - math::digamma(alpha + beta);
771}
772
773template <typename RealType>
775{
776 double var = alpha + beta;
777 var *= var * (var + 1);
778 var = alpha * beta / var;
779 return bma * bma * var;
780}
781
782template <typename RealType>
784{
785 return math::trigamma(alpha) - math::trigamma(alpha + beta);
786}
787
788template <typename RealType>
790{
791 if (alpha == beta)
792 return a + bma * 0.5;
793 if (alpha == 1.0)
794 return a - bma * std::expm1l(-randlib::consts::ln2 / beta);
795 if (beta == 1.0)
796 return a + bma * std::exp(-randlib::consts::ln2 / alpha);
797 if (alpha >= 1.0 && beta >= 1.0) {
798 double initValue = 3 * alpha - 1.0;
799 initValue /= 3 * (alpha + beta) - 2.0;
800 initValue *= bma;
801 initValue += a;
803 }
805}
806
807template <typename RealType>
809{
810 double mode;
811 if (alpha > 1)
812 mode = (beta > 1) ? (alpha - 1) / (alpha + beta - 2) : 1.0;
813 else
814 mode = (beta > 1) ? 0.0 : (alpha > beta);
815 return a + bma * mode;
816}
817
818template <typename RealType>
820{
821 long double skewness = (alpha + beta + 1) / (alpha * beta);
822 skewness = std::sqrt(skewness);
823 skewness *= beta - alpha;
824 skewness /= alpha + beta + 2;
825 return 2 * skewness;
826}
827
828template <typename RealType>
830{
831 long double sum = alpha + beta;
832 long double kurtosis = alpha - beta;
833 kurtosis *= kurtosis;
834 kurtosis *= (sum + 1);
835 kurtosis /= (alpha * beta * (sum + 2));
836 --kurtosis;
837 kurtosis /= (sum + 3);
838 return 6 * kurtosis;
839}
840
841template <typename RealType>
843{
844 double y = randlib::consts::ln2;
845 y += alpha * std::log(alpha);
846 y += beta * std::log(beta);
847 y -= (alpha + beta + 1) * std::log(alpha + beta);
848 y -= logBetaFun;
849 y += logbma;
850 return std::exp(y);
851}
852
853template <typename RealType>
855{
856 if (alpha == beta) {
857 if (alpha == 0.5) {
858 double x = std::sin(0.5 * randlib::consts::pi * p);
859 return a + bma * x * x;
860 }
861 if (alpha == 1.0)
862 return a + bma * p;
863 }
864 if (alpha == 1.0)
865 return a - bma * std::expm1l(std::log1pl(-p) / beta);
866 if (beta == 1.0)
867 return a + bma * std::pow(p, 1.0 / alpha);
869}
870
871template <typename RealType>
873{
874 if (alpha == beta) {
875 if (alpha == 0.5) {
876 double x = std::cos(0.5 * randlib::consts::pi * p);
877 return a + bma * x * x;
878 }
879 if (alpha == 1.0)
880 return b - bma * p;
881 }
882 if (alpha == 1.0)
883 return a - bma * std::expm1l(std::log(p) / beta);
884 if (beta == 1.0)
885 return a + bma * std::exp(std::log1pl(-p) / alpha);
887}
888
889template <typename RealType>
890std::complex<double> BetaDistribution<RealType>::CFImpl(double t) const
891{
893 if (alpha >= 1 && beta >= 1)
895
896 double z = bma * t;
897 double sinZ = std::sin(z);
898 double cosZm1 = std::cos(z) - 1.0;
899
900 double re = math::integrate(
901 [this, z, cosZm1](double x) {
902 if (x >= 1)
903 return 0.0;
904 if (x <= 0)
905 return -cosZm1;
906 double y = std::cos(z * x) - 1;
907 y *= std::pow(x, alpha - 1);
908 y -= cosZm1;
909 return std::pow(1.0 - x, beta - 1) * y;
910 },
911 0, 1);
912 re += betaFun;
913 re += cosZm1 / beta;
914
915 double im = math::integrate(
916 [this, z, sinZ](double x) {
917 if (x >= 1)
918 return 0.0;
919 if (x <= 0)
920 return -sinZ;
921 double y = std::sin(z * x);
922 y *= std::pow(x, alpha - 1);
923 y -= sinZ;
924 return std::pow(1.0 - x, beta - 1) * y;
925 },
926 0, 1);
927 im += sinZ / beta;
928
929 std::complex<double> y(re, im);
930 double cosTA = std::cos(t * a), sinTA = std::sin(t * a);
931 return y * std::complex<double>(cosTA, sinTA) / betaFun;
932}
933
934template <typename RealType>
936template <typename RealType>
938// BETARAND
939
940template <typename RealType>
941std::string BetaRand<RealType>::Name() const
942{
943 return "Beta(" + this->toStringWithPrecision(this->GetAlpha()) + ", " +
944 this->toStringWithPrecision(this->GetBeta()) + ", " + this->toStringWithPrecision(this->MinValue()) + ", " +
945 this->toStringWithPrecision(this->MaxValue()) + ")";
946}
947
948template <typename RealType>
950{
951 double y = (x - this->a) * this->bmaInv;
952 return {std::log(y), std::log1pl(-y)};
953}
954
955template <typename RealType>
957{
958 return {this->alpha, this->beta};
959}
960
961template <typename RealType>
963{
964 return {sourceParameters.first - 1, sourceParameters.second - 1};
965}
966
967template <typename RealType>
969{
970 return this->logbma + math::logBeta(theta.first + 1, theta.second + 1);
971}
972
973template <typename RealType>
975{
976 double psi1 = math::digamma(theta.first + 1);
977 double psi2 = math::digamma(theta.second + 1);
978 double psisum = math::digamma(theta.first + theta.second + 2);
979 return {psi1 - psisum, psi2 - psisum};
980}
981
982template <typename RealType>
984{
985 return 0;
986}
987
988template <typename RealType>
989long double BetaRand<RealType>::GetSampleLogMeanNorm(std::span<const RealType> sample) const
990{
991 long double lnG = 0;
992 for (RealType var : sample) {
993 RealType x = (var - this->a) * this->bmaInv;
994 lnG += std::log(x);
995 }
996 return lnG / sample.size();
997}
998
999template <typename RealType>
1000long double BetaRand<RealType>::GetSampleLog1pMeanNorm(std::span<const RealType> sample) const
1001{
1002 long double lnG1p = 0;
1003 for (RealType var : sample) {
1004 RealType x = (var - this->a) * this->bmaInv;
1005 lnG1p += std::log1pl(x);
1006 }
1007 return lnG1p / sample.size();
1008}
1009
1010template <typename RealType>
1011long double BetaRand<RealType>::GetSampleLog1mMeanNorm(std::span<const RealType> sample) const
1012{
1013 long double lnG1m = 0;
1014 for (RealType var : sample) {
1015 RealType x = (var - this->a) * this->bmaInv;
1016 lnG1m += std::log1pl(-x);
1017 }
1018 return lnG1m / sample.size();
1019}
1020
1021template <typename RealType>
1022void BetaRand<RealType>::FitAlpha(long double lnG, long double meanNorm)
1023{
1024 if (meanNorm <= 0 || meanNorm >= 1)
1025 throw this->fitError(FitErrorCode::NotApplicable,
1026 "Normalized mean of the sample should be in interval of (0, 1)");
1027 if (this->beta == 1.0) {
1029 SetShapes(-1.0 / lnG, this->beta);
1030 } else {
1032 RealType shape = meanNorm;
1033 shape /= 1.0 - meanNorm;
1034 shape *= this->beta;
1036 if (!math::findRootNewtonFirstOrder<RealType>(
1037 [this, lnG](double x) {
1038 double first = math::digamma(x) - math::digamma(x + this->beta) - lnG;
1039 double second = math::trigamma(x);
1040 return DoublePair(first, second);
1041 },
1042 shape))
1043 throw this->fitError(FitErrorCode::Undefined, "Error in root-finding procedure.");
1044 SetShapes(shape, this->beta);
1045 }
1046}
1047
1048template <typename RealType>
1049void BetaRand<RealType>::FitAlpha(std::span<const RealType> sample)
1050{
1051 if (!this->allElementsAreNotSmallerThan(this->a, sample))
1052 throw this->fitError(FitErrorCode::WrongSample,
1053 this->LOWER_LIMIT_VIOLATION + this->toStringWithPrecision(this->a));
1054 if (!this->allElementsAreNotGreaterThan(this->b, sample))
1055 throw this->fitError(FitErrorCode::WrongSample,
1056 this->UPPER_LIMIT_VIOLATION + this->toStringWithPrecision(this->b));
1057
1058 long double lnG = this->GetSampleLogMeanNorm(sample);
1059 if (!std::isfinite(lnG))
1060 throw this->fitError(FitErrorCode::WrongReturn, this->ALPHA_ZERO);
1061 long double mean = this->GetSampleMean(sample);
1062 mean -= this->a;
1063 mean *= this->bmaInv;
1064 FitAlpha(lnG, mean);
1065}
1066
1067template <typename RealType>
1068void BetaRand<RealType>::FitBeta(long double lnG1m, long double meanNorm)
1069{
1070 if (meanNorm <= 0 || meanNorm >= 1)
1071 throw this->fitError(FitErrorCode::NotApplicable,
1072 "Normalized mean of the sample should be in interval of (0, 1)");
1073 if (this->alpha == 1.0) {
1075 SetShapes(this->alpha, -1.0 / lnG1m);
1076 } else {
1078 RealType shape = this->alpha / meanNorm - this->alpha;
1080 if (!math::findRootNewtonFirstOrder<RealType>(
1081 [this, lnG1m](double x) {
1082 double first = math::digamma(x) - math::digamma(x + this->alpha) - lnG1m;
1083 double second = math::trigamma(x);
1084 return DoublePair(first, second);
1085 },
1086 shape))
1087 throw this->fitError(FitErrorCode::Undefined, "Error in root-finding procedure.");
1088 this->SetShapes(this->alpha, shape);
1089 }
1090}
1091
1092template <typename RealType>
1093void BetaRand<RealType>::FitBeta(std::span<const RealType> sample)
1094{
1095 if (!this->allElementsAreNotSmallerThan(this->a, sample))
1096 throw this->fitError(FitErrorCode::WrongSample,
1097 this->LOWER_LIMIT_VIOLATION + this->toStringWithPrecision(this->a));
1098 if (!this->allElementsAreNotGreaterThan(this->b, sample))
1099 throw this->fitError(FitErrorCode::WrongSample,
1100 this->UPPER_LIMIT_VIOLATION + this->toStringWithPrecision(this->b));
1101
1102 long double lnG1m = this->GetSampleLog1mMeanNorm(sample);
1103 if (!std::isfinite(lnG1m))
1104 throw this->fitError(FitErrorCode::WrongReturn, this->BETA_ZERO);
1105 long double mean = this->GetSampleMean(sample);
1106 mean -= this->a;
1107 mean *= this->bmaInv;
1108 FitBeta(lnG1m, mean);
1109}
1110
1111template <typename RealType>
1112void BetaRand<RealType>::FitShapes(long double lnG, long double lnG1m, long double mean, long double variance)
1113{
1115 double scaledMean = (mean - this->a) * this->bmaInv;
1116 double scaledVar = variance * this->bmaInv * this->bmaInv;
1117 double temp = scaledMean * (1.0 - scaledMean) / scaledVar - 1.0;
1118 double shape1 = 0.001, shape2 = shape1;
1119 if (temp > 0) {
1120 shape1 = scaledMean * temp;
1121 shape2 = (1.0 - scaledMean) * temp;
1122 }
1123 DoublePair shapes = std::make_pair(shape1, shape2);
1124
1127 [lnG, lnG1m](DoublePair x) {
1128 double digammaAlphapBeta = math::digamma(x.first + x.second);
1129 double digammaAlpha = math::digamma(x.first);
1130 double digammaBeta = math::digamma(x.second);
1131 double first = lnG + digammaAlphapBeta - digammaAlpha;
1132 double second = lnG1m + digammaAlphapBeta - digammaBeta;
1133 return DoublePair(first, second);
1134 },
1135 [](DoublePair x) {
1136 double trigammaAlphapBeta = math::trigamma(x.first + x.second);
1137 double trigammaAlpha = math::trigamma(x.first);
1138 double trigammaBeta = math::trigamma(x.second);
1139 DoublePair first = std::make_pair(trigammaAlphapBeta - trigammaAlpha, trigammaAlphapBeta);
1140 DoublePair second = std::make_pair(trigammaAlphapBeta, trigammaAlphapBeta - trigammaBeta);
1141 return std::make_tuple(first, second);
1142 },
1143 shapes))
1144 throw this->fitError(FitErrorCode::Undefined, "Error in root-finding procedure.");
1145 SetShapes(shapes.first, shapes.second);
1146}
1147
1148template <typename RealType>
1149void BetaRand<RealType>::FitShapes(std::span<const RealType> sample)
1150{
1151 if (!this->allElementsAreNotSmallerThan(this->a, sample))
1152 throw this->fitError(FitErrorCode::WrongSample,
1153 this->LOWER_LIMIT_VIOLATION + this->toStringWithPrecision(this->a));
1154 if (!this->allElementsAreNotGreaterThan(this->b, sample))
1155 throw this->fitError(FitErrorCode::WrongSample,
1156 this->UPPER_LIMIT_VIOLATION + this->toStringWithPrecision(this->b));
1157
1158 long double lnG = this->GetSampleLogMeanNorm(sample);
1159 if (!std::isfinite(lnG))
1160 throw this->fitError(FitErrorCode::WrongReturn, this->ALPHA_ZERO);
1161 long double lnG1m = this->GetSampleLog1mMeanNorm(sample);
1162 if (!std::isfinite(lnG1m))
1163 throw this->fitError(FitErrorCode::WrongReturn, this->BETA_ZERO);
1164
1166 DoublePair stats = this->GetSampleMeanAndVariance(sample);
1167 FitShapes(lnG, lnG1m, stats.first, stats.second);
1168}
1169// ARCSINERAND
1170
1171template <typename RealType>
1173{
1174 return "Arcsine(" + this->toStringWithPrecision(GetShape()) + ", " + this->toStringWithPrecision(this->MinValue()) +
1175 ", " + this->toStringWithPrecision(this->MaxValue()) + ")";
1176}
1177
1178template <typename RealType>
1180{
1181 BetaDistribution<RealType>::SetShapes(1.0 - shape, shape);
1182}
1183
1184template <typename RealType>
1185void ArcsineRand<RealType>::FitShape(long double lnG, long double lnG1m)
1186{
1187 double shape = randlib::consts::pi / (lnG1m - lnG);
1188 if (!std::isfinite(shape))
1189 SetShape(0.5);
1190 shape = -randlib::consts::inv_pi * math::atan(shape);
1191 SetShape(shape > 0 ? shape : shape + 1);
1192}
1193
1194template <typename RealType>
1195void ArcsineRand<RealType>::FitShape(std::span<const RealType> sample)
1196{
1197 if (!this->allElementsAreNotSmallerThan(this->a, sample))
1198 throw this->fitError(FitErrorCode::WrongSample,
1199 this->LOWER_LIMIT_VIOLATION + this->toStringWithPrecision(this->a));
1200 if (!this->allElementsAreNotGreaterThan(this->b, sample))
1201 throw this->fitError(FitErrorCode::WrongSample,
1202 this->UPPER_LIMIT_VIOLATION + this->toStringWithPrecision(this->b));
1203
1204 int n = sample.size();
1205 long double lnG = 0, lnG1m = 0;
1206 for (double var : sample) {
1207 double x = (var - this->a) * this->bmaInv;
1208 lnG += std::log(x);
1209 lnG1m += std::log1pl(-x);
1210 }
1211 if (!std::isfinite(lnG))
1212 throw this->fitError(FitErrorCode::WrongReturn, this->ALPHA_ZERO);
1213 if (!std::isfinite(lnG1m))
1214 throw this->fitError(FitErrorCode::WrongReturn, this->BETA_ZERO);
1215 lnG /= n;
1216 lnG1m /= n;
1217 FitShape(lnG, lnG1m);
1218}
1219// BALDINGNICHOLSRAND
1220
1221template <typename RealType>
1222BaldingNicholsRand<RealType>::BaldingNicholsRand(double fixatingIndex, double frequency)
1223{
1224 SetFixatingIndexAndFrequency(fixatingIndex, frequency);
1225}
1226
1227template <typename RealType>
1229{
1230 return "Balding-Nichols(" + this->toStringWithPrecision(GetFixatingIndex()) + ", " +
1231 this->toStringWithPrecision(GetFrequency()) + ")";
1232}
1233
1234template <typename RealType>
1235void BaldingNicholsRand<RealType>::SetFixatingIndexAndFrequency(double fixatingIndex, double frequency)
1236{
1237 if (!(fixatingIndex > 0 && fixatingIndex < 1))
1238 throw std::invalid_argument("Balding-Nichols distribution: fixation index should be in interval (0, 1)");
1239 if (!(frequency > 0 && frequency < 1))
1240 throw std::invalid_argument("Balding-Nichols distribution: frequency should be in interval (0, 1)");
1241 fixationIndex = fixatingIndex;
1242 p = frequency;
1243
1244 double frac = (1.0 - fixationIndex) / fixationIndex, fracP = frac * p;
1245 BetaDistribution<RealType>::SetShapes(fracP, frac - fracP);
1246}
1247
1248} // namespace randlib
1249
The ArcsineRand class Arcsine distribution.
Definition continuous/beta.hpp:340
void SetShape(double shape)
Definition continuous/beta.hpp:1179
void FitShape(long double lnG, long double lnG1m)
set α and β, estimated via maximum likelihood, using sufficient statistics instead of the whole sampl...
Definition continuous/beta.hpp:1185
std::string Name() const override
Definition continuous/beta.hpp:1172
ArcsineRand(double shape=0.5, double minValue=0, double maxValue=1)
Definition continuous/beta.hpp:342
double GetShape() const noexcept
Definition continuous/beta.hpp:351
The BaldingNicholsRand class Balding-Nichols distribution.
Definition continuous/beta.hpp:379
BaldingNicholsRand(double fixatingIndex, double frequency)
Definition continuous/beta.hpp:1222
double GetFixatingIndex() const noexcept
Definition continuous/beta.hpp:387
double GetFrequency() const noexcept
Definition continuous/beta.hpp:388
void SetFixatingIndexAndFrequency(double fixatingIndex, double frequency)
Definition continuous/beta.hpp:1235
std::string Name() const override
Definition continuous/beta.hpp:1228
The BetaDistribution class Abstract class for Beta distribution.
Definition continuous/beta.hpp:33
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition continuous/beta.hpp:808
Support SupportType() const override
Definition continuous/beta.hpp:67
RealType quantileImpl(double p) const override
Definition continuous/beta.hpp:854
double S(const RealType &x) const override
Definition continuous/beta.hpp:521
double logf(const RealType &x) const override
Definition continuous/beta.hpp:477
double alpha
first shape α
Definition continuous/beta.hpp:38
BetaDistribution(double shape1=1, double shape2=1, double minValue=0, double maxValue=1)
Definition continuous/beta.hpp:403
long double MeanAbsoluteDeviation() const
MeanAbsoluteDeviation.
Definition continuous/beta.hpp:842
virtual ~BetaDistribution()
Definition continuous/beta.hpp:65
double f(const RealType &x) const override
Definition continuous/beta.hpp:459
double GetAlpha() const noexcept
Definition continuous/beta.hpp:128
static constexpr char BETA_ZERO[]
Definition continuous/beta.hpp:236
RealType Median() const override
Definition continuous/beta.hpp:789
double b
max bound
Definition continuous/beta.hpp:41
long double ExcessKurtosis() const override
Definition continuous/beta.hpp:829
std::complex< double > CFImpl(double t) const override
Definition continuous/beta.hpp:890
double GetBetaFunction() const noexcept
Definition continuous/beta.hpp:136
double logbma
log(b-a)
Definition continuous/beta.hpp:44
double beta
second shape β
Definition continuous/beta.hpp:39
double GetLogBetaFunction() const noexcept
Definition continuous/beta.hpp:140
void SetSupport(double minValue, double maxValue)
Definition continuous/beta.hpp:446
long double Variance() const override
Definition continuous/beta.hpp:774
double bmaInv
1/(b-a)
Definition continuous/beta.hpp:43
long double Skewness() const override
Definition continuous/beta.hpp:819
double a
min bound
Definition continuous/beta.hpp:40
RealType MinValue() const override
Definition continuous/beta.hpp:68
long double Mean() const override
Definition continuous/beta.hpp:761
GammaRand< RealType > GammaRV2
Definition continuous/beta.hpp:46
RealType quantileImpl1m(double p) const override
Definition continuous/beta.hpp:872
long double GeometricMean() const
Definition continuous/beta.hpp:768
double bma
b-a
Definition continuous/beta.hpp:42
void SetShapes(double shape1, double shape2)
Definition continuous/beta.hpp:432
RealType operator()(G &g) const
Definition continuous/beta.hpp:670
RealType MaxValue() const override
Definition continuous/beta.hpp:69
static constexpr char ALPHA_ZERO[]
Definition continuous/beta.hpp:234
long double GeometricVariance() const
Definition continuous/beta.hpp:783
GammaRand< RealType > GammaRV1
Definition continuous/beta.hpp:46
double GetBeta() const noexcept
Definition continuous/beta.hpp:132
double F(const RealType &x) const override
Definition continuous/beta.hpp:505
The BetaRand class Beta distribution.
Definition continuous/beta.hpp:246
DoublePair SourceParameters() const override
Definition continuous/beta.hpp:956
std::string Name() const override
Definition continuous/beta.hpp:941
void FitAlpha(std::span< const RealType > sample)
set α, estimated via maximum likelihood
Definition continuous/beta.hpp:1049
DoublePair SourceToNatural(DoublePair sourceParameters) const override
Definition continuous/beta.hpp:962
double CarrierMeasure(RealType) const override
Definition continuous/beta.hpp:983
void FitAlpha(long double lnG, long double meanNorm)
set α, estimated via maximum likelihood, using sufficient statistics instead of the whole sample
Definition continuous/beta.hpp:1022
double LogNormalizer(DoublePair theta) const override
Definition continuous/beta.hpp:968
void FitShapes(std::span< const RealType > sample)
set α and β, estimated via maximum likelihood
Definition continuous/beta.hpp:1149
long double GetSampleLogMeanNorm(std::span< const RealType > sample) const
GetSampleLogMeanNorm.
Definition continuous/beta.hpp:989
DoublePair SufficientStatistic(RealType x) const override
Definition continuous/beta.hpp:949
void FitBeta(long double lnG1m, long double meanNorm)
set β, estimated via maximum likelihood, using sufficient statistics instead of the whole sample
Definition continuous/beta.hpp:1068
void FitBeta(std::span< const RealType > sample)
set β, estimated via maximum likelihood
Definition continuous/beta.hpp:1093
long double GetSampleLog1pMeanNorm(std::span< const RealType > sample) const
GetSampleLog1pMeanNorm.
Definition continuous/beta.hpp:1000
void FitShapes(long double lnG, long double lnG1m, long double mean, long double variance)
set α and β, estimated via maximum likelihood, using sufficient statistics instead of the whole sampl...
Definition continuous/beta.hpp:1112
DoublePair LogNormalizerGradient(DoublePair theta) const override
Definition continuous/beta.hpp:974
BetaRand(double shape1=1, double shape2=1, double minValue=0, double maxValue=1)
Definition continuous/beta.hpp:248
long double GetSampleLog1mMeanNorm(std::span< const RealType > sample) const
GetSampleLog1mMeanNorm.
Definition continuous/beta.hpp:1011
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
Definition exponential_family.hpp:14
The GammaRand class Gamma distribution.
Definition continuous/gamma.hpp:295
virtual std::complex< double > CFImpl(double t) const
Definition univariate.hpp:365
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
#define RANDLIB_DETAIL_SUPPRESS_DEPRECATED_END
Definition fwd.hpp:26
#define RANDLIB_DETAIL_SUPPRESS_DEPRECATED_BEGIN
Definition fwd.hpp:25
#define RANDLIB_DEPRECATED_FIT_MEMBER
Definition fwd.hpp:9
constexpr long double inv_pi
Definition constants.hpp:24
constexpr long double ln2
Definition constants.hpp:18
constexpr long double pi
Definition constants.hpp:22
constexpr long double two_inv_pi
Definition constants.hpp:25
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 digamma(Real x)
Definition math/gamma.hpp:691
Real logBeta(Real a, std::type_identity_t< Real > b)
Calculate logarithm of beta function.
Definition math/beta.hpp:72
Real atan(Real x)
Definition functions.hpp:238
Real ibeta(Real x, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > logBetaFun, std::type_identity_t< Real > logX, std::type_identity_t< Real > log1mX)
Fast calculation of regularized beta function, using precalculated values.
Definition math/beta.hpp:250
Real trigamma(Real x)
Definition math/gamma.hpp:720
bool findRootNewtonFirstOrder2d(const std::function< DoublePair(DoublePair)> &funPtr, const std::function< std::tuple< DoublePair, DoublePair >(DoublePair)> &gradPtr, DoublePair &root, long double funTol=1e-10, long double stepTol=1e-6)
Newton's root-finding procedure for 2 functions of 2 parameters, using Jacobian matrix.
Definition roots.hpp:347
Real integrate(const F &f, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > tolerance=1e-11, int maxSubdivisions=512)
Global adaptive Gauss-Kronrod quadrature (QUADPACK QAG).
Definition quadrature.hpp:226
Definition bivariate_normal.hpp:10
@ WrongSample
the sample could not have been drawn from this distribution
@ NotApplicable
the method cannot be applied to this distribution or sample
@ WrongReturn
the method returned invalid parameters
@ Undefined
any other failure
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
Pair< double > DoublePair
Definition fwd.hpp:39