1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 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 	#ifdef NDEBUG
1737 	/* Undo the defines from pub_nlhdlr.h, which exist if NDEBUG is defined. */
1738 	#undef SCIPnlrowGetConstant
1739 	#undef SCIPnlrowGetNLinearVars
1740 	#undef SCIPnlrowGetLinearVars
1741 	#undef SCIPnlrowGetLinearCoefs
1742 	#undef SCIPnlrowGetExpr
1743 	#undef SCIPnlrowGetLhs
1744 	#undef SCIPnlrowGetRhs
1745 	#undef SCIPnlrowGetCurvature
1746 	#undef SCIPnlrowSetCurvature
1747 	#undef SCIPnlrowGetName
1748 	#undef SCIPnlrowGetNLPPos
1749 	#undef SCIPnlrowIsInNLP
1750 	#undef SCIPnlrowGetDualsol
1751 	#endif
1752 	
1753 	/** gets constant */
1754 	SCIP_Real SCIPnlrowGetConstant(
1755 	   SCIP_NLROW*           nlrow               /**< NLP row */
1756 	   )
1757 	{
1758 	   assert(nlrow != NULL);
1759 	
1760 	   return nlrow->constant;
1761 	}
1762 	
1763 	/** gets number of variables of linear part */
1764 	int SCIPnlrowGetNLinearVars(
1765 	   SCIP_NLROW*           nlrow               /**< NLP row */
1766 	   )
1767 	{
1768 	   assert(nlrow != NULL);
1769 	
1770 	   return nlrow->nlinvars;
1771 	}
1772 	
1773 	/** gets array with variables of linear part */
1774 	SCIP_VAR** SCIPnlrowGetLinearVars(
1775 	   SCIP_NLROW*           nlrow               /**< NLP row */
1776 	   )
1777 	{
1778 	   assert(nlrow != NULL);
1779 	
1780 	   return nlrow->linvars;
1781 	}
1782 	
1783 	/** gets array with coefficients in linear part */
1784 	SCIP_Real* SCIPnlrowGetLinearCoefs(
1785 	   SCIP_NLROW*           nlrow               /**< NLP row */
1786 	   )
1787 	{
1788 	   assert(nlrow != NULL);
1789 	
1790 	   return nlrow->lincoefs;
1791 	}
1792 	
1793 	/** gets expression */
1794 	SCIP_EXPR* SCIPnlrowGetExpr(
1795 	   SCIP_NLROW*           nlrow               /**< NLP row */
1796 	   )
1797 	{
1798 	   assert(nlrow != NULL);
1799 	
1800 	   return nlrow->expr;
1801 	}
1802 	
1803 	/** returns the left hand side of a nonlinear row */
1804 	SCIP_Real SCIPnlrowGetLhs(
1805 	   SCIP_NLROW*           nlrow               /**< NLP row */
1806 	   )
1807 	{
1808 	   assert(nlrow != NULL);
1809 	
1810 	   return nlrow->lhs;
1811 	}
1812 	
1813 	/** returns the right hand side of a nonlinear row */
1814 	SCIP_Real SCIPnlrowGetRhs(
1815 	   SCIP_NLROW*           nlrow               /**< NLP row */
1816 	   )
1817 	{
1818 	   assert(nlrow != NULL);
1819 	
1820 	   return nlrow->rhs;
1821 	}
1822 	
1823 	/** returns the curvature of a nonlinear row */
1824 	SCIP_EXPRCURV SCIPnlrowGetCurvature(
1825 	   SCIP_NLROW*           nlrow               /**< NLP row */
1826 	   )
1827 	{
1828 	   assert(nlrow != NULL);
1829 	   return nlrow->curvature;
1830 	}
1831 	
1832 	/** sets the curvature of a nonlinear row */
1833 	void SCIPnlrowSetCurvature(
1834 	   SCIP_NLROW*           nlrow,              /**< NLP row */
1835 	   SCIP_EXPRCURV         curvature           /**< curvature of NLP row */
1836 	   )
1837 	{
1838 	   assert(nlrow != NULL);
1839 	   nlrow->curvature = curvature;
1840 	}
1841 	
1842 	/** returns the name of a nonlinear row */
1843 	const char* SCIPnlrowGetName(
1844 	   SCIP_NLROW*           nlrow               /**< NLP row */
1845 	   )
1846 	{
1847 	   assert(nlrow != NULL);
1848 	
1849 	   return nlrow->name;
1850 	}
1851 	
1852 	/** gets position of a nonlinear row in current NLP, or -1 if not in NLP */
1853 	int SCIPnlrowGetNLPPos(
1854 	   SCIP_NLROW*           nlrow               /**< NLP row */
1855 	   )
1856 	{
1857 	   assert(nlrow != NULL);
1858 	
1859 	   return nlrow->nlpindex;
1860 	}
1861 	
1862 	/** returns TRUE iff row is member of current NLP */
1863 	SCIP_Bool SCIPnlrowIsInNLP(
1864 	   SCIP_NLROW*           nlrow               /**< NLP row */
1865 	   )
1866 	{
1867 	   assert(nlrow != NULL);
1868 	
1869 	   return nlrow->nlpindex != -1;
1870 	}
1871 	
1872 	/** gets the dual NLP solution of a nlrow
1873 	 *
1874 	 * 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
1875 	 */
1876 	SCIP_Real SCIPnlrowGetDualsol(
1877 	   SCIP_NLROW*           nlrow               /**< NLP row */
1878 	   )
1879 	{
1880 	   assert(nlrow != NULL);
1881 	
1882 	   return nlrow->nlpiindex >= 0 ? nlrow->dualsol : 0.0;
1883 	}
1884 	
1885 	/** @} */
1886 	
1887 	/*
1888 	 * local NLP methods
1889 	 */
1890 	
1891 	/** announces, that a row of the NLP was modified
1892 	 * adjusts status of current solution
1893 	 * calling method has to ensure that change is passed to the NLPI!
1894 	 */ /*lint -e{715}*/
1895 	static
1896 	SCIP_RETCODE nlpRowChanged(
1897 	   SCIP_NLP*             nlp,                /**< current NLP data */
1898 	   SCIP_SET*             set,                /**< global SCIP settings */
1899 	   SCIP_STAT*            stat,               /**< problem statistics data */
1900 	   SCIP_NLROW*           nlrow               /**< nonlinear row which was changed */
1901 	   )
1902 	{  /*lint --e{715}*/
1903 	   assert(nlp != NULL);
1904 	   assert(nlrow != NULL);
1905 	   assert(!nlp->indiving);
1906 	   assert(nlrow->nlpindex >= 0);
1907 	
1908 	   /* nlrow is a row in the NLP, so changes effect feasibility */
1909 	   /* if we have a feasible NLP solution and it satisfies the modified row, then it is still feasible
1910 	    * if the NLP was globally or locally infeasible or unbounded, then this may not be the case anymore
1911 	    */
1912 	   if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1913 	   {
1914 	      /* TODO bring this back? then everything that may call nlpRowChanged will need to pass on blkmem, primal, tree as well
1915 	      SCIP_Real feasibility;
1916 	      SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1917 	      if( !SCIPsetIsFeasNegative(set, feasibility) )
1918 	         nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
1919 	      else */
1920 	      nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
1921 	   }
1922 	   else
1923 	   {
1924 	      nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
1925 	   }
1926 	
1927 	   return SCIP_OKAY;
1928 	}
1929 	
1930 	/** adds a set of nonlinear rows to the NLP and captures them */
1931 	static
1932 	SCIP_RETCODE nlpAddNlRows(
1933 	   SCIP_NLP*             nlp,                /**< NLP data */
1934 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1935 	   SCIP_SET*             set,                /**< global SCIP settings */
1936 	   SCIP_STAT*            stat,               /**< problem statistics data */
1937 	   int                   nnlrows,            /**< number of nonlinear rows to add */
1938 	   SCIP_NLROW**          nlrows              /**< nonlinear rows to add */
1939 	   )
1940 	{
1941 	#ifndef NDEBUG
1942 	   int i;
1943 	#endif
1944 	   int j;
1945 	   SCIP_NLROW* nlrow;
1946 	
1947 	   assert(nlp    != NULL);
1948 	   assert(blkmem != NULL);
1949 	   assert(set    != NULL);
1950 	   assert(nlrows != NULL || nnlrows == 0);
1951 	   assert(!nlp->indiving);
1952 	
1953 	   SCIP_CALL( SCIPnlpEnsureNlRowsSize(nlp, blkmem, set, nlp->nnlrows + nnlrows) );
1954 	
1955 	   for( j = 0; j < nnlrows; ++j )
1956 	   {
1957 	      nlrow = nlrows[j];  /*lint !e613*/
1958 	
1959 	      /* assert that row is not in NLP (or even NLPI) yet */
1960 	      assert(nlrow->nlpindex == -1);
1961 	      assert(nlrow->nlpiindex == -1);
1962 	
1963 	      /* make sure there are only active variables in row */
1964 	      SCIP_CALL( SCIPnlrowSimplify(nlrow, blkmem, set, stat, nlp) );
1965 	
1966 	#ifndef NDEBUG
1967 	      /* assert that variables of row are in NLP */
1968 	      for( i = 0; i < nlrow->nlinvars; ++i )
1969 	         assert(SCIPhashmapExists(nlp->varhash, nlrow->linvars[i]));
1970 	
1971 	      if( nlrow->expr != NULL )
1972 	      {
1973 	         SCIP_EXPRITER* it;
1974 	         SCIP_EXPR* expr;
1975 	
1976 	         SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
1977 	         SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
1978 	         for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
1979 	            assert(!SCIPexprIsVar(set, expr) || SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
1980 	         SCIPexpriterFree(&it);
1981 	      }
1982 	#endif
1983 	
1984 	      /* add row to NLP and capture it */
1985 	      nlp->nlrows[nlp->nnlrows + j] = nlrow;
1986 	      nlrow->nlpindex = nlp->nnlrows + j;
1987 	
1988 	      SCIPnlrowCapture(nlrow);
1989 	
1990 	      /* if we have a feasible NLP solution and it satisfies the new solution, then it is still feasible
1991 	       * if the NLP was globally or locally infeasible, then it stays that way
1992 	       * if the NLP was unbounded, then this may not be the case anymore
1993 	       */
1994 	      if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
1995 	      {
1996 	         /* TODO bring this back? then everything that may call nlpAddNlRows will need to pass on primal, tree as well
1997 	         SCIP_Real feasibility;
1998 	         SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) );
1999 	         if( !SCIPsetIsFeasNegative(set, feasibility) )
2000 	            nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2001 	         else
2002 	         */
2003 	         nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2004 	      }
2005 	      else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2006 	      {
2007 	         nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2008 	      }
2009 	   }
2010 	
2011 	   nlp->nnlrows += nnlrows;
2012 	   nlp->nunflushednlrowadd += nnlrows;
2013 	
2014 	   return SCIP_OKAY;
2015 	}
2016 	
2017 	/** moves a nonlinear row to a different place, and updates all corresponding data structures */
2018 	static
2019 	void nlpMoveNlrow(
2020 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2021 	   int                   oldpos,             /**< old position of nonlinear row */
2022 	   int                   newpos              /**< new position of nonlinear row */
2023 	   )
2024 	{
2025 	   assert(nlp != NULL);
2026 	   assert(0 <= oldpos && oldpos < nlp->nnlrows);
2027 	   assert(0 <= newpos && newpos < nlp->nnlrows);
2028 	   assert(nlp->nlrows[oldpos] != NULL);
2029 	
2030 	   if( oldpos == newpos )
2031 	      return;
2032 	
2033 	   nlp->nlrows[newpos] = nlp->nlrows[oldpos];
2034 	   nlp->nlrows[newpos]->nlpindex = newpos;
2035 	
2036 	   /* update nlpi to nlp row index mapping */
2037 	   if( nlp->nlrows[newpos]->nlpiindex >= 0 )
2038 	   {
2039 	      assert(nlp->nlrowmap_nlpi2nlp != NULL);
2040 	      assert(nlp->nlrows[newpos]->nlpiindex < nlp->sizenlrows_solver);
2041 	      nlp->nlrowmap_nlpi2nlp[nlp->nlrows[newpos]->nlpiindex] = newpos;
2042 	   }
2043 	}
2044 	
2045 	/** deletes nonlinear row with given position from NLP */
2046 	static
2047 	SCIP_RETCODE nlpDelNlRowPos(
2048 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2049 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2050 	   SCIP_SET*             set,                /**< global SCIP settings */
2051 	   SCIP_STAT*            stat,               /**< problem statistics data */
2052 	   int                   pos                 /**< position of nonlinear row that is to be removed */
2053 	   )
2054 	{
2055 	   SCIP_NLROW* nlrow;
2056 	
2057 	   assert(nlp != NULL);
2058 	   assert(blkmem != NULL);
2059 	   assert(set != NULL);
2060 	   assert(pos >= 0);
2061 	   assert(pos < nlp->nnlrows);
2062 	   assert(!nlp->indiving);
2063 	   assert(nlp->nlrows != NULL);
2064 	
2065 	   nlrow = nlp->nlrows[pos];
2066 	   assert(nlrow != NULL);
2067 	   assert(nlrow->nlpindex == pos);
2068 	
2069 	   /* if row is in NLPI, then mark that it has to be removed in the next flush
2070 	    * if row was not in NLPI yet, then we have one unflushed nlrow addition less */
2071 	   if( nlrow->nlpiindex >= 0 )
2072 	   {
2073 	      assert(nlrow->nlpiindex < nlp->nnlrows_solver);
2074 	      nlp->nlrowmap_nlpi2nlp[nlrow->nlpiindex] = -1;
2075 	      nlrow->nlpiindex = -1;
2076 	      ++nlp->nunflushednlrowdel;
2077 	   }
2078 	   else
2079 	   {
2080 	      assert(nlrow->nlpiindex == -1);
2081 	      --nlp->nunflushednlrowadd;
2082 	   }
2083 	
2084 	   /* move NLP row from the end to pos and mark nlrow to be not in NLP anymore */
2085 	   nlpMoveNlrow(nlp, nlp->nnlrows-1, pos);
2086 	   nlrow->nlpindex = -1;
2087 	
2088 	   /* forget about restriction */
2089 	   SCIP_CALL( SCIPnlrowRelease(&nlrow, blkmem, set, stat) );
2090 	   --nlp->nnlrows;
2091 	
2092 	   if( nlp->solstat < SCIP_NLPSOLSTAT_LOCOPT )
2093 	      nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2094 	   else if( nlp->solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
2095 	      nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2096 	
2097 	   return SCIP_OKAY; /*lint !e438*/
2098 	}
2099 	
2100 	/** updates bounds on a variable in the NLPI problem */
2101 	static
2102 	SCIP_RETCODE nlpUpdateVarBounds(
2103 	   SCIP_NLP*             nlp,                /**< NLP data */
2104 	   SCIP_SET*             set,                /**< global SCIP settings */
2105 	   SCIP_VAR*             var,                /**< variable which bounds have changed */
2106 	   SCIP_Bool             tightened           /**< whether the bound change was a bound tightening */
2107 	   )
2108 	{
2109 	   int pos;
2110 	   SCIP_Real lb;
2111 	   SCIP_Real ub;
2112 	
2113 	   assert(nlp != NULL);
2114 	   assert(var != NULL);
2115 	   assert(SCIPhashmapExists(nlp->varhash, var));
2116 	
2117 	   /* original variable bounds are ignored during diving
2118 	    * (all variable bounds are reset to their current value in exitDiving) */
2119 	   if( nlp->indiving )
2120 	      return SCIP_OKAY;
2121 	
2122 	   /* get position of variable in NLP */
2123 	   pos = SCIPhashmapGetImageInt(nlp->varhash, var);
2124 	
2125 	   /* if variable not in NLPI yet, nothing to do */
2126 	   if( nlp->varmap_nlp2nlpi[pos] == -1 )
2127 	      return SCIP_OKAY;
2128 	
2129 	   /* update bounds in NLPI problem */
2130 	   assert(nlp->solver != NULL);
2131 	   assert(nlp->problem != NULL);
2132 	
2133 	   pos = nlp->varmap_nlp2nlpi[pos];
2134 	   lb = SCIPvarGetLbLocal(var);
2135 	   ub = SCIPvarGetUbLocal(var);
2136 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
2137 	
2138 	   /* if we have a feasible NLP solution and it satisfies the new bounds, then it is still feasible
2139 	    * if the NLP was globally or locally infeasible and we tightened a bound, then it stays that way
2140 	    * if the NLP was unbounded and we tightened a bound, then this may not be the case anymore
2141 	    */
2142 	   if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2143 	   {
2144 	      if( !tightened ||
2145 	         ((SCIPsetIsInfinity(set, -lb) || SCIPsetIsFeasLE(set, lb, SCIPvarGetNLPSol(var))) &&
2146 	          (SCIPsetIsInfinity(set,  ub) || SCIPsetIsFeasGE(set, ub, SCIPvarGetNLPSol(var)))) )
2147 	         nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2148 	      else
2149 	         nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE;
2150 	   }
2151 	   else if( !tightened || nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2152 	   {
2153 	      nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2154 	   }
2155 	
2156 	   return SCIP_OKAY;
2157 	}
2158 	
2159 	/** updates coefficient of a variable in the objective */
2160 	static
2161 	SCIP_RETCODE nlpUpdateObjCoef(
2162 	   SCIP_SET*             set,                /**< global SCIP settings */
2163 	   SCIP_NLP*             nlp,                /**< NLP data */
2164 	   SCIP_VAR*             var                 /**< variable which bounds have changed */
2165 	   )
2166 	{
2167 	   int pos;
2168 	   int objidx;
2169 	   SCIP_Real coef;
2170 	
2171 	   assert(nlp != NULL);
2172 	   assert(var != NULL);
2173 	   assert(SCIPhashmapExists(nlp->varhash, var));
2174 	
2175 	   /* if the objective in the NLPI is not up to date, then we do not need to do something here */
2176 	   if( !nlp->objflushed )
2177 	      return SCIP_OKAY;
2178 	
2179 	   /* original objective is ignored during diving
2180 	    * we just need to remember that at end of diving we have to flush the objective */
2181 	   if( nlp->indiving )
2182 	   {
2183 	      nlp->objflushed = FALSE;
2184 	      return SCIP_OKAY;
2185 	   }
2186 	
2187 	   /* get position of variable in NLP and objective coefficient */
2188 	   pos  = SCIPhashmapGetImageInt(nlp->varhash, var);
2189 	   assert(nlp->varmap_nlp2nlpi[pos] == -1 || nlp->solver != NULL);
2190 	
2191 	   /* actually we only need to remember flushing the objective if we also have an NLPI */
2192 	   if( nlp->solver == NULL )
2193 	      return SCIP_OKAY;
2194 	
2195 	   coef = SCIPvarGetObj(var);
2196 	
2197 	   /* if variable not in NLPI yet, then we only need to remember to update the objective after variable additions were flushed */
2198 	   if( nlp->varmap_nlp2nlpi[pos] == -1 && coef != 0.0 )
2199 	   {
2200 	      nlp->objflushed = FALSE;
2201 	
2202 	      return SCIP_OKAY;
2203 	   }
2204 	
2205 	   /* if we are here, then the objective in the NLPI is up to date,
2206 	    * we keep it this way by changing the coefficient of var in the NLPI problem objective */
2207 	   assert(nlp->solver != NULL);
2208 	   assert(nlp->problem != NULL);
2209 	
2210 	   pos = nlp->varmap_nlp2nlpi[pos];
2211 	   objidx = -1;
2212 	   SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
2213 	
2214 	   /* if we had a solution and it was locally (or globally) optimal, then now we can only be sure that it is still feasible */
2215 	   if( nlp->solstat < SCIP_NLPSOLSTAT_FEASIBLE )
2216 	      nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2217 	
2218 	   return SCIP_OKAY;
2219 	}
2220 	
2221 	/** adds new variables to the NLP */
2222 	static
2223 	SCIP_RETCODE nlpAddVars(
2224 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2225 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2226 	   SCIP_SET*             set,                /**< global SCIP settings */
2227 	   int                   nvars,              /**< number of variables to add */
2228 	   SCIP_VAR**            vars                /**< variable to add to NLP */
2229 	   )
2230 	{
2231 	   int i;
2232 	   SCIP_VAR* var;
2233 	
2234 	   assert(nlp    != NULL);
2235 	   assert(blkmem != NULL);
2236 	   assert(set    != NULL);
2237 	   assert(vars   != NULL || nvars == 0);
2238 	   assert(!nlp->indiving || nvars == 0);
2239 	
2240 	   if( nvars == 0 )
2241 	      return SCIP_OKAY;
2242 	
2243 	   SCIP_CALL( SCIPnlpEnsureVarsSize(nlp, blkmem, set, nlp->nvars + nvars) );
2244 	   assert(nlp->sizevars >= nlp->nvars + nvars);
2245 	
2246 	   for( i = 0; i < nvars; ++i )
2247 	   {
2248 	      var = vars[i];  /*lint !e613*/
2249 	
2250 	      assert(SCIPvarIsTransformed(var));
2251 	      assert(SCIPvarIsActive(var));
2252 	      assert(!SCIPhashmapExists(nlp->varhash, var));
2253 	
2254 	      SCIPvarCapture(var);
2255 	
2256 	      nlp->vars[nlp->nvars+i]            = var;
2257 	      nlp->varmap_nlp2nlpi[nlp->nvars+i] = -1;
2258 	      SCIP_CALL( SCIPhashmapInsertInt(nlp->varhash, var, nlp->nvars+i) );
2259 	
2260 	      nlp->varlbdualvals[nlp->nvars+i]   = 0.0;
2261 	      nlp->varubdualvals[nlp->nvars+i]   = 0.0;
2262 	
2263 	      /* update objective, if necessary (new variables have coefficient 0.0 anyway) */
2264 	      if( SCIPvarGetObj(var) != 0.0 )
2265 	      {
2266 	         SCIP_CALL( nlpUpdateObjCoef(set, nlp, var) );
2267 	      }
2268 	
2269 	      /* let's keep the previous initial guess and set it for the new variable to the best bound
2270 	       * (since there can be no row that uses this variable yet, this seems a good guess) */
2271 	      if( nlp->haveinitguess )
2272 	      {
2273 	         assert(nlp->initialguess != NULL);
2274 	
2275 	         nlp->initialguess[nlp->nvars+i] = SCIPvarGetBestBoundLocal(var);
2276 	      }
2277 	
2278 	      /* if we have a feasible NLP solution, then it remains feasible
2279 	       * but we have to update the objective function
2280 	       */
2281 	      if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2282 	      {
2283 	         SCIP_CALL( SCIPvarSetNLPSol(var, set, SCIPvarGetBestBoundLocal(var)) );
2284 	         nlp->primalsolobjval += SCIPvarGetObj(var) * SCIPvarGetBestBoundLocal(var);
2285 	         nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE;
2286 	      }
2287 	
2288 	      /* catch events on variable */
2289 	      SCIP_CALL( SCIPvarCatchEvent(var, blkmem, set, \
2290 	            SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2291 	            nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, NULL) ); /* @todo should store event filter position in nlp? */
2292 	   }
2293 	
2294 	   nlp->nvars += nvars;
2295 	   nlp->nunflushedvaradd += nvars;
2296 	
2297 	   return SCIP_OKAY;
2298 	}
2299 	
2300 	/** moves a variable to a different place, and updates all corresponding data structures */
2301 	static
2302 	SCIP_RETCODE nlpMoveVar(
2303 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2304 	   int                   oldpos,             /**< old position of variable */
2305 	   int                   newpos              /**< new position of variable */
2306 	   )
2307 	{
2308 	   int nlpipos;
2309 	
2310 	   assert(nlp != NULL);
2311 	   assert(0 <= oldpos && oldpos < nlp->nvars);
2312 	   assert(0 <= newpos && newpos < nlp->nvars);
2313 	   assert(nlp->vars[oldpos] != NULL);
2314 	
2315 	   if( oldpos == newpos )
2316 	      return SCIP_OKAY;
2317 	
2318 	   SCIP_CALL( SCIPhashmapSetImageInt(nlp->varhash, nlp->vars[oldpos], newpos) );
2319 	   nlp->vars[newpos]            = nlp->vars[oldpos];
2320 	   nlp->varmap_nlp2nlpi[newpos] = nlp->varmap_nlp2nlpi[oldpos];
2321 	   nlp->varlbdualvals[newpos]   = nlp->varlbdualvals[oldpos];
2322 	   nlp->varubdualvals[newpos]   = nlp->varubdualvals[oldpos];
2323 	   if( nlp->initialguess != NULL )
2324 	      nlp->initialguess[newpos] = nlp->initialguess[oldpos];
2325 	
2326 	   nlpipos = nlp->varmap_nlp2nlpi[newpos];
2327 	   if( nlpipos > 0 )
2328 	      nlp->varmap_nlpi2nlp[nlpipos] = newpos;
2329 	
2330 	   return SCIP_OKAY;
2331 	}
2332 	
2333 	/** deletes variable with given position from NLP */
2334 	static
2335 	SCIP_RETCODE nlpDelVarPos(
2336 	   SCIP_NLP*             nlp,                /**< NLP data structure */
2337 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2338 	   SCIP_SET*             set,                /**< global SCIP settings */
2339 	   SCIP_STAT*            stat,               /**< problem statistics data */
2340 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2341 	   SCIP_LP*              lp,                 /**< SCIP LP, needed if a column-variable is freed */
2342 	   int                   pos                 /**< position of nonlinear row that is to be removed */
2343 	   )
2344 	{
2345 	   SCIP_VAR* var;
2346 	#ifndef NDEBUG
2347 	   int i;
2348 	#endif
2349 	   int nlpipos;
2350 	
2351 	   assert(nlp    != NULL);
2352 	   assert(blkmem != NULL);
2353 	   assert(set    != NULL);
2354 	   assert(pos >= 0);
2355 	   assert(pos < nlp->nvars);
2356 	   assert(!nlp->indiving);
2357 	
2358 	   var = nlp->vars[pos];
2359 	   assert(var != NULL);
2360 	
2361 	#ifndef NDEBUG
2362 	   /* assert that variable is not used by any nonlinear row */
2363 	   for( i = 0; i < nlp->nnlrows; ++i )
2364 	   {
2365 	      int j;
2366 	      SCIP_NLROW* nlrow;
2367 	
2368 	      nlrow = nlp->nlrows[i];
2369 	      assert(nlrow != NULL);
2370 	
2371 	      /* use nlrowSearchLinearCoef only if already sorted, since otherwise we may change the solving process slightly */
2372 	      if( nlrow->linvarssorted )
2373 	         assert( nlrowSearchLinearCoef(nlrow, var) == -1 );
2374 	      else
2375 	         for( j = 0; j < nlrow->nlinvars; ++j )
2376 	            assert( nlrow->linvars[j] != var );
2377 	
2378 	      if( nlrow->expr != NULL )
2379 	      {
2380 	         SCIP_EXPRITER* it;
2381 	         SCIP_EXPR* expr;
2382 	         SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2383 	         SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) );
2384 	         for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2385 	            assert(!SCIPexprIsVar(set, expr) || SCIPgetVarExprVar(expr) != var);
2386 	         SCIPexpriterFree(&it);
2387 	      }
2388 	   }
2389 	#endif
2390 	
2391 	   /* if we had a feasible solution, then adjust objective function value
2392 	    * if NLP was unbounded before, then maybe it is not anymore */
2393 	   if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2394 	      nlp->primalsolobjval -= SCIPvarGetObj(var) * SCIPvarGetNLPSol(var);
2395 	   else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED )
2396 	      nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN;
2397 	
2398 	   /* if variable is in NLPI problem, mark that we have to remember to delete it there
2399 	    * if it was not in the NLPI yet, then we have one unflushed var addition less now */
2400 	   nlpipos = nlp->varmap_nlp2nlpi[pos];
2401 	   if( nlpipos >= 0 )
2402 	   {
2403 	      assert(nlpipos < nlp->nvars_solver);
2404 	
2405 	      nlp->varmap_nlpi2nlp[nlpipos] = -1;
2406 	      ++nlp->nunflushedvardel;
2407 	   }
2408 	   else
2409 	      --nlp->nunflushedvaradd;
2410 	
2411 	   /* drop events on variable */
2412 	   SCIP_CALL( SCIPvarDropEvent(var, blkmem, set, \
2413 	         SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \
2414 	         nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, -1) );
2415 	
2416 	   /* move variable from end to pos */
2417 	   SCIP_CALL( nlpMoveVar(nlp, nlp->nvars-1, pos) );
2418 	
2419 	   /* forget about variable */
2420 	   SCIP_CALL( SCIPhashmapRemove(nlp->varhash, var) );
2421 	   SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
2422 	   --nlp->nvars;
2423 	
2424 	   return SCIP_OKAY;
2425 	}
2426 	
2427 	/** notifies NLP that a variable was fixed, so it is removed from objective, all rows, and the NLP variables */
2428 	static
2429 	SCIP_RETCODE nlpRemoveFixedVar(
2430 	   SCIP_NLP*             nlp,                /**< NLP data */
2431 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2432 	   SCIP_SET*             set,                /**< global SCIP settings */
2433 	   SCIP_STAT*            stat,               /**< problem statistics data */
2434 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2435 	   SCIP_LP*              lp,                 /**< SCIP LP, needed to release variable */
2436 	   SCIP_VAR*             var                 /**< variable that has been fixed */
2437 	   )
2438 	{
2439 	   int i;
2440 	
2441 	   assert(nlp != NULL);
2442 	   assert(var != NULL);
2443 	   assert(!SCIPvarIsActive(var));
2444 	   assert(!nlp->indiving);
2445 	   assert(SCIPhashmapExists(nlp->varhash, var));
2446 	
2447 	   /* remove var from all rows */
2448 	   for( i = 0; i < nlp->nnlrows; ++i )
2449 	   {
2450 	      SCIP_CALL( nlrowRemoveFixedVar(nlp->nlrows[i], blkmem, set, stat, nlp, var) );
2451 	   }
2452 	
2453 	   /* remove variable from NLP */
2454 	   SCIP_CALL( SCIPnlpDelVar(nlp, blkmem, set, stat, eventqueue, lp, var) );
2455 	
2456 	   return SCIP_OKAY;
2457 	}
2458 	
2459 	/** creates arrays with NLPI variable indices of linear variables in a nonlinear row */
2460 	static
2461 	SCIP_RETCODE nlpSetupNlpiIndices(
2462 	   SCIP_NLP*             nlp,                /**< NLP data */
2463 	   SCIP_SET*             set,                /**< global SCIP settings */
2464 	   SCIP_NLROW*           nlrow,              /**< nonlinear row */
2465 	   int**                 linidxs             /**< buffer to store pointer to NLPI indices of linear variables */
2466 	   )
2467 	{
2468 	   int i;
2469 	   SCIP_VAR* var;
2470 	
2471 	   assert(nlp    != NULL);
2472 	   assert(set    != NULL);
2473 	   assert(nlrow  != NULL);
2474 	   assert(linidxs   != NULL);
2475 	
2476 	   /* get indices of variables in linear part of row */
2477 	   if( nlrow->nlinvars > 0 )
2478 	   {
2479 	      assert(nlrow->linvars  != NULL);
2480 	      assert(nlrow->lincoefs != NULL);
2481 	
2482 	      SCIP_CALL( SCIPsetAllocBufferArray(set, linidxs, nlrow->nlinvars) );
2483 	
2484 	      for( i = 0; i < nlrow->nlinvars; ++i )
2485 	      {
2486 	         var = nlrow->linvars[i];
2487 	         assert(var != NULL);
2488 	         assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */
2489 	
2490 	         assert(SCIPhashmapExists(nlp->varhash, var));
2491 	         (*linidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)];
2492 	         assert((*linidxs)[i] >= 0);
2493 	      }
2494 	   }
2495 	   else
2496 	      *linidxs = NULL;
2497 	
2498 	   return SCIP_OKAY;
2499 	}
2500 	
2501 	/** ensures, that NLPI variables array of NLP can store at least num entries */
2502 	static
2503 	SCIP_RETCODE nlpEnsureVarsSolverSize(
2504 	   SCIP_NLP*             nlp,                /**< NLP data */
2505 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2506 	   SCIP_SET*             set,                /**< global SCIP settings */
2507 	   int                   num                 /**< minimum number of entries to store */
2508 	   )
2509 	{
2510 	   assert(nlp    != NULL);
2511 	   assert(blkmem != NULL);
2512 	   assert(set    != NULL);
2513 	   assert(nlp->nvars_solver <= nlp->sizevars_solver);
2514 	
2515 	   if( num > nlp->sizevars_solver )
2516 	   {
2517 	      int newsize;
2518 	
2519 	      newsize = SCIPsetCalcMemGrowSize(set, num);
2520 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlpi2nlp, nlp->sizevars_solver, newsize) );
2521 	
2522 	      nlp->sizevars_solver = newsize;
2523 	   }
2524 	   assert(num <= nlp->sizevars_solver);
2525 	
2526 	   return SCIP_OKAY;
2527 	}
2528 	
2529 	/** ensures, that NLPI nonlinear rows array of NLP can store at least num entries */
2530 	static
2531 	SCIP_RETCODE nlpEnsureNlRowsSolverSize(
2532 	   SCIP_NLP*             nlp,                /**< NLP data */
2533 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2534 	   SCIP_SET*             set,                /**< global SCIP settings */
2535 	   int                   num                 /**< minimum number of entries to store */
2536 	   )
2537 	{
2538 	   assert(nlp    != NULL);
2539 	   assert(blkmem != NULL);
2540 	   assert(set    != NULL);
2541 	   assert(nlp->nnlrows_solver <= nlp->sizenlrows_solver);
2542 	
2543 	   if( num > nlp->sizenlrows_solver )
2544 	   {
2545 	      int newsize;
2546 	
2547 	      newsize = SCIPsetCalcMemGrowSize(set, num);
2548 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrowmap_nlpi2nlp, nlp->sizenlrows_solver, newsize) );
2549 	
2550 	      nlp->sizenlrows_solver = newsize;
2551 	   }
2552 	   assert(num <= nlp->sizenlrows_solver);
2553 	
2554 	   return SCIP_OKAY;
2555 	}
2556 	
2557 	/** deletes rows from the NLPI problem that have been marked as to remove */
2558 	static
2559 	SCIP_RETCODE nlpFlushNlRowDeletions(
2560 	   SCIP_NLP*             nlp,                /**< NLP data */
2561 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2562 	   SCIP_SET*             set                 /**< global SCIP settings */
2563 	   )
2564 	{
2565 	   int         j;
2566 	   int         c;      /* counts the number of rows to delete */
2567 	   int*        rowset; /* marks which rows to delete and stores new indices */
2568 	   SCIP_NLROW* nlrow;
2569 	
2570 	   assert(nlp    != NULL);
2571 	   assert(blkmem != NULL);
2572 	   assert(set    != NULL);
2573 	   assert(nlp->nunflushednlrowdel >= 0);
2574 	   assert(!nlp->indiving);
2575 	
2576 	   if( nlp->nunflushednlrowdel == 0 )
2577 	   {
2578 	#ifndef NDEBUG
2579 	      /* check that there are really no pending removals of nonlinear rows */
2580 	      for( j = 0; j < nlp->nnlrows_solver; ++j )
2581 	         assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2582 	#endif
2583 	      return SCIP_OKAY;
2584 	   }
2585 	
2586 	   assert(nlp->solver != NULL);
2587 	   assert(nlp->problem != NULL);
2588 	
2589 	   /* create marker which rows have to be deleted */
2590 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &rowset, nlp->nnlrows_solver) );
2591 	   c = 0;
2592 	   for( j = 0; j < nlp->nnlrows_solver; ++j )
2593 	   {
2594 	      if( nlp->nlrowmap_nlpi2nlp[j] == -1 )
2595 	      {
2596 	         rowset[j] = 1;
2597 	         ++c;
2598 	      }
2599 	      else
2600 	         rowset[j] = 0;
2601 	   }
2602 	   assert(c == nlp->nunflushednlrowdel);
2603 	
2604 	   /* remove rows from NLPI problem */
2605 	   SCIP_CALL( SCIPnlpiDelConsSet(set, nlp->solver, nlp->problem, rowset, nlp->nnlrows_solver) );
2606 	
2607 	   /* update NLPI row indices */
2608 	   for( j = 0; j < nlp->nnlrows_solver; ++j )
2609 	   {
2610 	      assert(rowset[j] <= j); /* we assume that the NLP solver did not move a row behind its previous position!! */
2611 	      if( rowset[j] < 0 )
2612 	      {
2613 	         /* assert that row was marked as deleted */
2614 	         assert(nlp->nlrowmap_nlpi2nlp[j] == -1);
2615 	      }
2616 	      else if( rowset[j] < j )
2617 	      {
2618 	         /* nlrow at position j moved (forward) to position rowset[j] */
2619 	         assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2620 	         assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2621 	
2622 	         nlrow = nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]];
2623 	         assert(nlrow->nlpiindex == j);
2624 	
2625 	         /* there should be no row at the new position already */
2626 	         assert(nlp->nlrowmap_nlpi2nlp[rowset[j]] == -1);
2627 	
2628 	         nlrow->nlpiindex = rowset[j];
2629 	         nlp->nlrowmap_nlpi2nlp[rowset[j]] = nlrow->nlpindex;
2630 	      }
2631 	      else
2632 	      {
2633 	         /* row j stays at position j */
2634 	         assert(nlp->nlrowmap_nlpi2nlp[j] >= 0);
2635 	         assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows);
2636 	         assert(nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]->nlpiindex == j);
2637 	      }
2638 	   }
2639 	   nlp->nnlrows_solver -= c;
2640 	   nlp->nunflushednlrowdel = 0;
2641 	
2642 	   /* cleanup */
2643 	   SCIPsetFreeBufferArray(set, &rowset);
2644 	
2645 	   return SCIP_OKAY;
2646 	}
2647 	
2648 	/** deletes variables from the NLPI problem that have been marked as to remove
2649 	 *
2650 	 * assumes that there are no pending row deletions (nlpFlushNlRowDeletions() should be called first)
2651 	 */
2652 	static
2653 	SCIP_RETCODE nlpFlushVarDeletions(
2654 	   SCIP_NLP*             nlp,                /**< NLP data */
2655 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2656 	   SCIP_SET*             set                 /**< global SCIP settings */
2657 	   )
2658 	{
2659 	   int  i;
2660 	   int  c;      /* counter on number of variables to remove in solver */
2661 	   int* colset; /* marks which variables to delete and stores new indices */
2662 	
2663 	   assert(nlp    != NULL);
2664 	   assert(blkmem != NULL);
2665 	   assert(set    != NULL);
2666 	   assert(nlp->nunflushedvardel >= 0);
2667 	   assert(nlp->nunflushednlrowdel == 0);
2668 	   assert(!nlp->indiving);
2669 	
2670 	   if( nlp->nunflushedvardel == 0 )
2671 	   {
2672 	#ifndef NDEBUG
2673 	      /* check that there are really no pending removals of variables */
2674 	      for( i = 0; i < nlp->nvars_solver; ++i )
2675 	         assert(nlp->varmap_nlpi2nlp[i] >= 0);
2676 	#endif
2677 	      return SCIP_OKAY;
2678 	   }
2679 	
2680 	   assert(nlp->solver != NULL);
2681 	   assert(nlp->problem != NULL);
2682 	
2683 	   /* create marker which variables have to be deleted */
2684 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &colset, nlp->nvars_solver) );
2685 	   c = 0;
2686 	   for( i = 0; i < nlp->nvars_solver; ++i )
2687 	   {
2688 	      if( nlp->varmap_nlpi2nlp[i] == -1 )
2689 	      {
2690 	         colset[i] = 1;
2691 	         ++c;
2692 	      }
2693 	      else
2694 	         colset[i] = 0;
2695 	   }
2696 	   assert(c == nlp->nunflushedvardel);
2697 	
2698 	   /* delete variables from NLPI problem */
2699 	   SCIP_CALL( SCIPnlpiDelVarSet(set, nlp->solver, nlp->problem, colset, nlp->nvars_solver) );
2700 	
2701 	   /* update NLPI variable indices */
2702 	   for( i = 0; i < nlp->nvars_solver; ++i )
2703 	   {
2704 	      assert(colset[i] <= i); /* we assume that the NLP solver did not move a variable behind its previous position!! */
2705 	      if( colset[i] < 0 )
2706 	      {
2707 	         /* assert that variable was marked as deleted */
2708 	         assert(nlp->varmap_nlpi2nlp[i] == -1);
2709 	      }
2710 	      else if( colset[i] < i)
2711 	      {
2712 	         /* variable at position i moved (forward) to position colset[i] */
2713 	         int varpos;
2714 	
2715 	         varpos = nlp->varmap_nlpi2nlp[i]; /* position of variable i in NLP */
2716 	         assert(varpos >= 0);
2717 	         assert(varpos < nlp->nvars);
2718 	         assert(nlp->varmap_nlp2nlpi[varpos] == i);
2719 	
2720 	         /* there should be no variable at the new position already */
2721 	         assert(nlp->varmap_nlpi2nlp[colset[i]] == -1);
2722 	
2723 	         nlp->varmap_nlp2nlpi[varpos] = colset[i];
2724 	         nlp->varmap_nlpi2nlp[colset[i]] = varpos;
2725 	      }
2726 	      else
2727 	      {
2728 	         /* variable i stays at position i */
2729 	         assert(nlp->varmap_nlpi2nlp[i] >= 0);
2730 	         assert(nlp->varmap_nlpi2nlp[i] < nlp->nvars);
2731 	         assert(nlp->varmap_nlp2nlpi[nlp->varmap_nlpi2nlp[i]] == i);
2732 	      }
2733 	   }
2734 	
2735 	   nlp->nvars_solver -= c;
2736 	   nlp->nunflushedvardel = 0;
2737 	
2738 	   /* cleanup */
2739 	   SCIPsetFreeBufferArray(set, &colset);
2740 	
2741 	   return SCIP_OKAY;
2742 	}
2743 	
2744 	/** adds nonlinear rows to NLPI problem that have been added to NLP before
2745 	 *
2746 	 * assumes that there are no pending variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2747 	 */
2748 	static
2749 	SCIP_RETCODE nlpFlushNlRowAdditions(
2750 	   SCIP_NLP*             nlp,                /**< NLP data */
2751 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2752 	   SCIP_SET*             set,                /**< global SCIP settings */
2753 	   SCIP_STAT*            stat                /**< problem statistics */
2754 	   )
2755 	{
2756 	   int c, i;
2757 	   SCIP_NLROW* nlrow;
2758 	   SCIP_Real*  lhss;
2759 	   SCIP_Real*  rhss;
2760 	   int*        nlinvars;
2761 	   int**       linidxs;
2762 	   SCIP_Real** lincoefs;
2763 	   SCIP_EXPR** exprs;
2764 	   const char** names;
2765 	
2766 	   assert(nlp    != NULL);
2767 	   assert(blkmem != NULL);
2768 	   assert(set    != NULL);
2769 	   assert(nlp->nunflushednlrowadd >= 0);
2770 	   assert(nlp->nunflushedvaradd == 0);
2771 	   assert(nlp->nunflushedvardel == 0);
2772 	   assert(!nlp->indiving);
2773 	
2774 	   if( nlp->nunflushednlrowadd == 0 )
2775 	   {
2776 	#ifndef NDEBUG
2777 	      /* check that there are really no pending additions of variables */
2778 	      for( i = 0; i < nlp->nnlrows; ++i )
2779 	         assert(nlp->nlrows[i]->nlpiindex >= 0);
2780 	#endif
2781 	      return SCIP_OKAY;
2782 	   }
2783 	
2784 	   assert(nlp->solver != NULL);
2785 	   assert(nlp->problem != NULL);
2786 	
2787 	   SCIP_CALL( nlpEnsureNlRowsSolverSize(nlp, blkmem, set, nlp->nnlrows_solver + nlp->nunflushednlrowadd) );
2788 	
2789 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lhss,     nlp->nunflushednlrowadd) );
2790 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &rhss,     nlp->nunflushednlrowadd) );
2791 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinvars, nlp->nunflushednlrowadd) );
2792 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &linidxs,  nlp->nunflushednlrowadd) );
2793 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nunflushednlrowadd) );
2794 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &exprs,    nlp->nunflushednlrowadd) );
2795 	#if ADDNAMESTONLPI
2796 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &names,    nlp->nunflushednlrowadd) );
2797 	#else
2798 	   names = NULL;
2799 	#endif
2800 	
2801 	   c = 0;
2802 	   for( i = 0; i < nlp->nnlrows; ++i )
2803 	   {
2804 	      nlrow = nlp->nlrows[i];
2805 	      assert(nlrow != NULL);
2806 	
2807 	      /* skip nonlinear rows already in NLPI problem */
2808 	      if( nlrow->nlpiindex >= 0 )
2809 	         continue;
2810 	      assert(c < nlp->nunflushednlrowadd);
2811 	
2812 	      /* get indices in NLPI */
2813 	      SCIP_CALL( nlpSetupNlpiIndices(nlp, set, nlrow, &linidxs[c]) );
2814 	      assert(linidxs[c] != NULL || nlrow->nlinvars == 0);
2815 	
2816 	      nlp->nlrowmap_nlpi2nlp[nlp->nnlrows_solver+c] = i;
2817 	      nlrow->nlpiindex = nlp->nnlrows_solver+c;
2818 	
2819 	      lhss[c] = nlrow->lhs;
2820 	      rhss[c] = nlrow->rhs;
2821 	      if( nlrow->constant != 0.0 )
2822 	      {
2823 	         if( !SCIPsetIsInfinity(set, -nlrow->lhs) )
2824 	            lhss[c] -= nlrow->constant;
2825 	         if( !SCIPsetIsInfinity(set,  nlrow->rhs) )
2826 	            rhss[c] -= nlrow->constant;
2827 	      }
2828 	      if( rhss[c] < lhss[c] )
2829 	      {
2830 	         assert(SCIPsetIsEQ(set, lhss[c], rhss[c]));
2831 	         rhss[c] = lhss[c];
2832 	      }
2833 	
2834 	      nlinvars[c] = nlrow->nlinvars;
2835 	      lincoefs[c] = nlrow->lincoefs;
2836 	
2837 	      if( nlrow->expr != NULL )
2838 	      {
2839 	         /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */
2840 	         SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &exprs[c], mapvar2varidx, (void*)nlp, NULL, NULL) );
2841 	      }
2842 	      else
2843 	         exprs[c] = NULL;
2844 	
2845 	#if ADDNAMESTONLPI
2846 	      names[c]      = nlrow->name;
2847 	#endif
2848 	
2849 	      ++c;
2850 	
2851 	#ifdef NDEBUG
2852 	      /* have c vars to add already, there can be no more */
2853 	      if( c == nlp->nunflushednlrowadd )
2854 	         break;
2855 	#endif
2856 	   }
2857 	   assert(c == nlp->nunflushednlrowadd);
2858 	
2859 	   nlp->nnlrows_solver += c;
2860 	
2861 	   SCIP_CALL( SCIPnlpiAddConstraints(set, nlp->solver, nlp->problem, c, lhss, rhss,
2862 	         nlinvars, linidxs, lincoefs,
2863 	         exprs,
2864 	         names) );
2865 	
2866 	   for( c = nlp->nunflushednlrowadd - 1; c >= 0 ; --c )
2867 	   {
2868 	      if( linidxs[c] != NULL )
2869 	         SCIPsetFreeBufferArray(set, &linidxs[c]);
2870 	      if( exprs[c] != NULL )
2871 	      {
2872 	         SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &exprs[c]) );
2873 	      }
2874 	   }
2875 	
2876 	#if ADDNAMESTONLPI
2877 	   SCIPsetFreeBufferArray(set, &names);
2878 	#endif
2879 	   SCIPsetFreeBufferArray(set, &exprs);
2880 	   SCIPsetFreeBufferArray(set, &lincoefs);
2881 	   SCIPsetFreeBufferArray(set, &linidxs);
2882 	   SCIPsetFreeBufferArray(set, &nlinvars);
2883 	   SCIPsetFreeBufferArray(set, &rhss);
2884 	   SCIPsetFreeBufferArray(set, &lhss);
2885 	
2886 	   nlp->nunflushednlrowadd = 0;
2887 	
2888 	   return SCIP_OKAY;
2889 	}
2890 	
2891 	
2892 	/** adds variables to NLPI problem that have been added to NLP before
2893 	 *
2894 	 * may set nlp->objflushed to FALSE if a variable with nonzero objective coefficient is added to the NLPI problem
2895 	 */
2896 	static
2897 	SCIP_RETCODE nlpFlushVarAdditions(
2898 	   SCIP_NLP*             nlp,                /**< NLP data */
2899 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2900 	   SCIP_SET*             set                 /**< global SCIP settings */
2901 	   )
2902 	{
2903 	   int i, c;
2904 	   SCIP_Real*  lbs;
2905 	   SCIP_Real*  ubs;
2906 	   const char** names;
2907 	
2908 	   assert(nlp    != NULL);
2909 	   assert(blkmem != NULL);
2910 	   assert(set    != NULL);
2911 	   assert(nlp->nunflushedvaradd >= 0);
2912 	   assert(!nlp->indiving);
2913 	
2914 	   if( nlp->nunflushedvaradd == 0 )
2915 	   {
2916 	#ifndef NDEBUG
2917 	      /* check that there are really no pending additions of variables */
2918 	      for( i = 0; i < nlp->nvars; ++i )
2919 	         assert(nlp->varmap_nlp2nlpi[i] >= 0);
2920 	#endif
2921 	      return SCIP_OKAY;
2922 	   }
2923 	
2924 	   assert(nlp->solver != NULL);
2925 	   assert(nlp->problem != NULL);
2926 	
2927 	   SCIP_CALL( nlpEnsureVarsSolverSize(nlp, blkmem, set, nlp->nvars_solver + nlp->nunflushedvaradd) );
2928 	
2929 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lbs,   nlp->nunflushedvaradd) );
2930 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &ubs,   nlp->nunflushedvaradd) );
2931 	#if ADDNAMESTONLPI
2932 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushedvaradd) );
2933 	#else
2934 	   names = NULL;
2935 	#endif
2936 	
2937 	   c = 0;
2938 	   for( i = 0; i < nlp->nvars; ++i )
2939 	   {
2940 	      /* skip variables already in NLPI problem */
2941 	      if( nlp->varmap_nlp2nlpi[i] >= 0 )
2942 	         continue;
2943 	      assert(c < nlp->nunflushedvaradd);
2944 	
2945 	      nlp->varmap_nlpi2nlp[nlp->nvars_solver+c] = i;
2946 	      nlp->varmap_nlp2nlpi[i] = nlp->nvars_solver+c;
2947 	      lbs[c]   = SCIPvarGetLbLocal(nlp->vars[i]);
2948 	      ubs[c]   = SCIPvarGetUbLocal(nlp->vars[i]);
2949 	#if ADDNAMESTONLPI
2950 	      names[c] = SCIPvarGetName(nlp->vars[i]);
2951 	#endif
2952 	      ++c;
2953 	
2954 	      /* if the new variable has a nonzero objective coefficient, then the objective need to be updated */
2955 	      if( !SCIPsetIsZero(set, SCIPvarGetObj(nlp->vars[i])) )
2956 	         nlp->objflushed = FALSE;
2957 	
2958 	#ifdef NDEBUG
2959 	      /* have c vars to add already, there can be no more */
2960 	      if( c == nlp->nunflushedvaradd )
2961 	         break;
2962 	#endif
2963 	   }
2964 	   assert(c == nlp->nunflushedvaradd);
2965 	
2966 	   nlp->nvars_solver += c;
2967 	
2968 	   SCIP_CALL( SCIPnlpiAddVars(set, nlp->solver, nlp->problem, c, lbs, ubs, names) );
2969 	
2970 	#if ADDNAMESTONLPI
2971 	   SCIPsetFreeBufferArray(set, &names);
2972 	#endif
2973 	   SCIPsetFreeBufferArray(set, &ubs);
2974 	   SCIPsetFreeBufferArray(set, &lbs);
2975 	
2976 	   nlp->nunflushedvaradd = 0;
2977 	
2978 	   return SCIP_OKAY;
2979 	}
2980 	
2981 	/** updates the objective in the NLPI problem, if necessary
2982 	 *
2983 	 * assumes that there are no unflushed variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first)
2984 	 */
2985 	static
2986 	SCIP_RETCODE nlpFlushObjective(
2987 	   SCIP_NLP*             nlp,                /**< NLP data */
2988 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2989 	   SCIP_SET*             set                 /**< global SCIP settings */
2990 	   )
2991 	{
2992 	   int*       linindices;
2993 	   SCIP_Real* lincoefs;
2994 	   SCIP_Real  coef;
2995 	   int        i;
2996 	   int        nz;
2997 	
2998 	   assert(nlp    != NULL);
2999 	   assert(blkmem != NULL);
3000 	   assert(set    != NULL);
3001 	   assert(nlp->nunflushedvaradd == 0);
3002 	   assert(nlp->nunflushedvardel == 0);
3003 	   assert(!nlp->indiving);
3004 	
3005 	   if( nlp->objflushed )
3006 	      return SCIP_OKAY;
3007 	
3008 	   assert(nlp->solver != NULL);
3009 	   assert(nlp->problem != NULL);
3010 	
3011 	   /* assemble coefficients */
3012 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &linindices, nlp->nvars_solver) );
3013 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs,   nlp->nvars_solver) );
3014 	
3015 	   nz = 0;
3016 	   for( i = 0; i < nlp->nvars_solver; ++i )
3017 	   {
3018 	      assert(nlp->varmap_nlpi2nlp[i] >= 0); /* there should be no variable deletions pending */
3019 	
3020 	      coef = SCIPvarGetObj(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
3021 	      if( SCIPsetIsZero(set, coef) )
3022 	         continue;
3023 	
3024 	      linindices[nz] = i;
3025 	      lincoefs[nz]   = coef;
3026 	      ++nz;
3027 	   }
3028 	
3029 	   SCIP_CALL( SCIPnlpiSetObjective(set, nlp->solver, nlp->problem,
3030 	         nz, linindices, lincoefs,
3031 	         NULL,
3032 	         0.0) );
3033 	
3034 	   SCIPsetFreeBufferArray(set, &lincoefs);
3035 	   SCIPsetFreeBufferArray(set, &linindices);
3036 	
3037 	   nlp->objflushed = TRUE;
3038 	
3039 	   return SCIP_OKAY;
3040 	}
3041 	
3042 	/** solves the NLP (or diving NLP), assuming it has been flushed already */
3043 	static
3044 	SCIP_RETCODE nlpSolve(
3045 	   SCIP_NLP*             nlp,                /**< NLP data */
3046 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3047 	   SCIP_SET*             set,                /**< global SCIP settings */
3048 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
3049 	   SCIP_STAT*            stat,               /**< problem statistics */
3050 	   SCIP_PRIMAL*          primal,             /**< primal data */
3051 	   SCIP_TREE*            tree,               /**< branch and bound tree */
3052 	   SCIP_NLPPARAM*        nlpparam            /**< NLP solve parameters */
3053 	   )
3054 	{
3055 	   int i;
3056 	
3057 	   assert(nlp    != NULL);
3058 	   assert(blkmem != NULL);
3059 	   assert(set    != NULL);
3060 	   assert(stat   != NULL);
3061 	
3062 	   if( nlp->solver == NULL )
3063 	   {
3064 	      SCIPmessagePrintWarning(messagehdlr, "Attempted to solve NLP, but no solver available.\n");
3065 	
3066 	      nlp->solstat  = SCIP_NLPSOLSTAT_UNKNOWN;
3067 	      nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3068 	
3069 	      return SCIP_OKAY;
3070 	   }
3071 	
3072 	   assert(nlp->solver != NULL);
3073 	   assert(nlp->problem != NULL);
3074 	
3075 	   /* set initial guess, if available and warmstart hasn't been enabled
3076 	    * when using the NLP, passing a dual solution with the initguess is not available at the moment (TODO),
3077 	    * so a warmstart has to start from the last solution stored in the NLPI
3078 	    */
3079 	   if( nlp->haveinitguess && !nlpparam->warmstart )
3080 	   {
3081 	      /* @todo should we not set it if we had set it already? (initguessflushed...) */
3082 	      SCIP_Real* initialguess_solver;
3083 	      int nlpidx;
3084 	
3085 	      assert(nlp->initialguess != NULL);
3086 	
3087 	      SCIP_CALL( SCIPsetAllocBufferArray(set, &initialguess_solver, nlp->nvars_solver) );
3088 	
3089 	      for( i = 0; i < nlp->nvars_solver; ++i )
3090 	      {
3091 	         nlpidx = nlp->varmap_nlpi2nlp[i];
3092 	         assert(nlpidx >= 0);
3093 	         assert(nlpidx < nlp->nvars);
3094 	
3095 	         initialguess_solver[i] = nlp->initialguess[nlpidx];
3096 	      }
3097 	      SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, initialguess_solver, NULL, NULL, NULL) );
3098 	
3099 	      SCIPsetFreeBufferArray(set, &initialguess_solver);
3100 	   }
3101 	
3102 	   /* let NLP solver do his work */
3103 	   SCIPclockStart(stat->nlpsoltime, set);
3104 	
3105 	   SCIP_CALL( SCIPnlpiSolve(set, stat, nlp->solver, nlp->problem, nlpparam) );
3106 	
3107 	   SCIPclockStop(stat->nlpsoltime, set);
3108 	   ++stat->nnlps;
3109 	
3110 	   nlp->termstat = SCIPnlpiGetTermstat(set, nlp->solver, nlp->problem);
3111 	   nlp->solstat  = SCIPnlpiGetSolstat(set, nlp->solver, nlp->problem);
3112 	   switch( nlp->solstat )
3113 	   {
3114 	   case SCIP_NLPSOLSTAT_GLOBOPT:
3115 	   case SCIP_NLPSOLSTAT_LOCOPT:
3116 	   case SCIP_NLPSOLSTAT_FEASIBLE:
3117 	   case SCIP_NLPSOLSTAT_LOCINFEASIBLE:
3118 	   {
3119 	      SCIP_Real* primalvals;
3120 	      SCIP_Real* nlrowdualvals;
3121 	      SCIP_Real* varlbdualvals;
3122 	      SCIP_Real* varubdualvals;
3123 	
3124 	      primalvals    = NULL;
3125 	      nlrowdualvals = NULL;
3126 	      varlbdualvals = NULL;
3127 	      varubdualvals = NULL;
3128 	
3129 	      /* get NLP solution */
3130 	      SCIP_CALL( SCIPnlpiGetSolution(set, nlp->solver, nlp->problem, &primalvals, &nlrowdualvals, &varlbdualvals, &varubdualvals, NULL) );
3131 	      assert(primalvals != NULL || nlp->nvars == 0);
3132 	      assert((varlbdualvals != NULL) == (varubdualvals != NULL)); /* if there are duals for one bound, then there should also be duals for the other bound */
3133 	
3134 	      /* store solution primal values in variable and evaluate objective function */
3135 	      if( nlp->indiving && nlp->divingobj != NULL )
3136 	      {
3137 	         for( i = 0; i < nlp->nvars; ++i )
3138 	         {
3139 	            SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, primalvals[nlp->varmap_nlp2nlpi[i]]) );  /*lint !e613 */
3140 	         }
3141 	
3142 	         /* evaluate modified diving objective */
3143 	         SCIP_CALL( SCIPnlrowGetNLPActivity(nlp->divingobj, blkmem, set, stat, primal, tree, nlp, &nlp->primalsolobjval) );
3144 	      }
3145 	      else
3146 	      {
3147 	         /* evaluate SCIP objective function */
3148 	         nlp->primalsolobjval = 0.0;
3149 	         for( i = 0; i < nlp->nvars; ++i )
3150 	         {
3151 	            SCIP_Real solval = primalvals[nlp->varmap_nlp2nlpi[i]];  /*lint !e613 */
3152 	
3153 	            /* do a quick assert that variable bounds are satisfied, if feasibility is claimed */
3154 	            assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(nlp->vars[i])) ||
3155 	               SCIPsetIsFeasGE(set, solval, SCIPvarGetLbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3156 	            assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(nlp->vars[i])) ||
3157 	               SCIPsetIsFeasLE(set, solval, SCIPvarGetUbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE);
3158 	
3159 	            SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, solval) );  /*lint !e613 */
3160 	            nlp->primalsolobjval += SCIPvarGetObj(nlp->vars[i]) * solval;  /*lint !e613 */
3161 	         }
3162 	      }
3163 	
3164 	      /* store solution dual values in nlrows and variables */
3165 	      for( i = 0; i < nlp->nnlrows; ++i )
3166 	      {
3167 	         assert(nlp->nlrows[i]->nlpiindex >= 0); /* NLP was flushed before solve, so all nlrows should be in there */
3168 	
3169 	         nlp->nlrows[i]->dualsol = nlrowdualvals != NULL ? nlrowdualvals[nlp->nlrows[i]->nlpiindex] : 0.0;
3170 	
3171 	         /* SCIPsetDebugMsg(set, "dual of nlrow <%s> = %g\n", nlp->nlrows[i]->name, nlp->nlrows[i]->dualsol); */
3172 	      }
3173 	      assert(nlp->varlbdualvals != NULL || nlp->nvars == 0);
3174 	      assert(nlp->varubdualvals != NULL || nlp->nvars == 0);
3175 	      if( varlbdualvals != NULL )
3176 	      {
3177 	         for( i = 0; i < nlp->nvars; ++i )
3178 	         {
3179 	            assert(nlp->varmap_nlp2nlpi[i] >= 0); /* NLP was flushed before solve, so all vars should be in there */
3180 	
3181 	            nlp->varlbdualvals[i] = varlbdualvals[nlp->varmap_nlp2nlpi[i]];
3182 	            nlp->varubdualvals[i] = varubdualvals[nlp->varmap_nlp2nlpi[i]];
3183 	
3184 	            /* SCIPsetDebugMsg(set, "duals of var <%s> = %g %g\n", SCIPvarGetName(nlp->vars[i]), nlp->varlbdualvals[i], nlp->varubdualvals[i]); */
3185 	         }
3186 	      }
3187 	      else if( nlp->nvars > 0 )
3188 	      {
3189 	         BMSclearMemoryArray(nlp->varlbdualvals, nlp->nvars);
3190 	         BMSclearMemoryArray(nlp->varubdualvals, nlp->nvars);
3191 	      }
3192 	
3193 	      break;
3194 	   }
3195 	   default:
3196 	      nlp->primalsolobjval = SCIP_INVALID;
3197 	      break;
3198 	   } /*lint !e788*/
3199 	
3200 	   return SCIP_OKAY;
3201 	}
3202 	
3203 	/** assembles list of fractional variables in last NLP solution */
3204 	static
3205 	SCIP_RETCODE nlpCalcFracVars(
3206 	   SCIP_NLP*             nlp,                /**< NLP data */
3207 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3208 	   SCIP_SET*             set,                /**< global SCIP settings */
3209 	   SCIP_STAT*            stat                /**< problem statistics */
3210 	   )
3211 	{
3212 	   assert(nlp != NULL);
3213 	   assert(blkmem != NULL);
3214 	   assert(set != NULL);
3215 	   assert(stat != NULL);
3216 	   assert(nlp->validfracvars <= stat->nnlps);
3217 	   assert(SCIPnlpHasSolution(nlp));
3218 	
3219 	   SCIPsetDebugMsg(set, "calculating NLP fractional variables: validfracvars=%" SCIP_LONGINT_FORMAT ", nnlps=%" SCIP_LONGINT_FORMAT "\n", nlp->validfracvars, stat->nnlps);
3220 	
3221 	   if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE )
3222 	   {
3223 	      nlp->nfracvars     = 0;
3224 	      nlp->npriofracvars = 0;
3225 	      nlp->validfracvars = stat->nnlps;
3226 	
3227 	      SCIPsetDebugMsg(set, "NLP globally infeasible, unbounded, or worse -> no solution values -> no fractional variables\n");
3228 	      return SCIP_OKAY;
3229 	   }
3230 	
3231 	   /* check, if the current NLP fractional variables array is invalid */
3232 	   if( nlp->validfracvars < stat->nnlps )
3233 	   {
3234 	      SCIP_VAR* var;
3235 	      SCIP_Real primsol;
3236 	      SCIP_Real frac;
3237 	      int branchpriority;
3238 	      int insertpos;
3239 	      int maxpriority;
3240 	      int i;
3241 	
3242 	      SCIPsetDebugMsg(set, " -> recalculating NLP fractional variables\n");
3243 	
3244 	      if( nlp->fracvarssize == 0 )
3245 	      {
3246 	         assert(nlp->fracvars     == NULL);
3247 	         assert(nlp->fracvarssol  == NULL);
3248 	         assert(nlp->fracvarsfrac == NULL);
3249 	         nlp->fracvarssize = 5;
3250 	         SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvars,     nlp->fracvarssize) );
3251 	         SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarssol,  nlp->fracvarssize) );
3252 	         SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize) );
3253 	      }
3254 	
3255 	      maxpriority = INT_MIN;
3256 	      nlp->nfracvars = 0;
3257 	      nlp->npriofracvars = 0;
3258 	      for( i = 0; i < nlp->nvars; ++i )
3259 	      {
3260 	         var = nlp->vars[i];
3261 	         assert(var != NULL);
3262 	
3263 	         primsol = SCIPvarGetNLPSol(var);
3264 	         assert(primsol < SCIP_INVALID);
3265 	
3266 	         /* consider only binary and integer variables */
3267 	         if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER )
3268 	            continue;
3269 	
3270 	         /* ignore fixed variables (due to numerics, it is possible, that the NLP solution of a fixed integer variable
3271 	          * (with large fixed value) is fractional in terms of absolute feasibility measure)
3272 	          */
3273 	         if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
3274 	            continue;
3275 	
3276 	         /* check, if the LP solution value is fractional */
3277 	         frac = SCIPsetFeasFrac(set, primsol);
3278 	
3279 	         /* The fractionality should not be smaller than -feastol, however, if the primsol is large enough
3280 	          * and close to an integer, fixed precision floating point arithmetic might give us values slightly
3281 	          * smaller than -feastol. Originally, the "frac >= -feastol"-check was within SCIPsetIsFeasFracIntegral(),
3282 	          * however, we relaxed it to "frac >= -2*feastol" and have the stricter check here for small-enough primsols.
3283 	          */
3284 	         assert(SCIPsetIsGE(set, frac, -SCIPsetFeastol(set)) || (primsol > 1e14 * SCIPsetFeastol(set)));
3285 	
3286 	         if( SCIPsetIsFeasFracIntegral(set, frac) )
3287 	            continue;
3288 	
3289 	         /* ensure enough space in fracvars arrays */
3290 	         if( nlp->fracvarssize <= nlp->nfracvars )
3291 	         {
3292 	            int newsize;
3293 	
3294 	            newsize = SCIPsetCalcMemGrowSize(set, nlp->nfracvars + 1);
3295 	            SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvars,     nlp->fracvarssize, newsize) );
3296 	            SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarssol,  nlp->fracvarssize, newsize) );
3297 	            SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize, newsize) );
3298 	            nlp->fracvarssize = newsize;
3299 	         }
3300 	         assert(nlp->nfracvars < nlp->fracvarssize);
3301 	         assert(nlp->fracvars     != NULL);
3302 	         assert(nlp->fracvarssol  != NULL);
3303 	         assert(nlp->fracvarsfrac != NULL);
3304 	
3305 	         /* insert candidate in candidate list */
3306 	         branchpriority = SCIPvarGetBranchPriority(var);
3307 	         insertpos = nlp->nfracvars;
3308 	         nlp->nfracvars++;
3309 	         if( branchpriority > maxpriority )
3310 	         {
3311 	            /* candidate has higher priority than the current maximum:
3312 	             * move it to the front and declare it to be the single best candidate
3313 	             */
3314 	            if( insertpos != 0 )
3315 	            {
3316 	               nlp->fracvars[insertpos]     = nlp->fracvars[0];
3317 	               nlp->fracvarssol[insertpos]  = nlp->fracvarssol[0];
3318 	               nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[0];
3319 	               insertpos = 0;
3320 	            }
3321 	            nlp->npriofracvars = 1;
3322 	            maxpriority = branchpriority;
3323 	         }
3324 	         else if( branchpriority == maxpriority )
3325 	         {
3326 	            /* candidate has equal priority as the current maximum:
3327 	             * move away the first non-maximal priority candidate, move the current candidate to the correct
3328 	             * slot (binaries first) and increase the number of maximal priority candidates
3329 	             */
3330 	            if( insertpos != nlp->npriofracvars )
3331 	            {
3332 	               nlp->fracvars[insertpos]     = nlp->fracvars[nlp->npriofracvars];
3333 	               nlp->fracvarssol[insertpos]  = nlp->fracvarssol[nlp->npriofracvars];
3334 	               nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[nlp->npriofracvars];
3335 	               insertpos = nlp->npriofracvars;
3336 	            }
3337 	            ++nlp->npriofracvars;
3338 	         }
3339 	         nlp->fracvars[insertpos]     = var;
3340 	         nlp->fracvarssol[insertpos]  = primsol;
3341 	         nlp->fracvarsfrac[insertpos] = frac;
3342 	
3343 	         SCIPsetDebugMsg(set, " -> candidate %d: var=<%s>, sol=%g, frac=%g, prio=%d (max: %d) -> pos %d\n",
3344 	            nlp->nfracvars, SCIPvarGetName(var), primsol, frac, branchpriority, maxpriority, insertpos);
3345 	      }
3346 	
3347 	      nlp->validfracvars = stat->nnlps;
3348 	   }
3349 	   assert(0 <= nlp->npriofracvars);
3350 	   assert(nlp->npriofracvars <= nlp->nfracvars);
3351 	
3352 	   SCIPsetDebugMsg(set, " -> %d fractional variables (%d of maximal priority)\n", nlp->nfracvars, nlp->npriofracvars);
3353 	
3354 	   return SCIP_OKAY;
3355 	}
3356 	
3357 	/** event handling for variable events */
3358 	static
3359 	SCIP_DECL_EVENTEXEC(eventExecNlp)
3360 	{
3361 	   SCIP_EVENTTYPE etype;
3362 	   SCIP_VAR*      var;
3363 	
3364 	   assert(scip      != NULL);
3365 	   assert(eventhdlr != NULL);
3366 	   assert(event     != NULL);
3367 	   assert(eventdata != NULL);
3368 	
3369 	   assert((SCIP_NLP*)eventdata == scip->nlp);
3370 	
3371 	   etype = SCIPeventGetType(event);
3372 	   var   = SCIPeventGetVar(event);
3373 	
3374 	   if( SCIP_EVENTTYPE_VARADDED & etype )
3375 	   {
3376 	      SCIPdebugMessage("-> handling varadd event, variable <%s>\n", SCIPvarGetName(var) );
3377 	      SCIP_CALL( SCIPnlpAddVar(scip->nlp, SCIPblkmem(scip), scip->set, var) );
3378 	   }
3379 	   else if( SCIP_EVENTTYPE_VARDELETED & etype )
3380 	   {
3381 	      SCIPdebugMessage("-> handling vardel event, variable <%s>\n", SCIPvarGetName(var) );
3382 	      SCIP_CALL( SCIPnlpDelVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3383 	   }
3384 	   else if( SCIP_EVENTTYPE_VARFIXED & etype )
3385 	   {
3386 	      /* variable was fixed, aggregated, or multi-aggregated */
3387 	      /* TODO is this ever happening? that is, can we have changes in a variable status during solve? */
3388 	      SCIPdebugMessage("-> handling variable fixation event, variable <%s>\n", SCIPvarGetName(var) );
3389 	      SCIP_CALL( nlpRemoveFixedVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) );
3390 	   }
3391 	   else if( SCIP_EVENTTYPE_BOUNDCHANGED & etype )
3392 	   {
3393 	      SCIPdebugMessage("-> handling bound changed event %" SCIP_EVENTTYPE_FORMAT ", variable <%s>\n", etype, SCIPvarGetName(var) );
3394 	      SCIP_CALL( nlpUpdateVarBounds(scip->nlp, scip->set, var, (SCIP_Bool)(SCIP_EVENTTYPE_BOUNDTIGHTENED & etype)) );
3395 	   }
3396 	   else if( SCIP_EVENTTYPE_OBJCHANGED & etype )
3397 	   {
3398 	      SCIPdebugMessage("-> handling objchg event, variable <%s>\n", SCIPvarGetName(var) );
3399 	      SCIP_CALL( nlpUpdateObjCoef(scip->set, scip->nlp, var) );
3400 	   }
3401 	   else
3402 	   {
3403 	      SCIPerrorMessage("unexpected event %" SCIP_EVENTTYPE_FORMAT " on variable <%s>\n", etype, SCIPvarGetName(var) );
3404 	      return SCIP_ERROR;
3405 	   }
3406 	
3407 	   return SCIP_OKAY;
3408 	}
3409 	
3410 	
3411 	/*
3412 	 * public NLP methods
3413 	 */
3414 	
3415 	/** includes event handler that is used by NLP */
3416 	SCIP_RETCODE SCIPnlpInclude(
3417 	   SCIP_SET*             set,                /**< global SCIP settings */
3418 	   BMS_BLKMEM*           blkmem              /**< block memory */
3419 	   )
3420 	{
3421 	   SCIP_EVENTHDLR* eventhdlr;
3422 	
3423 	   assert(set != NULL);
3424 	   assert(blkmem != NULL);
3425 	   assert(set->stage == SCIP_STAGE_INIT);
3426 	
3427 	   /* check whether event handler is already present */
3428 	   if( SCIPsetFindEventhdlr(set, EVENTHDLR_NAME) != NULL )
3429 	   {
3430 	      SCIPerrorMessage("event handler <" EVENTHDLR_NAME "> already included.\n");
3431 	      return SCIP_INVALIDDATA;
3432 	   }
3433 	
3434 	   SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC,
3435 	         NULL, NULL, NULL, NULL, NULL, NULL, NULL, eventExecNlp, NULL) );
3436 	   SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) );
3437 	
3438 	   return SCIP_OKAY;
3439 	} /*lint !e715*/
3440 	
3441 	/** construct a new empty NLP */
3442 	SCIP_RETCODE SCIPnlpCreate(
3443 	   SCIP_NLP**            nlp,                /**< NLP handler, call by reference */
3444 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3445 	   SCIP_SET*             set,                /**< global SCIP settings */
3446 	   SCIP_STAT*            stat,               /**< problem statistics */
3447 	   const char*           name,               /**< problem name */
3448 	   int                   nvars_estimate      /**< an estimate on the number of variables that may be added to the NLP later */
3449 	   )
3450 	{
3451 	   assert(nlp  != NULL);
3452 	   assert(blkmem != NULL);
3453 	   assert(set  != NULL);
3454 	   assert(stat != NULL);
3455 	   assert(name != NULL);
3456 	
3457 	   SCIP_ALLOC( BMSallocMemory(nlp) );
3458 	
3459 	   /* select NLP solver (if any available) and setup problem */
3460 	   if( set->nnlpis > 0 )
3461 	   {
3462 	      assert(set->nlp_solver != NULL);
3463 	      if( set->nlp_solver[0] == '\0' )
3464 	      { /* take solver with highest priority */
3465 	         assert(set->nlpis != NULL);
3466 	
3467 	         /* sort the NLPIs if necessary */
3468 	         if( !set->nlpissorted )
3469 	            SCIPsetSortNlpis(set);
3470 	
3471 	         (*nlp)->solver = set->nlpis[0];
3472 	      }
3473 	      else
3474 	      { /* find user specified NLP solver */
3475 	         (*nlp)->solver = SCIPsetFindNlpi(set, set->nlp_solver);
3476 	         if( (*nlp)->solver == NULL )
3477 	         {
3478 	            SCIPerrorMessage("Selected NLP solver <%s> not available.\n", set->nlp_solver);
3479 	            return SCIP_PLUGINNOTFOUND;
3480 	         }
3481 	      }
3482 	      assert((*nlp)->solver != NULL);
3483 	      SCIP_CALL( SCIPnlpiCreateProblem(set, (*nlp)->solver, &(*nlp)->problem, name) );
3484 	   }
3485 	   else
3486 	   {
3487 	      /* maybe someone wanna use the NLP just to collect nonlinearities, but is not necessarily interesting on solving
3488 	       * so we allow this and just continue */
3489 	      (*nlp)->solver = NULL;
3490 	      (*nlp)->problem = NULL;
3491 	   }
3492 	
3493 	   /* status */
3494 	   (*nlp)->nunflushedvaradd   = 0;
3495 	   (*nlp)->nunflushedvardel   = 0;
3496 	   (*nlp)->nunflushednlrowadd = 0;
3497 	   (*nlp)->nunflushednlrowdel = 0;
3498 	   (*nlp)->indiving   = FALSE;
3499 	
3500 	   /* variables in problem and NLPI problem */
3501 	   (*nlp)->nvars = 0;
3502 	   (*nlp)->sizevars = 0;
3503 	   (*nlp)->vars = NULL;
3504 	   SCIP_CALL( SCIPhashmapCreate(&(*nlp)->varhash, blkmem, nvars_estimate) );
3505 	
3506 	   (*nlp)->nvars_solver = 0;
3507 	   (*nlp)->sizevars_solver = 0;
3508 	   (*nlp)->varmap_nlp2nlpi = NULL;
3509 	   (*nlp)->varmap_nlpi2nlp = NULL;
3510 	
3511 	   /* nonlinear rows in problem and NLPI problem */
3512 	   (*nlp)->nnlrows = 0;
3513 	   (*nlp)->sizenlrows = 0;
3514 	   (*nlp)->nlrows = NULL;
3515 	
3516 	   (*nlp)->nnlrows_solver = 0;
3517 	   (*nlp)->sizenlrows_solver = 0;
3518 	   (*nlp)->nlrowmap_nlpi2nlp = NULL;
3519 	
3520 	   /* objective function */
3521 	   (*nlp)->objflushed = TRUE;
3522 	   (*nlp)->divingobj = NULL;
3523 	
3524 	   /* initial guess */
3525 	   (*nlp)->haveinitguess = FALSE;
3526 	   (*nlp)->initialguess = NULL;
3527 	
3528 	   /* solution of NLP */
3529 	   (*nlp)->primalsolobjval = SCIP_INVALID;
3530 	   (*nlp)->solstat         = SCIP_NLPSOLSTAT_UNKNOWN;
3531 	   (*nlp)->termstat        = SCIP_NLPTERMSTAT_OTHER;
3532 	   (*nlp)->varlbdualvals   = NULL;
3533 	   (*nlp)->varubdualvals   = NULL;
3534 	
3535 	   /* event handling: catch variable addition and deletion events */
3536 	   (*nlp)->eventhdlr = SCIPsetFindEventhdlr(set, EVENTHDLR_NAME);
3537 	   if( (*nlp)->eventhdlr == NULL )
3538 	   {
3539 	      SCIPerrorMessage("NLP eventhandler <" EVENTHDLR_NAME "> not found.\n");
3540 	      return SCIP_PLUGINNOTFOUND;
3541 	   }
3542 	   SCIP_CALL( SCIPeventfilterAdd(set->scip->eventfilter, blkmem, set,
3543 	         SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3544 	         (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), &(*nlp)->globalfilterpos) );
3545 	
3546 	   /* fractional variables in last NLP solution */
3547 	   (*nlp)->fracvars     = NULL;
3548 	   (*nlp)->fracvarssol  = NULL;
3549 	   (*nlp)->fracvarsfrac = NULL;
3550 	   (*nlp)->nfracvars     = 0;
3551 	   (*nlp)->npriofracvars = 0;
3552 	   (*nlp)->fracvarssize  = 0;
3553 	   (*nlp)->validfracvars = -1;
3554 	
3555 	   /* miscellaneous */
3556 	   SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlp)->name, name, strlen(name)+1) );
3557 	
3558 	   return SCIP_OKAY;
3559 	}
3560 	
3561 	/** frees NLP data object */
3562 	SCIP_RETCODE SCIPnlpFree(
3563 	   SCIP_NLP**            nlp,                /**< pointer to NLP data object */
3564 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3565 	   SCIP_SET*             set,                /**< global SCIP settings */
3566 	   SCIP_STAT*            stat,               /**< problem statistics */
3567 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3568 	   SCIP_LP*              lp                  /**< SCIP LP, needed for releasing variables */
3569 	   )
3570 	{
3571 	   assert(nlp    != NULL);
3572 	   assert(*nlp   != NULL);
3573 	   assert(blkmem != NULL);
3574 	   assert(set    != NULL);
3575 	
3576 	   /* drop fractional variables */
3577 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvars,     (*nlp)->fracvarssize);
3578 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarssol,  (*nlp)->fracvarssize);
3579 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarsfrac, (*nlp)->fracvarssize);
3580 	
3581 	   /* drop global events (variable addition and deletion) */
3582 	   SCIP_CALL( SCIPeventfilterDel(set->scip->eventfilter, blkmem, set,
3583 	         SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED,
3584 	         (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), (*nlp)->globalfilterpos) );
3585 	
3586 	   SCIP_CALL( SCIPnlpReset(*nlp, blkmem, set, stat, eventqueue, lp) );
3587 	   assert((*nlp)->nnlrows == 0);
3588 	   assert((*nlp)->nnlrows_solver == 0);
3589 	   assert((*nlp)->nvars == 0);
3590 	   assert((*nlp)->nvars_solver == 0);
3591 	   assert((*nlp)->initialguess == NULL);
3592 	
3593 	   BMSfreeBlockMemoryArray(blkmem, &(*nlp)->name, strlen((*nlp)->name)+1);
3594 	
3595 	   /* free nonlinear rows arrays */
3596 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrowmap_nlpi2nlp, (*nlp)->sizenlrows_solver);
3597 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrows, (*nlp)->sizenlrows);
3598 	
3599 	   /* free variables arrays */
3600 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlp2nlpi, (*nlp)->sizevars);
3601 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlpi2nlp, (*nlp)->sizevars_solver);
3602 	   SCIPhashmapFree(&(*nlp)->varhash);
3603 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->vars, (*nlp)->sizevars);
3604 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varlbdualvals, (*nlp)->sizevars);
3605 	   BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varubdualvals, (*nlp)->sizevars);
3606 	
3607 	   /* free NLPI problem */
3608 	   if( (*nlp)->problem != NULL )
3609 	   {
3610 	      SCIP_CALL( SCIPnlpiFreeProblem(set, (*nlp)->solver, &(*nlp)->problem) );
3611 	   }
3612 	
3613 	   /* free NLP data structure */
3614 	   BMSfreeMemory(nlp);
3615 	
3616 	   return SCIP_OKAY;
3617 	}
3618 	
3619 	/** resets the NLP to the empty NLP by removing all variables and rows from NLP,
3620 	 *  releasing all rows, and flushing the changes to the NLP solver
3621 	 */
3622 	SCIP_RETCODE SCIPnlpReset(
3623 	   SCIP_NLP*             nlp,                /**< NLP data */
3624 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3625 	   SCIP_SET*             set,                /**< global SCIP settings */
3626 	   SCIP_STAT*            stat,               /**< problem statistics data */
3627 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3628 	   SCIP_LP*              lp                  /**< SCIP LP, needed for releasing variables */
3629 	   )
3630 	{
3631 	   int i;
3632 	
3633 	   assert(nlp    != NULL);
3634 	   assert(blkmem != NULL);
3635 	   assert(set    != NULL);
3636 	
3637 	   if( nlp->indiving )
3638 	   {
3639 	      SCIP_CALL( SCIPnlpEndDive(nlp, blkmem, set, stat) );
3640 	   }
3641 	
3642 	   nlp->solstat  = SCIP_NLPSOLSTAT_UNKNOWN;
3643 	   nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
3644 	
3645 	   BMSfreeBlockMemoryArrayNull(blkmem, &nlp->initialguess, nlp->sizevars);
3646 	   nlp->haveinitguess = FALSE;
3647 	
3648 	   for(i = nlp->nnlrows - 1; i >= 0; --i)
3649 	   {
3650 	      SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
3651 	   }
3652 	
3653 	   for(i = nlp->nvars - 1; i >= 0; --i)
3654 	   {
3655 	      SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, i) );
3656 	   }
3657 	
3658 	   SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3659 	
3660 	   return SCIP_OKAY;
3661 	}
3662 	
3663 	/** currently a dummy function that always returns TRUE */
3664 	SCIP_Bool SCIPnlpHasCurrentNodeNLP(
3665 	   SCIP_NLP*             nlp                 /**< NLP data */
3666 	   )
3667 	{
3668 	   assert(nlp != NULL);
3669 	   return TRUE;
3670 	} /*lint !e715*/
3671 	
3672 	/** ensures, that variables array of NLP can store at least num entries */
3673 	SCIP_RETCODE SCIPnlpEnsureVarsSize(
3674 	   SCIP_NLP*             nlp,                /**< NLP data */
3675 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3676 	   SCIP_SET*             set,                /**< global SCIP settings */
3677 	   int                   num                 /**< minimum number of entries to store */
3678 	   )
3679 	{
3680 	   assert(nlp    != NULL);
3681 	   assert(blkmem != NULL);
3682 	   assert(set    != NULL);
3683 	   assert(nlp->nvars <= nlp->sizevars);
3684 	
3685 	   if( num > nlp->sizevars )
3686 	   {
3687 	      int newsize;
3688 	
3689 	      newsize = SCIPsetCalcMemGrowSize(set, num);
3690 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->vars,            nlp->sizevars, newsize) );
3691 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlp2nlpi, nlp->sizevars, newsize) );
3692 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varlbdualvals,   nlp->sizevars, newsize) );
3693 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varubdualvals,   nlp->sizevars, newsize) );
3694 	      if( nlp->initialguess != NULL )
3695 	      {
3696 	         SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars, newsize) );
3697 	      }
3698 	
3699 	      nlp->sizevars = newsize;
3700 	   }
3701 	   assert(num <= nlp->sizevars);
3702 	
3703 	   return SCIP_OKAY;
3704 	}
3705 	
3706 	/** adds a variable to the NLP and captures the variable */
3707 	SCIP_RETCODE SCIPnlpAddVar(
3708 	   SCIP_NLP*             nlp,                /**< NLP data */
3709 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3710 	   SCIP_SET*             set,                /**< global SCIP settings */
3711 	   SCIP_VAR*             var                 /**< variable */
3712 	   )
3713 	{
3714 	   assert(nlp != NULL);
3715 	   assert(blkmem != NULL);
3716 	   assert(set != NULL);
3717 	   assert(var != NULL);
3718 	   assert(SCIPvarIsTransformed(var));
3719 	   assert(!SCIPhashmapExists(nlp->varhash, var));
3720 	
3721 	   if( nlp->indiving )
3722 	   {
3723 	      SCIPerrorMessage("cannot add variable during NLP diving\n");
3724 	      return SCIP_ERROR;
3725 	   }
3726 	
3727 	   SCIP_CALL( nlpAddVars(nlp, blkmem, set, 1, &var) );
3728 	
3729 	   return SCIP_OKAY;
3730 	}
3731 	
3732 	/** adds a set of variables to the NLP and captures the variables */
3733 	SCIP_RETCODE SCIPnlpAddVars(
3734 	   SCIP_NLP*             nlp,                /**< NLP data */
3735 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3736 	   SCIP_SET*             set,                /**< global SCIP settings */
3737 	   int                   nvars,              /**< number of variables to add */
3738 	   SCIP_VAR**            vars                /**< variables to add */
3739 	   )
3740 	{
3741 	   assert(nlp != NULL);
3742 	   assert(blkmem != NULL);
3743 	   assert(set != NULL);
3744 	   assert(vars != NULL || nvars == 0);
3745 	
3746 	   if( nlp->indiving && nvars > 0)
3747 	   {
3748 	      SCIPerrorMessage("cannot add variables during NLP diving\n");
3749 	      return SCIP_ERROR;
3750 	   }
3751 	
3752 	   SCIP_CALL( nlpAddVars(nlp, blkmem, set, nvars, vars) );
3753 	
3754 	   return SCIP_OKAY;
3755 	}
3756 	
3757 	/** deletes a variable from the NLP and releases the variable */
3758 	SCIP_RETCODE SCIPnlpDelVar(
3759 	   SCIP_NLP*             nlp,                /**< NLP data */
3760 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3761 	   SCIP_SET*             set,                /**< global SCIP settings */
3762 	   SCIP_STAT*            stat,               /**< problem statistics data */
3763 	   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3764 	   SCIP_LP*              lp,                 /**< SCIP LP, needed to release variable */
3765 	   SCIP_VAR*             var                 /**< variable */
3766 	   )
3767 	{
3768 	   int varpos;
3769 	
3770 	   assert(nlp    != NULL);
3771 	   assert(blkmem != NULL);
3772 	   assert(set    != NULL);
3773 	   assert(var    != NULL);
3774 	
3775 	   if( !SCIPhashmapExists(nlp->varhash, var) )
3776 	   {
3777 	      SCIPerrorMessage("variable <%s> not found in NLP, cannot delete\n", SCIPvarGetName(var));
3778 	      return SCIP_ERROR;
3779 	   }
3780 	
3781 	   if( nlp->indiving )
3782 	   {
3783 	      SCIPerrorMessage("cannot delete variable during NLP diving\n");
3784 	      return SCIP_ERROR;
3785 	   }
3786 	
3787 	   varpos = SCIPhashmapGetImageInt(nlp->varhash, var);
3788 	
3789 	   SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, varpos) );
3790 	
3791 	   return SCIP_OKAY;
3792 	}
3793 	
3794 	/** ensures, that nonlinear rows array of NLP can store at least num entries */
3795 	SCIP_RETCODE SCIPnlpEnsureNlRowsSize(
3796 	   SCIP_NLP*             nlp,                /**< NLP data */
3797 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3798 	   SCIP_SET*             set,                /**< global SCIP settings */
3799 	   int                   num                 /**< minimum number of entries to store */
3800 	   )
3801 	{
3802 	   assert(nlp    != NULL);
3803 	   assert(blkmem != NULL);
3804 	   assert(set    != NULL);
3805 	   assert(nlp->nnlrows <= nlp->sizenlrows);
3806 	
3807 	   if( num > nlp->sizenlrows )
3808 	   {
3809 	      int newsize;
3810 	
3811 	      newsize = SCIPsetCalcMemGrowSize(set, num);
3812 	      SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrows, nlp->sizenlrows, newsize) );
3813 	
3814 	      nlp->sizenlrows = newsize;
3815 	   }
3816 	   assert(num <= nlp->sizenlrows);
3817 	
3818 	   return SCIP_OKAY;
3819 	}
3820 	
3821 	/** adds a nonlinear row to the NLP and captures it
3822 	 *
3823 	 * all variables of the row need to be present in the NLP
3824 	 */
3825 	SCIP_RETCODE SCIPnlpAddNlRow(
3826 	   SCIP_NLP*             nlp,                /**< NLP data */
3827 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3828 	   SCIP_SET*             set,                /**< global SCIP settings */
3829 	   SCIP_STAT*            stat,               /**< problem statistics data */
3830 	   SCIP_NLROW*           nlrow               /**< nonlinear row */
3831 	   )
3832 	{
3833 	   assert(nlp   != NULL);
3834 	   assert(nlrow != NULL);
3835 	
3836 	   if( nlp->indiving )
3837 	   {
3838 	      SCIPerrorMessage("cannot add row during NLP diving\n");
3839 	      return SCIP_ERROR;
3840 	   }
3841 	
3842 	   SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, 1, &nlrow) );
3843 	
3844 	   return SCIP_OKAY;
3845 	}
3846 	
3847 	/** adds nonlinear rows to the NLP and captures them
3848 	 *
3849 	 * all variables of the row need to be present in the NLP
3850 	 */
3851 	SCIP_RETCODE SCIPnlpAddNlRows(
3852 	   SCIP_NLP*             nlp,                /**< NLP data */
3853 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3854 	   SCIP_SET*             set,                /**< global SCIP settings */
3855 	   SCIP_STAT*            stat,               /**< problem statistics data */
3856 	   int                   nnlrows,            /**< number of rows to add */
3857 	   SCIP_NLROW**          nlrows              /**< rows to add */
3858 	   )
3859 	{
3860 	   assert(nlp    != NULL);
3861 	   assert(nlrows != NULL || nnlrows == 0);
3862 	
3863 	   if( nnlrows == 0 )
3864 	      return SCIP_OKAY;
3865 	
3866 	   if( nlp->indiving )
3867 	   {
3868 	      SCIPerrorMessage("cannot add rows during NLP diving\n");
3869 	      return SCIP_ERROR;
3870 	   }
3871 	
3872 	   SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, nnlrows, nlrows) );
3873 	
3874 	   return SCIP_OKAY;
3875 	}
3876 	
3877 	/** deletes a nonlinear row from the NLP
3878 	 *
3879 	 * does nothing if nonlinear row is not in NLP
3880 	 */
3881 	SCIP_RETCODE SCIPnlpDelNlRow(
3882 	   SCIP_NLP*             nlp,                /**< NLP data */
3883 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3884 	   SCIP_SET*             set,                /**< global SCIP settings */
3885 	   SCIP_STAT*            stat,               /**< problem statistics data */
3886 	   SCIP_NLROW*           nlrow               /**< nonlinear row */
3887 	   )
3888 	{
3889 	   assert(nlp    != NULL);
3890 	   assert(blkmem != NULL);
3891 	   assert(set    != NULL);
3892 	   assert(nlrow  != NULL);
3893 	
3894 	   /* if row not in NLP, nothing to do */
3895 	   if( nlrow->nlpindex == -1 )
3896 	      return SCIP_OKAY;
3897 	
3898 	   assert(nlrow->nlpindex >= 0);
3899 	   assert(nlrow->nlpindex < nlp->nnlrows);
3900 	
3901 	   if( nlp->indiving )
3902 	   {
3903 	      SCIPerrorMessage("cannot delete row during NLP diving\n");
3904 	      return SCIP_ERROR;
3905 	   }
3906 	
3907 	   SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, nlrow->nlpindex) );
3908 	
3909 	   return SCIP_OKAY;
3910 	}
3911 	
3912 	/** applies all cached changes to the NLP solver */
3913 	SCIP_RETCODE SCIPnlpFlush(
3914 	   SCIP_NLP*             nlp,                /**< current NLP data */
3915 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3916 	   SCIP_SET*             set,                /**< global SCIP settings */
3917 	   SCIP_STAT*            stat                /**< problem statistics */
3918 	   )
3919 	{
3920 	   assert(nlp    != NULL);
3921 	   assert(blkmem != NULL);
3922 	   assert(set    != NULL);
3923 	
3924 	   if( nlp->indiving )
3925 	   {
3926 	      SCIPerrorMessage("cannot flush NLP during NLP diving\n");
3927 	      return SCIP_ERROR;
3928 	   }
3929 	
3930 	   /* flush removals of nonlinear rows and variables */
3931 	   SCIP_CALL( nlpFlushNlRowDeletions(nlp, blkmem, set) );
3932 	   SCIP_CALL( nlpFlushVarDeletions(nlp, blkmem, set) );
3933 	   assert(nlp->nunflushednlrowdel == 0);
3934 	   assert(nlp->nunflushedvardel   == 0);
3935 	
3936 	   /* flush addition of variables, objective, and addition of rows */
3937 	   SCIP_CALL( nlpFlushVarAdditions(nlp, blkmem, set) );
3938 	   SCIP_CALL( nlpFlushObjective(nlp, blkmem, set) );
3939 	   SCIP_CALL( nlpFlushNlRowAdditions(nlp, blkmem, set, stat) );
3940 	   assert(nlp->nunflushedvaradd == 0);
3941 	   assert(nlp->objflushed == TRUE);
3942 	   assert(nlp->nunflushednlrowadd == 0);
3943 	
3944 	   assert(nlp->nvars   == nlp->nvars_solver);
3945 	   assert(nlp->nnlrows == nlp->nnlrows_solver);
3946 	
3947 	   return SCIP_OKAY;
3948 	}
3949 	
3950 	/** solves the NLP or diving NLP */
3951 	SCIP_RETCODE SCIPnlpSolve(
3952 	   SCIP_NLP*             nlp,                /**< NLP data */
3953 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3954 	   SCIP_SET*             set,                /**< global SCIP settings */
3955 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
3956 	   SCIP_STAT*            stat,               /**< problem statistics */
3957 	   SCIP_PRIMAL*          primal,             /**< primal data */
3958 	   SCIP_TREE*            tree,               /**< branch and bound tree */
3959 	   SCIP_NLPPARAM*        nlpparam            /**< NLP solve parameters */
3960 	   )
3961 	{
3962 	   assert(nlp    != NULL);
3963 	   assert(blkmem != NULL);
3964 	   assert(set    != NULL);
3965 	   assert(stat   != NULL);
3966 	
3967 	   if( !nlp->indiving )
3968 	   {
3969 	      SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
3970 	   }
3971 	
3972 	   SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat, primal, tree, nlpparam) );
3973 	
3974 	   return SCIP_OKAY;
3975 	}
3976 	
3977 	/** gets objective value of current NLP */
3978 	SCIP_Real SCIPnlpGetObjval(
3979 	   SCIP_NLP*             nlp                 /**< current NLP data */
3980 	   )
3981 	{
3982 	   assert(nlp != NULL);
3983 	
3984 	   return nlp->primalsolobjval;
3985 	}
3986 	
3987 	/** gives current pseudo objective value */
3988 	SCIP_RETCODE SCIPnlpGetPseudoObjval(
3989 	   SCIP_NLP*             nlp,                /**< current NLP data */
3990 	   BMS_BLKMEM*           blkmem,             /**< block memory */
3991 	   SCIP_SET*             set,                /**< global SCIP settings */
3992 	   SCIP_STAT*            stat,               /**< problem statistics data */
3993 	   SCIP_PROB*            prob,               /**< SCIP problem */
3994 	   SCIP_PRIMAL*          primal,             /**< primal data */
3995 	   SCIP_TREE*            tree,               /**< branch and bound tree */
3996 	   SCIP_LP*              lp,                 /**< SCIP LP */
3997 	   SCIP_Real*            pseudoobjval        /**< buffer to store pseudo objective value */
3998 	   )
3999 	{
4000 	   assert(nlp != NULL);
4001 	   assert(pseudoobjval != NULL);
4002 	
4003 	   if( nlp->divingobj != NULL )
4004 	   {
4005 	      assert(nlp->indiving);
4006 	      SCIP_CALL( SCIPnlrowGetPseudoActivity(nlp->divingobj, blkmem, set, stat, prob, primal, tree, lp, pseudoobjval) );
4007 	   }
4008 	   else
4009 	   {
4010 	      int i;
4011 	
4012 	      *pseudoobjval = 0.0;
4013 	      for( i = 0; i < nlp->nvars; ++i )
4014 	         *pseudoobjval += SCIPvarGetObj(nlp->vars[i]) * SCIPvarGetBestBoundLocal(nlp->vars[i]);
4015 	   }
4016 	
4017 	   return SCIP_OKAY;
4018 	}
4019 	
4020 	/** gets fractional variables of last NLP solution along with solution values and fractionalities
4021 	 */
4022 	SCIP_RETCODE SCIPnlpGetFracVars(
4023 	   SCIP_NLP*             nlp,                /**< NLP data structure */
4024 	   BMS_BLKMEM*           blkmem,             /**< block memory */
4025 	   SCIP_SET*             set,                /**< global SCIP settings */
4026 	   SCIP_STAT*            stat,               /**< problem statistics */
4027 	   SCIP_VAR***           fracvars,           /**< pointer to store the array of NLP fractional variables, or NULL */
4028 	   SCIP_Real**           fracvarssol,        /**< pointer to store the array of NLP fractional variables solution values, or NULL */
4029 	   SCIP_Real**           fracvarsfrac,       /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
4030 	   int*                  nfracvars,          /**< pointer to store the number of NLP fractional variables , or NULL */
4031 	   int*                  npriofracvars       /**< pointer to store the number of NLP fractional variables with maximal branching priority, or NULL */
4032 	   )
4033 	{
4034 	   assert(nlp != NULL);
4035 	
4036 	   SCIP_CALL( nlpCalcFracVars(nlp, blkmem, set, stat) );
4037 	   assert(nlp->fracvars     != NULL);
4038 	   assert(nlp->fracvarssol  != NULL);
4039 	   assert(nlp->fracvarsfrac != NULL);
4040 	
4041 	   if( fracvars != NULL )
4042 	      *fracvars = nlp->fracvars;
4043 	   if( fracvarssol != NULL )
4044 	      *fracvarssol = nlp->fracvarssol;
4045 	   if( fracvarsfrac != NULL )
4046 	      *fracvarsfrac = nlp->fracvarsfrac;
4047 	   if( nfracvars != NULL )
4048 	      *nfracvars = nlp->nfracvars;
4049 	   if( npriofracvars != NULL )
4050 	      *npriofracvars = nlp->npriofracvars;
4051 	
4052 	   return SCIP_OKAY;
4053 	}
4054 	
4055 	/** removes all redundant nonlinear rows */
4056 	SCIP_RETCODE SCIPnlpRemoveRedundantNlRows(
4057 	   SCIP_NLP*             nlp,                /**< current NLP data */
4058 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4059 	   SCIP_SET*             set,                /**< global SCIP settings */
4060 	   SCIP_STAT*            stat                /**< problem statistics */
4061 	   )
4062 	{
4063 	   SCIP_NLPSOLSTAT solstatus;
4064 	   SCIP_Bool isredundant;
4065 	   int i;
4066 	
4067 	   assert(nlp    != NULL);
4068 	   assert(blkmem != NULL);
4069 	   assert(set    != NULL);
4070 	   assert(stat   != NULL);
4071 	
4072 	   if( nlp->nnlrows == 0 )
4073 	      return SCIP_OKAY;
4074 	
4075 	   if( nlp->indiving )
4076 	   {
4077 	      SCIPerrorMessage("cannot remove redundant rows during NLP diving\n");
4078 	      return SCIP_ERROR;
4079 	   }
4080 	
4081 	   /* removing redundant rows should not change the solution status, so we reset it at the end */
4082 	   solstatus = nlp->solstat;
4083 	
4084 	   for( i = 0; i < nlp->nnlrows; ++i )
4085 	   {
4086 	      SCIP_CALL( SCIPnlrowIsRedundant(nlp->nlrows[i], blkmem, set, stat, &isredundant) );
4087 	      if( isredundant )
4088 	      {
4089 	         SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) );
4090 	      }
4091 	   }
4092 	
4093 	   nlp->solstat = solstatus;
4094 	
4095 	   return SCIP_OKAY;
4096 	}
4097 	
4098 	/** set initial guess (approximate primal solution) for next solve
4099 	 *
4100 	 *  array initguess must be NULL or have length at least SCIPnlpGetNVars()
4101 	 */
4102 	SCIP_RETCODE SCIPnlpSetInitialGuess(
4103 	   SCIP_SET*             set,                /**< global SCIP settings */
4104 	   SCIP_NLP*             nlp,                /**< current NLP data */
4105 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4106 	   SCIP_Real*            initguess           /**< new initial guess, or NULL to clear previous one */
4107 	   )
4108 	{
4109 	   assert(nlp    != NULL);
4110 	   assert(blkmem != NULL);
4111 	   assert(nlp->solver  != NULL);
4112 	   assert(nlp->problem != NULL);
4113 	
4114 	   /* if user wants to let NLP solver choose start point, then invalidate current initial guess both in NLP and in NLPI */
4115 	   if( initguess == NULL )
4116 	   {
4117 	      nlp->haveinitguess = FALSE;
4118 	      SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, NULL, NULL, NULL, NULL) );
4119 	      return SCIP_OKAY;
4120 	   }
4121 	
4122 	   if( nlp->initialguess != NULL )
4123 	   {
4124 	      BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4125 	   }
4126 	   else
4127 	   {
4128 	      assert( nlp->sizevars >= nlp->nvars );
4129 	      SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars) );
4130 	      BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars);
4131 	   }
4132 	   nlp->haveinitguess = TRUE;
4133 	
4134 	   return SCIP_OKAY;
4135 	}
4136 	
4137 	/** writes NLP to a file */
4138 	SCIP_RETCODE SCIPnlpWrite(
4139 	   SCIP_NLP*             nlp,                /**< current NLP data */
4140 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4141 	   SCIP_SET*             set,                /**< global SCIP settings */
4142 	   SCIP_STAT*            stat,               /**< problem statistics */
4143 	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
4144 	   const char*           fname               /**< file name */
4145 	   )
4146 	{
4147 	   FILE* file;
4148 	   int i;
4149 	
4150 	   assert(nlp != NULL);
4151 	
(1) Event cond_true: Condition "fname != NULL", taking true branch.
4152 	   if( fname != NULL )
4153 	   {
(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]
4154 	      file = fopen(fname, "w");
(4) Event cond_false: Condition "file == NULL", taking false branch.
4155 	      if( file == NULL )
4156 	      {
4157 	         SCIPerrorMessage("could not open file <%s> for writing\n", fname);
4158 	         return SCIP_FILECREATEERROR;
(5) Event if_end: End of if statement.
4159 	      }
(6) Event if_fallthrough: Falling through to end of if statement.
4160 	   }
4161 	   else
(7) Event if_end: End of if statement.
4162 	      file = stdout;
4163 	
(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]
4164 	   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]
4165 	   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]
4166 	   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]
4167 	   SCIPmessageFPrintInfo(messagehdlr, file, "  Rows: %d\n", nlp->nnlrows);
4168 	
(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]
4169 	   SCIPmessageFPrintInfo(messagehdlr, file, "VARIABLES\n");
(13) Event cond_false: Condition "i < nlp->nvars", taking false branch.
4170 	   for( i = 0; i < nlp->nvars; ++i )
4171 	   {
4172 	      SCIP_CALL( SCIPvarPrint(nlp->vars[i], set, messagehdlr, file) );
(14) Event loop_end: Reached end of loop.
4173 	   }
4174 	
(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]
4175 	   SCIPmessageFPrintInfo(messagehdlr, file, "NONLINEAR ROWS\n");
(16) Event cond_true: Condition "i < nlp->nnlrows", taking true branch.
4176 	   for( i = 0; i < nlp->nnlrows; ++i )
4177 	   {
(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]
4178 	      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]
4179 	      SCIP_CALL( SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file) );
4180 	   }
4181 	
4182 	   if( fname != NULL )
4183 	   {
4184 	      fclose(file);
4185 	   }
4186 	
4187 	   return SCIP_OKAY;
4188 	}
4189 	
4190 	/** gets array with variables of the NLP */
4191 	SCIP_VAR** SCIPnlpGetVars(
4192 	   SCIP_NLP*             nlp                 /**< current NLP data */
4193 	   )
4194 	{
4195 	   assert(nlp != NULL);
4196 	
4197 	   return nlp->vars;
4198 	}
4199 	
4200 	/** gets current number of variables in NLP */
4201 	int SCIPnlpGetNVars(
4202 	   SCIP_NLP*             nlp                 /**< current NLP data */
4203 	   )
4204 	{
4205 	   assert(nlp != NULL);
4206 	
4207 	   return nlp->nvars;
4208 	}
4209 	
4210 	/** computes for each variables the number of NLP rows in which the variable appears in a nonlinear var */
4211 	SCIP_RETCODE SCIPnlpGetVarsNonlinearity(
4212 	   SCIP_NLP*             nlp,                /**< current NLP data */
4213 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4214 	   SCIP_SET*             set,                /**< global SCIP settings */
4215 	   SCIP_STAT*            stat,               /**< problem statistics */
4216 	   int*                  nlcount             /**< an array of length at least SCIPnlpGetNVars() to store nonlinearity counts of variables */
4217 	   )
4218 	{
4219 	   SCIP_NLROW* nlrow;
4220 	   SCIP_EXPRITER* it;
4221 	   SCIP_EXPR* expr;
4222 	   int varidx;
4223 	   int c;
4224 	
4225 	   assert(nlp != NULL);
4226 	   assert(nlcount != NULL || nlp->nvars == 0);
4227 	
4228 	   BMSclearMemoryArray(nlcount, nlp->nvars);
4229 	
4230 	   SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4231 	
4232 	   for( c = 0; c < nlp->nnlrows; ++c )
4233 	   {
4234 	      nlrow = nlp->nlrows[c];
4235 	      assert(nlrow != NULL);
4236 	
4237 	      if( nlrow->expr == NULL )
4238 	         continue;
4239 	
4240 	      SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, FALSE) );
4241 	      for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4242 	      {
4243 	         if( !SCIPexprIsVar(set, expr) )
4244 	            continue;
4245 	
4246 	         assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr)));
4247 	
4248 	         varidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(expr));
4249 	         assert(varidx < nlp->nvars);
4250 	         assert(nlcount != NULL);
4251 	         ++nlcount[varidx];
4252 	      }
4253 	   }
4254 	
4255 	   SCIPexpriterFree(&it);
4256 	
4257 	   return SCIP_OKAY;
4258 	}
4259 	
4260 	
4261 	/** indicates whether there exists a row that contains a continuous variable in a nonlinear term
4262 	 *
4263 	 * @note The method may have to touch every row and nonlinear term to compute its result.
4264 	 */
4265 	SCIP_RETCODE SCIPnlpHasContinuousNonlinearity(
4266 	   SCIP_NLP*             nlp,                /**< current NLP data */
4267 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4268 	   SCIP_SET*             set,                /**< global SCIP settings */
4269 	   SCIP_STAT*            stat,               /**< problem statistics */
4270 	   SCIP_Bool*            result              /**< buffer to store whether continuous variable present in an expression of any row */
4271 	   )
4272 	{
4273 	   SCIP_NLROW* nlrow;
4274 	   SCIP_EXPRITER* it;
4275 	   SCIP_EXPR* expr;
4276 	   int c;
4277 	
4278 	   assert(nlp != NULL);
4279 	
4280 	   SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
4281 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4282 	
4283 	   *result = FALSE;
4284 	   for( c = 0; c < nlp->nnlrows && !*result; ++c )
4285 	   {
4286 	      nlrow = nlp->nlrows[c];
4287 	      assert(nlrow != NULL);
4288 	
4289 	      if( nlrow->expr == NULL )
4290 	         continue;
4291 	
4292 	      for( expr = SCIPexpriterRestartDFS(it, nlrow->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4293 	      {
4294 	         if( SCIPexprIsVar(set, expr) && SCIPvarGetType(SCIPgetVarExprVar(expr)) == SCIP_VARTYPE_CONTINUOUS )
4295 	         {
4296 	            *result = TRUE;
4297 	            break;
4298 	         }
4299 	      }
4300 	   }
4301 	
4302 	   SCIPexpriterFree(&it);
4303 	
4304 	   return SCIP_OKAY;
4305 	}
4306 	
4307 	/** gives dual solution values associated with lower bounds of NLP variables */
4308 	SCIP_Real* SCIPnlpGetVarsLbDualsol(
4309 	   SCIP_NLP*             nlp                 /**< current NLP data */
4310 	   )
4311 	{
4312 	   assert(nlp != NULL);
4313 	
4314 	   return nlp->varlbdualvals;
4315 	}
4316 	
4317 	/** gives dual solution values associated with upper bounds of NLP variables */
4318 	SCIP_Real* SCIPnlpGetVarsUbDualsol(
4319 	   SCIP_NLP*             nlp                 /**< current NLP data */
4320 	   )
4321 	{
4322 	   assert(nlp != NULL);
4323 	
4324 	   return nlp->varubdualvals;
4325 	}
4326 	
4327 	/** gets array with nonlinear rows of the NLP */
4328 	SCIP_NLROW** SCIPnlpGetNlRows(
4329 	   SCIP_NLP*             nlp                 /**< current NLP data */
4330 	   )
4331 	{
4332 	   assert(nlp != NULL);
4333 	
4334 	   return nlp->nlrows;
4335 	}
4336 	
4337 	/** gets current number of nonlinear rows in NLP */
4338 	int SCIPnlpGetNNlRows(
4339 	   SCIP_NLP*             nlp                 /**< current NLP data */
4340 	   )
4341 	{
4342 	   assert(nlp != NULL);
4343 	
4344 	   return nlp->nnlrows;
4345 	}
4346 	
4347 	/** gets the NLP solver interface */
4348 	SCIP_NLPI* SCIPnlpGetNLPI(
4349 	   SCIP_NLP*             nlp                 /**< current NLP data */
4350 	   )
4351 	{
4352 	   assert(nlp != NULL);
4353 	
4354 	   return nlp->solver;
4355 	}
4356 	
4357 	/** gets the NLP problem in the solver interface */
4358 	SCIP_NLPIPROBLEM* SCIPnlpGetNLPIProblem(
4359 	   SCIP_NLP*             nlp                 /**< current NLP data */
4360 	   )
4361 	{
4362 	   assert(nlp != NULL);
4363 	
4364 	   return nlp->problem;
4365 	}
4366 	
4367 	/** indicates whether NLP is currently in diving mode */
4368 	SCIP_Bool SCIPnlpIsDiving(
4369 	   SCIP_NLP*             nlp                 /**< current NLP data */
4370 	   )
4371 	{
4372 	   assert(nlp != NULL);
4373 	
4374 	   return nlp->indiving;
4375 	}
4376 	
4377 	/** gets solution status of current NLP */
4378 	SCIP_NLPSOLSTAT SCIPnlpGetSolstat(
4379 	   SCIP_NLP*             nlp                 /**< current NLP data */
4380 	   )
4381 	{
4382 	   assert(nlp != NULL);
4383 	
4384 	   return nlp->solstat;
4385 	}
4386 	
4387 	/** gets termination status of last NLP solve */
4388 	SCIP_NLPTERMSTAT SCIPnlpGetTermstat(
4389 	   SCIP_NLP*             nlp                 /**< current NLP data */
4390 	   )
4391 	{
4392 	   assert(nlp != NULL);
4393 	
4394 	   return nlp->termstat;
4395 	}
4396 	
4397 	/** gives statistics (number of iterations, solving time, ...) of last NLP solve */
4398 	SCIP_RETCODE SCIPnlpGetStatistics(
4399 	   SCIP_SET*             set,                /**< global SCIP settings */
4400 	   SCIP_NLP*             nlp,                /**< pointer to NLP datastructure */
4401 	   SCIP_NLPSTATISTICS*   statistics          /**< pointer to store statistics */
4402 	   )
4403 	{
4404 	   assert(nlp != NULL);
4405 	   assert(nlp->solver != NULL);
4406 	   assert(nlp->problem != NULL);
4407 	   assert(statistics != NULL);
4408 	
4409 	   SCIP_CALL( SCIPnlpiGetStatistics(set, nlp->solver, nlp->problem, statistics) );
4410 	
4411 	   return SCIP_OKAY;
4412 	}
4413 	
4414 	/** indicates whether a solution for the current NLP is available
4415 	 *
4416 	 * The solution may be optimal, feasible, or infeasible.
4417 	 * Thus, returns whether the NLP solution status is at most \ref SCIP_NLPSOLSTAT_LOCINFEASIBLE.
4418 	 */
4419 	SCIP_Bool SCIPnlpHasSolution(
4420 	   SCIP_NLP*             nlp                 /**< current NLP data */
4421 	   )
4422 	{
4423 	   assert(nlp != NULL);
4424 	
4425 	   return nlp->solstat <= SCIP_NLPSOLSTAT_LOCINFEASIBLE;
4426 	}
4427 	
4428 	/*
4429 	 * NLP diving methods
4430 	 */
4431 	
4432 	/** signals start of diving */
4433 	SCIP_RETCODE SCIPnlpStartDive(
4434 	   SCIP_NLP*             nlp,                /**< current NLP data */
4435 	   BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4436 	   SCIP_SET*             set,                /**< global SCIP settings */
4437 	   SCIP_STAT*            stat                /**< problem statistics */
4438 	   )
4439 	{
4440 	   assert(nlp != NULL);
4441 	
4442 	   if( nlp->indiving )
4443 	   {
4444 	      SCIPerrorMessage("NLP is already in diving mode\n");
4445 	      return SCIP_ERROR;
4446 	   }
4447 	
4448 	   if( nlp->solver == NULL )
4449 	   {
4450 	      /* 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.
4451 	       * So we forbid diving of no solver is available. */
4452 	      SCIPerrorMessage("Cannot start diving if no NLP solver is available\n");
4453 	      return SCIP_ERROR;
4454 	   }
4455 	
4456 	   SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) );
4457 	
4458 	   nlp->indiving = TRUE;
4459 	
4460 	   return SCIP_OKAY;
4461 	}
4462 	
4463 	/** resets the bound and objective changes made during diving and disables diving mode */
4464 	SCIP_RETCODE SCIPnlpEndDive(
4465 	   SCIP_NLP*             nlp,                /**< current NLP data */
4466 	   BMS_BLKMEM*           blkmem,             /**< block memory */
4467 	   SCIP_SET*             set,                /**< global SCIP settings */
4468 	   SCIP_STAT*            stat                /**< problem statistics data */
4469 	   )
4470 	{
4471 	   int i;
4472 	   int* varidx;
4473 	   SCIP_Real* varlb;
4474 	   SCIP_Real* varub;
4475 	
4476 	   assert(nlp != NULL);
4477 	   assert(set != NULL);
4478 	   assert(nlp->nvars == nlp->nvars_solver);
4479 	
4480 	   if( !nlp->indiving )
4481 	   {
4482 	      SCIPerrorMessage("NLP not in diving mode, cannot end dive\n");
4483 	      return SCIP_ERROR;
4484 	   }
4485 	
4486 	   assert(nlp->solver != NULL);
4487 	   assert(nlp->problem != NULL);
4488 	
4489 	   /* reset variable bounds in NLPI problem to their current values */
4490 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &varidx, nlp->nvars) );
4491 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &varlb,  nlp->nvars) );
4492 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &varub,  nlp->nvars) );
4493 	   for( i = 0; i < nlp->nvars; ++i )
4494 	   {
4495 	      varidx[i] = i;
4496 	      varlb[i] = SCIPvarGetLbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4497 	      varub[i] = SCIPvarGetUbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]);
4498 	   }
4499 	
4500 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nlp->nvars, varidx, varlb, varub) );
4501 	
4502 	   SCIPsetFreeBufferArray(set, &varidx);
4503 	   SCIPsetFreeBufferArray(set, &varlb);
4504 	   SCIPsetFreeBufferArray(set, &varub);
4505 	
4506 	   /* clear diving objective, if one was used (i.e., if SCIPnlpChgVarObjDive had been called)
4507 	    * the objective in the NLPI will be reset in the next flush */
4508 	   if( nlp->divingobj != NULL )
4509 	   {
4510 	      SCIP_CALL( SCIPnlrowRelease(&nlp->divingobj, blkmem, set, stat) );
4511 	      assert(nlp->divingobj == NULL);
4512 	      assert(nlp->objflushed == FALSE);
4513 	   }
4514 	
4515 	   /* we do not have a valid solution anymore */
4516 	   nlp->solstat  = SCIP_NLPSOLSTAT_UNKNOWN;
4517 	   nlp->termstat = SCIP_NLPTERMSTAT_OTHER;
4518 	   nlp->primalsolobjval = SCIP_INVALID;
4519 	
4520 	   nlp->indiving = FALSE;
4521 	
4522 	   return SCIP_OKAY;
4523 	}
4524 	
4525 	/** changes coefficient of variable in diving NLP */
4526 	SCIP_RETCODE SCIPnlpChgVarObjDive(
4527 	   SCIP_NLP*             nlp,                /**< current NLP data */
4528 	   BMS_BLKMEM*           blkmem,             /**< block memory */
4529 	   SCIP_SET*             set,                /**< global SCIP settings */
4530 	   SCIP_STAT*            stat,               /**< problem statistics data */
4531 	   SCIP_VAR*             var,                /**< variable which coefficient to change */
4532 	   SCIP_Real             coef                /**< new linear coefficient of variable in objective */
4533 	   )
4534 	{
4535 	   int pos;
4536 	   int objidx;
4537 	
4538 	   assert(nlp != NULL);
4539 	   assert(var != NULL);
4540 	   assert(SCIPhashmapExists(nlp->varhash, var));
4541 	   assert(nlp->indiving);
4542 	   assert(nlp->solver != NULL);
4543 	   assert(nlp->problem != NULL);
4544 	
4545 	   /* get position of variable in NLPI problem */
4546 	   pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4547 	   pos = nlp->varmap_nlp2nlpi[pos];
4548 	   assert(pos >= 0);
4549 	
4550 	   /* set coefficient in NLPI problem objective */
4551 	   objidx = -1;
4552 	   SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) );
4553 	
4554 	   /* create an nlrow that holds the diving objective, if not done yet */
4555 	   if( nlp->divingobj == NULL )
4556 	   {
4557 	      SCIP_Real* coefs;
4558 	      int        i;
4559 	
4560 	      SCIP_CALL( SCIPsetAllocBufferArray(set, &coefs, nlp->nvars) );
4561 	      for( i = 0; i < nlp->nvars; ++i )
4562 	         coefs[i] = SCIPvarGetObj(nlp->vars[i]);
4563 	
4564 	      SCIP_CALL( SCIPnlrowCreate(&nlp->divingobj, blkmem, set, stat, "divingobj",
4565 	            0.0, nlp->nvars, nlp->vars, coefs, NULL,
4566 	            -SCIPsetInfinity(set), SCIPsetInfinity(set),
4567 	            SCIP_EXPRCURV_LINEAR) );
4568 	
4569 	      SCIPsetFreeBufferArray(set, &coefs);
4570 	   }
4571 	   assert(nlp->divingobj != NULL);
4572 	
4573 	   /* modify coefficient in diving objective */
4574 	   SCIP_CALL( SCIPnlrowChgLinearCoef(nlp->divingobj, blkmem, set, stat, nlp, var, coef) );
4575 	
4576 	   /* remember that we have to store objective after diving ended */
4577 	   nlp->objflushed = FALSE;
4578 	
4579 	   return SCIP_OKAY;
4580 	}
4581 	
4582 	/** changes bounds of variable in diving NLP */
4583 	SCIP_RETCODE SCIPnlpChgVarBoundsDive(
4584 	   SCIP_SET*             set,                /**< global SCIP settings */
4585 	   SCIP_NLP*             nlp,                /**< current NLP data */
4586 	   SCIP_VAR*             var,                /**< variable which coefficient to change */
4587 	   SCIP_Real             lb,                 /**< new lower bound of variable */
4588 	   SCIP_Real             ub                  /**< new upper bound of variable */
4589 	   )
4590 	{
4591 	   int pos;
4592 	
4593 	   assert(nlp != NULL);
4594 	   assert(var != NULL);
4595 	   assert(SCIPhashmapExists(nlp->varhash, var));
4596 	   assert(nlp->indiving);
4597 	   assert(nlp->solver != NULL);
4598 	   assert(nlp->problem != NULL);
4599 	
4600 	   /* get position of variable in NLPI problem */
4601 	   pos = SCIPhashmapGetImageInt(nlp->varhash, var);
4602 	   pos = nlp->varmap_nlp2nlpi[pos];
4603 	   assert(pos >= 0);
4604 	
4605 	   /* set new bounds in NLPI */
4606 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) );
4607 	
4608 	   return SCIP_OKAY;
4609 	}
4610 	
4611 	/** changes bounds of a set of variables in diving NLP */
4612 	SCIP_RETCODE SCIPnlpChgVarsBoundsDive(
4613 	   SCIP_NLP*             nlp,                /**< current NLP data */
4614 	   SCIP_SET*             set,                /**< global SCIP settings */
4615 	   int                   nvars,              /**< number of variables which bounds to change */
4616 	   SCIP_VAR**            vars,               /**< variables which bounds to change */
4617 	   SCIP_Real*            lbs,                /**< new lower bounds of variables */
4618 	   SCIP_Real*            ubs                 /**< new upper bounds of variables */
4619 	   )
4620 	{
4621 	   int i;
4622 	   int* poss;
4623 	
4624 	   assert(nlp  != NULL);
4625 	   assert(vars != NULL || nvars == 0);
4626 	   assert(nlp->indiving);
4627 	   assert(lbs  != NULL || nvars == 0);
4628 	   assert(ubs  != NULL || nvars == 0);
4629 	   assert(nlp->solver != NULL);
4630 	   assert(nlp->problem != NULL);
4631 	
4632 	   if( nvars == 0 )
4633 	      return SCIP_OKAY;
4634 	
4635 	   SCIP_CALL( SCIPsetAllocBufferArray(set, &poss, nvars) );
4636 	
4637 	   for( i = 0; i < nvars; ++i )
4638 	   {
4639 	      assert(SCIPhashmapExists(nlp->varhash, vars[i]));  /*lint !e613*/
4640 	
4641 	      /* get position of variable in NLPI problem */
4642 	      poss[i] = SCIPhashmapGetImageInt(nlp->varhash, vars[i]);   /*lint !e613*/
4643 	      poss[i] = nlp->varmap_nlp2nlpi[poss[i]];
4644 	      assert(poss[i] >= 0);
4645 	   }
4646 	
4647 	   /* set new bounds in NLPI */
4648 	   SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nvars, poss, lbs, ubs) );
4649 	
4650 	   SCIPsetFreeBufferArray(set, &poss);
4651 	
4652 	   return SCIP_OKAY;
4653 	}
4654 	
4655 	/** returns whether the objective function has been changed during diving */
4656 	SCIP_Bool SCIPnlpIsDivingObjChanged(
4657 	   SCIP_NLP*             nlp                 /**< current NLP data */
4658 	   )
4659 	{
4660 	   return nlp->divingobj != NULL;
4661 	}
4662