Scippy

SCIP

Solving Constraint Integer Programs

nlpi_ipopt.cpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlpi_ipopt.cpp
17  * @ingroup NLPIS
18  * @brief Ipopt NLP interface
19  * @author Stefan Vigerske
20  *
21  * @todo warm starts
22  * @todo use new_x: Ipopt sets new_x = false if any function has been evaluated for the current x already, while oracle allows new_x to be false only if the current function has been evaluated for the current x before
23  *
24  * This file can only be compiled if Ipopt is available.
25  * Otherwise, to resolve public functions, use nlpi_ipopt_dummy.c.
26  * Since the dummy code is C instead of C++, it has been moved into a separate file.
27  */
28 
29 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
30 
31 #include "nlpi/nlpi_ipopt.h"
32 
33 #include "nlpi/nlpi.h"
34 #include "nlpi/nlpioracle.h"
35 #include "nlpi/exprinterpret.h"
36 #include "scip/interrupt.h"
37 #include "scip/pub_misc.h"
38 
39 #include <new> /* for std::bad_alloc */
40 #include <sstream>
41 
42 #ifdef __GNUC__
43 #pragma GCC diagnostic ignored "-Wshadow"
44 #endif
45 #include "IpoptConfig.h"
46 #include "IpIpoptApplication.hpp"
47 #include "IpIpoptCalculatedQuantities.hpp"
48 #include "IpSolveStatistics.hpp"
49 #include "IpJournalist.hpp"
50 #include "IpIpoptData.hpp"
51 #include "IpTNLPAdapter.hpp"
52 #include "IpOrigIpoptNLP.hpp"
53 #ifdef __GNUC__
54 #pragma GCC diagnostic warning "-Wshadow"
55 #endif
56 
57 using namespace Ipopt;
58 
59 #define NLPI_NAME "ipopt" /**< short concise name of solver */
60 #define NLPI_DESC "Ipopt interface" /**< description of solver */
61 #define NLPI_PRIORITY 0 /**< priority */
62 
63 #ifdef SCIP_DEBUG
64 #define DEFAULT_PRINTLEVEL J_WARNING /**< default print level of Ipopt */
65 #else
66 #define DEFAULT_PRINTLEVEL J_STRONGWARNING /**< default print level of Ipopt */
67 #endif
68 #define DEFAULT_MAXITER 3000 /**< default iteration limit for Ipopt */
69 
70 #define MAXPERTURB 0.01 /**< maximal perturbation of bounds in starting point heuristic */
71 #define FEASTOLFACTOR 0.05 /**< factor for user-given feasibility tolerance to get feasibility tolerance that is actually passed to Ipopt */
72 
73 /* Convergence check (see ScipNLP::intermediate_callback)
74  *
75  * If the fastfail option is enabled, then we stop Ipopt if the reduction in
76  * primal infeasibility is not sufficient for a consecutive number of iterations.
77  * With the parameters as given below, we require Ipopt to
78  * - not increase the primal infeasibility after 5 iterations
79  * - reduce the primal infeasibility by at least 50% within 10 iterations
80  * - reduce the primal infeasibility by at least 90% within 30 iterations
81  * The targets are updated once they are reached and the limit on allowed iterations to reach the new target is reset.
82  *
83  * In certain situations, it is allowed to exceed an iteration limit:
84  * - If we are in the first 10 (convcheck_startiter) iterations.
85  * - If we are within 10 (convcheck_startiter) iterations after the restoration phase ended.
86  * The reason for this is that during feasibility restoration phase Ipopt aims completely on
87  * reducing constraint violation, completely forgetting the objective function.
88  * When returning from feasibility restoration and considering the original objective again,
89  * it is unlikely that Ipopt will continue to decrease primal infeasibility, since it may now target on
90  * more on optimality again. Thus, we do not check convergence for a number of iterations.
91  * - If the target on dual infeasibility reduction has been achieved, we are below twice the iteration limit, and
92  * we are not in restoration mode.
93  * The reason for this is that if Ipopt makes good progress towards optimality,
94  * we want to allow some more iterations where primal infeasibility is not reduced.
95  * However, in restoration mode, dual infeasibility does not correspond to the original problem and
96  * the complete aim is to restore primal infeasibility.
97  */
98 static const int convcheck_nchecks = 3; /**< number of convergence checks */
99 static const int convcheck_startiter = 10; /**< iteration where to start convergence checking */
100 static const int convcheck_maxiter[convcheck_nchecks] = { 5, 15, 30 }; /**< maximal number of iterations to achieve each convergence check */
101 static const SCIP_Real convcheck_minred[convcheck_nchecks] = { 1.0, 0.5, 0.1 }; /**< minimal required infeasibility reduction in each convergence check */
102 
103 class ScipNLP;
104 
105 struct SCIP_NlpiData
106 {
107 public:
108  BMS_BLKMEM* blkmem; /**< block memory */
109  SCIP_MESSAGEHDLR* messagehdlr; /**< message handler */
110  SCIP_Real infinity; /**< initial value for infinity */
111  std::string defoptions; /**< modified default options for Ipopt */
112 
113  /** constructor */
114  SCIP_NlpiData(
115  BMS_BLKMEM* blkmem_ /**< block memory */
116  )
117  : blkmem(blkmem_),
118  messagehdlr(NULL),
119  infinity(SCIP_DEFAULT_INFINITY)
120  { }
121 };
122 
124 {
125 public:
126  SCIP_NLPIORACLE* oracle; /**< Oracle-helper to store and evaluate NLP */
127 
128  SmartPtr<IpoptApplication> ipopt; /**< Ipopt application */
129  SmartPtr<ScipNLP> nlp; /**< NLP in Ipopt form */
130  std::string optfile; /**< name of options file */
131  bool storeintermediate;/**< whether to store intermediate solutions */
132  bool fastfail; /**< whether to stop Ipopt if convergence seems slow */
133 
134  SCIP_Bool firstrun; /**< whether the next NLP solve will be the first one (with the current problem structure) */
135  SCIP_Real* initguess; /**< initial values for primal variables, or NULL if not known */
136 
137  SCIP_NLPSOLSTAT lastsolstat; /**< solution status from last run */
138  SCIP_NLPTERMSTAT lasttermstat; /**< termination status from last run */
139  SCIP_Real* lastsolprimals; /**< primal solution values from last run, if available */
140  SCIP_Real* lastsoldualcons; /**< dual solution values of constraints from last run, if available */
141  SCIP_Real* lastsoldualvarlb; /**< dual solution values of variable lower bounds from last run, if available */
142  SCIP_Real* lastsoldualvarub; /**< dual solution values of variable upper bounds from last run, if available */
143  SCIP_Real lastsolinfeas;/**< infeasibility (constraint violation) of solution stored in lastsolprimals */
144  int lastniter; /**< number of iterations in last run */
145  SCIP_Real lasttime; /**< time spend in last run */
146 
147  /** constructor */
149  : oracle(NULL),
150  storeintermediate(false), fastfail(false),
151  firstrun(TRUE), initguess(NULL),
152  lastsolstat(SCIP_NLPSOLSTAT_UNKNOWN), lasttermstat(SCIP_NLPTERMSTAT_OTHER),
153  lastsolprimals(NULL), lastsoldualcons(NULL), lastsoldualvarlb(NULL), lastsoldualvarub(NULL),
154  lastniter(-1), lasttime(-1.0)
155  { }
156 };
157 
158 /** TNLP implementation for SCIPs NLP */
159 class ScipNLP : public TNLP
160 {
161 private:
162  SCIP_NLPIPROBLEM* nlpiproblem; /**< NLPI problem data */
163 
164  SCIP_Real conv_prtarget[convcheck_nchecks]; /**< target primal infeasibility for each convergence check */
165  SCIP_Real conv_dutarget[convcheck_nchecks]; /**< target dual infeasibility for each convergence check */
166  int conv_iterlim[convcheck_nchecks]; /**< iteration number where target primal infeasibility should to be achieved */
167  int conv_lastrestoiter; /**< last iteration number in restoration mode, or -1 if none */
168 
169 public:
170  bool approxhessian; /**< do we tell Ipopt to approximate the hessian? (may also be false if user set to approx. hessian via option file) */
171 
172  /** constructor */
173  ScipNLP(
174  SCIP_NLPIPROBLEM* nlpiproblem_ = NULL /**< NLPI problem data */
175  )
176  : nlpiproblem(nlpiproblem_), approxhessian(false)
177  { }
178 
179  /** destructor */
180  ~ScipNLP() { }
181 
182  /** sets NLPI data structure */
183  void setNLPIPROBLEM(SCIP_NLPIPROBLEM* nlpiproblem_)
184  {
185  assert(nlpiproblem_ != NULL);
186  nlpiproblem = nlpiproblem_;
187  }
188 
189  /** Method to return some info about the nlp */
190  bool get_nlp_info(
191  Index& n, /**< place to store number of variables */
192  Index& m, /**< place to store number of constraints */
193  Index& nnz_jac_g, /**< place to store number of nonzeros in jacobian */
194  Index& nnz_h_lag, /**< place to store number of nonzeros in hessian */
195  IndexStyleEnum& index_style /**< place to store used index style (0-based or 1-based) */
196  );
197 
198  /** Method to return the bounds for my problem */
199  bool get_bounds_info(
200  Index n, /**< number of variables */
201  Number* x_l, /**< buffer to store lower bounds on variables */
202  Number* x_u, /**< buffer to store upper bounds on variables */
203  Index m, /**< number of constraints */
204  Number* g_l, /**< buffer to store lower bounds on constraints */
205  Number* g_u /**< buffer to store lower bounds on constraints */
206  );
207 
208  /** Method to return the starting point for the algorithm */
209  bool get_starting_point(
210  Index n, /**< number of variables */
211  bool init_x, /**< whether initial values for primal values are requested */
212  Number* x, /**< buffer to store initial primal values */
213  bool init_z, /**< whether initial values for dual values of variable bounds are requested */
214  Number* z_L, /**< buffer to store dual values for variable lower bounds */
215  Number* z_U, /**< buffer to store dual values for variable upper bounds */
216  Index m, /**< number of constraints */
217  bool init_lambda, /**< whether initial values for dual values of constraints are required */
218  Number* lambda /**< buffer to store dual values of constraints */
219  );
220 
221  /** Method to return the variables linearity. */
222  bool get_variables_linearity(
223  Index n, /**< number of variables */
224  LinearityType* var_types /**< buffer to store linearity types of variables */
225  );
226 
227  /** Method to return the constraint linearity. */
228  bool get_constraints_linearity(
229  Index m, /**< number of constraints */
230  LinearityType* const_types /**< buffer to store linearity types of constraints */
231  );
232 
233  /** Method to return the number of nonlinear variables. */
234  Index get_number_of_nonlinear_variables();
235 
236  /** Method to return the indices of the nonlinear variables */
237  bool get_list_of_nonlinear_variables(
238  Index num_nonlin_vars, /**< number of nonlinear variables */
239  Index* pos_nonlin_vars /**< array to fill with indices of nonlinear variables */
240  );
241 
242  /** Method to return metadata about variables and constraints */
243  bool get_var_con_metadata(
244  Index n, /**< number of variables */
245  StringMetaDataMapType& var_string_md, /**< variable meta data of string type */
246  IntegerMetaDataMapType& var_integer_md,/**< variable meta data of integer type */
247  NumericMetaDataMapType& var_numeric_md,/**< variable meta data of numeric type */
248  Index m, /**< number of constraints */
249  StringMetaDataMapType& con_string_md, /**< constraint meta data of string type */
250  IntegerMetaDataMapType& con_integer_md,/**< constraint meta data of integer type */
251  NumericMetaDataMapType& con_numeric_md /**< constraint meta data of numeric type */
252  );
253 
254  /** Method to return the objective value */
255  bool eval_f(
256  Index n, /**< number of variables */
257  const Number* x, /**< point to evaluate */
258  bool new_x, /**< whether some function evaluation method has been called for this point before */
259  Number& obj_value /**< place to store objective function value */
260  );
261 
262  /** Method to return the gradient of the objective */
263  bool eval_grad_f(
264  Index n, /**< number of variables */
265  const Number* x, /**< point to evaluate */
266  bool new_x, /**< whether some function evaluation method has been called for this point before */
267  Number* grad_f /**< buffer to store objective gradient */
268  );
269 
270  /** Method to return the constraint residuals */
271  bool eval_g(
272  Index n, /**< number of variables */
273  const Number* x, /**< point to evaluate */
274  bool new_x, /**< whether some function evaluation method has been called for this point before */
275  Index m, /**< number of constraints */
276  Number* g /**< buffer to store constraint function values */
277  );
278 
279  /** Method to return:
280  * 1) The structure of the jacobian (if "values" is NULL)
281  * 2) The values of the jacobian (if "values" is not NULL)
282  */
283  bool eval_jac_g(
284  Index n, /**< number of variables */
285  const Number* x, /**< point to evaluate */
286  bool new_x, /**< whether some function evaluation method has been called for this point before */
287  Index m, /**< number of constraints */
288  Index nele_jac, /**< number of nonzero entries in jacobian */
289  Index* iRow, /**< buffer to store row indices of nonzero jacobian entries, or NULL if values
290  * are requested */
291  Index* jCol, /**< buffer to store column indices of nonzero jacobian entries, or NULL if values
292  * are requested */
293  Number* values /**< buffer to store values of nonzero jacobian entries, or NULL if structure is
294  * requested */
295  );
296 
297  /** Method to return:
298  * 1) The structure of the hessian of the lagrangian (if "values" is NULL)
299  * 2) The values of the hessian of the lagrangian (if "values" is not NULL)
300  */
301  bool eval_h(
302  Index n, /**< number of variables */
303  const Number* x, /**< point to evaluate */
304  bool new_x, /**< whether some function evaluation method has been called for this point before */
305  Number obj_factor, /**< weight for objective function */
306  Index m, /**< number of constraints */
307  const Number* lambda, /**< weights for constraint functions */
308  bool new_lambda, /**< whether the hessian has been evaluated for these values of lambda before */
309  Index nele_hess, /**< number of nonzero entries in hessian */
310  Index* iRow, /**< buffer to store row indices of nonzero hessian entries, or NULL if values
311  * are requested */
312  Index* jCol, /**< buffer to store column indices of nonzero hessian entries, or NULL if values
313  * are requested */
314  Number* values /**< buffer to store values of nonzero hessian entries, or NULL if structure is requested */
315  );
316 
317  /** Method called by the solver at each iteration.
318  *
319  * Checks whether Ctrl-C was hit.
320  */
321  bool intermediate_callback(
322  AlgorithmMode mode, /**< current mode of algorithm */
323  Index iter, /**< current iteration number */
324  Number obj_value, /**< current objective value */
325  Number inf_pr, /**< current primal infeasibility */
326  Number inf_du, /**< current dual infeasibility */
327  Number mu, /**< current barrier parameter */
328  Number d_norm, /**< current gradient norm */
329  Number regularization_size,/**< current size of regularization */
330  Number alpha_du, /**< current dual alpha */
331  Number alpha_pr, /**< current primal alpha */
332  Index ls_trials, /**< current number of linesearch trials */
333  const IpoptData* ip_data, /**< pointer to Ipopt Data */
334  IpoptCalculatedQuantities* ip_cq /**< pointer to current calculated quantities */
335  );
336 
337  /** This method is called when the algorithm is complete so the TNLP can store/write the solution. */
338  void finalize_solution(
339  SolverReturn status, /**< solve and solution status */
340  Index n, /**< number of variables */
341  const Number* x, /**< primal solution values */
342  const Number* z_L, /**< dual values of variable lower bounds */
343  const Number* z_U, /**< dual values of variable upper bounds */
344  Index m, /**< number of constraints */
345  const Number* g, /**< values of constraints */
346  const Number* lambda, /**< dual values of constraints */
347  Number obj_value, /**< objective function value */
348  const IpoptData* data, /**< pointer to Ipopt Data */
349  IpoptCalculatedQuantities* cq /**< pointer to calculated quantities */
350  );
351 };
352 
353 /** A particular Ipopt::Journal implementation that uses the SCIP message routines for output.
354  */
355 class ScipJournal : public Ipopt::Journal {
356 private:
357  /** reference to message handler pointer in NLPI data */
358  SCIP_MESSAGEHDLR*& messagehdlr;
359 
360 public:
361  ScipJournal(
362  const char* name, /**< name of journal */
363  Ipopt::EJournalLevel default_level, /**< default verbosity level */
364  SCIP_MESSAGEHDLR*& messagehdlr_ /**< pointer where to get message handler from */
365  )
366  : Ipopt::Journal(name, default_level),
367  messagehdlr(messagehdlr_)
368  { }
369 
370  ~ScipJournal() { }
371 
372 protected:
373  void PrintImpl(
374  Ipopt::EJournalCategory category, /**< category of message */
375  Ipopt::EJournalLevel level, /**< verbosity level of message */
376  const char* str /**< message to print */
377  )
378  {
379  if( level == J_ERROR )
380  {
382  }
383  else
384  {
385  SCIPmessagePrintInfo(messagehdlr, str);
386  }
387  }
388 
389  void PrintfImpl(
390  Ipopt::EJournalCategory category, /**< category of message */
391  Ipopt::EJournalLevel level, /**< verbosity level of message */
392  const char* pformat, /**< message printing format */
393  va_list ap /**< arguments of message */
394  )
395  {
396  if( level == J_ERROR )
397  {
398  SCIPmessageVPrintError(pformat, ap);
399  }
400  else
401  {
402  SCIPmessageVPrintInfo(messagehdlr, pformat, ap);
403  }
404  }
405 
406  void FlushBufferImpl() { }
407 };
408 
409 /** clears the last solution arrays and sets the solstat and termstat to unknown and other, resp. */
410 static
412  SCIP_NLPIPROBLEM* problem /**< data structure of problem */
413  )
414 {
415  assert(problem != NULL);
416 
423  problem->lastsolinfeas = SCIP_INVALID;
424 }
425 
426 /** sets feasibility tolerance parameters in Ipopt
427  *
428  * Sets tol and constr_viol_tol to FEASTOLFACTOR*feastol and acceptable_tol and acceptable_viol_tol to feastol.
429  * Since the users and Ipopts conception of feasibility may differ, we let Ipopt try to compute solutions
430  * that are more accurate (w.r.t. constraint violation) than requested by the user.
431  * Only if Ipopt has problems to achieve this accuracy, we also accept solutions that are accurate w.r.t. feastol only.
432  * The additional effort for computing a more accurate solution should be small if one can assume fast convergence when close to a local minimizer.
433  */
434 static
436  SCIP_NLPIPROBLEM* nlpiproblem,
437  SCIP_Real feastol
438  )
439 {
440  nlpiproblem->ipopt->Options()->SetNumericValue("tol", FEASTOLFACTOR * feastol);
441  nlpiproblem->ipopt->Options()->SetNumericValue("constr_viol_tol", FEASTOLFACTOR * feastol);
442 
443  nlpiproblem->ipopt->Options()->SetNumericValue("acceptable_tol", feastol);
444  nlpiproblem->ipopt->Options()->SetNumericValue("acceptable_constr_viol_tol", feastol);
445 
446  /* It seem to be better to let Ipopt relax bounds a bit to ensure that a relative interior exists.
447  * However, if we relax the bounds too much, then the solutions tend to be slightly infeasible.
448  * If the user wants to set a tight feasibility tolerance, then (s)he has probably difficulties to compute accurate enough solutions.
449  * Thus, we turn off the bound_relax_factor completely if it would be below its default value of 1e-8.
450  */
451  nlpiproblem->ipopt->Options()->SetNumericValue("bound_relax_factor", feastol < 1e-8/FEASTOLFACTOR ? 0.0 : FEASTOLFACTOR * feastol);
452 }
453 
454 /** copy method of NLP interface (called when SCIP copies plugins)
455  *
456  * input:
457  * - blkmem block memory of target SCIP
458  * - sourcenlpi the NLP interface to copy
459  * - targetnlpi buffer to store pointer to copy of NLP interface
460  */
461 static
462 SCIP_DECL_NLPICOPY(nlpiCopyIpopt)
463 {
464  SCIP_NLPIDATA* sourcedata;
465  SCIP_NLPIDATA* targetdata;
466 
467  assert(sourcenlpi != NULL);
468  assert(targetnlpi != NULL);
469 
470  sourcedata = SCIPnlpiGetData(sourcenlpi);
471  assert(sourcedata != NULL);
472 
473  SCIP_CALL( SCIPcreateNlpSolverIpopt(blkmem, targetnlpi) );
474  assert(*targetnlpi != NULL);
475 
476  SCIP_CALL( SCIPnlpiSetRealPar(*targetnlpi, NULL, SCIP_NLPPAR_INFINITY, sourcedata->infinity) );
477  SCIP_CALL( SCIPnlpiSetMessageHdlr(*targetnlpi, sourcedata->messagehdlr) );
478 
479  targetdata = SCIPnlpiGetData(*targetnlpi);
480  assert(targetdata != NULL);
481 
482  targetdata->defoptions = sourcedata->defoptions;
483 
484  return SCIP_OKAY;
485 }
486 
487 /** destructor of NLP interface to free nlpi data
488  *
489  * input:
490  * - nlpi datastructure for solver interface
491  */
492 static
493 SCIP_DECL_NLPIFREE(nlpiFreeIpopt)
494 {
495  SCIP_NLPIDATA* data;
496 
497  assert(nlpi != NULL);
498 
499  data = SCIPnlpiGetData(nlpi);
500  assert(data != NULL);
501 
502  delete data;
503 
504  return SCIP_OKAY;
505 }
506 
507 /** gets pointer for NLP solver
508  *
509  * to do dirty stuff
510  *
511  * input:
512  * - nlpi datastructure for solver interface
513  *
514  * return: void pointer to solver
515  */
516 static
517 SCIP_DECL_NLPIGETSOLVERPOINTER(nlpiGetSolverPointerIpopt)
518 {
519  assert(nlpi != NULL);
520 
521  return NULL;
522 }
523 
524 /** creates a problem instance
525  *
526  * input:
527  * - nlpi datastructure for solver interface
528  * - problem pointer to store the problem data
529  * - name name of problem, can be NULL
530  */
531 static
532 SCIP_DECL_NLPICREATEPROBLEM(nlpiCreateProblemIpopt)
533 {
534  SCIP_NLPIDATA* data;
535 
536  assert(nlpi != NULL);
537  assert(problem != NULL);
538 
539  data = SCIPnlpiGetData(nlpi);
540  assert(data != NULL);
541 
542  *problem = new SCIP_NLPIPROBLEM;
543  if( *problem == NULL )
544  return SCIP_NOMEMORY;
545 
546  SCIP_CALL( SCIPnlpiOracleCreate(data->blkmem, &(*problem)->oracle) );
547  SCIP_CALL( SCIPnlpiOracleSetInfinity((*problem)->oracle, data->infinity) );
548  SCIP_CALL( SCIPnlpiOracleSetProblemName((*problem)->oracle, name) );
549 
550  try
551  {
552  /* initialize IPOPT without default journal */
553  (*problem)->ipopt = new IpoptApplication(false);
554  if( IsNull((*problem)->ipopt) )
555  throw std::bad_alloc();
556 
557  /* plugin our journal to get output through SCIP message handler */
558  SmartPtr<Journal> jrnl = new ScipJournal("console", J_ITERSUMMARY, data->messagehdlr);
559  if( IsNull(jrnl) )
560  throw std::bad_alloc();
561  jrnl->SetPrintLevel(J_DBG, J_NONE);
562  if( !(*problem)->ipopt->Jnlst()->AddJournal(jrnl) )
563  {
564  SCIPerrorMessage("Failed to register ScipJournal for IPOPT output.");
565  }
566 
567  /* initialize Ipopt/SCIP NLP interface */
568  (*problem)->nlp = new ScipNLP(*problem);
569  if( IsNull((*problem)->nlp) )
570  throw std::bad_alloc();
571  }
572  catch( std::bad_alloc )
573  {
574  SCIPerrorMessage("Not enough memory to initialize Ipopt.\n");
575  return SCIP_NOMEMORY;
576  }
577 
578  /* modify Ipopt's default settings to what we believe is appropriate */
579  (*problem)->ipopt->RegOptions()->AddStringOption2("store_intermediate", "whether to store the most feasible intermediate solutions", "no", "yes", "", "no", "", "useful when Ipopt looses a once found feasible solution and then terminates with an infeasible point");
580  (*problem)->ipopt->Options()->SetIntegerValue("print_level", DEFAULT_PRINTLEVEL);
581  /* (*problem)->ipopt->Options()->SetStringValue("print_timing_statistics", "yes"); */
582  (*problem)->ipopt->Options()->SetStringValue("mu_strategy", "adaptive");
583  (*problem)->ipopt->Options()->SetStringValue("expect_infeasible_problem", "yes");
584  (*problem)->ipopt->Options()->SetIntegerValue("max_iter", DEFAULT_MAXITER);
585  (*problem)->ipopt->Options()->SetNumericValue("nlp_lower_bound_inf", -data->infinity, false);
586  (*problem)->ipopt->Options()->SetNumericValue("nlp_upper_bound_inf", data->infinity, false);
587  (*problem)->ipopt->Options()->SetNumericValue("diverging_iterates_tol", data->infinity, false);
588  /* (*problem)->ipopt->Options()->SetStringValue("dependency_detector", "ma28"); */
589  /* if the expression interpreter does not give hessians, tell Ipopt to approximate hessian */
590 #ifdef SCIP_DEBUG
591  (*problem)->ipopt->Options()->SetStringValue("derivative_test", "second-order");
592 #endif
593  setFeastol(*problem, SCIP_DEFAULT_FEASTOL);
594 
595  /* apply user's given modifications to Ipopt's default settings */
596  if( data->defoptions.length() > 0 )
597  {
598  std::istringstream is(data->defoptions);
599 
600  if( !(*problem)->ipopt->Options()->ReadFromStream(*(*problem)->ipopt->Jnlst(), is) )
601  {
602  SCIPerrorMessage("Error when modifiying Ipopt options using options string\n%s\n", data->defoptions.c_str());
603  return SCIP_ERROR;
604  }
605  }
606 
607  /* apply user's given options file (this one is NLPI problem specific) */
608  if( (*problem)->ipopt->Initialize((*problem)->optfile) != Solve_Succeeded )
609  {
610  SCIPerrorMessage("Error during initialization of Ipopt using optionfile \"%s\"\n", (*problem)->optfile.c_str());
611  return SCIP_ERROR;
612  }
613 
614 
615  return SCIP_OKAY;
616 }
617 
618 /** free a problem instance
619  *
620  * input:
621  * - nlpi datastructure for solver interface
622  * - problem pointer where problem data is stored
623  */
624 static
625 SCIP_DECL_NLPIFREEPROBLEM(nlpiFreeProblemIpopt)
626 {
627  assert(nlpi != NULL);
628  assert(problem != NULL);
629  assert(*problem != NULL);
630 
631  if( (*problem)->oracle != NULL )
632  {
633  SCIP_CALL( SCIPnlpiOracleFree(&(*problem)->oracle) );
634  }
635 
636  BMSfreeMemoryArrayNull(&(*problem)->initguess);
637  BMSfreeMemoryArrayNull(&(*problem)->lastsolprimals);
638  BMSfreeMemoryArrayNull(&(*problem)->lastsoldualcons);
639  BMSfreeMemoryArrayNull(&(*problem)->lastsoldualvarlb);
640  BMSfreeMemoryArrayNull(&(*problem)->lastsoldualvarub);
641 
642  delete *problem;
643  *problem = NULL;
644 
645  return SCIP_OKAY;
646 }
647 
648 /** gets pointer to solver-internal problem instance
649  *
650  * to do dirty stuff
651  *
652  * input:
653  * - nlpi datastructure for solver interface
654  * - problem datastructure for problem instance
655  *
656  * return: void pointer to problem instance
657  */
658 SCIP_DECL_NLPIGETPROBLEMPOINTER(nlpiGetProblemPointerIpopt)
659 {
660  assert(nlpi != NULL);
661  assert(problem != NULL);
662 
663  return GetRawPtr(problem->nlp);
664 }
665 
666 /** add variables
667  *
668  * input:
669  * - nlpi datastructure for solver interface
670  * - problem datastructure for problem instance
671  * - nvars number of variables
672  * - lbs lower bounds of variables, can be NULL if -infinity
673  * - ubs upper bounds of variables, can be NULL if +infinity
674  * - varnames names of variables, can be NULL
675  */
676 static
677 SCIP_DECL_NLPIADDVARS(nlpiAddVarsIpopt)
678 {
679  assert(nlpi != NULL);
680  assert(problem != NULL);
681  assert(problem->oracle != NULL);
682 
683  SCIP_CALL( SCIPnlpiOracleAddVars(problem->oracle, nvars, lbs, ubs, varnames) );
684 
685  problem->firstrun = TRUE;
686  BMSfreeMemoryArrayNull(&problem->initguess);
687  invalidateSolution(problem);
688 
689  return SCIP_OKAY;
690 }
691 
692 /** add constraints
693  * quadratic coefficiens: row oriented matrix for each constraint
694  *
695  * input:
696  * - nlpi datastructure for solver interface
697  * - problem datastructure for problem instance
698  * - ncons number of added constraints
699  * - lhss left hand sides of constraints
700  * - rhss right hand sides of constraints
701  * - linoffsets start index of each constraints linear coefficients in lininds and linvals
702  * length: ncons + 1, linoffsets[ncons] gives length of lininds and linvals
703  * may be NULL in case of no linear part
704  * - lininds variable indices
705  * may be NULL in case of no linear part
706  * - linvals coefficient values
707  * may be NULL in case of no linear part
708  * - nquadelems number of quadratic elements for each constraint
709  * may be NULL in case of no quadratic part
710  * - quadelems quadratic elements for each constraint
711  * may be NULL in case of no quadratic part
712  * - exprvaridxs indices of variables in expression tree, maps variable indices in expression tree to indices in nlp
713  * entry of array may be NULL in case of no expression tree
714  * may be NULL in case of no expression tree in any constraint
715  * - exprtrees expression tree for nonquadratic part of constraints
716  * entry of array may be NULL in case of no nonquadratic part
717  * may be NULL in case of no nonquadratic part in any constraint
718  * - names of constraints, may be NULL or entries may be NULL
719  */
720 static
721 SCIP_DECL_NLPIADDCONSTRAINTS(nlpiAddConstraintsIpopt)
722 {
723  assert(nlpi != NULL);
724  assert(problem != NULL);
725  assert(problem->oracle != NULL);
726 
727  SCIP_CALL( SCIPnlpiOracleAddConstraints(problem->oracle,
728  ncons, lhss, rhss,
729  nlininds, lininds, linvals,
730  nquadelems, quadelems,
731  exprvaridxs, exprtrees, names) );
732 
733  problem->firstrun = TRUE;
734  invalidateSolution(problem);
735 
736  return SCIP_OKAY;
737 }
738 
739 /** sets or overwrites objective, a minimization problem is expected
740  * May change sparsity pattern.
741  *
742  * input:
743  * - nlpi datastructure for solver interface
744  * - problem datastructure for problem instance
745  * - nlins number of linear variables
746  * - lininds variable indices
747  * may be NULL in case of no linear part
748  * - linvals coefficient values
749  * may be NULL in case of no linear part
750  * - nquadelems number of elements in matrix of quadratic part
751  * - quadelems elements of quadratic part
752  * may be NULL in case of no quadratic part
753  * - exprvaridxs indices of variables in expression tree, maps variable indices in expression tree to indices in nlp
754  * may be NULL in case of no expression tree
755  * - exprtree expression tree for nonquadratic part of objective function
756  * may be NULL in case of no nonquadratic part
757  * - constant objective value offset
758  */
759 static
760 SCIP_DECL_NLPISETOBJECTIVE(nlpiSetObjectiveIpopt)
761 {
762  assert(nlpi != NULL);
763  assert(problem != NULL);
764  assert(problem->oracle != NULL);
765 
766  SCIP_CALL( SCIPnlpiOracleSetObjective(problem->oracle,
767  constant, nlins, lininds, linvals,
768  nquadelems, quadelems,
769  exprvaridxs, exprtree) );
770 
771  problem->firstrun = TRUE;
772  invalidateSolution(problem);
773 
774  return SCIP_OKAY;
775 }
776 
777 /** change variable bounds
778  *
779  * input:
780  * - nlpi datastructure for solver interface
781  * - problem datastructure for problem instance
782  * - nvars number of variables to change bounds
783  * - indices indices of variables to change bounds
784  * - lbs new lower bounds
785  * - ubs new upper bounds
786  */
787 static
788 SCIP_DECL_NLPICHGVARBOUNDS(nlpiChgVarBoundsIpopt)
789 {
790  assert(nlpi != NULL);
791  assert(problem != NULL);
792  assert(problem->oracle != NULL);
793 
794  SCIP_CALL( SCIPnlpiOracleChgVarBounds(problem->oracle, nvars, indices, lbs, ubs) );
795 
796  invalidateSolution(problem);
797 
798  return SCIP_OKAY;
799 }
800 
801 /** change constraint bounds
802  *
803  * input:
804  * - nlpi datastructure for solver interface
805  * - problem datastructure for problem instance
806  * - nconss number of constraints to change sides
807  * - indices indices of constraints to change sides
808  * - lhss new left hand sides
809  * - rhss new right hand sides
810  */
811 static
812 SCIP_DECL_NLPICHGCONSSIDES(nlpiChgConsSidesIpopt)
813 {
814  assert(nlpi != NULL);
815  assert(problem != NULL);
816  assert(problem->oracle != NULL);
817 
818  SCIP_CALL( SCIPnlpiOracleChgConsSides(problem->oracle, nconss, indices, lhss, rhss) );
819 
820  invalidateSolution(problem);
821 
822  return SCIP_OKAY;
823 }
824 
825 /** delete a set of variables
826  *
827  * input:
828  * - nlpi datastructure for solver interface
829  * - problem datastructure for problem instance
830  * - nlpi datastructure for solver interface
831  * - dstats deletion status of vars; 1 if var should be deleted, 0 if not
832  *
833  * output:
834  * - dstats new position of var, -1 if var was deleted
835  */
836 static
837 SCIP_DECL_NLPIDELVARSET(nlpiDelVarSetIpopt)
838 {
839  assert(nlpi != NULL);
840  assert(problem != NULL);
841  assert(problem->oracle != NULL);
842 
843  SCIP_CALL( SCIPnlpiOracleDelVarSet(problem->oracle, dstats) );
844 
845  problem->firstrun = TRUE;
846  BMSfreeMemoryArrayNull(&problem->initguess); // @TODO keep initguess for remaining variables
847 
848  invalidateSolution(problem);
849 
850  return SCIP_OKAY;
851 }
852 
853 /** delete a set of constraints
854  *
855  * input:
856  * - nlpi datastructure for solver interface
857  * - problem datastructure for problem instance
858  * - dstats deletion status of rows; 1 if row should be deleted, 0 if not
859  *
860  * output:
861  * - dstats new position of row, -1 if row was deleted
862  */
863 static
864 SCIP_DECL_NLPIDELCONSSET(nlpiDelConstraintSetIpopt)
865 {
866  assert(nlpi != NULL);
867  assert(problem != NULL);
868  assert(problem->oracle != NULL);
869 
870  SCIP_CALL( SCIPnlpiOracleDelConsSet(problem->oracle, dstats) );
871 
872  problem->firstrun = TRUE;
873 
874  invalidateSolution(problem);
875 
876  return SCIP_OKAY;
877 }
878 
879 /** change one linear coefficient in a constraint or objective
880  *
881  * input:
882  * - nlpi datastructure for solver interface
883  * - problem datastructure for problem instance
884  * - idx index of constraint or -1 for objective
885  * - nvals number of values in linear constraint
886  * - varidxs indices of variable
887  * - vals new values for coefficient
888  *
889  * return: Error if coefficient did not exist before
890  */
891 static
892 SCIP_DECL_NLPICHGLINEARCOEFS(nlpiChgLinearCoefsIpopt)
893 {
894  assert(nlpi != NULL);
895  assert(problem != NULL);
896  assert(problem->oracle != NULL);
897 
898  SCIP_CALL( SCIPnlpiOracleChgLinearCoefs(problem->oracle, idx, nvals, varidxs, vals) );
899  invalidateSolution(problem);
900 
901  return SCIP_OKAY;
902 }
903 
904 /** change one coefficient in the quadratic part of a constraint or objective
905  *
906  * input:
907  * - nlpi datastructure for solver interface
908  * - problem datastructure for problem instance
909  * - idx index of constraint or -1 for objective
910  * - nquadelems number of entries in quadratic matrix to change
911  * - quadelems new elements in quadratic matrix (replacing already existing ones or adding new ones)
912  *
913  * return: Error if coefficient did not exist before
914  */
915 static
916 SCIP_DECL_NLPICHGQUADCOEFS(nlpiChgQuadraticCoefsIpopt)
917 {
918  assert(nlpi != NULL);
919  assert(problem != NULL);
920  assert(problem->oracle != NULL);
921 
922  SCIP_CALL( SCIPnlpiOracleChgQuadCoefs(problem->oracle, idx, nquadelems, quadelems) );
923  invalidateSolution(problem);
924 
925  return SCIP_OKAY;
926 }
927 
928 /** replaces the expression tree of a constraint or objective
929  *
930  * input:
931  * - nlpi datastructure for solver interface
932  * - problem datastructure for problem instance
933  * - idxcons index of constraint or -1 for objective
934  * - exprtree new expression tree for constraint or objective, or NULL to only remove previous tree
935  */
936 static
937 SCIP_DECL_NLPICHGEXPRTREE(nlpiChgExprtreeIpopt)
938 {
939  assert(nlpi != NULL);
940  assert(problem != NULL);
941  assert(problem->oracle != NULL);
942 
943  SCIP_CALL( SCIPnlpiOracleChgExprtree(problem->oracle, idxcons, exprvaridxs, exprtree) );
944  invalidateSolution(problem);
945 
946  return SCIP_OKAY;
947 }
948 
949 /** change the value of one parameter in the nonlinear part
950  *
951  * input:
952  * - nlpi datastructure for solver interface
953  * - problem datastructure for problem instance
954  * - idxcons index of constraint or -1 for objective
955  * - idxparam index of parameter
956  * - value new value for nonlinear parameter
957  *
958  * return: Error if parameter does not exist
959  */
960 static
961 SCIP_DECL_NLPICHGNONLINCOEF(nlpiChgNonlinCoefIpopt)
962 {
963  assert(nlpi != NULL);
964  assert(problem != NULL);
965  assert(problem->oracle != NULL);
966 
967  SCIP_CALL( SCIPnlpiOracleChgExprParam(problem->oracle, idxcons, idxparam, value) );
968  invalidateSolution(problem);
969 
970  return SCIP_OKAY;
971 }
972 
973 /** change the constant offset in the objective
974  *
975  * input:
976  * - nlpi datastructure for solver interface
977  * - problem datastructure for problem instance
978  * - objconstant new value for objective constant
979  */
980 static
981 SCIP_DECL_NLPICHGOBJCONSTANT( nlpiChgObjConstantIpopt )
982 {
983  assert(nlpi != NULL);
984  assert(problem != NULL);
985  assert(problem->oracle != NULL);
986 
987  SCIP_CALL( SCIPnlpiOracleChgObjConstant(problem->oracle, objconstant) );
988 
989  return SCIP_OKAY;
990 }
991 
992 /** sets initial guess for primal variables
993  *
994  * input:
995  * - nlpi datastructure for solver interface
996  * - problem datastructure for problem instance
997  * - primalvalues initial primal values for variables, or NULL to clear previous values
998  * - consdualvalues initial dual values for constraints, or NULL to clear previous values
999  * - varlbdualvalues initial dual values for variable lower bounds, or NULL to clear previous values
1000  * - varubdualvalues initial dual values for variable upper bounds, or NULL to clear previous values
1001  */
1002 static
1003 SCIP_DECL_NLPISETINITIALGUESS(nlpiSetInitialGuessIpopt)
1004 {
1005  assert(nlpi != NULL);
1006  assert(problem != NULL);
1007  assert(problem->oracle != NULL);
1008 
1009  if( primalvalues != NULL )
1010  {
1011  if( !problem->initguess )
1012  {
1013  if( BMSduplicateMemoryArray(&problem->initguess, primalvalues, SCIPnlpiOracleGetNVars(problem->oracle)) == NULL )
1014  return SCIP_NOMEMORY;
1015  }
1016  else
1017  {
1018  BMScopyMemoryArray(problem->initguess, primalvalues, SCIPnlpiOracleGetNVars(problem->oracle));
1019  }
1020  }
1021  else
1022  {
1023  BMSfreeMemoryArrayNull(&problem->initguess);
1024  }
1025 
1026  return SCIP_OKAY;
1027 }
1028 
1029 /** tries to solve NLP
1030  *
1031  * input:
1032  * - nlpi datastructure for solver interface
1033  * - problem datastructure for problem instance
1034  */
1035 static
1036 SCIP_DECL_NLPISOLVE(nlpiSolveIpopt)
1037 {
1038  ApplicationReturnStatus status;
1039 
1040  assert(nlpi != NULL);
1041  assert(problem != NULL);
1042  assert(problem->oracle != NULL);
1043 
1044  assert(IsValid(problem->ipopt));
1045  assert(IsValid(problem->nlp));
1046 
1047  problem->nlp->setNLPIPROBLEM(problem);
1048 
1049  problem->lastniter = -1;
1050  problem->lasttime = -1.0;
1051  problem->lastsolinfeas = SCIP_INVALID;
1052 
1053  try
1054  {
1055  SmartPtr<SolveStatistics> stats;
1056 
1057  if( problem->firstrun )
1058  {
1059  /* if the expression interpreter does not support function values and gradients and hessians, and the problem is not at most quadratic,
1060  * change NLP parameters or give an error
1061  */
1063  && SCIPnlpiOracleGetMaxDegree(problem->oracle) > 2 )
1064  {
1065  /* @todo could enable jacobian approximation in Ipopt */
1068  {
1069  SCIPerrorMessage("Do not have expression interpreter that can compute function values and gradients. Cannot solve NLP with Ipopt.\n");
1070  problem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
1071  problem->lasttermstat = SCIP_NLPTERMSTAT_OTHER;
1072  return SCIP_OKAY;
1073  }
1074 
1075  /* enable hessian approximation if we are nonquadratic and the expression interpreter does not support hessians */
1077  {
1078  problem->ipopt->Options()->SetStringValue("hessian_approximation", "limited-memory");
1079  problem->nlp->approxhessian = true;
1080  }
1081  else
1082  problem->nlp->approxhessian = false;
1083  }
1084 
1085  status = problem->ipopt->OptimizeTNLP(GetRawPtr(problem->nlp));
1086  }
1087  else
1088  {
1089  /* ReOptimizeNLP with Ipopt <= 3.10.3 could return a solution not within bounds if all variables are fixed (see Ipopt ticket #179) */
1090 #if (IPOPT_VERSION_MAJOR > 3) || (IPOPT_VERSION_MAJOR == 3 && IPOPT_VERSION_MINOR > 10) || (IPOPT_VERSION_MAJOR == 3 && IPOPT_VERSION_MINOR == 10 && IPOPT_VERSION_RELEASE > 3)
1091  status = problem->ipopt->ReOptimizeTNLP(GetRawPtr(problem->nlp));
1092 #else
1093  status = problem->ipopt->OptimizeTNLP(GetRawPtr(problem->nlp));
1094 #endif
1095  }
1096 
1097  // catch the very bad status codes
1098  switch( status ) {
1099  case Invalid_Problem_Definition:
1100  case Invalid_Option:
1101  case Unrecoverable_Exception:
1102  case NonIpopt_Exception_Thrown:
1103  case Internal_Error:
1104  SCIPerrorMessage("Ipopt returned with application return status %d\n", status);
1105  return SCIP_ERROR;
1106  case Insufficient_Memory:
1107  SCIPerrorMessage("Ipopt returned with status \"Insufficient Memory\"\n");
1108  return SCIP_NOMEMORY;
1109  case Invalid_Number_Detected:
1110  SCIPdebugMessage("Ipopt failed because of an invalid number in function or derivative value\n");
1111  invalidateSolution(problem);
1112  problem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
1113  problem->lasttermstat = SCIP_NLPTERMSTAT_EVALERR;
1114  default: ;
1115  }
1116 
1117  stats = problem->ipopt->Statistics();
1118  if( IsValid(stats) )
1119  {
1120  problem->lastniter = stats->IterationCount();
1121  problem->lasttime = stats->TotalCPUTime();
1122  }
1123  }
1124  catch( IpoptException except )
1125  {
1126  SCIPerrorMessage("Ipopt returned with exception: %s\n", except.Message().c_str());
1127  return SCIP_ERROR;
1128  }
1129 
1130  problem->firstrun = FALSE;
1131 
1132  return SCIP_OKAY;
1133 }
1134 
1135 /** gives solution status
1136  *
1137  * input:
1138  * - nlpi datastructure for solver interface
1139  * - problem datastructure for problem instance
1140  *
1141  * return: Solution Status
1142  */
1143 static
1144 SCIP_DECL_NLPIGETSOLSTAT(nlpiGetSolstatIpopt)
1145 {
1146  assert(nlpi != NULL);
1147  assert(problem != NULL);
1148 
1149  return problem->lastsolstat;
1150 }
1151 
1152 /** gives termination reason
1153  *
1154  * input:
1155  * - nlpi datastructure for solver interface
1156  * - problem datastructure for problem instance
1157  *
1158  * return: Termination Status
1159  */
1160 static
1161 SCIP_DECL_NLPIGETTERMSTAT(nlpiGetTermstatIpopt)
1162 {
1163  assert(nlpi != NULL);
1164  assert(problem != NULL);
1165 
1166  return problem->lasttermstat;
1167 }
1168 
1169 /** gives primal and dual solution values
1170  *
1171  * input:
1172  * - nlpi datastructure for solver interface
1173  * - problem datastructure for problem instance
1174  * - primalvalues buffer to store pointer to array to primal values, or NULL if not needed
1175  * - consdualvalues buffer to store pointer to array to dual values of constraints, or NULL if not needed
1176  * - varlbdualvalues buffer to store pointer to array to dual values of variable lower bounds, or NULL if not needed
1177  * - varubdualvalues buffer to store pointer to array to dual values of variable lower bounds, or NULL if not needed
1178  */
1179 static
1180 SCIP_DECL_NLPIGETSOLUTION(nlpiGetSolutionIpopt)
1181 {
1182  assert(nlpi != NULL);
1183  assert(problem != NULL);
1184 
1185  if( primalvalues != NULL )
1186  *primalvalues = problem->lastsolprimals;
1187 
1188  if( consdualvalues != NULL )
1189  *consdualvalues = problem->lastsoldualcons;
1190 
1191  if( varlbdualvalues != NULL )
1192  *varlbdualvalues = problem->lastsoldualvarlb;
1193 
1194  if( varubdualvalues != NULL )
1195  *varubdualvalues = problem->lastsoldualvarub;
1196 
1197  return SCIP_OKAY;
1198 }
1199 
1200 /** gives solve statistics
1201  *
1202  * input:
1203  * - nlpi datastructure for solver interface
1204  * - problem datastructure for problem instance
1205  * - statistics pointer to store statistics
1206  *
1207  * output:
1208  * - statistics solve statistics
1209  */
1210 static
1211 SCIP_DECL_NLPIGETSTATISTICS(nlpiGetStatisticsIpopt)
1212 {
1213  assert(nlpi != NULL);
1214  assert(problem != NULL);
1215 
1216  SCIPnlpStatisticsSetNIterations(statistics, problem->lastniter);
1217  SCIPnlpStatisticsSetTotalTime (statistics, problem->lasttime);
1218 
1219  return SCIP_OKAY;
1220 }
1221 
1222 /** gives required size of a buffer to store a warmstart object
1223  *
1224  * input:
1225  * - nlpi datastructure for solver interface
1226  * - problem datastructure for problem instance
1227  * - size pointer to store required size for warmstart buffer
1228  *
1229  * output:
1230  * - size required size for warmstart buffer
1231  */
1232 static
1233 SCIP_DECL_NLPIGETWARMSTARTSIZE(nlpiGetWarmstartSizeIpopt)
1234 {
1235  SCIPerrorMessage("method of Ipopt nonlinear solver is not implemented\n");
1236  return SCIP_ERROR;
1237 }
1238 
1239 /** stores warmstart information in buffer
1240  *
1241  * required size of buffer should have been obtained by SCIPnlpiGetWarmstartSize before
1242  *
1243  * input:
1244  * - nlpi datastructure for solver interface
1245  * - problem datastructure for problem instance
1246  * - buffer memory to store warmstart information
1247  *
1248  * output:
1249  * - buffer warmstart information in solver specific data structure
1250  */
1251 static
1252 SCIP_DECL_NLPIGETWARMSTARTMEMO(nlpiGetWarmstartMemoIpopt)
1253 {
1254  SCIPerrorMessage("method of Ipopt nonlinear solver is not implemented\n");
1255  return SCIP_ERROR;
1256 }
1257 
1258 /** sets warmstart information in solver
1259  *
1260  * write warmstart to buffer
1261  *
1262  * input:
1263  * - nlpi datastructure for solver interface
1264  * - problem datastructure for problem instance
1265  * - buffer warmstart information
1266  */
1267 static
1268 SCIP_DECL_NLPISETWARMSTARTMEMO(nlpiSetWarmstartMemoIpopt)
1269 {
1270  SCIPerrorMessage("method of Ipopt nonlinear solver is not implemented\n");
1271  SCIPABORT();
1272  return SCIP_OKAY;
1273 }
1274 
1275 /** gets integer parameter of NLP
1276  *
1277  * input:
1278  * - nlpi datastructure for solver interface
1279  * - problem datastructure for problem instance
1280  * - type parameter number
1281  * - ival pointer to store the parameter value
1282  *
1283  * output:
1284  * - ival parameter value
1285  */
1286 static
1287 SCIP_DECL_NLPIGETINTPAR(nlpiGetIntParIpopt)
1288 {
1289  assert(nlpi != NULL);
1290  assert(ival != NULL);
1291  assert(problem != NULL);
1292  assert(IsValid(problem->ipopt));
1293 
1294  //@TODO try-catch block for Ipopt exceptions
1295  switch( type )
1296  {
1298  {
1299  *ival = 1;
1300  break;
1301  }
1302 
1303  case SCIP_NLPPAR_VERBLEVEL:
1304  {
1305  int printlevel;
1306  problem->ipopt->Options()->GetIntegerValue("print_level", printlevel, "");
1307  if( printlevel <= J_STRONGWARNING )
1308  *ival = 0;
1309  else if( printlevel >= J_DETAILED )
1310  *ival = printlevel - J_ITERSUMMARY + 1;
1311  else /* J_SUMMARY or J_WARNING or J_ITERSUMMARY */
1312  *ival = 1;
1313  break;
1314  }
1315 
1316  case SCIP_NLPPAR_FEASTOL:
1317  {
1318  SCIPerrorMessage("feasibility tolerance parameter is of type real.\n");
1319  return SCIP_PARAMETERWRONGTYPE;
1320  }
1321 
1322  case SCIP_NLPPAR_RELOBJTOL:
1323  {
1324  SCIPerrorMessage("relative objective tolerance parameter is of type real.\n");
1325  return SCIP_PARAMETERWRONGTYPE;
1326  }
1327 
1328  case SCIP_NLPPAR_LOBJLIM:
1329  {
1330  SCIPerrorMessage("objective limit parameter is of type real.\n");
1331  return SCIP_PARAMETERWRONGTYPE;
1332  }
1333 
1334  case SCIP_NLPPAR_INFINITY:
1335  {
1336  SCIPerrorMessage("infinity parameter is of type real.\n");
1337  return SCIP_PARAMETERWRONGTYPE;
1338  }
1339 
1340  case SCIP_NLPPAR_ITLIM:
1341  {
1342  problem->ipopt->Options()->GetIntegerValue("max_iter", *ival, "");
1343  break;
1344  }
1345 
1346  case SCIP_NLPPAR_TILIM:
1347  {
1348  SCIPerrorMessage("time limit parameter is of type real.\n");
1349  return SCIP_PARAMETERWRONGTYPE;
1350  }
1351 
1352  case SCIP_NLPPAR_OPTFILE:
1353  {
1354  SCIPerrorMessage("optfile parameter is of type string.\n");
1355  return SCIP_PARAMETERWRONGTYPE;
1356  }
1357 
1358  case SCIP_NLPPAR_FASTFAIL:
1359  {
1360  *ival = problem->fastfail ? 1 : 0;
1361  break;
1362  }
1363 
1364  default:
1365  {
1366  SCIPerrorMessage("Parameter %d not known to Ipopt interface.\n", type);
1367  return SCIP_PARAMETERUNKNOWN;
1368  }
1369  }
1370 
1371  return SCIP_OKAY;
1372 }
1373 
1374 /** sets integer parameter of NLP
1375  *
1376  * input:
1377  * - nlpi datastructure for solver interface
1378  * - problem datastructure for problem instance
1379  * - type parameter number
1380  * - ival parameter value
1381  */
1382 static
1383 SCIP_DECL_NLPISETINTPAR(nlpiSetIntParIpopt)
1384 {
1385  assert(nlpi != NULL);
1386  assert(problem != NULL);
1387  assert(IsValid(problem->ipopt));
1388 
1389  switch( type )
1390  {
1392  {
1393  if( ival == 0 || ival == 1 )
1394  {
1395  SCIP_NLPIDATA* data;
1396 
1397  data = SCIPnlpiGetData(nlpi);
1398  assert(data != NULL);
1399 
1400  SCIPmessagePrintWarning(data->messagehdlr, "from scratch parameter not supported by Ipopt interface yet. Ignored.\n");
1401  }
1402  else
1403  {
1404  SCIPerrorMessage("Value %d for parameter from scratch out of range {0, 1}\n", ival);
1405  return SCIP_PARAMETERWRONGVAL;
1406  }
1407  break;
1408  }
1409 
1410  case SCIP_NLPPAR_VERBLEVEL:
1411  {
1412  switch( ival )
1413  {
1414  case 0:
1415  problem->ipopt->Options()->SetIntegerValue("print_level", J_STRONGWARNING);
1416  break;
1417  case 1:
1418  problem->ipopt->Options()->SetIntegerValue("print_level", J_ITERSUMMARY);
1419  break;
1420  case 2:
1421  problem->ipopt->Options()->SetIntegerValue("print_level", J_DETAILED);
1422  break;
1423  default:
1424  if( ival > 2 )
1425  {
1426  problem->ipopt->Options()->SetIntegerValue("print_level", MIN(J_ITERSUMMARY + (ival-1), J_ALL));
1427  break;
1428  }
1429  else
1430  {
1431  SCIPerrorMessage("Value %d for parameter from verbosity level out of range {0, 1, 2}\n", ival);
1432  return SCIP_PARAMETERWRONGVAL;
1433  }
1434  }
1435  break;
1436  }
1437 
1438  case SCIP_NLPPAR_FEASTOL:
1439  {
1440  SCIPerrorMessage("feasibility tolerance parameter is of type real.\n");
1441  return SCIP_PARAMETERWRONGTYPE;
1442  }
1443 
1444  case SCIP_NLPPAR_RELOBJTOL:
1445  {
1446  SCIPerrorMessage("relative objective tolerance parameter is of type real.\n");
1447  return SCIP_PARAMETERWRONGTYPE;
1448  }
1449 
1450  case SCIP_NLPPAR_LOBJLIM:
1451  {
1452  SCIPerrorMessage("objective limit parameter is of type real.\n");
1453  return SCIP_PARAMETERWRONGTYPE;
1454  }
1455 
1456  case SCIP_NLPPAR_INFINITY:
1457  {
1458  SCIPerrorMessage("infinity parameter is of type real.\n");
1459  return SCIP_PARAMETERWRONGTYPE;
1460  }
1461 
1462  case SCIP_NLPPAR_ITLIM:
1463  {
1464  if( ival >= 0 )
1465  {
1466  problem->ipopt->Options()->SetIntegerValue("max_iter", ival);
1467  }
1468  else
1469  {
1470  SCIPerrorMessage("Value %d for parameter iteration limit is negative\n", ival);
1471  return SCIP_PARAMETERWRONGVAL;
1472  }
1473  break;
1474  }
1475 
1476  case SCIP_NLPPAR_TILIM:
1477  {
1478  SCIPerrorMessage("time limit parameter is of type real.\n");
1479  return SCIP_PARAMETERWRONGTYPE;
1480  }
1481 
1482  case SCIP_NLPPAR_OPTFILE:
1483  {
1484  SCIPerrorMessage("optfile parameter is of type string.\n");
1485  return SCIP_PARAMETERWRONGTYPE;
1486  }
1487 
1488  case SCIP_NLPPAR_FASTFAIL:
1489  {
1490  if( ival == 0 || ival == 1 )
1491  {
1492  problem->fastfail = (bool)ival;
1493  problem->storeintermediate = (bool)ival;
1494  }
1495  else
1496  {
1497  SCIPerrorMessage("Value %d for parameter fastfail out of range {0, 1}\n", ival);
1498  return SCIP_PARAMETERWRONGVAL;
1499  }
1500  break;
1501  }
1502 
1503  default:
1504  {
1505  SCIPerrorMessage("Parameter %d not known to Ipopt interface.\n", type);
1506  return SCIP_PARAMETERUNKNOWN;
1507  }
1508  }
1509 
1510  return SCIP_OKAY;
1511 }
1512 
1513 /** gets floating point parameter of NLP
1514  *
1515  * input:
1516  * - nlpi datastructure for solver interface
1517  * - problem datastructure for problem instance, can be NULL only if type == SCIP_NLPPAR_INFINITY
1518  * - type parameter number
1519  * - dval pointer to store the parameter value
1520  *
1521  * output:
1522  * - dval parameter value
1523  */
1524 static
1525 SCIP_DECL_NLPIGETREALPAR(nlpiGetRealParIpopt)
1526 {
1527  assert(nlpi != NULL);
1528  assert(dval != NULL);
1529  assert(type == SCIP_NLPPAR_INFINITY || problem != NULL);
1530  assert(type == SCIP_NLPPAR_INFINITY || IsValid(problem->ipopt));
1531 
1532  switch( type )
1533  {
1535  {
1536  SCIPerrorMessage("from scratch parameter is of type int.\n");
1537  return SCIP_PARAMETERWRONGTYPE;
1538  }
1539 
1540  case SCIP_NLPPAR_VERBLEVEL:
1541  {
1542  SCIPerrorMessage("verbosity level parameter is of type int.\n");
1543  return SCIP_PARAMETERWRONGTYPE;
1544  }
1545 
1546  case SCIP_NLPPAR_FEASTOL:
1547  {
1548  problem->ipopt->Options()->GetNumericValue("acceptable_constr_viol_tol", *dval, "");
1549  break;
1550  }
1551 
1552  case SCIP_NLPPAR_RELOBJTOL:
1553  {
1554  problem->ipopt->Options()->GetNumericValue("dual_inf_tol", *dval, "");
1555  break;
1556  }
1557 
1558  case SCIP_NLPPAR_LOBJLIM:
1559  {
1560  *dval = -SCIPnlpiOracleGetInfinity(problem->oracle);
1561  break;
1562  }
1563 
1564  case SCIP_NLPPAR_INFINITY:
1565  {
1566  if( problem )
1567  {
1568  *dval = SCIPnlpiOracleGetInfinity(problem->oracle);
1569  }
1570  else
1571  {
1572  SCIP_NLPIDATA* data = SCIPnlpiGetData(nlpi);
1573  assert(data != NULL);
1574  *dval = data->infinity;
1575  }
1576  break;
1577  }
1578 
1579  case SCIP_NLPPAR_ITLIM:
1580  {
1581  SCIPerrorMessage("iteration limit parameter is of type int.\n");
1582  return SCIP_PARAMETERWRONGTYPE;
1583  }
1584 
1585  case SCIP_NLPPAR_TILIM:
1586  {
1587  problem->ipopt->Options()->GetNumericValue("max_cpu_time", *dval, "");
1588  break;
1589  }
1590 
1591  case SCIP_NLPPAR_OPTFILE:
1592  {
1593  SCIPerrorMessage("option file parameter is of type string.\n");
1594  return SCIP_PARAMETERWRONGTYPE;
1595  }
1596 
1597  case SCIP_NLPPAR_FASTFAIL:
1598  {
1599  SCIPerrorMessage("fastfail parameter is of type int.\n");
1600  return SCIP_PARAMETERWRONGTYPE;
1601  }
1602 
1603  default:
1604  {
1605  SCIPerrorMessage("Parameter %d not known to Ipopt interface.\n", type);
1606  return SCIP_PARAMETERUNKNOWN;
1607  }
1608  }
1609 
1610  return SCIP_OKAY;
1611 }
1612 
1613 /** sets floating point parameter of NLP
1614  *
1615  * input:
1616  * - nlpi datastructure for solver interface
1617  * - problem datastructure for problem instance, can be NULL only if type == SCIP_NLPPAR_INFINITY
1618  * - type parameter number
1619  * - dval parameter value
1620  */
1621 static
1622 SCIP_DECL_NLPISETREALPAR(nlpiSetRealParIpopt)
1623 {
1624  assert(nlpi != NULL);
1625  assert(type == SCIP_NLPPAR_INFINITY || problem != NULL);
1626  assert(type == SCIP_NLPPAR_INFINITY || IsValid(problem->ipopt));
1627 
1628  switch( type )
1629  {
1631  {
1632  SCIPerrorMessage("from scratch parameter is of type int.\n");
1633  return SCIP_PARAMETERWRONGTYPE;
1634  }
1635 
1636  case SCIP_NLPPAR_VERBLEVEL:
1637  {
1638  SCIPerrorMessage("verbosity level parameter is of type int.\n");
1639  return SCIP_PARAMETERWRONGTYPE;
1640  }
1641 
1642  case SCIP_NLPPAR_FEASTOL:
1643  {
1644  if( dval >= 0 )
1645  {
1646  setFeastol(problem, dval);
1647  }
1648  else
1649  {
1650  SCIPerrorMessage("Value %g for parameter feasibility tolerance is negative\n", dval);
1651  return SCIP_PARAMETERWRONGVAL;
1652  }
1653  break;
1654  }
1655 
1656  case SCIP_NLPPAR_RELOBJTOL:
1657  {
1658  if( dval >= 0 )
1659  {
1660  problem->ipopt->Options()->SetNumericValue("dual_inf_tol", dval);
1661  }
1662  else
1663  {
1664  SCIPerrorMessage("Value %g for parameter relative objective tolerance is negative\n", dval);
1665  return SCIP_PARAMETERWRONGVAL;
1666  }
1667  break;
1668  }
1669 
1670  case SCIP_NLPPAR_LOBJLIM:
1671  {
1672  SCIP_NLPIDATA* data;
1673 
1674  data = SCIPnlpiGetData(nlpi);
1675  assert(data != NULL);
1676 
1677  SCIPmessagePrintWarning(data->messagehdlr, "Parameter lower objective limit not supported by Ipopt interface yet. Ignored.\n");
1678  break;
1679  }
1680 
1681  case SCIP_NLPPAR_INFINITY:
1682  {
1683  if( dval < 0.0 )
1684  return SCIP_PARAMETERWRONGVAL;
1685  if( problem )
1686  {
1687  problem->ipopt->Options()->SetNumericValue("diverging_iterates_tol", dval);
1688  problem->ipopt->Options()->SetNumericValue("nlp_lower_bound_inf", -dval);
1689  problem->ipopt->Options()->SetNumericValue("nlp_upper_bound_inf", dval);
1690  SCIPnlpiOracleSetInfinity(problem->oracle, dval);
1691  }
1692  else
1693  {
1694  SCIP_NLPIDATA* data = SCIPnlpiGetData(nlpi);
1695  assert(data != NULL);
1696  data->infinity = dval;
1697  }
1698  break;
1699  }
1700 
1701  case SCIP_NLPPAR_ITLIM:
1702  {
1703  SCIPerrorMessage("iteration limit parameter is of type int.\n");
1704  return SCIP_PARAMETERWRONGTYPE;
1705  }
1706 
1707  case SCIP_NLPPAR_TILIM:
1708  {
1709  if( dval >= 0 )
1710  {
1711  problem->ipopt->Options()->SetNumericValue("max_cpu_time", dval);
1712  }
1713  else
1714  {
1715  SCIPerrorMessage("Value %g for parameter time limit is negative\n", dval);
1716  return SCIP_PARAMETERWRONGVAL;
1717  }
1718  break;
1719  }
1720 
1721  case SCIP_NLPPAR_OPTFILE:
1722  {
1723  SCIPerrorMessage("option file parameter is of type string.\n");
1724  return SCIP_PARAMETERWRONGTYPE;
1725  }
1726 
1727  case SCIP_NLPPAR_FASTFAIL:
1728  {
1729  SCIPerrorMessage("fastfail parameter is of type int.\n");
1730  return SCIP_PARAMETERWRONGTYPE;
1731  }
1732 
1733  default:
1734  {
1735  SCIPerrorMessage("Parameter %d not known to Ipopt interface.\n", type);
1736  return SCIP_PARAMETERUNKNOWN;
1737  }
1738  }
1739 
1740  return SCIP_OKAY;
1741 }
1742 
1743 /** gets string parameter of NLP
1744  *
1745  * input:
1746  * - nlpi NLP interface structure
1747  * - problem datastructure for problem instance
1748  * - type parameter number
1749  * - sval pointer to store the string value, the user must not modify the string
1750  *
1751  * output:
1752  * - sval parameter value
1753  */
1754 static
1755 SCIP_DECL_NLPIGETSTRINGPAR( nlpiGetStringParIpopt )
1756 {
1757  assert(nlpi != NULL);
1758  assert(problem != NULL);
1759 
1760  switch( type )
1761  {
1763  {
1764  SCIPerrorMessage("from scratch parameter is of type int.\n");
1765  return SCIP_PARAMETERWRONGTYPE;
1766  }
1767 
1768  case SCIP_NLPPAR_VERBLEVEL:
1769  {
1770  SCIPerrorMessage("verbosity level parameter is of type int.\n");
1771  return SCIP_PARAMETERWRONGTYPE;
1772  }
1773 
1774  case SCIP_NLPPAR_FEASTOL:
1775  {
1776  SCIPerrorMessage("feasibility tolerance parameter is of type real.\n");
1777  return SCIP_PARAMETERWRONGTYPE;
1778  }
1779 
1780  case SCIP_NLPPAR_RELOBJTOL:
1781  {
1782  SCIPerrorMessage("objective tolerance parameter is of type real.\n");
1783  return SCIP_PARAMETERWRONGTYPE;
1784  }
1785 
1786  case SCIP_NLPPAR_LOBJLIM:
1787  {
1788  SCIPerrorMessage("objective limit parameter is of type real.\n");
1789  return SCIP_PARAMETERWRONGTYPE;
1790  }
1791 
1792  case SCIP_NLPPAR_INFINITY:
1793  {
1794  SCIPerrorMessage("infinity parameter is of type real.\n");
1795  return SCIP_PARAMETERWRONGTYPE;
1796  }
1797 
1798  case SCIP_NLPPAR_ITLIM:
1799  {
1800  SCIPerrorMessage("iteration limit parameter is of type int.\n");
1801  return SCIP_PARAMETERWRONGTYPE;
1802  }
1803 
1804  case SCIP_NLPPAR_TILIM:
1805  {
1806  SCIPerrorMessage("time limit parameter is of type real.\n");
1807  return SCIP_PARAMETERWRONGTYPE;
1808  }
1809 
1810  case SCIP_NLPPAR_OPTFILE:
1811  {
1812  if( !problem->optfile.empty() )
1813  *sval = problem->optfile.c_str();
1814  else
1815  *sval = NULL;
1816  return SCIP_OKAY;
1817  }
1818 
1819  case SCIP_NLPPAR_FASTFAIL:
1820  {
1821  SCIPerrorMessage("fastfail parameter is of type int.\n");
1822  return SCIP_PARAMETERWRONGTYPE;
1823  }
1824 
1825  default:
1826  {
1827  SCIPerrorMessage("Parameter %d not known to Ipopt interface.\n", type);
1828  return SCIP_PARAMETERUNKNOWN;
1829  }
1830  }
1831 
1832  return SCIP_OKAY;
1833 }
1834 
1835 /** sets string parameter of NLP
1836  *
1837  * input:
1838  * - nlpi NLP interface structure
1839  * - problem datastructure for problem instance
1840  * - type parameter number
1841  * - sval parameter value
1842  */
1843 static
1844 SCIP_DECL_NLPISETSTRINGPAR( nlpiSetStringParIpopt )
1845 {
1846  assert(nlpi != NULL);
1847  assert(problem != NULL);
1848 
1849  switch( type )
1850  {
1852  {
1853  SCIPerrorMessage("from scratch parameter is of type int.\n");
1854  return SCIP_PARAMETERWRONGTYPE;
1855  }
1856 
1857  case SCIP_NLPPAR_VERBLEVEL:
1858  {
1859  SCIPerrorMessage("verbosity level parameter is of type int.\n");
1860  return SCIP_PARAMETERWRONGTYPE;
1861  }
1862 
1863  case SCIP_NLPPAR_FEASTOL:
1864  {
1865  SCIPerrorMessage("feasibility tolerance parameter is of type real.\n");
1866  return SCIP_PARAMETERWRONGTYPE;
1867  }
1868 
1869  case SCIP_NLPPAR_RELOBJTOL:
1870  {
1871  SCIPerrorMessage("objective tolerance parameter is of type real.\n");
1872  return SCIP_PARAMETERWRONGTYPE;
1873  }
1874 
1875  case SCIP_NLPPAR_LOBJLIM:
1876  {
1877  SCIPerrorMessage("objective limit parameter is of type real.\n");
1878  return SCIP_PARAMETERWRONGTYPE;
1879  }
1880 
1881  case SCIP_NLPPAR_INFINITY:
1882  {
1883  SCIPerrorMessage("infinity parameter is of type real.\n");
1884  return SCIP_PARAMETERWRONGTYPE;
1885  }
1886 
1887  case SCIP_NLPPAR_ITLIM:
1888  {
1889  SCIPerrorMessage("iteration limit parameter is of type int.\n");
1890  return SCIP_PARAMETERWRONGTYPE;
1891  }
1892 
1893  case SCIP_NLPPAR_TILIM:
1894  {
1895  SCIPerrorMessage("time limit parameter is of type real.\n");
1896  return SCIP_PARAMETERWRONGTYPE;
1897  }
1898 
1899  case SCIP_NLPPAR_OPTFILE:
1900  {
1901  if( sval != NULL )
1902  problem->optfile = sval;
1903  else
1904  problem->optfile.clear();
1905 
1906  if( problem->ipopt->Initialize(problem->optfile) != Solve_Succeeded )
1907  {
1908  SCIPerrorMessage("Error initializing Ipopt using optionfile \"%s\"\n", problem->optfile.c_str());
1909  return SCIP_ERROR;
1910  }
1911  problem->ipopt->Options()->GetBoolValue("store_intermediate", problem->storeintermediate, "");
1912  problem->firstrun = TRUE;
1913 
1914  return SCIP_OKAY;
1915  }
1916 
1917  case SCIP_NLPPAR_FASTFAIL:
1918  {
1919  SCIPerrorMessage("fastfail parameter is of type int.\n");
1920  return SCIP_PARAMETERWRONGTYPE;
1921  }
1922 
1923  default:
1924  {
1925  SCIPerrorMessage("Parameter %d not known to Ipopt interface.\n", type);
1926  return SCIP_PARAMETERUNKNOWN;
1927  }
1928  }
1929 
1930  return SCIP_OKAY;
1931 }
1932 
1933 /** sets message handler for message output
1934  *
1935  * input:
1936  * - nlpi NLP interface structure
1937  * - messagehdlr SCIP message handler, or NULL to suppress all output
1938  */
1939 static
1940 SCIP_DECL_NLPISETMESSAGEHDLR( nlpiSetMessageHdlrIpopt )
1941 {
1942  SCIP_NLPIDATA* nlpidata;
1943 
1944  assert(nlpi != NULL);
1945 
1946  nlpidata = SCIPnlpiGetData(nlpi);
1947  assert(nlpidata != NULL);
1948 
1949  nlpidata->messagehdlr = messagehdlr;
1950 
1951  return SCIP_OKAY; /*lint !e527*/
1952 } /*lint !e715*/
1953 
1954 /** create solver interface for Ipopt solver */
1956  BMS_BLKMEM* blkmem, /**< block memory data structure */
1957  SCIP_NLPI** nlpi /**< pointer to buffer for nlpi address */
1958  )
1959 {
1960  SCIP_NLPIDATA* nlpidata;
1961 
1962  assert(blkmem != NULL);
1963  assert(nlpi != NULL);
1964 
1965  SCIP_ALLOC( nlpidata = new SCIP_NLPIDATA(blkmem) );
1966 
1967  SCIP_CALL( SCIPnlpiCreate(nlpi,
1969  nlpiCopyIpopt, nlpiFreeIpopt, nlpiGetSolverPointerIpopt,
1970  nlpiCreateProblemIpopt, nlpiFreeProblemIpopt, nlpiGetProblemPointerIpopt,
1971  nlpiAddVarsIpopt, nlpiAddConstraintsIpopt, nlpiSetObjectiveIpopt,
1972  nlpiChgVarBoundsIpopt, nlpiChgConsSidesIpopt, nlpiDelVarSetIpopt, nlpiDelConstraintSetIpopt,
1973  nlpiChgLinearCoefsIpopt, nlpiChgQuadraticCoefsIpopt, nlpiChgExprtreeIpopt, nlpiChgNonlinCoefIpopt,
1974  nlpiChgObjConstantIpopt, nlpiSetInitialGuessIpopt, nlpiSolveIpopt, nlpiGetSolstatIpopt, nlpiGetTermstatIpopt,
1975  nlpiGetSolutionIpopt, nlpiGetStatisticsIpopt,
1976  nlpiGetWarmstartSizeIpopt, nlpiGetWarmstartMemoIpopt, nlpiSetWarmstartMemoIpopt,
1977  nlpiGetIntParIpopt, nlpiSetIntParIpopt, nlpiGetRealParIpopt, nlpiSetRealParIpopt,
1978  nlpiGetStringParIpopt, nlpiSetStringParIpopt, nlpiSetMessageHdlrIpopt,
1979  nlpidata) );
1980 
1981  return SCIP_OKAY;
1982 }
1983 
1984 /** gets string that identifies Ipopt (version number) */
1985 const char* SCIPgetSolverNameIpopt(void)
1986 {
1987  return "Ipopt " IPOPT_VERSION;
1988 }
1989 
1990 /** gets string that describes Ipopt (version number) */
1991 const char* SCIPgetSolverDescIpopt(void)
1992 {
1993  return "Interior Point Optimizer developed by A. Waechter et.al. (www.coin-or.org/Ipopt)";
1994 }
1995 
1996 /** returns whether Ipopt is available, i.e., whether it has been linked in */
1998 {
1999  return TRUE;
2000 }
2001 
2002 /** gives a pointer to the IpoptApplication object stored in Ipopt-NLPI's NLPI problem data structure */
2004  SCIP_NLPIPROBLEM* nlpiproblem /**< NLP problem of Ipopt-NLPI */
2005  )
2006 {
2007  assert(nlpiproblem != NULL);
2008 
2009  return (void*)GetRawPtr(nlpiproblem->ipopt);
2010 }
2011 
2012 /** gives a pointer to the NLPIORACLE object stored in Ipopt-NLPI's NLPI problem data structure */
2014  SCIP_NLPIPROBLEM* nlpiproblem /**< NLP problem of Ipopt-NLPI */
2015  )
2016 {
2017  assert(nlpiproblem != NULL);
2018 
2019  return nlpiproblem->oracle;
2020 }
2021 
2022 /** sets modified default settings that are used when setting up an Ipopt problem
2023  *
2024  * Do not forget to add a newline after the last option in optionsstring.
2025  */
2027  SCIP_NLPI* nlpi, /**< Ipopt NLP interface */
2028  const char* optionsstring /**< string with options as in Ipopt options file */
2029  )
2030 {
2031  SCIP_NLPIDATA* data;
2032 
2033  assert(nlpi != NULL);
2034 
2035  data = SCIPnlpiGetData(nlpi);
2036  assert(data != NULL);
2037 
2038  data->defoptions = optionsstring;
2039 }
2040 
2041 /** Method to return some info about the nlp */
2042 bool ScipNLP::get_nlp_info(
2043  Index& n, /**< place to store number of variables */
2044  Index& m, /**< place to store number of constraints */
2045  Index& nnz_jac_g, /**< place to store number of nonzeros in jacobian */
2046  Index& nnz_h_lag, /**< place to store number of nonzeros in hessian */
2047  IndexStyleEnum& index_style /**< place to store used index style (0-based or 1-based) */
2048  )
2049 {
2050  const int* offset;
2051  SCIP_RETCODE retcode;
2052 
2053  assert(nlpiproblem != NULL);
2054  assert(nlpiproblem->oracle != NULL);
2055 
2056  n = SCIPnlpiOracleGetNVars(nlpiproblem->oracle);
2057  m = SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle);
2058 
2059  retcode = SCIPnlpiOracleGetJacobianSparsity(nlpiproblem->oracle, &offset, NULL);
2060  if( retcode != SCIP_OKAY )
2061  return false;
2062  assert(offset != NULL);
2063  nnz_jac_g = offset[m];
2064 
2065  if( !approxhessian )
2066  {
2067  retcode = SCIPnlpiOracleGetHessianLagSparsity(nlpiproblem->oracle, &offset, NULL);
2068  if( retcode != SCIP_OKAY )
2069  return false;
2070  assert(offset != NULL);
2071  nnz_h_lag = offset[n];
2072  }
2073  else
2074  {
2075  nnz_h_lag = 0;
2076  }
2077 
2078  index_style = TNLP::C_STYLE;
2079 
2080  return true;
2081 }
2082 
2083 /** Method to return the bounds for my problem */
2084 bool ScipNLP::get_bounds_info(
2085  Index n, /**< number of variables */
2086  Number* x_l, /**< buffer to store lower bounds on variables */
2087  Number* x_u, /**< buffer to store upper bounds on variables */
2088  Index m, /**< number of constraints */
2089  Number* g_l, /**< buffer to store lower bounds on constraints */
2090  Number* g_u /**< buffer to store lower bounds on constraints */
2091  )
2092 {
2093  assert(nlpiproblem != NULL);
2094  assert(nlpiproblem->oracle != NULL);
2095 
2096  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2097  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2098 
2099  assert(SCIPnlpiOracleGetVarLbs(nlpiproblem->oracle) != NULL);
2100  assert(SCIPnlpiOracleGetVarUbs(nlpiproblem->oracle) != NULL);
2101 
2102  BMScopyMemoryArray(x_l, SCIPnlpiOracleGetVarLbs(nlpiproblem->oracle), n);
2103  BMScopyMemoryArray(x_u, SCIPnlpiOracleGetVarUbs(nlpiproblem->oracle), n);
2104 #ifndef NDEBUG
2105  for( int i = 0; i < n; ++i )
2106  assert(x_l[i] <= x_u[i]);
2107 #endif
2108 
2109  for( int i = 0; i < m; ++i )
2110  {
2111  g_l[i] = SCIPnlpiOracleGetConstraintLhs(nlpiproblem->oracle, i);
2112  g_u[i] = SCIPnlpiOracleGetConstraintRhs(nlpiproblem->oracle, i);
2113  assert(g_l[i] <= g_u[i]);
2114  }
2115 
2116  return true;
2117 }
2118 
2119 /** Method to return the starting point for the algorithm */
2120 bool ScipNLP::get_starting_point(
2121  Index n, /**< number of variables */
2122  bool init_x, /**< whether initial values for primal values are requested */
2123  Number* x, /**< buffer to store initial primal values */
2124  bool init_z, /**< whether initial values for dual values of variable bounds are requested */
2125  Number* z_L, /**< buffer to store dual values for variable lower bounds */
2126  Number* z_U, /**< buffer to store dual values for variable upper bounds */
2127  Index m, /**< number of constraints */
2128  bool init_lambda, /**< whether initial values for dual values of constraints are required */
2129  Number* lambda /**< buffer to store dual values of constraints */
2130  )
2131 {
2132  assert(nlpiproblem != NULL);
2133  assert(nlpiproblem->oracle != NULL);
2134 
2135  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2136  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2137 
2138  if( init_x )
2139  {
2140  if( nlpiproblem->initguess )
2141  {
2142  BMScopyMemoryArray(x, nlpiproblem->initguess, n);
2143  }
2144  else
2145  {
2146  SCIP_Real lb, ub;
2147  unsigned int perturbseed;
2148 
2149  SCIPdebugMessage("Ipopt started without intial primal values; make up starting guess by projecting 0 onto variable bounds\n");
2150 
2151  perturbseed = 1;
2152  for( int i = 0; i < n; ++i )
2153  {
2154  lb = SCIPnlpiOracleGetVarLbs(nlpiproblem->oracle)[i];
2155  ub = SCIPnlpiOracleGetVarUbs(nlpiproblem->oracle)[i];
2156  if( lb > 0.0 )
2157  x[i] = SCIPgetRandomReal(lb, lb + MAXPERTURB*MIN(1.0, ub-lb), &perturbseed);
2158  else if( ub < 0.0 )
2159  x[i] = SCIPgetRandomReal(ub - MAXPERTURB*MIN(1.0, ub-lb), ub, &perturbseed);
2160  else
2161  x[i] = SCIPgetRandomReal(MAX(lb, -MAXPERTURB*MIN(1.0, ub-lb)), MIN(ub, MAXPERTURB*MIN(1.0, ub-lb)), &perturbseed);
2162  }
2163  }
2164  }
2165  if( init_z || init_lambda )
2166  return false;
2167 
2168  return true;
2169 }
2170 
2171 /** Method to return the variables linearity. */
2172 bool ScipNLP::get_variables_linearity(
2173  Index n, /**< number of variables */
2174  LinearityType* var_types /**< buffer to store linearity types of variables */
2175  )
2176 {
2177  assert(nlpiproblem != NULL);
2178  assert(nlpiproblem->oracle != NULL);
2179 
2180  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2181 
2182  for( int i = 0; i < n; ++i )
2183  var_types[i] = (SCIPnlpiOracleGetVarDegree(nlpiproblem->oracle, i) <= 1 ? LINEAR : NON_LINEAR);
2184 
2185  return true;
2186 }
2187 
2188 /** Method to return the constraint linearity. */
2189 bool ScipNLP::get_constraints_linearity(
2190  Index m, /**< number of constraints */
2191  LinearityType* const_types /**< buffer to store linearity types of constraints */
2192  )
2193 {
2194  int i;
2195 
2196  assert(nlpiproblem != NULL);
2197  assert(nlpiproblem->oracle != NULL);
2198 
2199  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2200 
2201  for( i = 0; i < m; ++i )
2202  const_types[i] = (SCIPnlpiOracleGetConstraintDegree(nlpiproblem->oracle, i) <= 1 ? LINEAR : NON_LINEAR);
2203 
2204  return true;
2205 }
2206 
2207 
2208 /** Method to return the number of nonlinear variables. */
2209 Index ScipNLP::get_number_of_nonlinear_variables()
2210 {
2211  int count;
2212  int n;
2213 
2214  assert(nlpiproblem != NULL);
2215  assert(nlpiproblem->oracle != NULL);
2216 
2217  n = SCIPnlpiOracleGetNVars(nlpiproblem->oracle);
2218 
2219  count = 0;
2220  for( int i = 0; i < n; ++i )
2221  if (SCIPnlpiOracleGetVarDegree(nlpiproblem->oracle, i) > 1)
2222  ++count;
2223 
2224  return count;
2225 }
2226 
2227 /** Method to return the indices of the nonlinear variables */
2228 bool ScipNLP::get_list_of_nonlinear_variables(
2229  Index num_nonlin_vars, /**< number of nonlinear variables */
2230  Index* pos_nonlin_vars /**< array to fill with indices of nonlinear variables */
2231  )
2232 {
2233  int count;
2234  int n;
2235 
2236  assert(nlpiproblem != NULL);
2237  assert(nlpiproblem->oracle != NULL);
2238 
2239  n = SCIPnlpiOracleGetNVars(nlpiproblem->oracle);
2240 
2241  count = 0;
2242  for( int i = 0; i < n; ++i )
2243  if (SCIPnlpiOracleGetVarDegree(nlpiproblem->oracle, i) > 1)
2244  {
2245  assert(count < num_nonlin_vars);
2246  pos_nonlin_vars[count++] = i;
2247  }
2248 
2249  assert(count == num_nonlin_vars);
2250 
2251  return true;
2252 }
2253 
2254 /** Method to return metadata about variables and constraints */
2255 bool ScipNLP::get_var_con_metadata(
2256  Index n, /**< number of variables */
2257  StringMetaDataMapType& var_string_md, /**< variable meta data of string type */
2258  IntegerMetaDataMapType& var_integer_md,/**< variable meta data of integer type */
2259  NumericMetaDataMapType& var_numeric_md,/**< variable meta data of numeric type */
2260  Index m, /**< number of constraints */
2261  StringMetaDataMapType& con_string_md, /**< constraint meta data of string type */
2262  IntegerMetaDataMapType& con_integer_md,/**< constraint meta data of integer type */
2263  NumericMetaDataMapType& con_numeric_md /**< constraint meta data of numeric type */
2264  )
2265 {
2266  assert(nlpiproblem != NULL);
2267  assert(nlpiproblem->oracle != NULL);
2268  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2269  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2270 
2271  char** varnames = SCIPnlpiOracleGetVarNames(nlpiproblem->oracle);
2272  if( varnames != NULL )
2273  {
2274  std::vector<std::string>& varnamesvec(var_string_md["idx_names"]);
2275  varnamesvec.reserve(n);
2276  for( int i = 0; i < n; ++i )
2277  {
2278  if( varnames[i] != NULL )
2279  {
2280  varnamesvec.push_back(varnames[i]);
2281  }
2282  else
2283  {
2284  char buffer[20];
2285  sprintf(buffer, "nlpivar%8d", i);
2286  varnamesvec.push_back(buffer);
2287  }
2288  }
2289  }
2290 
2291  std::vector<std::string>& consnamesvec(con_string_md["idx_names"]);
2292  consnamesvec.reserve(m);
2293  for( int i = 0; i < m; ++i )
2294  {
2295  if( SCIPnlpiOracleGetConstraintName(nlpiproblem->oracle, i) != NULL )
2296  {
2297  consnamesvec.push_back(SCIPnlpiOracleGetConstraintName(nlpiproblem->oracle, i));
2298  }
2299  else
2300  {
2301  char buffer[20];
2302  sprintf(buffer, "nlpicons%8d", i);
2303  consnamesvec.push_back(buffer);
2304  }
2305  }
2306 
2307  return true;
2308 }
2309 
2310 /** Method to return the objective value */
2311 bool ScipNLP::eval_f(
2312  Index n, /**< number of variables */
2313  const Number* x, /**< point to evaluate */
2314  bool new_x, /**< whether some function evaluation method has been called for this point before */
2315  Number& obj_value /**< place to store objective function value */
2316  )
2317 {
2318  assert(nlpiproblem != NULL);
2319  assert(nlpiproblem->oracle != NULL);
2320 
2321  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2322 
2323  return SCIPnlpiOracleEvalObjectiveValue(nlpiproblem->oracle, x, &obj_value) == SCIP_OKAY;
2324 }
2325 
2326 /** Method to return the gradient of the objective */
2327 bool ScipNLP::eval_grad_f(
2328  Index n, /**< number of variables */
2329  const Number* x, /**< point to evaluate */
2330  bool new_x, /**< whether some function evaluation method has been called for this point before */
2331  Number* grad_f /**< buffer to store objective gradient */
2332  )
2333 {
2334  SCIP_Real dummy;
2335 
2336  assert(nlpiproblem != NULL);
2337  assert(nlpiproblem->oracle != NULL);
2338 
2339  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2340 
2341  return SCIPnlpiOracleEvalObjectiveGradient(nlpiproblem->oracle, x, TRUE, &dummy, grad_f) == SCIP_OKAY;
2342 }
2343 
2344 /** Method to return the constraint residuals */
2345 bool ScipNLP::eval_g(
2346  Index n, /**< number of variables */
2347  const Number* x, /**< point to evaluate */
2348  bool new_x, /**< whether some function evaluation method has been called for this point before */
2349  Index m, /**< number of constraints */
2350  Number* g /**< buffer to store constraint function values */
2351  )
2352 {
2353  assert(nlpiproblem != NULL);
2354  assert(nlpiproblem->oracle != NULL);
2355 
2356  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2357 
2358  return SCIPnlpiOracleEvalConstraintValues(nlpiproblem->oracle, x, g) == SCIP_OKAY;
2359 }
2360 
2361 /** Method to return:
2362  * 1) The structure of the jacobian (if "values" is NULL)
2363  * 2) The values of the jacobian (if "values" is not NULL)
2364  */
2365 bool ScipNLP::eval_jac_g(
2366  Index n, /**< number of variables */
2367  const Number* x, /**< point to evaluate */
2368  bool new_x, /**< whether some function evaluation method has been called for this point before */
2369  Index m, /**< number of constraints */
2370  Index nele_jac, /**< number of nonzero entries in jacobian */
2371  Index* iRow, /**< buffer to store row indices of nonzero jacobian entries, or NULL if values are requested */
2372  Index* jCol, /**< buffer to store column indices of nonzero jacobian entries, or NULL if values are requested */
2373  Number* values /**< buffer to store values of nonzero jacobian entries, or NULL if structure is requested */
2374  )
2375 {
2376  assert(nlpiproblem != NULL);
2377  assert(nlpiproblem->oracle != NULL);
2378 
2379  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2380  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2381 
2382  if( values == NULL )
2383  { /* Ipopt wants to know sparsity structure */
2384  const int* jacoffset;
2385  const int* jaccol;
2386  int j;
2387  int i;
2388 
2389  assert(iRow != NULL);
2390  assert(jCol != NULL);
2391 
2392  if( SCIPnlpiOracleGetJacobianSparsity(nlpiproblem->oracle, &jacoffset, &jaccol) != SCIP_OKAY )
2393  return false;
2394 
2395  assert(jacoffset[0] == 0);
2396  assert(jacoffset[m] == nele_jac);
2397  j = jacoffset[0];
2398  for( i = 0; i < m; ++i )
2399  for( ; j < jacoffset[i+1]; ++j )
2400  iRow[j] = i;
2401 
2402  BMScopyMemoryArray(jCol, jaccol, nele_jac);
2403  }
2404  else
2405  {
2406  if( SCIPnlpiOracleEvalJacobian(nlpiproblem->oracle, x, TRUE, NULL, values) != SCIP_OKAY )
2407  return false;
2408  }
2409 
2410  return true;
2411 }
2412 
2413 /** Method to return:
2414  * 1) The structure of the hessian of the lagrangian (if "values" is NULL)
2415  * 2) The values of the hessian of the lagrangian (if "values" is not NULL)
2416  */
2417 bool ScipNLP::eval_h(
2418  Index n, /**< number of variables */
2419  const Number* x, /**< point to evaluate */
2420  bool new_x, /**< whether some function evaluation method has been called for this point before */
2421  Number obj_factor, /**< weight for objective function */
2422  Index m, /**< number of constraints */
2423  const Number* lambda, /**< weights for constraint functions */
2424  bool new_lambda, /**< whether the hessian has been evaluated for these values of lambda before */
2425  Index nele_hess, /**< number of nonzero entries in hessian */
2426  Index* iRow, /**< buffer to store row indices of nonzero hessian entries, or NULL if values are requested */
2427  Index* jCol, /**< buffer to store column indices of nonzero hessian entries, or NULL if values are requested */
2428  Number* values /**< buffer to store values of nonzero hessian entries, or NULL if structure is requested */
2429  )
2430 {
2431  assert(nlpiproblem != NULL);
2432  assert(nlpiproblem->oracle != NULL);
2433 
2434  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2435  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2436 
2437  if( values == NULL )
2438  { /* Ipopt wants to know sparsity structure */
2439  const int* heslagoffset;
2440  const int* heslagcol;
2441  int j;
2442  int i;
2443 
2444  assert(iRow != NULL);
2445  assert(jCol != NULL);
2446 
2447  if( SCIPnlpiOracleGetHessianLagSparsity(nlpiproblem->oracle, &heslagoffset, &heslagcol) != SCIP_OKAY )
2448  return false;
2449 
2450  assert(heslagoffset[0] == 0);
2451  assert(heslagoffset[n] == nele_hess);
2452  j = heslagoffset[0];
2453  for( i = 0; i < n; ++i )
2454  for( ; j < heslagoffset[i+1]; ++j )
2455  iRow[j] = i;
2456 
2457  BMScopyMemoryArray(jCol, heslagcol, nele_hess);
2458  }
2459  else
2460  {
2461  if( SCIPnlpiOracleEvalHessianLag(nlpiproblem->oracle, x, TRUE, obj_factor, lambda, values) != SCIP_OKAY )
2462  return false;
2463  }
2464 
2465  return true;
2466 }
2467 
2468 /** Method called by the solver at each iteration.
2469  *
2470  * Checks whether Ctrl-C was hit.
2471  */
2472 bool ScipNLP::intermediate_callback(
2473  AlgorithmMode mode, /**< current mode of algorithm */
2474  Index iter, /**< current iteration number */
2475  Number obj_value, /**< current objective value */
2476  Number inf_pr, /**< current primal infeasibility */
2477  Number inf_du, /**< current dual infeasibility */
2478  Number mu, /**< current barrier parameter */
2479  Number d_norm, /**< current gradient norm */
2480  Number regularization_size,/**< current size of regularization */
2481  Number alpha_du, /**< current dual alpha */
2482  Number alpha_pr, /**< current primal alpha */
2483  Index ls_trials, /**< current number of linesearch trials */
2484  const IpoptData* ip_data, /**< pointer to Ipopt Data */
2485  IpoptCalculatedQuantities* ip_cq /**< pointer to current calculated quantities */
2486  )
2487 {
2488  if( nlpiproblem->storeintermediate && mode == RegularMode && inf_pr < nlpiproblem->lastsolinfeas )
2489  {
2490  Ipopt::TNLPAdapter* tnlp_adapter;
2491 
2492  tnlp_adapter = NULL;
2493  if( ip_cq != NULL )
2494  {
2495  Ipopt::OrigIpoptNLP* orignlp;
2496 
2497  orignlp = dynamic_cast<OrigIpoptNLP*>(GetRawPtr(ip_cq->GetIpoptNLP()));
2498  if( orignlp != NULL )
2499  tnlp_adapter = dynamic_cast<TNLPAdapter*>(GetRawPtr(orignlp->nlp()));
2500  }
2501 
2502  if( tnlp_adapter != NULL && ip_data != NULL && IsValid(ip_data->curr()) )
2503  {
2504  SCIPdebugMessage("update lastsol: inf_pr old = %g -> new = %g\n", nlpiproblem->lastsolinfeas, inf_pr);
2505 
2506  if( nlpiproblem->lastsolprimals == NULL )
2507  {
2508  assert(nlpiproblem->lastsoldualcons == NULL);
2509  assert(nlpiproblem->lastsoldualvarlb == NULL);
2510  assert(nlpiproblem->lastsoldualvarub == NULL);
2511  if( BMSallocMemoryArray(&nlpiproblem->lastsolprimals, SCIPnlpiOracleGetNVars(nlpiproblem->oracle)) == NULL ||
2512  BMSallocMemoryArray(&nlpiproblem->lastsoldualcons, SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle)) == NULL ||
2513  BMSallocMemoryArray(&nlpiproblem->lastsoldualvarlb, SCIPnlpiOracleGetNVars(nlpiproblem->oracle)) == NULL ||
2514  BMSallocMemoryArray(&nlpiproblem->lastsoldualvarub, SCIPnlpiOracleGetNVars(nlpiproblem->oracle)) == NULL )
2515  {
2516  SCIPerrorMessage("out-of-memory in ScipNLP::intermediate_callback()\n");
2517  return TRUE;
2518  }
2519  }
2520 
2521  assert(IsValid(ip_data->curr()->x()));
2522  tnlp_adapter->ResortX(*ip_data->curr()->x(), nlpiproblem->lastsolprimals);
2523  nlpiproblem->lastsolinfeas = inf_pr;
2524 
2525  assert(IsValid(ip_data->curr()->y_c()));
2526  assert(IsValid(ip_data->curr()->y_d()));
2527  tnlp_adapter->ResortG(*ip_data->curr()->y_c(), *ip_data->curr()->y_d(), nlpiproblem->lastsoldualcons);
2528 
2529  // need to clear arrays first because ResortBnds only sets values for non-fixed variables
2530  BMSclearMemoryArray(nlpiproblem->lastsoldualvarlb, SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2531  BMSclearMemoryArray(nlpiproblem->lastsoldualvarub, SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2532  assert(IsValid(ip_data->curr()->z_L()));
2533  assert(IsValid(ip_data->curr()->z_U()));
2534  tnlp_adapter->ResortBnds(*ip_data->curr()->z_L(), nlpiproblem->lastsoldualvarlb, *ip_data->curr()->z_U(), nlpiproblem->lastsoldualvarub);
2535 
2536  }
2537  }
2538 
2539  /* do convergence test if fastfail is enabled */
2540  if( nlpiproblem->fastfail )
2541  {
2542  int i;
2543 
2544  if( iter == 0 )
2545  {
2546  conv_lastrestoiter = -1;
2547  }
2548  else if( mode == RestorationPhaseMode )
2549  {
2550  conv_lastrestoiter = iter;
2551  }
2552  else if( conv_lastrestoiter == iter-1 )
2553  {
2554  /* just switched back from restoration mode, reset dual reduction targets */
2555  for( i = 0; i < convcheck_nchecks; ++i )
2556  conv_dutarget[i] = convcheck_minred[i] * inf_du;
2557  }
2558 
2559  if( iter == convcheck_startiter )
2560  {
2561  /* define initial targets and iteration limits */
2562  for( i = 0; i < convcheck_nchecks; ++i )
2563  {
2564  conv_prtarget[i] = convcheck_minred[i] * inf_pr;
2565  conv_dutarget[i] = convcheck_minred[i] * inf_du;
2566  conv_iterlim[i] = iter + convcheck_maxiter[i];
2567  }
2568  }
2569  else if( iter > convcheck_startiter )
2570  {
2571  /* check if we should stop */
2572  for( i = 0; i < convcheck_nchecks; ++i )
2573  {
2574  if( inf_pr <= conv_prtarget[i] )
2575  {
2576  /* sufficient reduction w.r.t. primal infeasibility target
2577  * reset target w.r.t. current infeasibilities
2578  */
2579  conv_prtarget[i] = convcheck_minred[i] * inf_pr;
2580  conv_dutarget[i] = convcheck_minred[i] * inf_du;
2581  conv_iterlim[i] = iter + convcheck_maxiter[i];
2582  }
2583  else if( iter >= conv_iterlim[i] )
2584  {
2585  /* we hit a limit, should we really stop? */
2586  SCIPdebugMessage("convcheck %d: inf_pr = %e > target %e; inf_du = %e target %e: ",
2587  i, inf_pr, conv_prtarget[i], inf_du, conv_dutarget[i]);
2588  if( mode == RegularMode && iter <= conv_lastrestoiter + convcheck_startiter )
2589  {
2590  /* if we returned from feasibility restoration recently, we allow some more iterations,
2591  * because Ipopt may go for optimality for some iterations, at the costs of infeasibility
2592  */
2593  SCIPdebugPrintf("continue, because restoration phase only %d iters ago\n", iter - conv_lastrestoiter);
2594  }
2595  else if( mode == RegularMode && inf_du <= conv_dutarget[i] && iter < conv_iterlim[i] + convcheck_maxiter[i] )
2596  {
2597  /* if dual reduction is sufficient, we allow for twice the number of iterations to reach primal infeas reduction */
2598  SCIPdebugPrintf("continue, because dual infeas. red. sufficient and only %d iters above limit\n", iter - conv_iterlim[i]);
2599  }
2600  else
2601  {
2602  SCIPdebugPrintf("abort\n");
2603  return false;
2604  }
2605  }
2606  }
2607  }
2608  }
2609 
2610  return (SCIPinterrupted() == FALSE);
2611 }
2612 
2613 /** This method is called when the algorithm is complete so the TNLP can store/write the solution.
2614  */
2615 void ScipNLP::finalize_solution(
2616  SolverReturn status, /**< solve and solution status */
2617  Index n, /**< number of variables */
2618  const Number* x, /**< primal solution values */
2619  const Number* z_L, /**< dual values of variable lower bounds */
2620  const Number* z_U, /**< dual values of variable upper bounds */
2621  Index m, /**< number of constraints */
2622  const Number* g, /**< values of constraints */
2623  const Number* lambda, /**< dual values of constraints */
2624  Number obj_value, /**< objective function value */
2625  const IpoptData* data, /**< pointer to Ipopt Data */
2626  IpoptCalculatedQuantities* cq /**< pointer to calculated quantities */
2627  )
2628 {
2629  assert(nlpiproblem != NULL);
2630  assert(nlpiproblem->oracle != NULL);
2631 
2632  assert(n == SCIPnlpiOracleGetNVars(nlpiproblem->oracle));
2633  assert(m == SCIPnlpiOracleGetNConstraints(nlpiproblem->oracle));
2634 
2635  bool check_feasibility = false; // whether we should check x for feasibility, if not NULL
2636  switch( status )
2637  {
2638  case SUCCESS:
2639  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCOPT;
2640  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_OKAY;
2641  assert(x != NULL);
2642  break;
2643 
2644  case STOP_AT_ACCEPTABLE_POINT:
2645  /* if stop at acceptable point, then dual infeasibility can be arbitrary large, so claim only feasibility */
2646  case FEASIBLE_POINT_FOUND:
2647  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_FEASIBLE;
2648  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_OKAY;
2649  assert(x != NULL);
2650  break;
2651 
2652  case MAXITER_EXCEEDED:
2653  check_feasibility = true;
2654  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2655  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_ITLIM;
2656  break;
2657 
2658  case CPUTIME_EXCEEDED:
2659  check_feasibility = true;
2660  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2661  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_TILIM;
2662  break;
2663 
2664  case STOP_AT_TINY_STEP:
2665  case RESTORATION_FAILURE:
2666  case ERROR_IN_STEP_COMPUTATION:
2667  check_feasibility = true;
2668  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2669  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_NUMERR;
2670  break;
2671 
2672  case LOCAL_INFEASIBILITY:
2673  /* still check feasibility, since we let Ipopt solve with higher tolerance than actually required */
2674  check_feasibility = true;
2675  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2676  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_OKAY;
2677  break;
2678 
2679  case DIVERGING_ITERATES:
2680  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNBOUNDED;
2681  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_UOBJLIM;
2682  break;
2683 
2684  case INVALID_NUMBER_DETECTED:
2685  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2686  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_EVALERR;
2687  break;
2688 
2689  case USER_REQUESTED_STOP:
2690  check_feasibility = true;
2691  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2692  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_OKAY;
2693  break;
2694 
2695  case TOO_FEW_DEGREES_OF_FREEDOM:
2696  case INTERNAL_ERROR:
2697  case INVALID_OPTION:
2698  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2699  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_OTHER;
2700  break;
2701 
2702  case OUT_OF_MEMORY:
2703  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2704  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_MEMERR;
2705  break;
2706 
2707  default:
2708  SCIPerrorMessage("Ipopt returned with unknown solution status %d\n", status);
2709  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2710  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_OTHER;
2711  break;
2712  }
2713 
2714  /* if Ipopt reports its solution as locally infeasible or we don't know feasibility, then report the intermediate point with lowest constraint violation, if available */
2715  if( (x == NULL || nlpiproblem->lastsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpiproblem->lastsolstat == SCIP_NLPSOLSTAT_UNKNOWN) && nlpiproblem->lastsolinfeas != SCIP_INVALID )
2716  {
2717  /* if infeasibility of lastsol is not invalid, then lastsol values should exist */
2718  assert(nlpiproblem->lastsolprimals != NULL);
2719  assert(nlpiproblem->lastsoldualcons != NULL);
2720  assert(nlpiproblem->lastsoldualvarlb != NULL);
2721  assert(nlpiproblem->lastsoldualvarub != NULL);
2722 
2723  /* check if lastsol is feasible */
2724  Number constrvioltol;
2725  nlpiproblem->ipopt->Options()->GetNumericValue("acceptable_constr_viol_tol", constrvioltol, "");
2726  if( nlpiproblem->lastsolinfeas <= constrvioltol )
2727  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_FEASIBLE;
2728  else
2729  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2730 
2731  SCIPdebugMessage("drop Ipopt's final point and report intermediate locally %sfeasible solution with infeas %g instead (acceptable: %g)\n",
2732  nlpiproblem->lastsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE ? "in" : "", nlpiproblem->lastsolinfeas, constrvioltol);
2733  }
2734  else
2735  {
2736  assert(x != NULL);
2737  assert(lambda != NULL);
2738  assert(z_L != NULL);
2739  assert(z_U != NULL);
2740 
2741  if( nlpiproblem->lastsolprimals == NULL )
2742  {
2743  assert(nlpiproblem->lastsoldualcons == NULL);
2744  assert(nlpiproblem->lastsoldualvarlb == NULL);
2745  assert(nlpiproblem->lastsoldualvarub == NULL);
2746  BMSallocMemoryArray(&nlpiproblem->lastsolprimals, n);
2747  BMSallocMemoryArray(&nlpiproblem->lastsoldualcons, m);
2748  BMSallocMemoryArray(&nlpiproblem->lastsoldualvarlb, n);
2749  BMSallocMemoryArray(&nlpiproblem->lastsoldualvarub, n);
2750 
2751  if( nlpiproblem->lastsolprimals == NULL || nlpiproblem->lastsoldualcons == NULL ||
2752  nlpiproblem->lastsoldualvarlb == NULL || nlpiproblem->lastsoldualvarub == NULL )
2753  {
2754  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2755  nlpiproblem->lasttermstat = SCIP_NLPTERMSTAT_MEMERR;
2756  return;
2757  }
2758  }
2759 
2760  BMScopyMemoryArray(nlpiproblem->lastsolprimals, x, n);
2761  BMScopyMemoryArray(nlpiproblem->lastsoldualcons, lambda, m);
2762  BMScopyMemoryArray(nlpiproblem->lastsoldualvarlb, z_L, n);
2763  BMScopyMemoryArray(nlpiproblem->lastsoldualvarub, z_U, n);
2764 
2765  if( check_feasibility && cq != NULL )
2766  {
2767  Number constrviol;
2768  Number constrvioltol;
2769 
2770  constrviol = cq->curr_constraint_violation();
2771 
2772  nlpiproblem->ipopt->Options()->GetNumericValue("acceptable_constr_viol_tol", constrvioltol, "");
2773  if( constrviol <= constrvioltol )
2774  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_FEASIBLE;
2775  else
2776  nlpiproblem->lastsolstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2777  }
2778  }
2779 }
2780 
2781 /* Ipopt >= 3.10 do not reveal defines like F77_FUNC.
2782  * However, they install IpLapack.hpp, so Ipopt's Lapack interface is available.
2783  * Thus, we use IpLapack if F77_FUNC is not defined and access Lapack's Dsyev directly if F77_FUNC is defined.
2784  */
2785 #ifndef F77_FUNC
2786 
2787 #include "IpLapack.hpp"
2788 
2789 /** Calls Lapacks Dsyev routine to compute eigenvalues and eigenvectors of a dense matrix.
2790  * It's here, because we use Ipopt's interface to Lapack.
2791  */
2793  SCIP_Bool computeeigenvectors,/**< should also eigenvectors should be computed ? */
2794  int N, /**< dimension */
2795  SCIP_Real* a, /**< matrix data on input (size N*N); eigenvectors on output if computeeigenvectors == TRUE */
2796  SCIP_Real* w /**< buffer to store eigenvalues (size N) */
2797  )
2798 {
2799  int info;
2800 
2801  IpLapackDsyev(computeeigenvectors, N, a, N, w, info);
2802 
2803  if( info != 0 )
2804  {
2805  SCIPerrorMessage("There was an error when calling DSYEV. INFO = %d\n", info);
2806  return SCIP_ERROR;
2807  }
2808 
2809  return SCIP_OKAY;
2810 }
2811 
2812 #else
2813 
2814 extern "C" {
2815  /** LAPACK Fortran subroutine DSYEV */
2816  void F77_FUNC(dsyev,DSYEV)(
2817  char* jobz, /**< 'N' to compute eigenvalues only, 'V' to compute eigenvalues and eigenvectors */
2818  char* uplo, /**< 'U' if upper triangle of A is stored, 'L' if lower triangle of A is stored */
2819  int* n, /**< dimension */
2820  double* A, /**< matrix A on entry; orthonormal eigenvectors on exit, if jobz == 'V' and info == 0; if jobz == 'N', then the matrix data is destroyed */
2821  int* ldA, /**< leading dimension, probably equal to n */
2822  double* W, /**< buffer for the eigenvalues in ascending order */
2823  double* WORK, /**< workspace array */
2824  int* LWORK, /**< length of WORK; if LWORK = -1, then the optimal workspace size is calculated and returned in WORK(1) */
2825  int* info /**< == 0: successful exit; < 0: illegal argument at given position; > 0: failed to converge */
2826  );
2827 }
2828 
2829 /** Calls Lapacks Dsyev routine to compute eigenvalues and eigenvectors of a dense matrix.
2830  * It's here, because Ipopt is linked against Lapack.
2831  */
2833  SCIP_Bool computeeigenvectors,/**< should also eigenvectors should be computed ? */
2834  int N, /**< dimension */
2835  SCIP_Real* a, /**< matrix data on input (size N*N); eigenvectors on output if computeeigenvectors == TRUE */
2836  SCIP_Real* w /**< buffer to store eigenvalues (size N) */
2837  )
2838 {
2839  int INFO;
2840  char JOBZ = computeeigenvectors ? 'V' : 'N';
2841  char UPLO = 'L';
2842  int LDA = N;
2843  double* WORK = NULL;
2844  int LWORK;
2845  double WORK_PROBE;
2846  int i;
2847 
2848  /* First we find out how large LWORK should be */
2849  LWORK = -1;
2850  F77_FUNC(dsyev,DSYEV)(&JOBZ, &UPLO, &N, a, &LDA, w, &WORK_PROBE, &LWORK, &INFO);
2851  if( INFO != 0 )
2852  {
2853  SCIPerrorMessage("There was an error when calling DSYEV. INFO = %d\n", INFO);
2854  return SCIP_ERROR;
2855  }
2856 
2857  LWORK = (int) WORK_PROBE;
2858  assert(LWORK > 0);
2859 
2860  SCIP_ALLOC( BMSallocMemoryArray(&WORK, LWORK) );
2861 
2862  for( i = 0; i < LWORK; ++i )
2863  WORK[i] = i;
2864 
2865  F77_FUNC(dsyev,DSYEV)(&JOBZ, &UPLO, &N, a, &LDA, w, WORK, &LWORK, &INFO);
2866 
2867  BMSfreeMemoryArray(&WORK);
2868 
2869  if( INFO != 0 )
2870  {
2871  SCIPerrorMessage("There was an error when calling DSYEV. INFO = %d\n", INFO);
2872  return SCIP_ERROR;
2873  }
2874 
2875  return SCIP_OKAY;
2876 }
2877 
2878 #endif
2879