Specialized Hat/Vee
parent
d376d0158d
commit
ab1be9c4de
|
@ -22,62 +22,16 @@
|
|||
|
||||
namespace gtsam {
|
||||
|
||||
// Implementation for N>5 just uses dynamic version
|
||||
template <int N>
|
||||
Matrix SO<N>::Hat(const Vector& xi) {
|
||||
size_t n = AmbientDim(xi.size());
|
||||
if (n < 2) throw std::invalid_argument("SO<N>::Hat: n<2 not supported");
|
||||
|
||||
Matrix X(n, n); // allocate space for n*n skew-symmetric matrix
|
||||
X.setZero();
|
||||
if (n == 2) {
|
||||
// Handle SO(2) case as recursion bottom
|
||||
assert(xi.size() == 1);
|
||||
X << 0, -xi(0), xi(0), 0;
|
||||
} else {
|
||||
// Recursively call SO(n-1) call for top-left block
|
||||
const size_t dmin = (n - 1) * (n - 2) / 2;
|
||||
X.topLeftCorner(n - 1, n - 1) = Hat(xi.tail(dmin));
|
||||
|
||||
// Now fill last row and column
|
||||
double sign = 1.0;
|
||||
for (size_t i = 0; i < n - 1; i++) {
|
||||
const size_t j = n - 2 - i;
|
||||
X(n - 1, j) = sign * xi(i);
|
||||
X(j, n - 1) = -X(n - 1, j);
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
return X;
|
||||
typename SO<N>::MatrixNN SO<N>::Hat(const TangentVector& xi) {
|
||||
return SOn::Hat(xi);
|
||||
}
|
||||
|
||||
// Implementation for N>5 just uses dynamic version
|
||||
template <int N>
|
||||
Vector SO<N>::Vee(const Matrix& X) {
|
||||
const size_t n = X.rows();
|
||||
if (n < 2) throw std::invalid_argument("SO<N>::Hat: n<2 not supported");
|
||||
|
||||
if (n == 2) {
|
||||
// Handle SO(2) case as recursion bottom
|
||||
Vector xi(1);
|
||||
xi(0) = X(1, 0);
|
||||
return xi;
|
||||
} else {
|
||||
// Calculate dimension and allocate space
|
||||
const size_t d = n * (n - 1) / 2;
|
||||
Vector xi(d);
|
||||
|
||||
// Fill first n-1 spots from last row of X
|
||||
double sign = 1.0;
|
||||
for (size_t i = 0; i < n - 1; i++) {
|
||||
const size_t j = n - 2 - i;
|
||||
xi(i) = sign * X(n - 1, j);
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
// Recursively call Vee to fill remainder of x
|
||||
const size_t dmin = (n - 1) * (n - 2) / 2;
|
||||
xi.tail(dmin) = Vee(X.topLeftCorner(n - 1, n - 1));
|
||||
return xi;
|
||||
}
|
||||
typename SO<N>::TangentVector SO<N>::Vee(const MatrixNN& X) {
|
||||
return SOn::Vee(X);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
|
|
|
@ -20,6 +20,64 @@
|
|||
|
||||
namespace gtsam {
|
||||
|
||||
template <>
|
||||
Matrix SOn::Hat(const Vector& xi) {
|
||||
size_t n = AmbientDim(xi.size());
|
||||
if (n < 2) throw std::invalid_argument("SO<N>::Hat: n<2 not supported");
|
||||
|
||||
Matrix X(n, n); // allocate space for n*n skew-symmetric matrix
|
||||
X.setZero();
|
||||
if (n == 2) {
|
||||
// Handle SO(2) case as recursion bottom
|
||||
assert(xi.size() == 1);
|
||||
X << 0, -xi(0), xi(0), 0;
|
||||
} else {
|
||||
// Recursively call SO(n-1) call for top-left block
|
||||
const size_t dmin = (n - 1) * (n - 2) / 2;
|
||||
X.topLeftCorner(n - 1, n - 1) = Hat(xi.tail(dmin));
|
||||
|
||||
// Now fill last row and column
|
||||
double sign = 1.0;
|
||||
for (size_t i = 0; i < n - 1; i++) {
|
||||
const size_t j = n - 2 - i;
|
||||
X(n - 1, j) = sign * xi(i);
|
||||
X(j, n - 1) = -X(n - 1, j);
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
return X;
|
||||
}
|
||||
|
||||
template <>
|
||||
Vector SOn::Vee(const Matrix& X) {
|
||||
const size_t n = X.rows();
|
||||
if (n < 2) throw std::invalid_argument("SO<N>::Hat: n<2 not supported");
|
||||
|
||||
if (n == 2) {
|
||||
// Handle SO(2) case as recursion bottom
|
||||
Vector xi(1);
|
||||
xi(0) = X(1, 0);
|
||||
return xi;
|
||||
} else {
|
||||
// Calculate dimension and allocate space
|
||||
const size_t d = n * (n - 1) / 2;
|
||||
Vector xi(d);
|
||||
|
||||
// Fill first n-1 spots from last row of X
|
||||
double sign = 1.0;
|
||||
for (size_t i = 0; i < n - 1; i++) {
|
||||
const size_t j = n - 2 - i;
|
||||
xi(i) = sign * X(n - 1, j);
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
// Recursively call Vee to fill remainder of x
|
||||
const size_t dmin = (n - 1) * (n - 2) / 2;
|
||||
xi.tail(dmin) = Vee(X.topLeftCorner(n - 1, n - 1));
|
||||
return xi;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
SOn LieGroup<SOn, Eigen::Dynamic>::compose(const SOn& g, DynamicJacobian H1,
|
||||
DynamicJacobian H2) const {
|
||||
|
|
|
@ -83,6 +83,10 @@ class SO : public LieGroup<SO<N>, internal::DimensionSO(N)> {
|
|||
template <typename Derived>
|
||||
explicit SO(const Eigen::MatrixBase<Derived>& R) : matrix_(R.eval()) {}
|
||||
|
||||
/// Construct dynamic SO(n) from Fixed SO<M>
|
||||
template <int M, int N_ = N, typename = IsDynamic<N_>>
|
||||
explicit SO(const SO<M>& R) : matrix_(R.matrix()) {}
|
||||
|
||||
/// Constructor from AngleAxisd
|
||||
template <int N_ = N, typename = IsSO3<N_>>
|
||||
SO(const Eigen::AngleAxisd& angleAxis) : matrix_(angleAxis) {}
|
||||
|
@ -188,12 +192,12 @@ class SO : public LieGroup<SO<N>, internal::DimensionSO(N)> {
|
|||
* -d c -b a 0
|
||||
* This scheme behaves exactly as expected for SO(2) and SO(3).
|
||||
*/
|
||||
static Matrix Hat(const Vector& xi);
|
||||
static MatrixNN Hat(const TangentVector& xi);
|
||||
|
||||
/**
|
||||
* Inverse of Hat. See note about xi element order in Hat.
|
||||
*/
|
||||
static Vector Vee(const Matrix& X);
|
||||
static TangentVector Vee(const MatrixNN& X);
|
||||
|
||||
// Chart at origin
|
||||
struct ChartAtOrigin {
|
||||
|
@ -259,8 +263,20 @@ class SO : public LieGroup<SO<N>, internal::DimensionSO(N)> {
|
|||
using SOn = SO<Eigen::Dynamic>;
|
||||
|
||||
/*
|
||||
* Fully specialize compose and between, because the derivative is unknowable by
|
||||
* the LieGroup implementations, who return a fixed-size matrix for H2.
|
||||
* Specialize dynamic Hat and Vee, because recursion depends on dynamic nature.
|
||||
* The definition is in SOn.cpp. Fixed-size SO3 and SO4 have their own version,
|
||||
* and implementation for other fixed N is in SOn-inl.h.
|
||||
*/
|
||||
|
||||
template <>
|
||||
Matrix SOn::Hat(const Vector& xi);
|
||||
|
||||
template <>
|
||||
Vector SOn::Vee(const Matrix& X);
|
||||
|
||||
/*
|
||||
* Specialize dynamic compose and between, because the derivative is unknowable
|
||||
* by the LieGroup implementations, who return a fixed-size matrix for H2.
|
||||
*/
|
||||
|
||||
using DynamicJacobian = OptionalJacobian<Eigen::Dynamic, Eigen::Dynamic>;
|
||||
|
|
Loading…
Reference in New Issue