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