1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SCIP is distributed under the terms of the ZIB Academic License.         */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   heur.c
17   	 * @ingroup OTHER_CFILES
18   	 * @brief  methods for primal heuristics
19   	 * @author Tobias Achterberg
20   	 * @author Timo Berthold
21   	 */
22   	
23   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24   	
25   	#include <assert.h>
26   	#include <string.h>
27   	
28   	#include "scip/def.h"
29   	#include "scip/set.h"
30   	#include "scip/clock.h"
31   	#include "scip/paramset.h"
32   	#include "scip/primal.h"
33   	#include "scip/scip.h"
34   	#include "scip/heur.h"
35   	#include "scip/pub_message.h"
36   	#include "scip/pub_misc.h"
37   	#include "scip/misc.h"
38   	
39   	#include "scip/struct_heur.h"
40   	
41   	/** compares two heuristics w.r.t. to their delay positions and priorities */
42   	SCIP_DECL_SORTPTRCOMP(SCIPheurComp)
43   	{  /*lint --e{715}*/
44   	   SCIP_HEUR* heur1 = (SCIP_HEUR*)elem1;
45   	   SCIP_HEUR* heur2 = (SCIP_HEUR*)elem2;
46   	
47   	   assert(heur1 != NULL);
48   	   assert(heur2 != NULL);
49   	
50   	   if( heur1->delaypos == heur2->delaypos )
51   	      if( heur1->priority != heur2->priority )
52   	         return heur2->priority - heur1->priority; /* prefer higher priorities */
53   	      else
54   	         return (strcmp(heur1->name, heur2->name)); /* tiebreaker */
55   	   else if( heur1->delaypos == -1 )
56   	      return +1;                                /* prefer delayed heuristics */
57   	   else if( heur2->delaypos == -1 )
58   	      return -1;                                /* prefer delayed heuristics */
59   	   else if( heur1->ncalls * heur1->freq > heur2->ncalls * heur2->freq )
60   	      return +1;
61   	   else if( heur1->ncalls * heur1->freq < heur2->ncalls * heur2->freq )
62   	      return -1;
63   	   else
64   	      return heur1->delaypos - heur2->delaypos; /* prefer lower delay positions */
65   	}
66   	
67   	/** compares two heuristics w.r.t. to their priority values */
68   	SCIP_DECL_SORTPTRCOMP(SCIPheurCompPriority)
69   	{
70   	   return SCIPheurGetPriority((SCIP_HEUR*)elem2) -
71   	     SCIPheurGetPriority((SCIP_HEUR*)elem1);
72   	}
73   	
74   	/** comparison method for sorting heuristics w.r.t. to their name */
75   	SCIP_DECL_SORTPTRCOMP(SCIPheurCompName)
76   	{
77   	   return strcmp(SCIPheurGetName((SCIP_HEUR*)elem1), SCIPheurGetName((SCIP_HEUR*)elem2));
78   	}
79   	
80   	/** method to call, when the priority of a heuristic was changed */
81   	static
82   	SCIP_DECL_PARAMCHGD(paramChgdHeurPriority)
83   	{  /*lint --e{715}*/
84   	   SCIP_PARAMDATA* paramdata;
85   	
86   	   paramdata = SCIPparamGetData(param);
87   	   assert(paramdata != NULL);
88   	
89   	   /* use SCIPsetHeurPriority() to mark the heuristics unsorted */
90   	   SCIP_CALL( SCIPsetHeurPriority(scip, (SCIP_HEUR*)paramdata, SCIPparamGetInt(param)) ); /*lint !e740*/
91   	
92   	   return SCIP_OKAY;
93   	}
94   	
95   	/** resets diving statistics */
96   	static
97   	void resetDivesetStats(
98   	   SCIP_DIVESETSTATS*    divesetstats        /**< dive set statistics */
99   	   )
100  	{
101  	   assert(divesetstats != NULL);
102  	
103  	   divesetstats->nlpiterations = 0L;
104  	   divesetstats->totaldepth = 0L;
105  	   divesetstats->totalsoldepth = 0L;
106  	   divesetstats->totalnnodes = 0L;
107  	   divesetstats->totalnbacktracks = 0L;
108  	   divesetstats->minsoldepth = INT_MAX;
109  	   divesetstats->maxsoldepth = -1;
110  	   divesetstats->mindepth = INT_MAX;
111  	   divesetstats->maxdepth = -1;
112  	   divesetstats->nlps = 0;
113  	   divesetstats->nsolsfound = 0;
114  	   divesetstats->nbestsolsfound = 0;
115  	   divesetstats->nconflictsfound = 0;
116  	   divesetstats->ncalls = 0;
117  	   divesetstats->nsolcalls = 0;
118  	}
119  	
120  	/* resets diving settings counters */
121  	SCIP_RETCODE SCIPdivesetReset(
122  	   SCIP_DIVESET*         diveset,            /**< diveset to be reset */
123  	   SCIP_SET*             set                 /**< global SCIP settings */
124  	   )
125  	{
126  	   int d;
127  	
128  	   assert(diveset != NULL);
129  	   assert(diveset->randnumgen != NULL);
130  	
131  	   /* reset diveset statistics for all contexts */
132  	   for( d = 0; d < 3; ++d )
133  	   {
134  	      resetDivesetStats(diveset->divesetstats[d]);
135  	   }
136  	
137  	   /* reset the random number generator */
138  	   SCIPrandomSetSeed(diveset->randnumgen, (unsigned int) SCIPsetInitializeRandomSeed(set, diveset->initialseed));
139  	
140  	   return SCIP_OKAY;
141  	}
142  	
143  	/** update dive set statistics */
144  	static
145  	void updateDivesetstats(
146  	   SCIP_DIVESETSTATS*    divesetstats,       /**< dive set statistics */
147  	   int                   depth,              /**< the depth reached this time */
148  	   int                   nprobingnodes,      /**< the number of probing nodes explored this time */
149  	   int                   nbacktracks,        /**< the number of backtracks during probing this time */
150  	   SCIP_Longint          nsolsfound,         /**< number of new solutions found this time */
151  	   SCIP_Longint          nbestsolsfound,     /**< number of new best solutions found this time */
152  	   SCIP_Longint          nconflictsfound,    /**< number of new conflicts found this time */
153  	   SCIP_Bool             leavesol            /**< has the diving heuristic reached a feasible leaf */
154  	   )
155  	{
156  	   divesetstats->totaldepth += depth;
157  	   divesetstats->mindepth = MIN(divesetstats->mindepth, depth);
158  	   divesetstats->maxdepth = MAX(divesetstats->maxdepth, depth);
159  	   divesetstats->totalnnodes += nprobingnodes;
160  	   divesetstats->totalnbacktracks += nbacktracks;
161  	   divesetstats->ncalls++;
162  	
163  	   /* update solution statistics only if a solution was found */
164  	   if( leavesol )
165  	   {
166  	      divesetstats->totalsoldepth += depth;
167  	      divesetstats->minsoldepth = MIN(divesetstats->minsoldepth, depth);
168  	      divesetstats->maxsoldepth = MAX(divesetstats->maxsoldepth, depth);
169  	      divesetstats->nsolcalls++;
170  	   }
171  	
172  	   divesetstats->nsolsfound += nsolsfound;
173  	   divesetstats->nbestsolsfound += nbestsolsfound;
174  	   divesetstats->nconflictsfound += nconflictsfound;
175  	}
176  	
177  	/** returns the dive set statistics for the given context */
178  	static
179  	SCIP_DIVESETSTATS* divesetGetStats(
180  	   SCIP_DIVESET*         diveset,            /**< diveset to be reset */
181  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
182  	   )
183  	{
184  	   assert(diveset != NULL);
185  	   assert(divecontext == SCIP_DIVECONTEXT_ADAPTIVE ||
186  	         divecontext == SCIP_DIVECONTEXT_SINGLE ||
187  	         divecontext == SCIP_DIVECONTEXT_TOTAL);
188  	
189  	   return diveset->divesetstats[(int)divecontext];
190  	}
191  	
192  	/** update diveset statistics and global diveset statistics */
193  	void SCIPdivesetUpdateStats(
194  	   SCIP_DIVESET*         diveset,            /**< diveset to be reset */
195  	   SCIP_STAT*            stat,               /**< global SCIP statistics */
196  	   int                   depth,              /**< the depth reached this time */
197  	   int                   nprobingnodes,      /**< the number of probing nodes explored this time */
198  	   int                   nbacktracks,        /**< the number of backtracks during probing this time */
199  	   SCIP_Longint          nsolsfound,         /**< number of new solutions found this time */
200  	   SCIP_Longint          nbestsolsfound,     /**< number of new best solutions found this time */
201  	   SCIP_Longint          nconflictsfound,    /**< number of new conflicts found this time */
202  	   SCIP_Bool             leavesol,           /**< has the diving heuristic reached a feasible leaf */
203  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
204  	   )
205  	{
206  	   int c;
207  	   SCIP_DIVECONTEXT updatecontexts[] = {SCIP_DIVECONTEXT_TOTAL, divecontext};
208  	
209  	   assert(diveset != NULL);
210  	   assert(divecontext == SCIP_DIVECONTEXT_ADAPTIVE || divecontext == SCIP_DIVECONTEXT_SINGLE);
211  	
212  	   /* update statistics for total context and given context */
213  	   for( c = 0; c < 2; ++c )
214  	   {
215  	      updateDivesetstats(divesetGetStats(diveset, updatecontexts[c]), depth, nprobingnodes,
216  	            nbacktracks, nsolsfound, nbestsolsfound, nconflictsfound, leavesol);
217  	   }
218  	
219  	   stat->totaldivesetdepth += depth;
220  	   stat->ndivesetcalls++;
221  	}
222  	
223  	/** append diveset to heuristic array of divesets */
224  	static
225  	SCIP_RETCODE heurAddDiveset(
226  	   SCIP_HEUR*            heur,               /**< the heuristic to which this dive setting belongs */
227  	   SCIP_DIVESET*         diveset             /**< pointer to the freshly created diveset */
228  	   )
229  	{
230  	   assert(heur != NULL);
231  	   assert(diveset != NULL);
232  	   assert(diveset->heur == NULL);
233  	
234  	   diveset->heur = heur;
235  	
236  	   if( heur->divesets == NULL )
237  	   {
238  	      assert(heur->ndivesets == 0);
239  	      SCIP_ALLOC( BMSallocMemoryArray(&heur->divesets, 1) );
240  	   }
241  	   else
242  	   {
243  	      assert(heur->ndivesets > 0);
244  	      SCIP_ALLOC( BMSreallocMemoryArray(&heur->divesets, heur->ndivesets + 1) ); /*lint !e776 I expect no overflow here */
245  	   }
246  	
247  	   /* append diveset to the end of the array */
248  	   heur->divesets[heur->ndivesets] = diveset;
249  	   heur->ndivesets++;
250  	
251  	   return SCIP_OKAY;
252  	}
253  	
254  	/** create a set of diving heuristic settings */
255  	SCIP_RETCODE SCIPdivesetCreate(
256  	   SCIP_DIVESET**        divesetptr,         /**< pointer to the freshly created diveset */
257  	   SCIP_HEUR*            heur,               /**< the heuristic to which this dive setting belongs */
258  	   const char*           name,               /**< name for the diveset, or NULL if the name of the heuristic should be used */
259  	   SCIP_SET*             set,                /**< global SCIP settings */
260  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
261  	   BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
262  	   SCIP_Real             minreldepth,        /**< minimal relative depth to start diving */
263  	   SCIP_Real             maxreldepth,        /**< maximal relative depth to start diving */
264  	   SCIP_Real             maxlpiterquot,      /**< maximal fraction of diving LP iterations compared to node LP iterations */
265  	   SCIP_Real             maxdiveubquot,      /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
266  	                                              *   where diving is performed (0.0: no limit) */
267  	   SCIP_Real             maxdiveavgquot,     /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
268  	                                              *   where diving is performed (0.0: no limit) */
269  	   SCIP_Real             maxdiveubquotnosol, /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
270  	   SCIP_Real             maxdiveavgquotnosol,/**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
271  	   SCIP_Real             lpresolvedomchgquot,/**< percentage of immediate domain changes during probing to trigger LP resolve */
272  	   int                   lpsolvefreq,        /**< LP solve frequency for (0: only if enough domain reductions are found by propagation)*/
273  	   int                   maxlpiterofs,       /**< additional number of allowed LP iterations */
274  	   unsigned int          initialseed,        /**< initial seed for random number generation */
275  	   SCIP_Bool             backtrack,          /**< use one level of backtracking if infeasibility is encountered? */
276  	   SCIP_Bool             onlylpbranchcands,  /**< should only LP branching candidates be considered instead of the slower but
277  	                                              *   more general constraint handler diving variable selection? */
278  	   SCIP_Bool             ispublic,           /**< is this dive set publicly available (ie., can be used by other primal heuristics?) */
279  	   SCIP_DIVETYPE         divetypemask,       /**< bit mask that represents the supported dive types by this dive set */
280  	   SCIP_DECL_DIVESETGETSCORE((*divesetgetscore)), /**< method for candidate score and rounding direction */
281  	   SCIP_DECL_DIVESETAVAILABLE((*divesetavailable)) /**< callback to check availability of dive set at the current stage, or NULL if always available */
282  	   )
283  	{
284  	   int c;
285  	   char paramname[SCIP_MAXSTRLEN];
286  	   const char* divesetname;
287  	   SCIP_DIVESET* diveset;
288  	
289  	   assert(divesetptr != NULL);
290  	   assert(set != NULL);
291  	   assert(divesetgetscore != NULL);
292  	   assert(heur != NULL);
293  	   assert(blkmem != NULL);
294  	
295  	   SCIP_ALLOC( BMSallocBlockMemory(blkmem, divesetptr) );
296  	   diveset = *divesetptr;
297  	
298  	   /* allocate random number generator. Note that we must make explicit use of random seed initialization because
299  	    * we create the random number generator directly, not through the public SCIP API
300  	    */
301  	   diveset->initialseed = initialseed;
302  	
303  	   /* simply use 0 as initial seed, the seed is reset in SCIPdivesetReset, anyway */
304  	   SCIP_CALL( SCIPrandomCreate(&diveset->randnumgen, blkmem, 0) );
305  	
306  	   /* for convenience, the name gets inferred from the heuristic to which the diveset is added if no name is provided */
307  	   divesetname = (name == NULL ? SCIPheurGetName(heur) : name);
308  	   SCIP_ALLOC( BMSduplicateMemoryArray(&diveset->name, divesetname, strlen(divesetname)+1) );
309  	   diveset->heur = NULL;
310  	
311  	   /* scoring callbacks */
312  	   diveset->divesetgetscore = divesetgetscore;
313  	   diveset->divesetavailable = divesetavailable;
314  	
315  	   SCIP_CALL( heurAddDiveset(heur, diveset) );
316  	   diveset->sol = NULL;
317  	   diveset->divetypemask = divetypemask;
318  	   diveset->ispublic = ispublic;
319  	
320  	   /* allocate memory for diveset statistics */
321  	   for( c = 0; c < 3; ++c )
322  	   {
323  	      SCIP_DIVESETSTATS** divesetstatsptr = &diveset->divesetstats[c];
324  	      SCIP_ALLOC( BMSallocBlockMemory(blkmem, divesetstatsptr) );
325  	   }
326  	
327  	   SCIP_CALL( SCIPdivesetReset(diveset, set) );
328  	
329  	   /* add collection of diving heuristic specific parameters */
330  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/minreldepth", diveset->name);
331  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem,
332  	         paramname, "minimal relative depth to start diving",
333  	         &diveset->minreldepth, TRUE, minreldepth, 0.0, 1.0, NULL, NULL) );
334  	
335  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxreldepth", diveset->name);
336  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
337  	         "maximal relative depth to start diving",
338  	         &diveset->maxreldepth, TRUE, maxreldepth, 0.0, 1.0, NULL, NULL) );
339  	
340  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxlpiterquot", diveset->name);
341  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem,
342  	         paramname,
343  	         "maximal fraction of diving LP iterations compared to node LP iterations",
344  	         &diveset->maxlpiterquot, FALSE, maxlpiterquot, 0.0, SCIP_REAL_MAX, NULL, NULL) );
345  	
346  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxlpiterofs", diveset->name);
347  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem,
348  	         paramname,
349  	         "additional number of allowed LP iterations",
350  	         &diveset->maxlpiterofs, FALSE, maxlpiterofs, 0, INT_MAX, NULL, NULL) );
351  	
352  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxdiveubquot", diveset->name);
353  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem,
354  	         paramname,
355  	         "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
356  	         &diveset->maxdiveubquot, TRUE, maxdiveubquot, 0.0, 1.0, NULL, NULL) );
357  	
358  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxdiveavgquot", diveset->name);
359  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem,
360  	         paramname,
361  	         "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
362  	         &diveset->maxdiveavgquot, TRUE, maxdiveavgquot, 0.0, SCIP_REAL_MAX, NULL, NULL) );
363  	
364  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxdiveubquotnosol", diveset->name);
365  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem,
366  	         paramname,
367  	         "maximal UBQUOT when no solution was found yet (0.0: no limit)",
368  	         &diveset->maxdiveubquotnosol, TRUE, maxdiveubquotnosol, 0.0, 1.0, NULL, NULL) );
369  	
370  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxdiveavgquotnosol", diveset->name);
371  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem,
372  	         paramname,
373  	         "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
374  	         &diveset->maxdiveavgquotnosol, TRUE, maxdiveavgquotnosol, 0.0, SCIP_REAL_MAX, NULL, NULL) );
375  	
376  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/backtrack", diveset->name);
377  	   SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem,
378  	         paramname,
379  	         "use one level of backtracking if infeasibility is encountered?",
380  	         &diveset->backtrack, FALSE, backtrack, NULL, NULL) );
381  	
382  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/lpresolvedomchgquot", diveset->name);
383  	   SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
384  	         "percentage of immediate domain changes during probing to trigger LP resolve",
385  	         &diveset->lpresolvedomchgquot, FALSE, lpresolvedomchgquot,  0.0, SCIP_REAL_MAX, NULL, NULL) );
386  	
387  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/lpsolvefreq", diveset->name);
388  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem,
389  	         paramname,
390  	         "LP solve frequency for diving heuristics (0: only after enough domain changes have been found)",
391  	         &diveset->lpsolvefreq, FALSE, lpsolvefreq, 0, INT_MAX,
392  	         NULL, NULL) );
393  	
394  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/onlylpbranchcands", diveset->name);
395  	   SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem,
396  	            paramname,
397  	            "should only LP branching candidates be considered instead of the slower but "
398  	            "more general constraint handler diving variable selection?",
399  	            &diveset->onlylpbranchcands, FALSE, onlylpbranchcands, NULL, NULL) );
400  	
401  	   return SCIP_OKAY;
402  	}
403  	
404  	/** get the heuristic to which this diving setting belongs */
405  	SCIP_HEUR* SCIPdivesetGetHeur(
406  	   SCIP_DIVESET*         diveset             /**< diving settings */
407  	   )
408  	{
409  	   return diveset->heur;
410  	}
411  	
412  	/** get the working solution of this dive set */
413  	SCIP_SOL* SCIPdivesetGetWorkSolution(
414  	   SCIP_DIVESET*         diveset             /**< diving settings */
415  	   )
416  	{
417  	   assert(diveset != NULL);
418  	
419  	   return diveset->sol;
420  	}
421  	
422  	/** set the working solution for this dive set */
423  	void SCIPdivesetSetWorkSolution(
424  	   SCIP_DIVESET*         diveset,            /**< diving settings */
425  	   SCIP_SOL*             sol                 /**< new working solution for this dive set, or NULL */
426  	   )
427  	{
428  	   assert(diveset != NULL);
429  	
430  	   diveset->sol = sol;
431  	}
432  	
433  	/** get the name of the dive set */
434  	const char* SCIPdivesetGetName(
435  	   SCIP_DIVESET*         diveset             /**< diving settings */
436  	   )
437  	{
438  	   assert(diveset != NULL);
439  	
440  	   return diveset->name;
441  	}
442  	
443  	/** get the minimum relative depth of the diving settings */
444  	SCIP_Real SCIPdivesetGetMinRelDepth(
445  	   SCIP_DIVESET*         diveset             /**< diving settings */
446  	   )
447  	{
448  	   return diveset->minreldepth;
449  	}
450  	
451  	/** get the maximum relative depth of the diving settings */
452  	SCIP_Real SCIPdivesetGetMaxRelDepth(
453  	   SCIP_DIVESET*         diveset             /**< diving settings */
454  	   )
455  	{
456  	   return diveset->maxreldepth;
457  	}
458  	
459  	/** get the number of successful runs of the diving settings */
460  	SCIP_Longint SCIPdivesetGetSolSuccess(
461  	   SCIP_DIVESET*         diveset,            /**< diving settings */
462  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
463  	
464  	   )
465  	{
466  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
467  	
468  	   assert(divesetstats != NULL);
469  	
470  	   return 10 * divesetstats->nbestsolsfound + divesetstats->nsolsfound;
471  	}
472  	
473  	/** get the number of calls to this dive set */
474  	int SCIPdivesetGetNCalls(
475  	   SCIP_DIVESET*         diveset,            /**< diving settings */
476  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
477  	   )
478  	{
479  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
480  	
481  	   assert(divesetstats != NULL);
482  	
483  	   return divesetstats->ncalls;
484  	}
485  	
486  	/** get the number of calls successfully terminated at a feasible leaf node */
487  	int SCIPdivesetGetNSolutionCalls(
488  	   SCIP_DIVESET*         diveset,            /**< diving settings */
489  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
490  	   )
491  	{
492  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
493  	
494  	   assert(diveset != NULL);
495  	
496  	   return divesetstats->nsolcalls;
497  	}
498  	
499  	/** get the minimum depth reached by this dive set */
500  	int SCIPdivesetGetMinDepth(
501  	   SCIP_DIVESET*         diveset,            /**< diving settings */
502  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
503  	   )
504  	{
505  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
506  	
507  	   assert(divesetstats != NULL);
508  	
509  	   return divesetstats->mindepth;
510  	}
511  	
512  	/** get the maximum depth reached by this dive set */
513  	int SCIPdivesetGetMaxDepth(
514  	   SCIP_DIVESET*         diveset,            /**< diving settings */
515  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
516  	   )
517  	{
518  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
519  	
520  	   assert(divesetstats != NULL);
521  	
522  	   return divesetstats->maxdepth;
523  	}
524  	
525  	/** get the average depth this dive set reached during execution */
526  	SCIP_Real SCIPdivesetGetAvgDepth(
527  	   SCIP_DIVESET*         diveset,            /**< diving settings */
528  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
529  	   )
530  	{
531  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
532  	
533  	   assert(divesetstats != NULL);
534  	
535  	   return (divesetstats->ncalls == 0 ? 0.0 : divesetstats->totaldepth / (SCIP_Real)divesetstats->ncalls);
536  	}
537  	
538  	/** get the minimum depth at which this dive set found a solution */
539  	int SCIPdivesetGetMinSolutionDepth(
540  	   SCIP_DIVESET*         diveset,            /**< diving settings */
541  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
542  	   )
543  	{
544  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
545  	
546  	   assert(divesetstats != NULL);
547  	
548  	   return divesetstats->minsoldepth;
549  	}
550  	
551  	/** get the maximum depth at which this dive set found a solution */
552  	int SCIPdivesetGetMaxSolutionDepth(
553  	   SCIP_DIVESET*         diveset,            /**< diving settings */
554  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
555  	   )
556  	{
557  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
558  	
559  	   assert(divesetstats != NULL);
560  	
561  	   return divesetstats->maxsoldepth;
562  	}
563  	
564  	/** get the average depth at which this dive set found a solution */
565  	SCIP_Real SCIPdivesetGetAvgSolutionDepth(
566  	   SCIP_DIVESET*         diveset,            /**< diving settings */
567  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
568  	   )
569  	{
570  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
571  	
572  	   assert(divesetstats != NULL);
573  	
574  	   return (divesetstats->nsolcalls == 0 ? 0.0 : divesetstats->totalsoldepth / (SCIP_Real)divesetstats->nsolcalls);
575  	}
576  	
577  	/** get the total number of LP iterations used by this dive set */
578  	SCIP_Longint SCIPdivesetGetNLPIterations(
579  	   SCIP_DIVESET*         diveset,            /**< diving settings */
580  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
581  	   )
582  	{
583  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
584  	
585  	   assert(divesetstats != NULL);
586  	
587  	   return divesetstats->nlpiterations;
588  	}
589  	
590  	/** get the total number of probing nodes used by this dive set */
591  	SCIP_Longint SCIPdivesetGetNProbingNodes(
592  	   SCIP_DIVESET*         diveset,            /**< diving settings */
593  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
594  	   )
595  	{
596  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
597  	
598  	   assert(divesetstats != NULL);
599  	
600  	   return divesetstats->totalnnodes;
601  	}
602  	
603  	/** get the total number of backtracks performed by this dive set */
604  	SCIP_Longint SCIPdivesetGetNBacktracks(
605  	   SCIP_DIVESET*         diveset,            /**< diving settings */
606  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
607  	   )
608  	{
609  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
610  	
611  	   assert(divesetstats != NULL);
612  	
613  	   return divesetstats->totalnbacktracks;
614  	}
615  	
616  	/** get the total number of conflicts found by this dive set */
617  	SCIP_Longint SCIPdivesetGetNConflicts(
618  	   SCIP_DIVESET*         diveset,            /**< diving settings */
619  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
620  	   )
621  	{
622  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
623  	
624  	   assert(divesetstats != NULL);
625  	
626  	   return divesetstats->nconflictsfound;
627  	}
628  	
629  	/** get the total number of solutions (leaf and rounded solutions) found by the dive set */
630  	SCIP_Longint SCIPdivesetGetNSols(
631  	   SCIP_DIVESET*         diveset,            /**< diving settings */
632  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
633  	   )
634  	{
635  	   SCIP_DIVESETSTATS* divesetstats = divesetGetStats(diveset, divecontext);
636  	
637  	   assert(divesetstats != NULL);
638  	
639  	   return divesetstats->nsolsfound;
640  	}
641  	
642  	
643  	/** get the maximum LP iterations quotient of the diving settings */
644  	SCIP_Real SCIPdivesetGetMaxLPIterQuot(
645  	   SCIP_DIVESET*         diveset             /**< diving settings */
646  	   )
647  	{
648  	   return diveset->maxlpiterquot;
649  	}
650  	
651  	/** get the maximum LP iterations offset of the diving settings */
652  	int SCIPdivesetGetMaxLPIterOffset(
653  	   SCIP_DIVESET*         diveset             /**< diving settings */
654  	   )
655  	{
656  	   return diveset->maxlpiterofs;
657  	}
658  	
659  	/** get the maximum upper bound quotient parameter of the diving settings if no solution is available */
660  	SCIP_Real SCIPdivesetGetUbQuotNoSol(
661  	   SCIP_DIVESET*         diveset             /**< diving settings */
662  	   )
663  	{
664  	   return diveset->maxdiveubquotnosol;
665  	}
666  	
667  	/** get the average quotient parameter of the diving settings if no solution is available */
668  	SCIP_Real SCIPdivesetGetAvgQuotNoSol(
669  	   SCIP_DIVESET*         diveset             /**< diving settings */
670  	   )
671  	{
672  	   return diveset->maxdiveavgquotnosol;
673  	}
674  	/** get the maximum upper bound quotient parameter of the diving settings if an incumbent solution exists */
675  	SCIP_Real SCIPdivesetGetUbQuot(
676  	   SCIP_DIVESET*         diveset             /**< diving settings */
677  	   )
678  	{
679  	   return diveset->maxdiveubquot;
680  	}
681  	
682  	/** get the average upper bound quotient parameter of the diving settings if an incumbent solution exists */
683  	SCIP_Real SCIPdivesetGetAvgQuot(
684  	   SCIP_DIVESET*         diveset             /**< diving settings */
685  	   )
686  	{
687  	   return diveset->maxdiveavgquot;
688  	}
689  	
690  	/** should backtracking be applied? */
691  	SCIP_Bool SCIPdivesetUseBacktrack(
692  	   SCIP_DIVESET*         diveset             /**< diving settings */
693  	   )
694  	{
695  	   return diveset->backtrack;
696  	}
697  	
698  	/** returns the LP solve frequency for diving LPs (0: dynamically based on number of intermediate domain reductions) */
699  	int SCIPdivesetGetLPSolveFreq(
700  	   SCIP_DIVESET*         diveset             /**< diving settings */
701  	   )
702  	{
703  	   assert(diveset != NULL);
704  	
705  	   return diveset->lpsolvefreq;
706  	}
707  	
708  	/** returns the random number generator of this \p diveset for tie-breaking */
709  	SCIP_RANDNUMGEN* SCIPdivesetGetRandnumgen(
710  	   SCIP_DIVESET*         diveset             /**< diving settings */
711  	   )
712  	{
713  	   assert(diveset != NULL);
714  	   assert(diveset->randnumgen != NULL);
715  	
716  	   return diveset->randnumgen;
717  	}
718  	
719  	/** returns the domain reduction quotient for triggering an immediate resolve of the diving LP (0.0: always resolve)*/
720  	SCIP_Real SCIPdivesetGetLPResolveDomChgQuot(
721  	   SCIP_DIVESET*         diveset             /**< diving settings */
722  	   )
723  	{
724  	   assert(diveset != NULL);
725  	
726  	   return diveset->lpresolvedomchgquot;
727  	}
728  	
729  	/** should only LP branching candidates be considered instead of the slower but
730  	 *  more general constraint handler diving variable selection?
731  	 */
732  	SCIP_Bool SCIPdivesetUseOnlyLPBranchcands(
733  	   SCIP_DIVESET*         diveset             /**< diving settings */
734  	   )
735  	{
736  	   assert(diveset != NULL);
737  	
738  	   return diveset->onlylpbranchcands;
739  	}
740  	
741  	/** returns TRUE if dive set supports diving of the specified type */
742  	SCIP_Bool SCIPdivesetSupportsType(
743  	   SCIP_DIVESET*         diveset,            /**< diving settings */
744  	   SCIP_DIVETYPE         divetype            /**< bit mask that represents the supported dive types by this dive set */
745  	   )
746  	{
747  	   assert(diveset != NULL);
748  	
749  	   return (divetype & diveset->divetypemask);
750  	}
751  	
752  	/** is this dive set publicly available (ie., can be used by other primal heuristics?) */
753  	SCIP_Bool SCIPdivesetIsPublic(
754  	   SCIP_DIVESET*         diveset             /**< diving settings */
755  	   )
756  	{
757  	   assert(diveset != NULL);
758  	
759  	   return diveset->ispublic;
760  	}
761  	
762  	/** updates LP related diveset statistics */
763  	static
764  	void updateDivesetstatsLP(
765  	   SCIP_DIVESETSTATS*    divesetstats,       /**< diving settings */
766  	   SCIP_Longint          niterstoadd         /**< additional number of LP iterations to be added */
767  	   )
768  	{
769  	   assert(divesetstats != NULL);
770  	
771  	   divesetstats->nlpiterations += niterstoadd;
772  	   divesetstats->nlps++;
773  	}
774  	
775  	/** update diveset LP statistics, should be called after every LP solved by this diving heuristic */
776  	void SCIPdivesetUpdateLPStats(
777  	   SCIP_DIVESET*         diveset,            /**< diving settings */
778  	   SCIP_STAT*            stat,               /**< global SCIP statistics */
779  	   SCIP_Longint          niterstoadd,        /**< additional number of LP iterations to be added */
780  	   SCIP_DIVECONTEXT      divecontext         /**< context for diving statistics */
781  	   )
782  	{
783  	   assert(diveset != NULL);
784  	   assert(divecontext == SCIP_DIVECONTEXT_ADAPTIVE || divecontext == SCIP_DIVECONTEXT_SINGLE);
785  	
786  	   /* update statistics for total context and given context */
787  	   updateDivesetstatsLP(divesetGetStats(diveset, divecontext), niterstoadd);
788  	   updateDivesetstatsLP(divesetGetStats(diveset, SCIP_DIVECONTEXT_TOTAL), niterstoadd);
789  	
790  	   stat->ndivesetlpiterations += niterstoadd;
791  	   stat->ndivesetlps++;
792  	}
793  	
794  	/** frees memory of a diveset */
795  	static
796  	void divesetFree(
797  	   SCIP_DIVESET**        divesetptr,         /**< general diving settings */
798  	   BMS_BLKMEM*           blkmem              /**< block memory for parameter settings */
799  	   )
800  	{
801  	   int c;
802  	   SCIP_DIVESET* diveset = *divesetptr;
803  	
804  	   assert(diveset != NULL);
805  	   assert(diveset->name != NULL);
806  	   assert(diveset->randnumgen != NULL);
807  	
808  	   SCIPrandomFree(&diveset->randnumgen, blkmem);
809  	
810  	   /* free all diveset statistics */
811  	   for( c = 0; c < 3; ++c )
812  	   {
813  	      SCIP_DIVESETSTATS** divesetstatsptr = &diveset->divesetstats[c];
814  	      BMSfreeBlockMemory(blkmem, divesetstatsptr);
815  	   }
816  	
817  	   BMSfreeMemoryArray(&diveset->name);
818  	   BMSfreeBlockMemory(blkmem, divesetptr);
819  	}
820  	
821  	/** get the candidate score and preferred rounding direction for a candidate variable */
822  	SCIP_RETCODE SCIPdivesetGetScore(
823  	   SCIP_DIVESET*         diveset,            /**< general diving settings */
824  	   SCIP_SET*             set,                /**< SCIP settings */
825  	   SCIP_DIVETYPE         divetype,           /**< the type of diving that should be applied */
826  	   SCIP_VAR*             divecand,           /**< the candidate for which the branching direction is requested */
827  	   SCIP_Real             divecandsol,        /**< LP solution value of the candidate */
828  	   SCIP_Real             divecandfrac,       /**< fractionality of the candidate */
829  	   SCIP_Real*            candscore,          /**< pointer to store the candidate score */
830  	   SCIP_Bool*            roundup             /**< pointer to store whether preferred direction for diving is upwards */
831  	   )
832  	{
833  	   assert(diveset->divesetgetscore != NULL);
834  	   assert(candscore != NULL);
835  	   assert(roundup != NULL);
836  	   assert(divecand != NULL);
837  	   assert(divetype & diveset->divetypemask);
838  	
839  	   SCIP_CALL( diveset->divesetgetscore(set->scip, diveset, divetype, divecand, divecandsol, divecandfrac,
840  	         candscore, roundup) );
841  	
842  	   return SCIP_OKAY;
843  	}
844  	
845  	/** check specific preconditions for diving, e.g., if an incumbent solution is available */
846  	SCIP_RETCODE SCIPdivesetIsAvailable(
847  	   SCIP_DIVESET*         diveset,            /**< diving heuristic settings */
848  	   SCIP_SET*             set,                /**< SCIP settings */
849  	   SCIP_Bool*            available           /**< pointer to store if the diving can run at the current solving stage */
850  	   )
851  	{
852  	   assert(set != NULL);
853  	   assert(diveset != NULL);
854  	   assert(available != NULL);
855  	
856  	   if( diveset->divesetavailable == NULL )
857  	      *available = TRUE;
858  	   else
859  	   {
860  	      *available = FALSE;
861  	      SCIP_CALL( diveset->divesetavailable(set->scip, diveset, available) );
862  	   }
863  	
864  	   return SCIP_OKAY;
865  	}
866  	
867  	
868  	
869  	/** copies the given primal heuristic to a new scip */
870  	SCIP_RETCODE SCIPheurCopyInclude(
871  	   SCIP_HEUR*            heur,               /**< primal heuristic */
872  	   SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
873  	   )
874  	{
875  	   assert(heur != NULL);
876  	   assert(set != NULL);
877  	   assert(set->scip != NULL);
878  	
879  	   if( heur->heurcopy != NULL )
880  	   {
881  	      SCIPsetDebugMsg(set, "including heur %s in subscip %p\n", SCIPheurGetName(heur), (void*)set->scip);
882  	      SCIP_CALL( heur->heurcopy(set->scip, heur) );
883  	   }
884  	
885  	   return SCIP_OKAY;
886  	}
887  	
888  	/** internal method for creating a primal heuristic */
889  	static
890  	SCIP_RETCODE doHeurCreate(
891  	   SCIP_HEUR**           heur,               /**< pointer to primal heuristic data structure */
892  	   SCIP_SET*             set,                /**< global SCIP settings */
893  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
894  	   BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
895  	   const char*           name,               /**< name of primal heuristic */
896  	   const char*           desc,               /**< description of primal heuristic */
897  	   char                  dispchar,           /**< display character of primal heuristic */
898  	   int                   priority,           /**< priority of the primal heuristic */
899  	   int                   freq,               /**< frequency for calling primal heuristic */
900  	   int                   freqofs,            /**< frequency offset for calling primal heuristic */
901  	   int                   maxdepth,           /**< maximal depth level to call heuristic at (-1: no limit) */
902  	   SCIP_HEURTIMING       timingmask,         /**< positions in the node solving loop where heuristic should be executed */
903  	   SCIP_Bool             usessubscip,        /**< does the heuristic use a secondary SCIP instance? */
904  	   SCIP_DECL_HEURCOPY    ((*heurcopy)),      /**< copy method of primal heuristic or NULL if you don't want to copy your plugin into sub-SCIPs */
905  	   SCIP_DECL_HEURFREE    ((*heurfree)),      /**< destructor of primal heuristic */
906  	   SCIP_DECL_HEURINIT    ((*heurinit)),      /**< initialize primal heuristic */
907  	   SCIP_DECL_HEUREXIT    ((*heurexit)),      /**< deinitialize primal heuristic */
908  	   SCIP_DECL_HEURINITSOL ((*heurinitsol)),   /**< solving process initialization method of primal heuristic */
909  	   SCIP_DECL_HEUREXITSOL ((*heurexitsol)),   /**< solving process deinitialization method of primal heuristic */
910  	   SCIP_DECL_HEUREXEC    ((*heurexec)),      /**< execution method of primal heuristic */
911  	   SCIP_HEURDATA*        heurdata            /**< primal heuristic data */
912  	   )
913  	{
914  	   char paramname[SCIP_MAXSTRLEN];
915  	   char paramdesc[SCIP_MAXSTRLEN];
916  	
917  	   assert(heur != NULL);
918  	   assert(name != NULL);
919  	   assert(desc != NULL);
920  	   assert(freq >= -1);
921  	   assert(freqofs >= 0);
922  	   assert(heurexec != NULL);
923  	
924  	   SCIP_ALLOC( BMSallocMemory(heur) );
925  	   BMSclearMemory(*heur);
926  	
927  	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*heur)->name, name, strlen(name)+1) );
928  	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*heur)->desc, desc, strlen(desc)+1) );
929  	   (*heur)->dispchar = dispchar;
930  	   (*heur)->priority = priority;
931  	   (*heur)->freq = freq;
932  	   (*heur)->freqofs = freqofs;
933  	   (*heur)->maxdepth = maxdepth;
934  	   (*heur)->delaypos = -1;
935  	   (*heur)->timingmask = timingmask;
936  	   (*heur)->usessubscip = usessubscip;
937  	   (*heur)->heurcopy = heurcopy;
938  	   (*heur)->heurfree = heurfree;
939  	   (*heur)->heurinit = heurinit;
940  	   (*heur)->heurexit = heurexit;
941  	   (*heur)->heurinitsol = heurinitsol;
942  	   (*heur)->heurexitsol = heurexitsol;
943  	   (*heur)->heurexec = heurexec;
944  	   (*heur)->heurdata = heurdata;
945  	   SCIP_CALL( SCIPclockCreate(&(*heur)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
946  	   SCIP_CALL( SCIPclockCreate(&(*heur)->heurclock, SCIP_CLOCKTYPE_DEFAULT) );
947  	   (*heur)->ncalls = 0;
948  	   (*heur)->nsolsfound = 0;
949  	   (*heur)->nbestsolsfound = 0;
950  	   (*heur)->initialized = FALSE;
951  	   (*heur)->divesets = NULL;
952  	   (*heur)->ndivesets = 0;
953  	
954  	   /* add parameters */
955  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/priority", name);
956  	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of heuristic <%s>", name);
957  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
958  	                  &(*heur)->priority, TRUE, priority, INT_MIN/4, INT_MAX/4,
959  	                  paramChgdHeurPriority, (SCIP_PARAMDATA*)(*heur)) ); /*lint !e740*/
960  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/freq", name);
961  	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "frequency for calling primal heuristic <%s> (-1: never, 0: only at depth freqofs)", name);
962  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
963  	                  &(*heur)->freq, FALSE, freq, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
964  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/freqofs", name);
965  	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "frequency offset for calling primal heuristic <%s>", name);
966  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
967  	                  &(*heur)->freqofs, FALSE, freqofs, 0, SCIP_MAXTREEDEPTH, NULL, NULL) );
968  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/%s/maxdepth", name);
969  	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "maximal depth level to call primal heuristic <%s> (-1: no limit)", name);
970  	   SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
971  	                  &(*heur)->maxdepth, TRUE, maxdepth, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
972  	
973  	   return SCIP_OKAY;
974  	}
975  	
976  	/** creates a primal heuristic */
977  	SCIP_RETCODE SCIPheurCreate(
978  	   SCIP_HEUR**           heur,               /**< pointer to primal heuristic data structure */
979  	   SCIP_SET*             set,                /**< global SCIP settings */
980  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
981  	   BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
982  	   const char*           name,               /**< name of primal heuristic */
983  	   const char*           desc,               /**< description of primal heuristic */
984  	   char                  dispchar,           /**< display character of primal heuristic */
985  	   int                   priority,           /**< priority of the primal heuristic */
986  	   int                   freq,               /**< frequency for calling primal heuristic */
987  	   int                   freqofs,            /**< frequency offset for calling primal heuristic */
988  	   int                   maxdepth,           /**< maximal depth level to call heuristic at (-1: no limit) */
989  	   SCIP_HEURTIMING       timingmask,         /**< positions in the node solving loop where heuristic should be executed */
990  	   SCIP_Bool             usessubscip,        /**< does the heuristic use a secondary SCIP instance? */
991  	   SCIP_DECL_HEURCOPY    ((*heurcopy)),      /**< copy method of primal heuristic or NULL if you don't want to copy your plugin into sub-SCIPs */
992  	   SCIP_DECL_HEURFREE    ((*heurfree)),      /**< destructor of primal heuristic */
993  	   SCIP_DECL_HEURINIT    ((*heurinit)),      /**< initialize primal heuristic */
994  	   SCIP_DECL_HEUREXIT    ((*heurexit)),      /**< deinitialize primal heuristic */
995  	   SCIP_DECL_HEURINITSOL ((*heurinitsol)),   /**< solving process initialization method of primal heuristic */
996  	   SCIP_DECL_HEUREXITSOL ((*heurexitsol)),   /**< solving process deinitialization method of primal heuristic */
997  	   SCIP_DECL_HEUREXEC    ((*heurexec)),      /**< execution method of primal heuristic */
998  	   SCIP_HEURDATA*        heurdata            /**< primal heuristic data */
999  	   )
1000 	{
1001 	   assert(heur != NULL);
1002 	   assert(name != NULL);
1003 	   assert(desc != NULL);
1004 	   assert(freq >= -1);
1005 	   assert(freqofs >= 0);
1006 	   assert(heurexec != NULL);
1007 	
1008 	   SCIP_CALL_FINALLY( doHeurCreate(heur, set, messagehdlr, blkmem, name, desc, dispchar, priority, freq, freqofs,
1009 	      maxdepth, timingmask, usessubscip, heurcopy, heurfree, heurinit, heurexit, heurinitsol, heurexitsol, heurexec,
1010 	      heurdata), (void) SCIPheurFree(heur, set, blkmem) );
1011 	
1012 	   return SCIP_OKAY;
1013 	}
1014 	
1015 	/** calls destructor and frees memory of primal heuristic */
1016 	SCIP_RETCODE SCIPheurFree(
1017 	   SCIP_HEUR**           heur,               /**< pointer to primal heuristic data structure */
1018 	   SCIP_SET*             set,                /**< global SCIP settings */
1019 	   BMS_BLKMEM*           blkmem              /**< block memory */
1020 	   )
1021 	{
1022 	   int d;
1023 	   assert(heur != NULL);
1024 	   if( *heur == NULL )
1025 	      return SCIP_OKAY;
1026 	   assert(!(*heur)->initialized);
1027 	   assert(set != NULL);
1028 	   assert((*heur)->divesets != NULL || (*heur)->ndivesets == 0);
1029 	
1030 	   /* call destructor of primal heuristic */
1031 	   if( (*heur)->heurfree != NULL )
1032 	   {
1033 	      SCIP_CALL( (*heur)->heurfree(set->scip, *heur) );
1034 	   }
1035 	
1036 	   for( d = 0; d < (*heur)->ndivesets; ++d )
1037 	   {
1038 	      assert((*heur)->divesets[d] != NULL);
1039 	      divesetFree(&((*heur)->divesets[d]), blkmem);
1040 	   }
1041 	   BMSfreeMemoryArrayNull(&(*heur)->divesets);
1042 	   SCIPclockFree(&(*heur)->heurclock);
1043 	   SCIPclockFree(&(*heur)->setuptime);
1044 	   BMSfreeMemoryArrayNull(&(*heur)->name);
1045 	   BMSfreeMemoryArrayNull(&(*heur)->desc);
1046 	   BMSfreeMemory(heur);
1047 	
1048 	   return SCIP_OKAY;
1049 	}
1050 	
1051 	/** initializes primal heuristic */
1052 	SCIP_RETCODE SCIPheurInit(
1053 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1054 	   SCIP_SET*             set                 /**< global SCIP settings */
1055 	   )
1056 	{
1057 	   int d;
1058 	   assert(heur != NULL);
1059 	   assert(set != NULL);
1060 	
1061 	   if( heur->initialized )
1062 	   {
1063 	      SCIPerrorMessage("primal heuristic <%s> already initialized\n", heur->name);
1064 	      return SCIP_INVALIDCALL;
1065 	   }
1066 	
1067 	   if( set->misc_resetstat )
1068 	   {
1069 	      SCIPclockReset(heur->setuptime);
1070 	      SCIPclockReset(heur->heurclock);
1071 	
1072 	      heur->delaypos = -1;
1073 	      heur->ncalls = 0;
1074 	      heur->nsolsfound = 0;
1075 	      heur->nbestsolsfound = 0;
1076 	
1077 	      set->heurssorted = FALSE;
1078 	      set->heursnamesorted = FALSE;
1079 	   }
1080 	
1081 	   if( heur->heurinit != NULL )
1082 	   {
1083 	      /* start timing */
1084 	      SCIPclockStart(heur->setuptime, set);
1085 	
1086 	      SCIP_CALL( heur->heurinit(set->scip, heur) );
1087 	
1088 	      /* stop timing */
1089 	      SCIPclockStop(heur->setuptime, set);
1090 	   }
1091 	
1092 	   /* reset dive sets */
1093 	   for( d = 0; d < heur->ndivesets; ++d )
1094 	   {
1095 	      assert(heur->divesets[d] != NULL);
1096 	      SCIP_CALL( SCIPdivesetReset(heur->divesets[d], set) );
1097 	   }
1098 	
1099 	   heur->initialized = TRUE;
1100 	
1101 	   return SCIP_OKAY;
1102 	}
1103 	
1104 	/** calls exit method of primal heuristic */
1105 	SCIP_RETCODE SCIPheurExit(
1106 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1107 	   SCIP_SET*             set                 /**< global SCIP settings */
1108 	   )
1109 	{
1110 	   assert(heur != NULL);
1111 	   assert(set != NULL);
1112 	
1113 	   if( !heur->initialized )
1114 	   {
1115 	      SCIPerrorMessage("primal heuristic <%s> not initialized\n", heur->name);
1116 	      return SCIP_INVALIDCALL;
1117 	   }
1118 	
1119 	   if( heur->heurexit != NULL )
1120 	   {
1121 	      /* start timing */
1122 	      SCIPclockStart(heur->setuptime, set);
1123 	
1124 	      SCIP_CALL( heur->heurexit(set->scip, heur) );
1125 	
1126 	      /* stop timing */
1127 	      SCIPclockStop(heur->setuptime, set);
1128 	   }
1129 	   heur->initialized = FALSE;
1130 	
1131 	   return SCIP_OKAY;
1132 	}
1133 	
1134 	/** informs primal heuristic that the branch and bound process is being started */
1135 	SCIP_RETCODE SCIPheurInitsol(
1136 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1137 	   SCIP_SET*             set                 /**< global SCIP settings */
1138 	   )
1139 	{
1140 	   assert(heur != NULL);
1141 	   assert(set != NULL);
1142 	
1143 	   if( heur->delaypos != -1 )
1144 	   {
1145 	      heur->delaypos = -1;
1146 	      set->heurssorted = FALSE;
1147 	   }
1148 	
1149 	   /* call solving process initialization method of primal heuristic */
1150 	   if( heur->heurinitsol != NULL )
1151 	   {
1152 	      /* start timing */
1153 	      SCIPclockStart(heur->setuptime, set);
1154 	
1155 	      SCIP_CALL( heur->heurinitsol(set->scip, heur) );
1156 	
1157 	      /* stop timing */
1158 	      SCIPclockStop(heur->setuptime, set);
1159 	   }
1160 	
1161 	   return SCIP_OKAY;
1162 	}
1163 	
1164 	/** informs primal heuristic that the branch and bound process data is being freed */
1165 	SCIP_RETCODE SCIPheurExitsol(
1166 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1167 	   SCIP_SET*             set                 /**< global SCIP settings */
1168 	   )
1169 	{
1170 	   assert(heur != NULL);
1171 	   assert(set != NULL);
1172 	
1173 	   /* call solving process deinitialization method of primal heuristic */
1174 	   if( heur->heurexitsol != NULL )
1175 	   {
1176 	      /* start timing */
1177 	      SCIPclockStart(heur->setuptime, set);
1178 	
1179 	      SCIP_CALL( heur->heurexitsol(set->scip, heur) );
1180 	
1181 	      /* stop timing */
1182 	      SCIPclockStop(heur->setuptime, set);
1183 	   }
1184 	
1185 	   return SCIP_OKAY;
1186 	}
1187 	
1188 	/** should the heuristic be executed at the given depth, frequency, timing, ... */
1189 	SCIP_Bool SCIPheurShouldBeExecuted(
1190 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1191 	   int                   depth,              /**< depth of current node */
1192 	   int                   lpstateforkdepth,   /**< depth of the last node with solved LP */
1193 	   SCIP_HEURTIMING       heurtiming,         /**< current point in the node solving process */
1194 	   SCIP_Bool*            delayed             /**< pointer to store whether the heuristic should be delayed */
1195 	   )
1196 	{
1197 	   SCIP_Bool execute;
1198 	
1199 	   if( ((heur->timingmask & SCIP_HEURTIMING_BEFOREPRESOL) && heurtiming == SCIP_HEURTIMING_BEFOREPRESOL)
1200 	       || ((heur->timingmask & SCIP_HEURTIMING_DURINGPRESOLLOOP) && heurtiming == SCIP_HEURTIMING_DURINGPRESOLLOOP) )
1201 	   {
1202 	      /* heuristic may be executed before/during presolving. Do so, if it was not disabled by setting the frequency to -1 */
1203 	      execute = heur->freq >= 0; 
1204 	   } 
1205 	   else if( (heur->timingmask & SCIP_HEURTIMING_AFTERPSEUDONODE) == 0
1206 	      && (heurtiming == SCIP_HEURTIMING_AFTERLPNODE || heurtiming == SCIP_HEURTIMING_AFTERLPPLUNGE) )
1207 	   {
1208 	      /* heuristic was skipped on intermediate pseudo nodes: check, if a node matching the execution frequency lies
1209 	       * between the current node and the last LP node of the path
1210 	       */
1211 	      execute = (heur->freq > 0 && depth >= heur->freqofs 
1212 	         && ((depth + heur->freq - heur->freqofs) / heur->freq
1213 	            != (lpstateforkdepth + heur->freq - heur->freqofs) / heur->freq));
1214 	   }
1215 	   else
1216 	   {
1217 	      /* heuristic may be executed on every node: check, if the current depth matches the execution frequency and offset */
1218 	      execute = (heur->freq > 0 && depth >= heur->freqofs && (depth - heur->freqofs) % heur->freq == 0);
1219 	   }
1220 	
1221 	   /* if frequency is zero, execute heuristic only at the depth level of the frequency offset */
1222 	   execute = execute || (depth == heur->freqofs && heur->freq == 0);
1223 	
1224 	   /* compare current depth against heuristic's maximal depth level */
1225 	   execute = execute && (heur->maxdepth == -1 || depth <= heur->maxdepth);
1226 	
1227 	   /* if the heuristic was delayed, execute it anyway */
1228 	   execute = execute || (heur->delaypos >= 0);
1229 	
1230 	   /* if the heuristic should be called after plunging but not during plunging, delay it if we are in plunging */
1231 	   if( execute
1232 	      && ((heurtiming == SCIP_HEURTIMING_AFTERLPNODE
1233 	            && (heur->timingmask & SCIP_HEURTIMING_AFTERLPNODE) == 0
1234 	            && (heur->timingmask & SCIP_HEURTIMING_AFTERLPPLUNGE) > 0)
1235 	         || (heurtiming == SCIP_HEURTIMING_AFTERPSEUDONODE
1236 	            && (heur->timingmask & SCIP_HEURTIMING_AFTERPSEUDONODE) == 0
1237 	            && (heur->timingmask & SCIP_HEURTIMING_AFTERPSEUDOPLUNGE) > 0)) )
1238 	   {
1239 	      /* the heuristic should be delayed until plunging is finished */
1240 	      execute = FALSE;
1241 	      *delayed = TRUE;
1242 	   }
1243 	
1244 	   /* execute heuristic only if its timing mask fits the current point in the node solving process */
1245 	   execute = execute && (heur->timingmask & heurtiming) > 0;
1246 	
1247 	   return execute;
1248 	}
1249 	
1250 	/** calls execution method of primal heuristic */
1251 	SCIP_RETCODE SCIPheurExec(
1252 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1253 	   SCIP_SET*             set,                /**< global SCIP settings */
1254 	   SCIP_PRIMAL*          primal,             /**< primal data */
1255 	   int                   depth,              /**< depth of current node */
1256 	   int                   lpstateforkdepth,   /**< depth of the last node with solved LP */
1257 	   SCIP_HEURTIMING       heurtiming,         /**< current point in the node solving process */
1258 	   SCIP_Bool             nodeinfeasible,     /**< was the current node already detected to be infeasible? */
1259 	   int*                  ndelayedheurs,      /**< pointer to count the number of delayed heuristics */
1260 	   SCIP_RESULT*          result              /**< pointer to store the result of the callback method */
1261 	   )
1262 	{
1263 	   SCIP_Bool execute;
1264 	   SCIP_Bool delayed;
1265 	
1266 	   assert(heur != NULL);
1267 	   assert(heur->heurexec != NULL);
1268 	   assert(heur->freq >= -1);
1269 	   assert(heur->freqofs >= 0);
1270 	   assert(heur->maxdepth >= -1);
1271 	   assert(set != NULL);
1272 	   assert(set->scip != NULL);
1273 	   assert(primal != NULL);
1274 	   assert(depth >= 0 || heurtiming == SCIP_HEURTIMING_BEFOREPRESOL || heurtiming == SCIP_HEURTIMING_DURINGPRESOLLOOP);
1275 	   assert(ndelayedheurs != NULL);
1276 	   assert(result != NULL);
1277 	
1278 	   *result = SCIP_DIDNOTRUN;
1279 	
1280 	   delayed = FALSE;
1281 	   execute = SCIPheurShouldBeExecuted(heur, depth, lpstateforkdepth, heurtiming, &delayed);
1282 	
1283 	   if( delayed )
1284 	   {
1285 	      assert(!execute);
1286 	      *result = SCIP_DELAYED;
1287 	   }
1288 	
1289 	   if( execute )
1290 	   {
1291 	      SCIP_Longint oldnsolsfound;
1292 	      SCIP_Longint oldnbestsolsfound;
1293 	
1294 	      SCIPsetDebugMsg(set, "executing primal heuristic <%s> in depth %d (delaypos: %d)\n", heur->name, depth, heur->delaypos);
1295 	
1296 	      oldnsolsfound = primal->nsolsfound;
1297 	      oldnbestsolsfound = primal->nbestsolsfound;
1298 	
1299 	      /* start timing */
1300 	      SCIPclockStart(heur->heurclock, set);
1301 	
1302 	      /* call external method */
1303 	      SCIP_CALL( heur->heurexec(set->scip, heur, heurtiming, nodeinfeasible, result) );
1304 	
1305 	      /* stop timing */
1306 	      SCIPclockStop(heur->heurclock, set);
1307 	
1308 	      /* evaluate result */
1309 	      if( *result != SCIP_FOUNDSOL
1310 	         && *result != SCIP_DIDNOTFIND
1311 	         && *result != SCIP_DIDNOTRUN
1312 	         && *result != SCIP_DELAYED
1313 	         && *result != SCIP_UNBOUNDED )
1314 	      {
1315 	         SCIPerrorMessage("execution method of primal heuristic <%s> returned invalid result <%d>\n", 
1316 	            heur->name, *result);
1317 	         return SCIP_INVALIDRESULT;
1318 	      }
1319 	      if( *result != SCIP_DIDNOTRUN && *result != SCIP_DELAYED )
1320 	         heur->ncalls++;
1321 	      heur->nsolsfound += primal->nsolsfound - oldnsolsfound;
1322 	      heur->nbestsolsfound += primal->nbestsolsfound - oldnbestsolsfound;
1323 	
1324 	      /* update delay position of heuristic */
1325 	      if( *result != SCIP_DELAYED && heur->delaypos != -1 )
1326 	      {
1327 	         heur->delaypos = -1;
1328 	         set->heurssorted = FALSE;
1329 	      }
1330 	   }
1331 	   assert(*result == SCIP_DIDNOTRUN || *result == SCIP_DELAYED || *result == SCIP_UNBOUNDED || heur->delaypos == -1);
1332 	
1333 	   /* check if the heuristic was (still) delayed */
1334 	   if( *result == SCIP_DELAYED || heur->delaypos >= 0 )
1335 	   {
1336 	      SCIPsetDebugMsg(set, "delaying execution of primal heuristic <%s> in depth %d (delaypos: %d), heur was%s delayed before, had delaypos %d\n",
1337 	         heur->name, depth, *ndelayedheurs, heur->delaypos >= 0 ? "" : " not", heur->delaypos);
1338 	
1339 	      /* mark the heuristic delayed */
1340 	      if( heur->delaypos != *ndelayedheurs )
1341 	      {
1342 	         heur->delaypos = *ndelayedheurs;
1343 	         set->heurssorted = FALSE;
1344 	      }
1345 	      (*ndelayedheurs)++;
1346 	   }
1347 	
1348 	   return SCIP_OKAY;
1349 	}
1350 	
1351 	/** gets user data of primal heuristic */
1352 	SCIP_HEURDATA* SCIPheurGetData(
1353 	   SCIP_HEUR*            heur                /**< primal heuristic */
1354 	   )
1355 	{
1356 	   assert(heur != NULL);
1357 	
1358 	   return heur->heurdata;
1359 	}
1360 	
1361 	/** sets user data of primal heuristic; user has to free old data in advance! */
1362 	void SCIPheurSetData(
1363 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1364 	   SCIP_HEURDATA*        heurdata            /**< new primal heuristic user data */
1365 	   )
1366 	{
1367 	   assert(heur != NULL);
1368 	
1369 	   heur->heurdata = heurdata;
1370 	}
1371 	
1372 	/* new callback setter methods */
1373 	
1374 	/** sets copy callback of primal heuristic */
1375 	void SCIPheurSetCopy(
1376 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1377 	   SCIP_DECL_HEURCOPY    ((*heurcopy))       /**< copy callback of primal heuristic or NULL if you don't want to copy your plugin into sub-SCIPs */
1378 	   )
1379 	{
1380 	   assert(heur != NULL);
1381 	
1382 	   heur->heurcopy = heurcopy;
1383 	}
1384 	
1385 	/** sets destructor callback of primal heuristic */
1386 	void SCIPheurSetFree(
1387 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1388 	   SCIP_DECL_HEURFREE    ((*heurfree))       /**< destructor of primal heuristic */
1389 	   )
1390 	{
1391 	   assert(heur != NULL);
1392 	
1393 	   heur->heurfree = heurfree;
1394 	}
1395 	
1396 	/** sets initialization callback of primal heuristic */
1397 	void SCIPheurSetInit(
1398 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1399 	   SCIP_DECL_HEURINIT    ((*heurinit))       /**< initialize primal heuristic */
1400 	   )
1401 	{
1402 	   assert(heur != NULL);
1403 	
1404 	   heur->heurinit = heurinit;
1405 	}
1406 	
1407 	/** sets deinitialization callback of primal heuristic */
1408 	void SCIPheurSetExit(
1409 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1410 	   SCIP_DECL_HEUREXIT    ((*heurexit))       /**< deinitialize primal heuristic */
1411 	   )
1412 	{
1413 	   assert(heur != NULL);
1414 	
1415 	   heur->heurexit = heurexit;
1416 	}
1417 	
1418 	/** sets solving process initialization callback of primal heuristic */
1419 	void SCIPheurSetInitsol(
1420 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1421 	   SCIP_DECL_HEURINITSOL ((*heurinitsol))    /**< solving process initialization callback of primal heuristic */
1422 	   )
1423 	{
1424 	   assert(heur != NULL);
1425 	
1426 	   heur->heurinitsol = heurinitsol;
1427 	}
1428 	
1429 	/** sets solving process deinitialization callback of primal heuristic */
1430 	void SCIPheurSetExitsol(
1431 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1432 	   SCIP_DECL_HEUREXITSOL ((*heurexitsol))    /**< solving process deinitialization callback of primal heuristic */
1433 	   )
1434 	{
1435 	   assert(heur != NULL);
1436 	
1437 	   heur->heurexitsol = heurexitsol;
1438 	}
1439 	
1440 	/** gets name of primal heuristic */
1441 	const char* SCIPheurGetName(
1442 	   SCIP_HEUR*            heur                /**< primal heuristic */
1443 	   )
1444 	{
1445 	   assert(heur != NULL);
1446 	
1447 	   return heur->name;
1448 	}
1449 	
1450 	/** gets description of primal heuristic */
1451 	const char* SCIPheurGetDesc(
1452 	   SCIP_HEUR*            heur                /**< primal heuristic */
1453 	   )
1454 	{
1455 	   assert(heur != NULL);
1456 	
1457 	   return heur->desc;
1458 	}
1459 	
1460 	/** gets display character of primal heuristic */
1461 	char SCIPheurGetDispchar(
1462 	   SCIP_HEUR*            heur                /**< primal heuristic */
1463 	   )
1464 	{
1465 	   assert(heur != NULL);
1466 	
1467 	   return heur->dispchar;
1468 	}
1469 	
1470 	/** returns the timing mask of the heuristic */
1471 	SCIP_HEURTIMING SCIPheurGetTimingmask(
1472 	   SCIP_HEUR*            heur                /**< primal heuristic */
1473 	   )
1474 	{
1475 	   assert(heur != NULL);
1476 	
1477 	   return heur->timingmask;
1478 	}
1479 	
1480 	/** sets new timing mask for heuristic */
1481 	void SCIPheurSetTimingmask(
1482 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1483 	   SCIP_HEURTIMING       timingmask          /**< new timing mask of heuristic */
1484 	   )
1485 	{
1486 	   assert(heur != NULL);
1487 	
1488 	   heur->timingmask = timingmask;
1489 	}
1490 	
1491 	/** does the heuristic use a secondary SCIP instance? */
1492 	SCIP_Bool SCIPheurUsesSubscip(
1493 	   SCIP_HEUR*            heur                /**< primal heuristic */
1494 	   )
1495 	{
1496 	   assert(heur != NULL);
1497 	
1498 	   return heur->usessubscip;
1499 	}
1500 	
1501 	/** gets priority of primal heuristic */
1502 	int SCIPheurGetPriority(
1503 	   SCIP_HEUR*            heur                /**< primal heuristic */
1504 	   )
1505 	{
1506 	   assert(heur != NULL);
1507 	
1508 	   return heur->priority;
1509 	}
1510 	
1511 	/** sets priority of primal heuristic */
1512 	void SCIPheurSetPriority(
1513 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1514 	   SCIP_SET*             set,                /**< global SCIP settings */
1515 	   int                   priority            /**< new priority of the primal heuristic */
1516 	   )
1517 	{
1518 	   assert(heur != NULL);
1519 	   assert(set != NULL);
1520 	
1521 	   heur->priority = priority;
1522 	   set->heurssorted = FALSE;
1523 	}
1524 	
1525 	/** gets frequency of primal heuristic */
1526 	int SCIPheurGetFreq(
1527 	   SCIP_HEUR*            heur                /**< primal heuristic */
1528 	   )
1529 	{
1530 	   assert(heur != NULL);
1531 	
1532 	   return heur->freq;
1533 	}
1534 	
1535 	/** sets frequency of primal heuristic */
1536 	void SCIPheurSetFreq(
1537 	   SCIP_HEUR*            heur,               /**< primal heuristic */
1538 	   int                   freq                /**< new frequency of heuristic */
1539 	   )
1540 	{
1541 	   assert(heur != NULL);
1542 	
1543 	   heur->freq = freq;
1544 	}
1545 	
1546 	/** gets frequency offset of primal heuristic */
1547 	int SCIPheurGetFreqofs(
1548 	   SCIP_HEUR*            heur                /**< primal heuristic */
1549 	   )
1550 	{
1551 	   assert(heur != NULL);
1552 	
1553 	   return heur->freqofs;
1554 	}
1555 	
1556 	/** gets maximal depth level for calling primal heuristic (returns -1, if no depth limit exists) */
1557 	int SCIPheurGetMaxdepth(
1558 	   SCIP_HEUR*            heur                /**< primal heuristic */
1559 	   )
1560 	{
1561 	   assert(heur != NULL);
1562 	
1563 	   return heur->maxdepth;
1564 	}
1565 	
1566 	/** gets the number of times, the heuristic was called and tried to find a solution */
1567 	SCIP_Longint SCIPheurGetNCalls(
1568 	   SCIP_HEUR*            heur                /**< primal heuristic */
1569 	   )
1570 	{
1571 	   assert(heur != NULL);
1572 	
1573 	   return heur->ncalls;
1574 	}
1575 	
1576 	/** gets the number of primal feasible solutions found by this heuristic */
1577 	SCIP_Longint SCIPheurGetNSolsFound(
1578 	   SCIP_HEUR*            heur                /**< primal heuristic */
1579 	   )
1580 	{
1581 	   assert(heur != NULL);
1582 	
1583 	   return heur->nsolsfound;
1584 	}
1585 	
1586 	/** gets the number of new best primal feasible solutions found by this heuristic */
1587 	SCIP_Longint SCIPheurGetNBestSolsFound(
1588 	   SCIP_HEUR*            heur                /**< primal heuristic */
1589 	   )
1590 	{
1591 	   assert(heur != NULL);
1592 	
1593 	   return heur->nbestsolsfound;
1594 	}
1595 	
1596 	/** is primal heuristic initialized? */
1597 	SCIP_Bool SCIPheurIsInitialized(
1598 	   SCIP_HEUR*            heur                /**< primal heuristic */
1599 	   )
1600 	{
1601 	   assert(heur != NULL);
1602 	
1603 	   return heur->initialized;
1604 	}
1605 	
1606 	/** enables or disables all clocks of \p heur, depending on the value of the flag */
1607 	void SCIPheurEnableOrDisableClocks(
1608 	   SCIP_HEUR*            heur,               /**< the heuristic for which all clocks should be enabled or disabled */
1609 	   SCIP_Bool             enable              /**< should the clocks of the heuristic be enabled? */
1610 	   )
1611 	{
1612 	   assert(heur != NULL);
1613 	
1614 	   SCIPclockEnableOrDisable(heur->setuptime, enable);
1615 	   SCIPclockEnableOrDisable(heur->heurclock, enable);
1616 	}
1617 	
1618 	/** gets time in seconds used in this heuristic for setting up for next stages */
1619 	SCIP_Real SCIPheurGetSetupTime(
1620 	   SCIP_HEUR*            heur                /**< primal heuristic */
1621 	   )
1622 	{
1623 	   assert(heur != NULL);
1624 	
1625 	   return SCIPclockGetTime(heur->setuptime);
1626 	}
1627 	
1628 	/** gets time in seconds used in this heuristic */
1629 	SCIP_Real SCIPheurGetTime(
1630 	   SCIP_HEUR*            heur                /**< primal heuristic */
1631 	   )
1632 	{
1633 	   assert(heur != NULL);
1634 	
1635 	   return SCIPclockGetTime(heur->heurclock);
1636 	}
1637 	
1638 	/** returns array of divesets of this primal heuristic, or NULL if it has no divesets */
1639 	SCIP_DIVESET** SCIPheurGetDivesets(
1640 	   SCIP_HEUR*            heur                /**< primal heuristic */
1641 	   )
1642 	{
1643 	   assert(heur != NULL);
1644 	
1645 	   return heur->divesets;
1646 	}
1647 	
1648 	/** returns the number of divesets of this primal heuristic */
1649 	int SCIPheurGetNDivesets(
1650 	   SCIP_HEUR*            heur                /**< primal heuristic */
1651 	   )
1652 	{
1653 	   assert(heur != NULL);
1654 	
1655 	   return heur->ndivesets;
1656 	}
1657 	
1658 	/** Perform breadth-first (BFS) search on the variable constraint graph.
1659 	 *
1660 	 *  The result of the algorithm is that the \p distances array contains the correct distances for
1661 	 *  every variable from the start variables. The distance of a variable can then be accessed through its
1662 	 *  problem index (calling SCIPvarGetProbindex()).
1663 	 *  Hence, The method assumes that the length of \p distances is at least
1664 	 *  SCIPgetNVars().
1665 	 *  Variables that are not connected through constraints to the start variables have a distance of -1.
1666 	 *
1667 	 *  Limits can be provided to further restrict the breadth-first search. If a distance limit is given,
1668 	 *  the search will be performed until the first variable at this distance is popped from the queue, i.e.,
1669 	 *  all variables with a distance < maxdistance have been labeled by the search.
1670 	 *  If a variable limit is given, the search stops after it completes the distance level at which
1671 	 *  the limit was reached. Hence, more variables may be actually labeled.
1672 	 *  The start variables are accounted for those variable limits.
1673 	 *
1674 	 *  If no variable variable constraint graph is provided, the method will create one and free it at the end
1675 	 *  This is useful for a single use of the variable constraint graph. For several consecutive uses,
1676 	 *  it is advised to create a variable constraint graph via SCIPvariableGraphCreate().
1677 	 */
1678 	SCIP_RETCODE SCIPvariablegraphBreadthFirst(
1679 	   SCIP*                 scip,               /**< SCIP data structure */
1680 	   SCIP_VGRAPH*          vargraph,           /**< pointer to the variable graph, or NULL to let the function create a local graph */
1681 	   SCIP_VAR**            startvars,          /**< array of start variables to calculate distance from */
1682 	   int                   nstartvars,         /**< number of starting variables, at least 1 */
1683 	   int*                  distances,          /**< array to keep distance in vargraph from start variables for every variable */
1684 	   int                   maxdistance,        /**< maximum distance >= 0 from start variable (INT_MAX for complete BFS) */
1685 	   int                   maxvars,            /**< maximum number of variables to compute distance for */
1686 	   int                   maxbinintvars       /**< maximum number of binary or integer variables to compute distance for */
1687 	   )
1688 	{
1689 	   SCIP_VAR** vars;
1690 	
1691 	   int* queue;
1692 	   int  nvars;
1693 	   int i;
1694 	   int currlvlidx;
1695 	   int nextlvlidx;
1696 	   int increment = 1;
1697 	   int currentdistance;
1698 	   int nbinintvarshit;
1699 	   int nvarshit;
1700 	   int nbinvars;
1701 	   int nintvars;
1702 	   int nbinintvars;
1703 	   SCIP_VAR** varbuffer;
1704 	   SCIP_Bool localvargraph;
1705 	
1706 	   assert(scip != NULL);
1707 	   assert(startvars != NULL);
1708 	   assert(nstartvars >= 1);
1709 	   assert(distances != NULL);
1710 	   assert(maxdistance >= 0);
1711 	
1712 	   /* get variable data */
(1) Event cond_false: Condition "(_restat_ = SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL)) != SCIP_OKAY", taking false branch.
(2) Event if_end: End of if statement.
1713 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
1714 	   nbinintvars = nbinvars + nintvars;
1715 	
(3) Event cond_false: Condition "(queue = BMSallocBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)nvars, 4UL /* sizeof (*queue) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/heur.c", 1716)) == NULL", taking false branch.
(4) Event cond_false: Condition "(_restat_ = (((queue = BMSallocBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)nvars, 4UL /* sizeof (*queue) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/heur.c", 1716)) == NULL) ? SCIP_NOMEMORY : SCIP_OKAY)) != SCIP_OKAY", taking false branch.
(5) Event if_end: End of if statement.
1716 	   SCIP_CALL( SCIPallocBufferArray(scip, &queue, nvars) );
(6) Event cond_false: Condition "(varbuffer = BMSallocClearBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)nvars, 8UL /* sizeof (*varbuffer) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/heur.c", 1717)) == NULL", taking false branch.
(7) Event cond_false: Condition "(_restat_ = (((varbuffer = BMSallocClearBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)nvars, 8UL /* sizeof (*varbuffer) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/heur.c", 1717)) == NULL) ? SCIP_NOMEMORY : SCIP_OKAY)) != SCIP_OKAY", taking false branch.
(8) Event if_end: End of if statement.
1717 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &varbuffer, nvars) );
1718 	
1719 	   /* create a variable graph locally for this method, if none is provided */
(9) Event cond_true: Condition "vargraph == NULL", taking true branch.
(10) Event var_compare_op: Comparing "vargraph" to null implies that "vargraph" might be null.
Also see events: [no_write_call][var_deref_op]
1720 	   if( vargraph == NULL )
1721 	   {
(11) Event no_write_call: Although "SCIPvariableGraphCreate" does overwrite "vargraph" on some paths, it also contains at least one feasible path which does not overwrite it.
(12) Event cond_false: Condition "(_restat_ = SCIPvariableGraphCreate(scip, &vargraph, 0, 1., NULL)) != SCIP_OKAY", taking false branch.
(13) Event if_end: End of if statement.
Also see events: [var_compare_op][var_deref_op]
1722 	      SCIP_CALL( SCIPvariableGraphCreate(scip, &vargraph, FALSE, 1.0, NULL) );
1723 	      localvargraph = TRUE;
(14) Event if_fallthrough: Falling through to end of if statement.
1724 	   }
1725 	   else
(15) Event if_end: End of if statement.
1726 	      localvargraph = FALSE;
1727 	
(16) Event var_deref_op: Dereferencing null pointer "vargraph".
Also see events: [var_compare_op][no_write_call]
1728 	   SCIPhashtableRemoveAll(vargraph->visitedconss);
1729 	
1730 	   /* initialize distances to -1 */
1731 	   for( i = 0; i < nvars; ++i )
1732 	   {
1733 	      queue[i] = -1;
1734 	      distances[i] = -1;
1735 	   }
1736 	
1737 	   nvarshit = 0;
1738 	   nbinintvarshit = 0;
1739 	   /* initialize distances for starting variables and add them to the queue */
1740 	   for( i = 0; i < nstartvars; ++i )
1741 	   {
1742 	      int probindex = SCIPvarGetProbindex(startvars[i]);
1743 	      assert(probindex >= 0);
1744 	      /* start variables have a distance of 0 */
1745 	      distances[probindex] = 0;
1746 	      queue[i] = probindex;
1747 	      nvarshit++;
1748 	
1749 	      if( probindex < nbinintvars )
1750 	         nbinintvarshit++;
1751 	   }
1752 	   currlvlidx = 0;
1753 	   nextlvlidx = nvars - 1;
1754 	
1755 	   /* loop over the queue and pop the next variable, starting with start variables */
1756 	   do
1757 	   {
1758 	      SCIP_VAR* currvar;
1759 	      int c;
1760 	      int varpos;
1761 	
1762 	      currvar = vars[queue[currlvlidx]];
1763 	      varpos = SCIPvarGetProbindex(currvar);
1764 	      currentdistance = distances[varpos];
1765 	      assert(currentdistance >= 0);
1766 	
1767 	      /* distances must only be computed up to maxdistance  */
1768 	      assert(currentdistance <= maxdistance);
1769 	
1770 	      /* check for termination because maximum distance has been reached */
1771 	      if( currentdistance == maxdistance )
1772 	         break;
1773 	
1774 	      assert(varpos >= 0);
1775 	
1776 	      /* loop over variable constraints and enqueue variables that were not visited yet */
1777 	      for( c = 0; c < vargraph->nvarconss[varpos]; ++c )
1778 	      {
1779 	         int nconsvars;
1780 	         int v;
1781 	         SCIP_Bool success;
1782 	         SCIP_CONS* cons = vargraph->varconss[varpos][c];
1783 	
1784 	         /* check first if this constraint has already been visited */
1785 	         if( SCIPhashtableExists(vargraph->visitedconss, (void *)cons) )
1786 	            continue;
1787 	
1788 	         /* request number of constraint variables */
1789 	         SCIP_CALL( SCIPgetConsNVars(scip, cons, &nconsvars, &success) );
1790 	
1791 	         if( !success )
1792 	            continue;
1793 	
1794 	         /* collect constraint variables in buffer */
1795 	         SCIP_CALL( SCIPgetConsVars(scip, cons, varbuffer, nvars, &success) );
1796 	
1797 	         if( !success )
1798 	            continue;
1799 	
1800 	         /* collect previously unvisited variables of the constraint and enqueue them for breadth-first search */
1801 	         for( v = 0; v < nconsvars; ++v )
1802 	         {
1803 	            SCIP_VAR* nextvar = varbuffer[v];
1804 	            int nextvarpos;
1805 	            assert(nextvar != NULL);
1806 	            if( !SCIPvarIsActive(nextvar) )
1807 	               continue;
1808 	
1809 	            nextvarpos = SCIPvarGetProbindex(nextvar);
1810 	            assert(nextvarpos >= 0);
1811 	
1812 	            /* insert variables that were not considered yet into the next level queue */
1813 	            if( distances[nextvarpos] == -1 )
1814 	            {
1815 	               distances[nextvarpos] = currentdistance + 1;
1816 	               queue[nextlvlidx] = nextvarpos;
1817 	               nextlvlidx -= increment;
1818 	
1819 	               nvarshit++;
1820 	               if( nextvarpos < nbinintvars )
1821 	                  ++nbinintvarshit;
1822 	            }
1823 	         } /* end constraint variables loop */
1824 	
1825 	         /* mark the constraint as visited */
1826 	         SCIP_CALL( SCIPhashtableInsert(vargraph->visitedconss, (void *)cons) );
1827 	      } /* end constraint loop */
1828 	
1829 	      queue[currlvlidx] = -1;
1830 	      currlvlidx += increment;
1831 	
1832 	      /* check if we need to swap current and next level index and reverse the increment */
1833 	      if( currlvlidx == nvars || currlvlidx == 0 || queue[currlvlidx] == -1 || currlvlidx == nextlvlidx )
1834 	      {
1835 	         /* break early if the distance has been determined for enough variables */
1836 	         if( nvarshit >= maxvars || nbinintvarshit >= maxbinintvars )
1837 	            break;
1838 	
1839 	         /* increment knows whether we are currently looping upwards (all variables with odd distance) or downwards the
1840 	          * queue
1841 	          */
1842 	         if( increment == +1 )
1843 	         {
1844 	            currlvlidx = nvars - 1;
1845 	            nextlvlidx = 0;
1846 	            increment = -1;
1847 	         }
1848 	         else
1849 	         {
1850 	            currlvlidx = 0;
1851 	            nextlvlidx = nvars - 1;
1852 	            increment = +1;
1853 	         }
1854 	      }
1855 	   }
1856 	   while( queue[currlvlidx] != -1 && distances[queue[currlvlidx]] >= currentdistance );
1857 	
1858 	   SCIPfreeBufferArray(scip, &varbuffer);
1859 	   SCIPfreeBufferArray(scip, &queue);
1860 	
1861 	   /* free also the variable graph, if it wasn't provided by the caller */
1862 	   if( localvargraph )
1863 	   {
1864 	      SCIPvariableGraphFree(scip, &vargraph);
1865 	   }
1866 	
1867 	   return SCIP_OKAY;
1868 	}
1869 	
1870 	/* fills variable graph data structure
1871 	 *
1872 	 * loops over global problem constraints and creates a mapping from the variables to their respective constraints
1873 	 */
1874 	static
1875 	SCIP_RETCODE fillVariableGraph(
1876 	   SCIP*                 scip,               /**< SCIP data structure */
1877 	   SCIP_VGRAPH*          vargraph,           /**< variable graph data structure for breadth-first-search neighborhoods */
1878 	   SCIP_Bool             relaxdenseconss,    /**< should dense constraints (at least as dense as \p density) be
1879 	                                              *   ignored by connectivity graph? */
1880 	   SCIP_Real             relaxdensity,       /**< density (with respect to number of variables) to relax constraint from graph */
1881 	   int*                  nrelaxedconstraints  /**< pointer to store the number of constraints that were relaxed, or NULL if not needed */
1882 	   )
1883 	{
1884 	   SCIP_CONS** conss;
1885 	   int nconss;
1886 	   int nvars;
1887 	   int c;
1888 	   int relaxlimit;
1889 	   SCIP_VAR** varbuffer;
1890 	
1891 	   assert(scip != NULL);
1892 	   assert(vargraph != NULL);
1893 	
1894 	   conss = SCIPgetConss(scip);
1895 	   nconss = SCIPgetNConss(scip);
1896 	
1897 	   nvars = SCIPgetNVars(scip);
1898 	   SCIP_CALL( SCIPallocBufferArray(scip, &varbuffer, nvars) );
1899 	
1900 	   if( nrelaxedconstraints != NULL )
1901 	      *nrelaxedconstraints = 0;
1902 	
1903 	   relaxlimit = (int)(relaxdensity * nvars);
1904 	
1905 	   for( c = 0; c < nconss; ++c )
1906 	   {
1907 	      int nconsvars;
1908 	      int v;
1909 	      SCIP_Bool success;
1910 	      SCIP_CONS* cons = conss[c];
1911 	
1912 	      /* we only consider constraints that are checkable */
1913 	      if( !SCIPconsIsChecked(cons) )
1914 	         continue;
1915 	
1916 	      /* request number of variables */
1917 	      SCIP_CALL( SCIPgetConsNVars(scip, cons, &nconsvars, &success) );
1918 	
1919 	      if( !success )
1920 	         continue;
1921 	
1922 	      /* relax constraints with density above the allowed number of free variables */
1923 	      if( relaxdenseconss && nconsvars >= relaxlimit )
1924 	      {
1925 	         if( nrelaxedconstraints != NULL )
1926 	            ++(*nrelaxedconstraints);
1927 	
1928 	         continue;
1929 	      }
1930 	
1931 	      /* collect constraint variables in buffer */
1932 	      SCIP_CALL( SCIPgetConsVars(scip, cons, varbuffer, nvars, &success) );
1933 	
1934 	      if( !success )
1935 	         continue;
1936 	
1937 	      /* loop over constraint variables and add this constraint to them if they are active */
1938 	      for( v = 0; v < nconsvars; ++v )
1939 	      {
1940 	         int varpos = SCIPvarGetProbindex(varbuffer[v]);
1941 	
1942 	         /* skip inactive variables */
1943 	         if( varpos == -1 )
1944 	            continue;
1945 	
1946 	         /* ensure array size */
1947 	         if( vargraph->varconssize[varpos] == vargraph->nvarconss[varpos]  )
1948 	         {
1949 	            int newmem = SCIPcalcMemGrowSize(scip, vargraph->nvarconss[varpos] + 1);
1950 	
1951 	            assert(newmem > vargraph->varconssize[varpos]);
1952 	
1953 	            if( vargraph->varconss[varpos] == NULL )
1954 	            {
1955 	               SCIP_CALL( SCIPallocBlockMemoryArray(scip, &vargraph->varconss[varpos], newmem) );
1956 	            }
1957 	            else
1958 	            {
1959 	               SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &vargraph->varconss[varpos], vargraph->varconssize[varpos], newmem) ); /*lint !e866*/
1960 	            }
1961 	            vargraph->varconssize[varpos] = newmem;
1962 	         }
1963 	
1964 	         assert(vargraph->nvarconss[varpos] < vargraph->varconssize[varpos]);
1965 	
1966 	         /* add constraint to constraint array for this variable */
1967 	         vargraph->varconss[varpos][vargraph->nvarconss[varpos]] = cons;
1968 	         vargraph->nvarconss[varpos] += 1;
1969 	      }
1970 	   }
1971 	
1972 	   /* free the buffer */
1973 	   SCIPfreeBufferArray(scip, &varbuffer);
1974 	
1975 	   return SCIP_OKAY;
1976 	}
1977 	
1978 	/** initialization method of variable graph data structure */
1979 	SCIP_RETCODE SCIPvariableGraphCreate(
1980 	   SCIP*                 scip,               /**< SCIP data structure */
1981 	   SCIP_VGRAPH**         vargraph,           /**< pointer to the variable graph */
1982 	   SCIP_Bool             relaxdenseconss,    /**< should dense constraints (at least as dense as \p density) be
1983 	                                              *   ignored by connectivity graph? */
1984 	   SCIP_Real             relaxdensity,       /**< density (with respect to number of variables) to relax constraint from graph */
1985 	   int*                  nrelaxedconstraints  /**< pointer to store the number of constraints that were relaxed, or NULL if not needed */
1986 	   )
1987 	{
1988 	   int nvars;
1989 	   int nconss;
1990 	
1991 	   assert(scip != NULL);
1992 	   assert(vargraph != NULL);
1993 	
1994 	   nvars = SCIPgetNVars(scip);
1995 	   nconss = SCIPgetNConss(scip);
1996 	
1997 	   if( nvars == 0 )
1998 	      return SCIP_OKAY;
1999 	
2000 	   SCIP_CALL( SCIPallocBlockMemory(scip, vargraph) );
2001 	
2002 	   SCIP_CALL( SCIPhashtableCreate(&(*vargraph)->visitedconss, SCIPblkmem(scip), 2 * nconss, SCIPhashGetKeyStandard,
2003 	         SCIPhashKeyEqPtr, SCIPhashKeyValPtr, NULL) );
2004 	
2005 	   /* allocate and clear memory */
2006 	   SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(*vargraph)->varconss, nvars) );
2007 	   SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(*vargraph)->nvarconss, nvars) );
2008 	   SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(*vargraph)->varconssize, nvars) );
2009 	
2010 	   /* fill the variable graph with variable-constraint mapping for breadth-first search*/
2011 	   SCIP_CALL( fillVariableGraph(scip, *vargraph, relaxdenseconss, relaxdensity, nrelaxedconstraints) );
2012 	
2013 	   return SCIP_OKAY;
2014 	}
2015 	
2016 	/** deinitialization method of variable graph data structure */
2017 	void SCIPvariableGraphFree(
2018 	   SCIP*                 scip,               /**< SCIP data structure */
2019 	   SCIP_VGRAPH**         vargraph            /**< pointer to the variable graph */
2020 	   )
2021 	{
2022 	   int nvars;
2023 	   int v;
2024 	   assert(scip != NULL);
2025 	   assert(vargraph != NULL);
2026 	
2027 	   nvars = SCIPgetNVars(scip);
2028 	
2029 	   for( v = nvars - 1; v >= 0; --v )
2030 	   {
2031 	      SCIPfreeBlockMemoryArrayNull(scip, &(*vargraph)->varconss[v], (*vargraph)->varconssize[v]); /*lint !e866*/
2032 	   }
2033 	
2034 	   /* allocate and clear memory */
2035 	   SCIPfreeBlockMemoryArray(scip, &(*vargraph)->varconssize, nvars);
2036 	   SCIPfreeBlockMemoryArray(scip, &(*vargraph)->nvarconss, nvars);
2037 	   SCIPfreeBlockMemoryArray(scip, &(*vargraph)->varconss, nvars);
2038 	
2039 	   SCIPhashtableFree(&(*vargraph)->visitedconss);
2040 	
2041 	   SCIPfreeBlockMemory(scip, vargraph);
2042 	}
2043