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