Scippy

SCIP

Solving Constraint Integer Programs

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