indii/ml/filter/ParticleSmoother.hpp

00001 #ifndef INDII_ML_FILTER_PARTICLESMOOTHER_HPP
00002 #define INDII_ML_FILTER_PARTICLESMOOTHER_HPP
00003 
00004 #include "Smoother.hpp"
00005 #include "ParticleResampler.hpp"
00006 #include "ParticleSmootherModel.hpp"
00007 
00008 namespace indii {
00009   namespace ml {
00010     namespace filter {
00011 
00012 /**
00013  * Forward-backward particle smoother.
00014  *
00015  * @author Lawrence Murray <lawrence@indii.org>
00016  * @version $Rev: 560 $
00017  * @date $Date: 2008-09-08 23:40:30 +0100 (Mon, 08 Sep 2008) $
00018  *
00019  * ParticleSmoother is suitable for models with nonlinear transition
00020  * and measurement functions, approximating state and noise with
00021  * indii::ml::aux::DiracMixturePdf distributions. It is particularly
00022  * suitable in situations where an appropriate backwards transition
00023  * function cannot be defined, such as for transition functions
00024  * defined as convergent differential equations that become divergent
00025  * when reversed.
00026  * 
00027  * @see indii::ml::filter for general usage guidelines.
00028  *
00029  * @section ParticleSmoother_details Details
00030  *
00031  * The implementation here is of the second algorithm described in
00032  * @ref Isard1998 "Isard & Blake (1998)". This reweights particles
00033  * obtained during the forwards pass rather than performing a
00034  * backwards filtering pass to obtain new particles. While this means
00035  * a backwards transition function need not be defined for the model,
00036  * the drawback is that the approach is computationally and spatially
00037  * expensive -- \f$O(P^2)\f$ in the number of particles \f$P\f$ in
00038  * both cases.
00039  *
00040  * The forwards pass provides a weighted sample set
00041  * \f$\{(\mathbf{s}_t^{(i)},\pi_t^{(i)})\}\f$ at each time point \f$t =
00042  * t_1,\ldots,t_T\f$ for \f$i = 1,\ldots,P\f$. Initialising with \f$\psi_{t_T}
00043  * = \pi_{t_T}\f$, the backwards step to calculate weights at time \f$t_n\f$
00044  * is as follows:
00045  *
00046  * \f{eqnarray*}
00047  * \alpha_{t_n}^{(i,j)} &=& p(\mathbf{x}({t_{n+1}}) =
00048  * \mathbf{s}_{t_{n+1}}^{(i)}\,|\,\mathbf{x}({t_n}) =
00049  * \mathbf{s}_{t_n}^{(j)}) \\
00050  * \mathbf{\gamma}_{t_n} &=& \alpha_{t_n} \mathbf{\pi}_{t_n} \\
00051  * \mathbf{\delta}_{t_n} &=& \alpha_{t_n}^T(\mathbf{\psi}_{t_{n+1}}
00052  * \oslash \mathbf{\gamma}_{t_n})\\
00053  * \mathbf{\psi}_{t_n} &=& \mathbf{\pi}_{t_n} \otimes
00054  * \mathbf{\delta}_{t_n}
00055  * \f}
00056  *
00057  * where \f$\oslash\f$ is element-wise division and \f$\otimes\f$
00058  * element-wise multiplication.
00059  *
00060  * These are then normalised so that \f$\sum \psi_{t_n}^{(i)} = 1\f$
00061  * and the smoothed result
00062  * \f$\{(\mathbf{s}_{t_n}^{(i)},\psi_{t_n}^{(i)})\}\f$ for \f$i =
00063  * 1,\ldots,P\f$ is stored.
00064  *
00065  * This implementation performs calculations in the above matrix form
00066  * to take advantage of low-level optimisations in the matrix
00067  * library. It also uses a sparse matrix implementation of
00068  * \f$\alpha\f$ to alleviate spatial complexity somewhat.
00069  *
00070  * @section ParticleSmoother_references References
00071  *
00072  * @anchor Isard1998
00073  * Isard, M. & Blake, A. A smoothing %filter for
00074  * Condensation. <i>Proceedings of the 5th European Conference on
00075  * Computer Vision</i>, <b>1998</b>, 1, 767-781.
00076  */
00077 template <class T = unsigned int>
00078 class ParticleSmoother : public Smoother<T,indii::ml::aux::DiracMixturePdf> {
00079 public:
00080   /**
00081    * Create new particle smoother.
00082    * 
00083    * @param model Model to estimate.
00084    * @param tT \f$t_T\f$; starting time.
00085    * @param p_xT \f$p(\mathbf{x}_T)\f$; prior over the state at time
00086    * \f$t_T\f$.
00087    */
00088   ParticleSmoother(ParticleSmootherModel<T>* model,
00089       const T tT, const indii::ml::aux::DiracMixturePdf& p_xT);
00090 
00091   /**
00092    * Destructor.
00093    */
00094   virtual ~ParticleSmoother();
00095 
00096   /**
00097    * Get the model being estimated.
00098    *
00099    * @return The model being estimated.
00100    */
00101   virtual ParticleSmootherModel<T>* getModel();
00102 
00103   /**
00104    * Rewind system to time of previous measurement and
00105    * smooth.
00106    *
00107    * @param tn \f$t_n\f$; the time to which to rewind the
00108    * system. This must be less than the current time \f$t_{n+1}\f$.
00109    * @param p_xtn_ytn \f$p(\mathbf{x}_n\,|\,\mathbf{y}_{1:n})\f$; filter
00110    * density at time \f$t_n\f$.
00111    */
00112   virtual void smooth(const T tn,
00113       const indii::ml::aux::DiracMixturePdf& p_xtn_ytn);
00114 
00115   virtual indii::ml::aux::DiracMixturePdf smoothedMeasure();
00116 
00117   /**
00118    * Resample the smoothed state.
00119    *
00120    * @see ParticleFilter::resample()
00121    */
00122   void smoothedResample(ParticleResampler* resampler);
00123 
00124 private:
00125   /**
00126    * Model.
00127    */
00128   ParticleSmootherModel<T>* model;
00129 
00130 };
00131 
00132     }
00133   }
00134 }
00135 
00136 #include "StratifiedParticleResampler.hpp"
00137 
00138 #include <assert.h>
00139 #include <vector>
00140 
00141 #include "boost/numeric/ublas/operation.hpp"
00142 #include "boost/numeric/ublas/operation_sparse.hpp"
00143 
00144 template <class T>
00145 indii::ml::filter::ParticleSmoother<T>::ParticleSmoother(
00146     ParticleSmootherModel<T>* model, const T tT,
00147     const indii::ml::aux::DiracMixturePdf& p_xT) :
00148     Smoother<T,indii::ml::aux::DiracMixturePdf>(tT, p_xT), model(model) {
00149   //
00150 }
00151 
00152 template <class T>
00153 indii::ml::filter::ParticleSmoother<T>::~ParticleSmoother() {
00154   //
00155 }
00156 
00157 template <class T>
00158 indii::ml::filter::ParticleSmootherModel<T>*
00159     indii::ml::filter::ParticleSmoother<T>::getModel() {
00160   return model;
00161 }
00162 
00163 template <class T>
00164 void indii::ml::filter::ParticleSmoother<T>::smooth(const T tn,
00165     const indii::ml::aux::DiracMixturePdf& p_xtn_ytn) {
00166   namespace aux = indii::ml::aux;
00167   namespace ublas = boost::numeric::ublas;
00168 
00169   /* pre-condition */
00170   assert (tn < this->tn);
00171 
00172   const T tnp1 = this->tn;
00173   aux::DiracMixturePdf& p_xtnp1_ytT = this->p_xtn_ytT;
00174   
00175   const unsigned int N = p_xtn_ytn.getDimensions();
00176   const unsigned int P1 = p_xtn_ytn.getSize();
00177   const unsigned int P2 = p_xtnp1_ytT.getSize();
00178   const T del = tnp1 - tn;
00179   unsigned int i;
00180 
00181   boost::mpi::communicator world;
00182   const unsigned int rank = world.rank();
00183   const unsigned int size = world.size();
00184   unsigned int k;
00185 
00186   const aux::vector& pi = p_xtn_ytn.getWeights();
00187   aux::vector psi(p_xtnp1_ytT.getWeights());
00188   aux::vector gamma(P2);
00189   aux::vector delta(P1);
00190   std::vector<aux::sparse_matrix> alphas;
00191 
00192   /* calculate \f$\alpha\f$ */
00193   model->alphaPrecalculate(p_xtn_ytn, tn, del);
00194   for (k = 0; k < size; k++) {
00195     alphas.push_back(model->alpha(p_xtn_ytn, p_xtnp1_ytT, tn, del));
00196     indii::ml::aux::rotate(p_xtnp1_ytT);
00197   }
00198 
00199   /* calculate \f$\gamma\f$ */
00200   gamma.clear();
00201   for (k = 0; k < size; k++) {
00202     ublas::axpy_prod(alphas[k], pi, gamma, false);
00203     indii::ml::aux::rotate(gamma);
00204   }
00205 
00206   /* calculate \f$\delta\f$ */
00207   delta.clear();
00208   psi = element_div(psi, gamma);
00209   for (k = 0; k < size; k++) {
00210     ublas::axpy_prod(psi, alphas[k], delta, false);
00211     indii::ml::aux::rotate(psi);
00212   }
00213 
00214   /* calculate \f$\psi_{t_{n+1}}\f$ */
00215   psi.resize(P1, false);
00216   noalias(psi) = element_prod(pi, delta);
00217 
00218   /* build smoothed distribution */
00219   this->p_xtn_ytT = p_xtn_ytn;
00220   this->p_xtn_ytT.setWeights(psi);
00221 
00222   /* update state */
00223   this->tn = tn;
00224 }
00225 
00226 template <class T>
00227 indii::ml::aux::DiracMixturePdf
00228     indii::ml::filter::ParticleSmoother<T>::smoothedMeasure() {
00229   namespace aux = indii::ml::aux;
00230 
00231   unsigned int i;
00232   StratifiedParticleResampler resampler;
00233   aux::DiracMixturePdf resampled(resampler.resample(
00234       Smoother<T,aux::DiracMixturePdf>::getSmoothedState()));
00235   aux::DiracMixturePdf p_ytn_xtT(model->getMeasurementSize());
00236 
00237   for (i = 0; i < resampled.getSize(); i++) {
00238     p_ytn_xtT.add(model->measure(resampled.get(i)));
00239   }  
00240   
00241   return p_ytn_xtT;
00242 }
00243 
00244 template <class T>
00245 void indii::ml::filter::ParticleSmoother<T>::smoothedResample(
00246     ParticleResampler* resampler) {
00247   indii::ml::aux::DiracMixturePdf resampled(resampler->resample(
00248       Smoother<T,aux::DiracMixturePdf>::getSmoothedState()));
00249   Smoother<T,aux::DiracMixturePdf>::setSmoothedState(resampled);
00250 }
00251 
00252 #endif
00253 

Generated on Wed Dec 17 15:11:57 2008 for dysii Dynamical Systems Library by  doxygen 1.5.3