Scippy

    SCIP

    Solving Constraint Integer Programs

    heur_zirounding.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_zirounding.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief zirounding primal heuristic
    28 * @author Gregor Hendel
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    35#include "scip/pub_heur.h"
    36#include "scip/pub_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 "zirounding"
    51#define HEUR_DESC "LP rounding heuristic as suggested by C. Wallace taking row slacks and bounds into account"
    52#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_ROUNDING
    53#define HEUR_PRIORITY -500
    54#define HEUR_FREQ 1
    55#define HEUR_FREQOFS 0
    56#define HEUR_MAXDEPTH -1
    57#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPNODE
    58#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    59
    60#define DEFAULT_MAXROUNDINGLOOPS 2 /**< delimits the number of main loops, can be set to -1 for no limit */
    61#define DEFAULT_STOPZIROUND TRUE /**< deactivation check is enabled by default */
    62#define DEFAULT_STOPPERCENTAGE 0.02 /**< the tolerance percentage after which zirounding will not be executed anymore */
    63#define DEFAULT_MINSTOPNCALLS 1000 /**< number of heuristic calls before deactivation check */
    64
    65#define MINSHIFT 1e-4 /**< minimum shift value for every single step */
    66
    67/*
    68 * Data structures
    69 */
    70
    71/** primal heuristic data */
    72struct SCIP_HeurData
    73{
    74 SCIP_SOL* sol; /**< working solution */
    75 SCIP_Longint lastlp; /**< the number of the last LP for which ZIRounding was called */
    76 int maxroundingloops; /**< limits rounding loops in execution */
    77 SCIP_Bool stopziround; /**< sets deactivation check */
    78 SCIP_Real stoppercentage; /**< threshold for deactivation check */
    79 int minstopncalls; /**< number of heuristic calls before deactivation check */
    80};
    81
    83{
    86};
    87typedef enum Direction DIRECTION;
    88
    89/*
    90 * Local methods
    91 */
    92
    93/** returns the fractionality of a value x, which is calculated as zivalue(x) = min(x-floor(x), ceil(x)-x) */
    94static
    96 SCIP* scip, /**< pointer to current SCIP data structure */
    97 SCIP_Real val /**< the value for which the fractionality should be computed */
    98 )
    99{
    100 SCIP_Real upgap; /* the gap between val and ceil(val) */
    101 SCIP_Real downgap; /* the gap between val and floor(val) */
    102
    103 assert(scip != NULL);
    104
    105 upgap = SCIPfeasCeil(scip, val) - val;
    106 downgap = val - SCIPfeasFloor(scip, val);
    107
    108 return MIN(upgap, downgap);
    109}
    110
    111/** determines shifting bounds for variable */
    112static
    114 SCIP* scip, /**< pointer to current SCIP data structure */
    115 SCIP_VAR* var, /**< the variable for which lb and ub have to be calculated */
    116 SCIP_Real currentvalue, /**< the current value of var in the working solution */
    117 SCIP_Real* upperbound, /**< pointer to store the calculated upper bound on the variable shift */
    118 SCIP_Real* lowerbound, /**< pointer to store the calculated lower bound on the variable shift */
    119 SCIP_Real* upslacks, /**< array that contains the slacks between row activities and the right hand sides of the rows */
    120 SCIP_Real* downslacks, /**< array that contains lhs slacks */
    121 int nslacks, /**< current number of slacks */
    122 SCIP_Bool* numericalerror /**< flag to determine whether a numerical error occurred */
    123 )
    124{
    125 SCIP_COL* col;
    126 SCIP_ROW** colrows;
    127 SCIP_Real* colvals;
    128 int ncolvals;
    129 int i;
    130
    131 assert(scip != NULL);
    132 assert(var != NULL);
    133 assert(upslacks != NULL);
    134 assert(downslacks != NULL);
    135 assert(upperbound != NULL);
    136 assert(lowerbound != NULL);
    137
    138 /* get the column associated to the variable, the nonzero rows and the nonzero coefficients */
    139 col = SCIPvarGetCol(var);
    140 colrows = SCIPcolGetRows(col);
    141 colvals = SCIPcolGetVals(col);
    142 ncolvals = SCIPcolGetNLPNonz(col);
    143
    144 /* only proceed, when variable has nonzero coefficients */
    145 if( ncolvals == 0 )
    146 return;
    147
    148 assert(colvals != NULL);
    149 assert(colrows != NULL);
    150
    151 /* initialize the bounds on the shift to be the gap of the current solution value to the bounds of the variable */
    153 *upperbound = SCIPinfinity(scip);
    154 else
    155 *upperbound = SCIPvarGetUbGlobal(var) - currentvalue;
    156
    158 *lowerbound = SCIPinfinity(scip);
    159 else
    160 *lowerbound = currentvalue - SCIPvarGetLbGlobal(var);
    161
    162 /* go through every nonzero row coefficient corresponding to var to determine bounds for shifting
    163 * in such a way that shifting maintains feasibility in every LP row.
    164 * a lower or upper bound as it is calculated in zirounding always has to be >= 0.0.
    165 * if one of these values is significantly < 0.0, this will cause the abort of execution of the heuristic so that
    166 * infeasible solutions are avoided
    167 */
    168 for( i = 0; i < ncolvals && MAX(*lowerbound, *upperbound) >= MINSHIFT; ++i )
    169 {
    170 SCIP_ROW* row;
    171 int rowpos;
    172
    173 row = colrows[i];
    174 rowpos = SCIProwGetLPPos(row);
    175
    176 /* the row might currently not be in the LP, ignore it! */
    177 if( rowpos == -1 )
    178 continue;
    179
    180 assert(0 <= rowpos && rowpos < nslacks);
    181
    182 /* all bounds and slacks as they are calculated in zirounding always have to be greater equal zero.
    183 * It might however be due to numerical issues, e.g. with scaling, that they are not. Better abort in this case.
    184 */
    185 if( SCIPisFeasLT(scip, *lowerbound, 0.0) || SCIPisFeasLT(scip, *upperbound, 0.0)
    186 || SCIPisFeasLT(scip, upslacks[rowpos], 0.0) || SCIPisFeasLT(scip, downslacks[rowpos] , 0.0) )
    187 {
    188 *numericalerror = TRUE;
    189 return;
    190 }
    191
    192 SCIPdebugMsg(scip, "colval: %15.8g, downslack: %15.8g, upslack: %5.2g, lb: %5.2g, ub: %5.2g\n", colvals[i], downslacks[rowpos], upslacks[rowpos],
    193 *lowerbound, *upperbound);
    194
    195 /* if coefficient > 0, rounding up might violate up slack and rounding down might violate down slack
    196 * thus search for the minimum so that no constraint is violated; vice versa for coefficient < 0
    197 */
    198 if( colvals[i] > 0 )
    199 {
    200 if( !SCIPisInfinity(scip, upslacks[rowpos]) )
    201 {
    202 SCIP_Real upslack;
    203 upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
    204 *upperbound = MIN(*upperbound, upslack/colvals[i]);
    205 }
    206
    207 if( !SCIPisInfinity(scip, downslacks[rowpos]) )
    208 {
    209 SCIP_Real downslack;
    210 downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
    211 *lowerbound = MIN(*lowerbound, downslack/colvals[i]);
    212 }
    213 }
    214 else
    215 {
    216 assert(colvals[i] != 0.0);
    217
    218 if( !SCIPisInfinity(scip, upslacks[rowpos]) )
    219 {
    220 SCIP_Real upslack;
    221 upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
    222 *lowerbound = MIN(*lowerbound, -upslack/colvals[i]);
    223 }
    224
    225 if( !SCIPisInfinity(scip, downslacks[rowpos]) )
    226 {
    227 SCIP_Real downslack;
    228 downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
    229 *upperbound = MIN(*upperbound, -downslack/colvals[i]);
    230 }
    231 }
    232 }
    233}
    234
    235/** when a variable is shifted, the activities and slacks of all rows it appears in have to be updated */
    236static
    238 SCIP* scip, /**< pointer to current SCIP data structure */
    239 SCIP_SOL* sol, /**< working solution */
    240 SCIP_VAR* var, /**< pointer to variable to be modified */
    241 SCIP_Real shiftvalue, /**< the value by which the variable is shifted */
    242 SCIP_Real* upslacks, /**< upslacks of all rows the variable appears in */
    243 SCIP_Real* downslacks, /**< downslacks of all rows the variable appears in */
    244 SCIP_Real* activities, /**< activities of the LP rows */
    245 SCIP_VAR** slackvars, /**< the slack variables for equality rows */
    246 SCIP_Real* slackcoeffs, /**< the slack variable coefficients */
    247 int nslacks /**< size of the arrays */
    248 )
    249{
    250 SCIP_COL* col; /* the corresponding column of variable var */
    251 SCIP_ROW** rows; /* pointer to the nonzero coefficient rows for variable var */
    252 int nrows; /* the number of nonzeros */
    253 SCIP_Real* colvals; /* array to store the nonzero coefficients */
    254 int i;
    255
    256 assert(scip != NULL);
    257 assert(sol != NULL);
    258 assert(var != NULL);
    259 assert(upslacks != NULL);
    260 assert(downslacks != NULL);
    261 assert(activities != NULL);
    262 assert(nslacks >= 0);
    263
    264 col = SCIPvarGetCol(var);
    265 assert(col != NULL);
    266
    267 rows = SCIPcolGetRows(col);
    268 nrows = SCIPcolGetNLPNonz(col);
    269 colvals = SCIPcolGetVals(col);
    270 assert(nrows == 0 || (rows != NULL && colvals != NULL));
    271
    272 /* go through all rows the shifted variable appears in */
    273 for( i = 0; i < nrows; ++i )
    274 {
    275 int rowpos;
    276
    277 rowpos = SCIProwGetLPPos(rows[i]);
    278 assert(-1 <= rowpos && rowpos < nslacks);
    279
    280 /* if the row is in the LP, update its activity, up and down slack */
    281 if( rowpos >= 0 )
    282 {
    283 SCIP_Real val;
    284 SCIP_Real lhs;
    285 SCIP_Real rhs;
    286 SCIP_ROW* row;
    287
    288 val = colvals[i] * shiftvalue;
    289 row = rows[i];
    290 lhs = SCIProwGetLhs(row);
    291 rhs = SCIProwGetRhs(row);
    292
    293 /* if the row is an equation, we update its slack variable instead of its activities */
    294 if( SCIPisFeasEQ(scip, lhs, rhs) )
    295 {
    296 SCIP_Real slackvarshiftval;
    297 SCIP_Real slackvarsolval;
    298
    299 assert(slackvars[rowpos] != NULL);
    300 assert(!SCIPisZero(scip, slackcoeffs[rowpos]));
    301
    302 slackvarsolval = SCIPgetSolVal(scip, sol, slackvars[rowpos]);
    303 slackvarshiftval = -val / slackcoeffs[rowpos];
    304
    305 assert(SCIPisFeasGE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetLbGlobal(slackvars[rowpos])));
    306 assert(SCIPisFeasLE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetUbGlobal(slackvars[rowpos])));
    307
    308 SCIP_CALL( SCIPsetSolVal(scip, sol, slackvars[rowpos], slackvarsolval + slackvarshiftval) );
    309 }
    310 else if( !SCIPisInfinity(scip, REALABS(activities[rowpos])) )
    311 activities[rowpos] += val;
    312
    313 /* the slacks of the row now can be updated independently of its type */
    314 if( !SCIPisInfinity(scip, upslacks[rowpos]) )
    315 upslacks[rowpos] -= val;
    316 if( !SCIPisInfinity(scip, -downslacks[rowpos]) )
    317 downslacks[rowpos] += val;
    318
    319 assert(SCIPisInfinity(scip, -lhs) || SCIPisFeasGE(scip, activities[rowpos], lhs));
    320 assert(SCIPisInfinity(scip, rhs) || SCIPisFeasLE(scip, activities[rowpos], rhs));
    321 }
    322 }
    323 return SCIP_OKAY;
    324}
    325
    326/** finds a continuous slack variable for an equation row, NULL if none exists */
    327static
    329 SCIP* scip, /**< pointer to current SCIP data structure */
    330 SCIP_ROW* row, /**< the row for which a slack variable is searched */
    331 SCIP_VAR** varpointer, /**< pointer to store the slack variable */
    332 SCIP_Real* coeffpointer /**< pointer to store the coefficient of the slack variable */
    333 )
    334{
    335 int v;
    336 SCIP_COL** rowcols;
    337 SCIP_Real* rowvals;
    338 int nrowvals;
    339
    340 assert(row != NULL);
    341 assert(varpointer != NULL);
    342 assert(coeffpointer != NULL);
    343
    344 rowcols = SCIProwGetCols(row);
    345 rowvals = SCIProwGetVals(row);
    346 nrowvals = SCIProwGetNNonz(row);
    347
    348 assert(nrowvals == 0 || rowvals != NULL);
    349 assert(nrowvals == 0 || rowcols != NULL);
    350
    351 /* iterate over the row variables. Stop after the first unfixed continuous variable was found. */
    352 for( v = nrowvals - 1; v >= 0; --v )
    353 {
    354 SCIP_VAR* colvar;
    355
    356 assert(rowcols[v] != NULL);
    357 if( SCIPcolGetLPPos(rowcols[v]) == -1 )
    358 continue;
    359
    360 colvar = SCIPcolGetVar(rowcols[v]);
    361
    362 if( !SCIPvarIsIntegral(colvar)
    364 && SCIPcolGetNLPNonz(rowcols[v]) == 1 )
    365 {
    366 SCIPdebugMsg(scip, " slack variable for row %s found: %s\n", SCIProwGetName(row), SCIPvarGetName(colvar));
    367
    368 *coeffpointer = rowvals[v];
    369 *varpointer = colvar;
    370
    371 return;
    372 }
    373 }
    374
    375 *varpointer = NULL;
    376 *coeffpointer = 0.0;
    377
    378 SCIPdebugMsg(scip, "No slack variable for row %s found. \n", SCIProwGetName(row));
    379}
    380
    381/*
    382 * Callback methods of primal heuristic
    383 */
    384
    385/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    386static
    387SCIP_DECL_HEURCOPY(heurCopyZirounding)
    388{ /*lint --e{715}*/
    389 assert(scip != NULL);
    390 assert(heur != NULL);
    391 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    392
    393 /* call inclusion method of primal heuristic */
    395
    396 return SCIP_OKAY;
    397}
    398
    399/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    400static
    401SCIP_DECL_HEURFREE(heurFreeZirounding)
    402{ /*lint --e{715}*/
    403 SCIP_HEURDATA* heurdata;
    404
    405 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    406
    407 heurdata = SCIPheurGetData(heur);
    408 assert(heurdata != NULL);
    409
    410 /* free heuristic data */
    411 SCIPfreeBlockMemory(scip, &heurdata);
    412 SCIPheurSetData(heur, NULL);
    413
    414 return SCIP_OKAY;
    415}
    416
    417/** initialization method of primal heuristic (called after problem was transformed) */
    418static
    419SCIP_DECL_HEURINIT(heurInitZirounding)
    420{ /*lint --e{715}*/
    421 SCIP_HEURDATA* heurdata;
    422
    423 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    424
    425 heurdata = SCIPheurGetData(heur);
    426 assert(heurdata != NULL);
    427
    428 /* create working solution */
    429 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    430
    431 return SCIP_OKAY;
    432}
    433
    434/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    435static
    436SCIP_DECL_HEUREXIT(heurExitZirounding) /*lint --e{715}*/
    437{ /*lint --e{715}*/
    438 SCIP_HEURDATA* heurdata;
    439
    440 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    441
    442 heurdata = SCIPheurGetData(heur);
    443 assert(heurdata != NULL);
    444
    445 /* free working solution */
    446 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    447
    448 return SCIP_OKAY;
    449}
    450
    451/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
    452static
    453SCIP_DECL_HEURINITSOL(heurInitsolZirounding)
    454{ /*lint --e{715}*/
    455 SCIP_HEURDATA* heurdata;
    456
    457 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    458
    459 heurdata = SCIPheurGetData(heur);
    460 assert(heurdata != NULL);
    461
    462 heurdata->lastlp = -1;
    463
    464 return SCIP_OKAY;
    465}
    466
    467
    468/** execution method of primal heuristic */
    469static
    470SCIP_DECL_HEUREXEC(heurExecZirounding)
    471{ /*lint --e{715}*/
    472 SCIP_HEURDATA* heurdata;
    473 SCIP_SOL* sol;
    474 SCIP_VAR** lpcands;
    475 SCIP_VAR** zilpcands;
    476
    477 SCIP_VAR** slackvars;
    478 SCIP_Real* upslacks;
    479 SCIP_Real* downslacks;
    480 SCIP_Real* activities;
    481 SCIP_Real* slackvarcoeffs;
    482 SCIP_Bool* rowneedsslackvar;
    483
    484 SCIP_ROW** rows;
    485 SCIP_Real* lpcandssol;
    486 SCIP_Real* solarray;
    487
    488 SCIP_Longint nlps;
    489 int currentlpcands;
    490 int nlpcands;
    491 int nimplfracs;
    492 int i;
    493 int c;
    494 int nslacks;
    495 int nroundings;
    496
    497 SCIP_Bool improvementfound;
    498 SCIP_Bool numericalerror;
    499
    500 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    501 assert(result != NULL);
    502 assert(SCIPhasCurrentNodeLP(scip));
    503
    504 *result = SCIP_DIDNOTRUN;
    505
    506 /* do not call heuristic of node was already detected to be infeasible */
    507 if( nodeinfeasible )
    508 return SCIP_OKAY;
    509
    510 /* only call heuristic if an optimal LP-solution is at hand */
    512 return SCIP_OKAY;
    513
    514 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    516 return SCIP_OKAY;
    517
    518 /* get heuristic data */
    519 heurdata = SCIPheurGetData(heur);
    520 assert(heurdata != NULL);
    521
    522 /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation
    523 * to number of calls falls below heurdata->stoppercentage */
    524 if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls
    525 && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage )
    526 return SCIP_OKAY;
    527
    528 /* assure that heuristic has not already been called after the last LP had been solved */
    529 nlps = SCIPgetNLPs(scip);
    530 if( nlps == heurdata->lastlp )
    531 return SCIP_OKAY;
    532
    533 heurdata->lastlp = nlps;
    534
    535 /* @todo: check whether rounding continuous implied integral variables is necessary */
    536 /* get fractional variables */
    537 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) );
    538 nlpcands = nlpcands + nimplfracs;
    539
    540 /* make sure that there is at least one fractional variable that should be integral */
    541 if( nlpcands == 0 )
    542 return SCIP_OKAY;
    543
    544 assert(nlpcands > 0);
    545 assert(lpcands != NULL);
    546 assert(lpcandssol != NULL);
    547
    548 /* get LP rows data */
    549 rows = SCIPgetLPRows(scip);
    550 nslacks = SCIPgetNLPRows(scip);
    551
    552 /* cannot do anything if LP is empty */
    553 if( nslacks == 0 )
    554 return SCIP_OKAY;
    555
    556 assert(rows != NULL);
    557 assert(nslacks > 0);
    558
    559 /* get the working solution from heuristic's local data */
    560 sol = heurdata->sol;
    561 assert(sol != NULL);
    562
    563 *result = SCIP_DIDNOTFIND;
    564
    565 solarray = NULL;
    566 zilpcands = NULL;
    567
    568 /* copy the current LP solution to the working solution and allocate memory for local data */
    570 SCIP_CALL( SCIPallocBufferArray(scip, &solarray, nlpcands) );
    571 SCIP_CALL( SCIPallocBufferArray(scip, &zilpcands, nlpcands) );
    572
    573 /* copy necessary data to local arrays */
    574 BMScopyMemoryArray(solarray, lpcandssol, nlpcands);
    575 BMScopyMemoryArray(zilpcands, lpcands, nlpcands);
    576
    577 /* allocate buffer data arrays */
    578 SCIP_CALL( SCIPallocBufferArray(scip, &slackvars, nslacks) );
    579 SCIP_CALL( SCIPallocBufferArray(scip, &upslacks, nslacks) );
    580 SCIP_CALL( SCIPallocBufferArray(scip, &downslacks, nslacks) );
    581 SCIP_CALL( SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks) );
    582 SCIP_CALL( SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks) );
    583 SCIP_CALL( SCIPallocBufferArray(scip, &activities, nslacks) );
    584
    585 BMSclearMemoryArray(slackvars, nslacks);
    586 BMSclearMemoryArray(slackvarcoeffs, nslacks);
    587 BMSclearMemoryArray(rowneedsslackvar, nslacks);
    588
    589 numericalerror = FALSE;
    590 nroundings = 0;
    591
    592 /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */
    593 for( c = 0; c < nlpcands; ++c )
    594 {
    595 SCIP_VAR* cand;
    596 SCIP_ROW** candrows;
    597 int r;
    598 int ncandrows;
    599
    600 cand = zilpcands[c];
    601 assert(cand != NULL);
    602 assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0);
    603
    604 candrows = SCIPcolGetRows(SCIPvarGetCol(cand));
    605 ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand));
    606
    607 assert(candrows == NULL || ncandrows > 0);
    608
    609 for( r = 0; r < ncandrows; ++r )
    610 {
    611 int rowpos;
    612
    613 assert(candrows != NULL); /* to please flexelint */
    614 assert(candrows[r] != NULL);
    615 rowpos = SCIProwGetLPPos(candrows[r]);
    616
    617 if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) )
    618 {
    619 rowneedsslackvar[rowpos] = TRUE;
    620 SCIPdebugMsg(scip, " Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand));
    621 }
    622 }
    623 }
    624
    625 /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution
    626 * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero,
    627 * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering
    628 */
    629 for( i = 0; i < nslacks; ++i )
    630 {
    631 SCIP_ROW* row;
    632 SCIP_Real lhs;
    633 SCIP_Real rhs;
    634
    635 row = rows[i];
    636
    637 assert(row != NULL);
    638
    639 lhs = SCIProwGetLhs(row);
    640 rhs = SCIProwGetRhs(row);
    641
    642 /* get row activity */
    643 activities[i] = SCIPgetRowActivity(scip, row);
    644 assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs));
    645
    646 /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */
    647 if( SCIPisInfinity(scip, -lhs) )
    648 downslacks[i] = SCIPinfinity(scip);
    649 else
    650 downslacks[i] = activities[i] - lhs;
    651
    652 if( SCIPisInfinity(scip, rhs) )
    653 upslacks[i] = SCIPinfinity(scip);
    654 else
    655 upslacks[i] = rhs - activities[i];
    656
    657 SCIPdebugMsg(scip, "lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]);
    658
    659 /* row is an equation. Try to find a slack variable in the row, i.e.,
    660 * a continuous variable which occurs only in this row. If no such variable exists,
    661 * there is no hope for an IP-feasible solution in this round
    662 */
    663 if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] )
    664 {
    665 /* @todo: This is only necessary for rows containing fractional variables. */
    666 rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i]));
    667
    668 if( slackvars[i] == NULL )
    669 {
    670 SCIPdebugMsg(scip, "No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row));
    671 goto TERMINATE;
    672 }
    673 else
    674 {
    675 SCIP_Real ubslackvar;
    676 SCIP_Real lbslackvar;
    677 SCIP_Real solvalslackvar;
    678 SCIP_Real coeffslackvar;
    679 SCIP_Real ubgap;
    680 SCIP_Real lbgap;
    681
    682 assert(!SCIPvarIsIntegral(slackvars[i]));
    683 solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]);
    684 ubslackvar = SCIPvarGetUbGlobal(slackvars[i]);
    685 lbslackvar = SCIPvarGetLbGlobal(slackvars[i]);
    686
    687 coeffslackvar = slackvarcoeffs[i];
    688 assert(!SCIPisZero(scip, coeffslackvar));
    689
    690 ubgap = MAX(0.0, ubslackvar - solvalslackvar);
    691 lbgap = MAX(0.0, solvalslackvar - lbslackvar);
    692
    693 if( SCIPisPositive(scip, coeffslackvar) )
    694 {
    695 if( !SCIPisInfinity(scip, lbslackvar) )
    696 upslacks[i] += coeffslackvar * lbgap;
    697 else
    698 upslacks[i] = SCIPinfinity(scip);
    699 if( !SCIPisInfinity(scip, ubslackvar) )
    700 downslacks[i] += coeffslackvar * ubgap;
    701 else
    702 downslacks[i] = SCIPinfinity(scip);
    703 }
    704 else
    705 {
    706 if( !SCIPisInfinity(scip, ubslackvar) )
    707 upslacks[i] -= coeffslackvar * ubgap;
    708 else
    709 upslacks[i] = SCIPinfinity(scip);
    710 if( !SCIPisInfinity(scip, lbslackvar) )
    711 downslacks[i] -= coeffslackvar * lbgap;
    712 else
    713 downslacks[i] = SCIPinfinity(scip);
    714 }
    715 SCIPdebugMsg(scip, " Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g \n",
    716 SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar,
    717 upslacks[i], downslacks[i]);
    718 }
    719 }
    720 /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are
    721 * significantly smaller than zero -> terminate
    722 */
    723 if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) )
    724 goto TERMINATE;
    725 }
    726
    727 assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL));
    728
    729 /* initialize number of remaining variables and flag to enter the main loop */
    730 currentlpcands = nlpcands;
    731 improvementfound = TRUE;
    732
    733 /* iterate over variables as long as there are fractional variables left */
    734 while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) )
    735 { /*lint --e{850}*/
    736 improvementfound = FALSE;
    737 nroundings++;
    738 SCIPdebugMsg(scip, "zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands);
    739
    740 /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */
    741 for( c = 0; c < currentlpcands; ++c )
    742 {
    743 SCIP_VAR* var;
    744 SCIP_Real oldsolval;
    745 SCIP_Real upperbound;
    746 SCIP_Real lowerbound;
    747 SCIP_Real up;
    748 SCIP_Real down;
    749 SCIP_Real ziup;
    750 SCIP_Real zidown;
    751 SCIP_Real zicurrent;
    752 SCIP_Real shiftval;
    753
    754 DIRECTION direction;
    755
    756 /* get values from local data */
    757 oldsolval = solarray[c];
    758 var = zilpcands[c];
    759
    760 assert(!SCIPisFeasIntegral(scip, oldsolval));
    762
    763 /* calculate bounds for variable and make sure that there are no numerical inconsistencies */
    764 upperbound = SCIPinfinity(scip);
    765 lowerbound = SCIPinfinity(scip);
    766 calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror);
    767
    768 if( numericalerror )
    769 goto TERMINATE;
    770
    771 /* continue if only marginal shifts are possible */
    772 if( MAX(upperbound, lowerbound) < MINSHIFT )
    773 {
    774 /* stop immediately if a variable has not been rounded during the last round */
    775 if( nroundings == heurdata->maxroundingloops )
    776 break;
    777 else
    778 continue;
    779 }
    780
    781 /* calculate the possible values after shifting */
    782 up = oldsolval + upperbound;
    783 down = oldsolval - lowerbound;
    784
    785 /* if the variable is integer or implied integral, do not shift further than the nearest integer */
    787 {
    788 SCIP_Real ceilx;
    789 SCIP_Real floorx;
    790
    791 ceilx = SCIPfeasCeil(scip, oldsolval);
    792 floorx = SCIPfeasFloor(scip, oldsolval);
    793 up = MIN(up, ceilx);
    794 down = MAX(down, floorx);
    795 }
    796
    797 /* calculate necessary values */
    798 ziup = getZiValue(scip, up);
    799 zidown = getZiValue(scip, down);
    800 zicurrent = getZiValue(scip, oldsolval);
    801
    802 /* calculate the shifting direction that reduces ZI-value the most,
    803 * if both directions improve ZI-value equally, take the direction which improves the objective
    804 */
    805 if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) )
    806 {
    807 if( SCIPisFeasEQ(scip,ziup, zidown) )
    808 direction = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP;
    809 else if( SCIPisFeasLT(scip, zidown, ziup) )
    810 direction = DIRECTION_DOWN;
    811 else
    812 direction = DIRECTION_UP;
    813
    814 /* once a possible shifting direction and value have been found, variable value is updated */
    815 shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval);
    816
    817 /* this improves numerical stability in some cases */
    818 if( direction == DIRECTION_UP )
    819 shiftval = MIN(shiftval, upperbound);
    820 else
    821 shiftval = MIN(shiftval, lowerbound);
    822 /* update the solution */
    823 solarray[c] = direction == DIRECTION_UP ? up : down;
    824 SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) );
    825
    826 /* update the rows activities and slacks */
    827 SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks,
    828 downslacks, activities, slackvars, slackvarcoeffs, nslacks) );
    829
    830 SCIPdebugMsg(scip, "zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n",
    831 SCIPvarGetIndex(var), oldsolval, shiftval);
    832 /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement
    833 * might affect many LP rows and their current slacks and thus make further rounding steps possible */
    834 improvementfound = TRUE;
    835 }
    836
    837 /* if solution value of variable has become feasibly integral due to rounding step,
    838 * variable is put at the end of remaining candidates array so as not to be considered in future loops
    839 */
    840 if( SCIPisFeasIntegral(scip, solarray[c]) )
    841 {
    842 zilpcands[c] = zilpcands[currentlpcands - 1];
    843 solarray[c] = solarray[currentlpcands - 1];
    844 currentlpcands--;
    845
    846 /* counter is decreased if end of candidates array has not been reached yet */
    847 if( c < currentlpcands )
    848 c--;
    849 }
    850 else if( nroundings == heurdata->maxroundingloops )
    851 goto TERMINATE;
    852 }
    853 }
    854
    855 /* in case that no candidate is left for rounding after the final main loop
    856 * the found solution has to be checked for feasibility in the original problem
    857 */
    858 if( currentlpcands == 0 )
    859 {
    860 SCIP_Bool stored;
    861 SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, FALSE, &stored) );
    862 if( stored )
    863 {
    864#ifdef SCIP_DEBUG
    865 SCIPdebugMsg(scip, "found feasible rounded solution:\n");
    867#endif
    868 SCIPstatisticMessage(" ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol));
    869
    870 *result = SCIP_FOUNDSOL;
    871 }
    872 }
    873
    874 /* free memory for all locally allocated data */
    875 TERMINATE:
    876 SCIPfreeBufferArrayNull(scip, &activities);
    877 SCIPfreeBufferArrayNull(scip, &rowneedsslackvar);
    878 SCIPfreeBufferArrayNull(scip, &slackvarcoeffs);
    879 SCIPfreeBufferArrayNull(scip, &downslacks);
    880 SCIPfreeBufferArrayNull(scip, &upslacks);
    881 SCIPfreeBufferArrayNull(scip, &slackvars);
    882 SCIPfreeBufferArrayNull(scip, &zilpcands);
    883 SCIPfreeBufferArrayNull(scip, &solarray);
    884
    885 return SCIP_OKAY;
    886}
    887
    888/*
    889 * primal heuristic specific interface methods
    890 */
    891
    892/** creates the zirounding primal heuristic and includes it in SCIP */
    894 SCIP* scip /**< SCIP data structure */
    895 )
    896{
    897 SCIP_HEURDATA* heurdata;
    898 SCIP_HEUR* heur;
    899
    900 /* create zirounding primal heuristic data */
    901 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    902
    903 /* include primal heuristic */
    906 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecZirounding, heurdata) );
    907
    908 assert(heur != NULL);
    909
    910 /* primal heuristic is safe to use in exact solving mode */
    911 SCIPheurMarkExact(heur);
    912
    913 /* set non-NULL pointers to callback methods */
    914 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyZirounding) );
    915 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeZirounding) );
    916 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitZirounding) );
    917 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitZirounding) );
    918 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolZirounding) );
    919
    920 /* add zirounding primal heuristic parameters */
    921 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/zirounding/maxroundingloops",
    922 "determines maximum number of rounding loops",
    923 &heurdata->maxroundingloops, TRUE, DEFAULT_MAXROUNDINGLOOPS, -1, INT_MAX, NULL, NULL) );
    924 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/zirounding/stopziround",
    925 "flag to determine if Zirounding is deactivated after a certain percentage of unsuccessful calls",
    926 &heurdata->stopziround, TRUE, DEFAULT_STOPZIROUND, NULL, NULL) );
    927 SCIP_CALL( SCIPaddRealParam(scip,"heuristics/zirounding/stoppercentage",
    928 "if percentage of found solutions falls below this parameter, Zirounding will be deactivated",
    929 &heurdata->stoppercentage, TRUE, DEFAULT_STOPPERCENTAGE, 0.0, 1.0, NULL, NULL) );
    930 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/zirounding/minstopncalls",
    931 "determines the minimum number of calls before percentage-based deactivation of Zirounding is applied",
    932 &heurdata->minstopncalls, TRUE, DEFAULT_MINSTOPNCALLS, 1, INT_MAX, NULL, NULL) );
    933
    934 return SCIP_OKAY;
    935}
    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 MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_CALL(x)
    Definition: def.h:355
    #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 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 SCIPincludeHeurZirounding(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
    int SCIPcolGetLPPos(SCIP_COL *col)
    Definition: lp.c:17487
    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 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 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_ROW ** SCIPgetLPRows(SCIP *scip)
    Definition: scip_lp.c:611
    int SCIPgetNLPRows(SCIP *scip)
    Definition: scip_lp.c:632
    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 SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
    Definition: lp.c:17686
    int SCIProwGetNNonz(SCIP_ROW *row)
    Definition: lp.c:17607
    SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
    Definition: lp.c:17632
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    int SCIProwGetLPPos(SCIP_ROW *row)
    Definition: lp.c:17895
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:2068
    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_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    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 SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23683
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23386
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23652
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    Direction
    Definition: heur_twoopt.c:138
    enum Direction DIRECTION
    Definition: heur_twoopt.c:143
    @ DIRECTION_DOWN
    @ DIRECTION_UP
    static void calculateBounds(SCIP *scip, SCIP_VAR *var, SCIP_Real currentvalue, SCIP_Real *upperbound, SCIP_Real *lowerbound, SCIP_Real *upslacks, SCIP_Real *downslacks, int nslacks, SCIP_Bool *numericalerror)
    #define DEFAULT_MAXROUNDINGLOOPS
    static SCIP_RETCODE updateSlacks(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real shiftvalue, SCIP_Real *upslacks, SCIP_Real *downslacks, SCIP_Real *activities, SCIP_VAR **slackvars, SCIP_Real *slackcoeffs, int nslacks)
    static SCIP_DECL_HEURCOPY(heurCopyZirounding)
    #define HEUR_TIMING
    #define HEUR_FREQOFS
    static void rowFindSlackVar(SCIP *scip, SCIP_ROW *row, SCIP_VAR **varpointer, SCIP_Real *coeffpointer)
    #define HEUR_DESC
    enum Direction DIRECTION
    #define DEFAULT_STOPPERCENTAGE
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    static SCIP_DECL_HEURINITSOL(heurInitsolZirounding)
    #define HEUR_PRIORITY
    #define DEFAULT_STOPZIROUND
    static SCIP_DECL_HEUREXEC(heurExecZirounding)
    static SCIP_DECL_HEUREXIT(heurExitZirounding)
    #define DEFAULT_MINSTOPNCALLS
    #define HEUR_NAME
    #define MINSHIFT
    static SCIP_DECL_HEURINIT(heurInitZirounding)
    static SCIP_Real getZiValue(SCIP *scip, SCIP_Real val)
    #define HEUR_FREQ
    #define HEUR_USESSUBSCIP
    static SCIP_DECL_HEURFREE(heurFreeZirounding)
    ZI Round primal heuristic.
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for primal heuristics
    public methods for LP management
    public methods for message output
    #define SCIPstatisticMessage
    Definition: pub_message.h:123
    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
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_COLUMN
    Definition: type_var.h:53