3#include <IpIpoptApplication.hpp>
14 Ipopt::SmartPtr<Ipopt::IpoptApplication> &solver,
15 std::ostream &os,
unsigned N_exp) {
18 Ipopt::SmartPtr<Ipopt::TNLP> nlp =
new Problem(problem.
problem);
19 auto *my_nlp =
dynamic_cast<Problem *
>(GetRawPtr(nlp));
23 throw std::invalid_argument(
24 "Invalid size for initial_guess_x (got " + std::to_string(sz) +
25 ", expected " + std::to_string(problem.
problem.
get_n()) +
")");
27 throw std::invalid_argument(
28 "Invalid size for initial_guess_y (got " + std::to_string(sz) +
29 ", expected " + std::to_string(problem.
problem.
get_m()) +
")");
34 throw std::invalid_argument(
35 "Invalid size for initial_guess_w (got " + std::to_string(sz) +
36 ", expected " + std::to_string(problem.
problem.
get_n() * 2) +
38 my_nlp->initial_guess_bounds_multipliers_l =
40 my_nlp->initial_guess_bounds_multipliers_u =
45 auto t0 = std::chrono::steady_clock::now();
46 auto status = solver->OptimizeTNLP(nlp);
47 auto t1 = std::chrono::steady_clock::now();
51 using ns = std::chrono::nanoseconds;
52 auto avg_duration = duration_cast<ns>(t1 - t0);
53 os.setstate(std::ios_base::badbit);
54 for (
unsigned i = 0; i < N_exp; ++i) {
58 auto t0 = std::chrono::steady_clock::now();
59 solver->OptimizeTNLP(nlp);
60 auto t1 = std::chrono::steady_clock::now();
61 avg_duration += duration_cast<ns>(t1 - t0);
64 avg_duration /= (N_exp + 1);
67 auto &nlp_res = my_nlp->results;
70 .success = status == Ipopt::Solve_Succeeded,
72 .duration = avg_duration,
75 .δ = nlp_res.infeasibility,
76 .ε = nlp_res.nlp_error,
79 .solution = nlp_res.solution_x,
80 .multipliers = nlp_res.solution_y,
81 .multipliers_bounds = Problem::vec(problem.
problem.
get_n() * 2),
82 .outer_iter = nlp_res.iter_count,
83 .inner_iter = nlp_res.iter_count,
86 results.multipliers_bounds << nlp_res.solution_z_L, nlp_res.solution_z_U;
90auto make_ipopt_solver(
Options &opts) {
91 using namespace Ipopt;
95 SmartPtr<IpoptApplication> app = IpoptApplicationFactory();
96 app->RethrowNonIpoptException(
true);
98 app->Options()->SetNumericValue(
"tol", 1e-8);
99 app->Options()->SetNumericValue(
"constr_viol_tol", 1e-8);
100 app->Options()->SetStringValue(
"linear_solver",
"mumps");
103 app->Options()->SetStringValue(
"hessian_approximation",
"exact");
108 ApplicationReturnStatus status = app->Initialize();
109 if (status != Solve_Succeeded)
110 throw std::runtime_error(
"Error during Ipopt initialization: " +
119 if (!direction.empty())
120 throw std::invalid_argument(
121 "Ipopt solver does not support any directions");
122 auto solver = make_ipopt_solver(opts);
125 return [solver{std::move(solver)},
128 return run_ipopt_solver(problem, solver, os, N_exp);
Based on https://coin-or.github.io/Ipopt/INTERFACES.html.
length_t get_n() const
[Required] Number of decision variables.
length_t get_m() const
[Required] Number of constraints.
solver_func_t make_ipopt_driver(std::string_view direction, Options &opts)
std::string_view enum_name(Ipopt::ApplicationReturnStatus s)
@ Ipopt
The stopping criterion used by Ipopt, see https://link.springer.com/article/10.1007/s10107-004-0559-y...
decltype(auto) set_params(T &t, std::string_view prefix, Options &opts)
vec initial_guess_y
Unknowns.
vec initial_guess_w
Multipliers g.
alpaqa::TypeErasedProblem< config_t > problem
std::shared_ptr< alpaqa::EvalCounter > evaluations
std::function< solver_free_func_t > solver_func_t