/*! \file \brief Bayesian Filtering using stochastic sampling (Particle Filters) \author Vaclav Smidl. ----------------------------------- BDM++ - C++ library for Bayesian Decision Making under Uncertainty Using IT++ for numerical operations ----------------------------------- */ #ifndef PARTICLES_H #define PARTICLES_H #include "../estim/arx_ext.h" #include "../stat/emix.h" namespace bdm { //! \brief Abstract class for Marginalized Particles class MarginalizedParticleBase : public BM { protected: //! discrte particle dirac est_emp; //! internal Bayes Model shared_ptr bm; //! \brief Internal class for custom posterior - product of empirical and exact part class eprod_2:public eprod_base { protected: MarginalizedParticleBase ∓ public: eprod_2(MarginalizedParticleBase &m):mp(m) {} const epdf* factor(int i) const { return (i==0) ? &mp.bm->posterior() : &mp.est_emp; } const int no_factors() const { return 2; } } est; public: MarginalizedParticleBase():est(*this) {}; MarginalizedParticleBase(const MarginalizedParticleBase &m2):BM(m2),est(*this) { bm = m2.bm->_copy(); est_emp = m2.est_emp; est.validate(); validate(); }; void bayes(const vec &dt, const vec &cond) NOT_IMPLEMENTED_VOID; const eprod_2& posterior() const { return est; } void set_prior(const epdf *pdf0) { const eprod *ep=dynamic_cast(pdf0); if (ep) { // full prior bdm_assert(ep->no_factors()==2,"Incompatible prod"); bm->set_prior(ep->factor(0)); est_emp.set_point(ep->factor(1)->sample()); } else { // assume prior is only for emp; est_emp.set_point(pdf0->sample()); } } /*! Create object from the following structure \code class = "MarginalizedParticleBase"; bm = configuration of bdm::BM; % any offspring of BM, bdm::BM::from_setting --- inherited fields --- bdm::BM::from_setting \endcode */ void from_setting(const Setting &set) { BM::from_setting ( set ); bm = UI::build ( set, "bm", UI::compulsory ); } void validate() { BM::validate(); //est.validate(); --pdfs not known bdm_assert(bm,"Internal BM is not given"); } }; //! \brief Particle with marginalized subspace, used in PF class MarginalizedParticle : public MarginalizedParticleBase { protected: //! pdf with for transitional par shared_ptr par; // pdf for non-linear part //! link from this to bm shared_ptr cond2bm; //! link from cond to par shared_ptr cond2par; //! link from emp 2 par shared_ptr emp2bm; //! link from emp 2 par shared_ptr emp2par; public: BM* _copy() const { return new MarginalizedParticle(*this); }; void bayes(const vec &dt, const vec &cond) { vec par_cond(par->dimensionc()); cond2par->filldown(cond,par_cond); // copy ut emp2par->filldown(est_emp._point(),par_cond); // copy xt-1 //sample new particle est_emp.set_point(par->samplecond(par_cond)); //if (evalll) vec bm_cond(bm->dimensionc()); cond2bm->filldown(cond, bm_cond);// set e.g. ut emp2bm->filldown(est_emp._point(), bm_cond);// set e.g. ut bm->bayes(dt, bm_cond); ll=bm->_ll(); } /*! Create object from the following structure \code class = "MarginalizedParticle"; parameter_pdf = configuration of bdm::epdf; % any offspring of epdf, bdm::epdf::from_setting --- inherited fields --- bdm::MarginalizedParticleBase::from_setting \endcode */ void from_setting(const Setting &set) { MarginalizedParticleBase::from_setting ( set ); par = UI::build ( set, "parameter_pdf", UI::compulsory ); } void to_setting(Setting &set)const { MarginalizedParticleBase::to_setting(set); UI::save(par,set,"parameter_pdf"); UI::save(bm,set,"bm"); } void validate() { MarginalizedParticleBase::validate(); est_emp.set_rv(par->_rv()); if (est_emp.point.length()!=par->dimension()) est_emp.set_point(zeros(par->dimension())); est.validate(); yrv = bm->_yrv(); dimy = bm->dimensiony(); set_rv( concat(bm->_rv(), par->_rv())); set_dim( par->dimension()+bm->dimension()); rvc = par->_rvc(); rvc.add(bm->_rvc()); rvc=rvc.subt(par->_rv()); rvc=rvc.subt(par->_rv().copy_t(-1)); rvc=rvc.subt(bm->_rv().copy_t(-1)); // cond2bm=new datalink_part; cond2par=new datalink_part; emp2bm =new datalink_part; emp2par =new datalink_part; cond2bm->set_connection(bm->_rvc(), rvc); cond2par->set_connection(par->_rvc(), rvc); emp2bm->set_connection(bm->_rvc(), par->_rv()); emp2par->set_connection(par->_rvc(), par->_rv().copy_t(-1)); dimc = rvc._dsize(); }; }; UIREGISTER(MarginalizedParticle); //! Internal class which is used in PF class BootstrapParticle : public BM { dirac est; shared_ptr par; shared_ptr obs; shared_ptr cond2par; shared_ptr cond2obs; shared_ptr xt2obs; shared_ptr xtm2par; public: BM* _copy() const { return new BootstrapParticle(*this); }; void bayes(const vec &dt, const vec &cond) { vec par_cond(par->dimensionc()); cond2par->filldown(cond,par_cond); // copy ut xtm2par->filldown(est._point(),par_cond); // copy xt-1 //sample new particle est.set_point(par->samplecond(par_cond)); //if (evalll) vec obs_cond(obs->dimensionc()); cond2obs->filldown(cond, obs_cond);// set e.g. ut xt2obs->filldown(est._point(), obs_cond);// set e.g. ut ll=obs->evallogcond(dt,obs_cond); } const dirac& posterior() const { return est; } void set_prior(const epdf *pdf0) { est.set_point(pdf0->sample()); } /*! Create object from the following structure \code class = "BootstrapParticle"; parameter_pdf = configuration of bdm::epdf; % any offspring of epdf, bdm::epdf::from_setting observation_pdf = configuration of bdm::epdf; % any offspring of epdf, bdm::epdf::from_setting --- inherited fields --- bdm::BM::from_setting \endcode */ void from_setting(const Setting &set) { BM::from_setting ( set ); par = UI::build ( set, "parameter_pdf", UI::compulsory ); obs = UI::build ( set, "observation_pdf", UI::compulsory ); } void validate() { yrv = obs->_rv(); dimy = obs->dimension(); set_rv( par->_rv()); set_dim( par->dimension()); rvc = par->_rvc().subt(par->_rv().copy_t(-1)); rvc.add(obs->_rvc()); // cond2obs=new datalink_part; cond2par=new datalink_part; xt2obs =new datalink_part; xtm2par =new datalink_part; cond2obs->set_connection(obs->_rvc(), rvc); cond2par->set_connection(par->_rvc(), rvc); xt2obs->set_connection(obs->_rvc(), _rv()); xtm2par->set_connection(par->_rvc(), _rv().copy_t(-1)); dimc = rvc._dsize(); }; }; UIREGISTER(BootstrapParticle); /*! * \brief Trivial particle filter with proposal density equal to parameter evolution model. Posterior density is represented by a weighted empirical density (\c eEmp ). */ class PF : public BM { //! \var log_level_enums logweights //! all weightes will be logged //! \var log_level_enums logmeans //! means of particles will be logged LOG_LEVEL(PF,logweights,logmeans,logvars,logNeff); class pf_mix: public emix_base { Array &bms; public: pf_mix(vec &w0, Array &bms0):emix_base(w0),bms(bms0) {} const epdf* component(const int &i)const { return &(bms(i)->posterior()); } int no_coms() const { return bms.length(); } }; protected: //!number of particles; int n; //!posterior density pf_mix est; //! weights; vec w; //! particles Array particles; //! internal structure storing loglikelihood of predictions vec lls; //! which resampling method will be used RESAMPLING_METHOD resmethod; //! resampling threshold; in this case its meaning is minimum ratio of active particles //! For example, for 0.5 resampling is performed when the numebr of active aprticles drops belo 50%. double res_threshold; //! \name Options //!@{ //!@} public: //! \name Constructors //!@{ PF ( ) : est(w,particles) { }; void set_parameters ( int n0, double res_th0 = 0.5, RESAMPLING_METHOD rm = SYSTEMATIC ) { n = n0; res_threshold = res_th0; resmethod = rm; }; void set_model ( const BM *particle0, const epdf *prior) { if (n>0) { particles.set_length(n); for (int i=0; i_copy(); particles(i)->set_prior(prior); } } // set values for posterior est.set_rv ( particle0->posterior()._rv() ); }; void set_statistics ( const vec w0, const epdf &epdf0 ) { //est.set_statistics ( w0, epdf0 ); }; /* void set_statistics ( const eEmp &epdf0 ) { bdm_assert_debug ( epdf0._rv().equal ( par->_rv() ), "Incompatible input" ); est = epdf0; };*/ //!@} //! bayes compute weights of the virtual void bayes_weights(); //! important part of particle filtering - decide if it is time to perform resampling virtual bool do_resampling() { double eff = 1.0 / ( w * w ); return eff < ( res_threshold*n ); } void bayes ( const vec &yt, const vec &cond ); //!access function vec& _lls() { return lls; } //!access function RESAMPLING_METHOD _resmethod() const { return resmethod; } //! return correctly typed posterior (covariant return) const pf_mix& posterior() const { return est; } /*! configuration structure for basic PF \code particle = bdm::BootstrapParticle; % one bayes rule for each point in the empirical support - or - = bdm::MarginalizedParticle; % (in case of Marginalized Particle filtering prior = epdf_class; % prior probability density on the empirical variable --- optional --- n = 10; % number of particles resmethod = 'systematic', or 'multinomial', or 'stratified' % resampling method res_threshold = 0.5; % resample when active particles drop below 50% \endcode */ void from_setting ( const Setting &set ) { BM::from_setting ( set ); UI::get ( log_level, set, "log_level", UI::optional ); shared_ptr bm0 = UI::build(set, "particle",UI::compulsory); n =0; UI::get(n,set,"n",UI::optional);; if (n>0) { particles.set_length(n); for(int i=0; i_copy(); } w = ones(n)/n; } shared_ptr pri = UI::build(set,"prior"); set_prior(pri.get()); // set resampling method resmethod_from_set ( set ); //set drv rvc = bm0->_rvc(); dimc = bm0->dimensionc(); BM::set_rv(bm0->_rv()); yrv=bm0->_yrv(); dimy = bm0->dimensiony(); } void to_setting(Setting &set) const{ BM::to_setting(set); UI::save(particles, set,"particles"); UI::save(w,set,"w"); } void log_register ( bdm::logger& L, const string& prefix ) { BM::log_register(L,prefix); if (log_level[logweights]) { L.add_vector( log_level, logweights, RV ( particles.length()), prefix); } if (log_level[logNeff]) { L.add_vector( log_level, logNeff, RV ( 1), prefix); } if (log_level[logmeans]) { for (int i=0; idimension() ), prefix , i); } } if (log_level[logvars]) { for (int i=0; idimension() ), prefix , i); } } }; void log_write ( ) const { BM::log_write(); // weigths are before resamplign -- bayes if (log_level[logmeans]) { for (int i=0; iposterior().mean(), i); } } if (log_level[logvars]) { for (int i=0; iposterior().variance(), i); } } } void set_prior(const epdf *pri) { const emix_base *emi=dynamic_cast(pri); if (emi) { bdm_assert(particles.length()>0, "initial particle is not assigned"); n = emi->_w().length(); int old_n = particles.length(); if (n!=old_n) { particles.set_length(n,true); } for(int i=old_n; i_copy(); } for (int i =0; iset_prior(emi->_com(i)); } } else { // try to find "n" bdm_assert(n>0, "Field 'n' must be filled when prior is not of type emix"); for (int i =0; iset_prior(pri); } } } //! auxiliary function reading parameter 'resmethod' from configuration file void resmethod_from_set ( const Setting &set ) { string resmeth; if ( UI::get ( resmeth, set, "resmethod", UI::optional ) ) { if ( resmeth == "systematic" ) { resmethod = SYSTEMATIC; } else { if ( resmeth == "multinomial" ) { resmethod = MULTINOMIAL; } else { if ( resmeth == "stratified" ) { resmethod = STRATIFIED; } else { bdm_error ( "Unknown resampling method" ); } } } } else { resmethod = SYSTEMATIC; }; if ( !UI::get ( res_threshold, set, "res_threshold", UI::optional ) ) { res_threshold = 0.9; } //validate(); } void validate() { BM::validate(); est.validate(); bdm_assert ( n>0, "empty particle pool" ); n = w.length(); lls = zeros ( n ); if ( particles(0)->_rv()._dsize() > 0 ) { bdm_assert ( particles(0)->_rv()._dsize() == est.dimension(), "MPF:: Mismatch of RV " +particles(0)->_rv().to_string() + " of size (" +num2str(particles(0)->_rv()._dsize())+") and dimension of posterior ("+num2str(est.dimension()) + ")" ); } } //! resample posterior density (from outside - see MPF) void resample ( ) { ivec ind = zeros_i ( n ); bdm::resample(w,ind,resmethod); // copy the internals according to ind for (int i = 0; i < n; i++ ) { if ( ind ( i ) != i ) { delete particles(i); particles( i ) = particles( ind ( i ) )->_copy(); } w ( i ) = 1.0 / n; } } //! access function Array& _particles() { return particles; } ~PF() { for (int i=0; i x_t+1 shared_ptr g; // pdf for non-linear part //! function transforming xt,ut -> yt shared_ptr fy; // pdf for non-linear part RV rvx; RV rvxc; RV rvyc; //!link from condition to f datalink_part cond2g; //!link from condition to h datalink_part cond2fy; //!link from xt to f datalink_part x2g; //!link from xt to h datalink_part x2fy; public: BM* _copy() const { return new NoiseParticleX(*this); }; void bayes(const vec &dt, const vec &cond) { //shared_ptr pred_v=bm->epredictor(); vec xt; vec xthat; //vec vt=pred_v->sample(); // vec vt = bm->samplepred(); if (1){ //vec vt=pred_v->sample(); int dim_x = bm->dimensiony(); int dim_y = dimensiony(); vec post_mean =bm->posterior().mean(); mat SigV; if (post_mean.length()==dim_x){ SigV=diag(vec(post_mean._data(), dim_x)); } else { SigV=mat(post_mean._data(), dim_x, dim_x); } vec &xtm=est_emp.point; vec g_args(g->dimensionc()); x2g.filldown(xtm,g_args); cond2g.filldown(cond,g_args); xthat = g->eval(g_args); mat IC = eye(dim_x+dim_y); IC.set_submatrix(0,0,eye(dim_x)); mat SigJo=eye(dim_x + dim_y); SigJo.set_submatrix(0,0,SigV); mlnorm* mlfy=dynamic_cast* >(fy.get()); SigJo.set_submatrix(dim_x,dim_x, mlfy->_R()); IC.set_submatrix(dim_x,0,-mlfy->_A()); mat iIC=inv(IC); enorm Jo; Jo._mu()=iIC*concat(xthat, zeros(dim_y)); Jo._R()=iIC*SigJo*iIC.T(); Jo.set_rv(concat(bm->_yrv(),yrv)); Jo.validate(); shared_ptr Cond=Jo.condition(bm->_yrv()); //new sample xt = Cond->samplecond(dt);// + vt; } else{ //new sample vec &xtm=est_emp.point; vec g_args(g->dimensionc()); x2g.filldown(xtm,g_args); cond2g.filldown(cond,g_args); xthat = g->eval(g_args); xt = xthat + bm->samplepred(); } est_emp.point=xt; // the vector [v_t] updates bm, bm->bayes(xt-xthat); // residue of observation vec fy_args(fy->dimensionc()); x2fy.filldown(xt,fy_args); cond2fy.filldown(cond,fy_args); ll= fy->evallogcond(dt,fy_args); } void from_setting(const Setting &set) { MarginalizedParticleBase::from_setting(set); //reads bm, yrv,rvc, bm_rv, etc... g=UI::build(set,"g",UI::compulsory); fy=UI::build(set,"fy",UI::compulsory); UI::get(rvx,set,"rvx",UI::compulsory); est_emp.set_rv(rvx); UI::get(rvxc,set,"rvxc",UI::compulsory); UI::get(rvyc,set,"rvyc",UI::compulsory); } void to_setting (Setting &set) const { MarginalizedParticleBase::to_setting(set); //reads bm, yrv,rvc, bm_rv, etc... UI::save(g,set,"g"); UI::save(fy,set,"fy"); UI::save(bm,set,"bm"); } void validate() { MarginalizedParticleBase::validate(); dimy = fy->dimension(); bm->set_yrv(rvx); est_emp.set_rv(rvx); est_emp.set_dim(rvx._dsize()); est.validate(); // //check dimensions rvc = rvxc.subt(rvx.copy_t(-1)); rvc.add( rvyc); rvc=rvc.subt(rvx); bdm_assert(g->dimension()==rvx._dsize(),"rvx is not described"); bdm_assert(g->dimensionc()==rvxc._dsize(),"rvxc is not described"); bdm_assert(fy->dimensionc()==rvyc._dsize(),"rvyc is not described"); bdm_assert(bm->dimensiony()==g->dimension(), "Incompatible noise estimator of dimension " + num2str(bm->dimensiony()) + " does not match dimension of g , " + num2str(g->dimension())); dimc = rvc._dsize(); //establish datalinks x2g.set_connection(rvxc, rvx.copy_t(-1)); cond2g.set_connection(rvxc, rvc); x2fy.set_connection(rvyc, rvx); cond2fy.set_connection(rvyc, rvc); } }; UIREGISTER(NoiseParticleX); /*! Marginalized particle for state-space models with unknown parameters of distribuution of residues on \f$v_t\f$ and \f$ w_t \f$. \f{eqnarray*}{ x_t &=& g(x_{t-1}) + v_t,\\ y_t &= &h(x_t)+w_t, \f} This particle is a only a shell creating the residues calling internal estimator of their parameters. The internal estimator can be of any compatible type, e.g. ARX for Gaussian residues with unknown mean and variance. */ class NoiseParticleXY : public BM { protected: //! discrte particle dirac est_emp; //! internal Bayes Model shared_ptr bmx; shared_ptr bmy; //! \brief Internal class for custom posterior - product of empirical and exact part class eprod_3:public eprod_base { protected: NoiseParticleXY ∓ public: eprod_3(NoiseParticleXY &m):mp(m) {} const epdf* factor(int i) const { if (i==0) return &mp.bmx->posterior() ; if(i==1) return &mp.bmy->posterior(); return &mp.est_emp; } const int no_factors() const { return 3; } } est; protected: //! function transforming xt, ut -> x_t+1 shared_ptr g; // pdf for non-linear part //! function transforming xt,ut -> yt shared_ptr h; // pdf for non-linear part RV rvx; RV rvxc; RV rvyc; //!link from condition to f datalink_part cond2g; //!link from condition to h datalink_part cond2h; //!link from xt to f datalink_part x2g; //!link from xt to h datalink_part x2h; public: NoiseParticleXY():est(*this) {}; NoiseParticleXY(const NoiseParticleXY &m2):BM(m2),est(*this),g(m2.g),h(m2.h), rvx(m2.rvx),rvxc(m2.rvxc),rvyc(m2.rvyc) { bmx = m2.bmx->_copy(); bmy = m2.bmy->_copy(); est_emp = m2.est_emp; //est.validate(); validate(); }; const eprod_3& posterior() const { return est; } void set_prior(const epdf *pdf0) { const eprod *ep=dynamic_cast(pdf0); if (ep) { // full prior bdm_assert(ep->no_factors()==2,"Incompatible prod"); bmx->set_prior(ep->factor(0)); bmy->set_prior(ep->factor(1)); est_emp.set_point(ep->factor(2)->sample()); } else { // assume prior is only for emp; est_emp.set_point(pdf0->sample()); } } BM* _copy() const { return new NoiseParticleXY(*this); }; void bayes(const vec &dt, const vec &cond) { //shared_ptr pred_v=bm->epredictor(); //vec vt=pred_v->sample(); vec vt = bmx->samplepred(); //new sample vec &xtm=est_emp.point; vec g_args(g->dimensionc()); x2g.filldown(xtm,g_args); cond2g.filldown(cond,g_args); vec xt = g->eval(g_args) + vt; est_emp.point=xt; // the vector [v_t] updates bm, bmx->bayes(vt); // residue of observation vec h_args(h->dimensionc()); x2h.filldown(xt,h_args); cond2h.filldown(cond,h_args); vec z_y =h->eval(h_args)-dt; // ARX *abm = dynamic_cast(bmy.get()); /* double ll2; if (abm){ //ARX shared_ptr pr_y(abm->epredictor_student(empty_vec)); ll2=pr_y->evallog(z_y); } else{ shared_ptr pr_y(bmy->epredictor(empty_vec)); ll2=pr_y->evallog(z_y); }*/ bmy->bayes(z_y); // test _lls ll= bmy->_ll(); } void from_setting(const Setting &set) { BM::from_setting(set); //reads bm, yrv,rvc, bm_rv, etc... bmx = UI::build(set,"bmx",UI::compulsory); bmy = UI::build(set,"bmy",UI::compulsory); g=UI::build(set,"g",UI::compulsory); h=UI::build(set,"h",UI::compulsory); UI::get(rvx,set,"rvx",UI::compulsory); est_emp.set_rv(rvx); UI::get(rvxc,set,"rvxc",UI::compulsory); UI::get(rvyc,set,"rvyc",UI::compulsory); } void to_setting (Setting &set) const { BM::to_setting(set); //reads bm, yrv,rvc, bm_rv, etc... UI::save(g,set,"g"); UI::save(h,set,"h"); UI::save(bmx,set,"bmx"); UI::save(bmy,set,"bmy"); } void validate() { BM::validate(); dimy = h->dimension(); // bmx->set_yrv(rvx); // bmy-> est_emp.set_rv(rvx); est_emp.set_dim(rvx._dsize()); est.validate(); // //check dimensions rvc = rvxc.subt(rvx.copy_t(-1)); rvc.add( rvyc); rvc=rvc.subt(rvx); bdm_assert(g->dimension()==rvx._dsize(),"rvx is not described"); bdm_assert(g->dimensionc()==rvxc._dsize(),"rvxc is not described"); bdm_assert(h->dimensionc()==rvyc._dsize(),"rvyc is not described"); bdm_assert(bmx->dimensiony()==g->dimension(), "Incompatible noise estimator of dimension " + num2str(bmx->dimensiony()) + " does not match dimension of g , " + num2str(g->dimension()) ); dimc = rvc._dsize(); //establish datalinks x2g.set_connection(rvxc, rvx.copy_t(-1)); cond2g.set_connection(rvxc, rvc); x2h.set_connection(rvyc, rvx); cond2h.set_connection(rvyc, rvc); } }; UIREGISTER(NoiseParticleXY); class NoiseParticleXYprop: public NoiseParticleXY{ public: BM* _copy() const { return new NoiseParticleXYprop(*this); }; void bayes(const vec &dt, const vec &cond) { int dim_x = bmx->dimensiony(); int dim_y = bmy->dimensiony(); //vec vt=pred_v->sample(); mat SigV=mat(bmx->posterior().mean()._data(), dim_x, dim_x); mat SigW=mat(bmy->posterior().mean()._data(), dim_y, dim_y); vec &xtm=est_emp.point; vec g_args(g->dimensionc()); x2g.filldown(xtm,g_args); cond2g.filldown(cond,g_args); vec xthat = g->eval(g_args); mat IC = eye(dim_x+dim_y); IC.set_submatrix(0,0,eye(dim_x)); mat SigJo=eye(dim_x + dim_y); SigJo.set_submatrix(0,0,SigV); SigJo.set_submatrix(dim_x,dim_x, 10*SigW); diffbifn* hb=dynamic_cast(h.get()); mat C=zeros(dim_y,dim_x); if (hb){ hb->dfdx_cond(xtm, cond, C,true); IC.set_submatrix(dim_x,0,-C); } mat iIC=inv(IC); enorm Jo; Jo._mu()=iIC*concat(xthat, zeros(dim_y)); Jo._R()=iIC*SigJo*iIC.T(); Jo.set_rv(concat(bmx->_yrv(), bmy->_yrv())); Jo.validate(); shared_ptr Cond=Jo.condition(bmx->_yrv()); //new sample vec xt = Cond->samplecond(dt);// + vt; est_emp.point=xt; // the vector [v_t] updates bm, bmx->bayes(xt-xthat); // residue of observation vec h_args(h->dimensionc()); x2h.filldown(xt,h_args); cond2h.filldown(cond,h_args); vec z_y =h->eval(h_args)-dt; // ARX *abm = dynamic_cast(bmy.get()); /* double ll2; i f (abm){ //ARX* shared_ptr pr_y(abm->epredictor_student(empty_vec)); ll2=pr_y->evallog(z_y); } else{ shared_ptr pr_y(bmy->epredictor(empty_vec)); ll2=pr_y->evallog(z_y); }*/ bmy->bayes(z_y); // test _lls ll= bmy->_ll(); } }; UIREGISTER(NoiseParticleXYprop); /*! Marginalized particle for state-space models with unknown parameters of residues distribution \f{eqnarray*}{ x_t &=& g(x_{t-1}) + v_t,\\ z_t &= &h(x_{t-1}) + w_t, \f} This particle is a only a shell creating the residues calling internal estimator of their parameters. The internal estimator can be of any compatible type, e.g. ARX for Gaussian residues with unknown mean and variance. */ class NoiseParticle : public MarginalizedParticleBase { protected: //! function transforming xt, ut -> x_t+1 shared_ptr g; // pdf for non-linear part //! function transforming xt,ut -> yt shared_ptr h; // pdf for non-linear part RV rvx; RV rvxc; RV rvyc; //!link from condition to f datalink_part cond2g; //!link from condition to h datalink_part cond2h; //!link from xt to f datalink_part x2g; //!link from xt to h datalink_part x2h; public: BM* _copy() const { return new NoiseParticle(*this); }; void bayes(const vec &dt, const vec &cond) { shared_ptr pred_vw=bm->epredictor(); shared_ptr pred_v = pred_vw->marginal(rvx); vec vt=pred_v->sample(); //new sample vec &xtm=est_emp.point; vec g_args(g->dimensionc()); x2g.filldown(xtm,g_args); cond2g.filldown(cond,g_args); vec xt = g->eval(g_args) + vt; est_emp.point=xt; // residue of observation vec h_args(h->dimensionc()); x2h.filldown(xt,h_args); cond2h.filldown(cond,h_args); vec wt = dt-h->eval(h_args); // the vector [v_t,w_t] is now complete bm->bayes(concat(vt,wt)); ll=bm->_ll(); } void from_setting(const Setting &set) { MarginalizedParticleBase::from_setting(set); //reads bm, yrv,rvc, bm_rv, etc... UI::get(g,set,"g",UI::compulsory); UI::get(h,set,"h",UI::compulsory); UI::get(rvx,set,"rvx",UI::compulsory); est_emp.set_rv(rvx); UI::get(rvxc,set,"rvxc",UI::compulsory); UI::get(rvyc,set,"rvyc",UI::compulsory); } void validate() { MarginalizedParticleBase::validate(); dimy = h->dimension(); bm->set_yrv(concat(rvx,yrv)); est_emp.set_rv(rvx); est_emp.set_dim(rvx._dsize()); est.validate(); // //check dimensions rvc = rvxc.subt(rvx.copy_t(-1)); rvc.add( rvyc); rvc=rvc.subt(rvx); bdm_assert(g->dimension()==rvx._dsize(),"rvx is not described"); bdm_assert(g->dimensionc()==rvxc._dsize(),"rvxc is not described"); bdm_assert(h->dimension()==rvyc._dsize(),"rvyc is not described"); bdm_assert(bm->dimensiony()==g->dimension()+h->dimension(), "Incompatible noise estimator of dimension " + num2str(bm->dimensiony()) + " does not match dimension of g and h, " + num2str(g->dimension())+" and "+ num2str(h->dimension()) ); dimc = rvc._dsize(); //establish datalinks x2g.set_connection(rvxc, rvx.copy_t(-1)); cond2g.set_connection(rvxc, rvc); x2h.set_connection(rvyc, rvx); cond2h.set_connection(rvyc, rvc); } }; UIREGISTER(NoiseParticle); } #endif // KF_H