Main MRPT website > C++ reference
MRPT logo
distributions.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  mrpt_math_distributions_H
00029 #define  mrpt_math_distributions_H
00030 
00031 #include <mrpt/utils/utils_defs.h>
00032 #include <mrpt/math/math_frwds.h>
00033 #include <mrpt/math/CMatrixTemplateNumeric.h>
00034 
00035 #include <mrpt/math/ops_matrices.h>
00036 
00037 /*---------------------------------------------------------------
00038                 Namespace
00039   ---------------------------------------------------------------*/
00040 namespace mrpt
00041 {
00042         namespace math
00043         {
00044                 using namespace mrpt::utils;
00045 
00046                 /** \addtogroup stats_grp Statistics functions, probability distributions
00047                   *  \ingroup mrpt_base_grp
00048                   * @{ */
00049 
00050                 /** Evaluates the univariate normal (Gaussian) distribution at a given point "x".
00051                   */
00052                 double BASE_IMPEXP  normalPDF(double x, double mu, double std);
00053 
00054                 /** Evaluates the multivariate normal (Gaussian) distribution at a given point "x".
00055                   *  \param  x   A vector or column or row matrix with the point at which to evaluate the pdf.
00056                   *  \param  mu  A vector or column or row matrix with the Gaussian mean.
00057                   *  \param  cov_inv  The inverse covariance (information) matrix of the Gaussian.
00058                   *  \param  scaled_pdf If set to true, the PDF will be scaled to be in the range [0,1], in contrast to its integral from [-inf,+inf] being 1.
00059                   */
00060                 template <class VECTORLIKE1,class VECTORLIKE2,class MATRIXLIKE>
00061                 inline typename MATRIXLIKE::value_type
00062                         normalPDFInf(
00063                                 const VECTORLIKE1  & x,
00064                                 const VECTORLIKE2  & mu,
00065                                 const MATRIXLIKE   & cov_inv,
00066                                 const bool scaled_pdf = false )
00067                 {
00068                         MRPT_START
00069                         typedef typename MATRIXLIKE::value_type T;
00070                         ASSERTDEB_(cov_inv.isSquare())
00071                         ASSERTDEB_(size_t(cov_inv.getColCount())==size_t(x.size()) && size_t(cov_inv.getColCount())==size_t(mu.size()))
00072                         T ret = ::exp( static_cast<T>(-0.5) * mrpt::math::multiply_HCHt_scalar((x-mu), cov_inv ) );
00073                         return scaled_pdf ? ret : ret * ::sqrt(cov_inv.det()) / ::pow(static_cast<T>(M_2PI),static_cast<T>( size(cov_inv,1) ));
00074                         MRPT_END
00075                 }
00076 
00077                 /** Evaluates the multivariate normal (Gaussian) distribution at a given point "x".
00078                   *  \param  x   A vector or column or row matrix with the point at which to evaluate the pdf.
00079                   *  \param  mu  A vector or column or row matrix with the Gaussian mean.
00080                   *  \param  cov  The covariance matrix of the Gaussian.
00081                   *  \param  scaled_pdf If set to true, the PDF will be scaled to be in the range [0,1], in contrast to its integral from [-inf,+inf] being 1.
00082                   */
00083                 template <class VECTORLIKE1,class VECTORLIKE2,class MATRIXLIKE>
00084                 inline typename MATRIXLIKE::value_type
00085                         normalPDF(
00086                                 const VECTORLIKE1  & x,
00087                                 const VECTORLIKE2  & mu,
00088                                 const MATRIXLIKE   & cov,
00089                                 const bool scaled_pdf = false )
00090                 {
00091                         return normalPDFInf(x,mu,cov.inverse(),scaled_pdf);
00092                 }
00093 
00094                 /** Evaluates the multivariate normal (Gaussian) distribution at a given point given its distance vector "d" from the Gaussian mean.
00095                   */
00096                 template <typename VECTORLIKE,typename MATRIXLIKE>
00097                 typename MATRIXLIKE::value_type
00098                 normalPDF(const VECTORLIKE &d,const MATRIXLIKE &cov)
00099                 {
00100                         MRPT_START
00101                         ASSERTDEB_(cov.isSquare())
00102                         ASSERTDEB_(size_t(cov.getColCount())==size_t(d.size()))
00103                         return std::exp( static_cast<typename MATRIXLIKE::value_type>(-0.5)*mrpt::math::multiply_HCHt_scalar(d,cov.inverse()))
00104                         / (::pow(
00105                                         static_cast<typename MATRIXLIKE::value_type>(M_2PI),
00106                                         static_cast<typename MATRIXLIKE::value_type>(cov.getColCount()))
00107                                 * ::sqrt(cov.det()));
00108                         MRPT_END
00109                 }
00110 
00111                 /** Kullback-Leibler divergence (KLD) between two independent multivariate Gaussians.
00112                   *
00113                   * \f$ D_\mathrm{KL}(\mathcal{N}_0 \| \mathcal{N}_1) = { 1 \over 2 } ( \log_e ( { \det \Sigma_1 \over \det \Sigma_0 } ) + \mathrm{tr} ( \Sigma_1^{-1} \Sigma_0 ) + ( \mu_1 - \mu_0 )^\top \Sigma_1^{-1} ( \mu_1 - \mu_0 ) - N ) \f$
00114                   */
00115                 template <typename VECTORLIKE1,typename MATRIXLIKE1,typename VECTORLIKE2,typename MATRIXLIKE2>
00116                 double KLD_Gaussians(
00117                         const VECTORLIKE1 &mu0, const MATRIXLIKE1 &cov0,
00118                         const VECTORLIKE2 &mu1, const MATRIXLIKE2 &cov1)
00119                 {
00120                         MRPT_START
00121                         ASSERT_(size_t(mu0.size())==size_t(mu1.size()) && size_t(mu0.size())==size_t(size(cov0,1)) && size_t(mu0.size())==size_t(size(cov1,1)) && cov0.isSquare() && cov1.isSquare() )
00122                         const size_t N = mu0.size();
00123                         MATRIXLIKE2 cov1_inv;
00124                         cov1.inv(cov1_inv);
00125                         const VECTORLIKE1 mu_difs = mu0-mu1;
00126                         return 0.5*( log(cov1.det()/cov0.det()) + (cov1_inv*cov0).trace() + multiply_HCHt_scalar(mu_difs,cov1_inv) - N );
00127                         MRPT_END
00128                 }
00129 
00130 
00131                 /** The complementary error function of a Normal distribution
00132                   */
00133 #ifdef HAVE_ERF
00134                 inline double erfc(double x) { return ::erfc(x); }
00135 #else
00136                 double BASE_IMPEXP  erfc(double x);
00137 #endif
00138 
00139                 /** The error function of a Normal distribution
00140                   */
00141 #ifdef HAVE_ERF
00142                 inline double erf(double x) { return ::erf(x); }
00143 #else
00144                 double BASE_IMPEXP   erf(double x);
00145 #endif
00146                 /** Evaluates the Gaussian distribution quantile for the probability value p=[0,1].
00147                   *  The employed approximation is that from Peter J. Acklam (pjacklam@online.no),
00148                   *  freely available in http://home.online.no/~pjacklam.
00149                   */
00150                 double BASE_IMPEXP  normalQuantile(double p);
00151 
00152                 /** Evaluates the Gaussian cumulative density function.
00153                   *  The employed approximation is that from W. J. Cody
00154                   *  freely available in http://www.netlib.org/specfun/erf
00155                   */
00156                 double  BASE_IMPEXP normalCDF(double p);
00157 
00158                 /** The "quantile" of the Chi-Square distribution, for dimension "dim" and probability 0<P<1 (the inverse of chi2CDF)
00159                   * An aproximation from the Wilson-Hilferty transformation is used.
00160                   */
00161                 double  BASE_IMPEXP chi2inv(double P, unsigned int dim=1);
00162 
00163                 /*! Cumulative non-central chi square distribution (approximate).
00164 
00165                         Computes approximate values of the cumulative density of a chi square distribution with \a degreesOfFreedom,
00166                         and noncentrality parameter \a noncentrality at the given argument
00167                         \a arg, i.e. the probability that a random number drawn from the distribution is below \a arg
00168                         It uses the approximate transform into a normal distribution due to Wilson and Hilferty
00169                         (see Abramovitz, Stegun: "Handbook of Mathematical Functions", formula 26.3.32).
00170                         The algorithm's running time is independent of the inputs. The accuracy is only
00171                         about 0.1 for few degrees of freedom, but reaches about 0.001 above dof = 5.
00172 
00173                         \note Function code from the Vigra project (http://hci.iwr.uni-heidelberg.de/vigra/); code under "MIT X11 License", GNU GPL-compatible.
00174                 */
00175                 template <class T>
00176                 double noncentralChi2CDF(unsigned int degreesOfFreedom, T noncentrality, T arg)
00177                 {
00178                         const double a = degreesOfFreedom + noncentrality;
00179                         const double b = (a + noncentrality) / square(a);
00180                         const double t = (std::pow((double)arg / a, 1.0/3.0) - (1.0 - 2.0 / 9.0 * b)) / std::sqrt(2.0 / 9.0 * b);
00181                         return 0.5*(1.0 + mrpt::math::erf(t/std::sqrt(2.0)));
00182                 }
00183 
00184                 /*! Cumulative chi square distribution.
00185 
00186                         Computes the cumulative density of a chi square distribution with \a degreesOfFreedom
00187                         and tolerance \a accuracy at the given argument \a arg, i.e. the probability that
00188                         a random number drawn from the distribution is below \a arg
00189                         by calling <tt>noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy)</tt>.
00190 
00191                         \note Function code from the Vigra project (http://hci.iwr.uni-heidelberg.de/vigra/); code under "MIT X11 License", GNU GPL-compatible.
00192                 */
00193                 inline double chi2CDF(unsigned int degreesOfFreedom, double arg)
00194                 {
00195                         return noncentralChi2CDF(degreesOfFreedom, 0.0, arg);
00196                 }
00197 
00198                 namespace detail
00199                 {
00200                         template <class T>
00201                         void noncentralChi2OneIteration(T arg, T & lans, T & dans, T & pans, unsigned int & j)
00202                         {
00203                                 double tol = -50.0;
00204                                 if(lans < tol)
00205                                 {
00206                                         lans = lans + std::log(arg / j);
00207                                         dans = std::exp(lans);
00208                                 }
00209                                 else
00210                                 {
00211                                         dans = dans * arg / j;
00212                                 }
00213                                 pans = pans - dans;
00214                                 j += 2;
00215                         }
00216 
00217                         template <class T>
00218                         std::pair<double, double> noncentralChi2CDF_exact(unsigned int degreesOfFreedom, T noncentrality, T arg, T eps)
00219                         {
00220                                 ASSERTMSG_(noncentrality >= 0.0 && arg >= 0.0 && eps > 0.0,"noncentralChi2P(): parameters must be positive.");
00221                                 if (arg == 0.0 && degreesOfFreedom > 0)
00222                                         return std::make_pair(0.0, 0.0);
00223 
00224                                 // Determine initial values
00225                                 double b1 = 0.5 * noncentrality,
00226                                            ao = std::exp(-b1),
00227                                            eps2 = eps / ao,
00228                                            lnrtpi2 = 0.22579135264473,
00229                                            probability, density, lans, dans, pans, sum, am, hold;
00230                                 unsigned int maxit = 500,
00231                                         i, m;
00232                                 if(degreesOfFreedom % 2)
00233                                 {
00234                                         i = 1;
00235                                         lans = -0.5 * (arg + std::log(arg)) - lnrtpi2;
00236                                         dans = std::exp(lans);
00237                                         pans = erf(std::sqrt(arg/2.0));
00238                                 }
00239                                 else
00240                                 {
00241                                         i = 2;
00242                                         lans = -0.5 * arg;
00243                                         dans = std::exp(lans);
00244                                         pans = 1.0 - dans;
00245                                 }
00246 
00247                                 // Evaluate first term
00248                                 if(degreesOfFreedom == 0)
00249                                 {
00250                                         m = 1;
00251                                         degreesOfFreedom = 2;
00252                                         am = b1;
00253                                         sum = 1.0 / ao - 1.0 - am;
00254                                         density = am * dans;
00255                                         probability = 1.0 + am * pans;
00256                                 }
00257                                 else
00258                                 {
00259                                         m = 0;
00260                                         degreesOfFreedom = degreesOfFreedom - 1;
00261                                         am = 1.0;
00262                                         sum = 1.0 / ao - 1.0;
00263                                         while(i < degreesOfFreedom)
00264                                                 detail::noncentralChi2OneIteration(arg, lans, dans, pans, i);
00265                                         degreesOfFreedom = degreesOfFreedom + 1;
00266                                         density = dans;
00267                                         probability = pans;
00268                                 }
00269                                 // Evaluate successive terms of the expansion
00270                                 for(++m; m<maxit; ++m)
00271                                 {
00272                                         am = b1 * am / m;
00273                                         detail::noncentralChi2OneIteration(arg, lans, dans, pans, degreesOfFreedom);
00274                                         sum = sum - am;
00275                                         density = density + am * dans;
00276                                         hold = am * pans;
00277                                         probability = probability + hold;
00278                                         if((pans * sum < eps2) && (hold < eps2))
00279                                                 break; // converged
00280                                 }
00281                                 if(m == maxit)
00282                                         THROW_EXCEPTION("noncentralChi2P(): no convergence.");
00283                                 return std::make_pair(0.5 * ao * density, std::min(1.0, std::max(0.0, ao * probability)));
00284                         }
00285                 } // namespace detail
00286 
00287                 /*! Chi square distribution.
00288 
00289                         Computes the density of a chi square distribution with \a degreesOfFreedom
00290                         and tolerance \a accuracy at the given argument \a arg
00291                         by calling <tt>noncentralChi2(degreesOfFreedom, 0.0, arg, accuracy)</tt>.
00292 
00293                         \note Function code from the Vigra project (http://hci.iwr.uni-heidelberg.de/vigra/); code under "MIT X11 License", GNU GPL-compatible.
00294                 */
00295                 inline double chi2PDF(unsigned int degreesOfFreedom, double arg, double accuracy = 1e-7)
00296                 {
00297                         return detail::noncentralChi2CDF_exact(degreesOfFreedom, 0.0, arg, accuracy).first;
00298                 }
00299 
00300                 /** Return the mean and the 10%-90% confidence points (or with any other confidence value) of a set of samples by building the cummulative CDF of all the elements of the container.
00301                   *  The container can be any MRPT container (CArray, matrices, vectors).
00302                   * \param confidenceInterval A number in the range (0,1) such as the confidence interval will be [100*confidenceInterval, 100*(1-confidenceInterval)].
00303                   */
00304                 template <typename CONTAINER>
00305                 void confidenceIntervals(
00306                         const CONTAINER &data,
00307                         typename CONTAINER::value_type &out_mean,
00308                         typename CONTAINER::value_type &out_lower_conf_interval,
00309                         typename CONTAINER::value_type &out_upper_conf_interval,
00310                         const double confidenceInterval = 0.1,
00311                         const size_t histogramNumBins = 1000 )
00312                 {
00313                         MRPT_START
00314                         ASSERT_(data.size()!=0)  // don't use .empty() here to allow using matrices
00315                         ASSERT_(confidenceInterval>0 && confidenceInterval<1)
00316 
00317                         out_mean = mean(data);
00318                         typename CONTAINER::value_type x_min,x_max;
00319                         minimum_maximum(data,x_min,x_max);
00320 
00321                         //std::vector<typename CONTAINER::value_type> xs;
00322                         //linspace(x_min,x_max,histogramNumBins, xs);
00323                         const typename CONTAINER::value_type binWidth = (x_max-x_min)/histogramNumBins;
00324 
00325                         const vector_double H = mrpt::math::histogram(data,x_min,x_max,histogramNumBins);
00326                         vector_double Hc;
00327                         cumsum(H,Hc); // CDF
00328                         Hc*=1.0/Hc.maximum();
00329 
00330                         vector_double::iterator it_low  = std::lower_bound(Hc.begin(),Hc.end(),confidenceInterval);   ASSERT_(it_low!=Hc.end())
00331                         vector_double::iterator it_high = std::upper_bound(Hc.begin(),Hc.end(),1-confidenceInterval); ASSERT_(it_high!=Hc.end())
00332                         const size_t idx_low = std::distance(Hc.begin(),it_low);
00333                         const size_t idx_high = std::distance(Hc.begin(),it_high);
00334                         out_lower_conf_interval = x_min + idx_low * binWidth;
00335                         out_upper_conf_interval = x_min + idx_high * binWidth;
00336 
00337                         MRPT_END
00338                 }
00339 
00340                 /** @} */
00341 
00342         } // End of MATH namespace
00343 
00344 } // End of namespace
00345 
00346 
00347 #endif



Page generated by Doxygen 1.7.4 for MRPT 0.9.5 SVN:2717 at Sun Oct 16 16:08:03 PDT 2011 Hosted on:
SourceForge.net Logo