1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SCIP is distributed under the terms of the ZIB Academic License.         */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   nlp.c
17   	 * @ingroup OTHER_CFILES
18   	 * @brief  NLP management methods
19   	 * @author Thorsten Gellermann
20   	 * @author Stefan Vigerske
21   	 *
22   	 *  In NLP management, we have to distinguish between the current NLP and the NLPI problem
23   	 *  stored in the NLP solver. All NLP methods affect the current NLP only.
24   	 *  Before solving the current NLP with the NLP solver, the NLP solvers data
25   	 *  has to be updated to the current NLP with a call to SCIPnlpFlush().
26   	 *
27   	 *  @todo handle linear rows from LP
28   	 */
29   	
30   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
31   	
32   	
33   	#include "scip/nlpi.h"
34   	#include "scip/pub_expr.h"
35   	#include "scip/expr.h"
36   	#include "scip/expr_varidx.h"
37   	#include "scip/clock.h"
38   	#include "scip/event.h"
39   	#include "scip/nlp.h"
40   	#include "scip/primal.h"
41   	#include "scip/pub_event.h"
42   	#include "scip/pub_lp.h"
43   	#include "scip/pub_message.h"
44   	#include "scip/pub_misc.h"
45   	#include "scip/pub_misc_sort.h"
46   	#include "scip/pub_nlp.h"
47   	#include "scip/pub_var.h"
48   	#include "scip/set.h"
49   	#include "scip/sol.h"
50   	#include "scip/struct_nlp.h"
51   	/* to get nlp, set, ... in event handling and mapvar2varidx */
52   	#include "scip/struct_scip.h"
53   	/* to get value of parameter "nlp/solver" and nlpis array and to get access to set->lp for releasing a variable */
54   	#include "scip/struct_set.h"
55   	#include "scip/struct_stat.h"
56   	#include "scip/var.h"
57   	#include <string.h>
58   	
59   	/* defines */
60   	
61   	#define EVENTHDLR_NAME   "nlpEventHdlr"      /**< name of NLP event handler that catches variable events */
62   	#define EVENTHDLR_DESC   "handles all events necessary for maintaining NLP data"  /**< description of NLP event handler */
63   	#define ADDNAMESTONLPI   0                   /**< whether to give variable and row names to NLPI */
64   	
65   	/*lint -e440*/
66   	/*lint -e441*/
67   	/*lint -e777*/
68   	
69   	#ifdef __cplusplus
70   	extern "C" {
71   	#endif
72   	
73   	/* avoid inclusion of scip.h */ /*lint -e{2701}*/
74   	BMS_BLKMEM* SCIPblkmem(
75   	   SCIP*                 scip                /**< SCIP data structure */
76   	   );
77   	
78   	#ifdef __cplusplus
79   	}
80   	#endif
81   	
82   	/*
83   	 * forward declarations
84   	 */
85   	
86   	/** NLP event handler execution method */
87   	static
88   	SCIP_DECL_EVENTEXEC( eventExecNlp );
89   	
90   	/** announces, that a row of the NLP was modified
91   	 *
92   	 * adjusts status of current solution;
93   	 * calling method has to ensure that change is passed on to the NLPI!
94   	 */
95   	static
96   	SCIP_RETCODE nlpRowChanged(
97   	   SCIP_NLP*             nlp,                /**< current NLP data */
98   	   SCIP_SET*             set,                /**< global SCIP settings */
99   	   SCIP_STAT*            stat,               /**< problem statistics data */
100  	   SCIP_NLROW*           nlrow               /**< nonlinear row which was changed */
101  	   );
102  	
103  	/*
104  	 * private NLP nonlinear row methods
105  	 */
106  	
107  	/** announces, that the given linear coefficient in the constraint matrix changed */
108  	static
109  	SCIP_RETCODE nlrowLinearCoefChanged(
110  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
111  	   SCIP_SET*             set,                /**< global SCIP settings */
112  	   SCIP_STAT*            stat,               /**< problem statistics data */
113  	   SCIP_VAR*             var,                /**< variable which coefficient changed */
114  	   SCIP_Real             coef,               /**< new coefficient of variable, 0.0 if deleted */
115  	   SCIP_NLP*             nlp                 /**< current NLP data */
116  	   )
117  	{
118  	   assert(nlrow != NULL);
119  	   assert(var   != NULL);
120  	
121  	   nlrow->activity = SCIP_INVALID;
122  	   nlrow->validactivitynlp = -1;
123  	   nlrow->pseudoactivity = SCIP_INVALID;
124  	   nlrow->validpsactivitydomchg = -1;
125  	   nlrow->minactivity = SCIP_INVALID;
126  	   nlrow->maxactivity = SCIP_INVALID;
127  	   nlrow->validactivitybdsdomchg = -1;
128  	
129  	   if( nlrow->nlpindex >= 0 )
130  	   {
131  	      assert(nlp != NULL);
132  	
133  	      /* notify NLP that row has changed */
134  	      SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
135  	
136  	      /* update NLPI problem, if row is in NLPI already */
137  	      if( nlrow->nlpiindex >= 0 )
138  	      {
139  	         int idx;
140  	
141  	         /* get index of variable in NLPI */
142  	         assert(SCIPhashmapExists(nlp->varhash, var));
143  	         idx = SCIPhashmapGetImageInt(nlp->varhash, var);
144  	         assert(idx >= 0 && idx < nlp->nvars);
145  	
146  	         idx = nlp->varmap_nlp2nlpi[idx];
147  	         assert(idx >= 0 && idx < nlp->nvars_solver);
148  	
149  	         /* change coefficient in NLPI problem */
150  	         SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, nlrow->nlpiindex, 1, &idx, &coef) );
151  	      }
152  	   }
153  	
154  	   return SCIP_OKAY;
155  	}
156  	
157  	/** create varidx expression for var expression
158  	 *
159  	 * called when expr is duplicated for addition to NLPI
160  	 */
161  	static
162  	SCIP_DECL_EXPR_MAPEXPR(mapvar2varidx)
163  	{
164  	   SCIP_NLP* nlp;
165  	   int nlpidx;
166  	
167  	   assert(sourcescip != NULL);
168  	   assert(sourcescip == targetscip);
169  	   assert(sourceexpr != NULL);
170  	   assert(targetexpr != NULL);
171  	   assert(*targetexpr == NULL);
172  	   assert(mapexprdata != NULL);
173  	
174  	   nlp = (SCIP_NLP*)mapexprdata;
175  	
176  	   /* do not provide map if not variable */
177  	   if( !SCIPexprIsVar(sourcescip->set, sourceexpr) )
178  	      return SCIP_OKAY;
179  	
180  	   assert(SCIPvarIsActive(SCIPgetVarExprVar(sourceexpr)));  /* because we simplified exprs */
181  	
182  	   assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(sourceexpr)));
183  	   nlpidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(sourceexpr));
184  	   assert(nlpidx < nlp->nvars);
185  	
186  	   assert(nlp->varmap_nlp2nlpi[nlpidx] >= 0);
187  	   assert(nlp->varmap_nlp2nlpi[nlpidx] < nlp->nvars_solver);
188  	   SCIP_CALL( SCIPcreateExprVaridx(targetscip, targetexpr, nlp->varmap_nlp2nlpi[nlpidx], ownercreate, ownercreatedata) );
189  	
190  	   return SCIP_OKAY;
191  	}
192  	
193  	/** announces, that an expression changed */
194  	static
195  	SCIP_RETCODE nlrowExprChanged(
196  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
197  	   BMS_BLKMEM*           blkmem,             /**< block memory */
198  	   SCIP_SET*             set,                /**< global SCIP settings */
199  	   SCIP_STAT*            stat,               /**< problem statistics data */
200  	   SCIP_NLP*             nlp                 /**< current NLP data */
201  	   )
202  	{
203  	   assert(nlrow != NULL);
204  	
205  	   nlrow->activity = SCIP_INVALID;
206  	   nlrow->validactivitynlp = -1;
207  	   nlrow->pseudoactivity = SCIP_INVALID;
208  	   nlrow->validpsactivitydomchg = -1;
209  	   nlrow->minactivity = SCIP_INVALID;
210  	   nlrow->maxactivity = SCIP_INVALID;
211  	   nlrow->validactivitybdsdomchg = -1;
212  	
213  	   if( nlrow->nlpindex >= 0 )
214  	   {
215  	      assert(nlp != NULL);
216  	
217  	      /* notify NLP that row has changed */
218  	      SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
219  	
220  	      if( nlrow->nlpiindex >= 0 )
221  	      {
222  	         /* change expression tree in NLPI problem */
223  	         SCIP_EXPR* nlpiexpr;
224  	
225  	         SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &nlpiexpr, mapvar2varidx, (void*)nlp, NULL, NULL) );
226  	         SCIP_CALL( SCIPnlpiChgExpr(set, nlp->solver, nlp->problem, nlrow->nlpiindex, nlpiexpr) );
227  	         SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlpiexpr) );
228  	      }
229  	   }
230  	
231  	   return SCIP_OKAY;
232  	}
233  	
234  	/** notifies nonlinear row, that its sides were changed */
235  	static
236  	SCIP_RETCODE nlrowSideChanged(
237  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
238  	   SCIP_SET*             set,                /**< global SCIP settings */
239  	   SCIP_STAT*            stat,               /**< problem statistics data */
240  	   SCIP_NLP*             nlp                 /**< current NLP data */
241  	   )
242  	{
243  	   assert(nlrow != NULL);
244  	
245  	   if( nlrow->nlpindex >= 0 )
246  	   {
247  	      assert(nlp != NULL);
248  	
249  	      /* notify NLP that row has changed */
250  	      SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
251  	
252  	      if( nlrow->nlpiindex >= 0 )
253  	      {
254  	         SCIP_Real lhs;
255  	         SCIP_Real rhs;
256  	
257  	         /* change sides in NLPI problem */
258  	         lhs = nlrow->lhs;
259  	         rhs = nlrow->rhs;
260  	         if( !SCIPsetIsInfinity(set, -lhs) )
261  	            lhs -= nlrow->constant;
262  	         if( !SCIPsetIsInfinity(set,  rhs) )
263  	            rhs -= nlrow->constant;
264  	
265  	         SCIP_CALL( SCIPnlpiChgConsSides(set, nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) );
266  	      }
267  	   }
268  	
269  	   return SCIP_OKAY;
270  	}
271  	
272  	/** notifies nonlinear row, that its constant was changed */
273  	static
274  	SCIP_RETCODE nlrowConstantChanged(
275  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
276  	   SCIP_SET*             set,                /**< global SCIP settings */
277  	   SCIP_STAT*            stat,               /**< problem statistics data */
278  	   SCIP_NLP*             nlp                 /**< current NLP data */
279  	   )
280  	{
281  	   assert(nlrow != NULL);
282  	
283  	   nlrow->activity = SCIP_INVALID;
284  	   nlrow->validactivitynlp = -1;
285  	   nlrow->pseudoactivity = SCIP_INVALID;
286  	   nlrow->validpsactivitydomchg = -1;
287  	   nlrow->minactivity = SCIP_INVALID;
288  	   nlrow->maxactivity = SCIP_INVALID;
289  	   nlrow->validactivitybdsdomchg = -1;
290  	
291  	   if( nlrow->nlpindex >= 0 )
292  	   {
293  	      assert(nlp != NULL);
294  	
295  	      /* notify NLP that row has changed */
296  	      SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) );
297  	
298  	      if( nlrow->nlpiindex >= 0 )
299  	      {
300  	         SCIP_Real lhs;
301  	         SCIP_Real rhs;
302  	
303  	         lhs = nlrow->lhs;
304  	         rhs = nlrow->rhs;
305  	         if( !SCIPsetIsInfinity(set, -lhs) )
306  	            lhs -= nlrow->constant;
307  	         if( !SCIPsetIsInfinity(set,  rhs) )
308  	            rhs -= nlrow->constant;
309  	
310  	         /* change sides in NLPI problem */
311  	         SCIP_CALL( SCIPnlpiChgConsSides(set, nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) );
312  	      }
313  	   }
314  	
315  	   return SCIP_OKAY;
316  	}
317  	
318  	/** sorts linear part of row entries such that lower variable indices precede higher ones */
319  	static
320  	void nlrowSortLinear(
321  	   SCIP_NLROW*           nlrow               /**< nonlinear row to be sorted */
322  	   )
323  	{
324  	   assert(nlrow != NULL);
325  	
326  	   /* check, if row is already sorted in the LP part, or if the sorting should be delayed */
327  	   if( nlrow->linvarssorted )
328  	      return;
329  	
330  	   /* sort linear coefficients */
331  	   SCIPsortPtrReal((void**)nlrow->linvars, nlrow->lincoefs, SCIPvarComp, nlrow->nlinvars);
332  	
333  	   nlrow->linvarssorted = TRUE;
334  	}
335  	
336  	/** searches linear variable in nonlinear row, returns position in linvars vector or -1 if not found */
337  	static
338  	int nlrowSearchLinearCoef(
339  	   SCIP_NLROW*           nlrow,              /**< nonlinear row to be searched in */
340  	   SCIP_VAR*             var                 /**< variable to be searched for */
341  	   )
342  	{
343  	   int pos;
344  	
345  	   assert(nlrow != NULL);
346  	   assert(var   != NULL);
347  	
348  	   if( nlrow->nlinvars == 0 )
349  	      return -1;
350  	
351  	   nlrowSortLinear(nlrow);
352  	   if( !SCIPsortedvecFindPtr((void**)nlrow->linvars, SCIPvarComp, (void*)var, nlrow->nlinvars, &pos) )
353  	      return -1;
354  	
355  	   return pos;
356  	}
357  	
358  	/** moves a coefficient in a nonlinear row to a different place, and updates all corresponding data structures */
359  	static
360  	void nlrowMoveLinearCoef(
361  	   SCIP_NLROW*           nlrow,              /**< NLP row */
362  	   int                   oldpos,             /**< old position of coefficient */
363  	   int                   newpos              /**< new position of coefficient */
364  	   )
365  	{
366  	   assert(nlrow != NULL);
367  	   assert(0 <= oldpos && oldpos < nlrow->nlinvars);
368  	   assert(0 <= newpos && newpos < nlrow->nlinvars);
369  	   assert(nlrow->linvars[oldpos] != NULL);
370  	
371  	   if( oldpos == newpos )
372  	      return;
373  	
374  	   nlrow->linvars[newpos]  = nlrow->linvars[oldpos];
375  	   nlrow->lincoefs[newpos] = nlrow->lincoefs[oldpos];
376  	
377  	   /* update sorted flags */
378  	   nlrow->linvarssorted = FALSE;
379  	}
380  	
381  	/** adds a previously non existing linear coefficient to a nonlinear row */
382  	static
383  	SCIP_RETCODE nlrowAddLinearCoef(
384  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
385  	   BMS_BLKMEM*           blkmem,             /**< block memory */
386  	   SCIP_SET*             set,                /**< global SCIP settings */
387  	   SCIP_STAT*            stat,               /**< problem statistics data */
388  	   SCIP_NLP*             nlp,                /**< current NLP data */
389  	   SCIP_VAR*             var,                /**< variable */
390  	   SCIP_Real             coef                /**< value of coefficient */
391  	   )
392  	{
393  	   int pos;
394  	
395  	   assert(nlrow  != NULL);
396  	   assert(blkmem != NULL);
397  	   assert(var    != NULL);
398  	   assert(coef   != 0.0);
399  	
400  	   /* assert that only active variables are added once the row is in the NLP */
401  	   assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
402  	
403  	   SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars+1) );
404  	   assert(nlrow->linvars  != NULL);
405  	   assert(nlrow->lincoefs != NULL);
406  	
407  	   pos = nlrow->nlinvars;
408  	   nlrow->nlinvars++;
409  	
410  	   /* insert the variable */
411  	   nlrow->linvars [pos] = var;
412  	   nlrow->lincoefs[pos] = coef;
413  	
414  	   SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, coef, nlp) );
415  	
416  	   /* update sorted flag */
417  	   if( pos > 0 && SCIPvarCompare(nlrow->linvars[pos-1], nlrow->linvars[pos]) > 0 )
418  	      nlrow->linvarssorted = FALSE;
419  	
420  	   SCIPsetDebugMsg(set, "added linear coefficient %g * <%s> at position %d to nonlinear row <%s>\n",
421  	      coef, SCIPvarGetName(var), pos, nlrow->name);
422  	
423  	   return SCIP_OKAY;
424  	}
425  	
426  	#ifdef SCIP_DISABLED_CODE
427  	/** adds a linear coefficient to a nonlinear row
428  	 * if the variable exists in the linear part of the row already, the coefficients are added
429  	 * otherwise the variable is added to the row */
430  	static
431  	SCIP_RETCODE nlrowAddToLinearCoef(
432  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
433  	   BMS_BLKMEM*           blkmem,             /**< block memory */
434  	   SCIP_SET*             set,                /**< global SCIP settings */
435  	   SCIP_STAT*            stat,               /**< problem statistics data */
436  	   SCIP_NLP*             nlp,                /**< current NLP data */
437  	   SCIP_VAR*             var,                /**< variable */
438  	   SCIP_Real             coef,               /**< value of coefficient */
439  	   SCIP_Bool             removefixed         /**< whether to disaggregate var before adding */
440  	   )
441  	{
442  	   int pos;
443  	
444  	   assert(nlrow  != NULL);
445  	   assert(blkmem != NULL);
446  	   assert(var    != NULL);
447  	
448  	   if( removefixed && !SCIPvarIsActive(var) )
449  	   {
450  	      SCIP_Real constant;
451  	
452  	      constant = 0.0;
453  	      SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &coef, &constant) );
454  	      if( constant != 0.0 )
455  	      {
456  	         nlrow->constant += constant;
457  	         SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
458  	      }
459  	
460  	      if( SCIPsetIsZero(set, coef) )
461  	         return SCIP_OKAY;
462  	
463  	      if( !SCIPvarIsActive(var) )
464  	      {
465  	         int j;
466  	
467  	         /* if var is still not active, then it is multi-aggregated */
468  	         assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
469  	
470  	         if( SCIPvarGetMultaggrConstant(var) != 0.0 )
471  	         {
472  	            nlrow->constant += coef * SCIPvarGetMultaggrConstant(var);
473  	            SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
474  	         }
475  	
476  	         for( j = 0; j < SCIPvarGetMultaggrNVars(var); ++j )
477  	         {
478  	            SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[j], SCIPvarGetMultaggrScalars(var)[j] * coef, TRUE) );
479  	         }
480  	
481  	         return SCIP_OKAY;
482  	      }
483  	   }
484  	   else if( SCIPsetIsZero(set, coef) )
485  	      return SCIP_OKAY;
486  	
487  	   assert(!removefixed || SCIPvarIsActive(var));
488  	
489  	   pos = nlrowSearchLinearCoef(nlrow, var);
490  	
491  	   if( pos == -1 )
492  	   {
493  	      /* add as new coefficient */
494  	      SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) );
495  	   }
496  	   else
497  	   {
498  	      assert(pos >= 0);
499  	      assert(pos <  nlrow->nlinvars);
500  	      assert(nlrow->linvars[pos] == var);
501  	
502  	      /* add to previously existing coefficient */
503  	      nlrow->lincoefs[pos] += coef;
504  	   }
505  	
506  	   return SCIP_OKAY;
507  	}
508  	#endif
509  	
510  	/** deletes coefficient at given position from row */
511  	static
512  	SCIP_RETCODE nlrowDelLinearCoefPos(
513  	   SCIP_NLROW*           nlrow,              /**< nonlinear row to be changed */
514  	   SCIP_SET*             set,                /**< global SCIP settings */
515  	   SCIP_STAT*            stat,               /**< problem statistics data */
516  	   SCIP_NLP*             nlp,                /**< current NLP data */
517  	   int                   pos                 /**< position in row vector to delete */
518  	   )
519  	{
520  	   SCIP_VAR* var;
521  	
522  	   assert(nlrow != NULL);
523  	   assert(set != NULL);
524  	   assert(0 <= pos && pos < nlrow->nlinvars);
525  	   assert(nlrow->linvars[pos] != NULL);
526  	
527  	   var = nlrow->linvars[pos];
528  	
529  	   /* move last coefficient to position of empty slot (should set sorted flag to FALSE, if not last variable was deleted) */
530  	   nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos);
531  	   nlrow->nlinvars--;
532  	   assert(pos == nlrow->nlinvars || nlrow->linvarssorted == FALSE);
533  	
534  	   SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) );
535  	
536  	   return SCIP_OKAY;
537  	}
538  	
539  	/** changes a coefficient at given position of a nonlinear row */
540  	static
541  	SCIP_RETCODE nlrowChgLinearCoefPos(
542  	   SCIP_NLROW*           nlrow,              /**< NLP row */
543  	   SCIP_SET*             set,                /**< global SCIP settings */
544  	   SCIP_STAT*            stat,               /**< problem statistics data */
545  	   SCIP_NLP*             nlp,                /**< current NLP data */
546  	   int                   pos,                /**< position in row vector to change */
547  	   SCIP_Real             coef                /**< new value of coefficient */
548  	   )
549  	{
550  	   assert(nlrow != NULL);
551  	   assert(0 <= pos && pos < nlrow->nlinvars);
552  	   assert(nlrow->linvars != NULL);
553  	   assert(nlrow->linvars[pos] != NULL);
554  	
555  	   if( SCIPsetIsZero(set, coef) )
556  	   {
557  	      /* delete existing coefficient */
558  	      SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
559  	   }
560  	   else if( !SCIPsetIsEQ(set, nlrow->lincoefs[pos], coef) )
561  	   {
562  	      /* change existing coefficient */
563  	      nlrow->lincoefs[pos] = coef;
564  	      SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], coef, nlp) );
565  	   }
566  	
567  	   return SCIP_OKAY;
568  	}
569  	
570  	/** calculates minimal and maximal activity of row w.r.t. the variable's bounds */
571  	static
572  	SCIP_RETCODE nlrowCalcActivityBounds(
573  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
574  	   BMS_BLKMEM*           blkmem,             /**< block memory */
575  	   SCIP_SET*             set,                /**< global SCIP settings */
576  	   SCIP_STAT*            stat                /**< problem statistics data */
577  	   )
578  	{
579  	   SCIP_Real inf;
580  	   SCIP_INTERVAL activity;
581  	   SCIP_INTERVAL bounds;
582  	   int i;
583  	
584  	   assert(nlrow != NULL);
585  	   assert(set   != NULL);
586  	   assert(stat  != NULL);
587  	
588  	   inf = SCIPsetInfinity(set);
589  	
590  	   /* calculate activity bounds */
591  	   SCIPintervalSet(&activity, nlrow->constant);
592  	   for( i = 0; i < nlrow->nlinvars && !SCIPintervalIsEntire(inf, activity); ++i )
593  	   {
594  	      SCIPintervalSetBounds(&bounds, SCIPvarGetLbLocal(nlrow->linvars[i]), SCIPvarGetUbLocal(nlrow->linvars[i]));
595  	      SCIPintervalMulScalar(inf, &bounds, bounds, nlrow->lincoefs[i]);
596  	      SCIPintervalAdd(inf, &activity, activity, bounds);
597  	   }
598  	
599  	   if( nlrow->expr != NULL && !SCIPintervalIsEntire(inf, activity) )
600  	   {
601  	      SCIP_CALL( SCIPexprEvalActivity(set, stat, blkmem, nlrow->expr) );
602  	      SCIPintervalAdd(inf, &activity, activity, SCIPexprGetActivity(nlrow->expr));
603  	   }
604  	
605  	   nlrow->minactivity = SCIPintervalGetInf(activity);
606  	   nlrow->maxactivity = SCIPintervalGetSup(activity);
607  	
608  	   nlrow->validactivitybdsdomchg = stat->domchgcount;
609  	
610  	   return SCIP_OKAY;
611  	}
612  	
613  	/** makes sure that there is no fixed variable at position pos of the linear part of a nonlinear row
614  	 *
615  	 * a fixed variable is replaced with the corresponding constant or disaggregated term
616  	 */
617  	static
618  	SCIP_RETCODE nlrowRemoveFixedLinearCoefPos(
619  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
620  	   BMS_BLKMEM*           blkmem,             /**< block memory */
621  	   SCIP_SET*             set,                /**< global SCIP settings */
622  	   SCIP_STAT*            stat,               /**< problem statistics data */
623  	   SCIP_NLP*             nlp,                /**< current NLP data */
624  	   int                   pos                 /**< position of variable in linear variables array */
625  	   )
626  	{
627  	   SCIP_Real oldconstant;
628  	   SCIP_VAR* var;
629  	
630  	   assert(nlrow  != NULL);
631  	   assert(blkmem != NULL);
632  	   assert(pos >= 0);
633  	   assert(pos <  nlrow->nlinvars);
634  	
635  	   var = nlrow->linvars[pos];
636  	
637  	   if( SCIPvarIsActive(var) )
638  	      return SCIP_OKAY;
639  	
640  	   oldconstant = nlrow->constant;
641  	
642  	   /* replace fixed, aggregated, or negated variable */
643  	   SCIP_CALL( SCIPvarGetProbvarSum( &nlrow->linvars[pos], set, &nlrow->lincoefs[pos], &nlrow->constant) );
644  	
645  	   /* if var had been fixed, entry should be removed from row */
646  	   if( nlrow->lincoefs[pos] == 0.0 )
647  	   {
648  	      nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos);
649  	      nlrow->nlinvars--;
650  	
651  	      if( pos < nlrow->nlinvars )
652  	      {
653  	         SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
654  	      }
655  	
656  	      return SCIP_OKAY;
657  	   }
658  	   nlrow->linvarssorted = FALSE;
659  	
660  	   /* notify nlrow that coefficient of var is now 0.0 in row */
661  	   SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) );
662  	
663  	   /* notify nlrow that constant of row has changed */
664  	   if( oldconstant != nlrow->constant )
665  	      SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
666  	
667  	   if( SCIPvarIsActive(nlrow->linvars[pos]) )
668  	   {
669  	      /* if var was aggregated or negated, notify nlrow about new coefficient */
670  	      SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], nlrow->lincoefs[pos], nlp) );
671  	   }
672  	   else
673  	   {
674  	      SCIP_Real coef;
675  	      int i;
676  	
677  	      /* if not removed or active, the new variable should be multi-aggregated */
678  	      assert(SCIPvarGetStatus(nlrow->linvars[pos]) == SCIP_VARSTATUS_MULTAGGR);
679  	
680  	      var  = nlrow->linvars[pos];
681  	      coef = nlrow->lincoefs[pos];
682  	
683  	      /* remove the variable from the row */
684  	      SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
685  	
686  	      /* add multi-aggregated term to row */
687  	      if( SCIPvarGetMultaggrConstant(var) != 0.0 )
688  	      {
689  	         nlrow->constant += coef * SCIPvarGetMultaggrConstant(var);
690  	         SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
691  	      }
692  	      SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars + SCIPvarGetMultaggrNVars(var)) );
693  	      for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i )
694  	      {
695  	         if( SCIPsetIsZero(set, coef * SCIPvarGetMultaggrScalars(var)[i]) )
696  	            continue;
697  	         SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], coef * SCIPvarGetMultaggrScalars(var)[i]) );
698  	         assert(SCIPvarGetMultaggrVars(var)[i] == nlrow->linvars[nlrow->nlinvars-1]);
699  	         if( !SCIPvarIsActive(SCIPvarGetMultaggrVars(var)[i]) )
700  	         {
701  	            /* if newly added variable is fixed, replace it now */
702  	            SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, nlrow->nlinvars-1) );
703  	         }
704  	      }
705  	
706  	      /* due to nlrowDelLinearCoefPos, an inactive variable may have moved to position pos
707  	       * if that is the case, call ourself recursively
708  	       */
709  	      if( pos < nlrow->nlinvars && !SCIPvarIsActive(nlrow->linvars[pos]) )
710  	      {
711  	         SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
712  	      }
713  	   }
714  	
715  	   return SCIP_OKAY;
716  	}
717  	
718  	/** removes fixed variables from the linear part of a nonlinear row */
719  	static
720  	SCIP_RETCODE nlrowRemoveFixedLinearCoefs(
721  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
722  	   BMS_BLKMEM*           blkmem,             /**< block memory */
723  	   SCIP_SET*             set,                /**< global SCIP settings */
724  	   SCIP_STAT*            stat,               /**< problem statistics data */
725  	   SCIP_NLP*             nlp                 /**< current NLP data */
726  	   )
727  	{
728  	   int i;
729  	   int oldlen;
730  	
731  	   assert(nlrow != NULL);
732  	   assert(nlrow->linvars != NULL || nlrow->nlinvars == 0);
733  	
734  	   oldlen = nlrow->nlinvars;
735  	   for( i = 0; i < MIN(oldlen, nlrow->nlinvars); ++i )
736  	   {
737  	      assert(nlrow->linvars[i] != NULL);
738  	      SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, i) );
739  	   }
740  	
741  	   return SCIP_OKAY;
742  	}
743  	
744  	/** removes fixed variables from expression of a nonlinear row */
745  	static
746  	SCIP_RETCODE nlrowSimplifyExpr(
747  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
748  	   BMS_BLKMEM*           blkmem,             /**< block memory */
749  	   SCIP_SET*             set,                /**< global SCIP settings */
750  	   SCIP_STAT*            stat,               /**< problem statistics data */
751  	   SCIP_NLP*             nlp                 /**< current NLP data */
752  	   )
753  	{
754  	   SCIP_EXPR* simplified;
755  	   SCIP_Bool changed;
756  	   SCIP_Bool infeasible;
757  	
758  	   if( nlrow->expr == NULL )
759  	      return SCIP_OKAY;
760  	
761  	   SCIP_CALL( SCIPexprSimplify(set, stat, blkmem, nlrow->expr, &simplified, &changed, &infeasible, NULL, NULL) );
762  	   assert(!infeasible);
763  	
764  	   if( !changed )
765  	   {
766  	      SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &simplified) );
767  	      return SCIP_OKAY;
768  	   }
769  	
770  	   SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
771  	   nlrow->expr = simplified;
772  	
773  	   if( SCIPexprIsValue(set, nlrow->expr) )
774  	   {
775  	      /* if expression tree is constant, remove it */
776  	      SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + SCIPgetValueExprValue(nlrow->expr)) );
777  	
778  	      SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
779  	   }
780  	
781  	   SCIP_CALL( nlrowExprChanged(nlrow, blkmem, set, stat, nlp) );
782  	
783  	   return SCIP_OKAY;
784  	}
785  	
786  	/** removes fixed variable from nonlinear row */
787  	static
788  	SCIP_RETCODE nlrowRemoveFixedVar(
789  	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
790  	   BMS_BLKMEM*           blkmem,             /**< block memory */
791  	   SCIP_SET*             set,                /**< global SCIP settings */
792  	   SCIP_STAT*            stat,               /**< problem statistics data */
793  	   SCIP_NLP*             nlp,                /**< current NLP data */
794  	   SCIP_VAR*             var                 /**< variable that had been fixed */
795  	   )
796  	{
797  	   int pos;
798  	
799  	   assert(nlrow != NULL);
800  	   assert(var   != NULL);
801  	   assert(!SCIPvarIsActive(var));
802  	
803  	   /* search for variable in linear part and remove if existing */
804  	   pos = nlrowSearchLinearCoef(nlrow, var);
805  	   if( pos >= 0 )
806  	   {
807  	      SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) );
808  	   }
809  	
810  	   /* search for variable in nonlinear part and remove all fixed variables in expression if existing
811  	    * TODO only call simplify if var appears in expr, but currently we don't store the vars in a separate array
812  	    */
813  	   if( nlrow->expr != NULL )
814  	   {
815  	      SCIP_CALL( nlrowSimplifyExpr(nlrow, blkmem, set, stat, nlp) );
816  	   }
817  	
818  	   return SCIP_OKAY;
819  	}
820  	
821  	/*
822  	 * public NLP nonlinear row methods
823  	 */
824  	/**@addtogroup PublicNLRowMethods
825  	 *
826  	 * @{
827  	 */
828  	
829  	/** create a new nonlinear row
830  	 *
831  	 * the new row is already captured
832  	 */
833  	SCIP_RETCODE SCIPnlrowCreate(
834  	   SCIP_NLROW**          nlrow,              /**< buffer to store pointer to nonlinear row */
835  	   BMS_BLKMEM*           blkmem,             /**< block memory */
836  	   SCIP_SET*             set,                /**< global SCIP settings */
837  	   SCIP_STAT*            stat,               /**< problem statistics data */
838  	   const char*           name,               /**< name of nonlinear row */
839  	   SCIP_Real             constant,           /**< constant */
840  	   int                   nlinvars,           /**< number of linear variables */
841  	   SCIP_VAR**            linvars,            /**< linear variables, or NULL if nlinvars == 0 */
842  	   SCIP_Real*            lincoefs,           /**< linear coefficients, or NULL if nlinvars == 0 */
843  	   SCIP_EXPR*            expr,               /**< expression, or NULL */
844  	   SCIP_Real             lhs,                /**< left hand side */
845  	   SCIP_Real             rhs,                /**< right hand side */
846  	   SCIP_EXPRCURV         curvature           /**< curvature of the nonlinear row */
847  	   )
848  	{
849  	#ifndef NDEBUG
850  	   int i;
851  	#endif
852  	
853  	   assert(nlrow  != NULL);
854  	   assert(blkmem != NULL);
855  	   assert(set    != NULL);
856  	   assert(name   != NULL);
857  	   assert(!SCIPsetIsInfinity(set, ABS(constant)));
858  	   assert(nlinvars   == 0 || linvars   != NULL);
859  	   assert(nlinvars   == 0 || lincoefs  != NULL);
860  	   assert(SCIPsetIsRelLE(set, lhs, rhs));
861  	
862  	   SCIP_ALLOC( BMSallocBlockMemory(blkmem, nlrow) );
863  	
864  	   /* constant part */
865  	   assert(!SCIPsetIsInfinity(set, REALABS(constant)));
866  	   (*nlrow)->constant = constant;
867  	
868  	#ifndef NDEBUG
869  	   for( i = 0; i < nlinvars; ++i )
870  	   {
871  	      assert(linvars[i] != NULL);
872  	      assert(!SCIPsetIsInfinity(set, REALABS(lincoefs[i])));
873  	   }
874  	#endif
875  	
876  	   /* linear part */
877  	   (*nlrow)->nlinvars = nlinvars;
878  	   (*nlrow)->linvarssize = nlinvars;
879  	   if( nlinvars > 0 )
880  	   {
881  	      SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->linvars,  linvars,  nlinvars) );
882  	      SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->lincoefs, lincoefs, nlinvars) );
883  	      (*nlrow)->linvarssorted = FALSE;
884  	   }
885  	   else
886  	   {
887  	      (*nlrow)->linvars  = NULL;
888  	      (*nlrow)->lincoefs = NULL;
889  	      (*nlrow)->linvarssorted = TRUE;
890  	   }
891  	
892  	   /* nonlinear part */
893  	   if( expr != NULL )
894  	   {
895  	      /* TODO preserve common subexpressions, or at least use only one varexpr per var */
896  	      SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, expr, &(*nlrow)->expr, NULL, NULL, NULL, NULL) );
897  	   }
898  	   else
899  	   {
900  	      (*nlrow)->expr = NULL;
901  	   }
902  	
903  	   /* left and right hand sides, asserted above that lhs is relatively less equal than rhs */
904  	   (*nlrow)->lhs = MIN(lhs, rhs);
905  	   (*nlrow)->rhs = MAX(lhs, rhs);
906  	
907  	   /* miscellaneous */
908  	   SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->name, name, strlen(name)+1) );
909  	   (*nlrow)->activity = SCIP_INVALID;
910  	   (*nlrow)->validactivitynlp = FALSE;
911  	   (*nlrow)->pseudoactivity = SCIP_INVALID;
912  	   (*nlrow)->validpsactivitydomchg = FALSE;
913  	   (*nlrow)->minactivity = SCIP_INVALID;
914  	   (*nlrow)->maxactivity = SCIP_INVALID;
915  	   (*nlrow)->validactivitybdsdomchg = FALSE;
916  	   (*nlrow)->nlpindex = -1;
917  	   (*nlrow)->nlpiindex = -1;
918  	   (*nlrow)->nuses = 0;
919  	   (*nlrow)->dualsol = 0.0;
920  	   (*nlrow)->curvature = curvature;
921  	
922  	   /* capture the nonlinear row */
923  	   SCIPnlrowCapture(*nlrow);
924  	
925  	   return SCIP_OKAY;
926  	}
927  	
928  	/** create a nonlinear row that is a copy of a given row
929  	 *
930  	 * the new row is already captured
931  	 */
932  	SCIP_RETCODE SCIPnlrowCreateCopy(
933  	   SCIP_NLROW**          nlrow,              /**< buffer to store pointer to nonlinear row */
934  	   BMS_BLKMEM*           blkmem,             /**< block memory */
935  	   SCIP_SET*             set,                /**< global SCIP settings */
936  	   SCIP_STAT*            stat,               /**< problem statistics data */
937  	   SCIP_NLROW*           sourcenlrow         /**< nonlinear row to copy */
938  	   )
939  	{
940  	   assert(nlrow  != NULL);
941  	   assert(blkmem != NULL);
942  	   assert(set    != NULL);
943  	   assert(sourcenlrow != NULL);
944  	
945  	   SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, sourcenlrow->name,
946  	         sourcenlrow->constant,
947  	         sourcenlrow->nlinvars, sourcenlrow->linvars, sourcenlrow->lincoefs,
948  	         sourcenlrow->expr,
949  	         sourcenlrow->lhs, sourcenlrow->rhs, sourcenlrow->curvature) );
950  	
951  	   (*nlrow)->linvarssorted          = sourcenlrow->linvarssorted;
952  	   (*nlrow)->activity               = sourcenlrow->activity;
953  	   (*nlrow)->validactivitynlp       = sourcenlrow->validactivitynlp;
954  	   (*nlrow)->pseudoactivity         = sourcenlrow->pseudoactivity;
955  	   (*nlrow)->validpsactivitydomchg  = sourcenlrow->validpsactivitydomchg;
956  	   (*nlrow)->minactivity            = sourcenlrow->minactivity;
957  	   (*nlrow)->maxactivity            = sourcenlrow->maxactivity;
958  	   (*nlrow)->validactivitybdsdomchg = sourcenlrow->validactivitybdsdomchg;
959  	
960  	   return SCIP_OKAY;
961  	}
962  	
963  	/** create a new nonlinear row from a linear row
964  	 *
965  	 * the new row is already captured
966  	 */
967  	SCIP_RETCODE SCIPnlrowCreateFromRow(
968  	   SCIP_NLROW**          nlrow,              /**< buffer to store pointer to nonlinear row */
969  	   BMS_BLKMEM*           blkmem,             /**< block memory */
970  	   SCIP_SET*             set,                /**< global SCIP settings */
971  	   SCIP_STAT*            stat,               /**< problem statistics data */
972  	   SCIP_ROW*             row                 /**< the linear row to copy */
973  	   )
974  	{
975  	   int rownz;
976  	
977  	   assert(nlrow  != NULL);
978  	   assert(blkmem != NULL);
979  	   assert(set    != NULL);
980  	   assert(row    != NULL);
981  	
982  	   rownz = SCIProwGetNNonz(row);
983  	
984  	   if( rownz > 1 )
985  	   {
986  	      SCIP_VAR** rowvars;
987  	      int i;
988  	
989  	      SCIP_CALL( SCIPsetAllocBufferArray(set, &rowvars, rownz) );
990  	
991  	      for( i = 0; i < rownz; ++i )
992  	      {
993  	         rowvars[i] = SCIPcolGetVar(SCIProwGetCols(row)[i]);
994  	         assert(rowvars[i] != NULL);
995  	      }
996  	
997  	      SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row),
998  	            SCIProwGetConstant(row),
999  	            rownz, rowvars, SCIProwGetVals(row), NULL,
1000 	            SCIProwGetLhs(row), SCIProwGetRhs(row),
1001 	            SCIP_EXPRCURV_LINEAR) );
1002 	
1003 	      SCIPsetFreeBufferArray(set, &rowvars);
1004 	   }
1005 	   else if( rownz == 1 )
1006 	   {
1007 	      SCIP_VAR* rowvar;
1008 	
1009 	      rowvar = SCIPcolGetVar(SCIProwGetCols(row)[0]);
1010 	
1011 	      SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row),
1012 	            SCIProwGetConstant(row),
1013 	            1, &rowvar, SCIProwGetVals(row), NULL,
1014 	            SCIProwGetLhs(row), SCIProwGetRhs(row),
1015 	            SCIP_EXPRCURV_LINEAR) );
1016 	   }
1017 	   else
1018 	   {
1019 	      SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row),
1020 	            SCIProwGetConstant(row),
1021 	            0, NULL, NULL, NULL,
1022 	            SCIProwGetLhs(row), SCIProwGetRhs(row),
1023 	            SCIP_EXPRCURV_LINEAR) );
1024 	   }
1025 	
1026 	   return SCIP_OKAY;   
1027 	}
1028 	
1029 	/** output nonlinear row to file stream */
1030 	SCIP_RETCODE SCIPnlrowPrint(
1031 	   SCIP_NLROW*           nlrow,              /**< NLP row */
1032 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1033 	   SCIP_SET*             set,                /**< global SCIP settings */
1034 	   SCIP_STAT*            stat,               /**< problem statistics data */
1035 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
(1) Event noescape: "SCIPnlrowPrint(SCIP_NLROW *, BMS_BLKMEM *, SCIP_SET *, SCIP_STAT *, SCIP_MESSAGEHDLR *, FILE *)" does not free or save its parameter "file".
1036 	   FILE*                 file                /**< output file (or NULL for standard output) */
1037 	   )
1038 	{
1039 	   int i;
1040 	
1041 	   assert(nlrow != NULL);
1042 	
1043 	   /* print row name */
1044 	   if( nlrow->name != NULL && nlrow->name[0] != '\0' )
1045 	   {
1046 	      SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", nlrow->name);
1047 	   }
1048 	
1049 	   /* print left hand side */
1050 	   SCIPmessageFPrintInfo(messagehdlr, file, "%.15g <= ", nlrow->lhs);
1051 	
1052 	   /* print constant */
1053 	   SCIPmessageFPrintInfo(messagehdlr, file, "%.15g ", nlrow->constant);
1054 	
1055 	   /* print linear coefficients */
1056 	   for( i = 0; i < nlrow->nlinvars; ++i )
1057 	   {
1058 	      assert(nlrow->linvars[i] != NULL);
1059 	      assert(SCIPvarGetName(nlrow->linvars[i]) != NULL);
1060 	      SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", nlrow->lincoefs[i], SCIPvarGetName(nlrow->linvars[i]));
1061 	   }
1062 	
1063 	   /* print nonlinear part */
1064 	   if( nlrow->expr != NULL )
1065 	   {
1066 	      SCIPmessageFPrintInfo(messagehdlr, file, " + ");
1067 	      SCIP_CALL( SCIPexprPrint(set, stat, blkmem, messagehdlr, file, nlrow->expr) );
1068 	   }
1069 	
1070 	   /* print right hand side */
1071 	   SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", nlrow->rhs);
1072 	
1073 	   return SCIP_OKAY;
1074 	}
1075 	
1076 	/** increases usage counter of nonlinear row */
1077 	void SCIPnlrowCapture(
1078 	   SCIP_NLROW*           nlrow               /**< nonlinear row to capture */
1079 	   )
1080 	{
1081 	   assert(nlrow != NULL);
1082 	   assert(nlrow->nuses >= 0);
1083 	
1084 	   SCIPdebugMessage("capture nonlinear row <%s> with nuses=%d\n", nlrow->name, nlrow->nuses);
1085 	   nlrow->nuses++;
1086 	}
1087 	
1088 	/** decreases usage counter of nonlinear row */
1089 	SCIP_RETCODE SCIPnlrowRelease(
1090 	   SCIP_NLROW**          nlrow,              /**< nonlinear row to free */
1091 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1092 	   SCIP_SET*             set,                /**< global SCIP settings */
1093 	   SCIP_STAT*            stat                /**< problem statistics data */
1094 	   )
1095 	{
1096 	   assert(blkmem != NULL);
1097 	   assert(nlrow  != NULL);
1098 	   assert(*nlrow != NULL);
1099 	   assert((*nlrow)->nuses >= 1);
1100 	
1101 	   SCIPsetDebugMsg(set, "release nonlinear row <%s> with nuses=%d\n", (*nlrow)->name, (*nlrow)->nuses);
1102 	   (*nlrow)->nuses--;
1103 	   if( (*nlrow)->nuses > 0 )
1104 	   {
1105 	      *nlrow = NULL;
1106 	      return SCIP_OKAY;
1107 	   }
1108 	
1109 	   /* free row */
1110 	
1111 	   assert((*nlrow)->nuses == 0);
1112 	   assert((*nlrow)->nlpindex == -1);
1113 	   assert((*nlrow)->nlpiindex == -1);
1114 	
1115 	   /* linear part */
1116 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->linvars,   (*nlrow)->linvarssize);
1117 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->lincoefs,  (*nlrow)->linvarssize);
1118 	
1119 	   /* nonlinear part */
1120 	   if( (*nlrow)->expr != NULL )
1121 	   {
1122 	      SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &(*nlrow)->expr) );
1123 	   }
1124 	
1125 	   /* miscellaneous */
1126 	   BMSfreeBlockMemoryArray(blkmem, &(*nlrow)->name, strlen((*nlrow)->name)+1);
1127 	
1128 	   BMSfreeBlockMemory(blkmem, nlrow);
1129 	
1130 	   return SCIP_OKAY;
1131 	}
1132 	
1133 	/** ensures, that linear coefficient array of nonlinear row can store at least num entries */
1134 	SCIP_RETCODE SCIPnlrowEnsureLinearSize(
1135 	   SCIP_NLROW*           nlrow,              /**< NLP row */
1136 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1137 	   SCIP_SET*             set,                /**< global SCIP settings */
1138 	   int                   num                 /**< minimum number of entries to store */
1139 	   )
1140 	{
1141 	   assert(nlrow != NULL);
1142 	   assert(nlrow->nlinvars <= nlrow->linvarssize);
1143 	
1144 	   if( num > nlrow->linvarssize )
1145 	   {
1146 	      int newsize;
1147 	
1148 	      newsize = SCIPsetCalcMemGrowSize(set, num);
1149 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->linvars,  nlrow->linvarssize, newsize) );
1150 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->lincoefs, nlrow->linvarssize, newsize) );
1151 	      nlrow->linvarssize = newsize;
1152 	   }
1153 	   assert(num <= nlrow->linvarssize);
1154 	
1155 	   return SCIP_OKAY;
1156 	}
1157 	
1158 	/** adds a previously non existing linear coefficient to a nonlinear row */
1159 	SCIP_RETCODE SCIPnlrowAddLinearCoef(
1160 	   SCIP_NLROW*           nlrow,              /**< NLP nonlinear row */
1161 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1162 	   SCIP_SET*             set,                /**< global SCIP settings */
1163 	   SCIP_STAT*            stat,               /**< problem statistics data */
1164 	   SCIP_NLP*             nlp,                /**< current NLP data */
1165 	   SCIP_VAR*             var,                /**< variable */
1166 	   SCIP_Real             val                 /**< value of coefficient */
1167 	   )
1168 	{
1169 	   /* if row is in NLP already, make sure that only active variables are added */
1170 	   if( nlrow->nlpindex >= 0 )
1171 	   {
1172 	      SCIP_Real constant;
1173 	
1174 	      /* get corresponding active or multi-aggregated variable */
1175 	      constant = 0.0;
1176 	      SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &val, &constant) );
1177 	
1178 	      /* add constant */
1179 	      SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + constant) );
1180 	
1181 	      if( val == 0.0 )
1182 	         /* var has been fixed */
1183 	         return SCIP_OKAY;
1184 	
1185 	      if( !SCIPvarIsActive(var) )
1186 	      {
1187 	         /* var should be multi-aggregated, so call this function recursively */
1188 	         int i;
1189 	
1190 	         assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
1191 	         for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i )
1192 	         {
1193 	            SCIP_CALL( SCIPnlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], SCIPvarGetMultaggrScalars(var)[i] * val) );
1194 	         }
1195 	         return SCIP_OKAY;
1196 	      }
1197 	
1198 	      /* var is active, so can go on like normal */
1199 	   }
1200 	
1201 	   SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, val) );
1202 	
1203 	   return SCIP_OKAY;
1204 	}
1205 	
1206 	/** deletes linear coefficient from nonlinear row */
1207 	SCIP_RETCODE SCIPnlrowDelLinearCoef(
1208 	   SCIP_NLROW*           nlrow,              /**< nonlinear row to be changed */
1209 	   SCIP_SET*             set,                /**< global SCIP settings */
1210 	   SCIP_STAT*            stat,               /**< problem statistics data */
1211 	   SCIP_NLP*             nlp,                /**< current NLP data */
1212 	   SCIP_VAR*             var                 /**< coefficient to be deleted */
1213 	   )
1214 	{
1215 	   int pos;
1216 	
1217 	   assert(nlrow != NULL);
1218 	   assert(var   != NULL);
1219 	
1220 	   /* 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 */
1221 	   assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) );
1222 	
1223 	   /* search the position of the variable in the row's variable vector */
1224 	   pos = nlrowSearchLinearCoef(nlrow, var);
1225 	   if( pos == -1 )
1226 	   {
1227 	      SCIPerrorMessage("coefficient for variable <%s> doesn't exist in nonlinear row <%s>\n", SCIPvarGetName(var), nlrow->name);
1228 	      return SCIP_INVALIDDATA;
1229 	   }
1230 	   assert(0 <= pos && pos < nlrow->nlinvars);
1231 	   assert(nlrow->linvars[pos] == var);
1232 	
1233 	   /* delete the variable from the row's variable vector */
1234 	   SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) );
1235 	
1236 	   return SCIP_OKAY;
1237 	}
1238 	
1239 	/** changes or adds a linear coefficient to a nonlinear row */
1240 	SCIP_RETCODE SCIPnlrowChgLinearCoef(
1241 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1242 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1243 	   SCIP_SET*             set,                /**< global SCIP settings */
1244 	   SCIP_STAT*            stat,               /**< problem statistics data */
1245 	   SCIP_NLP*             nlp,                /**< current NLP data */
1246 	   SCIP_VAR*             var,                /**< variable */
1247 	   SCIP_Real             coef                /**< new value of coefficient */
1248 	   )
1249 	{
1250 	   int pos;
1251 	
1252 	   assert(nlrow != NULL);
1253 	   assert(nlp != NULL);
1254 	   assert(var != NULL);
1255 	
1256 	   /* search the position of the variable in the row's linvars vector */
1257 	   pos = nlrowSearchLinearCoef(nlrow, var);
1258 	
1259 	   /* check, if column already exists in the row's linear variables vector */
1260 	   if( pos == -1 )
1261 	   {
1262 	      if( !SCIPsetIsZero(set, coef) )
1263 	      {
1264 	         /* add previously not existing coefficient */
1265 	         SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) );
1266 	      }
1267 	   }
1268 	   else
1269 	   {
1270 	      /* change the coefficient in the row */
1271 	      SCIP_CALL( nlrowChgLinearCoefPos(nlrow, set, stat, nlp, pos, coef) );
1272 	   }
1273 	
1274 	   return SCIP_OKAY;
1275 	}
1276 	
1277 	/** replaces or deletes an expression in a nonlinear row */
1278 	SCIP_RETCODE SCIPnlrowChgExpr(
1279 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1280 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1281 	   SCIP_SET*             set,                /**< global SCIP settings */
1282 	   SCIP_STAT*            stat,               /**< problem statistics data */
1283 	   SCIP_NLP*             nlp,                /**< current NLP data */
1284 	   SCIP_EXPR*            expr                /**< new expression */
1285 	   )
1286 	{
1287 	   assert(nlrow  != NULL);
1288 	   assert(blkmem != NULL);
1289 	
1290 	   /* free previous expression tree */
1291 	   if( nlrow->expr != NULL )
1292 	   {
1293 	      SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
1294 	      assert(nlrow->expr == NULL);
1295 	   }
1296 	
1297 	   /* adds new expression tree */
1298 	   if( expr != NULL )
1299 	   {
1300 	      /* TODO preserve common subexpressions, or at least use only one varexpr per var */
1301 	      SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, expr, &nlrow->expr, NULL, NULL, NULL, NULL) );
1302 	
1303 	      /* if row is already in NLP, ensure that expr has only active variables */
1304 	      if( nlrow->nlpindex >= 0 )
1305 	      {
1306 	         SCIP_EXPR* simplified;
1307 	         SCIP_Bool changed;
1308 	         SCIP_Bool infeasible;
1309 	
1310 	         SCIP_CALL( SCIPexprSimplify(set, stat, blkmem, nlrow->expr, &simplified, &changed, &infeasible, NULL, NULL) );
1311 	         assert(!infeasible);
1312 	
1313 	         SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) );
1314 	         nlrow->expr = simplified;
1315 	      }
1316 	   }
1317 	
1318 	   /* notify row about the change */
1319 	   SCIP_CALL( nlrowExprChanged(nlrow, blkmem, set, stat, nlp) );
1320 	
1321 	   return SCIP_OKAY;
1322 	}
1323 	
1324 	/** changes constant of nonlinear row */
1325 	SCIP_RETCODE SCIPnlrowChgConstant(
1326 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1327 	   SCIP_SET*             set,                /**< global SCIP settings */
1328 	   SCIP_STAT*            stat,               /**< problem statistics data */
1329 	   SCIP_NLP*             nlp,                /**< current NLP data */
1330 	   SCIP_Real             constant            /**< new constant */
1331 	   )
1332 	{
1333 	   assert(nlrow != NULL);
1334 	
1335 	   if( !SCIPsetIsEQ(set, nlrow->constant, constant) )
1336 	   {
1337 	      nlrow->constant = constant;
1338 	      SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) );
1339 	   }
1340 	
1341 	   return SCIP_OKAY;
1342 	}
1343 	
1344 	/** changes left hand side of nonlinear row */
1345 	SCIP_RETCODE SCIPnlrowChgLhs(
1346 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1347 	   SCIP_SET*             set,                /**< global SCIP settings */
1348 	   SCIP_STAT*            stat,               /**< problem statistics data */
1349 	   SCIP_NLP*             nlp,                /**< current NLP data */
1350 	   SCIP_Real             lhs                 /**< new left hand side */
1351 	   )
1352 	{
1353 	   assert(nlrow != NULL);
1354 	
1355 	   if( !SCIPsetIsEQ(set, nlrow->lhs, lhs) )
1356 	   {
1357 	      nlrow->lhs = lhs;
1358 	      SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) );
1359 	   }
1360 	
1361 	   return SCIP_OKAY;
1362 	}
1363 	
1364 	/** changes right hand side of nonlinear row */
1365 	SCIP_RETCODE SCIPnlrowChgRhs(
1366 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1367 	   SCIP_SET*             set,                /**< global SCIP settings */
1368 	   SCIP_STAT*            stat,               /**< problem statistics data */
1369 	   SCIP_NLP*             nlp,                /**< current NLP data */
1370 	   SCIP_Real             rhs                 /**< new right hand side */
1371 	   )
1372 	{
1373 	   assert(nlrow != NULL);
1374 	
1375 	   if( !SCIPsetIsEQ(set, nlrow->rhs, rhs) )
1376 	   {
1377 	      nlrow->rhs = rhs;
1378 	      SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) );
1379 	   }
1380 	
1381 	   return SCIP_OKAY;
1382 	}
1383 	
1384 	/** removes (or substitutes) all fixed, negated, aggregated, multi-aggregated variables from the linear and nonlinear part of a nonlinear row and simplifies its expression */
1385 	SCIP_RETCODE SCIPnlrowSimplify(
1386 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1387 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1388 	   SCIP_SET*             set,                /**< global SCIP settings */
1389 	   SCIP_STAT*            stat,               /**< problem statistics data */
1390 	   SCIP_NLP*             nlp                 /**< current NLP data */
1391 	   )
1392 	{
1393 	   SCIP_CALL( nlrowRemoveFixedLinearCoefs(nlrow, blkmem, set, stat, nlp) );
1394 	   SCIP_CALL( nlrowSimplifyExpr(nlrow, blkmem, set, stat, nlp) );
1395 	
1396 	   return SCIP_OKAY;
1397 	}
1398 	
1399 	/** recalculates the current activity of a nonlinear row in the current NLP solution */
1400 	SCIP_RETCODE SCIPnlrowRecalcNLPActivity(
1401 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1402 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1403 	   SCIP_SET*             set,                /**< global SCIP settings */
1404 	   SCIP_STAT*            stat,               /**< problem statistics data */
1405 	   SCIP_PRIMAL*          primal,             /**< primal data */
1406 	   SCIP_TREE*            tree,               /**< branch and bound tree */
1407 	   SCIP_NLP*             nlp                 /**< current NLP data */
1408 	   )
1409 	{
1410 	   int i;
1411 	
1412 	   assert(nlrow  != NULL);
1413 	   assert(stat   != NULL);
1414 	   assert(nlp    != NULL);
1415 	
1416 	   if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
1417 	   {
1418 	      SCIPerrorMessage("do not have NLP solution for computing NLP activity\n");
1419 	      return SCIP_ERROR;
1420 	   }
1421 	
1422 	   nlrow->activity = nlrow->constant;
1423 	   for( i = 0; i < nlrow->nlinvars; ++i )
1424 	   {
1425 	      assert(nlrow->linvars[i] != NULL);
1426 	      assert(SCIPvarGetNLPSol(nlrow->linvars[i]) < SCIP_INVALID);
1427 	
1428 	      nlrow->activity += nlrow->lincoefs[i] * SCIPvarGetNLPSol(nlrow->linvars[i]);
1429 	   }
1430 	
1431 	   if( nlrow->expr != NULL )
1432 	   {
1433 	      SCIP_SOL* sol;
1434 	
1435 	      SCIP_CALL( SCIPsolCreateNLPSol(&sol, blkmem, set, stat, primal, tree, nlp, NULL) );
1436 	
1437 	      SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) );
1438 	      if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID )
1439 	         nlrow->activity = SCIP_INVALID;
1440 	      else
1441 	         nlrow->activity += SCIPexprGetEvalValue(nlrow->expr);
1442 	
1443 	      SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) );
1444 	   }
1445 	
1446 	   nlrow->validactivitynlp = stat->nnlps;
1447 	
1448 	   return SCIP_OKAY;
1449 	}
1450 	
1451 	/** gives the activity of a nonlinear row in the current NLP solution */
1452 	SCIP_RETCODE SCIPnlrowGetNLPActivity(
1453 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1454 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1455 	   SCIP_SET*             set,                /**< global SCIP settings */
1456 	   SCIP_STAT*            stat,               /**< problem statistics data */
1457 	   SCIP_PRIMAL*          primal,             /**< primal data */
1458 	   SCIP_TREE*            tree,               /**< branch and bound tree */
1459 	   SCIP_NLP*             nlp,                /**< current NLP data */
1460 	   SCIP_Real*            activity            /**< buffer to store activity value */
1461 	   )
1462 	{
1463 	   assert(nlrow  != NULL);
1464 	   assert(stat   != NULL);
1465 	   assert(activity != NULL);
1466 	
1467 	   assert(nlrow->validactivitynlp <= stat->nnlps);
1468 	
1469 	   if( nlrow->validactivitynlp != stat->nnlps )
1470 	   {
1471 	      SCIP_CALL( SCIPnlrowRecalcNLPActivity(nlrow, blkmem, set, stat, primal, tree, nlp) );
1472 	   }
1473 	   assert(nlrow->validactivitynlp == stat->nnlps);
1474 	   assert(nlrow->activity < SCIP_INVALID);
1475 	
1476 	   *activity = nlrow->activity;
1477 	
1478 	   return SCIP_OKAY;
1479 	}
1480 	
1481 	/** gives the feasibility of a nonlinear row in the current NLP solution: negative value means infeasibility */
1482 	SCIP_RETCODE SCIPnlrowGetNLPFeasibility(
1483 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1484 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1485 	   SCIP_SET*             set,                /**< global SCIP settings */
1486 	   SCIP_STAT*            stat,               /**< problem statistics data */
1487 	   SCIP_PRIMAL*          primal,             /**< primal data */
1488 	   SCIP_TREE*            tree,               /**< branch and bound tree */
1489 	   SCIP_NLP*             nlp,                /**< current NLP data */
1490 	   SCIP_Real*            feasibility         /**< buffer to store feasibility value */
1491 	   )
1492 	{
1493 	   SCIP_Real activity;
1494 	
1495 	   assert(nlrow != NULL);
1496 	   assert(feasibility != NULL);
1497 	
1498 	   SCIP_CALL( SCIPnlrowGetNLPActivity(nlrow, blkmem, set, stat, primal, tree, nlp, &activity) );
1499 	   *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs);
1500 	
1501 	   return SCIP_OKAY;
1502 	}
1503 	
1504 	/** calculates the current pseudo activity of a nonlinear row */
1505 	SCIP_RETCODE SCIPnlrowRecalcPseudoActivity(
1506 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1507 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1508 	   SCIP_SET*             set,                /**< global SCIP settings */
1509 	   SCIP_STAT*            stat,               /**< problem statistics data */
1510 	   SCIP_PROB*            prob,               /**< SCIP problem */
1511 	   SCIP_PRIMAL*          primal,             /**< primal data */
1512 	   SCIP_TREE*            tree,               /**< branch and bound tree */
1513 	   SCIP_LP*              lp                  /**< SCIP LP */
1514 	   )
1515 	{
1516 	   SCIP_Real val1;
1517 	   int i;
1518 	
1519 	   assert(nlrow  != NULL);
1520 	   assert(stat   != NULL);
1521 	
1522 	   nlrow->pseudoactivity = nlrow->constant;
1523 	   for( i = 0; i < nlrow->nlinvars; ++i )
1524 	   {
1525 	      assert(nlrow->linvars[i] != NULL);
1526 	
1527 	      val1 = SCIPvarGetBestBoundLocal(nlrow->linvars[i]);
1528 	      nlrow->pseudoactivity += nlrow->lincoefs[i] * val1;
1529 	   }
1530 	
1531 	   if( nlrow->expr != NULL )
1532 	   {
1533 	      SCIP_SOL* sol;
1534 	
1535 	      SCIP_CALL( SCIPsolCreatePseudoSol(&sol, blkmem, set, stat, prob, primal, tree, lp, NULL) );
1536 	
1537 	      SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) );
1538 	      if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID )
1539 	         nlrow->pseudoactivity = SCIP_INVALID;
1540 	      else
1541 	         nlrow->pseudoactivity += SCIPexprGetEvalValue(nlrow->expr);
1542 	
1543 	      SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) );
1544 	   }
1545 	
1546 	   nlrow->validpsactivitydomchg = stat->domchgcount;
1547 	
1548 	   return SCIP_OKAY;
1549 	}
1550 	
1551 	/** returns the pseudo activity of a nonlinear row in the current pseudo solution */
1552 	SCIP_RETCODE SCIPnlrowGetPseudoActivity(
1553 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1554 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1555 	   SCIP_SET*             set,                /**< global SCIP settings */
1556 	   SCIP_STAT*            stat,               /**< problem statistics data */
1557 	   SCIP_PROB*            prob,               /**< SCIP problem */
1558 	   SCIP_PRIMAL*          primal,             /**< primal data */
1559 	   SCIP_TREE*            tree,               /**< branch and bound tree */
1560 	   SCIP_LP*              lp,                 /**< SCIP LP */
1561 	   SCIP_Real*            pseudoactivity      /**< buffer to store pseudo activity value */
1562 	   )
1563 	{
1564 	   assert(nlrow != NULL);
1565 	   assert(stat  != NULL);
1566 	   assert(pseudoactivity != NULL);
1567 	   assert(nlrow->validpsactivitydomchg <= stat->domchgcount);
1568 	
1569 	   /* check, if pseudo activity has to be calculated */
1570 	   if( nlrow->validpsactivitydomchg != stat->domchgcount )
1571 	   {
1572 	      SCIP_CALL( SCIPnlrowRecalcPseudoActivity(nlrow, blkmem, set, stat, prob, primal, tree, lp) );
1573 	   }
1574 	   assert(nlrow->validpsactivitydomchg == stat->domchgcount);
1575 	   assert(nlrow->pseudoactivity < SCIP_INVALID);
1576 	
1577 	   *pseudoactivity = nlrow->pseudoactivity;
1578 	
1579 	   return SCIP_OKAY;
1580 	}
1581 	
1582 	/** returns the pseudo feasibility of a nonlinear row in the current pseudo solution: negative value means infeasibility */
1583 	SCIP_RETCODE SCIPnlrowGetPseudoFeasibility(
1584 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1585 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1586 	   SCIP_SET*             set,                /**< global SCIP settings */
1587 	   SCIP_STAT*            stat,               /**< problem statistics data */
1588 	   SCIP_PROB*            prob,               /**< SCIP problem */
1589 	   SCIP_PRIMAL*          primal,             /**< primal data */
1590 	   SCIP_TREE*            tree,               /**< branch and bound tree */
1591 	   SCIP_LP*              lp,                 /**< SCIP LP */
1592 	   SCIP_Real*            pseudofeasibility   /**< buffer to store pseudo feasibility value */
1593 	   )
1594 	{
1595 	   SCIP_Real pseudoactivity;
1596 	
1597 	   assert(nlrow != NULL);
1598 	   assert(stat  != NULL);
1599 	   assert(pseudofeasibility != NULL);
1600 	
1601 	   SCIP_CALL( SCIPnlrowGetPseudoActivity(nlrow, blkmem, set, stat, prob, primal, tree, lp, &pseudoactivity) );
1602 	   *pseudofeasibility = MIN(nlrow->rhs - pseudoactivity, pseudoactivity - nlrow->lhs);
1603 	
1604 	   return SCIP_OKAY;
1605 	}
1606 	
1607 	/** returns the activity of a nonlinear row for a given solution */
1608 	SCIP_RETCODE SCIPnlrowGetSolActivity(
1609 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1610 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1611 	   SCIP_SET*             set,                /**< global SCIP settings */
1612 	   SCIP_STAT*            stat,               /**< problem statistics data */
1613 	   SCIP_SOL*             sol,                /**< primal CIP solution */
1614 	   SCIP_Real*            activity            /**< buffer to store activity value */
1615 	   )
1616 	{
1617 	   SCIP_Real inf;
1618 	   SCIP_Real val1;
1619 	   int i;
1620 	
1621 	   assert(nlrow != NULL);
1622 	   assert(set != NULL);
1623 	   assert(stat != NULL);
1624 	   assert(activity != NULL);
1625 	
1626 	   *activity = nlrow->constant;
1627 	   for( i = 0; i < nlrow->nlinvars; ++i )
1628 	   {
1629 	      assert(nlrow->linvars[i] != NULL);
1630 	
1631 	      val1 = SCIPsolGetVal(sol, set, stat, nlrow->linvars[i]);
1632 	      if( val1 == SCIP_UNKNOWN )
1633 	      {
1634 	         *activity = SCIP_INVALID;
1635 	         return SCIP_OKAY;
1636 	      }
1637 	      *activity += nlrow->lincoefs[i] * val1;
1638 	   }
1639 	
1640 	   if( nlrow->expr != NULL )
1641 	   {
1642 	      SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) );
1643 	      if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID )
1644 	         *activity = SCIP_INVALID;
1645 	      else
1646 	         *activity += SCIPexprGetEvalValue(nlrow->expr);
1647 	   }
1648 	
1649 	   inf = SCIPsetInfinity(set);
1650 	   *activity = MAX(*activity, -inf);
1651 	   *activity = MIN(*activity, +inf);
1652 	
1653 	   return SCIP_OKAY;
1654 	}
1655 	
1656 	/** returns the feasibility of a nonlinear row for the given solution */
1657 	SCIP_RETCODE SCIPnlrowGetSolFeasibility(
1658 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1659 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1660 	   SCIP_SET*             set,                /**< global SCIP settings */
1661 	   SCIP_STAT*            stat,               /**< problem statistics data */
1662 	   SCIP_SOL*             sol,                /**< primal CIP solution */
1663 	   SCIP_Real*            feasibility         /**< buffer to store feasibility value */
1664 	   )
1665 	{
1666 	   SCIP_Real activity;
1667 	
1668 	   assert(nlrow != NULL);
1669 	   assert(feasibility != NULL);
1670 	
1671 	   SCIP_CALL( SCIPnlrowGetSolActivity(nlrow, blkmem, set, stat, sol, &activity) );
1672 	
1673 	   *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs);
1674 	
1675 	   return SCIP_OKAY;
1676 	}
1677 	
1678 	/** returns the minimal activity of a nonlinear row w.r.t. the variables' bounds */
1679 	SCIP_RETCODE SCIPnlrowGetActivityBounds(
1680 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1681 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1682 	   SCIP_SET*             set,                /**< global SCIP settings */
1683 	   SCIP_STAT*            stat,               /**< problem statistics data */
1684 	   SCIP_Real*            minactivity,        /**< buffer to store minimal activity, or NULL */
1685 	   SCIP_Real*            maxactivity         /**< buffer to store maximal activity, or NULL */
1686 	   )
1687 	{
1688 	   assert(nlrow != NULL);
1689 	   assert(set != NULL);
1690 	   assert(stat != NULL);
1691 	   assert(nlrow->validactivitybdsdomchg <= stat->domchgcount);
1692 	
1693 	   /* check, if activity bounds has to be calculated */
1694 	   if( nlrow->validactivitybdsdomchg != stat->domchgcount )
1695 	   {
1696 	      SCIP_CALL( nlrowCalcActivityBounds(nlrow, blkmem, set, stat) );
1697 	   }
1698 	   assert(nlrow->validactivitybdsdomchg == stat->domchgcount);
1699 	   assert(nlrow->minactivity < SCIP_INVALID);
1700 	   assert(nlrow->maxactivity < SCIP_INVALID);
1701 	
1702 	   if( minactivity != NULL )
1703 	      *minactivity = nlrow->minactivity;
1704 	   if( maxactivity != NULL )
1705 	      *maxactivity = nlrow->maxactivity;
1706 	
1707 	   return SCIP_OKAY;
1708 	}
1709 	
1710 	/** returns whether the nonlinear row is redundant w.r.t. the variables' bounds */
1711 	SCIP_RETCODE SCIPnlrowIsRedundant(
1712 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
1713 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1714 	   SCIP_SET*             set,                /**< global SCIP settings */
1715 	   SCIP_STAT*            stat,               /**< problem statistics data */
1716 	   SCIP_Bool*            isredundant         /**< buffer to store whether row is redundant */
1717 	   )
1718 	{
1719 	   SCIP_Real minactivity;
1720 	   SCIP_Real maxactivity;
1721 	
1722 	   assert(nlrow != NULL);
1723 	   assert(set != NULL);
1724 	   assert(isredundant != NULL);
1725 	
1726 	   SCIP_CALL( SCIPnlrowGetActivityBounds(nlrow, blkmem, set, stat, &minactivity, &maxactivity) );
1727 	
1728 	   *isredundant = TRUE;
1729 	   if( (!SCIPsetIsInfinity(set, -nlrow->lhs) && SCIPsetIsFeasLT(set, minactivity, nlrow->lhs)) ||
1730 	      ( !SCIPsetIsInfinity(set,  nlrow->rhs) && SCIPsetIsFeasGT(set, maxactivity, nlrow->rhs)) )
1731 	      *isredundant = FALSE;
1732 	
1733 	   return SCIP_OKAY;
1734 	}
1735 	
1736 	/** gets constant */
1737 	SCIP_Real SCIPnlrowGetConstant(
1738 	   SCIP_NLROW*           nlrow               /**< NLP row */
1739 	   )
1740 	{
1741 	   assert(nlrow != NULL);
1742 	
1743 	   return nlrow->constant;
1744 	}
1745 	
1746 	/** gets number of variables of linear part */
1747 	int SCIPnlrowGetNLinearVars(
1748 	   SCIP_NLROW*           nlrow               /**< NLP row */
1749 	   )
1750 	{
1751 	   assert(nlrow != NULL);
1752 	
1753 	   return nlrow->nlinvars;
1754 	}
1755 	
1756 	/** gets array with variables of linear part */
1757 	SCIP_VAR** SCIPnlrowGetLinearVars(
1758 	   SCIP_NLROW*           nlrow               /**< NLP row */
1759 	   )
1760 	{
1761 	   assert(nlrow != NULL);
1762 	
1763 	   return nlrow->linvars;
1764 	}
1765 	
1766 	/** gets array with coefficients in linear part */
1767 	SCIP_Real* SCIPnlrowGetLinearCoefs(
1768 	   SCIP_NLROW*           nlrow               /**< NLP row */
1769 	   )
1770 	{
1771 	   assert(nlrow != NULL);
1772 	
1773 	   return nlrow->lincoefs;
1774 	}
1775 	
1776 	/** gets expression */
1777 	SCIP_EXPR* SCIPnlrowGetExpr(
1778 	   SCIP_NLROW*           nlrow               /**< NLP row */
1779 	   )
1780 	{
1781 	   assert(nlrow != NULL);
1782 	
1783 	   return nlrow->expr;
1784 	}
1785 	
1786 	/** returns the left hand side of a nonlinear row */
1787 	SCIP_Real SCIPnlrowGetLhs(
1788 	   SCIP_NLROW*           nlrow               /**< NLP row */
1789 	   )
1790 	{
1791 	   assert(nlrow != NULL);
1792 	
1793 	   return nlrow->lhs;
1794 	}
1795 	
1796 	/** returns the right hand side of a nonlinear row */
1797 	SCIP_Real SCIPnlrowGetRhs(
1798 	   SCIP_NLROW*           nlrow               /**< NLP row */
1799 	   )
1800 	{
1801 	   assert(nlrow != NULL);
1802 	
1803 	   return nlrow->rhs;
1804 	}
1805 	
1806 	/** returns the curvature of a nonlinear row */
1807 	SCIP_EXPRCURV SCIPnlrowGetCurvature(
1808 	   SCIP_NLROW*           nlrow               /**< NLP row */
1809 	   )
1810 	{
1811 	   assert(nlrow != NULL);
1812 	   return nlrow->curvature;
1813 	}
1814 	
1815 	/** sets the curvature of a nonlinear row */
1816 	void SCIPnlrowSetCurvature(
1817 	   SCIP_NLROW*           nlrow,              /**< NLP row */
1818 	   SCIP_EXPRCURV         curvature           /**< curvature of NLP row */
1819 	   )
1820 	{
1821 	   assert(nlrow != NULL);
1822 	   nlrow->curvature = curvature;
1823 	}
1824 	
1825 	/** returns the name of a nonlinear row */
1826 	const char* SCIPnlrowGetName(
1827 	   SCIP_NLROW*           nlrow               /**< NLP row */
1828 	   )
1829 	{
1830 	   assert(nlrow != NULL);
1831 	
1832 	   return nlrow->name;
1833 	}
1834 	
1835 	/** gets position of a nonlinear row in current NLP, or -1 if not in NLP */
1836 	int SCIPnlrowGetNLPPos(
1837 	   SCIP_NLROW*           nlrow               /**< NLP row */
1838 	   )
1839 	{
1840 	   assert(nlrow != NULL);
1841 	
1842 	   return nlrow->nlpindex;
1843 	}
1844 	
1845 	/** returns TRUE iff row is member of current NLP */
1846 	SCIP_Bool SCIPnlrowIsInNLP(
1847 	   SCIP_NLROW*           nlrow               /**< NLP row */
1848 	   )
1849 	{
1850 	   assert(nlrow != NULL);
1851 	
1852 	   return nlrow->nlpindex != -1;
1853 	}
1854 	
1855 	/** gets the dual NLP solution of a nlrow
1856 	 *
1857 	 * 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
1858 	 */
1859 	SCIP_Real SCIPnlrowGetDualsol(
1860 	   SCIP_NLROW*           nlrow               /**< NLP row */
1861 	   )
1862 	{
1863 	   assert(nlrow != NULL);
1864 	
1865 	   return nlrow->nlpiindex >= 0 ? nlrow->dualsol : 0.0;
1866 	}
1867 	
1868 	/** @} */
1869 	
1870 	/*
1871 	 * local NLP methods
1872 	 */
1873 	
1874 	/** announces, that a row of the NLP was modified
1875 	 * adjusts status of current solution
1876 	 * calling method has to ensure that change is passed to the NLPI!
1877 	 */ /*lint -e{715}*/
1878 	static
1879 	SCIP_RETCODE nlpRowChanged(
1880 	   SCIP_NLP*             nlp,                /**< current NLP data */
1881 	   SCIP_SET*             set,                /**< global SCIP settings */
1882 	   SCIP_STAT*            stat,               /**< problem statistics data */
1883 	   SCIP_NLROW*           nlrow               /**< nonlinear row which was changed */
1884 	   )
1885 	{  /*lint --e{715}*/
1886 	   assert(nlp != NULL);
1887 	   assert(nlrow != NULL);
1888 	   assert(!nlp->indiving);
1889 	   assert(nlrow->nlpindex >= 0);
1890 	
1891 	   /* nlrow is a row in the NLP, so changes effect feasibility */
1892 	   /* if we have a feasible NLP solution and it satisfies the modified row, then it is still feasible
1893 	    * if the NLP was globally or locally infeasible or unbounded, then this may not be the case anymore
1894 	    */
1895 	   if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1896 	   {
1897 	      /* TODO bring this back? then everything that may call nlpRowChanged will need to pass on blkmem, primal, tree as well
1898 	      SCIP_Real feasibility;
1899 	      SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1900 	      if( !SCIPsetIsFeasNegative(set, feasibility) )
1901 	         nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
1902 	      else */
1903 	      nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
1904 	   }
1905 	   else
1906 	   {
1907 	      nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1908 	   }
1909 	
1910 	   return SCIP_OKAY;
1911 	}
1912 	
1913 	/** adds a set of nonlinear rows to the NLP and captures them */
1914 	static
1915 	SCIP_RETCODE nlpAddNlRows(
1916 	   SCIP_NLP*             nlp,                /**< NLP data */
1917 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1918 	   SCIP_SET*             set,                /**< global SCIP settings */
1919 	   SCIP_STAT*            stat,               /**< problem statistics data */
1920 	   int                   nnlrows,            /**< number of nonlinear rows to add */
1921 	   SCIP_NLROW**          nlrows              /**< nonlinear rows to add */
1922 	   )
1923 	{
1924 	#ifndef NDEBUG
1925 	   int i;
1926 	#endif
1927 	   int j;
1928 	   SCIP_NLROW* nlrow;
1929 	
1930 	   assert(nlp    != NULL);
1931 	   assert(blkmem != NULL);
1932 	   assert(set    != NULL);
1933 	   assert(nlrows != NULL || nnlrows == 0);
1934 	   assert(!nlp->indiving);
1935 	
1936 	   SCIP_CALL( SCIPnlpEnsureNlRowsSize(nlp, blkmem, set, nlp->nnlrows + nnlrows) );
1937 	
1938 	   for( j = 0; j < nnlrows; ++j )
1939 	   {
1940 	      nlrow = nlrows[j];  /*lint !e613*/
1941 	
1942 	      /* assert that row is not in NLP (or even NLPI) yet */
1943 	      assert(nlrow->nlpindex == -1);
1944 	      assert(nlrow->nlpiindex == -1);
1945 	
1946 	      /* make sure there are only active variables in row */
1947 	      SCIP_CALL( SCIPnlrowSimplify(nlrow, blkmem, set, stat, nlp) );
1948 	
1949 	#ifndef NDEBUG
1950 	      /* assert that variables of row are in NLP */
1951 	      for( i = 0; i < nlrow->nlinvars; ++i )
1952 	         assert(SCIPhashmapExists(nlp->varhash, nlrow->linvars[i]));
1953 	
1954 	      if( nlrow->expr != NULL )
1955 	      {
1956 	         SCIP_EXPRITER* it;
1957 	         SCIP_EXPR* expr;
1958 	
1959 	         SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
1960 	         SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
1961 	         for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
1962 	            assert(!SCIPexprIsVar(set, expr) || SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
1963 	         SCIPexpriterFree(&it);
1964 	      }
1965 	#endif
1966 	
1967 	      /* add row to NLP and capture it */
1968 	      nlp->nlrows[nlp->nnlrows + j] = nlrow;
1969 	      nlrow->nlpindex = nlp->nnlrows + j;
1970 	
1971 	      SCIPnlrowCapture(nlrow);
1972 	
1973 	      /* if we have a feasible NLP solution and it satisfies the new solution, then it is still feasible
1974 	       * if the NLP was globally or locally infeasible, then it stays that way
1975 	       * if the NLP was unbounded, then this may not be the case anymore
1976 	       */
1977 	      if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1978 	      {
1979 	         /* TODO bring this back? then everything that may call nlpAddNlRows will need to pass on primal, tree as well
1980 	         SCIP_Real feasibility;
1981 	         SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1982 	         if( !SCIPsetIsFeasNegative(set, feasibility) )
1983 	            nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
1984 	         else
1985 	         */
1986 	         nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
1987 	      }
1988 	      else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
1989 	      {
1990 	         nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1991 	      }
1992 	   }
1993 	
1994 	   nlp->nnlrows += nnlrows;
1995 	   nlp->nunflushednlrowadd += nnlrows;
1996 	
1997 	   return SCIP_OKAY;
1998 	}
1999 	
2000 	/** moves a nonlinear row to a different place, and updates all corresponding data structures */
2001 	static
2002 	void nlpMoveNlrow(
2003 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2004 	   int                   oldpos,             /**< old position of nonlinear row */
2005 	   int                   newpos              /**< new position of nonlinear row */
2006 	   )
2007 	{
2008 	   assert(nlp != NULL);
2009 	   assert(0 <= oldpos && oldpos < nlp->nnlrows);
2010 	   assert(0 <= newpos && newpos < nlp->nnlrows);
2011 	   assert(nlp->nlrows[oldpos] != NULL);
2012 	
2013 	   if( oldpos == newpos )
2014 	      return;
2015 	
2016 	   nlp->nlrows[newpos] = nlp->nlrows[oldpos];
2017 	   nlp->nlrows[newpos]->nlpindex = newpos;
2018 	
2019 	   /* update nlpi to nlp row index mapping */
2020 	   if( nlp->nlrows[newpos]->nlpiindex >= 0 )
2021 	   {
2022 	      assert(nlp->nlrowmap_nlpi2nlp != NULL);
2023 	      assert(nlp->nlrows[newpos]->nlpiindex < nlp->sizenlrows_solver);
2024 	      nlp->nlrowmap_nlpi2nlp[nlp->nlrows[newpos]->nlpiindex] = newpos;
2025 	   }
2026 	}
2027 	
2028 	/** deletes nonlinear row with given position from NLP */
2029 	static
2030 	SCIP_RETCODE nlpDelNlRowPos(
2031 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2032 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2033 	   SCIP_SET*             set,                /**< global SCIP settings */
2034 	   SCIP_STAT*            stat,               /**< problem statistics data */
2035 	   int                   pos                 /**< position of nonlinear row that is to be removed */
2036 	   )
2037 	{
2038 	   SCIP_NLROW* nlrow;
2039 	
2040 	   assert(nlp != NULL);
2041 	   assert(blkmem != NULL);
2042 	   assert(set != NULL);
2043 	   assert(pos >= 0);
2044 	   assert(pos < nlp->nnlrows);
2045 	   assert(!nlp->indiving);
2046 	   assert(nlp->nlrows != NULL);
2047 	
2048 	   nlrow = nlp->nlrows[pos];
2049 	   assert(nlrow != NULL);
2050 	   assert(nlrow->nlpindex == pos);
2051 	
2052 	   /* if row is in NLPI, then mark that it has to be removed in the next flush
2053 	    * if row was not in NLPI yet, then we have one unflushed nlrow addition less */
2054 	   if( nlrow->nlpiindex >= 0 )
2055 	   {
2056 	      assert(nlrow->nlpiindex < nlp->nnlrows_solver);
2057 	      nlp->nlrowmap_nlpi2nlp[nlrow->nlpiindex] = -1;
2058 	      nlrow->nlpiindex = -1;
2059 	      ++nlp->nunflushednlrowdel;
2060 	   }
2061 	   else
2062 	   {
2063 	      assert(nlrow->nlpiindex == -1);
2064 	      --nlp->nunflushednlrowadd;
2065 	   }
2066 	
2067 	   /* move NLP row from the end to pos and mark nlrow to be not in NLP anymore */
2068 	   nlpMoveNlrow(nlp, nlp->nnlrows-1, pos);
2069 	   nlrow->nlpindex = -1;
2070 	
2071 	   /* forget about restriction */
2072 	   SCIP_CALL( SCIPnlrowRelease(&nlrow, blkmem, set, stat) );
2073 	   --nlp->nnlrows;
2074 	
2075 	   if( nlp->solstat < SCIP_NLPSOLSTAT_LOCOPT )
2076 	      nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2077 	   else if( nlp->solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
2078 	      nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2079 	
2080 	   return SCIP_OKAY; /*lint !e438*/
2081 	}
2082 	
2083 	/** updates bounds on a variable in the NLPI problem */
2084 	static
2085 	SCIP_RETCODE nlpUpdateVarBounds(
2086 	   SCIP_NLP*             nlp,                /**< NLP data */
2087 	   SCIP_SET*             set,                /**< global SCIP settings */
2088 	   SCIP_VAR*             var,                /**< variable which bounds have changed */
2089 	   SCIP_Bool             tightened           /**< whether the bound change was a bound tightening */
2090 	   )
2091 	{
2092 	   int pos;
2093 	   SCIP_Real lb;
2094 	   SCIP_Real ub;
2095 	
2096 	   assert(nlp != NULL);
2097 	   assert(var != NULL);
2098 	   assert(SCIPhashmapExists(nlp->varhash, var));
2099 	
2100 	   /* original variable bounds are ignored during diving
2101 	    * (all variable bounds are reset to their current value in exitDiving) */
2102 	   if( nlp->indiving )
2103 	      return SCIP_OKAY;
2104 	
2105 	   /* get position of variable in NLP */
2106 	   pos = SCIPhashmapGetImageInt(nlp->varhash, var);
2107 	
2108 	   /* if variable not in NLPI yet, nothing to do */
2109 	   if( nlp->varmap_nlp2nlpi[pos] == -1 )
2110 	      return SCIP_OKAY;
2111 	
2112 	   /* update bounds in NLPI problem */
2113 	   assert(nlp->solver != NULL);
2114 	   assert(nlp->problem != NULL);
2115 	
2116 	   pos = nlp->varmap_nlp2nlpi[pos];
2117 	   lb = SCIPvarGetLbLocal(var);
2118 	   ub = SCIPvarGetUbLocal(var);
2119 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
2120 	
2121 	   /* if we have a feasible NLP solution and it satisfies the new bounds, then it is still feasible
2122 	    * if the NLP was globally or locally infeasible and we tightened a bound, then it stays that way
2123 	    * if the NLP was unbounded and we tightened a bound, then this may not be the case anymore
2124 	    */
2125 	   if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2126 	   {
2127 	      if( !tightened ||
2128 	         ((SCIPsetIsInfinity(set, -lb) || SCIPsetIsFeasLE(set, lb, SCIPvarGetNLPSol(var))) &&
2129 	          (SCIPsetIsInfinity(set,  ub) || SCIPsetIsFeasGE(set, ub, SCIPvarGetNLPSol(var)))) )
2130 	         nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2131 	      else
2132 	         nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2133 	   }
2134 	   else if( !tightened || nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2135 	   {
2136 	      nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2137 	   }
2138 	
2139 	   return SCIP_OKAY;
2140 	}
2141 	
2142 	/** updates coefficient of a variable in the objective */
2143 	static
2144 	SCIP_RETCODE nlpUpdateObjCoef(
2145 	   SCIP_SET*             set,                /**< global SCIP settings */
2146 	   SCIP_NLP*             nlp,                /**< NLP data */
2147 	   SCIP_VAR*             var                 /**< variable which bounds have changed */
2148 	   )
2149 	{
2150 	   int pos;
2151 	   int objidx;
2152 	   SCIP_Real coef;
2153 	
2154 	   assert(nlp != NULL);
2155 	   assert(var != NULL);
2156 	   assert(SCIPhashmapExists(nlp->varhash, var));
2157 	
2158 	   /* if the objective in the NLPI is not up to date, then we do not need to do something here */
2159 	   if( !nlp->objflushed )
2160 	      return SCIP_OKAY;
2161 	
2162 	   /* original objective is ignored during diving
2163 	    * we just need to remember that at end of diving we have to flush the objective */
2164 	   if( nlp->indiving )
2165 	   {
2166 	      nlp->objflushed = FALSE;
2167 	      return SCIP_OKAY;
2168 	   }
2169 	
2170 	   /* get position of variable in NLP and objective coefficient */
2171 	   pos  = SCIPhashmapGetImageInt(nlp->varhash, var);
2172 	   assert(nlp->varmap_nlp2nlpi[pos] == -1 || nlp->solver != NULL);
2173 	
2174 	   /* actually we only need to remember flushing the objective if we also have an NLPI */
2175 	   if( nlp->solver == NULL )
2176 	      return SCIP_OKAY;
2177 	
2178 	   coef = SCIPvarGetObj(var);
2179 	
2180 	   /* if variable not in NLPI yet, then we only need to remember to update the objective after variable additions were flushed */
2181 	   if( nlp->varmap_nlp2nlpi[pos] == -1 && coef != 0.0 )
2182 	   {
2183 	      nlp->objflushed = FALSE;
2184 	
2185 	      return SCIP_OKAY;
2186 	   }
2187 	
2188 	   /* if we are here, then the objective in the NLPI is up to date,
2189 	    * we keep it this way by changing the coefficient of var in the NLPI problem objective */
2190 	   assert(nlp->solver != NULL);
2191 	   assert(nlp->problem != NULL);
2192 	
2193 	   pos = nlp->varmap_nlp2nlpi[pos];
2194 	   objidx = -1;
2195 	   SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
2196 	
2197 	   /* if we had a solution and it was locally (or globally) optimal, then now we can only be sure that it is still feasible */
2198 	   if( nlp->solstat < SCIP_NLPSOLSTAT_FEASIBLE )
2199 	      nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2200 	
2201 	   return SCIP_OKAY;
2202 	}
2203 	
2204 	/** adds new variables to the NLP */
2205 	static
2206 	SCIP_RETCODE nlpAddVars(
2207 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2208 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2209 	   SCIP_SET*             set,                /**< global SCIP settings */
2210 	   int                   nvars,              /**< number of variables to add */
2211 	   SCIP_VAR**            vars                /**< variable to add to NLP */
2212 	   )
2213 	{
2214 	   int i;
2215 	   SCIP_VAR* var;
2216 	
2217 	   assert(nlp    != NULL);
2218 	   assert(blkmem != NULL);
2219 	   assert(set    != NULL);
2220 	   assert(vars   != NULL || nvars == 0);
2221 	   assert(!nlp->indiving || nvars == 0);
2222 	
2223 	   if( nvars == 0 )
2224 	      return SCIP_OKAY;
2225 	
2226 	   SCIP_CALL( SCIPnlpEnsureVarsSize(nlp, blkmem, set, nlp->nvars + nvars) );
2227 	   assert(nlp->sizevars >= nlp->nvars + nvars);
2228 	
2229 	   for( i = 0; i < nvars; ++i )
2230 	   {
2231 	      var = vars[i];  /*lint !e613*/
2232 	
2233 	      assert(SCIPvarIsTransformed(var));
2234 	      assert(SCIPvarIsActive(var));
2235 	      assert(!SCIPhashmapExists(nlp->varhash, var));
2236 	
2237 	      SCIPvarCapture(var);
2238 	
2239 	      nlp->vars[nlp->nvars+i]            = var;
2240 	      nlp->varmap_nlp2nlpi[nlp->nvars+i] = -1;
2241 	      SCIP_CALL( SCIPhashmapInsertInt(nlp->varhash, var, nlp->nvars+i) );
2242 	
2243 	      nlp->varlbdualvals[nlp->nvars+i]   = 0.0;
2244 	      nlp->varubdualvals[nlp->nvars+i]   = 0.0;
2245 	
2246 	      /* update objective, if necessary (new variables have coefficient 0.0 anyway) */
2247 	      if( SCIPvarGetObj(var) != 0.0 )
2248 	      {
2249 	         SCIP_CALL( nlpUpdateObjCoef(set, nlp, var) );
2250 	      }
2251 	
2252 	      /* let's keep the previous initial guess and set it for the new variable to the best bound
2253 	       * (since there can be no row that uses this variable yet, this seems a good guess) */
2254 	      if( nlp->haveinitguess )
2255 	      {
2256 	         assert(nlp->initialguess != NULL);
2257 	
2258 	         nlp->initialguess[nlp->nvars+i] = SCIPvarGetBestBoundLocal(var);
2259 	      }
2260 	
2261 	      /* if we have a feasible NLP solution, then it remains feasible
2262 	       * but we have to update the objective function
2263 	       */
2264 	      if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2265 	      {
2266 	         SCIP_CALL( SCIPvarSetNLPSol(var, set, SCIPvarGetBestBoundLocal(var)) );
2267 	         nlp->primalsolobjval += SCIPvarGetObj(var) * SCIPvarGetBestBoundLocal(var);
2268 	         nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2269 	      }
2270 	
2271 	      /* catch events on variable */
2272 	      SCIP_CALL( SCIPvarCatchEvent(var, blkmem, set, \
2273 	            SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2274 	            nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, NULL) ); /* @todo should store event filter position in nlp? */
2275 	   }
2276 	
2277 	   nlp->nvars += nvars;
2278 	   nlp->nunflushedvaradd += nvars;
2279 	
2280 	   return SCIP_OKAY;
2281 	}
2282 	
2283 	/** moves a variable to a different place, and updates all corresponding data structures */
2284 	static
2285 	SCIP_RETCODE nlpMoveVar(
2286 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2287 	   int                   oldpos,             /**< old position of variable */
2288 	   int                   newpos              /**< new position of variable */
2289 	   )
2290 	{
2291 	   int nlpipos;
2292 	
2293 	   assert(nlp != NULL);
2294 	   assert(0 <= oldpos && oldpos < nlp->nvars);
2295 	   assert(0 <= newpos && newpos < nlp->nvars);
2296 	   assert(nlp->vars[oldpos] != NULL);
2297 	
2298 	   if( oldpos == newpos )
2299 	      return SCIP_OKAY;
2300 	
2301 	   SCIP_CALL( SCIPhashmapSetImageInt(nlp->varhash, nlp->vars[oldpos], newpos) );
2302 	   nlp->vars[newpos]            = nlp->vars[oldpos];
2303 	   nlp->varmap_nlp2nlpi[newpos] = nlp->varmap_nlp2nlpi[oldpos];
2304 	   nlp->varlbdualvals[newpos]   = nlp->varlbdualvals[oldpos];
2305 	   nlp->varubdualvals[newpos]   = nlp->varubdualvals[oldpos];
2306 	   if( nlp->initialguess != NULL )
2307 	      nlp->initialguess[newpos] = nlp->initialguess[oldpos];
2308 	
2309 	   nlpipos = nlp->varmap_nlp2nlpi[newpos];
2310 	   if( nlpipos > 0 )
2311 	      nlp->varmap_nlpi2nlp[nlpipos] = newpos;
2312 	
2313 	   return SCIP_OKAY;
2314 	}
2315 	
2316 	/** deletes variable with given position from NLP */
2317 	static
2318 	SCIP_RETCODE nlpDelVarPos(
2319 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2320 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2321 	   SCIP_SET*             set,                /**< global SCIP settings */
2322 	   SCIP_STAT*            stat,               /**< problem statistics data */
2323 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2324 	   SCIP_LP*              lp,                 /**< SCIP LP, needed if a column-variable is freed */
2325 	   int                   pos                 /**< position of nonlinear row that is to be removed */
2326 	   )
2327 	{
2328 	   SCIP_VAR* var;
2329 	#ifndef NDEBUG
2330 	   int i;
2331 	#endif
2332 	   int nlpipos;
2333 	
2334 	   assert(nlp    != NULL);
2335 	   assert(blkmem != NULL);
2336 	   assert(set    != NULL);
2337 	   assert(pos >= 0);
2338 	   assert(pos < nlp->nvars);
2339 	   assert(!nlp->indiving);
2340 	
2341 	   var = nlp->vars[pos];
2342 	   assert(var != NULL);
2343 	
2344 	#ifndef NDEBUG
2345 	   /* assert that variable is not used by any nonlinear row */
2346 	   for( i = 0; i < nlp->nnlrows; ++i )
2347 	   {
2348 	      int j;
2349 	      SCIP_NLROW* nlrow;
2350 	
2351 	      nlrow = nlp->nlrows[i];
2352 	      assert(nlrow != NULL);
2353 	
2354 	      /* use nlrowSearchLinearCoef only if already sorted, since otherwise we may change the solving process slightly */
2355 	      if( nlrow->linvarssorted )
2356 	         assert( nlrowSearchLinearCoef(nlrow, var) == -1 );
2357 	      else
2358 	         for( j = 0; j < nlrow->nlinvars; ++j )
2359 	            assert( nlrow->linvars[j] != var );
2360 	
2361 	      if( nlrow->expr != NULL )
2362 	      {
2363 	         SCIP_EXPRITER* it;
2364 	         SCIP_EXPR* expr;
2365 	         SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2366 	         SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
2367 	         for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2368 	            assert(!SCIPexprIsVar(set, expr) || SCIPgetVarExprVar(expr) != var);
2369 	         SCIPexpriterFree(&it);
2370 	      }
2371 	   }
2372 	#endif
2373 	
2374 	   /* if we had a feasible solution, then adjust objective function value
2375 	    * if NLP was unbounded before, then maybe it is not anymore */
2376 	   if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2377 	      nlp->primalsolobjval -= SCIPvarGetObj(var) * SCIPvarGetNLPSol(var);
2378 	   else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2379 	      nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2380 	
2381 	   /* if variable is in NLPI problem, mark that we have to remember to delete it there
2382 	    * if it was not in the NLPI yet, then we have one unflushed var addition less now */
2383 	   nlpipos = nlp->varmap_nlp2nlpi[pos];
2384 	   if( nlpipos >= 0 )
2385 	   {
2386 	      assert(nlpipos < nlp->nvars_solver);
2387 	
2388 	      nlp->varmap_nlpi2nlp[nlpipos] = -1;
2389 	      ++nlp->nunflushedvardel;
2390 	   }
2391 	   else
2392 	      --nlp->nunflushedvaradd;
2393 	
2394 	   /* drop events on variable */
2395 	   SCIP_CALL( SCIPvarDropEvent(var, blkmem, set, \
2396 	         SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2397 	         nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, -1) );
2398 	
2399 	   /* move variable from end to pos */
2400 	   SCIP_CALL( nlpMoveVar(nlp, nlp->nvars-1, pos) );
2401 	
2402 	   /* forget about variable */
2403 	   SCIP_CALL( SCIPhashmapRemove(nlp->varhash, var) );
2404 	   SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
2405 	   --nlp->nvars;
2406 	
2407 	   return SCIP_OKAY;
2408 	}
2409 	
2410 	/** notifies NLP that a variable was fixed, so it is removed from objective, all rows, and the NLP variables */
2411 	static
2412 	SCIP_RETCODE nlpRemoveFixedVar(
2413 	   SCIP_NLP*             nlp,                /**< NLP data */
2414 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2415 	   SCIP_SET*             set,                /**< global SCIP settings */
2416 	   SCIP_STAT*            stat,               /**< problem statistics data */
2417 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2418 	   SCIP_LP*              lp,                 /**< SCIP LP, needed to release variable */
2419 	   SCIP_VAR*             var                 /**< variable that has been fixed */
2420 	   )
2421 	{
2422 	   int i;
2423 	
2424 	   assert(nlp != NULL);
2425 	   assert(var != NULL);
2426 	   assert(!SCIPvarIsActive(var));
2427 	   assert(!nlp->indiving);
2428 	   assert(SCIPhashmapExists(nlp->varhash, var));
2429 	
2430 	   /* remove var from all rows */
2431 	   for( i = 0; i < nlp->nnlrows; ++i )
2432 	   {
2433 	      SCIP_CALL( nlrowRemoveFixedVar(nlp->nlrows[i], blkmem, set, stat, nlp, var) );
2434 	   }
2435 	
2436 	   /* remove variable from NLP */
2437 	   SCIP_CALL( SCIPnlpDelVar(nlp, blkmem, set, stat, eventqueue, lp, var) );
2438 	
2439 	   return SCIP_OKAY;
2440 	}
2441 	
2442 	/** creates arrays with NLPI variable indices of linear variables in a nonlinear row */
2443 	static
2444 	SCIP_RETCODE nlpSetupNlpiIndices(
2445 	   SCIP_NLP*             nlp,                /**< NLP data */
2446 	   SCIP_SET*             set,                /**< global SCIP settings */
2447 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
2448 	   int**                 linidxs             /**< buffer to store pointer to NLPI indices of linear variables */
2449 	   )
2450 	{
2451 	   int i;
2452 	   SCIP_VAR* var;
2453 	
2454 	   assert(nlp    != NULL);
2455 	   assert(set    != NULL);
2456 	   assert(nlrow  != NULL);
2457 	   assert(linidxs   != NULL);
2458 	
2459 	   /* get indices of variables in linear part of row */
2460 	   if( nlrow->nlinvars > 0 )
2461 	   {
2462 	      assert(nlrow->linvars  != NULL);
2463 	      assert(nlrow->lincoefs != NULL);
2464 	
2465 	      SCIP_CALL( SCIPsetAllocBufferArray(set, linidxs, nlrow->nlinvars) );
2466 	
2467 	      for( i = 0; i < nlrow->nlinvars; ++i )
2468 	      {
2469 	         var = nlrow->linvars[i];
2470 	         assert(var != NULL);
2471 	         assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
2472 	
2473 	         assert(SCIPhashmapExists(nlp->varhash, var));
2474 	         (*linidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
2475 	         assert((*linidxs)[i] >= 0);
2476 	      }
2477 	   }
2478 	   else
2479 	      *linidxs = NULL;
2480 	
2481 	   return SCIP_OKAY;
2482 	}
2483 	
2484 	/** ensures, that NLPI variables array of NLP can store at least num entries */
2485 	static
2486 	SCIP_RETCODE nlpEnsureVarsSolverSize(
2487 	   SCIP_NLP*             nlp,                /**< NLP data */
2488 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2489 	   SCIP_SET*             set,                /**< global SCIP settings */
2490 	   int                   num                 /**< minimum number of entries to store */
2491 	   )
2492 	{
2493 	   assert(nlp    != NULL);
2494 	   assert(blkmem != NULL);
2495 	   assert(set    != NULL);
2496 	   assert(nlp->nvars_solver <= nlp->sizevars_solver);
2497 	
2498 	   if( num > nlp->sizevars_solver )
2499 	   {
2500 	      int newsize;
2501 	
2502 	      newsize = SCIPsetCalcMemGrowSize(set, num);
2503 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlpi2nlp, nlp->sizevars_solver, newsize) );
2504 	
2505 	      nlp->sizevars_solver = newsize;
2506 	   }
2507 	   assert(num <= nlp->sizevars_solver);
2508 	
2509 	   return SCIP_OKAY;
2510 	}
2511 	
2512 	/** ensures, that NLPI nonlinear rows array of NLP can store at least num entries */
2513 	static
2514 	SCIP_RETCODE nlpEnsureNlRowsSolverSize(
2515 	   SCIP_NLP*             nlp,                /**< NLP data */
2516 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2517 	   SCIP_SET*             set,                /**< global SCIP settings */
2518 	   int                   num                 /**< minimum number of entries to store */
2519 	   )
2520 	{
2521 	   assert(nlp    != NULL);
2522 	   assert(blkmem != NULL);
2523 	   assert(set    != NULL);
2524 	   assert(nlp->nnlrows_solver <= nlp->sizenlrows_solver);
2525 	
2526 	   if( num > nlp->sizenlrows_solver )
2527 	   {
2528 	      int newsize;
2529 	
2530 	      newsize = SCIPsetCalcMemGrowSize(set, num);
2531 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrowmap_nlpi2nlp, nlp->sizenlrows_solver, newsize) );
2532 	
2533 	      nlp->sizenlrows_solver = newsize;
2534 	   }
2535 	   assert(num <= nlp->sizenlrows_solver);
2536 	
2537 	   return SCIP_OKAY;
2538 	}
2539 	
2540 	/** deletes rows from the NLPI problem that have been marked as to remove */
2541 	static
2542 	SCIP_RETCODE nlpFlushNlRowDeletions(
2543 	   SCIP_NLP*             nlp,                /**< NLP data */
2544 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2545 	   SCIP_SET*             set                 /**< global SCIP settings */
2546 	   )
2547 	{
2548 	   int         j;
2549 	   int         c;      /* counts the number of rows to delete */
2550 	   int*        rowset; /* marks which rows to delete and stores new indices */
2551 	   SCIP_NLROW* nlrow;
2552 	
2553 	   assert(nlp    != NULL);
2554 	   assert(blkmem != NULL);
2555 	   assert(set    != NULL);
2556 	   assert(nlp->nunflushednlrowdel >= 0);
2557 	   assert(!nlp->indiving);
2558 	
2559 	   if( nlp->nunflushednlrowdel == 0 )
2560 	   {
2561 	#ifndef NDEBUG
2562 	      /* check that there are really no pending removals of nonlinear rows */
2563 	      for( j = 0; j < nlp->nnlrows_solver; ++j )
2564 	         assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2565 	#endif
2566 	      return SCIP_OKAY;
2567 	   }
2568 	
2569 	   assert(nlp->solver != NULL);
2570 	   assert(nlp->problem != NULL);
2571 	
2572 	   /* create marker which rows have to be deleted */
2573 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &rowset, nlp->nnlrows_solver) );
2574 	   c = 0;
2575 	   for( j = 0; j < nlp->nnlrows_solver; ++j )
2576 	   {
2577 	      if( nlp->nlrowmap_nlpi2nlp[j] == -1 )
2578 	      {
2579 	         rowset[j] = 1;
2580 	         ++c;
2581 	      }
2582 	      else
2583 	         rowset[j] = 0;
2584 	   }
2585 	   assert(c == nlp->nunflushednlrowdel);
2586 	
2587 	   /* remove rows from NLPI problem */
2588 	   SCIP_CALL( SCIPnlpiDelConsSet(set, nlp->solver, nlp->problem, rowset, nlp->nnlrows_solver) );
2589 	
2590 	   /* update NLPI row indices */
2591 	   for( j = 0; j < nlp->nnlrows_solver; ++j )
2592 	   {
2593 	      assert(rowset[j] <= j); /* we assume that the NLP solver did not move a row behind its previous position!! */
2594 	      if( rowset[j] < 0 )
2595 	      {
2596 	         /* assert that row was marked as deleted */
2597 	         assert(nlp->nlrowmap_nlpi2nlp[j] == -1);
2598 	      }
2599 	      else if( rowset[j] < j )
2600 	      {
2601 	         /* nlrow at position j moved (forward) to position rowset[j] */
2602 	         assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2603 	         assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2604 	
2605 	         nlrow = nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]];
2606 	         assert(nlrow->nlpiindex == j);
2607 	
2608 	         /* there should be no row at the new position already */
2609 	         assert(nlp->nlrowmap_nlpi2nlp[rowset[j]] == -1);
2610 	
2611 	         nlrow->nlpiindex = rowset[j];
2612 	         nlp->nlrowmap_nlpi2nlp[rowset[j]] = nlrow->nlpindex;
2613 	      }
2614 	      else
2615 	      {
2616 	         /* row j stays at position j */
2617 	         assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2618 	         assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2619 	         assert(nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]->nlpiindex == j);
2620 	      }
2621 	   }
2622 	   nlp->nnlrows_solver -= c;
2623 	   nlp->nunflushednlrowdel = 0;
2624 	
2625 	   /* cleanup */
2626 	   SCIPsetFreeBufferArray(set, &rowset);
2627 	
2628 	   return SCIP_OKAY;
2629 	}
2630 	
2631 	/** deletes variables from the NLPI problem that have been marked as to remove
2632 	 *
2633 	 * assumes that there are no pending row deletions (nlpFlushNlRowDeletions() should be called first)
2634 	 */
2635 	static
2636 	SCIP_RETCODE nlpFlushVarDeletions(
2637 	   SCIP_NLP*             nlp,                /**< NLP data */
2638 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2639 	   SCIP_SET*             set                 /**< global SCIP settings */
2640 	   )
2641 	{
2642 	   int  i;
2643 	   int  c;      /* counter on number of variables to remove in solver */
2644 	   int* colset; /* marks which variables to delete and stores new indices */
2645 	
2646 	   assert(nlp    != NULL);
2647 	   assert(blkmem != NULL);
2648 	   assert(set    != NULL);
2649 	   assert(nlp->nunflushedvardel >= 0);
2650 	   assert(nlp->nunflushednlrowdel == 0);
2651 	   assert(!nlp->indiving);
2652 	
2653 	   if( nlp->nunflushedvardel == 0 )
2654 	   {
2655 	#ifndef NDEBUG
2656 	      /* check that there are really no pending removals of variables */
2657 	      for( i = 0; i < nlp->nvars_solver; ++i )
2658 	         assert(nlp->varmap_nlpi2nlp[i] >= 0);
2659 	#endif
2660 	      return SCIP_OKAY;
2661 	   }
2662 	
2663 	   assert(nlp->solver != NULL);
2664 	   assert(nlp->problem != NULL);
2665 	
2666 	   /* create marker which variables have to be deleted */
2667 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &colset, nlp->nvars_solver) );
2668 	   c = 0;
2669 	   for( i = 0; i < nlp->nvars_solver; ++i )
2670 	   {
2671 	      if( nlp->varmap_nlpi2nlp[i] == -1 )
2672 	      {
2673 	         colset[i] = 1;
2674 	         ++c;
2675 	      }
2676 	      else
2677 	         colset[i] = 0;
2678 	   }
2679 	   assert(c == nlp->nunflushedvardel);
2680 	
2681 	   /* delete variables from NLPI problem */
2682 	   SCIP_CALL( SCIPnlpiDelVarSet(set, nlp->solver, nlp->problem, colset, nlp->nvars_solver) );
2683 	
2684 	   /* update NLPI variable indices */
2685 	   for( i = 0; i < nlp->nvars_solver; ++i )
2686 	   {
2687 	      assert(colset[i] <= i); /* we assume that the NLP solver did not move a variable behind its previous position!! */
2688 	      if( colset[i] < 0 )
2689 	      {
2690 	         /* assert that variable was marked as deleted */
2691 	         assert(nlp->varmap_nlpi2nlp[i] == -1);
2692 	      }
2693 	      else if( colset[i] < i)
2694 	      {
2695 	         /* variable at position i moved (forward) to position colset[i] */
2696 	         int varpos;
2697 	
2698 	         varpos = nlp->varmap_nlpi2nlp[i]; /* position of variable i in NLP */
2699 	         assert(varpos >= 0);
2700 	         assert(varpos < nlp->nvars);
2701 	         assert(nlp->varmap_nlp2nlpi[varpos] == i);
2702 	
2703 	         /* there should be no variable at the new position already */
2704 	         assert(nlp->varmap_nlpi2nlp[colset[i]] == -1);
2705 	
2706 	         nlp->varmap_nlp2nlpi[varpos] = colset[i];
2707 	         nlp->varmap_nlpi2nlp[colset[i]] = varpos;
2708 	      }
2709 	      else
2710 	      {
2711 	         /* variable i stays at position i */
2712 	         assert(nlp->varmap_nlpi2nlp[i] >= 0);
2713 	         assert(nlp->varmap_nlpi2nlp[i] < nlp->nvars);
2714 	         assert(nlp->varmap_nlp2nlpi[nlp->varmap_nlpi2nlp[i]] == i);
2715 	      }
2716 	   }
2717 	
2718 	   nlp->nvars_solver -= c;
2719 	   nlp->nunflushedvardel = 0;
2720 	
2721 	   /* cleanup */
2722 	   SCIPsetFreeBufferArray(set, &colset);
2723 	
2724 	   return SCIP_OKAY;
2725 	}
2726 	
2727 	/** adds nonlinear rows to NLPI problem that have been added to NLP before
2728 	 *
2729 	 * assumes that there are no pending variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2730 	 */
2731 	static
2732 	SCIP_RETCODE nlpFlushNlRowAdditions(
2733 	   SCIP_NLP*             nlp,                /**< NLP data */
2734 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2735 	   SCIP_SET*             set,                /**< global SCIP settings */
2736 	   SCIP_STAT*            stat                /**< problem statistics */
2737 	   )
2738 	{
2739 	   int c, i;
2740 	   SCIP_NLROW* nlrow;
2741 	   SCIP_Real*  lhss;
2742 	   SCIP_Real*  rhss;
2743 	   int*        nlinvars;
2744 	   int**       linidxs;
2745 	   SCIP_Real** lincoefs;
2746 	   SCIP_EXPR** exprs;
2747 	   const char** names;
2748 	
2749 	   assert(nlp    != NULL);
2750 	   assert(blkmem != NULL);
2751 	   assert(set    != NULL);
2752 	   assert(nlp->nunflushednlrowadd >= 0);
2753 	   assert(nlp->nunflushedvaradd == 0);
2754 	   assert(nlp->nunflushedvardel == 0);
2755 	   assert(!nlp->indiving);
2756 	
2757 	   if( nlp->nunflushednlrowadd == 0 )
2758 	   {
2759 	#ifndef NDEBUG
2760 	      /* check that there are really no pending additions of variables */
2761 	      for( i = 0; i < nlp->nnlrows; ++i )
2762 	         assert(nlp->nlrows[i]->nlpiindex >= 0);
2763 	#endif
2764 	      return SCIP_OKAY;
2765 	   }
2766 	
2767 	   assert(nlp->solver != NULL);
2768 	   assert(nlp->problem != NULL);
2769 	
2770 	   SCIP_CALL( nlpEnsureNlRowsSolverSize(nlp, blkmem, set, nlp->nnlrows_solver + nlp->nunflushednlrowadd) );
2771 	
2772 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lhss,     nlp->nunflushednlrowadd) );
2773 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &rhss,     nlp->nunflushednlrowadd) );
2774 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinvars, nlp->nunflushednlrowadd) );
2775 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &linidxs,  nlp->nunflushednlrowadd) );
2776 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nunflushednlrowadd) );
2777 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &exprs,    nlp->nunflushednlrowadd) );
2778 	#if ADDNAMESTONLPI
2779 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &names,    nlp->nunflushednlrowadd) );
2780 	#else
2781 	   names = NULL;
2782 	#endif
2783 	
2784 	   c = 0;
2785 	   for( i = 0; i < nlp->nnlrows; ++i )
2786 	   {
2787 	      nlrow = nlp->nlrows[i];
2788 	      assert(nlrow != NULL);
2789 	
2790 	      /* skip nonlinear rows already in NLPI problem */
2791 	      if( nlrow->nlpiindex >= 0 )
2792 	         continue;
2793 	      assert(c < nlp->nunflushednlrowadd);
2794 	
2795 	      /* get indices in NLPI */
2796 	      SCIP_CALL( nlpSetupNlpiIndices(nlp, set, nlrow, &linidxs[c]) );
2797 	      assert(linidxs[c] != NULL || nlrow->nlinvars == 0);
2798 	
2799 	      nlp->nlrowmap_nlpi2nlp[nlp->nnlrows_solver+c] = i;
2800 	      nlrow->nlpiindex = nlp->nnlrows_solver+c;
2801 	
2802 	      lhss[c] = nlrow->lhs;
2803 	      rhss[c] = nlrow->rhs;
2804 	      if( nlrow->constant != 0.0 )
2805 	      {
2806 	         if( !SCIPsetIsInfinity(set, -nlrow->lhs) )
2807 	            lhss[c] -= nlrow->constant;
2808 	         if( !SCIPsetIsInfinity(set,  nlrow->rhs) )
2809 	            rhss[c] -= nlrow->constant;
2810 	      }
2811 	      if( rhss[c] < lhss[c] )
2812 	      {
2813 	         assert(SCIPsetIsEQ(set, lhss[c], rhss[c]));
2814 	         rhss[c] = lhss[c];
2815 	      }
2816 	
2817 	      nlinvars[c] = nlrow->nlinvars;
2818 	      lincoefs[c] = nlrow->lincoefs;
2819 	
2820 	      if( nlrow->expr != NULL )
2821 	      {
2822 	         /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */
2823 	         SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &exprs[c], mapvar2varidx, (void*)nlp, NULL, NULL) );
2824 	      }
2825 	      else
2826 	         exprs[c] = NULL;
2827 	
2828 	#if ADDNAMESTONLPI
2829 	      names[c]      = nlrow->name;
2830 	#endif
2831 	
2832 	      ++c;
2833 	
2834 	#ifdef NDEBUG
2835 	      /* have c vars to add already, there can be no more */
2836 	      if( c == nlp->nunflushednlrowadd )
2837 	         break;
2838 	#endif
2839 	   }
2840 	   assert(c == nlp->nunflushednlrowadd);
2841 	
2842 	   nlp->nnlrows_solver += c;
2843 	
2844 	   SCIP_CALL( SCIPnlpiAddConstraints(set, nlp->solver, nlp->problem, c, lhss, rhss,
2845 	         nlinvars, linidxs, lincoefs,
2846 	         exprs,
2847 	         names) );
2848 	
2849 	   for( c = nlp->nunflushednlrowadd - 1; c >= 0 ; --c )
2850 	   {
2851 	      if( linidxs[c] != NULL )
2852 	         SCIPsetFreeBufferArray(set, &linidxs[c]);
2853 	      if( exprs[c] != NULL )
2854 	      {
2855 	         SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &exprs[c]) );
2856 	      }
2857 	   }
2858 	
2859 	#if ADDNAMESTONLPI
2860 	   SCIPsetFreeBufferArray(set, &names);
2861 	#endif
2862 	   SCIPsetFreeBufferArray(set, &exprs);
2863 	   SCIPsetFreeBufferArray(set, &lincoefs);
2864 	   SCIPsetFreeBufferArray(set, &linidxs);
2865 	   SCIPsetFreeBufferArray(set, &nlinvars);
2866 	   SCIPsetFreeBufferArray(set, &rhss);
2867 	   SCIPsetFreeBufferArray(set, &lhss);
2868 	
2869 	   nlp->nunflushednlrowadd = 0;
2870 	
2871 	   return SCIP_OKAY;
2872 	}
2873 	
2874 	
2875 	/** adds variables to NLPI problem that have been added to NLP before
2876 	 *
2877 	 * may set nlp->objflushed to FALSE if a variable with nonzero objective coefficient is added to the NLPI problem
2878 	 */
2879 	static
2880 	SCIP_RETCODE nlpFlushVarAdditions(
2881 	   SCIP_NLP*             nlp,                /**< NLP data */
2882 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2883 	   SCIP_SET*             set                 /**< global SCIP settings */
2884 	   )
2885 	{
2886 	   int i, c;
2887 	   SCIP_Real*  lbs;
2888 	   SCIP_Real*  ubs;
2889 	   const char** names;
2890 	
2891 	   assert(nlp    != NULL);
2892 	   assert(blkmem != NULL);
2893 	   assert(set    != NULL);
2894 	   assert(nlp->nunflushedvaradd >= 0);
2895 	   assert(!nlp->indiving);
2896 	
2897 	   if( nlp->nunflushedvaradd == 0 )
2898 	   {
2899 	#ifndef NDEBUG
2900 	      /* check that there are really no pending additions of variables */
2901 	      for( i = 0; i < nlp->nvars; ++i )
2902 	         assert(nlp->varmap_nlp2nlpi[i] >= 0);
2903 	#endif
2904 	      return SCIP_OKAY;
2905 	   }
2906 	
2907 	   assert(nlp->solver != NULL);
2908 	   assert(nlp->problem != NULL);
2909 	
2910 	   SCIP_CALL( nlpEnsureVarsSolverSize(nlp, blkmem, set, nlp->nvars_solver + nlp->nunflushedvaradd) );
2911 	
2912 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lbs,   nlp->nunflushedvaradd) );
2913 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &ubs,   nlp->nunflushedvaradd) );
2914 	#if ADDNAMESTONLPI
2915 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushedvaradd) );
2916 	#else
2917 	   names = NULL;
2918 	#endif
2919 	
2920 	   c = 0;
2921 	   for( i = 0; i < nlp->nvars; ++i )
2922 	   {
2923 	      /* skip variables already in NLPI problem */
2924 	      if( nlp->varmap_nlp2nlpi[i] >= 0 )
2925 	         continue;
2926 	      assert(c < nlp->nunflushedvaradd);
2927 	
2928 	      nlp->varmap_nlpi2nlp[nlp->nvars_solver+c] = i;
2929 	      nlp->varmap_nlp2nlpi[i] = nlp->nvars_solver+c;
2930 	      lbs[c]   = SCIPvarGetLbLocal(nlp->vars[i]);
2931 	      ubs[c]   = SCIPvarGetUbLocal(nlp->vars[i]);
2932 	#if ADDNAMESTONLPI
2933 	      names[c] = SCIPvarGetName(nlp->vars[i]);
2934 	#endif
2935 	      ++c;
2936 	
2937 	      /* if the new variable has a nonzero objective coefficient, then the objective need to be updated */
2938 	      if( !SCIPsetIsZero(set, SCIPvarGetObj(nlp->vars[i])) )
2939 	         nlp->objflushed = FALSE;
2940 	
2941 	#ifdef NDEBUG
2942 	      /* have c vars to add already, there can be no more */
2943 	      if( c == nlp->nunflushedvaradd )
2944 	         break;
2945 	#endif
2946 	   }
2947 	   assert(c == nlp->nunflushedvaradd);
2948 	
2949 	   nlp->nvars_solver += c;
2950 	
2951 	   SCIP_CALL( SCIPnlpiAddVars(set, nlp->solver, nlp->problem, c, lbs, ubs, names) );
2952 	
2953 	#if ADDNAMESTONLPI
2954 	   SCIPsetFreeBufferArray(set, &names);
2955 	#endif
2956 	   SCIPsetFreeBufferArray(set, &ubs);
2957 	   SCIPsetFreeBufferArray(set, &lbs);
2958 	
2959 	   nlp->nunflushedvaradd = 0;
2960 	
2961 	   return SCIP_OKAY;
2962 	}
2963 	
2964 	/** updates the objective in the NLPI problem, if necessary
2965 	 *
2966 	 * assumes that there are no unflushed variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2967 	 */
2968 	static
2969 	SCIP_RETCODE nlpFlushObjective(
2970 	   SCIP_NLP*             nlp,                /**< NLP data */
2971 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2972 	   SCIP_SET*             set                 /**< global SCIP settings */
2973 	   )
2974 	{
2975 	   int*       linindices;
2976 	   SCIP_Real* lincoefs;
2977 	   SCIP_Real  coef;
2978 	   int        i;
2979 	   int        nz;
2980 	
2981 	   assert(nlp    != NULL);
2982 	   assert(blkmem != NULL);
2983 	   assert(set    != NULL);
2984 	   assert(nlp->nunflushedvaradd == 0);
2985 	   assert(nlp->nunflushedvardel == 0);
2986 	   assert(!nlp->indiving);
2987 	
2988 	   if( nlp->objflushed )
2989 	      return SCIP_OKAY;
2990 	
2991 	   assert(nlp->solver != NULL);
2992 	   assert(nlp->problem != NULL);
2993 	
2994 	   /* assemble coefficients */
2995 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &linindices, nlp->nvars_solver) );
2996 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs,   nlp->nvars_solver) );
2997 	
2998 	   nz = 0;
2999 	   for( i = 0; i < nlp->nvars_solver; ++i )
3000 	   {
3001 	      assert(nlp->varmap_nlpi2nlp[i] >= 0); /* there should be no variable deletions pending */
3002 	
3003 	      coef = SCIPvarGetObj(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
3004 	      if( SCIPsetIsZero(set, coef) )
3005 	         continue;
3006 	
3007 	      linindices[nz] = i;
3008 	      lincoefs[nz]   = coef;
3009 	      ++nz;
3010 	   }
3011 	
3012 	   SCIP_CALL( SCIPnlpiSetObjective(set, nlp->solver, nlp->problem,
3013 	         nz, linindices, lincoefs,
3014 	         NULL,
3015 	         0.0) );
3016 	
3017 	   SCIPsetFreeBufferArray(set, &lincoefs);
3018 	   SCIPsetFreeBufferArray(set, &linindices);
3019 	
3020 	   nlp->objflushed = TRUE;
3021 	
3022 	   return SCIP_OKAY;
3023 	}
3024 	
3025 	/** solves the NLP (or diving NLP), assuming it has been flushed already */
3026 	static
3027 	SCIP_RETCODE nlpSolve(
3028 	   SCIP_NLP*             nlp,                /**< NLP data */
3029 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3030 	   SCIP_SET*             set,                /**< global SCIP settings */
3031 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
3032 	   SCIP_STAT*            stat,               /**< problem statistics */
3033 	   SCIP_PRIMAL*          primal,             /**< primal data */
3034 	   SCIP_TREE*            tree,               /**< branch and bound tree */
3035 	   SCIP_NLPPARAM*        nlpparam            /**< NLP solve parameters */
3036 	   )
3037 	{
3038 	   int i;
3039 	
3040 	   assert(nlp    != NULL);
3041 	   assert(blkmem != NULL);
3042 	   assert(set    != NULL);
3043 	   assert(stat   != NULL);
3044 	
3045 	   if( nlp->solver == NULL )
3046 	   {
3047 	      SCIPmessagePrintWarning(messagehdlr, "Attempted to solve NLP, but no solver available.\n");
3048 	
3049 	      nlp->solstat  = SCIP_NLPSOLSTAT_UNKNOWN;
3050 	      nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3051 	
3052 	      return SCIP_OKAY;
3053 	   }
3054 	
3055 	   assert(nlp->solver != NULL);
3056 	   assert(nlp->problem != NULL);
3057 	
3058 	   /* set initial guess, if available and warmstart hasn't been enabled
3059 	    * when using the NLP, passing a dual solution with the initguess is not available at the moment (TODO),
3060 	    * so a warmstart has to start from the last solution stored in the NLPI
3061 	    */
3062 	   if( nlp->haveinitguess && !nlpparam->warmstart )
3063 	   {
3064 	      /* @todo should we not set it if we had set it already? (initguessflushed...) */
3065 	      SCIP_Real* initialguess_solver;
3066 	      int nlpidx;
3067 	
3068 	      assert(nlp->initialguess != NULL);
3069 	
3070 	      SCIP_CALL( SCIPsetAllocBufferArray(set, &initialguess_solver, nlp->nvars_solver) );
3071 	
3072 	      for( i = 0; i < nlp->nvars_solver; ++i )
3073 	      {
3074 	         nlpidx = nlp->varmap_nlpi2nlp[i];
3075 	         assert(nlpidx >= 0);
3076 	         assert(nlpidx < nlp->nvars);
3077 	
3078 	         initialguess_solver[i] = nlp->initialguess[nlpidx];
3079 	      }
3080 	      SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, initialguess_solver, NULL, NULL, NULL) );
3081 	
3082 	      SCIPsetFreeBufferArray(set, &initialguess_solver);
3083 	   }
3084 	
3085 	   /* let NLP solver do his work */
3086 	   SCIPclockStart(stat->nlpsoltime, set);
3087 	
3088 	   SCIP_CALL( SCIPnlpiSolve(set, stat, nlp->solver, nlp->problem, nlpparam) );
3089 	
3090 	   SCIPclockStop(stat->nlpsoltime, set);
3091 	   ++stat->nnlps;
3092 	
3093 	   nlp->termstat = SCIPnlpiGetTermstat(set, nlp->solver, nlp->problem);
3094 	   nlp->solstat  = SCIPnlpiGetSolstat(set, nlp->solver, nlp->problem);
3095 	   switch( nlp->solstat )
3096 	   {
3097 	   case SCIP_NLPSOLSTAT_GLOBOPT:
3098 	   case SCIP_NLPSOLSTAT_LOCOPT:
3099 	   case SCIP_NLPSOLSTAT_FEASIBLE:
3100 	   case SCIP_NLPSOLSTAT_LOCINFEASIBLE:
3101 	   {
3102 	      SCIP_Real* primalvals;
3103 	      SCIP_Real* nlrowdualvals;
3104 	      SCIP_Real* varlbdualvals;
3105 	      SCIP_Real* varubdualvals;
3106 	
3107 	      primalvals    = NULL;
3108 	      nlrowdualvals = NULL;
3109 	      varlbdualvals = NULL;
3110 	      varubdualvals = NULL;
3111 	
3112 	      /* get NLP solution */
3113 	      SCIP_CALL( SCIPnlpiGetSolution(set, nlp->solver, nlp->problem, &primalvals, &nlrowdualvals, &varlbdualvals, &varubdualvals, NULL) );
3114 	      assert(primalvals != NULL || nlp->nvars == 0);
3115 	      assert((varlbdualvals != NULL) == (varubdualvals != NULL)); /* if there are duals for one bound, then there should also be duals for the other bound */
3116 	
3117 	      /* store solution primal values in variable and evaluate objective function */
3118 	      if( nlp->indiving && nlp->divingobj != NULL )
3119 	      {
3120 	         for( i = 0; i < nlp->nvars; ++i )
3121 	         {
3122 	            SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, primalvals[nlp->varmap_nlp2nlpi[i]]) );  /*lint !e613 */
3123 	         }
3124 	
3125 	         /* evaluate modified diving objective */
3126 	         SCIP_CALL( SCIPnlrowGetNLPActivity(nlp->divingobj, blkmem, set, stat, primal, tree, nlp, &nlp->primalsolobjval) );
3127 	      }
3128 	      else
3129 	      {
3130 	         /* evaluate SCIP objective function */
3131 	         nlp->primalsolobjval = 0.0;
3132 	         for( i = 0; i < nlp->nvars; ++i )
3133 	         {
3134 	            SCIP_Real solval = primalvals[nlp->varmap_nlp2nlpi[i]];  /*lint !e613 */
3135 	
3136 	            /* do a quick assert that variable bounds are satisfied, if feasibility is claimed */
3137 	            assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(nlp->vars[i])) ||
3138 	               SCIPsetIsFeasGE(set, solval, SCIPvarGetLbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3139 	            assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(nlp->vars[i])) ||
3140 	               SCIPsetIsFeasLE(set, solval, SCIPvarGetUbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3141 	
3142 	            SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, solval) );  /*lint !e613 */
3143 	            nlp->primalsolobjval += SCIPvarGetObj(nlp->vars[i]) * solval;  /*lint !e613 */
3144 	         }
3145 	      }
3146 	
3147 	      /* store solution dual values in nlrows and variables */
3148 	      for( i = 0; i < nlp->nnlrows; ++i )
3149 	      {
3150 	         assert(nlp->nlrows[i]->nlpiindex >= 0); /* NLP was flushed before solve, so all nlrows should be in there */
3151 	
3152 	         nlp->nlrows[i]->dualsol = nlrowdualvals != NULL ? nlrowdualvals[nlp->nlrows[i]->nlpiindex] : 0.0;
3153 	
3154 	         /* SCIPsetDebugMsg(set, "dual of nlrow <%s> = %g\n", nlp->nlrows[i]->name, nlp->nlrows[i]->dualsol); */
3155 	      }
3156 	      assert(nlp->varlbdualvals != NULL || nlp->nvars == 0);
3157 	      assert(nlp->varubdualvals != NULL || nlp->nvars == 0);
3158 	      if( varlbdualvals != NULL )
3159 	      {
3160 	         for( i = 0; i < nlp->nvars; ++i )
3161 	         {
3162 	            assert(nlp->varmap_nlp2nlpi[i] >= 0); /* NLP was flushed before solve, so all vars should be in there */
3163 	
3164 	            nlp->varlbdualvals[i] = varlbdualvals[nlp->varmap_nlp2nlpi[i]];
3165 	            nlp->varubdualvals[i] = varubdualvals[nlp->varmap_nlp2nlpi[i]];
3166 	
3167 	            /* SCIPsetDebugMsg(set, "duals of var <%s> = %g %g\n", SCIPvarGetName(nlp->vars[i]), nlp->varlbdualvals[i], nlp->varubdualvals[i]); */
3168 	         }
3169 	      }
3170 	      else if( nlp->nvars > 0 )
3171 	      {
3172 	         BMSclearMemoryArray(nlp->varlbdualvals, nlp->nvars);
3173 	         BMSclearMemoryArray(nlp->varubdualvals, nlp->nvars);
3174 	      }
3175 	
3176 	      break;
3177 	   }
3178 	   default:
3179 	      nlp->primalsolobjval = SCIP_INVALID;
3180 	      break;
3181 	   } /*lint !e788*/
3182 	
3183 	   return SCIP_OKAY;
3184 	}
3185 	
3186 	/** assembles list of fractional variables in last NLP solution */
3187 	static
3188 	SCIP_RETCODE nlpCalcFracVars(
3189 	   SCIP_NLP*             nlp,                /**< NLP data */
3190 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3191 	   SCIP_SET*             set,                /**< global SCIP settings */
3192 	   SCIP_STAT*            stat                /**< problem statistics */
3193 	   )
3194 	{
3195 	   assert(nlp != NULL);
3196 	   assert(blkmem != NULL);
3197 	   assert(set != NULL);
3198 	   assert(stat != NULL);
3199 	   assert(nlp->validfracvars <= stat->nnlps);
3200 	   assert(SCIPnlpHasSolution(nlp));
3201 	
3202 	   SCIPsetDebugMsg(set, "calculating NLP fractional variables: validfracvars=%" SCIP_LONGINT_FORMAT ", nnlps=%" SCIP_LONGINT_FORMAT "\n", nlp->validfracvars, stat->nnlps);
3203 	
3204 	   if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
3205 	   {
3206 	      nlp->nfracvars     = 0;
3207 	      nlp->npriofracvars = 0;
3208 	      nlp->validfracvars = stat->nnlps;
3209 	
3210 	      SCIPsetDebugMsg(set, "NLP globally infeasible, unbounded, or worse -> no solution values -> no fractional variables\n");
3211 	      return SCIP_OKAY;
3212 	   }
3213 	
3214 	   /* check, if the current NLP fractional variables array is invalid */
3215 	   if( nlp->validfracvars < stat->nnlps )
3216 	   {
3217 	      SCIP_VAR* var;
3218 	      SCIP_Real primsol;
3219 	      SCIP_Real frac;
3220 	      int branchpriority;
3221 	      int insertpos;
3222 	      int maxpriority;
3223 	      int i;
3224 	
3225 	      SCIPsetDebugMsg(set, " -> recalculating NLP fractional variables\n");
3226 	
3227 	      if( nlp->fracvarssize == 0 )
3228 	      {
3229 	         assert(nlp->fracvars     == NULL);
3230 	         assert(nlp->fracvarssol  == NULL);
3231 	         assert(nlp->fracvarsfrac == NULL);
3232 	         nlp->fracvarssize = 5;
3233 	         SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvars,     nlp->fracvarssize) );
3234 	         SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarssol,  nlp->fracvarssize) );
3235 	         SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize) );
3236 	      }
3237 	
3238 	      maxpriority = INT_MIN;
3239 	      nlp->nfracvars = 0;
3240 	      nlp->npriofracvars = 0;
3241 	      for( i = 0; i < nlp->nvars; ++i )
3242 	      {
3243 	         var = nlp->vars[i];
3244 	         assert(var != NULL);
3245 	
3246 	         primsol = SCIPvarGetNLPSol(var);
3247 	         assert(primsol < SCIP_INVALID);
3248 	
3249 	         /* consider only binary and integer variables */
3250 	         if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER )
3251 	            continue;
3252 	
3253 	         /* ignore fixed variables (due to numerics, it is possible, that the NLP solution of a fixed integer variable
3254 	          * (with large fixed value) is fractional in terms of absolute feasibility measure)
3255 	          */
3256 	         if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
3257 	            continue;
3258 	
3259 	         /* check, if the LP solution value is fractional */
3260 	         frac = SCIPsetFeasFrac(set, primsol);
3261 	
3262 	         /* The fractionality should not be smaller than -feastol, however, if the primsol is large enough
3263 	          * and close to an integer, fixed precision floating point arithmetic might give us values slightly
3264 	          * smaller than -feastol. Originally, the "frac >= -feastol"-check was within SCIPsetIsFeasFracIntegral(),
3265 	          * however, we relaxed it to "frac >= -2*feastol" and have the stricter check here for small-enough primsols.
3266 	          */
3267 	         assert(SCIPsetIsGE(set, frac, -SCIPsetFeastol(set)) || (primsol > 1e14 * SCIPsetFeastol(set)));
3268 	
3269 	         if( SCIPsetIsFeasFracIntegral(set, frac) )
3270 	            continue;
3271 	
3272 	         /* ensure enough space in fracvars arrays */
3273 	         if( nlp->fracvarssize <= nlp->nfracvars )
3274 	         {
3275 	            int newsize;
3276 	
3277 	            newsize = SCIPsetCalcMemGrowSize(set, nlp->nfracvars + 1);
3278 	            SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvars,     nlp->fracvarssize, newsize) );
3279 	            SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarssol,  nlp->fracvarssize, newsize) );
3280 	            SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize, newsize) );
3281 	            nlp->fracvarssize = newsize;
3282 	         }
3283 	         assert(nlp->nfracvars < nlp->fracvarssize);
3284 	         assert(nlp->fracvars     != NULL);
3285 	         assert(nlp->fracvarssol  != NULL);
3286 	         assert(nlp->fracvarsfrac != NULL);
3287 	
3288 	         /* insert candidate in candidate list */
3289 	         branchpriority = SCIPvarGetBranchPriority(var);
3290 	         insertpos = nlp->nfracvars;
3291 	         nlp->nfracvars++;
3292 	         if( branchpriority > maxpriority )
3293 	         {
3294 	            /* candidate has higher priority than the current maximum:
3295 	             * move it to the front and declare it to be the single best candidate
3296 	             */
3297 	            if( insertpos != 0 )
3298 	            {
3299 	               nlp->fracvars[insertpos]     = nlp->fracvars[0];
3300 	               nlp->fracvarssol[insertpos]  = nlp->fracvarssol[0];
3301 	               nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[0];
3302 	               insertpos = 0;
3303 	            }
3304 	            nlp->npriofracvars = 1;
3305 	            maxpriority = branchpriority;
3306 	         }
3307 	         else if( branchpriority == maxpriority )
3308 	         {
3309 	            /* candidate has equal priority as the current maximum:
3310 	             * move away the first non-maximal priority candidate, move the current candidate to the correct
3311 	             * slot (binaries first) and increase the number of maximal priority candidates
3312 	             */
3313 	            if( insertpos != nlp->npriofracvars )
3314 	            {
3315 	               nlp->fracvars[insertpos]     = nlp->fracvars[nlp->npriofracvars];
3316 	               nlp->fracvarssol[insertpos]  = nlp->fracvarssol[nlp->npriofracvars];
3317 	               nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[nlp->npriofracvars];
3318 	               insertpos = nlp->npriofracvars;
3319 	            }
3320 	            ++nlp->npriofracvars;
3321 	         }
3322 	         nlp->fracvars[insertpos]     = var;
3323 	         nlp->fracvarssol[insertpos]  = primsol;
3324 	         nlp->fracvarsfrac[insertpos] = frac;
3325 	
3326 	         SCIPsetDebugMsg(set, " -> candidate %d: var=<%s>, sol=%g, frac=%g, prio=%d (max: %d) -> pos %d\n",
3327 	            nlp->nfracvars, SCIPvarGetName(var), primsol, frac, branchpriority, maxpriority, insertpos);
3328 	      }
3329 	
3330 	      nlp->validfracvars = stat->nnlps;
3331 	   }
3332 	   assert(0 <= nlp->npriofracvars);
3333 	   assert(nlp->npriofracvars <= nlp->nfracvars);
3334 	
3335 	   SCIPsetDebugMsg(set, " -> %d fractional variables (%d of maximal priority)\n", nlp->nfracvars, nlp->npriofracvars);
3336 	
3337 	   return SCIP_OKAY;
3338 	}
3339 	
3340 	/** event handling for variable events */
3341 	static
3342 	SCIP_DECL_EVENTEXEC(eventExecNlp)
3343 	{
3344 	   SCIP_EVENTTYPE etype;
3345 	   SCIP_VAR*      var;
3346 	
3347 	   assert(scip      != NULL);
3348 	   assert(eventhdlr != NULL);
3349 	   assert(event     != NULL);
3350 	   assert(eventdata != NULL);
3351 	
3352 	   assert((SCIP_NLP*)eventdata == scip->nlp);
3353 	
3354 	   etype = SCIPeventGetType(event);
3355 	   var   = SCIPeventGetVar(event);
3356 	
3357 	   if( SCIP_EVENTTYPE_VARADDED & etype )
3358 	   {
3359 	      SCIPdebugMessage("-> handling varadd event, variable <%s>\n", SCIPvarGetName(var) );
3360 	      SCIP_CALL( SCIPnlpAddVar(scip->nlp, SCIPblkmem(scip), scip->set, var) );
3361 	   }
3362 	   else if( SCIP_EVENTTYPE_VARDELETED & etype )
3363 	   {
3364 	      SCIPdebugMessage("-> handling vardel event, variable <%s>\n", SCIPvarGetName(var) );
3365 	      SCIP_CALL( SCIPnlpDelVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3366 	   }
3367 	   else if( SCIP_EVENTTYPE_VARFIXED & etype )
3368 	   {
3369 	      /* variable was fixed, aggregated, or multi-aggregated */
3370 	      /* TODO is this ever happening? that is, can we have changes in a variable status during solve? */
3371 	      SCIPdebugMessage("-> handling variable fixation event, variable <%s>\n", SCIPvarGetName(var) );
3372 	      SCIP_CALL( nlpRemoveFixedVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3373 	   }
3374 	   else if( SCIP_EVENTTYPE_BOUNDCHANGED & etype )
3375 	   {
3376 	      SCIPdebugMessage("-> handling bound changed event %" SCIP_EVENTTYPE_FORMAT ", variable <%s>\n", etype, SCIPvarGetName(var) );
3377 	      SCIP_CALL( nlpUpdateVarBounds(scip->nlp, scip->set, var, (SCIP_Bool)(SCIP_EVENTTYPE_BOUNDTIGHTENED & etype)) );
3378 	   }
3379 	   else if( SCIP_EVENTTYPE_OBJCHANGED & etype )
3380 	   {
3381 	      SCIPdebugMessage("-> handling objchg event, variable <%s>\n", SCIPvarGetName(var) );
3382 	      SCIP_CALL( nlpUpdateObjCoef(scip->set, scip->nlp, var) );
3383 	   }
3384 	   else
3385 	   {
3386 	      SCIPerrorMessage("unexpected event %" SCIP_EVENTTYPE_FORMAT " on variable <%s>\n", etype, SCIPvarGetName(var) );
3387 	      return SCIP_ERROR;
3388 	   }
3389 	
3390 	   return SCIP_OKAY;
3391 	}
3392 	
3393 	
3394 	/*
3395 	 * public NLP methods
3396 	 */
3397 	
3398 	/** includes event handler that is used by NLP */
3399 	SCIP_RETCODE SCIPnlpInclude(
3400 	   SCIP_SET*             set,                /**< global SCIP settings */
3401 	   BMS_BLKMEM*           blkmem              /**< block memory */
3402 	   )
3403 	{
3404 	   SCIP_EVENTHDLR* eventhdlr;
3405 	
3406 	   assert(set != NULL);
3407 	   assert(blkmem != NULL);
3408 	   assert(set->stage == SCIP_STAGE_INIT);
3409 	
3410 	   /* check whether event handler is already present */
3411 	   if( SCIPsetFindEventhdlr(set, EVENTHDLR_NAME) != NULL )
3412 	   {
3413 	      SCIPerrorMessage("event handler <" EVENTHDLR_NAME "> already included.\n");
3414 	      return SCIP_INVALIDDATA;
3415 	   }
3416 	
3417 	   SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC,
3418 	         NULL, NULL, NULL, NULL, NULL, NULL, NULL, eventExecNlp, NULL) );
3419 	   SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) );
3420 	
3421 	   return SCIP_OKAY;
3422 	} /*lint !e715*/
3423 	
3424 	/** construct a new empty NLP */
3425 	SCIP_RETCODE SCIPnlpCreate(
3426 	   SCIP_NLP**            nlp,                /**< NLP handler, call by reference */
3427 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3428 	   SCIP_SET*             set,                /**< global SCIP settings */
3429 	   SCIP_STAT*            stat,               /**< problem statistics */
3430 	   const char*           name,               /**< problem name */
3431 	   int                   nvars_estimate      /**< an estimate on the number of variables that may be added to the NLP later */
3432 	   )
3433 	{
3434 	   assert(nlp  != NULL);
3435 	   assert(blkmem != NULL);
3436 	   assert(set  != NULL);
3437 	   assert(stat != NULL);
3438 	   assert(name != NULL);
3439 	
3440 	   SCIP_ALLOC( BMSallocMemory(nlp) );
3441 	
3442 	   /* select NLP solver (if any available) and setup problem */
3443 	   if( set->nnlpis > 0 )
3444 	   {
3445 	      assert(set->nlp_solver != NULL);
3446 	      if( set->nlp_solver[0] == '\0' )
3447 	      { /* take solver with highest priority */
3448 	         assert(set->nlpis != NULL);
3449 	
3450 	         /* sort the NLPIs if necessary */
3451 	         if( !set->nlpissorted )
3452 	            SCIPsetSortNlpis(set);
3453 	
3454 	         (*nlp)->solver = set->nlpis[0];
3455 	      }
3456 	      else
3457 	      { /* find user specified NLP solver */
3458 	         (*nlp)->solver = SCIPsetFindNlpi(set, set->nlp_solver);
3459 	         if( (*nlp)->solver == NULL )
3460 	         {
3461 	            SCIPerrorMessage("Selected NLP solver <%s> not available.\n", set->nlp_solver);
3462 	            return SCIP_PLUGINNOTFOUND;
3463 	         }
3464 	      }
3465 	      assert((*nlp)->solver != NULL);
3466 	      SCIP_CALL( SCIPnlpiCreateProblem(set, (*nlp)->solver, &(*nlp)->problem, name) );
3467 	   }
3468 	   else
3469 	   {
3470 	      /* maybe someone wanna use the NLP just to collect nonlinearities, but is not necessarily interesting on solving
3471 	       * so we allow this and just continue */
3472 	      (*nlp)->solver = NULL;
3473 	      (*nlp)->problem = NULL;
3474 	   }
3475 	
3476 	   /* status */
3477 	   (*nlp)->nunflushedvaradd   = 0;
3478 	   (*nlp)->nunflushedvardel   = 0;
3479 	   (*nlp)->nunflushednlrowadd = 0;
3480 	   (*nlp)->nunflushednlrowdel = 0;
3481 	   (*nlp)->indiving   = FALSE;
3482 	
3483 	   /* variables in problem and NLPI problem */
3484 	   (*nlp)->nvars = 0;
3485 	   (*nlp)->sizevars = 0;
3486 	   (*nlp)->vars = NULL;
3487 	   SCIP_CALL( SCIPhashmapCreate(&(*nlp)->varhash, blkmem, nvars_estimate) );
3488 	
3489 	   (*nlp)->nvars_solver = 0;
3490 	   (*nlp)->sizevars_solver = 0;
3491 	   (*nlp)->varmap_nlp2nlpi = NULL;
3492 	   (*nlp)->varmap_nlpi2nlp = NULL;
3493 	
3494 	   /* nonlinear rows in problem and NLPI problem */
3495 	   (*nlp)->nnlrows = 0;
3496 	   (*nlp)->sizenlrows = 0;
3497 	   (*nlp)->nlrows = NULL;
3498 	
3499 	   (*nlp)->nnlrows_solver = 0;
3500 	   (*nlp)->sizenlrows_solver = 0;
3501 	   (*nlp)->nlrowmap_nlpi2nlp = NULL;
3502 	
3503 	   /* objective function */
3504 	   (*nlp)->objflushed = TRUE;
3505 	   (*nlp)->divingobj = NULL;
3506 	
3507 	   /* initial guess */
3508 	   (*nlp)->haveinitguess = FALSE;
3509 	   (*nlp)->initialguess = NULL;
3510 	
3511 	   /* solution of NLP */
3512 	   (*nlp)->primalsolobjval = SCIP_INVALID;
3513 	   (*nlp)->solstat         = SCIP_NLPSOLSTAT_UNKNOWN;
3514 	   (*nlp)->termstat        = SCIP_NLPTERMSTAT_OTHER;
3515 	   (*nlp)->varlbdualvals   = NULL;
3516 	   (*nlp)->varubdualvals   = NULL;
3517 	
3518 	   /* event handling: catch variable addition and deletion events */
3519 	   (*nlp)->eventhdlr = SCIPsetFindEventhdlr(set, EVENTHDLR_NAME);
3520 	   if( (*nlp)->eventhdlr == NULL )
3521 	   {
3522 	      SCIPerrorMessage("NLP eventhandler <" EVENTHDLR_NAME "> not found.\n");
3523 	      return SCIP_PLUGINNOTFOUND;
3524 	   }
3525 	   SCIP_CALL( SCIPeventfilterAdd(set->scip->eventfilter, blkmem, set,
3526 	         SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3527 	         (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), &(*nlp)->globalfilterpos) );
3528 	
3529 	   /* fractional variables in last NLP solution */
3530 	   (*nlp)->fracvars     = NULL;
3531 	   (*nlp)->fracvarssol  = NULL;
3532 	   (*nlp)->fracvarsfrac = NULL;
3533 	   (*nlp)->nfracvars     = 0;
3534 	   (*nlp)->npriofracvars = 0;
3535 	   (*nlp)->fracvarssize  = 0;
3536 	   (*nlp)->validfracvars = -1;
3537 	
3538 	   /* miscellaneous */
3539 	   SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlp)->name, name, strlen(name)+1) );
3540 	
3541 	   return SCIP_OKAY;
3542 	}
3543 	
3544 	/** frees NLP data object */
3545 	SCIP_RETCODE SCIPnlpFree(
3546 	   SCIP_NLP**            nlp,                /**< pointer to NLP data object */
3547 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3548 	   SCIP_SET*             set,                /**< global SCIP settings */
3549 	   SCIP_STAT*            stat,               /**< problem statistics */
3550 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3551 	   SCIP_LP*              lp                  /**< SCIP LP, needed for releasing variables */
3552 	   )
3553 	{
3554 	   assert(nlp    != NULL);
3555 	   assert(*nlp   != NULL);
3556 	   assert(blkmem != NULL);
3557 	   assert(set    != NULL);
3558 	
3559 	   /* drop fractional variables */
3560 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvars,     (*nlp)->fracvarssize);
3561 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarssol,  (*nlp)->fracvarssize);
3562 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarsfrac, (*nlp)->fracvarssize);
3563 	
3564 	   /* drop global events (variable addition and deletion) */
3565 	   SCIP_CALL( SCIPeventfilterDel(set->scip->eventfilter, blkmem, set,
3566 	         SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3567 	         (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), (*nlp)->globalfilterpos) );
3568 	
3569 	   SCIP_CALL( SCIPnlpReset(*nlp, blkmem, set, stat, eventqueue, lp) );
3570 	   assert((*nlp)->nnlrows == 0);
3571 	   assert((*nlp)->nnlrows_solver == 0);
3572 	   assert((*nlp)->nvars == 0);
3573 	   assert((*nlp)->nvars_solver == 0);
3574 	   assert((*nlp)->initialguess == NULL);
3575 	
3576 	   BMSfreeBlockMemoryArray(blkmem, &(*nlp)->name, strlen((*nlp)->name)+1);
3577 	
3578 	   /* free nonlinear rows arrays */
3579 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrowmap_nlpi2nlp, (*nlp)->sizenlrows_solver);
3580 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrows, (*nlp)->sizenlrows);
3581 	
3582 	   /* free variables arrays */
3583 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlp2nlpi, (*nlp)->sizevars);
3584 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlpi2nlp, (*nlp)->sizevars_solver);
3585 	   SCIPhashmapFree(&(*nlp)->varhash);
3586 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->vars, (*nlp)->sizevars);
3587 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varlbdualvals, (*nlp)->sizevars);
3588 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varubdualvals, (*nlp)->sizevars);
3589 	
3590 	   /* free NLPI problem */
3591 	   if( (*nlp)->problem != NULL )
3592 	   {
3593 	      SCIP_CALL( SCIPnlpiFreeProblem(set, (*nlp)->solver, &(*nlp)->problem) );
3594 	   }
3595 	
3596 	   /* free NLP data structure */
3597 	   BMSfreeMemory(nlp);
3598 	
3599 	   return SCIP_OKAY;
3600 	}
3601 	
3602 	/** resets the NLP to the empty NLP by removing all variables and rows from NLP,
3603 	 *  releasing all rows, and flushing the changes to the NLP solver
3604 	 */
3605 	SCIP_RETCODE SCIPnlpReset(
3606 	   SCIP_NLP*             nlp,                /**< NLP data */
3607 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3608 	   SCIP_SET*             set,                /**< global SCIP settings */
3609 	   SCIP_STAT*            stat,               /**< problem statistics data */
3610 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3611 	   SCIP_LP*              lp                  /**< SCIP LP, needed for releasing variables */
3612 	   )
3613 	{
3614 	   int i;
3615 	
3616 	   assert(nlp    != NULL);
3617 	   assert(blkmem != NULL);
3618 	   assert(set    != NULL);
3619 	
3620 	   if( nlp->indiving )
3621 	   {
3622 	      SCIP_CALL( SCIPnlpEndDive(nlp, blkmem, set, stat) );
3623 	   }
3624 	
3625 	   nlp->solstat  = SCIP_NLPSOLSTAT_UNKNOWN;
3626 	   nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3627 	
3628 	   BMSfreeBlockMemoryArrayNull(blkmem, &nlp->initialguess, nlp->sizevars);
3629 	   nlp->haveinitguess = FALSE;
3630 	
3631 	   for(i = nlp->nnlrows - 1; i >= 0; --i)
3632 	   {
3633 	      SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
3634 	   }
3635 	
3636 	   for(i = nlp->nvars - 1; i >= 0; --i)
3637 	   {
3638 	      SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, i) );
3639 	   }
3640 	
3641 	   SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3642 	
3643 	   return SCIP_OKAY;
3644 	}
3645 	
3646 	/** currently a dummy function that always returns TRUE */
3647 	SCIP_Bool SCIPnlpHasCurrentNodeNLP(
3648 	   SCIP_NLP*             nlp                 /**< NLP data */
3649 	   )
3650 	{
3651 	   assert(nlp != NULL);
3652 	   return TRUE;
3653 	} /*lint !e715*/
3654 	
3655 	/** ensures, that variables array of NLP can store at least num entries */
3656 	SCIP_RETCODE SCIPnlpEnsureVarsSize(
3657 	   SCIP_NLP*             nlp,                /**< NLP data */
3658 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3659 	   SCIP_SET*             set,                /**< global SCIP settings */
3660 	   int                   num                 /**< minimum number of entries to store */
3661 	   )
3662 	{
3663 	   assert(nlp    != NULL);
3664 	   assert(blkmem != NULL);
3665 	   assert(set    != NULL);
3666 	   assert(nlp->nvars <= nlp->sizevars);
3667 	
3668 	   if( num > nlp->sizevars )
3669 	   {
3670 	      int newsize;
3671 	
3672 	      newsize = SCIPsetCalcMemGrowSize(set, num);
3673 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->vars,            nlp->sizevars, newsize) );
3674 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlp2nlpi, nlp->sizevars, newsize) );
3675 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varlbdualvals,   nlp->sizevars, newsize) );
3676 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varubdualvals,   nlp->sizevars, newsize) );
3677 	      if( nlp->initialguess != NULL )
3678 	      {
3679 	         SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars, newsize) );
3680 	      }
3681 	
3682 	      nlp->sizevars = newsize;
3683 	   }
3684 	   assert(num <= nlp->sizevars);
3685 	
3686 	   return SCIP_OKAY;
3687 	}
3688 	
3689 	/** adds a variable to the NLP and captures the variable */
3690 	SCIP_RETCODE SCIPnlpAddVar(
3691 	   SCIP_NLP*             nlp,                /**< NLP data */
3692 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3693 	   SCIP_SET*             set,                /**< global SCIP settings */
3694 	   SCIP_VAR*             var                 /**< variable */
3695 	   )
3696 	{
3697 	   assert(nlp != NULL);
3698 	   assert(blkmem != NULL);
3699 	   assert(set != NULL);
3700 	   assert(var != NULL);
3701 	   assert(SCIPvarIsTransformed(var));
3702 	   assert(!SCIPhashmapExists(nlp->varhash, var));
3703 	
3704 	   if( nlp->indiving )
3705 	   {
3706 	      SCIPerrorMessage("cannot add variable during NLP diving\n");
3707 	      return SCIP_ERROR;
3708 	   }
3709 	
3710 	   SCIP_CALL( nlpAddVars(nlp, blkmem, set, 1, &var) );
3711 	
3712 	   return SCIP_OKAY;
3713 	}
3714 	
3715 	/** adds a set of variables to the NLP and captures the variables */
3716 	SCIP_RETCODE SCIPnlpAddVars(
3717 	   SCIP_NLP*             nlp,                /**< NLP data */
3718 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3719 	   SCIP_SET*             set,                /**< global SCIP settings */
3720 	   int                   nvars,              /**< number of variables to add */
3721 	   SCIP_VAR**            vars                /**< variables to add */
3722 	   )
3723 	{
3724 	   assert(nlp != NULL);
3725 	   assert(blkmem != NULL);
3726 	   assert(set != NULL);
3727 	   assert(vars != NULL || nvars == 0);
3728 	
3729 	   if( nlp->indiving && nvars > 0)
3730 	   {
3731 	      SCIPerrorMessage("cannot add variables during NLP diving\n");
3732 	      return SCIP_ERROR;
3733 	   }
3734 	
3735 	   SCIP_CALL( nlpAddVars(nlp, blkmem, set, nvars, vars) );
3736 	
3737 	   return SCIP_OKAY;
3738 	}
3739 	
3740 	/** deletes a variable from the NLP and releases the variable */
3741 	SCIP_RETCODE SCIPnlpDelVar(
3742 	   SCIP_NLP*             nlp,                /**< NLP data */
3743 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3744 	   SCIP_SET*             set,                /**< global SCIP settings */
3745 	   SCIP_STAT*            stat,               /**< problem statistics data */
3746 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3747 	   SCIP_LP*              lp,                 /**< SCIP LP, needed to release variable */
3748 	   SCIP_VAR*             var                 /**< variable */
3749 	   )
3750 	{
3751 	   int varpos;
3752 	
3753 	   assert(nlp    != NULL);
3754 	   assert(blkmem != NULL);
3755 	   assert(set    != NULL);
3756 	   assert(var    != NULL);
3757 	
3758 	   if( !SCIPhashmapExists(nlp->varhash, var) )
3759 	   {
3760 	      SCIPerrorMessage("variable <%s> not found in NLP, cannot delete\n", SCIPvarGetName(var));
3761 	      return SCIP_ERROR;
3762 	   }
3763 	
3764 	   if( nlp->indiving )
3765 	   {
3766 	      SCIPerrorMessage("cannot delete variable during NLP diving\n");
3767 	      return SCIP_ERROR;
3768 	   }
3769 	
3770 	   varpos = SCIPhashmapGetImageInt(nlp->varhash, var);
3771 	
3772 	   SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, varpos) );
3773 	
3774 	   return SCIP_OKAY;
3775 	}
3776 	
3777 	/** ensures, that nonlinear rows array of NLP can store at least num entries */
3778 	SCIP_RETCODE SCIPnlpEnsureNlRowsSize(
3779 	   SCIP_NLP*             nlp,                /**< NLP data */
3780 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3781 	   SCIP_SET*             set,                /**< global SCIP settings */
3782 	   int                   num                 /**< minimum number of entries to store */
3783 	   )
3784 	{
3785 	   assert(nlp    != NULL);
3786 	   assert(blkmem != NULL);
3787 	   assert(set    != NULL);
3788 	   assert(nlp->nnlrows <= nlp->sizenlrows);
3789 	
3790 	   if( num > nlp->sizenlrows )
3791 	   {
3792 	      int newsize;
3793 	
3794 	      newsize = SCIPsetCalcMemGrowSize(set, num);
3795 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrows, nlp->sizenlrows, newsize) );
3796 	
3797 	      nlp->sizenlrows = newsize;
3798 	   }
3799 	   assert(num <= nlp->sizenlrows);
3800 	
3801 	   return SCIP_OKAY;
3802 	}
3803 	
3804 	/** adds a nonlinear row to the NLP and captures it
3805 	 *
3806 	 * all variables of the row need to be present in the NLP
3807 	 */
3808 	SCIP_RETCODE SCIPnlpAddNlRow(
3809 	   SCIP_NLP*             nlp,                /**< NLP data */
3810 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3811 	   SCIP_SET*             set,                /**< global SCIP settings */
3812 	   SCIP_STAT*            stat,               /**< problem statistics data */
3813 	   SCIP_NLROW*           nlrow               /**< nonlinear row */
3814 	   )
3815 	{
3816 	   assert(nlp   != NULL);
3817 	   assert(nlrow != NULL);
3818 	
3819 	   if( nlp->indiving )
3820 	   {
3821 	      SCIPerrorMessage("cannot add row during NLP diving\n");
3822 	      return SCIP_ERROR;
3823 	   }
3824 	
3825 	   SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, 1, &nlrow) );
3826 	
3827 	   return SCIP_OKAY;
3828 	}
3829 	
3830 	/** adds nonlinear rows to the NLP and captures them
3831 	 *
3832 	 * all variables of the row need to be present in the NLP
3833 	 */
3834 	SCIP_RETCODE SCIPnlpAddNlRows(
3835 	   SCIP_NLP*             nlp,                /**< NLP data */
3836 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3837 	   SCIP_SET*             set,                /**< global SCIP settings */
3838 	   SCIP_STAT*            stat,               /**< problem statistics data */
3839 	   int                   nnlrows,            /**< number of rows to add */
3840 	   SCIP_NLROW**          nlrows              /**< rows to add */
3841 	   )
3842 	{
3843 	   assert(nlp    != NULL);
3844 	   assert(nlrows != NULL || nnlrows == 0);
3845 	
3846 	   if( nnlrows == 0 )
3847 	      return SCIP_OKAY;
3848 	
3849 	   if( nlp->indiving )
3850 	   {
3851 	      SCIPerrorMessage("cannot add rows during NLP diving\n");
3852 	      return SCIP_ERROR;
3853 	   }
3854 	
3855 	   SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, nnlrows, nlrows) );
3856 	
3857 	   return SCIP_OKAY;
3858 	}
3859 	
3860 	/** deletes a nonlinear row from the NLP
3861 	 *
3862 	 * does nothing if nonlinear row is not in NLP
3863 	 */
3864 	SCIP_RETCODE SCIPnlpDelNlRow(
3865 	   SCIP_NLP*             nlp,                /**< NLP data */
3866 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3867 	   SCIP_SET*             set,                /**< global SCIP settings */
3868 	   SCIP_STAT*            stat,               /**< problem statistics data */
3869 	   SCIP_NLROW*           nlrow               /**< nonlinear row */
3870 	   )
3871 	{
3872 	   assert(nlp    != NULL);
3873 	   assert(blkmem != NULL);
3874 	   assert(set    != NULL);
3875 	   assert(nlrow  != NULL);
3876 	
3877 	   /* if row not in NLP, nothing to do */
3878 	   if( nlrow->nlpindex == -1 )
3879 	      return SCIP_OKAY;
3880 	
3881 	   assert(nlrow->nlpindex >= 0);
3882 	   assert(nlrow->nlpindex < nlp->nnlrows);
3883 	
3884 	   if( nlp->indiving )
3885 	   {
3886 	      SCIPerrorMessage("cannot delete row during NLP diving\n");
3887 	      return SCIP_ERROR;
3888 	   }
3889 	
3890 	   SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, nlrow->nlpindex) );
3891 	
3892 	   return SCIP_OKAY;
3893 	}
3894 	
3895 	/** applies all cached changes to the NLP solver */
3896 	SCIP_RETCODE SCIPnlpFlush(
3897 	   SCIP_NLP*             nlp,                /**< current NLP data */
3898 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3899 	   SCIP_SET*             set,                /**< global SCIP settings */
3900 	   SCIP_STAT*            stat                /**< problem statistics */
3901 	   )
3902 	{
3903 	   assert(nlp    != NULL);
3904 	   assert(blkmem != NULL);
3905 	   assert(set    != NULL);
3906 	
3907 	   if( nlp->indiving )
3908 	   {
3909 	      SCIPerrorMessage("cannot flush NLP during NLP diving\n");
3910 	      return SCIP_ERROR;
3911 	   }
3912 	
3913 	   /* flush removals of nonlinear rows and variables */
3914 	   SCIP_CALL( nlpFlushNlRowDeletions(nlp, blkmem, set) );
3915 	   SCIP_CALL( nlpFlushVarDeletions(nlp, blkmem, set) );
3916 	   assert(nlp->nunflushednlrowdel == 0);
3917 	   assert(nlp->nunflushedvardel   == 0);
3918 	
3919 	   /* flush addition of variables, objective, and addition of rows */
3920 	   SCIP_CALL( nlpFlushVarAdditions(nlp, blkmem, set) );
3921 	   SCIP_CALL( nlpFlushObjective(nlp, blkmem, set) );
3922 	   SCIP_CALL( nlpFlushNlRowAdditions(nlp, blkmem, set, stat) );
3923 	   assert(nlp->nunflushedvaradd == 0);
3924 	   assert(nlp->objflushed == TRUE);
3925 	   assert(nlp->nunflushednlrowadd == 0);
3926 	
3927 	   assert(nlp->nvars   == nlp->nvars_solver);
3928 	   assert(nlp->nnlrows == nlp->nnlrows_solver);
3929 	
3930 	   return SCIP_OKAY;
3931 	}
3932 	
3933 	/** solves the NLP or diving NLP */
3934 	SCIP_RETCODE SCIPnlpSolve(
3935 	   SCIP_NLP*             nlp,                /**< NLP data */
3936 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3937 	   SCIP_SET*             set,                /**< global SCIP settings */
3938 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
3939 	   SCIP_STAT*            stat,               /**< problem statistics */
3940 	   SCIP_PRIMAL*          primal,             /**< primal data */
3941 	   SCIP_TREE*            tree,               /**< branch and bound tree */
3942 	   SCIP_NLPPARAM*        nlpparam            /**< NLP solve parameters */
3943 	   )
3944 	{
3945 	   assert(nlp    != NULL);
3946 	   assert(blkmem != NULL);
3947 	   assert(set    != NULL);
3948 	   assert(stat   != NULL);
3949 	
3950 	   if( !nlp->indiving )
3951 	   {
3952 	      SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3953 	   }
3954 	
3955 	   SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat, primal, tree, nlpparam) );
3956 	
3957 	   return SCIP_OKAY;
3958 	}
3959 	
3960 	/** gets objective value of current NLP */
3961 	SCIP_Real SCIPnlpGetObjval(
3962 	   SCIP_NLP*             nlp                 /**< current NLP data */
3963 	   )
3964 	{
3965 	   assert(nlp != NULL);
3966 	
3967 	   return nlp->primalsolobjval;
3968 	}
3969 	
3970 	/** gives current pseudo objective value */
3971 	SCIP_RETCODE SCIPnlpGetPseudoObjval(
3972 	   SCIP_NLP*             nlp,                /**< current NLP data */
3973 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3974 	   SCIP_SET*             set,                /**< global SCIP settings */
3975 	   SCIP_STAT*            stat,               /**< problem statistics data */
3976 	   SCIP_PROB*            prob,               /**< SCIP problem */
3977 	   SCIP_PRIMAL*          primal,             /**< primal data */
3978 	   SCIP_TREE*            tree,               /**< branch and bound tree */
3979 	   SCIP_LP*              lp,                 /**< SCIP LP */
3980 	   SCIP_Real*            pseudoobjval        /**< buffer to store pseudo objective value */
3981 	   )
3982 	{
3983 	   assert(nlp != NULL);
3984 	   assert(pseudoobjval != NULL);
3985 	
3986 	   if( nlp->divingobj != NULL )
3987 	   {
3988 	      assert(nlp->indiving);
3989 	      SCIP_CALL( SCIPnlrowGetPseudoActivity(nlp->divingobj, blkmem, set, stat, prob, primal, tree, lp, pseudoobjval) );
3990 	   }
3991 	   else
3992 	   {
3993 	      int i;
3994 	
3995 	      *pseudoobjval = 0.0;
3996 	      for( i = 0; i < nlp->nvars; ++i )
3997 	         *pseudoobjval += SCIPvarGetObj(nlp->vars[i]) * SCIPvarGetBestBoundLocal(nlp->vars[i]);
3998 	   }
3999 	
4000 	   return SCIP_OKAY;
4001 	}
4002 	
4003 	/** gets fractional variables of last NLP solution along with solution values and fractionalities
4004 	 */
4005 	SCIP_RETCODE SCIPnlpGetFracVars(
4006 	   SCIP_NLP*             nlp,                /**< NLP data structure */
4007 	   BMS_BLKMEM*           blkmem,             /**< block memory */
4008 	   SCIP_SET*             set,                /**< global SCIP settings */
4009 	   SCIP_STAT*            stat,               /**< problem statistics */
4010 	   SCIP_VAR***           fracvars,           /**< pointer to store the array of NLP fractional variables, or NULL */
4011 	   SCIP_Real**           fracvarssol,        /**< pointer to store the array of NLP fractional variables solution values, or NULL */
4012 	   SCIP_Real**           fracvarsfrac,       /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
4013 	   int*                  nfracvars,          /**< pointer to store the number of NLP fractional variables , or NULL */
4014 	   int*                  npriofracvars       /**< pointer to store the number of NLP fractional variables with maximal branching priority, or NULL */
4015 	   )
4016 	{
4017 	   assert(nlp != NULL);
4018 	
4019 	   SCIP_CALL( nlpCalcFracVars(nlp, blkmem, set, stat) );
4020 	   assert(nlp->fracvars     != NULL);
4021 	   assert(nlp->fracvarssol  != NULL);
4022 	   assert(nlp->fracvarsfrac != NULL);
4023 	
4024 	   if( fracvars != NULL )
4025 	      *fracvars = nlp->fracvars;
4026 	   if( fracvarssol != NULL )
4027 	      *fracvarssol = nlp->fracvarssol;
4028 	   if( fracvarsfrac != NULL )
4029 	      *fracvarsfrac = nlp->fracvarsfrac;
4030 	   if( nfracvars != NULL )
4031 	      *nfracvars = nlp->nfracvars;
4032 	   if( npriofracvars != NULL )
4033 	      *npriofracvars = nlp->npriofracvars;
4034 	
4035 	   return SCIP_OKAY;
4036 	}
4037 	
4038 	/** removes all redundant nonlinear rows */
4039 	SCIP_RETCODE SCIPnlpRemoveRedundantNlRows(
4040 	   SCIP_NLP*             nlp,                /**< current NLP data */
4041 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4042 	   SCIP_SET*             set,                /**< global SCIP settings */
4043 	   SCIP_STAT*            stat                /**< problem statistics */
4044 	   )
4045 	{
4046 	   SCIP_NLPSOLSTAT solstatus;
4047 	   SCIP_Bool isredundant;
4048 	   int i;
4049 	
4050 	   assert(nlp    != NULL);
4051 	   assert(blkmem != NULL);
4052 	   assert(set    != NULL);
4053 	   assert(stat   != NULL);
4054 	
4055 	   if( nlp->nnlrows == 0 )
4056 	      return SCIP_OKAY;
4057 	
4058 	   if( nlp->indiving )
4059 	   {
4060 	      SCIPerrorMessage("cannot remove redundant rows during NLP diving\n");
4061 	      return SCIP_ERROR;
4062 	   }
4063 	
4064 	   /* removing redundant rows should not change the solution status, so we reset it at the end */
4065 	   solstatus = nlp->solstat;
4066 	
4067 	   for( i = 0; i < nlp->nnlrows; ++i )
4068 	   {
4069 	      SCIP_CALL( SCIPnlrowIsRedundant(nlp->nlrows[i], blkmem, set, stat, &isredundant) );
4070 	      if( isredundant )
4071 	      {
4072 	         SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
4073 	      }
4074 	   }
4075 	
4076 	   nlp->solstat = solstatus;
4077 	
4078 	   return SCIP_OKAY;
4079 	}
4080 	
4081 	/** set initial guess (approximate primal solution) for next solve
4082 	 *
4083 	 *  array initguess must be NULL or have length at least SCIPnlpGetNVars()
4084 	 */
4085 	SCIP_RETCODE SCIPnlpSetInitialGuess(
4086 	   SCIP_SET*             set,                /**< global SCIP settings */
4087 	   SCIP_NLP*             nlp,                /**< current NLP data */
4088 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4089 	   SCIP_Real*            initguess           /**< new initial guess, or NULL to clear previous one */
4090 	   )
4091 	{
4092 	   assert(nlp    != NULL);
4093 	   assert(blkmem != NULL);
4094 	   assert(nlp->solver  != NULL);
4095 	   assert(nlp->problem != NULL);
4096 	
4097 	   /* if user wants to let NLP solver choose start point, then invalidate current initial guess both in NLP and in NLPI */
4098 	   if( initguess == NULL )
4099 	   {
4100 	      nlp->haveinitguess = FALSE;
4101 	      SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, NULL, NULL, NULL, NULL) );
4102 	      return SCIP_OKAY;
4103 	   }
4104 	
4105 	   if( nlp->initialguess != NULL )
4106 	   {
4107 	      BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4108 	   }
4109 	   else
4110 	   {
4111 	      assert( nlp->sizevars >= nlp->nvars );
4112 	      SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars) );
4113 	      BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4114 	   }
4115 	   nlp->haveinitguess = TRUE;
4116 	
4117 	   return SCIP_OKAY;
4118 	}
4119 	
4120 	/** writes NLP to a file */
4121 	SCIP_RETCODE SCIPnlpWrite(
4122 	   SCIP_NLP*             nlp,                /**< current NLP data */
4123 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4124 	   SCIP_SET*             set,                /**< global SCIP settings */
4125 	   SCIP_STAT*            stat,               /**< problem statistics */
4126 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
4127 	   const char*           fname               /**< file name */
4128 	   )
4129 	{
4130 	   FILE* file;
4131 	   int i;
4132 	
4133 	   assert(nlp != NULL);
4134 	
(1) Event cond_true: Condition "fname != NULL", taking true branch.
4135 	   if( fname != NULL )
4136 	   {
(2) Event alloc_fn: Storage is returned from allocation function "fopen".
(3) Event var_assign: Assigning: "file" = storage returned from "fopen(fname, "w")".
Also see events: [noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4137 	      file = fopen(fname, "w");
(4) Event cond_false: Condition "file == NULL", taking false branch.
4138 	      if( file == NULL )
4139 	      {
4140 	         SCIPerrorMessage("could not open file <%s> for writing\n", fname);
4141 	         return SCIP_FILECREATEERROR;
(5) Event if_end: End of if statement.
4142 	      }
(6) Event if_fallthrough: Falling through to end of if statement.
4143 	   }
4144 	   else
(7) Event if_end: End of if statement.
4145 	      file = stdout;
4146 	
(8) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4147 	   SCIPmessageFPrintInfo(messagehdlr, file, "STATISTICS\n");
(9) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4148 	   SCIPmessageFPrintInfo(messagehdlr, file, "  NLP name: %s\n", nlp->name);
(10) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4149 	   SCIPmessageFPrintInfo(messagehdlr, file, "  Variables: %d\n", nlp->nvars);
(11) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4150 	   SCIPmessageFPrintInfo(messagehdlr, file, "  Rows: %d\n", nlp->nnlrows);
4151 	
(12) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4152 	   SCIPmessageFPrintInfo(messagehdlr, file, "VARIABLES\n");
(13) Event cond_false: Condition "i < nlp->nvars", taking false branch.
4153 	   for( i = 0; i < nlp->nvars; ++i )
4154 	   {
4155 	      SCIP_CALL( SCIPvarPrint(nlp->vars[i], set, messagehdlr, file) );
(14) Event loop_end: Reached end of loop.
4156 	   }
4157 	
(15) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4158 	   SCIPmessageFPrintInfo(messagehdlr, file, "NONLINEAR ROWS\n");
(16) Event cond_true: Condition "i < nlp->nnlrows", taking true branch.
4159 	   for( i = 0; i < nlp->nnlrows; ++i )
4160 	   {
(17) Event noescape: Resource "file" is not freed or pointed-to in "SCIPmessageFPrintInfo". [details]
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][leaked_storage]
4161 	      SCIPmessageFPrintInfo(messagehdlr, file, "  ");
(18) Event noescape: Resource "file" is not freed or pointed-to in "SCIPnlrowPrint". [details]
(19) Event cond_true: Condition "(_restat_ = SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file)) != SCIP_OKAY", taking true branch.
(20) Event leaked_storage: Variable "file" going out of scope leaks the storage it points to.
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
4162 	      SCIP_CALL( SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file) );
4163 	   }
4164 	
4165 	   if( fname != NULL )
4166 	   {
4167 	      fclose(file);
4168 	   }
4169 	
4170 	   return SCIP_OKAY;
4171 	}
4172 	
4173 	/** gets array with variables of the NLP */
4174 	SCIP_VAR** SCIPnlpGetVars(
4175 	   SCIP_NLP*             nlp                 /**< current NLP data */
4176 	   )
4177 	{
4178 	   assert(nlp != NULL);
4179 	
4180 	   return nlp->vars;
4181 	}
4182 	
4183 	/** gets current number of variables in NLP */
4184 	int SCIPnlpGetNVars(
4185 	   SCIP_NLP*             nlp                 /**< current NLP data */
4186 	   )
4187 	{
4188 	   assert(nlp != NULL);
4189 	
4190 	   return nlp->nvars;
4191 	}
4192 	
4193 	/** computes for each variables the number of NLP rows in which the variable appears in a nonlinear var */
4194 	SCIP_RETCODE SCIPnlpGetVarsNonlinearity(
4195 	   SCIP_NLP*             nlp,                /**< current NLP data */
4196 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4197 	   SCIP_SET*             set,                /**< global SCIP settings */
4198 	   SCIP_STAT*            stat,               /**< problem statistics */
4199 	   int*                  nlcount             /**< an array of length at least SCIPnlpGetNVars() to store nonlinearity counts of variables */
4200 	   )
4201 	{
4202 	   SCIP_NLROW* nlrow;
4203 	   SCIP_EXPRITER* it;
4204 	   SCIP_EXPR* expr;
4205 	   int varidx;
4206 	   int c;
4207 	
4208 	   assert(nlp != NULL);
4209 	   assert(nlcount != NULL || nlp->nvars == 0);
4210 	
4211 	   BMSclearMemoryArray(nlcount, nlp->nvars);
4212 	
4213 	   SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4214 	
4215 	   for( c = 0; c < nlp->nnlrows; ++c )
4216 	   {
4217 	      nlrow = nlp->nlrows[c];
4218 	      assert(nlrow != NULL);
4219 	
4220 	      if( nlrow->expr == NULL )
4221 	         continue;
4222 	
4223 	      SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, FALSE) );
4224 	      for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4225 	      {
4226 	         if( !SCIPexprIsVar(set, expr) )
4227 	            continue;
4228 	
4229 	         assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
4230 	
4231 	         varidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(expr));
4232 	         assert(varidx < nlp->nvars);
4233 	         assert(nlcount != NULL);
4234 	         ++nlcount[varidx];
4235 	      }
4236 	   }
4237 	
4238 	   SCIPexpriterFree(&it);
4239 	
4240 	   return SCIP_OKAY;
4241 	}
4242 	
4243 	
4244 	/** indicates whether there exists a row that contains a continuous variable in a nonlinear term
4245 	 *
4246 	 * @note The method may have to touch every row and nonlinear term to compute its result.
4247 	 */
4248 	SCIP_RETCODE SCIPnlpHasContinuousNonlinearity(
4249 	   SCIP_NLP*             nlp,                /**< current NLP data */
4250 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4251 	   SCIP_SET*             set,                /**< global SCIP settings */
4252 	   SCIP_STAT*            stat,               /**< problem statistics */
4253 	   SCIP_Bool*            result              /**< buffer to store whether continuous variable present in an expression of any row */
4254 	   )
4255 	{
4256 	   SCIP_NLROW* nlrow;
4257 	   SCIP_EXPRITER* it;
4258 	   SCIP_EXPR* expr;
4259 	   int c;
4260 	
4261 	   assert(nlp != NULL);
4262 	
4263 	   SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4264 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4265 	
4266 	   *result = FALSE;
4267 	   for( c = 0; c < nlp->nnlrows && !*result; ++c )
4268 	   {
4269 	      nlrow = nlp->nlrows[c];
4270 	      assert(nlrow != NULL);
4271 	
4272 	      if( nlrow->expr == NULL )
4273 	         continue;
4274 	
4275 	      for( expr = SCIPexpriterRestartDFS(it, nlrow->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4276 	      {
4277 	         if( SCIPexprIsVar(set, expr) && SCIPvarGetType(SCIPgetVarExprVar(expr)) == SCIP_VARTYPE_CONTINUOUS )
4278 	         {
4279 	            *result = TRUE;
4280 	            break;
4281 	         }
4282 	      }
4283 	   }
4284 	
4285 	   SCIPexpriterFree(&it);
4286 	
4287 	   return SCIP_OKAY;
4288 	}
4289 	
4290 	/** gives dual solution values associated with lower bounds of NLP variables */
4291 	SCIP_Real* SCIPnlpGetVarsLbDualsol(
4292 	   SCIP_NLP*             nlp                 /**< current NLP data */
4293 	   )
4294 	{
4295 	   assert(nlp != NULL);
4296 	
4297 	   return nlp->varlbdualvals;
4298 	}
4299 	
4300 	/** gives dual solution values associated with upper bounds of NLP variables */
4301 	SCIP_Real* SCIPnlpGetVarsUbDualsol(
4302 	   SCIP_NLP*             nlp                 /**< current NLP data */
4303 	   )
4304 	{
4305 	   assert(nlp != NULL);
4306 	
4307 	   return nlp->varubdualvals;
4308 	}
4309 	
4310 	/** gets array with nonlinear rows of the NLP */
4311 	SCIP_NLROW** SCIPnlpGetNlRows(
4312 	   SCIP_NLP*             nlp                 /**< current NLP data */
4313 	   )
4314 	{
4315 	   assert(nlp != NULL);
4316 	
4317 	   return nlp->nlrows;
4318 	}
4319 	
4320 	/** gets current number of nonlinear rows in NLP */
4321 	int SCIPnlpGetNNlRows(
4322 	   SCIP_NLP*             nlp                 /**< current NLP data */
4323 	   )
4324 	{
4325 	   assert(nlp != NULL);
4326 	
4327 	   return nlp->nnlrows;
4328 	}
4329 	
4330 	/** gets the NLP solver interface */
4331 	SCIP_NLPI* SCIPnlpGetNLPI(
4332 	   SCIP_NLP*             nlp                 /**< current NLP data */
4333 	   )
4334 	{
4335 	   assert(nlp != NULL);
4336 	
4337 	   return nlp->solver;
4338 	}
4339 	
4340 	/** gets the NLP problem in the solver interface */
4341 	SCIP_NLPIPROBLEM* SCIPnlpGetNLPIProblem(
4342 	   SCIP_NLP*             nlp                 /**< current NLP data */
4343 	   )
4344 	{
4345 	   assert(nlp != NULL);
4346 	
4347 	   return nlp->problem;
4348 	}
4349 	
4350 	/** indicates whether NLP is currently in diving mode */
4351 	SCIP_Bool SCIPnlpIsDiving(
4352 	   SCIP_NLP*             nlp                 /**< current NLP data */
4353 	   )
4354 	{
4355 	   assert(nlp != NULL);
4356 	
4357 	   return nlp->indiving;
4358 	}
4359 	
4360 	/** gets solution status of current NLP */
4361 	SCIP_NLPSOLSTAT SCIPnlpGetSolstat(
4362 	   SCIP_NLP*             nlp                 /**< current NLP data */
4363 	   )
4364 	{
4365 	   assert(nlp != NULL);
4366 	
4367 	   return nlp->solstat;
4368 	}
4369 	
4370 	/** gets termination status of last NLP solve */
4371 	SCIP_NLPTERMSTAT SCIPnlpGetTermstat(
4372 	   SCIP_NLP*             nlp                 /**< current NLP data */
4373 	   )
4374 	{
4375 	   assert(nlp != NULL);
4376 	
4377 	   return nlp->termstat;
4378 	}
4379 	
4380 	/** gives statistics (number of iterations, solving time, ...) of last NLP solve */
4381 	SCIP_RETCODE SCIPnlpGetStatistics(
4382 	   SCIP_SET*             set,                /**< global SCIP settings */
4383 	   SCIP_NLP*             nlp,                /**< pointer to NLP datastructure */
4384 	   SCIP_NLPSTATISTICS*   statistics          /**< pointer to store statistics */
4385 	   )
4386 	{
4387 	   assert(nlp != NULL);
4388 	   assert(nlp->solver != NULL);
4389 	   assert(nlp->problem != NULL);
4390 	   assert(statistics != NULL);
4391 	
4392 	   SCIP_CALL( SCIPnlpiGetStatistics(set, nlp->solver, nlp->problem, statistics) );
4393 	
4394 	   return SCIP_OKAY;
4395 	}
4396 	
4397 	/** indicates whether a solution for the current NLP is available
4398 	 *
4399 	 * The solution may be optimal, feasible, or infeasible.
4400 	 * Thus, returns whether the NLP solution status is at most \ref SCIP_NLPSOLSTAT_LOCINFEASIBLE.
4401 	 */
4402 	SCIP_Bool SCIPnlpHasSolution(
4403 	   SCIP_NLP*             nlp                 /**< current NLP data */
4404 	   )
4405 	{
4406 	   assert(nlp != NULL);
4407 	
4408 	   return nlp->solstat <= SCIP_NLPSOLSTAT_LOCINFEASIBLE;
4409 	}
4410 	
4411 	/*
4412 	 * NLP diving methods
4413 	 */
4414 	
4415 	/** signals start of diving */
4416 	SCIP_RETCODE SCIPnlpStartDive(
4417 	   SCIP_NLP*             nlp,                /**< current NLP data */
4418 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4419 	   SCIP_SET*             set,                /**< global SCIP settings */
4420 	   SCIP_STAT*            stat                /**< problem statistics */
4421 	   )
4422 	{
4423 	   assert(nlp != NULL);
4424 	
4425 	   if( nlp->indiving )
4426 	   {
4427 	      SCIPerrorMessage("NLP is already in diving mode\n");
4428 	      return SCIP_ERROR;
4429 	   }
4430 	
4431 	   if( nlp->solver == NULL )
4432 	   {
4433 	      /* In diving mode we do not cache changes but put them directly in the NLPI problem, which does not exist if there is no solver.
4434 	       * So we forbid diving of no solver is available. */
4435 	      SCIPerrorMessage("Cannot start diving if no NLP solver is available\n");
4436 	      return SCIP_ERROR;
4437 	   }
4438 	
4439 	   SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
4440 	
4441 	   nlp->indiving = TRUE;
4442 	
4443 	   return SCIP_OKAY;
4444 	}
4445 	
4446 	/** resets the bound and objective changes made during diving and disables diving mode */
4447 	SCIP_RETCODE SCIPnlpEndDive(
4448 	   SCIP_NLP*             nlp,                /**< current NLP data */
4449 	   BMS_BLKMEM*           blkmem,             /**< block memory */
4450 	   SCIP_SET*             set,                /**< global SCIP settings */
4451 	   SCIP_STAT*            stat                /**< problem statistics data */
4452 	   )
4453 	{
4454 	   int i;
4455 	   int* varidx;
4456 	   SCIP_Real* varlb;
4457 	   SCIP_Real* varub;
4458 	
4459 	   assert(nlp != NULL);
4460 	   assert(set != NULL);
4461 	   assert(nlp->nvars == nlp->nvars_solver);
4462 	
4463 	   if( !nlp->indiving )
4464 	   {
4465 	      SCIPerrorMessage("NLP not in diving mode, cannot end dive\n");
4466 	      return SCIP_ERROR;
4467 	   }
4468 	
4469 	   assert(nlp->solver != NULL);
4470 	   assert(nlp->problem != NULL);
4471 	
4472 	   /* reset variable bounds in NLPI problem to their current values */
4473 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &varidx, nlp->nvars) );
4474 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &varlb,  nlp->nvars) );
4475 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &varub,  nlp->nvars) );
4476 	   for( i = 0; i < nlp->nvars; ++i )
4477 	   {
4478 	      varidx[i] = i;
4479 	      varlb[i] = SCIPvarGetLbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4480 	      varub[i] = SCIPvarGetUbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4481 	   }
4482 	
4483 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nlp->nvars, varidx, varlb, varub) );
4484 	
4485 	   SCIPsetFreeBufferArray(set, &varidx);
4486 	   SCIPsetFreeBufferArray(set, &varlb);
4487 	   SCIPsetFreeBufferArray(set, &varub);
4488 	
4489 	   /* clear diving objective, if one was used (i.e., if SCIPnlpChgVarObjDive had been called)
4490 	    * the objective in the NLPI will be reset in the next flush */
4491 	   if( nlp->divingobj != NULL )
4492 	   {
4493 	      SCIP_CALL( SCIPnlrowRelease(&nlp->divingobj, blkmem, set, stat) );
4494 	      assert(nlp->divingobj == NULL);
4495 	      assert(nlp->objflushed == FALSE);
4496 	   }
4497 	
4498 	   /* we do not have a valid solution anymore */
4499 	   nlp->solstat  = SCIP_NLPSOLSTAT_UNKNOWN;
4500 	   nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
4501 	   nlp->primalsolobjval = SCIP_INVALID;
4502 	
4503 	   nlp->indiving = FALSE;
4504 	
4505 	   return SCIP_OKAY;
4506 	}
4507 	
4508 	/** changes coefficient of variable in diving NLP */
4509 	SCIP_RETCODE SCIPnlpChgVarObjDive(
4510 	   SCIP_NLP*             nlp,                /**< current NLP data */
4511 	   BMS_BLKMEM*           blkmem,             /**< block memory */
4512 	   SCIP_SET*             set,                /**< global SCIP settings */
4513 	   SCIP_STAT*            stat,               /**< problem statistics data */
4514 	   SCIP_VAR*             var,                /**< variable which coefficient to change */
4515 	   SCIP_Real             coef                /**< new linear coefficient of variable in objective */
4516 	   )
4517 	{
4518 	   int pos;
4519 	   int objidx;
4520 	
4521 	   assert(nlp != NULL);
4522 	   assert(var != NULL);
4523 	   assert(SCIPhashmapExists(nlp->varhash, var));
4524 	   assert(nlp->indiving);
4525 	   assert(nlp->solver != NULL);
4526 	   assert(nlp->problem != NULL);
4527 	
4528 	   /* get position of variable in NLPI problem */
4529 	   pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4530 	   pos = nlp->varmap_nlp2nlpi[pos];
4531 	   assert(pos >= 0);
4532 	
4533 	   /* set coefficient in NLPI problem objective */
4534 	   objidx = -1;
4535 	   SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
4536 	
4537 	   /* create an nlrow that holds the diving objective, if not done yet */
4538 	   if( nlp->divingobj == NULL )
4539 	   {
4540 	      SCIP_Real* coefs;
4541 	      int        i;
4542 	
4543 	      SCIP_CALL( SCIPsetAllocBufferArray(set, &coefs, nlp->nvars) );
4544 	      for( i = 0; i < nlp->nvars; ++i )
4545 	         coefs[i] = SCIPvarGetObj(nlp->vars[i]);
4546 	
4547 	      SCIP_CALL( SCIPnlrowCreate(&nlp->divingobj, blkmem, set, stat, "divingobj",
4548 	            0.0, nlp->nvars, nlp->vars, coefs, NULL,
4549 	            -SCIPsetInfinity(set), SCIPsetInfinity(set),
4550 	            SCIP_EXPRCURV_LINEAR) );
4551 	
4552 	      SCIPsetFreeBufferArray(set, &coefs);
4553 	   }
4554 	   assert(nlp->divingobj != NULL);
4555 	
4556 	   /* modify coefficient in diving objective */
4557 	   SCIP_CALL( SCIPnlrowChgLinearCoef(nlp->divingobj, blkmem, set, stat, nlp, var, coef) );
4558 	
4559 	   /* remember that we have to store objective after diving ended */
4560 	   nlp->objflushed = FALSE;
4561 	
4562 	   return SCIP_OKAY;
4563 	}
4564 	
4565 	/** changes bounds of variable in diving NLP */
4566 	SCIP_RETCODE SCIPnlpChgVarBoundsDive(
4567 	   SCIP_SET*             set,                /**< global SCIP settings */
4568 	   SCIP_NLP*             nlp,                /**< current NLP data */
4569 	   SCIP_VAR*             var,                /**< variable which coefficient to change */
4570 	   SCIP_Real             lb,                 /**< new lower bound of variable */
4571 	   SCIP_Real             ub                  /**< new upper bound of variable */
4572 	   )
4573 	{
4574 	   int pos;
4575 	
4576 	   assert(nlp != NULL);
4577 	   assert(var != NULL);
4578 	   assert(SCIPhashmapExists(nlp->varhash, var));
4579 	   assert(nlp->indiving);
4580 	   assert(nlp->solver != NULL);
4581 	   assert(nlp->problem != NULL);
4582 	
4583 	   /* get position of variable in NLPI problem */
4584 	   pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4585 	   pos = nlp->varmap_nlp2nlpi[pos];
4586 	   assert(pos >= 0);
4587 	
4588 	   /* set new bounds in NLPI */
4589 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
4590 	
4591 	   return SCIP_OKAY;
4592 	}
4593 	
4594 	/** changes bounds of a set of variables in diving NLP */
4595 	SCIP_RETCODE SCIPnlpChgVarsBoundsDive(
4596 	   SCIP_NLP*             nlp,                /**< current NLP data */
4597 	   SCIP_SET*             set,                /**< global SCIP settings */
4598 	   int                   nvars,              /**< number of variables which bounds to change */
4599 	   SCIP_VAR**            vars,               /**< variables which bounds to change */
4600 	   SCIP_Real*            lbs,                /**< new lower bounds of variables */
4601 	   SCIP_Real*            ubs                 /**< new upper bounds of variables */
4602 	   )
4603 	{
4604 	   int i;
4605 	   int* poss;
4606 	
4607 	   assert(nlp  != NULL);
4608 	   assert(vars != NULL || nvars == 0);
4609 	   assert(nlp->indiving);
4610 	   assert(lbs  != NULL || nvars == 0);
4611 	   assert(ubs  != NULL || nvars == 0);
4612 	   assert(nlp->solver != NULL);
4613 	   assert(nlp->problem != NULL);
4614 	
4615 	   if( nvars == 0 )
4616 	      return SCIP_OKAY;
4617 	
4618 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &poss, nvars) );
4619 	
4620 	   for( i = 0; i < nvars; ++i )
4621 	   {
4622 	      assert(SCIPhashmapExists(nlp->varhash, vars[i]));  /*lint !e613*/
4623 	
4624 	      /* get position of variable in NLPI problem */
4625 	      poss[i] = SCIPhashmapGetImageInt(nlp->varhash, vars[i]);   /*lint !e613*/
4626 	      poss[i] = nlp->varmap_nlp2nlpi[poss[i]];
4627 	      assert(poss[i] >= 0);
4628 	   }
4629 	
4630 	   /* set new bounds in NLPI */
4631 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nvars, poss, lbs, ubs) );
4632 	
4633 	   SCIPsetFreeBufferArray(set, &poss);
4634 	
4635 	   return SCIP_OKAY;
4636 	}
4637 	
4638 	/** returns whether the objective function has been changed during diving */
4639 	SCIP_Bool SCIPnlpIsDivingObjChanged(
4640 	   SCIP_NLP*             nlp                 /**< current NLP data */
4641 	   )
4642 	{
4643 	   return nlp->divingobj != NULL;
4644 	}
4645