Newer
Older
template<typename Callable, typename Inputs>
auto NewtonRaphson(Callable f, const Inputs& args, double tol) {
// Jacobian matrix
Eigen::ArrayXd x = args, r0;
Eigen::MatrixXd J(args.size(), args.size());
for (int iter = 0; iter < 30; ++iter) {
r0 = f(x);
for (auto i = 0; i < args.size(); ++i) {
auto dri = std::max(1e-6 * x[i], 1e-8);
auto argsplus = x;
argsplus[i] += dri;
J.col(i) = (f(argsplus) - r0) / dri; // Forward diff to avoid negative concentration possibility
}
Eigen::ArrayXd v = J.colPivHouseholderQr().solve(-r0.matrix());
x += v;
auto err = r0.matrix().norm();
if (!std::isfinite(err)){
throw std::invalid_argument("err is now NaN");
}
if (err < tol) {
break;
}
}
return x;