Nonconvex constrained optimization
Loading...
Searching...
No Matches
ipopt-adapter.cpp
Go to the documentation of this file.
2
4
5#include <IpIpoptCalculatedQuantities.hpp>
6#include <IpIpoptData.hpp>
7#include <stdexcept>
8
9namespace alpaqa {
10
12
14 Index &nnz_h_lag, IndexStyleEnum &index_style) {
15 n = static_cast<Index>(problem.get_num_variables());
16 m = static_cast<Index>(problem.get_num_constraints());
17 nnz_jac_g = static_cast<Index>(cvt_sparsity_jac_g.get_sparsity().nnz());
18 nnz_h_lag = static_cast<Index>(cvt_sparsity_hess_L.get_sparsity().nnz());
19 auto jac_g_index = cvt_sparsity_jac_g.get_sparsity().first_index;
20 auto hess_L_index = cvt_sparsity_hess_L.get_sparsity().first_index;
21 if (jac_g_index != hess_L_index)
22 throw std::invalid_argument(
23 "All problem matrices should use the same index convention");
24 if (jac_g_index != 0 && jac_g_index != 1)
25 throw std::invalid_argument(
26 "Sparse matrix indices should start at 0 or 1");
27 index_style = jac_g_index == 0 ? TNLP::C_STYLE : TNLP::FORTRAN_STYLE;
28 auto hess_L_sym = cvt_sparsity_hess_L.get_sparsity().symmetry;
29 using enum sparsity::Symmetry;
30 if (hess_L_sym != Upper && hess_L_sym != Lower)
31 throw std::invalid_argument("Hessian matrix should be symmetric");
32 return true;
33}
34
36 Number *g_l, Number *g_u) {
37 if (problem.provides_get_variable_bounds()) {
38 const auto &C = problem.get_variable_bounds();
39 mvec{x_l, n} = C.lower;
40 mvec{x_u, n} = C.upper;
41 } else {
42 mvec{x_l, n}.setConstant(-std::numeric_limits<Number>::infinity());
43 mvec{x_u, n}.setConstant(+std::numeric_limits<Number>::infinity());
44 }
45 if (problem.provides_get_general_bounds()) {
46 const auto &D = problem.get_general_bounds();
47 mvec{g_l, m} = D.lower;
48 mvec{g_u, m} = D.upper;
49 } else {
50 mvec{g_l, m}.setConstant(-std::numeric_limits<Number>::infinity());
51 mvec{g_u, m}.setConstant(+std::numeric_limits<Number>::infinity());
52 }
53 return true;
54}
55
57 bool init_z, Number *z_L, Number *z_U,
58 Index m, bool init_lambda,
59 Number *lambda) {
60 if (init_x) {
61 if (initial_guess.size() > 0)
62 mvec{x, n} = initial_guess;
63 else
64 mvec{x, n}.setZero();
65 }
66 if (init_z) {
68 mvec{z_L, n} = (initial_guess_bounds_multipliers.array() < 0)
70 else
71 mvec{z_L, n}.setZero();
73 mvec{z_U, n} = (initial_guess_bounds_multipliers.array() > 0)
75 else
76 mvec{z_U, n}.setZero();
77 }
78 if (init_lambda) {
79 if (initial_guess_multipliers.size() > 0)
81 else
82 mvec{lambda, m}.setZero();
83 }
84 return true;
85}
86
87bool IpoptAdapter::eval_f(Index n, const Number *x, [[maybe_unused]] bool new_x,
88 Number &obj_value) {
89 obj_value = problem.eval_objective(cmvec{x, n});
90 return true;
91}
92
94 [[maybe_unused]] bool new_x, Number *grad_f) {
95 problem.eval_objective_gradient(cmvec{x, n}, mvec{grad_f, n});
96 return true;
97}
98
99bool IpoptAdapter::eval_g(Index n, const Number *x, [[maybe_unused]] bool new_x,
100 Index m, Number *g) {
101 problem.eval_constraints(cmvec{x, n}, mvec{g, m});
102 return true;
103}
104
106 [[maybe_unused]] bool new_x,
107 [[maybe_unused]] Index m, Index nele_jac,
108 Index *iRow, Index *jCol, Number *values) {
109 if (values == nullptr) { // Initialize sparsity
110 std::ranges::copy(cvt_sparsity_jac_g.get_sparsity().row_indices, iRow);
111 std::ranges::copy(cvt_sparsity_jac_g.get_sparsity().col_indices, jCol);
112 } else { // Evaluate values
113 cvt_sparsity_jac_g.convert_values_into(
114 std::span{values, static_cast<size_t>(nele_jac)},
115 [&](std::span<real_t> v) {
116 problem.eval_constraints_jacobian(cmvec{x, n}, as_vec(v));
117 });
118 // TODO: reuse workspace
119 }
120 return true;
121}
122
123bool IpoptAdapter::eval_h(Index n, const Number *x, [[maybe_unused]] bool new_x,
124 Number obj_factor, Index m, const Number *lambda,
125 [[maybe_unused]] bool new_lambda, Index nele_hess,
126 Index *iRow, Index *jCol, Number *values) {
127 if (values == nullptr) { // Initialize sparsity
128 std::ranges::copy(cvt_sparsity_hess_L.get_sparsity().row_indices, iRow);
129 std::ranges::copy(cvt_sparsity_hess_L.get_sparsity().col_indices, jCol);
130 } else { // Evaluate values
131 cvt_sparsity_hess_L.convert_values_into(
132 std::span{values, static_cast<size_t>(nele_hess)},
133 [&](std::span<real_t> v) {
134 problem.eval_lagrangian_hessian(cmvec{x, n}, cmvec{lambda, m},
135 obj_factor, as_vec(v));
136 });
137 // TODO: reuse workspace
138 }
139 return true;
140}
141void IpoptAdapter::finalize_solution(Ipopt::SolverReturn status, Index n,
142 const Number *x, const Number *z_L,
143 const Number *z_U, Index m,
144 const Number *g, const Number *lambda,
145 Number obj_value,
146 const Ipopt::IpoptData *ip_data,
147 Ipopt::IpoptCalculatedQuantities *ip_cq) {
148 results.status = status;
149 results.solution_x = cmvec{x, n};
150 results.solution_z_L = cmvec{z_L, n};
151 results.solution_z_U = cmvec{z_U, n};
152 results.solution_y = cmvec{lambda, m};
153 results.solution_g = cmvec{g, m};
154 results.solution_f = obj_value;
155 results.infeasibility = ip_cq->curr_constraint_violation();
156 results.nlp_error = ip_cq->unscaled_curr_nlp_error();
157 results.iter_count = ip_data->iter_count();
158}
159
160} // namespace alpaqa
IpoptAdapter(const Problem &problem)
const Problem & problem
bool eval_g(Index n, const Number *x, bool new_x, Index m, Number *g) override
bool eval_grad_f(Index n, const Number *x, bool new_x, Number *grad_f) override
SparsityConv cvt_sparsity_jac_g
bool eval_h(Index n, const Number *x, bool new_x, Number obj_factor, Index m, const Number *lambda, bool new_lambda, Index nele_hess, Index *iRow, Index *jCol, Number *values) override
bool get_starting_point(Index n, bool init_x, Number *x, bool init_z, Number *z_L, Number *z_U, Index m, bool init_lambda, Number *lambda) override
bool get_bounds_info(Index n, Number *x_l, Number *x_u, Index m, Number *g_l, Number *g_u) override
struct alpaqa::IpoptAdapter::Results results
bool eval_f(Index n, const Number *x, bool new_x, Number &obj_value) override
bool get_nlp_info(Index &n, Index &m, Index &nnz_jac_g, Index &nnz_h_lag, IndexStyleEnum &index_style) override
bool eval_jac_g(Index n, const Number *x, bool new_x, Index m, Index nele_jac, Index *iRow, Index *jCol, Number *values) override
void finalize_solution(Ipopt::SolverReturn status, Index n, const Number *x, const Number *z_L, const Number *z_U, Index m, const Number *g, const Number *lambda, Number obj_value, const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq) override
TypeErasedProblem< config_t > Problem
SparsityConv cvt_sparsity_hess_L
typename Conf::mvec mvec
Definition config.hpp:89
auto as_vec(std::span< T, E > s)
Convert a std::span to an Eigen::Vector view.
Definition span.hpp:51
typename Conf::cmvec cmvec
Definition config.hpp:90