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