gtsam
Loading...
Searching...
No Matches
MatrixLieGroup.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8 * See LICENSE for the license information
9
10 * -------------------------------------------------------------------------- */
11
17
18
19#pragma once
20
21#include <gtsam/base/Lie.h>
22#include <array>
23#include <type_traits>
24
25namespace gtsam {
26
27 namespace internal {
28 // Helper to compute product of compile-time dimensions, returning Dynamic if either is Dynamic.
29 constexpr int product(int a, int b) {
30 return (a == Eigen::Dynamic || b == Eigen::Dynamic) ? Eigen::Dynamic : a * b;
31 }
32
33 // Helper to compute the matrix of vectorized generators for fixed-size groups.
34 template<class Class, int D, int N>
35 auto computeVectorizedGenerators() {
36 static_assert(D != Eigen::Dynamic && N != Eigen::Dynamic,
37 "This helper is only for fixed-size Lie groups.");
38 Eigen::Matrix<double, N* N, D> P;
39 for (int i = 0; i < D; ++i) {
40 const auto G_i = Class::Hat(Class::TangentVector::Unit(D, i));
41 P.col(i) = Eigen::Map<const Eigen::Matrix<double, N* N, 1>>(G_i.data());
42 }
43 return P;
44 }
45 } // namespace internal
46
50 template<class Class, int D, int N>
51 struct MatrixLieGroup : public LieGroup<Class, D> {
52 using Base = LieGroup<Class, D>;
53 using Base::dimension;
54 using Base::Dim;
55 using Base::dim;
56 using ChartJacobian = typename Base::ChartJacobian;
57 using Jacobian = typename Base::Jacobian;
58 using TangentVector = typename Base::TangentVector;
59 using Vectorized = Eigen::Matrix<double, internal::product(N, N), 1>;
60 using VectorizedJacobian =
61 OptionalJacobian<internal::product(N, N), D>;
62
65
75 Eigen::Matrix<double, internal::product(N, N), 1> vec(
76 OptionalJacobian<internal::product(N, N), D> H = {}) const {
77 const auto& derived = static_cast<const Class&>(*this);
78 const auto& T = derived.matrix();
79
80 if (H) {
81 if constexpr (N != Eigen::Dynamic && D != Eigen::Dynamic) { // Fixed-size case
82 const auto& P = VectorizedGenerators();
83 for (int i = 0; i < N; ++i) {
84 H->block(i * N, 0, N, D) = T * P.block(i * N, 0, N, D);
85 }
86 }
87 else { // Dynamic-size case
88 const size_t n = T.rows();
89 const size_t d = derived.dim();
90 H->resize(n * n, d);
91
92 // Create P, the matrix of vectorized generators, on the fly.
93 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> P(n * n, d);
94 for (size_t j = 0; j < d; ++j) {
95 const auto G_j = Class::Hat(TangentVector::Unit(d, j));
96 P.col(j) = Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, 1>>(
97 G_j.data(), n * n);
98 }
99
100 // Apply the formula H = (I_n ⊗ T) * P.
101 for (size_t i = 0; i < n; ++i) {
102 H->block(i * n, 0, n, d) = T * P.block(i * n, 0, n, d);
103 }
104 }
105 }
106
107 if constexpr (N != Eigen::Dynamic) { // Fixed-size case
108 return Eigen::Map<const Eigen::Matrix<double, N* N, 1>>(T.data());
109 }
110 else { // Dynamic-size case
111 return Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, 1>>(
112 T.data(), T.size());
113 }
114 }
115
125 Jacobian AdjointMap() const {
126 const auto& m = static_cast<const Class&>(*this);
127 size_t d = D;
128 if constexpr (D == Eigen::Dynamic) d = m.dim();
129 Jacobian adj(d, d);
130 const auto T_mat = m.matrix();
131 const auto T_inv_mat = m.inverse().matrix();
132 for (size_t i = 0; i < d; i++) {
133 // TangentVector::Unit(d, i) works for both fixed and dynamic size vectors.
134 const auto G_i = Class::Hat(TangentVector::Unit(d, i));
135 adj.col(i) = Class::Vee(T_mat * G_i * T_inv_mat);
136 }
137 return adj;
138 }
139
145 TangentVector Adjoint(const TangentVector& xi,
146 ChartJacobian H_this = {},
147 ChartJacobian H_xi = {}) const {
148 const auto& m = static_cast<const Class&>(*this);
149 const Jacobian Ad = m.AdjointMap();
150 if (H_this) *H_this = -Ad * Class::adjointMap(xi);
151 if (H_xi) *H_xi = Ad;
152 return Ad * xi;
153 }
154
160 TangentVector AdjointTranspose(const TangentVector& x,
161 ChartJacobian H_this = {},
162 ChartJacobian H_x = {}) const {
163 const auto& m = static_cast<const Class&>(*this);
164 const Jacobian Ad = m.AdjointMap();
165 const TangentVector AdTx = Ad.transpose() * x;
166
167 if (H_this) {
168 const Eigen::Index d = tangentDim(&m, nullptr);
169 setZeroJacobian(H_this, d);
170 if constexpr (D == Eigen::Dynamic) {
171 for (Eigen::Index i = 0; i < d; ++i) {
172 H_this->col(i) =
173 Class::adjointMap(TangentVector::Unit(d, i)).transpose() * AdTx;
174 }
175 } else {
176 const auto& basis = adjointBasis();
177 for (Eigen::Index i = 0; i < d; ++i) {
178 H_this->col(i) = basis[static_cast<size_t>(i)].transpose() * AdTx;
179 }
180 }
181 }
182
183 if (H_x) *H_x = Ad.transpose();
184 return AdTx;
185 }
186
191 static Jacobian adjointMap(const TangentVector& xi) {
192 const Eigen::Index d = tangentDim(nullptr, &xi);
193 Jacobian ad;
194 if constexpr (D == Eigen::Dynamic) {
195 ad.setZero(d, d);
196 } else {
197 ad.setZero();
198 }
199 const auto Xi = Class::Hat(xi);
200 for (Eigen::Index i = 0; i < d; ++i) {
201 const auto Ei = Class::Hat(TangentVector::Unit(d, i));
202 ad.col(i) = Class::Vee(Xi * Ei - Ei * Xi);
203 }
204 return ad;
205 }
206
210 static TangentVector adjoint(const TangentVector& xi,
211 const TangentVector& y, ChartJacobian Hxi = {},
212 ChartJacobian H_y = {}) {
213 const Jacobian ad_xi = Class::adjointMap(xi);
214 if (Hxi) *Hxi = -Class::adjointMap(y);
215 if (H_y) *H_y = ad_xi;
216 return ad_xi * y;
217 }
218
222 static TangentVector adjointTranspose(const TangentVector& xi,
223 const TangentVector& y,
224 ChartJacobian Hxi = {},
225 ChartJacobian H_y = {}) {
226 const Jacobian adT_xi = Class::adjointMap(xi).transpose();
227 if (Hxi) {
228 const Eigen::Index d = tangentDim(nullptr, &xi);
229 setZeroJacobian(Hxi, d);
230 if constexpr (D == Eigen::Dynamic) {
231 for (Eigen::Index i = 0; i < d; ++i) {
232 Hxi->col(i) =
233 Class::adjointMap(TangentVector::Unit(d, i)).transpose() * y;
234 }
235 } else {
236 const auto& basis = adjointBasis();
237 for (Eigen::Index i = 0; i < d; ++i) {
238 Hxi->col(i) = basis[static_cast<size_t>(i)].transpose() * y;
239 }
240 }
241 }
242 if (H_y) *H_y = adT_xi;
243 return adT_xi * y;
244 }
245
247
248 private:
249 static Eigen::Index tangentDim(const Class* m, const TangentVector* xi) {
250 if constexpr (D == Eigen::Dynamic) {
251 return m ? static_cast<Eigen::Index>(traits<Class>::GetDimension(*m))
252 : static_cast<Eigen::Index>(xi->size());
253 } else {
254 (void)m;
255 (void)xi;
256 return D;
257 }
258 }
259
260 static void setZeroJacobian(ChartJacobian H, Eigen::Index d) {
261 if constexpr (D == Eigen::Dynamic) {
262 H->setZero(d, d);
263 } else {
264 (void)d;
265 H->setZero();
266 }
267 }
268
270 template <int DD = D, typename std::enable_if_t<DD != Eigen::Dynamic, int> = 0>
271 static const std::array<Jacobian, DD>& adjointBasis() {
272 static const std::array<Jacobian, DD> basis = []() {
273 std::array<Jacobian, DD> B{};
274 for (int i = 0; i < DD; ++i) {
275 B[static_cast<size_t>(i)] =
276 Class::adjointMap(TangentVector::Unit(DD, i));
277 }
278 return B;
279 }();
280 return basis;
281 }
282
284 inline static const Eigen::Matrix<double, internal::product(N, N), D>&
285 VectorizedGenerators() {
286 static const auto P =
287 internal::computeVectorizedGenerators<Class, D, N>();
288 return P;
289 }
290 };
291
292 namespace internal {
293
295 template <class Class, int N> struct MatrixLieGroupTraits : LieGroupTraits<Class> {
296 using LieAlgebra = typename Class::LieAlgebra;
297 using TangentVector = typename LieGroupTraits<Class>::TangentVector;
298 using Jacobian = typename LieGroupTraits<Class>::Jacobian;
299 using ChartJacobian = typename LieGroupTraits<Class>::ChartJacobian;
300
301 static LieAlgebra Hat(const TangentVector& v) {
302 return Class::Hat(v);
303 }
304
305 static TangentVector Vee(const LieAlgebra& X) {
306 return Class::Vee(X);
307 }
308
310 static Eigen::Matrix<double, product(N, N), 1> Vec(
311 const Class& m,
312 OptionalJacobian<product(N, N),
313 LieGroupTraits<Class>::dimension> H = {}) {
314 return m.vec(H);
315 }
316
317 static TangentVector AdjointTranspose(const Class& m,
318 const TangentVector& x,
319 ChartJacobian Hm = {},
320 ChartJacobian Hx = {}) {
321 return m.AdjointTranspose(x, Hm, Hx);
322 }
323
324 static TangentVector Adjoint(const Class& m, const TangentVector& x,
325 ChartJacobian Hm = {},
326 ChartJacobian Hx = {}) {
327 return m.Adjoint(x, Hm, Hx);
328 }
329
330 static Jacobian adjointMap(const TangentVector& xi) {
331 return Class::adjointMap(xi);
332 }
333
334 static TangentVector adjoint(const TangentVector& xi,
335 const TangentVector& y,
336 ChartJacobian Hxi = {},
337 ChartJacobian H_y = {}) {
338 return Class::adjoint(xi, y, Hxi, H_y);
339 }
340
341 static TangentVector adjointTranspose(const TangentVector& xi,
342 const TangentVector& y,
343 ChartJacobian Hxi = {},
344 ChartJacobian H_y = {}) {
345 return Class::adjointTranspose(xi, y, Hxi, H_y);
346 }
347 };
348
350 template<class Class, int N> struct MatrixLieGroup : MatrixLieGroupTraits<Class, N>, Testable<Class> {};
351
352 } // \ namespace internal
353
357 template<typename T>
358 class IsMatrixLieGroup : public IsLieGroup<T> {
359 public:
360 using LieAlgebra = typename traits<T>::LieAlgebra;
361 using TangentVector = typename traits<T>::TangentVector;
362
363 GTSAM_CONCEPT_USAGE(IsMatrixLieGroup) {
364 // hat and vee
365 X = traits<T>::Hat(xi);
366 xi = traits<T>::Vee(X);
367 // vec
368 (void)traits<T>::Vec(g);
369 }
370 private:
371 T g;
372 LieAlgebra X;
373 TangentVector xi;
374 };
375
384 template<class T>
385 T BCH(const T& X, const T& Y) {
386 static const double _2 = 1. / 2., _12 = 1. / 12., _24 = 1. / 24.;
387 T X_Y = bracket(X, Y);
388 return T(X + Y + _2 * X_Y + _12 * bracket(X - Y, X_Y) - _24 * bracket(Y, bracket(X, X_Y)));
389 }
390
391#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V43
393 template <class T>
394 [[deprecated("use T::Hat instead")]] Matrix wedge(const Vector& x) {
395 return T::Hat(x);
396 }
397#endif
398
405 template <class T>
406 T expm(const Vector& x, int K = 7) {
407 const Matrix xhat = T::Hat(x);
408 return T(expm(xhat, K));
409 }
410
411} // namespace gtsam
412
413
422#define GTSAM_CONCEPT_MATRIX_LIE_GROUP_INST(T) template class gtsam::IsMatrixLieGroup<T>;
423#define GTSAM_CONCEPT_MATRIX_LIE_GROUP_TYPE(T) using _gtsam_IsMatrixLieGroup_##T = gtsam::IsMatrixLieGroup<T>;
Base class and basic functions for Lie types.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Matrix expm(const Matrix &A, size_t K)
Numerical exponential map, naive approach, not industrial strength !
Definition Matrix.cpp:587
T BCH(const T &X, const T &Y)
Three term approximation of the Baker-Campbell-Hausdorff formula In non-commutative Lie groups,...
Definition MatrixLieGroup.h:385
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
A CRTP helper class that implements Lie group methods Prerequisites: methods operator*,...
Definition Lie.h:114
static constexpr int Dim()
Definition Lie.h:121
std::enable_if_t< M !=Eigen::Dynamic, int > dim() const
Definition Lie.h:125
A helper class that implements the traits interface for GTSAM lie groups.
Definition Lie.h:281
Lie Group Concept.
Definition Lie.h:377
A CRTP helper class that implements matrix Lie group methods.
Definition MatrixLieGroup.h:51
static TangentVector adjointTranspose(const TangentVector &xi, const TangentVector &y, ChartJacobian Hxi={}, ChartJacobian H_y={})
Dual Lie algebra action ad_xi^T(y), with optional Jacobians.
Definition MatrixLieGroup.h:222
static Jacobian adjointMap(const TangentVector &xi)
Lie algebra adjoint map ad_xi, with optional specialization in derived classes.
Definition MatrixLieGroup.h:191
Jacobian AdjointMap() const
A generic implementation of AdjointMap for matrix Lie groups.
Definition MatrixLieGroup.h:125
TangentVector AdjointTranspose(const TangentVector &x, ChartJacobian H_this={}, ChartJacobian H_x={}) const
Dual Adjoint action on a tangent covector.
Definition MatrixLieGroup.h:160
static TangentVector adjoint(const TangentVector &xi, const TangentVector &y, ChartJacobian Hxi={}, ChartJacobian H_y={})
Lie algebra action ad_xi(y), with optional Jacobians.
Definition MatrixLieGroup.h:210
TangentVector Adjoint(const TangentVector &xi, ChartJacobian H_this={}, ChartJacobian H_xi={}) const
Adjoint action on a tangent vector.
Definition MatrixLieGroup.h:145
Eigen::Matrix< double, internal::product(N, N), 1 > vec(OptionalJacobian< internal::product(N, N), D > H={}) const
Vectorize the matrix representation of a Lie group element.
Definition MatrixLieGroup.h:75
Adds MatrixLieGroup methods to LieGroupTraits.
Definition MatrixLieGroup.h:295
static Eigen::Matrix< double, product(N, N), 1 > Vec(const Class &m, OptionalJacobian< product(N, N), LieGroupTraits< Class >::dimension > H={})
Vectorize the matrix representation of a Lie group element.
Definition MatrixLieGroup.h:310
Both LieGroupTraits and Testable.
Definition MatrixLieGroup.h:350
Matrix Lie Group Concept.
Definition MatrixLieGroup.h:358
OptionalJacobian is an Eigen::Ref like class that can take be constructed using either a fixed size o...
Definition OptionalJacobian.h:40
A helper that implements the traits interface for GTSAM types.
Definition Testable.h:152