Merge remote-tracking branch 'origin/develop' into feature/tighteningTraits

Conflicts:
	gtsam/geometry/Pose2.h
	gtsam/geometry/Pose3.cpp
	gtsam/geometry/tests/testPose3.cpp
release/4.3a0
dellaert 2014-12-25 18:16:30 +01:00
commit b5c5a268a7
5 changed files with 96 additions and 57 deletions

View File

@ -137,6 +137,7 @@ Matrix3 Pose2::adjointMap(const Vector& v) {
/* ************************************************************************* */ /* ************************************************************************* */
Matrix3 Pose2::ExpmapDerivative(const Vector3& v) { Matrix3 Pose2::ExpmapDerivative(const Vector3& v) {
double alpha = v[2]; double alpha = v[2];
Matrix3 J;
if (fabs(alpha) > 1e-5) { if (fabs(alpha) > 1e-5) {
// Chirikjian11book2, pg. 36 // Chirikjian11book2, pg. 36
/* !!!Warning!!! Compare Iserles05an, formula 2.42 and Chirikjian11book2 pg.26 /* !!!Warning!!! Compare Iserles05an, formula 2.42 and Chirikjian11book2 pg.26
@ -149,39 +150,41 @@ Matrix3 Pose2::ExpmapDerivative(const Vector3& v) {
*/ */
double sZalpha = sin(alpha)/alpha, c_1Zalpha = (cos(alpha)-1)/alpha; double sZalpha = sin(alpha)/alpha, c_1Zalpha = (cos(alpha)-1)/alpha;
double v1Zalpha = v[0]/alpha, v2Zalpha = v[1]/alpha; double v1Zalpha = v[0]/alpha, v2Zalpha = v[1]/alpha;
return (Matrix(3,3) << J << sZalpha, -c_1Zalpha, v1Zalpha + v2Zalpha*c_1Zalpha - v1Zalpha*sZalpha,
sZalpha, -c_1Zalpha, v1Zalpha + v2Zalpha*c_1Zalpha - v1Zalpha*sZalpha, c_1Zalpha, sZalpha, -v1Zalpha*c_1Zalpha + v2Zalpha - v2Zalpha*sZalpha,
c_1Zalpha, sZalpha, -v1Zalpha*c_1Zalpha + v2Zalpha - v2Zalpha*sZalpha, 0, 0, 1;
0, 0, 1).finished();
} }
else { else {
// Thanks to Krunal: Apply L'Hospital rule to several times to // Thanks to Krunal: Apply L'Hospital rule to several times to
// compute the limits when alpha -> 0 // compute the limits when alpha -> 0
return (Matrix(3,3) << 1,0,-0.5*v[1], J << 1,0,-0.5*v[1],
0,1, 0.5*v[0], 0,1, 0.5*v[0],
0,0, 1).finished(); 0,0, 1;
} }
return J;
} }
/* ************************************************************************* */ /* ************************************************************************* */
Matrix3 Pose2::LogmapDerivative(const Pose2& p) { Matrix3 Pose2::LogmapDerivative(const Pose2& p) {
Vector3 v = Logmap(p); Vector3 v = Logmap(p);
double alpha = v[2]; double alpha = v[2];
Matrix3 J;
if (fabs(alpha) > 1e-5) { if (fabs(alpha) > 1e-5) {
double alphaInv = 1/alpha; double alphaInv = 1/alpha;
double halfCotHalfAlpha = 0.5*sin(alpha)/(1-cos(alpha)); double halfCotHalfAlpha = 0.5*sin(alpha)/(1-cos(alpha));
double v1 = v[0], v2 = v[1]; double v1 = v[0], v2 = v[1];
return (Matrix(3,3) << J << alpha*halfCotHalfAlpha, -0.5*alpha, v1*alphaInv - v1*halfCotHalfAlpha + 0.5*v2,
alpha*halfCotHalfAlpha, -0.5*alpha, v1*alphaInv - v1*halfCotHalfAlpha + 0.5*v2, 0.5*alpha, alpha*halfCotHalfAlpha, v2*alphaInv - 0.5*v1 - v2*halfCotHalfAlpha,
0.5*alpha, alpha*halfCotHalfAlpha, v2*alphaInv - 0.5*v1 - v2*halfCotHalfAlpha, 0, 0, 1;
0, 0, 1).finished();
} }
else { else {
return (Matrix(3,3) << 1,0, 0.5*v[1], J << 1,0, 0.5*v[1],
0,1, -0.5*v[0], 0,1, -0.5*v[0],
0,0, 1).finished(); 0,0, 1;
} }
return J;
} }
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -155,10 +155,10 @@ public:
return m; return m;
} }
/// Left-trivialized derivative of the exponential map /// Derivative of Expmap
static Matrix3 ExpmapDerivative(const Vector3& v); static Matrix3 ExpmapDerivative(const Vector3& v);
/// Left-trivialized derivative inverse of the exponential map /// Derivative of Logmap
static Matrix3 LogmapDerivative(const Pose2& v); static Matrix3 LogmapDerivative(const Pose2& v);
// Chart at origin, depends on compile-time flag SLOW_BUT_CORRECT_EXPMAP // Chart at origin, depends on compile-time flag SLOW_BUT_CORRECT_EXPMAP

View File

@ -91,26 +91,6 @@ Vector6 Pose3::adjointTranspose(const Vector6& xi, const Vector6& y,
return adjointMap(xi).transpose() * y; return adjointMap(xi).transpose() * y;
} }
/* ************************************************************************* */
Matrix6 Pose3::dExpInv_exp(const Vector6& xi) {
// Bernoulli numbers, from Wikipedia
static const Vector B = (Vector(9) << 1.0, -1.0 / 2.0, 1. / 6., 0.0, -1.0 / 30.0,
0.0, 1.0 / 42.0, 0.0, -1.0 / 30).finished();
static const int N = 5; // order of approximation
Matrix6 res;
res = I_6x6;
Matrix6 ad_i;
ad_i = I_6x6;
Matrix6 ad_xi = adjointMap(xi);
double fac = 1.0;
for (int i = 1; i < N; ++i) {
ad_i = ad_xi * ad_i;
fac = fac * i;
res = res + B(i) / fac * ad_i;
}
return res;
}
/* ************************************************************************* */ /* ************************************************************************* */
void Pose3::print(const string& s) const { void Pose3::print(const string& s) const {
cout << s; cout << s;
@ -126,7 +106,7 @@ bool Pose3::equals(const Pose3& pose, double tol) const {
/* ************************************************************************* */ /* ************************************************************************* */
/** Modified from Murray94book version (which assumes w and v normalized?) */ /** Modified from Murray94book version (which assumes w and v normalized?) */
Pose3 Pose3::Expmap(const Vector& xi, OptionalJacobian<6, 6> H) { Pose3 Pose3::Expmap(const Vector& xi, OptionalJacobian<6, 6> H) {
if (H) CONCEPT_NOT_IMPLEMENTED; if (H) *H = ExpmapDerivative(xi);
// get angular velocity omega and translational velocity v from twist xi // get angular velocity omega and translational velocity v from twist xi
Point3 w(xi(0), xi(1), xi(2)), v(xi(3), xi(4), xi(5)); Point3 w(xi(0), xi(1), xi(2)), v(xi(3), xi(4), xi(5));
@ -222,6 +202,66 @@ Vector6 Pose3::localCoordinates(const Pose3& T,
} }
} }
/* ************************************************************************* */
/**
* Compute the 3x3 bottom-left block Q of the SE3 Expmap derivative matrix
* J(xi) = [J_(w) Z_3x3;
* Q J_(w)]
* where J_(w) is the SO3 Expmap derivative.
* (see Chirikjian11book2, pg 44, eq 10.95.
* The closed-form formula is similar to formula 102 in Barfoot14tro)
*/
static Matrix3 computeQforExpmapDerivative(const Vector6& xi) {
Vector3 w(sub(xi, 0, 3));
Vector3 v(sub(xi, 3, 6));
Matrix3 V = skewSymmetric(v);
Matrix3 W = skewSymmetric(w);
Matrix3 Q;
#ifdef NUMERICAL_EXPMAP_DERIV
Matrix3 Qj = Z_3x3;
double invFac = 1.0;
Q = Z_3x3;
Matrix3 Wj = I_3x3;
for (size_t j=1; j<10; ++j) {
Qj = Qj*W + Wj*V;
invFac = -invFac/(j+1);
Q = Q + invFac*Qj;
Wj = Wj*W;
}
#else
// The closed-form formula in Barfoot14tro eq. (102)
double phi = w.norm(), sinPhi = sin(phi), cosPhi = cos(phi), phi2 = phi * phi,
phi3 = phi2 * phi, phi4 = phi3 * phi, phi5 = phi4 * phi;
// Invert the sign of odd-order terms to have the right Jacobian
Q = -0.5*V + (phi-sinPhi)/phi3*(W*V + V*W - W*V*W)
+ (1-phi2/2-cosPhi)/phi4*(W*W*V + V*W*W - 3*W*V*W)
- 0.5*((1-phi2/2-cosPhi)/phi4 - 3*(phi-sinPhi-phi3/6)/phi5)*(W*V*W*W + W*W*V*W);
#endif
return Q;
}
/* ************************************************************************* */
Matrix6 Pose3::ExpmapDerivative(const Vector6& xi) {
Vector3 w(sub(xi, 0, 3));
Matrix3 Jw = Rot3::ExpmapDerivative(w);
Matrix3 Q = computeQforExpmapDerivative(xi);
Matrix6 J = (Matrix(6,6) << Jw, Z_3x3, Q, Jw).finished();
return J;
}
/* ************************************************************************* */
Matrix6 Pose3::LogmapDerivative(const Vector6& xi) {
Vector3 w(sub(xi, 0, 3));
Matrix3 Jw = Rot3::LogmapDerivative(w);
Matrix3 Q = computeQforExpmapDerivative(xi);
Matrix3 Q2 = -Jw*Q*Jw;
Matrix6 J = (Matrix(6,6) << Jw, Z_3x3, Q2, Jw).finished();
return J;
}
/* ************************************************************************* */ /* ************************************************************************* */
Pose3 Pose3::retract(const Vector& d, OptionalJacobian<6, 6> Hthis, Pose3 Pose3::retract(const Vector& d, OptionalJacobian<6, 6> Hthis,
OptionalJacobian<6, 6> Hd, Pose3::CoordinatesMode mode) const { OptionalJacobian<6, 6> Hd, Pose3::CoordinatesMode mode) const {

View File

@ -218,18 +218,13 @@ public:
*/ */
static Vector6 adjointTranspose(const Vector6& xi, const Vector6& y, OptionalJacobian<6, 6> H = boost::none); static Vector6 adjointTranspose(const Vector6& xi, const Vector6& y, OptionalJacobian<6, 6> H = boost::none);
/** public:
* Compute the inverse right-trivialized tangent (derivative) map of the exponential map,
* as detailed in [Kobilarov09siggraph] eq. (15) /// Derivative of Expmap
* The full formula is documented in [Celledoni99cmame] static Matrix6 ExpmapDerivative(const Vector6& xi);
* Elena Celledoni and Brynjulf Owren. Lie group methods for rigid body dynamics and
* time integration on manifolds. Comput. meth. in Appl. Mech. and Eng., 19(3,4):421-438, 2003. /// Derivative of Logmap
* and in [Hairer06book] in formula (4.5), pg. 84, Lemma 4.2 static Matrix6 LogmapDerivative(const Vector6& xi);
* Ernst Hairer, et al., Geometric Numerical Integration,
* Structure-Preserving Algorithms for Ordinary Differential Equations, 2nd edition, Springer-Verlag, 2006.
* See also Iserles05an, pg. 33, formula 2.46
*/
static Matrix6 dExpInv_exp(const Vector6 &xi);
/** /**
* wedge for Pose3: * wedge for Pose3:

View File

@ -672,21 +672,22 @@ TEST(Pose3, align_2) {
} }
/* ************************************************************************* */ /* ************************************************************************* */
/// exp(xi) exp(y) = exp(xi + x) /// exp(xi) exp(y) = exp(xi + dxi)
/// Hence, y = log (exp(-xi)*exp(xi+x)) /// Hence, y = log (exp(-xi)*exp(xi+dxi))
Vector xi = (Vector(6) << 0.1, 0.2, 0.3, 1.0, 2.0, 3.0).finished(); Vector6 xi = (Vector(6) << 0.1, 0.2, 0.3, 4.0, 5.0, 6.0).finished();
Vector testDerivExpmapInv(const Vector6& dxi) { Vector6 testExpmapDerivative(const Vector6& xi, const Vector6& dxi) {
return Pose3::Logmap(Pose3::Expmap(-xi) * Pose3::Expmap(xi + dxi)); return Pose3::Logmap(Pose3::Expmap(-xi) * Pose3::Expmap(xi + dxi));
} }
TEST( Pose3, dExpInv_TLN) { TEST( Pose3, ExpmapDerivative) {
Matrix res = Pose3::dExpInv_exp(xi); Matrix actualDexpL = Pose3::ExpmapDerivative(xi);
Matrix expectedDexpL = numericalDerivative11<Vector6, Vector6>(
boost::bind(testExpmapDerivative, xi, _1), zero(6), 1e-2);
EXPECT(assert_equal(expectedDexpL, actualDexpL, 1e-5));
Matrix numericalDerivExpmapInv = numericalDerivative11<Vector6, Vector6>( Matrix actualDexpInvL = Pose3::LogmapDerivative(xi);
testDerivExpmapInv, Vector6::Zero(), 1e-5); EXPECT(assert_equal(expectedDexpL.inverse(), actualDexpInvL, 1e-5));
EXPECT(assert_equal(numericalDerivExpmapInv,res,3e-1));
} }
/* ************************************************************************* */ /* ************************************************************************* */