SCIP

    Solving Constraint Integer Programs

    heur_rounding.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_rounding.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief LP rounding heuristic that tries to recover from intermediate infeasibilities
    28 * @author Tobias Achterberg
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    34#include "scip/heur_rounding.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_heur.h"
    41#include "scip/scip_lp.h"
    42#include "scip/scip_mem.h"
    43#include "scip/scip_message.h"
    44#include "scip/scip_numerics.h"
    45#include "scip/scip_param.h"
    46#include "scip/scip_sol.h"
    48
    49
    50#define HEUR_NAME "rounding"
    51#define HEUR_DESC "LP rounding heuristic with infeasibility recovering"
    52#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_ROUNDING
    53#define HEUR_PRIORITY -1000
    54#define HEUR_FREQ 1
    55#define HEUR_FREQOFS 0
    56#define HEUR_MAXDEPTH -1
    57#define HEUR_TIMING SCIP_HEURTIMING_DURINGLPLOOP
    58#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    59
    60#define DEFAULT_SUCCESSFACTOR 100 /**< number of calls per found solution that are considered as standard success,
    61 * a higher factor causes the heuristic to be called more often
    62 */
    63#define DEFAULT_ONCEPERNODE FALSE /**< should the heuristic only be called once per node? */
    64
    65/* locally defined heuristic data */
    66struct SCIP_HeurData
    67{
    68 SCIP_SOL* sol; /**< working solution */
    69 SCIP_Longint lastlp; /**< last LP number where the heuristic was applied */
    70 int successfactor; /**< number of calls per found solution that are considered as standard success,
    71 * a higher factor causes the heuristic to be called more often
    72 */
    73 SCIP_Bool oncepernode; /**< should the heuristic only be called once per node? */
    74};
    75
    76
    77/*
    78 * local methods
    79 */
    80
    81/** update row violation arrays after a row's activity value changed */
    82static
    84 SCIP* scip, /**< SCIP data structure */
    85 SCIP_ROW* row, /**< LP row */
    86 SCIP_ROW** violrows, /**< array with currently violated rows */
    87 int* violrowpos, /**< position of LP rows in violrows array */
    88 int* nviolrows, /**< pointer to the number of currently violated rows */
    89 SCIP_Real oldactivity, /**< old activity value of LP row */
    90 SCIP_Real newactivity /**< new activity value of LP row */
    91 )
    92{
    93 SCIP_Real lhs;
    94 SCIP_Real rhs;
    95 SCIP_Bool oldviol;
    96 SCIP_Bool newviol;
    97
    98 assert(violrows != NULL);
    99 assert(violrowpos != NULL);
    100 assert(nviolrows != NULL);
    101
    102 lhs = SCIProwGetLhs(row);
    103 rhs = SCIProwGetRhs(row);
    104 oldviol = (SCIPisFeasLT(scip, oldactivity, lhs) || SCIPisFeasGT(scip, oldactivity, rhs));
    105 newviol = (SCIPisFeasLT(scip, newactivity, lhs) || SCIPisFeasGT(scip, newactivity, rhs));
    106 if( oldviol != newviol )
    107 {
    108 int rowpos;
    109 int violpos;
    110
    111 rowpos = SCIProwGetLPPos(row);
    112 assert(rowpos >= 0);
    113
    114 if( oldviol )
    115 {
    116 /* the row violation was repaired: remove row from violrows array, decrease violation count */
    117 violpos = violrowpos[rowpos];
    118 assert(0 <= violpos && violpos < *nviolrows);
    119 assert(violrows[violpos] == row);
    120 violrowpos[rowpos] = -1;
    121 if( violpos != *nviolrows-1 )
    122 {
    123 violrows[violpos] = violrows[*nviolrows-1];
    124 violrowpos[SCIProwGetLPPos(violrows[violpos])] = violpos;
    125 }
    126 (*nviolrows)--;
    127 }
    128 else
    129 {
    130 /* the row is now violated: add row to violrows array, increase violation count */
    131 assert(violrowpos[rowpos] == -1);
    132 violrows[*nviolrows] = row;
    133 violrowpos[rowpos] = *nviolrows;
    134 (*nviolrows)++;
    135 }
    136 }
    137}
    138
    139/** update row activities after a variable's solution value changed */
    140static
    142 SCIP* scip, /**< SCIP data structure */
    143 SCIP_Real* activities, /**< LP row activities */
    144 SCIP_ROW** violrows, /**< array with currently violated rows */
    145 int* violrowpos, /**< position of LP rows in violrows array */
    146 int* nviolrows, /**< pointer to the number of currently violated rows */
    147 int nlprows, /**< number of rows in current LP */
    148 SCIP_VAR* var, /**< variable that has been changed */
    149 SCIP_Real oldsolval, /**< old solution value of variable */
    150 SCIP_Real newsolval /**< new solution value of variable */
    151 )
    152{
    153 SCIP_COL* col;
    154 SCIP_ROW** colrows;
    155 SCIP_Real* colvals;
    156 SCIP_Real delta;
    157 int ncolrows;
    158 int r;
    159
    160 assert(activities != NULL);
    161 assert(nviolrows != NULL);
    162 assert(0 <= *nviolrows && *nviolrows <= nlprows);
    163
    164 delta = newsolval - oldsolval;
    165 col = SCIPvarGetCol(var);
    166 colrows = SCIPcolGetRows(col);
    167 colvals = SCIPcolGetVals(col);
    168 ncolrows = SCIPcolGetNLPNonz(col);
    169 assert(ncolrows == 0 || (colrows != NULL && colvals != NULL));
    170
    171 for( r = 0; r < ncolrows; ++r )
    172 {
    173 SCIP_ROW* row;
    174 int rowpos;
    175
    176 row = colrows[r];
    177 rowpos = SCIProwGetLPPos(row);
    178 assert(-1 <= rowpos && rowpos < nlprows);
    179
    180 if( rowpos >= 0 && !SCIProwIsLocal(row) )
    181 {
    182 SCIP_Real oldactivity;
    183 SCIP_Real newactivity;
    184
    185 assert(SCIProwIsInLP(row));
    186
    187 /* update row activity */
    188 oldactivity = activities[rowpos];
    189 if( !SCIPisInfinity(scip, -oldactivity) && !SCIPisInfinity(scip, oldactivity) )
    190 {
    191 newactivity = oldactivity + delta * colvals[r];
    192 if( SCIPisInfinity(scip, newactivity) )
    193 newactivity = SCIPinfinity(scip);
    194 else if( SCIPisInfinity(scip, -newactivity) )
    195 newactivity = -SCIPinfinity(scip);
    196 activities[rowpos] = newactivity;
    197
    198 /* update row violation arrays */
    199 updateViolations(scip, row, violrows, violrowpos, nviolrows, oldactivity, newactivity);
    200 }
    201 }
    202 }
    203
    204 return SCIP_OKAY;
    205}
    206
    207/** returns a variable, that pushes activity of the row in the given direction with minimal negative impact on other rows;
    208 * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction;
    209 * rounding in a direction is forbidden, if this forces the objective value over the upper bound
    210 */
    211static
    213 SCIP* scip, /**< SCIP data structure */
    214 SCIP_SOL* sol, /**< primal solution */
    215 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
    216 SCIP_ROW* row, /**< LP row */
    217 int direction, /**< should the activity be increased (+1) or decreased (-1)? */
    218 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
    219 SCIP_Real* oldsolval, /**< pointer to store old (fractional) solution value of rounding variable */
    220 SCIP_Real* newsolval /**< pointer to store new (rounded) solution value of rounding variable */
    221 )
    222{
    223 SCIP_COL* col;
    224 SCIP_VAR* var;
    225 SCIP_Real val;
    226 SCIP_COL** rowcols;
    227 SCIP_Real* rowvals;
    228 SCIP_Real solval;
    229 SCIP_Real roundval;
    230 SCIP_Real obj;
    231 SCIP_Real deltaobj;
    232 SCIP_Real bestdeltaobj;
    233 int nrowcols;
    234 int nlocks;
    235 int minnlocks;
    236 int c;
    237
    238 assert(direction == +1 || direction == -1);
    239 assert(roundvar != NULL);
    240 assert(oldsolval != NULL);
    241 assert(newsolval != NULL);
    242
    243 /* get row entries */
    244 rowcols = SCIProwGetCols(row);
    245 rowvals = SCIProwGetVals(row);
    246 nrowcols = SCIProwGetNLPNonz(row);
    247
    248 /* select rounding variable */
    249 minnlocks = INT_MAX;
    250 bestdeltaobj = SCIPinfinity(scip);
    251 *roundvar = NULL;
    252 for( c = 0; c < nrowcols; ++c )
    253 {
    254 col = rowcols[c];
    255 var = SCIPcolGetVar(col);
    256
    258 {
    259 solval = SCIPgetSolVal(scip, sol, var);
    260
    261 if( !SCIPisFeasIntegral(scip, solval) )
    262 {
    263 val = rowvals[c];
    264 obj = SCIPvarGetObj(var);
    265
    266 if( direction * val < 0.0 )
    267 {
    268 /* rounding down */
    270 if( nlocks <= minnlocks )
    271 {
    272 roundval = SCIPfeasFloor(scip, solval);
    273 deltaobj = obj * (roundval - solval);
    274 if( (nlocks < minnlocks || deltaobj < bestdeltaobj) && minobj - obj < SCIPgetCutoffbound(scip) )
    275 {
    276 minnlocks = nlocks;
    277 bestdeltaobj = deltaobj;
    278 *roundvar = var;
    279 *oldsolval = solval;
    280 *newsolval = roundval;
    281 }
    282 }
    283 }
    284 else
    285 {
    286 /* rounding up */
    287 assert(direction * val > 0.0);
    289 if( nlocks <= minnlocks )
    290 {
    291 roundval = SCIPfeasCeil(scip, solval);
    292 deltaobj = obj * (roundval - solval);
    293 if( (nlocks < minnlocks || deltaobj < bestdeltaobj) && minobj + obj < SCIPgetCutoffbound(scip) )
    294 {
    295 minnlocks = nlocks;
    296 bestdeltaobj = deltaobj;
    297 *roundvar = var;
    298 *oldsolval = solval;
    299 *newsolval = roundval;
    300 }
    301 }
    302 }
    303 }
    304 }
    305 }
    306
    307 return SCIP_OKAY;
    308}
    309
    310/** returns a variable, that increases the activity of the row */
    311static
    313 SCIP* scip, /**< SCIP data structure */
    314 SCIP_SOL* sol, /**< primal solution */
    315 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
    316 SCIP_ROW* row, /**< LP row */
    317 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
    318 SCIP_Real* oldsolval, /**< old (fractional) solution value of rounding variable */
    319 SCIP_Real* newsolval /**< new (rounded) solution value of rounding variable */
    320 )
    321{
    322 return selectRounding(scip, sol, minobj, row, +1, roundvar, oldsolval, newsolval);
    323}
    324
    325/** returns a variable, that decreases the activity of the row */
    326static
    328 SCIP* scip, /**< SCIP data structure */
    329 SCIP_SOL* sol, /**< primal solution */
    330 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
    331 SCIP_ROW* row, /**< LP row */
    332 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
    333 SCIP_Real* oldsolval, /**< old (fractional) solution value of rounding variable */
    334 SCIP_Real* newsolval /**< new (rounded) solution value of rounding variable */
    335 )
    336{
    337 return selectRounding(scip, sol, minobj, row, -1, roundvar, oldsolval, newsolval);
    338}
    339
    340/** returns a fractional variable, that has most impact on rows in opposite direction, i.e. that is most crucial to
    341 * fix in the other direction;
    342 * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction;
    343 * rounding in a direction is forbidden, if this forces the objective value over the upper bound
    344 */
    345static
    347 SCIP* scip, /**< SCIP data structure */
    348 SCIP_SOL* sol, /**< primal solution */
    349 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
    350 SCIP_VAR** lpcands, /**< fractional variables in LP */
    351 int nlpcands, /**< number of fractional variables in LP */
    352 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
    353 SCIP_Real* oldsolval, /**< old (fractional) solution value of rounding variable */
    354 SCIP_Real* newsolval /**< new (rounded) solution value of rounding variable */
    355 )
    356{
    357 SCIP_VAR* var;
    358 SCIP_Real solval;
    359 SCIP_Real roundval;
    360 SCIP_Real obj;
    361 SCIP_Real deltaobj;
    362 SCIP_Real bestdeltaobj;
    363 int maxnlocks;
    364 int nlocks;
    365 int v;
    366
    367 assert(roundvar != NULL);
    368 assert(oldsolval != NULL);
    369 assert(newsolval != NULL);
    370
    371 /* select rounding variable */
    372 maxnlocks = -1;
    373 bestdeltaobj = SCIPinfinity(scip);
    374 *roundvar = NULL;
    375 for( v = 0; v < nlpcands; ++v )
    376 {
    377 var = lpcands[v];
    379
    380 solval = SCIPgetSolVal(scip, sol, var);
    381 if( !SCIPisFeasIntegral(scip, solval) )
    382 {
    383 obj = SCIPvarGetObj(var);
    384
    385 /* rounding down */
    387 if( nlocks >= maxnlocks )
    388 {
    389 roundval = SCIPfeasFloor(scip, solval);
    390 deltaobj = obj * (roundval - solval);
    391 if( (nlocks > maxnlocks || deltaobj < bestdeltaobj) && minobj - obj < SCIPgetCutoffbound(scip) )
    392 {
    393 maxnlocks = nlocks;
    394 bestdeltaobj = deltaobj;
    395 *roundvar = var;
    396 *oldsolval = solval;
    397 *newsolval = roundval;
    398 }
    399 }
    400
    401 /* rounding up */
    403 if( nlocks >= maxnlocks )
    404 {
    405 roundval = SCIPfeasCeil(scip, solval);
    406 deltaobj = obj * (roundval - solval);
    407 if( (nlocks > maxnlocks || deltaobj < bestdeltaobj) && minobj + obj < SCIPgetCutoffbound(scip) )
    408 {
    409 maxnlocks = nlocks;
    410 bestdeltaobj = deltaobj;
    411 *roundvar = var;
    412 *oldsolval = solval;
    413 *newsolval = roundval;
    414 }
    415 }
    416 }
    417 }
    418
    419 return SCIP_OKAY;
    420}
    421
    422
    423/*
    424 * Callback methods
    425 */
    426
    427/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    428static
    429SCIP_DECL_HEURCOPY(heurCopyRounding)
    430{ /*lint --e{715}*/
    431 assert(scip != NULL);
    432 assert(heur != NULL);
    433
    435
    436 /* call inclusion method of primal heuristic */
    438
    439 return SCIP_OKAY;
    440}
    441
    442/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    443static
    444SCIP_DECL_HEURFREE(heurFreeRounding) /*lint --e{715}*/
    445{ /*lint --e{715}*/
    446 SCIP_HEURDATA* heurdata;
    447
    448 assert(heur != NULL);
    449 assert(scip != NULL);
    450
    452
    453 /* free heuristic data */
    454 heurdata = SCIPheurGetData(heur);
    455 assert(heurdata != NULL);
    456 SCIPfreeBlockMemory(scip, &heurdata);
    457 SCIPheurSetData(heur, NULL);
    458
    459 return SCIP_OKAY;
    460}
    461
    462/** initialization method of primal heuristic (called after problem was transformed) */
    463static
    464SCIP_DECL_HEURINIT(heurInitRounding) /*lint --e{715}*/
    465{ /*lint --e{715}*/
    466 SCIP_HEURDATA* heurdata;
    467
    469
    470 heurdata = SCIPheurGetData(heur);
    471 assert(heurdata != NULL);
    472
    473 /* create heuristic data */
    474 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    475 heurdata->lastlp = -1;
    476
    477 return SCIP_OKAY;
    478}
    479
    480/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    481static
    482SCIP_DECL_HEUREXIT(heurExitRounding) /*lint --e{715}*/
    483{ /*lint --e{715}*/
    484 SCIP_HEURDATA* heurdata;
    485
    487
    488 /* free heuristic data */
    489 heurdata = SCIPheurGetData(heur);
    490 assert(heurdata != NULL);
    491 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    492
    493 return SCIP_OKAY;
    494}
    495
    496/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
    497static
    498SCIP_DECL_HEURINITSOL(heurInitsolRounding)
    499{
    500 SCIP_HEURDATA* heurdata;
    501
    503
    504 heurdata = SCIPheurGetData(heur);
    505 assert(heurdata != NULL);
    506 heurdata->lastlp = -1;
    507
    508 /* change the heuristic's timingmask, if nit should be called only once per node */
    509 if( heurdata->oncepernode )
    511
    512 return SCIP_OKAY;
    513}
    514
    515/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
    516static
    517SCIP_DECL_HEUREXITSOL(heurExitsolRounding)
    518{
    519 /* reset the timing mask to its default value */
    521
    522 return SCIP_OKAY;
    523}
    524
    525
    526/** execution method of primal heuristic */
    527static
    528SCIP_DECL_HEUREXEC(heurExecRounding) /*lint --e{715}*/
    529{ /*lint --e{715}*/
    530 SCIP_HEURDATA* heurdata;
    531 SCIP_SOL* sol;
    532 SCIP_VAR** lpcands;
    533 SCIP_Real* lpcandssol;
    534 SCIP_ROW** lprows;
    535 SCIP_Real* activities;
    536 SCIP_ROW** violrows;
    537 int* violrowpos;
    538 SCIP_Real obj;
    539 SCIP_Real bestroundval;
    540 SCIP_Real minobj;
    541 int nfrac;
    542 int nlpcands;
    543 int nlprows;
    544 int nviolrows;
    545 int c;
    546 int r;
    547 SCIP_Longint nlps;
    548 SCIP_Longint ncalls;
    549 SCIP_Longint nsolsfound;
    551
    552 assert(scip != NULL);
    553 assert(result != NULL);
    554 assert(SCIPhasCurrentNodeLP(scip));
    555
    557
    558 *result = SCIP_DIDNOTRUN;
    559
    560 /* only call heuristic, if an optimal LP solution is at hand */
    562 return SCIP_OKAY;
    563
    564 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    566 return SCIP_OKAY;
    567
    568 /* get heuristic data */
    569 heurdata = SCIPheurGetData(heur);
    570 assert(heurdata != NULL);
    571
    572 /* don't call heuristic, if we have already processed the current LP solution */
    573 nlps = SCIPgetNLPs(scip);
    574 if( nlps == heurdata->lastlp )
    575 return SCIP_OKAY;
    576 heurdata->lastlp = nlps;
    577
    578 /* don't call heuristic, if it was not successful enough in the past */
    579 ncalls = SCIPheurGetNCalls(heur);
    580 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur);
    582 if( nnodes % ((ncalls/heurdata->successfactor)/(nsolsfound+1)+1) != 0 )
    583 return SCIP_OKAY;
    584
    585 /* get fractional variables, that should be integral */
    586 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) );
    587
    588 /* only call heuristic, if LP solution is fractional */
    589 if( nlpcands == 0 )
    590 return SCIP_OKAY;
    591
    592 *result = SCIP_DIDNOTFIND;
    593
    594 /* get LP rows */
    595 SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );
    596
    597 SCIPdebugMsg(scip, "executing rounding heuristic: %d LP rows, %d LP candidates\n", nlprows, nlpcands);
    598
    599 /* get memory for activities, violated rows, and row violation positions */
    600 nfrac = nlpcands;
    601 SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
    602 SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) );
    603 SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) );
    604
    605 /* get the activities for all globally valid rows;
    606 * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated
    607 */
    608 nviolrows = 0;
    609 for( r = 0; r < nlprows; ++r )
    610 {
    611 SCIP_ROW* row;
    612
    613 row = lprows[r];
    614 assert(SCIProwGetLPPos(row) == r);
    615
    616 if( !SCIProwIsLocal(row) )
    617 {
    618 activities[r] = SCIPgetRowActivity(scip, row);
    619 if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row))
    620 || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) )
    621 {
    622 violrows[nviolrows] = row;
    623 violrowpos[r] = nviolrows;
    624 nviolrows++;
    625 }
    626 else
    627 violrowpos[r] = -1;
    628 }
    629 }
    630
    631 /* get the working solution from heuristic's local data */
    632 sol = heurdata->sol;
    633 assert(sol != NULL);
    634
    635 /* copy the current LP solution to the working solution */
    637
    638 /* calculate the minimal objective value possible after rounding fractional variables */
    639 minobj = SCIPgetSolTransObj(scip, sol);
    640 assert(minobj < SCIPgetCutoffbound(scip));
    641 for( c = 0; c < nlpcands; ++c )
    642 {
    643 obj = SCIPvarGetObj(lpcands[c]);
    644 bestroundval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]);
    645 minobj += obj * (bestroundval - lpcandssol[c]);
    646 }
    647
    648 /* try to round remaining variables in order to become/stay feasible */
    649 while( nfrac > 0 )
    650 {
    651 SCIP_VAR* roundvar;
    652 SCIP_Real oldsolval;
    653 SCIP_Real newsolval;
    654
    655 SCIPdebugMsg(scip, "rounding heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
    656 nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
    657
    658 /* minobj < SCIPgetCutoffbound(scip) should be true, otherwise the rounding variable selection
    659 * should have returned NULL. Due to possible cancellation we use SCIPisLE. */
    660 assert( SCIPisLE(scip, minobj, SCIPgetCutoffbound(scip)) );
    661
    662 /* choose next variable to process:
    663 * - if a violated row exists, round a variable decreasing the violation, that has least impact on other rows
    664 * - otherwise, round a variable, that has strongest devastating impact on rows in opposite direction
    665 */
    666 if( nviolrows > 0 )
    667 {
    668 SCIP_ROW* row;
    669 int rowpos;
    670
    671 row = violrows[nviolrows-1];
    672 rowpos = SCIProwGetLPPos(row);
    673 assert(0 <= rowpos && rowpos < nlprows);
    674 assert(violrowpos[rowpos] == nviolrows-1);
    675
    676 SCIPdebugMsg(scip, "rounding heuristic: try to fix violated row <%s>: %g <= %g <= %g\n",
    677 SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row));
    678 if( SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) )
    679 {
    680 /* lhs is violated: select a variable rounding, that increases the activity */
    681 SCIP_CALL( selectIncreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
    682 }
    683 else
    684 {
    685 assert(SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row)));
    686 /* rhs is violated: select a variable rounding, that decreases the activity */
    687 SCIP_CALL( selectDecreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
    688 }
    689 }
    690 else
    691 {
    692 SCIPdebugMsg(scip, "rounding heuristic: search rounding variable and try to stay feasible\n");
    693 SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &roundvar, &oldsolval, &newsolval) );
    694 }
    695
    696 /* check, whether rounding was possible */
    697 if( roundvar == NULL )
    698 {
    699 SCIPdebugMsg(scip, "rounding heuristic: -> didn't find a rounding variable\n");
    700 break;
    701 }
    702
    703 SCIPdebugMsg(scip, "rounding heuristic: -> round var <%s>, oldval=%g, newval=%g, obj=%g\n",
    704 SCIPvarGetName(roundvar), oldsolval, newsolval, SCIPvarGetObj(roundvar));
    705
    706 /* update row activities of globally valid rows */
    707 SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows,
    708 roundvar, oldsolval, newsolval) );
    709
    710 /* store new solution value and decrease fractionality counter */
    711 SCIP_CALL( SCIPsetSolVal(scip, sol, roundvar, newsolval) );
    712 nfrac--;
    713
    714 /* update minimal objective value possible after rounding remaining variables */
    715 obj = SCIPvarGetObj(roundvar);
    716 if( obj > 0.0 && newsolval > oldsolval )
    717 minobj += obj;
    718 else if( obj < 0.0 && newsolval < oldsolval )
    719 minobj -= obj;
    720
    721 SCIPdebugMsg(scip, "rounding heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
    722 nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
    723 }
    724
    725 /* check, if the new solution is feasible */
    726 if( nfrac == 0 && nviolrows == 0 )
    727 {
    728 SCIP_Bool stored;
    729
    730 /* check solution for feasibility, and add it to solution store if possible
    731 * neither integrality nor feasibility of LP rows has to be checked, because this is already
    732 * done in the rounding heuristic itself; however, be better check feasibility of LP rows,
    733 * because of numerical problems with activity updating
    734 */
    735 SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, FALSE, TRUE, &stored) );
    736
    737 if( stored )
    738 {
    739#ifdef SCIP_DEBUG
    740 SCIPdebugMsg(scip, "found feasible rounded solution:\n");
    742#endif
    743 *result = SCIP_FOUNDSOL;
    744 }
    745 }
    746
    747 /* free memory buffers */
    748 SCIPfreeBufferArray(scip, &violrowpos);
    749 SCIPfreeBufferArray(scip, &violrows);
    750 SCIPfreeBufferArray(scip, &activities);
    751
    752 return SCIP_OKAY;
    753}
    754
    755
    756/*
    757 * heuristic specific interface methods
    758 */
    759
    760/** creates the rounding heuristic with infeasibility recovering and includes it in SCIP */
    762 SCIP* scip /**< SCIP data structure */
    763 )
    764{
    765 SCIP_HEURDATA* heurdata;
    766 SCIP_HEUR* heur;
    767
    768 /* create Rounding primal heuristic data */
    769 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    770
    771 /* include primal heuristic */
    774 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecRounding, heurdata) );
    775
    776 assert(heur != NULL);
    777
    778 /* primal heuristic is safe to use in exact solving mode */
    779 SCIPheurMarkExact(heur);
    780
    781 /* set non-NULL pointers to callback methods */
    782 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyRounding) );
    783 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeRounding) );
    784 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitRounding) );
    785 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitRounding) );
    786 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolRounding) );
    787 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolRounding) );
    788
    789 /* add rounding primal heuristic parameters */
    790 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/successfactor",
    791 "number of calls per found solution that are considered as standard success, a higher factor causes the heuristic to be called more often",
    792 &heurdata->successfactor, TRUE, DEFAULT_SUCCESSFACTOR, -1, INT_MAX, NULL, NULL) );
    793
    794 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/oncepernode",
    795 "should the heuristic only be called once per node?",
    796 &heurdata->oncepernode, TRUE, DEFAULT_ONCEPERNODE, NULL, NULL) );
    797
    798 return SCIP_OKAY;
    799}
    SCIP_Real * r
    Definition: circlepacking.c:59
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_Bool
    Definition: def.h:100
    #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 SCIP_CALL(x)
    Definition: def.h:364
    #define nnodes
    Definition: gastrans.c:74
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    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 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 SCIPincludeHeurRounding(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_VAR * SCIPcolGetVar(SCIP_COL *col)
    Definition: lp.c:17425
    SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
    Definition: lp.c:17555
    SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
    Definition: lp.c:17545
    int SCIPcolGetNLPNonz(SCIP_COL *col)
    Definition: lp.c:17534
    SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXITSOL((*heurexitsol)))
    Definition: scip_heur.c:247
    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_Longint SCIPheurGetNSolsFound(SCIP_HEUR *heur)
    Definition: heur.c:1603
    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
    void SCIPheurSetTimingmask(SCIP_HEUR *heur, SCIP_HEURTIMING timingmask)
    Definition: heur.c:1507
    SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
    Definition: heur.c:1593
    SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
    Definition: scip_heur.c:231
    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_Bool SCIPhasCurrentNodeLP(SCIP *scip)
    Definition: scip_lp.c:87
    SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
    Definition: scip_lp.c:576
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    #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_Real SCIProwGetLhs(SCIP_ROW *row)
    Definition: lp.c:17686
    SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
    Definition: lp.c:17632
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    int SCIProwGetNLPNonz(SCIP_ROW *row)
    Definition: lp.c:17621
    int SCIProwGetLPPos(SCIP_ROW *row)
    Definition: lp.c:17895
    SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
    Definition: lp.c:17795
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:2068
    SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
    Definition: lp.c:17917
    SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
    Definition: lp.c:17642
    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 SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2351
    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_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1569
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2003
    SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2134
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23715
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4380
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4322
    static SCIP_RETCODE selectEssentialRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_VAR **lpcands, int nlpcands, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
    #define DEFAULT_SUCCESSFACTOR
    Definition: heur_rounding.c:60
    static SCIP_DECL_HEURCOPY(heurCopyRounding)
    #define HEUR_TIMING
    Definition: heur_rounding.c:57
    static SCIP_RETCODE updateActivities(SCIP *scip, SCIP_Real *activities, SCIP_ROW **violrows, int *violrowpos, int *nviolrows, int nlprows, SCIP_VAR *var, SCIP_Real oldsolval, SCIP_Real newsolval)
    static void updateViolations(SCIP *scip, SCIP_ROW *row, SCIP_ROW **violrows, int *violrowpos, int *nviolrows, SCIP_Real oldactivity, SCIP_Real newactivity)
    Definition: heur_rounding.c:83
    #define HEUR_FREQOFS
    Definition: heur_rounding.c:55
    #define HEUR_DESC
    Definition: heur_rounding.c:51
    #define DEFAULT_ONCEPERNODE
    Definition: heur_rounding.c:63
    #define HEUR_DISPCHAR
    Definition: heur_rounding.c:52
    #define HEUR_MAXDEPTH
    Definition: heur_rounding.c:56
    #define HEUR_PRIORITY
    Definition: heur_rounding.c:53
    static SCIP_RETCODE selectIncreaseRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_ROW *row, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
    #define HEUR_NAME
    Definition: heur_rounding.c:50
    static SCIP_DECL_HEUREXEC(heurExecRounding)
    static SCIP_DECL_HEUREXIT(heurExitRounding)
    static SCIP_RETCODE selectDecreaseRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_ROW *row, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
    static SCIP_DECL_HEUREXITSOL(heurExitsolRounding)
    static SCIP_DECL_HEURINITSOL(heurInitsolRounding)
    static SCIP_DECL_HEURFREE(heurFreeRounding)
    static SCIP_RETCODE selectRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_ROW *row, int direction, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
    static SCIP_DECL_HEURINIT(heurInitRounding)
    #define HEUR_FREQ
    Definition: heur_rounding.c:54
    #define HEUR_USESSUBSCIP
    Definition: heur_rounding.c:58
    LP rounding heuristic that tries to recover from intermediate infeasibilities.
    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
    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 solutions
    public methods for querying solving statistics
    struct SCIP_HeurData SCIP_HEURDATA
    Definition: type_heur.h:77
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ 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
    #define SCIP_HEURTIMING_AFTERLPNODE
    Definition: type_timing.h:83
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141