1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file nlp.c
17 * @ingroup OTHER_CFILES
18 * @brief NLP management methods and datastructures
19 * @author Thorsten Gellermann
20 * @author Stefan Vigerske
21 *
22 * In NLP management, we have to differ between the current NLP and the NLPI problem
23 * stored in the NLP solver. All NLP methods affect the current NLP only.
24 * Before solving the current NLP with the NLP solver, the NLP solvers data
25 * has to be updated to the current NLP with a call to nlpFlush().
26 *
27 * @todo handle linear rows from LP
28 */
29
30 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
31
32
33 #include "nlpi/nlpi.h"
34 #include "nlpi/pub_expr.h"
35 #include "nlpi/struct_expr.h"
36 #include "scip/clock.h"
37 #include "scip/event.h"
38 #include "scip/intervalarith.h"
39 #include "scip/nlp.h"
40 #include "scip/primal.h"
41 #include "scip/pub_event.h"
42 #include "scip/pub_lp.h"
43 #include "scip/pub_message.h"
44 #include "scip/pub_misc.h"
45 #include "scip/pub_misc_sort.h"
46 #include "scip/pub_nlp.h"
47 #include "scip/pub_var.h"
48 #include "scip/set.h"
49 #include "scip/sol.h"
50 #include "scip/struct_nlp.h"
51 /* to get nlp, set, ... in event handling */
52 #include "scip/struct_scip.h"
53 /* to get value of parameter "nlp/solver" and nlpis array and to get access to set->lp for releasing a variable */
54 #include "scip/struct_set.h"
55 #include "scip/struct_stat.h"
56 #include "scip/var.h"
57 #include <string.h>
58
59 /* defines */
60
61 #define EVENTHDLR_NAME "nlpEventHdlr" /**< name of NLP event handler that catches variable events */
62 #define EVENTHDLR_DESC "handles all events necessary for maintaining NLP data" /**< description of NLP event handler */
63 #define ADDNAMESTONLPI 0 /**< whether to give variable and row names to NLPI */
64
65 #ifdef __cplusplus
66 extern "C" {
67 #endif
68
69 /* avoid inclusion of scip.h */ /*lint -e{2701}*/
70 BMS_BLKMEM* SCIPblkmem(
71 SCIP* scip /**< SCIP data structure */
72 );
73
74 #ifdef __cplusplus
75 }
76 #endif
77
78 /*
79 * forward declarations
80 */
81
82 /** NLP event handler execution method */
83 static
84 SCIP_DECL_EVENTEXEC( eventExecNlp );
85
86 /** announces, that a row of the NLP was modified
87 * adjusts status of current solution
88 * calling method has to ensure that change is passed to the NLPI!
89 */
90 static
91 SCIP_RETCODE nlpRowChanged(
92 SCIP_NLP* nlp, /**< current NLP data */
93 SCIP_SET* set, /**< global SCIP settings */
94 SCIP_STAT* stat, /**< problem statistics data */
95 SCIP_NLROW* nlrow /**< nonlinear row which was changed */
96 );
97
98 /*
99 * public expression tree methods
100 */
101
102 /** returns variables of expression tree */
SCIPexprtreeGetVars(SCIP_EXPRTREE * tree)103 SCIP_VAR** SCIPexprtreeGetVars(
104 SCIP_EXPRTREE* tree /**< expression tree */
105 )
106 {
107 assert(tree != NULL);
108
109 return (SCIP_VAR**)tree->vars;
110 }
111
112 /** stores array of variables in expression tree */
SCIPexprtreeSetVars(SCIP_EXPRTREE * tree,int nvars,SCIP_VAR ** vars)113 SCIP_RETCODE SCIPexprtreeSetVars(
114 SCIP_EXPRTREE* tree, /**< expression tree */
115 int nvars, /**< number of variables */
116 SCIP_VAR** vars /**< variables */
117 )
118 {
119 assert(tree != NULL);
120 assert(vars != NULL || nvars == 0);
121
122 if( nvars == 0 )
123 {
124 BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->vars, tree->nvars);
125 tree->nvars = 0;
126 }
127 else if( tree->vars != NULL )
128 {
129 SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->vars, tree->nvars, nvars) );
130 BMScopyMemoryArray(tree->vars, (void**)vars, nvars);
131 }
132 else
133 {
134 SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->vars, (void**)vars, nvars) );
135 }
136
137 tree->nvars = nvars;
138
139 assert(tree->vars != NULL || tree->nvars == 0);
140
141 return SCIP_OKAY;
142 }
143
144 /** adds variables to the expression tree variables array */
SCIPexprtreeAddVars(SCIP_EXPRTREE * tree,int nvars,SCIP_VAR ** vars)145 SCIP_RETCODE SCIPexprtreeAddVars(
146 SCIP_EXPRTREE* tree, /**< expression tree */
147 int nvars, /**< number of variables */
148 SCIP_VAR** vars /**< variables */
149 )
150 {
151 assert(tree != NULL);
152 assert(vars != NULL || nvars == 0);
153 assert(tree->vars != NULL || tree->nvars == 0);
154
155 if( nvars == 0 )
156 return SCIP_OKAY;
157
158 if( tree->nvars == 0 )
159 {
160 SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->vars, (void**)vars, nvars) );
161 tree->nvars = nvars;
162 return SCIP_OKAY;
163 }
164
165 /* append vars to tree->vars array */
166 SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->vars, tree->nvars, tree->nvars + nvars) );
167 BMScopyMemoryArray(&tree->vars[tree->nvars], (void**)vars, nvars); /*lint !e866*/
168 tree->nvars += nvars;
169
170 return SCIP_OKAY;
171 }
172
173 /** prints an expression tree using variable names from variables array */
SCIPexprtreePrintWithNames(SCIP_EXPRTREE * tree,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)174 SCIP_RETCODE SCIPexprtreePrintWithNames(
175 SCIP_EXPRTREE* tree, /**< expression tree */
176 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
177 FILE* file /**< file for printing, or NULL for stdout */
178 )
179 {
180 const char** varnames;
181 int i;
182
183 assert(tree != NULL);
184
185 if( tree->nvars == 0 )
186 {
187 SCIPexprtreePrint(tree, messagehdlr, file, NULL, NULL);
188 return SCIP_OKAY;
189 }
190
191 assert(tree->vars != NULL);
192
193 SCIP_ALLOC( BMSallocMemoryArray(&varnames, tree->nvars) );
194 for( i = 0; i < tree->nvars; ++i )
195 varnames[i] = SCIPvarGetName((SCIP_VAR*)tree->vars[i]);
196
197 SCIPexprtreePrint(tree, messagehdlr, file, varnames, NULL);
198
199 BMSfreeMemoryArray(&varnames);
200
201 return SCIP_OKAY;
202 }
203
204 /** searches the variables array of an expression tree for a variable and returns its position, or -1 if not found
205 * Note that this is an O(n) operation!
206 */
SCIPexprtreeFindVar(SCIP_EXPRTREE * tree,SCIP_VAR * var)207 int SCIPexprtreeFindVar(
208 SCIP_EXPRTREE* tree, /**< expression tree */
209 SCIP_VAR* var /**< variable to search for */
210 )
211 {
212 int i;
213
214 assert(tree != NULL);
215 assert(var != NULL);
216
217 for( i = 0; i < tree->nvars; ++i )
218 if( (SCIP_VAR*)tree->vars[i] == var )
219 return i;
220
221 return -1;
222 }
223
224 /** removes fixed variables from an expression tree, so that at exit all variables are active */
SCIPexprtreeRemoveFixedVars(SCIP_EXPRTREE * tree,SCIP_SET * set,SCIP_Bool * changed,int * varpos,int * newvarsstart)225 SCIP_RETCODE SCIPexprtreeRemoveFixedVars(
226 SCIP_EXPRTREE* tree, /**< expression tree */
227 SCIP_SET* set, /**< global SCIP settings */
228 SCIP_Bool* changed, /**< buffer to store whether the tree was changed, i.e., whether there was a fixed variable */
229 int* varpos, /**< array of length at least tree->nvars to store new indices of previously existing variables in expression tree, or -1 if variable was removed; set to NULL if not of interest */
230 int* newvarsstart /**< buffer to store index in tree->vars array where new variables begin, or NULL if not of interest */
231 )
232 {
233 SCIP_HASHMAP* varhash;
234 int i;
235 int j;
236 int nvarsold;
237 SCIP_VAR* var;
238 SCIP_Real scalar;
239 SCIP_Real constant;
240 SCIP_EXPR** replaceexprs;
241 SCIP_Bool havefixedvar;
242 int idx;
243 int* newpos;
244 int offset;
245
246 assert(tree != NULL);
247 assert(tree->vars != NULL || tree->nvars == 0);
248 assert(changed != NULL);
249
250 *changed = FALSE;
251 if( newvarsstart != NULL )
252 *newvarsstart = tree->nvars;
253
254 if( tree->nvars == 0 )
255 return SCIP_OKAY;
256
257 /* create hash map from variable to indices in tree->vars and check if there is a non-fixed variable */
258 havefixedvar = FALSE;
259 SCIP_CALL( SCIPhashmapCreate(&varhash, tree->blkmem, tree->nvars) );
260 for( i = 0; i < tree->nvars; ++i )
261 {
262 /* it's not possible to add a variable twice to the varhash map */
263 if( SCIPhashmapExists(varhash, tree->vars[i]) )
264 continue;
265
266 SCIP_CALL( SCIPhashmapInsertInt(varhash, tree->vars[i], i) );
267
268 if( !SCIPvarIsActive((SCIP_VAR*)tree->vars[i]) )
269 havefixedvar = TRUE;
270 }
271
272 if( !havefixedvar )
273 {
274 /* nothing to do */
275 if( varpos != NULL )
276 for( i = 0; i < tree->nvars; ++i )
277 varpos[i] = i;
278 SCIPhashmapFree(&varhash);
279 return SCIP_OKAY;
280 }
281
282 /* we will do something */
283 *changed = TRUE;
284
285 nvarsold = tree->nvars;
286
287 /* array to store expressions that replace a variable expression in the tree */
288 SCIP_ALLOC( BMSallocBlockMemoryArray(tree->blkmem, &replaceexprs, nvarsold) );
289 BMSclearMemoryArray(replaceexprs, nvarsold);
290
291 /* construct for each nonactive variable an expression that replaces this variable in the tree */
292 for( i = 0; i < nvarsold; ++i )
293 {
294 var = (SCIP_VAR*)tree->vars[i];
295
296 if( SCIPvarIsActive(var) )
297 continue;
298
299 scalar = 1.0;
300 constant = 0.0;
301 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &constant) );
302
303 if( scalar == 0.0 )
304 {
305 /* variable is fixed, thus replace by constant expression in tree */
306 SCIP_CALL( SCIPexprCreate(tree->blkmem, &replaceexprs[i], SCIP_EXPR_CONST, constant) );
307 continue;
308 }
309
310 if( SCIPvarIsActive(var) )
311 {
312 /* variable was aggregated or negated, thus replace by scalar * var + constant */
313 if( !SCIPhashmapExists(varhash, var) )
314 {
315 /* var not in tree yet, so add it */
316 SCIP_CALL( SCIPexprtreeAddVars(tree, 1, &var) );
317 idx = tree->nvars - 1;
318 SCIP_CALL( SCIPhashmapInsertInt(varhash, (void*)var, idx) );
319 }
320 else
321 {
322 idx = SCIPhashmapGetImageInt(varhash, (void*)var);
323 }
324 assert(idx >= 0 && idx < tree->nvars);
325 assert((SCIP_VAR*)tree->vars[idx] == var);
326
327 SCIP_CALL( SCIPexprCreate(tree->blkmem, &replaceexprs[i], SCIP_EXPR_VARIDX, idx) );
328 if( scalar != 1.0 || constant != 0.0 )
329 {
330 /* multiply by scalar and add constant -> linear expression */
331 SCIP_CALL( SCIPexprCreateLinear(tree->blkmem, &replaceexprs[i], 1, &replaceexprs[i], &scalar, constant) );
332 }
333 continue;
334 }
335
336 {
337 SCIP_EXPR** children;
338 SCIP_Real* coefs;
339 int nchildren;
340 SCIP_VAR* mvar;
341 SCIP_Real mscalar;
342
343 /* var is now multi-aggregated, thus replace by scalar * (multaggrconst + sum_j multaggrscalar_j*multaggrvar_j) + constant */
344 assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR );
345
346 /* allocate array for children and coefficients */
347 SCIP_ALLOC( BMSallocBlockMemoryArray(tree->blkmem, &children, SCIPvarGetMultaggrNVars(var)) ); /*lint !e666 */
348 SCIP_ALLOC( BMSallocBlockMemoryArray(tree->blkmem, &coefs, SCIPvarGetMultaggrNVars(var)) ); /*lint !e666 */
349 nchildren = 0;
350
351 /* linear part
352 * turn each variable in SCIPvarGetMultaggrVars(var) into an active or multi-aggregated one and add corresponding term to summands */
353 for( j = 0; j < SCIPvarGetMultaggrNVars(var); ++j )
354 {
355 mvar = SCIPvarGetMultaggrVars(var)[j];
356 mscalar = scalar * SCIPvarGetMultaggrScalars(var)[j];
357 SCIP_CALL( SCIPvarGetProbvarSum(&mvar, set, &mscalar, &constant) );
358
359 /* if variable mvar is fixed, constant has been added to constant and we can continue */
360 if( mscalar == 0.0 )
361 continue;
362
363 assert(SCIPvarIsActive(mvar) || SCIPvarGetStatus(mvar) == SCIP_VARSTATUS_MULTAGGR);
364
365 /* add mvar to tree, if not in tree yet */
366 if( !SCIPhashmapExists(varhash, mvar) )
367 {
368 /* var not in tree yet, so add it */
369 SCIP_CALL( SCIPexprtreeAddVars(tree, 1, &mvar) );
370 idx = tree->nvars - 1;
371 SCIP_CALL( SCIPhashmapInsertInt(varhash, (void*)mvar, idx) );
372 }
373 else
374 {
375 idx = SCIPhashmapGetImageInt(varhash, (void*)mvar);
376 }
377 assert(idx >= 0 && idx < tree->nvars);
378 assert((SCIP_VAR*)tree->vars[idx] == mvar);
379
380 SCIP_CALL( SCIPexprCreate(tree->blkmem, &children[nchildren], SCIP_EXPR_VARIDX, idx) );
381 coefs[nchildren] = mscalar;
382 ++nchildren;
383 }
384
385 /* constant part */
386 constant += scalar * SCIPvarGetMultaggrConstant(var);
387
388 if( nchildren == 0 )
389 {
390 /* somehow all aggregation variables were fixed */
391 SCIP_CALL( SCIPexprCreate(tree->blkmem, &replaceexprs[i], SCIP_EXPR_CONST, constant) );
392 }
393 else if( nchildren == 1 && constant == 0.0 )
394 {
395 /* somehow everything collapsed to one summand -> use that one for replaceexprs[i]*/
396 replaceexprs[i] = children[0];
397 }
398 else
399 {
400 /* set replaceexprs[i] to linear expression in children */
401 SCIP_CALL( SCIPexprCreateLinear(tree->blkmem, &replaceexprs[i], nchildren, children, coefs, constant) );
402 }
403
404 BMSfreeBlockMemoryArray(tree->blkmem, &children, SCIPvarGetMultaggrNVars(var));
405 BMSfreeBlockMemoryArray(tree->blkmem, &coefs, SCIPvarGetMultaggrNVars(var));
406 }
407 }
408
409 /* replace variables in tree by assembled expressions */
410 SCIP_CALL( SCIPexprtreeSubstituteVars(tree, replaceexprs) );
411 /* free replaceexprs */
412 for( i = 0; i < nvarsold; ++i )
413 if( replaceexprs[i] != NULL )
414 SCIPexprFreeDeep(tree->blkmem, &replaceexprs[i]);
415 BMSfreeBlockMemoryArray(tree->blkmem, &replaceexprs, nvarsold);
416
417 /* the varhash is not needed anymore */
418 SCIPhashmapFree(&varhash);
419
420 /* remove inactive variables from vars array and recompute variable indices */
421 SCIP_ALLOC( BMSallocBlockMemoryArray(tree->blkmem, &newpos, tree->nvars) );
422 offset = 0;
423 for( i = 0; i < tree->nvars; ++i )
424 {
425 if( SCIPvarIsActive((SCIP_VAR*)tree->vars[i]) || i >= nvarsold )
426 {
427 /* a new variable need to be either active or multi-aggregated */
428 assert(i < nvarsold || SCIPvarIsActive((SCIP_VAR*)tree->vars[i]) || SCIPvarGetStatus((SCIP_VAR*)tree->vars[i]) == SCIP_VARSTATUS_MULTAGGR);
429 newpos[i] = i - offset;
430 }
431 else
432 {
433 /* non-active variable are removed */
434 newpos[i] = -1;
435 ++offset;
436 }
437 if( varpos != NULL && i < nvarsold )
438 varpos[i] = newpos[i];
439 }
440 if( newvarsstart != NULL )
441 *newvarsstart -= offset;
442
443 /* update indices in tree */
444 SCIPexprReindexVars(tree->root, newpos);
445
446 /* move variable in expression tree vars array
447 * check if there is a fixed variable left */
448 havefixedvar = FALSE;
449 for( i = 0; i < tree->nvars; ++i )
450 {
451 if( newpos[i] == -1 )
452 {
453 /* variable was removed */
454 assert(!SCIPvarIsActive((SCIP_VAR*)tree->vars[i]));
455 continue;
456 }
457 /* variable is moved */
458 tree->vars[newpos[i]] = tree->vars[i];
459 if( !SCIPvarIsActive((SCIP_VAR*)tree->vars[i]) )
460 havefixedvar = TRUE;
461 }
462
463 /* free newpos array; resize vars array */
464 BMSfreeBlockMemoryArray(tree->blkmem, &newpos, tree->nvars);
465 if( offset < tree->nvars )
466 {
467 SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->vars, tree->nvars, tree->nvars - offset) );
468 tree->nvars -= offset;
469 }
470 else
471 {
472 /* all variables were removed */
473 BMSfreeBlockMemoryArray(tree->blkmem, &tree->vars, tree->nvars);
474 tree->nvars = 0;
475 }
476
477 if( havefixedvar )
478 {
479 /* if there are still fixed variables left, then this are newly added multi-aggregated variables
480 * it is then save to call this function recursively, since the original active variables should not be moved,
481 * i.e., varpos and *newvarsstart will remain valid
482 */
483 SCIP_Bool gotchange;
484
485 SCIP_CALL( SCIPexprtreeRemoveFixedVars(tree, set, &gotchange, NULL, NULL) );
486 assert(gotchange);
487 }
488
489 return SCIP_OKAY;
490 }
491
492 /*
493 * private NLP nonlinear row methods
494 */
495
496 /** announces, that the given linear coefficient in the constraint matrix changed */
497 static
nlrowLinearCoefChanged(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_Real coef,SCIP_NLP * nlp)498 SCIP_RETCODE nlrowLinearCoefChanged(
499 SCIP_NLROW* nlrow, /**< nonlinear row */
500 SCIP_SET* set, /**< global SCIP settings */
501 SCIP_STAT* stat, /**< problem statistics data */
502 SCIP_VAR* var, /**< variable which coefficient changed */
503 SCIP_Real coef, /**< new coefficient of variable, 0.0 if deleted */
504 SCIP_NLP* nlp /**< current NLP data */
505 )
506 {
507 assert(nlrow != NULL);
508 assert(var != NULL);
509
510 nlrow->activity = SCIP_INVALID;
511 nlrow->validactivitynlp = -1;
512 nlrow->pseudoactivity = SCIP_INVALID;
513 nlrow->validpsactivitydomchg = -1;
514 nlrow->minactivity = SCIP_INVALID;
515 nlrow->maxactivity = SCIP_INVALID;
516 nlrow->validactivitybdsdomchg = -1;
517
518 if( nlrow->nlpindex >= 0 )
519 {
520 assert(nlp != NULL);
521
522 /* notify NLP that row has changed */
523 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
524
525 /* update NLPI problem, if row is in NLPI already */
526 if( nlrow->nlpiindex >= 0 )
527 {
528 int idx;
529
530 /* get index of variable in NLPI */
531 assert(SCIPhashmapExists(nlp->varhash, var));
532 idx = SCIPhashmapGetImageInt(nlp->varhash, var);
533 assert(idx >= 0 && idx < nlp->nvars);
534
535 idx = nlp->varmap_nlp2nlpi[idx];
536 assert(idx >= 0 && idx < nlp->nvars_solver);
537
538 /* change coefficient in NLPI problem */
539 SCIP_CALL( SCIPnlpiChgLinearCoefs(nlp->solver, nlp->problem, nlrow->nlpiindex, 1, &idx, &coef) );
540 }
541 }
542
543 return SCIP_OKAY;
544 }
545
546 /** announces, that an element in the quadratic part of a nonlinear row changed */
547 static
nlrowQuadElemChanged(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_QUADELEM quadelem,SCIP_NLP * nlp)548 SCIP_RETCODE nlrowQuadElemChanged(
549 SCIP_NLROW* nlrow, /**< nonlinear row */
550 SCIP_SET* set, /**< global SCIP settings */
551 SCIP_STAT* stat, /**< problem statistics data */
552 SCIP_QUADELEM quadelem, /**< new element (variable indices and new values), quadelem.coef == 0 if it was deleted */
553 SCIP_NLP* nlp /**< current NLP data */
554 )
555 {
556 assert(nlrow != NULL);
557 assert(quadelem.idx1 >= 0);
558 assert(quadelem.idx1 < nlrow->nquadvars);
559 assert(quadelem.idx2 >= 0);
560 assert(quadelem.idx2 < nlrow->nquadvars);
561
562 nlrow->activity = SCIP_INVALID;
563 nlrow->validactivitynlp = -1;
564 nlrow->pseudoactivity = SCIP_INVALID;
565 nlrow->validpsactivitydomchg = -1;
566 nlrow->minactivity = SCIP_INVALID;
567 nlrow->maxactivity = SCIP_INVALID;
568 nlrow->validactivitybdsdomchg = -1;
569
570 if( nlrow->nlpindex >= 0 )
571 {
572 assert(nlp != NULL);
573
574 /* notify NLP that row has changed */
575 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
576
577 /* update NLPI problem, if row is in NLPI already */
578 if( nlrow->nlpiindex >= 0 )
579 {
580 SCIP_QUADELEM elem;
581
582 /* get NLPI index of first variable */
583 assert(nlrow->quadvars[quadelem.idx1] != NULL);
584 assert(SCIPhashmapExists(nlp->varhash, nlrow->quadvars[quadelem.idx1]));
585 elem.idx1 = SCIPhashmapGetImageInt(nlp->varhash, nlrow->quadvars[quadelem.idx1]);
586 assert(elem.idx1 >= 0 && elem.idx1 < nlp->nvars);
587
588 elem.idx1 = nlp->varmap_nlp2nlpi[elem.idx1];
589 assert(elem.idx1 >= 0 && elem.idx1 < nlp->nvars_solver);
590
591 /* get NLPI index of second variable */
592 assert(nlrow->quadvars[quadelem.idx2] != NULL);
593 assert(SCIPhashmapExists(nlp->varhash, nlrow->quadvars[quadelem.idx2]));
594 elem.idx2 = SCIPhashmapGetImageInt(nlp->varhash, nlrow->quadvars[quadelem.idx2]);
595 assert(elem.idx2 >= 0 && elem.idx2 < nlp->nvars);
596
597 elem.idx2 = nlp->varmap_nlp2nlpi[elem.idx2];
598 assert(elem.idx2 >= 0 && elem.idx2 < nlp->nvars_solver);
599
600 /* make sure idx1 <= idx2 */
601 if( elem.idx1 > elem.idx2 )
602 {
603 int tmp;
604 tmp = elem.idx2;
605 elem.idx2 = elem.idx1;
606 elem.idx1 = tmp;
607 }
608
609 elem.coef = quadelem.coef;
610
611 /* change coefficient in NLPI problem */
612 SCIP_CALL( SCIPnlpiChgQuadCoefs(nlp->solver, nlp->problem, nlrow->nlpiindex, 1, &elem) );
613 }
614 }
615
616 return SCIP_OKAY;
617 }
618
619 /** announces, that an expression tree changed */
620 static
nlrowExprtreeChanged(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)621 SCIP_RETCODE nlrowExprtreeChanged(
622 SCIP_NLROW* nlrow, /**< nonlinear row */
623 SCIP_SET* set, /**< global SCIP settings */
624 SCIP_STAT* stat, /**< problem statistics data */
625 SCIP_NLP* nlp /**< current NLP data */
626 )
627 {
628 assert(nlrow != NULL);
629
630 nlrow->activity = SCIP_INVALID;
631 nlrow->validactivitynlp = -1;
632 nlrow->pseudoactivity = SCIP_INVALID;
633 nlrow->validpsactivitydomchg = -1;
634 nlrow->minactivity = SCIP_INVALID;
635 nlrow->maxactivity = SCIP_INVALID;
636 nlrow->validactivitybdsdomchg = -1;
637
638 if( nlrow->nlpindex >= 0 )
639 {
640 assert(nlp != NULL);
641
642 /* notify NLP that row has changed */
643 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
644
645 if( nlrow->nlpiindex >= 0 )
646 {
647 /* change expression tree in NLPI problem */
648 int* nlinidxs;
649
650 /* get indices of variables in expression tree part of row */
651 if( nlrow->exprtree != NULL )
652 {
653 int i;
654 int n;
655 SCIP_VAR* var;
656
657 n = SCIPexprtreeGetNVars(nlrow->exprtree);
658 assert(n == 0 || SCIPexprtreeGetVars(nlrow->exprtree) != NULL);
659
660 SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinidxs, n) );
661
662 for( i = 0; i < n; ++i )
663 {
664 var = SCIPexprtreeGetVars(nlrow->exprtree)[i];
665 assert(var != NULL);
666 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
667
668 assert(SCIPhashmapExists(nlp->varhash, var));
669 nlinidxs[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
670 }
671
672 SCIP_CALL( SCIPnlpiChgExprtree(nlp->solver, nlp->problem, nlrow->nlpiindex, nlinidxs, nlrow->exprtree) );
673
674 SCIPsetFreeBufferArray(set, &nlinidxs);
675 }
676 else
677 {
678 SCIP_CALL( SCIPnlpiChgExprtree(nlp->solver, nlp->problem, nlrow->nlpiindex, NULL, NULL) );
679 }
680 }
681 }
682
683 return SCIP_OKAY;
684 }
685
686 /** announces, that a parameter in an expression tree has changed */
687 static
nlrowExprtreeParamChanged(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,int paramidx,SCIP_NLP * nlp)688 SCIP_RETCODE nlrowExprtreeParamChanged(
689 SCIP_NLROW* nlrow, /**< nonlinear row */
690 SCIP_SET* set, /**< global SCIP settings */
691 SCIP_STAT* stat, /**< problem statistics data */
692 int paramidx, /**< index of parameter which has changed, or -1 if all changed */
693 SCIP_NLP* nlp /**< current NLP data */
694 )
695 {
696 assert(nlrow != NULL);
697 assert(nlrow->exprtree != NULL);
698 assert(paramidx >= -1);
699 assert(paramidx < SCIPexprtreeGetNParams(nlrow->exprtree));
700
701 nlrow->activity = SCIP_INVALID;
702 nlrow->validactivitynlp = -1;
703 nlrow->pseudoactivity = SCIP_INVALID;
704 nlrow->validpsactivitydomchg = -1;
705 nlrow->minactivity = SCIP_INVALID;
706 nlrow->maxactivity = SCIP_INVALID;
707 nlrow->validactivitybdsdomchg = -1;
708
709 if( nlrow->nlpindex >= 0 )
710 {
711 assert(nlp != NULL);
712
713 /* notify NLP that row has changed */
714 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
715
716 if( nlrow->nlpiindex >= 0 )
717 {
718 if( paramidx >= 0 )
719 {
720 /* change coefficient in NLPI problem */
721 SCIP_CALL( SCIPnlpiChgNonlinCoef(nlp->solver, nlp->problem, nlrow->nlpiindex, paramidx, SCIPexprtreeGetParamVals(nlrow->exprtree)[paramidx]) );
722 }
723 else
724 {
725 SCIP_Real* paramvals;
726 int i;
727 int n;
728
729 /* change all coefficients in NLPI problem */
730 n = SCIPexprtreeGetNParams(nlrow->exprtree);
731 paramvals = SCIPexprtreeGetParamVals(nlrow->exprtree);
732 for( i = 0; i < n; ++i )
733 {
734 SCIP_CALL( SCIPnlpiChgNonlinCoef(nlp->solver, nlp->problem, nlrow->nlpiindex, i, paramvals[i]) );
735 }
736 }
737 }
738 }
739
740 return SCIP_OKAY;
741 }
742
743 /** notifies nonlinear row, that its sides were changed */
744 static
nlrowSideChanged(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)745 SCIP_RETCODE nlrowSideChanged(
746 SCIP_NLROW* nlrow, /**< nonlinear row */
747 SCIP_SET* set, /**< global SCIP settings */
748 SCIP_STAT* stat, /**< problem statistics data */
749 SCIP_NLP* nlp /**< current NLP data */
750 )
751 {
752 assert(nlrow != NULL);
753
754 if( nlrow->nlpindex >= 0 )
755 {
756 assert(nlp != NULL);
757
758 /* notify NLP that row has changed */
759 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
760
761 if( nlrow->nlpiindex >= 0 )
762 {
763 SCIP_Real lhs;
764 SCIP_Real rhs;
765
766 /* change sides in NLPI problem */
767 lhs = nlrow->lhs;
768 rhs = nlrow->rhs;
769 if( !SCIPsetIsInfinity(set, -lhs) )
770 lhs -= nlrow->constant;
771 if( !SCIPsetIsInfinity(set, rhs) )
772 rhs -= nlrow->constant;
773
774 SCIP_CALL( SCIPnlpiChgConsSides(nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) );
775 }
776 }
777
778 return SCIP_OKAY;
779 }
780
781 /** notifies nonlinear row, that its constant was changed */
782 static
nlrowConstantChanged(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)783 SCIP_RETCODE nlrowConstantChanged(
784 SCIP_NLROW* nlrow, /**< nonlinear row */
785 SCIP_SET* set, /**< global SCIP settings */
786 SCIP_STAT* stat, /**< problem statistics data */
787 SCIP_NLP* nlp /**< current NLP data */
788 )
789 {
790 assert(nlrow != NULL);
791
792 nlrow->activity = SCIP_INVALID;
793 nlrow->validactivitynlp = -1;
794 nlrow->pseudoactivity = SCIP_INVALID;
795 nlrow->validpsactivitydomchg = -1;
796 nlrow->minactivity = SCIP_INVALID;
797 nlrow->maxactivity = SCIP_INVALID;
798 nlrow->validactivitybdsdomchg = -1;
799
800 if( nlrow->nlpindex >= 0 )
801 {
802 assert(nlp != NULL);
803
804 /* notify NLP that row has changed */
805 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
806
807 if( nlrow->nlpiindex >= 0 )
808 {
809 SCIP_Real lhs;
810 SCIP_Real rhs;
811
812 lhs = nlrow->lhs;
813 rhs = nlrow->rhs;
814 if( !SCIPsetIsInfinity(set, -lhs) )
815 lhs -= nlrow->constant;
816 if( !SCIPsetIsInfinity(set, rhs) )
817 rhs -= nlrow->constant;
818
819 /* change sides in NLPI problem */
820 SCIP_CALL( SCIPnlpiChgConsSides(nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) );
821 }
822 }
823
824 return SCIP_OKAY;
825 }
826
827 /** sorts linear part of row entries such that lower variable indices precede higher ones */
828 static
nlrowSortLinear(SCIP_NLROW * nlrow)829 void nlrowSortLinear(
830 SCIP_NLROW* nlrow /**< nonlinear row to be sorted */
831 )
832 {
833 assert(nlrow != NULL);
834
835 /* check, if row is already sorted in the LP part, or if the sorting should be delayed */
836 if( nlrow->linvarssorted )
837 return;
838
839 /* sort linear coefficients */
840 SCIPsortPtrReal((void**)nlrow->linvars, nlrow->lincoefs, SCIPvarComp, nlrow->nlinvars);
841
842 nlrow->linvarssorted = TRUE;
843 }
844
845 /** searches linear variable in nonlinear row, returns position in linvars vector or -1 if not found */
846 static
nlrowSearchLinearCoef(SCIP_NLROW * nlrow,SCIP_VAR * var)847 int nlrowSearchLinearCoef(
848 SCIP_NLROW* nlrow, /**< nonlinear row to be searched in */
849 SCIP_VAR* var /**< variable to be searched for */
850 )
851 {
852 int pos;
853
854 assert(nlrow != NULL);
855 assert(var != NULL);
856
857 if( nlrow->nlinvars == 0 )
858 return -1;
859
860 nlrowSortLinear(nlrow);
861 if( !SCIPsortedvecFindPtr((void**)nlrow->linvars, SCIPvarComp, (void*)var, nlrow->nlinvars, &pos) )
862 return -1;
863
864 return pos;
865 }
866
867 /** moves a coefficient in a nonlinear row to a different place, and updates all corresponding data structures */
868 static
nlrowMoveLinearCoef(SCIP_NLROW * nlrow,int oldpos,int newpos)869 void nlrowMoveLinearCoef(
870 SCIP_NLROW* nlrow, /**< NLP row */
871 int oldpos, /**< old position of coefficient */
872 int newpos /**< new position of coefficient */
873 )
874 {
875 assert(nlrow != NULL);
876 assert(0 <= oldpos && oldpos < nlrow->nlinvars);
877 assert(0 <= newpos && newpos < nlrow->nlinvars);
878 assert(nlrow->linvars[oldpos] != NULL);
879
880 if( oldpos == newpos )
881 return;
882
883 nlrow->linvars[newpos] = nlrow->linvars[oldpos];
884 nlrow->lincoefs[newpos] = nlrow->lincoefs[oldpos];
885
886 /* update sorted flags */
887 nlrow->linvarssorted = FALSE;
888 }
889
890 /** adds a previously non existing linear coefficient to a nonlinear row */
891 static
nlrowAddLinearCoef(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_VAR * var,SCIP_Real coef)892 SCIP_RETCODE nlrowAddLinearCoef(
893 SCIP_NLROW* nlrow, /**< nonlinear row */
894 BMS_BLKMEM* blkmem, /**< block memory */
895 SCIP_SET* set, /**< global SCIP settings */
896 SCIP_STAT* stat, /**< problem statistics data */
897 SCIP_NLP* nlp, /**< current NLP data */
898 SCIP_VAR* var, /**< variable */
899 SCIP_Real coef /**< value of coefficient */
900 )
901 {
902 int pos;
903
904 assert(nlrow != NULL);
905 assert(blkmem != NULL);
906 assert(var != NULL);
907 assert(!SCIPsetIsZero(set, coef));
908
909 /* assert that only active variables are added once the row is in the NLP */
910 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
911
912 SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars+1) );
913 assert(nlrow->linvars != NULL);
914 assert(nlrow->lincoefs != NULL);
915
916 pos = nlrow->nlinvars;
917 nlrow->nlinvars++;
918
919 /* insert the variable */
920 nlrow->linvars [pos] = var;
921 nlrow->lincoefs[pos] = coef;
922
923 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, coef, nlp) );
924
925 /* update sorted flag */
926 if( pos > 0 && SCIPvarCompare(nlrow->linvars[pos-1], nlrow->linvars[pos]) > 0 )
927 nlrow->linvarssorted = FALSE;
928
929 SCIPsetDebugMsg(set, "added linear coefficient %g * <%s> at position %d to nonlinear row <%s>\n",
930 coef, SCIPvarGetName(var), pos, nlrow->name);
931
932 return SCIP_OKAY;
933 }
934
935 /** adds a linear coefficient to a nonlinear row
936 * if the variable exists in the linear part of the row already, the coefficients are added
937 * otherwise the variable is added to the row */
938 static
nlrowAddToLinearCoef(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_VAR * var,SCIP_Real coef,SCIP_Bool removefixed)939 SCIP_RETCODE nlrowAddToLinearCoef(
940 SCIP_NLROW* nlrow, /**< nonlinear row */
941 BMS_BLKMEM* blkmem, /**< block memory */
942 SCIP_SET* set, /**< global SCIP settings */
943 SCIP_STAT* stat, /**< problem statistics data */
944 SCIP_NLP* nlp, /**< current NLP data */
945 SCIP_VAR* var, /**< variable */
946 SCIP_Real coef, /**< value of coefficient */
947 SCIP_Bool removefixed /**< whether to disaggregate var before adding */
948 )
949 {
950 int pos;
951
952 assert(nlrow != NULL);
953 assert(blkmem != NULL);
954 assert(var != NULL);
955
956 if( removefixed && !SCIPvarIsActive(var) )
957 {
958 SCIP_Real constant;
959
960 constant = 0.0;
961 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &coef, &constant) );
962 if( constant != 0.0 )
963 {
964 nlrow->constant += constant;
965 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
966 }
967
968 if( SCIPsetIsZero(set, coef) )
969 return SCIP_OKAY;
970
971 if( !SCIPvarIsActive(var) )
972 {
973 int j;
974
975 /* if var is still not active, then it is multi-aggregated */
976 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
977
978 if( SCIPvarGetMultaggrConstant(var) != 0.0 )
979 {
980 nlrow->constant += coef * SCIPvarGetMultaggrConstant(var);
981 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
982 }
983
984 for( j = 0; j < SCIPvarGetMultaggrNVars(var); ++j )
985 {
986 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[j], SCIPvarGetMultaggrScalars(var)[j] * coef, TRUE) );
987 }
988
989 return SCIP_OKAY;
990 }
991 }
992 else if( SCIPsetIsZero(set, coef) )
993 return SCIP_OKAY;
994
995 assert(!removefixed || SCIPvarIsActive(var));
996
997 pos = nlrowSearchLinearCoef(nlrow, var);
998
999 if( pos == -1 )
1000 {
1001 /* add as new coefficient */
1002 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) );
1003 }
1004 else
1005 {
1006 assert(pos >= 0);
1007 assert(pos < nlrow->nlinvars);
1008 assert(nlrow->linvars[pos] == var);
1009
1010 /* add to previously existing coefficient */
1011 nlrow->lincoefs[pos] += coef;
1012 }
1013
1014 return SCIP_OKAY;
1015 }
1016
1017 /** deletes coefficient at given position from row */
1018 static
nlrowDelLinearCoefPos(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int pos)1019 SCIP_RETCODE nlrowDelLinearCoefPos(
1020 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */
1021 SCIP_SET* set, /**< global SCIP settings */
1022 SCIP_STAT* stat, /**< problem statistics data */
1023 SCIP_NLP* nlp, /**< current NLP data */
1024 int pos /**< position in row vector to delete */
1025 )
1026 {
1027 SCIP_VAR* var;
1028
1029 assert(nlrow != NULL);
1030 assert(set != NULL);
1031 assert(0 <= pos && pos < nlrow->nlinvars);
1032 assert(nlrow->linvars[pos] != NULL);
1033
1034 var = nlrow->linvars[pos];
1035
1036 /* move last coefficient to position of empty slot (should set sorted flag to FALSE, if not last variable was deleted) */
1037 nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos);
1038 nlrow->nlinvars--;
1039 assert(pos == nlrow->nlinvars || nlrow->linvarssorted == FALSE);
1040
1041 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) );
1042
1043 return SCIP_OKAY;
1044 }
1045
1046 /** changes a coefficient at given position of a nonlinear row */
1047 static
nlrowChgLinearCoefPos(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int pos,SCIP_Real coef)1048 SCIP_RETCODE nlrowChgLinearCoefPos(
1049 SCIP_NLROW* nlrow, /**< NLP row */
1050 SCIP_SET* set, /**< global SCIP settings */
1051 SCIP_STAT* stat, /**< problem statistics data */
1052 SCIP_NLP* nlp, /**< current NLP data */
1053 int pos, /**< position in row vector to change */
1054 SCIP_Real coef /**< new value of coefficient */
1055 )
1056 {
1057 assert(nlrow != NULL);
1058 assert(0 <= pos && pos < nlrow->nlinvars);
1059 assert(nlrow->linvars[pos] != NULL);
1060
1061 if( SCIPsetIsZero(set, coef) )
1062 {
1063 /* delete existing coefficient */
1064 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
1065 }
1066 else if( !SCIPsetIsEQ(set, nlrow->lincoefs[pos], coef) )
1067 {
1068 /* change existing coefficient */
1069 nlrow->lincoefs[pos] = coef;
1070 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], coef, nlp) );
1071 }
1072
1073 return SCIP_OKAY;
1074 }
1075
1076 /** sets up the variable hash for quadratic variables, if the number of variables exceeds some given threshold */
1077 static
nlrowSetupQuadVarsHash(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem)1078 SCIP_RETCODE nlrowSetupQuadVarsHash(
1079 SCIP_NLROW* nlrow, /**< nonlinear row */
1080 BMS_BLKMEM* blkmem /**< block memory */
1081 )
1082 {
1083 int i;
1084 assert(blkmem != NULL);
1085 assert(nlrow != NULL);
1086 assert(nlrow->quadvarshash == NULL);
1087
1088 if( nlrow->nquadvars < 3 )
1089 return SCIP_OKAY;
1090
1091 SCIP_CALL( SCIPhashmapCreate(&nlrow->quadvarshash, blkmem, nlrow->nquadvars) );
1092 assert(nlrow->quadvarshash != NULL);
1093
1094 for( i = 0; i < nlrow->nquadvars; ++i )
1095 {
1096 SCIP_CALL( SCIPhashmapInsertInt(nlrow->quadvarshash, (void*)nlrow->quadvars[i], i) );
1097 }
1098
1099 return SCIP_OKAY;
1100 }
1101
1102 /** sorts quadratic part of row entries */
1103 static
nlrowSortQuadElem(SCIP_NLROW * nlrow)1104 void nlrowSortQuadElem(
1105 SCIP_NLROW* nlrow /**< nonlinear row to be sorted */
1106 )
1107 {
1108 assert(nlrow != NULL);
1109 assert(nlrow->quadelems != NULL);
1110
1111 /* check, if row is already sorted in the LP part, or if the sorting should be delayed */
1112 if( nlrow->quadelemssorted )
1113 return;
1114
1115 /* sort quadratic elements */
1116 SCIPquadelemSort(nlrow->quadelems, nlrow->nquadelems);
1117
1118 nlrow->quadelemssorted = TRUE;
1119 }
1120
1121 /** searches quadratic elements in nonlinear row, returns position of given index pair in quadelems array or -1 if not found */
1122 static
nlrowSearchQuadElem(SCIP_NLROW * nlrow,int idx1,int idx2)1123 int nlrowSearchQuadElem(
1124 SCIP_NLROW* nlrow, /**< nonlinear row to be searched in */
1125 int idx1, /**< index of first variable to be searched for */
1126 int idx2 /**< index of second variable to be searched for */
1127 )
1128 {
1129 int pos;
1130
1131 assert(nlrow != NULL);
1132 assert(idx1 >= 0);
1133 assert(idx1 < nlrow->nquadvars);
1134 assert(idx2 >= 0);
1135 assert(idx2 < nlrow->nquadvars);
1136
1137 nlrowSortQuadElem(nlrow);
1138 if( !SCIPquadelemSortedFind(nlrow->quadelems, idx1, idx2, nlrow->nquadelems, &pos) )
1139 pos = -1;
1140
1141 return pos;
1142 }
1143
1144 /** moves a quadratic element in a nonlinear row to a different place, and updates all corresponding data structures */
1145 static
nlrowMoveQuadElement(SCIP_NLROW * nlrow,int oldpos,int newpos)1146 void nlrowMoveQuadElement(
1147 SCIP_NLROW* nlrow, /**< NLP row */
1148 int oldpos, /**< old position of coefficient */
1149 int newpos /**< new position of coefficient */
1150 )
1151 {
1152 assert(nlrow != NULL);
1153 assert(0 <= oldpos && oldpos < nlrow->nquadelems);
1154 assert(0 <= newpos && newpos < nlrow->nquadelems);
1155
1156 if( oldpos == newpos )
1157 return;
1158
1159 nlrow->quadelems[newpos] = nlrow->quadelems[oldpos];
1160
1161 /* update sorted flags */
1162 nlrow->quadelemssorted = FALSE;
1163 }
1164
1165 /** adds a previously non existing quadratic element to a nonlinear row */
1166 static
nlrowAddQuadElement(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_QUADELEM elem)1167 SCIP_RETCODE nlrowAddQuadElement(
1168 SCIP_NLROW* nlrow, /**< nonlinear row */
1169 BMS_BLKMEM* blkmem, /**< block memory */
1170 SCIP_SET* set, /**< global SCIP settings */
1171 SCIP_STAT* stat, /**< problem statistics data */
1172 SCIP_NLP* nlp, /**< current NLP data */
1173 SCIP_QUADELEM elem /**< quadratic element to add */
1174 )
1175 {
1176 int pos;
1177
1178 assert(nlrow != NULL);
1179 assert(blkmem != NULL);
1180 assert(elem.idx1 >= 0);
1181 assert(elem.idx1 < nlrow->nquadvars);
1182 assert(elem.idx2 >= 0);
1183 assert(elem.idx2 < nlrow->nquadvars);
1184
1185 if( SCIPsetIsZero(set, elem.coef) )
1186 return SCIP_OKAY;
1187
1188 SCIP_CALL( SCIPnlrowEnsureQuadElementsSize(nlrow, blkmem, set, nlrow->nquadelems+1) );
1189 assert(nlrow->quadelems != NULL);
1190
1191 pos = nlrow->nquadelems;
1192 nlrow->nquadelems++;
1193
1194 /* insert the element */
1195 nlrow->quadelems[pos] = elem;
1196
1197 /* notify row and NLP */
1198 SCIP_CALL( nlrowQuadElemChanged(nlrow, set, stat, elem, nlp) );
1199
1200 /* update sorted flag */
1201 if( pos > 0 )
1202 nlrow->quadelemssorted = FALSE;
1203
1204 SCIPsetDebugMsg(set, "added quadratic element %g * <%s> * <%s> at position %d to nonlinear row <%s>\n",
1205 elem.coef, SCIPvarGetName(nlrow->quadvars[elem.idx1]), SCIPvarGetName(nlrow->quadvars[elem.idx2]), pos, nlrow->name);
1206
1207 return SCIP_OKAY;
1208 }
1209
1210 /** deletes coefficient at given position from row */
1211 static
nlrowDelQuadElemPos(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int pos)1212 SCIP_RETCODE nlrowDelQuadElemPos(
1213 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */
1214 SCIP_SET* set, /**< global SCIP settings */
1215 SCIP_STAT* stat, /**< problem statistics data */
1216 SCIP_NLP* nlp, /**< current NLP data */
1217 int pos /**< position in row vector to delete */
1218 )
1219 {
1220 SCIP_QUADELEM elem;
1221
1222 assert(nlrow != NULL);
1223 assert(set != NULL);
1224 assert(0 <= pos && pos < nlrow->nquadelems);
1225
1226 SCIPsetDebugMsg(set, "delete quad element (%d,%d) at pos %d\n", nlrow->quadelems[pos].idx1, nlrow->quadelems[pos].idx2, pos);
1227
1228 elem = nlrow->quadelems[pos];
1229
1230 /* move last coefficient to position of empty slot (should set sorted flag to FALSE, if not last element was deleted) */
1231 nlrowMoveQuadElement(nlrow, nlrow->nquadelems-1, pos);
1232 nlrow->nquadelems--;
1233 assert(pos == nlrow->nquadelems || nlrow->quadelemssorted == FALSE);
1234
1235 /* notify row and NLP */
1236 elem.coef = 0.0;
1237 SCIP_CALL( nlrowQuadElemChanged(nlrow, set, stat, elem, nlp) );
1238
1239 return SCIP_OKAY;
1240 }
1241
1242 /** changes a coefficient at given position of quadratic element in nonlinear row */
1243 static
nlrowChgQuadElemPos(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int pos,SCIP_Real coef)1244 SCIP_RETCODE nlrowChgQuadElemPos(
1245 SCIP_NLROW* nlrow, /**< NLP row */
1246 SCIP_SET* set, /**< global SCIP settings */
1247 SCIP_STAT* stat, /**< problem statistics data */
1248 SCIP_NLP* nlp, /**< current NLP data */
1249 int pos, /**< position in quadratic elements array to change */
1250 SCIP_Real coef /**< new value of coefficient */
1251 )
1252 {
1253 assert(nlrow != NULL);
1254 assert(0 <= pos && pos < nlrow->nquadelems);
1255
1256 SCIPsetDebugMsg(set, "change quad element (%d,%d) at pos %d to %g\n", nlrow->quadelems[pos].idx1, nlrow->quadelems[pos].idx2, pos, coef);
1257
1258 if( SCIPsetIsZero(set, coef) )
1259 {
1260 /* delete existing coefficient */
1261 SCIP_CALL( nlrowDelQuadElemPos(nlrow, set, stat, nlp, pos) );
1262 }
1263 else if( !SCIPsetIsEQ(set, nlrow->quadelems[pos].coef, coef) )
1264 {
1265 /* change existing coefficient */
1266 nlrow->quadelems[pos].coef = coef;
1267 SCIP_CALL( nlrowQuadElemChanged(nlrow, set, stat, nlrow->quadelems[pos], nlp) );
1268 }
1269
1270 return SCIP_OKAY;
1271 }
1272
1273 /** calculates minimal and maximal activity of row w.r.t. the variable's bounds */
1274 static
nlrowCalcActivityBounds(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat)1275 SCIP_RETCODE nlrowCalcActivityBounds(
1276 SCIP_NLROW* nlrow, /**< nonlinear row */
1277 SCIP_SET* set, /**< global SCIP settings */
1278 SCIP_STAT* stat /**< problem statistics data */
1279 )
1280 {
1281 SCIP_Real inf;
1282 SCIP_INTERVAL activity;
1283 SCIP_INTERVAL bounds;
1284 int i;
1285
1286 assert(nlrow != NULL);
1287 assert(set != NULL);
1288 assert(stat != NULL);
1289
1290 inf = SCIPsetInfinity(set);
1291
1292 /* calculate activity bounds */
1293 SCIPintervalSet(&activity, nlrow->constant);
1294 for( i = 0; i < nlrow->nlinvars && !SCIPintervalIsEntire(inf, activity); ++i )
1295 {
1296 SCIPintervalSetBounds(&bounds, SCIPvarGetLbLocal(nlrow->linvars[i]), SCIPvarGetUbLocal(nlrow->linvars[i]));
1297 SCIPintervalMulScalar(inf, &bounds, bounds, nlrow->lincoefs[i]);
1298 SCIPintervalAdd(inf, &activity, activity, bounds);
1299 }
1300
1301 /* @todo make sure quadelems is sorted */
1302 for( i = 0; i < nlrow->nquadelems && !SCIPintervalIsEntire(inf, activity); )
1303 {
1304 SCIP_Real a;
1305 SCIP_INTERVAL b, tmp;
1306 int idx1;
1307
1308 idx1 = nlrow->quadelems[i].idx1;
1309 SCIPintervalSetBounds(&bounds, SCIPvarGetLbLocal(nlrow->quadvars[idx1]), SCIPvarGetUbLocal(nlrow->quadvars[idx1]));
1310
1311 /* for x_i*(a*x_i + sum_j b_jx_j) we assemble a and sum_j b_jx_j */
1312 a = 0.0;
1313 SCIPintervalSet(&b, 0.0);
1314 do
1315 {
1316 if( nlrow->quadelems[i].idx1 == nlrow->quadelems[i].idx2 )
1317 {
1318 a = nlrow->quadelems[i].coef;
1319 }
1320 else
1321 {
1322 SCIPintervalSetBounds(&tmp, SCIPvarGetLbLocal(nlrow->quadvars[nlrow->quadelems[i].idx2]), SCIPvarGetUbLocal(nlrow->quadvars[nlrow->quadelems[i].idx2]));
1323 SCIPintervalMulScalar(inf, &tmp, tmp, nlrow->quadelems[i].coef);
1324 SCIPintervalAdd(inf, &b, b, tmp);
1325 }
1326 ++i;
1327 }
1328 while( i < nlrow->nquadvars && idx1 == nlrow->quadelems[i].idx1 );
1329
1330 /* compute bounds for a*x_i^2 + b*x_i and add to activity bounds */
1331 SCIPintervalQuad(inf, &bounds, a, b, bounds);
1332 SCIPintervalAdd(inf, &activity, activity, bounds);
1333 }
1334
1335 if( nlrow->exprtree != NULL && !SCIPintervalIsEntire(inf, activity))
1336 {
1337 SCIP_INTERVAL* varvals;
1338 int n;
1339
1340 n = SCIPexprtreeGetNVars(nlrow->exprtree);
1341
1342 SCIP_CALL( SCIPsetAllocBufferArray(set, &varvals, n) );
1343
1344 for( i = 0; i < n; ++i )
1345 {
1346 SCIPintervalSetBounds(&varvals[i], SCIPvarGetLbLocal(SCIPexprtreeGetVars(nlrow->exprtree)[i]), SCIPvarGetUbLocal(SCIPexprtreeGetVars(nlrow->exprtree)[i]));
1347 }
1348
1349 SCIP_CALL( SCIPexprtreeEvalInt(nlrow->exprtree, inf, varvals, &bounds) );
1350 SCIPintervalAdd(inf, &activity, activity, bounds);
1351
1352 SCIPsetFreeBufferArray(set, &varvals);
1353 }
1354
1355 nlrow->minactivity = SCIPintervalGetInf(activity);
1356 nlrow->maxactivity = SCIPintervalGetSup(activity);
1357
1358 nlrow->validactivitybdsdomchg = stat->domchgcount;
1359
1360 return SCIP_OKAY;
1361 }
1362
1363 /** makes sure that there is no fixed variable at position pos of the linear part of a nonlinear row
1364 * a fixed variable is replaced with the corresponding constant or disaggregated term
1365 */
1366 static
nlrowRemoveFixedLinearCoefPos(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int pos)1367 SCIP_RETCODE nlrowRemoveFixedLinearCoefPos(
1368 SCIP_NLROW* nlrow, /**< nonlinear row */
1369 BMS_BLKMEM* blkmem, /**< block memory */
1370 SCIP_SET* set, /**< global SCIP settings */
1371 SCIP_STAT* stat, /**< problem statistics data */
1372 SCIP_NLP* nlp, /**< current NLP data */
1373 int pos /**< position of variable in linear variables array */
1374 )
1375 {
1376 SCIP_Real oldconstant;
1377 SCIP_VAR* var;
1378
1379 assert(nlrow != NULL);
1380 assert(blkmem != NULL);
1381 assert(pos >= 0);
1382 assert(pos < nlrow->nlinvars);
1383
1384 var = nlrow->linvars[pos];
1385
1386 if( SCIPvarIsActive(var) )
1387 return SCIP_OKAY;
1388
1389 oldconstant = nlrow->constant;
1390
1391 /* replace fixed, aggregated, or negated variable */
1392 SCIP_CALL( SCIPvarGetProbvarSum( &nlrow->linvars[pos], set, &nlrow->lincoefs[pos], &nlrow->constant) );
1393
1394 /* if var had been fixed, entry should be removed from row */
1395 if( nlrow->lincoefs[pos] == 0.0 )
1396 {
1397 nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos);
1398 nlrow->nlinvars--;
1399
1400 if( pos < nlrow->nlinvars )
1401 {
1402 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
1403 }
1404
1405 return SCIP_OKAY;
1406 }
1407 nlrow->linvarssorted = FALSE;
1408
1409 /* notify nlrow that coefficient of var is now 0.0 in row */
1410 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) );
1411
1412 /* notify nlrow that constant of row has changed */
1413 if( oldconstant != nlrow->constant ) /*lint !e777*/
1414 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1415
1416 if( SCIPvarIsActive(nlrow->linvars[pos]) )
1417 {
1418 /* if var was aggregated or negated, notify nlrow about new coefficient */
1419 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], nlrow->lincoefs[pos], nlp) );
1420 }
1421 else
1422 {
1423 SCIP_Real coef;
1424 int i;
1425
1426 /* if not removed or active, the new variable should be multi-aggregated */
1427 assert(SCIPvarGetStatus(nlrow->linvars[pos]) == SCIP_VARSTATUS_MULTAGGR);
1428
1429 var = nlrow->linvars[pos];
1430 coef = nlrow->lincoefs[pos];
1431
1432 /* remove the variable from the row */
1433 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
1434
1435 /* add multi-aggregated term to row */
1436 if( SCIPvarGetMultaggrConstant(var) != 0.0 )
1437 {
1438 nlrow->constant += coef * SCIPvarGetMultaggrConstant(var);
1439 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1440 }
1441 SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars + SCIPvarGetMultaggrNVars(var)) );
1442 for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i )
1443 {
1444 if( SCIPsetIsZero(set, coef * SCIPvarGetMultaggrScalars(var)[i]) )
1445 continue;
1446 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], coef * SCIPvarGetMultaggrScalars(var)[i]) );
1447 assert(SCIPvarGetMultaggrVars(var)[i] == nlrow->linvars[nlrow->nlinvars-1]);
1448 if( !SCIPvarIsActive(SCIPvarGetMultaggrVars(var)[i]) )
1449 {
1450 /* if newly added variable is fixed, replace it now */
1451 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, nlrow->nlinvars-1) );
1452 }
1453 }
1454
1455 /* due to nlrowDelLinearCoefPos, an inactive variable may have moved to position pos
1456 * if that is the case, call ourself recursively
1457 */
1458 if( pos < nlrow->nlinvars && !SCIPvarIsActive(nlrow->linvars[pos]) )
1459 {
1460 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
1461 }
1462 }
1463
1464 return SCIP_OKAY;
1465 }
1466
1467 /** removes fixed variables from the linear part of a nonlinear row */
1468 static
nlrowRemoveFixedLinearCoefs(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)1469 SCIP_RETCODE nlrowRemoveFixedLinearCoefs(
1470 SCIP_NLROW* nlrow, /**< nonlinear row */
1471 BMS_BLKMEM* blkmem, /**< block memory */
1472 SCIP_SET* set, /**< global SCIP settings */
1473 SCIP_STAT* stat, /**< problem statistics data */
1474 SCIP_NLP* nlp /**< current NLP data */
1475 )
1476 {
1477 int i;
1478 int oldlen;
1479
1480 assert(nlrow != NULL);
1481 assert(nlrow->linvars != NULL || nlrow->nlinvars == 0);
1482
1483 oldlen = nlrow->nlinvars;
1484 for( i = 0; i < MIN(oldlen, nlrow->nlinvars); ++i )
1485 {
1486 assert(nlrow->linvars[i] != NULL);
1487 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, i) );
1488 }
1489
1490 return SCIP_OKAY;
1491 }
1492
1493 /** removes fixed quadratic variables of a nonlinear row by replacing them with the corresponding constant or disaggregated terms */
1494 static
nlrowRemoveFixedQuadVars(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)1495 SCIP_RETCODE nlrowRemoveFixedQuadVars(
1496 SCIP_NLROW* nlrow, /**< nonlinear row */
1497 BMS_BLKMEM* blkmem, /**< block memory */
1498 SCIP_SET* set, /**< global SCIP settings */
1499 SCIP_STAT* stat, /**< problem statistics data */
1500 SCIP_NLP* nlp /**< current NLP data */
1501 )
1502 {
1503 int i;
1504 int nvarsold;
1505 SCIP_Bool* used;
1506 SCIP_QUADELEM elem;
1507 SCIP_QUADELEM newelem;
1508 int idx2;
1509 SCIP_Bool havechange;
1510
1511 SCIP_VAR* var1;
1512 SCIP_Real coef1;
1513 SCIP_Real constant1;
1514 SCIP_VAR* var2;
1515 SCIP_Real coef2;
1516 SCIP_Real constant2;
1517
1518 assert(nlrow != NULL);
1519 assert(blkmem != NULL);
1520
1521 if( nlrow->nquadvars == 0 )
1522 return SCIP_OKAY;
1523
1524 SCIPsetDebugMsg(set, "removing fixed quadratic variables from nlrow\n");
1525
1526 nvarsold = nlrow->nquadvars;
1527 havechange = FALSE;
1528
1529 /* allocate array to count number of uses for each variable */
1530 SCIP_CALL( SCIPsetAllocBufferArray(set, &used, nlrow->nquadvars) );
1531 BMSclearMemoryArray(used, nlrow->nquadvars);
1532
1533 i = 0;
1534 while( i < nlrow->nquadelems )
1535 {
1536 elem = nlrow->quadelems[i];
1537
1538 assert(elem.idx1 < nlrow->nquadvars);
1539 assert(elem.idx2 < nlrow->nquadvars);
1540 if( SCIPvarIsActive(nlrow->quadvars[elem.idx1]) && SCIPvarIsActive(nlrow->quadvars[elem.idx2]) )
1541 {
1542 /* both variables of quadratic element are active
1543 * thus, we just remember that we saw them and can continue with the next element
1544 */
1545 if( elem.idx1 < nvarsold )
1546 used[elem.idx1] = TRUE;
1547 if( elem.idx2 < nvarsold )
1548 used[elem.idx2] = TRUE;
1549 ++i;
1550 continue;
1551 }
1552
1553 SCIPsetDebugMsg(set, "removing fixed quadratic variables from %dth element %g <%s> <%s>\n",
1554 i, elem.coef, SCIPvarGetName(nlrow->quadvars[elem.idx1]), SCIPvarGetName(nlrow->quadvars[elem.idx2]));
1555
1556 /* if one of the variable is not active, we remove the element and insert new disaggregated ones */
1557 SCIP_CALL( nlrowDelQuadElemPos(nlrow, set, stat, nlp, i) );
1558 havechange = TRUE;
1559
1560 var1 = nlrow->quadvars[elem.idx1];
1561 var2 = nlrow->quadvars[elem.idx2];
1562 coef1 = 1.0;
1563 coef2 = 1.0;
1564 constant1 = 0.0;
1565 constant2 = 0.0;
1566
1567 SCIP_CALL( SCIPvarGetProbvarSum(&var1, set, &coef1, &constant1) );
1568 SCIP_CALL( SCIPvarGetProbvarSum(&var2, set, &coef2, &constant2) );
1569
1570 if( coef1 == 0.0 && coef2 == 0.0 )
1571 {
1572 /* both variables were fixed, so we may add a constant term and continue */
1573 if( constant1 != 0.0 && constant2 != 0.0 )
1574 {
1575 nlrow->constant += elem.coef * constant1 * constant2;
1576 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1577 }
1578 continue;
1579 }
1580
1581 if( coef1 == 0.0 )
1582 {
1583 /* only the first variable was fixed, so we may add a linear term
1584 * elem.coef * x * y -> elem.coef * constant1 * (coef2 * var2 + constant2) */
1585 if( constant1 != 0.0 )
1586 {
1587 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, var2, elem.coef * constant1 * coef2, TRUE) );
1588 if( constant2 != 0.0 )
1589 {
1590 nlrow->constant += elem.coef * constant1 * constant2;
1591 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1592 }
1593 }
1594 /* continue with next element that is at position i now */
1595 continue;
1596 }
1597
1598 if( coef2 == 0.0 )
1599 {
1600 /* only the second variable was fixed, so we may add a linear term
1601 * elem.coef * x * y -> elem.coef * (coef1 * var1 + constant1) * constant2 */
1602 if( constant2 != 0.0 )
1603 {
1604 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, var1, elem.coef * coef1 * constant2, TRUE) );
1605 if( constant1 != 0.0 )
1606 {
1607 nlrow->constant += elem.coef * constant1 * constant2;
1608 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1609 }
1610 }
1611 /* continue with next element that is at position i now */
1612 continue;
1613 }
1614
1615 if( var1 == var2 && !SCIPvarIsActive(var1) )
1616 {
1617 SCIP_Real tmp;
1618 int* multaggrvaridxs;
1619 int j, k;
1620
1621 assert(SCIPvarGetStatus(var1) == SCIP_VARSTATUS_MULTAGGR);
1622 assert(coef1 == coef2); /*lint !e777*/
1623 assert(constant1 == constant2); /*lint !e777*/
1624 /* square term which variable is multi-aggregated
1625 * elem.coef * x^2 -> elem.coef * (coef1 * (multaggrconstant + sum_i multaggrscalar_i*multaggrvar_i) + constant1)^2
1626 * = elem.coef * ( (coef1 * multaggrconstant + constant1)^2 +
1627 * 2 * (coef1 * multaggrconstant + constant1) * coef1 * (sum_j multaggrscalar_j*multaggrvar_j) +
1628 * coef1^2 * (sum_{j,k} multaggrscalar_j*multaggrscalar_k*multaggrvar_j*multaggrvar_k)
1629 * )
1630 */
1631
1632 /* add constant part */
1633 tmp = coef1 * SCIPvarGetMultaggrConstant(var1) + constant1;
1634 if( tmp != 0.0 )
1635 {
1636 nlrow->constant += elem.coef * tmp * tmp;
1637 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1638 }
1639
1640 /* add linear part */
1641 if( constant1 != 0.0 || SCIPvarGetMultaggrConstant(var1) != 0.0 )
1642 {
1643 for( j = 0; j < SCIPvarGetMultaggrNVars(var1); ++j )
1644 {
1645 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var1)[j],
1646 2.0 * elem.coef * (coef1 * SCIPvarGetMultaggrConstant(var1) + constant1) * coef1 * SCIPvarGetMultaggrScalars(var1)[j], TRUE) );
1647 }
1648 }
1649
1650 /* setup array with indices of multi-aggregated variables in quadvars */
1651 SCIP_CALL( SCIPsetAllocBufferArray(set, &multaggrvaridxs, SCIPvarGetMultaggrNVars(var1)) );
1652 for( j = 0; j < SCIPvarGetMultaggrNVars(var1); ++j )
1653 {
1654 multaggrvaridxs[j] = SCIPnlrowSearchQuadVar(nlrow, SCIPvarGetMultaggrVars(var1)[j]);
1655 if( multaggrvaridxs[j] == -1 )
1656 {
1657 /* variable multaggrvar_j not existing in quadvars array yet, so add it */
1658 SCIP_CALL( SCIPnlrowAddQuadVar(nlrow, blkmem, set, SCIPvarGetMultaggrVars(var1)[j]) );
1659 multaggrvaridxs[j] = nlrow->nquadvars-1;
1660 }
1661 assert(nlrow->quadvars[multaggrvaridxs[j]] == SCIPvarGetMultaggrVars(var1)[j]);
1662 }
1663
1664 /* add quadratic elements elem.coef * coef1^2 * (sum_{j,k} multaggrscalar_j*multaggrscalar_k*multaggrvar_j*multaggrvar_k) */
1665 for( j = 0; j < SCIPvarGetMultaggrNVars(var1); ++j )
1666 {
1667 /* bilinear terms */
1668 for( k = 0; k < j; ++k )
1669 {
1670 newelem.idx1 = MIN(multaggrvaridxs[j], multaggrvaridxs[k]);
1671 newelem.idx2 = MAX(multaggrvaridxs[j], multaggrvaridxs[k]);
1672 newelem.coef = 2 * elem.coef * coef1 * coef1 * SCIPvarGetMultaggrScalars(var1)[j] * SCIPvarGetMultaggrScalars(var1)[k];
1673 SCIP_CALL( SCIPnlrowAddQuadElement(nlrow, blkmem, set, stat, nlp, newelem) );
1674 }
1675
1676 /* square term */
1677 newelem.idx1 = multaggrvaridxs[j];
1678 newelem.idx2 = multaggrvaridxs[j];
1679 newelem.coef = elem.coef * coef1 * coef1 * SCIPvarGetMultaggrScalars(var1)[j] * SCIPvarGetMultaggrScalars(var1)[j];
1680 SCIP_CALL( SCIPnlrowAddQuadElement(nlrow, blkmem, set, stat, nlp, newelem) );
1681 }
1682
1683 SCIPsetFreeBufferArray(set, &multaggrvaridxs);
1684
1685 /* continue with next element that is at position i now */
1686 continue;
1687 }
1688
1689 assert(var1 != NULL);
1690 assert(var2 != NULL);
1691 if( SCIPvarIsActive(var1) && !SCIPvarIsActive(var2) )
1692 {
1693 /* if the second variable is multi-aggregated, but the first one is not, swap both terms */
1694 SCIP_VAR* tmpvar;
1695 SCIP_Real tmpcoef;
1696 SCIP_Real tmpconstant;
1697
1698 tmpvar = var1;
1699 tmpcoef = coef1;
1700 tmpconstant = constant1;
1701 var2 = var1;
1702 coef2 = coef1;
1703 constant2 = constant1;
1704 var1 = tmpvar;
1705 coef1 = tmpcoef;
1706 constant1 = tmpconstant;
1707 }
1708
1709 if( !SCIPvarIsActive(var1) )
1710 {
1711 SCIP_Real tmp;
1712 int j;
1713
1714 assert(SCIPvarGetStatus(var1) == SCIP_VARSTATUS_MULTAGGR);
1715
1716 /* the first variable is multi-aggregated, add a constant and sequences of linear and quadratic terms:
1717 * elem.coef * x * y -> elem.coef * (coef1 * (multaggrconstant + sum_i multaggrscalar_i*multaggrvar_i) + constant1) * (coef2 * var2 + constant2)
1718 * = elem.coef * ( (coef1 * multaggrconstant + constant1) * constant2 +
1719 * (coef1 * multaggrconstant + constant1) * coef2 * var2 +
1720 * (coef1 * (sum_j multaggrscalar_j*multaggrvar_j)) * constant2 +
1721 * (coef1 * (sum_j multaggrscalar_j*multaggrvar_j)) * coef2 * var2
1722 * )
1723 */
1724
1725 /* add constant part */
1726 tmp = elem.coef * (coef1 * SCIPvarGetMultaggrConstant(var1) + constant1) * constant2;
1727 if( tmp != 0.0 )
1728 {
1729 nlrow->constant += tmp;
1730 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1731 }
1732
1733 /* add linear part */
1734 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, var2, elem.coef * (coef1 * SCIPvarGetMultaggrConstant(var1) + constant1) * coef2, TRUE) );
1735 if( constant2 != 0.0 )
1736 {
1737 for( j = 0; j < SCIPvarGetMultaggrNVars(var1); ++j )
1738 {
1739 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var1)[j], elem.coef * coef1 * SCIPvarGetMultaggrScalars(var1)[j] * constant2, TRUE) );
1740 }
1741 }
1742
1743 /* get index of var2 in quadvars array */
1744 idx2 = SCIPnlrowSearchQuadVar(nlrow, var2);
1745 if( idx2 == -1 )
1746 {
1747 /* variable var2 not existing in quadvars array yet, so add it */
1748 SCIP_CALL( SCIPnlrowAddQuadVar(nlrow, blkmem, set, var2) );
1749 idx2 = nlrow->nquadvars-1;
1750 assert(nlrow->quadvars[idx2] == var2);
1751 }
1752
1753 /* add quadratic elements elem.coef * coef1 * (sum_j multaggrscalar_j*multaggrvar_j) * coef2 * var2 */
1754 for( j = 0; j < SCIPvarGetMultaggrNVars(var1); ++j )
1755 {
1756 newelem.idx1 = SCIPnlrowSearchQuadVar(nlrow, SCIPvarGetMultaggrVars(var1)[j]);
1757 if( newelem.idx1 == -1 )
1758 {
1759 /* variable not existing in quadvars array yet, so add it */
1760 SCIP_CALL( SCIPnlrowAddQuadVar(nlrow, blkmem, set, SCIPvarGetMultaggrVars(var1)[j]) );
1761 newelem.idx1 = nlrow->nquadvars-1;
1762 assert(nlrow->quadvars[newelem.idx1] == SCIPvarGetMultaggrVars(var1)[j]);
1763 }
1764
1765 newelem.idx2 = idx2;
1766
1767 /* swap indices if newelem.idx1 <= newelem.idx2 */
1768 if( newelem.idx1 > idx2 )
1769 {
1770 newelem.idx2 = newelem.idx1;
1771 newelem.idx1 = idx2;
1772 }
1773
1774 newelem.coef = elem.coef * coef1 * coef2 * SCIPvarGetMultaggrScalars(var1)[j];
1775
1776 SCIP_CALL( SCIPnlrowAddQuadElement(nlrow, blkmem, set, stat, nlp, newelem) );
1777
1778 /* continue with next element that is at position i now */
1779 continue;
1780 }
1781 }
1782
1783 assert(SCIPvarIsActive(var1));
1784 assert(SCIPvarIsActive(var2));
1785 /* add elem.coef * (coef1 * var1 + constant1) * (coef2 * var2 + constant2) */
1786 /* add constant part */
1787 if( constant1 != 0.0 && constant2 != 0.0 )
1788 {
1789 nlrow->constant += elem.coef * constant1 * constant2;
1790 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1791 }
1792 /* add linear coefficients */
1793 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, var1, elem.coef * coef1 * constant2, TRUE) );
1794 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, var2, elem.coef * coef2 * constant1, TRUE) );
1795 /* get index of var1 in quadvars array */
1796 newelem.idx1 = SCIPnlrowSearchQuadVar(nlrow, var1);
1797 if( newelem.idx1 == -1 )
1798 {
1799 /* variable var2 not existing in quadvars array yet, so add it */
1800 SCIP_CALL( SCIPnlrowAddQuadVar(nlrow, blkmem, set, var1) );
1801 newelem.idx1 = nlrow->nquadvars-1;
1802 assert(nlrow->quadvars[newelem.idx1] == var1);
1803 }
1804 /* get index of var2 in quadvars array */
1805 newelem.idx2 = SCIPnlrowSearchQuadVar(nlrow, var2);
1806 if( newelem.idx2 == -1 )
1807 {
1808 /* variable var2 not existing in quadvars array yet, so add it */
1809 SCIP_CALL( SCIPnlrowAddQuadVar(nlrow, blkmem, set, var2) );
1810 newelem.idx2 = nlrow->nquadvars-1;
1811 assert(nlrow->quadvars[newelem.idx2] == var2);
1812 }
1813 /* make sure idx1 <= idx2 */
1814 if( newelem.idx1 > newelem.idx2 )
1815 {
1816 idx2 = newelem.idx2;
1817 newelem.idx2 = newelem.idx1;
1818 newelem.idx1 = idx2;
1819 }
1820 newelem.coef = elem.coef * coef1 * coef2;
1821 /* add new quadratic element */
1822 SCIP_CALL( SCIPnlrowAddQuadElement(nlrow, blkmem, set, stat, nlp, newelem) );
1823
1824 /* continue with next element that is at position i now */
1825 }
1826
1827 /* clean up unused variables */
1828 if( nlrow->nquadelems == 0 )
1829 {
1830 /* the complete quadratic part was fixed or linearized, so we just free up all memory */
1831 BMSfreeBlockMemoryArray(blkmem, &nlrow->quadvars, nlrow->quadvarssize);
1832 if( nlrow->quadvarshash != NULL )
1833 SCIPhashmapFree(&nlrow->quadvarshash);
1834 BMSfreeBlockMemoryArray(blkmem, &nlrow->quadelems, nlrow->quadelemssize);
1835 nlrow->nquadvars = 0;
1836 nlrow->quadvarssize = 0;
1837 nlrow->nquadelems = 0;
1838 nlrow->quadelemssize = 0;
1839 nlrow->quadelemssorted = TRUE;
1840 }
1841 else if( havechange )
1842 {
1843 /* something had changed, so we likely have quadratic variables to remove */
1844 int* newpos;
1845 int offset;
1846
1847 /* compute new positions of variables in quadvars array */
1848 SCIP_CALL( SCIPsetAllocBufferArray(set, &newpos, nlrow->nquadvars) );
1849
1850 offset = 0;
1851 for( i = 0; i < nvarsold; ++i )
1852 {
1853 /* previously existing variables should either be active or not used anymore */
1854 assert(!used[i] || SCIPvarIsActive(nlrow->quadvars[i]));
1855
1856 if( !used[i] )
1857 {
1858 /* variable has been removed */
1859 newpos[i] = -1;
1860 ++offset;
1861 }
1862 else
1863 {
1864 /* variable will move to position i-offset */
1865 newpos[i] = i-offset;
1866 }
1867 }
1868 for( ; i < nlrow->nquadvars; ++i )
1869 {
1870 if( !SCIPvarIsActive(nlrow->quadvars[i]) )
1871 {
1872 /* it can have happened that a new quadratic variable was added that is not active (when multiplying two multi-aggregations)
1873 * in this case, the variable was only temporarily used and should not be used anymore (this is asserted in the next for-loop below),
1874 * thus we can remove it
1875 */
1876 newpos[i] = -1;
1877 ++offset;
1878 }
1879 else
1880 {
1881 /* variable will move to position i-offset */
1882 newpos[i] = i-offset;
1883 }
1884 }
1885
1886 /* adjust variable indices in quadratic elements */
1887 for( i = 0; i < nlrow->nquadelems; ++i )
1888 {
1889 assert(newpos[nlrow->quadelems[i].idx1] >= 0);
1890 assert(newpos[nlrow->quadelems[i].idx2] >= 0);
1891 nlrow->quadelems[i].idx1 = newpos[nlrow->quadelems[i].idx1];
1892 nlrow->quadelems[i].idx2 = newpos[nlrow->quadelems[i].idx2];
1893 assert(nlrow->quadelems[i].idx1 <= nlrow->quadelems[i].idx2); /* the way we shrink the quadvars array, variables should stay in the same relative position to each other */
1894 }
1895
1896 /* move variables in quadvars array and update quadvarshash */
1897 for( i = 0; i < nlrow->nquadvars; ++i )
1898 {
1899 if( newpos[i] == -1 )
1900 {
1901 if( nlrow->quadvarshash != NULL )
1902 {
1903 SCIP_CALL( SCIPhashmapRemove(nlrow->quadvarshash, (void*)nlrow->quadvars[i]) );
1904 }
1905 }
1906 else
1907 {
1908 nlrow->quadvars[newpos[i]] = nlrow->quadvars[i];
1909 if( nlrow->quadvarshash != NULL )
1910 {
1911 SCIP_CALL( SCIPhashmapSetImageInt(nlrow->quadvarshash, (void*)nlrow->quadvars[i], newpos[i]) );
1912 }
1913 }
1914 }
1915 nlrow->nquadvars -= offset;
1916
1917 SCIPsetFreeBufferArray(set, &newpos);
1918 }
1919
1920 SCIPsetFreeBufferArray(set, &used);
1921
1922 SCIPsetDebugMsg(set, "finished removing fixed quadratic variables\n");
1923
1924 return SCIP_OKAY;
1925 }
1926
1927 /** removes fixed variables from expression tree of a nonlinear row */
1928 static
nlrowRemoveFixedExprtreeVars(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)1929 SCIP_RETCODE nlrowRemoveFixedExprtreeVars(
1930 SCIP_NLROW* nlrow, /**< nonlinear row */
1931 SCIP_SET* set, /**< global SCIP settings */
1932 SCIP_STAT* stat, /**< problem statistics data */
1933 SCIP_NLP* nlp /**< current NLP data */
1934 )
1935 {
1936 SCIP_Bool changed;
1937
1938 if( nlrow->exprtree == NULL )
1939 return SCIP_OKAY;
1940
1941 SCIP_CALL( SCIPexprtreeRemoveFixedVars(nlrow->exprtree, set, &changed, NULL, NULL) );
1942 if( changed )
1943 {
1944 SCIP_CALL( nlrowExprtreeChanged(nlrow, set, stat, nlp) );
1945 }
1946
1947 if( SCIPexprtreeGetNVars(nlrow->exprtree) == 0 && SCIPexprtreeGetNParams(nlrow->exprtree) == 0 )
1948 {
1949 /* if expression tree is constant and not parameterized now, remove it */
1950 SCIP_Real exprval;
1951 SCIP_CALL( SCIPexprtreeEval(nlrow->exprtree, NULL, &exprval) );
1952 SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + exprval) );
1953
1954 SCIP_CALL( SCIPexprtreeFree(&nlrow->exprtree) );
1955 }
1956
1957 return SCIP_OKAY;
1958 }
1959
1960 /** removes fixed variable from nonlinear row */
1961 static
nlrowRemoveFixedVar(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_VAR * var)1962 SCIP_RETCODE nlrowRemoveFixedVar(
1963 SCIP_NLROW* nlrow, /**< nonlinear row */
1964 BMS_BLKMEM* blkmem, /**< block memory */
1965 SCIP_SET* set, /**< global SCIP settings */
1966 SCIP_STAT* stat, /**< problem statistics data */
1967 SCIP_NLP* nlp, /**< current NLP data */
1968 SCIP_VAR* var /**< variable that had been fixed */
1969 )
1970 {
1971 int pos;
1972
1973 assert(nlrow != NULL);
1974 assert(var != NULL);
1975 assert(!SCIPvarIsActive(var));
1976
1977 /* search for variable in linear part and remove if existing */
1978 pos = nlrowSearchLinearCoef(nlrow, var);
1979 if( pos >= 0 )
1980 {
1981 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
1982 }
1983
1984 /* search for variable in quadratic part and remove all fixed quadratic variables if existing */
1985 pos = SCIPnlrowSearchQuadVar(nlrow, var);
1986 if( pos >= 0 )
1987 {
1988 SCIP_CALL( nlrowRemoveFixedQuadVars(nlrow, blkmem, set, stat, nlp) );
1989 }
1990
1991 /* search for variable in non-quadratic part and remove all fixed variables in expression tree if existing */
1992 if( nlrow->exprtree != NULL && SCIPexprtreeFindVar(nlrow->exprtree, var) >= 0 )
1993 {
1994 SCIP_CALL( nlrowRemoveFixedExprtreeVars(nlrow, set, stat, nlp) );
1995 }
1996
1997 return SCIP_OKAY;
1998 }
1999
2000 /*
2001 * public NLP nonlinear row methods
2002 */
2003
2004 /** create a new nonlinear row
2005 * the new row is already captured
2006 */
SCIPnlrowCreate(SCIP_NLROW ** nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,const char * name,SCIP_Real constant,int nlinvars,SCIP_VAR ** linvars,SCIP_Real * lincoefs,int nquadvars,SCIP_VAR ** quadvars,int nquadelems,SCIP_QUADELEM * quadelems,SCIP_EXPRTREE * exprtree,SCIP_Real lhs,SCIP_Real rhs,SCIP_EXPRCURV curvature)2007 SCIP_RETCODE SCIPnlrowCreate(
2008 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */
2009 BMS_BLKMEM* blkmem, /**< block memory */
2010 SCIP_SET* set, /**< global SCIP settings */
2011 const char* name, /**< name of nonlinear row */
2012 SCIP_Real constant, /**< constant */
2013 int nlinvars, /**< number of linear variables */
2014 SCIP_VAR** linvars, /**< linear variables, or NULL if nlinvars == 0 */
2015 SCIP_Real* lincoefs, /**< linear coefficients, or NULL if nlinvars == 0 */
2016 int nquadvars, /**< number of variables in quadratic terms */
2017 SCIP_VAR** quadvars, /**< variables in quadratic terms, or NULL if nquadvars == 0 */
2018 int nquadelems, /**< number of entries in quadratic term matrix */
2019 SCIP_QUADELEM* quadelems, /**< elements of quadratic term matrix, or NULL if nquadelems == 0 */
2020 SCIP_EXPRTREE* exprtree, /**< expression tree, or NULL */
2021 SCIP_Real lhs, /**< left hand side */
2022 SCIP_Real rhs, /**< right hand side */
2023 SCIP_EXPRCURV curvature /**< curvature of the nonlinear row */
2024 )
2025 {
2026 #ifndef NDEBUG
2027 int i;
2028 #endif
2029
2030 assert(nlrow != NULL);
2031 assert(blkmem != NULL);
2032 assert(set != NULL);
2033 assert(name != NULL);
2034 assert(!SCIPsetIsInfinity(set, ABS(constant)));
2035 assert(nlinvars == 0 || linvars != NULL);
2036 assert(nlinvars == 0 || lincoefs != NULL);
2037 assert(nquadvars == 0 || quadvars != NULL);
2038 assert(nquadelems == 0 || quadelems != NULL);
2039 assert(nquadelems == 0 || nquadvars > 0);
2040 assert(SCIPsetIsRelLE(set, lhs, rhs));
2041
2042 SCIP_ALLOC( BMSallocBlockMemory(blkmem, nlrow) );
2043
2044 /* constant part */
2045 assert(!SCIPsetIsInfinity(set, REALABS(constant)));
2046 (*nlrow)->constant = constant;
2047
2048 #ifndef NDEBUG
2049 for( i = 0; i < nlinvars; ++i )
2050 {
2051 assert(linvars[i] != NULL);
2052 assert(!SCIPsetIsInfinity(set, REALABS(lincoefs[i])));
2053 }
2054 #endif
2055
2056 /* linear part */
2057 (*nlrow)->nlinvars = nlinvars;
2058 (*nlrow)->linvarssize = nlinvars;
2059 if( nlinvars > 0 )
2060 {
2061 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->linvars, linvars, nlinvars) );
2062 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->lincoefs, lincoefs, nlinvars) );
2063 (*nlrow)->linvarssorted = FALSE;
2064 }
2065 else
2066 {
2067 (*nlrow)->linvars = NULL;
2068 (*nlrow)->lincoefs = NULL;
2069 (*nlrow)->linvarssorted = TRUE;
2070 }
2071
2072 /* quadratic variables */
2073 #ifndef NDEBUG
2074 for( i = 0; i < nquadvars; ++i )
2075 assert(quadvars[i] != NULL);
2076 #endif
2077
2078 (*nlrow)->nquadvars = nquadvars;
2079 (*nlrow)->quadvarssize = nquadvars;
2080 (*nlrow)->quadvarshash = NULL;
2081 if( nquadvars > 0 )
2082 {
2083 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->quadvars, quadvars, nquadvars) );
2084 SCIP_CALL( nlrowSetupQuadVarsHash(*nlrow, blkmem) );
2085 }
2086 else
2087 {
2088 (*nlrow)->quadvars = NULL;
2089 }
2090
2091 /* quadratic elements */
2092 #ifndef NDEBUG
2093 for( i = 0; i < nquadelems; ++i )
2094 {
2095 assert(quadelems[i].idx1 >= 0);
2096 assert(quadelems[i].idx1 < nquadvars);
2097 assert(quadelems[i].idx2 >= 0);
2098 assert(quadelems[i].idx2 < nquadvars);
2099 assert(quadelems[i].idx1 <= quadelems[i].idx2);
2100 assert(!SCIPsetIsInfinity(set, REALABS(quadelems[i].coef)));
2101 }
2102 #endif
2103
2104 (*nlrow)->nquadelems = nquadelems;
2105 (*nlrow)->quadelemssize = nquadelems;
2106 if( nquadelems > 0 )
2107 {
2108 assert(nquadvars > 0);
2109 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->quadelems, quadelems, nquadelems) );
2110 (*nlrow)->quadelemssorted = FALSE;
2111 }
2112 else
2113 {
2114 (*nlrow)->quadelems = NULL;
2115 (*nlrow)->quadelemssorted = TRUE;
2116 }
2117
2118 /* non-quadratic part */
2119 if( exprtree != NULL )
2120 {
2121 SCIP_CALL( SCIPexprtreeCopy( blkmem, &(*nlrow)->exprtree, exprtree) );
2122 }
2123 else
2124 {
2125 (*nlrow)->exprtree = NULL;
2126 }
2127
2128 /* left and right hand sides, asserted above that lhs is relatively less equal than rhs */
2129 (*nlrow)->lhs = MIN(lhs, rhs);
2130 (*nlrow)->rhs = MAX(lhs, rhs);
2131
2132 /* miscellaneous */
2133 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->name, name, strlen(name)+1) );
2134 (*nlrow)->activity = SCIP_INVALID;
2135 (*nlrow)->validactivitynlp = FALSE;
2136 (*nlrow)->pseudoactivity = SCIP_INVALID;
2137 (*nlrow)->validpsactivitydomchg = FALSE;
2138 (*nlrow)->minactivity = SCIP_INVALID;
2139 (*nlrow)->maxactivity = SCIP_INVALID;
2140 (*nlrow)->validactivitybdsdomchg = FALSE;
2141 (*nlrow)->nlpindex = -1;
2142 (*nlrow)->nlpiindex = -1;
2143 (*nlrow)->nuses = 0;
2144 (*nlrow)->dualsol = 0.0;
2145 (*nlrow)->curvature = curvature;
2146
2147 /* capture the nonlinear row */
2148 SCIPnlrowCapture(*nlrow);
2149
2150 return SCIP_OKAY;
2151 }
2152
2153 /** create a nonlinear row that is a copy of a given row
2154 * the new row is already captured
2155 */
SCIPnlrowCreateCopy(SCIP_NLROW ** nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_NLROW * sourcenlrow)2156 SCIP_RETCODE SCIPnlrowCreateCopy(
2157 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */
2158 BMS_BLKMEM* blkmem, /**< block memory */
2159 SCIP_SET* set, /**< global SCIP settings */
2160 SCIP_NLROW* sourcenlrow /**< nonlinear row to copy */
2161 )
2162 {
2163 assert(nlrow != NULL);
2164 assert(blkmem != NULL);
2165 assert(set != NULL);
2166 assert(sourcenlrow != NULL);
2167
2168 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, sourcenlrow->name,
2169 sourcenlrow->constant,
2170 sourcenlrow->nlinvars, sourcenlrow->linvars, sourcenlrow->lincoefs,
2171 sourcenlrow->nquadvars, sourcenlrow->quadvars, sourcenlrow->nquadelems, sourcenlrow->quadelems,
2172 sourcenlrow->exprtree,
2173 sourcenlrow->lhs, sourcenlrow->rhs, sourcenlrow->curvature) );
2174
2175 (*nlrow)->linvarssorted = sourcenlrow->linvarssorted;
2176 (*nlrow)->quadelemssorted = sourcenlrow->quadelemssorted;
2177 (*nlrow)->activity = sourcenlrow->activity;
2178 (*nlrow)->validactivitynlp = sourcenlrow->validactivitynlp;
2179 (*nlrow)->pseudoactivity = sourcenlrow->pseudoactivity;
2180 (*nlrow)->validpsactivitydomchg = sourcenlrow->validpsactivitydomchg;
2181 (*nlrow)->minactivity = sourcenlrow->minactivity;
2182 (*nlrow)->maxactivity = sourcenlrow->maxactivity;
2183 (*nlrow)->validactivitybdsdomchg = sourcenlrow->validactivitybdsdomchg;
2184
2185 return SCIP_OKAY;
2186 }
2187
2188 /** create a new nonlinear row from a linear row
2189 * the new row is already captured
2190 */
SCIPnlrowCreateFromRow(SCIP_NLROW ** nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_ROW * row)2191 SCIP_RETCODE SCIPnlrowCreateFromRow(
2192 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */
2193 BMS_BLKMEM* blkmem, /**< block memory */
2194 SCIP_SET* set, /**< global SCIP settings */
2195 SCIP_ROW* row /**< the linear row to copy */
2196 )
2197 {
2198 int rownz;
2199
2200 assert(nlrow != NULL);
2201 assert(blkmem != NULL);
2202 assert(set != NULL);
2203 assert(row != NULL);
2204
2205 rownz = SCIProwGetNNonz(row);
2206
2207 if( rownz > 1 )
2208 {
2209 SCIP_VAR** rowvars;
2210 int i;
2211
2212 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowvars, rownz) );
2213
2214 for( i = 0; i < rownz; ++i )
2215 {
2216 rowvars[i] = SCIPcolGetVar(SCIProwGetCols(row)[i]);
2217 assert(rowvars[i] != NULL);
2218 }
2219
2220 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, SCIProwGetName(row),
2221 SCIProwGetConstant(row),
2222 rownz, rowvars, SCIProwGetVals(row),
2223 0, NULL, 0, NULL,
2224 NULL,
2225 SCIProwGetLhs(row), SCIProwGetRhs(row),
2226 SCIP_EXPRCURV_LINEAR) );
2227
2228 SCIPsetFreeBufferArray(set, &rowvars);
2229 }
2230 else if( rownz == 1 )
2231 {
2232 SCIP_VAR* rowvar;
2233
2234 rowvar = SCIPcolGetVar(SCIProwGetCols(row)[0]);
2235
2236 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, SCIProwGetName(row),
2237 SCIProwGetConstant(row),
2238 1, &rowvar, SCIProwGetVals(row),
2239 0, NULL, 0, NULL,
2240 NULL,
2241 SCIProwGetLhs(row), SCIProwGetRhs(row),
2242 SCIP_EXPRCURV_LINEAR) );
2243 }
2244 else
2245 {
2246 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, SCIProwGetName(row),
2247 SCIProwGetConstant(row),
2248 0, NULL, NULL,
2249 0, NULL, 0, NULL,
2250 NULL,
2251 SCIProwGetLhs(row), SCIProwGetRhs(row),
2252 SCIP_EXPRCURV_LINEAR) );
2253 }
2254
2255 return SCIP_OKAY;
2256 }
2257
2258 /** frees a nonlinear row */
SCIPnlrowFree(SCIP_NLROW ** nlrow,BMS_BLKMEM * blkmem)2259 SCIP_RETCODE SCIPnlrowFree(
2260 SCIP_NLROW** nlrow, /**< pointer to NLP row */
2261 BMS_BLKMEM* blkmem /**< block memory */
2262 )
2263 {
2264 assert(blkmem != NULL);
2265 assert(nlrow != NULL);
2266 assert(*nlrow != NULL);
2267 assert((*nlrow)->nuses == 0);
2268 assert((*nlrow)->nlpindex == -1);
2269 assert((*nlrow)->nlpiindex == -1);
2270
2271 /* linear part */
2272 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->linvars, (*nlrow)->linvarssize);
2273 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->lincoefs, (*nlrow)->linvarssize);
2274
2275 /* quadratic part */
2276 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->quadvars, (*nlrow)->quadvarssize);
2277 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->quadelems, (*nlrow)->quadelemssize);
2278 if( (*nlrow)->quadvarshash != NULL )
2279 SCIPhashmapFree(&(*nlrow)->quadvarshash);
2280
2281 /* non-quadratic part */
2282 if( (*nlrow)->exprtree != NULL )
2283 {
2284 SCIP_CALL( SCIPexprtreeFree(&(*nlrow)->exprtree) );
2285 }
2286
2287 /* miscellaneous */
2288 BMSfreeBlockMemoryArray(blkmem, &(*nlrow)->name, strlen((*nlrow)->name)+1);
2289
2290 BMSfreeBlockMemory(blkmem, nlrow);
2291
2292 return SCIP_OKAY;
2293 }
2294
2295 /** output nonlinear row to file stream */
SCIPnlrowPrint(SCIP_NLROW * nlrow,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)2296 SCIP_RETCODE SCIPnlrowPrint(
2297 SCIP_NLROW* nlrow, /**< NLP row */
2298 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2299 FILE* file /**< output file (or NULL for standard output) */
2300 )
2301 {
2302 int i;
2303
2304 assert(nlrow != NULL);
2305
2306 /* print row name */
2307 if( nlrow->name != NULL && nlrow->name[0] != '\0' )
2308 {
2309 SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", nlrow->name);
2310 }
2311
2312 /* print left hand side */
2313 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g <= ", nlrow->lhs);
2314
2315 /* print constant */
2316 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g ", nlrow->constant);
2317
2318 /* print linear coefficients */
2319 for( i = 0; i < nlrow->nlinvars; ++i )
2320 {
2321 assert(nlrow->linvars[i] != NULL);
2322 assert(SCIPvarGetName(nlrow->linvars[i]) != NULL);
2323 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", nlrow->lincoefs[i], SCIPvarGetName(nlrow->linvars[i]));
2324 }
2325
2326 /* print quadratic elements */
2327 for( i = 0; i < nlrow->nquadelems; ++i )
2328 {
2329 assert(SCIPvarGetName(nlrow->quadvars[nlrow->quadelems[i].idx1]) != NULL);
2330 assert(SCIPvarGetName(nlrow->quadvars[nlrow->quadelems[i].idx2]) != NULL);
2331 if( nlrow->quadelems[i].idx1 == nlrow->quadelems[i].idx2 )
2332 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15gsqr(<%s>) ", nlrow->quadelems[i].coef, SCIPvarGetName(nlrow->quadvars[nlrow->quadelems[i].idx1]));
2333 else
2334 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s><%s> ", nlrow->quadelems[i].coef, SCIPvarGetName(nlrow->quadvars[nlrow->quadelems[i].idx1]), SCIPvarGetName(nlrow->quadvars[nlrow->quadelems[i].idx2]));
2335 }
2336
2337 /* print non-quadratic part */
2338 if( nlrow->exprtree != NULL )
2339 {
2340 SCIPmessageFPrintInfo(messagehdlr, file, " + ");
2341 SCIP_CALL( SCIPexprtreePrintWithNames(nlrow->exprtree, messagehdlr, file) );
2342 }
2343
2344 /* print right hand side */
2345 SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", nlrow->rhs);
2346
2347 return SCIP_OKAY;
2348 }
2349
2350 /** increases usage counter of NLP nonlinear row */
SCIPnlrowCapture(SCIP_NLROW * nlrow)2351 void SCIPnlrowCapture(
2352 SCIP_NLROW* nlrow /**< nonlinear row to capture */
2353 )
2354 {
2355 assert(nlrow != NULL);
2356 assert(nlrow->nuses >= 0);
2357
2358 SCIPdebugMessage("capture nonlinear row <%s> with nuses=%d\n", nlrow->name, nlrow->nuses);
2359 nlrow->nuses++;
2360 }
2361
2362 /** decreases usage counter of NLP nonlinear row */
SCIPnlrowRelease(SCIP_NLROW ** nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set)2363 SCIP_RETCODE SCIPnlrowRelease(
2364 SCIP_NLROW** nlrow, /**< nonlinear row to free */
2365 BMS_BLKMEM* blkmem, /**< block memory */
2366 SCIP_SET* set /**< global SCIP settings */
2367 )
2368 {
2369 assert(blkmem != NULL);
2370 assert(nlrow != NULL);
2371 assert(*nlrow != NULL);
2372 assert((*nlrow)->nuses >= 1);
2373
2374 SCIPsetDebugMsg(set, "release nonlinear row <%s> with nuses=%d\n", (*nlrow)->name, (*nlrow)->nuses);
2375 (*nlrow)->nuses--;
2376 if( (*nlrow)->nuses == 0 )
2377 {
2378 SCIP_CALL( SCIPnlrowFree(nlrow, blkmem) );
2379 }
2380
2381 *nlrow = NULL;
2382
2383 return SCIP_OKAY;
2384 } /*lint !e715*/
2385
2386 /** ensures, that linear coefficient array of nonlinear row can store at least num entries */
SCIPnlrowEnsureLinearSize(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)2387 SCIP_RETCODE SCIPnlrowEnsureLinearSize(
2388 SCIP_NLROW* nlrow, /**< NLP row */
2389 BMS_BLKMEM* blkmem, /**< block memory */
2390 SCIP_SET* set, /**< global SCIP settings */
2391 int num /**< minimum number of entries to store */
2392 )
2393 {
2394 assert(nlrow != NULL);
2395 assert(nlrow->nlinvars <= nlrow->linvarssize);
2396
2397 if( num > nlrow->linvarssize )
2398 {
2399 int newsize;
2400
2401 newsize = SCIPsetCalcMemGrowSize(set, num);
2402 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->linvars, nlrow->linvarssize, newsize) );
2403 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->lincoefs, nlrow->linvarssize, newsize) );
2404 nlrow->linvarssize = newsize;
2405 }
2406 assert(num <= nlrow->linvarssize);
2407
2408 return SCIP_OKAY;
2409 }
2410
2411 /** adds a previously non existing linear coefficient to an NLP nonlinear row */
SCIPnlrowAddLinearCoef(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_VAR * var,SCIP_Real val)2412 SCIP_RETCODE SCIPnlrowAddLinearCoef(
2413 SCIP_NLROW* nlrow, /**< NLP nonlinear row */
2414 BMS_BLKMEM* blkmem, /**< block memory */
2415 SCIP_SET* set, /**< global SCIP settings */
2416 SCIP_STAT* stat, /**< problem statistics data */
2417 SCIP_NLP* nlp, /**< current NLP data */
2418 SCIP_VAR* var, /**< variable */
2419 SCIP_Real val /**< value of coefficient */
2420 )
2421 {
2422 /* if row is in NLP already, make sure that only active variables are added */
2423 if( nlrow->nlpindex >= 0 )
2424 {
2425 SCIP_Real constant;
2426
2427 /* get corresponding active or multi-aggregated variable */
2428 constant = 0.0;
2429 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &val, &constant) );
2430
2431 /* add constant */
2432 SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + constant) );
2433
2434 if( val == 0.0 )
2435 /* var has been fixed */
2436 return SCIP_OKAY;
2437
2438 if( !SCIPvarIsActive(var) )
2439 {
2440 /* var should be multi-aggregated, so call this function recursively */
2441 int i;
2442
2443 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2444 for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i )
2445 {
2446 SCIP_CALL( SCIPnlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], SCIPvarGetMultaggrScalars(var)[i] * val) );
2447 }
2448 return SCIP_OKAY;
2449 }
2450
2451 /* var is active, so can go on like normal */
2452 }
2453
2454 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, val) );
2455
2456 return SCIP_OKAY;
2457 }
2458
2459 /** deletes linear coefficient from nonlinear row */
SCIPnlrowDelLinearCoef(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_VAR * var)2460 SCIP_RETCODE SCIPnlrowDelLinearCoef(
2461 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */
2462 SCIP_SET* set, /**< global SCIP settings */
2463 SCIP_STAT* stat, /**< problem statistics data */
2464 SCIP_NLP* nlp, /**< current NLP data */
2465 SCIP_VAR* var /**< coefficient to be deleted */
2466 )
2467 {
2468 int pos;
2469
2470 assert(nlrow != NULL);
2471 assert(var != NULL);
2472
2473 /* if the row is in the NLP already, we can only have active variables, so var should also be active; in non-debug mode, one gets an error below */
2474 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
2475
2476 /* search the position of the variable in the row's variable vector */
2477 pos = nlrowSearchLinearCoef(nlrow, var);
2478 if( pos == -1 )
2479 {
2480 SCIPerrorMessage("coefficient for variable <%s> doesn't exist in nonlinear row <%s>\n", SCIPvarGetName(var), nlrow->name);
2481 return SCIP_INVALIDDATA;
2482 }
2483 assert(0 <= pos && pos < nlrow->nlinvars);
2484 assert(nlrow->linvars[pos] == var);
2485
2486 /* delete the variable from the row's variable vector */
2487 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
2488
2489 return SCIP_OKAY;
2490 }
2491
2492 /** changes or adds a linear coefficient to a nonlinear row */
SCIPnlrowChgLinearCoef(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_VAR * var,SCIP_Real coef)2493 SCIP_RETCODE SCIPnlrowChgLinearCoef(
2494 SCIP_NLROW* nlrow, /**< nonlinear row */
2495 BMS_BLKMEM* blkmem, /**< block memory */
2496 SCIP_SET* set, /**< global SCIP settings */
2497 SCIP_STAT* stat, /**< problem statistics data */
2498 SCIP_NLP* nlp, /**< current NLP data */
2499 SCIP_VAR* var, /**< variable */
2500 SCIP_Real coef /**< new value of coefficient */
2501 )
2502 {
2503 int pos;
2504
2505 assert(nlrow != NULL);
2506 assert(nlp != NULL);
2507 assert(var != NULL);
2508
2509 /* search the position of the variable in the row's linvars vector */
2510 pos = nlrowSearchLinearCoef(nlrow, var);
2511
2512 /* check, if column already exists in the row's linear variables vector */
2513 if( pos == -1 )
2514 {
2515 if( !SCIPsetIsZero(set, coef) )
2516 {
2517 /* add previously not existing coefficient */
2518 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) );
2519 }
2520 }
2521 else
2522 {
2523 /* change the coefficient in the row */
2524 SCIP_CALL( nlrowChgLinearCoefPos(nlrow, set, stat, nlp, pos, coef) );
2525 }
2526
2527 return SCIP_OKAY;
2528 }
2529
2530 /** ensures, that quadratic variables array of nonlinear row can store at least num entries */
SCIPnlrowEnsureQuadVarsSize(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)2531 SCIP_RETCODE SCIPnlrowEnsureQuadVarsSize(
2532 SCIP_NLROW* nlrow, /**< NLP row */
2533 BMS_BLKMEM* blkmem, /**< block memory */
2534 SCIP_SET* set, /**< global SCIP settings */
2535 int num /**< minimum number of entries to store */
2536 )
2537 {
2538 assert(nlrow != NULL);
2539 assert(nlrow->nquadvars <= nlrow->quadvarssize);
2540
2541 if( num > nlrow->quadvarssize )
2542 {
2543 int newsize;
2544
2545 newsize = SCIPsetCalcMemGrowSize(set, num);
2546 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->quadvars, nlrow->quadvarssize, newsize) );
2547 nlrow->quadvarssize = newsize;
2548 }
2549 assert(num <= nlrow->quadvarssize);
2550
2551 return SCIP_OKAY;
2552 }
2553
2554 /** adds variable to quadvars array of row */
SCIPnlrowAddQuadVar(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_VAR * var)2555 SCIP_RETCODE SCIPnlrowAddQuadVar(
2556 SCIP_NLROW* nlrow, /**< nonlinear row */
2557 BMS_BLKMEM* blkmem, /**< block memory */
2558 SCIP_SET* set, /**< global SCIP settings */
2559 SCIP_VAR* var /**< variable to search for */
2560 )
2561 {
2562 assert(blkmem != NULL);
2563 assert(nlrow != NULL);
2564 assert(var != NULL);
2565
2566 /* assert that only active variables are added once the row is in the NLP */
2567 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
2568
2569 /* assert that variable has not been added already */
2570 assert(SCIPnlrowSearchQuadVar(nlrow, var) == -1);
2571
2572 SCIP_CALL( SCIPnlrowEnsureQuadVarsSize(nlrow, blkmem, set, nlrow->nquadvars+1) );
2573 nlrow->quadvars[nlrow->nquadvars] = var;
2574 nlrow->nquadvars++;
2575
2576 if( nlrow->quadvarshash == NULL )
2577 {
2578 SCIP_CALL( nlrowSetupQuadVarsHash(nlrow, blkmem) );
2579 }
2580 else
2581 {
2582 SCIP_CALL( SCIPhashmapInsertInt(nlrow->quadvarshash, (void*)var, nlrow->nquadvars-1) );
2583 }
2584 assert(SCIPnlrowSearchQuadVar(nlrow, var) == nlrow->nquadvars-1);
2585
2586 return SCIP_OKAY;
2587 }
2588
2589 /** ensures, that quadratic elements array of nonlinear row can store at least num entries */
SCIPnlrowEnsureQuadElementsSize(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)2590 SCIP_RETCODE SCIPnlrowEnsureQuadElementsSize(
2591 SCIP_NLROW* nlrow, /**< NLP row */
2592 BMS_BLKMEM* blkmem, /**< block memory */
2593 SCIP_SET* set, /**< global SCIP settings */
2594 int num /**< minimum number of entries to store */
2595 )
2596 {
2597 assert(nlrow != NULL);
2598 assert(nlrow->nquadelems <= nlrow->quadelemssize);
2599
2600 if( num > nlrow->quadelemssize )
2601 {
2602 int newsize;
2603
2604 newsize = SCIPsetCalcMemGrowSize(set, num);
2605 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->quadelems, nlrow->quadelemssize, newsize) );
2606 nlrow->quadelemssize = newsize;
2607 }
2608 assert(num <= nlrow->quadelemssize);
2609
2610 return SCIP_OKAY;
2611 }
2612
2613 /** adds a previously non existing quadratic element to an NLP nonlinear row */
SCIPnlrowAddQuadElement(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_QUADELEM elem)2614 SCIP_RETCODE SCIPnlrowAddQuadElement(
2615 SCIP_NLROW* nlrow, /**< NLP nonlinear row */
2616 BMS_BLKMEM* blkmem, /**< block memory */
2617 SCIP_SET* set, /**< global SCIP settings */
2618 SCIP_STAT* stat, /**< problem statistics data */
2619 SCIP_NLP* nlp, /**< current NLP data */
2620 SCIP_QUADELEM elem /**< quadratic element to add */
2621 )
2622 {
2623 SCIP_CALL( nlrowAddQuadElement(nlrow, blkmem, set, stat, nlp, elem) );
2624
2625 return SCIP_OKAY;
2626 }
2627
2628 /** deletes quadratic element from nonlinear row */
SCIPnlrowDelQuadElement(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int idx1,int idx2)2629 SCIP_RETCODE SCIPnlrowDelQuadElement(
2630 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */
2631 SCIP_SET* set, /**< global SCIP settings */
2632 SCIP_STAT* stat, /**< problem statistics data */
2633 SCIP_NLP* nlp, /**< current NLP data */
2634 int idx1, /**< index of first variable in element */
2635 int idx2 /**< index of second variable in element */
2636 )
2637 {
2638 int pos;
2639
2640 assert(nlrow != NULL);
2641 assert(idx1 >= 0);
2642 assert(idx1 < nlrow->nquadvars);
2643 assert(idx2 >= 0);
2644 assert(idx2 < nlrow->nquadvars);
2645 assert(idx1 <= idx2);
2646
2647 /* search the position of the variable in the row's variable vector */
2648 pos = nlrowSearchQuadElem(nlrow, idx1, idx2);
2649 if( pos == -1 )
2650 {
2651 SCIPerrorMessage("coefficient for index pair (%d, %d) doesn't exist in nonlinear row <%s>\n", idx1, idx2, nlrow->name);
2652 return SCIP_INVALIDDATA;
2653 }
2654 assert(0 <= pos && pos < nlrow->nquadelems);
2655
2656 /* delete the element from the row's quadratic elements array */
2657 SCIP_CALL( nlrowDelQuadElemPos(nlrow, set, stat, nlp, pos) );
2658
2659 return SCIP_OKAY;
2660 }
2661
2662 /** changes or adds a quadratic element to a nonlinear row */
SCIPnlrowChgQuadElem(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_QUADELEM elem)2663 SCIP_RETCODE SCIPnlrowChgQuadElem(
2664 SCIP_NLROW* nlrow, /**< nonlinear row */
2665 BMS_BLKMEM* blkmem, /**< block memory */
2666 SCIP_SET* set, /**< global SCIP settings */
2667 SCIP_STAT* stat, /**< problem statistics data */
2668 SCIP_NLP* nlp, /**< current NLP data */
2669 SCIP_QUADELEM elem /**< new quadratic element */
2670 )
2671 {
2672 int pos;
2673
2674 assert(nlrow != NULL);
2675 assert(nlp != NULL);
2676
2677 /* search the position of the variable in the row's linvars vector */
2678 pos = nlrowSearchQuadElem(nlrow, elem.idx1, elem.idx2);
2679
2680 if( pos == -1 )
2681 {
2682 /* add previously not existing element */
2683 SCIP_CALL( nlrowAddQuadElement(nlrow, blkmem, set, stat, nlp, elem) );
2684 }
2685 else
2686 {
2687 /* change the coefficient in the row */
2688 SCIP_CALL( nlrowChgQuadElemPos(nlrow, set, stat, nlp, pos, elem.coef) );
2689 }
2690
2691 return SCIP_OKAY;
2692 }
2693
2694 /** replaces an expression tree in nonlinear row */
SCIPnlrowChgExprtree(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_EXPRTREE * exprtree)2695 SCIP_RETCODE SCIPnlrowChgExprtree(
2696 SCIP_NLROW* nlrow, /**< nonlinear row */
2697 BMS_BLKMEM* blkmem, /**< block memory */
2698 SCIP_SET* set, /**< global SCIP settings */
2699 SCIP_STAT* stat, /**< problem statistics data */
2700 SCIP_NLP* nlp, /**< current NLP data */
2701 SCIP_EXPRTREE* exprtree /**< new expression tree */
2702 )
2703 {
2704 assert(nlrow != NULL);
2705 assert(blkmem != NULL);
2706
2707 /* free previous expression tree */
2708 if( nlrow->exprtree != NULL )
2709 {
2710 SCIP_CALL( SCIPexprtreeFree(&nlrow->exprtree) );
2711 assert(nlrow->exprtree == NULL);
2712 }
2713
2714 /* adds new expression tree */
2715 if( exprtree != NULL )
2716 {
2717 SCIP_CALL( SCIPexprtreeCopy(blkmem, &nlrow->exprtree, exprtree) );
2718
2719 /* if row is already in NLP, ensure that exprtree has only active variables */
2720 if( nlrow->nlpindex >= 0 )
2721 {
2722 SCIP_Bool dummy;
2723 SCIP_CALL( SCIPexprtreeRemoveFixedVars(nlrow->exprtree, set, &dummy, NULL, NULL) );
2724 } /*lint !e438*/
2725 }
2726
2727 /* notify row about the change */
2728 SCIP_CALL( nlrowExprtreeChanged(nlrow, set, stat, nlp) );
2729
2730 return SCIP_OKAY;
2731 }
2732
2733 /** changes a parameter in an expression of a nonlinear row */
SCIPnlrowChgExprtreeParam(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,int paramidx,SCIP_Real paramval)2734 SCIP_RETCODE SCIPnlrowChgExprtreeParam(
2735 SCIP_NLROW* nlrow, /**< nonlinear row */
2736 BMS_BLKMEM* blkmem, /**< block memory */
2737 SCIP_SET* set, /**< global SCIP settings */
2738 SCIP_STAT* stat, /**< problem statistics data */
2739 SCIP_NLP* nlp, /**< current NLP data */
2740 int paramidx, /**< index of parameter in expression tree's parameter array */
2741 SCIP_Real paramval /**< new value of parameter */
2742 )
2743 {
2744 assert(nlrow != NULL);
2745 assert(blkmem != NULL);
2746 assert(nlrow->exprtree != NULL);
2747
2748 SCIPexprtreeSetParamVal(nlrow->exprtree, paramidx, paramval);
2749
2750 /* notify row about the change */
2751 SCIP_CALL( nlrowExprtreeParamChanged(nlrow, set, stat, paramidx, nlp) );
2752
2753 return SCIP_OKAY;
2754 }
2755
2756 /** changes all parameters in an expression of a nonlinear row */
SCIPnlrowChgExprtreeParams(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_Real * paramvals)2757 SCIP_RETCODE SCIPnlrowChgExprtreeParams(
2758 SCIP_NLROW* nlrow, /**< nonlinear row */
2759 BMS_BLKMEM* blkmem, /**< block memory */
2760 SCIP_SET* set, /**< global SCIP settings */
2761 SCIP_STAT* stat, /**< problem statistics data */
2762 SCIP_NLP* nlp, /**< current NLP data */
2763 SCIP_Real* paramvals /**< new values of parameters */
2764 )
2765 {
2766 assert(nlrow != NULL);
2767 assert(blkmem != NULL);
2768 assert(nlrow->exprtree != NULL);
2769
2770 SCIP_CALL( SCIPexprtreeSetParams(nlrow->exprtree, SCIPexprtreeGetNParams(nlrow->exprtree), paramvals) );
2771
2772 /* notify row about the change */
2773 SCIP_CALL( nlrowExprtreeParamChanged(nlrow, set, stat, -1, nlp) );
2774
2775 return SCIP_OKAY;
2776 }
2777
2778 /** changes constant of nonlinear row */
SCIPnlrowChgConstant(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_Real constant)2779 SCIP_RETCODE SCIPnlrowChgConstant(
2780 SCIP_NLROW* nlrow, /**< nonlinear row */
2781 SCIP_SET* set, /**< global SCIP settings */
2782 SCIP_STAT* stat, /**< problem statistics data */
2783 SCIP_NLP* nlp, /**< current NLP data */
2784 SCIP_Real constant /**< new constant */
2785 )
2786 {
2787 assert(nlrow != NULL);
2788
2789 if( !SCIPsetIsEQ(set, nlrow->constant, constant) )
2790 {
2791 nlrow->constant = constant;
2792 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
2793 }
2794
2795 return SCIP_OKAY;
2796 }
2797
2798 /** changes left hand side of nonlinear row */
SCIPnlrowChgLhs(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_Real lhs)2799 SCIP_RETCODE SCIPnlrowChgLhs(
2800 SCIP_NLROW* nlrow, /**< nonlinear row */
2801 SCIP_SET* set, /**< global SCIP settings */
2802 SCIP_STAT* stat, /**< problem statistics data */
2803 SCIP_NLP* nlp, /**< current NLP data */
2804 SCIP_Real lhs /**< new left hand side */
2805 )
2806 {
2807 assert(nlrow != NULL);
2808
2809 if( !SCIPsetIsEQ(set, nlrow->lhs, lhs) )
2810 {
2811 nlrow->lhs = lhs;
2812 SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) );
2813 }
2814
2815 return SCIP_OKAY;
2816 }
2817
2818 /** changes right hand side of nonlinear row */
SCIPnlrowChgRhs(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_Real rhs)2819 SCIP_RETCODE SCIPnlrowChgRhs(
2820 SCIP_NLROW* nlrow, /**< nonlinear row */
2821 SCIP_SET* set, /**< global SCIP settings */
2822 SCIP_STAT* stat, /**< problem statistics data */
2823 SCIP_NLP* nlp, /**< current NLP data */
2824 SCIP_Real rhs /**< new right hand side */
2825 )
2826 {
2827 assert(nlrow != NULL);
2828
2829 if( !SCIPsetIsEQ(set, nlrow->rhs, rhs) )
2830 {
2831 nlrow->rhs = rhs;
2832 SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) );
2833 }
2834
2835 return SCIP_OKAY;
2836 }
2837
2838 /** removes (or substitutes) all fixed, negated, aggregated, multi-aggregated variables from the linear, quadratic, and non-quadratic terms of a nonlinear row */
SCIPnlrowRemoveFixedVars(SCIP_NLROW * nlrow,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)2839 SCIP_RETCODE SCIPnlrowRemoveFixedVars(
2840 SCIP_NLROW* nlrow, /**< nonlinear row */
2841 BMS_BLKMEM* blkmem, /**< block memory */
2842 SCIP_SET* set, /**< global SCIP settings */
2843 SCIP_STAT* stat, /**< problem statistics data */
2844 SCIP_NLP* nlp /**< current NLP data */
2845 )
2846 {
2847 SCIP_CALL( nlrowRemoveFixedLinearCoefs(nlrow, blkmem, set, stat, nlp) );
2848 SCIP_CALL( nlrowRemoveFixedQuadVars(nlrow, blkmem, set, stat, nlp) );
2849 SCIP_CALL( nlrowRemoveFixedExprtreeVars(nlrow, set, stat, nlp) );
2850
2851 return SCIP_OKAY;
2852 }
2853
2854 /** recalculates the current activity of a nonlinear row */
SCIPnlrowRecalcNLPActivity(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp)2855 SCIP_RETCODE SCIPnlrowRecalcNLPActivity(
2856 SCIP_NLROW* nlrow, /**< nonlinear row */
2857 SCIP_SET* set, /**< global SCIP settings */
2858 SCIP_STAT* stat, /**< problem statistics */
2859 SCIP_NLP* nlp /**< current NLP data */
2860 )
2861 {
2862 SCIP_Real val1, val2;
2863 int i;
2864 int previdx1;
2865
2866 assert(nlrow != NULL);
2867 assert(stat != NULL);
2868 assert(nlp != NULL);
2869
2870 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
2871 {
2872 SCIPerrorMessage("do not have NLP solution for computing NLP activity\n");
2873 return SCIP_ERROR;
2874 }
2875
2876 nlrow->activity = nlrow->constant;
2877 for( i = 0; i < nlrow->nlinvars; ++i )
2878 {
2879 assert(nlrow->linvars[i] != NULL);
2880 assert(SCIPvarGetNLPSol(nlrow->linvars[i]) < SCIP_INVALID);
2881
2882 nlrow->activity += nlrow->lincoefs[i] * SCIPvarGetNLPSol(nlrow->linvars[i]);
2883 }
2884
2885 val1 = 0.0; /* for lint */
2886 previdx1 = -1;
2887 for( i = 0; i < nlrow->nquadelems; ++i )
2888 {
2889 /* if first index of quadelems is the same as in last round, val1 is still up to date */
2890 if( previdx1 != nlrow->quadelems[i].idx1 )
2891 {
2892 previdx1 = nlrow->quadelems[i].idx1;
2893 val1 = SCIPvarGetNLPSol(nlrow->quadvars[previdx1]);
2894 assert(val1 < SCIP_INVALID);
2895
2896 if( val1 == 0.0 )
2897 continue;
2898 }
2899
2900 val2 = SCIPvarGetNLPSol(nlrow->quadvars[nlrow->quadelems[i].idx2]);
2901 assert(val2 < SCIP_INVALID);
2902
2903 nlrow->activity += nlrow->quadelems[i].coef * val1 * val2;
2904 }
2905
2906 if( nlrow->exprtree != NULL )
2907 {
2908 SCIP_Real* varvals;
2909 int n;
2910
2911 n = SCIPexprtreeGetNVars(nlrow->exprtree);
2912
2913 SCIP_CALL( SCIPsetAllocBufferArray(set, &varvals, n) );
2914
2915 for( i = 0; i < n; ++i )
2916 {
2917 varvals[i] = SCIPvarGetNLPSol(SCIPexprtreeGetVars(nlrow->exprtree)[i]);
2918 }
2919
2920 SCIP_CALL( SCIPexprtreeEval(nlrow->exprtree, varvals, &val1) );
2921 nlrow->activity += val1;
2922
2923 SCIPsetFreeBufferArray(set, &varvals);
2924 }
2925
2926 nlrow->validactivitynlp = stat->nnlps;
2927
2928 return SCIP_OKAY;
2929 }
2930
2931 /** returns the activity of a nonlinear row in the current NLP solution */
SCIPnlrowGetNLPActivity(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_Real * activity)2932 SCIP_RETCODE SCIPnlrowGetNLPActivity(
2933 SCIP_NLROW* nlrow, /**< nonlinear row */
2934 SCIP_SET* set, /**< global SCIP settings */
2935 SCIP_STAT* stat, /**< problem statistics */
2936 SCIP_NLP* nlp, /**< current NLP data */
2937 SCIP_Real* activity /**< buffer to store activity value */
2938 )
2939 {
2940 assert(nlrow != NULL);
2941 assert(stat != NULL);
2942 assert(activity != NULL);
2943
2944 assert(nlrow->validactivitynlp <= stat->nnlps);
2945
2946 if( nlrow->validactivitynlp != stat->nnlps )
2947 {
2948 SCIP_CALL( SCIPnlrowRecalcNLPActivity(nlrow, set, stat, nlp) );
2949 }
2950 assert(nlrow->validactivitynlp == stat->nnlps);
2951 assert(nlrow->activity < SCIP_INVALID);
2952
2953 *activity = nlrow->activity;
2954
2955 return SCIP_OKAY;
2956 }
2957
2958 /** gives the feasibility of a nonlinear row in the current NLP solution: negative value means infeasibility */
SCIPnlrowGetNLPFeasibility(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLP * nlp,SCIP_Real * feasibility)2959 SCIP_RETCODE SCIPnlrowGetNLPFeasibility(
2960 SCIP_NLROW* nlrow, /**< nonlinear row */
2961 SCIP_SET* set, /**< global SCIP settings */
2962 SCIP_STAT* stat, /**< problem statistics */
2963 SCIP_NLP* nlp, /**< current NLP data */
2964 SCIP_Real* feasibility /**< buffer to store feasibility value */
2965 )
2966 {
2967 SCIP_Real activity;
2968
2969 assert(nlrow != NULL);
2970 assert(feasibility != NULL);
2971
2972 SCIP_CALL( SCIPnlrowGetNLPActivity(nlrow, set, stat, nlp, &activity) );
2973 *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs);
2974
2975 return SCIP_OKAY;
2976 }
2977
2978 /** calculates the current pseudo activity of a nonlinear row */
SCIPnlrowRecalcPseudoActivity(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat)2979 SCIP_RETCODE SCIPnlrowRecalcPseudoActivity(
2980 SCIP_NLROW* nlrow, /**< nonlinear row */
2981 SCIP_SET* set, /**< global SCIP settings */
2982 SCIP_STAT* stat /**< problem statistics */
2983 )
2984 {
2985 SCIP_Real val1, val2;
2986 int i;
2987
2988 assert(nlrow != NULL);
2989 assert(stat != NULL);
2990
2991 nlrow->pseudoactivity = nlrow->constant;
2992 for( i = 0; i < nlrow->nlinvars; ++i )
2993 {
2994 assert(nlrow->linvars[i] != NULL);
2995
2996 val1 = SCIPvarGetBestBoundLocal(nlrow->linvars[i]);
2997 nlrow->pseudoactivity += nlrow->lincoefs[i] * val1;
2998 }
2999
3000 for( i = 0; i < nlrow->nquadelems; ++i )
3001 {
3002 val1 = SCIPvarGetBestBoundLocal(nlrow->quadvars[nlrow->quadelems[i].idx1]);
3003 if( val1 == 0.0 )
3004 continue;
3005
3006 val2 = SCIPvarGetBestBoundLocal(nlrow->quadvars[nlrow->quadelems[i].idx2]);
3007 nlrow->pseudoactivity += nlrow->quadelems[i].coef * val1 * val2;
3008 }
3009
3010 if( nlrow->exprtree != NULL )
3011 {
3012 SCIP_Real* varvals;
3013 int n;
3014
3015 n = SCIPexprtreeGetNVars(nlrow->exprtree);
3016
3017 SCIP_CALL( SCIPsetAllocBufferArray(set, &varvals, n) );
3018
3019 for( i = 0; i < n; ++i )
3020 varvals[i] = SCIPvarGetBestBoundLocal(SCIPexprtreeGetVars(nlrow->exprtree)[i]);
3021
3022 SCIP_CALL( SCIPexprtreeEval(nlrow->exprtree, varvals, &val1) );
3023 nlrow->pseudoactivity += val1;
3024
3025 SCIPsetFreeBufferArray(set, &varvals);
3026 }
3027
3028 nlrow->validpsactivitydomchg = stat->domchgcount;
3029
3030 return SCIP_OKAY;
3031 }
3032
3033 /** returns the pseudo activity of a nonlinear row in the current pseudo solution */
SCIPnlrowGetPseudoActivity(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * pseudoactivity)3034 SCIP_RETCODE SCIPnlrowGetPseudoActivity(
3035 SCIP_NLROW* nlrow, /**< nonlinear row */
3036 SCIP_SET* set, /**< global SCIP settings */
3037 SCIP_STAT* stat, /**< problem statistics */
3038 SCIP_Real* pseudoactivity /**< buffer to store pseudo activity value */
3039 )
3040 {
3041 assert(nlrow != NULL);
3042 assert(stat != NULL);
3043 assert(pseudoactivity != NULL);
3044 assert(nlrow->validpsactivitydomchg <= stat->domchgcount);
3045
3046 /* check, if pseudo activity has to be calculated */
3047 if( nlrow->validpsactivitydomchg != stat->domchgcount )
3048 {
3049 SCIP_CALL( SCIPnlrowRecalcPseudoActivity(nlrow, set, stat) );
3050 }
3051 assert(nlrow->validpsactivitydomchg == stat->domchgcount);
3052 assert(nlrow->pseudoactivity < SCIP_INVALID);
3053
3054 *pseudoactivity = nlrow->pseudoactivity;
3055
3056 return SCIP_OKAY;
3057 }
3058
3059 /** returns the pseudo feasibility of a nonlinear row in the current pseudo solution: negative value means infeasibility */
SCIPnlrowGetPseudoFeasibility(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * pseudofeasibility)3060 SCIP_RETCODE SCIPnlrowGetPseudoFeasibility(
3061 SCIP_NLROW* nlrow, /**< nonlinear row */
3062 SCIP_SET* set, /**< global SCIP settings */
3063 SCIP_STAT* stat, /**< problem statistics */
3064 SCIP_Real* pseudofeasibility /**< buffer to store pseudo feasibility value */
3065 )
3066 {
3067 SCIP_Real pseudoactivity;
3068
3069 assert(nlrow != NULL);
3070 assert(stat != NULL);
3071 assert(pseudofeasibility != NULL);
3072
3073 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlrow, set, stat, &pseudoactivity) );
3074 *pseudofeasibility = MIN(nlrow->rhs - pseudoactivity, pseudoactivity - nlrow->lhs);
3075
3076 return SCIP_OKAY;
3077 }
3078
3079 /** returns the activity of a nonlinear row for a given solution */
SCIPnlrowGetSolActivity(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol,SCIP_Real * activity)3080 SCIP_RETCODE SCIPnlrowGetSolActivity(
3081 SCIP_NLROW* nlrow, /**< nonlinear row */
3082 SCIP_SET* set, /**< global SCIP settings */
3083 SCIP_STAT* stat, /**< problem statistics data */
3084 SCIP_SOL* sol, /**< primal CIP solution */
3085 SCIP_Real* activity /**< buffer to store activity value */
3086 )
3087 {
3088 SCIP_Real inf;
3089 SCIP_Real val1, val2;
3090 int i;
3091
3092 assert(nlrow != NULL);
3093 assert(set != NULL);
3094 assert(stat != NULL);
3095 assert(activity != NULL);
3096
3097 *activity = nlrow->constant;
3098 for( i = 0; i < nlrow->nlinvars; ++i )
3099 {
3100 assert(nlrow->linvars[i] != NULL);
3101
3102 val1 = SCIPsolGetVal(sol, set, stat, nlrow->linvars[i]);
3103 if( val1 == SCIP_UNKNOWN ) /*lint !e777*/
3104 {
3105 *activity = SCIP_INVALID;
3106 return SCIP_OKAY;
3107 }
3108 *activity += nlrow->lincoefs[i] * val1;
3109 }
3110
3111 for( i = 0; i < nlrow->nquadelems; ++i )
3112 {
3113 val1 = SCIPsolGetVal(sol, set, stat, nlrow->quadvars[nlrow->quadelems[i].idx1]);
3114 if( val1 == SCIP_UNKNOWN ) /*lint !e777*/
3115 {
3116 *activity = SCIP_INVALID;
3117 return SCIP_OKAY;
3118 }
3119 if( val1 == 0.0 )
3120 continue;
3121
3122 val2 = SCIPsolGetVal(sol, set, stat, nlrow->quadvars[nlrow->quadelems[i].idx2]);
3123 if( val2 == SCIP_UNKNOWN ) /*lint !e777*/
3124 {
3125 *activity = SCIP_INVALID;
3126 return SCIP_OKAY;
3127 }
3128 *activity += nlrow->quadelems[i].coef * val1 * val2;
3129 }
3130
3131 if( nlrow->exprtree != NULL )
3132 {
3133 SCIP_Real* varvals;
3134 int n;
3135
3136 n = SCIPexprtreeGetNVars(nlrow->exprtree);
3137
3138 SCIP_CALL( SCIPsetAllocBufferArray(set, &varvals, n) );
3139
3140 for( i = 0; i < n; ++i )
3141 {
3142 varvals[i] = SCIPsolGetVal(sol, set, stat, SCIPexprtreeGetVars(nlrow->exprtree)[i]);
3143 if( varvals[i] == SCIP_UNKNOWN ) /*lint !e777*/
3144 {
3145 *activity = SCIP_INVALID;
3146 SCIPsetFreeBufferArray(set, &varvals);
3147 return SCIP_OKAY;
3148 }
3149 }
3150
3151 SCIP_CALL( SCIPexprtreeEval(nlrow->exprtree, varvals, &val1) );
3152 *activity += val1;
3153
3154 SCIPsetFreeBufferArray(set, &varvals);
3155 }
3156
3157 inf = SCIPsetInfinity(set);
3158 *activity = MAX(*activity, -inf);
3159 *activity = MIN(*activity, +inf);
3160
3161 return SCIP_OKAY;
3162 }
3163
3164 /** returns the feasibility of a nonlinear row for the given solution */
SCIPnlrowGetSolFeasibility(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol,SCIP_Real * feasibility)3165 SCIP_RETCODE SCIPnlrowGetSolFeasibility(
3166 SCIP_NLROW* nlrow, /**< nonlinear row */
3167 SCIP_SET* set, /**< global SCIP settings */
3168 SCIP_STAT* stat, /**< problem statistics data */
3169 SCIP_SOL* sol, /**< primal CIP solution */
3170 SCIP_Real* feasibility /**< buffer to store feasibility value */
3171 )
3172 {
3173 SCIP_Real activity;
3174
3175 assert(nlrow != NULL);
3176 assert(feasibility != NULL);
3177
3178 SCIP_CALL( SCIPnlrowGetSolActivity(nlrow, set, stat, sol, &activity) );
3179
3180 *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs);
3181
3182 return SCIP_OKAY;
3183 }
3184
3185 /** returns the minimal activity of a nonlinear row w.r.t. the variables' bounds */
SCIPnlrowGetActivityBounds(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * minactivity,SCIP_Real * maxactivity)3186 SCIP_RETCODE SCIPnlrowGetActivityBounds(
3187 SCIP_NLROW* nlrow, /**< nonlinear row */
3188 SCIP_SET* set, /**< global SCIP settings */
3189 SCIP_STAT* stat, /**< problem statistics data */
3190 SCIP_Real* minactivity, /**< buffer to store minimal activity, or NULL */
3191 SCIP_Real* maxactivity /**< buffer to store maximal activity, or NULL */
3192 )
3193 {
3194 assert(nlrow != NULL);
3195 assert(set != NULL);
3196 assert(stat != NULL);
3197 assert(nlrow->validactivitybdsdomchg <= stat->domchgcount);
3198
3199 /* check, if activity bounds has to be calculated */
3200 if( nlrow->validactivitybdsdomchg != stat->domchgcount )
3201 {
3202 SCIP_CALL( nlrowCalcActivityBounds(nlrow, set, stat) );
3203 }
3204 assert(nlrow->validactivitybdsdomchg == stat->domchgcount);
3205 assert(nlrow->minactivity < SCIP_INVALID);
3206 assert(nlrow->maxactivity < SCIP_INVALID);
3207
3208 if( minactivity != NULL )
3209 *minactivity = nlrow->minactivity;
3210 if( maxactivity != NULL )
3211 *maxactivity = nlrow->maxactivity;
3212
3213 return SCIP_OKAY;
3214 }
3215
3216 /** returns whether the nonlinear row is redundant w.r.t. the variables' bounds */
SCIPnlrowIsRedundant(SCIP_NLROW * nlrow,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool * isredundant)3217 SCIP_RETCODE SCIPnlrowIsRedundant(
3218 SCIP_NLROW* nlrow, /**< nonlinear row */
3219 SCIP_SET* set, /**< global SCIP settings */
3220 SCIP_STAT* stat, /**< problem statistics data */
3221 SCIP_Bool* isredundant /**< buffer to store whether row is redundant */
3222 )
3223 {
3224 SCIP_Real minactivity;
3225 SCIP_Real maxactivity;
3226
3227 assert(nlrow != NULL);
3228 assert(set != NULL);
3229 assert(isredundant != NULL);
3230
3231 SCIP_CALL( SCIPnlrowGetActivityBounds(nlrow, set, stat, &minactivity, &maxactivity) );
3232
3233 *isredundant = TRUE;
3234 if( (!SCIPsetIsInfinity(set, -nlrow->lhs) && SCIPsetIsFeasLT(set, minactivity, nlrow->lhs)) ||
3235 ( !SCIPsetIsInfinity(set, nlrow->rhs) && SCIPsetIsFeasGT(set, maxactivity, nlrow->rhs)) )
3236 *isredundant = FALSE;
3237
3238 return SCIP_OKAY;
3239 }
3240
3241 /** gets constant */
SCIPnlrowGetConstant(SCIP_NLROW * nlrow)3242 SCIP_Real SCIPnlrowGetConstant(
3243 SCIP_NLROW* nlrow /**< NLP row */
3244 )
3245 {
3246 assert(nlrow != NULL);
3247
3248 return nlrow->constant;
3249 }
3250
3251 /** gets number of variables of linear part */
SCIPnlrowGetNLinearVars(SCIP_NLROW * nlrow)3252 int SCIPnlrowGetNLinearVars(
3253 SCIP_NLROW* nlrow /**< NLP row */
3254 )
3255 {
3256 assert(nlrow != NULL);
3257
3258 return nlrow->nlinvars;
3259 }
3260
3261 /** gets array with variables of linear part */
SCIPnlrowGetLinearVars(SCIP_NLROW * nlrow)3262 SCIP_VAR** SCIPnlrowGetLinearVars(
3263 SCIP_NLROW* nlrow /**< NLP row */
3264 )
3265 {
3266 assert(nlrow != NULL);
3267
3268 return nlrow->linvars;
3269 }
3270
3271 /** gets array with coefficients in linear part */
SCIPnlrowGetLinearCoefs(SCIP_NLROW * nlrow)3272 SCIP_Real* SCIPnlrowGetLinearCoefs(
3273 SCIP_NLROW* nlrow /**< NLP row */
3274 )
3275 {
3276 assert(nlrow != NULL);
3277
3278 return nlrow->lincoefs;
3279 }
3280
3281 /** gets number of quadratic variables in quadratic part */
SCIPnlrowGetNQuadVars(SCIP_NLROW * nlrow)3282 int SCIPnlrowGetNQuadVars(
3283 SCIP_NLROW* nlrow /**< NLP row */
3284 )
3285 {
3286 assert(nlrow != NULL);
3287
3288 return nlrow->nquadvars;
3289 }
3290
3291 /** gets quadratic variables in quadratic part */
SCIPnlrowGetQuadVars(SCIP_NLROW * nlrow)3292 SCIP_VAR** SCIPnlrowGetQuadVars(
3293 SCIP_NLROW* nlrow /**< NLP row */
3294 )
3295 {
3296 assert(nlrow != NULL);
3297
3298 return nlrow->quadvars;
3299 }
3300
3301 /** gives position of variable in quadvars array of row, or -1 if not found */
SCIPnlrowSearchQuadVar(SCIP_NLROW * nlrow,SCIP_VAR * var)3302 int SCIPnlrowSearchQuadVar(
3303 SCIP_NLROW* nlrow, /**< nonlinear row */
3304 SCIP_VAR* var /**< variable to search for */
3305 )
3306 {
3307 int pos;
3308
3309 assert(nlrow != NULL);
3310 assert(var != NULL);
3311
3312 if( nlrow->quadvarshash != NULL )
3313 {
3314 pos = SCIPhashmapExists(nlrow->quadvarshash, var) ? SCIPhashmapGetImageInt(nlrow->quadvarshash, var) : -1;
3315 }
3316 else
3317 {
3318 for( pos = nlrow->nquadvars-1; pos >= 0; --pos )
3319 if( nlrow->quadvars[pos] == var )
3320 break;
3321 }
3322
3323 assert(pos == -1 || (pos < nlrow->nquadvars && nlrow->quadvars[pos] == var));
3324
3325 return pos;
3326 }
3327
3328 /** gets number of quadratic elements in quadratic part */
SCIPnlrowGetNQuadElems(SCIP_NLROW * nlrow)3329 int SCIPnlrowGetNQuadElems(
3330 SCIP_NLROW* nlrow /**< NLP row */
3331 )
3332 {
3333 assert(nlrow != NULL);
3334
3335 return nlrow->nquadelems;
3336 }
3337
3338 /** gets quadratic elements in quadratic part */
SCIPnlrowGetQuadElems(SCIP_NLROW * nlrow)3339 SCIP_QUADELEM* SCIPnlrowGetQuadElems(
3340 SCIP_NLROW* nlrow /**< NLP row */
3341 )
3342 {
3343 assert(nlrow != NULL);
3344
3345 return nlrow->quadelems;
3346 }
3347
3348 /** gets array with coefficients in linear part */
SCIPnlrowGetQuadData(SCIP_NLROW * nlrow,int * nquadvars,SCIP_VAR *** quadvars,int * nquadelems,SCIP_QUADELEM ** quadelems)3349 void SCIPnlrowGetQuadData(
3350 SCIP_NLROW* nlrow, /**< NLP row */
3351 int* nquadvars, /**< buffer to store number of variables in quadratic term, or NULL if not of interest */
3352 SCIP_VAR*** quadvars, /**< buffer to store pointer to array of variables in quadratic term, or NULL if not of interest */
3353 int* nquadelems, /**< buffer to store number of entries in quadratic term, or NULL if not of interest */
3354 SCIP_QUADELEM** quadelems /**< buffer to store pointer to array of entries in quadratic term, or NULL if not of interest */
3355 )
3356 {
3357 assert(nlrow != NULL);
3358
3359 if( nquadvars != NULL )
3360 *nquadvars = nlrow->nquadvars;
3361 if( quadvars != NULL )
3362 *quadvars = nlrow->quadvars;
3363 if( nquadelems != NULL )
3364 *nquadelems = nlrow->nquadelems;
3365 if( quadelems != NULL )
3366 *quadelems = nlrow->quadelems;
3367 }
3368
3369 /** gets expression tree */
SCIPnlrowGetExprtree(SCIP_NLROW * nlrow)3370 SCIP_EXPRTREE* SCIPnlrowGetExprtree(
3371 SCIP_NLROW* nlrow /**< NLP row */
3372 )
3373 {
3374 assert(nlrow != NULL);
3375
3376 return nlrow->exprtree;
3377 }
3378
3379 /** returns the left hand side of a nonlinear row */
SCIPnlrowGetLhs(SCIP_NLROW * nlrow)3380 SCIP_Real SCIPnlrowGetLhs(
3381 SCIP_NLROW* nlrow /**< NLP row */
3382 )
3383 {
3384 assert(nlrow != NULL);
3385
3386 return nlrow->lhs;
3387 }
3388
3389 /** returns the right hand side of a nonlinear row */
SCIPnlrowGetRhs(SCIP_NLROW * nlrow)3390 SCIP_Real SCIPnlrowGetRhs(
3391 SCIP_NLROW* nlrow /**< NLP row */
3392 )
3393 {
3394 assert(nlrow != NULL);
3395
3396 return nlrow->rhs;
3397 }
3398
3399 /** returns the curvature of a nonlinear row */
SCIPnlrowGetCurvature(SCIP_NLROW * nlrow)3400 SCIP_EXPRCURV SCIPnlrowGetCurvature(
3401 SCIP_NLROW* nlrow /**< NLP row */
3402 )
3403 {
3404 assert(nlrow != NULL);
3405 return nlrow->curvature;
3406 }
3407
3408 /** sets the curvature of a nonlinear row */
SCIPnlrowSetCurvature(SCIP_NLROW * nlrow,SCIP_EXPRCURV curvature)3409 void SCIPnlrowSetCurvature(
3410 SCIP_NLROW* nlrow, /**< NLP row */
3411 SCIP_EXPRCURV curvature /**< curvature of NLP row */
3412 )
3413 {
3414 assert(nlrow != NULL);
3415 nlrow->curvature = curvature;
3416 }
3417
3418 /** returns the name of a nonlinear row */
SCIPnlrowGetName(SCIP_NLROW * nlrow)3419 const char* SCIPnlrowGetName(
3420 SCIP_NLROW* nlrow /**< NLP row */
3421 )
3422 {
3423 assert(nlrow != NULL);
3424
3425 return nlrow->name;
3426 }
3427
3428 /** gets position of a nonlinear row in current NLP, or -1 if not in NLP */
SCIPnlrowGetNLPPos(SCIP_NLROW * nlrow)3429 int SCIPnlrowGetNLPPos(
3430 SCIP_NLROW* nlrow /**< NLP row */
3431 )
3432 {
3433 assert(nlrow != NULL);
3434
3435 return nlrow->nlpindex;
3436 }
3437
3438 /** returns TRUE iff row is member of current NLP */
SCIPnlrowIsInNLP(SCIP_NLROW * nlrow)3439 SCIP_Bool SCIPnlrowIsInNLP(
3440 SCIP_NLROW* nlrow /**< NLP row */
3441 )
3442 {
3443 assert(nlrow != NULL);
3444
3445 return nlrow->nlpindex != -1;
3446 }
3447
3448 /** gets the dual NLP solution of a nlrow
3449 * for a ranged constraint, the dual value is positive if the right hand side is active and negative if the left hand side is active
3450 */
SCIPnlrowGetDualsol(SCIP_NLROW * nlrow)3451 SCIP_Real SCIPnlrowGetDualsol(
3452 SCIP_NLROW* nlrow /**< NLP row */
3453 )
3454 {
3455 assert(nlrow != NULL);
3456
3457 return nlrow->nlpiindex >= 0 ? nlrow->dualsol : 0.0;
3458 }
3459
3460 /*
3461 * private NLP methods
3462 */
3463
3464 /** announces, that a row of the NLP was modified
3465 * adjusts status of current solution
3466 * calling method has to ensure that change is passed to the NLPI!
3467 */
3468 static
nlpRowChanged(SCIP_NLP * nlp,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLROW * nlrow)3469 SCIP_RETCODE nlpRowChanged(
3470 SCIP_NLP* nlp, /**< current NLP data */
3471 SCIP_SET* set, /**< global SCIP settings */
3472 SCIP_STAT* stat, /**< problem statistics data */
3473 SCIP_NLROW* nlrow /**< nonlinear row which was changed */
3474 )
3475 {
3476 assert(nlp != NULL);
3477 assert(nlrow != NULL);
3478 assert(!nlp->indiving);
3479 assert(nlrow->nlpindex >= 0);
3480
3481 /* nlrow is a row in the NLP, so changes effect feasibility */
3482 /* if we have a feasible NLP solution and it satisfies the modified row, then it is still feasible
3483 * if the NLP was globally or locally infeasible or unbounded, then this may not be the case anymore
3484 */
3485 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
3486 {
3487 SCIP_Real feasibility;
3488 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, set, stat, nlp, &feasibility) );
3489 if( !SCIPsetIsFeasNegative(set, feasibility) )
3490 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
3491 else
3492 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
3493 }
3494 else
3495 {
3496 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3497 }
3498
3499 return SCIP_OKAY;
3500 }
3501
3502 /** adds a set of nonlinear rows to the NLP and captures them */
3503 static
nlpAddNlRows(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,int nnlrows,SCIP_NLROW ** nlrows)3504 SCIP_RETCODE nlpAddNlRows(
3505 SCIP_NLP* nlp, /**< NLP data */
3506 BMS_BLKMEM* blkmem, /**< block memory */
3507 SCIP_SET* set, /**< global SCIP settings */
3508 SCIP_STAT* stat, /**< problem statistics data */
3509 int nnlrows, /**< number of nonlinear rows to add */
3510 SCIP_NLROW** nlrows /**< nonlinear rows to add */
3511 )
3512 {
3513 #ifndef NDEBUG
3514 int i;
3515 #endif
3516 int j;
3517 SCIP_NLROW* nlrow;
3518
3519 assert(nlp != NULL);
3520 assert(blkmem != NULL);
3521 assert(set != NULL);
3522 assert(nlrows != NULL || nnlrows == 0);
3523 assert(!nlp->indiving);
3524
3525 SCIP_CALL( SCIPnlpEnsureNlRowsSize(nlp, blkmem, set, nlp->nnlrows + nnlrows) );
3526
3527 for( j = 0; j < nnlrows; ++j )
3528 {
3529 nlrow = nlrows[j]; /*lint !e613*/
3530
3531 /* assert that row is not in NLP (or even NLPI) yet */
3532 assert(nlrow->nlpindex == -1);
3533 assert(nlrow->nlpiindex == -1);
3534
3535 /* make sure there are only active variables in row */
3536 SCIP_CALL( SCIPnlrowRemoveFixedVars(nlrow, blkmem, set, stat, nlp) );
3537
3538 #ifndef NDEBUG
3539 /* assert that variables of row are in NLP */
3540 for( i = 0; i < nlrow->nlinvars; ++i )
3541 assert(SCIPhashmapExists(nlp->varhash, nlrow->linvars[i]));
3542
3543 for( i = 0; i < nlrow->nquadvars; ++i )
3544 assert(SCIPhashmapExists(nlp->varhash, nlrow->quadvars[i]));
3545
3546 if( nlrow->exprtree )
3547 {
3548 int n;
3549
3550 n = SCIPexprtreeGetNVars(nlrow->exprtree);
3551 assert(SCIPexprtreeGetVars(nlrow->exprtree) != NULL || n == 0);
3552
3553 for( i = 0; i < n; ++i )
3554 assert(SCIPhashmapExists(nlp->varhash, SCIPexprtreeGetVars(nlrow->exprtree)[i]));
3555 }
3556 #endif
3557
3558 /* add row to NLP and capture it */
3559 nlp->nlrows[nlp->nnlrows + j] = nlrow;
3560 nlrow->nlpindex = nlp->nnlrows + j;
3561
3562 SCIPnlrowCapture(nlrow);
3563
3564 /* if we have a feasible NLP solution and it satisfies the new solution, then it is still feasible
3565 * if the NLP was globally or locally infeasible, then it stays that way
3566 * if the NLP was unbounded, then this may not be the case anymore
3567 */
3568 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
3569 {
3570 SCIP_Real feasibility;
3571 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, set, stat, nlp, &feasibility) );
3572 if( !SCIPsetIsFeasNegative(set, feasibility) )
3573 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
3574 else
3575 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
3576 }
3577 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
3578 {
3579 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3580 }
3581 }
3582
3583 nlp->nnlrows += nnlrows;
3584 nlp->nunflushednlrowadd += nnlrows;
3585
3586 return SCIP_OKAY;
3587 }
3588
3589 /** moves a nonlinear row to a different place, and updates all corresponding data structures */
3590 static
nlpMoveNlrow(SCIP_NLP * nlp,int oldpos,int newpos)3591 void nlpMoveNlrow(
3592 SCIP_NLP* nlp, /**< NLP data structure */
3593 int oldpos, /**< old position of nonlinear row */
3594 int newpos /**< new position of nonlinear row */
3595 )
3596 {
3597 assert(nlp != NULL);
3598 assert(0 <= oldpos && oldpos < nlp->nnlrows);
3599 assert(0 <= newpos && newpos < nlp->nnlrows);
3600 assert(nlp->nlrows[oldpos] != NULL);
3601
3602 if( oldpos == newpos )
3603 return;
3604
3605 nlp->nlrows[newpos] = nlp->nlrows[oldpos];
3606 nlp->nlrows[newpos]->nlpindex = newpos;
3607
3608 /* update nlpi to nlp row index mapping */
3609 if( nlp->nlrows[newpos]->nlpiindex >= 0 )
3610 {
3611 assert(nlp->nlrowmap_nlpi2nlp != NULL);
3612 assert(nlp->nlrows[newpos]->nlpiindex < nlp->sizenlrows_solver);
3613 nlp->nlrowmap_nlpi2nlp[nlp->nlrows[newpos]->nlpiindex] = newpos;
3614 }
3615 }
3616
3617 /** deletes nonlinear row with given position from NLP */
3618 static
nlpDelNlRowPos(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int pos)3619 SCIP_RETCODE nlpDelNlRowPos(
3620 SCIP_NLP* nlp, /**< NLP data structure */
3621 BMS_BLKMEM* blkmem, /**< block memory */
3622 SCIP_SET* set, /**< global SCIP settings */
3623 int pos /**< position of nonlinear row that is to be removed */
3624 )
3625 {
3626 SCIP_NLROW* nlrow;
3627
3628 assert(nlp != NULL);
3629 assert(blkmem != NULL);
3630 assert(set != NULL);
3631 assert(pos >= 0);
3632 assert(pos < nlp->nnlrows);
3633 assert(!nlp->indiving);
3634 assert(nlp->nlrows != NULL);
3635
3636 nlrow = nlp->nlrows[pos];
3637 assert(nlrow != NULL);
3638 assert(nlrow->nlpindex == pos);
3639
3640 /* if row is in NLPI, then mark that it has to be removed in the next flush
3641 * if row was not in NLPI yet, then we have one unflushed nlrow addition less */
3642 if( nlrow->nlpiindex >= 0 )
3643 {
3644 assert(nlrow->nlpiindex < nlp->nnlrows_solver);
3645 nlp->nlrowmap_nlpi2nlp[nlrow->nlpiindex] = -1;
3646 nlrow->nlpiindex = -1;
3647 ++nlp->nunflushednlrowdel;
3648 }
3649 else
3650 {
3651 assert(nlrow->nlpiindex == -1);
3652 --nlp->nunflushednlrowadd;
3653 }
3654
3655 /* move NLP row from the end to pos and mark nlrow to be not in NLP anymore */
3656 nlpMoveNlrow(nlp, nlp->nnlrows-1, pos);
3657 nlrow->nlpindex = -1;
3658
3659 /* forget about restriction */
3660 SCIP_CALL( SCIPnlrowRelease(&nlrow, blkmem, set) );
3661 --nlp->nnlrows;
3662
3663 if( nlp->solstat < SCIP_NLPSOLSTAT_LOCOPT )
3664 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
3665 else if( nlp->solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
3666 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
3667
3668 return SCIP_OKAY; /*lint !e438*/
3669 }
3670
3671 /** updates bounds on a variable in the NLPI problem */
3672 static
nlpUpdateVarBounds(SCIP_NLP * nlp,SCIP_SET * set,SCIP_VAR * var,SCIP_Bool tightened)3673 SCIP_RETCODE nlpUpdateVarBounds(
3674 SCIP_NLP* nlp, /**< NLP data */
3675 SCIP_SET* set, /**< global SCIP settings */
3676 SCIP_VAR* var, /**< variable which bounds have changed */
3677 SCIP_Bool tightened /**< whether the bound change was a bound tightening */
3678 )
3679 {
3680 int pos;
3681 SCIP_Real lb;
3682 SCIP_Real ub;
3683
3684 assert(nlp != NULL);
3685 assert(var != NULL);
3686 assert(SCIPhashmapExists(nlp->varhash, var));
3687
3688 /* original variable bounds are ignored during diving
3689 * (all variable bounds are reset to their current value in exitDiving) */
3690 if( nlp->indiving )
3691 return SCIP_OKAY;
3692
3693 /* get position of variable in NLP */
3694 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
3695
3696 /* if variable not in NLPI yet, nothing to do */
3697 if( nlp->varmap_nlp2nlpi[pos] == -1 )
3698 return SCIP_OKAY;
3699
3700 /* update bounds in NLPI problem */
3701 assert(nlp->solver != NULL);
3702 assert(nlp->problem != NULL);
3703
3704 pos = nlp->varmap_nlp2nlpi[pos];
3705 lb = SCIPvarGetLbLocal(var);
3706 ub = SCIPvarGetUbLocal(var);
3707 SCIP_CALL( SCIPnlpiChgVarBounds(nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
3708
3709 /* if we have a feasible NLP solution and it satisfies the new bounds, then it is still feasible
3710 * if the NLP was globally or locally infeasible and we tightened a bound, then it stays that way
3711 * if the NLP was unbounded and we tightened a bound, then this may not be the case anymore
3712 */
3713 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
3714 {
3715 if( !tightened ||
3716 ((SCIPsetIsInfinity(set, -lb) || SCIPsetIsFeasLE(set, lb, SCIPvarGetNLPSol(var))) &&
3717 (SCIPsetIsInfinity(set, ub) || SCIPsetIsFeasGE(set, ub, SCIPvarGetNLPSol(var)))) )
3718 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
3719 else
3720 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
3721 }
3722 else if( !tightened || nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
3723 {
3724 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3725 }
3726
3727 return SCIP_OKAY;
3728 }
3729
3730 /** updates coefficient of a variable in the objective */
3731 static
nlpUpdateObjCoef(SCIP_NLP * nlp,SCIP_VAR * var)3732 SCIP_RETCODE nlpUpdateObjCoef(
3733 SCIP_NLP* nlp, /**< NLP data */
3734 SCIP_VAR* var /**< variable which bounds have changed */
3735 )
3736 {
3737 int pos;
3738 int objidx;
3739 SCIP_Real coef;
3740
3741 assert(nlp != NULL);
3742 assert(var != NULL);
3743 assert(SCIPhashmapExists(nlp->varhash, var));
3744
3745 /* if the objective in the NLPI is not up to date, then we do not need to do something here */
3746 if( !nlp->objflushed )
3747 return SCIP_OKAY;
3748
3749 /* original objective is ignored during diving
3750 * we just need to remember that at end of diving we have to flush the objective */
3751 if( nlp->indiving )
3752 {
3753 nlp->objflushed = FALSE;
3754 return SCIP_OKAY;
3755 }
3756
3757 /* get position of variable in NLP and objective coefficient */
3758 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
3759 assert(nlp->varmap_nlp2nlpi[pos] == -1 || nlp->solver != NULL);
3760
3761 /* actually we only need to remember flushing the objective if we also have an NLPI */
3762 if( nlp->solver == NULL )
3763 return SCIP_OKAY;
3764
3765 coef = SCIPvarGetObj(var);
3766
3767 /* if variable not in NLPI yet, then we only need to remember to update the objective after variable additions were flushed */
3768 if( nlp->varmap_nlp2nlpi[pos] == -1 && coef != 0.0 )
3769 {
3770 nlp->objflushed = FALSE;
3771
3772 return SCIP_OKAY;
3773 }
3774
3775 /* if we are here, then the objective in the NLPI is up to date,
3776 * we keep it this way by changing the coefficient of var in the NLPI problem objective */
3777 assert(nlp->solver != NULL);
3778 assert(nlp->problem != NULL);
3779
3780 pos = nlp->varmap_nlp2nlpi[pos];
3781 objidx = -1;
3782 SCIP_CALL( SCIPnlpiChgLinearCoefs(nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
3783
3784 /* if we had a solution and it was locally (or globally) optimal, then now we can only be sure that it is still feasible */
3785 if( nlp->solstat < SCIP_NLPSOLSTAT_FEASIBLE )
3786 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
3787
3788 return SCIP_OKAY;
3789 }
3790
3791 /** adds new variables to the NLP */
3792 static
nlpAddVars(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int nvars,SCIP_VAR ** vars)3793 SCIP_RETCODE nlpAddVars(
3794 SCIP_NLP* nlp, /**< NLP data structure */
3795 BMS_BLKMEM* blkmem, /**< block memory */
3796 SCIP_SET* set, /**< global SCIP settings */
3797 int nvars, /**< number of variables to add */
3798 SCIP_VAR** vars /**< variable to add to NLP */
3799 )
3800 {
3801 int i;
3802 SCIP_VAR* var;
3803
3804 assert(nlp != NULL);
3805 assert(blkmem != NULL);
3806 assert(set != NULL);
3807 assert(vars != NULL || nvars == 0);
3808 assert(!nlp->indiving || nvars == 0);
3809
3810 if( nvars == 0 )
3811 return SCIP_OKAY;
3812
3813 SCIP_CALL( SCIPnlpEnsureVarsSize(nlp, blkmem, set, nlp->nvars + nvars) );
3814 assert(nlp->sizevars >= nlp->nvars + nvars);
3815
3816 for( i = 0; i < nvars; ++i )
3817 {
3818 var = vars[i]; /*lint !e613*/
3819
3820 assert(SCIPvarIsTransformed(var));
3821 assert(SCIPvarIsActive(var));
3822 assert(!SCIPhashmapExists(nlp->varhash, var));
3823
3824 SCIPvarCapture(var);
3825
3826 nlp->vars[nlp->nvars+i] = var;
3827 nlp->varmap_nlp2nlpi[nlp->nvars+i] = -1;
3828 SCIP_CALL( SCIPhashmapInsertInt(nlp->varhash, var, nlp->nvars+i) );
3829
3830 nlp->varlbdualvals[nlp->nvars+i] = 0.0;
3831 nlp->varubdualvals[nlp->nvars+i] = 0.0;
3832
3833 /* update objective, if necessary (new variables have coefficient 0.0 anyway) */
3834 if( SCIPvarGetObj(var) != 0.0 )
3835 {
3836 SCIP_CALL( nlpUpdateObjCoef(nlp, var) );
3837 }
3838
3839 /* let's keep the previous initial guess and set it for the new variable to the best bound
3840 * (since there can be no row that uses this variable yet, this seems a good guess) */
3841 if( nlp->haveinitguess )
3842 {
3843 assert(nlp->initialguess != NULL);
3844
3845 nlp->initialguess[nlp->nvars+i] = SCIPvarGetBestBoundLocal(var);
3846 }
3847
3848 /* if we have a feasible NLP solution, then it remains feasible
3849 * but we have to update the objective function
3850 */
3851 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
3852 {
3853 SCIP_CALL( SCIPvarSetNLPSol(var, set, SCIPvarGetBestBoundLocal(var)) );
3854 nlp->primalsolobjval += SCIPvarGetObj(var) * SCIPvarGetBestBoundLocal(var);
3855 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
3856 }
3857
3858 /* catch events on variable */
3859 SCIP_CALL( SCIPvarCatchEvent(var, blkmem, set, \
3860 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
3861 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, NULL) ); /* @todo should store event filter position in nlp? */
3862 }
3863
3864 nlp->nvars += nvars;
3865 nlp->nunflushedvaradd += nvars;
3866
3867 return SCIP_OKAY;
3868 }
3869
3870 /** moves a variable to a different place, and updates all corresponding data structures */
3871 static
nlpMoveVar(SCIP_NLP * nlp,int oldpos,int newpos)3872 SCIP_RETCODE nlpMoveVar(
3873 SCIP_NLP* nlp, /**< NLP data structure */
3874 int oldpos, /**< old position of variable */
3875 int newpos /**< new position of variable */
3876 )
3877 {
3878 int nlpipos;
3879
3880 assert(nlp != NULL);
3881 assert(0 <= oldpos && oldpos < nlp->nvars);
3882 assert(0 <= newpos && newpos < nlp->nvars);
3883 assert(nlp->vars[oldpos] != NULL);
3884
3885 if( oldpos == newpos )
3886 return SCIP_OKAY;
3887
3888 SCIP_CALL( SCIPhashmapSetImageInt(nlp->varhash, nlp->vars[oldpos], newpos) );
3889 nlp->vars[newpos] = nlp->vars[oldpos];
3890 nlp->varmap_nlp2nlpi[newpos] = nlp->varmap_nlp2nlpi[oldpos];
3891 nlp->varlbdualvals[newpos] = nlp->varlbdualvals[oldpos];
3892 nlp->varubdualvals[newpos] = nlp->varubdualvals[oldpos];
3893 if( nlp->initialguess != NULL )
3894 nlp->initialguess[newpos] = nlp->initialguess[oldpos];
3895
3896 nlpipos = nlp->varmap_nlp2nlpi[newpos];
3897 if( nlpipos > 0 )
3898 nlp->varmap_nlpi2nlp[nlpipos] = newpos;
3899
3900 return SCIP_OKAY;
3901 }
3902
3903 /** deletes variable with given position from NLP */
3904 static
nlpDelVarPos(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,int pos)3905 SCIP_RETCODE nlpDelVarPos(
3906 SCIP_NLP* nlp, /**< NLP data structure */
3907 BMS_BLKMEM* blkmem, /**< block memory */
3908 SCIP_SET* set, /**< global SCIP settings */
3909 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3910 SCIP_LP* lp, /**< SCIP LP, needed if a column-variable is freed */
3911 int pos /**< position of nonlinear row that is to be removed */
3912 )
3913 {
3914 SCIP_VAR* var;
3915 #ifndef NDEBUG
3916 int i;
3917 #endif
3918 int nlpipos;
3919
3920 assert(nlp != NULL);
3921 assert(blkmem != NULL);
3922 assert(set != NULL);
3923 assert(pos >= 0);
3924 assert(pos < nlp->nvars);
3925 assert(!nlp->indiving);
3926
3927 var = nlp->vars[pos];
3928 assert(var != NULL);
3929
3930 #ifndef NDEBUG
3931 /* assert that variable is not used by any nonlinear row */
3932 for( i = 0; i < nlp->nnlrows; ++i )
3933 {
3934 int j;
3935 SCIP_NLROW* nlrow;
3936
3937 nlrow = nlp->nlrows[i];
3938 assert(nlrow != NULL);
3939
3940 /* use nlrowSearchLinearCoef only if already sorted, since otherwise we may change the solving process slightly */
3941 if( nlrow->linvarssorted )
3942 assert( nlrowSearchLinearCoef(nlrow, var) == -1 );
3943 else
3944 for( j = 0; j < nlrow->nlinvars; ++j )
3945 assert( nlrow->linvars[j] != var );
3946
3947 assert( SCIPnlrowSearchQuadVar(nlrow, var) == -1);
3948
3949 assert(nlrow->exprtree == NULL || SCIPexprtreeFindVar(nlrow->exprtree, var) == -1);
3950 }
3951 #endif
3952
3953 /* if we had a feasible solution, then adjust objective function value
3954 * if NLP was unbounded before, then maybe it is not anymore */
3955 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
3956 nlp->primalsolobjval -= SCIPvarGetObj(var) * SCIPvarGetNLPSol(var);
3957 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
3958 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3959
3960 /* if variable is in NLPI problem, mark that we have to remember to delete it there
3961 * if it was not in the NLPI yet, then we have one unflushed var addition less now */
3962 nlpipos = nlp->varmap_nlp2nlpi[pos];
3963 if( nlpipos >= 0 )
3964 {
3965 assert(nlpipos < nlp->nvars_solver);
3966
3967 nlp->varmap_nlpi2nlp[nlpipos] = -1;
3968 ++nlp->nunflushedvardel;
3969 }
3970 else
3971 --nlp->nunflushedvaradd;
3972
3973 /* drop events on variable */
3974 SCIP_CALL( SCIPvarDropEvent(var, blkmem, set, \
3975 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
3976 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, -1) );
3977
3978 /* move variable from end to pos */
3979 SCIP_CALL( nlpMoveVar(nlp, nlp->nvars-1, pos) );
3980
3981 /* forget about variable */
3982 SCIP_CALL( SCIPhashmapRemove(nlp->varhash, var) );
3983 SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
3984 --nlp->nvars;
3985
3986 return SCIP_OKAY;
3987 }
3988
3989 /** notifies NLP that a variable was fixed, so it is removed from objective, all rows, and the NLP variables */
3990 static
nlpRemoveFixedVar(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_VAR * var)3991 SCIP_RETCODE nlpRemoveFixedVar(
3992 SCIP_NLP* nlp, /**< NLP data */
3993 BMS_BLKMEM* blkmem, /**< block memory */
3994 SCIP_SET* set, /**< global SCIP settings */
3995 SCIP_STAT* stat, /**< problem statistics data */
3996 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3997 SCIP_LP* lp, /**< SCIP LP, needed to release variable */
3998 SCIP_VAR* var /**< variable that has been fixed */
3999 )
4000 {
4001 int i;
4002
4003 assert(nlp != NULL);
4004 assert(var != NULL);
4005 assert(!SCIPvarIsActive(var));
4006 assert(!nlp->indiving);
4007 assert(SCIPhashmapExists(nlp->varhash, var));
4008
4009 /* remove var from all rows */
4010 for( i = 0; i < nlp->nnlrows; ++i )
4011 {
4012 SCIP_CALL( nlrowRemoveFixedVar(nlp->nlrows[i], blkmem, set, stat, nlp, var) );
4013 }
4014
4015 /* remove variable from NLP */
4016 SCIP_CALL( SCIPnlpDelVar(nlp, blkmem, set, eventqueue, lp, var) );
4017
4018 return SCIP_OKAY;
4019 }
4020
4021 /** creates arrays with NLPI variable indices of variables in a nonlinear row */
4022 static
nlpSetupNlpiIndices(SCIP_NLP * nlp,SCIP_SET * set,SCIP_NLROW * nlrow,int ** linidxs,SCIP_QUADELEM ** quadelems,int ** nlinidxs)4023 SCIP_RETCODE nlpSetupNlpiIndices(
4024 SCIP_NLP* nlp, /**< NLP data */
4025 SCIP_SET* set, /**< global SCIP settings */
4026 SCIP_NLROW* nlrow, /**< nonlinear row */
4027 int** linidxs, /**< buffer to store pointer to NLPI indices of linear variables */
4028 SCIP_QUADELEM** quadelems, /**< buffer to store pointer to quadratic elements w.r.t. NLPI indices */
4029 int** nlinidxs /**< buffer to store pointer to NLPI indices of nonlinear variables */
4030 )
4031 {
4032 int i;
4033 SCIP_VAR* var;
4034
4035 assert(nlp != NULL);
4036 assert(set != NULL);
4037 assert(nlrow != NULL);
4038 assert(linidxs != NULL);
4039 assert(quadelems != NULL);
4040 assert(nlinidxs != NULL);
4041
4042 /* get indices of variables in linear part of row */
4043 if( nlrow->nlinvars > 0 )
4044 {
4045 assert(nlrow->linvars != NULL);
4046 assert(nlrow->lincoefs != NULL);
4047
4048 SCIP_CALL( SCIPsetAllocBufferArray(set, linidxs, nlrow->nlinvars) );
4049
4050 for( i = 0; i < nlrow->nlinvars; ++i )
4051 {
4052 var = nlrow->linvars[i];
4053 assert(var != NULL);
4054 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
4055
4056 assert(SCIPhashmapExists(nlp->varhash, var));
4057 (*linidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
4058 assert((*linidxs)[i] >= 0);
4059 }
4060 }
4061 else
4062 *linidxs = NULL;
4063
4064 /* get indices of variables in quadratic part of row */
4065 if( nlrow->nquadvars > 0 )
4066 {
4067 int* quadvarsidx;
4068
4069 assert(nlrow->quadvars != NULL);
4070 assert(nlrow->nquadelems > 0);
4071 assert(nlrow->quadelems != NULL);
4072
4073 /* allocate memory */
4074 SCIP_CALL( SCIPsetAllocBufferArray(set, quadelems, nlrow->nquadelems) );
4075 SCIP_CALL( SCIPsetAllocBufferArray(set, &quadvarsidx, nlrow->nquadvars) );
4076
4077 /* compute mapping of variable indices quadratic term -> NLPI */
4078 for( i = 0; i < nlrow->nquadvars; ++i )
4079 {
4080 var = nlrow->quadvars[i];
4081 assert(var != NULL);
4082 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
4083
4084 assert(SCIPhashmapExists(nlp->varhash, var));
4085 quadvarsidx[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
4086 }
4087
4088 /* compute quad elements using NLPI indices */
4089 for( i = 0; i < nlrow->nquadelems; ++i )
4090 {
4091 assert(nlrow->quadelems[i].idx1 >= 0);
4092 assert(nlrow->quadelems[i].idx1 < nlrow->nquadvars);
4093 assert(nlrow->quadelems[i].idx2 >= 0);
4094 assert(nlrow->quadelems[i].idx2 < nlrow->nquadvars);
4095
4096 (*quadelems)[i].idx1 = quadvarsidx[nlrow->quadelems[i].idx1];
4097 (*quadelems)[i].idx2 = quadvarsidx[nlrow->quadelems[i].idx2];
4098 if( (*quadelems)[i].idx1 > (*quadelems)[i].idx2 )
4099 {
4100 int tmp = (*quadelems)[i].idx1;
4101 (*quadelems)[i].idx1 = (*quadelems)[i].idx2;
4102 (*quadelems)[i].idx2 = tmp;
4103 }
4104 (*quadelems)[i].coef = nlrow->quadelems[i].coef;
4105 }
4106
4107 SCIPsetFreeBufferArray(set, &quadvarsidx);
4108 }
4109 else
4110 *quadelems = NULL;
4111
4112 /* get indices of variables in expression tree part of row */
4113 if( nlrow->exprtree != NULL )
4114 {
4115 int n;
4116
4117 n = SCIPexprtreeGetNVars(nlrow->exprtree);
4118 assert(n == 0 || SCIPexprtreeGetVars(nlrow->exprtree) != NULL);
4119
4120 SCIP_CALL( SCIPsetAllocBufferArray(set, nlinidxs, n) );
4121
4122 for( i = 0; i < n; ++i )
4123 {
4124 var = SCIPexprtreeGetVars(nlrow->exprtree)[i];
4125 assert(var != NULL);
4126 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
4127
4128 assert(SCIPhashmapExists(nlp->varhash, var));
4129 (*nlinidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
4130 }
4131 }
4132 else
4133 *nlinidxs = NULL;
4134
4135 return SCIP_OKAY;
4136 }
4137
4138 /** ensures, that NLPI variables array of NLP can store at least num entries */
4139 static
nlpEnsureVarsSolverSize(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)4140 SCIP_RETCODE nlpEnsureVarsSolverSize(
4141 SCIP_NLP* nlp, /**< NLP data */
4142 BMS_BLKMEM* blkmem, /**< block memory */
4143 SCIP_SET* set, /**< global SCIP settings */
4144 int num /**< minimum number of entries to store */
4145 )
4146 {
4147 assert(nlp != NULL);
4148 assert(blkmem != NULL);
4149 assert(set != NULL);
4150 assert(nlp->nvars_solver <= nlp->sizevars_solver);
4151
4152 if( num > nlp->sizevars_solver )
4153 {
4154 int newsize;
4155
4156 newsize = SCIPsetCalcMemGrowSize(set, num);
4157 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlpi2nlp, nlp->sizevars_solver, newsize) );
4158
4159 nlp->sizevars_solver = newsize;
4160 }
4161 assert(num <= nlp->sizevars_solver);
4162
4163 return SCIP_OKAY;
4164 }
4165
4166 /** ensures, that NLPI nonlinear rows array of NLP can store at least num entries */
4167 static
nlpEnsureNlRowsSolverSize(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)4168 SCIP_RETCODE nlpEnsureNlRowsSolverSize(
4169 SCIP_NLP* nlp, /**< NLP data */
4170 BMS_BLKMEM* blkmem, /**< block memory */
4171 SCIP_SET* set, /**< global SCIP settings */
4172 int num /**< minimum number of entries to store */
4173 )
4174 {
4175 assert(nlp != NULL);
4176 assert(blkmem != NULL);
4177 assert(set != NULL);
4178 assert(nlp->nnlrows_solver <= nlp->sizenlrows_solver);
4179
4180 if( num > nlp->sizenlrows_solver )
4181 {
4182 int newsize;
4183
4184 newsize = SCIPsetCalcMemGrowSize(set, num);
4185 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrowmap_nlpi2nlp, nlp->sizenlrows_solver, newsize) );
4186
4187 nlp->sizenlrows_solver = newsize;
4188 }
4189 assert(num <= nlp->sizenlrows_solver);
4190
4191 return SCIP_OKAY;
4192 }
4193
4194 /** deletes rows from the NLPI problem that have been marked as to remove */
4195 static
nlpFlushNlRowDeletions(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)4196 SCIP_RETCODE nlpFlushNlRowDeletions(
4197 SCIP_NLP* nlp, /**< NLP data */
4198 BMS_BLKMEM* blkmem, /**< block memory */
4199 SCIP_SET* set /**< global SCIP settings */
4200 )
4201 {
4202 int j;
4203 int c; /* counts the number of rows to delete */
4204 int* rowset; /* marks which rows to delete and stores new indices */
4205 SCIP_NLROW* nlrow;
4206
4207 assert(nlp != NULL);
4208 assert(blkmem != NULL);
4209 assert(set != NULL);
4210 assert(nlp->nunflushednlrowdel >= 0);
4211 assert(!nlp->indiving);
4212
4213 if( nlp->nunflushednlrowdel == 0 )
4214 {
4215 #ifndef NDEBUG
4216 /* check that there are really no pending removals of nonlinear rows */
4217 for( j = 0; j < nlp->nnlrows_solver; ++j )
4218 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
4219 #endif
4220 return SCIP_OKAY;
4221 }
4222
4223 assert(nlp->solver != NULL);
4224 assert(nlp->problem != NULL);
4225
4226 /* create marker which rows have to be deleted */
4227 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowset, nlp->nnlrows_solver) );
4228 c = 0;
4229 for( j = 0; j < nlp->nnlrows_solver; ++j )
4230 {
4231 if( nlp->nlrowmap_nlpi2nlp[j] == -1 )
4232 {
4233 rowset[j] = 1;
4234 ++c;
4235 }
4236 else
4237 rowset[j] = 0;
4238 }
4239 assert(c == nlp->nunflushednlrowdel);
4240
4241 /* remove rows from NLPI problem */
4242 SCIP_CALL( SCIPnlpiDelConsSet(nlp->solver, nlp->problem, rowset, nlp->nnlrows_solver) );
4243
4244 /* update NLPI row indices */
4245 for( j = 0; j < nlp->nnlrows_solver; ++j )
4246 {
4247 assert(rowset[j] <= j); /* we assume that the NLP solver did not move a row behind its previous position!! */
4248 if( rowset[j] < 0 )
4249 {
4250 /* assert that row was marked as deleted */
4251 assert(nlp->nlrowmap_nlpi2nlp[j] == -1);
4252 }
4253 else if( rowset[j] < j )
4254 {
4255 /* nlrow at position j moved (forward) to position rowset[j] */
4256 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
4257 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
4258
4259 nlrow = nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]];
4260 assert(nlrow->nlpiindex == j);
4261
4262 /* there should be no row at the new position already */
4263 assert(nlp->nlrowmap_nlpi2nlp[rowset[j]] == -1);
4264
4265 nlrow->nlpiindex = rowset[j];
4266 nlp->nlrowmap_nlpi2nlp[rowset[j]] = nlrow->nlpindex;
4267 }
4268 else
4269 {
4270 /* row j stays at position j */
4271 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
4272 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
4273 assert(nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]->nlpiindex == j);
4274 }
4275 }
4276 nlp->nnlrows_solver -= c;
4277 nlp->nunflushednlrowdel = 0;
4278
4279 /* cleanup */
4280 SCIPsetFreeBufferArray(set, &rowset);
4281
4282 return SCIP_OKAY;
4283 }
4284
4285 /** deletes variables from the NLPI problem that have been marked as to remove
4286 * assumes that there are no pending row deletions (nlpFlushNlRowDeletions should be called first)
4287 */
4288 static
nlpFlushVarDeletions(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)4289 SCIP_RETCODE nlpFlushVarDeletions(
4290 SCIP_NLP* nlp, /**< NLP data */
4291 BMS_BLKMEM* blkmem, /**< block memory */
4292 SCIP_SET* set /**< global SCIP settings */
4293 )
4294 {
4295 int i;
4296 int c; /* counter on number of variables to remove in solver */
4297 int* colset; /* marks which variables to delete and stores new indices */
4298
4299 assert(nlp != NULL);
4300 assert(blkmem != NULL);
4301 assert(set != NULL);
4302 assert(nlp->nunflushedvardel >= 0);
4303 assert(nlp->nunflushednlrowdel == 0);
4304 assert(!nlp->indiving);
4305
4306 if( nlp->nunflushedvardel == 0 )
4307 {
4308 #ifndef NDEBUG
4309 /* check that there are really no pending removals of variables */
4310 for( i = 0; i < nlp->nvars_solver; ++i )
4311 assert(nlp->varmap_nlpi2nlp[i] >= 0);
4312 #endif
4313 return SCIP_OKAY;
4314 }
4315
4316 assert(nlp->solver != NULL);
4317 assert(nlp->problem != NULL);
4318
4319 /* create marker which variables have to be deleted */
4320 SCIP_CALL( SCIPsetAllocBufferArray(set, &colset, nlp->nvars_solver) );
4321 c = 0;
4322 for( i = 0; i < nlp->nvars_solver; ++i )
4323 {
4324 if( nlp->varmap_nlpi2nlp[i] == -1 )
4325 {
4326 colset[i] = 1;
4327 ++c;
4328 }
4329 else
4330 colset[i] = 0;
4331 }
4332 assert(c == nlp->nunflushedvardel);
4333
4334 /* delete variables from NLPI problem */
4335 SCIP_CALL( SCIPnlpiDelVarSet(nlp->solver, nlp->problem, colset, nlp->nvars_solver) );
4336
4337 /* update NLPI variable indices */
4338 for( i = 0; i < nlp->nvars_solver; ++i )
4339 {
4340 assert(colset[i] <= i); /* we assume that the NLP solver did not move a variable behind its previous position!! */
4341 if( colset[i] < 0 )
4342 {
4343 /* assert that variable was marked as deleted */
4344 assert(nlp->varmap_nlpi2nlp[i] == -1);
4345 }
4346 else if( colset[i] < i)
4347 {
4348 /* variable at position i moved (forward) to position colset[i] */
4349 int varpos;
4350
4351 varpos = nlp->varmap_nlpi2nlp[i]; /* position of variable i in NLP */
4352 assert(varpos >= 0);
4353 assert(varpos < nlp->nvars);
4354 assert(nlp->varmap_nlp2nlpi[varpos] == i);
4355
4356 /* there should be no variable at the new position already */
4357 assert(nlp->varmap_nlpi2nlp[colset[i]] == -1);
4358
4359 nlp->varmap_nlp2nlpi[varpos] = colset[i];
4360 nlp->varmap_nlpi2nlp[colset[i]] = varpos;
4361 }
4362 else
4363 {
4364 /* variable i stays at position i */
4365 assert(nlp->varmap_nlpi2nlp[i] >= 0);
4366 assert(nlp->varmap_nlpi2nlp[i] < nlp->nvars);
4367 assert(nlp->varmap_nlp2nlpi[nlp->varmap_nlpi2nlp[i]] == i);
4368 }
4369 }
4370
4371 nlp->nvars_solver -= c;
4372 nlp->nunflushedvardel = 0;
4373
4374 /* cleanup */
4375 SCIPsetFreeBufferArray(set, &colset);
4376
4377 return SCIP_OKAY;
4378 }
4379
4380 /** adds nonlinear rows to NLPI problem that have been added to NLP before
4381 * assumes that there are no pending variable additions or deletions (nlpFlushVarDeletions and nlpFlushVarAdditions should be called first) */
4382 static
nlpFlushNlRowAdditions(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)4383 SCIP_RETCODE nlpFlushNlRowAdditions(
4384 SCIP_NLP* nlp, /**< NLP data */
4385 BMS_BLKMEM* blkmem, /**< block memory */
4386 SCIP_SET* set /**< global SCIP settings */
4387 )
4388 {
4389 int c, i;
4390 SCIP_NLROW* nlrow;
4391 SCIP_Real* lhss;
4392 SCIP_Real* rhss;
4393 int* nlinvars;
4394 int** linidxs;
4395 SCIP_Real** lincoefs;
4396 int* nquadelems;
4397 SCIP_QUADELEM** quadelems;
4398 int** nlidxs;
4399 SCIP_EXPRTREE** exprtrees;
4400 const char** names;
4401
4402 assert(nlp != NULL);
4403 assert(blkmem != NULL);
4404 assert(set != NULL);
4405 assert(nlp->nunflushednlrowadd >= 0);
4406 assert(nlp->nunflushedvaradd == 0);
4407 assert(nlp->nunflushedvardel == 0);
4408 assert(!nlp->indiving);
4409
4410 if( nlp->nunflushednlrowadd == 0 )
4411 {
4412 #ifndef NDEBUG
4413 /* check that there are really no pending additions of variables */
4414 for( i = 0; i < nlp->nnlrows; ++i )
4415 assert(nlp->nlrows[i]->nlpiindex >= 0);
4416 #endif
4417 return SCIP_OKAY;
4418 }
4419
4420 assert(nlp->solver != NULL);
4421 assert(nlp->problem != NULL);
4422
4423 SCIP_CALL( nlpEnsureNlRowsSolverSize(nlp, blkmem, set, nlp->nnlrows_solver + nlp->nunflushednlrowadd) );
4424
4425 SCIP_CALL( SCIPsetAllocBufferArray(set, &lhss, nlp->nunflushednlrowadd) );
4426 SCIP_CALL( SCIPsetAllocBufferArray(set, &rhss, nlp->nunflushednlrowadd) );
4427 SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinvars, nlp->nunflushednlrowadd) );
4428 SCIP_CALL( SCIPsetAllocBufferArray(set, &linidxs, nlp->nunflushednlrowadd) );
4429 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nunflushednlrowadd) );
4430 SCIP_CALL( SCIPsetAllocBufferArray(set, &nquadelems, nlp->nunflushednlrowadd) );
4431 SCIP_CALL( SCIPsetAllocBufferArray(set, &quadelems, nlp->nunflushednlrowadd) );
4432 SCIP_CALL( SCIPsetAllocBufferArray(set, &nlidxs, nlp->nunflushednlrowadd) );
4433 SCIP_CALL( SCIPsetAllocBufferArray(set, &exprtrees, nlp->nunflushednlrowadd) );
4434 #if ADDNAMESTONLPI
4435 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushednlrowadd) );
4436 #else
4437 names = NULL;
4438 #endif
4439
4440 c = 0;
4441 for( i = 0; i < nlp->nnlrows; ++i )
4442 {
4443 nlrow = nlp->nlrows[i];
4444 assert(nlrow != NULL);
4445
4446 /* skip nonlinear rows already in NLPI problem */
4447 if( nlrow->nlpiindex >= 0 )
4448 continue;
4449 assert(c < nlp->nunflushednlrowadd);
4450
4451 /* get indices in NLPI */
4452 SCIP_CALL( nlpSetupNlpiIndices(nlp, set, nlrow, &linidxs[c], &quadelems[c], &nlidxs[c]) );
4453 assert(linidxs[c] != NULL || nlrow->nlinvars == 0);
4454 assert(quadelems[c] != NULL || nlrow->nquadvars == 0);
4455 assert(nlidxs[c] != NULL || nlrow->exprtree == NULL);
4456
4457 nlp->nlrowmap_nlpi2nlp[nlp->nnlrows_solver+c] = i;
4458 nlrow->nlpiindex = nlp->nnlrows_solver+c;
4459
4460 lhss[c] = nlrow->lhs;
4461 rhss[c] = nlrow->rhs;
4462 if( nlrow->constant != 0.0 )
4463 {
4464 if( !SCIPsetIsInfinity(set, -nlrow->lhs) )
4465 lhss[c] -= nlrow->constant;
4466 if( !SCIPsetIsInfinity(set, nlrow->rhs) )
4467 rhss[c] -= nlrow->constant;
4468 }
4469 if( rhss[c] < lhss[c] )
4470 {
4471 assert(SCIPsetIsEQ(set, lhss[c], rhss[c]));
4472 rhss[c] = lhss[c];
4473 }
4474
4475 nlinvars[c] = nlrow->nlinvars;
4476 lincoefs[c] = nlrow->lincoefs;
4477
4478 nquadelems[c] = nlrow->nquadelems;
4479
4480 exprtrees[c] = nlrow->exprtree;
4481
4482 #if ADDNAMESTONLPI
4483 names[c] = nlrow->name;
4484 #endif
4485
4486 ++c;
4487
4488 #ifdef NDEBUG
4489 /* have c vars to add already, there can be no more */
4490 if( c == nlp->nunflushednlrowadd )
4491 break;
4492 #endif
4493 }
4494 assert(c == nlp->nunflushednlrowadd);
4495
4496 nlp->nnlrows_solver += c;
4497
4498 SCIP_CALL( SCIPnlpiAddConstraints(nlp->solver, nlp->problem, c, lhss, rhss,
4499 nlinvars, linidxs, lincoefs,
4500 nquadelems, quadelems,
4501 nlidxs, exprtrees,
4502 names) );
4503
4504 for( c = nlp->nunflushednlrowadd - 1; c >= 0 ; --c )
4505 {
4506 if( nlidxs[c] != NULL )
4507 SCIPsetFreeBufferArray(set, &nlidxs[c]);
4508 if( quadelems[c] != NULL )
4509 SCIPsetFreeBufferArray(set, &quadelems[c]);
4510 if( linidxs[c] != NULL )
4511 SCIPsetFreeBufferArray(set, &linidxs[c]);
4512 }
4513
4514 #if ADDNAMESTONLPI
4515 SCIPsetFreeBufferArray(set, &names);
4516 #endif
4517 SCIPsetFreeBufferArray(set, &exprtrees);
4518 SCIPsetFreeBufferArray(set, &nlidxs);
4519 SCIPsetFreeBufferArray(set, &quadelems);
4520 SCIPsetFreeBufferArray(set, &nquadelems);
4521 SCIPsetFreeBufferArray(set, &lincoefs);
4522 SCIPsetFreeBufferArray(set, &linidxs);
4523 SCIPsetFreeBufferArray(set, &nlinvars);
4524 SCIPsetFreeBufferArray(set, &rhss);
4525 SCIPsetFreeBufferArray(set, &lhss);
4526
4527 nlp->nunflushednlrowadd = 0;
4528
4529 return SCIP_OKAY;
4530 }
4531
4532
4533 /** adds variables to NLPI problem that have been added to NLP before
4534 * may set nlp->objflushed to FALSE if a variable with nonzero obj.coefficient is added to the NLPI problem */
4535 static
nlpFlushVarAdditions(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)4536 SCIP_RETCODE nlpFlushVarAdditions(
4537 SCIP_NLP* nlp, /**< NLP data */
4538 BMS_BLKMEM* blkmem, /**< block memory */
4539 SCIP_SET* set /**< global SCIP settings */
4540 )
4541 {
4542 int i, c;
4543 SCIP_Real* lbs;
4544 SCIP_Real* ubs;
4545 const char** names;
4546
4547 assert(nlp != NULL);
4548 assert(blkmem != NULL);
4549 assert(set != NULL);
4550 assert(nlp->nunflushedvaradd >= 0);
4551 assert(!nlp->indiving);
4552
4553 if( nlp->nunflushedvaradd == 0 )
4554 {
4555 #ifndef NDEBUG
4556 /* check that there are really no pending additions of variables */
4557 for( i = 0; i < nlp->nvars; ++i )
4558 assert(nlp->varmap_nlp2nlpi[i] >= 0);
4559 #endif
4560 return SCIP_OKAY;
4561 }
4562
4563 assert(nlp->solver != NULL);
4564 assert(nlp->problem != NULL);
4565
4566 SCIP_CALL( nlpEnsureVarsSolverSize(nlp, blkmem, set, nlp->nvars_solver + nlp->nunflushedvaradd) );
4567
4568 SCIP_CALL( SCIPsetAllocBufferArray(set, &lbs, nlp->nunflushedvaradd) );
4569 SCIP_CALL( SCIPsetAllocBufferArray(set, &ubs, nlp->nunflushedvaradd) );
4570 #if ADDNAMESTONLPI
4571 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushedvaradd) );
4572 #else
4573 names = NULL;
4574 #endif
4575
4576 c = 0;
4577 for( i = 0; i < nlp->nvars; ++i )
4578 {
4579 /* skip variables already in NLPI problem */
4580 if( nlp->varmap_nlp2nlpi[i] >= 0 )
4581 continue;
4582 assert(c < nlp->nunflushedvaradd);
4583
4584 nlp->varmap_nlpi2nlp[nlp->nvars_solver+c] = i;
4585 nlp->varmap_nlp2nlpi[i] = nlp->nvars_solver+c;
4586 lbs[c] = SCIPvarGetLbLocal(nlp->vars[i]);
4587 ubs[c] = SCIPvarGetUbLocal(nlp->vars[i]);
4588 #if ADDNAMESTONLPI
4589 names[c] = SCIPvarGetName(nlp->vars[i]);
4590 #endif
4591 ++c;
4592
4593 /* if the new variable has a nonzero objective coefficient, then the objective need to be updated */
4594 if( !SCIPsetIsZero(set, SCIPvarGetObj(nlp->vars[i])) )
4595 nlp->objflushed = FALSE;
4596
4597 #ifdef NDEBUG
4598 /* have c vars to add already, there can be no more */
4599 if( c == nlp->nunflushedvaradd )
4600 break;
4601 #endif
4602 }
4603 assert(c == nlp->nunflushedvaradd);
4604
4605 nlp->nvars_solver += c;
4606
4607 SCIP_CALL( SCIPnlpiAddVars(nlp->solver, nlp->problem, c, lbs, ubs, names) );
4608
4609 #if ADDNAMESTONLPI
4610 SCIPsetFreeBufferArray(set, &names);
4611 #endif
4612 SCIPsetFreeBufferArray(set, &ubs);
4613 SCIPsetFreeBufferArray(set, &lbs);
4614
4615 nlp->nunflushedvaradd = 0;
4616
4617 return SCIP_OKAY;
4618 }
4619
4620 /** updates the objective in the NLPI problem, if necessary
4621 * assumes that there are no unflushed variable additions or deletions (nlpFlushVarDeletions and nlpFlushVarAdditions should be called first)
4622 */
4623 static
nlpFlushObjective(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)4624 SCIP_RETCODE nlpFlushObjective(
4625 SCIP_NLP* nlp, /**< NLP data */
4626 BMS_BLKMEM* blkmem, /**< block memory */
4627 SCIP_SET* set /**< global SCIP settings */
4628 )
4629 {
4630 int* linindices;
4631 SCIP_Real* lincoefs;
4632 SCIP_Real coef;
4633 int i;
4634 int nz;
4635
4636 assert(nlp != NULL);
4637 assert(blkmem != NULL);
4638 assert(set != NULL);
4639 assert(nlp->nunflushedvaradd == 0);
4640 assert(nlp->nunflushedvardel == 0);
4641 assert(!nlp->indiving);
4642
4643 if( nlp->objflushed )
4644 return SCIP_OKAY;
4645
4646 assert(nlp->solver != NULL);
4647 assert(nlp->problem != NULL);
4648
4649 /* assemble coefficients */
4650 SCIP_CALL( SCIPsetAllocBufferArray(set, &linindices, nlp->nvars_solver) );
4651 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nvars_solver) );
4652
4653 nz = 0;
4654 for( i = 0; i < nlp->nvars_solver; ++i )
4655 {
4656 assert(nlp->varmap_nlpi2nlp[i] >= 0); /* there should be no variable deletions pending */
4657
4658 coef = SCIPvarGetObj(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4659 if( SCIPsetIsZero(set, coef) )
4660 continue;
4661
4662 linindices[nz] = i;
4663 lincoefs[nz] = coef;
4664 ++nz;
4665 }
4666
4667 SCIP_CALL( SCIPnlpiSetObjective(nlp->solver, nlp->problem,
4668 nz, linindices, lincoefs,
4669 0, NULL,
4670 NULL, NULL,
4671 0.0) );
4672
4673 SCIPsetFreeBufferArray(set, &lincoefs);
4674 SCIPsetFreeBufferArray(set, &linindices);
4675
4676 nlp->objflushed = TRUE;
4677
4678 return SCIP_OKAY;
4679 }
4680
4681 /** solves the NLP, assuming it has been flushed already
4682 *
4683 * is used also to solve diving NLP
4684 */
4685 static
nlpSolve(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat)4686 SCIP_RETCODE nlpSolve(
4687 SCIP_NLP* nlp, /**< NLP data */
4688 BMS_BLKMEM* blkmem, /**< block memory buffers */
4689 SCIP_SET* set, /**< global SCIP settings */
4690 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4691 SCIP_STAT* stat /**< problem statistics */
4692 )
4693 {
4694 SCIP_Real sciptimelimit;
4695 SCIP_Real timeleft;
4696 int i;
4697
4698 assert(nlp != NULL);
4699 assert(blkmem != NULL);
4700 assert(set != NULL);
4701 assert(stat != NULL);
4702
4703 if( nlp->solver == NULL )
4704 {
4705 SCIPmessagePrintWarning(messagehdlr, "Attempted to solve NLP, but no solver available.\n");
4706
4707 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
4708 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
4709
4710 return SCIP_OKAY;
4711 }
4712
4713 assert(nlp->solver != NULL);
4714 assert(nlp->problem != NULL);
4715
4716 /* set initial guess, if available */
4717 if( nlp->haveinitguess )
4718 {
4719 /* @todo should we not set it if we had set it already? (initguessflushed...) */
4720 SCIP_Real* initialguess_solver;
4721 int nlpidx;
4722
4723 assert(nlp->initialguess != NULL);
4724
4725 SCIP_CALL( SCIPsetAllocBufferArray(set, &initialguess_solver, nlp->nvars_solver) );
4726
4727 for( i = 0; i < nlp->nvars_solver; ++i )
4728 {
4729 nlpidx = nlp->varmap_nlpi2nlp[i];
4730 assert(nlpidx >= 0);
4731 assert(nlpidx < nlp->nvars);
4732
4733 initialguess_solver[i] = nlp->initialguess[nlpidx];
4734 }
4735 SCIP_CALL( SCIPnlpiSetInitialGuess(nlp->solver, nlp->problem, initialguess_solver, NULL, NULL, NULL) );
4736
4737 SCIPsetFreeBufferArray(set, &initialguess_solver);
4738 }
4739
4740 /* set NLP tolerances to current SCIP primal and dual feasibility tolerance */
4741 SCIP_CALL( SCIPnlpiSetRealPar(nlp->solver, nlp->problem, SCIP_NLPPAR_FEASTOL, SCIPsetFeastol(set)) );
4742 SCIP_CALL( SCIPnlpiSetRealPar(nlp->solver, nlp->problem, SCIP_NLPPAR_RELOBJTOL, SCIPsetDualfeastol(set)) );
4743
4744 /* set the NLP timelimit to the remaining time */
4745 SCIP_CALL( SCIPsetGetRealParam(set, "limits/time", &sciptimelimit) );
4746 timeleft = sciptimelimit - SCIPclockGetTime(stat->solvingtime);
4747 SCIP_CALL( SCIPnlpiSetRealPar(nlp->solver, nlp->problem, SCIP_NLPPAR_TILIM, MAX(0.0, timeleft)) );
4748
4749 /* let NLP solver do his work */
4750 SCIPclockStart(stat->nlpsoltime, set);
4751
4752 SCIP_CALL( SCIPnlpiSolve(nlp->solver, nlp->problem) );
4753
4754 SCIPclockStop(stat->nlpsoltime, set);
4755 ++stat->nnlps;
4756
4757 nlp->termstat = SCIPnlpiGetTermstat(nlp->solver, nlp->problem);
4758 nlp->solstat = SCIPnlpiGetSolstat(nlp->solver, nlp->problem);
4759 switch( nlp->solstat )
4760 {
4761 case SCIP_NLPSOLSTAT_GLOBOPT:
4762 case SCIP_NLPSOLSTAT_LOCOPT:
4763 case SCIP_NLPSOLSTAT_FEASIBLE:
4764 case SCIP_NLPSOLSTAT_LOCINFEASIBLE:
4765 {
4766 SCIP_Real* primalvals;
4767 SCIP_Real* nlrowdualvals;
4768 SCIP_Real* varlbdualvals;
4769 SCIP_Real* varubdualvals;
4770
4771 primalvals = NULL;
4772 nlrowdualvals = NULL;
4773 varlbdualvals = NULL;
4774 varubdualvals = NULL;
4775
4776 /* get NLP solution */
4777 SCIP_CALL( SCIPnlpiGetSolution(nlp->solver, nlp->problem, &primalvals, &nlrowdualvals, &varlbdualvals, &varubdualvals, NULL) );
4778 assert(primalvals != NULL || nlp->nvars == 0);
4779 assert((varlbdualvals != NULL) == (varubdualvals != NULL)); /* if there are duals for one bound, then there should also be duals for the other bound */
4780
4781 /* store solution primal values in variable and evaluate objective function */
4782 if( nlp->indiving && nlp->divingobj != NULL )
4783 {
4784 for( i = 0; i < nlp->nvars; ++i )
4785 {
4786 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, primalvals[nlp->varmap_nlp2nlpi[i]]) ); /*lint !e613 */
4787 }
4788
4789 /* evaluate modified diving objective */
4790 SCIP_CALL( SCIPnlrowGetNLPActivity(nlp->divingobj, set, stat, nlp, &nlp->primalsolobjval) );
4791 }
4792 else
4793 {
4794 /* evaluate SCIP objective function */
4795 nlp->primalsolobjval = 0.0;
4796 for( i = 0; i < nlp->nvars; ++i )
4797 {
4798 SCIP_Real solval = primalvals[nlp->varmap_nlp2nlpi[i]]; /*lint !e613 */
4799
4800 /* do a quick assert that variable bounds are satisfied, if feasibility is claimed */
4801 assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(nlp->vars[i])) ||
4802 SCIPsetIsFeasGE(set, solval, SCIPvarGetLbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
4803 assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(nlp->vars[i])) ||
4804 SCIPsetIsFeasLE(set, solval, SCIPvarGetUbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
4805
4806 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, solval) ); /*lint !e613 */
4807 nlp->primalsolobjval += SCIPvarGetObj(nlp->vars[i]) * solval; /*lint !e613 */
4808 }
4809 }
4810
4811 /* store solution dual values in nlrows and variables */
4812 for( i = 0; i < nlp->nnlrows; ++i )
4813 {
4814 assert(nlp->nlrows[i]->nlpiindex >= 0); /* NLP was flushed before solve, so all nlrows should be in there */
4815
4816 nlp->nlrows[i]->dualsol = nlrowdualvals != NULL ? nlrowdualvals[nlp->nlrows[i]->nlpiindex] : 0.0;
4817
4818 /* SCIPsetDebugMsg(set, "dual of nlrow <%s> = %g\n", nlp->nlrows[i]->name, nlp->nlrows[i]->dualsol); */
4819 }
4820 assert(nlp->varlbdualvals != NULL || nlp->nvars == 0);
4821 assert(nlp->varubdualvals != NULL || nlp->nvars == 0);
4822 if( varlbdualvals != NULL )
4823 {
4824 for( i = 0; i < nlp->nvars; ++i )
4825 {
4826 assert(nlp->varmap_nlp2nlpi[i] >= 0); /* NLP was flushed before solve, so all vars should be in there */
4827
4828 nlp->varlbdualvals[i] = varlbdualvals[nlp->varmap_nlp2nlpi[i]];
4829 nlp->varubdualvals[i] = varubdualvals[nlp->varmap_nlp2nlpi[i]];
4830
4831 /* SCIPsetDebugMsg(set, "duals of var <%s> = %g %g\n", SCIPvarGetName(nlp->vars[i]), nlp->varlbdualvals[i], nlp->varubdualvals[i]); */
4832 }
4833 }
4834 else if( nlp->nvars > 0 )
4835 {
4836 BMSclearMemoryArray(nlp->varlbdualvals, nlp->nvars);
4837 BMSclearMemoryArray(nlp->varubdualvals, nlp->nvars);
4838 }
4839
4840 break;
4841 }
4842 default:
4843 nlp->primalsolobjval = SCIP_INVALID;
4844 break;
4845 } /*lint !e788*/
4846
4847 return SCIP_OKAY;
4848 }
4849
4850 /** assembles list of fractional variables in last NLP solution */
4851 static
nlpCalcFracVars(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat)4852 SCIP_RETCODE nlpCalcFracVars(
4853 SCIP_NLP* nlp, /**< NLP data */
4854 BMS_BLKMEM* blkmem, /**< block memory buffers */
4855 SCIP_SET* set, /**< global SCIP settings */
4856 SCIP_STAT* stat /**< problem statistics */
4857 )
4858 {
4859 assert(nlp != NULL);
4860 assert(blkmem != NULL);
4861 assert(set != NULL);
4862 assert(stat != NULL);
4863 assert(nlp->validfracvars <= stat->nnlps);
4864 assert(SCIPnlpHasSolution(nlp));
4865
4866 SCIPsetDebugMsg(set, "calculating NLP fractional variables: validfracvars=%" SCIP_LONGINT_FORMAT ", nnlps=%" SCIP_LONGINT_FORMAT "\n", nlp->validfracvars, stat->nnlps);
4867
4868 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
4869 {
4870 nlp->nfracvars = 0;
4871 nlp->npriofracvars = 0;
4872 nlp->validfracvars = stat->nnlps;
4873
4874 SCIPsetDebugMsg(set, "NLP globally infeasible, unbounded, or worse -> no solution values -> no fractional variables\n");
4875 return SCIP_OKAY;
4876 }
4877
4878 /* check, if the current NLP fractional variables array is invalid */
4879 if( nlp->validfracvars < stat->nnlps )
4880 {
4881 SCIP_VAR* var;
4882 SCIP_Real primsol;
4883 SCIP_Real frac;
4884 int branchpriority;
4885 int insertpos;
4886 int maxpriority;
4887 int i;
4888
4889 SCIPsetDebugMsg(set, " -> recalculating NLP fractional variables\n");
4890
4891 if( nlp->fracvarssize == 0 )
4892 {
4893 assert(nlp->fracvars == NULL);
4894 assert(nlp->fracvarssol == NULL);
4895 assert(nlp->fracvarsfrac == NULL);
4896 nlp->fracvarssize = 5;
4897 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize) );
4898 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize) );
4899 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize) );
4900 }
4901
4902 maxpriority = INT_MIN;
4903 nlp->nfracvars = 0;
4904 nlp->npriofracvars = 0;
4905 for( i = 0; i < nlp->nvars; ++i )
4906 {
4907 var = nlp->vars[i];
4908 assert(var != NULL);
4909
4910 primsol = SCIPvarGetNLPSol(var);
4911 assert(primsol < SCIP_INVALID);
4912
4913 /* consider only binary and integer variables */
4914 if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER )
4915 continue;
4916
4917 /* ignore fixed variables (due to numerics, it is possible, that the NLP solution of a fixed integer variable
4918 * (with large fixed value) is fractional in terms of absolute feasibility measure)
4919 */
4920 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
4921 continue;
4922
4923 /* check, if the LP solution value is fractional */
4924 frac = SCIPsetFeasFrac(set, primsol);
4925
4926 /* The fractionality should not be smaller than -feastol, however, if the primsol is large enough
4927 * and close to an integer, fixed precision floating point arithmetic might give us values slightly
4928 * smaller than -feastol. Originally, the "frac >= -feastol"-check was within SCIPsetIsFeasFracIntegral(),
4929 * however, we relaxed it to "frac >= -2*feastol" and have the stricter check here for small-enough primsols.
4930 */
4931 assert(SCIPsetIsGE(set, frac, -SCIPsetFeastol(set)) || (primsol > 1e14 * SCIPsetFeastol(set)));
4932
4933 if( SCIPsetIsFeasFracIntegral(set, frac) )
4934 continue;
4935
4936 /* ensure enough space in fracvars arrays */
4937 if( nlp->fracvarssize <= nlp->nfracvars )
4938 {
4939 int newsize;
4940
4941 newsize = SCIPsetCalcMemGrowSize(set, nlp->nfracvars + 1);
4942 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize, newsize) );
4943 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize, newsize) );
4944 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize, newsize) );
4945 nlp->fracvarssize = newsize;
4946 }
4947 assert(nlp->nfracvars < nlp->fracvarssize);
4948 assert(nlp->fracvars != NULL);
4949 assert(nlp->fracvarssol != NULL);
4950 assert(nlp->fracvarsfrac != NULL);
4951
4952 /* insert candidate in candidate list */
4953 branchpriority = SCIPvarGetBranchPriority(var);
4954 insertpos = nlp->nfracvars;
4955 nlp->nfracvars++;
4956 if( branchpriority > maxpriority )
4957 {
4958 /* candidate has higher priority than the current maximum:
4959 * move it to the front and declare it to be the single best candidate
4960 */
4961 if( insertpos != 0 )
4962 {
4963 nlp->fracvars[insertpos] = nlp->fracvars[0];
4964 nlp->fracvarssol[insertpos] = nlp->fracvarssol[0];
4965 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[0];
4966 insertpos = 0;
4967 }
4968 nlp->npriofracvars = 1;
4969 maxpriority = branchpriority;
4970 }
4971 else if( branchpriority == maxpriority )
4972 {
4973 /* candidate has equal priority as the current maximum:
4974 * move away the first non-maximal priority candidate, move the current candidate to the correct
4975 * slot (binaries first) and increase the number of maximal priority candidates
4976 */
4977 if( insertpos != nlp->npriofracvars )
4978 {
4979 nlp->fracvars[insertpos] = nlp->fracvars[nlp->npriofracvars];
4980 nlp->fracvarssol[insertpos] = nlp->fracvarssol[nlp->npriofracvars];
4981 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[nlp->npriofracvars];
4982 insertpos = nlp->npriofracvars;
4983 }
4984 ++nlp->npriofracvars;
4985 }
4986 nlp->fracvars[insertpos] = var;
4987 nlp->fracvarssol[insertpos] = primsol;
4988 nlp->fracvarsfrac[insertpos] = frac;
4989
4990 SCIPsetDebugMsg(set, " -> candidate %d: var=<%s>, sol=%g, frac=%g, prio=%d (max: %d) -> pos %d\n",
4991 nlp->nfracvars, SCIPvarGetName(var), primsol, frac, branchpriority, maxpriority, insertpos);
4992 }
4993
4994 nlp->validfracvars = stat->nnlps;
4995 }
4996 assert(0 <= nlp->npriofracvars);
4997 assert(nlp->npriofracvars <= nlp->nfracvars);
4998
4999 SCIPsetDebugMsg(set, " -> %d fractional variables (%d of maximal priority)\n", nlp->nfracvars, nlp->npriofracvars);
5000
5001 return SCIP_OKAY;
5002 }
5003
5004 /** event handling for variable events */
5005 static
SCIP_DECL_EVENTEXEC(eventExecNlp)5006 SCIP_DECL_EVENTEXEC(eventExecNlp)
5007 {
5008 SCIP_EVENTTYPE etype;
5009 SCIP_VAR* var;
5010
5011 assert(scip != NULL);
5012 assert(eventhdlr != NULL);
5013 assert(event != NULL);
5014 assert(eventdata != NULL);
5015
5016 assert((SCIP_NLP*)eventdata == scip->nlp);
5017
5018 etype = SCIPeventGetType(event);
5019 var = SCIPeventGetVar(event);
5020
5021 if( SCIP_EVENTTYPE_VARADDED & etype )
5022 {
5023 SCIPdebugMessage("-> handling varadd event, variable <%s>\n", SCIPvarGetName(var) );
5024 SCIP_CALL( SCIPnlpAddVar(scip->nlp, SCIPblkmem(scip), scip->set, var) );
5025 }
5026 else if( SCIP_EVENTTYPE_VARDELETED & etype )
5027 {
5028 SCIPdebugMessage("-> handling vardel event, variable <%s>\n", SCIPvarGetName(var) );
5029 SCIP_CALL( SCIPnlpDelVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->eventqueue, scip->lp, var) );
5030 }
5031 else if( SCIP_EVENTTYPE_VARFIXED & etype )
5032 {
5033 /* variable was fixed, aggregated, or multi-aggregated */
5034 SCIPdebugMessage("-> handling variable fixation event, variable <%s>\n", SCIPvarGetName(var) );
5035 SCIP_CALL( nlpRemoveFixedVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
5036 }
5037 else if( SCIP_EVENTTYPE_BOUNDCHANGED & etype )
5038 {
5039 SCIPdebugMessage("-> handling bound changed event %" SCIP_EVENTTYPE_FORMAT ", variable <%s>\n", etype, SCIPvarGetName(var) );
5040 SCIP_CALL( nlpUpdateVarBounds(scip->nlp, scip->set, var, (SCIP_Bool)(SCIP_EVENTTYPE_BOUNDTIGHTENED & etype)) );
5041 }
5042 else if( SCIP_EVENTTYPE_OBJCHANGED & etype )
5043 {
5044 SCIPdebugMessage("-> handling objchg event, variable <%s>\n", SCIPvarGetName(var) );
5045 SCIP_CALL( nlpUpdateObjCoef(scip->nlp, var) );
5046 }
5047 else
5048 {
5049 SCIPerrorMessage("unexpected event %ld on variable <%s>\n", etype, SCIPvarGetName(var) );
5050 return SCIP_ERROR;
5051 }
5052
5053 return SCIP_OKAY;
5054 }
5055
5056
5057 /*
5058 * public NLP methods
5059 */
5060
5061 /** includes NLP specific plugins (e.g., event handler) and parameters */
SCIPnlpInclude(SCIP_SET * set,BMS_BLKMEM * blkmem)5062 SCIP_RETCODE SCIPnlpInclude(
5063 SCIP_SET* set, /**< global SCIP settings */
5064 BMS_BLKMEM* blkmem /**< block memory */
5065 )
5066 {
5067 SCIP_EVENTHDLR* eventhdlr;
5068
5069 assert(set != NULL);
5070 assert(blkmem != NULL);
5071 assert(set->stage == SCIP_STAGE_INIT);
5072
5073 /* check whether event handler is already present */
5074 if( SCIPsetFindEventhdlr(set, EVENTHDLR_NAME) != NULL )
5075 {
5076 SCIPerrorMessage("event handler <" EVENTHDLR_NAME "> already included.\n");
5077 return SCIP_INVALIDDATA;
5078 }
5079
5080 SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC,
5081 NULL, NULL, NULL, NULL, NULL, NULL, NULL, eventExecNlp, NULL) );
5082 SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) );
5083
5084 return SCIP_OKAY;
5085 } /*lint !e715*/
5086
5087 /** construct a new empty NLP */
SCIPnlpCreate(SCIP_NLP ** nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,const char * name,int nvars_estimate)5088 SCIP_RETCODE SCIPnlpCreate(
5089 SCIP_NLP** nlp, /**< NLP handler, call by reference */
5090 BMS_BLKMEM* blkmem, /**< block memory */
5091 SCIP_SET* set, /**< global SCIP settings */
5092 SCIP_STAT* stat, /**< problem statistics */
5093 const char* name, /**< problem name */
5094 int nvars_estimate /**< an estimate on the number of variables that may be added to the NLP later */
5095 )
5096 {
5097 assert(nlp != NULL);
5098 assert(blkmem != NULL);
5099 assert(set != NULL);
5100 assert(stat != NULL);
5101 assert(name != NULL);
5102
5103 SCIP_ALLOC( BMSallocMemory(nlp) );
5104
5105 /* select NLP solver (if any available) and setup problem */
5106 if( set->nnlpis > 0 )
5107 {
5108 assert(set->nlp_solver != NULL);
5109 if( set->nlp_solver[0] == '\0' )
5110 { /* take solver with highest priority */
5111 assert(set->nlpis != NULL);
5112
5113 /* sort the NLPIs if necessary */
5114 if( !set->nlpissorted )
5115 SCIPsetSortNlpis(set);
5116
5117 (*nlp)->solver = set->nlpis[0];
5118 }
5119 else
5120 { /* find user specified NLP solver */
5121 (*nlp)->solver = SCIPsetFindNlpi(set, set->nlp_solver);
5122 if( (*nlp)->solver == NULL )
5123 {
5124 SCIPerrorMessage("Selected NLP solver <%s> not available.\n", set->nlp_solver);
5125 return SCIP_PLUGINNOTFOUND;
5126 }
5127 }
5128 assert((*nlp)->solver != NULL);
5129 SCIP_CALL( SCIPnlpiCreateProblem((*nlp)->solver, &(*nlp)->problem, "scip_nlp") );
5130 }
5131 else
5132 {
5133 /* maybe someone wanna use the NLP just to collect nonlinearities, but is not necessarily interesting on solving
5134 * so we allow this and just continue */
5135 (*nlp)->solver = NULL;
5136 (*nlp)->problem = NULL;
5137 }
5138
5139 /* status */
5140 (*nlp)->nunflushedvaradd = 0;
5141 (*nlp)->nunflushedvardel = 0;
5142 (*nlp)->nunflushednlrowadd = 0;
5143 (*nlp)->nunflushednlrowdel = 0;
5144 (*nlp)->isrelax = TRUE;
5145 (*nlp)->indiving = FALSE;
5146
5147 /* variables in problem and NLPI problem */
5148 (*nlp)->nvars = 0;
5149 (*nlp)->sizevars = 0;
5150 (*nlp)->vars = NULL;
5151 SCIP_CALL( SCIPhashmapCreate(&(*nlp)->varhash, blkmem, nvars_estimate) );
5152
5153 (*nlp)->nvars_solver = 0;
5154 (*nlp)->sizevars_solver = 0;
5155 (*nlp)->varmap_nlp2nlpi = NULL;
5156 (*nlp)->varmap_nlpi2nlp = NULL;
5157
5158 /* nonlinear rows in problem and NLPI problem */
5159 (*nlp)->nnlrows = 0;
5160 (*nlp)->sizenlrows = 0;
5161 (*nlp)->nlrows = NULL;
5162
5163 (*nlp)->nnlrows_solver = 0;
5164 (*nlp)->sizenlrows_solver = 0;
5165 (*nlp)->nlrowmap_nlpi2nlp = NULL;
5166
5167 /* objective function */
5168 (*nlp)->objflushed = TRUE;
5169 (*nlp)->divingobj = NULL;
5170
5171 /* initial guess */
5172 (*nlp)->haveinitguess = FALSE;
5173 (*nlp)->initialguess = NULL;
5174
5175 /* solution of NLP */
5176 (*nlp)->primalsolobjval = SCIP_INVALID;
5177 (*nlp)->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
5178 (*nlp)->termstat = SCIP_NLPTERMSTAT_OTHER;
5179 (*nlp)->varlbdualvals = NULL;
5180 (*nlp)->varubdualvals = NULL;
5181
5182 /* event handling: catch variable addition and deletion events */
5183 (*nlp)->eventhdlr = SCIPsetFindEventhdlr(set, EVENTHDLR_NAME);
5184 if( (*nlp)->eventhdlr == NULL )
5185 {
5186 SCIPerrorMessage("NLP eventhandler <" EVENTHDLR_NAME "> not found.\n");
5187 return SCIP_PLUGINNOTFOUND;
5188 }
5189 SCIP_CALL( SCIPeventfilterAdd(set->scip->eventfilter, blkmem, set,
5190 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
5191 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), &(*nlp)->globalfilterpos) );
5192
5193 /* fractional variables in last NLP solution */
5194 (*nlp)->fracvars = NULL;
5195 (*nlp)->fracvarssol = NULL;
5196 (*nlp)->fracvarsfrac = NULL;
5197 (*nlp)->nfracvars = 0;
5198 (*nlp)->npriofracvars = 0;
5199 (*nlp)->fracvarssize = 0;
5200 (*nlp)->validfracvars = -1;
5201
5202 /* miscellaneous */
5203 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlp)->name, name, strlen(name)+1) );
5204
5205 return SCIP_OKAY;
5206 }
5207
5208 /** frees NLP data object */
SCIPnlpFree(SCIP_NLP ** nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)5209 SCIP_RETCODE SCIPnlpFree(
5210 SCIP_NLP** nlp, /**< pointer to NLP data object */
5211 BMS_BLKMEM* blkmem, /**< block memory */
5212 SCIP_SET* set, /**< global SCIP settings */
5213 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5214 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */
5215 )
5216 {
5217 assert(nlp != NULL);
5218 assert(*nlp != NULL);
5219 assert(blkmem != NULL);
5220 assert(set != NULL);
5221
5222 /* drop fractional variables */
5223 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvars, (*nlp)->fracvarssize);
5224 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarssol, (*nlp)->fracvarssize);
5225 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarsfrac, (*nlp)->fracvarssize);
5226
5227 /* drop global events (variable addition and deletion) */
5228 SCIP_CALL( SCIPeventfilterDel(set->scip->eventfilter, blkmem, set,
5229 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
5230 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), (*nlp)->globalfilterpos) );
5231
5232 SCIP_CALL( SCIPnlpReset(*nlp, blkmem, set, eventqueue, lp) );
5233 assert((*nlp)->nnlrows == 0);
5234 assert((*nlp)->nnlrows_solver == 0);
5235 assert((*nlp)->nvars == 0);
5236 assert((*nlp)->nvars_solver == 0);
5237 assert((*nlp)->initialguess == NULL);
5238
5239 BMSfreeBlockMemoryArray(blkmem, &(*nlp)->name, strlen((*nlp)->name)+1);
5240
5241 /* free nonlinear rows arrays */
5242 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrowmap_nlpi2nlp, (*nlp)->sizenlrows_solver);
5243 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrows, (*nlp)->sizenlrows);
5244
5245 /* free variables arrays */
5246 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlp2nlpi, (*nlp)->sizevars);
5247 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlpi2nlp, (*nlp)->sizevars_solver);
5248 SCIPhashmapFree(&(*nlp)->varhash);
5249 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->vars, (*nlp)->sizevars);
5250 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varlbdualvals, (*nlp)->sizevars);
5251 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varubdualvals, (*nlp)->sizevars);
5252
5253 /* free NLPI problem */
5254 if( (*nlp)->problem != NULL )
5255 {
5256 SCIP_CALL( SCIPnlpiFreeProblem((*nlp)->solver, &(*nlp)->problem) );
5257 }
5258
5259 /* free NLP data structure */
5260 BMSfreeMemory(nlp);
5261
5262 return SCIP_OKAY;
5263 }
5264
5265 /** resets the NLP to the empty NLP by removing all variables and rows from NLP,
5266 * releasing all rows, and flushing the changes to the NLP solver
5267 */
SCIPnlpReset(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)5268 SCIP_RETCODE SCIPnlpReset(
5269 SCIP_NLP* nlp, /**< NLP data */
5270 BMS_BLKMEM* blkmem, /**< block memory */
5271 SCIP_SET* set, /**< global SCIP settings */
5272 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5273 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */
5274 )
5275 {
5276 int i;
5277
5278 assert(nlp != NULL);
5279 assert(blkmem != NULL);
5280 assert(set != NULL);
5281
5282 if( nlp->indiving )
5283 {
5284 SCIP_CALL( SCIPnlpEndDive(nlp, blkmem, set) );
5285 }
5286
5287 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
5288 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
5289
5290 BMSfreeBlockMemoryArrayNull(blkmem, &nlp->initialguess, nlp->sizevars);
5291 nlp->haveinitguess = FALSE;
5292
5293 for(i = nlp->nnlrows - 1; i >= 0; --i)
5294 {
5295 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, i) );
5296 }
5297
5298 for(i = nlp->nvars - 1; i >= 0; --i)
5299 {
5300 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, eventqueue, lp, i) );
5301 }
5302
5303 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set) );
5304
5305 return SCIP_OKAY;
5306 }
5307
5308 /** currently a dummy function that always returns TRUE */
SCIPnlpHasCurrentNodeNLP(SCIP_NLP * nlp)5309 SCIP_Bool SCIPnlpHasCurrentNodeNLP(
5310 SCIP_NLP* nlp /**< NLP data */
5311 )
5312 {
5313 assert(nlp != NULL);
5314 return TRUE;
5315 } /*lint !e715*/
5316
5317 /** ensures, that variables array of NLP can store at least num entries */
SCIPnlpEnsureVarsSize(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)5318 SCIP_RETCODE SCIPnlpEnsureVarsSize(
5319 SCIP_NLP* nlp, /**< NLP data */
5320 BMS_BLKMEM* blkmem, /**< block memory */
5321 SCIP_SET* set, /**< global SCIP settings */
5322 int num /**< minimum number of entries to store */
5323 )
5324 {
5325 assert(nlp != NULL);
5326 assert(blkmem != NULL);
5327 assert(set != NULL);
5328 assert(nlp->nvars <= nlp->sizevars);
5329
5330 if( num > nlp->sizevars )
5331 {
5332 int newsize;
5333
5334 newsize = SCIPsetCalcMemGrowSize(set, num);
5335 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->vars, nlp->sizevars, newsize) );
5336 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlp2nlpi, nlp->sizevars, newsize) );
5337 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varlbdualvals, nlp->sizevars, newsize) );
5338 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varubdualvals, nlp->sizevars, newsize) );
5339 if( nlp->initialguess != NULL )
5340 {
5341 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars, newsize) );
5342 }
5343
5344 nlp->sizevars = newsize;
5345 }
5346 assert(num <= nlp->sizevars);
5347
5348 return SCIP_OKAY;
5349 }
5350
5351 /** adds a variable to the NLP and captures the variable */
SCIPnlpAddVar(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_VAR * var)5352 SCIP_RETCODE SCIPnlpAddVar(
5353 SCIP_NLP* nlp, /**< NLP data */
5354 BMS_BLKMEM* blkmem, /**< block memory */
5355 SCIP_SET* set, /**< global SCIP settings */
5356 SCIP_VAR* var /**< variable */
5357 )
5358 {
5359 assert(nlp != NULL);
5360 assert(blkmem != NULL);
5361 assert(set != NULL);
5362 assert(var != NULL);
5363 assert(SCIPvarIsTransformed(var));
5364 assert(!SCIPhashmapExists(nlp->varhash, var));
5365
5366 if( nlp->indiving )
5367 {
5368 SCIPerrorMessage("cannot add variable during NLP diving\n");
5369 return SCIP_ERROR;
5370 }
5371
5372 SCIP_CALL( nlpAddVars(nlp, blkmem, set, 1, &var) );
5373
5374 return SCIP_OKAY;
5375 }
5376
5377 /** adds a set of variables to the NLP and captures the variables */
SCIPnlpAddVars(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int nvars,SCIP_VAR ** vars)5378 SCIP_RETCODE SCIPnlpAddVars(
5379 SCIP_NLP* nlp, /**< NLP data */
5380 BMS_BLKMEM* blkmem, /**< block memory */
5381 SCIP_SET* set, /**< global SCIP settings */
5382 int nvars, /**< number of variables to add */
5383 SCIP_VAR** vars /**< variables to add */
5384 )
5385 {
5386 assert(nlp != NULL);
5387 assert(blkmem != NULL);
5388 assert(set != NULL);
5389 assert(vars != NULL || nvars == 0);
5390
5391 if( nlp->indiving && nvars > 0)
5392 {
5393 SCIPerrorMessage("cannot add variables during NLP diving\n");
5394 return SCIP_ERROR;
5395 }
5396
5397 SCIP_CALL( nlpAddVars(nlp, blkmem, set, nvars, vars) );
5398
5399 return SCIP_OKAY;
5400 }
5401
5402 /** deletes a variable from the NLP and releases the variable */
SCIPnlpDelVar(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_VAR * var)5403 SCIP_RETCODE SCIPnlpDelVar(
5404 SCIP_NLP* nlp, /**< NLP data */
5405 BMS_BLKMEM* blkmem, /**< block memory */
5406 SCIP_SET* set, /**< global SCIP settings */
5407 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5408 SCIP_LP* lp, /**< SCIP LP, needed to release variable */
5409 SCIP_VAR* var /**< variable */
5410 )
5411 {
5412 int varpos;
5413
5414 assert(nlp != NULL);
5415 assert(blkmem != NULL);
5416 assert(set != NULL);
5417 assert(var != NULL);
5418
5419 if( !SCIPhashmapExists(nlp->varhash, var) )
5420 {
5421 SCIPerrorMessage("variable <%s> not found in NLP, cannot delete\n", SCIPvarGetName(var));
5422 return SCIP_ERROR;
5423 }
5424
5425 if( nlp->indiving )
5426 {
5427 SCIPerrorMessage("cannot delete variable during NLP diving\n");
5428 return SCIP_ERROR;
5429 }
5430
5431 varpos = SCIPhashmapGetImageInt(nlp->varhash, var);
5432
5433 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, eventqueue, lp, varpos) );
5434
5435 return SCIP_OKAY;
5436 }
5437
5438 /** ensures, that nonlinear rows array of NLP can store at least num entries */
SCIPnlpEnsureNlRowsSize(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)5439 SCIP_RETCODE SCIPnlpEnsureNlRowsSize(
5440 SCIP_NLP* nlp, /**< NLP data */
5441 BMS_BLKMEM* blkmem, /**< block memory */
5442 SCIP_SET* set, /**< global SCIP settings */
5443 int num /**< minimum number of entries to store */
5444 )
5445 {
5446 assert(nlp != NULL);
5447 assert(blkmem != NULL);
5448 assert(set != NULL);
5449 assert(nlp->nnlrows <= nlp->sizenlrows);
5450
5451 if( num > nlp->sizenlrows )
5452 {
5453 int newsize;
5454
5455 newsize = SCIPsetCalcMemGrowSize(set, num);
5456 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrows, nlp->sizenlrows, newsize) );
5457
5458 nlp->sizenlrows = newsize;
5459 }
5460 assert(num <= nlp->sizenlrows);
5461
5462 return SCIP_OKAY;
5463 }
5464
5465 /** adds a nonlinear row to the NLP and captures it
5466 * all variables of the row need to be present in the NLP */
SCIPnlpAddNlRow(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_NLROW * nlrow)5467 SCIP_RETCODE SCIPnlpAddNlRow(
5468 SCIP_NLP* nlp, /**< NLP data */
5469 BMS_BLKMEM* blkmem, /**< block memory */
5470 SCIP_SET* set, /**< global SCIP settings */
5471 SCIP_STAT* stat, /**< problem statistics data */
5472 SCIP_NLROW* nlrow /**< nonlinear row */
5473 )
5474 {
5475 assert(nlp != NULL);
5476 assert(nlrow != NULL);
5477
5478 if( nlp->indiving )
5479 {
5480 SCIPerrorMessage("cannot add row during NLP diving\n");
5481 return SCIP_ERROR;
5482 }
5483
5484 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, 1, &nlrow) );
5485
5486 return SCIP_OKAY;
5487 }
5488
5489 /** adds nonlinear rows to the NLP and captures them
5490 * all variables of the row need to be present in the NLP */
SCIPnlpAddNlRows(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,int nnlrows,SCIP_NLROW ** nlrows)5491 SCIP_RETCODE SCIPnlpAddNlRows(
5492 SCIP_NLP* nlp, /**< NLP data */
5493 BMS_BLKMEM* blkmem, /**< block memory */
5494 SCIP_SET* set, /**< global SCIP settings */
5495 SCIP_STAT* stat, /**< problem statistics data */
5496 int nnlrows, /**< number of rows to add */
5497 SCIP_NLROW** nlrows /**< rows to add */
5498 )
5499 {
5500 assert(nlp != NULL);
5501 assert(nlrows != NULL || nnlrows == 0);
5502
5503 if( nnlrows == 0 )
5504 return SCIP_OKAY;
5505
5506 if( nlp->indiving )
5507 {
5508 SCIPerrorMessage("cannot add rows during NLP diving\n");
5509 return SCIP_ERROR;
5510 }
5511
5512 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, nnlrows, nlrows) );
5513
5514 return SCIP_OKAY;
5515 }
5516
5517 /** deletes a nonlinear row from the NLP
5518 * does nothing if nonlinear row is not in NLP */
SCIPnlpDelNlRow(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_NLROW * nlrow)5519 SCIP_RETCODE SCIPnlpDelNlRow(
5520 SCIP_NLP* nlp, /**< NLP data */
5521 BMS_BLKMEM* blkmem, /**< block memory */
5522 SCIP_SET* set, /**< global SCIP settings */
5523 SCIP_NLROW* nlrow /**< nonlinear row */
5524 )
5525 {
5526 assert(nlp != NULL);
5527 assert(blkmem != NULL);
5528 assert(set != NULL);
5529 assert(nlrow != NULL);
5530
5531 /* if row not in NLP, nothing to do */
5532 if( nlrow->nlpindex == -1 )
5533 return SCIP_OKAY;
5534
5535 assert(nlrow->nlpindex >= 0);
5536 assert(nlrow->nlpindex < nlp->nnlrows);
5537
5538 if( nlp->indiving )
5539 {
5540 SCIPerrorMessage("cannot delete row during NLP diving\n");
5541 return SCIP_ERROR;
5542 }
5543
5544 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, nlrow->nlpindex) );
5545
5546 return SCIP_OKAY;
5547 }
5548
5549 /** applies all cached changes to the NLP solver */
SCIPnlpFlush(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)5550 SCIP_RETCODE SCIPnlpFlush(
5551 SCIP_NLP* nlp, /**< current NLP data */
5552 BMS_BLKMEM* blkmem, /**< block memory */
5553 SCIP_SET* set /**< global SCIP settings */
5554 )
5555 {
5556 assert(nlp != NULL);
5557 assert(blkmem != NULL);
5558 assert(set != NULL);
5559
5560 if( nlp->indiving )
5561 {
5562 SCIPerrorMessage("cannot flush NLP during NLP diving\n");
5563 return SCIP_ERROR;
5564 }
5565
5566 /* flush removals of nonlinear rows and variables */
5567 SCIP_CALL( nlpFlushNlRowDeletions(nlp, blkmem, set) );
5568 SCIP_CALL( nlpFlushVarDeletions(nlp, blkmem, set) );
5569 assert(nlp->nunflushednlrowdel == 0);
5570 assert(nlp->nunflushedvardel == 0);
5571
5572 /* flush addition of variables, objective, and addition of rows */
5573 SCIP_CALL( nlpFlushVarAdditions(nlp, blkmem, set) );
5574 SCIP_CALL( nlpFlushObjective(nlp, blkmem, set) );
5575 SCIP_CALL( nlpFlushNlRowAdditions(nlp, blkmem, set) );
5576 assert(nlp->nunflushedvaradd == 0);
5577 assert(nlp->objflushed == TRUE);
5578 assert(nlp->nunflushednlrowadd == 0);
5579
5580 assert(nlp->nvars == nlp->nvars_solver);
5581 assert(nlp->nnlrows == nlp->nnlrows_solver);
5582
5583 return SCIP_OKAY;
5584 }
5585
5586 /** solves the NLP */
SCIPnlpSolve(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat)5587 SCIP_RETCODE SCIPnlpSolve(
5588 SCIP_NLP* nlp, /**< NLP data */
5589 BMS_BLKMEM* blkmem, /**< block memory buffers */
5590 SCIP_SET* set, /**< global SCIP settings */
5591 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5592 SCIP_STAT* stat /**< problem statistics */
5593 )
5594 {
5595 assert(nlp != NULL);
5596 assert(blkmem != NULL);
5597 assert(set != NULL);
5598 assert(stat != NULL);
5599
5600 if( nlp->indiving )
5601 {
5602 SCIPerrorMessage("cannot solve NLP during NLP diving (use SCIPsolveDiveNLP)\n");
5603 return SCIP_ERROR;
5604 }
5605
5606 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set) );
5607
5608 SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat) );
5609
5610 return SCIP_OKAY;
5611 }
5612
5613 /** gets objective value of current NLP */
SCIPnlpGetObjval(SCIP_NLP * nlp)5614 SCIP_Real SCIPnlpGetObjval(
5615 SCIP_NLP* nlp /**< current NLP data */
5616 )
5617 {
5618 assert(nlp != NULL);
5619
5620 return nlp->primalsolobjval;
5621 }
5622
5623 /** gives current pseudo objective value */
SCIPnlpGetPseudoObjval(SCIP_NLP * nlp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * pseudoobjval)5624 SCIP_RETCODE SCIPnlpGetPseudoObjval(
5625 SCIP_NLP* nlp, /**< current NLP data */
5626 SCIP_SET* set, /**< global SCIP settings */
5627 SCIP_STAT* stat, /**< problem statistics */
5628 SCIP_Real* pseudoobjval /**< buffer to store pseudo objective value */
5629 )
5630 {
5631 assert(nlp != NULL);
5632 assert(pseudoobjval != NULL);
5633
5634 if( nlp->divingobj != NULL )
5635 {
5636 assert(nlp->indiving);
5637 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlp->divingobj, set, stat, pseudoobjval) );
5638 }
5639 else
5640 {
5641 int i;
5642
5643 *pseudoobjval = 0.0;
5644 for( i = 0; i < nlp->nvars; ++i )
5645 *pseudoobjval += SCIPvarGetObj(nlp->vars[i]) * SCIPvarGetBestBoundLocal(nlp->vars[i]);
5646 }
5647
5648 return SCIP_OKAY;
5649 }
5650
5651 /** gets fractional variables of last NLP solution along with solution values and fractionalities
5652 */
SCIPnlpGetFracVars(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR *** fracvars,SCIP_Real ** fracvarssol,SCIP_Real ** fracvarsfrac,int * nfracvars,int * npriofracvars)5653 SCIP_RETCODE SCIPnlpGetFracVars(
5654 SCIP_NLP* nlp, /**< NLP data structure */
5655 BMS_BLKMEM* blkmem, /**< block memory */
5656 SCIP_SET* set, /**< global SCIP settings */
5657 SCIP_STAT* stat, /**< problem statistics */
5658 SCIP_VAR*** fracvars, /**< pointer to store the array of NLP fractional variables, or NULL */
5659 SCIP_Real** fracvarssol, /**< pointer to store the array of NLP fractional variables solution values, or NULL */
5660 SCIP_Real** fracvarsfrac, /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
5661 int* nfracvars, /**< pointer to store the number of NLP fractional variables , or NULL */
5662 int* npriofracvars /**< pointer to store the number of NLP fractional variables with maximal branching priority, or NULL */
5663 )
5664 {
5665 assert(nlp != NULL);
5666
5667 SCIP_CALL( nlpCalcFracVars(nlp, blkmem, set, stat) );
5668 assert(nlp->fracvars != NULL);
5669 assert(nlp->fracvarssol != NULL);
5670 assert(nlp->fracvarsfrac != NULL);
5671
5672 if( fracvars != NULL )
5673 *fracvars = nlp->fracvars;
5674 if( fracvarssol != NULL )
5675 *fracvarssol = nlp->fracvarssol;
5676 if( fracvarsfrac != NULL )
5677 *fracvarsfrac = nlp->fracvarsfrac;
5678 if( nfracvars != NULL )
5679 *nfracvars = nlp->nfracvars;
5680 if( npriofracvars != NULL )
5681 *npriofracvars = nlp->npriofracvars;
5682
5683 return SCIP_OKAY;
5684 }
5685
5686 /** removes all redundant nonlinear rows */
SCIPnlpRemoveRedundantNlRows(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat)5687 SCIP_RETCODE SCIPnlpRemoveRedundantNlRows(
5688 SCIP_NLP* nlp, /**< current NLP data */
5689 BMS_BLKMEM* blkmem, /**< block memory buffers */
5690 SCIP_SET* set, /**< global SCIP settings */
5691 SCIP_STAT* stat /**< problem statistics */
5692 )
5693 {
5694 SCIP_NLPSOLSTAT solstatus;
5695 SCIP_Bool isredundant;
5696 int i;
5697
5698 assert(nlp != NULL);
5699 assert(blkmem != NULL);
5700 assert(set != NULL);
5701 assert(stat != NULL);
5702
5703 if( nlp->nnlrows == 0 )
5704 return SCIP_OKAY;
5705
5706 if( nlp->indiving )
5707 {
5708 SCIPerrorMessage("cannot remove redundant rows during NLP diving\n");
5709 return SCIP_ERROR;
5710 }
5711
5712 /* removing redundant rows should not change the solution status, so we reset it at the end */
5713 solstatus = nlp->solstat;
5714
5715 for( i = 0; i < nlp->nnlrows; ++i )
5716 {
5717 SCIP_CALL( SCIPnlrowIsRedundant(nlp->nlrows[i], set, stat, &isredundant) );
5718 if( isredundant )
5719 {
5720 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, i) );
5721 }
5722 }
5723
5724 nlp->solstat = solstatus;
5725
5726 return SCIP_OKAY;
5727 }
5728
5729 /** set initial guess (approximate primal solution) for next solve
5730 *
5731 * array initguess must be NULL or have length at least SCIPnlpGetNVars()
5732 */
SCIPnlpSetInitialGuess(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_Real * initguess)5733 SCIP_RETCODE SCIPnlpSetInitialGuess(
5734 SCIP_NLP* nlp, /**< current NLP data */
5735 BMS_BLKMEM* blkmem, /**< block memory buffers */
5736 SCIP_Real* initguess /**< new initial guess, or NULL to clear previous one */
5737 )
5738 {
5739 assert(nlp != NULL);
5740 assert(blkmem != NULL);
5741 assert(nlp->solver != NULL);
5742 assert(nlp->problem != NULL);
5743
5744 /* if user wants to let NLP solver choose start point, then invalidate current initial guess both in NLP and in NLPI */
5745 if( initguess == NULL )
5746 {
5747 nlp->haveinitguess = FALSE;
5748 SCIP_CALL( SCIPnlpiSetInitialGuess(nlp->solver, nlp->problem, NULL, NULL, NULL, NULL) );
5749 return SCIP_OKAY;
5750 }
5751
5752 if( nlp->initialguess != NULL )
5753 {
5754 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
5755 }
5756 else
5757 {
5758 assert( nlp->sizevars >= nlp->nvars );
5759 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars) );
5760 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
5761 }
5762 nlp->haveinitguess = TRUE;
5763
5764 return SCIP_OKAY;
5765 }
5766
5767 /** writes NLP to a file */
SCIPnlpWrite(SCIP_NLP * nlp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,const char * fname)5768 SCIP_RETCODE SCIPnlpWrite(
5769 SCIP_NLP* nlp, /**< current NLP data */
5770 SCIP_SET* set, /**< global SCIP settings */
5771 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5772 const char* fname /**< file name */
5773 )
5774 {
5775 FILE* file;
5776 int i;
5777
5778 assert(nlp != NULL);
5779
5780 if( fname != NULL )
5781 {
5782 file = fopen(fname, "w");
5783 if( file == NULL )
5784 {
5785 SCIPerrorMessage("could not open file <%s> for writing\n", fname);
5786 return SCIP_FILECREATEERROR;
5787 }
5788 }
5789 else
5790 file = stdout;
5791
5792 SCIPmessageFPrintInfo(messagehdlr, file, "STATISTICS\n");
5793 SCIPmessageFPrintInfo(messagehdlr, file, " NLP name: %s\n", nlp->name);
5794 SCIPmessageFPrintInfo(messagehdlr, file, " Variables: %d\n", nlp->nvars);
5795 SCIPmessageFPrintInfo(messagehdlr, file, " Rows: %d\n", nlp->nnlrows);
5796
5797 SCIPmessageFPrintInfo(messagehdlr, file, "VARIABLES\n");
5798 for( i = 0; i < nlp->nvars; ++i )
5799 {
5800 SCIP_CALL( SCIPvarPrint(nlp->vars[i], set, messagehdlr, file) );
5801 }
5802
5803 SCIPmessageFPrintInfo(messagehdlr, file, "NONLINEAR ROWS\n");
5804 for( i = 0; i < nlp->nnlrows; ++i )
5805 {
5806 SCIPmessageFPrintInfo(messagehdlr, file, " ");
5807 SCIP_CALL( SCIPnlrowPrint(nlp->nlrows[i], messagehdlr, file) );
5808 }
5809
5810 if( fname != NULL )
5811 {
5812 fclose(file);
5813 }
5814
5815 return SCIP_OKAY;
5816 }
5817
5818 /** gets array with variables of the NLP */
SCIPnlpGetVars(SCIP_NLP * nlp)5819 SCIP_VAR** SCIPnlpGetVars(
5820 SCIP_NLP* nlp /**< current NLP data */
5821 )
5822 {
5823 assert(nlp != NULL);
5824
5825 return nlp->vars;
5826 }
5827
5828 /** gets current number of variables in NLP */
SCIPnlpGetNVars(SCIP_NLP * nlp)5829 int SCIPnlpGetNVars(
5830 SCIP_NLP* nlp /**< current NLP data */
5831 )
5832 {
5833 assert(nlp != NULL);
5834
5835 return nlp->nvars;
5836 }
5837
5838 /** computes for each variables the number of NLP rows in which the variable appears in a nonlinear var */
SCIPnlpGetVarsNonlinearity(SCIP_NLP * nlp,int * nlcount)5839 SCIP_RETCODE SCIPnlpGetVarsNonlinearity(
5840 SCIP_NLP* nlp, /**< current NLP data */
5841 int* nlcount /**< an array of length at least SCIPnlpGetNVars() to store nonlinearity counts of variables */
5842 )
5843 {
5844 SCIP_NLROW* nlrow;
5845 int varidx;
5846 int i;
5847 int c;
5848
5849 assert(nlp != NULL);
5850 assert(nlcount != NULL || nlp->nvars == 0);
5851
5852 BMSclearMemoryArray(nlcount, nlp->nvars);
5853
5854 for( c = 0; c < nlp->nnlrows; ++c )
5855 {
5856 nlrow = nlp->nlrows[c];
5857 assert(nlrow != NULL);
5858
5859 for( i = 0; i < nlrow->nquadvars; ++i )
5860 {
5861 assert(SCIPhashmapExists(nlp->varhash, (void*)nlrow->quadvars[i]));
5862 varidx = SCIPhashmapGetImageInt(nlp->varhash, (void*)nlrow->quadvars[i]);
5863 assert(varidx < nlp->nvars);
5864 assert(nlcount != NULL);
5865 ++nlcount[varidx]; /*lint !e613 */
5866 }
5867
5868 if( nlrow->exprtree != NULL )
5869 {
5870 SCIP_VAR** exprtreevars;
5871 int nexprtreevars;
5872
5873 exprtreevars = SCIPexprtreeGetVars(nlrow->exprtree);
5874 nexprtreevars = SCIPexprtreeGetNVars(nlrow->exprtree);
5875 assert(exprtreevars != NULL || nexprtreevars == 0);
5876 for( i = 0; i < nexprtreevars; ++i )
5877 {
5878 assert(SCIPhashmapExists(nlp->varhash, (void*)exprtreevars[i])); /*lint !e613 */
5879
5880 /* skip variables that also appear in quadratic part, so they are not counted twice */
5881 if( nlrow->quadvarshash != NULL && SCIPhashmapExists(nlrow->quadvarshash, (void*)exprtreevars[i]) ) /*lint !e613 */
5882 continue;
5883
5884 varidx = SCIPhashmapGetImageInt(nlp->varhash, (void*)exprtreevars[i]); /*lint !e613 */
5885 assert(varidx < nlp->nvars);
5886 assert(nlcount != NULL);
5887 ++nlcount[varidx]; /*lint !e613 */
5888 }
5889 }
5890 }
5891
5892 return SCIP_OKAY;
5893 }
5894
5895
5896 /** indicates whether there exists a row that contains a continuous variable in a nonlinear term
5897 *
5898 * @note The method may have to touch every row and nonlinear term to compute its result.
5899 */
SCIPnlpHasContinuousNonlinearity(SCIP_NLP * nlp)5900 SCIP_Bool SCIPnlpHasContinuousNonlinearity(
5901 SCIP_NLP* nlp /**< current NLP data */
5902 )
5903 {
5904 SCIP_NLROW* nlrow;
5905 int c;
5906 int i;
5907
5908 assert(nlp != NULL);
5909
5910 for( c = 0; c < nlp->nnlrows; ++c )
5911 {
5912 nlrow = nlp->nlrows[c];
5913 assert(nlrow != NULL);
5914
5915 for( i = 0; i < nlrow->nquadvars; ++i )
5916 if( SCIPvarGetType(nlrow->quadvars[i]) == SCIP_VARTYPE_CONTINUOUS )
5917 return TRUE;
5918
5919 if( nlrow->exprtree != NULL )
5920 {
5921 SCIP_VAR** exprtreevars;
5922 int nexprtreevars;
5923
5924 exprtreevars = SCIPexprtreeGetVars(nlrow->exprtree);
5925 nexprtreevars = SCIPexprtreeGetNVars(nlrow->exprtree);
5926 assert(exprtreevars != NULL || nexprtreevars == 0);
5927
5928 for( i = 0; i < nexprtreevars; ++i )
5929 if( SCIPvarGetType(exprtreevars[i]) == SCIP_VARTYPE_CONTINUOUS ) /*lint !e613*/
5930 return TRUE;
5931 }
5932 }
5933
5934 return FALSE;
5935 }
5936
5937 /** gives dual solution values associated with lower bounds of NLP variables */
SCIPnlpGetVarsLbDualsol(SCIP_NLP * nlp)5938 SCIP_Real* SCIPnlpGetVarsLbDualsol(
5939 SCIP_NLP* nlp /**< current NLP data */
5940 )
5941 {
5942 assert(nlp != NULL);
5943
5944 return nlp->varlbdualvals;
5945 }
5946
5947 /** gives dual solution values associated with upper bounds of NLP variables */
SCIPnlpGetVarsUbDualsol(SCIP_NLP * nlp)5948 SCIP_Real* SCIPnlpGetVarsUbDualsol(
5949 SCIP_NLP* nlp /**< current NLP data */
5950 )
5951 {
5952 assert(nlp != NULL);
5953
5954 return nlp->varubdualvals;
5955 }
5956
5957 /** gets array with nonlinear rows of the NLP */
SCIPnlpGetNlRows(SCIP_NLP * nlp)5958 SCIP_NLROW** SCIPnlpGetNlRows(
5959 SCIP_NLP* nlp /**< current NLP data */
5960 )
5961 {
5962 assert(nlp != NULL);
5963
5964 return nlp->nlrows;
5965 }
5966
5967 /** gets current number of nonlinear rows in NLP */
SCIPnlpGetNNlRows(SCIP_NLP * nlp)5968 int SCIPnlpGetNNlRows(
5969 SCIP_NLP* nlp /**< current NLP data */
5970 )
5971 {
5972 assert(nlp != NULL);
5973
5974 return nlp->nnlrows;
5975 }
5976
5977 /** gets the NLP solver interface */
SCIPnlpGetNLPI(SCIP_NLP * nlp)5978 SCIP_NLPI* SCIPnlpGetNLPI(
5979 SCIP_NLP* nlp /**< current NLP data */
5980 )
5981 {
5982 assert(nlp != NULL);
5983
5984 return nlp->solver;
5985 }
5986
5987 /** gets the NLP problem in the solver interface */
SCIPnlpGetNLPIProblem(SCIP_NLP * nlp)5988 SCIP_NLPIPROBLEM* SCIPnlpGetNLPIProblem(
5989 SCIP_NLP* nlp /**< current NLP data */
5990 )
5991 {
5992 assert(nlp != NULL);
5993
5994 return nlp->problem;
5995 }
5996
5997 /** indicates whether NLP is currently in diving mode */
SCIPnlpIsDiving(SCIP_NLP * nlp)5998 SCIP_Bool SCIPnlpIsDiving(
5999 SCIP_NLP* nlp /**< current NLP data */
6000 )
6001 {
6002 assert(nlp != NULL);
6003
6004 return nlp->indiving;
6005 }
6006
6007 /** gets solution status of current NLP */
SCIPnlpGetSolstat(SCIP_NLP * nlp)6008 SCIP_NLPSOLSTAT SCIPnlpGetSolstat(
6009 SCIP_NLP* nlp /**< current NLP data */
6010 )
6011 {
6012 assert(nlp != NULL);
6013
6014 return nlp->solstat;
6015 }
6016
6017 /** gets termination status of last NLP solve */
SCIPnlpGetTermstat(SCIP_NLP * nlp)6018 SCIP_NLPTERMSTAT SCIPnlpGetTermstat(
6019 SCIP_NLP* nlp /**< current NLP data */
6020 )
6021 {
6022 assert(nlp != NULL);
6023
6024 return nlp->termstat;
6025 }
6026
6027 /** gives statistics (number of iterations, solving time, ...) of last NLP solve */
SCIPnlpGetStatistics(SCIP_NLP * nlp,SCIP_NLPSTATISTICS * statistics)6028 SCIP_RETCODE SCIPnlpGetStatistics(
6029 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6030 SCIP_NLPSTATISTICS* statistics /**< pointer to store statistics */
6031 )
6032 {
6033 assert(nlp != NULL);
6034 assert(nlp->solver != NULL);
6035 assert(nlp->problem != NULL);
6036 assert(statistics != NULL);
6037
6038 SCIP_CALL( SCIPnlpiGetStatistics(nlp->solver, nlp->problem, statistics) );
6039
6040 return SCIP_OKAY;
6041 }
6042
6043 /** indicates whether a feasible solution for the current NLP is available
6044 * thus, returns whether the solution status <= feasible */
SCIPnlpHasSolution(SCIP_NLP * nlp)6045 SCIP_Bool SCIPnlpHasSolution(
6046 SCIP_NLP* nlp /**< current NLP data */
6047 )
6048 {
6049 assert(nlp != NULL);
6050
6051 return nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE;
6052 }
6053
6054 /** gets integer parameter of NLP */
SCIPnlpGetIntPar(SCIP_NLP * nlp,SCIP_NLPPARAM type,int * ival)6055 SCIP_RETCODE SCIPnlpGetIntPar(
6056 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6057 SCIP_NLPPARAM type, /**< parameter number */
6058 int* ival /**< pointer to store the parameter value */
6059 )
6060 {
6061 assert(nlp != NULL);
6062 assert(nlp->solver != NULL);
6063 assert(nlp->problem != NULL);
6064 assert(ival != NULL);
6065
6066 SCIP_CALL( SCIPnlpiGetIntPar(nlp->solver, nlp->problem, type, ival) );
6067
6068 return SCIP_OKAY;
6069 }
6070
6071 /** sets integer parameter of NLP */
SCIPnlpSetIntPar(SCIP_NLP * nlp,SCIP_NLPPARAM type,int ival)6072 SCIP_RETCODE SCIPnlpSetIntPar(
6073 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6074 SCIP_NLPPARAM type, /**< parameter number */
6075 int ival /**< parameter value */
6076 )
6077 {
6078 assert(nlp != NULL);
6079 assert(nlp->solver != NULL);
6080 assert(nlp->problem != NULL);
6081
6082 SCIP_CALL( SCIPnlpiSetIntPar(nlp->solver, nlp->problem, type, ival) );
6083
6084 return SCIP_OKAY;
6085 }
6086
6087 /** gets floating point parameter of NLP */
SCIPnlpGetRealPar(SCIP_NLP * nlp,SCIP_NLPPARAM type,SCIP_Real * dval)6088 SCIP_RETCODE SCIPnlpGetRealPar(
6089 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6090 SCIP_NLPPARAM type, /**< parameter number */
6091 SCIP_Real* dval /**< pointer to store the parameter value */
6092 )
6093 {
6094 assert(nlp != NULL);
6095 assert(nlp->solver != NULL);
6096 assert(nlp->problem != NULL);
6097 assert(dval != NULL);
6098
6099 SCIP_CALL( SCIPnlpiGetRealPar(nlp->solver, nlp->problem, type, dval) );
6100
6101 return SCIP_OKAY;
6102 }
6103
6104 /** sets floating point parameter of NLP */
SCIPnlpSetRealPar(SCIP_NLP * nlp,SCIP_NLPPARAM type,SCIP_Real dval)6105 SCIP_RETCODE SCIPnlpSetRealPar(
6106 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6107 SCIP_NLPPARAM type, /**< parameter number */
6108 SCIP_Real dval /**< parameter value */
6109 )
6110 {
6111 assert(nlp != NULL);
6112 assert(nlp->solver != NULL);
6113 assert(nlp->problem != NULL);
6114
6115 SCIP_CALL( SCIPnlpiSetRealPar(nlp->solver, nlp->problem, type, dval) );
6116
6117 return SCIP_OKAY;
6118 }
6119
6120 /** gets string parameter of NLP */
SCIPnlpGetStringPar(SCIP_NLP * nlp,SCIP_NLPPARAM type,const char ** sval)6121 SCIP_RETCODE SCIPnlpGetStringPar(
6122 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6123 SCIP_NLPPARAM type, /**< parameter number */
6124 const char** sval /**< pointer to store the parameter value */
6125 )
6126 {
6127 assert(nlp != NULL);
6128 assert(nlp->solver != NULL);
6129 assert(nlp->problem != NULL);
6130 assert(sval != NULL);
6131
6132 SCIP_CALL( SCIPnlpiGetStringPar(nlp->solver, nlp->problem, type, sval) );
6133
6134 return SCIP_OKAY;
6135 }
6136
6137 /** sets string parameter of NLP */
SCIPnlpSetStringPar(SCIP_NLP * nlp,SCIP_NLPPARAM type,const char * sval)6138 SCIP_RETCODE SCIPnlpSetStringPar(
6139 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
6140 SCIP_NLPPARAM type, /**< parameter number */
6141 const char* sval /**< parameter value */
6142 )
6143 {
6144 assert(nlp != NULL);
6145 assert(nlp->solver != NULL);
6146 assert(nlp->problem != NULL);
6147
6148 SCIP_CALL( SCIPnlpiSetStringPar(nlp->solver, nlp->problem, type, sval) );
6149
6150 return SCIP_OKAY;
6151 }
6152
6153 /*
6154 * NLP diving methods
6155 */
6156
6157 /** signals start of diving */
SCIPnlpStartDive(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)6158 SCIP_RETCODE SCIPnlpStartDive(
6159 SCIP_NLP* nlp, /**< current NLP data */
6160 BMS_BLKMEM* blkmem, /**< block memory buffers */
6161 SCIP_SET* set /**< global SCIP settings */
6162 )
6163 {
6164 assert(nlp != NULL);
6165
6166 if( nlp->indiving )
6167 {
6168 SCIPerrorMessage("NLP is already in diving mode\n");
6169 return SCIP_ERROR;
6170 }
6171
6172 if( nlp->solver == NULL )
6173 {
6174 /* In diving mode we do not cache changes but put them directly in the NLPI problem, which does not exist if there is no solver.
6175 * So we forbid diving of no solver is available. */
6176 SCIPerrorMessage("Cannot start diving if no NLP solver is available\n");
6177 return SCIP_ERROR;
6178 }
6179
6180 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set) );
6181
6182 nlp->indiving = TRUE;
6183
6184 return SCIP_OKAY;
6185 }
6186
6187 /** resets the bound and objective changes made during diving and disables diving mode */
SCIPnlpEndDive(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set)6188 SCIP_RETCODE SCIPnlpEndDive(
6189 SCIP_NLP* nlp, /**< current NLP data */
6190 BMS_BLKMEM* blkmem, /**< block memory */
6191 SCIP_SET* set /**< global SCIP settings */
6192 )
6193 {
6194 int i;
6195 int* varidx;
6196 SCIP_Real* varlb;
6197 SCIP_Real* varub;
6198
6199 assert(nlp != NULL);
6200 assert(set != NULL);
6201 assert(nlp->nvars == nlp->nvars_solver);
6202
6203 if( !nlp->indiving )
6204 {
6205 SCIPerrorMessage("NLP not in diving mode, cannot end dive\n");
6206 return SCIP_ERROR;
6207 }
6208
6209 assert(nlp->solver != NULL);
6210 assert(nlp->problem != NULL);
6211
6212 /* reset variable bounds in NLPI problem to their current values */
6213 SCIP_CALL( SCIPsetAllocBufferArray(set, &varidx, nlp->nvars) );
6214 SCIP_CALL( SCIPsetAllocBufferArray(set, &varlb, nlp->nvars) );
6215 SCIP_CALL( SCIPsetAllocBufferArray(set, &varub, nlp->nvars) );
6216 for( i = 0; i < nlp->nvars; ++i )
6217 {
6218 varidx[i] = i;
6219 varlb[i] = SCIPvarGetLbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
6220 varub[i] = SCIPvarGetUbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
6221 }
6222
6223 SCIP_CALL( SCIPnlpiChgVarBounds(nlp->solver, nlp->problem, nlp->nvars, varidx, varlb, varub) );
6224
6225 SCIPsetFreeBufferArray(set, &varidx);
6226 SCIPsetFreeBufferArray(set, &varlb);
6227 SCIPsetFreeBufferArray(set, &varub);
6228
6229 /* clear diving objective, if one was used (i.e., if SCIPnlpChgVarObjDive had been called)
6230 * the objective in the NLPI will be reset in the next flush */
6231 if( nlp->divingobj != NULL )
6232 {
6233 SCIP_CALL( SCIPnlrowRelease(&nlp->divingobj, blkmem, set) );
6234 assert(nlp->divingobj == NULL);
6235 assert(nlp->objflushed == FALSE);
6236 }
6237
6238 /* we do not have a valid solution anymore */
6239 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
6240 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
6241 nlp->primalsolobjval = SCIP_INVALID;
6242
6243 nlp->indiving = FALSE;
6244
6245 return SCIP_OKAY;
6246 }
6247
6248 /** changes coefficient of variable in diving NLP */
SCIPnlpChgVarObjDive(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_Real coef)6249 SCIP_RETCODE SCIPnlpChgVarObjDive(
6250 SCIP_NLP* nlp, /**< current NLP data */
6251 BMS_BLKMEM* blkmem, /**< block memory */
6252 SCIP_SET* set, /**< global SCIP settings */
6253 SCIP_STAT* stat, /**< problem statistics data */
6254 SCIP_VAR* var, /**< variable which coefficient to change */
6255 SCIP_Real coef /**< new linear coefficient of variable in objective */
6256 )
6257 {
6258 int pos;
6259 int objidx;
6260
6261 assert(nlp != NULL);
6262 assert(var != NULL);
6263 assert(SCIPhashmapExists(nlp->varhash, var));
6264 assert(nlp->indiving);
6265 assert(nlp->solver != NULL);
6266 assert(nlp->problem != NULL);
6267
6268 /* get position of variable in NLPI problem */
6269 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
6270 pos = nlp->varmap_nlp2nlpi[pos];
6271 assert(pos >= 0);
6272
6273 /* set coefficient in NLPI problem objective */
6274 objidx = -1;
6275 SCIP_CALL( SCIPnlpiChgLinearCoefs(nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
6276
6277 /* create an nlrow that holds the diving objective, if not done yet */
6278 if( nlp->divingobj == NULL )
6279 {
6280 SCIP_Real* coefs;
6281 int i;
6282
6283 SCIP_CALL( SCIPsetAllocBufferArray(set, &coefs, nlp->nvars) );
6284 for( i = 0; i < nlp->nvars; ++i )
6285 coefs[i] = SCIPvarGetObj(nlp->vars[i]);
6286
6287 SCIP_CALL( SCIPnlrowCreate(&nlp->divingobj, blkmem, set, "divingobj",
6288 0.0,
6289 nlp->nvars, nlp->vars, coefs,
6290 0, NULL, 0, NULL,
6291 NULL,
6292 -SCIPsetInfinity(set), SCIPsetInfinity(set),
6293 SCIP_EXPRCURV_LINEAR) );
6294
6295 SCIPsetFreeBufferArray(set, &coefs);
6296 }
6297 assert(nlp->divingobj != NULL);
6298
6299 /* modify coefficient in diving objective */
6300 SCIP_CALL( SCIPnlrowChgLinearCoef(nlp->divingobj, blkmem, set, stat, nlp, var, coef) );
6301
6302 /* remember that we have to store objective after diving ended */
6303 nlp->objflushed = FALSE;
6304
6305 return SCIP_OKAY;
6306 }
6307
6308 /** changes bounds of variable in diving NLP */
SCIPnlpChgVarBoundsDive(SCIP_NLP * nlp,SCIP_VAR * var,SCIP_Real lb,SCIP_Real ub)6309 SCIP_RETCODE SCIPnlpChgVarBoundsDive(
6310 SCIP_NLP* nlp, /**< current NLP data */
6311 SCIP_VAR* var, /**< variable which coefficient to change */
6312 SCIP_Real lb, /**< new lower bound of variable */
6313 SCIP_Real ub /**< new upper bound of variable */
6314 )
6315 {
6316 int pos;
6317
6318 assert(nlp != NULL);
6319 assert(var != NULL);
6320 assert(SCIPhashmapExists(nlp->varhash, var));
6321 assert(nlp->indiving);
6322 assert(nlp->solver != NULL);
6323 assert(nlp->problem != NULL);
6324
6325 /* get position of variable in NLPI problem */
6326 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
6327 pos = nlp->varmap_nlp2nlpi[pos];
6328 assert(pos >= 0);
6329
6330 /* set new bounds in NLPI */
6331 SCIP_CALL( SCIPnlpiChgVarBounds(nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
6332
6333 return SCIP_OKAY;
6334 }
6335
6336 /** changes bounds of a set of variables in diving NLP */
SCIPnlpChgVarsBoundsDive(SCIP_NLP * nlp,SCIP_SET * set,int nvars,SCIP_VAR ** vars,SCIP_Real * lbs,SCIP_Real * ubs)6337 SCIP_RETCODE SCIPnlpChgVarsBoundsDive(
6338 SCIP_NLP* nlp, /**< current NLP data */
6339 SCIP_SET* set, /**< global SCIP settings */
6340 int nvars, /**< number of variables which bounds to change */
6341 SCIP_VAR** vars, /**< variables which bounds to change */
6342 SCIP_Real* lbs, /**< new lower bounds of variables */
6343 SCIP_Real* ubs /**< new upper bounds of variables */
6344 )
6345 {
6346 int i;
6347 int* poss;
6348
6349 assert(nlp != NULL);
6350 assert(vars != NULL || nvars == 0);
6351 assert(nlp->indiving);
6352 assert(lbs != NULL || nvars == 0);
6353 assert(ubs != NULL || nvars == 0);
6354 assert(nlp->solver != NULL);
6355 assert(nlp->problem != NULL);
6356
6357 if( nvars == 0 )
6358 return SCIP_OKAY;
6359
6360 SCIP_CALL( SCIPsetAllocBufferArray(set, &poss, nvars) );
6361
6362 for( i = 0; i < nvars; ++i )
6363 {
6364 assert(SCIPhashmapExists(nlp->varhash, vars[i])); /*lint !e613*/
6365
6366 /* get position of variable in NLPI problem */
6367 poss[i] = SCIPhashmapGetImageInt(nlp->varhash, vars[i]); /*lint !e613*/
6368 poss[i] = nlp->varmap_nlp2nlpi[poss[i]];
6369 assert(poss[i] >= 0);
6370 }
6371
6372 /* set new bounds in NLPI */
6373 SCIP_CALL( SCIPnlpiChgVarBounds(nlp->solver, nlp->problem, nvars, poss, lbs, ubs) );
6374
6375 SCIPsetFreeBufferArray(set, &poss);
6376
6377 return SCIP_OKAY;
6378 }
6379
6380 /** returns whether the objective function has been changed during diving */
SCIPnlpIsDivingObjChanged(SCIP_NLP * nlp)6381 SCIP_Bool SCIPnlpIsDivingObjChanged(
6382 SCIP_NLP* nlp /**< current NLP data */
6383 )
6384 {
6385 return nlp->divingobj != NULL;
6386 }
6387
6388 /** solves diving NLP */
SCIPnlpSolveDive(SCIP_NLP * nlp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat)6389 SCIP_RETCODE SCIPnlpSolveDive(
6390 SCIP_NLP* nlp, /**< current NLP data */
6391 BMS_BLKMEM* blkmem, /**< block memory buffers */
6392 SCIP_SET* set, /**< global SCIP settings */
6393 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
6394 SCIP_STAT* stat /**< problem statistics */
6395 )
6396 {
6397 SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat) );
6398
6399 return SCIP_OKAY;
6400 }
6401
6402