Implement low-variance sampling algorithm#482
Conversation
4a84380 to
614ed8f
Compare
hidmic
left a comment
There was a problem hiding this comment.
Great first take @larodriguez22! I think adding some unit tests will help a lot.
bd2804c to
3c63caf
Compare
hidmic
left a comment
There was a problem hiding this comment.
Second pass. Great job @larodriguez22 !
|
|
||
| /// Position the current iterator. | ||
| constexpr void next() { | ||
| ++m_; |
There was a problem hiding this comment.
@larodriguez22 meta: can we use complete names for variables? Or document the algorithm to put u, c, m, M in context?
There was a problem hiding this comment.
Yes, I used those names because of the book. But I can change them
There was a problem hiding this comment.
For the algorithm itself I don't mind using single letter variables so long as we have a comment block right next to it that explains what those variables mean.
glpuga
left a comment
There was a problem hiding this comment.
Good work @larodriguez22 .
Which of the versions discussed in #48 is targetted here? this looks like the version in Prob Robotics, but that version is known not to work with KLD. Is this meant to be used with fixed resampling?
| c_{*weights_begin_} {} | ||
|
|
||
| /// Access the current iterator. | ||
| [[nodiscard]] constexpr decltype(auto) read() const noexcept(noexcept(*range_begin_)) { return *it_; } |
There was a problem hiding this comment.
noexcept(noexcept(*range_begin_))
C++ needs to burn in hell.
There was a problem hiding this comment.
It was like that in the example of SampleView, isn't?
| template <class T, class U, class V> | ||
| constexpr auto operator()(T&& t, U&& u, V& v) const { |
There was a problem hiding this comment.
Let's not use single letter variables and template arguments, and even less if they are unrelated to their role in the code. TUV are just three consecutive letters. Names should be convey meaning. Use whole words, multiple words if needed, we are not billed for the characters we use.
https://google.github.io/styleguide/cppguide.html#General_Naming_Rules
There was a problem hiding this comment.
I used those names, because of conventions to the book. But I'll change them. Thanks for the link
| static_assert(ranges::range<T>); | ||
| static_assert(std::is_lvalue_reference_v<U&&>); // Assume U is a URNG | ||
| return low_variance_sample_from_range(std::forward<T>(t), u); |
There was a problem hiding this comment.
I think this needs more explaining.
hidmic
left a comment
There was a problem hiding this comment.
Great work @larodriguez22. Second pass.
| double r_; | ||
| uint64_t m_; | ||
| uint64_t i_; | ||
| double c_; |
There was a problem hiding this comment.
@larodriguez22 meta: why do we force this to use double types, instead of using the Range value type?
There was a problem hiding this comment.
I changed c_ to ranges::range_value_t<Weights>, but I think the other ones must be fixed to be double or int numbers
|
|
||
| /// Position the current iterator. | ||
| constexpr void next() { | ||
| ++m_; |
There was a problem hiding this comment.
For the algorithm itself I don't mind using single letter variables so long as we have a comment block right next to it that explains what those variables mean.
log/latest_test
Outdated
| @@ -0,0 +1 @@ | |||
| test_2025-06-01_21-06-40 No newline at end of file | |||
There was a problem hiding this comment.
@larodriguez22 let's remove this log directory. I wonder why it was picked up to begin with 🤔
hidmic
left a comment
There was a problem hiding this comment.
Third pass. Great work @larodriguez22.
beluga/docs/index.md
Outdated
| - Multinomial resampling from a particle range | ||
| - [Adaptive KLD resampling][fox2001] | ||
| - [Selective resampling][grisetti2007], on-motion resampling, and interval resampling policies | ||
| - Low Variance sampling |
There was a problem hiding this comment.
@larodriguez22 nit: would be nice to add a citation like we do for KLD and selective resampling.
| /// selecting each element is proportional to its weight. It works by computing a single random number r is generated in | ||
| /// the range [0, 1/M), where M is the total number of elements in the range. Then, starting from this random number r, |
There was a problem hiding this comment.
@larodriguez22 nit:
| /// selecting each element is proportional to its weight. It works by computing a single random number r is generated in | |
| /// the range [0, 1/M), where M is the total number of elements in the range. Then, starting from this random number r, | |
| /// selecting each element is proportional to its weight. It works with a single random number r in | |
| /// the [0, 1/M) interval, where M is the total number of elements in the range. Then, starting from this random number r, |
| c_ += *weights_begin_; | ||
| } | ||
| ++m_; | ||
| it_ = std::next(range_begin_, i_); |
There was a problem hiding this comment.
@larodriguez22 do we need i_? Why not increment it_ in the loop, checking it against the end iterator?
There was a problem hiding this comment.
You are right, fixed
| template <class T, class U, class V> | ||
| constexpr auto operator()(T&& t, U&& u, V& v) const { |
| auto lv_count_1 = ranges::count(lv_output, 1); | ||
| auto mult_count_1 = ranges::count(mult_output, 1); | ||
|
|
||
| double lv_ratio = static_cast<double>(lv_count_1) / num_samples; | ||
| double mult_ratio = static_cast<double>(mult_count_1) / num_samples; | ||
|
|
||
| // Store squared deviation from expected (0.1) | ||
| lv_variances.push_back(std::pow(lv_ratio - 0.1, 2)); | ||
| multinomial_variances.push_back(std::pow(mult_ratio - 0.1, 2)); |
There was a problem hiding this comment.
@larodriguez22 this is peculiar. We are computing variances over probabilities. I was expecting variances over distribution statistics (mean, variance, etc.). I wonder if results are equivalent (they should be, right?).
There was a problem hiding this comment.
It is not necessarily the same
|
|
||
| std::vector<double> lv_total_var, mult_total_var; | ||
|
|
||
| for (int trial = 0; trial < std::min(50, num_trials); ++trial) { // Subset for performance |
There was a problem hiding this comment.
@larodriguez22 this should perhaps be a separate test.
| auto first = ranges::begin(new_container); | ||
| auto last = ranges::copy(samples, first).out; | ||
| auto result = ranges::make_subrange(first, last); |
There was a problem hiding this comment.
@larodriguez22 why do we do this? Is it to force computation?
There was a problem hiding this comment.
Yes, it is to force computation
| const auto particle_count = state.range(0); | ||
| state.SetComplexityN(particle_count); | ||
| const auto container_size = static_cast<std::size_t>(particle_count); | ||
| const auto sample_size = std::max(static_cast<std::size_t>(1), container_size / 10); // Sample 10% of particles |
There was a problem hiding this comment.
@larodriguez22 nit:
| const auto sample_size = std::max(static_cast<std::size_t>(1), container_size / 10); // Sample 10% of particles | |
| const auto sample_size = std::max(1UL, container_size / 10UL); // Sample 10% of particles |
| for (auto&& [state, weight] : container) { | ||
| weight = dist(gen); | ||
| } | ||
| return container; |
There was a problem hiding this comment.
@larodriguez22 meta: don't we have to normalize weights? Same elsewhere.
|
@larodriguez22 may I take this to completion or are you still working on it? |
Signed-off-by: ADEGA <la.rodriguez@uniandes.edu.co>
… sample Signed-off-by: ADEGA <la.rodriguez@uniandes.edu.co>
Signed-off-by: ADEGA <la.rodriguez@uniandes.edu.co>
Signed-off-by: ADEGA <la.rodriguez@uniandes.edu.co>
Signed-off-by: ADEGA <la.rodriguez@uniandes.edu.co>
Signed-off-by: ADEGA <la.rodriguez@uniandes.edu.co>
323a77b to
60d5ebc
Compare
I took longer than expected. I'm sorry, ready for another review |
Proposed changes
This PR adds the strategy of low-variance sampling for the resampling step. Adds a new range adaptor called
beluga::views::low_variance_sample. Related to: #48Type of change
Checklist
Put an
xin the boxes that apply. This is simply a reminder of what we will require before merging your code.Additional comments
How to run it?
colcon build --packages-up-to beluga && ./build/beluga/test/benchmark/benchmark_beluga --benchmark_filter=Low