Scippy

    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-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file heur_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#include <string.h>
    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 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    434
    435 /* call inclusion method of primal heuristic */
    437
    438 return SCIP_OKAY;
    439}
    440
    441/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    442static
    443SCIP_DECL_HEURFREE(heurFreeRounding) /*lint --e{715}*/
    444{ /*lint --e{715}*/
    445 SCIP_HEURDATA* heurdata;
    446
    447 assert(heur != NULL);
    448 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    449 assert(scip != NULL);
    450
    451 /* free heuristic data */
    452 heurdata = SCIPheurGetData(heur);
    453 assert(heurdata != NULL);
    454 SCIPfreeBlockMemory(scip, &heurdata);
    455 SCIPheurSetData(heur, NULL);
    456
    457 return SCIP_OKAY;
    458}
    459
    460/** initialization method of primal heuristic (called after problem was transformed) */
    461static
    462SCIP_DECL_HEURINIT(heurInitRounding) /*lint --e{715}*/
    463{ /*lint --e{715}*/
    464 SCIP_HEURDATA* heurdata;
    465
    466 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    467
    468 heurdata = SCIPheurGetData(heur);
    469 assert(heurdata != NULL);
    470
    471 /* create heuristic data */
    472 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    473 heurdata->lastlp = -1;
    474
    475 return SCIP_OKAY;
    476}
    477
    478/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    479static
    480SCIP_DECL_HEUREXIT(heurExitRounding) /*lint --e{715}*/
    481{ /*lint --e{715}*/
    482 SCIP_HEURDATA* heurdata;
    483
    484 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    485
    486 /* free heuristic data */
    487 heurdata = SCIPheurGetData(heur);
    488 assert(heurdata != NULL);
    489 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    490
    491 return SCIP_OKAY;
    492}
    493
    494/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
    495static
    496SCIP_DECL_HEURINITSOL(heurInitsolRounding)
    497{
    498 SCIP_HEURDATA* heurdata;
    499
    500 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    501
    502 heurdata = SCIPheurGetData(heur);
    503 assert(heurdata != NULL);
    504 heurdata->lastlp = -1;
    505
    506 /* change the heuristic's timingmask, if nit should be called only once per node */
    507 if( heurdata->oncepernode )
    509
    510 return SCIP_OKAY;
    511}
    512
    513/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
    514static
    515SCIP_DECL_HEUREXITSOL(heurExitsolRounding)
    516{
    517 /* reset the timing mask to its default value */
    519
    520 return SCIP_OKAY;
    521}
    522
    523
    524/** execution method of primal heuristic */
    525static
    526SCIP_DECL_HEUREXEC(heurExecRounding) /*lint --e{715}*/
    527{ /*lint --e{715}*/
    528 SCIP_HEURDATA* heurdata;
    529 SCIP_SOL* sol;
    530 SCIP_VAR** lpcands;
    531 SCIP_Real* lpcandssol;
    532 SCIP_ROW** lprows;
    533 SCIP_Real* activities;
    534 SCIP_ROW** violrows;
    535 int* violrowpos;
    536 SCIP_Real obj;
    537 SCIP_Real bestroundval;
    538 SCIP_Real minobj;
    539 int nfrac;
    540 int nlpcands;
    541 int nlprows;
    542 int nviolrows;
    543 int c;
    544 int r;
    545 SCIP_Longint nlps;
    546 SCIP_Longint ncalls;
    547 SCIP_Longint nsolsfound;
    549
    550 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    551 assert(scip != NULL);
    552 assert(result != NULL);
    553 assert(SCIPhasCurrentNodeLP(scip));
    554
    555 *result = SCIP_DIDNOTRUN;
    556
    557 /* only call heuristic, if an optimal LP solution is at hand */
    559 return SCIP_OKAY;
    560
    561 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    563 return SCIP_OKAY;
    564
    565 /* get heuristic data */
    566 heurdata = SCIPheurGetData(heur);
    567 assert(heurdata != NULL);
    568
    569 /* don't call heuristic, if we have already processed the current LP solution */
    570 nlps = SCIPgetNLPs(scip);
    571 if( nlps == heurdata->lastlp )
    572 return SCIP_OKAY;
    573 heurdata->lastlp = nlps;
    574
    575 /* don't call heuristic, if it was not successful enough in the past */
    576 ncalls = SCIPheurGetNCalls(heur);
    577 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur);
    579 if( nnodes % ((ncalls/heurdata->successfactor)/(nsolsfound+1)+1) != 0 )
    580 return SCIP_OKAY;
    581
    582 /* get fractional variables, that should be integral */
    583 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) );
    584
    585 /* only call heuristic, if LP solution is fractional */
    586 if( nlpcands == 0 )
    587 return SCIP_OKAY;
    588
    589 *result = SCIP_DIDNOTFIND;
    590
    591 /* get LP rows */
    592 SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );
    593
    594 SCIPdebugMsg(scip, "executing rounding heuristic: %d LP rows, %d LP candidates\n", nlprows, nlpcands);
    595
    596 /* get memory for activities, violated rows, and row violation positions */
    597 nfrac = nlpcands;
    598 SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
    599 SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) );
    600 SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) );
    601
    602 /* get the activities for all globally valid rows;
    603 * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated
    604 */
    605 nviolrows = 0;
    606 for( r = 0; r < nlprows; ++r )
    607 {
    608 SCIP_ROW* row;
    609
    610 row = lprows[r];
    611 assert(SCIProwGetLPPos(row) == r);
    612
    613 if( !SCIProwIsLocal(row) )
    614 {
    615 activities[r] = SCIPgetRowActivity(scip, row);
    616 if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row))
    617 || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) )
    618 {
    619 violrows[nviolrows] = row;
    620 violrowpos[r] = nviolrows;
    621 nviolrows++;
    622 }
    623 else
    624 violrowpos[r] = -1;
    625 }
    626 }
    627
    628 /* get the working solution from heuristic's local data */
    629 sol = heurdata->sol;
    630 assert(sol != NULL);
    631
    632 /* copy the current LP solution to the working solution */
    634
    635 /* calculate the minimal objective value possible after rounding fractional variables */
    636 minobj = SCIPgetSolTransObj(scip, sol);
    637 assert(minobj < SCIPgetCutoffbound(scip));
    638 for( c = 0; c < nlpcands; ++c )
    639 {
    640 obj = SCIPvarGetObj(lpcands[c]);
    641 bestroundval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]);
    642 minobj += obj * (bestroundval - lpcandssol[c]);
    643 }
    644
    645 /* try to round remaining variables in order to become/stay feasible */
    646 while( nfrac > 0 )
    647 {
    648 SCIP_VAR* roundvar;
    649 SCIP_Real oldsolval;
    650 SCIP_Real newsolval;
    651
    652 SCIPdebugMsg(scip, "rounding heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
    653 nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
    654
    655 /* minobj < SCIPgetCutoffbound(scip) should be true, otherwise the rounding variable selection
    656 * should have returned NULL. Due to possible cancellation we use SCIPisLE. */
    657 assert( SCIPisLE(scip, minobj, SCIPgetCutoffbound(scip)) );
    658
    659 /* choose next variable to process:
    660 * - if a violated row exists, round a variable decreasing the violation, that has least impact on other rows
    661 * - otherwise, round a variable, that has strongest devastating impact on rows in opposite direction
    662 */
    663 if( nviolrows > 0 )
    664 {
    665 SCIP_ROW* row;
    666 int rowpos;
    667
    668 row = violrows[nviolrows-1];
    669 rowpos = SCIProwGetLPPos(row);
    670 assert(0 <= rowpos && rowpos < nlprows);
    671 assert(violrowpos[rowpos] == nviolrows-1);
    672
    673 SCIPdebugMsg(scip, "rounding heuristic: try to fix violated row <%s>: %g <= %g <= %g\n",
    674 SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row));
    675 if( SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) )
    676 {
    677 /* lhs is violated: select a variable rounding, that increases the activity */
    678 SCIP_CALL( selectIncreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
    679 }
    680 else
    681 {
    682 assert(SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row)));
    683 /* rhs is violated: select a variable rounding, that decreases the activity */
    684 SCIP_CALL( selectDecreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
    685 }
    686 }
    687 else
    688 {
    689 SCIPdebugMsg(scip, "rounding heuristic: search rounding variable and try to stay feasible\n");
    690 SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &roundvar, &oldsolval, &newsolval) );
    691 }
    692
    693 /* check, whether rounding was possible */
    694 if( roundvar == NULL )
    695 {
    696 SCIPdebugMsg(scip, "rounding heuristic: -> didn't find a rounding variable\n");
    697 break;
    698 }
    699
    700 SCIPdebugMsg(scip, "rounding heuristic: -> round var <%s>, oldval=%g, newval=%g, obj=%g\n",
    701 SCIPvarGetName(roundvar), oldsolval, newsolval, SCIPvarGetObj(roundvar));
    702
    703 /* update row activities of globally valid rows */
    704 SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows,
    705 roundvar, oldsolval, newsolval) );
    706
    707 /* store new solution value and decrease fractionality counter */
    708 SCIP_CALL( SCIPsetSolVal(scip, sol, roundvar, newsolval) );
    709 nfrac--;
    710
    711 /* update minimal objective value possible after rounding remaining variables */
    712 obj = SCIPvarGetObj(roundvar);
    713 if( obj > 0.0 && newsolval > oldsolval )
    714 minobj += obj;
    715 else if( obj < 0.0 && newsolval < oldsolval )
    716 minobj -= obj;
    717
    718 SCIPdebugMsg(scip, "rounding heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
    719 nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
    720 }
    721
    722 /* check, if the new solution is feasible */
    723 if( nfrac == 0 && nviolrows == 0 )
    724 {
    725 SCIP_Bool stored;
    726
    727 /* check solution for feasibility, and add it to solution store if possible
    728 * neither integrality nor feasibility of LP rows has to be checked, because this is already
    729 * done in the rounding heuristic itself; however, be better check feasibility of LP rows,
    730 * because of numerical problems with activity updating
    731 */
    732 SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, FALSE, TRUE, &stored) );
    733
    734 if( stored )
    735 {
    736#ifdef SCIP_DEBUG
    737 SCIPdebugMsg(scip, "found feasible rounded solution:\n");
    739#endif
    740 *result = SCIP_FOUNDSOL;
    741 }
    742 }
    743
    744 /* free memory buffers */
    745 SCIPfreeBufferArray(scip, &violrowpos);
    746 SCIPfreeBufferArray(scip, &violrows);
    747 SCIPfreeBufferArray(scip, &activities);
    748
    749 return SCIP_OKAY;
    750}
    751
    752
    753/*
    754 * heuristic specific interface methods
    755 */
    756
    757/** creates the rounding heuristic with infeasibility recovering and includes it in SCIP */
    759 SCIP* scip /**< SCIP data structure */
    760 )
    761{
    762 SCIP_HEURDATA* heurdata;
    763 SCIP_HEUR* heur;
    764
    765 /* create Rounding primal heuristic data */
    766 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    767
    768 /* include primal heuristic */
    771 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecRounding, heurdata) );
    772
    773 assert(heur != NULL);
    774
    775 /* primal heuristic is safe to use in exact solving mode */
    776 SCIPheurMarkExact(heur);
    777
    778 /* set non-NULL pointers to callback methods */
    779 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyRounding) );
    780 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeRounding) );
    781 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitRounding) );
    782 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitRounding) );
    783 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolRounding) );
    784 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolRounding) );
    785
    786 /* add rounding primal heuristic parameters */
    787 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/successfactor",
    788 "number of calls per found solution that are considered as standard success, a higher factor causes the heuristic to be called more often",
    789 &heurdata->successfactor, TRUE, DEFAULT_SUCCESSFACTOR, -1, INT_MAX, NULL, NULL) );
    790
    791 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/oncepernode",
    792 "should the heuristic only be called once per node?",
    793 &heurdata->oncepernode, TRUE, DEFAULT_ONCEPERNODE, NULL, NULL) );
    794
    795 return SCIP_OKAY;
    796}
    SCIP_Real * r
    Definition: circlepacking.c:59
    #define NULL
    Definition: def.h:248
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_CALL(x)
    Definition: def.h:355
    #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:516
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2349
    SCIP_RETCODE SCIPtrySol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
    Definition: scip_sol.c:4012
    SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1295
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1892
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2005
    SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2132
    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:23683
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4328
    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
    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