gtsam
Loading...
Searching...
No Matches
Lie.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
22
23#pragma once
24
25#include <gtsam/base/Group.h>
26#include <gtsam/base/Manifold.h>
27
28#include <type_traits>
29#include <utility>
30
31namespace gtsam {
32
33namespace internal {
34
36template <class C, class TangentVector, class ChartJacobian>
37using ExpmapWithJacobian = decltype(C::Expmap(
38 std::declval<const TangentVector&>(), std::declval<ChartJacobian>()));
39
41template <class C, class ChartJacobian>
42using LogmapWithJacobian = decltype(
43 C::Logmap(std::declval<const C&>(), std::declval<ChartJacobian>()));
44
46constexpr int dimensionSum(int n, int m) {
47 return n == Eigen::Dynamic || m == Eigen::Dynamic ? Eigen::Dynamic : n + m;
48}
49
51constexpr int dimensionProduct(int n, int m) {
52 return n == Eigen::Dynamic || m == Eigen::Dynamic ? Eigen::Dynamic : n * m;
53}
54
64template <class Class, int N>
66 using TangentVector = Eigen::Matrix<double, N, 1>;
67 using ChartJacobian = OptionalJacobian<N, N>;
68
69 static Class Retract(const TangentVector& v) {
70 if constexpr (N == Eigen::Dynamic) {
71 return Class::Expmap(v);
72 } else {
73 return Class::Identity().retract(v);
74 }
75 }
76
77 template <class C = Class,
79 static Class Retract(const TangentVector& v, ChartJacobian H) {
80 if constexpr (N == Eigen::Dynamic) {
81 return Class::Expmap(v, H);
82 } else {
83 return Class::Identity().retract(v, {}, H);
84 }
85 }
86
87 static TangentVector Local(const Class& value) {
88 if constexpr (N == Eigen::Dynamic) {
89 return Class::Logmap(value);
90 } else {
91 return Class::Identity().localCoordinates(value);
92 }
93 }
94
95 template <class C = Class,
97 static TangentVector Local(const Class& value, ChartJacobian H) {
98 if constexpr (N == Eigen::Dynamic) {
99 return Class::Logmap(value, H);
100 } else {
101 return Class::Identity().localCoordinates(value, {}, H);
102 }
103 }
104};
105
106} // namespace internal
107
113template <class Class, int N>
114struct LieGroup {
115 inline constexpr static auto dimension = N;
116 typedef OptionalJacobian<N, N> ChartJacobian;
117 typedef Eigen::Matrix<double, N, N> Jacobian;
118 typedef Eigen::Matrix<double, N, 1> TangentVector;
119
121 static constexpr int Dim() { return N; }
122
124 template <int M = N>
125 std::enable_if_t<M != Eigen::Dynamic, int> dim() const {
126 return N;
127 }
128
129 const Class& derived() const { return static_cast<const Class&>(*this); }
130
131 Class compose(const Class& g) const { return derived() * g; }
132
133 Class between(const Class& g) const { return derived().inverse() * g; }
134
135 Class compose(const Class& g, ChartJacobian H1, ChartJacobian H2 = {}) const {
136 if (H1) *H1 = g.inverse().AdjointMap();
137 if (H2) *H2 = identityMatrix();
138 return derived() * g;
139 }
140
141 Class between(const Class& g, ChartJacobian H1, ChartJacobian H2 = {}) const {
142 Class result = derived().inverse() * g;
143 if (H1) *H1 = -result.inverse().AdjointMap();
144 if (H2) *H2 = identityMatrix();
145 return result;
146 }
147
148 Class inverse(ChartJacobian H) const {
149 if (H) *H = -derived().AdjointMap();
150 return derived().inverse();
151 }
152
155 Class expmap(const TangentVector& v) const {
156 return compose(Class::Expmap(v));
157 }
158
161 TangentVector logmap(const Class& g) const {
162 return Class::Logmap(between(g));
163 }
164
166 template <class C = Class,
167 class = internal::ExpmapWithJacobian<C, TangentVector,
168 ChartJacobian>>
169 Class expmap(const TangentVector& v, //
170 ChartJacobian H1, ChartJacobian H2 = {}) const {
171 Jacobian D_g_v;
172 Class g = Class::Expmap(v, H2 ? &D_g_v : 0);
173 Class h = compose(g); // derivatives inlined below
174 if (H1) *H1 = g.inverse().AdjointMap();
175 if (H2) *H2 = D_g_v;
176 return h;
177 }
178
180 template <class C = Class,
181 class = internal::LogmapWithJacobian<C, ChartJacobian>>
182 TangentVector logmap(const Class& g, //
183 ChartJacobian H1, ChartJacobian H2 = {}) const {
184 Class h = between(g); // derivatives inlined below
185 Jacobian D_v_h;
186 TangentVector v = Class::Logmap(h, (H1 || H2) ? &D_v_h : 0);
187 if (H1) *H1 = -D_v_h * h.inverse().AdjointMap();
188 if (H2) *H2 = D_v_h;
189 return v;
190 }
191
193 static Class Retract(const TangentVector& v) {
194 return Class::ChartAtOrigin::Retract(v);
195 }
196
199 static TangentVector LocalCoordinates(const Class& g) {
200 return Class::ChartAtOrigin::Local(g);
201 }
202
204 template <class C = Class, class = decltype(C::ChartAtOrigin::Retract(
205 std::declval<const TangentVector&>(),
206 std::declval<ChartJacobian>()))>
207 static Class Retract(const TangentVector& v, ChartJacobian H) {
208 return Class::ChartAtOrigin::Retract(v, H);
209 }
210
212 template <class C = Class,
213 class = decltype(C::ChartAtOrigin::Local(
214 std::declval<const C&>(), std::declval<ChartJacobian>()))>
215 static TangentVector LocalCoordinates(const Class& g, ChartJacobian H) {
216 return Class::ChartAtOrigin::Local(g, H);
217 }
218
220 Class retract(const TangentVector& v) const {
221 return compose(Class::ChartAtOrigin::Retract(v));
222 }
223
226 TangentVector localCoordinates(const Class& g) const {
227 return Class::ChartAtOrigin::Local(between(g));
228 }
229
231 template <class C = Class, class = decltype(C::ChartAtOrigin::Retract(
232 std::declval<const TangentVector&>(),
233 std::declval<ChartJacobian>()))>
234 Class retract(const TangentVector& v, //
235 ChartJacobian H1, ChartJacobian H2 = {}) const {
236 Jacobian D_g_v;
237 Class g = Class::ChartAtOrigin::Retract(v, H2 ? &D_g_v : 0);
238 Class h = compose(g); // derivatives inlined below
239 if (H1) *H1 = g.inverse().AdjointMap();
240 if (H2) *H2 = D_g_v;
241 return h;
242 }
243
245 template <class C = Class,
246 class = decltype(C::ChartAtOrigin::Local(
247 std::declval<const C&>(), std::declval<ChartJacobian>()))>
248 TangentVector localCoordinates(const Class& g, //
249 ChartJacobian H1,
250 ChartJacobian H2 = {}) const {
251 Class h = between(g); // derivatives inlined below
252 Jacobian D_v_h;
253 TangentVector v = Class::ChartAtOrigin::Local(h, (H1 || H2) ? &D_v_h : 0);
254 if (H1) *H1 = -D_v_h * h.inverse().AdjointMap();
255 if (H2) *H2 = D_v_h;
256 return v;
257 }
258
259 private:
260 // Helper to get identity matrix of correct size for static or dynamic N
261 Jacobian identityMatrix() const {
262 if constexpr (N == Eigen::Dynamic) {
263 return Jacobian::Identity(derived().dim(), derived().dim());
264 } else {
265 return Jacobian::Identity();
266 }
267 }
268};
269
271struct lie_group_tag : public manifold_tag, public group_tag {};
272
273namespace internal {
274
280template <class Class>
282 using Manifold = ManifoldTraits<Class>;
283 using structure_category = lie_group_tag;
284
287 using group_flavor = multiplicative_group_tag;
288 static Class Identity() { return Class::Identity(); }
290
293 using typename Manifold::ChartJacobian;
294 using typename Manifold::ManifoldType;
295 using typename Manifold::TangentVector;
296 inline constexpr static auto dimension = Manifold::dimension;
297 using Jacobian = Eigen::Matrix<double, dimension, dimension>;
299
302 static TangentVector Logmap(const Class& m) { return Class::Logmap(m); }
303
304 template <class C = Class,
306 static TangentVector Logmap(const Class& m, ChartJacobian Hm) {
307 return Class::Logmap(m, Hm);
308 }
309
310 static Class Expmap(const TangentVector& v) { return Class::Expmap(v); }
311
312 template <class C = Class,
314 static Class Expmap(const TangentVector& v, ChartJacobian Hv) {
315 return Class::Expmap(v, Hv);
316 }
317
318 static Class Compose(const Class& m1, const Class& m2, //
319 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
320 return m1.compose(m2, H1, H2);
321 }
322
323 static Class Between(const Class& m1, const Class& m2, //
324 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
325 return m1.between(m2, H1, H2);
326 }
327
328 static Class Inverse(const Class& m, //
329 ChartJacobian H = {}) {
330 return m.inverse(H);
331 }
332
333 static Eigen::Matrix<double, dimension, dimension> AdjointMap(
334 const Class& m) {
335 // This assumes that the Class itself provides a member function
336 // `AdjointMap()` For dynamically-sized types (dimension == Eigen::Dynamic),
337 // m.AdjointMap() must return a gtsam::Matrix of the correct runtime
338 // dimensions.
339 return m.AdjointMap();
340 }
342};
343
345template <class Class>
346struct LieGroup : LieGroupTraits<Class>, Testable<Class> {};
347
348} // namespace internal
349
354
356template <class Class>
357inline Class between_default(const Class& l1, const Class& l2) {
358 return l1.inverse().compose(l2);
359}
360
362template <class Class>
363inline Vector logmap_default(const Class& l0, const Class& lp) {
364 return Class::Logmap(l0.between(lp));
365}
366
368template <class Class>
369inline Class expmap_default(const Class& t, const Vector& d) {
370 return t.compose(Class::Expmap(d));
371}
372
376template <typename T>
377class IsLieGroup : public IsGroup<T>, public IsManifold<T> {
378 public:
379 // Concept marker: allows checking IsLieGroup<T>::value in templates
380 static constexpr bool value =
381 std::is_base_of_v<lie_group_tag, typename traits<T>::structure_category>;
382
383 using structure_category_tag = typename traits<T>::structure_category;
384 using ManifoldType = typename traits<T>::ManifoldType;
385 using TangentVector = typename traits<T>::TangentVector;
386 using ChartJacobian = typename traits<T>::ChartJacobian;
387
388 GTSAM_CONCEPT_USAGE(IsLieGroup) {
389 static_assert(
390 value,
391 "This type's trait does not assert it is a Lie group (or derived)");
392
393 // group operations with Jacobians
394 g = traits<T>::Compose(g, h, Hg, Hh);
395 g = traits<T>::Between(g, h, Hg, Hh);
396 g = traits<T>::Inverse(g, Hg);
397 // log and exp map without Jacobians
398 g = traits<T>::Expmap(v);
399 v = traits<T>::Logmap(g);
400 // AdjointMap
401 *Hg = traits<T>::AdjointMap(g);
402 }
403
404 private:
405 T g, h;
406 TangentVector v;
407 ChartJacobian Hg, Hh;
408};
409
414template <typename T>
415T interpolate(const T& X, const T& Y, double t,
416 typename MakeOptionalJacobian<T, T>::type Hx = {},
417 typename MakeOptionalJacobian<T, T>::type Hy = {},
418 typename MakeOptionalJacobian<T, double>::type Ht = {}) {
419 if (Hx || Hy || Ht) {
420 typename MakeJacobian<T, T>::type between_H_x, log_H, exp_H, compose_H_x;
421 const T between =
422 traits<T>::Between(X, Y, between_H_x); // between_H_y = identity
423 typename traits<T>::TangentVector delta = traits<T>::Logmap(between, log_H);
424 const T Delta = traits<T>::Expmap(t * delta, exp_H);
425 const T result = traits<T>::Compose(
426 X, Delta, compose_H_x); // compose_H_xinv_y = identity
427
428 if (Hx) *Hx = compose_H_x + t * exp_H * log_H * between_H_x;
429 if (Hy) *Hy = t * exp_H * log_H;
430 if (Ht) *Ht = delta;
431 return result;
432 }
433 return traits<T>::Compose(
435}
436
441template <class T>
442class TransformCovariance {
443 private:
444 typename T::Jacobian adjointMap_;
445
446 public:
447 explicit TransformCovariance(const T& X) : adjointMap_{X.AdjointMap()} {}
448 typename T::Jacobian operator()(const typename T::Jacobian& covariance) {
449 return adjointMap_ * covariance * adjointMap_.transpose();
450 }
451};
452
453} // namespace gtsam
454
463#define GTSAM_CONCEPT_LIE_INST(T) template class gtsam::IsLieGroup<T>;
464#define GTSAM_CONCEPT_LIE_TYPE(T) \
465 using _gtsam_IsLieGroup_##T = gtsam::IsLieGroup<T>;
Concept check class for variable types with Group properties.
Base class and basic functions for Manifold types.
constexpr int dimensionSum(int n, int m)
Sum compile-time dimensions, propagating Eigen::Dynamic.
Definition Lie.h:46
decltype(C::Expmap( std::declval< const TangentVector & >(), std::declval< ChartJacobian >())) ExpmapWithJacobian
Probe for a class static Expmap implementation with a Jacobian.
Definition Lie.h:37
constexpr int dimensionProduct(int n, int m)
Multiply compile-time dimensions, propagating Eigen::Dynamic.
Definition Lie.h:51
decltype( C::Logmap(std::declval< const C & >(), std::declval< ChartJacobian >())) LogmapWithJacobian
Probe for a class static Logmap implementation with a Jacobian.
Definition Lie.h:42
Global functions in a separate testing namespace.
Definition chartTesting.h:28
T interpolate(const T &X, const T &Y, double t, typename MakeOptionalJacobian< T, T >::type Hx={}, typename MakeOptionalJacobian< T, T >::type Hy={}, typename MakeOptionalJacobian< T, double >::type Ht={})
Linear interpolation between X and Y by coefficient t.
Definition Lie.h:415
Vector logmap_default(const Class &l0, const Class &lp)
Log map centered at l0, s.t.
Definition Lie.h:363
@ Logmap
Use the SE_2(3) NavState Logmap for every backend.
Definition PreintegrationParams.h:32
Class between_default(const Class &l1, const Class &l2)
These core global functions can be specialized by new Lie types for better performance.
Definition Lie.h:357
Class expmap_default(const Class &t, const Vector &d)
Exponential map centered at l0, s.t.
Definition Lie.h:369
tag to assert a type is a group
Definition Group.h:31
Group operator syntax flavors.
Definition Group.h:34
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
Group Concept.
Definition Group.h:43
Chart-at-origin adapter for LieGroup-derived classes with explicit instance retract/localCoordinates ...
Definition Lie.h:65
A CRTP helper class that implements Lie group methods Prerequisites: methods operator*,...
Definition Lie.h:114
static TangentVector LocalCoordinates(const Class &g, ChartJacobian H)
LocalCoordinates at origin with optional derivative, when provided.
Definition Lie.h:215
Class expmap(const TangentVector &v, ChartJacobian H1, ChartJacobian H2={}) const
expmap with optional derivatives, when the class provides them
Definition Lie.h:169
TangentVector localCoordinates(const Class &g) const
localCoordinates as required by manifold concept: finds tangent vector between *this and g
Definition Lie.h:226
static constexpr int Dim()
Static method to get the dimension (compile-time or dynamic).
Definition Lie.h:121
TangentVector localCoordinates(const Class &g, ChartJacobian H1, ChartJacobian H2={}) const
localCoordinates with optional derivatives, when the chart provides them
Definition Lie.h:248
TangentVector logmap(const Class &g, ChartJacobian H1, ChartJacobian H2={}) const
logmap with optional derivatives, when the class provides them
Definition Lie.h:182
static Class Retract(const TangentVector &v, ChartJacobian H)
Retract at origin with optional derivative, when the chart provides it.
Definition Lie.h:207
Class retract(const TangentVector &v, ChartJacobian H1, ChartJacobian H2={}) const
retract with optional derivatives, when the chart provides them
Definition Lie.h:234
TangentVector logmap(const Class &g) const
logmap as required by manifold concept Applies logarithmic map to group element that takes *this to g
Definition Lie.h:161
static TangentVector LocalCoordinates(const Class &g)
LocalCoordinates at origin: possible in Lie group because it has an identity.
Definition Lie.h:199
Class retract(const TangentVector &v) const
retract as required by manifold concept: applies v at *this
Definition Lie.h:220
Class expmap(const TangentVector &v) const
expmap as required by manifold concept Applies exponential map to v and composes with *this
Definition Lie.h:155
static Class Retract(const TangentVector &v)
Retract at origin: possible in Lie group because it has an identity.
Definition Lie.h:193
std::enable_if_t< M !=Eigen::Dynamic, int > dim() const
Provided fixed dimension in dim() if needed.
Definition Lie.h:125
tag to assert a type is a Lie group
Definition Lie.h:271
A helper class that implements the traits interface for GTSAM lie groups.
Definition Lie.h:281
Both LieGroupTraits and Testable.
Definition Lie.h:346
Lie Group Concept.
Definition Lie.h:377
tag to assert a type is a manifold
Definition Manifold.h:33
A helper that implements the traits interface for GTSAM manifolds.
Definition Manifold.h:104
Manifold concept.
Definition Manifold.h:172
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