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

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

Major changes in BM -- OK is only test suite and tests/tutorial -- the rest is broken!!!

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