00001 /*************************************************************************** 00002 * GRan.cpp - Random number generator class * 00003 * ----------------------------------------------------------------------- * 00004 * copyright (C) 2011-2014 by Juergen Knoedlseder * 00005 * ----------------------------------------------------------------------- * 00006 * * 00007 * This program is free software: you can redistribute it and/or modify * 00008 * it under the terms of the GNU General Public License as published by * 00009 * the Free Software Foundation, either version 3 of the License, or * 00010 * (at your option) any later version. * 00011 * * 00012 * This program is distributed in the hope that it will be useful, * 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00015 * GNU General Public License for more details. * 00016 * * 00017 * You should have received a copy of the GNU General Public License * 00018 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 00019 * * 00020 ***************************************************************************/ 00021 /** 00022 * @file GRan.cpp 00023 * @brief Random number generator class implementation 00024 * @author Juergen Knoedlseder 00025 */ 00026 00027 /* __ Includes ___________________________________________________________ */ 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 #include <cmath> 00032 #include "GRan.hpp" 00033 #include "GTools.hpp" 00034 #include "GMath.hpp" 00035 #include "GException.hpp" 00036 00037 /* __ Method name definitions ____________________________________________ */ 00038 00039 /* __ Macros _____________________________________________________________ */ 00040 00041 /* __ Coding definitions _________________________________________________ */ 00042 00043 /* __ Debug definitions __________________________________________________ */ 00044 00045 /* __ Constants __________________________________________________________ */ 00046 00047 00048 /*========================================================================== 00049 = = 00050 = Constructors/destructors = 00051 = = 00052 ==========================================================================*/ 00053 00054 /***********************************************************************//** 00055 * @brief Void constructor 00056 ***************************************************************************/ 00057 GRan::GRan(void) 00058 { 00059 // Initialise private members 00060 init_members(); 00061 00062 // Return 00063 return; 00064 } 00065 00066 00067 /***********************************************************************//** 00068 * @brief Seed constructor 00069 * 00070 * @param[in] seed Random number generator seed. 00071 ***************************************************************************/ 00072 GRan::GRan(unsigned long long int seed) 00073 { 00074 // Initialise private 00075 init_members(seed); 00076 00077 // Return 00078 return; 00079 } 00080 00081 00082 /***********************************************************************//** 00083 * @brief Copy constructor 00084 * 00085 * @param[in] ran Random number generator. 00086 ***************************************************************************/ 00087 GRan::GRan(const GRan& ran) 00088 { 00089 // Initialise private 00090 init_members(); 00091 00092 // Copy members 00093 copy_members(ran); 00094 00095 // Return 00096 return; 00097 } 00098 00099 00100 /***********************************************************************//** 00101 * @brief Destructor 00102 ***************************************************************************/ 00103 GRan::~GRan(void) 00104 { 00105 // Free members 00106 free_members(); 00107 00108 // Return 00109 return; 00110 } 00111 00112 00113 /*========================================================================== 00114 = = 00115 = Operators = 00116 = = 00117 ==========================================================================*/ 00118 00119 /***********************************************************************//** 00120 * @brief Assignment operator 00121 * 00122 * @param[in] ran Random number generator. 00123 * @return Random number generator. 00124 ***************************************************************************/ 00125 GRan& GRan::operator=(const GRan& ran) 00126 { 00127 // Execute only if object is not identical 00128 if (this != &ran) { 00129 00130 // Free members 00131 free_members(); 00132 00133 // Initialise private members for clean destruction 00134 init_members(); 00135 00136 // Copy members 00137 copy_members(ran); 00138 00139 } // endif: object was not identical 00140 00141 // Return 00142 return *this; 00143 } 00144 00145 00146 /*========================================================================== 00147 = = 00148 = Public methods = 00149 = = 00150 ==========================================================================*/ 00151 00152 /***********************************************************************//** 00153 * @brief Clear random number generator 00154 * 00155 * This method properly resets the object to an initial state using the 00156 * default seed. 00157 ***************************************************************************/ 00158 void GRan::clear(void) 00159 { 00160 // Free class members 00161 free_members(); 00162 00163 // Initialise members 00164 init_members(); 00165 00166 // Return 00167 return; 00168 } 00169 00170 00171 /***********************************************************************//** 00172 * @brief Clone random number generator 00173 * 00174 * @return Pointer to deep copy of random number generator. 00175 **************************************************************************/ 00176 GRan* GRan::clone(void) const 00177 { 00178 return new GRan(*this); 00179 } 00180 00181 00182 /***********************************************************************//** 00183 * @brief Set seed of random number generator 00184 * 00185 * @param[in] seed Random number generator seed. 00186 * 00187 * This method properly resets the object to an initial state using the 00188 * specified seed. 00189 ***************************************************************************/ 00190 void GRan::seed(unsigned long long int seed) 00191 { 00192 // Free class members 00193 free_members(); 00194 00195 // Initialise members 00196 init_members(seed); 00197 00198 // Return 00199 return; 00200 } 00201 00202 00203 /***********************************************************************//** 00204 * @brief Return 32-bit random unsigned integer 00205 ***************************************************************************/ 00206 unsigned long int GRan::int32(void) 00207 { 00208 // Return random value 00209 return ((unsigned long int)int64()); 00210 } 00211 00212 00213 /***********************************************************************//** 00214 * @brief Return 64-bit random unsigned integer 00215 ***************************************************************************/ 00216 unsigned long long int GRan::int64(void) 00217 { 00218 // Update u 00219 m_value1 = m_value1 * 2862933555777941757LL + 7046029254386353087LL; 00220 00221 // Shuffle v 00222 m_value2 ^= m_value2 >> 17; 00223 m_value2 ^= m_value2 << 31; 00224 m_value2 ^= m_value2 >> 8; 00225 00226 // Update w 00227 m_value3 = 4294957665U * (m_value3 & 0xffffffff) + (m_value3 >> 32); 00228 00229 // Compute x 00230 unsigned long long int x = m_value1 ^ (m_value1 << 21); 00231 x ^= x >> 35; 00232 x ^= x << 4; 00233 00234 // Return random value 00235 return ((x + m_value2) ^ m_value3); 00236 } 00237 00238 00239 /***********************************************************************//** 00240 * @brief Returns random double precision floating value in range 0 to 1 00241 ***************************************************************************/ 00242 double GRan::uniform(void) 00243 { 00244 // Return random value 00245 return (5.42101086242752217e-20 * int64()); 00246 } 00247 00248 00249 /***********************************************************************//** 00250 * @brief Returns normal deviates 00251 * 00252 * Method Used: Box-Muller transform, outlined here: 00253 * http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform 00254 * 00255 * Code from: http://www.design.caltech.edu/erik/Misc/Gaussian.html 00256 ***************************************************************************/ 00257 double GRan::normal(void) 00258 { 00259 // Get random value 00260 double x1; 00261 double w; 00262 do { 00263 x1 = 2.0 * uniform() - 1.0; 00264 double x2 = 2.0 * uniform() - 1.0; 00265 w = x1 * x1 + x2 * x2; 00266 } while (w >= 1.0); 00267 00268 // Compute random value 00269 double value = x1 * std::sqrt((-2.0 * std::log(w)) / w); 00270 00271 // Return random value 00272 return value; 00273 } 00274 00275 00276 /***********************************************************************//** 00277 * @brief Returns exponential deviates 00278 * 00279 * @param[in] lambda Mean rate. 00280 * 00281 * Returns exponential deviates from the probability distribution 00282 * \f[p(x) = \lambda \exp( -\lambda x )\f] 00283 * where 00284 * \f$\lambda\f$ is the parameter of the distribution. 00285 * This method may be used to simulate the occurence time of an event, where 00286 * \f$\lambda\f$ is the mean event rate. Convsersely, \f$1/\lambda\f$ is the 00287 * mean waiting time between events. 00288 * 00289 * @todo Check that \f$\lambda>0\f$. 00290 ***************************************************************************/ 00291 double GRan::exp(const double& lambda) 00292 { 00293 // Allocate argument 00294 double x; 00295 00296 // Get non-zero uniform deviate 00297 do { 00298 x = uniform(); 00299 } while (x == 0.0); 00300 00301 // Return random value 00302 return (-std::log(x)/lambda); 00303 } 00304 00305 00306 /***********************************************************************//** 00307 * @brief Returns Poisson deviates 00308 * 00309 * @param[in] lambda Expectation value. 00310 * 00311 * Returns Poisson deviates for an expectation value. 00312 * 00313 * This method may be used to simulate the number of events in case that a 00314 * given mean number of events is expected. 00315 ***************************************************************************/ 00316 double GRan::poisson(const double& lambda) 00317 { 00318 // Declare result 00319 double value; 00320 00321 // Use direct method for small numbers ... 00322 if (lambda < 12.0) { 00323 if (lambda != m_old_lambda) { 00324 m_old_lambda = lambda; 00325 m_exp_lambda = std::exp(-lambda); 00326 } 00327 value = -1.0; 00328 double tmp = 1.0; 00329 do { 00330 value += 1.0; 00331 tmp *= uniform(); 00332 } while (tmp > m_exp_lambda); 00333 } // endif: direct method used 00334 00335 // ... otherwise use rejection method 00336 else { 00337 double tmp; 00338 if (lambda != m_old_lambda) { 00339 m_old_lambda = lambda; 00340 m_sqrt_lambda = std::sqrt(2.0*lambda); 00341 m_log_lambda = std::log(lambda); 00342 m_exp_lambda = lambda * m_log_lambda - gammalib::gammln(lambda+1.0); 00343 } 00344 do { 00345 double factor; 00346 do { 00347 factor = std::tan(gammalib::pi * uniform()); 00348 value = m_sqrt_lambda * factor + lambda; 00349 } while (value < 0.0); 00350 value = floor(value); 00351 tmp = 0.9*(1.0+factor*factor) * 00352 std::exp(value*m_log_lambda - gammalib::gammln(value+1.0)-m_exp_lambda); 00353 } while (uniform() > tmp); 00354 } 00355 00356 // Return random deviate 00357 return value; 00358 } 00359 00360 00361 /***********************************************************************//** 00362 * @brief Returns Chi2 deviates for 2 degrees of freedom 00363 * 00364 * Returns exponential deviates from the probability distribution 00365 * \f[p(x) = \frac{1}{2\pi} x \exp( -\frac{1}{2} x^2 )\f] 00366 * This method can be used to simulate the random radial offset of a measured 00367 * source position from the true source position, assuming an azimuthally 00368 * symmetric 2D Gaussian probability distribution. 00369 ***************************************************************************/ 00370 double GRan::chisq2(void) 00371 { 00372 // Allocate argument 00373 double x; 00374 00375 // Get uniform deviate < 1 00376 do { 00377 x = uniform(); 00378 } while (x == 1.0); 00379 00380 // Return random value 00381 return (std::sqrt(-2.0*std::log(1.0-x))); 00382 } 00383 00384 00385 /***********************************************************************//** 00386 * @brief Random sampling from a cumulative density function 00387 * 00388 * @param[in] cdf Array containing cumulative density function 00389 ***************************************************************************/ 00390 int GRan::cdf(const std::vector<double>& cdf) 00391 { 00392 // Get uniform random number 00393 double u = uniform(); 00394 00395 // Get pixel index according to random number. We use a bi-section 00396 // method to find the corresponding pixel index 00397 int low = 0; 00398 int high = cdf.size(); 00399 while ((high - low) > 1) { 00400 int mid = (low+high) / 2; 00401 if (u < cdf[mid]) { 00402 high = mid; 00403 } 00404 else if (cdf[mid] <= u) { 00405 low = mid; 00406 } 00407 } 00408 00409 // Return index 00410 return low; 00411 } 00412 00413 00414 /***********************************************************************//** 00415 * @brief Random sampling from a cumulative density function 00416 * 00417 * @param[in] cdf Vector containing cumulative density function 00418 * 00419 * @todo Somehow merge with the above method to reduce code repetition 00420 ***************************************************************************/ 00421 int GRan::cdf(const GVector& cdf) 00422 { 00423 // Get uniform random number 00424 double u = uniform(); 00425 00426 // Get pixel index according to random number. We use a bi-section 00427 // method to find the corresponding pixel index 00428 int low = 0; 00429 int high = cdf.size(); 00430 while ((high - low) > 1) { 00431 int mid = (low+high) / 2; 00432 if (u < cdf[mid]) { 00433 high = mid; 00434 } 00435 else if (cdf[mid] <= u) { 00436 low = mid; 00437 } 00438 } 00439 00440 // Return index 00441 return low; 00442 } 00443 00444 00445 /***********************************************************************//** 00446 * @brief Print random number generator information 00447 * 00448 * @param[in] chatter Chattiness (defaults to NORMAL). 00449 * @return String containing random number generator information. 00450 ***************************************************************************/ 00451 std::string GRan::print(const GChatter& chatter) const 00452 { 00453 // Initialise result string 00454 std::string result; 00455 00456 // Continue only if chatter is not silent 00457 if (chatter != SILENT) { 00458 00459 // Append header 00460 result.append("=== GRan ==="); 00461 00462 // Append information 00463 result.append("\n"+gammalib::parformat("Seed")+gammalib::str(m_seed)); 00464 result.append("\n"+gammalib::parformat("Value 1")+gammalib::str(m_value1)); 00465 result.append("\n"+gammalib::parformat("Value 2")+gammalib::str(m_value2)); 00466 result.append("\n"+gammalib::parformat("Value 3")+gammalib::str(m_value3)); 00467 00468 } // endif: chatter was not silent 00469 00470 // Return result 00471 return result; 00472 } 00473 00474 00475 /*========================================================================== 00476 = = 00477 = Private methods = 00478 = = 00479 ==========================================================================*/ 00480 00481 /***********************************************************************//** 00482 * @brief Initialise class members 00483 ***************************************************************************/ 00484 void GRan::init_members(unsigned long long int seed) 00485 { 00486 // Initialise members 00487 m_seed = seed; 00488 m_value2 = 4101842887655102017LL; 00489 m_value3 = 1; 00490 m_old_lambda = -1.0; 00491 m_sqrt_lambda = 0.0; 00492 m_log_lambda = 0.0; 00493 m_exp_lambda = 0.0; 00494 00495 // Initialise values 00496 m_value1 = m_seed ^ m_value2; 00497 int64(); 00498 m_value2 = m_value1; 00499 int64(); 00500 m_value3 = m_value2; 00501 int64(); 00502 00503 // Return 00504 return; 00505 } 00506 00507 00508 /***********************************************************************//** 00509 * @brief Copy class members 00510 * 00511 * @param[in] ran Random number generator. 00512 ***************************************************************************/ 00513 void GRan::copy_members(const GRan& ran) 00514 { 00515 // Copy members 00516 m_seed = ran.m_seed; 00517 m_value1 = ran.m_value1; 00518 m_value2 = ran.m_value2; 00519 m_value3 = ran.m_value3; 00520 m_old_lambda = ran.m_old_lambda; 00521 m_sqrt_lambda = ran.m_sqrt_lambda; 00522 m_log_lambda = ran.m_log_lambda; 00523 m_exp_lambda = ran.m_exp_lambda; 00524 00525 // Return 00526 return; 00527 } 00528 00529 00530 /***********************************************************************//** 00531 * @brief Delete class members 00532 ***************************************************************************/ 00533 void GRan::free_members(void) 00534 { 00535 // Return 00536 return; 00537 }