8 #ifndef INCLUDE_TEMPLE_NEWTON_RAPHSON_H
9 #define INCLUDE_TEMPLE_NEWTON_RAPHSON_H
12 #include <Eigen/Eigenvalues>
13 #include <unsupported/Eigen/NumericalDiff>
14 #include "Molassembler/Temple/STL17.h"
18 namespace Molassembler {
30 template<
typename FloatType =
double>
32 using MatrixType = Eigen::Matrix<FloatType, Eigen::Dynamic, Eigen::Dynamic>;
33 using VectorType = Eigen::Matrix<FloatType, Eigen::Dynamic, 1>;
46 typename UpdateFunction,
49 Eigen::Ref<VectorType> parameters,
50 UpdateFunction&&
function,
53 const unsigned P = parameters.size();
55 VectorType gradients = Eigen::VectorXd::Zero(P);
56 MatrixType hessian (P, P);
59 VectorType numericalGradient(P);
61 constexpr FloatType h = 1e-4;
64 VectorType diffParameters = parameters;
65 for(
unsigned i = 0; i < P; ++i) {
66 diffParameters(i) += h;
67 function(diffParameters, b, gradients, hessian);
68 diffParameters(i) -= 2 * h;
69 function(diffParameters, a, gradients, hessian);
70 diffParameters(i) = parameters(i);
71 numericalGradient(i) = (b - a) / (2 * h);
75 function(parameters, value, gradients, hessian);
77 if(numericalGradient.norm() > 1e-4) {
78 if(!numericalGradient.isApprox(gradients, 1e-8)) {
79 std::cout <<
"MISMATCH: Numerical gradient is " << numericalGradient.transpose() <<
"\nfunction gradient is : " << gradients.transpose() <<
"\n";
81 std::cout <<
"match: norm is " << gradients.norm() <<
" and diff norm is " << (numericalGradient - gradients).norm() <<
"\n";
85 MatrixType numericalHessian(P, P);
87 constexpr FloatType h = 1e-4;
92 VectorType diffParameters = parameters;
93 for(
unsigned i = 0; i < P; ++i) {
95 function(diffParameters, b, gradients, hessian);
96 diffParameters(i) += h;
97 function(diffParameters, c, gradients, hessian);
98 diffParameters(i) -= 2 * h;
99 function(diffParameters, a, gradients, hessian);
100 diffParameters(i) = parameters(i);
101 numericalHessian(i, i) = (a - 2 * b + c) / (h * h);
104 for(
unsigned j = i + 1; j < P; ++j) {
106 diffParameters(i) += h;
107 diffParameters(j) += h;
108 function(diffParameters, a, gradients, hessian);
110 diffParameters(j) -= 2 * h;
111 function(diffParameters, b, gradients, hessian);
113 diffParameters(i) -= 2 * h;
114 function(diffParameters, d, gradients, hessian);
116 diffParameters(j) += 2 * h;
117 function(diffParameters, c, gradients, hessian);
119 numericalHessian(i, j) = (a - b - c + d) / (4 * h * h);
120 numericalHessian(j, i) = numericalHessian(i, j);
125 function(parameters, value, gradients, hessian);
127 if(!numericalHessian.isApprox(hessian), 1e-2) {
128 std::cout <<
"MISMATCH: Hessian is\n" << hessian <<
"\nNumerical hessian is\n" << numericalHessian <<
"\n";
130 std::cout <<
"Hessian matches\n";
133 unsigned iteration = 0;
135 check.shouldContinue(
137 Stl17::as_const(value),
138 Stl17::as_const(gradients)
142 Eigen::JacobiSVD<MatrixType> svd(
144 Eigen::ComputeFullV | Eigen::ComputeFullU
147 VectorType steps = svd.solve(gradients);
150 FloatType rms = std::sqrt(steps.squaredNorm() / P);
156 function(parameters, value, gradients, hessian);
FloatType value
Final function value.
Definition: NewtonRaphson.h:40
unsigned iterations
Number of iterations.
Definition: NewtonRaphson.h:38
Type returned from an optimization.
Definition: NewtonRaphson.h:36
VectorType gradient
Final gradient.
Definition: NewtonRaphson.h:42
FloatType trustRadius
The maximum RMS of a taken step.
Definition: NewtonRaphson.h:170
FloatType svdThreshold
The SVD threshold for the decomposition of the Hessian.
Definition: NewtonRaphson.h:168
A very basic newton-raphson minimizer.
Definition: NewtonRaphson.h:31