SCIP

    Solving Constraint Integer Programs

    benderscut_opt.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file benderscut_opt.c
    26 * @ingroup OTHER_CFILES
    27 * @brief Generates a standard Benders' decomposition optimality cut
    28 * @author Stephen J. Maher
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "scip/pub_expr.h"
    34#include "scip/benderscut_opt.h"
    35#include "scip/cons_linear.h"
    36#include "scip/pub_benderscut.h"
    37#include "scip/pub_benders.h"
    38#include "scip/pub_lp.h"
    39#include "scip/pub_nlp.h"
    40#include "scip/pub_message.h"
    41#include "scip/pub_misc.h"
    43#include "scip/pub_var.h"
    44#include "scip/scip.h"
    45
    46
    47#define BENDERSCUT_NAME "optimality"
    48#define BENDERSCUT_DESC "Standard Benders' decomposition optimality cut"
    49#define BENDERSCUT_PRIORITY 5000
    50#define BENDERSCUT_LPCUT TRUE
    51
    52#define SCIP_DEFAULT_ADDCUTS FALSE /** Should cuts be generated, instead of constraints */
    53#define SCIP_DEFAULT_CALCMIR TRUE /** Should the mixed integer rounding procedure be used for the cut */
    54
    55/*
    56 * Data structures
    57 */
    58
    59/** Benders' decomposition cuts data */
    60struct SCIP_BenderscutData
    61{
    62 SCIP_Bool addcuts; /**< should cuts be generated instead of constraints */
    63 SCIP_Bool calcmir; /**< should the mixed integer rounding procedure be applied to cuts */
    64};
    65
    66
    67/*
    68 * Local methods
    69 */
    70
    71/** in the case of numerical troubles, the LP is resolved with solution polishing activated */
    72static
    74 SCIP* subproblem, /**< the SCIP data structure */
    75 SCIP_Bool* success /**< TRUE is the resolving of the LP was successful */
    76 )
    77{
    78 int oldpolishing;
    79 SCIP_Bool lperror;
    80 SCIP_Bool cutoff;
    81
    82 assert(subproblem != NULL);
    83 assert(SCIPinProbing(subproblem));
    84
    85 (*success) = FALSE;
    86
    87 /* setting the solution polishing parameter */
    88 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/solutionpolishing", &oldpolishing) );
    89 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/solutionpolishing", 2) );
    90
    91 /* resolving the probing LP */
    92 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
    93
    94 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL )
    95 (*success) = TRUE;
    96
    97 /* resetting the solution polishing parameter */
    98 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/solutionpolishing", oldpolishing) );
    99
    100 return SCIP_OKAY;
    101}
    102
    103/** verifying the activity of the cut when master variables are within epsilon of their upper or lower bounds
    104 *
    105 * When setting up the Benders' decomposition subproblem, master variables taking values that are within epsilon
    106 * greater than their upper bound or less than their lower bound are set to their upper and lower bounds respectively.
    107 * As such, there can be a difference between the subproblem dual solution objective and the optimality cut activity,
    108 * when computed using the master problem solution directly. This check is to verify whether this difference is an
    109 * actual error or due to the violation of the upper and lower bounds when setting up the Benders' decomposition
    110 * subproblem.
    111 */
    112static
    114 SCIP* masterprob, /**< the SCIP data structure */
    115 SCIP_SOL* sol, /**< the master problem solution */
    116 SCIP_VAR** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    117 SCIP_Real* vals, /**< pointer to array of coefficients of the variables in the generated cut */
    118 SCIP_Real lhs, /**< the left hand side of the cut */
    119 SCIP_Real checkobj, /**< the objective of the subproblem computed from the dual solution */
    120 int nvars, /**< the number of variables in the cut */
    121 SCIP_Bool* valid /**< returns true is the cut is valid */
    122 )
    123{
    124 SCIP_Real verifyobj;
    125 int i;
    126
    127 assert(masterprob != NULL);
    128 assert(vars != NULL);
    129 assert(vals != NULL);
    130
    131 /* initialising the verify objective with the left hand side of the optimality cut */
    132 verifyobj = lhs;
    133
    134 /* computing the activity of the cut from the master solution and the constraint values */
    135 for( i = 0; i < nvars; i++ )
    136 {
    137 SCIP_Real solval;
    138
    139 solval = SCIPgetSolVal(masterprob, sol, vars[i]);
    140
    141 /* checking whether the solution value is less than or greater than the variable bounds */
    142 if( !SCIPisLT(masterprob, solval, SCIPvarGetUbLocal(vars[i])) )
    143 solval = SCIPvarGetUbLocal(vars[i]);
    144 else if( !SCIPisGT(masterprob, solval, SCIPvarGetLbLocal(vars[i])) )
    145 solval = SCIPvarGetLbLocal(vars[i]);
    146
    147 verifyobj -= solval*vals[i];
    148 }
    149
    150 (*valid) = SCIPisFeasEQ(masterprob, checkobj, verifyobj);
    151
    152 return SCIP_OKAY;
    153}
    154
    155/** when solving NLP subproblems, numerical issues are addressed by tightening the feasibility tolerance */
    156static
    158 SCIP* subproblem, /**< the SCIP data structure */
    159 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    160 SCIP_Real multiplier, /**< the amount by which to decrease the tolerance */
    161 SCIP_Bool* success /**< TRUE is the resolving of the LP was successful */
    162 )
    163{
    164 SCIP_NLPSOLSTAT nlpsolstat;
    165#ifdef SCIP_DEBUG
    166 SCIP_NLPTERMSTAT nlptermstat;
    167#endif
    168 SCIP_NLPPARAM nlpparam = SCIPbendersGetNLPParam(benders);
    169#ifdef SCIP_MOREDEBUG
    170 SCIP_SOL* nlpsol;
    171#endif
    172
    173 assert(subproblem != NULL);
    174 assert(SCIPinProbing(subproblem));
    175
    176 (*success) = FALSE;
    177
    178 /* reduce the default feasibility and optimality tolerance by given factor (typically 0.01) */
    179 nlpparam.feastol *= multiplier;
    180 nlpparam.opttol *= multiplier;
    181
    182 SCIP_CALL( SCIPsolveNLPParam(subproblem, nlpparam) );
    183
    184 nlpsolstat = SCIPgetNLPSolstat(subproblem);
    185#ifdef SCIP_DEBUG
    186 nlptermstat = SCIPgetNLPTermstat(subproblem);
    187 SCIPdebugMsg(subproblem, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
    188#endif
    189
    190 if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT
    191 || nlpsolstat == SCIP_NLPSOLSTAT_FEASIBLE )
    192 {
    193#ifdef SCIP_MOREDEBUG
    194 SCIP_CALL( SCIPcreateNLPSol(subproblem, &nlpsol, NULL) );
    195 SCIP_CALL( SCIPprintSol(subproblem, nlpsol, NULL, FALSE) );
    196 SCIP_CALL( SCIPfreeSol(subproblem, &nlpsol) );
    197#endif
    198
    199 (*success) = TRUE;
    200 }
    201
    202 return SCIP_OKAY;
    203}
    204
    205/** adds a variable and value to the constraint/row arrays */
    206static
    208 SCIP* masterprob, /**< the SCIP instance of the master problem */
    209 SCIP_VAR*** vars, /**< pointer to the array of variables in the generated cut with non-zero coefficient */
    210 SCIP_Real** vals, /**< pointer to the array of coefficients of the variables in the generated cut */
    211 SCIP_VAR* addvar, /**< the variable that will be added to the array */
    212 SCIP_Real addval, /**< the value that will be added to the array */
    213 int* nvars, /**< the number of variables in the variable array */
    214 int* varssize /**< the length of the variable size */
    215 )
    216{
    217 assert(masterprob != NULL);
    218 assert(vars != NULL);
    219 assert(*vars != NULL);
    220 assert(vals != NULL);
    221 assert(*vals != NULL);
    222 assert(addvar != NULL);
    223 assert(nvars != NULL);
    224 assert(varssize != NULL);
    225
    226 if( *nvars >= *varssize )
    227 {
    228 *varssize = SCIPcalcMemGrowSize(masterprob, *varssize + 1);
    229 SCIP_CALL( SCIPreallocBufferArray(masterprob, vars, *varssize) );
    230 SCIP_CALL( SCIPreallocBufferArray(masterprob, vals, *varssize) );
    231 }
    232 assert(*nvars < *varssize);
    233
    234 (*vars)[*nvars] = addvar;
    235 (*vals)[*nvars] = addval;
    236 (*nvars)++;
    237
    238 return SCIP_OKAY;
    239}
    240
    241/** returns the variable solution either from the NLP or from the primal vals array */
    242static
    244 SCIP_VAR* var, /**< the variable for which the solution is requested */
    245 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    246 SCIP_HASHMAP* var2idx /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    247 )
    248{
    249 SCIP_Real varsol;
    250 int idx;
    251
    252 assert(var != NULL);
    253 assert((primalvals == NULL && var2idx == NULL) || (primalvals != NULL && var2idx != NULL));
    254
    255 if( var2idx != NULL && primalvals != NULL )
    256 {
    257 assert(SCIPhashmapExists(var2idx, (void*)var) );
    258 idx = SCIPhashmapGetImageInt(var2idx, (void*)var);
    259 varsol = primalvals[idx];
    260 }
    261 else
    262 varsol = SCIPvarGetNLPSol(var);
    263
    264 return varsol;
    265}
    266
    267/** calculates a MIR cut from the coefficients of the standard optimality cut */
    268static
    270 SCIP* masterprob, /**< the SCIP instance of the master problem */
    271 SCIP_SOL* sol, /**< primal CIP solution */
    272 SCIP_VAR** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    273 SCIP_Real* vals, /**< pointer to array of coefficients of the variables in the generated cut */
    274 SCIP_Real lhs, /**< the left hand side of the cut */
    275 int nvars, /**< the number of variables in the cut */
    276 SCIP_Real* cutcoefs, /**< the coefficients of the MIR cut */
    277 int* cutinds, /**< the variable indices of the MIR cut */
    278 SCIP_Real* cutrhs, /**< the RHS of the MIR cut */
    279 int* cutnnz, /**< the number of non-zeros in the cut */
    280 SCIP_Bool* success /**< was the MIR cut successfully computed? */
    281 )
    282{
    283 SCIP_AGGRROW* aggrrow;
    284 SCIP_Real* rowvals;
    285 int* rowinds;
    286
    287 SCIP_Real cutefficacy;
    288 int cutrank;
    289 SCIP_Bool cutislocal;
    290
    291 SCIP_Bool cutsuccess;
    292
    293 int i;
    294
    295 /* creating the aggregation row. There will be only a single row in this aggregation, since it is only used to
    296 * compute the MIR coefficients
    297 */
    298 SCIP_CALL( SCIPaggrRowCreate(masterprob, &aggrrow) );
    299
    300 /* retrieving the indices for the variables in the optimality cut. All of the values must be negated, since the
    301 * aggregation row requires a RHS, where the optimality cut is computed with an LHS
    302 */
    303 SCIP_CALL( SCIPallocBufferArray(masterprob, &rowvals, nvars) );
    304 SCIP_CALL( SCIPallocBufferArray(masterprob, &rowinds, nvars) );
    305
    306 assert(!SCIPisInfinity(masterprob, lhs));
    307 for( i = 0; i < nvars; i++ )
    308 {
    309 rowinds[i] = SCIPvarGetProbindex(vars[i]);
    310 assert(rowinds[i] >= 0);
    311 rowvals[i] = -vals[i];
    312 }
    313
    314 /* adding the optimality cut to the aggregation row */
    315 SCIP_CALL( SCIPaggrRowAddCustomCons(masterprob, aggrrow, rowinds, rowvals, nvars, -lhs, 1.0, 1, FALSE) );
    316
    317 /* calculating a flow cover for the optimality cut */
    318 cutefficacy = 0.0;
    319 SCIP_CALL( SCIPcalcFlowCover(masterprob, sol, TRUE, 0.9999, FALSE, aggrrow, cutcoefs, cutrhs, cutinds, cutnnz,
    320 &cutefficacy, NULL, &cutislocal, &cutsuccess) );
    321 (*success) = cutsuccess;
    322
    323 /* calculating the MIR coefficients for the optimality cut */
    324 SCIP_CALL( SCIPcalcMIR(masterprob, sol, TRUE, 0.9999, 1, FALSE, FALSE, NULL, NULL, 0.001, 0.999, 1.0, aggrrow,
    325 cutcoefs, cutrhs, cutinds, cutnnz, &cutefficacy, &cutrank, &cutislocal, &cutsuccess) );
    326 (*success) = ((*success) || cutsuccess);
    327
    328 /* the cut is only successful if the efficacy is high enough */
    329 (*success) = (*success) && SCIPisEfficacious(masterprob, cutefficacy);
    330
    331 /* try to tighten the coefficients of the cut */
    332 if( (*success) )
    333 {
    334 SCIP_Bool redundant;
    335 int nchgcoefs;
    336
    337 redundant = SCIPcutsTightenCoefficients(masterprob, FALSE, cutcoefs, cutrhs, cutinds, cutnnz, &nchgcoefs);
    338
    339 (*success) = !redundant;
    340 }
    341
    342 /* freeing the local memory */
    343 SCIPfreeBufferArray(masterprob, &rowinds);
    344 SCIPfreeBufferArray(masterprob, &rowvals);
    345 SCIPaggrRowFree(masterprob, &aggrrow);
    346
    347 return SCIP_OKAY;
    348}
    349
    350/** computes a standard Benders' optimality cut from the dual solutions of the LP */
    351static
    353 SCIP* masterprob, /**< the SCIP instance of the master problem */
    354 SCIP* subproblem, /**< the SCIP instance of the subproblem */
    355 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    356 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    357 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
    358 SCIP_Real* lhs, /**< the left hand side of the cut */
    359 int* nvars, /**< the number of variables in the cut */
    360 int* varssize, /**< the number of variables in the array */
    361 SCIP_Real* checkobj, /**< stores the objective function computed from the dual solution */
    362 SCIP_Bool* success /**< was the cut generation successful? */
    363 )
    364{
    365 SCIP_VAR** subvars;
    366 SCIP_VAR** fixedvars;
    367 int nsubvars;
    368 int nfixedvars;
    369 SCIP_Real dualsol;
    370 SCIP_Real addval;
    371 int nrows;
    372 int i;
    373
    374 assert(masterprob != NULL);
    375 assert(subproblem != NULL);
    376 assert(benders != NULL);
    377 assert(vars != NULL);
    378 assert(*vars != NULL);
    379 assert(vals != NULL);
    380 assert(*vals != NULL);
    381
    382 (*checkobj) = 0;
    383 (*success) = FALSE;
    384
    385 /* looping over all LP rows and setting the coefficients of the cut */
    386 nrows = SCIPgetNLPRows(subproblem);
    387 for( i = 0; i < nrows; i++ )
    388 {
    389 SCIP_ROW* lprow;
    390
    391 lprow = SCIPgetLPRows(subproblem)[i];
    392 assert(lprow != NULL);
    393
    394 dualsol = SCIProwGetDualsol(lprow);
    395 assert( !SCIPisInfinity(subproblem, dualsol) && !SCIPisInfinity(subproblem, -dualsol) );
    396
    397 if( SCIPisZero(subproblem, dualsol) )
    398 continue;
    399
    400 if( dualsol > 0.0 )
    401 addval = dualsol*SCIProwGetLhs(lprow);
    402 else
    403 addval = dualsol*SCIProwGetRhs(lprow);
    404
    405 (*lhs) += addval;
    406
    407 /* if the bound becomes infinite, then the cut generation terminates. */
    408 if( SCIPisInfinity(masterprob, (*lhs)) || SCIPisInfinity(masterprob, -(*lhs))
    409 || SCIPisInfinity(masterprob, addval) || SCIPisInfinity(masterprob, -addval))
    410 {
    411 (*success) = FALSE;
    412 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut. lhs = %g addval = %g.\n", (*lhs), addval);
    413 return SCIP_OKAY;
    414 }
    415 }
    416
    417 nsubvars = SCIPgetNVars(subproblem);
    418 subvars = SCIPgetVars(subproblem);
    419 nfixedvars = SCIPgetNFixedVars(subproblem);
    420 fixedvars = SCIPgetFixedVars(subproblem);
    421
    422 /* looping over all variables to update the coefficients in the computed cut. */
    423 for( i = 0; i < nsubvars + nfixedvars; i++ )
    424 {
    425 SCIP_VAR* var;
    426 SCIP_VAR* mastervar;
    427 SCIP_Real redcost;
    428
    429 if( i < nsubvars )
    430 var = subvars[i];
    431 else
    432 var = fixedvars[i - nsubvars];
    433
    434 /* retrieving the master problem variable for the given subproblem variable. */
    435 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
    436
    437 redcost = SCIPgetVarRedcost(subproblem, var);
    438
    439 (*checkobj) += SCIPvarGetUnchangedObj(var)*SCIPvarGetSol(var, TRUE);
    440
    441 /* checking whether the subproblem variable has a corresponding master variable. */
    442 if( mastervar != NULL )
    443 {
    444 SCIP_Real coef;
    445
    446 coef = -1.0*(SCIPvarGetObj(var) + redcost);
    447
    448 if( !SCIPisZero(masterprob, coef) )
    449 {
    450 /* adding the variable to the storage */
    451 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
    452 }
    453 }
    454 else
    455 {
    456 if( !SCIPisZero(subproblem, redcost) )
    457 {
    458 addval = 0;
    459
    460 if( SCIPisPositive(subproblem, redcost) )
    461 addval = redcost*SCIPvarGetLbLocal(var);
    462 else if( SCIPisNegative(subproblem, redcost) )
    463 addval = redcost*SCIPvarGetUbLocal(var);
    464
    465 (*lhs) += addval;
    466
    467 /* if the bound becomes infinite, then the cut generation terminates. */
    468 if( SCIPisInfinity(masterprob, (*lhs)) || SCIPisInfinity(masterprob, -(*lhs))
    469 || SCIPisInfinity(masterprob, addval) || SCIPisInfinity(masterprob, -addval))
    470 {
    471 (*success) = FALSE;
    472 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut.\n");
    473 return SCIP_OKAY;
    474 }
    475 }
    476 }
    477 }
    478
    479 (*success) = TRUE;
    480
    481 return SCIP_OKAY;
    482}
    483
    484/** computes a standard Benders' optimality cut from the dual solutions of the NLP */
    485static
    487 SCIP* masterprob, /**< the SCIP instance of the master problem */
    488 SCIP* subproblem, /**< the SCIP instance of the subproblem */
    489 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    490 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    491 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
    492 SCIP_Real* lhs, /**< the left hand side of the cut */
    493 int* nvars, /**< the number of variables in the cut */
    494 int* varssize, /**< the number of variables in the array */
    495 SCIP_Real objective, /**< the objective function of the subproblem */
    496 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    497 SCIP_Real* consdualvals, /**< dual variables for the constraints, can be NULL */
    498 SCIP_Real* varlbdualvals, /**< the dual variables for the variable lower bounds, can be NULL */
    499 SCIP_Real* varubdualvals, /**< the dual variables for the variable upper bounds, can be NULL */
    500 SCIP_HASHMAP* row2idx, /**< mapping between the row in the subproblem to the index in the dual array, can be NULL */
    501 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    502 SCIP_Real* checkobj, /**< stores the objective function computed from the dual solution */
    503 SCIP_Bool* success /**< was the cut generation successful? */
    504 )
    505{
    506 SCIP_VAR** subvars;
    507 SCIP_VAR** fixedvars;
    508 int nsubvars;
    509 int nfixedvars;
    510 SCIP_Real dirderiv;
    511 SCIP_Real dualsol;
    512 int nrows;
    513 int idx;
    514 int i;
    515
    516 assert(masterprob != NULL);
    517 assert(subproblem != NULL);
    518 assert(benders != NULL);
    519 assert(SCIPisNLPConstructed(subproblem));
    520 assert(SCIPgetNLPSolstat(subproblem) <= SCIP_NLPSOLSTAT_FEASIBLE || consdualvals != NULL);
    521 assert(SCIPhasNLPSolution(subproblem) || consdualvals != NULL);
    522
    523 (*checkobj) = 0;
    524 (*success) = FALSE;
    525
    526 if( !(primalvals == NULL && consdualvals == NULL && varlbdualvals == NULL && varubdualvals == NULL && row2idx == NULL && var2idx == NULL)
    527 && !(primalvals != NULL && consdualvals != NULL && varlbdualvals != NULL && varubdualvals != NULL && row2idx != NULL && var2idx != NULL) ) /*lint !e845*/
    528 {
    529 SCIPerrorMessage("The optimality cut must generated from either a SCIP instance or all of the dual solutions and indices must be supplied");
    530 (*success) = FALSE;
    531
    532 return SCIP_ERROR;
    533 }
    534
    535 nsubvars = SCIPgetNNLPVars(subproblem);
    536 subvars = SCIPgetNLPVars(subproblem);
    537 nfixedvars = SCIPgetNFixedVars(subproblem);
    538 fixedvars = SCIPgetFixedVars(subproblem);
    539
    540 /* our optimality cut implementation assumes that SCIP did not modify the objective function and sense,
    541 * that is, that the objective function value of the NLP corresponds to the value of the auxiliary variable
    542 * if that wouldn't be the case, then the scaling and offset may have to be considered when adding the
    543 * auxiliary variable to the cut (cons/row)?
    544 */
    545 assert(SCIPgetTransObjoffset(subproblem) == 0.0);
    546 assert(SCIPgetTransObjscale(subproblem) == 1.0);
    547 assert(SCIPgetObjsense(subproblem) == SCIP_OBJSENSE_MINIMIZE);
    548
    549 (*lhs) = objective;
    550 assert(!SCIPisInfinity(subproblem, REALABS(*lhs)));
    551
    552 dirderiv = 0.0;
    553
    554 /* looping over all NLP rows and setting the corresponding coefficients of the cut */
    555 nrows = SCIPgetNNLPNlRows(subproblem);
    556 for( i = 0; i < nrows; i++ )
    557 {
    558 SCIP_NLROW* nlrow;
    559
    560 nlrow = SCIPgetNLPNlRows(subproblem)[i];
    561 assert(nlrow != NULL);
    562
    563 if( row2idx != NULL && consdualvals != NULL )
    564 {
    565 assert(SCIPhashmapExists(row2idx, (void*)nlrow) );
    566 idx = SCIPhashmapGetImageInt(row2idx, (void*)nlrow);
    567 dualsol = consdualvals[idx];
    568 }
    569 else
    570 dualsol = SCIPnlrowGetDualsol(nlrow);
    571 assert( !SCIPisInfinity(subproblem, dualsol) && !SCIPisInfinity(subproblem, -dualsol) );
    572
    573 if( SCIPisZero(subproblem, dualsol) )
    574 continue;
    575
    576 SCIP_CALL( SCIPaddNlRowGradientBenderscutOpt(masterprob, subproblem, benders, nlrow,
    577 -dualsol, primalvals, var2idx, &dirderiv, vars, vals, nvars, varssize) );
    578 }
    579
    580 /* looping over sub- and fixed variables to compute checkobj */
    581 for( i = 0; i < nsubvars; i++ )
    582 (*checkobj) += SCIPvarGetObj(subvars[i]) * getNlpVarSol(subvars[i], primalvals, var2idx);
    583
    584 for( i = 0; i < nfixedvars; i++ )
    585 *checkobj += SCIPvarGetUnchangedObj(fixedvars[i]) * getNlpVarSol(fixedvars[i], primalvals, var2idx);
    586
    587 *lhs += dirderiv;
    588
    589 /* if the side became infinite or dirderiv was infinite, then the cut generation terminates. */
    590 if( SCIPisInfinity(masterprob, *lhs) || SCIPisInfinity(masterprob, -*lhs)
    591 || SCIPisInfinity(masterprob, dirderiv) || SCIPisInfinity(masterprob, -dirderiv))
    592 {
    593 (*success) = FALSE;
    594 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut. lhs = %g dirderiv = %g.\n", *lhs, dirderiv);
    595 return SCIP_OKAY;
    596 }
    597
    598 (*success) = TRUE;
    599
    600 return SCIP_OKAY;
    601}
    602
    603
    604/** Adds the auxiliary variable to the generated cut. If this is the first optimality cut for the subproblem, then the
    605 * auxiliary variable is first created and added to the master problem.
    606 */
    607static
    609 SCIP* masterprob, /**< the SCIP instance of the master problem */
    610 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    611 SCIP_VAR** vars, /**< the variables in the generated cut with non-zero coefficient */
    612 SCIP_Real* vals, /**< the coefficients of the variables in the generated cut */
    613 int* nvars, /**< the number of variables in the cut */
    614 int probnumber /**< the number of the pricing problem */
    615 )
    616{
    617 SCIP_VAR* auxiliaryvar;
    618
    619 assert(masterprob != NULL);
    620 assert(benders != NULL);
    621 assert(vars != NULL);
    622 assert(vals != NULL);
    623
    624 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
    625
    626 vars[(*nvars)] = auxiliaryvar;
    627 vals[(*nvars)] = 1.0;
    628 (*nvars)++;
    629
    630 return SCIP_OKAY;
    631}
    632
    633
    634/*
    635 * Callback methods of Benders' decomposition cuts
    636 */
    637
    638/** destructor of Benders' decomposition cuts to free user data (called when SCIP is exiting) */
    639static
    640SCIP_DECL_BENDERSCUTFREE(benderscutFreeOpt)
    641{ /*lint --e{715}*/
    642 SCIP_BENDERSCUTDATA* benderscutdata;
    643
    644 assert( benderscut != NULL );
    645
    647
    648 /* free Benders' cut data */
    649 benderscutdata = SCIPbenderscutGetData(benderscut);
    650 assert( benderscutdata != NULL );
    651
    652 SCIPfreeBlockMemory(scip, &benderscutdata);
    653
    654 SCIPbenderscutSetData(benderscut, NULL);
    655
    656 return SCIP_OKAY;
    657}
    658
    659
    660/** execution method of Benders' decomposition cuts */
    661static
    662SCIP_DECL_BENDERSCUTEXEC(benderscutExecOpt)
    663{ /*lint --e{715}*/
    664 SCIP* subproblem;
    665 SCIP_BENDERSCUTDATA* benderscutdata;
    666 SCIP_Bool nlprelaxation;
    667 SCIP_Bool addcut;
    668 char cutname[SCIP_MAXSTRLEN];
    669
    670 assert(scip != NULL);
    671 assert(benders != NULL);
    672 assert(benderscut != NULL);
    673 assert(result != NULL);
    674 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
    675
    676 /* retrieving the Benders' cut data */
    677 benderscutdata = SCIPbenderscutGetData(benderscut);
    678
    679 /* if the cuts are generated prior to the solving stage, then rows can not be generated. So constraints must be
    680 * added to the master problem.
    681 */
    683 addcut = FALSE;
    684 else
    685 addcut = benderscutdata->addcuts;
    686
    687 /* setting the name of the generated cut */
    688 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "optimalitycut_%d_%" SCIP_LONGINT_FORMAT, probnumber,
    689 SCIPbenderscutGetNFound(benderscut) );
    690
    691 subproblem = SCIPbendersSubproblem(benders, probnumber);
    692
    693 if( subproblem == NULL )
    694 {
    695 SCIPdebugMsg(scip, "The subproblem %d is set to NULL. The <%s> Benders' decomposition cut can not be executed.\n",
    696 probnumber, BENDERSCUT_NAME);
    697
    698 (*result) = SCIP_DIDNOTRUN;
    699 return SCIP_OKAY;
    700 }
    701
    702 /* setting a flag to indicate whether the NLP relaxation should be used to generate cuts */
    703 nlprelaxation = SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem);
    704
    705 /* only generate optimality cuts if the subproblem LP or NLP is optimal,
    706 * since we use the dual solution of the LP/NLP to construct the optimality cut
    707 */
    708 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING &&
    709 ((!nlprelaxation && SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL) ||
    710 (nlprelaxation && SCIPgetNLPSolstat(subproblem) <= SCIP_NLPSOLSTAT_FEASIBLE)) )
    711 {
    712 /* generating a cut for a given subproblem */
    713 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
    714 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
    715 FALSE, result) );
    716
    717 /* if it was not possible to generate a cut, this could be due to numerical issues. So the solution to the LP is
    718 * resolved and the generation of the cut is reattempted. For NLPs, we do not have such a polishing yet.
    719 */
    720 if( (*result) == SCIP_DIDNOTFIND )
    721 {
    722 SCIP_Bool success;
    723
    724 SCIPdebugMsg(scip, "Numerical trouble generating optimality cut for subproblem %d.\n", probnumber);
    725
    726 if( !nlprelaxation )
    727 {
    728 SCIPdebugMsg(scip, "Attempting to polish the LP solution to find an alternative dual extreme point.\n");
    729
    730 SCIP_CALL( polishSolution(subproblem, &success) );
    731
    732 /* only attempt to generate a cut if the solution polishing was successful */
    733 if( success )
    734 {
    735 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
    736 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
    737 FALSE, result) );
    738 }
    739 }
    740 else
    741 {
    742 SCIP_Real multiplier = 0.01;
    743
    744 SCIPdebugMsg(scip, "Attempting to resolve the NLP with a tighter feasibility tolerance to find an "
    745 "alternative dual extreme point.\n");
    746
    747 while( multiplier > 1e-06 && (*result) == SCIP_DIDNOTFIND )
    748 {
    749 SCIP_CALL( resolveNLPWithTighterFeastol(subproblem, benders, multiplier, &success) );
    750
    751 if( success )
    752 {
    753 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
    754 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
    755 FALSE, result) );
    756 }
    757
    758 multiplier *= 0.1;
    759 }
    760 }
    761 }
    762 }
    763
    764 return SCIP_OKAY;
    765}
    766
    767
    768/*
    769 * Benders' decomposition cuts specific interface methods
    770 */
    771
    772/** creates the opt Benders' decomposition cuts and includes it in SCIP */
    774 SCIP* scip, /**< SCIP data structure */
    775 SCIP_BENDERS* benders /**< Benders' decomposition */
    776 )
    777{
    778 SCIP_BENDERSCUTDATA* benderscutdata;
    779 SCIP_BENDERSCUT* benderscut;
    781
    782 assert(benders != NULL);
    783
    784 /* create opt Benders' decomposition cuts data */
    785 SCIP_CALL( SCIPallocBlockMemory(scip, &benderscutdata) );
    786
    787 benderscut = NULL;
    788
    789 /* include Benders' decomposition cuts */
    791 BENDERSCUT_PRIORITY, BENDERSCUT_LPCUT, benderscutExecOpt, benderscutdata) );
    792
    793 assert(benderscut != NULL);
    794
    795 /* setting the non fundamental callbacks via setter functions */
    796 SCIP_CALL( SCIPsetBenderscutFree(scip, benderscut, benderscutFreeOpt) );
    797
    798 /* add opt Benders' decomposition cuts parameters */
    799 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/addcuts",
    802 "should cuts be generated and added to the cutpool instead of global constraints directly added to the problem.",
    803 &benderscutdata->addcuts, FALSE, SCIP_DEFAULT_ADDCUTS, NULL, NULL) );
    804
    805 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/mir",
    808 "should the mixed integer rounding procedure be applied to cuts",
    809 &benderscutdata->calcmir, FALSE, SCIP_DEFAULT_CALCMIR, NULL, NULL) );
    810
    811 return SCIP_OKAY;
    812}
    813
    814/** Generates a classical Benders' optimality cut using the dual solutions from the subproblem or the input arrays. If
    815 * the dual solutions are input as arrays, then a mapping between the array indices and the rows/variables is required.
    816 * As a cut strengthening approach, when an optimality cut is being generated (i.e. not for feasibility cuts) a MIR
    817 * procedure is performed on the row. This procedure attempts to find a stronger constraint, if this doesn't happen,
    818 * then the original constraint is added to SCIP.
    819 *
    820 * This method can also be used to generate a feasibility cut, if a problem to minimise the infeasibilities has been solved
    821 * to generate the dual solutions
    822 */
    824 SCIP* masterprob, /**< the SCIP instance of the master problem */
    825 SCIP* subproblem, /**< the SCIP instance of the pricing problem */
    826 SCIP_BENDERS* benders, /**< the benders' decomposition */
    827 SCIP_BENDERSCUT* benderscut, /**< the benders' decomposition cut method */
    828 SCIP_SOL* sol, /**< primal CIP solution */
    829 int probnumber, /**< the number of the pricing problem */
    830 char* cutname, /**< the name for the cut to be generated */
    831 SCIP_Real objective, /**< the objective function of the subproblem */
    832 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    833 SCIP_Real* consdualvals, /**< dual variables for the constraints, can be NULL */
    834 SCIP_Real* varlbdualvals, /**< the dual variables for the variable lower bounds, can be NULL */
    835 SCIP_Real* varubdualvals, /**< the dual variables for the variable upper bounds, can be NULL */
    836 SCIP_HASHMAP* row2idx, /**< mapping between the row in the subproblem to the index in the dual array, can be NULL */
    837 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    838 SCIP_BENDERSENFOTYPE type, /**< the enforcement type calling this function */
    839 SCIP_Bool addcut, /**< should the Benders' cut be added as a cut or constraint */
    840 SCIP_Bool feasibilitycut, /**< is this called for the generation of a feasibility cut */
    841 SCIP_RESULT* result /**< the result from solving the subproblems */
    842 )
    843{
    844 SCIP_CONSHDLR* consbenders;
    845 SCIP_CONS* cons;
    846 SCIP_ROW* row;
    847 SCIP_VAR** vars;
    848 SCIP_Real* vals;
    849 SCIP_Real lhs;
    850 SCIP_Real rhs;
    851 int nvars;
    852 int varssize;
    853 int nmastervars;
    854 SCIP_Bool calcmir;
    855 SCIP_Bool optimal;
    856 SCIP_Bool success;
    857 SCIP_Bool mirsuccess;
    858
    859 SCIP_Real checkobj;
    860 SCIP_Real verifyobj;
    861
    862 assert(masterprob != NULL);
    863 assert(subproblem != NULL);
    864 assert(benders != NULL);
    865 assert(benderscut != NULL);
    866 assert(result != NULL);
    867 assert((primalvals == NULL && consdualvals == NULL && varlbdualvals == NULL && varubdualvals == NULL
    868 && row2idx == NULL && var2idx == NULL)
    869 || (primalvals != NULL && consdualvals != NULL && varlbdualvals != NULL && varubdualvals != NULL
    870 && row2idx != NULL && var2idx != NULL));
    871
    872 row = NULL;
    873 cons = NULL;
    874
    875 calcmir = SCIPbenderscutGetData(benderscut)->calcmir && SCIPgetStage(masterprob) >= SCIP_STAGE_INITSOLVE && SCIPgetSubscipDepth(masterprob) == 0;
    876 success = FALSE;
    877 mirsuccess = FALSE;
    878
    879 /* retrieving the Benders' decomposition constraint handler */
    880 consbenders = SCIPfindConshdlr(masterprob, "benders");
    881
    882 /* checking the optimality of the original problem with a comparison between the auxiliary variable and the
    883 * objective value of the subproblem */
    884 if( feasibilitycut )
    885 optimal = FALSE;
    886 else
    887 {
    888 SCIP_CALL( SCIPcheckBendersSubproblemOptimality(masterprob, benders, sol, probnumber, &optimal) );
    889 }
    890
    891 if( optimal )
    892 {
    893 (*result) = SCIP_FEASIBLE;
    894 SCIPdebugMsg(masterprob, "No cut added for subproblem %d\n", probnumber);
    895 return SCIP_OKAY;
    896 }
    897
    898 /* allocating memory for the variable and values arrays */
    899 nmastervars = SCIPgetNVars(masterprob) + SCIPgetNFixedVars(masterprob);
    900 SCIP_CALL( SCIPallocClearBufferArray(masterprob, &vars, nmastervars) );
    901 SCIP_CALL( SCIPallocClearBufferArray(masterprob, &vals, nmastervars) );
    902 lhs = 0.0;
    903 rhs = SCIPinfinity(masterprob);
    904 nvars = 0;
    905 varssize = nmastervars;
    906
    907 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) )
    908 {
    909 /* computing the coefficients of the optimality cut */
    910 SCIP_CALL( computeStandardNLPOptimalityCut(masterprob, subproblem, benders, &vars, &vals, &lhs, &nvars,
    911 &varssize, objective, primalvals, consdualvals, varlbdualvals, varubdualvals, row2idx,
    912 var2idx, &checkobj, &success) );
    913 }
    914 else
    915 {
    916 /* computing the coefficients of the optimality cut */
    917 SCIP_CALL( computeStandardLPOptimalityCut(masterprob, subproblem, benders, &vars, &vals, &lhs, &nvars,
    918 &varssize, &checkobj, &success) );
    919 }
    920 assert(SCIPisInfinity(masterprob, rhs));
    921
    922 /* if success is FALSE, then there was an error in generating the optimality cut. No cut will be added to the master
    923 * problem. Otherwise, the constraint is added to the master problem.
    924 */
    925 if( !success )
    926 {
    927 (*result) = SCIP_DIDNOTFIND;
    928 SCIPdebugMsg(masterprob, "Error in generating Benders' optimality cut for problem %d.\n", probnumber);
    929 }
    930 else
    931 {
    932 /* initially a row/constraint is created for the optimality cut using the master variables and coefficients
    933 * computed in computeStandardLPOptimalityCut. At this stage, the auxiliary variable is not added since the
    934 * activity of the row/constraint in its current form is used to determine the validity of the optimality cut.
    935 */
    936 if( addcut )
    937 {
    938 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname, lhs, rhs, FALSE, FALSE, TRUE) );
    939 SCIP_CALL( SCIPaddVarsToRow(masterprob, row, nvars, vars, vals) );
    940 }
    941 else
    942 {
    943 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, nvars, vars, vals, lhs, rhs) );
    944 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
    945 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
    946 }
    947
    948 /* computing the objective function from the cut activity to verify the accuracy of the constraint */
    949 verifyobj = 0.0;
    950 if( addcut )
    951 {
    952 verifyobj += SCIProwGetLhs(row) - SCIPgetRowSolActivity(masterprob, row, sol);
    953 }
    954 else
    955 {
    956 verifyobj += SCIPgetLhsLinear(masterprob, cons) - SCIPgetActivityLinear(masterprob, cons, sol);
    957 }
    958
    959 if( feasibilitycut && verifyobj < SCIPfeastol(masterprob) )
    960 {
    961 success = FALSE;
    962 SCIPdebugMsg(masterprob, "The violation of the feasibility cut (%g) is too small. Skipping feasibility cut.\n", verifyobj);
    963 }
    964
    965 /* it is possible that numerics will cause the generated cut to be invalid. This cut should not be added to the
    966 * master problem, since its addition could cut off feasible solutions. The success flag is set of false, indicating
    967 * that the Benders' cut could not find a valid cut.
    968 */
    969 if( !feasibilitycut && !SCIPisFeasEQ(masterprob, checkobj, verifyobj) )
    970 {
    971 SCIP_Bool valid;
    972
    973 /* the difference in the checkobj and verifyobj could be due to the setup tolerances. This is checked, and if
    974 * so, then the generated cut is still valid
    975 */
    976 SCIP_CALL( checkSetupTolerances(masterprob, sol, vars, vals, lhs, checkobj, nvars, &valid) );
    977
    978 if( !valid )
    979 {
    980 success = FALSE;
    981 SCIPdebugMsg(masterprob, "The objective function and cut activity are not equal (%g != %g).\n", checkobj,
    982 verifyobj);
    983
    984#ifdef SCIP_DEBUG
    985 /* we only need to abort if cut strengthen is not used. If cut strengthen has been used in this round and the
    986 * cut could not be generated, then another subproblem solving round will be executed
    987 */
    988 if( !SCIPbendersInStrengthenRound(benders) )
    989 {
    990#ifdef SCIP_MOREDEBUG
    991 int i;
    992
    993 for( i = 0; i < nvars; i++ )
    994 printf("<%s> %g %g\n", SCIPvarGetName(vars[i]), vals[i], SCIPgetSolVal(masterprob, sol, vars[i]));
    995#endif
    996 SCIPABORT();
    997 }
    998#endif
    999 }
    1000 }
    1001
    1002 if( success )
    1003 {
    1004 /* adding the auxiliary variable to the optimality cut. The auxiliary variable is added to the vars and vals
    1005 * arrays prior to the execution of the MIR procedure. This is necessary because the MIR procedure must be
    1006 * executed on the complete cut, not just the row/constraint without the auxiliary variable.
    1007 */
    1008 if( !feasibilitycut )
    1009 {
    1010 SCIP_CALL( addAuxiliaryVariableToCut(masterprob, benders, vars, vals, &nvars, probnumber) );
    1011 }
    1012
    1013 /* performing the MIR procedure. If the procedure is successful, then the vars and vals arrays are no longer
    1014 * needed for creating the optimality cut. These are superseeded with the cutcoefs and cutinds arrays. In the
    1015 * case that the MIR procedure is successful, the row/constraint that has been created previously is destroyed
    1016 * and the MIR cut is added in its place
    1017 */
    1018 if( calcmir )
    1019 {
    1020 SCIP_Real* cutcoefs;
    1021 int* cutinds;
    1022 SCIP_Real cutrhs;
    1023 int cutnnz;
    1024
    1025 /* allocating memory to compute the MIR cut */
    1026 SCIP_CALL( SCIPallocBufferArray(masterprob, &cutcoefs, nvars) );
    1027 SCIP_CALL( SCIPallocBufferArray(masterprob, &cutinds, nvars) );
    1028
    1029 SCIP_CALL( computeMIRForOptimalityCut(masterprob, sol, vars, vals, lhs, nvars, cutcoefs,
    1030 cutinds, &cutrhs, &cutnnz, &mirsuccess) );
    1031
    1032 /* if the MIR cut was computed successfully, then the current row/constraint needs to be destroyed and
    1033 * replaced with the updated coefficients
    1034 */
    1035 if( mirsuccess )
    1036 {
    1037 SCIP_VAR** mastervars;
    1038 int i;
    1039
    1040 mastervars = SCIPgetVars(masterprob);
    1041
    1042 if( addcut )
    1043 {
    1044 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
    1045
    1046 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname,
    1047 -SCIPinfinity(masterprob), cutrhs, FALSE, FALSE, TRUE) );
    1048
    1049 for( i = 0; i < cutnnz; i++)
    1050 {
    1051 SCIP_CALL( SCIPaddVarToRow(masterprob, row, mastervars[cutinds[i]], cutcoefs[i]) );
    1052 }
    1053 }
    1054 else
    1055 {
    1056 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
    1057
    1058 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, 0, NULL, NULL,
    1059 -SCIPinfinity(masterprob), cutrhs) );
    1060 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
    1061 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
    1062
    1063 for( i = 0; i < cutnnz; i++ )
    1064 {
    1065 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, mastervars[cutinds[i]], cutcoefs[i]) );
    1066 }
    1067 }
    1068 }
    1069
    1070 /* freeing the memory required to compute the MIR cut */
    1071 SCIPfreeBufferArray(masterprob, &cutinds);
    1072 SCIPfreeBufferArray(masterprob, &cutcoefs);
    1073 }
    1074
    1075 /* adding the constraint to the master problem */
    1076 if( addcut )
    1077 {
    1078 SCIP_Bool infeasible;
    1079
    1080 /* adding the auxiliary variable coefficient to the row. This is only added if the MIR procedure is not
    1081 * successful. If the MIR procedure was successful, then the auxiliary variable is already included in the
    1082 * row
    1083 */
    1084 if( !feasibilitycut && !mirsuccess )
    1085 {
    1086 SCIP_CALL( SCIPaddVarToRow(masterprob, row, vars[nvars - 1], vals[nvars - 1]) );
    1087 }
    1088
    1090 {
    1091 SCIP_CALL( SCIPaddRow(masterprob, row, FALSE, &infeasible) );
    1092 assert(!infeasible);
    1093 }
    1094 else
    1095 {
    1097 SCIP_CALL( SCIPaddPoolCut(masterprob, row) );
    1098 }
    1099
    1100 (*result) = SCIP_SEPARATED;
    1101 }
    1102 else
    1103 {
    1104 /* adding the auxiliary variable coefficient to the row. This is only added if the MIR procedure is not
    1105 * successful. If the MIR procedure was successful, then the auxiliary variable is already included in the
    1106 * constraint.
    1107 */
    1108 if( !feasibilitycut && !mirsuccess )
    1109 {
    1110 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, vars[nvars - 1], vals[nvars - 1]) );
    1111 }
    1112
    1113 SCIPdebugPrintCons(masterprob, cons, NULL);
    1114
    1115 SCIP_CALL( SCIPaddCons(masterprob, cons) );
    1116
    1117 (*result) = SCIP_CONSADDED;
    1118 }
    1119
    1120 /* storing the data that is used to create the cut */
    1121 SCIP_CALL( SCIPstoreBendersCut(masterprob, benders, vars, vals, lhs, rhs, nvars) );
    1122 }
    1123 else
    1124 {
    1125 (*result) = SCIP_DIDNOTFIND;
    1126 SCIPdebugMsg(masterprob, "Error in generating Benders' %s cut for problem %d.\n", feasibilitycut ? "feasibility" : "optimality", probnumber);
    1127 }
    1128
    1129 /* releasing the row or constraint */
    1130 if( addcut )
    1131 {
    1132 /* release the row */
    1133 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
    1134 }
    1135 else
    1136 {
    1137 /* release the constraint */
    1138 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
    1139 }
    1140 }
    1141
    1142 SCIPfreeBufferArray(masterprob, &vals);
    1143 SCIPfreeBufferArray(masterprob, &vars);
    1144
    1145 return SCIP_OKAY;
    1146}
    1147
    1148
    1149/** adds the gradient of a nonlinear row in the current NLP solution of a subproblem to a linear row or constraint in the master problem
    1150 *
    1151 * Only computes gradient w.r.t. master problem variables.
    1152 * Computes also the directional derivative, that is, mult times gradient times solution.
    1153 */
    1155 SCIP* masterprob, /**< the SCIP instance of the master problem */
    1156 SCIP* subproblem, /**< the SCIP instance of the subproblem */
    1157 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
    1158 SCIP_NLROW* nlrow, /**< nonlinear row */
    1159 SCIP_Real mult, /**< multiplier */
    1160 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
    1161 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
    1162 SCIP_Real* dirderiv, /**< storage to add directional derivative */
    1163 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
    1164 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
    1165 int* nvars, /**< the number of variables in the cut */
    1166 int* varssize /**< the number of variables in the array */
    1167 )
    1168{
    1169 SCIP_EXPR* expr;
    1170 SCIP_VAR* var;
    1171 SCIP_VAR* mastervar;
    1172 SCIP_Real coef;
    1173 int i;
    1174
    1175 assert(masterprob != NULL);
    1176 assert(subproblem != NULL);
    1177 assert(benders != NULL);
    1178 assert(nlrow != NULL);
    1179 assert((primalvals == NULL && var2idx == NULL) || (primalvals != NULL && var2idx != NULL));
    1180 assert(mult != 0.0);
    1181 assert(dirderiv != NULL);
    1182 assert(vars != NULL);
    1183 assert(vals != NULL);
    1184
    1185 /* linear part */
    1186 for( i = 0; i < SCIPnlrowGetNLinearVars(nlrow); i++ )
    1187 {
    1188 var = SCIPnlrowGetLinearVars(nlrow)[i];
    1189 assert(var != NULL);
    1190
    1191 /* retrieving the master problem variable for the given subproblem variable. */
    1192 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
    1193 if( mastervar == NULL )
    1194 continue;
    1195
    1196 coef = mult * SCIPnlrowGetLinearCoefs(nlrow)[i];
    1197
    1198 /* adding the variable to the storage */
    1199 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
    1200
    1201 *dirderiv += coef * getNlpVarSol(var, primalvals, var2idx);
    1202 }
    1203
    1204 /* expression part */
    1205 expr = SCIPnlrowGetExpr(nlrow);
    1206 if( expr != NULL )
    1207 {
    1208 SCIP_SOL* primalsol;
    1209 SCIP_EXPRITER* it;
    1210
    1211 /* create primalsol, either from primalvals, or pointing to NLP solution */
    1212 if( primalvals != NULL )
    1213 {
    1214 SCIP_CALL( SCIPcreateSol(subproblem, &primalsol, NULL) );
    1215
    1216 /* TODO would be better to change primalvals to a SCIP_SOL and do this once for the whole NLP instead of repeating it for each expr */
    1217 for( i = 0; i < SCIPhashmapGetNEntries(var2idx); ++i )
    1218 {
    1219 SCIP_HASHMAPENTRY* entry;
    1220 entry = SCIPhashmapGetEntry(var2idx, i);
    1221 if( entry == NULL )
    1222 continue;
    1223 SCIP_CALL( SCIPsetSolVal(subproblem, primalsol, (SCIP_VAR*) SCIPhashmapEntryGetOrigin(entry), primalvals[SCIPhashmapEntryGetImageInt(entry)]) );
    1224 }
    1225 }
    1226 else
    1227 {
    1228 SCIP_CALL( SCIPcreateNLPSol(subproblem, &primalsol, NULL) );
    1229 }
    1230
    1231 /* eval gradient */
    1232 SCIP_CALL( SCIPevalExprGradient(subproblem, expr, primalsol, 0L) );
    1233
    1234 assert(SCIPexprGetDerivative(expr) != SCIP_INVALID); /* TODO this should be a proper check&abort */ /*lint !e777*/
    1235
    1236 SCIP_CALL( SCIPfreeSol(subproblem, &primalsol) );
    1237
    1238 /* update corresponding gradient entry */
    1239 SCIP_CALL( SCIPcreateExpriter(subproblem, &it) );
    1241 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) /*lint !e441*/ /*lint !e440*/
    1242 {
    1243 if( !SCIPisExprVar(subproblem, expr) )
    1244 continue;
    1245
    1246 var = SCIPgetVarExprVar(expr);
    1247 assert(var != NULL);
    1248
    1249 /* retrieving the master problem variable for the given subproblem variable. */
    1250 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
    1251 if( mastervar == NULL )
    1252 continue;
    1253
    1254 assert(SCIPexprGetDerivative(expr) != SCIP_INVALID); /*lint !e777*/
    1255 coef = mult * SCIPexprGetDerivative(expr);
    1256
    1257 /* adding the variable to the storage */
    1258 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
    1259
    1260 *dirderiv += coef * getNlpVarSol(var, primalvals, var2idx);
    1261 }
    1262 SCIPfreeExpriter(&it);
    1263 }
    1264
    1265 return SCIP_OKAY;
    1266}
    static SCIP_RETCODE computeStandardNLPOptimalityCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, int *nvars, int *varssize, SCIP_Real objective, SCIP_Real *primalvals, SCIP_Real *consdualvals, SCIP_Real *varlbdualvals, SCIP_Real *varubdualvals, SCIP_HASHMAP *row2idx, SCIP_HASHMAP *var2idx, SCIP_Real *checkobj, SCIP_Bool *success)
    static SCIP_RETCODE checkSetupTolerances(SCIP *masterprob, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real checkobj, int nvars, SCIP_Bool *valid)
    #define SCIP_DEFAULT_ADDCUTS
    static SCIP_RETCODE addVariableToArray(SCIP *masterprob, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_VAR *addvar, SCIP_Real addval, int *nvars, int *varssize)
    #define BENDERSCUT_LPCUT
    static SCIP_RETCODE computeStandardLPOptimalityCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, int *nvars, int *varssize, SCIP_Real *checkobj, SCIP_Bool *success)
    static SCIP_RETCODE addAuxiliaryVariableToCut(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_VAR **vars, SCIP_Real *vals, int *nvars, int probnumber)
    #define SCIP_DEFAULT_CALCMIR
    static SCIP_DECL_BENDERSCUTEXEC(benderscutExecOpt)
    static SCIP_Real getNlpVarSol(SCIP_VAR *var, SCIP_Real *primalvals, SCIP_HASHMAP *var2idx)
    #define BENDERSCUT_PRIORITY
    #define BENDERSCUT_DESC
    static SCIP_RETCODE computeMIRForOptimalityCut(SCIP *masterprob, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, int nvars, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real *cutrhs, int *cutnnz, SCIP_Bool *success)
    #define BENDERSCUT_NAME
    static SCIP_RETCODE polishSolution(SCIP *subproblem, SCIP_Bool *success)
    static SCIP_RETCODE resolveNLPWithTighterFeastol(SCIP *subproblem, SCIP_BENDERS *benders, SCIP_Real multiplier, SCIP_Bool *success)
    static SCIP_DECL_BENDERSCUTFREE(benderscutFreeOpt)
    Generates a standard Benders' decomposition optimality cut.
    Constraint handler for linear constraints in their most general form, .
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #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 SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIPABORT()
    Definition: def.h:336
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_RETCODE SCIPgenerateAndApplyBendersOptCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, SCIP_SOL *sol, int probnumber, char *cutname, SCIP_Real objective, SCIP_Real *primalvals, SCIP_Real *consdualvals, SCIP_Real *varlbdualvals, SCIP_Real *varubdualvals, SCIP_HASHMAP *row2idx, SCIP_HASHMAP *var2idx, SCIP_BENDERSENFOTYPE type, SCIP_Bool addcut, SCIP_Bool feasibilitycut, SCIP_RESULT *result)
    SCIP_RETCODE SCIPaddNlRowGradientBenderscutOpt(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_NLROW *nlrow, SCIP_Real mult, SCIP_Real *primalvals, SCIP_HASHMAP *var2idx, SCIP_Real *dirderiv, SCIP_VAR ***vars, SCIP_Real **vals, int *nvars, int *varssize)
    SCIP_RETCODE SCIPincludeBenderscutOpt(SCIP *scip, SCIP_BENDERS *benders)
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_Real SCIPgetActivityLinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
    int SCIPgetSubscipDepth(SCIP *scip)
    Definition: scip_copy.c:2589
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_Real SCIPgetTransObjoffset(SCIP *scip)
    Definition: scip_prob.c:1606
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
    Definition: scip_prob.c:1400
    int SCIPgetNFixedVars(SCIP *scip)
    Definition: scip_prob.c:2705
    SCIP_VAR ** SCIPgetFixedVars(SCIP *scip)
    Definition: scip_prob.c:2662
    SCIP_Real SCIPgetTransObjscale(SCIP *scip)
    Definition: scip_prob.c:1629
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    int SCIPhashmapEntryGetImageInt(SCIP_HASHMAPENTRY *entry)
    Definition: misc.c:3623
    int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3584
    SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
    Definition: misc.c:3592
    void * SCIPhashmapEntryGetOrigin(SCIP_HASHMAPENTRY *entry)
    Definition: misc.c:3603
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    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 SCIPgetIntParam(SCIP *scip, const char *name, int *value)
    Definition: scip_param.c:269
    SCIP_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6231
    SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
    Definition: benders.c:5065
    SCIP_RETCODE SCIPgetBendersMasterVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar)
    Definition: scip_benders.c:685
    const char * SCIPbendersGetName(SCIP_BENDERS *benders)
    Definition: benders.c:5985
    int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
    Definition: benders.c:6029
    SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6039
    SCIP_RETCODE SCIPcheckBendersSubproblemOptimality(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_Bool *optimal)
    Definition: scip_benders.c:917
    SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
    Definition: benders.c:6320
    SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
    Definition: benders.c:6568
    SCIP_RETCODE SCIPincludeBenderscutBasic(SCIP *scip, SCIP_BENDERS *benders, SCIP_BENDERSCUT **benderscutptr, const char *name, const char *desc, int priority, SCIP_Bool islpcut, SCIP_DECL_BENDERSCUTEXEC((*benderscutexec)), SCIP_BENDERSCUTDATA *benderscutdata)
    SCIP_RETCODE SCIPsetBenderscutFree(SCIP *scip, SCIP_BENDERSCUT *benderscut, SCIP_DECL_BENDERSCUTFREE((*benderscutfree)))
    void SCIPbenderscutSetData(SCIP_BENDERSCUT *benderscut, SCIP_BENDERSCUTDATA *benderscutdata)
    Definition: benderscut.c:413
    const char * SCIPbenderscutGetName(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:492
    SCIP_BENDERSCUTDATA * SCIPbenderscutGetData(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:403
    SCIP_RETCODE SCIPstoreBendersCut(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars)
    SCIP_Longint SCIPbenderscutGetNFound(SCIP_BENDERSCUT *benderscut)
    Definition: benderscut.c:543
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
    Definition: scip_cons.c:1449
    SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
    Definition: scip_cons.c:1474
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:7934
    SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
    Definition: cuts.c:2477
    SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2679
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
    Definition: cuts.c:3154
    void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2711
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:11656
    SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
    Definition: scip_expr.c:1692
    SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
    Definition: expriter.c:969
    SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
    Definition: expr.c:3972
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2362
    SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:423
    void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2376
    SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
    Definition: expriter.c:501
    SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
    Definition: scip_lp.c:611
    int SCIPgetNLPRows(SCIP *scip)
    Definition: scip_lp.c:632
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPreallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:128
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    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_RETCODE SCIPsolveNLPParam(SCIP *scip, SCIP_NLPPARAM param)
    Definition: scip_nlp.c:545
    int SCIPgetNNLPVars(SCIP *scip)
    Definition: scip_nlp.c:201
    int SCIPgetNNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:341
    SCIP_VAR ** SCIPgetNLPVars(SCIP *scip)
    Definition: scip_nlp.c:179
    SCIP_Bool SCIPhasNLPSolution(SCIP *scip)
    Definition: scip_nlp.c:671
    SCIP_NLROW ** SCIPgetNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:319
    SCIP_NLPTERMSTAT SCIPgetNLPTermstat(SCIP *scip)
    Definition: scip_nlp.c:596
    int SCIPnlrowGetNLinearVars(SCIP_NLROW *nlrow)
    Definition: nlp.c:1864
    SCIP_VAR ** SCIPnlrowGetLinearVars(SCIP_NLROW *nlrow)
    Definition: nlp.c:1874
    SCIP_Real SCIPnlrowGetDualsol(SCIP_NLROW *nlrow)
    Definition: nlp.c:1966
    SCIP_EXPR * SCIPnlrowGetExpr(SCIP_NLROW *nlrow)
    Definition: nlp.c:1894
    SCIP_Real * SCIPnlrowGetLinearCoefs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1884
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
    Definition: lp.c:17686
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    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_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_lp.c:1672
    SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
    Definition: lp.c:17706
    SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
    Definition: scip_lp.c:2108
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    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 SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:662
    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 SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPvarGetSol(SCIP_VAR *var, SCIP_Bool getlpval)
    Definition: var.c:19036
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:2608
    SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
    Definition: var.c:24723
    SCIP_Real SCIPvarGetUnchangedObj(SCIP_VAR *var)
    Definition: var.c:23964
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    static const char * paramname[]
    Definition: lpi_msk.c:5172
    public methods for Benders' decomposition
    public methods for Benders' decomposition cuts
    public functions to work with algebraic expressions
    public methods for LP management
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebugPrintCons(x, y, z)
    Definition: pub_message.h:102
    public data structures and miscellaneous methods
    internal miscellaneous methods for linear constraints
    public methods for NLP management
    public methods for problem variables
    SCIP callable library.
    SCIP_Real feastol
    Definition: type_nlpi.h:69
    SCIP_Real opttol
    Definition: type_nlpi.h:70
    @ SCIP_BENDERSENFOTYPE_RELAX
    Definition: type_benders.h:52
    @ SCIP_BENDERSENFOTYPE_LP
    Definition: type_benders.h:51
    @ SCIP_BENDERSENFOTYPE_CHECK
    Definition: type_benders.h:54
    @ SCIP_BENDERSENFOTYPE_PSEUDO
    Definition: type_benders.h:53
    enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
    Definition: type_benders.h:56
    struct SCIP_BenderscutData SCIP_BENDERSCUTDATA
    @ SCIP_EXPRITER_DFS
    Definition: type_expr.h:718
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
    Definition: type_nlpi.h:168
    @ 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_OBJSENSE_MINIMIZE
    Definition: type_prob.h:48
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_FEASIBLE
    Definition: type_result.h:45
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_CONSADDED
    Definition: type_result.h:52
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ 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_INITSOLVE
    Definition: type_set.h:52
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53