test_multivariate_normal_distribution.cpp
Go to the documentation of this file.
1 // Copyright 2023 Ekumen, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 #include <numeric>
19 #include <stdexcept>
20 #include <utility>
21 #include <vector>
22 
23 #include <Eigen/Core>
24 
25 #include <range/v3/range/conversion.hpp>
26 #include <range/v3/view/generate.hpp>
27 #include <range/v3/view/take_exactly.hpp>
28 
33 
34 namespace {
35 
37 
38 TEST(MultivariateNormalDistribution, CopyAndCompare) {
39  const Eigen::Matrix3d covariance = Eigen::Vector3d::Ones().asDiagonal();
40  auto distribution = beluga::MultivariateNormalDistribution<Eigen::Vector3d>{covariance};
41  auto other_distribution = distribution;
42  ASSERT_EQ(distribution, other_distribution);
43  auto generator = std::mt19937{std::random_device()()};
44  auto other_generator = generator;
45  // Testing twice to assert that they generate the same sequence.
46  ASSERT_EQ(distribution(generator), other_distribution(other_generator));
47  ASSERT_EQ(distribution(generator), other_distribution(other_generator));
48 }
49 
50 TEST(MultivariateNormalDistribution, NegativeEigenvaluesMatrix) {
51  const Eigen::Matrix3d covariance = Eigen::Matrix3d::Ones();
52  EXPECT_THROW(beluga::MultivariateNormalDistribution<Eigen::Vector3d>{covariance}, std::runtime_error);
53 }
54 
55 TEST(MultivariateNormalDistribution, NonSymmetricMatrix) {
56  auto covariance = testing::as<Eigen::Matrix3d>({{1.0, 2.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 1.0}});
57  EXPECT_THROW(beluga::MultivariateNormalDistribution<Eigen::Vector3d>{covariance}, std::runtime_error);
58 }
59 
61  constexpr double kTolerance = 0.001;
62  auto generator = std::mt19937{std::random_device()()};
63  auto distribution = beluga::MultivariateNormalDistribution{Eigen::Vector2d::Zero(), Eigen::Matrix2d::Zero()};
64  ASSERT_THAT(distribution(generator), Vector2Near(Eigen::Vector2d{0, 0}, kTolerance));
65 }
66 
67 class MultivariateNormalDistributionWithParam
68  : public ::testing::TestWithParam<std::pair<Eigen::Vector2d, Eigen::Matrix2d>> {};
69 
70 TEST_P(MultivariateNormalDistributionWithParam, DistributionCovarianceAndMean) {
71  constexpr double kTolerance = 0.01;
72  const Eigen::Vector2d& expected_mean = std::get<0>(GetParam());
73  const Eigen::Matrix2d& expected_covariance = std::get<1>(GetParam());
74  auto distribution = beluga::MultivariateNormalDistribution{expected_mean, expected_covariance};
75  const auto sequence = ranges::views::generate([&]() {
76  static auto generator = std::mt19937{std::random_device()()};
77  return distribution(generator);
78  }) |
79  ranges::views::take_exactly(1'000'000) | ranges::to<std::vector>;
80 
81  const auto sum = std::accumulate(sequence.begin(), sequence.end(), Eigen::Vector2d{0, 0});
82  const auto mean = Eigen::Vector2d{sum / sequence.size()};
83  ASSERT_NEAR(mean(0), expected_mean(0), kTolerance);
84  ASSERT_NEAR(mean(1), expected_mean(1), kTolerance);
85  const auto covariance = beluga::calculate_covariance(sequence, mean);
86  ASSERT_NEAR(covariance(0, 0), expected_covariance(0, 0), kTolerance);
87  ASSERT_NEAR(covariance(0, 1), expected_covariance(0, 1), kTolerance);
88  ASSERT_NEAR(covariance(1, 0), expected_covariance(1, 0), kTolerance);
89  ASSERT_NEAR(covariance(1, 1), expected_covariance(1, 1), kTolerance);
90 }
91 
92 INSTANTIATE_TEST_SUITE_P(
93  MeanCovariancePairs,
94  MultivariateNormalDistributionWithParam,
95  testing::Values(
96  std::make_pair(Eigen::Vector2d{1.0, 2.0}, testing::as<Eigen::Matrix2d>({{0.0, 0.0}, {0.0, 0.0}})),
97  std::make_pair(Eigen::Vector2d{3.0, 4.0}, testing::as<Eigen::Matrix2d>({{1.0, 0.0}, {0.0, 1.0}})),
98  std::make_pair(Eigen::Vector2d{3.0, 4.0}, testing::as<Eigen::Matrix2d>({{1.5, -0.3}, {-0.3, 1.5}})),
99  std::make_pair(Eigen::Vector2d{5.0, 6.0}, testing::as<Eigen::Matrix2d>({{2.0, 0.7}, {0.7, 2.0}}))));
100 
102  constexpr double kTolerance = 0.001;
103  auto generator = std::mt19937{std::random_device()()};
104  auto expected_mean = Eigen::RowVector2d{1.0, 2.0};
105  auto distribution = beluga::MultivariateNormalDistribution{expected_mean, Eigen::Matrix2d::Zero()};
106  auto mean = distribution(generator);
107  ASSERT_NEAR(mean(0), expected_mean(0), kTolerance);
108  ASSERT_NEAR(mean(1), expected_mean(1), kTolerance);
109 }
110 
112  constexpr double kTolerance = 0.001;
113  auto generator = std::mt19937{std::random_device()()};
114  auto expected_mean = Sophus::SO2d{1.5};
115  auto distribution = beluga::MultivariateNormalDistribution{expected_mean, Eigen::Matrix<double, 1, 1>::Zero()};
116  auto mean = distribution(generator);
117  ASSERT_NEAR((mean).log(), expected_mean.log(), kTolerance);
118 }
119 
121  constexpr double kTolerance = 0.001;
122  auto generator = std::mt19937{std::random_device()()};
123  auto expected_mean = Sophus::SE2d{Sophus::SO2d{1.57}, Eigen::Vector2d{1.0, 2.0}};
124  auto distribution = beluga::MultivariateNormalDistribution{expected_mean, Eigen::Matrix3d::Zero()};
125  auto mean = distribution(generator);
126  ASSERT_NEAR(mean.so2().log(), expected_mean.so2().log(), kTolerance);
127  ASSERT_NEAR(mean.translation()(0), expected_mean.translation()(0), kTolerance);
128  ASSERT_NEAR(mean.translation()(1), expected_mean.translation()(1), kTolerance);
129 }
130 
132  auto generator = std::mt19937{std::random_device()()};
133  auto expected_mean = Sophus::SO3d::exp(Eigen::Vector3d{0.5, 1.0, 1.5});
134  auto distribution = beluga::MultivariateNormalDistribution{expected_mean, Eigen::Matrix3d::Zero()};
135  auto mean = distribution(generator);
136  ASSERT_NEAR(mean.log()(0), expected_mean.log()(0), 0.001);
137  ASSERT_NEAR(mean.log()(1), expected_mean.log()(1), 0.001);
138  ASSERT_NEAR(mean.log()(2), expected_mean.log()(2), 0.001);
139 }
140 
142  auto generator = std::mt19937{std::random_device()()};
143  auto expected_mean = Sophus::SE3d{Sophus::SO3d::exp(Eigen::Vector3d{0.5, 1.0, 1.5}), Eigen::Vector3d{1.0, 2.0, 3.0}};
144  auto distribution = beluga::MultivariateNormalDistribution{expected_mean, Eigen::Matrix<double, 6, 6>::Zero()};
145  auto mean = distribution(generator);
146  ASSERT_NEAR(mean.log()(0), expected_mean.log()(0), 0.001);
147  ASSERT_NEAR(mean.log()(1), expected_mean.log()(1), 0.001);
148  ASSERT_NEAR(mean.log()(2), expected_mean.log()(2), 0.001);
149  ASSERT_NEAR(mean.translation()(0), expected_mean.translation()(0), 0.001);
150  ASSERT_NEAR(mean.translation()(1), expected_mean.translation()(1), 0.001);
151  ASSERT_NEAR(mean.translation()(2), expected_mean.translation()(2), 0.001);
152 }
153 
154 } // namespace
Sophus::SO2
kTolerance
double kTolerance
Definition: test_cluster_based_estimation.cpp:47
Sophus::SO3::exp
static SOPHUS_FUNC SO3< Scalar > exp(Tangent const &omega)
estimation.hpp
Implementation of algorithms that allow calculating the estimated state of a particle filter.
beluga::testing::Vector2Near
auto Vector2Near(const Sophus::Vector2< Scalar > &t, Scalar e)
Vector2 element matcher.
Definition: sophus_matchers.hpp:45
eigen_initializers.hpp
Sophus::SE2
beluga::MultivariateNormalDistribution
MultivariateNormalDistribution(const T &, const typename multivariate_distribution_traits< T >::covariance_type &) -> MultivariateNormalDistribution< typename multivariate_distribution_traits< T >::result_type >
Deduction guide to deduce the correct result type.
Sophus::SE3
multivariate_normal_distribution.hpp
Implementation of a multivariate normal distribution.
sophus_matchers.hpp
Implements GTest matchers for Sophus/Eigen types.
beluga::MultivariateNormalDistribution
Multivariate normal distribution.
Definition: multivariate_normal_distribution.hpp:137
beluga::calculate_covariance
Sophus::Matrix2< Scalar > calculate_covariance(Range &&range, WeightsRange &&normalized_weights, const Sophus::Vector2< Scalar > &mean)
Calculates the covariance of a range given its mean and the weights of each element.
Definition: estimation.hpp:53
beluga::TEST
TEST(Bresenham, MultiPassGuarantee)
Definition: test_bresenham.cpp:27


beluga
Author(s):
autogenerated on Tue Jul 16 2024 02:59:53