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-2025 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#ifdef _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,
504 problem->evalbuffer, FALSE) == SCIP_OKAY )
505 {
506 *l_hess = nnz;
507
508 BMScopyMemoryArray(ws, problem->evalbuffer, nnz);
509
510 *errflag = 0;
511
512 /* copy the complete problem->hessiannz into lws */
513 for( i = 0; i < nnz + *n + 2; ++i )
514 lws[i] = problem->hessiannz[i];
515 *li_hess = nnz + *n + 2;
516 }
517 else
518 {
519 SCIPdebugMsg(problem->scip, "arithmetic exception in hessian\n");
520 }
521
522 BMSfreeMemoryArray(&lambda);
523}
524
525
526
527static
529 SCIP* scip, /**< SCIP data structure */
530 SCIP_NLPIORACLE* oracle, /**< NLPI oracle */
531 fint** la, /**< buffer to store pointer to sparsity structure */
532 int* lasize, /**< buffer to store length of *la array */
533 real** a /**< buffer to store pointer to value buffer */
534 )
535{
536 const int* offset;
537 const int* col;
538 int nnz; /* number of nonzeros in Jacobian */
539 int nvars;
540 int ncons;
541 int i;
542 int c;
543 int nnlnz;
544
545 assert(la != NULL);
546 assert(lasize != NULL);
547 assert(a != NULL);
548 assert(*la == NULL);
549 assert(*a == NULL);
550
551 nvars = SCIPnlpiOracleGetNVars(oracle);
552 ncons = SCIPnlpiOracleGetNConstraints(oracle);
553
554 /* get jacobian sparsity in oracle format: offset are rowstarts in col and col are column indices */
555 SCIP_CALL( SCIPnlpiOracleGetJacobianRowSparsity(scip, oracle, &offset, &col, NULL, &nnlnz) );
556 nnz = offset[ncons];
557
558 /* la stores both column indices (first) and rowstarts (at the end) of the objective gradient and Jacobian
559 * For the objective gradient, always n entries are taken, the Jacobian is stored sparse
560 * la(0) = n+nnz+1 position where rowstarts start in la
561 * la(j) column index of objective gradient or Jacobian row, rowwise
562 * la(la(0)) position of first nonzero element for objective gradient in a()
563 * la(la(0)+i) position of first nonzero element for constraint i gradient in a(), i=1..m
564 * la(la(0)+m+1) = n+nnz first unused position in a
565 * where n = nvars and m = ncons
566 */
567
568 /* need space for la(0) and column indices and rowstarts (1+ncons+1 for objective, constraints, and end (offsets[ncons])) */
569 *lasize = 1 + (nvars+nnz) + 1+ncons + 1;
571
572 (*la)[0] = nvars+nnz+1;
573
574 /* the objective gradient is stored in sparse form */
575 for( i = 0; i < nvars; ++i )
576 (*la)[1+i] = 1+i; /* shift by 1 for Fortran */
577 (*la)[(*la)[0]] = 1; /* objective entries start at the beginning in a, shift by 1 for Fortran */
578
579 /* column indicies are as given by col */
580 for( i = 0; i < nnz; ++i )
581 (*la)[1+nvars+i] = col[i] + 1; /* shift by 1 for Fortran */
582
583 /* rowstarts are as given by offset, plus extra for objective gradient */
584 for( c = 0; c <= ncons; ++c )
585 (*la)[(*la)[0]+1+c] = offset[c] + nvars + 1; /* shift by nvars for objective, shift by 1 for Fortran */
586
587 SCIP_CALL( SCIPallocBlockMemoryArray(scip, a, nvars + nnz) );
588
589#ifdef SCIP_MORE_DEBUG /* enable for debugging Jacobian */
590 for( i = 0; i < 1 + (nvars+nnz) + 1+ncons + 1; ++i )
591 printf("la[%2d] = %2d\n", i, (*la)[i]);
592#endif
593
594 return SCIP_OKAY;
595}
596
597static
599 SCIP* scip, /**< SCIP data structure */
600 SCIP_NLPIORACLE* oracle, /**< NLPI oracle */
601 fint** la, /**< buffer to store pointer to Hessian sparsity structure */
602 int* lasize /**< buffer to store length of *la array */
603 )
604{
605 const int* offset;
606 const int* col;
607 int nnz; /* number of nonzeros in Jacobian */
608 int nvars;
609 int i;
610 int v;
611
612 assert(la != NULL);
613 assert(lasize != NULL);
614 assert(*la == NULL);
615
616 nvars = SCIPnlpiOracleGetNVars(oracle);
617
618 /* get Hessian sparsity in oracle format: offset are rowstarts in col and col are column indices */
619 SCIP_CALL( SCIPnlpiOracleGetHessianLagSparsity(scip, oracle, &offset, &col, FALSE) );
620 nnz = offset[nvars];
621
622 /* la stores both column indices (first) and rowstarts (at the end) of the (sparse) Hessian
623 * la(0) = nnz+1 position where rowstarts start in la
624 * la(j) column index of Hessian row, rowwise
625 * la(la(0)+i) position of first nonzero element for row i, i = 0..n-1
626 * la(la(0)+n) = nnz first unused position in Hessian
627 * where n = nvars
628 */
629
630 /* need space for la(0) and column indices and rowstarts
631 * 1 for la(0)
632 * nnz for column indices
633 * nvars for rowstarts
634 * 1 for first unused position
635 */
636 *lasize = 1 + nnz + nvars + 1;
638
639 (*la)[0] = nnz+1;
640
641 /* column indicies are as given by col */
642 for( i = 0; i < nnz; ++i )
643 (*la)[1+i] = col[i] + 1; /* shift by 1 for Fortran */
644
645 /* rowstarts are as given by offset */
646 for( v = 0; v <= nvars; ++v )
647 (*la)[(*la)[0]+v] = offset[v] + 1; /* shift by 1 for Fortran */
648
649 F77_FUNC(hessc,HESSC).phl = 1;
650
651#ifdef SCIP_MORE_DEBUG /* enable for debugging Hessian */
652 for( i = 0; i < 1 + nnz + nvars + 1; ++i )
653 printf("lw[%2d] = %2d\n", i, (*la)[i]);
654#endif
655
656 return SCIP_OKAY;
657}
658
659/** setup starting point for FilterSQP */
660static
662 SCIP_NLPIDATA* data, /**< NLPI data */
663 SCIP_NLPIPROBLEM* problem, /**< NLPI problem */
664 real* x, /**< array to store initial values */
665 SCIP_Bool* success /**< whether we could setup a point in which functions could be evaluated */
666 )
667{
668 int i;
669 int n;
670 SCIP_Real val;
671
672 assert(data != NULL);
673 assert(problem != NULL);
674 assert(x != NULL);
675 assert(success != NULL);
676
677 n = SCIPnlpiOracleGetNVars(problem->oracle);
678
679 /* setup starting point */
680 if( problem->initguess != NULL )
681 {
682 for( i = 0; i < n; ++i )
683 x[i] = problem->initguess[i];
684 }
685 else
686 {
687 SCIP_Real lb;
688 SCIP_Real ub;
689
690 SCIPdebugMsg(problem->scip, "FilterSQP started without initial primal values; make up something by projecting 0 onto variable bounds and perturb\n");
691
692 if( data->randnumgen == NULL )
693 {
694 SCIP_CALL( SCIPcreateRandom(problem->scip, &data->randnumgen, RANDSEED, TRUE) );
695 }
696
697 for( i = 0; i < n; ++i )
698 {
699 lb = SCIPnlpiOracleGetVarLbs(problem->oracle)[i];
700 ub = SCIPnlpiOracleGetVarUbs(problem->oracle)[i];
701 if( lb > 0.0 )
702 x[i] = SCIPrandomGetReal(data->randnumgen, lb, lb + MAXPERTURB*MIN(1.0, ub-lb));
703 else if( ub < 0.0 )
704 x[i] = SCIPrandomGetReal(data->randnumgen, ub - MAXPERTURB*MIN(1.0, ub-lb), ub);
705 else
706 x[i] = SCIPrandomGetReal(data->randnumgen, MAX(lb, -MAXPERTURB*MIN(1.0, ub-lb)), MIN(ub, MAXPERTURB*MIN(1.0, ub-lb)));
707 }
708 }
709
710 /* check whether objective and constraints can be evaluated and differentiated once in starting point
711 * NOTE: this does not check whether hessian can be computed!
712 */
713 *success = SCIPnlpiOracleEvalObjectiveValue(problem->scip, problem->oracle, x, &val) == SCIP_OKAY && SCIPisFinite(val);
714 *success &= SCIPnlpiOracleEvalObjectiveGradient(problem->scip, problem->oracle, x, FALSE, &val, problem->evalbuffer) == SCIP_OKAY; /*lint !e514*/
715 i = 0;
716 for( ; *success && i < SCIPnlpiOracleGetNConstraints(problem->oracle); ++i )
717 *success = SCIPnlpiOracleEvalConstraintValue(problem->scip, problem->oracle, i, x, &val) == SCIP_OKAY && SCIPisFinite(val);
718 *success &= SCIPnlpiOracleEvalJacobian(problem->scip, problem->oracle, x, FALSE, NULL, problem->evalbuffer) == SCIP_OKAY; /*lint !e514*/
719
720 if( !*success )
721 {
722 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");
723
724 if( problem->initguess != NULL )
725 {
726 /* forget given starting point and try to make up our own */
727 SCIPfreeBlockMemoryArray(problem->scip, &problem->initguess, problem->varssize);
728 SCIP_CALL( setupStart(data, problem, x, success) );
729 }
730 }
731
732 return SCIP_OKAY;
733}
734
735/** sets the solstat and termstat to unknown and other, resp. */
736static
738 SCIP_NLPIPROBLEM* problem /**< data structure of problem */
739 )
740{
741 assert(problem != NULL);
742
745}
746
747/** store NLP solve parameters in nlpiproblem */
748static
750 SCIP* scip, /**< SCIP data structure */
751 SCIP_NLPIPROBLEM* nlpiproblem, /**< NLP */
752 const SCIP_NLPPARAM param /**< solve parameters */
753 )
754{
755 assert(scip != NULL);
756 assert(nlpiproblem != NULL);
757
758 if( param.fastfail )
759 {
760 SCIPdebugMsg(scip, "fast fail parameter not supported by FilterSQP interface yet. Ignored.\n");
761 }
762
763 nlpiproblem->fmin = param.lobjlimit;
764
765 nlpiproblem->maxtime = param.timelimit;
766
767 return SCIP_OKAY;
768}
769
770/** processes results from FilterSQP call */
771static
773 SCIP_NLPIDATA* nlpidata, /**< NLPI data */
774 SCIP_NLPIPROBLEM* problem, /**< NLPI problem */
775 fint ifail, /**< fail flag from FilterSQP call */
776 SCIP_Real feastol, /**< feasibility tolerance */
777 SCIP_Real opttol, /**< optimality tolerance */
778 real* x, /**< primal solution values from FilterSQP call, or NULL if stopped before filtersqp got called */
779 real* lam /**< dual solution values from FilterSQP call, or NULL if stopped before filtersqp got called */
780 )
781{
782 int i;
783 int nvars;
784 int ncons;
785
786 assert(problem != NULL);
787 assert(ifail >= 0);
788 assert((x != NULL) == (lam != NULL));
789
790 problem->solvetime = timeelapsed(nlpidata);
791
792 nvars = SCIPnlpiOracleGetNVars(problem->oracle);
793 ncons = SCIPnlpiOracleGetNConstraints(problem->oracle);
794
795 if( ifail <= 8 && x != NULL )
796 {
797 /* FilterSQP terminated somewhat normally -> store away solution */
798
799 /* make sure we have memory for solution */
800 if( problem->primalvalues == NULL )
801 {
802 assert(problem->varssize >= nvars); /* ensured in nlpiAddVariables */
803 assert(problem->conssize >= ncons); /* ensured in nlpiAddConstraints */
804 assert(problem->consdualvalues == NULL); /* if primalvalues == NULL, then also consdualvalues should be NULL */
805 assert(problem->varlbdualvalues == NULL); /* if primalvalues == NULL, then also varlbdualvalues should be NULL */
806 assert(problem->varubdualvalues == NULL); /* if primalvalues == NULL, then also varubdualvalues should be NULL */
807
808 SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->primalvalues, problem->varssize) );
809 SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->consdualvalues, problem->conssize) );
810 SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->varlbdualvalues, problem->varssize) );
811 SCIP_CALL( SCIPallocBlockMemoryArray(problem->scip, &problem->varubdualvalues, problem->varssize) );
812 }
813 else
814 {
815 assert(problem->consdualvalues != NULL);
816 assert(problem->varlbdualvalues != NULL);
817 assert(problem->varubdualvalues != NULL);
818 }
819
820 for( i = 0; i < nvars; ++i )
821 {
822 problem->primalvalues[i] = x[i];
823
824 /* if dual from FilterSQP is positive, then it belongs to the lower bound, otherwise to the upper bound */
825 problem->varlbdualvalues[i] = MAX(0.0, lam[i]);
826 problem->varubdualvalues[i] = MAX(0.0, -lam[i]);
827 }
828
829 /* duals from FilterSQP are negated */
830 for( i = 0; i < ncons; ++i )
831 problem->consdualvalues[i] = -lam[nvars + i];
832 }
833
834 /* translate ifail to solution and termination status and decide whether we could warmstart next */
835 problem->warmstart = FALSE;
836 switch( ifail )
837 {
838 case 0: /* successful run, solution found */
839 assert(problem->rstat[4] <= feastol); /* should be feasible */
840 problem->solstat = (problem->rstat[0] <= opttol ? SCIP_NLPSOLSTAT_LOCOPT : SCIP_NLPSOLSTAT_FEASIBLE);
842 problem->warmstart = TRUE;
843 break;
844 case 1: /* unbounded, feasible point with f(x) <= fmin */
845 assert(problem->rstat[4] <= feastol); /* should be feasible */
847 if( problem->fmin == SCIP_REAL_MIN ) /*lint !e777*/
848 problem->termstat = SCIP_NLPTERMSTAT_OKAY; /* fmin was not set */
849 else
851 break;
852 case 2: /* linear constraints are inconsistent */
855 break;
856 case 3: /* (locally) nonlinear infeasible, minimal-infeasible solution found */
857 /* problem->solstat = (problem->rstat[0] <= opttol ? SCIP_NLPSOLSTAT_LOCINFEASIBLE : SCIP_NLPSOLSTAT_UNKNOWN); */
858 problem->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE; /* TODO FilterSQP does not set rstat[0] in this case, assuming local infeasibility is valid */
860 problem->warmstart = TRUE;
861 break;
862 case 4: /* terminate at point with h(x) <= eps (constraint violation below epsilon) but QP infeasible */
863 assert(problem->rstat[4] <= feastol); /* should be feasible */
866 problem->warmstart = TRUE;
867 break;
868 case 5: /* termination with rho < eps (trust region radius below epsilon) */
869 if( problem->rstat[4] <= feastol )
871 else
874 problem->warmstart = TRUE;
875 break;
876 case 6: /* termination with iter > max_iter */
877 if( problem->rstat[4] <= feastol )
879 else
882 problem->warmstart = TRUE;
883 break;
884 case 7: /* crash in user routine (IEEE error) could not be resolved, or timelimit reached, or interrupted */
886 if( problem->solvetime >= problem->maxtime )
887 {
889 problem->warmstart = TRUE;
890 }
891 else if( SCIPisSolveInterrupted(problem->scip) )
893 else
895 break;
896 case 8: /* unexpect ifail from QP solver */
897 if( problem->rstat[4] <= feastol )
899 else
902 break;
903 case 9: /* not enough REAL workspace */
906 break;
907 case 10: /* not enough INTEGER workspace */
910 break;
911 default:
914 break;
915 }
916
917 return SCIP_OKAY;
918}
919
920
921/*
922 * Callback methods of NLP solver interface
923 */
924
925/** copy method of NLP interface (called when SCIP copies plugins) */
926static
927SCIP_DECL_NLPICOPY(nlpiCopyFilterSQP)
928{
930
931 return SCIP_OKAY; /*lint !e527*/
932} /*lint !e715*/
933
934/** destructor of NLP interface to free nlpi data */
935static
936SCIP_DECL_NLPIFREE(nlpiFreeFilterSQP)
937{
938 assert(nlpi != NULL);
939 assert(nlpidata != NULL);
940 assert(*nlpidata != NULL);
941
942 if( (*nlpidata)->randnumgen != NULL )
943 {
944 SCIPfreeRandom(scip, &(*nlpidata)->randnumgen);
945 }
946
947 SCIPfreeBlockMemory(scip, nlpidata);
948 assert(*nlpidata == NULL);
949
950 return SCIP_OKAY;
951}
952
953/** creates a problem instance */
954static
955SCIP_DECL_NLPICREATEPROBLEM(nlpiCreateProblemFilterSQP)
956{
957 assert(nlpi != NULL);
958 assert(problem != NULL);
959
961 (*problem)->scip = scip;
962
963 SCIP_CALL( SCIPnlpiOracleCreate(scip, &(*problem)->oracle) );
964 SCIP_CALL( SCIPnlpiOracleSetProblemName(scip, (*problem)->oracle, name) );
965
966 (*problem)->fmin = SCIP_REAL_MIN;
967 (*problem)->maxtime = SCIP_REAL_MAX;
968
969 invalidateSolution(*problem);
970
971 return SCIP_OKAY; /*lint !e527*/
972} /*lint !e715*/
973
974/** free a problem instance */
975static
976SCIP_DECL_NLPIFREEPROBLEM(nlpiFreeProblemFilterSQP)
977{
978 assert(nlpi != NULL);
979 assert(problem != NULL);
980 assert(*problem != NULL);
981
982 if( (*problem)->oracle != NULL )
983 {
984 SCIP_CALL( SCIPnlpiOracleFree(scip, &(*problem)->oracle) );
985 }
986
987 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->initguess, (*problem)->varssize);
988 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->primalvalues, (*problem)->varssize);
989 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->consdualvalues, (*problem)->conssize);
990 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->varlbdualvalues, (*problem)->varssize);
991 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->varubdualvalues, (*problem)->varssize);
992 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->cstype, (*problem)->conssize);
993 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->s, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
994 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->bu, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
995 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->bl, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
996 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->x, (*problem)->varssize);
997 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->c, (*problem)->conssize);
998 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->lam, (*problem)->varssize + (*problem)->conssize); /*lint !e776 */
999 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->a, (*problem)->la != NULL ? (*problem)->la[0]-1 : 0);
1000 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->la, (*problem)->lasize);
1001 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->hessiannz, (*problem)->hessiannzsize);
1002 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->lws, (*problem)->mxiwk);
1003 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->ws, (*problem)->mxwk);
1004 SCIPfreeBlockMemoryArrayNull(scip, &(*problem)->evalbuffer, (*problem)->evalbufsize);
1005
1006 SCIPfreeBlockMemory(scip, problem);
1007 assert(*problem == NULL);
1008
1009 return SCIP_OKAY;
1010} /*lint !e715*/
1011
1012/** add variables */
1013static
1014SCIP_DECL_NLPIADDVARS(nlpiAddVarsFilterSQP)
1015{
1016 int oldnvars;
1017
1018 assert(nlpi != NULL);
1019 assert(problem != NULL);
1020 assert(problem->oracle != NULL);
1021
1022 oldnvars = SCIPnlpiOracleGetNVars(problem->oracle);
1023
1024 SCIP_CALL( SCIPnlpiOracleAddVars(scip, problem->oracle, nvars, lbs, ubs, varnames) );
1025
1026 SCIPfreeBlockMemoryArrayNull(scip, &problem->initguess, problem->varssize);
1027 invalidateSolution(problem);
1028 problem->warmstart = FALSE;
1029
1030 /* increase variables-related arrays in problem, if necessary */
1031 if( problem->varssize < SCIPnlpiOracleGetNVars(problem->oracle) )
1032 {
1033 int newsize = SCIPcalcMemGrowSize(scip, SCIPnlpiOracleGetNVars(problem->oracle));
1034
1035 if( problem->primalvalues != NULL )
1036 {
1037 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->primalvalues, problem->varssize, newsize) );
1038 }
1039
1040 if( problem->varlbdualvalues != NULL )
1041 {
1042 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->varlbdualvalues, problem->varssize, newsize) );
1043 }
1044
1045 if( problem->varubdualvalues != NULL )
1046 {
1047 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->varubdualvalues, problem->varssize, newsize) );
1048 }
1049
1050 if( problem->x != NULL )
1051 {
1052 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->x, problem->varssize, newsize) );
1053 }
1054
1055 if( problem->lam != NULL )
1056 {
1057 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->lam, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1058 }
1059
1060 if( problem->bl != NULL )
1061 {
1062 assert(problem->bu != NULL);
1063 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bl, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1064 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bu, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1065 }
1066
1067 if( problem->s != NULL )
1068 {
1069 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->s, problem->varssize + problem->conssize, newsize + problem->conssize) ); /*lint !e776*/
1070 }
1071
1072 problem->varssize = newsize;
1073 }
1074
1075 /* update variable bounds in FilterSQP data */
1076 if( problem->bl != NULL )
1077 {
1078 int i;
1079 int nconss;
1080
1081 nconss = SCIPnlpiOracleGetNConstraints(problem->oracle);
1082
1083 /* bl and bu have first variable bounds and then constraint sides
1084 * copy the constraint sides to their new position before putting in the new variable bounds
1085 */
1086 for( i = nconss-1; i >= 0; --i )
1087 {
1088 problem->bl[oldnvars+nvars+i] = problem->bl[oldnvars+i];
1089 problem->bu[oldnvars+nvars+i] = problem->bu[oldnvars+i];
1090 }
1091
1092 /* set bounds of new variable */
1093 for( i = 0; i < nvars; ++i )
1094 {
1095 problem->bl[oldnvars+i] = lbs[i];
1096 problem->bu[oldnvars+i] = ubs[i];
1097 }
1098 }
1099
1100 /* gradients information is out of date now (objective gradient is stored in dense form) */
1101 SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1102 SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1103
1104 /* Hessian information is out of date now (no new entries in Hessian, but also empty cols shows up in sparsity info) */
1105 SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1106
1107 return SCIP_OKAY;
1108} /*lint !e715*/
1109
1110
1111/** add constraints */
1112static
1113SCIP_DECL_NLPIADDCONSTRAINTS(nlpiAddConstraintsFilterSQP)
1114{
1115 int oldnconss;
1116
1117 assert(nlpi != NULL);
1118 assert(problem != NULL);
1119 assert(problem->oracle != NULL);
1120
1121 oldnconss = SCIPnlpiOracleGetNConstraints(problem->oracle);
1122
1123 SCIP_CALL( SCIPnlpiOracleAddConstraints(scip, problem->oracle, nconss, lhss, rhss, nlininds, lininds, linvals, exprs, names) );
1124
1125 invalidateSolution(problem);
1126 problem->warmstart = FALSE;
1127
1128 /* increase constraints-related arrays in problem, if necessary */
1129 if( SCIPnlpiOracleGetNConstraints(problem->oracle) > problem->conssize )
1130 {
1131 int newsize = SCIPcalcMemGrowSize(scip, SCIPnlpiOracleGetNConstraints(problem->oracle));
1132
1133 if( problem->consdualvalues != NULL )
1134 {
1135 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->consdualvalues, problem->conssize, newsize) );
1136 }
1137
1138 if( problem->c != NULL )
1139 {
1140 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->c, problem->conssize, newsize) );
1141 }
1142
1143 if( problem->lam != NULL )
1144 {
1145 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->lam, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1146 }
1147
1148 if( problem->bl != NULL )
1149 {
1150 assert(problem->bu != NULL);
1151 assert(problem->cstype != NULL);
1152 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bl, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1153 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->bu, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1154 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->cstype, problem->conssize, newsize) );
1155 }
1156
1157 if( problem->s != NULL )
1158 {
1159 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &problem->s, problem->varssize + problem->conssize, problem->varssize + newsize) ); /*lint !e776*/
1160 }
1161
1162 problem->conssize = newsize;
1163 }
1164
1165 /* update constraint sides and type in FilterSQP data */
1166 if( problem->bl != NULL )
1167 {
1168 int i;
1169 int nvars;
1170
1171 nvars = SCIPnlpiOracleGetNVars(problem->oracle);
1172
1173 for( i = 0; i < nconss; ++i )
1174 {
1175 problem->bl[nvars+oldnconss+i] = lhss[i];
1176 problem->bu[nvars+oldnconss+i] = rhss[i];
1177 problem->cstype[oldnconss+i] = SCIPnlpiOracleIsConstraintNonlinear(problem->oracle, oldnconss+i) ? 'N' : 'L';
1178 }
1179 }
1180
1181 /* gradients information is out of date now */
1182 SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1183 SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1184
1185 /* Hessian information is out of date now */
1186 SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1187
1188 return SCIP_OKAY;
1189} /*lint !e715*/
1190
1191/** sets or overwrites objective, a minimization problem is expected */
1192static
1193SCIP_DECL_NLPISETOBJECTIVE( nlpiSetObjectiveFilterSQP )
1194{
1195 assert(nlpi != NULL);
1196 assert(problem != NULL);
1197 assert(problem->oracle != NULL);
1198
1199 SCIP_CALL( SCIPnlpiOracleSetObjective(scip, problem->oracle,
1200 constant, nlins, lininds, linvals, expr) );
1201
1202 invalidateSolution(problem);
1203
1204 /* gradients info (la,a) should still be ok, as objective gradient is stored in dense form */
1205
1206 /* Hessian information is out of date now */
1207 SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1208
1209 return SCIP_OKAY;
1210} /*lint !e715*/
1211
1212/** change variable bounds */
1213static
1214SCIP_DECL_NLPICHGVARBOUNDS(nlpiChgVarBoundsFilterSQP)
1215{
1216 assert(nlpi != NULL);
1217 assert(problem != NULL);
1218 assert(problem->oracle != NULL);
1219
1220 SCIP_CALL( SCIPnlpiOracleChgVarBounds(scip, problem->oracle, nvars, indices, lbs, ubs) );
1221
1222 invalidateSolution(problem);
1223
1224 /* update bounds in FilterSQP data */
1225 if( problem->bl != NULL )
1226 {
1227 int i;
1228
1229 for( i = 0; i < nvars; ++i )
1230 {
1231 problem->bl[indices[i]] = lbs[i];
1232 problem->bu[indices[i]] = ubs[i];
1233 }
1234 }
1235
1236 return SCIP_OKAY;
1237} /*lint !e715*/
1238
1239/** change constraint bounds */
1240static
1241SCIP_DECL_NLPICHGCONSSIDES(nlpiChgConsSidesFilterSQP)
1242{
1243 assert(nlpi != NULL);
1244 assert(problem != NULL);
1245 assert(problem->oracle != NULL);
1246
1247 SCIP_CALL( SCIPnlpiOracleChgConsSides(scip, problem->oracle, nconss, indices, lhss, rhss) );
1248
1249 invalidateSolution(problem);
1250
1251 /* update constraint sense in FilterSQP data */
1252 if( problem->bl != NULL )
1253 {
1254 int i;
1255 int nvars;
1256
1257 nvars = SCIPnlpiOracleGetNVars(problem->oracle);
1258
1259 for( i = 0; i < nconss; ++i )
1260 {
1261 problem->bl[nvars+indices[i]] = lhss[i];
1262 problem->bu[nvars+indices[i]] = rhss[i];
1263 }
1264 }
1265
1266 return SCIP_OKAY;
1267} /*lint !e715*/
1268
1269/** delete a set of variables */
1270static
1271SCIP_DECL_NLPIDELVARSET(nlpiDelVarSetFilterSQP)
1272{
1273 assert(nlpi != NULL);
1274 assert(problem != NULL);
1275 assert(problem->oracle != NULL);
1276
1277 SCIP_CALL( SCIPnlpiOracleDelVarSet(scip, problem->oracle, dstats) );
1278
1279 /* @TODO keep initguess and bl, bu for remaining variables? */
1280
1281 SCIPfreeBlockMemoryArrayNull(scip, &problem->initguess, problem->varssize);
1282 invalidateSolution(problem);
1283 problem->warmstart = FALSE;
1284
1285 SCIPfreeBlockMemoryArrayNull(scip, &problem->bl, problem->varssize + problem->conssize); /*lint !e776 */
1286 SCIPfreeBlockMemoryArrayNull(scip, &problem->bu, problem->varssize + problem->conssize); /*lint !e776 */
1287 SCIPfreeBlockMemoryArrayNull(scip, &problem->cstype, problem->conssize); /* because we assume that cstype is allocated iff bl is allocated */
1288
1289 /* gradients information is out of date now (objective gradient is stored in dense form) */
1290 SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1291 SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1292
1293 /* Hessian information is out of date now */
1294 SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1295
1296 return SCIP_OKAY;
1297} /*lint !e715*/
1298
1299/** delete a set of constraints */
1300static
1301SCIP_DECL_NLPIDELCONSSET(nlpiDelConstraintSetFilterSQP)
1302{
1303 assert(nlpi != NULL);
1304 assert(problem != NULL);
1305 assert(problem->oracle != NULL);
1306
1307 SCIP_CALL( SCIPnlpiOracleDelConsSet(scip, problem->oracle, dstats) );
1308
1309 invalidateSolution(problem);
1310 problem->warmstart = FALSE;
1311
1312 SCIPfreeBlockMemoryArrayNull(scip, &problem->bl, problem->varssize + problem->conssize); /*lint !e776 */
1313 SCIPfreeBlockMemoryArrayNull(scip, &problem->bu, problem->varssize + problem->conssize); /*lint !e776 */
1314 SCIPfreeBlockMemoryArrayNull(scip, &problem->cstype, problem->conssize); /* because we assume that cstype is allocated iff bl is allocated */
1315
1316 /* gradients information is out of date now */
1317 SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1318 SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1319
1320 /* Hessian information is out of date now */
1321 SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1322
1323 return SCIP_OKAY;
1324} /*lint !e715*/
1325
1326/** changes (or adds) linear coefficients in a constraint or objective */
1327static
1328SCIP_DECL_NLPICHGLINEARCOEFS(nlpiChgLinearCoefsFilterSQP)
1329{
1330 assert(nlpi != NULL);
1331 assert(problem != NULL);
1332 assert(problem->oracle != NULL);
1333
1334 SCIP_CALL( SCIPnlpiOracleChgLinearCoefs(scip, problem->oracle, idx, nvals, varidxs, vals) );
1335
1336 invalidateSolution(problem);
1337
1338 /* gradients information (la,a) may have changed if elements were added or removed
1339 * (we only care that sparsity doesn't change, not about actual values in a)
1340 * TODO free only if coefficients were added or removed (SCIPnlpiOracleChgLinearCoefs() could give feedback)
1341 */
1342 SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1343 SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1344
1345 /* Hessian information should still be ok */
1346
1347 return SCIP_OKAY;
1348} /*lint !e715*/
1349
1350/** replaces the expression of a constraint or objective */
1351static
1352SCIP_DECL_NLPICHGEXPR(nlpiChgExprFilterSQP)
1353{
1354 assert(nlpi != NULL);
1355 assert(problem != NULL);
1356 assert(problem->oracle != NULL);
1357
1358 SCIP_CALL( SCIPnlpiOracleChgExpr(scip, problem->oracle, idxcons, expr) );
1359
1360 invalidateSolution(problem);
1361
1362 /* update constraint linearity in FilterSQP data, as we might have changed from linear to nonlinear now */
1363 if( problem->cstype != NULL && idxcons >= 0 )
1364 problem->cstype[idxcons] = expr != NULL ? 'N' : 'L';
1365
1366 /* gradients information (la,a) may have changed */
1367 SCIPfreeBlockMemoryArrayNull(scip, &problem->a, problem->la != NULL ? problem->la[0]-1 : 0);
1368 SCIPfreeBlockMemoryArrayNull(scip, &problem->la, problem->lasize);
1369
1370 /* Hessian information may have changed */
1371 SCIPfreeBlockMemoryArrayNull(scip, &problem->hessiannz, problem->hessiannzsize);
1372
1373 return SCIP_OKAY;
1374} /*lint !e715*/
1375
1376/** change the constant offset in the objective */
1377static
1378SCIP_DECL_NLPICHGOBJCONSTANT(nlpiChgObjConstantFilterSQP)
1379{
1380 assert(nlpi != NULL);
1381 assert(problem != NULL);
1382 assert(problem->oracle != NULL);
1383
1384 SCIP_CALL( SCIPnlpiOracleChgObjConstant(scip, problem->oracle, objconstant) );
1385
1386 invalidateSolution(problem);
1387
1388 return SCIP_OKAY;
1389} /*lint !e715*/
1390
1391/** sets initial guess for primal variables */
1392static
1393SCIP_DECL_NLPISETINITIALGUESS(nlpiSetInitialGuessFilterSQP)
1394{
1395 assert(nlpi != NULL);
1396 assert(problem != NULL);
1397 assert(problem->oracle != NULL);
1398
1399 if( primalvalues != NULL )
1400 {
1401 if( problem->initguess == NULL )
1402 {
1403 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->initguess, problem->varssize) );
1404 }
1405 assert(SCIPnlpiOracleGetNVars(problem->oracle) <= problem->varssize);
1406 BMScopyMemoryArray(problem->initguess, primalvalues, SCIPnlpiOracleGetNVars(problem->oracle));
1407 }
1408 else
1409 {
1410 SCIPfreeBlockMemoryArrayNull(scip, &problem->initguess, problem->varssize);
1411 }
1412
1413 return SCIP_OKAY;
1414} /*lint !e715*/
1415
1416/** tries to solve NLP */
1417static
1418SCIP_DECL_NLPISOLVE(nlpiSolveFilterSQP)
1419{
1420 SCIP_NLPIDATA* data;
1421 SCIP_Bool success;
1422 fint n;
1423 fint m;
1424 fint kmax;
1425 fint maxa;
1426 fint maxf;
1427 fint mlp;
1428 fint lh1;
1429 fint nout;
1430 fint ifail;
1431 fint maxiter;
1432 fint iprint;
1433 real rho;
1434 real f;
1435 real* user;
1436 fint* iuser;
1437 ftnlen cstype_len = 1;
1438 fint minmxwk;
1439 fint minmxiwk;
1440 int nruns;
1441 int i;
1442
1443 SCIPdebugMsg(scip, "solve with parameters " SCIP_NLPPARAM_PRINT(param));
1444
1445 data = SCIPnlpiGetData(nlpi);
1446 assert(data != NULL);
1447
1448 SCIP_CALL( SCIPnlpiOracleResetEvalTime(scip, problem->oracle) );
1449
1450 if( param.timelimit == 0.0 )
1451 {
1452 /* there is nothing we can do if we are not given any time */
1453 problem->niterations = 0;
1454 problem->solvetime = 0.0;
1455 problem->termstat = SCIP_NLPTERMSTAT_TIMELIMIT;
1456 problem->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1457
1458 return SCIP_OKAY;
1459 }
1460
1461 /* start measuring time */
1462 data->starttime = gettime();
1463
1464 SCIP_CALL( handleNlpParam(scip, problem, param) );
1465
1466 iprint = param.verblevel;
1467
1468 /* if warmstart parameter is disabled, then we will not warmstart */
1469 if( !param.warmstart )
1470 problem->warmstart = FALSE;
1471
1472 n = SCIPnlpiOracleGetNVars(problem->oracle);
1473 m = SCIPnlpiOracleGetNConstraints(problem->oracle);
1474 kmax = n; /* maximal nullspace dimension */
1475 maxf = 100; /* maximal filter length */
1476 mlp = 100; /* maximum level of degeneracy */
1477
1478 /* TODO eventually, the output should be redirected to the message handler,
1479 * but even to just redirect to some other file, we would have to open the output-unit in Fortran
1480 */
1481 nout = 6; /* output to stdout for now */
1482 ifail = problem->warmstart ? -1 : 0; /* -1 for warmstart, otherwise 0 */
1483 rho = 10.0; /* initial trust-region radius */
1484
1485 user = (real*)data;
1486 iuser = (fint*)problem;
1487 if( problem->warmstart ) /* if warmstart, then need to keep istat[0] */
1488 memset(problem->istat+1, 0, sizeof(problem->istat)-sizeof(*problem->istat));
1489 else
1490 memset(problem->istat, 0, sizeof(problem->istat));
1491 memset(problem->rstat, 0, sizeof(problem->rstat));
1492 problem->niterations = 0;
1493
1494 if( problem->x == NULL )
1495 {
1496 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->x, problem->varssize) );
1497 }
1498 if( problem->c == NULL )
1499 {
1500 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->c, problem->conssize) );
1501 }
1502 if( problem->lam == NULL )
1503 {
1504 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &problem->lam, problem->varssize + problem->conssize) ); /*lint !e776 */
1505 }
1506 else
1507 {
1508 BMSclearMemoryArray(problem->lam, problem->varssize + problem->conssize);
1509 }
1510 if( problem->s == NULL )
1511 {
1512 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->s, problem->varssize + problem->conssize) );
1513 }
1514
1515 if( problem->la == NULL )
1516 {
1517 /* allocate la, a and initialize la for Objective Gradient and Jacobian */
1518 SCIP_CALL( setupGradients(scip, problem->oracle, &problem->la, &problem->lasize, &problem->a) );
1519 }
1520 /* maximal number entries in a = nvars+nnz */
1521 maxa = problem->la[0]-1;
1522
1523 if( problem->hessiannz == NULL )
1524 {
1525 /* allocate and initialize problem->hessiannz for Hessian */
1526 SCIP_CALL( setupHessian(scip, problem->oracle, &problem->hessiannz, &problem->hessiannzsize) );
1527 }
1528
1529 /* setup variable bounds, constraint sides, and constraint types */
1530 if( problem->bl == NULL )
1531 {
1532 assert(problem->bu == NULL);
1533 assert(problem->cstype == NULL);
1534
1535 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->bl, problem->varssize + problem->conssize) );
1536 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->bu, problem->varssize + problem->conssize) );
1537 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->cstype, problem->conssize) );
1538
1539 BMScopyMemoryArray(problem->bl, SCIPnlpiOracleGetVarLbs(problem->oracle), n);
1540 BMScopyMemoryArray(problem->bu, SCIPnlpiOracleGetVarUbs(problem->oracle), n);
1541 for( i = 0; i < m; ++i )
1542 {
1543 problem->bl[n+i] = SCIPnlpiOracleGetConstraintLhs(problem->oracle, i);
1544 problem->bu[n+i] = SCIPnlpiOracleGetConstraintRhs(problem->oracle, i);
1545 problem->cstype[i] = SCIPnlpiOracleIsConstraintNonlinear(problem->oracle, i) ? 'N' : 'L';
1546 }
1547 }
1548
1549 /* buffer for evaluation results (used in setupStart already) */
1550 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &problem->evalbuffer, &problem->evalbufsize, MAX3(n, problem->hessiannz[0], maxa)) );
1551
1552 /* setup starting point */
1553 SCIP_CALL( setupStart(data, problem, problem->x, &success) );
1554 if( !success )
1555 {
1556 /* FilterSQP would crash if starting point cannot be evaluated, so give up */
1557 SCIP_CALL( processSolveOutcome(data, problem, 7, param.feastol, param.opttol, NULL, NULL) );
1558 return SCIP_OKAY;
1559 }
1560
1561 /* setup workspace */
1562 /* initial guess of real workspace size */
1563 /* FilterSQP manual: mxwk = 21*n + 8*m + mlp + 8*maxf + kmax*(kmax+9)/2 + nprof, with nprof = 20*n as a good guess */
1564 /* Bonmin: mxwk = 21*n + 8*m + mlp + 8*maxf + lh1 + kmax*(kmax+9)/2 + mxwk0,
1565 * with lh1 = nnz_h+8+2*n+m and mxwk0 = 2000000 (parameter) */
1566 lh1 = problem->hessiannz[0]-1 + 8 + 2*n + m;
1567 minmxwk = 21*n + 8*m + mlp + 8*maxf + lh1 + kmax*(kmax+9)/2 + MAX(20*n,2000);
1568 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &problem->ws, &problem->mxwk, minmxwk) );
1569
1570 /* initial guess of integer workspace size */
1571 /* FilterSQP manual: mxiwk = 13*n + 4*m + mlp + 100 + kmax */
1572 /* Bonmin: mxiwk = 13*n + 4*m + mlp + lh1 + kmax + 113 + mxiwk0, with mxiwk0 = 500000 (parameter) */
1573 minmxiwk = 13*n + 4*m + mlp + lh1 + 100 + kmax + 113 + MAX(5*n,5000);
1574 if( !problem->warmstart ) /* if warmstart, then lws should remain untouched (n and m didn't change anyway) */
1575 {
1576 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &problem->lws, &problem->mxiwk, minmxiwk) );
1577 }
1578 assert(problem->lws != NULL);
1579 /* in case of some evalerrors, not clearing ws could lead to valgrind warnings about use of uninitialized memory */
1580 BMSclearMemoryArray(problem->ws, problem->mxwk);
1581
1582 /* from here on we are not thread-safe: if intended for multithread use, then protect filtersqp call with mutex
1583 * NOTE: we need to make sure that we do not return from nlpiSolve before unlocking the mutex
1584 */
1585#ifdef SCIP_THREADSAFE
1586 (void) pthread_mutex_lock(&filtersqpmutex);
1587#endif
1588
1589 /* initialize global variables from filtersqp */
1590 /* FilterSQP eps is tolerance for both feasibility and optimality, and also for trust-region radius, etc. */
1591 F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps = MIN(param.feastol, param.opttol * OPTTOLFACTOR);
1592 F77_FUNC(nlp_eps_inf,NLP_EPS_INF).infty = SCIPinfinity(scip);
1593 F77_FUNC(ubdc,UBDC).ubd = 100.0;
1594 F77_FUNC(ubdc,UBDC).tt = 1.25;
1595 F77_FUNC(scalec,SCALEC).scale_mode = 0;
1596
1597 for( nruns = 1; ; ++nruns )
1598 {
1599 maxiter = param.iterlimit - problem->niterations;
1600
1601 F77_FUNC(filtersqp,FILTERSQP)(
1602 &n, &m, &kmax, &maxa,
1603 &maxf, &mlp, &problem->mxwk, &problem->mxiwk,
1604 &iprint, &nout, &ifail, &rho,
1605 problem->x, problem->c, &f, &problem->fmin, problem->bl,
1606 problem->bu, problem->s, problem->a, problem->la, problem->ws,
1607 problem->lws, problem->lam, problem->cstype, user,
1608 iuser, &maxiter, problem->istat,
1609 problem->rstat, cstype_len);
1610
1611 problem->niterations += problem->istat[1];
1612
1613 assert(ifail <= 10);
1614 /* if ifail >= 8 (probably the workspace was too small), then retry with larger workspace
1615 * if ifail == 0 (local optimal), but absolute violation of KKT too large, then retry with small eps
1616 */
1617 if( ifail < 8 && (ifail != 0 || problem->rstat[0] <= param.opttol) )
1618 break;
1619
1620 if( param.verblevel > 0 )
1621 {
1622 SCIPinfoMessage(scip, NULL, "FilterSQP terminated with status %d in run %d, absolute KKT violation is %g\n", ifail, nruns, problem->rstat[0]);
1623 }
1624
1625 /* if iteration or time limit exceeded or solve is interrupted, then don't retry */
1626 if( problem->niterations >= param.iterlimit || SCIPisSolveInterrupted(scip) || timelimitreached(data, problem) )
1627 {
1628 if( param.verblevel > 0 )
1629 {
1630 SCIPinfoMessage(scip, NULL, "Time or iteration limit reached or interrupted, not retrying\n");
1631 }
1632 break;
1633 }
1634
1635 /* if maximal number of runs reached, then stop */
1636 if( nruns >= MAXNRUNS )
1637 {
1638 if( param.verblevel > 0 )
1639 {
1640 SCIPinfoMessage(scip, NULL, "Run limit reached, not retrying\n");
1641 }
1642 break;
1643 }
1644
1645 if( ifail == 0 )
1646 {
1647 SCIP_Real epsfactor;
1648
1649 if( F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps <= MINEPS )
1650 {
1651 if( param.verblevel > 0 )
1652 {
1653 SCIPinfoMessage(scip, NULL, "Already reached minimal epsilon, not retrying\n");
1654 }
1655 break;
1656 }
1657
1658 epsfactor = param.opttol / problem->rstat[0];
1659 assert(epsfactor < 1.0); /* because of the if's above */
1660 epsfactor *= OPTTOLFACTOR;
1661
1662 F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps = MAX(MINEPS, F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps * epsfactor);
1663 if( param.verblevel > 0 )
1664 {
1665 SCIPinfoMessage(scip, NULL, "Continue with eps = %g\n", F77_FUNC(nlp_eps_inf,NLP_EPS_INF).eps);
1666 }
1667 ifail = -1; /* do warmstart */
1668
1669 continue;
1670 }
1671
1672 /* increase real workspace, if ifail = 9 (real workspace too small) or ifail = 8 (unexpected ifail from QP solver, often also when workspace too small) */
1673 if( ifail == 8 || ifail == 9 )
1674 {
1675 int newsize = SCIPcalcMemGrowSize(scip, WORKSPACEGROWTHFACTOR*problem->mxwk);
1676 if( BMSreallocBlockMemoryArray(SCIPblkmem(scip), &problem->ws, problem->mxwk, newsize) == NULL )
1677 {
1678 /* realloc failed: give up NLP solve */
1679 problem->mxwk = 0;
1680 break;
1681 }
1682 problem->mxwk = newsize;
1683 }
1684
1685 /* increase integer workspace, if ifail = 10 (integer workspace too small) or ifail = 8 (unexpected ifail from QP solver, often also when workspace too small) */
1686 if( ifail == 8 || ifail == 10 )
1687 {
1688 int newsize = SCIPcalcMemGrowSize(scip, WORKSPACEGROWTHFACTOR*problem->mxiwk);
1689 if( BMSreallocBlockMemoryArray(SCIPblkmem(scip), &problem->lws, problem->mxiwk, newsize) == NULL )
1690 {
1691 /* realloc failed: give up NLP solve */
1692 problem->mxiwk = 0;
1693 break;
1694 }
1695 problem->mxiwk = newsize;
1696
1697 /* better don't try warmstart for the next trial; warmstart requires that lws is untouched, does extending count as touching? */
1698 ifail = 0;
1699 }
1700
1701 /* reset starting point, in case it was overwritten by failed solve (return can only be SCIP_OKAY, because randnumgen must exist already)
1702 * 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)
1703 * However, as no point was given, it shouldn't matter which point we actually start from.
1704 */
1705 (void) setupStart(data, problem, problem->x, &success);
1706 assert(success);
1707 }
1708
1709#ifdef SCIP_THREADSAFE
1710 (void) pthread_mutex_unlock(&filtersqpmutex);
1711#endif
1712
1713 SCIP_CALL( processSolveOutcome(data, problem, ifail, param.feastol, param.opttol, problem->x, problem->lam) );
1714
1715 return SCIP_OKAY; /*lint !e527*/
1716} /*lint !e715*/
1717
1718/** gives solution status */
1719static
1720SCIP_DECL_NLPIGETSOLSTAT(nlpiGetSolstatFilterSQP)
1721{
1722 assert(problem != NULL);
1723
1724 return problem->solstat;
1725} /*lint !e715*/
1726
1727/** gives termination reason */
1728static
1729SCIP_DECL_NLPIGETTERMSTAT(nlpiGetTermstatFilterSQP)
1730{
1731 assert(problem != NULL);
1732
1733 return problem->termstat;
1734} /*lint !e715*/
1735
1736/** gives primal and dual solution values */
1737static
1738SCIP_DECL_NLPIGETSOLUTION(nlpiGetSolutionFilterSQP)
1739{
1740 assert(problem != NULL);
1741
1742 if( primalvalues != NULL )
1743 {
1744 assert(problem->primalvalues != NULL);
1745
1746 *primalvalues = problem->primalvalues;
1747 }
1748
1749 if( consdualvalues != NULL )
1750 {
1751 assert(problem->consdualvalues != NULL);
1752
1753 *consdualvalues = problem->consdualvalues;
1754 }
1755
1756 if( varlbdualvalues != NULL )
1757 {
1758 assert(problem->varlbdualvalues != NULL);
1759
1760 *varlbdualvalues = problem->varlbdualvalues;
1761 }
1762
1763 if( varubdualvalues != NULL )
1764 {
1765 assert(problem->varubdualvalues != NULL);
1766
1767 *varubdualvalues = problem->varubdualvalues;
1768 }
1769
1770 if( objval != NULL )
1771 {
1772 if( problem->primalvalues != NULL )
1773 {
1774 /* TODO store last solution value instead of reevaluating the objective function */
1775 SCIP_CALL( SCIPnlpiOracleEvalObjectiveValue(scip, problem->oracle, problem->primalvalues, objval) );
1776 }
1777 else
1778 *objval = SCIP_INVALID;
1779 }
1780
1781 return SCIP_OKAY; /*lint !e527*/
1782} /*lint !e715*/
1783
1784/** gives solve statistics */
1785static
1786SCIP_DECL_NLPIGETSTATISTICS(nlpiGetStatisticsFilterSQP)
1787{
1788 assert(problem != NULL);
1789 assert(statistics != NULL);
1790
1791 statistics->niterations = problem->niterations;
1792 statistics->totaltime = problem->solvetime;
1793 statistics->evaltime = SCIPnlpiOracleGetEvalTime(scip, problem->oracle);
1794 statistics->consviol = problem->rstat[4];
1795 statistics->boundviol = 0.0;
1796
1797 return SCIP_OKAY; /*lint !e527*/
1798} /*lint !e715*/
1799
1800/*
1801 * NLP solver interface specific interface methods
1802 */
1803
1804/** create solver interface for filterSQP solver and include it into SCIP, if filterSQP is available */
1806 SCIP* scip /**< SCIP data structure */
1807 )
1808{
1809 SCIP_NLPIDATA* nlpidata;
1810
1811 /* create filterSQP solver interface data */
1813
1814 /* create solver interface */
1817 nlpiCopyFilterSQP, nlpiFreeFilterSQP, NULL,
1818 nlpiCreateProblemFilterSQP, nlpiFreeProblemFilterSQP, NULL,
1819 nlpiAddVarsFilterSQP, nlpiAddConstraintsFilterSQP, nlpiSetObjectiveFilterSQP,
1820 nlpiChgVarBoundsFilterSQP, nlpiChgConsSidesFilterSQP, nlpiDelVarSetFilterSQP, nlpiDelConstraintSetFilterSQP,
1821 nlpiChgLinearCoefsFilterSQP, nlpiChgExprFilterSQP,
1822 nlpiChgObjConstantFilterSQP, nlpiSetInitialGuessFilterSQP, nlpiSolveFilterSQP, nlpiGetSolstatFilterSQP, nlpiGetTermstatFilterSQP,
1823 nlpiGetSolutionFilterSQP, nlpiGetStatisticsFilterSQP,
1824 nlpidata) );
1825
1827
1828 return SCIP_OKAY;
1829}
1830
1831/** gets string that identifies filterSQP */
1833 void
1834 )
1835{
1836 return "filterSQP"; /* TODO version number? */
1837}
1838
1839/** gets string that describes filterSQP */
1841 void
1842 )
1843{
1844 return NLPI_DESC;
1845}
1846
1847/** returns whether filterSQP is available, i.e., whether it has been linked in */
1849 void
1850 )
1851{
1852 return TRUE;
1853}
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** x
Definition: circlepacking.c:63
#define NULL
Definition: def.h:248
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define MAX3(x, y, z)
Definition: def.h:228
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_REAL_MIN
Definition: def.h:159
#define SCIP_CALL(x)
Definition: def.h:355
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:2124
SCIP_RETCODE SCIPnlpiOracleChgLinearCoefs(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, int nentries, const int *varidxs, const SCIP_Real *newcoefs)
Definition: nlpioracle.c:1774
SCIP_RETCODE SCIPnlpiOracleGetJacobianRowSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **rowoffsets, const int **cols, const SCIP_Bool **colnlflags, int *nnlnz)
Definition: nlpioracle.c:2264
SCIP_RETCODE SCIPnlpiOracleGetHessianLagSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **offset, const int **allnz, SCIP_Bool colwise)
Definition: nlpioracle.c:2670
SCIP_RETCODE SCIPnlpiOracleChgVarBounds(SCIP *scip, SCIP_NLPIORACLE *oracle, int nvars, const int *indices, const SCIP_Real *lbs, const SCIP_Real *ubs)
Definition: nlpioracle.c:1474
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:1384
SCIP_Bool SCIPnlpiOracleIsConstraintNonlinear(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:2084
SCIP_RETCODE SCIPnlpiOracleDelVarSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
Definition: nlpioracle.c:1546
SCIP_RETCODE SCIPnlpiOracleCreate(SCIP *scip, SCIP_NLPIORACLE **oracle)
Definition: nlpioracle.c:1200
SCIP_RETCODE SCIPnlpiOracleEvalObjectiveGradient(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx, SCIP_Real *objval, SCIP_Real *objgrad)
Definition: nlpioracle.c:2205
SCIP_RETCODE SCIPnlpiOracleResetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:2821
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:1445
SCIP_Real SCIPnlpiOracleGetConstraintRhs(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:2038
SCIP_Real SCIPnlpiOracleGetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:2837
SCIP_RETCODE SCIPnlpiOracleChgConsSides(SCIP *scip, SCIP_NLPIORACLE *oracle, int nconss, const int *indices, const SCIP_Real *lhss, const SCIP_Real *rhss)
Definition: nlpioracle.c:1511
SCIP_Real SCIPnlpiOracleGetConstraintLhs(SCIP_NLPIORACLE *oracle, int considx)
Definition: nlpioracle.c:2025
SCIP_RETCODE SCIPnlpiOracleAddVars(SCIP *scip, SCIP_NLPIORACLE *oracle, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
Definition: nlpioracle.c:1298
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, SCIP_Bool colwise)
Definition: nlpioracle.c:2770
int SCIPnlpiOracleGetNVars(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1933
int SCIPnlpiOracleGetNConstraints(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1943
SCIP_RETCODE SCIPnlpiOracleEvalJacobian(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx, SCIP_Real *convals, SCIP_Real *jacobi)
Definition: nlpioracle.c:2543
SCIP_RETCODE SCIPnlpiOracleDelConsSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
Definition: nlpioracle.c:1688
SCIP_RETCODE SCIPnlpiOracleSetProblemName(SCIP *scip, SCIP_NLPIORACLE *oracle, const char *name)
Definition: nlpioracle.c:1262
SCIP_RETCODE SCIPnlpiOracleChgObjConstant(SCIP *scip, SCIP_NLPIORACLE *oracle, SCIP_Real objconstant)
Definition: nlpioracle.c:1916
SCIP_RETCODE SCIPnlpiOracleEvalConstraintValue(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, const SCIP_Real *x, SCIP_Real *conval)
Definition: nlpioracle.c:2149
const SCIP_Real * SCIPnlpiOracleGetVarLbs(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1953
const SCIP_Real * SCIPnlpiOracleGetVarUbs(SCIP_NLPIORACLE *oracle)
Definition: nlpioracle.c:1963
SCIP_RETCODE SCIPnlpiOracleFree(SCIP *scip, SCIP_NLPIORACLE **oracle)
Definition: nlpioracle.c:1230
SCIP_RETCODE SCIPnlpiOracleChgExpr(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, SCIP_EXPR *expr)
Definition: nlpioracle.c:1870
const char * SCIPgetSolverDescFilterSQP(void)
const char * SCIPgetSolverNameFilterSQP(void)
SCIP_Bool SCIPisFilterSQPAvailableFilterSQP(void)
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:769
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:91
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#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:113
SCIP_NLPIDATA * SCIPnlpiGetData(SCIP_NLPI *nlpi)
Definition: nlpi.c:712
SCIP_Bool SCIPisSolveInterrupted(SCIP *scip)
Definition: scip_solve.c:3580
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:10245
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
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
#define SCIPisFinite(x)
Definition: pub_misc.h:82
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
Definition: nlpi_conopt.c:78
SCIP_Real solvetime
Definition: nlpi_conopt.c:86
SCIP_NLPTERMSTAT termstat
Definition: nlpi_conopt.c:85
SCIP_Real * consdualvalues
SCIP_Real * varlbdualvalues
SCIP_Real * initguess
Definition: nlpi_conopt.c:82
SCIP_NLPSOLSTAT solstat
Definition: nlpi_conopt.c:84
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:184
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