Nonconvex constrained optimization
Loading...
Searching...
No Matches
ipopt-driver.cpp
Go to the documentation of this file.
1#ifdef ALPAQA_WITH_IPOPT
2
6#include <IpIpoptApplication.hpp>
7
8#include <stdexcept>
9#include <string>
10
13
14namespace alpaqa::driver {
15namespace {
16
17SolverResults run_ipopt_solver(auto &problem,
18 Ipopt::SmartPtr<Ipopt::IpoptApplication> &solver,
19 std::ostream &os, unsigned N_exp) {
20 // Ipopt problem adapter
21 using Problem = IpoptAdapter;
22 Ipopt::SmartPtr<Ipopt::TNLP> nlp = new Problem(problem.problem);
23 auto *my_nlp = dynamic_cast<Problem *>(GetRawPtr(nlp));
24
25 USING_ALPAQA_CONFIG(Problem::config_t);
26
27 // Dimensions
28 length_t n = problem.problem.get_num_variables(),
29 m = problem.problem.get_num_constraints();
30
31 // Initial guess
32 if (auto sz = problem.initial_guess_x.size(); sz != n)
33 throw std::invalid_argument(
34 "Invalid size for initial_guess_x (expected " + std::to_string(n) +
35 ", but got " + std::to_string(sz) + ")");
36 if (auto sz = problem.initial_guess_y.size(); sz != m)
37 throw std::invalid_argument(
38 "Invalid size for initial_guess_y (expected " + std::to_string(m) +
39 ", but got " + std::to_string(sz) + ")");
40 my_nlp->initial_guess = problem.initial_guess_x;
41 my_nlp->initial_guess_multipliers = problem.initial_guess_y;
42 if (auto sz = problem.initial_guess_w.size(); sz > 0) {
43 if (sz != n)
44 throw std::invalid_argument(
45 "Invalid size for initial_guess_w (expected " +
46 std::to_string(n) + ", but got " + std::to_string(sz) + ")");
47 my_nlp->initial_guess_bounds_multipliers = problem.initial_guess_w;
48 }
49
50 // Solve the problem
51 auto t0 = std::chrono::steady_clock::now();
52 auto status = solver->OptimizeTNLP(nlp);
53 auto t1 = std::chrono::steady_clock::now();
54
55 // Solve the problems again to average runtimes
56 using ns = std::chrono::nanoseconds;
57 auto avg_duration = duration_cast<ns>(t1 - t0);
58 os.setstate(std::ios_base::badbit);
59 for (unsigned i = 0; i < N_exp; ++i) {
60 my_nlp->initial_guess = problem.initial_guess_x;
61 my_nlp->initial_guess_multipliers = problem.initial_guess_y;
62 my_nlp->initial_guess_bounds_multipliers = problem.initial_guess_w;
63
64 auto t0 = std::chrono::steady_clock::now();
65 solver->OptimizeTNLP(nlp);
66 auto t1 = std::chrono::steady_clock::now();
67 avg_duration += duration_cast<ns>(t1 - t0);
68 }
69 os.clear();
70 avg_duration /= (N_exp + 1);
71 auto evals = *problem.evaluations;
72
73 // Results
74 auto &nlp_res = my_nlp->results;
75 if (nlp_res.status == Ipopt::SolverReturn::UNASSIGNED) {
76 nlp_res.solution_x = vec::Constant(n, NaN<config_t>);
77 nlp_res.solution_y = vec::Constant(m, NaN<config_t>);
78 nlp_res.solution_z_L = vec::Constant(n, NaN<config_t>);
79 nlp_res.solution_z_U = vec::Constant(n, NaN<config_t>);
80 }
81 SolverResults results{
82 .status = std::string(enum_name(status)),
83 .success = status == Ipopt::Solve_Succeeded,
84 .evals = evals,
85 .duration = avg_duration,
86 .solver = "Ipopt",
87 .h = 0,
88 .δ = nlp_res.infeasibility,
89 .ε = nlp_res.nlp_error,
90 .γ = 0,
91 .Σ = 0,
92 .solution = nlp_res.solution_x,
93 .multipliers = nlp_res.solution_y,
94 .multipliers_bounds = nlp_res.combine_bounds_multipliers(),
95 .penalties = vec::Zero(n),
96 .outer_iter = nlp_res.iter_count,
97 .inner_iter = nlp_res.iter_count,
98 .extra = {},
99 };
100 return results;
101}
102
103auto make_ipopt_solver(Options &opts) {
104 using namespace Ipopt;
105
106 // We are using the factory, since this allows us to compile this
107 // example with an Ipopt Windows DLL
108 SmartPtr<IpoptApplication> app = IpoptApplicationFactory();
109 app->RethrowNonIpoptException(true);
110
111 app->Options()->SetNumericValue("tol", 1e-8);
112 app->Options()->SetNumericValue("constr_viol_tol", 1e-8);
113 app->Options()->SetStringValue("linear_solver", "mumps");
114 // app->Options()->SetStringValue("print_timing_statistics", "yes");
115 // app->Options()->SetStringValue("timing_statistics", "yes");
116 app->Options()->SetStringValue("hessian_approximation", "exact");
117
118 set_params(*app, "solver", opts);
119
120 // Initialize the IpoptApplication and process the options
121 ApplicationReturnStatus status = app->Initialize();
122 if (status != Solve_Succeeded)
123 throw std::runtime_error("Error during Ipopt initialization: " +
124 std::string(enum_name(status)));
125
126 return app;
127}
128
129template <class LoadedProblem>
130SharedSolverWrapper make_ipopt_drive_impl(std::string_view direction,
131 Options &opts) {
132 if (!direction.empty())
133 throw std::invalid_argument(
134 "Ipopt solver does not support any directions");
135 auto solver = make_ipopt_solver(opts);
136 unsigned N_exp = 0;
137 set_params(N_exp, "num_exp", opts);
138 return std::make_shared<SolverWrapper>(
139 [solver{std::move(solver)}, N_exp](
140 LoadedProblem &problem, std::ostream &os) mutable -> SolverResults {
141 return run_ipopt_solver(problem, solver, os, N_exp);
142 });
143}
144
145} // namespace
146
147SharedSolverWrapper make_ipopt_driver(std::string_view direction,
148 Options &opts) {
149 static constexpr bool valid_config =
150 std::is_same_v<LoadedProblem::config_t, IpoptAdapter::config_t>;
151 if constexpr (valid_config)
152 return make_ipopt_drive_impl<LoadedProblem>(direction, opts);
153 else
154 throw std::invalid_argument(
155 "Ipopt solver only supports double precision");
156}
157} // namespace alpaqa::driver
158
159#else
160
162
163namespace alpaqa::driver {
165 throw std::invalid_argument(
166 "This version of alpaqa was compiled without Ipopt support.");
167}
168} // namespace alpaqa::driver
169
170#endif
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
SharedSolverWrapper make_ipopt_driver(std::string_view, Options &)
std::shared_ptr< SolverWrapper > SharedSolverWrapper
@ Ipopt
The stopping criterion used by Ipopt, see https://link.springer.com/article/10.1007/s10107-004-0559-y...
constexpr const auto NaN
Definition config.hpp:114
void set_params(T &t, std::string_view prefix, Options &opts)
Definition options.hpp:128
typename Conf::length_t length_t
Definition config.hpp:103
constexpr const char * enum_name(LBFGSStepSize s)
Definition lbfgs.hpp:229