1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SCIP is distributed under the terms of the ZIB Academic License.         */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SCIP; see the file COPYING. If not visit scip.zib.de.         */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   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  	   /**! [SnippetExprEvalLog] */
280  	   if( SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]) <= 0.0 )
281  	   {
282  	      SCIPdebugMsg(scip, "invalid evaluation of logarithmic expression\n");
283  	      *val = SCIP_INVALID;
284  	   }
285  	   else
286  	   {
287  	      *val = log(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]));
288  	   }
289  	   /**! [SnippetExprEvalLog] */
290  	
291  	   return SCIP_OKAY;
292  	}
293  	
294  	/** expression derivative evaluation callback */
295  	static
296  	SCIP_DECL_EXPRBWDIFF(bwdiffLog)
297  	{  /*lint --e{715}*/
298  	   SCIP_EXPR* child;
299  	
300  	   assert(expr != NULL);
301  	   assert(childidx == 0);
302  	   assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID); /*lint !e777*/
303  	
304  	   child = SCIPexprGetChildren(expr)[0];
305  	   assert(child != NULL);
306  	   assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
307  	   assert(SCIPexprGetEvalValue(child) > 0.0);
308  	
309  	   *val = 1.0 / SCIPexprGetEvalValue(child);
310  	
311  	   return SCIP_OKAY;
312  	}
313  	
314  	/** expression interval evaluation callback */
315  	static
316  	SCIP_DECL_EXPRINTEVAL(intevalLog)
317  	{  /*lint --e{715}*/
318  	   SCIP_EXPRHDLRDATA* exprhdlrdata;
319  	   SCIP_INTERVAL childinterval;
320  	
321  	   assert(expr != NULL);
322  	   assert(SCIPexprGetData(expr) == NULL);
323  	   assert(SCIPexprGetNChildren(expr) == 1);
324  	
325  	   exprhdlrdata = SCIPexprhdlrGetData(SCIPexprGetHdlr(expr));
326  	   assert(exprhdlrdata != NULL);
327  	
328  	   childinterval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
329  	
330  	   /* pretend childinterval to be >= epsilon, see also reversepropLog */
331  	   if( childinterval.inf < exprhdlrdata->minzerodistance && exprhdlrdata->minzerodistance > 0.0 )
332  	   {
333  	      if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
334  	      {
335  	         SCIPinfoMessage(scip, NULL, "Changing lower bound for child of log() from %g to %g.\n"
336  	            "Check your model formulation or use option expr/" EXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
337  	            childinterval.inf, exprhdlrdata->minzerodistance);
338  	         SCIPinfoMessage(scip, NULL, "Expression: ");
339  	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
340  	         SCIPinfoMessage(scip, NULL, "\n");
341  	         exprhdlrdata->warnedonpole = TRUE;
342  	      }
343  	      childinterval.inf = exprhdlrdata->minzerodistance;
344  	   }
345  	
346  	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childinterval) )
347  	   {
348  	      SCIPintervalSetEmpty(interval);
349  	      return SCIP_OKAY;
350  	   }
351  	
352  	   SCIPintervalLog(SCIP_INTERVAL_INFINITY, interval, childinterval);
353  	
354  	   return SCIP_OKAY;
355  	}
356  	
357  	/** expression estimation callback */
358  	static
359  	SCIP_DECL_EXPRESTIMATE(estimateLog)
360  	{  /*lint --e{715}*/
361  	   SCIP_Real lb;
362  	   SCIP_Real ub;
363  	
364  	   assert(scip != NULL);
365  	   assert(expr != NULL);
366  	   assert(SCIPexprGetNChildren(expr) == 1);
367  	   assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), EXPRHDLR_NAME) == 0);
368  	   assert(coefs != NULL);
369  	   assert(constant != NULL);
370  	   assert(islocal != NULL);
371  	   assert(branchcand != NULL);
372  	   assert(*branchcand == TRUE);
373  	   assert(success != NULL);
374  	   assert(refpoint != NULL);
375  	
376  	   lb = localbounds[0].inf;
377  	   ub = localbounds[0].sup;
378  	
379  	   *coefs = 0.0;
380  	   *constant = 0.0;
381  	   *success = TRUE;
382  	
383  	   if( overestimate )
384  	   {
385  	      if( !SCIPisPositive(scip, refpoint[0]) )
386  	      {
387  	         /* if refpoint is 0 (then lb=0 probably) or below, then slope is infinite, then try to move away from 0 */
388  	         if( SCIPisZero(scip, ub) )
389  	         {
390  	            *success = FALSE;
391  	            return SCIP_OKAY;
392  	         }
393  	
394  	         if( localbounds[0].sup < 0.2 )
395  	            refpoint[0] = 0.5 * lb + 0.5 * ub;
396  	         else
397  	            refpoint[0] = 0.1;
398  	      }
399  	
400  	      addLogLinearization(scip, refpoint[0], SCIPexprIsIntegral(SCIPexprGetChildren(expr)[0]), coefs, constant, success);
401  	      *islocal = FALSE; /* linearization is globally valid */
402  	      *branchcand = FALSE;
403  	   }
404  	   else
405  	   {
406  	      addLogSecant(scip, lb, ub, coefs, constant, success);
407  	      *islocal = TRUE; /* secants are only valid locally */
408  	   }
409  	
410  	   return SCIP_OKAY;
411  	}
412  	
413  	/** initial estimates callback that provides initial linear estimators for a logarithm expression */
414  	static
415  	SCIP_DECL_EXPRINITESTIMATES(initestimatesLog)
416  	{
417  	   SCIP_Real refpointsover[3] = {SCIP_INVALID, SCIP_INVALID, SCIP_INVALID};
418  	   SCIP_Bool overest[4] = {TRUE, TRUE, TRUE, FALSE};
419  	   SCIP_EXPR* child;
420  	   SCIP_Real lb;
421  	   SCIP_Real ub;
422  	   SCIP_Bool success;
423  	   int i;
424  	
425  	   assert(scip != NULL);
426  	   assert(expr != NULL);
427  	   assert(SCIPexprGetNChildren(expr) == 1);
428  	   assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), EXPRHDLR_NAME) == 0);
429  	
430  	   /* get expression data */
431  	   child = SCIPexprGetChildren(expr)[0];
432  	   assert(child != NULL);
433  	
434  	   lb = SCIPintervalGetInf(bounds[0]);
435  	   ub = SCIPintervalGetSup(bounds[0]);
436  	
(1) Event cond_false: Condition "fabs(lb - ub) <= scip->set->num_epsilon", taking false branch.
437  	   if( SCIPisEQ(scip, lb, ub) )
(2) Event if_end: End of if statement.
438  	      return SCIP_OKAY;
439  	
(3) Event cond_true: Condition "overestimate", taking true branch.
440  	   if( overestimate )
441  	   {
442  	      /* 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.
443  	      lb = MAX(lb, MIN(0.5 * lb + 0.5 * ub, 0.1));
444  	
445  	      refpointsover[0] = lb;
(6) Event cond_true: Condition "ub >= scip->set->num_infinity", taking true branch.
446  	      refpointsover[1] = SCIPisInfinity(scip, ub) ? lb + 2.0 : (lb + ub) / 2;
(7) Event cond_true: Condition "ub >= scip->set->num_infinity", taking true branch.
447  	      refpointsover[2] = SCIPisInfinity(scip, ub) ? lb + 20.0 : ub;
448  	   }
449  	
450  	   *nreturned = 0;
451  	
(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]
452  	   for( i = 0; i < 4; ++i )
453  	   {
(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.
454  	      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.
455  	         continue;
456  	
457  	      assert(!overest[i] || (SCIPisLE(scip, refpointsover[i], ub) && SCIPisGE(scip, refpointsover[i], lb))); /*lint !e661*/
458  	
459  	      success = TRUE;
460  	      coefs[*nreturned][0] = 0.0;
461  	      constant[*nreturned] = 0.0;
462  	
(13) Event cond_true: Condition "overest[i]", taking true branch.
(28) Event cond_true: Condition "overest[i]", taking true branch.
463  	      if( overest[i] )
464  	      {
465  	         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]
466  	         addLogLinearization(scip, refpointsover[i], SCIPexprIsIntegral(child), coefs[*nreturned], &constant[*nreturned], &success); /*lint !e661*/
(14) Event cond_true: Condition "success", taking true branch.
467  	         if( success )
468  	         {
(15) Event cond_false: Condition "0", taking false branch.
(16) Event loop_end: Reached end of loop.
469  	            SCIPdebugMsg(scip, "init overestimate log(x) at x=%g -> %g*x+%g\n", refpointsover[i], coefs[*nreturned][0], constant[*nreturned]);
470  	         }
(17) Event if_fallthrough: Falling through to end of if statement.
471  	      }
472  	      else
473  	      {
474  	         addLogSecant(scip, lb, ub, coefs[*nreturned], &constant[*nreturned], &success);
475  	         if( success )
476  	         {
477  	            SCIPdebugMsg(scip, "init underestimate log(x) on x=[%g,%g] -> %g*x+%g\n", lb, ub, coefs[*nreturned][0], constant[*nreturned]);
478  	         }
(18) Event if_end: End of if statement.
479  	      }
480  	
(19) Event cond_true: Condition "success", taking true branch.
481  	      if( success )
482  	      {
483  	         ++(*nreturned);
484  	      }
(20) Event loop: Jumping back to the beginning of the loop.
485  	   }
486  	
487  	   return SCIP_OKAY;
488  	}
489  	
490  	/** expression reverse propagation callback */
491  	static
492  	SCIP_DECL_EXPRREVERSEPROP(reversepropLog)
493  	{  /*lint --e{715}*/
494  	   SCIP_EXPRHDLRDATA* exprhdlrdata;
495  	
496  	   assert(scip != NULL);
497  	   assert(expr != NULL);
498  	   assert(SCIPexprGetNChildren(expr) == 1);
499  	
500  	   exprhdlrdata = SCIPexprhdlrGetData(SCIPexprGetHdlr(expr));
501  	   assert(exprhdlrdata != NULL);
502  	
503  	   /* f = log(c0) -> c0 = exp(f) */
504  	   SCIPintervalExp(SCIP_INTERVAL_INFINITY, &childrenbounds[0], bounds);
505  	
506  	   /* force child lower bound to be at least epsilon away from 0
507  	    * this can help a lot in enforcement (try ex8_5_3)
508  	    * child being equal 0 is already forbidden, so making it strictly greater-equal epsilon enforces
509  	    * and hopefully doesn't introduce much problems
510  	    * if childrenbounds[0].sup < epsilon, too, then this will result in a cutoff
511  	    */
512  	   if( childrenbounds[0].inf < exprhdlrdata->minzerodistance )
513  	   {
514  	      SCIPdebugMsg(scip, "Pushing child lower bound from %g to %g; upper bound remains at %g\n", childrenbounds[0].inf, SCIPepsilon(scip), childrenbounds[0].sup);
515  	
516  	      if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
517  	      {
518  	         SCIPinfoMessage(scip, NULL, "Changing lower bound for child of log() from %g to %g.\n"
519  	            "Check your model formulation or use option expr/" EXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
520  	            childrenbounds[0].inf, exprhdlrdata->minzerodistance);
521  	         SCIPinfoMessage(scip, NULL, "Expression: ");
522  	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
523  	         SCIPinfoMessage(scip, NULL, "\n");
524  	         exprhdlrdata->warnedonpole = TRUE;
525  	      }
526  	
527  	      childrenbounds[0].inf = exprhdlrdata->minzerodistance;
528  	   }
529  	
530  	   return SCIP_OKAY;
531  	}
532  	
533  	/** expression hash callback */
534  	static
535  	SCIP_DECL_EXPRHASH(hashLog)
536  	{  /*lint --e{715}*/
537  	   assert(scip != NULL);
538  	   assert(expr != NULL);
539  	   assert(SCIPexprGetNChildren(expr) == 1);
540  	   assert(hashkey != NULL);
541  	   assert(childrenhashes != NULL);
542  	
543  	   *hashkey = EXPRHDLR_HASHKEY;
544  	   *hashkey ^= childrenhashes[0];
545  	
546  	   return SCIP_OKAY;
547  	}
548  	
549  	/** expression curvature detection callback */
550  	static
551  	SCIP_DECL_EXPRCURVATURE(curvatureLog)
552  	{  /*lint --e{715}*/
553  	   assert(scip != NULL);
554  	   assert(expr != NULL);
555  	   assert(childcurv != NULL);
556  	   assert(SCIPexprGetNChildren(expr) == 1);
557  	
558  	   /* expression is concave if child is concave, expression cannot be linear or convex */
559  	   if( exprcurvature == SCIP_EXPRCURV_CONCAVE )
560  	   {
561  	      *childcurv = SCIP_EXPRCURV_CONCAVE;
562  	      *success = TRUE;
563  	   }
564  	   else
565  	      *success = FALSE;
566  	
567  	   return SCIP_OKAY;
568  	}
569  	
570  	/** expression monotonicity detection callback */
571  	static
572  	SCIP_DECL_EXPRMONOTONICITY(monotonicityLog)
573  	{  /*lint --e{715}*/
574  	   assert(scip != NULL);
575  	   assert(expr != NULL);
576  	   assert(result != NULL);
577  	   assert(childidx == 0);
578  	
579  	   *result = SCIP_MONOTONE_INC;
580  	
581  	   return SCIP_OKAY;
582  	}
583  	
584  	/** creates the handler for logarithmic expression and includes it into SCIP */
585  	SCIP_RETCODE SCIPincludeExprhdlrLog(
586  	   SCIP*                 scip                /**< SCIP data structure */
587  	   )
588  	{
589  	   SCIP_EXPRHDLR* exprhdlr;
590  	   SCIP_EXPRHDLRDATA* exprhdlrdata;
591  	
592  	   /**! [SnippetIncludeExprhdlrLog] */
593  	   SCIP_CALL( SCIPallocClearBlockMemory(scip, &exprhdlrdata) );
594  	
595  	   SCIP_CALL( SCIPincludeExprhdlr(scip, &exprhdlr, EXPRHDLR_NAME, EXPRHDLR_DESC, EXPRHDLR_PRECEDENCE, evalLog,
596  	         exprhdlrdata) );
597  	   assert(exprhdlr != NULL);
598  	
599  	   SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, copyhdlrLog, freehdlrLog);
600  	   SCIPexprhdlrSetCopyFreeData(exprhdlr, copydataLog, freedataLog);
601  	   SCIPexprhdlrSetSimplify(exprhdlr, simplifyLog);
602  	   SCIPexprhdlrSetParse(exprhdlr, parseLog);
603  	   SCIPexprhdlrSetIntEval(exprhdlr, intevalLog);
604  	   SCIPexprhdlrSetEstimate(exprhdlr, initestimatesLog, estimateLog);
605  	   SCIPexprhdlrSetReverseProp(exprhdlr, reversepropLog);
606  	   SCIPexprhdlrSetHash(exprhdlr, hashLog);
607  	   SCIPexprhdlrSetDiff(exprhdlr, bwdiffLog, NULL, NULL);
608  	   SCIPexprhdlrSetCurvature(exprhdlr, curvatureLog);
609  	   SCIPexprhdlrSetMonotonicity(exprhdlr, monotonicityLog);
610  	
611  	   SCIP_CALL( SCIPaddRealParam(scip, "expr/" EXPRHDLR_NAME "/minzerodistance",
612  	      "minimal distance from zero to enforce for child in bound tightening",
613  	      &exprhdlrdata->minzerodistance, FALSE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
614  	   /**! [SnippetIncludeExprhdlrLog] */
615  	
616  	   return SCIP_OKAY;
617  	}
618  	
619  	/** creates a logarithmic expression */
620  	SCIP_RETCODE SCIPcreateExprLog(
621  	   SCIP*                 scip,               /**< SCIP data structure */
622  	   SCIP_EXPR**           expr,               /**< pointer where to store expression */
623  	   SCIP_EXPR*            child,              /**< single child */
624  	   SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
625  	   void*                 ownercreatedata     /**< data to pass to ownercreate */
626  	   )
627  	{
628  	   assert(expr != NULL);
629  	   assert(child != NULL);
630  	
631  	   SCIP_CALL( SCIPcreateExpr(scip, expr, SCIPfindExprhdlr(scip, EXPRHDLR_NAME), NULL, 1, &child, ownercreate,
632  	         ownercreatedata) );
633  	
634  	   return SCIP_OKAY;
635  	}
636  	
637  	/** indicates whether expression is of log-type */  /*lint -e{715}*/
638  	SCIP_Bool SCIPisExprLog(
639  	   SCIP*                 scip,               /**< SCIP data structure */
640  	   SCIP_EXPR*            expr                /**< expression */
641  	   )
642  	{ /*lint --e{715}*/
643  	   assert(expr != NULL);
644  	
645  	   return strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), EXPRHDLR_NAME) == 0;
646  	}
647