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   expr_log.c
17   	 * @ingroup DEFPLUGINS_EXPR
18   	 * @brief  logarithm expression handler
19   	 * @author Stefan Vigerske
20   	 * @author Benjamin Mueller
21   	 * @author Ksenia Bestuzheva
22   	 *
23   	 */
24   	
25   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26   	
27   	#include <string.h>
28   	
29   	#include "scip/expr_value.h"
30   	#include "scip/expr_log.h"
31   	
32   	#define EXPRHDLR_NAME         "log"
33   	#define EXPRHDLR_DESC         "natural logarithm expression"
34   	#define EXPRHDLR_PRECEDENCE   80000
35   	#define EXPRHDLR_HASHKEY      SCIPcalcFibHash(16273.0)
36   	
37   	/*
38   	 * Data structures
39   	 */
40   	
41   	/** expression handler data */
42   	struct SCIP_ExprhdlrData
43   	{
44   	   SCIP_Real             minzerodistance;    /**< minimal distance from zero to enforce for child in bound tightening */
45   	   SCIP_Bool             warnedonpole;       /**< whether we warned on enforcing a minimal non-zero bound for child */
46   	};
47   	
48   	/*
49   	 * Local methods
50   	 */
51   	
52   	/** computes coefficients of secant of a logarithmic term */
53   	static
54   	void addLogSecant(
55   	   SCIP*                 scip,               /**< SCIP data structure */
56   	   SCIP_Real             lb,                 /**< lower bound on variable */
57   	   SCIP_Real             ub,                 /**< upper bound on variable */
58   	   SCIP_Real*            lincoef,            /**< buffer to add coefficient of secant */
59   	   SCIP_Real*            linconstant,        /**< buffer to add constant of secant */
60   	   SCIP_Bool*            success             /**< buffer to set to FALSE if secant has failed due to large numbers or unboundedness */
61   	   )
62   	{
63   	   SCIP_Real coef;
64   	   SCIP_Real constant;
65   	
66   	   assert(scip != NULL);
67   	   assert(!SCIPisInfinity(scip,  lb));
68   	   assert(!SCIPisInfinity(scip, -ub));
69   	   assert(SCIPisLE(scip, lb, ub));
70   	   assert(lincoef != NULL);
71   	   assert(linconstant != NULL);
72   	   assert(success != NULL);
73   	
74   	   if( SCIPisLE(scip, lb, 0.0) || SCIPisInfinity(scip, ub) )
75   	   {
76   	      /* unboundedness */
77   	      *success = FALSE;
78   	      return;
79   	   }
80   	
81   	   /* if lb and ub are too close use a safe secant */
82   	   if( SCIPisEQ(scip, lb, ub) )
83   	   {
84   	      coef = 0.0;
85   	      constant = log(ub);
86   	   }
87   	   else
88   	   {
89   	      coef = (log(ub) - log(lb)) / (ub - lb);
90   	      constant = log(ub) - coef * ub;
91   	   }
92   	
93   	   if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
94   	   {
95   	      *success = FALSE;
96   	      return;
97   	   }
98   	
99   	   *lincoef     += coef;
100  	   *linconstant += constant;
101  	}
102  	
103  	/** computes coefficients of linearization of a logarithmic term in a reference point */
104  	static
105  	void addLogLinearization(
106  	   SCIP*                 scip,               /**< SCIP data structure */
107  	   SCIP_Real             refpoint,           /**< point for which to compute value of linearization */
108  	   SCIP_Bool             isint,              /**< whether corresponding variable is a discrete variable, and thus linearization could be moved */
109  	   SCIP_Real*            lincoef,            /**< buffer to add coefficient of secant */
110  	   SCIP_Real*            linconstant,        /**< buffer to add constant of secant */
111  	   SCIP_Bool*            success             /**< buffer to set to FALSE if secant has failed due to large numbers or unboundedness */
112  	   )
113  	{
114  	   SCIP_Real constant;
115  	   SCIP_Real coef;
116  	
117  	   assert(scip != NULL);
118  	   assert(lincoef != NULL);
119  	   assert(linconstant != NULL);
120  	   assert(success != NULL);
121  	
122  	   /* can not compute a valid cut if zero is contained in [lb,ub] */
123  	   if( SCIPisInfinity(scip, REALABS(refpoint)) || SCIPisLE(scip, refpoint, 0.0) )
124  	   {
125  	      *success = FALSE;
126  	      return;
127  	   }
128  	
129  	   if( !isint || SCIPisIntegral(scip, refpoint) )
130  	   {
131  	      assert(refpoint != 0.0);
132  	      coef = 1.0 / refpoint;
133  	      constant = log(refpoint) - 1.0;
134  	   }
135  	   else
136  	   {
137  	      /* log(x) -> secant between f=floor(refpoint) and f+1 = log((f+1.0)/f) * x + log(f) - log((f+1.0)/f) * f */
138  	      SCIP_Real f;
139  	
140  	      f = SCIPfloor(scip, refpoint);
141  	      assert(f > 0.0);
142  	
143  	      coef     = log((f+1.0) / f);
144  	      constant = log(f) - coef * f;
145  	   }
146  	
147  	   if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
148  	   {
149  	      *success = FALSE;
150  	      return;
151  	   }
152  	
153  	   *lincoef += coef;
154  	   *linconstant += constant;
155  	}
156  	
157  	/*
158  	 * Callback methods of expression handler
159  	 */
160  	
161  	/** simplifies a log expression
162  	 *
163  	 * Evaluates the logarithm function when its child is a value expression.
164  	 *
165  	 * TODO: split products ?
166  	 * TODO: log(exp(*)) = *
167  	 */
168  	static
169  	SCIP_DECL_EXPRSIMPLIFY(simplifyLog)
170  	{  /*lint --e{715}*/
171  	   SCIP_EXPR* child;
172  	
173  	   assert(scip != NULL);
174  	   assert(expr != NULL);
175  	   assert(simplifiedexpr != NULL);
176  	   assert(SCIPexprGetNChildren(expr) == 1);
177  	
178  	   child = SCIPexprGetChildren(expr)[0];
179  	   assert(child != NULL);
180  	
181  	   /* check for value expression */
182  	   if( SCIPisExprValue(scip, child) )
183  	   {
184  	      /* TODO how to handle a non-positive value? */
185  	      assert(SCIPgetValueExprValue(child) > 0.0);
186  	
187  	      SCIP_CALL( SCIPcreateExprValue(scip, simplifiedexpr, log(SCIPgetValueExprValue(child)), ownercreate,
188  	            ownercreatedata) );
189  	   }
190  	   else
191  	   {
192  	      *simplifiedexpr = expr;
193  	
194  	      /* we have to capture it, since it must simulate a "normal" simplified call in which a new expression is created */
195  	      SCIPcaptureExpr(*simplifiedexpr);
196  	   }
197  	
198  	   return SCIP_OKAY;
199  	}
200  	
201  	/** expression handler copy callback */
202  	static
203  	SCIP_DECL_EXPRCOPYHDLR(copyhdlrLog)
204  	{  /*lint --e{715}*/
205  	   SCIP_CALL( SCIPincludeExprhdlrLog(scip) );
206  	
207  	   return SCIP_OKAY;
208  	}
209  	
210  	/** expression handler free callback */
211  	static
212  	SCIP_DECL_EXPRFREEHDLR(freehdlrLog)
213  	{  /*lint --e{715}*/
214  	   assert(exprhdlrdata != NULL);
215  	   assert(*exprhdlrdata != NULL);
216  	
217  	   SCIPfreeBlockMemory(scip, exprhdlrdata);
218  	
219  	   return SCIP_OKAY;
220  	}
221  	
222  	/** expression data copy callback */
223  	static
224  	SCIP_DECL_EXPRCOPYDATA(copydataLog)
225  	{  /*lint --e{715}*/
226  	   assert(targetexprdata != NULL);
227  	   assert(sourceexpr != NULL);
228  	   assert(SCIPexprGetData(sourceexpr) == NULL);
229  	
230  	   *targetexprdata = NULL;
231  	
232  	   return SCIP_OKAY;
233  	}
234  	
235  	/** expression data free callback */
236  	static
237  	SCIP_DECL_EXPRFREEDATA(freedataLog)
238  	{  /*lint --e{715}*/
239  	   assert(expr != NULL);
240  	
241  	   SCIPexprSetData(expr, NULL);
242  	
243  	   return SCIP_OKAY;
244  	}
245  	
246  	/** expression parse callback */
247  	static
248  	SCIP_DECL_EXPRPARSE(parseLog)
249  	{  /*lint --e{715}*/
250  	   SCIP_EXPR* childexpr;
251  	
252  	   assert(expr != NULL);
253  	
254  	   /* parse child expression from remaining string */
255  	   SCIP_CALL( SCIPparseExpr(scip, &childexpr, string, endstring, ownercreate, ownercreatedata) );
256  	   assert(childexpr != NULL);
257  	
258  	   /* create logarithmic expression */
259  	   SCIP_CALL( SCIPcreateExprLog(scip, expr, childexpr, ownercreate, ownercreatedata) );
260  	   assert(*expr != NULL);
261  	
262  	   /* release child expression since it has been captured by the logarithmic expression */
263  	   SCIP_CALL( SCIPreleaseExpr(scip, &childexpr) );
264  	
265  	   *success = TRUE;
266  	
267  	   return SCIP_OKAY;
268  	}
269  	
270  	/** expression point evaluation callback */
271  	static
272  	SCIP_DECL_EXPREVAL(evalLog)
273  	{  /*lint --e{715}*/
274  	   assert(expr != NULL);
275  	   assert(SCIPexprGetData(expr) == NULL);
276  	   assert(SCIPexprGetNChildren(expr) == 1);
277  	   assert(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]) != SCIP_INVALID); /*lint !e777*/
278  	
279  	   if( SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]) <= 0.0 )
280  	   {
281  	      SCIPdebugMsg(scip, "invalid evaluation of logarithmic expression\n");
282  	      *val = SCIP_INVALID;
283  	   }
284  	   else
285  	   {
286  	      *val = log(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]));
287  	   }
288  	
289  	   return SCIP_OKAY;
290  	}
291  	
292  	/** expression derivative evaluation callback */
293  	static
294  	SCIP_DECL_EXPRBWDIFF(bwdiffLog)
295  	{  /*lint --e{715}*/
296  	   SCIP_EXPR* child;
297  	
298  	   assert(expr != NULL);
299  	   assert(childidx == 0);
300  	   assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID); /*lint !e777*/
301  	
302  	   child = SCIPexprGetChildren(expr)[0];
303  	   assert(child != NULL);
304  	   assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
305  	   assert(SCIPexprGetEvalValue(child) > 0.0);
306  	
307  	   *val = 1.0 / SCIPexprGetEvalValue(child);
308  	
309  	   return SCIP_OKAY;
310  	}
311  	
312  	/** expression interval evaluation callback */
313  	static
314  	SCIP_DECL_EXPRINTEVAL(intevalLog)
315  	{  /*lint --e{715}*/
316  	   SCIP_EXPRHDLRDATA* exprhdlrdata;
317  	   SCIP_INTERVAL childinterval;
318  	
319  	   assert(expr != NULL);
320  	   assert(SCIPexprGetData(expr) == NULL);
321  	   assert(SCIPexprGetNChildren(expr) == 1);
322  	
323  	   exprhdlrdata = SCIPexprhdlrGetData(SCIPexprGetHdlr(expr));
324  	   assert(exprhdlrdata != NULL);
325  	
326  	   childinterval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
327  	
328  	   /* pretend childinterval to be >= epsilon, see also reversepropLog */
329  	   if( childinterval.inf < exprhdlrdata->minzerodistance && exprhdlrdata->minzerodistance > 0.0 )
330  	   {
331  	      if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
332  	      {
333  	         SCIPinfoMessage(scip, NULL, "Changing lower bound for child of log() from %g to %g.\n"
334  	            "Check your model formulation or use option expr/" EXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
335  	            childinterval.inf, exprhdlrdata->minzerodistance);
336  	         SCIPinfoMessage(scip, NULL, "Expression: ");
337  	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
338  	         SCIPinfoMessage(scip, NULL, "\n");
339  	         exprhdlrdata->warnedonpole = TRUE;
340  	      }
341  	      childinterval.inf = exprhdlrdata->minzerodistance;
342  	   }
343  	
344  	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childinterval) )
345  	   {
346  	      SCIPintervalSetEmpty(interval);
347  	      return SCIP_OKAY;
348  	   }
349  	
350  	   SCIPintervalLog(SCIP_INTERVAL_INFINITY, interval, childinterval);
351  	
352  	   return SCIP_OKAY;
353  	}
354  	
355  	/** expression estimation callback */
356  	static
357  	SCIP_DECL_EXPRESTIMATE(estimateLog)
358  	{  /*lint --e{715}*/
359  	   SCIP_Real lb;
360  	   SCIP_Real ub;
361  	
362  	   assert(scip != NULL);
363  	   assert(expr != NULL);
364  	   assert(SCIPexprGetNChildren(expr) == 1);
365  	   assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), EXPRHDLR_NAME) == 0);
366  	   assert(coefs != NULL);
367  	   assert(constant != NULL);
368  	   assert(islocal != NULL);
369  	   assert(branchcand != NULL);
370  	   assert(*branchcand == TRUE);
371  	   assert(success != NULL);
372  	   assert(refpoint != NULL);
373  	
374  	   lb = localbounds[0].inf;
375  	   ub = localbounds[0].sup;
376  	
377  	   *coefs = 0.0;
378  	   *constant = 0.0;
379  	   *success = TRUE;
380  	
381  	   if( overestimate )
382  	   {
383  	      if( !SCIPisPositive(scip, refpoint[0]) )
384  	      {
385  	         /* if refpoint is 0 (then lb=0 probably) or below, then slope is infinite, then try to move away from 0 */
386  	         if( SCIPisZero(scip, ub) )
387  	         {
388  	            *success = FALSE;
389  	            return SCIP_OKAY;
390  	         }
391  	
392  	         if( localbounds[0].sup < 0.2 )
393  	            refpoint[0] = 0.5 * lb + 0.5 * ub;
394  	         else
395  	            refpoint[0] = 0.1;
396  	      }
397  	
398  	      addLogLinearization(scip, refpoint[0], SCIPexprIsIntegral(SCIPexprGetChildren(expr)[0]), coefs, constant, success);
399  	      *islocal = FALSE; /* linearization is globally valid */
400  	      *branchcand = FALSE;
401  	   }
402  	   else
403  	   {
404  	      addLogSecant(scip, lb, ub, coefs, constant, success);
405  	      *islocal = TRUE; /* secants are only valid locally */
406  	   }
407  	
408  	   return SCIP_OKAY;
409  	}
410  	
411  	/** initial estimates callback that provides initial linear estimators for a logarithm expression */
412  	static
413  	SCIP_DECL_EXPRINITESTIMATES(initestimatesLog)
414  	{
415  	   SCIP_Real refpointsover[3] = {SCIP_INVALID, SCIP_INVALID, SCIP_INVALID};
416  	   SCIP_Bool overest[4] = {TRUE, TRUE, TRUE, FALSE};
417  	   SCIP_EXPR* child;
418  	   SCIP_Real lb;
419  	   SCIP_Real ub;
420  	   SCIP_Bool success;
421  	   int i;
422  	
423  	   assert(scip != NULL);
424  	   assert(expr != NULL);
425  	   assert(SCIPexprGetNChildren(expr) == 1);
426  	   assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), EXPRHDLR_NAME) == 0);
427  	
428  	   /* get expression data */
429  	   child = SCIPexprGetChildren(expr)[0];
430  	   assert(child != NULL);
431  	
432  	   lb = SCIPintervalGetInf(bounds[0]);
433  	   ub = SCIPintervalGetSup(bounds[0]);
434  	
(1) Event cond_false: Condition "fabs(lb - ub) <= scip->set->num_epsilon", taking false branch.
435  	   if( SCIPisEQ(scip, lb, ub) )
(2) Event if_end: End of if statement.
436  	      return SCIP_OKAY;
437  	
(3) Event cond_true: Condition "overestimate", taking true branch.
438  	   if( overestimate )
439  	   {
440  	      /* adjust lb */
(4) Event cond_true: Condition "0.5 * lb + 0.5 * ub <= 0.1", taking true branch.
(5) Event cond_true: Condition "lb >= ((0.5 * lb + 0.5 * ub <= 0.1) ? 0.5 * lb + 0.5 * ub : 0.1)", taking true branch.
441  	      lb = MAX(lb, MIN(0.5 * lb + 0.5 * ub, 0.1));
442  	
443  	      refpointsover[0] = lb;
(6) Event cond_true: Condition "ub >= scip->set->num_infinity", taking true branch.
444  	      refpointsover[1] = SCIPisInfinity(scip, ub) ? lb + 2.0 : (lb + ub) / 2;
(7) Event cond_true: Condition "ub >= scip->set->num_infinity", taking true branch.
445  	      refpointsover[2] = SCIPisInfinity(scip, ub) ? lb + 20.0 : ub;
446  	   }
447  	
448  	   *nreturned = 0;
449  	
(8) Event cond_true: Condition "i < 4", taking true branch.
(21) Event loop_begin: Jumped back to beginning of loop.
(22) Event cond_true: Condition "i < 4", taking true branch.
(23) Event cond_at_most: Checking "i < 4" implies that "i" may be up to 3 on the true branch.
Also see events: [overrun-local]
450  	   for( i = 0; i < 4; ++i )
451  	   {
(9) Event cond_true: Condition "overest[i]", taking true branch.
(10) Event cond_false: Condition "!overestimate", taking false branch.
(11) Event cond_false: Condition "!overest[i]", taking false branch.
(24) Event cond_true: Condition "overest[i]", taking true branch.
(25) Event cond_false: Condition "!overestimate", taking false branch.
(26) Event cond_false: Condition "!overest[i]", taking false branch.
452  	      if( (overest[i] && !overestimate) || (!overest[i] && (overestimate || SCIPisInfinity(scip, ub))) )
(12) Event if_end: End of if statement.
(27) Event if_end: End of if statement.
453  	         continue;
454  	
455  	      assert(!overest[i] || (SCIPisLE(scip, refpointsover[i], ub) && SCIPisGE(scip, refpointsover[i], lb))); /*lint !e661*/
456  	
457  	      success = TRUE;
458  	      coefs[*nreturned][0] = 0.0;
459  	      constant[*nreturned] = 0.0;
460  	
(13) Event cond_true: Condition "overest[i]", taking true branch.
(28) Event cond_true: Condition "overest[i]", taking true branch.
461  	      if( overest[i] )
462  	      {
463  	         assert(i < 3);
(29) Event overrun-local: Overrunning array "refpointsover" of 3 8-byte elements at element index 3 (byte offset 31) using index "i" (which evaluates to 3).
Also see events: [cond_at_most]
464  	         addLogLinearization(scip, refpointsover[i], SCIPexprIsIntegral(child), coefs[*nreturned], &constant[*nreturned], &success); /*lint !e661*/
(14) Event cond_true: Condition "success", taking true branch.
465  	         if( success )
466  	         {
(15) Event cond_false: Condition "0", taking false branch.
(16) Event loop_end: Reached end of loop.
467  	            SCIPdebugMsg(scip, "init overestimate log(x) at x=%g -> %g*x+%g\n", refpointsover[i], coefs[*nreturned][0], constant[*nreturned]);
468  	         }
(17) Event if_fallthrough: Falling through to end of if statement.
469  	      }
470  	      else
471  	      {
472  	         addLogSecant(scip, lb, ub, coefs[*nreturned], &constant[*nreturned], &success);
473  	         if( success )
474  	         {
475  	            SCIPdebugMsg(scip, "init underestimate log(x) on x=[%g,%g] -> %g*x+%g\n", lb, ub, coefs[*nreturned][0], constant[*nreturned]);
476  	         }
(18) Event if_end: End of if statement.
477  	      }
478  	
(19) Event cond_true: Condition "success", taking true branch.
479  	      if( success )
480  	      {
481  	         ++(*nreturned);
482  	      }
(20) Event loop: Jumping back to the beginning of the loop.
483  	   }
484  	
485  	   return SCIP_OKAY;
486  	}
487  	
488  	/** expression reverse propagation callback */
489  	static
490  	SCIP_DECL_EXPRREVERSEPROP(reversepropLog)
491  	{  /*lint --e{715}*/
492  	   SCIP_EXPRHDLRDATA* exprhdlrdata;
493  	
494  	   assert(scip != NULL);
495  	   assert(expr != NULL);
496  	   assert(SCIPexprGetNChildren(expr) == 1);
497  	
498  	   exprhdlrdata = SCIPexprhdlrGetData(SCIPexprGetHdlr(expr));
499  	   assert(exprhdlrdata != NULL);
500  	
501  	   /* f = log(c0) -> c0 = exp(f) */
502  	   SCIPintervalExp(SCIP_INTERVAL_INFINITY, &childrenbounds[0], bounds);
503  	
504  	   /* force child lower bound to be at least epsilon away from 0
505  	    * this can help a lot in enforcement (try ex8_5_3)
506  	    * child being equal 0 is already forbidden, so making it strictly greater-equal epsilon enforces
507  	    * and hopefully doesn't introduce much problems
508  	    * if childrenbounds[0].sup < epsilon, too, then this will result in a cutoff
509  	    */
510  	   if( childrenbounds[0].inf < exprhdlrdata->minzerodistance )
511  	   {
512  	      SCIPdebugMsg(scip, "Pushing child lower bound from %g to %g; upper bound remains at %g\n", childrenbounds[0].inf, SCIPepsilon(scip), childrenbounds[0].sup);
513  	
514  	      if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
515  	      {
516  	         SCIPinfoMessage(scip, NULL, "Changing lower bound for child of log() from %g to %g.\n"
517  	            "Check your model formulation or use option expr/" EXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
518  	            childrenbounds[0].inf, exprhdlrdata->minzerodistance);
519  	         SCIPinfoMessage(scip, NULL, "Expression: ");
520  	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
521  	         SCIPinfoMessage(scip, NULL, "\n");
522  	         exprhdlrdata->warnedonpole = TRUE;
523  	      }
524  	
525  	      childrenbounds[0].inf = exprhdlrdata->minzerodistance;
526  	   }
527  	
528  	   return SCIP_OKAY;
529  	}
530  	
531  	/** expression hash callback */
532  	static
533  	SCIP_DECL_EXPRHASH(hashLog)
534  	{  /*lint --e{715}*/
535  	   assert(scip != NULL);
536  	   assert(expr != NULL);
537  	   assert(SCIPexprGetNChildren(expr) == 1);
538  	   assert(hashkey != NULL);
539  	   assert(childrenhashes != NULL);
540  	
541  	   *hashkey = EXPRHDLR_HASHKEY;
542  	   *hashkey ^= childrenhashes[0];
543  	
544  	   return SCIP_OKAY;
545  	}
546  	
547  	/** expression curvature detection callback */
548  	static
549  	SCIP_DECL_EXPRCURVATURE(curvatureLog)
550  	{  /*lint --e{715}*/
551  	   assert(scip != NULL);
552  	   assert(expr != NULL);
553  	   assert(childcurv != NULL);
554  	   assert(SCIPexprGetNChildren(expr) == 1);
555  	
556  	   /* expression is concave if child is concave, expression cannot be linear or convex */
557  	   if( exprcurvature == SCIP_EXPRCURV_CONCAVE )
558  	   {
559  	      *childcurv = SCIP_EXPRCURV_CONCAVE;
560  	      *success = TRUE;
561  	   }
562  	   else
563  	      *success = FALSE;
564  	
565  	   return SCIP_OKAY;
566  	}
567  	
568  	/** expression monotonicity detection callback */
569  	static
570  	SCIP_DECL_EXPRMONOTONICITY(monotonicityLog)
571  	{  /*lint --e{715}*/
572  	   assert(scip != NULL);
573  	   assert(expr != NULL);
574  	   assert(result != NULL);
575  	   assert(childidx == 0);
576  	
577  	   *result = SCIP_MONOTONE_INC;
578  	
579  	   return SCIP_OKAY;
580  	}
581  	
582  	/** creates the handler for logarithmic expression and includes it into SCIP */
583  	SCIP_RETCODE SCIPincludeExprhdlrLog(
584  	   SCIP*                 scip                /**< SCIP data structure */
585  	   )
586  	{
587  	   SCIP_EXPRHDLR* exprhdlr;
588  	   SCIP_EXPRHDLRDATA* exprhdlrdata;
589  	
590  	   SCIP_CALL( SCIPallocClearBlockMemory(scip, &exprhdlrdata) );
591  	
592  	   SCIP_CALL( SCIPincludeExprhdlr(scip, &exprhdlr, EXPRHDLR_NAME, EXPRHDLR_DESC, EXPRHDLR_PRECEDENCE, evalLog,
593  	         exprhdlrdata) );
594  	   assert(exprhdlr != NULL);
595  	
596  	   SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, copyhdlrLog, freehdlrLog);
597  	   SCIPexprhdlrSetCopyFreeData(exprhdlr, copydataLog, freedataLog);
598  	   SCIPexprhdlrSetSimplify(exprhdlr, simplifyLog);
599  	   SCIPexprhdlrSetParse(exprhdlr, parseLog);
600  	   SCIPexprhdlrSetIntEval(exprhdlr, intevalLog);
601  	   SCIPexprhdlrSetEstimate(exprhdlr, initestimatesLog, estimateLog);
602  	   SCIPexprhdlrSetReverseProp(exprhdlr, reversepropLog);
603  	   SCIPexprhdlrSetHash(exprhdlr, hashLog);
604  	   SCIPexprhdlrSetDiff(exprhdlr, bwdiffLog, NULL, NULL);
605  	   SCIPexprhdlrSetCurvature(exprhdlr, curvatureLog);
606  	   SCIPexprhdlrSetMonotonicity(exprhdlr, monotonicityLog);
607  	
608  	   SCIP_CALL( SCIPaddRealParam(scip, "expr/" EXPRHDLR_NAME "/minzerodistance",
609  	      "minimal distance from zero to enforce for child in bound tightening",
610  	      &exprhdlrdata->minzerodistance, FALSE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
611  	
612  	   return SCIP_OKAY;
613  	}
614  	
615  	/** creates a logarithmic expression */
616  	SCIP_RETCODE SCIPcreateExprLog(
617  	   SCIP*                 scip,               /**< SCIP data structure */
618  	   SCIP_EXPR**           expr,               /**< pointer where to store expression */
619  	   SCIP_EXPR*            child,              /**< single child */
620  	   SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
621  	   void*                 ownercreatedata     /**< data to pass to ownercreate */
622  	   )
623  	{
624  	   assert(expr != NULL);
625  	   assert(child != NULL);
626  	
627  	   SCIP_CALL( SCIPcreateExpr(scip, expr, SCIPfindExprhdlr(scip, EXPRHDLR_NAME), NULL, 1, &child, ownercreate,
628  	         ownercreatedata) );
629  	
630  	   return SCIP_OKAY;
631  	}
632  	
633  	/** indicates whether expression is of log-type */  /*lint -e{715}*/
634  	SCIP_Bool SCIPisExprLog(
635  	   SCIP*                 scip,               /**< SCIP data structure */
636  	   SCIP_EXPR*            expr                /**< expression */
637  	   )
638  	{ /*lint --e{715}*/
639  	   assert(expr != NULL);
640  	
641  	   return strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), EXPRHDLR_NAME) == 0;
642  	}
643