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;
63 VectorType diffParameters = parameters;
64 for(
unsigned i = 0; i < P; ++i) {
65 diffParameters(i) += h;
66 function(diffParameters, b, gradients, hessian);
67 diffParameters(i) -= 2 * h;
68 function(diffParameters, a, gradients, hessian);
69 diffParameters(i) = parameters(i);
70 numericalGradient(i) = (b - a) / (2 * h);
74 function(parameters, value, gradients, hessian);
76 if(numericalGradient.norm() > 1e-4) {
77 if(!numericalGradient.isApprox(gradients, 1e-8)) {
78 std::cout <<
"MISMATCH: Numerical gradient is " << numericalGradient.transpose() <<
"\nfunction gradient is : " << gradients.transpose() <<
"\n";
80 std::cout <<
"match: norm is " << gradients.norm() <<
" and diff norm is " << (numericalGradient - gradients).norm() <<
"\n";
84 MatrixType numericalHessian(P, P);
86 constexpr FloatType h = 1e-4;
88 VectorType diffParameters = parameters;
89 for(
unsigned i = 0; i < P; ++i) {
91 function(diffParameters, b, gradients, hessian);
92 diffParameters(i) += h;
93 function(diffParameters, c, gradients, hessian);
94 diffParameters(i) -= 2 * h;
95 function(diffParameters, a, gradients, hessian);
96 diffParameters(i) = parameters(i);
97 numericalHessian(i, i) = (a - 2 * b + c) / (h * h);
100 for(
unsigned j = i + 1; j < P; ++j) {
102 diffParameters(i) += h;
103 diffParameters(j) += h;
104 function(diffParameters, a, gradients, hessian);
106 diffParameters(j) -= 2 * h;
107 function(diffParameters, b, gradients, hessian);
109 diffParameters(i) -= 2 * h;
110 function(diffParameters, d, gradients, hessian);
112 diffParameters(j) += 2 * h;
113 function(diffParameters, c, gradients, hessian);
115 numericalHessian(i, j) = (a - b - c + d) / (4 * h * h);
116 numericalHessian(j, i) = numericalHessian(i, j);
121 function(parameters, value, gradients, hessian);
123 if(!numericalHessian.isApprox(hessian), 1e-2) {
124 std::cout <<
"MISMATCH: Hessian is\n" << hessian <<
"\nNumerical hessian is\n" << numericalHessian <<
"\n";
126 std::cout <<
"Hessian matches\n";
129 unsigned iteration = 0;
131 check.shouldContinue(
133 Stl17::as_const(value),
134 Stl17::as_const(gradients)
138 Eigen::JacobiSVD<MatrixType> svd(
140 Eigen::ComputeFullV | Eigen::ComputeFullU
143 VectorType steps = svd.solve(gradients);
146 FloatType rms = std::sqrt(steps.squaredNorm() / P);
152 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:166
FloatType svdThreshold
The SVD threshold for the decomposition of the Hessian.
Definition: NewtonRaphson.h:164
A very basic newton-raphson minimizer.
Definition: NewtonRaphson.h:31