Scippy

SCIP

Solving Constraint Integer Programs

heur_rootsoldiving.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file heur_rootsoldiving.c
26 * @ingroup DEFPLUGINS_HEUR
27 * @brief LP diving heuristic that changes variable's objective values using root LP solution as guide
28 * @author Kati Wolter
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
35#include "scip/pub_heur.h"
36#include "scip/pub_message.h"
37#include "scip/pub_var.h"
38#include "scip/scip_branch.h"
39#include "scip/scip_exact.h"
40#include "scip/scip_general.h"
41#include "scip/scip_heur.h"
42#include "scip/scip_lp.h"
43#include "scip/scip_mem.h"
44#include "scip/scip_message.h"
45#include "scip/scip_numerics.h"
46#include "scip/scip_param.h"
47#include "scip/scip_prob.h"
48#include "scip/scip_sol.h"
50#include "scip/scip_tree.h"
51#include <string.h>
52
53#define HEUR_NAME "rootsoldiving"
54#define HEUR_DESC "LP diving heuristic that changes variable's objective values using root LP solution as guide"
55#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_OBJDIVING
56#define HEUR_PRIORITY -1005000
57#define HEUR_FREQ 20
58#define HEUR_FREQOFS 5
59#define HEUR_MAXDEPTH -1
60#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
61#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
62
63
64/*
65 * Default parameter settings
66 */
67
68#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
69#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
70#define DEFAULT_MAXLPITERQUOT 0.01 /**< maximal fraction of diving LP iterations compared to node LP iterations */
71#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
72#define DEFAULT_MAXSOLS -1 /**< total number of feasible solutions found up to which heuristic is called
73 * (-1: no limit) */
74#define DEFAULT_DEPTHFAC 0.5 /**< maximal diving depth: number of binary/integer variables times depthfac */
75#define DEFAULT_DEPTHFACNOSOL 2.0 /**< maximal diving depth factor if no feasible solution was found yet */
76
77#define MINLPITER 10000 /**< minimal number of LP iterations allowed in each LP solving call */
78#define DEFAULT_ALPHA 0.9 /**< soft rounding factor to fade out objective coefficients */
79
80
81/* locally defined heuristic data */
82struct SCIP_HeurData
83{
84 SCIP_SOL* sol; /**< working solution */
85 SCIP_Real minreldepth; /**< minimal relative depth to start diving */
86 SCIP_Real maxreldepth; /**< maximal relative depth to start diving */
87 SCIP_Real maxlpiterquot; /**< maximal fraction of diving LP iterations compared to node LP iterations */
88 int maxlpiterofs; /**< additional number of allowed LP iterations */
89 int maxsols; /**< total number of feasible solutions found up to which heuristic is called
90 * (-1: no limit) */
91 SCIP_Real depthfac; /**< maximal diving depth: number of binary/integer variables times depthfac */
92 SCIP_Real depthfacnosol; /**< maximal diving depth factor if no feasible solution was found yet */
93 SCIP_Real alpha; /**< soft rounding factor to fade out objective coefficients */
94 SCIP_Longint nlpiterations; /**< LP iterations used in this heuristic */
95 int nsuccess; /**< number of runs that produced at least one feasible solution */
96};
97
98
99/*
100 * Callback methods
101 */
102
103/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
104static
105SCIP_DECL_HEURCOPY(heurCopyRootsoldiving)
106{ /*lint --e{715}*/
107 assert(scip != NULL);
108 assert(heur != NULL);
109 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
110
111 /* call inclusion method of primal heuristic */
113
114 return SCIP_OKAY;
115}
116
117/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
118static
119SCIP_DECL_HEURFREE(heurFreeRootsoldiving) /*lint --e{715}*/
120{ /*lint --e{715}*/
121 SCIP_HEURDATA* heurdata;
122
123 assert(heur != NULL);
124 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
125 assert(scip != NULL);
126
127 /* free heuristic data */
128 heurdata = SCIPheurGetData(heur);
129 assert(heurdata != NULL);
130 SCIPfreeBlockMemory(scip, &heurdata);
131 SCIPheurSetData(heur, NULL);
132
133 return SCIP_OKAY;
134}
135
136
137/** initialization method of primal heuristic (called after problem was transformed) */
138static
139SCIP_DECL_HEURINIT(heurInitRootsoldiving) /*lint --e{715}*/
140{ /*lint --e{715}*/
141 SCIP_HEURDATA* heurdata;
142
143 assert(heur != NULL);
144 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
145
146 /* get heuristic data */
147 heurdata = SCIPheurGetData(heur);
148 assert(heurdata != NULL);
149
150 /* create working solution */
151 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
152
153 /* initialize data */
154 heurdata->nlpiterations = 0;
155 heurdata->nsuccess = 0;
156
157 return SCIP_OKAY;
158}
159
160
161/** deinitialization method of primal heuristic (called before transformed problem is freed) */
162static
163SCIP_DECL_HEUREXIT(heurExitRootsoldiving) /*lint --e{715}*/
164{ /*lint --e{715}*/
165 SCIP_HEURDATA* heurdata;
166
167 assert(heur != NULL);
168 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
169
170 /* get heuristic data */
171 heurdata = SCIPheurGetData(heur);
172 assert(heurdata != NULL);
173
174 /* free working solution */
175 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
176
177 return SCIP_OKAY;
178}
179
180
181/** execution method of primal heuristic */
182static
183SCIP_DECL_HEUREXEC(heurExecRootsoldiving) /*lint --e{715}*/
184{ /*lint --e{715}*/
185 SCIP_HEURDATA* heurdata;
186 SCIP_VAR** vars;
187 SCIP_Real* rootsol;
188 SCIP_Real* objchgvals;
189 int* softroundings;
190 int* intvalrounds;
191 SCIP_LPSOLSTAT lpsolstat;
192 SCIP_Real absstartobjval;
193 SCIP_Real objstep;
194 SCIP_Real alpha;
195 SCIP_Real oldobj;
196 SCIP_Real newobj;
197 SCIP_Bool lperror;
198 SCIP_Bool lpsolchanged;
199 SCIP_Longint nsolsfound;
200 SCIP_Longint ncalls;
201 SCIP_Longint nlpiterations;
202 SCIP_Longint maxnlpiterations;
203 int nvars;
204 int nenfovars;
205 int nlpcands;
206 int depth;
207 int maxdepth;
208 int maxdivedepth;
209 int divedepth;
210 int startnlpcands;
211 int ncycles;
212 int i;
213
214 assert(heur != NULL);
215 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
216 assert(scip != NULL);
217 assert(result != NULL);
218 assert(SCIPhasCurrentNodeLP(scip));
219
220 *result = SCIP_DELAYED;
221
222 /* do not call heuristic of node was already detected to be infeasible */
223 if( nodeinfeasible )
224 return SCIP_OKAY;
225
226 /* only call heuristic, if an optimal LP solution is at hand */
228 return SCIP_OKAY;
229
230 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
232 return SCIP_OKAY;
233
234 /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
235 if( !SCIPisLPSolBasic(scip) )
236 return SCIP_OKAY;
237
238 /* don't dive two times at the same node */
240 return SCIP_OKAY;
241
242 *result = SCIP_DIDNOTRUN;
243
244 /* get heuristic's data */
245 heurdata = SCIPheurGetData(heur);
246 assert(heurdata != NULL);
247
248 /* only apply heuristic, if only a few solutions have been found */
249 if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols )
250 return SCIP_OKAY;
251
252 /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
253 depth = SCIPgetDepth(scip);
254 maxdepth = SCIPgetMaxDepth(scip);
255 maxdepth = MAX(maxdepth, 30);
256 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
257 return SCIP_OKAY;
258
259 /* calculate the maximal number of LP iterations until heuristic is aborted */
260 nlpiterations = SCIPgetNNodeLPIterations(scip);
261 ncalls = SCIPheurGetNCalls(heur);
262 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
263 maxnlpiterations = (SCIP_Longint)(((nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
264 maxnlpiterations += heurdata->maxlpiterofs;
265
266 /* don't try to dive, if we took too many LP iterations during diving */
267 if( heurdata->nlpiterations >= maxnlpiterations )
268 return SCIP_OKAY;
269
270 /* allow at least a certain number of LP iterations in this dive */
271 maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
272
273 /* get number of fractional variables, that should be integral */
274 nlpcands = SCIPgetNLPBranchCands(scip);
275
276 /* don't try to dive, if there are no fractional variables */
277 if( nlpcands == 0 )
278 return SCIP_OKAY;
279
280 /* get all variables of LP */
281 vars = SCIPgetVars(scip);
282 nvars = SCIPgetNVars(scip);
283 nenfovars = nvars - SCIPgetNContVars(scip) - SCIPgetNContImplVars(scip);
284 assert(nenfovars >= 0);
285
286 /* calculate the maximal diving depth */
287 if( SCIPgetNSolsFound(scip) == 0 )
288 maxdivedepth = (int)(heurdata->depthfacnosol * nenfovars);
289 else
290 maxdivedepth = (int)(heurdata->depthfac * nenfovars);
291 maxdivedepth = MAX(maxdivedepth, 10);
292
293 *result = SCIP_DIDNOTFIND;
294
295 /* get root solution value of all binary and integer variables */
296 SCIP_CALL( SCIPallocBufferArray(scip, &rootsol, nenfovars) );
297 for( i = 0; i < nenfovars; i++ )
298 rootsol[i] = SCIPvarGetRootSol(vars[i]);
299
300 /* get current LP objective value, and calculate length of a single step in an objective coefficient */
301 absstartobjval = SCIPgetLPObjval(scip);
302 absstartobjval = ABS(absstartobjval);
303 absstartobjval = MAX(absstartobjval, 1.0);
304 objstep = absstartobjval / 10.0;
305
306 /* initialize array storing the preferred soft rounding directions and counting the integral value rounds */
307 SCIP_CALL( SCIPallocBufferArray(scip, &softroundings, nenfovars) );
308 BMSclearMemoryArray(softroundings, nenfovars);
309 SCIP_CALL( SCIPallocBufferArray(scip, &intvalrounds, nenfovars) );
310 BMSclearMemoryArray(intvalrounds, nenfovars);
311
312 /* allocate temporary memory for buffering objective changes */
313 SCIP_CALL( SCIPallocBufferArray(scip, &objchgvals, nenfovars) );
314
315 /* start diving */
317
318 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing rootsoldiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%" SCIP_LONGINT_FORMAT ", maxdivedepth=%d, LPobj=%g, objstep=%g\n",
319 SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth,
320 SCIPgetLPObjval(scip), objstep);
321
322 lperror = FALSE;
323 divedepth = 0;
324 lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
325 alpha = heurdata->alpha;
326 ncycles = 0;
327 lpsolchanged = TRUE;
328 startnlpcands = nlpcands;
329 while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && ncycles < 10
330 && (divedepth < 10
331 || nlpcands <= startnlpcands - divedepth/2
332 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations))
333 && !SCIPisStopped(scip) )
334 {
335 SCIP_Bool success;
336 int hardroundingidx;
337 int hardroundingdir;
338 SCIP_Real hardroundingoldbd;
339 SCIP_Real hardroundingnewbd;
340 SCIP_Bool boundschanged;
341
342 SCIP_RETCODE retcode;
343
344 /* create solution from diving LP and try to round it */
345 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
346 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
347
348 if( success && !SCIPisExact(scip) )
349 {
350 SCIPdebugMsg(scip, "rootsoldiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
351
352 /* try to add solution to SCIP */
353 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
354
355 /* check, if solution was feasible and good enough */
356 if( success )
357 {
358 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
359 *result = SCIP_FOUNDSOL;
360 }
361 }
362
363 divedepth++;
364 hardroundingidx = -1;
365 hardroundingdir = 0;
366 hardroundingoldbd = 0.0;
367 hardroundingnewbd = 0.0;
368 boundschanged = FALSE;
369
370 SCIPdebugMsg(scip, "dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ":\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations);
371
372 /* round solution x* from diving LP:
373 * - x~_j = down(x*_j) if x*_j is integer or binary variable and x*_j <= root solution_j
374 * - x~_j = up(x*_j) if x*_j is integer or binary variable and x*_j > root solution_j
375 * - x~_j = x*_j if x*_j is continuous variable
376 * change objective function in diving LP:
377 * - if x*_j is integral, or j is a continuous variable, set obj'_j = alpha * obj_j
378 * - otherwise, set obj'_j = alpha * obj_j + sign(x*_j - x~_j)
379 */
380 for( i = 0; i < nenfovars; i++ )
381 {
382 SCIP_VAR* var;
383 SCIP_Real solval;
384
385 var = vars[i];
386 oldobj = SCIPgetVarObjDive(scip, var);
387 newobj = oldobj;
388
389 solval = SCIPvarGetLPSol(var);
390 if( SCIPisFeasIntegral(scip, solval) )
391 {
392 /* if the variable became integral after a soft rounding, count the rounds; after a while, fix it to its
393 * current integral value;
394 * otherwise, fade out the objective value
395 */
396 if( softroundings[i] != 0 && lpsolchanged )
397 {
398 intvalrounds[i]++;
399 if( intvalrounds[i] == 5 && SCIPgetVarLbDive(scip, var) < SCIPgetVarUbDive(scip, var) - 0.5 )
400 {
401 /* use exact integral value, if the variable is only integral within numerical tolerances */
402 solval = SCIPfloor(scip, solval+0.5);
403 SCIPdebugMsg(scip, " -> fixing <%s> = %g\n", SCIPvarGetName(var), solval);
404 SCIP_CALL( SCIPchgVarLbDive(scip, var, solval) );
405 SCIP_CALL( SCIPchgVarUbDive(scip, var, solval) );
406 boundschanged = TRUE;
407 }
408 }
409 else
410 newobj = alpha * oldobj;
411 }
412 else if( solval <= rootsol[i] )
413 {
414 /* if the variable was soft rounded most of the time downwards, round it downwards by changing the bounds;
415 * otherwise, apply soft rounding by changing the objective value
416 */
417 softroundings[i]--;
418 if( softroundings[i] <= -10 && hardroundingidx == -1 )
419 {
420 SCIPdebugMsg(scip, " -> hard rounding <%s>[%g] <= %g\n",
421 SCIPvarGetName(var), solval, SCIPfeasFloor(scip, solval));
422 hardroundingidx = i;
423 hardroundingdir = -1;
424 hardroundingoldbd = SCIPgetVarUbDive(scip, var);
425 hardroundingnewbd = SCIPfeasFloor(scip, solval);
426 SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd) );
427 boundschanged = TRUE;
428 }
429 else
430 newobj = alpha * oldobj + objstep;
431 }
432 else
433 {
434 /* if the variable was soft rounded most of the time upwards, round it upwards by changing the bounds;
435 * otherwise, apply soft rounding by changing the objective value
436 */
437 softroundings[i]++;
438 if( softroundings[i] >= +10 && hardroundingidx == -1 )
439 {
440 SCIPdebugMsg(scip, " -> hard rounding <%s>[%g] >= %g\n",
441 SCIPvarGetName(var), solval, SCIPfeasCeil(scip, solval));
442 hardroundingidx = i;
443 hardroundingdir = +1;
444 hardroundingoldbd = SCIPgetVarLbDive(scip, var);
445 hardroundingnewbd = SCIPfeasCeil(scip, solval);
446 SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd) );
447 boundschanged = TRUE;
448 }
449 else
450 newobj = alpha * oldobj - objstep;
451 }
452
453 /* remember the objective change */
454 objchgvals[i] = newobj;
455 }
456
457 /* apply objective changes if there was no bound change */
458 if( !boundschanged )
459 {
460 /* apply cached changes on integer variables */
461 for( i = 0; i < nenfovars; ++i )
462 {
463 SCIP_VAR* var;
464
465 var = vars[i];
466 SCIPdebugMsg(scip, " -> i=%d var <%s>, solval=%g, rootsol=%g, oldobj=%g, newobj=%g\n",
467 i, SCIPvarGetName(var), SCIPvarGetLPSol(var), rootsol[i], SCIPgetVarObjDive(scip, var), objchgvals[i]);
468
469 SCIP_CALL( SCIPchgVarObjDive(scip, var, objchgvals[i]) );
470 }
471
472 /* fade out the objective values of the continuous variables */
473 for( i = nenfovars; i < nvars; i++ )
474 {
475 SCIP_VAR* var;
476
477 var = vars[i];
478 oldobj = SCIPgetVarObjDive(scip, var);
479 newobj = alpha * oldobj;
480
481 SCIPdebugMsg(scip, " -> i=%d var <%s>, solval=%g, oldobj=%g, newobj=%g\n",
482 i, SCIPvarGetName(var), SCIPvarGetLPSol(var), oldobj, newobj);
483
484 SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) );
485 }
486 }
487
488 SOLVEAGAIN:
489 /* resolve the diving LP */
490 nlpiterations = SCIPgetNLPIterations(scip);
491
492 retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL);
493 lpsolstat = SCIPgetLPSolstat(scip);
494
495 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
496 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
497 */
498 if( retcode != SCIP_OKAY )
499 {
500#ifndef NDEBUG
501 if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY )
502 {
503 SCIP_CALL( retcode );
504 }
505#endif
506 SCIPwarningMessage(scip, "Error while solving LP in Rootsoldiving heuristic; LP solve terminated with code <%d>\n", retcode);
507 SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n");
508 }
509
510 if( lperror )
511 break;
512
513 /* update iteration count */
514 heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
515
516 /* if no LP iterations were performed, we stayed at the same solution -> count this cycling */
517 lpsolchanged = (SCIPgetNLPIterations(scip) != nlpiterations);
518 if( lpsolchanged )
519 ncycles = 0;
520 else if( !boundschanged ) /* do not count if integral variables have been fixed */
521 ncycles++;
522
523 /* get LP solution status and number of fractional variables, that should be integral */
524 if( lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE && hardroundingidx != -1 )
525 {
526 SCIP_VAR* var;
527
528 var = vars[hardroundingidx];
529
530 /* round the hard rounded variable to the opposite direction and resolve the LP */
531 if( hardroundingdir == -1 )
532 {
533 SCIPdebugMsg(scip, " -> opposite hard rounding <%s> >= %g\n", SCIPvarGetName(var), hardroundingnewbd + 1.0);
534 SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingoldbd) );
535 SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd + 1.0) );
536 }
537 else
538 {
539 SCIPdebugMsg(scip, " -> opposite hard rounding <%s> <= %g\n", SCIPvarGetName(var), hardroundingnewbd - 1.0);
540 SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingoldbd) );
541 SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd - 1.0) );
542 }
543 hardroundingidx = -1;
544 goto SOLVEAGAIN;
545 }
546 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
547 nlpcands = SCIPgetNLPBranchCands(scip);
548 SCIPdebugMsg(scip, " -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands);
549 }
550
551 SCIPdebugMsg(scip, "---> diving finished: lpsolstat = %d, depth %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT "\n",
552 lpsolstat, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations);
553
554 /* check if a solution has been found */
555 if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
556 {
557 SCIP_Bool success;
558
559 /* create solution from diving LP */
560 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
561 SCIPdebugMsg(scip, "rootsoldiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
562
563 /* in exact mode we have to end diving prior to trying the solution */
564 if( SCIPisExact(scip) )
565 {
566 SCIP_CALL( SCIPunlinkSol(scip, heurdata->sol) );
568 }
569
570 /* try to add solution to SCIP */
571 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
572
573 /* check, if solution was feasible and good enough */
574 if( success )
575 {
576 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
577 *result = SCIP_FOUNDSOL;
578 }
579 }
580
581 /* end diving */
582 if( SCIPinDive(scip) )
583 {
585 }
586
587 if( *result == SCIP_FOUNDSOL )
588 heurdata->nsuccess++;
589
590 /* free temporary memory */
591 SCIPfreeBufferArray(scip, &objchgvals);
592 SCIPfreeBufferArray(scip, &intvalrounds);
593 SCIPfreeBufferArray(scip, &softroundings);
594 SCIPfreeBufferArray(scip, &rootsol);
595
596 SCIPdebugMsg(scip, "rootsoldiving heuristic finished\n");
597
598 return SCIP_OKAY;
599}
600
601
602/*
603 * heuristic specific interface methods
604 */
605
606/** creates the rootsoldiving heuristic and includes it in SCIP */
608 SCIP* scip /**< SCIP data structure */
609 )
610{
611 SCIP_HEURDATA* heurdata;
612 SCIP_HEUR* heur;
613
614 /* create Rootsoldiving primal heuristic data */
615 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
616
617 /* include primal heuristic */
620 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecRootsoldiving, heurdata) );
621
622 assert(heur != NULL);
623
624 /* primal heuristic is safe to use in exact solving mode */
625 SCIPheurMarkExact(heur);
626
627 /* set non-NULL pointers to callback methods */
628 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyRootsoldiving) );
629 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeRootsoldiving) );
630 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitRootsoldiving) );
631 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitRootsoldiving) );
632
633 /* rootsoldiving heuristic parameters */
635 "heuristics/rootsoldiving/minreldepth",
636 "minimal relative depth to start diving",
637 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
639 "heuristics/rootsoldiving/maxreldepth",
640 "maximal relative depth to start diving",
641 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
643 "heuristics/rootsoldiving/maxlpiterquot",
644 "maximal fraction of diving LP iterations compared to node LP iterations",
645 &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
647 "heuristics/rootsoldiving/maxlpiterofs",
648 "additional number of allowed LP iterations",
649 &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
651 "heuristics/rootsoldiving/maxsols",
652 "total number of feasible solutions found up to which heuristic is called (-1: no limit)",
653 &heurdata->maxsols, TRUE, DEFAULT_MAXSOLS, -1, INT_MAX, NULL, NULL) );
655 "heuristics/rootsoldiving/depthfac",
656 "maximal diving depth: number of binary/integer variables times depthfac",
657 &heurdata->depthfac, TRUE, DEFAULT_DEPTHFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
659 "heuristics/rootsoldiving/depthfacnosol",
660 "maximal diving depth factor if no feasible solution was found yet",
661 &heurdata->depthfacnosol, TRUE, DEFAULT_DEPTHFACNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
663 "heuristics/rootsoldiving/alpha",
664 "soft rounding factor to fade out objective coefficients",
665 &heurdata->alpha, TRUE, DEFAULT_ALPHA, 0.0, 1.0, NULL, NULL) );
666
667 return SCIP_OKAY;
668}
669
#define NULL
Definition: def.h:248
#define SCIP_Longint
Definition: def.h:141
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define ABS(x)
Definition: def.h:216
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
int SCIPgetNContImplVars(SCIP *scip)
Definition: scip_prob.c:2522
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
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 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 SCIPincludeHeurRootsoldiving(SCIP *scip)
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_Bool SCIPisExact(SCIP *scip)
Definition: scip_exact.c:193
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip_heur.c:167
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1368
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip_heur.c:122
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip_heur.c:183
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
Definition: scip_heur.c:215
SCIP_Longint SCIPheurGetNBestSolsFound(SCIP_HEUR *heur)
Definition: heur.c:1613
SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
Definition: heur.c:1593
void SCIPheurMarkExact(SCIP_HEUR *heur)
Definition: heur.c:1457
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip_heur.c:199
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1467
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:1378
SCIP_RETCODE SCIPchgVarLbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_lp.c:2384
SCIP_RETCODE SCIPchgVarUbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_lp.c:2416
SCIP_Real SCIPgetVarLbDive(SCIP *scip, SCIP_VAR *var)
Definition: scip_lp.c:2581
SCIP_Real SCIPgetVarUbDive(SCIP *scip, SCIP_VAR *var)
Definition: scip_lp.c:2610
SCIP_Real SCIPgetVarObjDive(SCIP *scip, SCIP_VAR *var)
Definition: scip_lp.c:2552
SCIP_RETCODE SCIPstartDive(SCIP *scip)
Definition: scip_lp.c:2206
SCIP_RETCODE SCIPchgVarObjDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_lp.c:2343
SCIP_RETCODE SCIPsolveDiveLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_lp.c:2643
SCIP_RETCODE SCIPendDive(SCIP *scip)
Definition: scip_lp.c:2255
SCIP_Bool SCIPinDive(SCIP *scip)
Definition: scip_lp.c:2740
SCIP_Longint SCIPgetLastDivenode(SCIP *scip)
Definition: scip_lp.c:2710
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip_lp.c:87
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:673
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1506
SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
Definition: scip_sol.c:3123
SCIP_RETCODE SCIPtrySol(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:4012
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1295
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1892
SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
int SCIPgetMaxDepth(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Real SCIPgetDualbound(SCIP *scip)
SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
Definition: var.c:19115
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:24664
static SCIP_DECL_HEURCOPY(heurCopyRootsoldiving)
#define DEFAULT_DEPTHFAC
#define HEUR_TIMING
static SCIP_DECL_HEURFREE(heurFreeRootsoldiving)
#define DEFAULT_MAXLPITERQUOT
#define HEUR_FREQOFS
#define HEUR_DESC
#define MINLPITER
static SCIP_DECL_HEUREXIT(heurExitRootsoldiving)
#define HEUR_DISPCHAR
#define HEUR_MAXDEPTH
#define HEUR_PRIORITY
#define DEFAULT_MAXRELDEPTH
#define DEFAULT_MAXLPITEROFS
#define HEUR_NAME
#define DEFAULT_DEPTHFACNOSOL
static SCIP_DECL_HEUREXEC(heurExecRootsoldiving)
#define DEFAULT_ALPHA
#define HEUR_FREQ
#define DEFAULT_MINRELDEPTH
#define DEFAULT_MAXSOLS
#define HEUR_USESSUBSCIP
static SCIP_DECL_HEURINIT(heurInitRootsoldiving)
LP diving heuristic that changes variables' objective values using root LP solution as guide.
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for primal heuristics
public methods for message output
public methods for problem variables
public methods for branching rule plugins and branching
public methods for exact solving
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 numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:77
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:52
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition: type_lp.h:46
@ SCIP_LPSOLSTAT_INFEASIBLE
Definition: type_lp.h:45
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_DELAYED
Definition: type_result.h:43
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_FOUNDSOL
Definition: type_result.h:56
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63