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

Revision 676, 10.8 kB (checked in by smidl, 15 years ago)

logger refactoring

  • 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 &dt );
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_drv(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        //! Log means of BMs
299        bool opt_L_mea;
300
301public:
302        //! Default constructor.
303        MPF () :  jest (pf,BMs) {};
304        //! set all parameters at once
305        void set_parameters ( shared_ptr<mpdf> par0, shared_ptr<mpdf> obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) {
306                pf->set_model ( par0, obs0); 
307                pf->set_parameters(n0, rm );
308                BMs.set_length ( n0 );
309        }
310        //! set a prototype of BM, copy it to as many times as there is particles in pf
311        void set_BM ( const BM &BMcond0 ) {
312
313                int n=pf->__w().length();
314                BMs.set_length(n);
315                // copy
316                //BMcond0 .condition ( pf->posterior()._sample ( 0 ) );
317                for ( int i = 0; i < n; i++ ) {
318                        BMs ( i ) = BMcond0._copy_();
319                }
320        };
321
322        void bayes ( const vec &dt );
323        const epdf& posterior() const {
324                return jest;
325        }
326        //! Extends options understood by BM::set_options by option
327        //! \li logmeans - meaning
328        void set_options ( const string &opt ) {
329                BM::set_options(opt);
330                opt_L_mea = ( opt.find ( "logmeans" ) != string::npos );
331        }
332
333        //!Access function
334        const BM* _BM ( int i ) {
335                return BMs ( i );
336        }
337       
338        /*! configuration structure for basic PF
339        \code
340        BM              = BM_class;           // Bayesian filtr for analytical part of the model
341        parameter_pdf   = mpdf_class;         // transitional pdf for non-parametric part of the model
342        prior           = epdf_class;         // prior probability density
343        --- optional ---
344        n               = 10;                 // number of particles
345        resmethod       = 'systematic', or 'multinomial', or 'stratified'
346                                                                                  // resampling method
347        \endcode
348        */     
349        void from_setting(const Setting &set){
350                shared_ptr<mpdf> par = UI::build<mpdf>(set,"parameter_pdf",UI::compulsory);
351                shared_ptr<mpdf> obs= new mpdf(); // not used!!
352
353                pf = new PF;
354                // rpior must be set before BM
355                pf->prior_from_set(set);
356                pf->resmethod_from_set(set);
357                pf->set_model(par,obs);
358               
359                shared_ptr<BM> BM0 =UI::build<BM>(set,"BM",UI::compulsory);
360                set_BM(*BM0);
361               
362                string opt;
363                if (UI::get(opt,set,"options",UI::optional)){
364                        set_options(opt);
365                }
366                //set drv
367                //find potential input - what remains in rvc when we subtract rv
368                RV u = par->_rvc().remove_time().subt( par->_rv() );           
369                set_drv(concat(BM0->_drv(),u) );
370                validate();
371        }
372        void validate(){
373                try{
374                pf->validate();
375                } catch (std::exception &e){
376                        throw UIException("Error in PF part of MPF:");
377                }
378                jest.read_parameters();
379                for ( int i = 0; i < pf->__w().length(); i++ ) {
380                        BMs ( i )->condition ( pf->posterior()._sample ( i ) );
381                }
382        }
383
384};
385UIREGISTER(MPF);
386
387}
388#endif // KF_H
389
Note: See TracBrowser for help on using the browser.