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"
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
78typedef int fint;
79typedef double real;
80typedef long ftnlen;
81
83{
84 time_t sec; /**< seconds part of time since epoch */
85 long usec; /**< micro-seconds part of time */
86};
87typedef struct SCIP_Time SCIP_TIME;
88
89struct 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
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 */
170void 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
204void F77_FUNC(objfun,OBJFUN)(real *x, fint *n, real *f, real *user, fint *iuser,
205 fint *errflag);
206
207void 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
212void F77_FUNC(objgrad,OBJGRAD)(fint *, fint *, fint *, real *, real *, fint *, fint
213 *, real *, fint *, fint *);
214*/
215void F77_FUNC(objgrad,OBJGRAD)(void);
216
217void 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
220void 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) */
226extern 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) */
235extern struct
236{
238} F77_FUNC(hessc,HESSC);
239/*lint -esym(754,phr,phc) */
240
241/** common block for upper bound on filter */
242extern struct
243{
245} F77_FUNC(ubdc,UBDC);
246
247/** common block for infinity & epsilon */
248extern 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) */
255extern 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) */
264extern struct
265{
267} F77_FUNC(scalec,SCALEC);
268/*lint -esym(754,phe) */
269
270#ifdef SCIP_THREADSAFE
271static pthread_mutex_t filtersqpmutex = PTHREAD_MUTEX_INITIALIZER; /*lint !e708*/
272#endif
273
274static
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) */
296static
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
314static
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} */
327void 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} */
362void 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} */
398void
399F77_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/*
442void 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*/
455void 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} */
468void
469F77_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
526static
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;
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
595static
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;
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 */
658static
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. */
734static
736 SCIP_NLPIPROBLEM* problem /**< data structure of problem */
737 )
738{
739 assert(problem != NULL);
740
743}
744
745/** store NLP solve parameters in nlpiproblem */
746static
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 */
769static
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);
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 */
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 */
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
872 problem->warmstart = TRUE;
873 break;
874 case 6: /* termination with iter > max_iter */
875 if( problem->rstat[4] <= feastol )
877 else
880 problem->warmstart = TRUE;
881 break;
882 case 7: /* crash in user routine (IEEE error) could not be resolved, or timelimit reached, or interrupted */
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
900 break;
901 case 9: /* not enough REAL workspace */
904 break;
905 case 10: /* not enough INTEGER workspace */
908 break;
909 default:
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) */
924static
925SCIP_DECL_NLPICOPY(nlpiCopyFilterSQP)
926{
928
929 return SCIP_OKAY; /*lint !e527*/
930} /*lint !e715*/
931
932/** destructor of NLP interface to free nlpi data */
933static
934SCIP_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 */
952static
953SCIP_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 */
973static
974SCIP_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 */
1011static
1012SCIP_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 */
1110static
1111SCIP_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 */
1190static
1191SCIP_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 */
1211static
1212SCIP_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 */
1238static
1239SCIP_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 */
1268static
1269SCIP_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 */
1298static
1299SCIP_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 */
1325static
1326SCIP_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 */
1349static
1350SCIP_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 */
1375static
1376SCIP_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 */
1390static
1391SCIP_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 */
1415static
1416SCIP_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 */
1717static
1718SCIP_DECL_NLPIGETSOLSTAT(nlpiGetSolstatFilterSQP)
1719{
1720 assert(problem != NULL);
1721
1722 return problem->solstat;
1723} /*lint !e715*/
1724
1725/** gives termination reason */
1726static
1727SCIP_DECL_NLPIGETTERMSTAT(nlpiGetTermstatFilterSQP)
1728{
1729 assert(problem != NULL);
1730
1731 return problem->termstat;
1732} /*lint !e715*/
1733
1734/** gives primal and dual solution values */
1735static
1736SCIP_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 */
1783static
1784SCIP_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 */
1811
1812 /* create solver interface */
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}
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** x
Definition: circlepacking.c:63
#define NULL
Definition: def.h:266
#define SCIP_REAL_MAX
Definition: def.h:173
#define SCIP_INVALID
Definition: def.h:192
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:242
#define MAX3(x, y, z)
Definition: def.h:246
#define SCIP_Real
Definition: def.h:172
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define SCIP_REAL_MIN
Definition: def.h:174
#define SCIP_CALL(x)
Definition: def.h:373
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPincludeNlpSolverFilterSQP(SCIP *scip)
SCIP_RETCODE SCIPnlpiOracleEvalObjectiveValue(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Real *objval)
Definition: nlpioracle.c:1887
SCIP_RETCODE SCIPnlpiOracleChgLinearCoefs(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, int nentries, const int *varidxs, const SCIP_Real *newcoefs)
Definition: nlpioracle.c:1557
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
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
SCIP_Bool SCIPnlpiOracleIsConstraintNonlinear(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:1847
SCIP_RETCODE SCIPnlpiOracleDelVarSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
Definition: nlpioracle.c:1329
SCIP_RETCODE SCIPnlpiOracleCreate(SCIP *scip, SCIP_NLPIORACLE **oracle)
Definition: nlpioracle.c:983
SCIP_RETCODE SCIPnlpiOracleGetJacobianSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **offset, const int **col)
Definition: nlpioracle.c:2027
SCIP_RETCODE SCIPnlpiOracleGetHessianLagSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **offset, const int **col)
Definition: nlpioracle.c:2286
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
SCIP_RETCODE SCIPnlpiOracleResetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:2427
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
SCIP_Real SCIPnlpiOracleGetConstraintRhs(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:1821
SCIP_Real SCIPnlpiOracleGetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:2443
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
SCIP_Real SCIPnlpiOracleGetConstraintLhs(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:1808
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
int SCIPnlpiOracleGetNVars(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1716
int SCIPnlpiOracleGetNConstraints(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1726
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
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
SCIP_RETCODE SCIPnlpiOracleDelConsSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
Definition: nlpioracle.c:1471
SCIP_RETCODE SCIPnlpiOracleSetProblemName(SCIP *scip, SCIP_NLPIORACLE *oracle, const char *name)
Definition: nlpioracle.c:1045
SCIP_RETCODE SCIPnlpiOracleChgObjConstant(SCIP *scip, SCIP_NLPIORACLE *oracle, SCIP_Real objconstant)
Definition: nlpioracle.c:1699
SCIP_RETCODE SCIPnlpiOracleEvalConstraintValue(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, const SCIP_Real *x, SCIP_Real *conval)
Definition: nlpioracle.c:1912
const SCIP_Real * SCIPnlpiOracleGetVarLbs(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1736
const SCIP_Real * SCIPnlpiOracleGetVarUbs(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1746
SCIP_RETCODE SCIPnlpiOracleFree(SCIP *scip, SCIP_NLPIORACLE **oracle)
Definition: nlpioracle.c:1013
SCIP_RETCODE SCIPnlpiOracleChgExpr(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, SCIP_EXPR *expr)
Definition: nlpioracle.c:1653
const char * SCIPgetSolverDescFilterSQP(void)
const char * SCIPgetSolverNameFilterSQP(void)
SCIP_Bool SCIPisFilterSQPAvailableFilterSQP(void)
#define SCIPisFinite(x)
Definition: pub_misc.h:1933
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:744
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:91
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition: scip_mem.h:107
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#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
SCIP_NLPIDATA * SCIPnlpiGetData(SCIP_NLPI *nlpi)
Definition: nlpi.c:712
SCIP_Bool SCIPisSolveInterrupted(SCIP *scip)
Definition: scip_solve.c:3468
SCIP_Real SCIPinfinity(SCIP *scip)
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10133
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:123
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:147
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:458
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
static SCIP_DECL_NLPIGETTERMSTAT(nlpiGetTermstatFilterSQP)
long ftnlen
static SCIP_DECL_NLPIADDCONSTRAINTS(nlpiAddConstraintsFilterSQP)
double real
#define NLPI_PRIORITY
static SCIP_DECL_NLPICHGOBJCONSTANT(nlpiChgObjConstantFilterSQP)
static SCIP_DECL_NLPICREATEPROBLEM(nlpiCreateProblemFilterSQP)
#define MAXPERTURB
static SCIP_RETCODE handleNlpParam(SCIP *scip, SCIP_NLPIPROBLEM *nlpiproblem, const SCIP_NLPPARAM param)
#define RANDSEED
fint phe
static SCIP_DECL_NLPIGETSOLUTION(nlpiGetSolutionFilterSQP)
static SCIP_DECL_NLPISOLVE(nlpiSolveFilterSQP)
static SCIP_DECL_NLPISETOBJECTIVE(nlpiSetObjectiveFilterSQP)
real tt
#define OPTTOLFACTOR
real ubd
static SCIP_DECL_NLPIFREEPROBLEM(nlpiFreeProblemFilterSQP)
static SCIP_TIME gettime(void)
static SCIP_DECL_NLPIGETSTATISTICS(nlpiGetStatisticsFilterSQP)
fint phr
fint scale_mode
#define WORKSPACEGROWTHFACTOR
static SCIP_DECL_NLPIDELVARSET(nlpiDelVarSetFilterSQP)
#define NLPI_NAME
static SCIP_DECL_NLPIADDVARS(nlpiAddVarsFilterSQP)
static SCIP_RETCODE setupGradients(SCIP *scip, SCIP_NLPIORACLE *oracle, fint **la, int *lasize, real **a)
real eps
static SCIP_Real timeelapsed(SCIP_NLPIDATA *nlpidata)
static SCIP_DECL_NLPICHGEXPR(nlpiChgExprFilterSQP)
static SCIP_RETCODE processSolveOutcome(SCIP_NLPIDATA *nlpidata, SCIP_NLPIPROBLEM *problem, fint ifail, SCIP_Real feastol, SCIP_Real opttol, real *x, real *lam)
real infty
void F77_FUNC(filtersqp, FILTERSQP)
static SCIP_DECL_NLPICHGLINEARCOEFS(nlpiChgLinearCoefsFilterSQP)
#define MINEPS
int fint
fint phc
fint n_bqpd_prfint
static SCIP_RETCODE setupHessian(SCIP *scip, SCIP_NLPIORACLE *oracle, fint **la, int *lasize)
static SCIP_DECL_NLPICHGCONSSIDES(nlpiChgConsSidesFilterSQP)
static SCIP_DECL_NLPICHGVARBOUNDS(nlpiChgVarBoundsFilterSQP)
static SCIP_DECL_NLPIDELCONSSET(nlpiDelConstraintSetFilterSQP)
static SCIP_DECL_NLPIFREE(nlpiFreeFilterSQP)
static SCIP_DECL_NLPIGETSOLSTAT(nlpiGetSolstatFilterSQP)
static SCIP_RETCODE setupStart(SCIP_NLPIDATA *data, SCIP_NLPIPROBLEM *problem, real *x, SCIP_Bool *success)
static SCIP_Bool timelimitreached(SCIP_NLPIDATA *nlpidata, SCIP_NLPIPROBLEM *nlpiproblem)
fint n_bqpd_calls
fint phl
#define MAXNRUNS
static SCIP_DECL_NLPISETINITIALGUESS(nlpiSetInitialGuessFilterSQP)
#define NLPI_DESC
static void invalidateSolution(SCIP_NLPIPROBLEM *problem)
static SCIP_DECL_NLPICOPY(nlpiCopyFilterSQP)
filterSQP NLP interface
methods to store an NLP and request function, gradient, and Hessian values
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public data structures and miscellaneous methods
general public methods
public methods for memory management
public methods for message handling
public methods for NLPI solver interfaces
public methods for numerical tolerances
public methods for random numbers
public solving methods
SCIP_Real timelimit
Definition: type_nlpi.h:72
SCIP_NLPPARAM_FASTFAIL fastfail
Definition: type_nlpi.h:75
SCIP_Real lobjlimit
Definition: type_nlpi.h:68
SCIP_Real * primalvalues
SCIP_Real * varubdualvalues
SCIP_NLPIORACLE * oracle
SCIP_NLPTERMSTAT termstat
SCIP_Real * consdualvalues
SCIP_Real * varlbdualvalues
SCIP_Real * initguess
SCIP_NLPSOLSTAT solstat
time_t sec
#define SCIP_NLPPARAM_PRINT(param)
Definition: type_nlpi.h:142
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:168
@ SCIP_NLPTERMSTAT_OKAY
Definition: type_nlpi.h:173
@ SCIP_NLPTERMSTAT_TIMELIMIT
Definition: type_nlpi.h:174
@ SCIP_NLPTERMSTAT_NUMERICERROR
Definition: type_nlpi.h:178
@ SCIP_NLPTERMSTAT_OTHER
Definition: type_nlpi.h:182
@ SCIP_NLPTERMSTAT_EVALERROR
Definition: type_nlpi.h:179
@ SCIP_NLPTERMSTAT_LOBJLIMIT
Definition: type_nlpi.h:176
@ SCIP_NLPTERMSTAT_ITERLIMIT
Definition: type_nlpi.h:175
@ SCIP_NLPTERMSTAT_OUTOFMEMORY
Definition: type_nlpi.h:180
@ SCIP_NLPTERMSTAT_INTERRUPT
Definition: type_nlpi.h:177
@ SCIP_NLPSOLSTAT_UNBOUNDED
Definition: type_nlpi.h:165
@ SCIP_NLPSOLSTAT_GLOBINFEASIBLE
Definition: type_nlpi.h:164
@ SCIP_NLPSOLSTAT_LOCINFEASIBLE
Definition: type_nlpi.h:163
@ SCIP_NLPSOLSTAT_FEASIBLE
Definition: type_nlpi.h:162
@ SCIP_NLPSOLSTAT_LOCOPT
Definition: type_nlpi.h:161
@ SCIP_NLPSOLSTAT_UNKNOWN
Definition: type_nlpi.h:166
enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
Definition: type_nlpi.h:194
struct SCIP_NlpiData SCIP_NLPIDATA
Definition: type_nlpi.h:52
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63