SCIP Doxygen Documentation
 
Loading...
Searching...
No Matches
nlpi_worhp.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-2023 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_worhp.c
26 * @ingroup DEFPLUGINS_NLPI
27 * @brief Worhp NLP interface
28 * @author Benjamin Mueller
29 * @author Renke Kuhlmann
30 *
31 * @todo So far, Worhp can not handle the case that variables have been fixed before warm-starting. Remove the code in
32 * nlpiChgVarBoundsWorhp when this has changed.
33 */
34
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
37#include "scip/nlpi_worhp.h"
38#include "scip/nlpioracle.h"
39#include "scip/exprinterpret.h"
40#include "scip/interrupt.h"
41#include "scip/scip_nlpi.h"
42#include "scip/scip_general.h"
43#include "scip/scip_message.h"
44#include "scip/scip_mem.h"
45#include "scip/scip_numerics.h"
47#include "scip/scip_solve.h"
48#include "scip/pub_misc.h"
49
50#include <stdio.h>
51#include <stdlib.h>
52
53#include "worhp/worhp.h"
54
55#if WORHP_MAJOR < 2 && WORHP_MINOR < 10
56#error "Require at least Worhp 1.10"
57#endif
58
59#define NLPI_DESC "Worhp interface" /**< description of solver */
60#define NLPI_PRIORITY_IP 0 /**< priority of NLP solver (Interior Point) */
61#define NLPI_PRIORITY_SQP -2000 /**< priority of NLP solver (SQP) */
62
63#define DEFAULT_VERBLEVEL 0 /**< default verbosity level (0: normal 1: full 2: debug >2: more debug) */
64#define DEFAULT_SCALEDKKT TRUE /**< default whether KKT conditions are allowed to be scaled in the solver */
65#define DEFAULT_RANDSEED 107 /**< initial random seed */
66
67#define MAXPERTURB 0.01 /**< maximal perturbation of bounds in starting point heuristic */
68
69/*
70 * Data structures
71 */
72
73struct SCIP_NlpiData
74{
75 SCIP_Bool useip; /**< should the Interior Point solver of Worhp be used? */
76};
77
79{
80 SCIP_NLPIORACLE* oracle; /**< Oracle-helper to store and evaluate NLP */
81 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
82
83 SCIP_NLPTERMSTAT lasttermstat; /**< termination status from last run */
84 SCIP_NLPSOLSTAT lastsolstat; /**< solution status from last run */
85 SCIP_Real lasttime; /**< time spend in last run */
86 int lastniter; /**< number of iterations in last run */
87
88 SCIP_Real* lastprimal; /**< primal solution from last run, if available */
89 SCIP_Real* lastdualcons; /**< dual solution from last run, if available */
90 SCIP_Real* lastduallb; /**< dual solution for lower bounds from last run, if available */
91 SCIP_Real* lastdualub; /**< dual solution for upper bounds from last run, if available */
92 int lastprimalsize; /**< size of lastprimal array */
93 int lastdualconssize; /**< size of lastdualcons array */
94 int lastduallbsize; /**< size of lastduallb array */
95 int lastdualubsize; /**< size of lastdualub array */
96
97 SCIP_Bool firstrun; /**< whether the next NLP solve will be the first one (with the current problem structure) */
98 SCIP_Real* initguess; /**< initial values for primal variables, or NULL if not known */
99
100 /* Worhp data structures */
101 OptVar* opt; /**< Worhp variables */
102 Workspace* wsp; /**< Worhp working space */
103 Params* par; /**< Worhp parameters */
104 Control* cnt; /**< Worhp control */
105};
106
107/*
108 * Local methods
109 */
110
111/** clears the last solution information */
112static
114 SCIP* scip, /**< SCIP data structure */
115 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
116 )
117{
118 assert(problem != NULL);
119
124
125 problem->lastprimalsize = 0;
126 problem->lastdualconssize = 0;
127 problem->lastduallbsize = 0;
128 problem->lastdualubsize = 0;
131}
132
133/** evaluate last Worhp run */
134static
136 SCIP* scip, /**< SCIP data structure */
137 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
138 )
139{
140 int i;
141
142 assert(problem != NULL);
143 assert(problem->opt != NULL);
144 assert(problem->wsp != NULL);
145 assert(problem->par != NULL);
146 assert(problem->cnt != NULL);
147
148 switch( problem->cnt->status )
149 {
150 case InitError:
151 {
152 /* initialization error */
153 SCIPdebugMsg(scip, "Worhp failed because of initialization error!\n");
154 invalidateSolution(scip, problem);
157 break;
158 }
159
160 case DataError:
161 {
162 /* data error */
163 SCIPdebugMsg(scip, "Worhp failed because of data error!\n");
164 invalidateSolution(scip, problem);
167 break;
168 }
169
170 case LicenseError:
171 {
172 /* license error */
173 SCIPerrorMessage("Worhp failed because of license error!\n");
174 invalidateSolution(scip, problem);
177 break;
178 }
179
180 case evalsNaN:
181 {
182 /* evaluation errors */
183 SCIPdebugMsg(scip, "Worhp failed because of a NaN value in an evaluation!\n");
184 invalidateSolution(scip, problem);
187 break;
188 }
189
190 case QPerror:
191 case MinimumStepsize:
192 case TooBig:
194 {
195 /* numerical errors during solution of NLP */
196 SCIPdebugMsg(scip, "Worhp failed because of a numerical error during optimization!\n");
197 invalidateSolution(scip, problem);
200 break;
201 }
202
203 case MaxCalls:
204 case MaxIter:
205 {
206 /* maximal number of calls or iteration */
207 SCIPdebugMsg(scip, "Worhp failed because maximal number of calls or iterations is reached!\n");
208 invalidateSolution(scip, problem);
211 break;
212 }
213
214 case Timeout:
215 {
216 /* time limit reached */
217 SCIPdebugMsg(scip, "Worhp failed because time limit is reached!\n");
218 invalidateSolution(scip, problem);
221 break;
222 }
223
224 case DivergingPrimal:
225 case DivergingDual:
226 {
227 /* iterates diverge */
228 SCIPdebugMsg(scip, "Worhp failed because of diverging iterates!\n");
229 invalidateSolution(scip, problem);
232 break;
233 }
234
235 case LocalInfeas:
237 {
238 /* infeasible stationary point found */
239 SCIPdebugMsg(scip, "Worhp failed because of convergence against infeasible stationary point!\n");
240 invalidateSolution(scip, problem);
243 break;
244 }
245
246 case GlobalInfeas:
247 {
248 /* infeasible stationary point found */
249 SCIPdebugMsg(scip, "Worhp failed because of convergence against infeasible stationary point!\n");
250 invalidateSolution(scip, problem);
253 break;
254 }
255
257 {
258 /* regularization of Hessian matrix failed */
259 SCIPdebugMsg(scip, "Worhp failed because of regularization of Hessian matrix failed!\n");
260 invalidateSolution(scip, problem);
263 break;
264 }
265
266 case OptimalSolution:
267 {
268 /* everything went fine */
269 SCIPdebugMsg(scip, "Worhp terminated successfully at a local optimum!\n");
272 break;
273 }
274
276 {
277 /* feasible point, KKT conditions are not satisfied, and Worhp thinks that there is no objective function */
278 SCIPdebugMsg(scip, "Worhp terminated successfully with a feasible point but KKT are not met!\n");
281 break;
282 }
283
287 {
288 /* feasible point but KKT conditions are violated in unscaled space */
289 SCIPdebugMsg(scip, "Worhp terminated successfully with a feasible point but KKT are violated in unscaled space!\n");
292 break;
293 }
294
296 {
297 /* feasible and no further progress */
298 SCIPdebugMsg(scip, "Worhp terminated at feasible solution without further progress!\n");
301 break;
302 }
303
304 case FeasibleSolution:
305 {
306 /* feasible and in feasibility mode, i.e., optimality not required */
307 SCIPdebugMsg(scip, "Worhp terminated at feasible solution, optimality was not required!\n");
310 break;
311 }
312
315 {
316 /* acceptable solution found, but stopped due to limit or error */
317 SCIPdebugMsg(scip, "Worhp terminated at acceptable solution due to limit or error!\n");
320 break;
321 }
322
325 {
326 /* previously acceptable solution was found, but stopped due to limit or error */
327 SCIPdebugMsg(scip, "Worhp previously found acceptable solution but terminated due to limit or error!\n");
330 break;
331 }
332
334 {
335 /* acceptable solution found, and no further progress */
336 SCIPdebugMsg(scip, "Worhp found acceptable solution but terminated due no further progress!\n");
339 break;
340 }
341
344 {
345 /* acceptable solution found, but search direction is small or zero */
346 SCIPdebugMsg(scip, "Worhp found acceptable solution but search direction is small or zero!\n");
349 break;
350 }
351
352 case FritzJohn:
353 case NotDiffable:
354 case Unbounded:
355 {
356 /* acceptable solution found, but not optimal */
357 SCIPdebugMsg(scip, "Worhp found acceptable solution but terminated perhaps due to nondifferentiability, unboundedness or at Fritz John point!\n");
360 break;
361 }
362
363 default:
364 {
365 SCIPerrorMessage("Worhp returned with unknown solution status %d\n", problem->cnt->status);
368 return SCIP_OKAY;
369 }
370 }
371
372 /* store solution */
373 if( problem->lastprimal == NULL )
374 {
375 if( problem->opt->m > 0 )
376 {
377 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &problem->lastdualcons, problem->opt->Mu, problem->opt->m) );
378 problem->lastdualconssize = problem->opt->m;
379 }
380
381 if( problem->opt->n > 0 )
382 {
383 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &problem->lastprimal, problem->opt->X, problem->opt->n) );
384 problem->lastprimalsize = problem->opt->n;
385
386 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->lastduallb, problem->opt->n) );
387 problem->lastduallbsize = problem->opt->n;
388
389 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &problem->lastdualub, problem->opt->n) );
390 problem->lastdualubsize = problem->opt->n;
391 }
392 }
393 else
394 {
395 BMScopyMemoryArray(problem->lastprimal, problem->opt->X, problem->opt->n);
396 BMScopyMemoryArray(problem->lastdualcons, problem->opt->Mu, problem->opt->m);
397 }
398
399 for( i = 0; i < problem->opt->n; ++i )
400 {
401 if( problem->opt->Lambda[i] <= 0.0 )
402 {
403 problem->lastduallb[i] = -problem->opt->Lambda[i];
404 problem->lastdualub[i] = 0.0;
405 }
406 else
407 {
408 problem->lastduallb[i] = 0.0;
409 problem->lastdualub[i] = problem->opt->Lambda[i];
410 }
411 }
412
413 assert(problem->lastprimal != NULL || problem->opt->n == 0);
414 assert(problem->lastdualcons != NULL || problem->opt->m == 0);
415 assert(problem->lastduallb != NULL || problem->opt->n == 0);
416 assert(problem->lastdualub != NULL || problem->opt->n == 0);
417
418 return SCIP_OKAY;
419}
420
421/** evaluates objective function and store the result in the corresponding Worhp data fields */
422static
424 SCIP* scip, /**< SCIP data structure */
425 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
426 )
427{
428 SCIP_Real objval;
429
430 assert(problem != NULL);
431 assert(problem->oracle != NULL);
432 assert(problem->opt != NULL);
433 assert(problem->wsp != NULL);
434 assert(problem->opt->n == SCIPnlpiOracleGetNVars(problem->oracle));
435 assert(problem->opt->m == SCIPnlpiOracleGetNConstraints(problem->oracle));
436
437 SCIP_CALL( SCIPnlpiOracleEvalObjectiveValue(scip, problem->oracle, problem->opt->X, &objval) );
438 problem->opt->F = problem->wsp->ScaleObj * objval;
439
440#ifdef SCIP_DEBUG_USERF
441 {
442 int i;
443
444 printf("userF()\n");
445 for( i = 0; i < problem->opt->n; ++i )
446 printf(" x[%d] = %g\n", i, problem->opt->X[i]);
447 printf(" obj = %g\n", problem->opt->F);
448 }
449#endif
450
451 return SCIP_OKAY;
452}
453
454/** evaluates constraints and store the result in the corresponding Worhp data fields */
455static
457 SCIP* scip, /**< SCIP data structure */
458 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
459 )
460{
461 assert(problem != NULL);
462 assert(problem->oracle != NULL);
463 assert(problem->opt != NULL);
464 assert(problem->wsp != NULL);
465 assert(problem->opt->n == SCIPnlpiOracleGetNVars(problem->oracle));
466 assert(problem->opt->m == SCIPnlpiOracleGetNConstraints(problem->oracle));
467
468 SCIP_CALL( SCIPnlpiOracleEvalConstraintValues(scip, problem->oracle, problem->opt->X, problem->opt->G) );
469
470#ifdef SCIP_DEBUG_USERG
471 {
472 int i;
473
474 printf("userG()\n");
475 for( i = 0; i < problem->opt->n; ++i )
476 printf(" x[%d] = %g\n", i, problem->opt->X[i]);
477
478 for( i = 0; i < problem->opt->m; ++i )
479 printf(" cons[%d] = %g\n", i, problem->opt->G[i]);
480 }
481#endif
482
483 return SCIP_OKAY;
484}
485
486/** computes objective gradient and store the result in the corresponding Worhp data fields */
487static
489 SCIP* scip, /**< SCIP data structure */
490 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
491 )
492{
493 SCIP_Real objval;
494
495 assert(problem != NULL);
496 assert(problem->oracle != NULL);
497 assert(problem->opt != NULL);
498 assert(problem->wsp != NULL);
499 assert(problem->opt->n == SCIPnlpiOracleGetNVars(problem->oracle));
500 assert(problem->opt->m == SCIPnlpiOracleGetNConstraints(problem->oracle));
501
502 /* TODO this needs to be changed if we store the gradient of the objective function in a sparse format */
504 problem->wsp->DF.val) );
505
506 /* scale gradient if necessary */
507 if( problem->wsp->ScaleObj != 1.0 )
508 {
509 int i;
510 for( i = 0; i < problem->opt->n; ++i )
511 problem->wsp->DF.val[i] *= problem->wsp->ScaleObj;
512 }
513
514#ifdef SCIP_DEBUG_USERDF
515 {
516 int i;
517
518 printf("userDF()\n");
519 for( i = 0; i < problem->opt->n; ++i )
520 printf(" x[%d] = %g\n", i, problem->opt->X[i]);
521
522 for( i = 0; i < problem->opt->n; ++i )
523 printf(" DF[%d] = %g\n", i, problem->wsp->DF.val[i]);
524 }
525#endif
526
527 return SCIP_OKAY;
528}
529
530/** computes jacobian matrix and store the result in the corresponding Worhp data fields */
531static
533 SCIP* scip, /**< SCIP data structure */
534 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
535 )
536{
537 SCIP_RETCODE retcode;
538 SCIP_Real* jacvals;
539
540 assert(problem != NULL);
541 assert(problem->oracle != NULL);
542 assert(problem->opt != NULL);
543 assert(problem->wsp != NULL);
544 assert(problem->opt->n == SCIPnlpiOracleGetNVars(problem->oracle));
545 assert(problem->opt->m == SCIPnlpiOracleGetNConstraints(problem->oracle));
546
547 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &jacvals, problem->wsp->DG.nnz) );
548 retcode = SCIPnlpiOracleEvalJacobian(scip, problem->oracle, problem->opt->X, TRUE, NULL, jacvals);
549
550 if( retcode == SCIP_OKAY )
551 {
552 int i;
553
554 /* map values with DG indices */
555 for( i = 0; i < problem->wsp->DG.nnz; ++i )
556 {
557 problem->wsp->DG.val[i] = jacvals[ problem->wsp->DG.perm[i]-1 ];
558 }
559
560#ifdef SCIP_DEBUG_USERDG
561 printf("userDG()\n");
562 for( i = 0; i < problem->opt->n; ++i )
563 printf(" x[%d] = %g\n", i, problem->opt->X[i]);
564 for( i = 0; i < problem->wsp->DG.nnz; ++i )
565 printf(" DG[%d] = %g\n", i, problem->wsp->DG.val[i]);
566#endif
567 }
568
569 /* free memory */
570 SCIPfreeBlockMemoryArray(scip, &jacvals, problem->wsp->DG.nnz);
571
572 return retcode;
573}
574
575/** computes hessian matrix and store the result in the corresponding Worhp data fields */
576static
578 SCIP* scip, /**< SCIP data structure */
579 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
580 )
581{
582 const int* offset;
583 SCIP_Real* hessianvals;
584 SCIP_RETCODE retcode;
585 int nnonz;
586
587 assert(problem != NULL);
588 assert(problem->oracle != NULL);
589 assert(problem->opt != NULL);
590 assert(problem->wsp != NULL);
591 assert(problem->opt->n == SCIPnlpiOracleGetNVars(problem->oracle));
592 assert(problem->opt->m == SCIPnlpiOracleGetNConstraints(problem->oracle));
593
594 /* get nonzero entries in HM of SCIP (excludes unused diagonal entries) */
596 nnonz = offset[problem->opt->n];
597
598 /* evaluate hessian */
600 retcode = SCIPnlpiOracleEvalHessianLag(scip, problem->oracle, problem->opt->X, TRUE, TRUE, problem->wsp->ScaleObj,
601 problem->opt->Mu, hessianvals);
602
603 if( retcode == SCIP_OKAY )
604 {
605 int i;
606
607 assert(problem->wsp->HM.nnz >= nnonz);
608 for( i = 0; i < problem->wsp->HM.nnz; ++i )
609 {
610 /* an entry i with HM.perm[i] - 1 >= nnonz corresponds to an in SCIP non-existing diagonal element */
611 if( problem->wsp->HM.perm[i] - 1 >= nnonz )
612 problem->wsp->HM.val[i] = 0.0;
613 else
614 problem->wsp->HM.val[i] = hessianvals[ problem->wsp->HM.perm[i] - 1 ];
615 }
616
617#ifdef SCIP_DEBUG_HM
618 printf("userHM()\n");
619 for( i = 0; i < problem->opt->n; ++i )
620 printf(" x[%d] = %g\n", i, problem->opt->X[i]);
621 for( i = 0; i < problem->wsp->HM.nnz; ++i )
622 printf(" HM[%d] = %g\n", i, problem->wsp->HM.val[i]);
623#endif
624 }
625
626 /* free memory */
627 SCIPfreeBlockMemoryArray(scip, &hessianvals, problem->wsp->HM.nnz);
628
629 return retcode;
630}
631
632/** Worhp print callback function that does nothing */ /*lint -e{715}*/
633static void noprint(
634 int mode, /**< the mode */
635 const char s[] /**< a string */
636 )
637{ /*lint --e{715}*/
638}
639
640/** initialize Worhp data */
641static
643 SCIP* scip, /**< SCIP data structure */
644 SCIP_NLPI* nlpi, /**< pointer to NLPI datastructure */
645 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
646 )
647{
648 Workspace* wsp;
649 Control* cnt;
650 OptVar* opt;
651 Params* par;
652 const SCIP_Real* lbs;
653 const SCIP_Real* ubs;
654 const int* offset;
655 const int* cols;
656 int i;
657 int j;
658
659 assert(nlpi != NULL);
660 assert(problem != NULL);
661 assert(problem->cnt != NULL);
662 assert(problem->wsp != NULL);
663 assert(problem->par != NULL);
664 assert(problem->opt != NULL);
665 assert(problem->firstrun);
666
667 wsp = problem->wsp;
668 cnt = problem->cnt;
669 opt = problem->opt;
670 par = problem->par;
671
672 /* properly zeros everything */
673 WorhpPreInit(opt, wsp, par, cnt);
674
675 /* set problem dimensions */
676 opt->n = SCIPnlpiOracleGetNVars(problem->oracle);
677 opt->m = SCIPnlpiOracleGetNConstraints(problem->oracle);
678 SCIPdebugMsg(scip, "nvars %d nconss %d\n", opt->n, opt->m);
679
680 /* assume that objective function is dense; TODO use sparse representation */
681 wsp->DF.nnz = opt->n;
682
683 /* get number of non-zero entries in Jacobian */
685 wsp->DG.nnz = offset[opt->m];
686 SCIPdebugMsg(scip, "nnonz jacobian %d\n", wsp->DG.nnz);
687
688 /* get number of non-zero entries in hessian
689 *
690 * note that Worhp wants to have the full diagonal in ANY case
691 */
693 wsp->HM.nnz = 0;
694
695 j = offset[0];
696 for( i = 0; i < opt->n; ++i )
697 {
698 /* diagonal element */
699 ++(wsp->HM.nnz);
700
701 /* strict lower triangle elements */
702 for( ; j < offset[i+1]; ++j )
703 {
704 if( i != cols[j] )
705 {
706 assert(i > cols[j]);
707 ++(wsp->HM.nnz);
708 }
709 }
710 }
711 assert(offset[opt->n] <= wsp->HM.nnz);
712 SCIPdebugMsg(scip, "nnonz hessian %d\n", wsp->HM.nnz);
713
714 /* initialize data in Worhp */
715 WorhpInit(opt, wsp, par, cnt);
716 if (cnt->status != FirstCall)
717 {
718 SCIPerrorMessage("Initialisation failed.\n");
719 return SCIP_ERROR;
720 }
721
722 /* set variable bounds */
723 lbs = SCIPnlpiOracleGetVarLbs(problem->oracle);
724 ubs = SCIPnlpiOracleGetVarUbs(problem->oracle);
725
726 BMScopyMemoryArray(opt->XL, lbs, opt->n);
727 BMScopyMemoryArray(opt->XU, ubs, opt->n);
728
729#ifdef SCIP_DEBUG
730 for( i = 0; i < opt->n; ++i )
731 {
732 SCIPdebugMsg(scip, "bounds %d [%g,%g]\n", i, opt->XL[i], opt->XU[i]);
733 }
734#endif
735
736 /* set constraint sides */
737 for( i = 0; i < opt->m; ++i )
738 {
739 opt->GL[i] = SCIPnlpiOracleGetConstraintLhs(problem->oracle, i);
740 opt->GU[i] = SCIPnlpiOracleGetConstraintRhs(problem->oracle, i);
741
742 /* adjust constraint sides when both are infinite */
743 if( SCIPisInfinity(scip, -opt->GL[i]) && SCIPisInfinity(scip, opt->GU[i]) )
744 {
745 SCIPwarningMessage(scip, "Lhs and rhs of constraint %d are infinite.\n", i);
746 opt->GL[i] = -SCIPinfinity(scip) / 10.0;
747 opt->GU[i] = SCIPinfinity(scip) / 10.0;
748 }
749
750 SCIPdebugMsg(scip, "sides %d [%g,%g]\n", i, opt->GL[i], opt->GU[i]);
751 }
752
753 /* set column indices of objective function; note that indices go from 1 to n */
754 /* if( wsp->DF.NeedStructure ) evaluates to FALSE if DF is dense */
755 {
756 SCIPdebugPrintf("column indices of objective function:");
757 for( i = 0; i < opt->n; ++i )
758 {
759 wsp->DF.row[i] = i + 1;
760 SCIPdebugPrintf(" %d", wsp->DF.row[i]);
761 }
762 SCIPdebugPrintf("\n");
763 }
764
765 /* set column and row indices of non-zero entries in Jacobian matrix */
766 /* if( wsp->DG.NeedStructure ) evaluates to FALSE if DG is dense */
767 {
768 int nnonz;
769
771 assert(offset[opt->m] == wsp->DG.nnz);
772
773 nnonz = 0;
774 j = offset[0];
775 for( i = 0; i < opt->m; ++i )
776 {
777 for( ; j < offset[i+1]; ++j )
778 {
779 wsp->DG.row[nnonz] = i + 1;
780 wsp->DG.col[nnonz] = cols[j] + 1;
781 ++nnonz;
782 }
783 }
784 assert(nnonz == wsp->DG.nnz);
785
786 /* sort arrays w.r.t the column-major order */
787 SortWorhpMatrix(&wsp->DG);
788 }
789
790 /* set column and row indices of non-zero entries in hessian matrix */
791 if( problem->par->UserHM || problem->par->FidifHM || problem->par->BFGSmethod > 1 )
792 {
793 int nnonz;
794 int k;
795
797 assert(offset[opt->n] <= wsp->HM.nnz);
798
799 k = offset[opt->n];
800 nnonz = 0;
801 j = offset[0];
802 for( i = 0; i < opt->n; ++i )
803 {
804 SCIP_Bool adddiag = TRUE;
805
806 for( ; j < offset[i+1]; ++j )
807 {
808 problem->wsp->HM.row[nnonz] = i + 1;
809 problem->wsp->HM.col[nnonz] = cols[j] + 1;
810 ++nnonz;
811
812 if( i == cols[j] )
813 adddiag = FALSE;
814 }
815
816 /* Worhp wants to have each diagonal element */
817 if( adddiag )
818 {
819 problem->wsp->HM.row[k] = i + 1;
820 problem->wsp->HM.col[k] = i + 1;
821 ++k;
822 }
823 }
824 assert(nnonz == offset[opt->n]);
825 assert(k == wsp->HM.nnz);
826
827 /* sort arrays w.r.t the LT column-major order */
828 SortWorhpMatrix(&wsp->HM);
829
830#ifdef SCIP_DEBUG
831 SCIPdebugMsg(scip, "column and row indices of hessian:\n");
832 for( i = 0; i < wsp->HM.nnz; ++i )
833 {
834 SCIPdebugMsg(scip, " entry %d: (row,col) = (%d,%d)\n", i, wsp->HM.row[i], wsp->HM.col[i]);
835 }
836#endif
837 }
838
839 return SCIP_OKAY;
840}
841
842/** update Worhp data */
843static
845 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
846 )
847{
848 const SCIP_Real* lbs;
849 const SCIP_Real* ubs;
850 int i;
851
852 assert(problem != NULL);
853 assert(problem->cnt != NULL);
854 assert(problem->wsp != NULL);
855 assert(problem->par != NULL);
856 assert(problem->opt != NULL);
857 assert(problem->oracle != NULL);
858 assert(problem->opt->n == SCIPnlpiOracleGetNVars(problem->oracle));
859 assert(problem->opt->m == SCIPnlpiOracleGetNConstraints(problem->oracle));
860
861 WorhpRestart(problem->opt, problem->wsp, problem->par, problem->cnt);
862
863 /* update variable bounds */
864 lbs = SCIPnlpiOracleGetVarLbs(problem->oracle);
865 ubs = SCIPnlpiOracleGetVarUbs(problem->oracle);
866 for( i = 0; i < problem->opt->n; ++i )
867 {
868 problem->opt->XL[i] = lbs[i];
869 problem->opt->XU[i] = ubs[i];
870 }
871
872 /* update constraint sides */
873 for( i = 0; i < problem->opt->m; ++i )
874 {
875 problem->opt->GL[i] = SCIPnlpiOracleGetConstraintLhs(problem->oracle, i);
876 problem->opt->GU[i] = SCIPnlpiOracleGetConstraintRhs(problem->oracle, i);
877 }
878
879 return SCIP_OKAY;
880}
881
882/** frees Worhp data */
883static
885 SCIP_NLPIPROBLEM* problem /**< pointer to problem data structure */
886 )
887{
888 assert(problem != NULL);
889 assert(problem->cnt != NULL);
890 assert(problem->wsp != NULL);
891 assert(problem->par != NULL);
892 assert(problem->opt != NULL);
893
894 if( problem->opt->initialised )
895 WorhpFree(problem->opt, problem->wsp, problem->par, problem->cnt);
896
897 return SCIP_OKAY;
898}
899
900/** pass NLP solve parameters to Ipopt */
901static
903 SCIP* scip, /**< SCIP data structure */
904 SCIP_NLPI* nlpi, /**< Worhp interface */
905 Params* par, /**< Worhp parameters */
906 const SCIP_NLPPARAM nlpparam /**< NLP solve parameters */
907 )
908{
909 SCIP_NLPIDATA* nlpidata;
910
911 assert(par != NULL);
912 assert(nlpi != NULL);
913
914 nlpidata = SCIPnlpiGetData(nlpi);
915 assert(nlpidata != NULL);
916
917 par->Algorithm = nlpidata->useip ? 2 : 1;
918 par->ScaledKKT = DEFAULT_SCALEDKKT;
919 par->sKKTOnlyAcceptable = DEFAULT_SCALEDKKT;
920 par->Infty = SCIPinfinity(scip);
921
922 if( nlpparam.warmstart )
923 {
924 SCIPdebugMsg(scip, "warmstart parameter not supported by Worhp interface yet. Ignored.\n");
925 }
926
927 if( nlpparam.lobjlimit > -SCIP_REAL_MAX )
928 {
929 SCIPwarningMessage(scip, "lobjlimit parameter not supported by Worhp interface yet. Ignored.\n");
930 }
931
932 if( nlpparam.fastfail )
933 {
934 SCIPdebugMsg(scip, "fastfail parameter not supported by Worhp interface yet. Ignored.\n");
935 }
936
937 par->TolFeas = nlpparam.feastol;
938 par->TolOpti = nlpparam.opttol;
939 par->TolComp = nlpparam.opttol;
940 par->Timeout = nlpparam.timelimit;
941 par->MaxIter = nlpparam.iterlimit;
942 par->NLPprint = nlpparam.verblevel - 1; /* Worhp verbosity levels: -1 = off, 0 = normal, 1 = debug, >1 = more debug */
943
944#ifdef CHECKFUNVALUES
945 /* activate gradient and hessian check */
946 par->CheckValuesDF = TRUE;
947 par->CheckValuesDG = TRUE;
948 par->CheckValuesHM = TRUE;
949#endif
950
951 return SCIP_OKAY;
952}
953
954/*
955 * Callback methods of NLP solver interface
956 */
957
958/** copy method of NLP interface (called when SCIP copies plugins) */
959static
973
974/** destructor of NLP interface to free nlpi data */
975static
977{
978 assert(nlpi != NULL);
979 assert(nlpidata != NULL);
980 assert(*nlpidata != NULL);
981
982 SCIPfreeBlockMemory(scip, nlpidata);
983 assert(*nlpidata == NULL);
984
985 return SCIP_OKAY;
986} /*lint !e715*/
987
988/** creates a problem instance */
989static
991{
992 assert(nlpi != NULL);
993 assert(problem != NULL);
994
996 assert( *problem != NULL );
997
998 /* initialize problem */
999 (*problem)->firstrun = TRUE;
1000 SCIP_CALL( SCIPnlpiOracleCreate(scip, &(*problem)->oracle) );
1001 SCIP_CALL( SCIPnlpiOracleSetProblemName(scip, (*problem)->oracle, name) );
1002
1003 /* allocate memory for Worhp data */
1004 SCIP_CALL( SCIPallocBlockMemory(scip, &(*problem)->opt) );
1005 SCIP_CALL( SCIPallocBlockMemory(scip, &(*problem)->wsp) );
1006 SCIP_CALL( SCIPallocBlockMemory(scip, &(*problem)->par) );
1007 SCIP_CALL( SCIPallocBlockMemory(scip, &(*problem)->cnt) );
1008 WorhpPreInit((*problem)->opt, (*problem)->wsp, (*problem)->par, (*problem)->cnt);
1009
1010 /* create random number generator */
1011 SCIP_CALL( SCIPcreateRandom(scip, &(*problem)->randnumgen, DEFAULT_RANDSEED, TRUE) );
1012
1013 return SCIP_OKAY;
1014} /*lint !e715*/
1015
1016/** free a problem instance */
1017static
1019{
1020 assert(nlpi != NULL);
1021 assert(problem != NULL);
1022 assert(*problem != NULL);
1023
1024 if( (*problem)->opt != NULL )
1025 {
1026 /* free memory for last solution information */
1027 invalidateSolution(scip, *problem);
1028
1029 assert((*problem)->wsp != NULL);
1030 assert((*problem)->par != NULL);
1031 assert((*problem)->cnt != NULL);
1032
1033 /* free Worhp data */
1034 SCIP_CALL( freeWorhp(*problem) );
1035 SCIPfreeBlockMemory(scip, &(*problem)->cnt);
1036 SCIPfreeBlockMemory(scip, &(*problem)->par);
1037 SCIPfreeBlockMemory(scip, &(*problem)->wsp);
1038 SCIPfreeBlockMemory(scip, &(*problem)->opt);
1039 }
1040
1041 if( (*problem)->oracle != NULL )
1042 {
1043 SCIP_CALL( SCIPnlpiOracleFree(scip, &(*problem)->oracle) );
1044 }
1045
1046 SCIPfreeRandom(scip, &(*problem)->randnumgen);
1047 SCIPfreeMemoryArrayNull(scip, &(*problem)->initguess);
1048 SCIPfreeBlockMemory(scip, problem);
1049 *problem = NULL;
1050
1051 return SCIP_OKAY;
1052} /*lint !e715*/
1053
1054/** add variables */
1055static
1057{
1058 assert(nlpi != NULL);
1059 assert(problem != NULL);
1060 assert(problem->oracle != NULL);
1061
1062 SCIP_CALL( SCIPnlpiOracleAddVars(scip, problem->oracle, nvars, lbs, ubs, varnames) );
1063
1064 SCIPfreeMemoryArrayNull(scip, &problem->initguess);
1065 invalidateSolution(scip, problem);
1066 problem->firstrun = TRUE;
1067
1068 return SCIP_OKAY; /*lint !e527*/
1069} /*lint !e715*/
1070
1071
1072/** add constraints */
1073static
1075{
1076 assert(nlpi != NULL);
1077 assert(problem != NULL);
1078 assert(problem->oracle != NULL);
1079
1081 nconss, lhss, rhss,
1083 exprs, names) );
1084
1085 invalidateSolution(scip, problem);
1086 problem->firstrun = TRUE;
1087
1088 return SCIP_OKAY; /*lint !e527*/
1089} /*lint !e715*/
1090
1091/** sets or overwrites objective, a minimization problem is expected */
1092static
1094{
1095 assert(nlpi != NULL);
1096 assert(problem != NULL);
1097 assert(problem->oracle != NULL);
1098
1099 /* We pass the objective gradient in dense form to WORHP, so if the sparsity of that gradient changes, we do not need
1100 * to reset WORHP (firstrun=TRUE). However, if the sparsity of the Hessian matrix of the objective changes, then the
1101 * sparsity pattern of the Hessian of the Lagrangian may change. Thus, reset Worhp if the objective was and/or
1102 * becomes nonlinear, but leave firstrun untouched if it was and stays linear.
1103 */
1104 if( expr != NULL || SCIPnlpiOracleIsConstraintNonlinear(problem->oracle, -1) )
1105 problem->firstrun = TRUE;
1106
1107 SCIP_CALL( SCIPnlpiOracleSetObjective(scip, problem->oracle,
1108 constant, nlins, lininds, linvals, expr) );
1109
1110 invalidateSolution(scip, problem);
1111
1112 return SCIP_OKAY; /*lint !e527*/
1113} /*lint !e715*/
1114
1115/** change variable bounds */
1116static
1118{
1119#ifdef SCIP_DISABLED_CODE
1120 const SCIP_Real* oldlbs = SCIPnlpiOracleGetVarLbs(problem->oracle);
1121 const SCIP_Real* oldubs = SCIPnlpiOracleGetVarUbs(problem->oracle);
1122 int i;
1123#endif
1124
1125 assert(nlpi != NULL);
1126 assert(problem != NULL);
1127 assert(problem->oracle != NULL);
1128
1129#ifdef SCIP_DISABLED_CODE
1130 /* TODO check WORHP version here */
1131 /* So far, Worhp can not handle fixed variables (and fixed variables that have been unfixed) when applying a
1132 * restart. The following code needs to be removed when this has changed.
1133 */
1134 for( i = 0; i < nvars; ++i )
1135 {
1136 int index = indices[i];
1137 SCIPdebugMsg(scip, "change bounds of %d from [%g,%g] -> [%g,%g]\n", index, oldlbs[index], oldubs[index],
1138 lbs[i], ubs[i]);
1139
1140 if( REALABS(lbs[i] - ubs[i]) <= problem->feastol )
1141 problem->firstrun = TRUE;
1142 else
1143 if( REALABS(oldlbs[index] - oldubs[index]) <= problem->feastol )
1144 problem->firstrun = TRUE;
1145 }
1146#endif
1147
1148 SCIP_CALL( SCIPnlpiOracleChgVarBounds(scip, problem->oracle, nvars, indices, lbs, ubs) );
1149
1150 invalidateSolution(scip, problem);
1151
1152 return SCIP_OKAY; /*lint !e527*/
1153} /*lint !e715*/
1154
1155/** change constraint bounds */
1156static
1158{
1159 assert(nlpi != NULL);
1160 assert(problem != NULL);
1161 assert(problem->oracle != NULL);
1162
1163#ifdef SCIP_DEBUG
1164 {
1165 SCIP_Real oldlhs;
1166 SCIP_Real oldrhs;
1167 int i;
1168
1169 for( i = 0; i < nconss; ++i )
1170 {
1171 int index = indices[i];
1172 oldlhs = SCIPnlpiOracleGetConstraintLhs(problem->oracle, index);
1173 oldrhs = SCIPnlpiOracleGetConstraintRhs(problem->oracle, index);
1174 SCIPdebugMsg(scip, "change constraint side of %d from [%g,%g] -> [%g,%g]\n", index, oldlhs, oldrhs, lhss[i], rhss[i]);
1175 }
1176 }
1177#endif
1178
1179 SCIP_CALL( SCIPnlpiOracleChgConsSides(scip, problem->oracle, nconss, indices, lhss, rhss) );
1180
1181 invalidateSolution(scip, problem);
1182
1183 return SCIP_OKAY; /*lint !e527*/
1184} /*lint !e715*/
1185
1186/** delete a set of variables */
1187static
1189{
1190 assert(nlpi != NULL);
1191 assert(problem != NULL);
1192 assert(problem->oracle != NULL);
1193
1194 SCIP_CALL( SCIPnlpiOracleDelVarSet(scip, problem->oracle, dstats) );
1195
1196 SCIPfreeMemoryArrayNull(scip, &problem->initguess); /* @TODO keep initguess for remaining variables */
1197
1198 invalidateSolution(scip, problem);
1199 problem->firstrun = TRUE;
1200
1201 return SCIP_OKAY; /*lint !e527*/
1202} /*lint !e715*/
1203
1204/** delete a set of constraints */
1205static
1207{
1208 assert(nlpi != NULL);
1209 assert(problem != NULL);
1210 assert(problem->oracle != NULL);
1211
1212 SCIP_CALL( SCIPnlpiOracleDelConsSet(scip, problem->oracle, dstats) );
1213
1214 invalidateSolution(scip, problem);
1215 problem->firstrun = TRUE;
1216
1217 return SCIP_OKAY; /*lint !e527*/
1218} /*lint !e715*/
1219
1220/** changes (or adds) linear coefficients in a constraint or objective */
1221static
1223{
1224 assert(nlpi != NULL);
1225 assert(problem != NULL);
1226 assert(problem->oracle != NULL);
1227
1228 SCIP_CALL( SCIPnlpiOracleChgLinearCoefs(scip, problem->oracle, idx, nvals, varidxs, vals) );
1229
1230 invalidateSolution(scip, problem);
1231 problem->firstrun = TRUE;
1232
1233 return SCIP_OKAY; /*lint !e527*/
1234} /*lint !e715*/
1235
1236/** replaces the expression of a constraint or objective */
1237static
1239{
1240 assert(nlpi != NULL);
1241 assert(problem != NULL);
1242 assert(problem->oracle != NULL);
1243
1244 SCIP_CALL( SCIPnlpiOracleChgExpr(scip, problem->oracle, idxcons, expr) );
1245
1246 invalidateSolution(scip, problem);
1247 problem->firstrun = TRUE;
1248
1249 return SCIP_OKAY; /*lint !e527*/
1250} /*lint !e715*/
1251
1252/** change the constant offset in the objective */
1253static
1255{
1256 assert(nlpi != NULL);
1257 assert(problem != NULL);
1258 assert(problem->oracle != NULL);
1259
1261
1262 return SCIP_OKAY; /*lint !e527*/
1263} /*lint !e715*/
1264
1265/** sets initial guess for primal variables */
1266static
1268{
1269 assert(nlpi != NULL);
1270 assert(problem != NULL);
1271 assert(problem->oracle != NULL);
1272
1273 if( primalvalues != NULL )
1274 {
1275 if( !problem->initguess )
1276 {
1277 SCIP_CALL( SCIPduplicateMemoryArray(scip, &problem->initguess, primalvalues, SCIPnlpiOracleGetNVars(problem->oracle)) );
1278 }
1279 else
1280 {
1281 BMScopyMemoryArray(problem->initguess, primalvalues, SCIPnlpiOracleGetNVars(problem->oracle));
1282 }
1283 }
1284 else
1285 {
1286 SCIPfreeMemoryArrayNull(scip, &problem->initguess);
1287 }
1288
1289 return SCIP_OKAY;
1290} /*lint !e715*/
1291
1292/** tries to solve NLP */
1293static
1295{
1296 Workspace* wsp = problem->wsp;
1297 Control* cnt = problem->cnt;
1298 OptVar* opt = problem->opt;
1299 Params* par = problem->par;
1300 int status;
1301 int i;
1302
1303 SCIPdebugMsg(scip, "solve with parameters " SCIP_NLPPARAM_PRINT(param));
1304
1305 SCIP_CALL( SCIPnlpiOracleResetEvalTime(scip, problem->oracle) );
1306
1307 if( param.timelimit == 0.0 )
1308 {
1309 /* there is nothing we can do if we are not given any time */
1310 problem->lastniter = 0;
1311 problem->lasttime = 0.0;
1312 problem->lasttermstat = SCIP_NLPTERMSTAT_TIMELIMIT;
1313 problem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
1314
1315 return SCIP_OKAY;
1316 }
1317
1318 problem->lastniter = -1;
1319 problem->lasttime = -1.0;
1320
1321 if( param.verblevel == 0 )
1322 {
1324 }
1325 else
1326 {
1327 /* TODO this should go to a function that prints to the SCIP message handler
1328 * all this doesn't seem threadsafe at all!
1329 */
1331 }
1332
1333 /* initialize Worhp data if necessary */
1334 if( problem->firstrun )
1335 {
1336 SCIP_CALL( freeWorhp(problem) );
1337 SCIP_CALL( initWorhp(scip, nlpi, problem) );
1338 problem->firstrun = FALSE;
1339 }
1340 else
1341 {
1342 SCIP_CALL( updateWorhp(problem) );
1343 }
1344
1345 /* set parameters */
1346 InitParams(&status, par);
1347
1348 if( status != OK )
1349 return SCIP_INVALIDCALL;
1350
1351 SCIP_CALL( handleNlpParam(scip, nlpi, par, param) );
1352
1353#ifdef SCIP_DEBUG
1354 SCIP_CALL( SCIPnlpiOraclePrintProblem(problem->oracle, nlpidata->messagehdlr, NULL) );
1355#endif
1356
1357 /* set initial guess (if available) */
1358 if( problem->initguess != NULL )
1359 {
1360 BMScopyMemoryArray(problem->opt->X, problem->initguess, problem->opt->n);
1361 }
1362 else
1363 {
1364 SCIP_Real lb, ub;
1365
1366 assert(problem->randnumgen != NULL);
1367
1368 SCIPdebugMsg(scip, "Worhp started without initial primal values; make up starting guess by projecting 0 onto variable bounds\n");
1369
1370 for( i = 0; i < problem->opt->n; ++i )
1371 {
1372 lb = SCIPnlpiOracleGetVarLbs(problem->oracle)[i];
1373 ub = SCIPnlpiOracleGetVarUbs(problem->oracle)[i];
1374
1375 if( lb > 0.0 )
1376 problem->opt->X[i] = SCIPrandomGetReal(problem->randnumgen, lb, lb + MAXPERTURB*MIN(1.0, ub-lb));
1377 else if( ub < 0.0 )
1378 problem->opt->X[i] = SCIPrandomGetReal(problem->randnumgen, ub - MAXPERTURB*MIN(1.0, ub-lb), ub);
1379 else
1380 problem->opt->X[i] = SCIPrandomGetReal(problem->randnumgen,
1381 MAX(lb, -MAXPERTURB*MIN(1.0, ub-lb)), MIN(ub, MAXPERTURB*MIN(1.0, ub-lb)));
1382 }
1383 }
1384
1385#ifdef SCIP_DEBUG
1386 SCIPdebugMsg(scip, "start point:\n");
1387 for( i = 0; i < problem->opt->n; ++i )
1388 {
1389 SCIPdebugMsg(scip, "x[%d] = %f\n", i, problem->opt->X[i]);
1390 }
1391#endif
1392
1393 /*
1394 * Worhp Reverse Communication loop.
1395 * In every iteration poll GetUserAction for the requested action, i.e. one
1396 * of {callWorhp, iterOutput, evalF, evalG, evalDF, evalDG, evalHM, fidif}.
1397 *
1398 * Make sure to reset the requested user action afterwards by calling
1399 * DoneUserAction, except for 'callWorhp' and 'fidif'.
1400 */
1401 while( cnt->status < TerminateSuccess && cnt->status > TerminateError && !SCIPisSolveInterrupted(scip) )
1402 {
1403 /*
1404 * Worhp's main routine.
1405 * Do not manually reset callWorhp, this is only done by the FD routines.
1406 */
1407 if( GetUserAction(cnt, callWorhp) )
1408 {
1409 Worhp(opt, wsp, par, cnt);
1410 /* No DoneUserAction! */
1411 }
1412
1413 /*
1414 * Show iteration output.
1415 * The call to IterationOutput() may be replaced by user-defined code.
1416 */
1417 if( GetUserAction(cnt, iterOutput) )
1418 {
1419 IterationOutput(opt, wsp, par, cnt);
1421 }
1422
1423 /*
1424 * Evaluate the objective function.
1425 * The call to UserF may be replaced by user-defined code.
1426 */
1427 if( GetUserAction(cnt, evalF) )
1428 {
1429 if( userF(scip, problem) != SCIP_OKAY )
1430 break;
1431 DoneUserAction(cnt, evalF);
1432 }
1433
1434 /*
1435 * Evaluate the constraints.
1436 * The call to UserG may be replaced by user-defined code.
1437 */
1438 if( GetUserAction(cnt, evalG) )
1439 {
1440 if( userG(scip, problem) != SCIP_OKAY )
1441 break;
1442 DoneUserAction(cnt, evalG);
1443 }
1444
1445 /*
1446 * Evaluate the gradient of the objective function.
1447 * The call to UserDF may be replaced by user-defined code.
1448 */
1449 if( GetUserAction(cnt, evalDF) )
1450 {
1451 if( userDF(scip, problem) != SCIP_OKAY )
1452 break;
1453 DoneUserAction(cnt, evalDF);
1454 }
1455
1456 /*
1457 * Evaluate the Jacobian of the constraints.
1458 * The call to UserDG may be replaced by user-defined code.
1459 */
1460 if( GetUserAction(cnt, evalDG) )
1461 {
1462 if( userDG(scip, problem) != SCIP_OKAY )
1463 break;
1464 DoneUserAction(cnt, evalDG);
1465 }
1466
1467 /*
1468 * Evaluate the Hessian matrix of the Lagrange function (L = f + mu*g)
1469 * The call to UserHM may be replaced by user-defined code.
1470 */
1471 if( GetUserAction(cnt, evalHM) )
1472 {
1473 if( userHM(scip, problem) != SCIP_OKAY)
1474 break;
1475 DoneUserAction(cnt, evalHM);
1476 }
1477
1478 /*
1479 * Use finite differences with RC to determine derivatives
1480 * Do not reset fidif, this is done by the FD routine.
1481 */
1482 if( GetUserAction(cnt, fidif) )
1483 {
1484 WorhpFidif(opt, wsp, par, cnt);
1485 /* No DoneUserAction! */
1486 }
1487 }
1488
1489 /* interpret Worhp result */
1491 {
1492 problem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
1493 problem->lasttermstat = SCIP_NLPTERMSTAT_INTERRUPT;
1494 }
1495 else if( cnt->status < TerminateSuccess && cnt->status > TerminateError )
1496 {
1497 SCIPwarningMessage(scip, "Worhp failed because of an invalid function evaluation!\n");
1498 problem->lastsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
1499 problem->lasttermstat = SCIP_NLPTERMSTAT_NUMERICERROR;
1500 }
1501 else
1502 {
1503 SCIP_CALL( evaluateWorhpRun(scip, problem) );
1504 }
1505
1506 /* prints a status message with information about the current solver status */
1507 StatusMsg(opt, wsp, par, cnt);
1508
1509 /* store statistics */
1510 problem->lastniter = wsp->MajorIter;
1511 problem->lasttime = GetTimerCont(&cnt->Timer);
1512
1513 return SCIP_OKAY;
1514} /*lint !e715*/
1515
1516/** gives solution status */
1517static
1519{
1520 assert(nlpi != NULL);
1521 assert(problem != NULL);
1522
1523 return problem->lastsolstat;
1524} /*lint !e715*/
1525
1526/** gives termination reason */
1527static
1529{
1530 assert(nlpi != NULL);
1531 assert(problem != NULL);
1532
1533 return problem->lasttermstat;
1534} /*lint !e715*/
1535
1536/** gives primal and dual solution values */
1537static
1539{
1540 assert(problem != NULL);
1541
1542 if( primalvalues != NULL )
1543 *primalvalues = problem->lastprimal;
1544
1545 if( consdualvalues != NULL )
1546 *consdualvalues = problem->lastdualcons;
1547
1548 if( varlbdualvalues != NULL )
1549 *varlbdualvalues = problem->lastduallb;
1550
1551 if( varubdualvalues != NULL )
1552 *varubdualvalues = problem->lastdualub;
1553
1554 if( objval != NULL )
1555 {
1556 if( problem->lastprimal != NULL )
1557 {
1558 /* TODO store last solution value instead of reevaluating the objective function */
1559 SCIP_CALL( SCIPnlpiOracleEvalObjectiveValue(scip, problem->oracle, problem->lastprimal, objval) );
1560 }
1561 else
1563 }
1564
1565 return SCIP_OKAY;
1566} /*lint !e715*/
1567
1568/** gives solve statistics */
1569static
1571{
1572 assert(nlpi != NULL);
1573 assert(problem != NULL);
1575
1576 statistics->niterations = problem->lastniter;
1577 statistics->totaltime = problem->lasttime;
1578 statistics->evaltime = SCIPnlpiOracleGetEvalTime(scip, problem->oracle);
1579 statistics->consviol = problem->wsp->FeasOrigMax;
1580 statistics->boundviol = 0.0;
1581
1582 return SCIP_OKAY;
1583} /*lint !e715*/
1584
1585/*
1586 * NLP solver interface specific interface methods
1587 */
1588
1589/** create solver interface for Worhp solver and includes it into SCIP, if Worhp is available */
1591 SCIP* scip, /**< SCIP data structure */
1592 SCIP_Bool useip /**< TRUE for using Interior Point, FALSE for SQP */
1593 )
1594{
1595 SCIP_NLPIDATA* nlpidata;
1596 char name[SCIP_MAXSTRLEN];
1597 int priority;
1598
1599 /* create Worhp solver interface data */
1600 SCIP_CALL( SCIPallocBlockMemory(scip, &nlpidata) );
1601 nlpidata->useip = useip;
1602
1603 /* disable Worhp's keyboard handler, not useful here and not threadsafe */
1604 (void) setenv("WORHP_DISABLE_KEYBOARD_HANDLER", "1", 0);
1605
1606#if DEFAULT_VERBLEVEL == 0
1607 /* disable Worhp output by default */
1609#endif
1610
1611 /* checks the version of the library and header files */
1613
1614 /* create solver interface */
1615 if( useip )
1616 {
1617 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "worhp-ip");
1618 priority = NLPI_PRIORITY_IP;
1619 }
1620 else
1621 {
1622 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "worhp-sqp");
1623 priority = NLPI_PRIORITY_SQP;
1624 }
1625
1627 name, NLPI_DESC, priority,
1635 nlpidata) );
1636
1637 if( useip ) /* TODO lookup whether Worhp info has already been included instead of assuming that worhp-up will be included */
1638 {
1640 }
1641
1642 return SCIP_OKAY;
1643}
1644
1645/** gets string that identifies Worhp (version number) */
1647 void
1648 )
1649{
1650#ifdef WORHP_VERSION
1651 return "WORHP " WORHP_VERSION;
1652#else
1653 static char solvername[20];
1655 return solvername;
1656#endif
1657}
1658
1659/** gets string that describes Worhp (version number) */
1661 void
1662 )
1663{
1664 return "Nonlinear programming solver developed at Research Institute Steinbeis (www.worhp.de)";
1665}
1666
1667/** returns whether Worhp is available, i.e., whether it has been linked in */
1669 void
1670 )
1671{
1672 return TRUE;
1673}
#define SCIP_MAXSTRLEN
Definition def.h:302
#define SCIP_REAL_MAX
Definition def.h:187
#define SCIP_INVALID
Definition def.h:206
#define TRUE
Definition def.h:95
#define FALSE
Definition def.h:96
#define REALABS(x)
Definition def.h:210
#define SCIP_CALL(x)
Definition def.h:388
methods to interpret (evaluate) an expression "fast"
#define SCIPdebugMsg
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
SCIP_RETCODE SCIPincludeNlpSolverWorhp(SCIP *scip, SCIP_Bool useip)
SCIP_RETCODE SCIPnlpiOracleEvalObjectiveValue(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Real *objval)
SCIP_RETCODE SCIPnlpiOracleChgLinearCoefs(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, int nentries, const int *varidxs, const SCIP_Real *newcoefs)
SCIP_RETCODE SCIPnlpiOracleChgVarBounds(SCIP *scip, SCIP_NLPIORACLE *oracle, int nvars, const int *indices, const SCIP_Real *lbs, const SCIP_Real *ubs)
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)
SCIP_Bool SCIPnlpiOracleIsConstraintNonlinear(SCIP_NLPIORACLE *oracle, int considx)
SCIP_RETCODE SCIPnlpiOracleDelVarSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
SCIP_RETCODE SCIPnlpiOracleEvalConstraintValues(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Real *convals)
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)
SCIP_RETCODE SCIPnlpiOracleGetHessianLagSparsity(SCIP *scip, SCIP_NLPIORACLE *oracle, const int **offset, const int **col)
SCIP_RETCODE SCIPnlpiOracleEvalObjectiveGradient(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx, SCIP_Real *objval, SCIP_Real *objgrad)
SCIP_RETCODE SCIPnlpiOracleResetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
SCIP_RETCODE SCIPnlpiOraclePrintProblem(SCIP *scip, SCIP_NLPIORACLE *oracle, FILE *file)
SCIP_RETCODE SCIPnlpiOracleSetObjective(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real constant, int nlin, const int *lininds, const SCIP_Real *linvals, SCIP_EXPR *expr)
SCIP_Real SCIPnlpiOracleGetConstraintRhs(SCIP_NLPIORACLE *oracle, int considx)
SCIP_Real SCIPnlpiOracleGetEvalTime(SCIP *scip, SCIP_NLPIORACLE *oracle)
SCIP_RETCODE SCIPnlpiOracleChgConsSides(SCIP *scip, SCIP_NLPIORACLE *oracle, int nconss, const int *indices, const SCIP_Real *lhss, const SCIP_Real *rhss)
SCIP_Real SCIPnlpiOracleGetConstraintLhs(SCIP_NLPIORACLE *oracle, int considx)
SCIP_RETCODE SCIPnlpiOracleAddVars(SCIP *scip, SCIP_NLPIORACLE *oracle, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
int SCIPnlpiOracleGetNVars(SCIP_NLPIORACLE *oracle)
int SCIPnlpiOracleGetNConstraints(SCIP_NLPIORACLE *oracle)
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_RETCODE SCIPnlpiOracleEvalJacobian(SCIP *scip, SCIP_NLPIORACLE *oracle, const SCIP_Real *x, SCIP_Bool isnewx, SCIP_Real *convals, SCIP_Real *jacobi)
SCIP_RETCODE SCIPnlpiOracleDelConsSet(SCIP *scip, SCIP_NLPIORACLE *oracle, int *delstats)
SCIP_RETCODE SCIPnlpiOracleSetProblemName(SCIP *scip, SCIP_NLPIORACLE *oracle, const char *name)
SCIP_RETCODE SCIPnlpiOracleChgObjConstant(SCIP *scip, SCIP_NLPIORACLE *oracle, SCIP_Real objconstant)
const SCIP_Real * SCIPnlpiOracleGetVarLbs(SCIP_NLPIORACLE *oracle)
const SCIP_Real * SCIPnlpiOracleGetVarUbs(SCIP_NLPIORACLE *oracle)
SCIP_RETCODE SCIPnlpiOracleFree(SCIP *scip, SCIP_NLPIORACLE **oracle)
SCIP_RETCODE SCIPnlpiOracleChgExpr(SCIP *scip, SCIP_NLPIORACLE *oracle, int considx, SCIP_EXPR *expr)
const char * SCIPgetSolverNameWorhp(void)
const char * SCIPgetSolverDescWorhp(void)
SCIP_Bool SCIPisWorhpAvailableWorhp(void)
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition scip_mem.h:81
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition scip_mem.h:91
#define SCIPduplicateMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:76
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
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:107
SCIP_NLPIDATA * SCIPnlpiGetData(SCIP_NLPI *nlpi)
Definition nlpi.c:712
SCIP_Bool SCIPisSolveInterrupted(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition misc.c:10041
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10788
return SCIP_OKAY
SCIPfreeRandom(scip, &heurdata->randnumgen)
SCIP_Real objval
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
methods for catching the user CTRL-C interrupt
#define NULL
Definition lpi_spx1.cpp:161
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:136
static SCIP_RETCODE userG(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:456
static void noprint(int mode, const char s[])
Definition nlpi_worhp.c:633
static SCIP_RETCODE userDG(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:532
#define MAXPERTURB
Definition nlpi_worhp.c:67
static SCIP_RETCODE userDF(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:488
static SCIP_RETCODE userHM(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:577
#define NLPI_PRIORITY_SQP
Definition nlpi_worhp.c:61
static SCIP_RETCODE userF(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:423
static SCIP_RETCODE initWorhp(SCIP *scip, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:642
static SCIP_RETCODE updateWorhp(SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:844
static void invalidateSolution(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:113
#define NLPI_PRIORITY_IP
Definition nlpi_worhp.c:60
#define DEFAULT_RANDSEED
Definition nlpi_worhp.c:65
static SCIP_RETCODE freeWorhp(SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:884
static SCIP_RETCODE handleNlpParam(SCIP *scip, SCIP_NLPI *nlpi, Params *par, const SCIP_NLPPARAM nlpparam)
Definition nlpi_worhp.c:902
#define DEFAULT_SCALEDKKT
Definition nlpi_worhp.c:64
#define NLPI_DESC
Definition nlpi_worhp.c:59
static SCIP_RETCODE evaluateWorhpRun(SCIP *scip, SCIP_NLPIPROBLEM *problem)
Definition nlpi_worhp.c:135
Worhp NLP interface.
methods to store an NLP and request function, gradient, and Hessian values
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebugPrintf
Definition pub_message.h:99
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_Bool firstrun
Definition nlpi_worhp.c:97
SCIP_NLPIORACLE * oracle
SCIP_Real * lastdualcons
Definition nlpi_worhp.c:89
SCIP_RANDNUMGEN * randnumgen
SCIP_Real * lastprimal
Definition nlpi_worhp.c:88
Workspace * wsp
Definition nlpi_worhp.c:102
SCIP_NLPTERMSTAT lasttermstat
Definition nlpi_worhp.c:83
SCIP_Real * lastduallb
Definition nlpi_worhp.c:90
SCIP_NLPSOLSTAT lastsolstat
Definition nlpi_worhp.c:84
SCIP_Real * lastdualub
Definition nlpi_worhp.c:91
SCIP_Real * initguess
#define MAX(x, y)
Definition tclique_def.h:92
#define SCIP_DECL_NLPISOLVE(x)
Definition type_nlpi.h:497
#define SCIP_DECL_NLPICHGLINEARCOEFS(x)
Definition type_nlpi.h:432
#define SCIP_DECL_NLPICHGOBJCONSTANT(x)
Definition type_nlpi.h:463
#define SCIP_NLPPARAM_PRINT(param)
Definition type_nlpi.h:142
#define SCIP_DECL_NLPIGETSOLUTION(x)
Definition type_nlpi.h:545
#define SCIP_DECL_NLPISETOBJECTIVE(x)
Definition type_nlpi.h:344
#define SCIP_DECL_NLPICREATEPROBLEM(x)
Definition type_nlpi.h:255
#define SCIP_DECL_NLPIGETSTATISTICS(x)
Definition type_nlpi.h:562
#define SCIP_DECL_NLPIDELCONSSET(x)
Definition type_nlpi.h:415
#define SCIP_DECL_NLPICHGCONSSIDES(x)
Definition type_nlpi.h:383
#define SCIP_DECL_NLPIDELVARSET(x)
Definition type_nlpi.h:400
#define SCIP_DECL_NLPICHGEXPR(x)
Definition type_nlpi.h:449
#define SCIP_DECL_NLPIADDVARS(x)
Definition type_nlpi.h:297
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition type_nlpi.h:168
#define SCIP_DECL_NLPISETINITIALGUESS(x)
Definition type_nlpi.h:481
#define SCIP_DECL_NLPIFREEPROBLEM(x)
Definition type_nlpi.h:267
@ 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_LICENSEERROR
Definition type_nlpi.h:181
@ SCIP_NLPTERMSTAT_ITERLIMIT
Definition type_nlpi.h:175
@ SCIP_NLPTERMSTAT_OUTOFMEMORY
Definition type_nlpi.h:180
@ SCIP_NLPTERMSTAT_INTERRUPT
Definition type_nlpi.h:177
#define SCIP_DECL_NLPICOPY(x)
Definition type_nlpi.h:215
#define SCIP_DECL_NLPIGETSOLSTAT(x)
Definition type_nlpi.h:511
#define SCIP_DECL_NLPICHGVARBOUNDS(x)
Definition type_nlpi.h:364
#define SCIP_DECL_NLPIFREE(x)
Definition type_nlpi.h:225
#define SCIP_DECL_NLPIADDCONSTRAINTS(x)
Definition type_nlpi.h:320
@ 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
#define SCIP_DECL_NLPIGETTERMSTAT(x)
Definition type_nlpi.h:524
enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
Definition type_nlpi.h:194
struct SCIP_NlpiData SCIP_NLPIDATA
Definition type_nlpi.h:52
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE