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