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

Revision 700, 11.1 kB (checked in by smidl, 15 years ago)

Making tutorial/userguide example work again (changes of mpdf and bayes)

  • 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() { return _w; }
98        //!access function
99        vec& _lls() { return lls; }
100        //!access function
101        RESAMPLING_METHOD _resmethod() const { return resmethod; }
102        //! return correctly typed posterior (covariant return)
103        const eEmp& posterior() const {return est;}
104       
105        /*! configuration structure for basic PF
106        \code
107        parameter_pdf   = pdf_class;         // parameter evolution pdf
108        observation_pdf = pdf_class;         // observation pdf
109        prior           = epdf_class;         // prior probability density
110        --- optional ---
111        n               = 10;                 // number of particles
112        resmethod       = 'systematic', or 'multinomial', or 'stratified'
113                                                                                  // resampling method
114        res_threshold   = 0.5;                // resample when active particles drop below 50%
115        \endcode
116        */
117        void from_setting(const Setting &set){
118                BM::from_setting(set);
119                par = UI::build<pdf>(set,"parameter_pdf",UI::compulsory);
120                obs = UI::build<pdf>(set,"observation_pdf",UI::compulsory);
121               
122                prior_from_set(set);
123                resmethod_from_set(set);
124                // set resampling method
125                //set drv
126                //find potential input - what remains in rvc when we subtract rv
127                RV u = par->_rvc().remove_time().subt( par->_rv() ); 
128                //find potential input - what remains in rvc when we subtract x_t
129                RV obs_u = obs->_rvc().remove_time().subt( par->_rv() ); 
130               
131                u.add(obs_u); // join both u, and check if they do not overlap
132
133                set_yrv(obs->_rv() );
134                rvc = u;
135        }
136        //! auxiliary function reading parameter 'resmethod' from configuration file
137        void resmethod_from_set(const Setting &set){
138                string resmeth;
139                if (UI::get(resmeth,set,"resmethod",UI::optional)){
140                        if (resmeth=="systematic") {
141                                resmethod= SYSTEMATIC;
142                        } else  {
143                                if (resmeth=="multinomial"){
144                                        resmethod=MULTINOMIAL;
145                                } else {
146                                        if (resmeth=="stratified"){
147                                                resmethod= STRATIFIED;
148                                        } else {
149                                                bdm_error("Unknown resampling method");
150                                        }
151                                }
152                        }
153                } else {
154                        resmethod=SYSTEMATIC;
155                };
156                if(!UI::get(res_threshold, set, "res_threshold", UI::optional)){
157                        res_threshold=0.5;
158                }
159                //validate();
160        }
161        //! load prior information from set and set internal structures accordingly
162        void prior_from_set(const Setting & set){
163                shared_ptr<epdf> pri = UI::build<epdf>(set,"prior",UI::compulsory);
164               
165                eEmp *test_emp=dynamic_cast<eEmp*>(&(*pri));
166                if (test_emp) { // given pdf is sampled
167                        est=*test_emp;
168                } else {
169                        //int n;
170                        if (!UI::get(n,set,"n",UI::optional)){n=10;}
171                        // sample from prior
172                        set_statistics(ones(n)/n, *pri);
173                }
174                n = est._w().length();
175                //validate();
176        }
177       
178        void validate(){
179                bdm_assert(par,"PF::parameter_pdf not specified.");
180                n=_w.length();
181                lls=zeros(n);
182               
183                if (par->_rv()._dsize()>0) {
184                        bdm_assert(par->_rv()._dsize()==est.dimension(),"Mismatch of RV and dimension of posterior" );
185                }
186        }
187        //! resample posterior density (from outside - see MPF)
188        void resample(ivec &ind){
189                est.resample(ind,resmethod);
190        }
191        //! access function
192        Array<vec>& __samples(){return _samples;}
193};
194UIREGISTER(PF);
195
196/*!
197\brief Marginalized Particle filter
198
199A composition of particle filter with exact (or almost exact) bayesian models (BMs).
200The Bayesian models provide marginalized predictive density. Internaly this is achieved by virtual class MPFpdf.
201*/
202
203class MPF : public BM  {
204        protected:
205                //! particle filter on non-linear variable
206        shared_ptr<PF> pf;
207        //! Array of Bayesian models
208        Array<BM*> BMs;
209
210        //! internal class for pdf providing composition of eEmp with external components
211
212        class mpfepdf : public epdf  {
213                //! pointer to particle filter
214                shared_ptr<PF> &pf;
215                //! pointer to Array of BMs
216                Array<BM*> &BMs;
217        public:
218                //! constructor
219                mpfepdf (shared_ptr<PF> &pf0, Array<BM*> &BMs0): epdf(), pf(pf0), BMs(BMs0) { };
220                //! a variant of set parameters - this time, parameters are read from BMs and pf
221                void read_parameters(){
222                        rv = concat(pf->posterior()._rv(), BMs(0)->posterior()._rv());
223                        dim = pf->posterior().dimension() + BMs(0)->posterior().dimension();
224                        bdm_assert_debug(dim == rv._dsize(), "Wrong name ");
225                }
226                vec mean() const {
227                        const vec &w = pf->posterior()._w();
228                        vec pom = zeros ( BMs(0)->posterior ().dimension() );
229                        //compute mean of BMs
230                        for ( int i = 0; i < w.length(); i++ ) {
231                                pom += BMs ( i )->posterior().mean() * w ( i );
232                        }
233                        return concat ( pf->posterior().mean(), pom );
234                }
235                vec variance() const {
236                        const vec &w = pf->posterior()._w();
237                       
238                        vec pom = zeros ( BMs(0)->posterior ().dimension() );
239                        vec pom2 = zeros ( BMs(0)->posterior ().dimension() );
240                        vec mea;
241                       
242                        for ( int i = 0; i < w.length(); i++ ) {
243                                // save current mean
244                                mea = BMs ( i )->posterior().mean();
245                                pom += mea * w ( i );
246                                //compute variance
247                                pom2 += ( BMs ( i )->posterior().variance() + pow ( mea, 2 ) ) * w ( i );
248                        }
249                        return concat ( pf->posterior().variance(), pom2 - pow ( pom, 2 ) );
250                }
251               
252                void qbounds ( vec &lb, vec &ub, double perc = 0.95 ) const {
253                        //bounds on particles
254                        vec lbp;
255                        vec ubp;
256                        pf->posterior().qbounds ( lbp, ubp );
257
258                        //bounds on Components
259                        int dimC = BMs ( 0 )->posterior().dimension();
260                        int j;
261                        // temporary
262                        vec lbc ( dimC );
263                        vec ubc ( dimC );
264                        // minima and maxima
265                        vec Lbc ( dimC );
266                        vec Ubc ( dimC );
267                        Lbc = std::numeric_limits<double>::infinity();
268                        Ubc = -std::numeric_limits<double>::infinity();
269
270                        for ( int i = 0; i < BMs.length(); i++ ) {
271                                // check Coms
272                                BMs ( i )->posterior().qbounds ( lbc, ubc );
273                                //save either minima or maxima
274                                for ( j = 0; j < dimC; j++ ) {
275                                        if ( lbc ( j ) < Lbc ( j ) ) {
276                                                Lbc ( j ) = lbc ( j );
277                                        }
278                                        if ( ubc ( j ) > Ubc ( j ) ) {
279                                                Ubc ( j ) = ubc ( j );
280                                        }
281                                }
282                        }
283                        lb = concat ( lbp, Lbc );
284                        ub = concat ( ubp, Ubc );
285                }
286
287                vec sample() const {
288                        bdm_error ( "Not implemented" );
289                        return vec();
290                }
291
292                double evallog ( const vec &val ) const {
293                        bdm_error ( "not implemented" );
294                        return 0.0;
295                }
296        };
297
298        //! Density joining PF.est with conditional parts
299        mpfepdf jest;
300
301        //! datalink from global yt and cond (Up) to BMs yt and cond (Down)
302        datalink_m2m this2bm;
303        //! datalink from global yt and cond (Up) to PFs yt and cond (Down)
304        datalink_m2m this2pf;
305        //!datalink from PF part to BM
306        datalink_part pf2bm;
307       
308public:
309        //! Default constructor.
310        MPF () :  jest (pf,BMs) {};
311        //! set all parameters at once
312        void set_parameters ( shared_ptr<pdf> par0, shared_ptr<pdf> obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) {
313                pf->set_model ( par0, obs0); 
314                pf->set_parameters(n0, rm );
315                BMs.set_length ( n0 );
316        }
317        //! set a prototype of BM, copy it to as many times as there is particles in pf
318        void set_BM ( const BM &BMcond0 ) {
319
320                int n=pf->__w().length();
321                BMs.set_length(n);
322                // copy
323                //BMcond0 .condition ( pf->posterior()._sample ( 0 ) );
324                for ( int i = 0; i < n; i++ ) {
325                        BMs ( i ) = BMcond0._copy_();
326                }
327        };
328
329        void bayes ( const vec &yt, const vec &cond );
330        const epdf& posterior() const {
331                return jest;
332        }
333        //! Extends options understood by BM::set_options by option
334        //! \li logmeans - meaning
335        void set_options ( const string &opt ) {
336                BM::set_options(opt);
337        }
338
339        //!Access function
340        const BM* _BM ( int i ) {
341                return BMs ( i );
342        }
343       
344        /*! configuration structure for basic PF
345        \code
346        BM              = BM_class;           // Bayesian filtr for analytical part of the model
347        parameter_pdf   = pdf_class;         // transitional pdf for non-parametric part of the model
348        prior           = epdf_class;         // prior probability density
349        --- optional ---
350        n               = 10;                 // number of particles
351        resmethod       = 'systematic', or 'multinomial', or 'stratified'
352                                                                                  // resampling method
353        \endcode
354        */     
355        void from_setting(const Setting &set){
356                shared_ptr<pdf> par = UI::build<pdf>(set,"parameter_pdf",UI::compulsory);
357                shared_ptr<pdf> obs= new pdf(); // not used!!
358
359                pf = new PF;
360                // prior must be set before BM
361                pf->prior_from_set(set);
362                pf->resmethod_from_set(set);
363                pf->set_model(par,obs);
364                               
365                shared_ptr<BM> BM0 =UI::build<BM>(set,"BM",UI::compulsory);
366                set_BM(*BM0);
367               
368                string opt;
369                if (UI::get(opt,set,"options",UI::optional)){
370                        set_options(opt);
371                }
372                //set drv
373                //??set_yrv(concat(BM0->_yrv(),u) );
374                set_yrv(BM0->_yrv() );
375                rvc = BM0->_rvc().subt(par->_rv());
376                //find potential input - what remains in rvc when we subtract rv
377                RV u = par->_rvc().subt( par->_rv().copy_t(-1) );               
378                rvc.add(u);
379                dimc = rvc._dsize();
380                validate();
381        }
382        void validate(){
383                try{
384                        pf->validate();
385                } catch (std::exception &e){
386                        throw UIException("Error in PF part of MPF:");
387                }
388                jest.read_parameters();
389                this2bm.set_connection(BMs(0)->_yrv(), BMs(0)->_rvc(), yrv, rvc);
390                this2pf.set_connection(pf->_yrv(), pf->_rvc(), yrv, rvc);
391                pf2bm.set_connection(BMs(0)->_rvc(), pf->posterior()._rv());
392        }
393
394};
395UIREGISTER(MPF);
396
397}
398#endif // KF_H
399
Note: See TracBrowser for help on using the browser.