#pragma once #include #include "autoopt/dual.hpp" namespace autoopt { template T derivative(Func&& f, const T& x) { dual a(x, T(1)); dual b = f(a); return b._dx; } template Eigen::VectorX gradient(Func&& f, const Eigen::VectorX& x) { Eigen::VectorX grad{x.size()}; Eigen::VectorX> dual_x{x.size()}; for (int i = 0; i < x.size(); ++i) { dual_x(i) = dual(x(i), T(0)); } for (int i = 0; i < x.size(); ++i) { dual_x(i)._dx = T(1); dual dual_y = f(dual_x); grad(i) = dual_y._dx; dual_x(i)._dx = T(0); } return grad; } template Eigen::MatrixX jacobian(Func&& f, const Eigen::VectorX& x) { Eigen::MatrixX jacob(f(x).size(), x.size()); Eigen::VectorX> dual_x(x.size()); for (int i = 0; i < x.size(); ++i) { dual_x(i) = dual(x(i), T(0)); } for (int i = 0; i < x.size(); ++i) { dual_x(i)._dx = T(1); Eigen::VectorX> dual_y = f(dual_x); for (int j = 0; j < dual_y.size(); ++j) { jacob(j, i) = dual_y(j)._dx; } dual_x(i)._dx = T(0); } return jacob; } template Eigen::MatrixX hessian(Func&& f, const Eigen::VectorX& x) { auto helper_func = [&f](const Eigen::VectorX& y) { return gradient(f, y); }; return jacobian(helper_func, x); } } // namespace autoopt