/*! \file \brief Bayesian Filtering using stochastic sampling (Particle Filters) \author Vaclav Smidl. ----------------------------------- BDM++ - C++ library for Bayesian Decision Making under Uncertainty Using IT++ for numerical operations ----------------------------------- */ #ifndef PARTICLES_H #define PARTICLES_H #include "../stat/exp_family.h" namespace bdm { /*! * \brief Trivial particle filter with proposal density equal to parameter evolution model. Posterior density is represented by a weighted empirical density (\c eEmp ). */ class PF : public BM { protected: //!number of particles; int n; //!posterior density eEmp est; //! pointer into \c eEmp vec &_w; //! pointer into \c eEmp Array &_samples; //! Parameter evolution model mpdf *par; //! Observation model mpdf *obs; //! which resampling method will be used RESAMPLING_METHOD resmethod; //! \name Options //!@{ //! Log all samples bool opt_L_smp; //! Log all samples bool opt_L_wei; //!@} public: //! \name Constructors //!@{ PF ( ) : est(), _w ( est._w() ), _samples ( est._samples() ), opt_L_smp ( false ), opt_L_wei ( false ) { LIDs.set_size ( 5 ); }; /* PF ( mpdf *par0, mpdf *obs0, epdf *epdf0, int n0 ) : est ( ),_w ( est._w() ),_samples ( est._samples() ),opt_L_smp(false), opt_L_wei(false) { set_parameters ( par0,obs0,n0 ); set_statistics ( ones ( n0 ),epdf0 ); };*/ void set_parameters ( mpdf *par0, mpdf *obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) { par = par0; obs = obs0; n = n0; resmethod = rm; }; void set_statistics ( const vec w0, epdf *epdf0 ) { est.set_statistics ( w0, epdf0 ); }; //!@} //! Set posterior density by sampling from epdf0 // void set_est ( const epdf &epdf0 ); void set_options ( const string &opt ) { BM::set_options ( opt ); opt_L_wei = ( opt.find ( "logweights" ) != string::npos ); opt_L_smp = ( opt.find ( "logsamples" ) != string::npos ); } void bayes ( const vec &dt ); //!access function vec* __w() { return &_w; } }; /*! \brief Marginalized Particle filter Trivial version: proposal = parameter evolution, observation model is not used. (it is assumed to be part of BM). */ template class MPF : public PF { Array BMs; //! internal class for MPDF providing composition of eEmp with external components class mpfepdf : public epdf { protected: eEmp &E; vec &_w; Array Coms; public: mpfepdf ( eEmp &E0 ) : epdf ( ), E ( E0 ), _w ( E._w() ), Coms ( _w.length() ) { }; //! read statistics from MPF void read_statistics ( Array &A ) { dim = E.dimension() + A ( 0 )->posterior().dimension(); for ( int i = 0; i < _w.length() ; i++ ) { Coms ( i ) = A ( i )->_e(); } } //! needed in resampling void set_elements ( int &i, double wi, const epdf* ep ) { _w ( i ) = wi; Coms ( i ) = ep; }; void set_parameters ( int n ) { E.set_parameters ( n, false ); Coms.set_length ( n ); } vec mean() const { // ugly vec pom = zeros ( Coms ( 0 )->dimension() ); for ( int i = 0; i < _w.length(); i++ ) { pom += Coms ( i )->mean() * _w ( i ); } return concat ( E.mean(), pom ); } vec variance() const { // ugly vec pom = zeros ( Coms ( 0 )->dimension() ); vec pom2 = zeros ( Coms ( 0 )->dimension() ); for ( int i = 0; i < _w.length(); i++ ) { pom += Coms ( i )->mean() * _w ( i ); pom2 += ( Coms ( i )->variance() + pow ( Coms ( i )->mean(), 2 ) ) * _w ( i ); } return concat ( E.variance(), pom2 - pow ( pom, 2 ) ); } void qbounds ( vec &lb, vec &ub, double perc = 0.95 ) const { //bounds on particles vec lbp; vec ubp; E.qbounds ( lbp, ubp ); //bounds on Components int dimC = Coms ( 0 )->dimension(); int j; // temporary vec lbc ( dimC ); vec ubc ( dimC ); // minima and maxima vec Lbc ( dimC ); vec Ubc ( dimC ); Lbc = std::numeric_limits::infinity(); Ubc = -std::numeric_limits::infinity(); for ( int i = 0; i < _w.length(); i++ ) { // check Coms Coms ( i )->qbounds ( lbc, ubc ); for ( j = 0; j < dimC; j++ ) { if ( lbc ( j ) < Lbc ( j ) ) { Lbc ( j ) = lbc ( j ); } if ( ubc ( j ) > Ubc ( j ) ) { Ubc ( j ) = ubc ( j ); } } } lb = concat ( lbp, Lbc ); ub = concat ( ubp, Ubc ); } vec sample() const { it_error ( "Not implemented" ); return 0; } double evallog ( const vec &val ) const { it_error ( "not implemented" ); return 0.0; } }; //! Density joining PF.est with conditional parts mpfepdf jest; //! Log means of BMs bool opt_L_mea; public: //! Default constructor. MPF () : PF (), jest ( est ) {}; void set_parameters ( mpdf *par0, mpdf *obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) { PF::set_parameters ( par0, obs0, n0, rm ); jest.set_parameters ( n0 );//duplication of rm BMs.set_length ( n0 ); } void set_statistics ( epdf *epdf0, const BM_T* BMcond0 ) { PF::set_statistics ( ones ( n ) / n, epdf0 ); // copy for ( int i = 0; i < n; i++ ) { BMs ( i ) = new BM_T ( *BMcond0 ); BMs ( i )->condition ( _samples ( i ) ); } jest.read_statistics ( BMs ); //options }; void bayes ( const vec &dt ); const epdf& posterior() const { return jest; } const epdf* _e() const { return &jest; //Fixme: is it useful? } //! Set postrior of \c rvc to samples from epdf0. Statistics of BMs are not re-computed! Use only for initialization! /* void set_est ( const epdf& epdf0 ) { PF::set_est ( epdf0 ); // sample params in condition // copy conditions to BMs for ( int i=0;icondition ( _samples ( i ) );} }*/ void set_options ( const string &opt ) { PF::set_options ( opt ); opt_L_mea = ( opt.find ( "logmeans" ) != string::npos ); } //!Access function BM* _BM ( int i ) { return BMs ( i ); } }; template void MPF::bayes ( const vec &dt ) { int i; vec lls ( n ); vec llsP ( n ); ivec ind; double mlls = -std::numeric_limits::infinity(); #pragma omp parallel for for ( i = 0; i < n; i++ ) { //generate new samples from paramater evolution model; vec old_smp=_samples ( i ); _samples ( i ) = par->samplecond ( old_smp ); llsP ( i ) = par->evallogcond ( _samples ( i ), old_smp ); BMs ( i )->condition ( _samples ( i ) ); BMs ( i )->bayes ( dt ); lls ( i ) = BMs ( i )->_ll(); // lls above is also in proposal her must be lls(i) =, not +=!! if ( lls ( i ) > mlls ) mlls = lls ( i ); //find maximum likelihood (for numerical stability) } double sum_w = 0.0; // compute weights #pragma omp parallel for for ( i = 0; i < n; i++ ) { _w ( i ) *= exp ( lls ( i ) - mlls ); // multiply w by likelihood sum_w += _w ( i ); } if ( sum_w > 0.0 ) { _w /= sum_w; //? } else { cout << "sum(w)==0" << endl; } double eff = 1.0 / ( _w * _w ); if ( eff < ( 0.3*n ) ) { ind = est.resample ( resmethod ); // Resample Bms! #pragma omp parallel for for ( i = 0; i < n; i++ ) { if ( ind ( i ) != i ) {//replace the current Bm by a new one //fixme this would require new assignment operator // *Bms[i] = *Bms[ind ( i ) ]; // poor-man's solution: replicate constructor here // copied from MPF::MPF delete BMs ( i ); BMs ( i ) = new BM_T ( *BMs ( ind ( i ) ) ); //copy constructor const epdf& pom = BMs ( i )->posterior(); jest.set_elements ( i, 1.0 / n, &pom ); } }; cout << '.'; } } } #endif // KF_H