15 #ifndef BELUGA_ALGORITHM_ESTIMATION_HPP
16 #define BELUGA_ALGORITHM_ESTIMATION_HPP
18 #include <range/v3/algorithm/count_if.hpp>
19 #include <range/v3/numeric/accumulate.hpp>
20 #include <range/v3/range/access.hpp>
21 #include <range/v3/range/primitives.hpp>
22 #include <range/v3/view/common.hpp>
23 #include <range/v3/view/repeat_n.hpp>
24 #include <range/v3/view/transform.hpp>
51 template <
class Range,
class WeightsRange,
class Scalar>
54 auto translations_view = range | ranges::views::common;
55 auto normalized_weights_view = normalized_weights | ranges::views::common;
57 auto calculate_weighted_sample_covariance = [mean](
const auto& value,
const auto&
weight) {
58 const auto centered = value - mean;
60 weight * centered.x() * centered.x(),
61 weight * centered.x() * centered.y(),
62 weight * centered.y() * centered.y(),
68 const auto squared_weight_sum = std::transform_reduce(
69 normalized_weights_view.begin(), normalized_weights_view.end(), Scalar{0.0}, std::plus{},
70 [](
const auto&
weight) { return (weight * weight); });
74 std::transform_reduce(
75 translations_view.begin(), translations_view.end(), normalized_weights_view.begin(),
77 (1.0 - squared_weight_sum);
81 covariance_matrix << coefficients(0), coefficients(1), coefficients(1), coefficients(2);
82 return covariance_matrix;
96 template <
class Range,
class Scalar>
98 const auto sample_count = range.size();
101 ranges::views::repeat_n(1.0 /
static_cast<Scalar
>(sample_count),
static_cast<std::ptrdiff_t
>(sample_count)),
126 class Pose = ranges::range_value_t<Poses>,
127 class Scalar =
typename Pose::Scalar,
128 typename = std::enable_if_t<std::is_same_v<Pose, typename Sophus::SE2<Scalar>>>>
130 auto translation_view = poses | ranges::views::transform([](
const auto& pose) {
return pose.translation(); });
131 auto poses_view = poses | ranges::views::common;
132 auto weights_view =
weights | ranges::views::common;
133 const auto weights_sum = std::accumulate(weights_view.begin(), weights_view.end(), 0.0);
134 auto normalized_weights_view =
135 weights_view | ranges::views::transform([weights_sum](
const auto&
weight) {
return weight / weights_sum; });
139 const auto pose_to_weighted_eigen_vector = [](
const auto& pose,
const auto&
weight) {
140 return Eigen::Map<const Sophus::Vector4<Scalar>>{pose.data()} *
weight;
149 std::plus{}, pose_to_weighted_eigen_vector);
157 covariance_matrix.template topLeftCorner<2, 2>() =
161 if (estimated_pose.
so2().
unit_complex().norm() < std::numeric_limits<double>::epsilon()) {
164 covariance_matrix.coeffRef(2, 2) = std::numeric_limits<double>::infinity();
169 covariance_matrix.coeffRef(2, 2) = -2.0 * std::log(estimated_pose.
so2().
unit_complex().norm());
170 estimated_pose.
so2().normalize();
172 return std::pair{estimated_pose, covariance_matrix};
191 class Scalar = ranges::range_value_t<Scalars>,
192 typename = std::enable_if_t<std::is_arithmetic_v<Scalar>>>
194 auto weights_view =
weights | ranges::views::common;
195 const auto weights_sum = ranges::accumulate(
weights, 0.0, std::plus<>{});
196 auto normalized_weights_view =
197 weights_view | ranges::views::transform([weights_sum](
auto weight) {
return weight / weights_sum; });
199 const Scalar weighted_mean = std::transform_reduce(
200 scalars.begin(), scalars.end(), normalized_weights_view.begin(), 0.0, std::plus<>{}, std::multiplies<>{});
202 const Scalar weighted_squared_deviations = std::transform_reduce(
203 scalars.begin(), scalars.end(), normalized_weights_view.begin(), 0.0, std::plus<>{},
204 [weighted_mean](
const auto& scalar,
const auto&
weight) {
205 return weight * (scalar - weighted_mean) * (scalar - weighted_mean);
208 const auto number_of_non_zero_weights =
209 static_cast<Scalar
>(ranges::count_if(weights_view, [&](
auto weight) {
return weight > 0; }));
211 const Scalar weighted_variance =
212 weighted_squared_deviations * number_of_non_zero_weights / (number_of_non_zero_weights - 1);
214 return std::pair{weighted_mean, weighted_variance};
237 class Pose = ranges::range_value_t<Poses>,
238 class Scalar =
typename Pose::Scalar,
239 typename = std::enable_if_t<std::is_same_v<Pose, typename Sophus::SE2<Scalar>>>>
241 return beluga::estimate(poses, ranges::views::repeat_n(1.0,
static_cast<std::ptrdiff_t
>(poses.size())));