1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2021 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_alns.c
17   	 * @ingroup DEFPLUGINS_HEUR
18   	 * @brief  Adaptive large neighborhood search heuristic that orchestrates popular LNS heuristics
19   	 * @author Gregor Hendel
20   	 */
21   	
22   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23   	
24   	#include "blockmemshell/memory.h"
25   	#include "scip/cons_linear.h"
26   	#include "scip/heur_alns.h"
27   	#include "scip/heuristics.h"
28   	#include "scip/pub_bandit_epsgreedy.h"
29   	#include "scip/pub_bandit_exp3.h"
30   	#include "scip/pub_bandit.h"
31   	#include "scip/pub_bandit_ucb.h"
32   	#include "scip/pub_cons.h"
33   	#include "scip/pub_event.h"
34   	#include "scip/pub_heur.h"
35   	#include "scip/pub_message.h"
36   	#include "scip/pub_misc.h"
37   	#include "scip/pub_misc_select.h"
38   	#include "scip/pub_sol.h"
39   	#include "scip/pub_var.h"
40   	#include "scip/scip_bandit.h"
41   	#include "scip/scip_branch.h"
42   	#include "scip/scip_cons.h"
43   	#include "scip/scip_copy.h"
44   	#include "scip/scip_event.h"
45   	#include "scip/scip_general.h"
46   	#include "scip/scip_heur.h"
47   	#include "scip/scip_lp.h"
48   	#include "scip/scip_mem.h"
49   	#include "scip/scip_message.h"
50   	#include "scip/scip_nodesel.h"
51   	#include "scip/scip_numerics.h"
52   	#include "scip/scip_param.h"
53   	#include "scip/scip_prob.h"
54   	#include "scip/scip_randnumgen.h"
55   	#include "scip/scip_sol.h"
56   	#include "scip/scip_solve.h"
57   	#include "scip/scip_solvingstats.h"
58   	#include "scip/scip_table.h"
59   	#include "scip/scip_timing.h"
60   	#include "scip/scip_tree.h"
61   	#include "scip/scip_var.h"
62   	#include <string.h>
63   	
64   	#if !defined(_WIN32) && !defined(_WIN64)
65   	#include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
66   	#endif
67   	
68   	#define HEUR_NAME             "alns"
69   	#define HEUR_DESC             "Large neighborhood search heuristic that orchestrates the popular neighborhoods Local Branching, RINS, RENS, DINS etc."
70   	#define HEUR_DISPCHAR         SCIP_HEURDISPCHAR_LNS
71   	#define HEUR_PRIORITY         -1100500
72   	#define HEUR_FREQ             20
73   	#define HEUR_FREQOFS          0
74   	#define HEUR_MAXDEPTH         -1
75   	#define HEUR_TIMING           SCIP_HEURTIMING_AFTERNODE | SCIP_HEURTIMING_DURINGLPLOOP
76   	#define HEUR_USESSUBSCIP      TRUE  /**< does the heuristic use a secondary SCIP instance? */
77   	
78   	#define NNEIGHBORHOODS 9
79   	
80   	/*
81   	 * limit parameters for sub-SCIPs
82   	 */
83   	#define DEFAULT_NODESQUOT        0.1
84   	#define DEFAULT_NODESQUOTMIN     0.0
85   	#define DEFAULT_NODESOFFSET      500LL
86   	#define DEFAULT_NSOLSLIM         3
87   	#define DEFAULT_MINNODES         50LL
88   	#define DEFAULT_MAXNODES         5000LL
89   	#define DEFAULT_WAITINGNODES     25LL  /**< number of nodes since last incumbent solution that the heuristic should wait */
90   	#define DEFAULT_TARGETNODEFACTOR 1.05
91   	#define LRATEMIN                 0.01 /**<  lower bound for learning rate for target nodes and minimum improvement */
92   	#define LPLIMFAC                 4.0
93   	#define DEFAULT_INITDURINGROOT FALSE
94   	#define DEFAULT_MAXCALLSSAMESOL  -1   /**< number of allowed executions of the heuristic on the same incumbent solution */
95   	
96   	/*
97   	 * parameters for the minimum improvement
98   	 */
99   	#define DEFAULT_MINIMPROVELOW    0.01
100  	#define DEFAULT_MINIMPROVEHIGH   0.01
101  	#define MINIMPROVEFAC            1.5
102  	#define DEFAULT_STARTMINIMPROVE  0.01
103  	#define DEFAULT_ADJUSTMINIMPROVE FALSE
104  	#define DEFAULT_ADJUSTTARGETNODES TRUE /**< should the target nodes be dynamically adjusted? */
105  	
106  	/*
107  	 * bandit algorithm parameters
108  	 */
109  	#define DEFAULT_BESTSOLWEIGHT  1
110  	#define DEFAULT_BANDITALGO     'u'  /**< the default bandit algorithm: (u)pper confidence bounds, (e)xp.3, epsilon (g)reedy */
111  	#define DEFAULT_REWARDCONTROL  0.8  /**< reward control to increase the weight of the simple solution indicator and decrease the weight of the closed gap reward */
112  	#define DEFAULT_SCALEBYEFFORT  TRUE /**< should the reward be scaled by the effort? */
113  	#define DEFAULT_RESETWEIGHTS   TRUE /**< should the bandit algorithms be reset when a new problem is read? */
114  	#define DEFAULT_SUBSCIPRANDSEEDS FALSE /**< should random seeds of sub-SCIPs be altered to increase diversification? */
115  	#define DEFAULT_REWARDBASELINE 0.5  /**< the reward baseline to separate successful and failed calls */
116  	#define DEFAULT_FIXTOL         0.1  /**< tolerance by which the fixing rate may be missed without generic fixing */
117  	#define DEFAULT_UNFIXTOL       0.1  /**< tolerance by which the fixing rate may be exceeded without generic unfixing */
118  	#define DEFAULT_USELOCALREDCOST FALSE /**< should local reduced costs be used for generic (un)fixing? */
119  	#define DEFAULT_BETA           0.0  /**< default reward offset between 0 and 1 at every observation for exp3 */
120  	
121  	/*
122  	 * the following 3 parameters have been tuned by a simulation experiment
123  	 * as described in the paper.
124  	 */
125  	#define DEFAULT_EPS            0.4685844   /**< increase exploration in epsilon-greedy bandit algorithm */
126  	#define DEFAULT_ALPHA          0.0016      /**< parameter to increase the confidence width in UCB */
127  	#define DEFAULT_GAMMA          0.07041455  /**< default weight between uniform (gamma ~ 1) and weight driven (gamma ~ 0) probability distribution for exp3 */
128  	/*
129  	 * parameters to control variable fixing
130  	 */
131  	#define DEFAULT_USEREDCOST       TRUE  /**< should reduced cost scores be used for variable priorization? */
132  	#define DEFAULT_USEPSCOST        TRUE  /**< should pseudo cost scores be used for variable priorization? */
133  	#define DEFAULT_USEDISTANCES     TRUE  /**< should distances from fixed variables be used for variable priorization */
134  	#define DEFAULT_DOMOREFIXINGS    TRUE  /**< should the ALNS heuristic do more fixings by itself based on variable prioritization
135  	                                         *  until the target fixing rate is reached? */
136  	#define DEFAULT_ADJUSTFIXINGRATE TRUE  /**< should the heuristic adjust the target fixing rate based on the success? */
137  	#define FIXINGRATE_DECAY         0.75  /**< geometric decay for fixing rate adjustments */
138  	#define FIXINGRATE_STARTINC      0.2   /**< initial increment value for fixing rate */
139  	#define DEFAULT_USESUBSCIPHEURS  FALSE /**< should the heuristic activate other sub-SCIP heuristics during its search?  */
140  	#define DEFAULT_COPYCUTS         FALSE /**< should cutting planes be copied to the sub-SCIP? */
141  	#define DEFAULT_REWARDFILENAME   "-"   /**< file name to store all rewards and the selection of the bandit */
142  	
143  	/* individual random seeds */
144  	#define DEFAULT_SEED 113
145  	#define MUTATIONSEED 121
146  	#define CROSSOVERSEED 321
147  	
148  	/* individual neighborhood parameters */
149  	#define DEFAULT_MINFIXINGRATE_RENS 0.3
150  	#define DEFAULT_MAXFIXINGRATE_RENS 0.9
151  	#define DEFAULT_ACTIVE_RENS TRUE
152  	#define DEFAULT_PRIORITY_RENS 1.0
153  	
154  	#define DEFAULT_MINFIXINGRATE_RINS 0.3
155  	#define DEFAULT_MAXFIXINGRATE_RINS 0.9
156  	#define DEFAULT_ACTIVE_RINS TRUE
157  	#define DEFAULT_PRIORITY_RINS 1.0
158  	
159  	#define DEFAULT_MINFIXINGRATE_MUTATION 0.3
160  	#define DEFAULT_MAXFIXINGRATE_MUTATION 0.9
161  	#define DEFAULT_ACTIVE_MUTATION TRUE
162  	#define DEFAULT_PRIORITY_MUTATION 1.0
163  	
164  	#define DEFAULT_MINFIXINGRATE_LOCALBRANCHING 0.3
165  	#define DEFAULT_MAXFIXINGRATE_LOCALBRANCHING 0.9
166  	#define DEFAULT_ACTIVE_LOCALBRANCHING TRUE
167  	#define DEFAULT_PRIORITY_LOCALBRANCHING 1.0
168  	
169  	#define DEFAULT_MINFIXINGRATE_PROXIMITY 0.3
170  	#define DEFAULT_MAXFIXINGRATE_PROXIMITY 0.9
171  	#define DEFAULT_ACTIVE_PROXIMITY TRUE
172  	#define DEFAULT_PRIORITY_PROXIMITY 1.0
173  	
174  	#define DEFAULT_MINFIXINGRATE_CROSSOVER 0.3
175  	#define DEFAULT_MAXFIXINGRATE_CROSSOVER 0.9
176  	#define DEFAULT_ACTIVE_CROSSOVER TRUE
177  	#define DEFAULT_PRIORITY_CROSSOVER 1.0
178  	
179  	#define DEFAULT_MINFIXINGRATE_ZEROOBJECTIVE 0.3
180  	#define DEFAULT_MAXFIXINGRATE_ZEROOBJECTIVE 0.9
181  	#define DEFAULT_ACTIVE_ZEROOBJECTIVE TRUE
182  	#define DEFAULT_PRIORITY_ZEROOBJECTIVE 1.0
183  	
184  	#define DEFAULT_MINFIXINGRATE_DINS 0.3
185  	#define DEFAULT_MAXFIXINGRATE_DINS 0.9
186  	#define DEFAULT_ACTIVE_DINS TRUE
187  	#define DEFAULT_PRIORITY_DINS 1.0
188  	
189  	#define DEFAULT_MINFIXINGRATE_TRUSTREGION 0.3
190  	#define DEFAULT_MAXFIXINGRATE_TRUSTREGION 0.9
191  	#define DEFAULT_ACTIVE_TRUSTREGION FALSE
192  	#define DEFAULT_PRIORITY_TRUSTREGION 1.0
193  	
194  	
195  	#define DEFAULT_NSOLS_CROSSOVER 2 /**< parameter for the number of solutions that crossover should combine */
196  	#define DEFAULT_NPOOLSOLS_DINS  5 /**< number of pool solutions where binary solution values must agree */
197  	#define DEFAULT_VIOLPENALTY_TRUSTREGION 100.0  /**< the penalty for violating the trust region */
198  	
199  	/* event handler properties */
200  	#define EVENTHDLR_NAME         "Alns"
201  	#define EVENTHDLR_DESC         "LP event handler for " HEUR_NAME " heuristic"
202  	#define SCIP_EVENTTYPE_ALNS (SCIP_EVENTTYPE_LPSOLVED | SCIP_EVENTTYPE_SOLFOUND | SCIP_EVENTTYPE_BESTSOLFOUND)
203  	
204  	/* properties of the ALNS neighborhood statistics table */
205  	#define TABLE_NAME_NEIGHBORHOOD                  "neighborhood"
206  	#define TABLE_DESC_NEIGHBORHOOD                  "ALNS neighborhood statistics"
207  	#define TABLE_POSITION_NEIGHBORHOOD              12500                  /**< the position of the statistics table */
208  	#define TABLE_EARLIEST_STAGE_NEIGHBORHOOD        SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
209  	
210  	
211  	/** reward types of ALNS */
212  	enum RewardType {
213  	   REWARDTYPE_TOTAL,                         /**< combination of the other rewards */
214  	   REWARDTYPE_BESTSOL,                       /**< 1, if a new solution was found, 0 otherwise */
215  	   REWARDTYPE_CLOSEDGAP,                           /**< 0 if no solution was found, closed gap otherwise */
216  	   REWARDTYPE_NOSOLPENALTY,                  /**< 1 if a solution was found, otherwise between 0 and 1 depending on the effort spent  */
217  	   NREWARDTYPES
218  	};
219  	
220  	/*
221  	 * Data structures
222  	 */
223  	
224  	/*
225  	 * additional neighborhood data structures
226  	 */
227  	
228  	
229  	typedef struct data_crossover DATA_CROSSOVER; /**< crossover neighborhood data structure */
230  	
231  	typedef struct data_mutation DATA_MUTATION; /**< mutation neighborhood data structure */
232  	
233  	typedef struct data_dins DATA_DINS; /**< dins neighborhood data structure */
234  	
235  	typedef struct data_trustregion DATA_TRUSTREGION; /**< trustregion neighborhood data structure */
236  	
237  	typedef struct NH_FixingRate NH_FIXINGRATE; /** fixing rate data structure */
238  	
239  	typedef struct NH_Stats NH_STATS; /**< neighborhood statistics data structure */
240  	
241  	typedef struct Nh NH;             /**< neighborhood data structure */
242  	
243  	
244  	/*
245  	 * variable priorization data structure for sorting
246  	 */
247  	typedef struct VarPrio VARPRIO;
248  	
249  	/** callback to collect variable fixings of neighborhood */
250  	 #define DECL_VARFIXINGS(x) SCIP_RETCODE x ( \
251  	   SCIP*                 scip,               /**< SCIP data structure */                     \
252  	   NH*                   neighborhood,       /**< ALNS neighborhood data structure */         \
253  	   SCIP_VAR**            varbuf,             /**< buffer array to collect variables to fix */\
254  	   SCIP_Real*            valbuf,             /**< buffer array to collect fixing values */   \
255  	   int*                  nfixings,           /**< pointer to store the number of fixings */  \
256  	   SCIP_RESULT*          result              /**< result pointer */                          \
257  	   )
258  	
259  	/** callback for subproblem changes other than variable fixings
260  	 *
261  	 *  this callback can be used to further modify the subproblem by changes other than variable fixings.
262  	 *  Typical modifications include restrictions of variable domains, the formulation of additional constraints,
263  	 *  or changed objective coefficients.
264  	 *
265  	 *  The callback should set the \p success pointer to indicate whether it was successful with its modifications or not.
266  	 */
267  	#define DECL_CHANGESUBSCIP(x) SCIP_RETCODE x (  \
268  	   SCIP*                 sourcescip,         /**< source SCIP data structure */\
269  	   SCIP*                 targetscip,         /**< target SCIP data structure */\
270  	   NH*                   neighborhood,       /**< ALNS neighborhood data structure */\
271  	   SCIP_VAR**            subvars,            /**< array of targetscip variables in the same order as the source SCIP variables */\
272  	   int*                  ndomchgs,           /**< pointer to store the number of performed domain changes */\
273  	   int*                  nchgobjs,           /**< pointer to store the number of changed objective coefficients */ \
274  	   int*                  naddedconss,        /**< pointer to store the number of additional constraints */\
275  	   SCIP_Bool*            success             /**< pointer to store if the sub-MIP was successfully adjusted */\
276  	   )
277  	
278  	/** optional initialization callback for neighborhoods when a new problem is read */
279  	#define DECL_NHINIT(x) SCIP_RETCODE x (                                          \
280  	   SCIP*                 scip,               /**< SCIP data structure */         \
281  	   NH*                   neighborhood        /**< neighborhood data structure */ \
282  	   )
283  	
284  	/** deinitialization callback for neighborhoods when exiting a problem */
285  	#define DECL_NHEXIT(x) SCIP_RETCODE x ( \
286  	   SCIP*                 scip,               /**< SCIP data structure */         \
287  	   NH*                   neighborhood        /**< neighborhood data structure */ \
288  	   )
289  	
290  	/** deinitialization callback for neighborhoods before SCIP is freed */
291  	#define DECL_NHFREE(x) SCIP_RETCODE x (      \
292  	   SCIP*                 scip,               /**< SCIP data structure */         \
293  	   NH*                   neighborhood        /**< neighborhood data structure */ \
294  	   )
295  	
296  	/** callback function to return a feasible reference solution for further fixings
297  	 *
298  	 *  The reference solution should be stored in the \p solptr.
299  	 *  The \p result pointer can be used to indicate either
300  	 *
301  	 *  - SCIP_SUCCESS or
302  	 *  - SCIP_DIDNOTFIND
303  	 */
304  	#define DECL_NHREFSOL(x) SCIP_RETCODE x (                                       \
305  	   SCIP*                 scip,               /**< SCIP data structure */  \
306  	   NH*                   neighborhood,       /**< neighborhood data structure */ \
307  	   SCIP_SOL**            solptr,             /**< pointer to store the reference solution */ \
308  	   SCIP_RESULT*          result              /**< pointer to indicate the callback success whether a reference solution is available */ \
309  	   )
310  	
311  	/** callback function to deactivate neighborhoods on problems where they are irrelevant */
312  	#define DECL_NHDEACTIVATE(x) SCIP_RETCODE x (\
313  	   SCIP*                 scip,               /**< SCIP data structure */  \
314  	   SCIP_Bool*            deactivate          /**< pointer to store whether the neighborhood should be deactivated (TRUE) for an instance */ \
315  	   )
316  	
317  	/** sub-SCIP status code enumerator */
318  	enum HistIndex
319  	{
320  	   HIDX_OPT              = 0,                /**< sub-SCIP was solved to optimality  */
321  	   HIDX_USR              = 1,                /**< sub-SCIP was user interrupted */
322  	   HIDX_NODELIM          = 2,                /**< sub-SCIP reached the node limit */
323  	   HIDX_STALLNODE        = 3,                /**< sub-SCIP reached the stall node limit */
324  	   HIDX_INFEAS           = 4,                /**< sub-SCIP was infeasible */
325  	   HIDX_SOLLIM           = 5,                /**< sub-SCIP reached the solution limit */
326  	   HIDX_OTHER            = 6                 /**< sub-SCIP reached none of the above codes */
327  	};
328  	typedef enum HistIndex HISTINDEX;
329  	#define NHISTENTRIES 7
330  	
331  	
332  	/** statistics for a neighborhood */
333  	struct NH_Stats
334  	{
335  	   SCIP_CLOCK*           setupclock;         /**< clock for sub-SCIP setup time */
336  	   SCIP_CLOCK*           submipclock;        /**< clock for the sub-SCIP solve */
337  	   SCIP_Longint          usednodes;          /**< total number of used nodes */
338  	   SCIP_Real             oldupperbound;      /**< upper bound before the sub-SCIP started */
339  	   SCIP_Real             newupperbound;      /**< new upper bound for allrewards mode to work correctly */
340  	   int                   nruns;              /**< number of runs of a neighborhood */
341  	   int                   nrunsbestsol;       /**< number of runs that produced a new incumbent */
342  	   SCIP_Longint          nsolsfound;         /**< the total number of solutions found */
343  	   SCIP_Longint          nbestsolsfound;     /**< the total number of improving solutions found */
344  	   int                   nfixings;           /**< the number of fixings in one run */
345  	   int                   statushist[NHISTENTRIES]; /**< array to count sub-SCIP statuses */
346  	};
347  	
348  	
349  	/** fixing rate data structure to control the amount of target fixings of a neighborhood */
350  	struct NH_FixingRate
351  	{
352  	   SCIP_Real             minfixingrate;      /**< the minimum fixing rate */
353  	   SCIP_Real             targetfixingrate;   /**< the current target fixing rate */
354  	   SCIP_Real             increment;          /**< the current increment by which the target fixing rate is in-/decreased */
355  	   SCIP_Real             maxfixingrate;      /**< the maximum fixing rate */
356  	};
357  	
358  	/** neighborhood data structure with callbacks, statistics, fixing rate */
359  	struct Nh
360  	{
361  	   char*                 name;               /**< the name of this neighborhood */
362  	   NH_FIXINGRATE         fixingrate;         /**< fixing rate for this neighborhood */
363  	   NH_STATS              stats;              /**< statistics for this neighborhood */
364  	   DECL_VARFIXINGS       ((*varfixings));    /**< variable fixings callback for this neighborhood */
365  	   DECL_CHANGESUBSCIP    ((*changesubscip)); /**< callback for subproblem changes other than variable fixings */
366  	   DECL_NHINIT           ((*nhinit));        /**< initialization callback when a new problem is read */
367  	   DECL_NHEXIT           ((*nhexit));        /**< deinitialization callback when exiting a problem */
368  	   DECL_NHFREE           ((*nhfree));        /**< deinitialization callback before SCIP is freed */
369  	   DECL_NHREFSOL         ((*nhrefsol));      /**< callback function to return a reference solution for further fixings, or NULL */
370  	   DECL_NHDEACTIVATE     ((*nhdeactivate));  /**< callback function to deactivate neighborhoods on problems where they are irrelevant, or NULL if it is always active */
371  	   SCIP_Bool             active;             /**< is this neighborhood active or not? */
372  	   SCIP_Real             priority;           /**< positive call priority to initialize bandit algorithms */
373  	   union
374  	   {
375  	      DATA_MUTATION*     mutation;           /**< mutation data */
376  	      DATA_CROSSOVER*    crossover;          /**< crossover data */
377  	      DATA_DINS*         dins;               /**< dins data */
378  	      DATA_TRUSTREGION*  trustregion;        /**< trustregion data */
379  	   }                     data;               /**< data object for neighborhood specific data */
380  	};
381  	
382  	/** mutation neighborhood data structure */
383  	struct data_mutation
384  	{
385  	   SCIP_RANDNUMGEN*      rng;                /**< random number generator */
386  	};
387  	
388  	/** crossover neighborhood data structure */
389  	struct data_crossover
390  	{
391  	   int                   nsols;              /**< the number of solutions that crossover should combine */
392  	   SCIP_RANDNUMGEN*      rng;                /**< random number generator to draw from the solution pool */
393  	   SCIP_SOL*             selsol;             /**< best selected solution by crossover as reference point */
394  	};
395  	
396  	/** dins neighborhood data structure */
397  	struct data_dins
398  	{
399  	   int                   npoolsols;          /**< number of pool solutions where binary solution values must agree */
400  	};
401  	
402  	struct data_trustregion
403  	{
404  	   SCIP_Real             violpenalty;        /**< the penalty for violating the trust region */
405  	};
406  	
407  	/** primal heuristic data */
408  	struct SCIP_HeurData
409  	{
410  	   NH**                  neighborhoods;      /**< array of neighborhoods */
411  	   SCIP_BANDIT*          bandit;             /**< bandit algorithm */
412  	   SCIP_SOL*             lastcallsol;        /**< incumbent when the heuristic was last called */
413  	   char*                 rewardfilename;     /**< file name to store all rewards and the selection of the bandit */
414  	   FILE*                 rewardfile;         /**< reward file pointer, or NULL */
415  	   SCIP_Longint          nodesoffset;        /**< offset added to the nodes budget */
416  	   SCIP_Longint          maxnodes;           /**< maximum number of nodes in a single sub-SCIP */
417  	   SCIP_Longint          targetnodes;        /**< targeted number of nodes to start a sub-SCIP */
418  	   SCIP_Longint          minnodes;           /**< minimum number of nodes required to start a sub-SCIP */
419  	   SCIP_Longint          usednodes;          /**< total number of nodes already spent in sub-SCIPs */
420  	   SCIP_Longint          waitingnodes;       /**< number of nodes since last incumbent solution that the heuristic should wait */
421  	   SCIP_Real             nodesquot;          /**< fraction of nodes compared to the main SCIP for budget computation */
422  	   SCIP_Real             nodesquotmin;       /**< lower bound on fraction of nodes compared to the main SCIP for budget computation */
423  	   SCIP_Real             startminimprove;    /**< initial factor by which ALNS should at least improve the incumbent */
424  	   SCIP_Real             minimprovelow;      /**< lower threshold for the minimal improvement over the incumbent */
425  	   SCIP_Real             minimprovehigh;     /**< upper bound for the minimal improvement over the incumbent */
426  	   SCIP_Real             minimprove;         /**< factor by which ALNS should at least improve the incumbent */
427  	   SCIP_Real             lplimfac;           /**< limit fraction of LPs per node to interrupt sub-SCIP */
428  	   SCIP_Real             exp3_gamma;         /**< weight between uniform (gamma ~ 1) and weight driven (gamma ~ 0) probability distribution for exp3 */
429  	   SCIP_Real             exp3_beta;          /**< reward offset between 0 and 1 at every observation for exp3 */
430  	   SCIP_Real             epsgreedy_eps;      /**< increase exploration in epsilon-greedy bandit algorithm */
431  	   SCIP_Real             ucb_alpha;          /**< parameter to increase the confidence width in UCB */
432  	   SCIP_Real             rewardcontrol;      /**< reward control to increase the weight of the simple solution indicator
433  	                                               *  and decrease the weight of the closed gap reward */
434  	   SCIP_Real             targetnodefactor;   /**< factor by which target node number is eventually increased */
435  	   SCIP_Real             rewardbaseline;     /**< the reward baseline to separate successful and failed calls */
436  	   SCIP_Real             fixtol;             /**< tolerance by which the fixing rate may be missed without generic fixing */
437  	   SCIP_Real             unfixtol;           /**< tolerance by which the fixing rate may be exceeded without generic unfixing */
438  	   int                   nneighborhoods;     /**< number of neighborhoods */
439  	   int                   nactiveneighborhoods;/**< number of active neighborhoods */
440  	   int                   ninitneighborhoods; /**< neighborhoods that were used at least one time */
441  	   int                   nsolslim;           /**< limit on the number of improving solutions in a sub-SCIP call */
442  	   int                   seed;               /**< initial random seed for bandit algorithms and random decisions by neighborhoods */
443  	   int                   currneighborhood;   /**< index of currently selected neighborhood */
444  	   int                   ndelayedcalls;      /**< the number of delayed calls */
445  	   int                   maxcallssamesol;    /**< number of allowed executions of the heuristic on the same incumbent solution
446  	                                              *   (-1: no limit, 0: number of active neighborhoods) */
447  	   SCIP_Longint          firstcallthissol;   /**< counter for the number of calls on this incumbent */
448  	   char                  banditalgo;         /**< the bandit algorithm: (u)pper confidence bounds, (e)xp.3, epsilon (g)reedy */
449  	   SCIP_Bool             useredcost;         /**< should reduced cost scores be used for variable prioritization? */
450  	   SCIP_Bool             usedistances;       /**< should distances from fixed variables be used for variable prioritization */
451  	   SCIP_Bool             usepscost;          /**< should pseudo cost scores be used for variable prioritization? */
452  	   SCIP_Bool             domorefixings;      /**< should the ALNS heuristic do more fixings by itself based on variable prioritization
453  	                                               *  until the target fixing rate is reached? */
454  	   SCIP_Bool             adjustfixingrate;   /**< should the heuristic adjust the target fixing rate based on the success? */
455  	   SCIP_Bool             usesubscipheurs;    /**< should the heuristic activate other sub-SCIP heuristics during its search?  */
456  	   SCIP_Bool             adjustminimprove;   /**< should the factor by which the minimum improvement is bound be dynamically updated? */
457  	   SCIP_Bool             adjusttargetnodes;  /**< should the target nodes be dynamically adjusted? */
458  	   SCIP_Bool             resetweights;       /**< should the bandit algorithms be reset when a new problem is read? */
459  	   SCIP_Bool             subsciprandseeds;   /**< should random seeds of sub-SCIPs be altered to increase diversification? */
460  	   SCIP_Bool             scalebyeffort;      /**< should the reward be scaled by the effort? */
461  	   SCIP_Bool             copycuts;           /**< should cutting planes be copied to the sub-SCIP? */
462  	   SCIP_Bool             uselocalredcost;    /**< should local reduced costs be used for generic (un)fixing? */
463  	   SCIP_Bool             initduringroot;     /**< should the heuristic be executed multiple times during the root node? */
464  	};
465  	
466  	/** event handler data */
467  	struct SCIP_EventData
468  	{
469  	   SCIP_VAR**            subvars;            /**< the variables of the subproblem */
470  	   SCIP*                 sourcescip;         /**< original SCIP data structure */
471  	   SCIP_HEUR*            heur;               /**< alns heuristic structure */
472  	   SCIP_Longint          nodelimit;          /**< node limit of the run */
473  	   SCIP_Real             lplimfac;           /**< limit fraction of LPs per node to interrupt sub-SCIP */
474  	   NH_STATS*             runstats;           /**< run statistics for the current neighborhood */
475  	   SCIP_Bool             allrewardsmode;     /**< true if solutions should only be checked for reward comparisons */
476  	};
477  	
478  	/** represents limits for the sub-SCIP solving process */
479  	struct SolveLimits
480  	{
481  	   SCIP_Longint          nodelimit;          /**< maximum number of solving nodes for the sub-SCIP */
482  	   SCIP_Real             memorylimit;        /**< memory limit for the sub-SCIP */
483  	   SCIP_Real             timelimit;          /**< time limit for the sub-SCIP */
484  	   SCIP_Longint          stallnodes;         /**< maximum number of nodes without (primal) stalling */
485  	};
486  	
487  	typedef struct SolveLimits SOLVELIMITS;
488  	
489  	/** data structure that can be used for variable prioritization for additional fixings */
490  	struct VarPrio
491  	{
492  	   SCIP*                 scip;               /**< SCIP data structure */
493  	   SCIP_Real*            randscores;         /**< random scores for prioritization */
494  	   int*                  distances;          /**< breadth-first distances from already fixed variables */
495  	   SCIP_Real*            redcostscores;      /**< reduced cost scores for fixing a variable to a reference value */
496  	   SCIP_Real*            pscostscores;       /**< pseudocost scores for fixing a variable to a reference value */
497  	   unsigned int          useredcost:1;       /**< should reduced cost scores be used for variable prioritization? */
498  	   unsigned int          usedistances:1;     /**< should distances from fixed variables be used for variable prioritization */
499  	   unsigned int          usepscost:1;        /**< should pseudo cost scores be used for variable prioritization? */
500  	};
501  	
502  	/*
503  	 * Local methods
504  	 */
505  	
506  	/** Reset target fixing rate */
507  	static
508  	SCIP_RETCODE resetFixingRate(
509  	   SCIP*                 scip,               /**< SCIP data structure */
510  	   NH_FIXINGRATE*        fixingrate          /**< heuristic fixing rate */
511  	   )
512  	{
513  	   assert(scip != NULL);
514  	   assert(fixingrate != NULL);
515  	   fixingrate->increment = FIXINGRATE_STARTINC;
516  	
517  	   /* always start with the most conservative value */
518  	   fixingrate->targetfixingrate = fixingrate->maxfixingrate;
519  	
520  	   return SCIP_OKAY;
521  	}
522  	
523  	/** reset the currently active neighborhood */
524  	static
525  	void resetCurrentNeighborhood(
526  	   SCIP_HEURDATA*        heurdata
527  	   )
528  	{
529  	   assert(heurdata != NULL);
530  	   heurdata->currneighborhood = -1;
531  	   heurdata->ndelayedcalls = 0;
532  	}
533  	
534  	/** update increment for fixing rate */
535  	static
536  	void updateFixingRateIncrement(
537  	   NH_FIXINGRATE*        fx                  /**< fixing rate */
538  	   )
539  	{
540  	   fx->increment *= FIXINGRATE_DECAY;
541  	   fx->increment = MAX(fx->increment, LRATEMIN);
542  	}
543  	
544  	
545  	/** increase fixing rate
546  	 *
547  	 *  decrease also the rate by which the target fixing rate is adjusted
548  	 */
549  	static
550  	void increaseFixingRate(
551  	   NH_FIXINGRATE*        fx                  /**< fixing rate */
552  	   )
553  	{
554  	   fx->targetfixingrate += fx->increment;
555  	   fx->targetfixingrate = MIN(fx->targetfixingrate, fx->maxfixingrate);
556  	}
557  	
558  	/** decrease fixing rate
559  	 *
560  	 *  decrease also the rate by which the target fixing rate is adjusted
561  	 */
562  	static
563  	void decreaseFixingRate(
564  	   NH_FIXINGRATE*        fx                  /**< fixing rate */
565  	   )
566  	{
567  	   fx->targetfixingrate -= fx->increment;
568  	   fx->targetfixingrate = MAX(fx->targetfixingrate, fx->minfixingrate);
569  	}
570  	
571  	/** update fixing rate based on the results of the current run */
572  	static
573  	void updateFixingRate(
574  	   NH*                   neighborhood,       /**< neighborhood */
575  	   SCIP_STATUS           subscipstatus,      /**< status of the sub-SCIP run */
576  	   NH_STATS*             runstats            /**< run statistics for this run */
577  	   )
578  	{
579  	   NH_FIXINGRATE* fx;
580  	
581  	   fx = &neighborhood->fixingrate;
582  	
583  	   switch (subscipstatus)
584  	   {
585  	   case SCIP_STATUS_OPTIMAL:
586  	   case SCIP_STATUS_INFEASIBLE:
587  	   case SCIP_STATUS_INFORUNBD:
588  	   case SCIP_STATUS_SOLLIMIT:
589  	   case SCIP_STATUS_BESTSOLLIMIT:
590  	      /* decrease the fixing rate (make subproblem harder) */
591  	      decreaseFixingRate(fx);
592  	      break;
593  	   case SCIP_STATUS_STALLNODELIMIT:
594  	   case SCIP_STATUS_USERINTERRUPT:
595  	   case SCIP_STATUS_TERMINATE:
596  	   case SCIP_STATUS_NODELIMIT:
597  	      /* increase the fixing rate (make the subproblem easier) only if no solution was found */
598  	      if( runstats->nbestsolsfound <= 0 )
599  	         increaseFixingRate(fx);
600  	      break;
601  	      /* fall through cases to please lint */
602  	   case SCIP_STATUS_UNKNOWN:
603  	   case SCIP_STATUS_TOTALNODELIMIT:
604  	   case SCIP_STATUS_TIMELIMIT:
605  	   case SCIP_STATUS_MEMLIMIT:
606  	   case SCIP_STATUS_GAPLIMIT:
607  	   case SCIP_STATUS_RESTARTLIMIT:
608  	   case SCIP_STATUS_UNBOUNDED:
609  	   default:
610  	      break;
611  	   }
612  	
613  	   updateFixingRateIncrement(fx);
614  	}
615  	
616  	/** increase target node limit */
617  	static
618  	void increaseTargetNodeLimit(
619  	   SCIP_HEURDATA*        heurdata            /**< heuristic data */
620  	   )
621  	{
622  	   heurdata->targetnodes = (SCIP_Longint)(heurdata->targetnodes * heurdata->targetnodefactor) + 1;
623  	
624  	   /* respect upper and lower parametrized bounds on targetnodes */
625  	   if( heurdata->targetnodes > heurdata->maxnodes )
626  	      heurdata->targetnodes = heurdata->maxnodes;
627  	}
628  	
629  	/** reset target node limit */
630  	static
631  	void resetTargetNodeLimit(
632  	   SCIP_HEURDATA*        heurdata            /**< heuristic data */
633  	   )
634  	{
635  	   heurdata->targetnodes = heurdata->minnodes;
636  	}
637  	
638  	/** update target node limit based on the current run results */
639  	static
640  	void updateTargetNodeLimit(
641  	   SCIP_HEURDATA*        heurdata,           /**< heuristic data */
642  	   NH_STATS*             runstats,           /**< statistics of the run */
643  	   SCIP_STATUS           subscipstatus       /**< status of the sub-SCIP run */
644  	   )
645  	{
646  	   switch (subscipstatus)
647  	   {
648  	   case SCIP_STATUS_STALLNODELIMIT:
649  	   case SCIP_STATUS_NODELIMIT:
650  	      /* the subproblem could be explored more */
651  	      if( runstats->nbestsolsfound == 0 )
652  	         increaseTargetNodeLimit(heurdata);
653  	      break;
654  	   case SCIP_STATUS_OPTIMAL:
655  	   case SCIP_STATUS_INFEASIBLE:
656  	   case SCIP_STATUS_INFORUNBD:
657  	   case SCIP_STATUS_SOLLIMIT:
658  	   case SCIP_STATUS_BESTSOLLIMIT:
659  	      break;
660  	   case SCIP_STATUS_USERINTERRUPT:
661  	   case SCIP_STATUS_TERMINATE:
662  	   case SCIP_STATUS_UNKNOWN:
663  	   case SCIP_STATUS_TOTALNODELIMIT:
664  	   case SCIP_STATUS_TIMELIMIT:
665  	   case SCIP_STATUS_MEMLIMIT:
666  	   case SCIP_STATUS_GAPLIMIT:
667  	   case SCIP_STATUS_RESTARTLIMIT:
668  	   case SCIP_STATUS_UNBOUNDED:
669  	      break;
670  	   default:
671  	      break;
672  	   }
673  	}
674  	
675  	/** reset the minimum improvement for the sub-SCIPs */
676  	static
677  	void resetMinimumImprovement(
678  	   SCIP_HEURDATA*        heurdata            /**< heuristic data */
679  	   )
680  	{
681  	   assert(heurdata != NULL);
682  	   heurdata->minimprove = heurdata->startminimprove;
683  	}
684  	
685  	/** increase minimum improvement for the sub-SCIPs */
686  	static
687  	void increaseMinimumImprovement(
688  	   SCIP_HEURDATA*        heurdata            /**< heuristic data */
689  	   )
690  	{
691  	   assert(heurdata != NULL);
692  	
693  	   heurdata->minimprove *= MINIMPROVEFAC;
694  	   heurdata->minimprove = MIN(heurdata->minimprove, heurdata->minimprovehigh);
695  	}
696  	
697  	/** decrease the minimum improvement for the sub-SCIPs */
698  	static
699  	void decreaseMinimumImprovement(
700  	   SCIP_HEURDATA*        heurdata            /**< heuristic data */
701  	   )
702  	{
703  	   assert(heurdata != NULL);
704  	
705  	   heurdata->minimprove /= MINIMPROVEFAC;
706  	   SCIPdebugMessage("%.4f", heurdata->minimprovelow);
707  	   heurdata->minimprove = MAX(heurdata->minimprove, heurdata->minimprovelow);
708  	}
709  	
710  	/** update the minimum improvement based on the status of the sub-SCIP */
711  	static
712  	void updateMinimumImprovement(
713  	   SCIP_HEURDATA*        heurdata,           /**< heuristic data */
714  	   SCIP_STATUS           subscipstatus,      /**< status of the sub-SCIP run */
715  	   NH_STATS*             runstats            /**< run statistics for this run */
716  	   )
717  	{
718  	   assert(heurdata != NULL);
719  	
720  	   /* if the sub-SCIP status was infeasible, we rather want to make the sub-SCIP easier
721  	    * with a smaller minimum improvement.
722  	    *
723  	    * If a solution limit was reached, we may, set it higher.
724  	    */
725  	   switch (subscipstatus)
726  	   {
727  	   case SCIP_STATUS_INFEASIBLE:
728  	   case SCIP_STATUS_INFORUNBD:
729  	      /* subproblem was infeasible, probably due to the minimum improvement -> decrease minimum improvement */
730  	      decreaseMinimumImprovement(heurdata);
731  	
732  	      break;
733  	   case SCIP_STATUS_SOLLIMIT:
734  	   case SCIP_STATUS_BESTSOLLIMIT:
735  	   case SCIP_STATUS_OPTIMAL:
736  	      /* subproblem could be optimally solved -> try higher minimum improvement */
737  	      increaseMinimumImprovement(heurdata);
738  	      break;
739  	   case SCIP_STATUS_NODELIMIT:
740  	   case SCIP_STATUS_STALLNODELIMIT:
741  	   case SCIP_STATUS_USERINTERRUPT:
742  	      /* subproblem was too hard, decrease minimum improvement */
743  	      if( runstats->nbestsolsfound <= 0 )
744  	         decreaseMinimumImprovement(heurdata);
745  	      break;
746  	   case SCIP_STATUS_UNKNOWN:
747  	   case SCIP_STATUS_TOTALNODELIMIT:
748  	   case SCIP_STATUS_TIMELIMIT:
749  	   case SCIP_STATUS_MEMLIMIT:
750  	   case SCIP_STATUS_GAPLIMIT:
751  	   case SCIP_STATUS_RESTARTLIMIT:
752  	   case SCIP_STATUS_UNBOUNDED:
753  	   case SCIP_STATUS_TERMINATE:
754  	   default:
755  	      break;
756  	   }
757  	}
758  	
759  	/** Reset neighborhood statistics */
760  	static
761  	SCIP_RETCODE neighborhoodStatsReset(
762  	   SCIP*                 scip,               /**< SCIP data structure */
763  	   NH_STATS*             stats               /**< neighborhood statistics */
764  	   )
765  	{
766  	   assert(scip != NULL);
767  	   assert(stats != NULL);
768  	
769  	   stats->nbestsolsfound = 0;
770  	   stats->nruns = 0;
771  	   stats->nrunsbestsol = 0;
772  	   stats->nsolsfound = 0;
773  	   stats->usednodes = 0L;
774  	   stats->nfixings = 0L;
775  	
776  	   BMSclearMemoryArray(stats->statushist, NHISTENTRIES);
777  	
778  	   SCIP_CALL( SCIPresetClock(scip, stats->setupclock) );
779  	   SCIP_CALL( SCIPresetClock(scip, stats->submipclock) );
780  	
781  	   return SCIP_OKAY;
782  	}
783  	
784  	/** create a neighborhood of the specified name and include it into the ALNS heuristic */
785  	static
786  	SCIP_RETCODE alnsIncludeNeighborhood(
787  	   SCIP*                 scip,               /**< SCIP data structure */
788  	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS heuristic */
789  	   NH**                  neighborhood,       /**< pointer to store the neighborhood */
790  	   const char*           name,               /**< name for this neighborhood */
791  	   SCIP_Real             minfixingrate,      /**< default value for minfixingrate parameter of this neighborhood */
792  	   SCIP_Real             maxfixingrate,      /**< default value for maxfixingrate parameter of this neighborhood */
793  	   SCIP_Bool             active,             /**< default value for active parameter of this neighborhood */
794  	   SCIP_Real             priority,           /**< positive call priority to initialize bandit algorithms */
795  	   DECL_VARFIXINGS       ((*varfixings)),    /**< variable fixing callback for this neighborhood, or NULL */
796  	   DECL_CHANGESUBSCIP    ((*changesubscip)), /**< subscip changes callback for this neighborhood, or NULL */
797  	   DECL_NHINIT           ((*nhinit)),        /**< initialization callback for neighborhood, or NULL */
798  	   DECL_NHEXIT           ((*nhexit)),        /**< deinitialization callback for neighborhood, or NULL */
799  	   DECL_NHFREE           ((*nhfree)),        /**< deinitialization callback before SCIP is freed, or NULL */
800  	   DECL_NHREFSOL         ((*nhrefsol)),      /**< callback function to return a reference solution for further fixings, or NULL */
801  	   DECL_NHDEACTIVATE     ((*nhdeactivate))   /**< callback function to deactivate neighborhoods on problems where they are irrelevant, or NULL if neighborhood is always active */
802  	   )
803  	{
804  	   char paramname[SCIP_MAXSTRLEN];
805  	
806  	   assert(scip != NULL);
807  	   assert(heurdata != NULL);
808  	   assert(neighborhood != NULL);
809  	   assert(name != NULL);
810  	
811  	   SCIP_CALL( SCIPallocBlockMemory(scip, neighborhood) );
812  	   assert(*neighborhood != NULL);
813  	
814  	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*neighborhood)->name, name, strlen(name)+1) );
815  	
816  	   SCIP_CALL( SCIPcreateClock(scip, &(*neighborhood)->stats.setupclock) );
817  	   SCIP_CALL( SCIPcreateClock(scip, &(*neighborhood)->stats.submipclock) );
818  	
819  	   (*neighborhood)->changesubscip = changesubscip;
820  	   (*neighborhood)->varfixings = varfixings;
821  	   (*neighborhood)->nhinit = nhinit;
822  	   (*neighborhood)->nhexit = nhexit;
823  	   (*neighborhood)->nhfree = nhfree;
824  	   (*neighborhood)->nhrefsol = nhrefsol;
825  	   (*neighborhood)->nhdeactivate = nhdeactivate;
826  	
827  	   /* add parameters for this neighborhood */
828  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/alns/%s/minfixingrate", name);
829  	   SCIP_CALL( SCIPaddRealParam(scip, paramname, "minimum fixing rate for this neighborhood",
830  	         &(*neighborhood)->fixingrate.minfixingrate, TRUE, minfixingrate, 0.0, 1.0, NULL, NULL) );
831  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/alns/%s/maxfixingrate", name);
832  	   SCIP_CALL( SCIPaddRealParam(scip, paramname, "maximum fixing rate for this neighborhood",
833  	         &(*neighborhood)->fixingrate.maxfixingrate, TRUE, maxfixingrate, 0.0, 1.0, NULL, NULL) );
834  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/alns/%s/active", name);
835  	   SCIP_CALL( SCIPaddBoolParam(scip, paramname, "is this neighborhood active?",
836  	         &(*neighborhood)->active, TRUE, active, NULL, NULL) );
837  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/alns/%s/priority", name);
838  	   SCIP_CALL( SCIPaddRealParam(scip, paramname, "positive call priority to initialize bandit algorithms",
839  	         &(*neighborhood)->priority, TRUE, priority, 1e-2, 1.0, NULL, NULL) );
840  	
841  	   /* add the neighborhood to the ALNS heuristic */
842  	   heurdata->neighborhoods[heurdata->nneighborhoods++] = (*neighborhood);
843  	
844  	   return SCIP_OKAY;
845  	}
846  	
847  	/** release all data and free neighborhood */
848  	static
849  	SCIP_RETCODE alnsFreeNeighborhood(
850  	   SCIP*                 scip,               /**< SCIP data structure */
851  	   NH**                  neighborhood        /**< pointer to neighborhood that should be freed */
852  	   )
853  	{
854  	   NH* nhptr;
855  	   assert(scip != NULL);
856  	   assert(neighborhood != NULL);
857  	
858  	   nhptr = *neighborhood;
859  	   assert(nhptr != NULL);
860  	
861  	   BMSfreeMemoryArray(&nhptr->name);
862  	
863  	   /* release further, neighborhood specific data structures */
864  	   if( nhptr->nhfree != NULL )
865  	   {
866  	      SCIP_CALL( nhptr->nhfree(scip, nhptr) );
867  	   }
868  	
869  	   SCIP_CALL( SCIPfreeClock(scip, &nhptr->stats.setupclock) );
870  	   SCIP_CALL( SCIPfreeClock(scip, &nhptr->stats.submipclock) );
871  	
872  	   SCIPfreeBlockMemory(scip, neighborhood);
873  	   *neighborhood = NULL;
874  	
875  	   return SCIP_OKAY;
876  	}
877  	
878  	/** initialize neighborhood specific data */
879  	static
880  	SCIP_RETCODE neighborhoodInit(
881  	   SCIP*                 scip,               /**< SCIP data structure */
882  	   NH*                   neighborhood        /**< neighborhood to initialize */
883  	   )
884  	{
885  	   assert(scip != NULL);
886  	   assert(neighborhood != NULL);
887  	
888  	   /* call the init callback of the neighborhood */
889  	   if( neighborhood->nhinit != NULL )
890  	   {
891  	      SCIP_CALL( neighborhood->nhinit(scip, neighborhood) );
892  	   }
893  	
894  	   return SCIP_OKAY;
895  	}
896  	
897  	/** deinitialize neighborhood specific data */
898  	static
899  	SCIP_RETCODE neighborhoodExit(
900  	   SCIP*                 scip,               /**< SCIP data structure */
901  	   NH*                   neighborhood        /**< neighborhood to initialize */
902  	   )
903  	{
904  	   assert(scip != NULL);
905  	   assert(neighborhood != NULL);
906  	
907  	   if( neighborhood->nhexit != NULL )
908  	   {
909  	      SCIP_CALL( neighborhood->nhexit(scip, neighborhood) );
910  	   }
911  	
912  	   return SCIP_OKAY;
913  	}
914  	
915  	/** creates a new solution for the original problem by copying the solution of the subproblem */
916  	static
917  	SCIP_RETCODE transferSolution(
918  	   SCIP*                 subscip,            /**< SCIP data structure of the subproblem */
919  	   SCIP_EVENTDATA*       eventdata           /**< event handler data */
920  	   )
921  	{
922  	   SCIP*      sourcescip;         /* original SCIP data structure */
923  	   SCIP_VAR** subvars;            /* the variables of the subproblem */
924  	   SCIP_HEUR* heur;               /* alns heuristic structure */
925  	   SCIP_SOL*  subsol;             /* solution of the subproblem */
926  	   SCIP_SOL*  newsol;             /* solution to be created for the original problem */
927  	   SCIP_Bool  success;
928  	   NH_STATS*  runstats;
929  	   SCIP_SOL*  oldbestsol;
930  	
931  	   assert(subscip != NULL);
932  	
933  	   subsol = SCIPgetBestSol(subscip);
934  	   assert(subsol != NULL);
935  	
936  	   sourcescip = eventdata->sourcescip;
937  	   subvars = eventdata->subvars;
938  	   heur = eventdata->heur;
939  	   runstats = eventdata->runstats;
940  	   assert(sourcescip != NULL);
941  	   assert(sourcescip != subscip);
942  	   assert(heur != NULL);
943  	   assert(subvars != NULL);
944  	   assert(runstats != NULL);
945  	
946  	   SCIP_CALL( SCIPtranslateSubSol(sourcescip, subscip, subsol, heur, subvars, &newsol) );
947  	
948  	   oldbestsol = SCIPgetBestSol(sourcescip);
949  	
950  	   /* in the special, experimental all rewards mode, the solution is only checked for feasibility
951  	    * but not stored
952  	    */
953  	   if( eventdata->allrewardsmode )
954  	   {
955  	      SCIP_CALL( SCIPcheckSol(sourcescip, newsol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
956  	
957  	      if( success )
958  	      {
959  	         runstats->nsolsfound++;
960  	         if( SCIPgetSolTransObj(sourcescip, newsol) < SCIPgetCutoffbound(sourcescip) )
961  	            runstats->nbestsolsfound++;
962  	      }
963  	
964  	      SCIP_CALL( SCIPfreeSol(sourcescip, &newsol) );
965  	   }
966  	   else
967  	   {
968  	      /* try to add new solution to scip and free it immediately */
969  	      SCIP_CALL( SCIPtrySolFree(sourcescip, &newsol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
970  	
971  	      if( success )
972  	      {
973  	         runstats->nsolsfound++;
974  	         if( SCIPgetBestSol(sourcescip) != oldbestsol )
975  	            runstats->nbestsolsfound++;
976  	      }
977  	   }
978  	
979  	   /* update new upper bound for reward later */
980  	   runstats->newupperbound = SCIPgetUpperbound(sourcescip);
981  	
982  	   return SCIP_OKAY;
983  	}
984  	
985  	
986  	/* ---------------- Callback methods of event handler ---------------- */
987  	
988  	/** execution callback of the event handler
989  	 *
990  	 * transfer new solutions or interrupt the solving process manually
991  	 */
992  	static
993  	SCIP_DECL_EVENTEXEC(eventExecAlns)
994  	{
995  	   assert(eventhdlr != NULL);
996  	   assert(eventdata != NULL);
997  	   assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
998  	   assert(event != NULL);
999  	   assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_ALNS);
1000 	   assert(eventdata != NULL);
1001 	
1002 	   /* treat the different atomic events */
1003 	   switch( SCIPeventGetType(event) )
1004 	   {
1005 	   case SCIP_EVENTTYPE_SOLFOUND:
1006 	   case SCIP_EVENTTYPE_BESTSOLFOUND:
1007 	      /* try to transfer the solution to the original SCIP */
1008 	      SCIP_CALL( transferSolution(scip, eventdata) );
1009 	      break;
1010 	   case SCIP_EVENTTYPE_LPSOLVED:
1011 	      /* interrupt solution process of sub-SCIP */
1012 	      if( SCIPgetNLPs(scip) > eventdata->lplimfac * eventdata->nodelimit )
1013 	      {
1014 	         SCIPdebugMsg(scip, "interrupt after  %" SCIP_LONGINT_FORMAT " LPs\n", SCIPgetNLPs(scip));
1015 	         SCIP_CALL( SCIPinterruptSolve(scip) );
1016 	      }
1017 	      break;
1018 	   default:
1019 	      break;
1020 	   }
1021 	
1022 	   return SCIP_OKAY;
1023 	}
1024 	
1025 	/** initialize neighborhood statistics before the next run */
1026 	static
1027 	void initRunStats(
1028 	   SCIP*                 scip,               /**< SCIP data structure */
1029 	   NH_STATS*             stats               /**< run statistics */
1030 	   )
1031 	{
1032 	   stats->nbestsolsfound = 0;
1033 	   stats->nsolsfound = 0;
1034 	   stats->usednodes = 0L;
1035 	   stats->nfixings = 0;
1036 	   stats->oldupperbound = SCIPgetUpperbound(scip);
1037 	   stats->newupperbound = SCIPgetUpperbound(scip);
1038 	}
1039 	
1040 	/** update run stats after the sub SCIP was solved */
1041 	static
1042 	void updateRunStats(
1043 	   NH_STATS*             stats,              /**< run statistics */
1044 	   SCIP*                 subscip             /**< sub-SCIP instance, or NULL */
1045 	   )
1046 	{
1047 	   /* treat an untransformed subscip as if none was created */
1048 	   if( subscip != NULL && ! SCIPisTransformed(subscip) )
1049 	      subscip = NULL;
1050 	
1051 	   stats->usednodes = subscip != NULL ? SCIPgetNNodes(subscip) : 0L;
1052 	}
1053 	
1054 	/** get the histogram index for this status */
1055 	static
1056 	int getHistIndex(
1057 	   SCIP_STATUS           subscipstatus       /**< sub-SCIP status */
1058 	   )
1059 	{
1060 	   switch (subscipstatus)
1061 	   {
1062 	   case SCIP_STATUS_OPTIMAL:
1063 	      return (int)HIDX_OPT;
1064 	   case SCIP_STATUS_INFEASIBLE:
1065 	      return (int)HIDX_INFEAS;
1066 	   case SCIP_STATUS_NODELIMIT:
1067 	      return (int)HIDX_NODELIM;
1068 	   case SCIP_STATUS_STALLNODELIMIT:
1069 	      return (int)HIDX_STALLNODE;
1070 	   case SCIP_STATUS_SOLLIMIT:
1071 	   case SCIP_STATUS_BESTSOLLIMIT:
1072 	      return (int)HIDX_SOLLIM;
1073 	   case SCIP_STATUS_USERINTERRUPT:
1074 	      return (int)HIDX_USR;
1075 	   default:
1076 	      return (int)HIDX_OTHER;
1077 	   } /*lint !e788*/
1078 	}
1079 	
1080 	/** print neighborhood statistics */
1081 	static
1082 	void printNeighborhoodStatistics(
1083 	   SCIP*                 scip,               /**< SCIP data structure */
1084 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data */
1085 	   FILE*                 file                /**< file handle, or NULL for standard out */
1086 	   )
1087 	{
1088 	   int i;
1089 	   int j;
1090 	   HISTINDEX statusses[] = {HIDX_OPT, HIDX_INFEAS, HIDX_NODELIM, HIDX_STALLNODE, HIDX_SOLLIM, HIDX_USR, HIDX_OTHER};
1091 	
1092 	   SCIPinfoMessage(scip, file, "Neighborhoods      : %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %4s %4s %4s %4s %4s %4s %4s %4s\n",
1093 	            "Calls", "SetupTime", "SolveTime", "SolveNodes", "Sols", "Best", "Exp3", "EpsGreedy", "UCB", "TgtFixRate",
1094 	            "Opt", "Inf", "Node", "Stal", "Sol", "Usr", "Othr", "Actv");
1095 	
1096 	   /* loop over neighborhoods and fill in statistics */
1097 	   for( i = 0; i < heurdata->nneighborhoods; ++i )
1098 	   {
1099 	      NH* neighborhood;
1100 	      SCIP_Real proba;
1101 	      SCIP_Real ucb;
1102 	      SCIP_Real epsgreedyweight;
1103 	
1104 	      neighborhood = heurdata->neighborhoods[i];
1105 	      SCIPinfoMessage(scip, file, "  %-17s:", neighborhood->name);
1106 	      SCIPinfoMessage(scip, file, " %10d", neighborhood->stats.nruns);
1107 	      SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, neighborhood->stats.setupclock) );
1108 	      SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, neighborhood->stats.submipclock) );
1109 	      SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, neighborhood->stats.usednodes );
1110 	      SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, neighborhood->stats.nsolsfound);
1111 	      SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, neighborhood->stats.nbestsolsfound);
1112 	
1113 	      proba = 0.0;
1114 	      ucb = 1.0;
1115 	      epsgreedyweight = -1.0;
1116 	
1117 	      if( heurdata->bandit != NULL && i < heurdata->nactiveneighborhoods )
1118 	      {
1119 	         switch (heurdata->banditalgo)
1120 	         {
1121 	         case 'u':
1122 	            ucb = SCIPgetConfidenceBoundUcb(heurdata->bandit, i);
1123 	            break;
1124 	         case 'g':
1125 	            epsgreedyweight = SCIPgetWeightsEpsgreedy(heurdata->bandit)[i];
1126 	            break;
1127 	         case 'e':
1128 	            proba = SCIPgetProbabilityExp3(heurdata->bandit, i);
1129 	            break;
1130 	         default:
1131 	            break;
1132 	         }
1133 	      }
1134 	
1135 	      SCIPinfoMessage(scip, file, " %10.5f", proba);
1136 	      SCIPinfoMessage(scip, file, " %10.5f", epsgreedyweight);
1137 	      SCIPinfoMessage(scip, file, " %10.5f", ucb);
1138 	      SCIPinfoMessage(scip, file, " %10.3f", neighborhood->fixingrate.targetfixingrate);
1139 	
1140 	      /* loop over status histogram */
1141 	      for( j = 0; j < NHISTENTRIES; ++j )
1142 	         SCIPinfoMessage(scip, file, " %4d", neighborhood->stats.statushist[statusses[j]]);
1143 	
1144 	      SCIPinfoMessage(scip, file, " %4d", i < heurdata->nactiveneighborhoods ? 1 : 0);
1145 	      SCIPinfoMessage(scip, file, "\n");
1146 	   }
1147 	}
1148 	
1149 	/** update the statistics of the neighborhood based on the sub-SCIP run */
1150 	static
1151 	void updateNeighborhoodStats(
1152 	   NH_STATS*             runstats,           /**< run statistics */
1153 	   NH*                   neighborhood,       /**< the selected neighborhood */
1154 	   SCIP_STATUS           subscipstatus       /**< status of the sub-SCIP solve */
1155 	   )
1156 	{  /*lint --e{715}*/
1157 	   NH_STATS* stats;
1158 	   stats = &neighborhood->stats;
1159 	
1160 	   /* copy run statistics into neighborhood statistics */
1161 	   stats->nbestsolsfound += runstats->nbestsolsfound;
1162 	   stats->nsolsfound += runstats->nsolsfound;
1163 	   stats->usednodes += runstats->usednodes;
1164 	   stats->nruns += 1;
1165 	
1166 	   if( runstats->nbestsolsfound > 0 )
1167 	      stats->nrunsbestsol += DEFAULT_BESTSOLWEIGHT;
1168 	   else if( runstats->nsolsfound > 0 )
1169 	      stats->nrunsbestsol++;
1170 	
1171 	   /* update the counter for the subscip status */
1172 	   ++stats->statushist[getHistIndex(subscipstatus)];
1173 	}
1174 	
1175 	/** sort callback for variable pointers using the ALNS variable prioritization
1176 	 *
1177 	 *  the variable prioritization works hierarchically as follows. A variable
1178 	 *  a has the higher priority over b iff
1179 	 *
1180 	 *  - variable distances should be used and a has a smaller distance than b
1181 	 *  - variable reduced costs should be used and a has a smaller score than b
1182 	 *  - variable pseudo costs should be used and a has a smaller score than b
1183 	 *  - based on previously assigned random scores
1184 	 *
1185 	 *  @note: distances are context-based. For fixing more variables,
1186 	 *  distances are initialized from the already fixed variables.
1187 	 *  For unfixing variables, distances are initialized starting
1188 	 *  from the unfixed variables
1189 	 */
1190 	static
1191 	SCIP_DECL_SORTINDCOMP(sortIndCompAlns)
1192 	{  /*lint --e{715}*/
1193 	   VARPRIO* varprio;
1194 	
1195 	   varprio = (VARPRIO*)dataptr;
1196 	   assert(varprio != NULL);
1197 	   assert(varprio->randscores != NULL);
1198 	
1199 	   if( ind1 == ind2 )
1200 	      return 0;
1201 	
1202 	   /* priority is on distances, if enabled. The variable which is closer in a breadth-first search sense to
1203 	    * the already fixed variables has precedence */
1204 	   if( varprio->usedistances )
1205 	   {
1206 	      int dist1;
1207 	      int dist2;
1208 	
1209 	      dist1 = varprio->distances[ind1];
1210 	      dist2 = varprio->distances[ind2];
1211 	
1212 	      if( dist1 < 0 )
1213 	         dist1 = INT_MAX;
1214 	
1215 	      if( dist2 < 0 )
1216 	         dist2 = INT_MAX;
1217 	
1218 	      assert(varprio->distances != NULL);
1219 	      if( dist1 < dist2 )
1220 	         return -1;
1221 	      else if( dist1 > dist2 )
1222 	         return 1;
1223 	   }
1224 	
1225 	   assert(! varprio->usedistances || varprio->distances[ind1] == varprio->distances[ind2]);
1226 	
1227 	   /* if the indices tie considering distances or distances are disabled -> use reduced cost information instead */
1228 	   if( varprio->useredcost )
1229 	   {
1230 	      assert(varprio->redcostscores != NULL);
1231 	
1232 	      if( varprio->redcostscores[ind1] < varprio->redcostscores[ind2] )
1233 	         return -1;
1234 	      else if( varprio->redcostscores[ind1] > varprio->redcostscores[ind2] )
1235 	         return 1;
1236 	   }
1237 	
1238 	   /* use pseudo cost scores if reduced costs are disabled or a tie was found */
1239 	   if( varprio->usepscost )
1240 	   {
1241 	      assert(varprio->pscostscores != NULL);
1242 	
1243 	      /* prefer the variable with smaller pseudocost score */
1244 	      if( varprio->pscostscores[ind1] < varprio->pscostscores[ind2] )
1245 	         return -1;
1246 	      else if( varprio->pscostscores[ind1] > varprio->pscostscores[ind2] )
1247 	         return 1;
1248 	   }
1249 	
1250 	   if( varprio->randscores[ind1] < varprio->randscores[ind2] )
1251 	      return -1;
1252 	   else if( varprio->randscores[ind1] > varprio->randscores[ind2] )
1253 	      return 1;
1254 	
1255 	   return ind1 - ind2;
1256 	}
1257 	
1258 	/** Compute the reduced cost score for this variable in the reference solution */
1259 	static
1260 	SCIP_Real getVariableRedcostScore(
1261 	   SCIP*                 scip,               /**< SCIP data structure */
1262 	   SCIP_VAR*             var,                /**< the variable for which the score should be computed */
1263 	   SCIP_Real             refsolval,          /**< solution value in reference solution */
1264 	   SCIP_Bool             uselocalredcost     /**< should local reduced costs be used for generic (un)fixing? */
1265 	   )
1266 	{
1267 	   SCIP_Real bestbound;
1268 	   SCIP_Real redcost;
1269 	   SCIP_Real score;
1270 	   assert(scip != NULL);
1271 	   assert(var != NULL);
1272 	
1273 	   /* prefer column variables */
1274 	   if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
1275 	      return SCIPinfinity(scip);
1276 	
1277 	   if( ! uselocalredcost )
1278 	   {
1279 	      redcost = SCIPvarGetBestRootRedcost(var);
1280 	
1281 	      bestbound = SCIPvarGetBestRootSol(var);
1282 	
1283 	      /* using global reduced costs, the two factors yield a nonnegative score within tolerances */
1284 	      assert(SCIPisDualfeasZero(scip, redcost)
1285 	         || (SCIPisDualfeasNegative(scip, redcost) && ! SCIPisFeasPositive(scip, refsolval - bestbound))
1286 	         || (SCIPisDualfeasPositive(scip, redcost) && ! SCIPisFeasNegative(scip, refsolval - bestbound)));
1287 	   }
1288 	   else
1289 	   {
1290 	      /* this can be safely asserted here, since the heuristic would not reach this point, otherwise */
1291 	      assert(SCIPhasCurrentNodeLP(scip));
1292 	      assert(SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
1293 	
1294 	      redcost = SCIPgetVarRedcost(scip, var);
1295 	
1296 	      bestbound = SCIPvarGetLPSol(var);
1297 	   }
1298 	
1299 	   assert(! SCIPisInfinity(scip, REALABS(bestbound)));
1300 	   assert(SCIPisDualfeasZero(scip, redcost) || SCIPisFeasIntegral(scip, bestbound));
1301 	
1302 	   score = redcost * (refsolval - bestbound);
1303 	
1304 	   /* max out numerical inaccuracies from global scores */
1305 	   if( ! uselocalredcost )
1306 	      score = MAX(score, 0.0);
1307 	
1308 	   return score;
1309 	}
1310 	
1311 	/** get the pseudo cost score of this variable with respect to the reference solution */
1312 	static
1313 	SCIP_Real getVariablePscostScore(
1314 	   SCIP*                 scip,               /**< SCIP data structure */
1315 	   SCIP_VAR*             var,                /**< the variable for which the score should be computed */
1316 	   SCIP_Real             refsolval,          /**< solution value in reference solution */
1317 	   SCIP_Bool             uselocallpsol       /**< should local LP solution be used? */
1318 	   )
1319 	{
1320 	   SCIP_Real lpsolval;
1321 	
1322 	   assert(scip != NULL);
1323 	   assert(var != NULL);
1324 	
1325 	   /* variables that aren't LP columns have no pseudocost score */
1326 	   if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
1327 	      return 0.0;
1328 	
1329 	   lpsolval = uselocallpsol ? SCIPvarGetLPSol(var) : SCIPvarGetRootSol(var);
1330 	
1331 	   /* the score is 0.0 if the values are equal */
1332 	   if( SCIPisEQ(scip, lpsolval, refsolval) )
1333 	      return 0.0;
1334 	   else
1335 	      return SCIPgetVarPseudocostVal(scip, var, refsolval - lpsolval);
1336 	}
1337 	
1338 	/** add variable and solution value to buffer data structure for variable fixings. The method checks if
1339 	 *  the value still lies within the variable bounds. The value stays unfixed otherwise.
1340 	 */
1341 	static
1342 	void tryAdd2variableBuffer(
1343 	   SCIP*                 scip,               /**< SCIP data structure */
1344 	   SCIP_VAR*             var,                /**< (source) SCIP variable that should be added to the buffer */
1345 	   SCIP_Real             val,                /**< fixing value for this variable */
1346 	   SCIP_VAR**            varbuf,             /**< variable buffer to store variables that should be fixed */
1347 	   SCIP_Real*            valbuf,             /**< value buffer to store fixing values */
1348 	   int*                  nfixings,           /**< pointer to number of fixed buffer variables, will be increased by 1 */
1349 	   SCIP_Bool             integer             /**< is this an integer variable? */
1350 	   )
1351 	{
1352 	   assert(SCIPisFeasIntegral(scip, val) || ! SCIPvarIsIntegral(var));
1353 	   assert(*nfixings < SCIPgetNVars(scip));
1354 	
1355 	   /* round the value to its nearest integer */
1356 	   if( integer )
1357 	      val = SCIPfloor(scip, val + 0.5);
1358 	
1359 	   /* only add fixing if it is still valid within the global variable bounds. Invalidity
1360 	    * of this solution value may come from a dual reduction that was performed after the solution from which
1361 	    * this value originated was found
1362 	    */
1363 	   if( SCIPvarGetLbGlobal(var) <= val && val <= SCIPvarGetUbGlobal(var) )
1364 	   {
1365 	      varbuf[*nfixings] = var;
1366 	      valbuf[*nfixings] = val;
1367 	      ++(*nfixings);
1368 	   }
1369 	}
1370 	
1371 	/** query neighborhood for a reference solution for further fixings */
1372 	static
1373 	SCIP_RETCODE neighborhoodGetRefsol(
1374 	   SCIP*                 scip,               /**< SCIP data structure */
1375 	   NH*                   neighborhood,       /**< ALNS neighborhood data structure */
1376 	   SCIP_SOL**            solptr              /**< solution pointer */
1377 	   )
1378 	{
1379 	   assert(solptr != NULL);
1380 	   assert(scip != NULL);
1381 	   assert(neighborhood != NULL);
1382 	
1383 	   *solptr = NULL;
1384 	   if( neighborhood->nhrefsol != NULL )
1385 	   {
1386 	      SCIP_RESULT result;
1387 	      SCIP_CALL( neighborhood->nhrefsol(scip, neighborhood, solptr, &result) );
1388 	
1389 	      if( result == SCIP_DIDNOTFIND )
1390 	         *solptr = NULL;
1391 	      else
1392 	         assert(*solptr != NULL);
1393 	   }
1394 	
1395 	   return SCIP_OKAY;
1396 	}
1397 	
1398 	/** fix additional variables found in feasible reference solution if the ones that the neighborhood found were not enough
1399 	 *
1400 	 *  use not always the best solution for the values, but a reference solution provided by the neighborhood itself
1401 	 *
1402 	 *  @note it may happen that the target fixing rate is not completely reached. This is the case if intermediate,
1403 	 *  dual reductions render the solution values of the reference solution infeasible for
1404 	 *  the current, global variable bounds.
1405 	 */
1406 	static
1407 	SCIP_RETCODE alnsFixMoreVariables(
1408 	   SCIP*                 scip,               /**< SCIP data structure */
1409 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS neighborhood */
1410 	   SCIP_SOL*             refsol,             /**< feasible reference solution for more variable fixings */
1411 	   SCIP_VAR**            varbuf,             /**< buffer array to store variables to fix */
1412 	   SCIP_Real*            valbuf,             /**< buffer array to store fixing values */
1413 	   int*                  nfixings,           /**< pointer to store the number of fixings */
1414 	   int                   ntargetfixings,     /**< number of required target fixings */
1415 	   SCIP_Bool*            success             /**< pointer to store whether the target fixings have been successfully reached */
1416 	   )
1417 	{
1418 	   VARPRIO varprio;
1419 	   SCIP_VAR** vars;
1420 	   SCIP_Real* redcostscores;
1421 	   SCIP_Real* pscostscores;
1422 	   SCIP_Real* solvals;
1423 	   SCIP_RANDNUMGEN* rng;
1424 	   SCIP_VAR** unfixedvars;
1425 	   SCIP_Bool* isfixed;
1426 	   int* distances;
1427 	   int* perm;
1428 	   SCIP_Real* randscores;
1429 	   int nbinvars;
1430 	   int nintvars;
1431 	   int nbinintvars;
1432 	   int nvars;
1433 	   int b;
1434 	   int nvarstoadd;
1435 	   int nunfixedvars;
1436 	
1437 	   assert(scip != NULL);
1438 	   assert(varbuf != NULL);
1439 	   assert(nfixings != NULL);
1440 	   assert(success != NULL);
1441 	   assert(heurdata != NULL);
1442 	   assert(refsol != NULL);
1443 	
1444 	   *success = FALSE;
1445 	
1446 	   /* if the user parameter forbids more fixings, return immediately */
1447 	   if( ! heurdata->domorefixings )
1448 	      return SCIP_OKAY;
1449 	
1450 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
1451 	
1452 	   nbinintvars = nbinvars + nintvars;
1453 	
1454 	   if( ntargetfixings >= nbinintvars )
1455 	      return SCIP_OKAY;
1456 	
1457 	   /* determine the number of required additional fixings */
1458 	   nvarstoadd = ntargetfixings - *nfixings;
1459 	   if( nvarstoadd == 0 )
1460 	      return SCIP_OKAY;
1461 	
1462 	   varprio.usedistances = heurdata->usedistances && (*nfixings >= 1);
1463 	   varprio.useredcost = heurdata->useredcost;
1464 	   varprio.usepscost = heurdata->usepscost;
1465 	   varprio.scip = scip;
1466 	   rng = SCIPbanditGetRandnumgen(heurdata->bandit);
1467 	   assert(rng != NULL);
1468 	
1469 	   SCIP_CALL( SCIPallocBufferArray(scip, &randscores, nbinintvars) );
1470 	   SCIP_CALL( SCIPallocBufferArray(scip, &perm, nbinintvars) );
1471 	   SCIP_CALL( SCIPallocBufferArray(scip, &distances, nvars) );
1472 	   SCIP_CALL( SCIPallocBufferArray(scip, &redcostscores, nbinintvars) );
1473 	   SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nbinintvars) );
1474 	   SCIP_CALL( SCIPallocBufferArray(scip, &isfixed, nbinintvars) );
1475 	   SCIP_CALL( SCIPallocBufferArray(scip, &unfixedvars, nbinintvars) );
1476 	   SCIP_CALL( SCIPallocBufferArray(scip, &pscostscores, nbinintvars) );
1477 	
1478 	   /* initialize variable graph distances from already fixed variables */
1479 	   if( varprio.usedistances )
1480 	   {
1481 	      SCIP_CALL( SCIPvariablegraphBreadthFirst(scip, NULL, varbuf, *nfixings, distances, INT_MAX, INT_MAX, ntargetfixings) );
1482 	   }
1483 	   else
1484 	   {
1485 	      /* initialize all equal distances to make them irrelevant */
1486 	      BMSclearMemoryArray(distances, nbinintvars);
1487 	   }
1488 	
1489 	   BMSclearMemoryArray(isfixed, nbinintvars);
1490 	
1491 	   /* mark binary and integer variables if they are fixed */
1492 	   for( b = 0; b < *nfixings; ++b )
1493 	   {
1494 	      int probindex;
1495 	
1496 	      assert(varbuf[b] != NULL);
1497 	      probindex = SCIPvarGetProbindex(varbuf[b]);
1498 	      assert(probindex >= 0);
1499 	
1500 	      if( probindex < nbinintvars )
1501 	         isfixed[probindex] = TRUE;
1502 	   }
1503 	
1504 	   SCIP_CALL( SCIPgetSolVals(scip, refsol, nbinintvars, vars, solvals) );
1505 	
1506 	   /* assign scores to unfixed every discrete variable of the problem */
1507 	   nunfixedvars = 0;
1508 	   for( b = 0; b < nbinintvars; ++b )
1509 	   {
1510 	      SCIP_VAR* var = vars[b];
1511 	
1512 	      /* filter fixed variables */
1513 	      if( isfixed[b] )
1514 	         continue;
1515 	
1516 	      /* filter variables with a solution value outside its global bounds */
1517 	      if( solvals[b] < SCIPvarGetLbGlobal(var) - 0.5 || solvals[b] > SCIPvarGetUbGlobal(var) + 0.5 )
1518 	         continue;
1519 	
1520 	      redcostscores[nunfixedvars] = getVariableRedcostScore(scip, var, solvals[b], heurdata->uselocalredcost);
1521 	      pscostscores[nunfixedvars] = getVariablePscostScore(scip, var, solvals[b], heurdata->uselocalredcost);
1522 	
1523 	      unfixedvars[nunfixedvars] = var;
1524 	      perm[nunfixedvars] = nunfixedvars;
1525 	      randscores[nunfixedvars] = SCIPrandomGetReal(rng, 0.0, 1.0);
1526 	
1527 	      /* these assignments are based on the fact that nunfixedvars <= b */
1528 	      solvals[nunfixedvars] = solvals[b];
1529 	      distances[nunfixedvars] = distances[b];
1530 	
1531 	      SCIPdebugMsg(scip, "Var <%s> scores: dist %3d, red cost %15.9g, pscost %15.9g rand %6.4f\n",
1532 	         SCIPvarGetName(var), distances[nunfixedvars], redcostscores[nunfixedvars],
1533 	         pscostscores[nunfixedvars], randscores[nunfixedvars]);
1534 	
1535 	      nunfixedvars++;
1536 	   }
1537 	
1538 	   /* use selection algorithm (order of the variables does not matter) for quickly completing the fixing */
1539 	   varprio.randscores = randscores;
1540 	   varprio.distances = distances;
1541 	   varprio.redcostscores = redcostscores;
1542 	   varprio.pscostscores = pscostscores;
1543 	
1544 	   nvarstoadd = MIN(nunfixedvars, nvarstoadd);
1545 	
1546 	   /* select the first nvarstoadd many variables according to the score */
1547 	   if( nvarstoadd < nunfixedvars )
1548 	      SCIPselectInd(perm, sortIndCompAlns, &varprio, nvarstoadd, nunfixedvars);
1549 	
1550 	   /* loop over the first elements of the selection defined in permutation. They represent the best variables */
1551 	   for( b = 0; b < nvarstoadd; ++b )
1552 	   {
1553 	      int permindex = perm[b];
1554 	      assert(permindex >= 0);
1555 	      assert(permindex < nunfixedvars);
1556 	
1557 	      tryAdd2variableBuffer(scip, unfixedvars[permindex], solvals[permindex], varbuf, valbuf, nfixings, TRUE);
1558 	   }
1559 	
1560 	   *success = TRUE;
1561 	
1562 	   /* free buffer arrays */
1563 	   SCIPfreeBufferArray(scip, &pscostscores);
1564 	   SCIPfreeBufferArray(scip, &unfixedvars);
1565 	   SCIPfreeBufferArray(scip, &isfixed);
1566 	   SCIPfreeBufferArray(scip, &solvals);
1567 	   SCIPfreeBufferArray(scip, &redcostscores);
1568 	   SCIPfreeBufferArray(scip, &distances);
1569 	   SCIPfreeBufferArray(scip, &perm);
1570 	   SCIPfreeBufferArray(scip, &randscores);
1571 	
1572 	   return SCIP_OKAY;
1573 	}
1574 	
1575 	/** create the bandit algorithm for the heuristic depending on the user parameter */
1576 	static
1577 	SCIP_RETCODE createBandit(
1578 	   SCIP*                 scip,               /**< SCIP data structure */
1579 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data structure */
1580 	   SCIP_Real*            priorities,         /**< call priorities for active neighborhoods */
1581 	   unsigned int          initseed            /**< initial random seed */
1582 	   )
1583 	{
1584 	   switch (heurdata->banditalgo)
1585 	   {
1586 	   case 'u':
1587 	      SCIP_CALL( SCIPcreateBanditUcb(scip, &heurdata->bandit, priorities,
1588 	            heurdata->ucb_alpha, heurdata->nactiveneighborhoods, initseed) );
1589 	      break;
1590 	
1591 	   case 'e':
1592 	      SCIP_CALL( SCIPcreateBanditExp3(scip, &heurdata->bandit, priorities,
1593 	            heurdata->exp3_gamma, heurdata->exp3_beta, heurdata->nactiveneighborhoods, initseed) );
1594 	      break;
1595 	
1596 	   case 'g':
1597 	      SCIP_CALL( SCIPcreateBanditEpsgreedy(scip, &heurdata->bandit, priorities,
1598 	            heurdata->epsgreedy_eps, FALSE, 0.9, 0, heurdata->nactiveneighborhoods, initseed) );
1599 	      break;
1600 	
1601 	   default:
1602 	      SCIPerrorMessage("Unknown bandit parameter %c\n", heurdata->banditalgo);
1603 	      return SCIP_INVALIDDATA;
1604 	   }
1605 	
1606 	   return SCIP_OKAY;
1607 	}
1608 	
1609 	/*
1610 	 * Callback methods of primal heuristic
1611 	 */
1612 	
1613 	/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
1614 	static
1615 	SCIP_DECL_HEURCOPY(heurCopyAlns)
1616 	{  /*lint --e{715}*/
1617 	   assert(scip != NULL);
1618 	   assert(heur != NULL);
1619 	   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1620 	
1621 	   /* call inclusion method of primal heuristic */
1622 	   SCIP_CALL( SCIPincludeHeurAlns(scip) );
1623 	
1624 	   return SCIP_OKAY;
1625 	}
1626 	
1627 	/** unfix some of the variables because there are too many fixed
1628 	 *
1629 	 *  a variable is ideally unfixed if it is close to other unfixed variables
1630 	 *  and fixing it has a high reduced cost impact
1631 	 */
1632 	static
1633 	SCIP_RETCODE alnsUnfixVariables(
1634 	   SCIP*                 scip,               /**< SCIP data structure */
1635 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS neighborhood */
1636 	   SCIP_VAR**            varbuf,             /**< buffer array to store variables to fix */
1637 	   SCIP_Real*            valbuf,             /**< buffer array to store fixing values */
1638 	   int*                  nfixings,           /**< pointer to store the number of fixings */
1639 	   int                   ntargetfixings,     /**< number of required target fixings */
1640 	   SCIP_Bool*            success             /**< pointer to store whether the target fixings have been successfully reached */
1641 	   )
1642 	{
1643 	   VARPRIO varprio;
1644 	   SCIP_Real* redcostscores;
1645 	   SCIP_Real* pscostscores;
1646 	   SCIP_Real* randscores;
1647 	   SCIP_VAR** unfixedvars;
1648 	   SCIP_VAR** varbufcpy;
1649 	   SCIP_Real* valbufcpy;
1650 	   SCIP_Bool* isfixedvar;
1651 	   SCIP_VAR** vars;
1652 	   SCIP_RANDNUMGEN* rng;
1653 	   int* distances;
1654 	   int* fixeddistances;
1655 	   int* perm;
1656 	   int nvars;
1657 	   int i;
1658 	   int nbinintvars;
1659 	   int nunfixed;
1660 	
1661 	   *success = FALSE;
1662 	
1663 	   nbinintvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
1664 	   if( nbinintvars == 0 )
1665 	      return SCIP_OKAY;
1666 	
1667 	   assert(*nfixings > 0);
1668 	
1669 	   nvars = SCIPgetNVars(scip);
1670 	   SCIP_CALL( SCIPallocBufferArray(scip, &isfixedvar, nvars) );
1671 	   SCIP_CALL( SCIPallocBufferArray(scip, &unfixedvars, nbinintvars) );
1672 	   SCIP_CALL( SCIPallocBufferArray(scip, &distances, nvars) );
1673 	   SCIP_CALL( SCIPallocBufferArray(scip, &fixeddistances, *nfixings) );
1674 	   SCIP_CALL( SCIPallocBufferArray(scip, &redcostscores, *nfixings) );
1675 	   SCIP_CALL( SCIPallocBufferArray(scip, &randscores, *nfixings) );
1676 	   SCIP_CALL( SCIPallocBufferArray(scip, &perm, *nfixings) );
1677 	   SCIP_CALL( SCIPallocBufferArray(scip, &pscostscores, *nfixings) );
1678 	
1679 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &varbufcpy, varbuf, *nfixings) );
1680 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &valbufcpy, valbuf, *nfixings) );
1681 	
1682 	   /*
1683 	    * collect the unfixed binary and integer variables
1684 	    */
1685 	   BMSclearMemoryArray(isfixedvar, nvars);
1686 	   /* loop over fixed variables and mark their respective positions as fixed */
1687 	   for( i = 0; i < *nfixings; ++i )
1688 	   {
1689 	      int probindex = SCIPvarGetProbindex(varbuf[i]);
1690 	
1691 	      assert(probindex >= 0);
1692 	
1693 	      isfixedvar[probindex] = TRUE;
1694 	   }
1695 	
1696 	   nunfixed = 0;
1697 	   vars = SCIPgetVars(scip);
1698 	   /* collect unfixed binary and integer variables */
1699 	   for( i = 0; i < nbinintvars; ++i )
1700 	   {
1701 	      if( ! isfixedvar[i] )
1702 	         unfixedvars[nunfixed++] = vars[i];
1703 	   }
1704 	
1705 	   varprio.usedistances = heurdata->usedistances && nunfixed > 0;
1706 	
1707 	   /* collect distances of all fixed variables from those that are not fixed */
1708 	   if( varprio.usedistances )
1709 	   {
1710 	      SCIP_CALL( SCIPvariablegraphBreadthFirst(scip, NULL, unfixedvars, nunfixed, distances, INT_MAX, INT_MAX, INT_MAX) );
1711 	
1712 	      for( i = 0; i < *nfixings; ++i )
1713 	      {
1714 	         int probindex = SCIPvarGetProbindex(varbuf[i]);
1715 	         if( probindex >= 0 )
1716 	            fixeddistances[i] = distances[probindex];
1717 	      }
1718 	   }
1719 	   else
1720 	   {
1721 	      BMSclearMemoryArray(fixeddistances, *nfixings);
1722 	   }
1723 	
1724 	   /* collect reduced cost scores of the fixings and assign random scores */
1725 	   rng = SCIPbanditGetRandnumgen(heurdata->bandit);
1726 	   for( i = 0; i < *nfixings; ++i )
1727 	   {
1728 	      SCIP_VAR* fixedvar = varbuf[i];
1729 	      SCIP_Real fixval = valbuf[i];
1730 	
1731 	      /* use negative reduced cost and pseudo cost scores to prefer variable fixings with small score */
1732 	      redcostscores[i] = - getVariableRedcostScore(scip, fixedvar, fixval, heurdata->uselocalredcost);
1733 	      pscostscores[i] = - getVariablePscostScore(scip, fixedvar, fixval, heurdata->uselocalredcost);
1734 	      randscores[i] = SCIPrandomGetReal(rng, 0.0, 1.0);
1735 	      perm[i] = i;
1736 	
1737 	      SCIPdebugMsg(scip, "Var <%s> scores: dist %3d, red cost %15.9g, pscost %15.9g rand %6.4f\n",
1738 	            SCIPvarGetName(fixedvar), fixeddistances[i], redcostscores[i], pscostscores[i], randscores[i]);
1739 	   }
1740 	
1741 	   varprio.distances = fixeddistances;
1742 	   varprio.randscores = randscores;
1743 	   varprio.redcostscores = redcostscores;
1744 	   varprio.pscostscores = pscostscores;
1745 	   varprio.useredcost = heurdata->useredcost;
1746 	   varprio.usepscost = heurdata->usepscost;
1747 	   varprio.scip = scip;
1748 	
1749 	   /* scores are assigned in such a way that variables with a smaller score should be fixed last */
1750 	   SCIPselectDownInd(perm, sortIndCompAlns, &varprio, ntargetfixings, *nfixings);
1751 	
1752 	   /* bring the desired variables to the front of the array */
1753 	   for( i = 0; i < ntargetfixings; ++i )
1754 	   {
1755 	      valbuf[i] = valbufcpy[perm[i]];
1756 	      varbuf[i] = varbufcpy[perm[i]];
1757 	   }
1758 	
1759 	   *nfixings = ntargetfixings;
1760 	
1761 	   /* free the buffer arrays in reverse order of allocation */
1762 	   SCIPfreeBufferArray(scip, &valbufcpy);
1763 	   SCIPfreeBufferArray(scip, &varbufcpy);
1764 	   SCIPfreeBufferArray(scip, &pscostscores);
1765 	   SCIPfreeBufferArray(scip, &perm);
1766 	   SCIPfreeBufferArray(scip, &randscores);
1767 	   SCIPfreeBufferArray(scip, &redcostscores);
1768 	   SCIPfreeBufferArray(scip, &fixeddistances);
1769 	   SCIPfreeBufferArray(scip, &distances);
1770 	   SCIPfreeBufferArray(scip, &unfixedvars);
1771 	   SCIPfreeBufferArray(scip, &isfixedvar);
1772 	
1773 	   *success = TRUE;
1774 	
1775 	   return SCIP_OKAY;
1776 	}
1777 	
1778 	/** call variable fixing callback for this neighborhood and orchestrate additional variable fixings, if necessary */
1779 	static
1780 	SCIP_RETCODE neighborhoodFixVariables(
1781 	   SCIP*                 scip,               /**< SCIP data structure */
1782 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS neighborhood */
1783 	   NH*                   neighborhood,       /**< neighborhood data structure */
1784 	   SCIP_VAR**            varbuf,             /**< buffer array to keep variables that should be fixed */
1785 	   SCIP_Real*            valbuf,             /**< buffer array to keep fixing values */
1786 	   int*                  nfixings,           /**< pointer to store the number of variable fixings */
1787 	   SCIP_RESULT*          result              /**< pointer to store the result of the fixing operation */
1788 	   )
1789 	{
1790 	   int ntargetfixings;
1791 	   int nmaxfixings;
1792 	   int nminfixings;
1793 	   int nbinintvars;
1794 	
1795 	   assert(scip != NULL);
1796 	   assert(neighborhood != NULL);
1797 	   assert(varbuf != NULL);
1798 	   assert(valbuf != NULL);
1799 	   assert(nfixings != NULL);
1800 	   assert(result != NULL);
1801 	
1802 	   *nfixings = 0;
1803 	
1804 	   *result = SCIP_DIDNOTRUN;
1805 	   ntargetfixings = (int)(neighborhood->fixingrate.targetfixingrate * (SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip)));
1806 	
1807 	   if( neighborhood->varfixings != NULL )
1808 	   {
1809 	      SCIP_CALL( neighborhood->varfixings(scip, neighborhood, varbuf, valbuf, nfixings, result) );
1810 	
1811 	      if( *result != SCIP_SUCCESS )
1812 	         return SCIP_OKAY;
1813 	   }
1814 	   else if( ntargetfixings == 0 )
1815 	   {
1816 	      *result = SCIP_SUCCESS;
1817 	
1818 	      return SCIP_OKAY;
1819 	   }
1820 	
1821 	   /* compute upper and lower target fixing limits using tolerance parameters */
1822 	   assert(neighborhood->varfixings == NULL || *result != SCIP_DIDNOTRUN);
1823 	   nbinintvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
1824 	   ntargetfixings = (int)(neighborhood->fixingrate.targetfixingrate * nbinintvars);
1825 	   nminfixings = (int)((neighborhood->fixingrate.targetfixingrate - heurdata->fixtol) * nbinintvars);
1826 	   nminfixings = MAX(nminfixings, 0);
1827 	   nmaxfixings = (int)((neighborhood->fixingrate.targetfixingrate + heurdata->unfixtol) * nbinintvars);
1828 	   nmaxfixings = MIN(nmaxfixings, nbinintvars);
1829 	
1830 	   SCIPdebugMsg(scip, "Neighborhood Fixings/Target: %d / %d <= %d <= %d\n",*nfixings, nminfixings, ntargetfixings, nmaxfixings);
1831 	
1832 	   /* if too few fixings, use a strategy to select more variable fixings: randomized, LP graph, ReducedCost based, mix */
1833 	   if( (*result == SCIP_SUCCESS || *result == SCIP_DIDNOTRUN) && (*nfixings < nminfixings) )
1834 	   {
1835 	      SCIP_Bool success;
1836 	      SCIP_SOL* refsol;
1837 	
1838 	      /* get reference solution from neighborhood */
1839 	      SCIP_CALL( neighborhoodGetRefsol(scip, neighborhood, &refsol) );
1840 	
1841 	      /* try to fix more variables based on the reference solution */
1842 	      if( refsol != NULL )
1843 	      {
1844 	         SCIP_CALL( alnsFixMoreVariables(scip, heurdata, refsol, varbuf, valbuf, nfixings, ntargetfixings, &success) );
1845 	      }
1846 	      else
1847 	         success = FALSE;
1848 	
1849 	      if( success )
1850 	         *result = SCIP_SUCCESS;
1851 	      else if( *result == SCIP_SUCCESS )
1852 	         *result = SCIP_DIDNOTFIND;
1853 	      else
1854 	         *result = SCIP_DIDNOTRUN;
1855 	
1856 	      SCIPdebugMsg(scip, "After additional fixings: %d / %d\n",*nfixings, ntargetfixings);
1857 	   }
1858 	   else if( (SCIP_Real)(*nfixings) > nmaxfixings )
1859 	   {
1860 	      SCIP_Bool success;
1861 	
1862 	      SCIP_CALL( alnsUnfixVariables(scip, heurdata, varbuf, valbuf, nfixings, ntargetfixings, &success) );
1863 	
1864 	      assert(success);
1865 	      *result = SCIP_SUCCESS;
1866 	      SCIPdebugMsg(scip, "Unfixed variables, fixed variables remaining: %d\n", ntargetfixings);
1867 	   }
1868 	   else
1869 	   {
1870 	      SCIPdebugMsg(scip, "No additional fixings performed\n");
1871 	   }
1872 	
1873 	   return SCIP_OKAY;
1874 	}
1875 	
1876 	/** change the sub-SCIP by restricting variable domains, changing objective coefficients, or adding constraints */
1877 	static
1878 	SCIP_RETCODE neighborhoodChangeSubscip(
1879 	   SCIP*                 sourcescip,         /**< source SCIP data structure */
1880 	   SCIP*                 targetscip,         /**< target SCIP data structure */
1881 	   NH*                   neighborhood,       /**< neighborhood */
1882 	   SCIP_VAR**            targetvars,         /**< array of target SCIP variables aligned with source SCIP variables */
1883 	   int*                  ndomchgs,           /**< pointer to store the number of variable domain changes */
1884 	   int*                  nchgobjs,           /**< pointer to store the number of changed objective coefficients */
1885 	   int*                  naddedconss,        /**< pointer to store the number of added constraints */
1886 	   SCIP_Bool*            success             /**< pointer to store whether the sub-SCIP has been successfully modified */
1887 	   )
1888 	{
1889 	   assert(sourcescip != NULL);
1890 	   assert(targetscip != NULL);
1891 	   assert(neighborhood != NULL);
1892 	   assert(targetvars != NULL);
1893 	   assert(ndomchgs != NULL);
1894 	   assert(nchgobjs != NULL);
1895 	   assert(naddedconss != NULL);
1896 	   assert(success != NULL);
1897 	
1898 	   *success = FALSE;
1899 	   *ndomchgs = 0;
1900 	   *nchgobjs = 0;
1901 	   *naddedconss = 0;
1902 	
1903 	   /* call the change sub-SCIP callback of the neighborhood */
1904 	   if( neighborhood->changesubscip != NULL )
1905 	   {
1906 	      SCIP_CALL( neighborhood->changesubscip(sourcescip, targetscip, neighborhood, targetvars, ndomchgs, nchgobjs, naddedconss, success) );
1907 	   }
1908 	   else
1909 	   {
1910 	      *success = TRUE;
1911 	   }
1912 	
1913 	   return SCIP_OKAY;
1914 	}
1915 	
1916 	/** set sub-SCIP solving limits */
1917 	static
1918 	SCIP_RETCODE setLimits(
1919 	   SCIP*                 subscip,            /**< SCIP data structure */
1920 	   SOLVELIMITS*          solvelimits         /**< pointer to solving limits data structure */
1921 	   )
1922 	{
1923 	   assert(subscip != NULL);
1924 	   assert(solvelimits != NULL);
1925 	
1926 	   assert(solvelimits->nodelimit >= solvelimits->stallnodes);
1927 	
1928 	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", solvelimits->nodelimit) );
1929 	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", solvelimits->stallnodes));
1930 	   SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", solvelimits->timelimit) );
1931 	   SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", solvelimits->memorylimit) );
1932 	
1933 	   return SCIP_OKAY;
1934 	}
1935 	
1936 	/** determine limits for a sub-SCIP */
1937 	static
1938 	SCIP_RETCODE determineLimits(
1939 	   SCIP*                 scip,               /**< SCIP data structure */
1940 	   SCIP_HEUR*            heur,               /**< this heuristic */
1941 	   SOLVELIMITS*          solvelimits,        /**< pointer to solving limits data structure */
1942 	   SCIP_Bool*            runagain            /**< can we solve another sub-SCIP with these limits */
1943 	   )
1944 	{
1945 	   SCIP_HEURDATA* heurdata;
1946 	   SCIP_Real initfactor;
1947 	   SCIP_Real nodesquot;
1948 	   SCIP_Bool avoidmemout;
1949 	
1950 	   assert(scip != NULL);
1951 	   assert(heur != NULL);
1952 	   assert(solvelimits != NULL);
1953 	   assert(runagain != NULL);
1954 	
1955 	   heurdata = SCIPheurGetData(heur);
1956 	
1957 	   /* check whether there is enough time and memory left */
1958 	   SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &solvelimits->timelimit) );
1959 	   if( ! SCIPisInfinity(scip, solvelimits->timelimit) )
1960 	      solvelimits->timelimit -= SCIPgetSolvingTime(scip);
1961 	   SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &solvelimits->memorylimit) );
1962 	   SCIP_CALL( SCIPgetBoolParam(scip, "misc/avoidmemout", &avoidmemout) );
1963 	
1964 	   /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
1965 	   if( ! SCIPisInfinity(scip, solvelimits->memorylimit) )
1966 	   {
1967 	      solvelimits->memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
1968 	      solvelimits->memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
1969 	   }
1970 	
1971 	   /* abort if no time is left or not enough memory (we don't abort in this case if misc_avoidmemout == FALSE)
1972 	   * to create a copy of SCIP, including external memory usage */
1973 	   if( solvelimits->timelimit <= 0.0 || (avoidmemout && solvelimits->memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0) )
1974 	      *runagain = FALSE;
1975 	
1976 	   nodesquot = heurdata->nodesquot;
1977 	
1978 	   /* if the heuristic is used to measure all rewards, it will always be penalized here */
1979 	   if( heurdata->rewardfile == NULL )
1980 	      nodesquot *= (SCIPheurGetNBestSolsFound(heur) + 1.0)/(SCIPheurGetNCalls(heur) + 1.0);
1981 	
1982 	   nodesquot = MAX(nodesquot, heurdata->nodesquotmin);
1983 	
1984 	   /* calculate the search node limit of the heuristic  */
1985 	   solvelimits->stallnodes = (SCIP_Longint)(nodesquot * SCIPgetNNodes(scip));
1986 	   solvelimits->stallnodes += heurdata->nodesoffset;
1987 	   solvelimits->stallnodes -= heurdata->usednodes;
1988 	   solvelimits->stallnodes -= 100 * SCIPheurGetNCalls(heur);
1989 	   solvelimits->stallnodes = MIN(heurdata->maxnodes, solvelimits->stallnodes);
1990 	
1991 	   /* use a smaller budget if not all neighborhoods have been initialized yet */
1992 	   assert(heurdata->ninitneighborhoods >= 0);
1993 	   initfactor = (heurdata->nactiveneighborhoods - heurdata->ninitneighborhoods + 1.0) / (heurdata->nactiveneighborhoods + 1.0);
1994 	   solvelimits->stallnodes = (SCIP_Longint)(solvelimits->stallnodes * initfactor);
1995 	   solvelimits->nodelimit = (SCIP_Longint)(heurdata->maxnodes);
1996 	
1997 	   /* check whether we have enough nodes left to call subproblem solving */
1998 	   if( solvelimits->stallnodes < heurdata->targetnodes )
1999 	      *runagain = FALSE;
2000 	
2001 	   return SCIP_OKAY;
2002 	}
2003 	
2004 	/** return the bandit algorithm that should be used */
2005 	static
2006 	SCIP_BANDIT* getBandit(
2007 	   SCIP_HEURDATA*        heurdata            /**< heuristic data of the ALNS neighborhood */
2008 	   )
2009 	{
2010 	   assert(heurdata != NULL);
2011 	   return heurdata->bandit;
2012 	}
2013 	
2014 	/** select a neighborhood depending on the selected bandit algorithm */
2015 	static
2016 	SCIP_RETCODE selectNeighborhood(
2017 	   SCIP*                 scip,               /**< SCIP data structure */
2018 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS neighborhood */
2019 	   int*                  neighborhoodidx     /**< pointer to store the selected neighborhood index */
2020 	   )
2021 	{
2022 	   SCIP_BANDIT* bandit;
2023 	   assert(scip != NULL);
2024 	   assert(heurdata != NULL);
2025 	   assert(neighborhoodidx != NULL);
2026 	
2027 	   *neighborhoodidx = -1;
2028 	
2029 	   bandit = getBandit(heurdata);
2030 	
2031 	   SCIP_CALL( SCIPbanditSelect(bandit, neighborhoodidx) );
2032 	   assert(*neighborhoodidx >= 0);
2033 	
2034 	   return SCIP_OKAY;
2035 	}
2036 	
2037 	/** Calculate reward based on the selected reward measure */
2038 	static
2039 	SCIP_RETCODE getReward(
2040 	   SCIP*                 scip,               /**< SCIP data structure */
2041 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS neighborhood */
2042 	   NH_STATS*             runstats,           /**< run statistics */
2043 	   SCIP_Real*            rewardptr           /**< array to store the computed rewards, total and individual */
2044 	   )
2045 	{
2046 	   SCIP_Real reward = 0.0;
2047 	   SCIP_Real effort;
2048 	   int ndiscretevars;
2049 	
2050 	   memset(rewardptr, 0, sizeof(*rewardptr)*(int)NREWARDTYPES);
2051 	
2052 	   assert(rewardptr != NULL);
2053 	   assert(runstats->usednodes >= 0);
2054 	   assert(runstats->nfixings >= 0);
2055 	
2056 	   effort = runstats->usednodes / 100.0;
2057 	
2058 	   ndiscretevars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
2059 	   /* assume that every fixed variable linearly reduces the subproblem complexity */
2060 	   if( ndiscretevars > 0 )
2061 	   {
2062 	      effort = (1.0 - (runstats->nfixings / (SCIP_Real)ndiscretevars)) * effort;
2063 	   }
2064 	   assert(rewardptr != NULL);
2065 	
2066 	   /* a positive reward is only assigned if a new incumbent solution was found */
2067 	   if( runstats->nbestsolsfound > 0 )
2068 	   {
2069 	      SCIP_Real rewardcontrol = heurdata->rewardcontrol;
2070 	
2071 	      SCIP_Real lb;
2072 	      SCIP_Real ub;
2073 	
2074 	      /* the indicator function is simply 1.0 */
2075 	      rewardptr[REWARDTYPE_BESTSOL] = 1.0;
2076 	      rewardptr[REWARDTYPE_NOSOLPENALTY] = 1.0;
2077 	
2078 	      ub = runstats->newupperbound;
2079 	      lb = SCIPgetLowerbound(scip);
2080 	
2081 	      /* compute the closed gap reward */
2082 	      if( SCIPisEQ(scip, ub, lb) || SCIPisInfinity(scip, runstats->oldupperbound) )
2083 	         rewardptr[REWARDTYPE_CLOSEDGAP] = 1.0;
2084 	      else
2085 	      {
2086 	         rewardptr[REWARDTYPE_CLOSEDGAP] = (runstats->oldupperbound - ub) / (runstats->oldupperbound - lb);
2087 	      }
2088 	
2089 	      /* the reward is a convex combination of the best solution reward and the reward for the closed gap */
2090 	      reward = rewardcontrol * rewardptr[REWARDTYPE_BESTSOL] + (1.0 - rewardcontrol) * rewardptr[REWARDTYPE_CLOSEDGAP];
2091 	
2092 	      /* optionally, scale the reward by the involved effort */
2093 	      if( heurdata->scalebyeffort )
2094 	         reward /= (effort + 1.0);
2095 	
2096 	      /* add the baseline and rescale the reward into the interval [baseline, 1.0] */
2097 	      reward = heurdata->rewardbaseline + (1.0 - heurdata->rewardbaseline) * reward;
2098 	   }
2099 	   else
2100 	   {
2101 	      /* linearly decrease the reward based on the number of nodes spent */
2102 	      SCIP_Real maxeffort = heurdata->targetnodes;
2103 	      SCIP_Real usednodes = runstats->usednodes;
2104 	
2105 	      if( ndiscretevars > 0 )
2106 	         usednodes *= (1.0 - (runstats->nfixings / (SCIP_Real)ndiscretevars));
2107 	
2108 	      rewardptr[REWARDTYPE_NOSOLPENALTY] = 1 - (usednodes / maxeffort);
2109 	      rewardptr[REWARDTYPE_NOSOLPENALTY] = MAX(0.0, rewardptr[REWARDTYPE_NOSOLPENALTY]);
2110 	      reward = heurdata->rewardbaseline * rewardptr[REWARDTYPE_NOSOLPENALTY];
2111 	   }
2112 	
2113 	   rewardptr[REWARDTYPE_TOTAL] = reward;
2114 	
2115 	   return SCIP_OKAY;
2116 	}
2117 	
2118 	/** update internal bandit algorithm statistics for future draws */
2119 	static
2120 	SCIP_RETCODE updateBanditAlgorithm(
2121 	   SCIP*                 scip,               /**< SCIP data structure */
2122 	   SCIP_HEURDATA*        heurdata,           /**< heuristic data of the ALNS neighborhood */
2123 	   SCIP_Real             reward,             /**< measured reward */
2124 	   int                   neighborhoodidx     /**< the neighborhood that was chosen */
2125 	   )
2126 	{
2127 	   SCIP_BANDIT* bandit;
2128 	   assert(scip != NULL);
2129 	   assert(heurdata != NULL);
2130 	   assert(neighborhoodidx >= 0);
2131 	   assert(neighborhoodidx < heurdata->nactiveneighborhoods);
2132 	
2133 	   bandit = getBandit(heurdata);
2134 	
2135 	   SCIPdebugMsg(scip, "Rewarding bandit algorithm action %d with reward %.2f\n", neighborhoodidx, reward);
2136 	   SCIP_CALL( SCIPbanditUpdate(bandit, neighborhoodidx, reward) );
2137 	
2138 	   return SCIP_OKAY;
2139 	}
2140 	
2141 	/** set up the sub-SCIP parameters, objective cutoff, and solution limits */
2142 	static
2143 	SCIP_RETCODE setupSubScip(
2144 	   SCIP*                 scip,               /**< SCIP data structure */
2145 	   SCIP*                 subscip,            /**< sub-SCIP data structure */
2146 	   SCIP_VAR**            subvars,            /**< array of sub-SCIP variables in the order of the main SCIP */
2147 	   SOLVELIMITS*          solvelimits,        /**< pointer to solving limits data structure */
2148 	   SCIP_HEUR*            heur,               /**< this heuristic */
2149 	   SCIP_Bool             objchgd             /**< did the objective change between the source and the target SCIP? */
2150 	   )
2151 	{
2152 	   SCIP_HEURDATA* heurdata;
2153 	   SCIP_Real cutoff;
2154 	   SCIP_Real upperbound;
2155 	
2156 	   heurdata = SCIPheurGetData(heur);
2157 	
2158 	   /* do not abort subproblem on CTRL-C */
2159 	   SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
2160 	
2161 	   /* disable output to console unless we are in debug mode */
2162 	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
2163 	
2164 	   /* disable statistic timing inside sub SCIP */
2165 	   SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) );
2166 	
2167 	#ifdef ALNS_SUBSCIPOUTPUT
2168 	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
2169 	   SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 1) );
2170 	   /* enable statistic timing inside sub SCIP */
2171 	      SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", TRUE) );
2172 	#endif
2173 	
2174 	   SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", heurdata->nsolslim) );
2175 	
2176 	   /* forbid recursive call of heuristics and separators solving subMIPs */
2177 	   if( ! heurdata->usesubscipheurs )
2178 	   {
2179 	      SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
2180 	   }
2181 	
2182 	   /* disable cutting plane separation */
2183 	   SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) );
2184 	
2185 	   /* disable expensive presolving */
2186 	   SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) );
2187 	
2188 	   /* use best estimate node selection */
2189 	   if( SCIPfindNodesel(subscip, "estimate") != NULL && ! SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
2190 	   {
2191 	      SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
2192 	   }
2193 	
2194 	   /* use inference branching */
(5) Event example_checked: Example 3: "SCIPfindBranchrule(subscip, "inference")" has its value checked in "SCIPfindBranchrule(subscip, "inference") != NULL".
Also see events: [returned_null][example_assign][example_checked][example_checked][example_checked][example_checked][var_assigned][dereference]
2195 	   if( SCIPfindBranchrule(subscip, "inference") != NULL && ! SCIPisParamFixed(subscip, "branching/inference/priority") )
2196 	   {
2197 	      SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
2198 	   }
2199 	
2200 	   /* enable conflict analysis and restrict conflict pool */
2201 	   if( ! SCIPisParamFixed(subscip, "conflict/enable") )
2202 	   {
2203 	      SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/enable", TRUE) );
2204 	   }
2205 	
2206 	   if( !SCIPisParamFixed(subscip, "conflict/useboundlp") )
2207 	   {
2208 	      SCIP_CALL( SCIPsetCharParam(subscip, "conflict/useboundlp", 'o') );
2209 	   }
2210 	
2211 	   if( ! SCIPisParamFixed(subscip, "conflict/maxstoresize") )
2212 	   {
2213 	      SCIP_CALL( SCIPsetIntParam(subscip, "conflict/maxstoresize", 100) );
2214 	   }
2215 	
2216 	   /* speed up sub-SCIP by not checking dual LP feasibility */
2217 	   SCIP_CALL( SCIPsetBoolParam(subscip, "lp/checkdualfeas", FALSE) );
2218 	
2219 	   /* add an objective cutoff */
2220 	   if( ! SCIPisInfinity(scip, SCIPgetUpperbound(scip)) )
2221 	   {
2222 	      upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip);
2223 	      if( ! SCIPisInfinity(scip, -1.0 * SCIPgetLowerbound(scip)) )
2224 	      {
2225 	         cutoff = (1 - heurdata->minimprove) * SCIPgetUpperbound(scip)
2226 	                            + heurdata->minimprove * SCIPgetLowerbound(scip);
2227 	      }
2228 	      else
2229 	      {
2230 	         if( SCIPgetUpperbound(scip) >= 0 )
2231 	            cutoff = (1 - heurdata->minimprove) * SCIPgetUpperbound(scip);
2232 	         else
2233 	            cutoff = (1 + heurdata->minimprove) * SCIPgetUpperbound(scip);
2234 	      }
2235 	      cutoff = MIN(upperbound, cutoff);
2236 	
2237 	      if( SCIPisObjIntegral(scip) )
2238 	         cutoff = SCIPfloor(scip, cutoff);
2239 	
2240 	      SCIPdebugMsg(scip, "Sub-SCIP cutoff: %15.9" SCIP_REAL_FORMAT " (%15.9" SCIP_REAL_FORMAT " in original space)\n",
2241 	         cutoff, SCIPretransformObj(scip, cutoff));
2242 	
2243 	      /* if the objective changed between the source and the target SCIP, encode the cutoff as a constraint */
2244 	      if( ! objchgd )
2245 	      {
2246 	         SCIP_CALL(SCIPsetObjlimit(subscip, cutoff));
2247 	
2248 	         SCIPdebugMsg(scip, "Cutoff added as Objective Limit\n");
2249 	      }
2250 	      else
2251 	      {
2252 	         SCIP_CONS* objcons;
2253 	         int nvars;
2254 	         SCIP_VAR** vars;
2255 	         int i;
2256 	
2257 	         vars = SCIPgetVars(scip);
2258 	         nvars = SCIPgetNVars(scip);
2259 	
2260 	         SCIP_CALL( SCIPcreateConsLinear(subscip, &objcons, "objbound_of_origscip", 0, NULL, NULL, -SCIPinfinity(subscip), cutoff,
2261 	                     TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2262 	         for( i = 0; i < nvars; ++i)
2263 	         {
2264 	            if( ! SCIPisFeasZero(subscip, SCIPvarGetObj(vars[i])) )
2265 	            {
2266 	               assert(subvars[i] != NULL);
2267 	               SCIP_CALL( SCIPaddCoefLinear(subscip, objcons, subvars[i], SCIPvarGetObj(vars[i])) );
2268 	            }
2269 	         }
2270 	         SCIP_CALL( SCIPaddCons(subscip, objcons) );
2271 	         SCIP_CALL( SCIPreleaseCons(subscip, &objcons) );
2272 	
2273 	         SCIPdebugMsg(scip, "Cutoff added as constraint\n");
2274 	      }
2275 	   }
2276 	
2277 	   /* set solve limits for sub-SCIP */
2278 	   SCIP_CALL( setLimits(subscip, solvelimits) );
2279 	
2280 	   /* change random seed of sub-SCIP */
2281 	   if( heurdata->subsciprandseeds )
2282 	   {
2283 	      SCIP_CALL( SCIPsetIntParam(subscip, "randomization/randomseedshift", (int)SCIPheurGetNCalls(heur)) );
2284 	   }
2285 	
2286 	   SCIPdebugMsg(scip, "Solve Limits: %lld (%lld) nodes (stall nodes), %.1f sec., %d sols\n",
2287 	         solvelimits->nodelimit, solvelimits->stallnodes, solvelimits->timelimit, heurdata->nsolslim);
2288 	
2289 	   return SCIP_OKAY;
2290 	}
2291 	
2292 	/** execution method of primal heuristic */
2293 	static
2294 	SCIP_DECL_HEUREXEC(heurExecAlns)
2295 	{  /*lint --e{715}*/
2296 	   SCIP_HEURDATA* heurdata;
2297 	   SCIP_VAR** varbuf;
2298 	   SCIP_Real* valbuf;
2299 	   SCIP_VAR** vars;
2300 	   SCIP_VAR** subvars;
2301 	   NH_STATS runstats[NNEIGHBORHOODS];
2302 	   SCIP_STATUS subscipstatus[NNEIGHBORHOODS];
2303 	   SCIP* subscip = NULL;
2304 	
2305 	   int nfixings;
2306 	   int nvars;
2307 	   int neighborhoodidx;
2308 	   int ntries;
2309 	   SCIP_Bool tryagain;
2310 	   NH* neighborhood;
2311 	   SOLVELIMITS solvelimits;
2312 	   SCIP_Bool success;
2313 	   SCIP_Bool run;
2314 	   SCIP_Bool allrewardsmode;
2315 	   SCIP_Real rewards[NNEIGHBORHOODS][NREWARDTYPES] = {{0}};
2316 	   int banditidx;
2317 	
2318 	   int i;
2319 	
2320 	   heurdata = SCIPheurGetData(heur);
2321 	   assert(heurdata != NULL);
2322 	
2323 	   *result = SCIP_DIDNOTRUN;
2324 	
2325 	   if( heurdata->nactiveneighborhoods == 0 )
2326 	      return SCIP_OKAY;
2327 	
2328 	   /* we only allow to run multiple times at a node during the root */
2329 	   if( (heurtiming & SCIP_HEURTIMING_DURINGLPLOOP) && (SCIPgetDepth(scip) > 0 || !heurdata->initduringroot) )
2330 	      return SCIP_OKAY;
2331 	
2332 	   /* update internal incumbent solution */
2333 	   if( SCIPgetBestSol(scip) != heurdata->lastcallsol )
2334 	   {
2335 	      heurdata->lastcallsol = SCIPgetBestSol(scip);
2336 	      heurdata->firstcallthissol = SCIPheurGetNCalls(heur);
2337 	   }
2338 	
2339 	   /* do not run more than a user-defined number of times on each incumbent (-1: no limit) */
2340 	   if( heurdata->maxcallssamesol != -1 )
2341 	   {
2342 	      SCIP_Longint samesollimit = (heurdata->maxcallssamesol > 0) ?
2343 	         heurdata->maxcallssamesol :
2344 	         heurdata->nactiveneighborhoods;
2345 	
2346 	      if( SCIPheurGetNCalls(heur) - heurdata->firstcallthissol >= samesollimit )
2347 	      {
2348 	         SCIPdebugMsg(scip, "Heuristic already called %" SCIP_LONGINT_FORMAT " times on current incumbent\n", SCIPheurGetNCalls(heur) - heurdata->firstcallthissol);
2349 	         return SCIP_OKAY;
2350 	      }
2351 	   }
2352 	
2353 	   /* wait for a sufficient number of nodes since last incumbent solution */
2354 	   if( SCIPgetDepth(scip) > 0 && SCIPgetBestSol(scip) != NULL
2355 	      && (SCIPgetNNodes(scip) - SCIPsolGetNodenum(SCIPgetBestSol(scip))) < heurdata->waitingnodes )
2356 	   {
2357 	      SCIPdebugMsg(scip, "Waiting nodes not satisfied\n");
2358 	      return SCIP_OKAY;
2359 	   }
2360 	
2361 	   run = TRUE;
2362 	   /* check if budget allows a run of the next selected neighborhood */
2363 	   SCIP_CALL( determineLimits(scip, heur, &solvelimits, &run) );
2364 	   SCIPdebugMsg(scip, "Budget check: %" SCIP_LONGINT_FORMAT " (%" SCIP_LONGINT_FORMAT ") %s\n", solvelimits.nodelimit, heurdata->targetnodes, run ? "passed" : "must wait");
2365 	
2366 	   if( ! run )
2367 	      return SCIP_OKAY;
2368 	
2369 	   /* delay the heuristic if local reduced costs should be used for generic variable unfixing */
2370 	   if( heurdata->uselocalredcost && (nodeinfeasible || ! SCIPhasCurrentNodeLP(scip) || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL) )
2371 	   {
2372 	      *result = SCIP_DELAYED;
2373 	
2374 	      return SCIP_OKAY;
2375 	   }
2376 	
2377 	   allrewardsmode = heurdata->rewardfile != NULL;
2378 	
2379 	   /* apply some other rules for a fair all rewards mode; in normal execution mode, neighborhoods are iterated through */
2380 	   if( allrewardsmode )
2381 	   {
2382 	      /* most neighborhoods require an incumbent solution */
2383 	      if( SCIPgetNSols(scip) < 2 )
2384 	      {
2385 	         SCIPdebugMsg(scip, "Not enough solutions for all rewards mode\n");
2386 	         return SCIP_OKAY;
2387 	      }
2388 	
2389 	      /* if the node is infeasible, or has no LP solution, which is required by some neighborhoods
2390 	       * if we are not in all rewards mode, the neighborhoods delay themselves individually
2391 	       */
2392 	      if( nodeinfeasible || ! SCIPhasCurrentNodeLP(scip) || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
2393 	      {
2394 	         SCIPdebugMsg(scip, "Delay ALNS heuristic until a feasible node with optimally solved LP relaxation\n");
2395 	         *result = SCIP_DELAYED;
2396 	         return SCIP_OKAY;
2397 	      }
2398 	   }
2399 	
2400 	   /* use the neighborhood that requested a delay or select the next neighborhood to run based on the selected bandit algorithm */
2401 	   if( heurdata->currneighborhood >= 0 )
2402 	   {
2403 	      assert(! allrewardsmode);
2404 	      banditidx = heurdata->currneighborhood;
2405 	      SCIPdebugMsg(scip, "Select delayed neighborhood %d (was delayed %d times)\n", banditidx, heurdata->ndelayedcalls);
2406 	   }
2407 	   else
2408 	   {
2409 	      SCIP_CALL( selectNeighborhood(scip, heurdata, &banditidx) );
2410 	      SCIPdebugMsg(scip, "Selected neighborhood %d with bandit algorithm\n", banditidx);
2411 	   }
2412 	
2413 	   /* in all rewards mode, we simply loop over all heuristics */
2414 	   if( ! allrewardsmode )
2415 	      neighborhoodidx = banditidx;
2416 	   else
2417 	      neighborhoodidx = 0;
2418 	
2419 	   assert(0 <= neighborhoodidx && neighborhoodidx < NNEIGHBORHOODS);
2420 	   assert(heurdata->nactiveneighborhoods > neighborhoodidx);
2421 	
2422 	   /* allocate memory for variable fixings buffer */
2423 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2424 	   SCIP_CALL( SCIPallocBufferArray(scip, &varbuf, nvars) );
2425 	   SCIP_CALL( SCIPallocBufferArray(scip, &valbuf, nvars) );
2426 	   SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
2427 	
2428 	   /* initialize neighborhood statistics for a run */
2429 	   ntries = 1;
2430 	   do
2431 	   {
2432 	      SCIP_HASHMAP* varmapf;
2433 	      SCIP_EVENTHDLR* eventhdlr;
2434 	      SCIP_EVENTDATA eventdata;
2435 	      char probnamesuffix[SCIP_MAXSTRLEN];
2436 	      SCIP_Real allfixingrate;
2437 	      int ndomchgs;
2438 	      int nchgobjs;
2439 	      int naddedconss;
2440 	      int v;
2441 	      SCIP_RETCODE retcode;
2442 	      SCIP_RESULT fixresult;
2443 	
2444 	      tryagain = FALSE;
2445 	      neighborhood = heurdata->neighborhoods[neighborhoodidx];
2446 	      SCIPdebugMsg(scip, "Running '%s' neighborhood %d\n", neighborhood->name, neighborhoodidx);
2447 	
2448 	      initRunStats(scip, &runstats[neighborhoodidx]);
2449 	      rewards[neighborhoodidx][REWARDTYPE_TOTAL] = 0.0;
2450 	
2451 	      subscipstatus[neighborhoodidx] = SCIP_STATUS_UNKNOWN;
2452 	      SCIP_CALL( SCIPstartClock(scip, neighborhood->stats.setupclock) );
2453 	
2454 	      /* determine variable fixings and objective coefficients of this neighborhood */
2455 	      SCIP_CALL( neighborhoodFixVariables(scip, heurdata, neighborhood, varbuf, valbuf, &nfixings, &fixresult) );
2456 	
2457 	      SCIPdebugMsg(scip, "Fix %d/%d variables, result code %d\n", nfixings, nvars,fixresult);
2458 	
2459 	      /* Fixing was not successful, either because the fixing rate was not reached (and no additional variable
2460 	       * prioritization was used), or the neighborhood requested a delay, e.g., because no LP relaxation solution exists
2461 	       * at the current node
2462 	       *
2463 	       * The ALNS heuristic keeps a delayed neighborhood active and delays itself.
2464 	       */
2465 	      if( fixresult != SCIP_SUCCESS )
2466 	      {
2467 	         SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.setupclock) );
2468 	
2469 	         /* to determine all rewards, we cannot delay neighborhoods */
2470 	         if( allrewardsmode )
2471 	         {
2472 	            if( ntries == heurdata->nactiveneighborhoods )
2473 	               break;
2474 	
2475 	            neighborhoodidx = (neighborhoodidx + 1) % heurdata->nactiveneighborhoods;
2476 	            ntries++;
2477 	            tryagain = TRUE;
2478 	
2479 	            continue;
2480 	         }
2481 	
2482 	         /* delay the heuristic along with the selected neighborhood
2483 	          *
2484 	          * if the neighborhood has been delayed for too many consecutive calls, the delay is treated as a failure */
2485 	         if( fixresult == SCIP_DELAYED )
2486 	         {
2487 	            if( heurdata->ndelayedcalls > (SCIPheurGetFreq(heur) / 4 + 1) )
2488 	            {
2489 	               resetCurrentNeighborhood(heurdata);
2490 	
2491 	               /* use SCIP_DIDNOTFIND to penalize the neighborhood with a bad reward */
2492 	               fixresult = SCIP_DIDNOTFIND;
2493 	            }
2494 	            else if( heurdata->currneighborhood == -1 )
2495 	            {
2496 	               heurdata->currneighborhood = neighborhoodidx;
2497 	               heurdata->ndelayedcalls = 1;
2498 	            }
2499 	            else
2500 	            {
2501 	               heurdata->ndelayedcalls++;
2502 	            }
2503 	         }
2504 	
2505 	         if( fixresult == SCIP_DIDNOTRUN )
2506 	         {
2507 	            if( ntries < heurdata->nactiveneighborhoods )
2508 	            {
2509 	               SCIP_CALL( updateBanditAlgorithm(scip, heurdata, 0.0, neighborhoodidx) );
2510 	               SCIP_CALL( selectNeighborhood(scip, heurdata, &neighborhoodidx) );
2511 	               ntries++;
2512 	               tryagain = TRUE;
2513 	
2514 	               SCIPdebugMsg(scip, "Neighborhood cannot run -> try next neighborhood %d\n", neighborhoodidx);
2515 	               continue;
2516 	            }
2517 	            else
2518 	               break;
2519 	         }
2520 	
2521 	         assert(fixresult == SCIP_DIDNOTFIND || fixresult == SCIP_DELAYED);
2522 	         *result = fixresult;
2523 	         break;
2524 	      }
2525 	
2526 	      *result = SCIP_DIDNOTFIND;
2527 	
2528 	      neighborhood->stats.nfixings += nfixings;
2529 	      runstats[neighborhoodidx].nfixings = nfixings;
2530 	
2531 	      SCIP_CALL( SCIPcreate(&subscip) );
2532 	      SCIP_CALL( SCIPhashmapCreate(&varmapf, SCIPblkmem(scip), nvars) );
2533 	      (void) SCIPsnprintf(probnamesuffix, SCIP_MAXSTRLEN, "alns_%s", neighborhood->name);
2534 	
2535 	      /* todo later: run global propagation for this set of fixings */
2536 	      SCIP_CALL( SCIPcopyLargeNeighborhoodSearch(scip, subscip, varmapf, probnamesuffix, varbuf, valbuf, nfixings, FALSE, heurdata->copycuts, &success, NULL) );
2537 	
2538 	      /* store sub-SCIP variables in array for faster access */
2539 	      for( v = 0; v < nvars; ++v )
2540 	      {
2541 	         subvars[v] = (SCIP_VAR*)SCIPhashmapGetImage(varmapf, (void *)vars[v]);
2542 	      }
2543 	
2544 	      SCIPhashmapFree(&varmapf);
2545 	
2546 	      /* let the neighborhood add additional constraints, or restrict domains */
2547 	      SCIP_CALL( neighborhoodChangeSubscip(scip, subscip, neighborhood, subvars, &ndomchgs, &nchgobjs, &naddedconss, &success) );
2548 	
2549 	      if( ! success )
2550 	      {
2551 	         SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.setupclock) );
2552 	
2553 	         if( ! allrewardsmode || ntries == heurdata->nactiveneighborhoods )
2554 	            break;
2555 	
2556 	         neighborhoodidx = (neighborhoodidx + 1) % heurdata->nactiveneighborhoods;
2557 	         ntries++;
2558 	         tryagain = TRUE;
2559 	
2560 	         SCIP_CALL( SCIPfree(&subscip) );
2561 	
2562 	         continue;
2563 	      }
2564 	
2565 	      /* set up sub-SCIP parameters */
2566 	      SCIP_CALL( setupSubScip(scip, subscip, subvars, &solvelimits, heur, nchgobjs > 0) );
2567 	
2568 	      /* copy the necessary data into the event data to create new solutions */
2569 	      eventdata.nodelimit = solvelimits.nodelimit;  /*lint !e644*/
2570 	      eventdata.lplimfac = heurdata->lplimfac;
2571 	      eventdata.heur = heur;
2572 	      eventdata.sourcescip = scip;
2573 	      eventdata.subvars = subvars;
2574 	      eventdata.runstats = &runstats[neighborhoodidx];
2575 	      eventdata.allrewardsmode = allrewardsmode;
2576 	
2577 	      /* include an event handler to transfer solutions into the main SCIP */
2578 	      SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecAlns, NULL) );
2579 	
2580 	      /* transform the problem before catching the events */
2581 	      SCIP_CALL( SCIPtransformProb(subscip) );
2582 	      SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_ALNS, eventhdlr, &eventdata, NULL) );
2583 	
2584 	      SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.setupclock) );
2585 	
2586 	      SCIP_CALL( SCIPstartClock(scip, neighborhood->stats.submipclock) );
2587 	
2588 	      /* set up sub-SCIP and run presolving */
2589 	      retcode = SCIPpresolve(subscip);
2590 	      if( retcode != SCIP_OKAY )
2591 	      {
2592 	         SCIPwarningMessage(scip, "Error while presolving subproblem in ALNS heuristic; sub-SCIP terminated with code <%d>\n", retcode);
2593 	         SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.submipclock) );
2594 	
2595 	         SCIPABORT();  /*lint --e{527}*/
2596 	         break;
2597 	      }
2598 	
2599 	      /* was presolving successful enough regarding fixings? otherwise, terminate */
2600 	      allfixingrate = (SCIPgetNOrigVars(subscip) - SCIPgetNVars(subscip)) / (SCIP_Real)SCIPgetNOrigVars(subscip);
2601 	
2602 	      /* additional variables added in presolving may lead to the subSCIP having more variables than the original */
2603 	      allfixingrate = MAX(allfixingrate, 0.0);
2604 	
2605 	      if( allfixingrate >= neighborhood->fixingrate.targetfixingrate / 2.0 )
2606 	      {
2607 	         /* run sub-SCIP for the given budget, and collect statistics */
2608 	         SCIP_CALL_ABORT( SCIPsolve(subscip) );
2609 	      }
2610 	      else
2611 	      {
2612 	         SCIPdebugMsg(scip, "Fixed only %.3f of all variables after presolving -> do not solve sub-SCIP\n", allfixingrate);
2613 	      }
2614 	
2615 	#ifdef ALNS_SUBSCIPOUTPUT
2616 	      SCIP_CALL( SCIPprintStatistics(subscip, NULL) );
2617 	#endif
2618 	
2619 	      SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.submipclock) );
2620 	
2621 	      /* update statistics based on the sub-SCIP run results */
2622 	      updateRunStats(&runstats[neighborhoodidx], subscip);
2623 	      subscipstatus[neighborhoodidx] = SCIPgetStatus(subscip);
2624 	      SCIPdebugMsg(scip, "Status of sub-SCIP run: %d\n", subscipstatus[neighborhoodidx]);
2625 	
2626 	      SCIP_CALL( getReward(scip, heurdata, &runstats[neighborhoodidx], rewards[neighborhoodidx]) );
2627 	
2628 	      /* in all rewards mode, continue with the next neighborhood */
2629 	      if( allrewardsmode && ntries < heurdata->nactiveneighborhoods )
2630 	      {
2631 	         neighborhoodidx = (neighborhoodidx + 1) % heurdata->nactiveneighborhoods;
2632 	         ntries++;
2633 	         tryagain = TRUE;
2634 	
2635 	         SCIP_CALL( SCIPfree(&subscip) );
2636 	      }
2637 	   }
2638 	   while( tryagain && ! SCIPisStopped(scip) );
2639 	
2640 	   if( subscip != NULL )
2641 	   {
2642 	      SCIP_CALL( SCIPfree(&subscip) );
2643 	   }
2644 	
2645 	   SCIPfreeBufferArray(scip, &subvars);
2646 	   SCIPfreeBufferArray(scip, &valbuf);
2647 	   SCIPfreeBufferArray(scip, &varbuf);
2648 	
2649 	   /* update bandit index that may have changed unless we are in all rewards mode */
2650 	   if( ! allrewardsmode )
2651 	      banditidx = neighborhoodidx;
2652 	
2653 	   if( *result != SCIP_DELAYED )
2654 	   {
2655 	      /* decrease the number of neighborhoods that have not been initialized */
2656 	      if( neighborhood->stats.nruns == 0 )
2657 	         --heurdata->ninitneighborhoods;
2658 	
2659 	      heurdata->usednodes += runstats[banditidx].usednodes;
2660 	
2661 	      /* determine the success of this neighborhood, and update the target fixing rate for the next time */
2662 	      updateNeighborhoodStats(&runstats[banditidx], heurdata->neighborhoods[banditidx], subscipstatus[banditidx]);
2663 	
2664 	      /* adjust the fixing rate for this neighborhood
2665 	       * make no adjustments in all rewards mode, because this only affects 1 of 8 heuristics
2666 	       */
2667 	      if( heurdata->adjustfixingrate && ! allrewardsmode )
2668 	      {
2669 	         SCIPdebugMsg(scip, "Update fixing rate: %.2f\n", heurdata->neighborhoods[banditidx]->fixingrate.targetfixingrate);
2670 	         updateFixingRate(heurdata->neighborhoods[banditidx], subscipstatus[banditidx], &runstats[banditidx]);
2671 	         SCIPdebugMsg(scip, "New fixing rate: %.2f\n", heurdata->neighborhoods[banditidx]->fixingrate.targetfixingrate);
2672 	      }
2673 	      /* similarly, update the minimum improvement for the ALNS heuristic */
2674 	      if( heurdata->adjustminimprove )
2675 	      {
2676 	         SCIPdebugMsg(scip, "Update Minimum Improvement: %.4f\n", heurdata->minimprove);
2677 	         updateMinimumImprovement(heurdata, subscipstatus[banditidx], &runstats[banditidx]);
2678 	         SCIPdebugMsg(scip, "--> %.4f\n", heurdata->minimprove);
2679 	      }
2680 	
2681 	      /* update the target node limit based on the status of the selected algorithm */
2682 	      if( heurdata->adjusttargetnodes && SCIPheurGetNCalls(heur) >= heurdata->nactiveneighborhoods )
2683 	      {
2684 	         updateTargetNodeLimit(heurdata, &runstats[banditidx], subscipstatus[banditidx]);
2685 	      }
2686 	
2687 	      /* update the bandit algorithm by the measured reward */
2688 	      SCIP_CALL( updateBanditAlgorithm(scip, heurdata, rewards[banditidx][REWARDTYPE_TOTAL], banditidx) );
2689 	
2690 	      resetCurrentNeighborhood(heurdata);
2691 	   }
2692 	
2693 	   /* write single, measured rewards and the bandit index to the reward file */
2694 	   if( allrewardsmode )
2695 	   {
2696 	      int j;
2697 	      for( j = 0; j < (int)NREWARDTYPES; j++ )
2698 	         for( i = 0; i < heurdata->nactiveneighborhoods; ++i )
2699 	            fprintf(heurdata->rewardfile, "%.4f,", rewards[i][j]);
2700 	
2701 	      fprintf(heurdata->rewardfile, "%d\n", banditidx);
2702 	   }
2703 	
2704 	   return SCIP_OKAY;
2705 	}
2706 	
2707 	/** callback to collect variable fixings of RENS */
2708 	static
2709 	DECL_VARFIXINGS(varFixingsRens)
2710 	{  /*lint --e{715}*/
2711 	   int nbinvars;
2712 	   int nintvars;
2713 	   SCIP_VAR** vars;
2714 	   int i;
2715 	   int *fracidx = NULL;
2716 	   SCIP_Real* frac = NULL;
2717 	   int nfracs;
2718 	
2719 	   assert(scip != NULL);
2720 	   assert(varbuf != NULL);
2721 	   assert(nfixings != NULL);
2722 	   assert(valbuf != NULL);
2723 	
2724 	   *result = SCIP_DELAYED;
2725 	
2726 	   if( ! SCIPhasCurrentNodeLP(scip) )
2727 	      return SCIP_OKAY;
2728 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
2729 	      return SCIP_OKAY;
2730 	
2731 	   *result = SCIP_DIDNOTRUN;
2732 	
2733 	   /* get variable information */
2734 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
2735 	
2736 	   /* return if no binary or integer variables are present */
2737 	   if( nbinvars + nintvars == 0 )
2738 	      return SCIP_OKAY;
2739 	
2740 	   SCIP_CALL( SCIPallocBufferArray(scip, &fracidx, nbinvars + nintvars) );
2741 	   SCIP_CALL( SCIPallocBufferArray(scip, &frac, nbinvars + nintvars) );
2742 	
2743 	   /* loop over binary and integer variables; determine those that should be fixed in the sub-SCIP */
2744 	   for( nfracs = 0, i = 0; i < nbinvars + nintvars; ++i )
2745 	   {
2746 	      SCIP_VAR* var = vars[i];
2747 	      SCIP_Real lpsolval = SCIPvarGetLPSol(var);
2748 	      assert((i < nbinvars && SCIPvarIsBinary(var)) || (i >= nbinvars && SCIPvarIsIntegral(var)));
2749 	
2750 	      /* fix all binary and integer variables with integer LP solution value */
2751 	      if( SCIPisFeasIntegral(scip, lpsolval) )
2752 	      {
2753 	         tryAdd2variableBuffer(scip, var, lpsolval, varbuf, valbuf, nfixings, TRUE);
2754 	      }
2755 	      else
2756 	      {
2757 	         frac[nfracs] = SCIPfrac(scip, lpsolval);
2758 	         frac[nfracs] = MIN(frac[nfracs], 1.0 - frac[nfracs]);
2759 	         fracidx[nfracs++] = i;
2760 	      }
2761 	   }
2762 	
2763 	   /* do some additional fixing */
2764 	   if( *nfixings < neighborhood->fixingrate.targetfixingrate * (nbinvars + nintvars) && nfracs > 0 )
2765 	   {
2766 	      SCIPsortDownRealInt(frac, fracidx, nfracs);
2767 	
2768 	      /* prefer variables that are almost integer */
2769 	      for( i = 0; i < nfracs && *nfixings < neighborhood->fixingrate.targetfixingrate * (nbinvars + nintvars); i++ )
2770 	      {
2771 	         tryAdd2variableBuffer(scip, vars[fracidx[i]], SCIPround(scip, SCIPvarGetLPSol(vars[fracidx[i]])), varbuf, valbuf, nfixings, TRUE);
2772 	      }
2773 	   }
2774 	
2775 	   SCIPfreeBufferArray(scip, &frac);
2776 	   SCIPfreeBufferArray(scip, &fracidx);
2777 	
2778 	   *result = SCIP_SUCCESS;
2779 	
2780 	   return SCIP_OKAY;
2781 	}
2782 	
2783 	/** callback for RENS subproblem changes */
2784 	static
2785 	DECL_CHANGESUBSCIP(changeSubscipRens)
2786 	{  /*lint --e{715}*/
2787 	   SCIP_VAR** vars;
2788 	   int nintvars;
2789 	   int nbinvars;
2790 	   int i;
2791 	
2792 	   assert(SCIPhasCurrentNodeLP(sourcescip));
2793 	   assert(SCIPgetLPSolstat(sourcescip) == SCIP_LPSOLSTAT_OPTIMAL);
2794 	
2795 	   /* get variable information */
2796 	   SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
2797 	
2798 	   /* restrict bounds of integer variables with fractional solution value */
2799 	   for( i = nbinvars; i < nbinvars + nintvars; ++i )
2800 	   {
2801 	      SCIP_VAR* var = vars[i];
2802 	      SCIP_Real lpsolval = SCIPgetSolVal(sourcescip, NULL, var);
2803 	
2804 	      if( subvars[i] == NULL )
2805 	         continue;
2806 	
2807 	      if( ! SCIPisFeasIntegral(sourcescip, lpsolval) )
2808 	      {
2809 	         SCIP_Real newlb = SCIPfloor(sourcescip, lpsolval);
2810 	         SCIP_Real newub = newlb + 1.0;
2811 	
2812 	         /* only count this as a domain change if the new lower and upper bound are a further restriction */
2813 	         if( newlb > SCIPvarGetLbGlobal(subvars[i]) + 0.5 || newub < SCIPvarGetUbGlobal(subvars[i]) - 0.5 )
2814 	         {
2815 	            SCIP_CALL( SCIPchgVarLbGlobal(targetscip, subvars[i], newlb) );
2816 	            SCIP_CALL( SCIPchgVarUbGlobal(targetscip, subvars[i], newub) );
2817 	            (*ndomchgs)++;
2818 	         }
2819 	      }
2820 	   }
2821 	
2822 	   *success = TRUE;
2823 	
2824 	   return SCIP_OKAY;
2825 	}
2826 	
2827 	/** collect fixings by matching solution values in a collection of solutions for all binary and integer variables,
2828 	 *  or for a custom set of variables
2829 	 */
2830 	static
2831 	SCIP_RETCODE fixMatchingSolutionValues(
2832 	   SCIP*                 scip,               /**< SCIP data structure */
2833 	   SCIP_SOL**            sols,               /**< array of 2 or more solutions. It is okay for the array to contain one element
2834 	                                              *   equal to NULL to represent the current LP solution */
2835 	   int                   nsols,              /**< number of solutions in the array */
2836 	   SCIP_VAR**            vars,               /**< variable array for which solution values must agree */
2837 	   int                   nvars,              /**< number of variables, or -1 for all binary and integer variables */
2838 	   SCIP_VAR**            varbuf,             /**< buffer storage for variable fixings */
2839 	   SCIP_Real*            valbuf,             /**< buffer storage for fixing values */
2840 	   int*                  nfixings            /**< pointer to store the number of fixings */
2841 	   )
2842 	{
2843 	   int v;
2844 	   int nbinintvars;
2845 	   SCIP_SOL* firstsol;
2846 	
2847 	   assert(scip != NULL);
2848 	   assert(sols != NULL);
2849 	   assert(nsols >= 2);
2850 	   assert(varbuf != NULL);
2851 	   assert(valbuf != NULL);
2852 	   assert(nfixings != NULL);
2853 	   assert(*nfixings == 0);
2854 	
2855 	   if( nvars == -1 || vars == NULL )
2856 	   {
2857 	      int nbinvars;
2858 	      int nintvars;
2859 	      SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
2860 	      nbinintvars = nbinvars + nintvars;
2861 	      nvars = nbinintvars;
2862 	   }
2863 	   firstsol = sols[0];
2864 	   assert(nvars > 0);
2865 	
2866 	   /* loop over integer and binary variables and check if their solution values match in all solutions */
2867 	   for( v = 0; v < nvars; ++v )
2868 	   {
2869 	      SCIP_Real solval;
2870 	      SCIP_VAR* var;
2871 	      int s;
2872 	
2873 	      var = vars[v];
2874 	      assert((v < SCIPgetNBinVars(scip) && SCIPvarIsBinary(var)) || (v >= SCIPgetNBinVars(scip) && SCIPvarIsIntegral(var)));
2875 	      solval = SCIPgetSolVal(scip, firstsol, var);
2876 	
2877 	      /* determine if solution values match in all given solutions */
2878 	      for( s = 1; s < nsols; ++s )
2879 	      {
2880 	         SCIP_Real solval2 = SCIPgetSolVal(scip, sols[s], var);
2881 	         if( ! SCIPisEQ(scip, solval, solval2) )
2882 	            break;
2883 	      }
2884 	
2885 	      /* if we did not break early, all solutions agree on the solution value of this variable */
2886 	      if( s == nsols )
2887 	      {
2888 	         tryAdd2variableBuffer(scip, var, solval, varbuf, valbuf, nfixings, TRUE);
2889 	      }
2890 	   }
2891 	
2892 	   return SCIP_OKAY;
2893 	}
2894 	
2895 	/** callback to collect variable fixings of RINS */
2896 	static
2897 	DECL_VARFIXINGS(varFixingsRins)
2898 	{
2899 	   /*lint --e{715}*/
2900 	   int nbinvars;
2901 	   int nintvars;
2902 	   SCIP_VAR** vars;
2903 	   SCIP_SOL* incumbent;
2904 	   SCIP_SOL* sols[2];
2905 	   assert(scip != NULL);
2906 	   assert(varbuf != NULL);
2907 	   assert(nfixings != NULL);
2908 	   assert(valbuf != NULL);
2909 	
2910 	   *result = SCIP_DELAYED;
2911 	
2912 	   if( ! SCIPhasCurrentNodeLP(scip) )
2913 	      return SCIP_OKAY;
2914 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
2915 	      return SCIP_OKAY;
2916 	
2917 	   *result = SCIP_DIDNOTRUN;
2918 	
2919 	   incumbent = SCIPgetBestSol(scip);
2920 	   if( incumbent == NULL )
2921 	      return SCIP_OKAY;
2922 	
2923 	   if( SCIPsolGetOrigin(incumbent) == SCIP_SOLORIGIN_ORIGINAL )
2924 	      return SCIP_OKAY;
2925 	
2926 	   /* get variable information */
2927 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
2928 	
2929 	   /* return if no binary or integer variables are present */
2930 	   if( nbinvars + nintvars == 0 )
2931 	      return SCIP_OKAY;
2932 	
2933 	   sols[0] = NULL;
2934 	   sols[1] = incumbent;
2935 	
2936 	   SCIP_CALL( fixMatchingSolutionValues(scip, sols, 2, vars, nbinvars + nintvars, varbuf, valbuf, nfixings) );
2937 	
2938 	   *result = SCIP_SUCCESS;
2939 	
2940 	   return SCIP_OKAY;
2941 	}
2942 	
2943 	/** initialization callback for crossover when a new problem is read */
2944 	static
2945 	DECL_NHINIT(nhInitCrossover)
2946 	{  /*lint --e{715}*/
2947 	   DATA_CROSSOVER* data;
2948 	
2949 	   data = neighborhood->data.crossover;
2950 	   assert(data != NULL);
2951 	
2952 	   if( data->rng != NULL )
2953 	      SCIPfreeRandom(scip, &data->rng);
2954 	
2955 	   data->selsol = NULL;
2956 	
2957 	   SCIP_CALL( SCIPcreateRandom(scip, &data->rng, CROSSOVERSEED + (unsigned int)SCIPgetNVars(scip), TRUE) );
2958 	
2959 	   return SCIP_OKAY;
2960 	}
2961 	
2962 	/** deinitialization callback for crossover when exiting a problem */
2963 	static
2964 	DECL_NHEXIT(nhExitCrossover)
2965 	{  /*lint --e{715}*/
2966 	   DATA_CROSSOVER* data;
2967 	   data = neighborhood->data.crossover;
2968 	
2969 	   assert(neighborhood != NULL);
2970 	   assert(data->rng != NULL);
2971 	
2972 	   SCIPfreeRandom(scip, &data->rng);
2973 	
2974 	   return SCIP_OKAY;
2975 	}
2976 	
2977 	/** deinitialization callback for crossover before SCIP is freed */
2978 	static
2979 	DECL_NHFREE(nhFreeCrossover)
2980 	{  /*lint --e{715}*/
2981 	   assert(neighborhood->data.crossover != NULL);
2982 	   SCIPfreeBlockMemory(scip, &neighborhood->data.crossover);
2983 	
2984 	   return SCIP_OKAY;
2985 	}
2986 	
2987 	/** callback to collect variable fixings of crossover */
2988 	static
2989 	DECL_VARFIXINGS(varFixingsCrossover)
2990 	{  /*lint --e{715}*/
2991 	   DATA_CROSSOVER* data;
2992 	   SCIP_RANDNUMGEN* rng;
2993 	   SCIP_SOL** sols;
2994 	   SCIP_SOL** scipsols;
2995 	   int nsols;
2996 	   int lastdraw;
2997 	   assert(scip != NULL);
2998 	   assert(varbuf != NULL);
2999 	   assert(nfixings != NULL);
3000 	   assert(valbuf != NULL);
3001 	
3002 	   data = neighborhood->data.crossover;
3003 	
3004 	   assert(data != NULL);
3005 	   nsols = data->nsols;
3006 	   data->selsol = NULL;
3007 	
3008 	   *result = SCIP_DIDNOTRUN;
3009 	
3010 	   /* return if the pool has not enough solutions */
3011 	   if( nsols > SCIPgetNSols(scip) )
3012 	      return SCIP_OKAY;
3013 	
3014 	   /* return if no binary or integer variables are present */
3015 	   if( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 )
3016 	      return SCIP_OKAY;
3017 	
3018 	   rng = data->rng;
3019 	   lastdraw = SCIPgetNSols(scip);
3020 	   SCIP_CALL( SCIPallocBufferArray(scip, &sols, nsols) );
3021 	   scipsols = SCIPgetSols(scip);
3022 	
3023 	   /* draw as many solutions from the pool as required by crossover, biased towards
3024 	    * better solutions; therefore, the sorting of the solutions by objective is implicitly used
3025 	    */
3026 	   while( nsols > 0 )
3027 	   {
3028 	      /* no need for randomization anymore, exactly nsols many solutions remain for the selection */
3029 	      if( lastdraw == nsols )
3030 	      {
3031 	         int s;
3032 	
3033 	         /* fill the remaining slots 0,...,nsols - 1 by the solutions at the same places */
3034 	         for( s = 0; s < nsols; ++s )
3035 	            sols[s] = scipsols[s];
3036 	
3037 	         nsols = 0;
3038 	      }
3039 	      else
3040 	      {
3041 	         int nextdraw;
3042 	
3043 	         assert(nsols < lastdraw);
3044 	
3045 	         /* draw from the lastdraw - nsols many solutions nsols - 1, ... lastdraw - 1 such that nsols many solution */
3046 	         nextdraw = SCIPrandomGetInt(rng, nsols - 1, lastdraw - 1);
3047 	         assert(nextdraw >= 0);
3048 	
3049 	         sols[nsols - 1] = scipsols[nextdraw];
3050 	         nsols--;
3051 	         lastdraw = nextdraw;
3052 	      }
3053 	   }
3054 	
3055 	   SCIP_CALL( fixMatchingSolutionValues(scip, sols, data->nsols, NULL, -1, varbuf, valbuf, nfixings) );
3056 	
3057 	   /* store best selected solution as reference solution */
3058 	   data->selsol = sols[0];
3059 	   assert(data->selsol != NULL);
3060 	
3061 	   *result = SCIP_SUCCESS;
3062 	
3063 	   SCIPfreeBufferArray(scip, &sols);
3064 	
3065 	   return SCIP_OKAY;
3066 	}
3067 	
3068 	/** callback for crossover reference solution */
3069 	static
3070 	DECL_NHREFSOL(nhRefsolCrossover)
3071 	{ /*lint --e{715}*/
3072 	   DATA_CROSSOVER* data;
3073 	
3074 	   data = neighborhood->data.crossover;
3075 	
3076 	   if( data->selsol != NULL )
3077 	   {
3078 	      *solptr = data->selsol;
3079 	      *result = SCIP_SUCCESS;
3080 	   }
3081 	   else
3082 	   {
3083 	      *result = SCIP_DIDNOTFIND;
3084 	   }
3085 	
3086 	   return SCIP_OKAY;
3087 	}
3088 	
3089 	/** initialization callback for mutation when a new problem is read */
3090 	static
3091 	DECL_NHINIT(nhInitMutation)
3092 	{  /*lint --e{715}*/
3093 	   DATA_MUTATION* data;
3094 	   assert(scip != NULL);
3095 	   assert(neighborhood != NULL);
3096 	
3097 	   SCIP_CALL( SCIPallocBlockMemory(scip, &neighborhood->data.mutation) );
3098 	
3099 	   data = neighborhood->data.mutation;
3100 	   assert(data != NULL);
3101 	
3102 	   SCIP_CALL( SCIPcreateRandom(scip, &data->rng, MUTATIONSEED + (unsigned int)SCIPgetNVars(scip), TRUE) );
3103 	
3104 	   return SCIP_OKAY;
3105 	}
3106 	
3107 	/** deinitialization callback for mutation when exiting a problem */
3108 	static
3109 	DECL_NHEXIT(nhExitMutation)
3110 	{  /*lint --e{715}*/
3111 	   DATA_MUTATION* data;
3112 	   assert(scip != NULL);
3113 	   assert(neighborhood != NULL);
3114 	   data = neighborhood->data.mutation;
3115 	   assert(data != NULL);
3116 	
3117 	   SCIPfreeRandom(scip, &data->rng);
3118 	
3119 	   SCIPfreeBlockMemory(scip, &neighborhood->data.mutation);
3120 	
3121 	   return SCIP_OKAY;
3122 	}
3123 	
3124 	/** callback to collect variable fixings of mutation */
3125 	static
3126 	DECL_VARFIXINGS(varFixingsMutation)
3127 	{  /*lint --e{715}*/
3128 	   SCIP_RANDNUMGEN* rng;
3129 	
3130 	   SCIP_VAR** vars;
3131 	   SCIP_VAR** varscpy;
3132 	   int i;
3133 	   int nvars;
3134 	   int nbinvars;
3135 	   int nintvars;
3136 	   int nbinintvars;
3137 	   int ntargetfixings;
3138 	   SCIP_SOL* incumbentsol;
3139 	   SCIP_Real targetfixingrate;
3140 	
3141 	   assert(scip != NULL);
3142 	   assert(neighborhood != NULL);
3143 	   assert(neighborhood->data.mutation != NULL);
3144 	   assert(neighborhood->data.mutation->rng != NULL);
3145 	   rng = neighborhood->data.mutation->rng;
3146 	
3147 	   *result = SCIP_DIDNOTRUN;
3148 	
3149 	   /* get the problem variables */
3150 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
3151 	
3152 	   nbinintvars = nbinvars + nintvars;
3153 	   if( nbinintvars == 0 )
3154 	      return SCIP_OKAY;
3155 	
3156 	   incumbentsol = SCIPgetBestSol(scip);
3157 	   if( incumbentsol == NULL )
3158 	      return SCIP_OKAY;
3159 	
3160 	   targetfixingrate = neighborhood->fixingrate.targetfixingrate;
3161 	   ntargetfixings = (int)(targetfixingrate * nbinintvars) + 1;
3162 	
3163 	   /* don't continue if number of discrete variables is too small to reach target fixing rate */
3164 	   if( nbinintvars <= ntargetfixings )
3165 	      return SCIP_OKAY;
3166 	
3167 	   *result = SCIP_DIDNOTFIND;
3168 	
3169 	   /* copy variables into a buffer array */
3170 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &varscpy, vars, nbinintvars) );
3171 	
3172 	   /* partially perturb the array until the number of target fixings is reached */
3173 	   for( i = 0; *nfixings < ntargetfixings && i < nbinintvars; ++i )
3174 	   {
3175 	      int randint = SCIPrandomGetInt(rng, i, nbinintvars - 1);
3176 	      assert(randint < nbinintvars);
3177 	
3178 	      if( randint > i )
3179 	      {
3180 	         SCIPswapPointers((void**)&varscpy[i], (void**)&varscpy[randint]);
3181 	      }
3182 	      /* copy the selected variables and their solution values into the buffer */
3183 	      tryAdd2variableBuffer(scip, varscpy[i], SCIPgetSolVal(scip, incumbentsol, varscpy[i]), varbuf, valbuf, nfixings, TRUE);
3184 	   }
3185 	
3186 	   assert(i == nbinintvars || *nfixings == ntargetfixings);
3187 	
3188 	   /* Not reaching the number of target fixings means that there is a significant fraction (at least 1 - targetfixingrate)
3189 	    * of variables for which the incumbent solution value does not lie within the global bounds anymore. This is a nonsuccess
3190 	    * for the neighborhood (additional fixings are not possible), which is okay because the incumbent solution is
3191 	    * significantly outdated
3192 	    */
3193 	   if( *nfixings == ntargetfixings )
3194 	      *result = SCIP_SUCCESS;
3195 	
3196 	   /* free the buffer array */
3197 	   SCIPfreeBufferArray(scip, &varscpy);
3198 	
3199 	   return SCIP_OKAY;
3200 	}
3201 	
3202 	/** add local branching constraint */
3203 	static
3204 	SCIP_RETCODE addLocalBranchingConstraint(
3205 	   SCIP*                 sourcescip,         /**< source SCIP data structure */
3206 	   SCIP*                 targetscip,         /**< target SCIP data structure */
3207 	   SCIP_VAR**            subvars,            /**< array of sub SCIP variables in same order as source SCIP variables */
3208 	   int                   distance,           /**< right hand side of the local branching constraint */
3209 	   SCIP_Bool*            success,            /**< pointer to store of a local branching constraint has been successfully added */
3210 	   int*                  naddedconss         /**< pointer to increase the number of added constraints */
3211 	   )
3212 	{
3213 	   int nbinvars;
3214 	   int i;
3215 	   SCIP_SOL* referencesol;
3216 	   SCIP_CONS* localbranchcons;
3217 	   SCIP_VAR** vars;
3218 	   SCIP_Real* consvals;
3219 	   SCIP_Real rhs;
3220 	
3221 	   assert(sourcescip != NULL);
3222 	   assert(*success == FALSE);
3223 	
3224 	   nbinvars = SCIPgetNBinVars(sourcescip);
3225 	   vars = SCIPgetVars(sourcescip);
3226 	
3227 	   if( nbinvars <= 3 )
3228 	      return SCIP_OKAY;
3229 	
3230 	   referencesol = SCIPgetBestSol(sourcescip);
3231 	   if( referencesol == NULL )
3232 	      return SCIP_OKAY;
3233 	
3234 	   rhs = (SCIP_Real)distance;
3235 	   rhs = MAX(rhs, 2.0);
3236 	
3237 	   SCIP_CALL( SCIPallocBufferArray(sourcescip, &consvals, nbinvars) );
3238 	
3239 	   /* loop over binary variables and fill the local branching constraint */
3240 	   for( i = 0; i < nbinvars; ++i )
3241 	   {
3242 	      /* skip variables that are not present in sub-SCIP */
3243 	      if( subvars[i] == NULL )
3244 	         continue;
3245 	
3246 	      if( SCIPisEQ(sourcescip, SCIPgetSolVal(sourcescip, referencesol, vars[i]), 0.0) )
3247 	         consvals[i] = 1.0;
3248 	      else
3249 	      {
3250 	         consvals[i] = -1.0;
3251 	         rhs -= 1.0;
3252 	      }
3253 	   }
3254 	
3255 	   /* create the local branching constraint in the target scip */
3256 	   SCIP_CALL( SCIPcreateConsBasicLinear(targetscip, &localbranchcons, "localbranch", nbinvars, subvars, consvals, -SCIPinfinity(sourcescip), rhs) );
3257 	   SCIP_CALL( SCIPaddCons(targetscip, localbranchcons) );
3258 	   SCIP_CALL( SCIPreleaseCons(targetscip, &localbranchcons) );
3259 	
3260 	   *naddedconss = 1;
3261 	   *success = TRUE;
3262 	
3263 	   SCIPfreeBufferArray(sourcescip, &consvals);
3264 	
3265 	   return SCIP_OKAY;
3266 	}
3267 	
3268 	/** callback for local branching subproblem changes */
3269 	static
3270 	DECL_CHANGESUBSCIP(changeSubscipLocalbranching)
3271 	{  /*lint --e{715}*/
3272 	
3273 	   SCIP_CALL( addLocalBranchingConstraint(sourcescip, targetscip, subvars, (int)(0.2 * SCIPgetNBinVars(sourcescip)), success, naddedconss) );
3274 	
3275 	   return SCIP_OKAY;
3276 	}
3277 	
3278 	/** callback for proximity subproblem changes */
3279 	static
3280 	DECL_CHANGESUBSCIP(changeSubscipProximity)
3281 	{  /*lint --e{715}*/
3282 	   SCIP_SOL* referencesol;
3283 	   SCIP_VAR** vars;
3284 	   int nbinvars;
3285 	   int nintvars;
3286 	   int nvars;
3287 	   int i;
3288 	
3289 	   SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
3290 	
3291 	   if( nbinvars == 0 )
3292 	      return SCIP_OKAY;
3293 	
3294 	   referencesol = SCIPgetBestSol(sourcescip);
3295 	   if( referencesol == NULL )
3296 	      return SCIP_OKAY;
3297 	
3298 	   /* loop over binary variables, set objective coefficients based on reference solution in a local branching fashion */
3299 	   for( i = 0; i < nbinvars; ++i )
3300 	   {
3301 	      SCIP_Real newobj;
3302 	
3303 	      /* skip variables not present in sub-SCIP */
3304 	      if( subvars[i] == NULL )
3305 	         continue;
3306 	
3307 	      if( SCIPgetSolVal(sourcescip, referencesol, vars[i]) < 0.5 )
3308 	         newobj = -1.0;
3309 	      else
3310 	         newobj = 1.0;
3311 	      SCIP_CALL( SCIPchgVarObj(targetscip, subvars[i], newobj) );
3312 	   }
3313 	
3314 	   /* loop over the remaining variables and change their objective coefficients to 0 */
3315 	   for( ; i < nvars; ++i )
3316 	   {
3317 	      /* skip variables not present in sub-SCIP */
3318 	      if( subvars[i] == NULL )
3319 	         continue;
3320 	
3321 	      SCIP_CALL( SCIPchgVarObj(targetscip, subvars[i], 0.0) );
3322 	   }
3323 	
3324 	   *nchgobjs = nvars;
3325 	   *success = TRUE;
3326 	
3327 	   return SCIP_OKAY;
3328 	}
3329 	
3330 	/** callback for zeroobjective subproblem changes */
3331 	static
3332 	DECL_CHANGESUBSCIP(changeSubscipZeroobjective)
3333 	{  /*lint --e{715}*/
3334 	   SCIP_CONSHDLR* conshdlrnl;
3335 	   SCIP_VAR** vars;
3336 	   int nvars;
3337 	   int i;
3338 	
3339 	   assert(*success == FALSE);
3340 	
3341 	   SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, &nvars, NULL, NULL, NULL, NULL) );
3342 	
3343 	   /* do not run if no objective variables are present */
3344 	   if( SCIPgetNObjVars(sourcescip) == 0 )
3345 	      return SCIP_OKAY;
3346 	
3347 	   /* zeroobj may trigger fixing objvar in nonlinear constraint to infinity,
3348 	    * which expr_var.c:simplify cannot handle at the moment; also #3273
3349 	    */
3350 	   conshdlrnl = SCIPfindConshdlr(sourcescip, "nonlinear");
3351 	   if( conshdlrnl != NULL && SCIPconshdlrGetNActiveConss(conshdlrnl) > 0 )
3352 	      return SCIP_OKAY;
3353 	
3354 	   /* loop over the variables and change their objective coefficients to 0 */
3355 	   for( i = 0; i < nvars; ++i )
3356 	   {
3357 	      /* skip variables not present in sub-SCIP */
3358 	      if( subvars[i] == NULL )
3359 	         continue;
3360 	
3361 	      SCIP_CALL( SCIPchgVarObj(targetscip, subvars[i], 0.0) );
3362 	   }
3363 	
3364 	   *nchgobjs = nvars;
3365 	   *success = TRUE;
3366 	
3367 	   return SCIP_OKAY;
3368 	}
3369 	
3370 	/** compute tightened bounds for integer variables depending on how much the LP and the incumbent solution values differ */
3371 	static
3372 	void computeIntegerVariableBoundsDins(
3373 	   SCIP*                 scip,               /**< SCIP data structure of the original problem */
3374 	   SCIP_VAR*             var,                /**< the variable for which bounds should be computed */
3375 	   SCIP_Real*            lbptr,              /**< pointer to store the lower bound in the DINS sub-SCIP */
3376 	   SCIP_Real*            ubptr               /**< pointer to store the upper bound in the DINS sub-SCIP */
3377 	   )
3378 	{
3379 	   SCIP_Real mipsol;
3380 	   SCIP_Real lpsol;
3381 	
3382 	   SCIP_Real lbglobal;
3383 	   SCIP_Real ubglobal;
3384 	   SCIP_SOL* bestsol;
3385 	
3386 	   /* get the bounds for each variable */
3387 	   lbglobal = SCIPvarGetLbGlobal(var);
3388 	   ubglobal = SCIPvarGetUbGlobal(var);
3389 	
3390 	   assert(SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER);
3391 	   /* get the current LP solution for each variable */
3392 	   lpsol = SCIPvarGetLPSol(var);
3393 	
3394 	   /* get the current MIP solution for each variable */
3395 	   bestsol = SCIPgetBestSol(scip);
3396 	   mipsol = SCIPgetSolVal(scip, bestsol, var);
3397 	
3398 	   /* if the solution values differ by 0.5 or more, the variable is rebounded, otherwise it is just copied */
3399 	   if( REALABS(lpsol - mipsol) >= 0.5 )
3400 	   {
3401 	      SCIP_Real range;
3402 	
3403 	      *lbptr = lbglobal;
3404 	      *ubptr = ubglobal;
3405 	
3406 	      /* create an equally sized range around lpsol for general integers: bounds are lpsol +- (mipsol-lpsol) */
3407 	      range = 2 * lpsol - mipsol;
3408 	
3409 	      if( mipsol >= lpsol )
3410 	      {
3411 	         range = SCIPfeasCeil(scip, range);
3412 	         *lbptr = MAX(*lbptr, range);
3413 	
3414 	         /* when the bound new upper bound is equal to the current MIP solution, we set both bounds to the integral bound (without eps) */
3415 	         if( SCIPisFeasEQ(scip, mipsol, *lbptr) )
3416 	            *ubptr = *lbptr;
3417 	         else
3418 	            *ubptr = mipsol;
3419 	      }
3420 	      else
3421 	      {
3422 	         range = SCIPfeasFloor(scip, range);
3423 	         *ubptr = MIN(*ubptr, range);
3424 	
3425 	         /* when the bound new upper bound is equal to the current MIP solution, we set both bounds to the integral bound (without eps) */
3426 	         if( SCIPisFeasEQ(scip, mipsol, *ubptr) )
3427 	            *lbptr = *ubptr;
3428 	         else
3429 	            *lbptr = mipsol;
3430 	      }
3431 	
3432 	      /* the global domain of variables might have been reduced since incumbent was found: adjust lb and ub accordingly */
3433 	      *lbptr = MAX(*lbptr, lbglobal);
3434 	      *ubptr = MIN(*ubptr, ubglobal);
3435 	   }
3436 	   else
3437 	   {
3438 	      /* the global domain of variables might have been reduced since incumbent was found: adjust it accordingly */
3439 	      *lbptr = MAX(mipsol, lbglobal);
3440 	      *ubptr = MIN(mipsol, ubglobal);
3441 	   }
3442 	}
3443 	
3444 	/** callback to collect variable fixings of DINS */
3445 	static
3446 	DECL_VARFIXINGS(varFixingsDins)
3447 	{
3448 	   DATA_DINS* data;
3449 	   SCIP_SOL* rootlpsol;
3450 	   SCIP_SOL** sols;
3451 	   int nsols;
3452 	   int nmipsols;
3453 	   int nbinvars;
3454 	   int nintvars;
3455 	   SCIP_VAR** vars;
3456 	   int v;
3457 	
3458 	   data = neighborhood->data.dins;
3459 	   assert(data != NULL);
3460 	   nmipsols = SCIPgetNSols(scip);
3461 	   nmipsols = MIN(nmipsols, data->npoolsols);
3462 	
3463 	   *result = SCIP_DELAYED;
3464 	
3465 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
3466 	      return SCIP_OKAY;
3467 	
3468 	   *result = SCIP_DIDNOTRUN;
3469 	
3470 	   if( nmipsols == 0 )
3471 	      return SCIP_OKAY;
3472 	
3473 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3474 	
3475 	   if( nbinvars + nintvars == 0 )
3476 	      return SCIP_OKAY;
3477 	
3478 	   SCIP_CALL( SCIPcreateSol(scip, &rootlpsol, NULL) );
3479 	
3480 	   /* save root solution LP values in solution */
3481 	   for( v = 0; v < nbinvars + nintvars; ++v )
3482 	   {
3483 	      SCIP_CALL( SCIPsetSolVal(scip, rootlpsol, vars[v], SCIPvarGetRootSol(vars[v])) );
3484 	   }
3485 	
3486 	   /* add the node and the root LP solution */
3487 	   nsols = nmipsols + 2;
3488 	
3489 	   SCIP_CALL( SCIPallocBufferArray(scip, &sols, nsols) );
3490 	   sols[0] = NULL; /* node LP solution */
3491 	   sols[1] = rootlpsol;
3492 	
3493 	   /* copy the remaining MIP solutions after the LP solutions */
3494 	   BMScopyMemoryArray(&sols[2], SCIPgetSols(scip), nmipsols); /*lint !e866*/
3495 	
3496 	   /* 1. Binary variables are fixed if their values agree in all the solutions */
3497 	   if( nbinvars > 0 )
3498 	   {
3499 	      SCIP_CALL( fixMatchingSolutionValues(scip, sols, nsols, vars, nbinvars, varbuf, valbuf, nfixings) );
3500 	   }
3501 	
3502 	   /* 2. Integer variables are fixed if they have a very low distance between the incumbent and the root LP solution */
3503 	   for( v = nbinvars; v < nintvars; ++v )
3504 	   {
3505 	      SCIP_Real lb;
3506 	      SCIP_Real ub;
3507 	      computeIntegerVariableBoundsDins(scip, vars[v], &lb, &ub);
3508 	
3509 	      if( ub - lb < 0.5 )
3510 	      {
3511 	         assert(SCIPisFeasIntegral(scip, lb));
3512 	         tryAdd2variableBuffer(scip, vars[v], lb, varbuf, valbuf, nfixings, TRUE);
3513 	      }
3514 	   }
3515 	
3516 	   *result = SCIP_SUCCESS;
3517 	
3518 	   SCIPfreeBufferArray(scip, &sols);
3519 	
3520 	   SCIP_CALL( SCIPfreeSol(scip, &rootlpsol) );
3521 	
3522 	   return SCIP_OKAY;
3523 	}
3524 	
3525 	/** callback for DINS subproblem changes */
3526 	static
3527 	DECL_CHANGESUBSCIP(changeSubscipDins)
3528 	{  /*lint --e{715}*/
3529 	   SCIP_VAR** vars;
3530 	   int nintvars;
3531 	   int nbinvars;
3532 	   int v;
3533 	
3534 	   SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3535 	
3536 	   /* 1. loop over integer variables and tighten the bounds */
3537 	   for( v = nbinvars; v < nintvars; ++v )
3538 	   {
3539 	      SCIP_Real lb;
3540 	      SCIP_Real ub;
3541 	
3542 	      /* skip variables not present in sub-SCIP */
3543 	      if( subvars[v] == NULL )
3544 	         continue;
3545 	
3546 	      computeIntegerVariableBoundsDins(sourcescip, vars[v], &lb, &ub);
3547 	
3548 	      SCIP_CALL( SCIPchgVarLbGlobal(targetscip, subvars[v], lb) );
3549 	      SCIP_CALL( SCIPchgVarUbGlobal(targetscip, subvars[v], ub) );
3550 	      ++(*ndomchgs);
3551 	   }
3552 	
3553 	   /* 2. add local branching constraint for binary variables */
3554 	   SCIP_CALL( addLocalBranchingConstraint(sourcescip, targetscip, subvars, (int)(0.1 * SCIPgetNBinVars(sourcescip)), success, naddedconss) );
3555 	
3556 	   *success = TRUE;
3557 	
3558 	   return SCIP_OKAY;
3559 	}
3560 	
3561 	/** deinitialization callback for DINS before SCIP is freed */
3562 	static
3563 	DECL_NHFREE(nhFreeDins)
3564 	{
3565 	   assert(neighborhood->data.dins != NULL);
3566 	
3567 	   SCIPfreeBlockMemory(scip, &neighborhood->data.dins);
3568 	
3569 	   return SCIP_OKAY;
3570 	}
3571 	
3572 	/** deinitialization callback for trustregion before SCIP is freed */
3573 	static
3574 	DECL_NHFREE(nhFreeTrustregion)
3575 	{
3576 	   assert(neighborhood->data.trustregion != NULL);
3577 	
3578 	   SCIPfreeBlockMemory(scip, &neighborhood->data.trustregion);
3579 	
3580 	   return SCIP_OKAY;
3581 	}
3582 	
3583 	/** add trust region neighborhood constraint and auxiliary objective variable */
3584 	static
3585 	DECL_CHANGESUBSCIP(changeSubscipTrustregion)
3586 	{  /*lint --e{715}*/
3587 	   DATA_TRUSTREGION* data;
3588 	
3589 	   data = neighborhood->data.trustregion;
3590 	
3591 	   /* adding the neighborhood constraint for the trust region heuristic */
3592 	   SCIP_CALL( SCIPaddTrustregionNeighborhoodConstraint(sourcescip, targetscip, subvars, data->violpenalty) );
3593 	
3594 	   /* incrementing the change in objective since an additional variable is added to the objective to penalize the
3595 	    * violation of the trust region.
3596 	    */
3597 	   ++(*nchgobjs);
3598 	
3599 	   return SCIP_OKAY;
3600 	}
3601 	
3602 	/** callback that returns the incumbent solution as a reference point */
3603 	static
3604 	DECL_NHREFSOL(nhRefsolIncumbent)
3605 	{  /*lint --e{715}*/
3606 	   assert(scip != NULL);
3607 	
3608 	   if( SCIPgetBestSol(scip) != NULL )
3609 	   {
3610 	      *result = SCIP_SUCCESS;
3611 	      *solptr = SCIPgetBestSol(scip);
3612 	   }
3613 	   else
3614 	   {
3615 	      *result = SCIP_DIDNOTFIND;
3616 	   }
3617 	
3618 	   return SCIP_OKAY;
3619 	}
3620 	
3621 	
3622 	/** callback function that deactivates a neighborhood on problems with no discrete variables */
3623 	static
3624 	DECL_NHDEACTIVATE(nhDeactivateDiscreteVars)
3625 	{ /*lint --e{715}*/
3626 	   assert(scip != NULL);
3627 	   assert(deactivate != NULL);
3628 	
3629 	   /* deactivate if no discrete variables are present */
3630 	   *deactivate = (SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0);
3631 	
3632 	   return SCIP_OKAY;
3633 	}
3634 	
3635 	/** callback function that deactivates a neighborhood on problems with no binary variables */
3636 	static
3637 	DECL_NHDEACTIVATE(nhDeactivateBinVars)
3638 	{ /*lint --e{715}*/
3639 	   assert(scip != NULL);
3640 	   assert(deactivate != NULL);
3641 	
3642 	   /* deactivate if no discrete variables are present */
3643 	   *deactivate = (SCIPgetNBinVars(scip) == 0);
3644 	
3645 	   return SCIP_OKAY;
3646 	}
3647 	
3648 	/** callback function that deactivates a neighborhood on problems with no objective variables */
3649 	static
3650 	DECL_NHDEACTIVATE(nhDeactivateObjVars)
3651 	{ /*lint --e{715}*/
3652 	   assert(scip != NULL);
3653 	   assert(deactivate != NULL);
3654 	
3655 	   /* deactivate if no discrete variables are present */
3656 	   *deactivate = (SCIPgetNObjVars(scip) == 0);
3657 	
3658 	   return SCIP_OKAY;
3659 	}
3660 	
3661 	
3662 	/** include all neighborhoods */
3663 	static
3664 	SCIP_RETCODE includeNeighborhoods(
3665 	   SCIP*                 scip,               /**< SCIP data structure */
3666 	   SCIP_HEURDATA*        heurdata            /**< heuristic data of the ALNS heuristic */
3667 	   )
3668 	{
3669 	   NH* rens;
3670 	   NH* rins;
3671 	   NH* mutation;
3672 	   NH* localbranching;
3673 	   NH* crossover;
3674 	   NH* proximity;
3675 	   NH* zeroobjective;
3676 	   NH* dins;
3677 	   NH* trustregion;
3678 	
3679 	   heurdata->nneighborhoods = 0;
3680 	
3681 	   /* include the RENS neighborhood */
3682 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &rens, "rens",
3683 	         DEFAULT_MINFIXINGRATE_RENS, DEFAULT_MAXFIXINGRATE_RENS, DEFAULT_ACTIVE_RENS, DEFAULT_PRIORITY_RENS,
3684 	         varFixingsRens, changeSubscipRens, NULL, NULL, NULL, NULL, nhDeactivateDiscreteVars) );
3685 	
3686 	   /* include the RINS neighborhood */
3687 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &rins, "rins",
3688 	         DEFAULT_MINFIXINGRATE_RINS, DEFAULT_MAXFIXINGRATE_RINS, DEFAULT_ACTIVE_RINS, DEFAULT_PRIORITY_RINS,
3689 	         varFixingsRins, NULL, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateDiscreteVars) );
3690 	
3691 	   /* include the mutation neighborhood */
3692 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &mutation, "mutation",
3693 	         DEFAULT_MINFIXINGRATE_MUTATION, DEFAULT_MAXFIXINGRATE_MUTATION, DEFAULT_ACTIVE_MUTATION, DEFAULT_PRIORITY_MUTATION,
3694 	         varFixingsMutation, NULL, nhInitMutation, nhExitMutation, NULL, nhRefsolIncumbent, nhDeactivateDiscreteVars) );
3695 	
3696 	   /* include the local branching neighborhood */
3697 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &localbranching, "localbranching",
3698 	         DEFAULT_MINFIXINGRATE_LOCALBRANCHING, DEFAULT_MAXFIXINGRATE_LOCALBRANCHING, DEFAULT_ACTIVE_LOCALBRANCHING, DEFAULT_PRIORITY_LOCALBRANCHING,
3699 	         NULL, changeSubscipLocalbranching, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateBinVars) );
3700 	
3701 	   /* include the crossover neighborhood */
3702 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &crossover, "crossover",
3703 	         DEFAULT_MINFIXINGRATE_CROSSOVER, DEFAULT_MAXFIXINGRATE_CROSSOVER, DEFAULT_ACTIVE_CROSSOVER, DEFAULT_PRIORITY_CROSSOVER,
3704 	         varFixingsCrossover, NULL,
3705 	         nhInitCrossover, nhExitCrossover, nhFreeCrossover, nhRefsolCrossover, nhDeactivateDiscreteVars) );
3706 	
3707 	   /* allocate data for crossover to include the parameter */
3708 	   SCIP_CALL( SCIPallocBlockMemory(scip, &crossover->data.crossover) );
3709 	   crossover->data.crossover->rng = NULL;
3710 	
3711 	   /* add crossover neighborhood parameters */
3712 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/alns/crossover/nsols", "the number of solutions that crossover should combine",
3713 	         &crossover->data.crossover->nsols, TRUE, DEFAULT_NSOLS_CROSSOVER, 2, 10, NULL, NULL) );
3714 	
3715 	   /* include the Proximity neighborhood */
3716 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &proximity, "proximity",
3717 	         DEFAULT_MINFIXINGRATE_PROXIMITY, DEFAULT_MAXFIXINGRATE_PROXIMITY, DEFAULT_ACTIVE_PROXIMITY, DEFAULT_PRIORITY_PROXIMITY,
3718 	         NULL, changeSubscipProximity, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateBinVars) );
3719 	
3720 	   /* include the Zeroobjective neighborhood */
3721 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &zeroobjective, "zeroobjective",
3722 	         DEFAULT_MINFIXINGRATE_ZEROOBJECTIVE, DEFAULT_MAXFIXINGRATE_ZEROOBJECTIVE, DEFAULT_ACTIVE_ZEROOBJECTIVE, DEFAULT_PRIORITY_ZEROOBJECTIVE,
3723 	         NULL, changeSubscipZeroobjective, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateObjVars) );
3724 	
3725 	   /* include the DINS neighborhood */
3726 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &dins, "dins",
3727 	         DEFAULT_MINFIXINGRATE_DINS, DEFAULT_MAXFIXINGRATE_DINS, DEFAULT_ACTIVE_DINS, DEFAULT_PRIORITY_DINS,
3728 	         varFixingsDins, changeSubscipDins, NULL, NULL, nhFreeDins, nhRefsolIncumbent, nhDeactivateBinVars) );
3729 	
3730 	   /* allocate data for DINS to include the parameter */
3731 	   SCIP_CALL( SCIPallocBlockMemory(scip, &dins->data.dins) );
3732 	
3733 	   /* add DINS neighborhood parameters */
3734 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/alns/dins/npoolsols",
3735 	         "number of pool solutions where binary solution values must agree",
3736 	         &dins->data.dins->npoolsols, TRUE, DEFAULT_NPOOLSOLS_DINS, 1, 100, NULL, NULL) );
3737 	
3738 	   /* include the trustregion neighborhood */
3739 	   SCIP_CALL( alnsIncludeNeighborhood(scip, heurdata, &trustregion, "trustregion",
3740 	         DEFAULT_MINFIXINGRATE_TRUSTREGION, DEFAULT_MAXFIXINGRATE_TRUSTREGION, DEFAULT_ACTIVE_TRUSTREGION, DEFAULT_PRIORITY_TRUSTREGION,
3741 	         NULL, changeSubscipTrustregion, NULL, NULL, nhFreeTrustregion, nhRefsolIncumbent, nhDeactivateBinVars) );
3742 	
3743 	   /* allocate data for trustregion to include the parameter */
3744 	   SCIP_CALL( SCIPallocBlockMemory(scip, &trustregion->data.trustregion) );
3745 	
3746 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/trustregion/violpenalty",
3747 	         "the penalty for each change in the binary variables from the candidate solution",
3748 	         &trustregion->data.trustregion->violpenalty, FALSE, DEFAULT_VIOLPENALTY_TRUSTREGION, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3749 	
3750 	   return SCIP_OKAY;
3751 	}
3752 	
3753 	/** initialization method of primal heuristic (called after problem was transformed) */
3754 	static
3755 	SCIP_DECL_HEURINIT(heurInitAlns)
3756 	{  /*lint --e{715}*/
3757 	   SCIP_HEURDATA* heurdata;
3758 	   int i;
3759 	
3760 	   assert(scip != NULL);
3761 	   assert(heur != NULL);
3762 	
3763 	   heurdata = SCIPheurGetData(heur);
3764 	   assert(heurdata != NULL);
3765 	
3766 	   /* reactivate all neighborhoods if a new problem is read in */
3767 	   heurdata->nactiveneighborhoods = heurdata->nneighborhoods;
3768 	
3769 	   /* initialize neighborhoods for new problem */
3770 	   for( i = 0; i < heurdata->nneighborhoods; ++i )
3771 	   {
3772 	      NH* neighborhood = heurdata->neighborhoods[i];
3773 	
3774 	      SCIP_CALL( neighborhoodInit(scip, neighborhood) );
3775 	
3776 	      SCIP_CALL( resetFixingRate(scip, &neighborhood->fixingrate) );
3777 	
3778 	      SCIP_CALL( neighborhoodStatsReset(scip, &neighborhood->stats) );
3779 	   }
3780 	
3781 	   /* open reward file for reading */
3782 	   if( strncasecmp(heurdata->rewardfilename, DEFAULT_REWARDFILENAME, strlen(DEFAULT_REWARDFILENAME)) != 0 )
3783 	   {
3784 	      heurdata->rewardfile = fopen(heurdata->rewardfilename, "w");
3785 	
3786 	      if( heurdata->rewardfile == NULL )
3787 	      {
3788 	         SCIPerrorMessage("Error: Could not open reward file <%s>\n", heurdata->rewardfilename);
3789 	         return SCIP_FILECREATEERROR;
3790 	      }
3791 	
3792 	      SCIPdebugMsg(scip, "Writing reward information to <%s>\n", heurdata->rewardfilename);
3793 	   }
3794 	   else
3795 	      heurdata->rewardfile = NULL;
3796 	
3797 	   return SCIP_OKAY;
3798 	}
3799 	
3800 	
3801 	/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
3802 	static
3803 	SCIP_DECL_HEURINITSOL(heurInitsolAlns)
3804 	{  /*lint --e{715}*/
3805 	   SCIP_HEURDATA* heurdata;
3806 	   int i;
3807 	   SCIP_Real* priorities;
3808 	   unsigned int initseed;
3809 	
3810 	   assert(scip != NULL);
3811 	   assert(heur != NULL);
3812 	
3813 	   heurdata = SCIPheurGetData(heur);
3814 	   assert(heurdata != NULL);
3815 	   heurdata->nactiveneighborhoods = heurdata->nneighborhoods;
3816 	
3817 	   SCIP_CALL( SCIPallocBufferArray(scip, &priorities, heurdata->nactiveneighborhoods) );
3818 	
3819 	   /* init neighborhoods for new problem by resetting their statistics and fixing rate */
3820 	   for( i = heurdata->nneighborhoods - 1; i >= 0; --i )
3821 	   {
3822 	      NH* neighborhood = heurdata->neighborhoods[i];
3823 	      SCIP_Bool deactivate;
3824 	
3825 	      SCIP_CALL( neighborhood->nhdeactivate(scip, &deactivate) );
3826 	
3827 	      /* disable inactive neighborhoods */
3828 	      if( deactivate || ! neighborhood->active )
3829 	      {
3830 	         if( heurdata->nactiveneighborhoods - 1 > i )
3831 	         {
3832 	            assert(heurdata->neighborhoods[heurdata->nactiveneighborhoods - 1]->active);
3833 	            SCIPswapPointers((void **)&heurdata->neighborhoods[i], (void **)&heurdata->neighborhoods[heurdata->nactiveneighborhoods - 1]);
3834 	         }
3835 	         heurdata->nactiveneighborhoods--;
3836 	      }
3837 	   }
3838 	
3839 	   /* collect neighborhood priorities */
3840 	   for( i = 0; i < heurdata->nactiveneighborhoods; ++i )
3841 	      priorities[i] = heurdata->neighborhoods[i]->priority;
3842 	
3843 	   initseed = (unsigned int)(heurdata->seed + SCIPgetNVars(scip));
3844 	
3845 	   /* active neighborhoods might change between init calls, reset functionality must take this into account */
3846 	   if( heurdata->bandit != NULL && SCIPbanditGetNActions(heurdata->bandit) != heurdata->nactiveneighborhoods )
3847 	   {
3848 	      SCIP_CALL( SCIPfreeBandit(scip, &heurdata->bandit) );
3849 	
3850 	      heurdata->bandit = NULL;
3851 	   }
3852 	
3853 	   if( heurdata->nactiveneighborhoods > 0 )
3854 	   {  /* create or reset bandit algorithm */
3855 	      if( heurdata->bandit == NULL )
3856 	      {
3857 	         SCIP_CALL( createBandit(scip, heurdata, priorities, initseed) );
3858 	
3859 	         resetMinimumImprovement(heurdata);
3860 	         resetTargetNodeLimit(heurdata);
3861 	      }
3862 	      else if( heurdata->resetweights )
3863 	      {
3864 	         SCIP_CALL( SCIPresetBandit(scip, heurdata->bandit, priorities, initseed) );
3865 	
3866 	         resetMinimumImprovement(heurdata);
3867 	         resetTargetNodeLimit(heurdata);
3868 	      }
3869 	   }
3870 	
3871 	   heurdata->usednodes = 0;
3872 	   heurdata->ninitneighborhoods = heurdata->nactiveneighborhoods;
3873 	
3874 	   heurdata->lastcallsol = NULL;
3875 	   heurdata->firstcallthissol = 0;
3876 	
3877 	   resetCurrentNeighborhood(heurdata);
3878 	
3879 	   SCIPfreeBufferArray(scip, &priorities);
3880 	
3881 	   return SCIP_OKAY;
3882 	}
3883 	
3884 	
3885 	/** deinitialization method of primal heuristic (called before transformed problem is freed) */
3886 	static
3887 	SCIP_DECL_HEUREXIT(heurExitAlns)
3888 	{  /*lint --e{715}*/
3889 	   SCIP_HEURDATA* heurdata;
3890 	   int i;
3891 	
3892 	   assert(scip != NULL);
3893 	   assert(heur != NULL);
3894 	
3895 	   heurdata = SCIPheurGetData(heur);
3896 	   assert(heurdata != NULL);
3897 	
3898 	   /* free neighborhood specific data */
3899 	   for( i = 0; i < heurdata->nneighborhoods; ++i )
3900 	   {
3901 	      NH* neighborhood = heurdata->neighborhoods[i];
3902 	
3903 	      SCIP_CALL( neighborhoodExit(scip, neighborhood) );
3904 	   }
3905 	
3906 	   if( heurdata->rewardfile != NULL )
3907 	   {
3908 	      fclose(heurdata->rewardfile);
3909 	      heurdata->rewardfile = NULL;
3910 	   }
3911 	
3912 	   return SCIP_OKAY;
3913 	}
3914 	
3915 	/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
3916 	static
3917 	SCIP_DECL_HEURFREE(heurFreeAlns)
3918 	{  /*lint --e{715}*/
3919 	   SCIP_HEURDATA* heurdata;
3920 	   int i;
3921 	
3922 	   assert(scip != NULL);
3923 	   assert(heur != NULL);
3924 	
3925 	   heurdata = SCIPheurGetData(heur);
3926 	   assert(heurdata != NULL);
3927 	
3928 	   /* bandits are only initialized if a problem has been read */
3929 	   if( heurdata->bandit != NULL )
3930 	   {
3931 	      SCIP_CALL( SCIPfreeBandit(scip, &heurdata->bandit) );
3932 	   }
3933 	
3934 	   /* free neighborhoods */
3935 	   for( i = 0; i < heurdata->nneighborhoods; ++i )
3936 	   {
3937 	      SCIP_CALL( alnsFreeNeighborhood(scip, &(heurdata->neighborhoods[i])) );
3938 	   }
3939 	
3940 	   SCIPfreeBlockMemoryArray(scip, &heurdata->neighborhoods, NNEIGHBORHOODS);
3941 	
3942 	   SCIPfreeBlockMemory(scip, &heurdata);
3943 	
3944 	   return SCIP_OKAY;
3945 	}
3946 	
3947 	/** output method of statistics table to output file stream 'file' */
3948 	static
3949 	SCIP_DECL_TABLEOUTPUT(tableOutputNeighborhood)
3950 	{ /*lint --e{715}*/
3951 	   SCIP_HEURDATA* heurdata;
3952 	
3953 	   assert(SCIPfindHeur(scip, HEUR_NAME) != NULL);
3954 	   heurdata = SCIPheurGetData(SCIPfindHeur(scip, HEUR_NAME));
3955 	   assert(heurdata != NULL);
3956 	
3957 	   printNeighborhoodStatistics(scip, heurdata, file);
3958 	
3959 	   return SCIP_OKAY;
3960 	}
3961 	
3962 	/*
3963 	 * primal heuristic specific interface methods
3964 	 */
3965 	
3966 	/** creates the alns primal heuristic and includes it in SCIP */
3967 	SCIP_RETCODE SCIPincludeHeurAlns(
3968 	   SCIP*                 scip                /**< SCIP data structure */
3969 	   )
3970 	{
3971 	   SCIP_HEURDATA* heurdata;
3972 	   SCIP_HEUR* heur;
3973 	
3974 	   /* create alns primal heuristic data */
3975 	   heurdata = NULL;
3976 	   heur = NULL;
3977 	
3978 	   SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
3979 	   BMSclearMemory(heurdata);
3980 	
3981 	   /* TODO make this a user parameter? */
3982 	   heurdata->lplimfac = LPLIMFAC;
3983 	
3984 	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &heurdata->neighborhoods, NNEIGHBORHOODS) );
3985 	
3986 	   /* include primal heuristic */
3987 	   SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
3988 	         HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS,
3989 	         HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecAlns, heurdata) );
3990 	
3991 	   assert(heur != NULL);
3992 	
3993 	   /* include all neighborhoods */
3994 	   SCIP_CALL( includeNeighborhoods(scip, heurdata) );
3995 	
3996 	   /* set non fundamental callbacks via setter functions */
3997 	   SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyAlns) );
3998 	   SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeAlns) );
3999 	   SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitAlns) );
4000 	   SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolAlns) );
4001 	   SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitAlns) );
4002 	
4003 	   /* add alns primal heuristic parameters */
4004 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/maxnodes",
4005 	         "maximum number of nodes to regard in the subproblem",
4006 	         &heurdata->maxnodes,  TRUE,DEFAULT_MAXNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4007 	
4008 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/nodesofs",
4009 	         "offset added to the nodes budget",
4010 	         &heurdata->nodesoffset, FALSE, DEFAULT_NODESOFFSET, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4011 	
4012 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/minnodes",
4013 	         "minimum number of nodes required to start a sub-SCIP",
4014 	         &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4015 	
4016 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/waitingnodes",
4017 	         "number of nodes since last incumbent solution that the heuristic should wait",
4018 	         &heurdata->waitingnodes, TRUE, DEFAULT_WAITINGNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4019 	
4020 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquot",
4021 	         "fraction of nodes compared to the main SCIP for budget computation",
4022 	         &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) );
4023 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquotmin",
4024 	         "lower bound fraction of nodes compared to the main SCIP for budget computation",
4025 	         &heurdata->nodesquotmin, FALSE, DEFAULT_NODESQUOTMIN, 0.0, 1.0, NULL, NULL) );
4026 	
4027 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/startminimprove",
4028 	         "initial factor by which ALNS should at least improve the incumbent",
4029 	         &heurdata->startminimprove, TRUE, DEFAULT_STARTMINIMPROVE, 0.0, 1.0, NULL, NULL) );
4030 	
4031 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minimprovelow",
4032 	         "lower threshold for the minimal improvement over the incumbent",
4033 	         &heurdata->minimprovelow, TRUE, DEFAULT_MINIMPROVELOW, 0.0, 1.0, NULL, NULL) );
4034 	
4035 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minimprovehigh",
4036 	         "upper bound for the minimal improvement over the incumbent",
4037 	         &heurdata->minimprovehigh, TRUE, DEFAULT_MINIMPROVEHIGH, 0.0, 1.0, NULL, NULL) );
4038 	
4039 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nsolslim",
4040 	         "limit on the number of improving solutions in a sub-SCIP call",
4041 	         &heurdata->nsolslim, FALSE, DEFAULT_NSOLSLIM, -1, INT_MAX, NULL, NULL) );
4042 	
4043 	   SCIP_CALL( SCIPaddCharParam(scip, "heuristics/" HEUR_NAME "/banditalgo",
4044 	         "the bandit algorithm: (u)pper confidence bounds, (e)xp.3, epsilon (g)reedy",
4045 	         &heurdata->banditalgo, TRUE, DEFAULT_BANDITALGO, "ueg", NULL, NULL) );
4046 	
4047 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/gamma",
4048 	         "weight between uniform (gamma ~ 1) and weight driven (gamma ~ 0) probability distribution for exp3",
4049 	         &heurdata->exp3_gamma, TRUE, DEFAULT_GAMMA, 0.0, 1.0, NULL, NULL) );
4050 	
4051 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/beta",
4052 	         "reward offset between 0 and 1 at every observation for Exp.3",
4053 	         &heurdata->exp3_beta, TRUE, DEFAULT_BETA, 0.0, 1.0, NULL, NULL) );
4054 	
4055 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/alpha",
4056 	         "parameter to increase the confidence width in UCB",
4057 	         &heurdata->ucb_alpha, TRUE, DEFAULT_ALPHA, 0.0, 100.0, NULL, NULL) );
4058 	
4059 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usedistances",
4060 	         "distances from fixed variables be used for variable prioritization",
4061 	         &heurdata->usedistances, TRUE, DEFAULT_USEDISTANCES, NULL, NULL) );
4062 	
4063 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/useredcost",
4064 	         "should reduced cost scores be used for variable prioritization?",
4065 	         &heurdata->useredcost, TRUE, DEFAULT_USEREDCOST, NULL, NULL) );
4066 	
4067 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/domorefixings",
4068 	         "should the ALNS heuristic do more fixings by itself based on variable prioritization "
4069 	         "until the target fixing rate is reached?",
4070 	         &heurdata->domorefixings, TRUE, DEFAULT_DOMOREFIXINGS, NULL, NULL) );
4071 	
4072 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/adjustfixingrate",
4073 	         "should the heuristic adjust the target fixing rate based on the success?",
4074 	         &heurdata->adjustfixingrate, TRUE, DEFAULT_ADJUSTFIXINGRATE, NULL, NULL) );
4075 	
4076 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usesubscipheurs",
4077 	         "should the heuristic activate other sub-SCIP heuristics during its search?",
4078 	         &heurdata->usesubscipheurs, TRUE, DEFAULT_USESUBSCIPHEURS, NULL, NULL) );
4079 	
4080 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/rewardcontrol",
4081 	         "reward control to increase the weight of the simple solution indicator and decrease the weight of the closed gap reward",
4082 	         &heurdata->rewardcontrol, TRUE, DEFAULT_REWARDCONTROL, 0.0, 1.0, NULL, NULL) );
4083 	
4084 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/targetnodefactor",
4085 	         "factor by which target node number is eventually increased",
4086 	         &heurdata->targetnodefactor, TRUE, DEFAULT_TARGETNODEFACTOR, 1.0, 1e+5, NULL, NULL) );
4087 	
4088 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/seed",
4089 	         "initial random seed for bandit algorithms and random decisions by neighborhoods",
4090 	         &heurdata->seed, FALSE, DEFAULT_SEED, 0, INT_MAX, NULL, NULL) );
4091 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxcallssamesol",
4092 	         "number of allowed executions of the heuristic on the same incumbent solution (-1: no limit, 0: number of active neighborhoods)",
4093 	         &heurdata->maxcallssamesol, TRUE, DEFAULT_MAXCALLSSAMESOL, -1, 100, NULL, NULL) );
4094 	
4095 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/adjustminimprove",
4096 	         "should the factor by which the minimum improvement is bound be dynamically updated?",
4097 	         &heurdata->adjustminimprove, TRUE, DEFAULT_ADJUSTMINIMPROVE, NULL, NULL) );
4098 	
4099 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/adjusttargetnodes",
4100 	         "should the target nodes be dynamically adjusted?",
4101 	         &heurdata->adjusttargetnodes, TRUE, DEFAULT_ADJUSTTARGETNODES, NULL, NULL) );
4102 	
4103 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/eps",
4104 	         "increase exploration in epsilon-greedy bandit algorithm",
4105 	         &heurdata->epsgreedy_eps, TRUE, DEFAULT_EPS, 0.0, 1.0, NULL, NULL) );
4106 	
4107 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/rewardbaseline",
4108 	         "the reward baseline to separate successful and failed calls",
4109 	         &heurdata->rewardbaseline, TRUE, DEFAULT_REWARDBASELINE, 0.0, 0.99, NULL, NULL) );
4110 	
4111 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/resetweights",
4112 	         "should the bandit algorithms be reset when a new problem is read?",
4113 	         &heurdata->resetweights, TRUE, DEFAULT_RESETWEIGHTS, NULL, NULL) );
4114 	
4115 	   SCIP_CALL( SCIPaddStringParam(scip, "heuristics/" HEUR_NAME "/rewardfilename", "file name to store all rewards and the selection of the bandit",
4116 	         &heurdata->rewardfilename, TRUE, DEFAULT_REWARDFILENAME, NULL, NULL) );
4117 	
4118 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/subsciprandseeds",
4119 	         "should random seeds of sub-SCIPs be altered to increase diversification?",
4120 	         &heurdata->subsciprandseeds, TRUE, DEFAULT_SUBSCIPRANDSEEDS, NULL, NULL) );
4121 	
4122 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/scalebyeffort",
4123 	         "should the reward be scaled by the effort?",
4124 	         &heurdata->scalebyeffort, TRUE, DEFAULT_SCALEBYEFFORT, NULL, NULL) );
4125 	
4126 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/copycuts",
4127 	         "should cutting planes be copied to the sub-SCIP?",
4128 	         &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
4129 	
4130 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/fixtol",
4131 	         "tolerance by which the fixing rate may be missed without generic fixing",
4132 	         &heurdata->fixtol, TRUE, DEFAULT_FIXTOL, 0.0, 1.0, NULL, NULL) );
4133 	
4134 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/unfixtol",
4135 	         "tolerance by which the fixing rate may be exceeded without generic unfixing",
4136 	         &heurdata->unfixtol, TRUE, DEFAULT_UNFIXTOL, 0.0, 1.0, NULL, NULL) );
4137 	
4138 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/uselocalredcost",
4139 	         "should local reduced costs be used for generic (un)fixing?",
4140 	         &heurdata->uselocalredcost, TRUE, DEFAULT_USELOCALREDCOST, NULL, NULL) );
4141 	
4142 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usepscost",
4143 	         "should pseudo cost scores be used for variable priorization?",
4144 	         &heurdata->usepscost, TRUE, DEFAULT_USEPSCOST, NULL, NULL) );
4145 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/initduringroot",
4146 	         "should the heuristic be executed multiple times during the root node?",
4147 	         &heurdata->initduringroot, TRUE, DEFAULT_INITDURINGROOT, NULL, NULL) );
4148 	
4149 	   assert(SCIPfindTable(scip, TABLE_NAME_NEIGHBORHOOD) == NULL);
4150 	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NEIGHBORHOOD, TABLE_DESC_NEIGHBORHOOD, TRUE,
4151 	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNeighborhood,
4152 	         NULL, TABLE_POSITION_NEIGHBORHOOD, TABLE_EARLIEST_STAGE_NEIGHBORHOOD) );
4153 	
4154 	   return SCIP_OKAY;
4155 	}
4156