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