applyLeftJacobian
parent
78f17aabc4
commit
c7f651d98d
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <Eigen/SVD>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
namespace gtsam {
|
||||
|
@ -98,35 +99,47 @@ Matrix3 DexpFunctor::rightJacobian() const {
|
|||
}
|
||||
}
|
||||
|
||||
// Derivative of w x w x v in w:
|
||||
static Matrix3 doubleCrossJacobian(const Vector3& w, const Vector3& v) {
|
||||
return v.dot(w) * I_3x3 + w * v.transpose() - 2 * v * w.transpose();
|
||||
Vector3 DexpFunctor::cross(const Vector3& v, OptionalJacobian<3, 3> H) const {
|
||||
// Wv = omega x * v
|
||||
const Vector3 Wv = gtsam::cross(omega, v);
|
||||
if (H) {
|
||||
// 1x3 Jacobian of B with respect to omega
|
||||
const Matrix13 HB = (A - 2.0 * B) / theta2 * omega.transpose();
|
||||
// Apply product rule:
|
||||
*H = Wv * HB - B * skewSymmetric(v);
|
||||
}
|
||||
return B * Wv;
|
||||
}
|
||||
|
||||
Vector3 DexpFunctor::doubleCross(const Vector3& v,
|
||||
OptionalJacobian<3, 3> H) const {
|
||||
// WWv = omega x (omega x * v)
|
||||
Matrix3 doubleCrossJacobian;
|
||||
const Vector3 WWv =
|
||||
gtsam::doubleCross(omega, v, H ? &doubleCrossJacobian : nullptr);
|
||||
if (H) {
|
||||
// 1x3 Jacobian of C with respect to omega
|
||||
const Matrix13 HC = (B - 3.0 * C) / theta2 * omega.transpose();
|
||||
// Apply product rule:
|
||||
*H = WWv * HC + C * doubleCrossJacobian;
|
||||
}
|
||||
return C * WWv;
|
||||
}
|
||||
|
||||
// Multiplies v with left Jacobian through vector operations only.
|
||||
// When Jacobian H1 wrt omega is requested, product rule is invoked twice, once
|
||||
// for (B * Wv) and (C * WWv). The Jacobian H2 wrt v is just the right Jacobian.
|
||||
Vector3 DexpFunctor::applyDexp(const Vector3& v, OptionalJacobian<3, 3> H1,
|
||||
OptionalJacobian<3, 3> H2) const {
|
||||
// Wv = omega x * v, with Jacobian -V in w
|
||||
const Vector3 Wv = gtsam::cross(omega, v);
|
||||
|
||||
if (nearZero) {
|
||||
if (H1) *H1 = 0.5 * skewSymmetric(v);
|
||||
if (H2) *H2 = I_3x3 - 0.5 * W;
|
||||
return v - 0.5 * Wv;
|
||||
return v - 0.5 * gtsam::cross(omega, v);
|
||||
} else {
|
||||
// WWv = omega x (omega x * v), with Jacobian doubleCrossJacobian
|
||||
const Vector3 WWv = gtsam::cross(omega, Wv);
|
||||
if (H1) {
|
||||
// 1x3 Jacobians of B and C with respect to theta
|
||||
const Matrix13 HB = (A - 2.0 * B) / theta2 * omega.transpose();
|
||||
const Matrix13 HC = (B - 3.0 * C) / theta2 * omega.transpose();
|
||||
*H1 = -Wv * HB + B * skewSymmetric(v) +
|
||||
C * doubleCrossJacobian(omega, v) + WWv * HC;
|
||||
}
|
||||
Matrix3 D_BWv_omega, D_CWWv_omega;
|
||||
const Vector3 BWv = cross(v, D_BWv_omega);
|
||||
const Vector3 CWWv = doubleCross(v, D_CWWv_omega);
|
||||
if (H1) *H1 = - D_BWv_omega + D_CWWv_omega;
|
||||
if (H2) *H2 = rightJacobian();
|
||||
return v - B * Wv + C * WWv;
|
||||
return v - BWv + CWWv;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,10 +167,18 @@ Matrix3 DexpFunctor::leftJacobian() const {
|
|||
Vector3 DexpFunctor::applyLeftJacobian(const Vector3& v,
|
||||
OptionalJacobian<3, 3> H1,
|
||||
OptionalJacobian<3, 3> H2) const {
|
||||
const Matrix3 Jw = leftJacobian();
|
||||
if (H1) H1->setZero();
|
||||
if (H2) *H2 = Jw;
|
||||
return Jw * v;
|
||||
if (nearZero) {
|
||||
if (H1) *H1 = - 0.5 * skewSymmetric(v);
|
||||
if (H2) *H2 = I_3x3 + 0.5 * W;
|
||||
return v + 0.5 * gtsam::cross(omega, v);
|
||||
} else {
|
||||
Matrix3 D_BWv_omega, D_CWWv_omega;
|
||||
const Vector3 BWv = cross(v, D_BWv_omega);
|
||||
const Vector3 CWWv = doubleCross(v, D_CWWv_omega);
|
||||
if (H1) *H1 = D_BWv_omega + D_CWWv_omega;
|
||||
if (H2) *H2 = leftJacobian();
|
||||
return v + BWv + CWWv;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace so3
|
||||
|
|
|
@ -160,6 +160,12 @@ class DexpFunctor : public ExpmapFunctor {
|
|||
const Vector3 omega;
|
||||
double C; // Ethan Eade's C constant
|
||||
|
||||
/// Computes B * (omega x v).
|
||||
Vector3 cross(const Vector3& v, OptionalJacobian<3, 3> H = {}) const;
|
||||
|
||||
/// Computes C * (omega x (omega x v)).
|
||||
Vector3 doubleCross(const Vector3& v, OptionalJacobian<3, 3> H = {}) const;
|
||||
|
||||
public:
|
||||
/// Constructor with element of Lie algebra so(3)
|
||||
GTSAM_EXPORT explicit DexpFunctor(const Vector3& omega,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/base/testLie.h>
|
||||
#include <gtsam/geometry/SO3.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace std;
|
||||
|
@ -326,6 +327,29 @@ TEST(SO3, ApplyDexp) {
|
|||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
TEST(SO3, ApplyLeftJacobian) {
|
||||
Matrix aH1, aH2;
|
||||
for (bool nearZeroApprox : {false, true}) {
|
||||
std::function<Vector3(const Vector3&, const Vector3&)> f =
|
||||
[=](const Vector3& omega, const Vector3& v) {
|
||||
return so3::DexpFunctor(omega, nearZeroApprox).applyLeftJacobian(v);
|
||||
};
|
||||
for (Vector3 omega : {Vector3(0, 0, 0), Vector3(1, 0, 0), Vector3(0, 1, 0),
|
||||
Vector3(0, 0, 1), Vector3(0.1, 0.2, 0.3)}) {
|
||||
so3::DexpFunctor local(omega, nearZeroApprox);
|
||||
for (Vector3 v : {Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1),
|
||||
Vector3(0.4, 0.3, 0.2)}) {
|
||||
CHECK(assert_equal(Vector3(local.leftJacobian() * v),
|
||||
local.applyLeftJacobian(v, aH1, aH2)));
|
||||
CHECK(assert_equal(numericalDerivative21(f, omega, v), aH1));
|
||||
CHECK(assert_equal(numericalDerivative22(f, omega, v), aH2));
|
||||
CHECK(assert_equal(local.leftJacobian(), aH2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
TEST(SO3, ApplyInvDexp) {
|
||||
Matrix aH1, aH2;
|
||||
|
|
Loading…
Reference in New Issue