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