RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
negative_hypergeometric.hpp
Go to the documentation of this file.
1#pragma once
2
8
9namespace randlib
10{
11
18template <typename IntType>
20{
21 IntType variate(detail::EngineRef g) const override { return (*this)(g); }
22
23 IntType N = 1;
24 IntType M = 1;
25 IntType m = 1;
26 double pmfCoef = 1;
27 BetaRand<double> successFraction{};
28
29public:
30 NegativeHyperGeometricRand(IntType totalSize = 1, IntType totalSuccessesNum = 1, IntType limitSuccessesNum = 1);
31 [[nodiscard]] std::string Name() const override;
32 [[nodiscard]] Support SupportType() const override { return Support::Finite; }
33 [[nodiscard]] IntType MinValue() const override { return 0; }
34 [[nodiscard]] IntType MaxValue() const override { return N - M; }
35
36 void SetParameters(IntType totalSize, IntType totalSuccessesNum, IntType limitSuccessesNum);
37 [[nodiscard]] inline IntType GetTotalSize() { return N; }
38 [[nodiscard]] inline IntType GetTotalSuccessesNum() { return M; }
39 [[nodiscard]] inline IntType GetLimitSuccessesNum() { return m; }
40
41 [[nodiscard]] double P(const IntType &k) const override;
42 [[nodiscard]] double logP(const IntType &k) const override;
43 [[nodiscard]] double F(const IntType &k) const override;
44 template <std::uniform_random_bit_generator G>
45 [[nodiscard]] IntType operator()(G &g) const;
46
47 [[nodiscard]] long double Mean() const override;
48 [[nodiscard]] long double Variance() const override;
49
50private:
52 static constexpr double SMALL_URN = 16;
53 template <std::uniform_random_bit_generator G>
54 IntType variateByUrn(G &g) const;
55};
56
57} // namespace randlib
58
61
62namespace randlib
63{
64
65template <typename IntType>
66NegativeHyperGeometricRand<IntType>::NegativeHyperGeometricRand(IntType totalSize, IntType totalSuccessesNum,
67 IntType limitSuccessesNum)
68{
69 SetParameters(totalSize, totalSuccessesNum, limitSuccessesNum);
70}
71
72template <typename IntType>
74{
75 return "Negative hypergeometric(" + this->toStringWithPrecision(N) + ", " + this->toStringWithPrecision(M) + ", " +
76 this->toStringWithPrecision(m) + ")";
77}
78
79template <typename IntType>
80void NegativeHyperGeometricRand<IntType>::SetParameters(IntType totalSize, IntType totalSuccessesNum,
81 IntType limitSuccessesNum)
82{
83 if (!(totalSize > 0 && totalSuccessesNum > 0 && limitSuccessesNum > 0))
84 throw std::invalid_argument("Negative-HyperGeometric distribution: all parameters should be positive");
85 if (!(totalSuccessesNum <= totalSize))
86 throw std::invalid_argument(
87 "Negative-HyperGeometric distribution: total size shouldn't be smaller than total successes number");
88 if (!(limitSuccessesNum <= totalSuccessesNum))
89 throw std::invalid_argument("Negative-HyperGeometric distribution: total successes number shouldn't be smaller "
90 "than limit successes number");
91
92 N = totalSize;
93 M = totalSuccessesNum;
94 m = limitSuccessesNum;
95
96 successFraction.SetShapes(m, M - m + 1);
97 pmfCoef = math::lfact(M);
98 pmfCoef += math::lfact(N - M);
99 pmfCoef -= math::lfact(m - 1);
100 pmfCoef -= math::lfact(M - m);
101 pmfCoef -= math::lfact(N);
102}
103
104template <typename IntType>
105double NegativeHyperGeometricRand<IntType>::P(const IntType &k) const
106{
107 return (k < MinValue() || k > MaxValue()) ? 0.0 : std::exp(logP(k));
108}
109
110template <typename IntType>
111double NegativeHyperGeometricRand<IntType>::logP(const IntType &k) const
112{
113 if (k < MinValue() || k > MaxValue())
114 return -INFINITY;
115 double p = math::lfact(k + m - 1);
116 p += math::lfact(N - m - k);
117 p -= math::lfact(k);
118 p -= math::lfact(N - M - k);
119 return p + pmfCoef;
120}
121
122template <typename IntType>
123double NegativeHyperGeometricRand<IntType>::F(const IntType &k) const
124{
125 // relation with hypergeometric distribution can be used here instead
126 if (k < MinValue())
127 return 0.0;
128 IntType maxVal = MaxValue();
129 if (k >= maxVal)
130 return 1.0;
131 if (k <= 0.5 * maxVal) {
133 double sum = 0;
134 for (IntType i = 0; i <= k; ++i)
135 sum += P(i);
136 return sum;
137 }
139 double sum = 1.0;
140 for (IntType i = k + 1; i <= maxVal; ++i)
141 sum -= P(i);
142 return sum;
143}
144
145template <typename IntType>
146template <std::uniform_random_bit_generator G>
148{
150 const double expectedDraws = m * (static_cast<double>(N) + 1) / (static_cast<double>(M) + 1);
151 if (expectedDraws < SMALL_URN)
152 return variateByUrn(g);
153 return BinomialDistribution<IntType>::Variate(N - M, successFraction(g), g);
154}
155
156template <typename IntType>
157template <std::uniform_random_bit_generator G>
159{
160 double p = static_cast<double>(M) / N;
161 IntType successesNum = 0;
162 IntType num = 0;
163 while (successesNum < m) {
164 ++num;
165 if (BernoulliRand::Variate(p, g) && ++successesNum == num - N + M)
166 return N - M;
167 p = M - successesNum;
168 p /= N - num;
169 }
170 return num - successesNum;
171}
172
173template <typename IntType>
175{
176 long double mean = m;
177 mean *= N - M;
178 mean /= static_cast<long double>(M) + 1.0L;
179 return mean;
180}
181
182template <typename IntType>
184{
185 long double Mp1 = static_cast<long double>(M) + 1.0L;
186 long double var = 1.0L - m / Mp1;
187 var *= static_cast<long double>(N) + 1.0L;
188 var *= N - M;
189 var /= Mp1 * (Mp1 + 1);
190 return m * var;
191}
192
193} // namespace randlib
The BetaRand class Beta distribution.
Definition continuous/beta.hpp:246
The DiscreteDistribution class Abstract class for all discrete distributions.
Definition discrete.hpp:21
The NegativeHyperGeometricRand class Negative hypergeometric distribution.
Definition negative_hypergeometric.hpp:20
Support SupportType() const override
Definition negative_hypergeometric.hpp:32
IntType operator()(G &g) const
Definition negative_hypergeometric.hpp:147
IntType GetLimitSuccessesNum()
Definition negative_hypergeometric.hpp:39
double P(const IntType &k) const override
Definition negative_hypergeometric.hpp:105
NegativeHyperGeometricRand(IntType totalSize=1, IntType totalSuccessesNum=1, IntType limitSuccessesNum=1)
Definition negative_hypergeometric.hpp:66
IntType GetTotalSuccessesNum()
Definition negative_hypergeometric.hpp:38
long double Variance() const override
Definition negative_hypergeometric.hpp:183
double logP(const IntType &k) const override
Definition negative_hypergeometric.hpp:111
IntType MinValue() const override
Definition negative_hypergeometric.hpp:33
double F(const IntType &k) const override
Definition negative_hypergeometric.hpp:123
void SetParameters(IntType totalSize, IntType totalSuccessesNum, IntType limitSuccessesNum)
Definition negative_hypergeometric.hpp:80
IntType GetTotalSize()
Definition negative_hypergeometric.hpp:37
long double Mean() const override
Definition negative_hypergeometric.hpp:174
std::string Name() const override
Definition negative_hypergeometric.hpp:73
IntType MaxValue() const override
Definition negative_hypergeometric.hpp:34
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
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
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15