Main Page   Class Hierarchy   Compound List   File List   Compound Members  

stoc1.cpp

00001 /*
00002  *  This program is free software; you can redistribute it and/or modify
00003  *  it under the terms of the GNU General Public License as published by
00004  *  the Free Software Foundation; either version 2 of the License, or
00005  *  (at your option) any later version.
00006  *
00007  *  This program is distributed in the hope that it will be useful,
00008  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  *  GNU General Public License for more details.
00011  *
00012  *  You should have received a copy of the GNU General Public License
00013  *  along with this program; if not, write to the Free Software
00014  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00015  *
00016  * This file is extracted from the random generator library provided by Agner Fog
00017  * (http://www.agner.org/random/) and has been modified for Seagull.
00018  * (c) 2002 Agner Fog. GNU General Public License www.gnu.org/copyleft/gpl.html
00019  *
00020  * (c)Copyright 2006 Hewlett-Packard Development Company, LP.
00021  *
00022  */
00023 
00024 #include <math.h>      // math functions
00025 #include "stocc.h"     // class definition
00026 
00027 /***********************************************************************
00028                      Log factorial function
00029 ***********************************************************************/
00030 double LnFac(int32 n) {
00031   // log factorial function. gives natural logarithm of n!
00032 
00033   // define constants
00034   static const double        // coefficients in Stirling approximation
00035     C0 =  0.918938533204672722,   // ln(sqrt(2*pi))
00036     C1 =  1./12.,
00037     C3 = -1./360.;
00038     // C5 =  1./1260.,  // use r^5 term if FAK_LEN < 50
00039     // C7 = -1./1680.;  // use r^7 term if FAK_LEN < 20
00040   // static variables
00041   static double fac_table[FAK_LEN]; // table of ln(n!):
00042   static int initialized = 0;   // remember if fac_table has been initialized
00043 
00044   if (n < FAK_LEN) {
00045     if (n <= 1) {
00046       if (n < 0) FatalError("Parameter negative in LnFac function");
00047       return 0;}
00048     if (!initialized) { // first time. Must initialize table
00049       // make table of ln(n!)
00050       double sum = fac_table[0] = 0.;
00051       for (int i=1; i<FAK_LEN; i++) {
00052         sum += log(float(i));
00053         fac_table[i] = sum;}
00054       initialized = 1;}
00055     return fac_table[n];}
00056 
00057   // not found in table. use Stirling approximation
00058   double  n1, r;
00059   n1 = n;  r  = 1. / n1;
00060   return (n1 + 0.5)*log(n1) - n1 + C0 + r*(C1 + r*r*C3);}
00061 
00062 
00063 /***********************************************************************
00064                       constants
00065 ***********************************************************************/
00066 const double SHAT1 = 2.943035529371538573;    // 8/e
00067 const double SHAT2 = 0.8989161620588987408;   // 3-sqrt(12/e)
00068 
00069 /***********************************************************************
00070                       Poisson distribution
00071 ***********************************************************************/
00072 int32 StochasticLib1::Poisson (double L) {
00073 /*
00074    This function generates a random variate with the poisson distribution.
00075 
00076    Uses inversion by chop-down method for L < 17, and ratio-of-uniforms
00077    method for L >= 17.
00078 
00079    For L < 1.E-6 numerical inaccuracy is avoided by direct calculation.
00080 */
00081 
00082   //------------------------------------------------------------------
00083   //                 choose method
00084   //------------------------------------------------------------------
00085   if (L < 17) {
00086     if (L < 1.E-6) {
00087       if (L == 0) return 0;
00088       if (L < 0) FatalError("Parameter negative in poisson function");
00089 
00090       //--------------------------------------------------------------
00091       // calculate probabilities
00092       //--------------------------------------------------------------
00093       // For extremely small L we calculate the probabilities of x = 1
00094       // and x = 2 (ignoring higher x). The reason for using this
00095       // method is to prevent numerical inaccuracies in other methods.
00096       //--------------------------------------------------------------
00097       return PoissonLow(L);}
00098 
00099     else {
00100 
00101       //--------------------------------------------------------------
00102       // inversion method
00103       //--------------------------------------------------------------
00104       // The computation time for this method grows with L.
00105       // Gives overflow for L > 80
00106       //--------------------------------------------------------------
00107       return PoissonInver(L);}}
00108 
00109   else {
00110     if (L > 2.E9) FatalError("Parameter too big in poisson function");
00111 
00112     //----------------------------------------------------------------
00113     // ratio-of-uniforms method
00114     //----------------------------------------------------------------
00115     // The computation time for this method does not depend on L.
00116     // Use where other methods would be slower.
00117     //----------------------------------------------------------------
00118     return PoissonRatioUniforms(L);}}
00119 
00120 
00121 /***********************************************************************
00122                       Subfunctions used by poisson
00123 ***********************************************************************/
00124 int32 StochasticLib1::PoissonLow(double L) {
00125 /*
00126    This subfunction generates a random variate with the poisson
00127    distribution for extremely low values of L.
00128 
00129    The method is a simple calculation of the probabilities of x = 1
00130    and x = 2. Higher values are ignored.
00131 
00132    The reason for using this method is to avoid the numerical inaccuracies
00133    in other methods.
00134 */
00135   double d, r;
00136   d = sqrt(L);
00137   if (Random() >= d) return 0;
00138   r = Random() * d;
00139   if (r > L * (1.-L)) return 0;
00140   if (r > 0.5 * L*L * (1.-L)) return 1;
00141   return 2;}
00142 
00143 int32 StochasticLib1::PoissonInver(double L) {
00144 /*
00145    This subfunction generates a random variate with the poisson
00146    distribution using inversion by the chop down method (PIN).
00147 
00148    Execution time grows with L. Gives overflow for L > 80.
00149 
00150    The value of bound must be adjusted to the maximal value of L.
00151 */
00152   const int bound = 130;             // safety bound. Must be > L + 8*sqrt(L).
00153   static double p_L_last = -1.;      // previous value of L
00154   static double p_f0;                // value at x=0
00155   double r;                          // uniform random number
00156   double f;                          // function value
00157   int32 x;                           // return value
00158 
00159   if (L != p_L_last) {               // set up
00160     p_L_last = L;
00161     p_f0 = exp(-L);}                 // f(0) = probability of x=0
00162 
00163   while (1) {
00164     r = Random();  x = 0;  f = p_f0;
00165     do {                        // recursive calculation: f(x) = f(x-1) * L / x
00166       r -= f;
00167       if (r <= 0) return x;
00168       x++;
00169       f *= L;
00170       r *= x;}                       // instead of f /= x
00171     while (x <= bound);}}
00172 
00173 int32 StochasticLib1::PoissonRatioUniforms(double L) {
00174 /*
00175    This subfunction generates a random variate with the poisson
00176    distribution using the ratio-of-uniforms rejection method (PRUAt).
00177 
00178    Execution time does not depend on L, except that it matters whether L
00179    is within the range where ln(n!) is tabulated.
00180 
00181    Reference: E. Stadlober: "The ratio of uniforms approach for generating
00182    discrete random variates". Journal of Computational and Applied Mathematics,
00183    vol. 31, no. 1, 1990, pp. 181-189.
00184 */
00185   static double p_L_last = -1.0;            // previous L
00186   static double p_a;                       // hat center
00187   static double p_h;                       // hat width
00188   static double p_g;                       // ln(L)
00189   static double p_q;                       // value at mode
00190   static int32 p_bound;                    // upper bound
00191   int32 mode;                              // mode
00192   double u;                                // uniform random
00193   double lf;                               // ln(f(x))
00194   double x;                                // real sample
00195   int32 k;                                 // integer sample
00196 
00197   if (p_L_last != L) {
00198     p_L_last = L;                           // Set-up
00199     p_a = L + 0.5;                          // hat center
00200     mode = (int32)L;                        // mode
00201     p_g  = log(L);
00202     p_q = mode * p_g - LnFac(mode);         // value at mode
00203     p_h = sqrt(SHAT1 * (L+0.5)) + SHAT2;    // hat width
00204     p_bound = (int32)(p_a + 6.0 * p_h);}    // safety-bound
00205 
00206   while(1) {
00207     u = Random();
00208     if (u == 0) continue;                   // avoid division by 0
00209     x = p_a + p_h * (Random() - 0.5) / u;
00210     if (x < 0 || x >= p_bound) continue;    // reject if outside valid range
00211     k = (int32)(x);
00212     lf = k * p_g - LnFac(k) - p_q;
00213     if (lf >= u * (4.0 - u) - 3.0) break;   // quick acceptance
00214     if (u * (u - lf) > 1.0) continue;       // quick rejection
00215     if (2.0 * log(u) <= lf) break;}         // final acceptance
00216   return(k);}
00217 
00218 
00219 /***********************************************************************
00220                       Constructor
00221 ***********************************************************************/
00222 StochasticLib1::StochasticLib1 (int seed)
00223   : RANDOM_GENERATOR(seed) {
00224   normal_x2_valid = 0;}
00225 
00226 
00227 

Generated on Wed Mar 7 14:44:59 2007 for Seagull by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002