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

Revision 675, 11.0 kB (checked in by mido, 15 years ago)

experiment: epdf as a descendat of mpdf

  • 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        //! Log all samples
54        bool opt_L_smp;
55        //! Log all samples
56        bool opt_L_wei;
57        //!@}
58
59public:
60        //! \name Constructors
61        //!@{
62        PF ( ) : est(), _w ( est._w() ), _samples ( est._samples() ), opt_L_smp ( false ), opt_L_wei ( false ) {
63                LIDs.set_size ( 5 );
64        };
65       
66        void set_parameters (int n0, double res_th0=0.5, RESAMPLING_METHOD rm = SYSTEMATIC ) {
67                n = n0;
68                res_threshold = res_th0;
69                resmethod = rm;
70        };
71        void set_model ( shared_ptr<mpdf> par0, shared_ptr<mpdf> obs0) {
72                par = par0;
73                obs = obs0;
74                // set values for posterior
75                est.set_rv(par->_rv());
76        };
77        void set_statistics ( const vec w0, const epdf &epdf0 ) {
78                est.set_statistics ( w0, epdf0 );
79        };
80        void set_statistics ( const eEmp &epdf0 ) {
81                bdm_assert_debug(epdf0._rv().equal(par->_rv()),"Incompatibel input");
82                est=epdf0;
83        };
84        //!@}
85        //! Set posterior density by sampling from epdf0
86        //! Extends original BM::set_options by two more options:
87        //! \li logweights - meaning that all weightes will be logged
88        //! \li logsamples - all samples will be also logged
89        void set_options ( const string &opt ) {
90                BM::set_options ( opt );
91                opt_L_wei = ( opt.find ( "logweights" ) != string::npos );
92                opt_L_smp = ( opt.find ( "logsamples" ) != string::npos );
93        }
94        //! bayes I - generate samples and add their weights to lls
95        virtual void bayes_gensmp(const vec &ut);
96        //! bayes II - compute weights of the
97        virtual void bayes_weights();
98        //! important part of particle filtering - decide if it is time to perform resampling
99        virtual bool do_resampling(){   
100                double eff = 1.0 / ( _w * _w );
101                return eff < ( res_threshold*n );
102        }
103        void bayes ( const vec &dt );
104        //!access function
105        vec& __w() { return _w; }
106        //!access function
107        vec& _lls() { return lls; }
108        //!access function
109        RESAMPLING_METHOD _resmethod() const { return resmethod; }
110        //! return correctly typed posterior (covariant return)
111        const eEmp& posterior() const {return est;}
112       
113        /*! configuration structure for basic PF
114        \code
115        parameter_pdf   = mpdf_class;         // parameter evolution pdf
116        observation_pdf = mpdf_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<mpdf>(set,"parameter_pdf",UI::compulsory);
128                obs = UI::build<mpdf>(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_drv(concat(obs->_rv(),u) );
142        }
143        //! auxiliary function reading parameter 'resmethod' from configuration file
144        void resmethod_from_set(const Setting &set){
145                string resmeth;
146                if (UI::get(resmeth,set,"resmethod",UI::optional)){
147                        if (resmeth=="systematic") {
148                                resmethod= SYSTEMATIC;
149                        } else  {
150                                if (resmeth=="multinomial"){
151                                        resmethod=MULTINOMIAL;
152                                } else {
153                                        if (resmeth=="stratified"){
154                                                resmethod= STRATIFIED;
155                                        } else {
156                                                bdm_error("Unknown resampling method");
157                                        }
158                                }
159                        }
160                } else {
161                        resmethod=SYSTEMATIC;
162                };
163                if(!UI::get(res_threshold, set, "res_threshold", UI::optional)){
164                        res_threshold=0.5;
165                }
166                validate();
167        }
168        //! load prior information from set and set internal structures accordingly
169        void prior_from_set(const Setting & set){
170                shared_ptr<epdf> pri = UI::build<epdf>(set,"prior",UI::compulsory);
171               
172                eEmp *test_emp=dynamic_cast<eEmp*>(&(*pri));
173                if (test_emp) { // given pdf is sampled
174                        est=*test_emp;
175                } else {
176                        //int n;
177                        if (!UI::get(n,set,"n",UI::optional)){n=10;}
178                        // sample from prior
179                        set_statistics(ones(n)/n, *pri);
180                }
181                n = est._w().length();
182                //validate();
183        }
184       
185        void validate(){
186                n=_w.length();
187                lls=zeros(n);
188                if (par->_rv()._dsize()>0) {
189                        bdm_assert(par->_rv()._dsize()==est.dimension(),"Mismatch of RV and dimension of posterior" );
190                }
191        }
192        //! resample posterior density (from outside - see MPF)
193        void resample(ivec &ind){
194                est.resample(ind,resmethod);
195        }
196        //! access function
197        Array<vec>& __samples(){return _samples;}
198};
199UIREGISTER(PF);
200
201/*!
202\brief Marginalized Particle filter
203
204A composition of particle filter with exact (or almost exact) bayesian models (BMs).
205The Bayesian models provide marginalized predictive density. Internaly this is achieved by virtual class MPFmpdf.
206*/
207
208class MPF : public BM  {
209        protected:
210                //! particle filter on non-linear variable
211        shared_ptr<PF> pf;
212        //! Array of Bayesian models
213        Array<BM*> BMs;
214
215        //! internal class for MPDF providing composition of eEmp with external components
216
217        class mpfepdf : public epdf  {
218                //! pointer to particle filter
219                shared_ptr<PF> &pf;
220                //! pointer to Array of BMs
221                Array<BM*> &BMs;
222        public:
223                //! constructor
224                mpfepdf (shared_ptr<PF> &pf0, Array<BM*> &BMs0): epdf(), pf(pf0), BMs(BMs0) { };
225                //! a variant of set parameters - this time, parameters are read from BMs and pf
226                void read_parameters(){
227                        rv = concat(pf->posterior()._rv(), BMs(0)->posterior()._rv());
228                        dim = pf->posterior().dimension() + BMs(0)->posterior().dimension();
229                        bdm_assert_debug(dim == rv._dsize(), "Wrong name ");
230                }
231                vec mean() const {
232                        const vec &w = pf->posterior()._w();
233                        vec pom = zeros ( BMs(0)->posterior ().dimension() );
234                        //compute mean of BMs
235                        for ( int i = 0; i < w.length(); i++ ) {
236                                pom += BMs ( i )->posterior().mean() * w ( i );
237                        }
238                        return concat ( pf->posterior().mean(), pom );
239                }
240                vec variance() const {
241                        const vec &w = pf->posterior()._w();
242                       
243                        vec pom = zeros ( BMs(0)->posterior ().dimension() );
244                        vec pom2 = zeros ( BMs(0)->posterior ().dimension() );
245                        vec mea;
246                       
247                        for ( int i = 0; i < w.length(); i++ ) {
248                                // save current mean
249                                mea = BMs ( i )->posterior().mean();
250                                pom += mea * w ( i );
251                                //compute variance
252                                pom2 += ( BMs ( i )->posterior().variance() + pow ( mea, 2 ) ) * w ( i );
253                        }
254                        return concat ( pf->posterior().variance(), pom2 - pow ( pom, 2 ) );
255                }
256               
257                void qbounds ( vec &lb, vec &ub, double perc = 0.95 ) const {
258                        //bounds on particles
259                        vec lbp;
260                        vec ubp;
261                        pf->posterior().qbounds ( lbp, ubp );
262
263                        //bounds on Components
264                        int dimC = BMs ( 0 )->posterior().dimension();
265                        int j;
266                        // temporary
267                        vec lbc ( dimC );
268                        vec ubc ( dimC );
269                        // minima and maxima
270                        vec Lbc ( dimC );
271                        vec Ubc ( dimC );
272                        Lbc = std::numeric_limits<double>::infinity();
273                        Ubc = -std::numeric_limits<double>::infinity();
274
275                        for ( int i = 0; i < BMs.length(); i++ ) {
276                                // check Coms
277                                BMs ( i )->posterior().qbounds ( lbc, ubc );
278                                //save either minima or maxima
279                                for ( j = 0; j < dimC; j++ ) {
280                                        if ( lbc ( j ) < Lbc ( j ) ) {
281                                                Lbc ( j ) = lbc ( j );
282                                        }
283                                        if ( ubc ( j ) > Ubc ( j ) ) {
284                                                Ubc ( j ) = ubc ( j );
285                                        }
286                                }
287                        }
288                        lb = concat ( lbp, Lbc );
289                        ub = concat ( ubp, Ubc );
290                }
291
292                vec sample() const {
293                        bdm_error ( "Not implemented" );
294                        return vec();
295                }
296
297                double evallog ( const vec &val ) const {
298                        bdm_error ( "not implemented" );
299                        return 0.0;
300                }
301        };
302
303        //! Density joining PF.est with conditional parts
304        mpfepdf jest;
305
306        //! Log means of BMs
307        bool opt_L_mea;
308
309public:
310        //! Default constructor.
311        MPF () :  jest (pf,BMs) {};
312        //! set all parameters at once
313        void set_parameters ( shared_ptr<mpdf> par0, shared_ptr<mpdf> obs0, int n0, RESAMPLING_METHOD rm = SYSTEMATIC ) {
314                pf->set_model ( par0, obs0); 
315                pf->set_parameters(n0, rm );
316                BMs.set_length ( n0 );
317        }
318        //! set a prototype of BM, copy it to as many times as there is particles in pf
319        void set_BM ( const BM &BMcond0 ) {
320
321                int n=pf->__w().length();
322                BMs.set_length(n);
323                // copy
324                //BMcond0 .condition ( pf->posterior()._sample ( 0 ) );
325                for ( int i = 0; i < n; i++ ) {
326                        BMs ( i ) = BMcond0._copy_();
327                }
328        };
329
330        void bayes ( const vec &dt );
331        const epdf& posterior() const {
332                return jest;
333        }
334        //! Extends options understood by BM::set_options by option
335        //! \li logmeans - meaning
336        void set_options ( const string &opt ) {
337                BM::set_options(opt);
338                opt_L_mea = ( opt.find ( "logmeans" ) != string::npos );
339        }
340
341        //!Access function
342        const BM* _BM ( int i ) {
343                return BMs ( i );
344        }
345       
346        /*! configuration structure for basic PF
347        \code
348        BM              = BM_class;           // Bayesian filtr for analytical part of the model
349        parameter_pdf   = mpdf_class;         // transitional pdf for non-parametric part of the model
350        prior           = epdf_class;         // prior probability density
351        --- optional ---
352        n               = 10;                 // number of particles
353        resmethod       = 'systematic', or 'multinomial', or 'stratified'
354                                                                                  // resampling method
355        \endcode
356        */     
357        void from_setting(const Setting &set){
358                shared_ptr<mpdf> par = UI::build<mpdf>(set,"parameter_pdf",UI::compulsory);
359                shared_ptr<mpdf> obs= new mpdf(); // not used!!
360
361                pf = new PF;
362                // rpior must be set before BM
363                pf->prior_from_set(set);
364                pf->resmethod_from_set(set);
365                pf->set_model(par,obs);
366               
367                shared_ptr<BM> BM0 =UI::build<BM>(set,"BM",UI::compulsory);
368                set_BM(*BM0);
369               
370                string opt;
371                if (UI::get(opt,set,"options",UI::optional)){
372                        set_options(opt);
373                }
374                //set drv
375                //find potential input - what remains in rvc when we subtract rv
376                RV u = par->_rvc().remove_time().subt( par->_rv() );           
377                set_drv(concat(BM0->_drv(),u) );
378                validate();
379        }
380        void validate(){
381                try{
382                pf->validate();
383                } catch (std::exception &e){
384                        throw UIException("Error in PF part of MPF:");
385                }
386                jest.read_parameters();
387                for ( int i = 0; i < pf->__w().length(); i++ ) {
388                        BMs ( i )->condition ( pf->posterior()._sample ( i ) );
389                }
390        }
391
392};
393UIREGISTER(MPF);
394
395}
396#endif // KF_H
397
Note: See TracBrowser for help on using the browser.