130 auto x = std::vector<size_t>( p.size() );
133 for(
size_t k = 0; k < p.size(); ++k ) {
135 assert( n >= sum_n );
136 assert( norm >= sum_p );
139 auto const binom_t = n - sum_n;
140 auto const binom_p =
static_cast<double>( p[k] ) /
static_cast<double>(norm - sum_p);
141 std::binomial_distribution<size_t> distrib( binom_t, binom_p );
142 x[k] = distrib( engine );
162 if( !std::isfinite(e) || e < 0.0 ) {
163 throw std::invalid_argument(
164 "Cannot compute multinomial distribution "
194 assert( m + n <= N );
197 auto fc_lnpk_ = [](
size_t k,
size_t L,
size_t m,
size_t n )
205 auto const L = N - m - n;
206 auto const rNN = 1.0 / (
static_cast<double>(N) *
static_cast<double>(N + 2));
207 auto const mean = (double)n * m * rNN * (N + 2);
210 auto const mode =
static_cast<size_t>(
211 static_cast<double>(n + 1) *
static_cast<double>(m + 1) * rNN * N
216 (
static_cast<double>(n) * m * (N - m) * (N - n) ) /
217 (
static_cast<double>(N) * N * (N - 1) )
221 double const SHAT1 = 2.943035529371538573;
222 double const SHAT2 = 0.8989161620588987408;
223 auto const hyp_h = std::sqrt(SHAT1 * (var + 0.5)) + SHAT2;
224 auto const hyp_a =
mean + 0.5;
225 auto const hyp_fm = fc_lnpk_(mode, L, m, n);
228 auto hyp_bound =
static_cast<size_t>( hyp_a + 4.0 * hyp_h );
229 if( hyp_bound > n ) {
235 std::uniform_real_distribution<double> distrib( 0.0, 1.0 );
239 double const u = distrib( engine );
247 auto const x = hyp_a + hyp_h * (distrib( engine ) - 0.5) / u;
249 if( x < 0. || x > 2E9 ) {
255 k =
static_cast<size_t>(x);
256 if( k > hyp_bound ) {
262 auto const lf = hyp_fm - fc_lnpk_(k, L, m, n);
263 if( u * (4.0 - u) - 3.0 <= lf ) {
267 if( u * (u - lf) > 1.0 ) {
271 if( 2.0 * log(u) <= lf ) {
299 auto const Mp =
static_cast<double>(m + 1);
300 auto const np =
static_cast<double>(n + 1);
301 auto const p = Mp / (N + 2.0);
302 assert( N >= m + n );
303 auto const L = N - m - n;
304 double const L1 =
static_cast<double>(L);
307 auto const modef = np * p;
308 size_t hyp_mode =
static_cast<size_t>( modef );
310 if( hyp_mode == modef && p == 0.5) {
313 hyp_mp = hyp_mode + 1;
319 assert( n >= hyp_mode );
320 assert( m >= hyp_mode );
321 auto const hyp_fm = std::exp(
329 auto hyp_bound =
static_cast<size_t>(
330 modef + 11.0 * std::sqrt( modef * (1.0 - p) * (1.0 - n /
static_cast<double>(N)) + 1.0 )
338 std::uniform_real_distribution<double> distrib( 0.0, 1.0 );
341 double U = distrib( engine );
344 if( (U -= hyp_fm) <= 0.0 ) {
354 double k1 = hyp_mp - 1;
355 double k2 = hyp_mode + 1;
358 for( I = 1; I <= hyp_mode; I++, k1--, k2++ ) {
361 auto divisor = (np - k1) * (Mp - k1);
368 if( (U -= c) <= 0.0 ) {
369 return (hyp_mp - I - 1);
373 divisor = k2 * (L1 + k2);
378 d *= (np - k2) * (Mp - k2);
379 if( (U -= d) <= 0.0 ) {
380 return (hyp_mode + I);
388 for( k2 = I = hyp_mp + hyp_mode; I <= hyp_bound; I++, k2++ ) {
389 auto divisor = k2 * (L1 + k2);
391 d *= (np - k2) * (Mp - k2);
392 if( (U -= d) <= 0.0 ) {
415 throw std::invalid_argument(
416 "Invalid arguments for hypergeometric_distribution(), called with t == " +
418 ", as we cannot draw more values without replacement than there are values."
452 if( N > 680 || n > 70 ) {
460 return x * fak + addd;
476 size_t const n = n1 + n2;
483 std::uniform_real_distribution<double> distrib( 0.0, 1.0 );
489 for(
size_t i = 0; i < t; i++ ) {
490 double const u = distrib( engine );
502 for(
size_t i = 0; i < n - t; i++ ) {
503 double const u = distrib( engine );
523 auto x = std::vector<size_t>( p.size() );
531 if( !std::isfinite(e) || e < 0.0 ) {
532 throw std::invalid_argument(
533 "Cannot compute multivariate hypergeometric distribution "
540 throw std::invalid_argument(
541 "Cannot compute multivariate hypergeometric distribution "
543 ", as we cannot draw more values without replacement than there are values to draw."
549 for( i = 0; i < p.size() - 1; ++i ) {
551 assert(
sum >= p[i] );