pf
bootstrap_filter_with_covariates.h
Go to the documentation of this file.
1 #ifndef BOOTSTRAP_FILTER_WC_H
2 #define BOOTSTRAP_FILTER_WC_H
3 
4 #include <iostream>
5 #include <array>
6 #include <vector>
7 
8 #ifdef DROPPINGTHISINRPACKAGE
9  #include <RcppEigen.h>
10  // [[Rcpp::depends(RcppEigen)]]
11 #else
12  #include <Eigen/Dense>
13 #endif
14 
15 #include <iostream>
16 
17 #include "pf_base.h"
18 
19 
20 namespace pf {
21 
22 namespace filters {
23 
25 
36 template<size_t nparts, size_t dimx, size_t dimy, size_t dimcov, typename resamp_t, typename float_t, bool debug=false>
37 class BSFilterWC : public bases::pf_withcov_base<float_t, dimy, dimx, dimcov>
38 {
39 private:
40 
42  using ssv = Eigen::Matrix<float_t, dimx, 1>;
44  using osv = Eigen::Matrix<float_t, dimy, 1>; // obs size vec
46  using cvsv = Eigen::Matrix<float_t,dimcov,1>;
48  using Mat = Eigen::Matrix<float_t,Eigen::Dynamic,Eigen::Dynamic>;
50  using arrayStates = std::array<ssv, nparts>;
52  using arrayfloat_t = std::array<float_t, nparts>;
53 
54 public:
59  BSFilterWC(const unsigned int &rs = 1);
60 
61 
65  virtual ~BSFilterWC();
66 
67 
72  float_t getLogCondLike() const;
73 
74 
82  void filter(const osv &ydata,
83  const cvsv &covdata,
84  const std::vector<std::function<const Mat(const ssv&, const cvsv&)>>& fs = std::vector<std::function<const Mat(const ssv&, const cvsv&)>>());
85 
86 
91  auto getExpectations () const -> std::vector<Mat>;
92 
93 
100  virtual float_t logMuEv (const ssv &x1, const cvsv &z1) = 0;
101 
102 
109  virtual ssv q1Samp (const osv &y1, const cvsv &z1) = 0;
110 
111 
119  virtual float_t logQ1Ev (const ssv &x1, const osv &y1, const cvsv &z1) = 0;
120 
121 
129  virtual float_t logGEv (const osv &yt, const ssv &xt, const cvsv &zt) = 0;
130 
131 
133 
139  virtual ssv fSamp (const ssv &xtm1, const cvsv &zt) = 0;
140 
141 protected:
144 
147 
149  unsigned int m_now;
150 
153 
155  resamp_t m_resampler;
156 
158  std::vector<Mat> m_expectations;
159 
161  unsigned int m_resampSched;
162 };
163 
164 
165 
169 
170 template<size_t nparts, size_t dimx, size_t dimy, size_t dimcov, typename resamp_t, typename float_t,bool debug>
171 BSFilterWC<nparts, dimx, dimy, dimcov, resamp_t, float_t, debug>::BSFilterWC(const unsigned int &rs)
172  : m_now(0)
173  , m_logLastCondLike(0.0)
174  , m_resampSched(rs)
175 
176 {
177  std::fill(m_logUnNormWeights.begin(), m_logUnNormWeights.end(), 0.0); // log(1) = 0
178 }
179 
180 
181 template<size_t nparts, size_t dimx, size_t dimy, size_t dimcov, typename resamp_t, typename float_t, bool debug>
183 
184 
185 template<size_t nparts, size_t dimx, size_t dimy, size_t dimcov, typename resamp_t, typename float_t, bool debug>
186 void BSFilterWC<nparts, dimx, dimy, dimcov, resamp_t, float_t,debug>::filter(const osv &dat, const cvsv &covData, const std::vector<std::function<const Mat(const ssv&, const cvsv&)> >& fs)
187 {
188  if( m_now > 0)
189  {
190 
191  // try to iterate over particles all at once
192  ssv newSamp;
193  float_t maxOldLogUnNormWts(-std::numeric_limits<float_t>::infinity());
194  arrayfloat_t oldLogUnNormWts = m_logUnNormWeights;
195  for(size_t ii = 0; ii < nparts; ++ii)
196  {
197  // update max of old logUnNormWts
198  if (m_logUnNormWeights[ii] > maxOldLogUnNormWts)
199  maxOldLogUnNormWts = m_logUnNormWeights[ii];
200 
201  // sample and get weight adjustments
202  newSamp = fSamp(m_particles[ii], covData);
203  m_logUnNormWeights[ii] += logGEv(dat, newSamp, covData);
204 
205  // overwrite stuff
206  m_particles[ii] = newSamp;
207 
208  #ifndef DROPPINGTHISINRPACKAGE
209  if constexpr(debug)
210  std::cout << "time: " << m_now << ", transposed sample: " << m_particles[ii].transose() << ", log unnorm weight: " << m_logUnNormWeights[ii] << "\n";
211  }
212  #endif
213 
214  // compute estimate of log p(y_t|y_{1:t-1}) with log-exp-sum trick
215  float_t maxNumer = *std::max_element(m_logUnNormWeights.begin(), m_logUnNormWeights.end()); //because you added log adjustments
216  float_t sumExp1(0.0);
217  float_t sumExp2(0.0);
218  for(size_t i = 0; i < nparts; ++i){
219  sumExp1 += std::exp(m_logUnNormWeights[i] - maxNumer);
220  sumExp2 += std::exp(oldLogUnNormWts[i] - maxOldLogUnNormWts); //1
221  }
222  m_logLastCondLike = maxNumer + std::log(sumExp1) - maxOldLogUnNormWts - std::log(sumExp2);
223 
224  // calculate expectations before you resample
225  int fId(0);
226  for(auto & h : fs){ // iterate over all functions
227 
228  Mat testOutput = h(m_particles[0], covData);
229  unsigned int rows = testOutput.rows();
230  unsigned int cols = testOutput.cols();
231  Mat numer = Mat::Zero(rows,cols);
232  float_t weightNormConst (0.0);
233  for(size_t prtcl = 0; prtcl < nparts; ++prtcl){ // iterate over all particles
234  numer += h(m_particles[prtcl],covData) * std::exp(m_logUnNormWeights[prtcl] - maxNumer);
235  weightNormConst += std::exp(m_logUnNormWeights[prtcl] - maxNumer);
236  }
237  m_expectations[fId] = numer/weightNormConst;
238 
239  #ifndef DROPPINGTHISINRPACKAGE
240  if constexpr(debug)
241  std::cout << "transposed expectation " << fId << ": " << m_expectations[fId].transpose() << "\n";
242  #endif
243 
244  fId++;
245  }
246 
247  // resample if you should
248  if ( (m_now+1) % m_resampSched == 0)
250 
251  // advance time
252  m_now += 1;
253  }
254  else // m_now == 0
255  {
256  // only need to iterate over particles once
257  for(size_t ii = 0; ii < nparts; ++ii)
258  {
259  // sample particles
260  m_particles[ii] = q1Samp(dat, covData);
261  m_logUnNormWeights[ii] = logMuEv(m_particles[ii], covData);
262  m_logUnNormWeights[ii] += logGEv(dat, m_particles[ii], covData);
263  m_logUnNormWeights[ii] -= logQ1Ev(m_particles[ii], dat, covData);
264 
265  #ifndef DROPPINGTHISINRPACKAGE
266  if constexpr(debug)
267  std::cout << "time: " << m_now << ", transposed sample: " << m_particles[ii].transpose() << ", log unnorm weight: " << m_logUnNormWeights[ii] << "\n";
268  #endif
269 
270  }
271 
272  // calculate log cond likelihood with log-exp-sum trick
273  float_t max = *std::max_element(m_logUnNormWeights.begin(), m_logUnNormWeights.end());
274  float_t sumExp(0.0);
275  for(size_t i = 0; i < nparts; ++i){
276  sumExp += std::exp(m_logUnNormWeights[i] - max);
277  }
278  m_logLastCondLike = -std::log(nparts) + max + std::log(sumExp);
279 
280  // calculate expectations before you resample
281  // paying mind to underflow
282  m_expectations.resize(fs.size());
283  unsigned int fId(0);
284  for(auto & h : fs){
285 
286  Mat testOutput = h(m_particles[0], covData);
287  unsigned int rows = testOutput.rows();
288  unsigned int cols = testOutput.cols();
289  Mat numer = Mat::Zero(rows,cols);
290  float_t weightNormConst (0.0);
291  for(size_t prtcl = 0; prtcl < nparts; ++prtcl){ // iterate over all particles
292  numer += h(m_particles[prtcl],covData) * std::exp( m_logUnNormWeights[prtcl] - max);
293  weightNormConst += std::exp( m_logUnNormWeights[prtcl] - max );
294  }
295  m_expectations[fId] = numer/weightNormConst;
296  fId++;
297  }
298 
299  // resample if you should
300  if ( (m_now+1) % m_resampSched == 0){
302  }
303 
304  // advance time step
305  m_now += 1;
306  }
307 }
308 
309 
310 template<size_t nparts, size_t dimx, size_t dimy, size_t dimcov, typename resamp_t, typename float_t, bool debug>
312 {
313  return m_logLastCondLike;
314 }
315 
316 
317 template<size_t nparts, size_t dimx, size_t dimy, size_t dimcov, typename resamp_t, typename float_t, bool debug>
319 {
320  return m_expectations;
321 }
322 
323 } // namespace filters
324 } // namespace pf
325 
326 #endif // BOOTSTRAP_FILTER_WC_H
pf::filters::BSFilterWC::logMuEv
virtual float_t logMuEv(const ssv &x1, const cvsv &z1)=0
Calculate muEv or logmuEv.
pf::filters::BSFilterWC::logQ1Ev
virtual float_t logQ1Ev(const ssv &x1, const osv &y1, const cvsv &z1)=0
Calculate q1Ev or log q1Ev.
pf::filters::BSFilterWC::arrayfloat_t
std::array< float_t, nparts > arrayfloat_t
Definition: bootstrap_filter_with_covariates.h:52
pf::filters::BSFilterWC::cvsv
Eigen::Matrix< float_t, dimcov, 1 > cvsv
Definition: bootstrap_filter_with_covariates.h:46
pf::filters::BSFilterWC::Mat
Eigen::Matrix< float_t, Eigen::Dynamic, Eigen::Dynamic > Mat
Definition: bootstrap_filter_with_covariates.h:48
pf::filters::BSFilterWC::filter
void filter(const osv &ydata, const cvsv &covdata, const std::vector< std::function< const Mat(const ssv &, const cvsv &)>> &fs=std::vector< std::function< const Mat(const ssv &, const cvsv &)>>())
updates filtering distribution on a new datapoint. Optionally stores expectations of functionals.
Definition: bootstrap_filter_with_covariates.h:186
pf::filters::BSFilterWC::BSFilterWC
BSFilterWC(const unsigned int &rs=1)
The constructor.
Definition: bootstrap_filter_with_covariates.h:171
pf::filters::BSFilterWC::m_now
unsigned int m_now
time point
Definition: bootstrap_filter_with_covariates.h:149
pf_base.h
All non Rao-Blackwellized particle filters without covariates inherit from this.
pf::filters::BSFilterWC::m_logUnNormWeights
arrayfloat_t m_logUnNormWeights
particle unnormalized weights
Definition: bootstrap_filter_with_covariates.h:146
pf::filters::BSFilterWC::fSamp
virtual ssv fSamp(const ssv &xtm1, const cvsv &zt)=0
Sample from the state transition distribution.
pf::filters::BSFilterWC::q1Samp
virtual ssv q1Samp(const osv &y1, const cvsv &z1)=0
Samples from time 1 proposal.
pf::filters::BSFilterWC::logGEv
virtual float_t logGEv(const osv &yt, const ssv &xt, const cvsv &zt)=0
Calculate gEv or logGEv.
pf::filters::BSFilterWC::getExpectations
auto getExpectations() const -> std::vector< Mat >
return all stored expectations (taken with respect to $p(x_t|y_{1:t})$
Definition: bootstrap_filter_with_covariates.h:318
pf::filters::BSFilterWC::m_resampler
resamp_t m_resampler
resampler object
Definition: bootstrap_filter_with_covariates.h:155
pf::filters::BSFilterWC::arrayStates
std::array< ssv, nparts > arrayStates
Definition: bootstrap_filter_with_covariates.h:50
pf::filters::BSFilterWC::ssv
Eigen::Matrix< float_t, dimx, 1 > ssv
Definition: bootstrap_filter_with_covariates.h:42
pf::filters::BSFilterWC::getLogCondLike
float_t getLogCondLike() const
Returns the most recent (log-) conditiona likelihood.
Definition: bootstrap_filter_with_covariates.h:311
pf::filters::BSFilterWC::m_expectations
std::vector< Mat > m_expectations
expectations E[h(x_t) | y_{1:t}] for user defined "h"s
Definition: bootstrap_filter_with_covariates.h:158
pf::filters::BSFilterWC
A base class for the bootstrap particle filter with covariates.
Definition: bootstrap_filter_with_covariates.h:37
pf::filters::BSFilterWC::osv
Eigen::Matrix< float_t, dimy, 1 > osv
Definition: bootstrap_filter_with_covariates.h:44
pf::filters::BSFilterWC::m_resampSched
unsigned int m_resampSched
resampling schedule (e.g. resample every __ time points)
Definition: bootstrap_filter_with_covariates.h:161
pf::bases::pf_withcov_base
Definition: pf_base.h:98
pf::filters::BSFilterWC::~BSFilterWC
virtual ~BSFilterWC()
The (virtual) destructor.
Definition: bootstrap_filter_with_covariates.h:182
pf::filters::BSFilterWC::m_particles
arrayStates m_particles
particle samples
Definition: bootstrap_filter_with_covariates.h:143
pf::filters::BSFilterWC::m_logLastCondLike
float_t m_logLastCondLike
log p(y_t|y_{1:t-1}) or log p(y1)
Definition: bootstrap_filter_with_covariates.h:152