Scippy

    SCIP

    Solving Constraint Integer Programs

    relax_benders.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file relax_benders.c
    26 * @ingroup DEFPLUGINS_RELAX
    27 * @brief benders relaxator
    28 * @author Stephen J. Maher
    29 *
    30 * This relaxator is provided to apply Benders' decomposition to a supplied decomposition structure. The relaxator is
    31 * invoked if the user supplies a decomposition structure and sets the parameter "decomposition/applybenders" to TRUE.
    32 * In addition, it is recommended that the parameter "decomposition/benderslabels" is set to TRUE to ensure that the
    33 * block labelling of the variables and constraints is correct for applying Benders' decomposition.
    34 *
    35 * Given a decomposition structure, the relaxator will create a number of SCIP instances: one for the master problem and
    36 * one for each subproblems. These SCIP instances are supplied to the default Benders' decomposition plugin to trigger
    37 * the execution of the Benders' decomposition algorithm. The original SCIP instance will execute presolving and start
    38 * the solving process. When the root node starts solving, this relaxator will be called first. The Benders'
    39 * decomposition algorithm attempts to solve the problem to optimality. At the completion of the Benders' decomposition
    40 * algorithm, the best found primal and dual bounds are returned to the original SCIP instance. The solution from the
    41 * decomposed problem is mapped back to the original instance variables.
    42 *
    43 * By default, the original SCIP instance will terminate with an optimal solution or infeasible status (if found or
    44 * proven by the Benders' decomposition algorithm, resp.), or a status indicating a time, gap, or bound limit, or a
    45 * "user interrupt". To prevent the original SCIP instance to continue solving if the Benders' decomposition algorithm
    46 * fails to solve the problem, the user interrupt is also triggered if the Benders' decomposition algorithm stopped due
    47 * to a node, restart, or solution limit, or when transferring the solution to the original SCIP instance fails.
    48 * To continue solving the original SCIP instance after the conclusion of the Benders' decomposition algorithm,
    49 * parameter "relaxing/benders/continueorig" can be set to TRUE.
    50 *
    51 * The working limits from the original SCIP instance are copied across to the master problem SCIP instance. However, if
    52 * the user desires to have a different node limit for the master problem, for example if they wish to use
    53 * Benders' decomposition as a start heuristic, then this can be set with the parameter "relaxing/benders/nodelimit".
    54 *
    55 * If the Benders' decomposition relaxator is used, then statistics for both the original SCIP instance and the master
    56 * problem SCIP instance are displayed when the statistics are requested by via the SCIP shell dialog.
    57 */
    58
    59/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    60
    61#include <assert.h>
    62
    63#include "scip/scip.h"
    65#include "scip/pub_benders.h"
    66#include "scip/pub_relax.h"
    67#include "scip/relax_benders.h"
    68#include "scip/type_benders.h"
    69#include "scip/type_message.h"
    70#include "scip/type_relax.h"
    71#include "scip/type_retcode.h"
    72#include "scip/type_stat.h"
    73
    74#define RELAX_NAME "benders"
    75#define RELAX_DESC "applies default Benders' decomposition and solves the problem"
    76#define RELAX_PRIORITY 1
    77#define RELAX_FREQ 0
    78
    79#define DEFAULT_CONTORIG FALSE /**< continue solving the original SCIP instance if optimal solution is not found */
    80#define DEFAULT_NODELIMIT -1LL /**< node limit for the Benders' decomposition solve, -1 indicates original SCIP limit is used. */
    81
    82
    83/*
    84 * Data structures
    85 */
    86
    87/** relaxator data */
    88struct SCIP_RelaxData
    89{
    90 SCIP* masterprob; /**< the SCIP instance of the master problem */
    91 SCIP** subproblems; /**< an array of SCIP instances for the subproblems */
    92 SCIP_DECOMP* decomp; /**< the structure used for the decomposition */
    93 SCIP_HASHMAP* mastervarmap; /**< variables mapping between the original SCIP and the master problem */
    94 SCIP_HASHMAP** subvarmaps; /**< variables mapping between the original SCIP and the subproblems */
    95 int nsubproblems; /**< the number of subproblems */
    96 SCIP_Bool decompapplied; /**< indicates whether the decomposition was applied */
    97
    98 /* parameters */
    99 SCIP_Longint nodelimit; /**< the node limit for the Benders' decomposition solve */
    100 SCIP_Bool contorig; /**< continue solving the original SCIP instance if optimal solution is not found */
    101};
    102
    103/*
    104 * Local methods
    105 */
    106
    107/** adding variables from the original problem to the respective decomposed problem */
    108static
    110 SCIP* scip, /**< the SCIP data structure */
    111 SCIP* targetscip, /**< the SCIP instance that the constraint will be copied into */
    112 SCIP_HASHMAP* varmap, /**< the variable hash map mapping the source variables to the target variables */
    113 SCIP_VAR* sourcevar /**< the variable to add to the problem */
    114 )
    115{
    116 assert(scip != NULL);
    117 assert(targetscip != NULL);
    118 assert(varmap != NULL);
    119 assert(sourcevar != NULL);
    120
    121 /* if the variable is not in the hashmap, then it doesn't exist in the subproblem */
    122 if( !SCIPhashmapExists(varmap, sourcevar) )
    123 {
    124 SCIP_VAR* var;
    125
    126 /* creating a variable as a copy of the original variable. */
    127 SCIP_CALL( SCIPcreateVarImpl(targetscip, &var, SCIPvarGetName(sourcevar), SCIPvarGetLbGlobal(sourcevar),
    128 SCIPvarGetUbGlobal(sourcevar), SCIPvarGetObj(sourcevar), SCIPvarGetType(sourcevar),
    129 SCIPvarGetImplType(sourcevar), SCIPvarIsInitial(sourcevar), SCIPvarIsRemovable(sourcevar),
    130 NULL, NULL, NULL, NULL, NULL) );
    131
    132 /* adding the variable to the subproblem */
    133 SCIP_CALL( SCIPaddVar(targetscip, var) );
    134
    135 /* adding the variable to the hash map so that it is copied correctly in the constraint */
    136 SCIP_CALL( SCIPhashmapInsert(varmap, sourcevar, var) );
    137
    138 /* releasing the variable */
    139 SCIP_CALL( SCIPreleaseVar(targetscip, &var) );
    140 }
    141
    142 return SCIP_OKAY;
    143}
    144
    145/* when applying the decomposition, the constraints must be copied across from the original SCIP instance to the
    146 * respective Benders' problems in the relaxator. This could be either the master problem or one of the subproblems. The
    147 * process for performing this is the same for either problem type.
    148 */
    149static
    151 SCIP* scip, /**< the original SCIP instance */
    152 SCIP* targetscip, /**< the SCIP instance that the constraint will be copied into */
    153 SCIP_HASHMAP* varmap, /**< the variable hash map mapping the source variables to the target variables */
    154 SCIP_CONS* sourcecons /**< the constraint that being added to the subproblem */
    155 )
    156{
    157 SCIP_CONS* cons;
    158 SCIP_VAR** consvars;
    159 int nconsvars;
    160 int i;
    161 SCIP_Bool success;
    162
    163 assert(scip != NULL);
    164 assert(targetscip != NULL);
    165 assert(varmap != NULL);
    166 assert(sourcecons != NULL);
    167
    168 SCIPdebugMessage("Adding constraint <%s> to Benders' decomposition subproblem\n", SCIPconsGetName(sourcecons));
    169
    170 /* getting the variables that are in the constraint */
    171 SCIP_CALL( SCIPgetConsNVars(scip, sourcecons, &nconsvars, &success) );
    172 if( !success )
    173 return SCIP_ERROR;
    174
    175 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nconsvars) );
    176
    177 SCIP_CALL( SCIPgetConsVars(scip, sourcecons, consvars, nconsvars, &success) );
    178 if( !success )
    179 {
    180 SCIPfreeBufferArray(scip, &consvars);
    181 return SCIP_ERROR;
    182 }
    183
    184 /* checking all variables to see whether they already exist in the subproblem. If they don't exist, then the variable
    185 * is created
    186 */
    187 for( i = 0; i < nconsvars; i++ )
    188 {
    189 SCIP_CALL( addVariableToBendersProblem(scip, targetscip, varmap, consvars[i]) );
    190 }
    191
    192 /* freeing the buffer memory for the consvars */
    193 SCIPfreeBufferArray(scip, &consvars);
    194
    195 /* copying the constraint from the master scip to the subproblem */
    196 SCIP_CALL( SCIPgetConsCopy(scip, targetscip, sourcecons, &cons, SCIPconsGetHdlr(sourcecons), varmap, NULL,
    197 SCIPconsGetName(sourcecons), SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
    198 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons), SCIPconsIsMarkedPropagate(sourcecons),
    199 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
    200 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons), TRUE, &success) );
    201
    202 /* if the copy failed, then the subproblem for the decomposition could not be performed. */
    203 if( !success )
    204 {
    205 SCIPerrorMessage("It is not possible to copy constraint <%s>. Benders' decomposition could not be applied.\n",
    206 SCIPconsGetName(sourcecons));
    207 return SCIP_ERROR;
    208 }
    209
    210 SCIP_CALL( SCIPaddCons(targetscip, cons) );
    211 SCIP_CALL( SCIPreleaseCons(targetscip, &cons) );
    212
    213 return SCIP_OKAY;
    214}
    215
    216/** Applies a Benders' decomposition to the problem based upon the decomposition selected from the storage */
    217static
    219 SCIP* scip, /**< the original SCIP instance */
    220 SCIP_RELAX* relax, /**< the relaxator */
    221 SCIP_DECOMP* decomp /**< the decomposition to apply to the problem */
    222 )
    223{
    224 SCIP_RELAXDATA* relaxdata;
    225 SCIP_VAR** vars;
    226 SCIP_CONS** conss;
    227 int* varslabels;
    228 int* conslabels;
    229 int nvars;
    230 int nconss;
    231 int nblocks;
    232 int i;
    233 char probname[SCIP_MAXSTRLEN];
    234 SCIP_Bool valid;
    235
    236 assert(scip != NULL);
    237 assert(decomp != NULL);
    238 assert(relax != NULL);
    239
    240 relaxdata = SCIPrelaxGetData(relax);
    241 assert(relaxdata != NULL);
    242
    243 SCIPdebugMessage("Applying a Benders' decomposition to <%s>\n", SCIPgetProbName(scip));
    244
    245 /* storing the decomposition */
    246 relaxdata->decomp = decomp;
    247
    248 /* retrieving the number of blocks for this decomposition */
    249 nblocks = SCIPdecompGetNBlocks(decomp);
    250 assert(nblocks > 0);
    251
    252 /* initialising the subproblems for the Benders' decomposition */
    253 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->subproblems, nblocks) );
    254 relaxdata->nsubproblems = nblocks;
    255
    256 /* creating the master problem */
    257 SCIP_CALL( SCIPcreate(&relaxdata->masterprob) );
    258
    259 /* copying the plugins from the original SCIP instance to the master SCIP */
    260 SCIP_CALL( SCIPcopyPlugins(scip, relaxdata->masterprob, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
    261 TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, &valid) );
    262
    263 /* including the default Benders' decomposition plugin. This is added separately so that any addition of the plugin
    264 * in the master problem is ignored
    265 */
    266 SCIP_CALL( SCIPincludeBendersDefault(relaxdata->masterprob) );
    267
    268 /* copying the parameter settings from the original SCIP to the master problem */
    269 SCIP_CALL( SCIPcopyParamSettings(scip, relaxdata->masterprob) );
    270
    271 (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "master_%s", SCIPgetProbName(scip));
    272 SCIP_CALL( SCIPcreateProbBasic(relaxdata->masterprob, probname) );
    273
    274 /* creating the subproblems before adding the constraints */
    275 for( i = 0; i < nblocks; i++ )
    276 {
    277 SCIP_CALL( SCIPcreate(&relaxdata->subproblems[i]) );
    278
    279 /* copying the plugins from the original SCIP instance to the subproblem SCIP */
    280 SCIP_CALL( SCIPcopyPlugins(scip, relaxdata->subproblems[i], TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
    281 TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, &valid) );
    282
    283 (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "sub_%s_%d", SCIPgetProbName(scip), i);
    284 SCIP_CALL( SCIPcreateProbBasic(relaxdata->subproblems[i], probname) );
    285 }
    286
    287 /* TODO: Need to work out whether a check for original and transformed problem is necessary */
    288
    289 /* getting the variables and constraints from the problem */
    290 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    291 conss = SCIPgetConss(scip);
    292 nconss = SCIPgetNConss(scip);
    293
    294 /* allocating buffer memory for the labels arrays */
    295 SCIP_CALL( SCIPallocBufferArray(scip, &varslabels, nvars) );
    296 SCIP_CALL( SCIPallocBufferArray(scip, &conslabels, nconss) );
    297
    298 /* getting the labels for the variables and constraints from the decomposition */
    299 SCIPdecompGetVarsLabels(decomp, vars, varslabels, nvars);
    300 SCIPdecompGetConsLabels(decomp, conss, conslabels, nconss);
    301
    302 /* creating the variable map for the master problem */
    303 SCIP_CALL( SCIPhashmapCreate(&relaxdata->mastervarmap, SCIPblkmem(relaxdata->masterprob), nvars) );
    304
    305 /* creating the variable maps for adding the constraints to the subproblems */
    306 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->subvarmaps, nblocks) );
    307
    308 for( i = 0; i < nblocks; i++ )
    309 {
    310 SCIP_CALL( SCIPhashmapCreate(&relaxdata->subvarmaps[i], SCIPblkmem(relaxdata->subproblems[i]), nvars) );
    311 }
    312
    313 /* copying the constraints to the appropriate subproblems */
    314 for( i = 0; i < nconss; i++ )
    315 {
    316 /* the constraints with a block label >= 0 correspond to subproblem constraints. All other constraints are master
    317 * constraints.
    318 */
    319 if( conslabels[i] >= 0 )
    320 {
    321 assert(conslabels[i] < relaxdata->nsubproblems);
    322 SCIP_CALL( addConstraintToBendersProblem(scip, relaxdata->subproblems[conslabels[i]], relaxdata->subvarmaps[conslabels[i]],
    323 conss[i]) );
    324 }
    325 else
    326 {
    327 SCIP_CALL( addConstraintToBendersProblem(scip, relaxdata->masterprob, relaxdata->mastervarmap, conss[i]) );
    328 }
    329 }
    330
    331 /* creating the Benders' decomposition by calling the default plugin */
    332 SCIP_CALL( SCIPcreateBendersDefault(relaxdata->masterprob, relaxdata->subproblems, nblocks) );
    333
    334 /* activating the Benders' constraint handler for the scenario stages.
    335 * TODO: consider whether the two-phase method should be activated by default in the scenario stages.
    336 */
    337 SCIP_CALL( SCIPsetBoolParam(relaxdata->masterprob, "constraints/benders/active", TRUE) );
    338 SCIP_CALL( SCIPsetBoolParam(relaxdata->masterprob, "constraints/benderslp/active", TRUE) );
    339
    340 /* changing settings that are required for Benders' decomposition */
    341 SCIP_CALL( SCIPsetPresolving(relaxdata->masterprob, SCIP_PARAMSETTING_OFF, TRUE) );
    342 SCIP_CALL( SCIPsetIntParam(relaxdata->masterprob, "propagating/maxrounds", 0) );
    343 SCIP_CALL( SCIPsetIntParam(relaxdata->masterprob, "propagating/maxroundsroot", 0) );
    344
    345 /* disabling aggregation since it can affect the mapping between the master and subproblem variables */
    346 SCIP_CALL( SCIPsetBoolParam(relaxdata->masterprob, "presolving/donotaggr", TRUE) );
    347 SCIP_CALL( SCIPsetBoolParam(relaxdata->masterprob, "presolving/donotmultaggr", TRUE) );
    348
    349 SCIPfreeBufferArray(scip, &conslabels);
    350 SCIPfreeBufferArray(scip, &varslabels);
    351
    352 relaxdata->decompapplied = TRUE;
    353
    354 return SCIP_OKAY;
    355}
    356
    357/** copies the best solution from the original SCIP instance and adds it to the master problem of the decomposed problem */
    358static
    360 SCIP* scip, /**< the SCIP instance */
    361 SCIP_RELAXDATA* relaxdata /**< the relaxator data */
    362 )
    363{
    364 SCIP* masterprob;
    365 SCIP_SOL* sol;
    366 SCIP_SOL* bestsol;
    367 SCIP_DECOMP* decomp;
    368 SCIP_VAR** vars;
    369 int* varslabels;
    370 int nvars;
    371 int i;
    372 SCIP_Bool stored;
    373
    374 assert(scip != NULL);
    375 assert(relaxdata != NULL);
    376 assert(relaxdata->masterprob != NULL);
    377
    378 masterprob = relaxdata->masterprob;
    379
    380 bestsol = SCIPgetBestSol(scip);
    381
    382 /* if the best solution doesn't exist, then there is no solution to copy */
    383 if( bestsol == NULL )
    384 return SCIP_OKAY;
    385
    386 vars = SCIPgetVars(scip);
    387 nvars = SCIPgetNVars(scip);
    388
    389 SCIP_CALL( SCIPcreateSol(masterprob, &sol, NULL) );
    390
    391 decomp = relaxdata->decomp;
    392
    393 /* allocating buffer memory for the labels arrays */
    394 SCIP_CALL( SCIPallocBufferArray(scip, &varslabels, nvars) );
    395
    396 /* getting the labels for the variables and constraints from the decomposition */
    397 SCIPdecompGetVarsLabels(decomp, vars, varslabels, nvars);
    398
    399 /* setting the value of the variables that are in the master problem */
    400 for( i = 0; i < nvars; i++ )
    401 {
    402 SCIP_VAR* mappedvar;
    403
    404 /* we are only interested in the master problem variables */
    405 if( varslabels[i] < 0 )
    406 {
    407 mappedvar = (SCIP_VAR*)SCIPhashmapGetImage(relaxdata->mastervarmap, vars[i]);
    408 if( mappedvar != NULL )
    409 {
    410 SCIP_CALL( SCIPsetSolVal(masterprob, sol, mappedvar,
    411 SCIPgetSolVal(scip, bestsol, vars[i])) );
    412 }
    413 }
    414 }
    415
    416 SCIPfreeBufferArray(scip, &varslabels);
    417
    418 SCIP_CALL( SCIPtrySolFree(relaxdata->masterprob, &sol, FALSE, FALSE, TRUE, TRUE, TRUE, &stored) );
    419
    420 return SCIP_OKAY;
    421}
    422
    423/** returns whether a solution exists for the master problem */
    424static
    426 SCIP* scip, /**< the SCIP data structure */
    427 SCIP_RELAX* relax /**< the relaxator */
    428 )
    429{
    430 SCIP_RELAXDATA* relaxdata;
    431
    432 assert(scip != NULL);
    433 assert(relax != NULL);
    434
    435 relaxdata = SCIPrelaxGetData(relax);
    436 assert(relaxdata != NULL);
    437
    438 assert(relaxdata->masterprob != NULL);
    439
    440 return (SCIPgetBestSol(relaxdata->masterprob) != NULL);
    441}
    442
    443
    444/** solves the Benders' decomposition subproblems using the best solution from the master problem */
    445static
    447 SCIP* scip, /**< the SCIP data structure */
    448 SCIP_RELAX* relax, /**< the relaxator */
    449 SCIP_Bool* infeasible /**< indicates whether the best solution is infeasible */
    450 )
    451{
    452 SCIP_RELAXDATA* relaxdata;
    453 SCIP* masterprob;
    454 SCIP_BENDERS* benders;
    455 SCIP_SOL* bestsol;
    456 int i;
    457
    458 assert(scip != NULL);
    459 assert(relax != NULL);
    460 assert(infeasible != NULL);
    461
    462 relaxdata = SCIPrelaxGetData(relax);
    463 assert(relaxdata != NULL);
    464
    465 masterprob = relaxdata->masterprob;
    466
    467 assert(SCIPgetNActiveBenders(masterprob) == 1);
    468
    469 /* getting the Default Benders' plugin to solve the subproblems */
    470 benders = SCIPfindBenders(masterprob, "default");
    471 assert(benders != NULL);
    472 assert(relaxdata->nsubproblems == SCIPbendersGetNSubproblems(benders));
    473
    474 /* getting the best solution for the master problem */
    475 bestsol = SCIPgetBestSol(masterprob);
    476
    477 /* solving the Benders' decomposition subproblems */
    478 for( i = 0; i < relaxdata->nsubproblems; i++)
    479 {
    480 assert(SCIPbendersSubproblem(benders, i) != NULL
    482
    483 /* setting up the subproblem with the best solution from the master problem */
    484 SCIP_CALL( SCIPsetupBendersSubproblem(masterprob, benders, bestsol, i, SCIP_BENDERSENFOTYPE_CHECK) );
    485
    486 /* solving the subproblem */
    487 SCIP_CALL( SCIPsolveBendersSubproblem(masterprob, benders, bestsol, i, infeasible, TRUE, NULL) );
    488
    489 /* if a subproblem is infeasible, then the solution is reported as infeasible */
    490 if( (*infeasible) )
    491 break;
    492 }
    493
    494 return SCIP_OKAY;
    495}
    496
    497/** constructs the NLP solution and returns it */
    498static
    500 SCIP* scip, /**< the SCIP instance for which an NLP must be constructed */
    501 SCIP_SOL** nlpsol /**< the NLP solution that will be created */
    502 )
    503{
    504 assert(scip != NULL);
    505 assert(SCIPisNLPConstructed(scip));
    506 assert(SCIPgetNNlpis(scip));
    507
    508 SCIP_CALL( SCIPcreateNLPSol(scip, nlpsol, NULL) );
    509
    510 return SCIP_OKAY;
    511}
    512
    513/** using the stored mappings for the variables, the solution values from the master and subproblems are used to set the
    514 * solution values in the original SCIP solution
    515 */
    516static
    518 SCIP* scip, /**< the original SCIP instance */
    519 SCIP_RELAX* relax, /**< the relaxator */
    520 SCIP_SOL* sol /**< the solution for the original SCIP instance */
    521 )
    522{
    523 SCIP_RELAXDATA* relaxdata;
    524 SCIP_DECOMP* decomp;
    525 SCIP_VAR** vars;
    526 SCIP_SOL** nlpsols;
    527 int* varslabels;
    528 int nvars;
    529 int i;
    530 SCIP_Bool nlpsubprob;
    531
    532 relaxdata = SCIPrelaxGetData(relax);
    533 assert(relaxdata != NULL);
    534
    535 nlpsols = NULL;
    536 nlpsubprob = FALSE;
    537 /* checking whether the NLP solutions should be collected. */
    538 for( i = 0; i < relaxdata->nsubproblems; i++ )
    539 {
    540 if( SCIPisNLPConstructed(relaxdata->subproblems[i]) && SCIPgetNNlpis(relaxdata->subproblems[i]) )
    541 {
    542 nlpsubprob = TRUE;
    543 break;
    544 }
    545 }
    546
    547 /* if there are NLP subproblems, then we need to allocate the nlpsols array and collect the NLP subproblems */
    548 if( nlpsubprob )
    549 {
    550 SCIP* subproblem;
    551
    552 SCIP_CALL( SCIPallocClearBufferArray(scip, &nlpsols, relaxdata->nsubproblems) );
    553
    554 for( i = 0; i < relaxdata->nsubproblems; i++ )
    555 {
    556 subproblem = relaxdata->subproblems[i];
    557 if( SCIPisNLPConstructed(relaxdata->subproblems[i]) && SCIPgetNNlpis(relaxdata->subproblems[i]) )
    558 {
    559 SCIP_CALL( getNlpSolution(subproblem, &(nlpsols[i])) );
    560 }
    561 }
    562 }
    563
    564 decomp = relaxdata->decomp;
    565
    566 /* getting the variables and constraints from the problem */
    567 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    568
    569 /* allocating buffer memory for the labels arrays */
    570 SCIP_CALL( SCIPallocBufferArray(scip, &varslabels, nvars) );
    571
    572 /* getting the labels for the variables and constraints from the decomposition */
    573 SCIPdecompGetVarsLabels(decomp, vars, varslabels, nvars);
    574
    575 /* looping over all variables and assigning the value to the current master or subproblem solution */
    576 for( i = 0; i < nvars; i++ )
    577 {
    578 SCIP* solscip;
    579 SCIP_HASHMAP* varmap;
    580 SCIP_SOL* bestsol;
    581 SCIP_Bool subproblem;
    582
    583 /* if the varlabel is >= 0, then the variable belongs to the subproblem. Otherwise, the variable belongs to the
    584 * master problem.
    585 */
    586 subproblem = varslabels[i] >= 0;
    587 if( subproblem )
    588 {
    589 solscip = relaxdata->subproblems[varslabels[i]];
    590 varmap = relaxdata->subvarmaps[varslabels[i]];
    591 }
    592 else
    593 {
    594 solscip = relaxdata->masterprob;
    595 varmap = relaxdata->mastervarmap;
    596 }
    597
    598 if( SCIPhashmapExists(varmap, vars[i]) )
    599 {
    600 SCIP_VAR* mappedvar;
    601 SCIP_Bool nlprelaxation;
    602
    603 /* the subproblem could be an NLP. As such, we need to get the solution directly from the NLP */
    604 nlprelaxation = subproblem && SCIPisNLPConstructed(solscip) && SCIPgetNNlpis(solscip);
    605 assert(!nlprelaxation || nlpsols != NULL);
    606 if( nlprelaxation && nlpsols != NULL )
    607 {
    608 assert(nlpsols[varslabels[i]] != NULL);
    609 bestsol = nlpsols[varslabels[i]];
    610 }
    611 else
    612 bestsol = SCIPgetBestSol(solscip);
    613
    614 mappedvar = (SCIP_VAR*)SCIPhashmapGetImage(varmap, vars[i]);
    615 if( mappedvar != NULL )
    616 {
    617 SCIP_CALL( SCIPsetSolVal(scip, sol, vars[i],
    618 SCIPgetSolVal(solscip, bestsol, mappedvar)) );
    619 }
    620 }
    621 }
    622
    623 SCIPfreeBufferArray(scip, &varslabels);
    624
    625 /* if there were NLP subproblems, then the solutions and storage array must be freed */
    626 if( nlpsubprob )
    627 {
    628 for( i = relaxdata->nsubproblems - 1; i >= 0; i-- )
    629 {
    630 if( nlpsols[i] != NULL )
    631 {
    632 SCIP_CALL( SCIPfreeSol(relaxdata->subproblems[i], &(nlpsols[i])) );
    633 }
    634 }
    635
    636 SCIPfreeBufferArray(scip, &nlpsols);
    637 }
    638
    639 return SCIP_OKAY;
    640}
    641
    642/** frees the subproblems after the solve */
    643static
    645 SCIP* scip, /**< the SCIP data structure */
    646 SCIP_RELAX* relax /**< the relaxator */
    647 )
    648{
    649 SCIP_RELAXDATA* relaxdata;
    650 SCIP* masterprob;
    651 SCIP_BENDERS* benders;
    652 int i;
    653
    654 assert(scip != NULL);
    655 assert(relax != NULL);
    656
    657 relaxdata = SCIPrelaxGetData(relax);
    658 assert(relaxdata != NULL);
    659
    660 masterprob = relaxdata->masterprob;
    661 assert(SCIPgetNActiveBenders(masterprob) == 1);
    662
    663 /* getting the Default Benders' plugin to solve the subproblems */
    664 benders = SCIPfindBenders(masterprob, "default");
    665 assert(benders != NULL);
    666 assert(relaxdata->nsubproblems == SCIPbendersGetNSubproblems(benders));
    667
    668 /* freeing the Benders' decomposition subproblems */
    669 for( i = 0; i < relaxdata->nsubproblems; i++)
    670 {
    672 }
    673
    674 return SCIP_OKAY;
    675}
    676
    677
    678/** creates a solution for the original SCIP instance using the solution from the decomposed problem */
    679static
    681 SCIP* scip, /**< the SCIP data structure */
    682 SCIP_RELAX* relax, /**< the relaxator */
    683 SCIP_Bool* infeasible /**< indicates whether the best solution is infeasible */
    684 )
    685{
    686 SCIP_SOL* sol;
    687 SCIP_Bool success;
    688
    689 assert(scip != NULL);
    690 assert(relax != NULL);
    691 assert(infeasible != NULL);
    692
    693 (*infeasible) = FALSE;
    694
    695 /* if there is no master solution, then no solution is copied across to the original SCIP instance */
    696 if( !masterSolutionExists(scip, relax) )
    697 return SCIP_OKAY;
    698
    699 /* creating the solution for the original SCIP */
    700 SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) );
    701
    702 /* solving the Benders' decomposition subproblems with the best master problem solution */
    703 SCIP_CALL( solveBendersSubproblems(scip, relax, infeasible) );
    704
    705 /* setting the solution values of the solution based on the decomposed problem solution */
    706 SCIP_CALL( setSolutionValues(scip, relax, sol) );
    707
    708 /* checking if the solution is feasible for the original problem */
    709 SCIP_CALL( SCIPcheckSol(scip, sol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
    710 if( success )
    711 {
    712 SCIP_Bool stored;
    713 SCIP_CALL( SCIPaddSol(scip, sol, &stored) );
    714 }
    715 else
    716 {
    718 "The solution found by the Benders' decomposition algorithm is not valid for the original problem.\n");
    719 }
    720
    721 SCIP_CALL( SCIPfreeSol(scip, &sol) );
    722
    723 /* freeing the subproblems after the solve */
    725
    726 return SCIP_OKAY;
    727}
    728
    729/* frees all of the data structures used to apply the decomposition */
    730static
    732 SCIP* scip, /**< the SCIP data structure */
    733 SCIP_RELAX* relax /**< the relaxator */
    734 )
    735{
    736 SCIP_RELAXDATA* relaxdata;
    737 int i;
    738
    739 assert(scip != NULL);
    740 assert(relax != NULL);
    741
    742 relaxdata = SCIPrelaxGetData(relax);
    743 assert(relaxdata != NULL);
    744
    745 /* if the decomposition has been applied, then the corresponding SCIP instances need to be freed */
    746 if( relaxdata->decompapplied )
    747 {
    748 /* freeing the variable hash maps */
    749 for( i = relaxdata->nsubproblems - 1; i >= 0; i-- )
    750 {
    751 SCIPhashmapFree(&relaxdata->subvarmaps[i]);
    752 }
    753 SCIPhashmapFree(&relaxdata->mastervarmap);
    754
    755 SCIP_CALL( SCIPfree(&relaxdata->masterprob) );
    756
    757 for( i = relaxdata->nsubproblems - 1; i >= 0; i-- )
    758 {
    759 SCIP_CALL( SCIPfree(&relaxdata->subproblems[i]) );
    760 }
    761
    762 /* freeing the allocated arrays */
    763 SCIPfreeBlockMemoryArray(scip, &relaxdata->subvarmaps, relaxdata->nsubproblems);
    764 SCIPfreeBlockMemoryArray(scip, &relaxdata->subproblems, relaxdata->nsubproblems);
    765
    766 relaxdata->decompapplied = FALSE;
    767 }
    768
    769 return SCIP_OKAY;
    770}
    771
    772/*
    773 * Callback methods of relaxator
    774 */
    775
    776#define relaxCopyBenders NULL
    777#define relaxInitBenders NULL
    778#define relaxExitBenders NULL
    779#define relaxExitsolBenders NULL
    780
    781/** destructor of relaxator to free user data (called when SCIP is exiting) */
    782static
    783SCIP_DECL_RELAXFREE(relaxFreeBenders)
    784{ /*lint --e{715}*/
    785SCIP_RELAXDATA* relaxdata;
    786
    787 assert(scip != NULL);
    788 assert(relax != NULL);
    789
    790 relaxdata = SCIPrelaxGetData(relax);
    791 assert(relaxdata != NULL);
    792
    793 /* freeing the decomposition information */
    795
    796 SCIPfreeBlockMemory(scip, &relaxdata);
    797
    798 return SCIP_OKAY;
    799}
    800
    801
    802
    803
    804/** solving process initialization method of relaxator (called when branch and bound process is about to begin) */
    805static
    806SCIP_DECL_RELAXINITSOL(relaxInitsolBenders)
    807{ /*lint --e{715}*/
    808 SCIP_BENDERS* benders;
    809 SCIP_DECOMP** decomps;
    810 int ndecomps;
    811 SCIP_Bool applybenders;
    812
    813 assert(scip != NULL);
    814
    815 /* if a decomposition has been previously applied, then it must be freed first */
    817
    818 SCIP_CALL( SCIPgetBoolParam(scip, "decomposition/applybenders", &applybenders) );
    819 if( !applybenders )
    820 return SCIP_OKAY;
    821
    822 SCIPgetDecomps(scip, &decomps, &ndecomps, FALSE);
    823
    824 /* if there are no decompositions, then Benders' decomposition can't be applied */
    825 if( ndecomps == 0 )
    826 return SCIP_OKAY;
    827
    828 assert(decomps[0] != NULL);
    829
    830 /* if there already exists an active Benders' decomposition, then default decomposition is not applied. */
    831 if( SCIPgetNActiveBenders(scip) > 0 )
    832 {
    833 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "A Benders' decomposition already exists. The default Benders' decomposition will not be applied to the stored decomposition.\n");
    834 return SCIP_OKAY;
    835 }
    836
    837 /* retrieving the default Benders' decomposition plugin */
    838 benders = SCIPfindBenders(scip, "default");
    839
    840 /* if the default Benders' decomposition plugin doesn't exist, then this will result in an error */
    841 if( benders == NULL )
    842 {
    843 SCIPerrorMessage("The default Benders' decomposition plugin is required to apply Benders' decomposition using the input decomposition.");
    844 return SCIP_ERROR;
    845 }
    846
    847 /* applying the Benders' decomposition */
    848 SCIP_CALL( applyDecomposition(scip, relax, decomps[0]) );
    849
    850 return SCIP_OKAY;
    851}
    852
    853/** execution method of relaxator */
    854static
    855SCIP_DECL_RELAXEXEC(relaxExecBenders)
    856{ /*lint --e{715}*/
    857 SCIP_RELAXDATA* relaxdata;
    858 SCIP_Bool success;
    859 SCIP_Bool infeasible;
    860 SCIP_STATUS masterstatus;
    861
    862 assert(scip != NULL);
    863 assert(relax != NULL);
    864
    865 (*result) = SCIP_DIDNOTRUN;
    866 infeasible = FALSE;
    867
    868 relaxdata = SCIPrelaxGetData(relax);
    869 assert(relaxdata != NULL);
    870
    871 /* the relaxator is only executed if the Benders decomposition is applied */
    872 if( !relaxdata->decompapplied )
    873 return SCIP_OKAY;
    874
    875 /* checking whether there is enough time and memory to perform the decomposition solve */
    876 SCIP_CALL( SCIPcheckCopyLimits(scip, &success) );
    877 if( !success )
    878 return SCIP_OKAY;
    879
    881 "\nApplying Benders' decomposition and solving the decomposed problem.\n\n");
    882
    883 /* copying the time and memory limits from the original SCIP to the master problem */
    884 SCIP_CALL( SCIPcopyLimits(scip, relaxdata->masterprob) );
    885
    886 /* is a Benders' decomposition node limit is set, then it is applied to the master problem */
    887 if( relaxdata->nodelimit >= 0 )
    888 SCIP_CALL( SCIPsetLongintParam(relaxdata->masterprob, "limits/totalnodes", relaxdata->nodelimit) );
    889
    890 /* presolving the master problem to initialise the Benders' decomposition data structures. This will allow us to
    891 * supply an initial solution coming from the original SCIP instance.
    892 */
    893 SCIP_CALL( SCIPpresolve(relaxdata->masterprob) );
    894
    895 /* adding an initial solution from the original SCIP instance */
    896 SCIP_CALL( addInitialSolution(scip, relaxdata) );
    897
    898 SCIP_CALL( SCIPsolve(relaxdata->masterprob) );
    899
    900 masterstatus = SCIPgetStatus(relaxdata->masterprob);
    901
    903 "\nBenders' decomposition solve has completed with status %s.", SCIPstatusName(masterstatus));
    904
    905 /* if the problem is solved to be infeasible, then the result needs to be set to CUTOFF. */
    906 if( masterstatus == SCIP_STATUS_INFEASIBLE )
    907 {
    909 (*result) = SCIP_CUTOFF;
    910 return SCIP_OKAY;
    911 }
    912
    913 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " Copying the solution to the original problem variables\n\n");
    914
    915 /* a solution for the original SCIP needs to be created. This will transfer the best found solution from the
    916 * Benders decomposition solve back to the original SCIP instance.
    917 */
    918 SCIP_CALL( createOriginalSolution(scip, relax, &infeasible) );
    919
    920 (*lowerbound) = SCIPgetDualbound(relaxdata->masterprob);
    921 (*result) = SCIP_SUCCESS;
    922
    923 /* if only the Benders' decomposition algorithm should be executed, then there we need to stop the original SCIP
    924 * instance. This is achieved by calling SCIPinterruptSolve. However, it is not necessary to interrupt the solve if
    925 * the time, gap, primal or dual limits are reached in the Benders' decomposition algorithm.
    926 */
    927 if( !relaxdata->contorig &&
    928 masterstatus != SCIP_STATUS_TIMELIMIT &&
    929 masterstatus != SCIP_STATUS_GAPLIMIT &&
    930 masterstatus != SCIP_STATUS_PRIMALLIMIT &&
    931 masterstatus != SCIP_STATUS_DUALLIMIT
    932 )
    933 {
    935 }
    936
    937 /* if the user interrupted the Benders' decomposition algorithm, then the main SCIP should be interrupted too */
    938 if( masterstatus == SCIP_STATUS_USERINTERRUPT )
    939 {
    941 }
    942
    943 return SCIP_OKAY;
    944}
    945
    946
    947
    948
    949
    950/*
    951 * relaxator specific interface methods
    952 */
    953
    954/** creates the benders relaxator and includes it in SCIP */
    956 SCIP* scip /**< SCIP data structure */
    957 )
    958{
    959 SCIP_RELAXDATA* relaxdata;
    960
    961 /* create benders relaxator data */
    962 relaxdata = NULL;
    964
    965 /* include relaxator */
    967 relaxCopyBenders, relaxFreeBenders, relaxInitBenders, relaxExitBenders, relaxInitsolBenders,
    968 relaxExitsolBenders, relaxExecBenders, relaxdata) );
    969
    970 /* adding parameters for the Benders' relaxator */
    971 SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/" RELAX_NAME "/continueorig",
    972 "continue solving the original SCIP instance if the optimal solution is not found by Benders' decomposition",
    973 &relaxdata->contorig, FALSE, DEFAULT_CONTORIG, NULL, NULL) );
    974
    975 SCIP_CALL( SCIPaddLongintParam(scip, "relaxing/" RELAX_NAME "/nodelimit",
    976 "the node limit applied only to the Benders' decomposition solve (-1 indicates that the original SCIP node limit is used).",
    977 &relaxdata->nodelimit, FALSE, DEFAULT_NODELIMIT, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
    978
    979 return SCIP_OKAY;
    980}
    981
    982/** returns the master problem SCIP instance */
    984 SCIP* scip /**< SCIP data structure */
    985 )
    986{
    987 SCIP_RELAX* relax;
    988 SCIP_RELAXDATA* relaxdata;
    989
    990 assert(scip != NULL);
    991
    992 relax = SCIPfindRelax(scip, RELAX_NAME);
    993 if( relax == NULL )
    994 return NULL;
    995
    996 relaxdata = SCIPrelaxGetData(relax);
    997 assert(relaxdata != NULL);
    998
    999 /* if the decomposition has not been applied, then there are no statistics to display */
    1000 if( !relaxdata->decompapplied )
    1001 return NULL;
    1002
    1003 return relaxdata->masterprob;
    1004}
    default Benders' decomposition plugin
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_Bool
    Definition: def.h:91
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_LONGINT_MAX
    Definition: def.h:142
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPcreateBendersDefault(SCIP *scip, SCIP **subproblems, int nsubproblems)
    SCIP_RETCODE SCIPincludeBendersDefault(SCIP *scip)
    SCIP_RETCODE SCIPcopyPlugins(SCIP *sourcescip, SCIP *targetscip, SCIP_Bool copyreaders, SCIP_Bool copypricers, SCIP_Bool copyconshdlrs, SCIP_Bool copyconflicthdlrs, SCIP_Bool copypresolvers, SCIP_Bool copyrelaxators, SCIP_Bool copyseparators, SCIP_Bool copycutselectors, SCIP_Bool copypropagators, SCIP_Bool copyheuristics, SCIP_Bool copyeventhdlrs, SCIP_Bool copynodeselectors, SCIP_Bool copybranchrules, SCIP_Bool copyiisfinders, SCIP_Bool copydisplays, SCIP_Bool copydialogs, SCIP_Bool copytables, SCIP_Bool copyexprhdlrs, SCIP_Bool copynlpis, SCIP_Bool passmessagehdlr, SCIP_Bool *valid)
    Definition: scip_copy.c:276
    SCIP_RETCODE SCIPcheckCopyLimits(SCIP *sourcescip, SCIP_Bool *success)
    Definition: scip_copy.c:3249
    SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
    Definition: scip_copy.c:1580
    SCIP_RETCODE SCIPcopyParamSettings(SCIP *sourcescip, SCIP *targetscip)
    Definition: scip_copy.c:2547
    SCIP_RETCODE SCIPcopyLimits(SCIP *sourcescip, SCIP *targetscip)
    Definition: scip_copy.c:3292
    void SCIPgetDecomps(SCIP *scip, SCIP_DECOMP ***decomps, int *ndecomps, SCIP_Bool original)
    Definition: scip_dcmp.c:263
    int SCIPdecompGetNBlocks(SCIP_DECOMP *decomp)
    Definition: dcmp.c:279
    void SCIPdecompGetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)
    Definition: dcmp.c:198
    void SCIPdecompGetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vars, int *labels, int nvars)
    Definition: dcmp.c:149
    const char * SCIPstatusName(SCIP_STATUS status)
    Definition: scip_general.c:576
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_RETCODE SCIPcreate(SCIP **scip)
    Definition: scip_general.c:370
    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
    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_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
    Definition: scip_prob.c:182
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    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
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
    Definition: scip_param.c:250
    SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:111
    SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:956
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
    Definition: scip_param.c:429
    int SCIPgetNActiveBenders(SCIP *scip)
    Definition: scip_benders.c:532
    SCIP_BENDERS * SCIPfindBenders(SCIP *scip, const char *name)
    Definition: scip_benders.c:493
    SCIP_RETCODE SCIPfreeBendersSubproblem(SCIP *scip, SCIP_BENDERS *benders, int probnumber)
    Definition: scip_benders.c:886
    SCIP_RETCODE SCIPsetupBendersSubproblem(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type)
    Definition: scip_benders.c:805
    SCIP_RETCODE SCIPsolveBendersSubproblem(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_Bool *infeasible, SCIP_Bool solvecip, SCIP_Real *objective)
    Definition: scip_benders.c:843
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6011
    SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6021
    SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
    Definition: scip_cons.c:2621
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8409
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
    Definition: cons.c:8598
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
    Definition: scip_cons.c:2577
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8578
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8628
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
    Definition: cons.c:8668
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8568
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8658
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPallocClearBlockMemory(scip, ptr)
    Definition: scip_mem.h:91
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    int SCIPgetNNlpis(SCIP *scip)
    Definition: scip_nlpi.c:205
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    SCIP_RETCODE SCIPincludeRelax(SCIP *scip, const char *name, const char *desc, int priority, int freq, SCIP_DECL_RELAXCOPY((*relaxcopy)), SCIP_DECL_RELAXFREE((*relaxfree)), SCIP_DECL_RELAXINIT((*relaxinit)), SCIP_DECL_RELAXEXIT((*relaxexit)), SCIP_DECL_RELAXINITSOL((*relaxinitsol)), SCIP_DECL_RELAXEXITSOL((*relaxexitsol)), SCIP_DECL_RELAXEXEC((*relaxexec)), SCIP_RELAXDATA *relaxdata)
    Definition: scip_relax.c:61
    SCIP_RELAX * SCIPfindRelax(SCIP *scip, const char *name)
    Definition: scip_relax.c:237
    SCIP_RELAXDATA * SCIPrelaxGetData(SCIP_RELAX *relax)
    Definition: relax.c:460
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:516
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:664
    SCIP_RETCODE SCIPaddSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *stored)
    Definition: scip_sol.c:3842
    SCIP_RETCODE SCIPcheckSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *feasible)
    Definition: scip_sol.c:4312
    SCIP_RETCODE SCIPtrySolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
    Definition: scip_sol.c:4109
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_RETCODE SCIPpresolve(SCIP *scip)
    Definition: scip_solve.c:2449
    SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
    Definition: scip_solve.c:3548
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2635
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
    Definition: var.c:23514
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
    Definition: scip_var.c:225
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
    Definition: var.c:23524
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
    Definition: var.c:23463
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    public methods for Benders' decomposition
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    public methods for relaxation handlers
    static SCIP_RETCODE addVariableToBendersProblem(SCIP *scip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_VAR *sourcevar)
    #define RELAX_DESC
    Definition: relax_benders.c:75
    static SCIP_RETCODE createOriginalSolution(SCIP *scip, SCIP_RELAX *relax, SCIP_Bool *infeasible)
    #define RELAX_PRIORITY
    Definition: relax_benders.c:76
    SCIP_RETCODE SCIPincludeRelaxBenders(SCIP *scip)
    static SCIP_RETCODE freeDecomposition(SCIP *scip, SCIP_RELAX *relax)
    static SCIP_RETCODE addInitialSolution(SCIP *scip, SCIP_RELAXDATA *relaxdata)
    #define RELAX_NAME
    Definition: relax_benders.c:74
    #define RELAX_FREQ
    Definition: relax_benders.c:77
    #define relaxExitBenders
    static SCIP_RETCODE freeBendersSubproblems(SCIP *scip, SCIP_RELAX *relax)
    SCIP * SCIPgetMasterProblemRelaxBenders(SCIP *scip)
    static SCIP_RETCODE solveBendersSubproblems(SCIP *scip, SCIP_RELAX *relax, SCIP_Bool *infeasible)
    #define relaxExitsolBenders
    static SCIP_DECL_RELAXEXEC(relaxExecBenders)
    static SCIP_RETCODE getNlpSolution(SCIP *scip, SCIP_SOL **nlpsol)
    #define DEFAULT_NODELIMIT
    Definition: relax_benders.c:80
    static SCIP_DECL_RELAXINITSOL(relaxInitsolBenders)
    static SCIP_Bool masterSolutionExists(SCIP *scip, SCIP_RELAX *relax)
    static SCIP_RETCODE setSolutionValues(SCIP *scip, SCIP_RELAX *relax, SCIP_SOL *sol)
    static SCIP_DECL_RELAXFREE(relaxFreeBenders)
    #define relaxInitBenders
    #define DEFAULT_CONTORIG
    Definition: relax_benders.c:79
    #define relaxCopyBenders
    static SCIP_RETCODE addConstraintToBendersProblem(SCIP *scip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_CONS *sourcecons)
    static SCIP_RETCODE applyDecomposition(SCIP *scip, SCIP_RELAX *relax, SCIP_DECOMP *decomp)
    benders relaxator
    SCIP callable library.
    type definitions for Benders' decomposition methods
    @ SCIP_BENDERSENFOTYPE_CHECK
    Definition: type_benders.h:54
    type definitions for message output methods
    @ SCIP_VERBLEVEL_NORMAL
    Definition: type_message.h:60
    @ SCIP_PARAMSETTING_OFF
    Definition: type_paramset.h:63
    type definitions for relaxators
    struct SCIP_RelaxData SCIP_RELAXDATA
    Definition: type_relax.h:52
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    type definitions for return codes for SCIP methods
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ 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
    type definitions for problem statistics
    @ SCIP_STATUS_PRIMALLIMIT
    Definition: type_stat.h:57
    @ SCIP_STATUS_GAPLIMIT
    Definition: type_stat.h:56
    @ 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_DUALLIMIT
    Definition: type_stat.h:58
    enum SCIP_Status SCIP_STATUS
    Definition: type_stat.h:64