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

Revision 766, 10.2 kB (checked in by mido, 14 years ago)

abstract methods restored wherever they are meaningful
macros NOT_IMPLEMENTED and NOT_IMPLEMENTED_VOID defined to make sources shorter
emix::set_parameters and mmix::set_parameters removed, corresponding acces methods created and the corresponding validate methods improved appropriately
some compilator warnings were avoided
and also a few other things cleaned up

  • 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
206        virtual double logpred ( const vec &yt ) const NOT_IMPLEMENTED(0);
207
208        virtual epdf* epredictor() const NOT_IMPLEMENTED(NULL);
209       
210        virtual pdf* predictor() const NOT_IMPLEMENTED(NULL);
211};
212UIREGISTER ( PF );
213
214/*!
215\brief Marginalized Particle filter
216
217A composition of particle filter with exact (or almost exact) bayesian models (BMs).
218The Bayesian models provide marginalized predictive density. Internaly this is achieved by virtual class MPFpdf.
219*/
220
221class MPF : public BM  {
222protected:
223        //! particle filter on non-linear variable
224        shared_ptr<PF> pf;
225        //! Array of Bayesian models
226        Array<BM*> BMs;
227
228        //! internal class for pdf providing composition of eEmp with external components
229
230        class mpfepdf : public epdf  {
231                //! pointer to particle filter
232                shared_ptr<PF> &pf;
233                //! pointer to Array of BMs
234                Array<BM*> &BMs;
235        public:
236                //! constructor
237                mpfepdf ( shared_ptr<PF> &pf0, Array<BM*> &BMs0 ) : epdf(), pf ( pf0 ), BMs ( BMs0 ) { };
238                //! a variant of set parameters - this time, parameters are read from BMs and pf
239                void read_parameters() {
240                        rv = concat ( pf->posterior()._rv(), BMs ( 0 )->posterior()._rv() );
241                        dim = pf->posterior().dimension() + BMs ( 0 )->posterior().dimension();
242                        bdm_assert_debug ( dim == rv._dsize(), "Wrong name " );
243                }
244                vec mean() const;
245
246                vec variance() const;
247
248                void qbounds ( vec &lb, vec &ub, double perc = 0.95 ) const;
249
250                vec sample() const NOT_IMPLEMENTED(0);
251
252                double evallog ( const vec &val ) const NOT_IMPLEMENTED(0);             
253        };
254
255        //! Density joining PF.est with conditional parts
256        mpfepdf jest;
257
258        //! datalink from global yt and cond (Up) to BMs yt and cond (Down)
259        datalink_m2m this2bm;
260        //! datalink from global yt and cond (Up) to PFs yt and cond (Down)
261        datalink_m2m this2pf;
262        //!datalink from PF part to BM
263        datalink_part pf2bm;
264
265public:
266        //! Default constructor.
267        MPF () :  jest ( pf, BMs ) {};
268        //! set all parameters at once
269        void set_pf ( shared_ptr<pdf> par0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) {
270                if (!pf) pf=new PF;
271                pf->set_model ( par0, par0 ); // <=== nasty!!!
272                pf->set_parameters ( n0, rm );
273                pf->set_rv(par0->_rv());
274                BMs.set_length ( n0 );
275        }
276        //! set a prototype of BM, copy it to as many times as there is particles in pf
277        void set_BM ( const BM &BMcond0 ) {
278
279                int n = pf->__w().length();
280                BMs.set_length ( n );
281                // copy
282                //BMcond0 .condition ( pf->posterior()._sample ( 0 ) );
283                for ( int i = 0; i < n; i++ ) {
284                        BMs ( i ) = (BM*) BMcond0._copy();
285                }
286        };
287
288        void bayes ( const vec &yt, const vec &cond );
289
290        const epdf& posterior() const {
291                return jest;
292        }
293        //! Extends options understood by BM::set_options by option
294        //! \li logmeans - meaning
295        void set_options ( const string &opt ) {
296                BM::set_options ( opt );
297        }
298
299        //!Access function
300        const BM* _BM ( int i ) {
301                return BMs ( i );
302        }
303        PF& _pf() {return *pf;}
304
305
306        virtual double logpred ( const vec &yt ) const NOT_IMPLEMENTED(0); 
307               
308        virtual epdf* epredictor() const NOT_IMPLEMENTED(NULL); 
309       
310        virtual pdf* predictor() const NOT_IMPLEMENTED(NULL); 
311
312
313        /*! configuration structure for basic PF
314        \code
315        BM              = BM_class;           // Bayesian filtr for analytical part of the model
316        parameter_pdf   = pdf_class;         // transitional pdf for non-parametric part of the model
317        prior           = epdf_class;         // prior probability density
318        --- optional ---
319        n               = 10;                 // number of particles
320        resmethod       = 'systematic', or 'multinomial', or 'stratified'
321                                                                                  // resampling method
322        \endcode
323        */
324        void from_setting ( const Setting &set ) {
325                shared_ptr<pdf> par = UI::build<pdf> ( set, "parameter_pdf", UI::compulsory );
326
327                pf = new PF;
328                // prior must be set before BM
329                pf->prior_from_set ( set );
330                pf->resmethod_from_set ( set );
331                pf->set_model ( par, par ); // too hackish!
332
333                shared_ptr<BM> BM0 = UI::build<BM> ( set, "BM", UI::compulsory );
334                set_BM ( *BM0 );
335
336                string opt;
337                if ( UI::get ( opt, set, "options", UI::optional ) ) {
338                        set_options ( opt );
339                }
340                //set drv
341                //??set_yrv(concat(BM0->_yrv(),u) );
342                set_yrv ( BM0->_yrv() );
343                rvc = BM0->_rvc().subt ( par->_rv() );
344                //find potential input - what remains in rvc when we subtract rv
345                RV u = par->_rvc().subt ( par->_rv().copy_t ( -1 ) );
346                rvc.add ( u );
347                dimc = rvc._dsize();
348                validate();
349        }
350
351        void validate() {
352                try {
353                        pf->validate();
354                } catch ( std::exception ) {
355                        throw UIException ( "Error in PF part of MPF:" );
356                }
357                jest.read_parameters();
358                this2bm.set_connection ( BMs ( 0 )->_yrv(), BMs ( 0 )->_rvc(), yrv, rvc );
359                this2pf.set_connection ( pf->_yrv(), pf->_rvc(), yrv, rvc );
360                pf2bm.set_connection ( BMs ( 0 )->_rvc(), pf->posterior()._rv() );
361        }
362};
363UIREGISTER ( MPF );
364
365}
366#endif // KF_H
367
Note: See TracBrowser for help on using the browser.