Main MRPT website > C++ reference
MRPT logo
ops_containers.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_container_ops_H
00029 #define  mrpt_math_container_ops_H
00030 
00031 #include <mrpt/math/math_frwds.h>  // Fordward declarations
00032 
00033 #include <mrpt/math/lightweight_geom_data.h>  // Fordward declarations
00034 
00035 #include <functional>
00036 #include <algorithm>
00037 #include <cmath>
00038 
00039 /** \addtogroup container_ops_grp Vector and matrices mathematical operations and other utilities
00040   *  \ingroup mrpt_base_grp
00041   *  @{ */
00042 
00043 /** \file ops_containers.h
00044   * This file implements several operations that operate element-wise on individual or pairs of containers.
00045   *  Containers here means any of: mrpt::math::CVectorTemplace, mrpt::math::CArray, mrpt::math::CMatrixFixedNumeric, mrpt::math::CMatrixTemplate.
00046   *
00047   *  In general, any container having a type "mrpt_autotype" self-referencing to the type itself, and a dummy struct mrpt_container<>
00048   *   which is only used as a way to force the compiler to assure that BOTH containers are valid ones in binary operators.
00049   *   This restrictions
00050   *   have been designed as a way to provide "polymorphism" at a template level, so the "+,-,..." operators do not
00051   *   generate ambiguities for ANY type, and limiting them to MRPT containers.
00052   *
00053   *   In some cases, the containers provide specializations of some operations, for increased performance.
00054   */
00055 
00056 #include <algorithm>
00057 #include <numeric>
00058 #include <functional>
00059 
00060 #include <mrpt/math/CHistogram.h>  // Used in ::histogram()
00061 
00062 
00063 namespace mrpt
00064 {
00065         namespace math
00066         {
00067                 /** Computes the normalized or normal histogram of a sequence of numbers given the number of bins and the limits.
00068                   *  In any case this is a "linear" histogram, i.e. for matrices, all the elements are taken as if they were a plain sequence, not taking into account they were in columns or rows.
00069                   *  If desired, out_bin_centers can be set to receive the bins centers.
00070                   */
00071                 template<class CONTAINER>
00072                 vector_double histogram(
00073                         const CONTAINER &v,
00074                         double limit_min,
00075                         double limit_max,
00076                         size_t number_bins,
00077                         bool do_normalization = false,
00078                         vector_double *out_bin_centers = NULL)
00079                 {
00080                         mrpt::math::CHistogram  H( limit_min, limit_max, number_bins );
00081                         vector_double ret(number_bins);
00082                         vector_double dummy_ret_bins;
00083                         H.add(v);
00084                         if (do_normalization)
00085                                         H.getHistogramNormalized( out_bin_centers ? *out_bin_centers : dummy_ret_bins, ret );
00086                         else    H.getHistogram( out_bin_centers ? *out_bin_centers : dummy_ret_bins, ret );
00087                         return ret;
00088                 }
00089 
00090                 /** Computes the cumulative sum of all the elements, saving the result in another container.
00091                   *  This works for both matrices (even mixing their types) and vectores/arrays (even mixing types),
00092                   *  and even to store the cumsum of any matrix into any vector/array, but not in opposite direction.
00093                   * \sa sum */
00094                 template <class CONTAINER1,class CONTAINER2>
00095                 inline void cumsum(const CONTAINER1 &in_data, CONTAINER2 &out_cumsum)
00096                 {
00097                         out_cumsum.resizeLike(in_data);
00098                         typename CONTAINER1::value_type last=0;
00099                         const size_t N = in_data.size();
00100                         for (size_t i=0;i<N;i++)
00101                                 last = out_cumsum[i] = last + in_data[i];
00102                 }
00103 
00104                 /** Computes the cumulative sum of all the elements
00105                   * \sa sum  */
00106                 template<class CONTAINER>
00107                 inline CONTAINER cumsum(const CONTAINER &in_data)
00108                 {
00109                         CONTAINER ret;
00110                         cumsum(in_data,ret);
00111                         return ret;
00112                 }
00113 
00114                 template <class CONTAINER> inline typename CONTAINER::value_type norm_inf(const CONTAINER &v) { return v.norm_inf(); }
00115                 template <class CONTAINER> inline typename CONTAINER::value_type norm(const CONTAINER &v) { return v.norm(); }
00116                 template <class CONTAINER> inline typename CONTAINER::value_type maximum(const CONTAINER &v) { return v.maximum(); }
00117                 template <class CONTAINER> inline typename CONTAINER::value_type minimum(const CONTAINER &v) { return v.minimum(); }
00118 
00119                 template <typename T> inline T maximum(const std::vector<T> &v)
00120                 {
00121                         ASSERT_(!v.empty())
00122                         T m = v[0];
00123                         for (size_t i=0;i<v.size();i++) mrpt::utils::keep_max(m,v[i]);
00124                         return m;
00125                 }
00126                 template <typename T> inline T minimum(const std::vector<T> &v)
00127                 {
00128                         ASSERT_(!v.empty())
00129                         T m = v[0];
00130                         for (size_t i=0;i<v.size();i++) mrpt::utils::keep_min(m,v[i]);
00131                         return m;
00132                 }
00133 
00134                 /** \name Container initializer from pose classes
00135                   * @{
00136                   */
00137 
00138                 /** Conversion of poses to MRPT containers (vector/matrix) */
00139                 template <class CONTAINER> CONTAINER & containerFromPoseOrPoint(CONTAINER &C, const TPoint2D &p) {
00140                         C.resize(2,1);
00141                         for (size_t i=0;i<2;i++)  C.coeffRef(i,0)=p[i];
00142                         return C;
00143                 }
00144                 template <class CONTAINER> CONTAINER & containerFromPoseOrPoint(CONTAINER &C, const TPoint3D &p) {
00145                         C.resize(3,1);
00146                         for (size_t i=0;i<3;i++)  C.coeffRef(i,0)=p[i];
00147                         return C;
00148                 }
00149                 template <class CONTAINER> CONTAINER & containerFromPoseOrPoint(CONTAINER &C, const TPose2D &p) {
00150                         C.resize(3,1);
00151                         for (size_t i=0;i<3;i++)  C.coeffRef(i,0)=p[i];
00152                         return C;
00153                 }
00154                 template <class CONTAINER> CONTAINER & containerFromPoseOrPoint(CONTAINER &C, const TPose3D &p) {
00155                         C.resize(6,1);
00156                         for (size_t i=0;i<6;i++)  C.coeffRef(i,0)=p[i];
00157                         return C;
00158                 }
00159                 template <class CONTAINER> CONTAINER & containerFromPoseOrPoint(CONTAINER &C, const TPose3DQuat &p) {
00160                         C.resize(7,1);
00161                         for (size_t i=0;i<7;i++)  C.coeffRef(i,0)=p[i];
00162                         return C;
00163                 }
00164 
00165                 /** @} */
00166 
00167 
00168 
00169                 /** \name Generic container element-wise operations - Miscelaneous
00170                   * @{
00171                   */
00172 
00173                 /** Accumulate the squared-norm of a vector/array/matrix into "total" (this function is compatible with std::accumulate). */
00174                 template <class CONTAINER>
00175                 typename CONTAINER::value_type squareNorm_accum(const typename CONTAINER::value_type total, const CONTAINER &v);
00176                 template <class CONTAINER> typename CONTAINER::value_type squareNorm_accum(const typename CONTAINER::value_type total, const CONTAINER &v) {
00177                         return total+v.squaredNorm();
00178                 }
00179 
00180                 /** Compute the square norm of anything implementing [].
00181                   \sa norm */
00182                 template<size_t N,class T,class U>
00183                 inline T squareNorm(const U &v) {
00184                         T res=0;
00185                         for (size_t i=0;i<N;i++) res+=square(v[i]);
00186                         return res;
00187                 }
00188 
00189                 /** v1·v2: The dot product of two containers (vectors/arrays/matrices) */
00190                 template <class CONTAINER1,class CONTAINER2>
00191                 inline typename CONTAINER1::value_type
00192                 dotProduct(const CONTAINER1 &v1,const CONTAINER1 &v2)
00193                 {
00194                         return v1.dot(v2);
00195                 }
00196 
00197                 /** v1·v2: The dot product of any two objects supporting []  */
00198                 template<size_t N,class T,class U,class V>
00199                 inline T dotProduct(const U &v1,const V &v2)    {
00200                         T res=0;
00201                         for (size_t i=0;i<N;i++) res+=v1[i]*v2[i];
00202                         return res;
00203                 }
00204 
00205                 /** Computes the sum of all the elements.
00206                   * \note If used with containers of integer types (uint8_t, int, etc...) this could overflow. In those cases, use sumRetType the second argument RET to specify a larger type to hold the sum.
00207                    \sa cumsum  */
00208                 template <class CONTAINER> inline typename CONTAINER::value_type sum(const CONTAINER &v) { return v.sum(); }
00209 
00210                 /// \overload
00211                 template <typename T> inline T sum(const std::vector<T> &v) { return std::accumulate(v.begin(),v.end(),T(0)); }
00212 
00213                 /** Computes the sum of all the elements, with a custom return type.
00214                    \sa sum, cumsum  */
00215                 template <class CONTAINER,typename RET> inline RET sumRetType(const CONTAINER &v) { return v.sumRetType<RET>(); }
00216 
00217                 /** Computes the mean value of a vector  \return The mean, as a double number.
00218                   * \sa math::stddev,math::meanAndStd  */
00219                 template <class CONTAINER>
00220                 inline double mean(const CONTAINER &v)
00221                 {
00222                         if (v.empty())
00223                              return 0;
00224                         else return sum(v)/static_cast<double>(v.size());
00225                 }
00226 
00227                 /** Return the maximum and minimum values of a std::vector */
00228                 template <typename T>
00229                 inline void minimum_maximum(const std::vector<T> &V, T&curMin,T&curMax)
00230                 {
00231                         ASSERT_(V.size()!=0)
00232                         const size_t N=V.size();
00233                         curMin=curMax=V[0];
00234                         for (size_t i=1;i<N;i++)
00235                         {
00236                                 mrpt::utils::keep_min(curMin,V[i]);
00237                                 mrpt::utils::keep_max(curMax,V[i]);
00238                         }
00239                 }
00240 
00241                 /** Return the maximum and minimum values of a Eigen-based vector or matrix */
00242                 template <class Derived>
00243                 inline void minimum_maximum(
00244                         const Eigen::MatrixBase<Derived> &V,
00245                         typename Eigen::MatrixBase<Derived>::value_type &curMin,
00246                         typename Eigen::MatrixBase<Derived>::value_type &curMax)
00247                 {
00248                         V.minimum_maximum(curMin,curMax);
00249                 }
00250 
00251                 /** Counts the number of elements that appear in both STL-like containers (comparison through the == operator)
00252                   *  It is assumed that no repeated elements appear within each of the containers.  */
00253                 template <class CONTAINER1,class CONTAINER2>
00254                 size_t  countCommonElements(const CONTAINER1 &a,const CONTAINER2 &b)
00255                 {
00256                     size_t ret=0;
00257                         for (typename CONTAINER1::const_iterator it1 = a.begin();it1!=a.end();it1++)
00258                             for (typename CONTAINER2::const_iterator it2 = b.begin();it2!=b.end();it2++)
00259                     if ( (*it1) == (*it2) )
00260                          ret++;
00261                         return ret;
00262                 }
00263 
00264                 /** Adjusts the range of all the elements such as the minimum and maximum values being those supplied by the user.  */
00265                 template <class CONTAINER>
00266                 void  adjustRange(CONTAINER &m, const typename CONTAINER::value_type minVal,const typename CONTAINER::value_type maxVal)
00267                 {
00268                         if (size_t(m.size())==0) return;
00269                         typename CONTAINER::value_type curMin,curMax;
00270                         minimum_maximum(m,curMin,curMax);
00271                         const typename CONTAINER::value_type curRan = curMax-curMin;
00272                         m -= (curMin+minVal);
00273                         if (curRan!=0) m *= (maxVal-minVal)/curRan;
00274                 }
00275 
00276 
00277                 /** Computes the standard deviation of a vector
00278                   * \param v The set of data
00279                   * \param out_mean The output for the estimated mean
00280                   * \param out_std The output for the estimated standard deviation
00281                   * \param unbiased If set to true or false the std is normalized by "N-1" or "N", respectively.
00282                   * \sa math::mean,math::stddev
00283                   */
00284                 template<class VECTORLIKE>
00285                 void  meanAndStd(
00286                         const VECTORLIKE &v,
00287                         double                  &out_mean,
00288                         double                  &out_std,
00289                         bool                    unbiased = true)
00290                 {
00291                         if (v.size()<2)
00292                         {
00293                                 out_std = 0;
00294                                 out_mean = (v.size()==1) ? *v.begin() : 0;
00295                         }
00296                         else
00297                         {
00298                                 // Compute the mean:
00299                                 const size_t N = v.size();
00300                                 out_mean = mrpt::math::sum(v) / static_cast<double>(N);
00301                                 // Compute the std:
00302                                 double  vector_std=0;
00303                                 for (size_t i=0;i<N;i++) vector_std += mrpt::utils::square( v[i]-out_mean);
00304                                 out_std = std::sqrt(vector_std  / static_cast<double>(N - (unbiased ? 1:0)) );
00305                         }
00306                 }
00307 
00308 
00309                 /** Computes the standard deviation of a vector
00310                   * \param v The set of data
00311                   * \param unbiased If set to true or false the std is normalized by "N-1" or "N", respectively.
00312                   * \sa math::mean,math::meanAndStd
00313                   */
00314                 template<class VECTORLIKE>
00315                 inline double  stddev(const VECTORLIKE &v, bool unbiased = true)
00316                 {
00317                         double m,s;
00318                         meanAndStd(v,m,s,unbiased);
00319                         return s;
00320                 }
00321 
00322                 /** Computes the mean vector and covariance from a list of values given as a vector of vectors, where each row is a sample.
00323                   * \param v The set of data, as a vector of N vectors of M elements.
00324                   * \param out_mean The output M-vector for the estimated mean.
00325                   * \param out_cov The output MxM matrix for the estimated covariance matrix.
00326                   * \sa mrpt::math::meanAndCovMat, math::mean,math::stddev, math::cov
00327                   */
00328                 template<class VECTOR_OF_VECTOR, class VECTORLIKE, class MATRIXLIKE>
00329                 void  meanAndCovVec(
00330                         const VECTOR_OF_VECTOR &v,
00331                         VECTORLIKE &out_mean,
00332                         MATRIXLIKE &out_cov
00333                         )
00334                 {
00335                         const size_t N = v.size();
00336                         ASSERTMSG_(N>0,"The input vector contains no elements");
00337                         const double N_inv = 1.0/N;
00338 
00339                         const size_t M = v[0].size();
00340                         ASSERTMSG_(M>0,"The input vector contains rows of length 0");
00341 
00342                         // First: Compute the mean
00343                         out_mean.assign(M,0);
00344                         for (size_t i=0;i<N;i++)
00345                                 for (size_t j=0;j<M;j++)
00346                                         out_mean[j]+=v[i][j];
00347                         out_mean*=N_inv;
00348 
00349                         // Second: Compute the covariance
00350                         //  Save only the above-diagonal part, then after averaging
00351                         //  duplicate that part to the other half.
00352                         out_cov.zeros(M,M);
00353                         for (size_t i=0;i<N;i++)
00354                         {
00355                                 for (size_t j=0;j<M;j++)
00356                                         out_cov.get_unsafe(j,j)+=square(v[i][j]-out_mean[j]);
00357 
00358                                 for (size_t j=0;j<M;j++)
00359                                         for (size_t k=j+1;k<M;k++)
00360                                                 out_cov.get_unsafe(j,k)+=(v[i][j]-out_mean[j])*(v[i][k]-out_mean[k]);
00361                         }
00362                         for (size_t j=0;j<M;j++)
00363                                 for (size_t k=j+1;k<M;k++)
00364                                         out_cov.get_unsafe(k,j) = out_cov.get_unsafe(j,k);
00365                         out_cov*=N_inv;
00366                 }
00367 
00368                 /** Computes the covariance matrix from a list of values given as a vector of vectors, where each row is a sample.
00369                   * \param v The set of data, as a vector of N vectors of M elements.
00370                   * \param out_cov The output MxM matrix for the estimated covariance matrix.
00371                   * \sa math::mean,math::stddev, math::cov, meanAndCovVec
00372                   */
00373                 template<class VECTOR_OF_VECTOR>
00374                 inline Eigen::MatrixXd covVector( const VECTOR_OF_VECTOR &v )
00375                 {
00376                         vector_double   m;
00377                         Eigen::MatrixXd C;
00378                         meanAndCovVec(v,m,C);
00379                         return C;
00380                 }
00381 
00382 
00383                 /** Normalised Cross Correlation between two vector patches
00384                   * The Matlab code for this is
00385                   * a = a - mean2(a);
00386                   * b = b - mean2(b);
00387                   * r = sum(sum(a.*b))/sqrt(sum(sum(a.*a))*sum(sum(b.*b)));
00388                   */
00389                 template <class CONT1,class CONT2>
00390                 double ncc_vector( const CONT1 &patch1, const CONT2 &patch2 )
00391                 {
00392                         ASSERT_( patch1.size()==patch2.size() )
00393 
00394                         double numerator = 0, sum_a = 0, sum_b = 0, result, a_mean, b_mean;
00395                         a_mean = patch1.mean();
00396                         b_mean = patch2.mean();
00397 
00398                         const size_t N = patch1.size();
00399                         for(size_t i=0;i<N;++i)
00400                         {
00401                                 numerator += (patch1[i]-a_mean)*(patch2[i]-b_mean);
00402                                 sum_a += mrpt::utils::square(patch1[i]-a_mean);
00403                                 sum_b += mrpt::utils::square(patch2[i]-b_mean);
00404                         }
00405                         ASSERTMSG_(sum_a*sum_b!=0,"Divide by zero when normalizing.")
00406                         result=numerator/std::sqrt(sum_a*sum_b);
00407                         return result;
00408                 }
00409 
00410                 /** @} Misc ops */
00411 
00412         } // End of math namespace
00413 } // End of mrpt namespace
00414 
00415 /**  @} */  // end of grouping
00416 
00417 #endif



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