Main MRPT website > C++ reference
MRPT logo
RandomGenerators.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef RandomGenerator_H
00029 #define RandomGenerator_H
00030 
00031 #include <mrpt/utils/utils_defs.h>
00032 #include <mrpt/math/CMatrixTemplateNumeric.h>
00033 #include <mrpt/math/ops_matrices.h>
00034 
00035 namespace mrpt
00036 {
00037         /** A namespace of pseudo-random numbers genrators of diferent distributions. The central class in this namespace is mrpt::random::CRandomGenerator
00038          * \ingroup mrpt_base_grp
00039          */
00040         namespace random
00041         {
00042                 using namespace mrpt::utils;
00043                 using namespace mrpt::math;
00044 
00045                 /** A thred-safe pseudo random number generator, based on an internal MT19937 randomness generator.
00046                   * The base algorithm for randomness is platform-independent. See http://en.wikipedia.org/wiki/Mersenne_twister
00047                   *
00048                   * For real thread-safety, each thread must create and use its own instance of this class.
00049                   *
00050                   * Single-thread programs can use the static object mrpt::random::randomGenerator
00051                  * \ingroup mrpt_base_grp
00052                   */
00053                 class BASE_IMPEXP CRandomGenerator
00054                 {
00055                 protected:
00056                         /** Data used internally by the MT19937 PRNG algorithm. */
00057                         struct  TMT19937_data
00058                         {
00059                                 TMT19937_data() : index(0), seed_initialized(false)
00060                                 {}
00061                                 uint32_t        MT[624];
00062                                 uint32_t        index;
00063                                 bool            seed_initialized;
00064                         } m_MT19937_data;
00065 
00066                         void MT19937_generateNumbers();
00067                         void MT19937_initializeGenerator(const uint32_t &seed);
00068 
00069                 public:
00070 
00071                         /** @name Initialization
00072                          @{ */
00073 
00074                                 /** Default constructor: initialize random seed based on current time */
00075                                 CRandomGenerator() : m_MT19937_data() { randomize(); }
00076 
00077                                 /** Constructor for providing a custom random seed to initialize the PRNG */
00078                                 CRandomGenerator(const uint32_t seed) : m_MT19937_data() { randomize(seed); }
00079 
00080                                 void randomize(const uint32_t seed);  //!< Initialize the PRNG from the given random seed
00081                                 void randomize();       //!< Randomize the generators, based on current time
00082 
00083                         /** @} */
00084 
00085                         /** @name Uniform pdf
00086                          @{ */
00087 
00088                                 /** Generate a uniformly distributed pseudo-random number using the MT19937 algorithm, in the whole range of 32-bit integers.
00089                                   *  See: http://en.wikipedia.org/wiki/Mersenne_twister */
00090                                 uint32_t drawUniform32bit();
00091 
00092                                 /** Generate a uniformly distributed pseudo-random number using the MT19937 algorithm, scaled to the selected range. */
00093                                 double drawUniform( const double Min, const double Max) {
00094                                         return Min + (Max-Min)* drawUniform32bit() * 2.3283064370807973754314699618685e-10; // 0xFFFFFFFF ^ -1
00095                                 }
00096 
00097                                 /** Fills the given matrix with independent, uniformly distributed samples.
00098                                   * Matrix classes can be CMatrixTemplateNumeric or CMatrixFixedNumeric
00099                                   * \sa drawUniform
00100                                   */
00101                                 template <class MAT>
00102                                 void drawUniformMatrix(
00103                                         MAT &matrix,
00104                                         const  double unif_min = 0,
00105                                         const  double unif_max = 1 )
00106                                 {
00107                                         for (size_t r=0;r<matrix.getRowCount();r++)
00108                                                 for (size_t c=0;c<matrix.getColCount();c++)
00109                                                         matrix.get_unsafe(r,c) = static_cast<typename MAT::value_type>( drawUniform(unif_min,unif_max) );
00110                                 }
00111 
00112                                 /** Fills the given vector with independent, uniformly distributed samples.
00113                                   * \sa drawUniform
00114                                   */
00115                                 template <class VEC>
00116                                 void drawUniformVector(
00117                                         VEC & v,
00118                                         const  double unif_min = 0,
00119                                         const  double unif_max = 1 )
00120                                 {
00121                                         const size_t N = v.size();
00122                                         for (size_t c=0;c<N;c++)
00123                                                 v[c] = static_cast<typename VEC::value_type>( drawUniform(unif_min,unif_max) );
00124                                 }
00125 
00126                         /** @} */
00127 
00128                         /** @name Normal/Gaussian pdf
00129                          @{ */
00130 
00131                                 /** Generate a normalized (mean=0, std=1) normally distributed sample.
00132                                  *  \param likelihood If desired, pass a pointer to a double which will receive the likelihood of the given sample to have been obtained, that is, the value of the normal pdf at the sample value.
00133                                  */
00134                                 double drawGaussian1D_normalized( double *likelihood = NULL);
00135 
00136                                 /** Generate a normally distributed pseudo-random number.
00137                                  * \param mean The mean value of desired normal distribution
00138                                  * \param std  The standard deviation value of desired normal distribution
00139                                  */
00140                                 double drawGaussian1D( const double mean, const double std ) {
00141                                         return mean+std*drawGaussian1D_normalized();
00142                                 }
00143 
00144                                 /** Fills the given matrix with independent, 1D-normally distributed samples.
00145                                   * Matrix classes can be CMatrixTemplateNumeric or CMatrixFixedNumeric
00146                                   * \sa drawGaussian1D
00147                                   */
00148                                 template <class MAT>
00149                                 void drawGaussian1DMatrix(
00150                                         MAT &matrix,
00151                                         const double mean = 0,
00152                                         const double std = 1 )
00153                                 {
00154                                         for (size_t r=0;r<matrix.getRowCount();r++)
00155                                                 for (size_t c=0;c<matrix.getColCount();c++)
00156                                                         matrix.get_unsafe(r,c) = static_cast<typename MAT::value_type>( drawGaussian1D(mean,std) );
00157                                 }
00158 
00159                                 /** Generates a random definite-positive matrix of the given size, using the formula C = v*v^t + epsilon*I, with "v" being a vector of gaussian random samples.
00160                                   */
00161                                 CMatrixDouble drawDefinitePositiveMatrix(const size_t dim, const double std_scale = 1.0, const double diagonal_epsilon = 1e-8);
00162 
00163                                 /** Fills the given vector with independent, 1D-normally distributed samples.
00164                                   * \sa drawGaussian1D
00165                                   */
00166                                 template <class VEC>
00167                                 void drawGaussian1DVector(
00168                                         VEC & v,
00169                                         const double mean = 0,
00170                                         const double std = 1 )
00171                                 {
00172                                         const size_t N = v.size();
00173                                         for (size_t c=0;c<N;c++)
00174                                                 v[c] = static_cast<typename VEC::value_type>( drawGaussian1D(mean,std) );
00175                                 }
00176 
00177                                 /** Generate multidimensional random samples according to a given covariance matrix.
00178                                  *  Mean is assumed to be zero if mean==NULL.
00179                                  * \exception std::exception On invalid covariance matrix
00180                                  * \sa drawGaussianMultivariateMany
00181                                  */
00182                                  template <typename T>
00183                                  void  drawGaussianMultivariate(
00184                                         std::vector<T>          &out_result,
00185                                         const CMatrixTemplateNumeric<T> &cov,
00186                                         const std::vector<T>*  mean = NULL
00187                                         );
00188 
00189 
00190                                 /** Generate multidimensional random samples according to a given covariance matrix.
00191                                  *  Mean is assumed to be zero if mean==NULL.
00192                                  * \exception std::exception On invalid covariance matrix
00193                                  * \sa drawGaussianMultivariateMany
00194                                  */
00195                                  template <class VECTORLIKE,class COVMATRIX>
00196                                  void  drawGaussianMultivariate(
00197                                         VECTORLIKE      &out_result,
00198                                         const COVMATRIX &cov,
00199                                         const VECTORLIKE* mean = NULL
00200                                         )
00201                                 {
00202                                         const size_t N = cov.rows();
00203                                         ASSERT_(cov.rows()==cov.cols())
00204                                         if (mean) ASSERT_EQUAL_(size_t(mean->size()),N)
00205 
00206                                         // Compute eigenvalues/eigenvectors of cov:
00207                                         Eigen::SelfAdjointEigenSolver<typename COVMATRIX::PlainObject> eigensolver(cov);
00208 
00209                                         typename Eigen::SelfAdjointEigenSolver<typename COVMATRIX::PlainObject>::MatrixType eigVecs = eigensolver.eigenvectors();
00210                                         typename Eigen::SelfAdjointEigenSolver<typename COVMATRIX::PlainObject>::RealVectorType eigVals = eigensolver.eigenvalues();
00211 
00212                                         // Scale eigenvectors with eigenvalues:
00213                                         // D.Sqrt(); Z = Z * D; (for each column)
00214                                         eigVals = eigVals.array().sqrt();
00215                                         for (typename COVMATRIX::Index i=0;i<eigVecs.cols();i++)
00216                                                 eigVecs.col(i) *= eigVals[i];
00217 
00218                                         // Set size of output vector:
00219                                         out_result.assign(N,0);
00220 
00221                                         for (size_t i=0;i<N;i++)
00222                                         {
00223                                                 typename COVMATRIX::Scalar rnd = drawGaussian1D_normalized();
00224                                                 for (size_t d=0;d<N;d++)
00225                                                         out_result[d]+= eigVecs.coeff(d,i) * rnd;
00226                                         }
00227                                         if (mean)
00228                                                 for (size_t d=0;d<N;d++)
00229                                                         out_result[d]+= (*mean)[d];
00230                                 }
00231 
00232                                 /** Generate a given number of multidimensional random samples according to a given covariance matrix.
00233                                  * \param cov The covariance matrix where to draw the samples from.
00234                                  * \param desiredSamples The number of samples to generate.
00235                                  * \param ret The output list of samples
00236                                  * \param mean The mean, or zeros if mean==NULL.
00237                                  */
00238                                  template <typename VECTOR_OF_VECTORS,typename COVMATRIX>
00239                                  void  drawGaussianMultivariateMany(
00240                                         VECTOR_OF_VECTORS       &ret,
00241                                         size_t               desiredSamples,
00242                                         const COVMATRIX     &cov,
00243                                         const typename VECTOR_OF_VECTORS::value_type *mean = NULL )
00244                                 {
00245                                         ASSERT_EQUAL_(cov.cols(),cov.rows())
00246                                         if (mean) ASSERT_EQUAL_(size_t(mean->size()),size_t(cov.cols()))
00247 
00248                                         // Compute eigenvalues/eigenvectors of cov:
00249                                         Eigen::SelfAdjointEigenSolver<typename COVMATRIX::PlainObject> eigensolver(cov);
00250 
00251                                         typename Eigen::SelfAdjointEigenSolver<typename COVMATRIX::PlainObject>::MatrixType eigVecs = eigensolver.eigenvectors();
00252                                         typename Eigen::SelfAdjointEigenSolver<typename COVMATRIX::PlainObject>::RealVectorType eigVals = eigensolver.eigenvalues();
00253 
00254                                         // Scale eigenvectors with eigenvalues:
00255                                         // D.Sqrt(); Z = Z * D; (for each column)
00256                                         eigVals = eigVals.array().sqrt();
00257                                         for (typename COVMATRIX::Index i=0;i<eigVecs.cols();i++)
00258                                                 eigVecs.col(i) *= eigVals[i];
00259 
00260                                         // Set size of output vector:
00261                                         ret.resize(desiredSamples);
00262                                         const size_t N = cov.cols();
00263                                         for (size_t k=0;k<desiredSamples;k++)
00264                                         {
00265                                                 ret[k].assign(N,0);
00266                                                 for (size_t i=0;i<N;i++)
00267                                                 {
00268                                                         typename COVMATRIX::Scalar rnd = drawGaussian1D_normalized();
00269                                                         for (size_t d=0;d<N;d++)
00270                                                                 ret[k][d]+= eigVecs.coeff(d,i) * rnd;
00271                                                 }
00272                                                 if (mean)
00273                                                         for (size_t d=0;d<N;d++)
00274                                                                 ret[k][d]+= (*mean)[d];
00275                                         }
00276                                 }
00277 
00278 
00279                         /** @} */
00280 
00281 
00282                         /** @name Miscellaneous
00283                          @{ */
00284 
00285                                 /** Returns a random permutation of a vector: all the elements of the input vector are in the output but at random positions.
00286                                   */
00287                                 template <class VEC>
00288                                 void  permuteVector(const VEC &in_vector, VEC &out_result)
00289                                 {
00290                                         out_result = in_vector;
00291                                         const size_t N = out_result.size();
00292                                         if (N>1)
00293                                                 std::random_shuffle( &out_result[0],&out_result[N-1] );
00294                                 }
00295 
00296                         /** @} */
00297 
00298                 }; // end of CRandomGenerator --------------------------------------------------------------
00299 
00300 
00301                 /** A static instance of a CRandomGenerator class, for use in single-thread applications */
00302                 extern BASE_IMPEXP CRandomGenerator randomGenerator;
00303 
00304 
00305                 /** A random number generator for usage in STL algorithms expecting a function like this (eg, random_shuffle):
00306                   */
00307                 inline ptrdiff_t random_generator_for_STL(ptrdiff_t i)
00308                 {
00309                         return randomGenerator.drawUniform32bit() % i;
00310                 }
00311 
00312                 /** Fills the given matrix with independent, uniformly distributed samples.
00313                   * Matrix classes can be CMatrixTemplateNumeric or CMatrixFixedNumeric
00314                   * \sa matrixRandomNormal
00315                   */
00316                 template <class MAT>
00317                 void matrixRandomUni(
00318                         MAT &matrix,
00319                         const  double unif_min = 0,
00320                         const  double unif_max = 1 )
00321                 {
00322                         for (size_t r=0;r<matrix.getRowCount();r++)
00323                                 for (size_t c=0;c<matrix.getColCount();c++)
00324                                         matrix.get_unsafe(r,c) = static_cast<typename MAT::value_type>( randomGenerator.drawUniform(unif_min,unif_max) );
00325                 }
00326 
00327                 /** Fills the given matrix with independent, uniformly distributed samples.
00328                   * \sa vectorRandomNormal
00329                   */
00330                 template <class T>
00331                 void vectorRandomUni(
00332                         std::vector<T> &v_out,
00333                         const  T& unif_min = 0,
00334                         const  T& unif_max = 1 )
00335                 {
00336                         size_t n = v_out.size();
00337                         for (size_t r=0;r<n;r++)
00338                                 v_out[r] = randomGenerator.drawUniform(unif_min,unif_max);
00339                 }
00340 
00341                 /** Fills the given matrix with independent, normally distributed samples.
00342                   * Matrix classes can be CMatrixTemplateNumeric or CMatrixFixedNumeric
00343                   * \sa matrixRandomUni
00344                   */
00345                 template <class MAT>
00346                 void matrixRandomNormal(
00347                         MAT &matrix,
00348                         const double mean = 0,
00349                         const double std = 1 )
00350                 {
00351                         for (size_t r=0;r<matrix.getRowCount();r++)
00352                                 for (size_t c=0;c<matrix.getColCount();c++)
00353                                         matrix.get_unsafe(r,c) = static_cast<typename MAT::value_type>( mean + std*randomGenerator.drawGaussian1D_normalized() );
00354                 }
00355 
00356                 /** Generates a random vector with independent, normally distributed samples.
00357                   * \sa matrixRandomUni
00358                   */
00359                 template <class T>
00360                 void vectorRandomNormal(
00361                         std::vector<T> &v_out,
00362                         const  T& mean = 0,
00363                         const  T& std = 1 )
00364                 {
00365                         size_t n = v_out.size();
00366                         for (size_t r=0;r<n;r++)
00367                                 v_out[r] = mean + std*randomGenerator.drawGaussian1D_normalized();
00368                 }
00369 
00370                 /** Randomize the generators.
00371                  *   A seed can be providen, or a current-time based seed can be used (default)
00372                  */
00373                 inline void Randomize(const uint32_t seed)  {
00374                         randomGenerator.randomize(seed);
00375                 }
00376                 inline void Randomize()  {
00377                         randomGenerator.randomize();
00378                 }
00379 
00380                 /** Returns a random permutation of a vector: all the elements of the input vector are in the output but at random positions.
00381                   */
00382                 template <class T>
00383                 void  randomPermutation(
00384                         const std::vector<T> &in_vector,
00385                         std::vector<T>       &out_result)
00386                 {
00387                         randomGenerator.permuteVector(in_vector,out_result);
00388                 }
00389 
00390 
00391                 /** Generate multidimensional random samples according to a given covariance matrix.
00392                  * \exception std::exception On invalid covariance matrix
00393                  * \sa randomNormalMultiDimensionalMany
00394                  */
00395                 template <typename T>
00396                 void  randomNormalMultiDimensional(
00397                         const CMatrixTemplateNumeric<T> &cov,
00398                         std::vector<T>          &out_result)
00399                  {
00400                         randomGenerator.drawGaussianMultivariate(out_result,cov);
00401                  }
00402 
00403                  /** Generate a given number of multidimensional random samples according to a given covariance matrix.
00404                  * \param cov The covariance matrix where to draw the samples from.
00405                  * \param desiredSamples The number of samples to generate.
00406                  * \param samplesLikelihoods If desired, set to a valid pointer to a vector, where it will be stored the likelihoods of having obtained each sample: the product of the gaussian-pdf for each independent variable.
00407                  * \param ret The output list of samples
00408                  *
00409                  * \exception std::exception On invalid covariance matrix
00410                  *
00411                  * \sa randomNormalMultiDimensional
00412                  */
00413                  template <typename T>
00414                  void  randomNormalMultiDimensionalMany(
00415                         const CMatrixTemplateNumeric<T> &cov,
00416                         size_t                                                  desiredSamples,
00417                         std::vector< std::vector<T> >   &ret,
00418                         std::vector<T>                                  *samplesLikelihoods = NULL)
00419                 {
00420                         randomGenerator.drawGaussianMultivariateMany(ret,desiredSamples,cov,static_cast<const std::vector<T>*>(NULL),samplesLikelihoods);
00421                 }
00422 
00423                 /** Generate multidimensional random samples according to a given covariance matrix.
00424                  * \exception std::exception On invalid covariance matrix
00425                  * \sa randomNormalMultiDimensional
00426                  */
00427                  template <typename T,size_t N>
00428                  void  randomNormalMultiDimensionalMany(
00429                         const CMatrixFixedNumeric<T,N,N> &cov,
00430                         size_t                                                  desiredSamples,
00431                         std::vector< std::vector<T> >   &ret )
00432                  {
00433                          randomGenerator.drawGaussianMultivariateMany(ret,desiredSamples,cov);
00434                  }
00435 
00436                 /** Generate multidimensional random samples according to a given covariance matrix.
00437                  * \exception std::exception On invalid covariance matrix
00438                  * \sa randomNormalMultiDimensionalMany
00439                  */
00440                  template <typename T,size_t N>
00441                  void  randomNormalMultiDimensional(
00442                         const CMatrixFixedNumeric<T,N,N> &cov,
00443                         std::vector<T>          &out_result)
00444                 {
00445                         randomGenerator.drawGaussianMultivariate(out_result,cov);
00446                 }
00447 
00448 
00449         }// End of namespace
00450 
00451 } // End of namespace
00452 
00453 #endif



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011