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 }