bonmin_nlp.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "bonmin_nlp.hpp"
27 #include "bonmin_interface.hpp"
28 #include "casadi/core/timing.hpp"
29 
30 namespace casadi {
31 
33  : solver_(solver), mem_(mem) {
34  n_ = solver_.nx_;
35  m_ = solver_.ng_;
36  }
37 
39  }
40 
41  // returns the size of the problem
42  bool BonminUserClass::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
43  Index& nnz_h_lag, TNLP::IndexStyleEnum& index_style) {
44  solver_.get_nlp_info(mem_, n, m, nnz_jac_g, nnz_h_lag);
45 
46  // use the C style indexing (0-based)
47  index_style = TNLP::C_STYLE;
48 
49  return true;
50  }
51 
52  // returns the variable bounds
53  bool BonminUserClass::get_bounds_info(Index n, Number* x_l, Number* x_u,
54  Index m, Number* g_l, Number* g_u) {
55  casadi_assert_dev(n==solver_.nx_);
56  casadi_assert_dev(m==solver_.ng_);
57  return solver_.get_bounds_info(mem_, x_l, x_u, g_l, g_u);
58  }
59 
60  // returns the initial point for the problem
61  bool BonminUserClass::get_starting_point(Index n, bool init_x, Number* x,
62  bool init_z, Number* z_L, Number* z_U,
63  Index m, bool init_lambda,
64  Number* lambda) {
65  casadi_assert_dev(n==solver_.nx_);
66  casadi_assert_dev(m==solver_.ng_);
67  return solver_.get_starting_point(mem_, init_x, x, init_z, z_L, z_U, init_lambda, lambda);
68  }
69 
70  // returns the value of the objective function
71  bool BonminUserClass::eval_f(Index n, const Number* x, bool new_x, Number& obj_value) {
72  mem_->arg[0] = x;
73  mem_->arg[1] = mem_->d_nlp.p;
74  mem_->res[0] = &obj_value;
75  try {
76  return solver_.calc_function(mem_, "nlp_f")==0;
77  } catch(KeyboardInterruptException& ex) {
78  casadi_warning("KeyboardInterruptException");
80  } catch (std::exception& ex) {
81  if (solver_.show_eval_warnings_) {
82  casadi_warning("BonminUserClass::nlp_f failed:" + std::string(ex.what()));
83  }
84  return false;
85  }
86  }
87 
88  // return the gradient of the objective function grad_ {x} f(x)
89  bool BonminUserClass::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f) {
90  mem_->arg[0] = x;
91  mem_->arg[1] = mem_->d_nlp.p;
92  mem_->res[0] = nullptr;
93  mem_->res[1] = grad_f;
94  try {
95  return solver_.calc_function(mem_, "nlp_grad_f")==0;
96  } catch(KeyboardInterruptException& ex) {
97  casadi_warning("KeyboardInterruptException");
99  } catch (std::exception& ex) {
100  if (solver_.show_eval_warnings_) {
101  casadi_warning("BonminUserClass::eval_grad_f failed:" + std::string(ex.what()));
102  }
103  return false;
104  }
105  }
106 
107  // return the value of the constraints: g(x)
108  bool BonminUserClass::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g) {
109  mem_->arg[0] = x;
110  mem_->arg[1] = mem_->d_nlp.p;
111  mem_->res[0] = g;
112  try {
113  return solver_.calc_function(mem_, "nlp_g")==0;
114  } catch(KeyboardInterruptException& ex) {
115  casadi_warning("KeyboardInterruptException");
117  } catch (std::exception& ex) {
118  if (solver_.show_eval_warnings_) {
119  casadi_warning("BonminUserClass::eval_g failed:" + std::string(ex.what()));
120  }
121  return false;
122  }
123  }
124 
125  // return the structure or values of the jacobian
126  bool BonminUserClass::eval_jac_g(Index n, const Number* x, bool new_x,
127  Index m, Index nele_jac, Index* iRow, Index *jCol,
128  Number* values) {
129  if (values) {
130  // Evaluate numerically
131  mem_->arg[0] = x;
132  mem_->arg[1] = mem_->d_nlp.p;
133  mem_->res[0] = nullptr;
134  mem_->res[1] = values;
135  try {
136  return solver_.calc_function(mem_, "nlp_jac_g")==0;
137  } catch(KeyboardInterruptException& ex) {
138  casadi_warning("KeyboardInterruptException");
140  } catch (std::exception& ex) {
141  if (solver_.show_eval_warnings_) {
142  casadi_warning("BonminUserClass::eval_jac_g failed:" + std::string(ex.what()));
143  }
144  return false;
145  }
146  } else {
147  // Get the sparsity pattern
148  casadi_int ncol = solver_.jacg_sp_.size2();
149  const casadi_int* colind = solver_.jacg_sp_.colind();
150  const casadi_int* row = solver_.jacg_sp_.row();
151  if (nele_jac!=colind[ncol]) return false; // consistency check
152 
153  // Pass to BONMIN
154  for (casadi_int cc=0; cc<ncol; ++cc) {
155  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
156  *iRow++ = row[el];
157  *jCol++ = cc;
158  }
159  }
160  return true;
161  }
162  }
163 
164 
165  bool BonminUserClass::eval_h(Index n, const Number* x, bool new_x,
166  Number obj_factor, Index m, const Number* lambda,
167  bool new_lambda, Index nele_hess, Index* iRow,
168  Index* jCol, Number* values) {
169  if (values) {
170  // Evaluate numerically
171  mem_->arg[0] = x;
172  mem_->arg[1] = mem_->d_nlp.p;
173  mem_->arg[2] = &obj_factor;
174  mem_->arg[3] = lambda;
175  mem_->res[0] = values;
176  try {
177  return solver_.calc_function(mem_, "nlp_hess_l")==0;
178  } catch(KeyboardInterruptException& ex) {
179  casadi_warning("KeyboardInterruptException");
181  } catch (std::exception& ex) {
182  if (solver_.show_eval_warnings_) {
183  casadi_warning("BonminUserClass::eval_h failed:" + std::string(ex.what()));
184  }
185  return false;
186  }
187  } else {
188  // Get the sparsity pattern
189  casadi_int ncol = solver_.hesslag_sp_.size2();
190  const casadi_int* colind = solver_.hesslag_sp_.colind();
191  const casadi_int* row = solver_.hesslag_sp_.row();
192 
193  // Pass to BONMIN
194  for (casadi_int cc=0; cc<ncol; ++cc) {
195  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
196  *iRow++ = row[el];
197  *jCol++ = cc;
198  }
199  }
200  return true;
201  }
202  }
203 
204  void BonminUserClass::finalize_solution(TMINLP::SolverReturn status,
205  Ipopt::Index n, const Ipopt::Number* x, Ipopt::Number obj_value) {
206  solver_.finalize_solution(mem_, status, x, obj_value);
207  }
208 
209 
210  bool BonminUserClass::intermediate_callback(AlgorithmMode mode, Index iter, Number obj_value,
211  Number inf_pr, Number inf_du,
212  Number mu, Number d_norm,
213  Number regularization_size,
214  Number alpha_du, Number alpha_pr,
215  Index ls_trials,
216  const IpoptData* ip_data,
217  IpoptCalculatedQuantities* ip_cq) {
218 
219  // Only do the callback every few iterations
220  if (iter % solver_.callback_step_!=0) return true;
221 
224  // http://list.coin-or.org/pipermail/ipopt/2010-April/001965.html
225 
226  bool full_callback = false;
227 
228  return solver_.intermediate_callback(mem_, x_, z_L_, z_U_, g_, lambda_, obj_value, iter,
229  inf_pr, inf_du, mu, d_norm, regularization_size,
230  alpha_du, alpha_pr, ls_trials, full_callback);
231  }
232 
234  return solver_.get_number_of_nonlinear_variables();
235  }
236 
238  Index* pos_nonlin_vars) {
239  return solver_.get_list_of_nonlinear_variables(num_nonlin_vars, pos_nonlin_vars);
240  }
241 
243  if (solver_.discrete_.empty()) {
244  std::fill_n(var_types, n, CONTINUOUS);
245  } else {
246  if (solver_.discrete_.size()!=n) return false;
247  for (auto&& d : solver_.discrete_) {
248  *var_types++ = d ? INTEGER : CONTINUOUS;
249  }
250  }
251  return true;
252  }
253 
254  bool BonminUserClass::get_variables_linearity(Index n, Ipopt::TNLP::LinearityType* var_types) {
255  casadi_assert_dev(n==solver_.nl_ex_.size());
256  for (casadi_int i=0; i<n; ++i)
257  var_types[i] = solver_.nl_ex_[i] ? Ipopt::TNLP::NON_LINEAR : Ipopt::TNLP::LINEAR;
258  return true;
259  }
260 
261  bool BonminUserClass::get_constraints_linearity(Index m, Ipopt::TNLP::LinearityType* const_types) {
262  casadi_assert_dev(m==solver_.nl_g_.size());
263  for (casadi_int i=0; i<m; ++i)
264  const_types[i] = solver_.nl_g_[i] ? Ipopt::TNLP::NON_LINEAR : Ipopt::TNLP::LINEAR;
265  return true;
266  }
267 
268  const Bonmin::TMINLP::SosInfo * BonminUserClass::sosConstraints() const {
269  return &solver_.sosConstraints(mem_);
270  }
271 
272 
273 
274 } // namespace casadi
'bonmin' plugin for Nlpsol
std::vector< bool > nl_g_
bool get_list_of_nonlinear_variables(int num_nonlin_vars, int *pos_nonlin_vars) const
void finalize_solution(BonminMemory *m, Bonmin::TMINLP::SolverReturn status, const double *x, double obj_value) const
const Bonmin::TMINLP::SosInfo & sosConstraints(BonminMemory *m) const
bool get_starting_point(BonminMemory *m, bool init_x, double *x, bool init_z, double *z_L, double *z_U, bool init_lambda, double *lambda) const
int get_number_of_nonlinear_variables() const
std::vector< bool > nl_ex_
void get_nlp_info(BonminMemory *m, int &nx, int &ng, int &nnz_jac_g, int &nnz_h_lag) const
bool intermediate_callback(BonminMemory *m, const double *x, const double *z_L, const double *z_U, const double *g, const double *lambda, double obj_value, int iter, double inf_pr, double inf_du, double mu, double d_norm, double regularization_size, double alpha_du, double alpha_pr, int ls_trials, bool full_callback) const
bool get_bounds_info(BonminMemory *m, double *x_l, double *x_u, double *g_l, double *g_u) const
virtual bool intermediate_callback(AlgorithmMode mode, Index iter, Number obj_value, Number inf_pr, Number inf_du, Number mu, Number d_norm, Number regularization_size, Number alpha_du, Number alpha_pr, Index ls_trials, const IpoptData *ip_data, IpoptCalculatedQuantities *ip_cq)
Definition: bonmin_nlp.cpp:210
bool get_variables_linearity(Index n, Ipopt::TNLP::LinearityType *var_types) override
Definition: bonmin_nlp.cpp:254
BonminUserClass(const BonminInterface &bonminInterface, BonminMemory *mem)
Definition: bonmin_nlp.cpp:32
bool get_nlp_info(Index &n, Index &m, Index &nnz_jac_g, Index &nnz_h_lag, TNLP::IndexStyleEnum &index_style) override
Definition: bonmin_nlp.cpp:42
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
Definition: bonmin_nlp.cpp:165
bool get_variables_types(Index n, VariableType *var_types) override
Definition: bonmin_nlp.cpp:242
bool get_bounds_info(Index n, Number *x_l, Number *x_u, Index m, Number *g_l, Number *g_u) override
Definition: bonmin_nlp.cpp:53
bool eval_grad_f(Index n, const Number *x, bool new_x, Number *grad_f) override
Definition: bonmin_nlp.cpp:89
virtual bool get_list_of_nonlinear_variables(Index num_nonlin_vars, Index *pos_nonlin_vars)
Definition: bonmin_nlp.cpp:237
bool eval_jac_g(Index n, const Number *x, bool new_x, Index m, Index nele_jac, Index *iRow, Index *jCol, Number *values) override
Definition: bonmin_nlp.cpp:126
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
Definition: bonmin_nlp.cpp:61
const SosInfo * sosConstraints() const override
Definition: bonmin_nlp.cpp:268
void finalize_solution(TMINLP::SolverReturn status, Index n, const Number *x, Number obj_value) override
Definition: bonmin_nlp.cpp:204
~BonminUserClass() override
Definition: bonmin_nlp.cpp:38
bool eval_g(Index n, const Number *x, bool new_x, Index m, Number *g) override
Definition: bonmin_nlp.cpp:108
bool get_constraints_linearity(Index m, Ipopt::TNLP::LinearityType *const_types) override
Definition: bonmin_nlp.cpp:261
virtual Index get_number_of_nonlinear_variables()
Definition: bonmin_nlp.cpp:233
bool eval_f(Index n, const Number *x, bool new_x, Number &obj_value) override
Definition: bonmin_nlp.cpp:71
const char * what() const override
Display error.
Definition: exception.hpp:90
casadi_int ng_
Number of constraints.
Definition: nlpsol_impl.hpp:69
casadi_int callback_step_
Execute the callback function only after this amount of iterations.
Definition: nlpsol_impl.hpp:78
std::vector< bool > discrete_
Options.
casadi_int nx_
Number of variables.
Definition: nlpsol_impl.hpp:66
int calc_function(OracleMemory *m, const std::string &fcn, const double *const *arg=nullptr, int thread_id=0) const
bool show_eval_warnings_
Show evaluation warnings.
casadi_int size2() const
Get the number of columns.
Definition: sparsity.cpp:128
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:164
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:168
The casadi namespace.
Definition: archiver.cpp:28
casadi_nlpsol_data< double > d_nlp
Definition: nlpsol_impl.hpp:42