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-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file 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( BMSreallocMemoryArray(&benders->submastervars[probnumber], newsize) ); /*lint !e866*/
    1485
    1486 benders->submastervarssize[probnumber] = newsize;
    1487 }
    1488
    1489 benders->submastervars[probnumber][benders->nsubmastervars[probnumber]] = var;
    1490 benders->nsubmastervars[probnumber]++;
    1491
    1492 /* capturing the variable, so that it is not released before */
    1493
    1494 /* getting the variable type and updating the statistics */
    1496 benders->nsubmasterbinvars[probnumber]++;
    1497 else if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
    1498 benders->nsubmasterintvars[probnumber]++;
    1499
    1500 return SCIP_OKAY;
    1501}
    1503static
    1505 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1506 SCIP_SET* set, /**< global SCIP settings */
    1507 int probnumber /**< the subproblem number */
    1508 )
    1509{
    1510 SCIP* subproblem;
    1511 SCIP_VAR** vars;
    1512 SCIP_VAR* mastervar;
    1513 int nvars;
    1514 int i;
    1515
    1516 assert(benders != NULL);
    1517 assert(set != NULL);
    1518 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1519
    1520 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1521
    1522 /* getting the variables of the subproblem to store the master problem variables */
    1523 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
    1524
    1525 for( i = 0; i < nvars; i++ )
    1526 {
    1527 /* retrieving the master problem variable */
    1528 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
    1529
    1530 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
    1531 if( mastervar != NULL )
    1532 {
    1533 SCIP_CALL( storeSubproblemMasterVar(benders, set, mastervar, probnumber) );
    1534 }
    1535 }
    1536
    1537 return SCIP_OKAY;
    1538}
    1539
    1540/* adds a slack variable to the given constraint */
    1541static
    1543 SCIP* scip, /**< the SCIP data structure */
    1544 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1545 SCIP_CONS* cons, /**< constraint to which the slack variable(s) is added to */
    1546 SCIP_CONSHDLR** linearconshdlrs, /**< an array storing the linear constraint handlers */
    1547 SCIP_CONSHDLR* nlconshdlr, /**< pointer to the nonlinear constraint handler */
    1548 int nlinearconshdlrs /**< the number of linear constraint handlers */
    1549 )
    1550{
    1551 SCIP_CONSHDLR* conshdlr;
    1552 SCIP_VAR* var;
    1553 SCIP_Real rhs;
    1554 SCIP_Real lhs;
    1555 SCIP_Real objcoef;
    1556 int i;
    1557 SCIP_Bool linearcons;
    1558 SCIP_Bool success;
    1559 char name[SCIP_MAXSTRLEN];
    1560
    1561 conshdlr = SCIPconsGetHdlr(cons);
    1562
    1563 /* assume that the constraint is not linear, then we check whether it is linear */
    1564 linearcons = FALSE;
    1565
    1566 /* checking whether the constraint is a linear constraint. If so, we add a coefficient to the constraint */
    1567 for( i = 0; i < nlinearconshdlrs; ++i )
    1568 {
    1569 if( conshdlr == linearconshdlrs[i] )
    1570 {
    1571 linearcons = TRUE;
    1572 break;
    1573 }
    1574 }
    1575
    1576 if( !linearcons && conshdlr != nlconshdlr )
    1577 {
    1578 SCIPwarningMessage(scip, "The subproblem includes constraint <%s>. "
    1579 "This is not supported and the slack variable will not be added to the constraint. Feasibility cuts may be invalid.\n",
    1580 SCIPconshdlrGetName(conshdlr));
    1581 }
    1582
    1583 if( linearcons )
    1584 {
    1585 rhs = SCIPconsGetRhs(scip, cons, &success);
    1586 assert(success);
    1587 lhs = SCIPconsGetLhs(scip, cons, &success);
    1588 assert(success);
    1589 }
    1590 else
    1591 {
    1592 rhs = SCIPgetRhsNonlinear(cons);
    1593 lhs = SCIPgetLhsNonlinear(cons);
    1594 }
    1595
    1596 /* getting the objective coefficient for the slack variables */
    1597 objcoef = benders->slackvarcoef;
    1598
    1599 /* if the right hand side is finite, then we need to add a slack variable with a negative coefficient */
    1600 if( !SCIPisInfinity(scip, rhs) )
    1601 {
    1602 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_neg", SLACKVAR_NAME, SCIPconsGetName(cons) );
    1603
    1605
    1606 /* adding the slack variable to the subproblem */
    1607 SCIP_CALL( SCIPaddVar(scip, var) );
    1608
    1609 /* adds the slack variable to the constraint */
    1610 if( linearcons )
    1611 {
    1612 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, -1.0) );
    1613 }
    1614 else
    1615 {
    1616 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, var, -1.0) );
    1617 }
    1618
    1619 /* releasing the variable */
    1620 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    1621 }
    1622
    1623 /* if the left hand side if finite, then we need to add a slack variable with a positive coefficient */
    1624 if( !SCIPisInfinity(scip, -lhs) )
    1625 {
    1626 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_pos", SLACKVAR_NAME, SCIPconsGetName(cons) );
    1627
    1629
    1630 /* adding the slack variable to the subproblem */
    1631 SCIP_CALL( SCIPaddVar(scip, var) );
    1632
    1633 /* adds the slack variable to the constraint */
    1634 if( linearcons )
    1635 {
    1636 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, 1.0) );
    1637 }
    1638 else
    1639 {
    1640 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, var, 1.0) );
    1641 }
    1642
    1643 /* releasing the variable */
    1644 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    1645 }
    1646
    1647 return SCIP_OKAY;
    1648}
    1649
    1650/** adds the slack variables to each of the constraints for the generation of feasibility cuts for the given non-linear
    1651 * subproblem
    1653static
    1655 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1656 SCIP_SET* set, /**< global SCIP settings */
    1657 int probnumber /**< the subproblem number */
    1658 )
    1659{
    1660 SCIP* subproblem;
    1661 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
    1662 SCIP_CONSHDLR* nlconshdlr;
    1663 SCIP_CONS* cons;
    1664 int i;
    1665
    1666 assert(benders != NULL);
    1667 assert(set != NULL);
    1668 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1669
    1670 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1671
    1672 /* get pointers to linear constraints handlers, so can avoid string comparisons */
    1673 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
    1674 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
    1675 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
    1676 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
    1677 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
    1678
    1679 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
    1680
    1681 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
    1682 {
    1683 cons = SCIPgetOrigConss(subproblem)[i];
    1684
    1685 /* adding the slack variables to the constraint */
    1686 SCIP_CALL( addSlackVars(subproblem, benders, cons, linearconshdlrs, nlconshdlr, NLINEARCONSHDLRS) );
    1687 }
    1688
    1689 return SCIP_OKAY;
    1690}
    1691
    1692/** initialises a MIP subproblem by putting the problem into SCIP_STAGE_SOLVING. This is achieved by calling SCIPsolve
    1693 * and then interrupting the solve in a node focus event handler.
    1694 * The LP subproblem is also initialised using this method; however, a different event handler is added. This event
    1695 * handler will put the LP subproblem into probing mode.
    1696 * The MIP solving function is called to initialise the subproblem because this function calls SCIPsolve with the
    1697 * appropriate parameter settings for Benders' decomposition.
    1699static
    1701 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1702 SCIP_SET* set, /**< global SCIP settings */
    1703 int probnumber, /**< the subproblem number */
    1704 SCIP_Bool* infeasible, /**< pointer to store whether the lp is detected as infeasible */
    1705 SCIP_Bool* success /**< was the initialisation process successful */
    1706 )
    1707{
    1708 SCIP* subproblem;
    1709 SCIP_STATUS solvestatus;
    1710
    1711 assert(benders != NULL);
    1712 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1713 assert(success != NULL);
    1714
    1715 (*success) = FALSE;
    1716 (*infeasible) = FALSE;
    1717
    1718 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1719 assert(subproblem != NULL);
    1720
    1721 /* Getting the problem into the right SCIP stage for solving */
    1722 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
    1723
    1724 /* Constructing the LP that can be solved in later iterations */
    1725 if( solvestatus != SCIP_STATUS_BESTSOLLIMIT && solvestatus != SCIP_STATUS_TIMELIMIT
    1726 && solvestatus != SCIP_STATUS_MEMLIMIT )
    1727 {
    1728 assert(SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING);
    1729
    1730 SCIP_CALL( SCIPconstructLP(subproblem, infeasible) );
    1731
    1732 (*success) = !(*infeasible);
    1733 }
    1734
    1735 return SCIP_OKAY;
    1736}
    1737
    1738
    1739/** initialises an LP subproblem by putting the problem into probing mode. The probing mode is invoked in a node focus
    1740 * event handler. This event handler is added just prior to calling the initialise subproblem function.
    1742static
    1744 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1745 SCIP_SET* set, /**< global SCIP settings */
    1746 int probnumber, /**< the subproblem number */
    1747 SCIP_Bool* infeasible /**< pointer to store whether the lp is detected as infeasible */
    1748 )
    1749{
    1750 SCIP* subproblem;
    1751 SCIP_EVENTHDLR* eventhdlr;
    1752 SCIP_EVENTHDLRDATA* eventhdlrdata;
    1753 SCIP_Bool success;
    1754
    1755 assert(benders != NULL);
    1756 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    1757 assert(infeasible != NULL);
    1758
    1759 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1760 assert(subproblem != NULL);
    1761
    1762 /* include event handler into SCIP */
    1763 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata) );
    1764
    1765 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata) );
    1766
    1768 eventExecBendersNodefocus, eventhdlrdata) );
    1769 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersNodefocus) );
    1770 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersNodefocus) );
    1771 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersNodefocus) );
    1772 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersNodefocus) );
    1773 assert(eventhdlr != NULL);
    1774
    1775 /* calling an initial solve to put the problem into probing mode */
    1776 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
    1777
    1778 return SCIP_OKAY; /*lint !e438*/
    1779}
    1780
    1781/** checks whether the convex relaxation of the subproblem is sufficient to solve the original problem to optimality
    1782 *
    1783 * We check whether we can conclude that the CIP is actually an LP or a convex NLP.
    1784 * To do this, we check that all variables are of continuous type and that every constraint is either handled by known
    1785 * linear constraint handler (knapsack, linear, logicor, setppc, varbound) or the nonlinear constraint handler.
    1786 * In the latter case, we also check whether the nonlinear constraint is convex.
    1787 * Further, nonlinear constraints are only considered if an NLP solver interface is available, i.e., and NLP could
    1788 * be solved.
    1789 * If constraints are present that cannot be identified as linear or convex nonlinear, then we assume that the
    1790 * problem is not convex, thus solving its LP or NLP relaxation will not be sufficient.
    1792static
    1794 SCIP_BENDERS* benders, /**< Benders' decomposition */
    1795 SCIP_SET* set, /**< global SCIP settings */
    1796 int probnumber /**< the subproblem number, or -1 for the master problem */
    1797 )
    1798{
    1799 SCIP* subproblem;
    1800 SCIP_CONSHDLR* conshdlr;
    1801 SCIP_CONS* cons;
    1802 SCIP_HASHMAP* assumevarfixed;
    1803 SCIP_VAR** vars;
    1804 int nvars;
    1805 int nbinvars;
    1806 int nintvars;
    1807 int nimplintvars;
    1808 int i;
    1809 int j;
    1810 SCIP_Bool convexcons;
    1811 SCIP_Bool discretevar;
    1812 SCIP_Bool isnonlinear;
    1813 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
    1814 SCIP_CONSHDLR* nlconshdlr = NULL;
    1815
    1816 assert(benders != NULL);
    1817 assert(set != NULL);
    1818 assert(probnumber >= -1 && probnumber < SCIPbendersGetNSubproblems(benders));
    1819
    1820 assumevarfixed = NULL;
    1821 if( probnumber >= 0 )
    1822 subproblem = SCIPbendersSubproblem(benders, probnumber);
    1823 else
    1824 subproblem = set->scip;
    1825
    1826 assert(subproblem != NULL);
    1827
    1828 convexcons = FALSE;
    1829 discretevar = FALSE;
    1830 isnonlinear = FALSE;
    1831
    1832 /* getting the number of integer and binary variables to determine the problem type */
    1833 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, &nbinvars, &nintvars, &nimplintvars, NULL) );
    1834
    1835 /* if there are any binary, integer or implicit integer variables, then the subproblems is marked as non-convex */
    1836 if( nbinvars != 0 || nintvars != 0 || nimplintvars != 0 )
    1837 {
    1838 discretevar = TRUE;
    1839 }
    1840
    1841 /* get pointers to linear constraints handlers, so can avoid string comparisons */
    1842 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
    1843 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
    1844 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
    1845 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
    1846 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
    1847
    1848 /* Get pointer to the nonlinear constraint handler if we also have an NLP solver to solve NLPs.
    1849 * If there is no NLP solver, but there are (convex) nonlinear constraints, then the LP relaxation of subproblems
    1850 * will (currently) not be sufficient to solve subproblems to optimality. Thus, we also take the presence of convex
    1851 * nonlinear constraints as signal for having to solve the CIP eventually, thus, by abuse of notation,
    1852 * return not-convex here. In summary, we do not need to have a special look onto non-linear constraints
    1853 * if no NLP solver is present, and can treat them as any other constraint that is not of linear type.
    1854 */
    1855 if( SCIPgetNNlpis(subproblem) > 0 )
    1856 {
    1857 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
    1858 }
    1859
    1860 /* if the nonlinear constraint handler exists, then we create a hashmap of variables that can be assumed to be fixed.
    1861 * These variables correspond to the copies of the master variables in the subproblem
    1862 */
    1863 if( probnumber >= 0 && nlconshdlr != NULL )
    1864 {
    1865 SCIP_VAR* mappedvar;
    1866
    1867 SCIP_CALL( SCIPhashmapCreate(&assumevarfixed, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
    1868
    1869 /* finding the subproblem variables that correspond to master variables */
    1870 for( i = 0; i < nvars; i++ )
    1871 {
    1872 /* getting the corresponding master problem variable for the given variable */
    1873 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mappedvar, -1) );
    1874
    1875 /* if the mapped variable is not NULL, then it must be stored as a possible fixed variable */
    1876 if( mappedvar != NULL )
    1877 {
    1878 SCIP_CALL( SCIPhashmapInsert(assumevarfixed, vars[i], vars[i]) );
    1879 }
    1880 }
    1881 }
    1882
    1883 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
    1884 {
    1885 cons = SCIPgetOrigConss(subproblem)[i];
    1886 conshdlr = SCIPconsGetHdlr(cons);
    1887
    1888 for( j = 0; j < NLINEARCONSHDLRS; ++j )
    1889 if( conshdlr == linearconshdlrs[j] )
    1890 break;
    1891
    1892 /* if linear constraint, then we are good */
    1893 if( j < NLINEARCONSHDLRS )
    1894 {
    1895#ifdef SCIP_MOREDEBUG
    1896 SCIPdebugMsg(subproblem, "subproblem <%s>: constraint <%s> is linear\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1897#endif
    1898 continue;
    1899 }
    1900
    1901 /* if cons_nonlinear (and nlconshdlr != NULL), then check whether convex */
    1902 if( conshdlr == nlconshdlr )
    1903 {
    1904 SCIP_Bool isconvex;
    1905 SCIP_EXPRCURV curv;
    1906 SCIP_Bool havelhs;
    1907 SCIP_Bool haverhs;
    1908
    1909 isnonlinear = TRUE;
    1910
    1911 havelhs = !SCIPisInfinity(subproblem, -SCIPgetLhsNonlinear(cons));
    1912 haverhs = !SCIPisInfinity(subproblem, SCIPgetRhsNonlinear(cons));
    1913 if( havelhs && haverhs )
    1914 {
    1915 isconvex = FALSE;
    1916 }
    1917 else
    1918 {
    1919 /* look at curvature stored in cons, though at this stage this will be unknown a.a. */
    1920 curv = SCIPgetCurvatureNonlinear(cons);
    1921 isconvex = ((!havelhs || (curv & SCIP_EXPRCURV_CONCAVE) == SCIP_EXPRCURV_CONCAVE)) &&
    1922 ((!haverhs || (curv & SCIP_EXPRCURV_CONVEX) == SCIP_EXPRCURV_CONVEX));
    1923
    1924 if( !isconvex )
    1925 {
    1926 /* if not found convex, compute curvature via nlhdlr_convex and decide again */
    1927
    1928 /* make sure activities are up to date. SCIPhasExprCurvature currently assumes that this is already the case */
    1930
    1931 SCIP_CALL( SCIPhasExprCurvature(subproblem, SCIPgetExprNonlinear(cons), havelhs ? SCIP_EXPRCURV_CONCAVE : SCIP_EXPRCURV_CONVEX, &isconvex, assumevarfixed) );
    1932 }
    1933 }
    1934
    1935 if( isconvex )
    1936 {
    1937#ifdef SCIP_MOREDEBUG
    1938 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> is convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1939#endif
    1940 continue;
    1941 }
    1942 else
    1943 {
    1944#ifdef SCIP_MOREDEBUG
    1945 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> not convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1946#endif
    1947 goto TERMINATE;
    1948 }
    1949 }
    1950
    1951#ifdef SCIP_MOREDEBUG
    1952 SCIPdebugMsg(subproblem, "subproblem <%s>: potentially nonconvex constraint <%s>\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
    1953#endif
    1954 goto TERMINATE;
    1955 }
    1956
    1957 /* if we made it until here, then all constraints are known and convex */
    1958 convexcons = TRUE;
    1959
    1960TERMINATE:
    1961 /* setting the flag for the convexity of the subproblem. If convexity doesn't need to be checked, then it is assumed
    1962 * that the subproblems are convex. However, if there are discrete variables, then the problem must be set as
    1963 * non-convex. The discrete master variables will be changed to continuous, but this will happen at the first call to
    1964 * SCIPbendersSetupSubproblem
    1965 */
    1966 if( probnumber >= 0 )
    1967 {
    1968 convexcons = convexcons || !benders->checkconsconvexity;
    1969
    1970 if( convexcons && !discretevar )
    1972 else if( convexcons && discretevar )
    1974 else if( !convexcons && !discretevar )
    1976 else if( !convexcons && discretevar )
    1978 else
    1979 SCIPABORT();
    1980
    1981 /* setting the non-linear subproblem flag */
    1982 SCIPbendersSetSubproblemIsNonlinear(benders, probnumber, isnonlinear);
    1983
    1984 SCIPsetDebugMsg(set, "subproblem <%s> has been found to be of type %d\n", SCIPgetProbName(subproblem),
    1985 SCIPbendersGetSubproblemType(benders, probnumber));
    1986 }
    1987 else
    1988 {
    1989 SCIPbendersSetMasterIsNonlinear(benders, isnonlinear);
    1990 }
    1991
    1992 /* releasing the fixed variable hashmap */
    1993 if( assumevarfixed != NULL )
    1994 SCIPhashmapFree(&assumevarfixed);
    1995
    1996 return SCIP_OKAY;
    1997}
    1998
    1999/** creates the subproblems and registers it with the Benders' decomposition struct */
    2000static
    2002 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2003 SCIP_SET* set /**< global SCIP settings */
    2004 )
    2005{
    2006 SCIP* subproblem;
    2007 SCIP_EVENTHDLR* eventhdlr;
    2008 SCIP_VAR* mastervar;
    2009 SCIP_VAR** vars;
    2010 int nvars;
    2011 int nsubproblems;
    2012 int i;
    2013 int j;
    2014
    2015 assert(benders != NULL);
    2016 assert(set != NULL);
    2017
    2018 /* if the subproblems have already been created, then they will not be created again. This is the case if the
    2019 * transformed problem has been freed and then retransformed. The subproblems should only be created when the problem
    2020 * is first transformed. */
    2021 if( benders->subprobscreated )
    2022 return SCIP_OKAY;
    2023
    2024 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2025
    2026 /* creating all subproblems */
    2027 for( i = 0; i < nsubproblems; i++ )
    2028 {
    2029 /* calling the create subproblem call back method */
    2030 SCIP_CALL( benders->benderscreatesub(set->scip, benders, i) );
    2031
    2032 subproblem = SCIPbendersSubproblem(benders, i);
    2033
    2034 /* the subproblem SCIP instance could be set to NULL. This is because user defined subproblem solving methods
    2035 * could be used that don't solve a SCIP instance. Thus, the following setup of the subproblem SCIP instance is
    2036 * not required.
    2037 *
    2038 * NOTE: since the subproblems are supplied as NULL pointers, the internal convexity check can not be performed.
    2039 * The user needs to explicitly specify the subproblem type.
    2040 */
    2041 if( subproblem != NULL )
    2042 {
    2043 /* stores the master problem variables that are in the subproblem. This is helpful for all instances where the
    2044 * master problem variable needs to extracted from the subproblem
    2045 */
    2046 SCIP_CALL( storeSubproblemMasterVars(benders, set, i) );
    2047
    2048 /* setting global limits for the subproblems. This overwrites the limits set by the user */
    2049 SCIP_CALL( SCIPsetIntParam(subproblem, "limits/maxorigsol", 0) );
    2050
    2051 /* getting the number of integer and binary variables to determine the problem type */
    2052 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
    2053
    2054 /* The objective function coefficients of the master problem are set to zero. This is necessary for the Benders'
    2055 * decomposition algorithm, since the cut methods and the objective function check assumes that the objective
    2056 * coefficients of the master problem variables are zero.
    2057 *
    2058 * This only occurs if the Benders' decomposition is not a copy. It is assumed that the correct objective
    2059 * coefficients are given during the first subproblem creation.
    2060 *
    2061 * If the subproblems were copied, then the master variables will be checked to ensure that they have a zero
    2062 * objective value.
    2063 */
    2064 if( !benders->iscopy || benders->threadsafe )
    2065 {
    2066 SCIP_Bool objchanged = FALSE;
    2067
    2068 assert(SCIPgetStage(subproblem) == SCIP_STAGE_PROBLEM);
    2069 for( j = 0; j < nvars; j++ )
    2070 {
    2071 /* retrieving the master problem variable */
    2072 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[j], &mastervar, -1) );
    2073
    2074 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
    2075 if( mastervar != NULL && SCIPvarGetObj(vars[j]) != 0.0 )
    2076 {
    2077 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Changing the objective "
    2078 "coefficient of copy of master problem variable <%s> in subproblem %d to zero.\n",
    2079 SCIPvarGetName(mastervar), i);
    2080 /* changing the subproblem variable objective coefficient to zero */
    2081 SCIP_CALL( SCIPchgVarObj(subproblem, vars[j], 0.0) );
    2082
    2083 objchanged = TRUE;
    2084 }
    2085 }
    2086
    2087 if( objchanged )
    2088 {
    2089 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Objective coefficients of "
    2090 "copy of master problem variables in a subproblem have been changed to zero.\n");
    2091 }
    2092 }
    2093
    2094 /* changing all of the master problem variable to continuous. */
    2096
    2097 /* checking the convexity of the subproblem. The convexity of the subproblem indicates whether the convex
    2098 * relaxation is a valid relaxation for the problem
    2099 */
    2100 SCIP_CALL( checkSubproblemConvexity(benders, set, i) );
    2101
    2102 /* if the problem is convex and has nonlinear constraints, then slack variables must be added to each of the
    2103 * constraints
    2104 */
    2105 if( benders->execfeasphase ||
    2107 && SCIPbendersSubproblemIsNonlinear(benders, i)) )
    2108 {
    2109 /* the slack variables are only added to the subproblem once. If the initialisation methods are called from a
    2110 * copy, then the slack variables are not re-added. Alternatively, if the copy must be threadsafe, then the
    2111 * subproblems are created from scratch again, so the slack variables need to be added.
    2112 */
    2113 if( !benders->iscopy || benders->threadsafe )
    2114 {
    2115 SCIP_CALL( addSlackVarsToConstraints(benders, set, i) );
    2116 }
    2117
    2118 /* setting the flag to indicate that slack variables have been added to the subproblem constraints. This is only
    2119 * set if the slack variables have been added at the request of the user.
    2120 */
    2121 if( benders->execfeasphase )
    2122 benders->feasibilityphase = TRUE;
    2123 }
    2124
    2125 /* after checking the subproblem for convexity, if the subproblem has convex constraints and continuous variables,
    2126 * then the problem is entered into probing mode. Otherwise, it is initialised as a CIP
    2127 */
    2129 {
    2130 /* if the user has not implemented a solve subproblem callback, then the subproblem solves are performed
    2131 * internally. To be more efficient the subproblem is put into probing mode. */
    2132 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
    2133 && SCIPgetStage(subproblem) <= SCIP_STAGE_PROBLEM )
    2134 {
    2135 SCIP_Bool infeasible;
    2136 SCIP_CALL( initialiseLPSubproblem(benders, set, i, &infeasible) );
    2137
    2138 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
    2139 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
    2140 * during the solving process.
    2141 */
    2142 if( infeasible )
    2144 }
    2145 }
    2146 else
    2147 {
    2148 SCIP_EVENTHDLRDATA* eventhdlrdata_mipnodefocus;
    2149 SCIP_EVENTHDLRDATA* eventhdlrdata_upperbound;
    2150
    2151 /* because the subproblems could be reused in the copy, the event handler is not created again. If the
    2152 * threadsafe is TRUE, then it is assumed that the subproblems are not reused.
    2153 * NOTE: This currently works with the benders_default implementation. It may not be very general. */
    2154 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
    2155 && (!benders->iscopy || benders->threadsafe) )
    2156 {
    2157 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_mipnodefocus) );
    2158 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_upperbound) );
    2159
    2160 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_mipnodefocus) );
    2161 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_upperbound) );
    2162
    2163 /* include the first LP solved event handler into the subproblem */
    2165 MIPNODEFOCUS_EVENTHDLR_DESC, eventExecBendersMipnodefocus, eventhdlrdata_mipnodefocus) );
    2166 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersMipnodefocus) );
    2167 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersMipnodefocus) );
    2168 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersMipnodefocus) );
    2169 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersMipnodefocus) );
    2170 assert(eventhdlr != NULL);
    2171
    2172 /* include the upper bound interrupt event handler into the subproblem */
    2174 UPPERBOUND_EVENTHDLR_DESC, eventExecBendersUpperbound, eventhdlrdata_upperbound) );
    2175 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersUpperbound) );
    2176 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersUpperbound) );
    2177 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersUpperbound) );
    2178 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersUpperbound) );
    2179 assert(eventhdlr != NULL);
    2180 }
    2181 }
    2182 }
    2183 else
    2184 {
    2185 /* a user must specify the subproblem type if they are not supplying a SCIP instance. */
    2187 {
    2188 SCIPerrorMessage("If the subproblem is set to NULL, then the subproblem type must be specified.\n");
    2189 SCIPerrorMessage("In the subproblem creation callback, call SCIPbendersSetSubproblemType with the appropriate problem type.\n");
    2190
    2191 return SCIP_ERROR;
    2192 }
    2193 }
    2194 }
    2195
    2196 /* checking the convexity of the master problem. This information is useful for the cut generation methods, such as
    2197 * non-good and integer cuts
    2198 */
    2199 SCIP_CALL( checkSubproblemConvexity(benders, set, -1) );
    2200
    2201 benders->subprobscreated = TRUE;
    2202
    2203 return SCIP_OKAY;
    2204}
    2205
    2207/** initializes Benders' decomposition */
    2209 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2210 SCIP_SET* set /**< global SCIP settings */
    2211 )
    2212{
    2213 int i;
    2214
    2215 assert(benders != NULL);
    2216 assert(set != NULL);
    2217
    2218 if( benders->initialized )
    2219 {
    2220 SCIPerrorMessage("Benders' decomposition <%s> already initialized\n", benders->name);
    2221 return SCIP_INVALIDCALL;
    2222 }
    2223
    2224 if( set->misc_resetstat )
    2225 {
    2226 SCIPclockReset(benders->setuptime);
    2227 SCIPclockReset(benders->bendersclock);
    2228
    2229 benders->ncalls = 0;
    2230 benders->ncutsfound = 0;
    2231 benders->ntransferred = 0;
    2232 }
    2233
    2234 /* start timing */
    2235 SCIPclockStart(benders->setuptime, set);
    2236
    2237 if( benders->bendersinit != NULL )
    2238 {
    2239 SCIP_CALL( benders->bendersinit(set->scip, benders) );
    2240 }
    2241
    2242 benders->initialized = TRUE;
    2243
    2244 /* if the Benders' decomposition is a copy, then the auxiliary variables already exist. So they are registered with
    2245 * the Benders' decomposition struct during the init stage. If the Benders' decomposition is not a copy, then the
    2246 * auxiliary variables need to be created, which occurs in the initpre stage
    2247 */
    2248 if( benders->iscopy )
    2249 {
    2250 /* the copied auxiliary variables must be assigned to the target Benders' decomposition */
    2251 SCIP_CALL( assignAuxiliaryVariables(set->scip, benders) );
    2252 }
    2253
    2254 /* creates the subproblems and sets up the probing mode for LP subproblems. This function calls the benderscreatesub
    2255 * callback. */
    2256 SCIP_CALL( createSubproblems(benders, set) );
    2257
    2258 /* storing the solution tolerance set by the SCIP parameters */
    2259 SCIP_CALL( SCIPsetGetRealParam(set, "benders/solutiontol", &benders->solutiontol) );
    2260
    2261 /* allocating memory for the stored constraints array */
    2262 if( benders->storedcutssize == 0 )
    2263 {
    2266 benders->nstoredcuts = 0;
    2267 }
    2268
    2269 /* initialising the Benders' cuts */
    2271 for( i = 0; i < benders->nbenderscuts; i++ )
    2272 {
    2274 }
    2275
    2276 /* stop timing */
    2277 SCIPclockStop(benders->setuptime, set);
    2278
    2279 return SCIP_OKAY;
    2280}
    2281
    2282
    2283/** Transfers Benders' cuts that were generated while solving a sub-SCIP to the original SCIP instance. This involves
    2284 * creating a constraint/cut that is equivalent to the generated cut in the sub-SCIP. This new constraint/cut is then
    2285 * added to the original SCIP instance.
    2287static
    2289 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
    2290 SCIP_BENDERS* benders, /**< the Benders' decomposition structure of the sub SCIP */
    2291 SCIP_VAR** vars, /**< the variables from the source constraint */
    2292 SCIP_Real* vals, /**< the coefficients of the variables in the source constriant */
    2293 SCIP_Real lhs, /**< the LHS of the source constraint */
    2294 SCIP_Real rhs, /**< the RHS of the source constraint */
    2295 int nvars /**< the number of variables in the source constraint */
    2296 )
    2297{
    2298 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
    2299 SCIP_CONSHDLR* consbenders; /* a helper variable for the Benders' decomposition constraint handler */
    2300 SCIP_CONS* transfercons = NULL; /* the constraint that is generated to transfer the constraints/cuts */
    2301 SCIP_ROW* transfercut = NULL; /* the cut that is generated to transfer the constraints/cuts */
    2302 SCIP_VAR* sourcevar; /* the source variable that will be added to the transferred cut */
    2303 SCIP_VAR* origvar;
    2304 SCIP_Real scalar;
    2305 SCIP_Real constant;
    2306 char cutname[SCIP_MAXSTRLEN]; /* the name of the transferred cut */
    2307 int i;
    2308 SCIP_Bool fail;
    2309
    2310 assert(sourcescip != NULL);
    2311 assert(benders != NULL);
    2312 assert(vars != NULL);
    2313 assert(vals != NULL);
    2314
    2315 /* retrieving the source Benders' decomposition structure */
    2316 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
    2317
    2318 /* retrieving the Benders' decomposition constraint handler */
    2319 consbenders = SCIPfindConshdlr(sourcescip, "benders");
    2320
    2321 /* setting the name of the transferred cut */
    2322 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "transferredcut_%d",
    2323 SCIPbendersGetNTransferredCuts(sourcebenders) );
    2324
    2325 /* TODO: It could be more efficient to pass an updated vars array with the vals array to the
    2326 * SCIPcreateConsBasicLinear/SCIPcreateEmptyRowConshdlr. This should be implemented to improve the performance of the
    2327 * Large Neighbourhood Benders Search.
    2328 */
    2329
    2330 /* creating an empty row/constraint for the transferred cut */
    2331 if( sourcebenders->cutsasconss )
    2332 {
    2333 SCIP_CALL( SCIPcreateConsBasicLinear(sourcescip, &transfercons, cutname, 0, NULL, NULL, lhs, rhs) );
    2334 SCIP_CALL( SCIPsetConsRemovable(sourcescip, transfercons, TRUE) );
    2335 }
    2336 else
    2337 {
    2338 SCIP_CALL( SCIPcreateEmptyRowConshdlr(sourcescip, &transfercut, consbenders, cutname, lhs, rhs, FALSE,
    2339 FALSE, TRUE) );
    2340 }
    2341
    2342 fail = FALSE;
    2343 for( i = 0; i < nvars; i++ )
    2344 {
    2345 /* getting the original variable for the transformed variable */
    2346 origvar = vars[i];
    2347 scalar = 1.0;
    2348 constant = 0.0;
    2349 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
    2350
    2351 /* getting the source var from the hash map */
    2352 sourcevar = (SCIP_VAR*) SCIPhashmapGetImage(benders->mastervarsmap, origvar);
    2353
    2354 /* if the source variable is not found, then the mapping in incomplete. So the constraint can not be
    2355 * transferred. */
    2356 if( sourcevar == NULL )
    2357 {
    2358 fail = TRUE;
    2359 break;
    2360 }
    2361
    2362 if( sourcebenders->cutsasconss )
    2363 {
    2364 assert( transfercons != NULL );
    2365 SCIP_CALL( SCIPaddCoefLinear(sourcescip, transfercons, sourcevar, vals[i]) ); /*lint !e644*/
    2366 }
    2367 else
    2368 {
    2369 assert( transfercut != NULL );
    2370 SCIP_CALL( SCIPaddVarToRow(sourcescip, transfercut, sourcevar, vals[i]) ); /*lint !e644*/
    2371 }
    2372 }
    2373
    2374 /* if all of the source variables were found to generate the cut */
    2375 if( !fail )
    2376 {
    2377 if( sourcebenders->cutsasconss )
    2378 {
    2379 SCIP_CALL( SCIPaddCons(sourcescip, transfercons) );
    2380 }
    2381 else
    2382 {
    2383 SCIP_CALL( SCIPaddPoolCut(sourcescip, transfercut) );
    2384 }
    2385
    2386 sourcebenders->ntransferred++;
    2387 }
    2388
    2389 /* release the row/constraint */
    2390 if( sourcebenders->cutsasconss )
    2391 {
    2392 /* only release if the creation of the constraint failed. */
    2393 SCIP_CALL( SCIPreleaseCons(sourcescip, &transfercons) );
    2394 }
    2395 else
    2396 {
    2397 SCIP_CALL( SCIPreleaseRow(sourcescip, &transfercut) );
    2398 }
    2399
    2400 return SCIP_OKAY;
    2401}
    2402
    2403
    2404/** transfers the cuts generated in a subscip to the source scip */
    2405static
    2407 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
    2408 SCIP* subscip, /**< the sub SCIP where the Benders' cuts were generated */
    2409 SCIP_BENDERS* benders /**< the Benders' decomposition structure of the sub SCIP */
    2410 )
    2411{
    2412 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
    2413 SCIP_VAR** vars; /* the variables of the added constraint/row */
    2414 SCIP_Real* vals; /* the values of the added constraint/row */
    2415 SCIP_Real lhs; /* the LHS of the added constraint/row */
    2416 SCIP_Real rhs; /* the RHS of the added constraint/row */
    2417 int naddedcuts;
    2418 int nvars;
    2419 int i;
    2420
    2421 assert(subscip != NULL);
    2422 assert(benders != NULL);
    2423
    2424 /* retrieving the source Benders' decomposition structure */
    2425 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
    2426
    2427 /* exit if the cuts should not be transferred from the sub SCIP to the source SCIP. */
    2428 if( !sourcebenders->transfercuts || benders->mastervarsmap == NULL )
    2429 return SCIP_OKAY;
    2430
    2431 /* retrieving the number of stored Benders' cuts */
    2432 naddedcuts = SCIPbendersGetNStoredCuts(benders);
    2433
    2434 /* looping over all added cuts to construct the cut for the source scip */
    2435 for( i = 0; i < naddedcuts; i++ )
    2436 {
    2437 /* collecting the variable information from the constraint */
    2438 SCIP_CALL( SCIPbendersGetStoredCutData(benders, i, &vars, &vals, &lhs, &rhs, &nvars) );
    2439
    2440 if( nvars > 0 )
    2441 {
    2442 /* create and add the cut to be transferred from the sub SCIP to the source SCIP */
    2443 SCIP_CALL( createAndAddTransferredCut(sourcescip, benders, vars, vals, lhs, rhs, nvars) );
    2444 }
    2445 }
    2446
    2447 return SCIP_OKAY;
    2448}
    2449
    2451/** calls exit method of Benders' decomposition */
    2453 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2454 SCIP_SET* set /**< global SCIP settings */
    2455 )
    2456{
    2457 int nsubproblems;
    2458 int i;
    2459
    2460 assert(benders != NULL);
    2461 assert(set != NULL);
    2462
    2463 if( !benders->initialized )
    2464 {
    2465 SCIPerrorMessage("Benders' decomposition <%s> not initialized\n", benders->name);
    2466 return SCIP_INVALIDCALL;
    2467 }
    2468
    2469 /* start timing */
    2470 SCIPclockStart(benders->setuptime, set);
    2471
    2472 if( benders->bendersexit != NULL )
    2473 {
    2474 SCIP_CALL( benders->bendersexit(set->scip, benders) );
    2475 }
    2476
    2477 /* if the Benders' decomposition is a copy, then is a variable mapping was provided, then the generated cuts will
    2478 * be transferred to the source scip
    2479 */
    2480 if( benders->iscopy && benders->mastervarsmap != NULL )
    2481 {
    2482 SCIP_CALL( transferBendersCuts(benders->sourcescip, set->scip, benders) );
    2483 }
    2484
    2485 /* releasing the stored constraints */
    2486 for( i = benders->nstoredcuts - 1; i >= 0; i-- )
    2487 {
    2488 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vals, benders->storedcuts[i]->nvars);
    2489 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vars, benders->storedcuts[i]->nvars);
    2490 SCIPfreeBlockMemory(set->scip, &benders->storedcuts[i]); /*lint !e866*/
    2491 }
    2492
    2493 BMSfreeBlockMemoryArray(SCIPblkmem(set->scip), &benders->storedcuts, benders->storedcutssize);
    2494 benders->storedcutssize = 0;
    2495 benders->nstoredcuts = 0;
    2496
    2497 /* releasing all of the auxiliary variables and constraints */
    2498 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2499 for( i = 0; i < nsubproblems; i++ )
    2500 {
    2501 /* it is possible that the master problem is not solved. As such, the auxiliary variables will not be created. So
    2502 * we don't need to release the variables or the constraints
    2503 */
    2504 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX && benders->auxiliaryvarcons[i] != NULL )
    2505 {
    2506 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[i]) );
    2507 }
    2508
    2509 if( benders->auxiliaryvars[i] != NULL )
    2510 {
    2511 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
    2512 * Benders' plugin and others if the auxiliary variables are not shared
    2513 */
    2514 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->auxiliaryvars[i]) > 0 )
    2515 SCIP_CALL( SCIPaddVarLocksType(set->scip, benders->auxiliaryvars[i], SCIP_LOCKTYPE_MODEL, -1, 0) );
    2516
    2517 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->auxiliaryvars[i]) );
    2518 }
    2519 }
    2520
    2521 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM && benders->auxiliaryvarcons[0] != NULL )
    2522 {
    2523 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[0]) );
    2524 }
    2525
    2526 if( benders->masterauxvar != NULL )
    2527 {
    2528 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
    2529 * Benders' plugin and others if the auxiliary variables are not shared
    2530 */
    2531 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->masterauxvar) > 0 )
    2532 {
    2534 }
    2535
    2536 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->masterauxvar) );
    2537 }
    2538
    2540
    2541 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
    2542 if( benders->corepoint != NULL )
    2543 {
    2544 SCIP_CALL( SCIPfreeSol(set->scip, &benders->corepoint) );
    2545 }
    2546
    2547 /* calling the exit method for the Benders' cuts */
    2549 for( i = 0; i < benders->nbenderscuts; i++ )
    2550 {
    2552 }
    2553
    2554 benders->initialized = FALSE;
    2555
    2556 /* stop timing */
    2557 SCIPclockStop(benders->setuptime, set);
    2558
    2559 return SCIP_OKAY;
    2560}
    2561
    2562/** Checks whether a subproblem is independent. */
    2563static
    2565 SCIP* scip, /**< the SCIP data structure */
    2566 SCIP_BENDERS* benders /**< Benders' decomposition */
    2567 )
    2568{
    2569 SCIP_VAR** vars;
    2570 int nvars;
    2571 int nsubproblems;
    2572 int i;
    2573 int j;
    2574
    2575 assert(scip != NULL);
    2576 assert(benders != NULL);
    2577
    2578 /* retrieving the master problem variables */
    2579 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    2580
    2581 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2582
    2583 /* looping over all subproblems to check whether there exists at least one master problem variable */
    2584 for( i = 0; i < nsubproblems; i++ )
    2585 {
    2586 /* if there are user defined solving or freeing functions, then it is not possible to declare the independence of
    2587 * the subproblems.
    2588 */
    2589 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
    2590 && benders->bendersfreesub == NULL )
    2591 {
    2592 SCIP_Bool independent = TRUE;
    2593
    2594 for( j = 0; j < nvars; j++ )
    2595 {
    2596 SCIP_VAR* subprobvar;
    2597
    2598 /* getting the subproblem problem variable corresponding to the master problem variable */
    2599 SCIP_CALL( SCIPgetBendersSubproblemVar(scip, benders, vars[j], &subprobvar, i) );
    2600
    2601 /* if the subporblem variable is not NULL, then the subproblem depends on the master problem */
    2602 if( subprobvar != NULL )
    2603 {
    2604 independent = FALSE;
    2605 break;
    2606 }
    2607 }
    2608
    2609 /* setting the independent flag */
    2610 SCIPbendersSetSubproblemIsIndependent(benders, i, independent);
    2611 }
    2612 }
    2613
    2614 return SCIP_OKAY;
    2615}
    2617/** informs the Benders' decomposition that the presolving process is being started */
    2619 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2620 SCIP_SET* set, /**< global SCIP settings */
    2621 SCIP_STAT* stat /**< dynamic problem statistics */
    2622 )
    2623{
    2624 assert(benders != NULL);
    2625 assert(set != NULL);
    2626 assert(stat != NULL);
    2627
    2628 /* the arrays for the auxiliary variables and constraints are not allocated at the activate stage. This is because
    2629 * SCIPbendersActivate can be called during SCIP_STAGE_PROBLEM. As such, the user may still change the objective type
    2630 * after the Benders' decomposition has been activated. The memory allocation occurs immediately before the variables
    2631 * are created, then freed in SCIPbendersExit.
    2632 */
    2633 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
    2634 {
    2636 }
    2637 else
    2638 {
    2639 assert(benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX);
    2641 }
    2642
    2643 /* if the Benders' decomposition is the original, then the auxiliary variables need to be created. If the Benders'
    2644 * decomposition is a copy, then the auxiliary variables already exist. The assignment of the auxiliary variables
    2645 * occurs in bendersInit
    2646 */
    2647 if( !benders->iscopy )
    2648 {
    2649 /* check the subproblem independence. This check is only performed if the user has not implemented a solve
    2650 * subproblem function.
    2651 */
    2652 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL )
    2653 SCIP_CALL( checkSubproblemIndependence(set->scip, benders) );
    2654
    2655 /* adding the auxiliary variables to the master problem */
    2656 SCIP_CALL( addAuxiliaryVariablesToMaster(set->scip, benders) );
    2657 }
    2658
    2659 /* call presolving initialization method of Benders' decomposition */
    2660 if( benders->bendersinitpre != NULL )
    2661 {
    2662 /* start timing */
    2663 SCIPclockStart(benders->setuptime, set);
    2664
    2665 SCIP_CALL( benders->bendersinitpre(set->scip, benders) );
    2666
    2667 /* stop timing */
    2668 SCIPclockStop(benders->setuptime, set);
    2669 }
    2670
    2671 return SCIP_OKAY;
    2672}
    2673
    2675/** informs the Benders' decomposition that the presolving process has completed */
    2677 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2678 SCIP_SET* set, /**< global SCIP settings */
    2679 SCIP_STAT* stat /**< dynamic problem statistics */
    2680 )
    2681{
    2682 assert(benders != NULL);
    2683 assert(set != NULL);
    2684 assert(stat != NULL);
    2685
    2686 /* call presolving deinitialization method of Benders' decomposition */
    2687 if( benders->bendersexitpre != NULL )
    2688 {
    2689 /* start timing */
    2690 SCIPclockStart(benders->setuptime, set);
    2691
    2692 SCIP_CALL( benders->bendersexitpre(set->scip, benders) );
    2693
    2694 /* stop timing */
    2695 SCIPclockStop(benders->setuptime, set);
    2696 }
    2697
    2698 return SCIP_OKAY;
    2699}
    2701/** informs Benders' decomposition that the branch and bound process is being started */
    2703 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2704 SCIP_SET* set /**< global SCIP settings */
    2705 )
    2706{
    2707 int i;
    2708
    2709 assert(benders != NULL);
    2710 assert(set != NULL);
    2711
    2712 /* call solving process initialization method of Benders' decomposition */
    2713 if( benders->bendersinitsol != NULL )
    2714 {
    2715 /* start timing */
    2716 SCIPclockStart(benders->setuptime, set);
    2717
    2718 SCIP_CALL( benders->bendersinitsol(set->scip, benders) );
    2719
    2720 /* stop timing */
    2721 SCIPclockStop(benders->setuptime, set);
    2722 }
    2723
    2724 /* calling the initsol method for the Benders' cuts */
    2726 for( i = 0; i < benders->nbenderscuts; i++ )
    2727 {
    2729 }
    2730
    2731 return SCIP_OKAY;
    2732}
    2734/** informs Benders' decomposition that the branch and bound process data is being freed */
    2736 SCIP_BENDERS* benders, /**< Benders' decomposition */
    2737 SCIP_SET* set /**< global SCIP settings */
    2738 )
    2739{
    2740 int nsubproblems;
    2741 int i;
    2742
    2743 assert(benders != NULL);
    2744 assert(set != NULL);
    2745
    2746 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2747 /* freeing all subproblems that are independent, this is because they have not bee freed during the subproblem
    2748 * solving loop.
    2749 */
    2750 for( i = 0; i < nsubproblems; i++ )
    2751 {
    2752 if( SCIPbendersSubproblemIsIndependent(benders, i) )
    2753 {
    2754 /* disabling the independence of the subproblem so that it can be freed */
    2756
    2757 /* freeing the independent subproblem */
    2758 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, i) );
    2759 }
    2760 }
    2761
    2762 /* call solving process deinitialization method of Benders' decomposition */
    2763 if( benders->bendersexitsol != NULL )
    2764 {
    2765 /* start timing */
    2766 SCIPclockStart(benders->setuptime, set);
    2767
    2768 SCIP_CALL( benders->bendersexitsol(set->scip, benders) );
    2769
    2770 /* stop timing */
    2771 SCIPclockStop(benders->setuptime, set);
    2772 }
    2773
    2774 /* sorting the Benders' decomposition cuts in order of priority. Only a single cut is generated for each subproblem
    2775 * per solving iteration. This is particularly important in the case of the optimality and feasibility cuts. Since
    2776 * these work on two different solutions to the subproblem, it is not necessary to generate both cuts. So, once the
    2777 * feasibility cut is generated, then no other cuts will be generated.
    2778 */
    2780
    2781 /* calling the exitsol method for the Benders' cuts */
    2782 for( i = 0; i < benders->nbenderscuts; i++ )
    2783 {
    2785 }
    2786
    2787 return SCIP_OKAY;
    2788}
    2790/** activates Benders' decomposition such that it is called in LP solving loop */
    2792 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    2793 SCIP_SET* set, /**< global SCIP settings */
    2794 int nsubproblems /**< the number subproblems used in this decomposition */
    2795 )
    2796{
    2797 SCIP_EVENTHDLR* eventhdlr;
    2798 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2799 int i;
    2800
    2801 assert(benders != NULL);
    2802 assert(set != NULL);
    2803 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
    2804
    2805 if( !benders->active )
    2806 {
    2807 benders->active = TRUE;
    2808 set->nactivebenders++;
    2809 set->benderssorted = FALSE;
    2810
    2811 benders->nsubproblems = nsubproblems;
    2812 benders->nactivesubprobs = nsubproblems;
    2813 benders->prevlowerbound = -SCIPsetInfinity(set);
    2814 benders->strengthenround = FALSE;
    2815
    2816 /* allocating memory for the subproblems arrays */
    2824 SCIP_ALLOC( BMSallocMemoryArray(&benders->solvestat, benders->nsubproblems) );
    2835
    2836 /* creating the priority queue for the subproblem solving status */
    2837 SCIP_CALL( SCIPpqueueCreate(&benders->subprobqueue, benders->nsubproblems, 1.1,
    2838 benders->benderssubcomp == NULL ? benderssubcompdefault : benders->benderssubcomp, NULL) );
    2839
    2840 for( i = 0; i < benders->nsubproblems; i++ )
    2841 {
    2842 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
    2843
    2845
    2846 benders->subproblems[i] = NULL;
    2847 benders->auxiliaryvars[i] = NULL;
    2849 benders->nsubmastervars[i] = 0;
    2850 benders->nsubmasterbinvars[i] = 0;
    2851 benders->nsubmasterintvars[i] = 0;
    2852 benders->subprobobjval[i] = SCIPsetInfinity(set);
    2853 benders->bestsubprobobjval[i] = SCIPsetInfinity(set);
    2854 benders->subproblowerbound[i] = -SCIPsetInfinity(set);
    2856 benders->subprobisconvex[i] = FALSE;
    2857 benders->subprobisnonlinear[i] = FALSE;
    2858 benders->subprobsetup[i] = FALSE;
    2859 benders->indepsubprob[i] = FALSE;
    2860 benders->subprobenabled[i] = TRUE;
    2861 benders->mastervarscont[i] = FALSE;
    2862
    2863 /* initialising the subproblem solving status */
    2864 SCIP_ALLOC( BMSallocMemory(&solvestat) );
    2865 solvestat->idx = i;
    2866 solvestat->ncalls = 0;
    2867 solvestat->avgiter = 0;
    2868 benders->solvestat[i] = solvestat;
    2869
    2870 /* inserting the initial elements into the priority queue */
    2871 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, benders->solvestat[i]) );
    2872 }
    2873
    2875 {
    2876 /* adding an eventhandler for updating the lower bound when the root node is solved. */
    2877 eventhdlrdata = (SCIP_EVENTHDLRDATA*)benders;
    2878
    2879 /* include event handler into SCIP */
    2881 eventExecBendersNodesolved, eventhdlrdata) );
    2882 SCIP_CALL( SCIPsetEventhdlrInitsol(set->scip, eventhdlr, eventInitsolBendersNodesolved) );
    2883 assert(eventhdlr != NULL);
    2884 }
    2885 }
    2886
    2887 return SCIP_OKAY;
    2888}
    2890/** deactivates Benders' decomposition such that it is no longer called in LP solving loop */
    2892 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    2893 SCIP_SET* set /**< global SCIP settings */
    2894 )
    2895{
    2896 int i;
    2897
    2898 assert(benders != NULL);
    2899 assert(set != NULL);
    2900 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
    2901
    2902 if( benders->active )
    2903 {
    2904 SCIP_EVENTHDLR* eventhdlr;
    2905 int nsubproblems;
    2906
    2907 nsubproblems = SCIPbendersGetNSubproblems(benders);
    2908
    2909#ifndef NDEBUG
    2910 /* checking whether the auxiliary variables and subproblems are all NULL */
    2911 for( i = 0; i < nsubproblems; i++ )
    2912 assert(benders->auxiliaryvars[i] == NULL);
    2913#endif
    2914
    2915 /* if the subproblems were created by the Benders' decomposition core, then they need to be freed */
    2916 if( benders->freesubprobs )
    2917 {
    2918 for( i = SCIPbendersGetNSubproblems(benders) - 1; i >= 0; i-- )
    2919 {
    2920 SCIP* subproblem = SCIPbendersSubproblem(benders, i);
    2921 SCIP_CALL( SCIPfree(&subproblem) );
    2922 }
    2923 }
    2924
    2925 benders->active = FALSE;
    2926 set->nactivebenders--;
    2927 set->benderssorted = FALSE;
    2928
    2929 /* freeing the priority queue memory */
    2930 SCIPpqueueFree(&benders->subprobqueue);
    2931
    2932 for( i = nsubproblems - 1; i >= 0; i-- )
    2933 BMSfreeMemory(&benders->solvestat[i]);
    2934
    2935 /* freeing the master variable storage if it exists */
    2936 for( i = nsubproblems - 1; i >= 0; i-- )
    2938
    2939 /* freeing the memory allocated during the activation of the Benders' decomposition */
    2950 BMSfreeMemoryArray(&benders->solvestat);
    2958
    2959 benders->ncalls = 0;
    2960 benders->ncutsfound = 0;
    2961 benders->ntransferred = 0;
    2962
    2963 benders->naddedsubprobs = 0;
    2964 benders->nconvexsubprobs = 0;
    2965 benders->nnonlinearsubprobs = 0;
    2966 benders->subprobscreated = FALSE;
    2967 benders->freesubprobs = FALSE;
    2968 benders->masterisnonlinear = FALSE;
    2969
    2970 benders->nstrengthencuts = 0;
    2971 benders->nstrengthencalls = 0;
    2972 benders->nstrengthenfails = 0;
    2973
    2974 benders->npseudosols = 0;
    2975 benders->feasibilityphase = FALSE;
    2976
    2977 /* dropping the event from the node solved event handler */
    2979 if( eventhdlr != NULL && SCIPsetGetStage(set) >= SCIP_STAGE_INITSOLVE )
    2980 {
    2981 SCIP_CALL( SCIPdropEvent(set->scip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, NULL, -1) );
    2982 }
    2983 }
    2984
    2985 return SCIP_OKAY;
    2986}
    2988/** returns whether the given Benders' decomposition is in use in the current problem */
    2990 SCIP_BENDERS* benders /**< the Benders' decomposition structure */
    2991 )
    2992{
    2993 assert(benders != NULL);
    2994
    2995 return benders->active;
    2996}
    2997
    2998/** updates the lower bound for all auxiliary variables. This is called if the first LP enforced is unbounded. */
    2999static
    3001 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3002 SCIP_SET* set, /**< global SCIP settings */
    3003 SCIP_RESULT* result /**< the result from updating the auxiliary variable lower bound */
    3004 )
    3005{
    3006 int nsubproblems;
    3007 int i;
    3008
    3009 assert(benders != NULL);
    3010 assert(set != NULL);
    3011
    3012 (*result) = SCIP_DIDNOTRUN;
    3013
    3014 nsubproblems = SCIPbendersGetNSubproblems(benders);
    3015
    3016 for( i = 0; i < nsubproblems; i++ )
    3017 {
    3018 SCIP_VAR* auxiliaryvar;
    3019 SCIP_Real lowerbound;
    3020 SCIP_Bool infeasible;
    3021
    3022 infeasible = FALSE;
    3023
    3024 /* computing the lower bound of the subproblem by solving it without any variable fixings */
    3025 SCIP_CALL( SCIPbendersComputeSubproblemLowerbound(benders, set, i, &lowerbound, &infeasible) );
    3026
    3027 /* if the subproblem is infeasible, then the original problem is infeasible */
    3028 if( infeasible )
    3029 {
    3030 (*result) = SCIP_INFEASIBLE;
    3031 break;
    3032 }
    3033
    3034 /* retrieving the auxiliary variable */
    3035 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, i);
    3036
    3037 /* only update the lower bound if it is greater than the current lower bound */
    3038 if( SCIPsetIsGT(set, lowerbound, SCIPvarGetLbGlobal(auxiliaryvar)) )
    3039 {
    3040 SCIPsetDebugMsg(set, "Tightened lower bound of <%s> to %g\n", SCIPvarGetName(auxiliaryvar), lowerbound);
    3041 /* updating the lower bound of the auxiliary variable */
    3042 SCIP_CALL( SCIPchgVarLb(set->scip, auxiliaryvar, lowerbound) );
    3043 (*result) = SCIP_REDUCEDDOM;
    3044 }
    3045
    3046 /* stores the lower bound for the subproblem */
    3047 SCIPbendersUpdateSubproblemLowerbound(benders, i, lowerbound);
    3048 }
    3049
    3050 return SCIP_OKAY;
    3051}
    3052
    3053/** sets the core point used for cut strengthening. If the strenghtenintpoint is set to 'i', then the core point is
    3054 * reinitialised each time the incumbent is updated
    3056static
    3058 SCIP* scip, /**< the SCIP data structure */
    3059 SCIP_BENDERS* benders /**< Benders' decomposition */
    3060 )
    3061{
    3062 SCIP_SOL* bestsol;
    3063
    3064 assert(scip != NULL);
    3065 assert(benders != NULL);
    3066
    3067 /* if the core point is not NULL and the interior point is not reinitialised, then nothing is done */
    3068 if( benders->corepoint != NULL && benders->strengthenintpoint != 'i' )
    3069 return SCIP_OKAY;
    3070
    3071 bestsol = SCIPgetBestSol(scip);
    3072
    3073 /* if the core point should be updated, then this only happens if the incumbent solution has been updated */
    3074 if( benders->strengthenintpoint == 'i' && benders->initcorepoint == bestsol )
    3075 return SCIP_OKAY;
    3076
    3077 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
    3078 if( benders->corepoint != NULL )
    3079 {
    3080 SCIP_CALL( SCIPfreeSol(scip, &benders->corepoint) );
    3081 }
    3082
    3083 switch( benders->strengthenintpoint )
    3084 {
    3085 SCIP_VAR** vars;
    3086 SCIP_Real timelimit;
    3087 int nvars;
    3088 int i;
    3089
    3090 case 'l':
    3092 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3093 break;
    3094 case 'f':
    3095 case 'i':
    3096 SCIP_CALL( SCIPcreateSolCopy(scip, &benders->corepoint, bestsol) );
    3097 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3098 benders->initcorepoint = bestsol;
    3099 break;
    3100 case 'r':
    3101 /* prepare time limit */
    3102 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    3103 if ( ! SCIPisInfinity(scip, timelimit) )
    3104 timelimit -= SCIPgetSolvingTime(scip);
    3105
    3106 /* if there is time remaining, then compute the relative interior point. Otherwise, return the LP solution */
    3107 if ( timelimit > 0.0 )
    3108 {
    3109 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, 0, "Computing relative interior point (time limit: %g, iter limit: %d) ...\n", timelimit, INT_MAX);
    3110 SCIP_CALL( SCIPcomputeLPRelIntPoint(scip, TRUE, FALSE, timelimit, INT_MAX, &benders->corepoint) );
    3111 }
    3112 else
    3113 {
    3115 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3116 }
    3117 break;
    3118 case 'z':
    3119 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
    3120 break;
    3121 case 'o':
    3122 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
    3123
    3124 /* getting the variable data so that the */
    3125 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    3126
    3127 /* setting all variable values to 1.0 */
    3128 for( i = 0; i < nvars; i++ )
    3129 {
    3130 SCIP_CALL( SCIPsetSolVal(scip, benders->corepoint, vars[i], 1.0) );
    3131 }
    3132 break;
    3133 default:
    3135 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
    3136 }
    3137
    3138 return SCIP_OKAY;
    3139}
    3140
    3141/** performs cut strengthening by using an interior solution to generate cuts */
    3142static
    3144 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3145 SCIP_SET* set, /**< global SCIP settings */
    3146 SCIP_SOL* sol, /**< primal CIP solution */
    3147 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3148 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
    3149 SCIP_Bool perturbsol, /**< should the solution be perturbed to escape infeasibility? */
    3150 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
    3151 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
    3152 SCIP_Bool* skipsolve, /**< should the main solve be skipped as a result of this strengthening? */
    3153 SCIP_RESULT* result /**< result of the pricing process */
    3154 )
    3155{
    3156 SCIP_SOL* sepapoint;
    3157 SCIP_VAR** vars;
    3158 int prevcutsfound;
    3159 int nvars;
    3160 int i;
    3161
    3162 assert(benders != NULL);
    3163 assert(set != NULL);
    3164
    3165 (*result) = SCIP_DIDNOTRUN;
    3166 (*skipsolve) = FALSE;
    3167
    3168 /* the cut stabilisation is only performed when enforcing LP solutions. The solution is not NULL if the stabilisation
    3169 * is currently being performed. It is important to avoid recursion
    3170 */
    3171 if( type != SCIP_BENDERSENFOTYPE_LP || sol != NULL )
    3172 return SCIP_OKAY;
    3173
    3174 /* checking if a change to the lower bound has occurred */
    3175 if( SCIPsetIsGT(set, SCIPgetLowerbound(set->scip), benders->prevlowerbound)
    3176 || SCIPgetCurrentNode(set->scip) != benders->prevnode )
    3177 {
    3178 benders->prevnode = SCIPgetCurrentNode(set->scip);
    3179 benders->prevlowerbound = SCIPgetLowerbound(set->scip);
    3180 benders->noimprovecount = 0;
    3181 }
    3182 else
    3183 benders->noimprovecount++;
    3184
    3185 /* if the number of iterations without improvement exceeds 3*noimprovelimit, then the no stabilisation is performed
    3186 */
    3187 if( benders->noimprovecount > 3*benders->noimprovelimit )
    3188 return SCIP_OKAY;
    3189
    3190 /* if there is no incumbent solution, then it is not possible to create the core point and hence the strengthening
    3191 * can not be performed
    3192 */
    3193 if( SCIPgetBestSol(set->scip) == NULL )
    3194 return SCIP_OKAY;
    3195
    3196 /* if no LP iterations have been performed since the last call of the cut strenghtening, then the strengthening is
    3197 * aborted
    3198 */
    3199 if( benders->prevnlpiter == SCIPgetNLPIterations(set->scip) )
    3200 return SCIP_OKAY;
    3201
    3202 benders->prevnlpiter = SCIPgetNLPIterations(set->scip);
    3203
    3204 /* if the separation point solution is NULL, then we create the solution using the current LP relaxation. */
    3205 SCIP_CALL( setAndUpdateCorePoint(set->scip, benders) );
    3206
    3207 /* creating the separation point
    3208 * TODO: This could be a little to memory heavy, it may be better just to create the separation point once and then
    3209 * update it each time.
    3210 */
    3211 SCIP_CALL( SCIPcreateLPSol(set->scip, &sepapoint, NULL) );
    3212 SCIP_CALL( SCIPunlinkSol(set->scip, sepapoint) );
    3213
    3214 SCIP_CALL( SCIPgetVarsData(set->scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    3215 assert(vars != NULL);
    3216
    3217 /* creating a solution that is a convex combination of the LP solution and the separation point */
    3218 for( i = 0; i < nvars; i++ )
    3219 {
    3220 SCIP_VAR* subvar;
    3221 SCIP_Real corepointval;
    3222 SCIP_Real lpsolval;
    3223 SCIP_Real newsolval;
    3224 int j;
    3225
    3226 corepointval = SCIPgetSolVal(set->scip, benders->corepoint, vars[i]);
    3227 lpsolval = SCIPgetSolVal(set->scip, sol, vars[i]);
    3228 newsolval = lpsolval;
    3229
    3230 /* checking whether the master variable is mapped to any subproblem variables */
    3231 subvar = NULL;
    3232 j = 0;
    3233 while( subvar == NULL && j < SCIPgetBendersNSubproblems(set->scip, benders) )
    3234 {
    3235 SCIP_CALL( SCIPgetBendersSubproblemVar(set->scip, benders, vars[i], &subvar, j) );
    3236 j++;
    3237 }
    3238
    3239 /* if the variable is a linking variable and it is not fixed, then a convex combination with the corepoint is
    3240 * computed.
    3241 */
    3242 if( subvar != NULL && SCIPvarGetStatus(vars[i]) != SCIP_VARSTATUS_FIXED )
    3243 {
    3244 /* if the number of iterations without improvement exceeds noimprovelimit, then no convex combination is
    3245 * created
    3246 */
    3247 if( !perturbsol && benders->noimprovecount <= benders->noimprovelimit )
    3248 {
    3249 newsolval = lpsolval*benders->convexmult + corepointval*(1 - benders->convexmult);
    3250
    3251 /* updating the core point */
    3252 SCIP_CALL( SCIPsetSolVal(set->scip, benders->corepoint, vars[i], newsolval) );
    3253 }
    3254
    3255 /* if the number of iterations without improvement is less than 2*noimprovelimit, then perturbation is
    3256 * performed
    3257 * TODO: This should be a random vector!!!!
    3258 */
    3259 if( perturbsol || benders->noimprovecount <= 2*benders->noimprovelimit )
    3260 newsolval += benders->perturbeps;
    3261 }
    3262
    3263 /* updating the separation point */
    3264 SCIP_CALL( SCIPsetSolVal(set->scip, sepapoint, vars[i], newsolval) );
    3265 }
    3266
    3267 /* storing the number of cuts found */
    3268 prevcutsfound = SCIPbendersGetNCutsFound(benders);
    3269
    3270 SCIPsetDebugMsg(set, "solving Benders' decomposition subproblems with stabilised point.\n");
    3271
    3272 /* calling the subproblem solving method to generate cuts from the separation solution */
    3273 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sepapoint, result, infeasible, auxviol, type, checkint) );
    3274
    3275 SCIPsetDebugMsg(set, "solved Benders' decomposition subproblems with stabilised point. noimprovecount %d result %d\n",
    3276 benders->noimprovecount, (*result));
    3277
    3278 /* if constraints were added, then the main Benders' solving loop is skipped. */
    3279 if( !(*infeasible) && ((*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED) )
    3280 (*skipsolve) = TRUE;
    3281
    3282 /* capturing cut strengthening statistics */
    3283 benders->nstrengthencalls++;
    3284 benders->nstrengthencuts += (SCIPbendersGetNCutsFound(benders) - prevcutsfound);
    3285
    3286 /* if no cuts were added, then the strengthening round is marked as failed */
    3287 if( SCIPbendersGetNCutsFound(benders) == prevcutsfound )
    3288 benders->nstrengthenfails++;
    3289
    3290 /* freeing the sepapoint solution */
    3291 SCIP_CALL( SCIPfreeSol(set->scip, &sepapoint) );
    3292
    3293 return SCIP_OKAY;
    3294}
    3295
    3296
    3297/** Returns whether only the convex relaxations will be checked in this solve loop
    3298 * when Benders' is used in the LNS heuristics, only the convex relaxations of the master/subproblems are checked,
    3299 * i.e. no integer cuts are generated. In this case, then Benders' decomposition is performed under the assumption
    3300 * that all subproblems are convex relaxations.
    3301 */
    3303 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3304 SCIP_Bool subscipsoff /**< flag indicating whether plugins using sub-SCIPs are deactivated */
    3305 )
    3306{
    3307 return benders->iscopy && benders->lnscheck && subscipsoff;
    3308}
    3309
    3310/** returns the number of subproblems that will be checked in this iteration */
    3311static
    3313 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3314 SCIP_SET* set, /**< global SCIP settings */
    3315 SCIP_BENDERSENFOTYPE type /**< the type of solution being enforced */
    3316 )
    3317{
    3318 if( benders->ncalls == 0 || type == SCIP_BENDERSENFOTYPE_CHECK
    3320 return SCIPbendersGetNSubproblems(benders);
    3321 else
    3322 return (int) SCIPsetCeil(set, (SCIP_Real) SCIPbendersGetNSubproblems(benders)*benders->subprobfrac);
    3323}
    3324
    3325/** returns whether the solving of the given subproblem needs to be executed */
    3326static
    3328 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3329 int probnumber /**< the subproblem index */
    3330 )
    3331{
    3332 return (!SCIPbendersSubproblemIsIndependent(benders, probnumber)
    3333 && SCIPbendersSubproblemIsEnabled(benders, probnumber));
    3334}
    3335
    3336/** creates an ordered list of subproblem indices to be solved */
    3337static
    3339 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3340 SCIP_SET* set, /**< global SCIP settings */
    3341 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3342 int** solveidx, /**< a list of subproblem indices to the solved in the current iteration */
    3343 int* nsolveidx /**< the number of subproblem indices in the list */
    3344 )
    3345{
    3346 int nsubproblems;
    3347 int numtocheck;
    3348 int subproblemcount;
    3349
    3350 assert(benders != NULL);
    3351 assert(set != NULL);
    3352 assert((*solveidx) != NULL);
    3353 assert(nsolveidx != NULL);
    3354 assert(SCIPpqueueNElems(benders->subprobqueue) <= SCIPbendersGetNSubproblems(benders));
    3355
    3356 nsubproblems = SCIPbendersGetNSubproblems(benders);
    3357
    3358 /* it is possible to only solve a subset of subproblems. This is given by a parameter. */
    3359 numtocheck = numSubproblemsToCheck(benders, set, type);
    3360
    3361 (*nsolveidx) = 0;
    3362
    3363 subproblemcount = 0;
    3364 while( subproblemcount < nsubproblems && subproblemcount < numtocheck )
    3365 {
    3366 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
    3367
    3369 (*solveidx)[(*nsolveidx)] = solvestat->idx;
    3370 (*nsolveidx)++;
    3371
    3372 subproblemcount++;
    3373 }
    3374}
    3375
    3376/** updates the subproblem solving statistics and inserts the indices into the queue */
    3377static
    3379 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3380 int* solveidx, /**< the list of indices of subproblems that were solved */
    3381 int nsolveidx, /**< the number of subproblem indices */
    3382 SCIP_Bool updatestat /**< should the statistics be updated */
    3383 )
    3384{
    3385 int i;
    3386
    3387 assert(benders != NULL);
    3388 assert(solveidx != NULL);
    3389
    3390 for( i = 0; i < nsolveidx; i++ )
    3391 {
    3392 SCIP* subproblem;
    3393 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
    3394
    3395 subproblem = SCIPbendersSubproblem(benders, solveidx[i]);
    3396 solvestat = benders->solvestat[solveidx[i]];
    3397 assert(solvestat->idx == solveidx[i]);
    3398
    3399 /* updating the solving statistics */
    3400 if( updatestat )
    3401 {
    3402 if( !subproblemIsActive(benders, solveidx[i]) || subproblem == NULL )
    3403 solvestat->avgiter = 1;
    3404 else
    3405 solvestat->avgiter = (SCIP_Real)(solvestat->avgiter*solvestat->ncalls + SCIPgetNLPIterations(subproblem))
    3406 /(SCIP_Real)(solvestat->ncalls + 1);
    3407 solvestat->ncalls++;
    3408 }
    3409
    3410 /* inserting the solving statistics into the priority queue */
    3411 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, solvestat) );
    3412 }
    3413
    3414 assert(SCIPpqueueNElems(benders->subprobqueue) == SCIPbendersGetNSubproblems(benders));
    3415
    3416 return SCIP_OKAY;
    3417}
    3418
    3419/** Solves each of the Benders' decomposition subproblems for the given solution. All, or a fraction, of subproblems are
    3420 * solved before the Benders' decomposition cuts are generated.
    3421 * Since a convex relaxation of the subproblem could be solved to generate cuts, a parameter nverified is used to
    3422 * identified the number of subproblems that have been solved in their "original" form. For example, if the subproblem
    3423 * is a MIP, then if the LP is solved to generate cuts, this does not constitute a verification. The verification is
    3424 * only performed when the MIP is solved.
    3426static
    3428 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3429 SCIP_SET* set, /**< global SCIP settings */
    3430 SCIP_SOL* sol, /**< primal CIP solution */
    3431 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3432 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
    3433 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
    3434 int* nverified, /**< the number of subproblems verified in the current loop */
    3435 int* solveidx, /**< the indices of subproblems to be solved in this loop */
    3436 int nsolveidx, /**< the number of subproblems to be solved in this loop */
    3437 SCIP_Bool** subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
    3438 SCIP_BENDERSSUBSTATUS** substatus, /**< array to store the status of the subsystem */
    3439 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
    3440 SCIP_Bool* optimal, /**< is the current solution optimal? */
    3441 SCIP_Bool* stopped /**< was the solving process stopped? */
    3442 )
    3443{
    3444 SCIP_Bool onlyconvexcheck;
    3445 int i;
    3446 int j;
    3447
    3448 SCIP_RETCODE retcode = SCIP_OKAY;
    3449
    3450 assert(benders != NULL);
    3451 assert(set != NULL);
    3452
    3453 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
    3454 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
    3455 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
    3456 * employed.
    3457 */
    3458 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
    3459
    3460 SCIPsetDebugMsg(set, "Performing the subproblem solving process. Number of subproblems to check %d\n", nsolveidx);
    3461
    3462 SCIPsetDebugMsg(set, "Benders' decomposition - solve loop %d\n", solveloop);
    3463
    3464 if( type == SCIP_BENDERSENFOTYPE_CHECK && sol == NULL )
    3465 {
    3466 /* TODO: Check whether this is absolutely necessary. I think that this if statment can be removed. */
    3467 (*infeasible) = TRUE;
    3468 }
    3469 else
    3470 {
    3471 /* solving each of the subproblems for Benders' decomposition */
    3472 /* TODO: ensure that the each of the subproblems solve and update the parameters with the correct return values
    3473 */
    3474 for( j = 0; j < nsolveidx; j++ )
    3475 {
    3476 SCIP_Bool subinfeas = FALSE;
    3477 SCIP_Bool convexsub;
    3478 SCIP_Bool solvesub = TRUE;
    3479 SCIP_Bool solved;
    3480
    3481 i = solveidx[j];
    3483
    3484 /* the subproblem is initially flagged as not solved for this solving loop */
    3485 (*subprobsolved)[i] = FALSE;
    3486
    3487 /* setting the subsystem status to UNKNOWN at the start of each solve loop */
    3488 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
    3489
    3490 /* for the second solving loop, if the problem is an LP, it is not solved again. If the problem is a MIP,
    3491 * then the subproblem objective function value is set to infinity. However, if the subproblem is proven
    3492 * infeasible from the LP, then the IP loop is not performed.
    3493 * If the solve loop is SCIP_BENDERSSOLVELOOP_USERCIP, then nothing is done. It is assumed that the user will
    3494 * correctly update the objective function within the user-defined solving function.
    3495 */
    3496 if( solveloop == SCIP_BENDERSSOLVELOOP_CIP )
    3497 {
    3498 if( convexsub )
    3499 solvesub = FALSE;
    3500 else
    3501 {
    3502 SCIPbendersSetSubproblemObjval(benders, i, SCIPbendersSubproblem(benders, i) != NULL ?
    3504 }
    3505 }
    3506
    3507 /* if the subproblem is independent, then it does not need to be solved. In this case, the nverified flag will
    3508 * increase by one. When the subproblem is not independent, then it needs to be checked.
    3509 */
    3510 if( !subproblemIsActive(benders, i) )
    3511 {
    3512 /* NOTE: There is no need to update the optimal flag. This is because optimal is always TRUE until a
    3513 * non-optimal subproblem is found.
    3514 */
    3515 /* if the auxiliary variable value is infinity, then the subproblem has not been solved yet. Currently the
    3516 * subproblem statue is unknown. */
    3520 {
    3521 SCIPbendersSetSubproblemObjval(benders, i, SCIPbendersSubproblem(benders, i) != NULL ?
    3523
    3524 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
    3525 (*optimal) = FALSE;
    3526
    3527 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, but has not been solved."
    3528 " setting status to UNKNOWN\n", i);
    3529 }
    3530 else
    3531 {
    3533 SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i)) < benders->solutiontol )
    3534 {
    3536 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
    3537 }
    3538 else
    3539 {
    3541 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
    3542 }
    3543
    3544 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, setting status to OPTIMAL\n", i);
    3545 }
    3546
    3547 (*subprobsolved)[i] = TRUE;
    3548
    3549 /* the nverified counter is only increased in the convex solving loop */
    3550 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
    3551 (*nverified)++;
    3552 }
    3553 else if( solvesub )
    3554 {
    3555 retcode = SCIPbendersExecSubproblemSolve(benders, set, sol, i, solveloop, FALSE, &solved, &subinfeas, type);
    3556
    3557 /* the solution for the subproblem is only processed if the return code is SCIP_OKAY */
    3558 if( retcode == SCIP_OKAY )
    3559 {
    3560#ifdef SCIP_DEBUG
    3561 if( type == SCIP_BENDERSENFOTYPE_LP )
    3562 {
    3563 SCIPsetDebugMsg(set, "Enfo LP: Subproblem %d Type %d (%f < %f)\n", i,
    3564 SCIPbendersGetSubproblemType(benders, i), SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i),
    3565 SCIPbendersGetSubproblemObjval(benders, i));
    3566 }
    3567#endif
    3568 (*subprobsolved)[i] = solved;
    3569
    3570 (*infeasible) = (*infeasible) || subinfeas;
    3571 if( subinfeas )
    3572 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_INFEAS;
    3573
    3574 /* if the subproblems are solved to check integer feasibility, then the optimality check must be performed.
    3575 * This will only be performed if checkint is TRUE and the subproblem was solved. The subproblem may not be
    3576 * solved if the user has defined a solving function
    3577 */
    3578 if( checkint && (*subprobsolved)[i] )
    3579 {
    3580 /* if the subproblem is feasible, then it is necessary to update the value of the auxiliary variable to the
    3581 * objective function value of the subproblem.
    3582 */
    3583 if( !subinfeas )
    3584 {
    3585 SCIP_Bool subproboptimal;
    3586
    3587 subproboptimal = SCIPbendersSubproblemIsOptimal(benders, set, sol, i);
    3588
    3589 if( subproboptimal )
    3590 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
    3591 else
    3592 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
    3593
    3594 /* It is only possible to determine the optimality of a solution within a given subproblem in four
    3595 * different cases:
    3596 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is convex.
    3597 * ii) solveloop == SCIP_BENDERSOLVELOOP_CONVEX and only the convex relaxations will be checked.
    3598 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP and the subproblem was solved, since the user has
    3599 * defined a solve function, it is expected that the solving is correctly executed.
    3600 * iv) solveloop == SCIP_BENDERSSOLVELOOP_CIP and the MIP for the subproblem has been solved.
    3601 */
    3602 if( convexsub || onlyconvexcheck
    3603 || solveloop == SCIP_BENDERSSOLVELOOP_CIP
    3604 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
    3605 (*optimal) = (*optimal) && subproboptimal;
    3606
    3607#ifdef SCIP_DEBUG
    3608 if( convexsub || solveloop >= SCIP_BENDERSSOLVELOOP_CIP )
    3609 {
    3610 if( subproboptimal )
    3611 {
    3612 SCIPsetDebugMsg(set, "Subproblem %d is Optimal (%f >= %f)\n", i,
    3614 }
    3615 else
    3616 {
    3617 SCIPsetDebugMsg(set, "Subproblem %d is NOT Optimal (%f < %f)\n", i,
    3619 }
    3620 }
    3621#endif
    3622
    3623 /* the nverified variable is only incremented when the original form of the subproblem has been solved.
    3624 * What is meant by "original" is that the LP relaxation of CIPs are solved to generate valid cuts. So
    3625 * if the subproblem is defined as a CIP, then it is only classified as checked if the CIP is solved.
    3626 * There are three cases where the "original" form is solved are:
    3627 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is an LP
    3628 * - the original form has been solved.
    3629 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP or USERCIP and the CIP for the subproblem has been
    3630 * solved.
    3631 * iii) or, only a convex check is performed.
    3632 */
    3633 if( ((solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX)
    3634 && convexsub)
    3635 || ((solveloop == SCIP_BENDERSSOLVELOOP_CIP || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)
    3636 && !convexsub)
    3637 || onlyconvexcheck )
    3638 (*nverified)++;
    3639 }
    3640 }
    3641 }
    3642 }
    3643
    3644 /* checking whether the limits have been exceeded in the master problem */
    3645 (*stopped) = SCIPisStopped(set->scip);
    3646 }
    3647 }
    3648
    3649 return retcode;
    3650}
    3651
    3652/** Calls the Benders' decompsition cuts for the given solve loop. There are four cases:
    3653 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX - only the LP Benders' cuts are called
    3654 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP - only the CIP Benders' cuts are called
    3655 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX - only the LP Benders' cuts are called
    3656 * iv) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP - only the CIP Benders' cuts are called
    3657 *
    3658 * The priority of the results are: SCIP_CONSADDED (SCIP_SEPARATED), SCIP_DIDNOTFIND, SCIP_FEASIBLE, SCIP_DIDNOTRUN. In
    3659 * this function, there are four levels of results that need to be assessed. These are:
    3660 * i) The result from the individual cut for the subproblem
    3661 * ii) The overall result for the subproblem from all cuts
    3662 * iii) the overall result for the solve loop from all cuts
    3663 * iv) the over all result from all solve loops.
    3664 * In each level, the priority of results must be adhered to.
    3666static
    3668 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3669 SCIP_SET* set, /**< global SCIP settings */
    3670 SCIP_SOL* sol, /**< primal CIP solution */
    3671 SCIP_RESULT* result, /**< result of the pricing process */
    3672 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3673 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
    3674 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
    3675 SCIP_Bool* subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
    3676 SCIP_BENDERSSUBSTATUS* substatus, /**< array to store the status of the subsystem */
    3677 int* solveidx, /**< the indices of subproblems to be solved in this loop */
    3678 int nsolveidx, /**< the number of subproblems to be solved in this loop */
    3679 int** mergecands, /**< the subproblems that are merge candidates */
    3680 int* npriomergecands, /**< the number of priority merge candidates. */
    3681 int* nmergecands, /**< the number of merge candidates. */
    3682 int* nsolveloops /**< the number of solve loops, is updated w.r.t added cuts */
    3683 )
    3684{
    3685 SCIP_BENDERSCUT** benderscuts;
    3686 SCIP_RESULT solveloopresult;
    3687 int nbenderscuts;
    3688 SCIP_Longint addedcuts = 0;
    3689 int i;
    3690 int j;
    3691 int k;
    3692 SCIP_Bool onlyconvexcheck;
    3693
    3694 assert(benders != NULL);
    3695 assert(set != NULL);
    3696
    3697 /* getting the Benders' decomposition cuts */
    3698 benderscuts = SCIPbendersGetBenderscuts(benders);
    3699 nbenderscuts = SCIPbendersGetNBenderscuts(benders);
    3700
    3701 solveloopresult = SCIP_DIDNOTRUN;
    3702
    3703 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
    3704 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
    3705 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
    3706 * employed.
    3707 */
    3708 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
    3709
    3710 /* It is only possible to add cuts to the problem if it has not already been solved */
    3713 && (benders->cutcheck || type != SCIP_BENDERSENFOTYPE_CHECK) )
    3714 {
    3715 /* This is done in two loops. The first is by subproblem and the second is by cut type. */
    3716 for( k = 0; k < nsolveidx; k++ )
    3717 {
    3718 SCIP_RESULT subprobresult;
    3719 SCIP_Bool convexsub;
    3720
    3721 i = solveidx[k];
    3722
    3724
    3725 /* cuts can only be generated if the subproblem is not independent and if it has been solved. Additionally, the
    3726 * status of the subproblem solving must not be INFEASIBLE while in a cut strengthening round.
    3727 * The subproblem solved flag is important for the user-defined subproblem solving methods
    3728 */
    3729 if( subproblemIsActive(benders, i) && subprobsolved[i]
    3730 && !(substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS && benders->strengthenround) )
    3731 {
    3732 subprobresult = SCIP_DIDNOTRUN;
    3733 for( j = 0; j < nbenderscuts; j++ )
    3734 {
    3735 SCIP_RESULT cutresult;
    3736 SCIP_Longint prevaddedcuts;
    3737
    3738 assert(benderscuts[j] != NULL);
    3739
    3740 prevaddedcuts = SCIPbenderscutGetNFound(benderscuts[j]);
    3741 cutresult = SCIP_DIDNOTRUN;
    3742
    3743 /* the result is updated only if a Benders' cut is generated or one was not found. However, if a cut has
    3744 * been found in a previous iteration, then the result is returned as SCIP_CONSADDED or SCIP_SEPARATED.
    3745 * This result is permitted because if a constraint was added, the solution that caused the error in the cut
    3746 * generation will be cutoff from the master problem.
    3747 */
    3748 if( (SCIPbenderscutIsLPCut(benderscuts[j]) && (solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
    3749 || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX))
    3750 || (!SCIPbenderscutIsLPCut(benderscuts[j]) && ((solveloop == SCIP_BENDERSSOLVELOOP_CIP && !convexsub)
    3751 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)) )
    3752 SCIP_CALL( SCIPbenderscutExec(benderscuts[j], set, benders, sol, i, type, &cutresult) );
    3753
    3754 addedcuts += (SCIPbenderscutGetNFound(benderscuts[j]) - prevaddedcuts);
    3755
    3756 /* the result is updated only if a Benders' cut is generated */
    3757 if( cutresult == SCIP_CONSADDED || cutresult == SCIP_SEPARATED )
    3758 {
    3759 subprobresult = cutresult;
    3760
    3761 benders->ncutsfound++;
    3762
    3763 /* at most a single cut is generated for each subproblem */
    3764 break;
    3765 }
    3766 else
    3767 {
    3768 /* checking from lowest priority result */
    3769 if( subprobresult == SCIP_DIDNOTRUN )
    3770 subprobresult = cutresult;
    3771 else if( subprobresult == SCIP_FEASIBLE && cutresult == SCIP_DIDNOTFIND )
    3772 subprobresult = cutresult;
    3773 /* if the subprobresult is SCIP_DIDNOTFIND, then it can't be updated. */
    3774 }
    3775 }
    3776
    3777 /* the highest priority for the results is CONSADDED and SEPARATED. The solveloopresult will always be
    3778 * updated if the subprobresult is either of these.
    3779 */
    3780 if( subprobresult == SCIP_CONSADDED || subprobresult == SCIP_SEPARATED )
    3781 {
    3782 solveloopresult = subprobresult;
    3783 }
    3784 else if( subprobresult == SCIP_FEASIBLE )
    3785 {
    3786 /* updating the solve loop result based upon the priority */
    3787 if( solveloopresult == SCIP_DIDNOTRUN )
    3788 solveloopresult = subprobresult;
    3789 }
    3790 else if( subprobresult == SCIP_DIDNOTFIND )
    3791 {
    3792 /* updating the solve loop result based upon the priority */
    3793 if( solveloopresult == SCIP_DIDNOTRUN || solveloopresult == SCIP_FEASIBLE )
    3794 solveloopresult = subprobresult;
    3795
    3796 /* since a cut was not found, then merging could be useful to avoid this in subsequent iterations. The
    3797 * candidate is labelled as a non-priority merge candidate
    3798 */
    3799 if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
    3800 {
    3801 (*mergecands)[(*nmergecands)] = i;
    3802 (*nmergecands)++;
    3803 }
    3804 }
    3805 else if( subprobresult == SCIP_DIDNOTRUN )
    3806 {
    3807 /* if the subproblem is infeasible and no cut generation methods were run, then the infeasibility will
    3808 * never be resolved. As such, the subproblem will be merged into the master problem. If the subproblem
    3809 * was not infeasible, then it is added as a possible merge candidate
    3810 */
    3811 if( substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS )
    3812 {
    3813 (*mergecands)[(*nmergecands)] = (*mergecands)[(*npriomergecands)];
    3814 (*mergecands)[(*npriomergecands)] = i;
    3815 (*npriomergecands)++;
    3816 (*nmergecands)++;
    3817 }
    3818 else if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
    3819 {
    3820 (*mergecands)[(*nmergecands)] = i;
    3821 (*nmergecands)++;
    3822 }
    3823 }
    3824 }
    3825 }
    3826 }
    3827
    3828 /* updating the overall result based upon the priorities */
    3829 if( solveloopresult == SCIP_CONSADDED || solveloopresult == SCIP_SEPARATED )
    3830 {
    3831 (*result) = solveloopresult;
    3832 }
    3833 else if( solveloopresult == SCIP_FEASIBLE )
    3834 {
    3835 /* updating the solve loop result based upon the priority */
    3836 if( (*result) == SCIP_DIDNOTRUN )
    3837 (*result) = solveloopresult;
    3838 }
    3839 else if( solveloopresult == SCIP_DIDNOTFIND )
    3840 {
    3841 /* updating the solve loop result based upon the priority */
    3842 if( (*result) == SCIP_DIDNOTRUN || (*result) == SCIP_FEASIBLE )
    3843 (*result) = solveloopresult;
    3844 }
    3845
    3846 /* if no cuts were added, then the number of solve loops is increased */
    3847 if( addedcuts == 0 && SCIPbendersGetNConvexSubproblems(benders) < SCIPbendersGetNSubproblems(benders)
    3848 && checkint && !onlyconvexcheck )
    3849 (*nsolveloops) = 2;
    3850
    3851 return SCIP_OKAY;
    3852}
    3853
    3854/** Solves the subproblem using the current master problem solution.
    3855 *
    3856 * The checkint flag indicates whether integer feasibility can be assumed. If it is not assumed, i.e. checkint ==
    3857 * FALSE, then only the convex relaxations of the subproblems are solved. If integer feasibility is assumed, i.e.
    3858 * checkint == TRUE, then the convex relaxations and the full CIP are solved to generate Benders' cuts and check
    3859 * solution feasibility.
    3860 *
    3861 * TODO: consider allowing the possibility to pass solution information back from the subproblems instead of the scip
    3862 * instance. This would allow the use of different solvers for the subproblems, more importantly allowing the use of an
    3863 * LP solver for LP subproblems.
    3864 */
    3866 SCIP_BENDERS* benders, /**< Benders' decomposition */
    3867 SCIP_SET* set, /**< global SCIP settings */
    3868 SCIP_SOL* sol, /**< primal CIP solution */
    3869 SCIP_RESULT* result, /**< result of the pricing process */
    3870 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
    3871 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
    3872 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
    3873 SCIP_Bool checkint /**< should the integer solution be checked by the subproblems */
    3874 )
    3875{
    3876 int nsubproblems;
    3877 int subproblemcount;
    3878 int nsolveloops;
    3879 int nverified;
    3880 int nsolved;
    3881 int* mergecands;
    3882 int npriomergecands;
    3883 int nmergecands;
    3884 int* solveidx;
    3885 int* executedidx;
    3886 int nsolveidx;
    3887 int nexecutedidx;
    3888 int nfree;
    3889 SCIP_Bool* subprobsolved;
    3890 SCIP_BENDERSSUBSTATUS* substatus;
    3891 SCIP_Bool optimal;
    3892 SCIP_Bool allverified;
    3893 SCIP_Bool success;
    3894 SCIP_Bool stopped;
    3895 int i;
    3896 int l;
    3897
    3898 success = TRUE;
    3899 stopped = FALSE;
    3900
    3901 SCIPsetDebugMsg(set, "Starting Benders' decomposition subproblem solving. type %d checkint %u\n", type, checkint);
    3902
    3903#ifdef SCIP_MOREDEBUG
    3904 SCIP_CALL( SCIPprintSol(set->scip, sol, NULL, FALSE) );
    3905#endif
    3906
    3907 /* start timing */
    3908 SCIPclockStart(benders->bendersclock, set);
    3909
    3910 nsubproblems = SCIPbendersGetNSubproblems(benders);
    3911
    3912 (*auxviol) = FALSE;
    3913 (*infeasible) = FALSE;
    3914
    3915 /* It is assumed that the problem is optimal, until a subproblem is found not to be optimal. However, not all
    3916 * subproblems could be checked in each iteration. As such, it is not possible to state that the problem is optimal
    3917 * if not all subproblems are checked. Situations where this may occur is when a subproblem is a MIP and only the LP
    3918 * is solved. Also, in a distributed computation, then it may be advantageous to only solve some subproblems before
    3919 * resolving the master problem. As such, for a problem to be optimal, then (optimal && allverified) == TRUE
    3920 */
    3921 optimal = TRUE;
    3922 nverified = 0;
    3923 nsolved = 0;
    3924
    3925 assert(benders != NULL);
    3926 assert(result != NULL);
    3927 assert(infeasible != NULL);
    3928 assert(auxviol != NULL);
    3929
    3930 /* if the Benders' decomposition is called from a sub-SCIP and the sub-SCIPs have been deactivated, then it is
    3931 * assumed that this is an LNS heuristic. As such, the check is not performed and the solution is assumed to be
    3932 * feasible
    3933 */
    3934 if( benders->iscopy && set->subscipsoff
    3935 && (!benders->lnscheck
    3936 || (benders->lnsmaxdepth > -1 && SCIPgetDepth(benders->sourcescip) >= benders->lnsmaxdepth)
    3937 || (benders->lnsmaxcalls > -1 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcalls)
    3938 || (type != SCIP_BENDERSENFOTYPE_CHECK && SCIPgetDepth(set->scip) == 0 && benders->lnsmaxcallsroot > -1
    3939 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcallsroot)) )
    3940 {
    3941 (*result) = SCIP_DIDNOTRUN;
    3942 return SCIP_OKAY;
    3943 }
    3944
    3945 /* it is not necessary to check all primal solutions by solving the Benders' decomposition subproblems.
    3946 * Only the improving solutions are checked to improve efficiency of the algorithm.
    3947 * If the solution is non-improving, the result FEASIBLE is returned. While this may be incorrect w.r.t to the
    3948 * Benders' subproblems, this solution will never be the optimal solution. A non-improving solution may be used
    3949 * within LNS primal heuristics. If this occurs, the improving solution, if found, will be checked by the solving
    3950 * the Benders' decomposition subproblems.
    3951 * TODO: Add a parameter to control this behaviour.
    3952 */
    3953 if( checkint && SCIPsetIsLE(set, SCIPgetPrimalbound(set->scip)*(int)SCIPgetObjsense(set->scip),
    3954 SCIPgetSolOrigObj(set->scip, sol)*(int)SCIPgetObjsense(set->scip)) )
    3955 {
    3956 (*result) = SCIP_DIDNOTRUN;
    3957 return SCIP_OKAY;
    3958 }
    3959
    3960 /* if the enforcement type is SCIP_BENDERSENFOTYPE_LP and the LP is currently unbounded. This could mean that there
    3961 * is no lower bound on the auxiliary variables. In this case, we try to update the lower bound for the auxiliary
    3962 * variables.
    3963 */
    3965 && benders->updateauxvarbound )
    3966 {
    3967 SCIP_CALL( updateAuxiliaryVarLowerbound(benders, set, result) );
    3968
    3969 /* the auxiliary variable bound will only be updated once. */
    3970 benders->updateauxvarbound = FALSE;
    3971 }
    3972
    3973 /* sets the stored objective function values of the subproblems to infinity */
    3975
    3976 *result = SCIP_DIDNOTRUN;
    3977
    3978 if( benders->benderspresubsolve != NULL && !benders->strengthenround )
    3979 {
    3980 SCIP_Bool skipsolve;
    3981
    3982 skipsolve = FALSE;
    3983 SCIP_CALL( benders->benderspresubsolve(set->scip, benders, sol, type, checkint, infeasible, auxviol, &skipsolve,
    3984 result) );
    3985
    3986 /* evaluate result */
    3987 if( (*result) != SCIP_DIDNOTRUN
    3988 && (*result) != SCIP_FEASIBLE
    3989 && (*result) != SCIP_INFEASIBLE
    3990 && (*result) != SCIP_CONSADDED
    3991 && (*result) != SCIP_SEPARATED )
    3992 {
    3993 SCIPerrorMessage("the user-defined pre subproblem solving method for the Benders' decomposition <%s> returned "
    3994 "invalid result <%d>\n", benders->name, *result);
    3995 return SCIP_INVALIDRESULT;
    3996 }
    3997
    3998 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
    3999 if( skipsolve )
    4000 {
    4001 SCIPsetDebugMsg(set, "skipping the subproblem solving for Benders' decomposition <%s>. "
    4002 "returning result <%d>\n", benders->name, *result);
    4003 return SCIP_OKAY;
    4004 }
    4005 }
    4006
    4007 /* the cut strengthening is performed before the regular subproblem solve is called. To avoid recursion, the flag
    4008 * strengthenround is set to TRUE when the cut strengthening is performed. The cut strengthening is not performed as
    4009 * part of the large neighbourhood Benders' search.
    4010 *
    4011 * NOTE: cut strengthening is only applied for fractional solutions and integer solutions if there are no CIP
    4012 * subproblems.
    4013 */
    4014 if( benders->strengthenenabled && !benders->strengthenround && !benders->iscopy
    4015 && (!checkint || SCIPbendersGetNConvexSubproblems(benders) == SCIPbendersGetNSubproblems(benders)) )
    4016 {
    4017 SCIP_Bool skipsolve;
    4018
    4019 benders->strengthenround = TRUE;
    4020 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
    4021 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, FALSE, infeasible, auxviol,
    4022 &skipsolve, result) );
    4023 benders->strengthenround = FALSE;
    4024
    4025 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
    4026 if( skipsolve )
    4027 {
    4028 SCIPsetDebugMsg(set, "skipping the subproblem solving because cut strengthening found a cut "
    4029 "for Benders' decomposition <%s>. Returning result <%d>\n", benders->name, *result);
    4030 return SCIP_OKAY;
    4031 }
    4032
    4033 /* the result flag need to be reset to DIDNOTRUN for the main subproblem solve */
    4034 (*result) = SCIP_DIDNOTRUN;
    4035 }
    4036
    4037 /* allocating memory for the infeasible subproblem array */
    4038 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &subprobsolved, nsubproblems) );
    4039 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &substatus, nsubproblems) );
    4040 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &mergecands, nsubproblems) );
    4041 npriomergecands = 0;
    4042 nmergecands = 0;
    4043
    4044 /* allocating the memory for the subproblem solving and cut generation indices */
    4045 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &solveidx, nsubproblems) );
    4046 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &executedidx, nsubproblems) );
    4047 nsolveidx = 0;
    4048 nexecutedidx = 0;
    4049
    4050 /* only a subset of the subproblems are initially solved. Both solving loops are executed for the subproblems to
    4051 * check whether any cuts are generated. If a cut is generated, then no further subproblems are solved. If a cut is
    4052 * not generated, then an additional set of subproblems are solved.
    4053 */
    4054 while( nsolved < nsubproblems )
    4055 {
    4056 /* getting the indices for the subproblems that will be solved */
    4057 createSolveSubproblemIndexList(benders, set, type, &solveidx, &nsolveidx);
    4058
    4059 /* by default the number of solve loops is 1. This is the case if all subproblems are LP or the user has defined a
    4060 * benderssolvesub callback. If there is a subproblem that is not an LP, then 2 solve loops are performed. The first
    4061 * loop is the LP solving loop, the second solves the subproblem to integer optimality.
    4062 */
    4063 nsolveloops = 1;
    4064
    4065 for( l = 0; l < nsolveloops; l++ )
    4066 {
    4067 SCIP_BENDERSSOLVELOOP solveloop; /* identifies what problem type is solve in this solve loop */
    4068
    4069 /* if either benderssolvesubconvex or benderssolvesub are implemented, then the user callbacks are invoked */
    4070 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL )
    4071 {
    4072 if( l == 0 )
    4074 else
    4076 }
    4077 else
    4078 solveloop = (SCIP_BENDERSSOLVELOOP) l;
    4079
    4080 /* solving the subproblems for this round of enforcement/checking. */
    4081 SCIP_CALL( solveBendersSubproblems(benders, set, sol, type, solveloop, checkint, &nverified,
    4082 solveidx, nsolveidx, &subprobsolved, &substatus, infeasible, &optimal, &stopped) );
    4083
    4084 /* if the solving has been stopped, then the subproblem solving and cut generation must terminate */
    4085 if( stopped )
    4086 break;
    4087
    4088 /* Generating cuts for the subproblems. Cuts are only generated when the solution is from primal heuristics,
    4089 * relaxations or the LP
    4090 */
    4091 if( type != SCIP_BENDERSENFOTYPE_PSEUDO )
    4092 {
    4093 SCIP_CALL( generateBendersCuts(benders, set, sol, result, type, solveloop, checkint, subprobsolved,
    4094 substatus, solveidx, nsolveidx, &mergecands, &npriomergecands, &nmergecands, &nsolveloops) );
    4095 }
    4096 else
    4097 {
    4098 /* The first solving loop solves the convex subproblems and the convex relaxations of the CIP subproblems. The
    4099 * second solving loop solves the CIP subproblems. The second solving loop is only called if the integer
    4100 * feasibility is being checked and if the convex subproblems and convex relaxations are not infeasible.
    4101 */
    4102 if( !(*infeasible) && checkint && !SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set))
    4104 nsolveloops = 2;
    4105 }
    4106 }
    4107
    4108 nsolved += nsolveidx;
    4109
    4110 /* storing the indices of the subproblems for which the solving loop was executed */
    4111 for( i = 0; i < nsolveidx; i++ )
    4112 executedidx[nexecutedidx++] = solveidx[i];
    4113
    4114 /* if the result is CONSADDED or SEPARATED, then a cut is generated and no further subproblem processing is
    4115 * required
    4116 */
    4117 if( (*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED )
    4118 break;
    4119 }
    4120
    4121 /* inserting the subproblems into the priority queue for the next solve call */
    4122 SCIP_CALL( updateSubproblemStatQueue(benders, executedidx, nexecutedidx, TRUE) );
    4123
    4124 if( stopped ) /*lint !e774*/
    4125 goto TERMINATE;
    4126
    4127 allverified = (nverified == nsubproblems);
    4128
    4129 SCIPsetDebugMsg(set, "End Benders' decomposition subproblem solve. result %d infeasible %u auxviol %u nverified %d\n",
    4130 *result, *infeasible, *auxviol, nverified);
    4131
    4132#ifdef SCIP_DEBUG
    4133 if( (*result) == SCIP_CONSADDED )
    4134 {
    4135 SCIPsetDebugMsg(set, "Benders' decomposition: Cut added\n");
    4136 }
    4137#endif
    4138
    4139 /* if the number of checked pseudo solutions exceeds a set limit, then all subproblems are passed as merge
    4140 * candidates. Currently, merging subproblems into the master problem is the only method for resolving numerical
    4141 * troubles.
    4142 *
    4143 * We are only interested in the pseudo solutions that have been checked completely for integrality. This is
    4144 * identified by checkint == TRUE. This means that the Benders' decomposition constraint is one of the last
    4145 * constraint handlers that must resolve the infeasibility. If the Benders' decomposition framework can't resolve the
    4146 * infeasibility, then this will result in an error.
    4147 */
    4148 if( type == SCIP_BENDERSENFOTYPE_PSEUDO && checkint )
    4149 {
    4150 benders->npseudosols++;
    4151
    4152 if( benders->npseudosols > BENDERS_MAXPSEUDOSOLS )
    4153 {
    4154 /* if a priority merge candidate already exists, then no other merge candidates need to be added.*/
    4155 if( npriomergecands == 0 )
    4156 {
    4157 /* all subproblems are added to the merge candidate list. The first active subproblem is added as a
    4158 * priority merge candidate
    4159 */
    4160 nmergecands = 0;
    4161 npriomergecands = 1;
    4162 for( i = 0; i < nsubproblems; i++ )
    4163 {
    4164 /* only active subproblems are added to the merge candidate list */
    4165 if( subproblemIsActive(benders, i) )
    4166 {
    4167 mergecands[nmergecands] = i;
    4168 nmergecands++;
    4169 }
    4170 }
    4171
    4172 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " The number of checked pseudo solutions exceeds the "
    4173 "limit of %d. All active subproblems are merge candidates, with subproblem %d a priority candidate.\n",
    4174 BENDERS_MAXPSEUDOSOLS, mergecands[0]);
    4175 }
    4176 }
    4177 }
    4178 else
    4179 benders->npseudosols = 0;
    4180
    4181 /* if the result is SCIP_DIDNOTFIND, then there was a error in generating cuts in all subproblems that are not
    4182 * optimal. This result does not cutoff any solution, so the Benders' decomposition algorithm will fail.
    4183 *
    4184 * It could happen that the cut strengthening approach causes an error the cut generation. In this case, an error
    4185 * should not be thrown. So, this check will be skipped when in a strengthening round.
    4186 * TODO: Work out a way to ensure Benders' decomposition does not terminate due to a SCIP_DIDNOTFIND result.
    4187 */
    4188 if( (*result) == SCIP_DIDNOTFIND && !benders->strengthenround )
    4189 {
    4190 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
    4191 (*result) = SCIP_SOLVELP;
    4192 else
    4193 (*result) = SCIP_INFEASIBLE;
    4194
    4195 SCIPerrorMessage("An error was found when generating cuts for non-optimal subproblems of Benders' "
    4196 "decomposition <%s>. Consider merging the infeasible subproblems into the master problem.\n", SCIPbendersGetName(benders));
    4197
    4198 /* since no other cuts are generated, then this error will result in a crash. It is possible to avoid the error,
    4199 * by merging the affected subproblem into the master problem.
    4200 *
    4201 * NOTE: If the error occurs while checking solutions, i.e. SCIP_BENDERSENFOTYPE_CHECK, then it is valid to set
    4202 * the result to SCIP_INFEASIBLE and the success flag to TRUE
    4203 */
    4204 if( type != SCIP_BENDERSENFOTYPE_CHECK )
    4205 success = FALSE;
    4206
    4207 goto POSTSOLVE;
    4208 }
    4209
    4210 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
    4211 {
    4212 if( (*infeasible) || !allverified )
    4213 (*result) = SCIP_SOLVELP;
    4214 else
    4215 {
    4216 (*result) = SCIP_FEASIBLE;
    4217
    4218 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
    4219 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
    4220 * TRUE.
    4221 */
    4222 (*auxviol) = !optimal;
    4223 }
    4224 }
    4225 else if( checkint && (type == SCIP_BENDERSENFOTYPE_CHECK
    4226 || ((*result) != SCIP_CONSADDED && (*result) != SCIP_SEPARATED)) )
    4227 {
    4228 /* if the subproblems are being solved as part of conscheck, then the results flag must be returned after the solving
    4229 * has completed.
    4230 */
    4231 if( (*infeasible) || !allverified )
    4232 (*result) = SCIP_INFEASIBLE;
    4233 else
    4234 {
    4235 (*result) = SCIP_FEASIBLE;
    4236
    4237 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
    4238 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
    4239 * TRUE.
    4240 */
    4241 (*auxviol) = !optimal;
    4242 }
    4243 }
    4244
    4245POSTSOLVE:
    4246 /* calling the post-solve call back for the Benders' decomposition algorithm. This allows the user to work directly
    4247 * with the solved subproblems and the master problem */
    4248 if( benders->benderspostsolve != NULL )
    4249 {
    4250 SCIP_Bool merged;
    4251
    4252 merged = FALSE;
    4253
    4254 SCIP_CALL( benders->benderspostsolve(set->scip, benders, sol, type, mergecands, npriomergecands, nmergecands,
    4255 checkint, (*infeasible), &merged) );
    4256
    4257 if( merged )
    4258 {
    4259 (*result) = SCIP_CONSADDED;
    4260
    4261 /* since subproblems have been merged, then constraints have been added. This could resolve the unresolved
    4262 * infeasibility, so the error has been corrected.
    4263 */
    4264 success = TRUE;
    4265 }
    4266 else if( !success )
    4267 {
    4268 SCIPerrorMessage("An error occurred during Benders' decomposition cut generations and no merging had been "
    4269 "performed. It is not possible to continue solving the problem by Benders' decomposition\n");
    4270 }
    4271 }
    4272
    4273TERMINATE:
    4274 /* if the solving process has stopped, then all subproblems need to be freed */
    4275 if( stopped ) /*lint !e774*/
    4276 nfree = nsubproblems;
    4277 else
    4278 nfree = nexecutedidx;
    4279
    4280 /* freeing the subproblems after the cuts are generated */
    4281 subproblemcount = 0;
    4282 while( subproblemcount < nfree )
    4283 {
    4284 int subidx;
    4285
    4286 if( stopped )
    4287 subidx = subproblemcount;
    4288 else
    4289 subidx = executedidx[subproblemcount];
    4290
    4291 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, subidx) );
    4292
    4293 subproblemcount++;
    4294 }
    4295
    4296#ifndef NDEBUG
    4297 for( i = 0; i < nsubproblems; i++ )
    4298 assert(SCIPbendersSubproblem(benders, i) == NULL
    4300 || !SCIPinProbing(SCIPbendersSubproblem(benders, i))
    4301 || !subproblemIsActive(benders, i));
    4302#endif
    4303
    4304 /* increment the number of calls to the Benders' decomposition subproblem solve */
    4305 benders->ncalls++;
    4306
    4307 SCIPsetDebugMsg(set, "End Benders' decomposition execution method. result %d infeasible %u auxviol %u\n", *result,
    4308 *infeasible, *auxviol);
    4309
    4310 /* end timing */
    4311 SCIPclockStop(benders->bendersclock, set);
    4312
    4313 /* freeing memory */
    4314 SCIPfreeBlockMemoryArray(set->scip, &executedidx, nsubproblems);
    4315 SCIPfreeBlockMemoryArray(set->scip, &solveidx, nsubproblems);
    4316 SCIPfreeBlockMemoryArray(set->scip, &mergecands, nsubproblems);
    4317 SCIPfreeBlockMemoryArray(set->scip, &substatus, nsubproblems);
    4318 SCIPfreeBlockMemoryArray(set->scip, &subprobsolved, nsubproblems);
    4319
    4320 /* if there was an error in generating cuts and merging was not performed, then the solution is perturbed in an
    4321 * attempt to generate a cut and correct the infeasibility
    4322 */
    4323 if( !success && !stopped )
    4324 {
    4325 SCIP_Bool skipsolve;
    4326 SCIP_RESULT perturbresult;
    4327
    4328 skipsolve = FALSE;
    4329
    4330 benders->strengthenround = TRUE;
    4331 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
    4332 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, TRUE, infeasible, auxviol,
    4333 &skipsolve, &perturbresult) );
    4334 benders->strengthenround = FALSE;
    4335
    4336 if( perturbresult == SCIP_CONSADDED || perturbresult == SCIP_SEPARATED )
    4337 (*result) = perturbresult;
    4338
    4339 success = skipsolve;
    4340 }
    4341
    4342 /* if the Benders' decomposition subproblem check stopped, then we don't have a valid result. In this case, the
    4343 * safest thing to do is report INFEASIBLE.
    4344 */
    4345 if( stopped )
    4346 (*result) = SCIP_INFEASIBLE;
    4347
    4348 /* if the subproblem verification identifies the solution as feasible, then a check whether slack variables have been
    4349 * used is necessary. If any slack variables are non-zero, then the solution is reverified after the objective
    4350 * coefficient for the slack variables is increased.
    4351 */
    4352 if( (*result) == SCIP_FEASIBLE )
    4353 {
    4354 SCIP_Bool activeslack;
    4355
    4356 SCIP_CALL( SCIPbendersSolSlackVarsActive(benders, &activeslack) );
    4357 SCIPsetDebugMsg(set, "Type: %d Active slack: %u Feasibility Phase: %u\n", type, activeslack,
    4358 benders->feasibilityphase);
    4359 if( activeslack )
    4360 {
    4361 if( type == SCIP_BENDERSENFOTYPE_CHECK )
    4362 (*result) = SCIP_INFEASIBLE;
    4363 else
    4364 {
    4365 /* increasing the value of the slack variable by a factor of 10 */
    4366 benders->slackvarcoef *= 10.0;
    4367
    4368 if( benders->slackvarcoef <= benders->maxslackvarcoef )
    4369 {
    4370 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Increasing the slack variable coefficient to %g.\n", benders->slackvarcoef);
    4371 }
    4372 else
    4373 {
    4374 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Fixing the slack variables to zero.\n");
    4375 }
    4376
    4377 /* resolving the subproblems with an increased slack variable */
    4378 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
    4379 }
    4380 }
    4381 else if( benders->feasibilityphase )
    4382 {
    4383 if( type != SCIP_BENDERSENFOTYPE_CHECK )
    4384 {
    4385 /* disabling the feasibility phase */
    4386 benders->feasibilityphase = FALSE;
    4387
    4388 /* resolving the subproblems with the slack variables set to zero */
    4389 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
    4390 }
    4391 }
    4392 }
    4393
    4394 if( !success )
    4395 return SCIP_ERROR;
    4396 else
    4397 return SCIP_OKAY;
    4398}
    4399
    4400/** solves the user-defined subproblem solving function */
    4401static
    4403 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4404 SCIP_SET* set, /**< global SCIP settings */
    4405 SCIP_SOL* sol, /**< primal CIP solution */
    4406 int probnumber, /**< the subproblem number */
    4407 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
    4408 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
    4409 SCIP_Real* objective, /**< the objective function value of the subproblem */
    4410 SCIP_RESULT* result /**< the result from solving the subproblem */
    4411 )
    4412{
    4413 assert(benders != NULL);
    4414 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    4415 assert(benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL);
    4416
    4417 assert(solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP);
    4418
    4419 (*objective) = -SCIPsetInfinity(set);
    4420
    4421 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
    4422 * Neighbourhood Benders' Search. */
    4423 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
    4424 {
    4425 if( benders->benderssolvesubconvex != NULL )
    4426 {
    4427 SCIP_CALL( benders->benderssolvesubconvex(set->scip, benders, sol, probnumber,
    4428 SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set)), objective, result) );
    4429 }
    4430 else
    4431 (*result) = SCIP_DIDNOTRUN;
    4432 }
    4433 else if( solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
    4434 {
    4435 if( benders->benderssolvesub != NULL )
    4436 {
    4437 SCIP_CALL( benders->benderssolvesub(set->scip, benders, sol, probnumber, objective, result) );
    4438 }
    4439 else
    4440 (*result) = SCIP_DIDNOTRUN;
    4441 }
    4442
    4443 /* evaluate result */
    4444 if( (*result) != SCIP_DIDNOTRUN
    4445 && (*result) != SCIP_FEASIBLE
    4446 && (*result) != SCIP_INFEASIBLE
    4447 && (*result) != SCIP_UNBOUNDED )
    4448 {
    4449 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned invalid result <%d>\n",
    4450 benders->name, *result);
    4451 return SCIP_INVALIDRESULT;
    4452 }
    4453
    4454 if( (*result) == SCIP_INFEASIBLE )
    4455 (*infeasible) = TRUE;
    4456
    4457 if( (*result) == SCIP_FEASIBLE
    4458 && (SCIPsetIsInfinity(set, -(*objective)) || SCIPsetIsInfinity(set, (*objective))) )
    4459 {
    4460 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned objective value %g\n",
    4461 benders->name, (*objective));
    4462 return SCIP_ERROR;
    4463 }
    4464
    4465 /* if the result is SCIP_DIDNOTFIND, then an error is returned and SCIP will terminate. */
    4466 if( (*result) == SCIP_DIDNOTFIND )
    4467 return SCIP_ERROR;
    4468 else
    4469 return SCIP_OKAY;
    4470}
    4472/** executes the subproblem solving process */
    4474 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4475 SCIP_SET* set, /**< global SCIP settings */
    4476 SCIP_SOL* sol, /**< primal CIP solution */
    4477 int probnumber, /**< the subproblem number */
    4478 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
    4479 SCIP_Bool enhancement, /**< is the solve performed as part of and enhancement? */
    4480 SCIP_Bool* solved, /**< flag to indicate whether the subproblem was solved */
    4481 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
    4482 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
    4483 )
    4484{ /*lint --e{715}*/
    4485 SCIP* subproblem;
    4486 SCIP_RESULT result;
    4487 SCIP_Real objective;
    4488 SCIP_STATUS solvestatus = SCIP_STATUS_UNKNOWN;
    4489
    4490 assert(benders != NULL);
    4491 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    4492
    4493 SCIPsetDebugMsg(set, "Benders' decomposition: solving subproblem %d\n", probnumber);
    4494
    4495 result = SCIP_DIDNOTRUN;
    4496 objective = SCIPsetInfinity(set);
    4497
    4498 subproblem = SCIPbendersSubproblem(benders, probnumber);
    4499
    4500 if( subproblem == NULL && (benders->benderssolvesubconvex == NULL || benders->benderssolvesub == NULL) )
    4501 {
    4502 SCIPerrorMessage("The subproblem %d is set to NULL, but both bendersSolvesubconvex%s and bendersSolvesub%s "
    4503 "are not defined.\n", probnumber, benders->name, benders->name);
    4504 SCIPABORT();
    4505 return SCIP_ERROR;
    4506 }
    4507
    4508 /* initially setting the solved flag to FALSE */
    4509 (*solved) = FALSE;
    4510
    4511 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
    4512 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
    4513 {
    4514 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
    4515 * Neighbourhood Benders' Search. */
    4516 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &objective, &result) );
    4517
    4518 /* if the result is DIDNOTRUN, then the subproblem was not solved */
    4519 (*solved) = (result != SCIP_DIDNOTRUN);
    4520 }
    4521 else if( subproblem != NULL )
    4522 {
    4523 /* setting up the subproblem */
    4524 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX )
    4525 {
    4526 SCIP_CALL( SCIPbendersSetupSubproblem(benders, set, sol, probnumber, type) );
    4527
    4528 /* if the limits of the master problem were hit during the setup process, then the subproblem will not have
    4529 * been setup. In this case, the solving function must be exited.
    4530 */
    4531 if( !SCIPbendersSubproblemIsSetup(benders, probnumber) )
    4532 {
    4533 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4534 (*solved) = FALSE;
    4535 return SCIP_OKAY;
    4536 }
    4537 }
    4538 else
    4539 {
    4540 SCIP_CALL( updateEventhdlrUpperbound(benders, probnumber, SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber)) );
    4541 }
    4542
    4543 /* solving the subproblem
    4544 * the LP of the subproblem is solved in the first solveloop.
    4545 * In the second solve loop, the MIP problem is solved */
    4546 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
    4548 {
    4549 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &objective) );
    4550
    4551 /* if the (N)LP was solved without error, then the subproblem is labelled as solved */
    4552 if( solvestatus == SCIP_STATUS_OPTIMAL || solvestatus == SCIP_STATUS_INFEASIBLE )
    4553 (*solved) = TRUE;
    4554
    4555 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4556 (*infeasible) = TRUE;
    4557 }
    4558 else
    4559 {
    4560 SCIP_SOL* bestsol;
    4561
    4562 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
    4563
    4564 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4565 (*infeasible) = TRUE;
    4566
    4567 /* if the generic subproblem solving methods are used, then the CIP subproblems are always solved. */
    4568 (*solved) = TRUE;
    4569
    4570 bestsol = SCIPgetBestSol(subproblem);
    4571 if( bestsol != NULL )
    4572 objective = SCIPgetSolOrigObj(subproblem, bestsol)*(int)SCIPgetObjsense(set->scip);
    4573 else
    4574 objective = SCIPsetInfinity(set);
    4575 }
    4576 }
    4577 else
    4578 {
    4579 SCIPABORT();
    4580 }
    4581
    4582 if( !enhancement )
    4583 {
    4584 /* The following handles the cases when the subproblem is OPTIMAL, INFEASIBLE and UNBOUNDED.
    4585 * If a subproblem is unbounded, then the auxiliary variables are set to -infinity and the unbounded flag is
    4586 * returned as TRUE. No cut will be generated, but the result will be set to SCIP_FEASIBLE.
    4587 */
    4588 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_CIP )
    4589 {
    4590 /* TODO: Consider whether other solutions status should be handled */
    4591 if( solvestatus == SCIP_STATUS_OPTIMAL )
    4592 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
    4593 else if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4594 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4595 else if( solvestatus == SCIP_STATUS_USERINTERRUPT || solvestatus == SCIP_STATUS_BESTSOLLIMIT )
    4596 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
    4597 else if( solvestatus == SCIP_STATUS_MEMLIMIT || solvestatus == SCIP_STATUS_TIMELIMIT
    4598 || solvestatus == SCIP_STATUS_UNKNOWN )
    4599 {
    4600 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving "
    4601 "subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
    4602 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4603 }
    4604 else if( solvestatus == SCIP_STATUS_UNBOUNDED )
    4605 {
    4606 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    4607 probnumber);
    4608 SCIPABORT();
    4609 }
    4610 else
    4611 {
    4612 SCIPerrorMessage("Invalid status returned from solving Benders' decomposition subproblem %d. Solution status: %d\n",
    4613 probnumber, solvestatus);
    4614 SCIPABORT();
    4615 }
    4616 }
    4617 else
    4618 {
    4619 assert(solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP);
    4620 if( result == SCIP_FEASIBLE )
    4621 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
    4622 else if( result == SCIP_INFEASIBLE )
    4623 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
    4624 else if( result == SCIP_UNBOUNDED )
    4625 {
    4626 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    4627 probnumber);
    4628 SCIPABORT();
    4629 }
    4630 else if( result != SCIP_DIDNOTRUN )
    4631 {
    4632 SCIPerrorMessage("Invalid result <%d> from user-defined subproblem solving method. This should not happen.\n",
    4633 result);
    4634 }
    4635 }
    4636 }
    4637
    4638 return SCIP_OKAY;
    4639}
    4641/** sets up the subproblem using the solution to the master problem */
    4643 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4644 SCIP_SET* set, /**< global SCIP settings */
    4645 SCIP_SOL* sol, /**< primal CIP solution */
    4646 int probnumber, /**< the subproblem number */
    4647 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
    4648 )
    4649{
    4650 SCIP* subproblem;
    4651 SCIP_VAR** vars;
    4652 SCIP_VAR* mastervar;
    4653 SCIP_Real solval;
    4654 int nvars;
    4655 int i;
    4656
    4657 assert(benders != NULL);
    4658 assert(set != NULL);
    4659 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    4660
    4661 subproblem = SCIPbendersSubproblem(benders, probnumber);
    4662
    4663 /* the subproblem setup can only be performed if the subproblem is not NULL */
    4664 if( subproblem == NULL )
    4665 {
    4666 SCIPerrorMessage("The subproblem %d is NULL. Thus, the subproblem setup must be performed manually in either "
    4667 "bendersSolvesubconvex%s or bendersSolvesub%s.\n", probnumber, benders->name, benders->name);
    4668 return SCIP_ERROR;
    4669 }
    4670 assert(subproblem != NULL);
    4671
    4672 /* changing all of the master problem variable to continuous. */
    4673 SCIP_CALL( SCIPbendersChgMastervarsToCont(benders, set, probnumber) );
    4674
    4675 /* if the Benders' decomposition subproblem is convex and has continuous variables, then probing mode
    4676 * must be started.
    4677 * If the subproblem contains non-convex constraints or discrete variables, then the problem must be initialised,
    4678 * and then put into SCIP_STAGE_SOLVING to be able to change the variable bounds. The probing mode is entered once
    4679 * the variable bounds are set.
    4680 * In the latter case, the transformed problem is freed after each subproblem solve round. */
    4682 {
    4683 SCIP_CALL( SCIPstartProbing(subproblem) );
    4684 }
    4685 else
    4686 {
    4687 SCIP_Bool infeasible;
    4688 SCIP_Bool success;
    4689
    4690 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, &infeasible, &success) );
    4691 assert(success == !infeasible);
    4692
    4693 /* if the problem is identified as infeasible, this means that the underlying LP is infeasible. Since no variable
    4694 * fixings have been applied at this stage, this means that the complete problem is infeasible. It is only
    4695 * possible to set this parameter if we are at the root node or in an initialisation stage.
    4696 */
    4697 if( infeasible )
    4699
    4700 if( !success )
    4701 {
    4702 /* set the flag to indicate that the subproblems have been set up */
    4703 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
    4704
    4705 return SCIP_OKAY;
    4706 }
    4707 }
    4708
    4709 vars = SCIPgetVars(subproblem);
    4710 nvars = SCIPgetNVars(subproblem);
    4711
    4712 /* looping over all variables in the subproblem to find those corresponding to the master problem variables. */
    4713 /* TODO: It should be possible to store the pointers to the master variables to speed up the subproblem setup */
    4714 for( i = 0; i < nvars; i++ )
    4715 {
    4716 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
    4717
    4718 if( mastervar != NULL )
    4719 {
    4720 /* It is possible due to numerics that the solution value exceeds the upper or lower bounds. When this
    4721 * happens, it causes an error in the LP solver as a result of inconsistent bounds. So the following statements
    4722 * are used to ensure that the bounds are not exceeded when applying the fixings for the Benders'
    4723 * decomposition subproblems
    4724 */
    4725 solval = SCIPgetSolVal(set->scip, sol, mastervar);
    4726 if( !SCIPisLT(set->scip, solval, SCIPvarGetUbLocal(vars[i])) )
    4727 solval = SCIPvarGetUbLocal(vars[i]);
    4728 else if( !SCIPisGT(set->scip, solval, SCIPvarGetLbLocal(vars[i])) )
    4729 solval = SCIPvarGetLbLocal(vars[i]);
    4730
    4731 /* fixing the variable in the subproblem */
    4732 if( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) )
    4733 {
    4734 if( SCIPisGT(subproblem, solval, SCIPvarGetLbLocal(vars[i])) )
    4735 {
    4736 SCIP_CALL( SCIPchgVarLb(subproblem, vars[i], solval) );
    4737 }
    4738 if( SCIPisLT(subproblem, solval, SCIPvarGetUbLocal(vars[i])) )
    4739 {
    4740 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], solval) );
    4741 }
    4742 }
    4743
    4744 assert(SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])));
    4745 }
    4746 else if( strstr(SCIPvarGetName(vars[i]), SLACKVAR_NAME) != NULL )
    4747 {
    4748 /* if the slack variables have been added to help improve feasibility, then they remain unfixed with a large
    4749 * objective coefficient. Once the root node has been solved to optimality, then the slack variables are
    4750 * fixed to zero.
    4751 */
    4752 if( benders->feasibilityphase && SCIPgetDepth(set->scip) == 0 && type != SCIP_BENDERSENFOTYPE_CHECK )
    4753 {
    4754 /* The coefficient update or variable fixing can only be performed if the subproblem is in probing mode.
    4755 * If the slack var coef gets very large, then we fix the slack variable to 0 instead.
    4756 */
    4757 if( SCIPinProbing(subproblem) )
    4758 {
    4759 if( benders->slackvarcoef <= benders->maxslackvarcoef )
    4760 {
    4761 SCIP_CALL( SCIPchgVarObjProbing(subproblem, vars[i], benders->slackvarcoef) );
    4762 }
    4763 else
    4764 {
    4765 SCIP_CALL( SCIPchgVarUbProbing(subproblem, vars[i], 0.0) );
    4766 }
    4767 }
    4768 }
    4769 else
    4770 {
    4771 /* if the subproblem is non-linear and convex, then slack variables have been added to the subproblem. These
    4772 * need to be fixed to zero when first solving the subproblem. However, if the slack variables have been added
    4773 * by setting the execfeasphase runtime parameter, then they must not get fixed to zero
    4774 */
    4775 assert( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) );
    4776 assert( SCIPisZero(subproblem, SCIPvarGetLbLocal(vars[i])) );
    4777
    4778 if( SCIPisLT(subproblem, 0.0, SCIPvarGetUbLocal(vars[i])) )
    4779 {
    4780 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], 0.0) );
    4781 }
    4782 }
    4783 }
    4784 }
    4785
    4786 /* if the subproblem contain non-convex constraints or discrete variables, then the probing mode is entered after
    4787 * setting up the subproblem
    4788 */
    4790 {
    4791 SCIP_CALL( SCIPstartProbing(subproblem) );
    4792 }
    4793
    4794 /* set the flag to indicate that the subproblems have been set up */
    4795 SCIPbendersSetSubproblemIsSetup(benders, probnumber, TRUE);
    4796
    4797 return SCIP_OKAY;
    4798}
    4799
    4800/** Solve a Benders' decomposition subproblems. This will either call the user defined method or the generic solving
    4801 * methods. If the generic method is called, then the subproblem must be set up before calling this method. */
    4803 SCIP_BENDERS* benders, /**< Benders' decomposition */
    4804 SCIP_SET* set, /**< global SCIP settings */
    4805 SCIP_SOL* sol, /**< primal CIP solution, can be NULL */
    4806 int probnumber, /**< the subproblem number */
    4807 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
    4808 SCIP_Bool solvecip, /**< directly solve the CIP subproblem */
    4809 SCIP_Real* objective /**< the objective function value of the subproblem, can be NULL */
    4810 )
    4811{
    4812 assert(benders != NULL);
    4813 assert(set != NULL);
    4814 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    4815
    4816 assert(infeasible != NULL);
    4817 (*infeasible) = FALSE;
    4818
    4819 /* the subproblem must be set up before this function is called. */
    4820 if( SCIPbendersSubproblem(benders, probnumber) != NULL && !SCIPbendersSubproblemIsSetup(benders, probnumber)
    4821 && !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
    4822 {
    4823 SCIPerrorMessage("Benders' decomposition subproblem %d must be set up before calling SCIPbendersSolveSubproblem(). Call SCIPsetupSubproblem() first.\n", probnumber);
    4824 return SCIP_ERROR;
    4825 }
    4826
    4827 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
    4828 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL)
    4829 {
    4830 SCIP_BENDERSSOLVELOOP solveloop;
    4831 SCIP_RESULT result;
    4832 SCIP_Real subobj;
    4833
    4834 if( solvecip )
    4836 else
    4838
    4839 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &subobj, &result) );
    4840
    4841 if( objective != NULL )
    4842 (*objective) = subobj;
    4843 }
    4844 else
    4845 {
    4846 SCIP* subproblem;
    4847
    4848 subproblem = SCIPbendersSubproblem(benders, probnumber);
    4849 assert(subproblem != NULL);
    4850
    4851 /* solving the subproblem */
    4852 if( solvecip && SCIPbendersGetSubproblemType(benders, probnumber) != SCIP_BENDERSSUBTYPE_CONVEXCONT )
    4853 {
    4854 SCIP_STATUS solvestatus;
    4855
    4856 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, solvecip) );
    4857
    4858 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4859 (*infeasible) = TRUE;
    4860 if( objective != NULL )
    4861 (*objective) = SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem);
    4862 }
    4863 else
    4864 {
    4865 SCIP_Bool success;
    4866
    4867 /* if the subproblem has convex constraints and continuous variables, then it should have been initialised and
    4868 * in SCIP_STAGE_SOLVING. In this case, the subproblem only needs to be put into probing mode.
    4869 */
    4871 {
    4872 /* if the subproblem is not in probing mode, then it must be put into that mode for the LP solve. */
    4873 if( !SCIPinProbing(subproblem) )
    4874 {
    4875 SCIP_CALL( SCIPstartProbing(subproblem) );
    4876 }
    4877
    4878 success = TRUE;
    4879 }
    4880 else
    4881 {
    4882 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
    4883 }
    4884
    4885 /* if setting up the subproblem was successful */
    4886 if( success )
    4887 {
    4888 SCIP_STATUS solvestatus;
    4889 SCIP_Real lpobjective;
    4890
    4891 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &lpobjective) );
    4892
    4893 if( solvestatus == SCIP_STATUS_INFEASIBLE )
    4894 (*infeasible) = TRUE;
    4895 else if( objective != NULL )
    4896 (*objective) = lpobjective;
    4897 }
    4898 else
    4899 {
    4900 if( objective != NULL )
    4901 (*objective) = SCIPinfinity(subproblem);
    4902 }
    4903 }
    4904 }
    4905
    4906 return SCIP_OKAY;
    4907}
    4908
    4909/** copies the time and memory limit from the master problem to the subproblem */
    4910static
    4912 SCIP* scip, /**< the SCIP data structure */
    4913 SCIP* subproblem /**< the Benders' decomposition subproblem */
    4914 )
    4915{
    4916 SCIP_Real mastertimelimit;
    4917 SCIP_Real subtimelimit;
    4918 SCIP_Real maxsubtimelimit;
    4919 SCIP_Real mastermemorylimit;
    4920 SCIP_Real submemorylimit;
    4921 SCIP_Real maxsubmemorylimit;
    4922
    4923 assert(scip != NULL);
    4924
    4925 /* setting the time limit for the Benders' decomposition subproblems. It is set to 102% of the remaining time. */
    4926 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &mastertimelimit) );
    4927 maxsubtimelimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/time"));
    4928 subtimelimit = (mastertimelimit - SCIPgetSolvingTime(scip)) * 1.02;
    4929 subtimelimit = MIN(subtimelimit, maxsubtimelimit);
    4930 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", MAX(0.0, subtimelimit)) );
    4931
    4932 /* setting the memory limit for the Benders' decomposition subproblems. */
    4933 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &mastermemorylimit) );
    4934 maxsubmemorylimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/memory"));
    4935 submemorylimit = mastermemorylimit - (SCIPgetMemUsed(scip) + SCIPgetMemExternEstim(scip))/1048576.0;
    4936 submemorylimit = MIN(submemorylimit, maxsubmemorylimit);
    4937 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", MAX(0.0, submemorylimit)) );
    4938
    4939 return SCIP_OKAY;
    4940}
    4941
    4942/** stores the original parameters from the subproblem */
    4943static
    4945 SCIP* subproblem, /**< the SCIP data structure */
    4946 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
    4947 )
    4948{
    4949 assert(subproblem != NULL);
    4950 assert(origparams != NULL);
    4951
    4952 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &origparams->limits_memory) );
    4953 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &origparams->limits_time) );
    4954 SCIP_CALL( SCIPgetBoolParam(subproblem, "conflict/enable", &origparams->conflict_enable) );
    4955 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &origparams->lp_disablecutoff) );
    4956 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/scaling", &origparams->lp_scaling) );
    4957 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/initalgorithm", &origparams->lp_initalg) );
    4958 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/resolvealgorithm", &origparams->lp_resolvealg) );
    4959 SCIP_CALL( SCIPgetBoolParam(subproblem, "lp/alwaysgetduals", &origparams->lp_alwaysgetduals) );
    4960 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/scaleobj", &origparams->misc_scaleobj) );
    4961 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/catchctrlc", &origparams->misc_catchctrlc) );
    4962 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxrounds", &origparams->prop_maxrounds) );
    4963 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxroundsroot", &origparams->prop_maxroundsroot) );
    4964 SCIP_CALL( SCIPgetIntParam(subproblem, "constraints/linear/propfreq", &origparams->cons_linear_propfreq) );
    4965
    4966 return SCIP_OKAY;
    4967}
    4968
    4969/** sets the parameters for the subproblem */
    4970static
    4972 SCIP* scip, /**< the SCIP data structure */
    4973 SCIP* subproblem /**< the subproblem SCIP instance */
    4974 )
    4975{
    4976 assert(scip != NULL);
    4977 assert(subproblem != NULL);
    4978
    4979 /* copying memory and time limits */
    4980 SCIP_CALL( copyMemoryAndTimeLimits(scip, subproblem) );
    4981
    4982 /* Do we have to disable presolving? If yes, we have to store all presolving parameters. */
    4984
    4985 /* Disabling heuristics so that the problem is not trivially solved */
    4987
    4988 /* store parameters that are changed for the generation of the subproblem cuts */
    4989 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", FALSE) );
    4990
    4991 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
    4992 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", 0) );
    4993
    4994 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", 'd') );
    4995 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", 'd') );
    4996
    4997 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", TRUE) );
    4998 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", FALSE) );
    4999
    5000 /* do not abort subproblem on CTRL-C */
    5001 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", FALSE) );
    5002
    5003#ifndef SCIP_MOREDEBUG
    5004 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
    5005#endif
    5006
    5007 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", 0) );
    5008 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", 0) );
    5009
    5010 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", -1) );
    5011
    5012 SCIP_CALL( SCIPsetIntParam(subproblem, "heuristics/alns/freq", -1) );
    5013
    5014 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/aggregation/freq", -1) );
    5015 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/gomory/freq", -1) );
    5016
    5017 return SCIP_OKAY;
    5018}
    5019
    5020/** resets the original parameters from the subproblem */
    5021static
    5023 SCIP* subproblem, /**< the SCIP data structure */
    5024 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
    5025 )
    5026{
    5027 assert(subproblem != NULL);
    5028 assert(origparams != NULL);
    5029
    5030 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", origparams->limits_memory) );
    5031 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", origparams->limits_time) );
    5032 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", origparams->conflict_enable) );
    5033 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", origparams->lp_disablecutoff) );
    5034 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", origparams->lp_scaling) );
    5035 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", origparams->lp_initalg) );
    5036 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", origparams->lp_resolvealg) );
    5037 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", origparams->lp_alwaysgetduals) );
    5038 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", origparams->misc_scaleobj) );
    5039 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", origparams->misc_catchctrlc) );
    5040 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", origparams->prop_maxrounds) );
    5041 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", origparams->prop_maxroundsroot) );
    5042 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", origparams->cons_linear_propfreq) );
    5043
    5044 return SCIP_OKAY;
    5045}
    5047/** returns NLP solver parameters used for solving NLP subproblems */
    5049 SCIP_BENDERS* benders /**< Benders' decomposition */
    5050 )
    5051{
    5052 assert(benders != NULL);
    5053
    5054 return benders->nlpparam;
    5055}
    5056
    5057/** solves the LP of the Benders' decomposition subproblem
    5058 *
    5059 * This requires that the subproblem is in probing mode.
    5060 */
    5062 SCIP* scip, /**< the SCIP data structure */
    5063 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
    5064 int probnumber, /**< the subproblem number */
    5065 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
    5066 SCIP_Real* objective /**< optimal value of subproblem, if solved to optimality */
    5067 )
    5068{
    5069 SCIP* subproblem;
    5070 SCIP_SUBPROBPARAMS* origparams;
    5071 SCIP_Bool solvenlp;
    5072
    5073 assert(benders != NULL);
    5074 assert(solvestatus != NULL);
    5075 assert(objective != NULL);
    5076 assert(SCIPbendersSubproblemIsSetup(benders, probnumber));
    5077
    5078 /* TODO: This should be solved just as an LP, so as a MIP. There is too much overhead with the MIP.
    5079 * Need to change status check for checking the LP. */
    5080 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5081 assert(subproblem != NULL);
    5082
    5083 /* only solve the NLP relaxation if the NLP has been constructed and there exists an NLPI. If it is not possible to
    5084 * solve the NLP relaxation, then the LP relaxation is used to generate Benders' cuts
    5085 */
    5086 solvenlp = FALSE;
    5087 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
    5089 solvenlp = TRUE;
    5090
    5091 *objective = SCIPinfinity(subproblem);
    5092
    5093 assert(SCIPisNLPConstructed(subproblem) || SCIPisLPConstructed(subproblem));
    5094 assert(SCIPinProbing(subproblem));
    5095
    5096 /* allocating memory for the parameter storage */
    5097 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
    5098
    5099 /* store the original parameters of the subproblem */
    5100 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
    5101
    5102 /* setting the subproblem parameters */
    5103 SCIP_CALL( setSubproblemParams(scip, subproblem) );
    5104
    5105 if( solvenlp )
    5106 {
    5107 SCIP_NLPSOLSTAT nlpsolstat;
    5108 SCIP_NLPTERMSTAT nlptermstat;
    5109#ifdef SCIP_MOREDEBUG
    5110 SCIP_SOL* nlpsol;
    5111#endif
    5112
    5113 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
    5114
    5115 nlpsolstat = SCIPgetNLPSolstat(subproblem);
    5116 nlptermstat = SCIPgetNLPTermstat(subproblem);
    5117 SCIPdebugMsg(scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
    5118
    5119 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
    5120 {
    5121 /* trust infeasible only if terminated "okay" */
    5122 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
    5123 }
    5124 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT
    5125 || nlpsolstat == SCIP_NLPSOLSTAT_FEASIBLE )
    5126 {
    5127#ifdef SCIP_MOREDEBUG
    5128 SCIP_CALL( SCIPcreateNLPSol(subproblem, &nlpsol, NULL) );
    5129 SCIP_CALL( SCIPprintSol(subproblem, nlpsol, NULL, FALSE) );
    5130 SCIP_CALL( SCIPfreeSol(subproblem, &nlpsol) );
    5131#endif
    5132
    5133 (*solvestatus) = SCIP_STATUS_OPTIMAL;
    5134 (*objective) = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
    5135 }
    5136 else if( nlpsolstat == SCIP_NLPSOLSTAT_UNBOUNDED )
    5137 {
    5138 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
    5139 SCIPerrorMessage("The NLP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    5140 probnumber);
    5141 SCIPABORT();
    5142 }
    5143 else if( nlptermstat == SCIP_NLPTERMSTAT_TIMELIMIT )
    5144 {
    5145 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
    5146 }
    5147 else if( nlptermstat == SCIP_NLPTERMSTAT_ITERLIMIT)
    5148 {
    5149 /* this is an approximation in lack of a better fitting SCIP_STATUS */
    5150 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));
    5151 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
    5152 }
    5153 else if( nlptermstat == SCIP_NLPTERMSTAT_INTERRUPT )
    5154 {
    5155 (*solvestatus) = SCIP_STATUS_USERINTERRUPT;
    5156 }
    5157 else
    5158 {
    5159 SCIPerrorMessage("Invalid solution status: %d. Termination status: %d. Solving the NLP relaxation of Benders' decomposition subproblem %d.\n",
    5160 nlpsolstat, nlptermstat, probnumber);
    5161 SCIPABORT();
    5162 }
    5163 }
    5164 else
    5165 {
    5166 SCIP_Bool lperror;
    5167 SCIP_Bool cutoff;
    5168
    5169 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
    5170
    5171 switch( SCIPgetLPSolstat(subproblem) )
    5172 {
    5174 {
    5175 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
    5176 break;
    5177 }
    5178
    5180 {
    5181 (*solvestatus) = SCIP_STATUS_OPTIMAL;
    5182 (*objective) = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(scip);
    5183 break;
    5184 }
    5185
    5187 {
    5188 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
    5189 SCIPerrorMessage("The LP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
    5190 probnumber);
    5191 SCIPABORT();
    5192 break;
    5193 }
    5194
    5198 {
    5199 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_TIMELIMIT )
    5200 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
    5201 else
    5202 (*solvestatus) = SCIP_STATUS_UNKNOWN;
    5203
    5204 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving LP "
    5205 "relaxation of subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
    5206 break;
    5207 }
    5208
    5211 default:
    5212 {
    5213 SCIPerrorMessage("Invalid status: %d. Solving the LP relaxation of Benders' decomposition subproblem %d.\n",
    5214 SCIPgetLPSolstat(subproblem), probnumber);
    5215 SCIPABORT();
    5216 break;
    5217 }
    5218 }
    5219 }
    5220
    5221 /* resetting the subproblem parameters */
    5222 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
    5223
    5224 /* freeing the parameter storage */
    5225 SCIPfreeBlockMemory(subproblem, &origparams);
    5226
    5227 return SCIP_OKAY;
    5228}
    5230/** solves the Benders' decomposition subproblem */
    5232 SCIP* scip, /**< the SCIP data structure */
    5233 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
    5234 int probnumber, /**< the subproblem number */
    5235 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
    5236 SCIP_Bool solvecip /**< directly solve the CIP subproblem */
    5237 )
    5238{
    5239 SCIP* subproblem;
    5240 SCIP_SUBPROBPARAMS* origparams;
    5241
    5242 assert(benders != NULL);
    5243 assert(solvestatus != NULL);
    5244
    5245 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5246 assert(subproblem != NULL);
    5247
    5248 /* allocating memory for the parameter storage */
    5249 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
    5250
    5251 /* store the original parameters of the subproblem */
    5252 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
    5253
    5254 /* If the solve has been stopped for the subproblem, then we need to restart it to complete the solve. The subproblem
    5255 * is stopped when it is a MIP so that LP cuts and IP cuts can be generated. */
    5256 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING )
    5257 {
    5258 /* the subproblem should be in probing mode. Otherwise, the event handler did not work correctly */
    5259 assert( SCIPinProbing(subproblem) );
    5260
    5261 /* the probing mode needs to be stopped so that the MIP can be solved */
    5262 SCIP_CALL( SCIPendProbing(subproblem) );
    5263
    5264 /* the problem was interrupted in the event handler, so SCIP needs to be informed that the problem is to be restarted */
    5265 SCIP_CALL( SCIPrestartSolve(subproblem) );
    5266 }
    5267 else if( solvecip )
    5268 {
    5269 /* if the MIP will be solved directly, then the probing mode needs to be skipped.
    5270 * This is achieved by setting the solvecip flag in the event handler data to TRUE
    5271 */
    5272 SCIP_EVENTHDLR* eventhdlr;
    5273 SCIP_EVENTHDLRDATA* eventhdlrdata;
    5274
    5275 eventhdlr = SCIPfindEventhdlr(subproblem, MIPNODEFOCUS_EVENTHDLR_NAME);
    5276 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    5277
    5278 eventhdlrdata->solvecip = TRUE;
    5279 }
    5280 else
    5281 {
    5282 /* if the problem is not in probing mode, then we need to solve the LP. That requires all methods that will
    5283 * modify the structure of the problem need to be deactivated */
    5284
    5285 /* setting the subproblem parameters */
    5286 SCIP_CALL( setSubproblemParams(scip, subproblem) );
    5287
    5288#ifdef SCIP_EVENMOREDEBUG
    5289 SCIP_CALL( SCIPsetBoolParam(subproblem, "display/lpinfo", TRUE) );
    5290#endif
    5291 }
    5292
    5293#ifdef SCIP_MOREDEBUG
    5294 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_FULL) );
    5295 SCIP_CALL( SCIPsetIntParam(subproblem, "display/freq", 1) );
    5296#endif
    5297
    5298 SCIP_CALL( SCIPsolve(subproblem) );
    5299
    5300 *solvestatus = SCIPgetStatus(subproblem);
    5301
    5302 if( *solvestatus != SCIP_STATUS_OPTIMAL && *solvestatus != SCIP_STATUS_UNBOUNDED
    5303 && *solvestatus != SCIP_STATUS_INFEASIBLE && *solvestatus != SCIP_STATUS_USERINTERRUPT
    5304 && *solvestatus != SCIP_STATUS_BESTSOLLIMIT && *solvestatus != SCIP_STATUS_TIMELIMIT
    5305 && *solvestatus != SCIP_STATUS_MEMLIMIT )
    5306 {
    5307 SCIPerrorMessage("Invalid status: %d. Solving the CIP of Benders' decomposition subproblem %d.\n",
    5308 *solvestatus, probnumber);
    5309 SCIPABORT();
    5310 }
    5311
    5312 /* resetting the subproblem parameters */
    5313 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
    5314
    5315 /* freeing the parameter storage */
    5316 SCIPfreeBlockMemory(subproblem, &origparams);
    5317
    5318 return SCIP_OKAY;
    5319}
    5321/** frees the subproblems */
    5323 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5324 SCIP_SET* set, /**< global SCIP settings */
    5325 int probnumber /**< the subproblem number */
    5326 )
    5327{
    5328 assert(benders != NULL);
    5329 assert(benders->bendersfreesub != NULL
    5330 || (benders->bendersfreesub == NULL && benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL));
    5331 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    5332
    5333 if( benders->bendersfreesub != NULL )
    5334 {
    5335 SCIP_CALL( benders->bendersfreesub(set->scip, benders, probnumber) );
    5336 }
    5337 else
    5338 {
    5339 /* the subproblem is only freed if it is not independent */
    5340 if( subproblemIsActive(benders, probnumber) )
    5341 {
    5342 SCIP* subproblem = SCIPbendersSubproblem(benders, probnumber);
    5343
    5345 {
    5346 /* ending probing mode to reset the current node. The probing mode will be restarted at the next solve */
    5347 if( SCIPinProbing(subproblem) )
    5348 {
    5349 SCIP_CALL( SCIPendProbing(subproblem) );
    5350 }
    5351 }
    5352 else
    5353 {
    5354 /* if the subproblems were solved as part of an enforcement stage, then they will still be in probing mode. The
    5355 * probing mode must first be finished and then the problem can be freed */
    5356 if( SCIPgetStage(subproblem) >= SCIP_STAGE_TRANSFORMED && SCIPinProbing(subproblem) )
    5357 {
    5358 SCIP_CALL( SCIPendProbing(subproblem) );
    5359 }
    5360
    5361 SCIP_CALL( SCIPfreeTransform(subproblem) );
    5362 }
    5363 }
    5364 }
    5365
    5366 /* setting the setup flag for the subproblem to FALSE */
    5367 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
    5368 return SCIP_OKAY;
    5369}
    5371/** compares the subproblem objective value with the auxiliary variable value for optimality */
    5373 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    5374 SCIP_SET* set, /**< global SCIP settings */
    5375 SCIP_SOL* sol, /**< primal CIP solution */
    5376 int probnumber /**< the subproblem number */
    5377 )
    5378{
    5379 SCIP_Real auxiliaryvarval;
    5380 SCIP_Bool optimal;
    5381
    5382 assert(benders != NULL);
    5383 assert(set != NULL);
    5384 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    5385
    5386 optimal = FALSE;
    5387
    5388 auxiliaryvarval = SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber);
    5389
    5390 SCIPsetDebugMsg(set, "Subproblem %d - Auxiliary Variable: %g Subproblem Objective: %g Reldiff: %g Soltol: %g\n",
    5391 probnumber, auxiliaryvarval, SCIPbendersGetSubproblemObjval(benders, probnumber),
    5392 SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval), benders->solutiontol);
    5393
    5394 if( SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval) < benders->solutiontol )
    5395 optimal = TRUE;
    5396
    5397 return optimal;
    5398}
    5400/** returns the value of the auxiliary variable value in a master problem solution */
    5402 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    5403 SCIP_SET* set, /**< global SCIP settings */
    5404 SCIP_SOL* sol, /**< primal CIP solution */
    5405 int probnumber /**< the subproblem number */
    5406 )
    5407{
    5408 SCIP_VAR* auxiliaryvar;
    5409
    5410 assert(benders != NULL);
    5411 assert(set != NULL);
    5412
    5413 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    5414 assert(auxiliaryvar != NULL);
    5415
    5416 return SCIPgetSolVal(set->scip, sol, auxiliaryvar);
    5417}
    5418
    5419/** Solves an independent subproblem to identify its lower bound. The lower bound is then used to update the bound on
    5420 * the auxiliary variable.
    5421 */
    5423 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5424 SCIP_SET* set, /**< global SCIP settings */
    5425 int probnumber, /**< the subproblem to be evaluated */
    5426 SCIP_Real* lowerbound, /**< the lowerbound for the subproblem */
    5427 SCIP_Bool* infeasible /**< was the subproblem found to be infeasible? */
    5428 )
    5429{
    5430 SCIP* subproblem;
    5431 SCIP_Real dualbound;
    5432 SCIP_Real memorylimit;
    5433 SCIP_Real timelimit;
    5434 SCIP_Longint totalnodes;
    5435 int disablecutoff;
    5436 int verblevel;
    5437 SCIP_Bool lperror;
    5438 SCIP_Bool cutoff;
    5439
    5440 assert(benders != NULL);
    5441 assert(set != NULL);
    5442
    5443 if( benders->benderssolvesub != NULL || benders->benderssolvesubconvex != NULL )
    5444 {
    5445 (*lowerbound) = SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber));
    5446 (*infeasible) = FALSE;
    5447
    5448 SCIPinfoMessage(set->scip, NULL, "Benders' decomposition: a bendersSolvesub or bendersSolvesubconvex has been "
    5449 "implemented. SCIPbendersComputeSubproblemLowerbound can not be executed.\n");
    5450 SCIPinfoMessage(set->scip, NULL, "Set the auxiliary variable lower bound by calling "
    5451 "SCIPbendersUpdateSubproblemLowerbound in bendersCreatesub. The auxiliary variable %d will remain as %g\n",
    5452 probnumber, (*lowerbound));
    5453
    5454 return SCIP_OKAY;
    5455 }
    5456 else
    5457 {
    5458 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Computing a lower bound for"
    5459 " subproblem %d\n", probnumber);
    5460 }
    5461
    5462 /* getting the subproblem to evaluate */
    5463 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5464
    5465 (*lowerbound) = -SCIPinfinity(subproblem);
    5466 (*infeasible) = FALSE;
    5467
    5468 SCIP_CALL( SCIPgetIntParam(subproblem, "display/verblevel", &verblevel) );
    5469 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
    5470#ifdef SCIP_MOREDEBUG
    5471 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_HIGH) );
    5472#endif
    5473
    5474 /* copying memory and time limits */
    5475 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &timelimit) );
    5476 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &memorylimit) );
    5477 SCIP_CALL( copyMemoryAndTimeLimits(set->scip, subproblem) );
    5478
    5479 /* if the subproblem is independent, then the default SCIP settings are used. Otherwise, only the root node is solved
    5480 * to compute a lower bound on the subproblem
    5481 */
    5482 SCIP_CALL( SCIPgetLongintParam(subproblem, "limits/totalnodes", &totalnodes) );
    5483 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &disablecutoff) );
    5484 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
    5485 {
    5486 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", 1LL) );
    5487 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
    5488 }
    5489
    5490 /* if the subproblem not independent and is convex, then the probing LP is solved. Otherwise, the MIP is solved */
    5491 dualbound = -SCIPinfinity(subproblem);
    5493 {
    5494 SCIP_Bool solvenlp = FALSE;
    5495
    5496 assert(SCIPisLPConstructed(subproblem) || SCIPisNLPConstructed(subproblem));
    5497
    5498 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
    5500 solvenlp = TRUE;
    5501
    5502 SCIP_CALL( SCIPstartProbing(subproblem) );
    5503 if( solvenlp )
    5504 {
    5505 SCIP_NLPSOLSTAT nlpsolstat;
    5506 SCIP_NLPTERMSTAT nlptermstat;
    5507
    5508 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
    5509
    5510 nlpsolstat = SCIPgetNLPSolstat(subproblem);
    5511 nlptermstat = SCIPgetNLPTermstat(subproblem);
    5512 SCIPdebugMsg(set->scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
    5513
    5514 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
    5515 {
    5516 /* trust infeasible only if terminated "okay" */
    5517 (*infeasible) = TRUE;
    5518 }
    5519 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT )
    5520 {
    5521 dualbound = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
    5522 }
    5523 }
    5524 else
    5525 {
    5526 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
    5527
    5528 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_INFEASIBLE )
    5529 (*infeasible) = TRUE;
    5530 else if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL )
    5531 dualbound = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(set->scip);
    5532 }
    5533 }
    5534 else
    5535 {
    5536 SCIP_EVENTHDLRDATA* eventhdlrdata;
    5537
    5538 /* if the subproblem is not convex, then event handlers have been added to interrupt the solve. These must be
    5539 * disabled
    5540 */
    5542 eventhdlrdata->solvecip = TRUE;
    5543
    5544 SCIP_CALL( SCIPsolve(subproblem) );
    5545
    5546 if( SCIPgetStatus(subproblem) == SCIP_STATUS_INFEASIBLE )
    5547 (*infeasible) = TRUE;
    5548 else
    5549 dualbound = SCIPgetDualbound(subproblem);
    5550 }
    5551
    5552 /* getting the lower bound value */
    5553 (*lowerbound) = dualbound;
    5554
    5555 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
    5556 {
    5557 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", totalnodes) );
    5558 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", disablecutoff) );
    5559 }
    5560 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", verblevel) );
    5561 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", memorylimit) );
    5562 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", timelimit) );
    5563
    5564 /* the subproblem must be freed so that it is reset for the subsequent Benders' decomposition solves. If the
    5565 * subproblems are independent, they are not freed. SCIPfreeBendersSubproblem must still be called, but in this
    5566 * function the independent subproblems are not freed. However, they will still be freed at the end of the
    5567 * solving process for the master problem.
    5568 */
    5569 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
    5570
    5571 return SCIP_OKAY;
    5572}
    5573
    5574/** Merges a subproblem into the master problem. This process just adds a copy of the subproblem variables and
    5575 * constraints to the master problem, but keeps the subproblem stored in the Benders' decomposition data structure. The reason for
    5576 * keeping the subproblem available is for when it is queried for solutions after the problem is solved.
    5577 *
    5578 * Once the subproblem is merged into the master problem, then the subproblem is flagged as disabled. This means that
    5579 * it will not be solved in the subsequent subproblem solving loops.
    5580 *
    5581 * The associated auxiliary variables are kept in the master problem. The objective function of the merged subproblem
    5582 * is added as an underestimator constraint.
    5583 */
    5585 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5586 SCIP_SET* set, /**< global SCIP settings */
    5587 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of subproblem variables corresponding
    5588 * to the newly created master variables, or NULL */
    5589 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of subproblem constraints to the
    5590 * corresponding newly created constraints, or NULL */
    5591 int probnumber /**< the number of the subproblem that will be merged into the master problem*/
    5592 )
    5593{
    5594 SCIP* subproblem;
    5595 SCIP_HASHMAP* localvarmap;
    5596 SCIP_HASHMAP* localconsmap;
    5597 SCIP_VAR** vars;
    5598 SCIP_VAR* auxiliaryvar;
    5599 SCIP_CONS** conss;
    5600 SCIP_CONS* objcons;
    5601 int nvars;
    5602 int nconss;
    5603 int i;
    5604 SCIP_Bool uselocalvarmap;
    5605 SCIP_Bool uselocalconsmap;
    5606 char varname[SCIP_MAXSTRLEN];
    5607 char consname[SCIP_MAXSTRLEN];
    5608 const char* origvarname;
    5609
    5610 assert(benders != NULL);
    5611 assert(set != NULL);
    5612 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    5613
    5614 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " Benders' decomposition: Infeasibility of subproblem %d can't "
    5615 "be resolved. Subproblem %d is being merged into the master problem.\n", probnumber, probnumber);
    5616
    5617 /* freeing the subproblem because it will be flagged as independent. Since the subproblem is flagged as independent,
    5618 * it will no longer be solved or freed within the solving loop.
    5619 */
    5620 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
    5621
    5622 subproblem = SCIPbendersSubproblem(benders, probnumber);
    5623
    5624 uselocalvarmap = (varmap == NULL);
    5625 uselocalconsmap = (consmap == NULL);
    5626
    5627 if( uselocalvarmap )
    5628 {
    5629 /* create the variable mapping hash map */
    5630 SCIP_CALL( SCIPhashmapCreate(&localvarmap, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
    5631 }
    5632 else
    5633 localvarmap = varmap;
    5634
    5635 if( uselocalconsmap )
    5636 {
    5637 /* create the constraint mapping hash map */
    5638 SCIP_CALL( SCIPhashmapCreate(&localconsmap, SCIPblkmem(set->scip), SCIPgetNConss(subproblem)) );
    5639 }
    5640 else
    5641 localconsmap = consmap;
    5642
    5643 /* retrieving the subproblem variable to build a subproblem mapping */
    5644 vars = SCIPgetVars(subproblem);
    5645 nvars = SCIPgetNVars(subproblem);
    5646
    5647 /* creating the objective function constraint that will be added to the master problem */
    5648 /* setting the name of the transferred cut */
    5649 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "objectivecons_%d", probnumber );
    5650 SCIP_CALL( SCIPcreateConsBasicLinear(set->scip, &objcons, consname, 0, NULL, NULL, -SCIPsetInfinity(set), 0.0) );
    5651 SCIP_CALL( SCIPsetConsRemovable(set->scip, objcons, TRUE) );
    5652
    5653 for( i = 0; i < nvars; i++ )
    5654 {
    5655 SCIP_VAR* mastervar = NULL;
    5656 SCIP_Bool releasevar = FALSE;
    5657
    5658 SCIP_CALL( SCIPgetBendersMasterVar(set->scip, benders, vars[i], &mastervar) );
    5659
    5660 /* if the master problem variable is not NULL, then there is a corresponding variable in the master problem for
    5661 * the given subproblem variable. In this case, the variable is added to the hashmap.
    5662 */
    5663 if( mastervar == NULL )
    5664 {
    5665 SCIP_VAR* origvar;
    5666 SCIP_Real scalar;
    5667 SCIP_Real constant;
    5668
    5669 /* This is following the same process as in createVariableMappings. The original variable is used to map
    5670 * between the subproblem and the master problem
    5671 */
    5672 origvar = vars[i];
    5673 scalar = 1.0;
    5674 constant = 0.0;
    5675 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
    5676
    5677 /* retrieving the var name */
    5678 origvarname = SCIPvarGetName(origvar);
    5679 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", origvarname);
    5680
    5681 /* creating and adding the variable to the Benders' decomposition master problem */
    5682 SCIP_CALL( SCIPcreateVarBasic(set->scip, &mastervar, varname, SCIPvarGetLbOriginal(origvar),
    5683 SCIPvarGetUbOriginal(origvar), 0.0, SCIPvarGetType(origvar)) );
    5684
    5685 /* adding the variable to the master problem */
    5686 SCIP_CALL( SCIPaddVar(set->scip, mastervar) );
    5687
    5688 /* adds the variable to the objective function constraint */
    5689 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, mastervar, SCIPvarGetObj(origvar)) );
    5690
    5691 /* the variable must be released */
    5692 releasevar = TRUE;
    5693 }
    5694
    5695 /* creating the mapping betwen the subproblem var and the master var for the constraint copying */
    5696 SCIP_CALL( SCIPhashmapInsert(localvarmap, vars[i], mastervar) );
    5697
    5698 /* releasing the variable */
    5699 if( releasevar )
    5700 {
    5701 SCIP_CALL( SCIPreleaseVar(set->scip, &mastervar) );
    5702 }
    5703 }
    5704
    5705 /* getting the constraints from the subproblem that will be added to the master problem */
    5706 conss = SCIPgetConss(subproblem);
    5707 nconss = SCIPgetNConss(subproblem);
    5708
    5709 /* getting a copy of all constraints and adding it to the master problem */
    5710 for( i = 0; i < nconss; i++ )
    5711 {
    5712 SCIP_CONS* targetcons;
    5713 SCIP_Bool initial;
    5714 SCIP_Bool valid;
    5715
    5716 /* NOTE: adding all subproblem constraints appears to cause an error when resolving the LP, which results in the
    5717 * current incumbent being reported as optimal. To avoid this, only half of the subproblem constraints are added
    5718 * the master problem. The remaining half are marked as lazy and are separated as required.
    5719 */
    5720 initial = (i < nconss/2);
    5721
    5722 SCIP_CALL( SCIPgetConsCopy(subproblem, set->scip, conss[i], &targetcons, SCIPconsGetHdlr(conss[i]),
    5723 localvarmap, localconsmap, NULL, initial, SCIPconsIsSeparated(conss[i]),
    5724 SCIPconsIsEnforced(conss[i]), SCIPconsIsChecked(conss[i]), SCIPconsIsPropagated(conss[i]), FALSE,
    5725 SCIPconsIsModifiable(conss[i]), SCIPconsIsDynamic(conss[i]), SCIPconsIsRemovable(conss[i]),
    5726 FALSE, TRUE, &valid) );
    5727 assert(SCIPconsIsInitial(conss[i]));
    5728 assert(valid);
    5729
    5730 SCIP_CALL( SCIPaddCons(set->scip, targetcons) );
    5731
    5732 SCIP_CALL( SCIPreleaseCons(set->scip, &targetcons) );
    5733 }
    5734
    5735 /* freeing the hashmaps */
    5736 if( uselocalvarmap )
    5737 {
    5738 /* free hash map */
    5739 SCIPhashmapFree(&localvarmap);
    5740 }
    5741
    5742 if( uselocalconsmap )
    5743 {
    5744 /* free hash map */
    5745 SCIPhashmapFree(&localconsmap);
    5746 }
    5747
    5748 /* adding the auxiliary variable to the objective constraint */
    5749 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    5750 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, auxiliaryvar, -1.0) );
    5751
    5752 /* adding the objective function constraint to the master problem */
    5753 SCIP_CALL( SCIPaddCons(set->scip, objcons) );
    5754
    5755 SCIP_CALL( SCIPreleaseCons(set->scip, &objcons) );
    5756
    5757 /* the merged subproblem is no longer solved. This is indicated by setting the subproblem as disabled. The
    5758 * subproblem still exists, but it is not solved in the solving loop.
    5759 */
    5760 SCIPbendersSetSubproblemEnabled(benders, probnumber, FALSE);
    5761
    5762 return SCIP_OKAY;
    5763}
    5764
    5765/** Returns the corresponding master or subproblem variable for the given variable.
    5766 * This provides a call back for the variable mapping between the master and subproblems. */
    5768 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5769 SCIP_SET* set, /**< global SCIP settings */
    5770 SCIP_VAR* var, /**< the variable for which the corresponding variable is desired */
    5771 SCIP_VAR** mappedvar, /**< the variable that is mapped to var */
    5772 int probnumber /**< the problem number for the desired variable, -1 for the master problem */
    5773 )
    5774{
    5775 assert(benders != NULL);
    5776 assert(set != NULL);
    5777 assert(var != NULL);
    5778 assert(mappedvar != NULL);
    5779 assert(benders->bendersgetvar != NULL);
    5780
    5781 (*mappedvar) = NULL;
    5782
    5783 /* if the variable name matches the auxiliary variable, then the master variable is returned as NULL */
    5784 if( strstr(SCIPvarGetName(var), AUXILIARYVAR_NAME) != NULL )
    5785 return SCIP_OKAY;
    5786
    5787 SCIP_CALL( benders->bendersgetvar(set->scip, benders, var, mappedvar, probnumber) );
    5788
    5789 return SCIP_OKAY;
    5790}
    5792/** gets user data of Benders' decomposition */
    5794 SCIP_BENDERS* benders /**< Benders' decomposition */
    5795 )
    5796{
    5797 assert(benders != NULL);
    5798
    5799 return benders->bendersdata;
    5800}
    5802/** sets user data of Benders' decomposition; user has to free old data in advance! */
    5804 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5805 SCIP_BENDERSDATA* bendersdata /**< new Benders' decomposition user data */
    5806 )
    5807{
    5808 assert(benders != NULL);
    5809
    5810 benders->bendersdata = bendersdata;
    5811}
    5813/** sets copy callback of Benders' decomposition */
    5815 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5816 SCIP_DECL_BENDERSCOPY ((*benderscopy)) /**< copy callback of Benders' decomposition */
    5817 )
    5818{
    5819 assert(benders != NULL);
    5820
    5821 benders->benderscopy = benderscopy;
    5822}
    5824/** sets destructor callback of Benders' decomposition */
    5826 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5827 SCIP_DECL_BENDERSFREE ((*bendersfree)) /**< destructor of Benders' decomposition */
    5828 )
    5829{
    5830 assert(benders != NULL);
    5831
    5832 benders->bendersfree = bendersfree;
    5833}
    5835/** sets initialization callback of Benders' decomposition */
    5837 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5838 SCIP_DECL_BENDERSINIT((*bendersinit)) /**< initialize the Benders' decomposition */
    5839 )
    5840{
    5841 assert(benders != NULL);
    5842
    5843 benders->bendersinit = bendersinit;
    5844}
    5846/** sets deinitialization callback of Benders' decomposition */
    5848 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5849 SCIP_DECL_BENDERSEXIT((*bendersexit)) /**< deinitialize the Benders' decomposition */
    5850 )
    5851{
    5852 assert(benders != NULL);
    5853
    5854 benders->bendersexit = bendersexit;
    5855}
    5857/** sets presolving initialization callback of Benders' decomposition */
    5859 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5860 SCIP_DECL_BENDERSINITPRE((*bendersinitpre))/**< initialize presolving for Benders' decomposition */
    5861 )
    5862{
    5863 assert(benders != NULL);
    5864
    5865 benders->bendersinitpre = bendersinitpre;
    5866}
    5868/** sets presolving deinitialization callback of Benders' decomposition */
    5870 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5871 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre))/**< deinitialize presolving for Benders' decomposition */
    5872 )
    5873{
    5874 assert(benders != NULL);
    5875
    5876 benders->bendersexitpre = bendersexitpre;
    5877}
    5879/** sets solving process initialization callback of Benders' decomposition */
    5881 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5882 SCIP_DECL_BENDERSINITSOL((*bendersinitsol))/**< solving process initialization callback of Benders' decomposition */
    5883 )
    5884{
    5885 assert(benders != NULL);
    5886
    5887 benders->bendersinitsol = bendersinitsol;
    5888}
    5890/** sets solving process deinitialization callback of Benders' decomposition */
    5892 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5893 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol))/**< solving process deinitialization callback of Benders' decomposition */
    5894 )
    5895{
    5896 assert(benders != NULL);
    5897
    5898 benders->bendersexitsol = bendersexitsol;
    5899}
    5901/** sets the pre subproblem solve callback of Benders' decomposition */
    5903 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5904 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve))/**< called prior to the subproblem solving loop */
    5905 )
    5906{
    5907 assert(benders != NULL);
    5908
    5909 benders->benderspresubsolve = benderspresubsolve;
    5910}
    5912/** sets convex solve callback of Benders' decomposition */
    5914 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5915 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex))/**< solving method for the convex Benders' decomposition subproblem */
    5916 )
    5917{
    5918 assert(benders != NULL);
    5919
    5920 benders->benderssolvesubconvex = benderssolvesubconvex;
    5921}
    5923/** sets solve callback of Benders' decomposition */
    5925 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5926 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub))/**< solving method for a Benders' decomposition subproblem */
    5927 )
    5928{
    5929 assert(benders != NULL);
    5930
    5931 benders->benderssolvesub = benderssolvesub;
    5932}
    5934/** sets post-solve callback of Benders' decomposition */
    5936 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5937 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve))/**< solving process deinitialization callback of Benders' decomposition */
    5938 )
    5939{
    5940 assert(benders != NULL);
    5941
    5942 benders->benderspostsolve = benderspostsolve;
    5943}
    5945/** sets post-solve callback of Benders' decomposition */
    5947 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5948 SCIP_DECL_SORTPTRCOMP((*benderssubcomp)) /**< a comparator for defining the solving order of the subproblems */
    5949 )
    5950{
    5951 assert(benders != NULL);
    5952
    5953 benders->benderssubcomp = benderssubcomp;
    5954}
    5956/** sets free subproblem callback of Benders' decomposition */
    5958 SCIP_BENDERS* benders, /**< Benders' decomposition */
    5959 SCIP_DECL_BENDERSFREESUB((*bendersfreesub))/**< the freeing callback for the subproblem */
    5960 )
    5961{
    5962 assert(benders != NULL);
    5963
    5964 benders->bendersfreesub = bendersfreesub;
    5965}
    5967/** gets name of Benders' decomposition */
    5968const char* SCIPbendersGetName(
    5969 SCIP_BENDERS* benders /**< Benders' decomposition */
    5970 )
    5971{
    5972 assert(benders != NULL);
    5973
    5974 return benders->name;
    5975}
    5977/** gets description of Benders' decomposition */
    5978const char* SCIPbendersGetDesc(
    5979 SCIP_BENDERS* benders /**< Benders' decomposition */
    5980 )
    5981{
    5982 assert(benders != NULL);
    5983
    5984 return benders->desc;
    5985}
    5987/** gets priority of Benders' decomposition */
    5989 SCIP_BENDERS* benders /**< Benders' decomposition */
    5990 )
    5991{
    5992 assert(benders != NULL);
    5993
    5994 return benders->priority;
    5995}
    5997/** sets priority of Benders' decomposition */
    5999 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6000 SCIP_SET* set, /**< global SCIP settings */
    6001 int priority /**< new priority of the Benders' decomposition */
    6002 )
    6003{
    6004 assert(benders != NULL);
    6005 assert(set != NULL);
    6006
    6007 benders->priority = priority;
    6008 set->benderssorted = FALSE;
    6009}
    6011/** gets the number of subproblems for the Benders' decomposition */
    6013 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
    6014 )
    6015{
    6016 assert(benders != NULL);
    6017
    6018 return benders->nsubproblems;
    6019}
    6021/** returns the SCIP instance for a given subproblem */
    6023 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
    6024 int probnumber /**< the subproblem number */
    6025 )
    6026{
    6027 assert(benders != NULL);
    6028 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
    6029
    6030 return benders->subproblems[probnumber];
    6031}
    6033/** gets the number of times, the Benders' decomposition was called and tried to find a variable with negative reduced costs */
    6035 SCIP_BENDERS* benders /**< Benders' decomposition */
    6036 )
    6037{
    6038 assert(benders != NULL);
    6039
    6040 return benders->ncalls;
    6041}
    6043/** gets the number of optimality cuts found by the collection of Benders' decomposition subproblems */
    6045 SCIP_BENDERS* benders /**< Benders' decomposition */
    6046 )
    6047{
    6048 assert(benders != NULL);
    6049
    6050 return benders->ncutsfound;
    6051}
    6053/** gets the number of cuts found from the strengthening round */
    6055 SCIP_BENDERS* benders /**< Benders' decomposition */
    6056 )
    6057{
    6058 assert(benders != NULL);
    6059
    6060 return benders->nstrengthencuts;
    6061}
    6063/** gets the number of calls to the strengthening round */
    6065 SCIP_BENDERS* benders /**< Benders' decomposition */
    6066 )
    6067{
    6068 assert(benders != NULL);
    6069
    6070 return benders->nstrengthencalls;
    6071}
    6073/** gets the number of calls to the strengthening round that fail */
    6075 SCIP_BENDERS* benders /**< Benders' decomposition */
    6076 )
    6077{
    6078 assert(benders != NULL);
    6079
    6080 return benders->nstrengthenfails;
    6081}
    6083/** gets time in seconds used in this Benders' decomposition for setting up for next stages */
    6085 SCIP_BENDERS* benders /**< Benders' decomposition */
    6086 )
    6087{
    6088 assert(benders != NULL);
    6089
    6090 return SCIPclockGetTime(benders->setuptime);
    6091}
    6093/** gets time in seconds used in this Benders' decomposition */
    6095 SCIP_BENDERS* benders /**< Benders' decomposition */
    6096 )
    6097{
    6098 assert(benders != NULL);
    6099
    6100 return SCIPclockGetTime(benders->bendersclock);
    6101}
    6103/** enables or disables all clocks of the Benders' decomposition, depending on the value of the flag */
    6105 SCIP_BENDERS* benders, /**< the Benders' decomposition for which all clocks should be enabled or disabled */
    6106 SCIP_Bool enable /**< should the clocks of the Benders' decomposition be enabled? */
    6107 )
    6108{
    6109 assert(benders != NULL);
    6110
    6111 SCIPclockEnableOrDisable(benders->setuptime, enable);
    6112 SCIPclockEnableOrDisable(benders->bendersclock, enable);
    6113}
    6115/** is Benders' decomposition initialized? */
    6117 SCIP_BENDERS* benders /**< Benders' decomposition */
    6118 )
    6119{
    6120 assert(benders != NULL);
    6121
    6122 return benders->initialized;
    6123}
    6125/** Are Benders' cuts generated from the LP solutions? */
    6127 SCIP_BENDERS* benders /**< Benders' decomposition */
    6128 )
    6129{
    6130 assert(benders != NULL);
    6131
    6132 return benders->cutlp;
    6133}
    6135/** Are Benders' cuts generated from the pseudo solutions? */
    6137 SCIP_BENDERS* benders /**< Benders' decomposition */
    6138 )
    6139{
    6140 assert(benders != NULL);
    6141
    6142 return benders->cutpseudo;
    6143}
    6145/** Are Benders' cuts generated from the relaxation solutions? */
    6147 SCIP_BENDERS* benders /**< Benders' decomposition */
    6148 )
    6149{
    6150 assert(benders != NULL);
    6151
    6152 return benders->cutrelax;
    6153}
    6155/** should this Benders' use the auxiliary variables from the highest priority Benders' */
    6157 SCIP_BENDERS* benders /**< Benders' decomposition */
    6158 )
    6159{
    6160 assert(benders != NULL);
    6161
    6162 return benders->shareauxvars;
    6163}
    6164
    6165/** adds a subproblem to the Benders' decomposition data. If a custom subproblem solving method is used, then the
    6166 * subproblem pointer can be set to NULL
    6167 */
    6169 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6170 SCIP* subproblem /**< subproblem to be added to the data storage, can be NULL */
    6171 )
    6172{
    6173 assert(benders != NULL);
    6174 assert(benders->naddedsubprobs + 1 <= benders->nsubproblems);
    6175
    6176 /* if the subproblem pointer is NULL, then the subproblem solving callback functions must be set. */
    6177 if( subproblem == NULL && (!benders->benderssolvesubconvex || !benders->benderssolvesub) )
    6178 {
    6179 SCIPerrorMessage("The subproblem can only be set to NULL if both bendersSolvesubconvex%s and bendersSolvesub%s "
    6180 "are defined.\n", benders->name, benders->name);
    6181 return SCIP_ERROR;
    6182 }
    6183
    6184 benders->subproblems[benders->naddedsubprobs] = subproblem;
    6185
    6186 benders->naddedsubprobs++;
    6187
    6188 return SCIP_OKAY;
    6189}
    6191/** removes the subproblems from the Benders' decomposition data */
    6193 SCIP_BENDERS* benders /**< Benders' decomposition */
    6194 )
    6195{
    6196 assert(benders != NULL);
    6197 assert(benders->subproblems != NULL);
    6198
    6199 BMSclearMemoryArray(&benders->subproblems, benders->naddedsubprobs);
    6200 benders->naddedsubprobs = 0;
    6201}
    6203/** returns the main auxiliary variable that is used the subproblem objective function. */
    6205 SCIP_BENDERS* benders /**< Benders' decomposition */
    6206 )
    6207{
    6208 assert(benders != NULL);
    6209
    6210 return benders->masterauxvar;
    6211}
    6213/** returns the auxiliary variable for the given subproblem */
    6215 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6216 int probnumber /**< the subproblem number */
    6217 )
    6218{
    6219 assert(benders != NULL);
    6220 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6221
    6222 return benders->auxiliaryvars[probnumber];
    6223}
    6225/** returns all auxiliary variables */
    6227 SCIP_BENDERS* benders /**< Benders' decomposition */
    6228 )
    6229{
    6230 assert(benders != NULL);
    6231
    6232 return benders->auxiliaryvars;
    6233}
    6235/** returns the subproblem master variables for the given subproblem */
    6237 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6238 int probnumber /**< the subproblem number */
    6239 )
    6240{
    6241 assert(benders != NULL);
    6242 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6243
    6244 return benders->submastervars[probnumber];
    6245}
    6247/** returns the number of subproblem master variables for the given subproblem */
    6249 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6250 int probnumber /**< the subproblem number */
    6251 )
    6252{
    6253 assert(benders != NULL);
    6254 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6255
    6256 return benders->nsubmastervars[probnumber];
    6257}
    6259/** returns the subproblem master variable data for the given subproblem */
    6261 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6262 int probnumber, /**< the subproblem number */
    6263 SCIP_VAR*** vars, /**< pointer to store the master variables, or NULL */
    6264 int* nvars, /**< the number of master problem variables, or NULL */
    6265 int* nbinvars, /**< the number of binary master problem variables, or NULL */
    6266 int* nintvars /**< the number of integer master problem variables, or NULL */
    6267 )
    6268{
    6269 assert(benders != NULL);
    6270 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6271
    6272 if( vars != NULL )
    6273 (*vars) = benders->submastervars[probnumber];
    6274
    6275 if( nvars != NULL )
    6276 (*nvars) = benders->nsubmastervars[probnumber];
    6277
    6278 if( nbinvars != NULL )
    6279 (*nbinvars) = benders->nsubmasterbinvars[probnumber];
    6280
    6281 if( nintvars != NULL )
    6282 (*nintvars) = benders->nsubmasterintvars[probnumber];
    6283}
    6285/** stores the objective function value of the subproblem for use in cut generation */
    6287 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
    6288 int probnumber, /**< the subproblem number */
    6289 SCIP_Real objval /**< the objective function value for the subproblem */
    6290 )
    6291{
    6292 assert(benders != NULL);
    6293 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6294
    6295 /* updating the best objval */
    6296 if( objval < benders->bestsubprobobjval[probnumber] )
    6297 benders->bestsubprobobjval[probnumber] = objval;
    6298
    6299 benders->subprobobjval[probnumber] = objval;
    6300}
    6302/** returns the objective function value of the subproblem for use in cut generation */
    6304 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6305 int probnumber /**< the subproblem number */
    6306 )
    6307{
    6308 assert(benders != NULL);
    6309 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6310
    6311 return benders->subprobobjval[probnumber];
    6312}
    6314/** returns whether the solution has non-zero slack variables */
    6316 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6317 SCIP_Bool* activeslack /**< flag to indicate whether a slack variable is active */
    6318 )
    6319{
    6320 SCIP* subproblem;
    6321 SCIP_SOL* sol;
    6322 SCIP_VAR** vars;
    6323 int nsubproblems;
    6324 int nvars;
    6325 int ncontvars;
    6326 int i;
    6327 int j;
    6328 SCIP_Bool freesol = FALSE;
    6329
    6330 assert(benders != NULL);
    6331 assert(activeslack != NULL);
    6332
    6333 (*activeslack) = FALSE;
    6334
    6335 /* if the slack variables have not been added, then we can immediately state that no slack variables are active */
    6336 if( !benders->feasibilityphase )
    6337 {
    6338 return SCIP_OKAY;
    6339 }
    6340
    6341 nsubproblems = SCIPbendersGetNSubproblems(benders);
    6342
    6343 /* checking all subproblems for active slack variables */
    6344 for( i = 0; i < nsubproblems && !(*activeslack); i++ )
    6345 {
    6346 subproblem = SCIPbendersSubproblem(benders, i);
    6347
    6348 /* if the subproblem is convex and an NLP, then we need to create the NLP solution. Otherwise, the solution can be
    6349 * retrieved from the LP or CIP.
    6350 */
    6352 {
    6353 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0 )
    6354 {
    6355 SCIP_CALL( SCIPcreateNLPSol(subproblem, &sol, NULL) );
    6356 }
    6357 else
    6358 {
    6359 SCIP_CALL( SCIPcreateCurrentSol(subproblem, &sol, NULL) );
    6360 }
    6361 freesol = TRUE;
    6362 }
    6363 else
    6364 sol = SCIPgetBestSol(subproblem);
    6365
    6366 /* getting the variable data. Only the continuous variables are important. */
    6367 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, &ncontvars) );
    6368
    6369 /* checking all slack variables for non-zero solution values */
    6370 for( j = nvars - 1; j >= nvars - ncontvars; j-- )
    6371 {
    6372 if( strstr(SCIPvarGetName(vars[j]), SLACKVAR_NAME) != NULL )
    6373 {
    6374 if( SCIPisPositive(subproblem, SCIPgetSolVal(subproblem, sol, vars[j])) )
    6375 {
    6376 (*activeslack) = TRUE;
    6377 break;
    6378 }
    6379 }
    6380 }
    6381
    6382 /* freeing the LP and NLP solutions */
    6383 if( freesol )
    6384 {
    6385 SCIP_CALL( SCIPfreeSol(subproblem, &sol) );
    6386 }
    6387 }
    6388
    6389 return SCIP_OKAY;
    6390}
    6391
    6392/** sets the subproblem type
    6393 *
    6394 * The subproblem types are:
    6395 * - Convex constraints with continuous variables
    6396 * - Convex constraints with discrete variables
    6397 * - Non-convex constraints with continuous variables
    6398 * - Non-convex constraints with discrete variables
    6399 */
    6401 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6402 int probnumber, /**< the subproblem number */
    6403 SCIP_BENDERSSUBTYPE subprobtype /**< the subproblem type */
    6404 )
    6405{
    6406 assert(benders != NULL);
    6407 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6408
    6409 if( subprobtype == SCIP_BENDERSSUBTYPE_CONVEXCONT
    6410 && benders->subprobtype[probnumber] != SCIP_BENDERSSUBTYPE_CONVEXCONT )
    6411 benders->nconvexsubprobs++;
    6412 else if( subprobtype != SCIP_BENDERSSUBTYPE_CONVEXCONT
    6413 && benders->subprobtype[probnumber] == SCIP_BENDERSSUBTYPE_CONVEXCONT )
    6414 benders->nconvexsubprobs--;
    6415
    6416 benders->subprobtype[probnumber] = subprobtype;
    6417
    6418 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
    6419}
    6420
    6421/** returns the type of the subproblem
    6422 *
    6423 * This type is used to determine whether the duals of the problem can be used to generate cuts
    6424 */
    6426 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6427 int probnumber /**< the subproblem number */
    6428 )
    6429{
    6430 assert(benders != NULL);
    6431 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6432
    6433 return benders->subprobtype[probnumber];
    6434}
    6435
    6436/** sets the flag indicating whether a subproblem is convex
    6437 *
    6438 * It is possible that this can change during the solving process. One example is when the three-phase method is
    6439 * employed, where the first phase solves the convex relaxation of both the master and subproblems, the second phase
    6440 * reintroduces the integrality constraints to the master problem and the third phase then reintroduces integrality
    6441 * constraints to the subproblems.
    6442 */
    6444 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6445 int probnumber, /**< the subproblem number */
    6446 SCIP_Bool isconvex /**< flag to indicate whether the subproblem is convex */
    6447 )
    6448{
    6449 assert(benders != NULL);
    6450 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6451
    6452 if( isconvex && !benders->subprobisconvex[probnumber] )
    6453 benders->nconvexsubprobs++;
    6454 else if( !isconvex && benders->subprobisconvex[probnumber] )
    6455 benders->nconvexsubprobs--;
    6456
    6457 benders->subprobisconvex[probnumber] = isconvex;
    6458
    6459 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
    6460}
    6461
    6462/** returns whether the subproblem is convex
    6463 *
    6464 * This means that the dual solution can be used to generate cuts.
    6465 */
    6467 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6468 int probnumber /**< the subproblem number */
    6469 )
    6470{
    6471 assert(benders != NULL);
    6472 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6473
    6474 return benders->subprobisconvex[probnumber];
    6475}
    6477/** returns the number of subproblems that are convex */
    6479 SCIP_BENDERS* benders /**< Benders' decomposition */
    6480 )
    6481{
    6482 assert(benders != NULL);
    6483
    6484 return benders->nconvexsubprobs;
    6485}
    6487/** sets the flag indicating whether a subproblem contains non-linear constraints */
    6489 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6490 int probnumber, /**< the subproblem number */
    6491 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
    6492 )
    6493{
    6494 assert(benders != NULL);
    6495 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6496
    6497 if( isnonlinear && !benders->subprobisnonlinear[probnumber] )
    6498 benders->nnonlinearsubprobs++;
    6499 else if( !isnonlinear && benders->subprobisnonlinear[probnumber] )
    6500 benders->nnonlinearsubprobs--;
    6501
    6502 benders->subprobisnonlinear[probnumber] = isnonlinear;
    6503
    6504 assert(benders->nnonlinearsubprobs >= 0 && benders->nnonlinearsubprobs <= benders->nsubproblems);
    6505}
    6507/** returns whether the subproblem contains non-linear constraints. */
    6509 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6510 int probnumber /**< the subproblem number */
    6511 )
    6512{
    6513 assert(benders != NULL);
    6514 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6515
    6516 return benders->subprobisnonlinear[probnumber];
    6517}
    6519/** returns the number of subproblems that contain non-linear constraints */
    6521 SCIP_BENDERS* benders /**< Benders' decomposition */
    6522 )
    6523{
    6524 assert(benders != NULL);
    6525
    6526 return benders->nnonlinearsubprobs;
    6527}
    6529/** sets the flag indicating whether the master problem contains non-linear constraints */
    6531 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6532 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
    6533 )
    6534{
    6535 assert(benders != NULL);
    6536
    6537 benders->masterisnonlinear = isnonlinear;
    6538}
    6540/** returns whether the master problem contains non-linear constraints. */
    6542 SCIP_BENDERS* benders /**< Benders' decomposition */
    6543 )
    6544{
    6545 assert(benders != NULL);
    6546
    6547 return benders->masterisnonlinear;
    6548}
    6550/** returns the flag indicating that Benders' decomposition is in a cut strengthening round */
    6552 SCIP_BENDERS* benders /**< Benders' decomposition */
    6553 )
    6554{
    6555 assert(benders != NULL);
    6556
    6557 return benders->strengthenround;
    6558}
    6559
    6560/** sets the flag to indicate that at least one subproblem is always infeasible
    6561 * NOTE: this is without any variable fixing being performed
    6562 */
    6564 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6565 SCIP_SET* set /**< global SCIP settings */
    6566 )
    6567{
    6568 assert(benders != NULL);
    6569 assert(set != NULL);
    6570
    6571 if( SCIPgetDepth(set->scip) <= 0 )
    6572 benders->subprobsinfeasible = TRUE;
    6573}
    6574
    6575/** returns whether at least one of the subproblems has been identified as infeasible.
    6576 * NOTE: this is without any variable fixing being performed
    6577 */
    6579 SCIP_BENDERS* benders /**< Benders' decomposition */
    6580 )
    6581{
    6582 assert(benders != NULL);
    6583
    6584 return benders->subprobsinfeasible;
    6585}
    6587/** changes all of the master problem variables in the given subproblem to continuous. */
    6589 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6590 SCIP_SET* set, /**< global SCIP settings */
    6591 int probnumber /**< the subproblem number */
    6592 )
    6593{
    6594 SCIP* subproblem;
    6595 SCIP_VAR** vars;
    6596 int nbinvars;
    6597 int nintvars;
    6598 int nimplvars;
    6599 int chgvarscount;
    6600 int origintvars;
    6601 int i;
    6602 SCIP_Bool infeasible;
    6603
    6604 assert(benders != NULL);
    6605 assert(set != NULL);
    6606 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6607
    6608 subproblem = SCIPbendersSubproblem(benders, probnumber);
    6609 assert(subproblem != NULL);
    6610
    6611 /* only set the master problem variable to continuous if they have not already been changed. */
    6612 if( !SCIPbendersGetMastervarsCont(benders, probnumber) )
    6613 {
    6614 SCIP_VAR* mastervar;
    6615
    6616 /* retrieving the variable data */
    6617 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
    6618
    6619 origintvars = nbinvars + nintvars + nimplvars;
    6620
    6621 chgvarscount = 0;
    6622
    6623 /* looping over all integer variables to change the master variables to continuous */
    6624 i = 0;
    6625 while( i < nbinvars + nintvars + nimplvars )
    6626 {
    6627 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
    6628
    6629 if( SCIPvarIsIntegral(vars[i]) && mastervar != NULL )
    6630 {
    6631 /* remove integrality of the subproblem variable corresponding to mastervar */
    6632 SCIP_CALL( SCIPchgVarType(subproblem, vars[i], SCIP_VARTYPE_CONTINUOUS, &infeasible) );
    6633 assert(!infeasible);
    6634 SCIP_CALL( SCIPchgVarImplType(subproblem, vars[i], SCIP_IMPLINTTYPE_NONE, &infeasible) );
    6635 assert(!infeasible);
    6636
    6637 chgvarscount++;
    6638 SCIP_CALL( SCIPgetVarsData(subproblem, NULL, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
    6639 }
    6640 else
    6641 i++;
    6642 }
    6643
    6644 /* if all of the integer variables have been changed to continuous, then the subproblem could now be a convex
    6645 * problem. This must be checked and if TRUE, then the LP subproblem is initialised and then put into probing
    6646 * mode
    6647 */
    6648 if( chgvarscount > 0 && chgvarscount == origintvars )
    6649 {
    6650 /* checking the convexity of the subproblem */
    6651 SCIP_CALL( checkSubproblemConvexity(benders, set, probnumber) );
    6652
    6653 /* if the subproblem has convex constraints and continuous variables, then it is initialised and put into
    6654 * probing mode
    6655 */
    6657 {
    6658 SCIP_CALL( initialiseLPSubproblem(benders, set, probnumber, &infeasible) );
    6659
    6660 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
    6661 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
    6662 * during the solving process.
    6663 */
    6664 if( infeasible )
    6666 }
    6667 }
    6668
    6669 SCIP_CALL( SCIPbendersSetMastervarsCont(benders, probnumber, TRUE) );
    6670 }
    6671
    6672 return SCIP_OKAY;
    6673}
    6675/** sets the subproblem setup flag */
    6677 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6678 int probnumber, /**< the subproblem number */
    6679 SCIP_Bool issetup /**< flag to indicate whether the subproblem has been setup */
    6680 )
    6681{
    6682 assert(benders != NULL);
    6683 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6684
    6685 benders->subprobsetup[probnumber] = issetup;
    6686}
    6688/** returns the subproblem setup flag */
    6690 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6691 int probnumber /**< the subproblem number */
    6692 )
    6693{
    6694 assert(benders != NULL);
    6695 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6696
    6697 return benders->subprobsetup[probnumber];
    6698}
    6700/** sets the independent subproblem flag */
    6702 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6703 int probnumber, /**< the subproblem number */
    6704 SCIP_Bool isindep /**< flag to indicate whether the subproblem is independent */
    6705 )
    6706{
    6707 assert(benders != NULL);
    6708 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6709
    6710 /* if the user has defined solving or freeing functions, then it is not possible to declare a subproblem as
    6711 * independent. This is because declaring a subproblem as independent changes the solving loop, so it would change
    6712 * the expected behaviour of the user defined plugin. If a user calls this function, then an error will be returned.
    6713 */
    6714 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL || benders->bendersfreesub != NULL )
    6715 {
    6716 SCIPerrorMessage("The user has defined either bendersSolvesubconvex%s, bendersSolvesub%s or bendersFreesub%s. "
    6717 "Thus, it is not possible to declare the independence of a subproblem.\n", benders->name, benders->name,
    6718 benders->name);
    6719 SCIPABORT();
    6720 }
    6721 else
    6722 {
    6723 SCIP_Bool activesubprob;
    6724
    6725 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
    6726 activesubprob = subproblemIsActive(benders, probnumber);
    6727
    6728 benders->indepsubprob[probnumber] = isindep;
    6729
    6730 /* updating the activesubprobs counter */
    6731 if( activesubprob && !subproblemIsActive(benders, probnumber) )
    6732 benders->nactivesubprobs--;
    6733 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
    6734 benders->nactivesubprobs++;
    6735
    6736 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
    6737 }
    6738}
    6740/** returns whether the subproblem is independent */
    6742 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6743 int probnumber /**< the subproblem number */
    6744 )
    6745{
    6746 assert(benders != NULL);
    6747 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6748
    6749 return benders->indepsubprob[probnumber];
    6750}
    6751
    6752/** Sets whether the subproblem is enabled or disabled. A subproblem is disabled if it has been merged into the master
    6753 * problem.
    6754 */
    6756 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6757 int probnumber, /**< the subproblem number */
    6758 SCIP_Bool enabled /**< flag to indicate whether the subproblem is enabled */
    6759 )
    6760{
    6761 SCIP_Bool activesubprob;
    6762
    6763 assert(benders != NULL);
    6764 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6765
    6766 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
    6767 activesubprob = subproblemIsActive(benders, probnumber);
    6768
    6769 benders->subprobenabled[probnumber] = enabled;
    6770
    6771 /* updating the activesubprobs counter */
    6772 if( activesubprob && !subproblemIsActive(benders, probnumber) )
    6773 benders->nactivesubprobs--;
    6774 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
    6775 benders->nactivesubprobs++;
    6776
    6777 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
    6778}
    6780/** returns whether the subproblem is enabled, i.e. the subproblem is still solved in the solving loop. */
    6782 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6783 int probnumber /**< the subproblem number */
    6784 )
    6785{
    6786 assert(benders != NULL);
    6787 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6788
    6789 return benders->subprobenabled[probnumber];
    6790}
    6792/** sets a flag to indicate whether the master variables are all set to continuous */
    6794 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6795 int probnumber, /**< the subproblem number */
    6796 SCIP_Bool arecont /**< flag to indicate whether the master problem variables are continuous */
    6797 )
    6798{
    6799 assert(benders != NULL);
    6800 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6801
    6802 /* if the master variables were all continuous and now are not, then the subproblem must exit probing mode and be
    6803 * changed to non-LP subproblem */
    6804 if( benders->mastervarscont[probnumber] && !arecont )
    6805 {
    6806 SCIP_BENDERSSUBTYPE subtype;
    6807
    6808 if( SCIPinProbing(SCIPbendersSubproblem(benders, probnumber)) )
    6809 {
    6810 SCIP_CALL( SCIPendProbing(SCIPbendersSubproblem(benders, probnumber)) );
    6811 }
    6812
    6813 subtype = SCIPbendersGetSubproblemType(benders, probnumber);
    6815
    6816 if( subtype == SCIP_BENDERSSUBTYPE_CONVEXCONT )
    6818 else if( subtype == SCIP_BENDERSSUBTYPE_NONCONVEXCONT )
    6820 }
    6821
    6822 benders->mastervarscont[probnumber] = arecont;
    6823
    6824 return SCIP_OKAY;
    6825}
    6827/** returns whether the master variables are all set to continuous */
    6829 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6830 int probnumber /**< the subproblem number */
    6831 )
    6832{
    6833 assert(benders != NULL);
    6834 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6835
    6836 return benders->mastervarscont[probnumber];
    6837}
    6838
    6839/** sets the objective type for the aggregation of the Benders' decomposition subproblem objectives. This is either the
    6840 * summation of the objective values or a minimax of the objective values (such as for a makespan objective)
    6841 */
    6843 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6844 SCIP_BENDERSOBJTYPE objectivetype /**< the objective type */
    6845 )
    6846{
    6847 assert(benders != NULL);
    6848
    6849 benders->objectivetype = objectivetype;
    6850}
    6852/** returns the objective type for the aggregation of the Benders' decomposition subproblem objectives */
    6854 SCIP_BENDERS* benders /**< Benders' decomposition */
    6855 )
    6856{
    6857 assert(benders != NULL);
    6858
    6859 return benders->objectivetype;
    6860}
    6862/** returns the number of cuts that have been transferred from sub SCIPs to the master SCIP */
    6864 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
    6865 )
    6866{
    6867 assert(benders != NULL);
    6868
    6869 return benders->ntransferred;
    6870}
    6871
    6872/** updates the lower bound for the subproblem. If the lower bound is not greater than the previously stored lowerbound,
    6873 * then no update occurs.
    6874 */
    6876 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6877 int probnumber, /**< the subproblem number */
    6878 SCIP_Real lowerbound /**< the lower bound */
    6879 )
    6880{
    6881 assert(benders != NULL);
    6882 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6883
    6884 if( EPSGE(lowerbound, benders->subproblowerbound[probnumber], 1e-06) )
    6885 benders->subproblowerbound[probnumber] = lowerbound;
    6886 else
    6887 {
    6888 SCIPdebugMessage("The lowerbound %g for subproblem %d is less than the currently stored lower bound %g\n",
    6889 lowerbound, probnumber, benders->subproblowerbound[probnumber]);
    6890 }
    6891}
    6893/** returns the stored lower bound for the given subproblem */
    6895 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6896 int probnumber /**< the subproblem number */
    6897 )
    6898{
    6899 assert(benders != NULL);
    6900 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    6901
    6902 return benders->subproblowerbound[probnumber];
    6903}
    6905/** returns the number of cuts that have been added for storage */
    6907 SCIP_BENDERS* benders /**< Benders' decomposition */
    6908 )
    6909{
    6910 assert(benders != NULL);
    6911
    6912 return benders->nstoredcuts;
    6913}
    6915/** returns the cuts that have been stored for transfer */
    6917 SCIP_BENDERS* benders, /**< Benders' decomposition */
    6918 int cutidx, /**< the index for the cut data that is requested */
    6919 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
    6920 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
    6921 SCIP_Real* lhs, /**< the left hand side of the cut */
    6922 SCIP_Real* rhs, /**< the right hand side of the cut */
    6923 int* nvars /**< the number of variables with non-zero coefficients in the cut */
    6924 )
    6925{
    6926 assert(benders != NULL);
    6927 assert(vars != NULL);
    6928 assert(vals != NULL);
    6929 assert(lhs != NULL);
    6930 assert(rhs != NULL);
    6931 assert(nvars != NULL);
    6932 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
    6933
    6934 (*vars) = benders->storedcuts[cutidx]->vars;
    6935 (*vals) = benders->storedcuts[cutidx]->vals;
    6936 (*lhs) = benders->storedcuts[cutidx]->lhs;
    6937 (*rhs) = benders->storedcuts[cutidx]->rhs;
    6938 (*nvars) = benders->storedcuts[cutidx]->nvars;
    6939
    6940 return SCIP_OKAY;
    6941}
    6942
    6943/** returns the original problem data for the cuts that have been added by the Benders' cut plugin. The stored
    6944 * variables and values will populate the input vars and vals arrays. Thus, memory must be allocated for the vars and
    6945 * vals arrays
    6946 */
    6948 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
    6949 int cutidx, /**< the index for the cut data that is requested */
    6950 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
    6951 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
    6952 SCIP_Real* lhs, /**< the left hand side of the cut */
    6953 SCIP_Real* rhs, /**< the right hand side of the cut */
    6954 int* nvars, /**< the number of variables with non-zero coefficients in the cut */
    6955 int varssize /**< the available slots in the array */
    6956 )
    6957{
    6958 SCIP_VAR* origvar;
    6959 SCIP_Real scalar;
    6960 SCIP_Real constant;
    6961 int i;
    6962
    6963 assert(benders != NULL);
    6964 assert(vars != NULL);
    6965 assert(vals != NULL);
    6966 assert(lhs != NULL);
    6967 assert(rhs != NULL);
    6968 assert(nvars != NULL);
    6969 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
    6970
    6971 (*lhs) = benders->storedcuts[cutidx]->lhs;
    6972 (*rhs) = benders->storedcuts[cutidx]->rhs;
    6973 (*nvars) = benders->storedcuts[cutidx]->nvars;
    6974
    6975 /* if there are enough slots, then store the cut variables and values */
    6976 if( varssize >= *nvars )
    6977 {
    6978 for( i = 0; i < *nvars; i++ )
    6979 {
    6980 /* getting the original variable for the transformed variable */
    6981 origvar = benders->storedcuts[cutidx]->vars[i];
    6982 scalar = 1.0;
    6983 constant = 0.0;
    6984 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
    6985
    6986 (*vars)[i] = origvar;
    6987 (*vals)[i] = benders->storedcuts[cutidx]->vals[i];
    6988 }
    6989 }
    6990
    6991 return SCIP_OKAY;
    6992}
    6994/** adds the data for the generated cuts to the Benders' cut storage */
    6996 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
    6997 SCIP_SET* set, /**< global SCIP settings */
    6998 SCIP_VAR** vars, /**< the variables that have non-zero coefficients in the cut */
    6999 SCIP_Real* vals, /**< the coefficients of the variables in the cut */
    7000 SCIP_Real lhs, /**< the left hand side of the cut */
    7001 SCIP_Real rhs, /**< the right hand side of the cut */
    7002 int nvars /**< the number of variables with non-zero coefficients in the cut */
    7003 )
    7004{
    7005 SCIP_BENDERSCUTCUT* cut;
    7006
    7007 assert(benders != NULL);
    7008 assert(set != NULL);
    7009 assert(vars != NULL);
    7010 assert(vals != NULL);
    7011
    7012 /* allocating the block memory for the cut storage */
    7013 SCIP_CALL( SCIPallocBlockMemory(set->scip, &cut) );
    7014
    7015 /* storing the cut data */
    7016 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vars, vars, nvars) );
    7017 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vals, vals, nvars) );
    7018 cut->lhs = lhs;
    7019 cut->rhs = rhs;
    7020 cut->nvars = nvars;
    7021
    7022 /* ensuring the required memory is available for the stored cuts array */
    7023 if( benders->storedcutssize < benders->nstoredcuts + 1 )
    7024 {
    7025 int newsize;
    7026
    7027 newsize = SCIPsetCalcMemGrowSize(set, benders->nstoredcuts + 1);
    7029 benders->storedcutssize, newsize) );
    7030
    7031 benders->storedcutssize = newsize;
    7032 }
    7033 assert(benders->storedcutssize >= benders->nstoredcuts + 1);
    7034
    7035 /* adding the cuts to the Benders' cut storage */
    7036 benders->storedcuts[benders->nstoredcuts] = cut;
    7037 benders->nstoredcuts++;
    7038
    7039 return SCIP_OKAY;
    7040}
    7042/** sets the sorted flags in the Benders' decomposition */
    7044 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
    7045 SCIP_Bool sorted /**< the value to set the sorted flag to */
    7046 )
    7047{
    7048 assert(benders != NULL);
    7049
    7050 benders->benderscutssorted = sorted;
    7051 benders->benderscutsnamessorted = sorted;
    7052}
    7054/** inserts a Benders' cut into the Benders' cuts list */
    7056 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
    7057 SCIP_SET* set, /**< global SCIP settings */
    7058 SCIP_BENDERSCUT* benderscut /**< Benders' cut */
    7059 )
    7060{
    7061 assert(benders != NULL);
    7062 assert(benderscut != NULL);
    7063
    7064 if( benders->nbenderscuts >= benders->benderscutssize )
    7065 {
    7068 }
    7069 assert(benders->nbenderscuts < benders->benderscutssize);
    7070
    7071 benders->benderscuts[benders->nbenderscuts] = benderscut;
    7072 benders->nbenderscuts++;
    7073 benders->benderscutssorted = FALSE;
    7074
    7075 return SCIP_OKAY;
    7076}
    7078/** returns the Benders' cut of the given name, or NULL if not existing */
    7080 SCIP_BENDERS* benders, /**< Benders' decomposition */
    7081 const char* name /**< name of Benderscut' decomposition */
    7082 )
    7083{
    7084 int i;
    7085
    7086 assert(benders != NULL);
    7087 assert(name != NULL);
    7088
    7089 for( i = 0; i < benders->nbenderscuts; i++ )
    7090 {
    7091 if( strcmp(SCIPbenderscutGetName(benders->benderscuts[i]), name) == 0 )
    7092 return benders->benderscuts[i];
    7093 }
    7094
    7095 return NULL;
    7096}
    7097
    7098/** returns the array of currently available Benders' cuts; active Benders' decomposition are in the first slots of
    7099 * the array
    7100 */
    7102 SCIP_BENDERS* benders /**< Benders' decomposition */
    7103 )
    7104{
    7105 assert(benders != NULL);
    7106
    7107 if( !benders->benderscutssorted )
    7108 {
    7109 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
    7110 benders->benderscutssorted = TRUE;
    7111 benders->benderscutsnamessorted = FALSE;
    7112 }
    7113
    7114 return benders->benderscuts;
    7115}
    7117/** returns the number of currently available Benders' cuts */
    7119 SCIP_BENDERS* benders /**< Benders' decomposition */
    7120 )
    7121{
    7122 assert(benders != NULL);
    7123
    7124 return benders->nbenderscuts;
    7125}
    7127/** sets the priority of a Benders' decomposition */
    7129 SCIP_BENDERS* benders, /**< Benders' decomposition */
    7130 SCIP_BENDERSCUT* benderscut, /**< Benders' cut */
    7131 int priority /**< new priority of the Benders' decomposition */
    7132 )
    7133{
    7134 assert(benders != NULL);
    7135 assert(benderscut != NULL);
    7136
    7137 benderscut->priority = priority;
    7138 benders->benderscutssorted = FALSE;
    7139
    7140 return SCIP_OKAY;
    7141}
    7143/** sorts Benders' decomposition cuts by priorities */
    7145 SCIP_BENDERS* benders /**< Benders' decomposition */
    7146 )
    7147{
    7148 assert(benders != NULL);
    7149
    7150 if( !benders->benderscutssorted )
    7151 {
    7152 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
    7153 benders->benderscutssorted = TRUE;
    7154 benders->benderscutsnamessorted = FALSE;
    7155 }
    7156}
    7158/** sorts Benders' decomposition cuts by name */
    7160 SCIP_BENDERS* benders /**< Benders' decomposition */
    7161 )
    7162{
    7163 assert(benders != NULL);
    7164
    7165 if( !benders->benderscutsnamessorted )
    7166 {
    7167 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutCompName, benders->nbenderscuts);
    7168 benders->benderscutssorted = FALSE;
    7169 benders->benderscutsnamessorted = TRUE;
    7170 }
    7171}
    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:255
    #define SCIP_MAXSTRLEN
    Definition: def.h:276
    #define EPSGE(x, y, eps)
    Definition: def.h:194
    #define SCIP_Longint
    Definition: def.h:148
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:304
    #define SCIP_Bool
    Definition: def.h:98
    #define MIN(x, y)
    Definition: def.h:231
    #define SCIP_ALLOC(x)
    Definition: def.h:373
    #define SCIP_Real
    Definition: def.h:163
    #define TRUE
    Definition: def.h:100
    #define FALSE
    Definition: def.h:101
    #define MAX(x, y)
    Definition: def.h:227
    #define SCIPABORT()
    Definition: def.h:334
    #define SCIP_CALL(x)
    Definition: def.h:362
    #define SCIP_CALL_FINALLY(x, y)
    Definition: def.h:404
    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:6851
    SCIP_Real SCIPbendersGetSetupTime(SCIP_BENDERS *benders)
    Definition: benders.c:6082
    void SCIPbendersSetSubproblemObjval(SCIP_BENDERS *benders, int probnumber, SCIP_Real objval)
    Definition: benders.c:6284
    SCIP_RETCODE SCIPbendersSolSlackVarsActive(SCIP_BENDERS *benders, SCIP_Bool *activeslack)
    Definition: benders.c:6313
    SCIP_Bool SCIPbendersCutRelaxation(SCIP_BENDERS *benders)
    Definition: benders.c:6144
    int SCIPbendersGetNTransferredCuts(SCIP_BENDERS *benders)
    Definition: benders.c:6861
    SCIP_Bool SCIPbendersSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6464
    int SCIPbendersGetNStrengthenFails(SCIP_BENDERS *benders)
    Definition: benders.c:6072
    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:6945
    SCIP_BENDERS ** SCIPgetBenders(SCIP *scip)
    Definition: scip_benders.c:508
    void SCIPbendersSetSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isnonlinear)
    Definition: benders.c:6486
    void SCIPbendersSetMasterIsNonlinear(SCIP_BENDERS *benders, SCIP_Bool isnonlinear)
    Definition: benders.c:6528
    SCIP_BENDERS * SCIPfindBenders(SCIP *scip, const char *name)
    Definition: scip_benders.c:493
    void SCIPbendersSetData(SCIP_BENDERS *benders, SCIP_BENDERSDATA *bendersdata)
    Definition: benders.c:5801
    SCIP_Bool SCIPbendersOnlyCheckConvexRelax(SCIP_BENDERS *benders, SCIP_Bool subscipsoff)
    Definition: benders.c:3300
    SCIP_Bool SCIPbendersSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6506
    int SCIPbendersGetPriority(SCIP_BENDERS *benders)
    Definition: benders.c:5986
    SCIP_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6212
    SCIP_BENDERSCUT * SCIPfindBenderscut(SCIP_BENDERS *benders, const char *name)
    Definition: benders.c:7077
    const char * SCIPbendersGetDesc(SCIP_BENDERS *benders)
    Definition: benders.c:5976
    int SCIPbendersGetNConvexSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6476
    SCIP_BENDERSSUBTYPE SCIPbendersGetSubproblemType(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6423
    SCIP_VAR ** SCIPbendersGetSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6234
    SCIP_RETCODE SCIPbendersSolveSubproblemCIP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Bool solvecip)
    Definition: benders.c:5229
    int SCIPbendersGetNNonlinearSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6518
    void SCIPsetBendersPriority(SCIP *scip, SCIP_BENDERS *benders, int priority)
    Definition: scip_benders.c:590
    SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
    Definition: benders.c:5046
    SCIP_Bool SCIPbendersSubproblemIsEnabled(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6779
    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:6062
    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:6904
    SCIP_RETCODE SCIPbendersSolveSubproblemLP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Real *objective)
    Definition: benders.c:5059
    int SCIPbendersGetNBenderscuts(SCIP_BENDERS *benders)
    Definition: benders.c:7116
    void SCIPbendersSetSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isconvex)
    Definition: benders.c:6441
    SCIP_Bool SCIPbendersIsActive(SCIP_BENDERS *benders)
    Definition: benders.c:2987
    SCIP_Bool SCIPbendersSubproblemsAreInfeasible(SCIP_BENDERS *benders)
    Definition: benders.c:6576
    void SCIPbendersSetSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber, SCIP_Bool issetup)
    Definition: benders.c:6674
    SCIP_BENDERSDATA * SCIPbendersGetData(SCIP_BENDERS *benders)
    Definition: benders.c:5791
    const char * SCIPbendersGetName(SCIP_BENDERS *benders)
    Definition: benders.c:5966
    SCIP_Bool SCIPbendersCutPseudo(SCIP_BENDERS *benders)
    Definition: benders.c:6134
    SCIP_VAR ** SCIPbendersGetAuxiliaryVars(SCIP_BENDERS *benders)
    Definition: benders.c:6224
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6010
    void SCIPbendersSetSubproblemType(SCIP_BENDERS *benders, int probnumber, SCIP_BENDERSSUBTYPE subprobtype)
    Definition: benders.c:6398
    int SCIPbendersGetNStrengthenCutsFound(SCIP_BENDERS *benders)
    Definition: benders.c:6052
    void SCIPbendersUpdateSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber, SCIP_Real lowerbound)
    Definition: benders.c:6873
    SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6020
    void SCIPbendersGetSubproblemMasterVarsData(SCIP_BENDERS *benders, int probnumber, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars)
    Definition: benders.c:6258
    SCIP_Bool SCIPbendersMasterIsNonlinear(SCIP_BENDERS *benders)
    Definition: benders.c:6539
    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:6914
    int SCIPbendersGetNCalls(SCIP_BENDERS *benders)
    Definition: benders.c:6032
    SCIP_Bool SCIPbendersIsInitialized(SCIP_BENDERS *benders)
    Definition: benders.c:6114
    int SCIPbendersGetNCutsFound(SCIP_BENDERS *benders)
    Definition: benders.c:6042
    SCIP_Bool SCIPbendersShareAuxVars(SCIP_BENDERS *benders)
    Definition: benders.c:6154
    SCIP_Bool SCIPbendersCutLP(SCIP_BENDERS *benders)
    Definition: benders.c:6124
    SCIP_RETCODE SCIPbendersSetBenderscutPriority(SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, int priority)
    Definition: benders.c:7126
    SCIP_Real SCIPbendersGetTime(SCIP_BENDERS *benders)
    Definition: benders.c:6092
    SCIP_Bool SCIPbendersSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6739
    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:7099
    SCIP_VAR * SCIPbenderGetMasterAuxiliaryVar(SCIP_BENDERS *benders)
    Definition: benders.c:6202
    SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6301
    void SCIPbendersSetSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isindep)
    Definition: benders.c:6699
    SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
    Definition: benders.c:6549
    SCIP_Bool SCIPbendersSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6687
    SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6892
    int SCIPbendersGetNSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6246
    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:2988
    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:2353
    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:2136
    SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
    Definition: scip_solve.c:3596
    SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
    Definition: scip_solve.c:3455
    SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
    Definition: scip_solve.c:3541
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2628
    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:5765
    void SCIPbendersSetSolvesubconvex(SCIP_BENDERS *benders, SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)))
    Definition: benders.c:5911
    static void createSolveSubproblemIndexList(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type, int **solveidx, int *nsolveidx)
    Definition: benders.c:3336
    #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:5370
    void SCIPbendersSetPresubsolve(SCIP_BENDERS *benders, SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)))
    Definition: benders.c:5900
    #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:6840
    SCIP_RETCODE SCIPbendersActivate(SCIP_BENDERS *benders, SCIP_SET *set, int nsubproblems)
    Definition: benders.c:2789
    SCIP_RETCODE SCIPbendersComputeSubproblemLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Real *lowerbound, SCIP_Bool *infeasible)
    Definition: benders.c:5420
    void SCIPbendersRemoveSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6190
    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:4400
    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:1502
    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:3141
    void SCIPbendersSetExit(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXIT((*bendersexit)))
    Definition: benders.c:5845
    #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:5320
    #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:5996
    static SCIP_DECL_SORTPTRCOMP(benderssubcompdefault)
    Definition: benders.c:609
    static SCIP_Bool subproblemIsActive(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:3325
    static SCIP_RETCODE addSlackVars(SCIP *scip, SCIP_BENDERS *benders, SCIP_CONS *cons, SCIP_CONSHDLR **linearconshdlrs, SCIP_CONSHDLR *nlconshdlr, int nlinearconshdlrs)
    Definition: benders.c:1540
    SCIP_RETCODE SCIPbendersExit(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2450
    void SCIPbendersSetInitsol(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINITSOL((*bendersinitsol)))
    Definition: benders.c:5878
    static SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodefocus)
    Definition: benders.c:249
    SCIP_RETCODE SCIPbendersChgMastervarsToCont(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:6586
    #define SCIP_DEFAULT_NLPITERLIMIT
    Definition: benders.c:81
    void SCIPbendersSortBenderscuts(SCIP_BENDERS *benders)
    Definition: benders.c:7142
    SCIP_RETCODE SCIPbendersSetupSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type)
    Definition: benders.c:4640
    static SCIP_RETCODE setAndUpdateCorePoint(SCIP *scip, SCIP_BENDERS *benders)
    Definition: benders.c:3055
    #define SCIP_DEFAULT_STRENGTHENMULT
    Definition: benders.c:69
    static SCIP_RETCODE createSubproblems(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:1999
    SCIP_RETCODE SCIPbendersSetMastervarsCont(SCIP_BENDERS *benders, int probnumber, SCIP_Bool arecont)
    Definition: benders.c:6791
    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:5922
    void SCIPbendersSetSubproblemsAreInfeasible(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:6561
    void SCIPbendersSetExitsol(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)))
    Definition: benders.c:5889
    void SCIPbendersSortBenderscutsName(SCIP_BENDERS *benders)
    Definition: benders.c:7157
    static SCIP_RETCODE resetOrigSubproblemParams(SCIP *subproblem, SCIP_SUBPROBPARAMS *origparams)
    Definition: benders.c:5020
    #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:1652
    static SCIP_RETCODE updateAuxiliaryVarLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_RESULT *result)
    Definition: benders.c:2998
    #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:3665
    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:3425
    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:2286
    SCIP_RETCODE SCIPbendersMergeSubproblemIntoMaster(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, int probnumber)
    Definition: benders.c:5582
    #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:1698
    #define SCIP_DEFAULT_AUXVARSIMPLINT
    Definition: benders.c:67
    static SCIP_RETCODE copyMemoryAndTimeLimits(SCIP *scip, SCIP *subproblem)
    Definition: benders.c:4909
    static SCIP_RETCODE transferBendersCuts(SCIP *sourcescip, SCIP *subscip, SCIP_BENDERS *benders)
    Definition: benders.c:2404
    void SCIPbendersSetBenderscutsSorted(SCIP_BENDERS *benders, SCIP_Bool sorted)
    Definition: benders.c:7041
    #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:5944
    #define SLACKVAR_NAME
    Definition: benders.c:88
    SCIP_RETCODE SCIPbendersInitsol(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2700
    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:4471
    void SCIPbendersSetFreesub(SCIP_BENDERS *benders, SCIP_DECL_BENDERSFREESUB((*bendersfreesub)))
    Definition: benders.c:5955
    #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:4969
    void SCIPbendersSetInit(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINIT((*bendersinit)))
    Definition: benders.c:5834
    #define NLINEARCONSHDLRS
    Definition: benders.c:89
    SCIP_RETCODE SCIPbendersDeactivate(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2889
    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:6993
    void SCIPbendersSetCopy(SCIP_BENDERS *benders, SCIP_DECL_BENDERSCOPY((*benderscopy)))
    Definition: benders.c:5812
    SCIP_RETCODE SCIPbendersAddSubproblem(SCIP_BENDERS *benders, SCIP *subproblem)
    Definition: benders.c:6166
    #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:5399
    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:3863
    SCIP_Bool SCIPbendersGetMastervarsCont(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6826
    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:5823
    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:4942
    #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:2616
    void SCIPbendersEnableOrDisableClocks(SCIP_BENDERS *benders, SCIP_Bool enable)
    Definition: benders.c:6102
    void SCIPbendersSetExitpre(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)))
    Definition: benders.c:5867
    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:3376
    static SCIP_RETCODE checkSubproblemConvexity(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
    Definition: benders.c:1791
    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:5856
    void SCIPbendersSetSubproblemEnabled(SCIP_BENDERS *benders, int probnumber, SCIP_Bool enabled)
    Definition: benders.c:6753
    void SCIPbendersSetPostsolve(SCIP_BENDERS *benders, SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)))
    Definition: benders.c:5933
    SCIP_RETCODE SCIPbendersIncludeBenderscut(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSCUT *benderscut)
    Definition: benders.c:7053
    SCIP_RETCODE SCIPbendersExitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
    Definition: benders.c:2674
    static int numSubproblemsToCheck(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type)
    Definition: benders.c:3310
    SCIP_RETCODE SCIPbendersExitsol(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2733
    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:4800
    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:1741
    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:2562
    SCIP_RETCODE SCIPbendersInit(SCIP_BENDERS *benders, SCIP_SET *set)
    Definition: benders.c:2206
    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