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.c
17   	 * @ingroup OTHER_CFILES
18   	 * @brief  functions for nonlinearity handlers of nonlinear constraint handler
19   	 * @author Ksenia Bestuzheva
20   	 * @author Benjamin Mueller
21   	 * @author Felipe Serrano
22   	 * @author Stefan Vigerske
23   	 */
24   	
25   	#include <assert.h>
26   	
27   	#include "scip/pub_nlhdlr.h"
28   	#include "scip/nlhdlr.h"
29   	#include "scip/struct_nlhdlr.h"
30   	#include "scip/scip_timing.h"
31   	#include "scip/scip_mem.h"
32   	#include "scip/scip_param.h"
33   	#include "scip/scip_message.h"
34   	#include "scip/pub_misc.h"
35   	
36   	/**@addtogroup PublicNlhdlrInterfaceMethods
37   	 * @{
38   	 */
39   	
40   	/** sets the copy handler callback of a nonlinear handler */
41   	void SCIPnlhdlrSetCopyHdlr(
42   	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
43   	   SCIP_DECL_NLHDLRCOPYHDLR((*copy))         /**< copy callback (can be NULL) */
44   	   )
45   	{
46   	   assert(nlhdlr != NULL);
47   	
48   	   nlhdlr->copyhdlr = copy;
49   	}
50   	
51   	/** sets the nonlinear handler callback to free the nonlinear handler data */
52   	void SCIPnlhdlrSetFreeHdlrData(
53   	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
54   	   SCIP_DECL_NLHDLRFREEHDLRDATA((*freehdlrdata)) /**< handler free callback (can be NULL) */
55   	   )
56   	{
57   	   assert(nlhdlr != NULL);
58   	
59   	   nlhdlr->freehdlrdata = freehdlrdata;
60   	}
61   	
62   	/** sets the nonlinear handler callback to free expression specific data of nonlinear handler */
63   	void SCIPnlhdlrSetFreeExprData(
64   	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
65   	   SCIP_DECL_NLHDLRFREEEXPRDATA((*freeexprdata)) /**< nonlinear handler expression data free callback
66   	                                                      (can be NULL if data does not need to be freed) */
67   	   )
68   	{
69   	   assert(nlhdlr != NULL);
70   	
71   	   nlhdlr->freeexprdata = freeexprdata;
72   	}
73   	
74   	/** sets the initialization and deinitialization callback of a nonlinear handler */
75   	void SCIPnlhdlrSetInitExit(
76   	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
77   	   SCIP_DECL_NLHDLRINIT((*init)),            /**< initialization callback (can be NULL) */
78   	   SCIP_DECL_NLHDLREXIT((*exit_))            /**< deinitialization callback (can be NULL) */
79   	   )
80   	{
81   	   assert(nlhdlr != NULL);
82   	
83   	   nlhdlr->init = init;
84   	   nlhdlr->exit = exit_;
85   	}
86   	
87   	/** sets the propagation callbacks of a nonlinear handler */
88   	void SCIPnlhdlrSetProp(
89   	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
90   	   SCIP_DECL_NLHDLRINTEVAL((*inteval)),      /**< interval evaluation callback (can be NULL) */
91   	   SCIP_DECL_NLHDLRREVERSEPROP((*reverseprop)) /**< reverse propagation callback (can be NULL) */
92   	   )
93   	{
94   	   assert(nlhdlr != NULL);
95   	
96   	   nlhdlr->inteval = inteval;
97   	   nlhdlr->reverseprop = reverseprop;
98   	}
99   	
100  	/** sets the enforcement callbacks of a nonlinear handler */
101  	void SCIPnlhdlrSetSepa(
102  	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
103  	   SCIP_DECL_NLHDLRINITSEPA((*initsepa)),    /**< separation initialization callback (can be NULL) */
104  	   SCIP_DECL_NLHDLRENFO((*enfo)),            /**< enforcement callback (can be NULL if estimate is not NULL) */
105  	   SCIP_DECL_NLHDLRESTIMATE((*estimate)),    /**< estimation callback (can be NULL if sepa is not NULL) */
106  	   SCIP_DECL_NLHDLREXITSEPA((*exitsepa))     /**< separation deinitialization callback (can be NULL) */
107  	   )
108  	{
109  	   assert(nlhdlr != NULL);
110  	   assert(enfo != NULL || estimate != NULL);
111  	
112  	   nlhdlr->initsepa = initsepa;
113  	   nlhdlr->enfo = enfo;
114  	   nlhdlr->estimate = estimate;
115  	   nlhdlr->exitsepa = exitsepa;
116  	}
117  	
118  	/** gives name of nonlinear handler */
119  	const char* SCIPnlhdlrGetName(
120  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
121  	   )
122  	{
123  	   assert(nlhdlr != NULL);
124  	
125  	   return nlhdlr->name;
126  	}
127  	
128  	/** gives description of nonlinear handler, can be NULL */
129  	const char* SCIPnlhdlrGetDesc(
130  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
131  	   )
132  	{
133  	   assert(nlhdlr != NULL);
134  	
135  	   return nlhdlr->desc;
136  	}
137  	
138  	/** gives detection priority of nonlinear handler */
139  	int SCIPnlhdlrGetDetectPriority(
140  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
141  	   )
142  	{
143  	   assert(nlhdlr != NULL);
144  	
145  	   return nlhdlr->detectpriority;
146  	}
147  	
148  	/** gives enforcement priority of nonlinear handler */
149  	int SCIPnlhdlrGetEnfoPriority(
150  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
151  	   )
152  	{
153  	   assert(nlhdlr != NULL);
154  	
155  	   return nlhdlr->enfopriority;
156  	}
157  	
158  	/** returns whether nonlinear handler is enabled */
159  	SCIP_Bool SCIPnlhdlrIsEnabled(
160  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
161  	   )
162  	{
163  	   assert(nlhdlr != NULL);
164  	
165  	   return nlhdlr->enabled;
166  	}
167  	
168  	/** gives handler data of nonlinear handler */
169  	SCIP_NLHDLRDATA* SCIPnlhdlrGetData(
170  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
171  	   )
172  	{
173  	   assert(nlhdlr != NULL);
174  	
175  	   return nlhdlr->data;
176  	}
177  	
178  	/** returns whether nonlinear handler implements the interval evaluation callback */
179  	SCIP_Bool SCIPnlhdlrHasIntEval(
180  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
181  	   )
182  	{
183  	   return nlhdlr->inteval != NULL;
184  	}
185  	
186  	/** returns whether nonlinear handler implements the reverse propagation callback */
187  	SCIP_Bool SCIPnlhdlrHasReverseProp(
188  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
189  	   )
190  	{
191  	   return nlhdlr->reverseprop != NULL;
192  	}
193  	
194  	/** returns whether nonlinear handler implements the separation initialization callback */
195  	SCIP_Bool SCIPnlhdlrHasInitSepa(
196  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
197  	   )
198  	{
199  	   return nlhdlr->initsepa != NULL;
200  	}
201  	
202  	/** returns whether nonlinear handler implements the separation deinitialization callback */
203  	SCIP_Bool SCIPnlhdlrHasExitSepa(
204  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
205  	   )
206  	{
207  	   return nlhdlr->exitsepa != NULL;
208  	}
209  	
210  	/** returns whether nonlinear handler implements the enforcement callback */
211  	SCIP_Bool SCIPnlhdlrHasEnfo(
212  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
213  	   )
214  	{
215  	   return nlhdlr->enfo != NULL;
216  	}
217  	
218  	/** returns whether nonlinear handler implements the estimator callback */
219  	SCIP_Bool SCIPnlhdlrHasEstimate(
220  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
221  	   )
222  	{
223  	   return nlhdlr->estimate != NULL;
224  	}
225  	
226  	/** compares two nonlinear handlers by detection priority
227  	 *
228  	 * if handlers have same detection priority, then compare by name
229  	 */
230  	SCIP_DECL_SORTPTRCOMP(SCIPnlhdlrComp)
231  	{
232  	   SCIP_NLHDLR* h1;
233  	   SCIP_NLHDLR* h2;
234  	
235  	   assert(elem1 != NULL);
236  	   assert(elem2 != NULL);
237  	
238  	   h1 = (SCIP_NLHDLR*)elem1;
239  	   h2 = (SCIP_NLHDLR*)elem2;
240  	
241  	   if( h1->detectpriority != h2->detectpriority )
242  	      return h1->detectpriority - h2->detectpriority;
243  	
244  	   return strcmp(h1->name, h2->name);
245  	}
246  	
247  	#ifdef SCIP_DISABLED_CODE
248  	/** compares nonlinear handler by enforcement priority
249  	 *
250  	 * if handlers have same enforcement priority, then compare by detection priority, then by name
251  	 */
252  	SCIP_DECL_SORTPTRCOMP(SCIPnlhdlrCompEnfo)
253  	{
254  	   SCIP_NLHDLR* h1;
255  	   SCIP_NLHDLR* h2;
256  	
257  	   assert(elem1 != NULL);
258  	   assert(elem2 != NULL);
259  	
260  	   h1 = (SCIP_NLHDLR*)elem1;
261  	   h2 = (SCIP_NLHDLR*)elem2;
262  	
263  	   if( h1->enfopriority != h2->enfopriority )
264  	      return h1->enfopriority - h2->enfopriority;
265  	
266  	   if( h1->detectpriority != h2->detectpriority )
267  	      return h1->detectpriority - h2->detectpriority;
268  	
269  	   return strcmp(h1->name, h2->name);
270  	}
271  	#endif
272  	
273  	/** @} */
274  	
275  	/* nlhdlr private API functions from nlhdlr.h */
276  	
277  	/** creates a nonlinear handler */
278  	SCIP_RETCODE SCIPnlhdlrCreate(
279  	   SCIP*                 scip,               /**< SCIP data structure */
280  	   SCIP_NLHDLR**         nlhdlr,             /**< buffer to store pointer to created nonlinear handler */
281  	   const char*           name,               /**< name of nonlinear handler (must not be NULL) */
282  	   const char*           desc,               /**< description of nonlinear handler (can be NULL) */
283  	   int                   detectpriority,     /**< detection priority of nonlinear handler */
284  	   int                   enfopriority,       /**< enforcement priority of nonlinear handler */
285  	   SCIP_DECL_NLHDLRDETECT((*detect)),        /**< structure detection callback of nonlinear handler */
286  	   SCIP_DECL_NLHDLREVALAUX((*evalaux)),      /**< auxiliary evaluation callback of nonlinear handler */
287  	   SCIP_NLHDLRDATA*      nlhdlrdata          /**< data of nonlinear handler (can be NULL) */
288  	   )
289  	{
290  	   char paramname[SCIP_MAXSTRLEN];
291  	
292  	   assert(scip != NULL);
293  	   assert(nlhdlr != NULL);
294  	   assert(name != NULL);
295  	   assert(detect != NULL);
296  	   assert(evalaux != NULL);
297  	
298  	   SCIP_CALL( SCIPallocClearMemory(scip, nlhdlr) );
299  	
300  	   SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*nlhdlr)->name, name, strlen(name)+1) );
301  	   if( desc != NULL )
302  	   {
303  	      SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*nlhdlr)->desc, desc, strlen(desc)+1) );
304  	   }
305  	
306  	   (*nlhdlr)->detectpriority = detectpriority;
307  	   (*nlhdlr)->enfopriority = enfopriority;
308  	   (*nlhdlr)->data = nlhdlrdata;
309  	   (*nlhdlr)->detect = detect;
310  	   (*nlhdlr)->evalaux = evalaux;
311  	
312  	   SCIP_CALL( SCIPcreateClock(scip, &(*nlhdlr)->detecttime) );
313  	   SCIP_CALL( SCIPcreateClock(scip, &(*nlhdlr)->enfotime) );
314  	   SCIP_CALL( SCIPcreateClock(scip, &(*nlhdlr)->proptime) );
315  	   SCIP_CALL( SCIPcreateClock(scip, &(*nlhdlr)->intevaltime) );
316  	
317  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "nlhdlr/%s/enabled", name);
318  	   SCIP_CALL( SCIPaddBoolParam(scip, paramname, "should this nonlinear handler be used",
319  	      &(*nlhdlr)->enabled, FALSE, TRUE, NULL, NULL) );
320  	
321  	   return SCIP_OKAY;
322  	}
323  	
324  	/** frees a nonlinear handler */
325  	SCIP_RETCODE SCIPnlhdlrFree(
326  	   SCIP*                 scip,               /**< SCIP data structure */
327  	   SCIP_NLHDLR**         nlhdlr              /**< pointer to nonlinear handler to be freed */
328  	   )
329  	{
330  	   assert(nlhdlr != NULL);
331  	   assert(*nlhdlr != NULL);
332  	
333  	   if( (*nlhdlr)->freehdlrdata != NULL )
334  	   {
335  	      SCIP_CALL( (*nlhdlr)->freehdlrdata(scip, *nlhdlr, &(*nlhdlr)->data) );
336  	   }
337  	
338  	   /* free clocks */
339  	   SCIP_CALL( SCIPfreeClock(scip, &(*nlhdlr)->detecttime) );
340  	   SCIP_CALL( SCIPfreeClock(scip, &(*nlhdlr)->enfotime) );
341  	   SCIP_CALL( SCIPfreeClock(scip, &(*nlhdlr)->proptime) );
342  	   SCIP_CALL( SCIPfreeClock(scip, &(*nlhdlr)->intevaltime) );
343  	
344  	   SCIPfreeMemory(scip, &(*nlhdlr)->name);
345  	   SCIPfreeMemoryNull(scip, &(*nlhdlr)->desc);
346  	
347  	   SCIPfreeMemory(scip, nlhdlr);
348  	
349  	   return SCIP_OKAY;
350  	}
351  	
352  	/** call the handler copy callback of a nonlinear handler */
353  	SCIP_DECL_NLHDLRCOPYHDLR(SCIPnlhdlrCopyhdlr)
354  	{
355  	   /* TODO for now just don't copy disabled nlhdlr, a clean way would probably be to first copy and disable then */
356  	   if( sourcenlhdlr->copyhdlr != NULL && sourcenlhdlr->enabled )
357  	   {
358  	      SCIP_CALL( sourcenlhdlr->copyhdlr(targetscip, targetconshdlr, sourceconshdlr, sourcenlhdlr) );
359  	   }
360  	
361  	   return SCIP_OKAY;
362  	}
363  	
364  	/** call the free expression specific data callback of a nonlinear handler */
365  	SCIP_DECL_NLHDLRFREEEXPRDATA(SCIPnlhdlrFreeexprdata)
366  	{
367  	   assert(nlhdlr != NULL);
368  	   assert(nlhdlrexprdata != NULL);
369  	   assert(*nlhdlrexprdata != NULL);
370  	
371  	   if( nlhdlr->freeexprdata != NULL )
372  	   {
373  	      SCIP_CALL( nlhdlr->freeexprdata(scip, nlhdlr, expr, nlhdlrexprdata) );
374  	      assert(*nlhdlrexprdata == NULL);
375  	   }
376  	
377  	   return SCIP_OKAY;
378  	}
379  	
380  	/** call the initialization callback of a nonlinear handler */
381  	SCIP_DECL_NLHDLRINIT(SCIPnlhdlrInit)
382  	{
383  	   assert(nlhdlr != NULL);
384  	
385  	   nlhdlr->nenfocalls = 0;
386  	   nlhdlr->nintevalcalls = 0;
387  	   nlhdlr->npropcalls = 0;
388  	   nlhdlr->nseparated = 0;
389  	   nlhdlr->ncutoffs = 0;
390  	   nlhdlr->ndomreds = 0;
391  	   nlhdlr->nbranchscores = 0;
392  	   nlhdlr->ndetections = 0;
393  	   nlhdlr->ndetectionslast = 0;
394  	
395  	   SCIP_CALL( SCIPresetClock(scip, nlhdlr->detecttime) );
396  	   SCIP_CALL( SCIPresetClock(scip, nlhdlr->enfotime) );
397  	   SCIP_CALL( SCIPresetClock(scip, nlhdlr->proptime) );
398  	   SCIP_CALL( SCIPresetClock(scip, nlhdlr->intevaltime) );
399  	
400  	   if( nlhdlr->init != NULL )
401  	   {
402  	      SCIP_CALL( nlhdlr->init(scip, nlhdlr) );
403  	   }
404  	
405  	   return SCIP_OKAY;
406  	}
407  	
408  	/** call the deinitialization callback of a nonlinear handler */
409  	SCIP_DECL_NLHDLREXIT(SCIPnlhdlrExit)
410  	{
411  	   assert(nlhdlr != NULL);
412  	
413  	   if( nlhdlr->exit != NULL )
414  	   {
415  	      SCIP_CALL( nlhdlr->exit(scip, nlhdlr) );
416  	   }
417  	
418  	   return SCIP_OKAY;
419  	}
420  	
421  	/** call the detect callback of a nonlinear handler */
422  	SCIP_DECL_NLHDLRDETECT(SCIPnlhdlrDetect)
423  	{
424  	   assert(scip != NULL);
425  	   assert(nlhdlr != NULL);
426  	   assert(nlhdlr->detect != NULL);
427  	   assert(nlhdlr->detecttime != NULL);
428  	   assert(participating != NULL);
429  	
(1) Event cond_false: Condition "(_restat_ = SCIPstartClock(scip, nlhdlr->detecttime)) != SCIP_OKAY", taking false branch.
(2) Event if_end: End of if statement.
430  	   SCIP_CALL( SCIPstartClock(scip, nlhdlr->detecttime) );
(3) Event deref_parm_in_call: Function "*nlhdlr->detect" dereferences "*nlhdlrexprdata". (The function pointer resolves to "nlhdlrDetectQuotient".) [details]
431  	   SCIP_CALL( nlhdlr->detect(scip, conshdlr, nlhdlr, expr, cons, enforcing, participating, nlhdlrexprdata) );
432  	   SCIP_CALL( SCIPstopClock(scip, nlhdlr->detecttime) );
433  	
434  	   if( *participating != SCIP_NLHDLR_METHOD_NONE )
435  	   {
436  	      ++nlhdlr->ndetections;
437  	      ++nlhdlr->ndetectionslast;
438  	   }
439  	
440  	   return SCIP_OKAY;
441  	}
442  	
443  	/** call the auxiliary evaluation callback of a nonlinear handler */
444  	SCIP_DECL_NLHDLREVALAUX(SCIPnlhdlrEvalaux)
445  	{
446  	   assert(nlhdlr != NULL);
447  	   assert(nlhdlr->evalaux != NULL);
448  	
449  	   SCIP_CALL( nlhdlr->evalaux(scip, nlhdlr, expr, nlhdlrexprdata, auxvalue, sol) );
450  	
451  	   return SCIP_OKAY;
452  	}
453  	
454  	/** call the interval evaluation callback of a nonlinear handler */
455  	SCIP_DECL_NLHDLRINTEVAL(SCIPnlhdlrInteval)
456  	{
457  	   assert(scip != NULL);
458  	   assert(nlhdlr != NULL);
459  	   assert(nlhdlr->intevaltime != NULL);
460  	
461  	   if( nlhdlr->inteval != NULL )
462  	   {
463  	      SCIP_CALL( SCIPstartClock(scip, nlhdlr->intevaltime) );
464  	      SCIP_CALL( nlhdlr->inteval(scip, nlhdlr, expr, nlhdlrexprdata, interval, intevalvar, intevalvardata) );
465  	      SCIP_CALL( SCIPstopClock(scip, nlhdlr->intevaltime) );
466  	
467  	      ++nlhdlr->nintevalcalls;
468  	   }
469  	
470  	   return SCIP_OKAY;
471  	}
472  	
473  	/** call the reverse propagation callback of a nonlinear handler */
474  	SCIP_DECL_NLHDLRREVERSEPROP(SCIPnlhdlrReverseprop)
475  	{
476  	   assert(scip != NULL);
477  	   assert(nlhdlr != NULL);
478  	   assert(nlhdlr->proptime != NULL);
479  	   assert(infeasible != NULL);
480  	   assert(nreductions != NULL);
481  	
482  	   if( nlhdlr->reverseprop == NULL )
483  	   {
484  	      *infeasible = FALSE;
485  	      *nreductions = 0;
486  	
487  	      return SCIP_OKAY;
488  	   }
489  	
490  	   SCIP_CALL( SCIPstartClock(scip, nlhdlr->proptime) );
491  	   SCIP_CALL( nlhdlr->reverseprop(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, bounds, infeasible, nreductions) );
492  	   SCIP_CALL( SCIPstopClock(scip, nlhdlr->proptime) );
493  	
494  	   /* update statistics */
495  	   nlhdlr->ndomreds += *nreductions;
496  	   if( *infeasible )
497  	      ++nlhdlr->ncutoffs;
498  	   ++nlhdlr->npropcalls;
499  	
500  	   return SCIP_OKAY;
501  	}
502  	
503  	/** call the separation initialization callback of a nonlinear handler */
504  	SCIP_DECL_NLHDLRINITSEPA(SCIPnlhdlrInitsepa)
505  	{
506  	   assert(scip != NULL);
507  	   assert(nlhdlr != NULL);
508  	   assert(nlhdlr->enfotime != NULL);
509  	   assert(infeasible != NULL);
510  	
511  	   if( nlhdlr->initsepa == NULL )
512  	   {
513  	      *infeasible = FALSE;
514  	      return SCIP_OKAY;
515  	   }
516  	
517  	   SCIP_CALL( SCIPstartClock(scip, nlhdlr->enfotime) );
518  	   SCIP_CALL( nlhdlr->initsepa(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, overestimate, underestimate, infeasible) );
519  	   SCIP_CALL( SCIPstopClock(scip, nlhdlr->enfotime) );
520  	
521  	   ++nlhdlr->nenfocalls;
522  	   if( *infeasible )
523  	      ++nlhdlr->ncutoffs;
524  	
525  	   return SCIP_OKAY;
526  	}
527  	
528  	/** call the separation deinitialization callback of a nonlinear handler */
529  	SCIP_DECL_NLHDLREXITSEPA(SCIPnlhdlrExitsepa)
530  	{
531  	   assert(scip != NULL);
532  	   assert(nlhdlr != NULL);
533  	   assert(nlhdlr->enfotime != NULL);
534  	
535  	   if( nlhdlr->exitsepa != NULL )
536  	   {
537  	      SCIP_CALL( SCIPstartClock(scip, nlhdlr->enfotime) );
538  	      SCIP_CALL( nlhdlr->exitsepa(scip, nlhdlr, expr, nlhdlrexprdata) );
539  	      SCIP_CALL( SCIPstopClock(scip, nlhdlr->enfotime) );
540  	   }
541  	
542  	   return SCIP_OKAY;
543  	}
544  	
545  	/** call the enforcement callback of a nonlinear handler */
546  	SCIP_DECL_NLHDLRENFO(SCIPnlhdlrEnfo)
547  	{
548  	   assert(scip != NULL);
549  	   assert(nlhdlr != NULL);
550  	   assert(nlhdlr->enfotime != NULL);
551  	   assert(result != NULL);
552  	
553  	   if( nlhdlr->enfo == NULL )
554  	   {
555  	      *result = SCIP_DIDNOTRUN;
556  	      return SCIP_OKAY;
557  	   }
558  	
559  	#ifndef NDEBUG
560  	   /* check that auxvalue is correct by reevaluating */
561  	   {
562  	      SCIP_Real auxvaluetest;
563  	      SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, nlhdlrexprdata, &auxvaluetest, sol) );
564  	      /* we should get EXACTLY the same value from calling evalaux with the same solution as before */
565  	      assert(auxvalue == auxvaluetest);  /*lint !e777*/
566  	   }
567  	#endif
568  	
569  	   SCIP_CALL( SCIPstartClock(scip, nlhdlr->enfotime) );
570  	   SCIP_CALL( nlhdlr->enfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue,
571  	         overestimate, allowweakcuts, separated, addbranchscores, result) );
572  	   SCIP_CALL( SCIPstopClock(scip, nlhdlr->enfotime) );
573  	
574  	   /* update statistics */
575  	   ++nlhdlr->nenfocalls;
576  	   switch( *result )
577  	   {
578  	      case SCIP_SEPARATED :
579  	         ++nlhdlr->nseparated;
580  	         break;
581  	      case SCIP_BRANCHED:
582  	         ++nlhdlr->nbranchscores;
583  	         break;
584  	      case SCIP_CUTOFF:
585  	         ++nlhdlr->ncutoffs;
586  	         break;
587  	      case SCIP_REDUCEDDOM:
588  	         ++nlhdlr->ndomreds;
589  	         break;
590  	      default: ;
591  	   }  /*lint !e788*/
592  	
593  	   return SCIP_OKAY;
594  	}
595  	
596  	/** call the estimator callback of a nonlinear handler */
597  	SCIP_DECL_NLHDLRESTIMATE(SCIPnlhdlrEstimate)
598  	{
599  	   assert(scip != NULL);
600  	   assert(nlhdlr != NULL);
601  	   assert(nlhdlr->enfotime != NULL);
602  	   assert(success != NULL);
603  	   assert(addedbranchscores != NULL);
604  	
605  	   if( nlhdlr->estimate == NULL )
606  	   {
607  	      *success = FALSE;
608  	      *addedbranchscores = FALSE;
609  	      return SCIP_OKAY;
610  	   }
611  	
612  	#ifndef NDEBUG
613  	   /* check that auxvalue is correct by reevaluating */
614  	   {
615  	      SCIP_Real auxvaluetest;
616  	      SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, nlhdlrexprdata, &auxvaluetest, sol) );
617  	      /* we should get EXACTLY the same value from calling evalaux with the same solution as before */
618  	      assert(auxvalue == auxvaluetest);  /*lint !e777*/
619  	   }
620  	#endif
621  	
622  	   SCIP_CALL( SCIPstartClock(scip, nlhdlr->enfotime) );
623  	   SCIP_CALL( nlhdlr->estimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate, targetvalue, addbranchscores, rowpreps, success, addedbranchscores) );
624  	   SCIP_CALL( SCIPstopClock(scip, nlhdlr->enfotime) );
625  	
626  	   /* update statistics */
627  	   ++nlhdlr->nenfocalls;
628  	
629  	   return SCIP_OKAY;
630  	}
631  	
632  	/** reset number of detections counter for last round */
633  	void SCIPnlhdlrResetNDetectionslast(
634  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
635  	   )
636  	{
637  	   assert(nlhdlr != NULL);
638  	   nlhdlr->ndetectionslast = 0;
639  	}
640  	
641  	/** increments number of cutoffs in statistics */
642  	void SCIPnlhdlrIncrementNCutoffs(
643  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
644  	   )
645  	{
646  	   assert(nlhdlr != NULL);
647  	   ++nlhdlr->ncutoffs;
648  	}
649  	
650  	/** increments number of separations in statistics */
651  	void SCIPnlhdlrIncrementNSeparated(
652  	   SCIP_NLHDLR*          nlhdlr              /**< nonlinear handler */
653  	   )
654  	{
655  	   assert(nlhdlr != NULL);
656  	   ++nlhdlr->nseparated;
657  	}
658  	
659  	/** print statistics for nonlinear handlers */
660  	void SCIPnlhdlrPrintStatistics(
661  	   SCIP*                 scip,               /**< SCIP data structure */
662  	   SCIP_NLHDLR**         nlhdlrs,            /**< nonlinear handlers */
663  	   int                   nnlhdlrs,           /**< number of nonlinear handlers */
664  	   FILE*                 file                /**< file handle, or NULL for standard out */
665  	   )
666  	{
667  	   int i;
668  	
669  	   SCIPinfoMessage(scip, file, "Nlhdlrs            : %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n",
670  	      "Detects", "DetectAll", "DetectTime",
671  	      "#IntEval", "IntEvalTi",
672  	      "#RevProp", "RevPropTi", "DomReds", "Cutoffs",
673  	      "#Enforce", "EnfoTime", "Cuts", "Branching");
674  	
675  	   for( i = 0; i < nnlhdlrs; ++i )
676  	   {
677  	      /* skip disabled nlhdlr */
678  	      if( !nlhdlrs[i]->enabled )
679  	         continue;
680  	
681  	      SCIPinfoMessage(scip, file, "  %-17s:", nlhdlrs[i]->name);
682  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->ndetectionslast);
683  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->ndetections);
684  	      SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, nlhdlrs[i]->detecttime));
685  	
686  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->nintevalcalls);
687  	      SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, nlhdlrs[i]->intevaltime));
688  	
689  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->npropcalls);
690  	      SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, nlhdlrs[i]->proptime));
691  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->ndomreds);
692  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->ncutoffs);
693  	
694  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->nenfocalls);
695  	      SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, nlhdlrs[i]->enfotime));
696  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->nseparated);
697  	      SCIPinfoMessage(scip, file, " %10lld", nlhdlrs[i]->nbranchscores);
698  	
699  	      SCIPinfoMessage(scip, file, "\n");
700  	   }
701  	}
702