Add AdjointMap into traits

release/4.3a0
Frank Dellaert 2025-05-09 15:46:25 -04:00
parent ea783b0edb
commit 2a22123d5d
3 changed files with 40 additions and 28 deletions

View File

@ -169,32 +169,34 @@ namespace internal {
/// To use this for your gtsam type, define: /// To use this for your gtsam type, define:
/// template<> struct traits<Class> : public internal::LieGroupTraits<Class> {}; /// template<> struct traits<Class> : public internal::LieGroupTraits<Class> {};
/// Assumes existence of: identity, dimension, localCoordinates, retract, /// Assumes existence of: identity, dimension, localCoordinates, retract,
/// and additionally Logmap, Expmap, compose, between, and inverse /// and additionally Logmap, Expmap, AdjointMap, compose, between, and inverse
template<class Class> template<class Class>
struct LieGroupTraits: public GetDimensionImpl<Class, Class::dimension> { struct LieGroupTraits : public GetDimensionImpl<Class, Class::dimension> {
using structure_category = lie_group_tag; using structure_category = lie_group_tag;
/// @name Group /// @name Group
/// @{ /// @{
using group_flavor = multiplicative_group_tag; using group_flavor = multiplicative_group_tag;
static Class Identity() { return Class::Identity();} static Class Identity() { return Class::Identity(); }
/// @} /// @}
/// @name Manifold /// @name Manifold
/// @{ /// @{
using ManifoldType = Class; using ManifoldType = Class;
// Note: Class::dimension can be an int or Eigen::Dynamic.
// GetDimensionImpl handles resolving this to a static value or providing GetDimension(obj).
inline constexpr static auto dimension = Class::dimension; inline constexpr static auto dimension = Class::dimension;
using TangentVector = Eigen::Matrix<double, dimension, 1>; using TangentVector = Eigen::Matrix<double, dimension, 1>;
using ChartJacobian = OptionalJacobian<dimension, dimension>; using ChartJacobian = OptionalJacobian<dimension, dimension>;
static TangentVector Local(const Class& origin, const Class& other, static TangentVector Local(const Class& origin, const Class& other,
ChartJacobian Horigin = {}, ChartJacobian Hother = {}) { ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
return origin.localCoordinates(other, Horigin, Hother); return origin.localCoordinates(other, H1, H2);
} }
static Class Retract(const Class& origin, const TangentVector& v, static Class Retract(const Class& origin, const TangentVector& v,
ChartJacobian Horigin = {}, ChartJacobian Hv = {}) { ChartJacobian H = {}, ChartJacobian Hv = {}) {
return origin.retract(v, Horigin, Hv); return origin.retract(v, H, Hv);
} }
/// @} /// @}
@ -222,6 +224,13 @@ struct LieGroupTraits: public GetDimensionImpl<Class, Class::dimension> {
ChartJacobian H = {}) { ChartJacobian H = {}) {
return m.inverse(H); return m.inverse(H);
} }
static Eigen::Matrix<double, dimension, dimension> AdjointMap(const Class& m) {
// This assumes that the Class itself provides a member function `AdjointMap()`
// For dynamically-sized types (dimension == Eigen::Dynamic),
// m.AdjointMap() must return a gtsam::Matrix of the correct runtime dimensions.
return m.AdjointMap();
}
/// @} /// @}
}; };

View File

@ -35,7 +35,7 @@ struct VectorSpaceImpl {
ChartJacobian H1 = {}, ChartJacobian H2 = {}) { ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
if (H1) *H1 = - Jacobian::Identity(); if (H1) *H1 = - Jacobian::Identity();
if (H2) *H2 = Jacobian::Identity(); if (H2) *H2 = Jacobian::Identity();
Class v = other-origin; Class v = other - origin;
return v.vector(); return v.vector();
} }
@ -82,12 +82,12 @@ struct VectorSpaceImpl {
return -v; return -v;
} }
static LieAlgebra Hat(const TangentVector& v) { static LieAlgebra Hat(const TangentVector& v) { return v; }
return v;
}
static TangentVector Vee(const LieAlgebra& X) { static TangentVector Vee(const LieAlgebra& X) { return X; }
return X;
static Jacobian AdjointMap(const Class& /*m*/) {
return Jacobian::Identity();
} }
/// @} /// @}
}; };
@ -118,7 +118,7 @@ struct VectorSpaceImpl<Class,Eigen::Dynamic> {
ChartJacobian H1 = {}, ChartJacobian H2 = {}) { ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
if (H1) *H1 = - Eye(origin); if (H1) *H1 = - Eye(origin);
if (H2) *H2 = Eye(other); if (H2) *H2 = Eye(other);
Class v = other-origin; Class v = other - origin;
return v.vector(); return v.vector();
} }
@ -141,8 +141,7 @@ struct VectorSpaceImpl<Class,Eigen::Dynamic> {
static Class Expmap(const TangentVector& v, ChartJacobian Hv = {}) { static Class Expmap(const TangentVector& v, ChartJacobian Hv = {}) {
Class result(v); Class result(v);
if (Hv) if (Hv) *Hv = Eye(v);
*Hv = Eye(v);
return result; return result;
} }
@ -165,6 +164,7 @@ struct VectorSpaceImpl<Class,Eigen::Dynamic> {
return -v; return -v;
} }
static Eigen::MatrixXd AdjointMap(const Class& m) { return Eye(m); }
/// @} /// @}
}; };
@ -273,8 +273,8 @@ struct ScalarTraits : VectorSpaceImpl<Scalar, 1> {
if (H) (*H)[0] = 1.0; if (H) (*H)[0] = 1.0;
return v[0]; return v[0];
} }
// AdjointMap for ScalarTraits is inherited from VectorSpaceImpl<Scalar, 1>
/// @} /// @}
}; };
} // namespace internal } // namespace internal
@ -352,6 +352,9 @@ struct traits<Eigen::Matrix<double, M, N, Options, MaxRows, MaxCols> > :
if (H) *H = Jacobian::Identity(); if (H) *H = Jacobian::Identity();
return m + Eigen::Map<const Fixed>(v.data()); return m + Eigen::Map<const Fixed>(v.data());
} }
// AdjointMap for fixed-size Eigen matrices is inherited from
// internal::VectorSpaceImpl< Eigen::Matrix<double, M, N, ...> , M*N >
/// @} /// @}
}; };
@ -425,7 +428,7 @@ struct DynamicTraits {
static TangentVector Logmap(const Dynamic& m, ChartJacobian H = {}) { static TangentVector Logmap(const Dynamic& m, ChartJacobian H = {}) {
if (H) *H = Eye(m); if (H) *H = Eye(m);
TangentVector result(GetDimension(m)); TangentVector result(GetDimension(m));
Eigen::Map<Dynamic>(result.data(), m.cols(), m.rows()) = m; Eigen::Map<Dynamic>(result.data(), m.rows(), m.cols()) = m;
return result; return result;
} }
@ -461,6 +464,7 @@ struct DynamicTraits {
return X; return X;
} }
static Jacobian AdjointMap(const Dynamic& m) { return Eye(m); }
/// @} /// @}
}; };
@ -506,4 +510,3 @@ private:
}; };
} // namespace gtsam } // namespace gtsam

View File

@ -77,9 +77,9 @@ namespace gtsam {
* @param Q Process noise covariance. * @param Q Process noise covariance.
*/ */
void predict(const G& U, const Covariance& Q) { void predict(const G& U, const Covariance& Q) {
this->X_ = this->X_.compose(U); this->X_ = traits<G>::Compose(this->X_, U);
// TODO(dellaert): traits<G>::AdjointMap should exist const G U_inv = traits<G>::Inverse(U);
const Jacobian A = traits<G>::Inverse(U).AdjointMap(); const Jacobian A = traits<G>::AdjointMap(U_inv);
// P_ is Covariance. A is Jacobian. Q is Covariance. // P_ is Covariance. A is Jacobian. Q is Covariance.
// All are Eigen::Matrix<double,Dim,Dim>. // All are Eigen::Matrix<double,Dim,Dim>.
this->P_ = A * this->P_ * A.transpose() + Q; this->P_ = A * this->P_ * A.transpose() + Q;