Main MRPT website > C++ reference
MRPT logo
CParticleFilterData.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 CParticleFilterData_H
00029 #define CParticleFilterData_H
00030 
00031 #include <mrpt/utils/utils_defs.h>
00032 #include <mrpt/bayes/CProbabilityParticle.h>
00033 
00034 #include <algorithm>
00035 
00036 namespace mrpt
00037 {
00038 namespace bayes
00039 {
00040         /** This template class declares the array of particles and its internal data, managing some memory-related issues and providing an easy implementation of virtual methods required for implementing a CParticleFilterCapable.
00041          *  By adding IMPLEMENT_PARTICLE_FILTER_CAPABLE(T) to the body of the declaration of classes inheriting from both CParticleFilterData and CParticleFilterCapable, the following
00042          *    pure virtual methods are automatically implemented (the param T must be equal to the argument of the template CParticleFilterData).
00043           *   - CParticleFilterCapable::getW
00044           *   - CParticleFilterCapable::setW
00045           *   - CParticleFilterCapable::particlesCount
00046           *   - CParticleFilterCapable::normalizeWeights
00047           *   - CParticleFilterCapable::ESS
00048           *   - CParticleFilterCapable::performSubstitution
00049          *
00050          *   Since CProbabilityParticle implements all the required operators, the member "m_particles" can be safely copied with "=" or copy constructor operators
00051          *    and new objects will be created internally instead of copying the internal pointers, which would lead to memory corruption.
00052          *
00053          * \sa CParticleFilter, CParticleFilterCapable, IMPLEMENT_PARTICLE_FILTER_CAPABLE
00054          * \ingroup mrpt_base_grp
00055          */
00056         template <class T>
00057         class CParticleFilterData
00058         {
00059         public:
00060                 typedef T                                                       CParticleDataContent;   //!< This is the type inside the corresponding CParticleData class
00061                 typedef CProbabilityParticle<T>         CParticleData;                  //!< Use this to refer to each element in the m_particles array.
00062                 typedef std::deque<CParticleData>       CParticleList;                  //!< Use this type to refer to the list of particles m_particles.
00063 
00064                 CParticleList  m_particles;     //!< The array of particles
00065 
00066                 /** Default constructor */
00067                 CParticleFilterData() : m_particles(0)
00068                 { }
00069 
00070         /** Free the memory of all the particles and reset the array "m_particles" to length zero.
00071           */
00072         void clearParticles()
00073                 {
00074                         MRPT_START
00075                         for (typename CParticleList::iterator it=m_particles.begin();it!=m_particles.end();it++)
00076                                 if (it->d) delete it->d;
00077                         m_particles.clear();
00078                         MRPT_END
00079                 }
00080 
00081         /** Virtual destructor
00082           */
00083         virtual ~CParticleFilterData()
00084                 {
00085                         MRPT_START
00086                         clearParticles();
00087                         MRPT_END
00088                 }
00089 
00090                 /** Dumps the sequence of particles and their weights to a stream (requires T implementing CSerializable).
00091                   * \sa readParticlesFromStream
00092                   */
00093                 void  writeParticlesToStream( utils::CStream &out ) const
00094                 {
00095                         MRPT_START
00096                         uint32_t        n = static_cast<uint32_t>(m_particles.size());
00097                         out << n;
00098                         typename CParticleList::const_iterator it;
00099                         for (it=m_particles.begin();it!=m_particles.end();it++)
00100                                 out << it->log_w << (*it->d);
00101                         MRPT_END
00102                 }
00103 
00104                 /** Reads the sequence of particles and their weights from a stream (requires T implementing CSerializable).
00105                   * \sa writeParticlesToStream
00106                   */
00107                 void  readParticlesFromStream(utils::CStream &in)
00108                 {
00109                         MRPT_START
00110                         clearParticles();       // Erase previous content:
00111                         uint32_t        n;
00112                         in >> n;
00113                         m_particles.resize(n);
00114                         typename CParticleList::iterator it;
00115                         for (it=m_particles.begin();it!=m_particles.end();it++)
00116                         {
00117                                 in >> it->log_w;
00118                                 it->d = new T();
00119                                 in >> *it->d;
00120                         }
00121                         MRPT_END
00122                 }
00123 
00124 
00125                 /** Returns a vector with the sequence of the logaritmic weights of all the samples.
00126                   */
00127                 void getWeights( vector_double &out_logWeights ) const
00128                 {
00129                         MRPT_START
00130                         out_logWeights.resize(m_particles.size());
00131                         vector_double::iterator                                         it;
00132                         typename CParticleList::const_iterator  it2;
00133                         for (it=out_logWeights.begin(),it2=m_particles.begin();it2!=m_particles.end();it++,it2++)
00134                                 *it = it2->log_w;
00135                         MRPT_END
00136                 }
00137 
00138                 /** Returns the particle with the highest weight.
00139                   */
00140                 const CParticleData * getMostLikelyParticle() const
00141                 {
00142                         MRPT_START
00143                         const CParticleData *ret = NULL;
00144                         ASSERT_(m_particles.size()>0)
00145 
00146                         typename CParticleList::const_iterator  it;
00147                         for (it=m_particles.begin();it!=m_particles.end();it++)
00148                         {
00149                                 if (ret==NULL || it->log_w > ret->log_w)
00150                                         ret = &(*it);
00151                         }
00152                         return ret;
00153                         MRPT_END
00154                 }
00155 
00156 
00157         }; // End of class def.
00158 
00159         /** This must be placed within the declaration of classes inheriting from both CParticleFilterData and CParticleFilterCapable to implement some pure virtual methods (the param T must be equal to the argument of the template CParticleFilterData).
00160           *  The following pure virtual methods are implemented:
00161           *   - CParticleFilterCapable::getW
00162           *   - CParticleFilterCapable::setW
00163           *   - CParticleFilterCapable::particlesCount
00164           *   - CParticleFilterCapable::normalizeWeights
00165           *   - CParticleFilterCapable::ESS
00166           *   - CParticleFilterCapable::performSubstitution
00167           */
00168 #define IMPLEMENT_PARTICLE_FILTER_CAPABLE(T) \
00169                 public: \
00170                 virtual double  getW(size_t i) const \
00171                 { \
00172                         MRPT_START \
00173                         if (i>=m_particles.size()) THROW_EXCEPTION_CUSTOM_MSG1("Index %i is out of range!",(int)i); \
00174                         return m_particles[i].log_w; \
00175                         MRPT_END \
00176                 } \
00177                 virtual void setW(size_t i, double w) \
00178                 { \
00179                         MRPT_START \
00180                         if (i>=m_particles.size()) THROW_EXCEPTION_CUSTOM_MSG1("Index %i is out of range!",(int)i); \
00181                         m_particles[i].log_w = w; \
00182                         MRPT_END \
00183                 } \
00184                 virtual size_t particlesCount() const { return m_particles.size(); } \
00185                 virtual double normalizeWeights( double *out_max_log_w = NULL ) \
00186                 { \
00187                         MRPT_START \
00188                         CParticleList::iterator it;\
00189                         \
00190                         if (!m_particles.size()) return 0; \
00191                         double  minW,maxW; \
00192                         minW = maxW = m_particles[0].log_w; \
00193                         /* Compute the max/min of weights: */ \
00194                         for (it=m_particles.begin();it!=m_particles.end();it++) \
00195                         { \
00196                                 maxW = std::max<double>( maxW, it->log_w ); \
00197                                 minW = std::min<double>( minW, it->log_w ); \
00198                         } \
00199                         /* Normalize: */ \
00200                         for (it=m_particles.begin();it!=m_particles.end();it++) \
00201                                 it->log_w -= maxW; \
00202                         if (out_max_log_w) \
00203                                 *out_max_log_w = maxW; \
00204                         /* Return the max/min ratio: */ \
00205                         return exp(maxW-minW); \
00206                         MRPT_END \
00207                 } \
00208                 virtual double ESS() \
00209                 { \
00210                         MRPT_START \
00211                         CParticleList::iterator it; \
00212                         double  cum = 0; \
00213                         \
00214                         /* Sum of weights: */ \
00215                         double sumLinearWeights = 0; \
00216                         for (it=m_particles.begin();it!=m_particles.end();it++) \
00217                                 sumLinearWeights += exp( it->log_w  ); \
00218                         /* Compute ESS: */ \
00219                         for (it=m_particles.begin();it!=m_particles.end();it++) \
00220                                 cum+= utils::square( exp( it->log_w ) / sumLinearWeights ); \
00221                         \
00222                         if (cum==0) \
00223                                         return 0; \
00224                         else    return 1.0/(m_particles.size()*cum); \
00225                         MRPT_END \
00226                 } \
00227                 /** Replaces the old particles by copies determined by the indexes in "indx", performing an efficient copy of the necesary particles only and allowing the number of particles to change.*/ \
00228                 virtual void  performSubstitution( const std::vector<size_t> &indx) \
00229                 {  \
00230                         MRPT_START \
00231                         CParticleList                       parts; \
00232                         CParticleList::iterator                 itDest,itSrc; \
00233                         size_t                                                                  M_old = m_particles.size(); \
00234                         size_t                                                                  i,j,lastIndxOld = 0; \
00235                         std::vector<bool>                                               oldParticlesReused(M_old,false); \
00236                         std::vector<bool>::const_iterator               oldPartIt; \
00237                         std::vector<size_t>                                             sorted_indx(indx); \
00238                         std::vector<size_t>::iterator                   sort_idx_it; \
00239                         /* Assure the input index is sorted: */ \
00240                         std::sort( sorted_indx.begin(), sorted_indx.end() ); \
00241                         /* Set the new size: */ \
00242                         parts.resize( sorted_indx.size() ); \
00243                         for (i=0,itDest=parts.begin();itDest!=parts.end();i++,itDest++) \
00244                         { \
00245                                 const size_t    sorted_idx = sorted_indx[i]; \
00246                                 itDest->log_w = m_particles[ sorted_idx ].log_w; \
00247                                 /* We can safely delete old m_particles from [lastIndxOld,indx[i]-1] (inclusive): */  \
00248                                 for (j=lastIndxOld;j<sorted_idx;j++) \
00249                                 { \
00250                                         if (!oldParticlesReused[j])     /* If reused we can not delete that memory! */ \
00251                                         { \
00252                                                 delete m_particles[j].d; \
00253                                                 m_particles[j].d = NULL; \
00254                                         } \
00255                                 } \
00256                                 /* For the next iteration:*/ \
00257                                 lastIndxOld = sorted_idx; \
00258                                 /* If this is the first time that the old particle "indx[i]" appears, */ \
00259                                 /*  we can reuse the old "data" instead of creating a new copy: */ \
00260                                 if (!oldParticlesReused[sorted_idx]) \
00261                                 { \
00262                                         /* Reuse the data from the particle: */ \
00263                                         parts[i].d = m_particles[ sorted_idx ].d; \
00264                                         oldParticlesReused[sorted_idx]=true; \
00265                                 } \
00266                                 else \
00267                                 { \
00268                                         /* Make a copy of the particle's data: */ \
00269                                         ASSERT_( m_particles[ sorted_idx ].d != NULL); \
00270                                         parts[i].d = new T( *m_particles[ sorted_idx ].d ); \
00271                                 } \
00272                         } \
00273                         /* Free memory of unused particles */ \
00274                         for (itSrc=m_particles.begin(),oldPartIt=oldParticlesReused.begin();itSrc!=m_particles.end();itSrc++,oldPartIt++) \
00275                                 if (! *oldPartIt ) \
00276                                 { \
00277                                         delete itSrc->d; \
00278                                         itSrc->d = NULL; \
00279                                 } \
00280                         /* Copy the pointers only to the final destination */ \
00281                         m_particles.resize( parts.size() ); \
00282                         for (itSrc=parts.begin(),itDest=m_particles.begin(); itSrc!=parts.end(); itSrc++, itDest++ ) \
00283                         { \
00284                                 itDest->log_w = itSrc->log_w; \
00285                                 itDest->d = itSrc->d; \
00286                                 itSrc->d = NULL; \
00287                         } \
00288                         parts.clear(); \
00289                         MRPT_END \
00290                 } \
00291 
00292         } // end namespace
00293 } // end namespace
00294 #endif



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