1 module rmathd.poisson; 2 3 public import rmathd.common; 4 public import rmathd.uniform; 5 public import rmathd.gamma; 6 public import rmathd.normal; 7 8 /* 9 ** dmd poisson.d uniform.d gamma.d common.d normal.d && ./poisson 10 */ 11 12 T dpois(T: double)(T x, T lambda, int give_log) 13 { 14 mixin R_D__0!give_log; 15 if(isNaN(x) || isNaN(lambda)) 16 return x + lambda; 17 18 if (lambda < 0) 19 return T.nan; 20 21 mixin R_D_nonint_check!(x); 22 if (x < 0 || !isFinite(x)) 23 return R_D__0; 24 25 x = nearbyint(x); 26 27 return( dpois_raw!T(x, lambda, give_log) ); 28 } 29 30 T ppois(T: double)(T x, T lambda, int lower_tail, int log_p) 31 { 32 if (isNaN(x) || isNaN(lambda)) 33 return x + lambda; 34 35 if(lambda < 0.) 36 return T.nan; 37 if (x < 0) 38 return R_DT_0!T(lower_tail, log_p); 39 if (lambda == 0.) 40 return R_DT_1!T(lower_tail, log_p); 41 if (!isFinite(x)) 42 return R_DT_1!T(lower_tail, log_p); 43 x = floor(x + 1e-7); 44 45 return pgamma!T(lambda, x + 1, 1., !lower_tail, log_p); 46 } 47 48 static T do_search(T)(T y, ref T z, T p, T lambda, T incr) 49 { 50 if(z >= p) { 51 /* search to the left */ 52 for(;;) { 53 if(y == 0 || (z = ppois!T(y - incr, lambda, /*l._t.*/1, /*log_p*/0)) < p) 54 return y; 55 y = fmax2(0, y - incr); 56 } 57 } else { /* search to the right */ 58 for(;;) { 59 y = y + incr; 60 if((z = ppois!T(y, lambda, /*l._t.*/1, /*log_p*/0)) >= p) 61 return y; 62 } 63 } 64 } 65 66 T qpois(T: double)(T p, T lambda, int lower_tail, int log_p) 67 { 68 T mu, sigma, gamma, z, y; 69 if (isNaN(p) || isNaN(lambda)) 70 return p + lambda; 71 if(!isFinite(lambda)) 72 return T.nan; 73 if(lambda < 0) 74 return T.nan; 75 mixin (R_Q_P01_check!(p)()); 76 if(lambda == 0) 77 return 0; 78 if(p == R_DT_0!T(lower_tail, log_p)) 79 return 0; 80 if(p == R_DT_1!T(lower_tail, log_p)) 81 return T.infinity; 82 83 mixin R_DT_qIv!(p); 84 mu = lambda; 85 sigma = sqrt(lambda); 86 /* gamma = sigma; PR#8058 should be kurtosis which is mu^-0.5 */ 87 gamma = 1.0/sigma; 88 89 /* Note : "same" code in qpois.c, qbinom.c, qnbinom.c -- 90 * FIXME: This is far from optimal [cancellation for p ~= 1, etc]: */ 91 if(!lower_tail || log_p) { 92 p = R_DT_qIv; /* need check again (cancellation!): */ 93 if (p == 0.) 94 return 0; 95 if (p == 1.) 96 return T.infinity; 97 } 98 /* temporary hack --- FIXME --- */ 99 if (p + 1.01*EPSILON!T >= 1.) 100 return T.infinity; 101 102 /* y := approx.value (Cornish-Fisher expansion) : */ 103 z = qnorm!T(p, 0., 1., /*lower_tail*/1, /*log_p*/0); 104 y = nearbyint(mu + sigma * (z + gamma * (z*z - 1) / 6)); 105 106 z = ppois!T(y, lambda, /*lower_tail*/1, /*log_p*/0); 107 108 /* fuzz to ensure left continuity; 1 - 1e-7 may lose too much : */ 109 p *= 1 - 64*EPSILON!T; 110 111 /* If the mean is not too large a simple search is OK */ 112 if(lambda < 1e5) 113 return do_search!T(y, z, p, lambda, 1); 114 /* Otherwise be a bit cleverer in the search */ 115 { 116 T incr = floor(y * 0.001); 117 T oldincr; 118 do { 119 oldincr = incr; 120 y = do_search!T(y, z, p, lambda, incr); 121 incr = fmax2(1, floor(incr/100)); 122 } while(oldincr > 1 && incr > lambda*1e-15); 123 return y; 124 } 125 } 126 127 128 /* For rpois */ 129 enum a0 = -0.5; 130 enum a1 = 0.3333333; 131 enum a2 = -0.2500068; 132 enum a3 = 0.2000118; 133 enum a4 = -0.1661269; 134 enum a5 = 0.1421878; 135 enum a6 = -0.1384794; 136 enum a7 = 0.1250060; 137 138 enum one_7 = 0.1428571428571428571; 139 enum one_12 = 0.0833333333333333333; 140 enum one_24 = 0.0416666666666666667; 141 142 T rpois(T: double)(T mu) 143 { 144 /* Factorial Table (0:9)! */ 145 const static T[10] fact = 146 [ 147 1., 1., 2., 6., 24., 120., 720., 5040., 40320., 362880. 148 ]; 149 150 /* These are static --- persistent between calls for same mu : */ 151 static int l, m; 152 153 static T b1, b2, c, c0, c1, c2, c3; 154 static T[36] pp; 155 static T p0, p, q, s, d, omega; 156 static T big_l;/* integer "w/o overflow" */ 157 static T muprev = 0., muprev2 = 0.;/*, muold = 0.*/ 158 159 /* Local Vars [initialize some for -Wall]: */ 160 T del, difmuk= 0., E= 0., fk= 0., fx, fy, g, px, py, t, u= 0., v, x; 161 T pois = -1.; 162 int k, kflag, big_mu, new_big_mu = 0; 163 164 if (!isFinite(mu) || mu < 0) 165 return T.nan; 166 167 if (mu <= 0.) 168 return 0.; 169 170 big_mu = mu >= 10.; 171 if(big_mu) 172 new_big_mu = 0; 173 174 if (!(big_mu && mu == muprev)) {/* maybe compute new persistent par.s */ 175 176 if (big_mu) { 177 new_big_mu = 1; 178 /* Case A. (recalculation of s,d,l because mu has changed): 179 * The poisson probabilities pk exceed the discrete normal 180 * probabilities fk whenever k >= m(mu). 181 */ 182 muprev = mu; 183 s = sqrt(mu); 184 d = 6. * mu * mu; 185 big_l = floor(mu - 1.1484); 186 /* = an upper bound to m(mu) for all mu >= 10.*/ 187 } 188 else { /* Small mu ( < 10) -- not using normal approx. */ 189 190 /* Case B. (start new table and calculate p0 if necessary) */ 191 192 /*muprev = 0.;-* such that next time, mu != muprev ..*/ 193 if (mu != muprev) { 194 muprev = mu; 195 m = imax2!int(1, cast(int) mu); 196 l = 0; /* pp[] is already ok up to pp[l] */ 197 q = p0 = p = exp(-mu); 198 } 199 200 for(;;) { 201 /* Step U. uniform sample for inversion method */ 202 u = unif_rand!T(); 203 if (u <= p0) 204 return 0.; 205 206 /* Step T. table comparison until the end pp[l] of the 207 pp-table of cumulative poisson probabilities 208 (0.458 > ~= pp[9](= 0.45792971447) for mu=10 ) */ 209 if (l != 0) { 210 for (k = (u <= 0.458) ? 1 : imin2!int(l, m); k <= l; k++) 211 if (u <= pp[k]) 212 return k; 213 if (l == 35) /* u > pp[35] */ 214 continue; 215 } 216 /* Step C. creation of new poisson 217 probabilities p[l..] and their cumulatives q =: pp[k] */ 218 l++; 219 for (k = l; k <= 35; k++) { 220 p *= mu / k; 221 q += p; 222 pp[k] = q; 223 if (u <= q) { 224 l = k; 225 return k; 226 } 227 } 228 l = 35; 229 } /* end(repeat) */ 230 }/* mu < 10 */ 231 232 } /* end {initialize persistent vars} */ 233 234 /* Only if mu >= 10 : ----------------------- */ 235 236 /* Step N. normal sample */ 237 g = mu + s * norm_rand!T();/* norm_rand() ~ N(0,1), standard normal */ 238 239 if (g >= 0.) { 240 pois = floor(g); 241 /* Step I. immediate acceptance if pois is large enough */ 242 if (pois >= big_l) 243 return pois; 244 /* Step S. squeeze acceptance */ 245 fk = pois; 246 difmuk = mu - fk; 247 u = unif_rand!T(); /* ~ U(0,1) - sample */ 248 if (d * u >= difmuk * difmuk * difmuk) 249 return pois; 250 } 251 252 /* Step P. preparations for steps Q and H. 253 (recalculations of parameters if necessary) */ 254 255 if (new_big_mu || mu != muprev2) { 256 /* Careful! muprev2 is not always == muprev 257 because one might have exited in step I or S 258 */ 259 muprev2 = mu; 260 omega = M_1_SQRT_2PI / s; 261 /* The quantities b1, b2, c3, c2, c1, c0 are for the Hermite 262 * approximations to the discrete normal probabilities fk. */ 263 264 b1 = one_24 / mu; 265 b2 = 0.3 * b1 * b1; 266 c3 = one_7 * b1 * b2; 267 c2 = b2 - 15. * c3; 268 c1 = b1 - 6. * b2 + 45. * c3; 269 c0 = 1. - b1 + 3. * b2 - 15. * c3; 270 c = 0.1069 / mu; /* guarantees majorization by the 'hat'-function. */ 271 } 272 273 if (g >= 0.) { 274 /* 'Subroutine' F is called (kflag=0 for correct return) */ 275 kflag = 0; 276 goto Step_F; 277 } 278 279 280 for(;;) { 281 /* Step E. Exponential Sample */ 282 283 E = exp_rand!T(); /* ~ Exp(1) (standard exponential) */ 284 285 /* sample t from the laplace 'hat' 286 (if t <= -0.6744 then pk < fk for all mu >= 10.) */ 287 u = 2 * unif_rand!T() - 1.; 288 t = 1.8 + fsign!T(E, u); 289 if (t > -0.6744) { 290 pois = floor(mu + s * t); 291 fk = pois; 292 difmuk = mu - fk; 293 294 /* 'subroutine' F is called (kflag=1 for correct return) */ 295 kflag = 1; 296 297 Step_F: /* 'subroutine' F : calculation of px,py,fx,fy. */ 298 299 if (pois < 10) { /* use factorials from table fact[] */ 300 px = -mu; 301 py = pow(mu, pois) / fact[cast(int)pois]; 302 } 303 else { 304 /* Case pois >= 10 uses polynomial approximation 305 a0-a7 for accuracy when advisable */ 306 del = one_12 / fk; 307 del = del * (1. - 4.8 * del * del); 308 v = difmuk / fk; 309 if (fabs(v) <= 0.25) 310 px = fk * v * v * (((((((a7 * v + a6) * v + a5) * v + a4) * 311 v + a3) * v + a2) * v + a1) * v + a0) 312 - del; 313 else /* |v| > 1/4 */ 314 px = fk * log(1. + v) - difmuk - del; 315 py = M_1_SQRT_2PI / sqrt(fk); 316 } 317 x = (0.5 - difmuk) / s; 318 x *= x;/* x^2 */ 319 fx = -0.5 * x; 320 fy = omega * (((c3 * x + c2) * x + c1) * x + c0); 321 if (kflag > 0) { 322 /* Step H. Hat acceptance (E is repeated on rejection) */ 323 if (c * fabs(u) <= py * exp(px + E) - fy * exp(fx + E)) 324 break; 325 } else 326 /* Step Q. Quotient acceptance (rare case) */ 327 if (fy - u * fy <= py * exp(px - fx)) 328 break; 329 }/* t > -.67.. */ 330 } 331 return pois; 332 } 333 334 335 void test_poisson() 336 { 337 import std.stdio: write, writeln; 338 writeln("dpois: ", dpois(2., 1., 0)); 339 writeln("ppois: ", ppois(2., 1., 1, 0)); 340 writeln("qpois: ", qpois(.9, 1., 1, 0)); 341 writeln("rpois: ", rpois(0.5), ", rpois: ", rpois(0.5), 342 ", rpois: ", rpois(0.5), ", rpois: ", rpois(0.5) 343 , ", rpois: ", rpois(0.5), ", rpois: ", rpois(0.5)); 344 }