/** * @file numericalDerivative.h * @brief Some functions to compute numerical derivatives * @author Frank Dellaert */ // \callgraph #pragma once #include #include #include #include #include //#define LINEARIZE_AT_IDENTITY 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/1_43_0/libs/bind/bind.html */ /** global functions for converting to a LieVector for use with numericalDerivative */ LieVector makeLieVector(const Vector& v) { return LieVector(v); } LieVector makeLieVectorD(double d) { return LieVector(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(n,0.0), g(n,0.0); 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(n,0.0); 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(n,0.0); 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(n,0.0); 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(n,0.0); 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(n,0.0); 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(n,0.0); 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); } }