Exercise: a Rounding Heuristic

advertisement
TU Berlin
ADM3: Computational Mixed Integer Programming
Exercise: a Rounding Heuristic
T. Berthold, M. Lübbecke
Rounding heuristics try to set integer variables which take a fractional value in a given LP
solution x? to a feasible integral value. A simple criterion which direction is suitable for
rounding are the locking numbers of a variable: for a linear system Ax ≤ b, the number of
downlocks of a variable is the number of linear constraints in which the variable appears
with a negative coefficient. The number of uplocks is the number of inequalities in which
the variable appears with a positive coefficient.
If a variable xj has no down-/up-locks, then rounding down/up the value of x?j maintains linear feasibility. Implement a Rounding heuristic, which rounds variables if they
have a direction without rounding locks. If this holds for all fractional variables, the
heuristic will produce a feasible solution, otherwise it should abort.
Getting started
In order to be efficient, we will only use one working solution for all calls of the heuristics.
Furthermore, we only want to compute the number of “easy-roundable” variables once.
Therefore, we use a global data structure, the SCIP HEURDATA. It has to be allocated in
SCIP DECL HEURINIT and freed in SCIP DECL HEUREXIT.
(a) Fill in a SCIP SOL* workingsolution and an int nroundablevars into the global
structure SCIP HeurData.
(b) In SCIPincludeHeurRounding(), allocate memory for your heuristic data using
SCIP RETCODE SCIPallocMemory(SCIP* scip, HEURDATA* heurdata).
(c) Implement SCIP DECL HEURINIT: Get your heuristic data with SCIP HEURDATA*
SCIPheurGetData(SCIP HEUR* heur), and set up the working solution in your heuristic data with SCIPcreateSol(SCIP* scip, SCIP SOL** sol, SCIP HEUR* heur).
Finally, count the number of roundable variables and store the information in your
data structure.
(d) Implement SCIP DECL HEUREXIT: Get your heuristic data, free the working solution
with SCIP RETCODE SCIPfreeSol(SCIP* scip, SCIP SOL** sol) and the heuristic’s
data structure with SCIPfreeMemory(SCIP* scip, SCIP HEURDATA** heurdata).
Hints:
◦ SCIP Bool SCIPvarMayRoundUp(SCIP VAR* var) returns the number of uplocks for
a given variable.
◦ SCIP RETCODE SCIPgetVarsData(SCIP* scip, SCIP VAR*** vars, int* nvars,
int* nbinvars, int* nintvars, int* nimplvars, int* ncontvars) provides
you information about the problem’s variables.
Implementing the fundamental callbacks
The fundamental callback of a heuristic is its execution method.
(a) Your heuristic may be called for every LP solution, so the best timing probably is
SCIP HEURTIMING DURINGLPLOOP.
1
(b) Get the fractional variables of the current LP solution and start your heuristic if there
is an appropriate number of them. Remember? The fractional variables are the LP
branching candidates.
(c) SCIP RETCODE SCIPlinkLPSol(SCIP* scip, SCIP SOL* sol) “copies” the current
LP solution to your working solution.
(d) Now iterate over all fractional variables, if possible round them by changing their
solution value with SCIPsetSolVal(SCIP* scip, SCIP SOL* sol, SCIP VAR* var,
SCIP Real val). If you find a variable which is neither down- nor up-roundable,
abort.
(e) If you were able to round all variables, hand over the solution by SCIP RETCODE
SCIPtrySol(SCIP* scip, SCIP SOL* sol, SCIP Bool checkbounds, SCIP Bool
checkintegrality, SCIP Bool checklprows, SCIP Bool* stored). If scip accepted your solution, set the result pointer to SCIP FOUNDSOL. If you searched for a solution, but did not succeed, it should be SCIP DIDNOTFIND, otherwise SCIP DIDNOTRUN.
Hints:
◦ If you do not want to carry around the heuristic’s data structure all the time, just
set a local pointer to your working solution.
SCIP HEURDATA* heurdata;
SCIP SOL* workingsolution;
heurdata = SCIPheurGetData(heur);
workingsolution = heurdata->workingsolution;
Additional exercise
(a) It is quite annoying to break, just because there are some variables with positive
locking numbers. Think about a heuristic which may also handle those variables.
Additional information
(a) Analogously to your plugin soecific data structures you may set up and destroy
arrays: SCIP RETCODE SCIPallocBufferArray(SCIP* scip, <yourarray>*, int*
length) and SCIP RETCODE SCIPfreeBufferArray(SCIP* scip, <yourarray>*) do
want you want.
(b) You may add your own user parameters to your plugin. This is quite comfortable
for testing. Check out methods called SCIPadd<Datatype>Param. They are called in
the SCIPinclude<YourPlugin>(). E.g., SCIPincludeHeurLocalbranching() adds a
modifiable parameter via calling
SCIPaddIntParam(scip, "heuristics/localbranching/neighborhoodsize",
"radius (in Manhattan metric) of the incumbent’s neighborhood",
&heurdata->neighborhoodsize, FALSE, 18, 1, INT MAX, NULL, NULL).
(c) Now may change parameters in the interactive shell: “se heur loc nei 42”, and store
the settings: “se diff settings/theanswer.set”.
(d) A call of “make TEST=instances TIME=60 SETTINGS=theanswer test” starts a test
run whose results will be saved in “check/results/check.instances.<. . . >.theanswer.res”.
You may include several of these calls into a shell script.
2
Download