/src/r-source/src/nmath/rhyper.c
Line | Count | Source |
1 | | /* |
2 | | * Mathlib : A C Library of Special Functions |
3 | | * Copyright (C) 2000-2026 The R Core Team |
4 | | * Copyright (C) 2005-2020 The R Foundation |
5 | | * Copyright (C) 1998 Ross Ihaka |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * This program is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, a copy is available at |
19 | | * https://www.R-project.org/Licenses/ |
20 | | * |
21 | | * SYNOPSIS |
22 | | * |
23 | | * #include <Rmath.h> |
24 | | * double rhyper(double NR, double NB, double n); |
25 | | * |
26 | | * DESCRIPTION |
27 | | * |
28 | | * Random variates from the hypergeometric distribution. |
29 | | * Returns the number of white balls drawn when kk balls |
30 | | * are drawn at random from an urn containing nn1 white |
31 | | * and nn2 black balls. |
32 | | * |
33 | | * REFERENCE |
34 | | * |
35 | | * V. Kachitvichyanukul and B. Schmeiser (1985). |
36 | | * ``Computer generation of hypergeometric random variates,'' |
37 | | * Journal of Statistical Computation and Simulation 22, 127-145. |
38 | | * |
39 | | * The original algorithm had a bug -- R bug report PR#7314 -- |
40 | | * giving numbers slightly too small in case III h2pe |
41 | | * where (m < 100 || ix <= 50) , see below. |
42 | | */ |
43 | | |
44 | | #include "nmath.h" |
45 | | #include "dpq.h" |
46 | | #include <limits.h> |
47 | | |
48 | | // afc(i) := ln( i! ) [logarithm of the factorial i] = {R:} lgamma(i + 1) = {C:} lgammafn(i + 1) |
49 | | static double afc(int i) |
50 | 0 | { |
51 | | // If (i > 7), use Stirling's approximation, otherwise use table lookup. |
52 | 0 | const static double al[8] = |
53 | 0 | { |
54 | 0 | 0.0,/*ln(0!)=ln(1)*/ |
55 | 0 | 0.0,/*ln(1!)=ln(1)*/ |
56 | 0 | 0.69314718055994530941723212145817,/*ln(2) */ |
57 | 0 | 1.79175946922805500081247735838070,/*ln(6) */ |
58 | 0 | 3.17805383034794561964694160129705,/*ln(24)*/ |
59 | 0 | 4.78749174278204599424770093452324, |
60 | 0 | 6.57925121201010099506017829290394, |
61 | 0 | 8.52516136106541430016553103634712 |
62 | | /* 10.60460290274525022841722740072165, approx. value below = |
63 | | 10.6046028788027; rel.error = 2.26 10^{-9} |
64 | | |
65 | | FIXME: Use constants and if(n > ..) decisions from ./stirlerr.c |
66 | | ----- will be even *faster* for n > 500 (or so) |
67 | | */ |
68 | 0 | }; |
69 | |
|
70 | 0 | if (i < 0) { |
71 | 0 | MATHLIB_WARNING(("rhyper.c: afc(i), i=%d < 0 -- SHOULD NOT HAPPEN!\n"), i); |
72 | 0 | return -1; // unreached |
73 | 0 | } |
74 | 0 | if (i <= 7) |
75 | 0 | return al[i]; |
76 | | // else i >= 8 : |
77 | 0 | double di = i, i2 = di*di; |
78 | 0 | return (di + 0.5) * log(di) - di + M_LN_SQRT_2PI + |
79 | 0 | (0.0833333333333333 - 0.00277777777777778 / i2) / di; |
80 | 0 | } |
81 | | |
82 | | // rhyper(NR, NB, n) -- NR 'red', NB 'blue', n drawn, how many are 'red' |
83 | | double rhyper(double nn1in, double nn2in, double kkin) |
84 | 0 | { |
85 | | /* check parameter validity */ |
86 | |
|
87 | 0 | if(!R_FINITE(nn1in) || !R_FINITE(nn2in) || !R_FINITE(kkin)) |
88 | 0 | ML_WARN_return_NAN; |
89 | |
|
90 | 0 | nn1in = R_forceint(nn1in); |
91 | 0 | nn2in = R_forceint(nn2in); |
92 | 0 | kkin = R_forceint(kkin); |
93 | 0 | double N = nn1in + nn2in; |
94 | |
|
95 | 0 | if (nn1in < 0 || nn2in < 0 || kkin < 0 || kkin > nn1in + nn2in) |
96 | 0 | ML_WARN_return_NAN; |
97 | 0 | if (N > INT_MAX || kkin >= INT_MAX) { |
98 | | /* large n -- evade integer overflow (and inappropriate algorithms) |
99 | | -------- */ |
100 | | #ifdef DEBUG_rhyper |
101 | | REprintf("rhyper(nn1=%.0f, nn2=%.0f, kk=%.0f): 'large n' case\n", nn1in, nn2in, kkin); |
102 | | #endif |
103 | | // FIXME: Much faster to give rbinom() approx when appropriate; -> see Kuensch(1989) |
104 | | // Johnson, Kotz,.. p.258 (top) mention the *four* different binomial approximations |
105 | 0 | if(kkin == 1.) { // Bernoulli |
106 | 0 | return rbinom(kkin, nn1in / (nn1in + nn2in)); |
107 | 0 | } |
108 | | // Slow, but safe: return F^{-1}(U) where F(.) = phyper(.) and U ~ U[0,1] |
109 | 0 | return qhyper(unif_rand(), nn1in, nn2in, kkin, |
110 | 0 | /*lower_tail =*/ false, /*log_p = */ false); |
111 | | // lower_tail=false: a thinko, is still "correct" as equiv. to U <--> 1-U |
112 | 0 | } |
113 | | |
114 | 0 | int |
115 | 0 | nn1 = (int)nn1in, |
116 | 0 | nn2 = (int)nn2in, |
117 | 0 | kk = (int)kkin; |
118 | | |
119 | | /* These should become 'thread_local globals' : */ |
120 | 0 | static int ks = -1, n1s = -1, n2s = -1; |
121 | 0 | static int m, minjx, maxjx; |
122 | 0 | static int k, n1, n2; // <- not allowing larger integer par |
123 | |
|
124 | 0 | bool setup1, setup2; |
125 | | /* if new parameter values, initialize */ |
126 | 0 | if (nn1 != n1s || nn2 != n2s) { // n1 | n2 is changed: setup all |
127 | 0 | setup1 = true; setup2 = true; |
128 | 0 | } else if (kk != ks) { // n1 & n2 are unchanged: setup 'k' only |
129 | 0 | setup1 = false; setup2 = true; |
130 | 0 | } else { // all three unchanged ==> no setup |
131 | 0 | setup1 = false; setup2 = false; |
132 | 0 | } |
133 | 0 | if (setup1) { // n1 & n2 |
134 | 0 | n1s = nn1; n2s = nn2; // save |
135 | 0 | if (nn1 <= nn2) { |
136 | 0 | n1 = nn1; n2 = nn2; |
137 | 0 | } else { // nn2 < nn1 |
138 | 0 | n1 = nn2; n2 = nn1; |
139 | 0 | } |
140 | | // now have n1 <= n2 |
141 | 0 | } |
142 | 0 | if (setup2) { // k |
143 | 0 | ks = kk; // save |
144 | 0 | if ((double)kk + kk >= N) { // this could overflow |
145 | 0 | k = (int)(N - kk); |
146 | 0 | } else { |
147 | 0 | k = kk; |
148 | 0 | } |
149 | | // now have k < N/2 = (n1+n2)/2 |
150 | 0 | } |
151 | 0 | if (setup1 || setup2) { |
152 | 0 | m = (int) ((k + 1.) * (n1 + 1.) / (N + 2.)); // m := floor(adjusted mean E[.]) |
153 | 0 | minjx = imax2(0, k - n2); |
154 | 0 | maxjx = imin2(n1, k); |
155 | | #ifdef DEBUG_rhyper |
156 | | REprintf("rhyper(n1=%d, n2=%d, k=%d), setup: floor(a.mean)=: m = %d, [min,maxjx]= [%d,%d]\n", |
157 | | nn1, nn2, kk, m, minjx, maxjx); |
158 | | #endif |
159 | 0 | } |
160 | | #ifdef DEBUG_rhyper |
161 | | else |
162 | | REprintf("rhyper(n1=%d, n2=%d, k=%d); setup UNchanged\n", nn1, nn2, kk); |
163 | | #endif |
164 | | |
165 | | // generate random variate --- Three basic cases --------------------------- |
166 | |
|
167 | 0 | int ix; // return value (coerced to double at the very end) .. FIXME?? what if overflows |
168 | |
|
169 | 0 | if (minjx == maxjx) { /* I: degenerate distribution ---------------- */ |
170 | | #ifdef DEBUG_rhyper |
171 | | REprintf("rhyper(), branch I (degenerate): ix := maxjx = %d\n", maxjx); |
172 | | #endif |
173 | 0 | ix = maxjx; |
174 | 0 | goto L_finis; // return appropriate variate |
175 | |
|
176 | 0 | } else if (m - minjx < 10) { // II: (Scaled) algorithm HIN (inverse transformation) ---- |
177 | 0 | const static double scale = 1e25; // scaling factor against (early) underflow |
178 | 0 | const static double con = 57.5646273248511421; |
179 | | // 25*log(10) = log(scale) { <==> exp(con) == scale } |
180 | 0 | static double w, |
181 | 0 | lw; // = log(w); w = exp(lw) * scale = exp(lw + log(scale)) = exp(lw + con) |
182 | 0 | if (setup1 || setup2) { |
183 | | // NB: n1 <= n2 here |
184 | 0 | if (k < n2) { |
185 | 0 | lw = afc(n2) + afc(n1 + n2 - k) - afc(n2 - k) - afc(n1 + n2); |
186 | 0 | } else { |
187 | 0 | lw = afc(n1) + afc( k ) - afc(k - n2) - afc(n1 + n2); |
188 | 0 | } |
189 | 0 | w = exp(lw + con); |
190 | 0 | } |
191 | |
|
192 | | #ifdef DEBUG_rhyper |
193 | | REprintf(" branch II; w = %g %s\n", w, |
194 | | (w > 0) ? "> 0" : "= 0 <==> Underflow __NOT GOOD__"); |
195 | | #endif |
196 | 0 | if(w <= 0.) |
197 | 0 | MATHLIB_ERROR(_("w = %g <= 0: Underflow in rhyper() SHOULD NOT HAPPEN!"), w); |
198 | | // FIXME: MM has code "rhyper.c+M3" for switching to log space if w == 0 |
199 | |
|
200 | 0 | double p, u; |
201 | 0 | L10: |
202 | 0 | p = w; |
203 | 0 | ix = minjx; |
204 | 0 | u = unif_rand() * scale; |
205 | | #ifdef DEBUG_rhyper |
206 | | REprintf(" _new_ u = %g\n", u); |
207 | | #endif |
208 | 0 | while (u > p) { |
209 | 0 | u -= p; |
210 | 0 | p *= ((double) n1 - ix) * (k - ix); |
211 | 0 | ix++; |
212 | 0 | p = p / ix / (n2 - k + ix); |
213 | | #ifdef DEBUG_rhyper |
214 | | REprintf(" ix=%3d, u=%11g, p=%20.14g (u-p=%g)\n", ix, u, p, u-p); |
215 | | #endif |
216 | 0 | if (ix > maxjx) |
217 | 0 | goto L10; |
218 | | // FIXME if(p == 0.) we also "have lost" => goto L10 |
219 | 0 | } |
220 | |
|
221 | 0 | } else { /* III : H2PE Algorithm --------------------------------------- */ |
222 | |
|
223 | 0 | static double a, xl, xr, lamdl, lamdr, p1, p2, p3; |
224 | 0 | if (setup1 || setup2) { |
225 | 0 | double |
226 | 0 | s = sqrt((N - k) * k * n1 * n2 / (N - 1) / N / N), |
227 | | |
228 | | /* remark: d is defined in reference without int. */ |
229 | | /* the truncation centers the cell boundaries at 0.5 */ |
230 | 0 | d = (int) (1.5 * s) + .5; |
231 | 0 | xl = m - d + .5; |
232 | 0 | xr = m + d + .5; |
233 | 0 | a = afc(m) + afc(n1 - m) + afc(k - m) + afc(n2 - k + m); |
234 | 0 | double |
235 | 0 | kl = exp(a - afc((int) (xl)) - afc((int) (n1 - xl)) |
236 | 0 | - afc((int) (k - xl)) |
237 | 0 | - afc((int) (n2 - k + xl))), |
238 | 0 | kr = exp(a - afc((int) (xr - 1)) |
239 | 0 | - afc((int) (n1 - xr + 1)) |
240 | 0 | - afc((int) (k - xr + 1)) |
241 | 0 | - afc((int) (n2 - k + xr - 1))); |
242 | 0 | lamdl = -log(xl * (n2 - k + xl) / (n1 - xl + 1) / (k - xl + 1)); |
243 | 0 | lamdr = -log((n1 - xr + 1) * (k - xr + 1) / xr / (n2 - k + xr)); |
244 | 0 | p1 = d + d; |
245 | 0 | p2 = p1 + kl / lamdl; |
246 | 0 | p3 = p2 + kr / lamdr; |
247 | | #ifdef DEBUG_rhyper |
248 | | REprintf("rhyper(), branch III {accept/reject}: (xl,xr)= (%g,%g); lamdl,r = (%g,%g)\n", |
249 | | xl, xr, lamdl, lamdr); |
250 | | REprintf(" --------> (p1,p2,p3) = (%g,%g,%g)\n", p1,p2,p3); |
251 | | } |
252 | | else |
253 | | REprintf("rhyper(), branch III {accept/reject}: NO setup needed; lamdl,r = (%g,%g)\n", |
254 | | lamdl, lamdr); |
255 | | #else |
256 | 0 | } |
257 | 0 | #endif |
258 | | |
259 | | /* acceptance/rejection test */ |
260 | 0 | bool reject = true; |
261 | 0 | int n_uv = 0; |
262 | 0 | do { // L30: -------------- acceptance / rejection : loop while reject=true ------------- |
263 | 0 | double |
264 | 0 | u = unif_rand() * p3, |
265 | 0 | v = unif_rand(); |
266 | 0 | n_uv++; |
267 | 0 | if(n_uv >= 10000) { |
268 | 0 | REprintf("rhyper(*, n1=%d, n2=%d, k=%d): branch III: giving up after %d rejections\n", |
269 | 0 | nn1, nn2, kk, n_uv); |
270 | 0 | ML_WARN_return_NAN; |
271 | 0 | } |
272 | | #ifdef DEBUG_rhyper |
273 | | REprintf(" ... L30 [%d]: new (u=%g, v ~ U[0,1]=%g): ", n_uv, u,v); |
274 | | #endif |
275 | | |
276 | 0 | if (u < p1) { /* rectangular region */ |
277 | 0 | ix = (int) (xl + u); |
278 | | #ifdef DEBUG_rhyper |
279 | | REprintf(" rectangular: ix=%d\n", ix); |
280 | | #endif |
281 | 0 | } else if (u <= p2) { /* left tail */ |
282 | 0 | ix = (int) (xl + log(v) / lamdl); |
283 | | #ifdef DEBUG_rhyper |
284 | | REprintf(" left tail: ix=%d %s", ix, (ix < minjx)? "< minjx (=> L30)\n" : ">= minjx;"); |
285 | | #endif |
286 | 0 | if (ix < minjx) |
287 | 0 | continue; // goto L30 |
288 | 0 | v = v * (u - p1) * lamdl; |
289 | 0 | } else { /* right tail */ |
290 | 0 | ix = (int) (xr - log(v) / lamdr); |
291 | | #ifdef DEBUG_rhyper |
292 | | REprintf(" right tail: ix=%d %s", ix, (ix > maxjx)? "> maxjx (=> L30)\n" : "< maxjx;"); |
293 | | #endif |
294 | 0 | if (ix > maxjx) |
295 | 0 | continue; // goto L30 |
296 | 0 | v = v * (u - p2) * lamdr; |
297 | 0 | } |
298 | | #ifdef DEBUG_rhyper |
299 | | if(u >= p1) REprintf(" new v = %g\n", v); |
300 | | #endif |
301 | | |
302 | 0 | if (m < 100 || ix <= 50) { |
303 | | /* explicit evaluation */ |
304 | | /* The original algorithm (and TOMS 668) have |
305 | | f = f * i * (n2 - k + i) / (n1 - i) / (k - i); |
306 | | in the (m > ix) case, but the definition of the |
307 | | recurrence relation on p134 shows that the +1 is |
308 | | needed. */ |
309 | 0 | double f = 1.0; |
310 | 0 | if (m < ix) { |
311 | 0 | for (int i = m + 1; i <= ix; i++) |
312 | 0 | f = f * (n1 - i + 1) * (k - i + 1) / (n2 - k + i) / i; |
313 | 0 | } else if (m > ix) { |
314 | 0 | for (int i = ix + 1; i <= m; i++) |
315 | 0 | f = f * i * (n2 - k + i) / (n1 - i + 1) / (k - i + 1); |
316 | 0 | } |
317 | | #ifdef DEBUG_rhyper |
318 | | REprintf(" small m or ix: f = %g\n", f); |
319 | | #endif |
320 | 0 | if (v <= f) { |
321 | 0 | reject = false; |
322 | 0 | } |
323 | 0 | } else { |
324 | |
|
325 | 0 | const static double deltal = 0.0078; |
326 | 0 | const static double deltau = 0.0034; |
327 | |
|
328 | | #ifdef DEBUG_rhyper |
329 | | REprintf(" ... accept/reject 'large' case v=%g\n", v); |
330 | | #endif |
331 | | /* squeeze using upper and lower bounds */ |
332 | 0 | double |
333 | 0 | y = ix, |
334 | 0 | y1 = y + 1.0, |
335 | 0 | ym = y - m, |
336 | 0 | yn = n1 - y + 1.0, |
337 | 0 | yk = k - y + 1.0, |
338 | 0 | nk = n2 - k + y1, |
339 | 0 | r = -ym / y1, |
340 | 0 | s = ym / yn, |
341 | 0 | t = ym / yk, |
342 | 0 | e = -ym / nk, |
343 | 0 | g = yn * yk / (y1 * nk) - 1.0, |
344 | 0 | dg = (g < 0.0) ? 1. + g : 1., |
345 | 0 | gu = g * (1.0 + g * (-0.5 + g / 3.0)), |
346 | 0 | gl = gu - .25 * (g * g * g * g) / dg, |
347 | 0 | xm = m + 0.5, |
348 | 0 | xn = n1 - m + 0.5, |
349 | 0 | xk = k - m + 0.5, |
350 | 0 | nm = n2 - k + xm, |
351 | 0 | ub = y * gu - m * gl + deltau |
352 | 0 | + xm * r * (1. + r * (-0.5 + r / 3.0)) |
353 | 0 | + xn * s * (1. + s * (-0.5 + s / 3.0)) |
354 | 0 | + xk * t * (1. + t * (-0.5 + t / 3.0)) |
355 | 0 | + nm * e * (1. + e * (-0.5 + e / 3.0)); |
356 | | /* test against upper bound */ |
357 | 0 | double alv = log(v); |
358 | 0 | if (alv > ub) { |
359 | 0 | reject = true; |
360 | 0 | } else { |
361 | | /* test against lower bound */ |
362 | 0 | double dr = xm * (r * r * r * r); |
363 | 0 | if (r < 0.) |
364 | 0 | dr /= (1.0 + r); |
365 | 0 | double ds = xn * (s * s * s * s); |
366 | 0 | if (s < 0.0) |
367 | 0 | ds /= (1.0 + s); |
368 | 0 | double dt = xk * (t * t * t * t); |
369 | 0 | if (t < 0.0) |
370 | 0 | dt /= (1.0 + t); |
371 | 0 | double de = nm * (e * e * e * e); |
372 | 0 | if (e < 0.0) |
373 | 0 | de /= (1.0 + e); |
374 | 0 | if (alv < ub - 0.25 * (dr + ds + dt + de) |
375 | 0 | + (y + m) * (gl - gu) - deltal) { |
376 | 0 | reject = false; |
377 | 0 | } |
378 | 0 | else { |
379 | | /* * Stirling's formula to machine accuracy |
380 | | */ |
381 | 0 | if (alv <= (a - afc(ix) - afc(n1 - ix) |
382 | 0 | - afc(k - ix) - afc(n2 - k + ix))) { |
383 | 0 | reject = false; |
384 | 0 | } else { |
385 | 0 | reject = true; |
386 | 0 | } |
387 | 0 | } |
388 | 0 | } |
389 | 0 | } // end{ III "large" } |
390 | |
|
391 | 0 | } while (reject); |
392 | |
|
393 | 0 | } // end{branch III} |
394 | | |
395 | | |
396 | 0 | L_finis: /* return appropriate variate */ |
397 | |
|
398 | | #ifdef DEBUG_rhyper |
399 | | REprintf(" L_finis: ix = %d, then", ix); |
400 | | #endif |
401 | 0 | if ((double)kk + kk >= N) { |
402 | 0 | if (nn1 > nn2) { |
403 | 0 | ix = kk - nn2 + ix; |
404 | 0 | } else { |
405 | 0 | ix = nn1 - ix; |
406 | 0 | } |
407 | 0 | } else if (nn1 > nn2) { |
408 | 0 | ix = kk - ix; |
409 | 0 | } |
410 | | #ifdef DEBUG_rhyper |
411 | | REprintf(" %d\n", ix); |
412 | | #endif |
413 | 0 | return ix; |
414 | 0 | } |