nonlinear solvers: tutorial 1#
#include "pressio/solvers_nonlinear.hpp"
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <optional>
struct MyProblem
{
using state_type = Eigen::VectorXd;
using residual_type = state_type;
using jacobian_type = Eigen::SparseMatrix<double>;
state_type createState() const {
state_type a(2);
a.setZero();
return a;
}
residual_type createResidual() const {
residual_type a(2);
a.setZero();
return a;
}
jacobian_type createJacobian() const {
jacobian_type a(2, 2);
a.setZero();
return a;
}
void residualAndJacobian(const state_type& x,
residual_type& res,
std::optional<jacobian_type*> Jin) const
{
res(0) = x(0)*x(0) + x(1)*x(1) - 4.0;
res(1) = x(0)*x(1) - 1.0;
if (Jin){
auto & jac = *Jin.value();
jac.coeffRef(0, 0) = 2*x(0);
jac.coeffRef(0, 1) = 2*x(1);
// Have incorrect entries so that line search is required
jac.coeffRef(1, 0) = 0.1*x(1);
jac.coeffRef(1, 1) = 0.1*x(0);
}
}
};
class MyLinearSolver{
using A_t = typename MyProblem::jacobian_type;
using b_t = typename MyProblem::residual_type;
using x_t = typename MyProblem::state_type;
public:
void solve(A_t const & A, b_t const & b, x_t & x)
{
Eigen::BiCGSTAB< A_t > solver;
solver.compute(A);
x = solver.solve(b);
}
};
int main()
{
namespace plog = pressio::log;
namespace pnonls = pressio::nonlinearsolvers;
plog::initialize(pressio::logto::terminal);
plog::setVerbosity({plog::level::info});
MyProblem problem;
auto solver = pressio::create_newton_solver(problem, MyLinearSolver{});
const auto updateMethod = pnonls::Update::BacktrackStrictlyDecreasingObjective;
solver.setUpdateCriterion(updateMethod);
auto x = problem.createState();
x(0) = 0.3; x(1) = 0.4;
solver.solve(x);
// check solution
std::cout << "Computed solution: \n "
<< "["
<< std::setprecision(14)
<< x(0) << " "
<< x(1) << " " << "] \n"
<< "Expected solution: \n "
<< "[1.93185165, 0.51763809] \n";
plog::finalize();
return 0;
}