src/support/GRan.cpp

Go to the documentation of this file.
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 }

Generated on Tue Jan 24 12:37:25 2017 for GammaLib by  doxygen 1.4.7