1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SCIP is distributed under the terms of the ZIB Academic License.         */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SCIP; see the file COPYING. If not visit scip.zib.de.         */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   nlhdlr_default.c
17   	 * @ingroup DEFPLUGINS_NLHDLR
18   	 * @brief  default nonlinear handler that calls expression handler methods
19   	 * @author Stefan Vigerske
20   	 */
21   	
22   	#include <string.h>
23   	
24   	#include "scip/nlhdlr_default.h"
25   	#include "scip/pub_nlhdlr.h"
26   	#include "scip/cons_nonlinear.h"
27   	
28   	/* fundamental nonlinear handler properties */
29   	#define NLHDLR_NAME            "default"
30   	#define NLHDLR_DESC            "default handler for expressions"
31   	#define NLHDLR_DETECTPRIORITY  0
32   	#define NLHDLR_ENFOPRIORITY    0
33   	
34   	/** translate from one value of infinity to another
35   	 *
36   	 *  if val is &ge; infty1, then give infty2, else give val
37   	 */
38   	#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
39   	
40   	#define UNDERESTIMATEUSESACTIVITY 0x1u  /**< whether underestimation uses activity */
41   	#define OVERESTIMATEUSESACTIVITY  0x2u  /**< whether overestimation uses activity */
42   	
43   	/*lint -e666*/
44   	/*lint -e850*/
45   	
46   	/** evaluates an expression w.r.t. the values in the auxiliary variables */
47   	static
48   	SCIP_RETCODE evalExprInAux(
49   	   SCIP*                 scip,               /**< SCIP data structure */
50   	   SCIP_EXPR*            expr,               /**< expression to be evaluated */
51   	   SCIP_Real*            val,                /**< buffer to store value of expression */
52   	   SCIP_SOL*             sol                 /**< solution to be evaluated */
53   	   )
54   	{
55   	   SCIP_Real* childvals;
56   	   SCIP_VAR* childvar;
57   	   int c;
58   	
59   	   assert(scip != NULL);
60   	   assert(expr != NULL);
61   	   assert(val != NULL);
62   	   assert(SCIPexprGetNChildren(expr) > 0);
63   	
64   	   SCIP_CALL( SCIPallocBufferArray(scip, &childvals, SCIPexprGetNChildren(expr)) );
65   	
66   	   for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
67   	   {
68   	      childvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[c]);
69   	      /* there should be an auxiliary variable, because we created them in detect for every child if we said that we will separate;
70   	       * at the moment, EVALAUX should only be called for nlhdlrs that said they will separate
71   	       * if that changes, then we should handle this here, e.g., via *val = SCIPexprGetEvalValue(expr); break;
72   	       */
73   	      assert(childvar != NULL);
74   	
75   	      childvals[c] = SCIPgetSolVal(scip, sol, childvar);
76   	   }
77   	
78   	   SCIP_CALL( SCIPcallExprEval(scip, expr, childvals, val) );
79   	
80   	   SCIPfreeBufferArray(scip, &childvals);
81   	
82   	   return SCIP_OKAY;
83   	}
84   	
85   	/** check whether expression should be handled by the default nlhdlr
86   	 *
87   	 * if no nlhdlr so far provides enforcement or boundtightening for expr, then the default nlhdlr takes over
88   	 */
89   	static
90   	SCIP_DECL_NLHDLRDETECT(nlhdlrDetectDefault)
91   	{ /*lint --e{715}*/
92   	   SCIP_EXPRHDLR* exprhdlr;
93   	   SCIP_Bool estimatebelowusesactivity = FALSE;
94   	   SCIP_Bool estimateaboveusesactivity = FALSE;
95   	   int c;
96   	
97   	   assert(scip != NULL);
98   	   assert(nlhdlr != NULL);
99   	   assert(expr != NULL);
100  	   assert(enforcing != NULL);
101  	   assert(participating != NULL);
102  	   assert(nlhdlrexprdata != NULL);
103  	
104  	   exprhdlr = SCIPexprGetHdlr(expr);
105  	   assert(exprhdlr != NULL);
106  	
107  	   if( (*enforcing & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
108  	   {
109  	      /* expr handlers having reverseprop but no inteval is something that we don't support at the moment for simplicity */
110  	      assert(!SCIPexprhdlrHasReverseProp(exprhdlr) || SCIPexprhdlrHasIntEval(exprhdlr));
111  	
112  	      /* participate in inteval and/or reverseprop if that is not yet provided in enforcing and we have inteval */
113  	      if( SCIPexprhdlrHasIntEval(exprhdlr) )
114  	         *participating = SCIP_NLHDLR_METHOD_ACTIVITY;
115  	   }
116  	
117  	   /* participate in sepa if exprhdlr for expr has an estimate callback and sepa below or above is still missing */
118  	   if( ((*enforcing & SCIP_NLHDLR_METHOD_SEPABOTH) != SCIP_NLHDLR_METHOD_SEPABOTH) && SCIPexprhdlrHasEstimate(exprhdlr) )
119  	   {
120  	      /* communicate back that the nlhdlr will provide the separation on the currently missing sides */
121  	      if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 )
122  	         *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
123  	
124  	      if( (*enforcing & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 )
125  	         *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
126  	   }
127  	
128  	   if( !*participating )
129  	      return SCIP_OKAY;
130  	
131  	   /* since this is the default handler, we enforce where we participate */
132  	   *enforcing |= *participating;
133  	
134  	   /* increment activity usage counter and create auxiliary variables if necessary
135  	    * if separating, first guess whether we will use activities in estimate (distinguish under- and overestimation)
136  	    * we assume that the exprhdlr will use activity on all children iff we are estimating on a nonconvex side
137  	    * TODO it would be better to request this information directly from the exprhdlr than inferring it from curvature,
138  	    * but with the currently available exprhdlr that wouldn't make a difference
139  	    */
140  	   if( *participating & SCIP_NLHDLR_METHOD_SEPABOTH )
141  	   {
142  	      SCIP_EXPRCURV* childcurv;
143  	
144  	      /* allocate memory to store the required curvature of the children (though we don't use it) */
145  	      SCIP_CALL( SCIPallocBufferArray(scip, &childcurv, SCIPexprGetNChildren(expr)) );
146  	
147  	      if( *participating & SCIP_NLHDLR_METHOD_SEPABELOW )
148  	      {
149  	         /* check whether the expression is convex */
150  	         SCIP_Bool isconvex;
151  	         SCIP_CALL( SCIPcallExprCurvature(scip, expr, SCIP_EXPRCURV_CONVEX, &isconvex, childcurv) );
152  	         estimatebelowusesactivity = !isconvex;
153  	      }
154  	
155  	      if( *participating & SCIP_NLHDLR_METHOD_SEPAABOVE )
156  	      {
157  	         /* check whether the expression is concave */
158  	         SCIP_Bool isconcave;
159  	         SCIP_CALL( SCIPcallExprCurvature(scip, expr, SCIP_EXPRCURV_CONCAVE, &isconcave, childcurv) );
160  	         estimateaboveusesactivity = !isconcave;
161  	      }
162  	
163  	      /* free memory */
164  	      SCIPfreeBufferArray(scip, &childcurv);
165  	   }
166  	
167  	   /* indicate enforcement methods required in children:
168  	    * - if separating, make sure that (auxiliary) variable will exist
169  	    * - if activity computation, then register activity usage
170  	    * - if estimating on a non-convex side, then indicate activity usage for separation for that side
171  	    */
172  	   for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
173  	   {
174  	      /* todo skip auxvarusage for value-expressions? would then need update in evalExprInAux, too */
175  	      SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, SCIPexprGetChildren(expr)[c],
176  	         *participating & SCIP_NLHDLR_METHOD_SEPABOTH,
177  	         *participating & SCIP_NLHDLR_METHOD_ACTIVITY, estimatebelowusesactivity, estimateaboveusesactivity) );
178  	   }
179  	
180  	   /* remember estimatebelowusesactivity and estimateaboveusesactivity in nlhdlrexprdata */
181  	   *nlhdlrexprdata = (SCIP_NLHDLREXPRDATA*)(size_t)((estimatebelowusesactivity ? UNDERESTIMATEUSESACTIVITY : 0x0u)
182  	      | (estimateaboveusesactivity ? OVERESTIMATEUSESACTIVITY : 0x0u));
183  	
184  	   return SCIP_OKAY;
185  	}
186  	
187  	/** evaluate expression w.r.t. values of auxiliary variables in children */
188  	static
189  	SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalAuxDefault)
190  	{ /*lint --e{715}*/
191  	   assert(expr != NULL);
192  	   assert(auxvalue != NULL);
193  	
194  	   SCIP_CALL( evalExprInAux(scip, expr, auxvalue, sol) );
195  	
196  	   return SCIP_OKAY;
197  	}
198  	
199  	/** initialize LP relaxation by initial estimators */
200  	static
201  	SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaDefault)
202  	{ /*lint --e{715}*/
203  	   SCIP_INTERVAL* childrenbounds;
204  	   SCIP_Real* coefs[SCIP_EXPR_MAXINITESTIMATES];
205  	   SCIP_Real constant[SCIP_EXPR_MAXINITESTIMATES];
206  	   SCIP_VAR* auxvar;
207  	   SCIP_ROWPREP* rowprep;
208  	   int nreturned;
209  	   int i, j;
210  	
211  	   assert(scip != NULL);
212  	   assert(expr != NULL);
213  	   assert(infeasible != NULL);
214  	
215  	   *infeasible = FALSE;
216  	
217  	   if( !SCIPexprhdlrHasInitEstimates(SCIPexprGetHdlr(expr)) )
218  	      return SCIP_OKAY;
219  	
220  	   SCIPdebug( SCIPinfoMessage(scip, NULL, "initsepa exprhdlr %s for expr ", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))) );
221  	   SCIPdebug( SCIPprintExpr(scip, expr, NULL) );
222  	   SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
223  	
224  	   /* use global bounds of auxvar as global valid bounds for children
225  	    * if at root node (thus local=global) and estimate actually uses bounds, then intersect with (local) activity of expression
226  	    */
227  	   SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
228  	   for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
229  	   {
230  	      auxvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[i]);
231  	      assert(auxvar != NULL);
232  	
233  	      SCIPintervalSetBounds(&childrenbounds[i],
234  	         -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -SCIPvarGetLbGlobal(auxvar)),
235  	          infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY,  SCIPvarGetUbGlobal(auxvar)));
236  	
237  	      if( SCIPgetDepth(scip) == 0 &&
238  	          ((underestimate && ((size_t)nlhdlrexprdata & UNDERESTIMATEUSESACTIVITY)) ||
239  	           (overestimate  && ((size_t)nlhdlrexprdata & OVERESTIMATEUSESACTIVITY ))) )
240  	      {
241  	         SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(expr)[i]) );
242  	         SCIPintervalIntersect(&childrenbounds[i], childrenbounds[i], SCIPexprGetActivity(SCIPexprGetChildren(expr)[i]));
243  	      }
244  	
245  	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childrenbounds[i]) )
246  	      {
247  	         SCIPdebugMsg(scip, "activity for expression %d (unexpectedly) empty in initsepa\n", i);
248  	         *infeasible = TRUE;
249  	         SCIPfreeBufferArray(scip, &childrenbounds);
250  	         return SCIP_OKAY;
251  	      }
252  	   }
253  	
254  	   /* allocate each coefficients array */
255  	   for( i = 0; i < SCIP_EXPR_MAXINITESTIMATES; ++i )
256  	   {
257  	      SCIP_CALL( SCIPallocBufferArray(scip, &coefs[i], SCIPexprGetNChildren(expr)) );
258  	   }
259  	
260  	   /* create rowprep */
261  	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, SCIP_SIDETYPE_RIGHT, FALSE) );
262  	   SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, SCIPexprGetNChildren(expr)+1) );
263  	
264  	   /* call the separation initialization callback of the expression handler and turn estimates into SCIP rows */
265  	   for( i = 0; i < 2 && !*infeasible; ++i )
266  	   {
267  	      nreturned = 0;
268  	      if( i == 0 && underestimate )
269  	      {
270  	         SCIP_CALL( SCIPcallExprInitestimates(scip, expr, childrenbounds, FALSE, coefs, constant, &nreturned) );
271  	         assert(SCIProwprepGetSidetype(rowprep) == SCIP_SIDETYPE_RIGHT);
272  	      }
273  	      if( i == 1 && overestimate )
274  	      {
275  	         SCIP_CALL( SCIPcallExprInitestimates(scip, expr, childrenbounds, TRUE, coefs, constant, &nreturned) );
276  	         SCIProwprepSetSidetype(rowprep, SCIP_SIDETYPE_LEFT);
277  	      }
278  	
279  	      for( j = 0; j < nreturned && !*infeasible; ++j )
280  	      {
281  	         SCIP_Bool success;
282  	         int v;
283  	
284  	         SCIProwprepReset(rowprep);
285  	
286  	         for( v = 0; v < SCIPexprGetNChildren(expr); ++v )
287  	         {
288  	            SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[v]), coefs[j][v]) );
289  	         }
290  	         SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
291  	         SCIProwprepAddConstant(rowprep, constant[j]);  /*lint !e644*/
292  	
293  	         /* special treatment for sums to get equality rows */
294  	         if( j == 0 && SCIPisExprSum(scip, expr) )
295  	         {
296  	            SCIP_Real scalefactor;
297  	            SCIP_ROW* row;
298  	
299  	            /* improve numerics by scaling only (does not relax inequality) */
300  	            scalefactor = SCIPscaleupRowprep(scip, rowprep, 1.0, &success);
301  	            if( success && scalefactor == 1.0 && underestimate && overestimate )
302  	            {
303  	               /* if the rowprep didn't have to be changed, then turn it into a row, change this to an equality, and add it to the LP */
304  	               /* TODO do this also if not actually needing both under- and overestimator (should still be valid, but also stronger?) */
305  	               (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "initestimate_sum", j);
306  	
307  	               SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
308  	
309  	               /* since we did not relax the estimator, we can turn the row into an equality */
310  	               if( SCIPisInfinity(scip, SCIProwGetRhs(row)) )
311  	               {
312  	                  SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetLhs(row)) );
313  	               }
314  	               else
315  	               {
316  	                  SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetRhs(row)) );
317  	               }
318  	               SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
319  	
320  	               SCIPdebug( SCIPinfoMessage(scip, NULL, "  added %scut ", *infeasible ? "infeasible " : "") );
321  	               SCIPdebug( SCIPprintRow(scip, row, NULL) );
322  	
323  	               SCIP_CALL( SCIPreleaseRow(scip, &row) );
324  	
325  	               i = 2;  /* to break outside loop on i, too */
326  	               break;
327  	            }
328  	         }
329  	
330  	         /* straighten out numerics */
331  	         SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, NULL, SCIPgetHugeValue(scip), &success) );
332  	
333  	         /* if cleanup removed all but one variable, then the cut is essentially a bound; we can skip this and rely on boundtightening */
334  	         if( success && SCIProwprepGetNVars(rowprep) > 1 )
335  	         {
336  	            /* add the cut */
337  	            SCIP_ROW* row;
338  	
339  	            (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "init%sestimate%d_%s",
340  	                  i == 0 ? "under" : "over", j, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
341  	
342  	            SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
343  	            SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
344  	
345  	            SCIPdebug( SCIPinfoMessage(scip, NULL, "  added %scut ", *infeasible ? "infeasible " : "") );
346  	            SCIPdebug( SCIPprintRow(scip, row, NULL) );
347  	
348  	            SCIP_CALL( SCIPreleaseRow(scip, &row) );
349  	         }
350  	      }
351  	   }
352  	
353  	   SCIPfreeRowprep(scip, &rowprep);
354  	
355  	   for( i = SCIP_EXPR_MAXINITESTIMATES-1; i >= 0; --i )
356  	   {
357  	      SCIPfreeBufferArray(scip, &coefs[i]);
358  	   }
359  	
360  	   SCIPfreeBufferArray(scip, &childrenbounds);
361  	
362  	   return SCIP_OKAY;
363  	}
364  	
365  	/** compute linear estimator */
366  	static
367  	SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateDefault)
368  	{ /*lint --e{715}*/
369  	   SCIP_Real constant;
370  	   SCIP_Bool local;
371  	   SCIP_Bool* branchcand = NULL;
372  	   int nchildren;
373  	   int c;
374  	   SCIP_INTERVAL* localbounds;
375  	   SCIP_INTERVAL* globalbounds;
376  	   SCIP_Real* refpoint;
377  	   SCIP_ROWPREP* rowprep;
378  	   SCIP_VAR* auxvar;
379  	
380  	   assert(scip != NULL);
381  	   assert(expr != NULL);
382  	   assert(rowpreps != NULL);
383  	   assert(success != NULL);
384  	
385  	   *addedbranchscores = FALSE;
386  	
387  	   nchildren = SCIPexprGetNChildren(expr);
388  	
389  	   SCIP_CALL( SCIPallocBufferArray(scip, &localbounds, nchildren) );
390  	   SCIP_CALL( SCIPallocBufferArray(scip, &globalbounds, nchildren) );
391  	   SCIP_CALL( SCIPallocBufferArray(scip, &refpoint, nchildren) );
392  	   /* we need to pass a branchcand array to exprhdlr's estimate also if not asked to add branching scores */
393  	   SCIP_CALL( SCIPallocBufferArray(scip, &branchcand, nchildren) );
394  	
395  	   SCIPdebug( SCIPinfoMessage(scip, NULL, "estimate exprhdlr %s for expr ", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))) );
396  	   SCIPdebug( SCIPprintExpr(scip, expr, NULL) );
397  	   SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
398  	
399  	   for( c = 0; c < nchildren; ++c )
400  	   {
401  	      auxvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[c]);
402  	      assert(auxvar != NULL);
403  	
404  	      SCIPintervalSetBounds(&localbounds[c],
405  	         -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -SCIPvarGetLbLocal(auxvar)),
406  	          infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY,  SCIPvarGetUbLocal(auxvar)));
407  	
408  	      if( ((size_t)nlhdlrexprdata & (overestimate ? OVERESTIMATEUSESACTIVITY : UNDERESTIMATEUSESACTIVITY)) )
409  	      {
410  	         /* if expr estimate uses bounds, then intersect the auxvar bounds with the current activity, in case the latter is a bit tighter */
411  	         SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(expr)[c]) );
412  	         SCIPintervalIntersectEps(&localbounds[c], SCIPepsilon(scip), localbounds[c], SCIPexprGetActivity(SCIPexprGetChildren(expr)[c]));
413  	
414  	         if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, localbounds[c]) )
415  	         {
416  	            *success = FALSE;
417  	            goto TERMINATE;
418  	         }
419  	      }
420  	      else
421  	      {
422  	         /* if we think that expr estimate wouldn't use bounds, then just set something valid */
423  	      }
424  	
425  	      SCIPintervalSetBounds(&globalbounds[c],
426  	         -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -SCIPvarGetLbGlobal(auxvar)),
427  	          infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY,  SCIPvarGetUbGlobal(auxvar)));
428  	
429  	      refpoint[c] = SCIPgetSolVal(scip, sol, auxvar);
430  	
431  	      branchcand[c] = TRUE;
432  	   }
433  	
434  	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT, TRUE) );
435  	
436  	   /* make sure enough space is available in rowprep arrays */
437  	   SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nchildren) );
438  	
439  	   /* call the estimation callback of the expression handler */
440  	   SCIP_CALL( SCIPcallExprEstimate(scip, expr, localbounds, globalbounds, refpoint, overestimate, targetvalue,
441  	         SCIProwprepGetCoefs(rowprep), &constant, &local, success, branchcand) );
442  	
443  	   if( *success )
444  	   {
445  	      int i;
446  	
447  	      SCIProwprepSetLocal(rowprep, local);
448  	
449  	      /* add variables to rowprep (coefs were already added by SCIPexprhdlrEstimateExpr) */
450  	      for( i = 0; i < nchildren; ++i )
451  	      {
452  	         SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[i]),
453  	               SCIProwprepGetCoefs(rowprep)[i]) );
454  	      }
455  	
456  	      SCIProwprepAddConstant(rowprep, constant);
457  	
458  	      SCIPdebug( SCIPinfoMessage(scip, NULL, "  found rowprep ") );
459  	      SCIPdebug( SCIPprintRowprepSol(scip, rowprep, sol, NULL) );
460  	
461  	      SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
462  	
463  	      (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_%s%p_%s%d",
464  	         overestimate ? "over" : "under",
465  	         SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
466  	         (void*)expr,
467  	         sol != NULL ? "sol" : "lp",
468  	         sol != NULL ? SCIPsolGetIndex(sol) : SCIPgetNLPs(scip));
469  	   }
470  	   else
471  	   {
472  	      SCIPfreeRowprep(scip, &rowprep);
473  	   }
474  	
475  	   if( addbranchscores )
476  	   {
477  	      SCIP_Real violation;
478  	
479  	#ifndef BRSCORE_ABSVIOL
480  	      SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violation, NULL, NULL) );
481  	#else
482  	      SCIP_CALL( SCIPgetExprAbsAuxViolationNonlinear(scip, expr, auxvalue, sol, &violation, NULL, NULL) );
483  	#endif
484  	      assert(violation > 0.0);  /* there should be a violation if we were called to enforce */
485  	
486  	      if( nchildren == 1 )
487  	      {
488  	         if( branchcand[0] )
489  	         {
490  	            SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, SCIPexprGetChildren(expr), 1, violation, sol, addedbranchscores) );
491  	         }
492  	      }
493  	      else
494  	      {
495  	         SCIP_EXPR** exprs;
496  	         int nexprs = 0;
497  	
498  	         /* get list of those children that have the branchcand-flag set */
499  	         SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
500  	
501  	         for( c = 0; c < nchildren; ++c )
502  	            if( branchcand[c] )
503  	               exprs[nexprs++] = SCIPexprGetChildren(expr)[c];
504  	
505  	         SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violation, sol, addedbranchscores) );
506  	
507  	         SCIPfreeBufferArray(scip, &exprs);
508  	      }
509  	
510  	      if( *addedbranchscores )
511  	      {
512  	         /* count this branchscore as belonging to the exprhdlr, too
513  	          * thus, it will be counted for the default nlhdlr, but also for this exprhdlr
514  	          */
515  	         SCIPexprhdlrIncrementNBranchings(SCIPexprGetHdlr(expr));
516  	      }
517  	   }
518  	
519  	TERMINATE:
520  	   SCIPfreeBufferArray(scip, &branchcand);
521  	   SCIPfreeBufferArray(scip, &refpoint);
522  	   SCIPfreeBufferArray(scip, &globalbounds);
523  	   SCIPfreeBufferArray(scip, &localbounds);
524  	
525  	   return SCIP_OKAY;
526  	}
527  	
528  	/** interval-evaluate expression w.r.t. activity of children */
529  	static
530  	SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalDefault)
531  	{ /*lint --e{715}*/
532  	   assert(scip != NULL);
533  	   assert(expr != NULL);
534  	
535  	   /* call the interval evaluation callback of the expression handler */
536  	   SCIP_CALL( SCIPcallExprInteval(scip, expr, interval, intevalvar, intevalvardata) );
537  	
538  	   return SCIP_OKAY;
539  	}
540  	
541  	/** tighten bounds on children from bounds on expression and bounds on children */
542  	static
543  	SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropDefault)
544  	{ /*lint --e{715}*/
545  	   SCIP_INTERVAL* childrenbounds;
546  	   int c;
547  	
548  	   assert(scip != NULL);
549  	   assert(expr != NULL);
550  	   assert(infeasible != NULL);
551  	   assert(nreductions != NULL);
552  	
553  	   *nreductions = 0;
554  	
555  	   SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
556  	   for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
557  	      childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
558  	
559  	   /* call the reverse propagation callback of the expression handler */
560  	   SCIP_CALL( SCIPcallExprReverseprop(scip, expr, bounds, childrenbounds, infeasible) );
561  	
562  	   if( !*infeasible )
563  	   {
564  	      for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
565  	      {
566  	         SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c],
567  	               infeasible, nreductions) );
568  	      }
569  	      SCIPexprhdlrIncrementNDomainReductions(SCIPexprGetHdlr(expr), *nreductions);
570  	   }
571  	
572  	   SCIPfreeBufferArray(scip, &childrenbounds);
573  	
574  	   return SCIP_OKAY;
575  	}
576  	
577  	/** nonlinear handler copy callback */
578  	static
579  	SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrDefault)
580  	{ /*lint --e{715}*/
581  	   assert(targetscip != NULL);
582  	   assert(sourcenlhdlr != NULL);
583  	   assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), NLHDLR_NAME) == 0);
584  	
585  	   SCIP_CALL( SCIPincludeNlhdlrDefault(targetscip) );
586  	
587  	   return SCIP_OKAY;
588  	}
589  	
590  	/** callback to free expression specific data */
591  	static
592  	SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataDefault)
593  	{  /*lint --e{715}*/
594  	   assert(nlhdlrexprdata != NULL);
595  	
596  	   *nlhdlrexprdata = NULL;
597  	
598  	   return SCIP_OKAY;
599  	}
600  	
601  	/** includes default nonlinear handler in nonlinear constraint handler */
602  	SCIP_RETCODE SCIPincludeNlhdlrDefault(
603  	   SCIP*                 scip                /**< SCIP data structure */
604  	   )
605  	{
606  	   SCIP_NLHDLR* nlhdlr;
607  	
608  	   assert(scip != NULL);
609  	
(1) Event alloc_arg: "SCIPincludeNlhdlrNonlinear" allocates memory that is stored into "nlhdlr". [details]
(2) Event cond_true: Condition "(_restat_ = SCIPincludeNlhdlrNonlinear(scip, &nlhdlr, "default", "default handler for expressions", 0, 0, nlhdlrDetectDefault, nlhdlrEvalAuxDefault, NULL)) != SCIP_OKAY", taking true branch.
(3) Event leaked_storage: Variable "nlhdlr" going out of scope leaks the storage it points to.
610  	   SCIP_CALL( SCIPincludeNlhdlrNonlinear(scip, &nlhdlr, NLHDLR_NAME, NLHDLR_DESC, NLHDLR_DETECTPRIORITY,
611  	         NLHDLR_ENFOPRIORITY, nlhdlrDetectDefault, nlhdlrEvalAuxDefault, NULL) );
612  	   assert(nlhdlr != NULL);
613  	
614  	   SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrDefault);
615  	   SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataDefault);
616  	   SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaDefault, NULL, nlhdlrEstimateDefault, NULL);
617  	   SCIPnlhdlrSetProp(nlhdlr, nlhdlrIntevalDefault, nlhdlrReversepropDefault);
618  	
619  	   return SCIP_OKAY;
620  	}
621