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