test_pf.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2017, the mcl_3dl authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <cmath>
31 #include <cstddef>
32 #include <vector>
33 
34 #include <mcl_3dl/nd.h>
35 #include <mcl_3dl/pf.h>
36 
37 #include <gtest/gtest.h>
38 
39 class State : public mcl_3dl::pf::ParticleBase<float>
40 {
41 public:
42  float x;
43  float& operator[](const size_t i) override
44  {
45  switch (i)
46  {
47  case 0:
48  return x;
49  }
50  return x;
51  }
52  const float& operator[](const size_t i) const
53  {
54  switch (i)
55  {
56  case 0:
57  return x;
58  }
59  return x;
60  }
61  size_t size() const override
62  {
63  return 1;
64  };
65  explicit State(const float x)
66  {
67  this->x = x;
68  }
70  {
71  x = 0;
72  }
73  void normalize()
74  {
75  }
76 };
77 
78 TEST(Pf, BayesianEstimation)
79 {
81  const float center_list[] =
82  {
83  10.0, 11.0, 9.5
84  };
85 
86  const float abs_error = 2e-1;
87  const float sigma = 1.0;
88  const float sigma2 = 2.0;
89 
90  for (auto center : center_list)
91  {
92  for (auto center2 : center_list)
93  {
94  pf.init(
95  State(center),
96  State(sigma));
97 
98  ASSERT_NEAR(center, pf.expectation()[0], abs_error);
99  ASSERT_NEAR(sigma, pf.covariance()[0][0], abs_error);
100 
101  auto likelihood = [center2, sigma2](const State& s) -> float
102  {
103  return std::exp(-std::pow(s[0] - center2, 2) / (2.0 * std::pow(sigma2, 2)));
104  };
105  pf.measure(likelihood);
106 
107  // Numerical representation
108  const int HISTOGRAM_SIZE = 4000;
109  const float HISTOGRAM_RESOLUTION = 0.02;
110 
111  float dist[HISTOGRAM_SIZE];
114  double avg = 0;
115  float total = 0;
116  for (int i = 0; i < HISTOGRAM_SIZE; i++)
117  {
118  const float x = (i - HISTOGRAM_SIZE / 2.0) * HISTOGRAM_RESOLUTION;
119  dist[i] = nd1(x - center) * nd2(x - center2);
120 
121  avg += dist[i] * x;
122  total += dist[i];
123  }
124  avg /= total;
125  double var = 0;
126  for (int i = 0; i < HISTOGRAM_SIZE; i++)
127  {
128  const float x = (i - HISTOGRAM_SIZE / 2.0) * HISTOGRAM_RESOLUTION - avg;
129  var += std::pow(x, 2) * dist[i];
130  }
131  var /= total;
132 
133  // Compare with numerical result
134  ASSERT_NEAR(avg, pf.expectation()[0], abs_error);
135  ASSERT_NEAR(var, pf.covariance()[0][0], abs_error);
136 
137  // Try resampling
138  pf.resample(State(0.0));
139  ASSERT_NEAR(avg, pf.expectation()[0], abs_error);
140  ASSERT_NEAR(var, pf.covariance()[0][0], abs_error);
141 
142  // 50% Random sampled covaliance calculation
143  ASSERT_NEAR(var, pf.covariance(1.0, 0.5)[0][0], abs_error * 2);
144  }
145  }
146 }
147 
148 TEST(Pf, VariableParticleSize)
149 {
150  const size_t size_num = 3;
151  const size_t size[size_num] =
152  {
153  1024, 2048, 900
154  };
156 
157  const float center = 12.3;
158  const float sigma = 0.45;
159  pf.init(
160  State(center),
161  State(sigma));
162 
163  for (size_t i = 0; i < size_num; ++i)
164  {
165  ASSERT_EQ(pf.getParticleSize(), size[i]);
166 
167  const State e = pf.expectation();
168  const std::vector<State> v = pf.covariance();
169  ASSERT_LT(fabs(e[0] - center), 1e-1);
170  ASSERT_LT(fabs(std::sqrt(v[0][0]) - sigma), 1e-1);
171 
172  pf.resample(State());
173 
174  const State e_r = pf.expectation();
175  const std::vector<State> v_r = pf.covariance();
176  ASSERT_LT(fabs(e_r[0] - center), 1e-1);
177  ASSERT_LT(fabs(std::sqrt(v_r[0][0]) - sigma), 1e-1);
178 
179  if (i + 1 != size_num)
180  {
181  pf.resizeParticle(size[i + 1]);
182  }
183  }
184 }
185 
186 TEST(Pf, ResampleFlatLikelihood)
187 {
189  const float center = 12.3;
190  const float sigma = 0.45;
191  pf.init(
192  State(center),
193  State(sigma));
194 
195  std::vector<float> orig;
196 
197  for (size_t i = 0; i < pf.getParticleSize(); ++i)
198  orig.push_back(pf.getParticle(i)[0]);
199 
200  pf.resample(State());
201 
202  for (size_t i = 0; i < pf.getParticleSize(); ++i)
203  ASSERT_EQ(pf.getParticle(i)[0], orig[i]);
204 }
205 
206 void testResample(const std::vector<float>& probs, const std::vector<float>& states,
207  const std::vector<float>& expected_resampled_states)
208 {
209  const size_t particle_num = probs.size();
210  mcl_3dl::pf::ParticleFilter<State, float> pf(particle_num, 12345);
211  auto it = pf.begin();
212  for (size_t i = 0; i < particle_num; ++i, ++it)
213  {
214  it->state_.x = states.at(i);
215  it->probability_ = probs.at(i);
216  }
217  pf.resample(State());
218 
219  ASSERT_EQ(particle_num, pf.getParticleSize());
220  for (size_t i = 0; i < pf.getParticleSize(); ++i)
221  {
222  EXPECT_FLOAT_EQ(expected_resampled_states.at(i), pf.getParticle(i)[0]);
223  }
224 }
225 
226 TEST(Pf, ResampleFirstAndLastParticle)
227 {
228  const float small_prob = 1.0e-06f;
229  {
230  SCOPED_TRACE("ResampleFirstParticle");
231  const std::vector<float> probs =
232  {
233  small_prob, 0.2f, 0.2f, 0.2f, 0.4f - small_prob
234  };
235  const std::vector<float> states =
236  {
237  0.0f, 1.0f, 2.0f, 3.0f, 4.0f
238  };
239  const std::vector<float> expected_resampled_states =
240  {
241  1.0f, 2.0f, 3.0f, 4.0f, 4.0f
242  };
243  testResample(probs, states, expected_resampled_states);
244  }
245  {
246  SCOPED_TRACE("ResampleLastParticle");
247  const std::vector<float> probs =
248  {
249  0.2f, 0.2f, 0.2f, 0.4f - small_prob, small_prob};
250  const std::vector<float> states =
251  {
252  0.0f, 1.0f, 2.0f, 3.0f, 4.0f
253  };
254  const std::vector<float> expected_resampled_states =
255  {
256  0.0f, 1.0f, 2.0f, 3.0f, 3.0f
257  };
258  testResample(probs, states, expected_resampled_states);
259  }
260 }
261 
262 TEST(Pf, Iterators)
263 {
265  const float val0 = 12.3;
266  const float val1 = 45.6;
267  pf.init(
268  State(val0),
269  State(0.0));
270 
271  for (auto it = pf.begin(); it != pf.end(); ++it)
272  {
273  ASSERT_EQ(it->state_[0], val0);
274  it->state_[0] = val1;
275  }
276  for (auto it = pf.begin(); it != pf.end(); ++it)
277  ASSERT_EQ(it->state_[0], val1);
278 }
279 
280 TEST(Pf, AppendParticles)
281 {
283  const float val0 = 12.3;
284  const float val1 = 45.6;
285  pf.init(
286  State(val0),
287  State(0.0));
288  // particles 0-9 has val0
289 
290  for (auto it = pf.appendParticle(10); it != pf.end(); ++it)
291  it->state_[0] = val1;
292  // appended particles 10-19 has val1
293 
294  ASSERT_EQ(pf.getParticleSize(), 20u);
295  for (size_t i = 0; i < 10; ++i)
296  ASSERT_EQ(pf.getParticle(i)[0], val0);
297  for (size_t i = 10; i < 20; ++i)
298  ASSERT_EQ(pf.getParticle(i)[0], val1);
299 }
300 
301 int main(int argc, char** argv)
302 {
303  testing::InitGoogleTest(&argc, argv);
304 
305  return RUN_ALL_TESTS();
306 }
T getParticle(const size_t i) const
Definition: pf.h:380
f
size_t getParticleSize() const
Definition: pf.h:384
void resample(T sigma)
Definition: pf.h:178
XmlRpcServer s
T expectation(const FLT_TYPE pass_ratio=1.0)
Definition: pf.h:270
void normalize()
Definition: test_pf.cpp:73
void testResample(const std::vector< float > &probs, const std::vector< float > &states, const std::vector< float > &expected_resampled_states)
Definition: test_pf.cpp:206
void resizeParticle(const size_t num)
Definition: pf.h:388
float x
Definition: test_pf.cpp:42
void init(T mean, T sigma)
Definition: pf.h:165
std::vector< T > covariance(const FLT_TYPE pass_ratio=1.0, const FLT_TYPE random_sample_ratio=1.0)
Definition: pf.h:294
int main(int argc, char **argv)
Definition: test_pf.cpp:301
std::vector< Particle< T, FLT_TYPE > >::iterator appendParticle(const size_t num)
Definition: pf.h:426
std::vector< Particle< T, FLT_TYPE > >::iterator begin()
Definition: pf.h:432
float & operator[](const size_t i) override
Definition: test_pf.cpp:43
std::vector< Particle< T, FLT_TYPE > >::iterator end()
Definition: pf.h:436
State(const float x)
Definition: test_pf.cpp:65
size_t size() const override
Definition: test_pf.cpp:61
State()
Definition: test_pf.cpp:69
TEST(Pf, BayesianEstimation)
Definition: test_pf.cpp:78
void measure(std::function< FLT_TYPE(const T &)> likelihood)
Definition: pf.h:248
const float & operator[](const size_t i) const
Definition: test_pf.cpp:52


mcl_3dl
Author(s): Atsushi Watanabe
autogenerated on Wed May 12 2021 02:16:29