SCIP

    Solving Constraint Integer Programs

    heur_intdiving.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_intdiving.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief LP diving heuristic that fixes variables with integral LP value
    28 * @author Tobias Achterberg
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    34#include "scip/heur_intdiving.h"
    35#include "scip/pub_heur.h"
    36#include "scip/pub_lp.h"
    37#include "scip/pub_message.h"
    38#include "scip/pub_var.h"
    39#include "scip/scip_branch.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_probing.h"
    49#include "scip/scip_sol.h"
    51#include "scip/scip_tree.h"
    52#include "scip/scip_var.h"
    53
    54
    55#define HEUR_NAME "intdiving"
    56#define HEUR_DESC "LP diving heuristic that fixes binary variables with large LP value to one"
    57#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_DIVING
    58#define HEUR_PRIORITY -1003500
    59#define HEUR_FREQ -1
    60#define HEUR_FREQOFS 9
    61#define HEUR_MAXDEPTH -1
    62#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
    63#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    64
    65
    66/*
    67 * Default parameter settings
    68 */
    69
    70#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
    71#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
    72#define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to node LP iterations */
    73#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
    74#define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    75 * where diving is performed (0.0: no limit) */
    76#define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    77 * where diving is performed (0.0: no limit) */
    78#define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
    79#define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
    80#define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
    81
    82#define MINLPITER 10000 /**< minimal number of LP iterations allowed in each LP solving call */
    83
    84
    85/* locally defined heuristic data */
    86struct SCIP_HeurData
    87{
    88 SCIP_SOL* sol; /**< working solution */
    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 node LP iterations */
    92 int maxlpiterofs; /**< additional number of allowed LP iterations */
    93 SCIP_Real maxdiveubquot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    94 * where diving is performed (0.0: no limit) */
    95 SCIP_Real maxdiveavgquot; /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    96 * where diving is performed (0.0: no limit) */
    97 SCIP_Real maxdiveubquotnosol; /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
    98 SCIP_Real maxdiveavgquotnosol;/**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
    99 SCIP_Bool backtrack; /**< use one level of backtracking if infeasibility is encountered? */
    100 SCIP_Longint nlpiterations; /**< LP iterations used in this heuristic */
    101 int nsuccess; /**< number of runs that produced at least one feasible solution */
    102};
    103
    104
    105/*
    106 * local methods
    107 */
    108
    109
    110/*
    111 * Callback methods
    112 */
    113
    114/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    115static
    116SCIP_DECL_HEURCOPY(heurCopyIntdiving)
    117{ /*lint --e{715}*/
    118 assert(scip != NULL);
    119 assert(heur != NULL);
    120
    122
    123 /* call inclusion method of primal heuristic */
    125
    126 return SCIP_OKAY;
    127}
    128
    129/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    130static
    131SCIP_DECL_HEURFREE(heurFreeIntdiving) /*lint --e{715}*/
    132{ /*lint --e{715}*/
    133 SCIP_HEURDATA* heurdata;
    134
    135 assert(heur != NULL);
    136 assert(scip != NULL);
    137
    139
    140 /* free heuristic data */
    141 heurdata = SCIPheurGetData(heur);
    142 assert(heurdata != NULL);
    143 SCIPfreeBlockMemory(scip, &heurdata);
    144 SCIPheurSetData(heur, NULL);
    145
    146 return SCIP_OKAY;
    147}
    148
    149
    150/** initialization method of primal heuristic (called after problem was transformed) */
    151static
    152SCIP_DECL_HEURINIT(heurInitIntdiving) /*lint --e{715}*/
    153{ /*lint --e{715}*/
    154 SCIP_HEURDATA* heurdata;
    155
    156 assert(heur != NULL);
    157
    159
    160 /* get heuristic data */
    161 heurdata = SCIPheurGetData(heur);
    162 assert(heurdata != NULL);
    163
    164 /* create working solution */
    165 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    166
    167 /* initialize data */
    168 heurdata->nlpiterations = 0;
    169 heurdata->nsuccess = 0;
    170
    171 return SCIP_OKAY;
    172}
    173
    174
    175/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    176static
    177SCIP_DECL_HEUREXIT(heurExitIntdiving) /*lint --e{715}*/
    178{ /*lint --e{715}*/
    179 SCIP_HEURDATA* heurdata;
    180
    181 assert(heur != NULL);
    182
    184
    185 /* get heuristic data */
    186 heurdata = SCIPheurGetData(heur);
    187 assert(heurdata != NULL);
    188
    189 /* free working solution */
    190 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    191
    192 return SCIP_OKAY;
    193}
    194
    195
    196/** execution method of primal heuristic */
    197static
    198SCIP_DECL_HEUREXEC(heurExecIntdiving) /*lint --e{715}*/
    199{ /*lint --e{715}*/
    200 SCIP_HEURDATA* heurdata;
    201 SCIP_LPSOLSTAT lpsolstat;
    202 SCIP_VAR** pseudocands;
    203 SCIP_VAR** fixcands;
    204 SCIP_Real* fixcandscores;
    205 SCIP_Real searchubbound;
    206 SCIP_Real searchavgbound;
    207 SCIP_Real searchbound;
    208 SCIP_Real objval;
    209 SCIP_Bool lperror;
    210 SCIP_Bool cutoff;
    211 SCIP_Bool backtracked;
    212 SCIP_Longint ncalls;
    213 SCIP_Longint nsolsfound;
    214 SCIP_Longint nlpiterations;
    215 SCIP_Longint maxnlpiterations;
    216 int nfixcands;
    217 int nbinfixcands;
    218 int depth;
    219 int maxdepth;
    220 int maxdivedepth;
    221 int divedepth;
    222 int nextcand;
    223 int c;
    224
    225 assert(heur != NULL);
    226 assert(scip != NULL);
    227 assert(result != NULL);
    228 assert(SCIPhasCurrentNodeLP(scip));
    229
    231
    232 *result = SCIP_DELAYED;
    233
    234 /* do not call heuristic of node was already detected to be infeasible */
    235 if( nodeinfeasible )
    236 return SCIP_OKAY;
    237
    238 /* only call heuristic, if an optimal LP solution is at hand */
    240 return SCIP_OKAY;
    241
    242 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    244 return SCIP_OKAY;
    245
    246 /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
    247 if( !SCIPisLPSolBasic(scip) )
    248 return SCIP_OKAY;
    249
    250 /* don't dive two times at the same node */
    252 return SCIP_OKAY;
    253
    254 *result = SCIP_DIDNOTRUN;
    255
    256 /* get heuristic's data */
    257 heurdata = SCIPheurGetData(heur);
    258 assert(heurdata != NULL);
    259
    260 /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
    261 depth = SCIPgetDepth(scip);
    262 maxdepth = SCIPgetMaxDepth(scip);
    263 maxdepth = MAX(maxdepth, 100);
    264 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
    265 return SCIP_OKAY;
    266
    267 /* calculate the maximal number of LP iterations until heuristic is aborted */
    268 nlpiterations = SCIPgetNNodeLPIterations(scip);
    269 ncalls = SCIPheurGetNCalls(heur);
    270 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
    271 maxnlpiterations = (SCIP_Longint)(((nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
    272 maxnlpiterations += heurdata->maxlpiterofs;
    273
    274 /* don't try to dive, if we took too many LP iterations during diving */
    275 if( heurdata->nlpiterations >= maxnlpiterations )
    276 return SCIP_OKAY;
    277
    278 /* allow at least a certain number of LP iterations in this dive */
    279 maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
    280
    281 /* get unfixed integer variables */
    282 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &nfixcands, NULL) );
    283
    284 /* don't try to dive, if there are no fractional variables */
    285 if( nfixcands == 0 )
    286 return SCIP_OKAY;
    287
    288 /* calculate the objective search bound */
    289 if( SCIPgetNSolsFound(scip) == 0 )
    290 {
    291 if( heurdata->maxdiveubquotnosol > 0.0 )
    292 searchubbound = SCIPgetLowerbound(scip)
    293 + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
    294 else
    295 searchubbound = SCIPinfinity(scip);
    296 if( heurdata->maxdiveavgquotnosol > 0.0 )
    297 searchavgbound = SCIPgetLowerbound(scip)
    298 + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
    299 else
    300 searchavgbound = SCIPinfinity(scip);
    301 }
    302 else
    303 {
    304 if( heurdata->maxdiveubquot > 0.0 )
    305 searchubbound = SCIPgetLowerbound(scip)
    306 + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
    307 else
    308 searchubbound = SCIPinfinity(scip);
    309 if( heurdata->maxdiveavgquot > 0.0 )
    310 searchavgbound = SCIPgetLowerbound(scip)
    311 + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
    312 else
    313 searchavgbound = SCIPinfinity(scip);
    314 }
    315 searchbound = MIN(searchubbound, searchavgbound);
    317 searchbound = SCIPceil(scip, searchbound);
    318
    319 /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
    321 assert(maxdivedepth >= 0);
    322 maxdivedepth = MIN(maxdivedepth, maxdepth);
    323 maxdivedepth *= 10;
    324
    325 *result = SCIP_DIDNOTFIND;
    326
    327 /* start diving */
    329
    330 /* enables collection of variable statistics during probing */
    332
    333 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing intdiving heuristic: depth=%d, %d non-fixed, dualbound=%g, searchbound=%g\n",
    335
    336 /* copy the pseudo candidates into own array, because we want to reorder them */
    337 SCIP_CALL( SCIPduplicateBufferArray(scip, &fixcands, pseudocands, nfixcands) );
    338
    339 /* sort non-fixed variables by non-increasing inference score, but prefer binaries over integers in any case */
    340 SCIP_CALL( SCIPallocBufferArray(scip, &fixcandscores, nfixcands) );
    341 nbinfixcands = 0;
    342 for( c = 0; c < nfixcands; ++c )
    343 {
    344 SCIP_VAR* var;
    345 SCIP_Real score;
    346 int colveclen;
    347 int left;
    348 int right;
    349 int i;
    350
    351 assert(c >= nbinfixcands);
    352 var = fixcands[c];
    353 assert(SCIPvarIsIntegral(var));
    355 if( SCIPvarIsBinary(var) )
    356 {
    357 score = 500.0 * SCIPvarGetNCliques(var, TRUE) + 100.0 * SCIPvarGetNImpls(var, TRUE)
    358 + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/100.0;
    359
    360 /* shift the non-binary variables one slot to the right */
    361 for( i = c; i > nbinfixcands; --i )
    362 {
    363 fixcands[i] = fixcands[i-1];
    364 fixcandscores[i] = fixcandscores[i-1];
    365 }
    366 /* put the new candidate into the first nbinfixcands slot */
    367 left = 0;
    368 right = nbinfixcands;
    369 nbinfixcands++;
    370 }
    371 else
    372 {
    373 score = 5.0 * (SCIPvarGetNCliques(var, FALSE) + SCIPvarGetNCliques(var, TRUE))
    375 + (SCIP_Real)colveclen/10000.0;
    376
    377 /* put the new candidate in the slots after the binary candidates */
    378 left = nbinfixcands;
    379 right = c;
    380 }
    381 for( i = right; i > left && score > fixcandscores[i-1]; --i )
    382 {
    383 fixcands[i] = fixcands[i-1];
    384 fixcandscores[i] = fixcandscores[i-1];
    385 }
    386 fixcands[i] = var;
    387 fixcandscores[i] = score;
    388 SCIPdebugMsg(scip, " <%s>: ncliques=%d/%d, nimpls=%d/%d, inferencescore=%g, colveclen=%d -> score=%g\n",
    391 colveclen, score);
    392 }
    393 SCIPfreeBufferArray(scip, &fixcandscores);
    394
    395 /* get LP objective value */
    396 lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
    397 objval = SCIPgetLPObjval(scip);
    398
    399 /* dive as long we are in the given objective, depth and iteration limits, but if possible, we dive at least with
    400 * the depth 10
    401 */
    402 lperror = FALSE;
    403 cutoff = FALSE;
    404 divedepth = 0;
    405 nextcand = 0;
    406 while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL
    407 && (divedepth < 10
    408 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
    409 && !SCIPisStopped(scip) )
    410 {
    411 SCIP_VAR* var;
    412 SCIP_Real bestsolval;
    413 SCIP_Real bestfixval;
    414 int bestcand;
    415 SCIP_Longint nnewlpiterations;
    416 SCIP_Longint nnewdomreds;
    417
    418 /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */
    420 {
    422 divedepth++;
    423 }
    424 else
    425 break;
    426
    427 nnewlpiterations = 0;
    428 nnewdomreds = 0;
    429
    430 /* fix binary variable that is closest to 1 in the LP solution to 1;
    431 * if all binary variables are fixed, fix integer variable with least fractionality in LP solution
    432 */
    433 bestcand = -1;
    434 bestsolval = -1.0;
    435 bestfixval = 1.0;
    436
    437 /* look in the binary variables for fixing candidates */
    438 for( c = nextcand; c < nbinfixcands; ++c )
    439 {
    440 SCIP_Real solval;
    441
    442 var = fixcands[c];
    443
    444 /* ignore already fixed variables */
    445 if( var == NULL )
    446 continue;
    447 if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
    448 {
    449 fixcands[c] = NULL;
    450 continue;
    451 }
    452
    453 /* get the LP solution value */
    454 solval = SCIPvarGetLPSol(var);
    455
    456 if( solval > bestsolval )
    457 {
    458 bestcand = c;
    459 bestfixval = 1.0;
    460 bestsolval = solval;
    461 if( SCIPisGE(scip, bestsolval, 1.0) )
    462 {
    463 /* we found an unfixed binary variable with LP solution value of 1.0 - there cannot be a better candidate */
    464 break;
    465 }
    466 else if( SCIPisLE(scip, bestsolval, 0.0) )
    467 {
    468 /* the variable is currently at 0.0 - this is the only situation where we want to fix it to 0.0 */
    469 bestfixval = 0.0;
    470 }
    471 }
    472 }
    473
    474 /* if all binary variables are fixed, look in the integer variables for a fixing candidate */
    475 if( bestcand == -1 )
    476 {
    477 SCIP_Real bestfrac;
    478
    479 bestfrac = SCIP_INVALID;
    480 for( c = MAX(nextcand, nbinfixcands); c < nfixcands; ++c )
    481 {
    482 SCIP_Real solval;
    483 SCIP_Real frac;
    484
    485 var = fixcands[c];
    486
    487 /* ignore already fixed variables */
    488 if( var == NULL )
    489 continue;
    490 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
    491 {
    492 fixcands[c] = NULL;
    493 continue;
    494 }
    495
    496 /* get the LP solution value */
    497 solval = SCIPvarGetLPSol(var);
    498 frac = SCIPfrac(scip, solval);
    499
    500 /* ignore integer variables that are currently integral */
    501 if( SCIPisFeasFracIntegral(scip, frac) )
    502 continue;
    503
    504 if( frac < bestfrac )
    505 {
    506 bestcand = c;
    507 bestsolval = solval;
    508 bestfrac = frac;
    509 bestfixval = SCIPfloor(scip, bestsolval + 0.5);
    510 if( SCIPisZero(scip, bestfrac) )
    511 {
    512 /* we found an unfixed integer variable with integral LP solution value */
    513 break;
    514 }
    515 }
    516 }
    517 }
    518 assert(-1 <= bestcand && bestcand < nfixcands);
    519
    520 /* if there is no unfixed candidate left, we are done */
    521 if( bestcand == -1 )
    522 break;
    523
    524 var = fixcands[bestcand];
    525 assert(var != NULL);
    526 assert(SCIPvarIsIntegral(var));
    527 assert(SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) > 0.5);
    528 assert(SCIPisGE(scip, bestfixval, SCIPvarGetLbLocal(var)));
    529 assert(SCIPisLE(scip, bestfixval, SCIPvarGetUbLocal(var)));
    530
    531 backtracked = FALSE;
    532 do
    533 {
    534 /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
    535 * occurred or variable was fixed by propagation while backtracking => Abort diving!
    536 */
    537 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
    538 {
    539 SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g], diving aborted \n",
    541 cutoff = TRUE;
    542 break;
    543 }
    544 if( SCIPisFeasLT(scip, bestfixval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestfixval, SCIPvarGetUbLocal(var)) )
    545 {
    546 SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
    547 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
    548 assert(backtracked);
    549 break;
    550 }
    551
    552 /* apply fixing of best candidate */
    553 SCIPdebugMsg(scip, " dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", %d unfixed: var <%s>, sol=%g, oldbounds=[%g,%g], fixed to %g\n",
    554 divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPgetNPseudoBranchCands(scip),
    555 SCIPvarGetName(var), bestsolval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
    556 SCIP_CALL( SCIPfixVarProbing(scip, var, bestfixval) );
    557
    558 /* apply domain propagation */
    559 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &nnewdomreds) );
    560 if( !cutoff )
    561 {
    562 /* if the best candidate was just fixed to its LP value and no domain reduction was found, the LP solution
    563 * stays valid, and the LP does not need to be resolved
    564 */
    565 if( nnewdomreds > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
    566 {
    567 /* resolve the diving LP */
    568 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
    569 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
    570 */
    571#ifdef NDEBUG
    572 SCIP_RETCODE retstat;
    573 nlpiterations = SCIPgetNLPIterations(scip);
    574 retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
    575 if( retstat != SCIP_OKAY )
    576 {
    577 SCIPwarningMessage(scip, "Error while solving LP in Intdiving heuristic; LP solve terminated with code <%d>\n",retstat);
    578 }
    579#else
    580 nlpiterations = SCIPgetNLPIterations(scip);
    581 SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
    582#endif
    583
    584 if( lperror )
    585 break;
    586
    587 /* update iteration count */
    588 nnewlpiterations = SCIPgetNLPIterations(scip) - nlpiterations;
    589 heurdata->nlpiterations += nnewlpiterations;
    590
    591 /* get LP solution status */
    592 lpsolstat = SCIPgetLPSolstat(scip);
    593 assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
    595 }
    596 }
    597
    598 /* perform backtracking if a cutoff was detected */
    599 if( cutoff && !backtracked && heurdata->backtrack )
    600 {
    601 SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
    603
    604 /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
    606
    608
    609 bestfixval = SCIPvarIsBinary(var)
    610 ? 1.0 - bestfixval
    611 : (SCIPisGT(scip, bestsolval, bestfixval) && SCIPisFeasLE(scip, bestfixval + 1, SCIPvarGetUbLocal(var)) ? bestfixval + 1 : bestfixval - 1);
    612
    613 backtracked = TRUE;
    614 }
    615 else
    616 backtracked = FALSE;
    617 }
    618 while( backtracked );
    619
    620 if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    621 {
    622 SCIP_Bool success;
    623
    624 /* get new objective value */
    625 objval = SCIPgetLPObjval(scip);
    626
    627 if( nnewlpiterations > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
    628 {
    629 /* we must start again with the first candidate, since the LP solution changed */
    630 nextcand = 0;
    631
    632 /* create solution from diving LP and try to round it */
    633 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
    634 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
    635 if( success )
    636 {
    637 SCIPdebugMsg(scip, "intdiving found roundable primal solution: obj=%g\n",
    638 SCIPgetSolOrigObj(scip, heurdata->sol));
    639
    640 /* try to add solution to SCIP */
    641 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
    642
    643 /* check, if solution was feasible and good enough */
    644 if( success )
    645 {
    646 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    647 *result = SCIP_FOUNDSOL;
    648 }
    649 }
    650 }
    651 else
    652 nextcand = bestcand+1; /* continue with the next candidate in the following loop */
    653 }
    654 SCIPdebugMsg(scip, " -> lpsolstat=%d, objval=%g/%g\n", lpsolstat, objval, searchbound);
    655 }
    656
    657 /* free temporary memory */
    658 SCIPfreeBufferArray(scip, &fixcands);
    659
    660 /* end diving */
    662
    663 if( *result == SCIP_FOUNDSOL )
    664 heurdata->nsuccess++;
    665
    666 SCIPdebugMsg(scip, "intdiving heuristic finished\n");
    667
    668 return SCIP_OKAY; /*lint !e438*/
    669}
    670
    671
    672/*
    673 * heuristic specific interface methods
    674 */
    675
    676/** creates the intdiving heuristic and includes it in SCIP */
    678 SCIP* scip /**< SCIP data structure */
    679 )
    680{
    681 SCIP_HEURDATA* heurdata;
    682 SCIP_HEUR* heur;
    683
    684 /* create Intdiving primal heuristic data */
    685 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    686
    687 /* include primal heuristic */
    690 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecIntdiving, heurdata) );
    691
    692 assert(heur != NULL);
    693
    694 /* primal heuristic is safe to use in exact solving mode */
    695 SCIPheurMarkExact(heur);
    696
    697 /* set non-NULL pointers to callback methods */
    698 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyIntdiving) );
    699 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeIntdiving) );
    700 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitIntdiving) );
    701 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitIntdiving) );
    702
    703 /* intdiving heuristic parameters */
    705 "heuristics/intdiving/minreldepth",
    706 "minimal relative depth to start diving",
    707 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
    709 "heuristics/intdiving/maxreldepth",
    710 "maximal relative depth to start diving",
    711 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
    713 "heuristics/intdiving/maxlpiterquot",
    714 "maximal fraction of diving LP iterations compared to node LP iterations",
    715 &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    717 "heuristics/intdiving/maxlpiterofs",
    718 "additional number of allowed LP iterations",
    719 &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
    721 "heuristics/intdiving/maxdiveubquot",
    722 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
    723 &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
    725 "heuristics/intdiving/maxdiveavgquot",
    726 "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
    727 &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    729 "heuristics/intdiving/maxdiveubquotnosol",
    730 "maximal UBQUOT when no solution was found yet (0.0: no limit)",
    731 &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
    733 "heuristics/intdiving/maxdiveavgquotnosol",
    734 "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
    735 &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    737 "heuristics/intdiving/backtrack",
    738 "use one level of backtracking if infeasibility is encountered?",
    739 &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
    740
    741 return SCIP_OKAY;
    742}
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:306
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_INVALID
    Definition: def.h:187
    #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
    SCIP_Bool SCIPisObjIntegral(SCIP *scip)
    Definition: scip_prob.c:1801
    #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 SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPincludeHeurIntdiving(SCIP *scip)
    SCIP_RETCODE SCIPgetPseudoBranchCands(SCIP *scip, SCIP_VAR ***pseudocands, int *npseudocands, int *npriopseudocands)
    Definition: scip_branch.c:741
    int SCIPgetNPseudoBranchCands(SCIP *scip)
    Definition: scip_branch.c:766
    int SCIPcolGetNNonz(SCIP_COL *col)
    Definition: lp.c:17520
    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_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 SCIPduplicateBufferArray(scip, ptr, source, num)
    Definition: scip_mem.h:132
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    int SCIPgetProbingDepth(SCIP *scip)
    Definition: scip_probing.c:199
    SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
    Definition: scip_probing.c:581
    SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
    Definition: scip_probing.c:226
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
    Definition: scip_probing.c:166
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_RETCODE SCIPfixVarProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval)
    Definition: scip_probing.c:419
    SCIP_RETCODE SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    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 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_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2134
    SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
    int SCIPgetMaxDepth(SCIP *scip)
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    SCIP_Real SCIPgetAvgLowerbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasFracIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23715
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_Real SCIPgetVarAvgInferenceScore(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11945
    int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24600
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
    Definition: var.c:24696
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24674
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    void SCIPenableVarHistory(SCIP *scip)
    Definition: scip_var.c:11083
    #define DEFAULT_MAXDIVEUBQUOT
    static SCIP_DECL_HEURFREE(heurFreeIntdiving)
    #define HEUR_TIMING
    #define DEFAULT_MAXLPITERQUOT
    #define HEUR_FREQOFS
    #define HEUR_DESC
    static SCIP_DECL_HEURCOPY(heurCopyIntdiving)
    #define MINLPITER
    #define DEFAULT_MAXDIVEAVGQUOT
    #define DEFAULT_BACKTRACK
    static SCIP_DECL_HEUREXEC(heurExecIntdiving)
    #define DEFAULT_MAXDIVEUBQUOTNOSOL
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    #define HEUR_PRIORITY
    #define DEFAULT_MAXRELDEPTH
    #define DEFAULT_MAXLPITEROFS
    #define DEFAULT_MAXDIVEAVGQUOTNOSOL
    #define HEUR_NAME
    static SCIP_DECL_HEURINIT(heurInitIntdiving)
    #define HEUR_FREQ
    #define DEFAULT_MINRELDEPTH
    static SCIP_DECL_HEUREXIT(heurExitIntdiving)
    #define HEUR_USESSUBSCIP
    LP diving heuristic that fixes variables with integral LP value.
    memory allocation routines
    public methods for primal heuristics
    public methods for LP management
    public methods for message output
    public methods for problem variables
    public methods for branching rule plugins and branching
    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 the probing mode
    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_INFEASIBLE
    Definition: type_lp.h:45
    @ SCIP_LPSOLSTAT_OBJLIMIT
    Definition: type_lp.h:47
    @ 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
    @ SCIP_VARSTATUS_COLUMN
    Definition: type_var.h:53