1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2020 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_convex.c
17   	 * @ingroup DEFPLUGINS_NLHDLR
18   	 * @brief  nonlinear handlers for convex and concave expressions
19   	 * @author Benjamin Mueller
20   	 * @author Stefan Vigerske
21   	 *
22   	 * TODO convex: perturb reference point if separation fails due to too large numbers
23   	 */
24   	
25   	#include <string.h>
26   	
27   	#include "scip/nlhdlr_convex.h"
28   	#include "scip/pub_nlhdlr.h"
29   	#include "scip/scip_expr.h"
30   	#include "scip/cons_nonlinear.h"
31   	#include "scip/expr_var.h"
32   	#include "scip/pub_misc_rowprep.h"
33   	#include "scip/dbldblarith.h"
34   	
35   	/* fundamental nonlinear handler properties */
36   	#define CONVEX_NLHDLR_NAME             "convex"
37   	#define CONVEX_NLHDLR_DESC             "handler that identifies and estimates convex expressions"
38   	#define CONVEX_NLHDLR_DETECTPRIORITY   50
39   	#define CONVEX_NLHDLR_ENFOPRIORITY     50
40   	
41   	#define CONCAVE_NLHDLR_NAME            "concave"
42   	#define CONCAVE_NLHDLR_DESC            "handler that identifies and estimates concave expressions"
43   	#define CONCAVE_NLHDLR_DETECTPRIORITY  40
44   	#define CONCAVE_NLHDLR_ENFOPRIORITY    40
45   	
46   	#define DEFAULT_DETECTSUM             FALSE
47   	#define DEFAULT_EXTENDEDFORM          TRUE
48   	#define DEFAULT_CVXQUADRATIC_CONVEX   TRUE
49   	#define DEFAULT_CVXQUADRATIC_CONCAVE  FALSE
50   	#define DEFAULT_CVXSIGNOMIAL          TRUE
51   	#define DEFAULT_CVXPRODCOMP           TRUE
52   	#define DEFAULT_HANDLETRIVIAL         FALSE
53   	
54   	#define INITLPMAXVARVAL          1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
55   	
56   	/*lint -e440*/
57   	/*lint -e441*/
58   	/*lint -e666*/
59   	/*lint -e777*/
60   	
61   	/*
62   	 * Data structures
63   	 */
64   	
65   	/** nonlinear handler expression data */
66   	struct SCIP_NlhdlrExprData
67   	{
68   	   SCIP_EXPR*            nlexpr;             /**< expression (copy) for which this nlhdlr estimates */
69   	   SCIP_HASHMAP*         nlexpr2origexpr;    /**< mapping of our copied expression to original expression */
70   	
71   	   int                   nleafs;             /**< number of distinct leafs of nlexpr, i.e., number of distinct (auxiliary) variables handled */
72   	   SCIP_EXPR**           leafexprs;          /**< distinct leaf expressions (excluding value-expressions), thus variables */
73   	};
74   	
75   	/** nonlinear handler data */
76   	struct SCIP_NlhdlrData
77   	{
78   	   SCIP_Bool             isnlhdlrconvex;     /**< whether this data is used for the convex nlhdlr (TRUE) or the concave one (FALSE) */
79   	   SCIP_SOL*             evalsol;            /**< solution used for evaluating expression in a different point,
80   	                                                  e.g., for facet computation of vertex-polyhedral function */
81   	
82   	   /* parameters */
83   	   SCIP_Bool             detectsum;          /**< whether to run detection when the root of an expression is a non-quadratic sum */
84   	   SCIP_Bool             extendedform;       /**< whether to create extended formulations instead of looking for maximal possible subexpression */
85   	
86   	   /* advanced parameters (maybe remove some day) */
87   	   SCIP_Bool             cvxquadratic;       /**< whether to use convexity check on quadratics */
88   	   SCIP_Bool             cvxsignomial;       /**< whether to use convexity check on signomials */
89   	   SCIP_Bool             cvxprodcomp;        /**< whether to use convexity check on product composition f(h)*h */
90   	   SCIP_Bool             handletrivial;      /**< whether to handle trivial expressions, i.e., those where all children are variables */
91   	};
92   	
93   	/** data struct to be be passed on to vertexpoly-evalfunction (see SCIPcomputeFacetVertexPolyhedralNonlinear) */
94   	typedef struct
95   	{
96   	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata;
97   	   SCIP_SOL*             evalsol;
98   	   SCIP*                 scip;
99   	} VERTEXPOLYFUN_EVALDATA;
100  	
101  	/** stack used in constructExpr to store expressions that need to be investigated ("to do list") */
102  	typedef struct
103  	{
104  	   SCIP_EXPR**           stack;              /**< stack elements */
105  	   int                   stacksize;          /**< allocated space (in number of pointers) */
106  	   int                   stackpos;           /**< position of top element of stack */
107  	} EXPRSTACK;
108  	
109  	#define DECL_CURVCHECK(x) SCIP_RETCODE x( \
110  	   SCIP*                 scip,               /**< SCIP data structure */ \
111  	   SCIP_EXPR*            nlexpr,             /**< nlhdlr-expr to check */ \
112  	   SCIP_Bool             isrootexpr,         /**< whether nlexpr is the root from where detection has been started */ \
113  	   EXPRSTACK*            stack,              /**< stack where to add generated leafs */ \
114  	   SCIP_HASHMAP*         nlexpr2origexpr,    /**< mapping from our expression copy to original expression */ \
115  	   SCIP_NLHDLRDATA*      nlhdlrdata,         /**< data of nlhdlr */ \
116  	   SCIP_HASHMAP*         assumevarfixed,     /**< hashmap containing variables that should be assumed to be fixed, or NULL */ \
117  	   SCIP_Bool*            success             /**< whether we found something */ \
118  	   )
119  	
120  	/*
121  	 * static methods
122  	 */
123  	
124  	/** create nlhdlr-expression
125  	 *
126  	 * does not create children, i.e., assumes that this will be a leaf
127  	 */
128  	static
129  	SCIP_RETCODE nlhdlrExprCreate(
130  	   SCIP*                 scip,               /**< SCIP data structure */
131  	   SCIP_HASHMAP*         nlexpr2origexpr,    /**< mapping from copied to original expression */
132  	   SCIP_EXPR**           nlhdlrexpr,         /**< buffer to store created expr */
133  	   SCIP_EXPR*            origexpr,           /**< original expression to be copied */
134  	   SCIP_EXPRCURV         curv                /**< curvature to achieve */
135  	   )
136  	{
137  	   assert(scip != NULL);
138  	   assert(nlexpr2origexpr != NULL);
139  	   assert(nlhdlrexpr != NULL);
140  	   assert(origexpr != NULL);
141  	
142  	   if( SCIPexprGetNChildren(origexpr) == 0 )
143  	   {
144  	      /* for leaves, do not copy */
145  	      *nlhdlrexpr = origexpr;
146  	      SCIPcaptureExpr(*nlhdlrexpr);
147  	      if( !SCIPhashmapExists(nlexpr2origexpr, (void*)*nlhdlrexpr) )
148  	      {
149  	         SCIP_CALL( SCIPhashmapInsert(nlexpr2origexpr, (void*)*nlhdlrexpr, (void*)origexpr) );
150  	      }
151  	      return SCIP_OKAY;
152  	   }
153  	
154  	   /* create copy of expression, but without children */
155  	   SCIP_CALL( SCIPduplicateExprShallow(scip, origexpr, nlhdlrexpr, NULL, NULL) );
156  	   assert(*nlhdlrexpr != NULL);  /* copies within the same SCIP must always work */
157  	
158  	   /* store the curvature we want to get in the curvature flag of the copied expression
159  	    * it's a bit of a misuse, but once we are done with everything, this is actually correct
160  	    */
161  	   SCIPexprSetCurvature(*nlhdlrexpr, curv);
162  	
163  	   /* remember which the original expression was */
164  	   SCIP_CALL( SCIPhashmapInsert(nlexpr2origexpr, (void*)*nlhdlrexpr, (void*)origexpr) );
165  	
166  	   return SCIP_OKAY;
167  	}
168  	
169  	/** expand nlhdlr-expression by adding children according to original expression */
170  	static
171  	SCIP_RETCODE nlhdlrExprGrowChildren(
172  	   SCIP*                 scip,               /**< SCIP data structure */
173  	   SCIP_HASHMAP*         nlexpr2origexpr,    /**< mapping from copied to original expression */
174  	   SCIP_EXPR*            nlhdlrexpr,         /**< expression for which to create children */
175  	   SCIP_EXPRCURV*        childrencurv        /**< curvature required for children, or NULL if to set to UNKNOWN */
176  	   )
177  	{
178  	   SCIP_EXPR* origexpr;
179  	   SCIP_EXPR* child;
180  	   int nchildren;
181  	   int i;
182  	
183  	   assert(scip != NULL);
184  	   assert(nlhdlrexpr != NULL);
185  	   assert(SCIPexprGetNChildren(nlhdlrexpr) == 0);
186  	
187  	   origexpr = (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlhdlrexpr);
188  	
189  	   nchildren = SCIPexprGetNChildren(origexpr);
190  	   if( nchildren == 0 )
191  	      return SCIP_OKAY;
192  	
193  	   for( i = 0; i < nchildren; ++i )
194  	   {
195  	      SCIP_CALL( nlhdlrExprCreate(scip, nlexpr2origexpr, &child, SCIPexprGetChildren(origexpr)[i],
196  	         childrencurv != NULL ? childrencurv[i] : SCIP_EXPRCURV_UNKNOWN) );
197  	      SCIP_CALL( SCIPappendExprChild(scip, nlhdlrexpr, child) );
198  	      /* append captures child, so we can release the capture from nlhdlrExprCreate */
199  	      SCIP_CALL( SCIPreleaseExpr(scip, &child) );
200  	   }
201  	
202  	   assert(SCIPexprGetNChildren(nlhdlrexpr) == SCIPexprGetNChildren(origexpr));
203  	
204  	   return SCIP_OKAY;
205  	}
206  	
207  	/** evaluate expression at solution w.r.t. auxiliary variables */
208  	static
209  	SCIP_DECL_VERTEXPOLYFUN(nlhdlrExprEvalConcave)
210  	{
211  	   VERTEXPOLYFUN_EVALDATA* evaldata = (VERTEXPOLYFUN_EVALDATA*)funcdata;
212  	   int i;
213  	
214  	   assert(args != NULL);
215  	   assert(nargs == evaldata->nlhdlrexprdata->nleafs);
216  	   assert(evaldata != NULL);
217  	
218  	#ifdef SCIP_MORE_DEBUG
219  	   SCIPdebugMsg(evaldata->scip, "eval vertexpolyfun at\n");
220  	#endif
221  	   for( i = 0; i < nargs; ++i )
222  	   {
223  	#ifdef SCIP_MORE_DEBUG
224  	      SCIPdebugMsg(evaldata->scip, "  <%s> = %g\n",
225  	            SCIPvarGetName(SCIPgetVarExprVar(evaldata->nlhdlrexprdata->leafexprs[i])), args[i]);
226  	#endif
227  	      SCIP_CALL_ABORT( SCIPsetSolVal(evaldata->scip, evaldata->evalsol,
228  	            SCIPgetVarExprVar(evaldata->nlhdlrexprdata->leafexprs[i]), args[i]) );
229  	   }
230  	
231  	   SCIP_CALL_ABORT( SCIPevalExpr(evaldata->scip, evaldata->nlhdlrexprdata->nlexpr, evaldata->evalsol, 0L) );
232  	
233  	   return SCIPexprGetEvalValue(evaldata->nlhdlrexprdata->nlexpr);
234  	}
235  	
236  	/** initialize expression stack */
237  	static
238  	SCIP_RETCODE exprstackInit(
239  	   SCIP*                 scip,               /**< SCIP data structure */
240  	   EXPRSTACK*            exprstack,          /**< stack to initialize */
241  	   int                   initsize            /**< initial size */
242  	   )
243  	{
244  	   assert(scip != NULL);
245  	   assert(exprstack != NULL);
246  	   assert(initsize > 0);
247  	
248  	   SCIP_CALL( SCIPallocBufferArray(scip, &exprstack->stack, initsize) );
249  	   exprstack->stacksize = initsize;
250  	   exprstack->stackpos = -1;
251  	
252  	   return SCIP_OKAY;
253  	}
254  	
255  	/** free expression stack */
256  	static
257  	void exprstackFree(
258  	   SCIP*                 scip,               /**< SCIP data structure */
259  	   EXPRSTACK*            exprstack           /**< free expression stack */
260  	   )
261  	{
262  	   assert(scip != NULL);
263  	   assert(exprstack != NULL);
264  	
265  	   SCIPfreeBufferArray(scip, &exprstack->stack);
266  	}
267  	
268  	/** add expressions to expression stack */
269  	static
270  	SCIP_RETCODE exprstackPush(
271  	   SCIP*                 scip,               /**< SCIP data structure */
272  	   EXPRSTACK*            exprstack,          /**< expression stack */
273  	   int                   nexprs,             /**< number of expressions to push */
274  	   SCIP_EXPR**           exprs               /**< expressions to push */
275  	   )
276  	{
277  	   assert(scip != NULL);
278  	   assert(exprstack != NULL);
279  	
280  	   if( nexprs == 0 )
281  	      return SCIP_OKAY;
282  	
283  	   assert(exprs != NULL);
284  	
285  	   if( exprstack->stackpos+1 + nexprs > exprstack->stacksize )  /*lint !e644*/
286  	   {
287  	      exprstack->stacksize = SCIPcalcMemGrowSize(scip, exprstack->stackpos+1 + nexprs);    /*lint !e644*/
288  	      SCIP_CALL( SCIPreallocBufferArray(scip, &exprstack->stack, exprstack->stacksize) );
289  	   }
290  	
291  	   memcpy(exprstack->stack + (exprstack->stackpos+1), exprs, nexprs * sizeof(SCIP_EXPR*));  /*lint !e679*/ /*lint !e737*/
292  	   exprstack->stackpos += nexprs;
293  	
294  	   return SCIP_OKAY;
295  	}
296  	
297  	/** gives expression from top of expression stack and removes it from stack */
298  	static
299  	SCIP_EXPR* exprstackPop(
300  	   EXPRSTACK*            exprstack           /**< expression stack */
301  	   )
302  	{
303  	   assert(exprstack != NULL);
304  	   assert(exprstack->stackpos >= 0);
305  	
306  	   return exprstack->stack[exprstack->stackpos--];
307  	}
308  	
309  	/** indicate whether expression stack is empty */
310  	static
311  	SCIP_Bool exprstackIsEmpty(
312  	   EXPRSTACK*            exprstack           /**< expression stack */
313  	   )
314  	{
315  	   assert(exprstack != NULL);
316  	
317  	   return exprstack->stackpos < 0;
318  	}
319  	
320  	/** looks whether given expression is (proper) quadratic and has a given curvature
321  	 *
322  	 * If having a given curvature, currently require all arguments of quadratic to be linear.
323  	 * Hence, not using this for a simple square term, as curvCheckExprhdlr may provide a better condition on argument curvature then.
324  	 * Also we wouldn't do anything useful for a single bilinear term.
325  	 * Thus, run on sum's only.
326  	 */
327  	static
328  	DECL_CURVCHECK(curvCheckQuadratic)
329  	{  /*lint --e{715}*/
330  	   SCIP_EXPR* expr;
331  	   SCIP_EXPRCURV presentcurv;
332  	   SCIP_EXPRCURV wantedcurv;
333  	   SCIP_HASHSET* lonelysquares = NULL;
334  	   SCIP_Bool isquadratic;
335  	   int nbilinexprs;
336  	   int nquadexprs;
337  	   int i;
338  	
339  	   assert(nlexpr != NULL);
340  	   assert(stack != NULL);
341  	   assert(nlexpr2origexpr != NULL);
342  	   assert(success != NULL);
343  	
344  	   *success = FALSE;
345  	
346  	   if( !nlhdlrdata->cvxquadratic )
347  	      return SCIP_OKAY;
348  	
349  	   if( !SCIPisExprSum(scip, nlexpr) )
350  	      return SCIP_OKAY;
351  	
352  	   wantedcurv = SCIPexprGetCurvature(nlexpr);
353  	   if( wantedcurv == SCIP_EXPRCURV_LINEAR )
354  	      return SCIP_OKAY;
355  	   assert(wantedcurv == SCIP_EXPRCURV_CONVEX || wantedcurv == SCIP_EXPRCURV_CONCAVE);
356  	
357  	   expr = (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlexpr);
358  	   assert(expr != NULL);
359  	
360  	   /* check whether quadratic */
361  	   SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, &isquadratic) );
362  	
363  	   /* if not quadratic, then give up here */
364  	   if( !isquadratic )
365  	      return SCIP_OKAY;
366  	
367  	   SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, &nbilinexprs, NULL, NULL);
368  	
369  	   /* if only single square term (+linear), then give up here (let curvCheckExprhdlr handle this) */
370  	   if( nquadexprs <= 1 )
371  	      return SCIP_OKAY;
372  	
373  	   /* if root expression is only sum of squares (+linear) and detectsum is disabled, then give up here, too */
374  	   if( isrootexpr && !nlhdlrdata->detectsum && nbilinexprs == 0 )
375  	      return SCIP_OKAY;
376  	
377  	   /* get curvature of quadratic
378  	    * TODO as we know what curvature we want, we could first do some simple checks like computing xQx for a random x
379  	    */
380  	   SCIP_CALL( SCIPcomputeExprQuadraticCurvature(scip, expr, &presentcurv, assumevarfixed, FALSE) );
381  	
382  	   /* if not having desired curvature, return */
383  	   if( presentcurv != wantedcurv )
384  	      return SCIP_OKAY;
385  	
386  	   *success = TRUE;
387  	
388  	   if( !nlhdlrdata->detectsum )
389  	   {
390  	      /* first step towards block-decomposition of quadratic term:
391  	       * collect all square-expressions (in original expr) which have no adjacent bilinear term
392  	       * we will treat these x^2 as linear, i.e., add an auxvar for them, so x^2 maybe linearized
393  	       * more efficiently (in particular if x is discrete)
394  	       */
395  	      SCIP_CALL( SCIPhashsetCreate(&lonelysquares, SCIPblkmem(scip), nquadexprs) );
396  	      for( i = 0; i < nquadexprs; ++i )
397  	      {
398  	         int nadjbilin;
399  	         SCIP_EXPR* sqrexpr;
400  	
401  	         SCIPexprGetQuadraticQuadTerm(expr, i, NULL, NULL, NULL, &nadjbilin, NULL, &sqrexpr);
402  	         if( nadjbilin == 0 )
403  	         {
404  	            assert(sqrexpr != NULL);
405  	            SCIP_CALL( SCIPhashsetInsert(lonelysquares, SCIPblkmem(scip), (void*)sqrexpr) );
406  	         }
407  	      }
408  	   }
409  	
410  	   /* add immediate children to nlexpr */
411  	   SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, nlexpr, NULL) );
412  	   assert(SCIPexprGetNChildren(nlexpr) == SCIPexprGetNChildren(expr));
413  	
414  	   /* put children that are not square or product on stack
415  	    * grow child for children that are square or product and put this child on stack
416  	    * require all children to be linear
417  	    */
418  	   for( i = 0; i < SCIPexprGetNChildren(nlexpr); ++i )
419  	   {
420  	      SCIP_EXPR* child;
421  	      SCIP_EXPRCURV curvlinear[2] = { SCIP_EXPRCURV_LINEAR, SCIP_EXPRCURV_LINEAR };
422  	
423  	      child = SCIPexprGetChildren(nlexpr)[i];
424  	      assert(child != NULL);
425  	
426  	      assert(SCIPhashmapGetImage(nlexpr2origexpr, (void*)child) == SCIPexprGetChildren(expr)[i]);
427  	
428  	      if( SCIPisExprPower(scip, child) && SCIPgetExponentExprPow(child) == 2.0 &&
429  	         (lonelysquares == NULL || !SCIPhashsetExists(lonelysquares, SCIPexprGetChildren(expr)[i])) )
430  	      {
431  	         /* square term that isn't lonely, i.e., orig-version of child is a square-expr and nadjbilin>0 */
432  	         SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, child, curvlinear) );
433  	         assert(SCIPexprGetNChildren(child) == 1);
434  	         SCIP_CALL( exprstackPush(scip, stack, 1, SCIPexprGetChildren(child)) );
435  	      }
436  	      else if( SCIPisExprProduct(scip, child) && SCIPexprGetNChildren(SCIPexprGetChildren(expr)[i]) == 2 )
437  	         /* using original version of child here as NChildren(child)==0 atm */
438  	      {
439  	         /* bilinear term */
440  	         SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, child, curvlinear) );
441  	         assert(SCIPexprGetNChildren(child) == 2);
442  	         SCIP_CALL( exprstackPush(scip, stack, 2, SCIPexprGetChildren(child)) );
443  	      }
444  	      else
445  	      {
446  	         /* linear term (or term to be considered as linear) */
447  	         SCIPexprSetCurvature(child, SCIP_EXPRCURV_LINEAR);
448  	         SCIP_CALL( exprstackPush(scip, stack, 1, &child) );
449  	      }
450  	   }
451  	
452  	   if( lonelysquares != NULL )
453  	      SCIPhashsetFree(&lonelysquares, SCIPblkmem(scip));
454  	
455  	   return SCIP_OKAY;
456  	}
457  	
458  	/** looks whether top of given expression looks like a signomial that can have a given curvature
459  	 *
460  	 * e.g., sqrt(x)*sqrt(y) is convex if x,y >= 0 and x and y are convex
461  	 *
462  	 * unfortunately, doesn't work for tls, because i) it's originally sqrt(x*y), and ii) it is expanded into some sqrt(z*y+y);
463  	 * but works for cvxnonsep_nsig
464  	 */
465  	static
466  	DECL_CURVCHECK(curvCheckSignomial)
467  	{  /*lint --e{715}*/
468  	   SCIP_EXPR* expr;
469  	   SCIP_EXPR* child;
470  	   SCIP_Real* exponents;
471  	   SCIP_INTERVAL* bounds;
472  	   SCIP_EXPRCURV* curv;
473  	   int nfactors;
474  	   int i;
475  	
476  	   assert(nlexpr != NULL);
477  	   assert(stack != NULL);
478  	   assert(nlexpr2origexpr != NULL);
479  	   assert(success != NULL);
480  	
481  	   *success = FALSE;
482  	
483  	   if( !nlhdlrdata->cvxsignomial )
484  	      return SCIP_OKAY;
485  	
486  	   if( !SCIPisExprProduct(scip, nlexpr) )
487  	      return SCIP_OKAY;
488  	
489  	   expr = (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlexpr);
490  	   assert(expr != NULL);
491  	
492  	   nfactors = SCIPexprGetNChildren(expr);
493  	   if( nfactors <= 1 )  /* boooring */
494  	      return SCIP_OKAY;
495  	
496  	   SCIP_CALL( SCIPallocBufferArray(scip, &exponents, nfactors) );
497  	   SCIP_CALL( SCIPallocBufferArray(scip, &bounds, nfactors) );
498  	   SCIP_CALL( SCIPallocBufferArray(scip, &curv, nfactors) );
499  	
500  	   for( i = 0; i < nfactors; ++i )
501  	   {
502  	      child = SCIPexprGetChildren(expr)[i];
503  	      assert(child != NULL);
504  	
505  	      if( !SCIPisExprPower(scip, child) )
506  	      {
507  	         exponents[i] = 1.0;
508  	         SCIP_CALL( SCIPevalExprActivity(scip, child) );
509  	         bounds[i] = SCIPexprGetActivity(child);
510  	      }
511  	      else
512  	      {
513  	         exponents[i] = SCIPgetExponentExprPow(child);
514  	         SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(child)[0]) );
515  	         bounds[i] = SCIPexprGetActivity(SCIPexprGetChildren(child)[0]);
516  	      }
517  	   }
518  	
519  	   if( !SCIPexprcurvMonomialInv(SCIPexprcurvMultiply(SCIPgetCoefExprProduct(expr), SCIPexprGetCurvature(nlexpr)),
520  	       nfactors, exponents, bounds, curv) )
521  	      goto TERMINATE;
522  	
523  	   /* add immediate children to nlexpr
524  	    * some entries in curv actually apply to arguments of pow's, will correct this next
525  	    */
526  	   SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, nlexpr, curv) );
527  	   assert(SCIPexprGetNChildren(nlexpr) == nfactors);
528  	
529  	   /* put children that are not power on stack
530  	    * grow child for children that are power and put this child on stack
531  	    * if extendedform, then require children to be linear
532  	    * unless they are linear, an auxvar will be introduced for them and thus they will be handled as var here
533  	    */
534  	   for( i = 0; i < nfactors; ++i )
535  	   {
536  	      child = SCIPexprGetChildren(nlexpr)[i];
537  	      assert(child != NULL);
538  	
539  	      if( SCIPisExprPower(scip, child) )
540  	      {
541  	         SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, child, &curv[i]) );
542  	         assert(SCIPexprGetNChildren(child) == 1);
543  	         child = SCIPexprGetChildren(child)[0];
544  	      }
545  	      assert(SCIPexprGetNChildren(child) == 0);
546  	
547  	      if( nlhdlrdata->extendedform )
548  	      {
549  	         SCIPexprSetCurvature(child, SCIP_EXPRCURV_LINEAR);
550  	#ifdef SCIP_DEBUG
551  	         SCIPinfoMessage(scip, NULL, "Extendedform: Require linearity for ");
552  	         SCIPprintExpr(scip, child, NULL);
553  	         SCIPinfoMessage(scip, NULL, "\n");
554  	#endif
555  	      }
556  	
557  	      SCIP_CALL( exprstackPush(scip, stack, 1, &child) );
558  	   }
559  	
560  	   *success = TRUE;
561  	
562  	TERMINATE:
563  	   SCIPfreeBufferArray(scip, &curv);
564  	   SCIPfreeBufferArray(scip, &bounds);
565  	   SCIPfreeBufferArray(scip, &exponents);
566  	
567  	   return SCIP_OKAY;
568  	}
569  	
570  	/** looks for \f$f(c h(x)+d) h(x) \cdot \text{constant}\f$ and tries to conclude conditions on curvature
571  	 *
572  	 * Assume \f$h\f$ is univariate:
573  	 * - First derivative is \f$f'(c h + d) c h' h + f(c h + d) h'\f$.
574  	 * - Second derivative is \f{align}{&f''(c h + d) c h' c h' h + f'(c h + d) (c h'' h + c h' h') + f'(c h + d) c h' h' + f(c h + d) h'' \\
575  	 *   =& f''(c h + d) c^2 h'^2 h + f'(c h + d) c h'' h + 2 f'(c h + d) c h'^2 + f(c h + d) h''.\f}
576  	 *   Remove always positive factors leaves \f[f''(c h + d) h,\quad f'(c h + d) c h'' h,\quad f'(c h + d) c,\quad f(c h + d) h''.\f]
577  	 *   For convexity we want all these terms to be nonnegative. For concavity we want all of them to be nonpositive.
578  	 *   Note, that in each term either both \f$f'(c h + d)\f$ and \f$c\f$ occur, or none of them.
579  	 * - Thus, \f$f(c h(x) + d)h(x)\f$ is convex if \f$cf\f$ is monotonically increasing \f$(c f' \geq 0)\f$ and either
580  	 *   - \f$f\f$ is convex \f$(f'' \geq 0)\f$ and \f$h\f$ is nonnegative \f$(h \geq 0)\f$ and \f$h\f$ is convex \f$(h'' \geq 0)\f$ and [\f$f\f$ is nonnegative \f$(f \geq 0)\f$ or \f$h\f$ is linear \f$(h''=0)\f$], or
581  	 *   - \f$f\f$ is concave \f$(f'' \leq 0)\f$ and \f$h\f$ is nonpositive \f$(h \leq 0)\f$ and \f$h\f$ is concave \f$(h'' \leq 0)\f$ and [\f$f\f$ is nonpositive \f$(f \leq 0)\f$ or \f$h\f$ is linear \f$(h''=0)\f$].
582  	 * - Further, \f$f(c h(x) + d)h(x)\f$ is concave if \f$cf\f$ is monotonically decreasing \f$(c f' \leq 0)\f$ and either
583  	 *   - f is convex \f$(f'' \geq 0)\f$ and \f$h\f$ is nonpositive \f$(h \leq 0)\f$ and \f$h\f$ is concave \f$(h'' \leq 0)\f$ and [\f$f\f$ is nonnegative \f$(f \geq 0)\f$ or \f$h\f$ is linear \f$(h''=0)\f$], or
584  	 *   - f is concave \f$(f'' \leq 0)\f$ and \f$h\f$ is nonnegative \f$(h >= 0)\f$ and \f$h\f$ is convex \f$(h'' \geq 0)\f$ and [\f$f\f$ is nonpositive \f$(f \leq 0)\f$ or \f$h\f$ is linear \f$(h''=0)\f$].
585  	 *
586  	 * This should hold also for multivariate and linear \f$h\f$, as things are invariant under linear transformations.
587  	 * Similar to signomial, I'll assume that this will also hold for other multivariate \f$h\f$ (someone has a formal proof?).
588  	 */
589  	static
590  	DECL_CURVCHECK(curvCheckProductComposite)
591  	{  /*lint --e{715}*/
592  	   SCIP_EXPR* expr;
593  	   SCIP_EXPR* f;
594  	   SCIP_EXPR* h = NULL;
595  	   SCIP_Real c = 0.0;
596  	   SCIP_EXPR* ch = NULL; /* c * h */
597  	   SCIP_INTERVAL fbounds;
598  	   SCIP_INTERVAL hbounds;
599  	   SCIP_MONOTONE fmonotonicity;
600  	   SCIP_EXPRCURV desiredcurv;
601  	   SCIP_EXPRCURV hcurv;
602  	   SCIP_EXPRCURV dummy;
603  	   int fidx;
604  	
605  	   assert(nlexpr != NULL);
606  	   assert(stack != NULL);
607  	   assert(nlexpr2origexpr != NULL);
608  	   assert(success != NULL);
609  	
610  	   *success = FALSE;
611  	
612  	   if( !nlhdlrdata->cvxprodcomp )
613  	      return SCIP_OKAY;
614  	
615  	   if( !SCIPisExprProduct(scip, nlexpr) )
616  	      return SCIP_OKAY;
617  	
618  	   expr = (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlexpr);
619  	   assert(expr != NULL);
620  	
621  	   if( SCIPexprGetNChildren(expr) != 2 )
622  	      return SCIP_OKAY;
623  	
624  	   /* check whether we have f(c * h(x)) * h(x) or h(x) * f(c * h(x)) */
625  	   for( fidx = 0; fidx <= 1; ++fidx )
626  	   {
627  	      f = SCIPexprGetChildren(expr)[fidx];
628  	
629  	      if( SCIPexprGetNChildren(f) != 1 )
630  	         continue;
631  	
632  	      ch = SCIPexprGetChildren(f)[0];
633  	      c = 1.0;
634  	      h = ch;
635  	
636  	      /* check whether ch is of the form c*h(x), then switch h to child ch */
637  	      if( SCIPisExprSum(scip, ch) && SCIPexprGetNChildren(ch) == 1 )
638  	      {
639  	         c = SCIPgetCoefsExprSum(ch)[0];
640  	         h = SCIPexprGetChildren(ch)[0];
641  	         assert(c != 1.0 || SCIPgetConstantExprSum(ch) != 0.0);  /* we could handle this, but it should have been simplified away */
642  	      }
643  	
644  	#ifndef NLHDLR_CONVEX_UNITTEST
645  	      /* can assume that duplicate subexpressions have been identified and comparing pointer is sufficient */
646  	      if( SCIPexprGetChildren(expr)[1-fidx] == h )
647  	#else
648  	      /* called from unittest -> duplicate subexpressions were not identified -> compare more expensively */
649  	      if( SCIPcompareExpr(scip, SCIPexprGetChildren(expr)[1-fidx], h) == 0 )
650  	#endif
651  	         break;
652  	   }
653  	   if( fidx == 2 )
654  	      return SCIP_OKAY;
655  	
656  	#ifdef SCIP_MORE_DEBUG
657  	   SCIPinfoMessage(scip, NULL, "f(c*h+d)*h with f = %s, c = %g, d = %g, h = ", SCIPexprhdlrGetName(SCIPexprGetHdlr(f)),
658  	         c, h != ch ? SCIPgetConstantExprSum(ch) : 0.0);
659  	   SCIPprintExpr(scip, h, NULL);
660  	   SCIPinfoMessage(scip, NULL, "\n");
661  	#endif
662  	
663  	   assert(c != 0.0);
664  	
665  	   SCIP_CALL( SCIPevalExprActivity(scip, f) );
666  	   SCIP_CALL( SCIPevalExprActivity(scip, h) );
667  	   fbounds = SCIPexprGetActivity(f);
668  	   hbounds = SCIPexprGetActivity(h);
669  	
670  	   /* if h has mixed sign, then cannot conclude anything */
671  	   if( hbounds.inf < 0.0 && hbounds.sup > 0.0 )
672  	      return SCIP_OKAY;
673  	
674  	   SCIP_CALL( SCIPcallExprMonotonicity(scip, f, 0, &fmonotonicity) );
675  	
676  	   /* if f is not monotone, then cannot conclude anything */
677  	   if( fmonotonicity == SCIP_MONOTONE_UNKNOWN )
678  	      return SCIP_OKAY;
679  	
680  	   /* curvature we want to achieve (negate if product has negative coef) */
681  	   desiredcurv = SCIPexprcurvMultiply(SCIPgetCoefExprProduct(nlexpr), SCIPexprGetCurvature(nlexpr));
682  	
683  	   /* now check the conditions as stated above */
684  	   if( desiredcurv == SCIP_EXPRCURV_CONVEX )
685  	   {
686  	      /* f(c h(x)+d)h(x) is convex if c*f is monotonically increasing (c f' >= 0) and either
687  	      *   - f is convex (f'' >= 0) and h is nonnegative (h >= 0) and h is convex (h'' >= 0) and [f is nonnegative (f >= 0) or h is linear (h''=0)], or
688  	      *   - f is concave (f'' <= 0) and h is nonpositive (h <= 0) and h is concave (h'' <= 0) and [f is nonpositive (f <= 0) or h is linear (h''=0)]
689  	      *  as the curvature requirements on f are on f only and not the composition f(h), we can ignore the requirements returned by SCIPcallExprCurvature (last arg)
690  	      */
691  	      if( (c > 0.0 && fmonotonicity != SCIP_MONOTONE_INC) || (c < 0.0 && fmonotonicity != SCIP_MONOTONE_DEC) )
692  	         return SCIP_OKAY;
693  	
694  	      /* check whether f can be convex (h>=0) or concave (h<=0), resp., and derive requirements for h */
695  	      if( hbounds.inf >= 0 )
696  	      {
697  	         SCIP_CALL( SCIPcallExprCurvature(scip, f, SCIP_EXPRCURV_CONVEX, success, &dummy) );
698  	
699  	         /* now h also needs to be convex; and if f < 0, then h actually needs to be linear */
700  	         if( fbounds.inf < 0.0 )
701  	            hcurv = SCIP_EXPRCURV_LINEAR;
702  	         else
703  	            hcurv = SCIP_EXPRCURV_CONVEX;
704  	      }
705  	      else
706  	      {
707  	         SCIP_CALL( SCIPcallExprCurvature(scip, f, SCIP_EXPRCURV_CONCAVE, success, &dummy) );
708  	
709  	         /* now h also needs to be concave; and if f > 0, then h actually needs to be linear */
710  	         if( fbounds.sup > 0.0 )
711  	            hcurv = SCIP_EXPRCURV_LINEAR;
712  	         else
713  	            hcurv = SCIP_EXPRCURV_CONCAVE;
714  	      }
715  	   }
716  	   else
717  	   {
718  	      /* f(c h(x)+d)*h(x) is concave if c*f is monotonically decreasing (c f' <= 0) and either
719  	      *   - f is convex (f'' >= 0) and h is nonpositive (h <= 0) and h is concave (h'' <= 0) and [f is nonnegative (f >= 0) or h is linear (h''=0)], or
720  	      *   - f is concave (f'' <= 0) and h is nonnegative (h >= 0) and h is convex (h'' >= 0) and [f is nonpositive (f <= 0) or h is linear (h''=0)]
721  	      *  as the curvature requirements on f are on f only and not the composition f(h), we can ignore the requirements returned by SCIPcallExprCurvature (last arg)
722  	      */
723  	      if( (c > 0.0 && fmonotonicity != SCIP_MONOTONE_DEC) || (c < 0.0 && fmonotonicity != SCIP_MONOTONE_INC) )
724  	         return SCIP_OKAY;
725  	
726  	      /* check whether f can be convex (h<=0) or concave (h>=0), resp., and derive requirements for h */
727  	      if( hbounds.sup <= 0 )
728  	      {
729  	         SCIP_CALL( SCIPcallExprCurvature(scip, f, SCIP_EXPRCURV_CONVEX, success, &dummy) );
730  	
731  	         /* now h also needs to be concave; and if f < 0, then h actually needs to be linear */
732  	         if( fbounds.inf < 0.0 )
733  	            hcurv = SCIP_EXPRCURV_LINEAR;
734  	         else
735  	            hcurv = SCIP_EXPRCURV_CONCAVE;
736  	      }
737  	      else
738  	      {
739  	         SCIP_CALL( SCIPcallExprCurvature(scip, f, SCIP_EXPRCURV_CONCAVE, success, &dummy) );
740  	
741  	         /* now h also needs to be convex; and if f > 0, then h actually needs to be linear */
742  	         if( fbounds.sup > 0.0 )
743  	            hcurv = SCIP_EXPRCURV_LINEAR;
744  	         else
745  	            hcurv = SCIP_EXPRCURV_CONVEX;
746  	      }
747  	   }
748  	
749  	   if( !*success )
750  	      return SCIP_OKAY;
751  	
752  	   /* add immediate children (f and ch) to nlexpr; we set required curvature for h further below */
753  	   SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, nlexpr, NULL) );
754  	   assert(SCIPexprGetNChildren(nlexpr) == 2);
755  	
756  	   /* copy of f (and h) should have same child position in nlexpr as f (and h) has on expr (resp) */
757  	   assert(SCIPhashmapGetImage(nlexpr2origexpr, (void*)SCIPexprGetChildren(nlexpr)[fidx]) == (void*)f);
758  	#ifndef NLHDLR_CONVEX_UNITTEST
759  	   assert(SCIPhashmapGetImage(nlexpr2origexpr, (void*)SCIPexprGetChildren(nlexpr)[1-fidx]) == (void*)h);
760  	#endif
761  	   /* push this h onto stack for further checking */
762  	   SCIP_CALL( exprstackPush(scip, stack, 1, &(SCIPexprGetChildren(nlexpr)[1-fidx])) );
763  	
764  	   /* if we prefer extended formulations, then we always want h() to be linear */
765  	   if( nlhdlrdata->extendedform )
766  	      hcurv = SCIP_EXPRCURV_LINEAR;
767  	
768  	   /* h-child of product should have curvature hcurv */
769  	   SCIPexprSetCurvature(SCIPexprGetChildren(nlexpr)[1-fidx], hcurv);
770  	
771  	   if( h != ch )
772  	   {
773  	      /* add copy of ch as child to copy of f */
774  	      SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, SCIPexprGetChildren(nlexpr)[fidx], NULL) );
775  	      assert(SCIPexprGetNChildren(SCIPexprGetChildren(nlexpr)[fidx]) == 1);
776  	      assert(SCIPhashmapGetImage(nlexpr2origexpr, (void*)SCIPexprGetChildren(SCIPexprGetChildren(nlexpr)[fidx])[0]) == (void*)ch);
777  	
778  	      /* add copy of h (created above as child of product) as child in copy of ch */
779  	      SCIP_CALL( SCIPappendExprChild(scip,
780  	         SCIPexprGetChildren(SCIPexprGetChildren(nlexpr)[fidx])[0] /* copy of ch */,
781  	         SCIPexprGetChildren(nlexpr)[1-fidx] /* copy of h */) );
782  	   }
783  	   else
784  	   {
785  	      /* add copy of h (created above as child of product) as child in copy of f */
786  	      SCIP_CALL( SCIPappendExprChild(scip,
787  	         SCIPexprGetChildren(nlexpr)[fidx] /* copy of f */,
788  	         SCIPexprGetChildren(nlexpr)[1-fidx] /* copy of h */) );
789  	   }
790  	
791  	   return SCIP_OKAY;
792  	}
793  	
794  	/** use expression handlers curvature callback to check whether given curvature can be achieved */
795  	static
796  	DECL_CURVCHECK(curvCheckExprhdlr)
797  	{  /*lint --e{715}*/
798  	   SCIP_EXPR* origexpr;
799  	   int nchildren;
800  	   SCIP_EXPRCURV* childcurv;
801  	
802  	   assert(nlexpr != NULL);
803  	   assert(stack != NULL);
804  	   assert(nlexpr2origexpr != NULL);
805  	   assert(success != NULL);
806  	
807  	   origexpr = (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, nlexpr);
808  	   assert(origexpr != NULL);
809  	   nchildren = SCIPexprGetNChildren(origexpr);
810  	
811  	   if( nchildren == 0 )
812  	   {
813  	      /* if originally no children, then should be var or value, which should have every curvature,
814  	       * so should always be success
815  	       */
816  	      SCIP_CALL( SCIPcallExprCurvature(scip, origexpr, SCIPexprGetCurvature(nlexpr), success, NULL) );
817  	      assert(*success);
818  	
819  	      return SCIP_OKAY;
820  	   }
821  	
822  	   /* ignore sums if > 1 children
823  	    * NOTE: this means that for something like 1+f(x), even if f is a trivial convex expression, we would handle 1+f(x)
824  	    * with this nlhdlr, instead of formulating this as 1+z and handling z=f(x) with the default nlhdlr, i.e., the exprhdlr
825  	    * today, I prefer handling this here, as it avoids introducing an extra auxiliary variable
826  	    */
827  	   if( isrootexpr && !nlhdlrdata->detectsum && SCIPisExprSum(scip, nlexpr) && nchildren > 1 )
828  	      return SCIP_OKAY;
829  	
830  	   SCIP_CALL( SCIPallocBufferArray(scip, &childcurv, nchildren) );
831  	
832  	   /* check whether and under which conditions origexpr can have desired curvature */
833  	   SCIP_CALL( SCIPcallExprCurvature(scip, origexpr, SCIPexprGetCurvature(nlexpr), success, childcurv) );
834  	#ifdef SCIP_MORE_DEBUG
835  	   SCIPprintExpr(scip, origexpr, NULL);
836  	   SCIPinfoMessage(scip, NULL, " is %s? %d\n", SCIPexprcurvGetName(SCIPexprGetCurvature(nlexpr)), *success);
837  	#endif
838  	   if( !*success )
839  	      goto TERMINATE;
840  	
841  	   /* if origexpr can have curvature curv, then don't treat it as leaf, but include its children */
842  	   SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, nlexpr, childcurv) );
843  	   assert(SCIPexprGetChildren(nlexpr) != NULL);
844  	   assert(SCIPexprGetNChildren(nlexpr) == nchildren);
845  	
846  	   /* If we prefer extended formulations, then require all children to be linear.
847  	    * Unless they are, auxvars will be introduced and they will be handles as variables, which can be an
848  	    * advantage in the context of extended formulations.
849  	    */
850  	   if( nlhdlrdata->extendedform )
851  	   {
852  	      int i;
853  	      for( i = 0; i < nchildren; ++i )
854  	         SCIPexprSetCurvature(SCIPexprGetChildren(nlexpr)[i], SCIP_EXPRCURV_LINEAR);
855  	#ifdef SCIP_DEBUG
856  	      SCIPinfoMessage(scip, NULL, "require linearity for children of ");
857  	      SCIPprintExpr(scip, origexpr, NULL);
858  	      SCIPinfoMessage(scip, NULL, "\n");
859  	#endif
860  	   }
861  	
862  	   /* add children expressions to to-do list (stack) */
863  	   SCIP_CALL( exprstackPush(scip, stack, nchildren, SCIPexprGetChildren(nlexpr)) );
864  	
865  	TERMINATE:
866  	   SCIPfreeBufferArray(scip, &childcurv);
867  	
868  	   return SCIP_OKAY;
869  	}
870  	
871  	/** curvature check and expression-growing methods
872  	 *
873  	 * some day this could be plugins added by users at runtime, but for now we have a fixed list here
874  	 * @note curvCheckExprhdlr should be last
875  	 */
876  	static DECL_CURVCHECK((*CURVCHECKS[])) = { curvCheckProductComposite, curvCheckSignomial, curvCheckQuadratic, curvCheckExprhdlr };
877  	/** number of curvcheck methods */
878  	static const int NCURVCHECKS = sizeof(CURVCHECKS) / sizeof(void*);
879  	
880  	/** checks whether expression is a sum with more than one child and each child being a variable or going to be a variable if `expr` is a nlhdlr-specific copy
881  	 *
882  	 * Within constructExpr(), we can have an expression of any type which is a copy of an original expression,
883  	 * but without children. At the end of constructExpr() (after the loop with the stack), these expressions
884  	 * will remain as leafs and will eventually be turned into variables in collectLeafs(). Thus, we treat
885  	 * every child that has no children as if it were a variable. Theoretically, there is still the possibility
886  	 * that it could be a constant (value-expression), but simplify should have removed these.
887  	 */
888  	static
889  	SCIP_Bool exprIsMultivarLinear(
890  	   SCIP*                 scip,               /**< SCIP data structure */
891  	   SCIP_EXPR*            expr                /**< expression to check */
892  	   )
893  	{
894  	   int nchildren;
895  	   int c;
896  	
897  	   assert(expr != NULL);
898  	
899  	   if( !SCIPisExprSum(scip, expr) )
900  	      return FALSE;
901  	
902  	   nchildren = SCIPexprGetNChildren(expr);
903  	   if( nchildren <= 1 )
904  	      return FALSE;
905  	
906  	   for( c = 0; c < nchildren; ++c )
907  	      /*if( !SCIPisExprVar(scip, SCIPexprGetChildren(expr)[c]) ) */
908  	      if( SCIPexprGetNChildren(SCIPexprGetChildren(expr)[c]) > 0 )
909  	         return FALSE;
910  	
911  	   return TRUE;
912  	}
913  	
914  	/** constructs a subexpression (as nlhdlr-expression) of maximal size that has a given curvature
915  	 *
916  	 * If the curvature cannot be achieved for an expression in the original expression graph,
917  	 * then this expression becomes a leaf in the nlhdlr-expression.
918  	 *
919  	 * Sets `*rootnlexpr` to NULL if failed.
920  	 */
921  	static
922  	SCIP_RETCODE constructExpr(
923  	   SCIP*                 scip,               /**< SCIP data structure */
924  	   SCIP_NLHDLRDATA*      nlhdlrdata,         /**< nonlinear handler data */
925  	   SCIP_EXPR**           rootnlexpr,         /**< buffer to store created expression */
926  	   SCIP_HASHMAP*         nlexpr2origexpr,    /**< mapping from our expression copy to original expression */
927  	   int*                  nleafs,             /**< number of leafs in constructed expression */
928  	   SCIP_EXPR*            rootexpr,           /**< expression */
929  	   SCIP_EXPRCURV         curv,               /**< curvature to achieve */
930  	   SCIP_HASHMAP*         assumevarfixed,     /**< hashmap containing variables that should be assumed to be fixed, or NULL */
931  	   SCIP_Bool*            curvsuccess         /**< pointer to store whether the curvature could be achieved
932  	                                                  w.r.t. the original variables (might be NULL) */
933  	   )
934  	{
935  	   SCIP_EXPR* nlexpr;
936  	   EXPRSTACK stack; /* to do list: expressions where to check whether they can have the desired curvature when taking their children into account */
937  	   int oldstackpos;
938  	   SCIP_Bool isrootexpr = TRUE;
939  	
940  	   assert(scip != NULL);
941  	   assert(nlhdlrdata != NULL);
942  	   assert(rootnlexpr != NULL);
943  	   assert(nlexpr2origexpr != NULL);
944  	   assert(nleafs != NULL);
945  	   assert(rootexpr != NULL);
946  	   assert(curv == SCIP_EXPRCURV_CONVEX || curv == SCIP_EXPRCURV_CONCAVE);
947  	
948  	   /* create root expression */
949  	   SCIP_CALL( nlhdlrExprCreate(scip, nlexpr2origexpr, rootnlexpr, rootexpr, curv) );
950  	
951  	   *nleafs = 0;
952  	   if( curvsuccess != NULL )
953  	      *curvsuccess = TRUE;
954  	
955  	   SCIP_CALL( exprstackInit(scip, &stack, 20) );
956  	   SCIP_CALL( exprstackPush(scip, &stack, 1, rootnlexpr) );
957  	   while( !exprstackIsEmpty(&stack) )
958  	   {
959  	      /* take expression from stack */
960  	      nlexpr = exprstackPop(&stack);
961  	      assert(nlexpr != NULL);
962  	      assert(SCIPexprGetNChildren(nlexpr) == 0);
963  	
964  	      oldstackpos = stack.stackpos;
965  	      if( nlhdlrdata->isnlhdlrconvex && !SCIPexprhdlrHasBwdiff(SCIPexprGetHdlr(nlexpr)) )
966  	      {
967  	         /* if bwdiff is not implemented, then we could not generate cuts in the convex nlhdlr, so "stop" (treat nlexpr as variable) */
968  	      }
969  	      else if( !nlhdlrdata->isnlhdlrconvex && exprIsMultivarLinear(scip, (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlexpr)) )
970  	      {
971  	         /* if we are in the concave handler, we would like to treat linear multivariate subexpressions by a new auxvar always,
972  	          * e.g., handle log(x+y) as log(z), z=x+y, because the estimation problem will be smaller then without making the estimator worse
973  	          * (cons_nonlinear does this, too)
974  	          * this check takes care of this when x and y are original variables
975  	          * however, it isn't unlikely that we will have sums that become linear after we add auxvars for some children
976  	          * this will be handled in a postprocessing below
977  	          * for now, the check is performed on the original expression since there is not enough information in nlexpr yet
978  	          */
979  	#ifdef SCIP_MORE_DEBUG
980  	         SCIPprintExpr(scip, SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlexpr), NULL);
981  	         SCIPinfoMessage(scip, NULL, "... is a multivariate linear sum that we'll treat as auxvar\n");
982  	#endif
983  	      }
984  	      else if( SCIPexprGetCurvature(nlexpr) != SCIP_EXPRCURV_UNKNOWN )
985  	      {
986  	         /* if we are here, either convexity or concavity is required; try to check for this curvature */
987  	         SCIP_Bool success;
988  	         int method;
989  	
990  	         /* try through curvature check methods until one succeeds */
991  	         for( method = 0; method < NCURVCHECKS; ++method )
992  	         {
993  	            SCIP_CALL( CURVCHECKS[method](scip, nlexpr, isrootexpr, &stack, nlexpr2origexpr, nlhdlrdata, assumevarfixed, &success) );
994  	            if( success )
995  	               break;
996  	         }
997  	      }
998  	      else
999  	      {
1000 	         /* if we don't care about curvature in this subtree anymore (very unlikely),
1001 	          * then only continue iterating this subtree to assemble leaf expressions
1002 	          */
1003 	         SCIP_CALL( nlhdlrExprGrowChildren(scip, nlexpr2origexpr, nlexpr, NULL) );
1004 	
1005 	         /* add children expressions, if any, to to-do list (stack) */
1006 	         SCIP_CALL( exprstackPush(scip, &stack, SCIPexprGetNChildren(nlexpr), SCIPexprGetChildren(nlexpr)) );
1007 	      }
1008 	      assert(stack.stackpos >= oldstackpos);  /* none of the methods above should have removed something from the stack */
1009 	
1010 	      isrootexpr = FALSE;
1011 	
1012 	      /* if nothing was added, then none of the successors of nlexpr were added to the stack
1013 	       * this is either because nlexpr was already a variable or value expressions, thus a leaf,
1014 	       * or because the desired curvature could not be achieved, so it will be handled as variables, thus a leaf
1015 	       */
1016 	      if( stack.stackpos == oldstackpos )
1017 	      {
1018 	         ++*nleafs;
1019 	
1020 	         /* check whether the new leaf is not an original variable (or constant) */
1021 	         if( curvsuccess != NULL && !SCIPisExprVar(scip, nlexpr) && !SCIPisExprValue(scip, nlexpr) )
1022 	            *curvsuccess = FALSE;
1023 	      }
1024 	   }
1025 	
1026 	   exprstackFree(scip, &stack);
1027 	
1028 	   if( !nlhdlrdata->isnlhdlrconvex && *rootnlexpr != NULL )
1029 	   {
1030 	      /* remove multivariate linear subexpressions, that is, change some f(z1+z2) into f(z3) (z3=z1+z2 will be done by nlhdlr_default)
1031 	       * this handles the case that was not covered by the above check, which could recognize f(x+y) for x, y original variables
1032 	       */
1033 	      SCIP_EXPRITER* it;
1034 	
1035 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
1036 	      SCIP_CALL( SCIPexpriterInit(it, *rootnlexpr, SCIP_EXPRITER_DFS, FALSE) );
1037 	      SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
1038 	
1039 	      while( !SCIPexpriterIsEnd(it) )
1040 	      {
1041 	         SCIP_EXPR* child;
1042 	
1043 	         child = SCIPexpriterGetChildExprDFS(it);
1044 	         assert(child != NULL);
1045 	
1046 	         /* We want to change some f(x+y+z) into just f(), where f is the expression the iterator points to
1047 	          * and x+y+z is child. A child of a child, e.g., z, may not be a variable yet (these are added in collectLeafs later),
1048 	          * but an expression of some nonlinear type without children.
1049 	          */
1050 	         if( exprIsMultivarLinear(scip, child) )
1051 	         {
1052 	            /* turn child (x+y+z) into a sum without children
1053 	             * collectLeafs() should then replace this by an auxvar
1054 	             */
1055 	#ifdef SCIP_MORE_DEBUG
1056 	            SCIPprintExpr(scip, child, NULL);
1057 	            SCIPinfoMessage(scip, NULL, "... is a multivariate linear sum that we'll treat as auxvar instead (postprocess)\n");
1058 	#endif
1059 	
1060 	            /* TODO remove children from nlexpr2origexpr ?
1061 	             * should also do this if they are not used somewhere else; we could check nuses for this
1062 	             * however, it shouldn't matter to have some stray entries in the hashmap either
1063 	             */
1064 	            SCIP_CALL( SCIPremoveExprChildren(scip, child) );
1065 	            assert(SCIPexprGetNChildren(child) == 0);
1066 	
1067 	            (void) SCIPexpriterSkipDFS(it);
1068 	         }
1069 	         else
1070 	         {
1071 	            (void) SCIPexpriterGetNext(it);
1072 	         }
1073 	      }
1074 	
1075 	      SCIPfreeExpriter(&it);
1076 	   }
1077 	
1078 	   if( *rootnlexpr != NULL )
1079 	   {
1080 	      SCIP_Bool istrivial = TRUE;
1081 	
1082 	      /* if handletrivial is enabled, then only require that rootnlexpr itself has required curvature (so has children; see below) and
1083 	       * that we are not a trivial sum  (because the previous implementation of this nlhdlr didn't allow this, either)
1084 	       */
1085 	      if( !nlhdlrdata->handletrivial || SCIPisExprSum(scip, *rootnlexpr) )
1086 	      {
1087 	         /* if all children do not have children, i.e., are variables, or will be replaced by auxvars, then free
1088 	          * also if rootnlexpr has no children, then free
1089 	          */
1090 	         int i;
1091 	         for( i = 0; i < SCIPexprGetNChildren(*rootnlexpr); ++i )
1092 	         {
1093 	            if( SCIPexprGetNChildren(SCIPexprGetChildren(*rootnlexpr)[i]) > 0 )
1094 	            {
1095 	               istrivial = FALSE;
1096 	               break;
1097 	            }
1098 	         }
1099 	      }
1100 	      else if( SCIPexprGetNChildren(*rootnlexpr) > 0 )  /* if handletrivial, then just require children */
1101 	            istrivial = FALSE;
1102 	
1103 	      if( istrivial )
1104 	      {
1105 	         SCIP_CALL( SCIPreleaseExpr(scip, rootnlexpr) );
1106 	      }
1107 	   }
1108 	
1109 	   return SCIP_OKAY;
1110 	}
1111 	
1112 	/** collects (non-value) leaf expressions and ensure that they correspond to a variable (original or auxiliary)
1113 	 *
1114 	 * For children where we could not achieve the desired curvature, get the auxvar and replace the child by a
1115 	 * var-expression that points to this auxvar.
1116 	 * Collect all leaf expressions (if not a value-expression) and index them.
1117 	 */
1118 	static
1119 	SCIP_RETCODE collectLeafs(
1120 	   SCIP*                 scip,               /**< SCIP data structure */
1121 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata      /**< nlhdlr expression data */
1122 	   )
1123 	{
1124 	   SCIP_EXPRITER* it;
1125 	   SCIP_EXPR* nlexpr;
1126 	   SCIP_HASHMAP* leaf2index;
1127 	   int i;
1128 	
1129 	   assert(nlhdlrexprdata != NULL);
1130 	   assert(nlhdlrexprdata->nlexpr != NULL);
1131 	   assert(nlhdlrexprdata->nlexpr2origexpr != NULL);
1132 	   /* nleafs should be the upper bound on the number of variables given by constructExpr
1133 	    * leafexprs should be NULL, as this is what we want to setup here
1134 	    */
1135 	   assert(nlhdlrexprdata->nleafs > 0);
1136 	   assert(nlhdlrexprdata->leafexprs == NULL);
1137 	
1138 	   /* collect all auxvars and collect all variables */
1139 	   SCIP_CALL( SCIPhashmapCreate(&leaf2index, SCIPblkmem(scip), nlhdlrexprdata->nleafs) );
1140 	   nlhdlrexprdata->nleafs = 0;  /* we start a new count, this time skipping value-expressions */
1141 	
1142 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
1143 	   SCIP_CALL( SCIPexpriterInit(it, nlhdlrexprdata->nlexpr, SCIP_EXPRITER_DFS, FALSE) );
1144 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
1145 	
1146 	   for( nlexpr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); nlexpr = SCIPexpriterGetNext(it) )
1147 	   {
1148 	      SCIP_EXPR* child;
1149 	      SCIP_EXPR* origexpr;
1150 	
1151 	      assert(nlexpr != NULL);
1152 	
1153 	      child = SCIPexpriterGetChildExprDFS(it);
1154 	
1155 	      /* if the to-be-visited child has children, then it doesn't need to be replaced by a new expression (representing the auxvar) */
1156 	      if( SCIPexprGetNChildren(child) > 0 )
1157 	         continue;
1158 	
1159 	      origexpr = (SCIP_EXPR*)SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, (void*)child);
1160 	      assert(origexpr != NULL);
1161 	
1162 	      if( SCIPexprGetNChildren(origexpr) > 0 )
1163 	      {
1164 	         SCIP_EXPR* newchild;
1165 	         int childidx;
1166 	         SCIP_VAR* var;
1167 	
1168 	         /* having a child that had children in original but not in copy means that we could not achieve the desired curvature
1169 	          * thus, replace by a new child that points to the auxvar of the original expression
1170 	          * we registered in createNlhdlrExprData that we need an auxvar, so it should exist now
1171 	          */
1172 	         var = SCIPgetExprAuxVarNonlinear(origexpr);
1173 	         assert(var != NULL);
1174 	
1175 	         SCIP_CALL( SCIPcreateExprVar(scip, &newchild, var, NULL, NULL) );  /* this captures newchild once */
1176 	
1177 	         childidx = SCIPexpriterGetChildIdxDFS(it);
1178 	         SCIP_CALL( SCIPreplaceExprChild(scip, nlexpr, childidx, newchild) );  /* this captures newchild again */
1179 	
1180 	         /* do not remove child->origexpr from hashmap, as child may appear again due to common subexprs
1181 	          * (created by curvCheckProductComposite, for example)
1182 	          * if it doesn't reappear, though, but the memory address is reused, we need to make sure it
1183 	          * points to the right origexpr
1184 	          */
1185 	         /* SCIP_CALL( SCIPhashmapRemove(nlexpr2origexpr, (void*)child) ); */
1186 	         SCIP_CALL( SCIPhashmapSetImage(nlhdlrexprdata->nlexpr2origexpr, (void*)newchild, (void*)origexpr) );
1187 	
1188 	         if( !SCIPhashmapExists(leaf2index, (void*)newchild) )
1189 	         {
1190 	            /* new leaf -> new index and remember in hashmap */
1191 	            SCIP_CALL( SCIPhashmapInsertInt(leaf2index, (void*)newchild, nlhdlrexprdata->nleafs++) );
1192 	         }
1193 	
1194 	         child = newchild;
1195 	         SCIP_CALL( SCIPreleaseExpr(scip, &newchild) );  /* because it was captured by both create and replace */
1196 	      }
1197 	      else if( SCIPisExprVar(scip, child) )
1198 	      {
1199 	         /* if variable, then add to hashmap, if not already there */
1200 	         if( !SCIPhashmapExists(leaf2index, (void*)child) )
1201 	         {
1202 	            SCIP_CALL( SCIPhashmapInsertInt(leaf2index, (void*)child, nlhdlrexprdata->nleafs++) );
1203 	         }
1204 	      }
1205 	      /* else: it's probably a value-expression, nothing to do */
1206 	
1207 	      /* update integrality flag for future leaf expressions: convex nlhdlr may use this information */
1208 	      SCIP_CALL( SCIPcomputeExprIntegrality(scip, child) );
1209 	   }
1210 	   assert(nlhdlrexprdata->nleafs > 0);
1211 	
1212 	   SCIPfreeExpriter(&it);
1213 	
1214 	   /* assemble auxvars array */
1215 	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(nlhdlrexprdata->leafexprs), nlhdlrexprdata->nleafs) );
1216 	   for( i = 0; i < SCIPhashmapGetNEntries(leaf2index); ++i )
1217 	   {
1218 	      SCIP_HASHMAPENTRY* entry;
1219 	      SCIP_EXPR* leaf;
1220 	      int idx;
1221 	
1222 	      entry = SCIPhashmapGetEntry(leaf2index, i);
1223 	      if( entry == NULL )
1224 	         continue;
1225 	
1226 	      leaf = (SCIP_EXPR*) SCIPhashmapEntryGetOrigin(entry);
1227 	      assert(leaf != NULL);
1228 	      assert(SCIPisExprVar(scip, leaf));
1229 	
1230 	      idx = SCIPhashmapEntryGetImageInt(entry);
1231 	      assert(idx >= 0);
1232 	      assert(idx < nlhdlrexprdata->nleafs);
1233 	
1234 	      nlhdlrexprdata->leafexprs[idx] = leaf;
1235 	
1236 	      SCIPdebugMsg(scip, "leaf %d: <%s>\n", idx, SCIPvarGetName(SCIPgetVarExprVar(leaf)));
1237 	   }
1238 	
1239 	   SCIPhashmapFree(&leaf2index);
1240 	
1241 	   return SCIP_OKAY;
1242 	}
1243 	
1244 	/** creates nonlinear handler expression data structure and registers expr usage */
1245 	static
1246 	SCIP_RETCODE createNlhdlrExprData(
1247 	   SCIP*                 scip,               /**< SCIP data structure */
1248 	   SCIP_NLHDLRDATA*      nlhdlrdata,         /**< nlhdlr data */
1249 	   SCIP_NLHDLREXPRDATA** nlhdlrexprdata,     /**< pointer to store nlhdlr expression data */
1250 	   SCIP_EXPR*            expr,               /**< original expression */
1251 	   SCIP_EXPR*            nlexpr,             /**< our copy of expression */
1252 	   SCIP_HASHMAP*         nlexpr2origexpr,    /**< mapping of expression copy to original */
1253 	   int                   nleafs,             /**< number of leafs as counted by constructExpr */
1254 	   SCIP_NLHDLR_METHOD    participating       /**< the enfo methods in which we plan to participate */
1255 	   )
1256 	{
1257 	   SCIP_EXPRITER* it;
1258 	   SCIP_Bool usingaux;
1259 	
1260 	   assert(scip != NULL);
1261 	   assert(expr != NULL);
1262 	   assert(nlhdlrexprdata != NULL);
1263 	   assert(*nlhdlrexprdata == NULL);
1264 	   assert(nlexpr != NULL);
1265 	   assert(nlexpr2origexpr != NULL);
1266 	
1267 	   assert(SCIPexprGetNChildren(nlexpr) > 0);
1268 	   assert(SCIPexprGetChildren(nlexpr) != NULL);
1269 	
1270 	   SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
1271 	   (*nlhdlrexprdata)->nlexpr = nlexpr;
1272 	   (*nlhdlrexprdata)->nlexpr2origexpr = nlexpr2origexpr;
1273 	   (*nlhdlrexprdata)->nleafs = nleafs;
1274 	
1275 	   usingaux = FALSE;
1276 	
1277 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
1278 	   SCIP_CALL( SCIPexpriterInit(it, nlexpr, SCIP_EXPRITER_DFS, FALSE) );
1279 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
1280 	
1281 	   for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
1282 	   {
1283 	      SCIP_EXPR* child;
1284 	      SCIP_EXPR* origexpr;
1285 	
1286 	      /* check whether to-be-visited child needs to be replaced by a new expression (representing the auxvar)
1287 	       * if child has children, then that is not the case
1288 	       * if child has no children, but also corresponding origexpr has no chilren, then this is also not the case
1289 	       */
1290 	      child = SCIPexpriterGetChildExprDFS(it);
1291 	      if( SCIPexprGetNChildren(child) > 0 )
1292 	         continue;
1293 	
1294 	      origexpr = (SCIP_EXPR*)SCIPhashmapGetImage(nlexpr2origexpr, (void*)child);
1295 	      assert(origexpr != NULL);
1296 	
1297 	      /* if child had children in original but not in copy means that we could not achieve the desired curvature
1298 	       * thus, we will later replace by a new child that points to the auxvar of the original expression
1299 	       * as we do not have the auxvar now, we will only register that we will need the auxvar later (if origexpr isn't a variable or constant)
1300 	       * if we are working for the concave nlhdlr, then we also indicate interest on the exprs activity for estimate (distinguish below or above)
1301 	       */
1302 	      SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, origexpr,
1303 	         SCIPexprGetNChildren(origexpr) > 0, FALSE,
1304 	         !nlhdlrdata->isnlhdlrconvex && (participating & SCIP_NLHDLR_METHOD_SEPABELOW),
1305 	         !nlhdlrdata->isnlhdlrconvex && (participating & SCIP_NLHDLR_METHOD_SEPAABOVE)) );
1306 	
1307 	      /* remember that we use an auxvar */
1308 	      if( SCIPexprGetNChildren(origexpr) > 0 )
1309 	         usingaux = TRUE;
1310 	   }
1311 	
1312 	   SCIPfreeExpriter(&it);
1313 	
1314 	#ifdef SCIP_DEBUG
1315 	   SCIPprintExpr(scip, nlexpr, NULL);
1316 	   SCIPinfoMessage(scip, NULL, " (%p) is handled as %s\n", SCIPhashmapGetImage(nlexpr2origexpr, (void*)nlexpr),
1317 	         SCIPexprcurvGetName(SCIPexprGetCurvature(nlexpr)));
1318 	#endif
1319 	
1320 	   /* If we don't work on the extended formulation, then set curvature also in original expression
1321 	    * (in case someone wants to pick this up; this might be removed again).
1322 	    * This doesn't ensure that every convex or concave original expression is actually marked here.
1323 	    * Not only because our tests are incomprehensive, but also because we may not detect on sums,
1324 	    * prefer extended formulations (in nlhdlr_convex), or introduce auxvars for linear subexpressions
1325 	    * on purpose (in nlhdlr_concave).
1326 	    */
1327 	   if( !usingaux )
1328 	      SCIPexprSetCurvature(expr, SCIPexprGetCurvature(nlexpr));
1329 	
1330 	   return SCIP_OKAY;
1331 	}
1332 	
1333 	/** adds an estimator for a vertex-polyhedral (e.g., concave) function to a given rowprep
1334 	 *
1335 	 * Calls \ref SCIPcomputeFacetVertexPolyhedralNonlinear() for given function and
1336 	 * box set to local bounds of auxiliary variables.
1337 	 */
1338 	static
1339 	SCIP_RETCODE estimateVertexPolyhedral(
1340 	   SCIP*                 scip,               /**< SCIP data structure */
1341 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
1342 	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
1343 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata,     /**< nonlinear handler expression data */
1344 	   SCIP_SOL*             sol,                /**< solution to use, unless usemidpoint is TRUE */
1345 	   SCIP_Bool             usemidpoint,        /**< whether to use the midpoint of the domain instead of sol */
1346 	   SCIP_Bool             overestimate,       /**< whether over- or underestimating */
1347 	   SCIP_Real             targetvalue,        /**< a target value to achieve; if not reachable, then can give up early */
1348 	   SCIP_ROWPREP*         rowprep,            /**< rowprep where to store estimator */
1349 	   SCIP_Bool*            success             /**< buffer to store whether successful */
1350 	   )
1351 	{
1352 	   SCIP_NLHDLRDATA* nlhdlrdata;
1353 	   VERTEXPOLYFUN_EVALDATA evaldata;
1354 	   SCIP_Real* xstar;
1355 	   SCIP_Real* box;
1356 	   SCIP_Real facetconstant;
1357 	   SCIP_VAR* var;
1358 	   int i;
1359 	   SCIP_Bool allfixed;
1360 	
1361 	   assert(scip != NULL);
1362 	   assert(nlhdlr != NULL);
1363 	   assert(nlhdlrexprdata != NULL);
1364 	   assert(rowprep != NULL);
1365 	   assert(success != NULL);
1366 	
1367 	   *success = FALSE;
1368 	
1369 	   /* caller is responsible to have checked whether we can estimate, i.e., expression curvature and overestimate flag match */
1370 	   assert( overestimate || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONCAVE);  /* if underestimate, then must be concave */
1371 	   assert(!overestimate || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONVEX);   /* if overestimate, then must be convex */
1372 	
1373 	#ifdef SCIP_DEBUG
1374 	   SCIPinfoMessage(scip, NULL, "%sestimate expression ", overestimate ? "over" : "under");
1375 	   SCIPprintExpr(scip, nlhdlrexprdata->nlexpr, NULL);
1376 	   SCIPinfoMessage(scip, NULL, " at point\n");
1377 	   for( i = 0; i < nlhdlrexprdata->nleafs; ++i )
1378 	   {
1379 	      var = SCIPgetVarExprVar(nlhdlrexprdata->leafexprs[i]);
1380 	      assert(var != NULL);
1381 	
1382 	      SCIPinfoMessage(scip, NULL, "  <%s> = %g [%g,%g]\n", SCIPvarGetName(var),
1383 	         usemidpoint ? 0.5 * (SCIPvarGetLbLocal(var) + SCIPvarGetUbLocal(var)) : SCIPgetSolVal(scip, sol, var),
1384 	        SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
1385 	   }
1386 	#endif
1387 	
1388 	   nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1389 	   assert(nlhdlrdata != NULL);
1390 	
1391 	   if( nlhdlrdata->evalsol == NULL )
1392 	   {
1393 	      SCIP_CALL( SCIPcreateSol(scip, &nlhdlrdata->evalsol, NULL) );
1394 	   }
1395 	
1396 	   evaldata.nlhdlrexprdata = nlhdlrexprdata;
1397 	   evaldata.evalsol = nlhdlrdata->evalsol;
1398 	   evaldata.scip = scip;
1399 	
1400 	   SCIP_CALL( SCIPallocBufferArray(scip, &xstar, nlhdlrexprdata->nleafs) );
1401 	   SCIP_CALL( SCIPallocBufferArray(scip, &box, 2*nlhdlrexprdata->nleafs) );
1402 	
1403 	   allfixed = TRUE;
1404 	   for( i = 0; i < nlhdlrexprdata->nleafs; ++i )
1405 	   {
1406 	      var = SCIPgetVarExprVar(nlhdlrexprdata->leafexprs[i]);
1407 	      assert(var != NULL);
1408 	
1409 	      box[2*i] = SCIPvarGetLbLocal(var);
1410 	      if( SCIPisInfinity(scip, -box[2*i]) )
1411 	      {
1412 	         SCIPdebugMsg(scip, "lower bound at -infinity, no estimate possible\n");
1413 	         goto TERMINATE;
1414 	      }
1415 	
1416 	      box[2*i+1] = SCIPvarGetUbLocal(var);
1417 	      if( SCIPisInfinity(scip, box[2*i+1]) )
1418 	      {
1419 	         SCIPdebugMsg(scip, "upper bound at +infinity, no estimate possible\n");
1420 	         goto TERMINATE;
1421 	      }
1422 	
1423 	      if( !SCIPisRelEQ(scip, box[2*i], box[2*i+1]) )
1424 	         allfixed = FALSE;
1425 	
1426 	      if( usemidpoint )
1427 	         xstar[i] = 0.5 * (box[2*i] + box[2*i+1]);
1428 	      else
1429 	         xstar[i] = SCIPgetSolVal(scip, sol, var);
1430 	      assert(xstar[i] != SCIP_INVALID);
1431 	   }
1432 	
1433 	   if( allfixed )
1434 	   {
1435 	      /* SCIPcomputeFacetVertexPolyhedralNonlinear prints a warning and does not succeed if all is fixed */
1436 	      SCIPdebugMsg(scip, "all variables fixed, skip estimate\n");
1437 	      goto TERMINATE;
1438 	   }
1439 	
1440 	   SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nlhdlrexprdata->nleafs + 1) );
1441 	
1442 	   SCIP_CALL( SCIPcomputeFacetVertexPolyhedralNonlinear(scip, conshdlr, overestimate, nlhdlrExprEvalConcave, (void*)&evaldata,
1443 	      xstar, box, nlhdlrexprdata->nleafs, targetvalue, success, SCIProwprepGetCoefs(rowprep), &facetconstant) );
1444 	
1445 	   if( !*success )
1446 	   {
1447 	      SCIPdebugMsg(scip, "failed to compute facet of convex hull\n");
1448 	      goto TERMINATE;
1449 	   }
1450 	
1451 	   SCIProwprepSetLocal(rowprep, TRUE);
1452 	   SCIProwprepAddConstant(rowprep, facetconstant);
1453 	   for( i = 0; i < nlhdlrexprdata->nleafs; ++i )
1454 	   {
1455 	      SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetVarExprVar(nlhdlrexprdata->leafexprs[i]), SCIProwprepGetCoefs(rowprep)[i]) );
1456 	   }
1457 	
1458 	#ifdef SCIP_DEBUG
1459 	   SCIPinfoMessage(scip, NULL, "computed estimator: ");
1460 	   SCIPprintRowprep(scip, rowprep, NULL);
1461 	#endif
1462 	
1463 	 TERMINATE:
1464 	   SCIPfreeBufferArray(scip, &box);
1465 	   SCIPfreeBufferArray(scip, &xstar);
1466 	
1467 	   return SCIP_OKAY;
1468 	}
1469 	
1470 	/** adds an estimator computed via a gradient to a given rowprep */
1471 	static
1472 	SCIP_RETCODE estimateGradient(
1473 	   SCIP*                 scip,               /**< SCIP data structure */
1474 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata,     /**< nonlinear handler expression data */
1475 	   SCIP_SOL*             sol,                /**< solution to use */
1476 	   SCIP_Real             auxvalue,           /**< value of nlexpr in sol - we may not be able to take this value
1477 	                                                  from nlexpr if it was evaluated at a different sol recently */
1478 	   SCIP_ROWPREP*         rowprep,            /**< rowprep where to store estimator */
1479 	   SCIP_Bool*            success             /**< buffer to store whether successful */
1480 	   )
1481 	{
1482 	   SCIP_EXPR* nlexpr;
1483 	   SCIP_Real QUAD(constant);
1484 	   int i;
1485 	
1486 	   assert(nlhdlrexprdata != NULL);
1487 	   assert(rowprep != NULL);
1488 	   assert(success != NULL);
1489 	
1490 	   nlexpr = nlhdlrexprdata->nlexpr;
1491 	   assert(nlexpr != NULL);
1492 	
1493 	#ifdef SCIP_DEBUG
1494 	   SCIPinfoMessage(scip, NULL, "estimate expression ");
1495 	   SCIPprintExpr(scip, nlexpr, NULL);
1496 	   SCIPinfoMessage(scip, NULL, " by gradient\n");
1497 	#endif
1498 	
1499 	   *success = FALSE;
1500 	
1501 	   /* evaluation error -> skip */
1502 	   if( auxvalue == SCIP_INVALID )
1503 	   {
1504 	      SCIPdebugMsg(scip, "evaluation error / too large value (%g) for %p\n", auxvalue, (void*)nlexpr);
1505 	      return SCIP_OKAY;
1506 	   }
1507 	
1508 	   /* compute gradient (TODO: this also re-evaluates (soltag=0), which shouldn't be necessary unless we tried ConvexSecant before) */
1509 	   SCIP_CALL( SCIPevalExprGradient(scip, nlexpr, sol, 0L) );
1510 	
1511 	   /* gradient evaluation error -> skip */
1512 	   if( SCIPexprGetDerivative(nlexpr) == SCIP_INVALID )
1513 	   {
1514 	      SCIPdebugMsg(scip, "gradient evaluation error for %p\n", (void*)nlexpr);
1515 	      return SCIP_OKAY;
1516 	   }
1517 	
1518 	   /* add gradient underestimator to rowprep: f(sol) + (x - sol) \nabla f(sol)
1519 	    * constant will store f(sol) - sol * \nabla f(sol)
1520 	    * to avoid some cancellation errors when linear variables take huge values (like 1e20),
1521 	    * we use double-double arithemtic here
1522 	    */
1523 	   QUAD_ASSIGN(constant, SCIPexprGetEvalValue(nlexpr)); /* f(sol) */
1524 	   for( i = 0; i < nlhdlrexprdata->nleafs; ++i )
1525 	   {
1526 	      SCIP_VAR* var;
1527 	      SCIP_Real deriv;
1528 	      SCIP_Real varval;
1529 	
1530 	      assert(SCIPexprGetDiffTag(nlhdlrexprdata->leafexprs[i]) == SCIPexprGetDiffTag(nlexpr));
1531 	      deriv = SCIPexprGetDerivative(nlhdlrexprdata->leafexprs[i]);
1532 	      if( deriv == SCIP_INVALID )
1533 	      {
1534 	         SCIPdebugMsg(scip, "gradient evaluation error for component %d of %p\n", i, (void*)nlexpr);
1535 	         return SCIP_OKAY;
1536 	      }
1537 	
1538 	      var = SCIPgetVarExprVar(nlhdlrexprdata->leafexprs[i]);
1539 	      assert(var != NULL);
1540 	
1541 	      varval = SCIPgetSolVal(scip, sol, var);
1542 	
1543 	      SCIPdebugMsg(scip, "add %g * (<%s> - %g) to rowprep\n", deriv, SCIPvarGetName(var), varval);
1544 	
1545 	      /* add deriv * var to rowprep and deriv * (-varval) to constant */
1546 	      SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, deriv) );
1547 	      SCIPquadprecSumQD(constant, constant, -deriv * varval);
1548 	   }
1549 	
1550 	   SCIProwprepAddConstant(rowprep, QUAD_TO_DBL(constant));
1551 	   SCIProwprepSetLocal(rowprep, FALSE);
1552 	
1553 	   *success = TRUE;
1554 	
1555 	   return SCIP_OKAY;
1556 	}
1557 	
1558 	/** adds an estimator generated by putting a secant through the coordinates given by the two closest integer points */
1559 	static
1560 	SCIP_RETCODE estimateConvexSecant(
1561 	   SCIP*                 scip,               /**< SCIP data structure */
1562 	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
1563 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata,     /**< nonlinear handler expression data */
1564 	   SCIP_SOL*             sol,                /**< solution to use, unless usemidpoint is TRUE */
1565 	   SCIP_ROWPREP*         rowprep,            /**< rowprep where to store estimator */
1566 	   SCIP_Bool*            success             /**< buffer to store whether successful */
1567 	   )
1568 	{
1569 	   SCIP_NLHDLRDATA* nlhdlrdata;
1570 	   SCIP_EXPR* nlexpr;
1571 	   SCIP_VAR* var;
1572 	   SCIP_Real x;
1573 	   SCIP_Real left, right;
1574 	   SCIP_Real fleft, fright;
1575 	
1576 	   assert(nlhdlrexprdata != NULL);
1577 	   assert(nlhdlrexprdata->nleafs == 1);
1578 	   assert(rowprep != NULL);
1579 	   assert(success != NULL);
1580 	
1581 	   nlexpr = nlhdlrexprdata->nlexpr;
1582 	   assert(nlexpr != NULL);
1583 	
1584 	   *success = FALSE;
1585 	
1586 	   nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1587 	   assert(nlhdlrdata != NULL);
1588 	
1589 	   var = SCIPgetVarExprVar(nlhdlrexprdata->leafexprs[0]);
1590 	   assert(var != NULL);
1591 	
1592 	   x = SCIPgetSolVal(scip, sol, var);
1593 	
1594 	#ifdef SCIP_DEBUG
1595 	   SCIPinfoMessage(scip, NULL, "estimate expression ");
1596 	   SCIPprintExpr(scip, nlexpr, NULL);
1597 	   SCIPinfoMessage(scip, NULL, " by secant\n");
1598 	   SCIPinfoMessage(scip, NULL, "integral variable <%s> = %g [%g,%g]\n", SCIPvarGetName(var),
1599 	         x, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1600 	#endif
1601 	
1602 	   /* find out coordinates of var left and right to sol */
1603 	   if( SCIPisIntegral(scip, x) )
1604 	   {
1605 	      x = SCIPround(scip, x);
1606 	      if( SCIPisEQ(scip, x, SCIPvarGetLbGlobal(var)) )
1607 	      {
1608 	         left = x;
1609 	         right = left + 1.0;
1610 	      }
1611 	      else
1612 	      {
1613 	         right = x;
1614 	         left = right - 1.0;
1615 	      }
1616 	   }
1617 	   else
1618 	   {
1619 	      left = SCIPfloor(scip, x);
1620 	      right = SCIPceil(scip, x);
1621 	   }
1622 	   assert(left != right);
1623 	
1624 	   /* now evaluate at left and right */
1625 	   if( nlhdlrdata->evalsol == NULL )
1626 	   {
1627 	      SCIP_CALL( SCIPcreateSol(scip, &nlhdlrdata->evalsol, NULL) );
1628 	   }
1629 	
1630 	   SCIP_CALL( SCIPsetSolVal(scip, nlhdlrdata->evalsol, var, left) );
1631 	   SCIP_CALL( SCIPevalExpr(scip, nlexpr, nlhdlrdata->evalsol, 0L) );
1632 	
1633 	   /* evaluation error or a too large constant -> skip */
1634 	   fleft = SCIPexprGetEvalValue(nlexpr);
1635 	   if( SCIPisInfinity(scip, REALABS(fleft)) )
1636 	   {
1637 	      SCIPdebugMsg(scip, "evaluation error / too large value (%g) for %p\n", SCIPexprGetEvalValue(nlexpr), (void*)nlexpr);
1638 	      return SCIP_OKAY;
1639 	   }
1640 	
1641 	   SCIP_CALL( SCIPsetSolVal(scip, nlhdlrdata->evalsol, var, right) );
1642 	   SCIP_CALL( SCIPevalExpr(scip, nlexpr, nlhdlrdata->evalsol, 0L) );
1643 	
1644 	   /* evaluation error or a too large constant -> skip */
1645 	   fright = SCIPexprGetEvalValue(nlexpr);
1646 	   if( SCIPisInfinity(scip, REALABS(fright)) )
1647 	   {
1648 	      SCIPdebugMsg(scip, "evaluation error / too large value (%g) for %p\n", SCIPexprGetEvalValue(nlexpr), (void*)nlexpr);
1649 	      return SCIP_OKAY;
1650 	   }
1651 	
1652 	   SCIPdebugMsg(scip, "f(%g)=%g, f(%g)=%g\n", left, fleft, right, fright);
1653 	
1654 	   /* skip if too steep
1655 	    * for clay0204h, this resulted in a wrong cut from f(0)=1e12 f(1)=0.99998,
1656 	    * since due to limited precision, this was handled as if f(1)=1
1657 	    */
1658 	   if( (!SCIPisZero(scip, fleft)  && REALABS(fright/fleft)*SCIPepsilon(scip) > 1.0) ||
1659 	       (!SCIPisZero(scip, fright) && REALABS(fleft/fright)*SCIPepsilon(scip) > 1.0) )
1660 	   {
1661 	      SCIPdebugMsg(scip, "function is too steep, abandoning\n");
1662 	      return SCIP_OKAY;
1663 	   }
1664 	
1665 	   /* now add f(left) + (f(right) - f(left)) * (x - left) as estimator to rowprep */
1666 	   SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, fright - fleft) );
1667 	   SCIProwprepAddConstant(rowprep, fleft - (fright - fleft) * left);
1668 	   SCIProwprepSetLocal(rowprep, FALSE);
1669 	
1670 	   *success = TRUE;
1671 	
1672 	   return SCIP_OKAY;
1673 	}
1674 	
1675 	/*
1676 	 * Callback methods of convex nonlinear handler
1677 	 */
1678 	
1679 	/** free handler data of convex or concave nlhdlr */
1680 	static
1681 	SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrfreeHdlrDataConvexConcave)
1682 	{  /*lint --e{715}*/
1683 	   assert(scip != NULL);
1684 	   assert(nlhdlrdata != NULL);
1685 	   assert(*nlhdlrdata != NULL);
1686 	   assert((*nlhdlrdata)->evalsol == NULL);
1687 	
1688 	   SCIPfreeBlockMemory(scip, nlhdlrdata);
1689 	
1690 	   return SCIP_OKAY;
1691 	}
1692 	
1693 	/** callback to free expression specific data */
1694 	static
1695 	SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrfreeExprDataConvexConcave)
1696 	{  /*lint --e{715}*/
1697 	   assert(scip != NULL);
1698 	   assert(nlhdlrexprdata != NULL);
1699 	   assert(*nlhdlrexprdata != NULL);
1700 	
1701 	   SCIPfreeBlockMemoryArrayNull(scip, &(*nlhdlrexprdata)->leafexprs, (*nlhdlrexprdata)->nleafs);
1702 	   SCIP_CALL( SCIPreleaseExpr(scip, &(*nlhdlrexprdata)->nlexpr) );
1703 	   SCIPhashmapFree(&(*nlhdlrexprdata)->nlexpr2origexpr);
1704 	
1705 	   SCIPfreeBlockMemory(scip, nlhdlrexprdata);
1706 	
1707 	   return SCIP_OKAY;
1708 	}
1709 	
1710 	/** deinitialization of problem-specific data */
1711 	static
1712 	SCIP_DECL_NLHDLREXIT(nlhdlrExitConvex)
1713 	{
1714 	   SCIP_NLHDLRDATA* nlhdlrdata;
1715 	
1716 	   nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1717 	   assert(nlhdlrdata != NULL);
1718 	
1719 	   if( nlhdlrdata->evalsol != NULL )
1720 	   {
1721 	      SCIP_CALL( SCIPfreeSol(scip, &nlhdlrdata->evalsol) );
1722 	   }
1723 	
1724 	   return SCIP_OKAY;
1725 	}
1726 	
1727 	/** checks whether expression (or -expression) is convex, possibly after introducing auxiliary variables */
1728 	static
1729 	SCIP_DECL_NLHDLRDETECT(nlhdlrDetectConvex)
1730 	{ /*lint --e{715}*/
1731 	   SCIP_NLHDLRDATA* nlhdlrdata;
1732 	   SCIP_EXPR* nlexpr = NULL;
1733 	   SCIP_HASHMAP* nlexpr2origexpr;
1734 	   int nleafs = 0;
1735 	
1736 	   assert(scip != NULL);
1737 	   assert(nlhdlr != NULL);
1738 	   assert(expr != NULL);
1739 	   assert(enforcing != NULL);
1740 	   assert(participating != NULL);
1741 	   assert(nlhdlrexprdata != NULL);
1742 	
1743 	   /* we currently do not participate if only activity computation is required */
1744 	   if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABOTH) == SCIP_NLHDLR_METHOD_SEPABOTH )
1745 	      return SCIP_OKAY;
1746 	
1747 	   /* ignore pure constants and variables */
1748 	   if( SCIPexprGetNChildren(expr) == 0 )
1749 	      return SCIP_OKAY;
1750 	
1751 	   nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1752 	   assert(nlhdlrdata != NULL);
1753 	   assert(nlhdlrdata->isnlhdlrconvex);
1754 	
1755 	   SCIPdebugMsg(scip, "nlhdlr_convex detect for expr %p\n", (void*)expr);
1756 	
1757 	   /* initialize mapping from copied expression to original one
1758 	    * 20 is not a bad estimate for the size of convex subexpressions that we can usually discover
1759 	    * when expressions will be allowed to store "user"data, we could get rid of this hashmap (TODO)
1760 	    */
1761 	   SCIP_CALL( SCIPhashmapCreate(&nlexpr2origexpr, SCIPblkmem(scip), 20) );
1762 	
1763 	   if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 )  /* if no separation below yet */
1764 	   {
1765 	      SCIP_CALL( constructExpr(scip, nlhdlrdata, &nlexpr, nlexpr2origexpr, &nleafs, expr,
1766 	         SCIP_EXPRCURV_CONVEX, NULL, NULL) );
1767 	      if( nlexpr != NULL )
1768 	      {
1769 	         assert(SCIPexprGetNChildren(nlexpr) > 0);  /* should not be trivial */
1770 	
1771 	         *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
1772 	
1773 	         SCIPdebugMsg(scip, "detected expr %p to be convex -> can enforce expr <= auxvar\n", (void*)expr);
1774 	      }
1775 	      else
1776 	      {
1777 	         SCIP_CALL( SCIPhashmapRemoveAll(nlexpr2origexpr) );
1778 	      }
1779 	   }
1780 	
1781 	   if( (*enforcing & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 && nlexpr == NULL )  /* if no separation above and not convex */
1782 	   {
1783 	      SCIP_CALL( constructExpr(scip, nlhdlrdata, &nlexpr, nlexpr2origexpr, &nleafs, expr,
1784 	         SCIP_EXPRCURV_CONCAVE, NULL, NULL) );
1785 	      if( nlexpr != NULL )
1786 	      {
1787 	         assert(SCIPexprGetNChildren(nlexpr) > 0);  /* should not be trivial */
1788 	
1789 	         *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
1790 	
1791 	         SCIPdebugMsg(scip, "detected expr %p to be concave -> can enforce expr >= auxvar\n", (void*)expr);
1792 	      }
1793 	   }
1794 	
1795 	   /* everything we participate in we also enforce */
1796 	   *enforcing |= *participating;
1797 	
1798 	   assert(*participating || nlexpr == NULL);
1799 	   if( !*participating )
1800 	   {
1801 	      SCIPhashmapFree(&nlexpr2origexpr);
1802 	      return SCIP_OKAY;
1803 	   }
1804 	
1805 	   /* create the expression data of the nonlinear handler
1806 	    * notify conshdlr about expr for which we will require auxiliary variables
1807 	    */
1808 	   SCIP_CALL( createNlhdlrExprData(scip, nlhdlrdata, nlhdlrexprdata, expr, nlexpr, nlexpr2origexpr, nleafs, *participating) );
1809 	
1810 	   return SCIP_OKAY;
1811 	}
1812 	
1813 	/** auxiliary evaluation callback */
1814 	static
1815 	SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalAuxConvexConcave)
1816 	{ /*lint --e{715}*/
1817 	   assert(nlhdlrexprdata != NULL);
1818 	   assert(nlhdlrexprdata->nlexpr != NULL);
1819 	   assert(auxvalue != NULL);
1820 	
1821 	   SCIP_CALL( SCIPevalExpr(scip, nlhdlrexprdata->nlexpr, sol, 0L) );
1822 	   *auxvalue = SCIPexprGetEvalValue(nlhdlrexprdata->nlexpr);
1823 	
1824 	   return SCIP_OKAY;
1825 	}
1826 	
1827 	/** init sepa callback that initializes LP */
1828 	static
1829 	SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaConvex)
1830 	{  /*lint --e{715}*/
1831 	   SCIP_EXPR* nlexpr;
1832 	   SCIP_EXPRCURV curvature;
1833 	   SCIP_Bool success;
1834 	   SCIP_ROWPREP* rowprep = NULL;
1835 	   SCIP_ROW* row;
1836 	   SCIP_Real lb;
1837 	   SCIP_Real ub;
1838 	   SCIP_Real lambda;
1839 	   SCIP_SOL* sol;
1840 	   int k;
1841 	
1842 	   assert(scip != NULL);
1843 	   assert(expr != NULL);
1844 	   assert(nlhdlrexprdata != NULL);
1845 	
1846 	   /* setup nlhdlrexprdata->leafexprs */
1847 	   SCIP_CALL( collectLeafs(scip, nlhdlrexprdata) );
1848 	
1849 	   nlexpr = nlhdlrexprdata->nlexpr;
1850 	   assert(nlexpr != NULL);
1851 	   assert(SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, (void*)nlexpr) == expr);
1852 	
1853 	   curvature = SCIPexprGetCurvature(nlexpr);
1854 	   assert(curvature == SCIP_EXPRCURV_CONVEX || curvature == SCIP_EXPRCURV_CONCAVE);
1855 	
1856 	   /* we can only be estimating on the convex side */
1857 	   if( curvature == SCIP_EXPRCURV_CONVEX )
1858 	      overestimate = FALSE;
1859 	   else if( curvature == SCIP_EXPRCURV_CONCAVE )
1860 	      underestimate = FALSE;
1861 	   if( !overestimate && !underestimate )
1862 	      return SCIP_OKAY;
1863 	
1864 	   /* linearizes at 5 different points obtained as convex combination of the lower and upper bound of the variables
1865 	    * present in the convex expression; whether more weight is given to the lower or upper bound of a variable depends
1866 	    * on whether the fixing of the variable to that value is better for the objective function
1867 	    */
1868 	   SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) );
1869 	
1870 	   *infeasible = FALSE;
1871 	
1872 	   for( k = 0; k < 5; ++k )
1873 	   {
1874 	      int i;
1875 	      lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
1876 	
1877 	      for( i = 0; i < nlhdlrexprdata->nleafs; ++i )
1878 	      {
1879 	         SCIP_VAR* var;
1880 	
1881 	         var = SCIPgetVarExprVar(nlhdlrexprdata->leafexprs[i]);
1882 	
1883 	         lb = SCIPvarGetLbGlobal(var);
1884 	         ub = SCIPvarGetUbGlobal(var);
1885 	
1886 	         /* make sure the absolute values of bounds are not too large */
1887 	         if( ub > -INITLPMAXVARVAL )
1888 	            lb = MAX(lb, -INITLPMAXVARVAL);
1889 	         if( lb <  INITLPMAXVARVAL )
1890 	            ub = MIN(ub,  INITLPMAXVARVAL);
1891 	
1892 	         /* in the case when ub < -maxabsbnd or lb > maxabsbnd, we still want to at least make bounds finite */
1893 	         if( SCIPisInfinity(scip, -lb) )
1894 	            lb = MIN(-10.0, ub - 0.1*REALABS(ub));
1895 	         if( SCIPisInfinity(scip,  ub) )
1896 	            ub = MAX( 10.0, lb + 0.1*REALABS(lb));
1897 	
1898 	         if( SCIPvarGetBestBoundType(var) == SCIP_BOUNDTYPE_LOWER )
1899 	            SCIP_CALL( SCIPsetSolVal(scip, sol, var, lambda * ub + (1.0 - lambda) * lb) );
1900 	         else
1901 	            SCIP_CALL( SCIPsetSolVal(scip, sol, var, lambda * lb + (1.0 - lambda) * ub) );
1902 	      }
1903 	
1904 	      SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT, TRUE) );
1905 	      SCIP_CALL( estimateGradient(scip, nlhdlrexprdata, sol, 0.0, rowprep, &success) );
1906 	      if( !success )
1907 	      {
1908 	         SCIPdebugMsg(scip, "failed to linearize for k = %d\n", k);
1909 	         if( rowprep != NULL )
1910 	            SCIPfreeRowprep(scip, &rowprep);
1911 	         continue;
1912 	      }
1913 	
1914 	      /* add auxiliary variable */
1915 	      SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1916 	
1917 	      /* straighten out numerics */
1918 	      SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, NULL, SCIPgetHugeValue(scip), &success) );
1919 	      if( !success )
1920 	      {
1921 	         SCIPdebugMsg(scip, "failed to cleanup rowprep numerics for k = %d\n", k);
1922 	         if( rowprep != NULL )
1923 	            SCIPfreeRowprep(scip, &rowprep);
1924 	         continue;
1925 	      }
1926 	
1927 	      (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_gradient%p_initsepa_%d",
1928 	            overestimate ? "over" : "under", (void*)expr, k);
1929 	      SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
1930 	      SCIPfreeRowprep(scip, &rowprep);
1931 	
1932 	#ifdef SCIP_DEBUG
1933 	      SCIPinfoMessage(scip, NULL, "initsepa computed row: ");
1934 	      SCIPprintRow(scip, row, NULL);
1935 	#endif
1936 	
1937 	      SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
1938 	      SCIP_CALL( SCIPreleaseRow(scip, &row) );
1939 	
1940 	      if( *infeasible )
1941 	         break;
1942 	   }
1943 	
1944 	   SCIP_CALL( SCIPfreeSol(scip, &sol) );
1945 	
1946 	   return SCIP_OKAY;
1947 	}
1948 	
1949 	/** estimator callback */
1950 	static
1951 	SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateConvex)
1952 	{ /*lint --e{715}*/
1953 	   SCIP_ROWPREP* rowprep;
1954 	
1955 	   assert(scip != NULL);
1956 	   assert(expr != NULL);
1957 	   assert(nlhdlrexprdata != NULL);
1958 	   assert(nlhdlrexprdata->nlexpr != NULL);
1959 	   assert(rowpreps != NULL);
1960 	   assert(success != NULL);
1961 	
1962 	   assert(SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, (void*)nlhdlrexprdata->nlexpr) == expr);
1963 	
1964 	   /* we must be called only for the side that we indicated to participate in during DETECT */
1965 	   assert(SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONVEX
1966 	          || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONCAVE);
1967 	   assert(!overestimate || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONCAVE);
1968 	   assert( overestimate || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONVEX);
1969 	
1970 	   *success = FALSE;
1971 	   *addedbranchscores = FALSE;
1972 	
1973 	   /* we can skip eval as nlhdlrEvalAux should have been called for same solution before */
1974 	   /* SCIP_CALL( nlhdlrExprEval(scip, nlexpr, sol) ); */
1975 	   assert(auxvalue == SCIPexprGetEvalValue(nlhdlrexprdata->nlexpr)); /* given value (originally from
1976 	         nlhdlrEvalAuxConvexConcave) should coincide with the one stored in nlexpr */
1977 	
1978 	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT, TRUE) );
1979 	
1980 	   if( nlhdlrexprdata->nleafs == 1 && SCIPexprIsIntegral(nlhdlrexprdata->leafexprs[0]) )
1981 	   {
1982 	      SCIP_CALL( estimateConvexSecant(scip, nlhdlr, nlhdlrexprdata, sol, rowprep, success) );
1983 	
1984 	      (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_convexsecant%p_%s%d",
1985 	         overestimate ? "over" : "under",
1986 	         (void*)expr,
1987 	         sol != NULL ? "sol" : "lp",
1988 	         sol != NULL ? SCIPsolGetIndex(sol) : SCIPgetNLPs(scip));
1989 	   }
1990 	
1991 	   /* if secant method was not used or failed, then try with gradient */
1992 	   if( !*success )
1993 	   {
1994 	      SCIP_CALL( estimateGradient(scip, nlhdlrexprdata, sol, auxvalue, rowprep, success) );
1995 	
1996 	      (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_convexgradient%p_%s%d",
1997 	         overestimate ? "over" : "under",
1998 	         (void*)expr,
1999 	         sol != NULL ? "sol" : "lp",
(1) Event invalid_type: Argument "(sol != NULL) ? sol->index : SCIPgetNLPs(scip)" to format specifier "%d" was expected to have type "int" but has type "long long". [details]
2000 	         sol != NULL ? SCIPsolGetIndex(sol) : SCIPgetNLPs(scip));
2001 	   }
2002 	
2003 	   if( *success )
2004 	   {
2005 	      SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
2006 	   }
2007 	   else
2008 	   {
2009 	      SCIPfreeRowprep(scip, &rowprep);
2010 	   }
2011 	
2012 	   return SCIP_OKAY;
2013 	}
2014 	
2015 	/** include nlhdlr in another scip instance */
2016 	static
2017 	SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrConvex)
2018 	{ /*lint --e{715}*/
2019 	   assert(targetscip != NULL);
2020 	   assert(sourcenlhdlr != NULL);
2021 	   assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), CONVEX_NLHDLR_NAME) == 0);
2022 	
2023 	   SCIP_CALL( SCIPincludeNlhdlrConvex(targetscip) );
2024 	
2025 	   return SCIP_OKAY;
2026 	}
2027 	
2028 	/** includes convex nonlinear handler in nonlinear constraint handler */
2029 	SCIP_RETCODE SCIPincludeNlhdlrConvex(
2030 	   SCIP*                 scip                /**< SCIP data structure */
2031 	   )
2032 	{
2033 	   SCIP_NLHDLR* nlhdlr;
2034 	   SCIP_NLHDLRDATA* nlhdlrdata;
2035 	
2036 	   assert(scip != NULL);
2037 	
2038 	   SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
2039 	   nlhdlrdata->isnlhdlrconvex = TRUE;
2040 	   nlhdlrdata->evalsol = NULL;
2041 	
2042 	   SCIP_CALL( SCIPincludeNlhdlrNonlinear(scip, &nlhdlr, CONVEX_NLHDLR_NAME, CONVEX_NLHDLR_DESC,
2043 	      CONVEX_NLHDLR_DETECTPRIORITY, CONVEX_NLHDLR_ENFOPRIORITY, nlhdlrDetectConvex, nlhdlrEvalAuxConvexConcave, nlhdlrdata) );
2044 	   assert(nlhdlr != NULL);
2045 	
2046 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONVEX_NLHDLR_NAME "/detectsum",
2047 	      "whether to run convexity detection when the root of an expression is a non-quadratic sum",
2048 	      &nlhdlrdata->detectsum, FALSE, DEFAULT_DETECTSUM, NULL, NULL) );
2049 	
2050 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONVEX_NLHDLR_NAME "/extendedform",
2051 	      "whether to create extended formulations instead of looking for maximal convex expressions",
2052 	      &nlhdlrdata->extendedform, FALSE, DEFAULT_EXTENDEDFORM, NULL, NULL) );
2053 	
2054 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONVEX_NLHDLR_NAME "/cvxquadratic",
2055 	      "whether to use convexity check on quadratics",
2056 	      &nlhdlrdata->cvxquadratic, TRUE, DEFAULT_CVXQUADRATIC_CONVEX, NULL, NULL) );
2057 	
2058 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONVEX_NLHDLR_NAME "/cvxsignomial",
2059 	      "whether to use convexity check on signomials",
2060 	      &nlhdlrdata->cvxsignomial, TRUE, DEFAULT_CVXSIGNOMIAL, NULL, NULL) );
2061 	
2062 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONVEX_NLHDLR_NAME "/cvxprodcomp",
2063 	      "whether to use convexity check on product composition f(h)*h",
2064 	      &nlhdlrdata->cvxprodcomp, TRUE, DEFAULT_CVXPRODCOMP, NULL, NULL) );
2065 	
2066 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONVEX_NLHDLR_NAME "/handletrivial",
2067 	      "whether to also handle trivial convex expressions",
2068 	      &nlhdlrdata->handletrivial, TRUE, DEFAULT_HANDLETRIVIAL, NULL, NULL) );
2069 	
2070 	   SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrfreeHdlrDataConvexConcave);
2071 	   SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrConvex);
2072 	   SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrfreeExprDataConvexConcave);
2073 	   SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaConvex, NULL, nlhdlrEstimateConvex, NULL);
2074 	   SCIPnlhdlrSetInitExit(nlhdlr, NULL, nlhdlrExitConvex);
2075 	
2076 	   return SCIP_OKAY;
2077 	}
2078 	
2079 	/*
2080 	 * Callback methods of concave nonlinear handler
2081 	 */
2082 	
2083 	/** deinitialization of problem-specific data */
2084 	static
2085 	SCIP_DECL_NLHDLREXIT(nlhdlrExitConcave)
2086 	{
2087 	   SCIP_NLHDLRDATA* nlhdlrdata;
2088 	
2089 	   nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
2090 	   assert(nlhdlrdata != NULL);
2091 	
2092 	   if( nlhdlrdata->evalsol != NULL )
2093 	   {
2094 	      SCIP_CALL( SCIPfreeSol(scip, &nlhdlrdata->evalsol) );
2095 	   }
2096 	
2097 	   return SCIP_OKAY;
2098 	}
2099 	
2100 	/** checks whether expression (or -expression) is concave, possibly after introducing auxiliary variables */
2101 	static
2102 	SCIP_DECL_NLHDLRDETECT(nlhdlrDetectConcave)
2103 	{ /*lint --e{715}*/
2104 	   SCIP_NLHDLRDATA* nlhdlrdata;
2105 	   SCIP_EXPR* nlexpr = NULL;
2106 	   SCIP_HASHMAP* nlexpr2origexpr;
2107 	   int nleafs = 0;
2108 	
2109 	   assert(scip != NULL);
2110 	   assert(nlhdlr != NULL);
2111 	   assert(expr != NULL);
2112 	   assert(enforcing != NULL);
2113 	   assert(participating != NULL);
2114 	   assert(nlhdlrexprdata != NULL);
2115 	
2116 	   /* we currently do not participate if only activity computation is required */
2117 	   if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABOTH) == SCIP_NLHDLR_METHOD_SEPABOTH )
2118 	      return SCIP_OKAY;
2119 	
2120 	   /* ignore pure constants and variables */
2121 	   if( SCIPexprGetNChildren(expr) == 0 )
2122 	      return SCIP_OKAY;
2123 	
2124 	   nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
2125 	   assert(nlhdlrdata != NULL);
2126 	   assert(!nlhdlrdata->isnlhdlrconvex);
2127 	
2128 	   SCIPdebugMsg(scip, "nlhdlr_concave detect for expr %p\n", (void*)expr);
2129 	
2130 	   /* initialize mapping from copied expression to original one
2131 	    * 20 is not a bad estimate for the size of concave subexpressions that we can usually discover
2132 	    * when expressions will be allowed to store "user"data, we could get rid of this hashmap (TODO)
2133 	    */
2134 	   SCIP_CALL( SCIPhashmapCreate(&nlexpr2origexpr, SCIPblkmem(scip), 20) );
2135 	
2136 	   if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 )  /* if no separation below yet */
2137 	   {
2138 	      SCIP_CALL( constructExpr(scip, nlhdlrdata, &nlexpr, nlexpr2origexpr, &nleafs, expr,
2139 	         SCIP_EXPRCURV_CONCAVE, NULL, NULL) );
2140 	
2141 	      if( nlexpr != NULL && nleafs > SCIP_MAXVERTEXPOLYDIM )
2142 	      {
2143 	         SCIPdebugMsg(scip, "Too many variables (%d) in constructed expression. Will not be able to estimate. Rejecting.\n", nleafs);
2144 	         SCIP_CALL( SCIPreleaseExpr(scip, &nlexpr) );
2145 	      }
2146 	
2147 	      if( nlexpr != NULL )
2148 	      {
2149 	         assert(SCIPexprGetNChildren(nlexpr) > 0);  /* should not be trivial */
2150 	
2151 	         *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
2152 	
2153 	         SCIPdebugMsg(scip, "detected expr %p to be concave -> can enforce expr <= auxvar\n", (void*)expr);
2154 	      }
2155 	      else
2156 	      {
2157 	         SCIP_CALL( SCIPhashmapRemoveAll(nlexpr2origexpr) );
2158 	      }
2159 	   }
2160 	
2161 	   if( (*enforcing & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 && nlexpr == NULL )  /* if no separation above and not concave */
2162 	   {
2163 	      SCIP_CALL( constructExpr(scip, nlhdlrdata, &nlexpr, nlexpr2origexpr, &nleafs, expr,
2164 	         SCIP_EXPRCURV_CONVEX, NULL, NULL) );
2165 	
2166 	      if( nlexpr != NULL && nleafs > SCIP_MAXVERTEXPOLYDIM )
2167 	      {
2168 	         SCIPdebugMsg(scip, "Too many variables (%d) in constructed expression. Will not be able to estimate. Rejecting.\n", nleafs);
2169 	         SCIP_CALL( SCIPreleaseExpr(scip, &nlexpr) );
2170 	      }
2171 	
2172 	      if( nlexpr != NULL )
2173 	      {
2174 	         assert(SCIPexprGetNChildren(nlexpr) > 0);  /* should not be trivial */
2175 	
2176 	         *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
2177 	
2178 	         SCIPdebugMsg(scip, "detected expr %p to be convex -> can enforce expr >= auxvar\n", (void*)expr);
2179 	      }
2180 	   }
2181 	
2182 	   /* everything we participate in we also enforce (at the moment) */
2183 	   *enforcing |= *participating;
2184 	
2185 	   assert(*participating || nlexpr == NULL);
2186 	   if( !*participating )
2187 	   {
2188 	      SCIPhashmapFree(&nlexpr2origexpr);
2189 	      return SCIP_OKAY;
2190 	   }
2191 	
2192 	   /* create the expression data of the nonlinear handler
2193 	    * notify conshdlr about expr for which we will require auxiliary variables and use activity
2194 	    */
2195 	   SCIP_CALL( createNlhdlrExprData(scip, nlhdlrdata, nlhdlrexprdata, expr, nlexpr, nlexpr2origexpr, nleafs, *participating) );
2196 	
2197 	   return SCIP_OKAY;
2198 	}
2199 	
2200 	/** init sepa callback that initializes LP */
2201 	static
2202 	SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaConcave)
2203 	{
2204 	   SCIP_EXPR* nlexpr;
2205 	   SCIP_EXPRCURV curvature;
2206 	   SCIP_Bool success;
2207 	   SCIP_ROWPREP* rowprep = NULL;
2208 	   SCIP_ROW* row;
2209 	
2210 	   assert(scip != NULL);
2211 	   assert(expr != NULL);
2212 	   assert(nlhdlrexprdata != NULL);
2213 	
2214 	   nlexpr = nlhdlrexprdata->nlexpr;
2215 	   assert(nlexpr != NULL);
2216 	   assert(SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, (void*)nlexpr) == expr);
2217 	
2218 	   /* setup nlhdlrexprdata->leafexprs */
2219 	   SCIP_CALL( collectLeafs(scip, nlhdlrexprdata) );
2220 	
2221 	   curvature = SCIPexprGetCurvature(nlexpr);
2222 	   assert(curvature == SCIP_EXPRCURV_CONVEX || curvature == SCIP_EXPRCURV_CONCAVE);
2223 	   /* we can only be estimating on non-convex side */
2224 	   if( curvature == SCIP_EXPRCURV_CONCAVE )
2225 	      overestimate = FALSE;
2226 	   else if( curvature == SCIP_EXPRCURV_CONVEX )
2227 	      underestimate = FALSE;
2228 	   if( !overestimate && !underestimate )
2229 	      return SCIP_OKAY;
2230 	
2231 	   /* compute estimator and store in rowprep */
2232 	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT, TRUE) );
2233 	   SCIP_CALL( estimateVertexPolyhedral(scip, conshdlr, nlhdlr, nlhdlrexprdata, NULL, TRUE, overestimate,
2234 	         overestimate ? SCIPinfinity(scip) : -SCIPinfinity(scip), rowprep, &success) );
2235 	   if( !success )
2236 	   {
2237 	      SCIPdebugMsg(scip, "failed to compute facet of convex hull\n");
2238 	      goto TERMINATE;
2239 	   }
2240 	
2241 	   /* add auxiliary variable */
2242 	   SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
2243 	
2244 	   /* straighten out numerics */
2245 	   SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, NULL, SCIPgetHugeValue(scip), &success) );
2246 	   if( !success )
2247 	   {
2248 	      SCIPdebugMsg(scip, "failed to cleanup rowprep numerics\n");
2249 	      goto TERMINATE;
2250 	   }
2251 	
2252 	   (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_concave%p_initsepa",
2253 	         overestimate ? "over" : "under", (void*)expr);
2254 	   SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
2255 	
2256 	#ifdef SCIP_DEBUG
2257 	   SCIPinfoMessage(scip, NULL, "initsepa computed row: ");
2258 	   SCIPprintRow(scip, row, NULL);
2259 	#endif
2260 	
2261 	   SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
2262 	   SCIP_CALL( SCIPreleaseRow(scip, &row) );
2263 	
2264 	 TERMINATE:
2265 	   if( rowprep != NULL )
2266 	      SCIPfreeRowprep(scip, &rowprep);
2267 	
2268 	   return SCIP_OKAY;
2269 	}
2270 	
2271 	/** estimator callback */
2272 	static
2273 	SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateConcave)
2274 	{ /*lint --e{715}*/
2275 	   SCIP_ROWPREP* rowprep;
2276 	
2277 	   assert(scip != NULL);
2278 	   assert(expr != NULL);
2279 	   assert(nlhdlrexprdata != NULL);
2280 	   assert(nlhdlrexprdata->nlexpr != NULL);
2281 	   assert(rowpreps != NULL);
2282 	   assert(success != NULL);
2283 	
2284 	   assert(SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, (void*)nlhdlrexprdata->nlexpr) == expr);
2285 	
2286 	   /* we must be called only for the side that we indicated to participate in during DETECT */
2287 	   assert(SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONVEX
2288 	         || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONCAVE);
2289 	   assert(!overestimate || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONVEX);
2290 	   assert( overestimate || SCIPexprGetCurvature(nlhdlrexprdata->nlexpr) == SCIP_EXPRCURV_CONCAVE);
2291 	
2292 	   *success = FALSE;
2293 	   *addedbranchscores = FALSE;
2294 	
2295 	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT, TRUE) );
2296 	
2297 	   SCIP_CALL( estimateVertexPolyhedral(scip, conshdlr, nlhdlr, nlhdlrexprdata, sol, FALSE, overestimate, targetvalue, rowprep, success) );
2298 	
2299 	   if( *success )
2300 	   {
2301 	      SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
2302 	
2303 	      (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_concave%p_%s%d",
2304 	         overestimate ? "over" : "under",
2305 	         (void*)expr,
2306 	         sol != NULL ? "sol" : "lp",
2307 	         sol != NULL ? SCIPsolGetIndex(sol) : SCIPgetNLPs(scip));
2308 	   }
2309 	   else
2310 	   {
2311 	      SCIPfreeRowprep(scip, &rowprep);
2312 	   }
2313 	
2314 	   if( addbranchscores )
2315 	   {
2316 	      SCIP_Real violation;
2317 	
2318 	      /* check how much is the violation on the side that we estimate */
2319 	      if( auxvalue == SCIP_INVALID )
2320 	      {
2321 	         /* if cannot evaluate, then always branch */
2322 	         violation = SCIPinfinity(scip);
2323 	      }
2324 	      else
2325 	      {
2326 	         SCIP_Real auxval;
2327 	
2328 	         /* get value of auxiliary variable of this expression */
2329 	         assert(SCIPgetExprAuxVarNonlinear(expr) != NULL);
2330 	         auxval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr));
2331 	
2332 	         /* compute the violation
2333 	          * if we underestimate, then we enforce expr <= auxval, so violation is (positive part of) auxvalue - auxval
2334 	          * if we overestimate,  then we enforce expr >= auxval, so violation is (positive part of) auxval - auxvalue
2335 	          */
2336 	         if( !overestimate )
2337 	            violation = MAX(0.0, auxvalue - auxval);
2338 	         else
2339 	            violation = MAX(0.0, auxval - auxvalue);
2340 	      }
2341 	      assert(violation >= 0.0);
2342 	
2343 	      /* add violation as branching-score to expressions; the core will take care distributing this onto variables */
2344 	      if( nlhdlrexprdata->nleafs == 1 )
2345 	      {
2346 	         SCIP_EXPR* e;
2347 	         e = (SCIP_EXPR*)SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, nlhdlrexprdata->leafexprs[0]);
2348 	         SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, &e, 1, violation, sol, addedbranchscores) );
2349 	      }
2350 	      else
2351 	      {
2352 	         SCIP_EXPR** exprs;
2353 	         int c;
2354 	
2355 	         /* map leaf expressions back to original expressions
2356 	          * TODO do this once at end of detect and store in nlhdlrexprdata
2357 	          */
2358 	         SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nlhdlrexprdata->nleafs) );
2359 	         for( c = 0; c < nlhdlrexprdata->nleafs; ++c )
2360 	               exprs[c] = (SCIP_EXPR*)SCIPhashmapGetImage(nlhdlrexprdata->nlexpr2origexpr, nlhdlrexprdata->leafexprs[c]);
2361 	
2362 	         SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nlhdlrexprdata->nleafs, violation, sol, addedbranchscores) );
2363 	
2364 	         SCIPfreeBufferArray(scip, &exprs);
2365 	      }
2366 	   }
2367 	
2368 	   return SCIP_OKAY;
2369 	}
2370 	
2371 	/** includes nonlinear handler in another scip instance */
2372 	static
2373 	SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrConcave)
2374 	{ /*lint --e{715}*/
2375 	   assert(targetscip != NULL);
2376 	   assert(sourcenlhdlr != NULL);
2377 	   assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), CONCAVE_NLHDLR_NAME) == 0);
2378 	
2379 	   SCIP_CALL( SCIPincludeNlhdlrConcave(targetscip) );
2380 	
2381 	   return SCIP_OKAY;
2382 	}
2383 	
2384 	/** includes concave nonlinear handler in nonlinear constraint handler */
2385 	SCIP_EXPORT
2386 	SCIP_RETCODE SCIPincludeNlhdlrConcave(
2387 	   SCIP*                 scip                /**< SCIP data structure */
2388 	   )
2389 	{
2390 	   SCIP_NLHDLR* nlhdlr;
2391 	   SCIP_NLHDLRDATA* nlhdlrdata;
2392 	
2393 	   assert(scip != NULL);
2394 	
2395 	   SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
2396 	   nlhdlrdata->isnlhdlrconvex = FALSE;
2397 	   nlhdlrdata->evalsol = NULL;
2398 	
2399 	   SCIP_CALL( SCIPincludeNlhdlrNonlinear(scip, &nlhdlr, CONCAVE_NLHDLR_NAME, CONCAVE_NLHDLR_DESC,
2400 	      CONCAVE_NLHDLR_DETECTPRIORITY, CONCAVE_NLHDLR_ENFOPRIORITY, nlhdlrDetectConcave, nlhdlrEvalAuxConvexConcave, nlhdlrdata) );
2401 	   assert(nlhdlr != NULL);
2402 	
2403 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONCAVE_NLHDLR_NAME "/detectsum",
2404 	      "whether to run convexity detection when the root of an expression is a sum",
2405 	      &nlhdlrdata->detectsum, FALSE, DEFAULT_DETECTSUM, NULL, NULL) );
2406 	
2407 	   /* "extended" formulations of a concave expressions can give worse estimators */
2408 	   nlhdlrdata->extendedform = FALSE;
2409 	
2410 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONCAVE_NLHDLR_NAME "/cvxquadratic",
2411 	      "whether to use convexity check on quadratics",
2412 	      &nlhdlrdata->cvxquadratic, TRUE, DEFAULT_CVXQUADRATIC_CONCAVE, NULL, NULL) );
2413 	
2414 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONCAVE_NLHDLR_NAME "/cvxsignomial",
2415 	      "whether to use convexity check on signomials",
2416 	      &nlhdlrdata->cvxsignomial, TRUE, DEFAULT_CVXSIGNOMIAL, NULL, NULL) );
2417 	
2418 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONCAVE_NLHDLR_NAME "/cvxprodcomp",
2419 	      "whether to use convexity check on product composition f(h)*h",
2420 	      &nlhdlrdata->cvxprodcomp, TRUE, DEFAULT_CVXPRODCOMP, NULL, NULL) );
2421 	
2422 	   SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" CONCAVE_NLHDLR_NAME "/handletrivial",
2423 	      "whether to also handle trivial convex expressions",
2424 	      &nlhdlrdata->handletrivial, TRUE, DEFAULT_HANDLETRIVIAL, NULL, NULL) );
2425 	
2426 	   SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrfreeHdlrDataConvexConcave);
2427 	   SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrConcave);
2428 	   SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrfreeExprDataConvexConcave);
2429 	   SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaConcave, NULL, nlhdlrEstimateConcave, NULL);
2430 	   SCIPnlhdlrSetInitExit(nlhdlr, NULL, nlhdlrExitConcave);
2431 	
2432 	   return SCIP_OKAY;
2433 	}
2434 	
2435 	/** checks whether a given expression is convex or concave w.r.t. the original variables
2436 	 *
2437 	 * This function uses the methods that are used in the detection algorithm of the convex nonlinear handler.
2438 	 */
2439 	SCIP_RETCODE SCIPhasExprCurvature(
2440 	   SCIP*                 scip,               /**< SCIP data structure */
2441 	   SCIP_EXPR*            expr,               /**< expression */
2442 	   SCIP_EXPRCURV         curv,               /**< curvature to check for */
2443 	   SCIP_Bool*            success,            /**< buffer to store whether expression has curvature curv (w.r.t. original variables) */
2444 	   SCIP_HASHMAP*         assumevarfixed      /**< hashmap containing variables that should be assumed to be fixed, or NULL */
2445 	   )
2446 	{
2447 	   SCIP_NLHDLRDATA nlhdlrdata;
2448 	   SCIP_EXPR* rootnlexpr;
2449 	   SCIP_HASHMAP* nlexpr2origexpr;
2450 	   int nleafs;
2451 	
2452 	   assert(expr != NULL);
2453 	   assert(curv != SCIP_EXPRCURV_UNKNOWN);
2454 	   assert(success != NULL);
2455 	
2456 	   /* create temporary hashmap */
2457 	   SCIP_CALL( SCIPhashmapCreate(&nlexpr2origexpr, SCIPblkmem(scip), 20) );
2458 	
2459 	   /* prepare nonlinear handler data */
2460 	   nlhdlrdata.isnlhdlrconvex = TRUE;
2461 	   nlhdlrdata.evalsol = NULL;
2462 	   nlhdlrdata.detectsum = TRUE;
2463 	   nlhdlrdata.extendedform = FALSE;
2464 	   nlhdlrdata.cvxquadratic = TRUE;
2465 	   nlhdlrdata.cvxsignomial = TRUE;
2466 	   nlhdlrdata.cvxprodcomp = TRUE;
2467 	   nlhdlrdata.handletrivial = TRUE;
2468 	
2469 	   SCIP_CALL( constructExpr(scip, &nlhdlrdata, &rootnlexpr, nlexpr2origexpr, &nleafs, expr, curv, assumevarfixed, success) );
2470 	
2471 	   /* free created expression */
2472 	   if( rootnlexpr != NULL )
2473 	   {
2474 	      SCIP_CALL( SCIPreleaseExpr(scip, &rootnlexpr) );
2475 	   }
2476 	
2477 	   /* free hashmap */
2478 	   SCIPhashmapFree(&nlexpr2origexpr);
2479 	
2480 	   return SCIP_OKAY;
2481 	}
2482