Scippy

SCIP

Solving Constraint Integer Programs

nlpi_filtersqp.c
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-2024 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file nlpi_filtersqp.c
26  * @ingroup DEFPLUGINS_NLPI
27  * @brief filterSQP NLP interface
28  * @author Stefan Vigerske
29  *
30  * @todo scaling
31  */
32 
33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34 
35 #include <string.h>
36 #if defined(_WIN32)
37 #include <windows.h>
38 #else
39 #include <sys/time.h>
40 #endif
41 
42 #include "scip/nlpi_filtersqp.h"
43 #include "scip/nlpioracle.h"
44 #include "scip/scip_general.h"
45 #include "scip/scip_message.h"
46 #include "scip/scip_mem.h"
47 #include "scip/scip_numerics.h"
48 #include "scip/scip_nlpi.h"
49 #include "scip/scip_randnumgen.h"
50 #include "scip/scip_solve.h"
51 #include "scip/pub_misc.h"
52 #include "scip/pub_message.h"
53 
54 /* fallback to non-thread version for windows, because pthread does not exist */
55 #if defined(_MSC_VER) && defined(SCIP_THREADSAFE)
56 #undef SCIP_THREADSAFE
57 #endif
58 
59 #ifdef SCIP_THREADSAFE
60 #include <pthread.h>
61 #endif
62 
63 #define NLPI_NAME "filtersqp" /**< short concise name of solver */
64 #define NLPI_DESC "Sequential Quadratic Programming trust region solver by R. Fletcher and S. Leyffer" /**< description of solver */
65 #define NLPI_PRIORITY -1000 /**< priority of NLP solver */
66 
67 #define RANDSEED 26051979 /**< initial random seed */
68 #define MAXPERTURB 0.01 /**< maximal perturbation of bounds in starting point heuristic */
69 #define MAXNRUNS 3 /**< maximal number of FilterSQP calls per NLP solve (several calls if increasing workspace or decreasing eps) */
70 #define WORKSPACEGROWTHFACTOR 2 /**< factor by which to increase workspace */
71 #define MINEPS 1e-14 /**< minimal FilterSQP epsilon */
72 #define OPTTOLFACTOR 0.5 /**< factor to apply to optimality tolerance, because FilterSQP do scaling */
73 
74 /*
75  * Data structures
76  */
77 
78 typedef int fint;
79 typedef double real;
80 typedef long ftnlen;
81 
82 struct SCIP_Time
83 {
84  time_t sec; /**< seconds part of time since epoch */
85  long usec; /**< micro-seconds part of time */
86 };
87 typedef struct SCIP_Time SCIP_TIME;
88 
89 struct SCIP_NlpiData
90 {
91  SCIP_RANDNUMGEN* randnumgen; /**< random number generator, if we have to make up a starting point */
92  SCIP_TIME starttime; /**< time at start of solve */
93 };
94 
95 struct SCIP_NlpiProblem
96 {
97  SCIP* scip; /**< SCIP data structure */
98  SCIP_NLPIORACLE* oracle; /**< Oracle-helper to store and evaluate NLP */
99 
100  int varssize; /**< length of variables-related arrays, if allocated */
101  int conssize; /**< length of constraints-related arrays, if allocated */
102 
103  SCIP_Real* initguess; /**< initial values for primal variables, or NULL if not known, size varssize */
104  SCIP_Bool warmstart; /**< whether we could warmstart the next solve */
105 
106  SCIP_Real* primalvalues; /**< primal values of variables in solution, size varssize */
107  SCIP_Real* consdualvalues; /**< dual values of constraints in solution, size conssize */
108  SCIP_Real* varlbdualvalues; /**< dual values of variable lower bounds in solution, size varssize */
109  SCIP_Real* varubdualvalues; /**< dual values of variable upper bounds in solution, size varssize */
110 
111  SCIP_NLPSOLSTAT solstat; /**< solution status from last NLP solve */
112  SCIP_NLPTERMSTAT termstat; /**< termination status from last NLP solve */
113  SCIP_Real solvetime; /**< time spend for last NLP solve */
114  int niterations; /**< number of iterations for last NLP solve */
115 
116  fint istat[14]; /**< integer solution statistics from last FilterSQP call */
117  real rstat[7]; /**< real solution statistics from last FilterSQP call */
118  real fmin; /**< lower bound on objective value */
119  SCIP_Real maxtime; /**< time limit */
120 
121  /* cached FilterSQP data */
122  real* x; /**< variable values, size varssize */
123  real* c; /**< constraint value, size conssize */
124  real* lam; /**< duals, size varssize + conssize */
125  real* bl; /**< variable lower bounds and constraint lhs, size varssize + conssize */
126  real* bu; /**< variable upper bounds and constraint rhs, size varssize + conssize */
127  real* s; /**< scaling factors, size varssize + conssize */
128  char* cstype; /**< constraint linearity, size conssize */
129  real* a; /**< gradients values, size la[0]-1 */
130  fint* la; /**< gradients indices, size lasize */
131  int lasize; /**< length of la array */
132  fint* hessiannz; /**< nonzero information about Hessian, size hessiannzsize */
133  int hessiannzsize;/**< length of hessiannz array */
134  real* ws; /**< real workspace, size mxwk */
135  fint* lws; /**< integer workspace, size mxiwk */
136  fint mxwk; /**< size of real workspace */
137  fint mxiwk; /**< size of integer workspace */
138  real* evalbuffer; /**< buffer to cache evaluation results before passing it to FilterSQP, size evalbufsize */
139  int evalbufsize; /**< size of evaluation buffer */
140 };
141 
142 /*
143  * Local methods
144  */
145 
146 #ifdef FNAME_LCASE_DECOR
147 # define F77_FUNC(name,NAME) name ## _
148 #endif
149 #ifdef FNAME_UCASE_DECOR
150 # define F77_FUNC(name,NAME) NAME ## _
151 #endif
152 #ifdef FNAME_LCASE_NODECOR
153 # define F77_FUNC(name,NAME) name
154 #endif
155 #ifdef FNAME_UCASE_NODECOR
156 # define F77_FUNC(name,NAME) NAME
157 #endif
158 
159 /** FilterSQP main routine.
160  *
161  * Array a has length nnza, which is the number of nonzeros in the gradient of the objective and the Jacobian.
162  * The first entries of a is the objective gradient, next are the gradients of the constraints.
163  *
164  * Array la has length lamax, which is at least nnza+m+2.
165  * la contains the index information of a row-oriented sparse matrix storage. It stores the number of nonzeros, the column indices, and the row starts:
166  * la[0] must be set to nnza+1.
167  * la[1]..la[nnza] are indices of the variables corresponding to the entries in a (colidx).
168  * la[nnza+1]..la[nnza+1+m] contain the index where each row starts in a and la (rowstart).
169  */
170 void F77_FUNC(filtersqp,FILTERSQP)(
171  fint* n, /**< number of variables */
172  fint* m, /**< number of constraints (excluding simple bounds) */
173  fint* kmax, /**< maximum size of null-space (at most n) */
174  fint* maxa, /**< maximum number of nonzero entries allowed in Jacobian */
175  fint* maxf, /**< maximum size of the filter - typically 100 */
176  fint* mlp, /**< maximum level parameter for resolving degeneracy in bqpd - typically 100 */
177  fint* mxwk, /**< maximum size of real workspace ws */
178  fint* mxiwk, /**< maximum size of integer workspace lws */
179  fint* iprint, /**< print flag: 0 is quiet, higher is more */
180  fint* nout, /**< output channel - 6 for screen */
181  fint* ifail, /**< fail flag and warmstart indicator */
182  real* rho, /**< initial trust-region radius - default 10 */
183  real* x, /**< starting point and final solution (array of length n) */
184  real* c, /**< final values of general constraints (array of length m) */
185  real* f, /**< final objective value */
186  real* fmin, /**< lower bound on objective value (as termination criteria) */
187  real* bl, /**< lower bounds of variables and constraints (array of length n+m) */
188  real* bu, /**< upper bounds of variables and constraints (array of length n+m) */
189  real* s, /**< scaling factors (array of length n+m) */
190  real* a, /**< objective gradient (always dense) and Jacobian (sparse or dense) entries */
191  fint* la, /**< column indices and length of rows of entries in a (if sparse) or leading dimension of a (if dense) */
192  real* ws, /**< real workspace (array of length mxwk) */
193  fint* lws, /**< integer workspace (array of length mxiwk) */
194  real* lam, /**< Lagrangian multipliers of simple bounds and general constraints (array of length n+m) */
195  char* cstype, /**< indicator whether constraint is linear ('L') or nonlinear ('N') (array of length m) */
196  real* user, /**< real workspace passed through to user routines */
197  fint* iuser, /**< integer workspace passed through to user routines */
198  fint* maxiter, /**< iteration limit for SQP solver */
199  fint* istat, /**< integer space for solution statistics (array of length 14) */
200  real* rstat, /**< real space for solution statitics (array of length 7) */
201  ftnlen cstype_len /**< 1 ??? */
202  );
203 
204 void F77_FUNC(objfun,OBJFUN)(real *x, fint *n, real *f, real *user, fint *iuser,
205  fint *errflag);
206 
207 void F77_FUNC(confun,CONFUN)(real *x, fint *n, fint *m, real *c, real *a, fint *la,
208  real *user, fint *iuser, fint *errflag);
209 
210 /* TODO what are the arguments of this function and does it need to be implemented?
211  * it's not in the filterSQP manual, but its an undefined symbol in the filterSQP library
212 void F77_FUNC(objgrad,OBJGRAD)(fint *, fint *, fint *, real *, real *, fint *, fint
213  *, real *, fint *, fint *);
214 */
215 void F77_FUNC(objgrad,OBJGRAD)(void);
216 
217 void F77_FUNC(gradient,GRADIENT)(fint *n, fint *m, fint *mxa, real *x, real *a, fint *la,
218  fint *maxa, real *user, fint *iuser, fint *errflag);
219 
220 void F77_FUNC(hessian,HESSIAN)(real *x, fint *n, fint *m, fint *phase, real *lam,
221  real *ws, fint *lws, real *user, fint *iuser,
222  fint *l_hess, fint *li_hess, fint *errflag);
223 
224 /** common block for problemname */
225 /*lint -esym(754,char_l,pname,*::char_l,*::pname) */
226 extern struct
227 {
228  fint char_l;
229  char pname[10];
230 } F77_FUNC(cpname,CPNAME);
231 /*lint -esym(752,cpname_) */
232 
233 /** common block for Hessian storage set to 0, i.e. NO Hessian */
234 /*lint -esym(754,*::phr,*::phc) */
235 extern struct
236 {
238 } F77_FUNC(hessc,HESSC);
239 /*lint -esym(754,phr,phc) */
240 
241 /** common block for upper bound on filter */
242 extern struct
243 {
245 } F77_FUNC(ubdc,UBDC);
246 
247 /** common block for infinity & epsilon */
248 extern struct
249 {
251 } F77_FUNC(nlp_eps_inf,NLP_EPS_INF);
252 
253 /** common block for printing from QP solver */
254 /*lint -esym(754,*::n_bqpd_calls,*::n_bqpd_prfint) */
255 extern struct
256 {
258 } F77_FUNC(bqpd_count,BQPD_COUNT);
259 /*lint -esym(752,bqpd_count_) */
260 /*lint -esym(754,n_bqpd_calls,n_bqpd_prfint) */
261 
262 /** common for scaling: scale_mode = 0 (none), 1 (variables), 2 (vars+cons) */
263 /*lint -esym(754,*::phe) */
264 extern struct
265 {
267 } F77_FUNC(scalec,SCALEC);
268 /*lint -esym(754,phe) */
269 
270 #ifdef SCIP_THREADSAFE
271 static pthread_mutex_t filtersqpmutex = PTHREAD_MUTEX_INITIALIZER; /*lint !e708*/
272 #endif
273 
274 static
276 {
277  SCIP_TIME t;
278 #ifndef _WIN32
279  struct timeval tp; /*lint !e86*/
280 #endif
281 
282 #ifdef _WIN32
283  t.sec = time(NULL);
284  t.usec = 0;
285 
286 #else
287  (void) gettimeofday(&tp, NULL);
288  t.sec = tp.tv_sec;
289  t.usec = tp.tv_usec;
290 #endif
291 
292  return t;
293 }
294 
295 /* gives time since starttime (in problem) */
296 static
298  SCIP_NLPIDATA* nlpidata /**< NLPI data */
299  )
300 {
301  SCIP_TIME now;
302 
303  assert(nlpidata != NULL);
304 
305  now = gettime();
306 
307  /* now should be after startime */
308  assert(now.sec >= nlpidata->starttime.sec);
309  assert(now.sec > nlpidata->starttime.sec || now.usec >= nlpidata->starttime.usec);
310 
311  return (SCIP_Real)(now.sec - nlpidata->starttime.sec) + 1e-6 * (SCIP_Real)(now.usec - nlpidata->starttime.usec);
312 }
313 
314 static
316  SCIP_NLPIDATA* nlpidata, /**< NLPI data */
317  SCIP_NLPIPROBLEM* nlpiproblem /**< NLPI problem */
318  )
319 {
320  if( nlpiproblem->maxtime == SCIP_REAL_MAX ) /*lint !e777 */
321  return FALSE;
322 
323  return timeelapsed(nlpidata) >= nlpiproblem->maxtime;
324 }
325 
326 /** Objective function evaluation */ /*lint -e{715} */
327 void F77_FUNC(objfun,OBJFUN)(
328  real* x, /**< value of current variables (array of length n) */
329  fint* n, /**< number of variables */
330  real* f, /**< buffer to store value of objective function */
331  real* user, /**< user real workspace */
332  fint* iuser, /**< user integer workspace */
333  fint* errflag /**< set to 1 if arithmetic exception occurs, otherwise 0 */
334  )
335 { /*lint --e{715} */
336  SCIP_NLPIPROBLEM* problem;
337  real val;
338 
339  problem = (SCIP_NLPIPROBLEM*)(void*)iuser;
340  assert(problem != NULL);
341 
342  if( SCIPisSolveInterrupted(problem->scip) || timelimitreached((SCIP_NLPIDATA*)(void*)user, problem) )
343  {
344  SCIPdebugMsg(problem->scip, "interrupted or timelimit reached, issuing arithmetic exception in objfun\n");
345  *errflag = 1;
346  return;
347  }
348 
349  *errflag = 1;
350  if( SCIPnlpiOracleEvalObjectiveValue(problem->scip, problem->oracle, x, &val) == SCIP_OKAY && SCIPisFinite(val) )
351  {
352  *errflag = 0;
353  *f = val;
354  }
355  else
356  {
357  SCIPdebugMsg(problem->scip, "arithmetic exception in objfun\n");
358  }
359 }
360 
361 /** Constraint functions evaluation */ /*lint -e{715} */
362 void F77_FUNC(confun,CONFUN)(
363  real* x, /**< value of current variables (array of length n) */
364  fint* n, /**< number of variables */
365  fint* m, /**< number of constraints */
366  real* c, /**< buffer to store values of constraints (array of length m) */
367  real* a, /**< Jacobian matrix entries */
368  fint* la, /**< Jacobian index information */
369  real* user, /**< user real workspace */
370  fint* iuser, /**< user integer workspace */
371  fint* errflag /**< set to 1 if arithmetic exception occurs, otherwise 0 */
372  )
373 { /*lint --e{715} */
374  SCIP_NLPIPROBLEM* problem;
375  real val;
376  int j;
377 
378  problem = (SCIP_NLPIPROBLEM*)(void*)iuser;
379  assert(problem != NULL);
380 
381  *errflag = 0;
382  for( j = 0; j < *m; ++j )
383  {
384  if( SCIPnlpiOracleEvalConstraintValue(problem->scip, problem->oracle, j, x, &val) != SCIP_OKAY || !SCIPisFinite(val) )
385  {
386  *errflag = 1;
387  SCIPdebugMsg(problem->scip, "arithmetic exception in confun for constraint %d\n", j);
388  break;
389  }
390  c[j] = val;
391  }
392 }
393 
394 /** Objective gradient and Jacobian evaluation
395  *
396  * \note If an arithmetic exception occurred, then the gradients must not be modified.
397  */ /*lint -e{715} */
398 void
399 F77_FUNC(gradient,GRADIENT)(
400  fint* n, /**< number of variables */
401  fint* m, /**< number of constraints */
402  fint* mxa, /**< actual number of entries in a */
403  real* x, /**< value of current variables (array of length n) */
404  real* a, /**< Jacobian matrix entries */
405  fint* la, /**< Jacobian index information: column indices and pointers to start of each row */
406  fint* maxa, /**< maximal size of a */
407  real* user, /**< user real workspace */
408  fint* iuser, /**< user integer workspace */
409  fint* errflag /**< set to 1 if arithmetic exception occurs, otherwise 0 */
410  )
411 { /*lint --e{715} */
412  SCIP_NLPIPROBLEM* problem;
413  SCIP_Real dummy;
414 
415  problem = (SCIP_NLPIPROBLEM*)(void*)iuser;
416  assert(problem != NULL);
417  assert(problem->evalbuffer != NULL);
418  assert(problem->evalbufsize >= *maxa);
419 
420  *errflag = 1;
421 
422  if( SCIPnlpiOracleEvalObjectiveGradient(problem->scip, problem->oracle, x, TRUE, &dummy, problem->evalbuffer) == SCIP_OKAY )
423  {
424  if( SCIPnlpiOracleEvalJacobian(problem->scip, problem->oracle, x, TRUE, NULL, problem->evalbuffer+*n) == SCIP_OKAY )
425  {
426  BMScopyMemoryArray(a, problem->evalbuffer, *maxa);
427  *errflag = 0;
428  }
429  else
430  {
431  SCIPdebugMsg(problem->scip, "arithmetic exception in gradient for constraints\n");
432  }
433  }
434  else
435  {
436  SCIPdebugMsg(problem->scip, "arithmetic exception in gradient for objective\n");
437  }
438 }
439 
440 /* Objective gradient evaluation */
441 /*
442 void F77_FUNC(objgrad,OBJGRAD)(
443  fint*,
444  fint*,
445  fint*,
446  real*,
447  real*,
448  fint*,
449  fint*,
450  real*,
451  fint*,
452  fint*
453  )
454 */
455 void F77_FUNC(objgrad,OBJGRAD)(void)
456 {
457  SCIPerrorMessage("Objgrad not implemented. Should not be called.\n");
458 }
459 
460 /** Hessian of the Lagrangian evaluation
461  *
462  * phase = 1 : Hessian of the Lagrangian without objective Hessian
463  *
464  * phase = 2 : Hessian of the Lagrangian (including objective Hessian)
465  *
466  * \note If an arithmetic exception occurred, then the Hessian must not be modified.
467  */ /*lint -e{715} */
468 void
469 F77_FUNC(hessian,HESSIAN)(
470  real* x, /**< value of current variables (array of length n) */
471  fint* n, /**< number of variables */
472  fint* m, /**< number of constraints */
473  fint* phase, /**< indicates what kind of Hessian matrix is required */
474  real* lam, /**< Lagrangian multipliers (array of length n+m) */
475  real* ws, /**< real workspace for Hessian, passed to Wdotd */
476  fint* lws, /**< integer workspace for Hessian, passed to Wdotd */
477  real* user, /**< user real workspace */
478  fint* iuser, /**< user integer workspace */
479  fint* l_hess, /**< space of Hessian real storage ws. On entry: maximal space allowed, on exit: actual amount used */
480  fint* li_hess, /**< space of Hessian integer storage lws. On entry: maximal space allowed, on exit: actual amount used */
481  fint* errflag /**< set to 1 if arithmetic exception occurs, otherwise 0 */
482  )
483 { /*lint --e{715} */
484  SCIP_NLPIPROBLEM* problem;
485  SCIP_Real* lambda;
486  int nnz;
487  int i;
488 
489  problem = (SCIP_NLPIPROBLEM*)(void*)iuser;
490  assert(problem != NULL);
491  assert(problem->evalbuffer != NULL);
492 
493  nnz = problem->hessiannz[0]-1;
494  assert(problem->evalbufsize >= nnz);
495 
496  *errflag = 1;
497 
498  /* initialize lambda to -lam */
499  BMSallocMemoryArray(&lambda, *m);
500  for( i = 0; i < *m; ++i )
501  lambda[i] = -lam[*n+i];
502 
503  if( SCIPnlpiOracleEvalHessianLag(problem->scip, problem->oracle, x, TRUE, TRUE, (*phase == 1) ? 0.0 : 1.0, lambda, problem->evalbuffer) == SCIP_OKAY )
504  {
505  *l_hess = nnz;
506 
507  BMScopyMemoryArray(ws, problem->evalbuffer, nnz);
508 
509  *errflag = 0;
510 
511  /* copy the complete problem->hessiannz into lws */
512  for( i = 0; i < nnz + *n + 2; ++i )
513  lws[i] = problem->hessiannz[i];
514  *li_hess = nnz + *n + 2;
515  }
516  else
517  {
518  SCIPdebugMsg(problem->scip, "arithmetic exception in hessian\n");
519  }
520 
521  BMSfreeMemoryArray(&lambda);
522 }
523 
524 
525 
526 static
528  SCIP* scip, /**< SCIP data structure */
529  SCIP_NLPIORACLE* oracle, /**< NLPI oracle */
530  fint** la, /**< buffer to store pointer to sparsity structure */
531  int* lasize, /**< buffer to store length of *la array */
532  real** a /**< buffer to store pointer to value buffer */
533  )
534 {
535  const int* offset;
536  const int* col;
537  int nnz; /* number of nonzeros in Jacobian */
538  int nvars;
539  int ncons;
540  int i;
541  int c;
542 
543  assert(la != NULL);
544  assert(lasize != NULL);
545  assert(a != NULL);
546  assert(*la == NULL);
547  assert(*a == NULL);
548 
549  nvars = SCIPnlpiOracleGetNVars(oracle);
550  ncons = SCIPnlpiOracleGetNConstraints(oracle);
551 
552  /* get jacobian sparsity in oracle format: offset are rowstarts in col and col are column indices */
553  SCIP_CALL( SCIPnlpiOracleGetJacobianSparsity(scip, oracle, &offset, &col) );
554  nnz = offset[ncons];
555 
556  /* la stores both column indices (first) and rowstarts (at the end) of the objective gradient and Jacobian
557  * For the objective gradient, always n entries are taken, the Jacobian is stored sparse
558  * la(0) = n+nnz+1 position where rowstarts start in la
559  * la(j) column index of objective gradient or Jacobian row, rowwise
560  * la(la(0)) position of first nonzero element for objective gradient in a()
561  * la(la(0)+i) position of first nonzero element for constraint i gradient in a(), i=1..m
562  * la(la(0)+m+1) = n+nnz first unused position in a
563  * where n = nvars and m = ncons
564  */
565 
566  /* need space for la(0) and column indices and rowstarts (1+ncons+1 for objective, constraints, and end (offsets[ncons])) */
567  *lasize = 1 + (nvars+nnz) + 1+ncons + 1;
568  SCIP_CALL( SCIPallocBlockMemoryArray(scip, la, *lasize) );
569 
570  (*la)[0] = nvars+nnz+1;
571 
572  /* the objective gradient is stored in sparse form */
573  for( i = 0; i < nvars; ++i )
574  (*la)[1+i] = 1+i; /* shift by 1 for Fortran */
575  (*la)[(*la)[0]] = 1; /* objective entries start at the beginning in a, shift by 1 for Fortran */
576 
577  /* column indicies are as given by col */
578  for( i = 0; i < nnz; ++i )
579  (*la)[1+nvars+i] = col[i] + 1; /* shift by 1 for Fortran */
580 
581  /* rowstarts are as given by offset, plus extra for objective gradient */
582  for( c = 0; c <= ncons; ++c )
583  (*la)[(*la)[0]+1+c] = offset[c] + nvars + 1; /* shift by nvars for objective, shift by 1 for Fortran */
584 
585  SCIP_CALL( SCIPallocBlockMemoryArray(scip, a, nvars + nnz) );
586 
587 #ifdef SCIP_MORE_DEBUG /* enable for debugging Jacobian */
588  for( i = 0; i < 1 + (nvars+nnz) + 1+ncons + 1; ++i )
589  printf("la[%2d] = %2d\n", i, (*la)[i]);
590 #endif
591 
592  return SCIP_OKAY;
593 }
594 
595 static
597  SCIP* scip, /**< SCIP data structure */
598  SCIP_NLPIORACLE* oracle, /**< NLPI oracle */
599  fint** la, /**< buffer to store pointer to Hessian sparsity structure */
600  int* lasize /**< buffer to store length of *la array */
601  )
602 {
603  const int* offset;
604  const int* col;
605  int nnz; /* number of nonzeros in Jacobian */
606  int nvars;
607  int i;
608  int v;
609 
610  assert(la != NULL);
611  assert(lasize != NULL);
612  assert(*la == NULL);
613 
614  nvars = SCIPnlpiOracleGetNVars(oracle);
615 
616  /* get Hessian sparsity in oracle format: offset are rowstarts in col and col are column indices */
617  SCIP_CALL( SCIPnlpiOracleGetHessianLagSparsity(scip, oracle, &offset, &col) );
618  nnz = offset[nvars];
619 
620  /* la stores both column indices (first) and rowstarts (at the end) of the (sparse) Hessian
621  * la(0) = nnz+1 position where rowstarts start in la
622  * la(j) column index of Hessian row, rowwise
623  * la(la(0)+i) position of first nonzero element for row i, i = 0..n-1
624  * la(la(0)+n) = nnz first unused position in Hessian
625  * where n = nvars
626  */
627 
628  /* need space for la(0) and column indices and rowstarts
629  * 1 for la(0)
630  * nnz for column indices
631  * nvars for rowstarts
632  * 1 for first unused position
633  */
634  *lasize = 1 + nnz + nvars + 1;
635  SCIP_CALL( SCIPallocBlockMemoryArray(scip, la, *lasize) );
636 
637  (*la)[0] = nnz+1;
638 
639  /* column indicies are as given by col */
640  for( i = 0; i < nnz; ++i )
641  (*la)[1+i] = col[i] + 1; /* shift by 1 for Fortran */
642 
643  /* rowstarts are as given by offset */
644  for( v = 0; v <= nvars; ++v )
645  (*la)[(*la)[0]+v] = offset[v] + 1; /* shift by 1 for Fortran */
646 
647  F77_FUNC(hessc,HESSC).phl = 1;
648 
649 #ifdef SCIP_MORE_DEBUG /* enable for debugging Hessian */
650  for( i = 0; i < 1 + nnz + nvars + 1; ++i )
651  printf("lw[%2d] = %2d\n", i, (*la)[i]);
652 #endif
653 
654  return SCIP_OKAY;
655 }
656 
657 /** setup starting point for FilterSQP */
658 static
660  SCIP_NLPIDATA* data, /**< NLPI data */
661  SCIP_NLPIPROBLEM* problem, /**< NLPI problem */
662  real* x, /**< array to store initial values */
663  SCIP_Bool* success /**< whether we could setup a point in which functions could be evaluated */
664  )
665 {
666  int i;
667  int n;
668  SCIP_Real val;
669 
670  assert(data != NULL);
671  assert(problem != NULL);
672  assert(x != NULL);
673  assert(success != NULL);
674 
675  n = SCIPnlpiOracleGetNVars(problem->oracle);
676 
677  /* setup starting point */
678  if( problem->initguess != NULL )
679  {
680  for( i = 0; i < n; ++i )
681  x[i] = problem->initguess[i];
682  }
683  else
684  {
685  SCIP_Real lb;
686  SCIP_Real ub;
687 
688  SCIPdebugMsg(problem->scip, "FilterSQP started without initial primal values; make up something by projecting 0 onto variable bounds and perturb\n");
689 
690  if( data->randnumgen == NULL )
691  {
692  SCIP_CALL( SCIPcreateRandom(problem->scip, &data->randnumgen, RANDSEED, TRUE) );
693  }
694 
695  for( i = 0; i < n; ++i )
696  {
697  lb = SCIPnlpiOracleGetVarLbs(problem->oracle)[i];
698  ub = SCIPnlpiOracleGetVarUbs(problem->oracle)[i];
699  if( lb > 0.0 )
700  x[i] = SCIPrandomGetReal(data->randnumgen, lb, lb + MAXPERTURB*MIN(1.0, ub-lb));
701  else if( ub < 0.0 )
702  x[i] = SCIPrandomGetReal(data->randnumgen, ub - MAXPERTURB*MIN(1.0, ub-lb), ub);
703  else
704  x[i] = SCIPrandomGetReal(data->randnumgen, MAX(lb, -MAXPERTURB*MIN(1.0, ub-lb)), MIN(ub, MAXPERTURB*MIN(1.0, ub-lb)));
705  }
706  }
707 
708  /* check whether objective and constraints can be evaluated and differentiated once in starting point
709  * NOTE: this does not check whether hessian can be computed!
710  */
711  *success = SCIPnlpiOracleEvalObjectiveValue(problem->scip, problem->oracle, x, &val) == SCIP_OKAY && SCIPisFinite(val);
712  *success &= SCIPnlpiOracleEvalObjectiveGradient(problem->scip, problem->oracle, x, FALSE, &val, problem->evalbuffer) == SCIP_OKAY; /*lint !e514*/
713  i = 0;
714  for( ; *success && i < SCIPnlpiOracleGetNConstraints(problem->oracle); ++i )
715  *success = SCIPnlpiOracleEvalConstraintValue(problem->scip, problem->oracle, i, x, &val) == SCIP_OKAY && SCIPisFinite(val);
716  *success &= SCIPnlpiOracleEvalJacobian(problem->scip, problem->oracle, x, FALSE, NULL, problem->evalbuffer) == SCIP_OKAY; /*lint !e514*/
717 
718  if( !*success )
719  {
720  SCIPdebugMsg(problem->scip, "could not evaluate or constraint %d in %s starting point or Jacobian not available\n", i-1, problem->initguess != NULL ? "provided" : "made up");
721 
722  if( problem->initguess != NULL )
723  {
724  /* forget given starting point and try to make up our own */
725  SCIPfreeBlockMemoryArray(problem->scip, &problem->initguess, problem->varssize);
726  SCIP_CALL( setupStart(data, problem, x, success) );
727  }
728  }
729 
730  return SCIP_OKAY;
731 }
732 
733 /** sets the solstat and termstat to unknown and other, resp. */
734 static
736  SCIP_NLPIPROBLEM* problem /**< data structure of problem */
737  )
738 {
739  assert(problem != NULL);
740 
741  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
742  problem->termstat = SCIP_NLPTERMSTAT_OTHER;
743 }
744 
745 /** store NLP solve parameters in nlpiproblem */
746 static
748  SCIP* scip, /**< SCIP data structure */
749  SCIP_NLPIPROBLEM* nlpiproblem, /**< NLP */
750  const SCIP_NLPPARAM param /**< solve parameters */
751  )
752 {
753  assert(scip != NULL);
754  assert(nlpiproblem != NULL);
755 
756  if( param.fastfail )
757  {
758  SCIPdebugMsg(scip, "fast fail parameter not supported by FilterSQP interface yet. Ignored.\n");
759  }
760 
761  nlpiproblem->fmin = param.lobjlimit;
762 
763  nlpiproblem->maxtime = param.timelimit;
764 
765  return SCIP_OKAY;
766 }
767 
768 /** processes results from FilterSQP call */
769 static
771  SCIP_NLPIDATA* nlpidata, /**< NLPI data */
772  SCIP_NLPIPROBLEM* problem, /**< NLPI problem */
773  fint ifail, /**< fail flag from FilterSQP call */
774  SCIP_Real feastol, /**< feasibility tolerance */
775  SCIP_Real opttol, /**< optimality tolerance */
776  real* x, /**< primal solution values from FilterSQP call, or NULL if stopped before filtersqp got called */
777  real* lam /**< dual solution values from FilterSQP call, or NULL if stopped before filtersqp got called */
778  )
779 {
780  int i;
781  int nvars;
782  int ncons;
783 
784  assert(problem != NULL);
785  assert(ifail >= 0);
786  assert((x != NULL) == (lam != NULL));
787 
788  problem->solvetime = timeelapsed(nlpidata);
789 
790  nvars = SCIPnlpiOracleGetNVars(problem->oracle);
791  ncons = SCIPnlpiOracleGetNConstraints(problem->oracle);
792 
793  if( ifail <= 8 && x != NULL )
794  {
795  /* FilterSQP terminated somewhat normally -> store away solution */
796 
797  /* make sure we have memory for solution */
798  if( problem->primalvalues == NULL )
799  {
800  assert(problem->varssize >= nvars); /* ensured in nlpiAddVariables */
801  assert(problem->conssize >= ncons); /* ensured in nlpiAddConstraints */
802  assert(problem->consdualvalues == NULL); /* if primalvalues == NULL, then also consdualvalues should be NULL */
803  assert(problem->varlbdualvalues == NULL); /* if primalvalues == NULL, then also varlbdualvalues should be NULL */
804  assert(problem->varubdualvalues == NULL); /* if primalvalues == NULL, then also varubdualvalues should be NULL */
805 
806  SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->primalvalues, problem->varssize) );
807  SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->consdualvalues, problem->conssize) );
808  SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->varlbdualvalues, problem->varssize) );
809  SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->varubdualvalues, problem->varssize) );
810  }
811  else
812  {
813  assert(problem->consdualvalues != NULL);
814  assert(problem->varlbdualvalues != NULL);
815  assert(problem->varubdualvalues != NULL);
816  }
817 
818  for( i = 0; i < nvars; ++i )
819  {
820  problem->primalvalues[i] = x[i];
821 
822  /* if dual from FilterSQP is positive, then it belongs to the lower bound, otherwise to the upper bound */
823  problem->varlbdualvalues[i] = MAX(0.0, lam[i]);
824  problem->varubdualvalues[i] = MAX(0.0, -lam[i]);
825  }
826 
827  /* duals from FilterSQP are negated */
828  for( i = 0; i < ncons; ++i )
829  problem->consdualvalues[i] = -lam[nvars + i];
830  }
831 
832  /* translate ifail to solution and termination status and decide whether we could warmstart next */
833  problem->warmstart = FALSE;
834  switch( ifail )
835  {
836  case 0: /* successful run, solution found */
837  assert(problem->rstat[4] <= feastol); /* should be feasible */
838  problem->solstat = (problem->rstat[0] <= opttol ? SCIP_NLPSOLSTAT_LOCOPT : SCIP_NLPSOLSTAT_FEASIBLE);
839  problem->termstat = SCIP_NLPTERMSTAT_OKAY;
840  problem->warmstart = TRUE;
841  break;
842  case 1: /* unbounded, feasible point with f(x) <= fmin */
843  assert(problem->rstat[4] <= feastol); /* should be feasible */
845  if( problem->fmin == SCIP_REAL_MIN ) /*lint !e777*/
846  problem->termstat = SCIP_NLPTERMSTAT_OKAY; /* fmin was not set */
847  else
849  break;
850  case 2: /* linear constraints are inconsistent */
852  problem->termstat = SCIP_NLPTERMSTAT_OKAY;
853  break;
854  case 3: /* (locally) nonlinear infeasible, minimal-infeasible solution found */
855  /* problem->solstat = (problem->rstat[0] <= opttol ? SCIP_NLPSOLSTAT_LOCINFEASIBLE : SCIP_NLPSOLSTAT_UNKNOWN); */
856  problem->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE; /* TODO FilterSQP does not set rstat[0] in this case, assuming local infeasibility is valid */
857  problem->termstat = SCIP_NLPTERMSTAT_OKAY;
858  problem->warmstart = TRUE;
859  break;
860  case 4: /* terminate at point with h(x) <= eps (constraint violation below epsilon) but QP infeasible */
861  assert(problem->rstat[4] <= feastol); /* should be feasible */
864  problem->warmstart = TRUE;
865  break;
866  case 5: /* termination with rho < eps (trust region radius below epsilon) */
867  if( problem->rstat[4] <= feastol )
869  else
870  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
872  problem->warmstart = TRUE;
873  break;
874  case 6: /* termination with iter > max_iter */
875  if( problem->rstat[4] <= feastol )
877  else
878  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
880  problem->warmstart = TRUE;
881  break;
882  case 7: /* crash in user routine (IEEE error) could not be resolved, or timelimit reached, or interrupted */
883  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
884  if( problem->solvetime >= problem->maxtime )
885  {
887  problem->warmstart = TRUE;
888  }
889  else if( SCIPisSolveInterrupted(problem->scip) )
891  else
893  break;
894  case 8: /* unexpect ifail from QP solver */
895  if( problem->rstat[4] <= feastol )
897  else
898  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
899  problem->termstat = SCIP_NLPTERMSTAT_OTHER;
900  break;
901  case 9: /* not enough REAL workspace */
902  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
904  break;
905  case 10: /* not enough INTEGER workspace */
906  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
908  break;
909  default:
910  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
911  problem->termstat = SCIP_NLPTERMSTAT_OTHER;
912  break;
913  }
914 
915  return SCIP_OKAY;
916 }
917 
918 
919 /*
920  * Callback methods of NLP solver interface
921  */
922 
923 /** copy method of NLP interface (called when SCIP copies plugins) */
924 static
925 SCIP_DECL_NLPICOPY(nlpiCopyFilterSQP)
926 {
928 
929  return SCIP_OKAY; /*lint !e527*/
930 } /*lint !e715*/
931 
932 /** destructor of NLP interface to free nlpi data */
933 static
934 SCIP_DECL_NLPIFREE(nlpiFreeFilterSQP)
935 {
936  assert(nlpi != NULL);
937  assert(nlpidata != NULL);
938  assert(*nlpidata != NULL);
939 
940  if( (*nlpidata)->randnumgen != NULL )
941  {
942  SCIPfreeRandom(scip, &(*nlpidata)->randnumgen);
943  }
944 
945  SCIPfreeBlockMemory(scip, nlpidata);
946  assert(*nlpidata == NULL);
947 
948  return SCIP_OKAY;
949 }
950 
951 /** creates a problem instance */
952 static
953 SCIP_DECL_NLPICREATEPROBLEM(nlpiCreateProblemFilterSQP)
954 {
955  assert(nlpi != NULL);
956  assert(problem != NULL);
957 
959  (*problem)->scip = scip;
960 
961  SCIP_CALL( SCIPnlpiOracleCreate(scip, &(*problem)->oracle) );
962  SCIP_CALL( SCIPnlpiOracleSetProblemName(scip, (*problem)->oracle, name) );
963 
964  (*problem)->fmin = SCIP_REAL_MIN;
965  (*problem)->maxtime = SCIP_REAL_MAX;
966 
967  invalidateSolution(*problem);
968 
969  return SCIP_OKAY; /*lint !e527*/
970 } /*lint !e715*/
971 
972 /** free a problem instance */
973 static
974 SCIP_DECL_NLPIFREEPROBLEM(nlpiFreeProblemFilterSQP)
975 {
976  assert(nlpi != NULL);
977  assert(problem != NULL);
978  assert(*problem != NULL);
979 
980  if( (*problem)->oracle != NULL )
981  {
982  SCIP_CALL( SCIPnlpiOracleFree(scip, &(*problem)->oracle) );
983  }
984 
985  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->initguess, (*problem)->varssize);
986  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->primalvalues, (*problem)->varssize);
987  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->consdualvalues, (*problem)->conssize);
988  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->varlbdualvalues, (*problem)->varssize);
989  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->varubdualvalues, (*problem)->varssize);
990  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->cstype, (*problem)->conssize);
991  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->s, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
992  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->bu, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
993  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->bl, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
994  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->x, (*problem)->varssize);
995  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->c, (*problem)->conssize);
996  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->lam, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
997  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->a, (*problem)->la != NULL ? (*problem)->la[0]-1 : 0);
998  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->la, (*problem)->lasize);
999  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->hessiannz, (*problem)->hessiannzsize);
1000  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->lws, (*problem)->mxiwk);
1001  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->ws, (*problem)->mxwk);
1002  SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->evalbuffer, (*problem)->evalbufsize);
1003 
1004  SCIPfreeBlockMemory(scip, problem);
1005  assert(*problem == NULL);
1006 
1007  return SCIP_OKAY;
1008 } /*lint !e715*/
1009 
1010 /** add variables */
1011 static
1012 SCIP_DECL_NLPIADDVARS(nlpiAddVarsFilterSQP)
1013 {
1014  int oldnvars;
1015 
1016  assert(nlpi != NULL);
1017  assert(problem != NULL);
1018  assert(problem->oracle != NULL);
1019 
1020  oldnvars = SCIPnlpiOracleGetNVars(problem->oracle);
1021 
1022  SCIP_CALL( SCIPnlpiOracleAddVars(scip, problem->oracle, nvars, lbs, ubs, varnames) );
1023 
1024  SCIPfreeBlockMemoryArrayNull(scip, &problem->initguess, problem->varssize);
1025  invalidateSolution(problem);
1026  problem->warmstart = FALSE;
1027 
1028  /* increase variables-related arrays in problem, if necessary */
1029  if( problem->varssize < SCIPnlpiOracleGetNVars(problem->oracle) )
1030  {
1031  int newsize = SCIPcalcMemGrowSize(scip, SCIPnlpiOracleGetNVars(problem->oracle));
1032 
1033  if( problem->primalvalues != NULL )
1034  {
1035  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->primalvalues, problem->varssize, newsize) );
1036  }
1037 
1038  if( problem->varlbdualvalues != NULL )
1039  {
1040  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->varlbdualvalues, problem->varssize, newsize) );
1041  }
1042 
1043  if( problem->varubdualvalues != NULL )
1044  {
1045  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->varubdualvalues, problem->varssize, newsize) );
1046  }
1047 
1048  if( problem->x != NULL )
1049  {
1050  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->x, problem->varssize, newsize) );
1051  }
1052 
1053  if( problem->lam != NULL )
1054  {
1055  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->lam, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1056  }
1057 
1058  if( problem->bl != NULL )
1059  {
1060  assert(problem->bu != NULL);
1061  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bl, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1062  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bu, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1063  }
1064 
1065  if( problem->s != NULL )
1066  {
1067  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->s, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1068  }
1069 
1070  problem->varssize = newsize;
1071  }
1072 
1073  /* update variable bounds in FilterSQP data */
1074  if( problem->bl != NULL )
1075  {
1076  int i;
1077  int nconss;
1078 
1079  nconss = SCIPnlpiOracleGetNConstraints(problem->oracle);
1080 
1081  /* bl and bu have first variable bounds and then constraint sides
1082  * copy the constraint sides to their new position before putting in the new variable bounds
1083  */
1084  for( i = nconss-1; i >= 0; --i )
1085  {
1086  problem->bl[oldnvars+nvars+i] = problem->bl[oldnvars+i];
1087  problem->bu[oldnvars+nvars+i] = problem->bu[oldnvars+i];
1088  }
1089 
1090  /* set bounds of new variable */
1091  for( i = 0; i < nvars; ++i )
1092  {
1093  problem->bl[oldnvars+i] = lbs[i];
1094  problem->bu[oldnvars+i] = ubs[i];
1095  }
1096  }
1097 
1098  /* gradients information is out of date now (objective gradient is stored in dense form) */
1099  SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1100  SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1101 
1102  /* Hessian information is out of date now (no new entries in Hessian, but also empty cols shows up in sparsity info) */
1103  SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1104 
1105  return SCIP_OKAY;
1106 } /*lint !e715*/
1107 
1108 
1109 /** add constraints */
1110 static
1111 SCIP_DECL_NLPIADDCONSTRAINTS(nlpiAddConstraintsFilterSQP)
1112 {
1113  int oldnconss;
1114 
1115  assert(nlpi != NULL);
1116  assert(problem != NULL);
1117  assert(problem->oracle != NULL);
1118 
1119  oldnconss = SCIPnlpiOracleGetNConstraints(problem->oracle);
1120 
1121  SCIP_CALL( SCIPnlpiOracleAddConstraints(scip, problem->oracle, nconss, lhss, rhss, nlininds, lininds, linvals, exprs, names) );
1122 
1123  invalidateSolution(problem);
1124  problem->warmstart = FALSE;
1125 
1126  /* increase constraints-related arrays in problem, if necessary */
1127  if( SCIPnlpiOracleGetNConstraints(problem->oracle) > problem->conssize )
1128  {
1129  int newsize = SCIPcalcMemGrowSize(scip, SCIPnlpiOracleGetNConstraints(problem->oracle));
1130 
1131  if( problem->consdualvalues != NULL )
1132  {
1133  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->consdualvalues, problem->conssize, newsize) );
1134  }
1135 
1136  if( problem->c != NULL )
1137  {
1138  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->c, problem->conssize, newsize) );
1139  }
1140 
1141  if( problem->lam != NULL )
1142  {
1143  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->lam, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1144  }
1145 
1146  if( problem->bl != NULL )
1147  {
1148  assert(problem->bu != NULL);
1149  assert(problem->cstype != NULL);
1150  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bl, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1151  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bu, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1152  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->cstype, problem->conssize, newsize) );
1153  }
1154 
1155  if( problem->s != NULL )
1156  {
1157  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->s, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1158  }
1159 
1160  problem->conssize = newsize;
1161  }
1162 
1163  /* update constraint sides and type in FilterSQP data */
1164  if( problem->bl != NULL )
1165  {
1166  int i;
1167  int nvars;
1168 
1169  nvars = SCIPnlpiOracleGetNVars(problem->oracle);
1170 
1171  for( i = 0; i < nconss; ++i )
1172  {
1173  problem->bl[nvars+oldnconss+i] = lhss[i];
1174  problem->bu[nvars+oldnconss+i] = rhss[i];
1175  problem->cstype[oldnconss+i] = SCIPnlpiOracleIsConstraintNonlinear(problem->oracle, oldnconss+i) ? 'N' : 'L';
1176  }
1177  }
1178 
1179  /* gradients information is out of date now */
1180  SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1181  SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1182 
1183  /* Hessian information is out of date now */
1184  SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1185 
1186  return SCIP_OKAY;
1187 } /*lint !e715*/
1188 
1189 /** sets or overwrites objective, a minimization problem is expected */
1190 static
1191 SCIP_DECL_NLPISETOBJECTIVE( nlpiSetObjectiveFilterSQP )
1192 {
1193  assert(nlpi != NULL);
1194  assert(problem != NULL);
1195  assert(problem->oracle != NULL);
1196 
1197  SCIP_CALL( SCIPnlpiOracleSetObjective(scip, problem->oracle,
1198  constant, nlins, lininds, linvals, expr) );
1199 
1200  invalidateSolution(problem);
1201 
1202  /* gradients info (la,a) should still be ok, as objective gradient is stored in dense form */
1203 
1204  /* Hessian information is out of date now */
1205  SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1206 
1207  return SCIP_OKAY;
1208 } /*lint !e715*/
1209 
1210 /** change variable bounds */
1211 static
1212 SCIP_DECL_NLPICHGVARBOUNDS(nlpiChgVarBoundsFilterSQP)
1213 {
1214  assert(nlpi != NULL);
1215  assert(problem != NULL);
1216  assert(problem->oracle != NULL);
1217 
1218  SCIP_CALL( SCIPnlpiOracleChgVarBounds(scip, problem->oracle, nvars, indices, lbs, ubs) );
1219 
1220  invalidateSolution(problem);
1221 
1222  /* update bounds in FilterSQP data */
1223  if( problem->bl != NULL )
1224  {
1225  int i;
1226 
1227  for( i = 0; i < nvars; ++i )
1228  {
1229  problem->bl[indices[i]] = lbs[i];
1230  problem->bu[indices[i]] = ubs[i];
1231  }
1232  }
1233 
1234  return SCIP_OKAY;
1235 } /*lint !e715*/
1236 
1237 /** change constraint bounds */
1238 static
1239 SCIP_DECL_NLPICHGCONSSIDES(nlpiChgConsSidesFilterSQP)
1240 {
1241  assert(nlpi != NULL);
1242  assert(problem != NULL);
1243  assert(problem->oracle != NULL);
1244 
1245  SCIP_CALL( SCIPnlpiOracleChgConsSides(scip, problem->oracle, nconss, indices, lhss, rhss) );
1246 
1247  invalidateSolution(problem);
1248 
1249  /* update constraint sense in FilterSQP data */
1250  if( problem->bl != NULL )
1251  {
1252  int i;
1253  int nvars;
1254 
1255  nvars = SCIPnlpiOracleGetNVars(problem->oracle);
1256 
1257  for( i = 0; i < nconss; ++i )
1258  {
1259  problem->bl[nvars+indices[i]] = lhss[i];
1260  problem->bu[nvars+indices[i]] = rhss[i];
1261  }
1262  }
1263 
1264  return SCIP_OKAY;
1265 } /*lint !e715*/
1266 
1267 /** delete a set of variables */
1268 static
1269 SCIP_DECL_NLPIDELVARSET(nlpiDelVarSetFilterSQP)
1270 {
1271  assert(nlpi != NULL);
1272  assert(problem != NULL);
1273  assert(problem->oracle != NULL);
1274 
1275  SCIP_CALL( SCIPnlpiOracleDelVarSet(scip, problem->oracle, dstats) );
1276 
1277  /* @TODO keep initguess and bl, bu for remaining variables? */
1278 
1279  SCIPfreeBlockMemoryArrayNull(scip, &problem->initguess, problem->varssize);
1280  invalidateSolution(problem);
1281  problem->warmstart = FALSE;
1282 
1283  SCIPfreeBlockMemoryArrayNull(scip, &problem->bl, problem->varssize + problem->conssize); /*lint !e776 */
1284  SCIPfreeBlockMemoryArrayNull(scip, &problem->bu, problem->varssize + problem->conssize); /*lint !e776 */
1285  SCIPfreeBlockMemoryArrayNull(scip, &problem->cstype, problem->conssize); /* because we assume that cstype is allocated iff bl is allocated */
1286 
1287  /* gradients information is out of date now (objective gradient is stored in dense form) */
1288  SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1289  SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1290 
1291  /* Hessian information is out of date now */
1292  SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1293 
1294  return SCIP_OKAY;
1295 } /*lint !e715*/
1296 
1297 /** delete a set of constraints */
1298 static
1299 SCIP_DECL_NLPIDELCONSSET(nlpiDelConstraintSetFilterSQP)
1300 {
1301  assert(nlpi != NULL);
1302  assert(problem != NULL);
1303  assert(problem->oracle != NULL);
1304 
1305  SCIP_CALL( SCIPnlpiOracleDelConsSet(scip, problem->oracle, dstats) );
1306 
1307  invalidateSolution(problem);
1308  problem->warmstart = FALSE;
1309 
1310  SCIPfreeBlockMemoryArrayNull(scip, &problem->bl, problem->varssize + problem->conssize); /*lint !e776 */
1311  SCIPfreeBlockMemoryArrayNull(scip, &problem->bu, problem->varssize + problem->conssize); /*lint !e776 */
1312  SCIPfreeBlockMemoryArrayNull(scip, &problem->cstype, problem->conssize); /* because we assume that cstype is allocated iff bl is allocated */
1313 
1314  /* gradients information is out of date now */
1315  SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1316  SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1317 
1318  /* Hessian information is out of date now */
1319  SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1320 
1321  return SCIP_OKAY;
1322 } /*lint !e715*/
1323 
1324 /** changes (or adds) linear coefficients in a constraint or objective */
1325 static
1326 SCIP_DECL_NLPICHGLINEARCOEFS(nlpiChgLinearCoefsFilterSQP)
1327 {
1328  assert(nlpi != NULL);
1329  assert(problem != NULL);
1330  assert(problem->oracle != NULL);
1331 
1332  SCIP_CALL( SCIPnlpiOracleChgLinearCoefs(scip, problem->oracle, idx, nvals, varidxs, vals) );
1333 
1334  invalidateSolution(problem);
1335 
1336  /* gradients information (la,a) may have changed if elements were added or removed
1337  * (we only care that sparsity doesn't change, not about actual values in a)
1338  * TODO free only if coefficients were added or removed (SCIPnlpiOracleChgLinearCoefs() could give feedback)
1339  */
1340  SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1341  SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1342 
1343  /* Hessian information should still be ok */
1344 
1345  return SCIP_OKAY;
1346 } /*lint !e715*/
1347 
1348 /** replaces the expression of a constraint or objective */
1349 static
1350 SCIP_DECL_NLPICHGEXPR(nlpiChgExprFilterSQP)
1351 {
1352  assert(nlpi != NULL);
1353  assert(problem != NULL);
1354  assert(problem->oracle != NULL);
1355 
1356  SCIP_CALL( SCIPnlpiOracleChgExpr(scip, problem->oracle, idxcons, expr) );
1357 
1358  invalidateSolution(problem);
1359 
1360  /* update constraint linearity in FilterSQP data, as we might have changed from linear to nonlinear now */
1361  if( problem->cstype != NULL && idxcons >= 0 )
1362  problem->cstype[idxcons] = expr != NULL ? 'N' : 'L';
1363 
1364  /* gradients information (la,a) may have changed */
1365  SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1366  SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1367 
1368  /* Hessian information may have changed */
1369  SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1370 
1371  return SCIP_OKAY;
1372 } /*lint !e715*/
1373 
1374 /** change the constant offset in the objective */
1375 static
1376 SCIP_DECL_NLPICHGOBJCONSTANT(nlpiChgObjConstantFilterSQP)
1377 {
1378  assert(nlpi != NULL);
1379  assert(problem != NULL);
1380  assert(problem->oracle != NULL);
1381 
1382  SCIP_CALL( SCIPnlpiOracleChgObjConstant(scip, problem->oracle, objconstant) );
1383 
1384  invalidateSolution(problem);
1385 
1386  return SCIP_OKAY;
1387 } /*lint !e715*/
1388 
1389 /** sets initial guess for primal variables */
1390 static
1391 SCIP_DECL_NLPISETINITIALGUESS(nlpiSetInitialGuessFilterSQP)
1392 {
1393  assert(nlpi != NULL);
1394  assert(problem != NULL);
1395  assert(problem->oracle != NULL);
1396 
1397  if( primalvalues != NULL )
1398  {
1399  if( problem->initguess == NULL )
1400  {
1401  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->initguess, problem->varssize) );
1402  }
1403  assert(SCIPnlpiOracleGetNVars(problem->oracle) <= problem->varssize);
1404  BMScopyMemoryArray(problem->initguess, primalvalues, SCIPnlpiOracleGetNVars(problem->oracle));
1405  }
1406  else
1407  {
1408  SCIPfreeBlockMemoryArrayNull(scip, &problem->initguess, problem->varssize);
1409  }
1410 
1411  return SCIP_OKAY;
1412 } /*lint !e715*/
1413 
1414 /** tries to solve NLP */
1415 static
1416 SCIP_DECL_NLPISOLVE(nlpiSolveFilterSQP)
1417 {
1418  SCIP_NLPIDATA* data;
1419  SCIP_Bool success;
1420  fint n;
1421  fint m;
1422  fint kmax;
1423  fint maxa;
1424  fint maxf;
1425  fint mlp;
1426  fint lh1;
1427  fint nout;
1428  fint ifail;
1429  fint maxiter;
1430  fint iprint;
1431  real rho;
1432  real f;
1433  real* user;
1434  fint* iuser;
1435  ftnlen cstype_len = 1;
1436  fint minmxwk;
1437  fint minmxiwk;
1438  int nruns;
1439  int i;
1440 
1441  SCIPdebugMsg(scip, "solve with parameters " SCIP_NLPPARAM_PRINT(param));
1442 
1443  data = SCIPnlpiGetData(nlpi);
1444  assert(data != NULL);
1445 
1446  SCIP_CALL( SCIPnlpiOracleResetEvalTime(scip, problem->oracle) );
1447 
1448  if( param.timelimit == 0.0 )
1449  {
1450  /* there is nothing we can do if we are not given any time */
1451  problem->niterations = 0;
1452  problem->solvetime = 0.0;
1453  problem->termstat = SCIP_NLPTERMSTAT_TIMELIMIT;
1454  problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1455 
1456  return SCIP_OKAY;
1457  }
1458 
1459  /* start measuring time */
1460  data->starttime = gettime();
1461 
1462  SCIP_CALL( handleNlpParam(scip, problem, param) );
1463 
1464  iprint = param.verblevel;
1465 
1466  /* if warmstart parameter is disabled, then we will not warmstart */
1467  if( !param.warmstart )
1468  problem->warmstart = FALSE;
1469 
1470  n = SCIPnlpiOracleGetNVars(problem->oracle);
1471  m = SCIPnlpiOracleGetNConstraints(problem->oracle);
1472  kmax = n; /* maximal nullspace dimension */
1473  maxf = 100; /* maximal filter length */
1474  mlp = 100; /* maximum level of degeneracy */
1475 
1476  /* TODO eventually, the output should be redirected to the message handler,
1477  * but even to just redirect to some other file, we would have to open the output-unit in Fortran
1478  */
1479  nout = 6; /* output to stdout for now */
1480  ifail = problem->warmstart ? -1 : 0; /* -1 for warmstart, otherwise 0 */
1481  rho = 10.0; /* initial trust-region radius */
1482 
1483  user = (real*)data;
1484  iuser = (fint*)problem;
1485  if( problem->warmstart ) /* if warmstart, then need to keep istat[0] */
1486  memset(problem->istat+1, 0, sizeof(problem->istat)-sizeof(*problem->istat));
1487  else
1488  memset(problem->istat, 0, sizeof(problem->istat));
1489  memset(problem->rstat, 0, sizeof(problem->rstat));
1490  problem->niterations = 0;
1491 
1492  if( problem->x == NULL )
1493  {
1494  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->x, problem->varssize) );
1495  }
1496  if( problem->c == NULL )
1497  {
1498  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->c, problem->conssize) );
1499  }
1500  if( problem->lam == NULL )
1501  {
1502  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &problem->lam, problem->varssize + problem->conssize) ); /*lint !e776 */
1503  }
1504  else
1505  {
1506  BMSclearMemoryArray(problem->lam, problem->varssize + problem->conssize);
1507  }
1508  if( problem->s == NULL )
1509  {
1510  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->s, problem->varssize + problem->conssize) );
1511  }
1512 
1513  if( problem->la == NULL )
1514  {
1515  /* allocate la, a and initialize la for Objective Gradient and Jacobian */
1516  SCIP_CALL( setupGradients(scip, problem->oracle, &problem->la, &problem->lasize, &problem->a) );
1517  }
1518  /* maximal number entries in a = nvars+nnz */
1519  maxa = problem->la[0]-1;
1520 
1521  if( problem->hessiannz == NULL )
1522  {
1523  /* allocate and initialize problem->hessiannz for Hessian */
1524  SCIP_CALL( setupHessian(scip, problem->oracle, &problem->hessiannz, &problem->hessiannzsize) );
1525  }
1526 
1527  /* setup variable bounds, constraint sides, and constraint types */
1528  if( problem->bl == NULL )
1529  {
1530  assert(problem->bu == NULL);
1531  assert(problem->cstype == NULL);
1532 
1533  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->bl, problem->varssize + problem->conssize) );
1534  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->bu, problem->varssize + problem->conssize) );
1535  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->cstype, problem->conssize) );
1536 
1537  BMScopyMemoryArray(problem->bl, SCIPnlpiOracleGetVarLbs(problem->oracle), n);
1538  BMScopyMemoryArray(problem->bu, SCIPnlpiOracleGetVarUbs(problem->oracle), n);
1539  for( i = 0; i < m; ++i )
1540  {
1541  problem->bl[n+i] = SCIPnlpiOracleGetConstraintLhs(problem->oracle, i);
1542  problem->bu[n+i] = SCIPnlpiOracleGetConstraintRhs(problem->oracle, i);
1543  problem->cstype[i] = SCIPnlpiOracleIsConstraintNonlinear(problem->oracle, i) ? 'N' : 'L';
1544  }
1545  }
1546 
1547  /* buffer for evaluation results (used in setupStart already) */
1548  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &problem->evalbuffer, &problem->evalbufsize, MAX3(n, problem->hessiannz[0], maxa)) );
1549 
1550  /* setup starting point */
1551  SCIP_CALL( setupStart(data, problem, problem->x, &success) );
1552  if( !success )
1553  {
1554  /* FilterSQP would crash if starting point cannot be evaluated, so give up */
1555  SCIP_CALL( processSolveOutcome(data, problem, 7, param.feastol, param.opttol, NULL, NULL) );
1556  return SCIP_OKAY;
1557  }
1558 
1559  /* setup workspace */
1560  /* initial guess of real workspace size */
1561  /* FilterSQP manual: mxwk = 21*n + 8*m + mlp + 8*maxf + kmax*(kmax+9)/2 + nprof, with nprof = 20*n as a good guess */
1562  /* Bonmin: mxwk = 21*n + 8*m + mlp + 8*maxf + lh1 + kmax*(kmax+9)/2 + mxwk0,
1563  * with lh1 = nnz_h+8+2*n+m and mxwk0 = 2000000 (parameter) */
1564  lh1 = problem->hessiannz[0]-1 + 8 + 2*n + m;
1565  minmxwk = 21*n + 8*m + mlp + 8*maxf + lh1 + kmax*(kmax+9)/2 + MAX(20*n,2000);
1566  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &problem->ws, &problem->mxwk, minmxwk) );
1567 
1568  /* initial guess of integer workspace size */
1569  /* FilterSQP manual: mxiwk = 13*n + 4*m + mlp + 100 + kmax */
1570  /* Bonmin: mxiwk = 13*n + 4*m + mlp + lh1 + kmax + 113 + mxiwk0, with mxiwk0 = 500000 (parameter) */
1571  minmxiwk = 13*n + 4*m + mlp + lh1 + 100 + kmax + 113 + MAX(5*n,5000);
1572  if( !problem->warmstart ) /* if warmstart, then lws should remain untouched (n and m didn't change anyway) */
1573  {
1574  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &problem->lws, &problem->mxiwk, minmxiwk) );
1575  }
1576  assert(problem->lws != NULL);
1577  /* in case of some evalerrors, not clearing ws could lead to valgrind warnings about use of uninitialized memory */
1578  BMSclearMemoryArray(problem->ws, problem->mxwk);
1579 
1580  /* from here on we are not thread-safe: if intended for multithread use, then protect filtersqp call with mutex
1581  * NOTE: we need to make sure that we do not return from nlpiSolve before unlocking the mutex
1582  */
1583 #ifdef SCIP_THREADSAFE
1584  (void) pthread_mutex_lock(&filtersqpmutex);
1585 #endif
1586 
1587  /* initialize global variables from filtersqp */
1588  /* FilterSQP eps is tolerance for both feasibility and optimality, and also for trust-region radius, etc. */
1589  F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps = MIN(param.feastol, param.opttol * OPTTOLFACTOR);
1590  F77_FUNC(nlp_eps_inf,NLP_EPS_INF).infty = SCIPinfinity(scip);
1591  F77_FUNC(ubdc,UBDC).ubd = 100.0;
1592  F77_FUNC(ubdc,UBDC).tt = 1.25;
1593  F77_FUNC(scalec,SCALEC).scale_mode = 0;
1594 
1595  for( nruns = 1; ; ++nruns )
1596  {
1597  maxiter = param.iterlimit - problem->niterations;
1598 
1599  F77_FUNC(filtersqp,FILTERSQP)(
1600  &n, &m, &kmax, &maxa,
1601  &maxf, &mlp, &problem->mxwk, &problem->mxiwk,
1602  &iprint, &nout, &ifail, &rho,
1603  problem->x, problem->c, &f, &problem->fmin, problem->bl,
1604  problem->bu, problem->s, problem->a, problem->la, problem->ws,
1605  problem->lws, problem->lam, problem->cstype, user,
1606  iuser, &maxiter, problem->istat,
1607  problem->rstat, cstype_len);
1608 
1609  problem->niterations += problem->istat[1];
1610 
1611  assert(ifail <= 10);
1612  /* if ifail >= 8 (probably the workspace was too small), then retry with larger workspace
1613  * if ifail == 0 (local optimal), but absolute violation of KKT too large, then retry with small eps
1614  */
1615  if( ifail < 8 && (ifail != 0 || problem->rstat[0] <= param.opttol) )
1616  break;
1617 
1618  if( param.verblevel > 0 )
1619  {
1620  SCIPinfoMessage(scip, NULL, "FilterSQP terminated with status %d in run %d, absolute KKT violation is %g\n", ifail, nruns, problem->rstat[0]);
1621  }
1622 
1623  /* if iteration or time limit exceeded or solve is interrupted, then don't retry */
1624  if( problem->niterations >= param.iterlimit || SCIPisSolveInterrupted(scip) || timelimitreached(data, problem) )
1625  {
1626  if( param.verblevel > 0 )
1627  {
1628  SCIPinfoMessage(scip, NULL, "Time or iteration limit reached or interrupted, not retrying\n");
1629  }
1630  break;
1631  }
1632 
1633  /* if maximal number of runs reached, then stop */
1634  if( nruns >= MAXNRUNS )
1635  {
1636  if( param.verblevel > 0 )
1637  {
1638  SCIPinfoMessage(scip, NULL, "Run limit reached, not retrying\n");
1639  }
1640  break;
1641  }
1642 
1643  if( ifail == 0 )
1644  {
1645  SCIP_Real epsfactor;
1646 
1647  if( F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps <= MINEPS )
1648  {
1649  if( param.verblevel > 0 )
1650  {
1651  SCIPinfoMessage(scip, NULL, "Already reached minimal epsilon, not retrying\n");
1652  }
1653  break;
1654  }
1655 
1656  epsfactor = param.opttol / problem->rstat[0];
1657  assert(epsfactor < 1.0); /* because of the if's above */
1658  epsfactor *= OPTTOLFACTOR;
1659 
1660  F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps = MAX(MINEPS, F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps * epsfactor);
1661  if( param.verblevel > 0 )
1662  {
1663  SCIPinfoMessage(scip, NULL, "Continue with eps = %g\n", F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps);
1664  }
1665  ifail = -1; /* do warmstart */
1666 
1667  continue;
1668  }
1669 
1670  /* increase real workspace, if ifail = 9 (real workspace too small) or ifail = 8 (unexpected ifail from QP solver, often also when workspace too small) */
1671  if( ifail == 8 || ifail == 9 )
1672  {
1673  int newsize = SCIPcalcMemGrowSize(scip, WORKSPACEGROWTHFACTOR*problem->mxwk);
1674  if( BMSreallocBlockMemoryArray(SCIPblkmem(scip), &problem->ws, problem->mxwk, newsize) == NULL )
1675  {
1676  /* realloc failed: give up NLP solve */
1677  problem->mxwk = 0;
1678  break;
1679  }
1680  problem->mxwk = newsize;
1681  }
1682 
1683  /* increase integer workspace, if ifail = 10 (integer workspace too small) or ifail = 8 (unexpected ifail from QP solver, often also when workspace too small) */
1684  if( ifail == 8 || ifail == 10 )
1685  {
1686  int newsize = SCIPcalcMemGrowSize(scip, WORKSPACEGROWTHFACTOR*problem->mxiwk);
1687  if( BMSreallocBlockMemoryArray(SCIPblkmem(scip), &problem->lws, problem->mxiwk, newsize) == NULL )
1688  {
1689  /* realloc failed: give up NLP solve */
1690  problem->mxiwk = 0;
1691  break;
1692  }
1693  problem->mxiwk = newsize;
1694 
1695  /* better don't try warmstart for the next trial; warmstart requires that lws is untouched, does extending count as touching? */
1696  ifail = 0;
1697  }
1698 
1699  /* reset starting point, in case it was overwritten by failed solve (return can only be SCIP_OKAY, because randnumgen must exist already)
1700  * NOTE: If initguess is NULL (no user-given starting point), then this will result in a slightly different starting point as in the previous setupStart() call (random numbers)
1701  * However, as no point was given, it shouldn't matter which point we actually start from.
1702  */
1703  (void) setupStart(data, problem, problem->x, &success);
1704  assert(success);
1705  }
1706 
1707 #ifdef SCIP_THREADSAFE
1708  (void) pthread_mutex_unlock(&filtersqpmutex);
1709 #endif
1710 
1711  SCIP_CALL( processSolveOutcome(data, problem, ifail, param.feastol, param.opttol, problem->x, problem->lam) );
1712 
1713  return SCIP_OKAY; /*lint !e527*/
1714 } /*lint !e715*/
1715 
1716 /** gives solution status */
1717 static
1718 SCIP_DECL_NLPIGETSOLSTAT(nlpiGetSolstatFilterSQP)
1719 {
1720  assert(problem != NULL);
1721 
1722  return problem->solstat;
1723 } /*lint !e715*/
1724 
1725 /** gives termination reason */
1726 static
1727 SCIP_DECL_NLPIGETTERMSTAT(nlpiGetTermstatFilterSQP)
1728 {
1729  assert(problem != NULL);
1730 
1731  return problem->termstat;
1732 } /*lint !e715*/
1733 
1734 /** gives primal and dual solution values */
1735 static
1736 SCIP_DECL_NLPIGETSOLUTION(nlpiGetSolutionFilterSQP)
1737 {
1738  assert(problem != NULL);
1739 
1740  if( primalvalues != NULL )
1741  {
1742  assert(problem->primalvalues != NULL);
1743 
1744  *primalvalues = problem->primalvalues;
1745  }
1746 
1747  if( consdualvalues != NULL )
1748  {
1749  assert(problem->consdualvalues != NULL);
1750 
1751  *consdualvalues = problem->consdualvalues;
1752  }
1753 
1754  if( varlbdualvalues != NULL )
1755  {
1756  assert(problem->varlbdualvalues != NULL);
1757 
1758  *varlbdualvalues = problem->varlbdualvalues;
1759  }
1760 
1761  if( varubdualvalues != NULL )
1762  {
1763  assert(problem->varubdualvalues != NULL);
1764 
1765  *varubdualvalues = problem->varubdualvalues;
1766  }
1767 
1768  if( objval != NULL )
1769  {
1770  if( problem->primalvalues != NULL )
1771  {
1772  /* TODO store last solution value instead of reevaluating the objective function */
1773  SCIP_CALL( SCIPnlpiOracleEvalObjectiveValue(scip, problem->oracle, problem->primalvalues, objval) );
1774  }
1775  else
1776  *objval = SCIP_INVALID;
1777  }
1778 
1779  return SCIP_OKAY; /*lint !e527*/
1780 } /*lint !e715*/
1781 
1782 /** gives solve statistics */
1783 static
1784 SCIP_DECL_NLPIGETSTATISTICS(nlpiGetStatisticsFilterSQP)
1785 {
1786  assert(problem != NULL);
1787  assert(statistics != NULL);
1788 
1789  statistics->niterations = problem->niterations;
1790  statistics->totaltime = problem->solvetime;
1791  statistics->evaltime = SCIPnlpiOracleGetEvalTime(scip, problem->oracle);
1792  statistics->consviol = problem->rstat[4];
1793  statistics->boundviol = 0.0;
1794 
1795  return SCIP_OKAY; /*lint !e527*/
1796 } /*lint !e715*/
1797 
1798 /*
1799  * NLP solver interface specific interface methods
1800  */
1801 
1802 /** create solver interface for filterSQP solver and include it into SCIP, if filterSQP is available */
1804  SCIP* scip /**< SCIP data structure */
1805  )
1806 {
1807  SCIP_NLPIDATA* nlpidata;
1808 
1809  /* create filterSQP solver interface data */
1810  SCIP_CALL( SCIPallocClearBlockMemory(scip, &nlpidata) );
1811 
1812  /* create solver interface */
1813  SCIP_CALL( SCIPincludeNlpi(scip,
1815  nlpiCopyFilterSQP, nlpiFreeFilterSQP, NULL,
1816  nlpiCreateProblemFilterSQP, nlpiFreeProblemFilterSQP, NULL,
1817  nlpiAddVarsFilterSQP, nlpiAddConstraintsFilterSQP, nlpiSetObjectiveFilterSQP,
1818  nlpiChgVarBoundsFilterSQP, nlpiChgConsSidesFilterSQP, nlpiDelVarSetFilterSQP, nlpiDelConstraintSetFilterSQP,
1819  nlpiChgLinearCoefsFilterSQP, nlpiChgExprFilterSQP,
1820  nlpiChgObjConstantFilterSQP, nlpiSetInitialGuessFilterSQP, nlpiSolveFilterSQP, nlpiGetSolstatFilterSQP, nlpiGetTermstatFilterSQP,
1821  nlpiGetSolutionFilterSQP, nlpiGetStatisticsFilterSQP,
1822  nlpidata) );
1823 
1825 
1826  return SCIP_OKAY;
1827 }
1828 
1829 /** gets string that identifies filterSQP */
1831  void
1832  )
1833 {
1834  return "filterSQP"; /* TODO version number? */
1835 }
1836 
1837 /** gets string that describes filterSQP */
1839  void
1840  )
1841 {
1842  return NLPI_DESC;
1843 }
1844 
1845 /** returns whether filterSQP is available, i.e., whether it has been linked in */
1847  void
1848  )
1849 {
1850  return TRUE;
1851 }
static SCIP_DECL_NLPIFREEPROBLEM(nlpiFreeProblemFilterSQP)
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
static SCIP_RETCODE processSolveOutcome(SCIP_NLPIDATA *nlpidata, SCIP_NLPIPROBLEM *problem, fint ifail, SCIP_Real feastol, SCIP_Real opttol, real *x, real *lam)
SCIP_RETCODE SCIPnlpiOracleEvalObjectiveGradient(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx, SCIP_Real *objval, SCIP_Real *objgrad)
Definition: nlpioracle.c:1968
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define NULL
Definition: def.h:267
enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
Definition: type_nlpi.h:194
static SCIP_DECL_NLPIGETSOLSTAT(nlpiGetSolstatFilterSQP)
SCIP_NLPIDATA * SCIPnlpiGetData(SCIP_NLPI *nlpi)
Definition: nlpi.c:712
SCIP_RETCODE SCIPnlpiOracleChgLinearCoefs(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, int nentries, const int *varidxs, const SCIP_Real *newcoefs)
Definition: nlpioracle.c:1557
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_RETCODE SCIPincludeNlpSolverFilterSQP(SCIP *scip)
public methods for memory management
SCIP_RETCODE SCIPnlpiOracleEvalConstraintValue(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, const SCIP_Real *x, SCIP_Real *conval)
Definition: nlpioracle.c:1912
static SCIP_DECL_NLPIADDCONSTRAINTS(nlpiAddConstraintsFilterSQP)
static SCIP_DECL_NLPICHGVARBOUNDS(nlpiChgVarBoundsFilterSQP)
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define NLPI_PRIORITY
fint n_bqpd_calls
public solving methods
SCIP_Real * varubdualvalues
static SCIP_DECL_NLPISOLVE(nlpiSolveFilterSQP)
methods to store an NLP and request function, gradient, and Hessian values
SCIP_RETCODE SCIPnlpiOracleEvalHessianLag(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx_obj, SCIP_Bool isnewx_cons, SCIP_Real objfactor, const SCIP_Real *lambda, SCIP_Real *hessian)
Definition: nlpioracle.c:2380
const char * SCIPgetSolverDescFilterSQP(void)
SCIP_NLPIORACLE * oracle
#define FALSE
Definition: def.h:94
SCIP_RETCODE SCIPnlpiOracleAddConstraints(SCIP *scip, SCIP_NLPIORACLE *oracle, int nconss, const SCIP_Real *lhss, const SCIP_Real *rhss, const int *nlininds, int *const *lininds, SCIP_Real *const *linvals, SCIP_EXPR **exprs, const char **consnames)
Definition: nlpioracle.c:1167
static SCIP_DECL_NLPICHGCONSSIDES(nlpiChgConsSidesFilterSQP)
SCIP_Real SCIPinfinity(SCIP *scip)
#define TRUE
Definition: def.h:93
#define NLPI_NAME
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
void F77_FUNC(filtersqp, FILTERSQP)
static SCIP_DECL_NLPIADDVARS(nlpiAddVarsFilterSQP)
SCIP_Real * primalvalues
SCIP_RETCODE SCIPnlpiOracleSetProblemName(SCIP *scip, SCIP_NLPIORACLE *oracle, const char *name)
Definition: nlpioracle.c:1045
#define WORKSPACEGROWTHFACTOR
SCIP_Real SCIPnlpiOracleGetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:2443
static SCIP_TIME gettime(void)
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:123
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
static SCIP_DECL_NLPIGETSOLUTION(nlpiGetSolutionFilterSQP)
SCIP_RETCODE SCIPnlpiOracleSetObjective(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real constant, int nlin, const int *lininds, const SCIP_Real *linvals, SCIP_EXPR *expr)
Definition: nlpioracle.c:1228
#define OPTTOLFACTOR
SCIP_Real SCIPnlpiOracleGetConstraintRhs(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:1821
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_VAR ** x
Definition: circlepacking.c:63
filterSQP NLP interface
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
SCIP_Real timelimit
Definition: type_nlpi.h:72
real eps
SCIP_Real * varlbdualvalues
static SCIP_DECL_NLPIDELVARSET(nlpiDelVarSetFilterSQP)
public methods for numerical tolerances
static SCIP_DECL_NLPIGETTERMSTAT(nlpiGetTermstatFilterSQP)
SCIP_Bool SCIPisFilterSQPAvailableFilterSQP(void)
public methods for NLPI solver interfaces
long ftnlen
static SCIP_DECL_NLPISETINITIALGUESS(nlpiSetInitialGuessFilterSQP)
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:147
#define SCIPerrorMessage
Definition: pub_message.h:64
int SCIPnlpiOracleGetNConstraints(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1726
struct SCIP_NlpiData SCIP_NLPIDATA
Definition: type_nlpi.h:52
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:168
#define SCIP_NLPPARAM_PRINT(param)
Definition: type_nlpi.h:142
int SCIPnlpiOracleGetNVars(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1716
SCIP_RETCODE SCIPnlpiOracleResetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:2427
SCIP_RETCODE SCIPnlpiOracleChgVarBounds(SCIP *scip, SCIP_NLPIORACLE *oracle, int nvars, const int *indices, const SCIP_Real *lbs, const SCIP_Real *ubs)
Definition: nlpioracle.c:1257
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#define MAX3(x, y, z)
Definition: def.h:247
fint scale_mode
int fint
fint n_bqpd_prfint
SCIP_RETCODE SCIPnlpiOracleGetJacobianSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **offset, const int **col)
Definition: nlpioracle.c:2027
SCIP_RETCODE SCIPnlpiOracleAddVars(SCIP *scip, SCIP_NLPIORACLE *oracle, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
Definition: nlpioracle.c:1081
#define SCIP_CALL(x)
Definition: def.h:380
static SCIP_DECL_NLPICOPY(nlpiCopyFilterSQP)
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition: scip_mem.h:107
SCIP_RETCODE SCIPnlpiOracleChgExpr(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, SCIP_EXPR *expr)
Definition: nlpioracle.c:1653
#define MAXNRUNS
static SCIP_DECL_NLPIFREE(nlpiFreeFilterSQP)
SCIP_Real SCIPnlpiOracleGetConstraintLhs(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:1808
static SCIP_RETCODE handleNlpParam(SCIP *scip, SCIP_NLPIPROBLEM *nlpiproblem, const SCIP_NLPPARAM param)
static SCIP_Real timeelapsed(SCIP_NLPIDATA *nlpidata)
real infty
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
fint phr
public data structures and miscellaneous methods
SCIP_RETCODE SCIPnlpiOracleEvalJacobian(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx, SCIP_Real *convals, SCIP_Real *jacobi)
Definition: nlpioracle.c:2159
#define MINEPS
SCIP_RETCODE SCIPnlpiOracleDelVarSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
Definition: nlpioracle.c:1329
static SCIP_Bool timelimitreached(SCIP_NLPIDATA *nlpidata, SCIP_NLPIPROBLEM *nlpiproblem)
#define SCIP_Bool
Definition: def.h:91
fint phl
#define RANDSEED
real ubd
SCIP_RETCODE SCIPnlpiOracleCreate(SCIP *scip, SCIP_NLPIORACLE **oracle)
Definition: nlpioracle.c:983
SCIP_Real lobjlimit
Definition: type_nlpi.h:68
#define MIN(x, y)
Definition: def.h:243
static SCIP_DECL_NLPICHGEXPR(nlpiChgExprFilterSQP)
const SCIP_Real * SCIPnlpiOracleGetVarLbs(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1736
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define NLPI_DESC
SCIP_Real * initguess
SCIP_Bool SCIPnlpiOracleIsConstraintNonlinear(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:1847
static SCIP_DECL_NLPIGETSTATISTICS(nlpiGetStatisticsFilterSQP)
const SCIP_Real * SCIPnlpiOracleGetVarUbs(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1746
SCIP_RETCODE SCIPnlpiOracleFree(SCIP *scip, SCIP_NLPIORACLE **oracle)
Definition: nlpioracle.c:1013
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10130
#define SCIP_REAL_MAX
Definition: def.h:174
#define SCIP_REAL_MIN
Definition: def.h:175
general public methods
#define MAX(x, y)
Definition: def.h:239
SCIP_RETCODE SCIPnlpiOracleEvalObjectiveValue(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Real *objval)
Definition: nlpioracle.c:1887
static SCIP_DECL_NLPIDELCONSSET(nlpiDelConstraintSetFilterSQP)
public methods for random numbers
time_t sec
static SCIP_DECL_NLPICHGOBJCONSTANT(nlpiChgObjConstantFilterSQP)
#define MAXPERTURB
public methods for message output
real tt
SCIP_VAR * a
Definition: circlepacking.c:66
#define SCIP_Real
Definition: def.h:173
SCIP_RETCODE SCIPnlpiOracleGetHessianLagSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **offset, const int **col)
Definition: nlpioracle.c:2286
static SCIP_DECL_NLPICREATEPROBLEM(nlpiCreateProblemFilterSQP)
static void invalidateSolution(SCIP_NLPIPROBLEM *problem)
public methods for message handling
#define SCIP_INVALID
Definition: def.h:193
static SCIP_RETCODE setupStart(SCIP_NLPIDATA *data, SCIP_NLPIPROBLEM *problem, real *x, SCIP_Bool *success)
#define SCIPisFinite(x)
Definition: pub_misc.h:1933
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:728
SCIP_Real * consdualvalues
SCIP_NLPTERMSTAT termstat
SCIP_NLPSOLSTAT solstat
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_RETCODE SCIPincludeNlpi(SCIP *scip, const char *name, const char *description, int priority, SCIP_DECL_NLPICOPY((*nlpicopy)), SCIP_DECL_NLPIFREE((*nlpifree)), SCIP_DECL_NLPIGETSOLVERPOINTER((*nlpigetsolverpointer)), SCIP_DECL_NLPICREATEPROBLEM((*nlpicreateproblem)), SCIP_DECL_NLPIFREEPROBLEM((*nlpifreeproblem)), SCIP_DECL_NLPIGETPROBLEMPOINTER((*nlpigetproblempointer)), SCIP_DECL_NLPIADDVARS((*nlpiaddvars)), SCIP_DECL_NLPIADDCONSTRAINTS((*nlpiaddconstraints)), SCIP_DECL_NLPISETOBJECTIVE((*nlpisetobjective)), SCIP_DECL_NLPICHGVARBOUNDS((*nlpichgvarbounds)), SCIP_DECL_NLPICHGCONSSIDES((*nlpichgconssides)), SCIP_DECL_NLPIDELVARSET((*nlpidelvarset)), SCIP_DECL_NLPIDELCONSSET((*nlpidelconsset)), SCIP_DECL_NLPICHGLINEARCOEFS((*nlpichglinearcoefs)), SCIP_DECL_NLPICHGEXPR((*nlpichgexpr)), SCIP_DECL_NLPICHGOBJCONSTANT((*nlpichgobjconstant)), SCIP_DECL_NLPISETINITIALGUESS((*nlpisetinitialguess)), SCIP_DECL_NLPISOLVE((*nlpisolve)), SCIP_DECL_NLPIGETSOLSTAT((*nlpigetsolstat)), SCIP_DECL_NLPIGETTERMSTAT((*nlpigettermstat)), SCIP_DECL_NLPIGETSOLUTION((*nlpigetsolution)), SCIP_DECL_NLPIGETSTATISTICS((*nlpigetstatistics)), SCIP_NLPIDATA *nlpidata)
Definition: scip_nlpi.c:108
static SCIP_RETCODE setupGradients(SCIP *scip, SCIP_NLPIORACLE *oracle, fint **la, int *lasize, real **a)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:91
static SCIP_RETCODE setupHessian(SCIP *scip, SCIP_NLPIORACLE *oracle, fint **la, int *lasize)
static SCIP_DECL_NLPISETOBJECTIVE(nlpiSetObjectiveFilterSQP)
SCIP_RETCODE SCIPnlpiOracleChgConsSides(SCIP *scip, SCIP_NLPIORACLE *oracle, int nconss, const int *indices, const SCIP_Real *lhss, const SCIP_Real *rhss)
Definition: nlpioracle.c:1294
fint phc
fint phe
double real
SCIP_RETCODE SCIPnlpiOracleDelConsSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
Definition: nlpioracle.c:1471
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:458
SCIP_NLPPARAM_FASTFAIL fastfail
Definition: type_nlpi.h:75
static SCIP_DECL_NLPICHGLINEARCOEFS(nlpiChgLinearCoefsFilterSQP)
const char * SCIPgetSolverNameFilterSQP(void)
SCIP_Bool SCIPisSolveInterrupted(SCIP *scip)
Definition: scip_solve.c:3449
SCIP_RETCODE SCIPnlpiOracleChgObjConstant(SCIP *scip, SCIP_NLPIORACLE *oracle, SCIP_Real objconstant)
Definition: nlpioracle.c:1699