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