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-2026 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
    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
    183
    184 /* call inclusion method of primal heuristic */
    186
    187 return SCIP_OKAY;
    188}
    189
    190/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    191static
    192SCIP_DECL_HEURFREE(heurFreeObjpscostdiving) /*lint --e{715}*/
    193{ /*lint --e{715}*/
    194 SCIP_HEURDATA* heurdata;
    195
    196 assert(heur != NULL);
    197 assert(scip != NULL);
    198
    200
    201 /* free heuristic data */
    202 heurdata = SCIPheurGetData(heur);
    203 assert(heurdata != NULL);
    204 SCIPfreeBlockMemory(scip, &heurdata);
    205 SCIPheurSetData(heur, NULL);
    206
    207 return SCIP_OKAY;
    208}
    209
    210
    211/** initialization method of primal heuristic (called after problem was transformed) */
    212static
    213SCIP_DECL_HEURINIT(heurInitObjpscostdiving) /*lint --e{715}*/
    214{ /*lint --e{715}*/
    215 SCIP_HEURDATA* heurdata;
    216
    217 assert(heur != NULL);
    218
    220
    221 /* get heuristic data */
    222 heurdata = SCIPheurGetData(heur);
    223 assert(heurdata != NULL);
    224
    225 /* create working solution */
    226 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    227
    228 /* create random number generator */
    229 SCIP_CALL( SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
    230
    231 /* initialize data */
    232 heurdata->nlpiterations = 0;
    233 heurdata->nsuccess = 0;
    234
    235 return SCIP_OKAY;
    236}
    237
    238
    239/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    240static
    241SCIP_DECL_HEUREXIT(heurExitObjpscostdiving) /*lint --e{715}*/
    242{ /*lint --e{715}*/
    243 SCIP_HEURDATA* heurdata;
    244
    245 assert(heur != NULL);
    246
    248
    249 /* get heuristic data */
    250 heurdata = SCIPheurGetData(heur);
    251 assert(heurdata != NULL);
    252
    253 /* free random number generator */
    254 SCIPfreeRandom(scip, &heurdata->randnumgen);
    255
    256 /* free working solution */
    257 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    258
    259 return SCIP_OKAY;
    260}
    261
    262
    263/** execution method of primal heuristic */
    264static
    265SCIP_DECL_HEUREXEC(heurExecObjpscostdiving) /*lint --e{715}*/
    266{ /*lint --e{715}*/
    267 SCIP_HEURDATA* heurdata;
    268 SCIP_LPSOLSTAT lpsolstat;
    269 SCIP_VAR* var;
    270 SCIP_VAR** lpcands;
    271 SCIP_Real* lpcandssol;
    272 SCIP_Real* lpcandsfrac;
    273 SCIP_Real primsol;
    274 SCIP_Real frac;
    275 SCIP_Real pscostquot;
    276 SCIP_Real bestpscostquot;
    277 SCIP_Real oldobj;
    278 SCIP_Real newobj;
    279 SCIP_Real objscale;
    280 SCIP_Bool bestcandmayrounddown;
    281 SCIP_Bool bestcandmayroundup;
    282 SCIP_Bool bestcandroundup;
    283 SCIP_Bool mayrounddown;
    284 SCIP_Bool mayroundup;
    285 SCIP_Bool roundup;
    286 SCIP_Bool lperror;
    287 SCIP_Longint ncalls;
    288 SCIP_Longint nsolsfound;
    289 SCIP_Longint nlpiterations;
    290 SCIP_Longint maxnlpiterations;
    291 int* roundings;
    292 int nvars;
    293 int varidx;
    294 int nlpcands;
    295 int startnlpcands;
    296 int depth;
    297 int maxdepth;
    298 int maxdivedepth;
    299 int divedepth;
    300 int bestcand;
    301 int c;
    302
    303 assert(heur != NULL);
    304 assert(scip != NULL);
    305 assert(result != NULL);
    306 assert(SCIPhasCurrentNodeLP(scip));
    307
    309
    310 *result = SCIP_DELAYED;
    311
    312 /* do not call heuristic of node was already detected to be infeasible */
    313 if( nodeinfeasible )
    314 return SCIP_OKAY;
    315
    316 /* only call heuristic, if an optimal LP solution is at hand */
    318 return SCIP_OKAY;
    319
    320 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    322 return SCIP_OKAY;
    323
    324 /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
    325 if( !SCIPisLPSolBasic(scip) )
    326 return SCIP_OKAY;
    327
    328 /* don't dive two times at the same node */
    330 return SCIP_OKAY;
    331
    332 *result = SCIP_DIDNOTRUN;
    333
    334 /* get heuristic's data */
    335 heurdata = SCIPheurGetData(heur);
    336 assert(heurdata != NULL);
    337
    338 /* only apply heuristic, if only a few solutions have been found */
    339 if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols )
    340 return SCIP_OKAY;
    341
    342 /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
    343 depth = SCIPgetDepth(scip);
    344 maxdepth = SCIPgetMaxDepth(scip);
    345 maxdepth = MAX(maxdepth, 30);
    346 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
    347 return SCIP_OKAY;
    348
    349 /* calculate the maximal number of LP iterations until heuristic is aborted */
    350 nlpiterations = SCIPgetNNodeLPIterations(scip);
    351 ncalls = SCIPheurGetNCalls(heur);
    352 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
    353 maxnlpiterations = (SCIP_Longint)(((nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
    354 maxnlpiterations += heurdata->maxlpiterofs;
    355
    356 /* don't try to dive, if we took too many LP iterations during diving */
    357 if( heurdata->nlpiterations >= maxnlpiterations )
    358 return SCIP_OKAY;
    359
    360 /* allow at least a certain number of LP iterations in this dive */
    361 maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
    362
    363 /* get fractional variables that should be integral */
    364 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
    365
    366 /* don't try to dive, if there are no fractional variables */
    367 if( nlpcands == 0 )
    368 return SCIP_OKAY;
    369
    370 /* calculate the maximal diving depth */
    372 assert(nvars >= 0);
    373 if( SCIPgetNSolsFound(scip) == 0 )
    374 maxdivedepth = (int)(heurdata->depthfacnosol * nvars);
    375 else
    376 maxdivedepth = (int)(heurdata->depthfac * nvars);
    377 maxdivedepth = MIN(maxdivedepth, 10*maxdepth);
    378
    379 *result = SCIP_DIDNOTFIND;
    380
    381 /* get temporary memory for remembering the current soft roundings */
    382 SCIP_CALL( SCIPallocBufferArray(scip, &roundings, nvars) );
    383 BMSclearMemoryArray(roundings, nvars);
    384
    385 /* start diving */
    387
    388 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing objpscostdiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%" SCIP_LONGINT_FORMAT ", maxdivedepth=%d\n",
    389 SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth);
    390
    391 /* dive as long we are in the given diving depth and iteration limits and fractional variables exist, but
    392 * - if the last objective change was in a direction, that corresponds to a feasible rounding, we continue in any case
    393 * - if possible, we dive at least with the depth 10
    394 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
    395 */
    396 lperror = FALSE;
    397 lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
    398 divedepth = 0;
    399 startnlpcands = nlpcands;
    400 while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
    401 && (divedepth < 10
    402 || nlpcands <= startnlpcands - divedepth/2
    403 || (divedepth < maxdivedepth && nlpcands <= startnlpcands - divedepth/10
    404 && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) )
    405 {
    406 SCIP_RETCODE retcode;
    407
    408 divedepth++;
    409
    410 /* choose variable for objective change:
    411 * - prefer variables that may not be rounded without destroying LP feasibility:
    412 * - of these variables, change objective value of variable with largest rel. difference of pseudo cost values
    413 * - if all remaining fractional variables may be rounded without destroying LP feasibility:
    414 * - change objective value of variable with largest rel. difference of pseudo cost values
    415 */
    416 bestcand = -1;
    417 bestpscostquot = -1.0;
    418 bestcandmayrounddown = TRUE;
    419 bestcandmayroundup = TRUE;
    420 bestcandroundup = FALSE;
    421 for( c = 0; c < nlpcands; ++c )
    422 {
    423 var = lpcands[c];
    424 mayrounddown = SCIPvarMayRoundDown(var);
    425 mayroundup = SCIPvarMayRoundUp(var);
    426 primsol = lpcandssol[c];
    427 frac = lpcandsfrac[c];
    428 if( mayrounddown || mayroundup )
    429 {
    430 /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
    431 if( bestcandmayrounddown || bestcandmayroundup )
    432 {
    433 /* choose rounding direction:
    434 * - if variable may be rounded in both directions, round corresponding to the pseudo cost values
    435 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
    436 * the current fractional solution
    437 */
    438 roundup = FALSE;
    439 if( mayrounddown && mayroundup )
    440 calcPscostQuot(scip, heurdata, var, primsol, frac, 0, &pscostquot, &roundup);
    441 else if( mayrounddown )
    442 calcPscostQuot(scip, heurdata, var, primsol, frac, +1, &pscostquot, &roundup);
    443 else
    444 calcPscostQuot(scip, heurdata, var, primsol, frac, -1, &pscostquot, &roundup);
    445
    446 /* prefer variables, that have already been soft rounded but failed to get integral */
    447 varidx = SCIPvarGetProbindex(var);
    448 assert(0 <= varidx && varidx < nvars);
    449 if( roundings[varidx] != 0 )
    450 pscostquot *= 1000.0;
    451
    452 /* check, if candidate is new best candidate */
    453 if( pscostquot > bestpscostquot )
    454 {
    455 bestcand = c;
    456 bestpscostquot = pscostquot;
    457 bestcandmayrounddown = mayrounddown;
    458 bestcandmayroundup = mayroundup;
    459 bestcandroundup = roundup;
    460 }
    461 }
    462 }
    463 else
    464 {
    465 /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */
    466 calcPscostQuot(scip, heurdata, var, primsol, frac, 0, &pscostquot, &roundup);
    467
    468 /* prefer variables, that have already been soft rounded but failed to get integral */
    469 varidx = SCIPvarGetProbindex(var);
    470 assert(0 <= varidx && varidx < nvars);
    471 if( roundings[varidx] != 0 )
    472 pscostquot *= 1000.0;
    473
    474 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
    475 if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot )
    476 {
    477 bestcand = c;
    478 bestpscostquot = pscostquot;
    479 bestcandmayrounddown = FALSE;
    480 bestcandmayroundup = FALSE;
    481 bestcandroundup = roundup;
    482 }
    483 }
    484 }
    485 assert(bestcand != -1);
    486
    487 /* if all candidates are roundable, try to round the solution */
    488 if( bestcandmayrounddown || bestcandmayroundup )
    489 {
    490 SCIP_Bool success;
    491
    492 /* create solution from diving LP and try to round it */
    493 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
    494 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
    495
    496 if( success && !SCIPisExact(scip) )
    497 {
    498 SCIPdebugMsg(scip, "objpscostdiving found roundable primal solution: obj=%g\n",
    499 SCIPgetSolOrigObj(scip, heurdata->sol));
    500
    501 /* try to add solution to SCIP */
    502 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
    503
    504 /* check, if solution was feasible and good enough */
    505 if( success )
    506 {
    507 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    508 *result = SCIP_FOUNDSOL;
    509 }
    510 }
    511 }
    512
    513 var = lpcands[bestcand];
    514
    515 /* check, if the best candidate was already subject to soft rounding */
    516 varidx = SCIPvarGetProbindex(var);
    517 assert(0 <= varidx && varidx < nvars);
    518 if( roundings[varidx] == +1 )
    519 {
    520 /* variable was already soft rounded upwards: hard round it downwards */
    521 SCIP_CALL( SCIPchgVarUbDive(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) );
    522 SCIPdebugMsg(scip, " dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded upwards -> bounds=[%g,%g]\n",
    523 divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
    524 lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var));
    525 }
    526 else if( roundings[varidx] == -1 )
    527 {
    528 /* variable was already soft rounded downwards: hard round it upwards */
    529 SCIP_CALL( SCIPchgVarLbDive(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
    530 SCIPdebugMsg(scip, " dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded downwards -> bounds=[%g,%g]\n",
    531 divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
    532 lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var));
    533 }
    534 else
    535 {
    536 assert(roundings[varidx] == 0);
    537
    538 /* apply soft rounding of best candidate via a change in the objective value */
    539 objscale = divedepth * 1000.0;
    540 oldobj = SCIPgetVarObjDive(scip, var);
    541 if( bestcandroundup )
    542 {
    543 /* soft round variable up: make objective value (more) negative */
    544 if( oldobj < 0.0 )
    545 newobj = objscale * oldobj;
    546 else
    547 newobj = -objscale * oldobj;
    548 newobj = MIN(newobj, -objscale);
    549
    550 /* remember, that this variable was soft rounded upwards */
    551 roundings[varidx] = +1;
    552 }
    553 else
    554 {
    555 /* soft round variable down: make objective value (more) positive */
    556 if( oldobj > 0.0 )
    557 newobj = objscale * oldobj;
    558 else
    559 newobj = -objscale * oldobj;
    560 newobj = MAX(newobj, objscale);
    561
    562 /* remember, that this variable was soft rounded downwards */
    563 roundings[varidx] = -1;
    564 }
    565 SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) );
    566 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",
    567 divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
    568 SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
    569 lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var), oldobj, newobj);
    570 }
    571
    572 /* resolve the diving LP */
    573 nlpiterations = SCIPgetNLPIterations(scip);
    574 retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL);
    575 lpsolstat = SCIPgetLPSolstat(scip);
    576
    577 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
    578 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
    579 */
    580 if( retcode != SCIP_OKAY )
    581 {
    582#ifndef NDEBUG
    583 if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY )
    584 {
    585 SCIP_CALL( retcode );
    586 }
    587#endif
    588 SCIPwarningMessage(scip, "Error while solving LP in Objpscostdiving heuristic; LP solve terminated with code <%d>\n", retcode);
    589 SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n");
    590 }
    591
    592 if( lperror )
    593 break;
    594
    595 /* update iteration count */
    596 heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
    597
    598 /* get LP solution status and fractional variables, that should be integral */
    599 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    600 {
    601 /* get new fractional variables */
    602 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
    603 }
    604 SCIPdebugMsg(scip, " -> lpsolstat=%d, nlpcands=%d\n", lpsolstat, nlpcands);
    605 }
    606
    607 /* check if a solution has been found */
    608 if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    609 {
    610 SCIP_Bool success;
    611
    612 /* create solution from diving LP */
    613 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
    614 SCIPdebugMsg(scip, "objpscostdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
    615
    616 /* in exact mode we have to end diving prior to trying the solution */
    617 if( SCIPisExact(scip) )
    618 {
    619 SCIP_CALL( SCIPunlinkSol(scip, heurdata->sol) );
    621 }
    622
    623 /* try to add solution to SCIP */
    624 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
    625
    626 /* check, if solution was feasible and good enough */
    627 if( success )
    628 {
    629 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    630 *result = SCIP_FOUNDSOL;
    631 }
    632 }
    633
    634 /* end diving */
    635 if( SCIPinDive(scip) )
    636 {
    638 }
    639
    640 if( *result == SCIP_FOUNDSOL )
    641 heurdata->nsuccess++;
    642
    643 /* free temporary memory for remembering the current soft roundings */
    644 SCIPfreeBufferArray(scip, &roundings);
    645
    646 SCIPdebugMsg(scip, "objpscostdiving heuristic finished\n");
    647
    648 return SCIP_OKAY; /*lint !e438*/
    649}
    650
    651
    652/*
    653 * heuristic specific interface methods
    654 */
    655
    656/** creates the objpscostdiving heuristic and includes it in SCIP */
    658 SCIP* scip /**< SCIP data structure */
    659 )
    660{
    661 SCIP_HEURDATA* heurdata;
    662 SCIP_HEUR* heur;
    663
    664 /* create Objpscostdiving primal heuristic data */
    665 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    666
    667 /* include primal heuristic */
    670 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecObjpscostdiving, heurdata) );
    671
    672 assert(heur != NULL);
    673
    674 /* primal heuristic is safe to use in exact solving mode */
    675 SCIPheurMarkExact(heur);
    676
    677 /* set non-NULL pointers to callback methods */
    678 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyObjpscostdiving) );
    679 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeObjpscostdiving) );
    680 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitObjpscostdiving) );
    681 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitObjpscostdiving) );
    682
    683 /* objpscostdiving heuristic parameters */
    685 "heuristics/objpscostdiving/minreldepth",
    686 "minimal relative depth to start diving",
    687 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
    689 "heuristics/objpscostdiving/maxreldepth",
    690 "maximal relative depth to start diving",
    691 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
    693 "heuristics/objpscostdiving/maxlpiterquot",
    694 "maximal fraction of diving LP iterations compared to total iteration number",
    695 &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, 1.0, NULL, NULL) );
    697 "heuristics/objpscostdiving/maxlpiterofs",
    698 "additional number of allowed LP iterations",
    699 &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
    701 "heuristics/objpscostdiving/maxsols",
    702 "total number of feasible solutions found up to which heuristic is called (-1: no limit)",
    703 &heurdata->maxsols, TRUE, DEFAULT_MAXSOLS, -1, INT_MAX, NULL, NULL) );
    705 "heuristics/objpscostdiving/depthfac",
    706 "maximal diving depth: number of binary/integer variables times depthfac",
    707 &heurdata->depthfac, TRUE, DEFAULT_DEPTHFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    709 "heuristics/objpscostdiving/depthfacnosol",
    710 "maximal diving depth factor if no feasible solution was found yet",
    711 &heurdata->depthfacnosol, TRUE, DEFAULT_DEPTHFACNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    712
    713 return SCIP_OKAY;
    714}
    715
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    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:514
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1504
    SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
    Definition: scip_sol.c:3128
    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:4017
    SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1293
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1890
    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:4478
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
    Definition: var.c:4467
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
    Definition: var.c:19144
    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
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63