average.hpp
Go to the documentation of this file.
1 
4 #ifndef SOPHUS_AVERAGE_HPP
5 #define SOPHUS_AVERAGE_HPP
6 
7 #include "common.hpp"
8 #include "rxso2.hpp"
9 #include "rxso3.hpp"
10 #include "se2.hpp"
11 #include "se3.hpp"
12 #include "sim2.hpp"
13 #include "sim3.hpp"
14 #include "so2.hpp"
15 #include "so3.hpp"
16 
17 namespace Sophus {
18 
23 template <class SequenceContainer>
25  SequenceContainer const& foo_Ts_bar, int max_num_iterations) {
26  size_t N = foo_Ts_bar.size();
27  SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
28 
29  using Group = typename SequenceContainer::value_type;
30  using Scalar = typename Group::Scalar;
31  using Tangent = typename Group::Tangent;
32 
33  // This implements the algorithm in the beginning of Sec. 4.2 in
34  // ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
35  Group foo_T_average = foo_Ts_bar.front();
36  Scalar w = Scalar(1. / N);
37  for (int i = 0; i < max_num_iterations; ++i) {
38  Tangent average;
39  setToZero<Tangent>(average);
40  for (Group const& foo_T_bar : foo_Ts_bar) {
41  average += w * (foo_T_average.inverse() * foo_T_bar).log();
42  }
43  Group foo_T_newaverage = foo_T_average * Group::exp(average);
44  if (squaredNorm<Tangent>(
45  (foo_T_newaverage.inverse() * foo_T_average).log()) <
47  return foo_T_newaverage;
48  }
49 
50  foo_T_average = foo_T_newaverage;
51  }
52  // LCOV_EXCL_START
53  return nullopt;
54  // LCOV_EXCL_STOP
55 }
56 
57 #ifdef DOXYGEN_SHOULD_SKIP_THIS
58 template <class SequenceContainer, class Scalar>
60 optional<typename SequenceContainer::value_type> average(
61  SequenceContainer const& foo_Ts_bar);
62 #else
63 
64 // Mean implementation for SO(2).
65 template <class SequenceContainer,
66  class Scalar = typename SequenceContainer::value_type::Scalar>
68  std::is_same<typename SequenceContainer::value_type, SO2<Scalar> >::value,
69  optional<typename SequenceContainer::value_type> >
70 average(SequenceContainer const& foo_Ts_bar) {
71  // This implements rotational part of Proposition 12 from Sec. 6.2 of
72  // ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
73  size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
74  SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
75  SO2<Scalar> foo_T_average = foo_Ts_bar.front();
76  Scalar w = Scalar(1. / N);
77 
78  Scalar average(0);
79  for (SO2<Scalar> const& foo_T_bar : foo_Ts_bar) {
80  average += w * (foo_T_average.inverse() * foo_T_bar).log();
81  }
82  return foo_T_average * SO2<Scalar>::exp(average);
83 }
84 
85 // Mean implementation for RxSO(2).
86 template <class SequenceContainer,
87  class Scalar = typename SequenceContainer::value_type::Scalar>
89  std::is_same<typename SequenceContainer::value_type, RxSO2<Scalar> >::value,
90  optional<typename SequenceContainer::value_type> >
91 average(SequenceContainer const& foo_Ts_bar) {
92  size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
93  SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
94  RxSO2<Scalar> foo_T_average = foo_Ts_bar.front();
95  Scalar w = Scalar(1. / N);
96 
97  Vector2<Scalar> average(Scalar(0), Scalar(0));
98  for (RxSO2<Scalar> const& foo_T_bar : foo_Ts_bar) {
99  average += w * (foo_T_average.inverse() * foo_T_bar).log();
100  }
101  return foo_T_average * RxSO2<Scalar>::exp(average);
102 }
103 
104 namespace details {
105 template <class T>
106 void getQuaternion(T const&);
107 
108 template <class Scalar>
109 Eigen::Quaternion<Scalar> getUnitQuaternion(SO3<Scalar> const& R) {
110  return R.unit_quaternion();
111 }
112 
113 template <class Scalar>
114 Eigen::Quaternion<Scalar> getUnitQuaternion(RxSO3<Scalar> const& sR) {
115  return sR.so3().unit_quaternion();
116 }
117 
118 template <class SequenceContainer,
119  class Scalar = typename SequenceContainer::value_type::Scalar>
120 Eigen::Quaternion<Scalar> averageUnitQuaternion(
121  SequenceContainer const& foo_Ts_bar) {
122  // This: http://stackoverflow.com/a/27410865/1221742
123  size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
124  SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
125  Eigen::Matrix<Scalar, 4, Eigen::Dynamic> Q(4, N);
126  int i = 0;
127  Scalar w = Scalar(1. / N);
128  for (auto const& foo_T_bar : foo_Ts_bar) {
129  Q.col(i) = w * details::getUnitQuaternion(foo_T_bar).coeffs();
130  ++i;
131  }
132 
133  Eigen::Matrix<Scalar, 4, 4> QQt = Q * Q.transpose();
134  // TODO: Figure out why we can't use SelfAdjointEigenSolver here.
135  Eigen::EigenSolver<Eigen::Matrix<Scalar, 4, 4> > es(QQt);
136 
137  std::complex<Scalar> max_eigenvalue = es.eigenvalues()[0];
138  Eigen::Matrix<std::complex<Scalar>, 4, 1> max_eigenvector =
139  es.eigenvectors().col(0);
140 
141  for (int i = 1; i < 4; i++) {
142  if (std::norm(es.eigenvalues()[i]) > std::norm(max_eigenvalue)) {
143  max_eigenvalue = es.eigenvalues()[i];
144  max_eigenvector = es.eigenvectors().col(i);
145  }
146  }
147  Eigen::Quaternion<Scalar> quat;
148  quat.coeffs() << //
149  max_eigenvector[0].real(), //
150  max_eigenvector[1].real(), //
151  max_eigenvector[2].real(), //
152  max_eigenvector[3].real();
153  return quat;
154 }
155 } // namespace details
156 
157 // Mean implementation for SO(3).
158 //
159 // TODO: Detect degenerated cases and return nullopt.
160 template <class SequenceContainer,
161  class Scalar = typename SequenceContainer::value_type::Scalar>
163  std::is_same<typename SequenceContainer::value_type, SO3<Scalar> >::value,
164  optional<typename SequenceContainer::value_type> >
165 average(SequenceContainer const& foo_Ts_bar) {
166  return SO3<Scalar>(details::averageUnitQuaternion(foo_Ts_bar));
167 }
168 
169 // Mean implementation for R x SO(3).
170 template <class SequenceContainer,
171  class Scalar = typename SequenceContainer::value_type::Scalar>
173  std::is_same<typename SequenceContainer::value_type, RxSO3<Scalar> >::value,
174  optional<typename SequenceContainer::value_type> >
175 average(SequenceContainer const& foo_Ts_bar) {
176  size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
177 
178  SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
179  Scalar scale_sum = Scalar(0);
180  using std::exp;
181  using std::log;
182  for (RxSO3<Scalar> const& foo_T_bar : foo_Ts_bar) {
183  scale_sum += log(foo_T_bar.scale());
184  }
185  return RxSO3<Scalar>(exp(scale_sum / Scalar(N)),
187 }
188 
189 template <class SequenceContainer,
190  class Scalar = typename SequenceContainer::value_type::Scalar>
192  std::is_same<typename SequenceContainer::value_type, SE2<Scalar> >::value,
193  optional<typename SequenceContainer::value_type> >
194 average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
195  // TODO: Implement Proposition 12 from Sec. 6.2 of
196  // ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
197  return iterativeMean(foo_Ts_bar, max_num_iterations);
198 }
199 
200 template <class SequenceContainer,
201  class Scalar = typename SequenceContainer::value_type::Scalar>
203  std::is_same<typename SequenceContainer::value_type, Sim2<Scalar> >::value,
204  optional<typename SequenceContainer::value_type> >
205 average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
206  return iterativeMean(foo_Ts_bar, max_num_iterations);
207 }
208 
209 template <class SequenceContainer,
210  class Scalar = typename SequenceContainer::value_type::Scalar>
212  std::is_same<typename SequenceContainer::value_type, SE3<Scalar> >::value,
213  optional<typename SequenceContainer::value_type> >
214 average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
215  return iterativeMean(foo_Ts_bar, max_num_iterations);
216 }
217 
218 template <class SequenceContainer,
219  class Scalar = typename SequenceContainer::value_type::Scalar>
221  std::is_same<typename SequenceContainer::value_type, Sim3<Scalar> >::value,
222  optional<typename SequenceContainer::value_type> >
223 average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
224  return iterativeMean(foo_Ts_bar, max_num_iterations);
225 }
226 
227 #endif // DOXYGEN_SHOULD_SKIP_THIS
228 
229 } // namespace Sophus
230 
231 #endif // SOPHUS_AVERAGE_HPP
Sophus::details::getUnitQuaternion
Eigen::Quaternion< Scalar > getUnitQuaternion(SO3< Scalar > const &R)
Definition: average.hpp:109
Sophus::SO2
SO2 using default storage; derived from SO2Base.
Definition: so2.hpp:19
Sophus::SO3
SO3 using default storage; derived from SO3Base.
Definition: so3.hpp:19
Sophus::iterativeMean
optional< typename SequenceContainer::value_type > iterativeMean(SequenceContainer const &foo_Ts_bar, int max_num_iterations)
Definition: average.hpp:24
common.hpp
se2.hpp
Sophus::SO2::exp
static SOPHUS_FUNC SO2< Scalar > exp(Tangent const &theta)
Definition: so2.hpp:421
Sophus::enable_if_t
typename std::enable_if< B, T >::type enable_if_t
Definition: common.hpp:221
SOPHUS_ENSURE
#define SOPHUS_ENSURE(expr,...)
Definition: common.hpp:137
rxso3.hpp
Sophus::Vector2
Vector< Scalar, 2, Options > Vector2
Definition: types.hpp:16
so3.hpp
Sophus::RxSO2::exp
static SOPHUS_FUNC RxSO2< Scalar > exp(Tangent const &a)
Definition: rxso2.hpp:467
Sophus
Definition: average.hpp:17
sim2.hpp
Sophus::details::getQuaternion
void getQuaternion(T const &)
Sophus::optional
Definition: common.hpp:185
Sophus::nullopt
constexpr nullopt_t nullopt
Definition: common.hpp:177
se3.hpp
rxso2.hpp
Sophus::RxSO2
RxSO2 using storage; derived from RxSO2Base.
Definition: rxso2.hpp:11
Sophus::Constants
Definition: common.hpp:146
Sophus::details::averageUnitQuaternion
Eigen::Quaternion< Scalar > averageUnitQuaternion(SequenceContainer const &foo_Ts_bar)
Definition: average.hpp:120
Sophus::SO3::unit_quaternion
SOPHUS_FUNC QuaternionMember const & unit_quaternion() const
Definition: so3.hpp:488
Sophus::average
enable_if_t< std::is_same< typename SequenceContainer::value_type, SO2< Scalar > >::value, optional< typename SequenceContainer::value_type > > average(SequenceContainer const &foo_Ts_bar)
Definition: average.hpp:70
Sophus::RxSO3
RxSO3 using storage; derived from RxSO3Base.
Definition: rxso3.hpp:11
so2.hpp
sim3.hpp


sophus
Author(s): Hauke Strasdat
autogenerated on Wed Mar 2 2022 01:01:47