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   benderscut.c
26   	 * @ingroup OTHER_CFILES
27   	 * @brief  methods for Benders' decomposition cut
28   	 * @author Stephen J. Maher
29   	 */
30   	
31   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32   	
33   	#include <assert.h>
34   	#include <string.h>
35   	
36   	#include "scip/def.h"
37   	#include "scip/set.h"
38   	#include "scip/clock.h"
39   	#include "scip/paramset.h"
40   	#include "scip/scip.h"
41   	#include "scip/benderscut.h"
42   	#include "scip/reopt.h"
43   	#include "scip/pub_message.h"
44   	#include "scip/pub_misc.h"
45   	#include "scip/pub_benders.h"
46   	
47   	#include "scip/struct_benderscut.h"
48   	
49   	/* default parameter settings for the Benders' decomposition cuts */
50   	#define SCIP_DEFAULT_ENABLED        TRUE
51   	
52   	/** compares two Benders' cuts w. r. to their delay positions and their priority */
53   	SCIP_DECL_SORTPTRCOMP(SCIPbenderscutComp)
54   	{  /*lint --e{715}*/
55   	   SCIP_BENDERSCUT* benderscut1 = (SCIP_BENDERSCUT*)elem1;
56   	   SCIP_BENDERSCUT* benderscut2 = (SCIP_BENDERSCUT*)elem2;
57   	
58   	   assert(benderscut1 != NULL);
59   	   assert(benderscut2 != NULL);
60   	
61   	   return benderscut2->priority - benderscut1->priority; /* prefer higher priorities */
62   	}
63   	
64   	/** comparison method for sorting Benders' cuts w.r.t. to their name */
65   	SCIP_DECL_SORTPTRCOMP(SCIPbenderscutCompName)
66   	{
67   	   return strcmp(SCIPbenderscutGetName((SCIP_BENDERSCUT*)elem1), SCIPbenderscutGetName((SCIP_BENDERSCUT*)elem2));
68   	}
69   	
70   	/** method to call, when the priority of a compression was changed */
71   	static
72   	SCIP_DECL_PARAMCHGD(paramChgdBenderscutPriority)
73   	{  /*lint --e{715}*/
74   	   SCIP_PARAMDATA* paramdata;
75   	
76   	   paramdata = SCIPparamGetData(param);
77   	   assert(paramdata != NULL);
78   	
79   	   /* use SCIPsetBenderscutPriority() to mark the compressions unsorted */
80   	   SCIP_CALL( SCIPsetBenderscutPriority(scip, (SCIP_BENDERSCUT*)paramdata, SCIPparamGetInt(param)) ); /*lint !e740*/
81   	
82   	   return SCIP_OKAY;
83   	}
84   	
85   	/** copies the given Benders' decomposition cut to a new scip */
86   	SCIP_RETCODE SCIPbenderscutCopyInclude(
87   	   SCIP_BENDERS*         benders,            /**< the Benders' decomposition that the cuts are copied to */
88   	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
89   	   SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
90   	   )
91   	{
92   	   assert(benderscut != NULL);
93   	   assert(set != NULL);
94   	   assert(set->scip != NULL);
95   	
96   	   if( benderscut->benderscutcopy != NULL )
97   	   {
98   	      SCIPsetDebugMsg(set, "including benderscut %s in subscip %p\n", SCIPbenderscutGetName(benderscut), (void*)set->scip);
99   	      SCIP_CALL( benderscut->benderscutcopy(set->scip, benders, benderscut) );
100  	   }
101  	
102  	   return SCIP_OKAY;
103  	}
104  	
105  	/** internal method for creating a Benders' decomposition structure */
106  	static
107  	SCIP_RETCODE doBenderscutCreate(
108  	   SCIP_BENDERS*         benders,            /**< Benders' decomposition */
109  	   SCIP_BENDERSCUT**     benderscut,         /**< pointer to the Benders' decomposition cut data structure */
110  	   SCIP_SET*             set,                /**< global SCIP settings */
111  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
112  	   BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
113  	   const char*           name,               /**< name of the Benders' decomposition cut */
114  	   const char*           desc,               /**< description of the Benders' decomposition cut */
115  	   int                   priority,           /**< priority of the the Benders' decomposition cut */
116  	   SCIP_Bool             islpcut,            /**< indicates whether the cut is generated from the LP solution */
117  	   SCIP_DECL_BENDERSCUTCOPY((*benderscutcopy)),/**< copy method of the Benders' decomposition cut or NULL if you don't want to copy your plugin into sub-SCIPs */
118  	   SCIP_DECL_BENDERSCUTFREE((*benderscutfree)),/**< destructor of the Benders' decomposition cut */
119  	   SCIP_DECL_BENDERSCUTINIT((*benderscutinit)),/**< initialize the Benders' decomposition cut */
120  	   SCIP_DECL_BENDERSCUTEXIT((*benderscutexit)),/**< deinitialize the Benders' decomposition cut */
121  	   SCIP_DECL_BENDERSCUTINITSOL((*benderscutinitsol)),/**< solving process initialization method of the Benders' decomposition cut */
122  	   SCIP_DECL_BENDERSCUTEXITSOL((*benderscutexitsol)),/**< solving process deinitialization method of the Benders' decomposition cut */
123  	   SCIP_DECL_BENDERSCUTEXEC((*benderscutexec)),/**< execution method of the Benders' decomposition cut */
124  	   SCIP_BENDERSCUTDATA*  benderscutdata      /**< Benders' decomposition cut data */
125  	   )
126  	{
127  	   char paramname[SCIP_MAXSTRLEN];
128  	   char paramdesc[SCIP_MAXSTRLEN];
129  	
130  	   assert(benderscut != NULL);
131  	   assert(name != NULL);
132  	   assert(desc != NULL);
133  	   assert(benderscutexec != NULL);
134  	
135  	   SCIP_ALLOC( BMSallocMemory(benderscut) );
136  	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*benderscut)->name, name, strlen(name)+1) );
137  	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*benderscut)->desc, desc, strlen(desc)+1) );
138  	   (*benderscut)->priority = priority;
139  	   (*benderscut)->islpcut = islpcut;
140  	   (*benderscut)->benderscutcopy = benderscutcopy;
141  	   (*benderscut)->benderscutfree = benderscutfree;
142  	   (*benderscut)->benderscutinit = benderscutinit;
143  	   (*benderscut)->benderscutexit = benderscutexit;
144  	   (*benderscut)->benderscutinitsol = benderscutinitsol;
145  	   (*benderscut)->benderscutexitsol = benderscutexitsol;
146  	   (*benderscut)->benderscutexec = benderscutexec;
147  	   (*benderscut)->benderscutdata = benderscutdata;
148  	   SCIP_CALL( SCIPclockCreate(&(*benderscut)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
149  	   SCIP_CALL( SCIPclockCreate(&(*benderscut)->benderscutclock, SCIP_CLOCKTYPE_DEFAULT) );
150  	   (*benderscut)->ncalls = 0;
151  	   (*benderscut)->nfound = 0;
152  	   (*benderscut)->initialized = FALSE;
153  	
154  	   /* add parameters */
155  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/priority", SCIPbendersGetName(benders), name);
156  	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of Benders' cut <%s>", name);
157  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
158  	                  &(*benderscut)->priority, TRUE, priority, INT_MIN/4, INT_MAX/4,
159  	                  paramChgdBenderscutPriority, (SCIP_PARAMDATA*)(*benderscut)) ); /*lint !e740*/
160  	
161  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/enabled", SCIPbendersGetName(benders), name);
162  	   SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
163  	        "is this Benders' decomposition cut method used to generate cuts?", &(*benderscut)->enabled, FALSE,
164  	        SCIP_DEFAULT_ENABLED, NULL, NULL) ); /*lint !e740*/
165  	
166  	   return SCIP_OKAY;
167  	}
168  	
169  	/** creates a Benders' decomposition cut */
170  	SCIP_RETCODE SCIPbenderscutCreate(
171  	   SCIP_BENDERS*         benders,            /**< Benders' decomposition */
172  	   SCIP_BENDERSCUT**     benderscut,         /**< pointer to the Benders' decomposition cut data structure */
173  	   SCIP_SET*             set,                /**< global SCIP settings */
174  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
175  	   BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
176  	   const char*           name,               /**< name of the Benders' decomposition cut */
177  	   const char*           desc,               /**< description of the Benders' decomposition cut */
178  	   int                   priority,           /**< priority of the the Benders' decomposition cut */
179  	   SCIP_Bool             islpcut,            /**< indicates whether the cut is generated from the LP solution */
180  	   SCIP_DECL_BENDERSCUTCOPY((*benderscutcopy)),/**< copy method of the Benders' decomposition cut or NULL if you don't want to copy your plugin into sub-SCIPs */
181  	   SCIP_DECL_BENDERSCUTFREE((*benderscutfree)),/**< destructor of the Benders' decomposition cut */
182  	   SCIP_DECL_BENDERSCUTINIT((*benderscutinit)),/**< initialize the Benders' decomposition cut */
183  	   SCIP_DECL_BENDERSCUTEXIT((*benderscutexit)),/**< deinitialize the Benders' decomposition cut */
184  	   SCIP_DECL_BENDERSCUTINITSOL((*benderscutinitsol)),/**< solving process initialization method of the Benders' decomposition cut */
185  	   SCIP_DECL_BENDERSCUTEXITSOL((*benderscutexitsol)),/**< solving process deinitialization method of the Benders' decomposition cut */
186  	   SCIP_DECL_BENDERSCUTEXEC((*benderscutexec)),/**< execution method of the Benders' decomposition cut */
187  	   SCIP_BENDERSCUTDATA*  benderscutdata      /**< Benders' decomposition cut data */
188  	   )
189  	{
190  	   assert(benderscut != NULL);
191  	   assert(name != NULL);
192  	   assert(desc != NULL);
193  	   assert(benderscutexec != NULL);
194  	
195  	   SCIP_CALL_FINALLY( doBenderscutCreate(benders, benderscut, set, messagehdlr, blkmem, name, desc, priority, islpcut,
196  	         benderscutcopy, benderscutfree, benderscutinit, benderscutexit, benderscutinitsol, benderscutexitsol,
197  	         benderscutexec, benderscutdata), (void)SCIPbenderscutFree(benderscut, set) );
198  	
199  	   return SCIP_OKAY;
200  	}
201  	
202  	/** calls destructor and frees memory of the Benders' decomposition cut */
203  	SCIP_RETCODE SCIPbenderscutFree(
204  	   SCIP_BENDERSCUT**     benderscut,         /**< pointer to the Benders' decomposition cut data structure */
205  	   SCIP_SET*             set                 /**< global SCIP settings */
206  	   )
207  	{
208  	   assert(benderscut != NULL);
209  	   assert(*benderscut != NULL);
210  	   assert(!(*benderscut)->initialized);
211  	   assert(set != NULL);
212  	
213  	   /* call destructor of the Benders' decomposition cut */
214  	   if( (*benderscut)->benderscutfree != NULL )
215  	   {
216  	      SCIP_CALL( (*benderscut)->benderscutfree(set->scip, *benderscut) );
217  	   }
218  	
219  	   SCIPclockFree(&(*benderscut)->benderscutclock);
220  	   SCIPclockFree(&(*benderscut)->setuptime);
221  	   BMSfreeMemoryArray(&(*benderscut)->name);
222  	   BMSfreeMemoryArray(&(*benderscut)->desc);
223  	   BMSfreeMemory(benderscut);
224  	
225  	   return SCIP_OKAY;
226  	}
227  	
228  	/** initializes the Benders' decomposition cut */
229  	SCIP_RETCODE SCIPbenderscutInit(
230  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
231  	   SCIP_SET*             set                 /**< global SCIP settings */
232  	   )
233  	{
234  	   assert(benderscut != NULL);
235  	   assert(set != NULL);
236  	
237  	   if( benderscut->initialized )
238  	   {
239  	      SCIPerrorMessage("Benders' decomposition cut <%s> already initialized\n", benderscut->name);
240  	      return SCIP_INVALIDCALL;
241  	   }
242  	
243  	   if( set->misc_resetstat )
244  	   {
245  	      SCIPclockReset(benderscut->setuptime);
246  	      SCIPclockReset(benderscut->benderscutclock);
247  	
248  	      benderscut->ncalls = 0;
249  	      benderscut->nfound = 0;
250  	   }
251  	
252  	   if( benderscut->benderscutinit != NULL )
253  	   {
254  	      /* start timing */
255  	      SCIPclockStart(benderscut->setuptime, set);
256  	
257  	      SCIP_CALL( benderscut->benderscutinit(set->scip, benderscut) );
258  	
259  	      /* stop timing */
260  	      SCIPclockStop(benderscut->setuptime, set);
261  	   }
262  	   benderscut->initialized = TRUE;
263  	
264  	   return SCIP_OKAY;
265  	}
266  	
267  	/** calls exit method of the Benders' decomposition cut */
268  	SCIP_RETCODE SCIPbenderscutExit(
269  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
270  	   SCIP_SET*             set                 /**< global SCIP settings */
271  	   )
272  	{
273  	   assert(benderscut != NULL);
274  	   assert(set != NULL);
275  	
276  	   if( !benderscut->initialized )
277  	   {
278  	      SCIPerrorMessage("Benders' decomposition cut <%s> not initialized\n", benderscut->name);
279  	      return SCIP_INVALIDCALL;
280  	   }
281  	
282  	   if( benderscut->benderscutexit != NULL )
283  	   {
284  	      /* start timing */
285  	      SCIPclockStart(benderscut->setuptime, set);
286  	
287  	      SCIP_CALL( benderscut->benderscutexit(set->scip, benderscut) );
288  	
289  	      /* stop timing */
290  	      SCIPclockStop(benderscut->setuptime, set);
291  	   }
292  	   benderscut->initialized = FALSE;
293  	
294  	   return SCIP_OKAY;
295  	}
296  	
297  	/** informs Benders' cut that the branch and bound process is being started */
298  	SCIP_RETCODE SCIPbenderscutInitsol(
299  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
300  	   SCIP_SET*             set                 /**< global SCIP settings */
301  	   )
302  	{
303  	   assert(benderscut != NULL);
304  	   assert(set != NULL);
305  	
306  	   /* call solving process initialization method of the Benders' decomposition cut */
307  	   if( benderscut->benderscutinitsol != NULL )
308  	   {
309  	      /* start timing */
310  	      SCIPclockStart(benderscut->setuptime, set);
311  	
312  	      SCIP_CALL( benderscut->benderscutinitsol(set->scip, benderscut) );
313  	
314  	      /* stop timing */
315  	      SCIPclockStop(benderscut->setuptime, set);
316  	   }
317  	
318  	   return SCIP_OKAY;
319  	}
320  	
321  	/** informs Benders' decomposition that the branch and bound process data is being freed */
322  	SCIP_RETCODE SCIPbenderscutExitsol(
323  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition */
324  	   SCIP_SET*             set                 /**< global SCIP settings */
325  	   )
326  	{
327  	   assert(benderscut != NULL);
328  	   assert(set != NULL);
329  	
330  	   /* call solving process deinitialization method of Benders' decomposition cut */
331  	   if( benderscut->benderscutexitsol != NULL )
332  	   {
333  	      /* start timing */
334  	      SCIPclockStart(benderscut->setuptime, set);
335  	
336  	      SCIP_CALL( benderscut->benderscutexitsol(set->scip, benderscut) );
337  	
338  	      /* stop timing */
339  	      SCIPclockStop(benderscut->setuptime, set);
340  	   }
341  	
342  	   return SCIP_OKAY;
343  	}
344  	
345  	/** calls execution method of the Benders' decomposition cut */
346  	SCIP_RETCODE SCIPbenderscutExec(
347  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
348  	   SCIP_SET*             set,                /**< global SCIP settings */
349  	   SCIP_BENDERS*         benders,            /**< Benders' decomposition */
350  	   SCIP_SOL*             sol,                /**< primal CIP solution */
351  	   int                   probnumber,         /**< the number of the subproblem for which the cut is generated */
352  	   SCIP_BENDERSENFOTYPE  type,               /**< the enforcement type calling this function */
353  	   SCIP_RESULT*          result              /**< pointer to store the result of the callback method */
354  	   )
355  	{
356  	   SCIP_RESULT cutresult;
357  	
358  	   assert(benderscut != NULL);
359  	   assert(benderscut->benderscutexec != NULL);
360  	   assert(set != NULL);
361  	   assert(set->scip != NULL);
362  	   assert(result != NULL);
363  	
364  	   cutresult = SCIP_DIDNOTRUN;
365  	
366  	   SCIPsetDebugMsg(set, "executing Benders' decomposition cut <%s>\n", benderscut->name);
367  	
368  	   /* start timing */
369  	   SCIPclockStart(benderscut->benderscutclock, set);
370  	
371  	   /* call the Benders' decomposition cut if it is enabled */
372  	   if( benderscut->enabled )
373  	   {
374  	      SCIP_CALL( benderscut->benderscutexec(set->scip, benders, benderscut, sol, probnumber, type, &cutresult) );
375  	   }
376  	
377  	   /* stop timing */
378  	   SCIPclockStop(benderscut->benderscutclock, set);
379  	
380  	   /* evaluate result */
381  	   if( cutresult != SCIP_DIDNOTRUN
382  	      && cutresult != SCIP_DIDNOTFIND
383  	      && cutresult != SCIP_CONSADDED
384  	      && cutresult != SCIP_FEASIBLE
385  	      && cutresult != SCIP_SEPARATED )
386  	   {
387  	      SCIPerrorMessage("execution method of Benders' decomposition cut <%s> returned invalid result <%d>\n",
388  	         benderscut->name, cutresult);
389  	      return SCIP_INVALIDRESULT;
390  	   }
391  	
392  	   benderscut->ncalls++;
393  	
394  	   if( cutresult == SCIP_CONSADDED || cutresult == SCIP_SEPARATED )
395  	      benderscut->nfound++;
396  	
397  	   (*result) = cutresult;
398  	
399  	   return SCIP_OKAY;
400  	}
401  	
402  	/** gets user data of the Benders' decomposition cut */
403  	SCIP_BENDERSCUTDATA* SCIPbenderscutGetData(
404  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
405  	   )
406  	{
407  	   assert(benderscut != NULL);
408  	
409  	   return benderscut->benderscutdata;
410  	}
411  	
412  	/** sets user data of the Benders' decomposition cut; user has to free old data in advance! */
413  	void SCIPbenderscutSetData(
414  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
415  	   SCIP_BENDERSCUTDATA*  benderscutdata      /**< new Benders' decomposition cut user data */
416  	   )
417  	{
418  	   assert(benderscut != NULL);
419  	
420  	   benderscut->benderscutdata = benderscutdata;
421  	}
422  	
423  	/* new callback setter methods */
424  	
425  	/** sets copy callback of the Benders' decomposition cut */
426  	void SCIPbenderscutSetCopy(
427  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
428  	   SCIP_DECL_BENDERSCUTCOPY((*benderscutcopy))/**< copy callback of the Benders' decomposition cut or NULL if you don't want to copy your plugin into sub-SCIPs */
429  	   )
430  	{
431  	   assert(benderscut != NULL);
432  	
433  	   benderscut->benderscutcopy = benderscutcopy;
434  	}
435  	
436  	/** sets destructor callback of the Benders' decomposition cut */
437  	void SCIPbenderscutSetFree(
438  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
439  	   SCIP_DECL_BENDERSCUTFREE((*benderscutfree))/**< destructor of the Benders' decomposition cut */
440  	   )
441  	{
442  	   assert(benderscut != NULL);
443  	
444  	   benderscut->benderscutfree = benderscutfree;
445  	}
446  	
447  	/** sets initialization callback of the Benders' decomposition cut */
448  	void SCIPbenderscutSetInit(
449  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
450  	   SCIP_DECL_BENDERSCUTINIT((*benderscutinit))/**< initialize the Benders' decomposition cut */
451  	   )
452  	{
453  	   assert(benderscut != NULL);
454  	
455  	   benderscut->benderscutinit = benderscutinit;
456  	}
457  	
458  	/** sets deinitialization callback of the Benders' decomposition cut */
459  	void SCIPbenderscutSetExit(
460  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
461  	   SCIP_DECL_BENDERSCUTEXIT((*benderscutexit))/**< deinitialize the Benders' decomposition cut */
462  	   )
463  	{
464  	   assert(benderscut != NULL);
465  	
466  	   benderscut->benderscutexit = benderscutexit;
467  	}
468  	
469  	/** sets solving process initialization callback of the Benders' decomposition cut */
470  	void SCIPbenderscutSetInitsol(
471  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
472  	   SCIP_DECL_BENDERSCUTINITSOL((*benderscutinitsol))/**< solving process initialization callback of the Benders' decomposition cut */
473  	   )
474  	{
475  	   assert(benderscut != NULL);
476  	
477  	   benderscut->benderscutinitsol = benderscutinitsol;
478  	}
479  	
480  	/** sets solving process deinitialization callback of Benders' decomposition cut */
481  	void SCIPbenderscutSetExitsol(
482  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
483  	   SCIP_DECL_BENDERSCUTEXITSOL((*benderscutexitsol))/**< solving process deinitialization callback of the Benders' decomposition cut */
484  	   )
485  	{
486  	   assert(benderscut != NULL);
487  	
488  	   benderscut->benderscutexitsol = benderscutexitsol;
489  	}
490  	
491  	/** gets name of the Benders' decomposition cut */
492  	const char* SCIPbenderscutGetName(
493  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
494  	   )
495  	{
496  	   assert(benderscut != NULL);
497  	
498  	   return benderscut->name;
499  	}
500  	
501  	/** gets description of the Benders' decomposition cut */
502  	const char* SCIPbenderscutGetDesc(
503  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
504  	   )
505  	{
506  	   assert(benderscut != NULL);
507  	
508  	   return benderscut->desc;
509  	}
510  	
511  	/** gets priority of the Benders' decomposition cut */
512  	int SCIPbenderscutGetPriority(
513  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
514  	   )
515  	{
516  	   assert(benderscut != NULL);
517  	
518  	   return benderscut->priority;
519  	}
520  	
521  	/** sets priority of the Benders' decomposition cut */
522  	void SCIPbenderscutSetPriority(
523  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
524  	   int                   priority            /**< new priority of the Benders' decomposition cut */
525  	   )
526  	{
527  	   assert(benderscut != NULL);
528  	
529  	   benderscut->priority = priority;
530  	}
531  	
532  	/** gets the number of times, the heuristic was called and tried to find a solution */
533  	SCIP_Longint SCIPbenderscutGetNCalls(
534  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
535  	   )
536  	{
537  	   assert(benderscut != NULL);
538  	
539  	   return benderscut->ncalls;
540  	}
541  	
542  	/** gets the number of Benders' cuts found by this Benders' decomposition cut */
543  	SCIP_Longint SCIPbenderscutGetNFound(
544  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
545  	   )
546  	{
547  	   assert(benderscut != NULL);
548  	
549  	   return benderscut->nfound;
550  	}
551  	
552  	/** is the Benders' decomposition cut initialized? */
553  	SCIP_Bool SCIPbenderscutIsInitialized(
554  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
555  	   )
556  	{
557  	   assert(benderscut != NULL);
558  	
559  	   return benderscut->initialized;
560  	}
561  	
562  	/** gets time in seconds used by this Benders' decomposition cut for setting up */
563  	SCIP_Real SCIPbenderscutGetSetupTime(
564  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
565  	   )
566  	{
567  	   assert(benderscut != NULL);
568  	
569  	   return SCIPclockGetTime(benderscut->setuptime);
570  	}
571  	
572  	/** gets time in seconds used in this Benders' decomposition cut */
573  	SCIP_Real SCIPbenderscutGetTime(
574  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
575  	   )
576  	{
577  	   assert(benderscut != NULL);
578  	
579  	   return SCIPclockGetTime(benderscut->benderscutclock);
580  	}
581  	
582  	/** returns whether the Benders' cut uses the LP information */
583  	SCIP_Bool SCIPbenderscutIsLPCut(
584  	   SCIP_BENDERSCUT*      benderscut          /**< Benders' decomposition cut */
585  	   )
586  	{
587  	   assert(benderscut != NULL);
588  	
589  	   return benderscut->islpcut;
590  	}
591  	
592  	/** sets the enabled flag of the Benders' decomposition cut method */
593  	void SCIPbenderscutSetEnabled(
594  	   SCIP_BENDERSCUT*      benderscut,         /**< Benders' decomposition cut */
595  	   SCIP_Bool             enabled             /**< flag to indicate whether the Benders' decomposition cut is enabled */
596  	   )
597  	{
598  	   assert(benderscut != NULL);
599  	
600  	   benderscut->enabled = enabled;
601  	}
602