1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2022 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
19 * @author Thorsten Gellermann
20 * @author Stefan Vigerske
21 *
22 * In NLP management, we have to distinguish 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 SCIPnlpFlush().
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 "scip/nlpi.h"
34 #include "scip/pub_expr.h"
35 #include "scip/expr.h"
36 #include "scip/expr_varidx.h"
37 #include "scip/clock.h"
38 #include "scip/event.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 and mapvar2varidx */
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 /*lint -e440*/
66 /*lint -e441*/
67 /*lint -e777*/
68
69 #ifdef __cplusplus
70 extern "C" {
71 #endif
72
73 /* avoid inclusion of scip.h */ /*lint -e{2701}*/
74 BMS_BLKMEM* SCIPblkmem(
75 SCIP* scip /**< SCIP data structure */
76 );
77
78 #ifdef __cplusplus
79 }
80 #endif
81
82 /*
83 * forward declarations
84 */
85
86 /** NLP event handler execution method */
87 static
88 SCIP_DECL_EVENTEXEC( eventExecNlp );
89
90 /** announces, that a row of the NLP was modified
91 *
92 * adjusts status of current solution;
93 * calling method has to ensure that change is passed on to the NLPI!
94 */
95 static
96 SCIP_RETCODE nlpRowChanged(
97 SCIP_NLP* nlp, /**< current NLP data */
98 SCIP_SET* set, /**< global SCIP settings */
99 SCIP_STAT* stat, /**< problem statistics data */
100 SCIP_NLROW* nlrow /**< nonlinear row which was changed */
101 );
102
103 /*
104 * private NLP nonlinear row methods
105 */
106
107 /** announces, that the given linear coefficient in the constraint matrix changed */
108 static
109 SCIP_RETCODE nlrowLinearCoefChanged(
110 SCIP_NLROW* nlrow, /**< nonlinear row */
111 SCIP_SET* set, /**< global SCIP settings */
112 SCIP_STAT* stat, /**< problem statistics data */
113 SCIP_VAR* var, /**< variable which coefficient changed */
114 SCIP_Real coef, /**< new coefficient of variable, 0.0 if deleted */
115 SCIP_NLP* nlp /**< current NLP data */
116 )
117 {
118 assert(nlrow != NULL);
119 assert(var != NULL);
120
121 nlrow->activity = SCIP_INVALID;
122 nlrow->validactivitynlp = -1;
123 nlrow->pseudoactivity = SCIP_INVALID;
124 nlrow->validpsactivitydomchg = -1;
125 nlrow->minactivity = SCIP_INVALID;
126 nlrow->maxactivity = SCIP_INVALID;
127 nlrow->validactivitybdsdomchg = -1;
128
129 if( nlrow->nlpindex >= 0 )
130 {
131 assert(nlp != NULL);
132
133 /* notify NLP that row has changed */
134 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
135
136 /* update NLPI problem, if row is in NLPI already */
137 if( nlrow->nlpiindex >= 0 )
138 {
139 int idx;
140
141 /* get index of variable in NLPI */
142 assert(SCIPhashmapExists(nlp->varhash, var));
143 idx = SCIPhashmapGetImageInt(nlp->varhash, var);
144 assert(idx >= 0 && idx < nlp->nvars);
145
146 idx = nlp->varmap_nlp2nlpi[idx];
147 assert(idx >= 0 && idx < nlp->nvars_solver);
148
149 /* change coefficient in NLPI problem */
150 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, nlrow->nlpiindex, 1, &idx, &coef) );
151 }
152 }
153
154 return SCIP_OKAY;
155 }
156
157 /** create varidx expression for var expression
158 *
159 * called when expr is duplicated for addition to NLPI
160 */
161 static
162 SCIP_DECL_EXPR_MAPEXPR(mapvar2varidx)
163 {
164 SCIP_NLP* nlp;
165 int nlpidx;
166
167 assert(sourcescip != NULL);
168 assert(sourcescip == targetscip);
169 assert(sourceexpr != NULL);
170 assert(targetexpr != NULL);
171 assert(*targetexpr == NULL);
172 assert(mapexprdata != NULL);
173
174 nlp = (SCIP_NLP*)mapexprdata;
175
176 /* do not provide map if not variable */
177 if( !SCIPexprIsVar(sourcescip->set, sourceexpr) )
178 return SCIP_OKAY;
179
180 assert(SCIPvarIsActive(SCIPgetVarExprVar(sourceexpr))); /* because we simplified exprs */
181
182 assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(sourceexpr)));
183 nlpidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(sourceexpr));
184 assert(nlpidx < nlp->nvars);
185
186 assert(nlp->varmap_nlp2nlpi[nlpidx] >= 0);
187 assert(nlp->varmap_nlp2nlpi[nlpidx] < nlp->nvars_solver);
188 SCIP_CALL( SCIPcreateExprVaridx(targetscip, targetexpr, nlp->varmap_nlp2nlpi[nlpidx], ownercreate, ownercreatedata) );
189
190 return SCIP_OKAY;
191 }
192
193 /** announces, that an expression changed */
194 static
195 SCIP_RETCODE nlrowExprChanged(
196 SCIP_NLROW* nlrow, /**< nonlinear row */
197 BMS_BLKMEM* blkmem, /**< block memory */
198 SCIP_SET* set, /**< global SCIP settings */
199 SCIP_STAT* stat, /**< problem statistics data */
200 SCIP_NLP* nlp /**< current NLP data */
201 )
202 {
203 assert(nlrow != NULL);
204
205 nlrow->activity = SCIP_INVALID;
206 nlrow->validactivitynlp = -1;
207 nlrow->pseudoactivity = SCIP_INVALID;
208 nlrow->validpsactivitydomchg = -1;
209 nlrow->minactivity = SCIP_INVALID;
210 nlrow->maxactivity = SCIP_INVALID;
211 nlrow->validactivitybdsdomchg = -1;
212
213 if( nlrow->nlpindex >= 0 )
214 {
215 assert(nlp != NULL);
216
217 /* notify NLP that row has changed */
218 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
219
220 if( nlrow->nlpiindex >= 0 )
221 {
222 /* change expression tree in NLPI problem */
223 SCIP_EXPR* nlpiexpr;
224
225 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &nlpiexpr, mapvar2varidx, (void*)nlp, NULL, NULL) );
226 SCIP_CALL( SCIPnlpiChgExpr(set, nlp->solver, nlp->problem, nlrow->nlpiindex, nlpiexpr) );
227 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlpiexpr) );
228 }
229 }
230
231 return SCIP_OKAY;
232 }
233
234 /** notifies nonlinear row, that its sides were changed */
235 static
236 SCIP_RETCODE nlrowSideChanged(
237 SCIP_NLROW* nlrow, /**< nonlinear row */
238 SCIP_SET* set, /**< global SCIP settings */
239 SCIP_STAT* stat, /**< problem statistics data */
240 SCIP_NLP* nlp /**< current NLP data */
241 )
242 {
243 assert(nlrow != NULL);
244
245 if( nlrow->nlpindex >= 0 )
246 {
247 assert(nlp != NULL);
248
249 /* notify NLP that row has changed */
250 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
251
252 if( nlrow->nlpiindex >= 0 )
253 {
254 SCIP_Real lhs;
255 SCIP_Real rhs;
256
257 /* change sides in NLPI problem */
258 lhs = nlrow->lhs;
259 rhs = nlrow->rhs;
260 if( !SCIPsetIsInfinity(set, -lhs) )
261 lhs -= nlrow->constant;
262 if( !SCIPsetIsInfinity(set, rhs) )
263 rhs -= nlrow->constant;
264
265 SCIP_CALL( SCIPnlpiChgConsSides(set, nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) );
266 }
267 }
268
269 return SCIP_OKAY;
270 }
271
272 /** notifies nonlinear row, that its constant was changed */
273 static
274 SCIP_RETCODE nlrowConstantChanged(
275 SCIP_NLROW* nlrow, /**< nonlinear row */
276 SCIP_SET* set, /**< global SCIP settings */
277 SCIP_STAT* stat, /**< problem statistics data */
278 SCIP_NLP* nlp /**< current NLP data */
279 )
280 {
281 assert(nlrow != NULL);
282
283 nlrow->activity = SCIP_INVALID;
284 nlrow->validactivitynlp = -1;
285 nlrow->pseudoactivity = SCIP_INVALID;
286 nlrow->validpsactivitydomchg = -1;
287 nlrow->minactivity = SCIP_INVALID;
288 nlrow->maxactivity = SCIP_INVALID;
289 nlrow->validactivitybdsdomchg = -1;
290
291 if( nlrow->nlpindex >= 0 )
292 {
293 assert(nlp != NULL);
294
295 /* notify NLP that row has changed */
296 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
297
298 if( nlrow->nlpiindex >= 0 )
299 {
300 SCIP_Real lhs;
301 SCIP_Real rhs;
302
303 lhs = nlrow->lhs;
304 rhs = nlrow->rhs;
305 if( !SCIPsetIsInfinity(set, -lhs) )
306 lhs -= nlrow->constant;
307 if( !SCIPsetIsInfinity(set, rhs) )
308 rhs -= nlrow->constant;
309
310 /* change sides in NLPI problem */
311 SCIP_CALL( SCIPnlpiChgConsSides(set, nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) );
312 }
313 }
314
315 return SCIP_OKAY;
316 }
317
318 /** sorts linear part of row entries such that lower variable indices precede higher ones */
319 static
320 void nlrowSortLinear(
321 SCIP_NLROW* nlrow /**< nonlinear row to be sorted */
322 )
323 {
324 assert(nlrow != NULL);
325
326 /* check, if row is already sorted in the LP part, or if the sorting should be delayed */
327 if( nlrow->linvarssorted )
328 return;
329
330 /* sort linear coefficients */
331 SCIPsortPtrReal((void**)nlrow->linvars, nlrow->lincoefs, SCIPvarComp, nlrow->nlinvars);
332
333 nlrow->linvarssorted = TRUE;
334 }
335
336 /** searches linear variable in nonlinear row, returns position in linvars vector or -1 if not found */
337 static
338 int nlrowSearchLinearCoef(
339 SCIP_NLROW* nlrow, /**< nonlinear row to be searched in */
340 SCIP_VAR* var /**< variable to be searched for */
341 )
342 {
343 int pos;
344
345 assert(nlrow != NULL);
346 assert(var != NULL);
347
348 if( nlrow->nlinvars == 0 )
349 return -1;
350
351 nlrowSortLinear(nlrow);
352 if( !SCIPsortedvecFindPtr((void**)nlrow->linvars, SCIPvarComp, (void*)var, nlrow->nlinvars, &pos) )
353 return -1;
354
355 return pos;
356 }
357
358 /** moves a coefficient in a nonlinear row to a different place, and updates all corresponding data structures */
359 static
360 void nlrowMoveLinearCoef(
361 SCIP_NLROW* nlrow, /**< NLP row */
362 int oldpos, /**< old position of coefficient */
363 int newpos /**< new position of coefficient */
364 )
365 {
366 assert(nlrow != NULL);
367 assert(0 <= oldpos && oldpos < nlrow->nlinvars);
368 assert(0 <= newpos && newpos < nlrow->nlinvars);
369 assert(nlrow->linvars[oldpos] != NULL);
370
371 if( oldpos == newpos )
372 return;
373
374 nlrow->linvars[newpos] = nlrow->linvars[oldpos];
375 nlrow->lincoefs[newpos] = nlrow->lincoefs[oldpos];
376
377 /* update sorted flags */
378 nlrow->linvarssorted = FALSE;
379 }
380
381 /** adds a previously non existing linear coefficient to a nonlinear row */
382 static
383 SCIP_RETCODE nlrowAddLinearCoef(
384 SCIP_NLROW* nlrow, /**< nonlinear row */
385 BMS_BLKMEM* blkmem, /**< block memory */
386 SCIP_SET* set, /**< global SCIP settings */
387 SCIP_STAT* stat, /**< problem statistics data */
388 SCIP_NLP* nlp, /**< current NLP data */
389 SCIP_VAR* var, /**< variable */
390 SCIP_Real coef /**< value of coefficient */
391 )
392 {
393 int pos;
394
395 assert(nlrow != NULL);
396 assert(blkmem != NULL);
397 assert(var != NULL);
398 assert(coef != 0.0);
399
400 /* assert that only active variables are added once the row is in the NLP */
401 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
402
403 SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars+1) );
404 assert(nlrow->linvars != NULL);
405 assert(nlrow->lincoefs != NULL);
406
407 pos = nlrow->nlinvars;
408 nlrow->nlinvars++;
409
410 /* insert the variable */
411 nlrow->linvars [pos] = var;
412 nlrow->lincoefs[pos] = coef;
413
414 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, coef, nlp) );
415
416 /* update sorted flag */
417 if( pos > 0 && SCIPvarCompare(nlrow->linvars[pos-1], nlrow->linvars[pos]) > 0 )
418 nlrow->linvarssorted = FALSE;
419
420 SCIPsetDebugMsg(set, "added linear coefficient %g * <%s> at position %d to nonlinear row <%s>\n",
421 coef, SCIPvarGetName(var), pos, nlrow->name);
422
423 return SCIP_OKAY;
424 }
425
426 #ifdef SCIP_DISABLED_CODE
427 /** adds a linear coefficient to a nonlinear row
428 * if the variable exists in the linear part of the row already, the coefficients are added
429 * otherwise the variable is added to the row */
430 static
431 SCIP_RETCODE nlrowAddToLinearCoef(
432 SCIP_NLROW* nlrow, /**< nonlinear row */
433 BMS_BLKMEM* blkmem, /**< block memory */
434 SCIP_SET* set, /**< global SCIP settings */
435 SCIP_STAT* stat, /**< problem statistics data */
436 SCIP_NLP* nlp, /**< current NLP data */
437 SCIP_VAR* var, /**< variable */
438 SCIP_Real coef, /**< value of coefficient */
439 SCIP_Bool removefixed /**< whether to disaggregate var before adding */
440 )
441 {
442 int pos;
443
444 assert(nlrow != NULL);
445 assert(blkmem != NULL);
446 assert(var != NULL);
447
448 if( removefixed && !SCIPvarIsActive(var) )
449 {
450 SCIP_Real constant;
451
452 constant = 0.0;
453 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &coef, &constant) );
454 if( constant != 0.0 )
455 {
456 nlrow->constant += constant;
457 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
458 }
459
460 if( SCIPsetIsZero(set, coef) )
461 return SCIP_OKAY;
462
463 if( !SCIPvarIsActive(var) )
464 {
465 int j;
466
467 /* if var is still not active, then it is multi-aggregated */
468 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
469
470 if( SCIPvarGetMultaggrConstant(var) != 0.0 )
471 {
472 nlrow->constant += coef * SCIPvarGetMultaggrConstant(var);
473 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
474 }
475
476 for( j = 0; j < SCIPvarGetMultaggrNVars(var); ++j )
477 {
478 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[j], SCIPvarGetMultaggrScalars(var)[j] * coef, TRUE) );
479 }
480
481 return SCIP_OKAY;
482 }
483 }
484 else if( SCIPsetIsZero(set, coef) )
485 return SCIP_OKAY;
486
487 assert(!removefixed || SCIPvarIsActive(var));
488
489 pos = nlrowSearchLinearCoef(nlrow, var);
490
491 if( pos == -1 )
492 {
493 /* add as new coefficient */
494 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) );
495 }
496 else
497 {
498 assert(pos >= 0);
499 assert(pos < nlrow->nlinvars);
500 assert(nlrow->linvars[pos] == var);
501
502 /* add to previously existing coefficient */
503 nlrow->lincoefs[pos] += coef;
504 }
505
506 return SCIP_OKAY;
507 }
508 #endif
509
510 /** deletes coefficient at given position from row */
511 static
512 SCIP_RETCODE nlrowDelLinearCoefPos(
513 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */
514 SCIP_SET* set, /**< global SCIP settings */
515 SCIP_STAT* stat, /**< problem statistics data */
516 SCIP_NLP* nlp, /**< current NLP data */
517 int pos /**< position in row vector to delete */
518 )
519 {
520 SCIP_VAR* var;
521
522 assert(nlrow != NULL);
523 assert(set != NULL);
524 assert(0 <= pos && pos < nlrow->nlinvars);
525 assert(nlrow->linvars[pos] != NULL);
526
527 var = nlrow->linvars[pos];
528
529 /* move last coefficient to position of empty slot (should set sorted flag to FALSE, if not last variable was deleted) */
530 nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos);
531 nlrow->nlinvars--;
532 assert(pos == nlrow->nlinvars || nlrow->linvarssorted == FALSE);
533
534 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) );
535
536 return SCIP_OKAY;
537 }
538
539 /** changes a coefficient at given position of a nonlinear row */
540 static
541 SCIP_RETCODE nlrowChgLinearCoefPos(
542 SCIP_NLROW* nlrow, /**< NLP row */
543 SCIP_SET* set, /**< global SCIP settings */
544 SCIP_STAT* stat, /**< problem statistics data */
545 SCIP_NLP* nlp, /**< current NLP data */
546 int pos, /**< position in row vector to change */
547 SCIP_Real coef /**< new value of coefficient */
548 )
549 {
550 assert(nlrow != NULL);
551 assert(0 <= pos && pos < nlrow->nlinvars);
552 assert(nlrow->linvars != NULL);
553 assert(nlrow->linvars[pos] != NULL);
554
555 if( SCIPsetIsZero(set, coef) )
556 {
557 /* delete existing coefficient */
558 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
559 }
560 else if( !SCIPsetIsEQ(set, nlrow->lincoefs[pos], coef) )
561 {
562 /* change existing coefficient */
563 nlrow->lincoefs[pos] = coef;
564 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], coef, nlp) );
565 }
566
567 return SCIP_OKAY;
568 }
569
570 /** calculates minimal and maximal activity of row w.r.t. the variable's bounds */
571 static
572 SCIP_RETCODE nlrowCalcActivityBounds(
573 SCIP_NLROW* nlrow, /**< nonlinear row */
574 BMS_BLKMEM* blkmem, /**< block memory */
575 SCIP_SET* set, /**< global SCIP settings */
576 SCIP_STAT* stat /**< problem statistics data */
577 )
578 {
579 SCIP_Real inf;
580 SCIP_INTERVAL activity;
581 SCIP_INTERVAL bounds;
582 int i;
583
584 assert(nlrow != NULL);
585 assert(set != NULL);
586 assert(stat != NULL);
587
588 inf = SCIPsetInfinity(set);
589
590 /* calculate activity bounds */
591 SCIPintervalSet(&activity, nlrow->constant);
592 for( i = 0; i < nlrow->nlinvars && !SCIPintervalIsEntire(inf, activity); ++i )
593 {
594 SCIPintervalSetBounds(&bounds, SCIPvarGetLbLocal(nlrow->linvars[i]), SCIPvarGetUbLocal(nlrow->linvars[i]));
595 SCIPintervalMulScalar(inf, &bounds, bounds, nlrow->lincoefs[i]);
596 SCIPintervalAdd(inf, &activity, activity, bounds);
597 }
598
599 if( nlrow->expr != NULL && !SCIPintervalIsEntire(inf, activity) )
600 {
601 SCIP_CALL( SCIPexprEvalActivity(set, stat, blkmem, nlrow->expr) );
602 SCIPintervalAdd(inf, &activity, activity, SCIPexprGetActivity(nlrow->expr));
603 }
604
605 nlrow->minactivity = SCIPintervalGetInf(activity);
606 nlrow->maxactivity = SCIPintervalGetSup(activity);
607
608 nlrow->validactivitybdsdomchg = stat->domchgcount;
609
610 return SCIP_OKAY;
611 }
612
613 /** makes sure that there is no fixed variable at position pos of the linear part of a nonlinear row
614 *
615 * a fixed variable is replaced with the corresponding constant or disaggregated term
616 */
617 static
618 SCIP_RETCODE nlrowRemoveFixedLinearCoefPos(
619 SCIP_NLROW* nlrow, /**< nonlinear row */
620 BMS_BLKMEM* blkmem, /**< block memory */
621 SCIP_SET* set, /**< global SCIP settings */
622 SCIP_STAT* stat, /**< problem statistics data */
623 SCIP_NLP* nlp, /**< current NLP data */
624 int pos /**< position of variable in linear variables array */
625 )
626 {
627 SCIP_Real oldconstant;
628 SCIP_VAR* var;
629
630 assert(nlrow != NULL);
631 assert(blkmem != NULL);
632 assert(pos >= 0);
633 assert(pos < nlrow->nlinvars);
634
635 var = nlrow->linvars[pos];
636
637 if( SCIPvarIsActive(var) )
638 return SCIP_OKAY;
639
640 oldconstant = nlrow->constant;
641
642 /* replace fixed, aggregated, or negated variable */
643 SCIP_CALL( SCIPvarGetProbvarSum( &nlrow->linvars[pos], set, &nlrow->lincoefs[pos], &nlrow->constant) );
644
645 /* if var had been fixed, entry should be removed from row */
646 if( nlrow->lincoefs[pos] == 0.0 )
647 {
648 nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos);
649 nlrow->nlinvars--;
650
651 if( pos < nlrow->nlinvars )
652 {
653 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
654 }
655
656 return SCIP_OKAY;
657 }
658 nlrow->linvarssorted = FALSE;
659
660 /* notify nlrow that coefficient of var is now 0.0 in row */
661 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) );
662
663 /* notify nlrow that constant of row has changed */
664 if( oldconstant != nlrow->constant )
665 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
666
667 if( SCIPvarIsActive(nlrow->linvars[pos]) )
668 {
669 /* if var was aggregated or negated, notify nlrow about new coefficient */
670 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], nlrow->lincoefs[pos], nlp) );
671 }
672 else
673 {
674 SCIP_Real coef;
675 int i;
676
677 /* if not removed or active, the new variable should be multi-aggregated */
678 assert(SCIPvarGetStatus(nlrow->linvars[pos]) == SCIP_VARSTATUS_MULTAGGR);
679
680 var = nlrow->linvars[pos];
681 coef = nlrow->lincoefs[pos];
682
683 /* remove the variable from the row */
684 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
685
686 /* add multi-aggregated term to row */
687 if( SCIPvarGetMultaggrConstant(var) != 0.0 )
688 {
689 nlrow->constant += coef * SCIPvarGetMultaggrConstant(var);
690 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
691 }
692 SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars + SCIPvarGetMultaggrNVars(var)) );
693 for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i )
694 {
695 if( SCIPsetIsZero(set, coef * SCIPvarGetMultaggrScalars(var)[i]) )
696 continue;
697 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], coef * SCIPvarGetMultaggrScalars(var)[i]) );
698 assert(SCIPvarGetMultaggrVars(var)[i] == nlrow->linvars[nlrow->nlinvars-1]);
699 if( !SCIPvarIsActive(SCIPvarGetMultaggrVars(var)[i]) )
700 {
701 /* if newly added variable is fixed, replace it now */
702 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, nlrow->nlinvars-1) );
703 }
704 }
705
706 /* due to nlrowDelLinearCoefPos, an inactive variable may have moved to position pos
707 * if that is the case, call ourself recursively
708 */
709 if( pos < nlrow->nlinvars && !SCIPvarIsActive(nlrow->linvars[pos]) )
710 {
711 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
712 }
713 }
714
715 return SCIP_OKAY;
716 }
717
718 /** removes fixed variables from the linear part of a nonlinear row */
719 static
720 SCIP_RETCODE nlrowRemoveFixedLinearCoefs(
721 SCIP_NLROW* nlrow, /**< nonlinear row */
722 BMS_BLKMEM* blkmem, /**< block memory */
723 SCIP_SET* set, /**< global SCIP settings */
724 SCIP_STAT* stat, /**< problem statistics data */
725 SCIP_NLP* nlp /**< current NLP data */
726 )
727 {
728 int i;
729 int oldlen;
730
731 assert(nlrow != NULL);
732 assert(nlrow->linvars != NULL || nlrow->nlinvars == 0);
733
734 oldlen = nlrow->nlinvars;
735 for( i = 0; i < MIN(oldlen, nlrow->nlinvars); ++i )
736 {
737 assert(nlrow->linvars[i] != NULL);
738 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, i) );
739 }
740
741 return SCIP_OKAY;
742 }
743
744 /** removes fixed variables from expression of a nonlinear row */
745 static
746 SCIP_RETCODE nlrowSimplifyExpr(
747 SCIP_NLROW* nlrow, /**< nonlinear row */
748 BMS_BLKMEM* blkmem, /**< block memory */
749 SCIP_SET* set, /**< global SCIP settings */
750 SCIP_STAT* stat, /**< problem statistics data */
751 SCIP_NLP* nlp /**< current NLP data */
752 )
753 {
754 SCIP_EXPR* simplified;
755 SCIP_Bool changed;
756 SCIP_Bool infeasible;
757
758 if( nlrow->expr == NULL )
759 return SCIP_OKAY;
760
761 SCIP_CALL( SCIPexprSimplify(set, stat, blkmem, nlrow->expr, &simplified, &changed, &infeasible, NULL, NULL) );
762 assert(!infeasible);
763
764 if( !changed )
765 {
766 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &simplified) );
767 return SCIP_OKAY;
768 }
769
770 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
771 nlrow->expr = simplified;
772
773 if( SCIPexprIsValue(set, nlrow->expr) )
774 {
775 /* if expression tree is constant, remove it */
776 SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + SCIPgetValueExprValue(nlrow->expr)) );
777
778 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
779 }
780
781 SCIP_CALL( nlrowExprChanged(nlrow, blkmem, set, stat, nlp) );
782
783 return SCIP_OKAY;
784 }
785
786 /** removes fixed variable from nonlinear row */
787 static
788 SCIP_RETCODE nlrowRemoveFixedVar(
789 SCIP_NLROW* nlrow, /**< nonlinear row */
790 BMS_BLKMEM* blkmem, /**< block memory */
791 SCIP_SET* set, /**< global SCIP settings */
792 SCIP_STAT* stat, /**< problem statistics data */
793 SCIP_NLP* nlp, /**< current NLP data */
794 SCIP_VAR* var /**< variable that had been fixed */
795 )
796 {
797 int pos;
798
799 assert(nlrow != NULL);
800 assert(var != NULL);
801 assert(!SCIPvarIsActive(var));
802
803 /* search for variable in linear part and remove if existing */
804 pos = nlrowSearchLinearCoef(nlrow, var);
805 if( pos >= 0 )
806 {
807 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
808 }
809
810 /* search for variable in nonlinear part and remove all fixed variables in expression if existing
811 * TODO only call simplify if var appears in expr, but currently we don't store the vars in a separate array
812 */
813 if( nlrow->expr != NULL )
814 {
815 SCIP_CALL( nlrowSimplifyExpr(nlrow, blkmem, set, stat, nlp) );
816 }
817
818 return SCIP_OKAY;
819 }
820
821 /*
822 * public NLP nonlinear row methods
823 */
824 /**@addtogroup PublicNLRowMethods
825 *
826 * @{
827 */
828
829 /** create a new nonlinear row
830 *
831 * the new row is already captured
832 */
833 SCIP_RETCODE SCIPnlrowCreate(
834 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */
835 BMS_BLKMEM* blkmem, /**< block memory */
836 SCIP_SET* set, /**< global SCIP settings */
837 SCIP_STAT* stat, /**< problem statistics data */
838 const char* name, /**< name of nonlinear row */
839 SCIP_Real constant, /**< constant */
840 int nlinvars, /**< number of linear variables */
841 SCIP_VAR** linvars, /**< linear variables, or NULL if nlinvars == 0 */
842 SCIP_Real* lincoefs, /**< linear coefficients, or NULL if nlinvars == 0 */
843 SCIP_EXPR* expr, /**< expression, or NULL */
844 SCIP_Real lhs, /**< left hand side */
845 SCIP_Real rhs, /**< right hand side */
846 SCIP_EXPRCURV curvature /**< curvature of the nonlinear row */
847 )
848 {
849 #ifndef NDEBUG
850 int i;
851 #endif
852
853 assert(nlrow != NULL);
854 assert(blkmem != NULL);
855 assert(set != NULL);
856 assert(name != NULL);
857 assert(!SCIPsetIsInfinity(set, ABS(constant)));
858 assert(nlinvars == 0 || linvars != NULL);
859 assert(nlinvars == 0 || lincoefs != NULL);
860 assert(SCIPsetIsRelLE(set, lhs, rhs));
861
862 SCIP_ALLOC( BMSallocBlockMemory(blkmem, nlrow) );
863
864 /* constant part */
865 assert(!SCIPsetIsInfinity(set, REALABS(constant)));
866 (*nlrow)->constant = constant;
867
868 #ifndef NDEBUG
869 for( i = 0; i < nlinvars; ++i )
870 {
871 assert(linvars[i] != NULL);
872 assert(!SCIPsetIsInfinity(set, REALABS(lincoefs[i])));
873 }
874 #endif
875
876 /* linear part */
877 (*nlrow)->nlinvars = nlinvars;
878 (*nlrow)->linvarssize = nlinvars;
879 if( nlinvars > 0 )
880 {
881 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->linvars, linvars, nlinvars) );
882 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->lincoefs, lincoefs, nlinvars) );
883 (*nlrow)->linvarssorted = FALSE;
884 }
885 else
886 {
887 (*nlrow)->linvars = NULL;
888 (*nlrow)->lincoefs = NULL;
889 (*nlrow)->linvarssorted = TRUE;
890 }
891
892 /* nonlinear part */
893 if( expr != NULL )
894 {
895 /* TODO preserve common subexpressions, or at least use only one varexpr per var */
896 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, expr, &(*nlrow)->expr, NULL, NULL, NULL, NULL) );
897 }
898 else
899 {
900 (*nlrow)->expr = NULL;
901 }
902
903 /* left and right hand sides, asserted above that lhs is relatively less equal than rhs */
904 (*nlrow)->lhs = MIN(lhs, rhs);
905 (*nlrow)->rhs = MAX(lhs, rhs);
906
907 /* miscellaneous */
908 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->name, name, strlen(name)+1) );
909 (*nlrow)->activity = SCIP_INVALID;
910 (*nlrow)->validactivitynlp = FALSE;
911 (*nlrow)->pseudoactivity = SCIP_INVALID;
912 (*nlrow)->validpsactivitydomchg = FALSE;
913 (*nlrow)->minactivity = SCIP_INVALID;
914 (*nlrow)->maxactivity = SCIP_INVALID;
915 (*nlrow)->validactivitybdsdomchg = FALSE;
916 (*nlrow)->nlpindex = -1;
917 (*nlrow)->nlpiindex = -1;
918 (*nlrow)->nuses = 0;
919 (*nlrow)->dualsol = 0.0;
920 (*nlrow)->curvature = curvature;
921
922 /* capture the nonlinear row */
923 SCIPnlrowCapture(*nlrow);
924
925 return SCIP_OKAY;
926 }
927
928 /** create a nonlinear row that is a copy of a given row
929 *
930 * the new row is already captured
931 */
932 SCIP_RETCODE SCIPnlrowCreateCopy(
933 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */
934 BMS_BLKMEM* blkmem, /**< block memory */
935 SCIP_SET* set, /**< global SCIP settings */
936 SCIP_STAT* stat, /**< problem statistics data */
937 SCIP_NLROW* sourcenlrow /**< nonlinear row to copy */
938 )
939 {
940 assert(nlrow != NULL);
941 assert(blkmem != NULL);
942 assert(set != NULL);
943 assert(sourcenlrow != NULL);
944
945 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, sourcenlrow->name,
946 sourcenlrow->constant,
947 sourcenlrow->nlinvars, sourcenlrow->linvars, sourcenlrow->lincoefs,
948 sourcenlrow->expr,
949 sourcenlrow->lhs, sourcenlrow->rhs, sourcenlrow->curvature) );
950
951 (*nlrow)->linvarssorted = sourcenlrow->linvarssorted;
952 (*nlrow)->activity = sourcenlrow->activity;
953 (*nlrow)->validactivitynlp = sourcenlrow->validactivitynlp;
954 (*nlrow)->pseudoactivity = sourcenlrow->pseudoactivity;
955 (*nlrow)->validpsactivitydomchg = sourcenlrow->validpsactivitydomchg;
956 (*nlrow)->minactivity = sourcenlrow->minactivity;
957 (*nlrow)->maxactivity = sourcenlrow->maxactivity;
958 (*nlrow)->validactivitybdsdomchg = sourcenlrow->validactivitybdsdomchg;
959
960 return SCIP_OKAY;
961 }
962
963 /** create a new nonlinear row from a linear row
964 *
965 * the new row is already captured
966 */
967 SCIP_RETCODE SCIPnlrowCreateFromRow(
968 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */
969 BMS_BLKMEM* blkmem, /**< block memory */
970 SCIP_SET* set, /**< global SCIP settings */
971 SCIP_STAT* stat, /**< problem statistics data */
972 SCIP_ROW* row /**< the linear row to copy */
973 )
974 {
975 int rownz;
976
977 assert(nlrow != NULL);
978 assert(blkmem != NULL);
979 assert(set != NULL);
980 assert(row != NULL);
981
982 rownz = SCIProwGetNNonz(row);
983
984 if( rownz > 1 )
985 {
986 SCIP_VAR** rowvars;
987 int i;
988
989 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowvars, rownz) );
990
991 for( i = 0; i < rownz; ++i )
992 {
993 rowvars[i] = SCIPcolGetVar(SCIProwGetCols(row)[i]);
994 assert(rowvars[i] != NULL);
995 }
996
997 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row),
998 SCIProwGetConstant(row),
999 rownz, rowvars, SCIProwGetVals(row), NULL,
1000 SCIProwGetLhs(row), SCIProwGetRhs(row),
1001 SCIP_EXPRCURV_LINEAR) );
1002
1003 SCIPsetFreeBufferArray(set, &rowvars);
1004 }
1005 else if( rownz == 1 )
1006 {
1007 SCIP_VAR* rowvar;
1008
1009 rowvar = SCIPcolGetVar(SCIProwGetCols(row)[0]);
1010
1011 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row),
1012 SCIProwGetConstant(row),
1013 1, &rowvar, SCIProwGetVals(row), NULL,
1014 SCIProwGetLhs(row), SCIProwGetRhs(row),
1015 SCIP_EXPRCURV_LINEAR) );
1016 }
1017 else
1018 {
1019 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row),
1020 SCIProwGetConstant(row),
1021 0, NULL, NULL, NULL,
1022 SCIProwGetLhs(row), SCIProwGetRhs(row),
1023 SCIP_EXPRCURV_LINEAR) );
1024 }
1025
1026 return SCIP_OKAY;
1027 }
1028
1029 /** output nonlinear row to file stream */
1030 SCIP_RETCODE SCIPnlrowPrint(
1031 SCIP_NLROW* nlrow, /**< NLP row */
1032 BMS_BLKMEM* blkmem, /**< block memory */
1033 SCIP_SET* set, /**< global SCIP settings */
1034 SCIP_STAT* stat, /**< problem statistics data */
1035 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
(1) Event noescape: |
"SCIPnlrowPrint(SCIP_NLROW *, BMS_BLKMEM *, SCIP_SET *, SCIP_STAT *, SCIP_MESSAGEHDLR *, FILE *)" does not free or save its parameter "file". |
1036 FILE* file /**< output file (or NULL for standard output) */
1037 )
1038 {
1039 int i;
1040
1041 assert(nlrow != NULL);
1042
1043 /* print row name */
1044 if( nlrow->name != NULL && nlrow->name[0] != '\0' )
1045 {
1046 SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", nlrow->name);
1047 }
1048
1049 /* print left hand side */
1050 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g <= ", nlrow->lhs);
1051
1052 /* print constant */
1053 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g ", nlrow->constant);
1054
1055 /* print linear coefficients */
1056 for( i = 0; i < nlrow->nlinvars; ++i )
1057 {
1058 assert(nlrow->linvars[i] != NULL);
1059 assert(SCIPvarGetName(nlrow->linvars[i]) != NULL);
1060 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", nlrow->lincoefs[i], SCIPvarGetName(nlrow->linvars[i]));
1061 }
1062
1063 /* print nonlinear part */
1064 if( nlrow->expr != NULL )
1065 {
1066 SCIPmessageFPrintInfo(messagehdlr, file, " + ");
1067 SCIP_CALL( SCIPexprPrint(set, stat, blkmem, messagehdlr, file, nlrow->expr) );
1068 }
1069
1070 /* print right hand side */
1071 SCIPmessageFPrintInfo(messagehdlr, file, " <= %.15g\n", nlrow->rhs);
1072
1073 return SCIP_OKAY;
1074 }
1075
1076 /** increases usage counter of nonlinear row */
1077 void SCIPnlrowCapture(
1078 SCIP_NLROW* nlrow /**< nonlinear row to capture */
1079 )
1080 {
1081 assert(nlrow != NULL);
1082 assert(nlrow->nuses >= 0);
1083
1084 SCIPdebugMessage("capture nonlinear row <%s> with nuses=%d\n", nlrow->name, nlrow->nuses);
1085 nlrow->nuses++;
1086 }
1087
1088 /** decreases usage counter of nonlinear row */
1089 SCIP_RETCODE SCIPnlrowRelease(
1090 SCIP_NLROW** nlrow, /**< nonlinear row to free */
1091 BMS_BLKMEM* blkmem, /**< block memory */
1092 SCIP_SET* set, /**< global SCIP settings */
1093 SCIP_STAT* stat /**< problem statistics data */
1094 )
1095 {
1096 assert(blkmem != NULL);
1097 assert(nlrow != NULL);
1098 assert(*nlrow != NULL);
1099 assert((*nlrow)->nuses >= 1);
1100
1101 SCIPsetDebugMsg(set, "release nonlinear row <%s> with nuses=%d\n", (*nlrow)->name, (*nlrow)->nuses);
1102 (*nlrow)->nuses--;
1103 if( (*nlrow)->nuses > 0 )
1104 {
1105 *nlrow = NULL;
1106 return SCIP_OKAY;
1107 }
1108
1109 /* free row */
1110
1111 assert((*nlrow)->nuses == 0);
1112 assert((*nlrow)->nlpindex == -1);
1113 assert((*nlrow)->nlpiindex == -1);
1114
1115 /* linear part */
1116 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->linvars, (*nlrow)->linvarssize);
1117 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->lincoefs, (*nlrow)->linvarssize);
1118
1119 /* nonlinear part */
1120 if( (*nlrow)->expr != NULL )
1121 {
1122 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &(*nlrow)->expr) );
1123 }
1124
1125 /* miscellaneous */
1126 BMSfreeBlockMemoryArray(blkmem, &(*nlrow)->name, strlen((*nlrow)->name)+1);
1127
1128 BMSfreeBlockMemory(blkmem, nlrow);
1129
1130 return SCIP_OKAY;
1131 }
1132
1133 /** ensures, that linear coefficient array of nonlinear row can store at least num entries */
1134 SCIP_RETCODE SCIPnlrowEnsureLinearSize(
1135 SCIP_NLROW* nlrow, /**< NLP row */
1136 BMS_BLKMEM* blkmem, /**< block memory */
1137 SCIP_SET* set, /**< global SCIP settings */
1138 int num /**< minimum number of entries to store */
1139 )
1140 {
1141 assert(nlrow != NULL);
1142 assert(nlrow->nlinvars <= nlrow->linvarssize);
1143
1144 if( num > nlrow->linvarssize )
1145 {
1146 int newsize;
1147
1148 newsize = SCIPsetCalcMemGrowSize(set, num);
1149 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->linvars, nlrow->linvarssize, newsize) );
1150 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->lincoefs, nlrow->linvarssize, newsize) );
1151 nlrow->linvarssize = newsize;
1152 }
1153 assert(num <= nlrow->linvarssize);
1154
1155 return SCIP_OKAY;
1156 }
1157
1158 /** adds a previously non existing linear coefficient to a nonlinear row */
1159 SCIP_RETCODE SCIPnlrowAddLinearCoef(
1160 SCIP_NLROW* nlrow, /**< NLP nonlinear row */
1161 BMS_BLKMEM* blkmem, /**< block memory */
1162 SCIP_SET* set, /**< global SCIP settings */
1163 SCIP_STAT* stat, /**< problem statistics data */
1164 SCIP_NLP* nlp, /**< current NLP data */
1165 SCIP_VAR* var, /**< variable */
1166 SCIP_Real val /**< value of coefficient */
1167 )
1168 {
1169 /* if row is in NLP already, make sure that only active variables are added */
1170 if( nlrow->nlpindex >= 0 )
1171 {
1172 SCIP_Real constant;
1173
1174 /* get corresponding active or multi-aggregated variable */
1175 constant = 0.0;
1176 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &val, &constant) );
1177
1178 /* add constant */
1179 SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + constant) );
1180
1181 if( val == 0.0 )
1182 /* var has been fixed */
1183 return SCIP_OKAY;
1184
1185 if( !SCIPvarIsActive(var) )
1186 {
1187 /* var should be multi-aggregated, so call this function recursively */
1188 int i;
1189
1190 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
1191 for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i )
1192 {
1193 SCIP_CALL( SCIPnlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], SCIPvarGetMultaggrScalars(var)[i] * val) );
1194 }
1195 return SCIP_OKAY;
1196 }
1197
1198 /* var is active, so can go on like normal */
1199 }
1200
1201 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, val) );
1202
1203 return SCIP_OKAY;
1204 }
1205
1206 /** deletes linear coefficient from nonlinear row */
1207 SCIP_RETCODE SCIPnlrowDelLinearCoef(
1208 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */
1209 SCIP_SET* set, /**< global SCIP settings */
1210 SCIP_STAT* stat, /**< problem statistics data */
1211 SCIP_NLP* nlp, /**< current NLP data */
1212 SCIP_VAR* var /**< coefficient to be deleted */
1213 )
1214 {
1215 int pos;
1216
1217 assert(nlrow != NULL);
1218 assert(var != NULL);
1219
1220 /* 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 */
1221 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
1222
1223 /* search the position of the variable in the row's variable vector */
1224 pos = nlrowSearchLinearCoef(nlrow, var);
1225 if( pos == -1 )
1226 {
1227 SCIPerrorMessage("coefficient for variable <%s> doesn't exist in nonlinear row <%s>\n", SCIPvarGetName(var), nlrow->name);
1228 return SCIP_INVALIDDATA;
1229 }
1230 assert(0 <= pos && pos < nlrow->nlinvars);
1231 assert(nlrow->linvars[pos] == var);
1232
1233 /* delete the variable from the row's variable vector */
1234 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
1235
1236 return SCIP_OKAY;
1237 }
1238
1239 /** changes or adds a linear coefficient to a nonlinear row */
1240 SCIP_RETCODE SCIPnlrowChgLinearCoef(
1241 SCIP_NLROW* nlrow, /**< nonlinear row */
1242 BMS_BLKMEM* blkmem, /**< block memory */
1243 SCIP_SET* set, /**< global SCIP settings */
1244 SCIP_STAT* stat, /**< problem statistics data */
1245 SCIP_NLP* nlp, /**< current NLP data */
1246 SCIP_VAR* var, /**< variable */
1247 SCIP_Real coef /**< new value of coefficient */
1248 )
1249 {
1250 int pos;
1251
1252 assert(nlrow != NULL);
1253 assert(nlp != NULL);
1254 assert(var != NULL);
1255
1256 /* search the position of the variable in the row's linvars vector */
1257 pos = nlrowSearchLinearCoef(nlrow, var);
1258
1259 /* check, if column already exists in the row's linear variables vector */
1260 if( pos == -1 )
1261 {
1262 if( !SCIPsetIsZero(set, coef) )
1263 {
1264 /* add previously not existing coefficient */
1265 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) );
1266 }
1267 }
1268 else
1269 {
1270 /* change the coefficient in the row */
1271 SCIP_CALL( nlrowChgLinearCoefPos(nlrow, set, stat, nlp, pos, coef) );
1272 }
1273
1274 return SCIP_OKAY;
1275 }
1276
1277 /** replaces or deletes an expression in a nonlinear row */
1278 SCIP_RETCODE SCIPnlrowChgExpr(
1279 SCIP_NLROW* nlrow, /**< nonlinear row */
1280 BMS_BLKMEM* blkmem, /**< block memory */
1281 SCIP_SET* set, /**< global SCIP settings */
1282 SCIP_STAT* stat, /**< problem statistics data */
1283 SCIP_NLP* nlp, /**< current NLP data */
1284 SCIP_EXPR* expr /**< new expression */
1285 )
1286 {
1287 assert(nlrow != NULL);
1288 assert(blkmem != NULL);
1289
1290 /* free previous expression tree */
1291 if( nlrow->expr != NULL )
1292 {
1293 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
1294 assert(nlrow->expr == NULL);
1295 }
1296
1297 /* adds new expression tree */
1298 if( expr != NULL )
1299 {
1300 /* TODO preserve common subexpressions, or at least use only one varexpr per var */
1301 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, expr, &nlrow->expr, NULL, NULL, NULL, NULL) );
1302
1303 /* if row is already in NLP, ensure that expr has only active variables */
1304 if( nlrow->nlpindex >= 0 )
1305 {
1306 SCIP_EXPR* simplified;
1307 SCIP_Bool changed;
1308 SCIP_Bool infeasible;
1309
1310 SCIP_CALL( SCIPexprSimplify(set, stat, blkmem, nlrow->expr, &simplified, &changed, &infeasible, NULL, NULL) );
1311 assert(!infeasible);
1312
1313 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
1314 nlrow->expr = simplified;
1315 }
1316 }
1317
1318 /* notify row about the change */
1319 SCIP_CALL( nlrowExprChanged(nlrow, blkmem, set, stat, nlp) );
1320
1321 return SCIP_OKAY;
1322 }
1323
1324 /** changes constant of nonlinear row */
1325 SCIP_RETCODE SCIPnlrowChgConstant(
1326 SCIP_NLROW* nlrow, /**< nonlinear row */
1327 SCIP_SET* set, /**< global SCIP settings */
1328 SCIP_STAT* stat, /**< problem statistics data */
1329 SCIP_NLP* nlp, /**< current NLP data */
1330 SCIP_Real constant /**< new constant */
1331 )
1332 {
1333 assert(nlrow != NULL);
1334
1335 if( !SCIPsetIsEQ(set, nlrow->constant, constant) )
1336 {
1337 nlrow->constant = constant;
1338 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1339 }
1340
1341 return SCIP_OKAY;
1342 }
1343
1344 /** changes left hand side of nonlinear row */
1345 SCIP_RETCODE SCIPnlrowChgLhs(
1346 SCIP_NLROW* nlrow, /**< nonlinear row */
1347 SCIP_SET* set, /**< global SCIP settings */
1348 SCIP_STAT* stat, /**< problem statistics data */
1349 SCIP_NLP* nlp, /**< current NLP data */
1350 SCIP_Real lhs /**< new left hand side */
1351 )
1352 {
1353 assert(nlrow != NULL);
1354
1355 if( !SCIPsetIsEQ(set, nlrow->lhs, lhs) )
1356 {
1357 nlrow->lhs = lhs;
1358 SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) );
1359 }
1360
1361 return SCIP_OKAY;
1362 }
1363
1364 /** changes right hand side of nonlinear row */
1365 SCIP_RETCODE SCIPnlrowChgRhs(
1366 SCIP_NLROW* nlrow, /**< nonlinear row */
1367 SCIP_SET* set, /**< global SCIP settings */
1368 SCIP_STAT* stat, /**< problem statistics data */
1369 SCIP_NLP* nlp, /**< current NLP data */
1370 SCIP_Real rhs /**< new right hand side */
1371 )
1372 {
1373 assert(nlrow != NULL);
1374
1375 if( !SCIPsetIsEQ(set, nlrow->rhs, rhs) )
1376 {
1377 nlrow->rhs = rhs;
1378 SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) );
1379 }
1380
1381 return SCIP_OKAY;
1382 }
1383
1384 /** removes (or substitutes) all fixed, negated, aggregated, multi-aggregated variables from the linear and nonlinear part of a nonlinear row and simplifies its expression */
1385 SCIP_RETCODE SCIPnlrowSimplify(
1386 SCIP_NLROW* nlrow, /**< nonlinear row */
1387 BMS_BLKMEM* blkmem, /**< block memory */
1388 SCIP_SET* set, /**< global SCIP settings */
1389 SCIP_STAT* stat, /**< problem statistics data */
1390 SCIP_NLP* nlp /**< current NLP data */
1391 )
1392 {
1393 SCIP_CALL( nlrowRemoveFixedLinearCoefs(nlrow, blkmem, set, stat, nlp) );
1394 SCIP_CALL( nlrowSimplifyExpr(nlrow, blkmem, set, stat, nlp) );
1395
1396 return SCIP_OKAY;
1397 }
1398
1399 /** recalculates the current activity of a nonlinear row in the current NLP solution */
1400 SCIP_RETCODE SCIPnlrowRecalcNLPActivity(
1401 SCIP_NLROW* nlrow, /**< nonlinear row */
1402 BMS_BLKMEM* blkmem, /**< block memory */
1403 SCIP_SET* set, /**< global SCIP settings */
1404 SCIP_STAT* stat, /**< problem statistics data */
1405 SCIP_PRIMAL* primal, /**< primal data */
1406 SCIP_TREE* tree, /**< branch and bound tree */
1407 SCIP_NLP* nlp /**< current NLP data */
1408 )
1409 {
1410 int i;
1411
1412 assert(nlrow != NULL);
1413 assert(stat != NULL);
1414 assert(nlp != NULL);
1415
1416 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
1417 {
1418 SCIPerrorMessage("do not have NLP solution for computing NLP activity\n");
1419 return SCIP_ERROR;
1420 }
1421
1422 nlrow->activity = nlrow->constant;
1423 for( i = 0; i < nlrow->nlinvars; ++i )
1424 {
1425 assert(nlrow->linvars[i] != NULL);
1426 assert(SCIPvarGetNLPSol(nlrow->linvars[i]) < SCIP_INVALID);
1427
1428 nlrow->activity += nlrow->lincoefs[i] * SCIPvarGetNLPSol(nlrow->linvars[i]);
1429 }
1430
1431 if( nlrow->expr != NULL )
1432 {
1433 SCIP_SOL* sol;
1434
1435 SCIP_CALL( SCIPsolCreateNLPSol(&sol, blkmem, set, stat, primal, tree, nlp, NULL) );
1436
1437 SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) );
1438 if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID )
1439 nlrow->activity = SCIP_INVALID;
1440 else
1441 nlrow->activity += SCIPexprGetEvalValue(nlrow->expr);
1442
1443 SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) );
1444 }
1445
1446 nlrow->validactivitynlp = stat->nnlps;
1447
1448 return SCIP_OKAY;
1449 }
1450
1451 /** gives the activity of a nonlinear row in the current NLP solution */
1452 SCIP_RETCODE SCIPnlrowGetNLPActivity(
1453 SCIP_NLROW* nlrow, /**< nonlinear row */
1454 BMS_BLKMEM* blkmem, /**< block memory */
1455 SCIP_SET* set, /**< global SCIP settings */
1456 SCIP_STAT* stat, /**< problem statistics data */
1457 SCIP_PRIMAL* primal, /**< primal data */
1458 SCIP_TREE* tree, /**< branch and bound tree */
1459 SCIP_NLP* nlp, /**< current NLP data */
1460 SCIP_Real* activity /**< buffer to store activity value */
1461 )
1462 {
1463 assert(nlrow != NULL);
1464 assert(stat != NULL);
1465 assert(activity != NULL);
1466
1467 assert(nlrow->validactivitynlp <= stat->nnlps);
1468
1469 if( nlrow->validactivitynlp != stat->nnlps )
1470 {
1471 SCIP_CALL( SCIPnlrowRecalcNLPActivity(nlrow, blkmem, set, stat, primal, tree, nlp) );
1472 }
1473 assert(nlrow->validactivitynlp == stat->nnlps);
1474 assert(nlrow->activity < SCIP_INVALID);
1475
1476 *activity = nlrow->activity;
1477
1478 return SCIP_OKAY;
1479 }
1480
1481 /** gives the feasibility of a nonlinear row in the current NLP solution: negative value means infeasibility */
1482 SCIP_RETCODE SCIPnlrowGetNLPFeasibility(
1483 SCIP_NLROW* nlrow, /**< nonlinear row */
1484 BMS_BLKMEM* blkmem, /**< block memory */
1485 SCIP_SET* set, /**< global SCIP settings */
1486 SCIP_STAT* stat, /**< problem statistics data */
1487 SCIP_PRIMAL* primal, /**< primal data */
1488 SCIP_TREE* tree, /**< branch and bound tree */
1489 SCIP_NLP* nlp, /**< current NLP data */
1490 SCIP_Real* feasibility /**< buffer to store feasibility value */
1491 )
1492 {
1493 SCIP_Real activity;
1494
1495 assert(nlrow != NULL);
1496 assert(feasibility != NULL);
1497
1498 SCIP_CALL( SCIPnlrowGetNLPActivity(nlrow, blkmem, set, stat, primal, tree, nlp, &activity) );
1499 *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs);
1500
1501 return SCIP_OKAY;
1502 }
1503
1504 /** calculates the current pseudo activity of a nonlinear row */
1505 SCIP_RETCODE SCIPnlrowRecalcPseudoActivity(
1506 SCIP_NLROW* nlrow, /**< nonlinear row */
1507 BMS_BLKMEM* blkmem, /**< block memory */
1508 SCIP_SET* set, /**< global SCIP settings */
1509 SCIP_STAT* stat, /**< problem statistics data */
1510 SCIP_PROB* prob, /**< SCIP problem */
1511 SCIP_PRIMAL* primal, /**< primal data */
1512 SCIP_TREE* tree, /**< branch and bound tree */
1513 SCIP_LP* lp /**< SCIP LP */
1514 )
1515 {
1516 SCIP_Real val1;
1517 int i;
1518
1519 assert(nlrow != NULL);
1520 assert(stat != NULL);
1521
1522 nlrow->pseudoactivity = nlrow->constant;
1523 for( i = 0; i < nlrow->nlinvars; ++i )
1524 {
1525 assert(nlrow->linvars[i] != NULL);
1526
1527 val1 = SCIPvarGetBestBoundLocal(nlrow->linvars[i]);
1528 nlrow->pseudoactivity += nlrow->lincoefs[i] * val1;
1529 }
1530
1531 if( nlrow->expr != NULL )
1532 {
1533 SCIP_SOL* sol;
1534
1535 SCIP_CALL( SCIPsolCreatePseudoSol(&sol, blkmem, set, stat, prob, primal, tree, lp, NULL) );
1536
1537 SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) );
1538 if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID )
1539 nlrow->pseudoactivity = SCIP_INVALID;
1540 else
1541 nlrow->pseudoactivity += SCIPexprGetEvalValue(nlrow->expr);
1542
1543 SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) );
1544 }
1545
1546 nlrow->validpsactivitydomchg = stat->domchgcount;
1547
1548 return SCIP_OKAY;
1549 }
1550
1551 /** returns the pseudo activity of a nonlinear row in the current pseudo solution */
1552 SCIP_RETCODE SCIPnlrowGetPseudoActivity(
1553 SCIP_NLROW* nlrow, /**< nonlinear row */
1554 BMS_BLKMEM* blkmem, /**< block memory */
1555 SCIP_SET* set, /**< global SCIP settings */
1556 SCIP_STAT* stat, /**< problem statistics data */
1557 SCIP_PROB* prob, /**< SCIP problem */
1558 SCIP_PRIMAL* primal, /**< primal data */
1559 SCIP_TREE* tree, /**< branch and bound tree */
1560 SCIP_LP* lp, /**< SCIP LP */
1561 SCIP_Real* pseudoactivity /**< buffer to store pseudo activity value */
1562 )
1563 {
1564 assert(nlrow != NULL);
1565 assert(stat != NULL);
1566 assert(pseudoactivity != NULL);
1567 assert(nlrow->validpsactivitydomchg <= stat->domchgcount);
1568
1569 /* check, if pseudo activity has to be calculated */
1570 if( nlrow->validpsactivitydomchg != stat->domchgcount )
1571 {
1572 SCIP_CALL( SCIPnlrowRecalcPseudoActivity(nlrow, blkmem, set, stat, prob, primal, tree, lp) );
1573 }
1574 assert(nlrow->validpsactivitydomchg == stat->domchgcount);
1575 assert(nlrow->pseudoactivity < SCIP_INVALID);
1576
1577 *pseudoactivity = nlrow->pseudoactivity;
1578
1579 return SCIP_OKAY;
1580 }
1581
1582 /** returns the pseudo feasibility of a nonlinear row in the current pseudo solution: negative value means infeasibility */
1583 SCIP_RETCODE SCIPnlrowGetPseudoFeasibility(
1584 SCIP_NLROW* nlrow, /**< nonlinear row */
1585 BMS_BLKMEM* blkmem, /**< block memory */
1586 SCIP_SET* set, /**< global SCIP settings */
1587 SCIP_STAT* stat, /**< problem statistics data */
1588 SCIP_PROB* prob, /**< SCIP problem */
1589 SCIP_PRIMAL* primal, /**< primal data */
1590 SCIP_TREE* tree, /**< branch and bound tree */
1591 SCIP_LP* lp, /**< SCIP LP */
1592 SCIP_Real* pseudofeasibility /**< buffer to store pseudo feasibility value */
1593 )
1594 {
1595 SCIP_Real pseudoactivity;
1596
1597 assert(nlrow != NULL);
1598 assert(stat != NULL);
1599 assert(pseudofeasibility != NULL);
1600
1601 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlrow, blkmem, set, stat, prob, primal, tree, lp, &pseudoactivity) );
1602 *pseudofeasibility = MIN(nlrow->rhs - pseudoactivity, pseudoactivity - nlrow->lhs);
1603
1604 return SCIP_OKAY;
1605 }
1606
1607 /** returns the activity of a nonlinear row for a given solution */
1608 SCIP_RETCODE SCIPnlrowGetSolActivity(
1609 SCIP_NLROW* nlrow, /**< nonlinear row */
1610 BMS_BLKMEM* blkmem, /**< block memory */
1611 SCIP_SET* set, /**< global SCIP settings */
1612 SCIP_STAT* stat, /**< problem statistics data */
1613 SCIP_SOL* sol, /**< primal CIP solution */
1614 SCIP_Real* activity /**< buffer to store activity value */
1615 )
1616 {
1617 SCIP_Real inf;
1618 SCIP_Real val1;
1619 int i;
1620
1621 assert(nlrow != NULL);
1622 assert(set != NULL);
1623 assert(stat != NULL);
1624 assert(activity != NULL);
1625
1626 *activity = nlrow->constant;
1627 for( i = 0; i < nlrow->nlinvars; ++i )
1628 {
1629 assert(nlrow->linvars[i] != NULL);
1630
1631 val1 = SCIPsolGetVal(sol, set, stat, nlrow->linvars[i]);
1632 if( val1 == SCIP_UNKNOWN )
1633 {
1634 *activity = SCIP_INVALID;
1635 return SCIP_OKAY;
1636 }
1637 *activity += nlrow->lincoefs[i] * val1;
1638 }
1639
1640 if( nlrow->expr != NULL )
1641 {
1642 SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) );
1643 if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID )
1644 *activity = SCIP_INVALID;
1645 else
1646 *activity += SCIPexprGetEvalValue(nlrow->expr);
1647 }
1648
1649 inf = SCIPsetInfinity(set);
1650 *activity = MAX(*activity, -inf);
1651 *activity = MIN(*activity, +inf);
1652
1653 return SCIP_OKAY;
1654 }
1655
1656 /** returns the feasibility of a nonlinear row for the given solution */
1657 SCIP_RETCODE SCIPnlrowGetSolFeasibility(
1658 SCIP_NLROW* nlrow, /**< nonlinear row */
1659 BMS_BLKMEM* blkmem, /**< block memory */
1660 SCIP_SET* set, /**< global SCIP settings */
1661 SCIP_STAT* stat, /**< problem statistics data */
1662 SCIP_SOL* sol, /**< primal CIP solution */
1663 SCIP_Real* feasibility /**< buffer to store feasibility value */
1664 )
1665 {
1666 SCIP_Real activity;
1667
1668 assert(nlrow != NULL);
1669 assert(feasibility != NULL);
1670
1671 SCIP_CALL( SCIPnlrowGetSolActivity(nlrow, blkmem, set, stat, sol, &activity) );
1672
1673 *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs);
1674
1675 return SCIP_OKAY;
1676 }
1677
1678 /** returns the minimal activity of a nonlinear row w.r.t. the variables' bounds */
1679 SCIP_RETCODE SCIPnlrowGetActivityBounds(
1680 SCIP_NLROW* nlrow, /**< nonlinear row */
1681 BMS_BLKMEM* blkmem, /**< block memory */
1682 SCIP_SET* set, /**< global SCIP settings */
1683 SCIP_STAT* stat, /**< problem statistics data */
1684 SCIP_Real* minactivity, /**< buffer to store minimal activity, or NULL */
1685 SCIP_Real* maxactivity /**< buffer to store maximal activity, or NULL */
1686 )
1687 {
1688 assert(nlrow != NULL);
1689 assert(set != NULL);
1690 assert(stat != NULL);
1691 assert(nlrow->validactivitybdsdomchg <= stat->domchgcount);
1692
1693 /* check, if activity bounds has to be calculated */
1694 if( nlrow->validactivitybdsdomchg != stat->domchgcount )
1695 {
1696 SCIP_CALL( nlrowCalcActivityBounds(nlrow, blkmem, set, stat) );
1697 }
1698 assert(nlrow->validactivitybdsdomchg == stat->domchgcount);
1699 assert(nlrow->minactivity < SCIP_INVALID);
1700 assert(nlrow->maxactivity < SCIP_INVALID);
1701
1702 if( minactivity != NULL )
1703 *minactivity = nlrow->minactivity;
1704 if( maxactivity != NULL )
1705 *maxactivity = nlrow->maxactivity;
1706
1707 return SCIP_OKAY;
1708 }
1709
1710 /** returns whether the nonlinear row is redundant w.r.t. the variables' bounds */
1711 SCIP_RETCODE SCIPnlrowIsRedundant(
1712 SCIP_NLROW* nlrow, /**< nonlinear row */
1713 BMS_BLKMEM* blkmem, /**< block memory */
1714 SCIP_SET* set, /**< global SCIP settings */
1715 SCIP_STAT* stat, /**< problem statistics data */
1716 SCIP_Bool* isredundant /**< buffer to store whether row is redundant */
1717 )
1718 {
1719 SCIP_Real minactivity;
1720 SCIP_Real maxactivity;
1721
1722 assert(nlrow != NULL);
1723 assert(set != NULL);
1724 assert(isredundant != NULL);
1725
1726 SCIP_CALL( SCIPnlrowGetActivityBounds(nlrow, blkmem, set, stat, &minactivity, &maxactivity) );
1727
1728 *isredundant = TRUE;
1729 if( (!SCIPsetIsInfinity(set, -nlrow->lhs) && SCIPsetIsFeasLT(set, minactivity, nlrow->lhs)) ||
1730 ( !SCIPsetIsInfinity(set, nlrow->rhs) && SCIPsetIsFeasGT(set, maxactivity, nlrow->rhs)) )
1731 *isredundant = FALSE;
1732
1733 return SCIP_OKAY;
1734 }
1735
1736 #ifdef NDEBUG
1737 /* Undo the defines from pub_nlhdlr.h, which exist if NDEBUG is defined. */
1738 #undef SCIPnlrowGetConstant
1739 #undef SCIPnlrowGetNLinearVars
1740 #undef SCIPnlrowGetLinearVars
1741 #undef SCIPnlrowGetLinearCoefs
1742 #undef SCIPnlrowGetExpr
1743 #undef SCIPnlrowGetLhs
1744 #undef SCIPnlrowGetRhs
1745 #undef SCIPnlrowGetCurvature
1746 #undef SCIPnlrowSetCurvature
1747 #undef SCIPnlrowGetName
1748 #undef SCIPnlrowGetNLPPos
1749 #undef SCIPnlrowIsInNLP
1750 #undef SCIPnlrowGetDualsol
1751 #endif
1752
1753 /** gets constant */
1754 SCIP_Real SCIPnlrowGetConstant(
1755 SCIP_NLROW* nlrow /**< NLP row */
1756 )
1757 {
1758 assert(nlrow != NULL);
1759
1760 return nlrow->constant;
1761 }
1762
1763 /** gets number of variables of linear part */
1764 int SCIPnlrowGetNLinearVars(
1765 SCIP_NLROW* nlrow /**< NLP row */
1766 )
1767 {
1768 assert(nlrow != NULL);
1769
1770 return nlrow->nlinvars;
1771 }
1772
1773 /** gets array with variables of linear part */
1774 SCIP_VAR** SCIPnlrowGetLinearVars(
1775 SCIP_NLROW* nlrow /**< NLP row */
1776 )
1777 {
1778 assert(nlrow != NULL);
1779
1780 return nlrow->linvars;
1781 }
1782
1783 /** gets array with coefficients in linear part */
1784 SCIP_Real* SCIPnlrowGetLinearCoefs(
1785 SCIP_NLROW* nlrow /**< NLP row */
1786 )
1787 {
1788 assert(nlrow != NULL);
1789
1790 return nlrow->lincoefs;
1791 }
1792
1793 /** gets expression */
1794 SCIP_EXPR* SCIPnlrowGetExpr(
1795 SCIP_NLROW* nlrow /**< NLP row */
1796 )
1797 {
1798 assert(nlrow != NULL);
1799
1800 return nlrow->expr;
1801 }
1802
1803 /** returns the left hand side of a nonlinear row */
1804 SCIP_Real SCIPnlrowGetLhs(
1805 SCIP_NLROW* nlrow /**< NLP row */
1806 )
1807 {
1808 assert(nlrow != NULL);
1809
1810 return nlrow->lhs;
1811 }
1812
1813 /** returns the right hand side of a nonlinear row */
1814 SCIP_Real SCIPnlrowGetRhs(
1815 SCIP_NLROW* nlrow /**< NLP row */
1816 )
1817 {
1818 assert(nlrow != NULL);
1819
1820 return nlrow->rhs;
1821 }
1822
1823 /** returns the curvature of a nonlinear row */
1824 SCIP_EXPRCURV SCIPnlrowGetCurvature(
1825 SCIP_NLROW* nlrow /**< NLP row */
1826 )
1827 {
1828 assert(nlrow != NULL);
1829 return nlrow->curvature;
1830 }
1831
1832 /** sets the curvature of a nonlinear row */
1833 void SCIPnlrowSetCurvature(
1834 SCIP_NLROW* nlrow, /**< NLP row */
1835 SCIP_EXPRCURV curvature /**< curvature of NLP row */
1836 )
1837 {
1838 assert(nlrow != NULL);
1839 nlrow->curvature = curvature;
1840 }
1841
1842 /** returns the name of a nonlinear row */
1843 const char* SCIPnlrowGetName(
1844 SCIP_NLROW* nlrow /**< NLP row */
1845 )
1846 {
1847 assert(nlrow != NULL);
1848
1849 return nlrow->name;
1850 }
1851
1852 /** gets position of a nonlinear row in current NLP, or -1 if not in NLP */
1853 int SCIPnlrowGetNLPPos(
1854 SCIP_NLROW* nlrow /**< NLP row */
1855 )
1856 {
1857 assert(nlrow != NULL);
1858
1859 return nlrow->nlpindex;
1860 }
1861
1862 /** returns TRUE iff row is member of current NLP */
1863 SCIP_Bool SCIPnlrowIsInNLP(
1864 SCIP_NLROW* nlrow /**< NLP row */
1865 )
1866 {
1867 assert(nlrow != NULL);
1868
1869 return nlrow->nlpindex != -1;
1870 }
1871
1872 /** gets the dual NLP solution of a nlrow
1873 *
1874 * 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
1875 */
1876 SCIP_Real SCIPnlrowGetDualsol(
1877 SCIP_NLROW* nlrow /**< NLP row */
1878 )
1879 {
1880 assert(nlrow != NULL);
1881
1882 return nlrow->nlpiindex >= 0 ? nlrow->dualsol : 0.0;
1883 }
1884
1885 /** @} */
1886
1887 /*
1888 * local NLP methods
1889 */
1890
1891 /** announces, that a row of the NLP was modified
1892 * adjusts status of current solution
1893 * calling method has to ensure that change is passed to the NLPI!
1894 */ /*lint -e{715}*/
1895 static
1896 SCIP_RETCODE nlpRowChanged(
1897 SCIP_NLP* nlp, /**< current NLP data */
1898 SCIP_SET* set, /**< global SCIP settings */
1899 SCIP_STAT* stat, /**< problem statistics data */
1900 SCIP_NLROW* nlrow /**< nonlinear row which was changed */
1901 )
1902 { /*lint --e{715}*/
1903 assert(nlp != NULL);
1904 assert(nlrow != NULL);
1905 assert(!nlp->indiving);
1906 assert(nlrow->nlpindex >= 0);
1907
1908 /* nlrow is a row in the NLP, so changes effect feasibility */
1909 /* if we have a feasible NLP solution and it satisfies the modified row, then it is still feasible
1910 * if the NLP was globally or locally infeasible or unbounded, then this may not be the case anymore
1911 */
1912 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1913 {
1914 /* TODO bring this back? then everything that may call nlpRowChanged will need to pass on blkmem, primal, tree as well
1915 SCIP_Real feasibility;
1916 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1917 if( !SCIPsetIsFeasNegative(set, feasibility) )
1918 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
1919 else */
1920 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
1921 }
1922 else
1923 {
1924 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1925 }
1926
1927 return SCIP_OKAY;
1928 }
1929
1930 /** adds a set of nonlinear rows to the NLP and captures them */
1931 static
1932 SCIP_RETCODE nlpAddNlRows(
1933 SCIP_NLP* nlp, /**< NLP data */
1934 BMS_BLKMEM* blkmem, /**< block memory */
1935 SCIP_SET* set, /**< global SCIP settings */
1936 SCIP_STAT* stat, /**< problem statistics data */
1937 int nnlrows, /**< number of nonlinear rows to add */
1938 SCIP_NLROW** nlrows /**< nonlinear rows to add */
1939 )
1940 {
1941 #ifndef NDEBUG
1942 int i;
1943 #endif
1944 int j;
1945 SCIP_NLROW* nlrow;
1946
1947 assert(nlp != NULL);
1948 assert(blkmem != NULL);
1949 assert(set != NULL);
1950 assert(nlrows != NULL || nnlrows == 0);
1951 assert(!nlp->indiving);
1952
1953 SCIP_CALL( SCIPnlpEnsureNlRowsSize(nlp, blkmem, set, nlp->nnlrows + nnlrows) );
1954
1955 for( j = 0; j < nnlrows; ++j )
1956 {
1957 nlrow = nlrows[j]; /*lint !e613*/
1958
1959 /* assert that row is not in NLP (or even NLPI) yet */
1960 assert(nlrow->nlpindex == -1);
1961 assert(nlrow->nlpiindex == -1);
1962
1963 /* make sure there are only active variables in row */
1964 SCIP_CALL( SCIPnlrowSimplify(nlrow, blkmem, set, stat, nlp) );
1965
1966 #ifndef NDEBUG
1967 /* assert that variables of row are in NLP */
1968 for( i = 0; i < nlrow->nlinvars; ++i )
1969 assert(SCIPhashmapExists(nlp->varhash, nlrow->linvars[i]));
1970
1971 if( nlrow->expr != NULL )
1972 {
1973 SCIP_EXPRITER* it;
1974 SCIP_EXPR* expr;
1975
1976 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
1977 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
1978 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
1979 assert(!SCIPexprIsVar(set, expr) || SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
1980 SCIPexpriterFree(&it);
1981 }
1982 #endif
1983
1984 /* add row to NLP and capture it */
1985 nlp->nlrows[nlp->nnlrows + j] = nlrow;
1986 nlrow->nlpindex = nlp->nnlrows + j;
1987
1988 SCIPnlrowCapture(nlrow);
1989
1990 /* if we have a feasible NLP solution and it satisfies the new solution, then it is still feasible
1991 * if the NLP was globally or locally infeasible, then it stays that way
1992 * if the NLP was unbounded, then this may not be the case anymore
1993 */
1994 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1995 {
1996 /* TODO bring this back? then everything that may call nlpAddNlRows will need to pass on primal, tree as well
1997 SCIP_Real feasibility;
1998 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1999 if( !SCIPsetIsFeasNegative(set, feasibility) )
2000 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2001 else
2002 */
2003 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2004 }
2005 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2006 {
2007 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2008 }
2009 }
2010
2011 nlp->nnlrows += nnlrows;
2012 nlp->nunflushednlrowadd += nnlrows;
2013
2014 return SCIP_OKAY;
2015 }
2016
2017 /** moves a nonlinear row to a different place, and updates all corresponding data structures */
2018 static
2019 void nlpMoveNlrow(
2020 SCIP_NLP* nlp, /**< NLP data structure */
2021 int oldpos, /**< old position of nonlinear row */
2022 int newpos /**< new position of nonlinear row */
2023 )
2024 {
2025 assert(nlp != NULL);
2026 assert(0 <= oldpos && oldpos < nlp->nnlrows);
2027 assert(0 <= newpos && newpos < nlp->nnlrows);
2028 assert(nlp->nlrows[oldpos] != NULL);
2029
2030 if( oldpos == newpos )
2031 return;
2032
2033 nlp->nlrows[newpos] = nlp->nlrows[oldpos];
2034 nlp->nlrows[newpos]->nlpindex = newpos;
2035
2036 /* update nlpi to nlp row index mapping */
2037 if( nlp->nlrows[newpos]->nlpiindex >= 0 )
2038 {
2039 assert(nlp->nlrowmap_nlpi2nlp != NULL);
2040 assert(nlp->nlrows[newpos]->nlpiindex < nlp->sizenlrows_solver);
2041 nlp->nlrowmap_nlpi2nlp[nlp->nlrows[newpos]->nlpiindex] = newpos;
2042 }
2043 }
2044
2045 /** deletes nonlinear row with given position from NLP */
2046 static
2047 SCIP_RETCODE nlpDelNlRowPos(
2048 SCIP_NLP* nlp, /**< NLP data structure */
2049 BMS_BLKMEM* blkmem, /**< block memory */
2050 SCIP_SET* set, /**< global SCIP settings */
2051 SCIP_STAT* stat, /**< problem statistics data */
2052 int pos /**< position of nonlinear row that is to be removed */
2053 )
2054 {
2055 SCIP_NLROW* nlrow;
2056
2057 assert(nlp != NULL);
2058 assert(blkmem != NULL);
2059 assert(set != NULL);
2060 assert(pos >= 0);
2061 assert(pos < nlp->nnlrows);
2062 assert(!nlp->indiving);
2063 assert(nlp->nlrows != NULL);
2064
2065 nlrow = nlp->nlrows[pos];
2066 assert(nlrow != NULL);
2067 assert(nlrow->nlpindex == pos);
2068
2069 /* if row is in NLPI, then mark that it has to be removed in the next flush
2070 * if row was not in NLPI yet, then we have one unflushed nlrow addition less */
2071 if( nlrow->nlpiindex >= 0 )
2072 {
2073 assert(nlrow->nlpiindex < nlp->nnlrows_solver);
2074 nlp->nlrowmap_nlpi2nlp[nlrow->nlpiindex] = -1;
2075 nlrow->nlpiindex = -1;
2076 ++nlp->nunflushednlrowdel;
2077 }
2078 else
2079 {
2080 assert(nlrow->nlpiindex == -1);
2081 --nlp->nunflushednlrowadd;
2082 }
2083
2084 /* move NLP row from the end to pos and mark nlrow to be not in NLP anymore */
2085 nlpMoveNlrow(nlp, nlp->nnlrows-1, pos);
2086 nlrow->nlpindex = -1;
2087
2088 /* forget about restriction */
2089 SCIP_CALL( SCIPnlrowRelease(&nlrow, blkmem, set, stat) );
2090 --nlp->nnlrows;
2091
2092 if( nlp->solstat < SCIP_NLPSOLSTAT_LOCOPT )
2093 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2094 else if( nlp->solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
2095 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2096
2097 return SCIP_OKAY; /*lint !e438*/
2098 }
2099
2100 /** updates bounds on a variable in the NLPI problem */
2101 static
2102 SCIP_RETCODE nlpUpdateVarBounds(
2103 SCIP_NLP* nlp, /**< NLP data */
2104 SCIP_SET* set, /**< global SCIP settings */
2105 SCIP_VAR* var, /**< variable which bounds have changed */
2106 SCIP_Bool tightened /**< whether the bound change was a bound tightening */
2107 )
2108 {
2109 int pos;
2110 SCIP_Real lb;
2111 SCIP_Real ub;
2112
2113 assert(nlp != NULL);
2114 assert(var != NULL);
2115 assert(SCIPhashmapExists(nlp->varhash, var));
2116
2117 /* original variable bounds are ignored during diving
2118 * (all variable bounds are reset to their current value in exitDiving) */
2119 if( nlp->indiving )
2120 return SCIP_OKAY;
2121
2122 /* get position of variable in NLP */
2123 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
2124
2125 /* if variable not in NLPI yet, nothing to do */
2126 if( nlp->varmap_nlp2nlpi[pos] == -1 )
2127 return SCIP_OKAY;
2128
2129 /* update bounds in NLPI problem */
2130 assert(nlp->solver != NULL);
2131 assert(nlp->problem != NULL);
2132
2133 pos = nlp->varmap_nlp2nlpi[pos];
2134 lb = SCIPvarGetLbLocal(var);
2135 ub = SCIPvarGetUbLocal(var);
2136 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
2137
2138 /* if we have a feasible NLP solution and it satisfies the new bounds, then it is still feasible
2139 * if the NLP was globally or locally infeasible and we tightened a bound, then it stays that way
2140 * if the NLP was unbounded and we tightened a bound, then this may not be the case anymore
2141 */
2142 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2143 {
2144 if( !tightened ||
2145 ((SCIPsetIsInfinity(set, -lb) || SCIPsetIsFeasLE(set, lb, SCIPvarGetNLPSol(var))) &&
2146 (SCIPsetIsInfinity(set, ub) || SCIPsetIsFeasGE(set, ub, SCIPvarGetNLPSol(var)))) )
2147 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2148 else
2149 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2150 }
2151 else if( !tightened || nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2152 {
2153 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2154 }
2155
2156 return SCIP_OKAY;
2157 }
2158
2159 /** updates coefficient of a variable in the objective */
2160 static
2161 SCIP_RETCODE nlpUpdateObjCoef(
2162 SCIP_SET* set, /**< global SCIP settings */
2163 SCIP_NLP* nlp, /**< NLP data */
2164 SCIP_VAR* var /**< variable which bounds have changed */
2165 )
2166 {
2167 int pos;
2168 int objidx;
2169 SCIP_Real coef;
2170
2171 assert(nlp != NULL);
2172 assert(var != NULL);
2173 assert(SCIPhashmapExists(nlp->varhash, var));
2174
2175 /* if the objective in the NLPI is not up to date, then we do not need to do something here */
2176 if( !nlp->objflushed )
2177 return SCIP_OKAY;
2178
2179 /* original objective is ignored during diving
2180 * we just need to remember that at end of diving we have to flush the objective */
2181 if( nlp->indiving )
2182 {
2183 nlp->objflushed = FALSE;
2184 return SCIP_OKAY;
2185 }
2186
2187 /* get position of variable in NLP and objective coefficient */
2188 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
2189 assert(nlp->varmap_nlp2nlpi[pos] == -1 || nlp->solver != NULL);
2190
2191 /* actually we only need to remember flushing the objective if we also have an NLPI */
2192 if( nlp->solver == NULL )
2193 return SCIP_OKAY;
2194
2195 coef = SCIPvarGetObj(var);
2196
2197 /* if variable not in NLPI yet, then we only need to remember to update the objective after variable additions were flushed */
2198 if( nlp->varmap_nlp2nlpi[pos] == -1 && coef != 0.0 )
2199 {
2200 nlp->objflushed = FALSE;
2201
2202 return SCIP_OKAY;
2203 }
2204
2205 /* if we are here, then the objective in the NLPI is up to date,
2206 * we keep it this way by changing the coefficient of var in the NLPI problem objective */
2207 assert(nlp->solver != NULL);
2208 assert(nlp->problem != NULL);
2209
2210 pos = nlp->varmap_nlp2nlpi[pos];
2211 objidx = -1;
2212 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
2213
2214 /* if we had a solution and it was locally (or globally) optimal, then now we can only be sure that it is still feasible */
2215 if( nlp->solstat < SCIP_NLPSOLSTAT_FEASIBLE )
2216 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2217
2218 return SCIP_OKAY;
2219 }
2220
2221 /** adds new variables to the NLP */
2222 static
2223 SCIP_RETCODE nlpAddVars(
2224 SCIP_NLP* nlp, /**< NLP data structure */
2225 BMS_BLKMEM* blkmem, /**< block memory */
2226 SCIP_SET* set, /**< global SCIP settings */
2227 int nvars, /**< number of variables to add */
2228 SCIP_VAR** vars /**< variable to add to NLP */
2229 )
2230 {
2231 int i;
2232 SCIP_VAR* var;
2233
2234 assert(nlp != NULL);
2235 assert(blkmem != NULL);
2236 assert(set != NULL);
2237 assert(vars != NULL || nvars == 0);
2238 assert(!nlp->indiving || nvars == 0);
2239
2240 if( nvars == 0 )
2241 return SCIP_OKAY;
2242
2243 SCIP_CALL( SCIPnlpEnsureVarsSize(nlp, blkmem, set, nlp->nvars + nvars) );
2244 assert(nlp->sizevars >= nlp->nvars + nvars);
2245
2246 for( i = 0; i < nvars; ++i )
2247 {
2248 var = vars[i]; /*lint !e613*/
2249
2250 assert(SCIPvarIsTransformed(var));
2251 assert(SCIPvarIsActive(var));
2252 assert(!SCIPhashmapExists(nlp->varhash, var));
2253
2254 SCIPvarCapture(var);
2255
2256 nlp->vars[nlp->nvars+i] = var;
2257 nlp->varmap_nlp2nlpi[nlp->nvars+i] = -1;
2258 SCIP_CALL( SCIPhashmapInsertInt(nlp->varhash, var, nlp->nvars+i) );
2259
2260 nlp->varlbdualvals[nlp->nvars+i] = 0.0;
2261 nlp->varubdualvals[nlp->nvars+i] = 0.0;
2262
2263 /* update objective, if necessary (new variables have coefficient 0.0 anyway) */
2264 if( SCIPvarGetObj(var) != 0.0 )
2265 {
2266 SCIP_CALL( nlpUpdateObjCoef(set, nlp, var) );
2267 }
2268
2269 /* let's keep the previous initial guess and set it for the new variable to the best bound
2270 * (since there can be no row that uses this variable yet, this seems a good guess) */
2271 if( nlp->haveinitguess )
2272 {
2273 assert(nlp->initialguess != NULL);
2274
2275 nlp->initialguess[nlp->nvars+i] = SCIPvarGetBestBoundLocal(var);
2276 }
2277
2278 /* if we have a feasible NLP solution, then it remains feasible
2279 * but we have to update the objective function
2280 */
2281 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2282 {
2283 SCIP_CALL( SCIPvarSetNLPSol(var, set, SCIPvarGetBestBoundLocal(var)) );
2284 nlp->primalsolobjval += SCIPvarGetObj(var) * SCIPvarGetBestBoundLocal(var);
2285 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2286 }
2287
2288 /* catch events on variable */
2289 SCIP_CALL( SCIPvarCatchEvent(var, blkmem, set, \
2290 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2291 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, NULL) ); /* @todo should store event filter position in nlp? */
2292 }
2293
2294 nlp->nvars += nvars;
2295 nlp->nunflushedvaradd += nvars;
2296
2297 return SCIP_OKAY;
2298 }
2299
2300 /** moves a variable to a different place, and updates all corresponding data structures */
2301 static
2302 SCIP_RETCODE nlpMoveVar(
2303 SCIP_NLP* nlp, /**< NLP data structure */
2304 int oldpos, /**< old position of variable */
2305 int newpos /**< new position of variable */
2306 )
2307 {
2308 int nlpipos;
2309
2310 assert(nlp != NULL);
2311 assert(0 <= oldpos && oldpos < nlp->nvars);
2312 assert(0 <= newpos && newpos < nlp->nvars);
2313 assert(nlp->vars[oldpos] != NULL);
2314
2315 if( oldpos == newpos )
2316 return SCIP_OKAY;
2317
2318 SCIP_CALL( SCIPhashmapSetImageInt(nlp->varhash, nlp->vars[oldpos], newpos) );
2319 nlp->vars[newpos] = nlp->vars[oldpos];
2320 nlp->varmap_nlp2nlpi[newpos] = nlp->varmap_nlp2nlpi[oldpos];
2321 nlp->varlbdualvals[newpos] = nlp->varlbdualvals[oldpos];
2322 nlp->varubdualvals[newpos] = nlp->varubdualvals[oldpos];
2323 if( nlp->initialguess != NULL )
2324 nlp->initialguess[newpos] = nlp->initialguess[oldpos];
2325
2326 nlpipos = nlp->varmap_nlp2nlpi[newpos];
2327 if( nlpipos > 0 )
2328 nlp->varmap_nlpi2nlp[nlpipos] = newpos;
2329
2330 return SCIP_OKAY;
2331 }
2332
2333 /** deletes variable with given position from NLP */
2334 static
2335 SCIP_RETCODE nlpDelVarPos(
2336 SCIP_NLP* nlp, /**< NLP data structure */
2337 BMS_BLKMEM* blkmem, /**< block memory */
2338 SCIP_SET* set, /**< global SCIP settings */
2339 SCIP_STAT* stat, /**< problem statistics data */
2340 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2341 SCIP_LP* lp, /**< SCIP LP, needed if a column-variable is freed */
2342 int pos /**< position of nonlinear row that is to be removed */
2343 )
2344 {
2345 SCIP_VAR* var;
2346 #ifndef NDEBUG
2347 int i;
2348 #endif
2349 int nlpipos;
2350
2351 assert(nlp != NULL);
2352 assert(blkmem != NULL);
2353 assert(set != NULL);
2354 assert(pos >= 0);
2355 assert(pos < nlp->nvars);
2356 assert(!nlp->indiving);
2357
2358 var = nlp->vars[pos];
2359 assert(var != NULL);
2360
2361 #ifndef NDEBUG
2362 /* assert that variable is not used by any nonlinear row */
2363 for( i = 0; i < nlp->nnlrows; ++i )
2364 {
2365 int j;
2366 SCIP_NLROW* nlrow;
2367
2368 nlrow = nlp->nlrows[i];
2369 assert(nlrow != NULL);
2370
2371 /* use nlrowSearchLinearCoef only if already sorted, since otherwise we may change the solving process slightly */
2372 if( nlrow->linvarssorted )
2373 assert( nlrowSearchLinearCoef(nlrow, var) == -1 );
2374 else
2375 for( j = 0; j < nlrow->nlinvars; ++j )
2376 assert( nlrow->linvars[j] != var );
2377
2378 if( nlrow->expr != NULL )
2379 {
2380 SCIP_EXPRITER* it;
2381 SCIP_EXPR* expr;
2382 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2383 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
2384 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2385 assert(!SCIPexprIsVar(set, expr) || SCIPgetVarExprVar(expr) != var);
2386 SCIPexpriterFree(&it);
2387 }
2388 }
2389 #endif
2390
2391 /* if we had a feasible solution, then adjust objective function value
2392 * if NLP was unbounded before, then maybe it is not anymore */
2393 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2394 nlp->primalsolobjval -= SCIPvarGetObj(var) * SCIPvarGetNLPSol(var);
2395 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2396 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2397
2398 /* if variable is in NLPI problem, mark that we have to remember to delete it there
2399 * if it was not in the NLPI yet, then we have one unflushed var addition less now */
2400 nlpipos = nlp->varmap_nlp2nlpi[pos];
2401 if( nlpipos >= 0 )
2402 {
2403 assert(nlpipos < nlp->nvars_solver);
2404
2405 nlp->varmap_nlpi2nlp[nlpipos] = -1;
2406 ++nlp->nunflushedvardel;
2407 }
2408 else
2409 --nlp->nunflushedvaradd;
2410
2411 /* drop events on variable */
2412 SCIP_CALL( SCIPvarDropEvent(var, blkmem, set, \
2413 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2414 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, -1) );
2415
2416 /* move variable from end to pos */
2417 SCIP_CALL( nlpMoveVar(nlp, nlp->nvars-1, pos) );
2418
2419 /* forget about variable */
2420 SCIP_CALL( SCIPhashmapRemove(nlp->varhash, var) );
2421 SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
2422 --nlp->nvars;
2423
2424 return SCIP_OKAY;
2425 }
2426
2427 /** notifies NLP that a variable was fixed, so it is removed from objective, all rows, and the NLP variables */
2428 static
2429 SCIP_RETCODE nlpRemoveFixedVar(
2430 SCIP_NLP* nlp, /**< NLP data */
2431 BMS_BLKMEM* blkmem, /**< block memory */
2432 SCIP_SET* set, /**< global SCIP settings */
2433 SCIP_STAT* stat, /**< problem statistics data */
2434 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2435 SCIP_LP* lp, /**< SCIP LP, needed to release variable */
2436 SCIP_VAR* var /**< variable that has been fixed */
2437 )
2438 {
2439 int i;
2440
2441 assert(nlp != NULL);
2442 assert(var != NULL);
2443 assert(!SCIPvarIsActive(var));
2444 assert(!nlp->indiving);
2445 assert(SCIPhashmapExists(nlp->varhash, var));
2446
2447 /* remove var from all rows */
2448 for( i = 0; i < nlp->nnlrows; ++i )
2449 {
2450 SCIP_CALL( nlrowRemoveFixedVar(nlp->nlrows[i], blkmem, set, stat, nlp, var) );
2451 }
2452
2453 /* remove variable from NLP */
2454 SCIP_CALL( SCIPnlpDelVar(nlp, blkmem, set, stat, eventqueue, lp, var) );
2455
2456 return SCIP_OKAY;
2457 }
2458
2459 /** creates arrays with NLPI variable indices of linear variables in a nonlinear row */
2460 static
2461 SCIP_RETCODE nlpSetupNlpiIndices(
2462 SCIP_NLP* nlp, /**< NLP data */
2463 SCIP_SET* set, /**< global SCIP settings */
2464 SCIP_NLROW* nlrow, /**< nonlinear row */
2465 int** linidxs /**< buffer to store pointer to NLPI indices of linear variables */
2466 )
2467 {
2468 int i;
2469 SCIP_VAR* var;
2470
2471 assert(nlp != NULL);
2472 assert(set != NULL);
2473 assert(nlrow != NULL);
2474 assert(linidxs != NULL);
2475
2476 /* get indices of variables in linear part of row */
2477 if( nlrow->nlinvars > 0 )
2478 {
2479 assert(nlrow->linvars != NULL);
2480 assert(nlrow->lincoefs != NULL);
2481
2482 SCIP_CALL( SCIPsetAllocBufferArray(set, linidxs, nlrow->nlinvars) );
2483
2484 for( i = 0; i < nlrow->nlinvars; ++i )
2485 {
2486 var = nlrow->linvars[i];
2487 assert(var != NULL);
2488 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
2489
2490 assert(SCIPhashmapExists(nlp->varhash, var));
2491 (*linidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
2492 assert((*linidxs)[i] >= 0);
2493 }
2494 }
2495 else
2496 *linidxs = NULL;
2497
2498 return SCIP_OKAY;
2499 }
2500
2501 /** ensures, that NLPI variables array of NLP can store at least num entries */
2502 static
2503 SCIP_RETCODE nlpEnsureVarsSolverSize(
2504 SCIP_NLP* nlp, /**< NLP data */
2505 BMS_BLKMEM* blkmem, /**< block memory */
2506 SCIP_SET* set, /**< global SCIP settings */
2507 int num /**< minimum number of entries to store */
2508 )
2509 {
2510 assert(nlp != NULL);
2511 assert(blkmem != NULL);
2512 assert(set != NULL);
2513 assert(nlp->nvars_solver <= nlp->sizevars_solver);
2514
2515 if( num > nlp->sizevars_solver )
2516 {
2517 int newsize;
2518
2519 newsize = SCIPsetCalcMemGrowSize(set, num);
2520 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlpi2nlp, nlp->sizevars_solver, newsize) );
2521
2522 nlp->sizevars_solver = newsize;
2523 }
2524 assert(num <= nlp->sizevars_solver);
2525
2526 return SCIP_OKAY;
2527 }
2528
2529 /** ensures, that NLPI nonlinear rows array of NLP can store at least num entries */
2530 static
2531 SCIP_RETCODE nlpEnsureNlRowsSolverSize(
2532 SCIP_NLP* nlp, /**< NLP data */
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(nlp != NULL);
2539 assert(blkmem != NULL);
2540 assert(set != NULL);
2541 assert(nlp->nnlrows_solver <= nlp->sizenlrows_solver);
2542
2543 if( num > nlp->sizenlrows_solver )
2544 {
2545 int newsize;
2546
2547 newsize = SCIPsetCalcMemGrowSize(set, num);
2548 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrowmap_nlpi2nlp, nlp->sizenlrows_solver, newsize) );
2549
2550 nlp->sizenlrows_solver = newsize;
2551 }
2552 assert(num <= nlp->sizenlrows_solver);
2553
2554 return SCIP_OKAY;
2555 }
2556
2557 /** deletes rows from the NLPI problem that have been marked as to remove */
2558 static
2559 SCIP_RETCODE nlpFlushNlRowDeletions(
2560 SCIP_NLP* nlp, /**< NLP data */
2561 BMS_BLKMEM* blkmem, /**< block memory */
2562 SCIP_SET* set /**< global SCIP settings */
2563 )
2564 {
2565 int j;
2566 int c; /* counts the number of rows to delete */
2567 int* rowset; /* marks which rows to delete and stores new indices */
2568 SCIP_NLROW* nlrow;
2569
2570 assert(nlp != NULL);
2571 assert(blkmem != NULL);
2572 assert(set != NULL);
2573 assert(nlp->nunflushednlrowdel >= 0);
2574 assert(!nlp->indiving);
2575
2576 if( nlp->nunflushednlrowdel == 0 )
2577 {
2578 #ifndef NDEBUG
2579 /* check that there are really no pending removals of nonlinear rows */
2580 for( j = 0; j < nlp->nnlrows_solver; ++j )
2581 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2582 #endif
2583 return SCIP_OKAY;
2584 }
2585
2586 assert(nlp->solver != NULL);
2587 assert(nlp->problem != NULL);
2588
2589 /* create marker which rows have to be deleted */
2590 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowset, nlp->nnlrows_solver) );
2591 c = 0;
2592 for( j = 0; j < nlp->nnlrows_solver; ++j )
2593 {
2594 if( nlp->nlrowmap_nlpi2nlp[j] == -1 )
2595 {
2596 rowset[j] = 1;
2597 ++c;
2598 }
2599 else
2600 rowset[j] = 0;
2601 }
2602 assert(c == nlp->nunflushednlrowdel);
2603
2604 /* remove rows from NLPI problem */
2605 SCIP_CALL( SCIPnlpiDelConsSet(set, nlp->solver, nlp->problem, rowset, nlp->nnlrows_solver) );
2606
2607 /* update NLPI row indices */
2608 for( j = 0; j < nlp->nnlrows_solver; ++j )
2609 {
2610 assert(rowset[j] <= j); /* we assume that the NLP solver did not move a row behind its previous position!! */
2611 if( rowset[j] < 0 )
2612 {
2613 /* assert that row was marked as deleted */
2614 assert(nlp->nlrowmap_nlpi2nlp[j] == -1);
2615 }
2616 else if( rowset[j] < j )
2617 {
2618 /* nlrow at position j moved (forward) to position rowset[j] */
2619 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2620 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2621
2622 nlrow = nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]];
2623 assert(nlrow->nlpiindex == j);
2624
2625 /* there should be no row at the new position already */
2626 assert(nlp->nlrowmap_nlpi2nlp[rowset[j]] == -1);
2627
2628 nlrow->nlpiindex = rowset[j];
2629 nlp->nlrowmap_nlpi2nlp[rowset[j]] = nlrow->nlpindex;
2630 }
2631 else
2632 {
2633 /* row j stays at position j */
2634 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2635 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2636 assert(nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]->nlpiindex == j);
2637 }
2638 }
2639 nlp->nnlrows_solver -= c;
2640 nlp->nunflushednlrowdel = 0;
2641
2642 /* cleanup */
2643 SCIPsetFreeBufferArray(set, &rowset);
2644
2645 return SCIP_OKAY;
2646 }
2647
2648 /** deletes variables from the NLPI problem that have been marked as to remove
2649 *
2650 * assumes that there are no pending row deletions (nlpFlushNlRowDeletions() should be called first)
2651 */
2652 static
2653 SCIP_RETCODE nlpFlushVarDeletions(
2654 SCIP_NLP* nlp, /**< NLP data */
2655 BMS_BLKMEM* blkmem, /**< block memory */
2656 SCIP_SET* set /**< global SCIP settings */
2657 )
2658 {
2659 int i;
2660 int c; /* counter on number of variables to remove in solver */
2661 int* colset; /* marks which variables to delete and stores new indices */
2662
2663 assert(nlp != NULL);
2664 assert(blkmem != NULL);
2665 assert(set != NULL);
2666 assert(nlp->nunflushedvardel >= 0);
2667 assert(nlp->nunflushednlrowdel == 0);
2668 assert(!nlp->indiving);
2669
2670 if( nlp->nunflushedvardel == 0 )
2671 {
2672 #ifndef NDEBUG
2673 /* check that there are really no pending removals of variables */
2674 for( i = 0; i < nlp->nvars_solver; ++i )
2675 assert(nlp->varmap_nlpi2nlp[i] >= 0);
2676 #endif
2677 return SCIP_OKAY;
2678 }
2679
2680 assert(nlp->solver != NULL);
2681 assert(nlp->problem != NULL);
2682
2683 /* create marker which variables have to be deleted */
2684 SCIP_CALL( SCIPsetAllocBufferArray(set, &colset, nlp->nvars_solver) );
2685 c = 0;
2686 for( i = 0; i < nlp->nvars_solver; ++i )
2687 {
2688 if( nlp->varmap_nlpi2nlp[i] == -1 )
2689 {
2690 colset[i] = 1;
2691 ++c;
2692 }
2693 else
2694 colset[i] = 0;
2695 }
2696 assert(c == nlp->nunflushedvardel);
2697
2698 /* delete variables from NLPI problem */
2699 SCIP_CALL( SCIPnlpiDelVarSet(set, nlp->solver, nlp->problem, colset, nlp->nvars_solver) );
2700
2701 /* update NLPI variable indices */
2702 for( i = 0; i < nlp->nvars_solver; ++i )
2703 {
2704 assert(colset[i] <= i); /* we assume that the NLP solver did not move a variable behind its previous position!! */
2705 if( colset[i] < 0 )
2706 {
2707 /* assert that variable was marked as deleted */
2708 assert(nlp->varmap_nlpi2nlp[i] == -1);
2709 }
2710 else if( colset[i] < i)
2711 {
2712 /* variable at position i moved (forward) to position colset[i] */
2713 int varpos;
2714
2715 varpos = nlp->varmap_nlpi2nlp[i]; /* position of variable i in NLP */
2716 assert(varpos >= 0);
2717 assert(varpos < nlp->nvars);
2718 assert(nlp->varmap_nlp2nlpi[varpos] == i);
2719
2720 /* there should be no variable at the new position already */
2721 assert(nlp->varmap_nlpi2nlp[colset[i]] == -1);
2722
2723 nlp->varmap_nlp2nlpi[varpos] = colset[i];
2724 nlp->varmap_nlpi2nlp[colset[i]] = varpos;
2725 }
2726 else
2727 {
2728 /* variable i stays at position i */
2729 assert(nlp->varmap_nlpi2nlp[i] >= 0);
2730 assert(nlp->varmap_nlpi2nlp[i] < nlp->nvars);
2731 assert(nlp->varmap_nlp2nlpi[nlp->varmap_nlpi2nlp[i]] == i);
2732 }
2733 }
2734
2735 nlp->nvars_solver -= c;
2736 nlp->nunflushedvardel = 0;
2737
2738 /* cleanup */
2739 SCIPsetFreeBufferArray(set, &colset);
2740
2741 return SCIP_OKAY;
2742 }
2743
2744 /** adds nonlinear rows to NLPI problem that have been added to NLP before
2745 *
2746 * assumes that there are no pending variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2747 */
2748 static
2749 SCIP_RETCODE nlpFlushNlRowAdditions(
2750 SCIP_NLP* nlp, /**< NLP data */
2751 BMS_BLKMEM* blkmem, /**< block memory */
2752 SCIP_SET* set, /**< global SCIP settings */
2753 SCIP_STAT* stat /**< problem statistics */
2754 )
2755 {
2756 int c, i;
2757 SCIP_NLROW* nlrow;
2758 SCIP_Real* lhss;
2759 SCIP_Real* rhss;
2760 int* nlinvars;
2761 int** linidxs;
2762 SCIP_Real** lincoefs;
2763 SCIP_EXPR** exprs;
2764 const char** names;
2765
2766 assert(nlp != NULL);
2767 assert(blkmem != NULL);
2768 assert(set != NULL);
2769 assert(nlp->nunflushednlrowadd >= 0);
2770 assert(nlp->nunflushedvaradd == 0);
2771 assert(nlp->nunflushedvardel == 0);
2772 assert(!nlp->indiving);
2773
2774 if( nlp->nunflushednlrowadd == 0 )
2775 {
2776 #ifndef NDEBUG
2777 /* check that there are really no pending additions of variables */
2778 for( i = 0; i < nlp->nnlrows; ++i )
2779 assert(nlp->nlrows[i]->nlpiindex >= 0);
2780 #endif
2781 return SCIP_OKAY;
2782 }
2783
2784 assert(nlp->solver != NULL);
2785 assert(nlp->problem != NULL);
2786
2787 SCIP_CALL( nlpEnsureNlRowsSolverSize(nlp, blkmem, set, nlp->nnlrows_solver + nlp->nunflushednlrowadd) );
2788
2789 SCIP_CALL( SCIPsetAllocBufferArray(set, &lhss, nlp->nunflushednlrowadd) );
2790 SCIP_CALL( SCIPsetAllocBufferArray(set, &rhss, nlp->nunflushednlrowadd) );
2791 SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinvars, nlp->nunflushednlrowadd) );
2792 SCIP_CALL( SCIPsetAllocBufferArray(set, &linidxs, nlp->nunflushednlrowadd) );
2793 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nunflushednlrowadd) );
2794 SCIP_CALL( SCIPsetAllocBufferArray(set, &exprs, nlp->nunflushednlrowadd) );
2795 #if ADDNAMESTONLPI
2796 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushednlrowadd) );
2797 #else
2798 names = NULL;
2799 #endif
2800
2801 c = 0;
2802 for( i = 0; i < nlp->nnlrows; ++i )
2803 {
2804 nlrow = nlp->nlrows[i];
2805 assert(nlrow != NULL);
2806
2807 /* skip nonlinear rows already in NLPI problem */
2808 if( nlrow->nlpiindex >= 0 )
2809 continue;
2810 assert(c < nlp->nunflushednlrowadd);
2811
2812 /* get indices in NLPI */
2813 SCIP_CALL( nlpSetupNlpiIndices(nlp, set, nlrow, &linidxs[c]) );
2814 assert(linidxs[c] != NULL || nlrow->nlinvars == 0);
2815
2816 nlp->nlrowmap_nlpi2nlp[nlp->nnlrows_solver+c] = i;
2817 nlrow->nlpiindex = nlp->nnlrows_solver+c;
2818
2819 lhss[c] = nlrow->lhs;
2820 rhss[c] = nlrow->rhs;
2821 if( nlrow->constant != 0.0 )
2822 {
2823 if( !SCIPsetIsInfinity(set, -nlrow->lhs) )
2824 lhss[c] -= nlrow->constant;
2825 if( !SCIPsetIsInfinity(set, nlrow->rhs) )
2826 rhss[c] -= nlrow->constant;
2827 }
2828 if( rhss[c] < lhss[c] )
2829 {
2830 assert(SCIPsetIsEQ(set, lhss[c], rhss[c]));
2831 rhss[c] = lhss[c];
2832 }
2833
2834 nlinvars[c] = nlrow->nlinvars;
2835 lincoefs[c] = nlrow->lincoefs;
2836
2837 if( nlrow->expr != NULL )
2838 {
2839 /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */
2840 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &exprs[c], mapvar2varidx, (void*)nlp, NULL, NULL) );
2841 }
2842 else
2843 exprs[c] = NULL;
2844
2845 #if ADDNAMESTONLPI
2846 names[c] = nlrow->name;
2847 #endif
2848
2849 ++c;
2850
2851 #ifdef NDEBUG
2852 /* have c vars to add already, there can be no more */
2853 if( c == nlp->nunflushednlrowadd )
2854 break;
2855 #endif
2856 }
2857 assert(c == nlp->nunflushednlrowadd);
2858
2859 nlp->nnlrows_solver += c;
2860
2861 SCIP_CALL( SCIPnlpiAddConstraints(set, nlp->solver, nlp->problem, c, lhss, rhss,
2862 nlinvars, linidxs, lincoefs,
2863 exprs,
2864 names) );
2865
2866 for( c = nlp->nunflushednlrowadd - 1; c >= 0 ; --c )
2867 {
2868 if( linidxs[c] != NULL )
2869 SCIPsetFreeBufferArray(set, &linidxs[c]);
2870 if( exprs[c] != NULL )
2871 {
2872 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &exprs[c]) );
2873 }
2874 }
2875
2876 #if ADDNAMESTONLPI
2877 SCIPsetFreeBufferArray(set, &names);
2878 #endif
2879 SCIPsetFreeBufferArray(set, &exprs);
2880 SCIPsetFreeBufferArray(set, &lincoefs);
2881 SCIPsetFreeBufferArray(set, &linidxs);
2882 SCIPsetFreeBufferArray(set, &nlinvars);
2883 SCIPsetFreeBufferArray(set, &rhss);
2884 SCIPsetFreeBufferArray(set, &lhss);
2885
2886 nlp->nunflushednlrowadd = 0;
2887
2888 return SCIP_OKAY;
2889 }
2890
2891
2892 /** adds variables to NLPI problem that have been added to NLP before
2893 *
2894 * may set nlp->objflushed to FALSE if a variable with nonzero objective coefficient is added to the NLPI problem
2895 */
2896 static
2897 SCIP_RETCODE nlpFlushVarAdditions(
2898 SCIP_NLP* nlp, /**< NLP data */
2899 BMS_BLKMEM* blkmem, /**< block memory */
2900 SCIP_SET* set /**< global SCIP settings */
2901 )
2902 {
2903 int i, c;
2904 SCIP_Real* lbs;
2905 SCIP_Real* ubs;
2906 const char** names;
2907
2908 assert(nlp != NULL);
2909 assert(blkmem != NULL);
2910 assert(set != NULL);
2911 assert(nlp->nunflushedvaradd >= 0);
2912 assert(!nlp->indiving);
2913
2914 if( nlp->nunflushedvaradd == 0 )
2915 {
2916 #ifndef NDEBUG
2917 /* check that there are really no pending additions of variables */
2918 for( i = 0; i < nlp->nvars; ++i )
2919 assert(nlp->varmap_nlp2nlpi[i] >= 0);
2920 #endif
2921 return SCIP_OKAY;
2922 }
2923
2924 assert(nlp->solver != NULL);
2925 assert(nlp->problem != NULL);
2926
2927 SCIP_CALL( nlpEnsureVarsSolverSize(nlp, blkmem, set, nlp->nvars_solver + nlp->nunflushedvaradd) );
2928
2929 SCIP_CALL( SCIPsetAllocBufferArray(set, &lbs, nlp->nunflushedvaradd) );
2930 SCIP_CALL( SCIPsetAllocBufferArray(set, &ubs, nlp->nunflushedvaradd) );
2931 #if ADDNAMESTONLPI
2932 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushedvaradd) );
2933 #else
2934 names = NULL;
2935 #endif
2936
2937 c = 0;
2938 for( i = 0; i < nlp->nvars; ++i )
2939 {
2940 /* skip variables already in NLPI problem */
2941 if( nlp->varmap_nlp2nlpi[i] >= 0 )
2942 continue;
2943 assert(c < nlp->nunflushedvaradd);
2944
2945 nlp->varmap_nlpi2nlp[nlp->nvars_solver+c] = i;
2946 nlp->varmap_nlp2nlpi[i] = nlp->nvars_solver+c;
2947 lbs[c] = SCIPvarGetLbLocal(nlp->vars[i]);
2948 ubs[c] = SCIPvarGetUbLocal(nlp->vars[i]);
2949 #if ADDNAMESTONLPI
2950 names[c] = SCIPvarGetName(nlp->vars[i]);
2951 #endif
2952 ++c;
2953
2954 /* if the new variable has a nonzero objective coefficient, then the objective need to be updated */
2955 if( !SCIPsetIsZero(set, SCIPvarGetObj(nlp->vars[i])) )
2956 nlp->objflushed = FALSE;
2957
2958 #ifdef NDEBUG
2959 /* have c vars to add already, there can be no more */
2960 if( c == nlp->nunflushedvaradd )
2961 break;
2962 #endif
2963 }
2964 assert(c == nlp->nunflushedvaradd);
2965
2966 nlp->nvars_solver += c;
2967
2968 SCIP_CALL( SCIPnlpiAddVars(set, nlp->solver, nlp->problem, c, lbs, ubs, names) );
2969
2970 #if ADDNAMESTONLPI
2971 SCIPsetFreeBufferArray(set, &names);
2972 #endif
2973 SCIPsetFreeBufferArray(set, &ubs);
2974 SCIPsetFreeBufferArray(set, &lbs);
2975
2976 nlp->nunflushedvaradd = 0;
2977
2978 return SCIP_OKAY;
2979 }
2980
2981 /** updates the objective in the NLPI problem, if necessary
2982 *
2983 * assumes that there are no unflushed variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2984 */
2985 static
2986 SCIP_RETCODE nlpFlushObjective(
2987 SCIP_NLP* nlp, /**< NLP data */
2988 BMS_BLKMEM* blkmem, /**< block memory */
2989 SCIP_SET* set /**< global SCIP settings */
2990 )
2991 {
2992 int* linindices;
2993 SCIP_Real* lincoefs;
2994 SCIP_Real coef;
2995 int i;
2996 int nz;
2997
2998 assert(nlp != NULL);
2999 assert(blkmem != NULL);
3000 assert(set != NULL);
3001 assert(nlp->nunflushedvaradd == 0);
3002 assert(nlp->nunflushedvardel == 0);
3003 assert(!nlp->indiving);
3004
3005 if( nlp->objflushed )
3006 return SCIP_OKAY;
3007
3008 assert(nlp->solver != NULL);
3009 assert(nlp->problem != NULL);
3010
3011 /* assemble coefficients */
3012 SCIP_CALL( SCIPsetAllocBufferArray(set, &linindices, nlp->nvars_solver) );
3013 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nvars_solver) );
3014
3015 nz = 0;
3016 for( i = 0; i < nlp->nvars_solver; ++i )
3017 {
3018 assert(nlp->varmap_nlpi2nlp[i] >= 0); /* there should be no variable deletions pending */
3019
3020 coef = SCIPvarGetObj(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
3021 if( SCIPsetIsZero(set, coef) )
3022 continue;
3023
3024 linindices[nz] = i;
3025 lincoefs[nz] = coef;
3026 ++nz;
3027 }
3028
3029 SCIP_CALL( SCIPnlpiSetObjective(set, nlp->solver, nlp->problem,
3030 nz, linindices, lincoefs,
3031 NULL,
3032 0.0) );
3033
3034 SCIPsetFreeBufferArray(set, &lincoefs);
3035 SCIPsetFreeBufferArray(set, &linindices);
3036
3037 nlp->objflushed = TRUE;
3038
3039 return SCIP_OKAY;
3040 }
3041
3042 /** solves the NLP (or diving NLP), assuming it has been flushed already */
3043 static
3044 SCIP_RETCODE nlpSolve(
3045 SCIP_NLP* nlp, /**< NLP data */
3046 BMS_BLKMEM* blkmem, /**< block memory buffers */
3047 SCIP_SET* set, /**< global SCIP settings */
3048 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3049 SCIP_STAT* stat, /**< problem statistics */
3050 SCIP_PRIMAL* primal, /**< primal data */
3051 SCIP_TREE* tree, /**< branch and bound tree */
3052 SCIP_NLPPARAM* nlpparam /**< NLP solve parameters */
3053 )
3054 {
3055 int i;
3056
3057 assert(nlp != NULL);
3058 assert(blkmem != NULL);
3059 assert(set != NULL);
3060 assert(stat != NULL);
3061
3062 if( nlp->solver == NULL )
3063 {
3064 SCIPmessagePrintWarning(messagehdlr, "Attempted to solve NLP, but no solver available.\n");
3065
3066 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3067 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3068
3069 return SCIP_OKAY;
3070 }
3071
3072 assert(nlp->solver != NULL);
3073 assert(nlp->problem != NULL);
3074
3075 /* set initial guess, if available and warmstart hasn't been enabled
3076 * when using the NLP, passing a dual solution with the initguess is not available at the moment (TODO),
3077 * so a warmstart has to start from the last solution stored in the NLPI
3078 */
3079 if( nlp->haveinitguess && !nlpparam->warmstart )
3080 {
3081 /* @todo should we not set it if we had set it already? (initguessflushed...) */
3082 SCIP_Real* initialguess_solver;
3083 int nlpidx;
3084
3085 assert(nlp->initialguess != NULL);
3086
3087 SCIP_CALL( SCIPsetAllocBufferArray(set, &initialguess_solver, nlp->nvars_solver) );
3088
3089 for( i = 0; i < nlp->nvars_solver; ++i )
3090 {
3091 nlpidx = nlp->varmap_nlpi2nlp[i];
3092 assert(nlpidx >= 0);
3093 assert(nlpidx < nlp->nvars);
3094
3095 initialguess_solver[i] = nlp->initialguess[nlpidx];
3096 }
3097 SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, initialguess_solver, NULL, NULL, NULL) );
3098
3099 SCIPsetFreeBufferArray(set, &initialguess_solver);
3100 }
3101
3102 /* let NLP solver do his work */
3103 SCIPclockStart(stat->nlpsoltime, set);
3104
3105 SCIP_CALL( SCIPnlpiSolve(set, stat, nlp->solver, nlp->problem, nlpparam) );
3106
3107 SCIPclockStop(stat->nlpsoltime, set);
3108 ++stat->nnlps;
3109
3110 nlp->termstat = SCIPnlpiGetTermstat(set, nlp->solver, nlp->problem);
3111 nlp->solstat = SCIPnlpiGetSolstat(set, nlp->solver, nlp->problem);
3112 switch( nlp->solstat )
3113 {
3114 case SCIP_NLPSOLSTAT_GLOBOPT:
3115 case SCIP_NLPSOLSTAT_LOCOPT:
3116 case SCIP_NLPSOLSTAT_FEASIBLE:
3117 case SCIP_NLPSOLSTAT_LOCINFEASIBLE:
3118 {
3119 SCIP_Real* primalvals;
3120 SCIP_Real* nlrowdualvals;
3121 SCIP_Real* varlbdualvals;
3122 SCIP_Real* varubdualvals;
3123
3124 primalvals = NULL;
3125 nlrowdualvals = NULL;
3126 varlbdualvals = NULL;
3127 varubdualvals = NULL;
3128
3129 /* get NLP solution */
3130 SCIP_CALL( SCIPnlpiGetSolution(set, nlp->solver, nlp->problem, &primalvals, &nlrowdualvals, &varlbdualvals, &varubdualvals, NULL) );
3131 assert(primalvals != NULL || nlp->nvars == 0);
3132 assert((varlbdualvals != NULL) == (varubdualvals != NULL)); /* if there are duals for one bound, then there should also be duals for the other bound */
3133
3134 /* store solution primal values in variable and evaluate objective function */
3135 if( nlp->indiving && nlp->divingobj != NULL )
3136 {
3137 for( i = 0; i < nlp->nvars; ++i )
3138 {
3139 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, primalvals[nlp->varmap_nlp2nlpi[i]]) ); /*lint !e613 */
3140 }
3141
3142 /* evaluate modified diving objective */
3143 SCIP_CALL( SCIPnlrowGetNLPActivity(nlp->divingobj, blkmem, set, stat, primal, tree, nlp, &nlp->primalsolobjval) );
3144 }
3145 else
3146 {
3147 /* evaluate SCIP objective function */
3148 nlp->primalsolobjval = 0.0;
3149 for( i = 0; i < nlp->nvars; ++i )
3150 {
3151 SCIP_Real solval = primalvals[nlp->varmap_nlp2nlpi[i]]; /*lint !e613 */
3152
3153 /* do a quick assert that variable bounds are satisfied, if feasibility is claimed */
3154 assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(nlp->vars[i])) ||
3155 SCIPsetIsFeasGE(set, solval, SCIPvarGetLbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3156 assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(nlp->vars[i])) ||
3157 SCIPsetIsFeasLE(set, solval, SCIPvarGetUbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3158
3159 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, solval) ); /*lint !e613 */
3160 nlp->primalsolobjval += SCIPvarGetObj(nlp->vars[i]) * solval; /*lint !e613 */
3161 }
3162 }
3163
3164 /* store solution dual values in nlrows and variables */
3165 for( i = 0; i < nlp->nnlrows; ++i )
3166 {
3167 assert(nlp->nlrows[i]->nlpiindex >= 0); /* NLP was flushed before solve, so all nlrows should be in there */
3168
3169 nlp->nlrows[i]->dualsol = nlrowdualvals != NULL ? nlrowdualvals[nlp->nlrows[i]->nlpiindex] : 0.0;
3170
3171 /* SCIPsetDebugMsg(set, "dual of nlrow <%s> = %g\n", nlp->nlrows[i]->name, nlp->nlrows[i]->dualsol); */
3172 }
3173 assert(nlp->varlbdualvals != NULL || nlp->nvars == 0);
3174 assert(nlp->varubdualvals != NULL || nlp->nvars == 0);
3175 if( varlbdualvals != NULL )
3176 {
3177 for( i = 0; i < nlp->nvars; ++i )
3178 {
3179 assert(nlp->varmap_nlp2nlpi[i] >= 0); /* NLP was flushed before solve, so all vars should be in there */
3180
3181 nlp->varlbdualvals[i] = varlbdualvals[nlp->varmap_nlp2nlpi[i]];
3182 nlp->varubdualvals[i] = varubdualvals[nlp->varmap_nlp2nlpi[i]];
3183
3184 /* SCIPsetDebugMsg(set, "duals of var <%s> = %g %g\n", SCIPvarGetName(nlp->vars[i]), nlp->varlbdualvals[i], nlp->varubdualvals[i]); */
3185 }
3186 }
3187 else if( nlp->nvars > 0 )
3188 {
3189 BMSclearMemoryArray(nlp->varlbdualvals, nlp->nvars);
3190 BMSclearMemoryArray(nlp->varubdualvals, nlp->nvars);
3191 }
3192
3193 break;
3194 }
3195 default:
3196 nlp->primalsolobjval = SCIP_INVALID;
3197 break;
3198 } /*lint !e788*/
3199
3200 return SCIP_OKAY;
3201 }
3202
3203 /** assembles list of fractional variables in last NLP solution */
3204 static
3205 SCIP_RETCODE nlpCalcFracVars(
3206 SCIP_NLP* nlp, /**< NLP data */
3207 BMS_BLKMEM* blkmem, /**< block memory buffers */
3208 SCIP_SET* set, /**< global SCIP settings */
3209 SCIP_STAT* stat /**< problem statistics */
3210 )
3211 {
3212 assert(nlp != NULL);
3213 assert(blkmem != NULL);
3214 assert(set != NULL);
3215 assert(stat != NULL);
3216 assert(nlp->validfracvars <= stat->nnlps);
3217 assert(SCIPnlpHasSolution(nlp));
3218
3219 SCIPsetDebugMsg(set, "calculating NLP fractional variables: validfracvars=%" SCIP_LONGINT_FORMAT ", nnlps=%" SCIP_LONGINT_FORMAT "\n", nlp->validfracvars, stat->nnlps);
3220
3221 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
3222 {
3223 nlp->nfracvars = 0;
3224 nlp->npriofracvars = 0;
3225 nlp->validfracvars = stat->nnlps;
3226
3227 SCIPsetDebugMsg(set, "NLP globally infeasible, unbounded, or worse -> no solution values -> no fractional variables\n");
3228 return SCIP_OKAY;
3229 }
3230
3231 /* check, if the current NLP fractional variables array is invalid */
3232 if( nlp->validfracvars < stat->nnlps )
3233 {
3234 SCIP_VAR* var;
3235 SCIP_Real primsol;
3236 SCIP_Real frac;
3237 int branchpriority;
3238 int insertpos;
3239 int maxpriority;
3240 int i;
3241
3242 SCIPsetDebugMsg(set, " -> recalculating NLP fractional variables\n");
3243
3244 if( nlp->fracvarssize == 0 )
3245 {
3246 assert(nlp->fracvars == NULL);
3247 assert(nlp->fracvarssol == NULL);
3248 assert(nlp->fracvarsfrac == NULL);
3249 nlp->fracvarssize = 5;
3250 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize) );
3251 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize) );
3252 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize) );
3253 }
3254
3255 maxpriority = INT_MIN;
3256 nlp->nfracvars = 0;
3257 nlp->npriofracvars = 0;
3258 for( i = 0; i < nlp->nvars; ++i )
3259 {
3260 var = nlp->vars[i];
3261 assert(var != NULL);
3262
3263 primsol = SCIPvarGetNLPSol(var);
3264 assert(primsol < SCIP_INVALID);
3265
3266 /* consider only binary and integer variables */
3267 if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER )
3268 continue;
3269
3270 /* ignore fixed variables (due to numerics, it is possible, that the NLP solution of a fixed integer variable
3271 * (with large fixed value) is fractional in terms of absolute feasibility measure)
3272 */
3273 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
3274 continue;
3275
3276 /* check, if the LP solution value is fractional */
3277 frac = SCIPsetFeasFrac(set, primsol);
3278
3279 /* The fractionality should not be smaller than -feastol, however, if the primsol is large enough
3280 * and close to an integer, fixed precision floating point arithmetic might give us values slightly
3281 * smaller than -feastol. Originally, the "frac >= -feastol"-check was within SCIPsetIsFeasFracIntegral(),
3282 * however, we relaxed it to "frac >= -2*feastol" and have the stricter check here for small-enough primsols.
3283 */
3284 assert(SCIPsetIsGE(set, frac, -SCIPsetFeastol(set)) || (primsol > 1e14 * SCIPsetFeastol(set)));
3285
3286 if( SCIPsetIsFeasFracIntegral(set, frac) )
3287 continue;
3288
3289 /* ensure enough space in fracvars arrays */
3290 if( nlp->fracvarssize <= nlp->nfracvars )
3291 {
3292 int newsize;
3293
3294 newsize = SCIPsetCalcMemGrowSize(set, nlp->nfracvars + 1);
3295 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize, newsize) );
3296 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize, newsize) );
3297 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize, newsize) );
3298 nlp->fracvarssize = newsize;
3299 }
3300 assert(nlp->nfracvars < nlp->fracvarssize);
3301 assert(nlp->fracvars != NULL);
3302 assert(nlp->fracvarssol != NULL);
3303 assert(nlp->fracvarsfrac != NULL);
3304
3305 /* insert candidate in candidate list */
3306 branchpriority = SCIPvarGetBranchPriority(var);
3307 insertpos = nlp->nfracvars;
3308 nlp->nfracvars++;
3309 if( branchpriority > maxpriority )
3310 {
3311 /* candidate has higher priority than the current maximum:
3312 * move it to the front and declare it to be the single best candidate
3313 */
3314 if( insertpos != 0 )
3315 {
3316 nlp->fracvars[insertpos] = nlp->fracvars[0];
3317 nlp->fracvarssol[insertpos] = nlp->fracvarssol[0];
3318 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[0];
3319 insertpos = 0;
3320 }
3321 nlp->npriofracvars = 1;
3322 maxpriority = branchpriority;
3323 }
3324 else if( branchpriority == maxpriority )
3325 {
3326 /* candidate has equal priority as the current maximum:
3327 * move away the first non-maximal priority candidate, move the current candidate to the correct
3328 * slot (binaries first) and increase the number of maximal priority candidates
3329 */
3330 if( insertpos != nlp->npriofracvars )
3331 {
3332 nlp->fracvars[insertpos] = nlp->fracvars[nlp->npriofracvars];
3333 nlp->fracvarssol[insertpos] = nlp->fracvarssol[nlp->npriofracvars];
3334 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[nlp->npriofracvars];
3335 insertpos = nlp->npriofracvars;
3336 }
3337 ++nlp->npriofracvars;
3338 }
3339 nlp->fracvars[insertpos] = var;
3340 nlp->fracvarssol[insertpos] = primsol;
3341 nlp->fracvarsfrac[insertpos] = frac;
3342
3343 SCIPsetDebugMsg(set, " -> candidate %d: var=<%s>, sol=%g, frac=%g, prio=%d (max: %d) -> pos %d\n",
3344 nlp->nfracvars, SCIPvarGetName(var), primsol, frac, branchpriority, maxpriority, insertpos);
3345 }
3346
3347 nlp->validfracvars = stat->nnlps;
3348 }
3349 assert(0 <= nlp->npriofracvars);
3350 assert(nlp->npriofracvars <= nlp->nfracvars);
3351
3352 SCIPsetDebugMsg(set, " -> %d fractional variables (%d of maximal priority)\n", nlp->nfracvars, nlp->npriofracvars);
3353
3354 return SCIP_OKAY;
3355 }
3356
3357 /** event handling for variable events */
3358 static
3359 SCIP_DECL_EVENTEXEC(eventExecNlp)
3360 {
3361 SCIP_EVENTTYPE etype;
3362 SCIP_VAR* var;
3363
3364 assert(scip != NULL);
3365 assert(eventhdlr != NULL);
3366 assert(event != NULL);
3367 assert(eventdata != NULL);
3368
3369 assert((SCIP_NLP*)eventdata == scip->nlp);
3370
3371 etype = SCIPeventGetType(event);
3372 var = SCIPeventGetVar(event);
3373
3374 if( SCIP_EVENTTYPE_VARADDED & etype )
3375 {
3376 SCIPdebugMessage("-> handling varadd event, variable <%s>\n", SCIPvarGetName(var) );
3377 SCIP_CALL( SCIPnlpAddVar(scip->nlp, SCIPblkmem(scip), scip->set, var) );
3378 }
3379 else if( SCIP_EVENTTYPE_VARDELETED & etype )
3380 {
3381 SCIPdebugMessage("-> handling vardel event, variable <%s>\n", SCIPvarGetName(var) );
3382 SCIP_CALL( SCIPnlpDelVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3383 }
3384 else if( SCIP_EVENTTYPE_VARFIXED & etype )
3385 {
3386 /* variable was fixed, aggregated, or multi-aggregated */
3387 /* TODO is this ever happening? that is, can we have changes in a variable status during solve? */
3388 SCIPdebugMessage("-> handling variable fixation event, variable <%s>\n", SCIPvarGetName(var) );
3389 SCIP_CALL( nlpRemoveFixedVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3390 }
3391 else if( SCIP_EVENTTYPE_BOUNDCHANGED & etype )
3392 {
3393 SCIPdebugMessage("-> handling bound changed event %" SCIP_EVENTTYPE_FORMAT ", variable <%s>\n", etype, SCIPvarGetName(var) );
3394 SCIP_CALL( nlpUpdateVarBounds(scip->nlp, scip->set, var, (SCIP_Bool)(SCIP_EVENTTYPE_BOUNDTIGHTENED & etype)) );
3395 }
3396 else if( SCIP_EVENTTYPE_OBJCHANGED & etype )
3397 {
3398 SCIPdebugMessage("-> handling objchg event, variable <%s>\n", SCIPvarGetName(var) );
3399 SCIP_CALL( nlpUpdateObjCoef(scip->set, scip->nlp, var) );
3400 }
3401 else
3402 {
3403 SCIPerrorMessage("unexpected event %" SCIP_EVENTTYPE_FORMAT " on variable <%s>\n", etype, SCIPvarGetName(var) );
3404 return SCIP_ERROR;
3405 }
3406
3407 return SCIP_OKAY;
3408 }
3409
3410
3411 /*
3412 * public NLP methods
3413 */
3414
3415 /** includes event handler that is used by NLP */
3416 SCIP_RETCODE SCIPnlpInclude(
3417 SCIP_SET* set, /**< global SCIP settings */
3418 BMS_BLKMEM* blkmem /**< block memory */
3419 )
3420 {
3421 SCIP_EVENTHDLR* eventhdlr;
3422
3423 assert(set != NULL);
3424 assert(blkmem != NULL);
3425 assert(set->stage == SCIP_STAGE_INIT);
3426
3427 /* check whether event handler is already present */
3428 if( SCIPsetFindEventhdlr(set, EVENTHDLR_NAME) != NULL )
3429 {
3430 SCIPerrorMessage("event handler <" EVENTHDLR_NAME "> already included.\n");
3431 return SCIP_INVALIDDATA;
3432 }
3433
3434 SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC,
3435 NULL, NULL, NULL, NULL, NULL, NULL, NULL, eventExecNlp, NULL) );
3436 SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) );
3437
3438 return SCIP_OKAY;
3439 } /*lint !e715*/
3440
3441 /** construct a new empty NLP */
3442 SCIP_RETCODE SCIPnlpCreate(
3443 SCIP_NLP** nlp, /**< NLP handler, call by reference */
3444 BMS_BLKMEM* blkmem, /**< block memory */
3445 SCIP_SET* set, /**< global SCIP settings */
3446 SCIP_STAT* stat, /**< problem statistics */
3447 const char* name, /**< problem name */
3448 int nvars_estimate /**< an estimate on the number of variables that may be added to the NLP later */
3449 )
3450 {
3451 assert(nlp != NULL);
3452 assert(blkmem != NULL);
3453 assert(set != NULL);
3454 assert(stat != NULL);
3455 assert(name != NULL);
3456
3457 SCIP_ALLOC( BMSallocMemory(nlp) );
3458
3459 /* select NLP solver (if any available) and setup problem */
3460 if( set->nnlpis > 0 )
3461 {
3462 assert(set->nlp_solver != NULL);
3463 if( set->nlp_solver[0] == '\0' )
3464 { /* take solver with highest priority */
3465 assert(set->nlpis != NULL);
3466
3467 /* sort the NLPIs if necessary */
3468 if( !set->nlpissorted )
3469 SCIPsetSortNlpis(set);
3470
3471 (*nlp)->solver = set->nlpis[0];
3472 }
3473 else
3474 { /* find user specified NLP solver */
3475 (*nlp)->solver = SCIPsetFindNlpi(set, set->nlp_solver);
3476 if( (*nlp)->solver == NULL )
3477 {
3478 SCIPerrorMessage("Selected NLP solver <%s> not available.\n", set->nlp_solver);
3479 return SCIP_PLUGINNOTFOUND;
3480 }
3481 }
3482 assert((*nlp)->solver != NULL);
3483 SCIP_CALL( SCIPnlpiCreateProblem(set, (*nlp)->solver, &(*nlp)->problem, name) );
3484 }
3485 else
3486 {
3487 /* maybe someone wanna use the NLP just to collect nonlinearities, but is not necessarily interesting on solving
3488 * so we allow this and just continue */
3489 (*nlp)->solver = NULL;
3490 (*nlp)->problem = NULL;
3491 }
3492
3493 /* status */
3494 (*nlp)->nunflushedvaradd = 0;
3495 (*nlp)->nunflushedvardel = 0;
3496 (*nlp)->nunflushednlrowadd = 0;
3497 (*nlp)->nunflushednlrowdel = 0;
3498 (*nlp)->indiving = FALSE;
3499
3500 /* variables in problem and NLPI problem */
3501 (*nlp)->nvars = 0;
3502 (*nlp)->sizevars = 0;
3503 (*nlp)->vars = NULL;
3504 SCIP_CALL( SCIPhashmapCreate(&(*nlp)->varhash, blkmem, nvars_estimate) );
3505
3506 (*nlp)->nvars_solver = 0;
3507 (*nlp)->sizevars_solver = 0;
3508 (*nlp)->varmap_nlp2nlpi = NULL;
3509 (*nlp)->varmap_nlpi2nlp = NULL;
3510
3511 /* nonlinear rows in problem and NLPI problem */
3512 (*nlp)->nnlrows = 0;
3513 (*nlp)->sizenlrows = 0;
3514 (*nlp)->nlrows = NULL;
3515
3516 (*nlp)->nnlrows_solver = 0;
3517 (*nlp)->sizenlrows_solver = 0;
3518 (*nlp)->nlrowmap_nlpi2nlp = NULL;
3519
3520 /* objective function */
3521 (*nlp)->objflushed = TRUE;
3522 (*nlp)->divingobj = NULL;
3523
3524 /* initial guess */
3525 (*nlp)->haveinitguess = FALSE;
3526 (*nlp)->initialguess = NULL;
3527
3528 /* solution of NLP */
3529 (*nlp)->primalsolobjval = SCIP_INVALID;
3530 (*nlp)->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3531 (*nlp)->termstat = SCIP_NLPTERMSTAT_OTHER;
3532 (*nlp)->varlbdualvals = NULL;
3533 (*nlp)->varubdualvals = NULL;
3534
3535 /* event handling: catch variable addition and deletion events */
3536 (*nlp)->eventhdlr = SCIPsetFindEventhdlr(set, EVENTHDLR_NAME);
3537 if( (*nlp)->eventhdlr == NULL )
3538 {
3539 SCIPerrorMessage("NLP eventhandler <" EVENTHDLR_NAME "> not found.\n");
3540 return SCIP_PLUGINNOTFOUND;
3541 }
3542 SCIP_CALL( SCIPeventfilterAdd(set->scip->eventfilter, blkmem, set,
3543 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3544 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), &(*nlp)->globalfilterpos) );
3545
3546 /* fractional variables in last NLP solution */
3547 (*nlp)->fracvars = NULL;
3548 (*nlp)->fracvarssol = NULL;
3549 (*nlp)->fracvarsfrac = NULL;
3550 (*nlp)->nfracvars = 0;
3551 (*nlp)->npriofracvars = 0;
3552 (*nlp)->fracvarssize = 0;
3553 (*nlp)->validfracvars = -1;
3554
3555 /* miscellaneous */
3556 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlp)->name, name, strlen(name)+1) );
3557
3558 return SCIP_OKAY;
3559 }
3560
3561 /** frees NLP data object */
3562 SCIP_RETCODE SCIPnlpFree(
3563 SCIP_NLP** nlp, /**< pointer to NLP data object */
3564 BMS_BLKMEM* blkmem, /**< block memory */
3565 SCIP_SET* set, /**< global SCIP settings */
3566 SCIP_STAT* stat, /**< problem statistics */
3567 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3568 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */
3569 )
3570 {
3571 assert(nlp != NULL);
3572 assert(*nlp != NULL);
3573 assert(blkmem != NULL);
3574 assert(set != NULL);
3575
3576 /* drop fractional variables */
3577 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvars, (*nlp)->fracvarssize);
3578 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarssol, (*nlp)->fracvarssize);
3579 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarsfrac, (*nlp)->fracvarssize);
3580
3581 /* drop global events (variable addition and deletion) */
3582 SCIP_CALL( SCIPeventfilterDel(set->scip->eventfilter, blkmem, set,
3583 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3584 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), (*nlp)->globalfilterpos) );
3585
3586 SCIP_CALL( SCIPnlpReset(*nlp, blkmem, set, stat, eventqueue, lp) );
3587 assert((*nlp)->nnlrows == 0);
3588 assert((*nlp)->nnlrows_solver == 0);
3589 assert((*nlp)->nvars == 0);
3590 assert((*nlp)->nvars_solver == 0);
3591 assert((*nlp)->initialguess == NULL);
3592
3593 BMSfreeBlockMemoryArray(blkmem, &(*nlp)->name, strlen((*nlp)->name)+1);
3594
3595 /* free nonlinear rows arrays */
3596 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrowmap_nlpi2nlp, (*nlp)->sizenlrows_solver);
3597 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrows, (*nlp)->sizenlrows);
3598
3599 /* free variables arrays */
3600 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlp2nlpi, (*nlp)->sizevars);
3601 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlpi2nlp, (*nlp)->sizevars_solver);
3602 SCIPhashmapFree(&(*nlp)->varhash);
3603 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->vars, (*nlp)->sizevars);
3604 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varlbdualvals, (*nlp)->sizevars);
3605 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varubdualvals, (*nlp)->sizevars);
3606
3607 /* free NLPI problem */
3608 if( (*nlp)->problem != NULL )
3609 {
3610 SCIP_CALL( SCIPnlpiFreeProblem(set, (*nlp)->solver, &(*nlp)->problem) );
3611 }
3612
3613 /* free NLP data structure */
3614 BMSfreeMemory(nlp);
3615
3616 return SCIP_OKAY;
3617 }
3618
3619 /** resets the NLP to the empty NLP by removing all variables and rows from NLP,
3620 * releasing all rows, and flushing the changes to the NLP solver
3621 */
3622 SCIP_RETCODE SCIPnlpReset(
3623 SCIP_NLP* nlp, /**< NLP data */
3624 BMS_BLKMEM* blkmem, /**< block memory */
3625 SCIP_SET* set, /**< global SCIP settings */
3626 SCIP_STAT* stat, /**< problem statistics data */
3627 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3628 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */
3629 )
3630 {
3631 int i;
3632
3633 assert(nlp != NULL);
3634 assert(blkmem != NULL);
3635 assert(set != NULL);
3636
3637 if( nlp->indiving )
3638 {
3639 SCIP_CALL( SCIPnlpEndDive(nlp, blkmem, set, stat) );
3640 }
3641
3642 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3643 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3644
3645 BMSfreeBlockMemoryArrayNull(blkmem, &nlp->initialguess, nlp->sizevars);
3646 nlp->haveinitguess = FALSE;
3647
3648 for(i = nlp->nnlrows - 1; i >= 0; --i)
3649 {
3650 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
3651 }
3652
3653 for(i = nlp->nvars - 1; i >= 0; --i)
3654 {
3655 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, i) );
3656 }
3657
3658 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3659
3660 return SCIP_OKAY;
3661 }
3662
3663 /** currently a dummy function that always returns TRUE */
3664 SCIP_Bool SCIPnlpHasCurrentNodeNLP(
3665 SCIP_NLP* nlp /**< NLP data */
3666 )
3667 {
3668 assert(nlp != NULL);
3669 return TRUE;
3670 } /*lint !e715*/
3671
3672 /** ensures, that variables array of NLP can store at least num entries */
3673 SCIP_RETCODE SCIPnlpEnsureVarsSize(
3674 SCIP_NLP* nlp, /**< NLP data */
3675 BMS_BLKMEM* blkmem, /**< block memory */
3676 SCIP_SET* set, /**< global SCIP settings */
3677 int num /**< minimum number of entries to store */
3678 )
3679 {
3680 assert(nlp != NULL);
3681 assert(blkmem != NULL);
3682 assert(set != NULL);
3683 assert(nlp->nvars <= nlp->sizevars);
3684
3685 if( num > nlp->sizevars )
3686 {
3687 int newsize;
3688
3689 newsize = SCIPsetCalcMemGrowSize(set, num);
3690 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->vars, nlp->sizevars, newsize) );
3691 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlp2nlpi, nlp->sizevars, newsize) );
3692 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varlbdualvals, nlp->sizevars, newsize) );
3693 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varubdualvals, nlp->sizevars, newsize) );
3694 if( nlp->initialguess != NULL )
3695 {
3696 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars, newsize) );
3697 }
3698
3699 nlp->sizevars = newsize;
3700 }
3701 assert(num <= nlp->sizevars);
3702
3703 return SCIP_OKAY;
3704 }
3705
3706 /** adds a variable to the NLP and captures the variable */
3707 SCIP_RETCODE SCIPnlpAddVar(
3708 SCIP_NLP* nlp, /**< NLP data */
3709 BMS_BLKMEM* blkmem, /**< block memory */
3710 SCIP_SET* set, /**< global SCIP settings */
3711 SCIP_VAR* var /**< variable */
3712 )
3713 {
3714 assert(nlp != NULL);
3715 assert(blkmem != NULL);
3716 assert(set != NULL);
3717 assert(var != NULL);
3718 assert(SCIPvarIsTransformed(var));
3719 assert(!SCIPhashmapExists(nlp->varhash, var));
3720
3721 if( nlp->indiving )
3722 {
3723 SCIPerrorMessage("cannot add variable during NLP diving\n");
3724 return SCIP_ERROR;
3725 }
3726
3727 SCIP_CALL( nlpAddVars(nlp, blkmem, set, 1, &var) );
3728
3729 return SCIP_OKAY;
3730 }
3731
3732 /** adds a set of variables to the NLP and captures the variables */
3733 SCIP_RETCODE SCIPnlpAddVars(
3734 SCIP_NLP* nlp, /**< NLP data */
3735 BMS_BLKMEM* blkmem, /**< block memory */
3736 SCIP_SET* set, /**< global SCIP settings */
3737 int nvars, /**< number of variables to add */
3738 SCIP_VAR** vars /**< variables to add */
3739 )
3740 {
3741 assert(nlp != NULL);
3742 assert(blkmem != NULL);
3743 assert(set != NULL);
3744 assert(vars != NULL || nvars == 0);
3745
3746 if( nlp->indiving && nvars > 0)
3747 {
3748 SCIPerrorMessage("cannot add variables during NLP diving\n");
3749 return SCIP_ERROR;
3750 }
3751
3752 SCIP_CALL( nlpAddVars(nlp, blkmem, set, nvars, vars) );
3753
3754 return SCIP_OKAY;
3755 }
3756
3757 /** deletes a variable from the NLP and releases the variable */
3758 SCIP_RETCODE SCIPnlpDelVar(
3759 SCIP_NLP* nlp, /**< NLP data */
3760 BMS_BLKMEM* blkmem, /**< block memory */
3761 SCIP_SET* set, /**< global SCIP settings */
3762 SCIP_STAT* stat, /**< problem statistics data */
3763 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3764 SCIP_LP* lp, /**< SCIP LP, needed to release variable */
3765 SCIP_VAR* var /**< variable */
3766 )
3767 {
3768 int varpos;
3769
3770 assert(nlp != NULL);
3771 assert(blkmem != NULL);
3772 assert(set != NULL);
3773 assert(var != NULL);
3774
3775 if( !SCIPhashmapExists(nlp->varhash, var) )
3776 {
3777 SCIPerrorMessage("variable <%s> not found in NLP, cannot delete\n", SCIPvarGetName(var));
3778 return SCIP_ERROR;
3779 }
3780
3781 if( nlp->indiving )
3782 {
3783 SCIPerrorMessage("cannot delete variable during NLP diving\n");
3784 return SCIP_ERROR;
3785 }
3786
3787 varpos = SCIPhashmapGetImageInt(nlp->varhash, var);
3788
3789 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, varpos) );
3790
3791 return SCIP_OKAY;
3792 }
3793
3794 /** ensures, that nonlinear rows array of NLP can store at least num entries */
3795 SCIP_RETCODE SCIPnlpEnsureNlRowsSize(
3796 SCIP_NLP* nlp, /**< NLP data */
3797 BMS_BLKMEM* blkmem, /**< block memory */
3798 SCIP_SET* set, /**< global SCIP settings */
3799 int num /**< minimum number of entries to store */
3800 )
3801 {
3802 assert(nlp != NULL);
3803 assert(blkmem != NULL);
3804 assert(set != NULL);
3805 assert(nlp->nnlrows <= nlp->sizenlrows);
3806
3807 if( num > nlp->sizenlrows )
3808 {
3809 int newsize;
3810
3811 newsize = SCIPsetCalcMemGrowSize(set, num);
3812 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrows, nlp->sizenlrows, newsize) );
3813
3814 nlp->sizenlrows = newsize;
3815 }
3816 assert(num <= nlp->sizenlrows);
3817
3818 return SCIP_OKAY;
3819 }
3820
3821 /** adds a nonlinear row to the NLP and captures it
3822 *
3823 * all variables of the row need to be present in the NLP
3824 */
3825 SCIP_RETCODE SCIPnlpAddNlRow(
3826 SCIP_NLP* nlp, /**< NLP data */
3827 BMS_BLKMEM* blkmem, /**< block memory */
3828 SCIP_SET* set, /**< global SCIP settings */
3829 SCIP_STAT* stat, /**< problem statistics data */
3830 SCIP_NLROW* nlrow /**< nonlinear row */
3831 )
3832 {
3833 assert(nlp != NULL);
3834 assert(nlrow != NULL);
3835
3836 if( nlp->indiving )
3837 {
3838 SCIPerrorMessage("cannot add row during NLP diving\n");
3839 return SCIP_ERROR;
3840 }
3841
3842 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, 1, &nlrow) );
3843
3844 return SCIP_OKAY;
3845 }
3846
3847 /** adds nonlinear rows to the NLP and captures them
3848 *
3849 * all variables of the row need to be present in the NLP
3850 */
3851 SCIP_RETCODE SCIPnlpAddNlRows(
3852 SCIP_NLP* nlp, /**< NLP data */
3853 BMS_BLKMEM* blkmem, /**< block memory */
3854 SCIP_SET* set, /**< global SCIP settings */
3855 SCIP_STAT* stat, /**< problem statistics data */
3856 int nnlrows, /**< number of rows to add */
3857 SCIP_NLROW** nlrows /**< rows to add */
3858 )
3859 {
3860 assert(nlp != NULL);
3861 assert(nlrows != NULL || nnlrows == 0);
3862
3863 if( nnlrows == 0 )
3864 return SCIP_OKAY;
3865
3866 if( nlp->indiving )
3867 {
3868 SCIPerrorMessage("cannot add rows during NLP diving\n");
3869 return SCIP_ERROR;
3870 }
3871
3872 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, nnlrows, nlrows) );
3873
3874 return SCIP_OKAY;
3875 }
3876
3877 /** deletes a nonlinear row from the NLP
3878 *
3879 * does nothing if nonlinear row is not in NLP
3880 */
3881 SCIP_RETCODE SCIPnlpDelNlRow(
3882 SCIP_NLP* nlp, /**< NLP data */
3883 BMS_BLKMEM* blkmem, /**< block memory */
3884 SCIP_SET* set, /**< global SCIP settings */
3885 SCIP_STAT* stat, /**< problem statistics data */
3886 SCIP_NLROW* nlrow /**< nonlinear row */
3887 )
3888 {
3889 assert(nlp != NULL);
3890 assert(blkmem != NULL);
3891 assert(set != NULL);
3892 assert(nlrow != NULL);
3893
3894 /* if row not in NLP, nothing to do */
3895 if( nlrow->nlpindex == -1 )
3896 return SCIP_OKAY;
3897
3898 assert(nlrow->nlpindex >= 0);
3899 assert(nlrow->nlpindex < nlp->nnlrows);
3900
3901 if( nlp->indiving )
3902 {
3903 SCIPerrorMessage("cannot delete row during NLP diving\n");
3904 return SCIP_ERROR;
3905 }
3906
3907 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, nlrow->nlpindex) );
3908
3909 return SCIP_OKAY;
3910 }
3911
3912 /** applies all cached changes to the NLP solver */
3913 SCIP_RETCODE SCIPnlpFlush(
3914 SCIP_NLP* nlp, /**< current NLP data */
3915 BMS_BLKMEM* blkmem, /**< block memory */
3916 SCIP_SET* set, /**< global SCIP settings */
3917 SCIP_STAT* stat /**< problem statistics */
3918 )
3919 {
3920 assert(nlp != NULL);
3921 assert(blkmem != NULL);
3922 assert(set != NULL);
3923
3924 if( nlp->indiving )
3925 {
3926 SCIPerrorMessage("cannot flush NLP during NLP diving\n");
3927 return SCIP_ERROR;
3928 }
3929
3930 /* flush removals of nonlinear rows and variables */
3931 SCIP_CALL( nlpFlushNlRowDeletions(nlp, blkmem, set) );
3932 SCIP_CALL( nlpFlushVarDeletions(nlp, blkmem, set) );
3933 assert(nlp->nunflushednlrowdel == 0);
3934 assert(nlp->nunflushedvardel == 0);
3935
3936 /* flush addition of variables, objective, and addition of rows */
3937 SCIP_CALL( nlpFlushVarAdditions(nlp, blkmem, set) );
3938 SCIP_CALL( nlpFlushObjective(nlp, blkmem, set) );
3939 SCIP_CALL( nlpFlushNlRowAdditions(nlp, blkmem, set, stat) );
3940 assert(nlp->nunflushedvaradd == 0);
3941 assert(nlp->objflushed == TRUE);
3942 assert(nlp->nunflushednlrowadd == 0);
3943
3944 assert(nlp->nvars == nlp->nvars_solver);
3945 assert(nlp->nnlrows == nlp->nnlrows_solver);
3946
3947 return SCIP_OKAY;
3948 }
3949
3950 /** solves the NLP or diving NLP */
3951 SCIP_RETCODE SCIPnlpSolve(
3952 SCIP_NLP* nlp, /**< NLP data */
3953 BMS_BLKMEM* blkmem, /**< block memory buffers */
3954 SCIP_SET* set, /**< global SCIP settings */
3955 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3956 SCIP_STAT* stat, /**< problem statistics */
3957 SCIP_PRIMAL* primal, /**< primal data */
3958 SCIP_TREE* tree, /**< branch and bound tree */
3959 SCIP_NLPPARAM* nlpparam /**< NLP solve parameters */
3960 )
3961 {
3962 assert(nlp != NULL);
3963 assert(blkmem != NULL);
3964 assert(set != NULL);
3965 assert(stat != NULL);
3966
3967 if( !nlp->indiving )
3968 {
3969 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3970 }
3971
3972 SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat, primal, tree, nlpparam) );
3973
3974 return SCIP_OKAY;
3975 }
3976
3977 /** gets objective value of current NLP */
3978 SCIP_Real SCIPnlpGetObjval(
3979 SCIP_NLP* nlp /**< current NLP data */
3980 )
3981 {
3982 assert(nlp != NULL);
3983
3984 return nlp->primalsolobjval;
3985 }
3986
3987 /** gives current pseudo objective value */
3988 SCIP_RETCODE SCIPnlpGetPseudoObjval(
3989 SCIP_NLP* nlp, /**< current NLP data */
3990 BMS_BLKMEM* blkmem, /**< block memory */
3991 SCIP_SET* set, /**< global SCIP settings */
3992 SCIP_STAT* stat, /**< problem statistics data */
3993 SCIP_PROB* prob, /**< SCIP problem */
3994 SCIP_PRIMAL* primal, /**< primal data */
3995 SCIP_TREE* tree, /**< branch and bound tree */
3996 SCIP_LP* lp, /**< SCIP LP */
3997 SCIP_Real* pseudoobjval /**< buffer to store pseudo objective value */
3998 )
3999 {
4000 assert(nlp != NULL);
4001 assert(pseudoobjval != NULL);
4002
4003 if( nlp->divingobj != NULL )
4004 {
4005 assert(nlp->indiving);
4006 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlp->divingobj, blkmem, set, stat, prob, primal, tree, lp, pseudoobjval) );
4007 }
4008 else
4009 {
4010 int i;
4011
4012 *pseudoobjval = 0.0;
4013 for( i = 0; i < nlp->nvars; ++i )
4014 *pseudoobjval += SCIPvarGetObj(nlp->vars[i]) * SCIPvarGetBestBoundLocal(nlp->vars[i]);
4015 }
4016
4017 return SCIP_OKAY;
4018 }
4019
4020 /** gets fractional variables of last NLP solution along with solution values and fractionalities
4021 */
4022 SCIP_RETCODE SCIPnlpGetFracVars(
4023 SCIP_NLP* nlp, /**< NLP data structure */
4024 BMS_BLKMEM* blkmem, /**< block memory */
4025 SCIP_SET* set, /**< global SCIP settings */
4026 SCIP_STAT* stat, /**< problem statistics */
4027 SCIP_VAR*** fracvars, /**< pointer to store the array of NLP fractional variables, or NULL */
4028 SCIP_Real** fracvarssol, /**< pointer to store the array of NLP fractional variables solution values, or NULL */
4029 SCIP_Real** fracvarsfrac, /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
4030 int* nfracvars, /**< pointer to store the number of NLP fractional variables , or NULL */
4031 int* npriofracvars /**< pointer to store the number of NLP fractional variables with maximal branching priority, or NULL */
4032 )
4033 {
4034 assert(nlp != NULL);
4035
4036 SCIP_CALL( nlpCalcFracVars(nlp, blkmem, set, stat) );
4037 assert(nlp->fracvars != NULL);
4038 assert(nlp->fracvarssol != NULL);
4039 assert(nlp->fracvarsfrac != NULL);
4040
4041 if( fracvars != NULL )
4042 *fracvars = nlp->fracvars;
4043 if( fracvarssol != NULL )
4044 *fracvarssol = nlp->fracvarssol;
4045 if( fracvarsfrac != NULL )
4046 *fracvarsfrac = nlp->fracvarsfrac;
4047 if( nfracvars != NULL )
4048 *nfracvars = nlp->nfracvars;
4049 if( npriofracvars != NULL )
4050 *npriofracvars = nlp->npriofracvars;
4051
4052 return SCIP_OKAY;
4053 }
4054
4055 /** removes all redundant nonlinear rows */
4056 SCIP_RETCODE SCIPnlpRemoveRedundantNlRows(
4057 SCIP_NLP* nlp, /**< current NLP data */
4058 BMS_BLKMEM* blkmem, /**< block memory buffers */
4059 SCIP_SET* set, /**< global SCIP settings */
4060 SCIP_STAT* stat /**< problem statistics */
4061 )
4062 {
4063 SCIP_NLPSOLSTAT solstatus;
4064 SCIP_Bool isredundant;
4065 int i;
4066
4067 assert(nlp != NULL);
4068 assert(blkmem != NULL);
4069 assert(set != NULL);
4070 assert(stat != NULL);
4071
4072 if( nlp->nnlrows == 0 )
4073 return SCIP_OKAY;
4074
4075 if( nlp->indiving )
4076 {
4077 SCIPerrorMessage("cannot remove redundant rows during NLP diving\n");
4078 return SCIP_ERROR;
4079 }
4080
4081 /* removing redundant rows should not change the solution status, so we reset it at the end */
4082 solstatus = nlp->solstat;
4083
4084 for( i = 0; i < nlp->nnlrows; ++i )
4085 {
4086 SCIP_CALL( SCIPnlrowIsRedundant(nlp->nlrows[i], blkmem, set, stat, &isredundant) );
4087 if( isredundant )
4088 {
4089 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
4090 }
4091 }
4092
4093 nlp->solstat = solstatus;
4094
4095 return SCIP_OKAY;
4096 }
4097
4098 /** set initial guess (approximate primal solution) for next solve
4099 *
4100 * array initguess must be NULL or have length at least SCIPnlpGetNVars()
4101 */
4102 SCIP_RETCODE SCIPnlpSetInitialGuess(
4103 SCIP_SET* set, /**< global SCIP settings */
4104 SCIP_NLP* nlp, /**< current NLP data */
4105 BMS_BLKMEM* blkmem, /**< block memory buffers */
4106 SCIP_Real* initguess /**< new initial guess, or NULL to clear previous one */
4107 )
4108 {
4109 assert(nlp != NULL);
4110 assert(blkmem != NULL);
4111 assert(nlp->solver != NULL);
4112 assert(nlp->problem != NULL);
4113
4114 /* if user wants to let NLP solver choose start point, then invalidate current initial guess both in NLP and in NLPI */
4115 if( initguess == NULL )
4116 {
4117 nlp->haveinitguess = FALSE;
4118 SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, NULL, NULL, NULL, NULL) );
4119 return SCIP_OKAY;
4120 }
4121
4122 if( nlp->initialguess != NULL )
4123 {
4124 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4125 }
4126 else
4127 {
4128 assert( nlp->sizevars >= nlp->nvars );
4129 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars) );
4130 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4131 }
4132 nlp->haveinitguess = TRUE;
4133
4134 return SCIP_OKAY;
4135 }
4136
4137 /** writes NLP to a file */
4138 SCIP_RETCODE SCIPnlpWrite(
4139 SCIP_NLP* nlp, /**< current NLP data */
4140 BMS_BLKMEM* blkmem, /**< block memory buffers */
4141 SCIP_SET* set, /**< global SCIP settings */
4142 SCIP_STAT* stat, /**< problem statistics */
4143 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4144 const char* fname /**< file name */
4145 )
4146 {
4147 FILE* file;
4148 int i;
4149
4150 assert(nlp != NULL);
4151
(1) Event cond_true: |
Condition "fname != NULL", taking true branch. |
4152 if( fname != NULL )
4153 {
4154 file = fopen(fname, "w");
(4) Event cond_false: |
Condition "file == NULL", taking false branch. |
4155 if( file == NULL )
4156 {
4157 SCIPerrorMessage("could not open file <%s> for writing\n", fname);
4158 return SCIP_FILECREATEERROR;
(5) Event if_end: |
End of if statement. |
4159 }
(6) Event if_fallthrough: |
Falling through to end of if statement. |
4160 }
4161 else
(7) Event if_end: |
End of if statement. |
4162 file = stdout;
4163
4164 SCIPmessageFPrintInfo(messagehdlr, file, "STATISTICS\n");
4165 SCIPmessageFPrintInfo(messagehdlr, file, " NLP name: %s\n", nlp->name);
4166 SCIPmessageFPrintInfo(messagehdlr, file, " Variables: %d\n", nlp->nvars);
4167 SCIPmessageFPrintInfo(messagehdlr, file, " Rows: %d\n", nlp->nnlrows);
4168
4169 SCIPmessageFPrintInfo(messagehdlr, file, "VARIABLES\n");
(13) Event cond_false: |
Condition "i < nlp->nvars", taking false branch. |
4170 for( i = 0; i < nlp->nvars; ++i )
4171 {
4172 SCIP_CALL( SCIPvarPrint(nlp->vars[i], set, messagehdlr, file) );
(14) Event loop_end: |
Reached end of loop. |
4173 }
4174
4175 SCIPmessageFPrintInfo(messagehdlr, file, "NONLINEAR ROWS\n");
(16) Event cond_true: |
Condition "i < nlp->nnlrows", taking true branch. |
4176 for( i = 0; i < nlp->nnlrows; ++i )
4177 {
4178 SCIPmessageFPrintInfo(messagehdlr, file, " ");
(18) Event noescape: |
Resource "file" is not freed or pointed-to in "SCIPnlrowPrint". [details] |
(19) Event cond_true: |
Condition "(_restat_ = SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file)) != SCIP_OKAY", taking true branch. |
(20) Event leaked_storage: |
Variable "file" going out of scope leaks the storage it points to. |
Also see events: |
[alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape] |
4179 SCIP_CALL( SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file) );
4180 }
4181
4182 if( fname != NULL )
4183 {
4184 fclose(file);
4185 }
4186
4187 return SCIP_OKAY;
4188 }
4189
4190 /** gets array with variables of the NLP */
4191 SCIP_VAR** SCIPnlpGetVars(
4192 SCIP_NLP* nlp /**< current NLP data */
4193 )
4194 {
4195 assert(nlp != NULL);
4196
4197 return nlp->vars;
4198 }
4199
4200 /** gets current number of variables in NLP */
4201 int SCIPnlpGetNVars(
4202 SCIP_NLP* nlp /**< current NLP data */
4203 )
4204 {
4205 assert(nlp != NULL);
4206
4207 return nlp->nvars;
4208 }
4209
4210 /** computes for each variables the number of NLP rows in which the variable appears in a nonlinear var */
4211 SCIP_RETCODE SCIPnlpGetVarsNonlinearity(
4212 SCIP_NLP* nlp, /**< current NLP data */
4213 BMS_BLKMEM* blkmem, /**< block memory buffers */
4214 SCIP_SET* set, /**< global SCIP settings */
4215 SCIP_STAT* stat, /**< problem statistics */
4216 int* nlcount /**< an array of length at least SCIPnlpGetNVars() to store nonlinearity counts of variables */
4217 )
4218 {
4219 SCIP_NLROW* nlrow;
4220 SCIP_EXPRITER* it;
4221 SCIP_EXPR* expr;
4222 int varidx;
4223 int c;
4224
4225 assert(nlp != NULL);
4226 assert(nlcount != NULL || nlp->nvars == 0);
4227
4228 BMSclearMemoryArray(nlcount, nlp->nvars);
4229
4230 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4231
4232 for( c = 0; c < nlp->nnlrows; ++c )
4233 {
4234 nlrow = nlp->nlrows[c];
4235 assert(nlrow != NULL);
4236
4237 if( nlrow->expr == NULL )
4238 continue;
4239
4240 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, FALSE) );
4241 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4242 {
4243 if( !SCIPexprIsVar(set, expr) )
4244 continue;
4245
4246 assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
4247
4248 varidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(expr));
4249 assert(varidx < nlp->nvars);
4250 assert(nlcount != NULL);
4251 ++nlcount[varidx];
4252 }
4253 }
4254
4255 SCIPexpriterFree(&it);
4256
4257 return SCIP_OKAY;
4258 }
4259
4260
4261 /** indicates whether there exists a row that contains a continuous variable in a nonlinear term
4262 *
4263 * @note The method may have to touch every row and nonlinear term to compute its result.
4264 */
4265 SCIP_RETCODE SCIPnlpHasContinuousNonlinearity(
4266 SCIP_NLP* nlp, /**< current NLP data */
4267 BMS_BLKMEM* blkmem, /**< block memory buffers */
4268 SCIP_SET* set, /**< global SCIP settings */
4269 SCIP_STAT* stat, /**< problem statistics */
4270 SCIP_Bool* result /**< buffer to store whether continuous variable present in an expression of any row */
4271 )
4272 {
4273 SCIP_NLROW* nlrow;
4274 SCIP_EXPRITER* it;
4275 SCIP_EXPR* expr;
4276 int c;
4277
4278 assert(nlp != NULL);
4279
4280 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4281 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4282
4283 *result = FALSE;
4284 for( c = 0; c < nlp->nnlrows && !*result; ++c )
4285 {
4286 nlrow = nlp->nlrows[c];
4287 assert(nlrow != NULL);
4288
4289 if( nlrow->expr == NULL )
4290 continue;
4291
4292 for( expr = SCIPexpriterRestartDFS(it, nlrow->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4293 {
4294 if( SCIPexprIsVar(set, expr) && SCIPvarGetType(SCIPgetVarExprVar(expr)) == SCIP_VARTYPE_CONTINUOUS )
4295 {
4296 *result = TRUE;
4297 break;
4298 }
4299 }
4300 }
4301
4302 SCIPexpriterFree(&it);
4303
4304 return SCIP_OKAY;
4305 }
4306
4307 /** gives dual solution values associated with lower bounds of NLP variables */
4308 SCIP_Real* SCIPnlpGetVarsLbDualsol(
4309 SCIP_NLP* nlp /**< current NLP data */
4310 )
4311 {
4312 assert(nlp != NULL);
4313
4314 return nlp->varlbdualvals;
4315 }
4316
4317 /** gives dual solution values associated with upper bounds of NLP variables */
4318 SCIP_Real* SCIPnlpGetVarsUbDualsol(
4319 SCIP_NLP* nlp /**< current NLP data */
4320 )
4321 {
4322 assert(nlp != NULL);
4323
4324 return nlp->varubdualvals;
4325 }
4326
4327 /** gets array with nonlinear rows of the NLP */
4328 SCIP_NLROW** SCIPnlpGetNlRows(
4329 SCIP_NLP* nlp /**< current NLP data */
4330 )
4331 {
4332 assert(nlp != NULL);
4333
4334 return nlp->nlrows;
4335 }
4336
4337 /** gets current number of nonlinear rows in NLP */
4338 int SCIPnlpGetNNlRows(
4339 SCIP_NLP* nlp /**< current NLP data */
4340 )
4341 {
4342 assert(nlp != NULL);
4343
4344 return nlp->nnlrows;
4345 }
4346
4347 /** gets the NLP solver interface */
4348 SCIP_NLPI* SCIPnlpGetNLPI(
4349 SCIP_NLP* nlp /**< current NLP data */
4350 )
4351 {
4352 assert(nlp != NULL);
4353
4354 return nlp->solver;
4355 }
4356
4357 /** gets the NLP problem in the solver interface */
4358 SCIP_NLPIPROBLEM* SCIPnlpGetNLPIProblem(
4359 SCIP_NLP* nlp /**< current NLP data */
4360 )
4361 {
4362 assert(nlp != NULL);
4363
4364 return nlp->problem;
4365 }
4366
4367 /** indicates whether NLP is currently in diving mode */
4368 SCIP_Bool SCIPnlpIsDiving(
4369 SCIP_NLP* nlp /**< current NLP data */
4370 )
4371 {
4372 assert(nlp != NULL);
4373
4374 return nlp->indiving;
4375 }
4376
4377 /** gets solution status of current NLP */
4378 SCIP_NLPSOLSTAT SCIPnlpGetSolstat(
4379 SCIP_NLP* nlp /**< current NLP data */
4380 )
4381 {
4382 assert(nlp != NULL);
4383
4384 return nlp->solstat;
4385 }
4386
4387 /** gets termination status of last NLP solve */
4388 SCIP_NLPTERMSTAT SCIPnlpGetTermstat(
4389 SCIP_NLP* nlp /**< current NLP data */
4390 )
4391 {
4392 assert(nlp != NULL);
4393
4394 return nlp->termstat;
4395 }
4396
4397 /** gives statistics (number of iterations, solving time, ...) of last NLP solve */
4398 SCIP_RETCODE SCIPnlpGetStatistics(
4399 SCIP_SET* set, /**< global SCIP settings */
4400 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
4401 SCIP_NLPSTATISTICS* statistics /**< pointer to store statistics */
4402 )
4403 {
4404 assert(nlp != NULL);
4405 assert(nlp->solver != NULL);
4406 assert(nlp->problem != NULL);
4407 assert(statistics != NULL);
4408
4409 SCIP_CALL( SCIPnlpiGetStatistics(set, nlp->solver, nlp->problem, statistics) );
4410
4411 return SCIP_OKAY;
4412 }
4413
4414 /** indicates whether a solution for the current NLP is available
4415 *
4416 * The solution may be optimal, feasible, or infeasible.
4417 * Thus, returns whether the NLP solution status is at most \ref SCIP_NLPSOLSTAT_LOCINFEASIBLE.
4418 */
4419 SCIP_Bool SCIPnlpHasSolution(
4420 SCIP_NLP* nlp /**< current NLP data */
4421 )
4422 {
4423 assert(nlp != NULL);
4424
4425 return nlp->solstat <= SCIP_NLPSOLSTAT_LOCINFEASIBLE;
4426 }
4427
4428 /*
4429 * NLP diving methods
4430 */
4431
4432 /** signals start of diving */
4433 SCIP_RETCODE SCIPnlpStartDive(
4434 SCIP_NLP* nlp, /**< current NLP data */
4435 BMS_BLKMEM* blkmem, /**< block memory buffers */
4436 SCIP_SET* set, /**< global SCIP settings */
4437 SCIP_STAT* stat /**< problem statistics */
4438 )
4439 {
4440 assert(nlp != NULL);
4441
4442 if( nlp->indiving )
4443 {
4444 SCIPerrorMessage("NLP is already in diving mode\n");
4445 return SCIP_ERROR;
4446 }
4447
4448 if( nlp->solver == NULL )
4449 {
4450 /* 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.
4451 * So we forbid diving of no solver is available. */
4452 SCIPerrorMessage("Cannot start diving if no NLP solver is available\n");
4453 return SCIP_ERROR;
4454 }
4455
4456 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
4457
4458 nlp->indiving = TRUE;
4459
4460 return SCIP_OKAY;
4461 }
4462
4463 /** resets the bound and objective changes made during diving and disables diving mode */
4464 SCIP_RETCODE SCIPnlpEndDive(
4465 SCIP_NLP* nlp, /**< current NLP data */
4466 BMS_BLKMEM* blkmem, /**< block memory */
4467 SCIP_SET* set, /**< global SCIP settings */
4468 SCIP_STAT* stat /**< problem statistics data */
4469 )
4470 {
4471 int i;
4472 int* varidx;
4473 SCIP_Real* varlb;
4474 SCIP_Real* varub;
4475
4476 assert(nlp != NULL);
4477 assert(set != NULL);
4478 assert(nlp->nvars == nlp->nvars_solver);
4479
4480 if( !nlp->indiving )
4481 {
4482 SCIPerrorMessage("NLP not in diving mode, cannot end dive\n");
4483 return SCIP_ERROR;
4484 }
4485
4486 assert(nlp->solver != NULL);
4487 assert(nlp->problem != NULL);
4488
4489 /* reset variable bounds in NLPI problem to their current values */
4490 SCIP_CALL( SCIPsetAllocBufferArray(set, &varidx, nlp->nvars) );
4491 SCIP_CALL( SCIPsetAllocBufferArray(set, &varlb, nlp->nvars) );
4492 SCIP_CALL( SCIPsetAllocBufferArray(set, &varub, nlp->nvars) );
4493 for( i = 0; i < nlp->nvars; ++i )
4494 {
4495 varidx[i] = i;
4496 varlb[i] = SCIPvarGetLbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4497 varub[i] = SCIPvarGetUbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4498 }
4499
4500 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nlp->nvars, varidx, varlb, varub) );
4501
4502 SCIPsetFreeBufferArray(set, &varidx);
4503 SCIPsetFreeBufferArray(set, &varlb);
4504 SCIPsetFreeBufferArray(set, &varub);
4505
4506 /* clear diving objective, if one was used (i.e., if SCIPnlpChgVarObjDive had been called)
4507 * the objective in the NLPI will be reset in the next flush */
4508 if( nlp->divingobj != NULL )
4509 {
4510 SCIP_CALL( SCIPnlrowRelease(&nlp->divingobj, blkmem, set, stat) );
4511 assert(nlp->divingobj == NULL);
4512 assert(nlp->objflushed == FALSE);
4513 }
4514
4515 /* we do not have a valid solution anymore */
4516 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
4517 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
4518 nlp->primalsolobjval = SCIP_INVALID;
4519
4520 nlp->indiving = FALSE;
4521
4522 return SCIP_OKAY;
4523 }
4524
4525 /** changes coefficient of variable in diving NLP */
4526 SCIP_RETCODE SCIPnlpChgVarObjDive(
4527 SCIP_NLP* nlp, /**< current NLP data */
4528 BMS_BLKMEM* blkmem, /**< block memory */
4529 SCIP_SET* set, /**< global SCIP settings */
4530 SCIP_STAT* stat, /**< problem statistics data */
4531 SCIP_VAR* var, /**< variable which coefficient to change */
4532 SCIP_Real coef /**< new linear coefficient of variable in objective */
4533 )
4534 {
4535 int pos;
4536 int objidx;
4537
4538 assert(nlp != NULL);
4539 assert(var != NULL);
4540 assert(SCIPhashmapExists(nlp->varhash, var));
4541 assert(nlp->indiving);
4542 assert(nlp->solver != NULL);
4543 assert(nlp->problem != NULL);
4544
4545 /* get position of variable in NLPI problem */
4546 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4547 pos = nlp->varmap_nlp2nlpi[pos];
4548 assert(pos >= 0);
4549
4550 /* set coefficient in NLPI problem objective */
4551 objidx = -1;
4552 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
4553
4554 /* create an nlrow that holds the diving objective, if not done yet */
4555 if( nlp->divingobj == NULL )
4556 {
4557 SCIP_Real* coefs;
4558 int i;
4559
4560 SCIP_CALL( SCIPsetAllocBufferArray(set, &coefs, nlp->nvars) );
4561 for( i = 0; i < nlp->nvars; ++i )
4562 coefs[i] = SCIPvarGetObj(nlp->vars[i]);
4563
4564 SCIP_CALL( SCIPnlrowCreate(&nlp->divingobj, blkmem, set, stat, "divingobj",
4565 0.0, nlp->nvars, nlp->vars, coefs, NULL,
4566 -SCIPsetInfinity(set), SCIPsetInfinity(set),
4567 SCIP_EXPRCURV_LINEAR) );
4568
4569 SCIPsetFreeBufferArray(set, &coefs);
4570 }
4571 assert(nlp->divingobj != NULL);
4572
4573 /* modify coefficient in diving objective */
4574 SCIP_CALL( SCIPnlrowChgLinearCoef(nlp->divingobj, blkmem, set, stat, nlp, var, coef) );
4575
4576 /* remember that we have to store objective after diving ended */
4577 nlp->objflushed = FALSE;
4578
4579 return SCIP_OKAY;
4580 }
4581
4582 /** changes bounds of variable in diving NLP */
4583 SCIP_RETCODE SCIPnlpChgVarBoundsDive(
4584 SCIP_SET* set, /**< global SCIP settings */
4585 SCIP_NLP* nlp, /**< current NLP data */
4586 SCIP_VAR* var, /**< variable which coefficient to change */
4587 SCIP_Real lb, /**< new lower bound of variable */
4588 SCIP_Real ub /**< new upper bound of variable */
4589 )
4590 {
4591 int pos;
4592
4593 assert(nlp != NULL);
4594 assert(var != NULL);
4595 assert(SCIPhashmapExists(nlp->varhash, var));
4596 assert(nlp->indiving);
4597 assert(nlp->solver != NULL);
4598 assert(nlp->problem != NULL);
4599
4600 /* get position of variable in NLPI problem */
4601 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4602 pos = nlp->varmap_nlp2nlpi[pos];
4603 assert(pos >= 0);
4604
4605 /* set new bounds in NLPI */
4606 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
4607
4608 return SCIP_OKAY;
4609 }
4610
4611 /** changes bounds of a set of variables in diving NLP */
4612 SCIP_RETCODE SCIPnlpChgVarsBoundsDive(
4613 SCIP_NLP* nlp, /**< current NLP data */
4614 SCIP_SET* set, /**< global SCIP settings */
4615 int nvars, /**< number of variables which bounds to change */
4616 SCIP_VAR** vars, /**< variables which bounds to change */
4617 SCIP_Real* lbs, /**< new lower bounds of variables */
4618 SCIP_Real* ubs /**< new upper bounds of variables */
4619 )
4620 {
4621 int i;
4622 int* poss;
4623
4624 assert(nlp != NULL);
4625 assert(vars != NULL || nvars == 0);
4626 assert(nlp->indiving);
4627 assert(lbs != NULL || nvars == 0);
4628 assert(ubs != NULL || nvars == 0);
4629 assert(nlp->solver != NULL);
4630 assert(nlp->problem != NULL);
4631
4632 if( nvars == 0 )
4633 return SCIP_OKAY;
4634
4635 SCIP_CALL( SCIPsetAllocBufferArray(set, &poss, nvars) );
4636
4637 for( i = 0; i < nvars; ++i )
4638 {
4639 assert(SCIPhashmapExists(nlp->varhash, vars[i])); /*lint !e613*/
4640
4641 /* get position of variable in NLPI problem */
4642 poss[i] = SCIPhashmapGetImageInt(nlp->varhash, vars[i]); /*lint !e613*/
4643 poss[i] = nlp->varmap_nlp2nlpi[poss[i]];
4644 assert(poss[i] >= 0);
4645 }
4646
4647 /* set new bounds in NLPI */
4648 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nvars, poss, lbs, ubs) );
4649
4650 SCIPsetFreeBufferArray(set, &poss);
4651
4652 return SCIP_OKAY;
4653 }
4654
4655 /** returns whether the objective function has been changed during diving */
4656 SCIP_Bool SCIPnlpIsDivingObjChanged(
4657 SCIP_NLP* nlp /**< current NLP data */
4658 )
4659 {
4660 return nlp->divingobj != NULL;
4661 }
4662