27template <
typename IntType>
44 double delta1{}, delta2{};
45 double sigma1{}, sigma2{}, c{};
46 double a1{}, a2{}, a3{}, a4{};
47 double coefa3{}, coefa4{};
51 double logPFloor = -INFINITY;
58 GeometricRand<IntType> geometric{};
65 [[nodiscard]] IntType
MinValue()
const override {
return 0; }
66 [[nodiscard]] IntType
MaxValue()
const override {
return n; }
69 void SetGeneratorConstants();
75 [[nodiscard]]
inline IntType
GetNumber() const noexcept {
return n; }
92 double logProbFloor(
int k)
const;
95 [[nodiscard]]
double P(
const IntType &k)
const override;
96 [[nodiscard]]
double logP(
const IntType &k)
const override;
97 [[nodiscard]]
double F(
const IntType &k)
const override;
98 [[nodiscard]]
double S(
const IntType &k)
const override;
108 [[nodiscard]] GENERATOR_ID GetIdOfUsedGenerator()
const
113 return BERNOULLI_SUM;
116 if ((npFloor <= 12) || (pRes > 0 && npFloor <= 16))
123 template <std::uniform_random_bit_generator G>
124 IntType variateRejection(G &g)
const;
125 template <std::uniform_random_bit_generator G>
126 IntType variateWaiting(IntType number, G &g)
const;
127 template <std::uniform_random_bit_generator G>
128 static IntType variateWaiting(IntType number,
double probability, G &g);
129 template <std::uniform_random_bit_generator G>
130 static IntType variateBernoulliSum(IntType number,
double probability, G &g);
131 template <std::uniform_random_bit_generator G>
132 static IntType variateInversion(IntType number,
double probability, G &g);
133 template <std::uniform_random_bit_generator G>
134 static IntType variateTransformedRejection(IntType number,
double probability, G &g);
137 template <std::uniform_random_bit_generator G>
140 template <std::uniform_random_bit_generator G>
141 [[nodiscard]]
static IntType
Variate(IntType number,
double probability, G &g);
143 [[nodiscard]]
long double Mean()
const override;
144 [[nodiscard]]
long double Variance()
const override;
145 [[nodiscard]] IntType
Median()
const override;
146 [[nodiscard]] IntType
Mode()
const override;
147 [[nodiscard]]
long double Skewness()
const override;
164 std::complex<double> CFImpl(
double t)
const override;
195template <
typename IntType>
200 [[nodiscard]] std::string
Name()
const override;
215template <
typename IntType>
218 SetParameters(number, probability);
221template <
typename IntType>
224 minpq = std::min(p, q);
227 npFloor = std::floor(n * minpq);
228 pFloor = npFloor / n;
231 GENERATOR_ID genId = GetIdOfUsedGenerator();
232 if (genId == BERNOULLI_SUM)
234 else if (genId == WAITING) {
235 geometric.SetProbability(minpq);
239 nqFloor = n - npFloor;
240 double qFloor = 1.0 - pFloor;
242 geometric.SetProbability(pRes / qFloor);
245 double npq = npFloor * qFloor;
247 delta1 = coef * pFloor / (81.0 * qFloor);
248 delta1 = npq * std::log(delta1);
250 delta1 = std::sqrt(delta1);
253 delta2 = coef * qFloor / pFloor;
254 delta2 = npq * std::log(delta2);
256 delta2 = std::sqrt(delta2);
261 double npqSqrt = std::sqrt(npq);
262 sigma1 = npqSqrt * (1.0 + 0.25 * delta1 / npFloor);
263 sigma2 = npqSqrt * (1.0 + 0.25 * delta2 / nqFloor);
264 c = 2.0 * delta1 / npFloor;
272 coefa3 = 0.5 * delta1 / (sigma1 * sigma1);
273 a3 = 1.0 / nqFloor - coefa3;
279 coefa4 = 0.5 * delta2 / (sigma2 * sigma2);
280 a4 = std::exp(-delta2 * coefa4) / coefa4;
283 logPFloor = std::log(pFloor);
284 logQFloor = (pFloor == qFloor) ? logPFloor : std::log1pl(-pFloor);
286 logPnpInv = logProbFloor(npFloor);
289template <
typename IntType>
292 if (!(probability >= 0.0 && probability <= 1.0))
293 throw std::invalid_argument(
"Binomial distribution: probability parameter should in interval [0, 1]");
295 throw std::invalid_argument(
"Binomial distribution: number should be positive");
301 logProb = std::log(p);
302 log1mProb = std::log1pl(-p);
303 SetGeneratorConstants();
306template <
typename IntType>
312template <
typename IntType>
318template <
typename IntType>
321 return std::log(sourceParameters) - std::log1p(-sourceParameters);
324template <
typename IntType>
327 return this->logProb - this->log1mProb;
330template <
typename IntType>
338template <
typename IntType>
341 double expTheta = std::exp(theta);
342 return this->n * expTheta / (1.0 + expTheta);
345template <
typename IntType>
353template <
typename IntType>
356 double H = this->p * this->logProb;
357 H += this->q * this->log1mProb;
363template <
typename IntType>
370 y += (n - k) * logQFloor;
374template <
typename IntType>
377 return (k < 0 || k > n) ? 0.0 : std::exp(logP(k));
380template <
typename IntType>
386 return n * log1mProb;
392 return y - 0.5 * std::log(2 *
randlib::consts::pi * k * (1.0 -
static_cast<double>(k) / n));
395template <
typename IntType>
402 int nmk = n - k, kp1 = k + 1;
405 return math::ibeta(q, nmk, kp1, logBetaFun, log1mProb, logProb);
408template <
typename IntType>
415 int nmk = n - k, kp1 = k + 1;
417 return math::ibeta(p, kp1, nmk, logBetaFun, logProb, log1mProb);
420template <
typename IntType>
421template <std::uniform_random_bit_generator G>
435 Y = sigma1 * std::fabs(N);
436 reject = (Y >= delta1);
440 V = -W - 0.5 * N * N + c;
442 }
else if (U <= a2) {
444 Y = sigma2 * std::fabs(N);
445 reject = (Y >= delta2);
449 V = -W - 0.5 * N * N;
451 }
else if (U <= a3) {
454 Y = delta1 + W1 / coefa3;
456 V = -W2 - coefa3 * Y + delta1 / nqFloor;
461 Y = delta2 + W1 / coefa4;
463 V = -W2 - coefa4 * Y;
469 if (X >= 0 && X <= n && V <= logProbFloor(X) - logPnpInv)
472 }
while (++iter <= ProbabilityDistribution<IntType>::MAX_ITER_REJECTION);
473 throw std::runtime_error(
"Binomial distribution: sampling failed");
476template <
typename IntType>
477template <std::uniform_random_bit_generator G>
478IntType BinomialDistribution<IntType>::variateWaiting(IntType number, G &g)
const
482 IntType X = 0, sum = 0;
484 IntType wait = geometric(g);
485 if (wait >= number - sum)
492template <
typename IntType>
493template <std::uniform_random_bit_generator G>
494IntType BinomialDistribution<IntType>::variateWaiting(IntType number,
double probability, G &g)
496 IntType X = 0, sum = 0;
499 if (wait >= number - sum)
506template <
typename IntType>
507template <std::uniform_random_bit_generator G>
508IntType BinomialDistribution<IntType>::variateBernoulliSum(IntType number,
double probability, G &g)
512 for (
int i = 0; i != number; ++i)
515 for (
int i = 0; i != number; ++i)
521template <
typename IntType>
522template <std::uniform_random_bit_generator G>
529 GENERATOR_ID genId = GetIdOfUsedGenerator();
532 IntType var = variateWaiting(n, g);
533 return (p <= 0.5) ? var : n - var;
538 IntType Z = variateRejection(g);
540 Z += variateWaiting(n - Z, g);
541 return (p > 0.5) ? n - Z : Z;
544 return variateBernoulliSum(n, p, g);
546 throw std::invalid_argument(
"Binomial distribution: invalid generator id");
550template <
typename IntType>
551template <std::uniform_random_bit_generator G>
556 throw std::invalid_argument(
"Binomial distribution: number should be positive, but it's equal to " +
557 std::to_string(number));
558 if (!(probability >= 0.0 && probability <= 1.0))
559 throw std::invalid_argument(
560 "Binomial distribution: probability parameter should in interval [0, 1], but it's equal to " +
561 std::to_string(probability));
562 if (probability == 0.0)
564 if (probability == 1.0)
568 return variateBernoulliSum(number, probability, g);
569 const bool complement = probability >= 0.5;
570 const double q = complement ? 1.0 - probability : probability;
571 const IntType var = (number * q < 10) ? variateInversion(number, q, g) : variateTransformedRejection(number, q, g);
572 return complement ? number - var : var;
575template <
typename IntType>
576template <std::uniform_random_bit_generator G>
580 const double ratio = probability / (1.0 - probability), first = std::exp(number * std::log1p(-probability));
581 for (
size_t iter = 0; iter < ProbabilityDistribution<IntType>::MAX_ITER_REJECTION; ++iter) {
583 double probabilityOfK = first, cumulative = first;
585 while (u > cumulative && probabilityOfK > 0 && k < number) {
587 probabilityOfK *= ratio *
static_cast<double>(number - k + 1) / k;
588 cumulative += probabilityOfK;
594 throw std::runtime_error(
"Binomial distribution: sampling failed");
597template <
typename IntType>
598template <std::uniform_random_bit_generator G>
599IntType BinomialDistribution<IntType>::variateTransformedRejection(IntType number,
double probability, G &g)
603 const double q = 1.0 - probability, spq = std::sqrt(number * probability * q);
604 const double b = 1.15 + 2.53 * spq, a = -0.0873 + 0.0248 * b + 0.01 * probability;
605 const double c = number * probability + 0.5, squeeze = 0.92 - 4.2 / b, alpha = (2.83 + 5.1 / b) * spq;
606 const double n = number, mode = std::floor((n + 1) * probability);
607 const double logOddsAtMode = std::log((n - mode + 1) * probability / ((mode + 1) * q));
608 auto correction = [](
double x) {
return math::stirlingError<double>(
static_cast<size_t>(x) + 1); };
609 const double peakCorrection = correction(mode) + correction(n - mode);
610 for (
size_t iter = 0; iter < 1000 * ProbabilityDistribution<IntType>::MAX_ITER_REJECTION; ++iter) {
612 const double us = 0.5 - std::fabs(u);
613 const double x = std::floor((2 * a / us + b) * u + c);
616 if (us >= 0.07 && v <= squeeze)
617 return static_cast<IntType
>(x);
619 const double logRatio = (x + 0.5) * std::log1p((mode - x) / (x + 1)) +
620 (n - x + 0.5) * std::log1p((x - mode) / (n - x + 1)) + (x - mode) * logOddsAtMode +
621 peakCorrection - correction(x) - correction(n - x);
622 if (std::log(v * alpha / (a / (us * us) + b)) <= logRatio)
623 return static_cast<IntType
>(x);
625 throw std::runtime_error(
"Binomial distribution: sampling failed");
628template <
typename IntType>
629void BinomialDistribution<IntType>::sample(detail::EngineRef g, std::span<IntType> outputData)
const
632 std::fill(outputData.begin(), outputData.end(), 0);
636 std::fill(outputData.begin(), outputData.end(), n);
640 GENERATOR_ID genId = GetIdOfUsedGenerator();
644 for (IntType &var : outputData)
645 var = variateWaiting(n, g);
647 for (IntType &var : outputData)
648 var = n - variateWaiting(n, g);
653 for (IntType &var : outputData)
654 var = variateRejection(g);
656 for (IntType &var : outputData)
657 var += variateWaiting(n - var, g);
660 for (IntType &var : outputData)
667 for (IntType &var : outputData)
668 var = variateBernoulliSum(n, p, g);
674template <
typename IntType>
680template <
typename IntType>
686template <
typename IntType>
690 IntType lower = std::floor(np);
691 return (this->F(lower) >= 0.5) ? lower : lower + 1;
694template <
typename IntType>
697 return std::min(n,
static_cast<IntType
>(std::floor(np + p)));
700template <
typename IntType>
703 return (q - p) / std::sqrt(np * q);
706template <
typename IntType>
709 long double y = 1.0 / (p * q);
714template <
typename IntType>
717 std::complex<double> y(q + p * std::cos(t), p * std::sin(t));
718 return std::pow(y, n);
721template <
typename IntType>
724 if (!this->allElementsAreNonNegative(sample))
726 if (!this->allElementsAreNotGreaterThan(n, sample))
728 SetParameters(n, this->GetSampleMean(sample) / n);
731template <
typename IntType>
735 if (!this->allElementsAreNonNegative(sample))
737 if (!this->allElementsAreNotGreaterThan(n, sample))
739 int N = sample.size();
740 double sum = this->GetSampleSum(sample);
741 double alpha = priorDistribution.
GetAlpha();
742 double beta = priorDistribution.
GetBeta();
743 BetaRand posteriorDistribution(sum + alpha, N * n - sum + beta);
744 SetParameters(n, MAP ? posteriorDistribution.
Mode() : posteriorDistribution.
Mean());
745 return posteriorDistribution;
748template <
typename IntType>
751 double shape = 0.5 * std::sqrt(n);
753 return FitProbabilityBayes(sample, B);
755template <
typename IntType>
758 return "Binomial(" + this->toStringWithPrecision(this->GetNumber()) +
", " +
759 this->toStringWithPrecision(this->GetProbability()) +
")";
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
double GetAlpha() const noexcept
Definition continuous/beta.hpp:128
long double Mean() const override
Definition continuous/beta.hpp:761
double GetBeta() const noexcept
Definition continuous/beta.hpp:132
The BetaRand class Beta distribution.
Definition continuous/beta.hpp:246
The BinomialDistribution class Abstract class for Binomial distribution.
Definition binomial.hpp:29
long double Variance() const override
Definition binomial.hpp:681
double EntropyAdjusted() const override
Definition binomial.hpp:354
long double Mean() const override
Definition binomial.hpp:675
Support SupportType() const override
Definition binomial.hpp:64
double F(const IntType &k) const override
Definition binomial.hpp:396
double LogNormalizerGradient(double theta) const override
Definition binomial.hpp:339
double P(const IntType &k) const override
Definition binomial.hpp:375
double GetLogProbability() const noexcept
Definition binomial.hpp:157
BetaRand FitProbabilityMinimax(std::span< const IntType > sample)
Fit probability p with minimax estimator.
Definition binomial.hpp:749
double NaturalParameters() const override
Definition binomial.hpp:325
double GetLog1mProbability() const noexcept
Definition binomial.hpp:161
double SufficientStatistic(IntType x) const override
Definition binomial.hpp:307
double logProb
log(p)
Definition binomial.hpp:36
void SetParameters(IntType number, double probability)
Definition binomial.hpp:290
double logP(const IntType &k) const override
Definition binomial.hpp:381
IntType operator()(G &g) const
Definition binomial.hpp:523
double S(const IntType &k) const override
Definition binomial.hpp:409
long double ExcessKurtosis() const override
Definition binomial.hpp:707
double q
probability of failure
Definition binomial.hpp:35
IntType MaxValue() const override
Definition binomial.hpp:66
BinomialDistribution(IntType number, double probability)
Definition binomial.hpp:216
BetaRand FitProbabilityBayes(std::span< const IntType > sample, const BetaDistribution<> &priorDistribution, bool MAP=false)
Fit probability p with prior assumption p ~ Beta(α, β)
Definition binomial.hpp:732
IntType MinValue() const override
Definition binomial.hpp:65
IntType Median() const override
Definition binomial.hpp:687
double SourceParameters() const override
Definition binomial.hpp:313
double GetProbability() const noexcept
Definition binomial.hpp:76
double SourceToNatural(double sourceParameters) const override
Definition binomial.hpp:319
IntType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition binomial.hpp:695
void FitProbability(std::span< const IntType > sample)
Fit probability p with maximum-likelihood estimation.
Definition binomial.hpp:722
double CarrierMeasure(IntType x) const override
Definition binomial.hpp:346
double log1mProb
log(q)
Definition binomial.hpp:37
double LogNormalizer(double theta) const override
Definition binomial.hpp:331
double p
probability of success
Definition binomial.hpp:34
long double Skewness() const override
Definition binomial.hpp:701
static IntType Variate(IntType number, double probability, G &g)
Definition binomial.hpp:552
double GetLogFactorialN() const noexcept
Definition binomial.hpp:153
IntType GetNumber() const noexcept
Definition binomial.hpp:75
The BinomialRand class Binomial distribution.
Definition binomial.hpp:197
BinomialRand(int number=1, double probability=0.5)
Definition binomial.hpp:199
std::string Name() const override
Definition binomial.hpp:756
The DiscreteDistribution class Abstract class for all discrete distributions.
Definition discrete.hpp:21
Definition exponential_family.hpp:14
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_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 ln2
Definition constants.hpp:18
constexpr long double pi
Definition constants.hpp:22
constexpr long double sqrt2pi
Definition constants.hpp:32
std::uint64_t randomBits(G &g, int count)
Definition engine/uniform.hpp:33
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 logBeta(Real a, std::type_identity_t< Real > b)
Calculate logarithm of beta function.
Definition math/beta.hpp:72
Real lfact(size_t n)
Calculate log(n!) using table values for small n <= 255 and built-in lgamma function for large n > 25...
Definition math/gamma.hpp:591
Real bd0(std::type_identity_t< Real > x, Real m)
Deviance term of the saddle-point expansions of Poisson and binomial probabilities (C.
Definition math/gamma.hpp:620
Real stirlingError(size_t n)
Definition math/gamma.hpp:598
Real softplus(Real x)
Definition functions.hpp:252
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
Definition bivariate_normal.hpp:10
@ WrongSample
the sample could not have been drawn from this distribution
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15