Scippy

    SCIP

    Solving Constraint Integer Programs

    benders.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 benders.c
    26 * @ingroup OTHER_CFILES
    27 * @brief methods for Benders' decomposition
    28 * @author Stephen J. Maher
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include <assert.h>
    34#include <string.h>
    35
    36#include "scip/def.h"
    37#include "scip/set.h"
    38#include "scip/clock.h"
    39#include "scip/dcmp.h"
    40#include "scip/paramset.h"
    41#include "scip/lp.h"
    42#include "scip/prob.h"
    43#include "scip/pricestore.h"
    44#include "scip/scip.h"
    45#include "scip/scipdefplugins.h"
    46#include "scip/benders.h"
    47#include "scip/pub_benders.h"
    48#include "scip/pub_message.h"
    49#include "scip/pub_misc.h"
    50#include "scip/cons_linear.h"
    51#include "scip/cons_nonlinear.h"
    52
    53#include "scip/struct_benders.h"
    55
    56#include "scip/benderscut.h"
    57
    58/* Defaults for parameters */
    59#define SCIP_DEFAULT_TRANSFERCUTS FALSE /** should Benders' cuts generated in LNS heuristics be transferred to the main SCIP instance? */
    60#define SCIP_DEFAULT_CUTSASCONSS TRUE /** should the transferred cuts be added as constraints? */
    61#define SCIP_DEFAULT_LNSCHECK TRUE /** should the Benders' decomposition be used in LNS heuristics */
    62#define SCIP_DEFAULT_LNSMAXDEPTH -1 /** maximum depth at which the LNS check is performed */
    63#define SCIP_DEFAULT_LNSMAXCALLS 10 /** the maximum number of Benders' decomposition calls in LNS heuristics */
    64#define SCIP_DEFAULT_LNSMAXCALLSROOT 0 /** the maximum number of root node Benders' decomposition calls in LNS heuristics */
    65#define SCIP_DEFAULT_SUBPROBFRAC 1.0 /** fraction of subproblems that are solved in each iteration */
    66#define SCIP_DEFAULT_UPDATEAUXVARBOUND FALSE /** should the auxiliary variable lower bound be updated by solving the subproblem */
    67#define SCIP_DEFAULT_AUXVARSIMPLINT FALSE /** set the auxiliary variables as implint if the subproblem objective is integer */
    68#define SCIP_DEFAULT_CUTCHECK TRUE /** should cuts be generated during the checking of solutions? */
    69#define SCIP_DEFAULT_STRENGTHENMULT 0.5 /** the convex combination multiplier for the cut strengthening */
    70#define SCIP_DEFAULT_NOIMPROVELIMIT 5 /** the maximum number of cut strengthening without improvement */
    71#define SCIP_DEFAULT_STRENGTHENPERTURB 1e-06 /** the amount by which the cut strengthening solution is perturbed */
    72#define SCIP_DEFAULT_STRENGTHENENABLED FALSE /** enable the core point cut strengthening approach */
    73#define SCIP_DEFAULT_STRENGTHENINTPOINT 'r' /** where should the strengthening interior point be sourced from ('l'p relaxation, 'f'irst solution, 'i'ncumbent solution, 'r'elative interior point, vector of 'o'nes, vector of 'z'eros) */
    74#ifdef SCIP_DISABLED_CODE /* temporarily disabling support for multiple threads in Benders' decomposition */
    75#define SCIP_DEFAULT_NUMTHREADS 1 /** the number of parallel threads to use when solving the subproblems */
    76#endif
    77#define SCIP_DEFAULT_EXECFEASPHASE FALSE /** should a feasibility phase be executed during the root node processing */
    78#define SCIP_DEFAULT_SLACKVARCOEF 1e+6 /** the initial objective coefficient of the slack variables in the subproblem */
    79#define SCIP_DEFAULT_MAXSLACKVARCOEF 1e+9 /** the maximal objective coefficient of the slack variables in the subproblem */
    80#define SCIP_DEFAULT_CHECKCONSCONVEXITY TRUE /** should the constraints of the subproblem be checked for convexity? */
    81#define SCIP_DEFAULT_NLPITERLIMIT 10000 /** iteration limit for NLP solver */
    82
    83#define BENDERS_MAXPSEUDOSOLS 5 /** the maximum number of pseudo solutions checked before suggesting
    84 * merge candidates */
    85#define BENDERS_MASTERVARARRAYSIZE 100 /**< the initial size of the submastervars arrays */
    86#define BENDERS_ARRAYSIZE 1000 /**< the initial size of the added constraints/cuts arrays */
    88#define AUXILIARYVAR_NAME "##bendersauxiliaryvar" /** the name for the Benders' auxiliary variables in the master problem */
    89#define SLACKVAR_NAME "##bendersslackvar" /** the name for the Benders' slack variables added to each
    90 * constraints in the subproblems */
    91#define NLINEARCONSHDLRS 5
    93/* event handler properties */
    94#define NODEFOCUS_EVENTHDLR_NAME "bendersnodefocus"
    95#define NODEFOCUS_EVENTHDLR_DESC "node focus event handler for Benders' decomposition"
    97#define MIPNODEFOCUS_EVENTHDLR_NAME "bendersmipsolvenodefocus"
    98#define MIPNODEFOCUS_EVENTHDLR_DESC "node focus event handler for the MIP solve method for Benders' decomposition"
    100#define UPPERBOUND_EVENTHDLR_NAME "bendersupperbound"
    101#define UPPERBOUND_EVENTHDLR_DESC "found solution event handler to terminate subproblem solve for a given upper bound"
    103#define NODESOLVED_EVENTHDLR_NAME "bendersnodesolved"
    104#define NODESOLVED_EVENTHDLR_DESC "node solved event handler for the Benders' integer cuts"
    105
    106
    107/** event handler data */
    108struct SCIP_EventhdlrData
    109{
    110 int filterpos; /**< the event filter entry */
    111 int numruns; /**< the number of times that the problem has been solved */
    112 SCIP_Real upperbound; /**< an upper bound for the problem */
    113 SCIP_Bool solvecip; /**< is the event called from a MIP subproblem solve*/
    114};
    115
    116
    117/* ---------------- Local methods for event handlers ---------------- */
    118
    119/** initialises the members of the eventhandler data */
    120static
    122 SCIP* scip, /**< the SCIP data structure */
    123 SCIP_EVENTHDLRDATA* eventhdlrdata /**< the event handler data */
    124 )
    125{
    126 assert(scip != NULL);
    127 assert(eventhdlrdata != NULL);
    128
    129 eventhdlrdata->filterpos = -1;
    130 eventhdlrdata->numruns = 0;
    131 eventhdlrdata->upperbound = -SCIPinfinity(scip);
    132 eventhdlrdata->solvecip = FALSE;
    133
    134 return SCIP_OKAY;
    135}
    136
    137/** initsol method for the event handlers */
    138static
    140 SCIP* scip, /**< the SCIP data structure */
    141 SCIP_EVENTHDLR* eventhdlr, /**< the event handlers data structure */
    142 SCIP_EVENTTYPE eventtype /**< event type mask to select events to catch */
    143 )
    144{
    145 SCIP_EVENTHDLRDATA* eventhdlrdata;
    146
    147 assert(scip != NULL);
    148 assert(eventhdlr != NULL);
    149
    150 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    151
    152 SCIP_CALL( SCIPcatchEvent(scip, eventtype, eventhdlr, NULL, &eventhdlrdata->filterpos) );
    153
    154 return SCIP_OKAY;
    155}
    156
    157/** the exit sol method for the event handlers */
    158static
    160 SCIP* scip, /**< the SCIP data structure */
    161 SCIP_EVENTHDLR* eventhdlr, /**< the event handlers data structure */
    162 SCIP_EVENTTYPE eventtype /**< event type mask to select events to catch */
    163 )
    164{
    165 SCIP_EVENTHDLRDATA* eventhdlrdata;
    166
    167 assert(scip != NULL);
    168 assert(eventhdlr != NULL);
    169
    170 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    171
    172 if( eventhdlrdata->filterpos >= 0 )
    173 {
    174 SCIP_CALL( SCIPdropEvent(scip, eventtype, eventhdlr, NULL, eventhdlrdata->filterpos) );
    175 eventhdlrdata->filterpos = -1;
    176 }
    177
    178 return SCIP_OKAY;
    179}
    180
    181/** the exit method for the event handlers */
    182static
    184 SCIP* scip, /**< the SCIP data structure */
    185 SCIP_EVENTHDLR* eventhdlr /**< the event handlers data structure */
    186 )
    187{
    188 SCIP_EVENTHDLRDATA* eventhdlrdata;
    189
    190 assert(scip != NULL);
    191 assert(eventhdlr != NULL);
    192
    193 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    194
    195 /* reinitialise the event handler data */
    196 SCIP_CALL( initEventhandlerData(scip, eventhdlrdata) );
    197
    198 return SCIP_OKAY;
    199}
    200
    201/** free method for the event handler */
    202static
    204 SCIP* scip, /**< the SCIP data structure */
    205 SCIP_EVENTHDLR* eventhdlr /**< the event handlers data structure */
    206 )
    207{
    208 SCIP_EVENTHDLRDATA* eventhdlrdata;
    209
    210 assert(scip != NULL);
    211 assert(eventhdlr != NULL);
    212
    213 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    214 assert(eventhdlrdata != NULL);
    215
    216 SCIPfreeBlockMemory(scip, &eventhdlrdata);
    217
    218 SCIPeventhdlrSetData(eventhdlr, NULL);
    219
    220 return SCIP_OKAY;
    221}
    222
    223
    224
    225/* ---------------- Callback methods of node focus event handler ---------------- */
    226
    227/** exec the event handler */
    228static
    229SCIP_DECL_EVENTEXEC(eventExecBendersNodefocus)
    230{ /*lint --e{715}*/
    231 SCIP_EVENTHDLRDATA* eventhdlrdata;
    232
    233 assert(scip != NULL);
    234 assert(eventhdlr != NULL);
    235 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODEFOCUS_EVENTHDLR_NAME) == 0);
    236
    237 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    238
    239 /* sending an interrupt solve signal to return the control back to the Benders' decomposition plugin.
    240 * This will ensure the SCIP stage is SCIP_STAGE_SOLVING, allowing the use of probing mode. */
    242
    243 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_NODEFOCUSED, eventhdlr, NULL, eventhdlrdata->filterpos) );
    244 eventhdlrdata->filterpos = -1;
    245
    246 return SCIP_OKAY;
    247}
    248
    249/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
    250static
    251SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodefocus)
    252{
    253 assert(scip != NULL);
    254 assert(eventhdlr != NULL);
    255 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODEFOCUS_EVENTHDLR_NAME) == 0);
    256
    258
    259 return SCIP_OKAY;
    260}
    261
    262/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
    263static
    264SCIP_DECL_EVENTEXITSOL(eventExitsolBendersNodefocus)
    265{
    266 assert(scip != NULL);
    267 assert(eventhdlr != NULL);
    268 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODEFOCUS_EVENTHDLR_NAME) == 0);
    269
    271
    272 return SCIP_OKAY;
    273}
    274
    275/** deinitialization method of event handler (called before transformed problem is freed) */
    276static
    277SCIP_DECL_EVENTEXIT(eventExitBendersNodefocus)
    278{
    279 assert(scip != NULL);
    280 assert(eventhdlr != NULL);
    281 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODEFOCUS_EVENTHDLR_NAME) == 0);
    282
    283 SCIP_CALL( exitEventhandler(scip, eventhdlr) );
    284
    285 return SCIP_OKAY;
    286}
    287
    288/** deinitialization method of event handler (called before transformed problem is freed) */
    289static
    290SCIP_DECL_EVENTFREE(eventFreeBendersNodefocus)
    291{
    292 assert(scip != NULL);
    293 assert(eventhdlr != NULL);
    294 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODEFOCUS_EVENTHDLR_NAME) == 0);
    295
    296 SCIP_CALL( freeEventhandler(scip, eventhdlr) );
    297
    298 return SCIP_OKAY;
    299}
    300
    301
    302/* ---------------- Callback methods of MIP solve node focus event handler ---------------- */
    303
    304/** exec the event handler */
    305static
    306SCIP_DECL_EVENTEXEC(eventExecBendersMipnodefocus)
    307{ /*lint --e{715}*/
    308 SCIP_EVENTHDLRDATA* eventhdlrdata;
    309
    310 assert(scip != NULL);
    311 assert(eventhdlr != NULL);
    312 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
    313
    314 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    315
    316 /* interrupting the solve so that the control is returned back to the Benders' core. */
    317 if( eventhdlrdata->numruns == 0 && !eventhdlrdata->solvecip )
    318 {
    320 }
    321
    322 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_NODEFOCUSED, eventhdlr, NULL, eventhdlrdata->filterpos) );
    323 eventhdlrdata->filterpos = -1;
    324
    325 eventhdlrdata->numruns++;
    326
    327 return SCIP_OKAY;
    328}
    329
    330/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
    331static
    332SCIP_DECL_EVENTINITSOL(eventInitsolBendersMipnodefocus)
    333{
    334 assert(scip != NULL);
    335 assert(eventhdlr != NULL);
    336 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
    337
    339
    340 return SCIP_OKAY;
    341}
    342
    343/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
    344static
    345SCIP_DECL_EVENTEXITSOL(eventExitsolBendersMipnodefocus)
    346{
    347 assert(scip != NULL);
    348 assert(eventhdlr != NULL);
    349 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
    350
    352
    353 return SCIP_OKAY;
    354}
    355
    356/** deinitialization method of event handler (called before transformed problem is freed) */
    357static
    358SCIP_DECL_EVENTEXIT(eventExitBendersMipnodefocus)
    359{
    360 assert(scip != NULL);
    361 assert(eventhdlr != NULL);
    362 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
    363
    364 SCIP_CALL( exitEventhandler(scip, eventhdlr) );
    365
    366 return SCIP_OKAY;
    367}
    368
    369/** deinitialization method of event handler (called before transformed problem is freed) */
    370static
    371SCIP_DECL_EVENTFREE(eventFreeBendersMipnodefocus)
    372{
    373 assert(scip != NULL);
    374 assert(eventhdlr != NULL);
    375 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
    376
    377 SCIP_CALL( freeEventhandler(scip, eventhdlr) );
    378
    379 return SCIP_OKAY;
    380}
    381
    382/* ---------------- Callback methods of solution found event handler ---------------- */
    383
    384/** exec the event handler */
    385static
    386SCIP_DECL_EVENTEXEC(eventExecBendersUpperbound)
    387{ /*lint --e{715}*/
    388 SCIP_EVENTHDLRDATA* eventhdlrdata;
    389 SCIP_SOL* bestsol;
    390
    391 assert(scip != NULL);
    392 assert(eventhdlr != NULL);
    393 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), UPPERBOUND_EVENTHDLR_NAME) == 0);
    394
    395 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    396 assert(eventhdlrdata != NULL);
    397
    398 bestsol = SCIPgetBestSol(scip);
    399
    400 if( SCIPisLT(scip, SCIPgetSolOrigObj(scip, bestsol)*(int)SCIPgetObjsense(scip), eventhdlrdata->upperbound) )
    401 {
    403 }
    404
    405 return SCIP_OKAY;
    406}
    407
    408/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
    409static
    410SCIP_DECL_EVENTINITSOL(eventInitsolBendersUpperbound)
    411{
    412 assert(scip != NULL);
    413 assert(eventhdlr != NULL);
    414 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), UPPERBOUND_EVENTHDLR_NAME) == 0);
    415
    417
    418 return SCIP_OKAY;
    419}
    420
    421/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
    422static
    423SCIP_DECL_EVENTEXITSOL(eventExitsolBendersUpperbound)
    424{
    425 assert(scip != NULL);
    426 assert(eventhdlr != NULL);
    427 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), UPPERBOUND_EVENTHDLR_NAME) == 0);
    428
    430
    431 return SCIP_OKAY;
    432}
    433
    434/** deinitialization method of event handler (called before transformed problem is freed) */
    435static
    436SCIP_DECL_EVENTEXIT(eventExitBendersUpperbound)
    437{
    438 assert(scip != NULL);
    439 assert(eventhdlr != NULL);
    440 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), UPPERBOUND_EVENTHDLR_NAME) == 0);
    441
    442 SCIP_CALL( exitEventhandler(scip, eventhdlr) );
    443
    444 return SCIP_OKAY;
    445}
    446
    447/** deinitialization method of event handler (called before transformed problem is freed) */
    448static
    449SCIP_DECL_EVENTFREE(eventFreeBendersUpperbound)
    450{
    451 assert(scip != NULL);
    452 assert(eventhdlr != NULL);
    453 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), UPPERBOUND_EVENTHDLR_NAME) == 0);
    454
    455 SCIP_CALL( freeEventhandler(scip, eventhdlr) );
    456
    457 return SCIP_OKAY;
    458}
    459
    460/** updates the upper bound in the event handler data */
    461static
    463 SCIP_BENDERS* benders, /**< Benders' decomposition */
    464 int probnumber, /**< the subproblem number */
    465 SCIP_Real upperbound /**< the upper bound value */
    466 )
    467{
    468 SCIP_EVENTHDLR* eventhdlr;
    469 SCIP_EVENTHDLRDATA* eventhdlrdata;
    470
    471 assert(benders != NULL);
    472 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    473
    474 eventhdlr = SCIPfindEventhdlr(SCIPbendersSubproblem(benders, probnumber), UPPERBOUND_EVENTHDLR_NAME);
    475 assert(eventhdlr != NULL);
    476
    477 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    478 assert(eventhdlrdata != NULL);
    479
    480 eventhdlrdata->upperbound = upperbound;
    481
    482 return SCIP_OKAY;
    483}
    484
    485/* ---------------- Callback methods of the node solved event handler ---------------- */
    486
    487/** Updates the cut constant of the Benders' cuts data.
    488 * This function solves the master problem with only the auxiliary variables in the objective function.
    489 */
    490static
    492 SCIP* masterprob, /**< the SCIP instance of the master problem */
    493 SCIP_BENDERS* benders /**< Benders' decomposition */
    494 )
    495{
    496 SCIP_VAR** vars;
    497 int nvars;
    498 int nsubproblems;
    499 int i;
    500 SCIP_Bool lperror;
    501 SCIP_Bool cutoff;
    502
    503 assert(masterprob != NULL);
    504 assert(benders != NULL);
    505
    506 /* don't run in probing or in repropagation */
    507 if( SCIPinProbing(masterprob) || SCIPinRepropagation(masterprob) || SCIPinDive(masterprob) )
    508 return SCIP_OKAY;
    509
    510 nsubproblems = SCIPbendersGetNSubproblems(benders);
    511
    512 SCIP_CALL( SCIPstartProbing(masterprob) );
    513
    514 /* change the master problem variables to 0 */
    515 nvars = SCIPgetNVars(masterprob);
    516 vars = SCIPgetVars(masterprob);
    517
    518 /* setting the objective function coefficient to 0 for all variables */
    519 for( i = 0; i < nvars; i++ )
    520 {
    522 {
    523 SCIP_CALL( SCIPchgVarObjProbing(masterprob, vars[i], 0.0) );
    524 }
    525 }
    526
    527 /* solving an LP for all subproblems to find the lower bound */
    528 for( i = 0; i < nsubproblems; i++)
    529 {
    530 SCIP_VAR* auxiliaryvar;
    531
    532 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, i);
    533
    534 if( SCIPvarGetStatus(auxiliaryvar) != SCIP_VARSTATUS_COLUMN )
    535 continue;
    536
    537 SCIP_CALL( SCIPchgVarObjProbing(masterprob, auxiliaryvar, 1.0) );
    538
    539 /* solving the probing LP to get a lower bound on the auxiliary variables */
    540 SCIP_CALL( SCIPsolveProbingLP(masterprob, -1, &lperror, &cutoff) );
    541
    542 if( !SCIPisInfinity(masterprob, -SCIPgetSolTransObj(masterprob, NULL)) )
    544
    545 SCIPdebugMsg(masterprob, "Cut constant for subproblem %d: %g\n", i,
    547
    548 SCIP_CALL( SCIPchgVarObjProbing(masterprob, auxiliaryvar, 0.0) );
    549 }
    550
    551 SCIP_CALL( SCIPendProbing(masterprob) );
    552
    553 return SCIP_OKAY;
    554}
    555
    556/** exec the event handler */
    557static
    558SCIP_DECL_EVENTEXEC(eventExecBendersNodesolved)
    559{ /*lint --e{715}*/
    560 SCIP_BENDERS* benders;
    561
    562 assert(scip != NULL);
    563 assert(eventhdlr != NULL);
    564 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODESOLVED_EVENTHDLR_NAME) == 0);
    565
    566 benders = (SCIP_BENDERS*)SCIPeventhdlrGetData(eventhdlr); /*lint !e826*/
    567
    568 if( SCIPbendersGetNSubproblems(benders) > 0
    570 {
    572 }
    573
    575
    576 return SCIP_OKAY;
    577}
    578
    579/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
    580static
    581SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodesolved)
    582{
    583 SCIP_BENDERS* benders;
    584
    585 assert(scip != NULL);
    586 assert(eventhdlr != NULL);
    587 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), NODESOLVED_EVENTHDLR_NAME) == 0);
    588
    589 /* getting the Benders' decomposition data structure */
    590 benders = (SCIP_BENDERS*)SCIPeventhdlrGetData(eventhdlr); /*lint !e826*/
    591
    592 /* The event is only caught if there is an active Benders' decomposition, the integer subproblem are solved and
    593 * the Benders' decomposition has not been copied in thread safe mode
    594 */
    596 && !benders->threadsafe )
    597 {
    599 }
    600
    601 return SCIP_OKAY;
    602}
    603
    604
    605/* ---------------- Methods for the parallelisation of Benders' decomposition ---------------- */
    606
    607/** comparison method for sorting the subproblems.
    608 * The subproblem that has been called the least is prioritised
    609 */
    610static
    611SCIP_DECL_SORTPTRCOMP(benderssubcompdefault)
    612{
    613 SCIP_SUBPROBLEMSOLVESTAT* solvestat1;
    614 SCIP_SUBPROBLEMSOLVESTAT* solvestat2;
    615
    616 assert(elem1 != NULL);
    617 assert(elem2 != NULL);
    618
    619 solvestat1 = (SCIP_SUBPROBLEMSOLVESTAT*)elem1;
    620 solvestat2 = (SCIP_SUBPROBLEMSOLVESTAT*)elem2;
    621
    622 /* prefer subproblems with fewer calls, using the index as tie breaker */
    623 if( MAX(solvestat1->ncalls, solvestat2->ncalls) == 0 )
    624 return solvestat1->idx - solvestat2->idx;
    625 else if( solvestat1->ncalls != solvestat2->ncalls )
    626 return solvestat1->ncalls - solvestat2->ncalls;
    627 else
    628 {
    629 /* prefer the harder problem (with more average iterations) */
    630 int avgiterdiff = (int)solvestat2->avgiter - (int)solvestat1->avgiter;
    631
    632 if( avgiterdiff != 0 )
    633 return avgiterdiff;
    634
    635 return solvestat1->idx - solvestat2->idx;
    636 }
    637
    638/* the code below does not give a total order of the elements */
    639#ifdef SCIP_DISABLED_CODE
    640 if( solvestat1->ncalls == 0 )
    641 if( solvestat2->ncalls == 0 )
    642 if( solvestat1->idx < solvestat2->idx )
    643 return -1;
    644 else
    645 return 1;
    646 else
    647 return -1;
    648 else if( solvestat2->ncalls == 0 )
    649 return 1;
    650 else
    651 {
    652 if( solvestat1->ncalls < solvestat2->ncalls )
    653 return -1;
    654 else if( solvestat2->ncalls < solvestat1->ncalls )
    655 return 1;
    656 else
    657 {
    658 /* we want to execute the hard subproblems first */
    659 if( solvestat1->avgiter > solvestat2->avgiter )
    660 return 1;
    661 else
    662 return -1;
    663 }
    664 }
    665#endif
    666}
    667
    668/* Local methods */
    669
    670/** A workaround for GCG. This is a temp vardata that is set for the auxiliary variables */
    671struct SCIP_VarData
    672{
    673 int vartype; /**< the variable type. In GCG this indicates whether the variable is a
    674 * master problem or subproblem variable. */
    675};
    676
    677/** adds the auxiliary variables to the Benders' decomposition master problem */
    678static
    680 SCIP* scip, /**< SCIP data structure */
    681 SCIP_BENDERS* benders /**< Benders' decomposition structure */
    682 )
    683{
    684 SCIP_BENDERS* topbenders; /* the highest priority Benders' decomposition */
    685 SCIP_VAR* auxiliaryvar;
    686 SCIP_CONS* cons;
    687 SCIP_VARDATA* vardata;
    688 char varname[SCIP_MAXSTRLEN]; /* the name of the auxiliary variable */
    689 char consname[SCIP_MAXSTRLEN]; /* the name of the auxiliary variable constraint */
    690 SCIP_Bool shareauxvars;
    691 SCIP_Bool allsubprobintegralobj;
    692 int i;
    693
    694 /* this is a workaround for GCG. GCG expects that the variable has vardata when added. So a dummy vardata is created */
    695 SCIP_CALL( SCIPallocBlockMemory(scip, &vardata) );
    696 vardata->vartype = -1;
    697
    698 /* getting the highest priority Benders' decomposition */
    699 topbenders = SCIPgetBenders(scip)[0];
    700
    701 /* if the current Benders is the highest priority Benders, then we need to create the auxiliary variables.
    702 * Otherwise, if the shareauxvars flag is set, then the auxiliary variables from the highest priority Benders' are
    703 * stored with this Benders. */
    704 shareauxvars = FALSE;
    705 if( topbenders != benders && SCIPbendersShareAuxVars(benders) )
    706 shareauxvars = TRUE;
    707
    708 /* creating the auxiliary variable objective sum constraint. If the auxiliary variables are shared, then the constraint
    709 * is only added to the top Benders. Otherwise, it is created for each Benders implementation. */
    710 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
    711 {
    712 if( shareauxvars )
    713 {
    714 benders->auxiliaryvarcons = topbenders->auxiliaryvarcons;
    715 }
    716 else
    717 {
    718 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_%s", AUXILIARYVAR_NAME, SCIPbendersGetName(benders) );
    719 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, consname, 0, NULL, NULL, 0.0, 0.0) );
    720 SCIP_CALL( SCIPaddCons(scip, cons) );
    721
    722 benders->auxiliaryvarcons[0] = cons;
    723 }
    724 }
    725
    726 /* sharing or creating the master auxiliary variable */
    727 if( shareauxvars )
    728 {
    729 benders->masterauxvar = topbenders->masterauxvar;
    730
    731 SCIP_CALL( SCIPcaptureVar(scip, topbenders->masterauxvar) );
    732 }
    733 else
    734 {
    735 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "master_%s_%s", AUXILIARYVAR_NAME, SCIPbendersGetName(benders) );
    738
    739 SCIPvarSetData(benders->masterauxvar, vardata);
    740
    742
    743 /* adding the down lock for the Benders' decomposition constraint handler */
    745
    746 /* adding the master auxiliary variable to the summation constraint */
    747 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
    748 {
    749 SCIP_CALL( SCIPaddCoefLinear(scip, benders->auxiliaryvarcons[0], benders->masterauxvar, 1.0) );
    750 }
    751 }
    752
    753 allsubprobintegralobj = TRUE;
    754
    755 for( i = 0; i < SCIPbendersGetNSubproblems(benders); i++ )
    756 {
    757 /* if the auxiliary variables are shared, then a pointer to the variable is retrieved from topbenders,
    758 * otherwise the auxiliaryvariable is created. The auxiliary variable constraint is also copied from the
    759 * topbenders if the auxiliary variables are shared. */
    760 if( shareauxvars )
    761 {
    762 auxiliaryvar = SCIPbendersGetAuxiliaryVar(topbenders, i);
    763
    764 SCIP_CALL( SCIPcaptureVar(scip, auxiliaryvar) );
    765
    766 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX )
    767 {
    768 benders->auxiliaryvarcons[i] = topbenders->auxiliaryvarcons[i];
    769
    771 }
    772 }
    773 else
    774 {
    775 SCIP_IMPLINTTYPE impltype;
    776
    777 /* declare an auxiliary variable implied integral if the objective function of the
    778 * subproblem is guaranteed to be integral and this is desired
    779 * NOTE: It is only possible to determine if the objective function is integral if the subproblem is defined as
    780 * a SCIP instance, i.e. not NULL.
    781 */
    782 if( benders->auxvarsimplint && SCIPbendersSubproblem(benders, i) != NULL
    784 impltype = SCIP_IMPLINTTYPE_WEAK;
    785 else
    786 {
    787 impltype = SCIP_IMPLINTTYPE_NONE;
    788 allsubprobintegralobj = FALSE;
    789 }
    790
    791 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s_%d_%s", AUXILIARYVAR_NAME, i, SCIPbendersGetName(benders) );
    792 SCIP_CALL( SCIPcreateVarImpl(scip, &auxiliaryvar, varname, benders->subproblowerbound[i], SCIPinfinity(scip), 0.0,
    794
    795 SCIPvarSetData(auxiliaryvar, vardata);
    796
    797 SCIP_CALL( SCIPaddVar(scip, auxiliaryvar) );
    798
    799 /* adding the down lock for the Benders' decomposition constraint handler */
    800 SCIP_CALL( SCIPaddVarLocksType(scip, auxiliaryvar, SCIP_LOCKTYPE_MODEL, 1, 0) );
    801
    802 /* if the objective type is minimax, then we need to create the auxiliary variable constraints and add the
    803 * auxiliary variable to them. If the objective type is sum, then the auxiliary variables are added to the
    804 * objective constraint.
    805 */
    806 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX )
    807 {
    808 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_%d_%s", AUXILIARYVAR_NAME, i, SCIPbendersGetName(benders) );
    809 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, consname, 0, NULL, NULL, 0.0, SCIPinfinity(scip)) );
    810 SCIP_CALL( SCIPaddCons(scip, cons) );
    811
    812 /* adding the coefficients to the constraint */
    813 SCIP_CALL( SCIPaddCoefLinear(scip, cons, benders->masterauxvar, 1.0) );
    814 SCIP_CALL( SCIPaddCoefLinear(scip, cons, auxiliaryvar, -1.0) );
    815
    816 benders->auxiliaryvarcons[i] = cons;
    817 }
    818 else
    819 {
    820 assert(benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM);
    821
    822 SCIP_CALL( SCIPaddCoefLinear(scip, benders->auxiliaryvarcons[0], auxiliaryvar, -1.0) );
    823 }
    824 }
    825
    826 benders->auxiliaryvars[i] = auxiliaryvar;
    827 }
    828
    829 if( !shareauxvars && allsubprobintegralobj )
    830 {
    831 SCIP_Bool infeasible;
    833 assert(!infeasible);
    834 }
    835
    836 SCIPfreeBlockMemory(scip, &vardata);
    837
    838 return SCIP_OKAY;
    839}
    840
    841
    842/** finds the Benders' auxiliary variable for a given sub-SCIP. If probnumber is -1, then the master auxiliary variable
    843 * is returned.
    844 */
    845static
    847 SCIP* scip, /**< SCIP data structure, the target scip */
    848 SCIP_BENDERS* benders, /**< the Benders' decomposition that the variable belongs to */
    849 SCIP_VAR** targetvar, /**< the variable that will be returned */
    850 int subscipdepth, /**< the depth of the current sub-SCIP */
    851 int probnumber /**< the number of the subproblem, or -1 for the master auxiliary variable */
    852 )
    853{
    854 char varname[SCIP_MAXSTRLEN]; /* the name of the auxiliary variable */
    855 char prefix[SCIP_MAXSTRLEN];
    856 char tmpprefix[SCIP_MAXSTRLEN];
    857 int len = 1;
    858 int i;
    859
    860 i = 0;
    861 (*targetvar) = NULL;
    862
    863 /* the prefix for the variable names is required for UG, since we don't know how many copies have been made. To
    864 * find the target variable, we start with an empty prefix. Then t_ is prepended until the target variable is
    865 * found
    866 */
    867 prefix[0] = '\0';
    868 while( i <= subscipdepth )
    869 {
    870 /* when probnumber == -1, we are searching for the master auxiliary variable. Otherwise, we are searching for the
    871 * subproblem auxiliary variable.
    872 */
    873 if( probnumber == -1 )
    874 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%smaster_%s_%s", prefix, AUXILIARYVAR_NAME, SCIPbendersGetName(benders));
    875 else
    876 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s%s_%d_%s", prefix, AUXILIARYVAR_NAME, probnumber, SCIPbendersGetName(benders));
    877
    878 /* finding the variable in the copied problem that has the same name as the auxiliary variable */
    879 (*targetvar) = SCIPfindVar(scip, varname);
    880
    881 /* if the target variable is found, then we can exit the method */
    882 if( (*targetvar) != NULL )
    883 return;
    884
    885 (void) SCIPsnprintf(tmpprefix, len, "t_%s", prefix);
    886 len += 2;
    887 (void) strncpy(prefix, tmpprefix, len); /*lint !e732*/
    888
    889 i++;
    890 }
    891}
    892
    893/** assigns the copied auxiliary variables in the target SCIP to the target Benders' decomposition data */
    894static
    896 SCIP* scip, /**< SCIP data structure, the target scip */
    897 SCIP_BENDERS* benders /**< Benders' decomposition */
    898 )
    899{
    900 SCIP_BENDERS* topbenders; /* the highest priority Benders' decomposition */
    901 SCIP_VAR* targetvar;
    902 SCIP_VARDATA* vardata;
    903 SCIP_Bool shareauxvars;
    904 int subscipdepth;
    905 int i;
    906
    907 assert(scip != NULL);
    908 assert(benders != NULL);
    909
    910 /* this is a workaround for GCG. GCG expects that the variable has vardata when added. So a dummy vardata is created */
    911 SCIP_CALL( SCIPallocBlockMemory(scip, &vardata) );
    912 vardata->vartype = -1;
    913
    914 /* getting the highest priority Benders' decomposition */
    915 topbenders = SCIPgetBenders(scip)[0];
    916
    917 /* if the auxiliary variable are shared, then the variable name will have a suffix of the highest priority Benders'
    918 * name. So the shareauxvars flag indicates how to search for the auxiliary variables */
    919 shareauxvars = FALSE;
    920 if( topbenders != benders && SCIPbendersShareAuxVars(benders) )
    921 shareauxvars = TRUE;
    922
    923 subscipdepth = SCIPgetSubscipDepth(scip);
    924
    925 /* storing the master auxiliary variable in the target Benders' implementation */
    926 findAuxiliaryVar(scip, shareauxvars ? topbenders : benders, &targetvar, subscipdepth, -1);
    927
    928 if( targetvar != NULL )
    929 {
    930 SCIPvarSetData(targetvar, vardata);
    931
    932 benders->masterauxvar = SCIPvarGetTransVar(targetvar);
    933
    935 }
    936 else
    937 benders->masterauxvar = NULL;
    938
    939 /* storing the auxiliary variable in the target Benders' implementation */
    940 for( i = 0; i < SCIPbendersGetNSubproblems(benders); i++ )
    941 {
    942 findAuxiliaryVar(scip, shareauxvars ? topbenders : benders, &targetvar, subscipdepth, i);
    943
    944 if( targetvar != NULL )
    945 {
    946 SCIPvarSetData(targetvar, vardata);
    947
    948 benders->auxiliaryvars[i] = SCIPvarGetTransVar(targetvar);
    949
    950 SCIP_CALL( SCIPcaptureVar(scip, benders->auxiliaryvars[i]) );
    951 }
    952 else
    953 {
    954 SCIPABORT();
    955 }
    956 }
    957
    958 SCIPfreeBlockMemory(scip, &vardata);
    959
    960 return SCIP_OKAY;
    961}
    962
    963/** sets the subproblem objective value array to -infinity */
    964static
    966 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    967 SCIP_SET* set /**< global SCIP settings */
    968 )
    969{
    970 SCIP* subproblem;
    971 SCIP_Real inf;
    972 int nsubproblems;
    973 int i;
    974
    975 assert(benders != NULL);
    976
    977 nsubproblems = SCIPbendersGetNSubproblems(benders);
    978
    979 for( i = 0; i < nsubproblems; i++ )
    980 {
    981 subproblem = SCIPbendersSubproblem(benders, i);
    982 if( subproblem != NULL )
    983 inf = SCIPinfinity(subproblem);
    984 else
    985 inf = SCIPsetInfinity(set);
    986
    987 SCIPbendersSetSubproblemObjval(benders, i, inf);
    988 }
    989}
    991/** compares two Benders' decompositions w. r. to their priority */
    992SCIP_DECL_SORTPTRCOMP(SCIPbendersComp)
    993{ /*lint --e{715}*/
    994 return ((SCIP_BENDERS*)elem2)->priority - ((SCIP_BENDERS*)elem1)->priority;
    995}
    997/** comparison method for sorting Benders' decompositions w.r.t. to their name */
    998SCIP_DECL_SORTPTRCOMP(SCIPbendersCompName)
    999{
    1000 return strcmp(SCIPbendersGetName((SCIP_BENDERS*)elem1), SCIPbendersGetName((SCIP_BENDERS*)elem2));
    1001}
    1002
    1003/** method to call, when the priority of a Benders' decomposition was changed */
    1004static
    1005SCIP_DECL_PARAMCHGD(paramChgdBendersPriority)
    1006{ /*lint --e{715}*/
    1007 SCIP_PARAMDATA* paramdata;
    1008
    1009 paramdata = SCIPparamGetData(param);
    1010 assert(paramdata != NULL);
    1011
    1012 /* use SCIPsetBendersPriority() to mark the Benders' decompositions as unsorted */
    1013 SCIPsetBendersPriority(scip, (SCIP_BENDERS*)paramdata, SCIPparamGetInt(param)); /*lint !e740*/
    1014
    1015 return SCIP_OKAY;
    1016}
    1017
    1018/** creates a variable mapping between the master problem variables of the source scip and the sub scip */
    1019static
    1021 SCIP_BENDERS* benders, /**< Benders' decomposition of the target SCIP instance */
    1022 SCIP_SET* sourceset, /**< global SCIP settings from the source SCIP */
    1023 SCIP_HASHMAP* varmap /**< a hashmap to store the mapping of source variables corresponding
    1024 * target variables; must not be NULL */
    1025 )
    1026{
    1027 SCIP_VAR** vars;
    1028 SCIP_VAR* targetvar;
    1029 int nvars;
    1030 int i;
    1031
    1032 assert(benders != NULL);
    1033 assert(sourceset != NULL);
    1034 assert(benders->iscopy);
    1035 assert(benders->mastervarsmap == NULL);
    1036
    1037 /* getting the master problem variable data */
    1038 vars = SCIPgetVars(sourceset->scip);
    1039 nvars = SCIPgetNVars(sourceset->scip);
    1040
    1041 /* creating the hashmap for the mapping between the master variable of the target and source scip */
    1042 SCIP_CALL( SCIPhashmapCreate(&benders->mastervarsmap, SCIPblkmem(sourceset->scip), nvars) );
    1043
    1044 for( i = 0; i < nvars; i++ )
    1045 {
    1046 /* getting the variable pointer for the target SCIP variables. The variable mapping returns the target SCIP
    1047 * varibale for a given source SCIP variable. */
    1048 targetvar = (SCIP_VAR*) SCIPhashmapGetImage(varmap, vars[i]);
    1049 if( targetvar != NULL )
    1050 {
    1051 SCIP_CALL( SCIPhashmapInsert(benders->mastervarsmap, targetvar, vars[i]) );
    1052 SCIP_CALL( SCIPcaptureVar(sourceset->scip, vars[i]) );
    1053 }
    1054 }
    1055
    1056 return SCIP_OKAY;
    1057}
    1059/** copies the given Benders' decomposition to a new SCIP */
    1061 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1062 SCIP_SET* sourceset, /**< SCIP_SET of SCIP to copy from */
    1063 SCIP_SET* targetset, /**< SCIP_SET of SCIP to copy to */
    1064 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding
    1065 * target variables; if NULL, then the transfer of cuts is not possible */
    1066 SCIP_Bool threadsafe, /**< must the Benders' decomposition copy be thread safe */
    1067 SCIP_Bool* valid /**< was the copying process valid? */
    1068 )
    1069{
    1070 SCIP_BENDERS* targetbenders; /* the copy of the Benders' decomposition struct in the target set */
    1071 int i;
    1072
    1073 assert(benders != NULL);
    1074 assert(targetset != NULL);
    1075 assert(valid != NULL);
    1076 assert(targetset->scip != NULL);
    1077
    1078 (*valid) = FALSE;
    1079
    1080 if( benders->benderscopy != NULL && targetset->benders_copybenders && SCIPbendersIsActive(benders) )
    1081 {
    1082 SCIPsetDebugMsg(targetset, "including Benders' decomposition %s in subscip %p\n", SCIPbendersGetName(benders), (void*)targetset->scip);
    1083 SCIP_CALL( benders->benderscopy(targetset->scip, benders, threadsafe) );
    1084
    1085 /* copying the Benders' cuts */
    1086 targetbenders = SCIPsetFindBenders(targetset, SCIPbendersGetName(benders));
    1087
    1088 /* storing the pointer to the source scip instance */
    1089 targetbenders->sourcescip = sourceset->scip;
    1090
    1091 /* the flag is set to indicate that the Benders' decomposition is a copy */
    1092 targetbenders->iscopy = TRUE;
    1093
    1094 /* storing whether the lnscheck should be performed */
    1095 targetbenders->lnscheck = benders->lnscheck;
    1096 targetbenders->lnsmaxdepth = benders->lnsmaxdepth;
    1097 targetbenders->lnsmaxcalls = benders->lnsmaxcalls;
    1098 targetbenders->lnsmaxcallsroot = benders->lnsmaxcallsroot;
    1099
    1100 /* storing whether the Benders' copy required thread safety */
    1101 targetbenders->threadsafe = threadsafe;
    1102
    1103 /* calling the copy method for the Benders' cuts */
    1105 for( i = 0; i < benders->nbenderscuts; i++ )
    1106 {
    1107 SCIP_CALL( SCIPbenderscutCopyInclude(targetbenders, benders->benderscuts[i], targetset) );
    1108 }
    1109
    1110 /* When the Benders' decomposition is copied then a variable mapping between the master problem variables is
    1111 * required. This variable mapping is used to transfer the cuts generated in the target SCIP to the source SCIP.
    1112 * The variable map is stored in the target Benders' decomposition. This will be freed when the sub-SCIP is freed.
    1113 */
    1114 if( varmap != NULL )
    1115 {
    1116 SCIP_CALL( createMasterVarMapping(targetbenders, sourceset, varmap) );
    1117 }
    1118
    1119 assert((varmap != NULL && targetbenders->mastervarsmap != NULL)
    1120 || (varmap == NULL && targetbenders->mastervarsmap == NULL));
    1121 }
    1122
    1123 /* if the Benders' decomposition is active, then copy is not valid. */
    1124 (*valid) = !SCIPbendersIsActive(benders);
    1125
    1126 return SCIP_OKAY;
    1127}
    1128
    1129/** internal method for creating a Benders' decomposition structure */
    1130static
    1132 SCIP_BENDERS** benders, /**< pointer to Benders' decomposition data structure */
    1133 SCIP_SET* set, /**< global SCIP settings */
    1134 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
    1135 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */
    1136 const char* name, /**< name of Benders' decomposition */
    1137 const char* desc, /**< description of Benders' decomposition */
    1138 int priority, /**< priority of the Benders' decomposition */
    1139 SCIP_Bool cutlp, /**< should Benders' cuts be generated for LP solutions */
    1140 SCIP_Bool cutpseudo, /**< should Benders' cuts be generated for pseudo solutions */
    1141 SCIP_Bool cutrelax, /**< should Benders' cuts be generated for relaxation solutions */
    1142 SCIP_Bool shareauxvars, /**< should this Benders' use the highest priority Benders aux vars */
    1143 SCIP_DECL_BENDERSCOPY ((*benderscopy)), /**< copy method of Benders' decomposition or NULL if you don't want to copy your plugin into sub-SCIPs */
    1144 SCIP_DECL_BENDERSFREE ((*bendersfree)), /**< destructor of Benders' decomposition */
    1145 SCIP_DECL_BENDERSINIT ((*bendersinit)), /**< initialize Benders' decomposition */
    1146 SCIP_DECL_BENDERSEXIT ((*bendersexit)), /**< deinitialize Benders' decomposition */
    1147 SCIP_DECL_BENDERSINITPRE((*bendersinitpre)),/**< presolving initialization method for Benders' decomposition */
    1148 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)),/**< presolving deinitialization method for Benders' decomposition */
    1149 SCIP_DECL_BENDERSINITSOL((*bendersinitsol)),/**< solving process initialization method of Benders' decomposition */
    1150 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)),/**< solving process deinitialization method of Benders' decomposition */
    1151 SCIP_DECL_BENDERSGETVAR((*bendersgetvar)),/**< returns the master variable for a given subproblem variable */
    1152 SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)),/**< creates a Benders' decomposition subproblem */
    1153 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)),/**< called prior to the subproblem solving loop */
    1154 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)),/**< the solving method for convex Benders' decomposition subproblems */
    1155 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)),/**< the solving method for the Benders' decomposition subproblems */
    1156 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)),/**< called after the subproblems are solved. */
    1157 SCIP_DECL_BENDERSFREESUB((*bendersfreesub)),/**< the freeing method for the Benders' decomposition subproblems */
    1158 SCIP_BENDERSDATA* bendersdata /**< Benders' decomposition data */
    1159 )
    1160{
    1162 char paramdesc[SCIP_MAXSTRLEN];
    1163
    1164 assert(benders != NULL);
    1165 assert(name != NULL);
    1166 assert(desc != NULL);
    1167
    1168 /* Checking whether the benderssolvesub and the bendersfreesub are both implemented or both are not implemented */
    1169 if( (benderssolvesubconvex == NULL && benderssolvesub == NULL && bendersfreesub != NULL)
    1170 || ((benderssolvesubconvex != NULL || benderssolvesub != NULL) && bendersfreesub == NULL) )
    1171 {
    1172 SCIPerrorMessage("Benders' decomposition <%s> requires that if bendersFreesub%s is implemented, then at least "
    1173 "one of bendersSolvesubconvex%s or bendersSolvesub%s are implemented.\n", name, name, name, name);
    1174 return SCIP_INVALIDCALL;
    1175 }
    1176
    1177 SCIP_ALLOC( BMSallocMemory(benders) );
    1178 BMSclearMemory(*benders);
    1179 SCIP_ALLOC( BMSduplicateMemoryArray(&(*benders)->name, name, strlen(name)+1) );
    1180 SCIP_ALLOC( BMSduplicateMemoryArray(&(*benders)->desc, desc, strlen(desc)+1) );
    1181 (*benders)->priority = priority;
    1182 (*benders)->cutlp = cutlp;
    1183 (*benders)->cutpseudo = cutpseudo;
    1184 (*benders)->cutrelax = cutrelax;
    1185 (*benders)->shareauxvars = shareauxvars;
    1186 (*benders)->benderscopy = benderscopy;
    1187 (*benders)->bendersfree = bendersfree;
    1188 (*benders)->bendersinit = bendersinit;
    1189 (*benders)->bendersexit = bendersexit;
    1190 (*benders)->bendersinitpre = bendersinitpre;
    1191 (*benders)->bendersexitpre = bendersexitpre;
    1192 (*benders)->bendersinitsol = bendersinitsol;
    1193 (*benders)->bendersexitsol = bendersexitsol;
    1194 (*benders)->bendersgetvar = bendersgetvar;
    1195 (*benders)->benderscreatesub = benderscreatesub;
    1196 (*benders)->benderspresubsolve = benderspresubsolve;
    1197 (*benders)->benderssolvesubconvex = benderssolvesubconvex;
    1198 (*benders)->benderssolvesub = benderssolvesub;
    1199 (*benders)->benderspostsolve = benderspostsolve;
    1200 (*benders)->bendersfreesub = bendersfreesub;
    1201 (*benders)->objectivetype = SCIP_BENDERSOBJTYPE_SUM;
    1202 (*benders)->bendersdata = bendersdata;
    1203 SCIP_CALL( SCIPclockCreate(&(*benders)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
    1204 SCIP_CALL( SCIPclockCreate(&(*benders)->bendersclock, SCIP_CLOCKTYPE_DEFAULT) );
    1205 (*benders)->nlpparam = SCIP_NLPPARAM_DEFAULT(set->scip); /*lint !e446*/
    1206
    1207 /* add parameters */
    1208 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/priority", name);
    1209 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of Benders' decomposition <%s>", name);
    1210 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
    1211 &(*benders)->priority, FALSE, priority, INT_MIN/4, INT_MAX/4,
    1212 paramChgdBendersPriority, (SCIP_PARAMDATA*)(*benders)) ); /*lint !e740*/
    1213
    1214 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutlp", name);
    1215 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1216 "should Benders' cuts be generated for LP solutions?", &(*benders)->cutlp, FALSE, cutlp, NULL, NULL) ); /*lint !e740*/
    1217
    1218 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutpseudo", name);
    1219 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1220 "should Benders' cuts be generated for pseudo solutions?", &(*benders)->cutpseudo, FALSE, cutpseudo, NULL, NULL) ); /*lint !e740*/
    1221
    1222 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutrelax", name);
    1223 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1224 "should Benders' cuts be generated for relaxation solutions?", &(*benders)->cutrelax, FALSE, cutrelax, NULL, NULL) ); /*lint !e740*/
    1225
    1226 /* These parameters are left for the user to decide in a settings file. This departs from the usual SCIP convention
    1227 * where the settings available at the creation of the plugin can be set in the function call.
    1228 */
    1229 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/transfercuts", name);
    1230 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1231 "should Benders' cuts from LNS heuristics be transferred to the main SCIP instance?", &(*benders)->transfercuts,
    1232 FALSE, SCIP_DEFAULT_TRANSFERCUTS, NULL, NULL) ); /*lint !e740*/
    1233
    1234 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnscheck", name);
    1235 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1236 "should Benders' decomposition be used in LNS heurisics?", &(*benders)->lnscheck, FALSE, SCIP_DEFAULT_LNSCHECK,
    1237 NULL, NULL) ); /*lint !e740*/
    1238
    1239 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnsmaxdepth", name);
    1240 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
    1241 "maximum depth at which the LNS check is performed (-1: no limit)", &(*benders)->lnsmaxdepth, TRUE,
    1243
    1244 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnsmaxcalls", name);
    1245 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
    1246 "the maximum number of Benders' decomposition calls in LNS heuristics (-1: no limit)", &(*benders)->lnsmaxcalls,
    1247 TRUE, SCIP_DEFAULT_LNSMAXCALLS, -1, INT_MAX, NULL, NULL) );
    1248
    1249 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnsmaxcallsroot", name);
    1250 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
    1251 "the maximum number of root node Benders' decomposition calls in LNS heuristics (-1: no limit)",
    1252 &(*benders)->lnsmaxcallsroot, TRUE, SCIP_DEFAULT_LNSMAXCALLSROOT, -1, INT_MAX, NULL, NULL) );
    1253
    1254 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutsasconss", name);
    1255 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1256 "should the transferred cuts be added as constraints?", &(*benders)->cutsasconss, FALSE,
    1257 SCIP_DEFAULT_CUTSASCONSS, NULL, NULL) ); /*lint !e740*/
    1258
    1259 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/subprobfrac", name);
    1260 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
    1261 "fraction of subproblems that are solved in each iteration", &(*benders)->subprobfrac, FALSE,
    1262 SCIP_DEFAULT_SUBPROBFRAC, 0.0, 1.0, NULL, NULL) ); /*lint !e740*/
    1263
    1264 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/updateauxvarbound", name);
    1265 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1266 "should the auxiliary variable bound be updated by solving the subproblem?", &(*benders)->updateauxvarbound,
    1267 FALSE, SCIP_DEFAULT_UPDATEAUXVARBOUND, NULL, NULL) ); /*lint !e740*/
    1268
    1269 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/auxvarsimplint", name);
    1270 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1271 "if the subproblem objective is integer, then define the auxiliary variables as implicit integers?",
    1272 &(*benders)->auxvarsimplint, FALSE, SCIP_DEFAULT_AUXVARSIMPLINT, NULL, NULL) ); /*lint !e740*/
    1273
    1274 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutcheck", name);
    1275 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1276 "should Benders' cuts be generated while checking solutions?",
    1277 &(*benders)->cutcheck, FALSE, SCIP_DEFAULT_CUTCHECK, NULL, NULL) ); /*lint !e740*/
    1278
    1279 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutstrengthenmult", name);
    1280 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
    1281 "the convex combination multiplier for the cut strengthening", &(*benders)->convexmult, FALSE,
    1282 SCIP_DEFAULT_STRENGTHENMULT, 0.0, 1.0, NULL, NULL) ); /*lint !e740*/
    1283
    1284 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/noimprovelimit", name);
    1285 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
    1286 "the maximum number of cut strengthening without improvement", &(*benders)->noimprovelimit, TRUE,
    1287 SCIP_DEFAULT_NOIMPROVELIMIT, 0, INT_MAX, NULL, NULL) );
    1288
    1289 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/corepointperturb", name);
    1290 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
    1291 "the constant use to perturb the cut strengthening core point", &(*benders)->perturbeps, FALSE,
    1292 SCIP_DEFAULT_STRENGTHENPERTURB, 0.0, 1.0, NULL, NULL) ); /*lint !e740*/
    1293
    1294 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutstrengthenenabled", name);
    1295 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1296 "should the core point cut strengthening be employed (only applied to fractional solutions or continuous subproblems)?",
    1297 &(*benders)->strengthenenabled, FALSE, SCIP_DEFAULT_STRENGTHENENABLED, NULL, NULL) ); /*lint !e740*/
    1298
    1299 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutstrengthenintpoint", name);
    1300 SCIP_CALL( SCIPsetAddCharParam(set, messagehdlr, blkmem, paramname,
    1301 "where should the strengthening interior point be sourced from ('l'p relaxation, 'f'irst solution, 'i'ncumbent solution, 'r'elative interior point, vector of 'o'nes, vector of 'z'eros)",
    1302 &(*benders)->strengthenintpoint, FALSE, SCIP_DEFAULT_STRENGTHENINTPOINT, "lfiroz", NULL, NULL) ); /*lint !e740*/
    1303
    1304#ifdef SCIP_DISABLED_CODE /* temporarily disabling support for multiple threads in Benders' decomposition */
    1305 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/numthreads", name);
    1306 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
    1307 "the number of threads to use when solving the subproblems", &(*benders)->numthreads, TRUE,
    1308 SCIP_DEFAULT_NUMTHREADS, 1, INT_MAX, NULL, NULL) );
    1309#endif
    1310
    1311 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/execfeasphase", name);
    1312 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1313 "should a feasibility phase be executed during the root node, i.e. adding slack variables to constraints to ensure feasibility",
    1314 &(*benders)->execfeasphase, FALSE, SCIP_DEFAULT_EXECFEASPHASE, NULL, NULL) ); /*lint !e740*/
    1315
    1316 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/slackvarcoef", name);
    1317 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
    1318 "the initial objective coefficient of the slack variables in the subproblem", &(*benders)->slackvarcoef, FALSE,
    1319 SCIP_DEFAULT_SLACKVARCOEF, 0.0, SCIPsetInfinity(set), NULL, NULL) ); /*lint !e740*/
    1320
    1321 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/maxslackvarcoef", name);
    1322 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
    1323 "the maximal objective coefficient of the slack variables in the subproblem", &(*benders)->maxslackvarcoef, FALSE,
    1324 SCIP_DEFAULT_MAXSLACKVARCOEF, 0.0, SCIPsetInfinity(set), NULL, NULL) ); /*lint !e740*/
    1325
    1326 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/checkconsconvexity", name);
    1327 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
    1328 "should the constraints of the subproblems be checked for convexity?", &(*benders)->checkconsconvexity, FALSE,
    1329 SCIP_DEFAULT_CHECKCONSCONVEXITY, NULL, NULL) ); /*lint !e740*/
    1330
    1331 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/nlpiterlimit", name);
    1332 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
    1333 "iteration limit for NLP solver", &(*benders)->nlpparam.iterlimit, FALSE,
    1334 SCIP_DEFAULT_NLPITERLIMIT, 0, INT_MAX, NULL, NULL) ); /*lint !e740*/
    1335
    1336 return SCIP_OKAY;
    1337}
    1338
    1339/** creates a Benders' decomposition structure
    1340 *
    1341 * To use the Benders' decomposition for solving a problem, it first has to be activated with a call to SCIPactivateBenders().
    1342 */
    1344 SCIP_BENDERS** benders, /**< pointer to Benders' decomposition data structure */
    1345 SCIP_SET* set, /**< global SCIP settings */
    1346 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
    1347 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */
    1348 const char* name, /**< name of Benders' decomposition */
    1349 const char* desc, /**< description of Benders' decomposition */
    1350 int priority, /**< priority of the Benders' decomposition */
    1351 SCIP_Bool cutlp, /**< should Benders' cuts be generated for LP solutions */
    1352 SCIP_Bool cutpseudo, /**< should Benders' cuts be generated for pseudo solutions */
    1353 SCIP_Bool cutrelax, /**< should Benders' cuts be generated for relaxation solutions */
    1354 SCIP_Bool shareauxvars, /**< should this Benders' use the highest priority Benders aux vars */
    1355 SCIP_DECL_BENDERSCOPY ((*benderscopy)), /**< copy method of Benders' decomposition or NULL if you don't want to copy your plugin into sub-SCIPs */
    1356 SCIP_DECL_BENDERSFREE ((*bendersfree)), /**< destructor of Benders' decomposition */
    1357 SCIP_DECL_BENDERSINIT ((*bendersinit)), /**< initialize Benders' decomposition */
    1358 SCIP_DECL_BENDERSEXIT ((*bendersexit)), /**< deinitialize Benders' decomposition */
    1359 SCIP_DECL_BENDERSINITPRE((*bendersinitpre)),/**< presolving initialization method for Benders' decomposition */
    1360 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)),/**< presolving deinitialization method for Benders' decomposition */
    1361 SCIP_DECL_BENDERSINITSOL((*bendersinitsol)),/**< solving process initialization method of Benders' decomposition */
    1362 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)),/**< solving process deinitialization method of Benders' decomposition */
    1363 SCIP_DECL_BENDERSGETVAR((*bendersgetvar)),/**< returns the master variable for a given subproblem variable */
    1364 SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)),/**< creates a Benders' decomposition subproblem */
    1365 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)),/**< called prior to the subproblem solving loop */
    1366 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)),/**< the solving method for convex Benders' decomposition subproblems */
    1367 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)),/**< the solving method for the Benders' decomposition subproblems */
    1368 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)),/**< called after the subproblems are solved. */
    1369 SCIP_DECL_BENDERSFREESUB((*bendersfreesub)),/**< the freeing method for the Benders' decomposition subproblems */
    1370 SCIP_BENDERSDATA* bendersdata /**< Benders' decomposition data */
    1371 )
    1372{
    1373 assert(benders != NULL);
    1374 assert(name != NULL);
    1375 assert(desc != NULL);
    1376
    1377 SCIP_CALL_FINALLY( doBendersCreate(benders, set, messagehdlr, blkmem, name, desc, priority, cutlp, cutpseudo,
    1378 cutrelax, shareauxvars, benderscopy, bendersfree, bendersinit, bendersexit, bendersinitpre, bendersexitpre,
    1379 bendersinitsol, bendersexitsol, bendersgetvar, benderscreatesub, benderspresubsolve, benderssolvesubconvex,
    1380 benderssolvesub, benderspostsolve, bendersfreesub, bendersdata), (void) SCIPbendersFree(benders, set) );
    1381
    1382 return SCIP_OKAY;
    1383}
    1384
    1385
    1386/** releases the variables that have been captured in the hashmap */
    1387static
    1389 SCIP* scip, /**< the SCIP data structure */
    1390 SCIP_BENDERS* benders /**< Benders' decomposition */
    1391 )
    1392{
    1393 int nentries;
    1394 int i;
    1395
    1396 assert(scip != NULL);
    1397 assert(benders != NULL);
    1398
    1399 assert(benders->mastervarsmap != NULL);
    1400
    1401 nentries = SCIPhashmapGetNEntries(benders->mastervarsmap);
    1402
    1403 for( i = 0; i < nentries; ++i )
    1404 {
    1405 SCIP_HASHMAPENTRY* entry;
    1406 entry = SCIPhashmapGetEntry(benders->mastervarsmap, i);
    1407
    1408 if( entry != NULL )
    1409 {
    1410 SCIP_VAR* var;
    1411 var = (SCIP_VAR*) SCIPhashmapEntryGetImage(entry);
    1412
    1413 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    1414 }
    1415 }
    1416
    1417 return SCIP_OKAY;
    1418}
    1419
    1421/** calls destructor and frees memory of Benders' decomposition */
    1423 SCIP_BENDERS** benders, /**< pointer to Benders' decomposition data structure */
    1424 SCIP_SET* set /**< global SCIP settings */
    1425 )
    1426{
    1427 int i;
    1428
    1429 assert(benders != NULL);
    1430 assert(*benders != NULL);
    1431 assert(!(*benders)->initialized);
    1432 assert(set != NULL);
    1433
    1434 /* call destructor of Benders' decomposition */
    1435 if( (*benders)->bendersfree != NULL )
    1436 {
    1437 SCIP_CALL( (*benders)->bendersfree(set->scip, *benders) );
    1438 }
    1439
    1440 /* if the Benders' decomposition is a copy and a varmap has been passed to SCIP_BENDERS, then the variable map
    1441 * between the source and the target SCIP needs to be freed.
    1442 */
    1443 if( (*benders)->iscopy && (*benders)->mastervarsmap != NULL )
    1444 {
    1445 SCIP_CALL( releaseVarMappingHashmapVars((*benders)->sourcescip, (*benders)) );
    1446 SCIPhashmapFree(&(*benders)->mastervarsmap);
    1447 }
    1448
    1449 /* freeing the Benders' cuts */
    1450 for( i = 0; i < (*benders)->nbenderscuts; i++ )
    1451 {
    1452 SCIP_CALL( SCIPbenderscutFree(&((*benders)->benderscuts[i]), set) );
    1453 }
    1454 BMSfreeMemoryArrayNull(&(*benders)->benderscuts);
    1455
    1456 SCIPclockFree(&(*benders)->bendersclock);
    1457 SCIPclockFree(&(*benders)->setuptime);
    1458 BMSfreeMemoryArray(&(*benders)->name);
    1459 BMSfreeMemoryArray(&(*benders)->desc);
    1460 BMSfreeMemory(benders);
    1461
    1462 return SCIP_OKAY;
    1463}
    1465static
    1467 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1468 SCIP_SET* set, /**< global SCIP settings */
    1469 SCIP_VAR* var, /**< the variable to be added to the store */
    1470 int probnumber /**< the subproblem number */
    1471 )
    1472{
    1473 assert(benders != NULL);
    1474 assert(set != NULL);
    1475 assert(var != NULL);
    1476 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1477
    1478 /* if the number of stored variables equals the size, then we need to extend the storage */
    1479 if( benders->submastervarssize[probnumber] < benders->nsubmastervars[probnumber] + 1 )
    1480 {
    1481 int newsize;
    1482
    1483 newsize = SCIPsetCalcMemGrowSize(set, benders->nsubmastervars[probnumber] + 1);
    1484 SCIP_ALLOC( BMSreallocBlockMemoryArray(SCIPblkmem(set->scip), &benders->submastervars[probnumber],
    1485 benders->submastervarssize[probnumber], newsize) );
    1486
    1487 benders->submastervarssize[probnumber] = newsize;
    1488 }
    1489
    1490 benders->submastervars[probnumber][benders->nsubmastervars[probnumber]] = var;
    1491 benders->nsubmastervars[probnumber]++;
    1492
    1493 /* capturing the variable, so that it is not released before */
    1494
    1495 /* getting the variable type and updating the statistics */
    1497 benders->nsubmasterbinvars[probnumber]++;
    1498 else if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
    1499 benders->nsubmasterintvars[probnumber]++;
    1500
    1501 return SCIP_OKAY;
    1502}
    1504static
    1506 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1507 SCIP_SET* set, /**< global SCIP settings */
    1508 int probnumber /**< the subproblem number */
    1509 )
    1510{
    1511 SCIP* subproblem;
    1512 SCIP_VAR** vars;
    1513 SCIP_VAR* mastervar;
    1514 int nvars;
    1515 int i;
    1516
    1517 assert(benders != NULL);
    1518 assert(set != NULL);
    1519 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1520
    1521 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1522
    1523 /* getting the variables of the subproblem to store the master problem variables */
    1524 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
    1525
    1526 for( i = 0; i < nvars; i++ )
    1527 {
    1528 /* retrieving the master problem variable */
    1529 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
    1530
    1531 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
    1532 if( mastervar != NULL )
    1533 {
    1534 SCIP_CALL( storeSubproblemMasterVar(benders, set, mastervar, probnumber) );
    1535 }
    1536 }
    1537
    1538 return SCIP_OKAY;
    1539}
    1540
    1541/* adds a slack variable to the given constraint */
    1542static
    1544 SCIP* scip, /**< the SCIP data structure */
    1545 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1546 SCIP_CONS* cons, /**< constraint to which the slack variable(s) is added to */
    1547 SCIP_CONSHDLR** linearconshdlrs, /**< an array storing the linear constraint handlers */
    1548 SCIP_CONSHDLR* nlconshdlr, /**< pointer to the nonlinear constraint handler */
    1549 int nlinearconshdlrs /**< the number of linear constraint handlers */
    1550 )
    1551{
    1552 SCIP_CONSHDLR* conshdlr;
    1553 SCIP_VAR* var;
    1554 SCIP_Real rhs;
    1555 SCIP_Real lhs;
    1556 SCIP_Real objcoef;
    1557 int i;
    1558 SCIP_Bool linearcons;
    1559 SCIP_Bool success;
    1560 char name[SCIP_MAXSTRLEN];
    1561
    1562 conshdlr = SCIPconsGetHdlr(cons);
    1563
    1564 /* assume that the constraint is not linear, then we check whether it is linear */
    1565 linearcons = FALSE;
    1566
    1567 /* checking whether the constraint is a linear constraint. If so, we add a coefficient to the constraint */
    1568 for( i = 0; i < nlinearconshdlrs; ++i )
    1569 {
    1570 if( conshdlr == linearconshdlrs[i] )
    1571 {
    1572 linearcons = TRUE;
    1573 break;
    1574 }
    1575 }
    1576
    1577 if( !linearcons && conshdlr != nlconshdlr )
    1578 {
    1579 SCIPwarningMessage(scip, "The subproblem includes constraint <%s>. "
    1580 "This is not supported and the slack variable will not be added to the constraint. Feasibility cuts may be invalid.\n",
    1581 SCIPconshdlrGetName(conshdlr));
    1582 }
    1583
    1584 if( linearcons )
    1585 {
    1586 rhs = SCIPconsGetRhs(scip, cons, &success);
    1587 assert(success);
    1588 lhs = SCIPconsGetLhs(scip, cons, &success);
    1589 assert(success);
    1590 }
    1591 else
    1592 {
    1593 rhs = SCIPgetRhsNonlinear(cons);
    1594 lhs = SCIPgetLhsNonlinear(cons);
    1595 }
    1596
    1597 /* getting the objective coefficient for the slack variables */
    1598 objcoef = benders->slackvarcoef;
    1599
    1600 /* if the right hand side is finite, then we need to add a slack variable with a negative coefficient */
    1601 if( !SCIPisInfinity(scip, rhs) )
    1602 {
    1603 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_neg", SLACKVAR_NAME, SCIPconsGetName(cons) );
    1604
    1606
    1607 /* adding the slack variable to the subproblem */
    1608 SCIP_CALL( SCIPaddVar(scip, var) );
    1609
    1610 /* adds the slack variable to the constraint */
    1611 if( linearcons )
    1612 {
    1613 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, -1.0) );
    1614 }
    1615 else
    1616 {
    1617 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, var, -1.0) );
    1618 }
    1619
    1620 /* releasing the variable */
    1621 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    1622 }
    1623
    1624 /* if the left hand side if finite, then we need to add a slack variable with a positive coefficient */
    1625 if( !SCIPisInfinity(scip, -lhs) )
    1626 {
    1627 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_pos", SLACKVAR_NAME, SCIPconsGetName(cons) );
    1628
    1630
    1631 /* adding the slack variable to the subproblem */
    1632 SCIP_CALL( SCIPaddVar(scip, var) );
    1633
    1634 /* adds the slack variable to the constraint */
    1635 if( linearcons )
    1636 {
    1637 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, 1.0) );
    1638 }
    1639 else
    1640 {
    1641 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, var, 1.0) );
    1642 }
    1643
    1644 /* releasing the variable */
    1645 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    1646 }
    1647
    1648 return SCIP_OKAY;
    1649}
    1650
    1651/** adds the slack variables to each of the constraints for the generation of feasibility cuts for the given non-linear
    1652 * subproblem
    1654static
    1656 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1657 SCIP_SET* set, /**< global SCIP settings */
    1658 int probnumber /**< the subproblem number */
    1659 )
    1660{
    1661 SCIP* subproblem;
    1662 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
    1663 SCIP_CONSHDLR* nlconshdlr;
    1664 SCIP_CONS* cons;
    1665 int i;
    1666
    1667 assert(benders != NULL);
    1668 assert(set != NULL);
    1669 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1670
    1671 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1672
    1673 /* get pointers to linear constraints handlers, so can avoid string comparisons */
    1674 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
    1675 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
    1676 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
    1677 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
    1678 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
    1679
    1680 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
    1681
    1682 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
    1683 {
    1684 cons = SCIPgetOrigConss(subproblem)[i];
    1685
    1686 /* adding the slack variables to the constraint */
    1687 SCIP_CALL( addSlackVars(subproblem, benders, cons, linearconshdlrs, nlconshdlr, NLINEARCONSHDLRS) );
    1688 }
    1689
    1690 return SCIP_OKAY;
    1691}
    1692
    1693/** initialises a MIP subproblem by putting the problem into SCIP_STAGE_SOLVING. This is achieved by calling SCIPsolve
    1694 * and then interrupting the solve in a node focus event handler.
    1695 * The LP subproblem is also initialised using this method; however, a different event handler is added. This event
    1696 * handler will put the LP subproblem into probing mode.
    1697 * The MIP solving function is called to initialise the subproblem because this function calls SCIPsolve with the
    1698 * appropriate parameter settings for Benders' decomposition.
    1700static
    1702 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1703 SCIP_SET* set, /**< global SCIP settings */
    1704 int probnumber, /**< the subproblem number */
    1705 SCIP_Bool* infeasible, /**< pointer to store whether the lp is detected as infeasible */
    1706 SCIP_Bool* success /**< was the initialisation process successful */
    1707 )
    1708{
    1709 SCIP* subproblem;
    1710 SCIP_STATUS solvestatus;
    1711
    1712 assert(benders != NULL);
    1713 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1714 assert(success != NULL);
    1715
    1716 (*success) = FALSE;
    1717 (*infeasible) = FALSE;
    1718
    1719 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1720 assert(subproblem != NULL);
    1721
    1722 /* Getting the problem into the right SCIP stage for solving */
    1723 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
    1724
    1725 /* Constructing the LP that can be solved in later iterations */
    1726 if( solvestatus != SCIP_STATUS_BESTSOLLIMIT && solvestatus != SCIP_STATUS_TIMELIMIT
    1727 && solvestatus != SCIP_STATUS_MEMLIMIT )
    1728 {
    1729 assert(SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING);
    1730
    1731 SCIP_CALL( SCIPconstructLP(subproblem, infeasible) );
    1732
    1733 (*success) = !(*infeasible);
    1734 }
    1735
    1736 return SCIP_OKAY;
    1737}
    1738
    1739
    1740/** initialises an LP subproblem by putting the problem into probing mode. The probing mode is invoked in a node focus
    1741 * event handler. This event handler is added just prior to calling the initialise subproblem function.
    1743static
    1745 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1746 SCIP_SET* set, /**< global SCIP settings */
    1747 int probnumber, /**< the subproblem number */
    1748 SCIP_Bool* infeasible /**< pointer to store whether the lp is detected as infeasible */
    1749 )
    1750{
    1751 SCIP* subproblem;
    1752 SCIP_EVENTHDLR* eventhdlr;
    1753 SCIP_EVENTHDLRDATA* eventhdlrdata;
    1754 SCIP_Bool success;
    1755
    1756 assert(benders != NULL);
    1757 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1758 assert(infeasible != NULL);
    1759
    1760 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1761 assert(subproblem != NULL);
    1762
    1763 /* include event handler into SCIP */
    1764 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata) );
    1765
    1766 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata) );
    1767
    1769 eventExecBendersNodefocus, eventhdlrdata) );
    1770 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersNodefocus) );
    1771 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersNodefocus) );
    1772 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersNodefocus) );
    1773 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersNodefocus) );
    1774 assert(eventhdlr != NULL);
    1775
    1776 /* calling an initial solve to put the problem into probing mode */
    1777 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
    1778
    1779 return SCIP_OKAY; /*lint !e438*/
    1780}
    1781
    1782/** checks whether the convex relaxation of the subproblem is sufficient to solve the original problem to optimality
    1783 *
    1784 * We check whether we can conclude that the CIP is actually an LP or a convex NLP.
    1785 * To do this, we check that all variables are of continuous type and that every constraint is either handled by known
    1786 * linear constraint handler (knapsack, linear, logicor, setppc, varbound) or the nonlinear constraint handler.
    1787 * In the latter case, we also check whether the nonlinear constraint is convex.
    1788 * Further, nonlinear constraints are only considered if an NLP solver interface is available, i.e., and NLP could
    1789 * be solved.
    1790 * If constraints are present that cannot be identified as linear or convex nonlinear, then we assume that the
    1791 * problem is not convex, thus solving its LP or NLP relaxation will not be sufficient.
    1793static
    1795 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1796 SCIP_SET* set, /**< global SCIP settings */
    1797 int probnumber /**< the subproblem number, or -1 for the master problem */
    1798 )
    1799{
    1800 SCIP* subproblem;
    1801 SCIP_CONSHDLR* conshdlr;
    1802 SCIP_CONS* cons;
    1803 SCIP_HASHMAP* assumevarfixed;
    1804 SCIP_VAR** vars;
    1805 int nvars;
    1806 int nbinvars;
    1807 int nintvars;
    1808 int nimplintvars;
    1809 int i;
    1810 int j;
    1811 SCIP_Bool convexcons;
    1812 SCIP_Bool discretevar;
    1813 SCIP_Bool isnonlinear;
    1814 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
    1815 SCIP_CONSHDLR* nlconshdlr = NULL;
    1816
    1817 assert(benders != NULL);
    1818 assert(set != NULL);
    1819 assert(probnumber >= -1 && probnumber < SCIPbendersGetNSubproblems(benders));
    1820
    1821 assumevarfixed = NULL;
    1822 if( probnumber >= 0 )
    1823 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1824 else
    1825 subproblem = set->scip;
    1826
    1827 assert(subproblem != NULL);
    1828
    1829 convexcons = FALSE;
    1830 discretevar = FALSE;
    1831 isnonlinear = FALSE;
    1832
    1833 /* getting the number of integer and binary variables to determine the problem type */
    1834 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, &nbinvars, &nintvars, &nimplintvars, NULL) );
    1835
    1836 /* if there are any binary, integer or implicit integer variables, then the subproblems is marked as non-convex */
    1837 if( nbinvars != 0 || nintvars != 0 || nimplintvars != 0 )
    1838 {
    1839 discretevar = TRUE;
    1840 }
    1841
    1842 /* get pointers to linear constraints handlers, so can avoid string comparisons */
    1843 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
    1844 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
    1845 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
    1846 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
    1847 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
    1848
    1849 /* Get pointer to the nonlinear constraint handler if we also have an NLP solver to solve NLPs.
    1850 * If there is no NLP solver, but there are (convex) nonlinear constraints, then the LP relaxation of subproblems
    1851 * will (currently) not be sufficient to solve subproblems to optimality. Thus, we also take the presence of convex
    1852 * nonlinear constraints as signal for having to solve the CIP eventually, thus, by abuse of notation,
    1853 * return not-convex here. In summary, we do not need to have a special look onto non-linear constraints
    1854 * if no NLP solver is present, and can treat them as any other constraint that is not of linear type.
    1855 */
    1856 if( SCIPgetNNlpis(subproblem) > 0 )
    1857 {
    1858 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
    1859 }
    1860
    1861 /* if the nonlinear constraint handler exists, then we create a hashmap of variables that can be assumed to be fixed.
    1862 * These variables correspond to the copies of the master variables in the subproblem
    1863 */
    1864 if( probnumber >= 0 && nlconshdlr != NULL )
    1865 {
    1866 SCIP_VAR* mappedvar;
    1867
    1868 SCIP_CALL( SCIPhashmapCreate(&assumevarfixed, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
    1869
    1870 /* finding the subproblem variables that correspond to master variables */
    1871 for( i = 0; i < nvars; i++ )
    1872 {
    1873 /* getting the corresponding master problem variable for the given variable */
    1874 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mappedvar, -1) );
    1875
    1876 /* if the mapped variable is not NULL, then it must be stored as a possible fixed variable */
    1877 if( mappedvar != NULL )
    1878 {
    1879 SCIP_CALL( SCIPhashmapInsert(assumevarfixed, vars[i], vars[i]) );
    1880 }
    1881 }
    1882 }
    1883
    1884 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
    1885 {
    1886 cons = SCIPgetOrigConss(subproblem)[i];
    1887 conshdlr = SCIPconsGetHdlr(cons);
    1888
    1889 for( j = 0; j < NLINEARCONSHDLRS; ++j )
    1890 if( conshdlr == linearconshdlrs[j] )
    1891 break;
    1892
    1893 /* if linear constraint, then we are good */
    1894 if( j < NLINEARCONSHDLRS )
    1895 {
    1896#ifdef SCIP_MOREDEBUG
    1897 SCIPdebugMsg(subproblem, "subproblem <%s>: constraint <%s> is linear\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1898#endif
    1899 continue;
    1900 }
    1901
    1902 /* if cons_nonlinear (and nlconshdlr != NULL), then check whether convex */
    1903 if( conshdlr == nlconshdlr )
    1904 {
    1905 SCIP_Bool isconvex;
    1906 SCIP_EXPRCURV curv;
    1907 SCIP_Bool havelhs;
    1908 SCIP_Bool haverhs;
    1909
    1910 isnonlinear = TRUE;
    1911
    1912 havelhs = !SCIPisInfinity(subproblem, -SCIPgetLhsNonlinear(cons));
    1913 haverhs = !SCIPisInfinity(subproblem, SCIPgetRhsNonlinear(cons));
    1914 if( havelhs && haverhs )
    1915 {
    1916 isconvex = FALSE;
    1917 }
    1918 else
    1919 {
    1920 /* look at curvature stored in cons, though at this stage this will be unknown a.a. */
    1921 curv = SCIPgetCurvatureNonlinear(cons);
    1922 isconvex = ((!havelhs || (curv & SCIP_EXPRCURV_CONCAVE) == SCIP_EXPRCURV_CONCAVE)) &&
    1923 ((!haverhs || (curv & SCIP_EXPRCURV_CONVEX) == SCIP_EXPRCURV_CONVEX));
    1924
    1925 if( !isconvex )
    1926 {
    1927 /* if not found convex, compute curvature via nlhdlr_convex and decide again */
    1928
    1929 /* make sure activities are up to date. SCIPhasExprCurvature currently assumes that this is already the case */
    1931
    1932 SCIP_CALL( SCIPhasExprCurvature(subproblem, SCIPgetExprNonlinear(cons), havelhs ? SCIP_EXPRCURV_CONCAVE : SCIP_EXPRCURV_CONVEX, &isconvex, assumevarfixed) );
    1933 }
    1934 }
    1935
    1936 if( isconvex )
    1937 {
    1938#ifdef SCIP_MOREDEBUG
    1939 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> is convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1940#endif
    1941 continue;
    1942 }
    1943 else
    1944 {
    1945#ifdef SCIP_MOREDEBUG
    1946 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> not convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1947#endif
    1948 goto TERMINATE;
    1949 }
    1950 }
    1951
    1952#ifdef SCIP_MOREDEBUG
    1953 SCIPdebugMsg(subproblem, "subproblem <%s>: potentially nonconvex constraint <%s>\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1954#endif
    1955 goto TERMINATE;
    1956 }
    1957
    1958 /* if we made it until here, then all constraints are known and convex */
    1959 convexcons = TRUE;
    1960
    1961TERMINATE:
    1962 /* setting the flag for the convexity of the subproblem. If convexity doesn't need to be checked, then it is assumed
    1963 * that the subproblems are convex. However, if there are discrete variables, then the problem must be set as
    1964 * non-convex. The discrete master variables will be changed to continuous, but this will happen at the first call to
    1965 * SCIPbendersSetupSubproblem
    1966 */
    1967 if( probnumber >= 0 )
    1968 {
    1969 convexcons = convexcons || !benders->checkconsconvexity;
    1970
    1971 if( convexcons && !discretevar )
    1973 else if( convexcons && discretevar )
    1975 else if( !convexcons && !discretevar )
    1977 else if( !convexcons && discretevar )
    1979 else
    1980 SCIPABORT();
    1981
    1982 /* setting the non-linear subproblem flag */
    1983 SCIPbendersSetSubproblemIsNonlinear(benders, probnumber, isnonlinear);
    1984
    1985 SCIPsetDebugMsg(set, "subproblem <%s> has been found to be of type %d\n", SCIPgetProbName(subproblem),
    1986 SCIPbendersGetSubproblemType(benders, probnumber));
    1987 }
    1988 else
    1989 {
    1990 SCIPbendersSetMasterIsNonlinear(benders, isnonlinear);
    1991 }
    1992
    1993 /* releasing the fixed variable hashmap */
    1994 if( assumevarfixed != NULL )
    1995 SCIPhashmapFree(&assumevarfixed);
    1996
    1997 return SCIP_OKAY;
    1998}
    1999
    2000/** creates the subproblems and registers it with the Benders' decomposition struct */
    2001static
    2003 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2004 SCIP_SET* set /**< global SCIP settings */
    2005 )
    2006{
    2007 SCIP* subproblem;
    2008 SCIP_EVENTHDLR* eventhdlr;
    2009 SCIP_VAR* mastervar;
    2010 SCIP_VAR** vars;
    2011 int nvars;
    2012 int nsubproblems;
    2013 int i;
    2014 int j;
    2015
    2016 assert(benders != NULL);
    2017 assert(set != NULL);
    2018
    2019 /* if the subproblems have already been created, then they will not be created again. This is the case if the
    2020 * transformed problem has been freed and then retransformed. The subproblems should only be created when the problem
    2021 * is first transformed. */
    2022 if( benders->subprobscreated )
    2023 return SCIP_OKAY;
    2024
    2025 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2026
    2027 /* creating all subproblems */
    2028 for( i = 0; i < nsubproblems; i++ )
    2029 {
    2030 /* calling the create subproblem call back method */
    2031 SCIP_CALL( benders->benderscreatesub(set->scip, benders, i) );
    2032
    2033 subproblem = SCIPbendersSubproblem(benders, i);
    2034
    2035 /* the subproblem SCIP instance could be set to NULL. This is because user defined subproblem solving methods
    2036 * could be used that don't solve a SCIP instance. Thus, the following setup of the subproblem SCIP instance is
    2037 * not required.
    2038 *
    2039 * NOTE: since the subproblems are supplied as NULL pointers, the internal convexity check can not be performed.
    2040 * The user needs to explicitly specify the subproblem type.
    2041 */
    2042 if( subproblem != NULL )
    2043 {
    2044 /* stores the master problem variables that are in the subproblem. This is helpful for all instances where the
    2045 * master problem variable needs to extracted from the subproblem
    2046 */
    2047 SCIP_CALL( storeSubproblemMasterVars(benders, set, i) );
    2048
    2049 /* setting global limits for the subproblems. This overwrites the limits set by the user */
    2050 SCIP_CALL( SCIPsetIntParam(subproblem, "limits/maxorigsol", 0) );
    2051
    2052 /* getting the number of integer and binary variables to determine the problem type */
    2053 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
    2054
    2055 /* The objective function coefficients of the master problem are set to zero. This is necessary for the Benders'
    2056 * decomposition algorithm, since the cut methods and the objective function check assumes that the objective
    2057 * coefficients of the master problem variables are zero.
    2058 *
    2059 * This only occurs if the Benders' decomposition is not a copy. It is assumed that the correct objective
    2060 * coefficients are given during the first subproblem creation.
    2061 *
    2062 * If the subproblems were copied, then the master variables will be checked to ensure that they have a zero
    2063 * objective value.
    2064 */
    2065 if( !benders->iscopy || benders->threadsafe )
    2066 {
    2067 SCIP_Bool objchanged = FALSE;
    2068
    2069 assert(SCIPgetStage(subproblem) == SCIP_STAGE_PROBLEM);
    2070 for( j = 0; j < nvars; j++ )
    2071 {
    2072 /* retrieving the master problem variable */
    2073 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[j], &mastervar, -1) );
    2074
    2075 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
    2076 if( mastervar != NULL && SCIPvarGetObj(vars[j]) != 0.0 )
    2077 {
    2078 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Changing the objective "
    2079 "coefficient of copy of master problem variable <%s> in subproblem %d to zero.\n",
    2080 SCIPvarGetName(mastervar), i);
    2081 /* changing the subproblem variable objective coefficient to zero */
    2082 SCIP_CALL( SCIPchgVarObj(subproblem, vars[j], 0.0) );
    2083
    2084 objchanged = TRUE;
    2085 }
    2086 }
    2087
    2088 if( objchanged )
    2089 {
    2090 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_HIGH, NULL, "Benders' decomposition: Objective coefficients of "
    2091 "copy of master problem variables in a subproblem have been changed to zero.\n");
    2092 }
    2093 }
    2094
    2095 /* changing all of the master problem variable to continuous. */
    2097
    2098 /* checking the convexity of the subproblem. The convexity of the subproblem indicates whether the convex
    2099 * relaxation is a valid relaxation for the problem
    2100 */
    2101 SCIP_CALL( checkSubproblemConvexity(benders, set, i) );
    2102
    2103 /* if the problem is convex and has nonlinear constraints, then slack variables must be added to each of the
    2104 * constraints
    2105 */
    2106 if( benders->execfeasphase ||
    2108 && SCIPbendersSubproblemIsNonlinear(benders, i)) )
    2109 {
    2110 /* the slack variables are only added to the subproblem once. If the initialisation methods are called from a
    2111 * copy, then the slack variables are not re-added. Alternatively, if the copy must be threadsafe, then the
    2112 * subproblems are created from scratch again, so the slack variables need to be added.
    2113 */
    2114 if( !benders->iscopy || benders->threadsafe )
    2115 {
    2116 SCIP_CALL( addSlackVarsToConstraints(benders, set, i) );
    2117 }
    2118
    2119 /* setting the flag to indicate that slack variables have been added to the subproblem constraints. This is only
    2120 * set if the slack variables have been added at the request of the user.
    2121 */
    2122 if( benders->execfeasphase )
    2123 benders->feasibilityphase = TRUE;
    2124 }
    2125
    2126 /* after checking the subproblem for convexity, if the subproblem has convex constraints and continuous variables,
    2127 * then the problem is entered into probing mode. Otherwise, it is initialised as a CIP
    2128 */
    2130 {
    2131 /* if the user has not implemented a solve subproblem callback, then the subproblem solves are performed
    2132 * internally. To be more efficient the subproblem is put into probing mode. */
    2133 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
    2134 && SCIPgetStage(subproblem) <= SCIP_STAGE_PROBLEM )
    2135 {
    2136 SCIP_Bool infeasible;
    2137 SCIP_CALL( initialiseLPSubproblem(benders, set, i, &infeasible) );
    2138
    2139 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
    2140 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
    2141 * during the solving process.
    2142 */
    2143 if( infeasible )
    2145 }
    2146 }
    2147 else
    2148 {
    2149 SCIP_EVENTHDLRDATA* eventhdlrdata_mipnodefocus;
    2150 SCIP_EVENTHDLRDATA* eventhdlrdata_upperbound;
    2151
    2152 /* because the subproblems could be reused in the copy, the event handler is not created again. If the
    2153 * threadsafe is TRUE, then it is assumed that the subproblems are not reused.
    2154 * NOTE: This currently works with the benders_default implementation. It may not be very general. */
    2155 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
    2156 && (!benders->iscopy || benders->threadsafe) )
    2157 {
    2158 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_mipnodefocus) );
    2159 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_upperbound) );
    2160
    2161 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_mipnodefocus) );
    2162 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_upperbound) );
    2163
    2164 /* include the first LP solved event handler into the subproblem */
    2166 MIPNODEFOCUS_EVENTHDLR_DESC, eventExecBendersMipnodefocus, eventhdlrdata_mipnodefocus) );
    2167 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersMipnodefocus) );
    2168 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersMipnodefocus) );
    2169 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersMipnodefocus) );
    2170 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersMipnodefocus) );
    2171 assert(eventhdlr != NULL);
    2172
    2173 /* include the upper bound interrupt event handler into the subproblem */
    2175 UPPERBOUND_EVENTHDLR_DESC, eventExecBendersUpperbound, eventhdlrdata_upperbound) );
    2176 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersUpperbound) );
    2177 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersUpperbound) );
    2178 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersUpperbound) );
    2179 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersUpperbound) );
    2180 assert(eventhdlr != NULL);
    2181 }
    2182 }
    2183 }
    2184 else
    2185 {
    2186 /* a user must specify the subproblem type if they are not supplying a SCIP instance. */
    2188 {
    2189 SCIPerrorMessage("If the subproblem is set to NULL, then the subproblem type must be specified.\n");
    2190 SCIPerrorMessage("In the subproblem creation callback, call SCIPbendersSetSubproblemType with the appropriate problem type.\n");
    2191
    2192 return SCIP_ERROR;
    2193 }
    2194 }
    2195 }
    2196
    2197 /* checking the convexity of the master problem. This information is useful for the cut generation methods, such as
    2198 * non-good and integer cuts
    2199 */
    2200 SCIP_CALL( checkSubproblemConvexity(benders, set, -1) );
    2201
    2202 benders->subprobscreated = TRUE;
    2203
    2204 return SCIP_OKAY;
    2205}
    2206
    2208/** initializes Benders' decomposition */
    2210 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2211 SCIP_SET* set /**< global SCIP settings */
    2212 )
    2213{
    2214 int i;
    2215
    2216 assert(benders != NULL);
    2217 assert(set != NULL);
    2218
    2219 if( benders->initialized )
    2220 {
    2221 SCIPerrorMessage("Benders' decomposition <%s> already initialized\n", benders->name);
    2222 return SCIP_INVALIDCALL;
    2223 }
    2224
    2225 if( set->misc_resetstat )
    2226 {
    2227 SCIPclockReset(benders->setuptime);
    2228 SCIPclockReset(benders->bendersclock);
    2229
    2230 benders->ncalls = 0;
    2231 benders->ncutsfound = 0;
    2232 benders->ntransferred = 0;
    2233 }
    2234
    2235 /* start timing */
    2236 SCIPclockStart(benders->setuptime, set);
    2237
    2238 if( benders->bendersinit != NULL )
    2239 {
    2240 SCIP_CALL( benders->bendersinit(set->scip, benders) );
    2241 }
    2242
    2243 benders->initialized = TRUE;
    2244
    2245 /* if the Benders' decomposition is a copy, then the auxiliary variables already exist. So they are registered with
    2246 * the Benders' decomposition struct during the init stage. If the Benders' decomposition is not a copy, then the
    2247 * auxiliary variables need to be created, which occurs in the initpre stage
    2248 */
    2249 if( benders->iscopy )
    2250 {
    2251 /* the copied auxiliary variables must be assigned to the target Benders' decomposition */
    2252 SCIP_CALL( assignAuxiliaryVariables(set->scip, benders) );
    2253 }
    2254
    2255 /* creates the subproblems and sets up the probing mode for LP subproblems. This function calls the benderscreatesub
    2256 * callback. */
    2257 SCIP_CALL( createSubproblems(benders, set) );
    2258
    2259 /* storing the solution tolerance set by the SCIP parameters */
    2260 SCIP_CALL( SCIPsetGetRealParam(set, "benders/solutiontol", &benders->solutiontol) );
    2261
    2262 /* allocating memory for the stored constraints array */
    2263 if( benders->storedcutssize == 0 )
    2264 {
    2267 benders->nstoredcuts = 0;
    2268 }
    2269
    2270 /* initialising the Benders' cuts */
    2272 for( i = 0; i < benders->nbenderscuts; i++ )
    2273 {
    2275 }
    2276
    2277 /* stop timing */
    2278 SCIPclockStop(benders->setuptime, set);
    2279
    2280 return SCIP_OKAY;
    2281}
    2282
    2283
    2284/** Transfers Benders' cuts that were generated while solving a sub-SCIP to the original SCIP instance. This involves
    2285 * creating a constraint/cut that is equivalent to the generated cut in the sub-SCIP. This new constraint/cut is then
    2286 * added to the original SCIP instance.
    2288static
    2290 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
    2291 SCIP_BENDERS* benders, /**< the Benders' decomposition structure of the sub SCIP */
    2292 SCIP_VAR** vars, /**< the variables from the source constraint */
    2293 SCIP_Real* vals, /**< the coefficients of the variables in the source constriant */
    2294 SCIP_Real lhs, /**< the LHS of the source constraint */
    2295 SCIP_Real rhs, /**< the RHS of the source constraint */
    2296 int nvars /**< the number of variables in the source constraint */
    2297 )
    2298{
    2299 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
    2300 SCIP_CONSHDLR* consbenders; /* a helper variable for the Benders' decomposition constraint handler */
    2301 SCIP_CONS* transfercons = NULL; /* the constraint that is generated to transfer the constraints/cuts */
    2302 SCIP_ROW* transfercut = NULL; /* the cut that is generated to transfer the constraints/cuts */
    2303 SCIP_VAR* sourcevar; /* the source variable that will be added to the transferred cut */
    2304 SCIP_VAR* origvar;
    2305 SCIP_Real scalar;
    2306 SCIP_Real constant;
    2307 char cutname[SCIP_MAXSTRLEN]; /* the name of the transferred cut */
    2308 int i;
    2309 SCIP_Bool fail;
    2310
    2311 assert(sourcescip != NULL);
    2312 assert(benders != NULL);
    2313 assert(vars != NULL);
    2314 assert(vals != NULL);
    2315
    2316 /* retrieving the source Benders' decomposition structure */
    2317 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
    2318
    2319 /* retrieving the Benders' decomposition constraint handler */
    2320 consbenders = SCIPfindConshdlr(sourcescip, "benders");
    2321
    2322 /* setting the name of the transferred cut */
    2323 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "transferredcut_%d",
    2324 SCIPbendersGetNTransferredCuts(sourcebenders) );
    2325
    2326 /* TODO: It could be more efficient to pass an updated vars array with the vals array to the
    2327 * SCIPcreateConsBasicLinear/SCIPcreateEmptyRowConshdlr. This should be implemented to improve the performance of the
    2328 * Large Neighbourhood Benders Search.
    2329 */
    2330
    2331 /* creating an empty row/constraint for the transferred cut */
    2332 if( sourcebenders->cutsasconss )
    2333 {
    2334 SCIP_CALL( SCIPcreateConsBasicLinear(sourcescip, &transfercons, cutname, 0, NULL, NULL, lhs, rhs) );
    2335 SCIP_CALL( SCIPsetConsRemovable(sourcescip, transfercons, TRUE) );
    2336 }
    2337 else
    2338 {
    2339 SCIP_CALL( SCIPcreateEmptyRowConshdlr(sourcescip, &transfercut, consbenders, cutname, lhs, rhs, FALSE,
    2340 FALSE, TRUE) );
    2341 }
    2342
    2343 fail = FALSE;
    2344 for( i = 0; i < nvars; i++ )
    2345 {
    2346 /* getting the original variable for the transformed variable */
    2347 origvar = vars[i];
    2348 scalar = 1.0;
    2349 constant = 0.0;
    2350 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
    2351
    2352 /* getting the source var from the hash map */
    2353 sourcevar = (SCIP_VAR*) SCIPhashmapGetImage(benders->mastervarsmap, origvar);
    2354
    2355 /* if the source variable is not found, then the mapping in incomplete. So the constraint can not be
    2356 * transferred. */
    2357 if( sourcevar == NULL )
    2358 {
    2359 fail = TRUE;
    2360 break;
    2361 }
    2362
    2363 if( sourcebenders->cutsasconss )
    2364 {
    2365 assert( transfercons != NULL );
    2366 SCIP_CALL( SCIPaddCoefLinear(sourcescip, transfercons, sourcevar, vals[i]) ); /*lint !e644*/
    2367 }
    2368 else
    2369 {
    2370 assert( transfercut != NULL );
    2371 SCIP_CALL( SCIPaddVarToRow(sourcescip, transfercut, sourcevar, vals[i]) ); /*lint !e644*/
    2372 }
    2373 }
    2374
    2375 /* if all of the source variables were found to generate the cut */
    2376 if( !fail )
    2377 {
    2378 if( sourcebenders->cutsasconss )
    2379 {
    2380 SCIP_CALL( SCIPaddCons(sourcescip, transfercons) );
    2381 }
    2382 else
    2383 {
    2384 SCIP_CALL( SCIPaddPoolCut(sourcescip, transfercut) );
    2385 }
    2386
    2387 sourcebenders->ntransferred++;
    2388 }
    2389
    2390 /* release the row/constraint */
    2391 if( sourcebenders->cutsasconss )
    2392 {
    2393 /* only release if the creation of the constraint failed. */
    2394 SCIP_CALL( SCIPreleaseCons(sourcescip, &transfercons) );
    2395 }
    2396 else
    2397 {
    2398 SCIP_CALL( SCIPreleaseRow(sourcescip, &transfercut) );
    2399 }
    2400
    2401 return SCIP_OKAY;
    2402}
    2403
    2404
    2405/** transfers the cuts generated in a subscip to the source scip */
    2406static
    2408 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
    2409 SCIP* subscip, /**< the sub SCIP where the Benders' cuts were generated */
    2410 SCIP_BENDERS* benders /**< the Benders' decomposition structure of the sub SCIP */
    2411 )
    2412{
    2413 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
    2414 SCIP_VAR** vars; /* the variables of the added constraint/row */
    2415 SCIP_Real* vals; /* the values of the added constraint/row */
    2416 SCIP_Real lhs; /* the LHS of the added constraint/row */
    2417 SCIP_Real rhs; /* the RHS of the added constraint/row */
    2418 int naddedcuts;
    2419 int nvars;
    2420 int i;
    2421
    2422 assert(subscip != NULL);
    2423 assert(benders != NULL);
    2424
    2425 /* retrieving the source Benders' decomposition structure */
    2426 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
    2427
    2428 /* exit if the cuts should not be transferred from the sub SCIP to the source SCIP. */
    2429 if( !sourcebenders->transfercuts || benders->mastervarsmap == NULL )
    2430 return SCIP_OKAY;
    2431
    2432 /* retrieving the number of stored Benders' cuts */
    2433 naddedcuts = SCIPbendersGetNStoredCuts(benders);
    2434
    2435 /* looping over all added cuts to construct the cut for the source scip */
    2436 for( i = 0; i < naddedcuts; i++ )
    2437 {
    2438 /* collecting the variable information from the constraint */
    2439 SCIP_CALL( SCIPbendersGetStoredCutData(benders, i, &vars, &vals, &lhs, &rhs, &nvars) );
    2440
    2441 if( nvars > 0 )
    2442 {
    2443 /* create and add the cut to be transferred from the sub SCIP to the source SCIP */
    2444 SCIP_CALL( createAndAddTransferredCut(sourcescip, benders, vars, vals, lhs, rhs, nvars) );
    2445 }
    2446 }
    2447
    2448 return SCIP_OKAY;
    2449}
    2450
    2452/** calls exit method of Benders' decomposition */
    2454 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2455 SCIP_SET* set /**< global SCIP settings */
    2456 )
    2457{
    2458 int nsubproblems;
    2459 int i;
    2460
    2461 assert(benders != NULL);
    2462 assert(set != NULL);
    2463
    2464 if( !benders->initialized )
    2465 {
    2466 SCIPerrorMessage("Benders' decomposition <%s> not initialized\n", benders->name);
    2467 return SCIP_INVALIDCALL;
    2468 }
    2469
    2470 /* start timing */
    2471 SCIPclockStart(benders->setuptime, set);
    2472
    2473 if( benders->bendersexit != NULL )
    2474 {
    2475 SCIP_CALL( benders->bendersexit(set->scip, benders) );
    2476 }
    2477
    2478 /* if the Benders' decomposition is a copy, then is a variable mapping was provided, then the generated cuts will
    2479 * be transferred to the source scip
    2480 */
    2481 if( benders->iscopy && benders->mastervarsmap != NULL )
    2482 {
    2483 SCIP_CALL( transferBendersCuts(benders->sourcescip, set->scip, benders) );
    2484 }
    2485
    2486 /* releasing the stored constraints */
    2487 for( i = benders->nstoredcuts - 1; i >= 0; i-- )
    2488 {
    2489 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vals, benders->storedcuts[i]->nvars);
    2490 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vars, benders->storedcuts[i]->nvars);
    2491 SCIPfreeBlockMemory(set->scip, &benders->storedcuts[i]); /*lint !e866*/
    2492 }
    2493
    2494 BMSfreeBlockMemoryArray(SCIPblkmem(set->scip), &benders->storedcuts, benders->storedcutssize);
    2495 benders->storedcutssize = 0;
    2496 benders->nstoredcuts = 0;
    2497
    2498 /* releasing all of the auxiliary variables and constraints */
    2499 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2500 for( i = 0; i < nsubproblems; i++ )
    2501 {
    2502 /* it is possible that the master problem is not solved. As such, the auxiliary variables will not be created. So
    2503 * we don't need to release the variables or the constraints
    2504 */
    2505 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX && benders->auxiliaryvarcons[i] != NULL )
    2506 {
    2507 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[i]) );
    2508 }
    2509
    2510 if( benders->auxiliaryvars[i] != NULL )
    2511 {
    2512 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
    2513 * Benders' plugin and others if the auxiliary variables are not shared
    2514 */
    2515 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->auxiliaryvars[i]) > 0 )
    2516 SCIP_CALL( SCIPaddVarLocksType(set->scip, benders->auxiliaryvars[i], SCIP_LOCKTYPE_MODEL, -1, 0) );
    2517
    2518 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->auxiliaryvars[i]) );
    2519 }
    2520 }
    2521
    2522 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM && benders->auxiliaryvarcons[0] != NULL )
    2523 {
    2524 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[0]) );
    2525 }
    2526
    2527 if( benders->masterauxvar != NULL )
    2528 {
    2529 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
    2530 * Benders' plugin and others if the auxiliary variables are not shared
    2531 */
    2532 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->masterauxvar) > 0 )
    2533 {
    2535 }
    2536
    2537 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->masterauxvar) );
    2538 }
    2539
    2541
    2542 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
    2543 if( benders->corepoint != NULL )
    2544 {
    2545 SCIP_CALL( SCIPfreeSol(set->scip, &benders->corepoint) );
    2546 }
    2547
    2548 /* calling the exit method for the Benders' cuts */
    2550 for( i = 0; i < benders->nbenderscuts; i++ )
    2551 {
    2553 }
    2554
    2555 benders->initialized = FALSE;
    2556
    2557 /* stop timing */
    2558 SCIPclockStop(benders->setuptime, set);
    2559
    2560 return SCIP_OKAY;
    2561}
    2562
    2563/** Checks whether a subproblem is independent. */
    2564static
    2566 SCIP* scip, /**< the SCIP data structure */
    2567 SCIP_BENDERS* benders /**< Benders' decomposition */
    2568 )
    2569{
    2570 SCIP_VAR** vars;
    2571 int nvars;
    2572 int nsubproblems;
    2573 int i;
    2574 int j;
    2575
    2576 assert(scip != NULL);
    2577 assert(benders != NULL);
    2578
    2579 /* retrieving the master problem variables */
    2580 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    2581
    2582 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2583
    2584 /* looping over all subproblems to check whether there exists at least one master problem variable */
    2585 for( i = 0; i < nsubproblems; i++ )
    2586 {
    2587 /* if there are user defined solving or freeing functions, then it is not possible to declare the independence of
    2588 * the subproblems.
    2589 */
    2590 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
    2591 && benders->bendersfreesub == NULL )
    2592 {
    2593 SCIP_Bool independent = TRUE;
    2594
    2595 for( j = 0; j < nvars; j++ )
    2596 {
    2597 SCIP_VAR* subprobvar;
    2598
    2599 /* getting the subproblem problem variable corresponding to the master problem variable */
    2600 SCIP_CALL( SCIPgetBendersSubproblemVar(scip, benders, vars[j], &subprobvar, i) );
    2601
    2602 /* if the subporblem variable is not NULL, then the subproblem depends on the master problem */
    2603 if( subprobvar != NULL )
    2604 {
    2605 independent = FALSE;
    2606 break;
    2607 }
    2608 }
    2609
    2610 /* setting the independent flag */
    2611 SCIPbendersSetSubproblemIsIndependent(benders, i, independent);
    2612 }
    2613 }
    2614
    2615 return SCIP_OKAY;
    2616}
    2618/** informs the Benders' decomposition that the presolving process is being started */
    2620 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2621 SCIP_SET* set, /**< global SCIP settings */
    2622 SCIP_STAT* stat /**< dynamic problem statistics */
    2623 )
    2624{
    2625 assert(benders != NULL);
    2626 assert(set != NULL);
    2627 assert(stat != NULL);
    2628
    2629 /* the arrays for the auxiliary variables and constraints are not allocated at the activate stage. This is because
    2630 * SCIPbendersActivate can be called during SCIP_STAGE_PROBLEM. As such, the user may still change the objective type
    2631 * after the Benders' decomposition has been activated. The memory allocation occurs immediately before the variables
    2632 * are created, then freed in SCIPbendersExit.
    2633 */
    2634 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
    2635 {
    2637 }
    2638 else
    2639 {
    2640 assert(benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX);
    2642 }
    2643
    2644 /* if the Benders' decomposition is the original, then the auxiliary variables need to be created. If the Benders'
    2645 * decomposition is a copy, then the auxiliary variables already exist. The assignment of the auxiliary variables
    2646 * occurs in bendersInit
    2647 */
    2648 if( !benders->iscopy )
    2649 {
    2650 /* check the subproblem independence. This check is only performed if the user has not implemented a solve
    2651 * subproblem function.
    2652 */
    2653 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL )
    2654 SCIP_CALL( checkSubproblemIndependence(set->scip, benders) );
    2655
    2656 /* adding the auxiliary variables to the master problem */
    2657 SCIP_CALL( addAuxiliaryVariablesToMaster(set->scip, benders) );
    2658 }
    2659
    2660 /* call presolving initialization method of Benders' decomposition */
    2661 if( benders->bendersinitpre != NULL )
    2662 {
    2663 /* start timing */
    2664 SCIPclockStart(benders->setuptime, set);
    2665
    2666 SCIP_CALL( benders->bendersinitpre(set->scip, benders) );
    2667
    2668 /* stop timing */
    2669 SCIPclockStop(benders->setuptime, set);
    2670 }
    2671
    2672 return SCIP_OKAY;
    2673}
    2674
    2676/** informs the Benders ␚' decomposition that the presolving process has completed */
    2678 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2679 SCIP_SET* set, /**< global SCIP settings */
    2680 SCIP_STAT* stat /**< dynamic problem statistics */
    2681 )
    2682{
    2683 assert(benders != NULL);
    2684 assert(set != NULL);
    2685 assert(stat != NULL);
    2686
    2687 /* call presolving deinitialization method of Benders' decomposition */
    2688 if( benders->bendersexitpre != NULL )
    2689 {
    2690 /* start timing */
    2691 SCIPclockStart(benders->setuptime, set);
    2692
    2693 SCIP_CALL( benders->bendersexitpre(set->scip, benders) );
    2694
    2695 /* stop timing */
    2696 SCIPclockStop(benders->setuptime, set);
    2697 }
    2698
    2699 return SCIP_OKAY;
    2700}
    2702/** informs Benders' decomposition that the branch and bound process is being started */
    2704 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2705 SCIP_SET* set /**< global SCIP settings */
    2706 )
    2707{
    2708 int i;
    2709
    2710 assert(benders != NULL);
    2711 assert(set != NULL);
    2712
    2713 /* call solving process initialization method of Benders' decomposition */
    2714 if( benders->bendersinitsol != NULL )
    2715 {
    2716 /* start timing */
    2717 SCIPclockStart(benders->setuptime, set);
    2718
    2719 SCIP_CALL( benders->bendersinitsol(set->scip, benders) );
    2720
    2721 /* stop timing */
    2722 SCIPclockStop(benders->setuptime, set);
    2723 }
    2724
    2725 /* calling the initsol method for the Benders' cuts */
    2727 for( i = 0; i < benders->nbenderscuts; i++ )
    2728 {
    2730 }
    2731
    2732 return SCIP_OKAY;
    2733}
    2735/** informs Benders' decomposition that the branch and bound process data is being freed */
    2737 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2738 SCIP_SET* set /**< global SCIP settings */
    2739 )
    2740{
    2741 int nsubproblems;
    2742 int i;
    2743
    2744 assert(benders != NULL);
    2745 assert(set != NULL);
    2746
    2747 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2748 /* freeing all subproblems that are independent, this is because they have not bee freed during the subproblem
    2749 * solving loop.
    2750 */
    2751 for( i = 0; i < nsubproblems; i++ )
    2752 {
    2753 if( SCIPbendersSubproblemIsIndependent(benders, i) )
    2754 {
    2755 /* disabling the independence of the subproblem so that it can be freed */
    2757
    2758 /* freeing the independent subproblem */
    2759 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, i) );
    2760 }
    2761 }
    2762
    2763 /* call solving process deinitialization method of Benders' decomposition */
    2764 if( benders->bendersexitsol != NULL )
    2765 {
    2766 /* start timing */
    2767 SCIPclockStart(benders->setuptime, set);
    2768
    2769 SCIP_CALL( benders->bendersexitsol(set->scip, benders) );
    2770
    2771 /* stop timing */
    2772 SCIPclockStop(benders->setuptime, set);
    2773 }
    2774
    2775 /* sorting the Benders' decomposition cuts in order of priority. Only a single cut is generated for each subproblem
    2776 * per solving iteration. This is particularly important in the case of the optimality and feasibility cuts. Since
    2777 * these work on two different solutions to the subproblem, it is not necessary to generate both cuts. So, once the
    2778 * feasibility cut is generated, then no other cuts will be generated.
    2779 */
    2781
    2782 /* calling the exitsol method for the Benders' cuts */
    2783 for( i = 0; i < benders->nbenderscuts; i++ )
    2784 {
    2786 }
    2787
    2788 return SCIP_OKAY;
    2789}
    2791/** activates Benders' decomposition such that it is called in LP solving loop */
    2793 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    2794 SCIP_SET* set, /**< global SCIP settings */
    2795 int nsubproblems /**< the number subproblems used in this decomposition */
    2796 )
    2797{
    2798 SCIP_EVENTHDLR* eventhdlr;
    2799 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2800 int i;
    2801
    2802 assert(benders != NULL);
    2803 assert(set != NULL);
    2804 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
    2805
    2806 if( !benders->active )
    2807 {
    2808 benders->active = TRUE;
    2809 set->nactivebenders++;
    2810 set->benderssorted = FALSE;
    2811
    2812 benders->nsubproblems = nsubproblems;
    2813 benders->nactivesubprobs = nsubproblems;
    2814 benders->prevlowerbound = -SCIPsetInfinity(set);
    2815 benders->strengthenround = FALSE;
    2816
    2817 /* allocating memory for the subproblems arrays */
    2825 SCIP_ALLOC( BMSallocMemoryArray(&benders->solvestat, benders->nsubproblems) );
    2836
    2837 /* creating the priority queue for the subproblem solving status */
    2838 SCIP_CALL( SCIPpqueueCreate(&benders->subprobqueue, benders->nsubproblems, 1.1,
    2839 benders->benderssubcomp == NULL ? benderssubcompdefault : benders->benderssubcomp, NULL) );
    2840
    2841 for( i = 0; i < benders->nsubproblems; i++ )
    2842 {
    2843 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
    2844
    2846
    2847 benders->subproblems[i] = NULL;
    2848 benders->auxiliaryvars[i] = NULL;
    2850 benders->nsubmastervars[i] = 0;
    2851 benders->nsubmasterbinvars[i] = 0;
    2852 benders->nsubmasterintvars[i] = 0;
    2853 benders->subprobobjval[i] = SCIPsetInfinity(set);
    2854 benders->bestsubprobobjval[i] = SCIPsetInfinity(set);
    2855 benders->subproblowerbound[i] = -SCIPsetInfinity(set);
    2857 benders->subprobisconvex[i] = FALSE;
    2858 benders->subprobisnonlinear[i] = FALSE;
    2859 benders->subprobsetup[i] = FALSE;
    2860 benders->indepsubprob[i] = FALSE;
    2861 benders->subprobenabled[i] = TRUE;
    2862 benders->mastervarscont[i] = FALSE;
    2863
    2864 /* initialising the subproblem solving status */
    2865 SCIP_ALLOC( BMSallocMemory(&solvestat) );
    2866 solvestat->idx = i;
    2867 solvestat->ncalls = 0;
    2868 solvestat->avgiter = 0;
    2869 benders->solvestat[i] = solvestat;
    2870
    2871 /* inserting the initial elements into the priority queue */
    2872 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, benders->solvestat[i]) );
    2873 }
    2874
    2876 {
    2877 /* adding an eventhandler for updating the lower bound when the root node is solved. */
    2878 eventhdlrdata = (SCIP_EVENTHDLRDATA*)benders;
    2879
    2880 /* include event handler into SCIP */
    2882 eventExecBendersNodesolved, eventhdlrdata) );
    2883 SCIP_CALL( SCIPsetEventhdlrInitsol(set->scip, eventhdlr, eventInitsolBendersNodesolved) );
    2884 assert(eventhdlr != NULL);
    2885 }
    2886 }
    2887
    2888 return SCIP_OKAY;
    2889}
    2891/** deactivates Benders' decomposition such that it is no longer called in LP solving loop */
    2893 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    2894 SCIP_SET* set /**< global SCIP settings */
    2895 )
    2896{
    2897 int i;
    2898
    2899 assert(benders != NULL);
    2900 assert(set != NULL);
    2901 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
    2902
    2903 if( benders->active )
    2904 {
    2905 SCIP_EVENTHDLR* eventhdlr;
    2906 int nsubproblems;
    2907
    2908 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2909
    2910#ifndef NDEBUG
    2911 /* checking whether the auxiliary variables and subproblems are all NULL */
    2912 for( i = 0; i < nsubproblems; i++ )
    2913 assert(benders->auxiliaryvars[i] == NULL);
    2914#endif
    2915
    2916 /* if the subproblems were created by the Benders' decomposition core, then they need to be freed */
    2917 if( benders->freesubprobs )
    2918 {
    2919 for( i = SCIPbendersGetNSubproblems(benders) - 1; i >= 0; i-- )
    2920 {
    2921 SCIP* subproblem = SCIPbendersSubproblem(benders, i);
    2922 SCIP_CALL( SCIPfree(&subproblem) );
    2923 }
    2924 }
    2925
    2926 benders->active = FALSE;
    2927 set->nactivebenders--;
    2928 set->benderssorted = FALSE;
    2929
    2930 /* freeing the priority queue memory */
    2931 SCIPpqueueFree(&benders->subprobqueue);
    2932
    2933 for( i = nsubproblems - 1; i >= 0; i-- )
    2934 BMSfreeMemory(&benders->solvestat[i]);
    2935
    2936 /* freeing the master variable storage if it exists */
    2937 for( i = nsubproblems - 1; i >= 0; i-- )
    2939
    2940 /* freeing the memory allocated during the activation of the Benders' decomposition */
    2951 BMSfreeMemoryArray(&benders->solvestat);
    2959
    2960 benders->ncalls = 0;
    2961 benders->ncutsfound = 0;
    2962 benders->ntransferred = 0;
    2963
    2964 benders->naddedsubprobs = 0;
    2965 benders->nconvexsubprobs = 0;
    2966 benders->nnonlinearsubprobs = 0;
    2967 benders->subprobscreated = FALSE;
    2968 benders->freesubprobs = FALSE;
    2969 benders->masterisnonlinear = FALSE;
    2970
    2971 benders->nstrengthencuts = 0;
    2972 benders->nstrengthencalls = 0;
    2973 benders->nstrengthenfails = 0;
    2974
    2975 benders->npseudosols = 0;
    2976 benders->feasibilityphase = FALSE;
    2977
    2978 /* dropping the event from the node solved event handler */
    2980 if( eventhdlr != NULL && SCIPsetGetStage(set) >= SCIP_STAGE_INITSOLVE )
    2981 {
    2982 SCIP_CALL( SCIPdropEvent(set->scip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, NULL, -1) );
    2983 }
    2984 }
    2985
    2986 return SCIP_OKAY;
    2987}
    2989/** returns whether the given Benders' decomposition is in use in the current problem */
    2991 SCIP_BENDERS* benders /**< the Benders' decomposition structure */
    2992 )
    2993{
    2994 assert(benders != NULL);
    2995
    2996 return benders->active;
    2997}
    2998
    2999/** updates the lower bound for all auxiliary variables. This is called if the first LP enforced is unbounded. */
    3000static
    3002 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3003 SCIP_SET* set, /**< global SCIP settings */
    3004 SCIP_RESULT* result /**< the result from updating the auxiliary variable lower bound */
    3005 )
    3006{
    3007 int nsubproblems;
    3008 int i;
    3009
    3010 assert(benders != NULL);
    3011 assert(set != NULL);
    3012
    3013 (*result) = SCIP_DIDNOTRUN;
    3014
    3015 nsubproblems = SCIPbendersGetNSubproblems(benders);
    3016
    3017 for( i = 0; i < nsubproblems; i++ )
    3018 {
    3019 SCIP_VAR* auxiliaryvar;
    3020 SCIP_Real lowerbound;
    3021 SCIP_Bool infeasible;
    3022
    3023 infeasible = FALSE;
    3024
    3025 /* computing the lower bound of the subproblem by solving it without any variable fixings */
    3026 SCIP_CALL( SCIPbendersComputeSubproblemLowerbound(benders, set, i, &lowerbound, &infeasible) );
    3027
    3028 /* if the subproblem is infeasible, then the original problem is infeasible */
    3029 if( infeasible )
    3030 {
    3031 (*result) = SCIP_INFEASIBLE;
    3032 break;
    3033 }
    3034
    3035 /* retrieving the auxiliary variable */
    3036 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, i);
    3037
    3038 /* only update the lower bound if it is greater than the current lower bound */
    3039 if( SCIPsetIsGT(set, lowerbound, SCIPvarGetLbGlobal(auxiliaryvar)) )
    3040 {
    3041 SCIPsetDebugMsg(set, "Tightened lower bound of <%s> to %g\n", SCIPvarGetName(auxiliaryvar), lowerbound);
    3042 /* updating the lower bound of the auxiliary variable */
    3043 SCIP_CALL( SCIPchgVarLb(set->scip, auxiliaryvar, lowerbound) );
    3044 (*result) = SCIP_REDUCEDDOM;
    3045 }
    3046
    3047 /* stores the lower bound for the subproblem */
    3048 SCIPbendersUpdateSubproblemLowerbound(benders, i, lowerbound);
    3049 }
    3050
    3051 return SCIP_OKAY;
    3052}
    3053
    3054/** sets the core point used for cut strengthening. If the strenghtenintpoint is set to 'i', then the core point is
    3055 * reinitialised each time the incumbent is updated
    3057static
    3059 SCIP* scip, /**< the SCIP data structure */
    3060 SCIP_BENDERS* benders /**< Benders' decomposition */
    3061 )
    3062{
    3063 SCIP_SOL* bestsol;
    3064
    3065 assert(scip != NULL);
    3066 assert(benders != NULL);
    3067
    3068 /* if the core point is not NULL and the interior point is not reinitialised, then nothing is done */
    3069 if( benders->corepoint != NULL && benders->strengthenintpoint != 'i' )
    3070 return SCIP_OKAY;
    3071
    3072 bestsol = SCIPgetBestSol(scip);
    3073
    3074 /* if the core point should be updated, then this only happens if the incumbent solution has been updated */
    3075 if( benders->strengthenintpoint == 'i' && benders->initcorepoint == bestsol )
    3076 return SCIP_OKAY;
    3077
    3078 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
    3079 if( benders->corepoint != NULL )
    3080 {
    3081 SCIP_CALL( SCIPfreeSol(scip, &benders->corepoint) );
    3082 }
    3083
    3084 switch( benders->strengthenintpoint )
    3085 {
    3086 SCIP_VAR** vars;
    3087 SCIP_Real timelimit;
    3088 int nvars;
    3089 int i;
    3090
    3091 case 'l':
    3093 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3094 break;
    3095 case 'f':
    3096 case 'i':
    3097 SCIP_CALL( SCIPcreateSolCopy(scip, &benders->corepoint, bestsol) );
    3098 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3099 benders->initcorepoint = bestsol;
    3100 break;
    3101 case 'r':
    3102 /* prepare time limit */
    3103 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    3104 if ( ! SCIPisInfinity(scip, timelimit) )
    3105 timelimit -= SCIPgetSolvingTime(scip);
    3106
    3107 /* if there is time remaining, then compute the relative interior point. Otherwise, return the LP solution */
    3108 if ( timelimit > 0.0 )
    3109 {
    3110 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, 0, "Computing relative interior point (time limit: %g, iter limit: %d) ...\n", timelimit, INT_MAX);
    3111 SCIP_CALL( SCIPcomputeLPRelIntPoint(scip, TRUE, FALSE, timelimit, INT_MAX, &benders->corepoint) );
    3112 }
    3113 else
    3114 {
    3116 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3117 }
    3118 break;
    3119 case 'z':
    3120 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
    3121 break;
    3122 case 'o':
    3123 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
    3124
    3125 /* getting the variable data so that the */
    3126 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    3127
    3128 /* setting all variable values to 1.0 */
    3129 for( i = 0; i < nvars; i++ )
    3130 {
    3131 SCIP_CALL( SCIPsetSolVal(scip, benders->corepoint, vars[i], 1.0) );
    3132 }
    3133 break;
    3134 default:
    3136 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3137 }
    3138
    3139 return SCIP_OKAY;
    3140}
    3141
    3142/** performs cut strengthening by using an interior solution to generate cuts */
    3143static
    3145 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3146 SCIP_SET* set, /**< global SCIP settings */
    3147 SCIP_SOL* sol, /**< primal CIP solution */
    3148 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3149 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
    3150 SCIP_Bool perturbsol, /**< should the solution be perturbed to escape infeasibility? */
    3151 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
    3152 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
    3153 SCIP_Bool* skipsolve, /**< should the main solve be skipped as a result of this strengthening? */
    3154 SCIP_RESULT* result /**< result of the pricing process */
    3155 )
    3156{
    3157 SCIP_SOL* sepapoint;
    3158 SCIP_VAR** vars;
    3159 int prevcutsfound;
    3160 int nvars;
    3161 int i;
    3162
    3163 assert(benders != NULL);
    3164 assert(set != NULL);
    3165
    3166 (*result) = SCIP_DIDNOTRUN;
    3167 (*skipsolve) = FALSE;
    3168
    3169 /* the cut stabilisation is only performed when enforcing LP solutions. The solution is not NULL if the stabilisation
    3170 * is currently being performed. It is important to avoid recursion
    3171 */
    3172 if( type != SCIP_BENDERSENFOTYPE_LP || sol != NULL )
    3173 return SCIP_OKAY;
    3174
    3175 /* checking if a change to the lower bound has occurred */
    3176 if( SCIPsetIsGT(set, SCIPgetLowerbound(set->scip), benders->prevlowerbound)
    3177 || SCIPgetCurrentNode(set->scip) != benders->prevnode )
    3178 {
    3179 benders->prevnode = SCIPgetCurrentNode(set->scip);
    3180 benders->prevlowerbound = SCIPgetLowerbound(set->scip);
    3181 benders->noimprovecount = 0;
    3182 }
    3183 else
    3184 benders->noimprovecount++;
    3185
    3186 /* if the number of iterations without improvement exceeds 3*noimprovelimit, then the no stabilisation is performed
    3187 */
    3188 if( benders->noimprovecount > 3*benders->noimprovelimit )
    3189 return SCIP_OKAY;
    3190
    3191 /* if there is no incumbent solution, then it is not possible to create the core point and hence the strengthening
    3192 * can not be performed
    3193 */
    3194 if( SCIPgetBestSol(set->scip) == NULL )
    3195 return SCIP_OKAY;
    3196
    3197 /* if no LP iterations have been performed since the last call of the cut strenghtening, then the strengthening is
    3198 * aborted
    3199 */
    3200 if( benders->prevnlpiter == SCIPgetNLPIterations(set->scip) )
    3201 return SCIP_OKAY;
    3202
    3203 benders->prevnlpiter = SCIPgetNLPIterations(set->scip);
    3204
    3205 /* if the separation point solution is NULL, then we create the solution using the current LP relaxation. */
    3206 SCIP_CALL( setAndUpdateCorePoint(set->scip, benders) );
    3207
    3208 /* creating the separation point
    3209 * TODO: This could be a little to memory heavy, it may be better just to create the separation point once and then
    3210 * update it each time.
    3211 */
    3212 SCIP_CALL( SCIPcreateLPSol(set->scip, &sepapoint, NULL) );
    3213 SCIP_CALL( SCIPunlinkSol(set->scip, sepapoint) );
    3214
    3215 SCIP_CALL( SCIPgetVarsData(set->scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    3216 assert(vars != NULL);
    3217
    3218 /* creating a solution that is a convex combination of the LP solution and the separation point */
    3219 for( i = 0; i < nvars; i++ )
    3220 {
    3221 SCIP_VAR* subvar;
    3222 SCIP_Real corepointval;
    3223 SCIP_Real lpsolval;
    3224 SCIP_Real newsolval;
    3225 int j;
    3226
    3227 corepointval = SCIPgetSolVal(set->scip, benders->corepoint, vars[i]);
    3228 lpsolval = SCIPgetSolVal(set->scip, sol, vars[i]);
    3229 newsolval = lpsolval;
    3230
    3231 /* checking whether the master variable is mapped to any subproblem variables */
    3232 subvar = NULL;
    3233 j = 0;
    3234 while( subvar == NULL && j < SCIPgetBendersNSubproblems(set->scip, benders) )
    3235 {
    3236 SCIP_CALL( SCIPgetBendersSubproblemVar(set->scip, benders, vars[i], &subvar, j) );
    3237 j++;
    3238 }
    3239
    3240 /* if the variable is a linking variable and it is not fixed, then a convex combination with the corepoint is
    3241 * computed.
    3242 */
    3243 if( subvar != NULL && SCIPvarGetStatus(vars[i]) != SCIP_VARSTATUS_FIXED )
    3244 {
    3245 /* if the number of iterations without improvement exceeds noimprovelimit, then no convex combination is
    3246 * created
    3247 */
    3248 if( !perturbsol && benders->noimprovecount <= benders->noimprovelimit )
    3249 {
    3250 newsolval = lpsolval*benders->convexmult + corepointval*(1 - benders->convexmult);
    3251
    3252 /* updating the core point */
    3253 SCIP_CALL( SCIPsetSolVal(set->scip, benders->corepoint, vars[i], newsolval) );
    3254 }
    3255
    3256 /* if the number of iterations without improvement is less than 2*noimprovelimit, then perturbation is
    3257 * performed
    3258 * TODO: This should be a random vector!!!!
    3259 */
    3260 if( perturbsol || benders->noimprovecount <= 2*benders->noimprovelimit )
    3261 newsolval += benders->perturbeps;
    3262 }
    3263
    3264 /* updating the separation point */
    3265 SCIP_CALL( SCIPsetSolVal(set->scip, sepapoint, vars[i], newsolval) );
    3266 }
    3267
    3268 /* storing the number of cuts found */
    3269 prevcutsfound = SCIPbendersGetNCutsFound(benders);
    3270
    3271 SCIPsetDebugMsg(set, "solving Benders' decomposition subproblems with stabilised point.\n");
    3272
    3273 /* calling the subproblem solving method to generate cuts from the separation solution */
    3274 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sepapoint, result, infeasible, auxviol, type, checkint) );
    3275
    3276 SCIPsetDebugMsg(set, "solved Benders' decomposition subproblems with stabilised point. noimprovecount %d result %d\n",
    3277 benders->noimprovecount, (*result));
    3278
    3279 /* if constraints were added, then the main Benders' solving loop is skipped. */
    3280 if( !(*infeasible) && ((*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED) )
    3281 (*skipsolve) = TRUE;
    3282
    3283 /* capturing cut strengthening statistics */
    3284 benders->nstrengthencalls++;
    3285 benders->nstrengthencuts += (SCIPbendersGetNCutsFound(benders) - prevcutsfound);
    3286
    3287 /* if no cuts were added, then the strengthening round is marked as failed */
    3288 if( SCIPbendersGetNCutsFound(benders) == prevcutsfound )
    3289 benders->nstrengthenfails++;
    3290
    3291 /* freeing the sepapoint solution */
    3292 SCIP_CALL( SCIPfreeSol(set->scip, &sepapoint) );
    3293
    3294 return SCIP_OKAY;
    3295}
    3296
    3297
    3298/** Returns whether only the convex relaxations will be checked in this solve loop
    3299 * when Benders' is used in the LNS heuristics, only the convex relaxations of the master/subproblems are checked,
    3300 * i.e. no integer cuts are generated. In this case, then Benders' decomposition is performed under the assumption
    3301 * that all subproblems are convex relaxations.
    3302 */
    3304 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3305 SCIP_Bool subscipsoff /**< flag indicating whether plugins using sub-SCIPs are deactivated */
    3306 )
    3307{
    3308 return benders->iscopy && benders->lnscheck && subscipsoff;
    3309}
    3310
    3311/** returns the number of subproblems that will be checked in this iteration */
    3312static
    3314 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3315 SCIP_SET* set, /**< global SCIP settings */
    3316 SCIP_BENDERSENFOTYPE type /**< the type of solution being enforced */
    3317 )
    3318{
    3319 if( benders->ncalls == 0 || type == SCIP_BENDERSENFOTYPE_CHECK
    3321 return SCIPbendersGetNSubproblems(benders);
    3322 else
    3323 return (int) SCIPsetCeil(set, (SCIP_Real) SCIPbendersGetNSubproblems(benders)*benders->subprobfrac);
    3324}
    3325
    3326/** returns whether the solving of the given subproblem needs to be executed */
    3327static
    3329 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3330 int probnumber /**< the subproblem index */
    3331 )
    3332{
    3333 return (!SCIPbendersSubproblemIsIndependent(benders, probnumber)
    3334 && SCIPbendersSubproblemIsEnabled(benders, probnumber));
    3335}
    3336
    3337/** creates an ordered list of subproblem indices to be solved */
    3338static
    3340 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3341 SCIP_SET* set, /**< global SCIP settings */
    3342 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3343 int** solveidx, /**< a list of subproblem indices to the solved in the current iteration */
    3344 int* nsolveidx /**< the number of subproblem indices in the list */
    3345 )
    3346{
    3347 int nsubproblems;
    3348 int numtocheck;
    3349 int subproblemcount;
    3350
    3351 assert(benders != NULL);
    3352 assert(set != NULL);
    3353 assert((*solveidx) != NULL);
    3354 assert(nsolveidx != NULL);
    3355 assert(SCIPpqueueNElems(benders->subprobqueue) <= SCIPbendersGetNSubproblems(benders));
    3356
    3357 nsubproblems = SCIPbendersGetNSubproblems(benders);
    3358
    3359 /* it is possible to only solve a subset of subproblems. This is given by a parameter. */
    3360 numtocheck = numSubproblemsToCheck(benders, set, type);
    3361
    3362 (*nsolveidx) = 0;
    3363
    3364 subproblemcount = 0;
    3365 while( subproblemcount < nsubproblems && subproblemcount < numtocheck )
    3366 {
    3367 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
    3368
    3370 (*solveidx)[(*nsolveidx)] = solvestat->idx;
    3371 (*nsolveidx)++;
    3372
    3373 subproblemcount++;
    3374 }
    3375}
    3376
    3377/** updates the subproblem solving statistics and inserts the indices into the queue */
    3378static
    3380 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3381 int* solveidx, /**< the list of indices of subproblems that were solved */
    3382 int nsolveidx, /**< the number of subproblem indices */
    3383 SCIP_Bool updatestat /**< should the statistics be updated */
    3384 )
    3385{
    3386 int i;
    3387
    3388 assert(benders != NULL);
    3389 assert(solveidx != NULL);
    3390
    3391 for( i = 0; i < nsolveidx; i++ )
    3392 {
    3393 SCIP* subproblem;
    3394 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
    3395
    3396 subproblem = SCIPbendersSubproblem(benders, solveidx[i]);
    3397 solvestat = benders->solvestat[solveidx[i]];
    3398 assert(solvestat->idx == solveidx[i]);
    3399
    3400 /* updating the solving statistics */
    3401 if( updatestat )
    3402 {
    3403 if( !subproblemIsActive(benders, solveidx[i]) || subproblem == NULL )
    3404 solvestat->avgiter = 1;
    3405 else
    3406 solvestat->avgiter = (SCIP_Real)(solvestat->avgiter*solvestat->ncalls + SCIPgetNLPIterations(subproblem))
    3407 /(SCIP_Real)(solvestat->ncalls + 1);
    3408 solvestat->ncalls++;
    3409 }
    3410
    3411 /* inserting the solving statistics into the priority queue */
    3412 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, solvestat) );
    3413 }
    3414
    3415 assert(SCIPpqueueNElems(benders->subprobqueue) == SCIPbendersGetNSubproblems(benders));
    3416
    3417 return SCIP_OKAY;
    3418}
    3419
    3420/** Solves each of the Benders' decomposition subproblems for the given solution. All, or a fraction, of subproblems are
    3421 * solved before the Benders' decomposition cuts are generated.
    3422 * Since a convex relaxation of the subproblem could be solved to generate cuts, a parameter nverified is used to
    3423 * identified the number of subproblems that have been solved in their "original" form. For example, if the subproblem
    3424 * is a MIP, then if the LP is solved to generate cuts, this does not constitute a verification. The verification is
    3425 * only performed when the MIP is solved.
    3427static
    3429 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3430 SCIP_SET* set, /**< global SCIP settings */
    3431 SCIP_SOL* sol, /**< primal CIP solution */
    3432 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3433 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
    3434 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
    3435 int* nverified, /**< the number of subproblems verified in the current loop */
    3436 int* solveidx, /**< the indices of subproblems to be solved in this loop */
    3437 int nsolveidx, /**< the number of subproblems to be solved in this loop */
    3438 SCIP_Bool** subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
    3439 SCIP_BENDERSSUBSTATUS** substatus, /**< array to store the status of the subsystem */
    3440 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
    3441 SCIP_Bool* optimal, /**< is the current solution optimal? */
    3442 SCIP_Bool* stopped /**< was the solving process stopped? */
    3443 )
    3444{
    3445 SCIP_Bool onlyconvexcheck;
    3446 int i;
    3447 int j;
    3448
    3449 SCIP_RETCODE retcode = SCIP_OKAY;
    3450
    3451 assert(benders != NULL);
    3452 assert(set != NULL);
    3453
    3454 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
    3455 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
    3456 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
    3457 * employed.
    3458 */
    3459 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
    3460
    3461 SCIPsetDebugMsg(set, "Performing the subproblem solving process. Number of subproblems to check %d\n", nsolveidx);
    3462
    3463 SCIPsetDebugMsg(set, "Benders' decomposition - solve loop %d\n", solveloop);
    3464
    3465 if( type == SCIP_BENDERSENFOTYPE_CHECK && sol == NULL )
    3466 {
    3467 /* TODO: Check whether this is absolutely necessary. I think that this if statment can be removed. */
    3468 (*infeasible) = TRUE;
    3469 }
    3470 else
    3471 {
    3472 /* solving each of the subproblems for Benders' decomposition */
    3473 /* TODO: ensure that the each of the subproblems solve and update the parameters with the correct return values
    3474 */
    3475 for( j = 0; j < nsolveidx; j++ )
    3476 {
    3477 SCIP_Bool subinfeas = FALSE;
    3478 SCIP_Bool convexsub;
    3479 SCIP_Bool solvesub = TRUE;
    3480 SCIP_Bool solved;
    3481
    3482 i = solveidx[j];
    3484
    3485 /* the subproblem is initially flagged as not solved for this solving loop */
    3486 (*subprobsolved)[i] = FALSE;
    3487
    3488 /* setting the subsystem status to UNKNOWN at the start of each solve loop */
    3489 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
    3490
    3491 /* for the second solving loop, if the problem is an LP, it is not solved again. If the problem is a MIP,
    3492 * then the subproblem objective function value is set to infinity. However, if the subproblem is proven
    3493 * infeasible from the LP, then the IP loop is not performed.
    3494 * If the solve loop is SCIP_BENDERSSOLVELOOP_USERCIP, then nothing is done. It is assumed that the user will
    3495 * correctly update the objective function within the user-defined solving function.
    3496 */
    3497 if( solveloop == SCIP_BENDERSSOLVELOOP_CIP )
    3498 {
    3499 if( convexsub )
    3500 solvesub = FALSE;
    3501 else
    3502 {
    3503 SCIPbendersSetSubproblemObjval(benders, i, SCIPbendersSubproblem(benders, i) != NULL ?
    3505 }
    3506 }
    3507
    3508 /* if the subproblem is independent, then it does not need to be solved. In this case, the nverified flag will
    3509 * increase by one. When the subproblem is not independent, then it needs to be checked.
    3510 */
    3511 if( !subproblemIsActive(benders, i) )
    3512 {
    3513 /* NOTE: There is no need to update the optimal flag. This is because optimal is always TRUE until a
    3514 * non-optimal subproblem is found.
    3515 */
    3516 /* if the auxiliary variable value is infinity, then the subproblem has not been solved yet. Currently the
    3517 * subproblem statue is unknown. */
    3521 {
    3522 SCIPbendersSetSubproblemObjval(benders, i, SCIPbendersSubproblem(benders, i) != NULL ?
    3524
    3525 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
    3526 (*optimal) = FALSE;
    3527
    3528 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, but has not been solved."
    3529 " setting status to UNKNOWN\n", i);
    3530 }
    3531 else
    3532 {
    3534 SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i)) < benders->solutiontol )
    3535 {
    3537 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
    3538 }
    3539 else
    3540 {
    3542 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
    3543 }
    3544
    3545 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, setting status to OPTIMAL\n", i);
    3546 }
    3547
    3548 (*subprobsolved)[i] = TRUE;
    3549
    3550 /* the nverified counter is only increased in the convex solving loop */
    3551 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
    3552 (*nverified)++;
    3553 }
    3554 else if( solvesub )
    3555 {
    3556 retcode = SCIPbendersExecSubproblemSolve(benders, set, sol, i, solveloop, FALSE, &solved, &subinfeas, type);
    3557
    3558 /* the solution for the subproblem is only processed if the return code is SCIP_OKAY */
    3559 if( retcode == SCIP_OKAY )
    3560 {
    3561#ifdef SCIP_DEBUG
    3562 if( type == SCIP_BENDERSENFOTYPE_LP )
    3563 {
    3564 SCIPsetDebugMsg(set, "Enfo LP: Subproblem %d Type %d (%f < %f)\n", i,
    3565 SCIPbendersGetSubproblemType(benders, i), SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i),
    3566 SCIPbendersGetSubproblemObjval(benders, i));
    3567 }
    3568#endif
    3569 (*subprobsolved)[i] = solved;
    3570
    3571 (*infeasible) = (*infeasible) || subinfeas;
    3572 if( subinfeas )
    3573 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_INFEAS;
    3574
    3575 /* if the subproblems are solved to check integer feasibility, then the optimality check must be performed.
    3576 * This will only be performed if checkint is TRUE and the subproblem was solved. The subproblem may not be
    3577 * solved if the user has defined a solving function
    3578 */
    3579 if( checkint && (*subprobsolved)[i] )
    3580 {
    3581 /* if the subproblem is feasible, then it is necessary to update the value of the auxiliary variable to the
    3582 * objective function value of the subproblem.
    3583 */
    3584 if( !subinfeas )
    3585 {
    3586 SCIP_Bool subproboptimal;
    3587
    3588 subproboptimal = SCIPbendersSubproblemIsOptimal(benders, set, sol, i);
    3589
    3590 if( subproboptimal )
    3591 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
    3592 else
    3593 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
    3594
    3595 /* It is only possible to determine the optimality of a solution within a given subproblem in four
    3596 * different cases:
    3597 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is convex.
    3598 * ii) solveloop == SCIP_BENDERSOLVELOOP_CONVEX and only the convex relaxations will be checked.
    3599 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP and the subproblem was solved, since the user has
    3600 * defined a solve function, it is expected that the solving is correctly executed.
    3601 * iv) solveloop == SCIP_BENDERSSOLVELOOP_CIP and the MIP for the subproblem has been solved.
    3602 */
    3603 if( convexsub || onlyconvexcheck
    3604 || solveloop == SCIP_BENDERSSOLVELOOP_CIP
    3605 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
    3606 (*optimal) = (*optimal) && subproboptimal;
    3607
    3608#ifdef SCIP_DEBUG
    3609 if( convexsub || solveloop >= SCIP_BENDERSSOLVELOOP_CIP )
    3610 {
    3611 if( subproboptimal )
    3612 {
    3613 SCIPsetDebugMsg(set, "Subproblem %d is Optimal (%f >= %f)\n", i,
    3615 }
    3616 else
    3617 {
    3618 SCIPsetDebugMsg(set, "Subproblem %d is NOT Optimal (%f < %f)\n", i,
    3620 }
    3621 }
    3622#endif
    3623
    3624 /* the nverified variable is only incremented when the original form of the subproblem has been solved.
    3625 * What is meant by "original" is that the LP relaxation of CIPs are solved to generate valid cuts. So
    3626 * if the subproblem is defined as a CIP, then it is only classified as checked if the CIP is solved.
    3627 * There are three cases where the "original" form is solved are:
    3628 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is an LP
    3629 * - the original form has been solved.
    3630 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP or USERCIP and the CIP for the subproblem has been
    3631 * solved.
    3632 * iii) or, only a convex check is performed.
    3633 */
    3634 if( ((solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX)
    3635 && convexsub)
    3636 || ((solveloop == SCIP_BENDERSSOLVELOOP_CIP || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)
    3637 && !convexsub)
    3638 || onlyconvexcheck )
    3639 (*nverified)++;
    3640 }
    3641 }
    3642 }
    3643 }
    3644
    3645 /* checking whether the limits have been exceeded in the master problem */
    3646 (*stopped) = SCIPisStopped(set->scip);
    3647 }
    3648 }
    3649
    3650 return retcode;
    3651}
    3652
    3653/** Calls the Benders' decompsition cuts for the given solve loop. There are four cases:
    3654 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX - only the LP Benders' cuts are called
    3655 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP - only the CIP Benders' cuts are called
    3656 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX - only the LP Benders' cuts are called
    3657 * iv) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP - only the CIP Benders' cuts are called
    3658 *
    3659 * The priority of the results are: SCIP_CONSADDED (SCIP_SEPARATED), SCIP_DIDNOTFIND, SCIP_FEASIBLE, SCIP_DIDNOTRUN. In
    3660 * this function, there are four levels of results that need to be assessed. These are:
    3661 * i) The result from the individual cut for the subproblem
    3662 * ii) The overall result for the subproblem from all cuts
    3663 * iii) the overall result for the solve loop from all cuts
    3664 * iv) the over all result from all solve loops.
    3665 * In each level, the priority of results must be adhered to.
    3667static
    3669 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3670 SCIP_SET* set, /**< global SCIP settings */
    3671 SCIP_SOL* sol, /**< primal CIP solution */
    3672 SCIP_RESULT* result, /**< result of the pricing process */
    3673 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3674 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
    3675 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
    3676 SCIP_Bool* subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
    3677 SCIP_BENDERSSUBSTATUS* substatus, /**< array to store the status of the subsystem */
    3678 int* solveidx, /**< the indices of subproblems to be solved in this loop */
    3679 int nsolveidx, /**< the number of subproblems to be solved in this loop */
    3680 int** mergecands, /**< the subproblems that are merge candidates */
    3681 int* npriomergecands, /**< the number of priority merge candidates. */
    3682 int* nmergecands, /**< the number of merge candidates. */
    3683 int* nsolveloops /**< the number of solve loops, is updated w.r.t added cuts */
    3684 )
    3685{
    3686 SCIP_BENDERSCUT** benderscuts;
    3687 SCIP_RESULT solveloopresult;
    3688 int nbenderscuts;
    3689 SCIP_Longint addedcuts = 0;
    3690 int i;
    3691 int j;
    3692 int k;
    3693 SCIP_Bool onlyconvexcheck;
    3694
    3695 assert(benders != NULL);
    3696 assert(set != NULL);
    3697
    3698 /* getting the Benders' decomposition cuts */
    3699 benderscuts = SCIPbendersGetBenderscuts(benders);
    3700 nbenderscuts = SCIPbendersGetNBenderscuts(benders);
    3701
    3702 solveloopresult = SCIP_DIDNOTRUN;
    3703
    3704 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
    3705 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
    3706 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
    3707 * employed.
    3708 */
    3709 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
    3710
    3711 /* It is only possible to add cuts to the problem if it has not already been solved */
    3714 && (benders->cutcheck || type != SCIP_BENDERSENFOTYPE_CHECK) )
    3715 {
    3716 /* This is done in two loops. The first is by subproblem and the second is by cut type. */
    3717 for( k = 0; k < nsolveidx; k++ )
    3718 {
    3719 SCIP_RESULT subprobresult;
    3720 SCIP_Bool convexsub;
    3721
    3722 i = solveidx[k];
    3723
    3725
    3726 /* cuts can only be generated if the subproblem is not independent and if it has been solved. Additionally, the
    3727 * status of the subproblem solving must not be INFEASIBLE while in a cut strengthening round.
    3728 * The subproblem solved flag is important for the user-defined subproblem solving methods
    3729 */
    3730 if( subproblemIsActive(benders, i) && subprobsolved[i]
    3731 && !(substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS && benders->strengthenround) )
    3732 {
    3733 subprobresult = SCIP_DIDNOTRUN;
    3734 for( j = 0; j < nbenderscuts; j++ )
    3735 {
    3736 SCIP_RESULT cutresult;
    3737 SCIP_Longint prevaddedcuts;
    3738
    3739 assert(benderscuts[j] != NULL);
    3740
    3741 prevaddedcuts = SCIPbenderscutGetNFound(benderscuts[j]);
    3742 cutresult = SCIP_DIDNOTRUN;
    3743
    3744 /* the result is updated only if a Benders' cut is generated or one was not found. However, if a cut has
    3745 * been found in a previous iteration, then the result is returned as SCIP_CONSADDED or SCIP_SEPARATED.
    3746 * This result is permitted because if a constraint was added, the solution that caused the error in the cut
    3747 * generation will be cutoff from the master problem.
    3748 */
    3749 if( (SCIPbenderscutIsLPCut(benderscuts[j]) && (solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
    3750 || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX))
    3751 || (!SCIPbenderscutIsLPCut(benderscuts[j]) && ((solveloop == SCIP_BENDERSSOLVELOOP_CIP && !convexsub)
    3752 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)) )
    3753 SCIP_CALL( SCIPbenderscutExec(benderscuts[j], set, benders, sol, i, type, &cutresult) );
    3754
    3755 addedcuts += (SCIPbenderscutGetNFound(benderscuts[j]) - prevaddedcuts);
    3756
    3757 /* the result is updated only if a Benders' cut is generated */
    3758 if( cutresult == SCIP_CONSADDED || cutresult == SCIP_SEPARATED )
    3759 {
    3760 subprobresult = cutresult;
    3761
    3762 benders->ncutsfound++;
    3763
    3764 /* at most a single cut is generated for each subproblem */
    3765 break;
    3766 }
    3767 else
    3768 {
    3769 /* checking from lowest priority result */
    3770 if( subprobresult == SCIP_DIDNOTRUN )
    3771 subprobresult = cutresult;
    3772 else if( subprobresult == SCIP_FEASIBLE && cutresult == SCIP_DIDNOTFIND )
    3773 subprobresult = cutresult;
    3774 /* if the subprobresult is SCIP_DIDNOTFIND, then it can't be updated. */
    3775 }
    3776 }
    3777
    3778 /* the highest priority for the results is CONSADDED and SEPARATED. The solveloopresult will always be
    3779 * updated if the subprobresult is either of these.
    3780 */
    3781 if( subprobresult == SCIP_CONSADDED || subprobresult == SCIP_SEPARATED )
    3782 {
    3783 solveloopresult = subprobresult;
    3784 }
    3785 else if( subprobresult == SCIP_FEASIBLE )
    3786 {
    3787 /* updating the solve loop result based upon the priority */
    3788 if( solveloopresult == SCIP_DIDNOTRUN )
    3789 solveloopresult = subprobresult;
    3790 }
    3791 else if( subprobresult == SCIP_DIDNOTFIND )
    3792 {
    3793 /* updating the solve loop result based upon the priority */
    3794 if( solveloopresult == SCIP_DIDNOTRUN || solveloopresult == SCIP_FEASIBLE )
    3795 solveloopresult = subprobresult;
    3796
    3797 /* since a cut was not found, then merging could be useful to avoid this in subsequent iterations. The
    3798 * candidate is labelled as a non-priority merge candidate
    3799 */
    3800 if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
    3801 {
    3802 (*mergecands)[(*nmergecands)] = i;
    3803 (*nmergecands)++;
    3804 }
    3805 }
    3806 else if( subprobresult == SCIP_DIDNOTRUN )
    3807 {
    3808 /* if the subproblem is infeasible and no cut generation methods were run, then the infeasibility will
    3809 * never be resolved. As such, the subproblem will be merged into the master problem. If the subproblem
    3810 * was not infeasible, then it is added as a possible merge candidate
    3811 */
    3812 if( substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS )
    3813 {
    3814 (*mergecands)[(*nmergecands)] = (*mergecands)[(*npriomergecands)];
    3815 (*mergecands)[(*npriomergecands)] = i;
    3816 (*npriomergecands)++;
    3817 (*nmergecands)++;
    3818 }
    3819 else if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
    3820 {
    3821 (*mergecands)[(*nmergecands)] = i;
    3822 (*nmergecands)++;
    3823 }
    3824 }
    3825 }
    3826 }
    3827 }
    3828
    3829 /* updating the overall result based upon the priorities */
    3830 if( solveloopresult == SCIP_CONSADDED || solveloopresult == SCIP_SEPARATED )
    3831 {
    3832 (*result) = solveloopresult;
    3833 }
    3834 else if( solveloopresult == SCIP_FEASIBLE )
    3835 {
    3836 /* updating the solve loop result based upon the priority */
    3837 if( (*result) == SCIP_DIDNOTRUN )
    3838 (*result) = solveloopresult;
    3839 }
    3840 else if( solveloopresult == SCIP_DIDNOTFIND )
    3841 {
    3842 /* updating the solve loop result based upon the priority */
    3843 if( (*result) == SCIP_DIDNOTRUN || (*result) == SCIP_FEASIBLE )
    3844 (*result) = solveloopresult;
    3845 }
    3846
    3847 /* if no cuts were added, then the number of solve loops is increased */
    3848 if( addedcuts == 0 && SCIPbendersGetNConvexSubproblems(benders) < SCIPbendersGetNSubproblems(benders)
    3849 && checkint && !onlyconvexcheck )
    3850 (*nsolveloops) = 2;
    3851
    3852 return SCIP_OKAY;
    3853}
    3854
    3855/** Solves the subproblem using the current master problem solution.
    3856 *
    3857 * The checkint flag indicates whether integer feasibility can be assumed. If it is not assumed, i.e. checkint ==
    3858 * FALSE, then only the convex relaxations of the subproblems are solved. If integer feasibility is assumed, i.e.
    3859 * checkint == TRUE, then the convex relaxations and the full CIP are solved to generate Benders' cuts and check
    3860 * solution feasibility.
    3861 *
    3862 * TODO: consider allowing the possibility to pass solution information back from the subproblems instead of the scip
    3863 * instance. This would allow the use of different solvers for the subproblems, more importantly allowing the use of an
    3864 * LP solver for LP subproblems.
    3865 */
    3867 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3868 SCIP_SET* set, /**< global SCIP settings */
    3869 SCIP_SOL* sol, /**< primal CIP solution */
    3870 SCIP_RESULT* result, /**< result of the pricing process */
    3871 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
    3872 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
    3873 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3874 SCIP_Bool checkint /**< should the integer solution be checked by the subproblems */
    3875 )
    3876{
    3877 int nsubproblems;
    3878 int subproblemcount;
    3879 int nsolveloops;
    3880 int nverified;
    3881 int nsolved;
    3882 int* mergecands;
    3883 int npriomergecands;
    3884 int nmergecands;
    3885 int* solveidx;
    3886 int* executedidx;
    3887 int nsolveidx;
    3888 int nexecutedidx;
    3889 int nfree;
    3890 SCIP_Bool* subprobsolved;
    3891 SCIP_BENDERSSUBSTATUS* substatus;
    3892 SCIP_Bool optimal;
    3893 SCIP_Bool allverified;
    3894 SCIP_Bool success;
    3895 SCIP_Bool stopped;
    3896 int i;
    3897 int l;
    3898
    3899 success = TRUE;
    3900 stopped = FALSE;
    3901
    3902 SCIPsetDebugMsg(set, "Starting Benders' decomposition subproblem solving. type %d checkint %u\n", type, checkint);
    3903
    3904#ifdef SCIP_MOREDEBUG
    3905 SCIP_CALL( SCIPprintSol(set->scip, sol, NULL, FALSE) );
    3906#endif
    3907
    3908 /* start timing */
    3909 SCIPclockStart(benders->bendersclock, set);
    3910
    3911 nsubproblems = SCIPbendersGetNSubproblems(benders);
    3912
    3913 (*auxviol) = FALSE;
    3914 (*infeasible) = FALSE;
    3915
    3916 /* It is assumed that the problem is optimal, until a subproblem is found not to be optimal. However, not all
    3917 * subproblems could be checked in each iteration. As such, it is not possible to state that the problem is optimal
    3918 * if not all subproblems are checked. Situations where this may occur is when a subproblem is a MIP and only the LP
    3919 * is solved. Also, in a distributed computation, then it may be advantageous to only solve some subproblems before
    3920 * resolving the master problem. As such, for a problem to be optimal, then (optimal && allverified) == TRUE
    3921 */
    3922 optimal = TRUE;
    3923 nverified = 0;
    3924 nsolved = 0;
    3925
    3926 assert(benders != NULL);
    3927 assert(result != NULL);
    3928 assert(infeasible != NULL);
    3929 assert(auxviol != NULL);
    3930
    3931 /* if the Benders' decomposition is called from a sub-SCIP and the sub-SCIPs have been deactivated, then it is
    3932 * assumed that this is an LNS heuristic. As such, the check is not performed and the solution is assumed to be
    3933 * feasible
    3934 */
    3935 if( benders->iscopy && set->subscipsoff
    3936 && (!benders->lnscheck
    3937 || (benders->lnsmaxdepth > -1 && SCIPgetDepth(benders->sourcescip) >= benders->lnsmaxdepth)
    3938 || (benders->lnsmaxcalls > -1 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcalls)
    3939 || (type != SCIP_BENDERSENFOTYPE_CHECK && SCIPgetDepth(set->scip) == 0 && benders->lnsmaxcallsroot > -1
    3940 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcallsroot)) )
    3941 {
    3942 (*result) = SCIP_DIDNOTRUN;
    3943 return SCIP_OKAY;
    3944 }
    3945
    3946 /* it is not necessary to check all primal solutions by solving the Benders' decomposition subproblems.
    3947 * Only the improving solutions are checked to improve efficiency of the algorithm.
    3948 * If the solution is non-improving, the result FEASIBLE is returned. While this may be incorrect w.r.t to the
    3949 * Benders' subproblems, this solution will never be the optimal solution. A non-improving solution may be used
    3950 * within LNS primal heuristics. If this occurs, the improving solution, if found, will be checked by the solving
    3951 * the Benders' decomposition subproblems.
    3952 * TODO: Add a parameter to control this behaviour.
    3953 */
    3954 if( checkint && SCIPsetIsLE(set, SCIPgetPrimalbound(set->scip)*(int)SCIPgetObjsense(set->scip),
    3955 SCIPgetSolOrigObj(set->scip, sol)*(int)SCIPgetObjsense(set->scip)) )
    3956 {
    3957 (*result) = SCIP_DIDNOTRUN;
    3958 return SCIP_OKAY;
    3959 }
    3960
    3961 /* if the enforcement type is SCIP_BENDERSENFOTYPE_LP and the LP is currently unbounded. This could mean that there
    3962 * is no lower bound on the auxiliary variables. In this case, we try to update the lower bound for the auxiliary
    3963 * variables.
    3964 */
    3966 && benders->updateauxvarbound )
    3967 {
    3968 SCIP_CALL( updateAuxiliaryVarLowerbound(benders, set, result) );
    3969
    3970 /* the auxiliary variable bound will only be updated once. */
    3971 benders->updateauxvarbound = FALSE;
    3972 }
    3973
    3974 /* sets the stored objective function values of the subproblems to infinity */
    3976
    3977 *result = SCIP_DIDNOTRUN;
    3978
    3979 if( benders->benderspresubsolve != NULL && !benders->strengthenround )
    3980 {
    3981 SCIP_Bool skipsolve;
    3982
    3983 skipsolve = FALSE;
    3984 SCIP_CALL( benders->benderspresubsolve(set->scip, benders, sol, type, checkint, infeasible, auxviol, &skipsolve,
    3985 result) );
    3986
    3987 /* evaluate result */
    3988 if( (*result) != SCIP_DIDNOTRUN
    3989 && (*result) != SCIP_FEASIBLE
    3990 && (*result) != SCIP_INFEASIBLE
    3991 && (*result) != SCIP_CONSADDED
    3992 && (*result) != SCIP_SEPARATED )
    3993 {
    3994 SCIPerrorMessage("the user-defined pre subproblem solving method for the Benders' decomposition <%s> returned "
    3995 "invalid result <%d>\n", benders->name, *result);
    3996 return SCIP_INVALIDRESULT;
    3997 }
    3998
    3999 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
    4000 if( skipsolve )
    4001 {
    4002 SCIPsetDebugMsg(set, "skipping the subproblem solving for Benders' decomposition <%s>. "
    4003 "returning result <%d>\n", benders->name, *result);
    4004 return SCIP_OKAY;
    4005 }
    4006 }
    4007
    4008 /* the cut strengthening is performed before the regular subproblem solve is called. To avoid recursion, the flag
    4009 * strengthenround is set to TRUE when the cut strengthening is performed. The cut strengthening is not performed as
    4010 * part of the large neighbourhood Benders' search.
    4011 *
    4012 * NOTE: cut strengthening is only applied for fractional solutions and integer solutions if there are no CIP
    4013 * subproblems.
    4014 */
    4015 if( benders->strengthenenabled && !benders->strengthenround && !benders->iscopy
    4016 && (!checkint || SCIPbendersGetNConvexSubproblems(benders) == SCIPbendersGetNSubproblems(benders)) )
    4017 {
    4018 SCIP_Bool skipsolve;
    4019
    4020 benders->strengthenround = TRUE;
    4021 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
    4022 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, FALSE, infeasible, auxviol,
    4023 &skipsolve, result) );
    4024 benders->strengthenround = FALSE;
    4025
    4026 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
    4027 if( skipsolve )
    4028 {
    4029 SCIPsetDebugMsg(set, "skipping the subproblem solving because cut strengthening found a cut "
    4030 "for Benders' decomposition <%s>. Returning result <%d>\n", benders->name, *result);
    4031 return SCIP_OKAY;
    4032 }
    4033
    4034 /* the result flag need to be reset to DIDNOTRUN for the main subproblem solve */
    4035 (*result) = SCIP_DIDNOTRUN;
    4036 }
    4037
    4038 /* allocating memory for the infeasible subproblem array */
    4039 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &subprobsolved, nsubproblems) );
    4040 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &substatus, nsubproblems) );
    4041 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &mergecands, nsubproblems) );
    4042 npriomergecands = 0;
    4043 nmergecands = 0;
    4044
    4045 /* allocating the memory for the subproblem solving and cut generation indices */
    4046 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &solveidx, nsubproblems) );
    4047 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &executedidx, nsubproblems) );
    4048 nsolveidx = 0;
    4049 nexecutedidx = 0;
    4050
    4051 /* only a subset of the subproblems are initially solved. Both solving loops are executed for the subproblems to
    4052 * check whether any cuts are generated. If a cut is generated, then no further subproblems are solved. If a cut is
    4053 * not generated, then an additional set of subproblems are solved.
    4054 */
    4055 while( nsolved < nsubproblems )
    4056 {
    4057 /* getting the indices for the subproblems that will be solved */
    4058 createSolveSubproblemIndexList(benders, set, type, &solveidx, &nsolveidx);
    4059
    4060 /* by default the number of solve loops is 1. This is the case if all subproblems are LP or the user has defined a
    4061 * benderssolvesub callback. If there is a subproblem that is not an LP, then 2 solve loops are performed. The first
    4062 * loop is the LP solving loop, the second solves the subproblem to integer optimality.
    4063 */
    4064 nsolveloops = 1;
    4065
    4066 for( l = 0; l < nsolveloops; l++ )
    4067 {
    4068 SCIP_BENDERSSOLVELOOP solveloop; /* identifies what problem type is solve in this solve loop */
    4069
    4070 /* if either benderssolvesubconvex or benderssolvesub are implemented, then the user callbacks are invoked */
    4071 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL )
    4072 {
    4073 if( l == 0 )
    4075 else
    4077 }
    4078 else
    4079 solveloop = (SCIP_BENDERSSOLVELOOP) l;
    4080
    4081 /* solving the subproblems for this round of enforcement/checking. */
    4082 SCIP_CALL( solveBendersSubproblems(benders, set, sol, type, solveloop, checkint, &nverified,
    4083 solveidx, nsolveidx, &subprobsolved, &substatus, infeasible, &optimal, &stopped) );
    4084
    4085 /* if the solving has been stopped, then the subproblem solving and cut generation must terminate */
    4086 if( stopped )
    4087 break;
    4088
    4089 /* Generating cuts for the subproblems. Cuts are only generated when the solution is from primal heuristics,
    4090 * relaxations or the LP
    4091 */
    4092 if( type != SCIP_BENDERSENFOTYPE_PSEUDO )
    4093 {
    4094 SCIP_CALL( generateBendersCuts(benders, set, sol, result, type, solveloop, checkint, subprobsolved,
    4095 substatus, solveidx, nsolveidx, &mergecands, &npriomergecands, &nmergecands, &nsolveloops) );
    4096 }
    4097 else
    4098 {
    4099 /* The first solving loop solves the convex subproblems and the convex relaxations of the CIP subproblems. The
    4100 * second solving loop solves the CIP subproblems. The second solving loop is only called if the integer
    4101 * feasibility is being checked and if the convex subproblems and convex relaxations are not infeasible.
    4102 */
    4103 if( !(*infeasible) && checkint && !SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set))
    4105 nsolveloops = 2;
    4106 }
    4107 }
    4108
    4109 nsolved += nsolveidx;
    4110
    4111 /* storing the indices of the subproblems for which the solving loop was executed */
    4112 for( i = 0; i < nsolveidx; i++ )
    4113 executedidx[nexecutedidx++] = solveidx[i];
    4114
    4115 /* if the result is CONSADDED or SEPARATED, then a cut is generated and no further subproblem processing is
    4116 * required
    4117 */
    4118 if( (*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED )
    4119 break;
    4120 }
    4121
    4122 /* inserting the subproblems into the priority queue for the next solve call */
    4123 SCIP_CALL( updateSubproblemStatQueue(benders, executedidx, nexecutedidx, TRUE) );
    4124
    4125 if( stopped ) /*lint !e774*/
    4126 goto TERMINATE;
    4127
    4128 allverified = (nverified == nsubproblems);
    4129
    4130 SCIPsetDebugMsg(set, "End Benders' decomposition subproblem solve. result %d infeasible %u auxviol %u nverified %d\n",
    4131 *result, *infeasible, *auxviol, nverified);
    4132
    4133#ifdef SCIP_DEBUG
    4134 if( (*result) == SCIP_CONSADDED )
    4135 {
    4136 SCIPsetDebugMsg(set, "Benders' decomposition: Cut added\n");
    4137 }
    4138#endif
    4139
    4140 /* if the number of checked pseudo solutions exceeds a set limit, then all subproblems are passed as merge
    4141 * candidates. Currently, merging subproblems into the master problem is the only method for resolving numerical
    4142 * troubles.
    4143 *
    4144 * We are only interested in the pseudo solutions that have been checked completely for integrality. This is
    4145 * identified by checkint == TRUE. This means that the Benders' decomposition constraint is one of the last
    4146 * constraint handlers that must resolve the infeasibility. If the Benders' decomposition framework can't resolve the
    4147 * infeasibility, then this will result in an error.
    4148 */
    4149 if( type == SCIP_BENDERSENFOTYPE_PSEUDO && checkint )
    4150 {
    4151 benders->npseudosols++;
    4152
    4153 if( benders->npseudosols > BENDERS_MAXPSEUDOSOLS )
    4154 {
    4155 /* if a priority merge candidate already exists, then no other merge candidates need to be added.*/
    4156 if( npriomergecands == 0 )
    4157 {
    4158 /* all subproblems are added to the merge candidate list. The first active subproblem is added as a
    4159 * priority merge candidate
    4160 */
    4161 nmergecands = 0;
    4162 npriomergecands = 1;
    4163 for( i = 0; i < nsubproblems; i++ )
    4164 {
    4165 /* only active subproblems are added to the merge candidate list */
    4166 if( subproblemIsActive(benders, i) )
    4167 {
    4168 mergecands[nmergecands] = i;
    4169 nmergecands++;
    4170 }
    4171 }
    4172
    4173 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " The number of checked pseudo solutions exceeds the "
    4174 "limit of %d. All active subproblems are merge candidates, with subproblem %d a priority candidate.\n",
    4175 BENDERS_MAXPSEUDOSOLS, mergecands[0]);
    4176 }
    4177 }
    4178 }
    4179 else
    4180 benders->npseudosols = 0;
    4181
    4182 /* if the result is SCIP_DIDNOTFIND, then there was a error in generating cuts in all subproblems that are not
    4183 * optimal. This result does not cutoff any solution, so the Benders' decomposition algorithm will fail.
    4184 *
    4185 * It could happen that the cut strengthening approach causes an error the cut generation. In this case, an error
    4186 * should not be thrown. So, this check will be skipped when in a strengthening round.
    4187 * TODO: Work out a way to ensure Benders' decomposition does not terminate due to a SCIP_DIDNOTFIND result.
    4188 */
    4189 if( (*result) == SCIP_DIDNOTFIND && !benders->strengthenround )
    4190 {
    4191 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
    4192 (*result) = SCIP_SOLVELP;
    4193 else
    4194 (*result) = SCIP_INFEASIBLE;
    4195
    4196 SCIPerrorMessage("An error was found when generating cuts for non-optimal subproblems of Benders' "
    4197 "decomposition <%s>. Consider merging the infeasible subproblems into the master problem.\n", SCIPbendersGetName(benders));
    4198
    4199 /* since no other cuts are generated, then this error will result in a crash. It is possible to avoid the error,
    4200 * by merging the affected subproblem into the master problem.
    4201 *
    4202 * NOTE: If the error occurs while checking solutions, i.e. SCIP_BENDERSENFOTYPE_CHECK, then it is valid to set
    4203 * the result to SCIP_INFEASIBLE and the success flag to TRUE
    4204 */
    4205 if( type != SCIP_BENDERSENFOTYPE_CHECK )
    4206 success = FALSE;
    4207
    4208 goto POSTSOLVE;
    4209 }
    4210
    4211 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
    4212 {
    4213 if( (*infeasible) || !allverified )
    4214 (*result) = SCIP_SOLVELP;
    4215 else
    4216 {
    4217 (*result) = SCIP_FEASIBLE;
    4218
    4219 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
    4220 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
    4221 * TRUE.
    4222 */
    4223 (*auxviol) = !optimal;
    4224 }
    4225 }
    4226 else if( checkint && (type == SCIP_BENDERSENFOTYPE_CHECK
    4227 || ((*result) != SCIP_CONSADDED && (*result) != SCIP_SEPARATED)) )
    4228 {
    4229 /* if the subproblems are being solved as part of conscheck, then the results flag must be returned after the solving
    4230 * has completed.
    4231 */
    4232 if( (*infeasible) || !allverified )
    4233 (*result) = SCIP_INFEASIBLE;
    4234 else
    4235 {
    4236 (*result) = SCIP_FEASIBLE;
    4237
    4238 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
    4239 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
    4240 * TRUE.
    4241 */
    4242 (*auxviol) = !optimal;
    4243 }
    4244 }
    4245
    4246POSTSOLVE:
    4247 /* calling the post-solve call back for the Benders' decomposition algorithm. This allows the user to work directly
    4248 * with the solved subproblems and the master problem */
    4249 if( benders->benderspostsolve != NULL )
    4250 {
    4251 SCIP_Bool merged;
    4252
    4253 merged = FALSE;
    4254
    4255 SCIP_CALL( benders->benderspostsolve(set->scip, benders, sol, type, mergecands, npriomergecands, nmergecands,
    4256 checkint, (*infeasible), &merged) );
    4257
    4258 if( merged )
    4259 {
    4260 (*result) = SCIP_CONSADDED;
    4261
    4262 /* since subproblems have been merged, then constraints have been added. This could resolve the unresolved
    4263 * infeasibility, so the error has been corrected.
    4264 */
    4265 success = TRUE;
    4266 }
    4267 else if( !success )
    4268 {
    4269 SCIPerrorMessage("An error occurred during Benders' decomposition cut generations and no merging had been "
    4270 "performed. It is not possible to continue solving the problem by Benders' decomposition\n");
    4271 }
    4272 }
    4273
    4274TERMINATE:
    4275 /* if the solving process has stopped, then all subproblems need to be freed */
    4276 if( stopped ) /*lint !e774*/
    4277 nfree = nsubproblems;
    4278 else
    4279 nfree = nexecutedidx;
    4280
    4281 /* freeing the subproblems after the cuts are generated */
    4282 subproblemcount = 0;
    4283 while( subproblemcount < nfree )
    4284 {
    4285 int subidx;
    4286
    4287 if( stopped )
    4288 subidx = subproblemcount;
    4289 else
    4290 subidx = executedidx[subproblemcount];
    4291
    4292 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, subidx) );
    4293
    4294 subproblemcount++;
    4295 }
    4296
    4297#ifndef NDEBUG
    4298 for( i = 0; i < nsubproblems; i++ )
    4299 assert(SCIPbendersSubproblem(benders, i) == NULL
    4301 || !SCIPinProbing(SCIPbendersSubproblem(benders, i))
    4302 || !subproblemIsActive(benders, i));
    4303#endif
    4304
    4305 /* increment the number of calls to the Benders' decomposition subproblem solve */
    4306 benders->ncalls++;
    4307
    4308 SCIPsetDebugMsg(set, "End Benders' decomposition execution method. result %d infeasible %u auxviol %u\n", *result,
    4309 *infeasible, *auxviol);
    4310
    4311 /* end timing */
    4312 SCIPclockStop(benders->bendersclock, set);
    4313
    4314 /* freeing memory */
    4315 SCIPfreeBlockMemoryArray(set->scip, &executedidx, nsubproblems);
    4316 SCIPfreeBlockMemoryArray(set->scip, &solveidx, nsubproblems);
    4317 SCIPfreeBlockMemoryArray(set->scip, &mergecands, nsubproblems);
    4318 SCIPfreeBlockMemoryArray(set->scip, &substatus, nsubproblems);
    4319 SCIPfreeBlockMemoryArray(set->scip, &subprobsolved, nsubproblems);
    4320
    4321 /* if there was an error in generating cuts and merging was not performed, then the solution is perturbed in an
    4322 * attempt to generate a cut and correct the infeasibility
    4323 */
    4324 if( !success && !stopped )
    4325 {
    4326 SCIP_Bool skipsolve;
    4327 SCIP_RESULT perturbresult;
    4328
    4329 skipsolve = FALSE;
    4330
    4331 benders->strengthenround = TRUE;
    4332 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
    4333 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, TRUE, infeasible, auxviol,
    4334 &skipsolve, &perturbresult) );
    4335 benders->strengthenround = FALSE;
    4336
    4337 if( perturbresult == SCIP_CONSADDED || perturbresult == SCIP_SEPARATED )
    4338 (*result) = perturbresult;
    4339
    4340 success = skipsolve;
    4341 }
    4342
    4343 /* if the Benders' decomposition subproblem check stopped, then we don't have a valid result. In this case, the
    4344 * safest thing to do is report INFEASIBLE.
    4345 */
    4346 if( stopped )
    4347 (*result) = SCIP_INFEASIBLE;
    4348
    4349 /* if the subproblem verification identifies the solution as feasible, then a check whether slack variables have been
    4350 * used is necessary. If any slack variables are non-zero, then the solution is reverified after the objective
    4351 * coefficient for the slack variables is increased.
    4352 */
    4353 if( (*result) == SCIP_FEASIBLE )
    4354 {
    4355 SCIP_Bool activeslack;
    4356
    4357 SCIP_CALL( SCIPbendersSolSlackVarsActive(benders, &activeslack) );
    4358 SCIPsetDebugMsg(set, "Type: %d Active slack: %u Feasibility Phase: %u\n", type, activeslack,
    4359 benders->feasibilityphase);
    4360 if( activeslack )
    4361 {
    4362 if( type == SCIP_BENDERSENFOTYPE_CHECK )
    4363 (*result) = SCIP_INFEASIBLE;
    4364 else
    4365 {
    4366 /* increasing the value of the slack variable by a factor of 10 */
    4367 benders->slackvarcoef *= 10.0;
    4368
    4369 if( benders->slackvarcoef <= benders->maxslackvarcoef )
    4370 {
    4371 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Increasing the slack variable coefficient to %g.\n", benders->slackvarcoef);
    4372 }
    4373 else
    4374 {
    4375 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Fixing the slack variables to zero.\n");
    4376 }
    4377
    4378 /* resolving the subproblems with an increased slack variable */
    4379 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
    4380 }
    4381 }
    4382 else if( benders->feasibilityphase )
    4383 {
    4384 if( type != SCIP_BENDERSENFOTYPE_CHECK )
    4385 {
    4386 /* disabling the feasibility phase */
    4387 benders->feasibilityphase = FALSE;
    4388
    4389 /* resolving the subproblems with the slack variables set to zero */
    4390 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
    4391 }
    4392 }
    4393 }
    4394
    4395 if( !success )
    4396 return SCIP_ERROR;
    4397 else
    4398 return SCIP_OKAY;
    4399}
    4400
    4401/** solves the user-defined subproblem solving function */
    4402static
    4404 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4405 SCIP_SET* set, /**< global SCIP settings */
    4406 SCIP_SOL* sol, /**< primal CIP solution */
    4407 int probnumber, /**< the subproblem number */
    4408 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
    4409 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
    4410 SCIP_Real* objective, /**< the objective function value of the subproblem */
    4411 SCIP_RESULT* result /**< the result from solving the subproblem */
    4412 )
    4413{
    4414 assert(benders != NULL);
    4415 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    4416 assert(benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL);
    4417
    4418 assert(solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP);
    4419
    4420 (*objective) = -SCIPsetInfinity(set);
    4421
    4422 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
    4423 * Neighbourhood Benders' Search. */
    4424 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
    4425 {
    4426 if( benders->benderssolvesubconvex != NULL )
    4427 {
    4428 SCIP_CALL( benders->benderssolvesubconvex(set->scip, benders, sol, probnumber,
    4429 SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set)), objective, result) );
    4430 }
    4431 else
    4432 (*result) = SCIP_DIDNOTRUN;
    4433 }
    4434 else if( solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
    4435 {
    4436 if( benders->benderssolvesub != NULL )
    4437 {
    4438 SCIP_CALL( benders->benderssolvesub(set->scip, benders, sol, probnumber, objective, result) );
    4439 }
    4440 else
    4441 (*result) = SCIP_DIDNOTRUN;
    4442 }
    4443
    4444 /* evaluate result */
    4445 if( (*result) != SCIP_DIDNOTRUN
    4446 && (*result) != SCIP_FEASIBLE
    4447 && (*result) != SCIP_INFEASIBLE
    4448 && (*result) != SCIP_UNBOUNDED )
    4449 {
    4450 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned invalid result <%d>\n",
    4451 benders->name, *result);
    4452 return SCIP_INVALIDRESULT;
    4453 }
    4454
    4455 if( (*result) == SCIP_INFEASIBLE )
    4456 (*infeasible) = TRUE;
    4457
    4458 if( (*result) == SCIP_FEASIBLE
    4459 && (SCIPsetIsInfinity(set, -(*objective)) || SCIPsetIsInfinity(set, (*objective))) )
    4460 {
    4461 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned objective value %g\n",
    4462 benders->name, (*objective));
    4463 return SCIP_ERROR;
    4464 }
    4465
    4466 /* if the result is SCIP_DIDNOTFIND, then an error is returned and SCIP will terminate. */
    4467 if( (*result) == SCIP_DIDNOTFIND )
    4468 return SCIP_ERROR;
    4469 else
    4470 return SCIP_OKAY;
    4471}
    4473/** executes the subproblem solving process */
    4475 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4476 SCIP_SET* set, /**< global SCIP settings */
    4477 SCIP_SOL* sol, /**< primal CIP solution */
    4478 int probnumber, /**< the subproblem number */
    4479 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
    4480 SCIP_Bool enhancement, /**< is the solve performed as part of and enhancement? */
    4481 SCIP_Bool* solved, /**< flag to indicate whether the subproblem was solved */
    4482 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
    4483 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
    4484 )
    4485{ /*lint --e{715}*/
    4486 SCIP* subproblem;
    4487 SCIP_RESULT result;
    4488 SCIP_Real objective;
    4489 SCIP_STATUS solvestatus = SCIP_STATUS_UNKNOWN;
    4490
    4491 assert(benders != NULL);
    4492 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    4493
    4494 SCIPsetDebugMsg(set, "Benders' decomposition: solving subproblem %d\n", probnumber);
    4495
    4496 result = SCIP_DIDNOTRUN;
    4497 objective = SCIPsetInfinity(set);
    4498
    4499 subproblem = SCIPbendersSubproblem(benders, probnumber);
    4500
    4501 if( subproblem == NULL && (benders->benderssolvesubconvex == NULL || benders->benderssolvesub == NULL) )
    4502 {
    4503 SCIPerrorMessage("The subproblem %d is set to NULL, but both bendersSolvesubconvex%s and bendersSolvesub%s "
    4504 "are not defined.\n", probnumber, benders->name, benders->name);
    4505 SCIPABORT();
    4506 return SCIP_ERROR;
    4507 }
    4508
    4509 /* initially setting the solved flag to FALSE */
    4510 (*solved) = FALSE;
    4511
    4512 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
    4513 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
    4514 {
    4515 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
    4516 * Neighbourhood Benders' Search. */
    4517 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &objective, &result) );
    4518
    4519 /* if the result is DIDNOTRUN, then the subproblem was not solved */
    4520 (*solved) = (result != SCIP_DIDNOTRUN);
    4521 }
    4522 else if( subproblem != NULL )
    4523 {
    4524 /* setting up the subproblem */
    4525 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX )
    4526 {
    4527 SCIP_CALL( SCIPbendersSetupSubproblem(benders, set, sol, probnumber, type) );
    4528
    4529 /* if the limits of the master problem were hit during the setup process, then the subproblem will not have
    4530 * been setup. In this case, the solving function must be exited.
    4531 */
    4532 if( !SCIPbendersSubproblemIsSetup(benders, probnumber) )
    4533 {
    4534 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4535 (*solved) = FALSE;
    4536 return SCIP_OKAY;
    4537 }
    4538 }
    4539 else
    4540 {
    4541 SCIP_CALL( updateEventhdlrUpperbound(benders, probnumber, SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber)) );
    4542 }
    4543
    4544 /* solving the subproblem
    4545 * the LP of the subproblem is solved in the first solveloop.
    4546 * In the second solve loop, the MIP problem is solved */
    4547 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
    4549 {
    4550 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &objective) );
    4551
    4552 /* if the (N)LP was solved without error, then the subproblem is labelled as solved */
    4553 if( solvestatus == SCIP_STATUS_OPTIMAL || solvestatus == SCIP_STATUS_INFEASIBLE )
    4554 (*solved) = TRUE;
    4555
    4556 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4557 (*infeasible) = TRUE;
    4558 }
    4559 else
    4560 {
    4561 SCIP_SOL* bestsol;
    4562
    4563 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
    4564
    4565 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4566 (*infeasible) = TRUE;
    4567
    4568 /* if the generic subproblem solving methods are used, then the CIP subproblems are always solved. */
    4569 (*solved) = TRUE;
    4570
    4571 bestsol = SCIPgetBestSol(subproblem);
    4572 if( bestsol != NULL )
    4573 objective = SCIPgetSolOrigObj(subproblem, bestsol)*(int)SCIPgetObjsense(set->scip);
    4574 else
    4575 objective = SCIPsetInfinity(set);
    4576 }
    4577 }
    4578 else
    4579 {
    4580 SCIPABORT();
    4581 }
    4582
    4583 if( !enhancement )
    4584 {
    4585 /* The following handles the cases when the subproblem is OPTIMAL, INFEASIBLE and UNBOUNDED.
    4586 * If a subproblem is unbounded, then the auxiliary variables are set to -infinity and the unbounded flag is
    4587 * returned as TRUE. No cut will be generated, but the result will be set to SCIP_FEASIBLE.
    4588 */
    4589 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_CIP )
    4590 {
    4591 /* TODO: Consider whether other solutions status should be handled */
    4592 if( solvestatus == SCIP_STATUS_OPTIMAL )
    4593 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
    4594 else if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4595 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4596 else if( solvestatus == SCIP_STATUS_USERINTERRUPT || solvestatus == SCIP_STATUS_BESTSOLLIMIT )
    4597 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
    4598 else if( solvestatus == SCIP_STATUS_MEMLIMIT || solvestatus == SCIP_STATUS_TIMELIMIT
    4599 || solvestatus == SCIP_STATUS_UNKNOWN )
    4600 {
    4601 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving "
    4602 "subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
    4603 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4604 }
    4605 else if( solvestatus == SCIP_STATUS_UNBOUNDED )
    4606 {
    4607 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    4608 probnumber);
    4609 SCIPABORT();
    4610 }
    4611 else
    4612 {
    4613 SCIPerrorMessage("Invalid status returned from solving Benders' decomposition subproblem %d. Solution status: %d\n",
    4614 probnumber, solvestatus);
    4615 SCIPABORT();
    4616 }
    4617 }
    4618 else
    4619 {
    4620 assert(solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP);
    4621 if( result == SCIP_FEASIBLE )
    4622 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
    4623 else if( result == SCIP_INFEASIBLE )
    4624 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4625 else if( result == SCIP_UNBOUNDED )
    4626 {
    4627 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    4628 probnumber);
    4629 SCIPABORT();
    4630 }
    4631 else if( result != SCIP_DIDNOTRUN )
    4632 {
    4633 SCIPerrorMessage("Invalid result <%d> from user-defined subproblem solving method. This should not happen.\n",
    4634 result);
    4635 }
    4636 }
    4637 }
    4638
    4639 return SCIP_OKAY;
    4640}
    4642/** sets up the subproblem using the solution to the master problem */
    4644 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4645 SCIP_SET* set, /**< global SCIP settings */
    4646 SCIP_SOL* sol, /**< primal CIP solution */
    4647 int probnumber, /**< the subproblem number */
    4648 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
    4649 )
    4650{
    4651 SCIP* subproblem;
    4652 SCIP_VAR** vars;
    4653 SCIP_VAR* mastervar;
    4654 SCIP_Real solval;
    4655 int nvars;
    4656 int i;
    4657
    4658 assert(benders != NULL);
    4659 assert(set != NULL);
    4660 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    4661
    4662 subproblem = SCIPbendersSubproblem(benders, probnumber);
    4663
    4664 /* the subproblem setup can only be performed if the subproblem is not NULL */
    4665 if( subproblem == NULL )
    4666 {
    4667 SCIPerrorMessage("The subproblem %d is NULL. Thus, the subproblem setup must be performed manually in either "
    4668 "bendersSolvesubconvex%s or bendersSolvesub%s.\n", probnumber, benders->name, benders->name);
    4669 return SCIP_ERROR;
    4670 }
    4671 assert(subproblem != NULL);
    4672
    4673 /* changing all of the master problem variable to continuous. */
    4674 SCIP_CALL( SCIPbendersChgMastervarsToCont(benders, set, probnumber) );
    4675
    4676 /* if the Benders' decomposition subproblem is convex and has continuous variables, then probing mode
    4677 * must be started.
    4678 * If the subproblem contains non-convex constraints or discrete variables, then the problem must be initialised,
    4679 * and then put into SCIP_STAGE_SOLVING to be able to change the variable bounds. The probing mode is entered once
    4680 * the variable bounds are set.
    4681 * In the latter case, the transformed problem is freed after each subproblem solve round. */
    4683 {
    4684 SCIP_CALL( SCIPstartProbing(subproblem) );
    4685 }
    4686 else
    4687 {
    4688 SCIP_Bool infeasible;
    4689 SCIP_Bool success;
    4690
    4691 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, &infeasible, &success) );
    4692 assert(success == !infeasible);
    4693
    4694 /* if the problem is identified as infeasible, this means that the underlying LP is infeasible. Since no variable
    4695 * fixings have been applied at this stage, this means that the complete problem is infeasible. It is only
    4696 * possible to set this parameter if we are at the root node or in an initialisation stage.
    4697 */
    4698 if( infeasible )
    4700
    4701 if( !success )
    4702 {
    4703 /* set the flag to indicate that the subproblems have been set up */
    4704 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
    4705
    4706 return SCIP_OKAY;
    4707 }
    4708 }
    4709
    4710 vars = SCIPgetVars(subproblem);
    4711 nvars = SCIPgetNVars(subproblem);
    4712
    4713 /* looping over all variables in the subproblem to find those corresponding to the master problem variables. */
    4714 /* TODO: It should be possible to store the pointers to the master variables to speed up the subproblem setup */
    4715 for( i = 0; i < nvars; i++ )
    4716 {
    4717 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
    4718
    4719 if( mastervar != NULL )
    4720 {
    4721 /* It is possible due to numerics that the solution value exceeds the upper or lower bounds. When this
    4722 * happens, it causes an error in the LP solver as a result of inconsistent bounds. So the following statements
    4723 * are used to ensure that the bounds are not exceeded when applying the fixings for the Benders'
    4724 * decomposition subproblems
    4725 */
    4726 solval = SCIPgetSolVal(set->scip, sol, mastervar);
    4727 if( !SCIPisLT(set->scip, solval, SCIPvarGetUbLocal(vars[i])) )
    4728 solval = SCIPvarGetUbLocal(vars[i]);
    4729 else if( !SCIPisGT(set->scip, solval, SCIPvarGetLbLocal(vars[i])) )
    4730 solval = SCIPvarGetLbLocal(vars[i]);
    4731
    4732 /* fixing the variable in the subproblem */
    4733 if( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) )
    4734 {
    4735 if( SCIPisGT(subproblem, solval, SCIPvarGetLbLocal(vars[i])) )
    4736 {
    4737 SCIP_CALL( SCIPchgVarLb(subproblem, vars[i], solval) );
    4738 }
    4739 if( SCIPisLT(subproblem, solval, SCIPvarGetUbLocal(vars[i])) )
    4740 {
    4741 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], solval) );
    4742 }
    4743 }
    4744
    4745 assert(SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])));
    4746 }
    4747 else if( strstr(SCIPvarGetName(vars[i]), SLACKVAR_NAME) != NULL )
    4748 {
    4749 /* if the slack variables have been added to help improve feasibility, then they remain unfixed with a large
    4750 * objective coefficient. Once the root node has been solved to optimality, then the slack variables are
    4751 * fixed to zero.
    4752 */
    4753 if( benders->feasibilityphase && SCIPgetDepth(set->scip) == 0 && type != SCIP_BENDERSENFOTYPE_CHECK )
    4754 {
    4755 /* The coefficient update or variable fixing can only be performed if the subproblem is in probing mode.
    4756 * If the slack var coef gets very large, then we fix the slack variable to 0 instead.
    4757 */
    4758 if( SCIPinProbing(subproblem) )
    4759 {
    4760 if( benders->slackvarcoef <= benders->maxslackvarcoef )
    4761 {
    4762 SCIP_CALL( SCIPchgVarObjProbing(subproblem, vars[i], benders->slackvarcoef) );
    4763 }
    4764 else
    4765 {
    4766 SCIP_CALL( SCIPchgVarUbProbing(subproblem, vars[i], 0.0) );
    4767 }
    4768 }
    4769 }
    4770 else
    4771 {
    4772 /* if the subproblem is non-linear and convex, then slack variables have been added to the subproblem. These
    4773 * need to be fixed to zero when first solving the subproblem. However, if the slack variables have been added
    4774 * by setting the execfeasphase runtime parameter, then they must not get fixed to zero
    4775 */
    4776 assert( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) );
    4777 assert( SCIPisZero(subproblem, SCIPvarGetLbLocal(vars[i])) );
    4778
    4779 if( SCIPisLT(subproblem, 0.0, SCIPvarGetUbLocal(vars[i])) )
    4780 {
    4781 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], 0.0) );
    4782 }
    4783 }
    4784 }
    4785 }
    4786
    4787 /* if the subproblem contain non-convex constraints or discrete variables, then the probing mode is entered after
    4788 * setting up the subproblem
    4789 */
    4791 {
    4792 SCIP_CALL( SCIPstartProbing(subproblem) );
    4793 }
    4794
    4795 /* set the flag to indicate that the subproblems have been set up */
    4796 SCIPbendersSetSubproblemIsSetup(benders, probnumber, TRUE);
    4797
    4798 return SCIP_OKAY;
    4799}
    4800
    4801/** Solve a Benders' decomposition subproblems. This will either call the user defined method or the generic solving
    4802 * methods. If the generic method is called, then the subproblem must be set up before calling this method. */
    4804 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4805 SCIP_SET* set, /**< global SCIP settings */
    4806 SCIP_SOL* sol, /**< primal CIP solution, can be NULL */
    4807 int probnumber, /**< the subproblem number */
    4808 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
    4809 SCIP_Bool solvecip, /**< directly solve the CIP subproblem */
    4810 SCIP_Real* objective /**< the objective function value of the subproblem, can be NULL */
    4811 )
    4812{
    4813 assert(benders != NULL);
    4814 assert(set != NULL);
    4815 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    4816
    4817 assert(infeasible != NULL);
    4818 (*infeasible) = FALSE;
    4819
    4820 /* the subproblem must be set up before this function is called. */
    4821 if( SCIPbendersSubproblem(benders, probnumber) != NULL && !SCIPbendersSubproblemIsSetup(benders, probnumber)
    4822 && !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
    4823 {
    4824 SCIPerrorMessage("Benders' decomposition subproblem %d must be set up before calling SCIPbendersSolveSubproblem(). Call SCIPsetupSubproblem() first.\n", probnumber);
    4825 return SCIP_ERROR;
    4826 }
    4827
    4828 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
    4829 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL)
    4830 {
    4831 SCIP_BENDERSSOLVELOOP solveloop;
    4832 SCIP_RESULT result;
    4833 SCIP_Real subobj;
    4834
    4835 if( solvecip )
    4837 else
    4839
    4840 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &subobj, &result) );
    4841
    4842 if( objective != NULL )
    4843 (*objective) = subobj;
    4844 }
    4845 else
    4846 {
    4847 SCIP* subproblem;
    4848
    4849 subproblem = SCIPbendersSubproblem(benders, probnumber);
    4850 assert(subproblem != NULL);
    4851
    4852 /* solving the subproblem */
    4853 if( solvecip && SCIPbendersGetSubproblemType(benders, probnumber) != SCIP_BENDERSSUBTYPE_CONVEXCONT )
    4854 {
    4855 SCIP_STATUS solvestatus;
    4856
    4857 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, solvecip) );
    4858
    4859 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4860 (*infeasible) = TRUE;
    4861 if( objective != NULL )
    4862 (*objective) = SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem);
    4863 }
    4864 else
    4865 {
    4866 SCIP_Bool success;
    4867
    4868 /* if the subproblem has convex constraints and continuous variables, then it should have been initialised and
    4869 * in SCIP_STAGE_SOLVING. In this case, the subproblem only needs to be put into probing mode.
    4870 */
    4872 {
    4873 /* if the subproblem is not in probing mode, then it must be put into that mode for the LP solve. */
    4874 if( !SCIPinProbing(subproblem) )
    4875 {
    4876 SCIP_CALL( SCIPstartProbing(subproblem) );
    4877 }
    4878
    4879 success = TRUE;
    4880 }
    4881 else
    4882 {
    4883 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
    4884 }
    4885
    4886 /* if setting up the subproblem was successful */
    4887 if( success )
    4888 {
    4889 SCIP_STATUS solvestatus;
    4890 SCIP_Real lpobjective;
    4891
    4892 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &lpobjective) );
    4893
    4894 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4895 (*infeasible) = TRUE;
    4896 else if( objective != NULL )
    4897 (*objective) = lpobjective;
    4898 }
    4899 else
    4900 {
    4901 if( objective != NULL )
    4902 (*objective) = SCIPinfinity(subproblem);
    4903 }
    4904 }
    4905 }
    4906
    4907 return SCIP_OKAY;
    4908}
    4909
    4910/** copies the time and memory limit from the master problem to the subproblem */
    4911static
    4913 SCIP* scip, /**< the SCIP data structure */
    4914 SCIP* subproblem /**< the Benders' decomposition subproblem */
    4915 )
    4916{
    4917 SCIP_Real mastertimelimit;
    4918 SCIP_Real subtimelimit;
    4919 SCIP_Real maxsubtimelimit;
    4920 SCIP_Real mastermemorylimit;
    4921 SCIP_Real submemorylimit;
    4922 SCIP_Real maxsubmemorylimit;
    4923
    4924 assert(scip != NULL);
    4925
    4926 /* setting the time limit for the Benders' decomposition subproblems. It is set to 102% of the remaining time. */
    4927 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &mastertimelimit) );
    4928 maxsubtimelimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/time"));
    4929 subtimelimit = (mastertimelimit - SCIPgetSolvingTime(scip)) * 1.02;
    4930 subtimelimit = MIN(subtimelimit, maxsubtimelimit);
    4931 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", MAX(0.0, subtimelimit)) );
    4932
    4933 /* setting the memory limit for the Benders' decomposition subproblems. */
    4934 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &mastermemorylimit) );
    4935 maxsubmemorylimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/memory"));
    4936 submemorylimit = mastermemorylimit - (SCIPgetMemUsed(scip) + SCIPgetMemExternEstim(scip))/1048576.0;
    4937 submemorylimit = MIN(submemorylimit, maxsubmemorylimit);
    4938 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", MAX(0.0, submemorylimit)) );
    4939
    4940 return SCIP_OKAY;
    4941}
    4942
    4943/** stores the original parameters from the subproblem */
    4944static
    4946 SCIP* subproblem, /**< the SCIP data structure */
    4947 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
    4948 )
    4949{
    4950 assert(subproblem != NULL);
    4951 assert(origparams != NULL);
    4952
    4953 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &origparams->limits_memory) );
    4954 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &origparams->limits_time) );
    4955 SCIP_CALL( SCIPgetBoolParam(subproblem, "conflict/enable", &origparams->conflict_enable) );
    4956 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &origparams->lp_disablecutoff) );
    4957 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/scaling", &origparams->lp_scaling) );
    4958 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/initalgorithm", &origparams->lp_initalg) );
    4959 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/resolvealgorithm", &origparams->lp_resolvealg) );
    4960 SCIP_CALL( SCIPgetBoolParam(subproblem, "lp/alwaysgetduals", &origparams->lp_alwaysgetduals) );
    4961 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/scaleobj", &origparams->misc_scaleobj) );
    4962 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/catchctrlc", &origparams->misc_catchctrlc) );
    4963 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxrounds", &origparams->prop_maxrounds) );
    4964 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxroundsroot", &origparams->prop_maxroundsroot) );
    4965 SCIP_CALL( SCIPgetIntParam(subproblem, "constraints/linear/propfreq", &origparams->cons_linear_propfreq) );
    4966
    4967 return SCIP_OKAY;
    4968}
    4969
    4970/** sets the parameters for the subproblem */
    4971static
    4973 SCIP* scip, /**< the SCIP data structure */
    4974 SCIP* subproblem /**< the subproblem SCIP instance */
    4975 )
    4976{
    4977 assert(scip != NULL);
    4978 assert(subproblem != NULL);
    4979
    4980 /* copying memory and time limits */
    4981 SCIP_CALL( copyMemoryAndTimeLimits(scip, subproblem) );
    4982
    4983 /* Do we have to disable presolving? If yes, we have to store all presolving parameters. */
    4985
    4986 /* Disabling heuristics so that the problem is not trivially solved */
    4988
    4989 /* store parameters that are changed for the generation of the subproblem cuts */
    4990 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", FALSE) );
    4991
    4992 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
    4993 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", 0) );
    4994
    4995 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", 'd') );
    4996 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", 'd') );
    4997
    4998 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", TRUE) );
    4999 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", FALSE) );
    5000
    5001 /* do not abort subproblem on CTRL-C */
    5002 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", FALSE) );
    5003
    5004#ifndef SCIP_MOREDEBUG
    5005 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
    5006#endif
    5007
    5008 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", 0) );
    5009 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", 0) );
    5010
    5011 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", -1) );
    5012
    5013 SCIP_CALL( SCIPsetIntParam(subproblem, "heuristics/alns/freq", -1) );
    5014
    5015 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/aggregation/freq", -1) );
    5016 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/gomory/freq", -1) );
    5017
    5018 return SCIP_OKAY;
    5019}
    5020
    5021/** resets the original parameters from the subproblem */
    5022static
    5024 SCIP* subproblem, /**< the SCIP data structure */
    5025 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
    5026 )
    5027{
    5028 assert(subproblem != NULL);
    5029 assert(origparams != NULL);
    5030
    5031 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", origparams->limits_memory) );
    5032 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", origparams->limits_time) );
    5033 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", origparams->conflict_enable) );
    5034 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", origparams->lp_disablecutoff) );
    5035 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", origparams->lp_scaling) );
    5036 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", origparams->lp_initalg) );
    5037 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", origparams->lp_resolvealg) );
    5038 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", origparams->lp_alwaysgetduals) );
    5039 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", origparams->misc_scaleobj) );
    5040 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", origparams->misc_catchctrlc) );
    5041 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", origparams->prop_maxrounds) );
    5042 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", origparams->prop_maxroundsroot) );
    5043 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", origparams->cons_linear_propfreq) );
    5044
    5045 return SCIP_OKAY;
    5046}
    5048/** returns NLP solver parameters used for solving NLP subproblems */
    5050 SCIP_BENDERS* benders /**< Benders' decomposition */
    5051 )
    5052{
    5053 assert(benders != NULL);
    5054
    5055 return benders->nlpparam;
    5056}
    5057
    5058/** solves the LP of the Benders' decomposition subproblem
    5059 *
    5060 * This requires that the subproblem is in probing mode.
    5061 */
    5063 SCIP* scip, /**< the SCIP data structure */
    5064 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
    5065 int probnumber, /**< the subproblem number */
    5066 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
    5067 SCIP_Real* objective /**< optimal value of subproblem, if solved to optimality */
    5068 )
    5069{
    5070 SCIP* subproblem;
    5071 SCIP_SUBPROBPARAMS* origparams;
    5072 SCIP_Bool solvenlp;
    5073
    5074 assert(benders != NULL);
    5075 assert(solvestatus != NULL);
    5076 assert(objective != NULL);
    5077 assert(SCIPbendersSubproblemIsSetup(benders, probnumber));
    5078
    5079 /* TODO: This should be solved just as an LP, so as a MIP. There is too much overhead with the MIP.
    5080 * Need to change status check for checking the LP. */
    5081 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5082 assert(subproblem != NULL);
    5083
    5084 /* only solve the NLP relaxation if the NLP has been constructed and there exists an NLPI. If it is not possible to
    5085 * solve the NLP relaxation, then the LP relaxation is used to generate Benders' cuts
    5086 */
    5087 solvenlp = FALSE;
    5088 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
    5090 solvenlp = TRUE;
    5091
    5092 *objective = SCIPinfinity(subproblem);
    5093
    5094 assert(SCIPisNLPConstructed(subproblem) || SCIPisLPConstructed(subproblem));
    5095 assert(SCIPinProbing(subproblem));
    5096
    5097 /* allocating memory for the parameter storage */
    5098 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
    5099
    5100 /* store the original parameters of the subproblem */
    5101 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
    5102
    5103 /* setting the subproblem parameters */
    5104 SCIP_CALL( setSubproblemParams(scip, subproblem) );
    5105
    5106 if( solvenlp )
    5107 {
    5108 SCIP_NLPSOLSTAT nlpsolstat;
    5109 SCIP_NLPTERMSTAT nlptermstat;
    5110#ifdef SCIP_MOREDEBUG
    5111 SCIP_SOL* nlpsol;
    5112#endif
    5113
    5114 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
    5115
    5116 nlpsolstat = SCIPgetNLPSolstat(subproblem);
    5117 nlptermstat = SCIPgetNLPTermstat(subproblem);
    5118 SCIPdebugMsg(scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
    5119
    5120 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
    5121 {
    5122 /* trust infeasible only if terminated "okay" */
    5123 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
    5124 }
    5125 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT
    5126 || nlpsolstat == SCIP_NLPSOLSTAT_FEASIBLE )
    5127 {
    5128#ifdef SCIP_MOREDEBUG
    5129 SCIP_CALL( SCIPcreateNLPSol(subproblem, &nlpsol, NULL) );
    5130 SCIP_CALL( SCIPprintSol(subproblem, nlpsol, NULL, FALSE) );
    5131 SCIP_CALL( SCIPfreeSol(subproblem, &nlpsol) );
    5132#endif
    5133
    5134 (*solvestatus) = SCIP_STATUS_OPTIMAL;
    5135 (*objective) = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
    5136 }
    5137 else if( nlpsolstat == SCIP_NLPSOLSTAT_UNBOUNDED )
    5138 {
    5139 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
    5140 SCIPerrorMessage("The NLP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    5141 probnumber);
    5142 SCIPABORT();
    5143 }
    5144 else if( nlptermstat == SCIP_NLPTERMSTAT_TIMELIMIT )
    5145 {
    5146 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
    5147 }
    5148 else if( nlptermstat == SCIP_NLPTERMSTAT_ITERLIMIT)
    5149 {
    5150 /* this is an approximation in lack of a better fitting SCIP_STATUS */
    5151 SCIPwarningMessage(scip, "The NLP solver stopped due to an iteration limit for Benders' decomposition subproblem %d. Consider increasing benders/%s/nlpiterlimit.\n", probnumber, SCIPbendersGetName(benders));
    5152 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
    5153 }
    5154 else if( nlptermstat == SCIP_NLPTERMSTAT_INTERRUPT )
    5155 {
    5156 (*solvestatus) = SCIP_STATUS_USERINTERRUPT;
    5157 }
    5158 else
    5159 {
    5160 SCIPerrorMessage("Invalid solution status: %d. Termination status: %d. Solving the NLP relaxation of Benders' decomposition subproblem %d.\n",
    5161 nlpsolstat, nlptermstat, probnumber);
    5162 SCIPABORT();
    5163 }
    5164 }
    5165 else
    5166 {
    5167 SCIP_Bool lperror;
    5168 SCIP_Bool cutoff;
    5169
    5170 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
    5171
    5172 switch( SCIPgetLPSolstat(subproblem) )
    5173 {
    5175 {
    5176 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
    5177 break;
    5178 }
    5179
    5181 {
    5182 (*solvestatus) = SCIP_STATUS_OPTIMAL;
    5183 (*objective) = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(scip);
    5184 break;
    5185 }
    5186
    5188 {
    5189 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
    5190 SCIPerrorMessage("The LP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    5191 probnumber);
    5192 SCIPABORT();
    5193 break;
    5194 }
    5195
    5199 {
    5200 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_TIMELIMIT )
    5201 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
    5202 else
    5203 (*solvestatus) = SCIP_STATUS_UNKNOWN;
    5204
    5205 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving LP "
    5206 "relaxation of subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
    5207 break;
    5208 }
    5209
    5212 default:
    5213 {
    5214 SCIPerrorMessage("Invalid status: %d. Solving the LP relaxation of Benders' decomposition subproblem %d.\n",
    5215 SCIPgetLPSolstat(subproblem), probnumber);
    5216 SCIPABORT();
    5217 break;
    5218 }
    5219 }
    5220 }
    5221
    5222 /* resetting the subproblem parameters */
    5223 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
    5224
    5225 /* freeing the parameter storage */
    5226 SCIPfreeBlockMemory(subproblem, &origparams);
    5227
    5228 return SCIP_OKAY;
    5229}
    5231/** solves the Benders' decomposition subproblem */
    5233 SCIP* scip, /**< the SCIP data structure */
    5234 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
    5235 int probnumber, /**< the subproblem number */
    5236 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
    5237 SCIP_Bool solvecip /**< directly solve the CIP subproblem */
    5238 )
    5239{
    5240 SCIP* subproblem;
    5241 SCIP_SUBPROBPARAMS* origparams;
    5242
    5243 assert(benders != NULL);
    5244 assert(solvestatus != NULL);
    5245
    5246 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5247 assert(subproblem != NULL);
    5248
    5249 /* allocating memory for the parameter storage */
    5250 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
    5251
    5252 /* store the original parameters of the subproblem */
    5253 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
    5254
    5255 /* If the solve has been stopped for the subproblem, then we need to restart it to complete the solve. The subproblem
    5256 * is stopped when it is a MIP so that LP cuts and IP cuts can be generated. */
    5257 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING )
    5258 {
    5259 /* the subproblem should be in probing mode. Otherwise, the event handler did not work correctly */
    5260 assert( SCIPinProbing(subproblem) );
    5261
    5262 /* the probing mode needs to be stopped so that the MIP can be solved */
    5263 SCIP_CALL( SCIPendProbing(subproblem) );
    5264
    5265 /* the problem was interrupted in the event handler, so SCIP needs to be informed that the problem is to be restarted */
    5266 SCIP_CALL( SCIPrestartSolve(subproblem) );
    5267 }
    5268 else if( solvecip )
    5269 {
    5270 /* if the MIP will be solved directly, then the probing mode needs to be skipped.
    5271 * This is achieved by setting the solvecip flag in the event handler data to TRUE
    5272 */
    5273 SCIP_EVENTHDLR* eventhdlr;
    5274 SCIP_EVENTHDLRDATA* eventhdlrdata;
    5275
    5276 eventhdlr = SCIPfindEventhdlr(subproblem, MIPNODEFOCUS_EVENTHDLR_NAME);
    5277 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    5278
    5279 eventhdlrdata->solvecip = TRUE;
    5280 }
    5281 else
    5282 {
    5283 /* if the problem is not in probing mode, then we need to solve the LP. That requires all methods that will
    5284 * modify the structure of the problem need to be deactivated */
    5285
    5286 /* setting the subproblem parameters */
    5287 SCIP_CALL( setSubproblemParams(scip, subproblem) );
    5288
    5289#ifdef SCIP_EVENMOREDEBUG
    5290 SCIP_CALL( SCIPsetBoolParam(subproblem, "display/lpinfo", TRUE) );
    5291#endif
    5292 }
    5293
    5294#ifdef SCIP_MOREDEBUG
    5295 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_FULL) );
    5296 SCIP_CALL( SCIPsetIntParam(subproblem, "display/freq", 1) );
    5297#endif
    5298
    5299 SCIP_CALL( SCIPsolve(subproblem) );
    5300
    5301 *solvestatus = SCIPgetStatus(subproblem);
    5302
    5303 if( *solvestatus != SCIP_STATUS_OPTIMAL && *solvestatus != SCIP_STATUS_UNBOUNDED
    5304 && *solvestatus != SCIP_STATUS_INFEASIBLE && *solvestatus != SCIP_STATUS_USERINTERRUPT
    5305 && *solvestatus != SCIP_STATUS_BESTSOLLIMIT && *solvestatus != SCIP_STATUS_TIMELIMIT
    5306 && *solvestatus != SCIP_STATUS_MEMLIMIT )
    5307 {
    5308 SCIPerrorMessage("Invalid status: %d. Solving the CIP of Benders' decomposition subproblem %d.\n",
    5309 *solvestatus, probnumber);
    5310 SCIPABORT();
    5311 }
    5312
    5313 /* resetting the subproblem parameters */
    5314 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
    5315
    5316 /* freeing the parameter storage */
    5317 SCIPfreeBlockMemory(subproblem, &origparams);
    5318
    5319 return SCIP_OKAY;
    5320}
    5322/** frees the subproblems */
    5324 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5325 SCIP_SET* set, /**< global SCIP settings */
    5326 int probnumber /**< the subproblem number */
    5327 )
    5328{
    5329 assert(benders != NULL);
    5330 assert(benders->bendersfreesub != NULL
    5331 || (benders->bendersfreesub == NULL && benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL));
    5332 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    5333
    5334 if( benders->bendersfreesub != NULL )
    5335 {
    5336 SCIP_CALL( benders->bendersfreesub(set->scip, benders, probnumber) );
    5337 }
    5338 else
    5339 {
    5340 /* the subproblem is only freed if it is not independent */
    5341 if( subproblemIsActive(benders, probnumber) )
    5342 {
    5343 SCIP* subproblem = SCIPbendersSubproblem(benders, probnumber);
    5344
    5346 {
    5347 /* ending probing mode to reset the current node. The probing mode will be restarted at the next solve */
    5348 if( SCIPinProbing(subproblem) )
    5349 {
    5350 SCIP_CALL( SCIPendProbing(subproblem) );
    5351 }
    5352 }
    5353 else
    5354 {
    5355 /* if the subproblems were solved as part of an enforcement stage, then they will still be in probing mode. The
    5356 * probing mode must first be finished and then the problem can be freed */
    5357 if( SCIPgetStage(subproblem) >= SCIP_STAGE_TRANSFORMED && SCIPinProbing(subproblem) )
    5358 {
    5359 SCIP_CALL( SCIPendProbing(subproblem) );
    5360 }
    5361
    5362 SCIP_CALL( SCIPfreeTransform(subproblem) );
    5363 }
    5364 }
    5365 }
    5366
    5367 /* setting the setup flag for the subproblem to FALSE */
    5368 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
    5369 return SCIP_OKAY;
    5370}
    5372/** compares the subproblem objective value with the auxiliary variable value for optimality */
    5374 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    5375 SCIP_SET* set, /**< global SCIP settings */
    5376 SCIP_SOL* sol, /**< primal CIP solution */
    5377 int probnumber /**< the subproblem number */
    5378 )
    5379{
    5380 SCIP_Real auxiliaryvarval;
    5381 SCIP_Bool optimal;
    5382
    5383 assert(benders != NULL);
    5384 assert(set != NULL);
    5385 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    5386
    5387 optimal = FALSE;
    5388
    5389 auxiliaryvarval = SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber);
    5390
    5391 SCIPsetDebugMsg(set, "Subproblem %d - Auxiliary Variable: %g Subproblem Objective: %g Reldiff: %g Soltol: %g\n",
    5392 probnumber, auxiliaryvarval, SCIPbendersGetSubproblemObjval(benders, probnumber),
    5393 SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval), benders->solutiontol);
    5394
    5395 if( SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval) < benders->solutiontol )
    5396 optimal = TRUE;
    5397
    5398 return optimal;
    5399}
    5401/** returns the value of the auxiliary variable value in a master problem solution */
    5403 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    5404 SCIP_SET* set, /**< global SCIP settings */
    5405 SCIP_SOL* sol, /**< primal CIP solution */
    5406 int probnumber /**< the subproblem number */
    5407 )
    5408{
    5409 SCIP_VAR* auxiliaryvar;
    5410
    5411 assert(benders != NULL);
    5412 assert(set != NULL);
    5413
    5414 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    5415 assert(auxiliaryvar != NULL);
    5416
    5417 return SCIPgetSolVal(set->scip, sol, auxiliaryvar);
    5418}
    5419
    5420/** Solves an independent subproblem to identify its lower bound. The lower bound is then used to update the bound on
    5421 * the auxiliary variable.
    5422 */
    5424 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5425 SCIP_SET* set, /**< global SCIP settings */
    5426 int probnumber, /**< the subproblem to be evaluated */
    5427 SCIP_Real* lowerbound, /**< the lowerbound for the subproblem */
    5428 SCIP_Bool* infeasible /**< was the subproblem found to be infeasible? */
    5429 )
    5430{
    5431 SCIP* subproblem;
    5432 SCIP_Real dualbound;
    5433 SCIP_Real memorylimit;
    5434 SCIP_Real timelimit;
    5435 SCIP_Longint totalnodes;
    5436 int disablecutoff;
    5437 int verblevel;
    5438 SCIP_Bool lperror;
    5439 SCIP_Bool cutoff;
    5440
    5441 assert(benders != NULL);
    5442 assert(set != NULL);
    5443
    5444 if( benders->benderssolvesub != NULL || benders->benderssolvesubconvex != NULL )
    5445 {
    5446 (*lowerbound) = SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber));
    5447 (*infeasible) = FALSE;
    5448
    5449 SCIPinfoMessage(set->scip, NULL, "Benders' decomposition: a bendersSolvesub or bendersSolvesubconvex has been "
    5450 "implemented. SCIPbendersComputeSubproblemLowerbound can not be executed.\n");
    5451 SCIPinfoMessage(set->scip, NULL, "Set the auxiliary variable lower bound by calling "
    5452 "SCIPbendersUpdateSubproblemLowerbound in bendersCreatesub. The auxiliary variable %d will remain as %g\n",
    5453 probnumber, (*lowerbound));
    5454
    5455 return SCIP_OKAY;
    5456 }
    5457 else
    5458 {
    5459 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Computing a lower bound for"
    5460 " subproblem %d\n", probnumber);
    5461 }
    5462
    5463 /* getting the subproblem to evaluate */
    5464 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5465
    5466 (*lowerbound) = -SCIPinfinity(subproblem);
    5467 (*infeasible) = FALSE;
    5468
    5469 SCIP_CALL( SCIPgetIntParam(subproblem, "display/verblevel", &verblevel) );
    5470 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
    5471#ifdef SCIP_MOREDEBUG
    5472 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_HIGH) );
    5473#endif
    5474
    5475 /* copying memory and time limits */
    5476 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &timelimit) );
    5477 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &memorylimit) );
    5478 SCIP_CALL( copyMemoryAndTimeLimits(set->scip, subproblem) );
    5479
    5480 /* if the subproblem is independent, then the default SCIP settings are used. Otherwise, only the root node is solved
    5481 * to compute a lower bound on the subproblem
    5482 */
    5483 SCIP_CALL( SCIPgetLongintParam(subproblem, "limits/totalnodes", &totalnodes) );
    5484 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &disablecutoff) );
    5485 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
    5486 {
    5487 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", 1LL) );
    5488 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
    5489 }
    5490
    5491 /* if the subproblem not independent and is convex, then the probing LP is solved. Otherwise, the MIP is solved */
    5492 dualbound = -SCIPinfinity(subproblem);
    5494 {
    5495 SCIP_Bool solvenlp = FALSE;
    5496
    5497 assert(SCIPisLPConstructed(subproblem) || SCIPisNLPConstructed(subproblem));
    5498
    5499 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
    5501 solvenlp = TRUE;
    5502
    5503 SCIP_CALL( SCIPstartProbing(subproblem) );
    5504 if( solvenlp )
    5505 {
    5506 SCIP_NLPSOLSTAT nlpsolstat;
    5507 SCIP_NLPTERMSTAT nlptermstat;
    5508
    5509 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
    5510
    5511 nlpsolstat = SCIPgetNLPSolstat(subproblem);
    5512 nlptermstat = SCIPgetNLPTermstat(subproblem);
    5513 SCIPdebugMsg(set->scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
    5514
    5515 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
    5516 {
    5517 /* trust infeasible only if terminated "okay" */
    5518 (*infeasible) = TRUE;
    5519 }
    5520 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT )
    5521 {
    5522 dualbound = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
    5523 }
    5524 }
    5525 else
    5526 {
    5527 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
    5528
    5529 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_INFEASIBLE )
    5530 (*infeasible) = TRUE;
    5531 else if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL )
    5532 dualbound = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(set->scip);
    5533 }
    5534 }
    5535 else
    5536 {
    5537 SCIP_EVENTHDLRDATA* eventhdlrdata;
    5538
    5539 /* if the subproblem is not convex, then event handlers have been added to interrupt the solve. These must be
    5540 * disabled
    5541 */
    5543 eventhdlrdata->solvecip = TRUE;
    5544
    5545 SCIP_CALL( SCIPsolve(subproblem) );
    5546
    5547 if( SCIPgetStatus(subproblem) == SCIP_STATUS_INFEASIBLE )
    5548 (*infeasible) = TRUE;
    5549 else
    5550 dualbound = SCIPgetDualbound(subproblem);
    5551 }
    5552
    5553 /* getting the lower bound value */
    5554 (*lowerbound) = dualbound;
    5555
    5556 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
    5557 {
    5558 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", totalnodes) );
    5559 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", disablecutoff) );
    5560 }
    5561 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", verblevel) );
    5562 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", memorylimit) );
    5563 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", timelimit) );
    5564
    5565 /* the subproblem must be freed so that it is reset for the subsequent Benders' decomposition solves. If the
    5566 * subproblems are independent, they are not freed. SCIPfreeBendersSubproblem must still be called, but in this
    5567 * function the independent subproblems are not freed. However, they will still be freed at the end of the
    5568 * solving process for the master problem.
    5569 */
    5570 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
    5571
    5572 return SCIP_OKAY;
    5573}
    5574
    5575/** Merges a subproblem into the master problem. This process just adds a copy of the subproblem variables and
    5576 * constraints to the master problem, but keeps the subproblem stored in the Benders' decomposition data structure. The reason for
    5577 * keeping the subproblem available is for when it is queried for solutions after the problem is solved.
    5578 *
    5579 * Once the subproblem is merged into the master problem, then the subproblem is flagged as disabled. This means that
    5580 * it will not be solved in the subsequent subproblem solving loops.
    5581 *
    5582 * The associated auxiliary variables are kept in the master problem. The objective function of the merged subproblem
    5583 * is added as an underestimator constraint.
    5584 */
    5586 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5587 SCIP_SET* set, /**< global SCIP settings */
    5588 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of subproblem variables corresponding
    5589 * to the newly created master variables, or NULL */
    5590 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of subproblem constraints to the
    5591 * corresponding newly created constraints, or NULL */
    5592 int probnumber /**< the number of the subproblem that will be merged into the master problem*/
    5593 )
    5594{
    5595 SCIP* subproblem;
    5596 SCIP_HASHMAP* localvarmap;
    5597 SCIP_HASHMAP* localconsmap;
    5598 SCIP_VAR** vars;
    5599 SCIP_VAR* auxiliaryvar;
    5600 SCIP_CONS** conss;
    5601 SCIP_CONS* objcons;
    5602 int nvars;
    5603 int nconss;
    5604 int i;
    5605 SCIP_Bool uselocalvarmap;
    5606 SCIP_Bool uselocalconsmap;
    5607 char varname[SCIP_MAXSTRLEN];
    5608 char consname[SCIP_MAXSTRLEN];
    5609 const char* origvarname;
    5610
    5611 assert(benders != NULL);
    5612 assert(set != NULL);
    5613 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    5614
    5615 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " Benders' decomposition: Infeasibility of subproblem %d can't "
    5616 "be resolved. Subproblem %d is being merged into the master problem.\n", probnumber, probnumber);
    5617
    5618 /* freeing the subproblem because it will be flagged as independent. Since the subproblem is flagged as independent,
    5619 * it will no longer be solved or freed within the solving loop.
    5620 */
    5621 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
    5622
    5623 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5624
    5625 uselocalvarmap = (varmap == NULL);
    5626 uselocalconsmap = (consmap == NULL);
    5627
    5628 if( uselocalvarmap )
    5629 {
    5630 /* create the variable mapping hash map */
    5631 SCIP_CALL( SCIPhashmapCreate(&localvarmap, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
    5632 }
    5633 else
    5634 localvarmap = varmap;
    5635
    5636 if( uselocalconsmap )
    5637 {
    5638 /* create the constraint mapping hash map */
    5639 SCIP_CALL( SCIPhashmapCreate(&localconsmap, SCIPblkmem(set->scip), SCIPgetNConss(subproblem)) );
    5640 }
    5641 else
    5642 localconsmap = consmap;
    5643
    5644 /* retrieving the subproblem variable to build a subproblem mapping */
    5645 vars = SCIPgetVars(subproblem);
    5646 nvars = SCIPgetNVars(subproblem);
    5647
    5648 /* creating the objective function constraint that will be added to the master problem */
    5649 /* setting the name of the transferred cut */
    5650 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "objectivecons_%d", probnumber );
    5651 SCIP_CALL( SCIPcreateConsBasicLinear(set->scip, &objcons, consname, 0, NULL, NULL, -SCIPsetInfinity(set), 0.0) );
    5652 SCIP_CALL( SCIPsetConsRemovable(set->scip, objcons, TRUE) );
    5653
    5654 for( i = 0; i < nvars; i++ )
    5655 {
    5656 SCIP_VAR* mastervar = NULL;
    5657 SCIP_Bool releasevar = FALSE;
    5658
    5659 SCIP_CALL( SCIPgetBendersMasterVar(set->scip, benders, vars[i], &mastervar) );
    5660
    5661 /* if the master problem variable is not NULL, then there is a corresponding variable in the master problem for
    5662 * the given subproblem variable. In this case, the variable is added to the hashmap.
    5663 */
    5664 if( mastervar == NULL )
    5665 {
    5666 SCIP_VAR* origvar;
    5667 SCIP_Real scalar;
    5668 SCIP_Real constant;
    5669
    5670 /* This is following the same process as in createVariableMappings. The original variable is used to map
    5671 * between the subproblem and the master problem
    5672 */
    5673 origvar = vars[i];
    5674 scalar = 1.0;
    5675 constant = 0.0;
    5676 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
    5677
    5678 /* retrieving the var name */
    5679 origvarname = SCIPvarGetName(origvar);
    5680 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", origvarname);
    5681
    5682 /* creating and adding the variable to the Benders' decomposition master problem */
    5683 SCIP_CALL( SCIPcreateVarBasic(set->scip, &mastervar, varname, SCIPvarGetLbOriginal(origvar),
    5684 SCIPvarGetUbOriginal(origvar), 0.0, SCIPvarGetType(origvar)) );
    5685
    5686 /* adding the variable to the master problem */
    5687 SCIP_CALL( SCIPaddVar(set->scip, mastervar) );
    5688
    5689 /* adds the variable to the objective function constraint */
    5690 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, mastervar, SCIPvarGetObj(origvar)) );
    5691
    5692 /* the variable must be released */
    5693 releasevar = TRUE;
    5694 }
    5695
    5696 /* creating the mapping betwen the subproblem var and the master var for the constraint copying */
    5697 SCIP_CALL( SCIPhashmapInsert(localvarmap, vars[i], mastervar) );
    5698
    5699 /* releasing the variable */
    5700 if( releasevar )
    5701 {
    5702 SCIP_CALL( SCIPreleaseVar(set->scip, &mastervar) );
    5703 }
    5704 }
    5705
    5706 /* getting the constraints from the subproblem that will be added to the master problem */
    5707 conss = SCIPgetConss(subproblem);
    5708 nconss = SCIPgetNConss(subproblem);
    5709
    5710 /* getting a copy of all constraints and adding it to the master problem */
    5711 for( i = 0; i < nconss; i++ )
    5712 {
    5713 SCIP_CONS* targetcons;
    5714 SCIP_Bool initial;
    5715 SCIP_Bool valid;
    5716
    5717 /* NOTE: adding all subproblem constraints appears to cause an error when resolving the LP, which results in the
    5718 * current incumbent being reported as optimal. To avoid this, only half of the subproblem constraints are added
    5719 * the master problem. The remaining half are marked as lazy and are separated as required.
    5720 */
    5721 initial = (i < nconss/2);
    5722
    5723 SCIP_CALL( SCIPgetConsCopy(subproblem, set->scip, conss[i], &targetcons, SCIPconsGetHdlr(conss[i]),
    5724 localvarmap, localconsmap, NULL, initial, SCIPconsIsSeparated(conss[i]),
    5725 SCIPconsIsEnforced(conss[i]), SCIPconsIsChecked(conss[i]), SCIPconsIsPropagated(conss[i]), FALSE,
    5726 SCIPconsIsModifiable(conss[i]), SCIPconsIsDynamic(conss[i]), SCIPconsIsRemovable(conss[i]),
    5727 FALSE, TRUE, &valid) );
    5728 assert(SCIPconsIsInitial(conss[i]));
    5729 assert(valid);
    5730
    5731 SCIP_CALL( SCIPaddCons(set->scip, targetcons) );
    5732
    5733 SCIP_CALL( SCIPreleaseCons(set->scip, &targetcons) );
    5734 }
    5735
    5736 /* freeing the hashmaps */
    5737 if( uselocalvarmap )
    5738 {
    5739 /* free hash map */
    5740 SCIPhashmapFree(&localvarmap);
    5741 }
    5742
    5743 if( uselocalconsmap )
    5744 {
    5745 /* free hash map */
    5746 SCIPhashmapFree(&localconsmap);
    5747 }
    5748
    5749 /* adding the auxiliary variable to the objective constraint */
    5750 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    5751 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, auxiliaryvar, -1.0) );
    5752
    5753 /* adding the objective function constraint to the master problem */
    5754 SCIP_CALL( SCIPaddCons(set->scip, objcons) );
    5755
    5756 SCIP_CALL( SCIPreleaseCons(set->scip, &objcons) );
    5757
    5758 /* the merged subproblem is no longer solved. This is indicated by setting the subproblem as disabled. The
    5759 * subproblem still exists, but it is not solved in the solving loop.
    5760 */
    5761 SCIPbendersSetSubproblemEnabled(benders, probnumber, FALSE);
    5762
    5763 return SCIP_OKAY;
    5764}
    5765
    5766/** Returns the corresponding master or subproblem variable for the given variable.
    5767 * This provides a call back for the variable mapping between the master and subproblems. */
    5769 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5770 SCIP_SET* set, /**< global SCIP settings */
    5771 SCIP_VAR* var, /**< the variable for which the corresponding variable is desired */
    5772 SCIP_VAR** mappedvar, /**< the variable that is mapped to var */
    5773 int probnumber /**< the problem number for the desired variable, -1 for the master problem */
    5774 )
    5775{
    5776 assert(benders != NULL);
    5777 assert(set != NULL);
    5778 assert(var != NULL);
    5779 assert(mappedvar != NULL);
    5780 assert(benders->bendersgetvar != NULL);
    5781
    5782 (*mappedvar) = NULL;
    5783
    5784 /* if the variable name matches the auxiliary variable, then the master variable is returned as NULL */
    5785 if( strstr(SCIPvarGetName(var), AUXILIARYVAR_NAME) != NULL )
    5786 return SCIP_OKAY;
    5787
    5788 SCIP_CALL( benders->bendersgetvar(set->scip, benders, var, mappedvar, probnumber) );
    5789
    5790 return SCIP_OKAY;
    5791}
    5793/** gets user data of Benders' decomposition */
    5795 SCIP_BENDERS* benders /**< Benders' decomposition */
    5796 )
    5797{
    5798 assert(benders != NULL);
    5799
    5800 return benders->bendersdata;
    5801}
    5803/** sets user data of Benders' decomposition; user has to free old data in advance! */
    5805 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5806 SCIP_BENDERSDATA* bendersdata /**< new Benders' decomposition user data */
    5807 )
    5808{
    5809 assert(benders != NULL);
    5810
    5811 benders->bendersdata = bendersdata;
    5812}
    5814/** sets copy callback of Benders' decomposition */
    5816 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5817 SCIP_DECL_BENDERSCOPY ((*benderscopy)) /**< copy callback of Benders' decomposition */
    5818 )
    5819{
    5820 assert(benders != NULL);
    5821
    5822 benders->benderscopy = benderscopy;
    5823}
    5825/** sets destructor callback of Benders' decomposition */
    5827 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5828 SCIP_DECL_BENDERSFREE ((*bendersfree)) /**< destructor of Benders' decomposition */
    5829 )
    5830{
    5831 assert(benders != NULL);
    5832
    5833 benders->bendersfree = bendersfree;
    5834}
    5836/** sets initialization callback of Benders' decomposition */
    5838 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5839 SCIP_DECL_BENDERSINIT((*bendersinit)) /**< initialize the Benders' decomposition */
    5840 )
    5841{
    5842 assert(benders != NULL);
    5843
    5844 benders->bendersinit = bendersinit;
    5845}
    5847/** sets deinitialization callback of Benders' decomposition */
    5849 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5850 SCIP_DECL_BENDERSEXIT((*bendersexit)) /**< deinitialize the Benders' decomposition */
    5851 )
    5852{
    5853 assert(benders != NULL);
    5854
    5855 benders->bendersexit = bendersexit;
    5856}
    5858/** sets presolving initialization callback of Benders' decomposition */
    5860 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5861 SCIP_DECL_BENDERSINITPRE((*bendersinitpre))/**< initialize presolving for Benders' decomposition */
    5862 )
    5863{
    5864 assert(benders != NULL);
    5865
    5866 benders->bendersinitpre = bendersinitpre;
    5867}
    5869/** sets presolving deinitialization callback of Benders' decomposition */
    5871 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5872 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre))/**< deinitialize presolving for Benders' decomposition */
    5873 )
    5874{
    5875 assert(benders != NULL);
    5876
    5877 benders->bendersexitpre = bendersexitpre;
    5878}
    5880/** sets solving process initialization callback of Benders' decomposition */
    5882 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5883 SCIP_DECL_BENDERSINITSOL((*bendersinitsol))/**< solving process initialization callback of Benders' decomposition */
    5884 )
    5885{
    5886 assert(benders != NULL);
    5887
    5888 benders->bendersinitsol = bendersinitsol;
    5889}
    5891/** sets solving process deinitialization callback of Benders' decomposition */
    5893 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5894 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol))/**< solving process deinitialization callback of Benders' decomposition */
    5895 )
    5896{
    5897 assert(benders != NULL);
    5898
    5899 benders->bendersexitsol = bendersexitsol;
    5900}
    5902/** sets the pre subproblem solve callback of Benders' decomposition */
    5904 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5905 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve))/**< called prior to the subproblem solving loop */
    5906 )
    5907{
    5908 assert(benders != NULL);
    5909
    5910 benders->benderspresubsolve = benderspresubsolve;
    5911}
    5913/** sets convex solve callback of Benders' decomposition */
    5915 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5916 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex))/**< solving method for the convex Benders' decomposition subproblem */
    5917 )
    5918{
    5919 assert(benders != NULL);
    5920
    5921 benders->benderssolvesubconvex = benderssolvesubconvex;
    5922}
    5924/** sets solve callback of Benders' decomposition */
    5926 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5927 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub))/**< solving method for a Benders' decomposition subproblem */
    5928 )
    5929{
    5930 assert(benders != NULL);
    5931
    5932 benders->benderssolvesub = benderssolvesub;
    5933}
    5935/** sets post-solve callback of Benders' decomposition */
    5937 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5938 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve))/**< solving process deinitialization callback of Benders' decomposition */
    5939 )
    5940{
    5941 assert(benders != NULL);
    5942
    5943 benders->benderspostsolve = benderspostsolve;
    5944}
    5946/** sets post-solve callback of Benders' decomposition */
    5948 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5949 SCIP_DECL_SORTPTRCOMP((*benderssubcomp)) /**< a comparator for defining the solving order of the subproblems */
    5950 )
    5951{
    5952 assert(benders != NULL);
    5953
    5954 benders->benderssubcomp = benderssubcomp;
    5955}
    5957/** sets free subproblem callback of Benders' decomposition */
    5959 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5960 SCIP_DECL_BENDERSFREESUB((*bendersfreesub))/**< the freeing callback for the subproblem */
    5961 )
    5962{
    5963 assert(benders != NULL);
    5964
    5965 benders->bendersfreesub = bendersfreesub;
    5966}
    5968/** gets name of Benders' decomposition */
    5969const char* SCIPbendersGetName(
    5970 SCIP_BENDERS* benders /**< Benders' decomposition */
    5971 )
    5972{
    5973 assert(benders != NULL);
    5974
    5975 return benders->name;
    5976}
    5978/** gets description of Benders' decomposition */
    5979const char* SCIPbendersGetDesc(
    5980 SCIP_BENDERS* benders /**< Benders' decomposition */
    5981 )
    5982{
    5983 assert(benders != NULL);
    5984
    5985 return benders->desc;
    5986}
    5988/** gets priority of Benders' decomposition */
    5990 SCIP_BENDERS* benders /**< Benders' decomposition */
    5991 )
    5992{
    5993 assert(benders != NULL);
    5994
    5995 return benders->priority;
    5996}
    5998/** sets priority of Benders' decomposition */
    6000 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6001 SCIP_SET* set, /**< global SCIP settings */
    6002 int priority /**< new priority of the Benders' decomposition */
    6003 )
    6004{
    6005 assert(benders != NULL);
    6006 assert(set != NULL);
    6007
    6008 benders->priority = priority;
    6009 set->benderssorted = FALSE;
    6010}
    6012/** gets the number of subproblems for the Benders' decomposition */
    6014 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
    6015 )
    6016{
    6017 assert(benders != NULL);
    6018
    6019 return benders->nsubproblems;
    6020}
    6022/** returns the SCIP instance for a given subproblem */
    6024 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
    6025 int probnumber /**< the subproblem number */
    6026 )
    6027{
    6028 assert(benders != NULL);
    6029 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    6030
    6031 return benders->subproblems[probnumber];
    6032}
    6034/** gets the number of times, the Benders' decomposition was called and tried to find a variable with negative reduced costs */
    6036 SCIP_BENDERS* benders /**< Benders' decomposition */
    6037 )
    6038{
    6039 assert(benders != NULL);
    6040
    6041 return benders->ncalls;
    6042}
    6044/** gets the number of optimality cuts found by the collection of Benders' decomposition subproblems */
    6046 SCIP_BENDERS* benders /**< Benders' decomposition */
    6047 )
    6048{
    6049 assert(benders != NULL);
    6050
    6051 return benders->ncutsfound;
    6052}
    6054/** gets the number of cuts found from the strengthening round */
    6056 SCIP_BENDERS* benders /**< Benders' decomposition */
    6057 )
    6058{
    6059 assert(benders != NULL);
    6060
    6061 return benders->nstrengthencuts;
    6062}
    6064/** gets the number of calls to the strengthening round */
    6066 SCIP_BENDERS* benders /**< Benders' decomposition */
    6067 )
    6068{
    6069 assert(benders != NULL);
    6070
    6071 return benders->nstrengthencalls;
    6072}
    6074/** gets the number of calls to the strengthening round that fail */
    6076 SCIP_BENDERS* benders /**< Benders' decomposition */
    6077 )
    6078{
    6079 assert(benders != NULL);
    6080
    6081 return benders->nstrengthenfails;
    6082}
    6084/** gets time in seconds used in this Benders' decomposition for setting up for next stages */
    6086 SCIP_BENDERS* benders /**< Benders' decomposition */
    6087 )
    6088{
    6089 assert(benders != NULL);
    6090
    6091 return SCIPclockGetTime(benders->setuptime);
    6092}
    6094/** gets time in seconds used in this Benders' decomposition */
    6096 SCIP_BENDERS* benders /**< Benders' decomposition */
    6097 )
    6098{
    6099 assert(benders != NULL);
    6100
    6101 return SCIPclockGetTime(benders->bendersclock);
    6102}
    6104/** enables or disables all clocks of the Benders' decomposition, depending on the value of the flag */
    6106 SCIP_BENDERS* benders, /**< the Benders' decomposition for which all clocks should be enabled or disabled */
    6107 SCIP_Bool enable /**< should the clocks of the Benders' decomposition be enabled? */
    6108 )
    6109{
    6110 assert(benders != NULL);
    6111
    6112 SCIPclockEnableOrDisable(benders->setuptime, enable);
    6113 SCIPclockEnableOrDisable(benders->bendersclock, enable);
    6114}
    6116/** is Benders' decomposition initialized? */
    6118 SCIP_BENDERS* benders /**< Benders' decomposition */
    6119 )
    6120{
    6121 assert(benders != NULL);
    6122
    6123 return benders->initialized;
    6124}
    6126/** Are Benders' cuts generated from the LP solutions? */
    6128 SCIP_BENDERS* benders /**< Benders' decomposition */
    6129 )
    6130{
    6131 assert(benders != NULL);
    6132
    6133 return benders->cutlp;
    6134}
    6136/** Are Benders' cuts generated from the pseudo solutions? */
    6138 SCIP_BENDERS* benders /**< Benders' decomposition */
    6139 )
    6140{
    6141 assert(benders != NULL);
    6142
    6143 return benders->cutpseudo;
    6144}
    6146/** Are Benders' cuts generated from the relaxation solutions? */
    6148 SCIP_BENDERS* benders /**< Benders' decomposition */
    6149 )
    6150{
    6151 assert(benders != NULL);
    6152
    6153 return benders->cutrelax;
    6154}
    6156/** should this Benders' use the auxiliary variables from the highest priority Benders' */
    6158 SCIP_BENDERS* benders /**< Benders' decomposition */
    6159 )
    6160{
    6161 assert(benders != NULL);
    6162
    6163 return benders->shareauxvars;
    6164}
    6165
    6166/** adds a subproblem to the Benders' decomposition data. If a custom subproblem solving method is used, then the
    6167 * subproblem pointer can be set to NULL
    6168 */
    6170 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6171 SCIP* subproblem /**< subproblem to be added to the data storage, can be NULL */
    6172 )
    6173{
    6174 assert(benders != NULL);
    6175 assert(benders->naddedsubprobs + 1 <= benders->nsubproblems);
    6176
    6177 /* if the subproblem pointer is NULL, then the subproblem solving callback functions must be set. */
    6178 if( subproblem == NULL && (!benders->benderssolvesubconvex || !benders->benderssolvesub) )
    6179 {
    6180 SCIPerrorMessage("The subproblem can only be set to NULL if both bendersSolvesubconvex%s and bendersSolvesub%s "
    6181 "are defined.\n", benders->name, benders->name);
    6182 return SCIP_ERROR;
    6183 }
    6184
    6185 benders->subproblems[benders->naddedsubprobs] = subproblem;
    6186
    6187 benders->naddedsubprobs++;
    6188
    6189 return SCIP_OKAY;
    6190}
    6192/** removes the subproblems from the Benders' decomposition data */
    6194 SCIP_BENDERS* benders /**< Benders' decomposition */
    6195 )
    6196{
    6197 assert(benders != NULL);
    6198 assert(benders->subproblems != NULL);
    6199
    6200 BMSclearMemoryArray(&benders->subproblems, benders->naddedsubprobs);
    6201 benders->naddedsubprobs = 0;
    6202}
    6204/** returns the main auxiliary variable that is used the subproblem objective function. */
    6206 SCIP_BENDERS* benders /**< Benders' decomposition */
    6207 )
    6208{
    6209 assert(benders != NULL);
    6210
    6211 return benders->masterauxvar;
    6212}
    6214/** returns the auxiliary variable for the given subproblem */
    6216 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6217 int probnumber /**< the subproblem number */
    6218 )
    6219{
    6220 assert(benders != NULL);
    6221 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6222
    6223 return benders->auxiliaryvars[probnumber];
    6224}
    6226/** returns all auxiliary variables */
    6228 SCIP_BENDERS* benders /**< Benders' decomposition */
    6229 )
    6230{
    6231 assert(benders != NULL);
    6232
    6233 return benders->auxiliaryvars;
    6234}
    6236/** returns the subproblem master variables for the given subproblem */
    6238 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6239 int probnumber /**< the subproblem number */
    6240 )
    6241{
    6242 assert(benders != NULL);
    6243 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6244
    6245 return benders->submastervars[probnumber];
    6246}
    6248/** returns the number of subproblem master variables for the given subproblem */
    6250 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6251 int probnumber /**< the subproblem number */
    6252 )
    6253{
    6254 assert(benders != NULL);
    6255 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6256
    6257 return benders->nsubmastervars[probnumber];
    6258}
    6260/** returns the subproblem master variable data for the given subproblem */
    6262 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6263 int probnumber, /**< the subproblem number */
    6264 SCIP_VAR*** vars, /**< pointer to store the master variables, or NULL */
    6265 int* nvars, /**< the number of master problem variables, or NULL */
    6266 int* nbinvars, /**< the number of binary master problem variables, or NULL */
    6267 int* nintvars /**< the number of integer master problem variables, or NULL */
    6268 )
    6269{
    6270 assert(benders != NULL);
    6271 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6272
    6273 if( vars != NULL )
    6274 (*vars) = benders->submastervars[probnumber];
    6275
    6276 if( nvars != NULL )
    6277 (*nvars) = benders->nsubmastervars[probnumber];
    6278
    6279 if( nbinvars != NULL )
    6280 (*nbinvars) = benders->nsubmasterbinvars[probnumber];
    6281
    6282 if( nintvars != NULL )
    6283 (*nintvars) = benders->nsubmasterintvars[probnumber];
    6284}
    6286/** stores the objective function value of the subproblem for use in cut generation */
    6288 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    6289 int probnumber, /**< the subproblem number */
    6290 SCIP_Real objval /**< the objective function value for the subproblem */
    6291 )
    6292{
    6293 assert(benders != NULL);
    6294 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6295
    6296 /* updating the best objval */
    6297 if( objval < benders->bestsubprobobjval[probnumber] )
    6298 benders->bestsubprobobjval[probnumber] = objval;
    6299
    6300 benders->subprobobjval[probnumber] = objval;
    6301}
    6303/** returns the objective function value of the subproblem for use in cut generation */
    6305 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6306 int probnumber /**< the subproblem number */
    6307 )
    6308{
    6309 assert(benders != NULL);
    6310 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6311
    6312 return benders->subprobobjval[probnumber];
    6313}
    6315/** returns whether the solution has non-zero slack variables */
    6317 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6318 SCIP_Bool* activeslack /**< flag to indicate whether a slack variable is active */
    6319 )
    6320{
    6321 SCIP* subproblem;
    6322 SCIP_SOL* sol;
    6323 SCIP_VAR** vars;
    6324 int nsubproblems;
    6325 int nvars;
    6326 int ncontvars;
    6327 int i;
    6328 int j;
    6329 SCIP_Bool freesol = FALSE;
    6330
    6331 assert(benders != NULL);
    6332 assert(activeslack != NULL);
    6333
    6334 (*activeslack) = FALSE;
    6335
    6336 /* if the slack variables have not been added, then we can immediately state that no slack variables are active */
    6337 if( !benders->feasibilityphase )
    6338 {
    6339 return SCIP_OKAY;
    6340 }
    6341
    6342 nsubproblems = SCIPbendersGetNSubproblems(benders);
    6343
    6344 /* checking all subproblems for active slack variables */
    6345 for( i = 0; i < nsubproblems && !(*activeslack); i++ )
    6346 {
    6347 subproblem = SCIPbendersSubproblem(benders, i);
    6348
    6349 /* if the subproblem is convex and an NLP, then we need to create the NLP solution. Otherwise, the solution can be
    6350 * retrieved from the LP or CIP.
    6351 */
    6353 {
    6354 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0 )
    6355 {
    6356 SCIP_CALL( SCIPcreateNLPSol(subproblem, &sol, NULL) );
    6357 }
    6358 else
    6359 {
    6360 SCIP_CALL( SCIPcreateCurrentSol(subproblem, &sol, NULL) );
    6361 }
    6362 freesol = TRUE;
    6363 }
    6364 else
    6365 sol = SCIPgetBestSol(subproblem);
    6366
    6367 /* getting the variable data. Only the continuous variables are important. */
    6368 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, &ncontvars) );
    6369
    6370 /* checking all slack variables for non-zero solution values */
    6371 for( j = nvars - 1; j >= nvars - ncontvars; j-- )
    6372 {
    6373 if( strstr(SCIPvarGetName(vars[j]), SLACKVAR_NAME) != NULL )
    6374 {
    6375 if( SCIPisPositive(subproblem, SCIPgetSolVal(subproblem, sol, vars[j])) )
    6376 {
    6377 (*activeslack) = TRUE;
    6378 break;
    6379 }
    6380 }
    6381 }
    6382
    6383 /* freeing the LP and NLP solutions */
    6384 if( freesol )
    6385 {
    6386 SCIP_CALL( SCIPfreeSol(subproblem, &sol) );
    6387 }
    6388 }
    6389
    6390 return SCIP_OKAY;
    6391}
    6392
    6393/** sets the subproblem type
    6394 *
    6395 * The subproblem types are:
    6396 * - Convex constraints with continuous variables
    6397 * - Convex constraints with discrete variables
    6398 * - Non-convex constraints with continuous variables
    6399 * - Non-convex constraints with discrete variables
    6400 */
    6402 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6403 int probnumber, /**< the subproblem number */
    6404 SCIP_BENDERSSUBTYPE subprobtype /**< the subproblem type */
    6405 )
    6406{
    6407 assert(benders != NULL);
    6408 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6409
    6410 if( subprobtype == SCIP_BENDERSSUBTYPE_CONVEXCONT
    6411 && benders->subprobtype[probnumber] != SCIP_BENDERSSUBTYPE_CONVEXCONT )
    6412 benders->nconvexsubprobs++;
    6413 else if( subprobtype != SCIP_BENDERSSUBTYPE_CONVEXCONT
    6414 && benders->subprobtype[probnumber] == SCIP_BENDERSSUBTYPE_CONVEXCONT )
    6415 benders->nconvexsubprobs--;
    6416
    6417 benders->subprobtype[probnumber] = subprobtype;
    6418
    6419 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
    6420}
    6421
    6422/** returns the type of the subproblem
    6423 *
    6424 * This type is used to determine whether the duals of the problem can be used to generate cuts
    6425 */
    6427 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6428 int probnumber /**< the subproblem number */
    6429 )
    6430{
    6431 assert(benders != NULL);
    6432 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6433
    6434 return benders->subprobtype[probnumber];
    6435}
    6436
    6437/** sets the flag indicating whether a subproblem is convex
    6438 *
    6439 * It is possible that this can change during the solving process. One example is when the three-phase method is
    6440 * employed, where the first phase solves the convex relaxation of both the master and subproblems, the second phase
    6441 * reintroduces the integrality constraints to the master problem and the third phase then reintroduces integrality
    6442 * constraints to the subproblems.
    6443 */
    6445 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6446 int probnumber, /**< the subproblem number */
    6447 SCIP_Bool isconvex /**< flag to indicate whether the subproblem is convex */
    6448 )
    6449{
    6450 assert(benders != NULL);
    6451 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6452
    6453 if( isconvex && !benders->subprobisconvex[probnumber] )
    6454 benders->nconvexsubprobs++;
    6455 else if( !isconvex && benders->subprobisconvex[probnumber] )
    6456 benders->nconvexsubprobs--;
    6457
    6458 benders->subprobisconvex[probnumber] = isconvex;
    6459
    6460 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
    6461}
    6462
    6463/** returns whether the subproblem is convex
    6464 *
    6465 * This means that the dual solution can be used to generate cuts.
    6466 */
    6468 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6469 int probnumber /**< the subproblem number */
    6470 )
    6471{
    6472 assert(benders != NULL);
    6473 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6474
    6475 return benders->subprobisconvex[probnumber];
    6476}
    6478/** returns the number of subproblems that are convex */
    6480 SCIP_BENDERS* benders /**< Benders' decomposition */
    6481 )
    6482{
    6483 assert(benders != NULL);
    6484
    6485 return benders->nconvexsubprobs;
    6486}
    6488/** sets the flag indicating whether a subproblem contains non-linear constraints */
    6490 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6491 int probnumber, /**< the subproblem number */
    6492 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
    6493 )
    6494{
    6495 assert(benders != NULL);
    6496 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6497
    6498 if( isnonlinear && !benders->subprobisnonlinear[probnumber] )
    6499 benders->nnonlinearsubprobs++;
    6500 else if( !isnonlinear && benders->subprobisnonlinear[probnumber] )
    6501 benders->nnonlinearsubprobs--;
    6502
    6503 benders->subprobisnonlinear[probnumber] = isnonlinear;
    6504
    6505 assert(benders->nnonlinearsubprobs >= 0 && benders->nnonlinearsubprobs <= benders->nsubproblems);
    6506}
    6508/** returns whether the subproblem contains non-linear constraints. */
    6510 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6511 int probnumber /**< the subproblem number */
    6512 )
    6513{
    6514 assert(benders != NULL);
    6515 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6516
    6517 return benders->subprobisnonlinear[probnumber];
    6518}
    6520/** returns the number of subproblems that contain non-linear constraints */
    6522 SCIP_BENDERS* benders /**< Benders' decomposition */
    6523 )
    6524{
    6525 assert(benders != NULL);
    6526
    6527 return benders->nnonlinearsubprobs;
    6528}
    6530/** sets the flag indicating whether the master problem contains non-linear constraints */
    6532 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6533 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
    6534 )
    6535{
    6536 assert(benders != NULL);
    6537
    6538 benders->masterisnonlinear = isnonlinear;
    6539}
    6541/** returns whether the master problem contains non-linear constraints. */
    6543 SCIP_BENDERS* benders /**< Benders' decomposition */
    6544 )
    6545{
    6546 assert(benders != NULL);
    6547
    6548 return benders->masterisnonlinear;
    6549}
    6551/** returns the flag indicating that Benders' decomposition is in a cut strengthening round */
    6553 SCIP_BENDERS* benders /**< Benders' decomposition */
    6554 )
    6555{
    6556 assert(benders != NULL);
    6557
    6558 return benders->strengthenround;
    6559}
    6560
    6561/** sets the flag to indicate that at least one subproblem is always infeasible
    6562 * NOTE: this is without any variable fixing being performed
    6563 */
    6565 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6566 SCIP_SET* set /**< global SCIP settings */
    6567 )
    6568{
    6569 assert(benders != NULL);
    6570 assert(set != NULL);
    6571
    6572 if( SCIPgetDepth(set->scip) <= 0 )
    6573 benders->subprobsinfeasible = TRUE;
    6574}
    6575
    6576/** returns whether at least one of the subproblems has been identified as infeasible.
    6577 * NOTE: this is without any variable fixing being performed
    6578 */
    6580 SCIP_BENDERS* benders /**< Benders' decomposition */
    6581 )
    6582{
    6583 assert(benders != NULL);
    6584
    6585 return benders->subprobsinfeasible;
    6586}
    6588/** changes all of the master problem variables in the given subproblem to continuous. */
    6590 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6591 SCIP_SET* set, /**< global SCIP settings */
    6592 int probnumber /**< the subproblem number */
    6593 )
    6594{
    6595 SCIP* subproblem;
    6596 SCIP_VAR** vars;
    6597 int nbinvars;
    6598 int nintvars;
    6599 int nimplvars;
    6600 int chgvarscount;
    6601 int origintvars;
    6602 int i;
    6603 SCIP_Bool infeasible;
    6604
    6605 assert(benders != NULL);
    6606 assert(set != NULL);
    6607 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6608
    6609 subproblem = SCIPbendersSubproblem(benders, probnumber);
    6610 assert(subproblem != NULL);
    6611
    6612 /* only set the master problem variable to continuous if they have not already been changed. */
    6613 if( !SCIPbendersGetMastervarsCont(benders, probnumber) )
    6614 {
    6615 SCIP_VAR* mastervar;
    6616
    6617 /* retrieving the variable data */
    6618 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
    6619
    6620 origintvars = nbinvars + nintvars + nimplvars;
    6621
    6622 chgvarscount = 0;
    6623
    6624 /* looping over all integer variables to change the master variables to continuous */
    6625 i = 0;
    6626 while( i < nbinvars + nintvars + nimplvars )
    6627 {
    6628 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
    6629
    6630 if( SCIPvarIsIntegral(vars[i]) && mastervar != NULL )
    6631 {
    6632 /* remove integrality of the subproblem variable corresponding to mastervar */
    6633 SCIP_CALL( SCIPchgVarType(subproblem, vars[i], SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    6634 assert(!infeasible);
    6635 SCIP_CALL( SCIPchgVarImplType(subproblem, vars[i], SCIP_IMPLINTTYPE_NONE, &infeasible) );
    6636 assert(!infeasible);
    6637
    6638 chgvarscount++;
    6639 SCIP_CALL( SCIPgetVarsData(subproblem, NULL, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
    6640 }
    6641 else
    6642 i++;
    6643 }
    6644
    6645 /* if all of the integer variables have been changed to continuous, then the subproblem could now be a convex
    6646 * problem. This must be checked and if TRUE, then the LP subproblem is initialised and then put into probing
    6647 * mode
    6648 */
    6649 if( chgvarscount > 0 && chgvarscount == origintvars )
    6650 {
    6651 /* checking the convexity of the subproblem */
    6652 SCIP_CALL( checkSubproblemConvexity(benders, set, probnumber) );
    6653
    6654 /* if the subproblem has convex constraints and continuous variables, then it is initialised and put into
    6655 * probing mode
    6656 */
    6658 {
    6659 SCIP_CALL( initialiseLPSubproblem(benders, set, probnumber, &infeasible) );
    6660
    6661 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
    6662 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
    6663 * during the solving process.
    6664 */
    6665 if( infeasible )
    6667 }
    6668 }
    6669
    6670 SCIP_CALL( SCIPbendersSetMastervarsCont(benders, probnumber, TRUE) );
    6671 }
    6672
    6673 return SCIP_OKAY;
    6674}
    6676/** sets the subproblem setup flag */
    6678 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6679 int probnumber, /**< the subproblem number */
    6680 SCIP_Bool issetup /**< flag to indicate whether the subproblem has been setup */
    6681 )
    6682{
    6683 assert(benders != NULL);
    6684 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6685
    6686 benders->subprobsetup[probnumber] = issetup;
    6687}
    6689/** returns the subproblem setup flag */
    6691 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6692 int probnumber /**< the subproblem number */
    6693 )
    6694{
    6695 assert(benders != NULL);
    6696 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6697
    6698 return benders->subprobsetup[probnumber];
    6699}
    6701/** sets the independent subproblem flag */
    6703 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6704 int probnumber, /**< the subproblem number */
    6705 SCIP_Bool isindep /**< flag to indicate whether the subproblem is independent */
    6706 )
    6707{
    6708 assert(benders != NULL);
    6709 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6710
    6711 /* if the user has defined solving or freeing functions, then it is not possible to declare a subproblem as
    6712 * independent. This is because declaring a subproblem as independent changes the solving loop, so it would change
    6713 * the expected behaviour of the user defined plugin. If a user calls this function, then an error will be returned.
    6714 */
    6715 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL || benders->bendersfreesub != NULL )
    6716 {
    6717 SCIPerrorMessage("The user has defined either bendersSolvesubconvex%s, bendersSolvesub%s or bendersFreesub%s. "
    6718 "Thus, it is not possible to declare the independence of a subproblem.\n", benders->name, benders->name,
    6719 benders->name);
    6720 SCIPABORT();
    6721 }
    6722 else
    6723 {
    6724 SCIP_Bool activesubprob;
    6725
    6726 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
    6727 activesubprob = subproblemIsActive(benders, probnumber);
    6728
    6729 benders->indepsubprob[probnumber] = isindep;
    6730
    6731 /* updating the activesubprobs counter */
    6732 if( activesubprob && !subproblemIsActive(benders, probnumber) )
    6733 benders->nactivesubprobs--;
    6734 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
    6735 benders->nactivesubprobs++;
    6736
    6737 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
    6738 }
    6739}
    6741/** returns whether the subproblem is independent */
    6743 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6744 int probnumber /**< the subproblem number */
    6745 )
    6746{
    6747 assert(benders != NULL);
    6748 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6749
    6750 return benders->indepsubprob[probnumber];
    6751}
    6752
    6753/** Sets whether the subproblem is enabled or disabled. A subproblem is disabled if it has been merged into the master
    6754 * problem.
    6755 */
    6757 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6758 int probnumber, /**< the subproblem number */
    6759 SCIP_Bool enabled /**< flag to indicate whether the subproblem is enabled */
    6760 )
    6761{
    6762 SCIP_Bool activesubprob;
    6763
    6764 assert(benders != NULL);
    6765 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6766
    6767 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
    6768 activesubprob = subproblemIsActive(benders, probnumber);
    6769
    6770 benders->subprobenabled[probnumber] = enabled;
    6771
    6772 /* updating the activesubprobs counter */
    6773 if( activesubprob && !subproblemIsActive(benders, probnumber) )
    6774 benders->nactivesubprobs--;
    6775 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
    6776 benders->nactivesubprobs++;
    6777
    6778 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
    6779}
    6781/** returns whether the subproblem is enabled, i.e. the subproblem is still solved in the solving loop. */
    6783 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6784 int probnumber /**< the subproblem number */
    6785 )
    6786{
    6787 assert(benders != NULL);
    6788 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6789
    6790 return benders->subprobenabled[probnumber];
    6791}
    6793/** sets a flag to indicate whether the master variables are all set to continuous */
    6795 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6796 int probnumber, /**< the subproblem number */
    6797 SCIP_Bool arecont /**< flag to indicate whether the master problem variables are continuous */
    6798 )
    6799{
    6800 assert(benders != NULL);
    6801 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6802
    6803 /* if the master variables were all continuous and now are not, then the subproblem must exit probing mode and be
    6804 * changed to non-LP subproblem */
    6805 if( benders->mastervarscont[probnumber] && !arecont )
    6806 {
    6807 SCIP_BENDERSSUBTYPE subtype;
    6808
    6809 if( SCIPinProbing(SCIPbendersSubproblem(benders, probnumber)) )
    6810 {
    6811 SCIP_CALL( SCIPendProbing(SCIPbendersSubproblem(benders, probnumber)) );
    6812 }
    6813
    6814 subtype = SCIPbendersGetSubproblemType(benders, probnumber);
    6816
    6817 if( subtype == SCIP_BENDERSSUBTYPE_CONVEXCONT )
    6819 else if( subtype == SCIP_BENDERSSUBTYPE_NONCONVEXCONT )
    6821 }
    6822
    6823 benders->mastervarscont[probnumber] = arecont;
    6824
    6825 return SCIP_OKAY;
    6826}
    6828/** returns whether the master variables are all set to continuous */
    6830 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6831 int probnumber /**< the subproblem number */
    6832 )
    6833{
    6834 assert(benders != NULL);
    6835 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6836
    6837 return benders->mastervarscont[probnumber];
    6838}
    6839
    6840/** sets the objective type for the aggregation of the Benders' decomposition subproblem objectives. This is either the
    6841 * summation of the objective values or a minimax of the objective values (such as for a makespan objective)
    6842 */
    6844 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6845 SCIP_BENDERSOBJTYPE objectivetype /**< the objective type */
    6846 )
    6847{
    6848 assert(benders != NULL);
    6849
    6850 benders->objectivetype = objectivetype;
    6851}
    6853/** returns the objective type for the aggregation of the Benders' decomposition subproblem objectives */
    6855 SCIP_BENDERS* benders /**< Benders' decomposition */
    6856 )
    6857{
    6858 assert(benders != NULL);
    6859
    6860 return benders->objectivetype;
    6861}
    6863/** returns the number of cuts that have been transferred from sub SCIPs to the master SCIP */
    6865 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
    6866 )
    6867{
    6868 assert(benders != NULL);
    6869
    6870 return benders->ntransferred;
    6871}
    6872
    6873/** updates the lower bound for the subproblem. If the lower bound is not greater than the previously stored lowerbound,
    6874 * then no update occurs.
    6875 */
    6877 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6878 int probnumber, /**< the subproblem number */
    6879 SCIP_Real lowerbound /**< the lower bound */
    6880 )
    6881{
    6882 assert(benders != NULL);
    6883 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6884
    6885 if( EPSGE(lowerbound, benders->subproblowerbound[probnumber], 1e-06) )
    6886 benders->subproblowerbound[probnumber] = lowerbound;
    6887 else
    6888 {
    6889 SCIPdebugMessage("The lowerbound %g for subproblem %d is less than the currently stored lower bound %g\n",
    6890 lowerbound, probnumber, benders->subproblowerbound[probnumber]);
    6891 }
    6892}
    6894/** returns the stored lower bound for the given subproblem */
    6896 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6897 int probnumber /**< the subproblem number */
    6898 )
    6899{
    6900 assert(benders != NULL);
    6901 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6902
    6903 return benders->subproblowerbound[probnumber];
    6904}
    6906/** returns the number of cuts that have been added for storage */
    6908 SCIP_BENDERS* benders /**< Benders' decomposition */
    6909 )
    6910{
    6911 assert(benders != NULL);
    6912
    6913 return benders->nstoredcuts;
    6914}
    6916/** returns the cuts that have been stored for transfer */
    6918 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6919 int cutidx, /**< the index for the cut data that is requested */
    6920 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
    6921 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
    6922 SCIP_Real* lhs, /**< the left hand side of the cut */
    6923 SCIP_Real* rhs, /**< the right hand side of the cut */
    6924 int* nvars /**< the number of variables with non-zero coefficients in the cut */
    6925 )
    6926{
    6927 assert(benders != NULL);
    6928 assert(vars != NULL);
    6929 assert(vals != NULL);
    6930 assert(lhs != NULL);
    6931 assert(rhs != NULL);
    6932 assert(nvars != NULL);
    6933 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
    6934
    6935 (*vars) = benders->storedcuts[cutidx]->vars;
    6936 (*vals) = benders->storedcuts[cutidx]->vals;
    6937 (*lhs) = benders->storedcuts[cutidx]->lhs;
    6938 (*rhs) = benders->storedcuts[cutidx]->rhs;
    6939 (*nvars) = benders->storedcuts[cutidx]->nvars;
    6940
    6941 return SCIP_OKAY;
    6942}
    6943
    6944/** returns the original problem data for the cuts that have been added by the Benders' cut plugin. The stored
    6945 * variables and values will populate the input vars and vals arrays. Thus, memory must be allocated for the vars and
    6946 * vals arrays
    6947 */
    6949 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
    6950 int cutidx, /**< the index for the cut data that is requested */
    6951 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
    6952 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
    6953 SCIP_Real* lhs, /**< the left hand side of the cut */
    6954 SCIP_Real* rhs, /**< the right hand side of the cut */
    6955 int* nvars, /**< the number of variables with non-zero coefficients in the cut */
    6956 int varssize /**< the available slots in the array */
    6957 )
    6958{
    6959 SCIP_VAR* origvar;
    6960 SCIP_Real scalar;
    6961 SCIP_Real constant;
    6962 int i;
    6963
    6964 assert(benders != NULL);
    6965 assert(vars != NULL);
    6966 assert(vals != NULL);
    6967 assert(lhs != NULL);
    6968 assert(rhs != NULL);
    6969 assert(nvars != NULL);
    6970 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
    6971
    6972 (*lhs) = benders->storedcuts[cutidx]->lhs;
    6973 (*rhs) = benders->storedcuts[cutidx]->rhs;
    6974 (*nvars) = benders->storedcuts[cutidx]->nvars;
    6975
    6976 /* if there are enough slots, then store the cut variables and values */
    6977 if( varssize >= *nvars )
    6978 {
    6979 for( i = 0; i < *nvars; i++ )
    6980 {
    6981 /* getting the original variable for the transformed variable */
    6982 origvar = benders->storedcuts[cutidx]->vars[i];
    6983 scalar = 1.0;
    6984 constant = 0.0;
    6985 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
    6986
    6987 (*vars)[i] = origvar;
    6988 (*vals)[i] = benders->storedcuts[cutidx]->vals[i];
    6989 }
    6990 }
    6991
    6992 return SCIP_OKAY;
    6993}
    6995/** adds the data for the generated cuts to the Benders' cut storage */
    6997 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
    6998 SCIP_SET* set, /**< global SCIP settings */
    6999 SCIP_VAR** vars, /**< the variables that have non-zero coefficients in the cut */
    7000 SCIP_Real* vals, /**< the coefficients of the variables in the cut */
    7001 SCIP_Real lhs, /**< the left hand side of the cut */
    7002 SCIP_Real rhs, /**< the right hand side of the cut */
    7003 int nvars /**< the number of variables with non-zero coefficients in the cut */
    7004 )
    7005{
    7006 SCIP_BENDERSCUTCUT* cut;
    7007
    7008 assert(benders != NULL);
    7009 assert(set != NULL);
    7010 assert(vars != NULL);
    7011 assert(vals != NULL);
    7012
    7013 /* allocating the block memory for the cut storage */
    7014 SCIP_CALL( SCIPallocBlockMemory(set->scip, &cut) );
    7015
    7016 /* storing the cut data */
    7017 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vars, vars, nvars) );
    7018 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vals, vals, nvars) );
    7019 cut->lhs = lhs;
    7020 cut->rhs = rhs;
    7021 cut->nvars = nvars;
    7022
    7023 /* ensuring the required memory is available for the stored cuts array */
    7024 if( benders->storedcutssize < benders->nstoredcuts + 1 )
    7025 {
    7026 int newsize;
    7027
    7028 newsize = SCIPsetCalcMemGrowSize(set, benders->nstoredcuts + 1);
    7030 benders->storedcutssize, newsize) );
    7031
    7032 benders->storedcutssize = newsize;
    7033 }
    7034 assert(benders->storedcutssize >= benders->nstoredcuts + 1);
    7035
    7036 /* adding the cuts to the Benders' cut storage */
    7037 benders->storedcuts[benders->nstoredcuts] = cut;
    7038 benders->nstoredcuts++;
    7039
    7040 return SCIP_OKAY;
    7041}
    7043/** sets the sorted flags in the Benders' decomposition */
    7045 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
    7046 SCIP_Bool sorted /**< the value to set the sorted flag to */
    7047 )
    7048{
    7049 assert(benders != NULL);
    7050
    7051 benders->benderscutssorted = sorted;
    7052 benders->benderscutsnamessorted = sorted;
    7053}
    7055/** inserts a Benders' cut into the Benders' cuts list */
    7057 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
    7058 SCIP_SET* set, /**< global SCIP settings */
    7059 SCIP_BENDERSCUT* benderscut /**< Benders' cut */
    7060 )
    7061{
    7062 assert(benders != NULL);
    7063 assert(benderscut != NULL);
    7064
    7065 if( benders->nbenderscuts >= benders->benderscutssize )
    7066 {
    7069 }
    7070 assert(benders->nbenderscuts < benders->benderscutssize);
    7071
    7072 benders->benderscuts[benders->nbenderscuts] = benderscut;
    7073 benders->nbenderscuts++;
    7074 benders->benderscutssorted = FALSE;
    7075
    7076 return SCIP_OKAY;
    7077}
    7079/** returns the Benders' cut of the given name, or NULL if not existing */
    7081 SCIP_BENDERS* benders, /**< Benders' decomposition */
    7082 const char* name /**< name of Benderscut' decomposition */
    7083 )
    7084{
    7085 int i;
    7086
    7087 assert(benders != NULL);
    7088 assert(name != NULL);
    7089
    7090 for( i = 0; i < benders->nbenderscuts; i++ )
    7091 {
    7092 if( strcmp(SCIPbenderscutGetName(benders->benderscuts[i]), name) == 0 )
    7093 return benders->benderscuts[i];
    7094 }
    7095
    7096 return NULL;
    7097}
    7098
    7099/** returns the array of currently available Benders' cuts; active Benders' decomposition are in the first slots of
    7100 * the array
    7101 */
    7103 SCIP_BENDERS* benders /**< Benders' decomposition */
    7104 )
    7105{
    7106 assert(benders != NULL);
    7107
    7108 if( !benders->benderscutssorted )
    7109 {
    7110 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
    7111 benders->benderscutssorted = TRUE;
    7112 benders->benderscutsnamessorted = FALSE;
    7113 }
    7114
    7115 return benders->benderscuts;
    7116}
    7118/** returns the number of currently available Benders' cuts */
    7120 SCIP_BENDERS* benders /**< Benders' decomposition */
    7121 )
    7122{
    7123 assert(benders != NULL);
    7124
    7125 return benders->nbenderscuts;
    7126}
    7128/** sets the priority of a Benders' decomposition */
    7130 SCIP_BENDERS* benders, /**< Benders' decomposition */
    7131 SCIP_BENDERSCUT* benderscut, /**< Benders' cut */
    7132 int priority /**< new priority of the Benders' decomposition */
    7133 )
    7134{
    7135 assert(benders != NULL);
    7136 assert(benderscut != NULL);
    7137
    7138 benderscut->priority = priority;
    7139 benders->benderscutssorted = FALSE;
    7140
    7141 return SCIP_OKAY;
    7142}
    7144/** sorts Benders' decomposition cuts by priorities */
    7146 SCIP_BENDERS* benders /**< Benders' decomposition */
    7147 )
    7148{
    7149 assert(benders != NULL);
    7150
    7151 if( !benders->benderscutssorted )
    7152 {
    7153 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
    7154 benders->benderscutssorted = TRUE;
    7155 benders->benderscutsnamessorted = FALSE;
    7156 }
    7157}
    7159/** sorts Benders' decomposition cuts by name */
    7161 SCIP_BENDERS* benders /**< Benders' decomposition */
    7162 )
    7163{
    7164 assert(benders != NULL);
    7165
    7166 if( !benders->benderscutsnamessorted )
    7167 {
    7168 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutCompName, benders->nbenderscuts);
    7169 benders->benderscutssorted = FALSE;
    7170 benders->benderscutsnamessorted = TRUE;
    7171 }
    7172}
    SCIP_RETCODE SCIPbenderscutExit(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
    Definition: benderscut.c:268
    SCIP_RETCODE SCIPbenderscutFree(SCIP_BENDERSCUT **benderscut, SCIP_SET *set)
    Definition: benderscut.c:203
    SCIP_RETCODE SCIPbenderscutInitsol(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
    Definition: benderscut.c:298
    SCIP_RETCODE SCIPbenderscutExitsol(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
    Definition: benderscut.c:322
    SCIP_RETCODE SCIPbenderscutExec(SCIP_BENDERSCUT *benderscut, SCIP_SET *set, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type, SCIP_RESULT *result)
    Definition: benderscut.c:346
    SCIP_RETCODE SCIPbenderscutCopyInclude(SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
    Definition: benderscut.c:86
    SCIP_RETCODE SCIPbenderscutInit(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
    Definition: benderscut.c:229
    internal methods for Benders' decomposition cuts
    void SCIPclockStop(SCIP_CLOCK *clck, SCIP_SET *set)
    Definition: clock.c:360
    void SCIPclockEnableOrDisable(SCIP_CLOCK *clck, SCIP_Bool enable)
    Definition: clock.c:260
    void SCIPclockStart(SCIP_CLOCK *clck, SCIP_SET *set)
    Definition: clock.c:290
    SCIP_Real SCIPclockGetTime(SCIP_CLOCK *clck)
    Definition: clock.c:438
    void SCIPclockReset(SCIP_CLOCK *clck)
    Definition: clock.c:209
    void SCIPclockFree(SCIP_CLOCK **clck)
    Definition: clock.c:185
    SCIP_RETCODE SCIPclockCreate(SCIP_CLOCK **clck, SCIP_CLOCKTYPE clocktype)
    Definition: clock.c:170
    internal methods for clocks and timing issues
    Constraint handler for linear constraints in their most general form, .
    constraint handler for nonlinear constraints specified by algebraic expressions
    internal methods for decompositions and the decomposition store
    common defines and data types used in all packages of SCIP
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define EPSGE(x, y, eps)
    Definition: def.h:187
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:297
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_ALLOC(x)
    Definition: def.h:366
    #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 SCIPABORT()
    Definition: def.h:327
    #define SCIP_CALL(x)
    Definition: def.h:355
    #define SCIP_CALL_FINALLY(x, y)
    Definition: def.h:397
    SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    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_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
    SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
    SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
    SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
    int SCIPgetSubscipDepth(SCIP *scip)
    Definition: scip_copy.c:2588
    SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
    Definition: scip_copy.c:1580
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    const char * SCIPgetProbName(SCIP *scip)
    Definition: scip_prob.c:1242
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    int SCIPgetNOrigConss(SCIP *scip)
    Definition: scip_prob.c:3712
    SCIP_CONS ** SCIPgetConss(SCIP *scip)
    Definition: scip_prob.c:3666
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    int SCIPgetNConss(SCIP *scip)
    Definition: scip_prob.c:3620
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_CONS ** SCIPgetOrigConss(SCIP *scip)
    Definition: scip_prob.c:3739
    SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
    Definition: scip_prob.c:1400
    SCIP_Bool SCIPisObjIntegral(SCIP *scip)
    Definition: scip_prob.c:1801
    SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
    Definition: scip_prob.c:3189
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
    Definition: misc.c:3613
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
    Definition: misc.c:3143
    int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3584
    SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
    Definition: misc.c:3592
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
    Definition: scip_message.c:88
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
    SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
    Definition: misc.c:11162
    SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
    Definition: scip_param.c:250
    SCIP_PARAM * SCIPgetParam(SCIP *scip, const char *name)
    Definition: scip_param.c:234
    SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    SCIP_RETCODE SCIPsetHeuristics(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:930
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
    Definition: scip_param.c:307
    SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:956
    SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
    Definition: scip_param.c:661
    SCIP_Bool SCIPgetSubscipsOff(SCIP *scip)
    Definition: scip_param.c:1033
    SCIP_RETCODE SCIPgetLongintParam(SCIP *scip, const char *name, SCIP_Longint *value)
    Definition: scip_param.c:288
    SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
    Definition: scip_param.c:269
    SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
    Definition: scip_param.c:429
    SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
    Definition: scip_param.c:603
    SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
    Definition: scip_param.c:326
    void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
    Definition: misc.c:1324
    SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
    Definition: misc.c:1396
    int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1529
    SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)))
    Definition: misc.c:1297
    void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1495
    SCIP_BENDERSOBJTYPE SCIPbendersGetObjectiveType(SCIP_BENDERS *benders)
    Definition: benders.c:6852
    SCIP_Real SCIPbendersGetSetupTime(SCIP_BENDERS *benders)
    Definition: benders.c:6083
    void SCIPbendersSetSubproblemObjval(SCIP_BENDERS *benders, int probnumber, SCIP_Real objval)
    Definition: benders.c:6285
    SCIP_RETCODE SCIPbendersSolSlackVarsActive(SCIP_BENDERS *benders, SCIP_Bool *activeslack)
    Definition: benders.c:6314
    SCIP_Bool SCIPbendersCutRelaxation(SCIP_BENDERS *benders)
    Definition: benders.c:6145
    int SCIPbendersGetNTransferredCuts(SCIP_BENDERS *benders)
    Definition: benders.c:6862
    SCIP_Bool SCIPbendersSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6465
    int SCIPbendersGetNStrengthenFails(SCIP_BENDERS *benders)
    Definition: benders.c:6073
    int SCIPgetBendersNSubproblems(SCIP *scip, SCIP_BENDERS *benders)
    Definition: scip_benders.c:747
    SCIP_RETCODE SCIPbendersGetStoredCutOrigData(SCIP_BENDERS *benders, int cutidx, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars, int varssize)
    Definition: benders.c:6946
    SCIP_BENDERS ** SCIPgetBenders(SCIP *scip)
    Definition: scip_benders.c:508
    void SCIPbendersSetSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isnonlinear)
    Definition: benders.c:6487
    void SCIPbendersSetMasterIsNonlinear(SCIP_BENDERS *benders, SCIP_Bool isnonlinear)
    Definition: benders.c:6529
    SCIP_BENDERS * SCIPfindBenders(SCIP *scip, const char *name)
    Definition: scip_benders.c:493
    void SCIPbendersSetData(SCIP_BENDERS *benders, SCIP_BENDERSDATA *bendersdata)
    Definition: benders.c:5802
    SCIP_Bool SCIPbendersOnlyCheckConvexRelax(SCIP_BENDERS *benders, SCIP_Bool subscipsoff)
    Definition: benders.c:3301
    SCIP_Bool SCIPbendersSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6507
    int SCIPbendersGetPriority(SCIP_BENDERS *benders)
    Definition: benders.c:5987
    SCIP_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6213
    SCIP_BENDERSCUT * SCIPfindBenderscut(SCIP_BENDERS *benders, const char *name)
    Definition: benders.c:7078
    const char * SCIPbendersGetDesc(SCIP_BENDERS *benders)
    Definition: benders.c:5977
    int SCIPbendersGetNConvexSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6477
    SCIP_BENDERSSUBTYPE SCIPbendersGetSubproblemType(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6424
    SCIP_VAR ** SCIPbendersGetSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6235
    SCIP_RETCODE SCIPbendersSolveSubproblemCIP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Bool solvecip)
    Definition: benders.c:5230
    int SCIPbendersGetNNonlinearSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6519
    void SCIPsetBendersPriority(SCIP *scip, SCIP_BENDERS *benders, int priority)
    Definition: scip_benders.c:590
    SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
    Definition: benders.c:5047
    SCIP_Bool SCIPbendersSubproblemIsEnabled(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6780
    SCIP_RETCODE SCIPgetBendersMasterVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar)
    Definition: scip_benders.c:685
    int SCIPbendersGetNStrengthenCalls(SCIP_BENDERS *benders)
    Definition: benders.c:6063
    SCIP_RETCODE SCIPgetBendersSubproblemVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
    Definition: scip_benders.c:721
    int SCIPbendersGetNStoredCuts(SCIP_BENDERS *benders)
    Definition: benders.c:6905
    SCIP_RETCODE SCIPbendersSolveSubproblemLP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Real *objective)
    Definition: benders.c:5060
    int SCIPbendersGetNBenderscuts(SCIP_BENDERS *benders)
    Definition: benders.c:7117
    void SCIPbendersSetSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isconvex)
    Definition: benders.c:6442
    SCIP_Bool SCIPbendersIsActive(SCIP_BENDERS *benders)
    Definition: benders.c:2988
    SCIP_Bool SCIPbendersSubproblemsAreInfeasible(SCIP_BENDERS *benders)
    Definition: benders.c:6577
    void SCIPbendersSetSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber, SCIP_Bool issetup)
    Definition: benders.c:6675
    SCIP_BENDERSDATA * SCIPbendersGetData(SCIP_BENDERS *benders)
    Definition: benders.c:5792
    const char * SCIPbendersGetName(SCIP_BENDERS *benders)
    Definition: benders.c:5967
    SCIP_Bool SCIPbendersCutPseudo(SCIP_BENDERS *benders)
    Definition: benders.c:6135
    SCIP_VAR ** SCIPbendersGetAuxiliaryVars(SCIP_BENDERS *benders)
    Definition: benders.c:6225
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6011
    void SCIPbendersSetSubproblemType(SCIP_BENDERS *benders, int probnumber, SCIP_BENDERSSUBTYPE subprobtype)
    Definition: benders.c:6399
    int SCIPbendersGetNStrengthenCutsFound(SCIP_BENDERS *benders)
    Definition: benders.c:6053
    void SCIPbendersUpdateSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber, SCIP_Real lowerbound)
    Definition: benders.c:6874
    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_Bool SCIPbendersMasterIsNonlinear(SCIP_BENDERS *benders)
    Definition: benders.c:6540
    SCIP_RETCODE SCIPbendersGetStoredCutData(SCIP_BENDERS *benders, int cutidx, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars)
    Definition: benders.c:6915
    int SCIPbendersGetNCalls(SCIP_BENDERS *benders)
    Definition: benders.c:6033
    SCIP_Bool SCIPbendersIsInitialized(SCIP_BENDERS *benders)
    Definition: benders.c:6115
    int SCIPbendersGetNCutsFound(SCIP_BENDERS *benders)
    Definition: benders.c:6043
    SCIP_Bool SCIPbendersShareAuxVars(SCIP_BENDERS *benders)
    Definition: benders.c:6155
    SCIP_Bool SCIPbendersCutLP(SCIP_BENDERS *benders)
    Definition: benders.c:6125
    SCIP_RETCODE SCIPbendersSetBenderscutPriority(SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, int priority)
    Definition: benders.c:7127
    SCIP_Real SCIPbendersGetTime(SCIP_BENDERS *benders)
    Definition: benders.c:6093
    SCIP_Bool SCIPbendersSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6740
    SCIP_RETCODE SCIPsolveBendersSubproblems(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool *infeasible, SCIP_Bool *auxviol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint)
    Definition: scip_benders.c:647
    SCIP_BENDERSCUT ** SCIPbendersGetBenderscuts(SCIP_BENDERS *benders)
    Definition: benders.c:7100
    SCIP_VAR * SCIPbenderGetMasterAuxiliaryVar(SCIP_BENDERS *benders)
    Definition: benders.c:6203
    SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6302
    void SCIPbendersSetSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isindep)
    Definition: benders.c:6700
    SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
    Definition: benders.c:6550
    SCIP_Bool SCIPbendersSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6688
    SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6893
    int SCIPbendersGetNSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6247
    SCIP_Bool SCIPbenderscutIsLPCut(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:583
    const char * SCIPbenderscutGetName(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:492
    SCIP_Longint SCIPbenderscutGetNFound(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:543
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4316
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8409
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8578
    SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
    Definition: cons.c:8608
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
    Definition: scip_cons.c:1474
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8568
    SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1138
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8658
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_RETCODE SCIPsetEventhdlrInitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTINITSOL((*eventinitsol)))
    Definition: scip_event.c:199
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
    Definition: scip_event.c:241
    const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:396
    SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:406
    SCIP_RETCODE SCIPsetEventhdlrExitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTEXITSOL((*eventexitsol)))
    Definition: scip_event.c:213
    void SCIPeventhdlrSetData(SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event.c:416
    SCIP_RETCODE SCIPsetEventhdlrFree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTFREE((*eventfree)))
    Definition: scip_event.c:157
    SCIP_RETCODE SCIPsetEventhdlrExit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTEXIT((*eventexit)))
    Definition: scip_event.c:185
    SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:293
    SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:333
    SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1742
    SCIP_Bool SCIPinDive(SCIP *scip)
    Definition: scip_lp.c:2740
    SCIP_RETCODE SCIPconstructLP(SCIP *scip, SCIP_Bool *cutoff)
    Definition: scip_lp.c:130
    SCIP_Bool SCIPisLPConstructed(SCIP *scip)
    Definition: scip_lp.c:105
    SCIP_RETCODE SCIPcomputeLPRelIntPoint(SCIP *scip, SCIP_Bool relaxrows, SCIP_Bool inclobjcutoff, SCIP_Real timelimit, int iterlimit, SCIP_SOL **point)
    Definition: scip_lp.c:1103
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
    Definition: scip_mem.c:126
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    SCIP_Longint SCIPgetMemUsed(SCIP *scip)
    Definition: scip_mem.c:100
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocClearBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:97
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    int SCIPgetNNlpis(SCIP *scip)
    Definition: scip_nlpi.c:205
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
    Definition: scip_nlp.c:574
    SCIP_Real SCIPgetNLPObjval(SCIP *scip)
    Definition: scip_nlp.c:645
    SCIP_RETCODE SCIPsolveNLPParam(SCIP *scip, SCIP_NLPPARAM param)
    Definition: scip_nlp.c:545
    SCIP_NLPTERMSTAT SCIPgetNLPTermstat(SCIP *scip)
    Definition: scip_nlp.c:596
    SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:346
    SCIP_RETCODE SCIPchgVarObjProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
    Definition: scip_probing.c:475
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_RETCODE SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    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 SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:516
    SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
    Definition: scip_sol.c:884
    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 SCIPcreateCurrentSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:749
    SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:664
    SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:608
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1506
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1892
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2005
    SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2132
    SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
    Definition: scip_solve.c:3603
    SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
    Definition: scip_solve.c:3462
    SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
    Definition: scip_solve.c:3548
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2635
    SCIP_Real SCIPgetPrimalbound(SCIP *scip)
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
    SCIP_Real SCIPgetSolvingTime(SCIP *scip)
    Definition: scip_timing.c:378
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPinRepropagation(SCIP *scip)
    Definition: scip_tree.c:146
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
    Definition: var.c:18320
    SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:5697
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23386
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    int SCIPvarGetNLocksDown(SCIP_VAR *var)
    Definition: var.c:4449
    SCIP_Real SCIPvarGetLbOriginal(SCIP_VAR *var)
    Definition: var.c:24020
    SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:5875
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10218
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5118
    SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
    Definition: scip_var.c:225
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Real SCIPvarGetUbOriginal(SCIP_VAR *var)
    Definition: var.c:24063
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10113
    void SCIPvarSetData(SCIP_VAR *var, SCIP_VARDATA *vardata)
    Definition: var.c:23297
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
    Definition: scip_var.c:184
    SCIP_VAR * SCIPvarGetTransVar(SCIP_VAR *var)
    Definition: var.c:23672
    SCIP_RETCODE SCIPchgVarObj(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
    Definition: scip_var.c:5372
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    internal methods for LP management
    static const char * paramname[]
    Definition: lpi_msk.c:5172
    #define BMSfreeMemory(ptr)
    Definition: memory.h:145
    #define BMSreallocMemoryArray(ptr, num)
    Definition: memory.h:127
    #define BMSduplicateMemoryArray(ptr, source, num)
    Definition: memory.h:143
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define BMSallocMemoryArray(ptr, num)
    Definition: memory.h:123
    #define BMSfreeMemoryArray(ptr)
    Definition: memory.h:147
    #define BMSallocBlockMemoryArray(mem, ptr, num)
    Definition: memory.h:454
    #define BMSfreeBlockMemoryArray(mem, ptr, num)
    Definition: memory.h:467
    #define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
    Definition: memory.h:458
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    #define BMSallocClearMemoryArray(ptr, num)
    Definition: memory.h:125
    struct BMS_BlkMem BMS_BLKMEM
    Definition: memory.h:437
    #define BMSfreeMemoryArrayNull(ptr)
    Definition: memory.h:148
    #define BMSallocMemory(ptr)
    Definition: memory.h:118
    void SCIPmessagePrintVerbInfo(SCIP_MESSAGEHDLR *messagehdlr, SCIP_VERBLEVEL verblevel, SCIP_VERBLEVEL msgverblevel, const char *formatstr,...)
    Definition: message.c:678
    SCIP_Real SCIPconsGetLhs(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    Definition: misc_linear.c:112
    SCIP_RETCODE SCIPconsAddCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    Definition: misc_linear.c:675
    SCIP_Real SCIPconsGetRhs(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    Definition: misc_linear.c:48
    SCIP_PARAMDATA * SCIPparamGetData(SCIP_PARAM *param)
    Definition: paramset.c:678
    int SCIPparamGetInt(SCIP_PARAM *param)
    Definition: paramset.c:733
    SCIP_Real SCIPparamGetRealMax(SCIP_PARAM *param)
    Definition: paramset.c:852
    internal methods for handling parameter settings
    internal methods for storing priced variables
    internal methods for storing and manipulating the main problem
    public methods for Benders' decomposition
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    public data structures and miscellaneous methods
    SCIP callable library.
    default SCIP plugins
    SCIP_RETCODE SCIPsetAddIntParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, 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: set.c:3229
    SCIP_Bool SCIPsetGetSubscipsOff(SCIP_SET *set)
    Definition: set.c:7703
    SCIP_RETCODE SCIPsetAddCharParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: set.c:3301
    SCIP_Real SCIPsetCeil(SCIP_SET *set, SCIP_Real val)
    Definition: set.c:6728
    SCIP_RETCODE SCIPsetAddBoolParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: set.c:3207
    SCIP_Bool SCIPsetIsLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
    Definition: set.c:6577
    SCIP_RETCODE SCIPsetAddRealParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, 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: set.c:3277
    SCIP_BENDERS * SCIPsetFindBenders(SCIP_SET *set, const char *name)
    Definition: set.c:4055
    SCIP_STAGE SCIPsetGetStage(SCIP_SET *set)
    Definition: set.c:3197
    SCIP_Real SCIPsetInfinity(SCIP_SET *set)
    Definition: set.c:6380
    SCIP_Bool SCIPsetIsInfinity(SCIP_SET *set, SCIP_Real val)
    Definition: set.c:6515
    SCIP_RETCODE SCIPsetGetRealParam(SCIP_SET *set, const char *name, SCIP_Real *value)
    Definition: set.c:3410
    SCIP_Bool SCIPsetIsGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
    Definition: set.c:6597
    SCIP_EVENTHDLR * SCIPsetFindEventhdlr(SCIP_SET *set, const char *name)
    Definition: set.c:5011
    int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
    Definition: set.c:6080
    internal methods for global SCIP settings
    #define SCIPsetDebugMsg
    Definition: set.h:1811
    SCIP_RETCODE SCIPbendersGetVar(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
    Definition: benders.c:5766
    void SCIPbendersSetSolvesubconvex(SCIP_BENDERS *benders, SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)))
    Definition: benders.c:5912
    static void createSolveSubproblemIndexList(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type, int **solveidx, int *nsolveidx)
    Definition: benders.c:3337
    #define SCIP_DEFAULT_LNSMAXCALLSROOT
    Definition: benders.c:64
    #define AUXILIARYVAR_NAME
    Definition: benders.c:87
    #define SCIP_DEFAULT_STRENGTHENPERTURB
    Definition: benders.c:71
    SCIP_Bool SCIPbendersSubproblemIsOptimal(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber)
    Definition: benders.c:5371
    void SCIPbendersSetPresubsolve(SCIP_BENDERS *benders, SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)))
    Definition: benders.c:5901
    #define NODESOLVED_EVENTHDLR_NAME
    Definition: benders.c:101
    #define SCIP_DEFAULT_LNSMAXDEPTH
    Definition: benders.c:62
    void SCIPbendersSetObjectiveType(SCIP_BENDERS *benders, SCIP_BENDERSOBJTYPE objectivetype)
    Definition: benders.c:6841
    SCIP_RETCODE SCIPbendersActivate(SCIP_BENDERS *benders, SCIP_SET *set, int nsubproblems)
    Definition: benders.c:2790
    SCIP_RETCODE SCIPbendersComputeSubproblemLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Real *lowerbound, SCIP_Bool *infeasible)
    Definition: benders.c:5421
    void SCIPbendersRemoveSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6191
    static SCIP_RETCODE executeUserDefinedSolvesub(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool *infeasible, SCIP_Real *objective, SCIP_RESULT *result)
    Definition: benders.c:4401
    static SCIP_RETCODE initsolEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTTYPE eventtype)
    Definition: benders.c:137
    static SCIP_RETCODE storeSubproblemMasterVars(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:1503
    static SCIP_RETCODE performInteriorSolCutStrengthening(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint, SCIP_Bool perturbsol, SCIP_Bool *auxviol, SCIP_Bool *infeasible, SCIP_Bool *skipsolve, SCIP_RESULT *result)
    Definition: benders.c:3142
    void SCIPbendersSetExit(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXIT((*bendersexit)))
    Definition: benders.c:5846
    #define SCIP_DEFAULT_STRENGTHENENABLED
    Definition: benders.c:72
    #define SCIP_DEFAULT_UPDATEAUXVARBOUND
    Definition: benders.c:66
    #define SCIP_DEFAULT_LNSMAXCALLS
    Definition: benders.c:63
    #define SCIP_DEFAULT_SLACKVARCOEF
    Definition: benders.c:78
    SCIP_RETCODE SCIPbendersFreeSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:5321
    #define SCIP_DEFAULT_LNSCHECK
    Definition: benders.c:61
    #define BENDERS_MAXPSEUDOSOLS
    Definition: benders.c:83
    void SCIPbendersSetPriority(SCIP_BENDERS *benders, SCIP_SET *set, int priority)
    Definition: benders.c:5997
    static SCIP_DECL_SORTPTRCOMP(benderssubcompdefault)
    Definition: benders.c:609
    static SCIP_Bool subproblemIsActive(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:3326
    static SCIP_RETCODE addSlackVars(SCIP *scip, SCIP_BENDERS *benders, SCIP_CONS *cons, SCIP_CONSHDLR **linearconshdlrs, SCIP_CONSHDLR *nlconshdlr, int nlinearconshdlrs)
    Definition: benders.c:1541
    SCIP_RETCODE SCIPbendersExit(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2451
    void SCIPbendersSetInitsol(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINITSOL((*bendersinitsol)))
    Definition: benders.c:5879
    static SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodefocus)
    Definition: benders.c:249
    SCIP_RETCODE SCIPbendersChgMastervarsToCont(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:6587
    #define SCIP_DEFAULT_NLPITERLIMIT
    Definition: benders.c:81
    void SCIPbendersSortBenderscuts(SCIP_BENDERS *benders)
    Definition: benders.c:7143
    SCIP_RETCODE SCIPbendersSetupSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type)
    Definition: benders.c:4641
    static SCIP_RETCODE setAndUpdateCorePoint(SCIP *scip, SCIP_BENDERS *benders)
    Definition: benders.c:3056
    #define SCIP_DEFAULT_STRENGTHENMULT
    Definition: benders.c:69
    static SCIP_RETCODE createSubproblems(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2000
    SCIP_RETCODE SCIPbendersSetMastervarsCont(SCIP_BENDERS *benders, int probnumber, SCIP_Bool arecont)
    Definition: benders.c:6792
    static SCIP_RETCODE freeEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
    Definition: benders.c:201
    #define SCIP_DEFAULT_STRENGTHENINTPOINT
    Definition: benders.c:73
    void SCIPbendersSetSolvesub(SCIP_BENDERS *benders, SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)))
    Definition: benders.c:5923
    void SCIPbendersSetSubproblemsAreInfeasible(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:6562
    void SCIPbendersSetExitsol(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)))
    Definition: benders.c:5890
    void SCIPbendersSortBenderscutsName(SCIP_BENDERS *benders)
    Definition: benders.c:7158
    static SCIP_RETCODE resetOrigSubproblemParams(SCIP *subproblem, SCIP_SUBPROBPARAMS *origparams)
    Definition: benders.c:5021
    #define SCIP_DEFAULT_CHECKCONSCONVEXITY
    Definition: benders.c:80
    SCIP_RETCODE SCIPbendersCreate(SCIP_BENDERS **benders, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, int priority, SCIP_Bool cutlp, SCIP_Bool cutpseudo, SCIP_Bool cutrelax, SCIP_Bool shareauxvars, SCIP_DECL_BENDERSCOPY((*benderscopy)), SCIP_DECL_BENDERSFREE((*bendersfree)), SCIP_DECL_BENDERSINIT((*bendersinit)), SCIP_DECL_BENDERSEXIT((*bendersexit)), SCIP_DECL_BENDERSINITPRE((*bendersinitpre)), SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)), SCIP_DECL_BENDERSINITSOL((*bendersinitsol)), SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)), SCIP_DECL_BENDERSGETVAR((*bendersgetvar)), SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)), SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)), SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)), SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)), SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)), SCIP_DECL_BENDERSFREESUB((*bendersfreesub)), SCIP_BENDERSDATA *bendersdata)
    Definition: benders.c:1341
    static SCIP_RETCODE addSlackVarsToConstraints(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:1653
    static SCIP_RETCODE updateAuxiliaryVarLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_RESULT *result)
    Definition: benders.c:2999
    #define SCIP_DEFAULT_MAXSLACKVARCOEF
    Definition: benders.c:79
    static SCIP_RETCODE generateBendersCuts(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_BENDERSENFOTYPE type, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool checkint, SCIP_Bool *subprobsolved, SCIP_BENDERSSUBSTATUS *substatus, int *solveidx, int nsolveidx, int **mergecands, int *npriomergecands, int *nmergecands, int *nsolveloops)
    Definition: benders.c:3666
    static SCIP_RETCODE exitEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
    Definition: benders.c:181
    static SCIP_RETCODE solveBendersSubproblems(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_BENDERSENFOTYPE type, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool checkint, int *nverified, int *solveidx, int nsolveidx, SCIP_Bool **subprobsolved, SCIP_BENDERSSUBSTATUS **substatus, SCIP_Bool *infeasible, SCIP_Bool *optimal, SCIP_Bool *stopped)
    Definition: benders.c:3426
    static SCIP_RETCODE storeSubproblemMasterVar(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_VAR *var, int probnumber)
    Definition: benders.c:1464
    SCIP_RETCODE SCIPbendersCopyInclude(SCIP_BENDERS *benders, SCIP_SET *sourceset, SCIP_SET *targetset, SCIP_HASHMAP *varmap, SCIP_Bool threadsafe, SCIP_Bool *valid)
    Definition: benders.c:1058
    static SCIP_RETCODE createAndAddTransferredCut(SCIP *sourcescip, SCIP_BENDERS *benders, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars)
    Definition: benders.c:2287
    SCIP_RETCODE SCIPbendersMergeSubproblemIntoMaster(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, int probnumber)
    Definition: benders.c:5583
    #define BENDERS_MASTERVARARRAYSIZE
    Definition: benders.c:84
    static SCIP_RETCODE doBendersCreate(SCIP_BENDERS **benders, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, int priority, SCIP_Bool cutlp, SCIP_Bool cutpseudo, SCIP_Bool cutrelax, SCIP_Bool shareauxvars, SCIP_DECL_BENDERSCOPY((*benderscopy)), SCIP_DECL_BENDERSFREE((*bendersfree)), SCIP_DECL_BENDERSINIT((*bendersinit)), SCIP_DECL_BENDERSEXIT((*bendersexit)), SCIP_DECL_BENDERSINITPRE((*bendersinitpre)), SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)), SCIP_DECL_BENDERSINITSOL((*bendersinitsol)), SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)), SCIP_DECL_BENDERSGETVAR((*bendersgetvar)), SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)), SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)), SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)), SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)), SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)), SCIP_DECL_BENDERSFREESUB((*bendersfreesub)), SCIP_BENDERSDATA *bendersdata)
    Definition: benders.c:1129
    #define UPPERBOUND_EVENTHDLR_DESC
    Definition: benders.c:99
    static SCIP_DECL_EVENTEXITSOL(eventExitsolBendersNodefocus)
    Definition: benders.c:262
    static SCIP_RETCODE initialiseSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Bool *infeasible, SCIP_Bool *success)
    Definition: benders.c:1699
    #define SCIP_DEFAULT_AUXVARSIMPLINT
    Definition: benders.c:67
    static SCIP_RETCODE copyMemoryAndTimeLimits(SCIP *scip, SCIP *subproblem)
    Definition: benders.c:4910
    static SCIP_RETCODE transferBendersCuts(SCIP *sourcescip, SCIP *subscip, SCIP_BENDERS *benders)
    Definition: benders.c:2405
    void SCIPbendersSetBenderscutsSorted(SCIP_BENDERS *benders, SCIP_Bool sorted)
    Definition: benders.c:7042
    #define UPPERBOUND_EVENTHDLR_NAME
    Definition: benders.c:98
    static SCIP_RETCODE assignAuxiliaryVariables(SCIP *scip, SCIP_BENDERS *benders)
    Definition: benders.c:893
    #define NODEFOCUS_EVENTHDLR_DESC
    Definition: benders.c:93
    SCIP_RETCODE SCIPbendersFree(SCIP_BENDERS **benders, SCIP_SET *set)
    Definition: benders.c:1420
    void SCIPbendersSetSubproblemComp(SCIP_BENDERS *benders, SCIP_DECL_SORTPTRCOMP((*benderssubcomp)))
    Definition: benders.c:5945
    #define SLACKVAR_NAME
    Definition: benders.c:88
    SCIP_RETCODE SCIPbendersInitsol(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2701
    SCIP_RETCODE SCIPbendersExecSubproblemSolve(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool enhancement, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_BENDERSENFOTYPE type)
    Definition: benders.c:4472
    void SCIPbendersSetFreesub(SCIP_BENDERS *benders, SCIP_DECL_BENDERSFREESUB((*bendersfreesub)))
    Definition: benders.c:5956
    #define MIPNODEFOCUS_EVENTHDLR_DESC
    Definition: benders.c:96
    static SCIP_DECL_EVENTFREE(eventFreeBendersNodefocus)
    Definition: benders.c:288
    static SCIP_RETCODE releaseVarMappingHashmapVars(SCIP *scip, SCIP_BENDERS *benders)
    Definition: benders.c:1386
    static SCIP_RETCODE addAuxiliaryVariablesToMaster(SCIP *scip, SCIP_BENDERS *benders)
    Definition: benders.c:677
    #define SCIP_DEFAULT_NOIMPROVELIMIT
    Definition: benders.c:70
    static SCIP_DECL_EVENTEXIT(eventExitBendersNodefocus)
    Definition: benders.c:275
    static SCIP_DECL_EVENTEXEC(eventExecBendersNodefocus)
    Definition: benders.c:227
    static SCIP_RETCODE setSubproblemParams(SCIP *scip, SCIP *subproblem)
    Definition: benders.c:4970
    void SCIPbendersSetInit(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINIT((*bendersinit)))
    Definition: benders.c:5835
    #define NLINEARCONSHDLRS
    Definition: benders.c:89
    SCIP_RETCODE SCIPbendersDeactivate(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2890
    static SCIP_DECL_PARAMCHGD(paramChgdBendersPriority)
    Definition: benders.c:1003
    SCIP_RETCODE SCIPbendersStoreCut(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars)
    Definition: benders.c:6994
    void SCIPbendersSetCopy(SCIP_BENDERS *benders, SCIP_DECL_BENDERSCOPY((*benderscopy)))
    Definition: benders.c:5813
    SCIP_RETCODE SCIPbendersAddSubproblem(SCIP_BENDERS *benders, SCIP *subproblem)
    Definition: benders.c:6167
    #define SCIP_DEFAULT_TRANSFERCUTS
    Definition: benders.c:59
    SCIP_Real SCIPbendersGetAuxiliaryVarVal(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber)
    Definition: benders.c:5400
    SCIP_RETCODE SCIPbendersExec(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool *infeasible, SCIP_Bool *auxviol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint)
    Definition: benders.c:3864
    SCIP_Bool SCIPbendersGetMastervarsCont(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6827
    static SCIP_RETCODE exitsolEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTTYPE eventtype)
    Definition: benders.c:157
    void SCIPbendersSetFree(SCIP_BENDERS *benders, SCIP_DECL_BENDERSFREE((*bendersfree)))
    Definition: benders.c:5824
    static SCIP_RETCODE updateEventhdlrUpperbound(SCIP_BENDERS *benders, int probnumber, SCIP_Real upperbound)
    Definition: benders.c:460
    static SCIP_RETCODE storeOrigSubproblemParams(SCIP *subproblem, SCIP_SUBPROBPARAMS *origparams)
    Definition: benders.c:4943
    #define MIPNODEFOCUS_EVENTHDLR_NAME
    Definition: benders.c:95
    #define SCIP_DEFAULT_SUBPROBFRAC
    Definition: benders.c:65
    #define SCIP_DEFAULT_EXECFEASPHASE
    Definition: benders.c:77
    #define NODEFOCUS_EVENTHDLR_NAME
    Definition: benders.c:92
    SCIP_RETCODE SCIPbendersInitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
    Definition: benders.c:2617
    void SCIPbendersEnableOrDisableClocks(SCIP_BENDERS *benders, SCIP_Bool enable)
    Definition: benders.c:6103
    void SCIPbendersSetExitpre(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)))
    Definition: benders.c:5868
    static void findAuxiliaryVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR **targetvar, int subscipdepth, int probnumber)
    Definition: benders.c:844
    static SCIP_RETCODE updateSubproblemStatQueue(SCIP_BENDERS *benders, int *solveidx, int nsolveidx, SCIP_Bool updatestat)
    Definition: benders.c:3377
    static SCIP_RETCODE checkSubproblemConvexity(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:1792
    static SCIP_RETCODE updateSubproblemLowerbound(SCIP *masterprob, SCIP_BENDERS *benders)
    Definition: benders.c:489
    #define SCIP_DEFAULT_CUTCHECK
    Definition: benders.c:68
    #define SCIP_DEFAULT_CUTSASCONSS
    Definition: benders.c:60
    static SCIP_RETCODE initEventhandlerData(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: benders.c:119
    void SCIPbendersSetInitpre(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINITPRE((*bendersinitpre)))
    Definition: benders.c:5857
    void SCIPbendersSetSubproblemEnabled(SCIP_BENDERS *benders, int probnumber, SCIP_Bool enabled)
    Definition: benders.c:6754
    void SCIPbendersSetPostsolve(SCIP_BENDERS *benders, SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)))
    Definition: benders.c:5934
    SCIP_RETCODE SCIPbendersIncludeBenderscut(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSCUT *benderscut)
    Definition: benders.c:7054
    SCIP_RETCODE SCIPbendersExitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
    Definition: benders.c:2675
    static int numSubproblemsToCheck(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type)
    Definition: benders.c:3311
    SCIP_RETCODE SCIPbendersExitsol(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2734
    SCIP_RETCODE SCIPbendersSolveSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_Bool *infeasible, SCIP_Bool solvecip, SCIP_Real *objective)
    Definition: benders.c:4801
    static void resetSubproblemObjectiveValue(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:963
    #define BENDERS_ARRAYSIZE
    Definition: benders.c:85
    static SCIP_RETCODE initialiseLPSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Bool *infeasible)
    Definition: benders.c:1742
    static SCIP_RETCODE createMasterVarMapping(SCIP_BENDERS *benders, SCIP_SET *sourceset, SCIP_HASHMAP *varmap)
    Definition: benders.c:1018
    #define NODESOLVED_EVENTHDLR_DESC
    Definition: benders.c:102
    static SCIP_RETCODE checkSubproblemIndependence(SCIP *scip, SCIP_BENDERS *benders)
    Definition: benders.c:2563
    SCIP_RETCODE SCIPbendersInit(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2207
    internal methods for Benders' decomposition
    int * submastervarssize
    SCIP_Bool subprobsinfeasible
    SCIP_NLPPARAM nlpparam
    SCIP_Bool * subprobisconvex
    SCIP ** subproblems
    SCIP_Bool * subprobenabled
    SCIP_Bool transfercuts
    SCIP_BENDERSDATA * bendersdata
    SCIP_Bool threadsafe
    SCIP_SUBPROBLEMSOLVESTAT ** solvestat
    SCIP_Real slackvarcoef
    SCIP_Bool cutlp
    SCIP_Bool lnscheck
    SCIP_BENDERSOBJTYPE objectivetype
    SCIP_Bool strengthenround
    SCIP_Bool cutpseudo
    SCIP_Bool freesubprobs
    SCIP_CONS ** auxiliaryvarcons
    SCIP_Bool * mastervarscont
    SCIP_VAR ** auxiliaryvars
    SCIP_Real prevlowerbound
    SCIP_Bool * subprobsetup
    SCIP_Real * subprobobjval
    SCIP_Bool active
    SCIP_HASHMAP * mastervarsmap
    SCIP_Real perturbeps
    SCIP_PQUEUE * subprobqueue
    SCIP_VAR *** submastervars
    SCIP_Bool execfeasphase
    SCIP_Real * bestsubprobobjval
    SCIP_Bool benderscutssorted
    SCIP_Real maxslackvarcoef
    SCIP_Bool initialized
    SCIP_Bool cutsasconss
    SCIP_BENDERSSUBTYPE * subprobtype
    int * nsubmastervars
    SCIP_Real convexmult
    SCIP_Bool shareauxvars
    SCIP_Longint prevnlpiter
    SCIP_Bool * subprobisnonlinear
    SCIP_Bool * indepsubprob
    SCIP_Bool cutcheck
    SCIP_Bool strengthenenabled
    SCIP_Bool iscopy
    SCIP_Bool benderscutsnamessorted
    char strengthenintpoint
    SCIP_Bool masterisnonlinear
    SCIP_BENDERSCUTCUT ** storedcuts
    SCIP_Real subprobfrac
    SCIP_Bool feasibilityphase
    SCIP_BENDERSCUT ** benderscuts
    SCIP_CLOCK * setuptime
    SCIP_CLOCK * bendersclock
    SCIP_Bool cutrelax
    SCIP_Bool subprobscreated
    SCIP_Bool updateauxvarbound
    SCIP_SOL * corepoint
    SCIP_Bool checkconsconvexity
    int * nsubmasterbinvars
    SCIP_SOL * initcorepoint
    SCIP_NODE * prevnode
    SCIP_Bool auxvarsimplint
    SCIP_Real solutiontol
    int * nsubmasterintvars
    SCIP_VAR * masterauxvar
    SCIP_Real * subproblowerbound
    SCIP * scip
    Definition: struct_set.h:77
    SCIP_Bool benders_copybenders
    Definition: struct_set.h:513
    data structures required for Benders' decomposition
    datastructures for Benders' decomposition cuts techniques
    Definition: heur_padm.c:135
    #define SCIP_DECL_BENDERSFREESUB(x)
    Definition: type_benders.h:362
    #define SCIP_DECL_BENDERSCREATESUB(x)
    Definition: type_benders.h:206
    #define SCIP_DECL_BENDERSCOPY(x)
    Definition: type_benders.h:107
    @ SCIP_BENDERSENFOTYPE_LP
    Definition: type_benders.h:51
    @ SCIP_BENDERSENFOTYPE_CHECK
    Definition: type_benders.h:54
    @ SCIP_BENDERSENFOTYPE_PSEUDO
    Definition: type_benders.h:53
    #define SCIP_DECL_BENDERSSOLVESUB(x)
    Definition: type_benders.h:304
    enum SCIP_BendersObjectiveType SCIP_BENDERSOBJTYPE
    Definition: type_benders.h:91
    #define SCIP_DECL_BENDERSEXITPRE(x)
    Definition: type_benders.h:152
    @ SCIP_BENDERSSUBSTATUS_AUXVIOL
    Definition: type_benders.h:71
    @ SCIP_BENDERSSUBSTATUS_UNKNOWN
    Definition: type_benders.h:69
    @ SCIP_BENDERSSUBSTATUS_INFEAS
    Definition: type_benders.h:72
    @ SCIP_BENDERSSUBSTATUS_OPTIMAL
    Definition: type_benders.h:70
    #define SCIP_DECL_BENDERSSOLVESUBCONVEX(x)
    Definition: type_benders.h:271
    #define SCIP_DECL_BENDERSINIT(x)
    Definition: type_benders.h:124
    #define SCIP_DECL_BENDERSFREE(x)
    Definition: type_benders.h:115
    #define SCIP_DECL_BENDERSEXITSOL(x)
    Definition: type_benders.h:174
    @ SCIP_BENDERSOBJTYPE_SUM
    Definition: type_benders.h:88
    @ SCIP_BENDERSOBJTYPE_MAX
    Definition: type_benders.h:89
    #define SCIP_DECL_BENDERSPRESUBSOLVE(x)
    Definition: type_benders.h:230
    @ SCIP_BENDERSSUBTYPE_NONCONVEXDIS
    Definition: type_benders.h:81
    @ SCIP_BENDERSSUBTYPE_CONVEXCONT
    Definition: type_benders.h:78
    @ SCIP_BENDERSSUBTYPE_NONCONVEXCONT
    Definition: type_benders.h:80
    @ SCIP_BENDERSSUBTYPE_CONVEXDIS
    Definition: type_benders.h:79
    @ SCIP_BENDERSSUBTYPE_UNKNOWN
    Definition: type_benders.h:82
    enum SCIP_BendersSubType SCIP_BENDERSSUBTYPE
    Definition: type_benders.h:84
    @ SCIP_BENDERSSOLVELOOP_CIP
    Definition: type_benders.h:61
    @ SCIP_BENDERSSOLVELOOP_CONVEX
    Definition: type_benders.h:60
    @ SCIP_BENDERSSOLVELOOP_USERCONVEX
    Definition: type_benders.h:62
    @ SCIP_BENDERSSOLVELOOP_USERCIP
    Definition: type_benders.h:63
    enum SCIP_BendersSolveLoop SCIP_BENDERSSOLVELOOP
    Definition: type_benders.h:65
    enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
    Definition: type_benders.h:56
    #define SCIP_DECL_BENDERSGETVAR(x)
    Definition: type_benders.h:378
    enum SCIP_BendersSubStatus SCIP_BENDERSSUBSTATUS
    Definition: type_benders.h:74
    #define SCIP_DECL_BENDERSPOSTSOLVE(x)
    Definition: type_benders.h:340
    #define SCIP_DECL_BENDERSINITPRE(x)
    Definition: type_benders.h:144
    #define SCIP_DECL_BENDERSEXIT(x)
    Definition: type_benders.h:133
    #define SCIP_DECL_BENDERSINITSOL(x)
    Definition: type_benders.h:163
    struct SCIP_BendersData SCIP_BENDERSDATA
    Definition: type_benders.h:94
    @ SCIP_CLOCKTYPE_DEFAULT
    Definition: type_clock.h:43
    #define SCIP_EVENTTYPE_NODEFOCUSED
    Definition: type_event.h:93
    struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
    Definition: type_event.h:160
    #define SCIP_EVENTTYPE_NODESOLVED
    Definition: type_event.h:138
    #define SCIP_EVENTTYPE_BESTSOLFOUND
    Definition: type_event.h:106
    uint64_t SCIP_EVENTTYPE
    Definition: type_event.h:156
    SCIP_EXPRCURV
    Definition: type_expr.h:61
    @ SCIP_EXPRCURV_CONVEX
    Definition: type_expr.h:63
    @ SCIP_EXPRCURV_CONCAVE
    Definition: type_expr.h:64
    @ SCIP_LPSOLSTAT_ERROR
    Definition: type_lp.h:50
    @ SCIP_LPSOLSTAT_NOTSOLVED
    Definition: type_lp.h:43
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_LPSOLSTAT_TIMELIMIT
    Definition: type_lp.h:49
    @ SCIP_LPSOLSTAT_UNBOUNDEDRAY
    Definition: type_lp.h:46
    @ SCIP_LPSOLSTAT_INFEASIBLE
    Definition: type_lp.h:45
    @ SCIP_LPSOLSTAT_OBJLIMIT
    Definition: type_lp.h:47
    @ SCIP_LPSOLSTAT_ITERLIMIT
    Definition: type_lp.h:48
    @ SCIP_VERBLEVEL_NONE
    Definition: type_message.h:57
    @ SCIP_VERBLEVEL_MINIMAL
    Definition: type_message.h:59
    @ SCIP_VERBLEVEL_HIGH
    Definition: type_message.h:61
    @ SCIP_VERBLEVEL_FULL
    Definition: type_message.h:62
    #define SCIP_NLPPARAM_DEFAULT(scip)
    Definition: type_nlpi.h:126
    enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
    Definition: type_nlpi.h:168
    @ SCIP_NLPTERMSTAT_OKAY
    Definition: type_nlpi.h:173
    @ SCIP_NLPTERMSTAT_TIMELIMIT
    Definition: type_nlpi.h:174
    @ SCIP_NLPTERMSTAT_ITERLIMIT
    Definition: type_nlpi.h:175
    @ SCIP_NLPTERMSTAT_INTERRUPT
    Definition: type_nlpi.h:177
    @ SCIP_NLPSOLSTAT_UNBOUNDED
    Definition: type_nlpi.h:165
    @ SCIP_NLPSOLSTAT_GLOBINFEASIBLE
    Definition: type_nlpi.h:164
    @ SCIP_NLPSOLSTAT_LOCINFEASIBLE
    Definition: type_nlpi.h:163
    @ SCIP_NLPSOLSTAT_FEASIBLE
    Definition: type_nlpi.h:162
    @ SCIP_NLPSOLSTAT_LOCOPT
    Definition: type_nlpi.h:161
    @ SCIP_NLPSOLSTAT_GLOBOPT
    Definition: type_nlpi.h:160
    enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
    Definition: type_nlpi.h:184
    @ SCIP_PARAMSETTING_OFF
    Definition: type_paramset.h:63
    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_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_CONSADDED
    Definition: type_result.h:52
    @ SCIP_UNBOUNDED
    Definition: type_result.h:47
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    @ SCIP_SOLVELP
    Definition: type_result.h:55
    @ SCIP_INFEASIBLE
    Definition: type_result.h:46
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_INVALIDRESULT
    Definition: type_retcode.h:53
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_PROBLEM
    Definition: type_set.h:45
    @ SCIP_STAGE_SOLVED
    Definition: type_set.h:54
    @ SCIP_STAGE_TRANSFORMED
    Definition: type_set.h:47
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52
    @ SCIP_STAGE_INIT
    Definition: type_set.h:44
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_STAGE_PRESOLVED
    Definition: type_set.h:51
    @ SCIP_STATUS_OPTIMAL
    Definition: type_stat.h:43
    @ SCIP_STATUS_BESTSOLLIMIT
    Definition: type_stat.h:60
    @ SCIP_STATUS_UNBOUNDED
    Definition: type_stat.h:45
    @ SCIP_STATUS_UNKNOWN
    Definition: type_stat.h:42
    @ SCIP_STATUS_USERINTERRUPT
    Definition: type_stat.h:47
    @ SCIP_STATUS_TIMELIMIT
    Definition: type_stat.h:54
    @ SCIP_STATUS_INFEASIBLE
    Definition: type_stat.h:44
    @ SCIP_STATUS_MEMLIMIT
    Definition: type_stat.h:55
    enum SCIP_Status SCIP_STATUS
    Definition: type_stat.h:64
    struct SCIP_VarData SCIP_VARDATA
    Definition: type_var.h:167
    enum SCIP_ImplintType SCIP_IMPLINTTYPE
    Definition: type_var.h:117
    @ SCIP_IMPLINTTYPE_NONE
    Definition: type_var.h:90
    @ SCIP_IMPLINTTYPE_WEAK
    Definition: type_var.h:91
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_FIXED
    Definition: type_var.h:54
    @ SCIP_VARSTATUS_COLUMN
    Definition: type_var.h:53
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141