1 module rmathd.geom;
2 
3 public import rmathd.common;
4 public import rmathd.poisson;
5 public import rmathd.exponential;
6 
7 
8 /*
9 ** dmd geom.d common.d normal.d poisson.d exponential.d && ./geom
10 */
11 
12 
13 T dgeom(T: double)(T x, T p, int give_log)
14 { 
15     T prob;
16     mixin R_D__0!give_log;
17     
18     if (isNaN(x) || isNaN(p))
19     	return x + p;
20 
21     if (p <= 0 || p > 1)
22     	return T.nan;
23 
24     mixin (R_D_nonint_check!(x));
25     if (x < 0 || !isFinite(x) || p == 0)
26     	return R_D__0;
27     x = nearbyint(x);
28 
29     /* prob = (1-p)^x, stable for small p */
30     prob = dbinom_raw!T(0., x, p, 1 - p, give_log);
31 
32     return((give_log) ? log(p) + prob : p*prob);
33 }
34 
35 
36 T pgeom(T: double)(T x, T p, int lower_tail, int log_p)
37 {
38     if (isNaN(x) || isNaN(p))
39 	    return x + p;
40     
41     if(p <= 0 || p > 1)
42     	return T.nan;
43 
44     if (x < 0.)
45     	return R_DT_0!T(lower_tail, log_p);
46     if (!isFinite(x))
47     	return R_DT_1!T(lower_tail, log_p);
48     x = floor(x + 1e-7);
49 
50     if(p == 1.) { /* we cannot assume IEEE */
51 	    x = lower_tail ? 1: 0;
52 	    return log_p ? log(x) : x;
53     }
54     x = log1p(-p) * (x + 1);
55     if (log_p)
56 	    return R_DT_Clog!T(x, lower_tail, log_p);
57     else
58 	    return lower_tail ? -expm1(x) : exp(x);
59 }
60 
61 
62 T qgeom(T: double)(T p, T prob, int lower_tail, int log_p)
63 {
64     if (isNaN(p) || isNaN(prob))
65 	    return p + prob;
66     
67     if (prob <= 0 || prob > 1)
68     	return T.nan;
69 
70     mixin (R_Q_P01_check!(p)());
71     if (prob == 1)
72     	return 0;
73     immutable(T) INF = T.infinity;
74     mixin (R_Q_P01_boundaries!(p, 0, INF)());
75 
76 /* add a fuzz to ensure left continuity, but value must be >= 0 */
77     return fmax2!T(0, ceil(R_DT_Clog!T(p, lower_tail, log_p) / log1p(- prob) - 1 - 1e-12));
78 }
79 
80 
81 T rgeom(T: double)(T p)
82 {
83     if (!isFinite(p) || p <= 0 || p > 1)
84     	return T.nan;
85 
86     return rpois!T(exp_rand!T() * ((1 - p) / p));
87 }
88 
89 
90 
91 void test_geom()
92 {
93 	import std.stdio: writeln;
94 	writeln("dgeom: ", dgeom(1., .5, 0));
95 	writeln("pgeom: ", pgeom(1., .5, 1, 0));
96 	writeln("qgeom: ", qgeom(0.8, 0.2, 1, 0));
97 	writeln("rgeom: ", rgeom(0.2), ", rgeom: ", rgeom(0.2), ", rgeom: ", rgeom(0.2), ", rgeom: ", rgeom(0.2));
98 }
99 
100 
101