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

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

doc - doxygen warnings

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