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