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