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-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file 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 "scip/type_message.h"
    54#include <string.h>
    55
    56#define BENDERSCUT_NAME "integer"
    57#define BENDERSCUT_DESC "Laporte and Louveaux Benders' decomposition integer cut"
    58#define BENDERSCUT_PRIORITY 0
    59#define BENDERSCUT_LPCUT FALSE
    60
    61#define SCIP_DEFAULT_ADDCUTS FALSE /** Should cuts be generated, instead of constraints */
    62#define SCIP_DEFAULT_CUTCONSTANT -10000.0
    63
    64/*
    65 * Data structures
    66 */
    67
    68/** Benders' decomposition cuts data */
    69struct SCIP_BenderscutData
    70{
    71 SCIP_BENDERS* benders; /**< the Benders' decomposition data structure */
    72 SCIP_Real cutconstant; /**< the constant for computing the integer cuts */
    73 SCIP_Real* subprobconstant; /**< the constant for each subproblem used for computing the integer cuts */
    74 SCIP_Bool addcuts; /**< should cuts be generated instead of constraints */
    75 SCIP_Bool* firstcut; /**< flag to indicate that the first cut needs to be generated. */
    76 int nsubproblems; /**< the number of subproblems for the Benders' decomposition */
    77 SCIP_Bool subprobsvalid; /**< is it valid to apply integer cuts for this problem */
    78 SCIP_Bool created; /**< has the Benders cut data been created */
    79};
    80
    81/** method to call, when the priority of a Benders' decomposition was changed */
    82static
    83SCIP_DECL_PARAMCHGD(paramChgdBenderscutintConstant)
    84{ /*lint --e{715}*/
    85 SCIP_BENDERSCUTDATA* benderscutdata;
    86 int i;
    87
    88 benderscutdata = (SCIP_BENDERSCUTDATA*)SCIPparamGetData(param);
    89 assert(benderscutdata != NULL);
    90
    91 for( i = 0; i < benderscutdata->nsubproblems; i++ )
    92 benderscutdata->subprobconstant[i] = benderscutdata->cutconstant;
    93
    94 return SCIP_OKAY;
    95}
    96
    97
    98/** creates the Benders' decomposition cut data */
    99static
    101 SCIP* scip, /**< the SCIP data structure */
    102 SCIP_BENDERSCUTDATA* benderscutdata /**< the Benders' cut data */
    103 )
    104{
    105 int nmastervars;
    106 int nmasterbinvars;
    107 int i;
    108
    109 assert(scip != NULL);
    110 assert(benderscutdata != NULL);
    111
    112 benderscutdata->nsubproblems = SCIPbendersGetNSubproblems(benderscutdata->benders);
    113 benderscutdata->subprobsvalid = TRUE;
    114
    115 /* allocating the memory for the subproblem constants */
    116 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &benderscutdata->subprobconstant, benderscutdata->nsubproblems) );
    117 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &benderscutdata->firstcut, benderscutdata->nsubproblems) );
    118
    119 for( i = 0; i < benderscutdata->nsubproblems; i++ )
    120 {
    121 benderscutdata->subprobconstant[i] = benderscutdata->cutconstant;
    122 benderscutdata->firstcut[i] = TRUE;
    123
    124 /* it is only possible to generate the no-good cut for subproblems that only include binary master variables */
    125 SCIPbendersGetSubproblemMasterVarsData(benderscutdata->benders, i, NULL, &nmastervars, &nmasterbinvars, NULL);
    126
    127 if( nmastervars != nmasterbinvars )
    128 {
    129 benderscutdata->subprobsvalid = FALSE;
    130 }
    131 }
    132
    133 benderscutdata->created = TRUE;
    134
    135 return SCIP_OKAY;
    136}
    137
    138/*
    139 * Local methods
    140 */
    141
    142/** updates the cut constant for the given subproblem based upon the global bounds of the associated auxiliary variable */
    143static
    145 SCIP* masterprob, /**< the SCIP instance of the master problem */
    146 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    147 SCIP_BENDERSCUTDATA* benderscutdata, /**< the Benders' decomposition cut data */
    148 int probnumber /**< the index for the subproblem */
    149 )
    150{
    151 SCIP_VAR* auxiliaryvar;
    152
    153 assert(masterprob != NULL);
    154 assert(benders != NULL);
    155 assert(benderscutdata != NULL);
    156
    157 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    158
    159 /* checking if the subproblem lower bound has been updated. If it is has changed, then firstcut is set to TRUE.
    160 * Otherwise, the constant remains the same.
    161 */
    162 if( SCIPisGT(masterprob, SCIPbendersGetSubproblemLowerbound(benders, probnumber),
    163 benderscutdata->subprobconstant[probnumber]) )
    164 {
    165 benderscutdata->subprobconstant[probnumber] = SCIPbendersGetSubproblemLowerbound(benders, probnumber);
    166 benderscutdata->firstcut[probnumber] = TRUE;
    167 }
    168
    169 /* updating the cut constant if the auxiliary variable global lower bound is greater than the current constant */
    170 if( SCIPisGT(masterprob, SCIPvarGetLbGlobal(auxiliaryvar), benderscutdata->subprobconstant[probnumber]) )
    171 benderscutdata->subprobconstant[probnumber] = SCIPvarGetLbGlobal(auxiliaryvar);
    172}
    173
    174/** computes a standard Benders' optimality cut from the dual solutions of the LP */
    175static
    177 SCIP* masterprob, /**< the SCIP instance of the master problem */
    178 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    179 SCIP_SOL* sol, /**< primal CIP solution */
    180 SCIP_CONS* cons, /**< the constraint for the generated cut, can be NULL */
    181 SCIP_ROW* row, /**< the row for the generated cut, can be NULL */
    182 SCIP_Real cutconstant, /**< the constant value in the integer optimality cut */
    183 int probnumber, /**< the number of the pricing problem */
    184 SCIP_Bool addcut, /**< indicates whether a cut is created instead of a constraint */
    185 SCIP_Bool* success /**< was the cut generation successful? */
    186 )
    187{
    188 SCIP_VAR** vars;
    189 int nvars;
    190 SCIP_Real subprobobj; /* the objective function value of the subproblem */
    191 SCIP_Real lhs; /* the left hand side of the cut */
    192 int i;
    193 SCIPdebug( SCIP* subproblem; )
    194
    195#ifndef NDEBUG
    196 SCIP_Real verifyobj = 0;
    197#endif
    198
    199 assert(masterprob != NULL);
    200 assert(benders != NULL);
    201 assert(cons != NULL || addcut);
    202 assert(row != NULL || !addcut);
    203
    204 (*success) = FALSE;
    205
    206 /* getting the best solution from the subproblem */
    207
    208 subprobobj = SCIPbendersGetSubproblemObjval(benders, probnumber);
    209
    210 SCIPdebug( subproblem = SCIPbendersSubproblem(benders, probnumber); )
    211 SCIPdebug( SCIPdebugMsg(masterprob, "Subproblem %d - Objective Value: Stored - %g Orig Obj - %g Cut constant - %g\n",
    212 probnumber, SCIPbendersGetSubproblemObjval(benders, probnumber), SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem),
    213 cutconstant); )
    214
    215 nvars = SCIPgetNVars(masterprob);
    216 vars = SCIPgetVars(masterprob);
    217
    218 /* adding the subproblem objective function value to the lhs */
    219 if( addcut )
    220 lhs = SCIProwGetLhs(row);
    221 else
    222 lhs = SCIPgetLhsLinear(masterprob, cons);
    223
    224 /* looping over all master problem variables to update the coefficients in the computed cut. */
    225 for( i = 0; i < nvars; i++ )
    226 {
    227 SCIP_VAR* subprobvar;
    228 SCIP_Real coef;
    229
    230 SCIP_CALL( SCIPgetBendersSubproblemVar(masterprob, benders, vars[i], &subprobvar, probnumber) );
    231
    232 /* if there is a corresponding subproblem variable, then the variable will not be NULL. */
    233 if( subprobvar != NULL )
    234 {
    235 /* if the variable is on its upper bound, then the subproblem objective value is added to the cut */
    236 if( SCIPisFeasEQ(masterprob, SCIPgetSolVal(masterprob, sol, vars[i]), 1.0) )
    237 {
    238 coef = -(subprobobj - cutconstant);
    239 lhs -= (subprobobj - cutconstant);
    240 }
    241 else
    242 coef = (subprobobj - cutconstant);
    243
    244 /* adding the variable to the cut. The coefficient is the subproblem objective value */
    245 if( addcut )
    246 {
    247 SCIP_CALL( SCIPaddVarToRow(masterprob, row, vars[i], coef) );
    248 }
    249 else
    250 {
    251 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, vars[i], coef) );
    252 }
    253 }
    254 }
    255
    256 lhs += subprobobj;
    257
    258 /* if the bound becomes infinite, then the cut generation terminates. */
    259 if( SCIPisInfinity(masterprob, lhs) || SCIPisInfinity(masterprob, -lhs) )
    260 {
    261 (*success) = FALSE;
    262 SCIPdebugMsg(masterprob, "Infinite bound when generating integer optimality cut.\n");
    263 return SCIP_OKAY;
    264 }
    265
    266 /* Update the lhs of the cut */
    267 if( addcut )
    268 {
    269 SCIP_CALL( SCIPchgRowLhs(masterprob, row, lhs) );
    270 }
    271 else
    272 {
    273 SCIP_CALL( SCIPchgLhsLinear(masterprob, cons, lhs) );
    274 }
    275
    276#ifndef NDEBUG
    277 if( addcut )
    278 lhs = SCIProwGetLhs(row);
    279 else
    280 lhs = SCIPgetLhsLinear(masterprob, cons);
    281 verifyobj += lhs;
    282
    283 if( addcut )
    284 verifyobj -= SCIPgetRowSolActivity(masterprob, row, sol);
    285 else
    286 verifyobj -= SCIPgetActivityLinear(masterprob, cons, sol);
    287#endif
    288
    289 assert(SCIPisFeasEQ(masterprob, verifyobj, subprobobj));
    290
    291 (*success) = TRUE;
    292
    293 return SCIP_OKAY;
    294}
    295
    296
    297/** adds the auxiliary variable to the generated cut. If this is the first optimality cut for the subproblem, then the
    298 * auxiliary variable is first created and added to the master problem.
    299 */
    300static
    302 SCIP* masterprob, /**< the SCIP instance of the master problem */
    303 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    304 SCIP_CONS* cons, /**< the constraint for the generated cut, can be NULL */
    305 SCIP_ROW* row, /**< the row for the generated cut, can be NULL */
    306 int probnumber, /**< the number of the pricing problem */
    307 SCIP_Bool addcut /**< indicates whether a cut is created instead of a constraint */
    308 )
    309{
    310 SCIP_VAR* auxiliaryvar;
    311
    312 assert(masterprob != NULL);
    313 assert(benders != NULL);
    314 assert(cons != NULL || addcut);
    315 assert(row != NULL || !addcut);
    316
    317 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    318
    319 /* adding the auxiliary variable to the generated cut */
    320 if( addcut )
    321 {
    322 SCIP_CALL( SCIPaddVarToRow(masterprob, row, auxiliaryvar, 1.0) );
    323 }
    324 else
    325 {
    326 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, auxiliaryvar, 1.0) );
    327 }
    328
    329 return SCIP_OKAY;
    330}
    331
    332
    333/** generates and applies Benders' cuts */
    334static
    336 SCIP* masterprob, /**< the SCIP instance of the master problem */
    337 SCIP_BENDERS* benders, /**< the benders' decomposition */
    338 SCIP_BENDERSCUT* benderscut, /**< the benders' decomposition cut method */
    339 SCIP_SOL* sol, /**< primal CIP solution */
    340 int probnumber, /**< the number of the pricing problem */
    341 SCIP_BENDERSENFOTYPE type, /**< the enforcement type calling this function */
    342 SCIP_RESULT* result, /**< the result from solving the subproblems */
    343 SCIP_Bool initcons /**< is this function called to generate the initial constraint */
    344 )
    345{
    346 SCIP_BENDERSCUTDATA* benderscutdata;
    347 SCIP_CONSHDLR* consbenders;
    348 SCIP_CONS* cons;
    349 SCIP_ROW* row;
    350 char cutname[SCIP_MAXSTRLEN];
    351 SCIP_Bool optimal;
    352 SCIP_Bool addcut;
    353 SCIP_Bool success;
    354
    355 assert(masterprob != NULL);
    356 assert(benders != NULL);
    357 assert(benderscut != NULL);
    358 assert(result != NULL);
    359
    360 row = NULL;
    361 cons = NULL;
    362
    363 success = FALSE;
    364
    365 /* retrieving the Benders' cut data */
    366 benderscutdata = SCIPbenderscutGetData(benderscut);
    367
    368 /* if the cuts are generated prior to the solving stage, then rows can not be generated. So constraints must be added
    369 * to the master problem.
    370 */
    371 if( SCIPgetStage(masterprob) < SCIP_STAGE_INITSOLVE )
    372 addcut = FALSE;
    373 else
    374 addcut = benderscutdata->addcuts;
    375
    376 /* retrieving the Benders' decomposition constraint handler */
    377 consbenders = SCIPfindConshdlr(masterprob, "benders");
    378
    379 /* checking the optimality of the original problem with a comparison between the auxiliary variable and the
    380 * objective value of the subproblem
    381 */
    382 optimal = FALSE;
    383 SCIP_CALL( SCIPcheckBendersSubproblemOptimality(masterprob, benders, sol, probnumber, &optimal) );
    384
    385 if( optimal )
    386 {
    387 (*result) = SCIP_FEASIBLE;
    388 SCIPdebugMsg(masterprob, "No <%s> cut added. Current Master Problem Obj: %g\n", BENDERSCUT_NAME,
    389 SCIPgetSolOrigObj(masterprob, NULL)*(int)SCIPgetObjsense(masterprob));
    390 return SCIP_OKAY;
    391 }
    392
    393 /* checking whether the subproblem constant is less than the auxiliary variable global lower bound */
    394 updateSubproblemCutConstant(masterprob, benders, benderscutdata, probnumber);
    395
    396 /* if no integer cuts have been previously generated and the bound on the auxiliary variable is -infinity,
    397 * then an initial lower bounding cut is added
    398 */
    399 if( benderscutdata->firstcut[probnumber]
    400 && SCIPisInfinity(masterprob, -SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber))) )
    401 {
    402 benderscutdata->firstcut[probnumber] = FALSE;
    403 SCIP_CALL( generateAndApplyBendersIntegerCuts(masterprob, benders, benderscut, sol, probnumber, type, result,
    404 TRUE) );
    405 }
    406
    407 /* setting the name of the generated cut */
    408 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "integeroptcut_%d_%" SCIP_LONGINT_FORMAT, probnumber,
    409 SCIPbenderscutGetNFound(benderscut) );
    410
    411 /* creating an empty row or constraint for the Benders' cut */
    412 if( addcut )
    413 {
    414 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname, 0.0, SCIPinfinity(masterprob), FALSE,
    415 FALSE, TRUE) );
    416 }
    417 else
    418 {
    419 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, 0, NULL, NULL, 0.0, SCIPinfinity(masterprob)) );
    420 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
    421 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
    422 }
    423
    424 if( initcons )
    425 {
    426 SCIP_Real lhs;
    427
    428 /* adding the subproblem objective function value to the lhs */
    429 if( addcut )
    430 lhs = SCIProwGetLhs(row);
    431 else
    432 lhs = SCIPgetLhsLinear(masterprob, cons);
    433
    434 lhs += benderscutdata->subprobconstant[probnumber];
    435
    436 /* if the bound becomes infinite, then the cut generation terminates. */
    437 if( SCIPisInfinity(masterprob, lhs) || SCIPisInfinity(masterprob, -lhs) )
    438 {
    439 success = FALSE;
    440 SCIPdebugMsg(masterprob, "Infinite bound when generating integer optimality cut.\n");
    441 }
    442
    443 /* Update the lhs of the cut */
    444 if( addcut )
    445 {
    446 SCIP_CALL( SCIPchgRowLhs(masterprob, row, lhs) );
    447 }
    448 else
    449 {
    450 SCIP_CALL( SCIPchgLhsLinear(masterprob, cons, lhs) );
    451 }
    452 }
    453 else
    454 {
    455 /* computing the coefficients of the optimality cut */
    456 SCIP_CALL( computeStandardIntegerOptCut(masterprob, benders, sol, cons, row,
    457 benderscutdata->subprobconstant[probnumber], probnumber, addcut, &success) );
    458 }
    459
    460 /* if success is FALSE, then there was an error in generating the integer optimality cut. No cut will be added to
    461 * the master problem. Otherwise, the constraint is added to the master problem.
    462 */
    463 if( !success )
    464 {
    465 (*result) = SCIP_DIDNOTFIND;
    466 SCIPdebugMsg(masterprob, "Error in generating Benders' integer optimality cut for problem %d.\n", probnumber);
    467 }
    468 else
    469 {
    470 /* adding the auxiliary variable to the optimality cut */
    471 SCIP_CALL( addAuxiliaryVariableToCut(masterprob, benders, cons, row, probnumber, addcut) );
    472
    473 /* adding the constraint to the master problem */
    474 if( addcut )
    475 {
    476 SCIP_Bool infeasible;
    477
    479 {
    480 SCIP_CALL( SCIPaddRow(masterprob, row, FALSE, &infeasible) );
    481 assert(!infeasible);
    482 }
    483 else
    484 {
    486 SCIP_CALL( SCIPaddPoolCut(masterprob, row) );
    487 }
    488
    489#ifdef SCIP_DEBUG
    490 SCIP_CALL( SCIPprintRow(masterprob, row, NULL) );
    491 SCIPinfoMessage(masterprob, NULL, ";\n");
    492#endif
    493
    494 (*result) = SCIP_SEPARATED;
    495 }
    496 else
    497 {
    498 SCIP_CALL( SCIPaddCons(masterprob, cons) );
    499
    500 SCIPdebugPrintCons(masterprob, cons, NULL);
    501
    502 (*result) = SCIP_CONSADDED;
    503 }
    504 }
    505
    506 if( addcut )
    507 {
    508 /* release the row */
    509 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
    510 }
    511 else
    512 {
    513 /* release the constraint */
    514 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
    515 }
    516
    517 return SCIP_OKAY;
    518}
    519
    520/*
    521 * Callback methods of Benders' decomposition cuts
    522 */
    523
    524/** destructor of Benders' decomposition cuts to free user data (called when SCIP is exiting) */
    525static
    526SCIP_DECL_BENDERSCUTFREE(benderscutFreeInt)
    527{ /*lint --e{715}*/
    528 SCIP_BENDERSCUTDATA* benderscutdata;
    529
    530 assert( benderscut != NULL );
    531 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
    532
    533 /* free Benders' cut data */
    534 benderscutdata = SCIPbenderscutGetData(benderscut);
    535 assert( benderscutdata != NULL );
    536
    537 SCIPfreeBlockMemory(scip, &benderscutdata);
    538
    539 SCIPbenderscutSetData(benderscut, NULL);
    540
    541 return SCIP_OKAY;
    542}
    543
    544
    545/** deinitialization method of Benders' decomposition cuts (called before transformed problem is freed) */
    546static
    547SCIP_DECL_BENDERSCUTEXIT(benderscutExitInt)
    548{ /*lint --e{715}*/
    549 SCIP_BENDERSCUTDATA* benderscutdata;
    550
    551 assert( benderscut != NULL );
    552 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
    553
    554 /* free Benders' cut data */
    555 benderscutdata = SCIPbenderscutGetData(benderscut);
    556 assert( benderscutdata != NULL );
    557
    558 if( benderscutdata->firstcut != NULL )
    559 SCIPfreeBlockMemoryArray(scip, &benderscutdata->firstcut, benderscutdata->nsubproblems);
    560
    561 if( benderscutdata->subprobconstant != NULL)
    562 SCIPfreeBlockMemoryArray(scip, &benderscutdata->subprobconstant, benderscutdata->nsubproblems);
    563
    564 return SCIP_OKAY;
    565}
    566
    567/** execution method of Benders' decomposition cuts */
    568static
    569SCIP_DECL_BENDERSCUTEXEC(benderscutExecInt)
    570{ /*lint --e{715}*/
    571 SCIP* subproblem;
    572 SCIP_BENDERSCUTDATA* benderscutdata;
    573
    574 assert(scip != NULL);
    575 assert(benders != NULL);
    576 assert(benderscut != NULL);
    577 assert(result != NULL);
    578
    579 subproblem = SCIPbendersSubproblem(benders, probnumber);
    580
    581 if( subproblem == NULL )
    582 {
    583 SCIPdebugMsg(scip, "The subproblem %d is set to NULL. The <%s> Benders' decomposition cut can not be executed.\n",
    584 probnumber, BENDERSCUT_NAME);
    585
    586 (*result) = SCIP_DIDNOTRUN;
    587 return SCIP_OKAY;
    588 }
    589
    590 /* retrieving the Benders' cut data */
    591 benderscutdata = SCIPbenderscutGetData(benderscut);
    592 assert(benderscutdata != NULL);
    593
    594 /* if the Benders' cut data has not been created, then it is created now */
    595 if( !benderscutdata->created )
    596 {
    597 SCIP_CALL( createBenderscutData(scip, benderscutdata) );
    598 }
    599
    600 /* it is only possible to generate the Laporte and Louveaux cuts when the linking variables are all binary */
    601 if( !benderscutdata->subprobsvalid )
    602 {
    603 SCIPwarningMessage(scip, "The integer optimality cuts have been disabled because some linking variables are not binary.\n"
    604 "Since there is at least one non-convex subproblem, i.e. not LP or convex NLP, the problem will be solved heuristically.\n");
    605
    606 SCIPbenderscutSetEnabled(benderscut, FALSE);
    607
    608 return SCIP_OKAY;
    609 }
    610
    611 /* the integer subproblem could terminate early if the auxiliary variable value is much greater than the optimal
    612 * solution. As such, it is only necessary to generate a cut if the subproblem is OPTIMAL */
    613 if( SCIPgetStatus(subproblem) == SCIP_STATUS_OPTIMAL )
    614 {
    615 /* generating a cut for a given subproblem */
    616 SCIP_CALL( generateAndApplyBendersIntegerCuts(scip, benders, benderscut, sol, probnumber, type, result, FALSE) );
    617 }
    618
    619 return SCIP_OKAY;
    620}
    621
    622
    623/*
    624 * Benders' decomposition cuts specific interface methods
    625 */
    626
    627/** creates the int Benders' decomposition cuts and includes it in SCIP */
    629 SCIP* scip, /**< SCIP data structure */
    630 SCIP_BENDERS* benders /**< Benders' decomposition */
    631 )
    632{
    633 SCIP_BENDERSCUTDATA* benderscutdata;
    634 SCIP_BENDERSCUT* benderscut;
    636
    637 assert(benders != NULL);
    638
    639 /* create int Benders' decomposition cuts data */
    640 SCIP_CALL( SCIPallocBlockMemory(scip, &benderscutdata) );
    641 BMSclearMemory(benderscutdata);
    642 benderscutdata->benders = benders;
    643
    644 benderscut = NULL;
    645
    646 /* include Benders' decomposition cuts */
    648 BENDERSCUT_PRIORITY, BENDERSCUT_LPCUT, benderscutExecInt, benderscutdata) );
    649
    650 assert(benderscut != NULL);
    651
    652 /* set non fundamental callbacks via setter functions */
    653 SCIP_CALL( SCIPsetBenderscutFree(scip, benderscut, benderscutFreeInt) );
    654 SCIP_CALL( SCIPsetBenderscutExit(scip, benderscut, benderscutExitInt) );
    655
    656 /* add int Benders' decomposition cuts parameters */
    657 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/cutsconstant",
    660 "the constant term of the integer Benders' cuts.",
    661 &benderscutdata->cutconstant, FALSE, SCIP_DEFAULT_CUTCONSTANT, -SCIPinfinity(scip), SCIPinfinity(scip),
    662 paramChgdBenderscutintConstant, (SCIP_PARAMDATA*)benderscutdata) );
    663
    664 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/addcuts",
    667 "should cuts be generated and added to the cutpool instead of global constraints directly added to the problem.",
    668 &benderscutdata->addcuts, FALSE, SCIP_DEFAULT_ADDCUTS, NULL, NULL) );
    669
    670 return SCIP_OKAY;
    671}
    #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:255
    #define SCIP_MAXSTRLEN
    Definition: def.h:276
    #define SCIP_Bool
    Definition: def.h:98
    #define SCIP_Real
    Definition: def.h:163
    #define TRUE
    Definition: def.h:100
    #define FALSE
    Definition: def.h:101
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:155
    #define SCIP_CALL(x)
    Definition: def.h:362
    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
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    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:6212
    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:5966
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6010
    SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6020
    void SCIPbendersGetSubproblemMasterVarsData(SCIP_BENDERS *benders, int probnumber, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars)
    Definition: benders.c:6258
    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:6301
    SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6892
    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:2988
    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
    type definitions for message output methods
    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