Geant4 Cross Reference |
1 // -*- C++ -*- 1 // -*- C++ -*- 2 // 2 // 3 // ------------------------------------------- 3 // ----------------------------------------------------------------------- 4 // HEP Random 4 // HEP Random 5 // --- RandPoissonQ -- 5 // --- RandPoissonQ --- 6 // class implementation f 6 // class implementation file 7 // ------------------------------------------- 7 // ----------------------------------------------------------------------- 8 8 9 // =========================================== 9 // ======================================================================= 10 // M. Fischler - Implemented new, much fast 10 // M. Fischler - Implemented new, much faster table-driven algorithm 11 // applicable for mu < 100 11 // applicable for mu < 100 12 // - Implemented "quick()" methods, shich 12 // - Implemented "quick()" methods, shich are the same as the 13 // new methods for mu < 100 and are a s 13 // new methods for mu < 100 and are a skew-corrected gaussian 14 // approximation for large mu. 14 // approximation for large mu. 15 // M. Fischler - Removed mean=100 from the 15 // M. Fischler - Removed mean=100 from the table-driven set, since it 16 // uses a value just off the end of the 16 // uses a value just off the end of the table. (April 2004) 17 // M Fischler - put and get to/from stream 17 // M Fischler - put and get to/from streams 12/15/04 18 // M Fischler - Utilize RandGaussQ rather 18 // M Fischler - Utilize RandGaussQ rather than RandGauss, as clearly 19 // intended by the inclusion of RandGau 19 // intended by the inclusion of RandGaussQ.h. Using RandGauss 20 // introduces a subtle trap in that the 20 // introduces a subtle trap in that the state of RandPoissonQ 21 // can never be properly captured witho 21 // can never be properly captured without also saveing the 22 // state of RandGauss! RandGaussQ is, 22 // state of RandGauss! RandGaussQ is, on the other hand, 23 // stateless except for the engine used 23 // stateless except for the engine used. 24 // M Fischler - Modified use of wrong engine << 24 // M Fisculer - Modified use of wrong engine when shoot (anEngine, mean) 25 // is called. This flaw was preventing 25 // is called. This flaw was preventing any hope of proper 26 // saving and restoring in the instance 26 // saving and restoring in the instance cases. 27 // M Fischler - fireArray using defaultMea 27 // M Fischler - fireArray using defaultMean 2/10/05 28 // M Fischler - put/get to/from streams 28 // M Fischler - put/get to/from streams uses pairs of ulongs when 29 // + storing doubles avoid problems with 29 // + storing doubles avoid problems with precision 30 // 4/14/05 30 // 4/14/05 31 // M Fischler - Modified use of shoot (mean) << 31 // M Fisculer - Modified use of shoot (mean) instead of 32 // shoot(getLocalEngine(), mean) when f 32 // shoot(getLocalEngine(), mean) when fire(mean) is called. 33 // This flaw was causing bad "cross-tal 33 // This flaw was causing bad "cross-talk" between modules 34 // in CMS, where one used its own engin 34 // in CMS, where one used its own engine, and the other 35 // used the static generator. 10/18/07 35 // used the static generator. 10/18/07 36 // 36 // 37 // =========================================== 37 // ======================================================================= 38 38 39 #include "CLHEP/Random/RandPoissonQ.h" 39 #include "CLHEP/Random/RandPoissonQ.h" 40 #include "CLHEP/Random/RandGaussQ.h" 40 #include "CLHEP/Random/RandGaussQ.h" 41 #include "CLHEP/Random/DoubConv.h" 41 #include "CLHEP/Random/DoubConv.h" 42 #include "CLHEP/Random/Stat.h" 42 #include "CLHEP/Random/Stat.h" 43 #include "CLHEP/Utility/thread_local.h" 43 #include "CLHEP/Utility/thread_local.h" 44 #include <cmath> // for std::pow() 44 #include <cmath> // for std::pow() 45 #include <iostream> << 46 #include <string> << 47 #include <vector> << 48 45 49 namespace CLHEP { 46 namespace CLHEP { 50 47 51 std::string RandPoissonQ::name() const {return 48 std::string RandPoissonQ::name() const {return "RandPoissonQ";} 52 HepRandomEngine & RandPoissonQ::engine() {retu 49 HepRandomEngine & RandPoissonQ::engine() {return RandPoisson::engine();} 53 50 54 // Initialization of static data: Note that t 51 // Initialization of static data: Note that this is all const static data, 55 // so that saveEngineStatus properly saves all 52 // so that saveEngineStatus properly saves all needed information. 56 53 57 // The following MUST MATCH the correspondin 54 // The following MUST MATCH the corresponding values used (in 58 // poissonTables.cc) when poissonTables.cdat 55 // poissonTables.cc) when poissonTables.cdat was created. 59 56 60 const double RandPoissonQ::FIRST_MU = 10;// lo 57 const double RandPoissonQ::FIRST_MU = 10;// lowest mu value in table 61 const double RandPoissonQ::LAST_MU = 95;// hi 58 const double RandPoissonQ::LAST_MU = 95;// highest mu value 62 const double RandPoissonQ::S = 5; // Sp 59 const double RandPoissonQ::S = 5; // Spacing between mu values 63 const int RandPoissonQ::BELOW = 30; // St 60 const int RandPoissonQ::BELOW = 30; // Starting point for N is at mu - BELOW 64 const int RandPoissonQ::ENTRIES = 51; // Nu 61 const int RandPoissonQ::ENTRIES = 51; // Number of entries in each mu row 65 62 66 const double RandPoissonQ::MAXIMUM_POISSON_DEV 63 const double RandPoissonQ::MAXIMUM_POISSON_DEVIATE = 2.0E9; 67 // Careful -- this is NOT the maximum number 64 // Careful -- this is NOT the maximum number that can be held in 68 // a long. It actually should be some large 65 // a long. It actually should be some large number of sigma below 69 // that. 66 // that. 70 67 71 // Here comes the big (9K bytes) table, kept 68 // Here comes the big (9K bytes) table, kept in a file of 72 // ENTRIES * (FIRST_MU - LAST_MU + 1)/S doub 69 // ENTRIES * (FIRST_MU - LAST_MU + 1)/S doubles 73 70 74 static const double poissonTables [ 51 * ( (95 71 static const double poissonTables [ 51 * ( (95-10)/5 + 1 ) ] = { 75 #include "CLHEP/Random/poissonTables.cdat" 72 #include "CLHEP/Random/poissonTables.cdat" 76 }; 73 }; 77 74 78 // 75 // 79 // Constructors and destructors: 76 // Constructors and destructors: 80 // 77 // 81 78 82 RandPoissonQ::~RandPoissonQ() { 79 RandPoissonQ::~RandPoissonQ() { 83 } 80 } 84 81 85 void RandPoissonQ::setupForDefaultMu() { 82 void RandPoissonQ::setupForDefaultMu() { 86 83 87 // The following are useful for quick approx 84 // The following are useful for quick approximation, for large mu 88 85 89 double sig2 = defaultMean * (.9998654 - .083 86 double sig2 = defaultMean * (.9998654 - .08346/defaultMean); 90 sigma = std::sqrt(sig2); 87 sigma = std::sqrt(sig2); 91 // sigma for the Guassian which approximates 88 // sigma for the Guassian which approximates the Poisson -- naively 92 // sqrt (defaultMean). 89 // sqrt (defaultMean). 93 // 90 // 94 // The multiplier corrects for fact that dis 91 // The multiplier corrects for fact that discretization of the form 95 // [gaussian+.5] increases the second moment 92 // [gaussian+.5] increases the second moment by a small amount. 96 93 97 double t = 1./(sig2); 94 double t = 1./(sig2); 98 95 99 a2 = t/6 + t*t/324; 96 a2 = t/6 + t*t/324; 100 a1 = std::sqrt (1-2*a2*a2*sig2); 97 a1 = std::sqrt (1-2*a2*a2*sig2); 101 a0 = defaultMean + .5 - sig2 * a2; 98 a0 = defaultMean + .5 - sig2 * a2; 102 99 103 // The formula will be a0 + a1*x + a2*x*x wh 100 // The formula will be a0 + a1*x + a2*x*x where x has 2nd moment of sigma. 104 // The coeffeicients are chosen to match the 101 // The coeffeicients are chosen to match the first THREE moments of the 105 // true Poisson distribution. 102 // true Poisson distribution. 106 // 103 // 107 // Actually, if the correction for discretiz 104 // Actually, if the correction for discretization were not needed, then 108 // a2 could be taken one order higher by add 105 // a2 could be taken one order higher by adding t*t*t/5832. However, 109 // the discretization correction is not perf 106 // the discretization correction is not perfect, leading to inaccuracy 110 // on the order to 1/mu**2, so adding a thir 107 // on the order to 1/mu**2, so adding a third term is overkill. 111 108 112 } // setupForDefaultMu() 109 } // setupForDefaultMu() 113 110 114 111 115 // 112 // 116 // fire, quick, operator(), and shoot methods: 113 // fire, quick, operator(), and shoot methods: 117 // 114 // 118 115 119 long RandPoissonQ::shoot(double xm) { 116 long RandPoissonQ::shoot(double xm) { 120 return shoot(getTheEngine(), xm); 117 return shoot(getTheEngine(), xm); 121 } 118 } 122 119 123 double RandPoissonQ::operator()() { 120 double RandPoissonQ::operator()() { 124 return (double) fire(); 121 return (double) fire(); 125 } 122 } 126 123 127 double RandPoissonQ::operator()( double mean ) 124 double RandPoissonQ::operator()( double mean ) { 128 return (double) fire(mean); 125 return (double) fire(mean); 129 } 126 } 130 127 131 long RandPoissonQ::fire(double mean) { 128 long RandPoissonQ::fire(double mean) { 132 return shoot(getLocalEngine(), mean); 129 return shoot(getLocalEngine(), mean); 133 } 130 } 134 131 135 long RandPoissonQ::fire() { 132 long RandPoissonQ::fire() { 136 if ( defaultMean < LAST_MU + S ) { 133 if ( defaultMean < LAST_MU + S ) { 137 return poissonDeviateSmall ( getLocalEngin 134 return poissonDeviateSmall ( getLocalEngine(), defaultMean ); 138 } else { 135 } else { 139 return poissonDeviateQuick ( getLocalEngin 136 return poissonDeviateQuick ( getLocalEngine(), a0, a1, a2, sigma ); 140 } 137 } 141 } // fire() 138 } // fire() 142 139 143 long RandPoissonQ::shoot(HepRandomEngine* anEn 140 long RandPoissonQ::shoot(HepRandomEngine* anEngine, double mean) { 144 141 145 // The following variables, static to this m 142 // The following variables, static to this method, apply to the 146 // last time a large mean was supplied; they 143 // last time a large mean was supplied; they obviate certain calculations 147 // if consecutive calls use the same mean. 144 // if consecutive calls use the same mean. 148 145 149 static CLHEP_THREAD_LOCAL double lastLargeMe 146 static CLHEP_THREAD_LOCAL double lastLargeMean = -1.; // Mean from previous shoot 150 // requiring poissonDeviateQuick() 147 // requiring poissonDeviateQuick() 151 static CLHEP_THREAD_LOCAL double lastA0; 148 static CLHEP_THREAD_LOCAL double lastA0; 152 static CLHEP_THREAD_LOCAL double lastA1; 149 static CLHEP_THREAD_LOCAL double lastA1; 153 static CLHEP_THREAD_LOCAL double lastA2; 150 static CLHEP_THREAD_LOCAL double lastA2; 154 static CLHEP_THREAD_LOCAL double lastSigma; 151 static CLHEP_THREAD_LOCAL double lastSigma; 155 152 156 if ( mean < LAST_MU + S ) { 153 if ( mean < LAST_MU + S ) { 157 return poissonDeviateSmall ( anEngine, mea 154 return poissonDeviateSmall ( anEngine, mean ); 158 } else { 155 } else { 159 if ( mean != lastLargeMean ) { 156 if ( mean != lastLargeMean ) { 160 // Compute the coefficients defining the 157 // Compute the coefficients defining the quadratic transformation from a 161 // Gaussian to a Poisson for this mean. 158 // Gaussian to a Poisson for this mean. Also save these for next time. 162 double sig2 = mean * (.9998654 - .08346/ 159 double sig2 = mean * (.9998654 - .08346/mean); 163 lastSigma = std::sqrt(sig2); 160 lastSigma = std::sqrt(sig2); 164 double t = 1./sig2; 161 double t = 1./sig2; 165 lastA2 = t*(1./6.) + t*t*(1./324.); 162 lastA2 = t*(1./6.) + t*t*(1./324.); 166 lastA1 = std::sqrt (1-2*lastA2*lastA2*si 163 lastA1 = std::sqrt (1-2*lastA2*lastA2*sig2); 167 lastA0 = mean + .5 - sig2 * lastA2; 164 lastA0 = mean + .5 - sig2 * lastA2; 168 } 165 } 169 return poissonDeviateQuick ( anEngine, las 166 return poissonDeviateQuick ( anEngine, lastA0, lastA1, lastA2, lastSigma ); 170 } 167 } 171 168 172 } // shoot (anEngine, mean) 169 } // shoot (anEngine, mean) 173 170 174 void RandPoissonQ::shootArray(const int size, 171 void RandPoissonQ::shootArray(const int size, long* vect, double m) { 175 for( long* v = vect; v != vect + size; ++v ) 172 for( long* v = vect; v != vect + size; ++v ) 176 *v = shoot(m); 173 *v = shoot(m); 177 // Note: We could test for m > 100, and i 174 // Note: We could test for m > 100, and if it is, precompute a0, a1, a2, 178 // and sigma and call the appropriate for 175 // and sigma and call the appropriate form of poissonDeviateQuick. 179 // But since those are cached anyway, not 176 // But since those are cached anyway, not much time would be saved. 180 } 177 } 181 178 182 void RandPoissonQ::shootArray(HepRandomEngine* << 183 long* vect, doubl << 184 for( long* v = vect; v != vect + size; ++v ) << 185 *v = shoot(anEngine,m1); << 186 } << 187 << 188 void RandPoissonQ::fireArray(const int size, l 179 void RandPoissonQ::fireArray(const int size, long* vect, double m) { 189 for( long* v = vect; v != vect + size; ++v ) 180 for( long* v = vect; v != vect + size; ++v ) 190 *v = fire( m ); 181 *v = fire( m ); 191 } 182 } 192 183 193 void RandPoissonQ::fireArray(const int size, l 184 void RandPoissonQ::fireArray(const int size, long* vect) { 194 for( long* v = vect; v != vect + size; ++v ) 185 for( long* v = vect; v != vect + size; ++v ) 195 *v = fire( defaultMean ); 186 *v = fire( defaultMean ); 196 } 187 } 197 188 198 189 199 // Quick Poisson deviate algorithm used by qui 190 // Quick Poisson deviate algorithm used by quick for large mu: 200 191 201 long RandPoissonQ::poissonDeviateQuick ( HepRa 192 long RandPoissonQ::poissonDeviateQuick ( HepRandomEngine *e, double mu ) { 202 193 203 // Compute the coefficients defining the qua 194 // Compute the coefficients defining the quadratic transformation from a 204 // Gaussian to a Poisson: 195 // Gaussian to a Poisson: 205 196 206 double sig2 = mu * (.9998654 - .08346/mu); 197 double sig2 = mu * (.9998654 - .08346/mu); 207 double sig = std::sqrt(sig2); 198 double sig = std::sqrt(sig2); 208 // The multiplier corrects for fact that dis 199 // The multiplier corrects for fact that discretization of the form 209 // [gaussian+.5] increases the second moment 200 // [gaussian+.5] increases the second moment by a small amount. 210 201 211 double t = 1./sig2; 202 double t = 1./sig2; 212 203 213 double sa2 = t*(1./6.) + t*t*(1./324.); 204 double sa2 = t*(1./6.) + t*t*(1./324.); 214 double sa1 = std::sqrt (1-2*sa2*sa2*sig2); 205 double sa1 = std::sqrt (1-2*sa2*sa2*sig2); 215 double sa0 = mu + .5 - sig2 * sa2; 206 double sa0 = mu + .5 - sig2 * sa2; 216 207 217 // The formula will be sa0 + sa1*x + sa2*x*x 208 // The formula will be sa0 + sa1*x + sa2*x*x where x has sigma of sq. 218 // The coeffeicients are chosen to match the 209 // The coeffeicients are chosen to match the first THREE moments of the 219 // true Poisson distribution. 210 // true Poisson distribution. 220 211 221 return poissonDeviateQuick ( e, sa0, sa1, sa 212 return poissonDeviateQuick ( e, sa0, sa1, sa2, sig ); 222 } 213 } 223 214 224 215 225 long RandPoissonQ::poissonDeviateQuick ( HepRa 216 long RandPoissonQ::poissonDeviateQuick ( HepRandomEngine *e, 226 double A0, double A1, double A2, double si 217 double A0, double A1, double A2, double sig) { 227 // 218 // 228 // Quick Poisson deviate algorithm used by qui 219 // Quick Poisson deviate algorithm used by quick for large mu: 229 // 220 // 230 // The principle: For very large mu, a poisso 221 // The principle: For very large mu, a poisson distribution can be approximated 231 // by a gaussian: return the integer part of m 222 // by a gaussian: return the integer part of mu + .5 + g where g is a unit 232 // normal. However, this yelds a miserable ap 223 // normal. However, this yelds a miserable approximation at values as 233 // "large" as 100. The primary problem is tha 224 // "large" as 100. The primary problem is that the poisson distribution is 234 // supposed to have a skew of 1/mu**2, and the 225 // supposed to have a skew of 1/mu**2, and the zero skew of the Guassian 235 // leads to errors of order as big as 1/mu**2. 226 // leads to errors of order as big as 1/mu**2. 236 // 227 // 237 // We substitute for the gaussian a quadratic 228 // We substitute for the gaussian a quadratic function of that gaussian random. 238 // The expression looks very nearly like mu + 229 // The expression looks very nearly like mu + .5 - 1/6 + g + g**2/(6*mu). 239 // The small positive quadratic term causes th 230 // The small positive quadratic term causes the resulting variate to have 240 // a positive skew; the -1/6 constant term is 231 // a positive skew; the -1/6 constant term is there to correct for this bias 241 // in the mean. By adjusting these two and th 232 // in the mean. By adjusting these two and the linear term, we can match the 242 // first three moments to high accuracy in 1/m 233 // first three moments to high accuracy in 1/mu. 243 // 234 // 244 // The sigma used is not precisely sqrt(mu) si 235 // The sigma used is not precisely sqrt(mu) since a rounded-off Gaussian 245 // has a second moment which is slightly large 236 // has a second moment which is slightly larger than that of the Gaussian. 246 // To compensate, sig is multiplied by a facto 237 // To compensate, sig is multiplied by a factor which is slightly less than 1. 247 238 248 // double g = RandGauss::shootQuick( e ); 239 // double g = RandGauss::shootQuick( e ); // TEMPORARY MOD: 249 double g = RandGaussQ::shoot( e ); // Unit 240 double g = RandGaussQ::shoot( e ); // Unit normal 250 g *= sig; 241 g *= sig; 251 double p = A2*g*g + A1*g + A0; 242 double p = A2*g*g + A1*g + A0; 252 if ( p < 0 ) return 0; // Shouldn't ever po 243 if ( p < 0 ) return 0; // Shouldn't ever possibly happen since 253 // mean should not be less than 100, b 244 // mean should not be less than 100, but 254 // we check due to paranoia. 245 // we check due to paranoia. 255 if ( p > MAXIMUM_POISSON_DEVIATE ) p = MAXIM 246 if ( p > MAXIMUM_POISSON_DEVIATE ) p = MAXIMUM_POISSON_DEVIATE; 256 247 257 return long(p); 248 return long(p); 258 249 259 } // poissonDeviateQuick () 250 } // poissonDeviateQuick () 260 251 261 252 262 253 263 long RandPoissonQ::poissonDeviateSmall (HepRan 254 long RandPoissonQ::poissonDeviateSmall (HepRandomEngine * e, double mean) { 264 long N1; 255 long N1; 265 long N2; 256 long N2; 266 // The following are for later use to form a 257 // The following are for later use to form a secondary random s: 267 double rRange; // This will hold the in 258 double rRange; // This will hold the interval between cdf for the 268 // computed N1 and cdf for N1+1. 259 // computed N1 and cdf for N1+1. 269 double rRemainder = 0; // This will hold the 260 double rRemainder = 0; // This will hold the length into that interval. 270 261 271 // Coming in, mean should not be more than L 262 // Coming in, mean should not be more than LAST_MU + S. However, we will 272 // be paranoid and test for this: 263 // be paranoid and test for this: 273 264 274 if ( mean > LAST_MU + S ) { 265 if ( mean > LAST_MU + S ) { 275 return RandPoisson::shoot(e, mean); 266 return RandPoisson::shoot(e, mean); 276 } 267 } 277 268 278 if (mean <= 0) { 269 if (mean <= 0) { 279 return 0; // Perhaps we ought to balk 270 return 0; // Perhaps we ought to balk harder here! 280 } 271 } 281 272 282 // >>> 1 <<< 273 // >>> 1 <<< 283 // Generate the first random, which we alwa 274 // Generate the first random, which we always will need. 284 275 285 double r = e->flat(); 276 double r = e->flat(); 286 277 287 // >>> 2 <<< 278 // >>> 2 <<< 288 // For small mean, below the start of the t 279 // For small mean, below the start of the tables, 289 // do the series for cdf directly. 280 // do the series for cdf directly. 290 281 291 // In this case, since we know the series wi 282 // In this case, since we know the series will terminate relatively quickly, 292 // almost alwaye use a precomputed 1/N array 283 // almost alwaye use a precomputed 1/N array without fear of overrunning it. 293 284 294 static const double oneOverN[50] = 285 static const double oneOverN[50] = 295 { 0, 1., 1/2., 1/3., 1/4., 1/5., 286 { 0, 1., 1/2., 1/3., 1/4., 1/5., 1/6., 1/7., 1/8., 1/9., 296 1/10., 1/11., 1/12., 1/13., 1/14., 1/15., 287 1/10., 1/11., 1/12., 1/13., 1/14., 1/15., 1/16., 1/17., 1/18., 1/19., 297 1/20., 1/21., 1/22., 1/23., 1/24., 1/25., 288 1/20., 1/21., 1/22., 1/23., 1/24., 1/25., 1/26., 1/27., 1/28., 1/29., 298 1/30., 1/31., 1/32., 1/33., 1/34., 1/35., 289 1/30., 1/31., 1/32., 1/33., 1/34., 1/35., 1/36., 1/37., 1/38., 1/39., 299 1/40., 1/41., 1/42., 1/43., 1/44., 1/45., 290 1/40., 1/41., 1/42., 1/43., 1/44., 1/45., 1/46., 1/47., 1/48., 1/49. }; 300 291 301 292 302 if ( mean < FIRST_MU ) { 293 if ( mean < FIRST_MU ) { 303 294 304 long N = 0; 295 long N = 0; 305 double term = std::exp(-mean); 296 double term = std::exp(-mean); 306 double cdf = term; 297 double cdf = term; 307 298 308 if ( r < (1 - 1.0E-9) ) { 299 if ( r < (1 - 1.0E-9) ) { 309 // 300 // 310 // **** This is a normal path: **** 301 // **** This is a normal path: **** 311 // 302 // 312 // Except when r is very close to 1, it 303 // Except when r is very close to 1, it is certain that we will exceed r 313 // before the 30-th term in the series, 304 // before the 30-th term in the series, so a simple while loop is OK. 314 const double* oneOverNptr = oneOverN; 305 const double* oneOverNptr = oneOverN; 315 while( cdf <= r ) { 306 while( cdf <= r ) { 316 N++ ; 307 N++ ; 317 oneOverNptr++; 308 oneOverNptr++; 318 term *= ( mean * (*oneOverNptr) ); 309 term *= ( mean * (*oneOverNptr) ); 319 cdf += term; 310 cdf += term; 320 } 311 } 321 return N; 312 return N; 322 // 313 // 323 // **** **** 314 // **** **** 324 // 315 // 325 } else { // r is almost 1... 316 } else { // r is almost 1... 326 // For r very near to 1 we would have to 317 // For r very near to 1 we would have to check that we don't fall 327 // off the end of the table of 1/N. Sin 318 // off the end of the table of 1/N. Since this is very rare, we just 328 // ignore the table and do the identical 319 // ignore the table and do the identical while loop, using explicit 329 // division. 320 // division. 330 double cdf0; 321 double cdf0; 331 while ( cdf <= r ) { 322 while ( cdf <= r ) { 332 N++ ; 323 N++ ; 333 term *= ( mean / N ); 324 term *= ( mean / N ); 334 cdf0 = cdf; 325 cdf0 = cdf; 335 cdf += term; 326 cdf += term; 336 if (cdf == cdf0) break; // Can't happen, but 327 if (cdf == cdf0) break; // Can't happen, but just in case... 337 } 328 } 338 return N; 329 return N; 339 } // end of if ( r compared to (1 - 1.0E-9 330 } // end of if ( r compared to (1 - 1.0E-9) ) 340 331 341 } // End of the code for mean < FIRST_MU 332 } // End of the code for mean < FIRST_MU 342 333 343 // >>> 3 <<< 334 // >>> 3 <<< 344 // Find the row of the tables corresponding 335 // Find the row of the tables corresponding to the highest tabulated mu 345 // which is no greater than our actual mean 336 // which is no greater than our actual mean. 346 337 347 int rowNumber = int((mean - FIRST_MU)/S); 338 int rowNumber = int((mean - FIRST_MU)/S); 348 const double * cdfs = &poissonTables [rowNum 339 const double * cdfs = &poissonTables [rowNumber*ENTRIES]; 349 double mu = FIRST_MU + rowNumber*S; 340 double mu = FIRST_MU + rowNumber*S; 350 double deltaMu = mean - mu; 341 double deltaMu = mean - mu; 351 int Nmin = int(mu - BELOW); 342 int Nmin = int(mu - BELOW); 352 if (Nmin < 1) Nmin = 1; 343 if (Nmin < 1) Nmin = 1; 353 int Nmax = Nmin + (ENTRIES - 1); 344 int Nmax = Nmin + (ENTRIES - 1); 354 345 355 346 356 // >>> 4 <<< 347 // >>> 4 <<< 357 // If r is less that the smallest entry in 348 // If r is less that the smallest entry in the row, then 358 // generate the deviate directly from the s 349 // generate the deviate directly from the series. 359 350 360 if ( r < cdfs[0] ) { 351 if ( r < cdfs[0] ) { 361 352 362 // In this case, we are tempted to use the 353 // In this case, we are tempted to use the actual mean, and not 363 // generate a second deviate to account fo 354 // generate a second deviate to account for the leftover part mean - mu. 364 // That would be an error, generating a di 355 // That would be an error, generating a distribution with enough excess 365 // at Nmin + (mean-mu)/2 to be detectable 356 // at Nmin + (mean-mu)/2 to be detectable in 4,000,000 trials. 366 357 367 // Since this case is very rare (never mor 358 // Since this case is very rare (never more than .2% of the r values) 368 // and can happen where N will be large (u 359 // and can happen where N will be large (up to 65 for the mu=95 row) 369 // we use explicit division so as to avoid 360 // we use explicit division so as to avoid having to worry about running 370 // out of oneOverN table. 361 // out of oneOverN table. 371 362 372 long N = 0; 363 long N = 0; 373 double term = std::exp(-mu); 364 double term = std::exp(-mu); 374 double cdf = term; 365 double cdf = term; 375 double cdf0; 366 double cdf0; 376 367 377 while(cdf <= r) { 368 while(cdf <= r) { 378 N++ ; 369 N++ ; 379 term *= ( mu / N ); 370 term *= ( mu / N ); 380 cdf0 = cdf; 371 cdf0 = cdf; 381 cdf += term; 372 cdf += term; 382 if (cdf == cdf0) break; // Can't happen, but 373 if (cdf == cdf0) break; // Can't happen, but just in case... 383 } 374 } 384 N1 = N; 375 N1 = N; 385 // std::cout << r << " " << N << " "; 376 // std::cout << r << " " << N << " "; 386 // DBG_small = true; 377 // DBG_small = true; 387 rRange = 0; // In this case there is alw 378 rRange = 0; // In this case there is always a second r needed 388 379 389 } // end of small-r case 380 } // end of small-r case 390 381 391 382 392 // >>> 5 <<< 383 // >>> 5 <<< 393 // Assuming r lies within the scope of the 384 // Assuming r lies within the scope of the row for this mu, find the 394 // largest entry not greater than r. N1 is 385 // largest entry not greater than r. N1 is the N corresponding to the 395 // index a. 386 // index a. 396 387 397 else if ( r < cdfs[ENTRIES-1] ) { // r i 388 else if ( r < cdfs[ENTRIES-1] ) { // r is also >= cdfs[0] 398 389 399 // 390 // 400 // **** This is the normal code path **** 391 // **** This is the normal code path **** 401 // 392 // 402 393 403 int a = 0; // Highest val 394 int a = 0; // Highest value of index such that cdfs[a] 404 // is known NOT to be greater than r. 395 // is known NOT to be greater than r. 405 int b = ENTRIES - 1; // Lowest value of i 396 int b = ENTRIES - 1; // Lowest value of index such that cdfs[b] is 406 // known to exeed r. 397 // known to exeed r. 407 398 408 while (b != (a+1) ) { 399 while (b != (a+1) ) { 409 int c = (a+b+1)>>1; 400 int c = (a+b+1)>>1; 410 if (r > cdfs[c]) { 401 if (r > cdfs[c]) { 411 a = c; 402 a = c; 412 } else { 403 } else { 413 b = c; 404 b = c; 414 } 405 } 415 } 406 } 416 407 417 N1 = Nmin + a; 408 N1 = Nmin + a; 418 rRange = cdfs[a+1] - cdfs[a]; 409 rRange = cdfs[a+1] - cdfs[a]; 419 rRemainder = r - cdfs[a]; 410 rRemainder = r - cdfs[a]; 420 411 421 // 412 // 422 // **** **** 413 // **** **** 423 // 414 // 424 415 425 } // end of medium-r (normal) case 416 } // end of medium-r (normal) case 426 417 427 418 428 // >>> 6 <<< 419 // >>> 6 <<< 429 // If r exceeds the greatest entry in the t 420 // If r exceeds the greatest entry in the table for this mu, then start 430 // from that cdf, and use the series to com 421 // from that cdf, and use the series to compute from there until r is 431 // exceeded. 422 // exceeded. 432 423 433 else { // if ( r >= cdfs[ENTRIES-1] ) { 424 else { // if ( r >= cdfs[ENTRIES-1] ) { 434 425 435 // Here, division must be done explicitly, 426 // Here, division must be done explicitly, and we must also protect against 436 // roundoff preventing termination. 427 // roundoff preventing termination. 437 428 438 // 429 // 439 //+++ cdfs[ENTRIES-1] is exp(-mu) sum (mu**m 430 //+++ cdfs[ENTRIES-1] is exp(-mu) sum (mu**m/m! , m=0 to Nmax) 440 //+++ (where Nmax = mu - BELOW + ENTRIES - 1 431 //+++ (where Nmax = mu - BELOW + ENTRIES - 1) 441 //+++ cdfs[ENTRIES-1]-cdfs[ENTRIES-2] is exp 432 //+++ cdfs[ENTRIES-1]-cdfs[ENTRIES-2] is exp(-mu) mu**(Nmax)/(Nmax)! 442 //+++ If the sum up to k-1 <= r < sum up to 433 //+++ If the sum up to k-1 <= r < sum up to k, then N = k-1 443 //+++ Consider k = Nmax in the above stateme 434 //+++ Consider k = Nmax in the above statement: 444 //+++ If cdfs[ENTRIES-2] <= r < cdfs[ENTRIES 435 //+++ If cdfs[ENTRIES-2] <= r < cdfs[ENTRIES-1], N would be Nmax-1 445 //+++ But here r >= cdfs[ENTRIES-1] so N >= 436 //+++ But here r >= cdfs[ENTRIES-1] so N >= Nmax 446 // 437 // 447 438 448 // Erroneous: 439 // Erroneous: 449 //+++ cdfs[ENTRIES-1] is exp(-mu) sum (mu**m 440 //+++ cdfs[ENTRIES-1] is exp(-mu) sum (mu**m/m! , m=0 to Nmax-1) 450 //+++ cdfs[ENTRIES-1]-cdfs[ENTRIES-2] is exp 441 //+++ cdfs[ENTRIES-1]-cdfs[ENTRIES-2] is exp(-mu) mu**(Nmax-1)/(Nmax-1)! 451 //+++ If a sum up to k-1 <= r < sum up to k, 442 //+++ If a sum up to k-1 <= r < sum up to k, then N = k-1 452 //+++ So if cdfs[ENTRIES-1] were > r, N woul 443 //+++ So if cdfs[ENTRIES-1] were > r, N would be Nmax-1 (or less) 453 //+++ But here r >= cdfs[ENTRIES-1] so N >= 444 //+++ But here r >= cdfs[ENTRIES-1] so N >= Nmax 454 // 445 // 455 446 456 // std::cout << "r = " << r << " mu = " < 447 // std::cout << "r = " << r << " mu = " << mu << "\n"; 457 long N = Nmax -1; 448 long N = Nmax -1; 458 double cdf = cdfs[ENTRIES-1]; 449 double cdf = cdfs[ENTRIES-1]; 459 double term = cdf - cdfs[ENTRIES-2]; 450 double term = cdf - cdfs[ENTRIES-2]; 460 double cdf0; 451 double cdf0; 461 while(cdf <= r) { 452 while(cdf <= r) { 462 N++ ; 453 N++ ; 463 // std::cout << " N " << N << " term " < 454 // std::cout << " N " << N << " term " << 464 // term << " cdf " << cdf << "\n"; 455 // term << " cdf " << cdf << "\n"; 465 term *= ( mu / N ); 456 term *= ( mu / N ); 466 cdf0 = cdf; 457 cdf0 = cdf; 467 cdf += term; 458 cdf += term; 468 if (cdf == cdf0) break; // If term gets so s 459 if (cdf == cdf0) break; // If term gets so small cdf stops increasing, 469 // terminate using that value of N sin 460 // terminate using that value of N since we 470 // would never reach r. 461 // would never reach r. 471 } 462 } 472 N1 = N; 463 N1 = N; 473 rRange = 0; // We can't validly omit the 464 rRange = 0; // We can't validly omit the second true random 474 465 475 // N = Nmax -1; 466 // N = Nmax -1; 476 // cdf = cdfs[ENTRIES-1]; 467 // cdf = cdfs[ENTRIES-1]; 477 // term = cdf - cdfs[ENTRIES-2]; 468 // term = cdf - cdfs[ENTRIES-2]; 478 // for (int isxz=0; isxz < 100; isxz++) 469 // for (int isxz=0; isxz < 100; isxz++) { 479 // N++ ; 470 // N++ ; 480 // term *= ( mu / N ); 471 // term *= ( mu / N ); 481 // cdf0 = cdf; 472 // cdf0 = cdf; 482 // cdf += term; 473 // cdf += term; 483 // } 474 // } 484 // std::cout.precision(20); 475 // std::cout.precision(20); 485 // std::cout << "Final sum is " << cdf 476 // std::cout << "Final sum is " << cdf << "\n"; 486 477 487 } // end of large-r case 478 } // end of large-r case 488 479 489 480 490 481 491 // >>> 7 <<< 482 // >>> 7 <<< 492 // Form a second random, s, based on the po 483 // Form a second random, s, based on the position of r within the range 493 // of this table entry to the next entry. 484 // of this table entry to the next entry. 494 485 495 // However, if this range is very small, the 486 // However, if this range is very small, then we lose too many bits of 496 // randomness. In that situation, we genera 487 // randomness. In that situation, we generate a second random for s. 497 488 498 double s; 489 double s; 499 490 500 static const double MINRANGE = .01; // Sac 491 static const double MINRANGE = .01; // Sacrifice up to two digits of 501 // randomness when using r to 492 // randomness when using r to produce 502 // a second random s. Leads to up t 493 // a second random s. Leads to up to 503 // .09 extra randoms each time. 494 // .09 extra randoms each time. 504 495 505 if ( rRange > MINRANGE ) { 496 if ( rRange > MINRANGE ) { 506 // 497 // 507 // **** This path taken 90% of the time ** 498 // **** This path taken 90% of the time **** 508 // 499 // 509 s = rRemainder / rRange; 500 s = rRemainder / rRange; 510 } else { 501 } else { 511 s = e->flat(); // extra true random neede 502 s = e->flat(); // extra true random needed about one time in 10. 512 } 503 } 513 504 514 // >>> 8 <<< 505 // >>> 8 <<< 515 // Use the direct summation method to form 506 // Use the direct summation method to form a second poisson deviate N2 516 // from deltaMu and s. 507 // from deltaMu and s. 517 508 518 N2 = 0; 509 N2 = 0; 519 double term = std::exp(-deltaMu); 510 double term = std::exp(-deltaMu); 520 double cdf = term; 511 double cdf = term; 521 512 522 if ( s < (1 - 1.0E-10) ) { 513 if ( s < (1 - 1.0E-10) ) { 523 // 514 // 524 // This is the normal path: 515 // This is the normal path: 525 // 516 // 526 const double* oneOverNptr = oneOverN; 517 const double* oneOverNptr = oneOverN; 527 while( cdf <= s ) { 518 while( cdf <= s ) { 528 N2++ ; 519 N2++ ; 529 oneOverNptr++; 520 oneOverNptr++; 530 term *= ( deltaMu * (*oneOverNptr) ); 521 term *= ( deltaMu * (*oneOverNptr) ); 531 cdf += term; 522 cdf += term; 532 } 523 } 533 } else { // s is almost 1... 524 } else { // s is almost 1... 534 while( cdf <= s ) { 525 while( cdf <= s ) { 535 N2++ ; 526 N2++ ; 536 term *= ( deltaMu / N2 ); 527 term *= ( deltaMu / N2 ); 537 cdf += term; 528 cdf += term; 538 } 529 } 539 } // end of if ( s compared to (1 - 1.0E-10) 530 } // end of if ( s compared to (1 - 1.0E-10) ) 540 531 541 // >>> 9 <<< 532 // >>> 9 <<< 542 // The result is the sum of those two devia 533 // The result is the sum of those two deviates 543 534 544 // if (DBG_small) { 535 // if (DBG_small) { 545 // std::cout << N2 << " " << N1+N2 << 536 // std::cout << N2 << " " << N1+N2 << "\n"; 546 // DBG_small = false; 537 // DBG_small = false; 547 // } 538 // } 548 539 549 return N1 + N2; 540 return N1 + N2; 550 541 551 } // poissonDeviate() 542 } // poissonDeviate() 552 543 553 std::ostream & RandPoissonQ::put ( std::ostrea 544 std::ostream & RandPoissonQ::put ( std::ostream & os ) const { 554 long pr=os.precision(20); << 545 int pr=os.precision(20); 555 std::vector<unsigned long> t(2); 546 std::vector<unsigned long> t(2); 556 os << " " << name() << "\n"; 547 os << " " << name() << "\n"; 557 os << "Uvec" << "\n"; 548 os << "Uvec" << "\n"; 558 t = DoubConv::dto2longs(a0); 549 t = DoubConv::dto2longs(a0); 559 os << a0 << " " << t[0] << " " << t[1] << "\ 550 os << a0 << " " << t[0] << " " << t[1] << "\n"; 560 t = DoubConv::dto2longs(a1); 551 t = DoubConv::dto2longs(a1); 561 os << a1 << " " << t[0] << " " << t[1] << "\ 552 os << a1 << " " << t[0] << " " << t[1] << "\n"; 562 t = DoubConv::dto2longs(a2); 553 t = DoubConv::dto2longs(a2); 563 os << a2 << " " << t[0] << " " << t[1] << "\ 554 os << a2 << " " << t[0] << " " << t[1] << "\n"; 564 t = DoubConv::dto2longs(sigma); 555 t = DoubConv::dto2longs(sigma); 565 os << sigma << " " << t[0] << " " << t[1] << 556 os << sigma << " " << t[0] << " " << t[1] << "\n"; 566 RandPoisson::put(os); 557 RandPoisson::put(os); 567 os.precision(pr); 558 os.precision(pr); 568 return os; 559 return os; 569 #ifdef REMOVED 560 #ifdef REMOVED 570 int pr=os.precision(20); 561 int pr=os.precision(20); 571 os << " " << name() << "\n"; 562 os << " " << name() << "\n"; 572 os << a0 << " " << a1 << " " << a2 << "\n"; 563 os << a0 << " " << a1 << " " << a2 << "\n"; 573 os << sigma << "\n"; 564 os << sigma << "\n"; 574 RandPoisson::put(os); 565 RandPoisson::put(os); 575 os.precision(pr); 566 os.precision(pr); 576 return os; 567 return os; 577 #endif 568 #endif 578 } 569 } 579 570 580 std::istream & RandPoissonQ::get ( std::istrea 571 std::istream & RandPoissonQ::get ( std::istream & is ) { 581 std::string inName; 572 std::string inName; 582 is >> inName; 573 is >> inName; 583 if (inName != name()) { 574 if (inName != name()) { 584 is.clear(std::ios::badbit | is.rdstate()); 575 is.clear(std::ios::badbit | is.rdstate()); 585 std::cerr << "Mismatch when expecting to r 576 std::cerr << "Mismatch when expecting to read state of a " 586 << name() << " distribution\n" 577 << name() << " distribution\n" 587 << "Name found was " << inName 578 << "Name found was " << inName 588 << "\nistream is left in the badbit st 579 << "\nistream is left in the badbit state\n"; 589 return is; 580 return is; 590 } 581 } 591 if (possibleKeywordInput(is, "Uvec", a0)) { 582 if (possibleKeywordInput(is, "Uvec", a0)) { 592 std::vector<unsigned long> t(2); 583 std::vector<unsigned long> t(2); 593 is >> a0 >> t[0] >> t[1]; a0 = DoubConv::l 584 is >> a0 >> t[0] >> t[1]; a0 = DoubConv::longs2double(t); 594 is >> a1 >> t[0] >> t[1]; a1 = DoubConv::l 585 is >> a1 >> t[0] >> t[1]; a1 = DoubConv::longs2double(t); 595 is >> a2 >> t[0] >> t[1]; a2 = DoubConv::l 586 is >> a2 >> t[0] >> t[1]; a2 = DoubConv::longs2double(t); 596 is >> sigma >> t[0] >> t[1]; sigma = DoubC 587 is >> sigma >> t[0] >> t[1]; sigma = DoubConv::longs2double(t); 597 RandPoisson::get(is); 588 RandPoisson::get(is); 598 return is; 589 return is; 599 } 590 } 600 // is >> a0 encompassed by possibleKeywordIn 591 // is >> a0 encompassed by possibleKeywordInput 601 is >> a1 >> a2 >> sigma; 592 is >> a1 >> a2 >> sigma; 602 RandPoisson::get(is); 593 RandPoisson::get(is); 603 return is; 594 return is; 604 } 595 } 605 596 606 } // namespace CLHEP 597 } // namespace CLHEP 607 598 608 599