00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #if defined (HAVE_CONFIG_H)
00035 #include <config.h>
00036 #endif
00037
00038 #include <stdio.h>
00039
00040 #include "f77-fcn.h"
00041 #include "lo-error.h"
00042 #include "lo-ieee.h"
00043 #include "lo-math.h"
00044 #include "randmtzig.h"
00045 #include "randpoisson.h"
00046
00047 #undef NAN
00048 #define NAN octave_NaN
00049 #undef INFINITE
00050 #define INFINITE lo_ieee_isinf
00051 #define RUNI oct_randu()
00052 #define RNOR oct_randn()
00053 #define LGAMMA xlgamma
00054
00055 F77_RET_T
00056 F77_FUNC (dlgams, DLGAMS) (const double *, double *, double *);
00057
00058 static double
00059 xlgamma (double x)
00060 {
00061 double result;
00062 #ifdef HAVE_LGAMMA
00063 result = lgamma (x);
00064 #else
00065 double sgngam;
00066
00067 if (lo_ieee_isnan (x))
00068 result = x;
00069 else if (x <= 0 || lo_ieee_isinf (x))
00070 result = octave_Inf;
00071 else
00072 F77_XFCN (dlgams, DLGAMS, (&x, &result, &sgngam));
00073 #endif
00074 return result;
00075 }
00076
00077
00078
00079
00080 static double
00081 flogfak (double k)
00082 {
00083 #define C0 9.18938533204672742e-01
00084 #define C1 8.33333333333333333e-02
00085 #define C3 -2.77777777777777778e-03
00086 #define C5 7.93650793650793651e-04
00087 #define C7 -5.95238095238095238e-04
00088
00089 static double logfak[30L] = {
00090 0.00000000000000000, 0.00000000000000000, 0.69314718055994531,
00091 1.79175946922805500, 3.17805383034794562, 4.78749174278204599,
00092 6.57925121201010100, 8.52516136106541430, 10.60460290274525023,
00093 12.80182748008146961, 15.10441257307551530, 17.50230784587388584,
00094 19.98721449566188615, 22.55216385312342289, 25.19122118273868150,
00095 27.89927138384089157, 30.67186010608067280, 33.50507345013688888,
00096 36.39544520803305358, 39.33988418719949404, 42.33561646075348503,
00097 45.38013889847690803, 48.47118135183522388, 51.60667556776437357,
00098 54.78472939811231919, 58.00360522298051994, 61.26170176100200198,
00099 64.55753862700633106, 67.88974313718153498, 71.25703896716800901
00100 };
00101
00102 double r, rr;
00103
00104 if (k >= 30.0)
00105 {
00106 r = 1.0 / k;
00107 rr = r * r;
00108 return ((k + 0.5)*log(k) - k + C0 + r*(C1 + rr*(C3 + rr*(C5 + rr*C7))));
00109 }
00110 else
00111 return (logfak[(int)k]);
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 static double
00147 f (double k, double l_nu, double c_pm)
00148 {
00149 return exp(k * l_nu - flogfak(k) - c_pm);
00150 }
00151
00152 static double
00153 pprsc (double my)
00154 {
00155 static double my_last = -1.0;
00156 static double m, k2, k4, k1, k5;
00157 static double dl, dr, r1, r2, r4, r5, ll, lr, l_my, c_pm,
00158 f1, f2, f4, f5, p1, p2, p3, p4, p5, p6;
00159 double Dk, X, Y;
00160 double Ds, U, V, W;
00161
00162 if (my != my_last)
00163 {
00164 my_last = my;
00165
00166 Ds = sqrt(my + 0.25);
00167
00168
00169
00170 m = floor(my);
00171 k2 = ceil(my - 0.5 - Ds);
00172 k4 = floor(my - 0.5 + Ds);
00173 k1 = k2 + k2 - m + 1L;
00174 k5 = k4 + k4 - m;
00175
00176
00177 dl = (k2 - k1);
00178 dr = (k5 - k4);
00179
00180
00181 r1 = my / k1;
00182 r2 = my / k2;
00183 r4 = my / (k4 + 1.0);
00184 r5 = my / (k5 + 1.0);
00185
00186
00187 ll = log(r1);
00188 lr = -log(r5);
00189
00190
00191 l_my = log(my);
00192 c_pm = m * l_my - flogfak(m);
00193
00194
00195 f2 = f(k2, l_my, c_pm);
00196 f4 = f(k4, l_my, c_pm);
00197 f1 = f(k1, l_my, c_pm);
00198 f5 = f(k5, l_my, c_pm);
00199
00200
00201
00202 p1 = f2 * (dl + 1.0);
00203 p2 = f2 * dl + p1;
00204 p3 = f4 * (dr + 1.0) + p2;
00205 p4 = f4 * dr + p3;
00206 p5 = f1 / ll + p4;
00207 p6 = f5 / lr + p5;
00208 }
00209
00210 for (;;)
00211 {
00212
00213
00214 if ((U = RUNI * p6) < p2)
00215 {
00216
00217
00218
00219 if ((V = U - p1) < 0.0) return(k2 + floor(U/f2));
00220
00221
00222 if ((W = V / dl) < f1 ) return(k1 + floor(V/f1));
00223
00224
00225
00226 Dk = floor(dl * RUNI) + 1.0;
00227 if (W <= f2 - Dk * (f2 - f2/r2))
00228 {
00229 return(k2 - Dk);
00230 }
00231 if ((V = f2 + f2 - W) < 1.0)
00232 {
00233 Y = k2 + Dk;
00234 if (V <= f2 + Dk * (1.0 - f2)/(dl + 1.0))
00235 {
00236 return(Y);
00237 }
00238 if (V <= f(Y, l_my, c_pm)) return(Y);
00239 }
00240 X = k2 - Dk;
00241 }
00242 else if (U < p4)
00243 {
00244
00245
00246 if ((V = U - p3) < 0.0) return(k4 - floor((U - p2)/f4));
00247
00248
00249 if ((W = V / dr) < f5 ) return(k5 - floor(V/f5));
00250
00251
00252
00253 Dk = floor(dr * RUNI) + 1.0;
00254 if (W <= f4 - Dk * (f4 - f4*r4))
00255 {
00256 return(k4 + Dk);
00257 }
00258 if ((V = f4 + f4 - W) < 1.0)
00259 {
00260 Y = k4 - Dk;
00261 if (V <= f4 + Dk * (1.0 - f4)/ dr)
00262 {
00263 return(Y);
00264 }
00265 if (V <= f(Y, l_my, c_pm)) return(Y);
00266 }
00267 X = k4 + Dk;
00268 }
00269 else
00270 {
00271 W = RUNI;
00272 if (U < p5)
00273 {
00274 Dk = floor(1.0 - log(W)/ll);
00275 if ((X = k1 - Dk) < 0L) continue;
00276 W *= (U - p4) * ll;
00277 if (W <= f1 - Dk * (f1 - f1/r1))
00278 return(X);
00279 }
00280 else
00281 {
00282 Dk = floor(1.0 - log(W)/lr);
00283 X = k5 + Dk;
00284 W *= (U - p5) * lr;
00285 if (W <= f5 - Dk * (f5 - f5*r5))
00286 return(X);
00287 }
00288 }
00289
00290
00291
00292
00293 if (log(W) <= X * l_my - flogfak(X) - c_pm) return(X);
00294 }
00295 }
00296
00297
00298
00299
00300
00301
00302 static void
00303 poisson_cdf_lookup(double lambda, double *p, size_t n)
00304 {
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 #define TABLESIZE 46
00315 double t[TABLESIZE];
00316
00317
00318
00319 int intlambda = (int)floor(lambda);
00320 double P;
00321 int tableidx;
00322 size_t i = n;
00323
00324 t[0] = P = exp(-lambda);
00325 for (tableidx = 1; tableidx <= intlambda; tableidx++) {
00326 P = P*lambda/(double)tableidx;
00327 t[tableidx] = t[tableidx-1] + P;
00328 }
00329
00330 while (i-- > 0) {
00331 double u = RUNI;
00332
00333
00334
00335
00336
00337
00338 int k = (u > 0.458 ? intlambda : 0);
00339
00340
00341
00342
00343
00344 nextk:
00345 if ( u <= t[k] ) {
00346 p[i] = (double) k;
00347 continue;
00348 }
00349 if (++k < tableidx) goto nextk;
00350
00351
00352
00353 while (tableidx < TABLESIZE) {
00354 P = P*lambda/(double)tableidx;
00355 t[tableidx] = t[tableidx-1] + P;
00356
00357
00358 if (t[tableidx] == t[tableidx-1]) t[tableidx] = 1.0;
00359 tableidx++;
00360 if (u <= t[tableidx-1]) break;
00361 }
00362
00363
00364
00365
00366
00367 p[i] = (double)(tableidx-1);
00368 }
00369 }
00370
00371
00372 static void
00373 poisson_rejection (double lambda, double *p, size_t n)
00374 {
00375 double sq = sqrt(2.0*lambda);
00376 double alxm = log(lambda);
00377 double g = lambda*alxm - LGAMMA(lambda+1.0);
00378 size_t i;
00379
00380 for (i = 0; i < n; i++)
00381 {
00382 double y, em, t;
00383 do {
00384 do {
00385 y = tan(M_PI*RUNI);
00386 em = sq * y + lambda;
00387 } while (em < 0.0);
00388 em = floor(em);
00389 t = 0.9*(1.0+y*y)*exp(em*alxm-flogfak(em)-g);
00390 } while (RUNI > t);
00391 p[i] = em;
00392 }
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 void
00406 oct_fill_randp (double L, octave_idx_type n, double *p)
00407 {
00408 octave_idx_type i;
00409 if (L < 0.0 || INFINITE(L))
00410 {
00411 for (i=0; i<n; i++)
00412 p[i] = NAN;
00413 }
00414 else if (L <= 10.0)
00415 {
00416 poisson_cdf_lookup(L, p, n);
00417 }
00418 else if (L <= 1e8)
00419 {
00420 for (i=0; i<n; i++)
00421 p[i] = pprsc(L);
00422 }
00423 else
00424 {
00425
00426 const double sqrtL = sqrt(L);
00427 for (i = 0; i < n; i++)
00428 {
00429 p[i] = floor(RNOR*sqrtL + L + 0.5);
00430 if (p[i] < 0.0)
00431 p[i] = 0.0;
00432 }
00433 }
00434 }
00435
00436
00437 double
00438 oct_randp (double L)
00439 {
00440 double ret;
00441 if (L < 0.0) ret = NAN;
00442 else if (L <= 12.0) {
00443
00444 double g = exp(-L);
00445 int em = -1;
00446 double t = 1.0;
00447 do {
00448 ++em;
00449 t *= RUNI;
00450 } while (t > g);
00451 ret = em;
00452 } else if (L <= 1e8) {
00453
00454 poisson_rejection(L, &ret, 1);
00455 } else if (INFINITE(L)) {
00456
00457
00458 ret = NAN;
00459 } else {
00460
00461 ret = floor(RNOR*sqrt(L) + L + 0.5);
00462 if (ret < 0.0) ret = 0.0;
00463 }
00464 return ret;
00465 }