indii/ml/filter/AuxiliaryParticleResampler.hpp

00001 #ifndef INDII_ML_FILTER_AUXILIARYPARTICLERESAMPLER_HPP
00002 #define INDII_ML_FILTER_AUXILIARYPARTICLERESAMPLER_HPP
00003 
00004 #include "ParticleResampler.hpp"
00005 #include "ParticleFilter.hpp"
00006 
00007 namespace indii {
00008   namespace ml {
00009     namespace filter {
00010 /**
00011  * Auxiliary particle resampler.
00012  *
00013  * @author Lawrence Murray <lawrence@indii.org>
00014  * @version $Rev: 544 $
00015  * @date $Date: 2008-09-01 15:04:39 +0100 (Mon, 01 Sep 2008) $
00016  *
00017  * @param T The type of time.
00018  *
00019  * Produces a new approximation of a weighted sample set at time
00020  * \f$t_n\f$ by performing a one step lookahead, favouring those
00021  * particles more likely to have higher weights at time
00022  * \f$t_{n+1}\f$. Combined with ParticleFilter, this produces the
00023  * Auxiliary Particle Filter.
00024  *
00025  * @section AuxiliaryParticleResampler_references References
00026  */
00027 template <class T = unsigned int>
00028 class AuxiliaryParticleResampler : public ParticleResampler {
00029 public:
00030   /**
00031    * Constructor.
00032    *
00033    * @param filter Particle %filter to which to couple the resampler.
00034    * @param P Number of particles to resample from each distribution
00035    * supplied to resample(). If zero, will resample the same number of
00036    * particles as the distribution supplied.
00037    */
00038   AuxiliaryParticleResampler(ParticleFilter<T>* filter,
00039       const unsigned int P = 0);
00040 
00041   /**
00042    * Destructor.
00043    */
00044   virtual ~AuxiliaryParticleResampler();
00045 
00046   /**
00047    * Set the number of particles to resample.
00048    *
00049    * @param P Number of particles to resample from each distribution
00050    * supplied to resample(). If zero, will resample the same number of
00051    * particles as the distribution supplied.
00052    */
00053   void setNumParticles(const unsigned int P = 0);
00054 
00055   /**
00056    * Set lookahead parameters for next resampling.
00057    *
00058    * @param tnp1 \f$t_{n+1}\f$; the time at which the next measurement
00059    * will be available.
00060    * @param ytnp1 \f$\mathbf{y}(t_{n+1})\f$; the next measurement, at
00061    * time \f$t_{n+1}\f$.
00062    *
00063    * Sets the parameters for the next call to
00064    * ParticleFilter::filter(). These provide a lookahead to the future
00065    * time \f$t_{n+1}\f$ on which to base the resampling of particles
00066    * at the current time \f$t_b\f$.
00067    */
00068   void setLookAhead(const T tnp1, const indii::ml::aux::vector& ytnp1);
00069 
00070   virtual indii::ml::aux::DiracMixturePdf resample(
00071       indii::ml::aux::DiracMixturePdf& p);
00072 
00073 private:
00074   /**
00075    * Reweighted component.
00076    */
00077   struct reweighted_component {
00078     /**
00079      * Weight.
00080      */
00081     double w;
00082 
00083     /**
00084      * Reweighted weight.
00085      */
00086     double rw;
00087 
00088     /**
00089      * Component
00090      */
00091     indii::ml::aux::DiracPdf x;
00092 
00093     /**
00094      * Comparison operator for sorting.
00095      *
00096      * @return True if this component has greater reweight than the
00097      * argument's component.
00098      */
00099     bool operator<(const reweighted_component& o) const;
00100 
00101   };
00102 
00103   /**
00104    * Reweighted component vector.
00105    */
00106   typedef std::vector<reweighted_component> reweighted_component_vector;
00107 
00108   /**
00109    * Reweighted component iterator.
00110    */
00111   typedef typename reweighted_component_vector::iterator
00112       reweighted_component_iterator;
00113 
00114   /**
00115    * Reweighted component const iterator.
00116    */
00117   typedef typename reweighted_component_vector::const_iterator
00118       reweighted_component_const_iterator;
00119 
00120   /**
00121    * Particle filter to which the resampler is coupled.
00122    */
00123   ParticleFilter<T>* filter;
00124 
00125   /**
00126    * Number of particles to resample from each distribution.
00127    */
00128   unsigned int P;
00129 
00130   /**
00131    * Time at which the next measurement will be available.
00132    */
00133   T tnp1;
00134 
00135   /**
00136    * The next measurement.
00137    */
00138   indii::ml::aux::vector ytnp1;
00139 
00140 };
00141 
00142     }
00143   }
00144 }
00145 
00146 template <class T>
00147 indii::ml::filter::AuxiliaryParticleResampler<T>::AuxiliaryParticleResampler(
00148     ParticleFilter<T>* filter, const unsigned int P) : filter(filter), P(P) {
00149   //
00150 }
00151 
00152 template <class T>
00153 indii::ml::filter::AuxiliaryParticleResampler<T>::~AuxiliaryParticleResampler() {
00154   //
00155 }
00156 
00157 template <class T>
00158 void indii::ml::filter::AuxiliaryParticleResampler<T>::setNumParticles(
00159     const unsigned int P) {
00160   this->P = P;
00161 }
00162 
00163 template <class T>
00164 void indii::ml::filter::AuxiliaryParticleResampler<T>::setLookAhead(
00165     const T tnp1, const indii::ml::aux::vector& ytnp1) {
00166   this->tnp1 = tnp1;
00167   this->ytnp1.resize(ytnp1.size());
00168   this->ytnp1 = ytnp1;
00169 }
00170 
00171 template <class T>
00172 indii::ml::aux::DiracMixturePdf
00173     indii::ml::filter::AuxiliaryParticleResampler<T>::resample(
00174     indii::ml::aux::DiracMixturePdf& p) {
00175   namespace aux = indii::ml::aux;
00176 
00177   boost::mpi::communicator world;
00178   const unsigned int rank = world.rank();
00179   const unsigned int size = world.size();
00180 
00181   aux::DiracMixturePdf resampled(p.getDimensions());
00182   aux::vector x(p.getDimensions());
00183 
00184   ParticleFilterModel<T>* model = filter->getModel();
00185   const T tn = filter->getTime();
00186   const T delta = tnp1 - tn;
00187 
00188   unsigned int i;
00189   unsigned int P = this->P;
00190   if (P == 0) {
00191     P = p.getDistributedSize();
00192   }
00193   const unsigned int P_local = p.getSize();
00194 
00195   double W_rw;  // local reweight total
00196   double W_rws; // scan sum reweight
00197   double W_rwt; // distributed reweight total
00198   aux::vector rw(P_local); // auxiliary weights
00199 
00200   /* calculate auxiliary weights */
00201   W_rw = 0.0;
00202   for (i = 0; i < P_local; i++) {
00203     noalias(x) = model->transition(p.get(i), tn, delta);
00204     rw(i) = model->weight(x, ytnp1) * p.getWeight(i);
00205     W_rw += rw(i);
00206   }
00207 
00208   /* scan sum and total reweights */
00209   W_rws = boost::mpi::scan(world, W_rw, std::plus<double>());
00210   if (rank == size - 1) {
00211     W_rwt = W_rws; // already has total weight
00212   }
00213   boost::mpi::broadcast(world, W_rwt, size - 1);
00214 
00215   /* generate common random alpha across nodes */
00216   double alpha;
00217   if (rank == 0) {
00218     alpha = aux::Random::uniform(0.0, 1.0);
00219   }
00220   boost::mpi::broadcast(world, alpha, 0);
00221 
00222   /* resample */
00223   double u = 0.0;
00224   double w, j, rem;
00225 
00226   w = W_rwt / P;
00227   rem = fmod(W_rws - W_rw, w);
00228   if (rem >= alpha*w) {
00229     j = 1.0 + alpha - rem/w;
00230   } else {
00231     j = alpha - rem/w;
00232   }
00233 
00234   for (i = 0; i < P_local; i++) {
00235     u += rw(i);
00236     while (u >= w * j) {
00237       resampled.add(p.get(i), p.getWeight(i) / rw(i));
00238       j += 1.0;
00239     }
00240   }
00241 
00242   resampled.redistributeBySize();
00243   
00244   return resampled;
00245 }
00246 
00247 template <class T>
00248 bool indii::ml::filter::AuxiliaryParticleResampler<T>::reweighted_component::operator<(
00249     const reweighted_component& o) const {
00250   return this->rw > o.rw;
00251 }
00252 
00253 #endif

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