Bayes Filters Library
EstimatesExtraction.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2016-2019 Istituto Italiano di Tecnologia (IIT)
3  *
4  * This software may be modified and distributed under the terms of the
5  * BSD 3-Clause license. See the accompanying LICENSE file for details.
6  */
7 
10 #include <BayesFilters/utils.h>
11 
12 using namespace bfl;
13 using namespace Eigen;
14 
15 
16 EstimatesExtraction::EstimatesExtraction(const std::size_t linear_size) noexcept :
17  EstimatesExtraction(linear_size, 0)
18 { }
19 
20 
21 EstimatesExtraction::EstimatesExtraction(const std::size_t linear_size, const std::size_t circular_size) noexcept :
22  hist_buffer_(linear_size + circular_size),
23  linear_size_(linear_size),
24  circular_size_(circular_size),
25  state_size_(linear_size + circular_size)
26 { }
27 
28 
30  extraction_method_(estimate_extraction.extraction_method_),
31  hist_buffer_(std::move(estimate_extraction.hist_buffer_)),
32  sm_weights_(std::move(estimate_extraction.sm_weights_)),
33  wm_weights_(std::move(estimate_extraction.wm_weights_)),
34  em_weights_(std::move(estimate_extraction.em_weights_)),
35  linear_size_(estimate_extraction.linear_size_),
36  circular_size_(estimate_extraction.circular_size_),
37  state_size_(estimate_extraction.state_size_)
38 {
39  estimate_extraction.extraction_method_ = ExtractionMethod::emode;
40 }
41 
42 
44 {
45  if (this == &estimate_extraction)
46  return *this;
47 
48  extraction_method_ = estimate_extraction.extraction_method_;
49  estimate_extraction.extraction_method_ = ExtractionMethod::emode;
50 
51  hist_buffer_ = std::move(estimate_extraction.hist_buffer_);
52 
53  sm_weights_ = std::move(estimate_extraction.sm_weights_);
54  wm_weights_ = std::move(estimate_extraction.wm_weights_);
55  em_weights_ = std::move(estimate_extraction.em_weights_);
56 
57  linear_size_ = estimate_extraction.linear_size_;
58  circular_size_ = estimate_extraction.circular_size_;
59  state_size_ = estimate_extraction.state_size_;
60 
61  return *this;
62 }
63 
64 
65 bool EstimatesExtraction::setMethod(const ExtractionMethod& extraction_method)
66 {
67  extraction_method_ = extraction_method;
68 
69  return true;
70 }
71 
72 
74 {
75  if (window > 0)
76  return hist_buffer_.setHistorySize(window);
77  else
78  return false;
79 }
80 
81 
82 std::pair<bool, VectorXd> EstimatesExtraction::extract(const Ref<const MatrixXd>& particles, const Ref<const VectorXd>& weights)
83 {
84  VectorXd out_particle(state_size_);
85 
86  bool estimate_available = true;
87 
88  switch (extraction_method_)
89  {
90  case ExtractionMethod::mean :
91  out_particle = mean(particles, weights);
92  break;
93 
94  case ExtractionMethod::smean :
95  out_particle = simpleAverage(particles, weights, VectorXd(0), VectorXd(0), MatrixXd(0, 0), Statistics::mean);
96  break;
97 
98  case ExtractionMethod::wmean :
99  out_particle = weightedAverage(particles, weights, VectorXd(0), VectorXd(0), MatrixXd(0, 0), Statistics::mean);
100  break;
101 
102  case ExtractionMethod::emean :
103  out_particle = exponentialAverage(particles, weights, VectorXd(0), VectorXd(0), MatrixXd(0, 0), Statistics::mean);
104  break;
105 
106  case ExtractionMethod::mode :
107  out_particle = mode(particles, weights);
108  break;
109 
110  case ExtractionMethod::smode :
111  out_particle = simpleAverage(particles, weights, VectorXd(0), VectorXd(0), MatrixXd(0, 0), Statistics::mode);
112  break;
113 
114  case ExtractionMethod::wmode :
115  out_particle = weightedAverage(particles, weights, VectorXd(0), VectorXd(0), MatrixXd(0, 0), Statistics::mode);
116  break;
117 
118  case ExtractionMethod::emode :
119  out_particle = exponentialAverage(particles, weights, VectorXd(0), VectorXd(0), MatrixXd(0, 0), Statistics::mode);
120  break;
121 
122  case ExtractionMethod::map :
123  case ExtractionMethod::smap :
124  case ExtractionMethod::wmap :
125  case ExtractionMethod::emap :
126  /*
127  * These methods cannot be used if only particles and weights are provided by the user.
128  */
129  estimate_available = false;
130  break;
131  }
132 
133  return std::make_pair(estimate_available, out_particle);
134 }
135 
136 
137 std::pair<bool, VectorXd> EstimatesExtraction::extract
138 (
139  const Ref<const MatrixXd>& particles,
140  const Ref<const VectorXd>& weights,
141  const Ref<const VectorXd>& previous_weights,
142  const Ref<const VectorXd>& likelihoods,
143  const Ref<const MatrixXd>& transition_probabilities
144 )
145 {
146  VectorXd out_particle(state_size_);
147 
148  switch (extraction_method_)
149  {
150  case ExtractionMethod::mean :
151  case ExtractionMethod::smean :
152  case ExtractionMethod::wmean :
153  case ExtractionMethod::emean :
154  case ExtractionMethod::mode :
155  case ExtractionMethod::smode :
156  case ExtractionMethod::wmode :
157  case ExtractionMethod::emode :
158  return extract(particles, weights);
159 
160  case ExtractionMethod::map :
161  out_particle = map(particles, previous_weights, likelihoods, transition_probabilities);
162  break;
163 
164  case ExtractionMethod::smap :
165  out_particle = simpleAverage(particles, weights, previous_weights, likelihoods, transition_probabilities, Statistics::map);
166  break;
167 
168  case ExtractionMethod::wmap :
169  out_particle = weightedAverage(particles, weights, previous_weights, likelihoods, transition_probabilities, Statistics::map);
170  break;
171 
172  case ExtractionMethod::emap :
173  out_particle = exponentialAverage(particles, weights, previous_weights, likelihoods, transition_probabilities, Statistics::map);
174  break;
175  }
176 
177  return std::make_pair(true, out_particle);
178 }
179 
180 
182 {
183  return hist_buffer_.clear();
184 }
185 
186 
187 std::vector<std::string> EstimatesExtraction::getInfo() const
188 {
189  std::vector<std::string> info;
190 
191  info.push_back("<| Current window size: " + std::to_string(hist_buffer_.getHistorySize()) + " |>");
192  info.push_back("<| Available estimate extraction methods: " +
193  std::string(extraction_method_ == ExtractionMethod::mean ? "1) mean <-- In use; " : "1) mean; " ) +
194  std::string(extraction_method_ == ExtractionMethod::smean ? "2) smean <-- In use; " : "2) smean; ") +
195  std::string(extraction_method_ == ExtractionMethod::wmean ? "3) wmean <-- In use; " : "3) wmean; ") +
196  std::string(extraction_method_ == ExtractionMethod::emean ? "4) emean <-- In use; " : "4) emean; ") +
197  std::string(extraction_method_ == ExtractionMethod::mode ? "5) mode <-- In use; " : "5) mode; " ) +
198  std::string(extraction_method_ == ExtractionMethod::smode ? "6) smode <-- In use; " : "6) smode; ") +
199  std::string(extraction_method_ == ExtractionMethod::wmode ? "7) wmode <-- In use; " : "7) wmode; ") +
200  std::string(extraction_method_ == ExtractionMethod::emode ? "8) emode <-- In use; " : "8) emode" ) +
201  std::string(extraction_method_ == ExtractionMethod::map ? "9) map <-- In use; " : "9) map; ") +
202  std::string(extraction_method_ == ExtractionMethod::smap ? "10) smap <-- In use; " : "10) smap; ") +
203  std::string(extraction_method_ == ExtractionMethod::wmap ? "11) wmap <-- In use; " : "11) wmap; ") +
204  std::string(extraction_method_ == ExtractionMethod::emap ? "12) emap <-- In use; " : "12) emap; ") + " |>");
205 
206  return info;
207 }
208 
209 
210 VectorXd EstimatesExtraction::mean(const Ref<const MatrixXd>& particles, const Ref<const VectorXd>& weights) const
211 {
212  VectorXd out_particle(state_size_);
213 
214  if (linear_size_ > 0)
215  out_particle.head(linear_size_) = particles.topRows(linear_size_) * weights.array().exp().matrix();
216 
217  if (circular_size_ > 0)
218  out_particle.tail(circular_size_) = directional_statistics::directional_mean(particles.bottomRows(circular_size_), weights.array().exp().matrix());
219 
220  return out_particle;
221 }
222 
223 
224 VectorXd EstimatesExtraction::mode(const Ref<const MatrixXd>& particles, const Ref<const VectorXd>& weights) const
225 {
226  MatrixXd::Index maxRow;
227  MatrixXd::Index maxCol;
228  weights.maxCoeff(&maxRow, &maxCol);
229 
230  return particles.col(maxRow);
231 }
232 
233 
235 (
236  const Ref<const MatrixXd>& particles,
237  const Ref<const VectorXd>& previous_weights,
238  const Ref<const VectorXd>& likelihoods,
239  const Ref<const MatrixXd>& transition_probabilities
240 ) const
241 {
242  /* Using equation (10) from paper:
243  * Saha, S., Boers, Y., Driessen, H., Mandal, P. K., Bagchi, A. (2009),
244  * 'Particle Based MAP State Estimation: A Comparison.',
245  * 12th International Conference on Information Fusion,
246  * Seattle, WA, USA, July 6-9, 2009.
247  *
248  * The equation is rewritten in order to work in the log space.
249  */
250 
251  ArrayXd::Index map_index;
252 
253  VectorXd values(particles.cols());
254 
255  double eps = std::numeric_limits<double>::min();
256  for (std::size_t i = 0; i < values.size(); i++)
257  values(i) = std::log(likelihoods(i) + eps) + utils::log_sum_exp(((transition_probabilities.row(i).transpose().array() + eps).log() + previous_weights.array()).matrix());
258 
259  values.maxCoeff(&map_index);
260 
261  return particles.col(map_index);
262 }
263 
264 
266 (
267  const Ref<const MatrixXd>& particles,
268  const Ref<const VectorXd>& weights,
269  const Ref<const VectorXd>& previous_weights,
270  const Ref<const VectorXd>& likelihoods,
271  const Ref<const MatrixXd>& transition_probabilities,
272  const Statistics& base_est_ext
273 )
274 {
275  VectorXd cur_estimates;
276  if (base_est_ext == Statistics::mean)
277  cur_estimates = mean(particles, weights);
278  else if (base_est_ext == Statistics::mode)
279  cur_estimates = mode(particles, weights);
280  else if (base_est_ext == Statistics::map)
281  cur_estimates = map(particles, previous_weights, likelihoods, transition_probabilities);
282 
283 
284  hist_buffer_.addElement(cur_estimates);
285 
286  MatrixXd history = hist_buffer_.getHistoryBuffer();
287  if (sm_weights_.size() != history.cols())
288  sm_weights_ = VectorXd::Constant(history.cols(), -std::log(history.cols()));
289 
290 
291  return mean(history, sm_weights_);
292 }
293 
294 
296 (
297  const Ref<const MatrixXd>& particles,
298  const Ref<const VectorXd>& weights,
299  const Ref<const VectorXd>& previous_weights,
300  const Ref<const VectorXd>& likelihoods,
301  const Ref<const MatrixXd>& transition_probabilities,
302  const Statistics& base_est_ext
303 )
304 {
305  VectorXd cur_estimates;
306  if (base_est_ext == Statistics::mean)
307  cur_estimates = mean(particles, weights);
308  else if (base_est_ext == Statistics::mode)
309  cur_estimates = mode(particles, weights);
310  else if (base_est_ext == Statistics::map)
311  cur_estimates = map(particles, previous_weights, likelihoods, transition_probabilities);
312 
313 
314  hist_buffer_.addElement(cur_estimates);
315 
316  MatrixXd history = hist_buffer_.getHistoryBuffer();
317  if (wm_weights_.size() != history.cols())
318  {
319  wm_weights_.resize(history.cols());
320  for (unsigned int i = 0; i < history.cols(); ++i)
321  wm_weights_(i) = std::log(history.cols() - i);
322 
323  wm_weights_.array() -= utils::log_sum_exp(wm_weights_);
324  }
325 
326 
327  return mean(history, wm_weights_);
328 }
329 
330 
332 (
333  const Ref<const MatrixXd>& particles,
334  const Ref<const VectorXd>& weights,
335  const Ref<const VectorXd>& previous_weights,
336  const Ref<const VectorXd>& likelihoods,
337  const Ref<const MatrixXd>& transition_probabilities,
338  const Statistics& base_est_ext
339 )
340 {
341  VectorXd cur_estimates;
342  if (base_est_ext == Statistics::mean)
343  cur_estimates = mean(particles, weights);
344  else if (base_est_ext == Statistics::mode)
345  cur_estimates = mode(particles, weights);
346  else if (base_est_ext == Statistics::map)
347  cur_estimates = map(particles, previous_weights, likelihoods, transition_probabilities);
348 
349 
350  hist_buffer_.addElement(cur_estimates);
351 
352  MatrixXd history = hist_buffer_.getHistoryBuffer();
353  if (em_weights_.size() != history.cols())
354  {
355  em_weights_.resize(history.cols());
356  for (unsigned int i = 0; i < history.cols(); ++i)
357  em_weights_(i) = -(static_cast<double>(i) / history.cols());
358 
359  em_weights_.array() -= utils::log_sum_exp(em_weights_);
360  }
361 
362  return mean(history, em_weights_);
363 }
bfl::directional_statistics::directional_mean
Eigen::VectorXd directional_mean(const Eigen::Ref< const Eigen::MatrixXd > &a, const Eigen::Ref< const Eigen::VectorXd > &w)
EstimatesExtraction.h
bfl::utils::log_sum_exp
double log_sum_exp(const Eigen::MatrixBase< Derived > &data)
Return the element-wise logarithm of the sum of exponentials of the input data.
Definition: utils.h:72
bfl::EstimatesExtraction::Statistics
Statistics
Definition: EstimatesExtraction.h:67
bfl::EstimatesExtraction::EstimatesExtraction
EstimatesExtraction(const std::size_t linear_size) noexcept
Definition: EstimatesExtraction.cpp:16
bfl::EstimatesExtraction::operator=
EstimatesExtraction & operator=(EstimatesExtraction &&estimate_extraction) noexcept
Definition: EstimatesExtraction.cpp:43
bfl::EstimatesExtraction::simpleAverage
Eigen::VectorXd simpleAverage(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &weights, const Eigen::Ref< const Eigen::VectorXd > &previous_weights, const Eigen::Ref< const Eigen::VectorXd > &likelihoods, const Eigen::Ref< const Eigen::MatrixXd > &transition_probabilities, const Statistics &base_est_ext)
Definition: EstimatesExtraction.cpp:266
bfl::EstimatesExtraction::clear
bool clear()
Definition: EstimatesExtraction.cpp:181
bfl
Port of boost::any for C++11 compilers.
Definition: AdditiveMeasurementModel.h:13
bfl::EstimatesExtraction::exponentialAverage
Eigen::VectorXd exponentialAverage(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &weights, const Eigen::Ref< const Eigen::VectorXd > &previous_weights, const Eigen::Ref< const Eigen::VectorXd > &likelihoods, const Eigen::Ref< const Eigen::MatrixXd > &transition_probabilities, const Statistics &base_est_ext)
Definition: EstimatesExtraction.cpp:332
bfl::EstimatesExtraction::getInfo
std::vector< std::string > getInfo() const
Definition: EstimatesExtraction.cpp:187
bfl::EstimatesExtraction::mode
Eigen::VectorXd mode(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &weights) const
bfl::EstimatesExtraction::mean
Eigen::VectorXd mean(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &weights) const
utils.h
bfl::EstimatesExtraction::ExtractionMethod
ExtractionMethod
Definition: EstimatesExtraction.h:36
bfl::EstimatesExtraction::extraction_method_
ExtractionMethod extraction_method_
Definition: EstimatesExtraction.h:57
bfl::EstimatesExtraction::setMethod
bool setMethod(const ExtractionMethod &extraction_method)
Definition: EstimatesExtraction.cpp:65
bfl::EstimatesExtraction::map
Eigen::VectorXd map(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &previous_weights, const Eigen::Ref< const Eigen::VectorXd > &likelihoods, const Eigen::Ref< const Eigen::MatrixXd > &transition_probabilities) const
Return an approximatation of the MAP (maximum a posteriori) estimate from a running particle filter.
bfl::EstimatesExtraction::weightedAverage
Eigen::VectorXd weightedAverage(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &weights, const Eigen::Ref< const Eigen::VectorXd > &previous_weights, const Eigen::Ref< const Eigen::VectorXd > &likelihoods, const Eigen::Ref< const Eigen::MatrixXd > &transition_probabilities, const Statistics &base_est_ext)
Definition: EstimatesExtraction.cpp:296
bfl::EstimatesExtraction::extract
std::pair< bool, Eigen::VectorXd > extract(const Eigen::Ref< const Eigen::MatrixXd > &particles, const Eigen::Ref< const Eigen::VectorXd > &weights)
bfl::EstimatesExtraction::setMobileAverageWindowSize
bool setMobileAverageWindowSize(const int window)
Definition: EstimatesExtraction.cpp:73
directional_statistics.h
bfl::EstimatesExtraction
Definition: EstimatesExtraction.h:23