Scippy

    SCIP

    Solving Constraint Integer Programs

    benderscut_int.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 benderscut_int.c
    26 * @ingroup OTHER_CFILES
    27 * @brief Generates a Laporte and Louveaux Benders' decomposition integer cut
    28 * @author Stephen J. Maher
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "scip/benderscut_int.h"
    34#include "scip/cons_linear.h"
    35#include "scip/pub_benderscut.h"
    36#include "scip/pub_benders.h"
    37#include "scip/pub_lp.h"
    38#include "scip/pub_message.h"
    39#include "scip/pub_misc.h"
    40#include "scip/pub_paramset.h"
    41#include "scip/pub_var.h"
    42#include "scip/scip_benders.h"
    43#include "scip/scip_cons.h"
    44#include "scip/scip_cut.h"
    45#include "scip/scip_general.h"
    46#include "scip/scip_lp.h"
    47#include "scip/scip_mem.h"
    48#include "scip/scip_message.h"
    49#include "scip/scip_numerics.h"
    50#include "scip/scip_param.h"
    51#include "scip/scip_prob.h"
    52#include "scip/scip_sol.h"
    53#include <string.h>
    54
    55#define BENDERSCUT_NAME "integer"
    56#define BENDERSCUT_DESC "Laporte and Louveaux Benders' decomposition integer cut"
    57#define BENDERSCUT_PRIORITY 0
    58#define BENDERSCUT_LPCUT FALSE
    59
    60#define SCIP_DEFAULT_ADDCUTS FALSE /** Should cuts be generated, instead of constraints */
    61#define SCIP_DEFAULT_CUTCONSTANT -10000.0
    62
    63/*
    64 * Data structures
    65 */
    66
    67/** Benders' decomposition cuts data */
    68struct SCIP_BenderscutData
    69{
    70 SCIP_BENDERS* benders; /**< the Benders' decomposition data structure */
    71 SCIP_Real cutconstant; /**< the constant for computing the integer cuts */
    72 SCIP_Real* subprobconstant; /**< the constant for each subproblem used for computing the integer cuts */
    73 SCIP_Bool addcuts; /**< should cuts be generated instead of constraints */
    74 SCIP_Bool* firstcut; /**< flag to indicate that the first cut needs to be generated. */
    75 int nsubproblems; /**< the number of subproblems for the Benders' decomposition */
    76 SCIP_Bool subprobsvalid; /**< is it valid to apply integer cuts for this problem */
    77 SCIP_Bool created; /**< has the Benders cut data been created */
    78};
    79
    80/** method to call, when the priority of a Benders' decomposition was changed */
    81static
    82SCIP_DECL_PARAMCHGD(paramChgdBenderscutintConstant)
    83{ /*lint --e{715}*/
    84 SCIP_BENDERSCUTDATA* benderscutdata;
    85 int i;
    86
    87 benderscutdata = (SCIP_BENDERSCUTDATA*)SCIPparamGetData(param);
    88 assert(benderscutdata != NULL);
    89
    90 for( i = 0; i < benderscutdata->nsubproblems; i++ )
    91 benderscutdata->subprobconstant[i] = benderscutdata->cutconstant;
    92
    93 return SCIP_OKAY;
    94}
    95
    96
    97/** creates the Benders' decomposition cut data */
    98static
    100 SCIP* scip, /**< the SCIP data structure */
    101 SCIP_BENDERSCUTDATA* benderscutdata /**< the Benders' cut data */
    102 )
    103{
    104 int nmastervars;
    105 int nmasterbinvars;
    106 int i;
    107
    108 assert(scip != NULL);
    109 assert(benderscutdata != NULL);
    110
    111 benderscutdata->nsubproblems = SCIPbendersGetNSubproblems(benderscutdata->benders);
    112 benderscutdata->subprobsvalid = TRUE;
    113
    114 /* allocating the memory for the subproblem constants */
    115 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &benderscutdata->subprobconstant, benderscutdata->nsubproblems) );
    116 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &benderscutdata->firstcut, benderscutdata->nsubproblems) );
    117
    118 for( i = 0; i < benderscutdata->nsubproblems; i++ )
    119 {
    120 benderscutdata->subprobconstant[i] = benderscutdata->cutconstant;
    121 benderscutdata->firstcut[i] = TRUE;
    122
    123 /* it is only possible to generate the no-good cut for subproblems that only include binary master variables */
    124 SCIPbendersGetSubproblemMasterVarsData(benderscutdata->benders, i, NULL, &nmastervars, &nmasterbinvars, NULL);
    125
    126 if( nmastervars != nmasterbinvars )
    127 {
    128 benderscutdata->subprobsvalid = FALSE;
    129 }
    130 }
    131
    132 benderscutdata->created = TRUE;
    133
    134 return SCIP_OKAY;
    135}
    136
    137/*
    138 * Local methods
    139 */
    140
    141/** updates the cut constant for the given subproblem based upon the global bounds of the associated auxiliary variable */
    142static
    144 SCIP* masterprob, /**< the SCIP instance of the master problem */
    145 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    146 SCIP_BENDERSCUTDATA* benderscutdata, /**< the Benders' decomposition cut data */
    147 int probnumber /**< the index for the subproblem */
    148 )
    149{
    150 SCIP_VAR* auxiliaryvar;
    151
    152 assert(masterprob != NULL);
    153 assert(benders != NULL);
    154 assert(benderscutdata != NULL);
    155
    156 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    157
    158 /* checking if the subproblem lower bound has been updated. If it is has changed, then firstcut is set to TRUE.
    159 * Otherwise, the constant remains the same.
    160 */
    161 if( SCIPisGT(masterprob, SCIPbendersGetSubproblemLowerbound(benders, probnumber),
    162 benderscutdata->subprobconstant[probnumber]) )
    163 {
    164 benderscutdata->subprobconstant[probnumber] = SCIPbendersGetSubproblemLowerbound(benders, probnumber);
    165 benderscutdata->firstcut[probnumber] = TRUE;
    166 }
    167
    168 /* updating the cut constant if the auxiliary variable global lower bound is greater than the current constant */
    169 if( SCIPisGT(masterprob, SCIPvarGetLbGlobal(auxiliaryvar), benderscutdata->subprobconstant[probnumber]) )
    170 benderscutdata->subprobconstant[probnumber] = SCIPvarGetLbGlobal(auxiliaryvar);
    171}
    172
    173/** computes a standard Benders' optimality cut from the dual solutions of the LP */
    174static
    176 SCIP* masterprob, /**< the SCIP instance of the master problem */
    177 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    178 SCIP_SOL* sol, /**< primal CIP solution */
    179 SCIP_CONS* cons, /**< the constraint for the generated cut, can be NULL */
    180 SCIP_ROW* row, /**< the row for the generated cut, can be NULL */
    181 SCIP_Real cutconstant, /**< the constant value in the integer optimality cut */
    182 int probnumber, /**< the number of the pricing problem */
    183 SCIP_Bool addcut, /**< indicates whether a cut is created instead of a constraint */
    184 SCIP_Bool* success /**< was the cut generation successful? */
    185 )
    186{
    187 SCIP_VAR** vars;
    188 int nvars;
    189 SCIP_Real subprobobj; /* the objective function value of the subproblem */
    190 SCIP_Real lhs; /* the left hand side of the cut */
    191 int i;
    192 SCIPdebug( SCIP* subproblem; )
    193
    194#ifndef NDEBUG
    195 SCIP_Real verifyobj = 0;
    196#endif
    197
    198 assert(masterprob != NULL);
    199 assert(benders != NULL);
    200 assert(cons != NULL || addcut);
    201 assert(row != NULL || !addcut);
    202
    203 (*success) = FALSE;
    204
    205 /* getting the best solution from the subproblem */
    206
    207 subprobobj = SCIPbendersGetSubproblemObjval(benders, probnumber);
    208
    209 SCIPdebug( subproblem = SCIPbendersSubproblem(benders, probnumber); )
    210 SCIPdebug( SCIPdebugMsg(masterprob, "Subproblem %d - Objective Value: Stored - %g Orig Obj - %g Cut constant - %g\n",
    211 probnumber, SCIPbendersGetSubproblemObjval(benders, probnumber), SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem),
    212 cutconstant); )
    213
    214 nvars = SCIPgetNVars(masterprob);
    215 vars = SCIPgetVars(masterprob);
    216
    217 /* adding the subproblem objective function value to the lhs */
    218 if( addcut )
    219 lhs = SCIProwGetLhs(row);
    220 else
    221 lhs = SCIPgetLhsLinear(masterprob, cons);
    222
    223 /* looping over all master problem variables to update the coefficients in the computed cut. */
    224 for( i = 0; i < nvars; i++ )
    225 {
    226 SCIP_VAR* subprobvar;
    227 SCIP_Real coef;
    228
    229 SCIP_CALL( SCIPgetBendersSubproblemVar(masterprob, benders, vars[i], &subprobvar, probnumber) );
    230
    231 /* if there is a corresponding subproblem variable, then the variable will not be NULL. */
    232 if( subprobvar != NULL )
    233 {
    234 /* if the variable is on its upper bound, then the subproblem objective value is added to the cut */
    235 if( SCIPisFeasEQ(masterprob, SCIPgetSolVal(masterprob, sol, vars[i]), 1.0) )
    236 {
    237 coef = -(subprobobj - cutconstant);
    238 lhs -= (subprobobj - cutconstant);
    239 }
    240 else
    241 coef = (subprobobj - cutconstant);
    242
    243 /* adding the variable to the cut. The coefficient is the subproblem objective value */
    244 if( addcut )
    245 {
    246 SCIP_CALL( SCIPaddVarToRow(masterprob, row, vars[i], coef) );
    247 }
    248 else
    249 {
    250 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, vars[i], coef) );
    251 }
    252 }
    253 }
    254
    255 lhs += subprobobj;
    256
    257 /* if the bound becomes infinite, then the cut generation terminates. */
    258 if( SCIPisInfinity(masterprob, lhs) || SCIPisInfinity(masterprob, -lhs) )
    259 {
    260 (*success) = FALSE;
    261 SCIPdebugMsg(masterprob, "Infinite bound when generating integer optimality cut.\n");
    262 return SCIP_OKAY;
    263 }
    264
    265 /* Update the lhs of the cut */
    266 if( addcut )
    267 {
    268 SCIP_CALL( SCIPchgRowLhs(masterprob, row, lhs) );
    269 }
    270 else
    271 {
    272 SCIP_CALL( SCIPchgLhsLinear(masterprob, cons, lhs) );
    273 }
    274
    275#ifndef NDEBUG
    276 if( addcut )
    277 lhs = SCIProwGetLhs(row);
    278 else
    279 lhs = SCIPgetLhsLinear(masterprob, cons);
    280 verifyobj += lhs;
    281
    282 if( addcut )
    283 verifyobj -= SCIPgetRowSolActivity(masterprob, row, sol);
    284 else
    285 verifyobj -= SCIPgetActivityLinear(masterprob, cons, sol);
    286#endif
    287
    288 assert(SCIPisFeasEQ(masterprob, verifyobj, subprobobj));
    289
    290 (*success) = TRUE;
    291
    292 return SCIP_OKAY;
    293}
    294
    295
    296/** adds the auxiliary variable to the generated cut. If this is the first optimality cut for the subproblem, then the
    297 * auxiliary variable is first created and added to the master problem.
    298 */
    299static
    301 SCIP* masterprob, /**< the SCIP instance of the master problem */
    302 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    303 SCIP_CONS* cons, /**< the constraint for the generated cut, can be NULL */
    304 SCIP_ROW* row, /**< the row for the generated cut, can be NULL */
    305 int probnumber, /**< the number of the pricing problem */
    306 SCIP_Bool addcut /**< indicates whether a cut is created instead of a constraint */
    307 )
    308{
    309 SCIP_VAR* auxiliaryvar;
    310
    311 assert(masterprob != NULL);
    312 assert(benders != NULL);
    313 assert(cons != NULL || addcut);
    314 assert(row != NULL || !addcut);
    315
    316 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    317
    318 /* adding the auxiliary variable to the generated cut */
    319 if( addcut )
    320 {
    321 SCIP_CALL( SCIPaddVarToRow(masterprob, row, auxiliaryvar, 1.0) );
    322 }
    323 else
    324 {
    325 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, auxiliaryvar, 1.0) );
    326 }
    327
    328 return SCIP_OKAY;
    329}
    330
    331
    332/** generates and applies Benders' cuts */
    333static
    335 SCIP* masterprob, /**< the SCIP instance of the master problem */
    336 SCIP_BENDERS* benders, /**< the benders' decomposition */
    337 SCIP_BENDERSCUT* benderscut, /**< the benders' decomposition cut method */
    338 SCIP_SOL* sol, /**< primal CIP solution */
    339 int probnumber, /**< the number of the pricing problem */
    340 SCIP_BENDERSENFOTYPE type, /**< the enforcement type calling this function */
    341 SCIP_RESULT* result, /**< the result from solving the subproblems */
    342 SCIP_Bool initcons /**< is this function called to generate the initial constraint */
    343 )
    344{
    345 SCIP_BENDERSCUTDATA* benderscutdata;
    346 SCIP_CONSHDLR* consbenders;
    347 SCIP_CONS* cons;
    348 SCIP_ROW* row;
    349 char cutname[SCIP_MAXSTRLEN];
    350 SCIP_Bool optimal;
    351 SCIP_Bool addcut;
    352 SCIP_Bool success;
    353
    354 assert(masterprob != NULL);
    355 assert(benders != NULL);
    356 assert(benderscut != NULL);
    357 assert(result != NULL);
    358
    359 row = NULL;
    360 cons = NULL;
    361
    362 success = FALSE;
    363
    364 /* retrieving the Benders' cut data */
    365 benderscutdata = SCIPbenderscutGetData(benderscut);
    366
    367 /* if the cuts are generated prior to the solving stage, then rows can not be generated. So constraints must be added
    368 * to the master problem.
    369 */
    370 if( SCIPgetStage(masterprob) < SCIP_STAGE_INITSOLVE )
    371 addcut = FALSE;
    372 else
    373 addcut = benderscutdata->addcuts;
    374
    375 /* retrieving the Benders' decomposition constraint handler */
    376 consbenders = SCIPfindConshdlr(masterprob, "benders");
    377
    378 /* checking the optimality of the original problem with a comparison between the auxiliary variable and the
    379 * objective value of the subproblem
    380 */
    381 optimal = FALSE;
    382 SCIP_CALL( SCIPcheckBendersSubproblemOptimality(masterprob, benders, sol, probnumber, &optimal) );
    383
    384 if( optimal )
    385 {
    386 (*result) = SCIP_FEASIBLE;
    387 SCIPdebugMsg(masterprob, "No <%s> cut added. Current Master Problem Obj: %g\n", BENDERSCUT_NAME,
    388 SCIPgetSolOrigObj(masterprob, NULL)*(int)SCIPgetObjsense(masterprob));
    389 return SCIP_OKAY;
    390 }
    391
    392 /* checking whether the subproblem constant is less than the auxiliary variable global lower bound */
    393 updateSubproblemCutConstant(masterprob, benders, benderscutdata, probnumber);
    394
    395 /* if no integer cuts have been previously generated and the bound on the auxiliary variable is -infinity,
    396 * then an initial lower bounding cut is added
    397 */
    398 if( benderscutdata->firstcut[probnumber]
    399 && SCIPisInfinity(masterprob, -SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber))) )
    400 {
    401 benderscutdata->firstcut[probnumber] = FALSE;
    402 SCIP_CALL( generateAndApplyBendersIntegerCuts(masterprob, benders, benderscut, sol, probnumber, type, result,
    403 TRUE) );
    404 }
    405
    406 /* setting the name of the generated cut */
    407 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "integeroptcut_%d_%" SCIP_LONGINT_FORMAT, probnumber,
    408 SCIPbenderscutGetNFound(benderscut) );
    409
    410 /* creating an empty row or constraint for the Benders' cut */
    411 if( addcut )
    412 {
    413 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname, 0.0, SCIPinfinity(masterprob), FALSE,
    414 FALSE, TRUE) );
    415 }
    416 else
    417 {
    418 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, 0, NULL, NULL, 0.0, SCIPinfinity(masterprob)) );
    419 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
    420 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
    421 }
    422
    423 if( initcons )
    424 {
    425 SCIP_Real lhs;
    426
    427 /* adding the subproblem objective function value to the lhs */
    428 if( addcut )
    429 lhs = SCIProwGetLhs(row);
    430 else
    431 lhs = SCIPgetLhsLinear(masterprob, cons);
    432
    433 lhs += benderscutdata->subprobconstant[probnumber];
    434
    435 /* if the bound becomes infinite, then the cut generation terminates. */
    436 if( SCIPisInfinity(masterprob, lhs) || SCIPisInfinity(masterprob, -lhs) )
    437 {
    438 success = FALSE;
    439 SCIPdebugMsg(masterprob, "Infinite bound when generating integer optimality cut.\n");
    440 }
    441
    442 /* Update the lhs of the cut */
    443 if( addcut )
    444 {
    445 SCIP_CALL( SCIPchgRowLhs(masterprob, row, lhs) );
    446 }
    447 else
    448 {
    449 SCIP_CALL( SCIPchgLhsLinear(masterprob, cons, lhs) );
    450 }
    451 }
    452 else
    453 {
    454 /* computing the coefficients of the optimality cut */
    455 SCIP_CALL( computeStandardIntegerOptCut(masterprob, benders, sol, cons, row,
    456 benderscutdata->subprobconstant[probnumber], probnumber, addcut, &success) );
    457 }
    458
    459 /* if success is FALSE, then there was an error in generating the integer optimality cut. No cut will be added to
    460 * the master problem. Otherwise, the constraint is added to the master problem.
    461 */
    462 if( !success )
    463 {
    464 (*result) = SCIP_DIDNOTFIND;
    465 SCIPdebugMsg(masterprob, "Error in generating Benders' integer optimality cut for problem %d.\n", probnumber);
    466 }
    467 else
    468 {
    469 /* adding the auxiliary variable to the optimality cut */
    470 SCIP_CALL( addAuxiliaryVariableToCut(masterprob, benders, cons, row, probnumber, addcut) );
    471
    472 /* adding the constraint to the master problem */
    473 if( addcut )
    474 {
    475 SCIP_Bool infeasible;
    476
    478 {
    479 SCIP_CALL( SCIPaddRow(masterprob, row, FALSE, &infeasible) );
    480 assert(!infeasible);
    481 }
    482 else
    483 {
    485 SCIP_CALL( SCIPaddPoolCut(masterprob, row) );
    486 }
    487
    488#ifdef SCIP_DEBUG
    489 SCIP_CALL( SCIPprintRow(masterprob, row, NULL) );
    490 SCIPinfoMessage(masterprob, NULL, ";\n");
    491#endif
    492
    493 (*result) = SCIP_SEPARATED;
    494 }
    495 else
    496 {
    497 SCIP_CALL( SCIPaddCons(masterprob, cons) );
    498
    499 SCIPdebugPrintCons(masterprob, cons, NULL);
    500
    501 (*result) = SCIP_CONSADDED;
    502 }
    503 }
    504
    505 if( addcut )
    506 {
    507 /* release the row */
    508 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
    509 }
    510 else
    511 {
    512 /* release the constraint */
    513 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
    514 }
    515
    516 return SCIP_OKAY;
    517}
    518
    519/*
    520 * Callback methods of Benders' decomposition cuts
    521 */
    522
    523/** destructor of Benders' decomposition cuts to free user data (called when SCIP is exiting) */
    524static
    525SCIP_DECL_BENDERSCUTFREE(benderscutFreeInt)
    526{ /*lint --e{715}*/
    527 SCIP_BENDERSCUTDATA* benderscutdata;
    528
    529 assert( benderscut != NULL );
    530 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
    531
    532 /* free Benders' cut data */
    533 benderscutdata = SCIPbenderscutGetData(benderscut);
    534 assert( benderscutdata != NULL );
    535
    536 SCIPfreeBlockMemory(scip, &benderscutdata);
    537
    538 SCIPbenderscutSetData(benderscut, NULL);
    539
    540 return SCIP_OKAY;
    541}
    542
    543
    544/** deinitialization method of Benders' decomposition cuts (called before transformed problem is freed) */
    545static
    546SCIP_DECL_BENDERSCUTEXIT(benderscutExitInt)
    547{ /*lint --e{715}*/
    548 SCIP_BENDERSCUTDATA* benderscutdata;
    549
    550 assert( benderscut != NULL );
    551 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
    552
    553 /* free Benders' cut data */
    554 benderscutdata = SCIPbenderscutGetData(benderscut);
    555 assert( benderscutdata != NULL );
    556
    557 if( benderscutdata->firstcut != NULL )
    558 SCIPfreeBlockMemoryArray(scip, &benderscutdata->firstcut, benderscutdata->nsubproblems);
    559
    560 if( benderscutdata->subprobconstant != NULL)
    561 SCIPfreeBlockMemoryArray(scip, &benderscutdata->subprobconstant, benderscutdata->nsubproblems);
    562
    563 return SCIP_OKAY;
    564}
    565
    566/** execution method of Benders' decomposition cuts */
    567static
    568SCIP_DECL_BENDERSCUTEXEC(benderscutExecInt)
    569{ /*lint --e{715}*/
    570 SCIP* subproblem;
    571 SCIP_BENDERSCUTDATA* benderscutdata;
    572
    573 assert(scip != NULL);
    574 assert(benders != NULL);
    575 assert(benderscut != NULL);
    576 assert(result != NULL);
    577
    578 subproblem = SCIPbendersSubproblem(benders, probnumber);
    579
    580 if( subproblem == NULL )
    581 {
    582 SCIPdebugMsg(scip, "The subproblem %d is set to NULL. The <%s> Benders' decomposition cut can not be executed.\n",
    583 probnumber, BENDERSCUT_NAME);
    584
    585 (*result) = SCIP_DIDNOTRUN;
    586 return SCIP_OKAY;
    587 }
    588
    589 /* retrieving the Benders' cut data */
    590 benderscutdata = SCIPbenderscutGetData(benderscut);
    591 assert(benderscutdata != NULL);
    592
    593 /* if the Benders' cut data has not been created, then it is created now */
    594 if( !benderscutdata->created )
    595 {
    596 SCIP_CALL( createBenderscutData(scip, benderscutdata) );
    597 }
    598
    599 /* it is only possible to generate the Laporte and Louveaux cuts when the linking variables are all binary */
    600 if( !benderscutdata->subprobsvalid )
    601 {
    602 SCIPinfoMessage(scip, NULL, "The integer optimality cuts can only be applied to problems "
    603 "where all linking variables are binary. The integer optimality cuts will be disabled.\n");
    604
    605 SCIPbenderscutSetEnabled(benderscut, FALSE);
    606
    607 return SCIP_OKAY;
    608 }
    609
    610 /* the integer subproblem could terminate early if the auxiliary variable value is much greater than the optimal
    611 * solution. As such, it is only necessary to generate a cut if the subproblem is OPTIMAL */
    612 if( SCIPgetStatus(subproblem) == SCIP_STATUS_OPTIMAL )
    613 {
    614 /* generating a cut for a given subproblem */
    615 SCIP_CALL( generateAndApplyBendersIntegerCuts(scip, benders, benderscut, sol, probnumber, type, result, FALSE) );
    616 }
    617
    618 return SCIP_OKAY;
    619}
    620
    621
    622/*
    623 * Benders' decomposition cuts specific interface methods
    624 */
    625
    626/** creates the int Benders' decomposition cuts and includes it in SCIP */
    628 SCIP* scip, /**< SCIP data structure */
    629 SCIP_BENDERS* benders /**< Benders' decomposition */
    630 )
    631{
    632 SCIP_BENDERSCUTDATA* benderscutdata;
    633 SCIP_BENDERSCUT* benderscut;
    635
    636 assert(benders != NULL);
    637
    638 /* create int Benders' decomposition cuts data */
    639 SCIP_CALL( SCIPallocBlockMemory(scip, &benderscutdata) );
    640 BMSclearMemory(benderscutdata);
    641 benderscutdata->benders = benders;
    642
    643 benderscut = NULL;
    644
    645 /* include Benders' decomposition cuts */
    647 BENDERSCUT_PRIORITY, BENDERSCUT_LPCUT, benderscutExecInt, benderscutdata) );
    648
    649 assert(benderscut != NULL);
    650
    651 /* set non fundamental callbacks via setter functions */
    652 SCIP_CALL( SCIPsetBenderscutFree(scip, benderscut, benderscutFreeInt) );
    653 SCIP_CALL( SCIPsetBenderscutExit(scip, benderscut, benderscutExitInt) );
    654
    655 /* add int Benders' decomposition cuts parameters */
    656 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/cutsconstant",
    659 "the constant term of the integer Benders' cuts.",
    660 &benderscutdata->cutconstant, FALSE, SCIP_DEFAULT_CUTCONSTANT, -SCIPinfinity(scip), SCIPinfinity(scip),
    661 paramChgdBenderscutintConstant, (SCIP_PARAMDATA*)benderscutdata) );
    662
    663 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/addcuts",
    666 "should cuts be generated and added to the cutpool instead of global constraints directly added to the problem.",
    667 &benderscutdata->addcuts, FALSE, SCIP_DEFAULT_ADDCUTS, NULL, NULL) );
    668
    669 return SCIP_OKAY;
    670}
    #define SCIP_DEFAULT_ADDCUTS
    #define BENDERSCUT_LPCUT
    static SCIP_DECL_BENDERSCUTFREE(benderscutFreeInt)
    static SCIP_RETCODE computeStandardIntegerOptCut(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_SOL *sol, SCIP_CONS *cons, SCIP_ROW *row, SCIP_Real cutconstant, int probnumber, SCIP_Bool addcut, SCIP_Bool *success)
    static SCIP_DECL_BENDERSCUTEXEC(benderscutExecInt)
    #define BENDERSCUT_PRIORITY
    #define BENDERSCUT_DESC
    #define BENDERSCUT_NAME
    static SCIP_DECL_BENDERSCUTEXIT(benderscutExitInt)
    #define SCIP_DEFAULT_CUTCONSTANT
    static SCIP_RETCODE createBenderscutData(SCIP *scip, SCIP_BENDERSCUTDATA *benderscutdata)
    static SCIP_RETCODE generateAndApplyBendersIntegerCuts(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type, SCIP_RESULT *result, SCIP_Bool initcons)
    static void updateSubproblemCutConstant(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_BENDERSCUTDATA *benderscutdata, int probnumber)
    static SCIP_DECL_PARAMCHGD(paramChgdBenderscutintConstant)
    static SCIP_RETCODE addAuxiliaryVariableToCut(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_CONS *cons, SCIP_ROW *row, int probnumber, SCIP_Bool addcut)
    Generates a Laporte and Louveaux Benders' decomposition integer cut.
    Constraint handler for linear constraints in their most general form, .
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #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_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPincludeBenderscutInt(SCIP *scip, SCIP_BENDERS *benders)
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_Real SCIPgetActivityLinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
    SCIP_RETCODE SCIPchgLhsLinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
    Definition: scip_prob.c:1400
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    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_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6213
    SCIP_RETCODE SCIPgetBendersSubproblemVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
    Definition: scip_benders.c:721
    const char * SCIPbendersGetName(SCIP_BENDERS *benders)
    Definition: benders.c:5967
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6011
    SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6021
    void SCIPbendersGetSubproblemMasterVarsData(SCIP_BENDERS *benders, int probnumber, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars)
    Definition: benders.c:6259
    SCIP_RETCODE SCIPcheckBendersSubproblemOptimality(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_Bool *optimal)
    Definition: scip_benders.c:917
    SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6302
    SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6893
    SCIP_RETCODE SCIPincludeBenderscutBasic(SCIP *scip, SCIP_BENDERS *benders, SCIP_BENDERSCUT **benderscutptr, const char *name, const char *desc, int priority, SCIP_Bool islpcut, SCIP_DECL_BENDERSCUTEXEC((*benderscutexec)), SCIP_BENDERSCUTDATA *benderscutdata)
    SCIP_RETCODE SCIPsetBenderscutExit(SCIP *scip, SCIP_BENDERSCUT *benderscut, SCIP_DECL_BENDERSCUTEXIT((*benderscutexit)))
    SCIP_RETCODE SCIPsetBenderscutFree(SCIP *scip, SCIP_BENDERSCUT *benderscut, SCIP_DECL_BENDERSCUTFREE((*benderscutfree)))
    void SCIPbenderscutSetData(SCIP_BENDERSCUT *benderscut, SCIP_BENDERSCUTDATA *benderscutdata)
    Definition: benderscut.c:413
    const char * SCIPbenderscutGetName(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:492
    SCIP_BENDERSCUTDATA * SCIPbenderscutGetData(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:403
    SCIP_Longint SCIPbenderscutGetNFound(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:543
    void SCIPbenderscutSetEnabled(SCIP_BENDERSCUT *benderscut, SCIP_Bool enabled)
    Definition: benderscut.c:593
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
    Definition: scip_cons.c:1449
    SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
    Definition: scip_cons.c:1474
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #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_RETCODE SCIPchgRowLhs(SCIP *scip, SCIP_ROW *row, SCIP_Real lhs)
    Definition: scip_lp.c:1529
    SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1367
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
    Definition: scip_lp.c:2108
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1892
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    static const char * paramname[]
    Definition: lpi_msk.c:5172
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    SCIP_PARAMDATA * SCIPparamGetData(SCIP_PARAM *param)
    Definition: paramset.c:678
    public methods for Benders' decomposition
    public methods for Benders' decomposition cuts
    public methods for LP management
    public methods for message output
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    #define SCIPdebugPrintCons(x, y, z)
    Definition: pub_message.h:102
    public data structures and miscellaneous methods
    public methods for handling parameter settings
    public methods for problem variables
    public methods for Benders decomposition
    public methods for constraint handler plugins and constraints
    public methods for cuts and aggregation rows
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for solutions
    @ SCIP_BENDERSENFOTYPE_RELAX
    Definition: type_benders.h:52
    @ SCIP_BENDERSENFOTYPE_LP
    Definition: type_benders.h:51
    @ SCIP_BENDERSENFOTYPE_CHECK
    Definition: type_benders.h:54
    @ SCIP_BENDERSENFOTYPE_PSEUDO
    Definition: type_benders.h:53
    enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
    Definition: type_benders.h:56
    struct SCIP_BenderscutData SCIP_BENDERSCUTDATA
    struct SCIP_ParamData SCIP_PARAMDATA
    Definition: type_paramset.h:87
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_FEASIBLE
    Definition: type_result.h:45
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_CONSADDED
    Definition: type_result.h:52
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52
    @ SCIP_STATUS_OPTIMAL
    Definition: type_stat.h:43