randpoisson.c

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 /* Original version written by Paul Kienzle distributed as free
00024    software in the in the public domain.  */
00025 
00026 /* Needs the following defines:
00027  * NAN: value to return for Not-A-Number
00028  * RUNI: uniform generator on (0,1)
00029  * RNOR: normal generator
00030  * LGAMMA: log gamma function
00031  * INFINITE: function to test whether a value is infinite
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 /* ---- pprsc.c from Stadloeber's winrand --- */
00078 
00079 /* flogfak(k) = ln(k!) */
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  * Poisson Distribution - Patchwork Rejection/Inversion  *
00118  *                                                                *
00119  ******************************************************************
00120  *                                                                *
00121  * For parameter  my < 10  Tabulated Inversion is applied.        *
00122  * For my >= 10  Patchwork Rejection is employed:                 *
00123  * The area below the histogram function f(x) is rearranged in    *
00124  * its body by certain point reflections. Within a large center   *
00125  * interval variates are sampled efficiently by rejection from    *
00126  * uniform hats. Rectangular immediate acceptance regions speed   *
00127  * up the generation. The remaining tails are covered by          *
00128  * exponential functions.                                         *
00129  *                                                                *
00130  ******************************************************************
00131  *                                                                *
00132  * FUNCTION :   - pprsc samples a random number from the Poisson  *
00133  *                distribution with parameter my > 0.             *
00134  * REFERENCE :  - H. Zechner (1994): Efficient sampling from      *
00135  *                continuous and discrete unimodal distributions, *
00136  *                Doctoral Dissertation, 156 pp., Technical       *
00137  *                University Graz, Austria.                       *
00138  * SUBPROGRAM : - drand(seed) ... (0,1)-Uniform generator with    *
00139  *                unsigned long integer *seed.                    *
00140  *                                                                *
00141  * Implemented by H. Zechner, January 1994                        *
00142  * Revised by F. Niederl, July 1994                               *
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     {                               /* set-up           */
00164       my_last = my;
00165       /* approximate deviation of reflection points k2, k4 from my - 1/2 */
00166       Ds = sqrt(my + 0.25);
00167 
00168       /* mode m, reflection points k2 and k4, and points k1 and k5,      */
00169       /* which delimit the centre region of h(x)                         */
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       /* range width of the critical left and right centre region        */
00177       dl = (k2 - k1);
00178       dr = (k5 - k4);
00179 
00180       /* recurrence constants r(k)=p(k)/p(k-1) at k = k1, k2, k4+1, k5+1 */
00181       r1 = my / k1;
00182       r2 = my / k2;
00183       r4 = my / (k4 + 1.0);
00184       r5 = my / (k5 + 1.0);
00185 
00186       /* reciprocal values of the scale parameters of exp. tail envelope */
00187       ll =  log(r1);                                 /* expon. tail left */
00188       lr = -log(r5);                                 /* expon. tail right*/
00189 
00190       /* Poisson constants, necessary for computing function values f(k) */
00191       l_my = log(my);
00192       c_pm = m * l_my - flogfak(m);
00193 
00194       /* function values f(k) = p(k)/p(m) at k = k2, k4, k1, k5          */
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       /* area of the two centre and the two exponential tail regions     */
00201       /* area of the two immediate acceptance regions between k2, k4     */
00202       p1 = f2 * (dl + 1.0);                            /* immed. left    */
00203       p2 = f2 * dl         + p1;                       /* centre left    */
00204       p3 = f4 * (dr + 1.0) + p2;                       /* immed. right   */
00205       p4 = f4 * dr         + p3;                       /* centre right   */
00206       p5 = f1 / ll         + p4;                       /* exp. tail left */
00207       p6 = f5 / lr         + p5;                       /* exp. tail right*/
00208     }
00209 
00210   for (;;)
00211     {
00212       /* generate uniform number U -- U(0, p6)                           */
00213       /* case distinction corresponding to U                             */
00214       if ((U = RUNI * p6) < p2)
00215         {                                            /* centre left      */
00216 
00217           /* immediate acceptance region
00218              R2 = [k2, m) *[0, f2),  X = k2, ... m -1 */
00219           if ((V = U - p1) < 0.0)  return(k2 + floor(U/f2));
00220           /* immediate acceptance region
00221              R1 = [k1, k2)*[0, f1),  X = k1, ... k2-1 */
00222           if ((W = V / dl) < f1 )  return(k1 + floor(V/f1));
00223 
00224           /* computation of candidate X < k2, and its counterpart Y > k2 */
00225           /* either squeeze-acceptance of X or acceptance-rejection of Y */
00226           Dk = floor(dl * RUNI) + 1.0;
00227           if (W <= f2 - Dk * (f2 - f2/r2))
00228             {                                        /* quick accept of  */
00229               return(k2 - Dk);                       /* X = k2 - Dk      */
00230             }
00231           if ((V = f2 + f2 - W) < 1.0)
00232             {                                        /* quick reject of Y*/
00233               Y = k2 + Dk;
00234               if (V <= f2 + Dk * (1.0 - f2)/(dl + 1.0))
00235                 {                                    /* quick accept of  */
00236                   return(Y);                         /* Y = k2 + Dk      */
00237                 }
00238               if (V <= f(Y, l_my, c_pm))  return(Y); /* final accept of Y*/
00239             }
00240           X = k2 - Dk;
00241         }
00242       else if (U < p4)
00243         {                                            /* centre right     */
00244           /*  immediate acceptance region
00245               R3 = [m, k4+1)*[0, f4), X = m, ... k4    */
00246           if ((V = U - p3) < 0.0)  return(k4 - floor((U - p2)/f4));
00247           /* immediate acceptance region
00248              R4 = [k4+1, k5+1)*[0, f5)                */
00249           if ((W = V / dr) < f5 )  return(k5 - floor(V/f5));
00250 
00251           /* computation of candidate X > k4, and its counterpart Y < k4 */
00252           /* either squeeze-acceptance of X or acceptance-rejection of Y */
00253           Dk = floor(dr * RUNI) + 1.0;
00254           if (W <= f4 - Dk * (f4 - f4*r4))
00255             {                                        /* quick accept of  */
00256               return(k4 + Dk);                       /* X = k4 + Dk      */
00257             }
00258           if ((V = f4 + f4 - W) < 1.0)
00259             {                                        /* quick reject of Y*/
00260               Y = k4 - Dk;
00261               if (V <= f4 + Dk * (1.0 - f4)/ dr)
00262                 {                                    /* quick accept of  */
00263                   return(Y);                         /* Y = k4 - Dk      */
00264                 }
00265               if (V <= f(Y, l_my, c_pm))  return(Y); /* final accept of Y*/
00266             }
00267           X = k4 + Dk;
00268         }
00269       else
00270         {
00271           W = RUNI;
00272           if (U < p5)
00273             {                                        /* expon. tail left */
00274               Dk = floor(1.0 - log(W)/ll);
00275               if ((X = k1 - Dk) < 0L)  continue;     /* 0 <= X <= k1 - 1 */
00276               W *= (U - p4) * ll;                    /* W -- U(0, h(x))  */
00277               if (W <= f1 - Dk * (f1 - f1/r1))
00278                 return(X);                           /* quick accept of X*/
00279             }
00280           else
00281             {                                        /* expon. tail right*/
00282               Dk = floor(1.0 - log(W)/lr);
00283               X  = k5 + Dk;                          /* X >= k5 + 1      */
00284               W *= (U - p5) * lr;                    /* W -- U(0, h(x))  */
00285               if (W <= f5 - Dk * (f5 - f5*r5))
00286                 return(X);                           /* quick accept of X*/
00287             }
00288         }
00289 
00290       /* acceptance-rejection test of candidate X from the original area */
00291       /* test, whether  W <= f(k),    with  W = U*h(x)  and  U -- U(0, 1)*/
00292       /* log f(X) = (X - m)*log(my) - log X! + log m!                    */
00293       if (log(W) <= X * l_my - flogfak(X) - c_pm)  return(X);
00294     }
00295 }
00296 /* ---- pprsc.c end ------ */
00297 
00298 
00299 /* The remainder of the file is by Paul Kienzle */
00300 
00301 /* Given uniform u, find x such that CDF(L,x)==u.  Return x. */
00302 static void
00303 poisson_cdf_lookup(double lambda, double *p, size_t n)
00304 {
00305   /* Table size is predicated on the maximum value of lambda
00306    * we want to store in the table, and the maximum value of
00307    * returned by the uniform random number generator on [0,1).
00308    * With lambda==10 and u_max = 1 - 1/(2^32+1), we
00309    * have poisson_pdf(lambda,36) < 1-u_max.  If instead our
00310    * generator uses more bits of mantissa or returns a value
00311    * in the range [0,1], then for lambda==10 we need a table
00312    * size of 46 instead.  For long doubles, the table size
00313    * will need to be longer still.  */
00314 #define TABLESIZE 46
00315   double t[TABLESIZE];
00316 
00317   /* Precompute the table for the u up to and including 0.458.
00318    * We will almost certainly need it. */
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     /* If u > 0.458 we know we can jump to floor(lambda) before
00334      * comparing (this observation is based on Stadlober's winrand
00335      * code). For lambda >= 1, this will be a win.  Lambda < 1
00336      * is already fast, so adding an extra comparison is not a
00337      * problem. */
00338     int k = (u > 0.458 ? intlambda : 0);
00339 
00340     /* We aren't using a for loop here because when we find the
00341      * right k we want to jump to the next iteration of the
00342      * outer loop, and the continue statement will only work for
00343      * the inner loop. */
00344   nextk:
00345     if ( u <= t[k] ) {
00346       p[i] = (double) k;
00347       continue;
00348     }
00349     if (++k < tableidx) goto nextk;
00350 
00351     /* We only need high values of the table very rarely so we
00352      * don't automatically compute the entire table. */
00353     while (tableidx < TABLESIZE) {
00354       P = P*lambda/(double)tableidx;
00355       t[tableidx] = t[tableidx-1] + P;
00356       /* Make sure we converge to 1.0 just in case u is uniform
00357        * on [0,1] rather than [0,1). */
00358       if (t[tableidx] == t[tableidx-1]) t[tableidx] = 1.0;
00359       tableidx++;
00360       if (u <= t[tableidx-1]) break;
00361     }
00362 
00363     /* We are assuming that the table size is big enough here.
00364      * This should be true even if RUNI is returning values in
00365      * the range [0,1] rather than [0,1).
00366      */
00367     p[i] = (double)(tableidx-1);
00368   }
00369 }
00370 
00371 /* From Press, et al., Numerical Recipes */
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 /* The cutoff of L <= 1e8 in the following two functions before using
00396  * the normal approximation is based on:
00397  *   > L=1e8; x=floor(linspace(0,2*L,1000));
00398  *   > max(abs(normal_pdf(x,L,L)-poisson_pdf(x,L)))
00399  *   ans =  1.1376e-28
00400  * For L=1e7, the max is around 1e-9, which is within the step size of RUNI.
00401  * For L>1e10 the pprsc function breaks down, as I saw from the histogram
00402  * of a large sample, so 1e8 is both small enough and large enough. */
00403 
00404 /* Generate a set of poisson numbers with the same distribution */
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       /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
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; /* will probably never happen */
00432         }
00433     }
00434 }
00435 
00436 /* Generate one poisson variate */
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     /* From Press, et al. Numerical recipes */
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     /* numerical recipes */
00454     poisson_rejection(L, &ret, 1);
00455   } else if (INFINITE(L)) {
00456     /* FIXME R uses NaN, but the normal approx. suggests that as
00457      * limit should be inf. Which is correct? */
00458     ret = NAN;
00459   } else {
00460     /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
00461     ret = floor(RNOR*sqrt(L) + L + 0.5);
00462     if (ret < 0.0) ret = 0.0; /* will probably never happen */
00463   }
00464   return ret;
00465 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines