Scippy

SCIP

Solving Constraint Integer Programs

heur_scheduler.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file heur_scheduler.c
26 * @ingroup DEFPLUGINS_HEUR
27 * @brief Adaptive heuristic to schedule LNS and diving heuristics
28 * @author Gregor Hendel
29 * @author Antonia Chmiela
30 */
31
32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33
35#include "scip/cons_linear.h"
36#include "scip/heur_scheduler.h"
37#include "scip/heuristics.h"
41#include "scip/pub_bandit.h"
42#include "scip/pub_bandit_ucb.h"
43#include "scip/pub_cons.h"
44#include "scip/pub_event.h"
45#include "scip/pub_heur.h"
46#include "scip/pub_message.h"
47#include "scip/pub_misc.h"
49#include "scip/pub_sol.h"
50#include "scip/pub_var.h"
51#include "scip/scip_bandit.h"
52#include "scip/scip_branch.h"
53#include "scip/scip_cons.h"
54#include "scip/scip_copy.h"
55#include "scip/scip_event.h"
56#include "scip/scip_general.h"
57#include "scip/scip_heur.h"
58#include "scip/scip_lp.h"
59#include "scip/scip_mem.h"
60#include "scip/scip_message.h"
61#include "scip/scip_nodesel.h"
62#include "scip/scip_numerics.h"
63#include "scip/scip_param.h"
64#include "scip/scip_prob.h"
66#include "scip/scip_sol.h"
67#include "scip/scip_solve.h"
69#include "scip/scip_table.h"
70#include "scip/scip_timing.h"
71#include "scip/scip_tree.h"
72#include "scip/scip_var.h"
73#include <string.h>
74
75
76#define HEUR_NAME "scheduler"
77#define HEUR_DESC "Adaptive heuristic to schedule LNS and diving heuristics"
78#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_LNS
79#define HEUR_PRIORITY -30000
80#define HEUR_FREQ -1
81#define HEUR_FREQOFS 0
82#define HEUR_MAXDEPTH -1
83#define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
84#define HEUR_USESSUBSCIP TRUE /**< does the heuristic use a secondary SCIP instance? */
85
86#define NNEIGHBORHOODS 9
87#define DIVINGHEURS_INITIALSIZE 10
88
89/*
90 * limit parameters for sub-SCIPs
91 */
92#define DEFAULT_NODESQUOT 0.1
93#define DEFAULT_NODESQUOTMIN 0.0
94#define DEFAULT_NODESOFFSET 500LL
95#define DEFAULT_NSOLSLIM 3
96#define DEFAULT_MINNODES 50LL
97#define DEFAULT_MAXNODES 500LL
98#define DEFAULT_WAITINGNODES 0LL /**< number of nodes since last incumbent solution that the heuristic should wait */
99#define DEFAULT_INITLNSNODELIMIT 50
100#define DEFAULT_INITDIVINGNODELIMIT 500LL
101#define DEFAULT_TARGETNODEFACTOR 1.05
102#define LRATEMIN 0.01 /**< lower bound for learning rate for target nodes and minimum improvement */
103#define LPLIMFAC 4.0
104#define DEFAULT_INITDURINGROOT FALSE
105#define DEFAULT_MAXCALLSSAMESOL -1 /**< number of allowed executions of the heuristic on the same incumbent solution */
106
107/*
108 * bandit algorithm parameters
109 */
110#define DEFAULT_BESTSOLWEIGHT 1
111#define DEFAULT_BANDITALGO 'i' /**< the default bandit algorithm: (u)pper confidence bounds, (e)xp.3, epsilon (g)reedy, exp.3-(i)x */
112#define DEFAULT_RESETWEIGHTS FALSE/**< should the bandit algorithms be reset when a new problem is read? */
113#define DEFAULT_SUBSCIPRANDSEEDS FALSE /**< should random seeds of sub-SCIPs be altered to increase diversification? */
114#define DEFAULT_FIXTOL 0.1 /**< tolerance by which the fixing rate may be missed without generic fixing */
115#define DEFAULT_UNFIXTOL 0.1 /**< tolerance by which the fixing rate may be exceeded without generic unfixing */
116#define DEFAULT_BETA 0.0 /**< default reward offset between 0 and 1 at every observation for exp3 */
117#define DEFAULT_NSELECTIONS 5 /**< number of heuristics picked by the scheduler in one call (-1: number of controlled heuristics, 0: until new incumbent is found) */
118
119/*
120 * parameters to control variable fixing
121 */
122#define DEFAULT_USEREDCOST TRUE /**< should reduced cost scores be used for variable priorization? */
123#define DEFAULT_USEPSCOST TRUE /**< should pseudo cost scores be used for variable priorization? */
124#define DEFAULT_USEDISTANCES TRUE /**< should distances from fixed variables be used for variable priorization */
125#define DEFAULT_USELOCALREDCOST FALSE /**< should local reduced costs be used for generic (un)fixing? */
126
127/*
128 * parameters for reward computation
129 */
130#define DEFAULT_EFFORTREWARDWEIGHT 0.2
131#define DEFAULT_SOLREWARDWEIGHT 0.3
132#define DEFAULT_QUALREWARDWEIGHT 0.3
133#define DEFAULT_CONFLICTREWARDWEIGHT 0.2
134
135/*
136 * the following 3 parameters have been tuned by a simulation experiment
137 * as described in the paper.
138 */
139#define DEFAULT_EPS 0.4685844 /**< increase exploration in epsilon-greedy bandit algorithm */
140#define DEFAULT_ALPHA 0.0016 /**< parameter to increase the confidence width in UCB */
141#define DEFAULT_GAMMA 0.07041455 /**< default weight between uniform (gamma ~ 1) and weight driven (gamma ~ 0) probability distribution for exp3 */
142
143/*
144 * parameters to control solve frequency for diving heuristics
145 */
146#define SOLVEFREQ_DECAY 0.75 /**< geometric decay for solving freq adjustments */
147#define SOLVEFREQ_STARTINC 0.2 /**< initial increment value for solving frequency */
148#define MAXSOLVEFREQ 0.3 /**< maximal solving frequency */
149#define MINSOLVEFREQ 0.05 /**< minimal solving frequency */
150
151/*
152 * parameters to control variable fixing
153 */
154#define FIXINGRATE_DECAY 0.75 /**< geometric decay for fixing rate adjustments */
155#define FIXINGRATE_STARTINC 0.2 /**< initial increment value for fixing rate */
156#define DEFAULT_USESUBSCIPHEURS FALSE /**< should the heuristic activate other sub-SCIP heuristics during its search? */
157#define DEFAULT_COPYCUTS FALSE /**< should cutting planes be copied to the sub-SCIP? */
158
159/* individual random seeds */
160#define DEFAULT_SEED 113
161#define MUTATIONSEED 121
162#define CROSSOVERSEED 321
163
164/* individual neighborhood parameters */
165#define DEFAULT_MINFIXINGRATE_RENS 0.3
166#define DEFAULT_MAXFIXINGRATE_RENS 0.9
167#define DEFAULT_ACTIVE_RENS TRUE
168//#define DEFAULT_PRIORITY_RENS 1.0
169#define DEFAULT_PRIORITY_RENS -1100000
170
171#define DEFAULT_MINFIXINGRATE_RINS 0.3
172#define DEFAULT_MAXFIXINGRATE_RINS 0.9
173#define DEFAULT_ACTIVE_RINS TRUE
174//#define DEFAULT_PRIORITY_RINS 1.0
175#define DEFAULT_PRIORITY_RINS -1101000
176
177#define DEFAULT_MINFIXINGRATE_MUTATION 0.3
178#define DEFAULT_MAXFIXINGRATE_MUTATION 0.9
179#define DEFAULT_ACTIVE_MUTATION TRUE
180//#define DEFAULT_PRIORITY_MUTATION 1.0
181#define DEFAULT_PRIORITY_MUTATION -1103010
182
183#define DEFAULT_MINFIXINGRATE_LOCALBRANCHING 0.3
184#define DEFAULT_MAXFIXINGRATE_LOCALBRANCHING 0.9
185#define DEFAULT_ACTIVE_LOCALBRANCHING TRUE
186//#define DEFAULT_PRIORITY_LOCALBRANCHING 1.0
187#define DEFAULT_PRIORITY_LOCALBRANCHING -1102000
188
189#define DEFAULT_MINFIXINGRATE_PROXIMITY 0.3
190#define DEFAULT_MAXFIXINGRATE_PROXIMITY 0.9
191#define DEFAULT_ACTIVE_PROXIMITY TRUE
192//#define DEFAULT_PRIORITY_PROXIMITY 1.0
193#define DEFAULT_PRIORITY_PROXIMITY -2000000
194
195#define DEFAULT_MINFIXINGRATE_CROSSOVER 0.3
196#define DEFAULT_MAXFIXINGRATE_CROSSOVER 0.9
197#define DEFAULT_ACTIVE_CROSSOVER TRUE
198//#define DEFAULT_PRIORITY_CROSSOVER 1.0
199#define DEFAULT_PRIORITY_CROSSOVER -1104000
200
201#define DEFAULT_MINFIXINGRATE_ZEROOBJECTIVE 0.3
202#define DEFAULT_MAXFIXINGRATE_ZEROOBJECTIVE 0.9
203#define DEFAULT_ACTIVE_ZEROOBJECTIVE TRUE
204//#define DEFAULT_PRIORITY_ZEROOBJECTIVE 1.0
205#define DEFAULT_PRIORITY_ZEROOBJECTIVE 100
206
207#define DEFAULT_MINFIXINGRATE_DINS 0.3
208#define DEFAULT_MAXFIXINGRATE_DINS 0.9
209#define DEFAULT_ACTIVE_DINS TRUE
210//#define DEFAULT_PRIORITY_DINS 1.0
211#define DEFAULT_PRIORITY_DINS -1105000
212
213#define DEFAULT_MINFIXINGRATE_TRUSTREGION 0.3
214#define DEFAULT_MAXFIXINGRATE_TRUSTREGION 0.9
215#define DEFAULT_ACTIVE_TRUSTREGION FALSE
216//#define DEFAULT_PRIORITY_TRUSTREGION 1.0
217#define DEFAULT_PRIORITY_TRUSTREGION -1102010
218
219
220#define DEFAULT_NSOLS_CROSSOVER 2 /**< parameter for the number of solutions that crossover should combine */
221#define DEFAULT_NPOOLSOLS_DINS 5 /**< number of pool solutions where binary solution values must agree */
222#define DEFAULT_VIOLPENALTY_TRUSTREGION 100.0 /**< the penalty for violating the trust region */
223
224/* event handler properties */
225#define EVENTHDLR_NAME "Scheduler"
226#define EVENTHDLR_DESC "LP event handler for " HEUR_NAME " heuristic"
227#define SCIP_EVENTTYPE_SCHEDULER (SCIP_EVENTTYPE_LPSOLVED | SCIP_EVENTTYPE_SOLFOUND | SCIP_EVENTTYPE_BESTSOLFOUND)
228
229/* properties of the scheduler neighborhood statistics table */
230#define TABLE_NAME_NEIGHBORHOOD "scheduler"
231#define TABLE_DESC_NEIGHBORHOOD "scheduler heuristics statistics"
232#define TABLE_POSITION_NEIGHBORHOOD 12500 /**< the position of the statistics table */
233#define TABLE_EARLIEST_STAGE_NEIGHBORHOOD SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
234
235/*
236 * additional neighborhood data structures
237 */
238
239
240typedef struct data_crossover DATA_CROSSOVER; /**< crossover neighborhood data structure */
241
242typedef struct data_mutation DATA_MUTATION; /**< mutation neighborhood data structure */
243
244typedef struct data_dins DATA_DINS; /**< dins neighborhood data structure */
245
246typedef struct data_trustregion DATA_TRUSTREGION; /**< trustregion neighborhood data structure */
247
248typedef struct NH_FixingRate NH_FIXINGRATE; /** fixing rate data structure */
249
250typedef struct SolveFreq SOLVEFREQ; /** diving heuristic solving frequency data structure */
251
252typedef struct Heur_Stats HEUR_STATS; /**< heuristic statistics data structure */
253
254typedef struct Nh NH; /**< neighborhood data structure */
255
256typedef struct Diving_Heur DIVING_HEUR; /**< diving heuristic data structure */
257
258/*
259 * variable priorization data structure for sorting
260 */
261typedef struct VarPrio VARPRIO;
262
263/** callback to collect variable fixings of neighborhood */
264 #define DECL_VARFIXINGS(x) SCIP_RETCODE x ( \
265 SCIP* scip, /**< SCIP data structure */ \
266 NH* neighborhood, /**< neighborhood data structure */ \
267 SCIP_VAR** varbuf, /**< buffer array to collect variables to fix */\
268 SCIP_Real* valbuf, /**< buffer array to collect fixing values */ \
269 int* nfixings, /**< pointer to store the number of fixings */ \
270 SCIP_RESULT* result /**< result pointer */ \
271 )
272
273/** callback for subproblem changes other than variable fixings
274 *
275 * this callback can be used to further modify the subproblem by changes other than variable fixings.
276 * Typical modifications include restrictions of variable domains, the formulation of additional constraints,
277 * or changed objective coefficients.
278 *
279 * The callback should set the \p success pointer to indicate whether it was successful with its modifications or not.
280 */
281#define DECL_CHANGESUBSCIP(x) SCIP_RETCODE x ( \
282 SCIP* sourcescip, /**< source SCIP data structure */\
283 SCIP* targetscip, /**< target SCIP data structure */\
284 NH* neighborhood, /**< neighborhood data structure */\
285 SCIP_VAR** subvars, /**< array of targetscip variables in the same order as the source SCIP variables */\
286 int* ndomchgs, /**< pointer to store the number of performed domain changes */\
287 int* nchgobjs, /**< pointer to store the number of changed objective coefficients */ \
288 int* naddedconss, /**< pointer to store the number of additional constraints */\
289 SCIP_Bool* success /**< pointer to store if the sub-MIP was successfully adjusted */\
290 )
291
292/** optional initialization callback for neighborhoods when a new problem is read */
293#define DECL_NHINIT(x) SCIP_RETCODE x ( \
294 SCIP* scip, /**< SCIP data structure */ \
295 NH* neighborhood /**< neighborhood data structure */ \
296 )
297
298/** deinitialization callback for neighborhoods when exiting a problem */
299#define DECL_NHEXIT(x) SCIP_RETCODE x ( \
300 SCIP* scip, /**< SCIP data structure */ \
301 NH* neighborhood /**< neighborhood data structure */ \
302 )
303
304/** deinitialization callback for neighborhoods before SCIP is freed */
305#define DECL_NHFREE(x) SCIP_RETCODE x ( \
306 SCIP* scip, /**< SCIP data structure */ \
307 NH* neighborhood /**< neighborhood data structure */ \
308 )
309
310/** callback function to return a feasible reference solution for further fixings
311 *
312 * The reference solution should be stored in the \p solptr.
313 * The \p result pointer can be used to indicate either
314 *
315 * - SCIP_SUCCESS or
316 * - SCIP_DIDNOTFIND
317 */
318#define DECL_NHREFSOL(x) SCIP_RETCODE x ( \
319 SCIP* scip, /**< SCIP data structure */ \
320 NH* neighborhood, /**< neighborhood data structure */ \
321 SCIP_SOL** solptr, /**< pointer to store the reference solution */ \
322 SCIP_RESULT* result /**< pointer to indicate the callback success whether a reference solution is available */ \
323 )
324
325/** callback function to deactivate neighborhoods on problems where they are irrelevant */
326#define DECL_NHDEACTIVATE(x) SCIP_RETCODE x (\
327 SCIP* scip, /**< SCIP data structure */ \
328 SCIP_Bool* deactivate /**< pointer to store whether the neighborhood should be deactivated (TRUE) for an instance */ \
329 )
330
331/** sub-SCIP status code enumerator */
333{
334 HIDX_OPT = 0, /**< sub-SCIP was solved to optimality */
335 HIDX_USR = 1, /**< sub-SCIP was user interrupted */
336 HIDX_NODELIM = 2, /**< sub-SCIP reached the node limit */
337 HIDX_STALLNODE = 3, /**< sub-SCIP reached the stall node limit */
338 HIDX_INFEAS = 4, /**< sub-SCIP was infeasible */
339 HIDX_SOLLIM = 5, /**< sub-SCIP reached the solution limit */
340 HIDX_OTHER = 6 /**< sub-SCIP reached none of the above codes */
342typedef enum HistIndex HISTINDEX;
343#define NHISTENTRIES 7
344
345
346/** statistics for heuristics */
348{
349 SCIP_Real oldupperbound; /**< upper bound before the heuristic started */
350 SCIP_Real newupperbound; /**< new upper bound for allrewards mode to work correctly */
351 int nruns; /**< number of runs of a heuristic */
352 int nrunsbestsol; /**< number of runs that produced a new incumbent */
353 SCIP_Longint nsolsfound; /**< the total number of solutions found */
354 SCIP_Longint nbestsolsfound; /**< the total number of improving solutions found */
355 SCIP_CLOCK* setupclock; /**< clock for setup time */
356 SCIP_CLOCK* execclock; /**< clock for the heuristic execution */
357 /* for diving */
358 SCIP_Longint nbacktracks; /**< total number of used backtracks */
359 SCIP_Longint nconflicts; /**< total number of conflict constraints generated */
360 SCIP_Longint nprobnodes; /**< total number of probing nodes used */
361 int divingdepth; /**< depth of last dive */
362 /* for LNS */
363 SCIP_Longint usednodes; /**< total number of used nodes */
364 int nfixings; /**< the number of fixings in one run */
365 int statushist[NHISTENTRIES]; /**< array to count sub-SCIP statuses */
366};
367
368
369/** fixing rate data structure to control the amount of target fixings of a neighborhood */
370struct NH_FixingRate
371{
372 SCIP_Real minfixingrate; /**< the minimum fixing rate */
373 SCIP_Real targetfixingrate; /**< the current target fixing rate */
374 SCIP_Real increment; /**< the current increment by which the target fixing rate is in-/decreased */
375 SCIP_Real maxfixingrate; /**< the maximum fixing rate */
376};
377
378/** solve frequency for diving heuristics */
380{
381 SCIP_Real minsolvefreq; /**< the minimum solve frequency */
382 SCIP_Real currentsolvefreq; /**< the current solve frequency */
383 SCIP_Real increment; /**< the current increment by which the solve frequency is in-/decreased */
384 SCIP_Real maxsolvefreq; /**< the maximum solve frequency */
385};
386
387/** neighborhood data structure with callbacks, statistics, fixing rate */
388struct Nh
389{
390 char* name; /**< the name of this neighborhood */
391 NH_FIXINGRATE fixingrate; /**< fixing rate for this neighborhood */
392 HEUR_STATS stats; /**< statistics for this neighborhood */
393 int nodelimit; /**< nodelimit for next execution */
394 DECL_VARFIXINGS ((*varfixings)); /**< variable fixings callback for this neighborhood */
395 DECL_CHANGESUBSCIP ((*changesubscip)); /**< callback for subproblem changes other than variable fixings */
396 DECL_NHINIT ((*nhinit)); /**< initialization callback when a new problem is read */
397 DECL_NHEXIT ((*nhexit)); /**< deinitialization callback when exiting a problem */
398 DECL_NHFREE ((*nhfree)); /**< deinitialization callback before SCIP is freed */
399 DECL_NHREFSOL ((*nhrefsol)); /**< callback function to return a reference solution for further fixings, or NULL */
400 DECL_NHDEACTIVATE ((*nhdeactivate)); /**< callback function to deactivate neighborhoods on problems where they are irrelevant, or NULL if it is always active */
401 SCIP_Bool active; /**< is this neighborhood active or not? */
402 SCIP_Real priority; /**< positive call priority to initialize bandit algorithms */
403 int rootnodepriority; /**< heuristic's priority for call at rootnode */
404 union
405 {
406 DATA_MUTATION* mutation; /**< mutation data */
407 DATA_CROSSOVER* crossover; /**< crossover data */
408 DATA_DINS* dins; /**< dins data */
409 DATA_TRUSTREGION* trustregion; /**< trustregion data */
410 } data; /**< data object for neighborhood specific data */
411};
412
413/** diving heuristic data structure with statistics and diveset */
415{
416 SCIP_DIVESET* diveset; /**< publicly available divesets from diving heuristics */
417 HEUR_STATS* stats; /**< statistics for this diveset */
418 SCIP_Longint nodelimit; /**< node limit of diving heuristics for next execution */
419 SOLVEFREQ* solvefreqdata; /**< solve frequency data */
420 SCIP_Real priority; /**< positive call priority to initialize bandit algorithms */
421 int rootnodepriority; /**< heuristic's priority for call at rootnode */
422};
423
424/** mutation neighborhood data structure */
425struct data_mutation
426{
427 SCIP_RANDNUMGEN* rng; /**< random number generator */
428};
429
430/** crossover neighborhood data structure */
431struct data_crossover
432{
433 int nsols; /**< the number of solutions that crossover should combine */
434 SCIP_RANDNUMGEN* rng; /**< random number generator to draw from the solution pool */
435 SCIP_SOL* selsol; /**< best selected solution by crossover as reference point */
436};
437
438/** dins neighborhood data structure */
439struct data_dins
440{
441 int npoolsols; /**< number of pool solutions where binary solution values must agree */
442};
443
444struct data_trustregion
445{
446 SCIP_Real violpenalty; /**< the penalty for violating the trust region */
447};
448
449/** primal heuristic data */
450struct SCIP_HeurData
451{
452 SCIP_BANDIT* bandit; /**< bandit algorithm */
453 int* sortedindices; /**< array of indices of heuristics sorted w.r.t. heuristic priorities */
454 int counter; /**< counter to count how often the scheduler selected a heuristic in the rootnode */
455 SCIP_SOL* lastcallsol; /**< incumbent when the heuristic was last called */
456 SCIP_Longint waitingnodes; /**< number of nodes since last incumbent solution that the heuristic should wait */
457 SCIP_Longint firstcallthissol; /**< counter for the number of calls on this incumbent */
458 char banditalgo; /**< the bandit algorithm: (u)pper confidence bounds, (e)xp.3, epsilon (g)reedy */
459 int maxcallssamesol; /**< number of allowed executions of the heuristic on the same incumbent solution
460 * (-1: no limit, 0: number of active neighborhoods) */
461 int nselections; /**< number of heuristics picked by the scheduler in one call
462 * (-1: number of controlled heuristics, 0: until new incumbent is found) */
463 int nskippedcalls; /**< number of calls to heuristic we need to skip since last execution */
464 int nfailedcalls; /**< number of failed calls to heursitic since last successful one */
465 SCIP_Bool resetweights; /**< should the bandit algorithms be reset when a new problem is read? */
466 SCIP_Bool initduringroot; /**< should the heuristic be executed multiple times during the root node? */
467 int maxnconflicts; /**< maximum number of conflicts detected by diving heur so far */
468 SCIP_Bool defaultroot; /**< should the default priorities be used at the root node */
469 /* bandit algorithm parameters */
470 SCIP_Real exp3_gamma; /**< weight between uniform (gamma ~ 1) and weight driven (gamma ~ 0) probability distribution for exp3 */
471 SCIP_Real exp3_beta; /**< reward offset between 0 and 1 at every observation for exp3 */
472 SCIP_Real epsgreedy_eps; /**< increase exploration in epsilon-greedy bandit algorithm */
473 SCIP_Bool epsgreedy_usemod; /**< TRUE if modified version of the epsilon-greedy bandit algorithm should be used */
474 SCIP_Real ucb_alpha; /**< parameter to increase the confidence width in UCB */
475 /* reward function parameters (reward is a function between 0 and 1 and thus always upper bounded by 1, even if
476 * sum of weights do not add up to 1.0) */
477 SCIP_Real solrewardweight; /**< weight by how much finding a new incumbent is rewarded in reward function */
478 SCIP_Real effortrewardweight; /**< weight by how much effort is rewarded in reward function */
479 SCIP_Real qualrewardweight; /**< weight by how much quality of a new incumbent is rewarded in reward function */
480 SCIP_Real conflictrewardweight;/**< weight by how much number of conflicts found by diving is rewarded in reward function */
481 /* diving data */
482 SCIP_SOL* sol; /**< working solution */
483 DIVING_HEUR** divingheurs; /**< array of diving heuristics */
484 int divingheurssize; /**< array size for diving heurs array */
485 int ndiving; /**< number of diving heuristics used by scheduler */
486 SCIP_Longint initdivingnodelimit;/**< initial node limit for diving heuristics */
487 SCIP_Longint maxdivingnodelimit; /**< maximum of node limits among all diving heurisitics */
488 /* LNS data */
489 NH** neighborhoods; /**< array of neighborhoods */
490 SCIP_Longint nodesoffset; /**< offset added to the nodes budget */
491 SCIP_Longint maxnodes; /**< maximum number of nodes in a single sub-SCIP */
492 SCIP_Longint targetnodes; /**< targeted number of nodes to start a sub-SCIP */
493 SCIP_Longint minnodes; /**< minimum number of nodes required to start a sub-SCIP */
494 SCIP_Longint usednodes; /**< total number of nodes already spent in sub-SCIPs */
495 SCIP_Real nodesquot; /**< fraction of nodes compared to the main SCIP for budget computation */
496 SCIP_Real nodesquotmin; /**< lower bound on fraction of nodes compared to the main SCIP for budget computation */
497 SCIP_Real lplimfac; /**< limit fraction of LPs per node to interrupt sub-SCIP */
498 SCIP_Real targetnodefactor; /**< factor by which target node number is eventually increased */
499 SCIP_Real fixtol; /**< tolerance by which the fixing rate may be missed without generic fixing */
500 SCIP_Real unfixtol; /**< tolerance by which the fixing rate may be exceeded without generic unfixing */
501 int nneighborhoods; /**< number of neighborhoods */
502 int nactiveneighborhoods;/**< number of active neighborhoods */
503 int ninitneighborhoods; /**< neighborhoods that were used at least one time */
504 int nsolslim; /**< limit on the number of improving solutions in a sub-SCIP call */
505 int seed; /**< initial random seed for bandit algorithms and random decisions by neighborhoods */
506 int currneighborhood; /**< index of currently selected neighborhood */
507 int ndelayedcalls; /**< the number of delayed calls */
508 SCIP_Bool usesubscipheurs; /**< should the heuristic activate other sub-SCIP heuristics during its search? */
509 SCIP_Bool subsciprandseeds; /**< should random seeds of sub-SCIPs be altered to increase diversification? */
510 SCIP_Bool copycuts; /**< should cutting planes be copied to the sub-SCIP? */
511 int initlnsnodelimit; /**< initial node limit for LNS heuristics */
512 int maxlnsnodelimit; /**< maximum of nodelimits among all LNS heuristics */
513 SCIP_Bool useredcost; /**< should reduced cost scores be used for variable prioritization? */
514 SCIP_Bool usedistances; /**< should distances from fixed variables be used for variable prioritization */
515 SCIP_Bool usepscost; /**< should pseudo cost scores be used for variable prioritization? */
516 SCIP_Bool uselocalredcost; /**< should local reduced costs be used for generic (un)fixing? */
517};
518
519/** event handler data */
520struct SCIP_EventData
521{
522 SCIP_VAR** subvars; /**< the variables of the subproblem */
523 SCIP* sourcescip; /**< original SCIP data structure */
524 SCIP_HEUR* heur; /**< scheduler heuristic structure */
525 SCIP_Longint nodelimit; /**< node limit of the run */
526 SCIP_Real lplimfac; /**< limit fraction of LPs per node to interrupt sub-SCIP */
527 HEUR_STATS* runstats; /**< run statistics for the current neighborhood */
528};
529
530/** represents limits for the sub-SCIP solving process */
531struct SolveLimits
532{
533 SCIP_Longint nodelimit; /**< maximum number of solving nodes for the sub-SCIP */
534 SCIP_Real memorylimit; /**< memory limit for the sub-SCIP */
535 SCIP_Real timelimit; /**< time limit for the sub-SCIP */
536 SCIP_Longint stallnodes; /**< maximum number of nodes without (primal) stalling */
537};
538
540
541/** data structure that can be used for variable prioritization for additional fixings */
542struct VarPrio
543{
544 SCIP* scip; /**< SCIP data structure */
545 SCIP_Real* randscores; /**< random scores for prioritization */
546 int* distances; /**< breadth-first distances from already fixed variables */
547 SCIP_Real* redcostscores; /**< reduced cost scores for fixing a variable to a reference value */
548 SCIP_Real* pscostscores; /**< pseudocost scores for fixing a variable to a reference value */
549 unsigned int useredcost:1; /**< should reduced cost scores be used for variable prioritization? */
550 unsigned int usedistances:1; /**< should distances from fixed variables be used for variable prioritization */
551 unsigned int usepscost:1; /**< should pseudo cost scores be used for variable prioritization? */
552};
553
554/*
555 * Local methods
556 */
557
558/** Reset target fixing rate */
559static
561 SCIP* scip, /**< SCIP data structure */
562 NH_FIXINGRATE* fixingrate /**< heuristic fixing rate */
563 )
564{
565 assert(scip != NULL);
566 assert(fixingrate != NULL);
567 fixingrate->increment = FIXINGRATE_STARTINC;
568
569 /* always start with the most conservative value */
570 fixingrate->targetfixingrate = fixingrate->maxfixingrate;
571
572 return SCIP_OKAY;
573}
574
575/** update increment for fixing rate */
576static
578 NH_FIXINGRATE* fx /**< fixing rate */
579 )
580{
582 fx->increment = MAX(fx->increment, LRATEMIN);
583}
584
585/** increase fixing rate
586 *
587 * decrease also the rate by which the target fixing rate is adjusted
588 */
589static
591 NH_FIXINGRATE* fx /**< fixing rate */
592 )
593{
594 fx->targetfixingrate += fx->increment;
596}
597
598/** decrease fixing rate
599 *
600 * decrease also the rate by which the target fixing rate is adjusted
601 */
602static
604 NH_FIXINGRATE* fx /**< fixing rate */
605 )
606{
607 fx->targetfixingrate -= fx->increment;
609}
610
611/** update fixing rate based on the results of the current run */
612static
614 NH* neighborhood, /**< neighborhood */
615 SCIP_STATUS subscipstatus, /**< status of the sub-SCIP run */
616 HEUR_STATS* runstats /**< run statistics for this run */
617 )
618{
619 NH_FIXINGRATE* fx;
620
621 fx = &neighborhood->fixingrate;
622
623 switch (subscipstatus)
624 {
630 /* decrease the fixing rate (make subproblem harder) */
632 break;
637 /* increase the fixing rate (make the subproblem easier) only if no solution was found */
638 if( runstats->nbestsolsfound <= 0 )
640 break;
650 default:
651 break;
652 }
653
655}
656
657/** reset the currently active neighborhood */
658static
660 SCIP_HEURDATA* heurdata
661 )
662{
663 assert(heurdata != NULL);
664 heurdata->currneighborhood = -1;
665 heurdata->ndelayedcalls = 0;
666}
667
668/** reset target node limit */
669static
671 SCIP_HEURDATA* heurdata /**< heuristic data */
672 )
673{
674 heurdata->targetnodes = heurdata->minnodes;
675}
676
677/** Reset neighborhood statistics */
678static
680 SCIP* scip, /**< SCIP data structure */
681 HEUR_STATS* stats, /**< heuristic statistics */
682 SCIP_Bool usediving /**< TRUE if the statistics belong to a diving heuristic */
683 )
684{
685 assert(scip != NULL);
686 assert(stats != NULL);
687
688 stats->nbestsolsfound = 0;
689 stats->nruns = 0;
690 stats->nrunsbestsol = 0;
691 stats->nsolsfound = 0;
692 stats->usednodes = 0L;
693 stats->nfixings = 0L;
694 stats->nbacktracks = 0L;
695 stats->nconflicts = 0L;
696 stats->nprobnodes = 0L;
697 stats->divingdepth = 0;
698
701
702 /* if we use diving, these stats are not used (and memory not allocated) */
703 if( ! usediving )
704 {
706 }
707
708 return SCIP_OKAY;
709}
710
711/** create a neighborhood of the specified name and include it into the scheduler heuristic */
712static
714 SCIP* scip, /**< SCIP data structure */
715 SCIP_HEURDATA* heurdata, /**< heuristic data of the scheduler heuristic */
716 NH** neighborhood, /**< pointer to store the neighborhood */
717 const char* name, /**< name for this neighborhood */
718 SCIP_Real minfixingrate, /**< default value for minfixingrate parameter of this neighborhood */
719 SCIP_Real maxfixingrate, /**< default value for maxfixingrate parameter of this neighborhood */
720 SCIP_Bool active, /**< default value for active parameter of this neighborhood */
721 int priority, /**< priority for heuristic in rootnode */
722 DECL_VARFIXINGS ((*varfixings)), /**< variable fixing callback for this neighborhood, or NULL */
723 DECL_CHANGESUBSCIP ((*changesubscip)), /**< subscip changes callback for this neighborhood, or NULL */
724 DECL_NHINIT ((*nhinit)), /**< initialization callback for neighborhood, or NULL */
725 DECL_NHEXIT ((*nhexit)), /**< deinitialization callback for neighborhood, or NULL */
726 DECL_NHFREE ((*nhfree)), /**< deinitialization callback before SCIP is freed, or NULL */
727 DECL_NHREFSOL ((*nhrefsol)), /**< callback function to return a reference solution for further fixings, or NULL */
728 DECL_NHDEACTIVATE ((*nhdeactivate)) /**< callback function to deactivate neighborhoods on problems where they are irrelevant, or NULL if neighborhood is always active */
729 )
730{
732
733 assert(scip != NULL);
734 assert(heurdata != NULL);
735 assert(neighborhood != NULL);
736 assert(name != NULL);
737
738 SCIP_CALL( SCIPallocBlockMemory(scip, neighborhood) );
739 assert(*neighborhood != NULL);
740
741 SCIP_ALLOC( BMSduplicateMemoryArray(&(*neighborhood)->name, name, strlen(name)+1) );
742
743 SCIP_CALL( SCIPcreateClock(scip, &(*neighborhood)->stats.setupclock) );
744 SCIP_CALL( SCIPcreateClock(scip, &(*neighborhood)->stats.execclock) );
745
746 (*neighborhood)->changesubscip = changesubscip;
747 (*neighborhood)->varfixings = varfixings;
748 (*neighborhood)->nhinit = nhinit;
749 (*neighborhood)->nhexit = nhexit;
750 (*neighborhood)->nhfree = nhfree;
751 (*neighborhood)->nhrefsol = nhrefsol;
752 (*neighborhood)->nhdeactivate = nhdeactivate;
753
754 (*neighborhood)->rootnodepriority = priority;
755
756 /* add parameters for this neighborhood */
757 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/scheduler/%s/minfixingrate", name);
758 SCIP_CALL( SCIPaddRealParam(scip, paramname, "minimum fixing rate for this neighborhood",
759 &(*neighborhood)->fixingrate.minfixingrate, TRUE, minfixingrate, 0.0, 1.0, NULL, NULL) );
760 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/scheduler/%s/maxfixingrate", name);
761 SCIP_CALL( SCIPaddRealParam(scip, paramname, "maximum fixing rate for this neighborhood",
762 &(*neighborhood)->fixingrate.maxfixingrate, TRUE, maxfixingrate, 0.0, 1.0, NULL, NULL) );
763 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/scheduler/%s/active", name);
764 SCIP_CALL( SCIPaddBoolParam(scip, paramname, "is this neighborhood active?",
765 &(*neighborhood)->active, TRUE, active, NULL, NULL) );
766 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "heuristics/scheduler/%s/priority", name);
767 SCIP_CALL( SCIPaddRealParam(scip, paramname, "positive call priority to initialize bandit algorithms",
768 &(*neighborhood)->priority, TRUE, 1.0, 1e-2, 1.0, NULL, NULL) );
769
770 /* add the neighborhood to heuristic */
771 heurdata->neighborhoods[heurdata->nneighborhoods++] = (*neighborhood);
772
773 return SCIP_OKAY;
774}
775
776/** release all data and free neighborhood */
777static
779 SCIP* scip, /**< SCIP data structure */
780 NH** neighborhood /**< pointer to neighborhood that should be freed */
781 )
782{
783 NH* nhptr;
784 assert(scip != NULL);
785 assert(neighborhood != NULL);
786
787 nhptr = *neighborhood;
788 assert(nhptr != NULL);
789
790 BMSfreeMemoryArray(&nhptr->name);
791
792 /* release further, neighborhood specific data structures */
793 if( nhptr->nhfree != NULL )
794 {
795 SCIP_CALL( nhptr->nhfree(scip, nhptr) );
796 }
797
799 SCIP_CALL( SCIPfreeClock(scip, &nhptr->stats.execclock) );
800
801 SCIPfreeBlockMemory(scip, neighborhood);
802 *neighborhood = NULL;
803
804 return SCIP_OKAY;
805}
806
807/** initialize neighborhood specific data */
808static
810 SCIP* scip, /**< SCIP data structure */
811 NH* neighborhood /**< neighborhood to initialize */
812 )
813{
814 assert(scip != NULL);
815 assert(neighborhood != NULL);
816
817 /* call the init callback of the neighborhood */
818 if( neighborhood->nhinit != NULL )
819 {
820 SCIP_CALL( neighborhood->nhinit(scip, neighborhood) );
821 }
822
823 return SCIP_OKAY;
824}
825
826/** deinitialize neighborhood specific data */
827static
829 SCIP* scip, /**< SCIP data structure */
830 NH* neighborhood /**< neighborhood to initialize */
831 )
832{
833 assert(scip != NULL);
834 assert(neighborhood != NULL);
835
836 if( neighborhood->nhexit != NULL )
837 {
838 SCIP_CALL( neighborhood->nhexit(scip, neighborhood) );
839 }
840
841 return SCIP_OKAY;
842}
843
844/** creates a new solution for the original problem by copying the solution of the subproblem */
845static
847 SCIP* subscip, /**< SCIP data structure of the subproblem */
848 SCIP_EVENTDATA* eventdata /**< event handler data */
849 )
850{
851 SCIP* sourcescip; /* original SCIP data structure */
852 SCIP_VAR** subvars; /* the variables of the subproblem */
853 SCIP_HEUR* heur; /* scheduler heuristic structure */
854 SCIP_SOL* subsol; /* solution of the subproblem */
855 SCIP_SOL* newsol; /* solution to be created for the original problem */
856 SCIP_Bool success;
857 HEUR_STATS* runstats;
858 SCIP_SOL* oldbestsol;
859
860 assert(subscip != NULL);
861
862 subsol = SCIPgetBestSol(subscip);
863 assert(subsol != NULL);
864
865 sourcescip = eventdata->sourcescip;
866 subvars = eventdata->subvars;
867 heur = eventdata->heur;
868 runstats = eventdata->runstats;
869 assert(sourcescip != NULL);
870 assert(sourcescip != subscip);
871 assert(heur != NULL);
872 assert(subvars != NULL);
873 assert(runstats != NULL);
874
875 SCIP_CALL( SCIPtranslateSubSol(sourcescip, subscip, subsol, heur, subvars, &newsol) );
876
877 oldbestsol = SCIPgetBestSol(sourcescip);
878
879 /* try to add new solution to scip and free it immediately */
880 SCIP_CALL( SCIPtrySolFree(sourcescip, &newsol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
881
882 if( success )
883 {
884 runstats->nsolsfound++;
885 if( SCIPgetBestSol(sourcescip) != oldbestsol )
886 runstats->nbestsolsfound++;
887 }
888
889 /* update new upper bound for reward later */
890 runstats->newupperbound = SCIPgetUpperbound(sourcescip);
891
892 return SCIP_OKAY;
893}
894
895/** release all data and free diving heuristic */
896static
898 SCIP* scip, /**< SCIP data structure */
899 DIVING_HEUR** divingheur /**< pointer to diving heuristic that should be freed */
900 )
901{
902 DIVING_HEUR* divingheurptr;
903 assert(scip != NULL);
904 assert(divingheur != NULL);
905
906 divingheurptr = *divingheur;
907 assert(divingheurptr != NULL);
908
909 SCIP_CALL( SCIPfreeClock(scip, &divingheurptr->stats->setupclock) );
910 SCIP_CALL( SCIPfreeClock(scip, &divingheurptr->stats->execclock) );
911
912 SCIPfreeBlockMemory(scip, &divingheurptr->solvefreqdata);
913 SCIPfreeBlockMemory(scip, &divingheurptr->stats);
914 SCIPfreeBlockMemory(scip, divingheur);
915
916 return SCIP_OKAY;
917}
918
919/* ---------------- Callback methods of event handler ---------------- */
920
921/** execution callback of the event handler
922 *
923 * transfer new solutions or interrupt the solving process manually
924 */
925static
926SCIP_DECL_EVENTEXEC(eventExecScheduler)
927{
928 assert(eventhdlr != NULL);
929 assert(eventdata != NULL);
930 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
931 assert(event != NULL);
933 assert(eventdata != NULL);
934
935 /* treat the different atomic events */
936 switch( SCIPeventGetType(event) )
937 {
940 /* try to transfer the solution to the original SCIP */
941 SCIP_CALL( transferSolution(scip, eventdata) );
942 break;
944 /* interrupt solution process of sub-SCIP */
945 if( SCIPgetNLPs(scip) > eventdata->lplimfac * eventdata->nodelimit )
946 {
947 SCIPdebugMsg(scip, "interrupt after %" SCIP_LONGINT_FORMAT " LPs\n", SCIPgetNLPs(scip));
949 }
950 break;
951 default:
952 break;
953 }
954
955 return SCIP_OKAY;
956}
957
958/** initialize heuristic statistics before the next run */
959static
961 SCIP* scip, /**< SCIP data structure */
962 HEUR_STATS* stats /**< run statistics */
963 )
964{
965 stats->nbestsolsfound = 0;
966 stats->nsolsfound = 0;
967 stats->usednodes = 0L;
968 stats->nprobnodes = 0L;
969 stats->nbacktracks = 0L;
970 stats->nconflicts = 0L;
971 stats->nfixings = 0;
972 stats->divingdepth = 0;
975}
976
977/** update run stats after the sub SCIP was solved */
978static
980 HEUR_STATS* stats, /**< run statistics */
981 SCIP* subscip /**< sub-SCIP instance, or NULL */
982 )
983{
984 /* treat an untransformed subscip as if none was created */
985 if( subscip != NULL && ! SCIPisTransformed(subscip) )
986 subscip = NULL;
987
988 stats->usednodes = subscip != NULL ? SCIPgetNNodes(subscip) : 0L;
989}
990
991/** get the histogram index for this status */
992static
994 SCIP_STATUS subscipstatus /**< sub-SCIP status */
995 )
996{
997 switch (subscipstatus)
998 {
1000 return (int)HIDX_OPT;
1002 return (int)HIDX_INFEAS;
1004 return (int)HIDX_NODELIM;
1006 return (int)HIDX_STALLNODE;
1009 return (int)HIDX_SOLLIM;
1011 return (int)HIDX_USR;
1012 default:
1013 return (int)HIDX_OTHER;
1014 } /*lint !e788*/
1015}
1016
1017/** print neighborhood statistics */
1018static
1020 SCIP* scip, /**< SCIP data structure */
1021 SCIP_HEURDATA* heurdata, /**< heuristic data */
1022 FILE* file /**< file handle, or NULL for standard out */
1023 )
1024{
1025 int i;
1026 int j;
1028
1029 SCIPinfoMessage(scip, file, "LNS (Scheduler) : %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %4s %4s %4s %4s %4s %4s %4s %4s\n",
1030 "Calls", "SetupTime", "SolveTime", "SolveNodes", "Sols", "Best", "Exp3", "Exp3-IX", "EpsGreedy", "UCB", "TgtFixRate",
1031 "Opt", "Inf", "Node", "Stal", "Sol", "Usr", "Othr", "Actv");
1032
1033 /* loop over neighborhoods and fill in statistics */
1034 for( i = 0; i < heurdata->nneighborhoods; ++i )
1035 {
1036 NH* neighborhood;
1037 SCIP_Real proba;
1038 SCIP_Real probaix;
1039 SCIP_Real ucb;
1040 SCIP_Real epsgreedyweight;
1041
1042 neighborhood = heurdata->neighborhoods[i];
1043 SCIPinfoMessage(scip, file, " %-17s:", neighborhood->name);
1044 SCIPinfoMessage(scip, file, " %10d", neighborhood->stats.nruns);
1045 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, neighborhood->stats.setupclock) );
1046 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, neighborhood->stats.execclock) );
1047 SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, neighborhood->stats.usednodes );
1048 SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, neighborhood->stats.nsolsfound);
1049 SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, neighborhood->stats.nbestsolsfound);
1050
1051 proba = 0.0;
1052 probaix = 0.0;
1053 ucb = 1.0;
1054 epsgreedyweight = -1.0;
1055
1056 if( heurdata->bandit != NULL && i < heurdata->nactiveneighborhoods )
1057 {
1058 switch (heurdata->banditalgo)
1059 {
1060 case 'u':
1061 ucb = SCIPgetConfidenceBoundUcb(heurdata->bandit, i + heurdata->ndiving ); /* note: we need to shift the index since LNS heuristics come after diving */
1062 break;
1063 case 'g':
1064 epsgreedyweight = SCIPgetWeightsEpsgreedy(heurdata->bandit)[i + heurdata->ndiving];
1065 break;
1066 case 'e':
1067 proba = SCIPgetProbabilityExp3(heurdata->bandit, i + heurdata->ndiving);
1068 break;
1069 case 'i':
1070 probaix = SCIPgetProbabilityExp3IX(heurdata->bandit, i + heurdata->ndiving);
1071 break;
1072 default:
1073 break;
1074 }
1075 }
1076
1077 SCIPinfoMessage(scip, file, " %10.5f", proba);
1078 SCIPinfoMessage(scip, file, " %10.5f", probaix);
1079 SCIPinfoMessage(scip, file, " %10.5f", epsgreedyweight);
1080 SCIPinfoMessage(scip, file, " %10.5f", ucb);
1081 SCIPinfoMessage(scip, file, " %10.3f", neighborhood->fixingrate.targetfixingrate);
1082
1083 /* loop over status histogram */
1084 for( j = 0; j < NHISTENTRIES; ++j )
1085 SCIPinfoMessage(scip, file, " %4d", neighborhood->stats.statushist[statusses[j]]);
1086
1087 SCIPinfoMessage(scip, file, " %4d", i < heurdata->nactiveneighborhoods ? 1 : 0);
1088 SCIPinfoMessage(scip, file, "\n");
1089 }
1090}
1091
1092/** collects neighborhood statistics into a SCIP_DATATREE object */
1093static
1095 SCIP* scip, /**< SCIP data structure */
1096 SCIP_HEURDATA* heurdata, /**< heuristic data */
1097 SCIP_DATATREE* datatree /**< data tree */
1098 )
1099{
1100 int i;
1101 int j;
1103 const char* statusnames[] = {"optimal", "infeasible", "nodelimit", "stallnodelimit", "sollimit", "userinterrupt", "other"};
1104 SCIP_DATATREE* lnsstats;
1105
1106 assert(scip != NULL);
1107 assert(heurdata != NULL);
1108 assert(datatree != NULL);
1109
1110 /* Create a subtree for LNS statistics */
1111 SCIP_CALL( SCIPcreateDatatreeInTree(scip, datatree, &lnsstats, "plugins", -1) );
1112
1113 /* Loop over neighborhoods and collect statistics */
1114 for( i = 0; i < heurdata->nneighborhoods; ++i )
1115 {
1116 SCIP_DATATREE* neighborhoodtree;
1117 SCIP_DATATREE* statushist;
1118 const char* statusname;
1119 NH* neighborhood = heurdata->neighborhoods[i];
1120 assert(neighborhood != NULL);
1121
1122 SCIP_CALL( SCIPcreateDatatreeInTree(scip, lnsstats, &neighborhoodtree, neighborhood->name, -1) );
1123
1124 SCIP_CALL( SCIPinsertDatatreeInt(scip, neighborhoodtree, "calls", neighborhood->stats.nruns) );
1125 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "setup_time", SCIPgetClockTime(scip, neighborhood->stats.setupclock)) );
1126 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "solve_time", SCIPgetClockTime(scip, neighborhood->stats.execclock)) );
1127 SCIP_CALL( SCIPinsertDatatreeLong(scip, neighborhoodtree, "solve_nodes", neighborhood->stats.usednodes) );
1128 SCIP_CALL( SCIPinsertDatatreeLong(scip, neighborhoodtree, "solutions_found", neighborhood->stats.nsolsfound) );
1129 SCIP_CALL( SCIPinsertDatatreeLong(scip, neighborhoodtree, "best_solutions_found", neighborhood->stats.nbestsolsfound) );
1130
1131 SCIP_Real proba = 0.0;
1132 SCIP_Real probaix = 0.0;
1133 SCIP_Real ucb = 1.0;
1134 SCIP_Real epsgreedyweight = -1.0;
1135
1136 if( heurdata->bandit != NULL && i < heurdata->nactiveneighborhoods )
1137 {
1138 switch( heurdata->banditalgo )
1139 {
1140 case 'u':
1141 ucb = SCIPgetConfidenceBoundUcb(heurdata->bandit, i + heurdata->ndiving);
1142 break;
1143 case 'g':
1144 epsgreedyweight = SCIPgetWeightsEpsgreedy(heurdata->bandit)[i + heurdata->ndiving];
1145 break;
1146 case 'e':
1147 proba = SCIPgetProbabilityExp3(heurdata->bandit, i + heurdata->ndiving);
1148 break;
1149 case 'i':
1150 probaix = SCIPgetProbabilityExp3IX(heurdata->bandit, i + heurdata->ndiving);
1151 break;
1152 default:
1153 break;
1154 }
1155 }
1156
1157 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "exp3_probability", proba) );
1158 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "exp3_ix_probability", probaix) );
1159 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "eps_greedy_weight", epsgreedyweight) );
1160 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "ucb", ucb) );
1161 SCIP_CALL( SCIPinsertDatatreeReal(scip, neighborhoodtree, "target_fixing_rate", neighborhood->fixingrate.targetfixingrate) );
1162
1163 /* Status histogram */
1164 SCIP_CALL( SCIPcreateDatatreeInTree(scip, neighborhoodtree, &statushist, "status_histogram", -1) );
1165 for( j = 0; j < NHISTENTRIES; ++j )
1166 {
1167 statusname = statusnames[j];
1168 SCIP_CALL( SCIPinsertDatatreeInt(scip, statushist, statusname, neighborhood->stats.statushist[statusses[j]]) );
1169 }
1170
1171 /* Active flag */
1172 SCIP_CALL( SCIPinsertDatatreeBool(scip, neighborhoodtree, "active", i < heurdata->nactiveneighborhoods ? 1 : 0) );
1173 }
1174
1175 return SCIP_OKAY;
1176}
1177
1178/** print diving heuristic statistics */
1179static
1181 SCIP* scip, /**< SCIP data structure */
1182 SCIP_HEURDATA* heurdata, /**< heuristic data */
1183 FILE* file /**< file handle, or NULL for standard out */
1184 )
1185{
1186 int i;
1187
1188 SCIPinfoMessage(scip, file, "Diving (Scheduler) : %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s \n",
1189 "Calls", "SetupTime", "SolveTime", "SolveNodes", "Sols", "Best", "Exp3", "Exp3-IX", "EpsGreedy", "UCB", "LPResolveQuot", "MaxDiveDepth");
1190
1191 /* loop over neighborhoods and fill in statistics */
1192 for( i = 0; i < heurdata->ndiving; ++i )
1193 {
1194 DIVING_HEUR* divingheur;
1195 SCIP_Real proba;
1196 SCIP_Real probaix;
1197 SCIP_Real ucb;
1198 SCIP_Real epsgreedyweight;
1199
1200 divingheur = heurdata->divingheurs[i];
1201 SCIPinfoMessage(scip, file, " %-17s:", SCIPdivesetGetName(divingheur->diveset));
1202 SCIPinfoMessage(scip, file, " %10d", divingheur->stats->nruns);
1203 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, divingheur->stats->setupclock) );
1204 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, divingheur->stats->execclock) );
1205 SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, divingheur->stats->nprobnodes );
1206 SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, divingheur->stats->nsolsfound);
1207 SCIPinfoMessage(scip, file, " %10" SCIP_LONGINT_FORMAT, divingheur->stats->nbestsolsfound);
1208
1209 proba = 0.0;
1210 probaix = 0.0;
1211 ucb = 1.0;
1212 epsgreedyweight = -1.0;
1213
1214 if( heurdata->bandit != NULL )
1215 {
1216 switch (heurdata->banditalgo)
1217 {
1218 case 'u':
1219 ucb = SCIPgetConfidenceBoundUcb(heurdata->bandit, i);
1220 break;
1221 case 'g':
1222 epsgreedyweight = SCIPgetWeightsEpsgreedy(heurdata->bandit)[i];
1223 break;
1224 case 'e':
1225 proba = SCIPgetProbabilityExp3(heurdata->bandit, i);
1226 break;
1227 case 'i':
1228 probaix = SCIPgetProbabilityExp3IX(heurdata->bandit, i);
1229 break;
1230 default:
1231 break;
1232 }
1233 }
1234
1235 SCIPinfoMessage(scip, file, " %10.5f", proba);
1236 SCIPinfoMessage(scip, file, " %10.5f", probaix);
1237 SCIPinfoMessage(scip, file, " %10.5f", epsgreedyweight);
1238 SCIPinfoMessage(scip, file, " %10.5f", ucb);
1239 SCIPinfoMessage(scip, file, " %10.3f", divingheur->solvefreqdata->currentsolvefreq);
1240 SCIPinfoMessage(scip, file, " %10lld", divingheur->nodelimit);
1241
1242 SCIPinfoMessage(scip, file, "\n");
1243 }
1244}
1245
1246/** collects diving heuristic statistics into a SCIP_DATATREE object */
1247static
1249 SCIP* scip, /**< SCIP data structure */
1250 SCIP_HEURDATA* heurdata, /**< heuristic data */
1251 SCIP_DATATREE* datatree /**< data tree */
1252 )
1253{
1254 SCIP_DATATREE* divingstats;
1255 int i;
1256
1257 assert(scip != NULL);
1258 assert(heurdata != NULL);
1259 assert(datatree != NULL);
1260
1261 /* Create a subtree for diving heuristic statistics */
1262 SCIP_CALL( SCIPcreateDatatreeInTree(scip, datatree, &divingstats, "diving_statistics", -1) );
1263
1264 /* Loop over diving heuristics and collect statistics */
1265 for( i = 0; i < heurdata->ndiving; ++i )
1266 {
1267 DIVING_HEUR* divingheur = heurdata->divingheurs[i];
1268 SCIP_DATATREE* divingtree;
1269 assert(divingheur != NULL);
1270
1271 SCIP_CALL( SCIPcreateDatatreeInTree(scip, divingstats, &divingtree, SCIPdivesetGetName(divingheur->diveset), -1) );
1272
1273 SCIP_CALL( SCIPinsertDatatreeInt(scip, divingtree, "calls", divingheur->stats->nruns) );
1274 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "setup_time", SCIPgetClockTime(scip, divingheur->stats->setupclock)) );
1275 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "solve_time", SCIPgetClockTime(scip, divingheur->stats->execclock)) );
1276 SCIP_CALL( SCIPinsertDatatreeLong(scip, divingtree, "solve_nodes", divingheur->stats->nprobnodes) );
1277 SCIP_CALL( SCIPinsertDatatreeLong(scip, divingtree, "solutions_found", divingheur->stats->nsolsfound) );
1278 SCIP_CALL( SCIPinsertDatatreeLong(scip, divingtree, "best_solutions_found", divingheur->stats->nbestsolsfound) );
1279
1280 SCIP_Real proba = 0.0;
1281 SCIP_Real probaix = 0.0;
1282 SCIP_Real ucb = 1.0;
1283 SCIP_Real epsgreedyweight = -1.0;
1284
1285 if( heurdata->bandit != NULL )
1286 {
1287 switch( heurdata->banditalgo )
1288 {
1289 case 'u':
1290 ucb = SCIPgetConfidenceBoundUcb(heurdata->bandit, i);
1291 break;
1292 case 'g':
1293 epsgreedyweight = SCIPgetWeightsEpsgreedy(heurdata->bandit)[i];
1294 break;
1295 case 'e':
1296 proba = SCIPgetProbabilityExp3(heurdata->bandit, i);
1297 break;
1298 case 'i':
1299 probaix = SCIPgetProbabilityExp3IX(heurdata->bandit, i);
1300 break;
1301 default:
1302 break;
1303 }
1304 }
1305
1306 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "exp3_probability", proba) );
1307 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "exp3_ix_probability", probaix) );
1308 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "eps_greedy_weight", epsgreedyweight) );
1309 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "ucb", ucb) );
1310 SCIP_CALL( SCIPinsertDatatreeReal(scip, divingtree, "lp_resolve_quotient", divingheur->solvefreqdata->currentsolvefreq) );
1311 SCIP_CALL( SCIPinsertDatatreeLong(scip, divingtree, "max_dive_depth", divingheur->nodelimit) );
1312 }
1313
1314 return SCIP_OKAY;
1315}
1316
1317/** update the statistics of the diving heuristic based on the heuristic run */
1318static
1320 HEUR_STATS* runstats, /**< run statistics */
1321 DIVING_HEUR* divingheur /**< the selected diving heuristic or NULL if LNS was used */
1322 )
1323{ /*lint --e{715}*/
1324 HEUR_STATS* stats;
1325
1326 assert(divingheur != NULL);
1327
1328 stats = divingheur->stats;
1329
1330 /* update diving specific statistics */
1331 stats->nprobnodes += runstats->nprobnodes;
1332 stats->nbacktracks += runstats->nbacktracks;
1333 stats->nconflicts += runstats->nconflicts;
1334
1335 /* copy run statistics into heur statistics */
1336 stats->nbestsolsfound += runstats->nbestsolsfound;
1337 stats->nsolsfound += runstats->nsolsfound;
1338 stats->nruns += 1;
1339
1340 if( runstats->nbestsolsfound > 0 )
1342 else if( runstats->nsolsfound > 0 )
1343 stats->nrunsbestsol++;
1344}
1345
1346/** update the statistics of LNS heuristic based on the heuristic run */
1347static
1349 HEUR_STATS* runstats, /**< run statistics */
1350 NH* neighborhood, /**< the selected neighborhood */
1351 SCIP_STATUS* subscipstatus /**< status of the sub-SCIP solve */
1352 )
1353{
1354 HEUR_STATS* stats;
1355
1356 assert(runstats != NULL);
1357 assert(neighborhood != NULL);
1358 assert(subscipstatus != NULL);
1359
1360 /* update LNS specific statistics */
1361 stats = &neighborhood->stats;
1362 stats->usednodes += runstats->usednodes;
1363 ++stats->statushist[getHistIndex(*subscipstatus)]; /* update the counter for the subscip status */
1364
1365 /* copy run statistics into heur statistics */
1366 stats->nbestsolsfound += runstats->nbestsolsfound;
1367 stats->nsolsfound += runstats->nsolsfound;
1368 stats->nruns += 1;
1369
1370 if( runstats->nbestsolsfound > 0 )
1372 else if( runstats->nsolsfound > 0 )
1373 stats->nrunsbestsol++;
1374}
1375
1376/** sort callback for variable pointers using the ALNS variable prioritization
1377 *
1378 * the variable prioritization works hierarchically as follows. A variable
1379 * a has the higher priority over b iff
1380 *
1381 * - variable distances should be used and a has a smaller distance than b
1382 * - variable reduced costs should be used and a has a smaller score than b
1383 * - variable pseudo costs should be used and a has a smaller score than b
1384 * - based on previously assigned random scores
1385 *
1386 * @note: distances are context-based. For fixing more variables,
1387 * distances are initialized from the already fixed variables.
1388 * For unfixing variables, distances are initialized starting
1389 * from the unfixed variables
1390 */
1391static
1392SCIP_DECL_SORTINDCOMP(sortIndCompScheduler)
1393{ /*lint --e{715}*/
1394 VARPRIO* varprio;
1395
1396 varprio = (VARPRIO*)dataptr;
1397 assert(varprio != NULL);
1398 assert(varprio->randscores != NULL);
1399
1400 if( ind1 == ind2 )
1401 return 0;
1402
1403 /* priority is on distances, if enabled. The variable which is closer in a breadth-first search sense to
1404 * the already fixed variables has precedence */
1405 if( varprio->usedistances )
1406 {
1407 int dist1;
1408 int dist2;
1409
1410 dist1 = varprio->distances[ind1];
1411 dist2 = varprio->distances[ind2];
1412
1413 if( dist1 < 0 )
1414 dist1 = INT_MAX;
1415
1416 if( dist2 < 0 )
1417 dist2 = INT_MAX;
1418
1419 assert(varprio->distances != NULL);
1420 if( dist1 < dist2 )
1421 return -1;
1422 else if( dist1 > dist2 )
1423 return 1;
1424 }
1425
1426 assert(! varprio->usedistances || varprio->distances[ind1] == varprio->distances[ind2]);
1427
1428 /* if the indices tie considering distances or distances are disabled -> use reduced cost information instead */
1429 if( varprio->useredcost )
1430 {
1431 assert(varprio->redcostscores != NULL);
1432
1433 if( varprio->redcostscores[ind1] < varprio->redcostscores[ind2] )
1434 return -1;
1435 else if( varprio->redcostscores[ind1] > varprio->redcostscores[ind2] )
1436 return 1;
1437 }
1438
1439 /* use pseudo cost scores if reduced costs are disabled or a tie was found */
1440 if( varprio->usepscost )
1441 {
1442 assert(varprio->pscostscores != NULL);
1443
1444 /* prefer the variable with smaller pseudocost score */
1445 if( varprio->pscostscores[ind1] < varprio->pscostscores[ind2] )
1446 return -1;
1447 else if( varprio->pscostscores[ind1] > varprio->pscostscores[ind2] )
1448 return 1;
1449 }
1450
1451 if( varprio->randscores[ind1] < varprio->randscores[ind2] )
1452 return -1;
1453 else if( varprio->randscores[ind1] > varprio->randscores[ind2] )
1454 return 1;
1455
1456 return ind1 - ind2;
1457}
1458
1459/** Compute the reduced cost score for this variable in the reference solution */
1460static
1462 SCIP* scip, /**< SCIP data structure */
1463 SCIP_VAR* var, /**< the variable for which the score should be computed */
1464 SCIP_Real refsolval, /**< solution value in reference solution */
1465 SCIP_Bool uselocalredcost /**< should local reduced costs be used for generic (un)fixing? */
1466 )
1467{
1468 SCIP_Real bestbound;
1469 SCIP_Real redcost;
1470 SCIP_Real score;
1471 assert(scip != NULL);
1472 assert(var != NULL);
1473
1474 /* prefer column variables */
1476 return SCIPinfinity(scip);
1477
1478 if( ! uselocalredcost )
1479 {
1480 redcost = SCIPvarGetBestRootRedcost(var);
1481
1482 bestbound = SCIPvarGetBestRootSol(var);
1483
1484 /* using global reduced costs, the two factors yield a nonnegative score within tolerances */
1485 assert(SCIPisDualfeasZero(scip, redcost)
1486 || (SCIPisDualfeasNegative(scip, redcost) && ! SCIPisFeasPositive(scip, refsolval - bestbound))
1487 || (SCIPisDualfeasPositive(scip, redcost) && ! SCIPisFeasNegative(scip, refsolval - bestbound)));
1488 }
1489 else
1490 {
1491 /* this can be safely asserted here, since the heuristic would not reach this point, otherwise */
1492 assert(SCIPhasCurrentNodeLP(scip));
1494
1495 redcost = SCIPgetVarRedcost(scip, var);
1496
1497 bestbound = SCIPvarGetLPSol(var);
1498 }
1499
1500 assert(! SCIPisInfinity(scip, REALABS(bestbound)));
1501 assert(SCIPisDualfeasZero(scip, redcost) || SCIPisFeasIntegral(scip, bestbound));
1502
1503 score = redcost * (refsolval - bestbound);
1504
1505 /* max out numerical inaccuracies from global scores */
1506 if( ! uselocalredcost )
1507 score = MAX(score, 0.0);
1508
1509 return score;
1510}
1511
1512/** get the pseudo cost score of this variable with respect to the reference solution */
1513static
1515 SCIP* scip, /**< SCIP data structure */
1516 SCIP_VAR* var, /**< the variable for which the score should be computed */
1517 SCIP_Real refsolval, /**< solution value in reference solution */
1518 SCIP_Bool uselocallpsol /**< should local LP solution be used? */
1519 )
1520{
1521 SCIP_Real lpsolval;
1522
1523 assert(scip != NULL);
1524 assert(var != NULL);
1525
1526 /* variables that aren't LP columns have no pseudocost score */
1528 return 0.0;
1529
1530 lpsolval = uselocallpsol ? SCIPvarGetLPSol(var) : SCIPvarGetRootSol(var);
1531
1532 /* the score is 0.0 if the values are equal */
1533 if( SCIPisEQ(scip, lpsolval, refsolval) )
1534 return 0.0;
1535 else
1536 return SCIPgetVarPseudocostVal(scip, var, refsolval - lpsolval);
1537}
1538
1539/** add variable and solution value to buffer data structure for variable fixings. The method checks if
1540 * the value still lies within the variable bounds. The value stays unfixed otherwise.
1541 */
1542static
1544 SCIP* scip, /**< SCIP data structure */
1545 SCIP_VAR* var, /**< (source) SCIP variable that should be added to the buffer */
1546 SCIP_Real val, /**< fixing value for this variable */
1547 SCIP_VAR** varbuf, /**< variable buffer to store variables that should be fixed */
1548 SCIP_Real* valbuf, /**< value buffer to store fixing values */
1549 int* nfixings, /**< pointer to number of fixed buffer variables, will be increased by 1 */
1550 SCIP_Bool integer /**< is this an integer variable? */
1551 )
1552{
1553 assert(SCIPisFeasIntegral(scip, val) || ! SCIPvarIsIntegral(var));
1554 assert(*nfixings < SCIPgetNVars(scip));
1555
1556 /* round the value to its nearest integer */
1557 if( integer )
1558 val = SCIPfloor(scip, val + 0.5);
1559
1560 /* only add fixing if it is still valid within the global variable bounds. Invalidity
1561 * of this solution value may come from a dual reduction that was performed after the solution from which
1562 * this value originated was found
1563 */
1564 if( SCIPvarGetLbGlobal(var) <= val && val <= SCIPvarGetUbGlobal(var) )
1565 {
1566 varbuf[*nfixings] = var;
1567 valbuf[*nfixings] = val;
1568 ++(*nfixings);
1569 }
1570}
1571
1572/** fix additional variables found in feasible reference solution if the ones that the neighborhood found were not enough
1573 *
1574 * use not always the best solution for the values, but a reference solution provided by the neighborhood itself
1575 *
1576 * @note it may happen that the target fixing rate is not completely reached. This is the case if intermediate,
1577 * dual reductions render the solution values of the reference solution infeasible for
1578 * the current, global variable bounds.
1579 */
1580static
1582 SCIP* scip, /**< SCIP data structure */
1583 SCIP_HEURDATA* heurdata, /**< heuristic data of the Scheduler neighborhood */
1584 SCIP_SOL* refsol, /**< feasible reference solution for more variable fixings */
1585 SCIP_VAR** varbuf, /**< buffer array to store variables to fix */
1586 SCIP_Real* valbuf, /**< buffer array to store fixing values */
1587 int* nfixings, /**< pointer to store the number of fixings */
1588 int ntargetfixings, /**< number of required target fixings */
1589 SCIP_Bool* success /**< pointer to store whether the target fixings have been successfully reached */
1590 )
1591{
1592 VARPRIO varprio;
1593 SCIP_VAR** vars;
1594 SCIP_Real* redcostscores;
1595 SCIP_Real* pscostscores;
1596 SCIP_Real* solvals;
1597 SCIP_RANDNUMGEN* rng;
1598 SCIP_VAR** unfixedvars;
1599 SCIP_Bool* isfixed;
1600 int* distances;
1601 int* perm;
1602 SCIP_Real* randscores;
1603 int nbinvars;
1604 int nintvars;
1605 int nbinintvars;
1606 int nvars;
1607 int b;
1608 int nvarstoadd;
1609 int nunfixedvars;
1610
1611 assert(scip != NULL);
1612 assert(varbuf != NULL);
1613 assert(nfixings != NULL);
1614 assert(success != NULL);
1615 assert(heurdata != NULL);
1616 assert(refsol != NULL);
1617
1618 *success = FALSE;
1619
1620 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
1621
1622 nbinintvars = nbinvars + nintvars;
1623
1624 if( ntargetfixings >= nbinintvars )
1625 return SCIP_OKAY;
1626
1627 /* determine the number of required additional fixings */
1628 nvarstoadd = ntargetfixings - *nfixings;
1629 if( nvarstoadd == 0 )
1630 return SCIP_OKAY;
1631
1632 varprio.usedistances = heurdata->usedistances && (*nfixings >= 1);
1633 varprio.useredcost = heurdata->useredcost;
1634 varprio.usepscost = heurdata->usepscost;
1635 varprio.scip = scip;
1636 rng = SCIPbanditGetRandnumgen(heurdata->bandit);
1637 assert(rng != NULL);
1638
1639 SCIP_CALL( SCIPallocBufferArray(scip, &randscores, nbinintvars) );
1640 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nbinintvars) );
1641 SCIP_CALL( SCIPallocBufferArray(scip, &distances, nvars) );
1642 SCIP_CALL( SCIPallocBufferArray(scip, &redcostscores, nbinintvars) );
1643 SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nbinintvars) );
1644 SCIP_CALL( SCIPallocBufferArray(scip, &isfixed, nbinintvars) );
1645 SCIP_CALL( SCIPallocBufferArray(scip, &unfixedvars, nbinintvars) );
1646 SCIP_CALL( SCIPallocBufferArray(scip, &pscostscores, nbinintvars) );
1647
1648 /* initialize variable graph distances from already fixed variables */
1649 if( varprio.usedistances )
1650 {
1651 SCIP_CALL( SCIPvariablegraphBreadthFirst(scip, NULL, varbuf, *nfixings, distances, INT_MAX, INT_MAX, ntargetfixings) );
1652 }
1653 else
1654 {
1655 /* initialize all equal distances to make them irrelevant */
1656 BMSclearMemoryArray(distances, nbinintvars);
1657 }
1658
1659 BMSclearMemoryArray(isfixed, nbinintvars);
1660
1661 /* mark binary and integer variables if they are fixed */
1662 for( b = 0; b < *nfixings; ++b )
1663 {
1664 int probindex;
1665
1666 assert(varbuf[b] != NULL);
1667 probindex = SCIPvarGetProbindex(varbuf[b]);
1668 assert(probindex >= 0);
1669
1670 if( probindex < nbinintvars )
1671 isfixed[probindex] = TRUE;
1672 }
1673
1674 SCIP_CALL( SCIPgetSolVals(scip, refsol, nbinintvars, vars, solvals) );
1675
1676 /* assign scores to unfixed every discrete variable of the problem */
1677 nunfixedvars = 0;
1678 for( b = 0; b < nbinintvars; ++b )
1679 {
1680 SCIP_VAR* var = vars[b];
1681
1682 /* filter fixed variables */
1683 if( isfixed[b] )
1684 continue;
1685
1686 /* filter variables with a solution value outside its global bounds */
1687 if( solvals[b] < SCIPvarGetLbGlobal(var) - 0.5 || solvals[b] > SCIPvarGetUbGlobal(var) + 0.5 )
1688 continue;
1689
1690 redcostscores[nunfixedvars] = getVariableRedcostScore(scip, var, solvals[b], heurdata->uselocalredcost);
1691 pscostscores[nunfixedvars] = getVariablePscostScore(scip, var, solvals[b], heurdata->uselocalredcost);
1692
1693 unfixedvars[nunfixedvars] = var;
1694 perm[nunfixedvars] = nunfixedvars;
1695 randscores[nunfixedvars] = SCIPrandomGetReal(rng, 0.0, 1.0);
1696
1697 /* these assignments are based on the fact that nunfixedvars <= b */
1698 solvals[nunfixedvars] = solvals[b];
1699 distances[nunfixedvars] = distances[b];
1700
1701 //SCIPdebugMsg(scip, "Var <%s> scores: dist %3d, red cost %15.9g, pscost %15.9g rand %6.4f\n",
1702 // SCIPvarGetName(var), distances[nunfixedvars], redcostscores[nunfixedvars],
1703 // pscostscores[nunfixedvars], randscores[nunfixedvars]);
1704
1705 nunfixedvars++;
1706 }
1707
1708 /* use selection algorithm (order of the variables does not matter) for quickly completing the fixing */
1709 varprio.randscores = randscores;
1710 varprio.distances = distances;
1711 varprio.redcostscores = redcostscores;
1712 varprio.pscostscores = pscostscores;
1713
1714 /* select the first nvarstoadd many variables according to the score */
1715 if( nvarstoadd < nunfixedvars )
1716 SCIPselectInd(perm, sortIndCompScheduler, &varprio, nvarstoadd, nunfixedvars);
1717 else
1718 nvarstoadd = nunfixedvars;
1719
1720 /* loop over the first elements of the selection defined in permutation. They represent the best variables */
1721 for( b = 0; b < nvarstoadd; ++b )
1722 {
1723 int permindex = perm[b];
1724 assert(permindex >= 0);
1725 assert(permindex < nunfixedvars);
1726
1727 tryAdd2variableBuffer(scip, unfixedvars[permindex], solvals[permindex], varbuf, valbuf, nfixings, TRUE);
1728 }
1729
1730 *success = TRUE;
1731
1732 /* free buffer arrays */
1733 SCIPfreeBufferArray(scip, &pscostscores);
1734 SCIPfreeBufferArray(scip, &unfixedvars);
1735 SCIPfreeBufferArray(scip, &isfixed);
1736 SCIPfreeBufferArray(scip, &solvals);
1737 SCIPfreeBufferArray(scip, &redcostscores);
1738 SCIPfreeBufferArray(scip, &distances);
1739 SCIPfreeBufferArray(scip, &perm);
1740 SCIPfreeBufferArray(scip, &randscores);
1741
1742 return SCIP_OKAY;
1743}
1744
1745/** create the bandit algorithm for the heuristic depending on the user parameter */
1746static
1748 SCIP* scip, /**< SCIP data structure */
1749 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
1750 SCIP_Real* priorities, /**< call priorities for active neighborhoods */
1751 unsigned int initseed /**< initial random seed */
1752 )
1753{
1754 int nactions;
1755
1756 nactions = heurdata->nactiveneighborhoods + heurdata->ndiving;
1757
1758 switch (heurdata->banditalgo)
1759 {
1760 case 'u':
1761 SCIP_CALL( SCIPcreateBanditUcb(scip, &heurdata->bandit, priorities,
1762 heurdata->ucb_alpha, nactions, initseed) );
1763 break;
1764
1765 case 'e':
1766 SCIP_CALL( SCIPcreateBanditExp3(scip, &heurdata->bandit, priorities,
1767 heurdata->exp3_gamma, heurdata->exp3_beta, nactions, initseed) );
1768 break;
1769
1770 case 'i':
1771 SCIP_CALL( SCIPcreateBanditExp3IX(scip, &heurdata->bandit, priorities, nactions, initseed) );
1772 break;
1773
1774 case 'g':
1775 SCIP_CALL( SCIPcreateBanditEpsgreedy(scip, &heurdata->bandit, priorities,
1776 heurdata->epsgreedy_eps, heurdata->epsgreedy_usemod, FALSE, 0.9, 0, nactions, initseed) );
1777 break;
1778
1779 default:
1780 SCIPerrorMessage("Unknown bandit parameter %c\n", heurdata->banditalgo);
1781 return SCIP_INVALIDDATA;
1782 }
1783
1784 return SCIP_OKAY;
1785}
1786
1787/*
1788 * Callback methods of primal heuristic
1789 */
1790
1791/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
1792static
1793SCIP_DECL_HEURCOPY(heurCopyScheduler)
1794{ /*lint --e{715}*/
1795 assert(scip != NULL);
1796 assert(heur != NULL);
1797 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1798
1799 /* call inclusion method of primal heuristic */
1801
1802 return SCIP_OKAY;
1803}
1804
1805/** query neighborhood for a reference solution for further fixings */
1806static
1808 SCIP* scip, /**< SCIP data structure */
1809 NH* neighborhood, /**< neighborhood data structure */
1810 SCIP_SOL** solptr /**< solution pointer */
1811 )
1812{
1813 assert(solptr != NULL);
1814 assert(scip != NULL);
1815 assert(neighborhood != NULL);
1816
1817 *solptr = NULL;
1818 if( neighborhood->nhrefsol != NULL )
1819 {
1820 SCIP_RESULT result;
1821 SCIP_CALL( neighborhood->nhrefsol(scip, neighborhood, solptr, &result) );
1822
1823 if( result == SCIP_DIDNOTFIND )
1824 *solptr = NULL;
1825 else
1826 assert(*solptr != NULL);
1827 }
1828
1829 return SCIP_OKAY;
1830}
1831
1832/** unfix some of the variables because there are too many fixed
1833 *
1834 * a variable is ideally unfixed if it is close to other unfixed variables
1835 * and fixing it has a high reduced cost impact
1836 */
1837static
1839 SCIP* scip, /**< SCIP data structure */
1840 SCIP_HEURDATA* heurdata, /**< heuristic data of neighborhood */
1841 SCIP_VAR** varbuf, /**< buffer array to store variables to fix */
1842 SCIP_Real* valbuf, /**< buffer array to store fixing values */
1843 int* nfixings, /**< pointer to store the number of fixings */
1844 int ntargetfixings, /**< number of required target fixings */
1845 SCIP_Bool* success /**< pointer to store whether the target fixings have been successfully reached */
1846 )
1847{
1848 VARPRIO varprio;
1849 SCIP_Real* redcostscores;
1850 SCIP_Real* pscostscores;
1851 SCIP_Real* randscores;
1852 SCIP_VAR** unfixedvars;
1853 SCIP_VAR** varbufcpy;
1854 SCIP_Real* valbufcpy;
1855 SCIP_Bool* isfixedvar;
1856 SCIP_VAR** vars;
1857 SCIP_RANDNUMGEN* rng;
1858 int* distances;
1859 int* fixeddistances;
1860 int* perm;
1861 int nvars;
1862 int i;
1863 int nbinintvars;
1864 int nunfixed;
1865
1866 *success = FALSE;
1867
1868 nbinintvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
1869 if( nbinintvars == 0 )
1870 return SCIP_OKAY;
1871
1872 assert(*nfixings > 0);
1873
1874 nvars = SCIPgetNVars(scip);
1875 SCIP_CALL( SCIPallocBufferArray(scip, &isfixedvar, nvars) );
1876 SCIP_CALL( SCIPallocBufferArray(scip, &unfixedvars, nbinintvars) );
1877 SCIP_CALL( SCIPallocBufferArray(scip, &distances, nvars) );
1878 SCIP_CALL( SCIPallocBufferArray(scip, &fixeddistances, *nfixings) );
1879 SCIP_CALL( SCIPallocBufferArray(scip, &redcostscores, *nfixings) );
1880 SCIP_CALL( SCIPallocBufferArray(scip, &randscores, *nfixings) );
1881 SCIP_CALL( SCIPallocBufferArray(scip, &perm, *nfixings) );
1882 SCIP_CALL( SCIPallocBufferArray(scip, &pscostscores, *nfixings) );
1883
1884 SCIP_CALL( SCIPduplicateBufferArray(scip, &varbufcpy, varbuf, *nfixings) );
1885 SCIP_CALL( SCIPduplicateBufferArray(scip, &valbufcpy, valbuf, *nfixings) );
1886
1887 /*
1888 * collect the unfixed binary and integer variables
1889 */
1890 BMSclearMemoryArray(isfixedvar, nvars);
1891 /* loop over fixed variables and mark their respective positions as fixed */
1892 for( i = 0; i < *nfixings; ++i )
1893 {
1894 int probindex = SCIPvarGetProbindex(varbuf[i]);
1895
1896 assert(probindex >= 0);
1897
1898 isfixedvar[probindex] = TRUE;
1899 }
1900
1901 nunfixed = 0;
1902 vars = SCIPgetVars(scip);
1903 /* collect unfixed binary and integer variables */
1904 for( i = 0; i < nbinintvars; ++i )
1905 {
1906 if( ! isfixedvar[i] )
1907 unfixedvars[nunfixed++] = vars[i];
1908 }
1909
1910 varprio.usedistances = heurdata->usedistances && nunfixed > 0;
1911
1912 /* collect distances of all fixed variables from those that are not fixed */
1913 if( varprio.usedistances )
1914 {
1915 SCIP_CALL( SCIPvariablegraphBreadthFirst(scip, NULL, unfixedvars, nunfixed, distances, INT_MAX, INT_MAX, INT_MAX) );
1916
1917 for( i = 0; i < *nfixings; ++i )
1918 {
1919 int probindex = SCIPvarGetProbindex(varbuf[i]);
1920 if( probindex >= 0 )
1921 fixeddistances[i] = distances[probindex];
1922 }
1923 }
1924 else
1925 {
1926 BMSclearMemoryArray(fixeddistances, *nfixings);
1927 }
1928
1929 /* collect reduced cost scores of the fixings and assign random scores */
1930 rng = SCIPbanditGetRandnumgen(heurdata->bandit);
1931 for( i = 0; i < *nfixings; ++i )
1932 {
1933 SCIP_VAR* fixedvar = varbuf[i];
1934 SCIP_Real fixval = valbuf[i];
1935
1936 /* use negative reduced cost and pseudo cost scores to prefer variable fixings with small score */
1937 redcostscores[i] = - getVariableRedcostScore(scip, fixedvar, fixval, heurdata->uselocalredcost);
1938 pscostscores[i] = - getVariablePscostScore(scip, fixedvar, fixval, heurdata->uselocalredcost);
1939 randscores[i] = SCIPrandomGetReal(rng, 0.0, 1.0);
1940 perm[i] = i;
1941
1942 //SCIPdebugMsg(scip, "Var <%s> scores: dist %3d, red cost %15.9g, pscost %15.9g rand %6.4f\n",
1943 // SCIPvarGetName(fixedvar), fixeddistances[i], redcostscores[i], pscostscores[i], randscores[i]);
1944 }
1945
1946 varprio.distances = fixeddistances;
1947 varprio.randscores = randscores;
1948 varprio.redcostscores = redcostscores;
1949 varprio.pscostscores = pscostscores;
1950 varprio.useredcost = heurdata->useredcost;
1951 varprio.usepscost = heurdata->usepscost;
1952 varprio.scip = scip;
1953
1954 /* scores are assigned in such a way that variables with a smaller score should be fixed last */
1955 SCIPselectDownInd(perm, sortIndCompScheduler, &varprio, ntargetfixings, *nfixings);
1956
1957 /* bring the desired variables to the front of the array */
1958 for( i = 0; i < ntargetfixings; ++i )
1959 {
1960 valbuf[i] = valbufcpy[perm[i]];
1961 varbuf[i] = varbufcpy[perm[i]];
1962 }
1963
1964 *nfixings = ntargetfixings;
1965
1966 /* free the buffer arrays in reverse order of allocation */
1967 SCIPfreeBufferArray(scip, &valbufcpy);
1968 SCIPfreeBufferArray(scip, &varbufcpy);
1969 SCIPfreeBufferArray(scip, &pscostscores);
1970 SCIPfreeBufferArray(scip, &perm);
1971 SCIPfreeBufferArray(scip, &randscores);
1972 SCIPfreeBufferArray(scip, &redcostscores);
1973 SCIPfreeBufferArray(scip, &fixeddistances);
1974 SCIPfreeBufferArray(scip, &distances);
1975 SCIPfreeBufferArray(scip, &unfixedvars);
1976 SCIPfreeBufferArray(scip, &isfixedvar);
1977
1978 *success = TRUE;
1979
1980 return SCIP_OKAY;
1981}
1982
1983/** call variable fixing callback for this neighborhood and orchestrate additional variable fixings, if necessary */
1984static
1986 SCIP* scip, /**< SCIP data structure */
1987 SCIP_HEURDATA* heurdata, /**< heuristic data of the scheduler neighborhood */
1988 NH* neighborhood, /**< neighborhood data structure */
1989 SCIP_VAR** varbuf, /**< buffer array to keep variables that should be fixed */
1990 SCIP_Real* valbuf, /**< buffer array to keep fixing values */
1991 int* nfixings, /**< pointer to store the number of variable fixings */
1992 SCIP_RESULT* result /**< pointer to store the result of the fixing operation */
1993 )
1994{
1995 int ntargetfixings;
1996 int nmaxfixings;
1997 int nminfixings;
1998 int nbinintvars;
1999
2000 assert(scip != NULL);
2001 assert(neighborhood != NULL);
2002 assert(varbuf != NULL);
2003 assert(valbuf != NULL);
2004 assert(nfixings != NULL);
2005 assert(result != NULL);
2006
2007 *nfixings = 0;
2008
2009 *result = SCIP_DIDNOTRUN;
2010 ntargetfixings = (int)(neighborhood->fixingrate.targetfixingrate * (SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip)));
2011
2012 if( neighborhood->varfixings != NULL )
2013 {
2014 SCIP_CALL( neighborhood->varfixings(scip, neighborhood, varbuf, valbuf, nfixings, result) );
2015
2016 if( *result != SCIP_SUCCESS )
2017 return SCIP_OKAY;
2018 }
2019 else if( ntargetfixings == 0 )
2020 {
2021 *result = SCIP_SUCCESS;
2022 return SCIP_OKAY;
2023 }
2024
2025 /* compute upper and lower target fixing limits using tolerance parameters */
2026 assert(neighborhood->varfixings == NULL || *result != SCIP_DIDNOTRUN);
2027 nbinintvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
2028 ntargetfixings = (int)(neighborhood->fixingrate.targetfixingrate * nbinintvars);
2029 nminfixings = (int)((neighborhood->fixingrate.targetfixingrate - heurdata->fixtol) * nbinintvars);
2030 nminfixings = MAX(nminfixings, 0);
2031 nmaxfixings = (int)((neighborhood->fixingrate.targetfixingrate + heurdata->unfixtol) * nbinintvars);
2032 nmaxfixings = MIN(nmaxfixings, nbinintvars);
2033
2034 SCIPdebugMsg(scip, "Neighborhood Fixings/Target: %d / %d <= %d <= %d\n",*nfixings, nminfixings, ntargetfixings, nmaxfixings);
2035
2036 /* if too few fixings, use a strategy to select more variable fixings: randomized, LP graph, ReducedCost based, mix */
2037 if( (*result == SCIP_SUCCESS || *result == SCIP_DIDNOTRUN) && (*nfixings < nminfixings) )
2038 {
2039 SCIP_Bool success;
2040 SCIP_SOL* refsol;
2041
2042 /* get reference solution from neighborhood */
2043 SCIP_CALL( neighborhoodGetRefsol(scip, neighborhood, &refsol) );
2044
2045 /* try to fix more variables based on the reference solution */
2046 if( refsol != NULL )
2047 {
2048 SCIP_CALL( LNSFixMoreVariables(scip, heurdata, refsol, varbuf, valbuf, nfixings, ntargetfixings, &success) );
2049 }
2050 else
2051 success = FALSE;
2052
2053 if( success )
2054 *result = SCIP_SUCCESS;
2055 else if( *result == SCIP_SUCCESS )
2056 *result = SCIP_DIDNOTFIND;
2057 else
2058 *result = SCIP_DIDNOTRUN;
2059
2060 SCIPdebugMsg(scip, "After additional fixings: %d / %d\n",*nfixings, ntargetfixings);
2061 }
2062 else if( (SCIP_Real)(*nfixings) > nmaxfixings )
2063 {
2064 SCIP_Bool success;
2065
2066 SCIP_CALL( LNSUnfixVariables(scip, heurdata, varbuf, valbuf, nfixings, ntargetfixings, &success) );
2067
2068 assert(success);
2069 *result = SCIP_SUCCESS;
2070 SCIPdebugMsg(scip, "Unfixed variables, fixed variables remaining: %d\n", ntargetfixings);
2071 }
2072 else
2073 {
2074 SCIPdebugMsg(scip, "No additional fixings performed\n");
2075 }
2076
2077 return SCIP_OKAY;
2078}
2079
2080/** change the sub-SCIP by restricting variable domains, changing objective coefficients, or adding constraints */
2081static
2083 SCIP* sourcescip, /**< source SCIP data structure */
2084 SCIP* targetscip, /**< target SCIP data structure */
2085 NH* neighborhood, /**< neighborhood */
2086 SCIP_VAR** targetvars, /**< array of target SCIP variables aligned with source SCIP variables */
2087 int* ndomchgs, /**< pointer to store the number of variable domain changes */
2088 int* nchgobjs, /**< pointer to store the number of changed objective coefficients */
2089 int* naddedconss, /**< pointer to store the number of added constraints */
2090 SCIP_Bool* success /**< pointer to store whether the sub-SCIP has been successfully modified */
2091 )
2092{
2093 assert(sourcescip != NULL);
2094 assert(targetscip != NULL);
2095 assert(neighborhood != NULL);
2096 assert(targetvars != NULL);
2097 assert(ndomchgs != NULL);
2098 assert(nchgobjs != NULL);
2099 assert(naddedconss != NULL);
2100 assert(success != NULL);
2101
2102 *success = FALSE;
2103 *ndomchgs = 0;
2104 *nchgobjs = 0;
2105 *naddedconss = 0;
2106
2107 /* call the change sub-SCIP callback of the neighborhood */
2108 if( neighborhood->changesubscip != NULL )
2109 {
2110 SCIP_CALL( neighborhood->changesubscip(sourcescip, targetscip, neighborhood, targetvars, ndomchgs, nchgobjs, naddedconss, success) );
2111 }
2112 else
2113 {
2114 *success = TRUE;
2115 }
2116
2117 return SCIP_OKAY;
2118}
2119
2120/** set sub-SCIP solving limits */
2121static
2123 SCIP* subscip, /**< SCIP data structure */
2124 SOLVELIMITS* solvelimits /**< pointer to solving limits data structure */
2125 )
2126{
2127 assert(subscip != NULL);
2128 assert(solvelimits != NULL);
2129
2130 assert(solvelimits->nodelimit >= solvelimits->stallnodes);
2131
2132 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", solvelimits->nodelimit) );
2133 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", solvelimits->stallnodes) );
2134 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", solvelimits->timelimit) );
2135 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", solvelimits->memorylimit) );
2136
2137 return SCIP_OKAY;
2138}
2139
2140/** determine limits for a sub-SCIP */
2141static
2143 SCIP* scip, /**< SCIP data structure */
2144 SCIP_HEUR* heur, /**< this heuristic */
2145 int selection, /**< index of selected neighborhood */
2146 SOLVELIMITS* solvelimits, /**< pointer to solving limits data structure */
2147 SCIP_Bool* runagain /**< can we solve another sub-SCIP with these limits */
2148 )
2149{
2150 SCIP_HEURDATA* heurdata;
2151 SCIP_Bool avoidmemout;
2152
2153 assert(scip != NULL);
2154 assert(heur != NULL);
2155 assert(solvelimits != NULL);
2156 assert(runagain != NULL);
2157
2158 heurdata = SCIPheurGetData(heur);
2159
2160 /* check whether there is enough time and memory left */
2161 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &solvelimits->timelimit) );
2162 if( ! SCIPisInfinity(scip, solvelimits->timelimit) )
2163 solvelimits->timelimit -= SCIPgetSolvingTime(scip);
2164 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &solvelimits->memorylimit) );
2165 SCIP_CALL( SCIPgetBoolParam(scip, "misc/avoidmemout", &avoidmemout) );
2166
2167 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
2168 if( ! SCIPisInfinity(scip, solvelimits->memorylimit) )
2169 {
2170 solvelimits->memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
2171 solvelimits->memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
2172 }
2173
2174 /* abort if no time is left or not enough memory (we don't abort in this case if misc_avoidmemout == FALSE)
2175 * to create a copy of SCIP, including external memory usage */
2176 if( solvelimits->timelimit <= 0.0 || (avoidmemout && solvelimits->memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0) )
2177 {
2178 SCIPdebugMsg(scip, "Aborting LNS heuristic call: Not enough memory or time left.\n");
2179 *runagain = FALSE;
2180 return SCIP_OKAY;
2181 }
2182
2183 /* TODO: set stalling limit */
2184 solvelimits->stallnodes = -1;
2185 solvelimits->nodelimit = (SCIP_Longint) heurdata->neighborhoods[selection]->nodelimit;
2186
2187 return SCIP_OKAY;
2188}
2189
2190/** Calculate reward based on the selected reward measure */
2191static
2193 SCIP* scip, /**< SCIP data structure */
2194 SCIP_HEURDATA* heurdata, /**< heuristic data of the scheduler neighborhood */
2195 int selection, /**< index of selected heuristic */
2196 HEUR_STATS* runstats /**< run statistics */
2197 )
2198{
2199 SCIP_Real totalreward;
2200 SCIP_Real effortsaved;
2201 SCIP_Real bestsolreward;
2202 SCIP_Real closedgapreward;
2203 SCIP_Real conflictreward;
2204
2205 /* compute the effort it took to execute selected heuristic */
2206 if( selection < heurdata->ndiving )
2207 effortsaved = (SCIP_Real) runstats->divingdepth / (SCIP_Real)heurdata->maxdivingnodelimit;
2208 else
2209 effortsaved = MIN(1.0, (SCIP_Real) runstats->usednodes / (SCIP_Real)heurdata->maxlnsnodelimit);
2210 effortsaved = (1.0 - effortsaved);
2211 assert(effortsaved >= 0.0 && effortsaved <= 1.0);
2212 assert(heurdata->maxlnsnodelimit > 0);
2213 assert(heurdata->maxdivingnodelimit > 0);
2214
2215 /* compute reward for number of conflicts generated */
2216 if( selection < heurdata->ndiving )
2217 {
2218 if( runstats->nconflicts == 0 )
2219 conflictreward = 0.0;
2220 else if( heurdata->maxnconflicts > 0 )
2221 conflictreward = (SCIP_Real) runstats->nconflicts / (SCIP_Real) heurdata->maxnconflicts;
2222 else
2223 conflictreward = 1.0;
2224 }
2225 else
2226 conflictreward = 0.0; /* LNS heuristics don't add conflict constraints */
2227 assert(conflictreward >= 0.0 && conflictreward <= 1.0);
2228
2229 /* a positive reward is only assigned if a new incumbent solution was found */
2230 if( runstats->nbestsolsfound > 0 )
2231 {
2232 SCIP_Real lb;
2233 SCIP_Real ub;
2234
2235 /* the indicator function is simply 1.0 */
2236 bestsolreward = 1.0;
2237
2238 ub = runstats->newupperbound;
2239 lb = SCIPgetLowerbound(scip);
2240
2241 /* compute the closed gap reward */
2242 if( SCIPisEQ(scip, ub, lb) || SCIPisInfinity(scip, runstats->oldupperbound) ) // gap is closed or first primal solution was found
2243 closedgapreward = 1.0;
2244 else
2245 closedgapreward = (runstats->oldupperbound - ub) / (runstats->oldupperbound - lb);
2246 }
2247 else
2248 {
2249 bestsolreward = 0.0;
2250 closedgapreward = 0.0;
2251 }
2252
2253 /* compute total reward */
2254 totalreward = heurdata->effortrewardweight * effortsaved + heurdata->solrewardweight * bestsolreward
2255 + heurdata->qualrewardweight * closedgapreward + heurdata->conflictrewardweight * conflictreward;
2256 totalreward = MIN( totalreward, 1.0);
2257 assert(totalreward >= 0.0 && totalreward <= 1.0);
2258
2259 return totalreward;
2260}
2261
2262/** set up the sub-SCIP parameters, objective cutoff, and solution limits */
2263static
2265 SCIP* scip, /**< SCIP data structure */
2266 SCIP* subscip, /**< sub-SCIP data structure */
2267 SCIP_VAR** subvars, /**< array of sub-SCIP variables in the order of the main SCIP */
2268 SOLVELIMITS* solvelimits, /**< pointer to solving limits data structure */
2269 SCIP_HEUR* heur, /**< this heuristic */
2270 SCIP_Bool objchgd /**< did the objective change between the source and the target SCIP? */
2271 )
2272{
2273 SCIP_HEURDATA* heurdata;
2274 SCIP_Real cutoff;
2275
2276 heurdata = SCIPheurGetData(heur);
2277
2278 /* do not abort subproblem on CTRL-C */
2279 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
2280
2281 /* disable output to console unless we are in debug mode */
2282 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
2283
2284 /* disable statistic timing inside sub SCIP */
2285 SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) );
2286
2287#ifdef SCHEDULER_SUBSCIPOUTPUT
2288 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
2289 SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 1) );
2290 /* enable statistic timing inside sub SCIP */
2291 SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", TRUE) );
2292#endif
2293
2294 SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", heurdata->nsolslim) );
2295
2296 /* forbid recursive call of heuristics and separators solving subMIPs */
2297 if( ! heurdata->usesubscipheurs )
2298 {
2299 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
2300 }
2301
2302 /* disable cutting plane separation */
2304
2305 /* disable expensive presolving */
2307
2308 /* use best estimate node selection */
2309 if( SCIPfindNodesel(subscip, "estimate") != NULL && ! SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
2310 {
2311 SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
2312 }
2313
2314 /* use inference branching */
2315 if( SCIPfindBranchrule(subscip, "inference") != NULL && ! SCIPisParamFixed(subscip, "branching/inference/priority") )
2316 {
2317 SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
2318 }
2319
2320 /* enable conflict analysis and restrict conflict pool */
2321 if( ! SCIPisParamFixed(subscip, "conflict/enable") )
2322 {
2323 SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/enable", TRUE) );
2324 }
2325
2326 if( !SCIPisParamFixed(subscip, "conflict/useboundlp") )
2327 {
2328 SCIP_CALL( SCIPsetCharParam(subscip, "conflict/useboundlp", 'o') );
2329 }
2330
2331 if( ! SCIPisParamFixed(subscip, "conflict/maxstoresize") )
2332 {
2333 SCIP_CALL( SCIPsetIntParam(subscip, "conflict/maxstoresize", 100) );
2334 }
2335
2336 /* speed up sub-SCIP by not checking dual LP feasibility */
2337 SCIP_CALL( SCIPsetBoolParam(subscip, "lp/checkdualfeas", FALSE) );
2338
2339 /* add an objective cutoff */
2341 {
2343
2344 /* if the objective changed between the source and the target SCIP, encode the cutoff as a constraint */
2345 if( ! objchgd )
2346 {
2347 SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) );
2348 }
2349 else
2350 {
2351 SCIP_CONS* objcons;
2352 int nvars;
2353 SCIP_VAR** vars;
2354 int i;
2355
2356 vars = SCIPgetVars(scip);
2357 nvars = SCIPgetNVars(scip);
2358
2359 SCIP_CALL( SCIPcreateConsLinear(subscip, &objcons, "objbound_of_origscip", 0, NULL, NULL, -SCIPinfinity(subscip), cutoff,
2361 for( i = 0; i < nvars; ++i)
2362 {
2363 if( ! SCIPisFeasZero(subscip, SCIPvarGetObj(vars[i])) )
2364 {
2365 assert(subvars[i] != NULL);
2366 SCIP_CALL( SCIPaddCoefLinear(subscip, objcons, subvars[i], SCIPvarGetObj(vars[i])) );
2367 }
2368 }
2369 SCIP_CALL( SCIPaddCons(subscip, objcons) );
2370 SCIP_CALL( SCIPreleaseCons(subscip, &objcons) );
2371 }
2372 }
2373
2374 /* set solve limits for sub-SCIP */
2375 SCIP_CALL( setLimits(subscip, solvelimits) );
2376
2377 /* change random seed of sub-SCIP */
2378 if( heurdata->subsciprandseeds )
2379 {
2380 SCIP_CALL( SCIPsetIntParam(subscip, "randomization/randomseedshift", (int)SCIPheurGetNCalls(heur)) );
2381 }
2382
2383 return SCIP_OKAY;
2384}
2385
2386/** initialize solving frequency */
2387static
2389 SOLVEFREQ* solvefreqdata /**< diving heuristic solving freq data */
2390 )
2391{
2392 assert(solvefreqdata != NULL);
2393
2394 /* initialize solve frequency data */
2395 solvefreqdata->increment = SOLVEFREQ_STARTINC;
2396 solvefreqdata->maxsolvefreq = MAXSOLVEFREQ;
2397 solvefreqdata->minsolvefreq = MINSOLVEFREQ;
2398
2399 /* always start with the most conservative value */
2400 solvefreqdata->currentsolvefreq = solvefreqdata->minsolvefreq;
2401}
2402
2403/** update increment for solving frequency */
2404static
2406 SOLVEFREQ* solvefreqdata /**< diving heuristic solving freq data */
2407 )
2408{
2409 solvefreqdata->increment *= SOLVEFREQ_DECAY;
2410 solvefreqdata->increment = MAX(solvefreqdata->increment, LRATEMIN);
2411}
2412
2413/** increase solving frequency
2414 *
2415 * decrease also the rate by which the solving frequency is adjusted
2416 */
2417static
2419 SOLVEFREQ* solvefreqdata /**< diving heuristic solving freq data */
2420 )
2421{
2422 solvefreqdata->currentsolvefreq += solvefreqdata->increment;
2423 solvefreqdata->currentsolvefreq = MIN(solvefreqdata->currentsolvefreq, solvefreqdata->maxsolvefreq);
2424}
2425
2426/** decrease solving frequency
2427 *
2428 * decrease also the rate by which the solving frequency is adjusted
2429 */
2430static
2432 SOLVEFREQ* solvefreqdata /**< diving heuristic solving freq data */
2433 )
2434{
2435 solvefreqdata->currentsolvefreq -= solvefreqdata->increment;
2436 solvefreqdata->currentsolvefreq = MAX(solvefreqdata->currentsolvefreq, solvefreqdata->minsolvefreq);
2437}
2438
2439/** update solve frequency for diving heuristics */
2440static
2442 DIVING_HEUR* divingheur, /**< diving heuristic */
2443 HEUR_STATS* stats /**< run statistics for this run */
2444 )
2445{
2446 /* find out why diving heuristic terminated and adapt resolve frequency accordingly */
2447 if( (int) stats->nprobnodes == divingheur->nodelimit )
2448 increaseSolveFreq(divingheur->solvefreqdata);
2449 else if( stats->nsolsfound == 0 )
2450 decreaseSolveFreq(divingheur->solvefreqdata);
2451
2453}
2454
2455/** find publicly available divesets and store them */
2456static
2458 SCIP* scip, /**< SCIP data structure */
2459 SCIP_HEUR* heur, /**< the heuristic */
2460 SCIP_HEURDATA* heurdata /**< heuristic data */
2461 )
2462{
2463 int h;
2464 SCIP_HEUR** heurs;
2465
2466 assert(scip != NULL);
2467 assert(heur != NULL);
2468 assert(heurdata != NULL);
2469
2470 heurs = SCIPgetHeurs(scip);
2471
2472 heurdata->divingheurssize = DIVINGHEURS_INITIALSIZE;
2473 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &heurdata->divingheurs, heurdata->divingheurssize) );
2474 heurdata->ndiving = 0;
2475
2476 for( h = 0; h < SCIPgetNHeurs(scip); ++h )
2477 {
2478 int d;
2479 assert(heurs[h] != NULL);
2480
2481 /* loop over divesets of this heuristic and check whether they are public */
2482 for( d = 0; d < SCIPheurGetNDivesets(heurs[h]); ++d )
2483 {
2484 SCIP_DIVESET* diveset = SCIPheurGetDivesets(heurs[h])[d];
2485
2486 if( SCIPdivesetIsPublic(diveset) )
2487 {
2488 DIVING_HEUR* divingheur;
2489
2490 SCIPdebugMsg(scip, "Found publicly available diveset %s\n", SCIPdivesetGetName(diveset));
2491
2492 /* allocate memory for the diving heuristic */
2493 SCIP_CALL( SCIPallocBlockMemory(scip, &divingheur) );
2494 SCIP_CALL( SCIPallocBlockMemory(scip, &(divingheur->stats)) );
2496
2497 /* fill struct with diving heuristic specific information */
2498 divingheur->diveset = diveset;
2499 divingheur->nodelimit = heurdata->initdivingnodelimit;
2500 divingheur->rootnodepriority = SCIPheurGetPriority(heurs[h]);
2501 divingheur->priority = 1.0;
2502
2503 initSolveFreq(divingheur->solvefreqdata);
2504 SCIP_CALL( SCIPcreateClock(scip, &(divingheur->stats->setupclock)) );
2505 SCIP_CALL( SCIPcreateClock(scip, &(divingheur->stats->execclock)) );
2506 SCIP_CALL( heurStatsReset(scip, divingheur->stats, TRUE) );
2507
2508 if( heurdata->ndiving == heurdata->divingheurssize )
2509 {
2510 int newsize = 2 * heurdata->divingheurssize;
2511 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &heurdata->divingheurs, heurdata->divingheurssize, newsize) );
2512 heurdata->divingheurssize = newsize;
2513 }
2514 assert( heurdata->ndiving < heurdata->divingheurssize );
2515
2516 heurdata->divingheurs[heurdata->ndiving] = divingheur;
2517 heurdata->ndiving++;
2518 }
2519 else
2520 {
2521 SCIPdebugMsg(scip, "Skipping private diveset %s\n", SCIPdivesetGetName(diveset));
2522 }
2523 }
2524 }
2525 return SCIP_OKAY;
2526}
2527
2528/** select a heuristic depending on the selected bandit algorithm */
2529static
2531 SCIP* scip, /**< SCIP data structure */
2532 SCIP_HEURDATA* heurdata, /**< heuristic data of the scheduler heuristic */
2533 int* selection /**< pointer to store the selected heuristic index */
2534 )
2535{
2536 SCIP_BANDIT* bandit;
2537 int nactions;
2538
2539 assert(scip != NULL);
2540 assert(heurdata != NULL);
2541 assert(selection != NULL);
2542
2543 *selection = -1;
2544 bandit = heurdata->bandit;
2545 nactions = heurdata->ndiving + heurdata->nactiveneighborhoods;
2546
2547 /* if we use default priorities for executing heuristics for the first time, we don't have to call
2548 * the bandit to select next action */
2549 if( heurdata->defaultroot && heurdata->counter < nactions )
2550 {
2551 *selection = heurdata->sortedindices[heurdata->counter];
2552 heurdata->counter++;
2553 }
2554 else
2555 {
2556 SCIP_CALL( SCIPbanditSelect(bandit, selection) );
2557 }
2558 assert(*selection >= 0);
2559 assert(*selection < heurdata->nactiveneighborhoods + heurdata->ndiving);
2560
2561 return SCIP_OKAY;
2562}
2563
2564/** update selection strategy with observed reward for future draws */
2565static
2567 SCIP* scip, /**< SCIP data structure */
2568 SCIP_HEURDATA* heurdata, /**< heuristic data of the scheduler heuristic */
2569 SCIP_Real reward, /**< measured reward */
2570 int selection /**< the heuristic index that was chosen */
2571 )
2572{
2573 SCIP_BANDIT* bandit;
2574
2575 assert(scip != NULL);
2576 assert(heurdata != NULL);
2577 assert(selection >= 0);
2578 assert(selection < heurdata->nneighborhoods + heurdata->ndiving);
2579
2580 bandit = heurdata->bandit;
2581
2582 SCIPdebugMsg(scip, "Rewarding bandit algorithm action %d with reward %.2f\n", selection, reward);
2583 SCIP_CALL( SCIPbanditUpdate(bandit, selection, reward) );
2584
2585 return SCIP_OKAY;
2586}
2587
2588/** execute diving heuristic */
2589static
2591 SCIP* scip, /**< SCIP data structure */
2592 SCIP_HEUR* heur, /**< scheduler heuristic */
2593 int selection, /**< the heuristic index that was chosen */
2594 HEUR_STATS* runstats, /**< statistics of the call to selection */
2595 SCIP_RESULT* result /**< pointer to store the result of the heuristic call */
2596 )
2597{
2598 SCIP_HEURDATA* heurdata;
2599 DIVING_HEUR** divingheurs;
2600 SCIP_DIVESET* diveset;
2601
2602 heurdata = SCIPheurGetData(heur);
2603 assert(heurdata != NULL);
2604
2605 divingheurs = heurdata->divingheurs;
2606 assert(divingheurs != NULL);
2607 assert(heurdata->ndiving > 0);
2608 assert(selection < heurdata->ndiving);
2609 assert(divingheurs[selection] != NULL);
2610
2611 diveset = divingheurs[selection]->diveset;
2612 assert(diveset != NULL);
2613
2614 SCIPdebugMsg(scip, "Selected diving heuristic %s (idx: %d)\n", SCIPdivesetGetName(diveset), selection);
2615
2616 /* store some data beforehand to track all improvemnts */
2623
2624 if( strcmp(SCIPdivesetGetName(diveset), "guideddiving") != 0 || (strcmp(SCIPdivesetGetName(diveset), "guideddiving") == 0
2626 {
2627 SCIP_CALL( SCIPstartClock(scip, divingheurs[selection]->stats->execclock) );
2628
2629 /* perform dive */
2630 SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, divingheurs[selection]->diveset, heurdata->sol, heur,
2631 result, FALSE, -1LL, (int) divingheurs[selection]->nodelimit,
2632 divingheurs[selection]->solvefreqdata->currentsolvefreq, SCIP_DIVECONTEXT_SCHEDULER) );
2633
2634 SCIP_CALL( SCIPstopClock(scip, divingheurs[selection]->stats->execclock) );
2635 }
2636
2637 /* store improvements (if solution was found, what solution was found, nconflict constraints, etc.) */
2641 runstats->nsolsfound = SCIPdivesetGetNSols(diveset, SCIP_DIVECONTEXT_SCHEDULER) - runstats->nsolsfound;
2644
2645 /* update maximum number of conflicts found */
2646 heurdata->maxnconflicts = MAX(heurdata->maxnconflicts, (int) runstats->nconflicts);
2647
2648 SCIPdebugMsg(scip, "Finished executing diving heuristic %s (idx: %d) with %lld sols (%lld best sols), %lld conflicts, %lld backtracks and %lld probing nodes \n",
2649 SCIPdivesetGetName(diveset), selection, runstats->nsolsfound, runstats->nbestsolsfound,
2650 runstats->nconflicts, runstats->nbacktracks, runstats->nprobnodes);
2651
2652 if( runstats->nbestsolsfound > 0 )
2653 SCIPdebugMsg(scip, "Upperbound changed: %g -> %g\n", runstats->oldupperbound, runstats->newupperbound);
2654
2655 assert( runstats->nbestsolsfound == 0 || runstats->oldupperbound > runstats->newupperbound );
2656
2657 return SCIP_OKAY;
2658}
2659
2660/** execute LNS heuristic */
2661static
2663 SCIP* scip, /**< SCIP data structure */
2664 SCIP_HEUR* heur, /**< scheduler heuristic */
2665 int selection, /**< the heuristic index that was chosen */
2666 HEUR_STATS* runstats, /**< statistics of the call to selection */
2667 SCIP_STATUS* subscipstatus, /**< pointer to store status of the sub-SCIP solve */
2668 SCIP_RESULT* result /**< pointer to store the result of the heuristic call */
2669 )
2670{
2671 SCIP_HEURDATA* heurdata;
2672 SCIP_VAR** varbuf;
2673 SCIP_Real* valbuf;
2674 SCIP_VAR** vars;
2675 SCIP_VAR** subvars;
2676 SCIP* subscip = NULL;
2677
2678 int nfixings;
2679 int nvars;
2680 NH* neighborhood;
2681 SOLVELIMITS solvelimits;
2682 SCIP_Bool success;
2683 SCIP_Bool run;
2684
2685 SCIP_HASHMAP* varmapf;
2686 SCIP_EVENTHDLR* eventhdlr;
2687 SCIP_EVENTDATA eventdata;
2688 char probnamesuffix[SCIP_MAXSTRLEN];
2689 int ndomchgs;
2690 int nchgobjs;
2691 int naddedconss;
2692 int v;
2693 SCIP_RETCODE retcode;
2694 SCIP_RESULT fixresult;
2695
2696 heurdata = SCIPheurGetData(heur);
2697 assert(heurdata != NULL);
2698
2699 *result = SCIP_DIDNOTRUN;
2700 *subscipstatus = SCIP_STATUS_UNKNOWN;
2701 run = TRUE;
2702
2703 SCIPdebugMsg(scip, "Selected LNS heuristic %s (idx: %d)\n", heurdata->neighborhoods[selection]->name, selection + heurdata->ndiving);
2704
2705 /* check if budget allows a run of the next selected neighborhood */
2706 SCIP_CALL( determineLimits(scip, heur, selection, &solvelimits, &run) );
2707
2708 if( ! run )
2709 return SCIP_OKAY;
2710
2711 /* allocate memory for variable fixings buffer */
2712 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2713 SCIP_CALL( SCIPallocBufferArray(scip, &varbuf, nvars) );
2714 SCIP_CALL( SCIPallocBufferArray(scip, &valbuf, nvars) );
2715 SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
2716
2717 neighborhood = heurdata->neighborhoods[selection];
2718 SCIPdebugMsg(scip, "Running '%s' neighborhood %d\n", neighborhood->name, selection);
2719
2720 SCIP_CALL( SCIPstartClock(scip, neighborhood->stats.setupclock) );
2721
2722 /* determine variable fixings and objective coefficients of this neighborhood */
2723 SCIP_CALL( neighborhoodFixVariables(scip, heurdata, neighborhood, varbuf, valbuf, &nfixings, &fixresult) );
2724
2725 SCIPdebugMsg(scip, "Fix %d/%d variables, result code %d\n", nfixings, nvars, fixresult);
2726
2727 /* Fixing was not successful, either because the fixing rate was not reached (and no additional variable
2728 * prioritization was used), or the neighborhood requested a delay, e.g., because no LP relaxation solution exists
2729 * at the current node
2730 *
2731 * The scheduler heuristic keeps a delayed neighborhood active and delays itself.
2732 * TODO: handle delays
2733 */
2734 if( fixresult != SCIP_SUCCESS )
2735 {
2736 SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.setupclock) );
2737
2738 SCIPdebugMsg(scip, "Aborting LNS heuristic call: Not enough variables fixed.\n");
2739
2740 *result = fixresult;
2741 goto CLEANUP;
2742 }
2743
2744 *result = SCIP_DIDNOTFIND;
2745
2746 neighborhood->stats.nfixings += nfixings;
2747 runstats->nfixings = nfixings;
2748
2749 SCIP_CALL( SCIPcreate(&subscip) );
2750 SCIP_CALL( SCIPhashmapCreate(&varmapf, SCIPblkmem(scip), nvars) );
2751 (void) SCIPsnprintf(probnamesuffix, SCIP_MAXSTRLEN, "scheduler_%s", neighborhood->name);
2752
2753 /* todo later: run global propagation for this set of fixings */
2754 SCIP_CALL( SCIPcopyLargeNeighborhoodSearch(scip, subscip, varmapf, probnamesuffix, varbuf, valbuf, nfixings, FALSE, heurdata->copycuts, &success, NULL) );
2755
2756 /* store sub-SCIP variables in array for faster access */
2757 for( v = 0; v < nvars; ++v )
2758 {
2759 subvars[v] = (SCIP_VAR*)SCIPhashmapGetImage(varmapf, (void *)vars[v]);
2760 }
2761
2762 SCIPhashmapFree(&varmapf);
2763
2764 /* let the neighborhood add additional constraints, or restrict domains */
2765 SCIP_CALL( neighborhoodChangeSubscip(scip, subscip, neighborhood, subvars, &ndomchgs, &nchgobjs, &naddedconss, &success) );
2766
2767 if( ! success )
2768 {
2769 SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.setupclock) );
2770 SCIPdebugMsg(scip, "Aborting LNS heuristic call: Problems with creating subproblem.\n");
2771 goto CLEANUP;
2772 }
2773
2774 /* set up sub-SCIP parameters */
2775 SCIP_CALL( setupSubScip(scip, subscip, subvars, &solvelimits, heur, nchgobjs > 0) );
2776
2777 /* copy the necessary data into the event data to create new solutions */
2778 eventdata.nodelimit = solvelimits.nodelimit; /*lint !e644*/
2779 eventdata.lplimfac = heurdata->lplimfac;
2780 eventdata.heur = heur;
2781 eventdata.sourcescip = scip;
2782 eventdata.subvars = subvars;
2783 eventdata.runstats = runstats;
2784
2785 /* include an event handler to transfer solutions into the main SCIP */
2786 SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecScheduler, NULL) );
2787
2788 /* transform the problem before catching the events */
2789 SCIP_CALL( SCIPtransformProb(subscip) );
2790 SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_SCHEDULER, eventhdlr, &eventdata, NULL) );
2791
2792 SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.setupclock) );
2793
2794 SCIP_CALL( SCIPstartClock(scip, neighborhood->stats.execclock) );
2795
2796 /* set up sub-SCIP and run presolving */
2797 retcode = SCIPpresolve(subscip);
2798 if( retcode != SCIP_OKAY )
2799 {
2800 SCIPwarningMessage(scip, "Error while presolving subproblem in Scheduler heuristic; sub-SCIP terminated with code <%d>\n", retcode);
2801 SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.execclock) );
2802
2803 SCIPABORT(); /*lint --e{527}*/
2804 goto CLEANUP;
2805 }
2806
2807 /* run sub-SCIP for the given budget, and collect statistics */
2808 SCIP_CALL_ABORT( SCIPsolve(subscip) );
2809
2810#ifdef SCHEDULER_SUBSCIPOUTPUT
2811 SCIP_CALL( SCIPprintStatistics(subscip, NULL) );
2812#endif
2813
2814 SCIP_CALL( SCIPstopClock(scip, neighborhood->stats.execclock) );
2815
2816 /* update statistics based on the sub-SCIP run results */
2817 updateRunStats(runstats, subscip);
2818 *subscipstatus = SCIPgetStatus(subscip);
2819 SCIPdebugMsg(scip, "Status of sub-SCIP run: %d\n", *subscipstatus);
2820
2821CLEANUP:
2822 if( subscip != NULL )
2823 {
2824 SCIP_CALL( SCIPfree(&subscip) );
2825 }
2826
2827 SCIPfreeBufferArray(scip, &subvars);
2828 SCIPfreeBufferArray(scip, &valbuf);
2829 SCIPfreeBufferArray(scip, &varbuf);
2830
2831 if( *result != SCIP_DELAYED && *result != SCIP_DIDNOTRUN )
2832 {
2833 /* decrease the number of neighborhoods that have not been initialized */
2834 if( neighborhood->stats.nruns == 0 )
2835 --heurdata->ninitneighborhoods;
2836
2837 heurdata->usednodes += runstats->usednodes;
2838
2839 SCIPdebugMsg(scip, "Finished executing LNS heuristic %s (idx: %d) with %lld sols (%lld best sols) and %lld nodes used.\n",
2840 neighborhood->name, selection + heurdata->ndiving, runstats->nsolsfound, runstats->nbestsolsfound, runstats->usednodes);
2841
2842 if( runstats->nbestsolsfound > 0 )
2843 SCIPdebugMsg(scip, "Upperbound changed: %g -> %g\n", runstats->oldupperbound, SCIPgetUpperbound(scip));
2844
2845 resetCurrentNeighborhood(heurdata);
2846 }
2847
2848 return SCIP_OKAY;
2849}
2850
2851/** execute selected heuristic */
2852static
2854 SCIP* scip, /**< SCIP data structure */
2855 SCIP_HEUR* heur, /**< scheduler heuristic */
2856 int selection, /**< the heuristic index that was chosen */
2857 HEUR_STATS* runstats, /**< statistics of call to selection */
2858 SCIP_STATUS* subscipstatus, /**< pointer to store status of the sub-SCIP solve or NULL if diving was used */
2859 SCIP_RESULT* result /**< pointer to store the result of the heuristic call */
2860 )
2861{
2862 SCIP_HEURDATA* heurdata;
2863
2864 heurdata = SCIPheurGetData(heur);
2865 assert(heurdata != NULL);
2866 assert(scip != NULL);
2867 assert(selection >= 0);
2868 assert(selection < heurdata->nneighborhoods + heurdata->ndiving);
2869
2870 /* check if a diving or LNS heuristic was selected */
2871 if( selection < heurdata->ndiving )
2872 {
2873 SCIP_CALL( executeDivingHeuristic(scip, heur, selection, runstats, result) );
2874 }
2875 else
2876 {
2877 SCIP_CALL( executeLNSHeuristic(scip, heur, selection - heurdata->ndiving, runstats, subscipstatus, result) );
2878 }
2879
2880 return SCIP_OKAY;
2881}
2882
2883/** reinitialize bandit algorithm since the number of actions has changed */
2884static
2886 SCIP* scip, /**< SCIP data structure */
2887 SCIP_HEURDATA* heurdata, /**< heuristic data */
2888 int nactions /**< new number of actions */
2889 )
2890{
2891 SCIP_Real* priorities;
2892 int i;
2893 unsigned int initseed;
2894
2895 /* allocate memory for the priorities */
2896 SCIP_CALL( SCIPallocBufferArray(scip, &priorities, nactions) );
2897
2898 /* get the priorities */
2899 for( i = 0; i < heurdata->ndiving; ++i )
2900 priorities[i] = heurdata->divingheurs[i]->priority;
2901 for( i = 0; i < heurdata->nactiveneighborhoods; ++i )
2902 priorities[i + heurdata->ndiving] = heurdata->neighborhoods[i]->priority;
2903
2904 /* free bandit if necessary */
2905 if( heurdata->bandit != NULL )
2906 {
2907 SCIP_CALL( SCIPfreeBandit(scip, &heurdata->bandit) );
2908 heurdata->bandit = NULL;
2909 }
2910
2911 /* create bandit again */
2912 initseed = (unsigned int)(heurdata->seed + SCIPgetNVars(scip));
2913 SCIP_CALL( createBandit(scip, heurdata, priorities, initseed) );
2914 resetTargetNodeLimit(heurdata);
2915
2916 /* free memory */
2917 SCIPfreeBufferArray(scip, &priorities);
2918
2919 return SCIP_OKAY;
2920}
2921
2922/** initializes everything that was missing because diving heuristics were not proccessed by SCIP yet. In particular,
2923 * the function adds diving heuristics to heurdata, heurdata->maxdivingnodelimit,
2924 * heurdata->maxlnsnodelimit and heurdata->sortedindices if heurdata->defaultroot is set to TRUE
2925 */
2926static
2928 SCIP* scip, /**< SCIP data structure */
2929 SCIP_HEUR* heur /**< scheduler heuristic */
2930 )
2931{
2932 SCIP_HEURDATA* heurdata;
2933 SCIP_Real* priorities;
2934 int nheurs;
2935 int i;
2936
2937 /* get heuristic data */
2938 heurdata = SCIPheurGetData(heur);
2939
2940 /* include the diving heuristics */
2941 SCIP_CALL( includeDivingHeurs(scip, heur, heurdata) );
2942
2943 /* get number of active heuristics we can choose from */
2944 nheurs = heurdata->ndiving + heurdata->nactiveneighborhoods;
2945
2946 /* we need to initialize the bandit method again since the number of actions has changed */
2947 SCIP_CALL( reinitBandit(scip, heurdata, nheurs) );
2948
2949 /* set maximum of all node and diving depth limit */
2950 heurdata->maxdivingnodelimit = heurdata->initdivingnodelimit;
2951 heurdata->maxlnsnodelimit = heurdata->initlnsnodelimit;
2952
2953 /* initialize nodelimit for all LNS heursitics */
2954 for( i = 0; i < heurdata->nactiveneighborhoods; ++i )
2955 heurdata->neighborhoods[i]->nodelimit = heurdata->initlnsnodelimit;
2956
2957 /* initialize indices array and sort according to heuristic's priorities if we want to execute heuristics in default order
2958 * at the root node*/
2959 if( heurdata->defaultroot )
2960 {
2961 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &heurdata->sortedindices, heurdata->ndiving + heurdata->nneighborhoods) );
2962 SCIP_CALL( SCIPallocBufferArray(scip, &priorities, nheurs) );
2963 heurdata->counter = 0;
2964
2965 for( i = 0; i < nheurs; ++i )
2966 {
2967 heurdata->sortedindices[i] = i;
2968
2969 if( i < heurdata->ndiving )
2970 priorities[i] = (SCIP_Real)-heurdata->divingheurs[i]->rootnodepriority;
2971 else
2972 priorities[i] = (SCIP_Real)-heurdata->neighborhoods[i - heurdata->ndiving]->rootnodepriority;
2973 }
2974
2975 /* sort indices */
2976 SCIPsortRealInt(priorities, heurdata->sortedindices, nheurs);
2977
2978 SCIPfreeBufferArray(scip, &priorities);
2979 }
2980
2981 return SCIP_OKAY;
2982}
2983
2984/** execution method of primal heuristic */
2985static
2986SCIP_DECL_HEUREXEC(heurExecScheduler)
2987{ /*lint --e{715}*/
2988 SCIP_HEURDATA* heurdata;
2989 SCIP_Bool success;
2990
2991 assert(heur != NULL);
2992 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
2993 assert(scip != NULL);
2994 assert(result != NULL);
2995
2996 /* get heuristic data */
2997 heurdata = SCIPheurGetData(heur);
2998
2999 SCIPdebugMsg(scip, "Calling heurExecScheduler: depth %d sols %d inf %u node %lld \n",
3000 SCIPgetDepth(scip), SCIPgetNSols(scip), nodeinfeasible, SCIPgetNNodes(scip));
3001
3002 /* store diving heuristics if not done already and reset stats */
3003 if( heurdata->divingheurs == NULL )
3004 {
3005 SCIP_CALL( initRest(scip, heur) );
3006 }
3007 assert( heurdata->divingheurs != NULL );
3008
3009 *result = SCIP_DELAYED;
3010
3011 /* do not call heuristic in node that was already detected to be infeasible */
3012 if( nodeinfeasible )
3013 return SCIP_OKAY;
3014
3015 /* only call heuristic, if an optimal LP solution is at hand */
3017 return SCIP_OKAY;
3018
3019 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
3021 return SCIP_OKAY;
3022
3023 /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
3024 if( !SCIPisLPSolBasic(scip) )
3025 return SCIP_OKAY;
3026
3027 /* update internal incumbent solution */
3028 if( SCIPgetBestSol(scip) != heurdata->lastcallsol )
3029 {
3030 heurdata->lastcallsol = SCIPgetBestSol(scip);
3031 heurdata->firstcallthissol = SCIPheurGetNCalls(heur);
3032 }
3033
3034 /* do not run more than a user-defined number of times on each incumbent (-1: no limit) */
3035 if( heurdata->maxcallssamesol != -1 )
3036 {
3037 SCIP_Longint samesollimit;
3038
3039 /* either it is the user-defined limit or the number of heuristics controlled by the scheduler */
3040 samesollimit = (heurdata->maxcallssamesol > 0) ? heurdata->maxcallssamesol : (SCIP_Longint) heurdata->nneighborhoods + heurdata->ndiving;
3041
3042 if( SCIPheurGetNCalls(heur) - heurdata->firstcallthissol >= samesollimit )
3043 {
3044 SCIPdebugMsg(scip, "Heuristic already called %" SCIP_LONGINT_FORMAT " times on current incumbent\n", SCIPheurGetNCalls(heur) - heurdata->firstcallthissol);
3045 return SCIP_OKAY;
3046 }
3047 }
3048
3049 /* wait for a sufficient number of nodes since last incumbent solution */
3050 if( SCIPgetDepth(scip) > 0 && SCIPgetBestSol(scip) != NULL
3051 && (SCIPgetNNodes(scip) - SCIPsolGetNodenum(SCIPgetBestSol(scip))) < heurdata->waitingnodes )
3052 {
3053 SCIPdebugMsg(scip, "Waiting nodes not satisfied\n");
3054 return SCIP_OKAY;
3055 }
3056
3057 /* skip this call if scheduler was too unsuccessful in the past few calls */
3058 if( heurdata->nskippedcalls > 0 )
3059 {
3060 /* reduce counter because we need to skip one call less now */
3061 heurdata->nskippedcalls--;
3062
3063 return SCIP_OKAY;
3064 }
3065 else
3066 {
3067 /* check if we need to skip calls in the future */
3068 heurdata->nskippedcalls = (int) floor(exp(0.1 * (SCIP_Real) heurdata->nfailedcalls)) - 1;
3069 }
3070
3071 *result = SCIP_DIDNOTRUN;
3072 success = FALSE;
3073 {
3074 int selection;
3075 SCIP_Real reward;
3076 HEUR_STATS* stats;
3077 SCIP_STATUS subscipstatus;
3078
3079 subscipstatus = SCIP_STATUS_UNKNOWN;
3080
3081 /* allocate memory for statistics and initialize it */
3082 SCIP_CALL( SCIPallocBuffer(scip, &stats) );
3083 initRunStats(scip, stats);
3084
3085 /* select the heuristic based on previous success. The heuristics are sorted such that
3086 * diving comes before LNS */
3087 SCIP_CALL( selectHeuristic(scip, heurdata, &selection) );
3088
3089 /* execute selected heuristic */
3090 SCIP_CALL( executeHeuristic(scip, heur, selection, stats, &subscipstatus, result) );
3091
3092 /* update global statistics */
3093 if( selection < heurdata->ndiving ) /* diving was selected */
3094 updateHeurStatsDiving(stats, heurdata->divingheurs[selection]);
3095 else /* LNS was selected */
3096 updateHeurStatsLNS(stats, heurdata->neighborhoods[selection - heurdata->ndiving], &subscipstatus);
3097
3098 /* observe reward */
3099 reward = getReward(scip, heurdata, selection, stats);
3100
3101 /* call was successfull if solution was found */
3102 if( stats->nbestsolsfound > 0 )
3103 success = TRUE;
3104
3105 /* update either LP resolve freq or target fixing rate, depending on which heuristic was chosen */
3106 if( selection < heurdata->ndiving )
3107 {
3108 /* update resolve freq */
3109 updateSolveFreq(heurdata->divingheurs[selection], stats);
3110 }
3111 else
3112 {
3113 /* update target fixing rate */
3114 SCIPdebugMsg(scip, "Update fixing rate: %.2f\n", heurdata->neighborhoods[selection - heurdata->ndiving]->fixingrate.targetfixingrate);
3115 updateFixingRate(heurdata->neighborhoods[selection - heurdata->ndiving], subscipstatus, stats);
3116 SCIPdebugMsg(scip, "New fixing rate: %.2f\n", heurdata->neighborhoods[selection - heurdata->ndiving]->fixingrate.targetfixingrate);
3117 }
3118
3119 /* update selection strategy */
3120 SCIP_CALL( updateSelectionStrategy(scip, heurdata, reward, selection) );
3121
3122 /* free statistics data struct */
3123 SCIPfreeBuffer(scip, &stats);
3124 }
3125
3126 /* count how many consecutive failed calls we had */
3127 if( success )
3128 heurdata->nfailedcalls = 0;
3129 else
3130 heurdata->nfailedcalls++;
3131
3132 return SCIP_OKAY;
3133}
3134
3135/** callback to collect variable fixings of RENS */
3136static
3137DECL_VARFIXINGS(varFixingsRens)
3138{ /*lint --e{715}*/
3139 int nbinvars;
3140 int nintvars;
3141 SCIP_VAR** vars;
3142 int i;
3143 int *fracidx = NULL;
3144 SCIP_Real* frac = NULL;
3145 int nfracs;
3146
3147 assert(scip != NULL);
3148 assert(varbuf != NULL);
3149 assert(nfixings != NULL);
3150 assert(valbuf != NULL);
3151
3152 *result = SCIP_DELAYED;
3153
3154 if( ! SCIPhasCurrentNodeLP(scip) )
3155 return SCIP_OKAY;
3157 return SCIP_OKAY;
3158
3159 *result = SCIP_DIDNOTRUN;
3160
3161 /* get variable information */
3162 SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3163
3164 /* return if no binary or integer variables are present */
3165 if( nbinvars + nintvars == 0 )
3166 return SCIP_OKAY;
3167
3168 SCIP_CALL( SCIPallocBufferArray(scip, &fracidx, nbinvars + nintvars) );
3169 SCIP_CALL( SCIPallocBufferArray(scip, &frac, nbinvars + nintvars) );
3170
3171 /* loop over binary and integer variables; determine those that should be fixed in the sub-SCIP */
3172 for( nfracs = 0, i = 0; i < nbinvars + nintvars; ++i )
3173 {
3174 SCIP_VAR* var = vars[i];
3175 SCIP_Real lpsolval = SCIPvarGetLPSol(var);
3176 assert((i < nbinvars && SCIPvarIsBinary(var)) || (i >= nbinvars && SCIPvarIsIntegral(var)));
3177
3178 /* fix all binary and integer variables with integer LP solution value */
3179 if( SCIPisFeasIntegral(scip, lpsolval) )
3180 {
3181 tryAdd2variableBuffer(scip, var, lpsolval, varbuf, valbuf, nfixings, TRUE);
3182 }
3183 else
3184 {
3185 frac[nfracs] = SCIPfrac(scip, lpsolval);
3186 frac[nfracs] = MIN(frac[nfracs], 1.0 - frac[nfracs]);
3187 fracidx[nfracs++] = i;
3188 }
3189 }
3190
3191 /* do some additional fixing */
3192 if( *nfixings < neighborhood->fixingrate.targetfixingrate * (nbinvars + nintvars) && nfracs > 0 )
3193 {
3194 SCIPsortDownRealInt(frac, fracidx, nfracs);
3195
3196 /* prefer variables that are almost integer */
3197 for( i = 0; i < nfracs && *nfixings < neighborhood->fixingrate.targetfixingrate * (nbinvars + nintvars); i++ )
3198 {
3199 tryAdd2variableBuffer(scip, vars[fracidx[i]], SCIPround(scip, SCIPvarGetLPSol(vars[fracidx[i]])), varbuf, valbuf, nfixings, TRUE);
3200 }
3201 }
3202
3203 SCIPfreeBufferArray(scip, &frac);
3204 SCIPfreeBufferArray(scip, &fracidx);
3205
3206 *result = SCIP_SUCCESS;
3207
3208 return SCIP_OKAY;
3209}
3210
3211/** callback for RENS subproblem changes */
3212static
3213DECL_CHANGESUBSCIP(changeSubscipRens)
3214{ /*lint --e{715}*/
3215 SCIP_VAR** vars;
3216 int nintvars;
3217 int nbinvars;
3218 int i;
3219
3220 assert(SCIPhasCurrentNodeLP(sourcescip));
3221 assert(SCIPgetLPSolstat(sourcescip) == SCIP_LPSOLSTAT_OPTIMAL);
3222
3223 /* get variable information */
3224 SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3225
3226 /* restrict bounds of integer variables with fractional solution value */
3227 for( i = nbinvars; i < nbinvars + nintvars; ++i )
3228 {
3229 SCIP_VAR* var = vars[i];
3230 SCIP_Real lpsolval = SCIPgetSolVal(sourcescip, NULL, var);
3231
3232 if( subvars[i] == NULL )
3233 continue;
3234
3235 if( ! SCIPisFeasIntegral(sourcescip, lpsolval) )
3236 {
3237 SCIP_Real newlb = SCIPfloor(sourcescip, lpsolval);
3238 SCIP_Real newub = newlb + 1.0;
3239
3240 /* only count this as a domain change if the new lower and upper bound are a further restriction */
3241 if( newlb > SCIPvarGetLbGlobal(subvars[i]) + 0.5 || newub < SCIPvarGetUbGlobal(subvars[i]) - 0.5 )
3242 {
3243 SCIP_CALL( SCIPchgVarLbGlobal(targetscip, subvars[i], newlb) );
3244 SCIP_CALL( SCIPchgVarUbGlobal(targetscip, subvars[i], newub) );
3245 (*ndomchgs)++;
3246 }
3247 }
3248 }
3249
3250 *success = TRUE;
3251
3252 return SCIP_OKAY;
3253}
3254
3255/** collect fixings by matching solution values in a collection of solutions for all binary and integer variables,
3256 * or for a custom set of variables
3257 */
3258static
3260 SCIP* scip, /**< SCIP data structure */
3261 SCIP_SOL** sols, /**< array of 2 or more solutions. It is okay for the array to contain one element
3262 * equal to NULL to represent the current LP solution */
3263 int nsols, /**< number of solutions in the array */
3264 SCIP_VAR** vars, /**< variable array for which solution values must agree */
3265 int nvars, /**< number of variables, or -1 for all binary and integer variables */
3266 SCIP_VAR** varbuf, /**< buffer storage for variable fixings */
3267 SCIP_Real* valbuf, /**< buffer storage for fixing values */
3268 int* nfixings /**< pointer to store the number of fixings */
3269 )
3270{
3271 int v;
3272 int nbinintvars;
3273 SCIP_SOL* firstsol;
3274
3275 assert(scip != NULL);
3276 assert(sols != NULL);
3277 assert(nsols >= 2);
3278 assert(varbuf != NULL);
3279 assert(valbuf != NULL);
3280 assert(nfixings != NULL);
3281 assert(*nfixings == 0);
3282
3283 if( nvars == -1 || vars == NULL )
3284 {
3285 int nbinvars;
3286 int nintvars;
3287 SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3288 nbinintvars = nbinvars + nintvars;
3289 nvars = nbinintvars;
3290 }
3291 firstsol = sols[0];
3292 assert(nvars > 0);
3293
3294 /* loop over integer and binary variables and check if their solution values match in all solutions */
3295 for( v = 0; v < nvars; ++v )
3296 {
3297 SCIP_Real solval;
3298 SCIP_VAR* var;
3299 int s;
3300
3301 var = vars[v];
3302 assert((v < SCIPgetNBinVars(scip) && SCIPvarIsBinary(var)) || (v >= SCIPgetNBinVars(scip) && SCIPvarIsIntegral(var)));
3303 solval = SCIPgetSolVal(scip, firstsol, var);
3304
3305 /* determine if solution values match in all given solutions */
3306 for( s = 1; s < nsols; ++s )
3307 {
3308 SCIP_Real solval2 = SCIPgetSolVal(scip, sols[s], var);
3309 if( ! SCIPisEQ(scip, solval, solval2) )
3310 break;
3311 }
3312
3313 /* if we did not break early, all solutions agree on the solution value of this variable */
3314 if( s == nsols )
3315 {
3316 tryAdd2variableBuffer(scip, var, solval, varbuf, valbuf, nfixings, TRUE);
3317 }
3318 }
3319
3320 return SCIP_OKAY;
3321}
3322
3323/** callback to collect variable fixings of RINS */
3324static
3325DECL_VARFIXINGS(varFixingsRins)
3326{
3327 /*lint --e{715}*/
3328 int nbinvars;
3329 int nintvars;
3330 SCIP_VAR** vars;
3331 SCIP_SOL* incumbent;
3332 SCIP_SOL* sols[2];
3333 assert(scip != NULL);
3334 assert(varbuf != NULL);
3335 assert(nfixings != NULL);
3336 assert(valbuf != NULL);
3337
3338 *result = SCIP_DELAYED;
3339
3340 if( ! SCIPhasCurrentNodeLP(scip) )
3341 return SCIP_OKAY;
3343 return SCIP_OKAY;
3344
3345 *result = SCIP_DIDNOTRUN;
3346
3347 incumbent = SCIPgetBestSol(scip);
3348 if( incumbent == NULL )
3349 return SCIP_OKAY;
3350
3351 if( SCIPsolGetOrigin(incumbent) == SCIP_SOLORIGIN_ORIGINAL )
3352 return SCIP_OKAY;
3353
3354 /* get variable information */
3355 SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3356
3357 /* return if no binary or integer variables are present */
3358 if( nbinvars + nintvars == 0 )
3359 return SCIP_OKAY;
3360
3361 sols[0] = NULL;
3362 sols[1] = incumbent;
3363
3364 SCIP_CALL( fixMatchingSolutionValues(scip, sols, 2, vars, nbinvars + nintvars, varbuf, valbuf, nfixings) );
3365
3366 *result = SCIP_SUCCESS;
3367
3368 return SCIP_OKAY;
3369}
3370
3371/** initialization callback for crossover when a new problem is read */
3372static
3373DECL_NHINIT(nhInitCrossover)
3374{ /*lint --e{715}*/
3375 DATA_CROSSOVER* data;
3376
3377 data = neighborhood->data.crossover;
3378 assert(data != NULL);
3379
3380 if( data->rng != NULL )
3381 SCIPfreeRandom(scip, &data->rng);
3382
3383 data->selsol = NULL;
3384
3385 SCIP_CALL( SCIPcreateRandom(scip, &data->rng, CROSSOVERSEED + (unsigned int)SCIPgetNVars(scip), TRUE) );
3386
3387 return SCIP_OKAY;
3388}
3389
3390/** deinitialization callback for crossover when exiting a problem */
3391static
3392DECL_NHEXIT(nhExitCrossover)
3393{ /*lint --e{715}*/
3394 DATA_CROSSOVER* data;
3395 data = neighborhood->data.crossover;
3396
3397 assert(neighborhood != NULL);
3398 assert(data->rng != NULL);
3399
3400 SCIPfreeRandom(scip, &data->rng);
3401
3402 return SCIP_OKAY;
3403}
3404
3405/** deinitialization callback for crossover before SCIP is freed */
3406static
3407DECL_NHFREE(nhFreeCrossover)
3408{ /*lint --e{715}*/
3409 assert(neighborhood->data.crossover != NULL);
3410 SCIPfreeBlockMemory(scip, &neighborhood->data.crossover);
3411
3412 return SCIP_OKAY;
3413}
3414
3415/** callback to collect variable fixings of crossover */
3416static
3417DECL_VARFIXINGS(varFixingsCrossover)
3418{ /*lint --e{715}*/
3419 DATA_CROSSOVER* data;
3420 SCIP_RANDNUMGEN* rng;
3421 SCIP_SOL** sols;
3422 SCIP_SOL** scipsols;
3423 int nsols;
3424 int lastdraw;
3425 assert(scip != NULL);
3426 assert(varbuf != NULL);
3427 assert(nfixings != NULL);
3428 assert(valbuf != NULL);
3429
3430 data = neighborhood->data.crossover;
3431
3432 assert(data != NULL);
3433 nsols = data->nsols;
3434 data->selsol = NULL;
3435
3436 *result = SCIP_DIDNOTRUN;
3437
3438 /* return if the pool has not enough solutions */
3439 if( nsols > SCIPgetNSols(scip) )
3440 return SCIP_OKAY;
3441
3442 /* return if no binary or integer variables are present */
3444 return SCIP_OKAY;
3445
3446 rng = data->rng;
3447 lastdraw = SCIPgetNSols(scip);
3448 SCIP_CALL( SCIPallocBufferArray(scip, &sols, nsols) );
3449 scipsols = SCIPgetSols(scip);
3450
3451 /* draw as many solutions from the pool as required by crossover, biased towards
3452 * better solutions; therefore, the sorting of the solutions by objective is implicitly used
3453 */
3454 while( nsols > 0 )
3455 {
3456 /* no need for randomization anymore, exactly nsols many solutions remain for the selection */
3457 if( lastdraw == nsols )
3458 {
3459 int s;
3460
3461 /* fill the remaining slots 0,...,nsols - 1 by the solutions at the same places */
3462 for( s = 0; s < nsols; ++s )
3463 sols[s] = scipsols[s];
3464
3465 nsols = 0;
3466 }
3467 else
3468 {
3469 int nextdraw;
3470
3471 assert(nsols < lastdraw);
3472
3473 /* draw from the lastdraw - nsols many solutions nsols - 1, ... lastdraw - 1 such that nsols many solution */
3474 nextdraw = SCIPrandomGetInt(rng, nsols - 1, lastdraw - 1);
3475 assert(nextdraw >= 0);
3476
3477 sols[nsols - 1] = scipsols[nextdraw];
3478 nsols--;
3479 lastdraw = nextdraw;
3480 }
3481 }
3482
3483 SCIP_CALL( fixMatchingSolutionValues(scip, sols, data->nsols, NULL, -1, varbuf, valbuf, nfixings) );
3484
3485 /* store best selected solution as reference solution */
3486 data->selsol = sols[0];
3487 assert(data->selsol != NULL);
3488
3489 *result = SCIP_SUCCESS;
3490
3491 SCIPfreeBufferArray(scip, &sols);
3492
3493 return SCIP_OKAY;
3494}
3495
3496/** callback for crossover reference solution */
3497static
3498DECL_NHREFSOL(nhRefsolCrossover)
3499{ /*lint --e{715}*/
3500 DATA_CROSSOVER* data;
3501
3502 data = neighborhood->data.crossover;
3503
3504 if( data->selsol != NULL )
3505 {
3506 *solptr = data->selsol;
3507 *result = SCIP_SUCCESS;
3508 }
3509 else
3510 {
3511 *result = SCIP_DIDNOTFIND;
3512 }
3513
3514 return SCIP_OKAY;
3515}
3516
3517/** initialization callback for mutation when a new problem is read */
3518static
3519DECL_NHINIT(nhInitMutation)
3520{ /*lint --e{715}*/
3521 DATA_MUTATION* data;
3522 assert(scip != NULL);
3523 assert(neighborhood != NULL);
3524
3525 SCIP_CALL( SCIPallocBlockMemory(scip, &neighborhood->data.mutation) );
3526
3527 data = neighborhood->data.mutation;
3528 assert(data != NULL);
3529
3530 SCIP_CALL( SCIPcreateRandom(scip, &data->rng, MUTATIONSEED + (unsigned int)SCIPgetNVars(scip), TRUE) );
3531
3532 return SCIP_OKAY;
3533}
3534
3535/** deinitialization callback for mutation when exiting a problem */
3536static
3537DECL_NHEXIT(nhExitMutation)
3538{ /*lint --e{715}*/
3539 DATA_MUTATION* data;
3540 assert(scip != NULL);
3541 assert(neighborhood != NULL);
3542 data = neighborhood->data.mutation;
3543 assert(data != NULL);
3544
3545 SCIPfreeRandom(scip, &data->rng);
3546
3547 SCIPfreeBlockMemory(scip, &neighborhood->data.mutation);
3548
3549 return SCIP_OKAY;
3550}
3551
3552/** callback to collect variable fixings of mutation */
3553static
3554DECL_VARFIXINGS(varFixingsMutation)
3555{ /*lint --e{715}*/
3556 SCIP_RANDNUMGEN* rng;
3557
3558 SCIP_VAR** vars;
3559 SCIP_VAR** varscpy;
3560 int i;
3561 int nvars;
3562 int nbinvars;
3563 int nintvars;
3564 int nbinintvars;
3565 int ntargetfixings;
3566 SCIP_SOL* incumbentsol;
3567 SCIP_Real targetfixingrate;
3568
3569 assert(scip != NULL);
3570 assert(neighborhood != NULL);
3571 assert(neighborhood->data.mutation != NULL);
3572 assert(neighborhood->data.mutation->rng != NULL);
3573 rng = neighborhood->data.mutation->rng;
3574
3575 *result = SCIP_DIDNOTRUN;
3576
3577 /* get the problem variables */
3578 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
3579
3580 nbinintvars = nbinvars + nintvars;
3581 if( nbinintvars == 0 )
3582 return SCIP_OKAY;
3583
3584 incumbentsol = SCIPgetBestSol(scip);
3585 if( incumbentsol == NULL )
3586 return SCIP_OKAY;
3587
3588 targetfixingrate = neighborhood->fixingrate.targetfixingrate;
3589 ntargetfixings = (int)(targetfixingrate * nbinintvars) + 1;
3590
3591 /* don't continue if number of discrete variables is too small to reach target fixing rate */
3592 if( nbinintvars <= ntargetfixings )
3593 return SCIP_OKAY;
3594
3595 *result = SCIP_DIDNOTFIND;
3596
3597 /* copy variables into a buffer array */
3598 SCIP_CALL( SCIPduplicateBufferArray(scip, &varscpy, vars, nbinintvars) );
3599
3600 /* partially perturb the array until the number of target fixings is reached */
3601 for( i = 0; *nfixings < ntargetfixings && i < nbinintvars; ++i )
3602 {
3603 int randint = SCIPrandomGetInt(rng, i, nbinintvars - 1);
3604 assert(randint < nbinintvars);
3605
3606 if( randint > i )
3607 {
3608 SCIPswapPointers((void**)&varscpy[i], (void**)&varscpy[randint]);
3609 }
3610 /* copy the selected variables and their solution values into the buffer */
3611 tryAdd2variableBuffer(scip, varscpy[i], SCIPgetSolVal(scip, incumbentsol, varscpy[i]), varbuf, valbuf, nfixings, TRUE);
3612 }
3613
3614 assert(i == nbinintvars || *nfixings == ntargetfixings);
3615
3616 /* Not reaching the number of target fixings means that there is a significant fraction (at least 1 - targetfixingrate)
3617 * of variables for which the incumbent solution value does not lie within the global bounds anymore. This is a nonsuccess
3618 * for the neighborhood (additional fixings are not possible), which is okay because the incumbent solution is
3619 * significantly outdated
3620 */
3621 if( *nfixings == ntargetfixings )
3622 *result = SCIP_SUCCESS;
3623
3624 /* free the buffer array */
3625 SCIPfreeBufferArray(scip, &varscpy);
3626
3627 return SCIP_OKAY;
3628}
3629
3630/** add local branching constraint */
3631static
3633 SCIP* sourcescip, /**< source SCIP data structure */
3634 SCIP* targetscip, /**< target SCIP data structure */
3635 SCIP_VAR** subvars, /**< array of sub SCIP variables in same order as source SCIP variables */
3636 int distance, /**< right hand side of the local branching constraint */
3637 SCIP_Bool* success, /**< pointer to store of a local branching constraint has been successfully added */
3638 int* naddedconss /**< pointer to increase the number of added constraints */
3639 )
3640{
3641 int nbinvars;
3642 int i;
3643 SCIP_SOL* referencesol;
3644 SCIP_CONS* localbranchcons;
3645 SCIP_VAR** vars;
3646 SCIP_Real* consvals;
3647 SCIP_Real rhs;
3648
3649 assert(sourcescip != NULL);
3650 assert(*success == FALSE);
3651
3652 nbinvars = SCIPgetNBinVars(sourcescip);
3653 vars = SCIPgetVars(sourcescip);
3654
3655 if( nbinvars <= 3 )
3656 return SCIP_OKAY;
3657
3658 referencesol = SCIPgetBestSol(sourcescip);
3659 if( referencesol == NULL )
3660 return SCIP_OKAY;
3661
3662 rhs = (SCIP_Real)distance;
3663 rhs = MAX(rhs, 2.0);
3664
3665 SCIP_CALL( SCIPallocBufferArray(sourcescip, &consvals, nbinvars) );
3666
3667 /* loop over binary variables and fill the local branching constraint */
3668 for( i = 0; i < nbinvars; ++i )
3669 {
3670 /* skip variables that are not present in sub-SCIP */
3671 if( subvars[i] == NULL )
3672 continue;
3673
3674 if( SCIPisEQ(sourcescip, SCIPgetSolVal(sourcescip, referencesol, vars[i]), 0.0) )
3675 consvals[i] = 1.0;
3676 else
3677 {
3678 consvals[i] = -1.0;
3679 rhs -= 1.0;
3680 }
3681 }
3682
3683 /* create the local branching constraint in the target scip */
3684 SCIP_CALL( SCIPcreateConsBasicLinear(targetscip, &localbranchcons, "localbranch", nbinvars, subvars, consvals, -SCIPinfinity(sourcescip), rhs) );
3685 SCIP_CALL( SCIPaddCons(targetscip, localbranchcons) );
3686 SCIP_CALL( SCIPreleaseCons(targetscip, &localbranchcons) );
3687
3688 *naddedconss = 1;
3689 *success = TRUE;
3690
3691 SCIPfreeBufferArray(sourcescip, &consvals);
3692
3693 return SCIP_OKAY;
3694}
3695
3696/** callback for local branching subproblem changes */
3697static
3698DECL_CHANGESUBSCIP(changeSubscipLocalbranching)
3699{ /*lint --e{715}*/
3700
3701 SCIP_CALL( addLocalBranchingConstraint(sourcescip, targetscip, subvars, (int)(0.2 * SCIPgetNBinVars(sourcescip)), success, naddedconss) );
3702
3703 return SCIP_OKAY;
3704}
3705
3706/** callback for proximity subproblem changes */
3707static
3708DECL_CHANGESUBSCIP(changeSubscipProximity)
3709{ /*lint --e{715}*/
3710 SCIP_SOL* referencesol;
3711 SCIP_VAR** vars;
3712 int nbinvars;
3713 int nintvars;
3714 int nvars;
3715 int i;
3716
3717 SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
3718
3719 if( nbinvars == 0 )
3720 return SCIP_OKAY;
3721
3722 referencesol = SCIPgetBestSol(sourcescip);
3723 if( referencesol == NULL )
3724 return SCIP_OKAY;
3725
3726 /* loop over binary variables, set objective coefficients based on reference solution in a local branching fashion */
3727 for( i = 0; i < nbinvars; ++i )
3728 {
3729 SCIP_Real newobj;
3730
3731 /* skip variables not present in sub-SCIP */
3732 if( subvars[i] == NULL )
3733 continue;
3734
3735 if( SCIPgetSolVal(sourcescip, referencesol, vars[i]) < 0.5 )
3736 newobj = -1.0;
3737 else
3738 newobj = 1.0;
3739 SCIP_CALL( SCIPchgVarObj(targetscip, subvars[i], newobj) );
3740 }
3741
3742 /* loop over the remaining variables and change their objective coefficients to 0 */
3743 for( ; i < nvars; ++i )
3744 {
3745 /* skip variables not present in sub-SCIP */
3746 if( subvars[i] == NULL )
3747 continue;
3748
3749 SCIP_CALL( SCIPchgVarObj(targetscip, subvars[i], 0.0) );
3750 }
3751
3752 *nchgobjs = nvars;
3753 *success = TRUE;
3754
3755 return SCIP_OKAY;
3756}
3757
3758/** callback for zeroobjective subproblem changes */
3759static
3760DECL_CHANGESUBSCIP(changeSubscipZeroobjective)
3761{ /*lint --e{715}*/
3762 SCIP_CONSHDLR* conshdlrnl;
3763 SCIP_VAR** vars;
3764 int nvars;
3765 int i;
3766
3767 assert(*success == FALSE);
3768
3769 SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, &nvars, NULL, NULL, NULL, NULL) );
3770
3771 /* do not run if no objective variables are present */
3772 if( SCIPgetNObjVars(sourcescip) == 0 )
3773 return SCIP_OKAY;
3774
3775 /* zeroobj may trigger fixing objvar in nonlinear constraint to infinity,
3776 * which expr_var.c:simplify cannot handle at the moment; also #3273
3777 */
3778 conshdlrnl = SCIPfindConshdlr(sourcescip, "nonlinear");
3779 if( conshdlrnl != NULL && SCIPconshdlrGetNActiveConss(conshdlrnl) > 0 )
3780 return SCIP_OKAY;
3781
3782 /* loop over the variables and change their objective coefficients to 0 */
3783 for( i = 0; i < nvars; ++i )
3784 {
3785 /* skip variables not present in sub-SCIP */
3786 if( subvars[i] == NULL )
3787 continue;
3788
3789 SCIP_CALL( SCIPchgVarObj(targetscip, subvars[i], 0.0) );
3790 }
3791
3792 *nchgobjs = nvars;
3793 *success = TRUE;
3794
3795 return SCIP_OKAY;
3796}
3797
3798/** compute tightened bounds for integer variables depending on how much the LP and the incumbent solution values differ */
3799static
3801 SCIP* scip, /**< SCIP data structure of the original problem */
3802 SCIP_VAR* var, /**< the variable for which bounds should be computed */
3803 SCIP_Real* lbptr, /**< pointer to store the lower bound in the DINS sub-SCIP */
3804 SCIP_Real* ubptr /**< pointer to store the upper bound in the DINS sub-SCIP */
3805 )
3806{
3807 SCIP_Real mipsol;
3808 SCIP_Real lpsol;
3809
3810 SCIP_Real lbglobal;
3811 SCIP_Real ubglobal;
3812 SCIP_SOL* bestsol;
3813
3814 /* get the bounds for each variable */
3815 lbglobal = SCIPvarGetLbGlobal(var);
3816 ubglobal = SCIPvarGetUbGlobal(var);
3817
3819 /* get the current LP solution for each variable */
3820 lpsol = SCIPvarGetLPSol(var);
3821
3822 /* get the current MIP solution for each variable */
3823 bestsol = SCIPgetBestSol(scip);
3824 mipsol = SCIPgetSolVal(scip, bestsol, var);
3825
3826 /* if the solution values differ by 0.5 or more, the variable is rebounded, otherwise it is just copied */
3827 if( REALABS(lpsol - mipsol) >= 0.5 )
3828 {
3829 SCIP_Real range;
3830
3831 *lbptr = lbglobal;
3832 *ubptr = ubglobal;
3833
3834 /* create an equally sized range around lpsol for general integers: bounds are lpsol +- (mipsol-lpsol) */
3835 range = 2 * lpsol - mipsol;
3836
3837 if( mipsol >= lpsol )
3838 {
3839 range = SCIPfeasCeil(scip, range);
3840 *lbptr = MAX(*lbptr, range);
3841
3842 /* when the bound new upper bound is equal to the current MIP solution, we set both bounds to the integral bound (without eps) */
3843 if( SCIPisFeasEQ(scip, mipsol, *lbptr) )
3844 *ubptr = *lbptr;
3845 else
3846 *ubptr = mipsol;
3847 }
3848 else
3849 {
3850 range = SCIPfeasFloor(scip, range);
3851 *ubptr = MIN(*ubptr, range);
3852
3853 /* when the bound new upper bound is equal to the current MIP solution, we set both bounds to the integral bound (without eps) */
3854 if( SCIPisFeasEQ(scip, mipsol, *ubptr) )
3855 *lbptr = *ubptr;
3856 else
3857 *lbptr = mipsol;
3858 }
3859
3860 /* the global domain of variables might have been reduced since incumbent was found: adjust lb and ub accordingly */
3861 *lbptr = MAX(*lbptr, lbglobal);
3862 *ubptr = MIN(*ubptr, ubglobal);
3863 }
3864 else
3865 {
3866 /* the global domain of variables might have been reduced since incumbent was found: adjust it accordingly */
3867 *lbptr = MAX(mipsol, lbglobal);
3868 *ubptr = MIN(mipsol, ubglobal);
3869 }
3870}
3871
3872/** callback to collect variable fixings of DINS */
3873static
3874DECL_VARFIXINGS(varFixingsDins)
3875{
3876 DATA_DINS* data;
3877 SCIP_SOL* rootlpsol;
3878 SCIP_SOL** sols;
3879 int nsols;
3880 int nmipsols;
3881 int nbinvars;
3882 int nintvars;
3883 SCIP_VAR** vars;
3884 int v;
3885
3886 data = neighborhood->data.dins;
3887 assert(data != NULL);
3888 nmipsols = SCIPgetNSols(scip);
3889 nmipsols = MIN(nmipsols, data->npoolsols);
3890
3891 *result = SCIP_DELAYED;
3892
3894 return SCIP_OKAY;
3895
3896 *result = SCIP_DIDNOTRUN;
3897
3898 if( nmipsols == 0 )
3899 return SCIP_OKAY;
3900
3901 SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3902
3903 if( nbinvars + nintvars == 0 )
3904 return SCIP_OKAY;
3905
3906 SCIP_CALL( SCIPcreateSol(scip, &rootlpsol, NULL) );
3907
3908 /* save root solution LP values in solution */
3909 for( v = 0; v < nbinvars + nintvars; ++v )
3910 {
3911 SCIP_CALL( SCIPsetSolVal(scip, rootlpsol, vars[v], SCIPvarGetRootSol(vars[v])) );
3912 }
3913
3914 /* add the node and the root LP solution */
3915 nsols = nmipsols + 2;
3916
3917 SCIP_CALL( SCIPallocBufferArray(scip, &sols, nsols) );
3918 sols[0] = NULL; /* node LP solution */
3919 sols[1] = rootlpsol;
3920
3921 /* copy the remaining MIP solutions after the LP solutions */
3922 BMScopyMemoryArray(&sols[2], SCIPgetSols(scip), nmipsols); /*lint !e866*/
3923
3924 /* 1. Binary variables are fixed if their values agree in all the solutions */
3925 if( nbinvars > 0 )
3926 {
3927 SCIP_CALL( fixMatchingSolutionValues(scip, sols, nsols, vars, nbinvars, varbuf, valbuf, nfixings) );
3928 }
3929
3930 /* 2. Integer variables are fixed if they have a very low distance between the incumbent and the root LP solution */
3931 for( v = nbinvars; v < nintvars; ++v )
3932 {
3933 SCIP_Real lb;
3934 SCIP_Real ub;
3935 computeIntegerVariableBoundsDins(scip, vars[v], &lb, &ub);
3936
3937 if( ub - lb < 0.5 )
3938 {
3939 assert(SCIPisFeasIntegral(scip, lb));
3940 tryAdd2variableBuffer(scip, vars[v], lb, varbuf, valbuf, nfixings, TRUE);
3941 }
3942 }
3943
3944 *result = SCIP_SUCCESS;
3945
3946 SCIPfreeBufferArray(scip, &sols);
3947
3948 SCIP_CALL( SCIPfreeSol(scip, &rootlpsol) );
3949
3950 return SCIP_OKAY;
3951}
3952
3953/** callback for DINS subproblem changes */
3954static
3955DECL_CHANGESUBSCIP(changeSubscipDins)
3956{ /*lint --e{715}*/
3957 SCIP_VAR** vars;
3958 int nintvars;
3959 int nbinvars;
3960 int v;
3961
3962 SCIP_CALL( SCIPgetVarsData(sourcescip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
3963
3964 /* 1. loop over integer variables and tighten the bounds */
3965 for( v = nbinvars; v < nintvars; ++v )
3966 {
3967 SCIP_Real lb;
3968 SCIP_Real ub;
3969
3970 /* skip variables not present in sub-SCIP */
3971 if( subvars[v] == NULL )
3972 continue;
3973
3974 computeIntegerVariableBoundsDins(sourcescip, vars[v], &lb, &ub);
3975
3976 SCIP_CALL( SCIPchgVarLbGlobal(targetscip, subvars[v], lb) );
3977 SCIP_CALL( SCIPchgVarUbGlobal(targetscip, subvars[v], ub) );
3978 ++(*ndomchgs);
3979 }
3980
3981 /* 2. add local branching constraint for binary variables */
3982 SCIP_CALL( addLocalBranchingConstraint(sourcescip, targetscip, subvars, (int)(0.1 * SCIPgetNBinVars(sourcescip)), success, naddedconss) );
3983
3984 *success = TRUE;
3985
3986 return SCIP_OKAY;
3987}
3988
3989/** deinitialization callback for DINS before SCIP is freed */
3990static
3991DECL_NHFREE(nhFreeDins)
3992{
3993 assert(neighborhood->data.dins != NULL);
3994
3995 SCIPfreeBlockMemory(scip, &neighborhood->data.dins);
3996
3997 return SCIP_OKAY;
3998}
3999
4000/** deinitialization callback for trustregion before SCIP is freed */
4001static
4002DECL_NHFREE(nhFreeTrustregion)
4003{
4004 assert(neighborhood->data.trustregion != NULL);
4005
4006 SCIPfreeBlockMemory(scip, &neighborhood->data.trustregion);
4007
4008 return SCIP_OKAY;
4009}
4010
4011/** add trust region neighborhood constraint and auxiliary objective variable */
4012static
4013DECL_CHANGESUBSCIP(changeSubscipTrustregion)
4014{ /*lint --e{715}*/
4015 DATA_TRUSTREGION* data;
4016
4017 data = neighborhood->data.trustregion;
4018
4019 /* adding the neighborhood constraint for the trust region heuristic */
4020 SCIP_CALL( SCIPaddTrustregionNeighborhoodConstraint(sourcescip, targetscip, subvars, data->violpenalty) );
4021
4022 /* incrementing the change in objective since an additional variable is added to the objective to penalize the
4023 * violation of the trust region.
4024 */
4025 ++(*nchgobjs);
4026
4027 return SCIP_OKAY;
4028}
4029
4030/** callback that returns the incumbent solution as a reference point */
4031static
4032DECL_NHREFSOL(nhRefsolIncumbent)
4033{ /*lint --e{715}*/
4034 assert(scip != NULL);
4035
4036 if( SCIPgetBestSol(scip) != NULL )
4037 {
4038 *result = SCIP_SUCCESS;
4039 *solptr = SCIPgetBestSol(scip);
4040 }
4041 else
4042 {
4043 *result = SCIP_DIDNOTFIND;
4044 }
4045
4046 return SCIP_OKAY;
4047}
4048
4049
4050/** callback function that deactivates a neighborhood on problems with no discrete variables */
4051static
4052DECL_NHDEACTIVATE(nhDeactivateDiscreteVars)
4053{ /*lint --e{715}*/
4054 assert(scip != NULL);
4055 assert(deactivate != NULL);
4056
4057 /* deactivate if no discrete variables are present */
4058 *deactivate = (SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0);
4059
4060 return SCIP_OKAY;
4061}
4062
4063/** callback function that deactivates a neighborhood on problems with no binary variables */
4064static
4065DECL_NHDEACTIVATE(nhDeactivateBinVars)
4066{ /*lint --e{715}*/
4067 assert(scip != NULL);
4068 assert(deactivate != NULL);
4069
4070 /* deactivate if no discrete variables are present */
4071 *deactivate = (SCIPgetNBinVars(scip) == 0);
4072
4073 return SCIP_OKAY;
4074}
4075
4076/** callback function that deactivates a neighborhood on problems with no objective variables */
4077static
4078DECL_NHDEACTIVATE(nhDeactivateObjVars)
4079{ /*lint --e{715}*/
4080 assert(scip != NULL);
4081 assert(deactivate != NULL);
4082
4083 /* deactivate if no discrete variables are present */
4084 *deactivate = (SCIPgetNObjVars(scip) == 0);
4085
4086 return SCIP_OKAY;
4087}
4088
4089
4090/** include all neighborhoods */
4091static
4093 SCIP* scip, /**< SCIP data structure */
4094 SCIP_HEURDATA* heurdata /**< heuristic data of the scheduler heuristic */
4095 )
4096{
4097 NH* rens;
4098 NH* rins;
4099 NH* mutation;
4100 NH* localbranching;
4101 NH* crossover;
4102 NH* proximity;
4103 NH* zeroobjective;
4104 NH* dins;
4105 NH* trustregion;
4106
4107 heurdata->nneighborhoods = 0;
4108
4109 /* include the RENS neighborhood */
4110 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &rens, "rens",
4112 varFixingsRens, changeSubscipRens, NULL, NULL, NULL, NULL, nhDeactivateDiscreteVars) );
4113
4114 /* include the RINS neighborhood */
4115 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &rins, "rins",
4117 varFixingsRins, NULL, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateDiscreteVars) );
4118
4119 /* include the mutation neighborhood */
4120 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &mutation, "mutation",
4122 varFixingsMutation, NULL, nhInitMutation, nhExitMutation, NULL, nhRefsolIncumbent, nhDeactivateDiscreteVars) );
4123
4124 /* include the local branching neighborhood */
4125 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &localbranching, "localbranching",
4127 NULL, changeSubscipLocalbranching, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateBinVars) );
4128
4129 /* include the crossover neighborhood */
4130 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &crossover, "crossover",
4132 varFixingsCrossover, NULL,
4133 nhInitCrossover, nhExitCrossover, nhFreeCrossover, nhRefsolCrossover, nhDeactivateDiscreteVars) );
4134
4135 /* allocate data for crossover to include the parameter */
4137 crossover->data.crossover->rng = NULL;
4138
4139 /* add crossover neighborhood parameters */
4140 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/scheduler/crossover/nsols", "the number of solutions that crossover should combine",
4141 &crossover->data.crossover->nsols, TRUE, DEFAULT_NSOLS_CROSSOVER, 2, 10, NULL, NULL) );
4142
4143 /* include the Proximity neighborhood */
4144 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &proximity, "proximity",
4146 NULL, changeSubscipProximity, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateBinVars) );
4147
4148 /* include the Zeroobjective neighborhood */
4149 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &zeroobjective, "zeroobjective",
4151 NULL, changeSubscipZeroobjective, NULL, NULL, NULL, nhRefsolIncumbent, nhDeactivateObjVars) );
4152
4153 /* include the DINS neighborhood */
4154 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &dins, "dins",
4156 varFixingsDins, changeSubscipDins, NULL, NULL, nhFreeDins, nhRefsolIncumbent, nhDeactivateBinVars) );
4157
4158 /* allocate data for DINS to include the parameter */
4160
4161 /* add DINS neighborhood parameters */
4162 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/scheduler/dins/npoolsols",
4163 "number of pool solutions where binary solution values must agree",
4164 &dins->data.dins->npoolsols, TRUE, DEFAULT_NPOOLSOLS_DINS, 1, 100, NULL, NULL) );
4165
4166 /* include the trustregion neighborhood */
4167 SCIP_CALL( schedulerIncludeNeighborhood(scip, heurdata, &trustregion, "trustregion",
4169 NULL, changeSubscipTrustregion, NULL, NULL, nhFreeTrustregion, nhRefsolIncumbent, nhDeactivateBinVars) );
4170
4171 /* allocate data for trustregion to include the parameter */
4173
4174 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/trustregion/violpenalty",
4175 "the penalty for each change in the binary variables from the candidate solution",
4177
4178 return SCIP_OKAY;
4179}
4180
4181/** initialization method of primal heuristic (called after problem was transformed) */
4182static
4183SCIP_DECL_HEURINIT(heurInitScheduler)
4184{ /*lint --e{715}*/
4185 SCIP_HEURDATA* heurdata;
4186 int i;
4187
4188 assert(scip != NULL);
4189 assert(heur != NULL);
4190
4191 heurdata = SCIPheurGetData(heur);
4192 assert(heurdata != NULL);
4193
4194 /* reactivate all neighborhoods if a new problem is read in */
4195 heurdata->nactiveneighborhoods = heurdata->nneighborhoods;
4196
4197 /* initialize neighborhoods for new problem */
4198 for( i = 0; i < heurdata->nneighborhoods; ++i )
4199 {
4200 NH* neighborhood = heurdata->neighborhoods[i];
4201
4202 SCIP_CALL( neighborhoodInit(scip, neighborhood) );
4203
4204 SCIP_CALL( resetFixingRate(scip, &neighborhood->fixingrate) );
4205
4206 SCIP_CALL( heurStatsReset(scip, &neighborhood->stats, FALSE) );
4207 }
4208
4209 /* we clear the list of collected diving heuristics to ensure reproducability and consistent state across multiple runs
4210 * within the same SCIP data structure */
4211 /* note: diving heuristics data will be initialized when executing scheduler */
4212 if( heurdata->divingheurs != NULL )
4213 {
4214 int j;
4215
4216 for( j = 0; j < heurdata->ndiving; ++j )
4217 {
4218 SCIP_CALL( schedulerFreeDivingHeur(scip, &(heurdata->divingheurs[j])) );
4219 }
4220
4221 SCIPfreeBlockMemoryArray(scip, &heurdata->divingheurs, heurdata->divingheurssize);
4222
4223 if( heurdata->defaultroot )
4224 SCIPfreeBlockMemoryArray(scip, &heurdata->sortedindices, heurdata->ndiving + heurdata->nneighborhoods);
4225 }
4226
4227 /* create working solution */
4228 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
4229
4230 return SCIP_OKAY;
4231}
4232
4233
4234/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
4235static
4236SCIP_DECL_HEURINITSOL(heurInitsolScheduler)
4237{ /*lint --e{715}*/
4238 SCIP_HEURDATA* heurdata;
4239 int i;
4240 SCIP_Real* priorities;
4241 unsigned int initseed;
4242
4243 assert(scip != NULL);
4244 assert(heur != NULL);
4245
4246 heurdata = SCIPheurGetData(heur);
4247 assert(heurdata != NULL);
4248 heurdata->nactiveneighborhoods = heurdata->nneighborhoods;
4249
4250 SCIP_CALL( SCIPallocBufferArray(scip, &priorities, heurdata->ndiving + heurdata->nactiveneighborhoods) );
4251
4252 /* init neighborhoods for new problem by resetting their statistics and fixing rate */
4253 for( i = heurdata->nneighborhoods - 1; i >= 0; --i )
4254 {
4255 NH* neighborhood = heurdata->neighborhoods[i];
4256 SCIP_Bool deactivate;
4257
4258 SCIP_CALL( neighborhood->nhdeactivate(scip, &deactivate) );
4259
4260 /* disable inactive neighborhoods */
4261 if( deactivate || ! neighborhood->active )
4262 {
4263 if( heurdata->nactiveneighborhoods - 1 > i )
4264 {
4265 assert(heurdata->neighborhoods[heurdata->nactiveneighborhoods - 1]->active);
4266 SCIPswapPointers((void **)&heurdata->neighborhoods[i], (void **)&heurdata->neighborhoods[heurdata->nactiveneighborhoods - 1]);
4267 }
4268 heurdata->nactiveneighborhoods--;
4269 }
4270 }
4271
4272 /* if diving is already initialized (only happens after all diving heuristics are initialized),
4273 * take the proper priorities. Otherwise, set all priorities to 1.0 */
4274 if( heurdata->divingheurs != NULL )
4275 {
4276 /* collect diving heuristic priorities */
4277 for( i = 0; i < heurdata->ndiving; ++i )
4278 priorities[i] = heurdata->divingheurs[i]->priority;
4279
4280 /* collect neighborhood priorities */
4281 for( i = 0; i < heurdata->nactiveneighborhoods; ++i )
4282 priorities[i + heurdata->ndiving] = heurdata->neighborhoods[i]->priority;
4283 }
4284 else
4285 {
4286 for( i = 0; i < heurdata->ndiving + heurdata->nactiveneighborhoods; ++i )
4287 priorities[i] = 1.0;
4288 }
4289
4290 initseed = (unsigned int)(heurdata->seed + SCIPgetNVars(scip));
4291
4292 /* active neighborhoods might change between init calls, reset functionality must take this into account */
4293 if( heurdata->bandit != NULL && SCIPbanditGetNActions(heurdata->bandit) != heurdata->ndiving + heurdata->nactiveneighborhoods )
4294 {
4295 SCIP_CALL( SCIPfreeBandit(scip, &heurdata->bandit) );
4296 heurdata->bandit = NULL;
4297
4298 /* since the number of active heursitics has changed, we have to update
4299 * how heuristics are sorted by priority, if we already initialized the data */
4300 if( heurdata->divingheurs != NULL )
4301 {
4302 SCIP_Real* initpriorities;
4303 int nheurs;
4304
4305 nheurs = heurdata->nactiveneighborhoods + heurdata->ndiving;
4306 SCIP_CALL( SCIPallocBufferArray(scip, &initpriorities, nheurs) );
4307 heurdata->counter = 0;
4308
4309 for( i = 0; i < nheurs; ++i )
4310 {
4311 heurdata->sortedindices[i] = i;
4312
4313 if( i < heurdata->ndiving )
4314 initpriorities[i] = (SCIP_Real)-heurdata->divingheurs[i]->rootnodepriority;
4315 else
4316 initpriorities[i] = (SCIP_Real)-heurdata->neighborhoods[i - heurdata->ndiving]->rootnodepriority;
4317 }
4318
4319 SCIPsortRealInt(initpriorities, heurdata->sortedindices, nheurs);
4320
4321 SCIPfreeBufferArray(scip, &initpriorities);
4322 }
4323 }
4324
4325 if( heurdata->nactiveneighborhoods + heurdata->ndiving > 0 )
4326 { /* create or reset bandit algorithm */
4327 if( heurdata->bandit == NULL )
4328 {
4329 SCIP_CALL( createBandit(scip, heurdata, priorities, initseed) );
4330 resetTargetNodeLimit(heurdata);
4331 }
4332 else if( heurdata->resetweights )
4333 {
4334 SCIP_CALL( SCIPresetBandit(scip, heurdata->bandit, priorities, initseed) );
4335 resetTargetNodeLimit(heurdata);
4336 }
4337 }
4338
4339 /* TODO: maybe do something for diving as well here? */
4340 heurdata->usednodes = 0;
4341 heurdata->ninitneighborhoods = heurdata->nactiveneighborhoods;
4342
4343 heurdata->lastcallsol = NULL;
4344 heurdata->firstcallthissol = 0;
4345
4346 resetCurrentNeighborhood(heurdata);
4347
4348 SCIPfreeBufferArray(scip, &priorities);
4349
4350 return SCIP_OKAY;
4351}
4352
4353
4354/** deinitialization method of primal heuristic (called before transformed problem is freed) */
4355static
4356SCIP_DECL_HEUREXIT(heurExitScheduler)
4357{ /*lint --e{715}*/
4358 SCIP_HEURDATA* heurdata;
4359 int i;
4360
4361 assert(scip != NULL);
4362 assert(heur != NULL);
4363
4364 heurdata = SCIPheurGetData(heur);
4365 assert(heurdata != NULL);
4366
4367 /* free neighborhood specific data */
4368 for( i = 0; i < heurdata->nneighborhoods; ++i )
4369 {
4370 NH* neighborhood = heurdata->neighborhoods[i];
4371
4372 SCIP_CALL( neighborhoodExit(scip, neighborhood) );
4373 }
4374
4375 /* free working solution */
4376 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
4377
4378 return SCIP_OKAY;
4379}
4380
4381/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
4382static
4383SCIP_DECL_HEURFREE(heurFreeScheduler)
4384{ /*lint --e{715}*/
4385 SCIP_HEURDATA* heurdata;
4386 int i;
4387
4388 assert(scip != NULL);
4389 assert(heur != NULL);
4390
4391 heurdata = SCIPheurGetData(heur);
4392 assert(heurdata != NULL);
4393
4394 /* bandits are only initialized if a problem has been read */
4395 if( heurdata->bandit != NULL )
4396 {
4397 SCIP_CALL( SCIPfreeBandit(scip, &heurdata->bandit) );
4398 }
4399
4400 /* free diving heuristics */
4401 if( heurdata->divingheurs != NULL )
4402 {
4403 int j;
4404
4405 for( j = 0; j < heurdata->ndiving; ++j )
4406 {
4407 SCIP_CALL( schedulerFreeDivingHeur(scip, &(heurdata->divingheurs[j])) );
4408 }
4409
4410 SCIPfreeBlockMemoryArray(scip, &heurdata->divingheurs, heurdata->divingheurssize);
4411
4412 if( heurdata->defaultroot )
4413 SCIPfreeBlockMemoryArray(scip, &heurdata->sortedindices, heurdata->ndiving + heurdata->nneighborhoods);
4414 }
4415
4416 /* free neighborhoods */
4417 for( i = 0; i < heurdata->nneighborhoods; ++i )
4418 {
4419 SCIP_CALL( schedulerFreeNeighborhood(scip, &(heurdata->neighborhoods[i])) );
4420 }
4421
4422 SCIPfreeBlockMemoryArray(scip, &heurdata->neighborhoods, NNEIGHBORHOODS);
4423
4424 SCIPfreeBlockMemory(scip, &heurdata);
4425
4426 return SCIP_OKAY;
4427}
4428
4429/** output method of statistics table to output file stream 'file' */
4430static
4431SCIP_DECL_TABLEOUTPUT(tableOutputNeighborhood)
4432{ /*lint --e{715}*/
4433 SCIP_HEURDATA* heurdata;
4434
4435 assert(SCIPfindHeur(scip, HEUR_NAME) != NULL);
4437 assert(heurdata != NULL);
4438
4439 /* print neighborhood statistics */
4440 printNeighborhoodStatistics(scip, heurdata, file);
4441
4442 /* print only diving statistics if scheduler got executed at least once (because we only then
4443 * initialize the diving heuristics)
4444 * Note: More Diving statistics will be printed in scip_solvingstats.c with all other stats about
4445 * diving since adaptive diving and the scheduler use the same diving context
4446 */
4447 if( heurdata->divingheurs != NULL )
4448 printDivingHeurStatistics(scip, heurdata, file);
4449
4450 return SCIP_OKAY;
4451}
4452
4453static
4454SCIP_DECL_TABLECOLLECT(tableCollectNeighborhood)
4455{
4456 assert(table != NULL);
4457
4458 SCIP_HEURDATA* heurdata;
4459
4460 assert(SCIPfindHeur(scip, HEUR_NAME) != NULL);
4462 assert(heurdata != NULL);
4463
4464 /* print neighborhood statistics */
4465 SCIP_CALL( collectNeighborhoodStatistics(scip, heurdata, datatree) );
4466
4467 if( heurdata->divingheurs != NULL )
4468 {
4469 SCIP_CALL( collectDivingHeurStatistics(scip, heurdata, datatree) );
4470 }
4471
4472 return SCIP_OKAY;
4473}
4474
4475/*
4476 * primal heuristic specific interface methods
4477 */
4478
4479/** creates the scheduler primal heuristic and includes it in SCIP */
4481 SCIP* scip /**< SCIP data structure */
4482 )
4483{
4484 SCIP_HEURDATA* heurdata;
4485 SCIP_HEUR* heur;
4486
4487 /* create primal heuristic data */
4488 heurdata = NULL;
4489 heur = NULL;
4490
4491 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
4492 BMSclearMemory(heurdata);
4493
4494 /* TODO make this a user parameter? */
4495 heurdata->lplimfac = LPLIMFAC;
4496
4497 heurdata->nskippedcalls = 0;
4498 heurdata->nfailedcalls = 0;
4499 heurdata->maxnconflicts = 0;
4500
4501 /* allocate memory for LNS heuristics */
4502 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &heurdata->neighborhoods, NNEIGHBORHOODS) );
4503
4504 /* include primal heuristic */
4507 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecScheduler, heurdata) );
4508
4509 assert(heur != NULL);
4510
4511 /* primal heuristic is safe to use in exact solving mode */
4512 SCIPheurMarkExact(heur);
4513
4514 /* include all neighborhoods */
4515 /* note: diving heuristics will be included when executing the scheduler heuristic for
4516 * the first time, because it relies on all heuristics being already added to SCIP
4517 */
4518 SCIP_CALL( includeNeighborhoods(scip, heurdata) );
4519
4520 /* set non fundamental callbacks via setter functions */
4521 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyScheduler) );
4522 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeScheduler) );
4523 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitScheduler) );
4524 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolScheduler) );
4525 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitScheduler) );
4526
4527 /* add scheduler primal heuristic parameters */
4528 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/maxnodes",
4529 "maximum number of nodes to regard in the subproblem",
4530 &heurdata->maxnodes, TRUE,DEFAULT_MAXNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4531
4532 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/nodesofs",
4533 "offset added to the nodes budget",
4534 &heurdata->nodesoffset, FALSE, DEFAULT_NODESOFFSET, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4535
4536 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/minnodes",
4537 "minimum number of nodes required to start a sub-SCIP",
4538 &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4539
4540 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/waitingnodes",
4541 "number of nodes since last incumbent solution that the heuristic should wait",
4542 &heurdata->waitingnodes, TRUE, DEFAULT_WAITINGNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4543
4544 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/initlnsnodelimit",
4545 "initial node limit for LNS heuristics",
4546 &heurdata->initlnsnodelimit, TRUE, DEFAULT_INITLNSNODELIMIT, 0, INT_MAX, NULL, NULL) );
4547
4548 SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/initdivingnodelimit",
4549 "initial node limit for diving heuristics",
4550 &heurdata->initdivingnodelimit, TRUE, DEFAULT_INITDIVINGNODELIMIT, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
4551
4552 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquot",
4553 "fraction of nodes compared to the main SCIP for budget computation",
4554 &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) );
4555
4556 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquotmin",
4557 "lower bound fraction of nodes compared to the main SCIP for budget computation",
4558 &heurdata->nodesquotmin, FALSE, DEFAULT_NODESQUOTMIN, 0.0, 1.0, NULL, NULL) );
4559
4560 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nsolslim",
4561 "limit on the number of improving solutions in a sub-SCIP call",
4562 &heurdata->nsolslim, FALSE, DEFAULT_NSOLSLIM, -1, INT_MAX, NULL, NULL) );
4563
4564 SCIP_CALL( SCIPaddCharParam(scip, "heuristics/" HEUR_NAME "/banditalgo",
4565 "the bandit algorithm: (u)pper confidence bounds, (e)xp.3, epsilon (g)reedy, exp.3-(i)x",
4566 &heurdata->banditalgo, TRUE, DEFAULT_BANDITALGO, "uegi", NULL, NULL) );
4567
4568 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/gamma",
4569 "weight between uniform (gamma ~ 1) and weight driven (gamma ~ 0) probability distribution for exp3",
4570 &heurdata->exp3_gamma, TRUE, DEFAULT_GAMMA, 0.0, 1.0, NULL, NULL) );
4571
4572 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/beta",
4573 "reward offset between 0 and 1 at every observation for Exp.3",
4574 &heurdata->exp3_beta, TRUE, DEFAULT_BETA, 0.0, 1.0, NULL, NULL) );
4575
4576 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/alpha",
4577 "parameter to increase the confidence width in UCB",
4578 &heurdata->ucb_alpha, TRUE, DEFAULT_ALPHA, 0.0, 100.0, NULL, NULL) );
4579
4580 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usedistances",
4581 "distances from fixed variables be used for variable prioritization",
4582 &heurdata->usedistances, TRUE, DEFAULT_USEDISTANCES, NULL, NULL) );
4583
4584 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/useredcost",
4585 "should reduced cost scores be used for variable prioritization?",
4586 &heurdata->useredcost, TRUE, DEFAULT_USEREDCOST, NULL, NULL) );
4587
4588 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usepscost",
4589 "should pseudo cost scores be used for variable priorization?",
4590 &heurdata->usepscost, TRUE, DEFAULT_USEPSCOST, NULL, NULL) );
4591
4592 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/uselocalredcost",
4593 "should local reduced costs be used for generic (un)fixing?",
4594 &heurdata->uselocalredcost, TRUE, DEFAULT_USELOCALREDCOST, NULL, NULL) );
4595
4596 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/usesubscipheurs",
4597 "should the heuristic activate other sub-SCIP heuristics during its search?",
4598 &heurdata->usesubscipheurs, TRUE, DEFAULT_USESUBSCIPHEURS, NULL, NULL) );
4599
4600 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/targetnodefactor",
4601 "factor by which target node number is eventually increased",
4602 &heurdata->targetnodefactor, TRUE, DEFAULT_TARGETNODEFACTOR, 1.0, 1e+5, NULL, NULL) );
4603
4604 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/seed",
4605 "initial random seed for bandit algorithms and random decisions by neighborhoods",
4606 &heurdata->seed, FALSE, DEFAULT_SEED, 0, INT_MAX, NULL, NULL) );
4607
4608 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxcallssamesol",
4609 "number of allowed executions of the heuristic on the same incumbent solution (-1: no limit, 0: number of active neighborhoods)",
4610 &heurdata->maxcallssamesol, TRUE, DEFAULT_MAXCALLSSAMESOL, -1, 100, NULL, NULL) );
4611
4612 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/eps",
4613 "increase exploration in epsilon-greedy bandit algorithm",
4614 &heurdata->epsgreedy_eps, TRUE, DEFAULT_EPS, 0.0, 1.0, NULL, NULL) );
4615
4616 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/epsgreedy_usemod",
4617 "TRUE if modified version of the epsilon-greedy bandit algorithm should be used",
4618 &heurdata->epsgreedy_usemod, TRUE, TRUE, NULL, NULL) );
4619
4620 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/solrewardweight",
4621 "weight by how much finding a new incumbent is rewarded in reward function",
4622 &heurdata->solrewardweight, TRUE, DEFAULT_SOLREWARDWEIGHT, 0.0, 1.0, NULL, NULL) );
4623
4624 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/effortrewardweight",
4625 "weight by how much effort is rewarded in reward function",
4626 &heurdata->effortrewardweight, TRUE, DEFAULT_EFFORTREWARDWEIGHT, 0.0, 1.0, NULL, NULL) );
4627
4628 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/qualrewardweight",
4629 "weight by how much quality of a new incumbent is rewarded in reward function",
4630 &heurdata->qualrewardweight, TRUE, DEFAULT_QUALREWARDWEIGHT, 0.0, 1.0, NULL, NULL) );
4631
4632 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/conflictrewardweight",
4633 "weight by how much number of conflicts found by diving is rewarded in reward function",
4634 &heurdata->conflictrewardweight, TRUE, DEFAULT_CONFLICTREWARDWEIGHT, 0.0, 1.0, NULL, NULL) );
4635
4636 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/resetweights",
4637 "should the bandit algorithms be reset when a new problem is read?",
4638 &heurdata->resetweights, TRUE, DEFAULT_RESETWEIGHTS, NULL, NULL) );
4639
4640 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/subsciprandseeds",
4641 "should random seeds of sub-SCIPs be altered to increase diversification?",
4642 &heurdata->subsciprandseeds, TRUE, DEFAULT_SUBSCIPRANDSEEDS, NULL, NULL) );
4643
4644 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/copycuts",
4645 "should cutting planes be copied to the sub-SCIP?",
4646 &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
4647
4648 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/fixtol",
4649 "tolerance by which the fixing rate may be missed without generic fixing",
4650 &heurdata->fixtol, TRUE, DEFAULT_FIXTOL, 0.0, 1.0, NULL, NULL) );
4651
4652 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/unfixtol",
4653 "tolerance by which the fixing rate may be exceeded without generic unfixing",
4654 &heurdata->unfixtol, TRUE, DEFAULT_UNFIXTOL, 0.0, 1.0, NULL, NULL) );
4655
4656 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/initduringroot",
4657 "should the heuristic be executed multiple times during the root node?",
4658 &heurdata->initduringroot, TRUE, DEFAULT_INITDURINGROOT, NULL, NULL) );
4659
4660 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/defaultroot",
4661 "should the default priorities be used at the root node?",
4662 &heurdata->defaultroot, TRUE, TRUE, NULL, NULL) );
4663
4664 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nselections",
4665 "number of heuristics picked by the scheduler in one call (-1: number of controlled heuristics, 0: until new incumbent is found)",
4666 &heurdata->nselections, TRUE, DEFAULT_NSELECTIONS, -1, 100, NULL, NULL) );
4667
4670 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNeighborhood, tableCollectNeighborhood,
4672
4673 return SCIP_OKAY;
4674}
static GRAPHNODE ** active
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_VAR ** b
Definition: circlepacking.c:65
Constraint handler for linear constraints in their most general form, .
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_ALLOC(x)
Definition: def.h:366
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL_ABORT(x)
Definition: def.h:334
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIPABORT()
Definition: def.h:327
#define REALABS(x)
Definition: def.h:182
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPtranslateSubSol(SCIP *scip, SCIP *subscip, SCIP_SOL *subsol, SCIP_HEUR *heur, SCIP_VAR **subvars, SCIP_SOL **newsol)
Definition: scip_copy.c:1397
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:647
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:402
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:370
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:562
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2616
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2340
SCIP_RETCODE SCIPsetObjlimit(SCIP *scip, SCIP_Real objlimit)
Definition: scip_prob.c:1661
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:2115
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2293
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3095
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3284
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3061
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition: scip_param.c:250
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:111
SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
Definition: scip_param.c:219
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:167
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:545
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:904
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition: scip_param.c:956
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:661
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:429
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
SCIP_RETCODE SCIPsetSeparating(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition: scip_param.c:985
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10511
SCIP_RETCODE SCIPincludeHeurScheduler(SCIP *scip)
SCIP_RETCODE SCIPresetBandit(SCIP *scip, SCIP_BANDIT *bandit, SCIP_Real *priorities, unsigned int seed)
Definition: scip_bandit.c:91
SCIP_RETCODE SCIPbanditUpdate(SCIP_BANDIT *bandit, int action, SCIP_Real score)
Definition: bandit.c:174
int SCIPbanditGetNActions(SCIP_BANDIT *bandit)
Definition: bandit.c:303
SCIP_Real SCIPgetProbabilityExp3IX(SCIP_BANDIT *exp3ix, int action)
SCIP_Real * SCIPgetWeightsEpsgreedy(SCIP_BANDIT *epsgreedy)
SCIP_RANDNUMGEN * SCIPbanditGetRandnumgen(SCIP_BANDIT *bandit)
Definition: bandit.c:293
SCIP_RETCODE SCIPcreateBanditExp3(SCIP *scip, SCIP_BANDIT **exp3, SCIP_Real *priorities, SCIP_Real gammaparam, SCIP_Real beta, int nactions, unsigned int initseed)
Definition: bandit_exp3.c:311
SCIP_RETCODE SCIPcreateBanditEpsgreedy(SCIP *scip, SCIP_BANDIT **epsgreedy, SCIP_Real *priorities, SCIP_Real eps, SCIP_Bool usemodification, SCIP_Bool preferrecent, SCIP_Real decayfactor, int avglim, int nactions, unsigned int initseed)
SCIP_Real SCIPgetConfidenceBoundUcb(SCIP_BANDIT *ucb, int action)
Definition: bandit_ucb.c:263
SCIP_RETCODE SCIPcreateBanditExp3IX(SCIP *scip, SCIP_BANDIT **exp3ix, SCIP_Real *priorities, int nactions, unsigned int initseed)
SCIP_RETCODE SCIPbanditSelect(SCIP_BANDIT *bandit, int *action)
Definition: bandit.c:153
SCIP_RETCODE SCIPcreateBanditUcb(SCIP *scip, SCIP_BANDIT **ucb, SCIP_Real *priorities, SCIP_Real alpha, int nactions, unsigned int initseed)
Definition: bandit_ucb.c:337
SCIP_RETCODE SCIPfreeBandit(SCIP *scip, SCIP_BANDIT **bandit)
Definition: scip_bandit.c:107
SCIP_Real SCIPgetProbabilityExp3(SCIP_BANDIT *exp3, int action)
Definition: bandit_exp3.c:363
SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
Definition: scip_branch.c:304
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4812
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_RETCODE SCIPcreateDatatreeInTree(SCIP *scip, SCIP_DATATREE *datatree, SCIP_DATATREE **newtree, const char *name, int capacity)
Definition: scip_datatree.c:61
SCIP_RETCODE SCIPinsertDatatreeBool(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Bool value)
Definition: scip_datatree.c:82
SCIP_RETCODE SCIPinsertDatatreeInt(SCIP *scip, SCIP_DATATREE *datatree, const char *name, int value)
SCIP_RETCODE SCIPinsertDatatreeLong(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Longint value)
SCIP_RETCODE SCIPinsertDatatreeReal(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Real value)
SCIP_Bool SCIPdivesetIsPublic(SCIP_DIVESET *diveset)
Definition: heur.c:764
SCIP_Longint SCIPdivesetGetNBacktracks(SCIP_DIVESET *diveset, SCIP_DIVECONTEXT divecontext)
Definition: heur.c:615
SCIP_Longint SCIPdivesetGetNSols(SCIP_DIVESET *diveset, SCIP_DIVECONTEXT divecontext)
Definition: heur.c:641
SCIP_Longint SCIPdivesetGetNConflicts(SCIP_DIVESET *diveset, SCIP_DIVECONTEXT divecontext)
Definition: heur.c:628
const char * SCIPdivesetGetName(SCIP_DIVESET *diveset)
Definition: heur.c:445
SCIP_Longint SCIPdivesetGetNProbingNodes(SCIP_DIVESET *diveset, SCIP_DIVECONTEXT divecontext)
Definition: heur.c:602
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:111
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:396
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1194
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:293
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip_heur.c:167
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1368
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip_heur.c:122
SCIP_HEUR ** SCIPgetHeurs(SCIP *scip)
Definition: scip_heur.c:276
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip_heur.c:183
int SCIPheurGetPriority(SCIP_HEUR *heur)
Definition: heur.c:1528
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
Definition: scip_heur.c:215
int SCIPgetNHeurs(SCIP *scip)
Definition: scip_heur.c:287
SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
Definition: heur.c:1593
SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
Definition: scip_heur.c:231
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:263
int SCIPheurGetNDivesets(SCIP_HEUR *heur)
Definition: heur.c:1675
void SCIPheurMarkExact(SCIP_HEUR *heur)
Definition: heur.c:1457
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip_heur.c:199
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1467
SCIP_DIVESET ** SCIPheurGetDivesets(SCIP_HEUR *heur)
Definition: heur.c:1665
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip_lp.c:87
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:673
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:126
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:100
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_NODESEL * SCIPfindNodesel(SCIP *scip, const char *name)
Definition: scip_nodesel.c:242
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2981
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_SOLORIGIN SCIPsolGetOrigin(SCIP_SOL *sol)
Definition: sol.c:4130
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_Longint SCIPsolGetNodenum(SCIP_SOL *sol)
Definition: sol.c:4239
int SCIPgetNSols(SCIP *scip)
Definition: scip_sol.c:2882
SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
Definition: sol.c:4140
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1846
SCIP_SOL ** SCIPgetSols(SCIP *scip)
Definition: scip_sol.c:2931
SCIP_RETCODE SCIPtrySolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition: scip_sol.c:4109
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_RETCODE SCIPtransformProb(SCIP *scip)
Definition: scip_solve.c:232
SCIP_RETCODE SCIPpresolve(SCIP *scip)
Definition: scip_solve.c:2449
SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
Definition: scip_solve.c:3548
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2635
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_RETCODE SCIPprintStatistics(SCIP *scip, FILE *file)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Longint SCIPgetNBestSolsFound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_RETCODE SCIPperformGenericDivingAlgorithm(SCIP *scip, SCIP_DIVESET *diveset, SCIP_SOL *worksol, SCIP_HEUR *heur, SCIP_RESULT *result, SCIP_Bool nodeinfeasible, SCIP_Longint iterlim, int nodelimit, SCIP_Real lpresolvedomchgquot, SCIP_DIVECONTEXT divecontext)
Definition: heuristics.c:221
SCIP_RETCODE SCIPcopyLargeNeighborhoodSearch(SCIP *sourcescip, SCIP *subscip, SCIP_HASHMAP *varmap, const char *suffix, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, int nfixedvars, SCIP_Bool uselprows, SCIP_Bool copycuts, SCIP_Bool *success, SCIP_Bool *valid)
Definition: heuristics.c:953
SCIP_RETCODE SCIPaddTrustregionNeighborhoodConstraint(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR **subvars, SCIP_Real violpenalty)
Definition: heuristics.c:1042
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:101
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition: scip_table.c:62
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:76
SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:144
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:178
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:127
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:319
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:161
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisDualfeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisDualfeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisDualfeasZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_RETCODE SCIPvariablegraphBreadthFirst(SCIP *scip, SCIP_VGRAPH *vargraph, SCIP_VAR **startvars, int nstartvars, int *distances, int maxdistance, int maxvars, int maxbinintvars)
Definition: heur.c:1704
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetBestRootSol(SCIP_VAR *var)
Definition: var.c:19480
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
Definition: var.c:19115
SCIP_RETCODE SCIPchgVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:6141
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:11188
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:24664
SCIP_RETCODE SCIPchgVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:6230
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2608
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_Real SCIPvarGetBestRootRedcost(SCIP_VAR *var)
Definition: var.c:19547
SCIP_RETCODE SCIPchgVarObj(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_var.c:5372
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10245
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10223
void SCIPselectInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int k, int len)
void SCIPselectDownInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int k, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
enum HistIndex HISTINDEX
Definition: heur_alns.c:335
HistIndex
Definition: heur_alns.c:326
static void tryAdd2variableBuffer(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_VAR **varbuf, SCIP_Real *valbuf, int *nfixings, SCIP_Bool integer)
static SCIP_RETCODE includeDivingHeurs(SCIP *scip, SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
#define DEFAULT_ACTIVE_MUTATION
#define DEFAULT_MINFIXINGRATE_ZEROOBJECTIVE
static void printDivingHeurStatistics(SCIP *scip, SCIP_HEURDATA *heurdata, FILE *file)
enum HistIndex HISTINDEX
static SCIP_RETCODE initRest(SCIP *scip, SCIP_HEUR *heur)
static SCIP_DECL_HEURFREE(heurFreeScheduler)
#define DECL_NHEXIT(x)
#define TABLE_POSITION_NEIGHBORHOOD
#define DEFAULT_NODESQUOT
static void increaseFixingRate(NH_FIXINGRATE *fx)
#define DEFAULT_MAXCALLSSAMESOL
#define NNEIGHBORHOODS
static SCIP_DECL_SORTINDCOMP(sortIndCompScheduler)
static SCIP_RETCODE updateSelectionStrategy(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_Real reward, int selection)
#define DEFAULT_NSOLSLIM
#define DECL_NHDEACTIVATE(x)
static SCIP_DECL_HEURINIT(heurInitScheduler)
#define DEFAULT_PRIORITY_RENS
#define DEFAULT_ACTIVE_PROXIMITY
#define DEFAULT_NODESQUOTMIN
#define DEFAULT_MINFIXINGRATE_DINS
#define DEFAULT_SEED
#define DEFAULT_ACTIVE_RINS
#define TABLE_NAME_NEIGHBORHOOD
static void initRunStats(SCIP *scip, HEUR_STATS *stats)
#define DEFAULT_COPYCUTS
#define DEFAULT_MAXNODES
static SCIP_RETCODE neighborhoodGetRefsol(SCIP *scip, NH *neighborhood, SCIP_SOL **solptr)
#define DEFAULT_USEREDCOST
#define SOLVEFREQ_DECAY
#define HEUR_TIMING
#define DEFAULT_MINNODES
static void decreaseFixingRate(NH_FIXINGRATE *fx)
#define DECL_NHINIT(x)
#define DECL_NHFREE(x)
static void decreaseSolveFreq(SOLVEFREQ *solvefreqdata)
static SCIP_RETCODE executeLNSHeuristic(SCIP *scip, SCIP_HEUR *heur, int selection, HEUR_STATS *runstats, SCIP_STATUS *subscipstatus, SCIP_RESULT *result)
#define DEFAULT_FIXTOL
static void updateFixingRate(NH *neighborhood, SCIP_STATUS subscipstatus, HEUR_STATS *runstats)
#define SCIP_EVENTTYPE_SCHEDULER
#define DEFAULT_SOLREWARDWEIGHT
#define HEUR_FREQOFS
static void updateRunStats(HEUR_STATS *stats, SCIP *subscip)
#define FIXINGRATE_STARTINC
#define HEUR_DESC
#define DEFAULT_MAXFIXINGRATE_RENS
#define DEFAULT_PRIORITY_PROXIMITY
static void resetTargetNodeLimit(SCIP_HEURDATA *heurdata)
#define SOLVEFREQ_STARTINC
static SCIP_RETCODE neighborhoodInit(SCIP *scip, NH *neighborhood)
#define DEFAULT_ACTIVE_TRUSTREGION
#define DEFAULT_MINFIXINGRATE_RENS
#define DEFAULT_MAXFIXINGRATE_DINS
static SCIP_DECL_TABLECOLLECT(tableCollectNeighborhood)
static SCIP_DECL_HEURINITSOL(heurInitsolScheduler)
#define FIXINGRATE_DECAY
#define DEFAULT_MINFIXINGRATE_RINS
static SCIP_Real getReward(SCIP *scip, SCIP_HEURDATA *heurdata, int selection, HEUR_STATS *runstats)
#define DEFAULT_PRIORITY_ZEROOBJECTIVE
#define DEFAULT_INITLNSNODELIMIT
#define DEFAULT_WAITINGNODES
#define DEFAULT_NODESOFFSET
#define TABLE_DESC_NEIGHBORHOOD
#define DECL_CHANGESUBSCIP(x)
#define DEFAULT_EFFORTREWARDWEIGHT
#define DEFAULT_RESETWEIGHTS
static SCIP_RETCODE selectHeuristic(SCIP *scip, SCIP_HEURDATA *heurdata, int *selection)
#define HEUR_DISPCHAR
#define DEFAULT_QUALREWARDWEIGHT
#define HEUR_MAXDEPTH
#define HEUR_PRIORITY
#define DEFAULT_MAXFIXINGRATE_MUTATION
#define TABLE_EARLIEST_STAGE_NEIGHBORHOOD
static SCIP_DECL_HEURCOPY(heurCopyScheduler)
#define DECL_NHREFSOL(x)
static void increaseSolveFreq(SOLVEFREQ *solvefreqdata)
#define DEFAULT_USELOCALREDCOST
#define DEFAULT_CONFLICTREWARDWEIGHT
#define DEFAULT_MAXFIXINGRATE_TRUSTREGION
static SCIP_RETCODE schedulerIncludeNeighborhood(SCIP *scip, SCIP_HEURDATA *heurdata, NH **neighborhood, const char *name, SCIP_Real minfixingrate, SCIP_Real maxfixingrate, SCIP_Bool active, int priority, DECL_VARFIXINGS((*varfixings)), DECL_CHANGESUBSCIP((*changesubscip)), DECL_NHINIT((*nhinit)), DECL_NHEXIT((*nhexit)), DECL_NHFREE((*nhfree)), DECL_NHREFSOL((*nhrefsol)), DECL_NHDEACTIVATE((*nhdeactivate)))
#define DIVINGHEURS_INITIALSIZE
#define DEFAULT_MAXFIXINGRATE_ZEROOBJECTIVE
#define HEUR_NAME
#define DEFAULT_ACTIVE_RENS
#define NHISTENTRIES
static void initSolveFreq(SOLVEFREQ *solvefreqdata)
static void updateFixingRateIncrement(NH_FIXINGRATE *fx)
#define DEFAULT_INITDIVINGNODELIMIT
#define DEFAULT_MINFIXINGRATE_CROSSOVER
static SCIP_RETCODE addLocalBranchingConstraint(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR **subvars, int distance, SCIP_Bool *success, int *naddedconss)
#define DEFAULT_ACTIVE_ZEROOBJECTIVE
#define DEFAULT_MINFIXINGRATE_LOCALBRANCHING
#define MINSOLVEFREQ
@ HIDX_STALLNODE
@ HIDX_OTHER
@ HIDX_SOLLIM
@ HIDX_USR
@ HIDX_OPT
@ HIDX_INFEAS
@ HIDX_NODELIM
#define DEFAULT_PRIORITY_CROSSOVER
#define DEFAULT_NSELECTIONS
static SCIP_RETCODE collectNeighborhoodStatistics(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_DATATREE *datatree)
static SCIP_RETCODE setLimits(SCIP *subscip, SOLVELIMITS *solvelimits)
#define DEFAULT_INITDURINGROOT
static SCIP_RETCODE executeHeuristic(SCIP *scip, SCIP_HEUR *heur, int selection, HEUR_STATS *runstats, SCIP_STATUS *subscipstatus, SCIP_RESULT *result)
static SCIP_DECL_HEUREXEC(heurExecScheduler)
#define DEFAULT_VIOLPENALTY_TRUSTREGION
#define DEFAULT_UNFIXTOL
static SCIP_RETCODE resetFixingRate(SCIP *scip, NH_FIXINGRATE *fixingrate)
#define DEFAULT_ALPHA
#define MUTATIONSEED
#define DEFAULT_ACTIVE_LOCALBRANCHING
static SCIP_RETCODE collectDivingHeurStatistics(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_DATATREE *datatree)
static SCIP_RETCODE fixMatchingSolutionValues(SCIP *scip, SCIP_SOL **sols, int nsols, SCIP_VAR **vars, int nvars, SCIP_VAR **varbuf, SCIP_Real *valbuf, int *nfixings)
#define DEFAULT_PRIORITY_MUTATION
#define DEFAULT_PRIORITY_RINS
static SCIP_Real getVariablePscostScore(SCIP *scip, SCIP_VAR *var, SCIP_Real refsolval, SCIP_Bool uselocallpsol)
#define MAXSOLVEFREQ
static int getHistIndex(SCIP_STATUS subscipstatus)
#define DEFAULT_ACTIVE_DINS
#define EVENTHDLR_DESC
#define DEFAULT_PRIORITY_TRUSTREGION
static SCIP_DECL_HEUREXIT(heurExitScheduler)
static void updateSolveFreqIncrement(SOLVEFREQ *solvefreqdata)
#define LPLIMFAC
#define CROSSOVERSEED
#define DEFAULT_MAXFIXINGRATE_LOCALBRANCHING
#define HEUR_FREQ
#define DEFAULT_SUBSCIPRANDSEEDS
#define DEFAULT_NPOOLSOLS_DINS
static void computeIntegerVariableBoundsDins(SCIP *scip, SCIP_VAR *var, SCIP_Real *lbptr, SCIP_Real *ubptr)
#define DEFAULT_MAXFIXINGRATE_RINS
static SCIP_RETCODE includeNeighborhoods(SCIP *scip, SCIP_HEURDATA *heurdata)
#define DEFAULT_MINFIXINGRATE_MUTATION
#define DEFAULT_EPS
static SCIP_RETCODE LNSUnfixVariables(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **varbuf, SCIP_Real *valbuf, int *nfixings, int ntargetfixings, SCIP_Bool *success)
#define DEFAULT_TARGETNODEFACTOR
#define DEFAULT_MAXFIXINGRATE_CROSSOVER
#define DEFAULT_NSOLS_CROSSOVER
#define DEFAULT_USEDISTANCES
static SCIP_RETCODE reinitBandit(SCIP *scip, SCIP_HEURDATA *heurdata, int nactions)
static void updateHeurStatsLNS(HEUR_STATS *runstats, NH *neighborhood, SCIP_STATUS *subscipstatus)
static void resetCurrentNeighborhood(SCIP_HEURDATA *heurdata)
static SCIP_Real getVariableRedcostScore(SCIP *scip, SCIP_VAR *var, SCIP_Real refsolval, SCIP_Bool uselocalredcost)
static void updateSolveFreq(DIVING_HEUR *divingheur, HEUR_STATS *stats)
static SCIP_DECL_EVENTEXEC(eventExecScheduler)
#define HEUR_USESSUBSCIP
#define DEFAULT_BETA
static SCIP_RETCODE schedulerFreeDivingHeur(SCIP *scip, DIVING_HEUR **divingheur)
static void updateHeurStatsDiving(HEUR_STATS *runstats, DIVING_HEUR *divingheur)
static SCIP_RETCODE schedulerFreeNeighborhood(SCIP *scip, NH **neighborhood)
static SCIP_RETCODE neighborhoodExit(SCIP *scip, NH *neighborhood)
#define DEFAULT_ACTIVE_CROSSOVER
static SCIP_RETCODE executeDivingHeuristic(SCIP *scip, SCIP_HEUR *heur, int selection, HEUR_STATS *runstats, SCIP_RESULT *result)
#define DEFAULT_USESUBSCIPHEURS
#define DEFAULT_PRIORITY_DINS
#define EVENTHDLR_NAME
static void printNeighborhoodStatistics(SCIP *scip, SCIP_HEURDATA *heurdata, FILE *file)
static SCIP_RETCODE setupSubScip(SCIP *scip, SCIP *subscip, SCIP_VAR **subvars, SOLVELIMITS *solvelimits, SCIP_HEUR *heur, SCIP_Bool objchgd)
static SCIP_RETCODE determineLimits(SCIP *scip, SCIP_HEUR *heur, int selection, SOLVELIMITS *solvelimits, SCIP_Bool *runagain)
#define DEFAULT_MAXFIXINGRATE_PROXIMITY
static SCIP_RETCODE neighborhoodChangeSubscip(SCIP *sourcescip, SCIP *targetscip, NH *neighborhood, SCIP_VAR **targetvars, int *ndomchgs, int *nchgobjs, int *naddedconss, SCIP_Bool *success)
#define DECL_VARFIXINGS(x)
#define DEFAULT_PRIORITY_LOCALBRANCHING
static SCIP_RETCODE heurStatsReset(SCIP *scip, HEUR_STATS *stats, SCIP_Bool usediving)
#define DEFAULT_MINFIXINGRATE_TRUSTREGION
#define DEFAULT_BESTSOLWEIGHT
#define DEFAULT_BANDITALGO
static SCIP_RETCODE LNSFixMoreVariables(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_SOL *refsol, SCIP_VAR **varbuf, SCIP_Real *valbuf, int *nfixings, int ntargetfixings, SCIP_Bool *success)
#define DEFAULT_MINFIXINGRATE_PROXIMITY
static SCIP_RETCODE createBandit(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_Real *priorities, unsigned int initseed)
static SCIP_RETCODE neighborhoodFixVariables(SCIP *scip, SCIP_HEURDATA *heurdata, NH *neighborhood, SCIP_VAR **varbuf, SCIP_Real *valbuf, int *nfixings, SCIP_RESULT *result)
#define DEFAULT_GAMMA
static SCIP_DECL_TABLEOUTPUT(tableOutputNeighborhood)
#define LRATEMIN
#define DEFAULT_USEPSCOST
static SCIP_RETCODE transferSolution(SCIP *subscip, SCIP_EVENTDATA *eventdata)
Adaptive heuristic to schedule LNS and diving heuristics.
methods commonly used by primal heuristics
static const char * paramname[]
Definition: lpi_msk.c:5172
memory allocation routines
#define BMSduplicateMemoryArray(ptr, source, num)
Definition: memory.h:143
#define BMSclearMemory(ptr)
Definition: memory.h:129
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:147
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for bandit algorithms
public methods for the epsilon greedy bandit selector
public methods for Exp.3
public methods for Exp.3-IX
public methods for UCB bandit selection
public methods for managing constraints
public methods for managing events
public methods for primal heuristics
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public data structures and miscellaneous methods
methods for selecting (weighted) k-medians
public methods for primal CIP solutions
public methods for problem variables
public methods for bandit algorithms
public methods for branching rule plugins and branching
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for event handler plugins and event handlers
general public methods
public methods for primal heuristic plugins and divesets
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for node selector plugins
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for random numbers
public methods for solutions
public solving methods
public methods for querying solving statistics
public methods for statistics table plugins
public methods for timing
public methods for the branch-and-bound tree
public methods for SCIP variables
SCIP_Longint nodelimit
SCIP_DIVESET * diveset
SOLVEFREQ * solvefreqdata
SCIP_Real priority
HEUR_STATS * stats
SCIP_Real oldupperbound
SCIP_Longint nprobnodes
int statushist[NHISTENTRIES]
SCIP_Longint nbacktracks
SCIP_Longint nconflicts
SCIP_CLOCK * execclock
SCIP_Longint nbestsolsfound
SCIP_Real newupperbound
SCIP_Longint usednodes
SCIP_CLOCK * setupclock
SCIP_Longint nsolsfound
SCIP_Real targetfixingrate
Definition: heur_alns.c:360
SCIP_Real increment
Definition: heur_alns.c:361
SCIP_Real minfixingrate
Definition: heur_alns.c:359
SCIP_Real maxfixingrate
Definition: heur_alns.c:362
SCIP_Longint nsolsfound
Definition: heur_alns.c:349
int statushist[NHISTENTRIES]
Definition: heur_alns.c:352
SCIP_CLOCK * setupclock
Definition: heur_alns.c:342
int nruns
Definition: heur_alns.c:347
SCIP_Longint nbestsolsfound
Definition: heur_alns.c:350
SCIP_Longint usednodes
Definition: heur_alns.c:344
int nfixings
Definition: heur_alns.c:351
Definition: heur_alns.c:367
HEUR_STATS stats
NH_FIXINGRATE fixingrate
Definition: heur_alns.c:369
DECL_NHINIT((*nhinit))
DATA_MUTATION * mutation
Definition: heur_alns.c:382
int nodelimit
union Nh::@7 data
DECL_CHANGESUBSCIP((*changesubscip))
SCIP_Bool active
Definition: heur_alns.c:378
NH_STATS stats
Definition: heur_alns.c:370
DECL_NHFREE((*nhfree))
DATA_CROSSOVER * crossover
Definition: heur_alns.c:383
DECL_NHEXIT((*nhexit))
DECL_NHDEACTIVATE((*nhdeactivate))
DATA_TRUSTREGION * trustregion
Definition: heur_alns.c:385
int rootnodepriority
DECL_VARFIXINGS((*varfixings))
DECL_NHREFSOL((*nhrefsol))
DATA_DINS * dins
Definition: heur_alns.c:384
char * name
Definition: heur_alns.c:368
SCIP_Real priority
Definition: heur_alns.c:379
SCIP_SOL * sol
Definition: struct_heur.h:71
SCIP_Real minsolvefreq
SCIP_Real increment
SCIP_Real maxsolvefreq
SCIP_Real currentsolvefreq
SCIP_Real timelimit
Definition: heur_alns.c:491
SCIP_Longint stallnodes
Definition: heur_alns.c:492
SCIP_Longint nodelimit
Definition: heur_alns.c:489
SCIP_Real memorylimit
Definition: heur_alns.c:490
SCIP * scip
Definition: heur_alns.c:500
unsigned int useredcost
Definition: heur_alns.c:505
SCIP_Real * randscores
Definition: heur_alns.c:501
int * distances
Definition: heur_alns.c:502
SCIP_Real * pscostscores
Definition: heur_alns.c:504
unsigned int usedistances
Definition: heur_alns.c:506
SCIP_Real * redcostscores
Definition: heur_alns.c:503
unsigned int usepscost
Definition: heur_alns.c:507
SCIP_SOL * selsol
Definition: heur_alns.c:400
SCIP_RANDNUMGEN * rng
Definition: heur_alns.c:399
int npoolsols
Definition: heur_alns.c:406
SCIP_RANDNUMGEN * rng
Definition: heur_alns.c:392
SCIP_Real violpenalty
Definition: heur_alns.c:411
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:179
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition: type_event.h:106
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:146
#define SCIP_EVENTTYPE_LPSOLVED
Definition: type_event.h:102
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:77
@ SCIP_DIVECONTEXT_SCHEDULER
Definition: type_heur.h:71
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_PARAMSETTING_OFF
Definition: type_paramset.h:63
@ SCIP_PARAMSETTING_FAST
Definition: type_paramset.h:62
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_DELAYED
Definition: type_result.h:43
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SUCCESS
Definition: type_result.h:58
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_SOLORIGIN_ORIGINAL
Definition: type_sol.h:42
@ SCIP_STATUS_OPTIMAL
Definition: type_stat.h:43
@ SCIP_STATUS_TOTALNODELIMIT
Definition: type_stat.h:50
@ SCIP_STATUS_BESTSOLLIMIT
Definition: type_stat.h:60
@ SCIP_STATUS_SOLLIMIT
Definition: type_stat.h:59
@ SCIP_STATUS_UNBOUNDED
Definition: type_stat.h:45
@ SCIP_STATUS_UNKNOWN
Definition: type_stat.h:42
@ SCIP_STATUS_PRIMALLIMIT
Definition: type_stat.h:57
@ SCIP_STATUS_GAPLIMIT
Definition: type_stat.h:56
@ SCIP_STATUS_USERINTERRUPT
Definition: type_stat.h:47
@ SCIP_STATUS_TERMINATE
Definition: type_stat.h:48
@ SCIP_STATUS_INFORUNBD
Definition: type_stat.h:46
@ SCIP_STATUS_STALLNODELIMIT
Definition: type_stat.h:52
@ SCIP_STATUS_TIMELIMIT
Definition: type_stat.h:54
@ SCIP_STATUS_INFEASIBLE
Definition: type_stat.h:44
@ SCIP_STATUS_NODELIMIT
Definition: type_stat.h:49
@ SCIP_STATUS_DUALLIMIT
Definition: type_stat.h:58
@ SCIP_STATUS_MEMLIMIT
Definition: type_stat.h:55
@ SCIP_STATUS_RESTARTLIMIT
Definition: type_stat.h:62
enum SCIP_Status SCIP_STATUS
Definition: type_stat.h:64
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65
@ SCIP_VARSTATUS_COLUMN
Definition: type_var.h:53