17template <
typename IntType>
28 HyperGeometricRand(IntType totalSize = 1, IntType drawsNum = 1, IntType successesNum = 1);
29 [[nodiscard]] std::string
Name()
const override;
31 [[nodiscard]] IntType
MinValue()
const override {
return std::max(
static_cast<IntType
>(0), n - N + K); }
32 [[nodiscard]] IntType
MaxValue()
const override {
return std::min(n, K); }
34 void SetParameters(IntType totalSize, IntType drawsNum, IntType successesNum);
39 [[nodiscard]]
double P(
const IntType &k)
const override;
40 [[nodiscard]]
double logP(
const IntType &k)
const override;
41 [[nodiscard]]
double F(
const IntType &k)
const override;
42 template <std::uniform_random_bit_generator G>
47 static constexpr IntType SMALL_SAMPLE = 10;
48 template <std::uniform_random_bit_generator G>
49 IntType variateByUrn(IntType draws, IntType successes, G &g)
const;
50 template <std::uniform_random_bit_generator G>
51 IntType variateRatioOfUniforms(IntType draws, IntType successes, G &g)
const;
54 [[nodiscard]]
long double Mean()
const override;
55 [[nodiscard]]
long double Variance()
const override;
56 [[nodiscard]] IntType
Mode()
const override;
57 [[nodiscard]]
long double Skewness()
const override;
69template <
typename IntType>
72 SetParameters(totalSize, drawsNum, successesNum);
75template <
typename IntType>
78 return "Hypergeometric(" + this->toStringWithPrecision(N) +
", " + this->toStringWithPrecision(n) +
", " +
79 this->toStringWithPrecision(K) +
")";
82template <
typename IntType>
85 if (!(totalSize > 0 && drawsNum > 0 && successesNum > 0))
86 throw std::invalid_argument(
"HyperGeometric distribution: all parameters should be positive");
87 if (!(drawsNum <= totalSize))
88 throw std::invalid_argument(
"HyperGeometric distribution: total size should be greater than draws number");
89 if (!(successesNum <= totalSize))
90 throw std::invalid_argument(
"HyperGeometric distribution: total size should be greater than successes number");
103template <
typename IntType>
106 return (k < MinValue() || k > MaxValue()) ? 0.0 : std::exp(logP(k));
109template <
typename IntType>
112 if (k < MinValue() || k > MaxValue())
121template <
typename IntType>
124 IntType minVal = MinValue();
127 IntType maxVal = MaxValue();
130 if (k - minVal <= maxVal - k) {
133 for (IntType i = minVal; i <= k; ++i)
139 for (IntType i = k + 1; i <= maxVal; ++i)
144template <
typename IntType>
145template <std::uniform_random_bit_generator G>
150 const bool complementDraws = 2 * n > N, complementSuccesses = 2 * K > N;
151 const IntType draws = complementDraws ? N - n : n;
152 const IntType successes = complementSuccesses ? N - K : K;
153 const IntType reduced =
154 (draws < SMALL_SAMPLE) ? variateByUrn(draws, successes, g) : variateRatioOfUniforms(draws, successes, g);
155 IntType result = complementSuccesses ? draws - reduced : reduced;
161template <
typename IntType>
162template <std::uniform_random_bit_generator G>
167 for (IntType i = 0; i < draws && sum < successes; ++i) {
168 const double p =
static_cast<double>(successes - sum) / (N - i);
175template <
typename IntType>
176template <std::uniform_random_bit_generator G>
177IntType HyperGeometricRand<IntType>::variateRatioOfUniforms(IntType draws, IntType successes, G &g)
const
181 static constexpr double D1 = 1.7155277699214135, D2 = 0.8989161620588988;
182 const IntType failures = N - successes;
183 const double p =
static_cast<double>(successes) / N, q =
static_cast<double>(failures) / N;
184 const double a = draws * p + 0.5;
185 const double c = std::sqrt(
static_cast<double>(N - draws) * draws * p * q / (N - 1) + 0.5);
186 const double h = D1 * c + D2;
187 const IntType mode =
static_cast<IntType
>(std::floor((draws + 1.0) * (successes + 1.0) / (N + 2.0)));
189 auto logRatioToPeak = [draws, successes, failures, mode](IntType k) {
190 auto ratio = [](IntType x, IntType y) {
193 return ratio(mode, k) + ratio(successes - mode, successes - k) + ratio(draws - mode, draws - k) +
194 ratio(failures - draws + mode, failures - draws + k);
196 const double end =
static_cast<double>(std::min(draws, successes)) + 1;
197 for (
size_t iter = 0; iter < 1000 * ProbabilityDistribution<IntType>::MAX_ITER_REJECTION; ++iter) {
199 const double x = a + h * (v - 0.5) / u;
200 if (x < 0 || x >= end)
202 const IntType k =
static_cast<IntType
>(std::floor(x));
203 const double t = logRatioToPeak(k);
204 if (u * (4 - u) - 3 <= t)
206 if (u * (u - t) >= 1)
208 if (2 * std::log(u) <= t)
211 throw std::runtime_error(
"HyperGeometric distribution: sampling failed");
214template <
typename IntType>
217 return static_cast<long double>(n) * K / N;
220template <
typename IntType>
223 if (n == N || K == N)
225 long double numerator = n;
229 long double denominator = N;
231 denominator *= N - 1;
232 return numerator / denominator;
235template <
typename IntType>
238 long double mode = (
static_cast<long double>(n) + 1.0L) * (
static_cast<long double>(K) + 1.0L);
239 return static_cast<IntType
>(std::floor(mode / (
static_cast<long double>(N) + 2.0L)));
242template <
typename IntType>
245 if (n == N || K == N)
249 long double population = N, draws = n, successes = K;
250 long double skewness = population - 1.0L;
252 skewness /= successes;
253 skewness /= population - successes;
254 skewness /= population - draws;
255 skewness = std::sqrt(skewness);
256 skewness *= population - 2.0L * successes;
257 skewness *= population - 2.0L * draws;
258 return skewness / (population - 2.0L);
261template <
typename IntType>
264 long double variance = Variance();
265 if (variance == 0.0L)
268 long double mean = Mean(), fourthMoment = 0.0L;
269 for (IntType k = MinValue(); k <= MaxValue(); ++k) {
270 long double centered = k - mean;
271 fourthMoment += centered * centered * centered * centered * P(k);
273 return fourthMoment / (variance * variance) - 3.0L;
276 long double population = N, draws = n, successes = K;
277 long double numerator = population * (population + 1.0L);
278 long double a1 = successes * (population - successes);
279 long double a2 = draws * (population - draws);
280 numerator -= 6 * (a1 + a2);
281 numerator *= population * population * (population - 1.0L);
282 long double aux = draws * successes * (population - successes) * (population - draws);
283 numerator += 6.0L * aux * (5.0L * population - 6.0L);
284 long double denominator = aux * (population - 2.0L) * (population - 3.0L);
285 return numerator / denominator;
The DiscreteDistribution class Abstract class for all discrete distributions.
Definition discrete.hpp:21
The HyperGeometricRand class Hypergeometric distribution.
Definition hypergeometric.hpp:19
long double Mean() const override
Definition hypergeometric.hpp:215
IntType MaxValue() const override
Definition hypergeometric.hpp:32
HyperGeometricRand(IntType totalSize=1, IntType drawsNum=1, IntType successesNum=1)
Definition hypergeometric.hpp:70
long double Skewness() const override
Definition hypergeometric.hpp:243
double F(const IntType &k) const override
Definition hypergeometric.hpp:122
IntType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition hypergeometric.hpp:236
long double Variance() const override
Definition hypergeometric.hpp:221
double P(const IntType &k) const override
Definition hypergeometric.hpp:104
long double ExcessKurtosis() const override
Definition hypergeometric.hpp:262
IntType GetTotalSize()
Definition hypergeometric.hpp:35
std::string Name() const override
Definition hypergeometric.hpp:76
IntType MinValue() const override
Definition hypergeometric.hpp:31
Support SupportType() const override
Definition hypergeometric.hpp:30
double logP(const IntType &k) const override
Definition hypergeometric.hpp:110
void SetParameters(IntType totalSize, IntType drawsNum, IntType successesNum)
Definition hypergeometric.hpp:83
IntType GetSuccessesNum()
Definition hypergeometric.hpp:37
IntType operator()(G &g) const
Definition hypergeometric.hpp:146
IntType GetDrawsNum()
Definition hypergeometric.hpp:36
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 standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
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 logFactorialRatio(size_t x, size_t y)
Definition math/gamma.hpp:607
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15