gtsam
Loading...
Searching...
No Matches
VectorSpace.h
1/*
2 * VectorSpace.h
3 *
4 * @date December 21, 2014
5 * @author Mike Bosse
6 * @author Frank Dellaert
7 */
8
9#pragma once
10
11#include <gtsam/base/Lie.h>
12
13#include <cmath>
14#include <stdexcept>
15#include <utility>
16#include <vector>
17
18namespace gtsam {
19
22};
23
24template<typename T> struct traits;
25
26namespace internal {
27
29template<class Class, int N>
31
34 typedef Eigen::Matrix<double, N, 1> TangentVector;
35 typedef OptionalJacobian<N, N> ChartJacobian;
36 typedef Eigen::Matrix<double, N, N> Jacobian;
37 static size_t GetDimension(const Class&) { return static_cast<size_t>(N);}
38
39 static TangentVector Local(const Class& origin, const Class& other,
40 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
41 if (H1) *H1 = - Jacobian::Identity();
42 if (H2) *H2 = Jacobian::Identity();
43 Class v = other - origin;
44 return v.vector();
45 }
46
47 static Class Retract(const Class& origin, const TangentVector& v,
48 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
49 if (H1) *H1 = Jacobian::Identity();
50 if (H2) *H2 = Jacobian::Identity();
51 return origin + v;
52 }
53
55
58
59 typedef Eigen::Matrix<double, N, 1> LieAlgebra;
60
61 static TangentVector Logmap(const Class& m, ChartJacobian Hm = {}) {
62 if (Hm) *Hm = Jacobian::Identity();
63 return m.vector();
64 }
65
66 static Class Expmap(const TangentVector& v, ChartJacobian Hv = {}) {
67 if (Hv) *Hv = Jacobian::Identity();
68 return Class(v);
69 }
70
71 static Class Compose(const Class& v1, const Class& v2, ChartJacobian H1 = {},
72 ChartJacobian H2 = {}) {
73 if (H1) *H1 = Jacobian::Identity();
74 if (H2) *H2 = Jacobian::Identity();
75 return v1 + v2;
76 }
77
78 static Class Between(const Class& v1, const Class& v2, ChartJacobian H1 = {},
79 ChartJacobian H2 = {}) {
80 if (H1) *H1 = - Jacobian::Identity();
81 if (H2) *H2 = Jacobian::Identity();
82 return v2 - v1;
83 }
84
85 static Class Inverse(const Class& v, ChartJacobian H = {}) {
86 if (H) *H = - Jacobian::Identity();
87 return -v;
88 }
89
90 static LieAlgebra Hat(const TangentVector& v) { return v; }
91
92 static TangentVector Vee(const LieAlgebra& X) { return X; }
93
94 static Jacobian AdjointMap(const Class& /*m*/) {
95 return Jacobian::Identity();
96 }
98};
99
101template<class Class>
102struct VectorSpaceImpl<Class,Eigen::Dynamic> {
103
106 static Class Compose(const Class& v1, const Class& v2) { return v1+v2;}
107 static Class Between(const Class& v1, const Class& v2) { return v2-v1;}
108 static Class Inverse(const Class& m) { return -m;}
110
113 typedef Eigen::VectorXd TangentVector;
115 static size_t GetDimension(const Class& m) { return m.dim();}
116
117 static Eigen::MatrixXd Eye(const Class& m) {
118 size_t dim = GetDimension(m);
119 return Eigen::MatrixXd::Identity(dim, dim);
120 }
121
122 static TangentVector Local(const Class& origin, const Class& other,
123 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
124 if (H1) *H1 = - Eye(origin);
125 if (H2) *H2 = Eye(other);
126 Class v = other - origin;
127 return v.vector();
128 }
129
130 static Class Retract(const Class& origin, const TangentVector& v,
131 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
132 if (H1) *H1 = Eye(origin);
133 if (H2) *H2 = Eye(origin);
134 return origin + v;
135 }
136
138
141
142 static TangentVector Logmap(const Class& m, ChartJacobian Hm = {}) {
143 if (Hm) *Hm = Eye(m);
144 return m.vector();
145 }
146
147 static Class Expmap(const TangentVector& v, ChartJacobian Hv = {}) {
148 Class result(v);
149 if (Hv) *Hv = Eye(result);
150 return result;
151 }
152
153 static Class Compose(const Class& v1, const Class& v2, ChartJacobian H1,
154 ChartJacobian H2 = {}) {
155 if (H1) *H1 = Eye(v1);
156 if (H2) *H2 = Eye(v2);
157 return v1 + v2;
158 }
159
160 static Class Between(const Class& v1, const Class& v2, ChartJacobian H1,
161 ChartJacobian H2 = {}) {
162 if (H1) *H1 = - Eye(v1);
163 if (H2) *H2 = Eye(v2);
164 return v2 - v1;
165 }
166
167 static Class Inverse(const Class& v, ChartJacobian H) {
168 if (H) *H = -Eye(v);
169 return -v;
170 }
171
172 static Eigen::MatrixXd AdjointMap(const Class& m) { return Eye(m); }
174};
175
177template<class Class>
179
180 inline constexpr static auto dim = Class::dimension;
181
182 Class p, q;
183 Vector v;
184
185 GTSAM_CONCEPT_USAGE(HasVectorSpacePrereqs) {
186 p = Class::Identity(); // identity
187 q = p + p; // addition
188 q = p - p; // subtraction
189 v = p.vector(); // conversion to vector
190 q = p + v; // addition of a vector on the right
191 }
192};
193
198template<class Class>
199struct VectorSpaceTraits: VectorSpaceImpl<Class, Class::dimension> {
200
201 // Check that Class has the necessary machinery
202GTSAM_CONCEPT_ASSERT(HasVectorSpacePrereqs<Class>);
203
204 typedef vector_space_tag structure_category;
205
208 typedef additive_group_tag group_flavor;
209 static Class Identity() { return Class::Identity();}
211
214 inline constexpr static auto dimension = Class::dimension;
215 typedef Class ManifoldType;
217};
218
220template<class Class>
221struct VectorSpace: Testable<Class>, VectorSpaceTraits<Class> {};
222
225template<typename Scalar>
226struct ScalarTraits : VectorSpaceImpl<Scalar, 1> {
227
228 typedef vector_space_tag structure_category;
229
232 static void Print(Scalar m, const std::string& str = "") {
233 gtsam::print(m, str);
234 }
235 static bool Equals(Scalar v1, Scalar v2, double tol = 1e-8) {
236 return std::abs(v1 - v2) < tol;
237 }
239
242 typedef additive_group_tag group_flavor;
243 static Scalar Identity() { return 0;}
245
248 typedef Scalar ManifoldType;
249 inline constexpr static auto dimension = 1;
250 typedef Eigen::Matrix<double, 1, 1> TangentVector;
251 typedef OptionalJacobian<1, 1> ChartJacobian;
252
253 static TangentVector Local(Scalar origin, Scalar other,
254 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
255 if (H1) (*H1)[0] = -1.0;
256 if (H2) (*H2)[0] = 1.0;
257 TangentVector result;
258 result(0) = other - origin;
259 return result;
260 }
261
262 static Scalar Retract(Scalar origin, const TangentVector& v,
263 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
264 if (H1) (*H1)[0] = 1.0;
265 if (H2) (*H2)[0] = 1.0;
266 return origin + v[0];
267 }
269
272 static TangentVector Logmap(Scalar m, ChartJacobian H = {}) {
273 if (H) (*H)[0] = 1.0;
274 return Local(0, m);
275 }
276
277 static Scalar Expmap(const TangentVector& v, ChartJacobian H = {}) {
278 if (H) (*H)[0] = 1.0;
279 return v[0];
280 }
281 // AdjointMap for ScalarTraits is inherited from VectorSpaceImpl<Scalar, 1>
283};
284
285} // namespace internal
286
288template<> struct traits<double> : public internal::ScalarTraits<double> {
289};
290
292template<> struct traits<float> : public internal::ScalarTraits<float> {
293};
294
295// traits for any fixed double Eigen matrix
296template<int M, int N, int Options, int MaxRows, int MaxCols>
297struct traits<Eigen::Matrix<double, M, N, Options, MaxRows, MaxCols> > :
299 Eigen::Matrix<double, M, N, Options, MaxRows, MaxCols>, M * N> {
300
301 typedef vector_space_tag structure_category;
302 typedef Eigen::Matrix<double, M, N, Options, MaxRows, MaxCols> Fixed;
303
306 static void Print(const Fixed& m, const std::string& str = "") {
307 gtsam::print(Eigen::MatrixXd(m), str);
308 }
309 static bool Equals(const Fixed& v1, const Fixed& v2, double tol = 1e-8) {
310 return equal_with_abs_tol(v1, v2, tol);
311 }
313
316 typedef additive_group_tag group_flavor;
317 static Fixed Identity() { return Fixed::Zero();}
319
322 inline constexpr static auto dimension = M * N;
323 typedef Fixed ManifoldType;
324 typedef Eigen::Matrix<double, dimension, 1> TangentVector;
325 typedef Eigen::Matrix<double, dimension, dimension> Jacobian;
326 typedef OptionalJacobian<dimension, dimension> ChartJacobian;
327
329 inline constexpr static int QcqpVectorDim = dimension + 1;
330
332 template <int D>
333 static Matrix QcqpValue(const Fixed& value) {
334 if constexpr (D == 1) {
335 Matrix result(QcqpVectorDim, 1);
336 result(0, 0) = 1.0;
337 result.col(0).tail(dimension) =
338 Eigen::Map<const TangentVector>(value.data());
339 return result;
340 } else {
341 throw std::invalid_argument(
342 "fixed-size vector-space QCQP values only support D=1.");
343 }
344 }
345
347 template <int D>
348 static std::vector<std::pair<Matrix, double>> QcqpConstraints() {
349 if constexpr (D == 1) {
350 Matrix A = Matrix::Zero(QcqpVectorDim, QcqpVectorDim);
351 A(0, 0) = 1.0;
352 return {{A, 1.0}};
353 } else {
354 throw std::invalid_argument(
355 "fixed-size vector-space QCQP constraints only support D=1.");
356 }
357 }
358
360 template <int D>
361 static Fixed FromQcqpValue(const Matrix& qcqpValue) {
362 if constexpr (D == 1) {
363 if (qcqpValue.rows() != QcqpVectorDim || qcqpValue.cols() != 1 ||
364 std::abs(qcqpValue(0, 0)) < 1e-12) {
365 throw std::invalid_argument(
366 "fixed-size vector-space QCQP recovery requires a compatible "
367 "homogeneous vector.");
368 }
369 Fixed result;
370 Eigen::Map<TangentVector>(result.data()) =
371 qcqpValue.col(0).tail(dimension) / qcqpValue(0, 0);
372 return result;
373 } else {
374 throw std::invalid_argument(
375 "fixed-size vector-space QCQP recovery only supports D=1.");
376 }
377 }
378
379 static TangentVector Local(const Fixed& origin, const Fixed& other,
380 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
381 if (H1) (*H1) = -Jacobian::Identity();
382 if (H2) (*H2) = Jacobian::Identity();
383 TangentVector result;
384 Eigen::Map<Fixed>(result.data()) = other - origin;
385 return result;
386 }
387
388 static Fixed Retract(const Fixed& origin, const TangentVector& v,
389 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
390 if (H1) (*H1) = Jacobian::Identity();
391 if (H2) (*H2) = Jacobian::Identity();
392 return origin + Eigen::Map<const Fixed>(v.data());
393 }
395
398 static TangentVector Logmap(const Fixed& m, ChartJacobian H = {}) {
399 if (H) *H = Jacobian::Identity();
400 TangentVector result;
401 Eigen::Map<Fixed>(result.data()) = m;
402 return result;
403 }
404
405 static Fixed Expmap(const TangentVector& v, ChartJacobian H = {}) {
406 Fixed m;
407 m.setZero();
408 if (H) *H = Jacobian::Identity();
409 return m + Eigen::Map<const Fixed>(v.data());
410 }
411
412 // AdjointMap for fixed-size Eigen matrices is inherited from
413 // internal::VectorSpaceImpl< Eigen::Matrix<double, M, N, ...> , M*N >
415};
416
417
418namespace internal {
419
420// traits for dynamic Eigen matrices
421template<int M, int N, int Options, int MaxRows, int MaxCols>
423
424 typedef vector_space_tag structure_category;
425 typedef Eigen::Matrix<double, M, N, Options, MaxRows, MaxCols> Dynamic;
426
429 static void Print(const Dynamic& m, const std::string& str = "") {
430 gtsam::print(Eigen::MatrixXd(m), str);
431 }
432 static bool Equals(const Dynamic& v1, const Dynamic& v2,
433 double tol = 1e-8) {
434 return equal_with_abs_tol(v1, v2, tol);
435 }
437
440 typedef additive_group_tag group_flavor;
441 static Dynamic Identity() {
442 throw std::runtime_error("Identity not defined for dynamic types");
443 }
445
448 inline constexpr static auto dimension = Eigen::Dynamic;
449 typedef Eigen::VectorXd TangentVector;
450 typedef Eigen::MatrixXd Jacobian;
451 typedef OptionalJacobian<dimension, dimension> ChartJacobian;
452 typedef Dynamic ManifoldType;
453
454 static size_t GetDimension(const Dynamic& m) {
455 return static_cast<size_t>(m.rows() * m.cols());
456 }
457
458 static Jacobian Eye(const Dynamic& m) {
459 size_t dim = GetDimension(m);
460 return Eigen::Matrix<double, dimension, dimension>::Identity(dim, dim);
461 }
462
463 static TangentVector Local(const Dynamic& m, const Dynamic& other, //
464 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
465 if (H1) *H1 = -Eye(m);
466 if (H2) *H2 = Eye(m);
467 TangentVector v(GetDimension(m));
468 Eigen::Map<Dynamic>(v.data(), m.rows(), m.cols()) = other - m;
469 return v;
470 }
471
472 static Dynamic Retract(const Dynamic& m, const TangentVector& v, //
473 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
474 if (H1) *H1 = Eye(m);
475 if (H2) *H2 = Eye(m);
476 return m + Eigen::Map<const Dynamic>(v.data(), m.rows(), m.cols());
477 }
479
482 using LieAlgebra = Dynamic;
483
484 static TangentVector Logmap(const Dynamic& m, ChartJacobian H = {}) {
485 if (H) *H = Eye(m);
486 TangentVector result(GetDimension(m));
487 Eigen::Map<Dynamic>(result.data(), m.rows(), m.cols()) = m;
488 return result;
489 }
490
491 static Dynamic Expmap(const TangentVector& v, ChartJacobian H = {}) {
492 if constexpr (M == Eigen::Dynamic && N == Eigen::Dynamic) {
493 static_cast<void>(v);
494 static_cast<void>(H);
495 throw std::runtime_error("Expmap not defined for fully dynamic matrices");
496 } else {
497 const int rows = (M == Eigen::Dynamic) ? v.size() / N : M;
498 const int cols = (N == Eigen::Dynamic) ? v.size() / M : N;
499 if (rows * cols != v.size()) {
500 throw std::invalid_argument(
501 "Dynamic Expmap tangent dimension does not match matrix shape");
502 }
503 Dynamic result(rows, cols);
504 result = Eigen::Map<const Dynamic>(v.data(), rows, cols);
505 if (H) *H = Jacobian::Identity(v.size(), v.size());
506 return result;
507 }
508 }
509
510 static Dynamic Inverse(const Dynamic& m, ChartJacobian H = {}) {
511 if (H) *H = -Eye(m);
512 return -m;
513 }
514
515 static Dynamic Compose(const Dynamic& v1, const Dynamic& v2,
516 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
517 if (H1) *H1 = Eye(v1);
518 if (H2) *H2 = Eye(v1);
519 return v1 + v2;
520 }
521
522 static Dynamic Between(const Dynamic& v1, const Dynamic& v2,
523 ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
524 if (H1) *H1 = -Eye(v1);
525 if (H2) *H2 = Eye(v1);
526 return v2 - v1;
527 }
528
529 static LieAlgebra Hat(const TangentVector& v) {
530 return v;
531 }
532
533 static TangentVector Vee(const LieAlgebra& X) {
534 return X;
535 }
536
537 static Jacobian AdjointMap(const Dynamic& m) { return Eye(m); }
539
540};
541
542} // \ internal
543
544// traits for fully dynamic matrix
545template<int Options, int MaxRows, int MaxCols>
546struct traits<Eigen::Matrix<double, -1, -1, Options, MaxRows, MaxCols> > :
547 public internal::DynamicTraits<-1, -1, Options, MaxRows, MaxCols> {
548};
549
550// traits for dynamic column vector
551template<int Options, int MaxRows, int MaxCols>
552struct traits<Eigen::Matrix<double, -1, 1, Options, MaxRows, MaxCols> > :
553 public internal::DynamicTraits<-1, 1, Options, MaxRows, MaxCols> {
554};
555
556// traits for dynamic row vector
557template<int Options, int MaxRows, int MaxCols>
558struct traits<Eigen::Matrix<double, 1, -1, Options, MaxRows, MaxCols> > :
559 public internal::DynamicTraits<1, -1, Options, MaxRows, MaxCols> {
560};
561
563template<typename T>
564class IsVectorSpace: public IsLieGroup<T> {
565public:
566
567 typedef typename traits<T>::structure_category structure_category_tag;
568
569 GTSAM_CONCEPT_USAGE(IsVectorSpace) {
570 static_assert(
571 (std::is_base_of<vector_space_tag, structure_category_tag>::value),
572 "This type's trait does not assert it as a vector space (or derived)");
573 r = p + q;
574 r = -p;
575 r = p - q;
576 }
577
578private:
579 T p, q, r;
580};
581
582} // namespace gtsam
Base class and basic functions for Lie types.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
void print(const Matrix &A, const string &s, ostream &stream)
print without optional string, must specify cout yourself
Definition Matrix.cpp:143
@ Logmap
Use the SE_2(3) NavState Logmap for every backend.
Definition PreintegrationParams.h:32
bool equal_with_abs_tol(const Eigen::DenseBase< MATRIX > &A, const Eigen::DenseBase< MATRIX > &B, double tol=1e-9)
equals with a tolerance
Definition Matrix.h:81
Definition Group.h:35
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
tag to assert a type is a Lie group
Definition Lie.h:271
Lie Group Concept.
Definition Lie.h:377
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
tag to assert a type is a vector space
Definition VectorSpace.h:21
VectorSpaceTraits Implementation for Fixed sizes.
Definition VectorSpace.h:30
Requirements on type to pass it to Manifold template below.
Definition VectorSpace.h:178
A helper that implements the traits interface for classes that define vector spaces To use this for y...
Definition VectorSpace.h:199
VectorSpace provides both Testable and VectorSpaceTraits.
Definition VectorSpace.h:221
A helper that implements the traits interface for scalar vector spaces.
Definition VectorSpace.h:226
static Matrix QcqpValue(const Fixed &value)
Return the exact D=1 homogeneous QCQP representation.
Definition VectorSpace.h:333
static std::vector< std::pair< Matrix, double > > QcqpConstraints()
Return the homogeneous-coordinate constraint x(0)^2 = 1.
Definition VectorSpace.h:348
static constexpr int QcqpVectorDim
Dimension of the exact D=1 homogeneous QCQP vector [1; vec(value)].
Definition VectorSpace.h:329
static Fixed FromQcqpValue(const Matrix &qcqpValue)
Recover a fixed-size value from its exact D=1 homogeneous QCQP vector.
Definition VectorSpace.h:361
Definition VectorSpace.h:422
Vector Space concept.
Definition VectorSpace.h:564