/** * @file numericalDerivative.h * @brief Some functions to compute numerical derivatives * @author Frank Dellaert */ // \callgraph #pragma once #include #include #include "Lie.h" #include "Matrix.h" //#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 */ /** * 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 = dim(hx), n = dim(x); 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); } /** * 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 = dim(hx), n = dim(x1); Vector d(n,0.0); Matrix H = zeros(m,n); for (size_t j=0;j 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 * 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 = dim(hx), n = dim(x2); Vector d(n,0.0); Matrix H = zeros(m,n); for (size_t j=0;j 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) { Y hx = h(x1,x2,x3); double factor = 1.0/(2.0*delta); const size_t m = dim(hx), n = dim(x1); Vector d(n,0.0); Matrix H = zeros(m,n); for (size_t j=0;j 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); } // arg 2 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 = dim(hx), n = dim(x2); Vector d(n,0.0); Matrix H = zeros(m,n); for (size_t j=0;j 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); } // arg 3 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 = dim(hx), n = dim(x3); Vector d(n,0.0); Matrix H = zeros(m,n); for (size_t j=0;j 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); } }