1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file nlp.c
17 * @ingroup OTHER_CFILES
18 * @brief NLP management methods
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 /** gets constant */
1737 SCIP_Real SCIPnlrowGetConstant(
1738 SCIP_NLROW* nlrow /**< NLP row */
1739 )
1740 {
1741 assert(nlrow != NULL);
1742
1743 return nlrow->constant;
1744 }
1745
1746 /** gets number of variables of linear part */
1747 int SCIPnlrowGetNLinearVars(
1748 SCIP_NLROW* nlrow /**< NLP row */
1749 )
1750 {
1751 assert(nlrow != NULL);
1752
1753 return nlrow->nlinvars;
1754 }
1755
1756 /** gets array with variables of linear part */
1757 SCIP_VAR** SCIPnlrowGetLinearVars(
1758 SCIP_NLROW* nlrow /**< NLP row */
1759 )
1760 {
1761 assert(nlrow != NULL);
1762
1763 return nlrow->linvars;
1764 }
1765
1766 /** gets array with coefficients in linear part */
1767 SCIP_Real* SCIPnlrowGetLinearCoefs(
1768 SCIP_NLROW* nlrow /**< NLP row */
1769 )
1770 {
1771 assert(nlrow != NULL);
1772
1773 return nlrow->lincoefs;
1774 }
1775
1776 /** gets expression */
1777 SCIP_EXPR* SCIPnlrowGetExpr(
1778 SCIP_NLROW* nlrow /**< NLP row */
1779 )
1780 {
1781 assert(nlrow != NULL);
1782
1783 return nlrow->expr;
1784 }
1785
1786 /** returns the left hand side of a nonlinear row */
1787 SCIP_Real SCIPnlrowGetLhs(
1788 SCIP_NLROW* nlrow /**< NLP row */
1789 )
1790 {
1791 assert(nlrow != NULL);
1792
1793 return nlrow->lhs;
1794 }
1795
1796 /** returns the right hand side of a nonlinear row */
1797 SCIP_Real SCIPnlrowGetRhs(
1798 SCIP_NLROW* nlrow /**< NLP row */
1799 )
1800 {
1801 assert(nlrow != NULL);
1802
1803 return nlrow->rhs;
1804 }
1805
1806 /** returns the curvature of a nonlinear row */
1807 SCIP_EXPRCURV SCIPnlrowGetCurvature(
1808 SCIP_NLROW* nlrow /**< NLP row */
1809 )
1810 {
1811 assert(nlrow != NULL);
1812 return nlrow->curvature;
1813 }
1814
1815 /** sets the curvature of a nonlinear row */
1816 void SCIPnlrowSetCurvature(
1817 SCIP_NLROW* nlrow, /**< NLP row */
1818 SCIP_EXPRCURV curvature /**< curvature of NLP row */
1819 )
1820 {
1821 assert(nlrow != NULL);
1822 nlrow->curvature = curvature;
1823 }
1824
1825 /** returns the name of a nonlinear row */
1826 const char* SCIPnlrowGetName(
1827 SCIP_NLROW* nlrow /**< NLP row */
1828 )
1829 {
1830 assert(nlrow != NULL);
1831
1832 return nlrow->name;
1833 }
1834
1835 /** gets position of a nonlinear row in current NLP, or -1 if not in NLP */
1836 int SCIPnlrowGetNLPPos(
1837 SCIP_NLROW* nlrow /**< NLP row */
1838 )
1839 {
1840 assert(nlrow != NULL);
1841
1842 return nlrow->nlpindex;
1843 }
1844
1845 /** returns TRUE iff row is member of current NLP */
1846 SCIP_Bool SCIPnlrowIsInNLP(
1847 SCIP_NLROW* nlrow /**< NLP row */
1848 )
1849 {
1850 assert(nlrow != NULL);
1851
1852 return nlrow->nlpindex != -1;
1853 }
1854
1855 /** gets the dual NLP solution of a nlrow
1856 *
1857 * 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
1858 */
1859 SCIP_Real SCIPnlrowGetDualsol(
1860 SCIP_NLROW* nlrow /**< NLP row */
1861 )
1862 {
1863 assert(nlrow != NULL);
1864
1865 return nlrow->nlpiindex >= 0 ? nlrow->dualsol : 0.0;
1866 }
1867
1868 /** @} */
1869
1870 /*
1871 * local NLP methods
1872 */
1873
1874 /** announces, that a row of the NLP was modified
1875 * adjusts status of current solution
1876 * calling method has to ensure that change is passed to the NLPI!
1877 */ /*lint -e{715}*/
1878 static
1879 SCIP_RETCODE nlpRowChanged(
1880 SCIP_NLP* nlp, /**< current NLP data */
1881 SCIP_SET* set, /**< global SCIP settings */
1882 SCIP_STAT* stat, /**< problem statistics data */
1883 SCIP_NLROW* nlrow /**< nonlinear row which was changed */
1884 )
1885 { /*lint --e{715}*/
1886 assert(nlp != NULL);
1887 assert(nlrow != NULL);
1888 assert(!nlp->indiving);
1889 assert(nlrow->nlpindex >= 0);
1890
1891 /* nlrow is a row in the NLP, so changes effect feasibility */
1892 /* if we have a feasible NLP solution and it satisfies the modified row, then it is still feasible
1893 * if the NLP was globally or locally infeasible or unbounded, then this may not be the case anymore
1894 */
1895 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1896 {
1897 /* TODO bring this back? then everything that may call nlpRowChanged will need to pass on blkmem, primal, tree as well
1898 SCIP_Real feasibility;
1899 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1900 if( !SCIPsetIsFeasNegative(set, feasibility) )
1901 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
1902 else */
1903 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
1904 }
1905 else
1906 {
1907 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1908 }
1909
1910 return SCIP_OKAY;
1911 }
1912
1913 /** adds a set of nonlinear rows to the NLP and captures them */
1914 static
1915 SCIP_RETCODE nlpAddNlRows(
1916 SCIP_NLP* nlp, /**< NLP data */
1917 BMS_BLKMEM* blkmem, /**< block memory */
1918 SCIP_SET* set, /**< global SCIP settings */
1919 SCIP_STAT* stat, /**< problem statistics data */
1920 int nnlrows, /**< number of nonlinear rows to add */
1921 SCIP_NLROW** nlrows /**< nonlinear rows to add */
1922 )
1923 {
1924 #ifndef NDEBUG
1925 int i;
1926 #endif
1927 int j;
1928 SCIP_NLROW* nlrow;
1929
1930 assert(nlp != NULL);
1931 assert(blkmem != NULL);
1932 assert(set != NULL);
1933 assert(nlrows != NULL || nnlrows == 0);
1934 assert(!nlp->indiving);
1935
1936 SCIP_CALL( SCIPnlpEnsureNlRowsSize(nlp, blkmem, set, nlp->nnlrows + nnlrows) );
1937
1938 for( j = 0; j < nnlrows; ++j )
1939 {
1940 nlrow = nlrows[j]; /*lint !e613*/
1941
1942 /* assert that row is not in NLP (or even NLPI) yet */
1943 assert(nlrow->nlpindex == -1);
1944 assert(nlrow->nlpiindex == -1);
1945
1946 /* make sure there are only active variables in row */
1947 SCIP_CALL( SCIPnlrowSimplify(nlrow, blkmem, set, stat, nlp) );
1948
1949 #ifndef NDEBUG
1950 /* assert that variables of row are in NLP */
1951 for( i = 0; i < nlrow->nlinvars; ++i )
1952 assert(SCIPhashmapExists(nlp->varhash, nlrow->linvars[i]));
1953
1954 if( nlrow->expr != NULL )
1955 {
1956 SCIP_EXPRITER* it;
1957 SCIP_EXPR* expr;
1958
1959 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
1960 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
1961 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
1962 assert(!SCIPexprIsVar(set, expr) || SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
1963 SCIPexpriterFree(&it);
1964 }
1965 #endif
1966
1967 /* add row to NLP and capture it */
1968 nlp->nlrows[nlp->nnlrows + j] = nlrow;
1969 nlrow->nlpindex = nlp->nnlrows + j;
1970
1971 SCIPnlrowCapture(nlrow);
1972
1973 /* if we have a feasible NLP solution and it satisfies the new solution, then it is still feasible
1974 * if the NLP was globally or locally infeasible, then it stays that way
1975 * if the NLP was unbounded, then this may not be the case anymore
1976 */
1977 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1978 {
1979 /* TODO bring this back? then everything that may call nlpAddNlRows will need to pass on primal, tree as well
1980 SCIP_Real feasibility;
1981 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1982 if( !SCIPsetIsFeasNegative(set, feasibility) )
1983 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
1984 else
1985 */
1986 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
1987 }
1988 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
1989 {
1990 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1991 }
1992 }
1993
1994 nlp->nnlrows += nnlrows;
1995 nlp->nunflushednlrowadd += nnlrows;
1996
1997 return SCIP_OKAY;
1998 }
1999
2000 /** moves a nonlinear row to a different place, and updates all corresponding data structures */
2001 static
2002 void nlpMoveNlrow(
2003 SCIP_NLP* nlp, /**< NLP data structure */
2004 int oldpos, /**< old position of nonlinear row */
2005 int newpos /**< new position of nonlinear row */
2006 )
2007 {
2008 assert(nlp != NULL);
2009 assert(0 <= oldpos && oldpos < nlp->nnlrows);
2010 assert(0 <= newpos && newpos < nlp->nnlrows);
2011 assert(nlp->nlrows[oldpos] != NULL);
2012
2013 if( oldpos == newpos )
2014 return;
2015
2016 nlp->nlrows[newpos] = nlp->nlrows[oldpos];
2017 nlp->nlrows[newpos]->nlpindex = newpos;
2018
2019 /* update nlpi to nlp row index mapping */
2020 if( nlp->nlrows[newpos]->nlpiindex >= 0 )
2021 {
2022 assert(nlp->nlrowmap_nlpi2nlp != NULL);
2023 assert(nlp->nlrows[newpos]->nlpiindex < nlp->sizenlrows_solver);
2024 nlp->nlrowmap_nlpi2nlp[nlp->nlrows[newpos]->nlpiindex] = newpos;
2025 }
2026 }
2027
2028 /** deletes nonlinear row with given position from NLP */
2029 static
2030 SCIP_RETCODE nlpDelNlRowPos(
2031 SCIP_NLP* nlp, /**< NLP data structure */
2032 BMS_BLKMEM* blkmem, /**< block memory */
2033 SCIP_SET* set, /**< global SCIP settings */
2034 SCIP_STAT* stat, /**< problem statistics data */
2035 int pos /**< position of nonlinear row that is to be removed */
2036 )
2037 {
2038 SCIP_NLROW* nlrow;
2039
2040 assert(nlp != NULL);
2041 assert(blkmem != NULL);
2042 assert(set != NULL);
2043 assert(pos >= 0);
2044 assert(pos < nlp->nnlrows);
2045 assert(!nlp->indiving);
2046 assert(nlp->nlrows != NULL);
2047
2048 nlrow = nlp->nlrows[pos];
2049 assert(nlrow != NULL);
2050 assert(nlrow->nlpindex == pos);
2051
2052 /* if row is in NLPI, then mark that it has to be removed in the next flush
2053 * if row was not in NLPI yet, then we have one unflushed nlrow addition less */
2054 if( nlrow->nlpiindex >= 0 )
2055 {
2056 assert(nlrow->nlpiindex < nlp->nnlrows_solver);
2057 nlp->nlrowmap_nlpi2nlp[nlrow->nlpiindex] = -1;
2058 nlrow->nlpiindex = -1;
2059 ++nlp->nunflushednlrowdel;
2060 }
2061 else
2062 {
2063 assert(nlrow->nlpiindex == -1);
2064 --nlp->nunflushednlrowadd;
2065 }
2066
2067 /* move NLP row from the end to pos and mark nlrow to be not in NLP anymore */
2068 nlpMoveNlrow(nlp, nlp->nnlrows-1, pos);
2069 nlrow->nlpindex = -1;
2070
2071 /* forget about restriction */
2072 SCIP_CALL( SCIPnlrowRelease(&nlrow, blkmem, set, stat) );
2073 --nlp->nnlrows;
2074
2075 if( nlp->solstat < SCIP_NLPSOLSTAT_LOCOPT )
2076 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2077 else if( nlp->solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
2078 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2079
2080 return SCIP_OKAY; /*lint !e438*/
2081 }
2082
2083 /** updates bounds on a variable in the NLPI problem */
2084 static
2085 SCIP_RETCODE nlpUpdateVarBounds(
2086 SCIP_NLP* nlp, /**< NLP data */
2087 SCIP_SET* set, /**< global SCIP settings */
2088 SCIP_VAR* var, /**< variable which bounds have changed */
2089 SCIP_Bool tightened /**< whether the bound change was a bound tightening */
2090 )
2091 {
2092 int pos;
2093 SCIP_Real lb;
2094 SCIP_Real ub;
2095
2096 assert(nlp != NULL);
2097 assert(var != NULL);
2098 assert(SCIPhashmapExists(nlp->varhash, var));
2099
2100 /* original variable bounds are ignored during diving
2101 * (all variable bounds are reset to their current value in exitDiving) */
2102 if( nlp->indiving )
2103 return SCIP_OKAY;
2104
2105 /* get position of variable in NLP */
2106 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
2107
2108 /* if variable not in NLPI yet, nothing to do */
2109 if( nlp->varmap_nlp2nlpi[pos] == -1 )
2110 return SCIP_OKAY;
2111
2112 /* update bounds in NLPI problem */
2113 assert(nlp->solver != NULL);
2114 assert(nlp->problem != NULL);
2115
2116 pos = nlp->varmap_nlp2nlpi[pos];
2117 lb = SCIPvarGetLbLocal(var);
2118 ub = SCIPvarGetUbLocal(var);
2119 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
2120
2121 /* if we have a feasible NLP solution and it satisfies the new bounds, then it is still feasible
2122 * if the NLP was globally or locally infeasible and we tightened a bound, then it stays that way
2123 * if the NLP was unbounded and we tightened a bound, then this may not be the case anymore
2124 */
2125 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2126 {
2127 if( !tightened ||
2128 ((SCIPsetIsInfinity(set, -lb) || SCIPsetIsFeasLE(set, lb, SCIPvarGetNLPSol(var))) &&
2129 (SCIPsetIsInfinity(set, ub) || SCIPsetIsFeasGE(set, ub, SCIPvarGetNLPSol(var)))) )
2130 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2131 else
2132 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2133 }
2134 else if( !tightened || nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2135 {
2136 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2137 }
2138
2139 return SCIP_OKAY;
2140 }
2141
2142 /** updates coefficient of a variable in the objective */
2143 static
2144 SCIP_RETCODE nlpUpdateObjCoef(
2145 SCIP_SET* set, /**< global SCIP settings */
2146 SCIP_NLP* nlp, /**< NLP data */
2147 SCIP_VAR* var /**< variable which bounds have changed */
2148 )
2149 {
2150 int pos;
2151 int objidx;
2152 SCIP_Real coef;
2153
2154 assert(nlp != NULL);
2155 assert(var != NULL);
2156 assert(SCIPhashmapExists(nlp->varhash, var));
2157
2158 /* if the objective in the NLPI is not up to date, then we do not need to do something here */
2159 if( !nlp->objflushed )
2160 return SCIP_OKAY;
2161
2162 /* original objective is ignored during diving
2163 * we just need to remember that at end of diving we have to flush the objective */
2164 if( nlp->indiving )
2165 {
2166 nlp->objflushed = FALSE;
2167 return SCIP_OKAY;
2168 }
2169
2170 /* get position of variable in NLP and objective coefficient */
2171 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
2172 assert(nlp->varmap_nlp2nlpi[pos] == -1 || nlp->solver != NULL);
2173
2174 /* actually we only need to remember flushing the objective if we also have an NLPI */
2175 if( nlp->solver == NULL )
2176 return SCIP_OKAY;
2177
2178 coef = SCIPvarGetObj(var);
2179
2180 /* if variable not in NLPI yet, then we only need to remember to update the objective after variable additions were flushed */
2181 if( nlp->varmap_nlp2nlpi[pos] == -1 && coef != 0.0 )
2182 {
2183 nlp->objflushed = FALSE;
2184
2185 return SCIP_OKAY;
2186 }
2187
2188 /* if we are here, then the objective in the NLPI is up to date,
2189 * we keep it this way by changing the coefficient of var in the NLPI problem objective */
2190 assert(nlp->solver != NULL);
2191 assert(nlp->problem != NULL);
2192
2193 pos = nlp->varmap_nlp2nlpi[pos];
2194 objidx = -1;
2195 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
2196
2197 /* if we had a solution and it was locally (or globally) optimal, then now we can only be sure that it is still feasible */
2198 if( nlp->solstat < SCIP_NLPSOLSTAT_FEASIBLE )
2199 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2200
2201 return SCIP_OKAY;
2202 }
2203
2204 /** adds new variables to the NLP */
2205 static
2206 SCIP_RETCODE nlpAddVars(
2207 SCIP_NLP* nlp, /**< NLP data structure */
2208 BMS_BLKMEM* blkmem, /**< block memory */
2209 SCIP_SET* set, /**< global SCIP settings */
2210 int nvars, /**< number of variables to add */
2211 SCIP_VAR** vars /**< variable to add to NLP */
2212 )
2213 {
2214 int i;
2215 SCIP_VAR* var;
2216
2217 assert(nlp != NULL);
2218 assert(blkmem != NULL);
2219 assert(set != NULL);
2220 assert(vars != NULL || nvars == 0);
2221 assert(!nlp->indiving || nvars == 0);
2222
2223 if( nvars == 0 )
2224 return SCIP_OKAY;
2225
2226 SCIP_CALL( SCIPnlpEnsureVarsSize(nlp, blkmem, set, nlp->nvars + nvars) );
2227 assert(nlp->sizevars >= nlp->nvars + nvars);
2228
2229 for( i = 0; i < nvars; ++i )
2230 {
2231 var = vars[i]; /*lint !e613*/
2232
2233 assert(SCIPvarIsTransformed(var));
2234 assert(SCIPvarIsActive(var));
2235 assert(!SCIPhashmapExists(nlp->varhash, var));
2236
2237 SCIPvarCapture(var);
2238
2239 nlp->vars[nlp->nvars+i] = var;
2240 nlp->varmap_nlp2nlpi[nlp->nvars+i] = -1;
2241 SCIP_CALL( SCIPhashmapInsertInt(nlp->varhash, var, nlp->nvars+i) );
2242
2243 nlp->varlbdualvals[nlp->nvars+i] = 0.0;
2244 nlp->varubdualvals[nlp->nvars+i] = 0.0;
2245
2246 /* update objective, if necessary (new variables have coefficient 0.0 anyway) */
2247 if( SCIPvarGetObj(var) != 0.0 )
2248 {
2249 SCIP_CALL( nlpUpdateObjCoef(set, nlp, var) );
2250 }
2251
2252 /* let's keep the previous initial guess and set it for the new variable to the best bound
2253 * (since there can be no row that uses this variable yet, this seems a good guess) */
2254 if( nlp->haveinitguess )
2255 {
2256 assert(nlp->initialguess != NULL);
2257
2258 nlp->initialguess[nlp->nvars+i] = SCIPvarGetBestBoundLocal(var);
2259 }
2260
2261 /* if we have a feasible NLP solution, then it remains feasible
2262 * but we have to update the objective function
2263 */
2264 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2265 {
2266 SCIP_CALL( SCIPvarSetNLPSol(var, set, SCIPvarGetBestBoundLocal(var)) );
2267 nlp->primalsolobjval += SCIPvarGetObj(var) * SCIPvarGetBestBoundLocal(var);
2268 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2269 }
2270
2271 /* catch events on variable */
2272 SCIP_CALL( SCIPvarCatchEvent(var, blkmem, set, \
2273 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2274 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, NULL) ); /* @todo should store event filter position in nlp? */
2275 }
2276
2277 nlp->nvars += nvars;
2278 nlp->nunflushedvaradd += nvars;
2279
2280 return SCIP_OKAY;
2281 }
2282
2283 /** moves a variable to a different place, and updates all corresponding data structures */
2284 static
2285 SCIP_RETCODE nlpMoveVar(
2286 SCIP_NLP* nlp, /**< NLP data structure */
2287 int oldpos, /**< old position of variable */
2288 int newpos /**< new position of variable */
2289 )
2290 {
2291 int nlpipos;
2292
2293 assert(nlp != NULL);
2294 assert(0 <= oldpos && oldpos < nlp->nvars);
2295 assert(0 <= newpos && newpos < nlp->nvars);
2296 assert(nlp->vars[oldpos] != NULL);
2297
2298 if( oldpos == newpos )
2299 return SCIP_OKAY;
2300
2301 SCIP_CALL( SCIPhashmapSetImageInt(nlp->varhash, nlp->vars[oldpos], newpos) );
2302 nlp->vars[newpos] = nlp->vars[oldpos];
2303 nlp->varmap_nlp2nlpi[newpos] = nlp->varmap_nlp2nlpi[oldpos];
2304 nlp->varlbdualvals[newpos] = nlp->varlbdualvals[oldpos];
2305 nlp->varubdualvals[newpos] = nlp->varubdualvals[oldpos];
2306 if( nlp->initialguess != NULL )
2307 nlp->initialguess[newpos] = nlp->initialguess[oldpos];
2308
2309 nlpipos = nlp->varmap_nlp2nlpi[newpos];
2310 if( nlpipos > 0 )
2311 nlp->varmap_nlpi2nlp[nlpipos] = newpos;
2312
2313 return SCIP_OKAY;
2314 }
2315
2316 /** deletes variable with given position from NLP */
2317 static
2318 SCIP_RETCODE nlpDelVarPos(
2319 SCIP_NLP* nlp, /**< NLP data structure */
2320 BMS_BLKMEM* blkmem, /**< block memory */
2321 SCIP_SET* set, /**< global SCIP settings */
2322 SCIP_STAT* stat, /**< problem statistics data */
2323 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2324 SCIP_LP* lp, /**< SCIP LP, needed if a column-variable is freed */
2325 int pos /**< position of nonlinear row that is to be removed */
2326 )
2327 {
2328 SCIP_VAR* var;
2329 #ifndef NDEBUG
2330 int i;
2331 #endif
2332 int nlpipos;
2333
2334 assert(nlp != NULL);
2335 assert(blkmem != NULL);
2336 assert(set != NULL);
2337 assert(pos >= 0);
2338 assert(pos < nlp->nvars);
2339 assert(!nlp->indiving);
2340
2341 var = nlp->vars[pos];
2342 assert(var != NULL);
2343
2344 #ifndef NDEBUG
2345 /* assert that variable is not used by any nonlinear row */
2346 for( i = 0; i < nlp->nnlrows; ++i )
2347 {
2348 int j;
2349 SCIP_NLROW* nlrow;
2350
2351 nlrow = nlp->nlrows[i];
2352 assert(nlrow != NULL);
2353
2354 /* use nlrowSearchLinearCoef only if already sorted, since otherwise we may change the solving process slightly */
2355 if( nlrow->linvarssorted )
2356 assert( nlrowSearchLinearCoef(nlrow, var) == -1 );
2357 else
2358 for( j = 0; j < nlrow->nlinvars; ++j )
2359 assert( nlrow->linvars[j] != var );
2360
2361 if( nlrow->expr != NULL )
2362 {
2363 SCIP_EXPRITER* it;
2364 SCIP_EXPR* expr;
2365 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2366 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
2367 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2368 assert(!SCIPexprIsVar(set, expr) || SCIPgetVarExprVar(expr) != var);
2369 SCIPexpriterFree(&it);
2370 }
2371 }
2372 #endif
2373
2374 /* if we had a feasible solution, then adjust objective function value
2375 * if NLP was unbounded before, then maybe it is not anymore */
2376 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2377 nlp->primalsolobjval -= SCIPvarGetObj(var) * SCIPvarGetNLPSol(var);
2378 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2379 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2380
2381 /* if variable is in NLPI problem, mark that we have to remember to delete it there
2382 * if it was not in the NLPI yet, then we have one unflushed var addition less now */
2383 nlpipos = nlp->varmap_nlp2nlpi[pos];
2384 if( nlpipos >= 0 )
2385 {
2386 assert(nlpipos < nlp->nvars_solver);
2387
2388 nlp->varmap_nlpi2nlp[nlpipos] = -1;
2389 ++nlp->nunflushedvardel;
2390 }
2391 else
2392 --nlp->nunflushedvaradd;
2393
2394 /* drop events on variable */
2395 SCIP_CALL( SCIPvarDropEvent(var, blkmem, set, \
2396 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2397 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, -1) );
2398
2399 /* move variable from end to pos */
2400 SCIP_CALL( nlpMoveVar(nlp, nlp->nvars-1, pos) );
2401
2402 /* forget about variable */
2403 SCIP_CALL( SCIPhashmapRemove(nlp->varhash, var) );
2404 SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
2405 --nlp->nvars;
2406
2407 return SCIP_OKAY;
2408 }
2409
2410 /** notifies NLP that a variable was fixed, so it is removed from objective, all rows, and the NLP variables */
2411 static
2412 SCIP_RETCODE nlpRemoveFixedVar(
2413 SCIP_NLP* nlp, /**< NLP data */
2414 BMS_BLKMEM* blkmem, /**< block memory */
2415 SCIP_SET* set, /**< global SCIP settings */
2416 SCIP_STAT* stat, /**< problem statistics data */
2417 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2418 SCIP_LP* lp, /**< SCIP LP, needed to release variable */
2419 SCIP_VAR* var /**< variable that has been fixed */
2420 )
2421 {
2422 int i;
2423
2424 assert(nlp != NULL);
2425 assert(var != NULL);
2426 assert(!SCIPvarIsActive(var));
2427 assert(!nlp->indiving);
2428 assert(SCIPhashmapExists(nlp->varhash, var));
2429
2430 /* remove var from all rows */
2431 for( i = 0; i < nlp->nnlrows; ++i )
2432 {
2433 SCIP_CALL( nlrowRemoveFixedVar(nlp->nlrows[i], blkmem, set, stat, nlp, var) );
2434 }
2435
2436 /* remove variable from NLP */
2437 SCIP_CALL( SCIPnlpDelVar(nlp, blkmem, set, stat, eventqueue, lp, var) );
2438
2439 return SCIP_OKAY;
2440 }
2441
2442 /** creates arrays with NLPI variable indices of linear variables in a nonlinear row */
2443 static
2444 SCIP_RETCODE nlpSetupNlpiIndices(
2445 SCIP_NLP* nlp, /**< NLP data */
2446 SCIP_SET* set, /**< global SCIP settings */
2447 SCIP_NLROW* nlrow, /**< nonlinear row */
2448 int** linidxs /**< buffer to store pointer to NLPI indices of linear variables */
2449 )
2450 {
2451 int i;
2452 SCIP_VAR* var;
2453
2454 assert(nlp != NULL);
2455 assert(set != NULL);
2456 assert(nlrow != NULL);
2457 assert(linidxs != NULL);
2458
2459 /* get indices of variables in linear part of row */
2460 if( nlrow->nlinvars > 0 )
2461 {
2462 assert(nlrow->linvars != NULL);
2463 assert(nlrow->lincoefs != NULL);
2464
2465 SCIP_CALL( SCIPsetAllocBufferArray(set, linidxs, nlrow->nlinvars) );
2466
2467 for( i = 0; i < nlrow->nlinvars; ++i )
2468 {
2469 var = nlrow->linvars[i];
2470 assert(var != NULL);
2471 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
2472
2473 assert(SCIPhashmapExists(nlp->varhash, var));
2474 (*linidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
2475 assert((*linidxs)[i] >= 0);
2476 }
2477 }
2478 else
2479 *linidxs = NULL;
2480
2481 return SCIP_OKAY;
2482 }
2483
2484 /** ensures, that NLPI variables array of NLP can store at least num entries */
2485 static
2486 SCIP_RETCODE nlpEnsureVarsSolverSize(
2487 SCIP_NLP* nlp, /**< NLP data */
2488 BMS_BLKMEM* blkmem, /**< block memory */
2489 SCIP_SET* set, /**< global SCIP settings */
2490 int num /**< minimum number of entries to store */
2491 )
2492 {
2493 assert(nlp != NULL);
2494 assert(blkmem != NULL);
2495 assert(set != NULL);
2496 assert(nlp->nvars_solver <= nlp->sizevars_solver);
2497
2498 if( num > nlp->sizevars_solver )
2499 {
2500 int newsize;
2501
2502 newsize = SCIPsetCalcMemGrowSize(set, num);
2503 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlpi2nlp, nlp->sizevars_solver, newsize) );
2504
2505 nlp->sizevars_solver = newsize;
2506 }
2507 assert(num <= nlp->sizevars_solver);
2508
2509 return SCIP_OKAY;
2510 }
2511
2512 /** ensures, that NLPI nonlinear rows array of NLP can store at least num entries */
2513 static
2514 SCIP_RETCODE nlpEnsureNlRowsSolverSize(
2515 SCIP_NLP* nlp, /**< NLP data */
2516 BMS_BLKMEM* blkmem, /**< block memory */
2517 SCIP_SET* set, /**< global SCIP settings */
2518 int num /**< minimum number of entries to store */
2519 )
2520 {
2521 assert(nlp != NULL);
2522 assert(blkmem != NULL);
2523 assert(set != NULL);
2524 assert(nlp->nnlrows_solver <= nlp->sizenlrows_solver);
2525
2526 if( num > nlp->sizenlrows_solver )
2527 {
2528 int newsize;
2529
2530 newsize = SCIPsetCalcMemGrowSize(set, num);
2531 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrowmap_nlpi2nlp, nlp->sizenlrows_solver, newsize) );
2532
2533 nlp->sizenlrows_solver = newsize;
2534 }
2535 assert(num <= nlp->sizenlrows_solver);
2536
2537 return SCIP_OKAY;
2538 }
2539
2540 /** deletes rows from the NLPI problem that have been marked as to remove */
2541 static
2542 SCIP_RETCODE nlpFlushNlRowDeletions(
2543 SCIP_NLP* nlp, /**< NLP data */
2544 BMS_BLKMEM* blkmem, /**< block memory */
2545 SCIP_SET* set /**< global SCIP settings */
2546 )
2547 {
2548 int j;
2549 int c; /* counts the number of rows to delete */
2550 int* rowset; /* marks which rows to delete and stores new indices */
2551 SCIP_NLROW* nlrow;
2552
2553 assert(nlp != NULL);
2554 assert(blkmem != NULL);
2555 assert(set != NULL);
2556 assert(nlp->nunflushednlrowdel >= 0);
2557 assert(!nlp->indiving);
2558
2559 if( nlp->nunflushednlrowdel == 0 )
2560 {
2561 #ifndef NDEBUG
2562 /* check that there are really no pending removals of nonlinear rows */
2563 for( j = 0; j < nlp->nnlrows_solver; ++j )
2564 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2565 #endif
2566 return SCIP_OKAY;
2567 }
2568
2569 assert(nlp->solver != NULL);
2570 assert(nlp->problem != NULL);
2571
2572 /* create marker which rows have to be deleted */
2573 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowset, nlp->nnlrows_solver) );
2574 c = 0;
2575 for( j = 0; j < nlp->nnlrows_solver; ++j )
2576 {
2577 if( nlp->nlrowmap_nlpi2nlp[j] == -1 )
2578 {
2579 rowset[j] = 1;
2580 ++c;
2581 }
2582 else
2583 rowset[j] = 0;
2584 }
2585 assert(c == nlp->nunflushednlrowdel);
2586
2587 /* remove rows from NLPI problem */
2588 SCIP_CALL( SCIPnlpiDelConsSet(set, nlp->solver, nlp->problem, rowset, nlp->nnlrows_solver) );
2589
2590 /* update NLPI row indices */
2591 for( j = 0; j < nlp->nnlrows_solver; ++j )
2592 {
2593 assert(rowset[j] <= j); /* we assume that the NLP solver did not move a row behind its previous position!! */
2594 if( rowset[j] < 0 )
2595 {
2596 /* assert that row was marked as deleted */
2597 assert(nlp->nlrowmap_nlpi2nlp[j] == -1);
2598 }
2599 else if( rowset[j] < j )
2600 {
2601 /* nlrow at position j moved (forward) to position rowset[j] */
2602 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2603 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2604
2605 nlrow = nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]];
2606 assert(nlrow->nlpiindex == j);
2607
2608 /* there should be no row at the new position already */
2609 assert(nlp->nlrowmap_nlpi2nlp[rowset[j]] == -1);
2610
2611 nlrow->nlpiindex = rowset[j];
2612 nlp->nlrowmap_nlpi2nlp[rowset[j]] = nlrow->nlpindex;
2613 }
2614 else
2615 {
2616 /* row j stays at position j */
2617 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2618 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2619 assert(nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]->nlpiindex == j);
2620 }
2621 }
2622 nlp->nnlrows_solver -= c;
2623 nlp->nunflushednlrowdel = 0;
2624
2625 /* cleanup */
2626 SCIPsetFreeBufferArray(set, &rowset);
2627
2628 return SCIP_OKAY;
2629 }
2630
2631 /** deletes variables from the NLPI problem that have been marked as to remove
2632 *
2633 * assumes that there are no pending row deletions (nlpFlushNlRowDeletions() should be called first)
2634 */
2635 static
2636 SCIP_RETCODE nlpFlushVarDeletions(
2637 SCIP_NLP* nlp, /**< NLP data */
2638 BMS_BLKMEM* blkmem, /**< block memory */
2639 SCIP_SET* set /**< global SCIP settings */
2640 )
2641 {
2642 int i;
2643 int c; /* counter on number of variables to remove in solver */
2644 int* colset; /* marks which variables to delete and stores new indices */
2645
2646 assert(nlp != NULL);
2647 assert(blkmem != NULL);
2648 assert(set != NULL);
2649 assert(nlp->nunflushedvardel >= 0);
2650 assert(nlp->nunflushednlrowdel == 0);
2651 assert(!nlp->indiving);
2652
2653 if( nlp->nunflushedvardel == 0 )
2654 {
2655 #ifndef NDEBUG
2656 /* check that there are really no pending removals of variables */
2657 for( i = 0; i < nlp->nvars_solver; ++i )
2658 assert(nlp->varmap_nlpi2nlp[i] >= 0);
2659 #endif
2660 return SCIP_OKAY;
2661 }
2662
2663 assert(nlp->solver != NULL);
2664 assert(nlp->problem != NULL);
2665
2666 /* create marker which variables have to be deleted */
2667 SCIP_CALL( SCIPsetAllocBufferArray(set, &colset, nlp->nvars_solver) );
2668 c = 0;
2669 for( i = 0; i < nlp->nvars_solver; ++i )
2670 {
2671 if( nlp->varmap_nlpi2nlp[i] == -1 )
2672 {
2673 colset[i] = 1;
2674 ++c;
2675 }
2676 else
2677 colset[i] = 0;
2678 }
2679 assert(c == nlp->nunflushedvardel);
2680
2681 /* delete variables from NLPI problem */
2682 SCIP_CALL( SCIPnlpiDelVarSet(set, nlp->solver, nlp->problem, colset, nlp->nvars_solver) );
2683
2684 /* update NLPI variable indices */
2685 for( i = 0; i < nlp->nvars_solver; ++i )
2686 {
2687 assert(colset[i] <= i); /* we assume that the NLP solver did not move a variable behind its previous position!! */
2688 if( colset[i] < 0 )
2689 {
2690 /* assert that variable was marked as deleted */
2691 assert(nlp->varmap_nlpi2nlp[i] == -1);
2692 }
2693 else if( colset[i] < i)
2694 {
2695 /* variable at position i moved (forward) to position colset[i] */
2696 int varpos;
2697
2698 varpos = nlp->varmap_nlpi2nlp[i]; /* position of variable i in NLP */
2699 assert(varpos >= 0);
2700 assert(varpos < nlp->nvars);
2701 assert(nlp->varmap_nlp2nlpi[varpos] == i);
2702
2703 /* there should be no variable at the new position already */
2704 assert(nlp->varmap_nlpi2nlp[colset[i]] == -1);
2705
2706 nlp->varmap_nlp2nlpi[varpos] = colset[i];
2707 nlp->varmap_nlpi2nlp[colset[i]] = varpos;
2708 }
2709 else
2710 {
2711 /* variable i stays at position i */
2712 assert(nlp->varmap_nlpi2nlp[i] >= 0);
2713 assert(nlp->varmap_nlpi2nlp[i] < nlp->nvars);
2714 assert(nlp->varmap_nlp2nlpi[nlp->varmap_nlpi2nlp[i]] == i);
2715 }
2716 }
2717
2718 nlp->nvars_solver -= c;
2719 nlp->nunflushedvardel = 0;
2720
2721 /* cleanup */
2722 SCIPsetFreeBufferArray(set, &colset);
2723
2724 return SCIP_OKAY;
2725 }
2726
2727 /** adds nonlinear rows to NLPI problem that have been added to NLP before
2728 *
2729 * assumes that there are no pending variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2730 */
2731 static
2732 SCIP_RETCODE nlpFlushNlRowAdditions(
2733 SCIP_NLP* nlp, /**< NLP data */
2734 BMS_BLKMEM* blkmem, /**< block memory */
2735 SCIP_SET* set, /**< global SCIP settings */
2736 SCIP_STAT* stat /**< problem statistics */
2737 )
2738 {
2739 int c, i;
2740 SCIP_NLROW* nlrow;
2741 SCIP_Real* lhss;
2742 SCIP_Real* rhss;
2743 int* nlinvars;
2744 int** linidxs;
2745 SCIP_Real** lincoefs;
2746 SCIP_EXPR** exprs;
2747 const char** names;
2748
2749 assert(nlp != NULL);
2750 assert(blkmem != NULL);
2751 assert(set != NULL);
2752 assert(nlp->nunflushednlrowadd >= 0);
2753 assert(nlp->nunflushedvaradd == 0);
2754 assert(nlp->nunflushedvardel == 0);
2755 assert(!nlp->indiving);
2756
2757 if( nlp->nunflushednlrowadd == 0 )
2758 {
2759 #ifndef NDEBUG
2760 /* check that there are really no pending additions of variables */
2761 for( i = 0; i < nlp->nnlrows; ++i )
2762 assert(nlp->nlrows[i]->nlpiindex >= 0);
2763 #endif
2764 return SCIP_OKAY;
2765 }
2766
2767 assert(nlp->solver != NULL);
2768 assert(nlp->problem != NULL);
2769
2770 SCIP_CALL( nlpEnsureNlRowsSolverSize(nlp, blkmem, set, nlp->nnlrows_solver + nlp->nunflushednlrowadd) );
2771
2772 SCIP_CALL( SCIPsetAllocBufferArray(set, &lhss, nlp->nunflushednlrowadd) );
2773 SCIP_CALL( SCIPsetAllocBufferArray(set, &rhss, nlp->nunflushednlrowadd) );
2774 SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinvars, nlp->nunflushednlrowadd) );
2775 SCIP_CALL( SCIPsetAllocBufferArray(set, &linidxs, nlp->nunflushednlrowadd) );
2776 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nunflushednlrowadd) );
2777 SCIP_CALL( SCIPsetAllocBufferArray(set, &exprs, nlp->nunflushednlrowadd) );
2778 #if ADDNAMESTONLPI
2779 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushednlrowadd) );
2780 #else
2781 names = NULL;
2782 #endif
2783
2784 c = 0;
2785 for( i = 0; i < nlp->nnlrows; ++i )
2786 {
2787 nlrow = nlp->nlrows[i];
2788 assert(nlrow != NULL);
2789
2790 /* skip nonlinear rows already in NLPI problem */
2791 if( nlrow->nlpiindex >= 0 )
2792 continue;
2793 assert(c < nlp->nunflushednlrowadd);
2794
2795 /* get indices in NLPI */
2796 SCIP_CALL( nlpSetupNlpiIndices(nlp, set, nlrow, &linidxs[c]) );
2797 assert(linidxs[c] != NULL || nlrow->nlinvars == 0);
2798
2799 nlp->nlrowmap_nlpi2nlp[nlp->nnlrows_solver+c] = i;
2800 nlrow->nlpiindex = nlp->nnlrows_solver+c;
2801
2802 lhss[c] = nlrow->lhs;
2803 rhss[c] = nlrow->rhs;
2804 if( nlrow->constant != 0.0 )
2805 {
2806 if( !SCIPsetIsInfinity(set, -nlrow->lhs) )
2807 lhss[c] -= nlrow->constant;
2808 if( !SCIPsetIsInfinity(set, nlrow->rhs) )
2809 rhss[c] -= nlrow->constant;
2810 }
2811 if( rhss[c] < lhss[c] )
2812 {
2813 assert(SCIPsetIsEQ(set, lhss[c], rhss[c]));
2814 rhss[c] = lhss[c];
2815 }
2816
2817 nlinvars[c] = nlrow->nlinvars;
2818 lincoefs[c] = nlrow->lincoefs;
2819
2820 if( nlrow->expr != NULL )
2821 {
2822 /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */
2823 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &exprs[c], mapvar2varidx, (void*)nlp, NULL, NULL) );
2824 }
2825 else
2826 exprs[c] = NULL;
2827
2828 #if ADDNAMESTONLPI
2829 names[c] = nlrow->name;
2830 #endif
2831
2832 ++c;
2833
2834 #ifdef NDEBUG
2835 /* have c vars to add already, there can be no more */
2836 if( c == nlp->nunflushednlrowadd )
2837 break;
2838 #endif
2839 }
2840 assert(c == nlp->nunflushednlrowadd);
2841
2842 nlp->nnlrows_solver += c;
2843
2844 SCIP_CALL( SCIPnlpiAddConstraints(set, nlp->solver, nlp->problem, c, lhss, rhss,
2845 nlinvars, linidxs, lincoefs,
2846 exprs,
2847 names) );
2848
2849 for( c = nlp->nunflushednlrowadd - 1; c >= 0 ; --c )
2850 {
2851 if( linidxs[c] != NULL )
2852 SCIPsetFreeBufferArray(set, &linidxs[c]);
2853 if( exprs[c] != NULL )
2854 {
2855 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &exprs[c]) );
2856 }
2857 }
2858
2859 #if ADDNAMESTONLPI
2860 SCIPsetFreeBufferArray(set, &names);
2861 #endif
2862 SCIPsetFreeBufferArray(set, &exprs);
2863 SCIPsetFreeBufferArray(set, &lincoefs);
2864 SCIPsetFreeBufferArray(set, &linidxs);
2865 SCIPsetFreeBufferArray(set, &nlinvars);
2866 SCIPsetFreeBufferArray(set, &rhss);
2867 SCIPsetFreeBufferArray(set, &lhss);
2868
2869 nlp->nunflushednlrowadd = 0;
2870
2871 return SCIP_OKAY;
2872 }
2873
2874
2875 /** adds variables to NLPI problem that have been added to NLP before
2876 *
2877 * may set nlp->objflushed to FALSE if a variable with nonzero objective coefficient is added to the NLPI problem
2878 */
2879 static
2880 SCIP_RETCODE nlpFlushVarAdditions(
2881 SCIP_NLP* nlp, /**< NLP data */
2882 BMS_BLKMEM* blkmem, /**< block memory */
2883 SCIP_SET* set /**< global SCIP settings */
2884 )
2885 {
2886 int i, c;
2887 SCIP_Real* lbs;
2888 SCIP_Real* ubs;
2889 const char** names;
2890
2891 assert(nlp != NULL);
2892 assert(blkmem != NULL);
2893 assert(set != NULL);
2894 assert(nlp->nunflushedvaradd >= 0);
2895 assert(!nlp->indiving);
2896
2897 if( nlp->nunflushedvaradd == 0 )
2898 {
2899 #ifndef NDEBUG
2900 /* check that there are really no pending additions of variables */
2901 for( i = 0; i < nlp->nvars; ++i )
2902 assert(nlp->varmap_nlp2nlpi[i] >= 0);
2903 #endif
2904 return SCIP_OKAY;
2905 }
2906
2907 assert(nlp->solver != NULL);
2908 assert(nlp->problem != NULL);
2909
2910 SCIP_CALL( nlpEnsureVarsSolverSize(nlp, blkmem, set, nlp->nvars_solver + nlp->nunflushedvaradd) );
2911
2912 SCIP_CALL( SCIPsetAllocBufferArray(set, &lbs, nlp->nunflushedvaradd) );
2913 SCIP_CALL( SCIPsetAllocBufferArray(set, &ubs, nlp->nunflushedvaradd) );
2914 #if ADDNAMESTONLPI
2915 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushedvaradd) );
2916 #else
2917 names = NULL;
2918 #endif
2919
2920 c = 0;
2921 for( i = 0; i < nlp->nvars; ++i )
2922 {
2923 /* skip variables already in NLPI problem */
2924 if( nlp->varmap_nlp2nlpi[i] >= 0 )
2925 continue;
2926 assert(c < nlp->nunflushedvaradd);
2927
2928 nlp->varmap_nlpi2nlp[nlp->nvars_solver+c] = i;
2929 nlp->varmap_nlp2nlpi[i] = nlp->nvars_solver+c;
2930 lbs[c] = SCIPvarGetLbLocal(nlp->vars[i]);
2931 ubs[c] = SCIPvarGetUbLocal(nlp->vars[i]);
2932 #if ADDNAMESTONLPI
2933 names[c] = SCIPvarGetName(nlp->vars[i]);
2934 #endif
2935 ++c;
2936
2937 /* if the new variable has a nonzero objective coefficient, then the objective need to be updated */
2938 if( !SCIPsetIsZero(set, SCIPvarGetObj(nlp->vars[i])) )
2939 nlp->objflushed = FALSE;
2940
2941 #ifdef NDEBUG
2942 /* have c vars to add already, there can be no more */
2943 if( c == nlp->nunflushedvaradd )
2944 break;
2945 #endif
2946 }
2947 assert(c == nlp->nunflushedvaradd);
2948
2949 nlp->nvars_solver += c;
2950
2951 SCIP_CALL( SCIPnlpiAddVars(set, nlp->solver, nlp->problem, c, lbs, ubs, names) );
2952
2953 #if ADDNAMESTONLPI
2954 SCIPsetFreeBufferArray(set, &names);
2955 #endif
2956 SCIPsetFreeBufferArray(set, &ubs);
2957 SCIPsetFreeBufferArray(set, &lbs);
2958
2959 nlp->nunflushedvaradd = 0;
2960
2961 return SCIP_OKAY;
2962 }
2963
2964 /** updates the objective in the NLPI problem, if necessary
2965 *
2966 * assumes that there are no unflushed variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2967 */
2968 static
2969 SCIP_RETCODE nlpFlushObjective(
2970 SCIP_NLP* nlp, /**< NLP data */
2971 BMS_BLKMEM* blkmem, /**< block memory */
2972 SCIP_SET* set /**< global SCIP settings */
2973 )
2974 {
2975 int* linindices;
2976 SCIP_Real* lincoefs;
2977 SCIP_Real coef;
2978 int i;
2979 int nz;
2980
2981 assert(nlp != NULL);
2982 assert(blkmem != NULL);
2983 assert(set != NULL);
2984 assert(nlp->nunflushedvaradd == 0);
2985 assert(nlp->nunflushedvardel == 0);
2986 assert(!nlp->indiving);
2987
2988 if( nlp->objflushed )
2989 return SCIP_OKAY;
2990
2991 assert(nlp->solver != NULL);
2992 assert(nlp->problem != NULL);
2993
2994 /* assemble coefficients */
2995 SCIP_CALL( SCIPsetAllocBufferArray(set, &linindices, nlp->nvars_solver) );
2996 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nvars_solver) );
2997
2998 nz = 0;
2999 for( i = 0; i < nlp->nvars_solver; ++i )
3000 {
3001 assert(nlp->varmap_nlpi2nlp[i] >= 0); /* there should be no variable deletions pending */
3002
3003 coef = SCIPvarGetObj(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
3004 if( SCIPsetIsZero(set, coef) )
3005 continue;
3006
3007 linindices[nz] = i;
3008 lincoefs[nz] = coef;
3009 ++nz;
3010 }
3011
3012 SCIP_CALL( SCIPnlpiSetObjective(set, nlp->solver, nlp->problem,
3013 nz, linindices, lincoefs,
3014 NULL,
3015 0.0) );
3016
3017 SCIPsetFreeBufferArray(set, &lincoefs);
3018 SCIPsetFreeBufferArray(set, &linindices);
3019
3020 nlp->objflushed = TRUE;
3021
3022 return SCIP_OKAY;
3023 }
3024
3025 /** solves the NLP (or diving NLP), assuming it has been flushed already */
3026 static
3027 SCIP_RETCODE nlpSolve(
3028 SCIP_NLP* nlp, /**< NLP data */
3029 BMS_BLKMEM* blkmem, /**< block memory buffers */
3030 SCIP_SET* set, /**< global SCIP settings */
3031 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3032 SCIP_STAT* stat, /**< problem statistics */
3033 SCIP_PRIMAL* primal, /**< primal data */
3034 SCIP_TREE* tree, /**< branch and bound tree */
3035 SCIP_NLPPARAM* nlpparam /**< NLP solve parameters */
3036 )
3037 {
3038 int i;
3039
3040 assert(nlp != NULL);
3041 assert(blkmem != NULL);
3042 assert(set != NULL);
3043 assert(stat != NULL);
3044
3045 if( nlp->solver == NULL )
3046 {
3047 SCIPmessagePrintWarning(messagehdlr, "Attempted to solve NLP, but no solver available.\n");
3048
3049 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3050 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3051
3052 return SCIP_OKAY;
3053 }
3054
3055 assert(nlp->solver != NULL);
3056 assert(nlp->problem != NULL);
3057
3058 /* set initial guess, if available and warmstart hasn't been enabled
3059 * when using the NLP, passing a dual solution with the initguess is not available at the moment (TODO),
3060 * so a warmstart has to start from the last solution stored in the NLPI
3061 */
3062 if( nlp->haveinitguess && !nlpparam->warmstart )
3063 {
3064 /* @todo should we not set it if we had set it already? (initguessflushed...) */
3065 SCIP_Real* initialguess_solver;
3066 int nlpidx;
3067
3068 assert(nlp->initialguess != NULL);
3069
3070 SCIP_CALL( SCIPsetAllocBufferArray(set, &initialguess_solver, nlp->nvars_solver) );
3071
3072 for( i = 0; i < nlp->nvars_solver; ++i )
3073 {
3074 nlpidx = nlp->varmap_nlpi2nlp[i];
3075 assert(nlpidx >= 0);
3076 assert(nlpidx < nlp->nvars);
3077
3078 initialguess_solver[i] = nlp->initialguess[nlpidx];
3079 }
3080 SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, initialguess_solver, NULL, NULL, NULL) );
3081
3082 SCIPsetFreeBufferArray(set, &initialguess_solver);
3083 }
3084
3085 /* let NLP solver do his work */
3086 SCIPclockStart(stat->nlpsoltime, set);
3087
3088 SCIP_CALL( SCIPnlpiSolve(set, stat, nlp->solver, nlp->problem, nlpparam) );
3089
3090 SCIPclockStop(stat->nlpsoltime, set);
3091 ++stat->nnlps;
3092
3093 nlp->termstat = SCIPnlpiGetTermstat(set, nlp->solver, nlp->problem);
3094 nlp->solstat = SCIPnlpiGetSolstat(set, nlp->solver, nlp->problem);
3095 switch( nlp->solstat )
3096 {
3097 case SCIP_NLPSOLSTAT_GLOBOPT:
3098 case SCIP_NLPSOLSTAT_LOCOPT:
3099 case SCIP_NLPSOLSTAT_FEASIBLE:
3100 case SCIP_NLPSOLSTAT_LOCINFEASIBLE:
3101 {
3102 SCIP_Real* primalvals;
3103 SCIP_Real* nlrowdualvals;
3104 SCIP_Real* varlbdualvals;
3105 SCIP_Real* varubdualvals;
3106
3107 primalvals = NULL;
3108 nlrowdualvals = NULL;
3109 varlbdualvals = NULL;
3110 varubdualvals = NULL;
3111
3112 /* get NLP solution */
3113 SCIP_CALL( SCIPnlpiGetSolution(set, nlp->solver, nlp->problem, &primalvals, &nlrowdualvals, &varlbdualvals, &varubdualvals, NULL) );
3114 assert(primalvals != NULL || nlp->nvars == 0);
3115 assert((varlbdualvals != NULL) == (varubdualvals != NULL)); /* if there are duals for one bound, then there should also be duals for the other bound */
3116
3117 /* store solution primal values in variable and evaluate objective function */
3118 if( nlp->indiving && nlp->divingobj != NULL )
3119 {
3120 for( i = 0; i < nlp->nvars; ++i )
3121 {
3122 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, primalvals[nlp->varmap_nlp2nlpi[i]]) ); /*lint !e613 */
3123 }
3124
3125 /* evaluate modified diving objective */
3126 SCIP_CALL( SCIPnlrowGetNLPActivity(nlp->divingobj, blkmem, set, stat, primal, tree, nlp, &nlp->primalsolobjval) );
3127 }
3128 else
3129 {
3130 /* evaluate SCIP objective function */
3131 nlp->primalsolobjval = 0.0;
3132 for( i = 0; i < nlp->nvars; ++i )
3133 {
3134 SCIP_Real solval = primalvals[nlp->varmap_nlp2nlpi[i]]; /*lint !e613 */
3135
3136 /* do a quick assert that variable bounds are satisfied, if feasibility is claimed */
3137 assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(nlp->vars[i])) ||
3138 SCIPsetIsFeasGE(set, solval, SCIPvarGetLbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3139 assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(nlp->vars[i])) ||
3140 SCIPsetIsFeasLE(set, solval, SCIPvarGetUbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3141
3142 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, solval) ); /*lint !e613 */
3143 nlp->primalsolobjval += SCIPvarGetObj(nlp->vars[i]) * solval; /*lint !e613 */
3144 }
3145 }
3146
3147 /* store solution dual values in nlrows and variables */
3148 for( i = 0; i < nlp->nnlrows; ++i )
3149 {
3150 assert(nlp->nlrows[i]->nlpiindex >= 0); /* NLP was flushed before solve, so all nlrows should be in there */
3151
3152 nlp->nlrows[i]->dualsol = nlrowdualvals != NULL ? nlrowdualvals[nlp->nlrows[i]->nlpiindex] : 0.0;
3153
3154 /* SCIPsetDebugMsg(set, "dual of nlrow <%s> = %g\n", nlp->nlrows[i]->name, nlp->nlrows[i]->dualsol); */
3155 }
3156 assert(nlp->varlbdualvals != NULL || nlp->nvars == 0);
3157 assert(nlp->varubdualvals != NULL || nlp->nvars == 0);
3158 if( varlbdualvals != NULL )
3159 {
3160 for( i = 0; i < nlp->nvars; ++i )
3161 {
3162 assert(nlp->varmap_nlp2nlpi[i] >= 0); /* NLP was flushed before solve, so all vars should be in there */
3163
3164 nlp->varlbdualvals[i] = varlbdualvals[nlp->varmap_nlp2nlpi[i]];
3165 nlp->varubdualvals[i] = varubdualvals[nlp->varmap_nlp2nlpi[i]];
3166
3167 /* SCIPsetDebugMsg(set, "duals of var <%s> = %g %g\n", SCIPvarGetName(nlp->vars[i]), nlp->varlbdualvals[i], nlp->varubdualvals[i]); */
3168 }
3169 }
3170 else if( nlp->nvars > 0 )
3171 {
3172 BMSclearMemoryArray(nlp->varlbdualvals, nlp->nvars);
3173 BMSclearMemoryArray(nlp->varubdualvals, nlp->nvars);
3174 }
3175
3176 break;
3177 }
3178 default:
3179 nlp->primalsolobjval = SCIP_INVALID;
3180 break;
3181 } /*lint !e788*/
3182
3183 return SCIP_OKAY;
3184 }
3185
3186 /** assembles list of fractional variables in last NLP solution */
3187 static
3188 SCIP_RETCODE nlpCalcFracVars(
3189 SCIP_NLP* nlp, /**< NLP data */
3190 BMS_BLKMEM* blkmem, /**< block memory buffers */
3191 SCIP_SET* set, /**< global SCIP settings */
3192 SCIP_STAT* stat /**< problem statistics */
3193 )
3194 {
3195 assert(nlp != NULL);
3196 assert(blkmem != NULL);
3197 assert(set != NULL);
3198 assert(stat != NULL);
3199 assert(nlp->validfracvars <= stat->nnlps);
3200 assert(SCIPnlpHasSolution(nlp));
3201
3202 SCIPsetDebugMsg(set, "calculating NLP fractional variables: validfracvars=%" SCIP_LONGINT_FORMAT ", nnlps=%" SCIP_LONGINT_FORMAT "\n", nlp->validfracvars, stat->nnlps);
3203
3204 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
3205 {
3206 nlp->nfracvars = 0;
3207 nlp->npriofracvars = 0;
3208 nlp->validfracvars = stat->nnlps;
3209
3210 SCIPsetDebugMsg(set, "NLP globally infeasible, unbounded, or worse -> no solution values -> no fractional variables\n");
3211 return SCIP_OKAY;
3212 }
3213
3214 /* check, if the current NLP fractional variables array is invalid */
3215 if( nlp->validfracvars < stat->nnlps )
3216 {
3217 SCIP_VAR* var;
3218 SCIP_Real primsol;
3219 SCIP_Real frac;
3220 int branchpriority;
3221 int insertpos;
3222 int maxpriority;
3223 int i;
3224
3225 SCIPsetDebugMsg(set, " -> recalculating NLP fractional variables\n");
3226
3227 if( nlp->fracvarssize == 0 )
3228 {
3229 assert(nlp->fracvars == NULL);
3230 assert(nlp->fracvarssol == NULL);
3231 assert(nlp->fracvarsfrac == NULL);
3232 nlp->fracvarssize = 5;
3233 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize) );
3234 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize) );
3235 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize) );
3236 }
3237
3238 maxpriority = INT_MIN;
3239 nlp->nfracvars = 0;
3240 nlp->npriofracvars = 0;
3241 for( i = 0; i < nlp->nvars; ++i )
3242 {
3243 var = nlp->vars[i];
3244 assert(var != NULL);
3245
3246 primsol = SCIPvarGetNLPSol(var);
3247 assert(primsol < SCIP_INVALID);
3248
3249 /* consider only binary and integer variables */
3250 if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER )
3251 continue;
3252
3253 /* ignore fixed variables (due to numerics, it is possible, that the NLP solution of a fixed integer variable
3254 * (with large fixed value) is fractional in terms of absolute feasibility measure)
3255 */
3256 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
3257 continue;
3258
3259 /* check, if the LP solution value is fractional */
3260 frac = SCIPsetFeasFrac(set, primsol);
3261
3262 /* The fractionality should not be smaller than -feastol, however, if the primsol is large enough
3263 * and close to an integer, fixed precision floating point arithmetic might give us values slightly
3264 * smaller than -feastol. Originally, the "frac >= -feastol"-check was within SCIPsetIsFeasFracIntegral(),
3265 * however, we relaxed it to "frac >= -2*feastol" and have the stricter check here for small-enough primsols.
3266 */
3267 assert(SCIPsetIsGE(set, frac, -SCIPsetFeastol(set)) || (primsol > 1e14 * SCIPsetFeastol(set)));
3268
3269 if( SCIPsetIsFeasFracIntegral(set, frac) )
3270 continue;
3271
3272 /* ensure enough space in fracvars arrays */
3273 if( nlp->fracvarssize <= nlp->nfracvars )
3274 {
3275 int newsize;
3276
3277 newsize = SCIPsetCalcMemGrowSize(set, nlp->nfracvars + 1);
3278 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize, newsize) );
3279 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize, newsize) );
3280 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize, newsize) );
3281 nlp->fracvarssize = newsize;
3282 }
3283 assert(nlp->nfracvars < nlp->fracvarssize);
3284 assert(nlp->fracvars != NULL);
3285 assert(nlp->fracvarssol != NULL);
3286 assert(nlp->fracvarsfrac != NULL);
3287
3288 /* insert candidate in candidate list */
3289 branchpriority = SCIPvarGetBranchPriority(var);
3290 insertpos = nlp->nfracvars;
3291 nlp->nfracvars++;
3292 if( branchpriority > maxpriority )
3293 {
3294 /* candidate has higher priority than the current maximum:
3295 * move it to the front and declare it to be the single best candidate
3296 */
3297 if( insertpos != 0 )
3298 {
3299 nlp->fracvars[insertpos] = nlp->fracvars[0];
3300 nlp->fracvarssol[insertpos] = nlp->fracvarssol[0];
3301 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[0];
3302 insertpos = 0;
3303 }
3304 nlp->npriofracvars = 1;
3305 maxpriority = branchpriority;
3306 }
3307 else if( branchpriority == maxpriority )
3308 {
3309 /* candidate has equal priority as the current maximum:
3310 * move away the first non-maximal priority candidate, move the current candidate to the correct
3311 * slot (binaries first) and increase the number of maximal priority candidates
3312 */
3313 if( insertpos != nlp->npriofracvars )
3314 {
3315 nlp->fracvars[insertpos] = nlp->fracvars[nlp->npriofracvars];
3316 nlp->fracvarssol[insertpos] = nlp->fracvarssol[nlp->npriofracvars];
3317 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[nlp->npriofracvars];
3318 insertpos = nlp->npriofracvars;
3319 }
3320 ++nlp->npriofracvars;
3321 }
3322 nlp->fracvars[insertpos] = var;
3323 nlp->fracvarssol[insertpos] = primsol;
3324 nlp->fracvarsfrac[insertpos] = frac;
3325
3326 SCIPsetDebugMsg(set, " -> candidate %d: var=<%s>, sol=%g, frac=%g, prio=%d (max: %d) -> pos %d\n",
3327 nlp->nfracvars, SCIPvarGetName(var), primsol, frac, branchpriority, maxpriority, insertpos);
3328 }
3329
3330 nlp->validfracvars = stat->nnlps;
3331 }
3332 assert(0 <= nlp->npriofracvars);
3333 assert(nlp->npriofracvars <= nlp->nfracvars);
3334
3335 SCIPsetDebugMsg(set, " -> %d fractional variables (%d of maximal priority)\n", nlp->nfracvars, nlp->npriofracvars);
3336
3337 return SCIP_OKAY;
3338 }
3339
3340 /** event handling for variable events */
3341 static
3342 SCIP_DECL_EVENTEXEC(eventExecNlp)
3343 {
3344 SCIP_EVENTTYPE etype;
3345 SCIP_VAR* var;
3346
3347 assert(scip != NULL);
3348 assert(eventhdlr != NULL);
3349 assert(event != NULL);
3350 assert(eventdata != NULL);
3351
3352 assert((SCIP_NLP*)eventdata == scip->nlp);
3353
3354 etype = SCIPeventGetType(event);
3355 var = SCIPeventGetVar(event);
3356
3357 if( SCIP_EVENTTYPE_VARADDED & etype )
3358 {
3359 SCIPdebugMessage("-> handling varadd event, variable <%s>\n", SCIPvarGetName(var) );
3360 SCIP_CALL( SCIPnlpAddVar(scip->nlp, SCIPblkmem(scip), scip->set, var) );
3361 }
3362 else if( SCIP_EVENTTYPE_VARDELETED & etype )
3363 {
3364 SCIPdebugMessage("-> handling vardel event, variable <%s>\n", SCIPvarGetName(var) );
3365 SCIP_CALL( SCIPnlpDelVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3366 }
3367 else if( SCIP_EVENTTYPE_VARFIXED & etype )
3368 {
3369 /* variable was fixed, aggregated, or multi-aggregated */
3370 /* TODO is this ever happening? that is, can we have changes in a variable status during solve? */
3371 SCIPdebugMessage("-> handling variable fixation event, variable <%s>\n", SCIPvarGetName(var) );
3372 SCIP_CALL( nlpRemoveFixedVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3373 }
3374 else if( SCIP_EVENTTYPE_BOUNDCHANGED & etype )
3375 {
3376 SCIPdebugMessage("-> handling bound changed event %" SCIP_EVENTTYPE_FORMAT ", variable <%s>\n", etype, SCIPvarGetName(var) );
3377 SCIP_CALL( nlpUpdateVarBounds(scip->nlp, scip->set, var, (SCIP_Bool)(SCIP_EVENTTYPE_BOUNDTIGHTENED & etype)) );
3378 }
3379 else if( SCIP_EVENTTYPE_OBJCHANGED & etype )
3380 {
3381 SCIPdebugMessage("-> handling objchg event, variable <%s>\n", SCIPvarGetName(var) );
3382 SCIP_CALL( nlpUpdateObjCoef(scip->set, scip->nlp, var) );
3383 }
3384 else
3385 {
3386 SCIPerrorMessage("unexpected event %" SCIP_EVENTTYPE_FORMAT " on variable <%s>\n", etype, SCIPvarGetName(var) );
3387 return SCIP_ERROR;
3388 }
3389
3390 return SCIP_OKAY;
3391 }
3392
3393
3394 /*
3395 * public NLP methods
3396 */
3397
3398 /** includes event handler that is used by NLP */
3399 SCIP_RETCODE SCIPnlpInclude(
3400 SCIP_SET* set, /**< global SCIP settings */
3401 BMS_BLKMEM* blkmem /**< block memory */
3402 )
3403 {
3404 SCIP_EVENTHDLR* eventhdlr;
3405
3406 assert(set != NULL);
3407 assert(blkmem != NULL);
3408 assert(set->stage == SCIP_STAGE_INIT);
3409
3410 /* check whether event handler is already present */
3411 if( SCIPsetFindEventhdlr(set, EVENTHDLR_NAME) != NULL )
3412 {
3413 SCIPerrorMessage("event handler <" EVENTHDLR_NAME "> already included.\n");
3414 return SCIP_INVALIDDATA;
3415 }
3416
3417 SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC,
3418 NULL, NULL, NULL, NULL, NULL, NULL, NULL, eventExecNlp, NULL) );
3419 SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) );
3420
3421 return SCIP_OKAY;
3422 } /*lint !e715*/
3423
3424 /** construct a new empty NLP */
3425 SCIP_RETCODE SCIPnlpCreate(
3426 SCIP_NLP** nlp, /**< NLP handler, call by reference */
3427 BMS_BLKMEM* blkmem, /**< block memory */
3428 SCIP_SET* set, /**< global SCIP settings */
3429 SCIP_STAT* stat, /**< problem statistics */
3430 const char* name, /**< problem name */
3431 int nvars_estimate /**< an estimate on the number of variables that may be added to the NLP later */
3432 )
3433 {
3434 assert(nlp != NULL);
3435 assert(blkmem != NULL);
3436 assert(set != NULL);
3437 assert(stat != NULL);
3438 assert(name != NULL);
3439
3440 SCIP_ALLOC( BMSallocMemory(nlp) );
3441
3442 /* select NLP solver (if any available) and setup problem */
3443 if( set->nnlpis > 0 )
3444 {
3445 assert(set->nlp_solver != NULL);
3446 if( set->nlp_solver[0] == '\0' )
3447 { /* take solver with highest priority */
3448 assert(set->nlpis != NULL);
3449
3450 /* sort the NLPIs if necessary */
3451 if( !set->nlpissorted )
3452 SCIPsetSortNlpis(set);
3453
3454 (*nlp)->solver = set->nlpis[0];
3455 }
3456 else
3457 { /* find user specified NLP solver */
3458 (*nlp)->solver = SCIPsetFindNlpi(set, set->nlp_solver);
3459 if( (*nlp)->solver == NULL )
3460 {
3461 SCIPerrorMessage("Selected NLP solver <%s> not available.\n", set->nlp_solver);
3462 return SCIP_PLUGINNOTFOUND;
3463 }
3464 }
3465 assert((*nlp)->solver != NULL);
3466 SCIP_CALL( SCIPnlpiCreateProblem(set, (*nlp)->solver, &(*nlp)->problem, name) );
3467 }
3468 else
3469 {
3470 /* maybe someone wanna use the NLP just to collect nonlinearities, but is not necessarily interesting on solving
3471 * so we allow this and just continue */
3472 (*nlp)->solver = NULL;
3473 (*nlp)->problem = NULL;
3474 }
3475
3476 /* status */
3477 (*nlp)->nunflushedvaradd = 0;
3478 (*nlp)->nunflushedvardel = 0;
3479 (*nlp)->nunflushednlrowadd = 0;
3480 (*nlp)->nunflushednlrowdel = 0;
3481 (*nlp)->indiving = FALSE;
3482
3483 /* variables in problem and NLPI problem */
3484 (*nlp)->nvars = 0;
3485 (*nlp)->sizevars = 0;
3486 (*nlp)->vars = NULL;
3487 SCIP_CALL( SCIPhashmapCreate(&(*nlp)->varhash, blkmem, nvars_estimate) );
3488
3489 (*nlp)->nvars_solver = 0;
3490 (*nlp)->sizevars_solver = 0;
3491 (*nlp)->varmap_nlp2nlpi = NULL;
3492 (*nlp)->varmap_nlpi2nlp = NULL;
3493
3494 /* nonlinear rows in problem and NLPI problem */
3495 (*nlp)->nnlrows = 0;
3496 (*nlp)->sizenlrows = 0;
3497 (*nlp)->nlrows = NULL;
3498
3499 (*nlp)->nnlrows_solver = 0;
3500 (*nlp)->sizenlrows_solver = 0;
3501 (*nlp)->nlrowmap_nlpi2nlp = NULL;
3502
3503 /* objective function */
3504 (*nlp)->objflushed = TRUE;
3505 (*nlp)->divingobj = NULL;
3506
3507 /* initial guess */
3508 (*nlp)->haveinitguess = FALSE;
3509 (*nlp)->initialguess = NULL;
3510
3511 /* solution of NLP */
3512 (*nlp)->primalsolobjval = SCIP_INVALID;
3513 (*nlp)->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3514 (*nlp)->termstat = SCIP_NLPTERMSTAT_OTHER;
3515 (*nlp)->varlbdualvals = NULL;
3516 (*nlp)->varubdualvals = NULL;
3517
3518 /* event handling: catch variable addition and deletion events */
3519 (*nlp)->eventhdlr = SCIPsetFindEventhdlr(set, EVENTHDLR_NAME);
3520 if( (*nlp)->eventhdlr == NULL )
3521 {
3522 SCIPerrorMessage("NLP eventhandler <" EVENTHDLR_NAME "> not found.\n");
3523 return SCIP_PLUGINNOTFOUND;
3524 }
3525 SCIP_CALL( SCIPeventfilterAdd(set->scip->eventfilter, blkmem, set,
3526 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3527 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), &(*nlp)->globalfilterpos) );
3528
3529 /* fractional variables in last NLP solution */
3530 (*nlp)->fracvars = NULL;
3531 (*nlp)->fracvarssol = NULL;
3532 (*nlp)->fracvarsfrac = NULL;
3533 (*nlp)->nfracvars = 0;
3534 (*nlp)->npriofracvars = 0;
3535 (*nlp)->fracvarssize = 0;
3536 (*nlp)->validfracvars = -1;
3537
3538 /* miscellaneous */
3539 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlp)->name, name, strlen(name)+1) );
3540
3541 return SCIP_OKAY;
3542 }
3543
3544 /** frees NLP data object */
3545 SCIP_RETCODE SCIPnlpFree(
3546 SCIP_NLP** nlp, /**< pointer to NLP data object */
3547 BMS_BLKMEM* blkmem, /**< block memory */
3548 SCIP_SET* set, /**< global SCIP settings */
3549 SCIP_STAT* stat, /**< problem statistics */
3550 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3551 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */
3552 )
3553 {
3554 assert(nlp != NULL);
3555 assert(*nlp != NULL);
3556 assert(blkmem != NULL);
3557 assert(set != NULL);
3558
3559 /* drop fractional variables */
3560 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvars, (*nlp)->fracvarssize);
3561 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarssol, (*nlp)->fracvarssize);
3562 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarsfrac, (*nlp)->fracvarssize);
3563
3564 /* drop global events (variable addition and deletion) */
3565 SCIP_CALL( SCIPeventfilterDel(set->scip->eventfilter, blkmem, set,
3566 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3567 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), (*nlp)->globalfilterpos) );
3568
3569 SCIP_CALL( SCIPnlpReset(*nlp, blkmem, set, stat, eventqueue, lp) );
3570 assert((*nlp)->nnlrows == 0);
3571 assert((*nlp)->nnlrows_solver == 0);
3572 assert((*nlp)->nvars == 0);
3573 assert((*nlp)->nvars_solver == 0);
3574 assert((*nlp)->initialguess == NULL);
3575
3576 BMSfreeBlockMemoryArray(blkmem, &(*nlp)->name, strlen((*nlp)->name)+1);
3577
3578 /* free nonlinear rows arrays */
3579 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrowmap_nlpi2nlp, (*nlp)->sizenlrows_solver);
3580 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrows, (*nlp)->sizenlrows);
3581
3582 /* free variables arrays */
3583 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlp2nlpi, (*nlp)->sizevars);
3584 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlpi2nlp, (*nlp)->sizevars_solver);
3585 SCIPhashmapFree(&(*nlp)->varhash);
3586 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->vars, (*nlp)->sizevars);
3587 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varlbdualvals, (*nlp)->sizevars);
3588 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varubdualvals, (*nlp)->sizevars);
3589
3590 /* free NLPI problem */
3591 if( (*nlp)->problem != NULL )
3592 {
3593 SCIP_CALL( SCIPnlpiFreeProblem(set, (*nlp)->solver, &(*nlp)->problem) );
3594 }
3595
3596 /* free NLP data structure */
3597 BMSfreeMemory(nlp);
3598
3599 return SCIP_OKAY;
3600 }
3601
3602 /** resets the NLP to the empty NLP by removing all variables and rows from NLP,
3603 * releasing all rows, and flushing the changes to the NLP solver
3604 */
3605 SCIP_RETCODE SCIPnlpReset(
3606 SCIP_NLP* nlp, /**< NLP data */
3607 BMS_BLKMEM* blkmem, /**< block memory */
3608 SCIP_SET* set, /**< global SCIP settings */
3609 SCIP_STAT* stat, /**< problem statistics data */
3610 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3611 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */
3612 )
3613 {
3614 int i;
3615
3616 assert(nlp != NULL);
3617 assert(blkmem != NULL);
3618 assert(set != NULL);
3619
3620 if( nlp->indiving )
3621 {
3622 SCIP_CALL( SCIPnlpEndDive(nlp, blkmem, set, stat) );
3623 }
3624
3625 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
3626 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3627
3628 BMSfreeBlockMemoryArrayNull(blkmem, &nlp->initialguess, nlp->sizevars);
3629 nlp->haveinitguess = FALSE;
3630
3631 for(i = nlp->nnlrows - 1; i >= 0; --i)
3632 {
3633 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
3634 }
3635
3636 for(i = nlp->nvars - 1; i >= 0; --i)
3637 {
3638 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, i) );
3639 }
3640
3641 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3642
3643 return SCIP_OKAY;
3644 }
3645
3646 /** currently a dummy function that always returns TRUE */
3647 SCIP_Bool SCIPnlpHasCurrentNodeNLP(
3648 SCIP_NLP* nlp /**< NLP data */
3649 )
3650 {
3651 assert(nlp != NULL);
3652 return TRUE;
3653 } /*lint !e715*/
3654
3655 /** ensures, that variables array of NLP can store at least num entries */
3656 SCIP_RETCODE SCIPnlpEnsureVarsSize(
3657 SCIP_NLP* nlp, /**< NLP data */
3658 BMS_BLKMEM* blkmem, /**< block memory */
3659 SCIP_SET* set, /**< global SCIP settings */
3660 int num /**< minimum number of entries to store */
3661 )
3662 {
3663 assert(nlp != NULL);
3664 assert(blkmem != NULL);
3665 assert(set != NULL);
3666 assert(nlp->nvars <= nlp->sizevars);
3667
3668 if( num > nlp->sizevars )
3669 {
3670 int newsize;
3671
3672 newsize = SCIPsetCalcMemGrowSize(set, num);
3673 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->vars, nlp->sizevars, newsize) );
3674 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlp2nlpi, nlp->sizevars, newsize) );
3675 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varlbdualvals, nlp->sizevars, newsize) );
3676 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varubdualvals, nlp->sizevars, newsize) );
3677 if( nlp->initialguess != NULL )
3678 {
3679 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars, newsize) );
3680 }
3681
3682 nlp->sizevars = newsize;
3683 }
3684 assert(num <= nlp->sizevars);
3685
3686 return SCIP_OKAY;
3687 }
3688
3689 /** adds a variable to the NLP and captures the variable */
3690 SCIP_RETCODE SCIPnlpAddVar(
3691 SCIP_NLP* nlp, /**< NLP data */
3692 BMS_BLKMEM* blkmem, /**< block memory */
3693 SCIP_SET* set, /**< global SCIP settings */
3694 SCIP_VAR* var /**< variable */
3695 )
3696 {
3697 assert(nlp != NULL);
3698 assert(blkmem != NULL);
3699 assert(set != NULL);
3700 assert(var != NULL);
3701 assert(SCIPvarIsTransformed(var));
3702 assert(!SCIPhashmapExists(nlp->varhash, var));
3703
3704 if( nlp->indiving )
3705 {
3706 SCIPerrorMessage("cannot add variable during NLP diving\n");
3707 return SCIP_ERROR;
3708 }
3709
3710 SCIP_CALL( nlpAddVars(nlp, blkmem, set, 1, &var) );
3711
3712 return SCIP_OKAY;
3713 }
3714
3715 /** adds a set of variables to the NLP and captures the variables */
3716 SCIP_RETCODE SCIPnlpAddVars(
3717 SCIP_NLP* nlp, /**< NLP data */
3718 BMS_BLKMEM* blkmem, /**< block memory */
3719 SCIP_SET* set, /**< global SCIP settings */
3720 int nvars, /**< number of variables to add */
3721 SCIP_VAR** vars /**< variables to add */
3722 )
3723 {
3724 assert(nlp != NULL);
3725 assert(blkmem != NULL);
3726 assert(set != NULL);
3727 assert(vars != NULL || nvars == 0);
3728
3729 if( nlp->indiving && nvars > 0)
3730 {
3731 SCIPerrorMessage("cannot add variables during NLP diving\n");
3732 return SCIP_ERROR;
3733 }
3734
3735 SCIP_CALL( nlpAddVars(nlp, blkmem, set, nvars, vars) );
3736
3737 return SCIP_OKAY;
3738 }
3739
3740 /** deletes a variable from the NLP and releases the variable */
3741 SCIP_RETCODE SCIPnlpDelVar(
3742 SCIP_NLP* nlp, /**< NLP data */
3743 BMS_BLKMEM* blkmem, /**< block memory */
3744 SCIP_SET* set, /**< global SCIP settings */
3745 SCIP_STAT* stat, /**< problem statistics data */
3746 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3747 SCIP_LP* lp, /**< SCIP LP, needed to release variable */
3748 SCIP_VAR* var /**< variable */
3749 )
3750 {
3751 int varpos;
3752
3753 assert(nlp != NULL);
3754 assert(blkmem != NULL);
3755 assert(set != NULL);
3756 assert(var != NULL);
3757
3758 if( !SCIPhashmapExists(nlp->varhash, var) )
3759 {
3760 SCIPerrorMessage("variable <%s> not found in NLP, cannot delete\n", SCIPvarGetName(var));
3761 return SCIP_ERROR;
3762 }
3763
3764 if( nlp->indiving )
3765 {
3766 SCIPerrorMessage("cannot delete variable during NLP diving\n");
3767 return SCIP_ERROR;
3768 }
3769
3770 varpos = SCIPhashmapGetImageInt(nlp->varhash, var);
3771
3772 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, varpos) );
3773
3774 return SCIP_OKAY;
3775 }
3776
3777 /** ensures, that nonlinear rows array of NLP can store at least num entries */
3778 SCIP_RETCODE SCIPnlpEnsureNlRowsSize(
3779 SCIP_NLP* nlp, /**< NLP data */
3780 BMS_BLKMEM* blkmem, /**< block memory */
3781 SCIP_SET* set, /**< global SCIP settings */
3782 int num /**< minimum number of entries to store */
3783 )
3784 {
3785 assert(nlp != NULL);
3786 assert(blkmem != NULL);
3787 assert(set != NULL);
3788 assert(nlp->nnlrows <= nlp->sizenlrows);
3789
3790 if( num > nlp->sizenlrows )
3791 {
3792 int newsize;
3793
3794 newsize = SCIPsetCalcMemGrowSize(set, num);
3795 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrows, nlp->sizenlrows, newsize) );
3796
3797 nlp->sizenlrows = newsize;
3798 }
3799 assert(num <= nlp->sizenlrows);
3800
3801 return SCIP_OKAY;
3802 }
3803
3804 /** adds a nonlinear row to the NLP and captures it
3805 *
3806 * all variables of the row need to be present in the NLP
3807 */
3808 SCIP_RETCODE SCIPnlpAddNlRow(
3809 SCIP_NLP* nlp, /**< NLP data */
3810 BMS_BLKMEM* blkmem, /**< block memory */
3811 SCIP_SET* set, /**< global SCIP settings */
3812 SCIP_STAT* stat, /**< problem statistics data */
3813 SCIP_NLROW* nlrow /**< nonlinear row */
3814 )
3815 {
3816 assert(nlp != NULL);
3817 assert(nlrow != NULL);
3818
3819 if( nlp->indiving )
3820 {
3821 SCIPerrorMessage("cannot add row during NLP diving\n");
3822 return SCIP_ERROR;
3823 }
3824
3825 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, 1, &nlrow) );
3826
3827 return SCIP_OKAY;
3828 }
3829
3830 /** adds nonlinear rows to the NLP and captures them
3831 *
3832 * all variables of the row need to be present in the NLP
3833 */
3834 SCIP_RETCODE SCIPnlpAddNlRows(
3835 SCIP_NLP* nlp, /**< NLP data */
3836 BMS_BLKMEM* blkmem, /**< block memory */
3837 SCIP_SET* set, /**< global SCIP settings */
3838 SCIP_STAT* stat, /**< problem statistics data */
3839 int nnlrows, /**< number of rows to add */
3840 SCIP_NLROW** nlrows /**< rows to add */
3841 )
3842 {
3843 assert(nlp != NULL);
3844 assert(nlrows != NULL || nnlrows == 0);
3845
3846 if( nnlrows == 0 )
3847 return SCIP_OKAY;
3848
3849 if( nlp->indiving )
3850 {
3851 SCIPerrorMessage("cannot add rows during NLP diving\n");
3852 return SCIP_ERROR;
3853 }
3854
3855 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, nnlrows, nlrows) );
3856
3857 return SCIP_OKAY;
3858 }
3859
3860 /** deletes a nonlinear row from the NLP
3861 *
3862 * does nothing if nonlinear row is not in NLP
3863 */
3864 SCIP_RETCODE SCIPnlpDelNlRow(
3865 SCIP_NLP* nlp, /**< NLP data */
3866 BMS_BLKMEM* blkmem, /**< block memory */
3867 SCIP_SET* set, /**< global SCIP settings */
3868 SCIP_STAT* stat, /**< problem statistics data */
3869 SCIP_NLROW* nlrow /**< nonlinear row */
3870 )
3871 {
3872 assert(nlp != NULL);
3873 assert(blkmem != NULL);
3874 assert(set != NULL);
3875 assert(nlrow != NULL);
3876
3877 /* if row not in NLP, nothing to do */
3878 if( nlrow->nlpindex == -1 )
3879 return SCIP_OKAY;
3880
3881 assert(nlrow->nlpindex >= 0);
3882 assert(nlrow->nlpindex < nlp->nnlrows);
3883
3884 if( nlp->indiving )
3885 {
3886 SCIPerrorMessage("cannot delete row during NLP diving\n");
3887 return SCIP_ERROR;
3888 }
3889
3890 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, nlrow->nlpindex) );
3891
3892 return SCIP_OKAY;
3893 }
3894
3895 /** applies all cached changes to the NLP solver */
3896 SCIP_RETCODE SCIPnlpFlush(
3897 SCIP_NLP* nlp, /**< current NLP data */
3898 BMS_BLKMEM* blkmem, /**< block memory */
3899 SCIP_SET* set, /**< global SCIP settings */
3900 SCIP_STAT* stat /**< problem statistics */
3901 )
3902 {
3903 assert(nlp != NULL);
3904 assert(blkmem != NULL);
3905 assert(set != NULL);
3906
3907 if( nlp->indiving )
3908 {
3909 SCIPerrorMessage("cannot flush NLP during NLP diving\n");
3910 return SCIP_ERROR;
3911 }
3912
3913 /* flush removals of nonlinear rows and variables */
3914 SCIP_CALL( nlpFlushNlRowDeletions(nlp, blkmem, set) );
3915 SCIP_CALL( nlpFlushVarDeletions(nlp, blkmem, set) );
3916 assert(nlp->nunflushednlrowdel == 0);
3917 assert(nlp->nunflushedvardel == 0);
3918
3919 /* flush addition of variables, objective, and addition of rows */
3920 SCIP_CALL( nlpFlushVarAdditions(nlp, blkmem, set) );
3921 SCIP_CALL( nlpFlushObjective(nlp, blkmem, set) );
3922 SCIP_CALL( nlpFlushNlRowAdditions(nlp, blkmem, set, stat) );
3923 assert(nlp->nunflushedvaradd == 0);
3924 assert(nlp->objflushed == TRUE);
3925 assert(nlp->nunflushednlrowadd == 0);
3926
3927 assert(nlp->nvars == nlp->nvars_solver);
3928 assert(nlp->nnlrows == nlp->nnlrows_solver);
3929
3930 return SCIP_OKAY;
3931 }
3932
3933 /** solves the NLP or diving NLP */
3934 SCIP_RETCODE SCIPnlpSolve(
3935 SCIP_NLP* nlp, /**< NLP data */
3936 BMS_BLKMEM* blkmem, /**< block memory buffers */
3937 SCIP_SET* set, /**< global SCIP settings */
3938 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3939 SCIP_STAT* stat, /**< problem statistics */
3940 SCIP_PRIMAL* primal, /**< primal data */
3941 SCIP_TREE* tree, /**< branch and bound tree */
3942 SCIP_NLPPARAM* nlpparam /**< NLP solve parameters */
3943 )
3944 {
3945 assert(nlp != NULL);
3946 assert(blkmem != NULL);
3947 assert(set != NULL);
3948 assert(stat != NULL);
3949
3950 if( !nlp->indiving )
3951 {
3952 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3953 }
3954
3955 SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat, primal, tree, nlpparam) );
3956
3957 return SCIP_OKAY;
3958 }
3959
3960 /** gets objective value of current NLP */
3961 SCIP_Real SCIPnlpGetObjval(
3962 SCIP_NLP* nlp /**< current NLP data */
3963 )
3964 {
3965 assert(nlp != NULL);
3966
3967 return nlp->primalsolobjval;
3968 }
3969
3970 /** gives current pseudo objective value */
3971 SCIP_RETCODE SCIPnlpGetPseudoObjval(
3972 SCIP_NLP* nlp, /**< current NLP data */
3973 BMS_BLKMEM* blkmem, /**< block memory */
3974 SCIP_SET* set, /**< global SCIP settings */
3975 SCIP_STAT* stat, /**< problem statistics data */
3976 SCIP_PROB* prob, /**< SCIP problem */
3977 SCIP_PRIMAL* primal, /**< primal data */
3978 SCIP_TREE* tree, /**< branch and bound tree */
3979 SCIP_LP* lp, /**< SCIP LP */
3980 SCIP_Real* pseudoobjval /**< buffer to store pseudo objective value */
3981 )
3982 {
3983 assert(nlp != NULL);
3984 assert(pseudoobjval != NULL);
3985
3986 if( nlp->divingobj != NULL )
3987 {
3988 assert(nlp->indiving);
3989 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlp->divingobj, blkmem, set, stat, prob, primal, tree, lp, pseudoobjval) );
3990 }
3991 else
3992 {
3993 int i;
3994
3995 *pseudoobjval = 0.0;
3996 for( i = 0; i < nlp->nvars; ++i )
3997 *pseudoobjval += SCIPvarGetObj(nlp->vars[i]) * SCIPvarGetBestBoundLocal(nlp->vars[i]);
3998 }
3999
4000 return SCIP_OKAY;
4001 }
4002
4003 /** gets fractional variables of last NLP solution along with solution values and fractionalities
4004 */
4005 SCIP_RETCODE SCIPnlpGetFracVars(
4006 SCIP_NLP* nlp, /**< NLP data structure */
4007 BMS_BLKMEM* blkmem, /**< block memory */
4008 SCIP_SET* set, /**< global SCIP settings */
4009 SCIP_STAT* stat, /**< problem statistics */
4010 SCIP_VAR*** fracvars, /**< pointer to store the array of NLP fractional variables, or NULL */
4011 SCIP_Real** fracvarssol, /**< pointer to store the array of NLP fractional variables solution values, or NULL */
4012 SCIP_Real** fracvarsfrac, /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
4013 int* nfracvars, /**< pointer to store the number of NLP fractional variables , or NULL */
4014 int* npriofracvars /**< pointer to store the number of NLP fractional variables with maximal branching priority, or NULL */
4015 )
4016 {
4017 assert(nlp != NULL);
4018
4019 SCIP_CALL( nlpCalcFracVars(nlp, blkmem, set, stat) );
4020 assert(nlp->fracvars != NULL);
4021 assert(nlp->fracvarssol != NULL);
4022 assert(nlp->fracvarsfrac != NULL);
4023
4024 if( fracvars != NULL )
4025 *fracvars = nlp->fracvars;
4026 if( fracvarssol != NULL )
4027 *fracvarssol = nlp->fracvarssol;
4028 if( fracvarsfrac != NULL )
4029 *fracvarsfrac = nlp->fracvarsfrac;
4030 if( nfracvars != NULL )
4031 *nfracvars = nlp->nfracvars;
4032 if( npriofracvars != NULL )
4033 *npriofracvars = nlp->npriofracvars;
4034
4035 return SCIP_OKAY;
4036 }
4037
4038 /** removes all redundant nonlinear rows */
4039 SCIP_RETCODE SCIPnlpRemoveRedundantNlRows(
4040 SCIP_NLP* nlp, /**< current NLP data */
4041 BMS_BLKMEM* blkmem, /**< block memory buffers */
4042 SCIP_SET* set, /**< global SCIP settings */
4043 SCIP_STAT* stat /**< problem statistics */
4044 )
4045 {
4046 SCIP_NLPSOLSTAT solstatus;
4047 SCIP_Bool isredundant;
4048 int i;
4049
4050 assert(nlp != NULL);
4051 assert(blkmem != NULL);
4052 assert(set != NULL);
4053 assert(stat != NULL);
4054
4055 if( nlp->nnlrows == 0 )
4056 return SCIP_OKAY;
4057
4058 if( nlp->indiving )
4059 {
4060 SCIPerrorMessage("cannot remove redundant rows during NLP diving\n");
4061 return SCIP_ERROR;
4062 }
4063
4064 /* removing redundant rows should not change the solution status, so we reset it at the end */
4065 solstatus = nlp->solstat;
4066
4067 for( i = 0; i < nlp->nnlrows; ++i )
4068 {
4069 SCIP_CALL( SCIPnlrowIsRedundant(nlp->nlrows[i], blkmem, set, stat, &isredundant) );
4070 if( isredundant )
4071 {
4072 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
4073 }
4074 }
4075
4076 nlp->solstat = solstatus;
4077
4078 return SCIP_OKAY;
4079 }
4080
4081 /** set initial guess (approximate primal solution) for next solve
4082 *
4083 * array initguess must be NULL or have length at least SCIPnlpGetNVars()
4084 */
4085 SCIP_RETCODE SCIPnlpSetInitialGuess(
4086 SCIP_SET* set, /**< global SCIP settings */
4087 SCIP_NLP* nlp, /**< current NLP data */
4088 BMS_BLKMEM* blkmem, /**< block memory buffers */
4089 SCIP_Real* initguess /**< new initial guess, or NULL to clear previous one */
4090 )
4091 {
4092 assert(nlp != NULL);
4093 assert(blkmem != NULL);
4094 assert(nlp->solver != NULL);
4095 assert(nlp->problem != NULL);
4096
4097 /* if user wants to let NLP solver choose start point, then invalidate current initial guess both in NLP and in NLPI */
4098 if( initguess == NULL )
4099 {
4100 nlp->haveinitguess = FALSE;
4101 SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, NULL, NULL, NULL, NULL) );
4102 return SCIP_OKAY;
4103 }
4104
4105 if( nlp->initialguess != NULL )
4106 {
4107 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4108 }
4109 else
4110 {
4111 assert( nlp->sizevars >= nlp->nvars );
4112 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars) );
4113 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4114 }
4115 nlp->haveinitguess = TRUE;
4116
4117 return SCIP_OKAY;
4118 }
4119
4120 /** writes NLP to a file */
4121 SCIP_RETCODE SCIPnlpWrite(
4122 SCIP_NLP* nlp, /**< current NLP data */
4123 BMS_BLKMEM* blkmem, /**< block memory buffers */
4124 SCIP_SET* set, /**< global SCIP settings */
4125 SCIP_STAT* stat, /**< problem statistics */
4126 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4127 const char* fname /**< file name */
4128 )
4129 {
4130 FILE* file;
4131 int i;
4132
4133 assert(nlp != NULL);
4134
|
(1) Event cond_true: |
Condition "fname != NULL", taking true branch. |
4135 if( fname != NULL )
4136 {
4137 file = fopen(fname, "w");
|
(4) Event cond_false: |
Condition "file == NULL", taking false branch. |
4138 if( file == NULL )
4139 {
4140 SCIPerrorMessage("could not open file <%s> for writing\n", fname);
4141 return SCIP_FILECREATEERROR;
|
(5) Event if_end: |
End of if statement. |
4142 }
|
(6) Event if_fallthrough: |
Falling through to end of if statement. |
4143 }
4144 else
|
(7) Event if_end: |
End of if statement. |
4145 file = stdout;
4146
4147 SCIPmessageFPrintInfo(messagehdlr, file, "STATISTICS\n");
4148 SCIPmessageFPrintInfo(messagehdlr, file, " NLP name: %s\n", nlp->name);
4149 SCIPmessageFPrintInfo(messagehdlr, file, " Variables: %d\n", nlp->nvars);
4150 SCIPmessageFPrintInfo(messagehdlr, file, " Rows: %d\n", nlp->nnlrows);
4151
4152 SCIPmessageFPrintInfo(messagehdlr, file, "VARIABLES\n");
|
(13) Event cond_false: |
Condition "i < nlp->nvars", taking false branch. |
4153 for( i = 0; i < nlp->nvars; ++i )
4154 {
4155 SCIP_CALL( SCIPvarPrint(nlp->vars[i], set, messagehdlr, file) );
|
(14) Event loop_end: |
Reached end of loop. |
4156 }
4157
4158 SCIPmessageFPrintInfo(messagehdlr, file, "NONLINEAR ROWS\n");
|
(16) Event cond_true: |
Condition "i < nlp->nnlrows", taking true branch. |
4159 for( i = 0; i < nlp->nnlrows; ++i )
4160 {
4161 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] |
4162 SCIP_CALL( SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file) );
4163 }
4164
4165 if( fname != NULL )
4166 {
4167 fclose(file);
4168 }
4169
4170 return SCIP_OKAY;
4171 }
4172
4173 /** gets array with variables of the NLP */
4174 SCIP_VAR** SCIPnlpGetVars(
4175 SCIP_NLP* nlp /**< current NLP data */
4176 )
4177 {
4178 assert(nlp != NULL);
4179
4180 return nlp->vars;
4181 }
4182
4183 /** gets current number of variables in NLP */
4184 int SCIPnlpGetNVars(
4185 SCIP_NLP* nlp /**< current NLP data */
4186 )
4187 {
4188 assert(nlp != NULL);
4189
4190 return nlp->nvars;
4191 }
4192
4193 /** computes for each variables the number of NLP rows in which the variable appears in a nonlinear var */
4194 SCIP_RETCODE SCIPnlpGetVarsNonlinearity(
4195 SCIP_NLP* nlp, /**< current NLP data */
4196 BMS_BLKMEM* blkmem, /**< block memory buffers */
4197 SCIP_SET* set, /**< global SCIP settings */
4198 SCIP_STAT* stat, /**< problem statistics */
4199 int* nlcount /**< an array of length at least SCIPnlpGetNVars() to store nonlinearity counts of variables */
4200 )
4201 {
4202 SCIP_NLROW* nlrow;
4203 SCIP_EXPRITER* it;
4204 SCIP_EXPR* expr;
4205 int varidx;
4206 int c;
4207
4208 assert(nlp != NULL);
4209 assert(nlcount != NULL || nlp->nvars == 0);
4210
4211 BMSclearMemoryArray(nlcount, nlp->nvars);
4212
4213 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4214
4215 for( c = 0; c < nlp->nnlrows; ++c )
4216 {
4217 nlrow = nlp->nlrows[c];
4218 assert(nlrow != NULL);
4219
4220 if( nlrow->expr == NULL )
4221 continue;
4222
4223 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, FALSE) );
4224 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4225 {
4226 if( !SCIPexprIsVar(set, expr) )
4227 continue;
4228
4229 assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
4230
4231 varidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(expr));
4232 assert(varidx < nlp->nvars);
4233 assert(nlcount != NULL);
4234 ++nlcount[varidx];
4235 }
4236 }
4237
4238 SCIPexpriterFree(&it);
4239
4240 return SCIP_OKAY;
4241 }
4242
4243
4244 /** indicates whether there exists a row that contains a continuous variable in a nonlinear term
4245 *
4246 * @note The method may have to touch every row and nonlinear term to compute its result.
4247 */
4248 SCIP_RETCODE SCIPnlpHasContinuousNonlinearity(
4249 SCIP_NLP* nlp, /**< current NLP data */
4250 BMS_BLKMEM* blkmem, /**< block memory buffers */
4251 SCIP_SET* set, /**< global SCIP settings */
4252 SCIP_STAT* stat, /**< problem statistics */
4253 SCIP_Bool* result /**< buffer to store whether continuous variable present in an expression of any row */
4254 )
4255 {
4256 SCIP_NLROW* nlrow;
4257 SCIP_EXPRITER* it;
4258 SCIP_EXPR* expr;
4259 int c;
4260
4261 assert(nlp != NULL);
4262
4263 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4264 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4265
4266 *result = FALSE;
4267 for( c = 0; c < nlp->nnlrows && !*result; ++c )
4268 {
4269 nlrow = nlp->nlrows[c];
4270 assert(nlrow != NULL);
4271
4272 if( nlrow->expr == NULL )
4273 continue;
4274
4275 for( expr = SCIPexpriterRestartDFS(it, nlrow->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4276 {
4277 if( SCIPexprIsVar(set, expr) && SCIPvarGetType(SCIPgetVarExprVar(expr)) == SCIP_VARTYPE_CONTINUOUS )
4278 {
4279 *result = TRUE;
4280 break;
4281 }
4282 }
4283 }
4284
4285 SCIPexpriterFree(&it);
4286
4287 return SCIP_OKAY;
4288 }
4289
4290 /** gives dual solution values associated with lower bounds of NLP variables */
4291 SCIP_Real* SCIPnlpGetVarsLbDualsol(
4292 SCIP_NLP* nlp /**< current NLP data */
4293 )
4294 {
4295 assert(nlp != NULL);
4296
4297 return nlp->varlbdualvals;
4298 }
4299
4300 /** gives dual solution values associated with upper bounds of NLP variables */
4301 SCIP_Real* SCIPnlpGetVarsUbDualsol(
4302 SCIP_NLP* nlp /**< current NLP data */
4303 )
4304 {
4305 assert(nlp != NULL);
4306
4307 return nlp->varubdualvals;
4308 }
4309
4310 /** gets array with nonlinear rows of the NLP */
4311 SCIP_NLROW** SCIPnlpGetNlRows(
4312 SCIP_NLP* nlp /**< current NLP data */
4313 )
4314 {
4315 assert(nlp != NULL);
4316
4317 return nlp->nlrows;
4318 }
4319
4320 /** gets current number of nonlinear rows in NLP */
4321 int SCIPnlpGetNNlRows(
4322 SCIP_NLP* nlp /**< current NLP data */
4323 )
4324 {
4325 assert(nlp != NULL);
4326
4327 return nlp->nnlrows;
4328 }
4329
4330 /** gets the NLP solver interface */
4331 SCIP_NLPI* SCIPnlpGetNLPI(
4332 SCIP_NLP* nlp /**< current NLP data */
4333 )
4334 {
4335 assert(nlp != NULL);
4336
4337 return nlp->solver;
4338 }
4339
4340 /** gets the NLP problem in the solver interface */
4341 SCIP_NLPIPROBLEM* SCIPnlpGetNLPIProblem(
4342 SCIP_NLP* nlp /**< current NLP data */
4343 )
4344 {
4345 assert(nlp != NULL);
4346
4347 return nlp->problem;
4348 }
4349
4350 /** indicates whether NLP is currently in diving mode */
4351 SCIP_Bool SCIPnlpIsDiving(
4352 SCIP_NLP* nlp /**< current NLP data */
4353 )
4354 {
4355 assert(nlp != NULL);
4356
4357 return nlp->indiving;
4358 }
4359
4360 /** gets solution status of current NLP */
4361 SCIP_NLPSOLSTAT SCIPnlpGetSolstat(
4362 SCIP_NLP* nlp /**< current NLP data */
4363 )
4364 {
4365 assert(nlp != NULL);
4366
4367 return nlp->solstat;
4368 }
4369
4370 /** gets termination status of last NLP solve */
4371 SCIP_NLPTERMSTAT SCIPnlpGetTermstat(
4372 SCIP_NLP* nlp /**< current NLP data */
4373 )
4374 {
4375 assert(nlp != NULL);
4376
4377 return nlp->termstat;
4378 }
4379
4380 /** gives statistics (number of iterations, solving time, ...) of last NLP solve */
4381 SCIP_RETCODE SCIPnlpGetStatistics(
4382 SCIP_SET* set, /**< global SCIP settings */
4383 SCIP_NLP* nlp, /**< pointer to NLP datastructure */
4384 SCIP_NLPSTATISTICS* statistics /**< pointer to store statistics */
4385 )
4386 {
4387 assert(nlp != NULL);
4388 assert(nlp->solver != NULL);
4389 assert(nlp->problem != NULL);
4390 assert(statistics != NULL);
4391
4392 SCIP_CALL( SCIPnlpiGetStatistics(set, nlp->solver, nlp->problem, statistics) );
4393
4394 return SCIP_OKAY;
4395 }
4396
4397 /** indicates whether a solution for the current NLP is available
4398 *
4399 * The solution may be optimal, feasible, or infeasible.
4400 * Thus, returns whether the NLP solution status is at most \ref SCIP_NLPSOLSTAT_LOCINFEASIBLE.
4401 */
4402 SCIP_Bool SCIPnlpHasSolution(
4403 SCIP_NLP* nlp /**< current NLP data */
4404 )
4405 {
4406 assert(nlp != NULL);
4407
4408 return nlp->solstat <= SCIP_NLPSOLSTAT_LOCINFEASIBLE;
4409 }
4410
4411 /*
4412 * NLP diving methods
4413 */
4414
4415 /** signals start of diving */
4416 SCIP_RETCODE SCIPnlpStartDive(
4417 SCIP_NLP* nlp, /**< current NLP data */
4418 BMS_BLKMEM* blkmem, /**< block memory buffers */
4419 SCIP_SET* set, /**< global SCIP settings */
4420 SCIP_STAT* stat /**< problem statistics */
4421 )
4422 {
4423 assert(nlp != NULL);
4424
4425 if( nlp->indiving )
4426 {
4427 SCIPerrorMessage("NLP is already in diving mode\n");
4428 return SCIP_ERROR;
4429 }
4430
4431 if( nlp->solver == NULL )
4432 {
4433 /* 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.
4434 * So we forbid diving of no solver is available. */
4435 SCIPerrorMessage("Cannot start diving if no NLP solver is available\n");
4436 return SCIP_ERROR;
4437 }
4438
4439 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
4440
4441 nlp->indiving = TRUE;
4442
4443 return SCIP_OKAY;
4444 }
4445
4446 /** resets the bound and objective changes made during diving and disables diving mode */
4447 SCIP_RETCODE SCIPnlpEndDive(
4448 SCIP_NLP* nlp, /**< current NLP data */
4449 BMS_BLKMEM* blkmem, /**< block memory */
4450 SCIP_SET* set, /**< global SCIP settings */
4451 SCIP_STAT* stat /**< problem statistics data */
4452 )
4453 {
4454 int i;
4455 int* varidx;
4456 SCIP_Real* varlb;
4457 SCIP_Real* varub;
4458
4459 assert(nlp != NULL);
4460 assert(set != NULL);
4461 assert(nlp->nvars == nlp->nvars_solver);
4462
4463 if( !nlp->indiving )
4464 {
4465 SCIPerrorMessage("NLP not in diving mode, cannot end dive\n");
4466 return SCIP_ERROR;
4467 }
4468
4469 assert(nlp->solver != NULL);
4470 assert(nlp->problem != NULL);
4471
4472 /* reset variable bounds in NLPI problem to their current values */
4473 SCIP_CALL( SCIPsetAllocBufferArray(set, &varidx, nlp->nvars) );
4474 SCIP_CALL( SCIPsetAllocBufferArray(set, &varlb, nlp->nvars) );
4475 SCIP_CALL( SCIPsetAllocBufferArray(set, &varub, nlp->nvars) );
4476 for( i = 0; i < nlp->nvars; ++i )
4477 {
4478 varidx[i] = i;
4479 varlb[i] = SCIPvarGetLbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4480 varub[i] = SCIPvarGetUbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4481 }
4482
4483 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nlp->nvars, varidx, varlb, varub) );
4484
4485 SCIPsetFreeBufferArray(set, &varidx);
4486 SCIPsetFreeBufferArray(set, &varlb);
4487 SCIPsetFreeBufferArray(set, &varub);
4488
4489 /* clear diving objective, if one was used (i.e., if SCIPnlpChgVarObjDive had been called)
4490 * the objective in the NLPI will be reset in the next flush */
4491 if( nlp->divingobj != NULL )
4492 {
4493 SCIP_CALL( SCIPnlrowRelease(&nlp->divingobj, blkmem, set, stat) );
4494 assert(nlp->divingobj == NULL);
4495 assert(nlp->objflushed == FALSE);
4496 }
4497
4498 /* we do not have a valid solution anymore */
4499 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
4500 nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
4501 nlp->primalsolobjval = SCIP_INVALID;
4502
4503 nlp->indiving = FALSE;
4504
4505 return SCIP_OKAY;
4506 }
4507
4508 /** changes coefficient of variable in diving NLP */
4509 SCIP_RETCODE SCIPnlpChgVarObjDive(
4510 SCIP_NLP* nlp, /**< current NLP data */
4511 BMS_BLKMEM* blkmem, /**< block memory */
4512 SCIP_SET* set, /**< global SCIP settings */
4513 SCIP_STAT* stat, /**< problem statistics data */
4514 SCIP_VAR* var, /**< variable which coefficient to change */
4515 SCIP_Real coef /**< new linear coefficient of variable in objective */
4516 )
4517 {
4518 int pos;
4519 int objidx;
4520
4521 assert(nlp != NULL);
4522 assert(var != NULL);
4523 assert(SCIPhashmapExists(nlp->varhash, var));
4524 assert(nlp->indiving);
4525 assert(nlp->solver != NULL);
4526 assert(nlp->problem != NULL);
4527
4528 /* get position of variable in NLPI problem */
4529 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4530 pos = nlp->varmap_nlp2nlpi[pos];
4531 assert(pos >= 0);
4532
4533 /* set coefficient in NLPI problem objective */
4534 objidx = -1;
4535 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
4536
4537 /* create an nlrow that holds the diving objective, if not done yet */
4538 if( nlp->divingobj == NULL )
4539 {
4540 SCIP_Real* coefs;
4541 int i;
4542
4543 SCIP_CALL( SCIPsetAllocBufferArray(set, &coefs, nlp->nvars) );
4544 for( i = 0; i < nlp->nvars; ++i )
4545 coefs[i] = SCIPvarGetObj(nlp->vars[i]);
4546
4547 SCIP_CALL( SCIPnlrowCreate(&nlp->divingobj, blkmem, set, stat, "divingobj",
4548 0.0, nlp->nvars, nlp->vars, coefs, NULL,
4549 -SCIPsetInfinity(set), SCIPsetInfinity(set),
4550 SCIP_EXPRCURV_LINEAR) );
4551
4552 SCIPsetFreeBufferArray(set, &coefs);
4553 }
4554 assert(nlp->divingobj != NULL);
4555
4556 /* modify coefficient in diving objective */
4557 SCIP_CALL( SCIPnlrowChgLinearCoef(nlp->divingobj, blkmem, set, stat, nlp, var, coef) );
4558
4559 /* remember that we have to store objective after diving ended */
4560 nlp->objflushed = FALSE;
4561
4562 return SCIP_OKAY;
4563 }
4564
4565 /** changes bounds of variable in diving NLP */
4566 SCIP_RETCODE SCIPnlpChgVarBoundsDive(
4567 SCIP_SET* set, /**< global SCIP settings */
4568 SCIP_NLP* nlp, /**< current NLP data */
4569 SCIP_VAR* var, /**< variable which coefficient to change */
4570 SCIP_Real lb, /**< new lower bound of variable */
4571 SCIP_Real ub /**< new upper bound of variable */
4572 )
4573 {
4574 int pos;
4575
4576 assert(nlp != NULL);
4577 assert(var != NULL);
4578 assert(SCIPhashmapExists(nlp->varhash, var));
4579 assert(nlp->indiving);
4580 assert(nlp->solver != NULL);
4581 assert(nlp->problem != NULL);
4582
4583 /* get position of variable in NLPI problem */
4584 pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4585 pos = nlp->varmap_nlp2nlpi[pos];
4586 assert(pos >= 0);
4587
4588 /* set new bounds in NLPI */
4589 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
4590
4591 return SCIP_OKAY;
4592 }
4593
4594 /** changes bounds of a set of variables in diving NLP */
4595 SCIP_RETCODE SCIPnlpChgVarsBoundsDive(
4596 SCIP_NLP* nlp, /**< current NLP data */
4597 SCIP_SET* set, /**< global SCIP settings */
4598 int nvars, /**< number of variables which bounds to change */
4599 SCIP_VAR** vars, /**< variables which bounds to change */
4600 SCIP_Real* lbs, /**< new lower bounds of variables */
4601 SCIP_Real* ubs /**< new upper bounds of variables */
4602 )
4603 {
4604 int i;
4605 int* poss;
4606
4607 assert(nlp != NULL);
4608 assert(vars != NULL || nvars == 0);
4609 assert(nlp->indiving);
4610 assert(lbs != NULL || nvars == 0);
4611 assert(ubs != NULL || nvars == 0);
4612 assert(nlp->solver != NULL);
4613 assert(nlp->problem != NULL);
4614
4615 if( nvars == 0 )
4616 return SCIP_OKAY;
4617
4618 SCIP_CALL( SCIPsetAllocBufferArray(set, &poss, nvars) );
4619
4620 for( i = 0; i < nvars; ++i )
4621 {
4622 assert(SCIPhashmapExists(nlp->varhash, vars[i])); /*lint !e613*/
4623
4624 /* get position of variable in NLPI problem */
4625 poss[i] = SCIPhashmapGetImageInt(nlp->varhash, vars[i]); /*lint !e613*/
4626 poss[i] = nlp->varmap_nlp2nlpi[poss[i]];
4627 assert(poss[i] >= 0);
4628 }
4629
4630 /* set new bounds in NLPI */
4631 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nvars, poss, lbs, ubs) );
4632
4633 SCIPsetFreeBufferArray(set, &poss);
4634
4635 return SCIP_OKAY;
4636 }
4637
4638 /** returns whether the objective function has been changed during diving */
4639 SCIP_Bool SCIPnlpIsDivingObjChanged(
4640 SCIP_NLP* nlp /**< current NLP data */
4641 )
4642 {
4643 return nlp->divingobj != NULL;
4644 }
4645