Scippy

SCIP

Solving Constraint Integer Programs

heur_objpscostdiving.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_objpscostdiving.c
26 * @ingroup DEFPLUGINS_HEUR
27 * @brief LP diving heuristic that changes variable's objective value instead of bounds, using pseudo cost values as guide
28 * @author Tobias Achterberg
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_misc.h"
38#include "scip/pub_var.h"
39#include "scip/scip_branch.h"
40#include "scip/scip_exact.h"
41#include "scip/scip_general.h"
42#include "scip/scip_heur.h"
43#include "scip/scip_lp.h"
44#include "scip/scip_mem.h"
45#include "scip/scip_message.h"
46#include "scip/scip_numerics.h"
47#include "scip/scip_param.h"
48#include "scip/scip_prob.h"
50#include "scip/scip_sol.h"
52#include "scip/scip_tree.h"
53#include "scip/scip_var.h"
54#include <string.h>
55
56#define HEUR_NAME "objpscostdiving"
57#define HEUR_DESC "LP diving heuristic that changes variable's objective values instead of bounds, using pseudo costs as guide"
58#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_OBJDIVING
59#define HEUR_PRIORITY -1004000
60#define HEUR_FREQ 20
61#define HEUR_FREQOFS 4
62#define HEUR_MAXDEPTH -1
63#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
64#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
65
66
67/*
68 * Default parameter settings
69 */
70
71#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
72#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
73#define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to total iteration number */
74#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
75#define DEFAULT_MAXSOLS -1 /**< total number of feasible solutions found up to which heuristic is called
76 * (-1: no limit) */
77#define DEFAULT_DEPTHFAC 0.5 /**< maximal diving depth: number of binary/integer variables times depthfac */
78#define DEFAULT_DEPTHFACNOSOL 2.0 /**< maximal diving depth factor if no feasible solution was found yet */
79#define DEFAULT_RANDSEED 139 /**< initial random seed */
80
81#define MINLPITER 10000 /**< minimal number of LP iterations allowed in each LP solving call */
82
83
84/* locally defined heuristic data */
85struct SCIP_HeurData
86{
87 SCIP_SOL* sol; /**< working solution */
88 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
89 SCIP_Real minreldepth; /**< minimal relative depth to start diving */
90 SCIP_Real maxreldepth; /**< maximal relative depth to start diving */
91 SCIP_Real maxlpiterquot; /**< maximal fraction of diving LP iterations compared to total iteration number */
92 int maxlpiterofs; /**< additional number of allowed LP iterations */
93 int maxsols; /**< total number of feasible solutions found up to which heuristic is called
94 * (-1: no limit) */
95 SCIP_Real depthfac; /**< maximal diving depth: number of binary/integer variables times depthfac */
96 SCIP_Real depthfacnosol; /**< maximal diving depth factor if no feasible solution was found yet */
97 SCIP_Longint nlpiterations; /**< LP iterations used in this heuristic */
98 int nsuccess; /**< number of runs that produced at least one feasible solution */
99};
100
101
102/*
103 * local methods
104 */
105
106static
108 SCIP* scip, /**< SCIP data structure */
109 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
110 SCIP_VAR* var, /**< problem variable */
111 SCIP_Real primsol, /**< primal solution of variable */
112 SCIP_Real frac, /**< fractionality of variable */
113 int rounddir, /**< -1: round down, +1: round up, 0: select due to pseudo cost values */
114 SCIP_Real* pscostquot, /**< pointer to store pseudo cost quotient */
115 SCIP_Bool* roundup /**< pointer to store whether the variable should be rounded up */
116 )
117{
118 SCIP_Real pscostdown;
119 SCIP_Real pscostup;
120
121 assert(heurdata != NULL);
122 assert(pscostquot != NULL);
123 assert(roundup != NULL);
124
125 /* bound fractions to not prefer variables that are nearly integral */
126 frac = MAX(frac, 0.1);
127 frac = MIN(frac, 0.9);
128
129 /* get pseudo cost quotient */
130 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0-frac);
131 pscostup = SCIPgetVarPseudocostVal(scip, var, 1.0-frac);
132 assert(pscostdown >= 0.0 && pscostup >= 0.0);
133
134 /* choose rounding direction
135 *
136 * to avoid performance variability caused by numerics we use random numbers to decide whether we want to roundup or
137 * round down if the values to compare are equal within tolerances.
138 */
139 if( rounddir == -1 )
140 *roundup = FALSE;
141 else if( rounddir == +1 )
142 *roundup = TRUE;
143 else if( SCIPisLT(scip, frac, 0.3) || (SCIPisEQ(scip, frac, 0.3) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
144 *roundup = FALSE;
145 else if( SCIPisGT(scip, frac, 0.7) || (SCIPisEQ(scip, frac, 0.7) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
146 *roundup = TRUE;
147 else if( SCIPisLT(scip, primsol, SCIPvarGetRootSol(var) - 0.4)
148 || (SCIPisEQ(scip, primsol, SCIPvarGetRootSol(var) - 0.4) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
149 *roundup = FALSE;
150 else if( SCIPisGT(scip, primsol, SCIPvarGetRootSol(var) + 0.4)
151 || (SCIPisEQ(scip, primsol, SCIPvarGetRootSol(var) + 0.4) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
152 *roundup = TRUE;
153 else if( SCIPisLT(scip, pscostdown, pscostup)
154 || (SCIPisEQ(scip, pscostdown, pscostup) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
155 *roundup = FALSE;
156 else
157 *roundup = TRUE;
158
159 /* calculate pseudo cost quotient */
160 if( *roundup )
161 *pscostquot = sqrt(frac) * (1.0+pscostdown) / (1.0+pscostup);
162 else
163 *pscostquot = sqrt(1.0-frac) * (1.0+pscostup) / (1.0+pscostdown);
164
165 /* prefer decisions on binary variables */
166 if( SCIPvarIsBinary(var) )
167 (*pscostquot) *= 1000.0;
168}
169
170
171/*
172 * Callback methods
173 */
174
175/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
176static
177SCIP_DECL_HEURCOPY(heurCopyObjpscostdiving)
178{ /*lint --e{715}*/
179 assert(scip != NULL);
180 assert(heur != NULL);
181 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
182
183 /* call inclusion method of primal heuristic */
185
186 return SCIP_OKAY;
187}
188
189/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
190static
191SCIP_DECL_HEURFREE(heurFreeObjpscostdiving) /*lint --e{715}*/
192{ /*lint --e{715}*/
193 SCIP_HEURDATA* heurdata;
194
195 assert(heur != NULL);
196 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
197 assert(scip != NULL);
198
199 /* free heuristic data */
200 heurdata = SCIPheurGetData(heur);
201 assert(heurdata != NULL);
202 SCIPfreeBlockMemory(scip, &heurdata);
203 SCIPheurSetData(heur, NULL);
204
205 return SCIP_OKAY;
206}
207
208
209/** initialization method of primal heuristic (called after problem was transformed) */
210static
211SCIP_DECL_HEURINIT(heurInitObjpscostdiving) /*lint --e{715}*/
212{ /*lint --e{715}*/
213 SCIP_HEURDATA* heurdata;
214
215 assert(heur != NULL);
216 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
217
218 /* get heuristic data */
219 heurdata = SCIPheurGetData(heur);
220 assert(heurdata != NULL);
221
222 /* create working solution */
223 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
224
225 /* create random number generator */
226 SCIP_CALL( SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
227
228 /* initialize data */
229 heurdata->nlpiterations = 0;
230 heurdata->nsuccess = 0;
231
232 return SCIP_OKAY;
233}
234
235
236/** deinitialization method of primal heuristic (called before transformed problem is freed) */
237static
238SCIP_DECL_HEUREXIT(heurExitObjpscostdiving) /*lint --e{715}*/
239{ /*lint --e{715}*/
240 SCIP_HEURDATA* heurdata;
241
242 assert(heur != NULL);
243 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
244
245 /* get heuristic data */
246 heurdata = SCIPheurGetData(heur);
247 assert(heurdata != NULL);
248
249 /* free random number generator */
250 SCIPfreeRandom(scip, &heurdata->randnumgen);
251
252 /* free working solution */
253 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
254
255 return SCIP_OKAY;
256}
257
258
259/** execution method of primal heuristic */
260static
261SCIP_DECL_HEUREXEC(heurExecObjpscostdiving) /*lint --e{715}*/
262{ /*lint --e{715}*/
263 SCIP_HEURDATA* heurdata;
264 SCIP_LPSOLSTAT lpsolstat;
265 SCIP_VAR* var;
266 SCIP_VAR** lpcands;
267 SCIP_Real* lpcandssol;
268 SCIP_Real* lpcandsfrac;
269 SCIP_Real primsol;
270 SCIP_Real frac;
271 SCIP_Real pscostquot;
272 SCIP_Real bestpscostquot;
273 SCIP_Real oldobj;
274 SCIP_Real newobj;
275 SCIP_Real objscale;
276 SCIP_Bool bestcandmayrounddown;
277 SCIP_Bool bestcandmayroundup;
278 SCIP_Bool bestcandroundup;
279 SCIP_Bool mayrounddown;
280 SCIP_Bool mayroundup;
281 SCIP_Bool roundup;
282 SCIP_Bool lperror;
283 SCIP_Longint ncalls;
284 SCIP_Longint nsolsfound;
285 SCIP_Longint nlpiterations;
286 SCIP_Longint maxnlpiterations;
287 int* roundings;
288 int nvars;
289 int varidx;
290 int nlpcands;
291 int startnlpcands;
292 int depth;
293 int maxdepth;
294 int maxdivedepth;
295 int divedepth;
296 int bestcand;
297 int c;
298
299 assert(heur != NULL);
300 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
301 assert(scip != NULL);
302 assert(result != NULL);
303 assert(SCIPhasCurrentNodeLP(scip));
304
305 *result = SCIP_DELAYED;
306
307 /* do not call heuristic of node was already detected to be infeasible */
308 if( nodeinfeasible )
309 return SCIP_OKAY;
310
311 /* only call heuristic, if an optimal LP solution is at hand */
313 return SCIP_OKAY;
314
315 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
317 return SCIP_OKAY;
318
319 /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
320 if( !SCIPisLPSolBasic(scip) )
321 return SCIP_OKAY;
322
323 /* don't dive two times at the same node */
325 return SCIP_OKAY;
326
327 *result = SCIP_DIDNOTRUN;
328
329 /* get heuristic's data */
330 heurdata = SCIPheurGetData(heur);
331 assert(heurdata != NULL);
332
333 /* only apply heuristic, if only a few solutions have been found */
334 if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols )
335 return SCIP_OKAY;
336
337 /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
338 depth = SCIPgetDepth(scip);
339 maxdepth = SCIPgetMaxDepth(scip);
340 maxdepth = MAX(maxdepth, 30);
341 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
342 return SCIP_OKAY;
343
344 /* calculate the maximal number of LP iterations until heuristic is aborted */
345 nlpiterations = SCIPgetNNodeLPIterations(scip);
346 ncalls = SCIPheurGetNCalls(heur);
347 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
348 maxnlpiterations = (SCIP_Longint)(((nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
349 maxnlpiterations += heurdata->maxlpiterofs;
350
351 /* don't try to dive, if we took too many LP iterations during diving */
352 if( heurdata->nlpiterations >= maxnlpiterations )
353 return SCIP_OKAY;
354
355 /* allow at least a certain number of LP iterations in this dive */
356 maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
357
358 /* get fractional variables that should be integral */
359 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
360
361 /* don't try to dive, if there are no fractional variables */
362 if( nlpcands == 0 )
363 return SCIP_OKAY;
364
365 /* calculate the maximal diving depth */
367 assert(nvars >= 0);
368 if( SCIPgetNSolsFound(scip) == 0 )
369 maxdivedepth = (int)(heurdata->depthfacnosol * nvars);
370 else
371 maxdivedepth = (int)(heurdata->depthfac * nvars);
372 maxdivedepth = MIN(maxdivedepth, 10*maxdepth);
373
374 *result = SCIP_DIDNOTFIND;
375
376 /* get temporary memory for remembering the current soft roundings */
377 SCIP_CALL( SCIPallocBufferArray(scip, &roundings, nvars) );
378 BMSclearMemoryArray(roundings, nvars);
379
380 /* start diving */
382
383 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing objpscostdiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%" SCIP_LONGINT_FORMAT ", maxdivedepth=%d\n",
384 SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth);
385
386 /* dive as long we are in the given diving depth and iteration limits and fractional variables exist, but
387 * - if the last objective change was in a direction, that corresponds to a feasible rounding, we continue in any case
388 * - if possible, we dive at least with the depth 10
389 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
390 */
391 lperror = FALSE;
392 lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
393 divedepth = 0;
394 startnlpcands = nlpcands;
395 while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
396 && (divedepth < 10
397 || nlpcands <= startnlpcands - divedepth/2
398 || (divedepth < maxdivedepth && nlpcands <= startnlpcands - divedepth/10
399 && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) )
400 {
401 SCIP_RETCODE retcode;
402
403 divedepth++;
404
405 /* choose variable for objective change:
406 * - prefer variables that may not be rounded without destroying LP feasibility:
407 * - of these variables, change objective value of variable with largest rel. difference of pseudo cost values
408 * - if all remaining fractional variables may be rounded without destroying LP feasibility:
409 * - change objective value of variable with largest rel. difference of pseudo cost values
410 */
411 bestcand = -1;
412 bestpscostquot = -1.0;
413 bestcandmayrounddown = TRUE;
414 bestcandmayroundup = TRUE;
415 bestcandroundup = FALSE;
416 for( c = 0; c < nlpcands; ++c )
417 {
418 var = lpcands[c];
419 mayrounddown = SCIPvarMayRoundDown(var);
420 mayroundup = SCIPvarMayRoundUp(var);
421 primsol = lpcandssol[c];
422 frac = lpcandsfrac[c];
423 if( mayrounddown || mayroundup )
424 {
425 /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
426 if( bestcandmayrounddown || bestcandmayroundup )
427 {
428 /* choose rounding direction:
429 * - if variable may be rounded in both directions, round corresponding to the pseudo cost values
430 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
431 * the current fractional solution
432 */
433 roundup = FALSE;
434 if( mayrounddown && mayroundup )
435 calcPscostQuot(scip, heurdata, var, primsol, frac, 0, &pscostquot, &roundup);
436 else if( mayrounddown )
437 calcPscostQuot(scip, heurdata, var, primsol, frac, +1, &pscostquot, &roundup);
438 else
439 calcPscostQuot(scip, heurdata, var, primsol, frac, -1, &pscostquot, &roundup);
440
441 /* prefer variables, that have already been soft rounded but failed to get integral */
442 varidx = SCIPvarGetProbindex(var);
443 assert(0 <= varidx && varidx < nvars);
444 if( roundings[varidx] != 0 )
445 pscostquot *= 1000.0;
446
447 /* check, if candidate is new best candidate */
448 if( pscostquot > bestpscostquot )
449 {
450 bestcand = c;
451 bestpscostquot = pscostquot;
452 bestcandmayrounddown = mayrounddown;
453 bestcandmayroundup = mayroundup;
454 bestcandroundup = roundup;
455 }
456 }
457 }
458 else
459 {
460 /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */
461 calcPscostQuot(scip, heurdata, var, primsol, frac, 0, &pscostquot, &roundup);
462
463 /* prefer variables, that have already been soft rounded but failed to get integral */
464 varidx = SCIPvarGetProbindex(var);
465 assert(0 <= varidx && varidx < nvars);
466 if( roundings[varidx] != 0 )
467 pscostquot *= 1000.0;
468
469 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
470 if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot )
471 {
472 bestcand = c;
473 bestpscostquot = pscostquot;
474 bestcandmayrounddown = FALSE;
475 bestcandmayroundup = FALSE;
476 bestcandroundup = roundup;
477 }
478 }
479 }
480 assert(bestcand != -1);
481
482 /* if all candidates are roundable, try to round the solution */
483 if( bestcandmayrounddown || bestcandmayroundup )
484 {
485 SCIP_Bool success;
486
487 /* create solution from diving LP and try to round it */
488 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
489 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
490
491 if( success && !SCIPisExact(scip) )
492 {
493 SCIPdebugMsg(scip, "objpscostdiving found roundable primal solution: obj=%g\n",
494 SCIPgetSolOrigObj(scip, heurdata->sol));
495
496 /* try to add solution to SCIP */
497 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
498
499 /* check, if solution was feasible and good enough */
500 if( success )
501 {
502 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
503 *result = SCIP_FOUNDSOL;
504 }
505 }
506 }
507
508 var = lpcands[bestcand];
509
510 /* check, if the best candidate was already subject to soft rounding */
511 varidx = SCIPvarGetProbindex(var);
512 assert(0 <= varidx && varidx < nvars);
513 if( roundings[varidx] == +1 )
514 {
515 /* variable was already soft rounded upwards: hard round it downwards */
516 SCIP_CALL( SCIPchgVarUbDive(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) );
517 SCIPdebugMsg(scip, " dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded upwards -> bounds=[%g,%g]\n",
518 divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
519 lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var));
520 }
521 else if( roundings[varidx] == -1 )
522 {
523 /* variable was already soft rounded downwards: hard round it upwards */
524 SCIP_CALL( SCIPchgVarLbDive(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
525 SCIPdebugMsg(scip, " dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded downwards -> bounds=[%g,%g]\n",
526 divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
527 lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var));
528 }
529 else
530 {
531 assert(roundings[varidx] == 0);
532
533 /* apply soft rounding of best candidate via a change in the objective value */
534 objscale = divedepth * 1000.0;
535 oldobj = SCIPgetVarObjDive(scip, var);
536 if( bestcandroundup )
537 {
538 /* soft round variable up: make objective value (more) negative */
539 if( oldobj < 0.0 )
540 newobj = objscale * oldobj;
541 else
542 newobj = -objscale * oldobj;
543 newobj = MIN(newobj, -objscale);
544
545 /* remember, that this variable was soft rounded upwards */
546 roundings[varidx] = +1;
547 }
548 else
549 {
550 /* soft round variable down: make objective value (more) positive */
551 if( oldobj > 0.0 )
552 newobj = objscale * oldobj;
553 else
554 newobj = -objscale * oldobj;
555 newobj = MAX(newobj, objscale);
556
557 /* remember, that this variable was soft rounded downwards */
558 roundings[varidx] = -1;
559 }
560 SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) );
561 SCIPdebugMsg(scip, " dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ": var <%s>, round=%u/%u, sol=%g, bounds=[%g,%g], obj=%g, newobj=%g\n",
562 divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
563 SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
564 lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var), oldobj, newobj);
565 }
566
567 /* resolve the diving LP */
568 nlpiterations = SCIPgetNLPIterations(scip);
569 retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL);
570 lpsolstat = SCIPgetLPSolstat(scip);
571
572 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
573 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
574 */
575 if( retcode != SCIP_OKAY )
576 {
577#ifndef NDEBUG
578 if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY )
579 {
580 SCIP_CALL( retcode );
581 }
582#endif
583 SCIPwarningMessage(scip, "Error while solving LP in Objpscostdiving heuristic; LP solve terminated with code <%d>\n", retcode);
584 SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n");
585 }
586
587 if( lperror )
588 break;
589
590 /* update iteration count */
591 heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
592
593 /* get LP solution status and fractional variables, that should be integral */
594 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
595 {
596 /* get new fractional variables */
597 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
598 }
599 SCIPdebugMsg(scip, " -> lpsolstat=%d, nlpcands=%d\n", lpsolstat, nlpcands);
600 }
601
602 /* check if a solution has been found */
603 if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
604 {
605 SCIP_Bool success;
606
607 /* create solution from diving LP */
608 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
609 SCIPdebugMsg(scip, "objpscostdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
610
611 /* in exact mode we have to end diving prior to trying the solution */
612 if( SCIPisExact(scip) )
613 {
614 SCIP_CALL( SCIPunlinkSol(scip, heurdata->sol) );
616 }
617
618 /* try to add solution to SCIP */
619 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
620
621 /* check, if solution was feasible and good enough */
622 if( success )
623 {
624 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
625 *result = SCIP_FOUNDSOL;
626 }
627 }
628
629 /* end diving */
630 if( SCIPinDive(scip) )
631 {
633 }
634
635 if( *result == SCIP_FOUNDSOL )
636 heurdata->nsuccess++;
637
638 /* free temporary memory for remembering the current soft roundings */
639 SCIPfreeBufferArray(scip, &roundings);
640
641 SCIPdebugMsg(scip, "objpscostdiving heuristic finished\n");
642
643 return SCIP_OKAY; /*lint !e438*/
644}
645
646
647/*
648 * heuristic specific interface methods
649 */
650
651/** creates the objpscostdiving heuristic and includes it in SCIP */
653 SCIP* scip /**< SCIP data structure */
654 )
655{
656 SCIP_HEURDATA* heurdata;
657 SCIP_HEUR* heur;
658
659 /* create Objpscostdiving primal heuristic data */
660 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
661
662 /* include primal heuristic */
665 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecObjpscostdiving, heurdata) );
666
667 assert(heur != NULL);
668
669 /* primal heuristic is safe to use in exact solving mode */
670 SCIPheurMarkExact(heur);
671
672 /* set non-NULL pointers to callback methods */
673 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyObjpscostdiving) );
674 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeObjpscostdiving) );
675 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitObjpscostdiving) );
676 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitObjpscostdiving) );
677
678 /* objpscostdiving heuristic parameters */
680 "heuristics/objpscostdiving/minreldepth",
681 "minimal relative depth to start diving",
682 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
684 "heuristics/objpscostdiving/maxreldepth",
685 "maximal relative depth to start diving",
686 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
688 "heuristics/objpscostdiving/maxlpiterquot",
689 "maximal fraction of diving LP iterations compared to total iteration number",
690 &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, 1.0, NULL, NULL) );
692 "heuristics/objpscostdiving/maxlpiterofs",
693 "additional number of allowed LP iterations",
694 &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
696 "heuristics/objpscostdiving/maxsols",
697 "total number of feasible solutions found up to which heuristic is called (-1: no limit)",
698 &heurdata->maxsols, TRUE, DEFAULT_MAXSOLS, -1, INT_MAX, NULL, NULL) );
700 "heuristics/objpscostdiving/depthfac",
701 "maximal diving depth: number of binary/integer variables times depthfac",
702 &heurdata->depthfac, TRUE, DEFAULT_DEPTHFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
704 "heuristics/objpscostdiving/depthfacnosol",
705 "maximal diving depth factor if no feasible solution was found yet",
706 &heurdata->depthfacnosol, TRUE, DEFAULT_DEPTHFACNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
707
708 return SCIP_OKAY;
709}
710
#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 MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_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
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 SCIPincludeHeurObjpscostdiving(SCIP *scip)
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
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 SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
Definition: var.c:4484
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
Definition: var.c:4473
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
Definition: var.c:19115
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:11188
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10223
static void calcPscostQuot(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR *var, SCIP_Real primsol, SCIP_Real frac, int rounddir, SCIP_Real *pscostquot, SCIP_Bool *roundup)
static SCIP_DECL_HEUREXEC(heurExecObjpscostdiving)
#define DEFAULT_DEPTHFAC
#define HEUR_TIMING
static SCIP_DECL_HEUREXIT(heurExitObjpscostdiving)
#define DEFAULT_MAXLPITERQUOT
#define HEUR_FREQOFS
#define HEUR_DESC
static SCIP_DECL_HEURINIT(heurInitObjpscostdiving)
#define MINLPITER
#define HEUR_DISPCHAR
#define HEUR_MAXDEPTH
#define HEUR_PRIORITY
#define DEFAULT_MAXRELDEPTH
#define DEFAULT_MAXLPITEROFS
#define HEUR_NAME
#define DEFAULT_DEPTHFACNOSOL
#define DEFAULT_RANDSEED
static SCIP_DECL_HEURCOPY(heurCopyObjpscostdiving)
#define HEUR_FREQ
#define DEFAULT_MINRELDEPTH
#define DEFAULT_MAXSOLS
#define HEUR_USESSUBSCIP
static SCIP_DECL_HEURFREE(heurFreeObjpscostdiving)
LP diving heuristic that changes variable's objective value instead of bounds, using pseudo cost valu...
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for primal heuristics
public methods for message output
public data structures and miscellaneous methods
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 random numbers
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
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_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