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

Revision 686, 10.9 kB (checked in by smidl, 15 years ago)

pmsm using new syntax for 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<mpdf> par;
39        //! Observation model
40        shared_ptr<mpdf> 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<mpdf> par0, shared_ptr<mpdf> 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   = mpdf_class;         // parameter evolution pdf
108        observation_pdf = mpdf_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<mpdf>(set,"parameter_pdf",UI::compulsory);
120                obs = UI::build<mpdf>(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                n=_w.length();
180                lls=zeros(n);
181                if (par->_rv()._dsize()>0) {
182                        bdm_assert(par->_rv()._dsize()==est.dimension(),"Mismatch of RV and dimension of posterior" );
183                }
184        }
185        //! resample posterior density (from outside - see MPF)
186        void resample(ivec &ind){
187                est.resample(ind,resmethod);
188        }
189        //! access function
190        Array<vec>& __samples(){return _samples;}
191};
192UIREGISTER(PF);
193
194/*!
195\brief Marginalized Particle filter
196
197A composition of particle filter with exact (or almost exact) bayesian models (BMs).
198The Bayesian models provide marginalized predictive density. Internaly this is achieved by virtual class MPFmpdf.
199*/
200
201class MPF : public BM  {
202        protected:
203                //! particle filter on non-linear variable
204        shared_ptr<PF> pf;
205        //! Array of Bayesian models
206        Array<BM*> BMs;
207
208        //! internal class for MPDF providing composition of eEmp with external components
209
210        class mpfepdf : public epdf  {
211                //! pointer to particle filter
212                shared_ptr<PF> &pf;
213                //! pointer to Array of BMs
214                Array<BM*> &BMs;
215        public:
216                //! constructor
217                mpfepdf (shared_ptr<PF> &pf0, Array<BM*> &BMs0): epdf(), pf(pf0), BMs(BMs0) { };
218                //! a variant of set parameters - this time, parameters are read from BMs and pf
219                void read_parameters(){
220                        rv = concat(pf->posterior()._rv(), BMs(0)->posterior()._rv());
221                        dim = pf->posterior().dimension() + BMs(0)->posterior().dimension();
222                        bdm_assert_debug(dim == rv._dsize(), "Wrong name ");
223                }
224                vec mean() const {
225                        const vec &w = pf->posterior()._w();
226                        vec pom = zeros ( BMs(0)->posterior ().dimension() );
227                        //compute mean of BMs
228                        for ( int i = 0; i < w.length(); i++ ) {
229                                pom += BMs ( i )->posterior().mean() * w ( i );
230                        }
231                        return concat ( pf->posterior().mean(), pom );
232                }
233                vec variance() const {
234                        const vec &w = pf->posterior()._w();
235                       
236                        vec pom = zeros ( BMs(0)->posterior ().dimension() );
237                        vec pom2 = zeros ( BMs(0)->posterior ().dimension() );
238                        vec mea;
239                       
240                        for ( int i = 0; i < w.length(); i++ ) {
241                                // save current mean
242                                mea = BMs ( i )->posterior().mean();
243                                pom += mea * w ( i );
244                                //compute variance
245                                pom2 += ( BMs ( i )->posterior().variance() + pow ( mea, 2 ) ) * w ( i );
246                        }
247                        return concat ( pf->posterior().variance(), pom2 - pow ( pom, 2 ) );
248                }
249               
250                void qbounds ( vec &lb, vec &ub, double perc = 0.95 ) const {
251                        //bounds on particles
252                        vec lbp;
253                        vec ubp;
254                        pf->posterior().qbounds ( lbp, ubp );
255
256                        //bounds on Components
257                        int dimC = BMs ( 0 )->posterior().dimension();
258                        int j;
259                        // temporary
260                        vec lbc ( dimC );
261                        vec ubc ( dimC );
262                        // minima and maxima
263                        vec Lbc ( dimC );
264                        vec Ubc ( dimC );
265                        Lbc = std::numeric_limits<double>::infinity();
266                        Ubc = -std::numeric_limits<double>::infinity();
267
268                        for ( int i = 0; i < BMs.length(); i++ ) {
269                                // check Coms
270                                BMs ( i )->posterior().qbounds ( lbc, ubc );
271                                //save either minima or maxima
272                                for ( j = 0; j < dimC; j++ ) {
273                                        if ( lbc ( j ) < Lbc ( j ) ) {
274                                                Lbc ( j ) = lbc ( j );
275                                        }
276                                        if ( ubc ( j ) > Ubc ( j ) ) {
277                                                Ubc ( j ) = ubc ( j );
278                                        }
279                                }
280                        }
281                        lb = concat ( lbp, Lbc );
282                        ub = concat ( ubp, Ubc );
283                }
284
285                vec sample() const {
286                        bdm_error ( "Not implemented" );
287                        return vec();
288                }
289
290                double evallog ( const vec &val ) const {
291                        bdm_error ( "not implemented" );
292                        return 0.0;
293                }
294        };
295
296        //! Density joining PF.est with conditional parts
297        mpfepdf jest;
298
299        //! datalink from global yt and cond (Up) to BMs yt and cond (Down)
300        datalink_m2m this2bm;
301        //! datalink from global yt and cond (Up) to PFs yt and cond (Down)
302        datalink_m2m this2pf;
303       
304public:
305        //! Default constructor.
306        MPF () :  jest (pf,BMs) {};
307        //! set all parameters at once
308        void set_parameters ( shared_ptr<mpdf> par0, shared_ptr<mpdf> obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) {
309                pf->set_model ( par0, obs0); 
310                pf->set_parameters(n0, rm );
311                BMs.set_length ( n0 );
312        }
313        //! set a prototype of BM, copy it to as many times as there is particles in pf
314        void set_BM ( const BM &BMcond0 ) {
315
316                int n=pf->__w().length();
317                BMs.set_length(n);
318                // copy
319                //BMcond0 .condition ( pf->posterior()._sample ( 0 ) );
320                for ( int i = 0; i < n; i++ ) {
321                        BMs ( i ) = BMcond0._copy_();
322                }
323        };
324
325        void bayes ( const vec &yt, const vec &cond );
326        const epdf& posterior() const {
327                return jest;
328        }
329        //! Extends options understood by BM::set_options by option
330        //! \li logmeans - meaning
331        void set_options ( const string &opt ) {
332                BM::set_options(opt);
333        }
334
335        //!Access function
336        const BM* _BM ( int i ) {
337                return BMs ( i );
338        }
339       
340        /*! configuration structure for basic PF
341        \code
342        BM              = BM_class;           // Bayesian filtr for analytical part of the model
343        parameter_pdf   = mpdf_class;         // transitional pdf for non-parametric part of the model
344        prior           = epdf_class;         // prior probability density
345        --- optional ---
346        n               = 10;                 // number of particles
347        resmethod       = 'systematic', or 'multinomial', or 'stratified'
348                                                                                  // resampling method
349        \endcode
350        */     
351        void from_setting(const Setting &set){
352                shared_ptr<mpdf> par = UI::build<mpdf>(set,"parameter_pdf",UI::compulsory);
353                shared_ptr<mpdf> obs= new mpdf(); // not used!!
354
355                pf = new PF;
356                // prior must be set before BM
357                pf->prior_from_set(set);
358                pf->resmethod_from_set(set);
359                pf->set_model(par,obs);
360                               
361                shared_ptr<BM> BM0 =UI::build<BM>(set,"BM",UI::compulsory);
362                set_BM(*BM0);
363               
364                string opt;
365                if (UI::get(opt,set,"options",UI::optional)){
366                        set_options(opt);
367                }
368                //set drv
369                //find potential input - what remains in rvc when we subtract rv
370                RV u = par->_rvc().remove_time().subt( par->_rv() );           
371                set_yrv(concat(BM0->_yrv(),u) );
372                validate();
373        }
374        void validate(){
375                try{
376                pf->validate();
377                } catch (std::exception &e){
378                        throw UIException("Error in PF part of MPF:");
379                }
380                jest.read_parameters();
381                this2bm.set_connection(BMs(0)->_yrv(), BMs(0)->_rvc(), yrv, rvc);
382                this2bm.set_connection(pf->_yrv(), pf->_rvc(), yrv, rvc);
383        }
384
385};
386UIREGISTER(MPF);
387
388}
389#endif // KF_H
390
Note: See TracBrowser for help on using the browser.