root/library/bdm/estim/particles.h @ 737

Revision 737, 11.4 kB (checked in by mido, 14 years ago)

ASTYLER RUN OVER THE WHOLE LIBRARY, JUPEE

  • Property svn:eol-style set to native
Line 
1/*!
2  \file
3  \brief Bayesian Filtering using stochastic sampling (Particle Filters)
4  \author Vaclav Smidl.
5
6  -----------------------------------
7  BDM++ - C++ library for Bayesian Decision Making under Uncertainty
8
9  Using IT++ for numerical operations
10  -----------------------------------
11*/
12
13#ifndef PARTICLES_H
14#define PARTICLES_H
15
16
17#include "../stat/exp_family.h"
18
19namespace bdm {
20
21/*!
22* \brief Trivial particle filter with proposal density equal to parameter evolution model.
23
24Posterior density is represented by a weighted empirical density (\c eEmp ).
25*/
26
27class PF : public BM {
28protected:
29        //!number of particles;
30        int n;
31        //!posterior density
32        eEmp est;
33        //! pointer into \c eEmp
34        vec &_w;
35        //! pointer into \c eEmp
36        Array<vec> &_samples;
37        //! Parameter evolution model
38        shared_ptr<pdf> par;
39        //! Observation model
40        shared_ptr<pdf> obs;
41        //! internal structure storing loglikelihood of predictions
42        vec lls;
43
44        //! which resampling method will be used
45        RESAMPLING_METHOD resmethod;
46        //! resampling threshold; in this case its meaning is minimum ratio of active particles
47        //! For example, for 0.5 resampling is performed when the numebr of active aprticles drops belo 50%.
48        double res_threshold;
49
50        //! \name Options
51        //!@{
52        //!@}
53
54public:
55        //! \name Constructors
56        //!@{
57        PF ( ) : est(), _w ( est._w() ), _samples ( est._samples() ) {
58        };
59
60        void set_parameters ( int n0, double res_th0 = 0.5, RESAMPLING_METHOD rm = SYSTEMATIC ) {
61                n = n0;
62                res_threshold = res_th0;
63                resmethod = rm;
64        };
65        void set_model ( shared_ptr<pdf> par0, shared_ptr<pdf> obs0 ) {
66                par = par0;
67                obs = obs0;
68                // set values for posterior
69                est.set_rv ( par->_rv() );
70        };
71        void set_statistics ( const vec w0, const epdf &epdf0 ) {
72                est.set_statistics ( w0, epdf0 );
73        };
74        void set_statistics ( const eEmp &epdf0 ) {
75                bdm_assert_debug ( epdf0._rv().equal ( par->_rv() ), "Incompatibel input" );
76                est = epdf0;
77        };
78        //!@}
79        //! Set posterior density by sampling from epdf0
80        //! Extends original BM::set_options by two more options:
81        //! \li logweights - meaning that all weightes will be logged
82        //! \li logsamples - all samples will be also logged
83        void set_options ( const string &opt ) {
84                BM::set_options ( opt );
85        }
86        //! bayes I - generate samples and add their weights to lls
87        virtual void bayes_gensmp ( const vec &ut );
88        //! bayes II - compute weights of the
89        virtual void bayes_weights();
90        //! important part of particle filtering - decide if it is time to perform resampling
91        virtual bool do_resampling() {
92                double eff = 1.0 / ( _w * _w );
93                return eff < ( res_threshold*n );
94        }
95        void bayes ( const vec &yt, const vec &cond );
96        //!access function
97        vec& __w() {
98                return _w;
99        }
100        //!access function
101        vec& _lls() {
102                return lls;
103        }
104        //!access function
105        RESAMPLING_METHOD _resmethod() const {
106                return resmethod;
107        }
108        //! return correctly typed posterior (covariant return)
109        const eEmp& posterior() const {
110                return est;
111        }
112
113        /*! configuration structure for basic PF
114        \code
115        parameter_pdf   = pdf_class;         // parameter evolution pdf
116        observation_pdf = pdf_class;         // observation pdf
117        prior           = epdf_class;         // prior probability density
118        --- optional ---
119        n               = 10;                 // number of particles
120        resmethod       = 'systematic', or 'multinomial', or 'stratified'
121                                                                                  // resampling method
122        res_threshold   = 0.5;                // resample when active particles drop below 50%
123        \endcode
124        */
125        void from_setting ( const Setting &set ) {
126                BM::from_setting ( set );
127                par = UI::build<pdf> ( set, "parameter_pdf", UI::compulsory );
128                obs = UI::build<pdf> ( set, "observation_pdf", UI::compulsory );
129
130                prior_from_set ( set );
131                resmethod_from_set ( set );
132                // set resampling method
133                //set drv
134                //find potential input - what remains in rvc when we subtract rv
135                RV u = par->_rvc().remove_time().subt ( par->_rv() );
136                //find potential input - what remains in rvc when we subtract x_t
137                RV obs_u = obs->_rvc().remove_time().subt ( par->_rv() );
138
139                u.add ( obs_u ); // join both u, and check if they do not overlap
140
141                set_yrv ( obs->_rv() );
142                rvc = u;
143        }
144        //! auxiliary function reading parameter 'resmethod' from configuration file
145        void resmethod_from_set ( const Setting &set ) {
146                string resmeth;
147                if ( UI::get ( resmeth, set, "resmethod", UI::optional ) ) {
148                        if ( resmeth == "systematic" ) {
149                                resmethod = SYSTEMATIC;
150                        } else  {
151                                if ( resmeth == "multinomial" ) {
152                                        resmethod = MULTINOMIAL;
153                                } else {
154                                        if ( resmeth == "stratified" ) {
155                                                resmethod = STRATIFIED;
156                                        } else {
157                                                bdm_error ( "Unknown resampling method" );
158                                        }
159                                }
160                        }
161                } else {
162                        resmethod = SYSTEMATIC;
163                };
164                if ( !UI::get ( res_threshold, set, "res_threshold", UI::optional ) ) {
165                        res_threshold = 0.5;
166                }
167                //validate();
168        }
169        //! load prior information from set and set internal structures accordingly
170        void prior_from_set ( const Setting & set ) {
171                shared_ptr<epdf> pri = UI::build<epdf> ( set, "prior", UI::compulsory );
172
173                eEmp *test_emp = dynamic_cast<eEmp*> ( & ( *pri ) );
174                if ( test_emp ) { // given pdf is sampled
175                        est = *test_emp;
176                } else {
177                        //int n;
178                        if ( !UI::get ( n, set, "n", UI::optional ) ) {
179                                n = 10;
180                        }
181                        // sample from prior
182                        set_statistics ( ones ( n ) / n, *pri );
183                }
184                n = est._w().length();
185                //validate();
186        }
187
188        void validate() {
189                bdm_assert ( par, "PF::parameter_pdf not specified." );
190                n = _w.length();
191                lls = zeros ( n );
192
193                if ( par->_rv()._dsize() > 0 ) {
194                        bdm_assert ( par->_rv()._dsize() == est.dimension(), "Mismatch of RV and dimension of posterior" );
195                }
196        }
197        //! resample posterior density (from outside - see MPF)
198        void resample ( ivec &ind ) {
199                est.resample ( ind, resmethod );
200        }
201        //! access function
202        Array<vec>& __samples() {
203                return _samples;
204        }
205};
206UIREGISTER ( PF );
207
208/*!
209\brief Marginalized Particle filter
210
211A composition of particle filter with exact (or almost exact) bayesian models (BMs).
212The Bayesian models provide marginalized predictive density. Internaly this is achieved by virtual class MPFpdf.
213*/
214
215class MPF : public BM  {
216protected:
217        //! particle filter on non-linear variable
218        shared_ptr<PF> pf;
219        //! Array of Bayesian models
220        Array<BM*> BMs;
221
222        //! internal class for pdf providing composition of eEmp with external components
223
224        class mpfepdf : public epdf  {
225                //! pointer to particle filter
226                shared_ptr<PF> &pf;
227                //! pointer to Array of BMs
228                Array<BM*> &BMs;
229        public:
230                //! constructor
231                mpfepdf ( shared_ptr<PF> &pf0, Array<BM*> &BMs0 ) : epdf(), pf ( pf0 ), BMs ( BMs0 ) { };
232                //! a variant of set parameters - this time, parameters are read from BMs and pf
233                void read_parameters() {
234                        rv = concat ( pf->posterior()._rv(), BMs ( 0 )->posterior()._rv() );
235                        dim = pf->posterior().dimension() + BMs ( 0 )->posterior().dimension();
236                        bdm_assert_debug ( dim == rv._dsize(), "Wrong name " );
237                }
238                vec mean() const {
239                        const vec &w = pf->posterior()._w();
240                        vec pom = zeros ( BMs ( 0 )->posterior ().dimension() );
241                        //compute mean of BMs
242                        for ( int i = 0; i < w.length(); i++ ) {
243                                pom += BMs ( i )->posterior().mean() * w ( i );
244                        }
245                        return concat ( pf->posterior().mean(), pom );
246                }
247                vec variance() const {
248                        const vec &w = pf->posterior()._w();
249
250                        vec pom = zeros ( BMs ( 0 )->posterior ().dimension() );
251                        vec pom2 = zeros ( BMs ( 0 )->posterior ().dimension() );
252                        vec mea;
253
254                        for ( int i = 0; i < w.length(); i++ ) {
255                                // save current mean
256                                mea = BMs ( i )->posterior().mean();
257                                pom += mea * w ( i );
258                                //compute variance
259                                pom2 += ( BMs ( i )->posterior().variance() + pow ( mea, 2 ) ) * w ( i );
260                        }
261                        return concat ( pf->posterior().variance(), pom2 - pow ( pom, 2 ) );
262                }
263
264                void qbounds ( vec &lb, vec &ub, double perc = 0.95 ) const {
265                        //bounds on particles
266                        vec lbp;
267                        vec ubp;
268                        pf->posterior().qbounds ( lbp, ubp );
269
270                        //bounds on Components
271                        int dimC = BMs ( 0 )->posterior().dimension();
272                        int j;
273                        // temporary
274                        vec lbc ( dimC );
275                        vec ubc ( dimC );
276                        // minima and maxima
277                        vec Lbc ( dimC );
278                        vec Ubc ( dimC );
279                        Lbc = std::numeric_limits<double>::infinity();
280                        Ubc = -std::numeric_limits<double>::infinity();
281
282                        for ( int i = 0; i < BMs.length(); i++ ) {
283                                // check Coms
284                                BMs ( i )->posterior().qbounds ( lbc, ubc );
285                                //save either minima or maxima
286                                for ( j = 0; j < dimC; j++ ) {
287                                        if ( lbc ( j ) < Lbc ( j ) ) {
288                                                Lbc ( j ) = lbc ( j );
289                                        }
290                                        if ( ubc ( j ) > Ubc ( j ) ) {
291                                                Ubc ( j ) = ubc ( j );
292                                        }
293                                }
294                        }
295                        lb = concat ( lbp, Lbc );
296                        ub = concat ( ubp, Ubc );
297                }
298
299                vec sample() const {
300                        bdm_error ( "Not implemented" );
301                        return vec();
302                }
303
304                double evallog ( const vec &val ) const {
305                        bdm_error ( "not implemented" );
306                        return 0.0;
307                }
308        };
309
310        //! Density joining PF.est with conditional parts
311        mpfepdf jest;
312
313        //! datalink from global yt and cond (Up) to BMs yt and cond (Down)
314        datalink_m2m this2bm;
315        //! datalink from global yt and cond (Up) to PFs yt and cond (Down)
316        datalink_m2m this2pf;
317        //!datalink from PF part to BM
318        datalink_part pf2bm;
319
320public:
321        //! Default constructor.
322        MPF () :  jest ( pf, BMs ) {};
323        //! set all parameters at once
324        void set_parameters ( shared_ptr<pdf> par0, shared_ptr<pdf> obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) {
325                pf->set_model ( par0, obs0 );
326                pf->set_parameters ( n0, rm );
327                BMs.set_length ( n0 );
328        }
329        //! set a prototype of BM, copy it to as many times as there is particles in pf
330        void set_BM ( const BM &BMcond0 ) {
331
332                int n = pf->__w().length();
333                BMs.set_length ( n );
334                // copy
335                //BMcond0 .condition ( pf->posterior()._sample ( 0 ) );
336                for ( int i = 0; i < n; i++ ) {
337                        BMs ( i ) = BMcond0._copy_();
338                }
339        };
340
341        void bayes ( const vec &yt, const vec &cond );
342        const epdf& posterior() const {
343                return jest;
344        }
345        //! Extends options understood by BM::set_options by option
346        //! \li logmeans - meaning
347        void set_options ( const string &opt ) {
348                BM::set_options ( opt );
349        }
350
351        //!Access function
352        const BM* _BM ( int i ) {
353                return BMs ( i );
354        }
355
356        /*! configuration structure for basic PF
357        \code
358        BM              = BM_class;           // Bayesian filtr for analytical part of the model
359        parameter_pdf   = pdf_class;         // transitional pdf for non-parametric part of the model
360        prior           = epdf_class;         // prior probability density
361        --- optional ---
362        n               = 10;                 // number of particles
363        resmethod       = 'systematic', or 'multinomial', or 'stratified'
364                                                                                  // resampling method
365        \endcode
366        */
367        void from_setting ( const Setting &set ) {
368                shared_ptr<pdf> par = UI::build<pdf> ( set, "parameter_pdf", UI::compulsory );
369                shared_ptr<pdf> obs = new pdf(); // not used!!
370
371                pf = new PF;
372                // prior must be set before BM
373                pf->prior_from_set ( set );
374                pf->resmethod_from_set ( set );
375                pf->set_model ( par, obs );
376
377                shared_ptr<BM> BM0 = UI::build<BM> ( set, "BM", UI::compulsory );
378                set_BM ( *BM0 );
379
380                string opt;
381                if ( UI::get ( opt, set, "options", UI::optional ) ) {
382                        set_options ( opt );
383                }
384                //set drv
385                //??set_yrv(concat(BM0->_yrv(),u) );
386                set_yrv ( BM0->_yrv() );
387                rvc = BM0->_rvc().subt ( par->_rv() );
388                //find potential input - what remains in rvc when we subtract rv
389                RV u = par->_rvc().subt ( par->_rv().copy_t ( -1 ) );
390                rvc.add ( u );
391                dimc = rvc._dsize();
392                validate();
393        }
394        void validate() {
395                try {
396                        pf->validate();
397                } catch ( std::exception &e ) {
398                        throw UIException ( "Error in PF part of MPF:" );
399                }
400                jest.read_parameters();
401                this2bm.set_connection ( BMs ( 0 )->_yrv(), BMs ( 0 )->_rvc(), yrv, rvc );
402                this2pf.set_connection ( pf->_yrv(), pf->_rvc(), yrv, rvc );
403                pf2bm.set_connection ( BMs ( 0 )->_rvc(), pf->posterior()._rv() );
404        }
405
406};
407UIREGISTER ( MPF );
408
409}
410#endif // KF_H
411
Note: See TracBrowser for help on using the browser.