diff --git a/.cproject b/.cproject
index 38c4c66f4..700b82ce6 100644
--- a/.cproject
+++ b/.cproject
@@ -2329,6 +2329,14 @@
true
true
+
+ make
+ -j5
+ testNumericalDerivative.run
+ true
+ true
+ true
+
make
-j5
diff --git a/gtsam/base/numericalDerivative.h b/gtsam/base/numericalDerivative.h
index 036f23f68..01ed3f09a 100644
--- a/gtsam/base/numericalDerivative.h
+++ b/gtsam/base/numericalDerivative.h
@@ -16,7 +16,6 @@
*/
// \callgraph
-
#pragma once
#include
@@ -31,595 +30,497 @@
#include
#include
+#include
namespace gtsam {
- /*
- * Note that all of these functions have two versions, a boost.function version and a
- * standard C++ function pointer version. This allows reformulating the arguments of
- * a function to fit the correct structure, which is useful for situations like
- * member functions and functions with arguments not involved in the derivative:
- *
- * Usage of the boost bind version to rearrange arguments:
- * for a function with one relevant param and an optional derivative:
- * Foo bar(const Obj& a, boost::optional H1)
- * Use boost.bind to restructure:
- * boost::bind(bar, _1, boost::none)
- * This syntax will fix the optional argument to boost::none, while using the first argument provided
- *
- * For member functions, such as below, with an instantiated copy instanceOfSomeClass
- * Foo SomeClass::bar(const Obj& a)
- * Use boost bind as follows to create a function pointer that uses the member function:
- * boost::bind(&SomeClass::bar, ref(instanceOfSomeClass), _1)
- *
- * For additional details, see the documentation:
- * http://www.boost.org/doc/libs/release/libs/bind/bind.html
- */
-
-
- /** global functions for converting to a LieVector for use with numericalDerivative */
- inline LieVector makeLieVector(const Vector& v) { return LieVector(v); }
- inline LieVector makeLieVectorD(double d) { return LieVector((Vector) (Vector(1) << d)); }
-
- /**
- * Numerically compute gradient of scalar function
- * Class X is the input argument
- * The class X needs to have dim, expmap, logmap
- */
- template
- Vector numericalGradient(boost::function h, const X& x, double delta=1e-5) {
- double factor = 1.0/(2.0*delta);
- const size_t n = x.dim();
- Vector d = zero(n), g = zero(n);
- for (size_t j=0;j
- Vector numericalGradient(double (*h)(const X&), const X& x, double delta=1e-5) {
- return numericalGradient(boost::bind(h, _1), x, delta);
- }
-
- /**
- * Compute numerical derivative in argument 1 of unary function
- * @param h unary function yielding m-vector
- * @param x n-dimensional value at which to evaluate h
- * @param delta increment for numerical derivative
- * Class Y is the output argument
- * Class X is the input argument
- * @return m*n Jacobian computed via central differencing
- * Both classes X,Y need dim, expmap, logmap
- */
- template
- Matrix numericalDerivative11(boost::function h, const X& x, double delta=1e-5) {
- Y hx = h(x);
- double factor = 1.0/(2.0*delta);
- const size_t m = hx.dim(), n = x.dim();
- Vector d = zero(n);
- Matrix H = zeros(m,n);
- for (size_t j=0;j
- Matrix numericalDerivative11(Y (*h)(const X&), const X& x, double delta=1e-5) {
- return numericalDerivative11(boost::bind(h, _1), x, delta);
- }
-
-// /** remapping for double valued functions */
-// template
-// Matrix numericalDerivative11(boost::function h, const X& x, double delta=1e-5) {
-// return numericalDerivative11(boost::bind(makeLieVectorD, boost::bind(h, _1)), x, delta);
-// }
-
- template
- Matrix numericalDerivative11(double (*h)(const X&), const X& x, double delta=1e-5) {
- return numericalDerivative11(boost::bind(makeLieVectorD, boost::bind(h, _1)), x, delta);
- }
-
- /** remapping for vector valued functions */
- template
- Matrix numericalDerivative11(boost::function h, const X& x, double delta=1e-5) {
- return numericalDerivative11(boost::bind(makeLieVector, boost::bind(h, _1)), x, delta);
- }
-
- template
- Matrix numericalDerivative11(Vector (*h)(const X&), const X& x, double delta=1e-5) {
- return numericalDerivative11(boost::bind(makeLieVector, boost::bind(h, _1)), x, delta);
- }
-
- /**
- * Compute numerical derivative in argument 1 of binary function
- * @param h binary function yielding m-vector
- * @param x1 n-dimensional first argument value
- * @param x2 second argument value
- * @param delta increment for numerical derivative
- * @return m*n Jacobian computed via central differencing
- * All classes Y,X1,X2 need dim, expmap, logmap
- */
- template
- Matrix numericalDerivative21(boost::function h,
- const X1& x1, const X2& x2, double delta=1e-5) {
- Y hx = h(x1,x2);
- double factor = 1.0/(2.0*delta);
- const size_t m = hx.dim(), n = x1.dim();
- Vector d = zero(n);
- Matrix H = zeros(m,n);
- for (size_t j=0;j
- inline Matrix numericalDerivative21(Y (*h)(const X1&, const X2&),
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative21(boost::bind(h, _1, _2), x1, x2, delta);
- }
-
- /** pseudo-partial template specialization for double return values */
- template
- Matrix numericalDerivative21(boost::function h,
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative21(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- template
- Matrix numericalDerivative21(double (*h)(const X1&, const X2&),
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative21(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- /** pseudo-partial template specialization for vector return values */
- template
- Matrix numericalDerivative21(boost::function h,
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative21(
- boost::bind(makeLieVector, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- template
- inline Matrix numericalDerivative21(Vector (*h)(const X1&, const X2&),
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative21(
- boost::bind(makeLieVector, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- /**
- * Compute numerical derivative in argument 2 of binary function
- * @param h binary function yielding m-vector
- * @param x1 first argument value
- * @param x2 n-dimensional second argument value
- * @param delta increment for numerical derivative
- * @return m*n Jacobian computed via central differencing
- * All classes Y,X1,X2 need dim, expmap, logmap
- */
- template
- Matrix numericalDerivative22
- (boost::function h,
- const X1& x1, const X2& x2, double delta=1e-5) {
- Y hx = h(x1,x2);
- double factor = 1.0/(2.0*delta);
- const size_t m = hx.dim(), n = x2.dim();
- Vector d = zero(n);
- Matrix H = zeros(m,n);
- for (size_t j=0;j
- inline Matrix numericalDerivative22
- (Y (*h)(const X1&, const X2&), const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative22(boost::bind(h, _1, _2), x1, x2, delta);
- }
-
- /** pseudo-partial template specialization for double return values */
- template
- Matrix numericalDerivative22(boost::function h,
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative22(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- template
- inline Matrix numericalDerivative22(double (*h)(const X1&, const X2&),
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative22(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- /** pseudo-partial template specialization for vector return values */
- template
- Matrix numericalDerivative22(boost::function h,
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative22(
- boost::bind(makeLieVector, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- template
- inline Matrix numericalDerivative22(Vector (*h)(const X1&, const X2&),
- const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalDerivative22(
- boost::bind(makeLieVector, boost::bind(h, _1, _2)), x1, x2, delta);
- }
-
- /**
- * Compute numerical derivative in argument 1 of ternary function
- * @param h ternary function yielding m-vector
- * @param x1 n-dimensional first argument value
- * @param x2 second argument value
- * @param x3 third argument value
- * @param delta increment for numerical derivative
- * @return m*n Jacobian computed via central differencing
- * All classes Y,X1,X2,X3 need dim, expmap, logmap
- */
- template
- Matrix numericalDerivative31
- (boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5)
- {
- Y hx = h(x1,x2,x3);
- double factor = 1.0/(2.0*delta);
- const size_t m = hx.dim(), n = x1.dim();
- Vector d = zero(n);
- Matrix H = zeros(m,n);
- for (size_t j=0;j
- inline Matrix numericalDerivative31
- (Y (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative31(boost::bind(h, _1, _2, _3), x1, x2, x3, delta);
- }
-
- /** pseudo-partial template specialization for double return values */
- template
- Matrix numericalDerivative31(boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative31(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalDerivative31(double (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative31(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- /** pseudo-partial template specialization for vector return values */
- template
- Matrix numericalDerivative31(boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative31(
- boost::bind(makeLieVector, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalDerivative31(Vector (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative31(
- boost::bind(makeLieVector, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- /**
- * Compute numerical derivative in argument 2 of ternary function
- * @param h ternary function yielding m-vector
- * @param x1 n-dimensional first argument value
- * @param x2 second argument value
- * @param x3 third argument value
- * @param delta increment for numerical derivative
- * @return m*n Jacobian computed via central differencing
- * All classes Y,X1,X2,X3 need dim, expmap, logmap
- */
- template
- Matrix numericalDerivative32
- (boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5)
- {
- Y hx = h(x1,x2,x3);
- double factor = 1.0/(2.0*delta);
- const size_t m = hx.dim(), n = x2.dim();
- Vector d = zero(n);
- Matrix H = zeros(m,n);
- for (size_t j=0;j
- inline Matrix numericalDerivative32
- (Y (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative32(boost::bind(h, _1, _2, _3), x1, x2, x3, delta);
- }
-
- /** pseudo-partial template specialization for double return values */
- template
- Matrix numericalDerivative32(boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative32(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalDerivative32(double (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative32(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- /** pseudo-partial template specialization for vector return values */
- template
- Matrix numericalDerivative32(boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative32(
- boost::bind(makeLieVector, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalDerivative32(Vector (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative32(
- boost::bind(makeLieVector, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- /**
- * Compute numerical derivative in argument 3 of ternary function
- * @param h ternary function yielding m-vector
- * @param x1 n-dimensional first argument value
- * @param x2 second argument value
- * @param x3 third argument value
- * @param delta increment for numerical derivative
- * @return m*n Jacobian computed via central differencing
- * All classes Y,X1,X2,X3 need dim, expmap, logmap
- */
- template
- Matrix numericalDerivative33
- (boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5)
- {
- Y hx = h(x1,x2,x3);
- double factor = 1.0/(2.0*delta);
- const size_t m = hx.dim(), n = x3.dim();
- Vector d = zero(n);
- Matrix H = zeros(m,n);
- for (size_t j=0;j
- inline Matrix numericalDerivative33
- (Y (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative33(boost::bind(h, _1, _2, _3), x1, x2, x3, delta);
- }
-
- /** pseudo-partial template specialization for double return values */
- template
- Matrix numericalDerivative33(boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative33(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalDerivative33(double (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative33(
- boost::bind(makeLieVectorD, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- /** pseudo-partial template specialization for vector return values */
- template
- Matrix numericalDerivative33(boost::function h,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative33(
- boost::bind(makeLieVector, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalDerivative33(Vector (*h)(const X1&, const X2&, const X3&),
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalDerivative33(
- boost::bind(makeLieVector, boost::bind(h, _1, _2, _3)), x1, x2, x3, delta);
- }
-
- /**
- * Compute numerical Hessian matrix. Requires a single-argument Lie->scalar
- * function. This is implemented simply as the derivative of the gradient.
- * @param f A function taking a Lie object as input and returning a scalar
- * @param x The center point for computing the Hessian
- * @param delta The numerical derivative step size
- * @return n*n Hessian matrix computed via central differencing
- */
- template
- inline Matrix numericalHessian(boost::function f, const X& x, double delta=1e-5) {
- return numericalDerivative11(boost::function(boost::bind(
- static_cast,const X&, double)>(&numericalGradient),
- f, _1, delta)), x, delta);
- }
-
- template
- inline Matrix numericalHessian(double (*f)(const X&), const X& x, double delta=1e-5) {
- return numericalHessian(boost::function(f), x, delta);
- }
-
-
- /** Helper class that computes the derivative of f w.r.t. x1, centered about
- * x1_, as a function of x2
- */
- template
- class G_x1 {
- const boost::function& f_;
- const X1& x1_;
- double delta_;
- public:
- G_x1(const boost::function& f, const X1& x1, double delta) : f_(f), x1_(x1), delta_(delta) {}
- Vector operator()(const X2& x2) {
- return numericalGradient(boost::function(boost::bind(f_, _1, x2)), x1_, delta_);
- }
- };
-
- template
- inline Matrix numericalHessian212(boost::function f, const X1& x1, const X2& x2, double delta=1e-5) {
- G_x1 g_x1(f, x1, delta);
- return numericalDerivative11(boost::function(boost::bind(boost::ref(g_x1), _1)), x2, delta);
- }
-
-
- template
- inline Matrix numericalHessian212(double (*f)(const X1&, const X2&), const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalHessian212(boost::function(f), x1, x2, delta);
- }
-
-
- template
- inline Matrix numericalHessian211(boost::function f, const X1& x1, const X2& x2, double delta=1e-5) {
-
- Vector (*numGrad)(boost::function, const X1&, double) = &numericalGradient;
- boost::function f2(boost::bind(f, _1, x2));
-
- return numericalDerivative11(boost::function(boost::bind(numGrad, f2, _1, delta)), x1, delta);
- }
-
-
- template
- inline Matrix numericalHessian211(double (*f)(const X1&, const X2&), const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalHessian211(boost::function(f), x1, x2, delta);
- }
-
-
- template
- inline Matrix numericalHessian222(boost::function f, const X1& x1, const X2& x2, double delta=1e-5) {
-
- Vector (*numGrad)(boost::function, const X2&, double) = &numericalGradient;
- boost::function f2(boost::bind(f, x1, _1));
-
- return numericalDerivative11(boost::function(boost::bind(numGrad, f2, _1, delta)), x2, delta);
- }
-
-
- template
- inline Matrix numericalHessian222(double (*f)(const X1&, const X2&), const X1& x1, const X2& x2, double delta=1e-5) {
- return numericalHessian222(boost::function(f), x1, x2, delta);
- }
-
- /**
- * Numerical Hessian for tenary functions
- */
- /* **************************************************************** */
- template
- inline Matrix numericalHessian311(boost::function f,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
-
- Vector (*numGrad)(boost::function, const X1&, double) = &numericalGradient;
- boost::function f2(boost::bind(f, _1, x2, x3));
-
- return numericalDerivative11(boost::function(boost::bind(numGrad, f2, _1, delta)), x1, delta);
- }
-
- template
- inline Matrix numericalHessian311(double (*f)(const X1&, const X2&, const X3&), const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian311(boost::function(f), x1, x2, x3, delta);
- }
-
- /* **************************************************************** */
- template
- inline Matrix numericalHessian322(boost::function f,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
-
- Vector (*numGrad)(boost::function, const X2&, double) = &numericalGradient;
- boost::function f2(boost::bind(f, x1, _1, x3));
-
- return numericalDerivative11(boost::function(boost::bind(numGrad, f2, _1, delta)), x2, delta);
- }
-
- template
- inline Matrix numericalHessian322(double (*f)(const X1&, const X2&, const X3&), const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian322(boost::function(f), x1, x2, x3, delta);
- }
-
- /* **************************************************************** */
- template
- inline Matrix numericalHessian333(boost::function f,
- const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
-
- Vector (*numGrad)(boost::function, const X3&, double) = &numericalGradient;
- boost::function f2(boost::bind(f, x1, x2, _1));
-
- return numericalDerivative11(boost::function(boost::bind(numGrad, f2, _1, delta)), x3, delta);
- }
-
- template
- inline Matrix numericalHessian333(double (*f)(const X1&, const X2&, const X3&), const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian333(boost::function(f), x1, x2, x3, delta);
- }
-
- /* **************************************************************** */
- template
- inline Matrix numericalHessian312(boost::function f, const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian212(boost::function(boost::bind(f, _1, _2, x3)), x1, x2, delta );
- }
-
- template
- inline Matrix numericalHessian313(boost::function f, const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian212(boost::function(boost::bind(f, _1, x2, _2)), x1, x3, delta );
- }
-
- template
- inline Matrix numericalHessian323(boost::function f, const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian212(boost::function(boost::bind(f, x1, _1, _2)), x2, x3, delta );
- }
-
- /* **************************************************************** */
- template
- inline Matrix numericalHessian312(double (*f)(const X1&, const X2&, const X3&), const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian312(boost::function(f), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalHessian313(double (*f)(const X1&, const X2&, const X3&), const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian313(boost::function(f), x1, x2, x3, delta);
- }
-
- template
- inline Matrix numericalHessian323(double (*f)(const X1&, const X2&, const X3&), const X1& x1, const X2& x2, const X3& x3, double delta=1e-5) {
- return numericalHessian323(boost::function(f), x1, x2, x3, delta);
- }
+/*
+ * Note that all of these functions have two versions, a boost.function version and a
+ * standard C++ function pointer version. This allows reformulating the arguments of
+ * a function to fit the correct structure, which is useful for situations like
+ * member functions and functions with arguments not involved in the derivative:
+ *
+ * Usage of the boost bind version to rearrange arguments:
+ * for a function with one relevant param and an optional derivative:
+ * Foo bar(const Obj& a, boost::optional H1)
+ * Use boost.bind to restructure:
+ * boost::bind(bar, _1, boost::none)
+ * This syntax will fix the optional argument to boost::none, while using the first argument provided
+ *
+ * For member functions, such as below, with an instantiated copy instanceOfSomeClass
+ * Foo SomeClass::bar(const Obj& a)
+ * Use boost bind as follows to create a function pointer that uses the member function:
+ * boost::bind(&SomeClass::bar, ref(instanceOfSomeClass), _1)
+ *
+ * For additional details, see the documentation:
+ * http://www.boost.org/doc/libs/release/libs/bind/bind.html
+ */
+
+/** global functions for converting to a LieVector for use with numericalDerivative */
+inline LieVector makeLieVector(const Vector& v) {
+ return LieVector(v);
+}
+inline LieVector makeLieVectorD(double d) {
+ return LieVector((Vector) (Vector(1) << d));
+}
+
+/**
+ * Numerically compute gradient of scalar function
+ * Class X is the input argument
+ * The class X needs to have dim, expmap, logmap
+ */
+template
+Vector numericalGradient(boost::function h, const X& x,
+ double delta = 1e-5) {
+ double factor = 1.0 / (2.0 * delta);
+
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X must be a manifold type.");
+ typedef DefaultChart ChartX;
+ typedef typename ChartX::vector TangentX;
+
+ // get chart at x
+ ChartX chartX(x);
+ TangentX zeroX = chartX.apply(x);
+ size_t n = zeroX.size(); // hack to get size if dynamic type
+
+ // Prepare a tangent vector to perturb x with, only works for fixed size
+ TangentX d;
+ d.setZero();
+
+ Vector g = zero(n);
+ for (int j = 0; j < n; j++) {
+ d(j) = delta;
+ double hxplus = h(chartX.retract(d));
+ d(j) = -delta;
+ double hxmin = h(chartX.retract(d));
+ d(j) = 0;
+ g(j) = (hxplus - hxmin) * factor;
+ }
+ return g;
+}
+
+/**
+ * @brief New-style numerical derivatives using manifold_traits
+ * @brief Computes numerical derivative in argument 1 of unary function
+ * @param h unary function yielding m-vector
+ * @param x n-dimensional value at which to evaluate h
+ * @param delta increment for numerical derivative
+ * Class Y is the output argument
+ * Class X is the input argument
+ * @return m*n Jacobian computed via central differencing
+ */
+template
+// TODO Should compute fixed-size matrix
+Matrix numericalDerivative11(boost::function h, const X& x,
+ double delta = 1e-5) {
+ using namespace traits;
+
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument Y must be a manifold type.");
+ typedef DefaultChart ChartY;
+ typedef typename ChartY::vector TangentY;
+
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X must be a manifold type.");
+ typedef DefaultChart ChartX;
+ typedef typename ChartX::vector TangentX;
+
+ // get value at x, and corresponding chart
+ Y hx = h(x);
+ ChartY chartY(hx);
+ TangentY zeroY = chartY.apply(hx);
+ size_t m = zeroY.size();
+
+ // get chart at x
+ ChartX chartX(x);
+ TangentX zeroX = chartX.apply(x);
+ size_t n = zeroX.size();
+
+ // Prepare a tangent vector to perturb x with, only works for fixed size
+ TangentX dx;
+ dx.setZero();
+
+ // Fill in Jacobian H
+ Matrix H = zeros(m,n);
+ double factor = 1.0 / (2.0 * delta);
+ for (int j = 0; j < n; j++) {
+ dx(j) = delta;
+ TangentY dy1 = chartY.apply(h(chartX.retract(dx)));
+ dx(j) = -delta;
+ TangentY dy2 = chartY.apply(h(chartX.retract(dx)));
+ dx(j) = 0;
+ H.col(j) << (dy1 - dy2) * factor;
+ }
+ return H;
+}
+
+/** use a raw C++ function pointer */
+template
+Matrix numericalDerivative11(Y (*h)(const X&), const X& x,
+ double delta = 1e-5) {
+ return numericalDerivative11(boost::bind(h, _1), x, delta);
+}
+
+/**
+ * Compute numerical derivative in argument 1 of binary function
+ * @param h binary function yielding m-vector
+ * @param x1 n-dimensional first argument value
+ * @param x2 second argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ */
+template
+Matrix numericalDerivative21(const boost::function& h,
+ const X1& x1, const X2& x2, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X1 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, _1, x2), x1, delta);
+}
+
+/** use a raw C++ function pointer */
+template
+inline Matrix numericalDerivative21(Y (*h)(const X1&, const X2&), const X1& x1,
+ const X2& x2, double delta = 1e-5) {
+ return numericalDerivative21(boost::bind(h, _1, _2), x1, x2, delta);
+}
+
+/**
+ * Compute numerical derivative in argument 2 of binary function
+ * @param h binary function yielding m-vector
+ * @param x1 first argument value
+ * @param x2 n-dimensional second argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ */
+template
+Matrix numericalDerivative22(boost::function h,
+ const X1& x1, const X2& x2, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X2 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, x1, _1), x2, delta);
+}
+
+/** use a raw C++ function pointer */
+template
+inline Matrix numericalDerivative22(Y (*h)(const X1&, const X2&), const X1& x1,
+ const X2& x2, double delta = 1e-5) {
+ return numericalDerivative22(boost::bind(h, _1, _2), x1, x2, delta);
+}
+
+/**
+ * Compute numerical derivative in argument 1 of ternary function
+ * @param h ternary function yielding m-vector
+ * @param x1 n-dimensional first argument value
+ * @param x2 second argument value
+ * @param x3 third argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ * All classes Y,X1,X2,X3 need dim, expmap, logmap
+ */
+template
+Matrix numericalDerivative31(
+ boost::function h, const X1& x1,
+ const X2& x2, const X3& x3, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X1 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, _1, x2, x3), x1, delta);
+}
+
+template
+inline Matrix numericalDerivative31(Y (*h)(const X1&, const X2&, const X3&),
+ const X1& x1, const X2& x2, const X3& x3, double delta = 1e-5) {
+ return numericalDerivative31(boost::bind(h, _1, _2, _3), x1,
+ x2, x3, delta);
+}
+
+/**
+ * Compute numerical derivative in argument 2 of ternary function
+ * @param h ternary function yielding m-vector
+ * @param x1 n-dimensional first argument value
+ * @param x2 second argument value
+ * @param x3 third argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ * All classes Y,X1,X2,X3 need dim, expmap, logmap
+ */
+template
+Matrix numericalDerivative32(
+ boost::function h, const X1& x1,
+ const X2& x2, const X3& x3, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X2 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, x1, _1, x3), x2, delta);
+}
+
+template
+inline Matrix numericalDerivative32(Y (*h)(const X1&, const X2&, const X3&),
+ const X1& x1, const X2& x2, const X3& x3, double delta = 1e-5) {
+ return numericalDerivative32(boost::bind(h, _1, _2, _3), x1,
+ x2, x3, delta);
+}
+
+/**
+ * Compute numerical derivative in argument 3 of ternary function
+ * @param h ternary function yielding m-vector
+ * @param x1 n-dimensional first argument value
+ * @param x2 second argument value
+ * @param x3 third argument value
+ * @param delta increment for numerical derivative
+ * @return m*n Jacobian computed via central differencing
+ * All classes Y,X1,X2,X3 need dim, expmap, logmap
+ */
+template
+Matrix numericalDerivative33(
+ boost::function h, const X1& x1,
+ const X2& x2, const X3& x3, double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument Y must be a manifold type.");
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X3 must be a manifold type.");
+ return numericalDerivative11(boost::bind(h, x1, x2, _1), x3, delta);
+}
+
+template
+inline Matrix numericalDerivative33(Y (*h)(const X1&, const X2&, const X3&),
+ const X1& x1, const X2& x2, const X3& x3, double delta = 1e-5) {
+ return numericalDerivative33(boost::bind(h, _1, _2, _3), x1,
+ x2, x3, delta);
+}
+
+/**
+ * Compute numerical Hessian matrix. Requires a single-argument Lie->scalar
+ * function. This is implemented simply as the derivative of the gradient.
+ * @param f A function taking a Lie object as input and returning a scalar
+ * @param x The center point for computing the Hessian
+ * @param delta The numerical derivative step size
+ * @return n*n Hessian matrix computed via central differencing
+ */
+template
+inline Matrix numericalHessian(boost::function f, const X& x,
+ double delta = 1e-5) {
+ BOOST_STATIC_ASSERT_MSG(traits::is_manifold::value,
+ "Template argument X must be a manifold type.");
+ typedef boost::function F;
+ typedef boost::function G;
+ G ng = static_cast(numericalGradient );
+ return numericalDerivative11(boost::bind(ng, f, _1, delta), x,
+ delta);
+}
+
+template
+inline Matrix numericalHessian(double (*f)(const X&), const X& x, double delta =
+ 1e-5) {
+ return numericalHessian(boost::function(f), x, delta);
+}
+
+/** Helper class that computes the derivative of f w.r.t. x1, centered about
+ * x1_, as a function of x2
+ */
+template
+class G_x1 {
+ const boost::function& f_;
+ X1 x1_;
+ double delta_;
+public:
+ G_x1(const boost::function& f, const X1& x1,
+ double delta) :
+ f_(f), x1_(x1), delta_(delta) {
+ }
+ Vector operator()(const X2& x2) {
+ return numericalGradient(boost::bind(f_, _1, x2), x1_, delta_);
+ }
+};
+
+template
+inline Matrix numericalHessian212(
+ boost::function f, const X1& x1, const X2& x2,
+ double delta = 1e-5) {
+ G_x1 g_x1(f, x1, delta);
+ return numericalDerivative11(
+ boost::function(
+ boost::bind(boost::ref(g_x1), _1)), x2, delta);
+}
+
+template
+inline Matrix numericalHessian212(double (*f)(const X1&, const X2&),
+ const X1& x1, const X2& x2, double delta = 1e-5) {
+ return numericalHessian212(boost::function(f),
+ x1, x2, delta);
+}
+
+template
+inline Matrix numericalHessian211(
+ boost::function f, const X1& x1, const X2& x2,
+ double delta = 1e-5) {
+
+ Vector (*numGrad)(boost::function, const X1&,
+ double) = &numericalGradient;
+ boost::function f2(boost::bind(f, _1, x2));
+
+ return numericalDerivative11(
+ boost::function