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



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